Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorolpc user <olpc@localhost.localdomain>2010-01-30 13:13:29 (GMT)
committer olpc user <olpc@localhost.localdomain>2010-01-30 13:13:29 (GMT)
commitf8a54f5c2f4487f264fe4647cec62599db93d063 (patch)
tree8758b1412c524129dad7e90a4da6b463a85ed96f
initial save 1-30-2010 bangladesh
-rw-r--r--.gitignore2
-rw-r--r--IPython/ColorANSI.py177
-rw-r--r--IPython/ConfigLoader.py111
-rw-r--r--IPython/CrashHandler.py230
-rw-r--r--IPython/DPyGetOpt.py690
-rw-r--r--IPython/Debugger.py522
-rw-r--r--IPython/Extensions/InterpreterExec.py253
-rw-r--r--IPython/Extensions/InterpreterPasteInput.py124
-rw-r--r--IPython/Extensions/PhysicalQInput.py84
-rw-r--r--IPython/Extensions/PhysicalQInteractive.py90
-rw-r--r--IPython/Extensions/__init__.py13
-rw-r--r--IPython/Extensions/astyle.py400
-rw-r--r--IPython/Extensions/clearcmd.py87
-rw-r--r--IPython/Extensions/envpersist.py90
-rw-r--r--IPython/Extensions/ext_rescapture.py63
-rw-r--r--IPython/Extensions/ibrowse.py1767
-rw-r--r--IPython/Extensions/igrid.py1126
-rw-r--r--IPython/Extensions/igrid_help.css45
-rw-r--r--IPython/Extensions/igrid_help.html86
-rw-r--r--IPython/Extensions/ipipe.py2327
-rw-r--r--IPython/Extensions/ipy_app_completers.py19
-rw-r--r--IPython/Extensions/ipy_autoreload.py349
-rw-r--r--IPython/Extensions/ipy_bzr.py343
-rw-r--r--IPython/Extensions/ipy_completers.py400
-rw-r--r--IPython/Extensions/ipy_constants.py669
-rw-r--r--IPython/Extensions/ipy_defaults.py62
-rw-r--r--IPython/Extensions/ipy_editors.py88
-rw-r--r--IPython/Extensions/ipy_exportdb.py76
-rw-r--r--IPython/Extensions/ipy_extutil.py43
-rw-r--r--IPython/Extensions/ipy_fsops.py244
-rw-r--r--IPython/Extensions/ipy_gnuglobal.py38
-rw-r--r--IPython/Extensions/ipy_greedycompleter.py75
-rw-r--r--IPython/Extensions/ipy_jot.py311
-rw-r--r--IPython/Extensions/ipy_kitcfg.py80
-rw-r--r--IPython/Extensions/ipy_legacy.py62
-rw-r--r--IPython/Extensions/ipy_lookfor.py234
-rw-r--r--IPython/Extensions/ipy_p4.py47
-rw-r--r--IPython/Extensions/ipy_pretty.py132
-rw-r--r--IPython/Extensions/ipy_profile_doctest.py46
-rw-r--r--IPython/Extensions/ipy_profile_none.py4
-rw-r--r--IPython/Extensions/ipy_profile_numpy.py24
-rw-r--r--IPython/Extensions/ipy_profile_scipy.py29
-rw-r--r--IPython/Extensions/ipy_profile_sh.py270
-rw-r--r--IPython/Extensions/ipy_profile_zope.py320
-rw-r--r--IPython/Extensions/ipy_pydb.py31
-rw-r--r--IPython/Extensions/ipy_rehashdir.py140
-rw-r--r--IPython/Extensions/ipy_render.py68
-rw-r--r--IPython/Extensions/ipy_server.py38
-rw-r--r--IPython/Extensions/ipy_signals.py62
-rw-r--r--IPython/Extensions/ipy_stock_completers.py17
-rw-r--r--IPython/Extensions/ipy_synchronize_with.py242
-rw-r--r--IPython/Extensions/ipy_system_conf.py24
-rw-r--r--IPython/Extensions/ipy_traits_completer.py184
-rw-r--r--IPython/Extensions/ipy_vimserver.py239
-rw-r--r--IPython/Extensions/ipy_which.py76
-rw-r--r--IPython/Extensions/ipy_winpdb.py83
-rw-r--r--IPython/Extensions/ipy_workdir.py43
-rw-r--r--IPython/Extensions/jobctrl.py242
-rw-r--r--IPython/Extensions/ledit.py98
-rw-r--r--IPython/Extensions/numeric_formats.py43
-rwxr-xr-xIPython/Extensions/pickleshare.py357
-rw-r--r--IPython/Extensions/pspersistence.py182
-rw-r--r--IPython/Extensions/scitedirector.py26
-rw-r--r--IPython/Extensions/win32clip.py45
-rw-r--r--IPython/FakeModule.py66
-rw-r--r--IPython/Gnuplot2.py665
-rw-r--r--IPython/GnuplotInteractive.py147
-rw-r--r--IPython/GnuplotRuntime.py146
-rw-r--r--IPython/Itpl.py290
-rw-r--r--IPython/Logger.py263
-rw-r--r--IPython/Magic.py3526
-rw-r--r--IPython/OInspect.py607
-rw-r--r--IPython/OutputTrap.py258
-rw-r--r--IPython/Prompts.py626
-rw-r--r--IPython/PyColorize.py300
-rw-r--r--IPython/Release.py121
-rw-r--r--IPython/Shell.py1246
-rw-r--r--IPython/UserConfig/__init__.py0
-rw-r--r--IPython/UserConfig/ipy_user_conf.py114
-rw-r--r--IPython/UserConfig/ipythonrc631
-rw-r--r--IPython/UserConfig/ipythonrc-math36
-rw-r--r--IPython/UserConfig/ipythonrc-numeric57
-rw-r--r--IPython/UserConfig/ipythonrc-physics45
-rw-r--r--IPython/UserConfig/ipythonrc-pysh94
-rw-r--r--IPython/UserConfig/ipythonrc-tutorial37
-rw-r--r--IPython/__init__.py72
-rw-r--r--IPython/background_jobs.py490
-rw-r--r--IPython/clipboard.py56
-rw-r--r--IPython/completer.py639
-rw-r--r--IPython/config/__init__.py14
-rw-r--r--IPython/config/api.py102
-rw-r--r--IPython/config/cutils.py34
-rw-r--r--IPython/config/tests/__init__.py0
-rw-r--r--IPython/deep_reload.py182
-rw-r--r--IPython/demo.py554
-rw-r--r--IPython/dtutils.py137
-rw-r--r--IPython/excolors.py137
-rw-r--r--IPython/external/Itpl.py276
-rw-r--r--IPython/external/__init__.py5
-rw-r--r--IPython/external/argparse.py2216
-rw-r--r--IPython/external/configobj.py2501
-rw-r--r--IPython/external/guid.py170
-rwxr-xr-xIPython/external/mglob.py229
-rw-r--r--IPython/external/path.py973
-rw-r--r--IPython/external/pretty.py705
-rw-r--r--IPython/external/simplegeneric.py139
-rw-r--r--IPython/external/validate.py1414
-rw-r--r--IPython/frontend/__init__.py0
-rw-r--r--IPython/frontend/asyncfrontendbase.py82
-rw-r--r--IPython/frontend/cocoa/__init__.py0
-rw-r--r--IPython/frontend/cocoa/cocoa_frontend.py560
-rw-r--r--IPython/frontend/cocoa/tests/__init__.py0
-rw-r--r--IPython/frontend/cocoa/tests/test_cocoa_frontend.py100
-rw-r--r--IPython/frontend/frontendbase.py343
-rw-r--r--IPython/frontend/linefrontendbase.py372
-rw-r--r--IPython/frontend/prefilterfrontend.py285
-rw-r--r--IPython/frontend/process/__init__.py19
-rw-r--r--IPython/frontend/process/killableprocess.py184
-rw-r--r--IPython/frontend/process/pipedprocess.py74
-rw-r--r--IPython/frontend/process/winprocess.py264
-rw-r--r--IPython/frontend/tests/__init__.py0
-rw-r--r--IPython/frontend/tests/test_asyncfrontendbase.py112
-rw-r--r--IPython/frontend/tests/test_frontendbase.py32
-rw-r--r--IPython/frontend/tests/test_linefrontend.py37
-rw-r--r--IPython/frontend/tests/test_prefilterfrontend.py266
-rw-r--r--IPython/frontend/tests/test_process.py67
-rw-r--r--IPython/frontend/wx/__init__.py0
-rw-r--r--IPython/frontend/wx/console_widget.py624
-rw-r--r--IPython/frontend/wx/ipythonx.py119
-rw-r--r--IPython/frontend/wx/wx_frontend.py602
-rw-r--r--IPython/frontend/zopeinterface.py27
-rw-r--r--IPython/generics.py54
-rw-r--r--IPython/genutils.py2171
-rw-r--r--IPython/gui/__init__.py0
-rw-r--r--IPython/gui/wx/__init__.py0
-rw-r--r--IPython/gui/wx/ipshell_nonblocking.py525
-rw-r--r--IPython/gui/wx/ipython_history.py509
-rw-r--r--IPython/gui/wx/ipython_view.py942
-rw-r--r--IPython/gui/wx/thread_ex.py50
-rw-r--r--IPython/gui/wx/wxIPython.py266
-rw-r--r--IPython/history.py258
-rw-r--r--IPython/hooks.py264
-rw-r--r--IPython/ipapi.py685
-rw-r--r--IPython/iplib.py2870
-rw-r--r--IPython/ipmaker.py773
-rw-r--r--IPython/ipstruct.py416
-rw-r--r--IPython/irunner.py441
-rwxr-xr-xIPython/kernel/__init__.py25
-rw-r--r--IPython/kernel/asyncclient.py41
-rw-r--r--IPython/kernel/client.py96
-rw-r--r--IPython/kernel/clientconnector.py150
-rw-r--r--IPython/kernel/clientinterfaces.py32
-rw-r--r--IPython/kernel/codeutil.py39
-rw-r--r--IPython/kernel/config/__init__.py126
-rw-r--r--IPython/kernel/contexts.py141
-rw-r--r--IPython/kernel/controllerservice.py376
-rw-r--r--IPython/kernel/core/__init__.py16
-rw-r--r--IPython/kernel/core/config/__init__.py25
-rw-r--r--IPython/kernel/core/display_formatter.py70
-rw-r--r--IPython/kernel/core/display_trap.py100
-rw-r--r--IPython/kernel/core/error.py41
-rw-r--r--IPython/kernel/core/fd_redirector.py81
-rw-r--r--IPython/kernel/core/file_like.py66
-rw-r--r--IPython/kernel/core/history.py137
-rw-r--r--IPython/kernel/core/interpreter.py761
-rw-r--r--IPython/kernel/core/macro.py34
-rw-r--r--IPython/kernel/core/magic.py147
-rw-r--r--IPython/kernel/core/message_cache.py98
-rw-r--r--IPython/kernel/core/notification.py125
-rw-r--r--IPython/kernel/core/output_trap.py107
-rw-r--r--IPython/kernel/core/prompts.py588
-rw-r--r--IPython/kernel/core/redirector_output_trap.py97
-rw-r--r--IPython/kernel/core/sync_traceback_trap.py53
-rw-r--r--IPython/kernel/core/tests/__init__.py10
-rw-r--r--IPython/kernel/core/tests/test_interpreter.py62
-rw-r--r--IPython/kernel/core/tests/test_notification.py161
-rw-r--r--IPython/kernel/core/tests/test_redirectors.py78
-rw-r--r--IPython/kernel/core/traceback_formatter.py62
-rw-r--r--IPython/kernel/core/traceback_trap.py85
-rw-r--r--IPython/kernel/core/util.py195
-rw-r--r--IPython/kernel/engineconnector.py92
-rw-r--r--IPython/kernel/enginefc.py548
-rw-r--r--IPython/kernel/engineservice.py902
-rw-r--r--IPython/kernel/error.py205
-rw-r--r--IPython/kernel/fcutil.py69
-rw-r--r--IPython/kernel/magic.py171
-rw-r--r--IPython/kernel/map.py121
-rw-r--r--IPython/kernel/mapper.py233
-rw-r--r--IPython/kernel/multiengine.py753
-rw-r--r--IPython/kernel/multiengineclient.py964
-rw-r--r--IPython/kernel/multienginefc.py757
-rw-r--r--IPython/kernel/newserialized.py170
-rw-r--r--IPython/kernel/parallelfunction.py107
-rw-r--r--IPython/kernel/pbconfig.py34
-rw-r--r--IPython/kernel/pbutil.py93
-rw-r--r--IPython/kernel/pendingdeferred.py178
-rw-r--r--IPython/kernel/pickleutil.py83
-rw-r--r--IPython/kernel/scripts/__init__.py16
-rwxr-xr-xIPython/kernel/scripts/ipcluster22
-rw-r--r--IPython/kernel/scripts/ipcluster.py813
-rwxr-xr-xIPython/kernel/scripts/ipcontroller20
-rwxr-xr-xIPython/kernel/scripts/ipcontroller.py416
-rwxr-xr-xIPython/kernel/scripts/ipengine20
-rwxr-xr-xIPython/kernel/scripts/ipengine.py193
-rw-r--r--IPython/kernel/task.py1116
-rw-r--r--IPython/kernel/taskclient.py180
-rw-r--r--IPython/kernel/taskfc.py329
-rw-r--r--IPython/kernel/tests/__init__.py10
-rw-r--r--IPython/kernel/tests/controllertest.py102
-rw-r--r--IPython/kernel/tests/engineservicetest.py377
-rw-r--r--IPython/kernel/tests/multienginetest.py827
-rw-r--r--IPython/kernel/tests/tasktest.py187
-rw-r--r--IPython/kernel/tests/test_contexts.py46
-rw-r--r--IPython/kernel/tests/test_controllerservice.py44
-rw-r--r--IPython/kernel/tests/test_enginefc.py92
-rw-r--r--IPython/kernel/tests/test_engineservice.py79
-rw-r--r--IPython/kernel/tests/test_multiengine.py55
-rw-r--r--IPython/kernel/tests/test_multienginefc.py144
-rw-r--r--IPython/kernel/tests/test_newserialized.py102
-rw-r--r--IPython/kernel/tests/test_pendingdeferred.py186
-rw-r--r--IPython/kernel/tests/test_task.py51
-rw-r--r--IPython/kernel/tests/test_taskfc.py161
-rw-r--r--IPython/kernel/tests/test_twistedutil.py51
-rw-r--r--IPython/kernel/twistedutil.py249
-rw-r--r--IPython/kernel/util.py102
-rw-r--r--IPython/macro.py43
-rw-r--r--IPython/numutils.py302
-rw-r--r--IPython/platutils.py103
-rw-r--r--IPython/platutils_dummy.py33
-rw-r--r--IPython/platutils_posix.py47
-rw-r--r--IPython/platutils_win32.py94
-rw-r--r--IPython/prefilter.py320
-rw-r--r--IPython/rlineimpl.py55
-rw-r--r--IPython/shadowns.py1
-rw-r--r--IPython/shellglobals.py101
-rw-r--r--IPython/strdispatch.py69
-rw-r--r--IPython/testing/__init__.py0
-rw-r--r--IPython/testing/decorator_msim.py146
-rw-r--r--IPython/testing/decorators.py254
-rw-r--r--IPython/testing/decorators_numpy.py90
-rw-r--r--IPython/testing/decorators_trial.py132
-rw-r--r--IPython/testing/iptest.py346
-rw-r--r--IPython/testing/mkdoctests.py244
-rw-r--r--IPython/testing/parametric.py55
-rw-r--r--IPython/testing/plugin/Makefile74
-rw-r--r--IPython/testing/plugin/README.txt39
-rw-r--r--IPython/testing/plugin/__init__.py0
-rw-r--r--IPython/testing/plugin/dtexample.py162
-rw-r--r--IPython/testing/plugin/ipdoctest.py939
-rwxr-xr-xIPython/testing/plugin/iptest.py18
-rwxr-xr-xIPython/testing/plugin/setup.py18
-rw-r--r--IPython/testing/plugin/show_refs.py19
-rw-r--r--IPython/testing/plugin/simple.py33
-rw-r--r--IPython/testing/plugin/simplevars.py2
-rw-r--r--IPython/testing/plugin/test_combo.txt36
-rw-r--r--IPython/testing/plugin/test_example.txt24
-rw-r--r--IPython/testing/plugin/test_exampleip.txt30
-rw-r--r--IPython/testing/plugin/test_ipdoctest.py94
-rw-r--r--IPython/testing/plugin/test_refs.py48
-rw-r--r--IPython/testing/tests/__init__.py10
-rw-r--r--IPython/testing/tests/test_decorators.py161
-rw-r--r--IPython/testing/tests/test_decorators_trial.py52
-rw-r--r--IPython/testing/tests/test_tools.py52
-rw-r--r--IPython/testing/tools.py89
-rw-r--r--IPython/testing/util.py64
-rw-r--r--IPython/tests/__init__.py0
-rw-r--r--IPython/tests/obj_del.py34
-rw-r--r--IPython/tests/refbug.py41
-rw-r--r--IPython/tests/tclass.py27
-rw-r--r--IPython/tests/test_fakemodule.py17
-rw-r--r--IPython/tests/test_genutils.py306
-rw-r--r--IPython/tests/test_iplib.py80
-rw-r--r--IPython/tests/test_magic.py302
-rw-r--r--IPython/tests/test_platutils.py59
-rw-r--r--IPython/tools/__init__.py0
-rw-r--r--IPython/tools/growl.py49
-rw-r--r--IPython/tools/tests/__init__.py0
-rw-r--r--IPython/tools/tests/test_tools_utils.txt17
-rw-r--r--IPython/tools/utils.py128
-rw-r--r--IPython/twshell.py285
-rw-r--r--IPython/ultraTB.py1061
-rw-r--r--IPython/upgrade_dir.py92
-rw-r--r--IPython/usage.py645
-rw-r--r--IPython/wildcard.py149
-rw-r--r--IPython/winconsole.py46
-rw-r--r--MANIFEST1125
-rw-r--r--Rpyc/AsyncNetProxy.py85
-rw-r--r--Rpyc/Boxing.py123
-rw-r--r--Rpyc/Channel.py57
-rw-r--r--Rpyc/Connection.py212
-rw-r--r--Rpyc/Demo/__init__.py0
-rw-r--r--Rpyc/Demo/demo-1.py156
-rw-r--r--Rpyc/Demo/demo-2.py81
-rw-r--r--Rpyc/Demo/demo-3.py129
-rw-r--r--Rpyc/Demo/demo-4.py41
-rw-r--r--Rpyc/Demo/demo-5.py66
-rw-r--r--Rpyc/Demo/demo-6.py130
-rw-r--r--Rpyc/Demo/pipe-child.py8
-rw-r--r--Rpyc/Demo/pipe-parent.py17
-rw-r--r--Rpyc/Demo/testmodule.py19
-rw-r--r--Rpyc/Demo/testsuite.bat6
-rw-r--r--Rpyc/Lib.py71
-rw-r--r--Rpyc/ModuleNetProxy.py55
-rw-r--r--Rpyc/NetProxy.py117
-rw-r--r--Rpyc/Servers/Users.py9
-rw-r--r--Rpyc/Servers/__init__.py0
-rw-r--r--Rpyc/Servers/forking_server.py32
-rw-r--r--Rpyc/Servers/selecting_server.py35
-rw-r--r--Rpyc/Servers/simple_server.py13
-rw-r--r--Rpyc/Servers/std_server.py31
-rw-r--r--Rpyc/Servers/threaded_server.py10
-rw-r--r--Rpyc/Servers/tls_server.py20
-rw-r--r--Rpyc/Stream.py113
-rw-r--r--Rpyc/Utils/Builtins.py152
-rw-r--r--Rpyc/Utils/Discovery.py38
-rw-r--r--Rpyc/Utils/Dist.py37
-rw-r--r--Rpyc/Utils/Factories.py56
-rw-r--r--Rpyc/Utils/Files.py112
-rw-r--r--Rpyc/Utils/Helpers.py149
-rw-r--r--Rpyc/Utils/Interpreter.py39
-rw-r--r--Rpyc/Utils/Serving.py126
-rw-r--r--Rpyc/Utils/__init__.py7
-rw-r--r--Rpyc/__init__.py33
-rw-r--r--Rpyc/tests/isinstance.py53
-rw-r--r--activity/PyDebug.svg38
-rw-r--r--activity/PyDebug.svg.save1632
-rw-r--r--activity/activity-terminal.svg11
-rw-r--r--activity/activity.info9
-rwxr-xr-xbin/PyDebug.sh12
-rw-r--r--bin/PyDebug.sh~11
-rw-r--r--bin/continue_debug.py180
-rw-r--r--bin/continue_debug.py~180
-rwxr-xr-xbin/gitbin0 -> 925172 bytes
-rwxr-xr-xbin/ipython.py11
-rwxr-xr-xbin/python.save12
-rw-r--r--bin/start_debug.py54
-rw-r--r--bin/startdb116
-rwxr-xr-xbin/sugar-launch96
-rwxr-xr-xbin/sugar-launch-path134
-rwxr-xr-xbin/sugar_start85
-rwxr-xr-xbin/sugarun160
-rwxr-xr-xbkuppydb3
-rw-r--r--browser.py64
-rw-r--r--continue_debug.py138
-rw-r--r--datastoretree.py228
-rw-r--r--db/shadowhist/075
-rw-r--r--db/shadowhist/0a5
-rw-r--r--db/shadowhist/0e8
-rw-r--r--db/shadowhist/155
-rw-r--r--db/shadowhist/185
-rw-r--r--db/shadowhist/1c5
-rw-r--r--db/shadowhist/1e5
-rw-r--r--db/shadowhist/205
-rw-r--r--db/shadowhist/2a5
-rw-r--r--db/shadowhist/2b5
-rw-r--r--db/shadowhist/2d5
-rw-r--r--db/shadowhist/3c5
-rw-r--r--db/shadowhist/3d5
-rw-r--r--db/shadowhist/3f5
-rw-r--r--db/shadowhist/425
-rw-r--r--db/shadowhist/495
-rw-r--r--db/shadowhist/4a5
-rw-r--r--db/shadowhist/4d11
-rw-r--r--db/shadowhist/505
-rw-r--r--db/shadowhist/515
-rw-r--r--db/shadowhist/5911
-rw-r--r--db/shadowhist/5a5
-rw-r--r--db/shadowhist/6c5
-rw-r--r--db/shadowhist/705
-rw-r--r--db/shadowhist/785
-rw-r--r--db/shadowhist/795
-rw-r--r--db/shadowhist/7c5
-rw-r--r--db/shadowhist/7e8
-rw-r--r--db/shadowhist/895
-rw-r--r--db/shadowhist/8f5
-rw-r--r--db/shadowhist/975
-rw-r--r--db/shadowhist/9f5
-rw-r--r--db/shadowhist/af5
-rw-r--r--db/shadowhist/b05
-rw-r--r--db/shadowhist/b95
-rw-r--r--db/shadowhist/c05
-rw-r--r--db/shadowhist/cb5
-rw-r--r--db/shadowhist/d35
-rw-r--r--db/shadowhist/dd5
-rw-r--r--db/shadowhist/e55
-rw-r--r--db/shadowhist/e64
-rw-r--r--db/shadowhist/e95
-rw-r--r--db/shadowhist/ef5
-rw-r--r--db/shadowhist/f55
-rw-r--r--db/shadowhist/f85
-rw-r--r--db/shadowhist/f95
-rw-r--r--db/shadowhist_idx2
-rw-r--r--examples/HelloWorld.activity/HelloWorldActivity.py40
-rw-r--r--examples/HelloWorld.activity/MANIFEST4
-rw-r--r--examples/HelloWorld.activity/activity/activity-helloworld.svg8
-rw-r--r--examples/HelloWorld.activity/activity/activity.info7
-rwxr-xr-xexamples/HelloWorld.activity/setup.py3
-rw-r--r--examples/bundle-2.xobin0 -> 108815 bytes
-rw-r--r--filetree.py221
m---------git/pippy-activity0
-rw-r--r--help/ActivityBook/ActivitiesGuideSugar/AddRefinements917
-rw-r--r--help/ActivityBook/ActivitiesGuideSugar/CreateFirstActivity290
-rw-r--r--help/ActivityBook/ActivitiesGuideSugar/Credits369
-rw-r--r--help/ActivityBook/ActivitiesGuideSugar/InheritFromActivity498
-rw-r--r--help/ActivityBook/ActivitiesGuideSugar/Introduction252
-rw-r--r--help/ActivityBook/ActivitiesGuideSugar/NeedtoKnowWriteSugarActivity284
-rw-r--r--help/ActivityBook/ActivitiesGuideSugar/PackageTheActivity462
-rw-r--r--help/ActivityBook/ActivitiesGuideSugar/SetUpDevEnvironment314
-rw-r--r--help/ActivityBook/ActivitiesGuideSugar/StandalonePythonReadEtexts461
-rw-r--r--help/ActivityBook/ActivitiesGuideSugar/UsingVersionControl544
-rw-r--r--help/ActivityBook/ActivitiesGuideSugar/WhatIsSugar311
-rw-r--r--help/ActivityBook/ActivitiesGuideSugar/WhatisanActivity256
-rw-r--r--help/ActivityBook/ActivitiesGuideSugar/print2129
-rw-r--r--help/ActivityBook/bookstore/bookstore.gifbin0 -> 1044 bytes
-rw-r--r--help/ActivityBook/bookstore/bookstore.js140
-rw-r--r--help/ActivityBook/floss/pub/ActivitiesGuideSugar/ReadEtexts_01_1.jpgbin0 -> 34804 bytes
-rw-r--r--help/ActivityBook/floss/pub/ActivitiesGuideSugar/ReadEtexts_02.jpgbin0 -> 45789 bytes
-rw-r--r--help/ActivityBook/floss/pub/ActivitiesGuideSugar/ReadEtexts_03.jpgbin0 -> 33653 bytes
-rw-r--r--help/ActivityBook/floss/pub/ActivitiesGuideSugar/ReadEtexts_04.jpgbin0 -> 31931 bytes
-rw-r--r--help/ActivityBook/floss/pub/ActivitiesGuideSugar/ReadEtexts_05.jpgbin0 -> 32213 bytes
-rw-r--r--help/ActivityBook/floss/pub/ActivitiesGuideSugar/git1.jpgbin0 -> 11035 bytes
-rw-r--r--help/ActivityBook/floss/pub/ActivitiesGuideSugar/git10.jpgbin0 -> 75087 bytes
-rw-r--r--help/ActivityBook/floss/pub/ActivitiesGuideSugar/git11_1.jpgbin0 -> 78179 bytes
-rw-r--r--help/ActivityBook/floss/pub/ActivitiesGuideSugar/git12.jpgbin0 -> 38527 bytes
-rw-r--r--help/ActivityBook/floss/pub/ActivitiesGuideSugar/git13.jpgbin0 -> 18516 bytes
-rw-r--r--help/ActivityBook/floss/pub/ActivitiesGuideSugar/git14.jpgbin0 -> 67245 bytes
-rw-r--r--help/ActivityBook/floss/pub/ActivitiesGuideSugar/git2.jpgbin0 -> 32774 bytes
-rw-r--r--help/ActivityBook/floss/pub/ActivitiesGuideSugar/git3.jpgbin0 -> 49867 bytes
-rw-r--r--help/ActivityBook/floss/pub/ActivitiesGuideSugar/git4.jpgbin0 -> 10053 bytes
-rw-r--r--help/ActivityBook/floss/pub/ActivitiesGuideSugar/git5.jpgbin0 -> 54709 bytes
-rw-r--r--help/ActivityBook/floss/pub/ActivitiesGuideSugar/git6.jpgbin0 -> 57414 bytes
-rw-r--r--help/ActivityBook/floss/pub/ActivitiesGuideSugar/git7.jpgbin0 -> 69235 bytes
-rw-r--r--help/ActivityBook/floss/pub/ActivitiesGuideSugar/git8.jpgbin0 -> 70787 bytes
-rw-r--r--help/ActivityBook/floss/pub/ActivitiesGuideSugar/git9.jpgbin0 -> 47536 bytes
-rw-r--r--help/ActivityBook/floss/pub/Floss/100.gifbin0 -> 1290 bytes
-rw-r--r--help/ActivityBook/floss/pub/TWiki/FlossSkin2/WHATDOIWANT2.gifbin0 -> 30825 bytes
-rw-r--r--help/ActivityBook/floss/pub/TWiki/FlossSkin2/background.gifbin0 -> 189 bytes
-rw-r--r--help/ActivityBook/floss/pub/TWiki/FlossSkin2/fl2.icobin0 -> 1150 bytes
-rw-r--r--help/ActivityBook/floss/pub/TWiki/FlossSkin2/free.gifbin0 -> 4379 bytes
-rw-r--r--help/ActivityBook/floss/pub/TWiki/FlossSkin2/text_read.gifbin0 -> 799 bytes
-rw-r--r--help/ActivityBook/floss/pub/TWiki/FlossSkin2/top_read.gifbin0 -> 7551 bytes
-rw-r--r--help/ActivityBook/floss/pub/TWiki/FlossSkin2/typography_cover.css229
-rw-r--r--help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/ReadEtexts_01_1.jpgbin0 -> 34804 bytes
-rw-r--r--help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/ReadEtexts_02.jpgbin0 -> 45789 bytes
-rw-r--r--help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/ReadEtexts_03.jpgbin0 -> 33653 bytes
-rw-r--r--help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/ReadEtexts_04.jpgbin0 -> 31931 bytes
-rw-r--r--help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/ReadEtexts_05.jpgbin0 -> 32213 bytes
-rw-r--r--help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git1.jpgbin0 -> 11035 bytes
-rw-r--r--help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git10.jpgbin0 -> 75087 bytes
-rw-r--r--help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git11_1.jpgbin0 -> 78179 bytes
-rw-r--r--help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git12.jpgbin0 -> 38527 bytes
-rw-r--r--help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git13.jpgbin0 -> 18516 bytes
-rw-r--r--help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git14.jpgbin0 -> 67245 bytes
-rw-r--r--help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git2.jpgbin0 -> 32774 bytes
-rw-r--r--help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git3.jpgbin0 -> 49867 bytes
-rw-r--r--help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git4.jpgbin0 -> 10053 bytes
-rw-r--r--help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git5.jpgbin0 -> 54709 bytes
-rw-r--r--help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git6.jpgbin0 -> 57414 bytes
-rw-r--r--help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git7.jpgbin0 -> 69235 bytes
-rw-r--r--help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git8.jpgbin0 -> 70787 bytes
-rw-r--r--help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git9.jpgbin0 -> 47536 bytes
-rw-r--r--help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/Floss/100.gifbin0 -> 1290 bytes
-rw-r--r--help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/background.gifbin0 -> 189 bytes
-rw-r--r--help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/fl2.icobin0 -> 1150 bytes
-rw-r--r--help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/lefttext.pngbin0 -> 1771 bytes
-rw-r--r--help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/makepdf.gifbin0 -> 695 bytes
-rw-r--r--help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/righttext.pngbin0 -> 1353 bytes
-rw-r--r--help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/top_read_back.gifbin0 -> 2276 bytes
-rw-r--r--help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/typography.css313
-rw-r--r--help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/viewprint.gifbin0 -> 1019 bytes
-rw-r--r--help/ActivityBook/index.html263
-rw-r--r--help/ActivityBook/library/library.info9
-rw-r--r--help/ActivityBook/robots.txt35
-rw-r--r--help/BeginnerPython/library/library.info9
-rw-r--r--help/BeginnerPython/robots.txt33
-rw-r--r--help/CSS/Accessible_Design.css119
-rw-r--r--help/PyDebug.htm32
-rw-r--r--help/Pygtk2Tutorial/library/library.info9
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/app-CodeExamples.html120
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/app-GtkSignals.html6
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/ch-Adjustments.html46
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/ch-AdvancedEventAndSignalHandling.html57
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/ch-ButtonWidget.html186
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/ch-ContainerWidgets.html76
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/ch-Contributing.html8
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/ch-Copyright.html14
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/ch-Credits.html5
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/ch-DragAndDrop.html25
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/ch-DrawingArea.html217
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/ch-GettingStarted.html173
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/ch-GtkRcFiles.html33
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/ch-Introduction.html101
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/ch-ManagingSelections.html21
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/ch-MenuWidget.html116
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/ch-MiscellaneousWidgets.html145
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/ch-MovingOn.html15
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/ch-NewInPyGTK2.2.html183
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/ch-NewInPyGTK2.4.html591
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/ch-PackingWidgets.html29
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/ch-RangeWidgets.html30
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/ch-Scribble.html3
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/ch-SettingWidgetAttributes.html47
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/ch-TextViewWidget.html40
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/ch-TimeoutsIOAndIdleFunctions.html19
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/ch-TipsForWritingPyGTKApplications.html4
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/ch-TreeViewWidget.html166
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/ch-UndocumentedWidgets.html9
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/ch-WidgetOverview.html165
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/actiongroup.pngbin0 -> 11454 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/actions.pngbin0 -> 10526 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/arrows.pngbin0 -> 3231 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/aspectframe.pngbin0 -> 7777 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/base.pngbin0 -> 6428 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/basicaction.pngbin0 -> 8427 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/basictreeview.pngbin0 -> 8377 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/button.pngbin0 -> 3043 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/buttonbox.pngbin0 -> 32992 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/calendar.pngbin0 -> 19494 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/celldatafunc.pngbin0 -> 16246 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/cellrenderer.pngbin0 -> 12216 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/celltextmarkup.pngbin0 -> 10075 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/checkbutton.pngbin0 -> 3891 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/clipboard.pngbin0 -> 40309 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/colorbutton.pngbin0 -> 57340 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/colorselection.pngbin0 -> 46163 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/comboboxbasic.pngbin0 -> 7693 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/comboboxentrybasic.pngbin0 -> 9685 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/comboboxwrap.pngbin0 -> 21872 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/dragndrop.pngbin0 -> 16636 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/drawingarea.pngbin0 -> 20090 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/entry.pngbin0 -> 5292 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/entrycompletion.pngbin0 -> 8028 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/eventbox.pngbin0 -> 6082 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/expander.pngbin0 -> 5046 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/filechooser.pngbin0 -> 32620 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/filelisting-gtm.pngbin0 -> 43543 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/filelisting.pngbin0 -> 32454 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/fileselection.pngbin0 -> 13483 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/fixed.pngbin0 -> 11795 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/fontbutton.pngbin0 -> 62506 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/fontselection.pngbin0 -> 14674 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/frame.pngbin0 -> 9890 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/getselection.pngbin0 -> 5018 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/helloworld.pngbin0 -> 3003 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/helloworld2.pngbin0 -> 4630 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/images.pngbin0 -> 35447 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/itemfactory.pngbin0 -> 9169 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/labels.pngbin0 -> 34508 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/layout.pngbin0 -> 7396 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/menu.pngbin0 -> 7896 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/notebook.pngbin0 -> 12660 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/packbox1.pngbin0 -> 26312 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/packbox2.pngbin0 -> 24782 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/packbox3.pngbin0 -> 15863 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/paned.pngbin0 -> 11847 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/pixmap.pngbin0 -> 685 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/progressbar.pngbin0 -> 5682 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/radiobutton.pngbin0 -> 3751 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/rangewidgets.pngbin0 -> 10549 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/rulers.pngbin0 -> 9473 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/scribblesimple.pngbin0 -> 8733 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/scrolledwin.pngbin0 -> 12434 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/setselection.pngbin0 -> 4443 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/simpleaction.pngbin0 -> 2003 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/spinbutton.pngbin0 -> 9186 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/statusbar.pngbin0 -> 8220 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/table.pngbin0 -> 5174 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/testtext.pngbin0 -> 37605 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/textview-basic.pngbin0 -> 19521 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/toggle.pngbin0 -> 5929 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/toolbar.pngbin0 -> 13032 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/tooltips.pngbin0 -> 13662 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/treemodelfilter.pngbin0 -> 44679 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/treemodelsort.pngbin0 -> 36186 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/treeviewcolumn.pngbin0 -> 7465 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/treeviewcolumn1expander.pngbin0 -> 14997 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/treeviewdnd.pngbin0 -> 11539 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/uimanager.pngbin0 -> 11305 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/uimerge.pngbin0 -> 27779 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/figures/wheelbarrow.pngbin0 -> 14691 bytes
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/index.html1
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/pygtk-tut-changelog.html370
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-AdjustmentInternals.html56
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-Alignment.html32
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-Arrows.html88
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-AspectFrames.html65
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-ButtonBoxes.html133
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-Calendar.html332
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-CellRenderers.html411
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-CheckButtons.html100
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-ColorButtonAndFontButton.html100
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-ColorSelection.html151
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-ComboBoxAndComboboxEntry.html207
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-ComboWidget.html80
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-CommonRangeMethods.html35
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-Curves.html1
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-DNDMethods.html254
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-DNDProperties.html28
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-DetailsOfBoxes.html56
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-Dialogs.html36
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-DrawingAreaWidgetAndDrawing.html129
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-DrawingMethods.html301
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-EntryCompletion.html65
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-EventHandling.html345
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-Events.html104
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-ExampleRcFile.html126
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-ExpanderWidget.html52
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-FileChoosers.html108
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-FileSelections.html81
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-Fixed.html77
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-FontSelectionDialog.html58
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-Frames.html80
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-GTKRcFileFormat.html51
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-GammaCurve.html1
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-GenericCellRenderer.html1
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-GenericTreeModel.html384
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkAdjustment.html5
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkButton.html11
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkCalendar.html15
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkCheckMenuItem.html3
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkColorSelection.html3
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkContainer.html11
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkCurve.html3
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkData.html3
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkEditable.html33
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkHandleBox.html5
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkInputDialog.html5
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkItem.html7
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkList.html7
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkMenuItem.html5
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkMenuShell.html11
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkNotebook.html3
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkStatusBar.html5
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkToggleButton.html3
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkToolbar.html5
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkWidget.html107
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkWindow.html3
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-IdleFunctions.html20
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-Images.html477
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-ItemFactoryExample.html101
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-KeyAndMouseBindings.html20
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-Layout.html112
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-ManipulatingTreeViews.html34
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-ManualMenuExample.html108
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-MenuItems.html1
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-MessageDialog.html1
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-MonitoringIO.html38
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-Notebooks.html223
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-OptionMenu.html1
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-OriginalGTK+Credits.html24
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-PackingDemonstrationProgram.html282
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-PackingUsingTables.html61
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-PanedWindowWidgets.html122
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-PlugsAndSockets.html148
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-ProgressBars.html188
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-RadioButtons.html101
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-RangeWidgetEample.html248
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-RetrievingTheSelection.html212
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-Rulers.html125
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-ScaleWidgets.html46
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-ScrolledWindows.html104
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-SignalEmissionAndPropagation.html16
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-SpinButtons.html290
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-Statusbars.html90
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-SteppingThroughHelloWorld.html140
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-SupplyingTheSelection.html132
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-TablePackingExample.html108
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-TextBuffers.html258
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-TextEntries.html123
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-TextIters.html231
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-TextMarks.html31
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-TextTagsAndTextTagTables.html61
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-TextViewExample.html75
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-TextViews.html267
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-TheoryOfSignalsAndCallbacks.html50
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-ToggleButtons.html130
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-Toolbar.html258
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-TooltipsObject.html99
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-TreeModelInterface.html631
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-TreeModelSortAndTreeModelFilter.html185
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-TreeSelections.html133
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-TreeViewColumns.html60
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-TreeViewDragAndDrop.html250
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-TreeViewSignals.html26
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-TreeViews.html88
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-UIManager.html413
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-UpgradedHelloWorld.html101
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-UsingAdjustmentsTheEasyWay.html29
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-UsingItemFactory.html2
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-Viewports.html33
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-WidgetAccelerators.html39
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-WidgetDisplayMethods.html30
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-WidgetNameMethods.html11
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-WidgetStyles.html74
-rw-r--r--help/Pygtk2Tutorial/pygtk2tutorial/sec-WidgetsWithoutWindows.html30
-rw-r--r--help/PythonExamples/index.html451
-rw-r--r--help/PythonExamples/library/library.info9
-rw-r--r--help/PythonExamples/pleac.css17
-rw-r--r--help/PythonExamples/pleac_python/a1102.html172
-rw-r--r--help/PythonExamples/pleac_python/arrays.html1495
-rw-r--r--help/PythonExamples/pleac_python/cgiprogramming.html980
-rw-r--r--help/PythonExamples/pleac_python/classesetc.html1423
-rw-r--r--help/PythonExamples/pleac_python/datesandtimes.html694
-rw-r--r--help/PythonExamples/pleac_python/dbaccess.html679
-rw-r--r--help/PythonExamples/pleac_python/directories.html838
-rw-r--r--help/PythonExamples/pleac_python/fileaccess.html1107
-rw-r--r--help/PythonExamples/pleac_python/filecontents.html1191
-rw-r--r--help/PythonExamples/pleac_python/hashes.html1111
-rw-r--r--help/PythonExamples/pleac_python/index.html284
-rw-r--r--help/PythonExamples/pleac_python/internetservices.html502
-rw-r--r--help/PythonExamples/pleac_python/numbers.html963
-rw-r--r--help/PythonExamples/pleac_python/packagesetc.html1089
-rw-r--r--help/PythonExamples/pleac_python/patternmatching.html1726
-rw-r--r--help/PythonExamples/pleac_python/processmanagementetc.html887
-rw-r--r--help/PythonExamples/pleac_python/referencesandrecords.html1019
-rw-r--r--help/PythonExamples/pleac_python/sockets.html917
-rw-r--r--help/PythonExamples/pleac_python/strings.html1277
-rw-r--r--help/PythonExamples/pleac_python/subroutines.html1071
-rw-r--r--help/PythonExamples/pleac_python/userinterfaces.html1050
-rw-r--r--help/PythonExamples/pleac_python/webautomation.html975
-rw-r--r--help/PythonTutorial/_sources/tutorial/index.txt62
-rw-r--r--help/PythonTutorial/_static/default.css210
-rw-r--r--help/PythonTutorial/_static/doctools.js232
-rw-r--r--help/PythonTutorial/_static/jquery.js32
-rw-r--r--help/PythonTutorial/_static/minus.pngbin0 -> 199 bytes
-rw-r--r--help/PythonTutorial/_static/opensearch.xml10
-rw-r--r--help/PythonTutorial/_static/py.pngbin0 -> 695 bytes
-rw-r--r--help/PythonTutorial/_static/pygments.css61
-rw-r--r--help/PythonTutorial/about.html374
-rw-r--r--help/PythonTutorial/copyright.html140
-rw-r--r--help/PythonTutorial/genindex.html177
-rw-r--r--help/PythonTutorial/glossary.html610
-rw-r--r--help/PythonTutorial/index.html189
-rw-r--r--help/PythonTutorial/library/library.info9
-rw-r--r--help/PythonTutorial/modindex.html1905
-rw-r--r--help/PythonTutorial/tutorial/appetite.html201
-rw-r--r--help/PythonTutorial/tutorial/classes.html838
-rw-r--r--help/PythonTutorial/tutorial/controlflow.html695
-rw-r--r--help/PythonTutorial/tutorial/datastructures.html739
-rw-r--r--help/PythonTutorial/tutorial/errors.html510
-rw-r--r--help/PythonTutorial/tutorial/floatingpoint.html333
-rw-r--r--help/PythonTutorial/tutorial/index.html337
-rw-r--r--help/PythonTutorial/tutorial/inputoutput.html506
-rw-r--r--help/PythonTutorial/tutorial/interactive.html281
-rw-r--r--help/PythonTutorial/tutorial/interpreter.html356
-rw-r--r--help/PythonTutorial/tutorial/introduction.html751
-rw-r--r--help/PythonTutorial/tutorial/modules.html636
-rw-r--r--help/PythonTutorial/tutorial/stdlib.html413
-rw-r--r--help/PythonTutorial/tutorial/stdlib2.html496
-rw-r--r--help/PythonTutorial/tutorial/whatnow.html186
-rw-r--r--help/PythonTutorial/whatsnew/2.0.html1177
-rw-r--r--help/application.html51
-rw-r--r--help/byteofpython/read/about-the-author.html17
-rw-r--r--help/byteofpython/read/about.html29
-rw-r--r--help/byteofpython/read/assert-statement.html26
-rw-r--r--help/byteofpython/read/basics-summary.html13
-rw-r--r--help/byteofpython/read/basics.html23
-rw-r--r--help/byteofpython/read/break-statement.html74
-rw-r--r--help/byteofpython/read/byte-compiled.html18
-rw-r--r--help/byteofpython/read/byte.css121
-rw-r--r--help/byteofpython/read/choosing-an-editor.html58
-rw-r--r--help/byteofpython/read/class-and-object-vars.html186
-rw-r--r--help/byteofpython/read/class-init.html65
-rw-r--r--help/byteofpython/read/classes.html50
-rw-r--r--help/byteofpython/read/continue-statement.html51
-rw-r--r--help/byteofpython/read/control-flow-summary.html18
-rw-r--r--help/byteofpython/read/control-flow.html21
-rw-r--r--help/byteofpython/read/data-structures-summary.html17
-rw-r--r--help/byteofpython/read/data-structures.html18
-rw-r--r--help/byteofpython/read/data-type-object.html97
-rw-r--r--help/byteofpython/read/data-types.html14
-rw-r--r--help/byteofpython/read/default-argument-values.html69
-rw-r--r--help/byteofpython/read/dictionary.html130
-rw-r--r--help/byteofpython/read/dir.html78
-rw-r--r--help/byteofpython/read/docstrings.html85
-rw-r--r--help/byteofpython/read/exceptions-summary.html17
-rw-r--r--help/byteofpython/read/exceptions.html43
-rw-r--r--help/byteofpython/read/exec-statement.html29
-rw-r--r--help/byteofpython/read/executable-python-programs.html79
-rw-r--r--help/byteofpython/read/explore-more.html89
-rw-r--r--help/byteofpython/read/expressions.html44
-rw-r--r--help/byteofpython/read/features-of-python.html123
-rw-r--r--help/byteofpython/read/feedback.html12
-rw-r--r--help/byteofpython/read/first-steps-summary.html12
-rw-r--r--help/byteofpython/read/first-steps.html17
-rw-r--r--help/byteofpython/read/floss.html177
-rw-r--r--help/byteofpython/read/for-loop.html93
-rw-r--r--help/byteofpython/read/for-windows-users.html49
-rw-r--r--help/byteofpython/read/from-import.html18
-rw-r--r--help/byteofpython/read/function-parameters.html62
-rw-r--r--help/byteofpython/read/functions-summary.html17
-rw-r--r--help/byteofpython/read/functions.html47
-rw-r--r--help/byteofpython/read/getting-help.html51
-rw-r--r--help/byteofpython/read/history-lesson.html38
-rw-r--r--help/byteofpython/read/identifier.html42
-rw-r--r--help/byteofpython/read/if-statement.html140
-rw-r--r--help/byteofpython/read/images/home.gifbin0 -> 321 bytes
-rw-r--r--help/byteofpython/read/images/next.gifbin0 -> 1083 bytes
-rw-r--r--help/byteofpython/read/images/prev.gifbin0 -> 1118 bytes
-rw-r--r--help/byteofpython/read/images/up.gifbin0 -> 1089 bytes
-rw-r--r--help/byteofpython/read/indentation.html68
-rw-r--r--help/byteofpython/read/index.html14
-rw-r--r--help/byteofpython/read/inheritance.html161
-rw-r--r--help/byteofpython/read/installation-summary.html19
-rw-r--r--help/byteofpython/read/installing-python.html68
-rw-r--r--help/byteofpython/read/interpreter-prompt.html52
-rw-r--r--help/byteofpython/read/introduction.html38
-rw-r--r--help/byteofpython/read/io-summary.html16
-rw-r--r--help/byteofpython/read/io.html100
-rw-r--r--help/byteofpython/read/keyword-arguments.html69
-rw-r--r--help/byteofpython/read/lambda-forms.html42
-rw-r--r--help/byteofpython/read/license.html20
-rw-r--r--help/byteofpython/read/list-comprehension.html37
-rw-r--r--help/byteofpython/read/list.html150
-rw-r--r--help/byteofpython/read/local-variables.html106
-rw-r--r--help/byteofpython/read/logical-and-physical-lines.html113
-rw-r--r--help/byteofpython/read/making-modules.html81
-rw-r--r--help/byteofpython/read/module-name.html42
-rw-r--r--help/byteofpython/read/modules-summary.html17
-rw-r--r--help/byteofpython/read/modules.html119
-rw-r--r--help/byteofpython/read/more-about-strings.html63
-rw-r--r--help/byteofpython/read/more-python-summary.html18
-rw-r--r--help/byteofpython/read/more-python.html63
-rw-r--r--help/byteofpython/read/numbers.html33
-rw-r--r--help/byteofpython/read/object-methods.html37
-rw-r--r--help/byteofpython/read/official-website.html11
-rw-r--r--help/byteofpython/read/oops-summary.html18
-rw-r--r--help/byteofpython/read/oops.html59
-rw-r--r--help/byteofpython/read/operator-precedence.html57
-rw-r--r--help/byteofpython/read/operators-expressions-summary.html13
-rw-r--r--help/byteofpython/read/operators-expressions.html20
-rw-r--r--help/byteofpython/read/operators.html256
-rw-r--r--help/byteofpython/read/os-module.html81
-rw-r--r--help/byteofpython/read/pickle.html71
-rw-r--r--help/byteofpython/read/preface.html27
-rw-r--r--help/byteofpython/read/problem-solving-summary.html17
-rw-r--r--help/byteofpython/read/problem-solving.html57
-rw-r--r--help/byteofpython/read/raising-exceptions.html72
-rw-r--r--help/byteofpython/read/references.html71
-rw-r--r--help/byteofpython/read/repr-function.html30
-rw-r--r--help/byteofpython/read/return.html64
-rw-r--r--help/byteofpython/read/revhistory.html48
-rw-r--r--help/byteofpython/read/self.html43
-rw-r--r--help/byteofpython/read/sequences.html120
-rw-r--r--help/byteofpython/read/single-statement-blocks.html40
-rw-r--r--help/byteofpython/read/software-development-process.html44
-rw-r--r--help/byteofpython/read/something-to-think-about.html14
-rw-r--r--help/byteofpython/read/source-file.html91
-rw-r--r--help/byteofpython/read/status.html15
-rw-r--r--help/byteofpython/read/stdlib-summary.html18
-rw-r--r--help/byteofpython/read/stdlib.html20
-rw-r--r--help/byteofpython/read/strings.html139
-rw-r--r--help/byteofpython/read/sys-module.html137
-rw-r--r--help/byteofpython/read/the-solution.html471
-rw-r--r--help/byteofpython/read/try-except.html92
-rw-r--r--help/byteofpython/read/try-finally.html60
-rw-r--r--help/byteofpython/read/tuple.html150
-rw-r--r--help/byteofpython/read/tuples-lists-functions.html35
-rw-r--r--help/byteofpython/read/variables.html16
-rw-r--r--help/byteofpython/read/what-next-summary.html15
-rw-r--r--help/byteofpython/read/what-next.html119
-rw-r--r--help/byteofpython/read/what-programmers-say.html45
-rw-r--r--help/byteofpython/read/while-statement.html98
-rw-r--r--help/byteofpython/read/why-not-perl.html49
-rw-r--r--help/diveintopython-5.4/html/appendix/about.html68
-rw-r--r--help/diveintopython-5.4/html/appendix/abstracts.html1163
-rw-r--r--help/diveintopython-5.4/html/appendix/examples.html1110
-rw-r--r--help/diveintopython-5.4/html/appendix/fdl.html124
-rw-r--r--help/diveintopython-5.4/html/appendix/fdl_aggregation.html81
-rw-r--r--help/diveintopython-5.4/html/appendix/fdl_applicability.html128
-rw-r--r--help/diveintopython-5.4/html/appendix/fdl_collections.html77
-rw-r--r--help/diveintopython-5.4/html/appendix/fdl_combining.html87
-rw-r--r--help/diveintopython-5.4/html/appendix/fdl_copying.html78
-rw-r--r--help/diveintopython-5.4/html/appendix/fdl_copyinginquantity.html102
-rw-r--r--help/diveintopython-5.4/html/appendix/fdl_future.html80
-rw-r--r--help/diveintopython-5.4/html/appendix/fdl_howto.html94
-rw-r--r--help/diveintopython-5.4/html/appendix/fdl_modifications.html179
-rw-r--r--help/diveintopython-5.4/html/appendix/fdl_termination.html73
-rw-r--r--help/diveintopython-5.4/html/appendix/fdl_translation.html76
-rw-r--r--help/diveintopython-5.4/html/appendix/furtherreading.html468
-rw-r--r--help/diveintopython-5.4/html/appendix/history.html1068
-rw-r--r--help/diveintopython-5.4/html/appendix/license.html120
-rw-r--r--help/diveintopython-5.4/html/appendix/license_terms.html305
-rw-r--r--help/diveintopython-5.4/html/appendix/tips.html839
-rw-r--r--help/diveintopython-5.4/html/diveintopython.css187
-rw-r--r--help/diveintopython-5.4/html/dynamic_functions/index.html121
-rw-r--r--help/diveintopython-5.4/html/dynamic_functions/stage1.html235
-rw-r--r--help/diveintopython-5.4/html/dynamic_functions/stage2.html158
-rw-r--r--help/diveintopython-5.4/html/dynamic_functions/stage3.html120
-rw-r--r--help/diveintopython-5.4/html/dynamic_functions/stage4.html212
-rw-r--r--help/diveintopython-5.4/html/dynamic_functions/stage5.html148
-rw-r--r--help/diveintopython-5.4/html/dynamic_functions/stage6.html256
-rw-r--r--help/diveintopython-5.4/html/dynamic_functions/summary.html86
-rw-r--r--help/diveintopython-5.4/html/file_handling/all_together.html132
-rw-r--r--help/diveintopython-5.4/html/file_handling/file_objects.html403
-rw-r--r--help/diveintopython-5.4/html/file_handling/for_loops.html224
-rw-r--r--help/diveintopython-5.4/html/file_handling/index.html276
-rw-r--r--help/diveintopython-5.4/html/file_handling/more_on_modules.html200
-rw-r--r--help/diveintopython-5.4/html/file_handling/os_module.html322
-rw-r--r--help/diveintopython-5.4/html/file_handling/summary.html161
-rw-r--r--help/diveintopython-5.4/html/functional_programming/all_together.html261
-rw-r--r--help/diveintopython-5.4/html/functional_programming/data_centric.html96
-rw-r--r--help/diveintopython-5.4/html/functional_programming/dynamic_import.html161
-rw-r--r--help/diveintopython-5.4/html/functional_programming/filtering_lists.html169
-rw-r--r--help/diveintopython-5.4/html/functional_programming/finding_the_path.html251
-rw-r--r--help/diveintopython-5.4/html/functional_programming/index.html187
-rw-r--r--help/diveintopython-5.4/html/functional_programming/mapping_lists.html155
-rw-r--r--help/diveintopython-5.4/html/functional_programming/summary.html81
-rw-r--r--help/diveintopython-5.4/html/getting_to_know_python/declaring_functions.html132
-rw-r--r--help/diveintopython-5.4/html/getting_to_know_python/documenting_functions.html107
-rw-r--r--help/diveintopython-5.4/html/getting_to_know_python/everything_is_an_object.html196
-rw-r--r--help/diveintopython-5.4/html/getting_to_know_python/indenting_code.html142
-rw-r--r--help/diveintopython-5.4/html/getting_to_know_python/index.html148
-rw-r--r--help/diveintopython-5.4/html/getting_to_know_python/testing_modules.html106
-rw-r--r--help/diveintopython-5.4/html/history.xml1
-rw-r--r--help/diveintopython-5.4/html/html_processing/all_together.html181
-rw-r--r--help/diveintopython-5.4/html/html_processing/basehtmlprocessor.html205
-rw-r--r--help/diveintopython-5.4/html/html_processing/dialect.html227
-rw-r--r--help/diveintopython-5.4/html/html_processing/dictionary_based_string_formatting.html167
-rw-r--r--help/diveintopython-5.4/html/html_processing/extracting_data.html229
-rw-r--r--help/diveintopython-5.4/html/html_processing/index.html336
-rw-r--r--help/diveintopython-5.4/html/html_processing/introducing_sgmllib.html173
-rw-r--r--help/diveintopython-5.4/html/html_processing/locals_and_globals.html267
-rw-r--r--help/diveintopython-5.4/html/html_processing/quoting_attribute_values.html130
-rw-r--r--help/diveintopython-5.4/html/html_processing/summary.html86
-rw-r--r--help/diveintopython-5.4/html/http_web_services/alltogether.html258
-rw-r--r--help/diveintopython-5.4/html/http_web_services/debugging.html150
-rw-r--r--help/diveintopython-5.4/html/http_web_services/etags.html279
-rw-r--r--help/diveintopython-5.4/html/http_web_services/gzip_compression.html223
-rw-r--r--help/diveintopython-5.4/html/http_web_services/http_features.html186
-rw-r--r--help/diveintopython-5.4/html/http_web_services/index.html236
-rw-r--r--help/diveintopython-5.4/html/http_web_services/redirects.html345
-rw-r--r--help/diveintopython-5.4/html/http_web_services/review.html100
-rw-r--r--help/diveintopython-5.4/html/http_web_services/summary.html83
-rw-r--r--help/diveintopython-5.4/html/http_web_services/user_agent.html178
-rw-r--r--help/diveintopython-5.4/html/images/callouts/1.pngbin0 -> 329 bytes
-rw-r--r--help/diveintopython-5.4/html/images/callouts/10.pngbin0 -> 361 bytes
-rw-r--r--help/diveintopython-5.4/html/images/callouts/2.pngbin0 -> 353 bytes
-rw-r--r--help/diveintopython-5.4/html/images/callouts/3.pngbin0 -> 350 bytes
-rw-r--r--help/diveintopython-5.4/html/images/callouts/4.pngbin0 -> 345 bytes
-rw-r--r--help/diveintopython-5.4/html/images/callouts/5.pngbin0 -> 348 bytes
-rw-r--r--help/diveintopython-5.4/html/images/callouts/6.pngbin0 -> 355 bytes
-rw-r--r--help/diveintopython-5.4/html/images/callouts/7.pngbin0 -> 344 bytes
-rw-r--r--help/diveintopython-5.4/html/images/callouts/8.pngbin0 -> 357 bytes
-rw-r--r--help/diveintopython-5.4/html/images/callouts/9.pngbin0 -> 357 bytes
-rw-r--r--help/diveintopython-5.4/html/images/caution.pngbin0 -> 1250 bytes
-rw-r--r--help/diveintopython-5.4/html/images/diveintopython.pngbin0 -> 2487 bytes
-rw-r--r--help/diveintopython-5.4/html/images/dot.pngbin0 -> 90 bytes
-rw-r--r--help/diveintopython-5.4/html/images/important.pngbin0 -> 1293 bytes
-rw-r--r--help/diveintopython-5.4/html/images/note.pngbin0 -> 490 bytes
-rw-r--r--help/diveintopython-5.4/html/images/tip.pngbin0 -> 449 bytes
-rw-r--r--help/diveintopython-5.4/html/images/warning.pngbin0 -> 1241 bytes
-rw-r--r--help/diveintopython-5.4/html/index.html208
-rw-r--r--help/diveintopython-5.4/html/installing_python/debian.html102
-rw-r--r--help/diveintopython-5.4/html/installing_python/index.html106
-rw-r--r--help/diveintopython-5.4/html/installing_python/macos9.html111
-rw-r--r--help/diveintopython-5.4/html/installing_python/macosx.html172
-rw-r--r--help/diveintopython-5.4/html/installing_python/redhat.html118
-rw-r--r--help/diveintopython-5.4/html/installing_python/shell.html107
-rw-r--r--help/diveintopython-5.4/html/installing_python/source.html106
-rw-r--r--help/diveintopython-5.4/html/installing_python/summary.html72
-rw-r--r--help/diveintopython-5.4/html/installing_python/windows.html154
-rw-r--r--help/diveintopython-5.4/html/native_data_types/chef.html506
-rw-r--r--help/diveintopython-5.4/html/native_data_types/declaring_variables.html200
-rw-r--r--help/diveintopython-5.4/html/native_data_types/formatting_strings.html187
-rw-r--r--help/diveintopython-5.4/html/native_data_types/fudd.html506
-rw-r--r--help/diveintopython-5.4/html/native_data_types/index.html346
-rw-r--r--help/diveintopython-5.4/html/native_data_types/joining_lists.html165
-rw-r--r--help/diveintopython-5.4/html/native_data_types/lists.html506
-rw-r--r--help/diveintopython-5.4/html/native_data_types/mapping_lists.html180
-rw-r--r--help/diveintopython-5.4/html/native_data_types/olde.html506
-rw-r--r--help/diveintopython-5.4/html/native_data_types/summary.html107
-rw-r--r--help/diveintopython-5.4/html/native_data_types/tuples.html185
-rw-r--r--help/diveintopython-5.4/html/object_oriented_framework/class_attributes.html189
-rw-r--r--help/diveintopython-5.4/html/object_oriented_framework/defining_classes.html275
-rw-r--r--help/diveintopython-5.4/html/object_oriented_framework/importing_modules.html161
-rw-r--r--help/diveintopython-5.4/html/object_oriented_framework/index.html249
-rw-r--r--help/diveintopython-5.4/html/object_oriented_framework/instantiating_classes.html173
-rw-r--r--help/diveintopython-5.4/html/object_oriented_framework/private_functions.html119
-rw-r--r--help/diveintopython-5.4/html/object_oriented_framework/special_class_methods.html234
-rw-r--r--help/diveintopython-5.4/html/object_oriented_framework/special_class_methods2.html144
-rw-r--r--help/diveintopython-5.4/html/object_oriented_framework/summary.html85
-rw-r--r--help/diveintopython-5.4/html/object_oriented_framework/userdict.html244
-rw-r--r--help/diveintopython-5.4/html/performance_tuning/dictionary_lookups.html210
-rw-r--r--help/diveintopython-5.4/html/performance_tuning/index.html223
-rw-r--r--help/diveintopython-5.4/html/performance_tuning/list_operations.html180
-rw-r--r--help/diveintopython-5.4/html/performance_tuning/regular_expressions.html235
-rw-r--r--help/diveintopython-5.4/html/performance_tuning/string_manipulation.html155
-rw-r--r--help/diveintopython-5.4/html/performance_tuning/summary.html88
-rw-r--r--help/diveintopython-5.4/html/performance_tuning/timeit.html146
-rw-r--r--help/diveintopython-5.4/html/power_of_introspection/all_together.html211
-rw-r--r--help/diveintopython-5.4/html/power_of_introspection/and_or.html229
-rw-r--r--help/diveintopython-5.4/html/power_of_introspection/built_in_functions.html322
-rw-r--r--help/diveintopython-5.4/html/power_of_introspection/filtering_lists.html129
-rw-r--r--help/diveintopython-5.4/html/power_of_introspection/getattr.html260
-rw-r--r--help/diveintopython-5.4/html/power_of_introspection/index.html193
-rw-r--r--help/diveintopython-5.4/html/power_of_introspection/lambda_functions.html189
-rw-r--r--help/diveintopython-5.4/html/power_of_introspection/optional_arguments.html130
-rw-r--r--help/diveintopython-5.4/html/power_of_introspection/summary.html115
-rw-r--r--help/diveintopython-5.4/html/refactoring/handling_changing_requirements.html456
-rw-r--r--help/diveintopython-5.4/html/refactoring/index.html223
-rw-r--r--help/diveintopython-5.4/html/refactoring/postscript.html169
-rw-r--r--help/diveintopython-5.4/html/refactoring/refactoring.html320
-rw-r--r--help/diveintopython-5.4/html/refactoring/summary.html116
-rw-r--r--help/diveintopython-5.4/html/regular_expressions/index.html110
-rw-r--r--help/diveintopython-5.4/html/regular_expressions/n_m_syntax.html283
-rw-r--r--help/diveintopython-5.4/html/regular_expressions/phone_numbers.html401
-rw-r--r--help/diveintopython-5.4/html/regular_expressions/roman_numerals.html288
-rw-r--r--help/diveintopython-5.4/html/regular_expressions/street_addresses.html172
-rw-r--r--help/diveintopython-5.4/html/regular_expressions/summary.html116
-rw-r--r--help/diveintopython-5.4/html/regular_expressions/verbose.html136
-rw-r--r--help/diveintopython-5.4/html/scripts_and_streams/all_together.html142
-rw-r--r--help/diveintopython-5.4/html/scripts_and_streams/caching.html118
-rw-r--r--help/diveintopython-5.4/html/scripts_and_streams/child_nodes.html106
-rw-r--r--help/diveintopython-5.4/html/scripts_and_streams/command_line_arguments.html293
-rw-r--r--help/diveintopython-5.4/html/scripts_and_streams/handlers_by_node_type.html187
-rw-r--r--help/diveintopython-5.4/html/scripts_and_streams/index.html366
-rw-r--r--help/diveintopython-5.4/html/scripts_and_streams/stdin_stdout_stderr.html317
-rw-r--r--help/diveintopython-5.4/html/scripts_and_streams/summary.html79
-rw-r--r--help/diveintopython-5.4/html/soap_web_services/debugging.html200
-rw-r--r--help/diveintopython-5.4/html/soap_web_services/first_steps.html111
-rw-r--r--help/diveintopython-5.4/html/soap_web_services/google.html236
-rw-r--r--help/diveintopython-5.4/html/soap_web_services/index.html178
-rw-r--r--help/diveintopython-5.4/html/soap_web_services/install.html226
-rw-r--r--help/diveintopython-5.4/html/soap_web_services/introspection.html232
-rw-r--r--help/diveintopython-5.4/html/soap_web_services/summary.html84
-rw-r--r--help/diveintopython-5.4/html/soap_web_services/troubleshooting.html271
-rw-r--r--help/diveintopython-5.4/html/soap_web_services/wsdl.html99
-rw-r--r--help/diveintopython-5.4/html/toc/index.html393
-rw-r--r--help/diveintopython-5.4/html/unit_testing/diving_in.html102
-rw-r--r--help/diveintopython-5.4/html/unit_testing/index.html138
-rw-r--r--help/diveintopython-5.4/html/unit_testing/romantest.html221
-rw-r--r--help/diveintopython-5.4/html/unit_testing/stage_1.html297
-rw-r--r--help/diveintopython-5.4/html/unit_testing/stage_2.html289
-rw-r--r--help/diveintopython-5.4/html/unit_testing/stage_3.html268
-rw-r--r--help/diveintopython-5.4/html/unit_testing/stage_4.html206
-rw-r--r--help/diveintopython-5.4/html/unit_testing/stage_5.html222
-rw-r--r--help/diveintopython-5.4/html/unit_testing/testing_for_failure.html164
-rw-r--r--help/diveintopython-5.4/html/unit_testing/testing_for_sanity.html181
-rw-r--r--help/diveintopython-5.4/html/unit_testing/testing_for_success.html195
-rw-r--r--help/diveintopython-5.4/html/xml_processing/attributes.html164
-rw-r--r--help/diveintopython-5.4/html/xml_processing/index.html447
-rw-r--r--help/diveintopython-5.4/html/xml_processing/packages.html165
-rw-r--r--help/diveintopython-5.4/html/xml_processing/parsing_xml.html279
-rw-r--r--help/diveintopython-5.4/html/xml_processing/searching.html181
-rw-r--r--help/diveintopython-5.4/html/xml_processing/summary.html78
-rw-r--r--help/diveintopython-5.4/html/xml_processing/unicode.html308
-rw-r--r--help/diveintopython-5.4/py/BaseHTMLProcessor.py93
-rw-r--r--help/diveintopython-5.4/py/LICENSE.txt234
-rw-r--r--help/diveintopython-5.4/py/apihelper.py47
-rw-r--r--help/diveintopython-5.4/py/apihelpertest.py62
-rw-r--r--help/diveintopython-5.4/py/argecho.py17
-rw-r--r--help/diveintopython-5.4/py/autosize.py83
-rw-r--r--help/diveintopython-5.4/py/builddialectexamples.py32
-rw-r--r--help/diveintopython-5.4/py/colorize.py142
-rw-r--r--help/diveintopython-5.4/py/dialect.py166
-rw-r--r--help/diveintopython-5.4/py/fibonacci.py21
-rw-r--r--help/diveintopython-5.4/py/fileinfo.py86
-rw-r--r--help/diveintopython-5.4/py/fileinfo_fromdict.py75
-rw-r--r--help/diveintopython-5.4/py/fullpath.py6
-rw-r--r--help/diveintopython-5.4/py/kgp/binary.xml11
-rw-r--r--help/diveintopython-5.4/py/kgp/husserl.xml178
-rw-r--r--help/diveintopython-5.4/py/kgp/kant.xml306
-rw-r--r--help/diveintopython-5.4/py/kgp/kgp.dtd9
-rw-r--r--help/diveintopython-5.4/py/kgp/kgp.py251
-rw-r--r--help/diveintopython-5.4/py/kgp/russiansample.xml4
-rw-r--r--help/diveintopython-5.4/py/kgp/stderr.py5
-rw-r--r--help/diveintopython-5.4/py/kgp/stdout.py9
-rw-r--r--help/diveintopython-5.4/py/kgp/template.xml1
-rw-r--r--help/diveintopython-5.4/py/kgp/test.xml26
-rw-r--r--help/diveintopython-5.4/py/kgp/thanks.xml436
-rw-r--r--help/diveintopython-5.4/py/kgp/toolbox.py58
-rw-r--r--help/diveintopython-5.4/py/kgptest.py65
-rw-r--r--help/diveintopython-5.4/py/makerealworddoc.py62
-rw-r--r--help/diveintopython-5.4/py/odbchelper.py30
-rw-r--r--help/diveintopython-5.4/py/odbchelpertest.py47
-rw-r--r--help/diveintopython-5.4/py/openanything.py107
-rw-r--r--help/diveintopython-5.4/py/parsephone.py37
-rw-r--r--help/diveintopython-5.4/py/piglatin.py33
-rw-r--r--help/diveintopython-5.4/py/plural-rules.en19
-rw-r--r--help/diveintopython-5.4/py/plural.py36
-rw-r--r--help/diveintopython-5.4/py/plural/stage1/plural1.py35
-rw-r--r--help/diveintopython-5.4/py/plural/stage1/pluraltest1.py50
-rw-r--r--help/diveintopython-5.4/py/plural/stage2/plural2.py60
-rw-r--r--help/diveintopython-5.4/py/plural/stage2/pluraltest2.py50
-rw-r--r--help/diveintopython-5.4/py/plural/stage3/plural3.py50
-rw-r--r--help/diveintopython-5.4/py/plural/stage3/pluraltest3.py50
-rw-r--r--help/diveintopython-5.4/py/plural/stage4/plural4.py44
-rw-r--r--help/diveintopython-5.4/py/plural/stage4/pluraltest4.py50
-rw-r--r--help/diveintopython-5.4/py/plural/stage5/plural5.py37
-rw-r--r--help/diveintopython-5.4/py/plural/stage5/pluraltest5.py50
-rw-r--r--help/diveintopython-5.4/py/plural/stage5/rules.en4
-rw-r--r--help/diveintopython-5.4/py/plural/stage6/plural6.py35
-rw-r--r--help/diveintopython-5.4/py/plural/stage6/pluraltest6.py67
-rw-r--r--help/diveintopython-5.4/py/plural/stage6/rules.en15
-rw-r--r--help/diveintopython-5.4/py/pluraltest.py80
-rw-r--r--help/diveintopython-5.4/py/pyfontify.py131
-rw-r--r--help/diveintopython-5.4/py/regression.py34
-rw-r--r--help/diveintopython-5.4/py/roman.py77
-rw-r--r--help/diveintopython-5.4/py/roman/stage1/roman1.py26
-rw-r--r--help/diveintopython-5.4/py/roman/stage1/romantest1.py145
-rw-r--r--help/diveintopython-5.4/py/roman/stage2/roman2.py46
-rw-r--r--help/diveintopython-5.4/py/roman/stage2/romantest2.py145
-rw-r--r--help/diveintopython-5.4/py/roman/stage3/roman3.py51
-rw-r--r--help/diveintopython-5.4/py/roman/stage3/romantest3.py145
-rw-r--r--help/diveintopython-5.4/py/roman/stage4/roman4.py57
-rw-r--r--help/diveintopython-5.4/py/roman/stage4/romantest4.py145
-rw-r--r--help/diveintopython-5.4/py/roman/stage5/roman5.py65
-rw-r--r--help/diveintopython-5.4/py/roman/stage5/romantest5.py145
-rw-r--r--help/diveintopython-5.4/py/roman/stage6/roman61.py65
-rw-r--r--help/diveintopython-5.4/py/roman/stage6/roman62.py67
-rw-r--r--help/diveintopython-5.4/py/roman/stage6/romantest61.py149
-rw-r--r--help/diveintopython-5.4/py/roman/stage6/romantest62.py149
-rw-r--r--help/diveintopython-5.4/py/roman/stage7/roman71.py67
-rw-r--r--help/diveintopython-5.4/py/roman/stage7/roman72.py67
-rw-r--r--help/diveintopython-5.4/py/roman/stage7/romantest71.py153
-rw-r--r--help/diveintopython-5.4/py/roman/stage7/romantest72.py153
-rw-r--r--help/diveintopython-5.4/py/roman/stage8/roman81.py68
-rw-r--r--help/diveintopython-5.4/py/roman/stage8/roman82.py68
-rw-r--r--help/diveintopython-5.4/py/roman/stage8/roman83.py77
-rw-r--r--help/diveintopython-5.4/py/roman/stage8/romantest81.py153
-rw-r--r--help/diveintopython-5.4/py/roman/stage8/romantest82.py153
-rw-r--r--help/diveintopython-5.4/py/roman/stage8/romantest83.py153
-rw-r--r--help/diveintopython-5.4/py/roman/stage9/roman9.py83
-rw-r--r--help/diveintopython-5.4/py/roman/stage9/romantest9.py153
-rw-r--r--help/diveintopython-5.4/py/romantest.py153
-rw-r--r--help/diveintopython-5.4/py/search.py37
-rw-r--r--help/diveintopython-5.4/py/soundex.py53
-rw-r--r--help/diveintopython-5.4/py/soundex/stage1/soundex1a.py85
-rw-r--r--help/diveintopython-5.4/py/soundex/stage1/soundex1b.py84
-rw-r--r--help/diveintopython-5.4/py/soundex/stage1/soundex1c.py85
-rw-r--r--help/diveintopython-5.4/py/soundex/stage1/soundex1d.py87
-rw-r--r--help/diveintopython-5.4/py/soundex/stage1/soundex1e.py84
-rw-r--r--help/diveintopython-5.4/py/soundex/stage2/soundex2a.py80
-rw-r--r--help/diveintopython-5.4/py/soundex/stage2/soundex2b.py80
-rw-r--r--help/diveintopython-5.4/py/soundex/stage2/soundex2c.py55
-rw-r--r--help/diveintopython-5.4/py/soundex/stage3/soundex3a.py57
-rw-r--r--help/diveintopython-5.4/py/soundex/stage3/soundex3b.py53
-rw-r--r--help/diveintopython-5.4/py/soundex/stage3/soundex3c.py58
-rw-r--r--help/diveintopython-5.4/py/soundex/stage3/soundex3d.py55
-rw-r--r--help/diveintopython-5.4/py/soundex/stage4/soundex4a.py58
-rw-r--r--help/diveintopython-5.4/py/soundex/stage4/soundex4b.py55
-rw-r--r--help/diveintopython-5.4/py/soundex/stage4/soundex4c.py54
-rw-r--r--help/diveintopython-5.4/py/soundex/stage4/soundex4d.py49
-rw-r--r--help/diveintopython-5.4/py/soundextest.py41
-rw-r--r--help/diveintopython-5.4/py/statsout.py22
-rw-r--r--help/diveintopython-5.4/py/unicode2koi8r.py130
-rw-r--r--help/diveintopython-5.4/py/urllister.py33
-rw-r--r--help/images/3080617962_604fcfe2ed.jpgbin0 -> 103322 bytes
-rw-r--r--help/images/Edit Page.jpgbin0 -> 47584 bytes
-rw-r--r--help/images/Help Page.jpgbin0 -> 37168 bytes
-rw-r--r--help/images/Project Page.jpgbin0 -> 50374 bytes
-rw-r--r--help/images/Terminal_Ipython Page.jpgbin0 -> 32535 bytes
-rw-r--r--help/images/Your Program Output Page.jpgbin0 -> 12351 bytes
-rw-r--r--help/images/journal.jpgbin0 -> 48416 bytes
-rw-r--r--help/images/project page.pngbin0 -> 84156 bytes
-rw-r--r--help/images/project page_2.pngbin0 -> 21639 bytes
-rw-r--r--help/images/project page_3.pngbin0 -> 35978 bytes
-rw-r--r--help/images/project_whole.jpgbin0 -> 69876 bytes
-rw-r--r--help/ipythonbook/doc/rel-0.10/html/_images/inheritance471b45c3f1.pngbin0 -> 3756 bytes
-rw-r--r--help/ipythonbook/doc/rel-0.10/html/_sources/interactive/reference.txt1631
-rw-r--r--help/ipythonbook/doc/rel-0.10/html/_static/default.css657
-rw-r--r--help/ipythonbook/doc/rel-0.10/html/_static/doctools.js232
-rw-r--r--help/ipythonbook/doc/rel-0.10/html/_static/jquery.js32
-rw-r--r--help/ipythonbook/doc/rel-0.10/html/_static/minus.pngbin0 -> 199 bytes
-rw-r--r--help/ipythonbook/doc/rel-0.10/html/_static/pygments.css59
-rw-r--r--help/ipythonbook/doc/rel-0.10/html/api/generated/IPython.Magic.html1565
-rw-r--r--help/ipythonbook/doc/rel-0.10/html/config/customization.html375
-rw-r--r--help/ipythonbook/doc/rel-0.10/html/config/initial_config.html332
-rw-r--r--help/ipythonbook/doc/rel-0.10/html/genindex.html3114
-rw-r--r--help/ipythonbook/doc/rel-0.10/html/index.html342
-rw-r--r--help/ipythonbook/doc/rel-0.10/html/interactive/index.html152
-rw-r--r--help/ipythonbook/doc/rel-0.10/html/interactive/reference.html1651
-rw-r--r--help/ipythonbook/doc/rel-0.10/html/interactive/shell.html371
-rw-r--r--help/ipythonbook/doc/rel-0.10/html/interactive/tutorial.html408
-rw-r--r--help/ipythonbook/doc/rel-0.10/html/modindex.html613
-rw-r--r--help/ipythonbook/library/library.info9
-rw-r--r--help_pd.py195
-rw-r--r--history1000
-rw-r--r--icons/activity-become-root.svg7
-rw-r--r--ipy_user_conf.py117
-rw-r--r--ipythonrc632
-rw-r--r--lib/python2.5/site-packages/sugar/graphics/colorbutton.py531
-rw-r--r--lib/python2.6/site-packages/browser.py229
-rw-r--r--lib/python2.6/site-packages/sugar.save/activity/activityshim.py60
-rw-r--r--lib/python2.6/site-packages/sugar.save/activity/olpcactivity.pth2
-rw-r--r--lib/python2.6/site-packages/terminal.py308
-rw-r--r--locale/af/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 586 bytes
-rw-r--r--locale/af/activity.linfo2
-rw-r--r--locale/am/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 407 bytes
-rw-r--r--locale/am/activity.linfo2
-rw-r--r--locale/ar/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 610 bytes
-rw-r--r--locale/ar/activity.linfo2
-rw-r--r--locale/ay/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 407 bytes
-rw-r--r--locale/ay/activity.linfo2
-rw-r--r--locale/bg/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 407 bytes
-rw-r--r--locale/bg/activity.linfo2
-rw-r--r--locale/bi/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 407 bytes
-rw-r--r--locale/bi/activity.linfo2
-rw-r--r--locale/bn/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 407 bytes
-rw-r--r--locale/bn/activity.linfo2
-rw-r--r--locale/bn_IN/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 692 bytes
-rw-r--r--locale/bn_IN/activity.linfo2
-rw-r--r--locale/ca/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 407 bytes
-rw-r--r--locale/ca/activity.linfo2
-rw-r--r--locale/cpp/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 407 bytes
-rw-r--r--locale/cpp/activity.linfo2
-rw-r--r--locale/cs/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 407 bytes
-rw-r--r--locale/cs/activity.linfo2
-rw-r--r--locale/de/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 579 bytes
-rw-r--r--locale/de/activity.linfo2
-rw-r--r--locale/dz/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 407 bytes
-rw-r--r--locale/dz/activity.linfo2
-rw-r--r--locale/el/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 644 bytes
-rw-r--r--locale/el/activity.linfo2
-rw-r--r--locale/en/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 407 bytes
-rw-r--r--locale/en/activity.linfo2
-rw-r--r--locale/en_US/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 581 bytes
-rw-r--r--locale/en_US/activity.linfo2
-rw-r--r--locale/es/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 602 bytes
-rw-r--r--locale/es/activity.linfo2
-rw-r--r--locale/fa/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 407 bytes
-rw-r--r--locale/fa/activity.linfo2
-rw-r--r--locale/fa_AF/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 407 bytes
-rw-r--r--locale/fa_AF/activity.linfo2
-rw-r--r--locale/ff/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 407 bytes
-rw-r--r--locale/ff/activity.linfo2
-rw-r--r--locale/fi/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 407 bytes
-rw-r--r--locale/fi/activity.linfo2
-rw-r--r--locale/fr/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 589 bytes
-rw-r--r--locale/fr/activity.linfo2
-rw-r--r--locale/gu/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 407 bytes
-rw-r--r--locale/gu/activity.linfo2
-rw-r--r--locale/ha/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 407 bytes
-rw-r--r--locale/ha/activity.linfo2
-rw-r--r--locale/he/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 407 bytes
-rw-r--r--locale/he/activity.linfo2
-rw-r--r--locale/hi/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 407 bytes
-rw-r--r--locale/hi/activity.linfo2
-rw-r--r--locale/ht/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 407 bytes
-rw-r--r--locale/ht/activity.linfo2
-rw-r--r--locale/hu/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 407 bytes
-rw-r--r--locale/hu/activity.linfo2
-rw-r--r--locale/ig/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 407 bytes
-rw-r--r--locale/ig/activity.linfo2
-rw-r--r--locale/is/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 407 bytes
-rw-r--r--locale/is/activity.linfo2
-rw-r--r--locale/it/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 599 bytes
-rw-r--r--locale/it/activity.linfo2
-rw-r--r--locale/ja/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 629 bytes
-rw-r--r--locale/ja/activity.linfo2
-rw-r--r--locale/km/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 407 bytes
-rw-r--r--locale/km/activity.linfo2
-rw-r--r--locale/ko/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 407 bytes
-rw-r--r--locale/ko/activity.linfo2
-rw-r--r--locale/mi/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 407 bytes
-rw-r--r--locale/mi/activity.linfo2
-rw-r--r--locale/mk/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 407 bytes
-rw-r--r--locale/mk/activity.linfo2
-rw-r--r--locale/ml/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 407 bytes
-rw-r--r--locale/ml/activity.linfo2
-rw-r--r--locale/mn/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 680 bytes
-rw-r--r--locale/mn/activity.linfo2
-rw-r--r--locale/mr/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 653 bytes
-rw-r--r--locale/mr/activity.linfo2
-rw-r--r--locale/ms/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 407 bytes
-rw-r--r--locale/ms/activity.linfo2
-rw-r--r--locale/mvo/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 407 bytes
-rw-r--r--locale/mvo/activity.linfo2
-rw-r--r--locale/nb/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 476 bytes
-rw-r--r--locale/nb/activity.linfo2
-rw-r--r--locale/ne/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 646 bytes
-rw-r--r--locale/ne/activity.linfo2
-rw-r--r--locale/nl/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 584 bytes
-rw-r--r--locale/nl/activity.linfo2
-rw-r--r--locale/pa/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 407 bytes
-rw-r--r--locale/pa/activity.linfo2
-rw-r--r--locale/pap/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 573 bytes
-rw-r--r--locale/pap/activity.linfo2
-rw-r--r--locale/pis/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 407 bytes
-rw-r--r--locale/pis/activity.linfo2
-rw-r--r--locale/pl/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 407 bytes
-rw-r--r--locale/pl/activity.linfo2
-rw-r--r--locale/ps/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 407 bytes
-rw-r--r--locale/ps/activity.linfo2
-rw-r--r--locale/pt/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 586 bytes
-rw-r--r--locale/pt/activity.linfo2
-rw-r--r--locale/pt_BR/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 407 bytes
-rw-r--r--locale/pt_BR/activity.linfo2
-rw-r--r--locale/qu/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 407 bytes
-rw-r--r--locale/qu/activity.linfo2
-rw-r--r--locale/ro/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 407 bytes
-rw-r--r--locale/ro/activity.linfo2
-rw-r--r--locale/ru/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 407 bytes
-rw-r--r--locale/ru/activity.linfo2
-rw-r--r--locale/rw/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 598 bytes
-rw-r--r--locale/rw/activity.linfo2
-rw-r--r--locale/sd/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 407 bytes
-rw-r--r--locale/sd/activity.linfo2
-rw-r--r--locale/si/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 407 bytes
-rw-r--r--locale/si/activity.linfo2
-rw-r--r--locale/sk/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 407 bytes
-rw-r--r--locale/sk/activity.linfo2
-rw-r--r--locale/sl/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 582 bytes
-rw-r--r--locale/sl/activity.linfo2
-rw-r--r--locale/sv/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 600 bytes
-rw-r--r--locale/sv/activity.linfo2
-rw-r--r--locale/sw/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 407 bytes
-rw-r--r--locale/sw/activity.linfo2
-rw-r--r--locale/te/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 683 bytes
-rw-r--r--locale/te/activity.linfo2
-rw-r--r--locale/th/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 407 bytes
-rw-r--r--locale/th/activity.linfo2
-rw-r--r--locale/tpi/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 407 bytes
-rw-r--r--locale/tpi/activity.linfo2
-rw-r--r--locale/tr/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 585 bytes
-rw-r--r--locale/tr/activity.linfo2
-rw-r--r--locale/ug/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 407 bytes
-rw-r--r--locale/ug/activity.linfo2
-rw-r--r--locale/ur/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 608 bytes
-rw-r--r--locale/ur/activity.linfo2
-rw-r--r--locale/vi/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 624 bytes
-rw-r--r--locale/vi/activity.linfo2
-rw-r--r--locale/wa/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 407 bytes
-rw-r--r--locale/wa/activity.linfo2
-rw-r--r--locale/yo/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 407 bytes
-rw-r--r--locale/yo/activity.linfo2
-rw-r--r--locale/zh_CN/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 407 bytes
-rw-r--r--locale/zh_CN/activity.linfo2
-rw-r--r--locale/zh_TW/LC_MESSAGES/com.gmail.georgejhunt.mobin0 -> 580 bytes
-rw-r--r--locale/zh_TW/activity.linfo2
-rw-r--r--notebook.py151
-rw-r--r--notebook.py~150
-rw-r--r--po/Terminal.pot33
-rw-r--r--po/af.po32
-rw-r--r--po/am.po33
-rw-r--r--po/ar.po32
-rw-r--r--po/ay.po33
-rw-r--r--po/bg.po33
-rw-r--r--po/bi.po33
-rw-r--r--po/bn.po33
-rw-r--r--po/bn_IN.po32
-rw-r--r--po/ca.po33
-rw-r--r--po/cpp.po33
-rw-r--r--po/cs.po33
-rw-r--r--po/de.po32
-rw-r--r--po/dz.po33
-rw-r--r--po/el.po32
-rw-r--r--po/en.po33
-rw-r--r--po/en_US.po32
-rw-r--r--po/es.po32
-rw-r--r--po/fa.po33
-rw-r--r--po/fa_AF.po33
-rw-r--r--po/ff.po33
-rw-r--r--po/fi.po33
-rw-r--r--po/fr.po32
-rw-r--r--po/gu.po33
-rw-r--r--po/ha.po33
-rw-r--r--po/he.po33
-rw-r--r--po/hi.po33
-rw-r--r--po/ht.po33
-rw-r--r--po/hu.po33
-rw-r--r--po/ig.po33
-rw-r--r--po/is.po33
-rw-r--r--po/it.po32
-rw-r--r--po/ja.po32
-rw-r--r--po/km.po33
-rw-r--r--po/ko.po33
-rw-r--r--po/mi.po33
-rw-r--r--po/mk.po33
-rw-r--r--po/ml.po33
-rw-r--r--po/mn.po32
-rw-r--r--po/mr.po32
-rw-r--r--po/ms.po33
-rw-r--r--po/mvo.po33
-rw-r--r--po/nb.po34
-rw-r--r--po/ne.po32
-rw-r--r--po/nl.po32
-rw-r--r--po/pa.po33
-rw-r--r--po/pap.po32
-rw-r--r--po/pis.po33
-rw-r--r--po/pl.po33
-rw-r--r--po/ps.po33
-rw-r--r--po/pt.po32
-rw-r--r--po/pt_BR.po33
-rw-r--r--po/qu.po33
-rw-r--r--po/ro.po33
-rw-r--r--po/ru.po33
-rw-r--r--po/rw.po32
-rw-r--r--po/sd.po33
-rw-r--r--po/si.po33
-rw-r--r--po/sk.po33
-rw-r--r--po/sl.po32
-rw-r--r--po/sv.po32
-rw-r--r--po/sw.po33
-rw-r--r--po/te.po32
-rw-r--r--po/th.po33
-rw-r--r--po/tpi.po33
-rw-r--r--po/tr.po32
-rw-r--r--po/ug.po33
-rw-r--r--po/ur.po32
-rw-r--r--po/vi.po32
-rw-r--r--po/wa.po33
-rw-r--r--po/yo.po33
-rw-r--r--po/zh_CN.po33
-rw-r--r--po/zh_TW.po32
-rw-r--r--progresslistener.py89
-rw-r--r--project.glade949
-rw-r--r--pydebug.py1478
-rw-r--r--pydebug.py~1478
-rw-r--r--pydebug_logging.py47
-rw-r--r--pytoolbar.py192
-rw-r--r--pytoolbar.py~221
-rwxr-xr-xsetup.py22
-rw-r--r--sourceview_editor.py636
-rw-r--r--sourceview_editor.py~636
-rw-r--r--start_debug.py44
-rw-r--r--terminal_pd.py278
-rw-r--r--tmp.py4
-rw-r--r--vibrant.xml122
-rw-r--r--webview.py302
-rw-r--r--zope/__init__.py7
-rw-r--r--zope/interface/__init__.py80
-rw-r--r--zope/interface/_flatten.py37
-rw-r--r--zope/interface/adapter.py644
-rw-r--r--zope/interface/advice.py192
-rw-r--r--zope/interface/common/__init__.py2
-rw-r--r--zope/interface/common/idatetime.py577
-rw-r--r--zope/interface/common/interfaces.py98
-rw-r--r--zope/interface/common/mapping.py127
-rw-r--r--zope/interface/common/sequence.py152
-rw-r--r--zope/interface/declarations.py1386
-rw-r--r--zope/interface/document.py107
-rw-r--r--zope/interface/exceptions.py69
-rw-r--r--zope/interface/interface.py821
-rw-r--r--zope/interface/interfaces.py730
-rw-r--r--zope/interface/ro.py63
-rw-r--r--zope/interface/tests/__init__.py2
-rw-r--r--zope/interface/tests/dummy.py25
-rw-r--r--zope/interface/tests/ifoo.py28
-rw-r--r--zope/interface/tests/m1.py23
-rw-r--r--zope/interface/tests/m2.py17
-rw-r--r--zope/interface/tests/odd.py129
-rw-r--r--zope/interface/tests/test_adapter.py335
-rw-r--r--zope/interface/tests/test_advice.py178
-rw-r--r--zope/interface/tests/test_declarations.py416
-rw-r--r--zope/interface/tests/test_document.py71
-rw-r--r--zope/interface/tests/test_element.py43
-rw-r--r--zope/interface/tests/test_interface.py352
-rw-r--r--zope/interface/tests/test_odd_declarations.py204
-rw-r--r--zope/interface/tests/test_sorting.py49
-rw-r--r--zope/interface/tests/test_verify.py196
-rw-r--r--zope/interface/tests/unitfixtures.py142
-rw-r--r--zope/interface/verify.py111
1454 files changed, 219186 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..762497d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+#don't include python compilations
+*.pyc
diff --git a/IPython/ColorANSI.py b/IPython/ColorANSI.py
new file mode 100644
index 0000000..783aa1d
--- /dev/null
+++ b/IPython/ColorANSI.py
@@ -0,0 +1,177 @@
+# -*- coding: utf-8 -*-
+"""Tools for coloring text in ANSI terminals.
+"""
+
+#*****************************************************************************
+# Copyright (C) 2002-2006 Fernando Perez. <fperez@colorado.edu>
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#*****************************************************************************
+
+__all__ = ['TermColors','InputTermColors','ColorScheme','ColorSchemeTable']
+
+import os
+
+from IPython.ipstruct import Struct
+
+def make_color_table(in_class):
+ """Build a set of color attributes in a class.
+
+ Helper function for building the *TermColors classes."""
+
+ color_templates = (
+ # Dark colors
+ ("Black" , "0;30"),
+ ("Red" , "0;31"),
+ ("Green" , "0;32"),
+ ("Brown" , "0;33"),
+ ("Blue" , "0;34"),
+ ("Purple" , "0;35"),
+ ("Cyan" , "0;36"),
+ ("LightGray" , "0;37"),
+ # Light colors
+ ("DarkGray" , "1;30"),
+ ("LightRed" , "1;31"),
+ ("LightGreen" , "1;32"),
+ ("Yellow" , "1;33"),
+ ("LightBlue" , "1;34"),
+ ("LightPurple" , "1;35"),
+ ("LightCyan" , "1;36"),
+ ("White" , "1;37"),
+ # Blinking colors. Probably should not be used in anything serious.
+ ("BlinkBlack" , "5;30"),
+ ("BlinkRed" , "5;31"),
+ ("BlinkGreen" , "5;32"),
+ ("BlinkYellow" , "5;33"),
+ ("BlinkBlue" , "5;34"),
+ ("BlinkPurple" , "5;35"),
+ ("BlinkCyan" , "5;36"),
+ ("BlinkLightGray", "5;37"),
+ )
+
+ for name,value in color_templates:
+ setattr(in_class,name,in_class._base % value)
+
+class TermColors:
+ """Color escape sequences.
+
+ This class defines the escape sequences for all the standard (ANSI?)
+ colors in terminals. Also defines a NoColor escape which is just the null
+ string, suitable for defining 'dummy' color schemes in terminals which get
+ confused by color escapes.
+
+ This class should be used as a mixin for building color schemes."""
+
+ NoColor = '' # for color schemes in color-less terminals.
+ Normal = '\033[0m' # Reset normal coloring
+ _base = '\033[%sm' # Template for all other colors
+
+# Build the actual color table as a set of class attributes:
+make_color_table(TermColors)
+
+class InputTermColors:
+ """Color escape sequences for input prompts.
+
+ This class is similar to TermColors, but the escapes are wrapped in \001
+ and \002 so that readline can properly know the length of each line and
+ can wrap lines accordingly. Use this class for any colored text which
+ needs to be used in input prompts, such as in calls to raw_input().
+
+ This class defines the escape sequences for all the standard (ANSI?)
+ colors in terminals. Also defines a NoColor escape which is just the null
+ string, suitable for defining 'dummy' color schemes in terminals which get
+ confused by color escapes.
+
+ This class should be used as a mixin for building color schemes."""
+
+ NoColor = '' # for color schemes in color-less terminals.
+
+ if os.name == 'nt' and os.environ.get('TERM','dumb') == 'emacs':
+ # (X)emacs on W32 gets confused with \001 and \002 so we remove them
+ Normal = '\033[0m' # Reset normal coloring
+ _base = '\033[%sm' # Template for all other colors
+ else:
+ Normal = '\001\033[0m\002' # Reset normal coloring
+ _base = '\001\033[%sm\002' # Template for all other colors
+
+# Build the actual color table as a set of class attributes:
+make_color_table(InputTermColors)
+
+class ColorScheme:
+ """Generic color scheme class. Just a name and a Struct."""
+ def __init__(self,__scheme_name_,colordict=None,**colormap):
+ self.name = __scheme_name_
+ if colordict is None:
+ self.colors = Struct(**colormap)
+ else:
+ self.colors = Struct(colordict)
+
+ def copy(self,name=None):
+ """Return a full copy of the object, optionally renaming it."""
+ if name is None:
+ name = self.name
+ return ColorScheme(name,self.colors.__dict__)
+
+class ColorSchemeTable(dict):
+ """General class to handle tables of color schemes.
+
+ It's basically a dict of color schemes with a couple of shorthand
+ attributes and some convenient methods.
+
+ active_scheme_name -> obvious
+ active_colors -> actual color table of the active scheme"""
+
+ def __init__(self,scheme_list=None,default_scheme=''):
+ """Create a table of color schemes.
+
+ The table can be created empty and manually filled or it can be
+ created with a list of valid color schemes AND the specification for
+ the default active scheme.
+ """
+
+ # create object attributes to be set later
+ self.active_scheme_name = ''
+ self.active_colors = None
+
+ if scheme_list:
+ if default_scheme == '':
+ raise ValueError,'you must specify the default color scheme'
+ for scheme in scheme_list:
+ self.add_scheme(scheme)
+ self.set_active_scheme(default_scheme)
+
+ def copy(self):
+ """Return full copy of object"""
+ return ColorSchemeTable(self.values(),self.active_scheme_name)
+
+ def add_scheme(self,new_scheme):
+ """Add a new color scheme to the table."""
+ if not isinstance(new_scheme,ColorScheme):
+ raise ValueError,'ColorSchemeTable only accepts ColorScheme instances'
+ self[new_scheme.name] = new_scheme
+
+ def set_active_scheme(self,scheme,case_sensitive=0):
+ """Set the currently active scheme.
+
+ Names are by default compared in a case-insensitive way, but this can
+ be changed by setting the parameter case_sensitive to true."""
+
+ scheme_names = self.keys()
+ if case_sensitive:
+ valid_schemes = scheme_names
+ scheme_test = scheme
+ else:
+ valid_schemes = [s.lower() for s in scheme_names]
+ scheme_test = scheme.lower()
+ try:
+ scheme_idx = valid_schemes.index(scheme_test)
+ except ValueError:
+ raise ValueError,'Unrecognized color scheme: ' + scheme + \
+ '\nValid schemes: '+str(scheme_names).replace("'', ",'')
+ else:
+ active = scheme_names[scheme_idx]
+ self.active_scheme_name = active
+ self.active_colors = self[active].colors
+ # Now allow using '' as an index for the current active scheme
+ self[''] = self[active]
diff --git a/IPython/ConfigLoader.py b/IPython/ConfigLoader.py
new file mode 100644
index 0000000..d64864d
--- /dev/null
+++ b/IPython/ConfigLoader.py
@@ -0,0 +1,111 @@
+# -*- coding: utf-8 -*-
+"""Configuration loader
+"""
+
+#*****************************************************************************
+# Copyright (C) 2001-2006 Fernando Perez. <fperez@colorado.edu>
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#*****************************************************************************
+
+import exceptions
+import os
+from pprint import pprint
+
+from IPython import ultraTB
+from IPython.ipstruct import Struct
+from IPython.genutils import *
+
+class ConfigLoaderError(exceptions.Exception):
+ """Exception for ConfigLoader class."""
+
+ def __init__(self,args=None):
+ self.args = args
+
+class ConfigLoader:
+
+ """Configuration file loader capable of handling recursive inclusions and
+ with parametrized conflict resolution for multiply found keys."""
+
+ def __init__(self,conflict=None,field_sep=None,reclimit=15):
+
+ """The reclimit parameter controls the number of recursive
+ configuration file inclusions. This way we can stop early on (before
+ python's own recursion limit is hit) if there is a circular
+ inclusion.
+
+ - conflict: dictionary for conflict resolutions (see Struct.merge())
+
+ """
+ self.conflict = conflict
+ self.field_sep = field_sep
+ self.reset(reclimit)
+
+ def reset(self,reclimit=15):
+ self.reclimit = reclimit
+ self.recdepth = 0
+ self.included = []
+
+ def load(self,fname,convert=None,recurse_key='',incpath = '.',**kw):
+ """Load a configuration file, return the resulting Struct.
+
+ Call: load_config(fname,convert=None,conflict=None,recurse_key='')
+
+ - fname: file to load from.
+ - convert: dictionary of type conversions (see read_dict())
+ - recurse_key: keyword in dictionary to trigger recursive file
+ inclusions.
+ """
+
+ if self.recdepth > self.reclimit:
+ raise ConfigLoaderError, 'maximum recursive inclusion of rcfiles '+\
+ 'exceeded: ' + `self.recdepth` + \
+ '.\nMaybe you have a circular chain of inclusions?'
+ self.recdepth += 1
+ fname = filefind(fname,incpath)
+ data = Struct()
+ # avoid including the same file more than once
+ if fname in self.included:
+ return data
+ Xinfo = ultraTB.AutoFormattedTB(color_scheme='NoColor')
+ if convert==None and recurse_key : convert = {qwflat:recurse_key}
+ # for production, change warn to 0:
+ data.merge(read_dict(fname,convert,fs=self.field_sep,strip=1,
+ warn=0,no_empty=0,**kw))
+ # keep track of successfully loaded files
+ self.included.append(fname)
+ if recurse_key in data:
+ for incfilename in data[recurse_key]:
+ found=0
+ try:
+ incfile = filefind(incfilename,incpath)
+ except IOError:
+ if os.name in ['nt','dos']:
+ try:
+ # Try again with '.ini' extension
+ incfilename += '.ini'
+ incfile = filefind(incfilename,incpath)
+ except IOError:
+ found = 0
+ else:
+ found = 1
+ else:
+ found = 0
+ else:
+ found = 1
+ if found:
+ try:
+ data.merge(self.load(incfile,convert,recurse_key,
+ incpath,**kw),
+ self.conflict)
+ except:
+ Xinfo()
+ warn('Problem loading included file: '+
+ `incfilename` + '. Ignoring it...')
+ else:
+ warn('File `%s` not found. Included by %s' % (incfilename,fname))
+
+ return data
+
+# end ConfigLoader
diff --git a/IPython/CrashHandler.py b/IPython/CrashHandler.py
new file mode 100644
index 0000000..d8388be
--- /dev/null
+++ b/IPython/CrashHandler.py
@@ -0,0 +1,230 @@
+# -*- coding: utf-8 -*-
+"""sys.excepthook for IPython itself, leaves a detailed report on disk.
+
+
+Authors
+-------
+- Fernando Perez <Fernando.Perez@berkeley.edu>
+"""
+
+#*****************************************************************************
+# Copyright (C) 2008-2009 The IPython Development Team
+# Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#*****************************************************************************
+
+#****************************************************************************
+# Required modules
+
+# From the standard library
+import os
+import sys
+from pprint import pprint,pformat
+
+# Our own
+from IPython import Release
+from IPython import ultraTB
+from IPython.ColorANSI import ColorScheme,ColorSchemeTable # too long names
+from IPython.Itpl import Itpl,itpl,printpl
+
+from IPython.genutils import *
+
+#****************************************************************************
+class CrashHandler:
+ """Customizable crash handlers for IPython-based systems.
+
+ Instances of this class provide a __call__ method which can be used as a
+ sys.excepthook, i.e., the __call__ signature is:
+
+ def __call__(self,etype, evalue, etb)
+
+ """
+
+ def __init__(self,IP,app_name,contact_name,contact_email,
+ bug_tracker,crash_report_fname,
+ show_crash_traceback=True):
+ """New crash handler.
+
+ Inputs:
+
+ - IP: a running IPython instance, which will be queried at crash time
+ for internal information.
+
+ - app_name: a string containing the name of your application.
+
+ - contact_name: a string with the name of the person to contact.
+
+ - contact_email: a string with the email address of the contact.
+
+ - bug_tracker: a string with the URL for your project's bug tracker.
+
+ - crash_report_fname: a string with the filename for the crash report
+ to be saved in. These reports are left in the ipython user directory
+ as determined by the running IPython instance.
+
+ Optional inputs:
+
+ - show_crash_traceback(True): if false, don't print the crash
+ traceback on stderr, only generate the on-disk report
+
+
+ Non-argument instance attributes:
+
+ These instances contain some non-argument attributes which allow for
+ further customization of the crash handler's behavior. Please see the
+ source for further details.
+ """
+
+ # apply args into instance
+ self.IP = IP # IPython instance
+ self.app_name = app_name
+ self.contact_name = contact_name
+ self.contact_email = contact_email
+ self.bug_tracker = bug_tracker
+ self.crash_report_fname = crash_report_fname
+ self.show_crash_traceback = show_crash_traceback
+
+ # Hardcoded defaults, which can be overridden either by subclasses or
+ # at runtime for the instance.
+
+ # Template for the user message. Subclasses which completely override
+ # this, or user apps, can modify it to suit their tastes. It gets
+ # expanded using itpl, so calls of the kind $self.foo are valid.
+ self.user_message_template = """
+Oops, $self.app_name crashed. We do our best to make it stable, but...
+
+A crash report was automatically generated with the following information:
+ - A verbatim copy of the crash traceback.
+ - A copy of your input history during this session.
+ - Data on your current $self.app_name configuration.
+
+It was left in the file named:
+\t'$self.crash_report_fname'
+If you can email this file to the developers, the information in it will help
+them in understanding and correcting the problem.
+
+You can mail it to: $self.contact_name at $self.contact_email
+with the subject '$self.app_name Crash Report'.
+
+If you want to do it now, the following command will work (under Unix):
+mail -s '$self.app_name Crash Report' $self.contact_email < $self.crash_report_fname
+
+To ensure accurate tracking of this issue, please file a report about it at:
+$self.bug_tracker
+"""
+
+ def __call__(self,etype, evalue, etb):
+ """Handle an exception, call for compatible with sys.excepthook"""
+
+ # Report tracebacks shouldn't use color in general (safer for users)
+ color_scheme = 'NoColor'
+
+ # Use this ONLY for developer debugging (keep commented out for release)
+ #color_scheme = 'Linux' # dbg
+
+ try:
+ rptdir = self.IP.rc.ipythondir
+ except:
+ rptdir = os.getcwd()
+ if not os.path.isdir(rptdir):
+ rptdir = os.getcwd()
+ report_name = os.path.join(rptdir,self.crash_report_fname)
+ # write the report filename into the instance dict so it can get
+ # properly expanded out in the user message template
+ self.crash_report_fname = report_name
+ TBhandler = ultraTB.VerboseTB(color_scheme=color_scheme,
+ long_header=1)
+ traceback = TBhandler.text(etype,evalue,etb,context=31)
+
+ # print traceback to screen
+ if self.show_crash_traceback:
+ print >> sys.stderr, traceback
+
+ # and generate a complete report on disk
+ try:
+ report = open(report_name,'w')
+ except:
+ print >> sys.stderr, 'Could not create crash report on disk.'
+ return
+
+ # Inform user on stderr of what happened
+ msg = itpl('\n'+'*'*70+'\n'+self.user_message_template)
+ print >> sys.stderr, msg
+
+ # Construct report on disk
+ report.write(self.make_report(traceback))
+ report.close()
+ raw_input("Press enter to exit:")
+
+ def make_report(self,traceback):
+ """Return a string containing a crash report."""
+
+ sec_sep = '\n\n'+'*'*75+'\n\n'
+
+ report = []
+ rpt_add = report.append
+
+ rpt_add('*'*75+'\n\n'+'IPython post-mortem report\n\n')
+ rpt_add('IPython version: %s \n\n' % Release.version)
+ rpt_add('BZR revision : %s \n\n' % Release.revision)
+ rpt_add('Platform info : os.name -> %s, sys.platform -> %s' %
+ (os.name,sys.platform) )
+ rpt_add(sec_sep+'Current user configuration structure:\n\n')
+ rpt_add(pformat(self.IP.rc.dict()))
+ rpt_add(sec_sep+'Crash traceback:\n\n' + traceback)
+ try:
+ rpt_add(sec_sep+"History of session input:")
+ for line in self.IP.user_ns['_ih']:
+ rpt_add(line)
+ rpt_add('\n*** Last line of input (may not be in above history):\n')
+ rpt_add(self.IP._last_input_line+'\n')
+ except:
+ pass
+
+ return ''.join(report)
+
+class IPythonCrashHandler(CrashHandler):
+ """sys.excepthook for IPython itself, leaves a detailed report on disk."""
+
+ def __init__(self,IP):
+
+ # Set here which of the IPython authors should be listed as contact
+ AUTHOR_CONTACT = 'Fernando'
+
+ # Set argument defaults
+ app_name = 'IPython'
+ bug_tracker = 'https://bugs.launchpad.net/ipython/+filebug'
+ contact_name,contact_email = Release.authors[AUTHOR_CONTACT][:2]
+ crash_report_fname = 'IPython_crash_report.txt'
+ # Call parent constructor
+ CrashHandler.__init__(self,IP,app_name,contact_name,contact_email,
+ bug_tracker,crash_report_fname)
+
+ def make_report(self,traceback):
+ """Return a string containing a crash report."""
+
+ sec_sep = '\n\n'+'*'*75+'\n\n'
+
+ report = []
+ rpt_add = report.append
+
+ rpt_add('*'*75+'\n\n'+'IPython post-mortem report\n\n')
+ rpt_add('IPython version: %s \n\n' % Release.version)
+ rpt_add('BZR revision : %s \n\n' % Release.revision)
+ rpt_add('Platform info : os.name -> %s, sys.platform -> %s' %
+ (os.name,sys.platform) )
+ rpt_add(sec_sep+'Current user configuration structure:\n\n')
+ rpt_add(pformat(self.IP.rc.dict()))
+ rpt_add(sec_sep+'Crash traceback:\n\n' + traceback)
+ try:
+ rpt_add(sec_sep+"History of session input:")
+ for line in self.IP.user_ns['_ih']:
+ rpt_add(line)
+ rpt_add('\n*** Last line of input (may not be in above history):\n')
+ rpt_add(self.IP._last_input_line+'\n')
+ except:
+ pass
+
+ return ''.join(report)
diff --git a/IPython/DPyGetOpt.py b/IPython/DPyGetOpt.py
new file mode 100644
index 0000000..f4b918e
--- /dev/null
+++ b/IPython/DPyGetOpt.py
@@ -0,0 +1,690 @@
+# -*- coding: utf-8 -*-
+"""DPyGetOpt -- Demiurge Python GetOptions Module
+
+This module is modeled after perl's Getopt::Long module-- which
+is, in turn, modeled after GNU's extended getopt() function.
+
+Upon instantiation, the option specification should be a sequence
+(list) of option definitions.
+
+Options that take no arguments should simply contain the name of
+the option. If a ! is post-pended, the option can be negated by
+prepending 'no'; ie 'debug!' specifies that -debug and -nodebug
+should be accepted.
+
+Mandatory arguments to options are specified using a postpended
+'=' + a type specifier. '=s' specifies a mandatory string
+argument, '=i' specifies a mandatory integer argument, and '=f'
+specifies a mandatory real number. In all cases, the '=' can be
+substituted with ':' to specify that the argument is optional.
+
+Dashes '-' in option names are allowed.
+
+If an option has the character '@' postpended (after the
+argumentation specification), it can appear multiple times within
+each argument list that is processed. The results will be stored
+in a list.
+
+The option name can actually be a list of names separated by '|'
+characters; ie-- 'foo|bar|baz=f@' specifies that all -foo, -bar,
+and -baz options that appear on within the parsed argument list
+must have a real number argument and that the accumulated list
+of values will be available under the name 'foo'
+"""
+
+#*****************************************************************************
+#
+# Copyright (c) 2001 Bill Bumgarner <bbum@friday.com>
+#
+#
+# Published under the terms of the MIT license, hereby reproduced:
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+#
+#*****************************************************************************
+
+__author__ = 'Bill Bumgarner <bbum@friday.com>'
+__license__ = 'MIT'
+__version__ = '1.2'
+
+# Modified to use re instead of regex and regsub modules.
+# 2001/5/7, Jonathan Hogg <jonathan@onegoodidea.com>
+
+import re
+import string
+import sys
+import types
+
+class Error(Exception):
+ """Base class for exceptions in the DPyGetOpt module."""
+
+class ArgumentError(Error):
+ """Exception indicating an error in the arguments passed to
+ DPyGetOpt.processArguments."""
+
+class SpecificationError(Error):
+ """Exception indicating an error with an option specification."""
+
+class TerminationError(Error):
+ """Exception indicating an error with an option processing terminator."""
+
+specificationExpr = re.compile('(?P<required>.)(?P<type>.)(?P<multi>@?)')
+
+ArgRequired = 'Requires an Argument'
+ArgOptional = 'Argument Optional'
+
+# The types modules is not used for these identifiers because there
+# is no identifier for 'boolean' or 'generic'
+StringArgType = 'String Argument Type'
+IntegerArgType = 'Integer Argument Type'
+RealArgType = 'Real Argument Type'
+BooleanArgType = 'Boolean Argument Type'
+GenericArgType = 'Generic Argument Type'
+
+# dictionary of conversion functions-- boolean and generic options
+# do not accept arguments and do not need conversion functions;
+# the identity function is used purely for convenience.
+ConversionFunctions = {
+ StringArgType : lambda x: x,
+ IntegerArgType : string.atoi,
+ RealArgType : string.atof,
+ BooleanArgType : lambda x: x,
+ GenericArgType : lambda x: x,
+ }
+
+class DPyGetOpt:
+
+ def __init__(self, spec = None, terminators = ['--']):
+ """
+ Declare and intialize instance variables
+
+ Yes, declaration is not necessary... but one of the things
+ I sorely miss from C/Obj-C is the concept of having an
+ interface definition that clearly declares all instance
+ variables and methods without providing any implementation
+ details. it is a useful reference!
+
+ all instance variables are initialized to 0/Null/None of
+ the appropriate type-- not even the default value...
+ """
+
+# sys.stderr.write(string.join(spec) + "\n")
+
+ self.allowAbbreviations = 1 # boolean, 1 if abbreviations will
+ # be expanded
+ self.freeValues = [] # list, contains free values
+ self.ignoreCase = 0 # boolean, YES if ignoring case
+ self.needsParse = 0 # boolean, YES if need to reparse parameter spec
+ self.optionNames = {} # dict, all option names-- value is index of tuple
+ self.optionStartExpr = None # regexp defining the start of an option (ie; '-', '--')
+ self.optionTuples = [] # list o' tuples containing defn of options AND aliases
+ self.optionValues = {} # dict, option names (after alias expansion) -> option value(s)
+ self.orderMixed = 0 # boolean, YES if options can be mixed with args
+ self.posixCompliance = 0 # boolean, YES indicates posix like behaviour
+ self.spec = [] # list, raw specs (in case it must be reparsed)
+ self.terminators = terminators # list, strings that terminate argument processing
+ self.termValues = [] # list, values after terminator
+ self.terminator = None # full name of terminator that ended
+ # option processing
+
+ # set up defaults
+ self.setPosixCompliance()
+ self.setIgnoreCase()
+ self.setAllowAbbreviations()
+
+ # parse spec-- if present
+ if spec:
+ self.parseConfiguration(spec)
+
+ def setPosixCompliance(self, aFlag = 0):
+ """
+ Enables and disables posix compliance.
+
+ When enabled, '+' can be used as an option prefix and free
+ values can be mixed with options.
+ """
+ self.posixCompliance = aFlag
+ self.needsParse = 1
+
+ if self.posixCompliance:
+ self.optionStartExpr = re.compile('(--|-)(?P<option>[A-Za-z0-9_-]+)(?P<arg>=.*)?')
+ self.orderMixed = 0
+ else:
+ self.optionStartExpr = re.compile('(--|-|\+)(?P<option>[A-Za-z0-9_-]+)(?P<arg>=.*)?')
+ self.orderMixed = 1
+
+ def isPosixCompliant(self):
+ """
+ Returns the value of the posix compliance flag.
+ """
+ return self.posixCompliance
+
+ def setIgnoreCase(self, aFlag = 1):
+ """
+ Enables and disables ignoring case during option processing.
+ """
+ self.needsParse = 1
+ self.ignoreCase = aFlag
+
+ def ignoreCase(self):
+ """
+ Returns 1 if the option processor will ignore case when
+ processing options.
+ """
+ return self.ignoreCase
+
+ def setAllowAbbreviations(self, aFlag = 1):
+ """
+ Enables and disables the expansion of abbreviations during
+ option processing.
+ """
+ self.allowAbbreviations = aFlag
+
+ def willAllowAbbreviations(self):
+ """
+ Returns 1 if abbreviated options will be automatically
+ expanded to the non-abbreviated form (instead of causing an
+ unrecognized option error).
+ """
+ return self.allowAbbreviations
+
+ def addTerminator(self, newTerm):
+ """
+ Adds newTerm as terminator of option processing.
+
+ Whenever the option processor encounters one of the terminators
+ during option processing, the processing of options terminates
+ immediately, all remaining options are stored in the termValues
+ instance variable and the full name of the terminator is stored
+ in the terminator instance variable.
+ """
+ self.terminators = self.terminators + [newTerm]
+
+ def _addOption(self, oTuple):
+ """
+ Adds the option described by oTuple (name, (type, mode,
+ default), alias) to optionTuples. Adds index keyed under name
+ to optionNames. Raises SpecificationError if name already in
+ optionNames
+ """
+ (name, (type, mode, default, multi), realName) = oTuple
+
+ # verify name and add to option names dictionary
+ if self.optionNames.has_key(name):
+ if realName:
+ raise SpecificationError('Alias \'' + name + '\' for \'' +
+ realName +
+ '\' already used for another option or alias.')
+ else:
+ raise SpecificationError('Option named \'' + name +
+ '\' specified more than once. Specification: '
+ + option)
+
+ # validated. add to optionNames
+ self.optionNames[name] = self.tupleIndex
+ self.tupleIndex = self.tupleIndex + 1
+
+ # add to optionTuples
+ self.optionTuples = self.optionTuples + [oTuple]
+
+ # if type is boolean, add negation
+ if type == BooleanArgType:
+ alias = 'no' + name
+ specTuple = (type, mode, 0, multi)
+ oTuple = (alias, specTuple, name)
+
+ # verify name and add to option names dictionary
+ if self.optionNames.has_key(alias):
+ if realName:
+ raise SpecificationError('Negated alias \'' + name +
+ '\' for \'' + realName +
+ '\' already used for another option or alias.')
+ else:
+ raise SpecificationError('Negated option named \'' + name +
+ '\' specified more than once. Specification: '
+ + option)
+
+ # validated. add to optionNames
+ self.optionNames[alias] = self.tupleIndex
+ self.tupleIndex = self.tupleIndex + 1
+
+ # add to optionTuples
+ self.optionTuples = self.optionTuples + [oTuple]
+
+ def addOptionConfigurationTuple(self, oTuple):
+ (name, argSpec, realName) = oTuple
+ if self.ignoreCase:
+ name = string.lower(name)
+ if realName:
+ realName = string.lower(realName)
+ else:
+ realName = name
+
+ oTuple = (name, argSpec, realName)
+
+ # add option
+ self._addOption(oTuple)
+
+ def addOptionConfigurationTuples(self, oTuple):
+ if type(oTuple) is ListType:
+ for t in oTuple:
+ self.addOptionConfigurationTuple(t)
+ else:
+ self.addOptionConfigurationTuple(oTuple)
+
+ def parseConfiguration(self, spec):
+ # destroy previous stored information + store raw spec
+ self.spec = spec
+ self.optionTuples = []
+ self.optionNames = {}
+ self.tupleIndex = 0
+
+ tupleIndex = 0
+
+ # create some regex's for parsing each spec
+ splitExpr = \
+ re.compile('(?P<names>\w+[-A-Za-z0-9|]*)?(?P<spec>!|[=:][infs]@?)?')
+ for option in spec:
+ # push to lower case (does not negatively affect
+ # specification)
+ if self.ignoreCase:
+ option = string.lower(option)
+
+ # break into names, specification
+ match = splitExpr.match(option)
+ if match is None:
+ raise SpecificationError('Invalid specification {' + option +
+ '}')
+
+ names = match.group('names')
+ specification = match.group('spec')
+
+ # break name into name, aliases
+ nlist = string.split(names, '|')
+
+ # get name
+ name = nlist[0]
+ aliases = nlist[1:]
+
+ # specificationExpr = regex.symcomp('\(<required>.\)\(<type>.\)\(<multi>@?\)')
+ if not specification:
+ #spec tuple is ('type', 'arg mode', 'default value', 'multiple')
+ argType = GenericArgType
+ argMode = None
+ argDefault = 1
+ argMultiple = 0
+ elif specification == '!':
+ argType = BooleanArgType
+ argMode = None
+ argDefault = 1
+ argMultiple = 0
+ else:
+ # parse
+ match = specificationExpr.match(specification)
+ if match is None:
+ # failed to parse, die
+ raise SpecificationError('Invalid configuration for option \''
+ + option + '\'')
+
+ # determine mode
+ required = match.group('required')
+ if required == '=':
+ argMode = ArgRequired
+ elif required == ':':
+ argMode = ArgOptional
+ else:
+ raise SpecificationError('Unknown requirement configuration \''
+ + required + '\'')
+
+ # determine type
+ type = match.group('type')
+ if type == 's':
+ argType = StringArgType
+ argDefault = ''
+ elif type == 'i':
+ argType = IntegerArgType
+ argDefault = 1
+ elif type == 'f' or type == 'n':
+ argType = RealArgType
+ argDefault = 1
+ else:
+ raise SpecificationError('Unknown type specifier \'' +
+ type + '\'')
+
+ # determine quantity
+ if match.group('multi') == '@':
+ argMultiple = 1
+ else:
+ argMultiple = 0
+ ## end else (of not specification)
+
+ # construct specification tuple
+ specTuple = (argType, argMode, argDefault, argMultiple)
+
+ # add the option-- option tuple is (name, specTuple, real name)
+ oTuple = (name, specTuple, name)
+ self._addOption(oTuple)
+
+ for alias in aliases:
+ # drop to all lower (if configured to do so)
+ if self.ignoreCase:
+ alias = string.lower(alias)
+ # create configuration tuple
+ oTuple = (alias, specTuple, name)
+ # add
+ self._addOption(oTuple)
+
+ # successfully parsed....
+ self.needsParse = 0
+
+ def _getArgTuple(self, argName):
+ """
+ Returns a list containing all the specification tuples that
+ match argName. If none match, None is returned. If one
+ matches, a list with one tuple is returned. If more than one
+ match, a list containing all the tuples that matched is
+ returned.
+
+ In other words, this function does not pass judgement upon the
+ validity of multiple matches.
+ """
+ # is it in the optionNames dict?
+
+ try:
+# sys.stderr.write(argName + string.join(self.optionNames.keys()) + "\n")
+
+ # yes, get index
+ tupleIndex = self.optionNames[argName]
+ # and return tuple as element of list
+ return [self.optionTuples[tupleIndex]]
+ except KeyError:
+ # are abbreviations allowed?
+ if not self.allowAbbreviations:
+ # No! terefore, this cannot be valid argument-- nothing found
+ return None
+
+ # argName might be an abbreviation (and, abbreviations must
+ # be allowed... or this would not have been reached!)
+
+ # create regex for argName
+ argExpr = re.compile('^' + argName)
+
+ tuples = filter(lambda x, argExpr=argExpr: argExpr.search(x[0]) is not None,
+ self.optionTuples)
+
+ if not len(tuples):
+ return None
+ else:
+ return tuples
+
+ def _isTerminator(self, optionName):
+ """
+ Returns the full name of the terminator if optionName is a valid
+ terminator. If it is, sets self.terminator to the full name of
+ the terminator.
+
+ If more than one terminator matched, raises a TerminationError with a
+ string describing the ambiguity.
+ """
+
+# sys.stderr.write(optionName + "\n")
+# sys.stderr.write(repr(self.terminators))
+
+ if optionName in self.terminators:
+ self.terminator = optionName
+ elif not self.allowAbbreviations:
+ return None
+
+# regex thing in bogus
+# termExpr = regex.compile('^' + optionName)
+
+ terms = filter(lambda x, on=optionName: string.find(x,on) == 0, self.terminators)
+
+ if not len(terms):
+ return None
+ elif len(terms) > 1:
+ raise TerminationError('Ambiguous terminator \'' + optionName +
+ '\' matches ' + repr(terms))
+
+ self.terminator = terms[0]
+ return self.terminator
+
+ def processArguments(self, args = None):
+ """
+ Processes args, a list of arguments (including options).
+
+ If args is the same as sys.argv, automatically trims the first
+ argument (the executable name/path).
+
+ If an exception is not raised, the argument list was parsed
+ correctly.
+
+ Upon successful completion, the freeValues instance variable
+ will contain all the arguments that were not associated with an
+ option in the order they were encountered. optionValues is a
+ dictionary containing the value of each option-- the method
+ valueForOption() can be used to query this dictionary.
+ terminator will contain the argument encountered that terminated
+ option processing (or None, if a terminator was never
+ encountered) and termValues will contain all of the options that
+ appeared after the Terminator (or an empty list).
+ """
+
+ if hasattr(sys, "argv") and args == sys.argv:
+ args = sys.argv[1:]
+
+ max = len(args) # maximum index + 1
+ self.freeValues = [] # array to hold return values
+ self.optionValues= {}
+ index = 0 # initial index
+ self.terminator = None
+ self.termValues = []
+
+ while index < max:
+ # obtain argument
+ arg = args[index]
+ # increment index -- REMEMBER; it is NOW incremented
+ index = index + 1
+
+ # terminate immediately if option terminator encountered
+ if self._isTerminator(arg):
+ self.freeValues = self.freeValues + args[index:]
+ self.termValues = args[index:]
+ return
+
+ # is this possibly an option?
+ match = self.optionStartExpr.match(arg)
+ if match is None:
+ # not an option-- add to freeValues
+ self.freeValues = self.freeValues + [arg]
+ if not self.orderMixed:
+ # mixing not allowed; add rest of args as freeValues
+ self.freeValues = self.freeValues + args[index:]
+ # return to caller
+ return
+ else:
+ continue
+
+ # grab name
+ optName = match.group('option')
+
+ # obtain next argument-- index has already been incremented
+ nextArg = match.group('arg')
+ if nextArg:
+ nextArg = nextArg[1:]
+ index = index - 1 # put it back
+ else:
+ try:
+ nextArg = args[index]
+ except:
+ nextArg = None
+
+ # transpose to lower case, if necessary
+ if self.ignoreCase:
+ optName = string.lower(optName)
+
+ # obtain defining tuple
+ tuples = self._getArgTuple(optName)
+
+ if tuples == None:
+ raise ArgumentError('Illegal option \'' + arg + '\'')
+ elif len(tuples) > 1:
+ raise ArgumentError('Ambiguous option \'' + arg +
+ '\'; matches ' +
+ repr(map(lambda x: x[0], tuples)))
+ else:
+ config = tuples[0]
+
+ # config is now set to the configuration tuple for the
+ # argument
+ (fullName, spec, realName) = config
+ (optType, optMode, optDefault, optMultiple) = spec
+
+ # if opt mode required, but nextArg is none, raise an error
+ if (optMode == ArgRequired):
+ if (not nextArg) or self._isTerminator(nextArg):
+# print nextArg
+ raise ArgumentError('Option \'' + arg +
+ '\' requires an argument of type ' +
+ optType)
+
+ if (not optMode == None) and nextArg and (not self._isTerminator(nextArg)):
+ # nextArg defined, option configured to possibly consume arg
+ try:
+ # grab conversion function-- the try is more for internal diagnostics
+ func = ConversionFunctions[optType]
+ try:
+ optionValue = func(nextArg)
+ index = index + 1
+ except:
+ # only raise conversion error if REQUIRED to consume argument
+ if optMode == ArgRequired:
+ raise ArgumentError('Invalid argument to option \''
+ + arg + '\'; should be \'' +
+ optType + '\'')
+ else:
+ optionValue = optDefault
+ except ArgumentError:
+ raise
+ except:
+ raise ArgumentError('(' + arg +
+ ') Conversion function for \'' +
+ optType + '\' not found.')
+ else:
+ optionValue = optDefault
+
+ # add value to options dictionary
+ if optMultiple:
+ # can be multiple values
+ try:
+ # try to append element
+ self.optionValues[realName] = self.optionValues[realName] + [optionValue]
+ except:
+ # failed-- must not exist; add it
+ self.optionValues[realName] = [optionValue]
+ else:
+ # only one value per
+ if self.isPosixCompliant and self.optionValues.has_key(realName):
+ raise ArgumentError('Argument \'' + arg +
+ '\' occurs multiple times.')
+
+ self.optionValues[realName] = optionValue
+
+ def valueForOption(self, optionName, defaultValue = None):
+ """
+ Return the value associated with optionName. If optionName was
+ not encountered during parsing of the arguments, returns the
+ defaultValue (which defaults to None).
+ """
+ try:
+ optionValue = self.optionValues[optionName]
+ except:
+ optionValue = defaultValue
+
+ return optionValue
+
+##
+## test/example section
+##
+test_error = 'Test Run Amok!'
+def _test():
+ """
+ A relatively complete test suite.
+ """
+ try:
+ DPyGetOpt(['foo', 'bar=s', 'foo'])
+ except Error, exc:
+ print 'EXCEPTION (should be \'foo\' already used..): %s' % exc
+
+ try:
+ DPyGetOpt(['foo|bar|apple=s@', 'baz|apple!'])
+ except Error, exc:
+ print 'EXCEPTION (should be duplicate alias/name error): %s' % exc
+
+ x = DPyGetOpt(['apple|atlas=i@', 'application|executable=f@'])
+ try:
+ x.processArguments(['-app', '29.3'])
+ except Error, exc:
+ print 'EXCEPTION (should be ambiguous argument): %s' % exc
+
+ x = DPyGetOpt(['foo'], ['antigravity', 'antithesis'])
+ try:
+ x.processArguments(['-foo', 'anti'])
+ except Error, exc:
+ print 'EXCEPTION (should be ambiguous terminator): %s' % exc
+
+ profile = ['plain-option',
+ 'boolean-option!',
+ 'list-of-integers=i@',
+ 'list-real-option|list-real-alias|list-real-pseudonym=f@',
+ 'optional-string-option:s',
+ 'abbreviated-string-list=s@']
+
+ terminators = ['terminator']
+
+ args = ['-plain-option',
+ '+noboolean-option',
+ '--list-of-integers', '1',
+ '+list-of-integers', '2',
+ '-list-of-integers', '3',
+ 'freeargone',
+ '-list-real-option', '1.1',
+ '+list-real-alias', '1.2',
+ '--list-real-pseudonym', '1.3',
+ 'freeargtwo',
+ '-abbreviated-string-list', 'String1',
+ '--abbreviated-s', 'String2',
+ '-abbrev', 'String3',
+ '-a', 'String4',
+ '-optional-string-option',
+ 'term',
+ 'next option should look like an invalid arg',
+ '-a']
+
+
+ print 'Using profile: ' + repr(profile)
+ print 'With terminator: ' + repr(terminators)
+ print 'Processing arguments: ' + repr(args)
+
+ go = DPyGetOpt(profile, terminators)
+ go.processArguments(args)
+
+ print 'Options (and values): ' + repr(go.optionValues)
+ print 'free args: ' + repr(go.freeValues)
+ print 'term args: ' + repr(go.termValues)
diff --git a/IPython/Debugger.py b/IPython/Debugger.py
new file mode 100644
index 0000000..117b7d1
--- /dev/null
+++ b/IPython/Debugger.py
@@ -0,0 +1,522 @@
+# -*- coding: utf-8 -*-
+"""
+Pdb debugger class.
+
+Modified from the standard pdb.Pdb class to avoid including readline, so that
+the command line completion of other programs which include this isn't
+damaged.
+
+In the future, this class will be expanded with improvements over the standard
+pdb.
+
+The code in this file is mainly lifted out of cmd.py in Python 2.2, with minor
+changes. Licensing should therefore be under the standard Python terms. For
+details on the PSF (Python Software Foundation) standard license, see:
+
+http://www.python.org/2.2.3/license.html"""
+
+#*****************************************************************************
+#
+# This file is licensed under the PSF license.
+#
+# Copyright (C) 2001 Python Software Foundation, www.python.org
+# Copyright (C) 2005-2006 Fernando Perez. <fperez@colorado.edu>
+#
+#
+#*****************************************************************************
+
+import bdb
+import cmd
+import linecache
+import os
+import sys
+
+from IPython import PyColorize, ColorANSI, ipapi
+from IPython.genutils import Term
+from IPython.excolors import exception_colors
+
+# See if we can use pydb.
+has_pydb = False
+prompt = 'ipdb> '
+#We have to check this directly from sys.argv, config struct not yet available
+if '-pydb' in sys.argv:
+ try:
+ import pydb
+ if hasattr(pydb.pydb, "runl") and pydb.version>'1.17':
+ # Version 1.17 is broken, and that's what ships with Ubuntu Edgy, so we
+ # better protect against it.
+ has_pydb = True
+ except ImportError:
+ print "Pydb (http://bashdb.sourceforge.net/pydb/) does not seem to be available"
+
+if has_pydb:
+ from pydb import Pdb as OldPdb
+ #print "Using pydb for %run -d and post-mortem" #dbg
+ prompt = 'ipydb> '
+else:
+ from pdb import Pdb as OldPdb
+
+# Allow the set_trace code to operate outside of an ipython instance, even if
+# it does so with some limitations. The rest of this support is implemented in
+# the Tracer constructor.
+def BdbQuit_excepthook(et,ev,tb):
+ if et==bdb.BdbQuit:
+ print 'Exiting Debugger.'
+ else:
+ BdbQuit_excepthook.excepthook_ori(et,ev,tb)
+
+def BdbQuit_IPython_excepthook(self,et,ev,tb):
+ print 'Exiting Debugger.'
+
+class Tracer(object):
+ """Class for local debugging, similar to pdb.set_trace.
+
+ Instances of this class, when called, behave like pdb.set_trace, but
+ providing IPython's enhanced capabilities.
+
+ This is implemented as a class which must be initialized in your own code
+ and not as a standalone function because we need to detect at runtime
+ whether IPython is already active or not. That detection is done in the
+ constructor, ensuring that this code plays nicely with a running IPython,
+ while functioning acceptably (though with limitations) if outside of it.
+ """
+
+ def __init__(self,colors=None):
+ """Create a local debugger instance.
+
+ :Parameters:
+
+ - `colors` (None): a string containing the name of the color scheme to
+ use, it must be one of IPython's valid color schemes. If not given, the
+ function will default to the current IPython scheme when running inside
+ IPython, and to 'NoColor' otherwise.
+
+ Usage example:
+
+ from IPython.Debugger import Tracer; debug_here = Tracer()
+
+ ... later in your code
+ debug_here() # -> will open up the debugger at that point.
+
+ Once the debugger activates, you can use all of its regular commands to
+ step through code, set breakpoints, etc. See the pdb documentation
+ from the Python standard library for usage details.
+ """
+
+ global __IPYTHON__
+ try:
+ __IPYTHON__
+ except NameError:
+ # Outside of ipython, we set our own exception hook manually
+ __IPYTHON__ = ipapi.get(True,False)
+ BdbQuit_excepthook.excepthook_ori = sys.excepthook
+ sys.excepthook = BdbQuit_excepthook
+ def_colors = 'NoColor'
+ try:
+ # Limited tab completion support
+ import rlcompleter,readline
+ readline.parse_and_bind('tab: complete')
+ except ImportError:
+ pass
+ else:
+ # In ipython, we use its custom exception handler mechanism
+ ip = ipapi.get()
+ def_colors = ip.options.colors
+ ip.set_custom_exc((bdb.BdbQuit,),BdbQuit_IPython_excepthook)
+
+ if colors is None:
+ colors = def_colors
+ self.debugger = Pdb(colors)
+
+ def __call__(self):
+ """Starts an interactive debugger at the point where called.
+
+ This is similar to the pdb.set_trace() function from the std lib, but
+ using IPython's enhanced debugger."""
+
+ self.debugger.set_trace(sys._getframe().f_back)
+
+def decorate_fn_with_doc(new_fn, old_fn, additional_text=""):
+ """Make new_fn have old_fn's doc string. This is particularly useful
+ for the do_... commands that hook into the help system.
+ Adapted from from a comp.lang.python posting
+ by Duncan Booth."""
+ def wrapper(*args, **kw):
+ return new_fn(*args, **kw)
+ if old_fn.__doc__:
+ wrapper.__doc__ = old_fn.__doc__ + additional_text
+ return wrapper
+
+def _file_lines(fname):
+ """Return the contents of a named file as a list of lines.
+
+ This function never raises an IOError exception: if the file can't be
+ read, it simply returns an empty list."""
+
+ try:
+ outfile = open(fname)
+ except IOError:
+ return []
+ else:
+ out = outfile.readlines()
+ outfile.close()
+ return out
+
+class Pdb(OldPdb):
+ """Modified Pdb class, does not load readline."""
+
+ if sys.version[:3] >= '2.5' or has_pydb:
+ def __init__(self,color_scheme='NoColor',completekey=None,
+ stdin=None, stdout=None):
+
+ # Parent constructor:
+ if has_pydb and completekey is None:
+ OldPdb.__init__(self,stdin=stdin,stdout=Term.cout)
+ else:
+ OldPdb.__init__(self,completekey,stdin,stdout)
+
+ self.prompt = prompt # The default prompt is '(Pdb)'
+
+ # IPython changes...
+ self.is_pydb = has_pydb
+
+ if self.is_pydb:
+
+ # iplib.py's ipalias seems to want pdb's checkline
+ # which located in pydb.fn
+ import pydb.fns
+ self.checkline = lambda filename, lineno: \
+ pydb.fns.checkline(self, filename, lineno)
+
+ self.curframe = None
+ self.do_restart = self.new_do_restart
+
+ self.old_all_completions = __IPYTHON__.Completer.all_completions
+ __IPYTHON__.Completer.all_completions=self.all_completions
+
+ self.do_list = decorate_fn_with_doc(self.list_command_pydb,
+ OldPdb.do_list)
+ self.do_l = self.do_list
+ self.do_frame = decorate_fn_with_doc(self.new_do_frame,
+ OldPdb.do_frame)
+
+ self.aliases = {}
+
+ # Create color table: we copy the default one from the traceback
+ # module and add a few attributes needed for debugging
+ self.color_scheme_table = exception_colors()
+
+ # shorthands
+ C = ColorANSI.TermColors
+ cst = self.color_scheme_table
+
+ cst['NoColor'].colors.breakpoint_enabled = C.NoColor
+ cst['NoColor'].colors.breakpoint_disabled = C.NoColor
+
+ cst['Linux'].colors.breakpoint_enabled = C.LightRed
+ cst['Linux'].colors.breakpoint_disabled = C.Red
+
+ cst['LightBG'].colors.breakpoint_enabled = C.LightRed
+ cst['LightBG'].colors.breakpoint_disabled = C.Red
+
+ self.set_colors(color_scheme)
+
+ # Add a python parser so we can syntax highlight source while
+ # debugging.
+ self.parser = PyColorize.Parser()
+
+
+ else:
+ # Ugly hack: for Python 2.3-2.4, we can't call the parent constructor,
+ # because it binds readline and breaks tab-completion. This means we
+ # have to COPY the constructor here.
+ def __init__(self,color_scheme='NoColor'):
+ bdb.Bdb.__init__(self)
+ cmd.Cmd.__init__(self,completekey=None) # don't load readline
+ self.prompt = 'ipdb> ' # The default prompt is '(Pdb)'
+ self.aliases = {}
+
+ # These two lines are part of the py2.4 constructor, let's put them
+ # unconditionally here as they won't cause any problems in 2.3.
+ self.mainpyfile = ''
+ self._wait_for_mainpyfile = 0
+
+ # Read $HOME/.pdbrc and ./.pdbrc
+ try:
+ self.rcLines = _file_lines(os.path.join(os.environ['HOME'],
+ ".pdbrc"))
+ except KeyError:
+ self.rcLines = []
+ self.rcLines.extend(_file_lines(".pdbrc"))
+
+ # Create color table: we copy the default one from the traceback
+ # module and add a few attributes needed for debugging
+ self.color_scheme_table = exception_colors()
+
+ # shorthands
+ C = ColorANSI.TermColors
+ cst = self.color_scheme_table
+
+ cst['NoColor'].colors.breakpoint_enabled = C.NoColor
+ cst['NoColor'].colors.breakpoint_disabled = C.NoColor
+
+ cst['Linux'].colors.breakpoint_enabled = C.LightRed
+ cst['Linux'].colors.breakpoint_disabled = C.Red
+
+ cst['LightBG'].colors.breakpoint_enabled = C.LightRed
+ cst['LightBG'].colors.breakpoint_disabled = C.Red
+
+ self.set_colors(color_scheme)
+
+ # Add a python parser so we can syntax highlight source while
+ # debugging.
+ self.parser = PyColorize.Parser()
+
+ def set_colors(self, scheme):
+ """Shorthand access to the color table scheme selector method."""
+ self.color_scheme_table.set_active_scheme(scheme)
+
+ def interaction(self, frame, traceback):
+ __IPYTHON__.set_completer_frame(frame)
+ OldPdb.interaction(self, frame, traceback)
+
+ def new_do_up(self, arg):
+ OldPdb.do_up(self, arg)
+ __IPYTHON__.set_completer_frame(self.curframe)
+ do_u = do_up = decorate_fn_with_doc(new_do_up, OldPdb.do_up)
+
+ def new_do_down(self, arg):
+ OldPdb.do_down(self, arg)
+ __IPYTHON__.set_completer_frame(self.curframe)
+
+ do_d = do_down = decorate_fn_with_doc(new_do_down, OldPdb.do_down)
+
+ def new_do_frame(self, arg):
+ OldPdb.do_frame(self, arg)
+ __IPYTHON__.set_completer_frame(self.curframe)
+
+ def new_do_quit(self, arg):
+
+ if hasattr(self, 'old_all_completions'):
+ __IPYTHON__.Completer.all_completions=self.old_all_completions
+
+
+ return OldPdb.do_quit(self, arg)
+
+ do_q = do_quit = decorate_fn_with_doc(new_do_quit, OldPdb.do_quit)
+
+ def new_do_restart(self, arg):
+ """Restart command. In the context of ipython this is exactly the same
+ thing as 'quit'."""
+ self.msg("Restart doesn't make sense here. Using 'quit' instead.")
+ return self.do_quit(arg)
+
+ def postloop(self):
+ __IPYTHON__.set_completer_frame(None)
+
+ def print_stack_trace(self):
+ try:
+ for frame_lineno in self.stack:
+ self.print_stack_entry(frame_lineno, context = 5)
+ except KeyboardInterrupt:
+ pass
+
+ def print_stack_entry(self,frame_lineno,prompt_prefix='\n-> ',
+ context = 3):
+ #frame, lineno = frame_lineno
+ print >>Term.cout, self.format_stack_entry(frame_lineno, '', context)
+
+ # vds: >>
+ frame, lineno = frame_lineno
+ filename = frame.f_code.co_filename
+ __IPYTHON__.hooks.synchronize_with_editor(filename, lineno, 0)
+ # vds: <<
+
+ def format_stack_entry(self, frame_lineno, lprefix=': ', context = 3):
+ import linecache, repr
+
+ ret = []
+
+ Colors = self.color_scheme_table.active_colors
+ ColorsNormal = Colors.Normal
+ tpl_link = '%s%%s%s' % (Colors.filenameEm, ColorsNormal)
+ tpl_call = '%s%%s%s%%s%s' % (Colors.vName, Colors.valEm, ColorsNormal)
+ tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
+ tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line,
+ ColorsNormal)
+
+ frame, lineno = frame_lineno
+
+ return_value = ''
+ if '__return__' in frame.f_locals:
+ rv = frame.f_locals['__return__']
+ #return_value += '->'
+ return_value += repr.repr(rv) + '\n'
+ ret.append(return_value)
+
+ #s = filename + '(' + `lineno` + ')'
+ filename = self.canonic(frame.f_code.co_filename)
+ link = tpl_link % filename
+
+ if frame.f_code.co_name:
+ func = frame.f_code.co_name
+ else:
+ func = "<lambda>"
+
+ call = ''
+ if func != '?':
+ if '__args__' in frame.f_locals:
+ args = repr.repr(frame.f_locals['__args__'])
+ else:
+ args = '()'
+ call = tpl_call % (func, args)
+
+ # The level info should be generated in the same format pdb uses, to
+ # avoid breaking the pdbtrack functionality of python-mode in *emacs.
+ if frame is self.curframe:
+ ret.append('> ')
+ else:
+ ret.append(' ')
+ ret.append('%s(%s)%s\n' % (link,lineno,call))
+
+ start = lineno - 1 - context//2
+ lines = linecache.getlines(filename)
+ start = max(start, 0)
+ start = min(start, len(lines) - context)
+ lines = lines[start : start + context]
+
+ for i,line in enumerate(lines):
+ show_arrow = (start + 1 + i == lineno)
+ linetpl = (frame is self.curframe or show_arrow) \
+ and tpl_line_em \
+ or tpl_line
+ ret.append(self.__format_line(linetpl, filename,
+ start + 1 + i, line,
+ arrow = show_arrow) )
+
+ return ''.join(ret)
+
+ def __format_line(self, tpl_line, filename, lineno, line, arrow = False):
+ bp_mark = ""
+ bp_mark_color = ""
+
+ scheme = self.color_scheme_table.active_scheme_name
+ new_line, err = self.parser.format2(line, 'str', scheme)
+ if not err: line = new_line
+
+ bp = None
+ if lineno in self.get_file_breaks(filename):
+ bps = self.get_breaks(filename, lineno)
+ bp = bps[-1]
+
+ if bp:
+ Colors = self.color_scheme_table.active_colors
+ bp_mark = str(bp.number)
+ bp_mark_color = Colors.breakpoint_enabled
+ if not bp.enabled:
+ bp_mark_color = Colors.breakpoint_disabled
+
+ numbers_width = 7
+ if arrow:
+ # This is the line with the error
+ pad = numbers_width - len(str(lineno)) - len(bp_mark)
+ if pad >= 3:
+ marker = '-'*(pad-3) + '-> '
+ elif pad == 2:
+ marker = '> '
+ elif pad == 1:
+ marker = '>'
+ else:
+ marker = ''
+ num = '%s%s' % (marker, str(lineno))
+ line = tpl_line % (bp_mark_color + bp_mark, num, line)
+ else:
+ num = '%*s' % (numbers_width - len(bp_mark), str(lineno))
+ line = tpl_line % (bp_mark_color + bp_mark, num, line)
+
+ return line
+
+ def list_command_pydb(self, arg):
+ """List command to use if we have a newer pydb installed"""
+ filename, first, last = OldPdb.parse_list_cmd(self, arg)
+ if filename is not None:
+ self.print_list_lines(filename, first, last)
+
+ def print_list_lines(self, filename, first, last):
+ """The printing (as opposed to the parsing part of a 'list'
+ command."""
+ try:
+ Colors = self.color_scheme_table.active_colors
+ ColorsNormal = Colors.Normal
+ tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
+ tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line, ColorsNormal)
+ src = []
+ for lineno in range(first, last+1):
+ line = linecache.getline(filename, lineno)
+ if not line:
+ break
+
+ if lineno == self.curframe.f_lineno:
+ line = self.__format_line(tpl_line_em, filename, lineno, line, arrow = True)
+ else:
+ line = self.__format_line(tpl_line, filename, lineno, line, arrow = False)
+
+ src.append(line)
+ self.lineno = lineno
+
+ print >>Term.cout, ''.join(src)
+
+ except KeyboardInterrupt:
+ pass
+
+ def do_list(self, arg):
+ self.lastcmd = 'list'
+ last = None
+ if arg:
+ try:
+ x = eval(arg, {}, {})
+ if type(x) == type(()):
+ first, last = x
+ first = int(first)
+ last = int(last)
+ if last < first:
+ # Assume it's a count
+ last = first + last
+ else:
+ first = max(1, int(x) - 5)
+ except:
+ print '*** Error in argument:', `arg`
+ return
+ elif self.lineno is None:
+ first = max(1, self.curframe.f_lineno - 5)
+ else:
+ first = self.lineno + 1
+ if last is None:
+ last = first + 10
+ self.print_list_lines(self.curframe.f_code.co_filename, first, last)
+
+ # vds: >>
+ lineno = first
+ filename = self.curframe.f_code.co_filename
+ __IPYTHON__.hooks.synchronize_with_editor(filename, lineno, 0)
+ # vds: <<
+
+ do_l = do_list
+
+ def do_pdef(self, arg):
+ """The debugger interface to magic_pdef"""
+ namespaces = [('Locals', self.curframe.f_locals),
+ ('Globals', self.curframe.f_globals)]
+ __IPYTHON__.magic_pdef(arg, namespaces=namespaces)
+
+ def do_pdoc(self, arg):
+ """The debugger interface to magic_pdoc"""
+ namespaces = [('Locals', self.curframe.f_locals),
+ ('Globals', self.curframe.f_globals)]
+ __IPYTHON__.magic_pdoc(arg, namespaces=namespaces)
+
+ def do_pinfo(self, arg):
+ """The debugger equivalant of ?obj"""
+ namespaces = [('Locals', self.curframe.f_locals),
+ ('Globals', self.curframe.f_globals)]
+ __IPYTHON__.magic_pinfo("pinfo %s" % arg, namespaces=namespaces)
diff --git a/IPython/Extensions/InterpreterExec.py b/IPython/Extensions/InterpreterExec.py
new file mode 100644
index 0000000..cca7c24
--- /dev/null
+++ b/IPython/Extensions/InterpreterExec.py
@@ -0,0 +1,253 @@
+# -*- coding: utf-8 -*-
+"""Modified input prompt for executing files.
+
+We define a special input line filter to allow typing lines which begin with
+'~', '/' or '.'. If one of those strings is encountered, it is automatically
+executed.
+"""
+
+#*****************************************************************************
+# Copyright (C) 2004 W.J. van der Laan <gnufnork@hetdigitalegat.nl>
+# Copyright (C) 2004-2006 Fernando Perez <fperez@colorado.edu>
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#*****************************************************************************
+
+# TODO: deprecated
+def prefilter_shell(self,line,continuation):
+ """Alternate prefilter, modified for shell-like functionality.
+
+ - Execute all lines beginning with '~', '/' or '.'
+ - $var=cmd <=> %sc var=cmd
+ - $$var=cmd <=> %sc -l var=cmd
+ """
+
+ if line:
+ l0 = line[0]
+ if l0 in '~/.':
+ return self._prefilter("!%s"%line,continuation)
+ elif l0=='$':
+ lrest = line[1:]
+ if lrest.startswith('$'):
+ # $$var=cmd <=> %sc -l var=cmd
+ return self._prefilter("%ssc -l %s" % (self.ESC_MAGIC,lrest[1:]),
+ continuation)
+ else:
+ # $var=cmd <=> %sc var=cmd
+ return self._prefilter("%ssc %s" % (self.ESC_MAGIC,lrest),
+ continuation)
+ else:
+ return self._prefilter(line,continuation)
+ else:
+ return self._prefilter(line,continuation)
+
+# Rebind this to be the new IPython prefilter:
+from IPython.iplib import InteractiveShell
+InteractiveShell.prefilter = prefilter_shell
+# Clean up the namespace.
+del InteractiveShell,prefilter_shell
+
+# Provide pysh and further shell-oriented services
+import os,sys,shutil
+from IPython.genutils import system,shell,getoutput,getoutputerror
+
+# Short aliases for getting shell output as a string and a list
+sout = getoutput
+lout = lambda cmd: getoutput(cmd,split=1)
+
+# Empty function, meant as a docstring holder so help(pysh) works.
+def pysh():
+ """Pysh is a set of modules and extensions to IPython which make shell-like
+ usage with Python syntax more convenient. Keep in mind that pysh is NOT a
+ full-blown shell, so don't try to make it your /etc/passwd entry!
+
+ In particular, it has no job control, so if you type Ctrl-Z (under Unix),
+ you'll suspend pysh itself, not the process you just started.
+
+ Since pysh is really nothing but a customized IPython, you should
+ familiarize yourself with IPython's features. This brief help mainly
+ documents areas in which pysh differs from the normal IPython.
+
+ ALIASES
+ -------
+ All of your $PATH has been loaded as IPython aliases, so you should be
+ able to type any normal system command and have it executed. See %alias?
+ and %unalias? for details on the alias facilities.
+
+ SPECIAL SYNTAX
+ --------------
+ Any lines which begin with '~', '/' and '.' will be executed as shell
+ commands instead of as Python code. The special escapes below are also
+ recognized. !cmd is valid in single or multi-line input, all others are
+ only valid in single-line input:
+
+ !cmd - pass 'cmd' directly to the shell
+ !!cmd - execute 'cmd' and return output as a list (split on '\\n')
+ $var=cmd - capture output of cmd into var, as a string
+ $$var=cmd - capture output of cmd into var, as a list (split on '\\n')
+
+ The $/$$ syntaxes make Python variables from system output, which you can
+ later use for further scripting. The converse is also possible: when
+ executing an alias or calling to the system via !/!!, you can expand any
+ python variable or expression by prepending it with $. Full details of
+ the allowed syntax can be found in Python's PEP 215.
+
+ A few brief examples will illustrate these:
+
+ fperez[~/test]|3> !ls *s.py
+ scopes.py strings.py
+
+ ls is an internal alias, so there's no need to use !:
+ fperez[~/test]|4> ls *s.py
+ scopes.py* strings.py
+
+ !!ls will return the output into a Python variable:
+ fperez[~/test]|5> !!ls *s.py
+ <5> ['scopes.py', 'strings.py']
+ fperez[~/test]|6> print _5
+ ['scopes.py', 'strings.py']
+
+ $ and $$ allow direct capture to named variables:
+ fperez[~/test]|7> $astr = ls *s.py
+ fperez[~/test]|8> astr
+ <8> 'scopes.py\\nstrings.py'
+
+ fperez[~/test]|9> $$alist = ls *s.py
+ fperez[~/test]|10> alist
+ <10> ['scopes.py', 'strings.py']
+
+ alist is now a normal python list you can loop over. Using $ will expand
+ back the python values when alias calls are made:
+ fperez[~/test]|11> for f in alist:
+ |..> print 'file',f,
+ |..> wc -l $f
+ |..>
+ file scopes.py 13 scopes.py
+ file strings.py 4 strings.py
+
+ Note that you may need to protect your variables with braces if you want
+ to append strings to their names. To copy all files in alist to .bak
+ extensions, you must use:
+ fperez[~/test]|12> for f in alist:
+ |..> cp $f ${f}.bak
+
+ If you try using $f.bak, you'll get an AttributeError exception saying
+ that your string object doesn't have a .bak attribute. This is because
+ the $ expansion mechanism allows you to expand full Python expressions:
+ fperez[~/test]|13> echo "sys.platform is: $sys.platform"
+ sys.platform is: linux2
+
+ IPython's input history handling is still active, which allows you to
+ rerun a single block of multi-line input by simply using exec:
+ fperez[~/test]|14> $$alist = ls *.eps
+ fperez[~/test]|15> exec _i11
+ file image2.eps 921 image2.eps
+ file image.eps 921 image.eps
+
+ While these are new special-case syntaxes, they are designed to allow very
+ efficient use of the shell with minimal typing. At an interactive shell
+ prompt, conciseness of expression wins over readability.
+
+ USEFUL FUNCTIONS AND MODULES
+ ----------------------------
+ The os, sys and shutil modules from the Python standard library are
+ automatically loaded. Some additional functions, useful for shell usage,
+ are listed below. You can request more help about them with '?'.
+
+ shell - execute a command in the underlying system shell
+ system - like shell(), but return the exit status of the command
+ sout - capture the output of a command as a string
+ lout - capture the output of a command as a list (split on '\\n')
+ getoutputerror - capture (output,error) of a shell command
+
+ sout/lout are the functional equivalents of $/$$. They are provided to
+ allow you to capture system output in the middle of true python code,
+ function definitions, etc (where $ and $$ are invalid).
+
+ DIRECTORY MANAGEMENT
+ --------------------
+ Since each command passed by pysh to the underlying system is executed in
+ a subshell which exits immediately, you can NOT use !cd to navigate the
+ filesystem.
+
+ Pysh provides its own builtin '%cd' magic command to move in the
+ filesystem (the % is not required with automagic on). It also maintains a
+ list of visited directories (use %dhist to see it) and allows direct
+ switching to any of them. Type 'cd?' for more details.
+
+ %pushd, %popd and %dirs are provided for directory stack handling.
+
+ PROMPT CUSTOMIZATION
+ --------------------
+
+ The supplied ipythonrc-pysh profile comes with an example of a very
+ colored and detailed prompt, mainly to serve as an illustration. The
+ valid escape sequences, besides color names, are:
+
+ \\# - Prompt number.
+ \\D - Dots, as many as there are digits in \\# (so they align).
+ \\w - Current working directory (cwd).
+ \\W - Basename of current working directory.
+ \\XN - Where N=0..5. N terms of the cwd, with $HOME written as ~.
+ \\YN - Where N=0..5. Like XN, but if ~ is term N+1 it's also shown.
+ \\u - Username.
+ \\H - Full hostname.
+ \\h - Hostname up to first '.'
+ \\$ - Root symbol ($ or #).
+ \\t - Current time, in H:M:S format.
+ \\v - IPython release version.
+ \\n - Newline.
+ \\r - Carriage return.
+ \\\\ - An explicitly escaped '\\'.
+
+ You can configure your prompt colors using any ANSI color escape. Each
+ color escape sets the color for any subsequent text, until another escape
+ comes in and changes things. The valid color escapes are:
+
+ \\C_Black
+ \\C_Blue
+ \\C_Brown
+ \\C_Cyan
+ \\C_DarkGray
+ \\C_Green
+ \\C_LightBlue
+ \\C_LightCyan
+ \\C_LightGray
+ \\C_LightGreen
+ \\C_LightPurple
+ \\C_LightRed
+ \\C_Purple
+ \\C_Red
+ \\C_White
+ \\C_Yellow
+ \\C_Normal - Stop coloring, defaults to your terminal settings.
+ """
+ pass
+
+# Configure a few things. Much of this is fairly hackish, since IPython
+# doesn't really expose a clean API for it. Be careful if you start making
+# many modifications here.
+
+
+# Set the 'cd' command to quiet mode, a more shell-like behavior
+__IPYTHON__.default_option('cd','-q')
+
+# This is redundant, ipy_user_conf.py will determine this
+# Load all of $PATH as aliases
+__IPYTHON__.magic_rehashx()
+
+# Remove %sc,%sx if present as aliases
+__IPYTHON__.magic_unalias('sc')
+__IPYTHON__.magic_unalias('sx')
+
+# We need different criteria for line-splitting, so that aliases such as
+# 'gnome-terminal' are interpreted as a single alias instead of variable
+# 'gnome' minus variable 'terminal'.
+import re
+__IPYTHON__.line_split = re.compile(r'^([\s*,;/])'
+ r'([\?\w\.\-\+]+\w*\s*)'
+ r'(\(?.*$)')
+
+# Namespace cleanup
+del re
diff --git a/IPython/Extensions/InterpreterPasteInput.py b/IPython/Extensions/InterpreterPasteInput.py
new file mode 100644
index 0000000..d16c911
--- /dev/null
+++ b/IPython/Extensions/InterpreterPasteInput.py
@@ -0,0 +1,124 @@
+# -*- coding: utf-8 -*-
+"""Modified input prompt for entering text with >>> or ... at the start.
+
+We define a special input line filter to allow typing lines which begin with
+'>>> ' or '... '. These two strings, if present at the start of the input
+line, are stripped. This allows for direct pasting of code from examples such
+as those available in the standard Python tutorial.
+
+Normally pasting such code is one chunk is impossible because of the
+extraneous >>> and ..., requiring one to do a line by line paste with careful
+removal of those characters. This module allows pasting that kind of
+multi-line examples in one pass.
+
+Here is an 'screenshot' of a section of the tutorial pasted into IPython with
+this feature enabled:
+
+In [1]: >>> def fib2(n): # return Fibonacci series up to n
+ ...: ... '''Return a list containing the Fibonacci series up to n.'''
+ ...: ... result = []
+ ...: ... a, b = 0, 1
+ ...: ... while b < n:
+ ...: ... result.append(b) # see below
+ ...: ... a, b = b, a+b
+ ...: ... return result
+ ...:
+
+In [2]: fib2(10)
+Out[2]: [1, 1, 2, 3, 5, 8]
+
+The >>> and ... are stripped from the input so that the python interpreter
+only sees the real part of the code.
+
+All other input is processed normally.
+
+Notes
+=====
+
+* You can even paste code that has extra initial spaces, such as is common in
+doctests:
+
+In [3]: >>> a = ['Mary', 'had', 'a', 'little', 'lamb']
+
+In [4]: >>> for i in range(len(a)):
+ ...: ... print i, a[i]
+ ...: ...
+0 Mary
+1 had
+2 a
+3 little
+4 lamb
+
+
+Authors
+-------
+- Fernando Perez <Fernando.Perez@berkeley.edu>
+"""
+
+#*****************************************************************************
+# Copyright (C) 2008-2009 The IPython Development Team
+# Copyright (C) 2001-2007 Fernando Perez <fperez@colorado.edu>
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#*****************************************************************************
+
+# This file is an example of how to modify IPython's line-processing behavior
+# without touching the internal code. We'll define an alternate pre-processing
+# stage which allows a special form of input (which is invalid Python syntax)
+# for certain quantities, rewrites a line of proper Python in those cases, and
+# then passes it off to IPython's normal processor for further work.
+
+# With this kind of customization, IPython can be adapted for many
+# special-purpose scenarios providing alternate input syntaxes.
+
+# This file can be imported like a regular module.
+
+# IPython has a prefilter() function that analyzes each input line. We redefine
+# it here to first pre-process certain forms of input
+
+# The prototype of any alternate prefilter must be like this one (the name
+# doesn't matter):
+# - line is a string containing the user input line.
+# - continuation is a parameter which tells us if we are processing a first
+# line of user input or the second or higher of a multi-line statement.
+
+import re
+
+from IPython.iplib import InteractiveShell
+
+PROMPT_RE = re.compile(r'(^[ \t]*>>> |^[ \t]*\.\.\. )')
+
+def prefilter_paste(self,line,continuation):
+ """Alternate prefilter for input of pasted code from an interpreter.
+ """
+ if not line:
+ return ''
+ m = PROMPT_RE.match(line)
+ if m:
+ # In the end, always call the default IPython _prefilter() function.
+ # Note that self must be passed explicitly, b/c we're calling the
+ # unbound class method (since this method will overwrite the instance
+ # prefilter())
+ return self._prefilter(line[len(m.group(0)):],continuation)
+ elif line.strip() == '...':
+ return self._prefilter('',continuation)
+ elif line.isspace():
+ # This allows us to recognize multiple input prompts separated by blank
+ # lines and pasted in a single chunk, very common when pasting doctests
+ # or long tutorial passages.
+ return ''
+ else:
+ return self._prefilter(line,continuation)
+
+def activate_prefilter():
+ """Rebind the input-pasting filter to be the new IPython prefilter"""
+ InteractiveShell.prefilter = prefilter_paste
+
+def deactivate_prefilter():
+ """Reset the filter."""
+ InteractiveShell.prefilter = InteractiveShell._prefilter
+
+# Just a heads up at the console
+activate_prefilter()
+print '*** Pasting of code with ">>>" or "..." has been enabled.'
diff --git a/IPython/Extensions/PhysicalQInput.py b/IPython/Extensions/PhysicalQInput.py
new file mode 100644
index 0000000..04f05c0
--- /dev/null
+++ b/IPython/Extensions/PhysicalQInput.py
@@ -0,0 +1,84 @@
+# -*- coding: utf-8 -*-
+"""Modified input prompt for entering quantities with units.
+
+Modify the behavior of the interactive interpreter to allow direct input of
+quantities with units without having to make a function call.
+
+Now the following forms are accepted:
+
+x = 4 m
+y = -.45e3 m/s
+g = 9.8 m/s**2
+a = 2.3 m/s^2 # ^ -> ** automatically
+
+All other input is processed normally.
+
+Authors
+-------
+- Fernando Perez <Fernando.Perez@berkeley.edu>
+"""
+#*****************************************************************************
+# Copyright (C) 2008-2009 The IPython Development Team
+# Copyright (C) 2001-2007 Fernando Perez <fperez@colorado.edu>
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#*****************************************************************************
+
+# This file is an example of how to modify IPython's line-processing behavior
+# without touching the internal code. We'll define an alternate pre-processing
+# stage which allows a special form of input (which is invalid Python syntax)
+# for certain quantities, rewrites a line of proper Python in those cases, and
+# then passes it off to IPython's normal processor for further work.
+
+# With this kind of customization, IPython can be adapted for many
+# special-purpose scenarios providing alternate input syntaxes.
+
+# This file can be imported like a regular module.
+
+# IPython has a prefilter() function that analyzes each input line. We redefine
+# it here to first pre-process certain forms of input
+
+# The prototype of any alternate prefilter must be like this one (the name
+# doesn't matter):
+# - line is a string containing the user input line.
+# - continuation is a parameter which tells us if we are processing a first line of
+# user input or the second or higher of a multi-line statement.
+
+def prefilter_PQ(self,line,continuation):
+ """Alternate prefilter for input of PhysicalQuantityInteractive objects.
+
+ This assumes that the function PhysicalQuantityInteractive() has been
+ imported."""
+
+ from re import match
+ from IPython.iplib import InteractiveShell
+
+ # This regexp is what does the real work
+ unit_split = match(r'\s*(\w+)\s*=\s*(-?\d*\.?\d*[eE]?-?\d*)\s+([a-zA-Z].*)',
+ line)
+
+ # If special input was ecnountered, process it:
+ if unit_split:
+ var,val,units = unit_split.groups()
+ if var and val and units:
+ units = units.replace('^','**')
+ # Now a valid line needs to be constructed for IPython to process:
+ line = var +" = PhysicalQuantityInteractive(" + val + ", '" + \
+ units + "')"
+ #print 'New line:',line # dbg
+
+ # In the end, always call the default IPython _prefilter() function. Note
+ # that self must be passed explicitly, b/c we're calling the unbound class
+ # method (since this method will overwrite the instance prefilter())
+ return InteractiveShell._prefilter(self,line,continuation)
+
+# Rebind this to be the new IPython prefilter:
+from IPython.iplib import InteractiveShell
+InteractiveShell.prefilter = prefilter_PQ
+
+# Clean up the namespace.
+del InteractiveShell,prefilter_PQ
+
+# Just a heads up at the console
+print '*** Simplified input for physical quantities enabled.'
diff --git a/IPython/Extensions/PhysicalQInteractive.py b/IPython/Extensions/PhysicalQInteractive.py
new file mode 100644
index 0000000..45817bc
--- /dev/null
+++ b/IPython/Extensions/PhysicalQInteractive.py
@@ -0,0 +1,90 @@
+# -*- coding: utf-8 -*-
+"""Modify the PhysicalQuantities class for more convenient interactive use.
+
+Also redefine some math functions to operate on PhysQties with no need for
+special method syntax. This just means moving them out to the global
+namespace.
+
+This module should always be loaded *after* math or Numeric, so it can
+overwrite math functions with the versions that handle units.
+
+Authors
+-------
+- Fernando Perez <Fernando.Perez@berkeley.edu>
+"""
+
+#*****************************************************************************
+# Copyright (C) 2008-2009 The IPython Development Team
+# Copyright (C) 2001-2007 Fernando Perez <fperez@colorado.edu>
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#*****************************************************************************
+
+from Scientific.Physics.PhysicalQuantities import PhysicalQuantity
+
+# This code can be set up to work with Numeric or with math for providing the
+# mathematical functions. Uncomment the one you prefer to use below.
+
+# If you use math, sin(x) won't work for x an array, only float or PhysQty
+import math
+
+# If you use Numeric, sin(x) works for x a float, PhysQty an array.
+#import Numeric as math
+
+class PhysicalQuantityFunction:
+ """Generic function wrapper for PhysicalQuantity instances.
+
+ Calls functions from either the math library or the instance's methods as
+ required. Allows using sin(theta) or sqrt(v**2) syntax irrespective of
+ whether theta is a pure number or a PhysicalQuantity.
+
+ This is *slow*. It's meant for convenient interactive use, not for
+ speed."""
+
+ def __init__(self,name):
+ self.name = name
+
+ def __call__(self,x):
+ if isinstance(x,PhysicalQuantity):
+ return PhysicalQuantity.__dict__[self.name](x)
+ else:
+ return math.__dict__[self.name](x)
+
+class PhysicalQuantityInteractive(PhysicalQuantity):
+ """Physical quantity with units - modified for Interactive use.
+
+ Basically, the __str__ and __repr__ methods have been swapped for more
+ convenient interactive use. Powers are shown as ^ instead of ** and only 4
+ significant figures are shown.
+
+ Also adds the following aliases for commonly used methods:
+ b = PhysicalQuantity.inBaseUnits
+ u = PhysicalQuantity.inUnitsOf
+
+ These are useful when doing a lot of interactive calculations.
+ """
+
+ # shorthands for the most useful unit conversions
+ b = PhysicalQuantity.inBaseUnits # so you can just type x.b to get base units
+ u = PhysicalQuantity.inUnitsOf
+
+ # This can be done, but it can get dangerous when coupled with IPython's
+ # auto-calling. Everything ends up shown in baseunits and things like x*2
+ # get automatically converted to k(*2), which doesn't work.
+ # Probably not a good idea in general...
+ #__call__ = b
+
+ def __str__(self):
+ return PhysicalQuantity.__repr__(self)
+
+ def __repr__(self):
+ value = '%.4G' % self.value
+ units = self.unit.name().replace('**','^')
+ return value + ' ' + units
+
+# implement the methods defined in PhysicalQuantity as PhysicalQuantityFunctions
+sin = PhysicalQuantityFunction('sin')
+cos = PhysicalQuantityFunction('cos')
+tan = PhysicalQuantityFunction('tan')
+sqrt = PhysicalQuantityFunction('sqrt')
diff --git a/IPython/Extensions/__init__.py b/IPython/Extensions/__init__.py
new file mode 100644
index 0000000..abc363b
--- /dev/null
+++ b/IPython/Extensions/__init__.py
@@ -0,0 +1,13 @@
+# -*- coding: utf-8 -*-
+"""This directory is meant for special-purpose extensions to IPython.
+
+This can include things which alter the syntax processing stage (see
+PhysicalQ_Input for an example of how to do this).
+
+Any file located here can be called with an 'execfile =' option as
+
+ execfile = Extensions/filename.py
+
+since the IPython directory itself is already part of the search path for
+files listed as 'execfile ='.
+"""
diff --git a/IPython/Extensions/astyle.py b/IPython/Extensions/astyle.py
new file mode 100644
index 0000000..9821d58
--- /dev/null
+++ b/IPython/Extensions/astyle.py
@@ -0,0 +1,400 @@
+"""
+``astyle`` provides classes for adding style (foreground and background color;
+bold; blink; etc.) to terminal and curses output.
+"""
+
+
+import sys, os
+
+try:
+ import curses
+except ImportError:
+ curses = None
+
+
+COLOR_BLACK = 0
+COLOR_RED = 1
+COLOR_GREEN = 2
+COLOR_YELLOW = 3
+COLOR_BLUE = 4
+COLOR_MAGENTA = 5
+COLOR_CYAN = 6
+COLOR_WHITE = 7
+
+A_BLINK = 1<<0 # Blinking text
+A_BOLD = 1<<1 # Extra bright or bold text
+A_DIM = 1<<2 # Half bright text
+A_REVERSE = 1<<3 # Reverse-video text
+A_STANDOUT = 1<<4 # The best highlighting mode available
+A_UNDERLINE = 1<<5 # Underlined text
+
+
+class Style(object):
+ """
+ Store foreground color, background color and attribute (bold, underlined
+ etc.).
+ """
+ __slots__ = ("fg", "bg", "attrs")
+
+ COLORNAMES = {
+ "black": COLOR_BLACK,
+ "red": COLOR_RED,
+ "green": COLOR_GREEN,
+ "yellow": COLOR_YELLOW,
+ "blue": COLOR_BLUE,
+ "magenta": COLOR_MAGENTA,
+ "cyan": COLOR_CYAN,
+ "white": COLOR_WHITE,
+ }
+ ATTRNAMES = {
+ "blink": A_BLINK,
+ "bold": A_BOLD,
+ "dim": A_DIM,
+ "reverse": A_REVERSE,
+ "standout": A_STANDOUT,
+ "underline": A_UNDERLINE,
+ }
+
+ def __init__(self, fg, bg, attrs=0):
+ """
+ Create a ``Style`` object with ``fg`` as the foreground color,
+ ``bg`` as the background color and ``attrs`` as the attributes.
+
+ Examples:
+ >>> Style(COLOR_RED, COLOR_BLACK)
+ <Style fg=red bg=black attrs=0>
+
+ >>> Style(COLOR_YELLOW, COLOR_BLUE, A_BOLD|A_UNDERLINE)
+ <Style fg=yellow bg=blue attrs=bold|underline>
+ """
+ self.fg = fg
+ self.bg = bg
+ self.attrs = attrs
+
+ def __call__(self, *args):
+ text = Text()
+ for arg in args:
+ if isinstance(arg, Text):
+ text.extend(arg)
+ else:
+ text.append((self, arg))
+ return text
+
+ def __eq__(self, other):
+ return self.fg == other.fg and self.bg == other.bg and self.attrs == other.attrs
+
+ def __neq__(self, other):
+ return self.fg != other.fg or self.bg != other.bg or self.attrs != other.attrs
+
+ def __repr__(self):
+ color2name = ("black", "red", "green", "yellow", "blue", "magenta", "cyan", "white")
+ attrs2name = ("blink", "bold", "dim", "reverse", "standout", "underline")
+
+ return "<%s fg=%s bg=%s attrs=%s>" % (
+ self.__class__.__name__, color2name[self.fg], color2name[self.bg],
+ "|".join([attrs2name[b] for b in xrange(6) if self.attrs&(1<<b)]) or 0)
+
+ def fromstr(cls, value):
+ """
+ Create a ``Style`` object from a string. The format looks like this:
+ ``"red:black:bold|blink"``.
+ """
+ # defaults
+ fg = COLOR_WHITE
+ bg = COLOR_BLACK
+ attrs = 0
+
+ parts = value.split(":")
+ if len(parts) > 0:
+ fg = cls.COLORNAMES[parts[0].lower()]
+ if len(parts) > 1:
+ bg = cls.COLORNAMES[parts[1].lower()]
+ if len(parts) > 2:
+ for strattr in parts[2].split("|"):
+ attrs |= cls.ATTRNAMES[strattr.lower()]
+ return cls(fg, bg, attrs)
+ fromstr = classmethod(fromstr)
+
+ def fromenv(cls, name, default):
+ """
+ Create a ``Style`` from an environment variable named ``name``
+ (using ``default`` if the environment variable doesn't exist).
+ """
+ return cls.fromstr(os.environ.get(name, default))
+ fromenv = classmethod(fromenv)
+
+
+def switchstyle(s1, s2):
+ """
+ Return the ANSI escape sequence needed to switch from style ``s1`` to
+ style ``s2``.
+ """
+ attrmask = (A_BLINK|A_BOLD|A_UNDERLINE|A_REVERSE)
+ a1 = s1.attrs & attrmask
+ a2 = s2.attrs & attrmask
+
+ args = []
+ if s1 != s2:
+ # do we have to get rid of the bold/underline/blink bit?
+ # (can only be done by a reset)
+ # use reset when our target color is the default color
+ # (this is shorter than 37;40)
+ if (a1 & ~a2 or s2==style_default):
+ args.append("0")
+ s1 = style_default
+ a1 = 0
+
+ # now we know that old and new color have the same boldness,
+ # or the new color is bold and the old isn't,
+ # i.e. we only might have to switch bold on, not off
+ if not (a1 & A_BOLD) and (a2 & A_BOLD):
+ args.append("1")
+
+ # Fix underline
+ if not (a1 & A_UNDERLINE) and (a2 & A_UNDERLINE):
+ args.append("4")
+
+ # Fix blink
+ if not (a1 & A_BLINK) and (a2 & A_BLINK):
+ args.append("5")
+
+ # Fix reverse
+ if not (a1 & A_REVERSE) and (a2 & A_REVERSE):
+ args.append("7")
+
+ # Fix foreground color
+ if s1.fg != s2.fg:
+ args.append("3%d" % s2.fg)
+
+ # Finally fix the background color
+ if s1.bg != s2.bg:
+ args.append("4%d" % s2.bg)
+
+ if args:
+ return "\033[%sm" % ";".join(args)
+ return ""
+
+
+class Text(list):
+ """
+ A colored string. A ``Text`` object is a sequence, the sequence
+ items will be ``(style, string)`` tuples.
+ """
+
+ def __init__(self, *args):
+ list.__init__(self)
+ self.append(*args)
+
+ def __repr__(self):
+ return "%s.%s(%s)" % (
+ self.__class__.__module__, self.__class__.__name__,
+ list.__repr__(self)[1:-1])
+
+ def append(self, *args):
+ for arg in args:
+ if isinstance(arg, Text):
+ self.extend(arg)
+ elif isinstance(arg, tuple): # must be (style, string)
+ list.append(self, arg)
+ elif isinstance(arg, unicode):
+ list.append(self, (style_default, arg))
+ else:
+ list.append(self, (style_default, str(arg)))
+
+ def insert(self, index, *args):
+ self[index:index] = Text(*args)
+
+ def __add__(self, other):
+ new = Text()
+ new.append(self)
+ new.append(other)
+ return new
+
+ def __iadd__(self, other):
+ self.append(other)
+ return self
+
+ def format(self, styled=True):
+ """
+ This generator yields the strings that will make up the final
+ colorized string.
+ """
+ if styled:
+ oldstyle = style_default
+ for (style, string) in self:
+ if not isinstance(style, (int, long)):
+ switch = switchstyle(oldstyle, style)
+ if switch:
+ yield switch
+ if string:
+ yield string
+ oldstyle = style
+ switch = switchstyle(oldstyle, style_default)
+ if switch:
+ yield switch
+ else:
+ for (style, string) in self:
+ if not isinstance(style, (int, long)):
+ yield string
+
+ def string(self, styled=True):
+ """
+ Return the resulting string (with escape sequences, if ``styled``
+ is true).
+ """
+ return "".join(self.format(styled))
+
+ def __str__(self):
+ """
+ Return ``self`` as a string (without ANSI escape sequences).
+ """
+ return self.string(False)
+
+ def write(self, stream, styled=True):
+ """
+ Write ``self`` to the output stream ``stream`` (with escape sequences,
+ if ``styled`` is true).
+ """
+ for part in self.format(styled):
+ stream.write(part)
+
+
+try:
+ import ipipe
+except ImportError:
+ pass
+else:
+ def xrepr_astyle_text(self, mode="default"):
+ yield (-1, True)
+ for info in self:
+ yield info
+ ipipe.xrepr.when_type(Text)(xrepr_astyle_text)
+
+
+def streamstyle(stream, styled=None):
+ """
+ If ``styled`` is ``None``, return whether ``stream`` refers to a terminal.
+ If this can't be determined (either because ``stream`` doesn't refer to a
+ real OS file, or because you're on Windows) return ``False``. If ``styled``
+ is not ``None`` ``styled`` will be returned unchanged.
+ """
+ if styled is None:
+ try:
+ styled = os.isatty(stream.fileno())
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except Exception:
+ styled = False
+ return styled
+
+
+def write(stream, styled, *texts):
+ """
+ Write ``texts`` to ``stream``.
+ """
+ text = Text(*texts)
+ text.write(stream, streamstyle(stream, styled))
+
+
+def writeln(stream, styled, *texts):
+ """
+ Write ``texts`` to ``stream`` and finish with a line feed.
+ """
+ write(stream, styled, *texts)
+ stream.write("\n")
+
+
+class Stream(object):
+ """
+ Stream wrapper that adds color output.
+ """
+ def __init__(self, stream, styled=None):
+ self.stream = stream
+ self.styled = streamstyle(stream, styled)
+
+ def write(self, *texts):
+ write(self.stream, self.styled, *texts)
+
+ def writeln(self, *texts):
+ writeln(self.stream, self.styled, *texts)
+
+ def __getattr__(self, name):
+ return getattr(self.stream, name)
+
+
+class stdout(object):
+ """
+ Stream wrapper for ``sys.stdout`` that adds color output.
+ """
+ def write(self, *texts):
+ write(sys.stdout, None, *texts)
+
+ def writeln(self, *texts):
+ writeln(sys.stdout, None, *texts)
+
+ def __getattr__(self, name):
+ return getattr(sys.stdout, name)
+stdout = stdout()
+
+
+class stderr(object):
+ """
+ Stream wrapper for ``sys.stderr`` that adds color output.
+ """
+ def write(self, *texts):
+ write(sys.stderr, None, *texts)
+
+ def writeln(self, *texts):
+ writeln(sys.stderr, None, *texts)
+
+ def __getattr__(self, name):
+ return getattr(sys.stdout, name)
+stderr = stderr()
+
+
+if curses is not None:
+ # This is probably just range(8)
+ COLOR2CURSES = [
+ COLOR_BLACK,
+ COLOR_RED,
+ COLOR_GREEN,
+ COLOR_YELLOW,
+ COLOR_BLUE,
+ COLOR_MAGENTA,
+ COLOR_CYAN,
+ COLOR_WHITE,
+ ]
+
+ A2CURSES = {
+ A_BLINK: curses.A_BLINK,
+ A_BOLD: curses.A_BOLD,
+ A_DIM: curses.A_DIM,
+ A_REVERSE: curses.A_REVERSE,
+ A_STANDOUT: curses.A_STANDOUT,
+ A_UNDERLINE: curses.A_UNDERLINE,
+ }
+
+
+# default style
+style_default = Style.fromstr("white:black")
+
+# Styles for datatypes
+style_type_none = Style.fromstr("magenta:black")
+style_type_bool = Style.fromstr("magenta:black")
+style_type_number = Style.fromstr("yellow:black")
+style_type_datetime = Style.fromstr("magenta:black")
+style_type_type = Style.fromstr("cyan:black")
+
+# Style for URLs and file/directory names
+style_url = Style.fromstr("green:black")
+style_dir = Style.fromstr("cyan:black")
+style_file = Style.fromstr("green:black")
+
+# Style for ellipsis (when an output has been shortened
+style_ellisis = Style.fromstr("red:black")
+
+# Style for displaying exceptions
+style_error = Style.fromstr("red:black")
+
+# Style for displaying non-existing attributes
+style_nodata = Style.fromstr("red:black")
diff --git a/IPython/Extensions/clearcmd.py b/IPython/Extensions/clearcmd.py
new file mode 100644
index 0000000..76cfbf7
--- /dev/null
+++ b/IPython/Extensions/clearcmd.py
@@ -0,0 +1,87 @@
+# -*- coding: utf-8 -*-
+""" IPython extension: add %clear magic """
+
+import IPython.ipapi
+import gc
+ip = IPython.ipapi.get()
+
+def clear_f(self,arg):
+ """ Clear various data (e.g. stored history data)
+
+ %clear in - clear input history
+ %clear out - clear output history
+ %clear shadow_compress - Compresses shadow history (to speed up ipython)
+ %clear shadow_nuke - permanently erase all entries in shadow history
+ %clear dhist - clear dir history
+ %clear array - clear only variables that are NumPy arrays
+
+ Examples:
+
+ In [1]: clear in
+ Flushing input history
+
+ In [2]: clear shadow_compress
+ Compressing shadow history
+
+ In [3]: clear shadow_nuke
+ Erased all keys from shadow history
+
+ In [4]: clear dhist
+ Clearing directory history
+ """
+
+ api = self.getapi()
+ user_ns = self.user_ns # local lookup, heavily used
+
+
+ for target in arg.split():
+
+ if target == 'out':
+ print "Flushing output cache (%d entries)" % len(user_ns['_oh'])
+ self.outputcache.flush()
+
+ elif target == 'in':
+ print "Flushing input history"
+ pc = self.outputcache.prompt_count + 1
+ for n in range(1, pc):
+ key = '_i'+`n`
+ user_ns.pop(key,None)
+ try:
+ del user_ns[key]
+ except: pass
+ # must be done in-place
+ self.input_hist[:] = ['\n'] * pc
+ self.input_hist_raw[:] = ['\n'] * pc
+
+ elif target == 'array':
+ # Support cleaning up numpy arrays
+ try:
+ from numpy import ndarray
+ # This must be done with items and not iteritems because we're
+ # going to modify the dict in-place.
+ for x,val in user_ns.items():
+ if isinstance(val,ndarray):
+ del user_ns[x]
+ except AttributeError:
+ print "Clear array only works if Numpy is available."
+
+ elif target == 'shadow_compress':
+ print "Compressing shadow history"
+ api.db.hcompress('shadowhist')
+
+ elif target == 'shadow_nuke':
+ print "Erased all keys from shadow history "
+ for k in ip.db.keys('shadowhist/*'):
+ del ip.db[k]
+
+ elif target == 'dhist':
+ print "Clearing directory history"
+ del user_ns['_dh'][:]
+
+ gc.collect()
+
+# Activate the extension
+ip.expose_magic("clear",clear_f)
+import ipy_completers
+ipy_completers.quick_completer(
+ '%clear','in out shadow_nuke shadow_compress dhist')
diff --git a/IPython/Extensions/envpersist.py b/IPython/Extensions/envpersist.py
new file mode 100644
index 0000000..ee4c139
--- /dev/null
+++ b/IPython/Extensions/envpersist.py
@@ -0,0 +1,90 @@
+# -*- coding: utf-8 -*-
+""" %env magic command for storing environment variables persistently
+"""
+
+import IPython.ipapi
+ip = IPython.ipapi.get()
+
+import os,sys
+
+def restore_env(self):
+ ip = self.getapi()
+ env = ip.db.get('stored_env', {'set' : {}, 'add' : [], 'pre' : []})
+ for k,v in env['set'].items():
+ os.environ[k] = v
+ for k,v in env['add']:
+ os.environ[k] = os.environ.get(k,"") + v
+ for k,v in env['pre']:
+ os.environ[k] = v + os.environ.get(k,"")
+ raise IPython.ipapi.TryNext
+
+ip.set_hook('late_startup_hook', restore_env)
+
+def persist_env(self, parameter_s=''):
+ """ Store environment variables persistently
+
+ IPython remembers the values across sessions, which is handy to avoid
+ editing startup files.
+
+ %env - Show all environment variables
+ %env VISUAL=jed - set VISUAL to jed
+ %env PATH+=;/foo - append ;foo to PATH
+ %env PATH+=;/bar - also append ;bar to PATH
+ %env PATH-=/wbin; - prepend /wbin; to PATH
+ %env -d VISUAL - forget VISUAL persistent val
+ %env -p - print all persistent env modifications
+ """
+
+ if not parameter_s.strip():
+ return os.environ.data
+
+ ip = self.getapi()
+ db = ip.db
+ env = ip.db.get('stored_env', {'set' : {}, 'add' : [], 'pre' : []})
+
+ if parameter_s.startswith('-p'):
+ return env
+
+ elif parameter_s.startswith('-d'):
+ parts = (parameter_s.split()[1], '<del>')
+
+ else:
+ parts = parameter_s.strip().split('=')
+
+ if len(parts) == 2:
+ k,v = [p.strip() for p in parts]
+
+ if v == '<del>':
+ if k in env['set']:
+ del env['set'][k]
+ env['add'] = [el for el in env['add'] if el[0] != k]
+ env['pre'] = [el for el in env['pre'] if el[0] != k]
+
+ print "Forgot '%s' (for next session)" % k
+
+ elif k.endswith('+'):
+ k = k[:-1]
+ env['add'].append((k,v))
+ os.environ[k] += v
+ print k,"after append =",os.environ[k]
+ elif k.endswith('-'):
+ k = k[:-1]
+ env['pre'].append((k,v))
+ os.environ[k] = v + os.environ.get(k,"")
+ print k,"after prepend =",os.environ[k]
+
+
+ else:
+ env['set'][k] = v
+ print "Setting",k,"to",v
+ os.environ[k] = v
+
+ db['stored_env'] = env
+
+def env_completer(self,event):
+ """ Custom completer that lists all env vars """
+ return os.environ.keys()
+
+ip.expose_magic('env', persist_env)
+ip.set_hook('complete_command',env_completer, str_key = '%env')
+
diff --git a/IPython/Extensions/ext_rescapture.py b/IPython/Extensions/ext_rescapture.py
new file mode 100644
index 0000000..e02b232
--- /dev/null
+++ b/IPython/Extensions/ext_rescapture.py
@@ -0,0 +1,63 @@
+# -*- coding: utf-8 -*-
+""" IPython extension: new prefilters for output grabbing
+
+Provides
+
+var = %magic blah blah
+
+var = !ls
+"""
+
+import IPython.ipapi
+from IPython.genutils import *
+
+ip = IPython.ipapi.get()
+
+import re
+
+def hnd_magic(line,mo):
+ """ Handle a = %mymagic blah blah """
+ #cmd = genutils.make_quoted_expr(mo.group('syscmd'))
+ #mag = 'ipmagic
+ #return "%s = %s"
+ var = mo.group('varname')
+ cmd = mo.group('cmd')
+ expr = make_quoted_expr(cmd)
+ return itpl('$var = _ip.magic($expr)')
+
+def hnd_syscmd(line,mo):
+ """ Handle a = !ls """
+ #cmd = genutils.make_quoted_expr(mo.group('syscmd'))
+ #mag = 'ipmagic
+ #return "%s = %s"
+ var = mo.group('varname')
+ cmd = mo.group('cmd')
+ expr = make_quoted_expr(itpl("sc -l =$cmd"))
+ return itpl('$var = _ip.magic($expr)')
+
+def install_re_handler(pat, hnd):
+ ip.meta.re_prefilters.append((re.compile(pat), hnd))
+
+def init_handlers():
+
+ ip.meta.re_prefilters = []
+
+ install_re_handler('(?P<varname>[\w\.]+)\s*=\s*%(?P<cmd>.*)',
+ hnd_magic
+ )
+
+ install_re_handler('(?P<varname>[\w\.]+)\s*=\s*!(?P<cmd>.*)',
+ hnd_syscmd
+ )
+
+init_handlers()
+
+def regex_prefilter_f(self,line):
+ for pat, handler in ip.meta.re_prefilters:
+ mo = pat.match(line)
+ if mo:
+ return handler(line,mo)
+
+ raise IPython.ipapi.TryNext
+
+ip.set_hook('input_prefilter', regex_prefilter_f)
diff --git a/IPython/Extensions/ibrowse.py b/IPython/Extensions/ibrowse.py
new file mode 100644
index 0000000..68a07c1
--- /dev/null
+++ b/IPython/Extensions/ibrowse.py
@@ -0,0 +1,1767 @@
+# -*- coding: iso-8859-1 -*-
+
+import curses, fcntl, signal, struct, tty, textwrap, inspect
+
+from IPython import ipapi
+
+import astyle, ipipe
+
+
+# Python 2.3 compatibility
+try:
+ set
+except NameError:
+ import sets
+ set = sets.Set
+
+# Python 2.3 compatibility
+try:
+ sorted
+except NameError:
+ from ipipe import sorted
+
+
+class UnassignedKeyError(Exception):
+ """
+ Exception that is used for reporting unassigned keys.
+ """
+
+
+class UnknownCommandError(Exception):
+ """
+ Exception that is used for reporting unknown commands (this should never
+ happen).
+ """
+
+
+class CommandError(Exception):
+ """
+ Exception that is used for reporting that a command can't be executed.
+ """
+
+
+class Keymap(dict):
+ """
+ Stores mapping of keys to commands.
+ """
+ def __init__(self):
+ self._keymap = {}
+
+ def __setitem__(self, key, command):
+ if isinstance(key, str):
+ for c in key:
+ dict.__setitem__(self, ord(c), command)
+ else:
+ dict.__setitem__(self, key, command)
+
+ def __getitem__(self, key):
+ if isinstance(key, str):
+ key = ord(key)
+ return dict.__getitem__(self, key)
+
+ def __detitem__(self, key):
+ if isinstance(key, str):
+ key = ord(key)
+ dict.__detitem__(self, key)
+
+ def register(self, command, *keys):
+ for key in keys:
+ self[key] = command
+
+ def get(self, key, default=None):
+ if isinstance(key, str):
+ key = ord(key)
+ return dict.get(self, key, default)
+
+ def findkey(self, command, default=ipipe.noitem):
+ for (key, commandcandidate) in self.iteritems():
+ if commandcandidate == command:
+ return key
+ if default is ipipe.noitem:
+ raise KeyError(command)
+ return default
+
+
+class _BrowserCachedItem(object):
+ # This is used internally by ``ibrowse`` to store a item together with its
+ # marked status.
+ __slots__ = ("item", "marked")
+
+ def __init__(self, item):
+ self.item = item
+ self.marked = False
+
+
+class _BrowserHelp(object):
+ style_header = astyle.Style.fromstr("yellow:black:bold")
+ # This is used internally by ``ibrowse`` for displaying the help screen.
+ def __init__(self, browser):
+ self.browser = browser
+
+ def __xrepr__(self, mode):
+ yield (-1, True)
+ if mode == "header" or mode == "footer":
+ yield (astyle.style_default, "ibrowse help screen")
+ else:
+ yield (astyle.style_default, repr(self))
+
+ def __iter__(self):
+ # Get reverse key mapping
+ allkeys = {}
+ for (key, cmd) in self.browser.keymap.iteritems():
+ allkeys.setdefault(cmd, []).append(key)
+
+ fields = ("key", "description")
+
+ commands = []
+ for name in dir(self.browser):
+ if name.startswith("cmd_"):
+ command = getattr(self.browser, name)
+ commands.append((inspect.getsourcelines(command)[-1], name[4:], command))
+ commands.sort()
+ commands = [(c[1], c[2]) for c in commands]
+ for (i, (name, command)) in enumerate(commands):
+ if i:
+ yield ipipe.Fields(fields, key="", description="")
+
+ description = command.__doc__
+ if description is None:
+ lines = []
+ else:
+ lines = [l.strip() for l in description.splitlines() if l.strip()]
+ description = "\n".join(lines)
+ lines = textwrap.wrap(description, 60)
+ keys = allkeys.get(name, [])
+
+ yield ipipe.Fields(fields, key="", description=astyle.Text((self.style_header, name)))
+ for i in xrange(max(len(keys), len(lines))):
+ try:
+ key = self.browser.keylabel(keys[i])
+ except IndexError:
+ key = ""
+ try:
+ line = lines[i]
+ except IndexError:
+ line = ""
+ yield ipipe.Fields(fields, key=key, description=line)
+
+
+class _BrowserLevel(object):
+ # This is used internally to store the state (iterator, fetch items,
+ # position of cursor and screen, etc.) of one browser level
+ # An ``ibrowse`` object keeps multiple ``_BrowserLevel`` objects in
+ # a stack.
+ def __init__(self, browser, input, mainsizey, *attrs):
+ self.browser = browser
+ self.input = input
+ self.header = [x for x in ipipe.xrepr(input, "header") if not isinstance(x[0], int)]
+ # iterator for the input
+ self.iterator = ipipe.xiter(input)
+
+ # is the iterator exhausted?
+ self.exhausted = False
+
+ # attributes to be display (autodetected if empty)
+ self.attrs = attrs
+
+ # fetched items (+ marked flag)
+ self.items = ipipe.deque()
+
+ # Number of marked objects
+ self.marked = 0
+
+ # Vertical cursor position
+ self.cury = 0
+
+ # Horizontal cursor position
+ self.curx = 0
+
+ # Index of first data column
+ self.datastartx = 0
+
+ # Index of first data line
+ self.datastarty = 0
+
+ # height of the data display area
+ self.mainsizey = mainsizey
+
+ # width of the data display area (changes when scrolling)
+ self.mainsizex = 0
+
+ # Size of row number (changes when scrolling)
+ self.numbersizex = 0
+
+ # Attributes to display (in this order)
+ self.displayattrs = []
+
+ # index and attribute under the cursor
+ self.displayattr = (None, ipipe.noitem)
+
+ # Maps attributes to column widths
+ self.colwidths = {}
+
+ # Set of hidden attributes
+ self.hiddenattrs = set()
+
+ # This takes care of all the caches etc.
+ self.moveto(0, 0, refresh=True)
+
+ def fetch(self, count):
+ # Try to fill ``self.items`` with at least ``count`` objects.
+ have = len(self.items)
+ while not self.exhausted and have < count:
+ try:
+ item = self.iterator.next()
+ except StopIteration:
+ self.exhausted = True
+ break
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except Exception, exc:
+ have += 1
+ self.items.append(_BrowserCachedItem(exc))
+ self.exhausted = True
+ break
+ else:
+ have += 1
+ self.items.append(_BrowserCachedItem(item))
+
+ def calcdisplayattrs(self):
+ # Calculate which attributes are available from the objects that are
+ # currently visible on screen (and store it in ``self.displayattrs``)
+
+ attrs = set()
+ self.displayattrs = []
+ if self.attrs:
+ # If the browser object specifies a fixed list of attributes,
+ # simply use it (removing hidden attributes).
+ for attr in self.attrs:
+ attr = ipipe.upgradexattr(attr)
+ if attr not in attrs and attr not in self.hiddenattrs:
+ self.displayattrs.append(attr)
+ attrs.add(attr)
+ else:
+ endy = min(self.datastarty+self.mainsizey, len(self.items))
+ for i in xrange(self.datastarty, endy):
+ for attr in ipipe.xattrs(self.items[i].item, "default"):
+ if attr not in attrs and attr not in self.hiddenattrs:
+ self.displayattrs.append(attr)
+ attrs.add(attr)
+
+ def getrow(self, i):
+ # Return a dictionary with the attributes for the object
+ # ``self.items[i]``. Attribute names are taken from
+ # ``self.displayattrs`` so ``calcdisplayattrs()`` must have been
+ # called before.
+ row = {}
+ item = self.items[i].item
+ for attr in self.displayattrs:
+ try:
+ value = attr.value(item)
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except Exception, exc:
+ value = exc
+ # only store attribute if it exists (or we got an exception)
+ if value is not ipipe.noitem:
+ # remember alignment, length and colored text
+ row[attr] = ipipe.xformat(value, "cell", self.browser.maxattrlength)
+ return row
+
+ def calcwidths(self):
+ # Recalculate the displayed fields and their widths.
+ # ``calcdisplayattrs()'' must have been called and the cache
+ # for attributes of the objects on screen (``self.displayrows``)
+ # must have been filled. This sets ``self.colwidths`` which maps
+ # attribute descriptors to widths.
+ self.colwidths = {}
+ for row in self.displayrows:
+ for attr in self.displayattrs:
+ try:
+ length = row[attr][1]
+ except KeyError:
+ length = 0
+ # always add attribute to colwidths, even if it doesn't exist
+ if attr not in self.colwidths:
+ self.colwidths[attr] = len(attr.name())
+ newwidth = max(self.colwidths[attr], length)
+ self.colwidths[attr] = newwidth
+
+ # How many characters do we need to paint the largest item number?
+ self.numbersizex = len(str(self.datastarty+self.mainsizey-1))
+ # How must space have we got to display data?
+ self.mainsizex = self.browser.scrsizex-self.numbersizex-3
+ # width of all columns
+ self.datasizex = sum(self.colwidths.itervalues()) + len(self.colwidths)
+
+ def calcdisplayattr(self):
+ # Find out which attribute the cursor is on and store this
+ # information in ``self.displayattr``.
+ pos = 0
+ for (i, attr) in enumerate(self.displayattrs):
+ if pos+self.colwidths[attr] >= self.curx:
+ self.displayattr = (i, attr)
+ break
+ pos += self.colwidths[attr]+1
+ else:
+ self.displayattr = (None, ipipe.noitem)
+
+ def moveto(self, x, y, refresh=False):
+ # Move the cursor to the position ``(x,y)`` (in data coordinates,
+ # not in screen coordinates). If ``refresh`` is true, all cached
+ # values will be recalculated (e.g. because the list has been
+ # resorted, so screen positions etc. are no longer valid).
+ olddatastarty = self.datastarty
+ oldx = self.curx
+ oldy = self.cury
+ x = int(x+0.5)
+ y = int(y+0.5)
+ newx = x # remember where we wanted to move
+ newy = y # remember where we wanted to move
+
+ scrollbordery = min(self.browser.scrollbordery, self.mainsizey//2)
+ scrollborderx = min(self.browser.scrollborderx, self.mainsizex//2)
+
+ # Make sure that the cursor didn't leave the main area vertically
+ if y < 0:
+ y = 0
+ # try to get enough items to fill the screen
+ self.fetch(max(y+scrollbordery+1, self.mainsizey))
+ if y >= len(self.items):
+ y = max(0, len(self.items)-1)
+
+ # Make sure that the cursor stays on screen vertically
+ if y < self.datastarty+scrollbordery:
+ self.datastarty = max(0, y-scrollbordery)
+ elif y >= self.datastarty+self.mainsizey-scrollbordery:
+ self.datastarty = max(0, min(y-self.mainsizey+scrollbordery+1,
+ len(self.items)-self.mainsizey))
+
+ if refresh: # Do we need to refresh the complete display?
+ self.calcdisplayattrs()
+ endy = min(self.datastarty+self.mainsizey, len(self.items))
+ self.displayrows = map(self.getrow, xrange(self.datastarty, endy))
+ self.calcwidths()
+ # Did we scroll vertically => update displayrows
+ # and various other attributes
+ elif self.datastarty != olddatastarty:
+ # Recalculate which attributes we have to display
+ olddisplayattrs = self.displayattrs
+ self.calcdisplayattrs()
+ # If there are new attributes, recreate the cache
+ if self.displayattrs != olddisplayattrs:
+ endy = min(self.datastarty+self.mainsizey, len(self.items))
+ self.displayrows = map(self.getrow, xrange(self.datastarty, endy))
+ elif self.datastarty<olddatastarty: # we did scroll up
+ # drop rows from the end
+ del self.displayrows[self.datastarty-olddatastarty:]
+ # fetch new items
+ for i in xrange(min(olddatastarty, self.datastarty+self.mainsizey)-1,
+ self.datastarty-1, -1):
+ try:
+ row = self.getrow(i)
+ except IndexError:
+ # we didn't have enough objects to fill the screen
+ break
+ self.displayrows.insert(0, row)
+ else: # we did scroll down
+ # drop rows from the start
+ del self.displayrows[:self.datastarty-olddatastarty]
+ # fetch new items
+ for i in xrange(max(olddatastarty+self.mainsizey, self.datastarty),
+ self.datastarty+self.mainsizey):
+ try:
+ row = self.getrow(i)
+ except IndexError:
+ # we didn't have enough objects to fill the screen
+ break
+ self.displayrows.append(row)
+ self.calcwidths()
+
+ # Make sure that the cursor didn't leave the data area horizontally
+ if x < 0:
+ x = 0
+ elif x >= self.datasizex:
+ x = max(0, self.datasizex-1)
+
+ # Make sure that the cursor stays on screen horizontally
+ if x < self.datastartx+scrollborderx:
+ self.datastartx = max(0, x-scrollborderx)
+ elif x >= self.datastartx+self.mainsizex-scrollborderx:
+ self.datastartx = max(0, min(x-self.mainsizex+scrollborderx+1,
+ self.datasizex-self.mainsizex))
+
+ if x == oldx and y == oldy and (x != newx or y != newy): # couldn't move
+ self.browser.beep()
+ else:
+ self.curx = x
+ self.cury = y
+ self.calcdisplayattr()
+
+ def sort(self, key, reverse=False):
+ """
+ Sort the currently list of items using the key function ``key``. If
+ ``reverse`` is true the sort order is reversed.
+ """
+ curitem = self.items[self.cury] # Remember where the cursor is now
+
+ # Sort items
+ def realkey(item):
+ return key(item.item)
+ self.items = ipipe.deque(sorted(self.items, key=realkey, reverse=reverse))
+
+ # Find out where the object under the cursor went
+ cury = self.cury
+ for (i, item) in enumerate(self.items):
+ if item is curitem:
+ cury = i
+ break
+
+ self.moveto(self.curx, cury, refresh=True)
+
+ def refresh(self):
+ """
+ Restart iterating the input.
+ """
+ self.iterator = ipipe.xiter(self.input)
+ self.items.clear()
+ self.exhausted = False
+ self.datastartx = self.datastarty = 0
+ self.moveto(0, 0, refresh=True)
+
+ def refreshfind(self):
+ """
+ Restart iterating the input and go back to the same object as before
+ (if it can be found in the new iterator).
+ """
+ try:
+ oldobject = self.items[self.cury].item
+ except IndexError:
+ oldobject = ipipe.noitem
+ self.iterator = ipipe.xiter(self.input)
+ self.items.clear()
+ self.exhausted = False
+ while True:
+ self.fetch(len(self.items)+1)
+ if self.exhausted:
+ curses.beep()
+ self.datastartx = self.datastarty = 0
+ self.moveto(self.curx, 0, refresh=True)
+ break
+ if self.items[-1].item == oldobject:
+ self.datastartx = self.datastarty = 0
+ self.moveto(self.curx, len(self.items)-1, refresh=True)
+ break
+
+
+class _CommandInput(object):
+ keymap = Keymap()
+ keymap.register("left", curses.KEY_LEFT)
+ keymap.register("right", curses.KEY_RIGHT)
+ keymap.register("home", curses.KEY_HOME, "\x01") # Ctrl-A
+ keymap.register("end", curses.KEY_END, "\x05") # Ctrl-E
+ # FIXME: What's happening here?
+ keymap.register("backspace", curses.KEY_BACKSPACE, "\x08\x7f")
+ keymap.register("delete", curses.KEY_DC)
+ keymap.register("delend", 0x0b) # Ctrl-K
+ keymap.register("execute", "\r\n")
+ keymap.register("up", curses.KEY_UP)
+ keymap.register("down", curses.KEY_DOWN)
+ keymap.register("incsearchup", curses.KEY_PPAGE)
+ keymap.register("incsearchdown", curses.KEY_NPAGE)
+ keymap.register("exit", "\x18"), # Ctrl-X
+
+ def __init__(self, prompt):
+ self.prompt = prompt
+ self.history = []
+ self.maxhistory = 100
+ self.input = ""
+ self.curx = 0
+ self.cury = -1 # blank line
+
+ def start(self):
+ self.input = ""
+ self.curx = 0
+ self.cury = -1 # blank line
+
+ def handlekey(self, browser, key):
+ cmdname = self.keymap.get(key, None)
+ if cmdname is not None:
+ cmdfunc = getattr(self, "cmd_%s" % cmdname, None)
+ if cmdfunc is not None:
+ return cmdfunc(browser)
+ curses.beep()
+ elif key != -1:
+ try:
+ char = chr(key)
+ except ValueError:
+ curses.beep()
+ else:
+ return self.handlechar(browser, char)
+
+ def handlechar(self, browser, char):
+ self.input = self.input[:self.curx] + char + self.input[self.curx:]
+ self.curx += 1
+ return True
+
+ def dohistory(self):
+ self.history.insert(0, self.input)
+ del self.history[:-self.maxhistory]
+
+ def cmd_backspace(self, browser):
+ if self.curx:
+ self.input = self.input[:self.curx-1] + self.input[self.curx:]
+ self.curx -= 1
+ return True
+ else:
+ curses.beep()
+
+ def cmd_delete(self, browser):
+ if self.curx<len(self.input):
+ self.input = self.input[:self.curx] + self.input[self.curx+1:]
+ return True
+ else:
+ curses.beep()
+
+ def cmd_delend(self, browser):
+ if self.curx<len(self.input):
+ self.input = self.input[:self.curx]
+ return True
+
+ def cmd_left(self, browser):
+ if self.curx:
+ self.curx -= 1
+ return True
+ else:
+ curses.beep()
+
+ def cmd_right(self, browser):
+ if self.curx < len(self.input):
+ self.curx += 1
+ return True
+ else:
+ curses.beep()
+
+ def cmd_home(self, browser):
+ if self.curx:
+ self.curx = 0
+ return True
+ else:
+ curses.beep()
+
+ def cmd_end(self, browser):
+ if self.curx < len(self.input):
+ self.curx = len(self.input)
+ return True
+ else:
+ curses.beep()
+
+ def cmd_up(self, browser):
+ if self.cury < len(self.history)-1:
+ self.cury += 1
+ self.input = self.history[self.cury]
+ self.curx = len(self.input)
+ return True
+ else:
+ curses.beep()
+
+ def cmd_down(self, browser):
+ if self.cury >= 0:
+ self.cury -= 1
+ if self.cury>=0:
+ self.input = self.history[self.cury]
+ else:
+ self.input = ""
+ self.curx = len(self.input)
+ return True
+ else:
+ curses.beep()
+
+ def cmd_incsearchup(self, browser):
+ prefix = self.input[:self.curx]
+ cury = self.cury
+ while True:
+ cury += 1
+ if cury >= len(self.history):
+ break
+ if self.history[cury].startswith(prefix):
+ self.input = self.history[cury]
+ self.cury = cury
+ return True
+ curses.beep()
+
+ def cmd_incsearchdown(self, browser):
+ prefix = self.input[:self.curx]
+ cury = self.cury
+ while True:
+ cury -= 1
+ if cury <= 0:
+ break
+ if self.history[cury].startswith(prefix):
+ self.input = self.history[self.cury]
+ self.cury = cury
+ return True
+ curses.beep()
+
+ def cmd_exit(self, browser):
+ browser.mode = "default"
+ return True
+
+ def cmd_execute(self, browser):
+ raise NotImplementedError
+
+
+class _CommandGoto(_CommandInput):
+ def __init__(self):
+ _CommandInput.__init__(self, "goto object #")
+
+ def handlechar(self, browser, char):
+ # Only accept digits
+ if not "0" <= char <= "9":
+ curses.beep()
+ else:
+ return _CommandInput.handlechar(self, browser, char)
+
+ def cmd_execute(self, browser):
+ level = browser.levels[-1]
+ if self.input:
+ self.dohistory()
+ level.moveto(level.curx, int(self.input))
+ browser.mode = "default"
+ return True
+
+
+class _CommandFind(_CommandInput):
+ def __init__(self):
+ _CommandInput.__init__(self, "find expression")
+
+ def cmd_execute(self, browser):
+ level = browser.levels[-1]
+ if self.input:
+ self.dohistory()
+ while True:
+ cury = level.cury
+ level.moveto(level.curx, cury+1)
+ if cury == level.cury:
+ curses.beep()
+ break # hit end
+ item = level.items[level.cury].item
+ try:
+ globals = ipipe.getglobals(None)
+ if eval(self.input, globals, ipipe.AttrNamespace(item)):
+ break # found something
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except Exception, exc:
+ browser.report(exc)
+ curses.beep()
+ break # break on error
+ browser.mode = "default"
+ return True
+
+
+class _CommandFindBackwards(_CommandInput):
+ def __init__(self):
+ _CommandInput.__init__(self, "find backwards expression")
+
+ def cmd_execute(self, browser):
+ level = browser.levels[-1]
+ if self.input:
+ self.dohistory()
+ while level.cury:
+ level.moveto(level.curx, level.cury-1)
+ item = level.items[level.cury].item
+ try:
+ globals = ipipe.getglobals(None)
+ if eval(self.input, globals, ipipe.AttrNamespace(item)):
+ break # found something
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except Exception, exc:
+ browser.report(exc)
+ curses.beep()
+ break # break on error
+ else:
+ curses.beep()
+ browser.mode = "default"
+ return True
+
+
+class ibrowse(ipipe.Display):
+ # Show this many lines from the previous screen when paging horizontally
+ pageoverlapx = 1
+
+ # Show this many lines from the previous screen when paging vertically
+ pageoverlapy = 1
+
+ # Start scrolling when the cursor is less than this number of columns
+ # away from the left or right screen edge
+ scrollborderx = 10
+
+ # Start scrolling when the cursor is less than this number of lines
+ # away from the top or bottom screen edge
+ scrollbordery = 5
+
+ # Accelerate by this factor when scrolling horizontally
+ acceleratex = 1.05
+
+ # Accelerate by this factor when scrolling vertically
+ acceleratey = 1.05
+
+ # The maximum horizontal scroll speed
+ # (as a factor of the screen width (i.e. 0.5 == half a screen width)
+ maxspeedx = 0.5
+
+ # The maximum vertical scroll speed
+ # (as a factor of the screen height (i.e. 0.5 == half a screen height)
+ maxspeedy = 0.5
+
+ # The maximum number of header lines for browser level
+ # if the nesting is deeper, only the innermost levels are displayed
+ maxheaders = 5
+
+ # The approximate maximum length of a column entry
+ maxattrlength = 200
+
+ # Styles for various parts of the GUI
+ style_objheadertext = astyle.Style.fromstr("white:black:bold|reverse")
+ style_objheadernumber = astyle.Style.fromstr("white:blue:bold|reverse")
+ style_objheaderobject = astyle.Style.fromstr("white:black:reverse")
+ style_colheader = astyle.Style.fromstr("blue:white:reverse")
+ style_colheaderhere = astyle.Style.fromstr("green:black:bold|reverse")
+ style_colheadersep = astyle.Style.fromstr("blue:black:reverse")
+ style_number = astyle.Style.fromstr("blue:white:reverse")
+ style_numberhere = astyle.Style.fromstr("green:black:bold|reverse")
+ style_sep = astyle.Style.fromstr("blue:black")
+ style_data = astyle.Style.fromstr("white:black")
+ style_datapad = astyle.Style.fromstr("blue:black:bold")
+ style_footer = astyle.Style.fromstr("black:white")
+ style_report = astyle.Style.fromstr("white:black")
+
+ # Column separator in header
+ headersepchar = "|"
+
+ # Character for padding data cell entries
+ datapadchar = "."
+
+ # Column separator in data area
+ datasepchar = "|"
+
+ # Character to use for "empty" cell (i.e. for non-existing attributes)
+ nodatachar = "-"
+
+ # Prompts for modes that require keyboard input
+ prompts = {
+ "goto": _CommandGoto(),
+ "find": _CommandFind(),
+ "findbackwards": _CommandFindBackwards()
+ }
+
+ # Maps curses key codes to "function" names
+ keymap = Keymap()
+ keymap.register("quit", "q")
+ keymap.register("up", curses.KEY_UP)
+ keymap.register("down", curses.KEY_DOWN)
+ keymap.register("pageup", curses.KEY_PPAGE)
+ keymap.register("pagedown", curses.KEY_NPAGE)
+ keymap.register("left", curses.KEY_LEFT)
+ keymap.register("right", curses.KEY_RIGHT)
+ keymap.register("home", curses.KEY_HOME, "\x01")
+ keymap.register("end", curses.KEY_END, "\x05")
+ keymap.register("prevattr", "<\x1b")
+ keymap.register("nextattr", ">\t")
+ keymap.register("pick", "p")
+ keymap.register("pickattr", "P")
+ keymap.register("pickallattrs", "C")
+ keymap.register("pickmarked", "m")
+ keymap.register("pickmarkedattr", "M")
+ keymap.register("pickinput", "i")
+ keymap.register("pickinputattr", "I")
+ keymap.register("hideattr", "h")
+ keymap.register("unhideattrs", "H")
+ keymap.register("help", "?")
+ keymap.register("enter", "\r\n")
+ keymap.register("enterattr", "E")
+ # FIXME: What's happening here?
+ keymap.register("leave", curses.KEY_BACKSPACE, "x\x08\x7f")
+ keymap.register("detail", "d")
+ keymap.register("detailattr", "D")
+ keymap.register("tooglemark", " ")
+ keymap.register("markrange", "%")
+ keymap.register("sortattrasc", "v")
+ keymap.register("sortattrdesc", "V")
+ keymap.register("goto", "g")
+ keymap.register("find", "f")
+ keymap.register("findbackwards", "b")
+ keymap.register("refresh", "r")
+ keymap.register("refreshfind", "R")
+
+ def __init__(self, input=None, *attrs):
+ """
+ Create a new browser. If ``attrs`` is not empty, it is the list
+ of attributes that will be displayed in the browser, otherwise
+ these will be determined by the objects on screen.
+ """
+ ipipe.Display.__init__(self, input)
+
+ self.attrs = attrs
+
+ # Stack of browser levels
+ self.levels = []
+ # how many colums to scroll (Changes when accelerating)
+ self.stepx = 1.
+
+ # how many rows to scroll (Changes when accelerating)
+ self.stepy = 1.
+
+ # Beep on the edges of the data area? (Will be set to ``False``
+ # once the cursor hits the edge of the screen, so we don't get
+ # multiple beeps).
+ self._dobeep = True
+
+ # Cache for registered ``curses`` colors and styles.
+ self._styles = {}
+ self._colors = {}
+ self._maxcolor = 1
+
+ # How many header lines do we want to paint (the numbers of levels
+ # we have, but with an upper bound)
+ self._headerlines = 1
+
+ # Index of first header line
+ self._firstheaderline = 0
+
+ # curses window
+ self.scr = None
+ # report in the footer line (error, executed command etc.)
+ self._report = None
+
+ # value to be returned to the caller (set by commands)
+ self.returnvalue = None
+
+ # The mode the browser is in
+ # e.g. normal browsing or entering an argument for a command
+ self.mode = "default"
+
+ # set by the SIGWINCH signal handler
+ self.resized = False
+
+ def nextstepx(self, step):
+ """
+ Accelerate horizontally.
+ """
+ return max(1., min(step*self.acceleratex,
+ self.maxspeedx*self.levels[-1].mainsizex))
+
+ def nextstepy(self, step):
+ """
+ Accelerate vertically.
+ """
+ return max(1., min(step*self.acceleratey,
+ self.maxspeedy*self.levels[-1].mainsizey))
+
+ def getstyle(self, style):
+ """
+ Register the ``style`` with ``curses`` or get it from the cache,
+ if it has been registered before.
+ """
+ try:
+ return self._styles[style.fg, style.bg, style.attrs]
+ except KeyError:
+ attrs = 0
+ for b in astyle.A2CURSES:
+ if style.attrs & b:
+ attrs |= astyle.A2CURSES[b]
+ try:
+ color = self._colors[style.fg, style.bg]
+ except KeyError:
+ curses.init_pair(
+ self._maxcolor,
+ astyle.COLOR2CURSES[style.fg],
+ astyle.COLOR2CURSES[style.bg]
+ )
+ color = curses.color_pair(self._maxcolor)
+ self._colors[style.fg, style.bg] = color
+ self._maxcolor += 1
+ c = color | attrs
+ self._styles[style.fg, style.bg, style.attrs] = c
+ return c
+
+ def addstr(self, y, x, begx, endx, text, style):
+ """
+ A version of ``curses.addstr()`` that can handle ``x`` coordinates
+ that are outside the screen.
+ """
+ text2 = text[max(0, begx-x):max(0, endx-x)]
+ if text2:
+ self.scr.addstr(y, max(x, begx), text2, self.getstyle(style))
+ return len(text)
+
+ def addchr(self, y, x, begx, endx, c, l, style):
+ x0 = max(x, begx)
+ x1 = min(x+l, endx)
+ if x1>x0:
+ self.scr.addstr(y, x0, c*(x1-x0), self.getstyle(style))
+ return l
+
+ def _calcheaderlines(self, levels):
+ # Calculate how many headerlines do we have to display, if we have
+ # ``levels`` browser levels
+ if levels is None:
+ levels = len(self.levels)
+ self._headerlines = min(self.maxheaders, levels)
+ self._firstheaderline = levels-self._headerlines
+
+ def getstylehere(self, style):
+ """
+ Return a style for displaying the original style ``style``
+ in the row the cursor is on.
+ """
+ return astyle.Style(style.fg, astyle.COLOR_BLUE, style.attrs | astyle.A_BOLD)
+
+ def report(self, msg):
+ """
+ Store the message ``msg`` for display below the footer line. This
+ will be displayed as soon as the screen is redrawn.
+ """
+ self._report = msg
+
+ def enter(self, item, *attrs):
+ """
+ Enter the object ``item``. If ``attrs`` is specified, it will be used
+ as a fixed list of attributes to display.
+ """
+ if self.levels and item is self.levels[-1].input:
+ curses.beep()
+ self.report(CommandError("Recursion on input object"))
+ else:
+ oldlevels = len(self.levels)
+ self._calcheaderlines(oldlevels+1)
+ try:
+ level = _BrowserLevel(
+ self,
+ item,
+ self.scrsizey-1-self._headerlines-2,
+ *attrs
+ )
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except Exception, exc:
+ if not self.levels:
+ raise
+ self._calcheaderlines(oldlevels)
+ curses.beep()
+ self.report(exc)
+ else:
+ self.levels.append(level)
+
+ def startkeyboardinput(self, mode):
+ """
+ Enter mode ``mode``, which requires keyboard input.
+ """
+ self.mode = mode
+ self.prompts[mode].start()
+
+ def keylabel(self, keycode):
+ """
+ Return a pretty name for the ``curses`` key ``keycode`` (used in the
+ help screen and in reports about unassigned keys).
+ """
+ if keycode <= 0xff:
+ specialsnames = {
+ ord("\n"): "RETURN",
+ ord(" "): "SPACE",
+ ord("\t"): "TAB",
+ ord("\x7f"): "DELETE",
+ ord("\x08"): "BACKSPACE",
+ }
+ if keycode in specialsnames:
+ return specialsnames[keycode]
+ elif 0x00 < keycode < 0x20:
+ return "CTRL-%s" % chr(keycode + 64)
+ return repr(chr(keycode))
+ for name in dir(curses):
+ if name.startswith("KEY_") and getattr(curses, name) == keycode:
+ return name
+ return str(keycode)
+
+ def beep(self, force=False):
+ if force or self._dobeep:
+ curses.beep()
+ # don't beep again (as long as the same key is pressed)
+ self._dobeep = False
+
+ def cmd_up(self):
+ """
+ Move the cursor to the previous row.
+ """
+ level = self.levels[-1]
+ self.report("up")
+ level.moveto(level.curx, level.cury-self.stepy)
+
+ def cmd_down(self):
+ """
+ Move the cursor to the next row.
+ """
+ level = self.levels[-1]
+ self.report("down")
+ level.moveto(level.curx, level.cury+self.stepy)
+
+ def cmd_pageup(self):
+ """
+ Move the cursor up one page.
+ """
+ level = self.levels[-1]
+ self.report("page up")
+ level.moveto(level.curx, level.cury-level.mainsizey+self.pageoverlapy)
+
+ def cmd_pagedown(self):
+ """
+ Move the cursor down one page.
+ """
+ level = self.levels[-1]
+ self.report("page down")
+ level.moveto(level.curx, level.cury+level.mainsizey-self.pageoverlapy)
+
+ def cmd_left(self):
+ """
+ Move the cursor left.
+ """
+ level = self.levels[-1]
+ self.report("left")
+ level.moveto(level.curx-self.stepx, level.cury)
+
+ def cmd_right(self):
+ """
+ Move the cursor right.
+ """
+ level = self.levels[-1]
+ self.report("right")
+ level.moveto(level.curx+self.stepx, level.cury)
+
+ def cmd_home(self):
+ """
+ Move the cursor to the first column.
+ """
+ level = self.levels[-1]
+ self.report("home")
+ level.moveto(0, level.cury)
+
+ def cmd_end(self):
+ """
+ Move the cursor to the last column.
+ """
+ level = self.levels[-1]
+ self.report("end")
+ level.moveto(level.datasizex+level.mainsizey-self.pageoverlapx, level.cury)
+
+ def cmd_prevattr(self):
+ """
+ Move the cursor one attribute column to the left.
+ """
+ level = self.levels[-1]
+ if level.displayattr[0] is None or level.displayattr[0] == 0:
+ self.beep()
+ else:
+ self.report("prevattr")
+ pos = 0
+ for (i, attrname) in enumerate(level.displayattrs):
+ if i == level.displayattr[0]-1:
+ break
+ pos += level.colwidths[attrname] + 1
+ level.moveto(pos, level.cury)
+
+ def cmd_nextattr(self):
+ """
+ Move the cursor one attribute column to the right.
+ """
+ level = self.levels[-1]
+ if level.displayattr[0] is None or level.displayattr[0] == len(level.displayattrs)-1:
+ self.beep()
+ else:
+ self.report("nextattr")
+ pos = 0
+ for (i, attrname) in enumerate(level.displayattrs):
+ if i == level.displayattr[0]+1:
+ break
+ pos += level.colwidths[attrname] + 1
+ level.moveto(pos, level.cury)
+
+ def cmd_pick(self):
+ """
+ 'Pick' the object under the cursor (i.e. the row the cursor is on).
+ This leaves the browser and returns the picked object to the caller.
+ (In IPython this object will be available as the ``_`` variable.)
+ """
+ level = self.levels[-1]
+ self.returnvalue = level.items[level.cury].item
+ return True
+
+ def cmd_pickattr(self):
+ """
+ 'Pick' the attribute under the cursor (i.e. the row/column the
+ cursor is on).
+ """
+ level = self.levels[-1]
+ attr = level.displayattr[1]
+ if attr is ipipe.noitem:
+ curses.beep()
+ self.report(CommandError("no column under cursor"))
+ return
+ value = attr.value(level.items[level.cury].item)
+ if value is ipipe.noitem:
+ curses.beep()
+ self.report(AttributeError(attr.name()))
+ else:
+ self.returnvalue = value
+ return True
+
+ def cmd_pickallattrs(self):
+ """
+ Pick' the complete column under the cursor (i.e. the attribute under
+ the cursor) from all currently fetched objects. These attributes
+ will be returned as a list.
+ """
+ level = self.levels[-1]
+ attr = level.displayattr[1]
+ if attr is ipipe.noitem:
+ curses.beep()
+ self.report(CommandError("no column under cursor"))
+ return
+ result = []
+ for cache in level.items:
+ value = attr.value(cache.item)
+ if value is not ipipe.noitem:
+ result.append(value)
+ self.returnvalue = result
+ return True
+
+ def cmd_pickmarked(self):
+ """
+ 'Pick' marked objects. Marked objects will be returned as a list.
+ """
+ level = self.levels[-1]
+ self.returnvalue = [cache.item for cache in level.items if cache.marked]
+ return True
+
+ def cmd_pickmarkedattr(self):
+ """
+ 'Pick' the attribute under the cursor from all marked objects
+ (This returns a list).
+ """
+
+ level = self.levels[-1]
+ attr = level.displayattr[1]
+ if attr is ipipe.noitem:
+ curses.beep()
+ self.report(CommandError("no column under cursor"))
+ return
+ result = []
+ for cache in level.items:
+ if cache.marked:
+ value = attr.value(cache.item)
+ if value is not ipipe.noitem:
+ result.append(value)
+ self.returnvalue = result
+ return True
+
+ def cmd_pickinput(self):
+ """
+ Use the object under the cursor (i.e. the row the cursor is on) as
+ the next input line. This leaves the browser and puts the picked object
+ in the input.
+ """
+ level = self.levels[-1]
+ value = level.items[level.cury].item
+ self.returnvalue = None
+ api = ipapi.get()
+ api.set_next_input(str(value))
+ return True
+
+ def cmd_pickinputattr(self):
+ """
+ Use the attribute under the cursor i.e. the row/column the cursor is on)
+ as the next input line. This leaves the browser and puts the picked
+ object in the input.
+ """
+ level = self.levels[-1]
+ attr = level.displayattr[1]
+ if attr is ipipe.noitem:
+ curses.beep()
+ self.report(CommandError("no column under cursor"))
+ return
+ value = attr.value(level.items[level.cury].item)
+ if value is ipipe.noitem:
+ curses.beep()
+ self.report(AttributeError(attr.name()))
+ self.returnvalue = None
+ api = ipapi.get()
+ api.set_next_input(str(value))
+ return True
+
+ def cmd_markrange(self):
+ """
+ Mark all objects from the last marked object before the current cursor
+ position to the cursor position.
+ """
+ level = self.levels[-1]
+ self.report("markrange")
+ start = None
+ if level.items:
+ for i in xrange(level.cury, -1, -1):
+ if level.items[i].marked:
+ start = i
+ break
+ if start is None:
+ self.report(CommandError("no mark before cursor"))
+ curses.beep()
+ else:
+ for i in xrange(start, level.cury+1):
+ cache = level.items[i]
+ if not cache.marked:
+ cache.marked = True
+ level.marked += 1
+
+ def cmd_enter(self):
+ """
+ Enter the object under the cursor. (what this mean depends on the object
+ itself (i.e. how it implements iteration). This opens a new browser 'level'.
+ """
+ level = self.levels[-1]
+ try:
+ item = level.items[level.cury].item
+ except IndexError:
+ self.report(CommandError("No object"))
+ curses.beep()
+ else:
+ self.report("entering object...")
+ self.enter(item)
+
+ def cmd_leave(self):
+ """
+ Leave the current browser level and go back to the previous one.
+ """
+ self.report("leave")
+ if len(self.levels) > 1:
+ self._calcheaderlines(len(self.levels)-1)
+ self.levels.pop(-1)
+ else:
+ self.report(CommandError("This is the last level"))
+ curses.beep()
+
+ def cmd_enterattr(self):
+ """
+ Enter the attribute under the cursor.
+ """
+ level = self.levels[-1]
+ attr = level.displayattr[1]
+ if attr is ipipe.noitem:
+ curses.beep()
+ self.report(CommandError("no column under cursor"))
+ return
+ try:
+ item = level.items[level.cury].item
+ except IndexError:
+ self.report(CommandError("No object"))
+ curses.beep()
+ else:
+ value = attr.value(item)
+ name = attr.name()
+ if value is ipipe.noitem:
+ self.report(AttributeError(name))
+ else:
+ self.report("entering object attribute %s..." % name)
+ self.enter(value)
+
+ def cmd_detail(self):
+ """
+ Show a detail view of the object under the cursor. This shows the
+ name, type, doc string and value of the object attributes (and it
+ might show more attributes than in the list view, depending on
+ the object).
+ """
+ level = self.levels[-1]
+ try:
+ item = level.items[level.cury].item
+ except IndexError:
+ self.report(CommandError("No object"))
+ curses.beep()
+ else:
+ self.report("entering detail view for object...")
+ attrs = [ipipe.AttributeDetail(item, attr) for attr in ipipe.xattrs(item, "detail")]
+ self.enter(attrs)
+
+ def cmd_detailattr(self):
+ """
+ Show a detail view of the attribute under the cursor.
+ """
+ level = self.levels[-1]
+ attr = level.displayattr[1]
+ if attr is ipipe.noitem:
+ curses.beep()
+ self.report(CommandError("no attribute"))
+ return
+ try:
+ item = level.items[level.cury].item
+ except IndexError:
+ self.report(CommandError("No object"))
+ curses.beep()
+ else:
+ try:
+ item = attr.value(item)
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except Exception, exc:
+ self.report(exc)
+ else:
+ self.report("entering detail view for attribute %s..." % attr.name())
+ attrs = [ipipe.AttributeDetail(item, attr) for attr in ipipe.xattrs(item, "detail")]
+ self.enter(attrs)
+
+ def cmd_tooglemark(self):
+ """
+ Mark/unmark the object under the cursor. Marked objects have a '!'
+ after the row number).
+ """
+ level = self.levels[-1]
+ self.report("toggle mark")
+ try:
+ item = level.items[level.cury]
+ except IndexError: # no items?
+ pass
+ else:
+ if item.marked:
+ item.marked = False
+ level.marked -= 1
+ else:
+ item.marked = True
+ level.marked += 1
+
+ def cmd_sortattrasc(self):
+ """
+ Sort the objects (in ascending order) using the attribute under
+ the cursor as the sort key.
+ """
+ level = self.levels[-1]
+ attr = level.displayattr[1]
+ if attr is ipipe.noitem:
+ curses.beep()
+ self.report(CommandError("no column under cursor"))
+ return
+ self.report("sort by %s (ascending)" % attr.name())
+ def key(item):
+ try:
+ return attr.value(item)
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except Exception:
+ return None
+ level.sort(key)
+
+ def cmd_sortattrdesc(self):
+ """
+ Sort the objects (in descending order) using the attribute under
+ the cursor as the sort key.
+ """
+ level = self.levels[-1]
+ attr = level.displayattr[1]
+ if attr is ipipe.noitem:
+ curses.beep()
+ self.report(CommandError("no column under cursor"))
+ return
+ self.report("sort by %s (descending)" % attr.name())
+ def key(item):
+ try:
+ return attr.value(item)
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except Exception:
+ return None
+ level.sort(key, reverse=True)
+
+ def cmd_hideattr(self):
+ """
+ Hide the attribute under the cursor.
+ """
+ level = self.levels[-1]
+ if level.displayattr[0] is None:
+ self.beep()
+ else:
+ self.report("hideattr")
+ level.hiddenattrs.add(level.displayattr[1])
+ level.moveto(level.curx, level.cury, refresh=True)
+
+ def cmd_unhideattrs(self):
+ """
+ Make all attributes visible again.
+ """
+ level = self.levels[-1]
+ self.report("unhideattrs")
+ level.hiddenattrs.clear()
+ level.moveto(level.curx, level.cury, refresh=True)
+
+ def cmd_goto(self):
+ """
+ Jump to a row. The row number can be entered at the
+ bottom of the screen.
+ """
+ self.startkeyboardinput("goto")
+
+ def cmd_find(self):
+ """
+ Search forward for a row. The search condition can be entered at the
+ bottom of the screen.
+ """
+ self.startkeyboardinput("find")
+
+ def cmd_findbackwards(self):
+ """
+ Search backward for a row. The search condition can be entered at the
+ bottom of the screen.
+ """
+ self.startkeyboardinput("findbackwards")
+
+ def cmd_refresh(self):
+ """
+ Refreshes the display by restarting the iterator.
+ """
+ level = self.levels[-1]
+ self.report("refresh")
+ level.refresh()
+
+ def cmd_refreshfind(self):
+ """
+ Refreshes the display by restarting the iterator and goes back to the
+ same object the cursor was on before restarting (if this object can't be
+ found the cursor jumps back to the first object).
+ """
+ level = self.levels[-1]
+ self.report("refreshfind")
+ level.refreshfind()
+
+ def cmd_help(self):
+ """
+ Opens the help screen as a new browser level, describing keyboard
+ shortcuts.
+ """
+ for level in self.levels:
+ if isinstance(level.input, _BrowserHelp):
+ curses.beep()
+ self.report(CommandError("help already active"))
+ return
+
+ self.enter(_BrowserHelp(self))
+
+ def cmd_quit(self):
+ """
+ Quit the browser and return to the IPython prompt.
+ """
+ self.returnvalue = None
+ return True
+
+ def sigwinchhandler(self, signal, frame):
+ self.resized = True
+
+ def _dodisplay(self, scr):
+ """
+ This method is the workhorse of the browser. It handles screen
+ drawing and the keyboard.
+ """
+ self.scr = scr
+ curses.halfdelay(1)
+ footery = 2
+
+ keys = []
+ for cmd in ("quit", "help"):
+ key = self.keymap.findkey(cmd, None)
+ if key is not None:
+ keys.append("%s=%s" % (self.keylabel(key), cmd))
+ helpmsg = " | %s" % " ".join(keys)
+
+ scr.clear()
+ msg = "Fetching first batch of objects..."
+ (self.scrsizey, self.scrsizex) = scr.getmaxyx()
+ scr.addstr(self.scrsizey//2, (self.scrsizex-len(msg))//2, msg)
+ scr.refresh()
+
+ lastc = -1
+
+ self.levels = []
+ # enter the first level
+ self.enter(self.input, *self.attrs)
+
+ self._calcheaderlines(None)
+
+ while True:
+ level = self.levels[-1]
+ (self.scrsizey, self.scrsizex) = scr.getmaxyx()
+ level.mainsizey = self.scrsizey-1-self._headerlines-footery
+
+ # Paint object header
+ for i in xrange(self._firstheaderline, self._firstheaderline+self._headerlines):
+ lv = self.levels[i]
+ posx = 0
+ posy = i-self._firstheaderline
+ endx = self.scrsizex
+ if i: # not the first level
+ msg = " (%d/%d" % (self.levels[i-1].cury, len(self.levels[i-1].items))
+ if not self.levels[i-1].exhausted:
+ msg += "+"
+ msg += ") "
+ endx -= len(msg)+1
+ posx += self.addstr(posy, posx, 0, endx, " ibrowse #%d: " % i, self.style_objheadertext)
+ for (style, text) in lv.header:
+ posx += self.addstr(posy, posx, 0, endx, text, self.style_objheaderobject)
+ if posx >= endx:
+ break
+ if i:
+ posx += self.addstr(posy, posx, 0, self.scrsizex, msg, self.style_objheadernumber)
+ posx += self.addchr(posy, posx, 0, self.scrsizex, " ", self.scrsizex-posx, self.style_objheadernumber)
+
+ if not level.items:
+ self.addchr(self._headerlines, 0, 0, self.scrsizex, " ", self.scrsizex, self.style_colheader)
+ self.addstr(self._headerlines+1, 0, 0, self.scrsizex, " <empty>", astyle.style_error)
+ scr.clrtobot()
+ else:
+ # Paint column headers
+ scr.move(self._headerlines, 0)
+ scr.addstr(" %*s " % (level.numbersizex, "#"), self.getstyle(self.style_colheader))
+ scr.addstr(self.headersepchar, self.getstyle(self.style_colheadersep))
+ begx = level.numbersizex+3
+ posx = begx-level.datastartx
+ for attr in level.displayattrs:
+ attrname = attr.name()
+ cwidth = level.colwidths[attr]
+ header = attrname.ljust(cwidth)
+ if attr is level.displayattr[1]:
+ style = self.style_colheaderhere
+ else:
+ style = self.style_colheader
+ posx += self.addstr(self._headerlines, posx, begx, self.scrsizex, header, style)
+ posx += self.addstr(self._headerlines, posx, begx, self.scrsizex, self.headersepchar, self.style_colheadersep)
+ if posx >= self.scrsizex:
+ break
+ else:
+ scr.addstr(" "*(self.scrsizex-posx), self.getstyle(self.style_colheader))
+
+ # Paint rows
+ posy = self._headerlines+1+level.datastarty
+ for i in xrange(level.datastarty, min(level.datastarty+level.mainsizey, len(level.items))):
+ cache = level.items[i]
+ if i == level.cury:
+ style = self.style_numberhere
+ else:
+ style = self.style_number
+
+ posy = self._headerlines+1+i-level.datastarty
+ posx = begx-level.datastartx
+
+ scr.move(posy, 0)
+ scr.addstr(" %*d%s" % (level.numbersizex, i, " !"[cache.marked]), self.getstyle(style))
+ scr.addstr(self.headersepchar, self.getstyle(self.style_sep))
+
+ for attrname in level.displayattrs:
+ cwidth = level.colwidths[attrname]
+ try:
+ (align, length, parts) = level.displayrows[i-level.datastarty][attrname]
+ except KeyError:
+ align = 2
+ style = astyle.style_nodata
+ if i == level.cury:
+ style = self.getstylehere(style)
+ padstyle = self.style_datapad
+ sepstyle = self.style_sep
+ if i == level.cury:
+ padstyle = self.getstylehere(padstyle)
+ sepstyle = self.getstylehere(sepstyle)
+ if align == 2:
+ posx += self.addchr(posy, posx, begx, self.scrsizex, self.nodatachar, cwidth, style)
+ else:
+ if align == 1:
+ posx += self.addchr(posy, posx, begx, self.scrsizex, self.datapadchar, cwidth-length, padstyle)
+ elif align == 0:
+ pad1 = (cwidth-length)//2
+ pad2 = cwidth-length-len(pad1)
+ posx += self.addchr(posy, posx, begx, self.scrsizex, self.datapadchar, pad1, padstyle)
+ for (style, text) in parts:
+ if i == level.cury:
+ style = self.getstylehere(style)
+ posx += self.addstr(posy, posx, begx, self.scrsizex, text, style)
+ if posx >= self.scrsizex:
+ break
+ if align == -1:
+ posx += self.addchr(posy, posx, begx, self.scrsizex, self.datapadchar, cwidth-length, padstyle)
+ elif align == 0:
+ posx += self.addchr(posy, posx, begx, self.scrsizex, self.datapadchar, pad2, padstyle)
+ posx += self.addstr(posy, posx, begx, self.scrsizex, self.datasepchar, sepstyle)
+ else:
+ scr.clrtoeol()
+
+ # Add blank row headers for the rest of the screen
+ for posy in xrange(posy+1, self.scrsizey-2):
+ scr.addstr(posy, 0, " " * (level.numbersizex+2), self.getstyle(self.style_colheader))
+ scr.clrtoeol()
+
+ posy = self.scrsizey-footery
+ # Display footer
+ scr.addstr(posy, 0, " "*self.scrsizex, self.getstyle(self.style_footer))
+
+ if level.exhausted:
+ flag = ""
+ else:
+ flag = "+"
+
+ endx = self.scrsizex-len(helpmsg)-1
+ scr.addstr(posy, endx, helpmsg, self.getstyle(self.style_footer))
+
+ posx = 0
+ msg = " %d%s objects (%d marked): " % (len(level.items), flag, level.marked)
+ posx += self.addstr(posy, posx, 0, endx, msg, self.style_footer)
+ try:
+ item = level.items[level.cury].item
+ except IndexError: # empty
+ pass
+ else:
+ for (nostyle, text) in ipipe.xrepr(item, "footer"):
+ if not isinstance(nostyle, int):
+ posx += self.addstr(posy, posx, 0, endx, text, self.style_footer)
+ if posx >= endx:
+ break
+
+ attrstyle = [(astyle.style_default, "no attribute")]
+ attr = level.displayattr[1]
+ if attr is not ipipe.noitem and not isinstance(attr, ipipe.SelfDescriptor):
+ posx += self.addstr(posy, posx, 0, endx, " | ", self.style_footer)
+ posx += self.addstr(posy, posx, 0, endx, attr.name(), self.style_footer)
+ posx += self.addstr(posy, posx, 0, endx, ": ", self.style_footer)
+ try:
+ value = attr.value(item)
+ except (SystemExit, KeyboardInterrupt):
+ raise
+ except Exception, exc:
+ value = exc
+ if value is not ipipe.noitem:
+ attrstyle = ipipe.xrepr(value, "footer")
+ for (nostyle, text) in attrstyle:
+ if not isinstance(nostyle, int):
+ posx += self.addstr(posy, posx, 0, endx, text, self.style_footer)
+ if posx >= endx:
+ break
+
+ try:
+ # Display input prompt
+ if self.mode in self.prompts:
+ history = self.prompts[self.mode]
+ posx = 0
+ posy = self.scrsizey-1
+ posx += self.addstr(posy, posx, 0, endx, history.prompt, astyle.style_default)
+ posx += self.addstr(posy, posx, 0, endx, " [", astyle.style_default)
+ if history.cury==-1:
+ text = "new"
+ else:
+ text = str(history.cury+1)
+ posx += self.addstr(posy, posx, 0, endx, text, astyle.style_type_number)
+ if history.history:
+ posx += self.addstr(posy, posx, 0, endx, "/", astyle.style_default)
+ posx += self.addstr(posy, posx, 0, endx, str(len(history.history)), astyle.style_type_number)
+ posx += self.addstr(posy, posx, 0, endx, "]: ", astyle.style_default)
+ inputstartx = posx
+ posx += self.addstr(posy, posx, 0, endx, history.input, astyle.style_default)
+ # Display report
+ else:
+ if self._report is not None:
+ if isinstance(self._report, Exception):
+ style = self.getstyle(astyle.style_error)
+ if self._report.__class__.__module__ == "exceptions":
+ msg = "%s: %s" % \
+ (self._report.__class__.__name__, self._report)
+ else:
+ msg = "%s.%s: %s" % \
+ (self._report.__class__.__module__,
+ self._report.__class__.__name__, self._report)
+ else:
+ style = self.getstyle(self.style_report)
+ msg = self._report
+ scr.addstr(self.scrsizey-1, 0, msg[:self.scrsizex], style)
+ self._report = None
+ else:
+ scr.move(self.scrsizey-1, 0)
+ except curses.error:
+ # Protect against errors from writing to the last line
+ pass
+ scr.clrtoeol()
+
+ # Position cursor
+ if self.mode in self.prompts:
+ history = self.prompts[self.mode]
+ scr.move(self.scrsizey-1, inputstartx+history.curx)
+ else:
+ scr.move(
+ 1+self._headerlines+level.cury-level.datastarty,
+ level.numbersizex+3+level.curx-level.datastartx
+ )
+ scr.refresh()
+
+ # Check keyboard
+ while True:
+ c = scr.getch()
+ if self.resized:
+ size = fcntl.ioctl(0, tty.TIOCGWINSZ, "12345678")
+ size = struct.unpack("4H", size)
+ oldsize = scr.getmaxyx()
+ scr.erase()
+ curses.resize_term(size[0], size[1])
+ newsize = scr.getmaxyx()
+ scr.erase()
+ for l in self.levels:
+ l.mainsizey += newsize[0]-oldsize[0]
+ l.moveto(l.curx, l.cury, refresh=True)
+ scr.refresh()
+ self.resized = False
+ break # Redisplay
+ if self.mode in self.prompts:
+ if self.prompts[self.mode].handlekey(self, c):
+ break # Redisplay
+ else:
+ # if no key is pressed slow down and beep again
+ if c == -1:
+ self.stepx = 1.
+ self.stepy = 1.
+ self._dobeep = True
+ else:
+ # if a different key was pressed slow down and beep too
+ if c != lastc:
+ lastc = c
+ self.stepx = 1.
+ self.stepy = 1.
+ self._dobeep = True
+ cmdname = self.keymap.get(c, None)
+ if cmdname is None:
+ self.report(
+ UnassignedKeyError("Unassigned key %s" %
+ self.keylabel(c)))
+ else:
+ cmdfunc = getattr(self, "cmd_%s" % cmdname, None)
+ if cmdfunc is None:
+ self.report(
+ UnknownCommandError("Unknown command %r" %
+ (cmdname,)))
+ elif cmdfunc():
+ returnvalue = self.returnvalue
+ self.returnvalue = None
+ return returnvalue
+ self.stepx = self.nextstepx(self.stepx)
+ self.stepy = self.nextstepy(self.stepy)
+ curses.flushinp() # get rid of type ahead
+ break # Redisplay
+ self.scr = None
+
+ def display(self):
+ if hasattr(curses, "resize_term"):
+ oldhandler = signal.signal(signal.SIGWINCH, self.sigwinchhandler)
+ try:
+ return curses.wrapper(self._dodisplay)
+ finally:
+ signal.signal(signal.SIGWINCH, oldhandler)
+ else:
+ return curses.wrapper(self._dodisplay)
diff --git a/IPython/Extensions/igrid.py b/IPython/Extensions/igrid.py
new file mode 100644
index 0000000..a2d317f
--- /dev/null
+++ b/IPython/Extensions/igrid.py
@@ -0,0 +1,1126 @@
+# -*- coding: iso-8859-1 -*-
+
+import ipipe, os, webbrowser, urllib
+from IPython import ipapi
+import wx
+import wx.grid, wx.html
+
+try:
+ sorted
+except NameError:
+ from ipipe import sorted
+try:
+ set
+except:
+ from sets import Set as set
+
+
+__all__ = ["igrid"]
+
+
+help = """
+<?xml version='1.0' encoding='iso-8859-1'?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+<link rel="stylesheet" href="igrid_help.css" type="text/css" />
+<title>igrid help</title>
+</head>
+<body>
+<h1>igrid help</h1>
+
+
+<h2>Commands</h2>
+
+
+<h3>pick (P)</h3>
+<p>Pick the whole row (object is available as "_")</p>
+
+<h3>pickattr (Shift-P)</h3>
+<p>Pick the attribute under the cursor</p>
+
+<h3>pickallattrs (Shift-C)</h3>
+<p>Pick the complete column under the cursor (i.e. the attribute under the
+cursor) from all currently fetched objects. These attributes will be returned
+as a list.</p>
+
+<h3>pickinput (I)</h3>
+<p>Pick the current row as next input line in IPython. Additionally the row is stored as "_"</p>
+
+<h3>pickinputattr (Shift-I)</h3>
+<p>Pick the attribute under the cursor as next input line in IPython. Additionally the row is stored as "_"</p>
+
+<h3>enter (E)</h3>
+<p>Enter the object under the cursor. (what this mean depends on the object
+itself, i.e. how it implements iteration). This opens a new browser 'level'.</p>
+
+<h3>enterattr (Shift-E)</h3>
+<p>Enter the attribute under the cursor.</p>
+
+<h3>detail (D)</h3>
+<p>Show a detail view of the object under the cursor. This shows the name,
+type, doc string and value of the object attributes (and it might show more
+attributes than in the list view, depending on the object).</p>
+
+<h3>detailattr (Shift-D)</h3>
+<p>Show a detail view of the attribute under the cursor.</p>
+
+<h3>pickrows (M)</h3>
+<p>Pick multiple selected rows (M)</p>
+
+<h3>pickrowsattr (CTRL-M)</h3>
+<p>From multiple selected rows pick the cells matching the attribute the cursor is in (CTRL-M)</p>
+
+<h3>find (CTRL-F)</h3>
+<p>Find text</p>
+
+<h3>find_expression (CTRL-Shift-F)</h3>
+<p>Find entries matching an expression</p>
+
+<h3>find_next (F3)</h3>
+<p>Find next occurrence</p>
+
+<h3>find_previous (Shift-F3)</h3>
+<p>Find previous occurrence</p>
+
+<h3>sortattrasc (V)</h3>
+<p>Sort the objects (in ascending order) using the attribute under the cursor as the sort key.</p>
+
+<h3>sortattrdesc (Shift-V)</h3>
+<p>Sort the objects (in descending order) using the attribute under the cursor as the sort key.</p>
+
+<h3>refresh_once (R, F5)</h3>
+<p>Refreshes the display by restarting the iterator</p>
+
+<h3>refresh_every_second</h3>
+<p>Refreshes the display by restarting the iterator every second until stopped by stop_refresh.</p>
+
+<h3>refresh_interval</h3>
+<p>Refreshes the display by restarting the iterator every X ms (X is a custom interval set by the user) until stopped by stop_refresh.</p>
+
+<h3>stop_refresh</h3>
+<p>Stops all refresh timers.</p>
+
+<h3>leave (Backspace, DEL, X)</h3>
+<p>Close current tab (and all the tabs to the right of the current one).</h3>
+
+<h3>quit (ESC,Q)</h3>
+<p>Quit igrid and return to the IPython prompt.</p>
+
+
+<h2>Navigation</h2>
+
+
+<h3>Jump to the last column of the current row (END, CTRL-E, CTRL-Right)</h3>
+
+<h3>Jump to the first column of the current row (HOME, CTRL-A, CTRL-Left)</h3>
+
+<h3>Move the cursor one column to the left (&lt;)</h3>
+
+<h3>Move the cursor one column to the right (&gt;)</h3>
+
+<h3>Jump to the first row in the current column (CTRL-Up)</h3>
+
+<h3>Jump to the last row in the current column (CTRL-Down)</h3>
+
+</body>
+</html>
+
+"""
+
+
+class IGridRenderer(wx.grid.PyGridCellRenderer):
+ """
+ This is a custom renderer for our IGridGrid
+ """
+ def __init__(self, table):
+ self.maxchars = 200
+ self.table = table
+ self.colormap = (
+ ( 0, 0, 0),
+ (174, 0, 0),
+ ( 0, 174, 0),
+ (174, 174, 0),
+ ( 0, 0, 174),
+ (174, 0, 174),
+ ( 0, 174, 174),
+ ( 64, 64, 64)
+ )
+
+ wx.grid.PyGridCellRenderer.__init__(self)
+
+ def _getvalue(self, row, col):
+ try:
+ value = self.table._displayattrs[col].value(self.table.items[row])
+ (align, width, text) = ipipe.xformat(value, "cell", self.maxchars)
+ except Exception, exc:
+ (align, width, text) = ipipe.xformat(exc, "cell", self.maxchars)
+ return (align, text)
+
+ def GetBestSize(self, grid, attr, dc, row, col):
+ text = grid.GetCellValue(row, col)
+ (align, text) = self._getvalue(row, col)
+ dc.SetFont(attr.GetFont())
+ (w, h) = dc.GetTextExtent(str(text))
+ return wx.Size(min(w+2, 600), h+2) # add border
+
+ def Draw(self, grid, attr, dc, rect, row, col, isSelected):
+ """
+ Takes care of drawing everything in the cell; aligns the text
+ """
+ text = grid.GetCellValue(row, col)
+ (align, text) = self._getvalue(row, col)
+ if isSelected:
+ bg = grid.GetSelectionBackground()
+ else:
+ bg = ["white", (240, 240, 240)][row%2]
+ dc.SetTextBackground(bg)
+ dc.SetBrush(wx.Brush(bg, wx.SOLID))
+ dc.SetPen(wx.TRANSPARENT_PEN)
+ dc.SetFont(attr.GetFont())
+ dc.DrawRectangleRect(rect)
+ dc.SetClippingRect(rect)
+ # Format the text
+ if align == -1: # left alignment
+ (width, height) = dc.GetTextExtent(str(text))
+ x = rect[0]+1
+ y = rect[1]+0.5*(rect[3]-height)
+
+ for (style, part) in text:
+ if isSelected:
+ fg = grid.GetSelectionForeground()
+ else:
+ fg = self.colormap[style.fg]
+ dc.SetTextForeground(fg)
+ (w, h) = dc.GetTextExtent(part)
+ dc.DrawText(part, x, y)
+ x += w
+ elif align == 0: # center alignment
+ (width, height) = dc.GetTextExtent(str(text))
+ x = rect[0]+0.5*(rect[2]-width)
+ y = rect[1]+0.5*(rect[3]-height)
+ for (style, part) in text:
+ if isSelected:
+ fg = grid.GetSelectionForeground()
+ else:
+ fg = self.colormap[style.fg]
+ dc.SetTextForeground(fg)
+ (w, h) = dc.GetTextExtent(part)
+ dc.DrawText(part, x, y)
+ x += w
+ else: # right alignment
+ (width, height) = dc.GetTextExtent(str(text))
+ x = rect[0]+rect[2]-1
+ y = rect[1]+0.5*(rect[3]-height)
+ for (style, part) in reversed(text):
+ (w, h) = dc.GetTextExtent(part)
+ x -= w
+ if isSelected:
+ fg = grid.GetSelectionForeground()
+ else:
+ fg = self.colormap[style.fg]
+ dc.SetTextForeground(fg)
+ dc.DrawText(part, x, y)
+ dc.DestroyClippingRegion()
+
+ def Clone(self):
+ return IGridRenderer(self.table)
+
+
+class IGridTable(wx.grid.PyGridTableBase):
+ # The data table for the ``IGridGrid``. Some dirty tricks were used here:
+ # ``GetValue()`` does not get any values (or at least it does not return
+ # anything, accessing the values is done by the renderer)
+ # but rather tries to fetch the objects which were requested into the table.
+ # General behaviour is: Fetch the first X objects. If the user scrolls down
+ # to the last object another bunch of X objects is fetched (if possible)
+ def __init__(self, input, fontsize, *attrs):
+ wx.grid.PyGridTableBase.__init__(self)
+ self.input = input
+ self.iterator = ipipe.xiter(input)
+ self.items = []
+ self.attrs = [ipipe.upgradexattr(attr) for attr in attrs]
+ self._displayattrs = self.attrs[:]
+ self._displayattrset = set(self.attrs)
+ self.fontsize = fontsize
+ self._fetch(1)
+ self.timer = wx.Timer()
+ self.timer.Bind(wx.EVT_TIMER, self.refresh_content)
+
+ def GetAttr(self, *args):
+ attr = wx.grid.GridCellAttr()
+ attr.SetFont(wx.Font(self.fontsize, wx.TELETYPE, wx.NORMAL, wx.NORMAL))
+ return attr
+
+ def GetNumberRows(self):
+ return len(self.items)
+
+ def GetNumberCols(self):
+ return len(self._displayattrs)
+
+ def GetColLabelValue(self, col):
+ if col < len(self._displayattrs):
+ return self._displayattrs[col].name()
+ else:
+ return ""
+
+ def GetRowLabelValue(self, row):
+ return str(row)
+
+ def IsEmptyCell(self, row, col):
+ return False
+
+ def _append(self, item):
+ self.items.append(item)
+ # Nothing to do if the set of attributes has been fixed by the user
+ if not self.attrs:
+ for attr in ipipe.xattrs(item):
+ attr = ipipe.upgradexattr(attr)
+ if attr not in self._displayattrset:
+ self._displayattrs.append(attr)
+ self._displayattrset.add(attr)
+
+ def _fetch(self, count):
+ # Try to fill ``self.items`` with at least ``count`` objects.
+ have = len(self.items)
+ while self.iterator is not None and have < count:
+ try:
+ item = self.iterator.next()
+ except StopIteration:
+ self.iterator = None
+ break
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except Exception, exc:
+ have += 1
+ self._append(exc)
+ self.iterator = None
+ break
+ else:
+ have += 1
+ self._append(item)
+
+ def GetValue(self, row, col):
+ # some kind of dummy-function: does not return anything but "";
+ # (The value isn't use anyway)
+ # its main task is to trigger the fetch of new objects
+ sizing_needed = False
+ had_cols = len(self._displayattrs)
+ had_rows = len(self.items)
+ if row == had_rows - 1 and self.iterator is not None:
+ self._fetch(row + 20)
+ sizing_needed = True
+ have_rows = len(self.items)
+ have_cols = len(self._displayattrs)
+ if have_rows > had_rows:
+ msg = wx.grid.GridTableMessage(self, wx.grid.GRIDTABLE_NOTIFY_ROWS_APPENDED, have_rows - had_rows)
+ self.GetView().ProcessTableMessage(msg)
+ sizing_needed = True
+ if row >= have_rows:
+ return ""
+ if have_cols != had_cols:
+ msg = wx.grid.GridTableMessage(self, wx.grid.GRIDTABLE_NOTIFY_COLS_APPENDED, have_cols - had_cols)
+ self.GetView().ProcessTableMessage(msg)
+ sizing_needed = True
+ if sizing_needed:
+ self.GetView().AutoSizeColumns(False)
+ return ""
+
+ def SetValue(self, row, col, value):
+ pass
+
+ def refresh_content(self, event):
+ msg = wx.grid.GridTableMessage(self, wx.grid.GRIDTABLE_NOTIFY_ROWS_DELETED, 0, self.GetNumberRows())
+ self.GetView().ProcessTableMessage(msg)
+ self.iterator = ipipe.xiter(self.input)
+ self.items = []
+ self.attrs = [] # _append will calculate new displayattrs
+ self._fetch(1) # fetch one...
+ if self.items:
+ msg = wx.grid.GridTableMessage(self, wx.grid.GRIDTABLE_NOTIFY_ROWS_APPENDED, 1)
+ self.GetView().ProcessTableMessage(msg)
+ self.GetValue(0, 0) # and trigger "fetch next 20"
+ item = self.items[0]
+ self.GetView().AutoSizeColumns(False)
+ panel = self.GetView().GetParent()
+ nb = panel.GetParent()
+ current = nb.GetSelection()
+ if nb.GetPage(current) == panel:
+ self.GetView().set_footer(item)
+
+class IGridGrid(wx.grid.Grid):
+ # The actual grid
+ # all methods for selecting/sorting/picking/... data are implemented here
+ def __init__(self, panel, input, *attrs):
+ wx.grid.Grid.__init__(self, panel)
+ fontsize = 9
+ self.input = input
+ self.table = IGridTable(self.input, fontsize, *attrs)
+ self.SetTable(self.table, True)
+ self.SetSelectionMode(wx.grid.Grid.wxGridSelectRows)
+ self.SetDefaultRenderer(IGridRenderer(self.table))
+ self.EnableEditing(False)
+ self.Bind(wx.EVT_KEY_DOWN, self.key_pressed)
+ self.Bind(wx.grid.EVT_GRID_CELL_LEFT_DCLICK, self.cell_doubleclicked)
+ self.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.cell_leftclicked)
+ self.Bind(wx.grid.EVT_GRID_LABEL_LEFT_DCLICK, self.label_doubleclicked)
+ self.Bind(wx.grid.EVT_GRID_LABEL_LEFT_CLICK, self.on_label_leftclick)
+ self.Bind(wx.grid.EVT_GRID_RANGE_SELECT, self._on_selected_range)
+ self.Bind(wx.grid.EVT_GRID_SELECT_CELL, self._on_selected_cell)
+ self.current_selection = set()
+ self.maxchars = 200
+
+ def on_label_leftclick(self, event):
+ event.Skip()
+
+ def error_output(self, text):
+ wx.Bell()
+ frame = self.GetParent().GetParent().GetParent()
+ frame.SetStatusText(str(text))
+
+ def _on_selected_range(self, event):
+ # Internal update to the selection tracking lists
+ if event.Selecting():
+ # adding to the list...
+ self.current_selection.update(xrange(event.GetTopRow(), event.GetBottomRow()+1))
+ else:
+ # removal from list
+ for index in xrange(event.GetTopRow(), event.GetBottomRow()+1):
+ self.current_selection.discard(index)
+ event.Skip()
+
+ def _on_selected_cell(self, event):
+ # Internal update to the selection tracking list
+ self.current_selection = set([event.GetRow()])
+ event.Skip()
+
+ def sort(self, key, reverse=False):
+ """
+ Sort the current list of items using the key function ``key``. If
+ ``reverse`` is true the sort order is reversed.
+ """
+ row = self.GetGridCursorRow()
+ col = self.GetGridCursorCol()
+ curitem = self.table.items[row] # Remember where the cursor is now
+ # Sort items
+ def realkey(item):
+ try:
+ return key(item)
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except Exception:
+ return None
+ try:
+ self.table.items = ipipe.deque(sorted(self.table.items, key=realkey, reverse=reverse))
+ except TypeError, exc:
+ self.error_output("Exception encountered: %s" % exc)
+ return
+ # Find out where the object under the cursor went
+ for (i, item) in enumerate(self.table.items):
+ if item is curitem:
+ self.SetGridCursor(i,col)
+ self.MakeCellVisible(i,col)
+ self.Refresh()
+
+ def sortattrasc(self):
+ """
+ Sort in ascending order; sorting criteria is the current attribute
+ """
+ col = self.GetGridCursorCol()
+ attr = self.table._displayattrs[col]
+ frame = self.GetParent().GetParent().GetParent()
+ if attr is ipipe.noitem:
+ self.error_output("no column under cursor")
+ return
+ frame.SetStatusText("sort by %s (ascending)" % attr.name())
+ def key(item):
+ try:
+ return attr.value(item)
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except Exception:
+ return None
+ self.sort(key)
+
+ def sortattrdesc(self):
+ """
+ Sort in descending order; sorting criteria is the current attribute
+ """
+ col = self.GetGridCursorCol()
+ attr = self.table._displayattrs[col]
+ frame = self.GetParent().GetParent().GetParent()
+ if attr is ipipe.noitem:
+ self.error_output("no column under cursor")
+ return
+ frame.SetStatusText("sort by %s (descending)" % attr.name())
+ def key(item):
+ try:
+ return attr.value(item)
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except Exception:
+ return None
+ self.sort(key, reverse=True)
+
+ def label_doubleclicked(self, event):
+ row = event.GetRow()
+ col = event.GetCol()
+ if col == -1:
+ self.enter(row)
+
+ def _getvalue(self, row, col):
+ """
+ Gets the text which is displayed at ``(row, col)``
+ """
+ try:
+ value = self.table._displayattrs[col].value(self.table.items[row])
+ (align, width, text) = ipipe.xformat(value, "cell", self.maxchars)
+ except IndexError:
+ raise IndexError
+ except Exception, exc:
+ (align, width, text) = ipipe.xformat(exc, "cell", self.maxchars)
+ return text
+
+ def searchexpression(self, searchexp, startrow=None, search_forward=True ):
+ """
+ Find by expression
+ """
+ frame = self.GetParent().GetParent().GetParent()
+ if searchexp:
+ if search_forward:
+ if not startrow:
+ row = self.GetGridCursorRow()+1
+ else:
+ row = startrow + 1
+ while True:
+ try:
+ foo = self.table.GetValue(row, 0)
+ item = self.table.items[row]
+ try:
+ globals = ipipe.getglobals(None)
+ if eval(searchexp, globals, ipipe.AttrNamespace(item)):
+ self.SetGridCursor(row, 0) # found something
+ self.MakeCellVisible(row, 0)
+ break
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except Exception, exc:
+ frame.SetStatusText(str(exc))
+ wx.Bell()
+ break # break on error
+ except IndexError:
+ return
+ row += 1
+ else:
+ if not startrow:
+ row = self.GetGridCursorRow() - 1
+ else:
+ row = startrow - 1
+ while True:
+ try:
+ foo = self.table.GetValue(row, 0)
+ item = self.table.items[row]
+ try:
+ globals = ipipe.getglobals(None)
+ if eval(searchexp, globals, ipipe.AttrNamespace(item)):
+ self.SetGridCursor(row, 0) # found something
+ self.MakeCellVisible(row, 0)
+ break
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except Exception, exc:
+ frame.SetStatusText(str(exc))
+ wx.Bell()
+ break # break on error
+ except IndexError:
+ return
+ row -= 1
+
+
+ def search(self, searchtext, startrow=None, startcol=None, search_forward=True):
+ """
+ search for ``searchtext``, starting in ``(startrow, startcol)``;
+ if ``search_forward`` is true the direction is "forward"
+ """
+ searchtext = searchtext.lower()
+ if search_forward:
+ if startrow is not None and startcol is not None:
+ row = startrow
+ else:
+ startcol = self.GetGridCursorCol() + 1
+ row = self.GetGridCursorRow()
+ if startcol >= self.GetNumberCols():
+ startcol = 0
+ row += 1
+ while True:
+ for col in xrange(startcol, self.table.GetNumberCols()):
+ try:
+ foo = self.table.GetValue(row, col)
+ text = self._getvalue(row, col)
+ if searchtext in text.string().lower():
+ self.SetGridCursor(row, col)
+ self.MakeCellVisible(row, col)
+ return
+ except IndexError:
+ return
+ startcol = 0
+ row += 1
+ else:
+ if startrow is not None and startcol is not None:
+ row = startrow
+ else:
+ startcol = self.GetGridCursorCol() - 1
+ row = self.GetGridCursorRow()
+ if startcol < 0:
+ startcol = self.GetNumberCols() - 1
+ row -= 1
+ while True:
+ for col in xrange(startcol, -1, -1):
+ try:
+ foo = self.table.GetValue(row, col)
+ text = self._getvalue(row, col)
+ if searchtext in text.string().lower():
+ self.SetGridCursor(row, col)
+ self.MakeCellVisible(row, col)
+ return
+ except IndexError:
+ return
+ startcol = self.table.GetNumberCols()-1
+ row -= 1
+
+ def key_pressed(self, event):
+ """
+ Maps pressed keys to functions
+ """
+ frame = self.GetParent().GetParent().GetParent()
+ frame.SetStatusText("")
+ sh = event.ShiftDown()
+ ctrl = event.ControlDown()
+
+ keycode = event.GetKeyCode()
+ if keycode == ord("P"):
+ row = self.GetGridCursorRow()
+ if sh:
+ col = self.GetGridCursorCol()
+ self.pickattr(row, col)
+ else:
+ self.pick(row)
+ elif keycode == ord("M"):
+ if ctrl:
+ col = self.GetGridCursorCol()
+ self.pickrowsattr(sorted(self.current_selection), col)
+ else:
+ self.pickrows(sorted(self.current_selection))
+ elif keycode in (wx.WXK_BACK, wx.WXK_DELETE, ord("X")) and not (ctrl or sh):
+ self.delete_current_notebook()
+ elif keycode in (ord("E"), ord("\r")):
+ row = self.GetGridCursorRow()
+ if sh:
+ col = self.GetGridCursorCol()
+ self.enterattr(row, col)
+ else:
+ self.enter(row)
+ elif keycode == ord("E") and ctrl:
+ row = self.GetGridCursorRow()
+ self.SetGridCursor(row, self.GetNumberCols()-1)
+ elif keycode == wx.WXK_HOME or (keycode == ord("A") and ctrl):
+ row = self.GetGridCursorRow()
+ self.SetGridCursor(row, 0)
+ elif keycode == ord("C") and sh:
+ col = self.GetGridCursorCol()
+ attr = self.table._displayattrs[col]
+ result = []
+ for i in xrange(self.GetNumberRows()):
+ result.append(self.table._displayattrs[col].value(self.table.items[i]))
+ self.quit(result)
+ elif keycode in (wx.WXK_ESCAPE, ord("Q")) and not (ctrl or sh):
+ self.quit()
+ elif keycode == ord("<"):
+ row = self.GetGridCursorRow()
+ col = self.GetGridCursorCol()
+ if not event.ShiftDown():
+ newcol = col - 1
+ if newcol >= 0:
+ self.SetGridCursor(row, col - 1)
+ else:
+ newcol = col + 1
+ if newcol < self.GetNumberCols():
+ self.SetGridCursor(row, col + 1)
+ elif keycode == ord("D"):
+ col = self.GetGridCursorCol()
+ row = self.GetGridCursorRow()
+ if not sh:
+ self.detail(row, col)
+ else:
+ self.detail_attr(row, col)
+ elif keycode == ord("F") and ctrl:
+ if sh:
+ frame.enter_searchexpression(event)
+ else:
+ frame.enter_searchtext(event)
+ elif keycode == wx.WXK_F3:
+ if sh:
+ frame.find_previous(event)
+ else:
+ frame.find_next(event)
+ elif keycode == ord("V"):
+ if sh:
+ self.sortattrdesc()
+ else:
+ self.sortattrasc()
+ elif keycode == wx.WXK_DOWN:
+ row = self.GetGridCursorRow()
+ try:
+ item = self.table.items[row+1]
+ except IndexError:
+ item = self.table.items[row]
+ self.set_footer(item)
+ event.Skip()
+ elif keycode == wx.WXK_UP:
+ row = self.GetGridCursorRow()
+ if row >= 1:
+ item = self.table.items[row-1]
+ else:
+ item = self.table.items[row]
+ self.set_footer(item)
+ event.Skip()
+ elif keycode == wx.WXK_RIGHT:
+ row = self.GetGridCursorRow()
+ item = self.table.items[row]
+ self.set_footer(item)
+ event.Skip()
+ elif keycode == wx.WXK_LEFT:
+ row = self.GetGridCursorRow()
+ item = self.table.items[row]
+ self.set_footer(item)
+ event.Skip()
+ elif keycode == ord("R") or keycode == wx.WXK_F5:
+ self.table.refresh_content(event)
+ elif keycode == ord("I"):
+ row = self.GetGridCursorRow()
+ if not sh:
+ self.pickinput(row)
+ else:
+ col = self.GetGridCursorCol()
+ self.pickinputattr(row, col)
+ else:
+ event.Skip()
+
+ def delete_current_notebook(self):
+ """
+ deletes the current notebook tab
+ """
+ panel = self.GetParent()
+ nb = panel.GetParent()
+ current = nb.GetSelection()
+ count = nb.GetPageCount()
+ if count > 1:
+ for i in xrange(count-1, current-1, -1):
+ nb.DeletePage(i)
+ nb.GetCurrentPage().grid.SetFocus()
+ else:
+ frame = nb.GetParent()
+ frame.SetStatusText("This is the last level!")
+
+ def _doenter(self, value, *attrs):
+ """
+ "enter" a special item resulting in a new notebook tab
+ """
+ panel = self.GetParent()
+ nb = panel.GetParent()
+ frame = nb.GetParent()
+ current = nb.GetSelection()
+ count = nb.GetPageCount()
+ try: # if we want to enter something non-iterable, e.g. a function
+ if current + 1 == count and value is not self.input: # we have an event in the last tab
+ frame._add_notebook(value, *attrs)
+ elif value != self.input: # we have to delete all tabs newer than [panel] first
+ for i in xrange(count-1, current, -1): # some tabs don't close if we don't close in *reverse* order
+ nb.DeletePage(i)
+ frame._add_notebook(value)
+ except TypeError, exc:
+ if exc.__class__.__module__ == "exceptions":
+ msg = "%s: %s" % (exc.__class__.__name__, exc)
+ else:
+ msg = "%s.%s: %s" % (exc.__class__.__module__, exc.__class__.__name__, exc)
+ frame.SetStatusText(msg)
+
+ def enterattr(self, row, col):
+ try:
+ attr = self.table._displayattrs[col]
+ value = attr.value(self.table.items[row])
+ except Exception, exc:
+ self.error_output(str(exc))
+ else:
+ self._doenter(value)
+
+ def set_footer(self, item):
+ frame = self.GetParent().GetParent().GetParent()
+ frame.SetStatusText(" ".join([str(text) for (style, text) in ipipe.xformat(item, "footer", 20)[2]]), 0)
+
+ def enter(self, row):
+ try:
+ value = self.table.items[row]
+ except Exception, exc:
+ self.error_output(str(exc))
+ else:
+ self._doenter(value)
+
+ def detail(self, row, col):
+ """
+ shows a detail-view of the current cell
+ """
+ try:
+ attr = self.table._displayattrs[col]
+ item = self.table.items[row]
+ except Exception, exc:
+ self.error_output(str(exc))
+ else:
+ attrs = [ipipe.AttributeDetail(item, attr) for attr in ipipe.xattrs(item, "detail")]
+ self._doenter(attrs)
+
+ def detail_attr(self, row, col):
+ try:
+ attr = self.table._displayattrs[col]
+ item = attr.value(self.table.items[row])
+ except Exception, exc:
+ self.error_output(str(exc))
+ else:
+ attrs = [ipipe.AttributeDetail(item, attr) for attr in ipipe.xattrs(item, "detail")]
+ self._doenter(attrs)
+
+ def quit(self, result=None):
+ """
+ quit
+ """
+ frame = self.GetParent().GetParent().GetParent()
+ if frame.helpdialog:
+ frame.helpdialog.Destroy()
+ app = frame.parent
+ if app is not None:
+ app.result = result
+ frame.Close()
+ frame.Destroy()
+
+ def cell_doubleclicked(self, event):
+ self.enterattr(event.GetRow(), event.GetCol())
+ event.Skip()
+
+ def cell_leftclicked(self, event):
+ row = event.GetRow()
+ item = self.table.items[row]
+ self.set_footer(item)
+ event.Skip()
+
+ def pick(self, row):
+ """
+ pick a single row and return to the IPython prompt
+ """
+ try:
+ value = self.table.items[row]
+ except Exception, exc:
+ self.error_output(str(exc))
+ else:
+ self.quit(value)
+
+ def pickinput(self, row):
+ try:
+ value = self.table.items[row]
+ except Exception, exc:
+ self.error_output(str(exc))
+ else:
+ api = ipapi.get()
+ api.set_next_input(str(value))
+ self.quit(value)
+
+ def pickinputattr(self, row, col):
+ try:
+ attr = self.table._displayattrs[col]
+ value = attr.value(self.table.items[row])
+ except Exception, exc:
+ self.error_output(str(exc))
+ else:
+ api = ipapi.get()
+ api.set_next_input(str(value))
+ self.quit(value)
+
+ def pickrows(self, rows):
+ """
+ pick multiple rows and return to the IPython prompt
+ """
+ try:
+ value = [self.table.items[row] for row in rows]
+ except Exception, exc:
+ self.error_output(str(exc))
+ else:
+ self.quit(value)
+
+ def pickrowsattr(self, rows, col):
+ """"
+ pick one column from multiple rows
+ """
+ values = []
+ try:
+ attr = self.table._displayattrs[col]
+ for row in rows:
+ try:
+ values.append(attr.value(self.table.items[row]))
+ except (SystemExit, KeyboardInterrupt):
+ raise
+ except Exception:
+ raise #pass
+ except Exception, exc:
+ self.error_output(str(exc))
+ else:
+ self.quit(values)
+
+ def pickattr(self, row, col):
+ try:
+ attr = self.table._displayattrs[col]
+ value = attr.value(self.table.items[row])
+ except Exception, exc:
+ self.error_output(str(exc))
+ else:
+ self.quit(value)
+
+
+class IGridPanel(wx.Panel):
+ # Each IGridPanel contains an IGridGrid
+ def __init__(self, parent, input, *attrs):
+ wx.Panel.__init__(self, parent, -1)
+ self.grid = IGridGrid(self, input, *attrs)
+ self.grid.FitInside()
+ sizer = wx.BoxSizer(wx.VERTICAL)
+ sizer.Add(self.grid, proportion=1, flag=wx.EXPAND | wx.ALL, border=10)
+ self.SetSizer(sizer)
+ sizer.Fit(self)
+ sizer.SetSizeHints(self)
+
+
+class IGridHTMLHelp(wx.Frame):
+ def __init__(self, parent, title, size):
+ wx.Frame.__init__(self, parent, -1, title, size=size)
+ html = wx.html.HtmlWindow(self)
+ if "gtk2" in wx.PlatformInfo:
+ html.SetStandardFonts()
+ html.SetPage(help)
+
+
+class IGridFrame(wx.Frame):
+ maxtitlelen = 30
+
+ def __init__(self, parent, input):
+ title = " ".join([str(text) for (style, text) in ipipe.xformat(input, "header", 20)[2]])
+ wx.Frame.__init__(self, None, title=title, size=(640, 480))
+ self.menubar = wx.MenuBar()
+ self.menucounter = 100
+ self.m_help = wx.Menu()
+ self.m_search = wx.Menu()
+ self.m_sort = wx.Menu()
+ self.m_refresh = wx.Menu()
+ self.notebook = wx.Notebook(self, -1, style=0)
+ self.statusbar = self.CreateStatusBar(1, wx.ST_SIZEGRIP)
+ self.statusbar.SetFieldsCount(2)
+ self.SetStatusWidths([-1, 200])
+ self.parent = parent
+ self._add_notebook(input)
+ self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
+ self.makemenu(self.m_sort, "&Sort (asc)\tV", "Sort ascending", self.sortasc)
+ self.makemenu(self.m_sort, "Sort (&desc)\tShift-V", "Sort descending", self.sortdesc)
+ self.makemenu(self.m_help, "&Help\tF1", "Help", self.display_help)
+# self.makemenu(self.m_help, "&Show help in browser", "Show help in browser", self.display_help_in_browser)
+ self.makemenu(self.m_search, "&Find text\tCTRL-F", "Find text", self.enter_searchtext)
+ self.makemenu(self.m_search, "Find by &expression\tCTRL-Shift-F", "Find by expression", self.enter_searchexpression)
+ self.makemenu(self.m_search, "Find &next\tF3", "Find next", self.find_next)
+ self.makemenu(self.m_search, "Find &previous\tShift-F3", "Find previous", self.find_previous)
+ self.makemenu(self.m_refresh, "&Refresh once \tF5", "Refresh once", self.refresh_once)
+ self.makemenu(self.m_refresh, "Refresh every &1s", "Refresh every second", self.refresh_every_second)
+ self.makemenu(self.m_refresh, "Refresh every &X seconds", "Refresh every X seconds", self.refresh_interval)
+ self.makemenu(self.m_refresh, "&Stop all refresh timers", "Stop refresh timers", self.stop_refresh)
+ self.menubar.Append(self.m_search, "&Find")
+ self.menubar.Append(self.m_sort, "&Sort")
+ self.menubar.Append(self.m_refresh, "&Refresh")
+ self.menubar.Append(self.m_help, "&Help")
+ self.SetMenuBar(self.menubar)
+ self.searchtext = ""
+ self.searchexpression = ""
+ self.helpdialog = None
+ self.refresh_interval = 1000
+ self.SetStatusText("Refreshing inactive", 1)
+
+ def refresh_once(self, event):
+ table = self.notebook.GetPage(self.notebook.GetSelection()).grid.table
+ table.refresh_content(event)
+
+ def refresh_interval(self, event):
+ table = self.notebook.GetPage(self.notebook.GetSelection()).grid.table
+ dlg = wx.TextEntryDialog(self, "Enter refresh interval (milliseconds):", "Refresh timer:", defaultValue=str(self.refresh_interval))
+ if dlg.ShowModal() == wx.ID_OK:
+ try:
+ milliseconds = int(dlg.GetValue())
+ except ValueError, exc:
+ self.SetStatusText(str(exc))
+ else:
+ table.timer.Start(milliseconds=milliseconds, oneShot=False)
+ self.SetStatusText("Refresh timer set to %s ms" % milliseconds)
+ self.SetStatusText("Refresh interval: %s ms" % milliseconds, 1)
+ self.refresh_interval = milliseconds
+ dlg.Destroy()
+
+ def stop_refresh(self, event):
+ for i in xrange(self.notebook.GetPageCount()):
+ nb = self.notebook.GetPage(i)
+ nb.grid.table.timer.Stop()
+ self.SetStatusText("Refreshing inactive", 1)
+
+ def refresh_every_second(self, event):
+ table = self.notebook.GetPage(self.notebook.GetSelection()).grid.table
+ table.timer.Start(milliseconds=1000, oneShot=False)
+ self.SetStatusText("Refresh interval: 1000 ms", 1)
+
+ def sortasc(self, event):
+ grid = self.notebook.GetPage(self.notebook.GetSelection()).grid
+ grid.sortattrasc()
+
+ def sortdesc(self, event):
+ grid = self.notebook.GetPage(self.notebook.GetSelection()).grid
+ grid.sortattrdesc()
+
+ def find_previous(self, event):
+ """
+ find previous occurrences
+ """
+ grid = self.notebook.GetPage(self.notebook.GetSelection()).grid
+ if self.searchtext:
+ row = grid.GetGridCursorRow()
+ col = grid.GetGridCursorCol()
+ self.SetStatusText('Search mode: text; looking for %s' % self.searchtext)
+ if col-1 >= 0:
+ grid.search(self.searchtext, row, col-1, False)
+ else:
+ grid.search(self.searchtext, row-1, grid.table.GetNumberCols()-1, False)
+ elif self.searchexpression:
+ self.SetStatusText("Search mode: expression; looking for %s" % repr(self.searchexpression)[2:-1])
+ grid.searchexpression(searchexp=self.searchexpression, search_forward=False)
+ else:
+ self.SetStatusText("No search yet: please enter search-text or -expression")
+
+ def find_next(self, event):
+ """
+ find the next occurrence
+ """
+ grid = self.notebook.GetPage(self.notebook.GetSelection()).grid
+ if self.searchtext != "":
+ row = grid.GetGridCursorRow()
+ col = grid.GetGridCursorCol()
+ self.SetStatusText('Search mode: text; looking for %s' % self.searchtext)
+ if col+1 < grid.table.GetNumberCols():
+ grid.search(self.searchtext, row, col+1)
+ else:
+ grid.search(self.searchtext, row+1, 0)
+ elif self.searchexpression != "":
+ self.SetStatusText('Search mode: expression; looking for %s' % repr(self.searchexpression)[2:-1])
+ grid.searchexpression(searchexp=self.searchexpression)
+ else:
+ self.SetStatusText("No search yet: please enter search-text or -expression")
+
+ def display_help(self, event):
+ """
+ Display a help dialog
+ """
+ if self.helpdialog:
+ self.helpdialog.Destroy()
+ self.helpdialog = IGridHTMLHelp(None, title="Help", size=wx.Size(600,400))
+ self.helpdialog.Show()
+
+ def display_help_in_browser(self, event):
+ """
+ Show the help-HTML in a browser (as a ``HtmlWindow`` does not understand
+ CSS this looks better)
+ """
+ filename = urllib.pathname2url(os.path.abspath(os.path.join(os.path.dirname(__file__), "igrid_help.html")))
+ if not filename.startswith("file"):
+ filename = "file:" + filename
+ webbrowser.open(filename, new=1, autoraise=True)
+
+ def enter_searchexpression(self, event):
+ dlg = wx.TextEntryDialog(self, "Find:", "Find matching expression:", defaultValue=self.searchexpression)
+ if dlg.ShowModal() == wx.ID_OK:
+ self.searchexpression = dlg.GetValue()
+ self.searchtext = ""
+ self.SetStatusText('Search mode: expression; looking for %s' % repr(self.searchexpression)[2:-1])
+ self.notebook.GetPage(self.notebook.GetSelection()).grid.searchexpression(self.searchexpression)
+ dlg.Destroy()
+
+ def makemenu(self, menu, label, help, cmd):
+ menu.Append(self.menucounter, label, help)
+ self.Bind(wx.EVT_MENU, cmd, id=self.menucounter)
+ self.menucounter += 1
+
+ def _add_notebook(self, input, *attrs):
+ # Adds another notebook which has the starting object ``input``
+ panel = IGridPanel(self.notebook, input, *attrs)
+ text = str(ipipe.xformat(input, "header", self.maxtitlelen)[2])
+ if len(text) >= self.maxtitlelen:
+ text = text[:self.maxtitlelen].rstrip(".") + "..."
+ self.notebook.AddPage(panel, text, True)
+ panel.grid.SetFocus()
+ self.Layout()
+
+ def OnCloseWindow(self, event):
+ self.Destroy()
+
+ def enter_searchtext(self, event):
+ # Displays a dialog asking for the searchtext
+ dlg = wx.TextEntryDialog(self, "Find:", "Find in list", defaultValue=self.searchtext)
+ if dlg.ShowModal() == wx.ID_OK:
+ self.searchtext = dlg.GetValue()
+ self.searchexpression = ""
+ self.SetStatusText('Search mode: text; looking for %s' % self.searchtext)
+ self.notebook.GetPage(self.notebook.GetSelection()).grid.search(self.searchtext)
+ dlg.Destroy()
+
+
+class App(wx.App):
+ def __init__(self, input):
+ self.input = input
+ self.result = None # Result to be returned to IPython. Set by quit().
+ wx.App.__init__(self)
+
+ def OnInit(self):
+ frame = IGridFrame(self, self.input)
+ frame.Show()
+ self.SetTopWindow(frame)
+ frame.Raise()
+ return True
+
+
+class igrid(ipipe.Display):
+ """
+ This is a wx-based display object that can be used instead of ``ibrowse``
+ (which is curses-based) or ``idump`` (which simply does a print).
+ """
+
+ if wx.VERSION < (2, 7):
+ def display(self):
+ try:
+ # Try to create a "standalone" frame. If this works we're probably
+ # running with -wthread.
+ # Note that this sets the parent of the frame to None, but we can't
+ # pass a result object back to the shell anyway.
+ frame = IGridFrame(None, self.input)
+ frame.Show()
+ frame.Raise()
+ except wx.PyNoAppError:
+ # There's no wx application yet => create one.
+ app = App(self.input)
+ app.MainLoop()
+ return app.result
+ else:
+ # With wx 2.7 it gets simpler.
+ def display(self):
+ app = App(self.input)
+ app.MainLoop()
+ return app.result
+
diff --git a/IPython/Extensions/igrid_help.css b/IPython/Extensions/igrid_help.css
new file mode 100644
index 0000000..c875f4d
--- /dev/null
+++ b/IPython/Extensions/igrid_help.css
@@ -0,0 +1,45 @@
+body
+{
+ background-color: #fff;
+ color: #000;
+ font-family: "Verdana", "Arial", "XHelvetica", "Helvetica", sans-serif;
+ padding: 20px 30px;
+ margin: 0px;
+ font-size: 11px;
+}
+h1
+{
+ font-family: "Trebuchet MS", sans-serif;
+ font-size: 24px;
+ margin: -20px -30px 4px -30px;
+ padding: 6px 30px;
+ font-weight: normal;
+ border-bottom: 1px solid #000;
+ letter-spacing: 1px;
+ background-color: #666;
+ color: #fff;
+}
+h2
+{
+ font-family: "Trebuchet MS", sans-serif;
+ font-size: 20px;
+ padding: 14px 0px 2px 0px;
+ margin: 0px;
+ font-weight: bold;
+ color: #333;
+}
+h3
+{
+ font-family: "Trebuchet MS", sans-serif;
+ font-size: 14px;
+ padding: 12px 0px 2px 0px;
+ margin: 0px;
+ font-weight: bold;
+ color: #333;
+}
+p
+{
+ line-height: 120%;
+ margin: 0px 0px 6px 0px;
+ padding: 0px;
+}
diff --git a/IPython/Extensions/igrid_help.html b/IPython/Extensions/igrid_help.html
new file mode 100644
index 0000000..3c7122e
--- /dev/null
+++ b/IPython/Extensions/igrid_help.html
@@ -0,0 +1,86 @@
+<?xml version='1.0' encoding='iso-8859-1'?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+<link rel="stylesheet" href="igrid_help.css" type="text/css" />
+<title>igrid help</title>
+</head>
+<body>
+<h1>igrid help</h1>
+
+
+<h2>Commands</h2>
+
+
+<h3>pick (P)</h3>
+<p>Pick the whole row (object is available as "_")</p>
+
+<h3>pickattr (Shift-P)</h3>
+<p>Pick the attribute under the cursor</p>
+
+<h3>pickallattrs (Shift-C)</h3>
+<p>Pick' the complete column under the cursor (i.e. the attribute under the
+cursor) from all currently fetched objects. These attributes will be returned
+as a list.</p>
+
+<h3>enter (E)</h3>
+<p>Enter the object under the cursor. (what this mean depends on the object
+itself, i.e. how it implements iteration). This opens a new browser 'level'.</p>
+
+<h3>enterattr (Shift-E)</h3>
+<p>Enter the attribute under the cursor.</p>
+
+<h3>detail (D)</h3>
+<p>Show a detail view of the object under the cursor. This shows the name,
+type, doc string and value of the object attributes (and it might show more
+attributes than in the list view, depending on the object).</p>
+
+<h3>detailattr (Shift-D)</h3>
+<p>Show a detail view of the attribute under the cursor.</p>
+
+<h3>pickrows (M)</h3>
+<p>Pick multiple selected rows (M)</p>
+
+<h3>pickrowsattr (CTRL-M)</h3>
+<p>From multiple selected rows pick the cells matching the attribute the cursor is in (CTRL-M)</p>
+
+<h3>find (CTRL-F)</h3>
+<p>Find text</p>
+
+<h3>find_next (F3)</h3>
+<p>Find next occurrence of the searchtext</p>
+
+<h3>find_previous (Shift-F3)</h3>
+<p>Find previous occurrence of the searchtext </p>
+
+<h3>sortattrasc (V)</h3>
+<p>Sort the objects (in ascending order) using the attribute under the cursor as the sort key.</p>
+
+<h3>sortattrdesc (Shift-V)</h3>
+<p>Sort the objects (in descending order) using the attribute under the cursor as the sort key.</p>
+
+<h3>leave (Backspace, DEL, X)</h3>
+<p>Close current tab (and all the tabs to the right of the current one).</h3>
+
+<h3>quit (ESC,Q)</h3>
+<p>Quit igrid and return to the IPython prompt.</p>
+
+
+<h2>Navigation</h2>
+
+
+<h3>Jump to the last column of the current row (END, CTRL-E, CTRL-Right)</h3>
+
+<h3>Jump to the first column of the current row (HOME, CTRL-A, CTRL-Left)</h3>
+
+<h3>Move the cursor one column to the left (&lt;)</h3>
+
+<h3>Move the cursor one column to the right (&gt;)</h3>
+
+<h3>Jump to the first row in the current column (CTRL-Up)</h3>
+
+<h3>Jump to the last row in the current column (CTRL-Down)</h3>
+
+</body>
+</html>
diff --git a/IPython/Extensions/ipipe.py b/IPython/Extensions/ipipe.py
new file mode 100644
index 0000000..7f9029a
--- /dev/null
+++ b/IPython/Extensions/ipipe.py
@@ -0,0 +1,2327 @@
+# -*- coding: iso-8859-1 -*-
+
+"""
+``ipipe`` provides classes to be used in an interactive Python session. Doing a
+``from ipipe import *`` is the preferred way to do this. The name of all
+objects imported this way starts with ``i`` to minimize collisions.
+
+``ipipe`` supports "pipeline expressions", which is something resembling Unix
+pipes. An example is::
+
+ >>> ienv | isort("key.lower()")
+
+This gives a listing of all environment variables sorted by name.
+
+
+There are three types of objects in a pipeline expression:
+
+* ``Table``s: These objects produce items. Examples are ``ils`` (listing the
+ current directory, ``ienv`` (listing environment variables), ``ipwd`` (listing
+ user accounts) and ``igrp`` (listing user groups). A ``Table`` must be the
+ first object in a pipe expression.
+
+* ``Pipe``s: These objects sit in the middle of a pipe expression. They
+ transform the input in some way (e.g. filtering or sorting it). Examples are:
+ ``ifilter`` (which filters the input pipe), ``isort`` (which sorts the input
+ pipe) and ``ieval`` (which evaluates a function or expression for each object
+ in the input pipe).
+
+* ``Display``s: These objects can be put as the last object in a pipeline
+ expression. There are responsible for displaying the result of the pipeline
+ expression. If a pipeline expression doesn't end in a display object a default
+ display objects will be used. One example is ``ibrowse`` which is a ``curses``
+ based browser.
+
+
+Adding support for pipeline expressions to your own objects can be done through
+three extensions points (all of them optional):
+
+* An object that will be displayed as a row by a ``Display`` object should
+ implement the method ``__xattrs__(self, mode)`` method or register an
+ implementation of the generic function ``xattrs``. For more info see ``xattrs``.
+
+* When an object ``foo`` is displayed by a ``Display`` object, the generic
+ function ``xrepr`` is used.
+
+* Objects that can be iterated by ``Pipe``s must iterable. For special cases,
+ where iteration for display is different than the normal iteration a special
+ implementation can be registered with the generic function ``xiter``. This
+ makes it possible to use dictionaries and modules in pipeline expressions,
+ for example::
+
+ >>> import sys
+ >>> sys | ifilter("isinstance(value, int)") | idump
+ key |value
+ api_version| 1012
+ dllhandle | 503316480
+ hexversion | 33817328
+ maxint |2147483647
+ maxunicode | 65535
+ >>> sys.modules | ifilter("_.value is not None") | isort("_.key.lower()")
+ ...
+
+ Note: The expression strings passed to ``ifilter()`` and ``isort()`` can
+ refer to the object to be filtered or sorted via the variable ``_`` and to any
+ of the attributes of the object, i.e.::
+
+ >>> sys.modules | ifilter("_.value is not None") | isort("_.key.lower()")
+
+ does the same as::
+
+ >>> sys.modules | ifilter("value is not None") | isort("key.lower()")
+
+ In addition to expression strings, it's possible to pass callables (taking
+ the object as an argument) to ``ifilter()``, ``isort()`` and ``ieval()``::
+
+ >>> sys | ifilter(lambda _:isinstance(_.value, int)) \
+ ... | ieval(lambda _: (_.key, hex(_.value))) | idump
+ 0 |1
+ api_version|0x3f4
+ dllhandle |0x1e000000
+ hexversion |0x20402f0
+ maxint |0x7fffffff
+ maxunicode |0xffff
+"""
+
+skip_doctest = True # ignore top-level docstring as a doctest.
+
+import sys, os, os.path, stat, glob, new, csv, datetime, types
+import itertools, mimetypes, StringIO
+
+try: # Python 2.3 compatibility
+ import collections
+except ImportError:
+ deque = list
+else:
+ deque = collections.deque
+
+try: # Python 2.3 compatibility
+ set
+except NameError:
+ import sets
+ set = sets.Set
+
+try: # Python 2.3 compatibility
+ sorted
+except NameError:
+ def sorted(iterator, key=None, reverse=False):
+ items = list(iterator)
+ if key is not None:
+ items.sort(lambda i1, i2: cmp(key(i1), key(i2)))
+ else:
+ items.sort()
+ if reverse:
+ items.reverse()
+ return items
+
+try: # Python 2.4 compatibility
+ GeneratorExit
+except NameError:
+ GeneratorExit = SystemExit
+
+try:
+ import pwd
+except ImportError:
+ pwd = None
+
+try:
+ import grp
+except ImportError:
+ grp = None
+
+from IPython.external import simplegeneric
+from IPython.external import path
+
+try:
+ from IPython import genutils, generics
+except ImportError:
+ genutils = None
+ generics = None
+
+from IPython import ipapi
+
+
+__all__ = [
+ "ifile", "ils", "iglob", "iwalk", "ipwdentry", "ipwd", "igrpentry", "igrp",
+ "icsv", "ix", "ichain", "isort", "ifilter", "ieval", "ienum",
+ "ienv", "ihist", "ialias", "icap", "idump", "iless"
+]
+
+
+os.stat_float_times(True) # enable microseconds
+
+
+class AttrNamespace(object):
+ """
+ Helper class that is used for providing a namespace for evaluating
+ expressions containing attribute names of an object.
+ """
+ def __init__(self, wrapped):
+ self.wrapped = wrapped
+
+ def __getitem__(self, name):
+ if name == "_":
+ return self.wrapped
+ try:
+ return getattr(self.wrapped, name)
+ except AttributeError:
+ raise KeyError(name)
+
+# Python 2.3 compatibility
+# use eval workaround to find out which names are used in the
+# eval string and put them into the locals. This works for most
+# normal uses case, bizarre ones like accessing the locals()
+# will fail
+try:
+ eval("_", None, AttrNamespace(None))
+except TypeError:
+ real_eval = eval
+ def eval(codestring, _globals, _locals):
+ """
+ eval(source[, globals[, locals]]) -> value
+
+ Evaluate the source in the context of globals and locals.
+ The source may be a string representing a Python expression
+ or a code object as returned by compile().
+ The globals must be a dictionary and locals can be any mappping.
+
+ This function is a workaround for the shortcomings of
+ Python 2.3's eval.
+ """
+
+ if isinstance(codestring, basestring):
+ code = compile(codestring, "_eval", "eval")
+ else:
+ code = codestring
+ newlocals = {}
+ for name in code.co_names:
+ try:
+ newlocals[name] = _locals[name]
+ except KeyError:
+ pass
+ return real_eval(code, _globals, newlocals)
+
+
+noitem = object()
+
+
+def item(iterator, index, default=noitem):
+ """
+ Return the ``index``th item from the iterator ``iterator``.
+ ``index`` must be an integer (negative integers are relative to the
+ end (i.e. the last items produced by the iterator)).
+
+ If ``default`` is given, this will be the default value when
+ the iterator doesn't contain an item at this position. Otherwise an
+ ``IndexError`` will be raised.
+
+ Note that using this function will partially or totally exhaust the
+ iterator.
+ """
+ i = index
+ if i>=0:
+ for item in iterator:
+ if not i:
+ return item
+ i -= 1
+ else:
+ i = -index
+ cache = deque()
+ for item in iterator:
+ cache.append(item)
+ if len(cache)>i:
+ cache.popleft()
+ if len(cache)==i:
+ return cache.popleft()
+ if default is noitem:
+ raise IndexError(index)
+ else:
+ return default
+
+
+def getglobals(g):
+ """
+ Return the global namespace that is used for expression strings in
+ ``ifilter`` and others. This is ``g`` or (if ``g`` is ``None``) IPython's
+ user namespace.
+ """
+ if g is None:
+ if ipapi is not None:
+ api = ipapi.get()
+ if api is not None:
+ return api.user_ns
+ return globals()
+ return g
+
+
+class Descriptor(object):
+ """
+ A ``Descriptor`` object is used for describing the attributes of objects.
+ """
+ def __hash__(self):
+ return hash(self.__class__) ^ hash(self.key())
+
+ def __eq__(self, other):
+ return self.__class__ is other.__class__ and self.key() == other.key()
+
+ def __ne__(self, other):
+ return self.__class__ is not other.__class__ or self.key() != other.key()
+
+ def key(self):
+ pass
+
+ def name(self):
+ """
+ Return the name of this attribute for display by a ``Display`` object
+ (e.g. as a column title).
+ """
+ key = self.key()
+ if key is None:
+ return "_"
+ return str(key)
+
+ def attrtype(self, obj):
+ """
+ Return the type of this attribute (i.e. something like "attribute" or
+ "method").
+ """
+
+ def valuetype(self, obj):
+ """
+ Return the type of this attribute value of the object ``obj``.
+ """
+
+ def value(self, obj):
+ """
+ Return the value of this attribute of the object ``obj``.
+ """
+
+ def doc(self, obj):
+ """
+ Return the documentation for this attribute.
+ """
+
+ def shortdoc(self, obj):
+ """
+ Return a short documentation for this attribute (defaulting to the
+ first line).
+ """
+ doc = self.doc(obj)
+ if doc is not None:
+ doc = doc.strip().splitlines()[0].strip()
+ return doc
+
+ def iter(self, obj):
+ """
+ Return an iterator for this attribute of the object ``obj``.
+ """
+ return xiter(self.value(obj))
+
+
+class SelfDescriptor(Descriptor):
+ """
+ A ``SelfDescriptor`` describes the object itself.
+ """
+ def key(self):
+ return None
+
+ def attrtype(self, obj):
+ return "self"
+
+ def valuetype(self, obj):
+ return type(obj)
+
+ def value(self, obj):
+ return obj
+
+ def __repr__(self):
+ return "Self"
+
+selfdescriptor = SelfDescriptor() # there's no need for more than one
+
+
+class AttributeDescriptor(Descriptor):
+ """
+ An ``AttributeDescriptor`` describes a simple attribute of an object.
+ """
+ __slots__ = ("_name", "_doc")
+
+ def __init__(self, name, doc=None):
+ self._name = name
+ self._doc = doc
+
+ def key(self):
+ return self._name
+
+ def doc(self, obj):
+ return self._doc
+
+ def attrtype(self, obj):
+ return "attr"
+
+ def valuetype(self, obj):
+ return type(getattr(obj, self._name))
+
+ def value(self, obj):
+ return getattr(obj, self._name)
+
+ def __repr__(self):
+ if self._doc is None:
+ return "Attribute(%r)" % self._name
+ else:
+ return "Attribute(%r, %r)" % (self._name, self._doc)
+
+
+class IndexDescriptor(Descriptor):
+ """
+ An ``IndexDescriptor`` describes an "attribute" of an object that is fetched
+ via ``__getitem__``.
+ """
+ __slots__ = ("_index",)
+
+ def __init__(self, index):
+ self._index = index
+
+ def key(self):
+ return self._index
+
+ def attrtype(self, obj):
+ return "item"
+
+ def valuetype(self, obj):
+ return type(obj[self._index])
+
+ def value(self, obj):
+ return obj[self._index]
+
+ def __repr__(self):
+ return "Index(%r)" % self._index
+
+
+class MethodDescriptor(Descriptor):
+ """
+ A ``MethodDescriptor`` describes a method of an object that can be called
+ without argument. Note that this method shouldn't change the object.
+ """
+ __slots__ = ("_name", "_doc")
+
+ def __init__(self, name, doc=None):
+ self._name = name
+ self._doc = doc
+
+ def key(self):
+ return self._name
+
+ def doc(self, obj):
+ if self._doc is None:
+ return getattr(obj, self._name).__doc__
+ return self._doc
+
+ def attrtype(self, obj):
+ return "method"
+
+ def valuetype(self, obj):
+ return type(self.value(obj))
+
+ def value(self, obj):
+ return getattr(obj, self._name)()
+
+ def __repr__(self):
+ if self._doc is None:
+ return "Method(%r)" % self._name
+ else:
+ return "Method(%r, %r)" % (self._name, self._doc)
+
+
+class IterAttributeDescriptor(Descriptor):
+ """
+ An ``IterAttributeDescriptor`` works like an ``AttributeDescriptor`` but
+ doesn't return an attribute values (because this value might be e.g. a large
+ list).
+ """
+ __slots__ = ("_name", "_doc")
+
+ def __init__(self, name, doc=None):
+ self._name = name
+ self._doc = doc
+
+ def key(self):
+ return self._name
+
+ def doc(self, obj):
+ return self._doc
+
+ def attrtype(self, obj):
+ return "iter"
+
+ def valuetype(self, obj):
+ return noitem
+
+ def value(self, obj):
+ return noitem
+
+ def iter(self, obj):
+ return xiter(getattr(obj, self._name))
+
+ def __repr__(self):
+ if self._doc is None:
+ return "IterAttribute(%r)" % self._name
+ else:
+ return "IterAttribute(%r, %r)" % (self._name, self._doc)
+
+
+class IterMethodDescriptor(Descriptor):
+ """
+ An ``IterMethodDescriptor`` works like an ``MethodDescriptor`` but doesn't
+ return an attribute values (because this value might be e.g. a large list).
+ """
+ __slots__ = ("_name", "_doc")
+
+ def __init__(self, name, doc=None):
+ self._name = name
+ self._doc = doc
+
+ def key(self):
+ return self._name
+
+ def doc(self, obj):
+ if self._doc is None:
+ return getattr(obj, self._name).__doc__
+ return self._doc
+
+ def attrtype(self, obj):
+ return "itermethod"
+
+ def valuetype(self, obj):
+ return noitem
+
+ def value(self, obj):
+ return noitem
+
+ def iter(self, obj):
+ return xiter(getattr(obj, self._name)())
+
+ def __repr__(self):
+ if self._doc is None:
+ return "IterMethod(%r)" % self._name
+ else:
+ return "IterMethod(%r, %r)" % (self._name, self._doc)
+
+
+class FunctionDescriptor(Descriptor):
+ """
+ A ``FunctionDescriptor`` turns a function into a descriptor. The function
+ will be called with the object to get the type and value of the attribute.
+ """
+ __slots__ = ("_function", "_name", "_doc")
+
+ def __init__(self, function, name=None, doc=None):
+ self._function = function
+ self._name = name
+ self._doc = doc
+
+ def key(self):
+ return self._function
+
+ def name(self):
+ if self._name is not None:
+ return self._name
+ return getattr(self._function, "__xname__", self._function.__name__)
+
+ def doc(self, obj):
+ if self._doc is None:
+ return self._function.__doc__
+ return self._doc
+
+ def attrtype(self, obj):
+ return "function"
+
+ def valuetype(self, obj):
+ return type(self._function(obj))
+
+ def value(self, obj):
+ return self._function(obj)
+
+ def __repr__(self):
+ if self._doc is None:
+ return "Function(%r)" % self._name
+ else:
+ return "Function(%r, %r)" % (self._name, self._doc)
+
+
+class Table(object):
+ """
+ A ``Table`` is an object that produces items (just like a normal Python
+ iterator/generator does) and can be used as the first object in a pipeline
+ expression. The displayhook will open the default browser for such an object
+ (instead of simply printing the ``repr()`` result).
+ """
+
+ # We want to support ``foo`` and ``foo()`` in pipeline expression:
+ # So we implement the required operators (``|`` and ``+``) in the metaclass,
+ # instantiate the class and forward the operator to the instance
+ class __metaclass__(type):
+ def __iter__(self):
+ return iter(self())
+
+ def __or__(self, other):
+ return self() | other
+
+ def __add__(self, other):
+ return self() + other
+
+ def __radd__(self, other):
+ return other + self()
+
+ def __getitem__(self, index):
+ return self()[index]
+
+ def __getitem__(self, index):
+ return item(self, index)
+
+ def __contains__(self, item):
+ for haveitem in self:
+ if item == haveitem:
+ return True
+ return False
+
+ def __or__(self, other):
+ # autoinstantiate right hand side
+ if isinstance(other, type) and issubclass(other, (Table, Display)):
+ other = other()
+ # treat simple strings and functions as ``ieval`` instances
+ elif not isinstance(other, Display) and not isinstance(other, Table):
+ other = ieval(other)
+ # forward operations to the right hand side
+ return other.__ror__(self)
+
+ def __add__(self, other):
+ # autoinstantiate right hand side
+ if isinstance(other, type) and issubclass(other, Table):
+ other = other()
+ return ichain(self, other)
+
+ def __radd__(self, other):
+ # autoinstantiate left hand side
+ if isinstance(other, type) and issubclass(other, Table):
+ other = other()
+ return ichain(other, self)
+
+
+class Pipe(Table):
+ """
+ A ``Pipe`` is an object that can be used in a pipeline expression. It
+ processes the objects it gets from its input ``Table``/``Pipe``. Note that
+ a ``Pipe`` object can't be used as the first object in a pipeline
+ expression, as it doesn't produces items itself.
+ """
+ class __metaclass__(Table.__metaclass__):
+ def __ror__(self, input):
+ return input | self()
+
+ def __ror__(self, input):
+ # autoinstantiate left hand side
+ if isinstance(input, type) and issubclass(input, Table):
+ input = input()
+ self.input = input
+ return self
+
+
+def xrepr(item, mode="default"):
+ """
+ Generic function that adds color output and different display modes to ``repr``.
+
+ The result of an ``xrepr`` call is iterable and consists of ``(style, string)``
+ tuples. The ``style`` in this tuple must be a ``Style`` object from the
+ ``astring`` module. To reconfigure the output the first yielded tuple can be
+ a ``(aligment, full)`` tuple instead of a ``(style, string)`` tuple.
+ ``alignment`` can be -1 for left aligned, 0 for centered and 1 for right
+ aligned (the default is left alignment). ``full`` is a boolean that specifies
+ whether the complete output must be displayed or the ``Display`` object is
+ allowed to stop output after enough text has been produced (e.g. a syntax
+ highlighted text line would use ``True``, but for a large data structure
+ (i.e. a nested list, tuple or dictionary) ``False`` would be used).
+ The default is full output.
+
+ There are four different possible values for ``mode`` depending on where
+ the ``Display`` object will display ``item``:
+
+ ``"header"``
+ ``item`` will be displayed in a header line (this is used by ``ibrowse``).
+
+ ``"footer"``
+ ``item`` will be displayed in a footer line (this is used by ``ibrowse``).
+
+ ``"cell"``
+ ``item`` will be displayed in a table cell/list.
+
+ ``"default"``
+ default mode. If an ``xrepr`` implementation recursively outputs objects,
+ ``"default"`` must be passed in the recursive calls to ``xrepr``.
+
+ If no implementation is registered for ``item``, ``xrepr`` will try the
+ ``__xrepr__`` method on ``item``. If ``item`` doesn't have an ``__xrepr__``
+ method it falls back to ``repr``/``__repr__`` for all modes.
+ """
+ try:
+ func = item.__xrepr__
+ except AttributeError:
+ yield (astyle.style_default, repr(item))
+ else:
+ try:
+ for x in func(mode):
+ yield x
+ except (KeyboardInterrupt, SystemExit, GeneratorExit):
+ raise
+ except Exception:
+ yield (astyle.style_default, repr(item))
+xrepr = simplegeneric.generic(xrepr)
+
+
+def xrepr_none(self, mode="default"):
+ yield (astyle.style_type_none, repr(self))
+xrepr.when_object(None)(xrepr_none)
+
+
+def xrepr_noitem(self, mode="default"):
+ yield (2, True)
+ yield (astyle.style_nodata, "<?>")
+xrepr.when_object(noitem)(xrepr_noitem)
+
+
+def xrepr_bool(self, mode="default"):
+ yield (astyle.style_type_bool, repr(self))
+xrepr.when_type(bool)(xrepr_bool)
+
+
+def xrepr_str(self, mode="default"):
+ if mode == "cell":
+ yield (astyle.style_default, repr(self.expandtabs(tab))[1:-1])
+ else:
+ yield (astyle.style_default, repr(self))
+xrepr.when_type(str)(xrepr_str)
+
+
+def xrepr_unicode(self, mode="default"):
+ if mode == "cell":
+ yield (astyle.style_default, repr(self.expandtabs(tab))[2:-1])
+ else:
+ yield (astyle.style_default, repr(self))
+xrepr.when_type(unicode)(xrepr_unicode)
+
+
+def xrepr_number(self, mode="default"):
+ yield (1, True)
+ yield (astyle.style_type_number, repr(self))
+xrepr.when_type(int)(xrepr_number)
+xrepr.when_type(long)(xrepr_number)
+xrepr.when_type(float)(xrepr_number)
+
+
+def xrepr_complex(self, mode="default"):
+ yield (astyle.style_type_number, repr(self))
+xrepr.when_type(complex)(xrepr_number)
+
+
+def xrepr_datetime(self, mode="default"):
+ if mode == "cell":
+ # Don't use strftime() here, as this requires year >= 1900
+ yield (astyle.style_type_datetime,
+ "%04d-%02d-%02d %02d:%02d:%02d.%06d" % \
+ (self.year, self.month, self.day,
+ self.hour, self.minute, self.second,
+ self.microsecond),
+ )
+ else:
+ yield (astyle.style_type_datetime, repr(self))
+xrepr.when_type(datetime.datetime)(xrepr_datetime)
+
+
+def xrepr_date(self, mode="default"):
+ if mode == "cell":
+ yield (astyle.style_type_datetime,
+ "%04d-%02d-%02d" % (self.year, self.month, self.day))
+ else:
+ yield (astyle.style_type_datetime, repr(self))
+xrepr.when_type(datetime.date)(xrepr_date)
+
+
+def xrepr_time(self, mode="default"):
+ if mode == "cell":
+ yield (astyle.style_type_datetime,
+ "%02d:%02d:%02d.%06d" % \
+ (self.hour, self.minute, self.second, self.microsecond))
+ else:
+ yield (astyle.style_type_datetime, repr(self))
+xrepr.when_type(datetime.time)(xrepr_time)
+
+
+def xrepr_timedelta(self, mode="default"):
+ yield (astyle.style_type_datetime, repr(self))
+xrepr.when_type(datetime.timedelta)(xrepr_timedelta)
+
+
+def xrepr_type(self, mode="default"):
+ if self.__module__ == "__builtin__":
+ yield (astyle.style_type_type, self.__name__)
+ else:
+ yield (astyle.style_type_type, "%s.%s" % (self.__module__, self.__name__))
+xrepr.when_type(type)(xrepr_type)
+
+
+def xrepr_exception(self, mode="default"):
+ if self.__class__.__module__ == "exceptions":
+ classname = self.__class__.__name__
+ else:
+ classname = "%s.%s" % \
+ (self.__class__.__module__, self.__class__.__name__)
+ if mode == "header" or mode == "footer":
+ yield (astyle.style_error, "%s: %s" % (classname, self))
+ else:
+ yield (astyle.style_error, classname)
+xrepr.when_type(Exception)(xrepr_exception)
+
+
+def xrepr_listtuple(self, mode="default"):
+ if mode == "header" or mode == "footer":
+ if self.__class__.__module__ == "__builtin__":
+ classname = self.__class__.__name__
+ else:
+ classname = "%s.%s" % \
+ (self.__class__.__module__,self.__class__.__name__)
+ yield (astyle.style_default,
+ "<%s object with %d items at 0x%x>" % \
+ (classname, len(self), id(self)))
+ else:
+ yield (-1, False)
+ if isinstance(self, list):
+ yield (astyle.style_default, "[")
+ end = "]"
+ else:
+ yield (astyle.style_default, "(")
+ end = ")"
+ for (i, subself) in enumerate(self):
+ if i:
+ yield (astyle.style_default, ", ")
+ for part in xrepr(subself, "default"):
+ yield part
+ yield (astyle.style_default, end)
+xrepr.when_type(list)(xrepr_listtuple)
+xrepr.when_type(tuple)(xrepr_listtuple)
+
+
+def xrepr_dict(self, mode="default"):
+ if mode == "header" or mode == "footer":
+ if self.__class__.__module__ == "__builtin__":
+ classname = self.__class__.__name__
+ else:
+ classname = "%s.%s" % \
+ (self.__class__.__module__,self.__class__.__name__)
+ yield (astyle.style_default,
+ "<%s object with %d items at 0x%x>" % \
+ (classname, len(self), id(self)))
+ else:
+ yield (-1, False)
+ if isinstance(self, dict):
+ yield (astyle.style_default, "{")
+ end = "}"
+ else:
+ yield (astyle.style_default, "dictproxy((")
+ end = "})"
+ for (i, (key, value)) in enumerate(self.iteritems()):
+ if i:
+ yield (astyle.style_default, ", ")
+ for part in xrepr(key, "default"):
+ yield part
+ yield (astyle.style_default, ": ")
+ for part in xrepr(value, "default"):
+ yield part
+ yield (astyle.style_default, end)
+xrepr.when_type(dict)(xrepr_dict)
+xrepr.when_type(types.DictProxyType)(xrepr_dict)
+
+
+def upgradexattr(attr):
+ """
+ Convert an attribute descriptor string to a real descriptor object.
+
+ If attr already is a descriptor object return it unmodified. A
+ ``SelfDescriptor`` will be returned if ``attr`` is ``None``. ``"foo"``
+ returns an ``AttributeDescriptor`` for the attribute named ``"foo"``.
+ ``"foo()"`` returns a ``MethodDescriptor`` for the method named ``"foo"``.
+ ``"-foo"`` will return an ``IterAttributeDescriptor`` for the attribute
+ named ``"foo"`` and ``"-foo()"`` will return an ``IterMethodDescriptor``
+ for the method named ``"foo"``. Furthermore integers will return the appropriate
+ ``IndexDescriptor`` and callables will return a ``FunctionDescriptor``.
+ """
+ if attr is None:
+ return selfdescriptor
+ elif isinstance(attr, Descriptor):
+ return attr
+ elif isinstance(attr, basestring):
+ if attr.endswith("()"):
+ if attr.startswith("-"):
+ return IterMethodDescriptor(attr[1:-2])
+ else:
+ return MethodDescriptor(attr[:-2])
+ else:
+ if attr.startswith("-"):
+ return IterAttributeDescriptor(attr[1:])
+ else:
+ return AttributeDescriptor(attr)
+ elif isinstance(attr, (int, long)):
+ return IndexDescriptor(attr)
+ elif callable(attr):
+ return FunctionDescriptor(attr)
+ else:
+ raise TypeError("can't handle descriptor %r" % attr)
+
+
+def xattrs(item, mode="default"):
+ """
+ Generic function that returns an iterable of attribute descriptors
+ to be used for displaying the attributes ob the object ``item`` in display
+ mode ``mode``.
+
+ There are two possible modes:
+
+ ``"detail"``
+ The ``Display`` object wants to display a detailed list of the object
+ attributes.
+
+ ``"default"``
+ The ``Display`` object wants to display the object in a list view.
+
+ If no implementation is registered for the object ``item`` ``xattrs`` falls
+ back to trying the ``__xattrs__`` method of the object. If this doesn't
+ exist either, ``dir(item)`` is used for ``"detail"`` mode and ``(None,)``
+ for ``"default"`` mode.
+
+ The implementation must yield attribute descriptors (see the class
+ ``Descriptor`` for more info). The ``__xattrs__`` method may also return
+ attribute descriptor strings (and ``None``) which will be converted to real
+ descriptors by ``upgradexattr()``.
+ """
+ try:
+ func = item.__xattrs__
+ except AttributeError:
+ if mode == "detail":
+ for attrname in dir(item):
+ yield AttributeDescriptor(attrname)
+ else:
+ yield selfdescriptor
+ else:
+ for attr in func(mode):
+ yield upgradexattr(attr)
+xattrs = simplegeneric.generic(xattrs)
+
+
+def xattrs_complex(self, mode="default"):
+ if mode == "detail":
+ return (AttributeDescriptor("real"), AttributeDescriptor("imag"))
+ return (selfdescriptor,)
+xattrs.when_type(complex)(xattrs_complex)
+
+
+def _isdict(item):
+ try:
+ itermeth = item.__class__.__iter__
+ except (AttributeError, TypeError):
+ return False
+ return itermeth is dict.__iter__ or itermeth is types.DictProxyType.__iter__
+
+
+def _isstr(item):
+ if not isinstance(item, basestring):
+ return False
+ try:
+ itermeth = item.__class__.__iter__
+ except AttributeError:
+ return True
+ return False # ``__iter__`` has been redefined
+
+
+def xiter(item):
+ """
+ Generic function that implements iteration for pipeline expression. If no
+ implementation is registered for ``item`` ``xiter`` falls back to ``iter``.
+ """
+ try:
+ func = item.__xiter__
+ except AttributeError:
+ if _isdict(item):
+ def items(item):
+ fields = ("key", "value")
+ for (key, value) in item.iteritems():
+ yield Fields(fields, key=key, value=value)
+ return items(item)
+ elif isinstance(item, new.module):
+ def items(item):
+ fields = ("key", "value")
+ for key in sorted(item.__dict__):
+ yield Fields(fields, key=key, value=getattr(item, key))
+ return items(item)
+ elif _isstr(item):
+ if not item:
+ raise ValueError("can't enter empty string")
+ lines = item.splitlines()
+ if len(lines) == 1:
+ def iterone(item):
+ yield item
+ return iterone(item)
+ else:
+ return iter(lines)
+ return iter(item)
+ else:
+ return iter(func()) # iter() just to be safe
+xiter = simplegeneric.generic(xiter)
+
+
+class ichain(Pipe):
+ """
+ Chains multiple ``Table``s into one.
+ """
+
+ def __init__(self, *iters):
+ self.iters = iters
+
+ def __iter__(self):
+ return itertools.chain(*self.iters)
+
+ def __xrepr__(self, mode="default"):
+ if mode == "header" or mode == "footer":
+ for (i, item) in enumerate(self.iters):
+ if i:
+ yield (astyle.style_default, "+")
+ if isinstance(item, Pipe):
+ yield (astyle.style_default, "(")
+ for part in xrepr(item, mode):
+ yield part
+ if isinstance(item, Pipe):
+ yield (astyle.style_default, ")")
+ else:
+ yield (astyle.style_default, repr(self))
+
+ def __repr__(self):
+ args = ", ".join([repr(it) for it in self.iters])
+ return "%s.%s(%s)" % \
+ (self.__class__.__module__, self.__class__.__name__, args)
+
+
+class ifile(path.path):
+ """
+ file (or directory) object.
+ """
+
+ def getmode(self):
+ return self.stat().st_mode
+ mode = property(getmode, None, None, "Access mode")
+
+ def gettype(self):
+ data = [
+ (stat.S_ISREG, "file"),
+ (stat.S_ISDIR, "dir"),
+ (stat.S_ISCHR, "chardev"),
+ (stat.S_ISBLK, "blockdev"),
+ (stat.S_ISFIFO, "fifo"),
+ (stat.S_ISLNK, "symlink"),
+ (stat.S_ISSOCK,"socket"),
+ ]
+ lstat = self.lstat()
+ if lstat is not None:
+ types = set([text for (func, text) in data if func(lstat.st_mode)])
+ else:
+ types = set()
+ m = self.mode
+ types.update([text for (func, text) in data if func(m)])
+ return ", ".join(types)
+ type = property(gettype, None, None, "file type (file, directory, link, etc.)")
+
+ def getmodestr(self):
+ m = self.mode
+ data = [
+ (stat.S_IRUSR, "-r"),
+ (stat.S_IWUSR, "-w"),
+ (stat.S_IXUSR, "-x"),
+ (stat.S_IRGRP, "-r"),
+ (stat.S_IWGRP, "-w"),
+ (stat.S_IXGRP, "-x"),
+ (stat.S_IROTH, "-r"),
+ (stat.S_IWOTH, "-w"),
+ (stat.S_IXOTH, "-x"),
+ ]
+ return "".join([text[bool(m&bit)] for (bit, text) in data])
+
+ modestr = property(getmodestr, None, None, "Access mode as string")
+
+ def getblocks(self):
+ return self.stat().st_blocks
+ blocks = property(getblocks, None, None, "File size in blocks")
+
+ def getblksize(self):
+ return self.stat().st_blksize
+ blksize = property(getblksize, None, None, "Filesystem block size")
+
+ def getdev(self):
+ return self.stat().st_dev
+ dev = property(getdev)
+
+ def getnlink(self):
+ return self.stat().st_nlink
+ nlink = property(getnlink, None, None, "Number of links")
+
+ def getuid(self):
+ return self.stat().st_uid
+ uid = property(getuid, None, None, "User id of file owner")
+
+ def getgid(self):
+ return self.stat().st_gid
+ gid = property(getgid, None, None, "Group id of file owner")
+
+ def getowner(self):
+ stat = self.stat()
+ try:
+ return pwd.getpwuid(stat.st_uid).pw_name
+ except KeyError:
+ return stat.st_uid
+ owner = property(getowner, None, None, "Owner name (or id)")
+
+ def getgroup(self):
+ stat = self.stat()
+ try:
+ return grp.getgrgid(stat.st_gid).gr_name
+ except KeyError:
+ return stat.st_gid
+ group = property(getgroup, None, None, "Group name (or id)")
+
+ def getadate(self):
+ return datetime.datetime.utcfromtimestamp(self.atime)
+ adate = property(getadate, None, None, "Access date")
+
+ def getcdate(self):
+ return datetime.datetime.utcfromtimestamp(self.ctime)
+ cdate = property(getcdate, None, None, "Creation date")
+
+ def getmdate(self):
+ return datetime.datetime.utcfromtimestamp(self.mtime)
+ mdate = property(getmdate, None, None, "Modification date")
+
+ def mimetype(self):
+ """
+ Return MIME type guessed from the extension.
+ """
+ return mimetypes.guess_type(self.basename())[0]
+
+ def encoding(self):
+ """
+ Return guessed compression (like "compress" or "gzip").
+ """
+ return mimetypes.guess_type(self.basename())[1]
+
+ def __repr__(self):
+ return "ifile(%s)" % path._base.__repr__(self)
+
+ if sys.platform == "win32":
+ defaultattrs = (None, "type", "size", "modestr", "mdate")
+ else:
+ defaultattrs = (None, "type", "size", "modestr", "owner", "group", "mdate")
+
+ def __xattrs__(self, mode="default"):
+ if mode == "detail":
+ return (
+ "name",
+ "basename()",
+ "abspath()",
+ "realpath()",
+ "type",
+ "mode",
+ "modestr",
+ "stat()",
+ "lstat()",
+ "uid",
+ "gid",
+ "owner",
+ "group",
+ "dev",
+ "nlink",
+ "ctime",
+ "mtime",
+ "atime",
+ "cdate",
+ "mdate",
+ "adate",
+ "size",
+ "blocks",
+ "blksize",
+ "isdir()",
+ "islink()",
+ "mimetype()",
+ "encoding()",
+ "-listdir()",
+ "-dirs()",
+ "-files()",
+ "-walk()",
+ "-walkdirs()",
+ "-walkfiles()",
+ )
+ else:
+ return self.defaultattrs
+
+
+def xiter_ifile(self):
+ if self.isdir():
+ yield (self / os.pardir).abspath()
+ for child in sorted(self.listdir()):
+ yield child
+ else:
+ f = self.open("rb")
+ for line in f:
+ yield line
+ f.close()
+xiter.when_type(ifile)(xiter_ifile)
+
+
+# We need to implement ``xrepr`` for ``ifile`` as a generic function, because
+# otherwise ``xrepr_str`` would kick in.
+def xrepr_ifile(self, mode="default"):
+ try:
+ if self.isdir():
+ name = "idir"
+ style = astyle.style_dir
+ else:
+ name = "ifile"
+ style = astyle.style_file
+ except IOError:
+ name = "ifile"
+ style = astyle.style_default
+ if mode in ("cell", "header", "footer"):
+ abspath = repr(path._base(self.normpath()))
+ if abspath.startswith("u"):
+ abspath = abspath[2:-1]
+ else:
+ abspath = abspath[1:-1]
+ if mode == "cell":
+ yield (style, abspath)
+ else:
+ yield (style, "%s(%s)" % (name, abspath))
+ else:
+ yield (style, repr(self))
+xrepr.when_type(ifile)(xrepr_ifile)
+
+
+class ils(Table):
+ """
+ List the current (or a specified) directory.
+
+ Examples::
+
+ >>> ils
+ <class 'IPython.Extensions.ipipe.ils'>
+ >>> ils("/usr/local/lib/python2.4")
+ IPython.Extensions.ipipe.ils('/usr/local/lib/python2.4')
+ >>> ils("~")
+ IPython.Extensions.ipipe.ils('/home/fperez')
+ # all-random
+ """
+ def __init__(self, base=os.curdir, dirs=True, files=True):
+ self.base = os.path.expanduser(base)
+ self.dirs = dirs
+ self.files = files
+
+ def __iter__(self):
+ base = ifile(self.base)
+ yield (base / os.pardir).abspath()
+ for child in sorted(base.listdir()):
+ if self.dirs:
+ if self.files:
+ yield child
+ else:
+ if child.isdir():
+ yield child
+ elif self.files:
+ if not child.isdir():
+ yield child
+
+ def __xrepr__(self, mode="default"):
+ return xrepr(ifile(self.base), mode)
+
+ def __repr__(self):
+ return "%s.%s(%r)" % \
+ (self.__class__.__module__, self.__class__.__name__, self.base)
+
+
+class iglob(Table):
+ """
+ List all files and directories matching a specified pattern.
+ (See ``glob.glob()`` for more info.).
+
+ Examples::
+
+ >>> iglob("*.py")
+ IPython.Extensions.ipipe.iglob('*.py')
+ """
+ def __init__(self, glob):
+ self.glob = glob
+
+ def __iter__(self):
+ for name in glob.glob(self.glob):
+ yield ifile(name)
+
+ def __xrepr__(self, mode="default"):
+ if mode == "header" or mode == "footer" or mode == "cell":
+ yield (astyle.style_default,
+ "%s(%r)" % (self.__class__.__name__, self.glob))
+ else:
+ yield (astyle.style_default, repr(self))
+
+ def __repr__(self):
+ return "%s.%s(%r)" % \
+ (self.__class__.__module__, self.__class__.__name__, self.glob)
+
+
+class iwalk(Table):
+ """
+ List all files and directories in a directory and it's subdirectory::
+
+ >>> iwalk
+ <class 'IPython.Extensions.ipipe.iwalk'>
+ >>> iwalk("/usr/lib")
+ IPython.Extensions.ipipe.iwalk('/usr/lib')
+ >>> iwalk("~")
+ IPython.Extensions.ipipe.iwalk('/home/fperez') # random
+
+ """
+ def __init__(self, base=os.curdir, dirs=True, files=True):
+ self.base = os.path.expanduser(base)
+ self.dirs = dirs
+ self.files = files
+
+ def __iter__(self):
+ for (dirpath, dirnames, filenames) in os.walk(self.base):
+ if self.dirs:
+ for name in sorted(dirnames):
+ yield ifile(os.path.join(dirpath, name))
+ if self.files:
+ for name in sorted(filenames):
+ yield ifile(os.path.join(dirpath, name))
+
+ def __xrepr__(self, mode="default"):
+ if mode == "header" or mode == "footer" or mode == "cell":
+ yield (astyle.style_default,
+ "%s(%r)" % (self.__class__.__name__, self.base))
+ else:
+ yield (astyle.style_default, repr(self))
+
+ def __repr__(self):
+ return "%s.%s(%r)" % \
+ (self.__class__.__module__, self.__class__.__name__, self.base)
+
+
+class ipwdentry(object):
+ """
+ ``ipwdentry`` objects encapsulate entries in the Unix user account and
+ password database.
+ """
+ def __init__(self, id):
+ self._id = id
+ self._entry = None
+
+ def __eq__(self, other):
+ return self.__class__ is other.__class__ and self._id == other._id
+
+ def __ne__(self, other):
+ return self.__class__ is not other.__class__ or self._id != other._id
+
+ def _getentry(self):
+ if self._entry is None:
+ if isinstance(self._id, basestring):
+ self._entry = pwd.getpwnam(self._id)
+ else:
+ self._entry = pwd.getpwuid(self._id)
+ return self._entry
+
+ def getname(self):
+ if isinstance(self._id, basestring):
+ return self._id
+ else:
+ return self._getentry().pw_name
+ name = property(getname, None, None, "User name")
+
+ def getpasswd(self):
+ return self._getentry().pw_passwd
+ passwd = property(getpasswd, None, None, "Password")
+
+ def getuid(self):
+ if isinstance(self._id, basestring):
+ return self._getentry().pw_uid
+ else:
+ return self._id
+ uid = property(getuid, None, None, "User id")
+
+ def getgid(self):
+ return self._getentry().pw_gid
+ gid = property(getgid, None, None, "Primary group id")
+
+ def getgroup(self):
+ return igrpentry(self.gid)
+ group = property(getgroup, None, None, "Group")
+
+ def getgecos(self):
+ return self._getentry().pw_gecos
+ gecos = property(getgecos, None, None, "Information (e.g. full user name)")
+
+ def getdir(self):
+ return self._getentry().pw_dir
+ dir = property(getdir, None, None, "$HOME directory")
+
+ def getshell(self):
+ return self._getentry().pw_shell
+ shell = property(getshell, None, None, "Login shell")
+
+ def __xattrs__(self, mode="default"):
+ return ("name", "passwd", "uid", "gid", "gecos", "dir", "shell")
+
+ def __repr__(self):
+ return "%s.%s(%r)" % \
+ (self.__class__.__module__, self.__class__.__name__, self._id)
+
+
+class ipwd(Table):
+ """
+ List all entries in the Unix user account and password database.
+
+ Example::
+
+ >>> ipwd | isort("uid")
+ <IPython.Extensions.ipipe.isort key='uid' reverse=False at 0x849efec>
+ # random
+ """
+ def __iter__(self):
+ for entry in pwd.getpwall():
+ yield ipwdentry(entry.pw_name)
+
+ def __xrepr__(self, mode="default"):
+ if mode == "header" or mode == "footer" or mode == "cell":
+ yield (astyle.style_default, "%s()" % self.__class__.__name__)
+ else:
+ yield (astyle.style_default, repr(self))
+
+
+class igrpentry(object):
+ """
+ ``igrpentry`` objects encapsulate entries in the Unix group database.
+ """
+ def __init__(self, id):
+ self._id = id
+ self._entry = None
+
+ def __eq__(self, other):
+ return self.__class__ is other.__class__ and self._id == other._id
+
+ def __ne__(self, other):
+ return self.__class__ is not other.__class__ or self._id != other._id
+
+ def _getentry(self):
+ if self._entry is None:
+ if isinstance(self._id, basestring):
+ self._entry = grp.getgrnam(self._id)
+ else:
+ self._entry = grp.getgrgid(self._id)
+ return self._entry
+
+ def getname(self):
+ if isinstance(self._id, basestring):
+ return self._id
+ else:
+ return self._getentry().gr_name
+ name = property(getname, None, None, "Group name")
+
+ def getpasswd(self):
+ return self._getentry().gr_passwd
+ passwd = property(getpasswd, None, None, "Password")
+
+ def getgid(self):
+ if isinstance(self._id, basestring):
+ return self._getentry().gr_gid
+ else:
+ return self._id
+ gid = property(getgid, None, None, "Group id")
+
+ def getmem(self):
+ return self._getentry().gr_mem
+ mem = property(getmem, None, None, "Members")
+
+ def __xattrs__(self, mode="default"):
+ return ("name", "passwd", "gid", "mem")
+
+ def __xrepr__(self, mode="default"):
+ if mode == "header" or mode == "footer" or mode == "cell":
+ yield (astyle.style_default, "group ")
+ try:
+ yield (astyle.style_default, self.name)
+ except KeyError:
+ if isinstance(self._id, basestring):
+ yield (astyle.style_default, self.name_id)
+ else:
+ yield (astyle.style_type_number, str(self._id))
+ else:
+ yield (astyle.style_default, repr(self))
+
+ def __iter__(self):
+ for member in self.mem:
+ yield ipwdentry(member)
+
+ def __repr__(self):
+ return "%s.%s(%r)" % \
+ (self.__class__.__module__, self.__class__.__name__, self._id)
+
+
+class igrp(Table):
+ """
+ This ``Table`` lists all entries in the Unix group database.
+ """
+ def __iter__(self):
+ for entry in grp.getgrall():
+ yield igrpentry(entry.gr_name)
+
+ def __xrepr__(self, mode="default"):
+ if mode == "header" or mode == "footer":
+ yield (astyle.style_default, "%s()" % self.__class__.__name__)
+ else:
+ yield (astyle.style_default, repr(self))
+
+
+class Fields(object):
+ def __init__(self, fieldnames, **fields):
+ self.__fieldnames = [upgradexattr(fieldname) for fieldname in fieldnames]
+ for (key, value) in fields.iteritems():
+ setattr(self, key, value)
+
+ def __xattrs__(self, mode="default"):
+ return self.__fieldnames
+
+ def __xrepr__(self, mode="default"):
+ yield (-1, False)
+ if mode == "header" or mode == "cell":
+ yield (astyle.style_default, self.__class__.__name__)
+ yield (astyle.style_default, "(")
+ for (i, f) in enumerate(self.__fieldnames):
+ if i:
+ yield (astyle.style_default, ", ")
+ yield (astyle.style_default, f.name())
+ yield (astyle.style_default, "=")
+ for part in xrepr(getattr(self, f), "default"):
+ yield part
+ yield (astyle.style_default, ")")
+ elif mode == "footer":
+ yield (astyle.style_default, self.__class__.__name__)
+ yield (astyle.style_default, "(")
+ for (i, f) in enumerate(self.__fieldnames):
+ if i:
+ yield (astyle.style_default, ", ")
+ yield (astyle.style_default, f.name())
+ yield (astyle.style_default, ")")
+ else:
+ yield (astyle.style_default, repr(self))
+
+
+class FieldTable(Table, list):
+ def __init__(self, *fields):
+ Table.__init__(self)
+ list.__init__(self)
+ self.fields = fields
+
+ def add(self, **fields):
+ self.append(Fields(self.fields, **fields))
+
+ def __xrepr__(self, mode="default"):
+ yield (-1, False)
+ if mode == "header" or mode == "footer":
+ yield (astyle.style_default, self.__class__.__name__)
+ yield (astyle.style_default, "(")
+ for (i, f) in enumerate(self.__fieldnames):
+ if i:
+ yield (astyle.style_default, ", ")
+ yield (astyle.style_default, f)
+ yield (astyle.style_default, ")")
+ else:
+ yield (astyle.style_default, repr(self))
+
+ def __repr__(self):
+ return "<%s.%s object with fields=%r at 0x%x>" % \
+ (self.__class__.__module__, self.__class__.__name__,
+ ", ".join(map(repr, self.fields)), id(self))
+
+
+class List(list):
+ def __xattrs__(self, mode="default"):
+ return xrange(len(self))
+
+ def __xrepr__(self, mode="default"):
+ yield (-1, False)
+ if mode == "header" or mode == "cell" or mode == "footer" or mode == "default":
+ yield (astyle.style_default, self.__class__.__name__)
+ yield (astyle.style_default, "(")
+ for (i, item) in enumerate(self):
+ if i:
+ yield (astyle.style_default, ", ")
+ for part in xrepr(item, "default"):
+ yield part
+ yield (astyle.style_default, ")")
+ else:
+ yield (astyle.style_default, repr(self))
+
+
+class ienv(Table):
+ """
+ List environment variables.
+
+ Example::
+
+ >>> ienv
+ <class 'IPython.Extensions.ipipe.ienv'>
+ """
+
+ def __iter__(self):
+ fields = ("key", "value")
+ for (key, value) in os.environ.iteritems():
+ yield Fields(fields, key=key, value=value)
+
+ def __xrepr__(self, mode="default"):
+ if mode == "header" or mode == "cell":
+ yield (astyle.style_default, "%s()" % self.__class__.__name__)
+ else:
+ yield (astyle.style_default, repr(self))
+
+
+class ihist(Table):
+ """
+ IPython input history
+
+ Example::
+
+ >>> ihist
+ <class 'IPython.Extensions.ipipe.ihist'>
+ >>> ihist(True) # raw mode
+ <IPython.Extensions.ipipe.ihist object at 0x849602c> # random
+ """
+ def __init__(self, raw=True):
+ self.raw = raw
+
+ def __iter__(self):
+ api = ipapi.get()
+ if self.raw:
+ for line in api.IP.input_hist_raw:
+ yield line.rstrip("\n")
+ else:
+ for line in api.IP.input_hist:
+ yield line.rstrip("\n")
+
+
+class Alias(object):
+ """
+ Entry in the alias table
+ """
+ def __init__(self, name, args, command):
+ self.name = name
+ self.args = args
+ self.command = command
+
+ def __xattrs__(self, mode="default"):
+ return ("name", "args", "command")
+
+
+class ialias(Table):
+ """
+ IPython alias list
+
+ Example::
+
+ >>> ialias
+ <class 'IPython.Extensions.ipipe.ialias'>
+ """
+ def __iter__(self):
+ api = ipapi.get()
+
+ for (name, (args, command)) in api.IP.alias_table.iteritems():
+ yield Alias(name, args, command)
+
+
+class icsv(Pipe):
+ """
+ This ``Pipe`` turns the input (with must be a pipe outputting lines
+ or an ``ifile``) into lines of CVS columns.
+ """
+ def __init__(self, **csvargs):
+ """
+ Create an ``icsv`` object. ``cvsargs`` will be passed through as
+ keyword arguments to ``cvs.reader()``.
+ """
+ self.csvargs = csvargs
+
+ def __iter__(self):
+ input = self.input
+ if isinstance(input, ifile):
+ input = input.open("rb")
+ reader = csv.reader(input, **self.csvargs)
+ for line in reader:
+ yield List(line)
+
+ def __xrepr__(self, mode="default"):
+ yield (-1, False)
+ if mode == "header" or mode == "footer":
+ input = getattr(self, "input", None)
+ if input is not None:
+ for part in xrepr(input, mode):
+ yield part
+ yield (astyle.style_default, " | ")
+ yield (astyle.style_default, "%s(" % self.__class__.__name__)
+ for (i, (name, value)) in enumerate(self.csvargs.iteritems()):
+ if i:
+ yield (astyle.style_default, ", ")
+ yield (astyle.style_default, name)
+ yield (astyle.style_default, "=")
+ for part in xrepr(value, "default"):
+ yield part
+ yield (astyle.style_default, ")")
+ else:
+ yield (astyle.style_default, repr(self))
+
+ def __repr__(self):
+ args = ", ".join(["%s=%r" % item for item in self.csvargs.iteritems()])
+ return "<%s.%s %s at 0x%x>" % \
+ (self.__class__.__module__, self.__class__.__name__, args, id(self))
+
+
+class ix(Table):
+ """
+ Execute a system command and list its output as lines
+ (similar to ``os.popen()``).
+
+ Examples::
+
+ >>> ix("ps x")
+ IPython.Extensions.ipipe.ix('ps x')
+
+ >>> ix("find .") | ifile
+ <IPython.Extensions.ipipe.ieval expr=<class 'IPython.Extensions.ipipe.ifile'> at 0x8509d2c>
+ # random
+ """
+ def __init__(self, cmd):
+ self.cmd = cmd
+ self._pipeout = None
+
+ def __iter__(self):
+ (_pipein, self._pipeout) = os.popen4(self.cmd)
+ _pipein.close()
+ for l in self._pipeout:
+ yield l.rstrip("\r\n")
+ self._pipeout.close()
+ self._pipeout = None
+
+ def __del__(self):
+ if self._pipeout is not None and not self._pipeout.closed:
+ self._pipeout.close()
+ self._pipeout = None
+
+ def __xrepr__(self, mode="default"):
+ if mode == "header" or mode == "footer":
+ yield (astyle.style_default,
+ "%s(%r)" % (self.__class__.__name__, self.cmd))
+ else:
+ yield (astyle.style_default, repr(self))
+
+ def __repr__(self):
+ return "%s.%s(%r)" % \
+ (self.__class__.__module__, self.__class__.__name__, self.cmd)
+
+
+class ifilter(Pipe):
+ """
+ Filter an input pipe. Only objects where an expression evaluates to true
+ (and doesn't raise an exception) are listed.
+
+ Examples::
+
+ >>> ils | ifilter("_.isfile() and size>1000")
+ >>> igrp | ifilter("len(mem)")
+ >>> sys.modules | ifilter(lambda _:_.value is not None)
+ # all-random
+ """
+
+ def __init__(self, expr, globals=None, errors="raiseifallfail"):
+ """
+ Create an ``ifilter`` object. ``expr`` can be a callable or a string
+ containing an expression. ``globals`` will be used as the global
+ namespace for calling string expressions (defaulting to IPython's
+ user namespace). ``errors`` specifies how exception during evaluation
+ of ``expr`` are handled:
+
+ ``"drop"``
+ drop all items that have errors;
+
+ ``"keep"``
+ keep all items that have errors;
+
+ ``"keeperror"``
+ keep the exception of all items that have errors;
+
+ ``"raise"``
+ raise the exception;
+
+ ``"raiseifallfail"``
+ raise the first exception if all items have errors; otherwise drop
+ those with errors (this is the default).
+ """
+ self.expr = expr
+ self.globals = globals
+ self.errors = errors
+
+ def __iter__(self):
+ if callable(self.expr):
+ test = self.expr
+ else:
+ g = getglobals(self.globals)
+ expr = compile(self.expr, "ipipe-expression", "eval")
+ def test(item):
+ return eval(expr, g, AttrNamespace(item))
+
+ ok = 0
+ exc_info = None
+ for item in xiter(self.input):
+ try:
+ if test(item):
+ yield item
+ ok += 1
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except Exception, exc:
+ if self.errors == "drop":
+ pass # Ignore errors
+ elif self.errors == "keep":
+ yield item
+ elif self.errors == "keeperror":
+ yield exc
+ elif self.errors == "raise":
+ raise
+ elif self.errors == "raiseifallfail":
+ if exc_info is None:
+ exc_info = sys.exc_info()
+ if not ok and exc_info is not None:
+ raise exc_info[0], exc_info[1], exc_info[2]
+
+ def __xrepr__(self, mode="default"):
+ if mode == "header" or mode == "footer":
+ input = getattr(self, "input", None)
+ if input is not None:
+ for part in xrepr(input, mode):
+ yield part
+ yield (astyle.style_default, " | ")
+ yield (astyle.style_default, "%s(" % self.__class__.__name__)
+ for part in xrepr(self.expr, "default"):
+ yield part
+ yield (astyle.style_default, ")")
+ else:
+ yield (astyle.style_default, repr(self))
+
+ def __repr__(self):
+ return "<%s.%s expr=%r at 0x%x>" % \
+ (self.__class__.__module__, self.__class__.__name__,
+ self.expr, id(self))
+
+
+class ieval(Pipe):
+ """
+ Evaluate an expression for each object in the input pipe.
+
+ Examples::
+
+ >>> ils | ieval("_.abspath()")
+ # random
+ >>> sys.path | ieval(ifile)
+ # random
+ """
+
+ def __init__(self, expr, globals=None, errors="raiseifallfail"):
+ """
+ Create an ``ieval`` object. ``expr`` can be a callable or a string
+ containing an expression. For the meaning of ``globals`` and
+ ``errors`` see ``ifilter``.
+ """
+ self.expr = expr
+ self.globals = globals
+ self.errors = errors
+
+ def __iter__(self):
+ if callable(self.expr):
+ do = self.expr
+ else:
+ g = getglobals(self.globals)
+ expr = compile(self.expr, "ipipe-expression", "eval")
+ def do(item):
+ return eval(expr, g, AttrNamespace(item))
+
+ ok = 0
+ exc_info = None
+ for item in xiter(self.input):
+ try:
+ yield do(item)
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except Exception, exc:
+ if self.errors == "drop":
+ pass # Ignore errors
+ elif self.errors == "keep":
+ yield item
+ elif self.errors == "keeperror":
+ yield exc
+ elif self.errors == "raise":
+ raise
+ elif self.errors == "raiseifallfail":
+ if exc_info is None:
+ exc_info = sys.exc_info()
+ if not ok and exc_info is not None:
+ raise exc_info[0], exc_info[1], exc_info[2]
+
+ def __xrepr__(self, mode="default"):
+ if mode == "header" or mode == "footer":
+ input = getattr(self, "input", None)
+ if input is not None:
+ for part in xrepr(input, mode):
+ yield part
+ yield (astyle.style_default, " | ")
+ yield (astyle.style_default, "%s(" % self.__class__.__name__)
+ for part in xrepr(self.expr, "default"):
+ yield part
+ yield (astyle.style_default, ")")
+ else:
+ yield (astyle.style_default, repr(self))
+
+ def __repr__(self):
+ return "<%s.%s expr=%r at 0x%x>" % \
+ (self.__class__.__module__, self.__class__.__name__,
+ self.expr, id(self))
+
+
+class ienum(Pipe):
+ """
+ Enumerate the input pipe (i.e. wrap each input object in an object
+ with ``index`` and ``object`` attributes).
+
+ Examples::
+
+ >>> xrange(20) | ieval("_,_*_") | ienum | ifilter("index % 2 == 0") | ieval("object")
+ """
+ skip_doctest = True
+
+ def __iter__(self):
+ fields = ("index", "object")
+ for (index, object) in enumerate(xiter(self.input)):
+ yield Fields(fields, index=index, object=object)
+
+
+class isort(Pipe):
+ """
+ Sorts the input pipe.
+
+ Examples::
+
+ >>> ils | isort("size")
+ <IPython.Extensions.ipipe.isort key='size' reverse=False at 0x849ec2c>
+ >>> ils | isort("_.isdir(), _.lower()", reverse=True)
+ <IPython.Extensions.ipipe.isort key='_.isdir(), _.lower()' reverse=True at 0x849eacc>
+ # all-random
+ """
+
+ def __init__(self, key=None, globals=None, reverse=False):
+ """
+ Create an ``isort`` object. ``key`` can be a callable or a string
+ containing an expression (or ``None`` in which case the items
+ themselves will be sorted). If ``reverse`` is true the sort order
+ will be reversed. For the meaning of ``globals`` see ``ifilter``.
+ """
+ self.key = key
+ self.globals = globals
+ self.reverse = reverse
+
+ def __iter__(self):
+ if self.key is None:
+ items = sorted(xiter(self.input), reverse=self.reverse)
+ elif callable(self.key):
+ items = sorted(xiter(self.input), key=self.key, reverse=self.reverse)
+ else:
+ g = getglobals(self.globals)
+ key = compile(self.key, "ipipe-expression", "eval")
+ def realkey(item):
+ return eval(key, g, AttrNamespace(item))
+ items = sorted(xiter(self.input), key=realkey, reverse=self.reverse)
+ for item in items:
+ yield item
+
+ def __xrepr__(self, mode="default"):
+ if mode == "header" or mode == "footer":
+ input = getattr(self, "input", None)
+ if input is not None:
+ for part in xrepr(input, mode):
+ yield part
+ yield (astyle.style_default, " | ")
+ yield (astyle.style_default, "%s(" % self.__class__.__name__)
+ for part in xrepr(self.key, "default"):
+ yield part
+ if self.reverse:
+ yield (astyle.style_default, ", ")
+ for part in xrepr(True, "default"):
+ yield part
+ yield (astyle.style_default, ")")
+ else:
+ yield (astyle.style_default, repr(self))
+
+ def __repr__(self):
+ return "<%s.%s key=%r reverse=%r at 0x%x>" % \
+ (self.__class__.__module__, self.__class__.__name__,
+ self.key, self.reverse, id(self))
+
+
+tab = 3 # for expandtabs()
+
+def _format(field):
+ if isinstance(field, str):
+ text = repr(field.expandtabs(tab))[1:-1]
+ elif isinstance(field, unicode):
+ text = repr(field.expandtabs(tab))[2:-1]
+ elif isinstance(field, datetime.datetime):
+ # Don't use strftime() here, as this requires year >= 1900
+ text = "%04d-%02d-%02d %02d:%02d:%02d.%06d" % \
+ (field.year, field.month, field.day,
+ field.hour, field.minute, field.second, field.microsecond)
+ elif isinstance(field, datetime.date):
+ text = "%04d-%02d-%02d" % (field.year, field.month, field.day)
+ else:
+ text = repr(field)
+ return text
+
+
+class Display(object):
+ class __metaclass__(type):
+ def __ror__(self, input):
+ return input | self()
+
+ def __init__(self, input=None):
+ self.input = input
+
+ def __ror__(self, input):
+ self.input = input
+ return self
+
+ def display(self):
+ pass
+
+
+class iless(Display):
+ cmd = "less --quit-if-one-screen --LONG-PROMPT --LINE-NUMBERS --chop-long-lines --shift=8 --RAW-CONTROL-CHARS"
+
+ def display(self):
+ try:
+ pager = os.popen(self.cmd, "w")
+ try:
+ for item in xiter(self.input):
+ first = False
+ for attr in xattrs(item, "default"):
+ if first:
+ first = False
+ else:
+ pager.write(" ")
+ attr = upgradexattr(attr)
+ if not isinstance(attr, SelfDescriptor):
+ pager.write(attr.name())
+ pager.write("=")
+ pager.write(str(attr.value(item)))
+ pager.write("\n")
+ finally:
+ pager.close()
+ except Exception, exc:
+ print "%s: %s" % (exc.__class__.__name__, str(exc))
+
+
+class _RedirectIO(object):
+ def __init__(self,*args,**kwargs):
+ """
+ Map the system output streams to self.
+ """
+ self.stream = StringIO.StringIO()
+ self.stdout = sys.stdout
+ sys.stdout = self
+ self.stderr = sys.stderr
+ sys.stderr = self
+
+ def write(self, text):
+ """
+ Write both to screen and to self.
+ """
+ self.stream.write(text)
+ self.stdout.write(text)
+ if "\n" in text:
+ self.stdout.flush()
+
+ def writelines(self, lines):
+ """
+ Write lines both to screen and to self.
+ """
+ self.stream.writelines(lines)
+ self.stdout.writelines(lines)
+ self.stdout.flush()
+
+ def restore(self):
+ """
+ Restore the default system streams.
+ """
+ self.stdout.flush()
+ self.stderr.flush()
+ sys.stdout = self.stdout
+ sys.stderr = self.stderr
+
+
+class icap(Table):
+ """
+ Execute a python string and capture any output to stderr/stdout.
+
+ Examples::
+
+ >>> import time
+ >>> icap("for i in range(10): print i, time.sleep(0.1)")
+
+ """
+ skip_doctest = True
+
+ def __init__(self, expr, globals=None):
+ self.expr = expr
+ self.globals = globals
+ log = _RedirectIO()
+ try:
+ exec(expr, getglobals(globals))
+ finally:
+ log.restore()
+ self.stream = log.stream
+
+ def __iter__(self):
+ self.stream.seek(0)
+ for line in self.stream:
+ yield line.rstrip("\r\n")
+
+ def __xrepr__(self, mode="default"):
+ if mode == "header" or mode == "footer":
+ yield (astyle.style_default,
+ "%s(%r)" % (self.__class__.__name__, self.expr))
+ else:
+ yield (astyle.style_default, repr(self))
+
+ def __repr__(self):
+ return "%s.%s(%r)" % \
+ (self.__class__.__module__, self.__class__.__name__, self.expr)
+
+
+def xformat(value, mode, maxlength):
+ align = None
+ full = True
+ width = 0
+ text = astyle.Text()
+ for (style, part) in xrepr(value, mode):
+ # only consider the first result
+ if align is None:
+ if isinstance(style, int):
+ # (style, text) really is (alignment, stop)
+ align = style
+ full = part
+ continue
+ else:
+ align = -1
+ full = True
+ if not isinstance(style, int):
+ text.append((style, part))
+ width += len(part)
+ if width >= maxlength and not full:
+ text.append((astyle.style_ellisis, "..."))
+ width += 3
+ break
+ if align is None: # default to left alignment
+ align = -1
+ return (align, width, text)
+
+
+
+import astyle
+
+class idump(Display):
+ # The approximate maximum length of a column entry
+ maxattrlength = 200
+
+ # Style for column names
+ style_header = astyle.Style.fromstr("white:black:bold")
+
+ def __init__(self, input=None, *attrs):
+ Display.__init__(self, input)
+ self.attrs = [upgradexattr(attr) for attr in attrs]
+ self.headerpadchar = " "
+ self.headersepchar = "|"
+ self.datapadchar = " "
+ self.datasepchar = "|"
+
+ def display(self):
+ stream = genutils.Term.cout
+ allattrs = []
+ attrset = set()
+ colwidths = {}
+ rows = []
+ for item in xiter(self.input):
+ row = {}
+ attrs = self.attrs
+ if not attrs:
+ attrs = xattrs(item, "default")
+ for attr in attrs:
+ if attr not in attrset:
+ allattrs.append(attr)
+ attrset.add(attr)
+ colwidths[attr] = len(attr.name())
+ try:
+ value = attr.value(item)
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except Exception, exc:
+ value = exc
+ (align, width, text) = xformat(value, "cell", self.maxattrlength)
+ colwidths[attr] = max(colwidths[attr], width)
+ # remember alignment, length and colored parts
+ row[attr] = (align, width, text)
+ rows.append(row)
+
+ stream.write("\n")
+ for (i, attr) in enumerate(allattrs):
+ attrname = attr.name()
+ self.style_header(attrname).write(stream)
+ spc = colwidths[attr] - len(attrname)
+ if i < len(colwidths)-1:
+ stream.write(self.headerpadchar*spc)
+ stream.write(self.headersepchar)
+ stream.write("\n")
+
+ for row in rows:
+ for (i, attr) in enumerate(allattrs):
+ (align, width, text) = row[attr]
+ spc = colwidths[attr] - width
+ if align == -1:
+ text.write(stream)
+ if i < len(colwidths)-1:
+ stream.write(self.datapadchar*spc)
+ elif align == 0:
+ spc = colwidths[attr] - width
+ spc1 = spc//2
+ spc2 = spc-spc1
+ stream.write(self.datapadchar*spc1)
+ text.write(stream)
+ if i < len(colwidths)-1:
+ stream.write(self.datapadchar*spc2)
+ else:
+ stream.write(self.datapadchar*spc)
+ text.write(stream)
+ if i < len(colwidths)-1:
+ stream.write(self.datasepchar)
+ stream.write("\n")
+
+
+class AttributeDetail(Table):
+ """
+ ``AttributeDetail`` objects are use for displaying a detailed list of object
+ attributes.
+ """
+ def __init__(self, object, descriptor):
+ self.object = object
+ self.descriptor = descriptor
+
+ def __iter__(self):
+ return self.descriptor.iter(self.object)
+
+ def name(self):
+ return self.descriptor.name()
+
+ def attrtype(self):
+ return self.descriptor.attrtype(self.object)
+
+ def valuetype(self):
+ return self.descriptor.valuetype(self.object)
+
+ def doc(self):
+ return self.descriptor.doc(self.object)
+
+ def shortdoc(self):
+ return self.descriptor.shortdoc(self.object)
+
+ def value(self):
+ return self.descriptor.value(self.object)
+
+ def __xattrs__(self, mode="default"):
+ attrs = ("name()", "attrtype()", "valuetype()", "value()", "shortdoc()")
+ if mode == "detail":
+ attrs += ("doc()",)
+ return attrs
+
+ def __xrepr__(self, mode="default"):
+ yield (-1, True)
+ valuetype = self.valuetype()
+ if valuetype is not noitem:
+ for part in xrepr(valuetype):
+ yield part
+ yield (astyle.style_default, " ")
+ yield (astyle.style_default, self.attrtype())
+ yield (astyle.style_default, " ")
+ yield (astyle.style_default, self.name())
+ yield (astyle.style_default, " of ")
+ for part in xrepr(self.object):
+ yield part
+
+
+try:
+ from ibrowse import ibrowse
+except ImportError:
+ # No curses (probably Windows) => try igrid
+ try:
+ from igrid import igrid
+ except ImportError:
+ # no wx either => use ``idump`` as the default display.
+ defaultdisplay = idump
+ else:
+ defaultdisplay = igrid
+ __all__.append("igrid")
+else:
+ defaultdisplay = ibrowse
+ __all__.append("ibrowse")
+
+
+# If we're running under IPython, register our objects with IPython's
+# generic function ``result_display``, else install a displayhook
+# directly as sys.displayhook
+if generics is not None:
+ def display_display(obj):
+ return obj.display()
+ generics.result_display.when_type(Display)(display_display)
+
+ def display_tableobject(obj):
+ return display_display(defaultdisplay(obj))
+ generics.result_display.when_type(Table)(display_tableobject)
+
+ def display_tableclass(obj):
+ return display_tableobject(obj())
+ generics.result_display.when_type(Table.__metaclass__)(display_tableclass)
+else:
+ def installdisplayhook():
+ _originalhook = sys.displayhook
+ def displayhook(obj):
+ if isinstance(obj, type) and issubclass(obj, Table):
+ obj = obj()
+ if isinstance(obj, Table):
+ obj = defaultdisplay(obj)
+ if isinstance(obj, Display):
+ return obj.display()
+ else:
+ _originalhook(obj)
+ sys.displayhook = displayhook
+ installdisplayhook()
diff --git a/IPython/Extensions/ipy_app_completers.py b/IPython/Extensions/ipy_app_completers.py
new file mode 100644
index 0000000..629ef79
--- /dev/null
+++ b/IPython/Extensions/ipy_app_completers.py
@@ -0,0 +1,19 @@
+""" Install various IPython completers
+
+IPython extension that installs the completers related to external apps.
+
+The actual implementations are in Extensions/ipy_completers.py
+
+"""
+import IPython.ipapi
+
+ip = IPython.ipapi.get()
+
+from ipy_completers import *
+
+ip.set_hook('complete_command', apt_completer, re_key = '.*apt-get')
+ip.set_hook('complete_command', svn_completer, str_key = 'svn')
+ip.set_hook('complete_command', hg_completer, str_key = 'hg')
+
+# the old bzr completer is deprecated, we recommend ipy_bzr
+#ip.set_hook('complete_command', bzr_completer, str_key = 'bzr')
diff --git a/IPython/Extensions/ipy_autoreload.py b/IPython/Extensions/ipy_autoreload.py
new file mode 100644
index 0000000..230f575
--- /dev/null
+++ b/IPython/Extensions/ipy_autoreload.py
@@ -0,0 +1,349 @@
+"""
+IPython extension: autoreload modules before executing the next line
+
+Try::
+
+ %autoreload?
+
+for documentation.
+"""
+
+# Pauli Virtanen <pav@iki.fi>, 2008.
+# Thomas Heller, 2000.
+#
+# This IPython module is written by Pauli Virtanen, based on the autoreload
+# code by Thomas Heller.
+
+#------------------------------------------------------------------------------
+# Autoreload functionality
+#------------------------------------------------------------------------------
+
+import time, os, threading, sys, types, imp, inspect, traceback, atexit
+import weakref
+
+def _get_compiled_ext():
+ """Official way to get the extension of compiled files (.pyc or .pyo)"""
+ for ext, mode, typ in imp.get_suffixes():
+ if typ == imp.PY_COMPILED:
+ return ext
+
+PY_COMPILED_EXT = _get_compiled_ext()
+
+class ModuleReloader(object):
+ failed = {}
+ """Modules that failed to reload: {module: mtime-on-failed-reload, ...}"""
+
+ modules = {}
+ """Modules specially marked as autoreloadable."""
+
+ skip_modules = {}
+ """Modules specially marked as not autoreloadable."""
+
+ check_all = True
+ """Autoreload all modules, not just those listed in 'modules'"""
+
+ old_objects = {}
+ """(module-name, name) -> weakref, for replacing old code objects"""
+
+ def check(self, check_all=False):
+ """Check whether some modules need to be reloaded."""
+
+ if check_all or self.check_all:
+ modules = sys.modules.keys()
+ else:
+ modules = self.modules.keys()
+
+ for modname in modules:
+ m = sys.modules.get(modname, None)
+
+ if modname in self.skip_modules:
+ continue
+
+ if not hasattr(m, '__file__'):
+ continue
+
+ if m.__name__ == '__main__':
+ # we cannot reload(__main__)
+ continue
+
+ filename = m.__file__
+ dirname = os.path.dirname(filename)
+ path, ext = os.path.splitext(filename)
+
+ if ext.lower() == '.py':
+ ext = PY_COMPILED_EXT
+ filename = os.path.join(dirname, path + PY_COMPILED_EXT)
+
+ if ext != PY_COMPILED_EXT:
+ continue
+
+ try:
+ pymtime = os.stat(filename[:-1]).st_mtime
+ if pymtime <= os.stat(filename).st_mtime:
+ continue
+ if self.failed.get(filename[:-1], None) == pymtime:
+ continue
+ except OSError:
+ continue
+
+ try:
+ superreload(m, reload, self.old_objects)
+ if filename[:-1] in self.failed:
+ del self.failed[filename[:-1]]
+ except:
+ print >> sys.stderr, "[autoreload of %s failed: %s]" % (
+ modname, traceback.format_exc(1))
+ self.failed[filename[:-1]] = pymtime
+
+#------------------------------------------------------------------------------
+# superreload
+#------------------------------------------------------------------------------
+
+def update_function(old, new):
+ """Upgrade the code object of a function"""
+ for name in ['func_code', 'func_defaults', 'func_doc',
+ 'func_closure', 'func_globals', 'func_dict']:
+ try:
+ setattr(old, name, getattr(new, name))
+ except (AttributeError, TypeError):
+ pass
+
+def update_class(old, new):
+ """Replace stuff in the __dict__ of a class, and upgrade
+ method code objects"""
+ for key in old.__dict__.keys():
+ old_obj = getattr(old, key)
+
+ try:
+ new_obj = getattr(new, key)
+ except AttributeError:
+ # obsolete attribute: remove it
+ try:
+ delattr(old, key)
+ except (AttributeError, TypeError):
+ pass
+ continue
+
+ if update_generic(old_obj, new_obj): continue
+
+ try:
+ setattr(old, key, getattr(new, key))
+ except (AttributeError, TypeError):
+ pass # skip non-writable attributes
+
+def update_property(old, new):
+ """Replace get/set/del functions of a property"""
+ update_generic(old.fdel, new.fdel)
+ update_generic(old.fget, new.fget)
+ update_generic(old.fset, new.fset)
+
+def isinstance2(a, b, typ):
+ return isinstance(a, typ) and isinstance(b, typ)
+
+UPDATE_RULES = [
+ (lambda a, b: isinstance2(a, b, types.ClassType),
+ update_class),
+ (lambda a, b: isinstance2(a, b, types.TypeType),
+ update_class),
+ (lambda a, b: isinstance2(a, b, types.FunctionType),
+ update_function),
+ (lambda a, b: isinstance2(a, b, property),
+ update_property),
+ (lambda a, b: isinstance2(a, b, types.MethodType),
+ lambda a, b: update_function(a.im_func, b.im_func)),
+]
+
+def update_generic(a, b):
+ for type_check, update in UPDATE_RULES:
+ if type_check(a, b):
+ update(a, b)
+ return True
+ return False
+
+class StrongRef(object):
+ def __init__(self, obj):
+ self.obj = obj
+ def __call__(self):
+ return self.obj
+
+def superreload(module, reload=reload, old_objects={}):
+ """Enhanced version of the builtin reload function.
+
+ superreload remembers objects previously in the module, and
+
+ - upgrades the class dictionary of every old class in the module
+ - upgrades the code object of every old function and method
+ - clears the module's namespace before reloading
+
+ """
+
+ # collect old objects in the module
+ for name, obj in module.__dict__.items():
+ if not hasattr(obj, '__module__') or obj.__module__ != module.__name__:
+ continue
+ key = (module.__name__, name)
+ try:
+ old_objects.setdefault(key, []).append(weakref.ref(obj))
+ except TypeError:
+ # weakref doesn't work for all types;
+ # create strong references for 'important' cases
+ if isinstance(obj, types.ClassType):
+ old_objects.setdefault(key, []).append(StrongRef(obj))
+
+ # reload module
+ try:
+ # clear namespace first from old cruft
+ old_name = module.__name__
+ module.__dict__.clear()
+ module.__dict__['__name__'] = old_name
+ except (TypeError, AttributeError, KeyError):
+ pass
+ module = reload(module)
+
+ # iterate over all objects and update functions & classes
+ for name, new_obj in module.__dict__.items():
+ key = (module.__name__, name)
+ if key not in old_objects: continue
+
+ new_refs = []
+ for old_ref in old_objects[key]:
+ old_obj = old_ref()
+ if old_obj is None: continue
+ new_refs.append(old_ref)
+ update_generic(old_obj, new_obj)
+
+ if new_refs:
+ old_objects[key] = new_refs
+ else:
+ del old_objects[key]
+
+ return module
+
+reloader = ModuleReloader()
+
+#------------------------------------------------------------------------------
+# IPython connectivity
+#------------------------------------------------------------------------------
+import IPython.ipapi
+
+ip = IPython.ipapi.get()
+
+autoreload_enabled = False
+
+def runcode_hook(self):
+ if not autoreload_enabled:
+ raise IPython.ipapi.TryNext
+ try:
+ reloader.check()
+ except:
+ pass
+
+def enable_autoreload():
+ global autoreload_enabled
+ autoreload_enabled = True
+
+def disable_autoreload():
+ global autoreload_enabled
+ autoreload_enabled = False
+
+def autoreload_f(self, parameter_s=''):
+ r""" %autoreload => Reload modules automatically
+
+ %autoreload
+ Reload all modules (except those excluded by %aimport) automatically now.
+
+ %autoreload 0
+ Disable automatic reloading.
+
+ %autoreload 1
+ Reload all modules imported with %aimport every time before executing
+ the Python code typed.
+
+ %autoreload 2
+ Reload all modules (except those excluded by %aimport) every time
+ before executing the Python code typed.
+
+ Reloading Python modules in a reliable way is in general
+ difficult, and unexpected things may occur. %autoreload tries to
+ work around common pitfalls by replacing function code objects and
+ parts of classes previously in the module with new versions. This
+ makes the following things to work:
+
+ - Functions and classes imported via 'from xxx import foo' are upgraded
+ to new versions when 'xxx' is reloaded.
+
+ - Methods and properties of classes are upgraded on reload, so that
+ calling 'c.foo()' on an object 'c' created before the reload causes
+ the new code for 'foo' to be executed.
+
+ Some of the known remaining caveats are:
+
+ - Replacing code objects does not always succeed: changing a @property
+ in a class to an ordinary method or a method to a member variable
+ can cause problems (but in old objects only).
+
+ - Functions that are removed (eg. via monkey-patching) from a module
+ before it is reloaded are not upgraded.
+
+ - C extension modules cannot be reloaded, and so cannot be
+ autoreloaded.
+
+ """
+ if parameter_s == '':
+ reloader.check(True)
+ elif parameter_s == '0':
+ disable_autoreload()
+ elif parameter_s == '1':
+ reloader.check_all = False
+ enable_autoreload()
+ elif parameter_s == '2':
+ reloader.check_all = True
+ enable_autoreload()
+
+def aimport_f(self, parameter_s=''):
+ """%aimport => Import modules for automatic reloading.
+
+ %aimport
+ List modules to automatically import and not to import.
+
+ %aimport foo
+ Import module 'foo' and mark it to be autoreloaded for %autoreload 1
+
+ %aimport -foo
+ Mark module 'foo' to not be autoreloaded for %autoreload 1
+
+ """
+
+ modname = parameter_s
+ if not modname:
+ to_reload = reloader.modules.keys()
+ to_reload.sort()
+ to_skip = reloader.skip_modules.keys()
+ to_skip.sort()
+ if reloader.check_all:
+ print "Modules to reload:\nall-expect-skipped"
+ else:
+ print "Modules to reload:\n%s" % ' '.join(to_reload)
+ print "\nModules to skip:\n%s" % ' '.join(to_skip)
+ elif modname.startswith('-'):
+ modname = modname[1:]
+ try: del reloader.modules[modname]
+ except KeyError: pass
+ reloader.skip_modules[modname] = True
+ else:
+ try: del reloader.skip_modules[modname]
+ except KeyError: pass
+ reloader.modules[modname] = True
+
+ # Inject module to user namespace; handle also submodules properly
+ __import__(modname)
+ basename = modname.split('.')[0]
+ mod = sys.modules[basename]
+ ip.to_user_ns({basename: mod})
+
+def init():
+ ip.expose_magic('autoreload', autoreload_f)
+ ip.expose_magic('aimport', aimport_f)
+ ip.set_hook('pre_runcode_hook', runcode_hook)
+
+init()
diff --git a/IPython/Extensions/ipy_bzr.py b/IPython/Extensions/ipy_bzr.py
new file mode 100644
index 0000000..873a84f
--- /dev/null
+++ b/IPython/Extensions/ipy_bzr.py
@@ -0,0 +1,343 @@
+""" Extension for bzr command tab completer. Supports comlpeting commands and options
+
+Unlike the core IPython, you should note that this extension is under GPL, not BSD.
+
+Based on "shell" bzr plugin by Aaron Bentley, license is below. The IPython additions
+are at the bottom of the file, the rest is left untouched.
+
+Must be loaded with ip.load('ipy_bzr')
+
+"""
+
+# Copyright (C) 2004, 2005 Aaron Bentley
+# <aaron@aaronbentley.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+import cmd
+from itertools import chain
+import os
+import shlex
+import stat
+import string
+import sys
+
+from bzrlib import osutils
+from bzrlib.branch import Branch
+from bzrlib.config import config_dir, ensure_config_dir_exists
+from bzrlib.commands import get_cmd_object, get_all_cmds, get_alias
+from bzrlib.errors import BzrError
+from bzrlib.workingtree import WorkingTree
+import bzrlib.plugin
+
+
+SHELL_BLACKLIST = set(['rm', 'ls'])
+COMPLETION_BLACKLIST = set(['shell'])
+
+
+class BlackListedCommand(BzrError):
+ def __init__(self, command):
+ BzrError.__init__(self, "The command %s is blacklisted for shell use" %
+ command)
+
+
+class CompletionContext(object):
+ def __init__(self, text, command=None, prev_opt=None, arg_pos=None):
+ self.text = text
+ self.command = command
+ self.prev_opt = prev_opt
+ self.arg_pos = None
+
+ def get_completions(self):
+ try:
+ return self.get_completions_or_raise()
+ except Exception, e:
+ print e, type(e)
+ return []
+
+ def get_option_completions(self):
+ try:
+ command_obj = get_cmd_object(self.command)
+ except BzrError:
+ return []
+ opts = [o+" " for o in iter_opt_completions(command_obj)]
+ return list(filter_completions(opts, self.text))
+
+ def get_completions_or_raise(self):
+ if self.command is None:
+ if '/' in self.text:
+ iter = iter_executables(self.text)
+ else:
+ iter = (c+" " for c in iter_command_names() if
+ c not in COMPLETION_BLACKLIST)
+ return list(filter_completions(iter, self.text))
+ if self.prev_opt is None:
+ completions = self.get_option_completions()
+ if self.command == "cd":
+ iter = iter_dir_completions(self.text)
+ completions.extend(list(filter_completions(iter, self.text)))
+ else:
+ iter = iter_file_completions(self.text)
+ completions.extend(filter_completions(iter, self.text))
+ return completions
+
+
+class PromptCmd(cmd.Cmd):
+
+ def __init__(self):
+ cmd.Cmd.__init__(self)
+ self.prompt = "bzr> "
+ try:
+ self.tree = WorkingTree.open_containing('.')[0]
+ except:
+ self.tree = None
+ self.set_title()
+ self.set_prompt()
+ self.identchars += '-'
+ ensure_config_dir_exists()
+ self.history_file = osutils.pathjoin(config_dir(), 'shell-history')
+ readline.set_completer_delims(string.whitespace)
+ if os.access(self.history_file, os.R_OK) and \
+ os.path.isfile(self.history_file):
+ readline.read_history_file(self.history_file)
+ self.cwd = os.getcwd()
+
+ def write_history(self):
+ readline.write_history_file(self.history_file)
+
+ def do_quit(self, args):
+ self.write_history()
+ raise StopIteration
+
+ def do_exit(self, args):
+ self.do_quit(args)
+
+ def do_EOF(self, args):
+ print
+ self.do_quit(args)
+
+ def postcmd(self, line, bar):
+ self.set_title()
+ self.set_prompt()
+
+ def set_prompt(self):
+ if self.tree is not None:
+ try:
+ prompt_data = (self.tree.branch.nick, self.tree.branch.revno(),
+ self.tree.relpath('.'))
+ prompt = " %s:%d/%s" % prompt_data
+ except:
+ prompt = ""
+ else:
+ prompt = ""
+ self.prompt = "bzr%s> " % prompt
+
+ def set_title(self, command=None):
+ try:
+ b = Branch.open_containing('.')[0]
+ version = "%s:%d" % (b.nick, b.revno())
+ except:
+ version = "[no version]"
+ if command is None:
+ command = ""
+ sys.stdout.write(terminal.term_title("bzr %s %s" % (command, version)))
+
+ def do_cd(self, line):
+ if line == "":
+ line = "~"
+ line = os.path.expanduser(line)
+ if os.path.isabs(line):
+ newcwd = line
+ else:
+ newcwd = self.cwd+'/'+line
+ newcwd = os.path.normpath(newcwd)
+ try:
+ os.chdir(newcwd)
+ self.cwd = newcwd
+ except Exception, e:
+ print e
+ try:
+ self.tree = WorkingTree.open_containing(".")[0]
+ except:
+ self.tree = None
+
+ def do_help(self, line):
+ self.default("help "+line)
+
+ def default(self, line):
+ args = shlex.split(line)
+ alias_args = get_alias(args[0])
+ if alias_args is not None:
+ args[0] = alias_args.pop(0)
+
+ commandname = args.pop(0)
+ for char in ('|', '<', '>'):
+ commandname = commandname.split(char)[0]
+ if commandname[-1] in ('|', '<', '>'):
+ commandname = commandname[:-1]
+ try:
+ if commandname in SHELL_BLACKLIST:
+ raise BlackListedCommand(commandname)
+ cmd_obj = get_cmd_object(commandname)
+ except (BlackListedCommand, BzrError):
+ return os.system(line)
+
+ try:
+ if too_complicated(line):
+ return os.system("bzr "+line)
+ else:
+ return (cmd_obj.run_argv_aliases(args, alias_args) or 0)
+ except BzrError, e:
+ print e
+ except KeyboardInterrupt, e:
+ print "Interrupted"
+ except Exception, e:
+# print "Unhandled error:\n%s" % errors.exception_str(e)
+ print "Unhandled error:\n%s" % (e)
+
+
+ def completenames(self, text, line, begidx, endidx):
+ return CompletionContext(text).get_completions()
+
+ def completedefault(self, text, line, begidx, endidx):
+ """Perform completion for native commands.
+
+ :param text: The text to complete
+ :type text: str
+ :param line: The entire line to complete
+ :type line: str
+ :param begidx: The start of the text in the line
+ :type begidx: int
+ :param endidx: The end of the text in the line
+ :type endidx: int
+ """
+ (cmd, args, foo) = self.parseline(line)
+ if cmd == "bzr":
+ cmd = None
+ return CompletionContext(text, command=cmd).get_completions()
+
+
+def run_shell():
+ try:
+ prompt = PromptCmd()
+ try:
+ prompt.cmdloop()
+ finally:
+ prompt.write_history()
+ except StopIteration:
+ pass
+
+
+def iter_opt_completions(command_obj):
+ for option_name, option in command_obj.options().items():
+ yield "--" + option_name
+ short_name = option.short_name()
+ if short_name:
+ yield "-" + short_name
+
+
+def iter_file_completions(arg, only_dirs = False):
+ """Generate an iterator that iterates through filename completions.
+
+ :param arg: The filename fragment to match
+ :type arg: str
+ :param only_dirs: If true, match only directories
+ :type only_dirs: bool
+ """
+ cwd = os.getcwd()
+ if cwd != "/":
+ extras = [".", ".."]
+ else:
+ extras = []
+ (dir, file) = os.path.split(arg)
+ if dir != "":
+ listingdir = os.path.expanduser(dir)
+ else:
+ listingdir = cwd
+ for file in chain(os.listdir(listingdir), extras):
+ if dir != "":
+ userfile = dir+'/'+file
+ else:
+ userfile = file
+ if userfile.startswith(arg):
+ if os.path.isdir(listingdir+'/'+file):
+ userfile+='/'
+ yield userfile
+ elif not only_dirs:
+ yield userfile + ' '
+
+
+def iter_dir_completions(arg):
+ """Generate an iterator that iterates through directory name completions.
+
+ :param arg: The directory name fragment to match
+ :type arg: str
+ """
+ return iter_file_completions(arg, True)
+
+
+def iter_command_names(hidden=False):
+ for real_cmd_name, cmd_class in get_all_cmds():
+ if not hidden and cmd_class.hidden:
+ continue
+ for name in [real_cmd_name] + cmd_class.aliases:
+ # Don't complete on aliases that are prefixes of the canonical name
+ if name == real_cmd_name or not real_cmd_name.startswith(name):
+ yield name
+
+
+def iter_executables(path):
+ dirname, partial = os.path.split(path)
+ for filename in os.listdir(dirname):
+ if not filename.startswith(partial):
+ continue
+ fullpath = os.path.join(dirname, filename)
+ mode=os.lstat(fullpath)[stat.ST_MODE]
+ if stat.S_ISREG(mode) and 0111 & mode:
+ yield fullpath + ' '
+
+
+def filter_completions(iter, arg):
+ return (c for c in iter if c.startswith(arg))
+
+
+def iter_munged_completions(iter, arg, text):
+ for completion in iter:
+ completion = str(completion)
+ if completion.startswith(arg):
+ yield completion[len(arg)-len(text):]+" "
+
+
+def too_complicated(line):
+ for char in '|<>*?':
+ if char in line:
+ return True
+ return False
+
+
+### IPython mods start
+
+def init_ipython(ip):
+ def bzr_completer(self,ev):
+ #print "bzr complete"
+ tup = ev.line.split(None,2)
+ if len(tup) > 2:
+ cmd = tup[1]
+ else:
+ cmd = None
+
+ return CompletionContext(ev.symbol, command = cmd).get_completions()
+ bzrlib.plugin.load_plugins()
+ ip.set_hook('complete_command', bzr_completer, str_key = 'bzr')
diff --git a/IPython/Extensions/ipy_completers.py b/IPython/Extensions/ipy_completers.py
new file mode 100644
index 0000000..e8c5eb5
--- /dev/null
+++ b/IPython/Extensions/ipy_completers.py
@@ -0,0 +1,400 @@
+
+""" Implementations for various useful completers
+
+See Extensions/ipy_stock_completers.py on examples of how to enable a completer,
+but the basic idea is to do:
+
+ip.set_hook('complete_command', svn_completer, str_key = 'svn')
+
+"""
+import IPython.ipapi
+import glob,os,shlex,sys
+import inspect
+from time import time
+from zipimport import zipimporter
+ip = IPython.ipapi.get()
+
+try:
+ set
+except:
+ from sets import Set as set
+
+TIMEOUT_STORAGE = 3 #Time in seconds after which the rootmodules will be stored
+TIMEOUT_GIVEUP = 20 #Time in seconds after which we give up
+
+def quick_completer(cmd, completions):
+ """ Easily create a trivial completer for a command.
+
+ Takes either a list of completions, or all completions in string
+ (that will be split on whitespace)
+
+ Example::
+
+ [d:\ipython]|1> import ipy_completers
+ [d:\ipython]|2> ipy_completers.quick_completer('foo', ['bar','baz'])
+ [d:\ipython]|3> foo b<TAB>
+ bar baz
+ [d:\ipython]|3> foo ba
+ """
+ if isinstance(completions, basestring):
+
+ completions = completions.split()
+ def do_complete(self,event):
+ return completions
+
+ ip.set_hook('complete_command',do_complete, str_key = cmd)
+
+def getRootModules():
+ """
+ Returns a list containing the names of all the modules available in the
+ folders of the pythonpath.
+ """
+ modules = []
+ if ip.db.has_key('rootmodules'):
+ return ip.db['rootmodules']
+ t = time()
+ store = False
+ for path in sys.path:
+ modules += moduleList(path)
+ if time() - t >= TIMEOUT_STORAGE and not store:
+ store = True
+ print "\nCaching the list of root modules, please wait!"
+ print "(This will only be done once - type '%rehashx' to " + \
+ "reset cache!)"
+ print
+ if time() - t > TIMEOUT_GIVEUP:
+ print "This is taking too long, we give up."
+ print
+ ip.db['rootmodules'] = []
+ return []
+
+ modules += sys.builtin_module_names
+
+ modules = list(set(modules))
+ if '__init__' in modules:
+ modules.remove('__init__')
+ modules = list(set(modules))
+ if store:
+ ip.db['rootmodules'] = modules
+ return modules
+
+def moduleList(path):
+ """
+ Return the list containing the names of the modules available in the given
+ folder.
+ """
+
+ if os.path.isdir(path):
+ folder_list = os.listdir(path)
+ elif path.endswith('.egg'):
+ try:
+ folder_list = [f for f in zipimporter(path)._files]
+ except:
+ folder_list = []
+ else:
+ folder_list = []
+ #folder_list = glob.glob(os.path.join(path,'*'))
+ folder_list = [p for p in folder_list \
+ if os.path.exists(os.path.join(path, p,'__init__.py'))\
+ or p[-3:] in ('.py','.so')\
+ or p[-4:] in ('.pyc','.pyo','.pyd')]
+
+ folder_list = [os.path.basename(p).split('.')[0] for p in folder_list]
+ return folder_list
+
+def moduleCompletion(line):
+ """
+ Returns a list containing the completion possibilities for an import line.
+ The line looks like this :
+ 'import xml.d'
+ 'from xml.dom import'
+ """
+ def tryImport(mod, only_modules=False):
+ def isImportable(module, attr):
+ if only_modules:
+ return inspect.ismodule(getattr(module, attr))
+ else:
+ return not(attr[:2] == '__' and attr[-2:] == '__')
+ try:
+ m = __import__(mod)
+ except:
+ return []
+ mods = mod.split('.')
+ for module in mods[1:]:
+ m = getattr(m,module)
+ if (not hasattr(m, '__file__')) or (not only_modules) or\
+ (hasattr(m, '__file__') and '__init__' in m.__file__):
+ completion_list = [attr for attr in dir(m) if isImportable(m, attr)]
+ completion_list.extend(getattr(m,'__all__',[]))
+ if hasattr(m, '__file__') and '__init__' in m.__file__:
+ completion_list.extend(moduleList(os.path.dirname(m.__file__)))
+ completion_list = list(set(completion_list))
+ if '__init__' in completion_list:
+ completion_list.remove('__init__')
+ return completion_list
+
+ words = line.split(' ')
+ if len(words) == 3 and words[0] == 'from':
+ return ['import ']
+ if len(words) < 3 and (words[0] in ['import','from']) :
+ if len(words) == 1:
+ return getRootModules()
+ mod = words[1].split('.')
+ if len(mod) < 2:
+ return getRootModules()
+ completion_list = tryImport('.'.join(mod[:-1]), True)
+ completion_list = ['.'.join(mod[:-1] + [el]) for el in completion_list]
+ return completion_list
+ if len(words) >= 3 and words[0] == 'from':
+ mod = words[1]
+ return tryImport(mod)
+
+def vcs_completer(commands, event):
+ """ utility to make writing typical version control app completers easier
+
+ VCS command line apps typically have the format:
+
+ [sudo ]PROGNAME [help] [command] file file...
+
+ """
+
+
+ cmd_param = event.line.split()
+ if event.line.endswith(' '):
+ cmd_param.append('')
+
+ if cmd_param[0] == 'sudo':
+ cmd_param = cmd_param[1:]
+
+ if len(cmd_param) == 2 or 'help' in cmd_param:
+ return commands.split()
+
+ return ip.IP.Completer.file_matches(event.symbol)
+
+
+pkg_cache = None
+
+def module_completer(self,event):
+ """ Give completions after user has typed 'import ...' or 'from ...'"""
+
+ # This works in all versions of python. While 2.5 has
+ # pkgutil.walk_packages(), that particular routine is fairly dangerous,
+ # since it imports *EVERYTHING* on sys.path. That is: a) very slow b) full
+ # of possibly problematic side effects.
+ # This search the folders in the sys.path for available modules.
+
+ return moduleCompletion(event.line)
+
+
+svn_commands = """\
+add blame praise annotate ann cat checkout co cleanup commit ci copy
+cp delete del remove rm diff di export help ? h import info list ls
+lock log merge mkdir move mv rename ren propdel pdel pd propedit pedit
+pe propget pget pg proplist plist pl propset pset ps resolved revert
+status stat st switch sw unlock update
+"""
+
+def svn_completer(self,event):
+ return vcs_completer(svn_commands, event)
+
+
+hg_commands = """
+add addremove annotate archive backout branch branches bundle cat
+clone commit copy diff export grep heads help identify import incoming
+init locate log manifest merge outgoing parents paths pull push
+qapplied qclone qcommit qdelete qdiff qfold qguard qheader qimport
+qinit qnew qnext qpop qprev qpush qrefresh qrename qrestore qsave
+qselect qseries qtop qunapplied recover remove rename revert rollback
+root serve showconfig status strip tag tags tip unbundle update verify
+version
+"""
+
+def hg_completer(self,event):
+ """ Completer for mercurial commands """
+
+ return vcs_completer(hg_commands, event)
+
+
+
+__bzr_commands = None
+
+def bzr_commands():
+ global __bzr_commands
+ if __bzr_commands is not None:
+ return __bzr_commands
+ out = os.popen('bzr help commands')
+ __bzr_commands = [l.split()[0] for l in out]
+ return __bzr_commands
+
+def bzr_completer(self,event):
+ """ Completer for bazaar commands """
+ cmd_param = event.line.split()
+ if event.line.endswith(' '):
+ cmd_param.append('')
+
+ if len(cmd_param) > 2:
+ cmd = cmd_param[1]
+ param = cmd_param[-1]
+ output_file = (param == '--output=')
+ if cmd == 'help':
+ return bzr_commands()
+ elif cmd in ['bundle-revisions','conflicts',
+ 'deleted','nick','register-branch',
+ 'serve','unbind','upgrade','version',
+ 'whoami'] and not output_file:
+ return []
+ else:
+ # the rest are probably file names
+ return ip.IP.Completer.file_matches(event.symbol)
+
+ return bzr_commands()
+
+
+def shlex_split(x):
+ """Helper function to split lines into segments."""
+ #shlex.split raise exception if syntax error in sh syntax
+ #for example if no closing " is found. This function keeps dropping
+ #the last character of the line until shlex.split does not raise
+ #exception. Adds end of the line to the result of shlex.split
+ #example: %run "c:/python -> ['%run','"c:/python']
+ endofline=[]
+ while x!="":
+ try:
+ comps=shlex.split(x)
+ if len(endofline)>=1:
+ comps.append("".join(endofline))
+ return comps
+ except ValueError:
+ endofline=[x[-1:]]+endofline
+ x=x[:-1]
+ return ["".join(endofline)]
+
+def runlistpy(self, event):
+ comps = shlex_split(event.line)
+ relpath = (len(comps) > 1 and comps[-1] or '').strip("'\"")
+
+ #print "\nev=",event # dbg
+ #print "rp=",relpath # dbg
+ #print 'comps=',comps # dbg
+
+ lglob = glob.glob
+ isdir = os.path.isdir
+ if relpath.startswith('~'):
+ relpath = os.path.expanduser(relpath)
+ dirs = [f.replace('\\','/') + "/" for f in lglob(relpath+'*')
+ if isdir(f)]
+
+ # Find if the user has already typed the first filename, after which we
+ # should complete on all files, since after the first one other files may
+ # be arguments to the input script.
+ #filter(
+ if filter(lambda f: f.endswith('.py') or f.endswith('.ipy') or
+ f.endswith('.pyw'),comps):
+ pys = [f.replace('\\','/') for f in lglob('*')]
+ else:
+ pys = [f.replace('\\','/')
+ for f in lglob(relpath+'*.py') + lglob(relpath+'*.ipy') +
+ lglob(relpath + '*.pyw')]
+ return dirs + pys
+
+
+greedy_cd_completer = False
+
+def cd_completer(self, event):
+ relpath = event.symbol
+ #print event # dbg
+ if '-b' in event.line:
+ # return only bookmark completions
+ bkms = self.db.get('bookmarks',{})
+ return bkms.keys()
+
+
+ if event.symbol == '-':
+ width_dh = str(len(str(len(ip.user_ns['_dh']) + 1)))
+ # jump in directory history by number
+ fmt = '-%0' + width_dh +'d [%s]'
+ ents = [ fmt % (i,s) for i,s in enumerate(ip.user_ns['_dh'])]
+ if len(ents) > 1:
+ return ents
+ return []
+
+ if event.symbol.startswith('--'):
+ return ["--" + os.path.basename(d) for d in ip.user_ns['_dh']]
+
+ if relpath.startswith('~'):
+ relpath = os.path.expanduser(relpath).replace('\\','/')
+ found = []
+ for d in [f.replace('\\','/') + '/' for f in glob.glob(relpath+'*')
+ if os.path.isdir(f)]:
+ if ' ' in d:
+ # we don't want to deal with any of that, complex code
+ # for this is elsewhere
+ raise IPython.ipapi.TryNext
+ found.append( d )
+
+ if not found:
+ if os.path.isdir(relpath):
+ return [relpath]
+ # if no completions so far, try bookmarks
+ bks = self.db.get('bookmarks',{}).keys()
+ bkmatches = [s for s in bks if s.startswith(event.symbol)]
+ if bkmatches:
+ return bkmatches
+
+ raise IPython.ipapi.TryNext
+
+
+ def single_dir_expand(matches):
+ "Recursively expand match lists containing a single dir."
+
+ if len(matches) == 1 and os.path.isdir(matches[0]):
+ # Takes care of links to directories also. Use '/'
+ # explicitly, even under Windows, so that name completions
+ # don't end up escaped.
+ d = matches[0]
+ if d[-1] in ['/','\\']:
+ d = d[:-1]
+
+ subdirs = [p for p in os.listdir(d) if os.path.isdir( d + '/' + p) and not p.startswith('.')]
+ if subdirs:
+ matches = [ (d + '/' + p) for p in subdirs ]
+ return single_dir_expand(matches)
+ else:
+ return matches
+ else:
+ return matches
+
+ if greedy_cd_completer:
+ return single_dir_expand(found)
+ else:
+ return found
+
+def apt_get_packages(prefix):
+ out = os.popen('apt-cache pkgnames')
+ for p in out:
+ if p.startswith(prefix):
+ yield p.rstrip()
+
+
+apt_commands = """\
+update upgrade install remove purge source build-dep dist-upgrade
+dselect-upgrade clean autoclean check"""
+
+def apt_completer(self, event):
+ """ Completer for apt-get (uses apt-cache internally)
+
+ """
+
+
+ cmd_param = event.line.split()
+ if event.line.endswith(' '):
+ cmd_param.append('')
+
+ if cmd_param[0] == 'sudo':
+ cmd_param = cmd_param[1:]
+
+ if len(cmd_param) == 2 or 'help' in cmd_param:
+ return apt_commands.split()
+
+ return list(apt_get_packages(event.symbol))
+
diff --git a/IPython/Extensions/ipy_constants.py b/IPython/Extensions/ipy_constants.py
new file mode 100644
index 0000000..59883cd
--- /dev/null
+++ b/IPython/Extensions/ipy_constants.py
@@ -0,0 +1,669 @@
+""" Module with physical constants for use with ipython, profile
+"physics".
+
+Definition of Fundamental Physical Constants, CODATA Recommended Values
+
+Source, Peter J. Mohr and Barry N. Taylor,
+CODATA Recommended Values of the Fundamental
+Physical Constants, 1998
+
+Website: physics.nist.gov/constants
+"""
+# License: BSD-like
+# Copyright: Gael Varoquaux (gael.varoquaux@normalesup.org)
+
+# inspired by maxima's physconst.mac by Cliff Yapp
+
+#from math import * # math MUST be imported BEFORE PhysicalQInteractive
+from IPython.Extensions.PhysicalQInteractive import PhysicalQuantityInteractive
+
+# Math constants:
+
+# Pi mathematical constants
+pi = 3.141592653589793238462643383279502884197169399375105820974944592
+
+# Universal Constants
+#-------------------------------------------------------------------------
+
+c = PhysicalQuantityInteractive(299792458 , 'm/s')
+c.__doc__ = """speed of light in vacuum"""
+c.__doc__ = "speed of light in vacuum"
+
+u_0 = PhysicalQuantityInteractive(4*pi*1E-7 , 'N/(A**2)')
+u_0.__doc__ = """magnetic constant"""
+mu_0 = PhysicalQuantityInteractive(4*pi*1E-7 , 'N/(A**2)')
+
+epsilon_0 = PhysicalQuantityInteractive(8.854187817E-12 , 'F/m')
+epsilon_0.__doc__ = """electric constant """
+
+Z_0 = PhysicalQuantityInteractive(376.730313461 , 'ohm')
+Z_0.__doc__ = """characteristic impedance of vacuum """
+
+G = PhysicalQuantityInteractive(6.673E-11 , 'm**3/(kg*s**2)')
+G.__doc__ = """Newtonian constant of gravitation """
+
+
+h = PhysicalQuantityInteractive(6.62606876E-34 , 'J*s')
+h.__doc__ = """Planck constant """
+
+
+h_eV = PhysicalQuantityInteractive(4.13566727E-15 , 'eV*s')
+h_eV.__doc__ = """Planck constant in eVs """
+
+
+h_bar = PhysicalQuantityInteractive(1.054571596E-34 , 'J*s')
+h_bar.__doc__ = """Hbar"""
+
+
+h_bar_eV = PhysicalQuantityInteractive(6.58211889E-16 , 'eV*s')
+h_bar_eV.__doc__ = """Hbar in eV"""
+
+
+P_m = PhysicalQuantityInteractive(2.1767E-8 , 'kg')
+P_m.__doc__ = """Planck mass"""
+
+
+P_l = PhysicalQuantityInteractive(1.6160E-35 , 'm')
+P_l.__doc__ = """Planck length """
+
+
+P_t = PhysicalQuantityInteractive(5.3906E-44 , 's')
+P_t.__doc__ = """Planck time """
+
+# Electromagnetic Constants
+#------------------------------------------------------------------------
+
+_e = PhysicalQuantityInteractive(1.602176462E-19 , 'C')
+_e.__doc__ = """elementary charge"""
+q = _e
+
+
+capitalphi_0 = PhysicalQuantityInteractive(2.067833636E-15 , 'Wb')
+capitalphi_0.__doc__ = """magnetic flux quantum """
+mfq_0 = PhysicalQuantityInteractive(2.067833636E-15 , 'Wb')
+
+
+G_0 = PhysicalQuantityInteractive(7.748091696E-5 , 'S')
+G_0.__doc__ = """conductance quantum """
+
+
+K_J = PhysicalQuantityInteractive(483597.898E9 , 'Hz/V')
+K_J.__doc__ = """Josephson constant"""
+
+
+R_K = PhysicalQuantityInteractive(25812.807572 , 'ohm')
+R_K.__doc__ = """von Klitzing constant"""
+
+
+u_B = PhysicalQuantityInteractive(927.400899E-26 , 'J/T')
+u_B.__doc__ = """Bohr magneton"""
+
+ueVT_B = PhysicalQuantityInteractive(5.788381749E-5 , 'eV/T')
+ueVT_B.__doc__ = """Bohr magneton in eV T-1"""
+
+
+u_N = PhysicalQuantityInteractive(5.05078317E-27 , 'J/T')
+u_N.__doc__ = """nuclear magneton """
+
+ueVT_N = PhysicalQuantityInteractive(3.152451238E-8 , 'eV/T')
+ueVT_N.__doc__ = """nuclear magneton in eV T-1 """
+
+# Atomic and Nuclear Constants
+# General
+#-------------------------------------------------------------------------
+# fine-structure constant
+alpha = 7.297352533E-3
+
+
+Ry = PhysicalQuantityInteractive(10973731.568549 , '1/m')
+Ry.__doc__ = """Rydberg constant """
+Ry_INF = PhysicalQuantityInteractive(10973731.568549 , '1/m')
+
+
+a_0 = PhysicalQuantityInteractive(0.5291772083E-10 , 'm')
+a_0.__doc__ = """Bohr radius """
+
+
+E_h = PhysicalQuantityInteractive(4.35974381E-18 , 'J')
+E_h.__doc__ = """Hartree energy """
+
+Eev_h = PhysicalQuantityInteractive(27.2113834 , 'eV')
+Eev_h.__doc__ = """Hartree energy in eV """
+
+
+qcir2 = PhysicalQuantityInteractive(3.636947516E-4 , 'm**2/s')
+qcir2.__doc__ = """quantum of circulation h/(2me) """
+
+qcir = PhysicalQuantityInteractive(7.273895032E-4 , 'm**2/s')
+qcir.__doc__ = """quantum of circulation h/(me) """
+
+# Electroweak
+#-------------------------------------------------------------------------
+
+Fcc = PhysicalQuantityInteractive(1.16639E-5 , '1/GeV**2')
+Fcc.__doc__ = """Fermi coupling constant """
+# weak mixing angled W (on-shell scheme)
+wma_W = 0.2224
+
+# Electron, e-
+#-------------------------------------------------------------------------
+
+m_e = PhysicalQuantityInteractive(9.10938188E-31 , 'kg')
+m_e.__doc__ = """electron mass """
+
+m_e_u = PhysicalQuantityInteractive(5.485799110E-4 , 'amu')
+m_e_u.__doc__ = """electron mass (electron relative atomic mass times amu)"""
+
+me_J = PhysicalQuantityInteractive(8.18710414E-14 , 'J')
+me_J.__doc__ = """electron mass - energy equivalent """
+
+me_MeV = PhysicalQuantityInteractive(0.510998902 , 'MeV')
+me_MeV.__doc__ = """electron mass - energy equivalent in MeV"""
+
+# electron-muon mass ratio
+memu = 4.83633210E-3
+
+# electron-tau mass ratio
+metau = 2.87555E-4
+
+# electron-proton mass ratio
+memp = 5.446170232E-4
+
+# electron-neutron mass ratio
+memn = 5.438673462E-4
+
+# electron-deuteron mass ratio
+memd = 2.7244371170E-4
+
+# electron to alpha particle mass ratio
+memalpha = 1.3709335611E-4
+
+
+echargeemass = PhysicalQuantityInteractive(-1.758820174E11 , 'C/kg')
+echargeemass.__doc__ = """electron charge to mass quotient """
+
+
+Molar_e = PhysicalQuantityInteractive(5.485799110E-7 , 'kg/mol')
+Molar_e.__doc__ = """electron molar mass """
+
+
+lambdaC = PhysicalQuantityInteractive(2.426310215E-12 , 'm')
+lambdaC.__doc__ = """Compton wavelength """
+
+
+r_e = PhysicalQuantityInteractive(2.817940285E-15 , 'm')
+r_e.__doc__ = """classical electron radius """
+
+
+sigma_e = PhysicalQuantityInteractive(0.665245854E-28 , 'm**2')
+sigma_e.__doc__ = """Thomson cross section """
+
+
+u_e = PhysicalQuantityInteractive(-928.476362E-26 , 'J/T')
+u_e.__doc__ = """electron magnetic moment """
+
+# electron magnetic moment to Bohr magneton ratio
+ueuB = -1.0011596521869
+
+# electron magnetic moment to nuclear magneton ratio
+ueuN = -1838.2819660
+
+# electron magnetic moment anomaly |ue|/uB - 1
+a_e = 1.1596521869E-3
+
+# electron g-factor
+g_e = -2.0023193043737
+
+# electron-muon magnetic moment ratio
+ueuu = 206.7669720
+
+# electron-proton magnetic moment ratio
+ueup = -658.2106875
+
+# electron to shielded proton magnetic moment ratio (H2O, sphere, 25 C)
+ueusp = -658.2275954
+
+# electron-neutron magnetic moment ratio
+ueun = 960.92050
+
+# electron-deuteron magnetic moment ratio
+ueud = -2143.923498
+
+# electron to shielded helione magnetic moment ratio (gas, sphere, 25 C)
+ueush = 864.058255
+
+
+gamma_e = PhysicalQuantityInteractive(1.760859794E11 , '1/(s*T)')
+gamma_e.__doc__ = """electron gyromagnetic ratio """
+
+# Muon, u-
+#-------------------------------------------------------------------------
+
+m_u = PhysicalQuantityInteractive(1.88353109E-28 , 'kg')
+m_u.__doc__ = """muon mass """
+
+mu_u = PhysicalQuantityInteractive(0.1134289168 , 'amu')
+mu_u.__doc__ = """muon mass in muon relative atomic mass times amu """
+
+
+muc2_J = PhysicalQuantityInteractive(1.69283332E-11 , 'J')
+muc2_J.__doc__ = """energy equivalent """
+
+muc2_MeV = PhysicalQuantityInteractive(105.6583568 , 'MeV')
+muc2_MeV.__doc__ = """energy equivalent in MeV """
+
+# muon-electron mass ratio
+mume = 206.7682657
+
+# muon-tau mass ratio
+mum = 5.94572E-2
+
+# muon-proton mass ratio
+mump = 0.1126095173
+
+# muon-neutron mass ratio
+mumn = 0.1124545079
+
+
+Molar_u = PhysicalQuantityInteractive(0.1134289168E-3 , 'kg/mol')
+Molar_u.__doc__ = """muon molar mass """
+
+
+lambda_C_u = PhysicalQuantityInteractive(11.73444197E-15 , 'm')
+lambda_C_u.__doc__ = """muon Compton wavelength """
+
+
+uu = PhysicalQuantityInteractive(-4.49044813E-26 , 'J/T')
+uu.__doc__ = """muon magnetic moment """
+
+# ratio of muon magnetic moment to Bohr magneton ratio
+uuuB = -4.84197085E-3
+
+# ratio of muon magnetic moment to nuclear magneton ratio
+uuuN = -8.89059770
+
+# muon magnetic moment anomaly |uu|/(e /2mu) - 1
+a_u = 1.16591602E-3
+
+# muon g-factor -2(1 + au)
+g_u = -2.0023318320
+
+# muon-proton magnetic moment ratio
+uuup = -3.18334539
+
+# Tau, tau-
+#-------------------------------------------------------------------------
+
+m_tau = PhysicalQuantityInteractive(3.16788E-27 , 'kg')
+m_tau.__doc__ = """tau mass """
+
+mu_tau = PhysicalQuantityInteractive(1.90774 , 'amu')
+mu_tau.__doc__ = """tau mass (tau relative atomic mass times amu) """
+
+
+mtauc2_J = PhysicalQuantityInteractive(2.84715E-10 , 'J')
+mtauc2_J.__doc__ = """tau mass energy equivalent """
+
+
+mtauc2_MeV = PhysicalQuantityInteractive(1777.05 , 'MeV')
+mtauc2_MeV.__doc__ = """tau mass energy equivalent in MeV """
+
+# tau-electron mass ratio
+mtaume = 3477.60
+
+# tau-muon mass ratio
+mtaumu = 16.8188
+
+# tau-proton mass ratio
+mtaump = 1.89396
+
+# tau-neutron mass ratio
+mtaumn = 1.89135
+
+
+Molar_tau = PhysicalQuantityInteractive(1.90774E-3 , 'kg/mol')
+Molar_tau.__doc__ = """tau molar mass """
+
+
+lambda_C_tau = PhysicalQuantityInteractive(0.69770E-15 , 'm')
+lambda_C_tau.__doc__ = """tau Compton wavelength """
+
+# Proton, p
+#-------------------------------------------------------------------------
+
+m_p = PhysicalQuantityInteractive(1.67262158E-27 , 'kg')
+m_p.__doc__ = """proton mass """
+
+mu_p = PhysicalQuantityInteractive(1.00727646688 , 'amu')
+mu_p.__doc__ = """proton mass (proton relative atomic mass times amu) """
+
+
+mpc2_J = PhysicalQuantityInteractive(1.50327731E-10 , 'J')
+mpc2_J.__doc__ = """energy equivalent """
+
+mpc2_MeV = PhysicalQuantityInteractive(938.271998 , 'MeV')
+mpc2_MeV.__doc__ = """energy equivalent in MeV """
+
+# proton-electron mass ratio
+mpme = 1836.1526675
+
+# proton-muon mass ratio
+mpmu = 8.88024408
+
+# proton-tau mass ratio
+mpmtau = 0.527994
+
+# proton-neutron mass ratio
+mpmn = 0.99862347855
+
+
+emp = PhysicalQuantityInteractive(9.57883408E7 , 'C/kg')
+emp.__doc__ = """proton charge to mass quotient """
+
+
+Molar_p = PhysicalQuantityInteractive(1.00727646688E-3 , 'kg/mol')
+Molar_p.__doc__ = """proton molar mass """
+
+
+lambda_C_p = PhysicalQuantityInteractive(1.321409847E-15 , 'm')
+lambda_C_p.__doc__ = """proton Compton wavelength h/mpc """
+
+
+up = PhysicalQuantityInteractive(1.410606633E-26 , 'J/T')
+up.__doc__ = """proton magnetic moment """
+
+# proton magnetic moment to Bohr magneton ratio
+upuB = 1.521032203E-3
+
+# proton magnetic moment to nuclear magneton ratio
+upuN = 2.792847337
+
+# proton g-factor 2up/uN
+g_p = 5.585694675
+
+# proton-neutron magnetic moment ratio
+upun = -1.45989805
+
+
+usp = PhysicalQuantityInteractive(1.410570399E-26 , 'J/T')
+usp.__doc__ = """shielded proton magnetic moment (H2O, sphere, 25 C)"""
+
+# shielded proton magnetic moment to Bohr magneton ratio
+uspuB = 1.520993132E-3
+
+# shielded proton magnetic moment to nuclear magneton ratio
+uspuN = 2.792775597
+
+# proton magnetic shielding correction 1 - u p/up (H2O, sphere, 25 C)
+spc = 25.687E-6
+
+
+gamma_p = PhysicalQuantityInteractive(2.67522212E8 , '1/(s*T)')
+gamma_p.__doc__ = """proton gyromagnetic ratio """
+
+
+gamma_sp = PhysicalQuantityInteractive(2.67515341E8 , '1/(s*T)')
+gamma_sp.__doc__ = """shielded proton gyromagnetic ratio (H2O, sphere, 25 C)"""
+
+# Neutron, n
+#-------------------------------------------------------------------------
+
+m_n = PhysicalQuantityInteractive(1.67492716E-27 , 'kg')
+m_n.__doc__ = """neutron mass """
+
+mu_n = PhysicalQuantityInteractive(1.00866491578 , 'amu')
+mu_n.__doc__ = """neutron mass (neutron relative atomic mass times amu) """
+
+
+mnc2_J = PhysicalQuantityInteractive(1.50534946E-10 , 'J')
+mnc2_J.__doc__ = """neutron mass energy equivalent """
+
+
+mnc2_MeV = PhysicalQuantityInteractive(939.565330 , 'MeV')
+mnc2_MeV.__doc__ = """neutron mass energy equivalent in MeV """
+
+# neutron-electron mass ratio
+mnme = 1838.6836550
+
+# neutron-muon mass ratio
+mnmu = 8.89248478
+
+# neutron-tau mass ratio
+mnm = 0.528722
+
+# neutron-proton mass ratio
+mnmp = 1.00137841887
+
+
+Molar_n = PhysicalQuantityInteractive(1.00866491578E-3 , 'kg/mol')
+Molar_n.__doc__ = """neutron molar mass """
+
+
+lambda_C_n = PhysicalQuantityInteractive(1.319590898E-15 , 'm')
+lambda_C_n.__doc__ = """neutron Compton wavelength"""
+
+
+un = PhysicalQuantityInteractive(-0.96623640E-26 , 'J/T')
+un.__doc__ = """neutron magnetic moment """
+
+# neutron magnetic moment to Bohr magneton ratio
+unuB = -1.04187563E-3
+
+# neutron magnetic moment to nuclear magneton ratio
+unuN = -1.91304272
+
+# neutron g-factor
+g_n = -3.82608545
+
+# neutron-electron magnetic moment ratio
+unue = 1.04066882E-3
+
+# neutron-proton magnetic moment ratio
+unup = -0.68497934
+
+# neutron to shielded proton magnetic moment ratio (H2O, sphere, 25 C)
+unusp = -0.68499694
+
+
+gamma_n = PhysicalQuantityInteractive(1.83247188E8 , '1/(s*T)')
+gamma_n.__doc__ = """neutron gyromagnetic ratio """
+
+# Deuteron, d
+#-------------------------------------------------------------------------
+
+m_d = PhysicalQuantityInteractive(3.34358309E-27 , 'kg')
+m_d.__doc__ = """deuteron mass """
+
+
+mu_d = PhysicalQuantityInteractive(2.01355321271 , 'amu')
+mu_d.__doc__ = """deuteron mass (deuteron relative atomic mass times amu) """
+
+
+mdc2_J = PhysicalQuantityInteractive(3.00506262E-10 , 'J')
+mdc2_J.__doc__ = """deuteron mass energy equivalent """
+
+
+mdc2_eV = PhysicalQuantityInteractive(1875.612762 , 'MeV')
+mdc2_eV.__doc__ = """deuteron mass energy equivalent in MeV """
+
+# deuteron-electron mass ratio
+mdme = 3670.4829550
+
+# deuteron-proton mass ratio
+mdmp = 1.99900750083
+
+
+Molar_d = PhysicalQuantityInteractive(2.01355321271E-3 , 'kg/mol')
+Molar_d.__doc__ = """deuteron molar mass """
+
+
+ud = PhysicalQuantityInteractive(0.433073457E-26 , 'J/T')
+ud.__doc__ = """deuteron magnetic moment """
+
+# deuteron magnetic moment to Bohr magneton ratio
+uduB = 0.4669754556E-3
+
+# deuteron magnetic moment to nuclear magneton ratio
+uduN = 0.8574382284
+
+# deuteron-electron magnetic moment ratio
+udue = -4.664345537E-4
+
+# deuteron-proton magnetic moment ratio
+udup = 0.3070122083
+
+# deuteron-neutron magnetic moment ratio
+udun = -0.44820652
+
+# Helion, h
+#-------------------------------------------------------------------------
+
+m_h = PhysicalQuantityInteractive(5.00641174E-27 , 'kg')
+m_h.__doc__ = """helion mass """
+
+
+mu_h = PhysicalQuantityInteractive(3.01493223469 , 'amu')
+mu_h.__doc__ = """helion mass (helion relative atomic mass times amu) """
+
+
+mhc2_J = PhysicalQuantityInteractive(4.49953848E-10 , 'J')
+mhc2_J.__doc__ = """helion mass energy equivalent """
+
+mhc2_MeV = PhysicalQuantityInteractive(2808.39132 , 'MeV')
+mhc2_MeV.__doc__ = """helion mass energy equivalent in MeV """
+
+# helion-electron mass ratio
+mhme = 5495.885238
+
+# helion-proton mass ratio
+mhmp = 2.99315265850
+
+
+Molar_h = PhysicalQuantityInteractive(3.01493223469E-3 , 'kg/mol')
+Molar_h.__doc__ = """helion molar mass """
+
+
+ush = PhysicalQuantityInteractive(-1.074552967E-26 , 'J/T')
+ush.__doc__ = """shielded helion magnetic moment (gas, sphere, 25 C)"""
+
+# shielded helion magnetic moment to Bohr magneton ratio
+ushuB = -1.158671474E-3
+
+# shielded helion magnetic moment to nuclear magneton ratio
+ushuN = -2.127497718
+
+# shielded helion to proton magnetic moment ratio (gas, sphere, 25 C)
+ushup = -0.761766563
+
+# shielded helion to shielded proton magnetic moment ratio (gas/H2O, spheres, 25 C)
+ushusp = -0.7617861313
+
+
+gamma_h = PhysicalQuantityInteractive(2.037894764E8 , '1/(s*T)')
+gamma_h.__doc__ = """shielded helion gyromagnetic (gas, sphere, 25 C) """
+
+# Alpha particle,
+#-------------------------------------------------------------------------
+
+m_alpha = PhysicalQuantityInteractive(6.64465598E-27 , 'kg')
+m_alpha.__doc__ = """alpha particle mass """
+
+mu_alpha = PhysicalQuantityInteractive(4.0015061747 , 'amu')
+mu_alpha.__doc__ = """alpha particle mass (alpha particle relative atomic mass times amu) """
+
+
+malphac2_J = PhysicalQuantityInteractive(5.97191897E-10 , 'J')
+malphac2_J.__doc__ = """alpha particle mass energy equivalent """
+
+
+malphac2_MeV = PhysicalQuantityInteractive(3727.37904 , 'MeV')
+malphac2_MeV.__doc__ = """alpha particle mass energy equivalent in MeV """
+
+# alpha particle to electron mass ratio
+malphame = 7294.299508
+
+# alpha particle to proton mass ratio
+malphamp = 3.9725996846
+
+
+Molar_alpha = PhysicalQuantityInteractive(4.0015061747E-3 , 'kg/mol')
+Molar_alpha.__doc__ = """alpha particle molar mass"""
+
+# PHYSICO-CHEMICAL
+#-------------------------------------------------------------------------
+
+N_A = PhysicalQuantityInteractive(6.02214199E23 , '1/mol')
+N_A.__doc__ = """Avogadro constant """
+L = PhysicalQuantityInteractive(6.02214199E23 , '1/mol')
+
+
+m_u = PhysicalQuantityInteractive(1.66053873E-27 , 'kg')
+m_u.__doc__ = """atomic mass constant mu = 112m(12C) = 1 u = 10E-3 kg mol-1/NA"""
+# atomic mass constant mu = 112m(12C) = 1 u = 10E-3 kg mol-1/NA
+amu = m_u
+
+
+muc2_J = PhysicalQuantityInteractive(1.49241778E-10 , 'J')
+muc2_J.__doc__ = """energy equivalent of the atomic mass constant"""
+
+
+muc2_MeV = PhysicalQuantityInteractive(931.494013 , 'MeV')
+muc2_MeV.__doc__ = """energy equivalent of the atomic mass constant in MeV """
+
+
+F = PhysicalQuantityInteractive(96485.3415 , 'C/mol')
+F.__doc__ = """Faraday constant"""
+
+
+N_Ah = PhysicalQuantityInteractive(3.990312689E-10 , 'J*s/mol')
+N_Ah.__doc__ = """molar Planck constant """
+
+
+R = PhysicalQuantityInteractive(8.314472 , 'J/(mol*K)')
+R.__doc__ = """molar gas constant """
+
+
+k_J = PhysicalQuantityInteractive(1.3806503E-23 , 'J/K')
+k_J.__doc__ = """Boltzmann constant """
+
+
+k_eV = PhysicalQuantityInteractive(8.617342E-5 , 'eV/K')
+k_eV.__doc__ = """Boltzmann constant in eV """
+
+
+n_0 = PhysicalQuantityInteractive(2.6867775E25 , '1/m**3')
+n_0.__doc__ = """Loschmidt constant NA/Vm """
+
+
+Vm_1 = PhysicalQuantityInteractive(22.413996E-3 , 'm**3/mol')
+Vm_1.__doc__ = """molar volume of ideal gas RT/p T = 273.15 K, p = 101.325 kPa """
+
+Vm_2 = PhysicalQuantityInteractive(22.710981E-3 , 'm**3/mol')
+Vm_2.__doc__ = """molar volume of ideal gas RT/p T = 273.15 K, p = 100 kPa """
+
+# Sackur-Tetrode constant (absolute entropy constant) 52 + ln_(2 mukT1/h2)3/2kT1/p0
+# T1 = 1 K, p0 = 100 kPa
+S_0R_1 = -1.1517048
+# T1 = 1 K, p0 = 101.325 kPa
+S_0R_2 = -1.1648678
+
+
+sigma = PhysicalQuantityInteractive(5.670400E-8 , 'W/(m**2*K**4)')
+sigma.__doc__ = """Stefan-Boltzmann constant """
+
+
+c_1 = PhysicalQuantityInteractive(3.74177107E-16 , 'W*m**2')
+c_1.__doc__ = """first radiation constant"""
+
+
+c_1L = PhysicalQuantityInteractive(1.191042722E-16 , 'W*m**2/sr')
+c_1L.__doc__ = """first radiation constant for spectral radiance"""
+
+
+c_2 = PhysicalQuantityInteractive(1.4387752E-2 , 'm*K')
+c_2.__doc__ = """second radiation constant"""
+
+
+b = PhysicalQuantityInteractive(2.8977686E-3 , 'm*K')
+b.__doc__ = """Wien displacement law constant b = maxT = c2/4.965 114231... """
+
diff --git a/IPython/Extensions/ipy_defaults.py b/IPython/Extensions/ipy_defaults.py
new file mode 100644
index 0000000..89ea3e2
--- /dev/null
+++ b/IPython/Extensions/ipy_defaults.py
@@ -0,0 +1,62 @@
+""" Set default options for IPython.
+
+Just import this module to get reasonable defaults for everything.
+
+These configurations used to be performed in ipythonrc (or ipythonrc.ini).
+Therefore importing this in your config files makes ipython basically
+ignore your ipythonrc. This is *not* imported by default, you need to import
+this manually in one of your config files.
+
+You can further override these defaults in e.g. your ipy_user_config.py,
+ipy_profile_PROFILENAME etc.
+
+"""
+
+import IPython.rlineimpl as readline
+import IPython.ipapi
+ip = IPython.ipapi.get()
+
+o = ip.options
+
+o.colors = "Linux"
+o.color_info=1
+o.confirm_exit=1
+o.pprint=1
+o.multi_line_specials=1
+o.xmode="Context"
+
+
+o.prompt_in1='In [\#]: '
+o.prompt_in2 =' .\D.: '
+o.prompt_out = 'Out[\#]: '
+o.prompts_pad_left=1
+
+o.autoindent = 1
+
+o.readline_remove_delims="-/~"
+o.readline_merge_completions=1
+
+o.readline = 1
+
+rlopts = """\
+tab: complete
+"\C-l": possible-completions
+set show-all-if-ambiguous on
+"\C-o": tab-insert
+"\M-i": " "
+"\M-o": "\d\d\d\d"
+"\M-I": "\d\d\d\d"
+"\C-r": reverse-search-history
+"\C-s": forward-search-history
+"\C-p": history-search-backward
+"\C-n": history-search-forward
+"\e[A": history-search-backward
+"\e[B": history-search-forward
+"\C-k": kill-line
+"\C-u": unix-line-discard"""
+
+if readline.have_readline:
+ for cmd in rlopts.split('\n'):
+ readline.parse_and_bind(cmd)
+
+
diff --git a/IPython/Extensions/ipy_editors.py b/IPython/Extensions/ipy_editors.py
new file mode 100644
index 0000000..88e064a
--- /dev/null
+++ b/IPython/Extensions/ipy_editors.py
@@ -0,0 +1,88 @@
+""" 'editor' hooks for common editors that work well with ipython
+
+They should honor the line number argument, at least.
+
+Contributions are *very* welcome.
+"""
+
+import IPython.ipapi
+ip = IPython.ipapi.get()
+
+from IPython.Itpl import itplns
+import os
+
+def install_editor(run_template, wait = False):
+ """ Gets a template in format "myeditor bah bah $file bah bah $line"
+
+ $file will be replaced by file name, $line by line number (or 0).
+ Installs the editor that is called by IPython, instead of the default
+ notepad or vi.
+
+ If wait is true, wait until the user presses enter before returning,
+ to facilitate non-blocking editors that exit immediately after
+ the call.
+ """
+
+ def call_editor(self, file, line=0):
+ if line is None:
+ line = 0
+ cmd = itplns(run_template, locals())
+ print ">",cmd
+ if os.system(cmd) != 0:
+ raise IPython.ipapi.TryNext()
+ if wait:
+ raw_input("Press Enter when done editing:")
+
+ ip.set_hook('editor',call_editor)
+
+
+# in these, exe is always the path/name of the executable. Useful
+# if you don't have the editor directory in your path
+
+def komodo(exe = 'komodo'):
+ """ Activestate Komodo [Edit] """
+ install_editor(exe + ' -l $line "$file"', wait = True)
+
+def scite(exe = "scite"):
+ """ SciTE or Sc1 """
+ install_editor(exe + ' "$file" -goto:$line')
+
+def notepadplusplus(exe = 'notepad++'):
+ """ Notepad++ http://notepad-plus.sourceforge.net """
+ install_editor(exe + ' -n$line "$file"')
+
+def jed(exe = 'jed'):
+ """ JED, the lightweight emacsish editor """
+ install_editor(exe + ' +$line "$file"')
+
+def idle(exe = None):
+ """ Idle, the editor bundled with python
+
+ Should be pretty smart about finding the executable.
+ """
+ if exe is None:
+ import idlelib
+ p = os.path.dirname(idlelib.__file__)
+ exe = p + '/idle.py'
+ install_editor(exe + ' "$file"')
+
+def mate(exe = 'mate'):
+ """ TextMate, the missing editor"""
+ install_editor(exe + ' -w -l $line "$file"')
+
+# these are untested, report any problems
+
+def emacs(exe = 'emacs'):
+ install_editor(exe + ' +$line "$file"')
+
+def gnuclient(exe= 'gnuclient'):
+ install_editor(exe + ' -nw +$line "$file"')
+
+def crimson_editor(exe = 'cedt.exe'):
+ install_editor(exe + ' /L:$line "$file"')
+
+def kate(exe = 'kate'):
+ install_editor(exe + ' -u -l $line "$file"')
+
+
+ \ No newline at end of file
diff --git a/IPython/Extensions/ipy_exportdb.py b/IPython/Extensions/ipy_exportdb.py
new file mode 100644
index 0000000..d19cfc0
--- /dev/null
+++ b/IPython/Extensions/ipy_exportdb.py
@@ -0,0 +1,76 @@
+import IPython.ipapi
+ip = IPython.ipapi.get()
+
+import os,pprint
+
+def export(filename = None):
+
+ lines = ['import IPython.ipapi', 'ip = IPython.ipapi.get()','']
+
+ vars = ip.db.keys('autorestore/*')
+ vars.sort()
+ varstomove = []
+ get = ip.db.get
+
+ macros = []
+ variables = []
+
+ for var in vars:
+ k = os.path.basename(var)
+ v = get(var)
+
+ if k.startswith('_'):
+ continue
+ if isinstance(v, IPython.macro.Macro):
+ macros.append((k,v))
+ if type(v) in [int, str, float]:
+ variables.append((k,v))
+
+
+
+ if macros:
+ lines.extend(['# === Macros ===' ,''])
+ for k,v in macros:
+ lines.append("ip.defmacro('%s'," % k)
+ for line in v.value.splitlines():
+ lines.append(' ' + repr(line+'\n'))
+ lines.extend([')', ''])
+
+ if variables:
+ lines.extend(['','# === Variables ===',''])
+ for k,v in variables:
+ varstomove.append(k)
+ lines.append('%s = %s' % (k,repr(v)))
+
+ lines.append('ip.to_user_ns("%s")' % (' '.join(varstomove)))
+
+ bkms = ip.db.get('bookmarks',{})
+
+ if bkms:
+ lines.extend(['','# === Bookmarks ===',''])
+ lines.append("ip.db['bookmarks'] = %s " % pprint.pformat(bkms, indent = 2) )
+
+ aliases = ip.db.get('stored_aliases', {} )
+
+ if aliases:
+ lines.extend(['','# === Alias definitions ===',''])
+ for k,v in aliases.items():
+ try:
+ lines.append("ip.defalias('%s', %s)" % (k, repr(v[1])))
+ except (AttributeError, TypeError):
+ pass
+
+ env = ip.db.get('stored_env')
+ if env:
+ lines.extend(['','# === Stored env vars ===',''])
+ lines.append("ip.db['stored_env'] = %s " % pprint.pformat(env, indent = 2) )
+
+
+
+ out = '\n'.join(lines)
+
+ if filename:
+ open(filename,'w').write(out)
+ else:
+ print out
+
diff --git a/IPython/Extensions/ipy_extutil.py b/IPython/Extensions/ipy_extutil.py
new file mode 100644
index 0000000..c35cbc3
--- /dev/null
+++ b/IPython/Extensions/ipy_extutil.py
@@ -0,0 +1,43 @@
+""" IPython extension management tools.
+
+After installation, you'll have the 'extutil' object in your namespace.
+to.
+"""
+
+# for the purposes of this module, every module that has the name 'ip' globally
+# installed as below is an IPython extension
+
+import IPython.ipapi
+ip = IPython.ipapi.get()
+
+import sys,textwrap,inspect
+
+def indent(s, ind= ' '):
+ return '\n'.join([ind +l for l in s.splitlines()])
+
+class ExtUtil:
+ """ IPython extensios (ipy_* etc.) management utilities """
+
+ def describe(self):
+ for n,mod in self._active():
+ doc = inspect.getdoc(mod)
+ if doc:
+ print '== %s ==' % n
+ print indent(doc)
+
+
+ def ls(self):
+ """ Show list of installed extensions. """
+ for n,m in self._active():
+ print '%-20s %s' % (n,m.__file__.replace('\\','/'))
+ def _active(self):
+ act = []
+ for mname,m in sys.modules.items():
+ o = getattr(m, 'ip', None)
+ if isinstance(o, IPython.ipapi.IPApi):
+ act.append((mname,m))
+ act.sort()
+ return act
+
+extutil = ExtUtil()
+ip.to_user_ns('extutil')
diff --git a/IPython/Extensions/ipy_fsops.py b/IPython/Extensions/ipy_fsops.py
new file mode 100644
index 0000000..a8cd2eb
--- /dev/null
+++ b/IPython/Extensions/ipy_fsops.py
@@ -0,0 +1,244 @@
+""" File system operations
+
+Contains: Simple variants of normal unix shell commands (icp, imv, irm,
+imkdir, igrep).
+
+Some "otherwise handy" utils ('collect' for gathering files to
+~/_ipython/collect, 'inote' for collecting single note lines to
+~/_ipython/note.txt)
+
+Mostly of use for bare windows installations where cygwin/equivalent is not
+installed and you would otherwise need to deal with dos versions of the
+commands (that e.g. don't understand / as path separator). These can
+do some useful tricks on their own, though (like use 'mglob' patterns).
+
+Not to be confused with ipipe commands (ils etc.) that also start with i.
+"""
+
+import IPython.ipapi
+ip = IPython.ipapi.get()
+
+import shutil,os,shlex
+from IPython.external import mglob
+from IPython.external.path import path
+from IPython.ipapi import UsageError
+
+def parse_args(args):
+ """ Given arg string 'CMD files... target', return ([files], target) """
+
+ tup = args.split(None, 1)
+ if len(tup) == 1:
+ raise UsageError("Expected arguments for " + tup[0])
+
+ tup2 = shlex.split(tup[1])
+
+ flist, trg = mglob.expand(tup2[0:-1]), tup2[-1]
+ if not flist:
+ raise UsageError("No files found:" + str(tup2[0:-1]))
+ return flist, trg
+
+def icp(ip,arg):
+ """ icp files... targetdir
+
+ Copy all files to target, creating dirs for target if necessary
+
+ icp srcdir dstdir
+
+ Copy srcdir to distdir
+
+ """
+ import distutils.dir_util
+
+ fs, targetdir = parse_args(arg)
+ if not os.path.isdir(targetdir) and len(fs) > 1:
+ distutils.dir_util.mkpath(targetdir,verbose =1)
+ for f in fs:
+ if os.path.isdir(f):
+ shutil.copytree(f, targetdir)
+ else:
+ shutil.copy2(f,targetdir)
+ return fs
+ip.defalias("icp",icp)
+
+def imv(ip,arg):
+ """ imv src tgt
+
+ Move source to target.
+ """
+
+ fs, target = parse_args(arg)
+ if len(fs) > 1:
+ assert os.path.isdir(target)
+ for f in fs:
+ shutil.move(f, target)
+ return fs
+ip.defalias("imv",imv)
+
+def irm(ip,arg):
+ """ irm path[s]...
+
+ Remove file[s] or dir[s] path. Dirs are deleted recursively.
+ """
+ try:
+ paths = mglob.expand(arg.split(None,1)[1])
+ except IndexError:
+ raise UsageError("%irm paths...")
+ import distutils.dir_util
+ for p in paths:
+ print "rm",p
+ if os.path.isdir(p):
+ distutils.dir_util.remove_tree(p, verbose = 1)
+ else:
+ os.remove(p)
+
+ip.defalias("irm",irm)
+
+def imkdir(ip,arg):
+ """ imkdir path
+
+ Creates dir path, and all dirs on the road
+ """
+ import distutils.dir_util
+ targetdir = arg.split(None,1)[1]
+ distutils.dir_util.mkpath(targetdir,verbose =1)
+
+ip.defalias("imkdir",imkdir)
+
+def igrep(ip,arg):
+ """ igrep PAT files...
+
+ Very dumb file scan, case-insensitive.
+
+ e.g.
+
+ igrep "test this" rec:*.py
+
+ """
+ elems = shlex.split(arg)
+ dummy, pat, fs = elems[0], elems[1], mglob.expand(elems[2:])
+ res = []
+ for f in fs:
+ found = False
+ for l in open(f):
+ if pat.lower() in l.lower():
+ if not found:
+ print "[[",f,"]]"
+ found = True
+ res.append(f)
+ print l.rstrip()
+ return res
+
+ip.defalias("igrep",igrep)
+
+def collect(ip,arg):
+ """ collect foo/a.txt rec:bar=*.py
+
+ Copies foo/a.txt to ~/_ipython/collect/foo/a.txt and *.py from bar,
+ likewise
+
+ Without args, try to open ~/_ipython/collect dir (in win32 at least).
+ """
+ from IPython.external.path import path
+ basedir = path(ip.options.ipythondir + '/collect')
+ try:
+ fs = mglob.expand(arg.split(None,1)[1])
+ except IndexError:
+ os.startfile(basedir)
+ return
+ for f in fs:
+ f = path(f)
+ trg = basedir / f.splitdrive()[1].lstrip('/\\')
+ if f.isdir():
+ print "mkdir",trg
+ trg.makedirs()
+ continue
+ dname = trg.dirname()
+ if not dname.isdir():
+ dname.makedirs()
+ print f,"=>",trg
+ shutil.copy2(f,trg)
+
+ip.defalias("collect",collect)
+
+def inote(ip,arg):
+ """ inote Hello world
+
+ Adds timestamp and Hello world to ~/_ipython/notes.txt
+
+ Without args, opens notes.txt for editing.
+ """
+ import time
+ fname = ip.options.ipythondir + '/notes.txt'
+
+ try:
+ entry = " === " + time.asctime() + ': ===\n' + arg.split(None,1)[1] + '\n'
+ f= open(fname, 'a').write(entry)
+ except IndexError:
+ ip.IP.hooks.editor(fname)
+
+ip.defalias("inote",inote)
+
+def pathobj_mangle(p):
+ return p.replace(' ', '__').replace('.','DOT')
+def pathobj_unmangle(s):
+ return s.replace('__',' ').replace('DOT','.')
+
+
+
+class PathObj(path):
+ def __init__(self,p):
+ self.path = p
+ if p != '.':
+ self.ents = [pathobj_mangle(ent) for ent in os.listdir(p)]
+ else:
+ self.ents = None
+ def __complete__(self):
+ if self.path != '.':
+ return self.ents
+ self.ents = [pathobj_mangle(ent) for ent in os.listdir('.')]
+ return self.ents
+ def __getattr__(self,name):
+ if name in self.ents:
+ if self.path.endswith('/'):
+ sep = ''
+ else:
+ sep = '/'
+
+ tgt = self.path + sep + pathobj_unmangle(name)
+ #print "tgt",tgt
+ if os.path.isdir(tgt):
+ return PathObj(tgt)
+ if os.path.isfile(tgt):
+ return path(tgt)
+
+ raise AttributeError, name # <<< DON'T FORGET THIS LINE !!
+ def __str__(self):
+ return self.path
+
+ def __repr__(self):
+ return "<PathObj to %s>" % self.path
+
+ def __call__(self):
+ print "cd:",self.path
+ os.chdir(self.path)
+
+def complete_pathobj(obj, prev_completions):
+ if hasattr(obj,'__complete__'):
+ res = obj.__complete__()
+ if res:
+ return res
+ # just return normal attributes of 'path' object if the dir is empty
+ raise IPython.ipapi.TryNext
+
+complete_pathobj = IPython.generics.complete_object.when_type(PathObj)(complete_pathobj)
+
+def test_pathobj():
+ #p = PathObj('c:/prj')
+ #p2 = p.cgi
+ #print p,p2
+ rootdir = PathObj("/")
+ startmenu = PathObj("d:/Documents and Settings/All Users/Start Menu/Programs")
+ cwd = PathObj('.')
+ ip.to_user_ns("rootdir startmenu cwd")
+
+#test_pathobj() \ No newline at end of file
diff --git a/IPython/Extensions/ipy_gnuglobal.py b/IPython/Extensions/ipy_gnuglobal.py
new file mode 100644
index 0000000..d03babc
--- /dev/null
+++ b/IPython/Extensions/ipy_gnuglobal.py
@@ -0,0 +1,38 @@
+#!/usr/bin/env python
+
+
+"""
+Add %global magic for GNU Global usage.
+
+http://www.gnu.org/software/global/
+
+"""
+
+import IPython.ipapi
+ip = IPython.ipapi.get()
+import os
+
+# alter to your liking
+global_bin = 'd:/opt/global/bin/global'
+
+def global_f(self,cmdline):
+ simple = 0
+ if '-' not in cmdline:
+ cmdline = '-rx ' + cmdline
+ simple = 1
+
+ lines = [l.rstrip() for l in os.popen( global_bin + ' ' + cmdline ).readlines()]
+
+ if simple:
+ parts = [l.split(None,3) for l in lines]
+ lines = ['%s [%s]\n%s' % (p[2].rjust(70),p[1],p[3].rstrip()) for p in parts]
+ print "\n".join(lines)
+
+ip.expose_magic('global', global_f)
+
+def global_completer(self,event):
+ compl = [l.rstrip() for l in os.popen(global_bin + ' -c ' + event.symbol).readlines()]
+ return compl
+
+ip.set_hook('complete_command', global_completer, str_key = '%global')
+
diff --git a/IPython/Extensions/ipy_greedycompleter.py b/IPython/Extensions/ipy_greedycompleter.py
new file mode 100644
index 0000000..37142d7
--- /dev/null
+++ b/IPython/Extensions/ipy_greedycompleter.py
@@ -0,0 +1,75 @@
+""" Greedy completer extension for IPython
+
+Normal tab completer refuses to evaluate nonsafe stuff. This will evaluate
+everything, so you need to consider the consequences of pressing tab
+yourself!
+
+Note that this extension simplifies readline interaction by setting
+only whitespace as completer delimiter. If this works well, we will
+do the same in default completer.
+
+"""
+from IPython import generics,ipapi
+from IPython.genutils import dir2
+
+def attr_matches(self, text):
+ """Compute matches when text contains a dot.
+
+ MONKEYPATCHED VERSION (ipy_greedycompleter.py)
+
+ Assuming the text is of the form NAME.NAME....[NAME], and is
+ evaluatable in self.namespace or self.global_namespace, it will be
+ evaluated and its attributes (as revealed by dir()) are used as
+ possible completions. (For class instances, class members are are
+ also considered.)
+
+ WARNING: this can still invoke arbitrary C code, if an object
+ with a __getattr__ hook is evaluated.
+
+ """
+ import re
+
+ force_complete = 1
+ # Another option, seems to work great. Catches things like ''.<tab>
+ m = re.match(r"(\S+(\.\w+)*)\.(\w*)$", text)
+
+ if m:
+ expr, attr = m.group(1, 3)
+ else:
+ # force match - eval anything that ends with colon
+ if not force_complete:
+ return []
+
+ m2 = re.match(r"(.+)\.(\w*)$", self.lbuf)
+ if not m2:
+ return []
+ expr, attr = m2.group(1,2)
+
+
+ try:
+ obj = eval(expr, self.namespace)
+ except:
+ try:
+ obj = eval(expr, self.global_namespace)
+ except:
+ return []
+
+ words = dir2(obj)
+
+ try:
+ words = generics.complete_object(obj, words)
+ except ipapi.TryNext:
+ pass
+ # Build match list to return
+ n = len(attr)
+ res = ["%s.%s" % (expr, w) for w in words if w[:n] == attr ]
+ return res
+
+def main():
+ import IPython.rlineimpl as readline
+ readline.set_completer_delims(" \n\t")
+ # monkeypatch - the code will be folded to normal completer later on
+ import IPython.completer
+ IPython.completer.Completer.attr_matches = attr_matches
+
+main() \ No newline at end of file
diff --git a/IPython/Extensions/ipy_jot.py b/IPython/Extensions/ipy_jot.py
new file mode 100644
index 0000000..dd71967
--- /dev/null
+++ b/IPython/Extensions/ipy_jot.py
@@ -0,0 +1,311 @@
+# -*- coding: utf-8 -*-
+"""
+%jot magic for lightweight persistence.
+
+Stores variables in Struct with some notes in PicleShare database
+
+
+"""
+
+from datetime import datetime
+import IPython.ipapi
+ip = IPython.ipapi.get()
+
+import pickleshare
+
+import inspect,pickle,os,sys,textwrap
+from IPython.FakeModule import FakeModule
+from IPython.ipstruct import Struct
+
+
+def refresh_variables(ip, key=None):
+ db = ip.db
+ if key is None:
+ keys = db.keys('jot/*')
+ else:
+ keys = db.keys('jot/'+key)
+ for key in keys:
+ # strip autorestore
+ justkey = os.path.basename(key)
+ print "Restoring from", justkey, "..."
+ try:
+ obj = db[key]
+ except KeyError:
+ print "Unable to restore variable '%s', ignoring (use %%jot -d to forget!)" % justkey
+ print "The error was:",sys.exc_info()[0]
+ else:
+ #print "restored",justkey,"=",obj #dbg
+ try:
+ origname = obj.name
+ except:
+ ip.user_ns[justkey] = obj
+ print "Restored", justkey
+ else:
+ ip.user_ns[origname] = obj['val']
+ print "Restored", origname
+
+def read_variables(ip, key=None):
+ db = ip.db
+ if key is None:
+ return None
+ else:
+ keys = db.keys('jot/'+key)
+ for key in keys:
+ # strip autorestore
+ justkey = os.path.basename(key)
+ print "restoring from ", justkey
+ try:
+ obj = db[key]
+ except KeyError:
+ print "Unable to read variable '%s', ignoring (use %%jot -d to forget!)" % justkey
+ print "The error was:",sys.exc_info()[0]
+ else:
+ return obj
+
+
+def detail_variables(ip, key=None):
+ db, get = ip.db, ip.db.get
+
+ if key is None:
+ keys = db.keys('jot/*')
+ else:
+ keys = db.keys('jot/'+key)
+ if keys:
+ size = max(map(len,keys))
+ else:
+ size = 0
+
+ fmthead = '%-'+str(size)+'s [%s]'
+ fmtbody = 'Comment:\n %s'
+ fmtdata = 'Data:\n %s, %s'
+ for key in keys:
+ v = get(key,'<unavailable>')
+ justkey = os.path.basename(key)
+ try:
+ print fmthead % (justkey, datetime.ctime(v.get('time','<unavailable>')))
+ print fmtbody % (v.get('comment','<unavailable>'))
+ d = v.get('val','unavailable')
+ print fmtdata % (repr(type(d)), '')
+ print repr(d)[0:200]
+ print
+ print
+ except AttributeError:
+ print fmt % (justkey, '<unavailable>', '<unavailable>', repr(v)[:50])
+
+
+def intm(n):
+ try:
+ return int(n)
+ except:
+ return 0
+
+def jot_obj(self, obj, name, comment=''):
+ """
+ write obj data to the note database, with whatever that should be noted.
+ """
+ had = self.db.keys('jot/'+name+'*')
+ # if it the same name but a later version, we stupidly add a number to the
+ # so the name doesn't collide. Any better idea?
+ suffix = ''
+ if len(had)>0:
+ pre = os.path.commonprefix(had)
+ suf = [n.split(pre)[1] for n in had]
+ versions = map(intm, suf)
+ suffix = str(max(versions)+1)
+
+ uname = 'jot/'+name+suffix
+
+ # which one works better?
+ #all = ip.IP.shadowhist.all()
+ all = ip.IP.shell.input_hist
+
+ # We may actually want to make snapshot of files that are run-ned.
+
+ # get the comment
+ try:
+ comment = ip.IP.magic_edit('-x').strip()
+ except:
+ print "No comment is recorded."
+ comment = ''
+
+ self.db[uname] = Struct({'val':obj,
+ 'time' : datetime.now(),
+ 'hist' : all,
+ 'name' : name,
+ 'comment' : comment,})
+
+ print "Jotted down notes for '%s' (%s)" % (uname, obj.__class__.__name__)
+
+
+
+def magic_jot(self, parameter_s=''):
+ """Lightweight persistence for python variables.
+
+ Example:
+
+ ville@badger[~]|1> A = ['hello',10,'world']\\
+ ville@badger[~]|2> %jot A\\
+ ville@badger[~]|3> Exit
+
+ (IPython session is closed and started again...)
+
+ ville@badger:~$ ipython -p pysh\\
+ ville@badger[~]|1> print A
+
+ ['hello', 10, 'world']
+
+ Usage:
+
+ %jot - Show list of all variables and their current values\\
+ %jot -l - Show list of all variables and their current values in detail\\
+ %jot -l <var> - Show one variable and its current values in detail\\
+ %jot <var> - Store the *current* value of the variable to disk\\
+ %jot -d <var> - Remove the variable and its value from storage\\
+ %jot -z - Remove all variables from storage (disabled)\\
+ %jot -r <var> - Refresh/Load variable from jot (delete current vals)\\
+ %jot foo >a.txt - Store value of foo to new file a.txt\\
+ %jot foo >>a.txt - Append value of foo to file a.txt\\
+
+ It should be noted that if you change the value of a variable, you
+ need to %note it again if you want to persist the new value.
+
+ Note also that the variables will need to be pickleable; most basic
+ python types can be safely %stored.
+
+ """
+
+ opts,argsl = self.parse_options(parameter_s,'drzl',mode='string')
+ args = argsl.split(None,1)
+ ip = self.getapi()
+ db = ip.db
+ # delete
+ if opts.has_key('d'):
+ try:
+ todel = args[0]
+ except IndexError:
+ error('You must provide the variable to forget')
+ else:
+ try:
+ del db['jot/' + todel]
+ except:
+ error("Can't delete variable '%s'" % todel)
+ # reset the whole database
+ elif opts.has_key('z'):
+ print "reseting the whole database has been disabled."
+ #for k in db.keys('autorestore/*'):
+ # del db[k]
+
+ elif opts.has_key('r'):
+ try:
+ toret = args[0]
+ except:
+ print "restoring all the variables jotted down..."
+ refresh_variables(ip)
+ else:
+ refresh_variables(ip, toret)
+
+ elif opts.has_key('l'):
+ try:
+ tolist = args[0]
+ except:
+ print "List details for all the items."
+ detail_variables(ip)
+ else:
+ print "Details for", tolist, ":"
+ detail_variables(ip, tolist)
+
+ # run without arguments -> list noted variables & notes
+ elif not args:
+ vars = self.db.keys('jot/*')
+ vars.sort()
+ if vars:
+ size = max(map(len,vars)) - 4
+ else:
+ size = 0
+
+ print 'Variables and their in-db values:'
+ fmt = '%-'+str(size)+'s [%s] -> %s'
+ get = db.get
+ for var in vars:
+ justkey = os.path.basename(var)
+ v = get(var,'<unavailable>')
+ try:
+ print fmt % (justkey,\
+ datetime.ctime(v.get('time','<unavailable>')),\
+ v.get('comment','<unavailable>')[:70].replace('\n',' '),)
+ except AttributeError:
+ print fmt % (justkey, '<unavailable>', '<unavailable>', repr(v)[:50])
+
+
+ # default action - store the variable
+ else:
+ # %store foo >file.txt or >>file.txt
+ if len(args) > 1 and args[1].startswith('>'):
+ fnam = os.path.expanduser(args[1].lstrip('>').lstrip())
+ if args[1].startswith('>>'):
+ fil = open(fnam,'a')
+ else:
+ fil = open(fnam,'w')
+ obj = ip.ev(args[0])
+ print "Writing '%s' (%s) to file '%s'." % (args[0],
+ obj.__class__.__name__, fnam)
+
+
+ if not isinstance (obj,basestring):
+ from pprint import pprint
+ pprint(obj,fil)
+ else:
+ fil.write(obj)
+ if not obj.endswith('\n'):
+ fil.write('\n')
+
+ fil.close()
+ return
+
+ # %note foo
+ try:
+ obj = ip.user_ns[args[0]]
+ except KeyError:
+ # this should not be alias, for aliases, use %store
+ print
+ print "Error: %s doesn't exist." % args[0]
+ print
+ print "Use %note -r <var> to retrieve variables. This should not be used " +\
+ "to store alias, for saving aliases, use %store"
+ return
+ else:
+ if isinstance(inspect.getmodule(obj), FakeModule):
+ print textwrap.dedent("""\
+ Warning:%s is %s
+ Proper storage of interactively declared classes (or instances
+ of those classes) is not possible! Only instances
+ of classes in real modules on file system can be %%store'd.
+ """ % (args[0], obj) )
+ return
+ #pickled = pickle.dumps(obj)
+ #self.db[ 'jot/' + args[0] ] = obj
+ jot_obj(self, obj, args[0])
+
+
+def magic_read(self, parameter_s=''):
+ """
+ %read <var> - Load variable from data that is jotted down.\\
+
+ """
+
+ opts,argsl = self.parse_options(parameter_s,'drzl',mode='string')
+ args = argsl.split(None,1)
+ ip = self.getapi()
+ db = ip.db
+ #if opts.has_key('r'):
+ try:
+ toret = args[0]
+ except:
+ print "which record do you want to read out?"
+ return
+ else:
+ return read_variables(ip, toret)
+
+
+ip.expose_magic('jot',magic_jot)
+ip.expose_magic('read',magic_read)
diff --git a/IPython/Extensions/ipy_kitcfg.py b/IPython/Extensions/ipy_kitcfg.py
new file mode 100644
index 0000000..d77f672
--- /dev/null
+++ b/IPython/Extensions/ipy_kitcfg.py
@@ -0,0 +1,80 @@
+import os,sys
+
+import ipy_rehashdir,glob
+from ipy_rehashdir import selflaunch, PyLauncher
+
+def pylaunchers():
+ """Create launchers for python scripts in cwd and store them in alias table
+
+ This is useful if you want to invoke .py scripts from ipykit session,
+ just adding .py files in PATH does not work without file association.
+
+ .ipy files will be run like macros.
+
+ """
+ fs = glob.glob('*.py') + glob.glob('*.ipy')
+ for f in fs:
+ l = PyLauncher(f)
+ n = os.path.splitext(f)[0]
+ ip.defalias(n, l)
+ ip.magic('store '+n)
+
+
+def exta_imports():
+ # add some modules that you'd want to be bundled in the ipykit
+ # library zip file here. Do this if you get ImportErrors from scripts you
+ # try to launch with 'py' or pylaunchers. In theory you could include
+ # the whole stdlib here for full script coverage
+
+ # note that this is never run, it's just here for py2exe
+ import distutils.dir_util
+
+def kitroot():
+ return os.environ.get('IPYKITROOT', None)
+
+def main():
+
+ if not kitroot():
+ print "Can't configure ipykit, IPYKITROOT should be set."
+ return
+
+ os.environ["PATH"] = os.environ["PATH"] + ";" + kitroot() + "\\bin;"
+ ip.to_user_ns("pylaunchers")
+ cmds = ip.db.get('syscmdlist', None)
+ if cmds is None:
+ ip.magic('rehashx')
+ cmds = ip.db.get('syscmdlist', [])
+ #print cmds
+ if 'sc1' in cmds:
+ print "Default editor: Sc1"
+ import ipy_editors
+ ipy_editors.scite('sc1')
+
+ # for icp, imv, imkdir, etc.
+ import ipy_fsops
+
+greeting = """\n\n === Welcome to ipykit ===
+
+%quickref - learn quickly about IPython.
+
+"""
+
+def ipython_firstrun(ip):
+
+ print "First run of ipykit - configuring"
+
+ ip.defalias('py',selflaunch)
+ ip.defalias('d','dir /w /og /on')
+ ip.magic('store py')
+ ip.magic('store d')
+
+ bins = kitroot() +'/bin'
+
+ print greeting
+
+def init_ipython(ipy):
+ global ip
+ ip = ipy
+ main()
+
+
diff --git a/IPython/Extensions/ipy_legacy.py b/IPython/Extensions/ipy_legacy.py
new file mode 100644
index 0000000..2807dfd
--- /dev/null
+++ b/IPython/Extensions/ipy_legacy.py
@@ -0,0 +1,62 @@
+""" Legacy stuff
+
+Various stuff that are there for historical / familiarity reasons.
+
+This is automatically imported by default profile, though not other profiles
+(e.g. 'sh' profile).
+
+Stuff that is considered obsolete / redundant is gradually moved here.
+
+"""
+
+import IPython.ipapi
+ip = IPython.ipapi.get()
+
+import os,sys
+
+from IPython.genutils import *
+
+# use rehashx
+
+def magic_rehash(self, parameter_s = ''):
+ """Update the alias table with all entries in $PATH.
+
+ This version does no checks on execute permissions or whether the
+ contents of $PATH are truly files (instead of directories or something
+ else). For such a safer (but slower) version, use %rehashx."""
+
+ # This function (and rehashx) manipulate the alias_table directly
+ # rather than calling magic_alias, for speed reasons. A rehash on a
+ # typical Linux box involves several thousand entries, so efficiency
+ # here is a top concern.
+
+ path = filter(os.path.isdir,os.environ.get('PATH','').split(os.pathsep))
+ alias_table = self.shell.alias_table
+ for pdir in path:
+ for ff in os.listdir(pdir):
+ # each entry in the alias table must be (N,name), where
+ # N is the number of positional arguments of the alias.
+ alias_table[ff] = (0,ff)
+ # Make sure the alias table doesn't contain keywords or builtins
+ self.shell.alias_table_validate()
+ # Call again init_auto_alias() so we get 'rm -i' and other modified
+ # aliases since %rehash will probably clobber them
+ self.shell.init_auto_alias()
+
+ip.expose_magic("rehash", magic_rehash)
+
+# Exit
+def magic_Quit(self, parameter_s=''):
+ """Exit IPython without confirmation (like %Exit)."""
+
+ self.shell.ask_exit()
+
+ip.expose_magic("Quit", magic_Quit)
+
+
+# make it autocallable fn if you really need it
+def magic_p(self, parameter_s=''):
+ """Just a short alias for Python's 'print'."""
+ exec 'print ' + parameter_s in self.shell.user_ns
+
+ip.expose_magic("p", magic_p)
diff --git a/IPython/Extensions/ipy_lookfor.py b/IPython/Extensions/ipy_lookfor.py
new file mode 100644
index 0000000..eb56f3d
--- /dev/null
+++ b/IPython/Extensions/ipy_lookfor.py
@@ -0,0 +1,234 @@
+"""
+IPython extension: %lookfor command for searching docstrings
+
+"""
+# Pauli Virtanen <pav@iki.fi>, 2008.
+
+import re, inspect, pkgutil, pydoc
+
+#------------------------------------------------------------------------------
+# Lookfor functionality
+#------------------------------------------------------------------------------
+
+# Cache for lookfor: {id(module): {name: (docstring, kind, index), ...}...}
+# where kind: "func", "class", "module", "object"
+# and index: index in breadth-first namespace traversal
+_lookfor_caches = {}
+
+# regexp whose match indicates that the string may contain a function signature
+_function_signature_re = re.compile(r"[a-z_]+\(.*[,=].*\)", re.I)
+
+def lookfor(what, modules=None, import_modules=True, regenerate=False):
+ """
+ Search for objects whose documentation contains all given words.
+ Shows a summary of matching objects, sorted roughly by relevance.
+
+ Parameters
+ ----------
+ what : str
+ String containing words to look for.
+
+ module : str, module
+ Module whose docstrings to go through.
+ import_modules : bool
+ Whether to import sub-modules in packages.
+ Will import only modules in __all__
+ regenerate: bool
+ Re-generate the docstring cache
+
+ """
+ # Cache
+ cache = {}
+ for module in modules:
+ try:
+ c = _lookfor_generate_cache(module, import_modules, regenerate)
+ cache.update(c)
+ except ImportError:
+ pass
+
+ # Search
+ # XXX: maybe using a real stemming search engine would be better?
+ found = []
+ whats = str(what).lower().split()
+ if not whats: return
+
+ for name, (docstring, kind, index) in cache.iteritems():
+ if kind in ('module', 'object'):
+ # don't show modules or objects
+ continue
+ ok = True
+ doc = docstring.lower()
+ for w in whats:
+ if w not in doc:
+ ok = False
+ break
+ if ok:
+ found.append(name)
+
+ # Relevance sort
+ # XXX: this is full Harrison-Stetson heuristics now,
+ # XXX: it probably could be improved
+
+ kind_relevance = {'func': 1000, 'class': 1000,
+ 'module': -1000, 'object': -1000}
+
+ def relevance(name, docstr, kind, index):
+ r = 0
+ # do the keywords occur within the start of the docstring?
+ first_doc = "\n".join(docstr.lower().strip().split("\n")[:3])
+ r += sum([200 for w in whats if w in first_doc])
+ # do the keywords occur in the function name?
+ r += sum([30 for w in whats if w in name])
+ # is the full name long?
+ r += -len(name) * 5
+ # is the object of bad type?
+ r += kind_relevance.get(kind, -1000)
+ # is the object deep in namespace hierarchy?
+ r += -name.count('.') * 10
+ r += max(-index / 100, -100)
+ return r
+
+ def relevance_sort(a, b):
+ dr = relevance(b, *cache[b]) - relevance(a, *cache[a])
+ if dr != 0: return dr
+ else: return cmp(a, b)
+ found.sort(relevance_sort)
+
+ # Pretty-print
+ s = "Search results for '%s'" % (' '.join(whats))
+ help_text = [s, "-"*len(s)]
+ for name in found:
+ doc, kind, ix = cache[name]
+
+ doclines = [line.strip() for line in doc.strip().split("\n")
+ if line.strip()]
+
+ # find a suitable short description
+ try:
+ first_doc = doclines[0].strip()
+ if _function_signature_re.search(first_doc):
+ first_doc = doclines[1].strip()
+ except IndexError:
+ first_doc = ""
+ help_text.append("%s\n %s" % (name, first_doc))
+
+ # Output
+ if len(help_text) > 10:
+ pager = pydoc.getpager()
+ pager("\n".join(help_text))
+ else:
+ print "\n".join(help_text)
+
+def _lookfor_generate_cache(module, import_modules, regenerate):
+ """
+ Generate docstring cache for given module.
+
+ Parameters
+ ----------
+ module : str, None, module
+ Module for which to generate docstring cache
+ import_modules : bool
+ Whether to import sub-modules in packages.
+ Will import only modules in __all__
+ regenerate: bool
+ Re-generate the docstring cache
+
+ Returns
+ -------
+ cache : dict {obj_full_name: (docstring, kind, index), ...}
+ Docstring cache for the module, either cached one (regenerate=False)
+ or newly generated.
+
+ """
+ global _lookfor_caches
+
+ if module is None:
+ module = "numpy"
+
+ if isinstance(module, str):
+ module = __import__(module)
+
+ if id(module) in _lookfor_caches and not regenerate:
+ return _lookfor_caches[id(module)]
+
+ # walk items and collect docstrings
+ cache = {}
+ _lookfor_caches[id(module)] = cache
+ seen = {}
+ index = 0
+ stack = [(module.__name__, module)]
+ while stack:
+ name, item = stack.pop(0)
+ if id(item) in seen: continue
+ seen[id(item)] = True
+
+ index += 1
+ kind = "object"
+
+ if inspect.ismodule(item):
+ kind = "module"
+ try:
+ _all = item.__all__
+ except AttributeError:
+ _all = None
+ # import sub-packages
+ if import_modules and hasattr(item, '__path__'):
+ for m in pkgutil.iter_modules(item.__path__):
+ if _all is not None and m[1] not in _all:
+ continue
+ try:
+ __import__("%s.%s" % (name, m[1]))
+ except ImportError:
+ continue
+ for n, v in inspect.getmembers(item):
+ if _all is not None and n not in _all:
+ continue
+ stack.append(("%s.%s" % (name, n), v))
+ elif inspect.isclass(item):
+ kind = "class"
+ for n, v in inspect.getmembers(item):
+ stack.append(("%s.%s" % (name, n), v))
+ elif callable(item):
+ kind = "func"
+
+ doc = inspect.getdoc(item)
+ if doc is not None:
+ cache[name] = (doc, kind, index)
+
+ return cache
+
+#------------------------------------------------------------------------------
+# IPython connectivity
+#------------------------------------------------------------------------------
+
+import IPython.ipapi
+ip = IPython.ipapi.get()
+
+_lookfor_modules = ['numpy', 'scipy']
+
+def lookfor_f(self, arg=''):
+ r"""
+ Search for objects whose documentation contains all given words.
+ Shows a summary of matching objects, sorted roughly by relevance.
+
+ Usage
+ -----
+ %lookfor +numpy some words
+ Search module 'numpy'
+
+ %lookfor_modules numpy scipy
+ Set default modules whose docstrings to search
+
+ """
+ lookfor(arg, modules=_lookfor_modules)
+
+def lookfor_modules_f(self, arg=''):
+ global _lookfor_modules
+ if not arg:
+ print "Modules included in %lookfor search:", _lookfor_modules
+ else:
+ _lookfor_modules = arg.split()
+
+ip.expose_magic('lookfor', lookfor_f)
+ip.expose_magic('lookfor_modules', lookfor_modules_f)
+
diff --git a/IPython/Extensions/ipy_p4.py b/IPython/Extensions/ipy_p4.py
new file mode 100644
index 0000000..448ce2a
--- /dev/null
+++ b/IPython/Extensions/ipy_p4.py
@@ -0,0 +1,47 @@
+# -*- coding: utf-8 -*-
+"""
+Add %p4 magic for pythonic p4 (Perforce) usage.
+"""
+
+import IPython.ipapi
+ip = IPython.ipapi.get()
+
+import os,sys,marshal
+
+import ipy_stock_completers
+
+def p4_f(self, parameter_s=''):
+ cmd = 'p4 -G ' + parameter_s
+ fobj = os.popen(cmd)
+ out = []
+ while 1:
+ try:
+ out.append(marshal.load(fobj))
+ except EOFError:
+ break
+
+ return out
+
+def p4d(fname):
+ return os.popen('p4 where ' + fname).read().split()[0]
+
+ip.to_user_ns("p4d")
+
+ip.expose_magic('p4', p4_f)
+
+p4_commands = """\
+add admin annotate branch branches change changes changelist
+changelists client clients counter counters delete depot depots
+describe diff diff2 dirs edit filelog files fix fixes flush fstat
+group groups have help info integrate integrated job jobs jobspec
+label labels labelsync lock logger login logout monitor obliterate
+opened passwd print protect rename reopen resolve resolved revert
+review reviews set submit sync tag tickets triggers typemap unlock
+user users verify workspace workspaces where"""
+
+def p4_completer(self,event):
+ return ipy_stock_completers.vcs_completer(p4_commands, event)
+
+ip.set_hook('complete_command', p4_completer, str_key = '%p4')
+ip.set_hook('complete_command', p4_completer, str_key = 'p4')
+
diff --git a/IPython/Extensions/ipy_pretty.py b/IPython/Extensions/ipy_pretty.py
new file mode 100644
index 0000000..924b7fa
--- /dev/null
+++ b/IPython/Extensions/ipy_pretty.py
@@ -0,0 +1,132 @@
+""" Use pretty.py for configurable pretty-printing.
+
+Register pretty-printers for types using ipy_pretty.for_type() or
+ipy_pretty.for_type_by_name(). For example, to use the example pretty-printer
+for numpy dtype objects, add the following to your ipy_user_conf.py::
+
+ from IPython.Extensions import ipy_pretty
+
+ ipy_pretty.activate()
+
+ # If you want to have numpy always imported anyways:
+ import numpy
+ ipy_pretty.for_type(numpy.dtype, ipy_pretty.dtype_pprinter)
+
+ # If you don't want to have numpy imported until it needs to be:
+ ipy_pretty.for_type_by_name('numpy', 'dtype', ipy_pretty.dtype_pprinter)
+"""
+
+import IPython.ipapi
+from IPython.genutils import Term
+
+from IPython.external import pretty
+
+ip = IPython.ipapi.get()
+
+
+#### Implementation ############################################################
+
+def pretty_result_display(self, arg):
+ """ Uber-pretty-printing display hook.
+
+ Called for displaying the result to the user.
+ """
+
+ if ip.options.pprint:
+ verbose = getattr(ip.options, 'pretty_verbose', False)
+ out = pretty.pretty(arg, verbose=verbose)
+ if '\n' in out:
+ # So that multi-line strings line up with the left column of
+ # the screen, instead of having the output prompt mess up
+ # their first line.
+ Term.cout.write('\n')
+ print >>Term.cout, out
+ else:
+ raise TryNext
+
+
+#### API #######################################################################
+
+# Expose the for_type and for_type_by_name functions for easier use.
+for_type = pretty.for_type
+for_type_by_name = pretty.for_type_by_name
+
+
+# FIXME: write deactivate(). We need a way to remove a hook.
+def activate():
+ """ Activate this extension.
+ """
+ ip.set_hook('result_display', pretty_result_display, priority=99)
+
+
+#### Example pretty-printers ###################################################
+
+def dtype_pprinter(obj, p, cycle):
+ """ A pretty-printer for numpy dtype objects.
+ """
+ if cycle:
+ return p.text('dtype(...)')
+ if obj.fields is None:
+ p.text(repr(obj))
+ else:
+ p.begin_group(7, 'dtype([')
+ for i, field in enumerate(obj.descr):
+ if i > 0:
+ p.text(',')
+ p.breakable()
+ p.pretty(field)
+ p.end_group(7, '])')
+
+
+#### Tests #####################################################################
+
+def test_pretty():
+ """
+ In [1]: from IPython.Extensions import ipy_pretty
+
+ In [2]: ipy_pretty.activate()
+
+ In [3]: class A(object):
+ ...: def __repr__(self):
+ ...: return 'A()'
+ ...:
+ ...:
+
+ In [4]: a = A()
+
+ In [5]: a
+ Out[5]: A()
+
+ In [6]: def a_pretty_printer(obj, p, cycle):
+ ...: p.text('<A>')
+ ...:
+ ...:
+
+ In [7]: ipy_pretty.for_type(A, a_pretty_printer)
+
+ In [8]: a
+ Out[8]: <A>
+
+ In [9]: class B(object):
+ ...: def __repr__(self):
+ ...: return 'B()'
+ ...:
+ ...:
+
+ In [10]: B.__module__, B.__name__
+ Out[10]: ('__main__', 'B')
+
+ In [11]: def b_pretty_printer(obj, p, cycle):
+ ....: p.text('<B>')
+ ....:
+ ....:
+
+ In [12]: ipy_pretty.for_type_by_name('__main__', 'B', b_pretty_printer)
+
+ In [13]: b = B()
+
+ In [14]: b
+ Out[14]: <B>
+ """
+ assert False, "This should only be doctested, not run."
+
diff --git a/IPython/Extensions/ipy_profile_doctest.py b/IPython/Extensions/ipy_profile_doctest.py
new file mode 100644
index 0000000..b35074e
--- /dev/null
+++ b/IPython/Extensions/ipy_profile_doctest.py
@@ -0,0 +1,46 @@
+"""Config file for 'doctest' profile.
+
+This profile modifies the prompts to be the standard Python ones, so that you
+can generate easily doctests from an IPython session.
+
+But more importantly, it enables pasting of code with '>>>' prompts and
+arbitrary initial whitespace, as is typical of doctests in reST files and
+docstrings. This allows you to easily re-run existing doctests and iteratively
+work on them as part of your development workflow.
+
+The exception mode is also set to 'plain' so the generated exceptions are as
+similar as possible to the default Python ones, for inclusion in doctests."""
+
+# get various stuff that are there for historical / familiarity reasons
+import ipy_legacy
+
+from IPython import ipapi
+
+from IPython.Extensions import InterpreterPasteInput
+
+def main():
+ ip = ipapi.get()
+ o = ip.options
+
+ # Set the prompts similar to the defaults
+ o.prompt_in1 = '>>> '
+ o.prompt_in2 = '... '
+ o.prompt_out = ''
+
+ # Add a blank line before each new set of inputs. This is needed by
+ # doctest to distinguish each test from the next.
+ o.separate_in = '\n'
+ o.separate_out = ''
+ o.separate_out2 = ''
+
+ # Disable pprint, so that outputs are printed as similarly to standard
+ # python as possible
+ o.pprint = False
+
+ # Use plain exceptions, to also resemble normal pyhton.
+ o.xmode = 'plain'
+
+ # Store the activity flag in the metadata bag from the running shell
+ ip.IP.meta.doctest_mode = True
+
+main()
diff --git a/IPython/Extensions/ipy_profile_none.py b/IPython/Extensions/ipy_profile_none.py
new file mode 100644
index 0000000..195aa87
--- /dev/null
+++ b/IPython/Extensions/ipy_profile_none.py
@@ -0,0 +1,4 @@
+""" Config file for 'default' profile """
+
+# get various stuff that are there for historical / familiarity reasons
+import ipy_legacy \ No newline at end of file
diff --git a/IPython/Extensions/ipy_profile_numpy.py b/IPython/Extensions/ipy_profile_numpy.py
new file mode 100644
index 0000000..a722627
--- /dev/null
+++ b/IPython/Extensions/ipy_profile_numpy.py
@@ -0,0 +1,24 @@
+""" IPython 'numpy' profile, to preload NumPy.
+
+This profile loads the math/cmath modules as well as all of numpy.
+
+It exposes numpy via the 'np' shorthand as well for convenience.
+"""
+
+import IPython.ipapi
+import ipy_defaults
+
+def main():
+ ip = IPython.ipapi.get()
+
+ try:
+ ip.ex("import math,cmath")
+ ip.ex("import numpy")
+ ip.ex("import numpy as np")
+
+ ip.ex("from numpy import *")
+
+ except ImportError:
+ print "Unable to start NumPy profile, is numpy installed?"
+
+main()
diff --git a/IPython/Extensions/ipy_profile_scipy.py b/IPython/Extensions/ipy_profile_scipy.py
new file mode 100644
index 0000000..907448a
--- /dev/null
+++ b/IPython/Extensions/ipy_profile_scipy.py
@@ -0,0 +1,29 @@
+""" IPython 'scipy' profile, preloads NumPy and SciPy.
+
+This profile loads the math/cmath modules as well as all of numpy and scipy.
+
+It exposes numpy and scipy via the 'np' and 'sp' shorthands as well for
+convenience.
+"""
+
+import IPython.ipapi
+import ipy_defaults
+
+def main():
+ ip = IPython.ipapi.get()
+
+ try:
+ ip.ex("import math,cmath")
+ ip.ex("import numpy")
+ ip.ex("import scipy")
+
+ ip.ex("import numpy as np")
+ ip.ex("import scipy as sp")
+
+ ip.ex("from numpy import *")
+ ip.ex("from scipy import *")
+
+ except ImportError:
+ print "Unable to start scipy profile, are numpy and scipy installed?"
+
+main()
diff --git a/IPython/Extensions/ipy_profile_sh.py b/IPython/Extensions/ipy_profile_sh.py
new file mode 100644
index 0000000..f320a3d
--- /dev/null
+++ b/IPython/Extensions/ipy_profile_sh.py
@@ -0,0 +1,270 @@
+"""Shell mode for IPython.
+
+Start ipython in shell mode by invoking "ipython -p sh"
+
+(the old version, "ipython -p pysh" still works but this is the more "modern"
+shell mode and is recommended for users who don't care about pysh-mode
+compatibility)
+"""
+
+from IPython import ipapi
+import os,re,textwrap
+
+# The import below effectively obsoletes your old-style ipythonrc[.ini],
+# so consider yourself warned!
+
+import ipy_defaults
+
+def main():
+ ip = ipapi.get()
+ o = ip.options
+ # autocall to "full" mode (smart mode is default, I like full mode)
+
+ o.autocall = 2
+
+ # Jason Orendorff's path class is handy to have in user namespace
+ # if you are doing shell-like stuff
+ try:
+ ip.ex("from IPython.external.path import path" )
+ except ImportError:
+ pass
+
+ # beefed up %env is handy in shell mode
+ import envpersist
+
+ # To see where mycmd resides (in path/aliases), do %which mycmd
+ import ipy_which
+
+ # tab completers for hg, svn, ...
+ import ipy_app_completers
+
+ # To make executables foo and bar in mybin usable without PATH change, do:
+ # %rehashdir c:/mybin
+ # %store foo
+ # %store bar
+ import ipy_rehashdir
+
+ # does not work without subprocess module!
+ #import ipy_signals
+
+ ip.ex('import os')
+ ip.ex("def up(): os.chdir('..')")
+ ip.user_ns['LA'] = LastArgFinder()
+
+ # You can assign to _prompt_title variable
+ # to provide some extra information for prompt
+ # (e.g. the current mode, host/username...)
+
+ ip.user_ns['_prompt_title'] = ''
+
+ # Nice prompt
+ o.prompt_in1= r'\C_Green${_prompt_title}\C_LightBlue[\C_LightCyan\Y2\C_LightBlue]\C_Green|\#> '
+ o.prompt_in2= r'\C_Green|\C_LightGreen\D\C_Green> '
+ o.prompt_out= '<\#> '
+
+ from IPython import Release
+
+ import sys
+ # Non-chatty banner
+ o.banner = "IPython %s [on Py %s]\n" % (Release.version,sys.version.split(None,1)[0])
+
+
+ ip.IP.default_option('cd','-q')
+ ip.IP.default_option('macro', '-r')
+ # If you only rarely want to execute the things you %edit...
+ #ip.IP.default_option('edit','-x')
+
+
+ o.prompts_pad_left="1"
+ # Remove all blank lines in between prompts, like a normal shell.
+ o.separate_in="0"
+ o.separate_out="0"
+ o.separate_out2="0"
+
+ # now alias all syscommands
+
+ db = ip.db
+
+ syscmds = db.get("syscmdlist",[] )
+ if not syscmds:
+ print textwrap.dedent("""
+ System command list not initialized, probably the first run...
+ running %rehashx to refresh the command list. Run %rehashx
+ again to refresh command list (after installing new software etc.)
+ """)
+ ip.magic('rehashx')
+ syscmds = db.get("syscmdlist")
+
+ # lowcase aliases on win32 only
+ if os.name == 'posix':
+ mapper = lambda s:s
+ else:
+ def mapper(s): return s.lower()
+
+ for cmd in syscmds:
+ # print "sys",cmd #dbg
+ noext, ext = os.path.splitext(cmd)
+ if ext.lower() == '.exe':
+ cmd = noext
+
+ key = mapper(cmd)
+ if key not in ip.IP.alias_table:
+ # Dots will be removed from alias names, since ipython
+ # assumes names with dots to be python code
+
+ ip.defalias(key.replace('.',''), cmd)
+
+ # mglob combines 'find', recursion, exclusion... '%mglob?' to learn more
+ ip.load("IPython.external.mglob")
+
+ # win32 is crippled w/o cygwin, try to help it a little bit
+ if sys.platform == 'win32':
+ if 'cygwin' in os.environ['PATH'].lower():
+ # use the colors of cygwin ls (recommended)
+ ip.defalias('d', 'ls -F --color=auto')
+ else:
+ # get icp, imv, imkdir, igrep, irm,...
+ ip.load('ipy_fsops')
+
+ # and the next best thing to real 'ls -F'
+ ip.defalias('d','dir /w /og /on')
+
+ ip.set_hook('input_prefilter', slash_prefilter_f)
+ extend_shell_behavior(ip)
+
+class LastArgFinder:
+ """ Allow $LA to work as "last argument of previous command", like $! in bash
+
+ To call this in normal IPython code, do LA()
+ """
+ def __call__(self, hist_idx = None):
+ ip = ipapi.get()
+ if hist_idx is None:
+ return str(self)
+ return ip.IP.input_hist_raw[hist_idx].strip().split()[-1]
+ def __str__(self):
+ ip = ipapi.get()
+ for cmd in reversed(ip.IP.input_hist_raw):
+ parts = cmd.strip().split()
+ if len(parts) < 2 or parts[-1] in ['$LA', 'LA()']:
+ continue
+ return parts[-1]
+ return ""
+
+def slash_prefilter_f(self,line):
+ """ ./foo, ~/foo and /bin/foo now run foo as system command
+
+ Removes the need for doing !./foo, !~/foo or !/bin/foo
+ """
+ import IPython.genutils
+ if re.match('(?:[.~]|/[a-zA-Z_0-9]+)/', line):
+ return "_ip.system(" + IPython.genutils.make_quoted_expr(line)+")"
+ raise ipapi.TryNext
+
+# XXX You do not need to understand the next function!
+# This should probably be moved out of profile
+
+def extend_shell_behavior(ip):
+
+ # Instead of making signature a global variable tie it to IPSHELL.
+ # In future if it is required to distinguish between different
+ # shells we can assign a signature per shell basis
+ ip.IP.__sig__ = 0xa005
+ # mark the IPSHELL with this signature
+ ip.IP.user_ns['__builtins__'].__dict__['__sig__'] = ip.IP.__sig__
+
+ from IPython.Itpl import ItplNS
+ from IPython.genutils import shell
+ # utility to expand user variables via Itpl
+ # xxx do something sensible with depth?
+ ip.IP.var_expand = lambda cmd, lvars=None, depth=2: \
+ str(ItplNS(cmd, ip.IP.user_ns, get_locals()))
+
+ def get_locals():
+ """ Substituting a variable through Itpl deep inside the IPSHELL stack
+ requires the knowledge of all the variables in scope upto the last
+ IPSHELL frame. This routine simply merges all the local variables
+ on the IPSHELL stack without worrying about their scope rules
+ """
+ import sys
+ # note lambda expression constitues a function call
+ # hence fno should be incremented by one
+ getsig = lambda fno: sys._getframe(fno+1).f_globals \
+ ['__builtins__'].__dict__['__sig__']
+ getlvars = lambda fno: sys._getframe(fno+1).f_locals
+ # trackback until we enter the IPSHELL
+ frame_no = 1
+ sig = ip.IP.__sig__
+ fsig = ~sig
+ while fsig != sig :
+ try:
+ fsig = getsig(frame_no)
+ except (AttributeError, KeyError):
+ frame_no += 1
+ except ValueError:
+ # stack is depleted
+ # call did not originate from IPSHELL
+ return {}
+ first_frame = frame_no
+ # walk further back until we exit from IPSHELL or deplete stack
+ try:
+ while(sig == getsig(frame_no+1)):
+ frame_no += 1
+ except (AttributeError, KeyError, ValueError):
+ pass
+ # merge the locals from top down hence overriding
+ # any re-definitions of variables, functions etc.
+ lvars = {}
+ for fno in range(frame_no, first_frame-1, -1):
+ lvars.update(getlvars(fno))
+ #print '\n'*5, first_frame, frame_no, '\n', lvars, '\n'*5 #dbg
+ return lvars
+
+ def _runlines(lines):
+ """Run a string of one or more lines of source.
+
+ This method is capable of running a string containing multiple source
+ lines, as if they had been entered at the IPython prompt. Since it
+ exposes IPython's processing machinery, the given strings can contain
+ magic calls (%magic), special shell access (!cmd), etc."""
+
+ # We must start with a clean buffer, in case this is run from an
+ # interactive IPython session (via a magic, for example).
+ ip.IP.resetbuffer()
+ lines = lines.split('\n')
+ more = 0
+ command = ''
+ for line in lines:
+ # skip blank lines so we don't mess up the prompt counter, but do
+ # NOT skip even a blank line if we are in a code block (more is
+ # true)
+ # if command is not empty trim the line
+ if command != '' :
+ line = line.strip()
+ # add the broken line to the command
+ if line and line[-1] == '\\' :
+ command += line[0:-1] + ' '
+ more = True
+ continue
+ else :
+ # add the last (current) line to the command
+ command += line
+ if command or more:
+ # push to raw history, so hist line numbers stay in sync
+ ip.IP.input_hist_raw.append("# " + command + "\n")
+
+ more = ip.IP.push(ip.IP.prefilter(command,more))
+ command = ''
+ # IPython's runsource returns None if there was an error
+ # compiling the code. This allows us to stop processing right
+ # away, so the user gets the error message at the right place.
+ if more is None:
+ break
+ # final newline in case the input didn't have it, so that the code
+ # actually does get executed
+ if more:
+ ip.IP.push('\n')
+
+ ip.IP.runlines = _runlines
+
+main()
diff --git a/IPython/Extensions/ipy_profile_zope.py b/IPython/Extensions/ipy_profile_zope.py
new file mode 100644
index 0000000..172853c
--- /dev/null
+++ b/IPython/Extensions/ipy_profile_zope.py
@@ -0,0 +1,320 @@
+# -*- coding: utf-8 -*-
+""" An ipython profile for zope and plone.
+
+Some ideas stolen from http://www.tomster.org.
+
+
+Authors
+-------
+- Stefan Eletzhofer <stefan.eletzhofer@inquant.de>
+"""
+
+# File: ipy_profile_zope.py
+#
+# Copyright (c) InQuant GmbH
+#
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+
+from IPython import ipapi
+from IPython import Release
+from types import StringType
+import sys
+import os
+import textwrap
+
+# The import below effectively obsoletes your old-style ipythonrc[.ini],
+# so consider yourself warned!
+# import ipy_defaults
+
+_marker = []
+def shasattr(obj, attr, acquire=False):
+ """ See Archetypes/utils.py
+ """
+ if not acquire:
+ obj = obj.aq_base
+ return getattr(obj, attr, _marker) is not _marker
+
+class ZopeDebug(object):
+ def __init__(self):
+
+ self.instancehome = os.environ.get( "INSTANCE_HOME" )
+
+ configfile = os.environ.get( "CONFIG_FILE" )
+ if configfile is None and self.instancehome is not None:
+ configfile = os.path.join( self.instancehome, "etc", "zope.conf" )
+
+ if configfile is None:
+ raise RuntimeError( "CONFIG_FILE env not set" )
+
+ print "CONFIG_FILE=", configfile
+ print "INSTANCE_HOME=", self.instancehome
+
+ self.configfile = configfile
+
+ try:
+ from Zope2 import configure
+ except ImportError:
+ from Zope import configure
+
+ configure( configfile )
+
+ try:
+ import Zope2
+ app = Zope2.app()
+ except ImportError:
+ import Zope
+ app = Zope.app()
+
+ from Testing.makerequest import makerequest
+ self.app = makerequest( app )
+
+ try:
+ self._make_permissive()
+ print "Permissive security installed"
+ except:
+ print "Permissive security NOT installed"
+
+ self._pwd = self.portal or self.app
+
+ try:
+ from zope.component import getSiteManager
+ from zope.component import getGlobalSiteManager
+ from zope.app.component.hooks import setSite
+
+ if self.portal is not None:
+ setSite( self.portal )
+
+ gsm = getGlobalSiteManager()
+ sm = getSiteManager()
+
+ if sm is gsm:
+ print "ERROR SETTING SITE!"
+ except:
+ pass
+
+
+ @property
+ def utils(self):
+ class Utils(object):
+ commit = self.commit
+ sync = self.sync
+ objectInfo = self.objectInfo
+ ls = self.ls
+ pwd = self.pwd
+ cd = self.cd
+ su = self.su
+ getCatalogInfo = self.getCatalogInfo
+
+ @property
+ def cwd(self):
+ return self.pwd()
+
+ return Utils()
+
+ @property
+ def namespace(self):
+ return dict( utils=self.utils, app=self.app, portal=self.portal )
+
+ @property
+ def portal(self):
+ portals = self.app.objectValues( "Plone Site" )
+ if len(portals):
+ return portals[0]
+ else:
+ raise KeyError( "No Plone Site found.")
+
+ def pwd(self):
+ return self._pwd
+
+ def _make_permissive(self):
+ """
+ Make a permissive security manager with all rights. Hell,
+ we're developers, aren't we? Security is for whimps. :)
+ """
+ from Products.CMFCore.tests.base.security import PermissiveSecurityPolicy
+ import AccessControl
+ from AccessControl.SecurityManagement import newSecurityManager
+ from AccessControl.SecurityManager import setSecurityPolicy
+
+ _policy = PermissiveSecurityPolicy()
+ self.oldpolicy = setSecurityPolicy(_policy)
+ newSecurityManager(None, AccessControl.User.system)
+
+ def su(self, username):
+ """ Change to named user.
+ """
+ # TODO Make it easy to change back to permissive security.
+ user = self.portal.acl_users.getUser(username)
+ if not user:
+ print "Can't find %s in %s" % (username, self.portal.acl_users)
+ return
+
+ from AccessControl import ZopeSecurityPolicy
+ import AccessControl
+ from AccessControl.SecurityManagement import newSecurityManager, getSecurityManager
+ from AccessControl.SecurityManager import setSecurityPolicy
+
+ _policy = ZopeSecurityPolicy
+ self.oldpolicy = setSecurityPolicy(_policy)
+ wrapped_user = user.__of__(self.portal.acl_users)
+ newSecurityManager(None, user)
+ print 'User changed.'
+ return getSecurityManager().getUser()
+
+ def getCatalogInfo(self, obj=None, catalog='portal_catalog', query=None, sort_on='created', sort_order='reverse' ):
+ """ Inspect portal_catalog. Pass an object or object id for a
+ default query on that object, or pass an explicit query.
+ """
+ if obj and query:
+ print "Ignoring %s, using query." % obj
+
+ catalog = self.portal.get(catalog)
+ if not catalog:
+ return 'No catalog'
+
+ indexes = catalog._catalog.indexes
+ if not query:
+ if type(obj) is StringType:
+ cwd = self.pwd()
+ obj = cwd.unrestrictedTraverse( obj )
+ # If the default in the signature is mutable, its value will
+ # persist across invocations.
+ query = {}
+ if indexes.get('path'):
+ from string import join
+ path = join(obj.getPhysicalPath(), '/')
+ query.update({'path': path})
+ if indexes.get('getID'):
+ query.update({'getID': obj.id, })
+ if indexes.get('UID') and shasattr(obj, 'UID'):
+ query.update({'UID': obj.UID(), })
+ if indexes.get(sort_on):
+ query.update({'sort_on': sort_on, 'sort_order': sort_order})
+ if not query:
+ return 'Empty query'
+ results = catalog(**query)
+
+ result_info = []
+ for r in results:
+ rid = r.getRID()
+ if rid:
+ result_info.append(
+ {'path': catalog.getpath(rid),
+ 'metadata': catalog.getMetadataForRID(rid),
+ 'indexes': catalog.getIndexDataForRID(rid), }
+ )
+ else:
+ result_info.append({'missing': rid})
+
+ if len(result_info) == 1:
+ return result_info[0]
+ return result_info
+
+ def commit(self):
+ """
+ Commit the transaction.
+ """
+ try:
+ import transaction
+ transaction.get().commit()
+ except ImportError:
+ get_transaction().commit()
+
+ def sync(self):
+ """
+ Sync the app's view of the zodb.
+ """
+ self.app._p_jar.sync()
+
+ def objectInfo( self, o ):
+ """
+ Return a descriptive string of an object
+ """
+ Title = ""
+ t = getattr( o, 'Title', None )
+ if t:
+ Title = t()
+ return {'id': o.getId(),
+ 'Title': Title,
+ 'portal_type': getattr( o, 'portal_type', o.meta_type),
+ 'folderish': o.isPrincipiaFolderish
+ }
+
+ def cd( self, path ):
+ """
+ Change current dir to a specific folder.
+
+ cd( ".." )
+ cd( "/plone/Members/admin" )
+ cd( portal.Members.admin )
+ etc.
+ """
+ if type(path) is not StringType:
+ path = '/'.join(path.getPhysicalPath())
+ cwd = self.pwd()
+ x = cwd.unrestrictedTraverse( path )
+ if x is None:
+ raise KeyError( "Can't cd to %s" % path )
+
+ print "%s -> %s" % ( self.pwd().getId(), x.getId() )
+ self._pwd = x
+
+ def ls( self, x=None ):
+ """
+ List object(s)
+ """
+ if type(x) is StringType:
+ cwd = self.pwd()
+ x = cwd.unrestrictedTraverse( x )
+ if x is None:
+ x = self.pwd()
+ if x.isPrincipiaFolderish:
+ return [self.objectInfo(o) for id, o in x.objectItems()]
+ else:
+ return self.objectInfo( x )
+
+zope_debug = None
+
+def ipy_set_trace():
+ import IPython; IPython.Debugger.Pdb().set_trace()
+
+def main():
+ global zope_debug
+ ip = ipapi.get()
+ o = ip.options
+ # autocall to "full" mode (smart mode is default, I like full mode)
+
+ SOFTWARE_HOME = os.environ.get( "SOFTWARE_HOME" )
+ sys.path.append( SOFTWARE_HOME )
+ print "SOFTWARE_HOME=%s\n" % SOFTWARE_HOME
+
+ zope_debug = ZopeDebug()
+
+ # <HACK ALERT>
+ import pdb;
+ pdb.set_trace = ipy_set_trace
+ # </HACK ALERT>
+
+ # I like my banner minimal.
+ o.banner = "ZOPE Py %s IPy %s\n" % (sys.version.split('\n')[0],Release.version)
+
+ print textwrap.dedent("""\
+ ZOPE mode iPython shell.
+
+ Bound names:
+ app
+ portal
+ utils.{ %s }
+
+ Uses the $SOFTWARE_HOME and $CONFIG_FILE environment
+ variables.
+ """ % ( ",".join([ x for x in dir(zope_debug.utils) if not x.startswith("_") ] ) ) )
+
+
+ ip.user_ns.update( zope_debug.namespace )
+
+
+main()
+# vim: set ft=python ts=4 sw=4 expandtab :
diff --git a/IPython/Extensions/ipy_pydb.py b/IPython/Extensions/ipy_pydb.py
new file mode 100644
index 0000000..ee30523
--- /dev/null
+++ b/IPython/Extensions/ipy_pydb.py
@@ -0,0 +1,31 @@
+import inspect
+import IPython.ipapi
+from IPython.genutils import arg_split
+ip = IPython.ipapi.get()
+
+from IPython import Debugger
+
+def call_pydb(self, args):
+ """Invoke pydb with the supplied parameters."""
+ try:
+ import pydb
+ except ImportError:
+ raise ImportError("pydb doesn't seem to be installed.")
+
+ if not hasattr(pydb.pydb, "runv"):
+ raise ImportError("You need pydb version 1.19 or later installed.")
+
+ argl = arg_split(args)
+ # print argl # dbg
+ if len(inspect.getargspec(pydb.runv)[0]) == 2:
+ pdb = Debugger.Pdb(color_scheme=self.rc.colors)
+ ip.IP.history_saving_wrapper( lambda : pydb.runv(argl, pdb) )()
+ else:
+ ip.IP.history_saving_wrapper( lambda : pydb.runv(argl) )()
+
+
+ip.expose_magic("pydb",call_pydb)
+
+
+
+
diff --git a/IPython/Extensions/ipy_rehashdir.py b/IPython/Extensions/ipy_rehashdir.py
new file mode 100644
index 0000000..15abcec
--- /dev/null
+++ b/IPython/Extensions/ipy_rehashdir.py
@@ -0,0 +1,140 @@
+# -*- coding: utf-8 -*-
+""" IPython extension: add %rehashdir magic
+
+Usage:
+
+%rehashdir c:/bin c:/tools
+ - Add all executables under c:/bin and c:/tools to alias table, in
+ order to make them directly executable from any directory.
+
+This also serves as an example on how to extend ipython
+with new magic functions.
+
+Unlike rest of ipython, this requires Python 2.4 (optional
+extensions are allowed to do that).
+
+"""
+
+import IPython.ipapi
+ip = IPython.ipapi.get()
+
+
+import os,re,fnmatch,sys
+
+def selflaunch(ip,line):
+ """ Launch python script with 'this' interpreter
+
+ e.g. d:\foo\ipykit.exe a.py
+
+ """
+
+ tup = line.split(None,1)
+ if len(tup) == 1:
+ print "Launching nested ipython session"
+ os.system(sys.executable)
+ return
+
+ cmd = sys.executable + ' ' + tup[1]
+ print ">",cmd
+ os.system(cmd)
+
+class PyLauncher:
+ """ Invoke selflanucher on the specified script
+
+ This is mostly useful for associating with scripts using::
+ _ip.defalias('foo',PyLauncher('foo_script.py'))
+
+ """
+ def __init__(self,script):
+ self.script = os.path.abspath(script)
+ def __call__(self, ip, line):
+ if self.script.endswith('.ipy'):
+ ip.runlines(open(self.script).read())
+ else:
+ # first word is the script/alias name itself, strip it
+ tup = line.split(None,1)
+ if len(tup) == 2:
+ tail = ' ' + tup[1]
+ else:
+ tail = ''
+
+ selflaunch(ip,"py " + self.script + tail)
+ def __repr__(self):
+ return 'PyLauncher("%s")' % self.script
+
+def rehashdir_f(self,arg):
+ """ Add executables in all specified dirs to alias table
+
+ Usage:
+
+ %rehashdir c:/bin;c:/tools
+ - Add all executables under c:/bin and c:/tools to alias table, in
+ order to make them directly executable from any directory.
+
+ Without arguments, add all executables in current directory.
+
+ """
+
+ # most of the code copied from Magic.magic_rehashx
+
+ def isjunk(fname):
+ junk = ['*~']
+ for j in junk:
+ if fnmatch.fnmatch(fname, j):
+ return True
+ return False
+
+ created = []
+ if not arg:
+ arg = '.'
+ path = map(os.path.abspath,arg.split(';'))
+ alias_table = self.shell.alias_table
+
+ if os.name == 'posix':
+ isexec = lambda fname:os.path.isfile(fname) and \
+ os.access(fname,os.X_OK)
+ else:
+
+ try:
+ winext = os.environ['pathext'].replace(';','|').replace('.','')
+ except KeyError:
+ winext = 'exe|com|bat|py'
+ if 'py' not in winext:
+ winext += '|py'
+
+ execre = re.compile(r'(.*)\.(%s)$' % winext,re.IGNORECASE)
+ isexec = lambda fname:os.path.isfile(fname) and execre.match(fname)
+ savedir = os.getcwd()
+ try:
+ # write the whole loop for posix/Windows so we don't have an if in
+ # the innermost part
+ if os.name == 'posix':
+ for pdir in path:
+ os.chdir(pdir)
+ for ff in os.listdir(pdir):
+ if isexec(ff) and not isjunk(ff):
+ # each entry in the alias table must be (N,name),
+ # where N is the number of positional arguments of the
+ # alias.
+ src,tgt = os.path.splitext(ff)[0], os.path.abspath(ff)
+ created.append(src)
+ alias_table[src] = (0,tgt)
+ else:
+ for pdir in path:
+ os.chdir(pdir)
+ for ff in os.listdir(pdir):
+ if isexec(ff) and not isjunk(ff):
+ src, tgt = execre.sub(r'\1',ff), os.path.abspath(ff)
+ src = src.lower()
+ created.append(src)
+ alias_table[src] = (0,tgt)
+ # Make sure the alias table doesn't contain keywords or builtins
+ self.shell.alias_table_validate()
+ # Call again init_auto_alias() so we get 'rm -i' and other
+ # modified aliases since %rehashx will probably clobber them
+ # self.shell.init_auto_alias()
+ finally:
+ os.chdir(savedir)
+ return created
+
+ip.expose_magic("rehashdir",rehashdir_f)
diff --git a/IPython/Extensions/ipy_render.py b/IPython/Extensions/ipy_render.py
new file mode 100644
index 0000000..3946a87
--- /dev/null
+++ b/IPython/Extensions/ipy_render.py
@@ -0,0 +1,68 @@
+#!/usr/bin/env python
+
+""" IPython extension: Render templates from variables and paste to clipbard """
+
+import IPython.ipapi
+
+ip = IPython.ipapi.get()
+
+from string import Template
+import sys,os
+
+from IPython.Itpl import itplns
+
+def toclip_w32(s):
+ """ Places contents of s to clipboard
+
+ Needs pyvin32 to work:
+ http://sourceforge.net/projects/pywin32/
+ """
+ import win32clipboard as cl
+ import win32con
+ cl.OpenClipboard()
+ cl.EmptyClipboard()
+ cl.SetClipboardText( s.replace('\n','\r\n' ))
+ cl.CloseClipboard()
+
+try:
+ import win32clipboard
+ toclip = toclip_w32
+except ImportError:
+ def toclip(s): pass
+
+
+def render(tmpl):
+ """ Render a template (Itpl format) from ipython variables
+
+ Example:
+
+ $ import ipy_render
+ $ my_name = 'Bob' # %store this for convenience
+ $ t_submission_form = "Submission report, author: $my_name" # %store also
+ $ render t_submission_form
+
+ => returns "Submission report, author: Bob" and copies to clipboard on win32
+
+ # if template exist as a file, read it. Note: ;f hei vaan => f("hei vaan")
+ $ ;render c:/templates/greeting.txt
+
+ Template examples (Ka-Ping Yee's Itpl library):
+
+ Here is a $string.
+ Here is a $module.member.
+ Here is an $object.member.
+ Here is a $functioncall(with, arguments).
+ Here is an ${arbitrary + expression}.
+ Here is an $array[3] member.
+ Here is a $dictionary['member'].
+ """
+
+ if os.path.isfile(tmpl):
+ tmpl = open(tmpl).read()
+
+ res = itplns(tmpl, ip.user_ns)
+ toclip(res)
+ return res
+
+ip.to_user_ns('render')
+ \ No newline at end of file
diff --git a/IPython/Extensions/ipy_server.py b/IPython/Extensions/ipy_server.py
new file mode 100644
index 0000000..cd4c55b
--- /dev/null
+++ b/IPython/Extensions/ipy_server.py
@@ -0,0 +1,38 @@
+""" Simple TCP socket server that executes statements in IPython instance.
+
+Usage:
+
+import ipy_server
+ipy_server.serve_thread(16455)
+
+Now, to execute the statements in this ipython instance, open a TCP socket
+(port 16455), write out the statements, and close the socket.
+You can use e.g. "telnet localhost 16455" or a script to do this.
+
+This is a bit like 'M-x server-start" or gnuserv in the emacs world.
+
+"""
+
+import IPython.ipapi
+ip = IPython.ipapi.get()
+
+import SocketServer
+
+# user-accessible port
+PORT = 8099
+
+class IPythonRequestHandler(SocketServer.StreamRequestHandler):
+ def handle(self):
+ #print "connection from", self.client_address
+ inp = self.rfile.read().replace('\r\n','\n')
+ #print "Execute",inp
+ ip.runlines(inp)
+
+def serve(port = PORT):
+ server = SocketServer.TCPServer(("", port), IPythonRequestHandler)
+ print "ipy_server on TCP port", port
+ server.serve_forever()
+
+def serve_thread(port = PORT):
+ import thread
+ thread.start_new_thread(serve, (port,)) \ No newline at end of file
diff --git a/IPython/Extensions/ipy_signals.py b/IPython/Extensions/ipy_signals.py
new file mode 100644
index 0000000..8debc62
--- /dev/null
+++ b/IPython/Extensions/ipy_signals.py
@@ -0,0 +1,62 @@
+""" Advanced signal (e.g. ctrl+C) handling for IPython
+
+So far, this only ignores ctrl + C in IPython file a subprocess
+is executing, to get closer to how a "proper" shell behaves.
+
+Other signal processing may be implemented later on.
+
+If _ip.options.verbose is true, show exit status if nonzero
+
+"""
+
+import signal,os,sys
+import IPython.ipapi
+import subprocess
+
+ip = IPython.ipapi.get()
+
+def new_ipsystem_posix(cmd):
+ """ ctrl+c ignoring replacement for system() command in iplib.
+
+ Ignore ctrl + c in IPython process during the command execution.
+ The subprocess will still get the ctrl + c signal.
+
+ posix implementation
+ """
+
+ p = subprocess.Popen(cmd, shell = True)
+
+ old_handler = signal.signal(signal.SIGINT, signal.SIG_IGN)
+ pid,status = os.waitpid(p.pid,0)
+ signal.signal(signal.SIGINT, old_handler)
+ if status and ip.options.verbose:
+ print "[exit status: %d]" % status
+
+def new_ipsystem_win32(cmd):
+ """ ctrl+c ignoring replacement for system() command in iplib.
+
+ Ignore ctrl + c in IPython process during the command execution.
+ The subprocess will still get the ctrl + c signal.
+
+ win32 implementation
+ """
+ old_handler = signal.signal(signal.SIGINT, signal.SIG_IGN)
+ status = os.system(cmd)
+ signal.signal(signal.SIGINT, old_handler)
+ if status and ip.options.verbose:
+ print "[exit status: %d]" % status
+
+
+def init():
+ o = ip.options
+ try:
+ o.verbose
+ except AttributeError:
+ o.allow_new_attr (True )
+ o.verbose = 0
+
+ ip.IP.system = (sys.platform == 'win32' and new_ipsystem_win32 or
+ new_ipsystem_posix)
+
+init()
+ \ No newline at end of file
diff --git a/IPython/Extensions/ipy_stock_completers.py b/IPython/Extensions/ipy_stock_completers.py
new file mode 100644
index 0000000..2714e0b
--- /dev/null
+++ b/IPython/Extensions/ipy_stock_completers.py
@@ -0,0 +1,17 @@
+""" Install various IPython completers
+
+IPython extension that installs completers related to core ipython behaviour.
+
+The actual implementations are in Extensions/ipy_completers.py
+
+"""
+import IPython.ipapi
+
+ip = IPython.ipapi.get()
+
+from ipy_completers import *
+
+ip.set_hook('complete_command', module_completer, str_key = 'import')
+ip.set_hook('complete_command', module_completer, str_key = 'from')
+ip.set_hook('complete_command', runlistpy, str_key = '%run')
+ip.set_hook('complete_command', cd_completer, str_key = '%cd')
diff --git a/IPython/Extensions/ipy_synchronize_with.py b/IPython/Extensions/ipy_synchronize_with.py
new file mode 100644
index 0000000..d6222b6
--- /dev/null
+++ b/IPython/Extensions/ipy_synchronize_with.py
@@ -0,0 +1,242 @@
+import IPython.ipapi
+ip = IPython.ipapi.get()
+
+import win32api
+import win32ui
+import win32console
+import dde
+import os
+import scitedirector
+
+# test to write.
+
+def set_hook(synchronize_with_editor):
+ """Set the synchronize with editor hook with a callable object.
+
+ The callable object will be called with the following arguments when
+ IPython wants to synchronize with you favorite editor:
+
+ - ip: a running IPython instance.
+
+ - filename: the path of the file the editor is supposed to display.
+
+ - lineno : the line number of the line the editor is supposed to
+ highlight.
+
+ - columnno : the column number of the character the editor is supposed
+ to highlight.
+ """
+ ip.set_hook("synchronize_with_editor", synchronize_with_editor)
+
+
+def find_filename(filename):
+ """Return the filename to synchronize with based on """
+ filename = os.path.splitext(filename)
+ if filename[1] == ".pyc":
+ filename = (filename[0], ".py")
+ filename = "".join(filename)
+
+ if not os.path.isabs(filename):
+ filename = os.path.join(os.getcwd(), filename)
+
+ if os.path.isfile(filename):
+ return filename
+
+ return ""
+
+
+def run_command(path, command, arguments, asynchronous = True):
+ """Run a shell command and return the exit code of the command"""
+ # This is a thin wrapper around os.system that:
+ # - Let you run command asynchronously.
+ # - Accept spaces in command path.
+ # - Dont throw exception if the command don't exist.
+ line = ''
+ if asynchronous:
+ line += 'start '
+
+ try:
+ line += win32api.GetShortPathName(os.path.join(path, command) + ".exe") + " "
+ except:
+ print 'could not find: "%s"' % (os.path.join(path, command) + ".exe")
+ return -1
+
+ line += arguments
+ r = os.system(line)
+ return r
+
+
+def sleep(milliseconds):
+ """Wait some milliseconds."""
+ # This is used to make sure the editor did its job before we reset the focus on the console.
+ win32api.Sleep(milliseconds)
+
+
+def restore_console_focus():
+ """Restore the focus to the IPython console."""
+ h = win32console.GetConsoleWindow()
+ console_window = win32ui.CreateWindowFromHandle(h)
+ console_window.SetForegroundWindow()
+
+
+# This is the most simple example of hook:
+class GVimHook:
+ def __init__(self, path, wakeup_duration):
+ self.path = path
+ self.wakeup_duration = wakeup_duration
+
+ def __call__(self, ip, filename, lineno, columnno):
+ filename = find_filename(filename)
+
+ if not filename:
+ return
+
+ run_command(self.path, 'gvim', '--remote-silent +%d "%s"' % (lineno, filename))
+
+ sleep(self.wakeup_duration)
+
+ restore_console_focus()
+
+
+def gvim(path = r"C:\Program Files\vim\vim71", wakeup_duration = 100):
+ synchronize_with_editor = GVimHook(path, wakeup_duration)
+ set_hook(synchronize_with_editor)
+
+
+class EmacsHook:
+ def __init__(self, path, wakeup_duration, start_duration):
+ self.path = path
+ self.wakeup_duration = wakeup_duration
+ self.start_duration = start_duration
+
+ def __call__(self, ip, filename, lineno, columnno):
+ filename = find_filename(filename)
+
+ if not filename:
+ return
+
+ r = run_command(self.path, "emacsclient", '-n +%d:%d "%s" 2>nul' % (lineno, columnno, filename), False)
+ if r != 0:
+ run_command(self.path, 'runemacs', '--quick -f server-start +%d:%d "%s"' % (lineno, columnno, filename))
+ sleep(self.start_duration)
+ else:
+ sleep(self.wakeup_duration)
+
+ restore_console_focus()
+
+
+def emacs(path = r"C:\Program Files\emacs\bin", wakeup_duration = 100, start_duration = 2000):
+ synchronize_with_editor = EmacsHook(path, wakeup_duration, start_duration)
+ set_hook(synchronize_with_editor)
+
+
+class SciteHook:
+ def __init__(self, path, wakeup_duration, start_duration):
+ self.path = path
+ self.wakeup_duration = wakeup_duration
+ self.start_duration = start_duration
+
+ def __call__(self, ip, filename, lineno, columnno):
+ filename = find_filename(filename)
+
+ if not filename:
+ return
+
+ scites = scitedirector.findWindows()
+ if not scites:
+ run_command(self.path, "scite", '"-open:%s" -goto:%d' % (filename.replace("\\", "/"), lineno))
+
+ sleep(self.start_duration)
+ restore_console_focus()
+ else:
+ scite = scites[0]
+ scitedirector.sendCommand(scite, 'open:%s' % filename.replace("\\", "/"))
+ scitedirector.sendCommand(scite, "goto:%d" % lineno)
+
+
+def scite(path = r"C:\Program Files\SciTE Source Code Editor", wakeup_duration = 100, start_duration = 500):
+ synchronize_with_editor = SciteHook(path, wakeup_duration, start_duration)
+ set_hook(synchronize_with_editor)
+
+
+class NodePadPlusPlusHook:
+ def __init__(self, path, wakeup_duration):
+ self.path = path
+ self.wakeup_duration = wakeup_duration
+
+ def __call__(self, ip, filename, lineno, columnno):
+ filename = find_filename(filename)
+
+ if not filename:
+ return
+
+ run_command(self.path, "notepad++", '"%s" -n%d' % (filename, lineno))
+
+ sleep(self.wakeup_duration)
+
+ restore_console_focus()
+
+
+def notepadplusplus(path = r"C:\Program Files\Notepad++", wakeup_duration = 100):
+ synchronize_with_editor = NodePadPlusPlusHook(path, wakeup_duration)
+ set_hook(synchronize_with_editor)
+
+
+class PsPadHook:
+ def __init__(self, path, wakeup_duration):
+ self.path = path
+ self.wakeup_duration = wakeup_duration
+
+ def __call__(self, ip, filename, lineno, columnno):
+ filename = find_filename(filename)
+
+ if not filename:
+ return
+
+ run_command(self.path, "pspad", '"%s" -%d' % (filename, lineno))
+
+ sleep(self.wakeup_duration)
+
+ restore_console_focus()
+
+
+def pspad(path = r"C:\Program Files\PSPad editor", wakeup_duration = 100):
+ synchronize_with_editor = PsPadHook(path, wakeup_duration)
+ set_hook(synchronize_with_editor)
+
+
+# This is an example of DDE hook:
+class UltraEditHook:
+ def __init__(self, path, wakeup_duration, start_duration):
+ self.path = path
+ self.wakeup_duration = wakeup_duration
+ self.start_duration = start_duration
+
+ def __call__(self, ip, filename, lineno, columnno):
+ filename = find_filename(filename)
+
+ if not filename:
+ return
+
+ server = dde.CreateServer()
+ server.Create("myddeserver")
+ conversation = dde.CreateConversation(server)
+ try:
+ conversation.ConnectTo("uedit32", "System")
+ conversation.Exec(r'[open("%s/%d"])' % (filename, lineno))
+
+ sleep(self.wakeup_duration)
+ except:
+ run_command(self.path, 'uedit32', '"%s/%d"' % (filename, lineno))
+
+ sleep(self.start_duration)
+
+ server.Shutdown()
+
+ restore_console_focus()
+
+
+def ultraedit(path = r"C:\Program Files\IDM Computer Solutions\UltraEdit-32", wakeup_duration = 10, start_duration = 2000):
+ synchronize_with_editor = UltraEditHook(path, wakeup_duration, start_duration)
+ set_hook(synchronize_with_editor)
+ \ No newline at end of file
diff --git a/IPython/Extensions/ipy_system_conf.py b/IPython/Extensions/ipy_system_conf.py
new file mode 100644
index 0000000..027594d
--- /dev/null
+++ b/IPython/Extensions/ipy_system_conf.py
@@ -0,0 +1,24 @@
+""" System wide configuration file for IPython.
+
+This will be imported by ipython for all users.
+
+After this ipy_user_conf.py is imported, user specific configuration
+should reside there.
+
+ """
+
+import IPython.ipapi
+ip = IPython.ipapi.get()
+
+# add system wide configuration information, import extensions etc. here.
+# nothing here is essential
+
+import sys
+
+import ext_rescapture # var = !ls and var = %magic
+import pspersistence # %store magic
+import clearcmd # %clear
+
+import ipy_stock_completers
+
+ip.load('IPython.history')
diff --git a/IPython/Extensions/ipy_traits_completer.py b/IPython/Extensions/ipy_traits_completer.py
new file mode 100644
index 0000000..6d3e6f7
--- /dev/null
+++ b/IPython/Extensions/ipy_traits_completer.py
@@ -0,0 +1,184 @@
+"""Traits-aware tab completion.
+
+This module provides a custom tab-completer that intelligently hides the names
+that the enthought.traits library (http://code.enthought.com/traits)
+automatically adds to all objects that inherit from its base HasTraits class.
+
+
+Activation
+==========
+
+To use this, put in your ~/.ipython/ipy_user_conf.py file:
+
+ from ipy_traits_completer import activate
+ activate([complete_threshold])
+
+The optional complete_threshold argument is the minimal length of text you need
+to type for tab-completion to list names that are automatically generated by
+traits. The default value is 3. Note that at runtime, you can change this
+value simply by doing:
+
+ import ipy_traits_completer
+ ipy_traits_completer.COMPLETE_THRESHOLD = 4
+
+
+Usage
+=====
+
+The system works as follows. If t is an empty object that HasTraits, then
+(assuming the threshold is at the default value of 3):
+
+In [7]: t.ed<TAB>
+
+doesn't show anything at all, but:
+
+In [7]: t.edi<TAB>
+t.edit_traits t.editable_traits
+
+shows these two names that come from traits. This allows you to complete on
+the traits-specific names by typing at least 3 letters from them (or whatever
+you set your threshold to), but to otherwise not see them in normal completion.
+
+
+Notes
+=====
+
+ - This requires Python 2.4 to work (I use sets). I don't think anyone is
+ using traits with 2.3 anyway, so that's OK.
+"""
+
+#############################################################################
+# External imports
+from enthought.traits import api as T
+
+# IPython imports
+from IPython.ipapi import TryNext, get as ipget
+from IPython.genutils import dir2
+try:
+ set
+except:
+ from sets import Set as set
+
+#############################################################################
+# Module constants
+
+# The completion threshold
+# This is currently implemented as a module global, since this sytem isn't
+# likely to be modified at runtime by multiple instances. If needed in the
+# future, we can always make it local to the completer as a function attribute.
+COMPLETE_THRESHOLD = 3
+
+# Set of names that Traits automatically adds to ANY traits-inheriting object.
+# These are the names we'll filter out.
+TRAIT_NAMES = set( dir2(T.HasTraits()) ) - set( dir2(object()) )
+
+#############################################################################
+# Code begins
+
+def trait_completer(self,event):
+ """A custom IPython tab-completer that is traits-aware.
+
+ It tries to hide the internal traits attributes, and reveal them only when
+ it can reasonably guess that the user really is after one of them.
+ """
+
+ #print '\nevent is:',event # dbg
+ symbol_parts = event.symbol.split('.')
+ base = '.'.join(symbol_parts[:-1])
+ #print 'base:',base # dbg
+
+ oinfo = self._ofind(base)
+ if not oinfo['found']:
+ raise TryNext
+
+ obj = oinfo['obj']
+ # OK, we got the object. See if it's traits, else punt
+ if not isinstance(obj,T.HasTraits):
+ raise TryNext
+
+ # it's a traits object, don't show the tr* attributes unless the completion
+ # begins with 'tr'
+ attrs = dir2(obj)
+ # Now, filter out the attributes that start with the user's request
+ attr_start = symbol_parts[-1]
+ if attr_start:
+ attrs = [a for a in attrs if a.startswith(attr_start)]
+
+ # Let's also respect the user's readline_omit__names setting:
+ omit__names = ipget().options.readline_omit__names
+ if omit__names == 1:
+ attrs = [a for a in attrs if not a.startswith('__')]
+ elif omit__names == 2:
+ attrs = [a for a in attrs if not a.startswith('_')]
+
+ #print '\nastart:<%r>' % attr_start # dbg
+
+ if len(attr_start)<COMPLETE_THRESHOLD:
+ attrs = list(set(attrs) - TRAIT_NAMES)
+
+ # The base of the completion, so we can form the final results list
+ bdot = base+'.'
+
+ tcomp = [bdot+a for a in attrs]
+ #print 'tcomp:',tcomp
+ return tcomp
+
+def activate(complete_threshold = COMPLETE_THRESHOLD):
+ """Activate the Traits completer.
+
+ :Keywords:
+ complete_threshold : int
+ The minimum number of letters that a user must type in order to
+ activate completion of traits-private names."""
+
+ if not (isinstance(complete_threshold,int) and
+ complete_threshold>0):
+ e='complete_threshold must be a positive integer, not %r' % \
+ complete_threshold
+ raise ValueError(e)
+
+ # Set the module global
+ global COMPLETE_THRESHOLD
+ COMPLETE_THRESHOLD = complete_threshold
+
+ # Activate the traits aware completer
+ ip = ipget()
+ ip.set_hook('complete_command', trait_completer, re_key = '.*')
+
+
+#############################################################################
+if __name__ == '__main__':
+ # Testing/debugging
+
+ # A sorted list of the names we'll filter out
+ TNL = list(TRAIT_NAMES)
+ TNL.sort()
+
+ # Make a few objects for testing
+ class TClean(T.HasTraits): pass
+ class Bunch(object): pass
+ # A clean traits object
+ t = TClean()
+ # A nested object containing t
+ f = Bunch()
+ f.t = t
+ # And a naked new-style object
+ o = object()
+
+ ip = ipget().IP
+
+ # A few simplistic tests
+
+ # Reset the threshold to the default, in case the test is running inside an
+ # instance of ipython that changed it
+ import ipy_traits_completer
+ ipy_traits_completer.COMPLETE_THRESHOLD = 3
+
+ assert ip.complete('t.ed') ==[]
+
+ # For some bizarre reason, these fail on the first time I run them, but not
+ # afterwards. Traits does some really weird stuff at object instantiation
+ # time...
+ ta = ip.complete('t.edi')
+ assert ta == ['t.edit_traits', 't.editable_traits']
+ print 'Tests OK'
diff --git a/IPython/Extensions/ipy_vimserver.py b/IPython/Extensions/ipy_vimserver.py
new file mode 100644
index 0000000..f23b712
--- /dev/null
+++ b/IPython/Extensions/ipy_vimserver.py
@@ -0,0 +1,239 @@
+""" Integration with gvim, by Erich Heine
+
+Provides a %vim magic command, and reuses the same vim session. Uses
+unix domain sockets for communication between vim and IPython. ipy.vim is
+available in doc/examples of the IPython distribution.
+
+Slightly touched up email announcement (and description how to use it) by
+Erich Heine is here:
+
+Ive recently been playing with ipython, and like it quite a bit. I did
+however discover a bit of frustration, namely with editor interaction.
+I am a gvim user, and using the command edit on a new file causes
+ipython to try and run that file as soon as the text editor opens
+up. The -x command of course fixes this, but its still a bit annoying,
+switching windows to do a run file, then back to the text
+editor. Being a heavy tab user in gvim, another annoyance is not being
+able to specify weather a new tab is how I choose to open the file.
+
+Not being one to shirk my open source duties (and seeing this as a
+good excuse to poke around ipython internals), Ive created a script
+for having gvim and ipython work very nicely together. Ive attached
+both to this email (hoping of course that the mailing list allows such
+things).
+
+There are 2 files:
+
+ipy_vimserver.py -- this file contains the ipython stuff
+ipy.vim -- this file contains the gvim stuff
+
+In combination they allow for a few functionalities:
+
+#1. the vim magic command. This is a fancy wrapper around the edit
+magic, that allows for a new option, -t, which opens the text in a new
+gvim tab. Otherwise it works the same as edit -x. (it internally
+calls edit -x). This magic command also juggles vim server management,
+so when it is called when there is not a gvim running, it creates a
+new gvim instance, named after the ipython session name. Once such a
+gvim instance is running, it will be used for subsequent uses of the
+vim command.
+
+#2. ipython - gvim interaction. Once a file has been opened with the
+vim magic (and a session set up, see below), pressing the F5 key in
+vim will cause the calling ipython instance to execute run
+filename.py. (if you typo like I do, this is very useful)
+
+#3. ipython server - this is a thread wich listens on a unix domain
+socket, and runs commands sent to that socket.
+
+Note, this only works on POSIX systems, that allow for AF_UNIX type
+sockets. It has only been tested on linux (a fairly recent debian
+testing distro).
+
+To install it put, the ipserver.py in your favorite locaion for
+sourcing ipython scripts. I put the ipy.vim in
+~/.vim/after/ftplugin/python/.
+
+To use (this can be scripted im sure, but i usually have 2 or 3
+ipythons and corresponding gvims open):
+
+import ipy_vimserver
+ipy_vimserver.setup('sessionname')
+
+(Editors note - you can probably add these to your ipy_user_conf.py)
+
+Then use ipython as you normally would, until you need to edit
+something. Instead of edit, use the vim magic. Thats it!
+
+"""
+
+import IPython.ipapi
+#import ipythonhooks
+import socket, select
+import os, threading, subprocess
+import re
+
+ERRCONDS = select.POLLHUP|select.POLLERR
+SERVER = None
+ip = IPython.ipapi.get()
+
+# this listens to a unix domain socket in a separate thread, so that comms
+# between a vim instance and ipython can happen in a fun and productive way
+class IpyServer(threading.Thread):
+ def __init__(self, sname):
+ super(IpyServer, self).__init__()
+ self.keep_running = True
+ self.__sname = sname
+ self.socket = socket.socket(socket.AF_UNIX)
+ self.poller = select.poll()
+ self.current_conns = dict()
+ self.setDaemon(True)
+
+ def listen(self):
+ self.socket.bind(self.__sname)
+ self.socket.listen(1)
+
+ def __handle_error(self, socket):
+ if socket == self.socket.fileno():
+ self.keep_running = False
+ for a in self.current_conns.values():
+ a.close()
+ return False
+ else:
+ y = self.current_conns[socket]
+ del self.current_conns[socket]
+ y.close()
+ self.poller.unregister(socket)
+
+ def serve_me(self):
+ self.listen()
+ self.poller.register(self.socket,select.POLLIN|ERRCONDS)
+
+ while self.keep_running:
+ try:
+ avail = self.poller.poll(1)
+ except:
+ continue
+
+ if not avail: continue
+
+ for sock, conds in avail:
+ if conds & (ERRCONDS):
+ if self.__handle_error(sock): continue
+ else: break
+
+ if sock == self.socket.fileno():
+ y = self.socket.accept()[0]
+ self.poller.register(y, select.POLLIN|ERRCONDS)
+ self.current_conns[y.fileno()] = y
+ else: y = self.current_conns.get(sock)
+
+ self.handle_request(y)
+
+ os.remove(self.__sname)
+
+ run = serve_me
+
+ def stop(self):
+ self.keep_running = False
+
+ def handle_request(self,sock):
+ sock.settimeout(1)
+ while self.keep_running:
+ try:
+ x = sock.recv(4096)
+ except socket.timeout:
+ pass
+ else:
+ break
+ self.do_it(x)
+
+ def do_it(self, data):
+ data = data.split('\n')
+ cmds = list()
+ for line in data:
+ cmds.append(line)
+ ip.runlines(cmds)
+
+
+# try to help ensure that the unix domain socket is cleaned up proper
+def shutdown_server(self):
+ if SERVER:
+ SERVER.stop()
+ SERVER.join(3)
+ raise IPython.ipapi.TryNext
+
+ip.set_hook('shutdown_hook', shutdown_server, 10)
+
+# this fun function exists to make setup easier for all, and makes the
+# vimhook function ready for instance specific communication
+def setup(sessionname='',socketdir=os.path.expanduser('~/.ipython/')):
+ global SERVER
+
+ if sessionname:
+ session = sessionname
+ elif os.environ.get('IPY_SESSION'):
+ session = os.environ.get('IPY_SESSION')
+ else:
+ session = 'IPYS'
+ vimhook.vimserver=session
+ vimhook.ipyserver = os.path.join(socketdir, session)
+ if not SERVER:
+ SERVER = IpyServer(vimhook.ipyserver)
+ SERVER.start()
+
+
+
+# calls gvim, with all ops happening on the correct gvim instance for this
+# ipython instance. it then calls edit -x (since gvim will return right away)
+# things of note: it sets up a special environment, so that the ipy.vim script
+# can connect back to the ipython instance and do fun things, like run the file
+def vimhook(self, fname, line):
+ env = os.environ.copy()
+ vserver = vimhook.vimserver.upper()
+ check = subprocess.Popen('gvim --serverlist', stdout = subprocess.PIPE,
+ shell=True)
+ check.wait()
+ cval = [l for l in check.stdout.readlines() if vserver in l]
+
+ if cval:
+ vimargs = '--remote%s' % (vimhook.extras,)
+ else:
+ vimargs = ''
+ vimhook.extras = ''
+
+ env['IPY_SESSION'] = vimhook.vimserver
+ env['IPY_SERVER'] = vimhook.ipyserver
+
+ if line is None: line = ''
+ else: line = '+' + line
+ vim_cmd = 'gvim --servername %s %s %s %s' % (vimhook.vimserver, vimargs,
+ line, fname)
+ subprocess.call(vim_cmd, env=env, shell=True)
+
+
+#default values to keep it sane...
+vimhook.vimserver = ''
+vimhook.ipyserver = ''
+
+ip.set_hook('editor',vimhook)
+
+# this is set up so more vim specific commands can be added, instead of just
+# the current -t. all thats required is a compiled regex, a call to do_arg(pat)
+# and the logic to deal with the new feature
+newtab = re.compile(r'-t(?:\s|$)')
+def vim(self, argstr):
+ def do_arg(pat, rarg):
+ x = len(pat.findall(argstr))
+ if x:
+ a = pat.sub('',argstr)
+ return rarg, a
+ else: return '', argstr
+
+ t, argstr = do_arg(newtab, '-tab')
+ vimhook.extras = t
+ argstr = 'edit -x ' + argstr
+ ip.magic(argstr)
+
+ip.expose_magic('vim', vim)
+
diff --git a/IPython/Extensions/ipy_which.py b/IPython/Extensions/ipy_which.py
new file mode 100644
index 0000000..44bfae1
--- /dev/null
+++ b/IPython/Extensions/ipy_which.py
@@ -0,0 +1,76 @@
+r""" %which magic command
+
+%which <cmd> => search PATH for files matching PATH. Also scans aliases
+
+"""
+
+import IPython.ipapi
+ip = IPython.ipapi.get()
+
+import os,sys
+from fnmatch import fnmatch
+def which(fname):
+ fullpath = filter(os.path.isdir,os.environ['PATH'].split(os.pathsep))
+
+ if '.' not in fullpath:
+ fullpath = ['.'] + fullpath
+ fn = fname
+ for p in fullpath:
+ for f in os.listdir(p):
+ head, ext = os.path.splitext(f)
+ if f == fn or fnmatch(head, fn):
+ yield os.path.join(p,f)
+ return
+
+def which_alias(fname):
+ for al, tgt in ip.IP.alias_table.items():
+ if not (al == fname or fnmatch(al, fname)):
+ continue
+ if callable(tgt):
+ print "Callable alias",tgt
+ d = tgt.__doc__
+ if d:
+ print "Docstring:\n",d
+ continue
+ trg = tgt[1]
+
+ trans = ip.expand_alias(trg)
+ cmd = trans.split(None,1)[0]
+ print al,"->",trans
+ for realcmd in which(cmd):
+ print " ==",realcmd
+
+def which_f(self, arg):
+ r""" %which <cmd> => search PATH for files matching cmd. Also scans aliases.
+
+ Traverses PATH and prints all files (not just executables!) that match the
+ pattern on command line. Probably more useful in finding stuff
+ interactively than 'which', which only prints the first matching item.
+
+ Also discovers and expands aliases, so you'll see what will be executed
+ when you call an alias.
+
+ Example:
+
+ [~]|62> %which d
+ d -> ls -F --color=auto
+ == c:\cygwin\bin\ls.exe
+ c:\cygwin\bin\d.exe
+
+ [~]|64> %which diff*
+ diff3 -> diff3
+ == c:\cygwin\bin\diff3.exe
+ diff -> diff
+ == c:\cygwin\bin\diff.exe
+ c:\cygwin\bin\diff.exe
+ c:\cygwin\bin\diff3.exe
+
+ """
+
+ which_alias(arg)
+
+ for e in which(arg):
+ print e
+
+ip.expose_magic("which",which_f)
+
diff --git a/IPython/Extensions/ipy_winpdb.py b/IPython/Extensions/ipy_winpdb.py
new file mode 100644
index 0000000..6c2d64b
--- /dev/null
+++ b/IPython/Extensions/ipy_winpdb.py
@@ -0,0 +1,83 @@
+""" Debug a script (like %run -d) in IPython process, Using WinPdb
+
+Usage:
+
+%wdb test.py
+ run test.py, with a winpdb breakpoint at start of the file
+
+%wdb pass
+ Change the password (e.g. if you have forgotten the old one)
+
+
+Notes
+-----
+
+**WARNING**: As of March 2009 (IPython 0.10), WinPdb has a known bug, which
+causes PyTables to become impossible to import if winpdb is loaded. Therefore,
+if you need PyTables, do *not* use this extension.
+
+For more details: https://bugs.launchpad.net/ipython/+bug/249036
+"""
+
+import os
+
+import IPython.ipapi
+import rpdb2
+
+ip = IPython.ipapi.get()
+
+rpdb_started = False
+
+def wdb_f(self, arg):
+ """ Debug a script (like %run -d) in IPython process, Using WinPdb
+
+ Usage:
+
+ %wdb test.py
+ run test.py, with a winpdb breakpoint at start of the file
+
+ %wdb pass
+ Change the password (e.g. if you have forgotten the old one)
+
+ Note that after the script has been run, you need to do "Go" (f5)
+ in WinPdb to resume normal IPython operation.
+ """
+
+ global rpdb_started
+ if not arg.strip():
+ print __doc__
+ return
+
+ if arg.strip() == 'pass':
+ passwd = raw_input('Enter new winpdb session password: ')
+ ip.db['winpdb_pass'] = passwd
+ print "Winpdb password changed"
+ if rpdb_started:
+ print "You need to restart IPython to use the new password"
+ return
+
+ path = os.path.abspath(arg)
+ if not os.path.isfile(path):
+ raise IPython.ipapi.UsageError("%%wdb: file %s does not exist" % path)
+ if not rpdb_started:
+ passwd = ip.db.get('winpdb_pass', None)
+ if passwd is None:
+ import textwrap
+ print textwrap.dedent("""\
+ Winpdb sessions need a password that you use for attaching the external
+ winpdb session. IPython will remember this. You can change the password later
+ by '%wpdb pass'
+ """)
+ passwd = raw_input('Enter new winpdb session password: ')
+ ip.db['winpdb_pass'] = passwd
+
+ print "Starting rpdb2 in IPython process"
+ rpdb2.start_embedded_debugger(passwd, timeout = 0)
+ rpdb_started = True
+
+ rpdb2.set_temp_breakpoint(path)
+ print 'It is time to attach with WinPdb (launch WinPdb if needed, File -> Attach)'
+ ip.magic('%run ' + arg)
+
+
+ip.expose_magic('wdb', wdb_f)
diff --git a/IPython/Extensions/ipy_workdir.py b/IPython/Extensions/ipy_workdir.py
new file mode 100644
index 0000000..e27b476
--- /dev/null
+++ b/IPython/Extensions/ipy_workdir.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+
+import IPython.ipapi
+ip = IPython.ipapi.get()
+
+import os, subprocess
+
+workdir = None
+def workdir_f(ip,line):
+ """ Exceute commands residing in cwd elsewhere
+
+ Example::
+
+ workdir /myfiles
+ cd bin
+ workdir myscript.py
+
+ executes myscript.py (stored in bin, but not in path) in /myfiles
+ """
+ global workdir
+ dummy,cmd = line.split(None,1)
+ if os.path.isdir(cmd):
+ workdir = os.path.abspath(cmd)
+ print "Set workdir",workdir
+ elif workdir is None:
+ print "Please set workdir first by doing e.g. 'workdir q:/'"
+ else:
+ sp = cmd.split(None,1)
+ if len(sp) == 1:
+ head, tail = cmd, ''
+ else:
+ head, tail = sp
+ if os.path.isfile(head):
+ cmd = os.path.abspath(head) + ' ' + tail
+ print "Execute command '" + cmd+ "' in",workdir
+ olddir = os.getcwd()
+ os.chdir(workdir)
+ try:
+ os.system(cmd)
+ finally:
+ os.chdir(olddir)
+
+ip.defalias("workdir",workdir_f)
diff --git a/IPython/Extensions/jobctrl.py b/IPython/Extensions/jobctrl.py
new file mode 100644
index 0000000..3d7b948
--- /dev/null
+++ b/IPython/Extensions/jobctrl.py
@@ -0,0 +1,242 @@
+""" Preliminary "job control" extensions for IPython
+
+requires python 2.4 (or separate 'subprocess' module
+
+This provides 2 features, launching background jobs and killing foreground jobs from another IPython instance.
+
+Launching background jobs:
+
+ Usage:
+
+ [ipython]|2> import jobctrl
+ [ipython]|3> &ls
+ <3> <jobctrl.IpyPopen object at 0x00D87FD0>
+ [ipython]|4> _3.go
+ -----------> _3.go()
+ ChangeLog
+ IPython
+ MANIFEST.in
+ README
+ README_Windows.txt
+
+ ...
+
+Killing foreground tasks:
+
+Launch IPython instance, run a blocking command:
+
+ [Q:/ipython]|1> import jobctrl
+ [Q:/ipython]|2> cat
+
+Now launch a new IPython prompt and kill the process:
+
+ IPython 0.8.3.svn.r2919 [on Py 2.5]
+ [Q:/ipython]|1> import jobctrl
+ [Q:/ipython]|2> %tasks
+ 6020: 'cat ' (Q:\ipython)
+ [Q:/ipython]|3> %kill
+ SUCCESS: The process with PID 6020 has been terminated.
+ [Q:/ipython]|4>
+
+(you don't need to specify PID for %kill if only one task is running)
+"""
+
+from subprocess import *
+import os,shlex,sys,time
+import threading,Queue
+
+from IPython import genutils
+
+import IPython.ipapi
+
+if os.name == 'nt':
+ def kill_process(pid):
+ os.system('taskkill /F /PID %d' % pid)
+else:
+ def kill_process(pid):
+ os.system('kill -9 %d' % pid)
+
+
+
+class IpyPopen(Popen):
+ def go(self):
+ print self.communicate()[0]
+ def __repr__(self):
+ return '<IPython job "%s" PID=%d>' % (self.line, self.pid)
+
+ def kill(self):
+ kill_process(self.pid)
+
+def startjob(job):
+ p = IpyPopen(shlex.split(job), stdout=PIPE, shell = False)
+ p.line = job
+ return p
+
+class AsyncJobQ(threading.Thread):
+ def __init__(self):
+ threading.Thread.__init__(self)
+ self.q = Queue.Queue()
+ self.output = []
+ self.stop = False
+ def run(self):
+ while 1:
+ cmd,cwd = self.q.get()
+ if self.stop:
+ self.output.append("** Discarding: '%s' - %s" % (cmd,cwd))
+ continue
+ self.output.append("** Task started: '%s' - %s" % (cmd,cwd))
+
+ p = Popen(cmd, shell=True, stdout=PIPE, stderr=STDOUT, cwd = cwd)
+ out = p.stdout.read()
+ self.output.append("** Task complete: '%s'\n" % cmd)
+ self.output.append(out)
+
+ def add(self,cmd):
+ self.q.put_nowait((cmd, os.getcwd()))
+
+ def dumpoutput(self):
+ while self.output:
+ item = self.output.pop(0)
+ print item
+
+_jobq = None
+
+def jobqueue_f(self, line):
+
+ global _jobq
+ if not _jobq:
+ print "Starting jobqueue - do '&some_long_lasting_system_command' to enqueue"
+ _jobq = AsyncJobQ()
+ _jobq.setDaemon(True)
+ _jobq.start()
+ ip.jobq = _jobq.add
+ return
+ if line.strip() == 'stop':
+ print "Stopping and clearing jobqueue, %jobqueue start to start again"
+ _jobq.stop = True
+ return
+ if line.strip() == 'start':
+ _jobq.stop = False
+ return
+
+def jobctrl_prefilter_f(self,line):
+ if line.startswith('&'):
+ pre,fn,rest = self.split_user_input(line[1:])
+
+ line = ip.IP.expand_aliases(fn,rest)
+ if not _jobq:
+ return '_ip.startjob(%s)' % genutils.make_quoted_expr(line)
+ return '_ip.jobq(%s)' % genutils.make_quoted_expr(line)
+
+ raise IPython.ipapi.TryNext
+
+def jobq_output_hook(self):
+ if not _jobq:
+ return
+ _jobq.dumpoutput()
+
+
+
+def job_list(ip):
+ keys = ip.db.keys('tasks/*')
+ ents = [ip.db[k] for k in keys]
+ return ents
+
+def magic_tasks(self,line):
+ """ Show a list of tasks.
+
+ A 'task' is a process that has been started in IPython when 'jobctrl' extension is enabled.
+ Tasks can be killed with %kill.
+
+ '%tasks clear' clears the task list (from stale tasks)
+ """
+ ip = self.getapi()
+ if line.strip() == 'clear':
+ for k in ip.db.keys('tasks/*'):
+ print "Clearing",ip.db[k]
+ del ip.db[k]
+ return
+
+ ents = job_list(ip)
+ if not ents:
+ print "No tasks running"
+ for pid,cmd,cwd,t in ents:
+ dur = int(time.time()-t)
+ print "%d: '%s' (%s) %d:%02d" % (pid,cmd,cwd, dur / 60,dur%60)
+
+def magic_kill(self,line):
+ """ Kill a task
+
+ Without args, either kill one task (if only one running) or show list (if many)
+ With arg, assume it's the process id.
+
+ %kill is typically (much) more powerful than trying to terminate a process with ctrl+C.
+ """
+ ip = self.getapi()
+ jobs = job_list(ip)
+
+ if not line.strip():
+ if len(jobs) == 1:
+ kill_process(jobs[0][0])
+ else:
+ magic_tasks(self,line)
+ return
+
+ try:
+ pid = int(line)
+ kill_process(pid)
+ except ValueError:
+ magic_tasks(self,line)
+
+if sys.platform == 'win32':
+ shell_internal_commands = 'break chcp cls copy ctty date del erase dir md mkdir path prompt rd rmdir start time type ver vol'.split()
+ PopenExc = WindowsError
+else:
+ # todo linux commands
+ shell_internal_commands = []
+ PopenExc = OSError
+
+
+def jobctrl_shellcmd(ip,cmd):
+ """ os.system replacement that stores process info to db['tasks/t1234'] """
+ cmd = cmd.strip()
+ cmdname = cmd.split(None,1)[0]
+ if cmdname in shell_internal_commands or '|' in cmd or '>' in cmd or '<' in cmd:
+ use_shell = True
+ else:
+ use_shell = False
+
+ jobentry = None
+ try:
+ try:
+ p = Popen(cmd,shell = use_shell)
+ except PopenExc :
+ if use_shell:
+ # try with os.system
+ os.system(cmd)
+ return
+ else:
+ # have to go via shell, sucks
+ p = Popen(cmd,shell = True)
+
+ jobentry = 'tasks/t' + str(p.pid)
+ ip.db[jobentry] = (p.pid,cmd,os.getcwd(),time.time())
+ p.communicate()
+
+ finally:
+ if jobentry:
+ del ip.db[jobentry]
+
+
+def install():
+ global ip
+ ip = IPython.ipapi.get()
+ # needed to make startjob visible as _ip.startjob('blah')
+ ip.startjob = startjob
+ ip.set_hook('input_prefilter', jobctrl_prefilter_f)
+ ip.set_hook('shell_hook', jobctrl_shellcmd)
+ ip.expose_magic('kill',magic_kill)
+ ip.expose_magic('tasks',magic_tasks)
+ ip.expose_magic('jobqueue',jobqueue_f)
+ ip.set_hook('pre_prompt_hook', jobq_output_hook)
+install()
diff --git a/IPython/Extensions/ledit.py b/IPython/Extensions/ledit.py
new file mode 100644
index 0000000..87683b4
--- /dev/null
+++ b/IPython/Extensions/ledit.py
@@ -0,0 +1,98 @@
+""" Fun magic line editor for ipython
+
+Use this to easily edit lists of strings gradually without crafting long
+list comprehensions.
+
+'l' is the magic variable name for every line (array element). Save the current
+result (or more exactly, retrieve the last ipython computation result into
+%led work area) by running '%led s'. Just run '%led' to show the current work
+area data.
+
+Example use:
+
+[ipython]|25> setups = !ls *setup*.py
+ ==
+['eggsetup.py', 'setup.py', 'setup_bdist_egg.py']
+[ipython]|26> setups
+ <26> ['eggsetup.py', 'setup.py', 'setup_bdist_egg.py']
+[ipython]|27> %led s
+Data set from last result (_)
+ <27> ['eggsetup.py', 'setup.py', 'setup_bdist_egg.py']
+[ipython]|28> %led upper
+cmd translated => l.upper()
+ <28> ['EGGSETUP.PY', 'SETUP.PY', 'SETUP_BDIST_EGG.PY']
+[ipython]|29> %led
+Magic line editor (for lists of strings)
+current data is:
+['eggsetup.py', 'setup.py', 'setup_bdist_egg.py']
+[ipython]|30> %led upper
+cmd translated => l.upper()
+ <30> ['EGGSETUP.PY', 'SETUP.PY', 'SETUP_BDIST_EGG.PY']
+[ipython]|31> %led s
+Data set from last result (_)
+ <31> ['EGGSETUP.PY', 'SETUP.PY', 'SETUP_BDIST_EGG.PY']
+[ipython]|32> %led "n:" + l
+ <32> ['n:EGGSETUP.PY', 'n:SETUP.PY', 'n:SETUP_BDIST_EGG.PY']
+[ipython]|33> %led s
+Data set from last result (_)
+ <33> ['n:EGGSETUP.PY', 'n:SETUP.PY', 'n:SETUP_BDIST_EGG.PY']
+[ipython]|34> %led l.
+l.__add__ l.__gt__ l.__reduce_ex__ l.endswith l.join l.rstrip
+l.__class__ l.__hash__ l.__repr__ l.expandtabs l.ljust l.split
+
+... (completions for string variable shown ) ...
+
+"""
+import IPython.ipapi
+import pprint
+ip = IPython.ipapi.get()
+
+curdata = []
+
+def line_edit_f(self, cmd ):
+ global curdata
+
+ if not cmd:
+
+ print "Magic line editor (for lists of strings)"
+ if curdata:
+ print "current data is:"
+ pprint.pprint(curdata)
+ else:
+ print "No current data, you should set it by running '%led s'"
+ print "When you have your data in _ (result of last computation)."
+ return
+
+ if cmd == 's':
+ curdata = ip.ev('_')
+ print "Data set from last result (_)"
+ newlines = curdata
+
+ else:
+ # simple method call, e.g. upper
+ if cmd.isalpha():
+ cmd = 'l.' + cmd + '()'
+ print "cmd translated =>",cmd
+
+ newlines = []
+ for l in curdata:
+ try:
+ l2 = eval(cmd)
+ except Exception,e:
+ print "Dropping exception",e,"on line:",l
+ continue
+ newlines.append(l2)
+
+
+ return newlines
+
+def line_edit_complete_f(self,event):
+ """ Show all string methods in completions """
+ if event.symbol.startswith('l.'):
+ return ['l.' + func for func in dir('')]
+
+ return dir('') + ['l.' + func for func in dir('')]
+
+ip.set_hook('complete_command', line_edit_complete_f , str_key = '%led')
+
+ip.expose_magic('led', line_edit_f) \ No newline at end of file
diff --git a/IPython/Extensions/numeric_formats.py b/IPython/Extensions/numeric_formats.py
new file mode 100644
index 0000000..b6b2d29
--- /dev/null
+++ b/IPython/Extensions/numeric_formats.py
@@ -0,0 +1,43 @@
+# -*- coding: utf-8 -*-
+"""
+Extension for printing Numeric Arrays in flexible ways.
+"""
+
+from Numeric import ArrayType
+
+def num_display(self,arg):
+ """Display method for printing which treats Numeric arrays specially.
+ """
+
+ # Non-numpy variables are printed using the system default
+ if type(arg) != ArrayType:
+ self._display(arg)
+ return
+ # Otherwise, we do work.
+ format = __IPYTHON__.runtime_rc.numarray_print_format
+ print 'NumPy array, format:',format
+ # Here is where all the printing logic needs to be implemented
+ print arg # nothing yet :)
+
+
+def magic_format(self,parameter_s=''):
+ """Specifies format of numerical output.
+
+ This command is similar to Ocave's format command.
+ """
+
+ valid_formats = ['long','short']
+
+ if parameter_s in valid_formats:
+ self.runtime_rc.numarray_print_format = parameter_s
+ print 'Numeric output format is now:',parameter_s
+ else:
+ print 'Invalid format:',parameter_s
+ print 'Valid formats:',valid_formats
+
+# setup default format
+__IPYTHON__.runtime_rc.numarray_print_format = 'long'
+
+# Bind our new functions to the interpreter
+__IPYTHON__.__class__.magic_format = magic_format
+__IPYTHON__.hooks.display = num_display
diff --git a/IPython/Extensions/pickleshare.py b/IPython/Extensions/pickleshare.py
new file mode 100755
index 0000000..40bfb8b
--- /dev/null
+++ b/IPython/Extensions/pickleshare.py
@@ -0,0 +1,357 @@
+#!/usr/bin/env python
+
+""" PickleShare - a small 'shelve' like datastore with concurrency support
+
+Like shelve, a PickleShareDB object acts like a normal dictionary. Unlike
+shelve, many processes can access the database simultaneously. Changing a
+value in database is immediately visible to other processes accessing the
+same database.
+
+Concurrency is possible because the values are stored in separate files. Hence
+the "database" is a directory where *all* files are governed by PickleShare.
+
+Example usage::
+
+ from pickleshare import *
+ db = PickleShareDB('~/testpickleshare')
+ db.clear()
+ print "Should be empty:",db.items()
+ db['hello'] = 15
+ db['aku ankka'] = [1,2,313]
+ db['paths/are/ok/key'] = [1,(5,46)]
+ print db.keys()
+ del db['aku ankka']
+
+This module is certainly not ZODB, but can be used for low-load
+(non-mission-critical) situations where tiny code size trumps the
+advanced features of a "real" object database.
+
+Installation guide: easy_install pickleshare
+
+Author: Ville Vainio <vivainio@gmail.com>
+License: MIT open source license.
+
+"""
+
+from IPython.external.path import path as Path
+import os,stat,time
+import cPickle as pickle
+import UserDict
+import warnings
+import glob
+
+def gethashfile(key):
+ return ("%02x" % abs(hash(key) % 256))[-2:]
+
+_sentinel = object()
+
+class PickleShareDB(UserDict.DictMixin):
+ """ The main 'connection' object for PickleShare database """
+ def __init__(self,root):
+ """ Return a db object that will manage the specied directory"""
+ self.root = Path(root).expanduser().abspath()
+ if not self.root.isdir():
+ self.root.makedirs()
+ # cache has { 'key' : (obj, orig_mod_time) }
+ self.cache = {}
+
+
+ def __getitem__(self,key):
+ """ db['key'] reading """
+ fil = self.root / key
+ try:
+ mtime = (fil.stat()[stat.ST_MTIME])
+ except OSError:
+ raise KeyError(key)
+
+ if fil in self.cache and mtime == self.cache[fil][1]:
+ return self.cache[fil][0]
+ try:
+ # The cached item has expired, need to read
+ obj = pickle.load(fil.open())
+ except:
+ raise KeyError(key)
+
+ self.cache[fil] = (obj,mtime)
+ return obj
+
+ def __setitem__(self,key,value):
+ """ db['key'] = 5 """
+ fil = self.root / key
+ parent = fil.parent
+ if parent and not parent.isdir():
+ parent.makedirs()
+ pickled = pickle.dump(value,fil.open('w'))
+ try:
+ self.cache[fil] = (value,fil.mtime)
+ except OSError,e:
+ if e.errno != 2:
+ raise
+
+ def hset(self, hashroot, key, value):
+ """ hashed set """
+ hroot = self.root / hashroot
+ if not hroot.isdir():
+ hroot.makedirs()
+ hfile = hroot / gethashfile(key)
+ d = self.get(hfile, {})
+ d.update( {key : value})
+ self[hfile] = d
+
+
+
+ def hget(self, hashroot, key, default = _sentinel, fast_only = True):
+ """ hashed get """
+ hroot = self.root / hashroot
+ hfile = hroot / gethashfile(key)
+
+ d = self.get(hfile, _sentinel )
+ #print "got dict",d,"from",hfile
+ if d is _sentinel:
+ if fast_only:
+ if default is _sentinel:
+ raise KeyError(key)
+
+ return default
+
+ # slow mode ok, works even after hcompress()
+ d = self.hdict(hashroot)
+
+ return d.get(key, default)
+
+ def hdict(self, hashroot):
+ """ Get all data contained in hashed category 'hashroot' as dict """
+ hfiles = self.keys(hashroot + "/*")
+ hfiles.sort()
+ last = len(hfiles) and hfiles[-1] or ''
+ if last.endswith('xx'):
+ # print "using xx"
+ hfiles = [last] + hfiles[:-1]
+
+ all = {}
+
+ for f in hfiles:
+ # print "using",f
+ try:
+ all.update(self[f])
+ except KeyError:
+ print "Corrupt",f,"deleted - hset is not threadsafe!"
+ del self[f]
+
+ self.uncache(f)
+
+ return all
+
+ def hcompress(self, hashroot):
+ """ Compress category 'hashroot', so hset is fast again
+
+ hget will fail if fast_only is True for compressed items (that were
+ hset before hcompress).
+
+ """
+ hfiles = self.keys(hashroot + "/*")
+ all = {}
+ for f in hfiles:
+ # print "using",f
+ all.update(self[f])
+ self.uncache(f)
+
+ self[hashroot + '/xx'] = all
+ for f in hfiles:
+ p = self.root / f
+ if p.basename() == 'xx':
+ continue
+ p.remove()
+
+
+
+ def __delitem__(self,key):
+ """ del db["key"] """
+ fil = self.root / key
+ self.cache.pop(fil,None)
+ try:
+ fil.remove()
+ except OSError:
+ # notfound and permission denied are ok - we
+ # lost, the other process wins the conflict
+ pass
+
+ def _normalized(self, p):
+ """ Make a key suitable for user's eyes """
+ return str(self.root.relpathto(p)).replace('\\','/')
+
+ def keys(self, globpat = None):
+ """ All keys in DB, or all keys matching a glob"""
+
+ if globpat is None:
+ files = self.root.walkfiles()
+ else:
+ files = [Path(p) for p in glob.glob(self.root/globpat)]
+ return [self._normalized(p) for p in files if p.isfile()]
+
+ def uncache(self,*items):
+ """ Removes all, or specified items from cache
+
+ Use this after reading a large amount of large objects
+ to free up memory, when you won't be needing the objects
+ for a while.
+
+ """
+ if not items:
+ self.cache = {}
+ for it in items:
+ self.cache.pop(it,None)
+
+ def waitget(self,key, maxwaittime = 60 ):
+ """ Wait (poll) for a key to get a value
+
+ Will wait for `maxwaittime` seconds before raising a KeyError.
+ The call exits normally if the `key` field in db gets a value
+ within the timeout period.
+
+ Use this for synchronizing different processes or for ensuring
+ that an unfortunately timed "db['key'] = newvalue" operation
+ in another process (which causes all 'get' operation to cause a
+ KeyError for the duration of pickling) won't screw up your program
+ logic.
+ """
+
+ wtimes = [0.2] * 3 + [0.5] * 2 + [1]
+ tries = 0
+ waited = 0
+ while 1:
+ try:
+ val = self[key]
+ return val
+ except KeyError:
+ pass
+
+ if waited > maxwaittime:
+ raise KeyError(key)
+
+ time.sleep(wtimes[tries])
+ waited+=wtimes[tries]
+ if tries < len(wtimes) -1:
+ tries+=1
+
+ def getlink(self,folder):
+ """ Get a convenient link for accessing items """
+ return PickleShareLink(self, folder)
+
+ def __repr__(self):
+ return "PickleShareDB('%s')" % self.root
+
+
+
+class PickleShareLink:
+ """ A shortdand for accessing nested PickleShare data conveniently.
+
+ Created through PickleShareDB.getlink(), example::
+
+ lnk = db.getlink('myobjects/test')
+ lnk.foo = 2
+ lnk.bar = lnk.foo + 5
+
+ """
+ def __init__(self, db, keydir ):
+ self.__dict__.update(locals())
+
+ def __getattr__(self,key):
+ return self.__dict__['db'][self.__dict__['keydir']+'/' + key]
+ def __setattr__(self,key,val):
+ self.db[self.keydir+'/' + key] = val
+ def __repr__(self):
+ db = self.__dict__['db']
+ keys = db.keys( self.__dict__['keydir'] +"/*")
+ return "<PickleShareLink '%s': %s>" % (
+ self.__dict__['keydir'],
+ ";".join([Path(k).basename() for k in keys]))
+
+
+def test():
+ db = PickleShareDB('~/testpickleshare')
+ db.clear()
+ print "Should be empty:",db.items()
+ db['hello'] = 15
+ db['aku ankka'] = [1,2,313]
+ db['paths/nest/ok/keyname'] = [1,(5,46)]
+ db.hset('hash', 'aku', 12)
+ db.hset('hash', 'ankka', 313)
+ print "12 =",db.hget('hash','aku')
+ print "313 =",db.hget('hash','ankka')
+ print "all hashed",db.hdict('hash')
+ print db.keys()
+ print db.keys('paths/nest/ok/k*')
+ print dict(db) # snapsot of whole db
+ db.uncache() # frees memory, causes re-reads later
+
+ # shorthand for accessing deeply nested files
+ lnk = db.getlink('myobjects/test')
+ lnk.foo = 2
+ lnk.bar = lnk.foo + 5
+ print lnk.bar # 7
+
+def stress():
+ db = PickleShareDB('~/fsdbtest')
+ import time,sys
+ for i in range(1000):
+ for j in range(1000):
+ if i % 15 == 0 and i < 200:
+ if str(j) in db:
+ del db[str(j)]
+ continue
+
+ if j%33 == 0:
+ time.sleep(0.02)
+
+ db[str(j)] = db.get(str(j), []) + [(i,j,"proc %d" % os.getpid())]
+ db.hset('hash',j, db.hget('hash',j,15) + 1 )
+
+ print i,
+ sys.stdout.flush()
+ if i % 10 == 0:
+ db.uncache()
+
+def main():
+ import textwrap
+ usage = textwrap.dedent("""\
+ pickleshare - manage PickleShare databases
+
+ Usage:
+
+ pickleshare dump /path/to/db > dump.txt
+ pickleshare load /path/to/db < dump.txt
+ pickleshare test /path/to/db
+ """)
+ DB = PickleShareDB
+ import sys
+ if len(sys.argv) < 2:
+ print usage
+ return
+
+ cmd = sys.argv[1]
+ args = sys.argv[2:]
+ if cmd == 'dump':
+ if not args: args= ['.']
+ db = DB(args[0])
+ import pprint
+ pprint.pprint(db.items())
+ elif cmd == 'load':
+ cont = sys.stdin.read()
+ db = DB(args[0])
+ data = eval(cont)
+ db.clear()
+ for k,v in db.items():
+ db[k] = v
+ elif cmd == 'testwait':
+ db = DB(args[0])
+ db.clear()
+ print db.waitget('250')
+ elif cmd == 'test':
+ test()
+ stress()
+
+if __name__== "__main__":
+ main()
+
+
diff --git a/IPython/Extensions/pspersistence.py b/IPython/Extensions/pspersistence.py
new file mode 100644
index 0000000..563308d
--- /dev/null
+++ b/IPython/Extensions/pspersistence.py
@@ -0,0 +1,182 @@
+# -*- coding: utf-8 -*-
+"""
+%store magic for lightweight persistence.
+
+Stores variables, aliases etc. in PickleShare database.
+"""
+
+import IPython.ipapi
+from IPython.ipapi import UsageError
+ip = IPython.ipapi.get()
+
+import pickleshare
+
+import inspect,pickle,os,sys,textwrap
+from IPython.FakeModule import FakeModule
+
+def restore_aliases(self):
+ ip = self.getapi()
+ staliases = ip.db.get('stored_aliases', {})
+ for k,v in staliases.items():
+ #print "restore alias",k,v # dbg
+ #self.alias_table[k] = v
+ ip.defalias(k,v)
+
+
+def refresh_variables(ip):
+ db = ip.db
+ for key in db.keys('autorestore/*'):
+ # strip autorestore
+ justkey = os.path.basename(key)
+ try:
+ obj = db[key]
+ except KeyError:
+ print "Unable to restore variable '%s', ignoring (use %%store -d to forget!)" % justkey
+ print "The error was:",sys.exc_info()[0]
+ else:
+ #print "restored",justkey,"=",obj #dbg
+ ip.user_ns[justkey] = obj
+
+
+def restore_dhist(ip):
+ db = ip.db
+ ip.user_ns['_dh'] = db.get('dhist',[])
+
+def restore_data(self):
+ ip = self.getapi()
+ refresh_variables(ip)
+ restore_aliases(self)
+ restore_dhist(self)
+ raise IPython.ipapi.TryNext
+
+ip.set_hook('late_startup_hook', restore_data)
+
+def magic_store(self, parameter_s=''):
+ """Lightweight persistence for python variables.
+
+ Example:
+
+ ville@badger[~]|1> A = ['hello',10,'world']\\
+ ville@badger[~]|2> %store A\\
+ ville@badger[~]|3> Exit
+
+ (IPython session is closed and started again...)
+
+ ville@badger:~$ ipython -p pysh\\
+ ville@badger[~]|1> print A
+
+ ['hello', 10, 'world']
+
+ Usage:
+
+ %store - Show list of all variables and their current values\\
+ %store <var> - Store the *current* value of the variable to disk\\
+ %store -d <var> - Remove the variable and its value from storage\\
+ %store -z - Remove all variables from storage\\
+ %store -r - Refresh all variables from store (delete current vals)\\
+ %store foo >a.txt - Store value of foo to new file a.txt\\
+ %store foo >>a.txt - Append value of foo to file a.txt\\
+
+ It should be noted that if you change the value of a variable, you
+ need to %store it again if you want to persist the new value.
+
+ Note also that the variables will need to be pickleable; most basic
+ python types can be safely %stored.
+
+ Also aliases can be %store'd across sessions.
+ """
+
+ opts,argsl = self.parse_options(parameter_s,'drz',mode='string')
+ args = argsl.split(None,1)
+ ip = self.getapi()
+ db = ip.db
+ # delete
+ if opts.has_key('d'):
+ try:
+ todel = args[0]
+ except IndexError:
+ raise UsageError('You must provide the variable to forget')
+ else:
+ try:
+ del db['autorestore/' + todel]
+ except:
+ raise UsageError("Can't delete variable '%s'" % todel)
+ # reset
+ elif opts.has_key('z'):
+ for k in db.keys('autorestore/*'):
+ del db[k]
+
+ elif opts.has_key('r'):
+ refresh_variables(ip)
+
+
+ # run without arguments -> list variables & values
+ elif not args:
+ vars = self.db.keys('autorestore/*')
+ vars.sort()
+ if vars:
+ size = max(map(len,vars))
+ else:
+ size = 0
+
+ print 'Stored variables and their in-db values:'
+ fmt = '%-'+str(size)+'s -> %s'
+ get = db.get
+ for var in vars:
+ justkey = os.path.basename(var)
+ # print 30 first characters from every var
+ print fmt % (justkey,repr(get(var,'<unavailable>'))[:50])
+
+ # default action - store the variable
+ else:
+ # %store foo >file.txt or >>file.txt
+ if len(args) > 1 and args[1].startswith('>'):
+ fnam = os.path.expanduser(args[1].lstrip('>').lstrip())
+ if args[1].startswith('>>'):
+ fil = open(fnam,'a')
+ else:
+ fil = open(fnam,'w')
+ obj = ip.ev(args[0])
+ print "Writing '%s' (%s) to file '%s'." % (args[0],
+ obj.__class__.__name__, fnam)
+
+
+ if not isinstance (obj,basestring):
+ from pprint import pprint
+ pprint(obj,fil)
+ else:
+ fil.write(obj)
+ if not obj.endswith('\n'):
+ fil.write('\n')
+
+ fil.close()
+ return
+
+ # %store foo
+ try:
+ obj = ip.user_ns[args[0]]
+ except KeyError:
+ # it might be an alias
+ if args[0] in self.alias_table:
+ staliases = db.get('stored_aliases',{})
+ staliases[ args[0] ] = self.alias_table[ args[0] ]
+ db['stored_aliases'] = staliases
+ print "Alias stored:", args[0], self.alias_table[ args[0] ]
+ return
+ else:
+ raise UsageError("Unknown variable '%s'" % args[0])
+
+ else:
+ if isinstance(inspect.getmodule(obj), FakeModule):
+ print textwrap.dedent("""\
+ Warning:%s is %s
+ Proper storage of interactively declared classes (or instances
+ of those classes) is not possible! Only instances
+ of classes in real modules on file system can be %%store'd.
+ """ % (args[0], obj) )
+ return
+ #pickled = pickle.dumps(obj)
+ self.db[ 'autorestore/' + args[0] ] = obj
+ print "Stored '%s' (%s)" % (args[0], obj.__class__.__name__)
+
+ip.expose_magic('store',magic_store)
diff --git a/IPython/Extensions/scitedirector.py b/IPython/Extensions/scitedirector.py
new file mode 100644
index 0000000..97dc6cd
--- /dev/null
+++ b/IPython/Extensions/scitedirector.py
@@ -0,0 +1,26 @@
+import win32api
+import win32gui
+import win32con
+
+import struct
+import array
+
+def findWindows():
+ ret = []
+ sdi = win32api.RegisterWindowMessage("SciTEDirectorInterface")
+ w = win32gui.GetWindow(win32gui.GetDesktopWindow(), win32con.GW_CHILD)
+ while w:
+ res = win32gui.SendMessage(w, sdi, 0, 0)
+ if res == sdi:
+ ret.append(w)
+ w = win32gui.GetWindow(w, win32con.GW_HWNDNEXT)
+
+ return ret
+
+def sendCommand(w, message):
+ CopyDataStruct = "IIP"
+ char_buffer = array.array('c', message)
+ char_buffer_address = char_buffer.buffer_info()[0]
+ char_buffer_size = char_buffer.buffer_info()[1]
+ cds = struct.pack(CopyDataStruct, 0, char_buffer_size, char_buffer_address)
+ win32gui.SendMessage(w, win32con.WM_COPYDATA, 0, cds)
diff --git a/IPython/Extensions/win32clip.py b/IPython/Extensions/win32clip.py
new file mode 100644
index 0000000..f2030e0
--- /dev/null
+++ b/IPython/Extensions/win32clip.py
@@ -0,0 +1,45 @@
+import IPython.ipapi
+
+ip = IPython.ipapi.get()
+
+def clip_f( self, parameter_s = '' ):
+ """Save a set of lines to the clipboard.
+
+ Usage:\\
+ %clip n1-n2 n3-n4 ... n5 .. n6 ...
+
+ This function uses the same syntax as %macro for line extraction, but
+ instead of creating a macro it saves the resulting string to the
+ clipboard.
+
+ When used without arguments, this returns the text contents of the clipboard.
+ E.g.
+
+ mytext = %clip
+
+ """
+
+ import win32clipboard as cl
+ import win32con
+ args = parameter_s.split()
+ cl.OpenClipboard()
+ if len( args ) == 0:
+ data = cl.GetClipboardData( win32con.CF_TEXT )
+ cl.CloseClipboard()
+ return data
+ api = self.getapi()
+
+ if parameter_s.lstrip().startswith('='):
+ rest = parameter_s[parameter_s.index('=')+1:].strip()
+ val = str(api.ev(rest))
+ else:
+ ranges = args[0:]
+ val = ''.join( self.extract_input_slices( ranges ) )
+
+ cl.EmptyClipboard()
+ cl.SetClipboardText( val )
+ cl.CloseClipboard()
+ print 'The following text was written to the clipboard'
+ print val
+
+ip.expose_magic( "clip", clip_f )
diff --git a/IPython/FakeModule.py b/IPython/FakeModule.py
new file mode 100644
index 0000000..41029f5
--- /dev/null
+++ b/IPython/FakeModule.py
@@ -0,0 +1,66 @@
+# -*- coding: utf-8 -*-
+"""
+Class which mimics a module.
+
+Needed to allow pickle to correctly resolve namespaces during IPython
+sessions.
+"""
+
+#*****************************************************************************
+# Copyright (C) 2002-2004 Fernando Perez. <fperez@colorado.edu>
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#*****************************************************************************
+
+import types
+
+def init_fakemod_dict(fm,adict=None):
+ """Initialize a FakeModule instance __dict__.
+
+ Kept as a standalone function and not a method so the FakeModule API can
+ remain basically empty.
+
+ This should be considered for private IPython use, used in managing
+ namespaces for %run.
+
+ Parameters
+ ----------
+
+ fm : FakeModule instance
+
+ adict : dict, optional
+ """
+
+ dct = {}
+ # It seems pydoc (and perhaps others) needs any module instance to
+ # implement a __nonzero__ method, so we add it if missing:
+ dct.setdefault('__nonzero__',lambda : True)
+ dct.setdefault('__file__',__file__)
+
+ if adict is not None:
+ dct.update(adict)
+
+ # Hard assignment of the object's __dict__. This is nasty but deliberate.
+ fm.__dict__.clear()
+ fm.__dict__.update(dct)
+
+
+class FakeModule(types.ModuleType):
+ """Simple class with attribute access to fake a module.
+
+ This is not meant to replace a module, but to allow inserting a fake
+ module in sys.modules so that systems which rely on run-time module
+ importing (like shelve and pickle) work correctly in interactive IPython
+ sessions.
+
+ Do NOT use this code for anything other than this IPython private hack."""
+
+ def __init__(self,adict=None):
+
+ # tmp to force __dict__ instance creation, else self.__dict__ fails
+ self.__iptmp = None
+ # cleanup our temp trick
+ del self.__iptmp
+ # Now, initialize the actual data in the instance dict.
+ init_fakemod_dict(self,adict)
diff --git a/IPython/Gnuplot2.py b/IPython/Gnuplot2.py
new file mode 100644
index 0000000..cc2eb17
--- /dev/null
+++ b/IPython/Gnuplot2.py
@@ -0,0 +1,665 @@
+# -*- coding: utf-8 -*-
+"""Improved replacement for the Gnuplot.Gnuplot class.
+
+This module imports Gnuplot and replaces some of its functionality with
+improved versions. They add better handling of arrays for plotting and more
+convenient PostScript generation, plus some fixes for hardcopy().
+
+It also adds a convenient plot2 method for plotting dictionaries and
+lists/tuples of arrays.
+
+This module is meant to be used as a drop-in replacement to the original
+Gnuplot, so it should be safe to do:
+
+import IPython.Gnuplot2 as Gnuplot
+"""
+
+import cStringIO
+import os
+import string
+import sys
+import tempfile
+import time
+import types
+
+import Gnuplot as Gnuplot_ori
+import Numeric
+
+from IPython.genutils import popkey,xsys
+
+# needed by hardcopy():
+gp = Gnuplot_ori.gp
+
+# Patch for Gnuplot.py 1.6 compatibility.
+# Thanks to Hayden Callow <h.callow@elec.canterbury.ac.nz>
+try:
+ OptionException = Gnuplot_ori.PlotItems.OptionException
+except AttributeError:
+ OptionException = Gnuplot_ori.Errors.OptionError
+
+# exhibit a similar interface to Gnuplot so it can be somewhat drop-in
+Data = Gnuplot_ori.Data
+Func = Gnuplot_ori.Func
+GridData = Gnuplot_ori.GridData
+PlotItem = Gnuplot_ori.PlotItem
+PlotItems = Gnuplot_ori.PlotItems
+
+# Modify some of Gnuplot's functions with improved versions (or bugfixed, in
+# hardcopy's case). In order to preserve the docstrings at runtime, I've
+# copied them from the original code.
+
+# After some significant changes in v 1.7 of Gnuplot.py, we need to do a bit
+# of version checking.
+
+if Gnuplot_ori.__version__ <= '1.6':
+ _BaseFileItem = PlotItems.File
+ _BaseTempFileItem = PlotItems.TempFile
+
+ # Fix the File class to add the 'index' option for Gnuplot versions < 1.7
+ class File(_BaseFileItem):
+
+ _option_list = _BaseFileItem._option_list.copy()
+ _option_list.update({
+ 'index' : lambda self, index: self.set_option_index(index),
+ })
+
+ # A new initializer is needed b/c we want to add a modified
+ # _option_sequence list which includes 'index' in the right place.
+ def __init__(self,*args,**kw):
+ self._option_sequence = ['binary', 'index', 'using', 'smooth', 'axes',
+ 'title', 'with']
+
+ _BaseFileItem.__init__(self,*args,**kw)
+
+ # Let's fix the constructor docstring
+ __newdoc = \
+ """Additional Keyword arguments added by IPython:
+
+ 'index=<int>' -- similar to the `index` keyword in Gnuplot.
+ This allows only some of the datasets in a file to be
+ plotted. Datasets within a file are assumed to be separated
+ by _pairs_ of blank lines, and the first one is numbered as
+ 0 (similar to C/Python usage)."""
+ __init__.__doc__ = PlotItems.File.__init__.__doc__ + __newdoc
+
+ def set_option_index(self, index):
+ if index is None:
+ self.clear_option('index')
+ elif type(index) in [type(''), type(1)]:
+ self._options['index'] = (index, 'index %s' % index)
+ elif type(index) is type(()):
+ self._options['index'] = (index,'index %s' %
+ string.join(map(repr, index), ':'))
+ else:
+ raise OptionException('index=%s' % (index,))
+
+ # We need a FileClass with a different name from 'File', which is a
+ # factory function in 1.7, so that our String class can subclass FileClass
+ # in any version.
+ _FileClass = File
+
+elif Gnuplot_ori.__version__ =='1.7':
+ _FileClass = _BaseFileItem = PlotItems._FileItem
+ _BaseTempFileItem = PlotItems._TempFileItem
+ File = PlotItems.File
+
+else: # changes in the newer version (svn as of March'06)
+ _FileClass = _BaseFileItem = PlotItems._FileItem
+ _BaseTempFileItem = PlotItems._NewFileItem
+ File = PlotItems.File
+
+
+# Now, we can add our generic code which is version independent
+
+# First some useful utilities
+def eps_fix_bbox(fname):
+ """Fix the bounding box of an eps file by running ps2eps on it.
+
+ If its name ends in .eps, the original file is removed.
+
+ This is particularly useful for plots made by Gnuplot with square aspect
+ ratio: there is a bug in Gnuplot which makes it generate a bounding box
+ which is far wider than the actual plot.
+
+ This function assumes that ps2eps is installed in your system."""
+
+ # note: ps2ps and eps2eps do NOT work, ONLY ps2eps works correctly. The
+ # others make output with bitmapped fonts, which looks horrible.
+ print 'Fixing eps file: <%s>' % fname
+ xsys('ps2eps -f -q -l %s' % fname)
+ if fname.endswith('.eps'):
+ os.rename(fname+'.eps',fname)
+
+def is_list1d(x,containers = [types.ListType,types.TupleType]):
+ """Returns true if x appears to be a 1d list/tuple/array.
+
+ The heuristics are: identify Numeric arrays, or lists/tuples whose first
+ element is not itself a list/tuple. This way zipped lists should work like
+ the original Gnuplot. There's no inexpensive way to know if a list doesn't
+ have a composite object after its first element, so that kind of input
+ will produce an error. But it should work well in most cases.
+ """
+ x_type = type(x)
+
+ return x_type == Numeric.ArrayType and len(x.shape)==1 or \
+ (x_type in containers and
+ type(x[0]) not in containers + [Numeric.ArrayType])
+
+def zip_items(items,titles=None):
+ """zip together neighboring 1-d arrays, and zip standalone ones
+ with their index. Leave other plot items alone."""
+
+ class StandaloneItem(Exception): pass
+
+ def get_titles(titles):
+ """Return the next title and the input titles array.
+
+ The input array may be changed to None when no titles are left to
+ prevent extra unnecessary calls to this function."""
+
+ try:
+ title = titles[tit_ct[0]] # tit_ct[0] is in zip_items'scope
+ except IndexError:
+ titles = None # so we don't enter again
+ title = None
+ else:
+ tit_ct[0] += 1
+ return title,titles
+
+ new_items = []
+
+ if titles:
+ # Initialize counter. It was put in a list as a hack to allow the
+ # nested get_titles to modify it without raising a NameError.
+ tit_ct = [0]
+
+ n = 0 # this loop needs to be done by hand
+ while n < len(items):
+ item = items[n]
+ try:
+ if is_list1d(item):
+ if n==len(items)-1: # last in list
+ raise StandaloneItem
+ else: # check the next item and zip together if needed
+ next_item = items[n+1]
+ if next_item is None:
+ n += 1
+ raise StandaloneItem
+ elif is_list1d(next_item):
+ # this would be best done with an iterator
+ if titles:
+ title,titles = get_titles(titles)
+ else:
+ title = None
+ new_items.append(Data(zip(item,next_item),
+ title=title))
+ n += 1 # avoid double-inclusion of next item
+ else: # can't zip with next, zip with own index list
+ raise StandaloneItem
+ else: # not 1-d array
+ new_items.append(item)
+ except StandaloneItem:
+ if titles:
+ title,titles = get_titles(titles)
+ else:
+ title = None
+ new_items.append(Data(zip(range(len(item)),item),title=title))
+ except AttributeError:
+ new_items.append(item)
+ n+=1
+
+ return new_items
+
+# And some classes with enhanced functionality.
+class String(_FileClass):
+ """Make a PlotItem from data in a string with the same format as a File.
+
+ This allows writing data directly inside python scripts using the exact
+ same format and manipulation options which would be used for external
+ files."""
+
+ def __init__(self, data_str, **keyw):
+ """Construct a String object.
+
+ <data_str> is a string formatted exactly like a valid Gnuplot data
+ file would be. All options from the File constructor are valid here.
+
+ Warning: when used for interactive plotting in scripts which exit
+ immediately, you may get an error because the temporary file used to
+ hold the string data was deleted before Gnuplot had a chance to see
+ it. You can work around this problem by putting a raw_input() call at
+ the end of the script.
+
+ This problem does not appear when generating PostScript output, only
+ with Gnuplot windows."""
+
+ self.tmpfile = _BaseTempFileItem()
+ tmpfile = file(self.tmpfile.filename,'w')
+ tmpfile.write(data_str)
+ _BaseFileItem.__init__(self,self.tmpfile,**keyw)
+
+
+class Gnuplot(Gnuplot_ori.Gnuplot):
+ """Improved Gnuplot class.
+
+ Enhancements: better plot,replot and hardcopy methods. New methods for
+ quick range setting.
+ """
+
+ def xrange(self,min='*',max='*'):
+ """Set xrange. If min/max is omitted, it is set to '*' (auto).
+
+ Note that this is different from the regular Gnuplot behavior, where
+ an unspecified limit means no change. Here any unspecified limit is
+ set to autoscaling, allowing these functions to be used for full
+ autoscaling when called with no arguments.
+
+ To preserve one limit's current value while changing the other, an
+ explicit '' argument must be given as the limit to be kept.
+
+ Similar functions exist for [y{2}z{2}rtuv]range."""
+
+ self('set xrange [%s:%s]' % (min,max))
+
+ def yrange(self,min='*',max='*'):
+ self('set yrange [%s:%s]' % (min,max))
+
+ def zrange(self,min='*',max='*'):
+ self('set zrange [%s:%s]' % (min,max))
+
+ def x2range(self,min='*',max='*'):
+ self('set xrange [%s:%s]' % (min,max))
+
+ def y2range(self,min='*',max='*'):
+ self('set yrange [%s:%s]' % (min,max))
+
+ def z2range(self,min='*',max='*'):
+ self('set zrange [%s:%s]' % (min,max))
+
+ def rrange(self,min='*',max='*'):
+ self('set rrange [%s:%s]' % (min,max))
+
+ def trange(self,min='*',max='*'):
+ self('set trange [%s:%s]' % (min,max))
+
+ def urange(self,min='*',max='*'):
+ self('set urange [%s:%s]' % (min,max))
+
+ def vrange(self,min='*',max='*'):
+ self('set vrange [%s:%s]' % (min,max))
+
+ def set_ps(self,option):
+ """Set an option for the PostScript terminal and reset default term."""
+
+ self('set terminal postscript %s ' % option)
+ self('set terminal %s' % gp.GnuplotOpts.default_term)
+
+ def __plot_ps(self, plot_method,*items, **keyw):
+ """Wrapper for plot/splot/replot, with processing of hardcopy options.
+
+ For internal use only."""
+
+ # Filter out PostScript options which will crash the normal plot/replot
+ psargs = {'filename':None,
+ 'mode':None,
+ 'eps':None,
+ 'enhanced':None,
+ 'color':None,
+ 'solid':None,
+ 'duplexing':None,
+ 'fontname':None,
+ 'fontsize':None,
+ 'debug':0 }
+
+ for k in psargs.keys():
+ if keyw.has_key(k):
+ psargs[k] = keyw[k]
+ del keyw[k]
+
+ # Filter out other options the original plot doesn't know
+ hardcopy = popkey(keyw,'hardcopy',psargs['filename'] is not None)
+ titles = popkey(keyw,'titles',0)
+
+ # the filename keyword should control hardcopy generation, this is an
+ # override switch only which needs to be explicitly set to zero
+ if hardcopy:
+ if psargs['filename'] is None:
+ raise ValueError, \
+ 'If you request hardcopy, you must give a filename.'
+
+ # set null output so nothing goes to screen. hardcopy() restores output
+ self('set term dumb')
+ # I don't know how to prevent screen output in Windows
+ if os.name == 'posix':
+ self('set output "/dev/null"')
+
+ new_items = zip_items(items,titles)
+ # plot_method is either plot or replot from the original Gnuplot class:
+ plot_method(self,*new_items,**keyw)
+
+ # Do hardcopy if requested
+ if hardcopy:
+ if psargs['filename'].endswith('.eps'):
+ psargs['eps'] = 1
+ self.hardcopy(**psargs)
+
+ def plot(self, *items, **keyw):
+ """Draw a new plot.
+
+ Clear the current plot and create a new 2-d plot containing
+ the specified items. Each arguments should be of the
+ following types:
+
+ 'PlotItem' (e.g., 'Data', 'File', 'Func') -- This is the most
+ flexible way to call plot because the PlotItems can
+ contain suboptions. Moreover, PlotItems can be saved to
+ variables so that their lifetime is longer than one plot
+ command; thus they can be replotted with minimal overhead.
+
+ 'string' (e.g., 'sin(x)') -- The string is interpreted as
+ 'Func(string)' (a function that is computed by gnuplot).
+
+ Anything else -- The object, which should be convertible to an
+ array, is passed to the 'Data' constructor, and thus
+ plotted as data. If the conversion fails, an exception is
+ raised.
+
+
+ This is a modified version of plot(). Compared to the original in
+ Gnuplot.py, this version has several enhancements, listed below.
+
+
+ Modifications to the input arguments
+ ------------------------------------
+
+ (1-d array means Numeric array, list or tuple):
+
+ (i) Any 1-d array which is NOT followed by another 1-d array, is
+ automatically zipped with range(len(array_1d)). Typing g.plot(y) will
+ plot y against its indices.
+
+ (ii) If two 1-d arrays are contiguous in the argument list, they are
+ automatically zipped together. So g.plot(x,y) plots y vs. x, and
+ g.plot(x1,y1,x2,y2) plots y1 vs. x1 and y2 vs. x2.
+
+ (iii) Any 1-d array which is followed by None is automatically zipped
+ with range(len(array_1d)). In this form, typing g.plot(y1,None,y2)
+ will plot both y1 and y2 against their respective indices (and NOT
+ versus one another). The None prevents zipping y1 and y2 together, and
+ since y2 is unpaired it is automatically zipped to its indices by (i)
+
+ (iv) Any other arguments which don't match these cases are left alone and
+ passed to the code below.
+
+ For lists or tuples, the heuristics used to determine whether they are
+ in fact 1-d is fairly simplistic: their first element is checked, and
+ if it is not a list or tuple itself, it is assumed that the whole
+ object is one-dimensional.
+
+ An additional optional keyword 'titles' has been added: it must be a
+ list of strings to be used as labels for the individual plots which
+ are NOT PlotItem objects (since those objects carry their own labels
+ within).
+
+
+ PostScript generation
+ ---------------------
+
+ This version of plot() also handles automatically the production of
+ PostScript output. The main options are (given as keyword arguments):
+
+ - filename: a string, typically ending in .eps. If given, the plot is
+ sent to this file in PostScript format.
+
+ - hardcopy: this can be set to 0 to override 'filename'. It does not
+ need to be given to produce PostScript, its purpose is to allow
+ switching PostScript output off globally in scripts without having to
+ manually change 'filename' values in multiple calls.
+
+ All other keywords accepted by Gnuplot.hardcopy() are transparently
+ passed, and safely ignored if output is sent to the screen instead of
+ PostScript.
+
+ For example:
+
+ In [1]: x=frange(0,2*pi,npts=100)
+
+ Generate a plot in file 'sin.eps':
+
+ In [2]: plot(x,sin(x),filename = 'sin.eps')
+
+ Plot to screen instead, without having to change the filename:
+
+ In [3]: plot(x,sin(x),filename = 'sin.eps',hardcopy=0)
+
+ Pass the 'color=0' option to hardcopy for monochrome output:
+
+ In [4]: plot(x,sin(x),filename = 'sin.eps',color=0)
+
+ PostScript generation through plot() is useful mainly for scripting
+ uses where you are not interested in interactive plotting. For
+ interactive use, the hardcopy() function is typically more convenient:
+
+ In [5]: plot(x,sin(x))
+
+ In [6]: hardcopy('sin.eps') """
+
+ self.__plot_ps(Gnuplot_ori.Gnuplot.plot,*items,**keyw)
+
+ def plot2(self,arg,**kw):
+ """Plot the entries of a dictionary or a list/tuple of arrays.
+
+ This simple utility calls plot() with a list of Gnuplot.Data objects
+ constructed either from the values of the input dictionary, or the entries
+ in it if it is a tuple or list. Each item gets labeled with the key/index
+ in the Gnuplot legend.
+
+ Each item is plotted by zipping it with a list of its indices.
+
+ Any keywords are passed directly to plot()."""
+
+ if hasattr(arg,'keys'):
+ keys = arg.keys()
+ keys.sort()
+ else:
+ keys = range(len(arg))
+
+ pitems = [Data(zip(range(len(arg[k])),arg[k]),title=`k`) for k in keys]
+ self.plot(*pitems,**kw)
+
+ def splot(self, *items, **keyw):
+ """Draw a new three-dimensional plot.
+
+ Clear the current plot and create a new 3-d plot containing
+ the specified items. Arguments can be of the following types:
+
+ 'PlotItem' (e.g., 'Data', 'File', 'Func', 'GridData' ) -- This
+ is the most flexible way to call plot because the
+ PlotItems can contain suboptions. Moreover, PlotItems can
+ be saved to variables so that their lifetime is longer
+ than one plot command--thus they can be replotted with
+ minimal overhead.
+
+ 'string' (e.g., 'sin(x*y)') -- The string is interpreted as a
+ 'Func()' (a function that is computed by gnuplot).
+
+ Anything else -- The object is converted to a Data() item, and
+ thus plotted as data. Note that each data point should
+ normally have at least three values associated with it
+ (i.e., x, y, and z). If the conversion fails, an
+ exception is raised.
+
+ This is a modified version of splot(). Compared to the original in
+ Gnuplot.py, this version has several enhancements, listed in the
+ plot() documentation.
+ """
+
+ self.__plot_ps(Gnuplot_ori.Gnuplot.splot,*items,**keyw)
+
+ def replot(self, *items, **keyw):
+ """Replot the data, possibly adding new 'PlotItem's.
+
+ Replot the existing graph, using the items in the current
+ itemlist. If arguments are specified, they are interpreted as
+ additional items to be plotted alongside the existing items on
+ the same graph. See 'plot' for details.
+
+ If you want to replot to a postscript file, you MUST give the
+ 'filename' keyword argument in each call to replot. The Gnuplot python
+ interface has no way of knowing that your previous call to
+ Gnuplot.plot() was meant for PostScript output."""
+
+ self.__plot_ps(Gnuplot_ori.Gnuplot.replot,*items,**keyw)
+
+ # The original hardcopy has a bug. See fix at the end. The rest of the code
+ # was lifted verbatim from the original, so that people using IPython get the
+ # benefits without having to manually patch Gnuplot.py
+ def hardcopy(self, filename=None,
+ mode=None,
+ eps=None,
+ enhanced=None,
+ color=None,
+ solid=None,
+ duplexing=None,
+ fontname=None,
+ fontsize=None,
+ debug = 0,
+ ):
+ """Create a hardcopy of the current plot.
+
+ Create a postscript hardcopy of the current plot to the
+ default printer (if configured) or to the specified filename.
+
+ Note that gnuplot remembers the postscript suboptions across
+ terminal changes. Therefore if you set, for example, color=1
+ for one hardcopy then the next hardcopy will also be color
+ unless you explicitly choose color=0. Alternately you can
+ force all of the options to their defaults by setting
+ mode='default'. I consider this to be a bug in gnuplot.
+
+ Keyword arguments:
+
+ 'filename=<string>' -- if a filename is specified, save the
+ output in that file; otherwise print it immediately
+ using the 'default_lpr' configuration option. If the
+ filename ends in '.eps', EPS mode is automatically
+ selected (like manually specifying eps=1 or mode='eps').
+
+ 'mode=<string>' -- set the postscript submode ('landscape',
+ 'portrait', 'eps', or 'default'). The default is
+ to leave this option unspecified.
+
+ 'eps=<bool>' -- shorthand for 'mode="eps"'; asks gnuplot to
+ generate encapsulated postscript.
+
+ 'enhanced=<bool>' -- if set (the default), then generate
+ enhanced postscript, which allows extra features like
+ font-switching, superscripts, and subscripts in axis
+ labels. (Some old gnuplot versions do not support
+ enhanced postscript; if this is the case set
+ gp.GnuplotOpts.prefer_enhanced_postscript=None.)
+
+ 'color=<bool>' -- if set, create a plot with color. Default
+ is to leave this option unchanged.
+
+ 'solid=<bool>' -- if set, force lines to be solid (i.e., not
+ dashed).
+
+ 'duplexing=<string>' -- set duplexing option ('defaultplex',
+ 'simplex', or 'duplex'). Only request double-sided
+ printing if your printer can handle it. Actually this
+ option is probably meaningless since hardcopy() can only
+ print a single plot at a time.
+
+ 'fontname=<string>' -- set the default font to <string>,
+ which must be a valid postscript font. The default is
+ to leave this option unspecified.
+
+ 'fontsize=<double>' -- set the default font size, in
+ postscript points.
+
+ 'debug=<bool>' -- print extra debugging information (useful if
+ your PostScript files are misteriously not being created).
+ """
+
+ if filename is None:
+ assert gp.GnuplotOpts.default_lpr is not None, \
+ OptionException('default_lpr is not set, so you can only '
+ 'print to a file.')
+ filename = gp.GnuplotOpts.default_lpr
+ lpr_output = 1
+ else:
+ if filename.endswith('.eps'):
+ eps = 1
+ lpr_output = 0
+
+ # Be careful processing the options. If the user didn't
+ # request an option explicitly, do not specify it on the 'set
+ # terminal' line (don't even specify the default value for the
+ # option). This is to avoid confusing older versions of
+ # gnuplot that do not support all of these options. The
+ # exception is 'enhanced', which is just too useful to have to
+ # specify each time!
+
+ setterm = ['set', 'terminal', 'postscript']
+ if eps:
+ assert mode is None or mode=='eps', \
+ OptionException('eps option and mode are incompatible')
+ setterm.append('eps')
+ else:
+ if mode is not None:
+ assert mode in ['landscape', 'portrait', 'eps', 'default'], \
+ OptionException('illegal mode "%s"' % mode)
+ setterm.append(mode)
+ if enhanced is None:
+ enhanced = gp.GnuplotOpts.prefer_enhanced_postscript
+ if enhanced is not None:
+ if enhanced: setterm.append('enhanced')
+ else: setterm.append('noenhanced')
+ if color is not None:
+ if color: setterm.append('color')
+ else: setterm.append('monochrome')
+ if solid is not None:
+ if solid: setterm.append('solid')
+ else: setterm.append('dashed')
+ if duplexing is not None:
+ assert duplexing in ['defaultplex', 'simplex', 'duplex'], \
+ OptionException('illegal duplexing mode "%s"' % duplexing)
+ setterm.append(duplexing)
+ if fontname is not None:
+ setterm.append('"%s"' % fontname)
+ if fontsize is not None:
+ setterm.append('%s' % fontsize)
+
+ self(string.join(setterm))
+ self.set_string('output', filename)
+ # replot the current figure (to the printer):
+ self.refresh()
+
+ # fperez. Ugly kludge: often for some reason the file is NOT created
+ # and we must reissue the creation commands. I have no idea why!
+ if not lpr_output:
+ #print 'Hardcopy <%s>' % filename # dbg
+ maxtries = 20
+ delay = 0.1 # delay (in seconds) between print attempts
+ for i in range(maxtries):
+ time.sleep(0.05) # safety, very small delay
+ if os.path.isfile(filename):
+ if debug:
+ print 'Hardcopy to file <%s> success at attempt #%s.' \
+ % (filename,i+1)
+ break
+ time.sleep(delay)
+ # try again, issue all commands just in case
+ self(string.join(setterm))
+ self.set_string('output', filename)
+ self.refresh()
+ if not os.path.isfile(filename):
+ print >> sys.stderr,'ERROR: Tried %s times and failed to '\
+ 'create hardcopy file `%s`' % (maxtries,filename)
+
+ # reset the terminal to its `default' setting:
+ self('set terminal %s' % gp.GnuplotOpts.default_term)
+ self.set_string('output')
+
+#********************** End of file <Gnuplot2.py> ************************
diff --git a/IPython/GnuplotInteractive.py b/IPython/GnuplotInteractive.py
new file mode 100644
index 0000000..074d2f5
--- /dev/null
+++ b/IPython/GnuplotInteractive.py
@@ -0,0 +1,147 @@
+# -*- coding: utf-8 -*-
+"""Interactive functions and magic functions for Gnuplot usage.
+
+This requires the Gnuplot.py module for interfacing python with Gnuplot, which
+can be downloaded from:
+
+http://gnuplot-py.sourceforge.net/
+
+See gphelp() below for details on the services offered by this module.
+
+Inspired by a suggestion/request from Arnd Baecker.
+"""
+
+__all__ = ['Gnuplot','gp','gp_new','plot','plot2','splot','replot',
+ 'hardcopy','gpdata','gpfile','gpstring','gpfunc','gpgrid',
+ 'gphelp']
+
+import IPython.GnuplotRuntime as GRun
+from IPython.genutils import page,warn
+
+# Set global names for interactive use
+Gnuplot = GRun.Gnuplot
+gp_new = GRun.gp_new
+gp = GRun.gp
+plot = gp.plot
+plot2 = gp.plot2
+splot = gp.splot
+replot = gp.replot
+hardcopy = gp.hardcopy
+
+# Accessors for the main plot object constructors:
+gpdata = Gnuplot.Data
+gpfile = Gnuplot.File
+gpstring = Gnuplot.String
+gpfunc = Gnuplot.Func
+gpgrid = Gnuplot.GridData
+
+def gphelp():
+ """Print information about the Gnuplot facilities in IPython."""
+
+ page("""
+IPython provides an interface to access the Gnuplot scientific plotting
+system, in an environment similar to that of Mathematica or Matlab.
+
+New top-level global objects
+----------------------------
+
+Please see their respective docstrings for further details.
+
+- gp: a running Gnuplot instance. You can access its methods as
+gp.<method>. gp(`a string`) will execute the given string as if it had been
+typed in an interactive gnuplot window.
+
+- plot, splot, replot and hardcopy: aliases to the methods of the same name in
+the global running Gnuplot instance gp. These allow you to simply type:
+
+In [1]: plot(x,sin(x),title='Sin(x)') # assuming x is a Numeric array
+
+and obtain a plot of sin(x) vs x with the title 'Sin(x)'.
+
+- gp_new: a function which returns a new Gnuplot instance. This can be used to
+have multiple Gnuplot instances running in your session to compare different
+plots, each in a separate window.
+
+- Gnuplot: alias to the Gnuplot2 module, an improved drop-in replacement for
+the original Gnuplot.py. Gnuplot2 needs Gnuplot but redefines several of its
+functions with improved versions (Gnuplot2 comes with IPython).
+
+- gpdata, gpfile, gpstring, gpfunc, gpgrid: aliases to Gnuplot.Data,
+Gnuplot.File, Gnuplot.String, Gnuplot.Func and Gnuplot.GridData
+respectively. These functions create objects which can then be passed to the
+plotting commands. See the Gnuplot.py documentation for details.
+
+Keep in mind that all commands passed to a Gnuplot instance are executed in
+the Gnuplot namespace, where no Python variables exist. For example, for
+plotting sin(x) vs x as above, typing
+
+In [2]: gp('plot x,sin(x)')
+
+would not work. Instead, you would get the plot of BOTH the functions 'x' and
+'sin(x)', since Gnuplot doesn't know about the 'x' Python array. The plot()
+method lives in python and does know about these variables.
+
+
+New magic functions
+-------------------
+
+%gpc: pass one command to Gnuplot and execute it or open a Gnuplot shell where
+each line of input is executed.
+
+%gp_set_default: reset the value of IPython's global Gnuplot instance.""")
+
+# Code below is all for IPython use
+# Define the magic functions for communicating with the above gnuplot instance.
+def magic_gpc(self,parameter_s=''):
+ """Execute a gnuplot command or open a gnuplot shell.
+
+ Usage (omit the % if automagic is on). There are two ways to use it:
+
+ 1) %gpc 'command' -> passes 'command' directly to the gnuplot instance.
+
+ 2) %gpc -> will open up a prompt (gnuplot>>>) which takes input like the
+ standard gnuplot interactive prompt. If you need to type a multi-line
+ command, use \\ at the end of each intermediate line.
+
+ Upon exiting of the gnuplot sub-shell, you return to your IPython
+ session (the gnuplot sub-shell can be invoked as many times as needed).
+ """
+
+ if parameter_s.strip():
+ self.shell.gnuplot(parameter_s)
+ else:
+ self.shell.gnuplot.interact()
+
+def magic_gp_set_default(self,parameter_s=''):
+ """Set the default gnuplot instance accessed by the %gp magic function.
+
+ %gp_set_default name
+
+ Call with the name of the new instance at the command line. If you want to
+ set this instance in your own code (using an embedded IPython, for
+ example), simply set the variable __IPYTHON__.gnuplot to your own gnuplot
+ instance object."""
+
+ gname = parameter_s.strip()
+ G = eval(gname,self.shell.user_ns)
+ self.shell.gnuplot = G
+ self.shell.user_ns.update({'plot':G.plot,'splot':G.splot,'plot2':G.plot2,
+ 'replot':G.replot,'hardcopy':G.hardcopy})
+
+try:
+ __IPYTHON__
+except NameError:
+ pass
+else:
+ # make the global Gnuplot instance known to IPython
+ __IPYTHON__.gnuplot = GRun.gp
+ __IPYTHON__.gnuplot.shell_first_time = 1
+
+ print """*** Type `gphelp` for help on the Gnuplot integration features."""
+
+ # Add the new magic functions to the class dict
+ from IPython.iplib import InteractiveShell
+ InteractiveShell.magic_gpc = magic_gpc
+ InteractiveShell.magic_gp_set_default = magic_gp_set_default
+
+#********************** End of file <GnuplotInteractive.py> *******************
diff --git a/IPython/GnuplotRuntime.py b/IPython/GnuplotRuntime.py
new file mode 100644
index 0000000..8bd5185
--- /dev/null
+++ b/IPython/GnuplotRuntime.py
@@ -0,0 +1,146 @@
+# -*- coding: utf-8 -*-
+"""Basic Gnuplot functionality for inclusion in other code.
+
+This module creates a running Gnuplot instance called 'gp' and builds other
+convenient globals for quick use in running scripts. It is intended to allow
+you to script plotting tasks in Python with a minimum of effort. A typical
+usage would be:
+
+import IPython.GnuplotRuntime as GP # or some other short name
+GP.gp.plot(GP.File('your_data.dat'))
+
+
+This module exposes the following objects:
+
+- gp: a running Gnuplot instance. You can access its methods as
+gp.<method>. gp(`a string`) will execute the given string as if it had been
+typed in an interactive gnuplot window.
+
+- gp_new: a function which returns a new Gnuplot instance. This can be used to
+have multiple Gnuplot instances running in your session to compare different
+plots.
+
+- Gnuplot: alias to the Gnuplot2 module, an improved drop-in replacement for
+the original Gnuplot.py. Gnuplot2 needs Gnuplot but redefines several of its
+functions with improved versions (Gnuplot2 comes with IPython).
+
+- Data: alias to Gnuplot.Data, makes a PlotItem from array data.
+
+- File: alias to Gnuplot.File, makes a PlotItem from a file.
+
+- String: alias to Gnuplot.String, makes a PlotItem from a string formatted
+exactly like a file for Gnuplot.File would be.
+
+- Func: alias to Gnuplot.Func, makes a PlotItem from a function string.
+
+- GridData: alias to Gnuplot.GridData, makes a PlotItem from grid data.
+
+- pm3d_config: a string with Gnuplot commands to set up the pm3d mode for
+surface plotting. You can activate it simply by calling gp(pm3d_config).
+
+- eps_fix_bbox: A Unix-only function to fix eps files with bad bounding boxes
+(which Gnuplot generates when the plot size is set to square).
+
+This requires the Gnuplot.py module for interfacing Python with Gnuplot, which
+can be downloaded from:
+
+http://gnuplot-py.sourceforge.net/
+
+Inspired by a suggestion/request from Arnd Baecker.
+"""
+
+__all__ = ['Gnuplot','gp','gp_new','Data','File','Func','GridData',
+ 'pm3d_config','eps_fix_bbox']
+
+import os,tempfile,sys
+from IPython.genutils import getoutput
+
+#---------------------------------------------------------------------------
+# Notes on mouse support for Gnuplot.py
+
+# If you do not have a mouse-enabled gnuplot, set gnuplot_mouse to 0. If you
+# use gnuplot, you should really grab a recent, mouse enabled copy. It is an
+# extremely useful feature. Mouse support is official as of gnuplot 4.0,
+# released in April 2004.
+
+# For the mouse features to work correctly, you MUST set your Gnuplot.py
+# module to use temporary files instead of 'inline data' for data
+# communication. Note that this is the default, so unless you've manually
+# fiddled with it you should be ok. If you need to make changes, in the
+# Gnuplot module directory, loook for the gp_unix.py file and make sure the
+# prefer_inline_data variable is set to 0. If you set it to 1 Gnuplot.py will
+# try to pass the data to gnuplot via standard input, which completely
+# confuses the mouse control system (even though it may be a bit faster than
+# using temp files).
+
+# As of Gnuplot.py v1.7, a new option was added to use FIFOs (pipes). This
+# mechanism, while fast, also breaks the mouse system. You must therefore set
+# the variable prefer_fifo_data to 0 in gp_unix.py.
+
+tmpname = tempfile.mktemp()
+open(tmpname,'w').write('set mouse')
+gnu_out = getoutput('gnuplot '+ tmpname)
+os.unlink(tmpname)
+if gnu_out: # Gnuplot won't print anything if it has mouse support
+ print "*** Your version of Gnuplot appears not to have mouse support."
+ gnuplot_mouse = 0
+else:
+ gnuplot_mouse = 1
+del tmpname,gnu_out
+
+# Default state for persistence of new gnuplot instances
+if os.name in ['nt','dos'] or sys.platform == 'cygwin':
+ gnuplot_persist = 0
+else:
+ gnuplot_persist = 1
+
+import IPython.Gnuplot2 as Gnuplot
+
+class NotGiven: pass
+
+def gp_new(mouse=NotGiven,persist=NotGiven):
+ """Return a new Gnuplot instance.
+
+ The instance returned uses the improved methods defined in Gnuplot2.
+
+ Options (boolean):
+
+ - mouse: if unspecified, the module global gnuplot_mouse is used.
+
+ - persist: if unspecified, the module global gnuplot_persist is used."""
+
+ if mouse is NotGiven:
+ mouse = gnuplot_mouse
+ if persist is NotGiven:
+ persist = gnuplot_persist
+ g = Gnuplot.Gnuplot(persist=persist)
+ if mouse:
+ g('set mouse')
+ return g
+
+# Global-level names.
+
+# A global Gnuplot instance for interactive use:
+gp = gp_new()
+
+# Accessors for the main plot object constructors:
+Data = Gnuplot.Data
+File = Gnuplot.File
+Func = Gnuplot.Func
+String = Gnuplot.String
+GridData = Gnuplot.GridData
+
+# A Unix-only function to fix eps files with bad bounding boxes (which Gnuplot
+# generates when the plot size is set to square):
+eps_fix_bbox = Gnuplot.eps_fix_bbox
+
+# String for configuring pm3d. Simply call g(pm3d_config) to execute it. pm3d
+# is a very nice mode for plotting colormaps on surfaces. Modify the defaults
+# below to suit your taste.
+pm3d_config = """
+set pm3d solid
+set hidden3d
+unset surface
+set isosamples 50
+"""
+#******************** End of file <GnuplotRuntime.py> ******************
diff --git a/IPython/Itpl.py b/IPython/Itpl.py
new file mode 100644
index 0000000..7deba81
--- /dev/null
+++ b/IPython/Itpl.py
@@ -0,0 +1,290 @@
+# -*- coding: utf-8 -*-
+"""String interpolation for Python (by Ka-Ping Yee, 14 Feb 2000).
+
+This module lets you quickly and conveniently interpolate values into
+strings (in the flavour of Perl or Tcl, but with less extraneous
+punctuation). You get a bit more power than in the other languages,
+because this module allows subscripting, slicing, function calls,
+attribute lookup, or arbitrary expressions. Variables and expressions
+are evaluated in the namespace of the caller.
+
+The itpl() function returns the result of interpolating a string, and
+printpl() prints out an interpolated string. Here are some examples:
+
+ from Itpl import printpl
+ printpl("Here is a $string.")
+ printpl("Here is a $module.member.")
+ printpl("Here is an $object.member.")
+ printpl("Here is a $functioncall(with, arguments).")
+ printpl("Here is an ${arbitrary + expression}.")
+ printpl("Here is an $array[3] member.")
+ printpl("Here is a $dictionary['member'].")
+
+The filter() function filters a file object so that output through it
+is interpolated. This lets you produce the illusion that Python knows
+how to do interpolation:
+
+ import Itpl
+ sys.stdout = Itpl.filter()
+ f = "fancy"
+ print "Is this not $f?"
+ print "Standard output has been replaced with a $sys.stdout object."
+ sys.stdout = Itpl.unfilter()
+ print "Okay, back $to $normal."
+
+Under the hood, the Itpl class represents a string that knows how to
+interpolate values. An instance of the class parses the string once
+upon initialization; the evaluation and substitution can then be done
+each time the instance is evaluated with str(instance). For example:
+
+ from Itpl import Itpl
+ s = Itpl("Here is $foo.")
+ foo = 5
+ print str(s)
+ foo = "bar"
+ print str(s)
+"""
+
+#*****************************************************************************
+#
+# Copyright (c) 2001 Ka-Ping Yee <ping@lfw.org>
+#
+#
+# Published under the terms of the MIT license, hereby reproduced:
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+#
+#*****************************************************************************
+
+__author__ = 'Ka-Ping Yee <ping@lfw.org>'
+__license__ = 'MIT'
+
+import string
+import sys
+from tokenize import tokenprog
+from types import StringType
+
+class ItplError(ValueError):
+ def __init__(self, text, pos):
+ self.text = text
+ self.pos = pos
+ def __str__(self):
+ return "unfinished expression in %s at char %d" % (
+ repr(self.text), self.pos)
+
+def matchorfail(text, pos):
+ match = tokenprog.match(text, pos)
+ if match is None:
+ raise ItplError(text, pos)
+
+ return match, match.end()
+
+try:
+ itpl_encoding = sys.stdin.encoding or 'ascii'
+except AttributeError:
+ itpl_encoding = 'ascii'
+
+
+
+class Itpl:
+ """Class representing a string with interpolation abilities.
+
+ Upon creation, an instance works out what parts of the format
+ string are literal and what parts need to be evaluated. The
+ evaluation and substitution happens in the namespace of the
+ caller when str(instance) is called."""
+
+ def __init__(self, format,codec=itpl_encoding,encoding_errors='backslashreplace'):
+ """The single mandatory argument to this constructor is a format
+ string.
+
+ The format string is parsed according to the following rules:
+
+ 1. A dollar sign and a name, possibly followed by any of:
+ - an open-paren, and anything up to the matching paren
+ - an open-bracket, and anything up to the matching bracket
+ - a period and a name
+ any number of times, is evaluated as a Python expression.
+
+ 2. A dollar sign immediately followed by an open-brace, and
+ anything up to the matching close-brace, is evaluated as
+ a Python expression.
+
+ 3. Outside of the expressions described in the above two rules,
+ two dollar signs in a row give you one literal dollar sign.
+
+ Optional arguments:
+
+ - codec('utf_8'): a string containing the name of a valid Python
+ codec.
+
+ - encoding_errors('backslashreplace'): a string with a valid error handling
+ policy. See the codecs module documentation for details.
+
+ These are used to encode the format string if a call to str() fails on
+ the expanded result."""
+
+ if not isinstance(format,basestring):
+ raise TypeError, "needs string initializer"
+ self.format = format
+ self.codec = codec
+ self.encoding_errors = encoding_errors
+
+ namechars = "abcdefghijklmnopqrstuvwxyz" \
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
+ chunks = []
+ pos = 0
+
+ while 1:
+ dollar = string.find(format, "$", pos)
+ if dollar < 0: break
+ nextchar = format[dollar+1]
+
+ if nextchar == "{":
+ chunks.append((0, format[pos:dollar]))
+ pos, level = dollar+2, 1
+ while level:
+ match, pos = matchorfail(format, pos)
+ tstart, tend = match.regs[3]
+ token = format[tstart:tend]
+ if token == "{": level = level+1
+ elif token == "}": level = level-1
+ chunks.append((1, format[dollar+2:pos-1]))
+
+ elif nextchar in namechars:
+ chunks.append((0, format[pos:dollar]))
+ match, pos = matchorfail(format, dollar+1)
+ while pos < len(format):
+ if format[pos] == "." and \
+ pos+1 < len(format) and format[pos+1] in namechars:
+ match, pos = matchorfail(format, pos+1)
+ elif format[pos] in "([":
+ pos, level = pos+1, 1
+ while level:
+ match, pos = matchorfail(format, pos)
+ tstart, tend = match.regs[3]
+ token = format[tstart:tend]
+ if token[0] in "([": level = level+1
+ elif token[0] in ")]": level = level-1
+ else: break
+ chunks.append((1, format[dollar+1:pos]))
+
+ else:
+ chunks.append((0, format[pos:dollar+1]))
+ pos = dollar + 1 + (nextchar == "$")
+
+ if pos < len(format): chunks.append((0, format[pos:]))
+ self.chunks = chunks
+
+ def __repr__(self):
+ return "<Itpl %s >" % repr(self.format)
+
+ def _str(self,glob,loc):
+ """Evaluate to a string in the given globals/locals.
+
+ The final output is built by calling str(), but if this fails, the
+ result is encoded with the instance's codec and error handling policy,
+ via a call to out.encode(self.codec,self.encoding_errors)"""
+ result = []
+ app = result.append
+ for live, chunk in self.chunks:
+ if live:
+ val = eval(chunk,glob,loc)
+ try:
+ app(str(val))
+ except UnicodeEncodeError:
+ app(unicode(val))
+
+ else: app(chunk)
+ out = ''.join(result)
+ try:
+ return str(out)
+ except UnicodeError:
+ return out.encode(self.codec,self.encoding_errors)
+
+ def __str__(self):
+ """Evaluate and substitute the appropriate parts of the string."""
+
+ # We need to skip enough frames to get to the actual caller outside of
+ # Itpl.
+ frame = sys._getframe(1)
+ while frame.f_globals["__name__"] == __name__: frame = frame.f_back
+ loc, glob = frame.f_locals, frame.f_globals
+
+ return self._str(glob,loc)
+
+class ItplNS(Itpl):
+ """Class representing a string with interpolation abilities.
+
+ This inherits from Itpl, but at creation time a namespace is provided
+ where the evaluation will occur. The interpolation becomes a bit more
+ efficient, as no traceback needs to be extracte. It also allows the
+ caller to supply a different namespace for the interpolation to occur than
+ its own."""
+
+ def __init__(self, format,globals,locals=None,
+ codec='utf_8',encoding_errors='backslashreplace'):
+ """ItplNS(format,globals[,locals]) -> interpolating string instance.
+
+ This constructor, besides a format string, takes a globals dictionary
+ and optionally a locals (which defaults to globals if not provided).
+
+ For further details, see the Itpl constructor."""
+
+ if locals is None:
+ locals = globals
+ self.globals = globals
+ self.locals = locals
+ Itpl.__init__(self,format,codec,encoding_errors)
+
+ def __str__(self):
+ """Evaluate and substitute the appropriate parts of the string."""
+ return self._str(self.globals,self.locals)
+
+ def __repr__(self):
+ return "<ItplNS %s >" % repr(self.format)
+
+# utilities for fast printing
+def itpl(text): return str(Itpl(text))
+def printpl(text): print itpl(text)
+# versions with namespace
+def itplns(text,globals,locals=None): return str(ItplNS(text,globals,locals))
+def printplns(text,globals,locals=None): print itplns(text,globals,locals)
+
+class ItplFile:
+ """A file object that filters each write() through an interpolator."""
+ def __init__(self, file): self.file = file
+ def __repr__(self): return "<interpolated " + repr(self.file) + ">"
+ def __getattr__(self, attr): return getattr(self.file, attr)
+ def write(self, text): self.file.write(str(Itpl(text)))
+
+def filter(file=sys.stdout):
+ """Return an ItplFile that filters writes to the given file object.
+
+ 'file = filter(file)' replaces 'file' with a filtered object that
+ has a write() method. When called with no argument, this creates
+ a filter to sys.stdout."""
+ return ItplFile(file)
+
+def unfilter(ifile=None):
+ """Return the original file that corresponds to the given ItplFile.
+
+ 'file = unfilter(file)' undoes the effect of 'file = filter(file)'.
+ 'sys.stdout = unfilter()' undoes the effect of 'sys.stdout = filter()'."""
+ return ifile and ifile.file or sys.stdout.file
diff --git a/IPython/Logger.py b/IPython/Logger.py
new file mode 100644
index 0000000..be7bd7b
--- /dev/null
+++ b/IPython/Logger.py
@@ -0,0 +1,263 @@
+# -*- coding: utf-8 -*-
+"""
+Logger class for IPython's logging facilities.
+"""
+
+#*****************************************************************************
+# Copyright (C) 2001 Janko Hauser <jhauser@zscout.de> and
+# Copyright (C) 2001-2006 Fernando Perez <fperez@colorado.edu>
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#*****************************************************************************
+
+#****************************************************************************
+# Modules and globals
+
+# Python standard modules
+import glob
+import os
+import time
+
+#****************************************************************************
+# FIXME: This class isn't a mixin anymore, but it still needs attributes from
+# ipython and does input cache management. Finish cleanup later...
+
+class Logger(object):
+ """A Logfile class with different policies for file creation"""
+
+ def __init__(self,shell,logfname='Logger.log',loghead='',logmode='over'):
+
+ self._i00,self._i,self._ii,self._iii = '','','',''
+
+ # this is the full ipython instance, we need some attributes from it
+ # which won't exist until later. What a mess, clean up later...
+ self.shell = shell
+
+ self.logfname = logfname
+ self.loghead = loghead
+ self.logmode = logmode
+ self.logfile = None
+
+ # Whether to log raw or processed input
+ self.log_raw_input = False
+
+ # whether to also log output
+ self.log_output = False
+
+ # whether to put timestamps before each log entry
+ self.timestamp = False
+
+ # activity control flags
+ self.log_active = False
+
+ # logmode is a validated property
+ def _set_mode(self,mode):
+ if mode not in ['append','backup','global','over','rotate']:
+ raise ValueError,'invalid log mode %s given' % mode
+ self._logmode = mode
+
+ def _get_mode(self):
+ return self._logmode
+
+ logmode = property(_get_mode,_set_mode)
+
+ def logstart(self,logfname=None,loghead=None,logmode=None,
+ log_output=False,timestamp=False,log_raw_input=False):
+ """Generate a new log-file with a default header.
+
+ Raises RuntimeError if the log has already been started"""
+
+ if self.logfile is not None:
+ raise RuntimeError('Log file is already active: %s' %
+ self.logfname)
+
+ self.log_active = True
+
+ # The parameters can override constructor defaults
+ if logfname is not None: self.logfname = logfname
+ if loghead is not None: self.loghead = loghead
+ if logmode is not None: self.logmode = logmode
+
+ # Parameters not part of the constructor
+ self.timestamp = timestamp
+ self.log_output = log_output
+ self.log_raw_input = log_raw_input
+
+ # init depending on the log mode requested
+ isfile = os.path.isfile
+ logmode = self.logmode
+
+ if logmode == 'append':
+ self.logfile = open(self.logfname,'a')
+
+ elif logmode == 'backup':
+ if isfile(self.logfname):
+ backup_logname = self.logfname+'~'
+ # Manually remove any old backup, since os.rename may fail
+ # under Windows.
+ if isfile(backup_logname):
+ os.remove(backup_logname)
+ os.rename(self.logfname,backup_logname)
+ self.logfile = open(self.logfname,'w')
+
+ elif logmode == 'global':
+ self.logfname = os.path.join(self.shell.home_dir,self.logfname)
+ self.logfile = open(self.logfname, 'a')
+
+ elif logmode == 'over':
+ if isfile(self.logfname):
+ os.remove(self.logfname)
+ self.logfile = open(self.logfname,'w')
+
+ elif logmode == 'rotate':
+ if isfile(self.logfname):
+ if isfile(self.logfname+'.001~'):
+ old = glob.glob(self.logfname+'.*~')
+ old.sort()
+ old.reverse()
+ for f in old:
+ root, ext = os.path.splitext(f)
+ num = int(ext[1:-1])+1
+ os.rename(f, root+'.'+`num`.zfill(3)+'~')
+ os.rename(self.logfname, self.logfname+'.001~')
+ self.logfile = open(self.logfname,'w')
+
+ if logmode != 'append':
+ self.logfile.write(self.loghead)
+
+ self.logfile.flush()
+
+ def switch_log(self,val):
+ """Switch logging on/off. val should be ONLY a boolean."""
+
+ if val not in [False,True,0,1]:
+ raise ValueError, \
+ 'Call switch_log ONLY with a boolean argument, not with:',val
+
+ label = {0:'OFF',1:'ON',False:'OFF',True:'ON'}
+
+ if self.logfile is None:
+ print """
+Logging hasn't been started yet (use logstart for that).
+
+%logon/%logoff are for temporarily starting and stopping logging for a logfile
+which already exists. But you must first start the logging process with
+%logstart (optionally giving a logfile name)."""
+
+ else:
+ if self.log_active == val:
+ print 'Logging is already',label[val]
+ else:
+ print 'Switching logging',label[val]
+ self.log_active = not self.log_active
+ self.log_active_out = self.log_active
+
+ def logstate(self):
+ """Print a status message about the logger."""
+ if self.logfile is None:
+ print 'Logging has not been activated.'
+ else:
+ state = self.log_active and 'active' or 'temporarily suspended'
+ print 'Filename :',self.logfname
+ print 'Mode :',self.logmode
+ print 'Output logging :',self.log_output
+ print 'Raw input log :',self.log_raw_input
+ print 'Timestamping :',self.timestamp
+ print 'State :',state
+
+ def log(self,line_ori,line_mod,continuation=None):
+ """Write the line to a log and create input cache variables _i*.
+
+ Inputs:
+
+ - line_ori: unmodified input line from the user. This is not
+ necessarily valid Python.
+
+ - line_mod: possibly modified input, such as the transformations made
+ by input prefilters or input handlers of various kinds. This should
+ always be valid Python.
+
+ - continuation: if True, indicates this is part of multi-line input."""
+
+ # update the auto _i tables
+ #print '***logging line',line_mod # dbg
+ #print '***cache_count', self.shell.outputcache.prompt_count # dbg
+ try:
+ input_hist = self.shell.user_ns['_ih']
+ except:
+ #print 'userns:',self.shell.user_ns.keys() # dbg
+ return
+
+ out_cache = self.shell.outputcache
+
+ # add blank lines if the input cache fell out of sync.
+ if out_cache.do_full_cache and \
+ out_cache.prompt_count +1 > len(input_hist):
+ input_hist.extend(['\n'] * (out_cache.prompt_count - len(input_hist)))
+
+ if not continuation and line_mod:
+ self._iii = self._ii
+ self._ii = self._i
+ self._i = self._i00
+ # put back the final \n of every input line
+ self._i00 = line_mod+'\n'
+ #print 'Logging input:<%s>' % line_mod # dbg
+ input_hist.append(self._i00)
+ #print '---[%s]' % (len(input_hist)-1,) # dbg
+
+ # hackish access to top-level namespace to create _i1,_i2... dynamically
+ to_main = {'_i':self._i,'_ii':self._ii,'_iii':self._iii}
+ if self.shell.outputcache.do_full_cache:
+ in_num = self.shell.outputcache.prompt_count
+
+ # but if the opposite is true (a macro can produce multiple inputs
+ # with no output display called), then bring the output counter in
+ # sync:
+ last_num = len(input_hist)-1
+ if in_num != last_num:
+ in_num = self.shell.outputcache.prompt_count = last_num
+ new_i = '_i%s' % in_num
+ if continuation:
+ self._i00 = '%s%s\n' % (self.shell.user_ns[new_i],line_mod)
+ input_hist[in_num] = self._i00
+ to_main[new_i] = self._i00
+ self.shell.user_ns.update(to_main)
+
+ # Write the log line, but decide which one according to the
+ # log_raw_input flag, set when the log is started.
+ if self.log_raw_input:
+ self.log_write(line_ori)
+ else:
+ self.log_write(line_mod)
+
+ def log_write(self,data,kind='input'):
+ """Write data to the log file, if active"""
+
+ #print 'data: %r' % data # dbg
+ if self.log_active and data:
+ write = self.logfile.write
+ if kind=='input':
+ if self.timestamp:
+ write(time.strftime('# %a, %d %b %Y %H:%M:%S\n',
+ time.localtime()))
+ write('%s\n' % data)
+ elif kind=='output' and self.log_output:
+ odata = '\n'.join(['#[Out]# %s' % s
+ for s in data.split('\n')])
+ write('%s\n' % odata)
+ self.logfile.flush()
+
+ def logstop(self):
+ """Fully stop logging and close log file.
+
+ In order to start logging again, a new logstart() call needs to be
+ made, possibly (though not necessarily) with a new filename, mode and
+ other options."""
+
+ self.logfile.close()
+ self.logfile = None
+ self.log_active = False
+
+ # For backwards compatibility, in case anyone was using this.
+ close_log = logstop
diff --git a/IPython/Magic.py b/IPython/Magic.py
new file mode 100644
index 0000000..2f1fe71
--- /dev/null
+++ b/IPython/Magic.py
@@ -0,0 +1,3526 @@
+# -*- coding: utf-8 -*-
+"""Magic functions for InteractiveShell.
+"""
+
+#*****************************************************************************
+# Copyright (C) 2001 Janko Hauser <jhauser@zscout.de> and
+# Copyright (C) 2001-2006 Fernando Perez <fperez@colorado.edu>
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#*****************************************************************************
+
+#****************************************************************************
+# Modules and globals
+
+# Python standard modules
+import __builtin__
+import bdb
+import inspect
+import os
+import pdb
+import pydoc
+import sys
+import re
+import tempfile
+import time
+import cPickle as pickle
+import textwrap
+from cStringIO import StringIO
+from getopt import getopt,GetoptError
+from pprint import pprint, pformat
+
+# cProfile was added in Python2.5
+try:
+ import cProfile as profile
+ import pstats
+except ImportError:
+ # profile isn't bundled by default in Debian for license reasons
+ try:
+ import profile,pstats
+ except ImportError:
+ profile = pstats = None
+
+# Homebrewed
+import IPython
+from IPython import Debugger, OInspect, wildcard
+from IPython.FakeModule import FakeModule
+from IPython.Itpl import Itpl, itpl, printpl,itplns
+from IPython.PyColorize import Parser
+from IPython.ipstruct import Struct
+from IPython.macro import Macro
+from IPython.genutils import *
+from IPython import platutils
+import IPython.generics
+import IPython.ipapi
+from IPython.ipapi import UsageError
+from IPython.testing import decorators as testdec
+
+#***************************************************************************
+# Utility functions
+def on_off(tag):
+ """Return an ON/OFF string for a 1/0 input. Simple utility function."""
+ return ['OFF','ON'][tag]
+
+class Bunch: pass
+
+def compress_dhist(dh):
+ head, tail = dh[:-10], dh[-10:]
+
+ newhead = []
+ done = set()
+ for h in head:
+ if h in done:
+ continue
+ newhead.append(h)
+ done.add(h)
+
+ return newhead + tail
+
+
+#***************************************************************************
+# Main class implementing Magic functionality
+class Magic:
+ """Magic functions for InteractiveShell.
+
+ Shell functions which can be reached as %function_name. All magic
+ functions should accept a string, which they can parse for their own
+ needs. This can make some functions easier to type, eg `%cd ../`
+ vs. `%cd("../")`
+
+ ALL definitions MUST begin with the prefix magic_. The user won't need it
+ at the command line, but it is is needed in the definition. """
+
+ # class globals
+ auto_status = ['Automagic is OFF, % prefix IS needed for magic functions.',
+ 'Automagic is ON, % prefix NOT needed for magic functions.']
+
+ #......................................................................
+ # some utility functions
+
+ def __init__(self,shell):
+
+ self.options_table = {}
+ if profile is None:
+ self.magic_prun = self.profile_missing_notice
+ self.shell = shell
+
+ # namespace for holding state we may need
+ self._magic_state = Bunch()
+
+ def profile_missing_notice(self, *args, **kwargs):
+ error("""\
+The profile module could not be found. It has been removed from the standard
+python packages because of its non-free license. To use profiling, install the
+python-profiler package from non-free.""")
+
+ def default_option(self,fn,optstr):
+ """Make an entry in the options_table for fn, with value optstr"""
+
+ if fn not in self.lsmagic():
+ error("%s is not a magic function" % fn)
+ self.options_table[fn] = optstr
+
+ def lsmagic(self):
+ """Return a list of currently available magic functions.
+
+ Gives a list of the bare names after mangling (['ls','cd', ...], not
+ ['magic_ls','magic_cd',...]"""
+
+ # FIXME. This needs a cleanup, in the way the magics list is built.
+
+ # magics in class definition
+ class_magic = lambda fn: fn.startswith('magic_') and \
+ callable(Magic.__dict__[fn])
+ # in instance namespace (run-time user additions)
+ inst_magic = lambda fn: fn.startswith('magic_') and \
+ callable(self.__dict__[fn])
+ # and bound magics by user (so they can access self):
+ inst_bound_magic = lambda fn: fn.startswith('magic_') and \
+ callable(self.__class__.__dict__[fn])
+ magics = filter(class_magic,Magic.__dict__.keys()) + \
+ filter(inst_magic,self.__dict__.keys()) + \
+ filter(inst_bound_magic,self.__class__.__dict__.keys())
+ out = []
+ for fn in set(magics):
+ out.append(fn.replace('magic_','',1))
+ out.sort()
+ return out
+
+ def extract_input_slices(self,slices,raw=False):
+ """Return as a string a set of input history slices.
+
+ Inputs:
+
+ - slices: the set of slices is given as a list of strings (like
+ ['1','4:8','9'], since this function is for use by magic functions
+ which get their arguments as strings.
+
+ Optional inputs:
+
+ - raw(False): by default, the processed input is used. If this is
+ true, the raw input history is used instead.
+
+ Note that slices can be called with two notations:
+
+ N:M -> standard python form, means including items N...(M-1).
+
+ N-M -> include items N..M (closed endpoint)."""
+
+ if raw:
+ hist = self.shell.input_hist_raw
+ else:
+ hist = self.shell.input_hist
+
+ cmds = []
+ for chunk in slices:
+ if ':' in chunk:
+ ini,fin = map(int,chunk.split(':'))
+ elif '-' in chunk:
+ ini,fin = map(int,chunk.split('-'))
+ fin += 1
+ else:
+ ini = int(chunk)
+ fin = ini+1
+ cmds.append(hist[ini:fin])
+ return cmds
+
+ def _ofind(self, oname, namespaces=None):
+ """Find an object in the available namespaces.
+
+ self._ofind(oname) -> dict with keys: found,obj,ospace,ismagic
+
+ Has special code to detect magic functions.
+ """
+
+ oname = oname.strip()
+
+ alias_ns = None
+ if namespaces is None:
+ # Namespaces to search in:
+ # Put them in a list. The order is important so that we
+ # find things in the same order that Python finds them.
+ namespaces = [ ('Interactive', self.shell.user_ns),
+ ('IPython internal', self.shell.internal_ns),
+ ('Python builtin', __builtin__.__dict__),
+ ('Alias', self.shell.alias_table),
+ ]
+ alias_ns = self.shell.alias_table
+
+ # initialize results to 'null'
+ found = 0; obj = None; ospace = None; ds = None;
+ ismagic = 0; isalias = 0; parent = None
+
+ # Look for the given name by splitting it in parts. If the head is
+ # found, then we look for all the remaining parts as members, and only
+ # declare success if we can find them all.
+ oname_parts = oname.split('.')
+ oname_head, oname_rest = oname_parts[0],oname_parts[1:]
+ for nsname,ns in namespaces:
+ try:
+ obj = ns[oname_head]
+ except KeyError:
+ continue
+ else:
+ #print 'oname_rest:', oname_rest # dbg
+ for part in oname_rest:
+ try:
+ parent = obj
+ obj = getattr(obj,part)
+ except:
+ # Blanket except b/c some badly implemented objects
+ # allow __getattr__ to raise exceptions other than
+ # AttributeError, which then crashes IPython.
+ break
+ else:
+ # If we finish the for loop (no break), we got all members
+ found = 1
+ ospace = nsname
+ if ns == alias_ns:
+ isalias = 1
+ break # namespace loop
+
+ # Try to see if it's magic
+ if not found:
+ if oname.startswith(self.shell.ESC_MAGIC):
+ oname = oname[1:]
+ obj = getattr(self,'magic_'+oname,None)
+ if obj is not None:
+ found = 1
+ ospace = 'IPython internal'
+ ismagic = 1
+
+ # Last try: special-case some literals like '', [], {}, etc:
+ if not found and oname_head in ["''",'""','[]','{}','()']:
+ obj = eval(oname_head)
+ found = 1
+ ospace = 'Interactive'
+
+ return {'found':found, 'obj':obj, 'namespace':ospace,
+ 'ismagic':ismagic, 'isalias':isalias, 'parent':parent}
+
+ def arg_err(self,func):
+ """Print docstring if incorrect arguments were passed"""
+ print 'Error in arguments:'
+ print OInspect.getdoc(func)
+
+ def format_latex(self,strng):
+ """Format a string for latex inclusion."""
+
+ # Characters that need to be escaped for latex:
+ escape_re = re.compile(r'(%|_|\$|#|&)',re.MULTILINE)
+ # Magic command names as headers:
+ cmd_name_re = re.compile(r'^(%s.*?):' % self.shell.ESC_MAGIC,
+ re.MULTILINE)
+ # Magic commands
+ cmd_re = re.compile(r'(?P<cmd>%s.+?\b)(?!\}\}:)' % self.shell.ESC_MAGIC,
+ re.MULTILINE)
+ # Paragraph continue
+ par_re = re.compile(r'\\$',re.MULTILINE)
+
+ # The "\n" symbol
+ newline_re = re.compile(r'\\n')
+
+ # Now build the string for output:
+ #strng = cmd_name_re.sub(r'\n\\texttt{\\textsl{\\large \1}}:',strng)
+ strng = cmd_name_re.sub(r'\n\\bigskip\n\\texttt{\\textbf{ \1}}:',
+ strng)
+ strng = cmd_re.sub(r'\\texttt{\g<cmd>}',strng)
+ strng = par_re.sub(r'\\\\',strng)
+ strng = escape_re.sub(r'\\\1',strng)
+ strng = newline_re.sub(r'\\textbackslash{}n',strng)
+ return strng
+
+ def format_screen(self,strng):
+ """Format a string for screen printing.
+
+ This removes some latex-type format codes."""
+ # Paragraph continue
+ par_re = re.compile(r'\\$',re.MULTILINE)
+ strng = par_re.sub('',strng)
+ return strng
+
+ def parse_options(self,arg_str,opt_str,*long_opts,**kw):
+ """Parse options passed to an argument string.
+
+ The interface is similar to that of getopt(), but it returns back a
+ Struct with the options as keys and the stripped argument string still
+ as a string.
+
+ arg_str is quoted as a true sys.argv vector by using shlex.split.
+ This allows us to easily expand variables, glob files, quote
+ arguments, etc.
+
+ Options:
+ -mode: default 'string'. If given as 'list', the argument string is
+ returned as a list (split on whitespace) instead of a string.
+
+ -list_all: put all option values in lists. Normally only options
+ appearing more than once are put in a list.
+
+ -posix (True): whether to split the input line in POSIX mode or not,
+ as per the conventions outlined in the shlex module from the
+ standard library."""
+
+ # inject default options at the beginning of the input line
+ caller = sys._getframe(1).f_code.co_name.replace('magic_','')
+ arg_str = '%s %s' % (self.options_table.get(caller,''),arg_str)
+
+ mode = kw.get('mode','string')
+ if mode not in ['string','list']:
+ raise ValueError,'incorrect mode given: %s' % mode
+ # Get options
+ list_all = kw.get('list_all',0)
+ posix = kw.get('posix',True)
+
+ # Check if we have more than one argument to warrant extra processing:
+ odict = {} # Dictionary with options
+ args = arg_str.split()
+ if len(args) >= 1:
+ # If the list of inputs only has 0 or 1 thing in it, there's no
+ # need to look for options
+ argv = arg_split(arg_str,posix)
+ # Do regular option processing
+ try:
+ opts,args = getopt(argv,opt_str,*long_opts)
+ except GetoptError,e:
+ raise UsageError('%s ( allowed: "%s" %s)' % (e.msg,opt_str,
+ " ".join(long_opts)))
+ for o,a in opts:
+ if o.startswith('--'):
+ o = o[2:]
+ else:
+ o = o[1:]
+ try:
+ odict[o].append(a)
+ except AttributeError:
+ odict[o] = [odict[o],a]
+ except KeyError:
+ if list_all:
+ odict[o] = [a]
+ else:
+ odict[o] = a
+
+ # Prepare opts,args for return
+ opts = Struct(odict)
+ if mode == 'string':
+ args = ' '.join(args)
+
+ return opts,args
+
+ #......................................................................
+ # And now the actual magic functions
+
+ # Functions for IPython shell work (vars,funcs, config, etc)
+ def magic_lsmagic(self, parameter_s = ''):
+ """List currently available magic functions."""
+ mesc = self.shell.ESC_MAGIC
+ print 'Available magic functions:\n'+mesc+\
+ (' '+mesc).join(self.lsmagic())
+ print '\n' + Magic.auto_status[self.shell.rc.automagic]
+ return None
+
+ def magic_magic(self, parameter_s = ''):
+ """Print information about the magic function system.
+
+ Supported formats: -latex, -brief, -rest
+ """
+
+ mode = ''
+ try:
+ if parameter_s.split()[0] == '-latex':
+ mode = 'latex'
+ if parameter_s.split()[0] == '-brief':
+ mode = 'brief'
+ if parameter_s.split()[0] == '-rest':
+ mode = 'rest'
+ rest_docs = []
+ except:
+ pass
+
+ magic_docs = []
+ for fname in self.lsmagic():
+ mname = 'magic_' + fname
+ for space in (Magic,self,self.__class__):
+ try:
+ fn = space.__dict__[mname]
+ except KeyError:
+ pass
+ else:
+ break
+ if mode == 'brief':
+ # only first line
+ if fn.__doc__:
+ fndoc = fn.__doc__.split('\n',1)[0]
+ else:
+ fndoc = 'No documentation'
+ else:
+ if fn.__doc__:
+ fndoc = fn.__doc__.rstrip()
+ else:
+ fndoc = 'No documentation'
+
+
+ if mode == 'rest':
+ rest_docs.append('**%s%s**::\n\n\t%s\n\n' %(self.shell.ESC_MAGIC,
+ fname,fndoc))
+
+ else:
+ magic_docs.append('%s%s:\n\t%s\n' %(self.shell.ESC_MAGIC,
+ fname,fndoc))
+
+ magic_docs = ''.join(magic_docs)
+
+ if mode == 'rest':
+ return "".join(rest_docs)
+
+ if mode == 'latex':
+ print self.format_latex(magic_docs)
+ return
+ else:
+ magic_docs = self.format_screen(magic_docs)
+ if mode == 'brief':
+ return magic_docs
+
+ outmsg = """
+IPython's 'magic' functions
+===========================
+
+The magic function system provides a series of functions which allow you to
+control the behavior of IPython itself, plus a lot of system-type
+features. All these functions are prefixed with a % character, but parameters
+are given without parentheses or quotes.
+
+NOTE: If you have 'automagic' enabled (via the command line option or with the
+%automagic function), you don't need to type in the % explicitly. By default,
+IPython ships with automagic on, so you should only rarely need the % escape.
+
+Example: typing '%cd mydir' (without the quotes) changes you working directory
+to 'mydir', if it exists.
+
+You can define your own magic functions to extend the system. See the supplied
+ipythonrc and example-magic.py files for details (in your ipython
+configuration directory, typically $HOME/.ipython/).
+
+You can also define your own aliased names for magic functions. In your
+ipythonrc file, placing a line like:
+
+ execute __IPYTHON__.magic_pf = __IPYTHON__.magic_profile
+
+will define %pf as a new name for %profile.
+
+You can also call magics in code using the ipmagic() function, which IPython
+automatically adds to the builtin namespace. Type 'ipmagic?' for details.
+
+For a list of the available magic functions, use %lsmagic. For a description
+of any of them, type %magic_name?, e.g. '%cd?'.
+
+Currently the magic system has the following functions:\n"""
+
+ mesc = self.shell.ESC_MAGIC
+ outmsg = ("%s\n%s\n\nSummary of magic functions (from %slsmagic):"
+ "\n\n%s%s\n\n%s" % (outmsg,
+ magic_docs,mesc,mesc,
+ (' '+mesc).join(self.lsmagic()),
+ Magic.auto_status[self.shell.rc.automagic] ) )
+
+ page(outmsg,screen_lines=self.shell.rc.screen_length)
+
+
+ def magic_autoindent(self, parameter_s = ''):
+ """Toggle autoindent on/off (if available)."""
+
+ self.shell.set_autoindent()
+ print "Automatic indentation is:",['OFF','ON'][self.shell.autoindent]
+
+
+ def magic_automagic(self, parameter_s = ''):
+ """Make magic functions callable without having to type the initial %.
+
+ Without argumentsl toggles on/off (when off, you must call it as
+ %automagic, of course). With arguments it sets the value, and you can
+ use any of (case insensitive):
+
+ - on,1,True: to activate
+
+ - off,0,False: to deactivate.
+
+ Note that magic functions have lowest priority, so if there's a
+ variable whose name collides with that of a magic fn, automagic won't
+ work for that function (you get the variable instead). However, if you
+ delete the variable (del var), the previously shadowed magic function
+ becomes visible to automagic again."""
+
+ rc = self.shell.rc
+ arg = parameter_s.lower()
+ if parameter_s in ('on','1','true'):
+ rc.automagic = True
+ elif parameter_s in ('off','0','false'):
+ rc.automagic = False
+ else:
+ rc.automagic = not rc.automagic
+ print '\n' + Magic.auto_status[rc.automagic]
+
+ @testdec.skip_doctest
+ def magic_autocall(self, parameter_s = ''):
+ """Make functions callable without having to type parentheses.
+
+ Usage:
+
+ %autocall [mode]
+
+ The mode can be one of: 0->Off, 1->Smart, 2->Full. If not given, the
+ value is toggled on and off (remembering the previous state).
+
+ In more detail, these values mean:
+
+ 0 -> fully disabled
+
+ 1 -> active, but do not apply if there are no arguments on the line.
+
+ In this mode, you get:
+
+ In [1]: callable
+ Out[1]: <built-in function callable>
+
+ In [2]: callable 'hello'
+ ------> callable('hello')
+ Out[2]: False
+
+ 2 -> Active always. Even if no arguments are present, the callable
+ object is called:
+
+ In [2]: float
+ ------> float()
+ Out[2]: 0.0
+
+ Note that even with autocall off, you can still use '/' at the start of
+ a line to treat the first argument on the command line as a function
+ and add parentheses to it:
+
+ In [8]: /str 43
+ ------> str(43)
+ Out[8]: '43'
+
+ # all-random (note for auto-testing)
+ """
+
+ rc = self.shell.rc
+
+ if parameter_s:
+ arg = int(parameter_s)
+ else:
+ arg = 'toggle'
+
+ if not arg in (0,1,2,'toggle'):
+ error('Valid modes: (0->Off, 1->Smart, 2->Full')
+ return
+
+ if arg in (0,1,2):
+ rc.autocall = arg
+ else: # toggle
+ if rc.autocall:
+ self._magic_state.autocall_save = rc.autocall
+ rc.autocall = 0
+ else:
+ try:
+ rc.autocall = self._magic_state.autocall_save
+ except AttributeError:
+ rc.autocall = self._magic_state.autocall_save = 1
+
+ print "Automatic calling is:",['OFF','Smart','Full'][rc.autocall]
+
+ def magic_system_verbose(self, parameter_s = ''):
+ """Set verbose printing of system calls.
+
+ If called without an argument, act as a toggle"""
+
+ if parameter_s:
+ val = bool(eval(parameter_s))
+ else:
+ val = None
+
+ self.shell.rc_set_toggle('system_verbose',val)
+ print "System verbose printing is:",\
+ ['OFF','ON'][self.shell.rc.system_verbose]
+
+
+ def magic_page(self, parameter_s=''):
+ """Pretty print the object and display it through a pager.
+
+ %page [options] OBJECT
+
+ If no object is given, use _ (last output).
+
+ Options:
+
+ -r: page str(object), don't pretty-print it."""
+
+ # After a function contributed by Olivier Aubert, slightly modified.
+
+ # Process options/args
+ opts,args = self.parse_options(parameter_s,'r')
+ raw = 'r' in opts
+
+ oname = args and args or '_'
+ info = self._ofind(oname)
+ if info['found']:
+ txt = (raw and str or pformat)( info['obj'] )
+ page(txt)
+ else:
+ print 'Object `%s` not found' % oname
+
+ def magic_profile(self, parameter_s=''):
+ """Print your currently active IPyhton profile."""
+ if self.shell.rc.profile:
+ printpl('Current IPython profile: $self.shell.rc.profile.')
+ else:
+ print 'No profile active.'
+
+ def magic_pinfo(self, parameter_s='', namespaces=None):
+ """Provide detailed information about an object.
+
+ '%pinfo object' is just a synonym for object? or ?object."""
+
+ #print 'pinfo par: <%s>' % parameter_s # dbg
+
+
+ # detail_level: 0 -> obj? , 1 -> obj??
+ detail_level = 0
+ # We need to detect if we got called as 'pinfo pinfo foo', which can
+ # happen if the user types 'pinfo foo?' at the cmd line.
+ pinfo,qmark1,oname,qmark2 = \
+ re.match('(pinfo )?(\?*)(.*?)(\??$)',parameter_s).groups()
+ if pinfo or qmark1 or qmark2:
+ detail_level = 1
+ if "*" in oname:
+ self.magic_psearch(oname)
+ else:
+ self._inspect('pinfo', oname, detail_level=detail_level,
+ namespaces=namespaces)
+
+ def magic_pdef(self, parameter_s='', namespaces=None):
+ """Print the definition header for any callable object.
+
+ If the object is a class, print the constructor information."""
+ self._inspect('pdef',parameter_s, namespaces)
+
+ def magic_pdoc(self, parameter_s='', namespaces=None):
+ """Print the docstring for an object.
+
+ If the given object is a class, it will print both the class and the
+ constructor docstrings."""
+ self._inspect('pdoc',parameter_s, namespaces)
+
+ def magic_psource(self, parameter_s='', namespaces=None):
+ """Print (or run through pager) the source code for an object."""
+ self._inspect('psource',parameter_s, namespaces)
+
+ def magic_pfile(self, parameter_s=''):
+ """Print (or run through pager) the file where an object is defined.
+
+ The file opens at the line where the object definition begins. IPython
+ will honor the environment variable PAGER if set, and otherwise will
+ do its best to print the file in a convenient form.
+
+ If the given argument is not an object currently defined, IPython will
+ try to interpret it as a filename (automatically adding a .py extension
+ if needed). You can thus use %pfile as a syntax highlighting code
+ viewer."""
+
+ # first interpret argument as an object name
+ out = self._inspect('pfile',parameter_s)
+ # if not, try the input as a filename
+ if out == 'not found':
+ try:
+ filename = get_py_filename(parameter_s)
+ except IOError,msg:
+ print msg
+ return
+ page(self.shell.inspector.format(file(filename).read()))
+
+ def _inspect(self,meth,oname,namespaces=None,**kw):
+ """Generic interface to the inspector system.
+
+ This function is meant to be called by pdef, pdoc & friends."""
+
+ #oname = oname.strip()
+ #print '1- oname: <%r>' % oname # dbg
+ try:
+ oname = oname.strip().encode('ascii')
+ #print '2- oname: <%r>' % oname # dbg
+ except UnicodeEncodeError:
+ print 'Python identifiers can only contain ascii characters.'
+ return 'not found'
+
+ info = Struct(self._ofind(oname, namespaces))
+
+ if info.found:
+ try:
+ IPython.generics.inspect_object(info.obj)
+ return
+ except IPython.ipapi.TryNext:
+ pass
+ # Get the docstring of the class property if it exists.
+ path = oname.split('.')
+ root = '.'.join(path[:-1])
+ if info.parent is not None:
+ try:
+ target = getattr(info.parent, '__class__')
+ # The object belongs to a class instance.
+ try:
+ target = getattr(target, path[-1])
+ # The class defines the object.
+ if isinstance(target, property):
+ oname = root + '.__class__.' + path[-1]
+ info = Struct(self._ofind(oname))
+ except AttributeError: pass
+ except AttributeError: pass
+
+ pmethod = getattr(self.shell.inspector,meth)
+ formatter = info.ismagic and self.format_screen or None
+ if meth == 'pdoc':
+ pmethod(info.obj,oname,formatter)
+ elif meth == 'pinfo':
+ pmethod(info.obj,oname,formatter,info,**kw)
+ else:
+ pmethod(info.obj,oname)
+ else:
+ print 'Object `%s` not found.' % oname
+ return 'not found' # so callers can take other action
+
+ def magic_psearch(self, parameter_s=''):
+ """Search for object in namespaces by wildcard.
+
+ %psearch [options] PATTERN [OBJECT TYPE]
+
+ Note: ? can be used as a synonym for %psearch, at the beginning or at
+ the end: both a*? and ?a* are equivalent to '%psearch a*'. Still, the
+ rest of the command line must be unchanged (options come first), so
+ for example the following forms are equivalent
+
+ %psearch -i a* function
+ -i a* function?
+ ?-i a* function
+
+ Arguments:
+
+ PATTERN
+
+ where PATTERN is a string containing * as a wildcard similar to its
+ use in a shell. The pattern is matched in all namespaces on the
+ search path. By default objects starting with a single _ are not
+ matched, many IPython generated objects have a single
+ underscore. The default is case insensitive matching. Matching is
+ also done on the attributes of objects and not only on the objects
+ in a module.
+
+ [OBJECT TYPE]
+
+ Is the name of a python type from the types module. The name is
+ given in lowercase without the ending type, ex. StringType is
+ written string. By adding a type here only objects matching the
+ given type are matched. Using all here makes the pattern match all
+ types (this is the default).
+
+ Options:
+
+ -a: makes the pattern match even objects whose names start with a
+ single underscore. These names are normally ommitted from the
+ search.
+
+ -i/-c: make the pattern case insensitive/sensitive. If neither of
+ these options is given, the default is read from your ipythonrc
+ file. The option name which sets this value is
+ 'wildcards_case_sensitive'. If this option is not specified in your
+ ipythonrc file, IPython's internal default is to do a case sensitive
+ search.
+
+ -e/-s NAMESPACE: exclude/search a given namespace. The pattern you
+ specifiy can be searched in any of the following namespaces:
+ 'builtin', 'user', 'user_global','internal', 'alias', where
+ 'builtin' and 'user' are the search defaults. Note that you should
+ not use quotes when specifying namespaces.
+
+ 'Builtin' contains the python module builtin, 'user' contains all
+ user data, 'alias' only contain the shell aliases and no python
+ objects, 'internal' contains objects used by IPython. The
+ 'user_global' namespace is only used by embedded IPython instances,
+ and it contains module-level globals. You can add namespaces to the
+ search with -s or exclude them with -e (these options can be given
+ more than once).
+
+ Examples:
+
+ %psearch a* -> objects beginning with an a
+ %psearch -e builtin a* -> objects NOT in the builtin space starting in a
+ %psearch a* function -> all functions beginning with an a
+ %psearch re.e* -> objects beginning with an e in module re
+ %psearch r*.e* -> objects that start with e in modules starting in r
+ %psearch r*.* string -> all strings in modules beginning with r
+
+ Case sensitve search:
+
+ %psearch -c a* list all object beginning with lower case a
+
+ Show objects beginning with a single _:
+
+ %psearch -a _* list objects beginning with a single underscore"""
+ try:
+ parameter_s = parameter_s.encode('ascii')
+ except UnicodeEncodeError:
+ print 'Python identifiers can only contain ascii characters.'
+ return
+
+ # default namespaces to be searched
+ def_search = ['user','builtin']
+
+ # Process options/args
+ opts,args = self.parse_options(parameter_s,'cias:e:',list_all=True)
+ opt = opts.get
+ shell = self.shell
+ psearch = shell.inspector.psearch
+
+ # select case options
+ if opts.has_key('i'):
+ ignore_case = True
+ elif opts.has_key('c'):
+ ignore_case = False
+ else:
+ ignore_case = not shell.rc.wildcards_case_sensitive
+
+ # Build list of namespaces to search from user options
+ def_search.extend(opt('s',[]))
+ ns_exclude = ns_exclude=opt('e',[])
+ ns_search = [nm for nm in def_search if nm not in ns_exclude]
+
+ # Call the actual search
+ try:
+ psearch(args,shell.ns_table,ns_search,
+ show_all=opt('a'),ignore_case=ignore_case)
+ except:
+ shell.showtraceback()
+
+ def magic_who_ls(self, parameter_s=''):
+ """Return a sorted list of all interactive variables.
+
+ If arguments are given, only variables of types matching these
+ arguments are returned."""
+
+ user_ns = self.shell.user_ns
+ internal_ns = self.shell.internal_ns
+ user_config_ns = self.shell.user_config_ns
+ out = []
+ typelist = parameter_s.split()
+
+ for i in user_ns:
+ if not (i.startswith('_') or i.startswith('_i')) \
+ and not (i in internal_ns or i in user_config_ns):
+ if typelist:
+ if type(user_ns[i]).__name__ in typelist:
+ out.append(i)
+ else:
+ out.append(i)
+ out.sort()
+ return out
+
+ def magic_who(self, parameter_s=''):
+ """Print all interactive variables, with some minimal formatting.
+
+ If any arguments are given, only variables whose type matches one of
+ these are printed. For example:
+
+ %who function str
+
+ will only list functions and strings, excluding all other types of
+ variables. To find the proper type names, simply use type(var) at a
+ command line to see how python prints type names. For example:
+
+ In [1]: type('hello')\\
+ Out[1]: <type 'str'>
+
+ indicates that the type name for strings is 'str'.
+
+ %who always excludes executed names loaded through your configuration
+ file and things which are internal to IPython.
+
+ This is deliberate, as typically you may load many modules and the
+ purpose of %who is to show you only what you've manually defined."""
+
+ varlist = self.magic_who_ls(parameter_s)
+ if not varlist:
+ if parameter_s:
+ print 'No variables match your requested type.'
+ else:
+ print 'Interactive namespace is empty.'
+ return
+
+ # if we have variables, move on...
+ count = 0
+ for i in varlist:
+ print i+'\t',
+ count += 1
+ if count > 8:
+ count = 0
+ print
+ print
+
+ def magic_whos(self, parameter_s=''):
+ """Like %who, but gives some extra information about each variable.
+
+ The same type filtering of %who can be applied here.
+
+ For all variables, the type is printed. Additionally it prints:
+
+ - For {},[],(): their length.
+
+ - For numpy and Numeric arrays, a summary with shape, number of
+ elements, typecode and size in memory.
+
+ - Everything else: a string representation, snipping their middle if
+ too long."""
+
+ varnames = self.magic_who_ls(parameter_s)
+ if not varnames:
+ if parameter_s:
+ print 'No variables match your requested type.'
+ else:
+ print 'Interactive namespace is empty.'
+ return
+
+ # if we have variables, move on...
+
+ # for these types, show len() instead of data:
+ seq_types = [types.DictType,types.ListType,types.TupleType]
+
+ # for numpy/Numeric arrays, display summary info
+ try:
+ import numpy
+ except ImportError:
+ ndarray_type = None
+ else:
+ ndarray_type = numpy.ndarray.__name__
+ try:
+ import Numeric
+ except ImportError:
+ array_type = None
+ else:
+ array_type = Numeric.ArrayType.__name__
+
+ # Find all variable names and types so we can figure out column sizes
+ def get_vars(i):
+ return self.shell.user_ns[i]
+
+ # some types are well known and can be shorter
+ abbrevs = {'IPython.macro.Macro' : 'Macro'}
+ def type_name(v):
+ tn = type(v).__name__
+ return abbrevs.get(tn,tn)
+
+ varlist = map(get_vars,varnames)
+
+ typelist = []
+ for vv in varlist:
+ tt = type_name(vv)
+
+ if tt=='instance':
+ typelist.append( abbrevs.get(str(vv.__class__),
+ str(vv.__class__)))
+ else:
+ typelist.append(tt)
+
+ # column labels and # of spaces as separator
+ varlabel = 'Variable'
+ typelabel = 'Type'
+ datalabel = 'Data/Info'
+ colsep = 3
+ # variable format strings
+ vformat = "$vname.ljust(varwidth)$vtype.ljust(typewidth)"
+ vfmt_short = '$vstr[:25]<...>$vstr[-25:]'
+ aformat = "%s: %s elems, type `%s`, %s bytes"
+ # find the size of the columns to format the output nicely
+ varwidth = max(max(map(len,varnames)), len(varlabel)) + colsep
+ typewidth = max(max(map(len,typelist)), len(typelabel)) + colsep
+ # table header
+ print varlabel.ljust(varwidth) + typelabel.ljust(typewidth) + \
+ ' '+datalabel+'\n' + '-'*(varwidth+typewidth+len(datalabel)+1)
+ # and the table itself
+ kb = 1024
+ Mb = 1048576 # kb**2
+ for vname,var,vtype in zip(varnames,varlist,typelist):
+ print itpl(vformat),
+ if vtype in seq_types:
+ print len(var)
+ elif vtype in [array_type,ndarray_type]:
+ vshape = str(var.shape).replace(',','').replace(' ','x')[1:-1]
+ if vtype==ndarray_type:
+ # numpy
+ vsize = var.size
+ vbytes = vsize*var.itemsize
+ vdtype = var.dtype
+ else:
+ # Numeric
+ vsize = Numeric.size(var)
+ vbytes = vsize*var.itemsize()
+ vdtype = var.typecode()
+
+ if vbytes < 100000:
+ print aformat % (vshape,vsize,vdtype,vbytes)
+ else:
+ print aformat % (vshape,vsize,vdtype,vbytes),
+ if vbytes < Mb:
+ print '(%s kb)' % (vbytes/kb,)
+ else:
+ print '(%s Mb)' % (vbytes/Mb,)
+ else:
+ try:
+ vstr = str(var)
+ except UnicodeEncodeError:
+ vstr = unicode(var).encode(sys.getdefaultencoding(),
+ 'backslashreplace')
+ vstr = vstr.replace('\n','\\n')
+ if len(vstr) < 50:
+ print vstr
+ else:
+ printpl(vfmt_short)
+
+ def magic_reset(self, parameter_s=''):
+ """Resets the namespace by removing all names defined by the user.
+
+ Input/Output history are left around in case you need them.
+
+ Parameters
+ ----------
+ -y : force reset without asking for confirmation.
+
+ Examples
+ --------
+ In [6]: a = 1
+
+ In [7]: a
+ Out[7]: 1
+
+ In [8]: 'a' in _ip.user_ns
+ Out[8]: True
+
+ In [9]: %reset -f
+
+ In [10]: 'a' in _ip.user_ns
+ Out[10]: False
+ """
+
+ if parameter_s == '-f':
+ ans = True
+ else:
+ ans = self.shell.ask_yes_no(
+ "Once deleted, variables cannot be recovered. Proceed (y/[n])? ")
+ if not ans:
+ print 'Nothing done.'
+ return
+ user_ns = self.shell.user_ns
+ for i in self.magic_who_ls():
+ del(user_ns[i])
+
+ # Also flush the private list of module references kept for script
+ # execution protection
+ self.shell.clear_main_mod_cache()
+
+ def magic_logstart(self,parameter_s=''):
+ """Start logging anywhere in a session.
+
+ %logstart [-o|-r|-t] [log_name [log_mode]]
+
+ If no name is given, it defaults to a file named 'ipython_log.py' in your
+ current directory, in 'rotate' mode (see below).
+
+ '%logstart name' saves to file 'name' in 'backup' mode. It saves your
+ history up to that point and then continues logging.
+
+ %logstart takes a second optional parameter: logging mode. This can be one
+ of (note that the modes are given unquoted):\\
+ append: well, that says it.\\
+ backup: rename (if exists) to name~ and start name.\\
+ global: single logfile in your home dir, appended to.\\
+ over : overwrite existing log.\\
+ rotate: create rotating logs name.1~, name.2~, etc.
+
+ Options:
+
+ -o: log also IPython's output. In this mode, all commands which
+ generate an Out[NN] prompt are recorded to the logfile, right after
+ their corresponding input line. The output lines are always
+ prepended with a '#[Out]# ' marker, so that the log remains valid
+ Python code.
+
+ Since this marker is always the same, filtering only the output from
+ a log is very easy, using for example a simple awk call:
+
+ awk -F'#\\[Out\\]# ' '{if($2) {print $2}}' ipython_log.py
+
+ -r: log 'raw' input. Normally, IPython's logs contain the processed
+ input, so that user lines are logged in their final form, converted
+ into valid Python. For example, %Exit is logged as
+ '_ip.magic("Exit"). If the -r flag is given, all input is logged
+ exactly as typed, with no transformations applied.
+
+ -t: put timestamps before each input line logged (these are put in
+ comments)."""
+
+ opts,par = self.parse_options(parameter_s,'ort')
+ log_output = 'o' in opts
+ log_raw_input = 'r' in opts
+ timestamp = 't' in opts
+
+ rc = self.shell.rc
+ logger = self.shell.logger
+
+ # if no args are given, the defaults set in the logger constructor by
+ # ipytohn remain valid
+ if par:
+ try:
+ logfname,logmode = par.split()
+ except:
+ logfname = par
+ logmode = 'backup'
+ else:
+ logfname = logger.logfname
+ logmode = logger.logmode
+ # put logfname into rc struct as if it had been called on the command
+ # line, so it ends up saved in the log header Save it in case we need
+ # to restore it...
+ old_logfile = rc.opts.get('logfile','')
+ if logfname:
+ logfname = os.path.expanduser(logfname)
+ rc.opts.logfile = logfname
+ loghead = self.shell.loghead_tpl % (rc.opts,rc.args)
+ try:
+ started = logger.logstart(logfname,loghead,logmode,
+ log_output,timestamp,log_raw_input)
+ except:
+ rc.opts.logfile = old_logfile
+ warn("Couldn't start log: %s" % sys.exc_info()[1])
+ else:
+ # log input history up to this point, optionally interleaving
+ # output if requested
+
+ if timestamp:
+ # disable timestamping for the previous history, since we've
+ # lost those already (no time machine here).
+ logger.timestamp = False
+
+ if log_raw_input:
+ input_hist = self.shell.input_hist_raw
+ else:
+ input_hist = self.shell.input_hist
+
+ if log_output:
+ log_write = logger.log_write
+ output_hist = self.shell.output_hist
+ for n in range(1,len(input_hist)-1):
+ log_write(input_hist[n].rstrip())
+ if n in output_hist:
+ log_write(repr(output_hist[n]),'output')
+ else:
+ logger.log_write(input_hist[1:])
+ if timestamp:
+ # re-enable timestamping
+ logger.timestamp = True
+
+ print ('Activating auto-logging. '
+ 'Current session state plus future input saved.')
+ logger.logstate()
+
+ def magic_logstop(self,parameter_s=''):
+ """Fully stop logging and close log file.
+
+ In order to start logging again, a new %logstart call needs to be made,
+ possibly (though not necessarily) with a new filename, mode and other
+ options."""
+ self.logger.logstop()
+
+ def magic_logoff(self,parameter_s=''):
+ """Temporarily stop logging.
+
+ You must have previously started logging."""
+ self.shell.logger.switch_log(0)
+
+ def magic_logon(self,parameter_s=''):
+ """Restart logging.
+
+ This function is for restarting logging which you've temporarily
+ stopped with %logoff. For starting logging for the first time, you
+ must use the %logstart function, which allows you to specify an
+ optional log filename."""
+
+ self.shell.logger.switch_log(1)
+
+ def magic_logstate(self,parameter_s=''):
+ """Print the status of the logging system."""
+
+ self.shell.logger.logstate()
+
+ def magic_pdb(self, parameter_s=''):
+ """Control the automatic calling of the pdb interactive debugger.
+
+ Call as '%pdb on', '%pdb 1', '%pdb off' or '%pdb 0'. If called without
+ argument it works as a toggle.
+
+ When an exception is triggered, IPython can optionally call the
+ interactive pdb debugger after the traceback printout. %pdb toggles
+ this feature on and off.
+
+ The initial state of this feature is set in your ipythonrc
+ configuration file (the variable is called 'pdb').
+
+ If you want to just activate the debugger AFTER an exception has fired,
+ without having to type '%pdb on' and rerunning your code, you can use
+ the %debug magic."""
+
+ par = parameter_s.strip().lower()
+
+ if par:
+ try:
+ new_pdb = {'off':0,'0':0,'on':1,'1':1}[par]
+ except KeyError:
+ print ('Incorrect argument. Use on/1, off/0, '
+ 'or nothing for a toggle.')
+ return
+ else:
+ # toggle
+ new_pdb = not self.shell.call_pdb
+
+ # set on the shell
+ self.shell.call_pdb = new_pdb
+ print 'Automatic pdb calling has been turned',on_off(new_pdb)
+
+ def magic_debug(self, parameter_s=''):
+ """Activate the interactive debugger in post-mortem mode.
+
+ If an exception has just occurred, this lets you inspect its stack
+ frames interactively. Note that this will always work only on the last
+ traceback that occurred, so you must call this quickly after an
+ exception that you wish to inspect has fired, because if another one
+ occurs, it clobbers the previous one.
+
+ If you want IPython to automatically do this on every exception, see
+ the %pdb magic for more details.
+ """
+
+ self.shell.debugger(force=True)
+
+ @testdec.skip_doctest
+ def magic_prun(self, parameter_s ='',user_mode=1,
+ opts=None,arg_lst=None,prog_ns=None):
+
+ """Run a statement through the python code profiler.
+
+ Usage:
+ %prun [options] statement
+
+ The given statement (which doesn't require quote marks) is run via the
+ python profiler in a manner similar to the profile.run() function.
+ Namespaces are internally managed to work correctly; profile.run
+ cannot be used in IPython because it makes certain assumptions about
+ namespaces which do not hold under IPython.
+
+ Options:
+
+ -l <limit>: you can place restrictions on what or how much of the
+ profile gets printed. The limit value can be:
+
+ * A string: only information for function names containing this string
+ is printed.
+
+ * An integer: only these many lines are printed.
+
+ * A float (between 0 and 1): this fraction of the report is printed
+ (for example, use a limit of 0.4 to see the topmost 40% only).
+
+ You can combine several limits with repeated use of the option. For
+ example, '-l __init__ -l 5' will print only the topmost 5 lines of
+ information about class constructors.
+
+ -r: return the pstats.Stats object generated by the profiling. This
+ object has all the information about the profile in it, and you can
+ later use it for further analysis or in other functions.
+
+ -s <key>: sort profile by given key. You can provide more than one key
+ by using the option several times: '-s key1 -s key2 -s key3...'. The
+ default sorting key is 'time'.
+
+ The following is copied verbatim from the profile documentation
+ referenced below:
+
+ When more than one key is provided, additional keys are used as
+ secondary criteria when the there is equality in all keys selected
+ before them.
+
+ Abbreviations can be used for any key names, as long as the
+ abbreviation is unambiguous. The following are the keys currently
+ defined:
+
+ Valid Arg Meaning
+ "calls" call count
+ "cumulative" cumulative time
+ "file" file name
+ "module" file name
+ "pcalls" primitive call count
+ "line" line number
+ "name" function name
+ "nfl" name/file/line
+ "stdname" standard name
+ "time" internal time
+
+ Note that all sorts on statistics are in descending order (placing
+ most time consuming items first), where as name, file, and line number
+ searches are in ascending order (i.e., alphabetical). The subtle
+ distinction between "nfl" and "stdname" is that the standard name is a
+ sort of the name as printed, which means that the embedded line
+ numbers get compared in an odd way. For example, lines 3, 20, and 40
+ would (if the file names were the same) appear in the string order
+ "20" "3" and "40". In contrast, "nfl" does a numeric compare of the
+ line numbers. In fact, sort_stats("nfl") is the same as
+ sort_stats("name", "file", "line").
+
+ -T <filename>: save profile results as shown on screen to a text
+ file. The profile is still shown on screen.
+
+ -D <filename>: save (via dump_stats) profile statistics to given
+ filename. This data is in a format understod by the pstats module, and
+ is generated by a call to the dump_stats() method of profile
+ objects. The profile is still shown on screen.
+
+ If you want to run complete programs under the profiler's control, use
+ '%run -p [prof_opts] filename.py [args to program]' where prof_opts
+ contains profiler specific options as described here.
+
+ You can read the complete documentation for the profile module with::
+
+ In [1]: import profile; profile.help()
+ """
+
+ opts_def = Struct(D=[''],l=[],s=['time'],T=[''])
+ # protect user quote marks
+ parameter_s = parameter_s.replace('"',r'\"').replace("'",r"\'")
+
+ if user_mode: # regular user call
+ opts,arg_str = self.parse_options(parameter_s,'D:l:rs:T:',
+ list_all=1)
+ namespace = self.shell.user_ns
+ else: # called to run a program by %run -p
+ try:
+ filename = get_py_filename(arg_lst[0])
+ except IOError,msg:
+ error(msg)
+ return
+
+ arg_str = 'execfile(filename,prog_ns)'
+ namespace = locals()
+
+ opts.merge(opts_def)
+
+ prof = profile.Profile()
+ try:
+ prof = prof.runctx(arg_str,namespace,namespace)
+ sys_exit = ''
+ except SystemExit:
+ sys_exit = """*** SystemExit exception caught in code being profiled."""
+
+ stats = pstats.Stats(prof).strip_dirs().sort_stats(*opts.s)
+
+ lims = opts.l
+ if lims:
+ lims = [] # rebuild lims with ints/floats/strings
+ for lim in opts.l:
+ try:
+ lims.append(int(lim))
+ except ValueError:
+ try:
+ lims.append(float(lim))
+ except ValueError:
+ lims.append(lim)
+
+ # Trap output.
+ stdout_trap = StringIO()
+
+ if hasattr(stats,'stream'):
+ # In newer versions of python, the stats object has a 'stream'
+ # attribute to write into.
+ stats.stream = stdout_trap
+ stats.print_stats(*lims)
+ else:
+ # For older versions, we manually redirect stdout during printing
+ sys_stdout = sys.stdout
+ try:
+ sys.stdout = stdout_trap
+ stats.print_stats(*lims)
+ finally:
+ sys.stdout = sys_stdout
+
+ output = stdout_trap.getvalue()
+ output = output.rstrip()
+
+ page(output,screen_lines=self.shell.rc.screen_length)
+ print sys_exit,
+
+ dump_file = opts.D[0]
+ text_file = opts.T[0]
+ if dump_file:
+ prof.dump_stats(dump_file)
+ print '\n*** Profile stats marshalled to file',\
+ `dump_file`+'.',sys_exit
+ if text_file:
+ pfile = file(text_file,'w')
+ pfile.write(output)
+ pfile.close()
+ print '\n*** Profile printout saved to text file',\
+ `text_file`+'.',sys_exit
+
+ if opts.has_key('r'):
+ return stats
+ else:
+ return None
+
+ @testdec.skip_doctest
+ def magic_run(self, parameter_s ='',runner=None,
+ file_finder=get_py_filename):
+ """Run the named file inside IPython as a program.
+
+ Usage:\\
+ %run [-n -i -t [-N<N>] -d [-b<N>] -p [profile options]] file [args]
+
+ Parameters after the filename are passed as command-line arguments to
+ the program (put in sys.argv). Then, control returns to IPython's
+ prompt.
+
+ This is similar to running at a system prompt:\\
+ $ python file args\\
+ but with the advantage of giving you IPython's tracebacks, and of
+ loading all variables into your interactive namespace for further use
+ (unless -p is used, see below).
+
+ The file is executed in a namespace initially consisting only of
+ __name__=='__main__' and sys.argv constructed as indicated. It thus
+ sees its environment as if it were being run as a stand-alone program
+ (except for sharing global objects such as previously imported
+ modules). But after execution, the IPython interactive namespace gets
+ updated with all variables defined in the program (except for __name__
+ and sys.argv). This allows for very convenient loading of code for
+ interactive work, while giving each program a 'clean sheet' to run in.
+
+ Options:
+
+ -n: __name__ is NOT set to '__main__', but to the running file's name
+ without extension (as python does under import). This allows running
+ scripts and reloading the definitions in them without calling code
+ protected by an ' if __name__ == "__main__" ' clause.
+
+ -i: run the file in IPython's namespace instead of an empty one. This
+ is useful if you are experimenting with code written in a text editor
+ which depends on variables defined interactively.
+
+ -e: ignore sys.exit() calls or SystemExit exceptions in the script
+ being run. This is particularly useful if IPython is being used to
+ run unittests, which always exit with a sys.exit() call. In such
+ cases you are interested in the output of the test results, not in
+ seeing a traceback of the unittest module.
+
+ -t: print timing information at the end of the run. IPython will give
+ you an estimated CPU time consumption for your script, which under
+ Unix uses the resource module to avoid the wraparound problems of
+ time.clock(). Under Unix, an estimate of time spent on system tasks
+ is also given (for Windows platforms this is reported as 0.0).
+
+ If -t is given, an additional -N<N> option can be given, where <N>
+ must be an integer indicating how many times you want the script to
+ run. The final timing report will include total and per run results.
+
+ For example (testing the script uniq_stable.py):
+
+ In [1]: run -t uniq_stable
+
+ IPython CPU timings (estimated):\\
+ User : 0.19597 s.\\
+ System: 0.0 s.\\
+
+ In [2]: run -t -N5 uniq_stable
+
+ IPython CPU timings (estimated):\\
+ Total runs performed: 5\\
+ Times : Total Per run\\
+ User : 0.910862 s, 0.1821724 s.\\
+ System: 0.0 s, 0.0 s.
+
+ -d: run your program under the control of pdb, the Python debugger.
+ This allows you to execute your program step by step, watch variables,
+ etc. Internally, what IPython does is similar to calling:
+
+ pdb.run('execfile("YOURFILENAME")')
+
+ with a breakpoint set on line 1 of your file. You can change the line
+ number for this automatic breakpoint to be <N> by using the -bN option
+ (where N must be an integer). For example:
+
+ %run -d -b40 myscript
+
+ will set the first breakpoint at line 40 in myscript.py. Note that
+ the first breakpoint must be set on a line which actually does
+ something (not a comment or docstring) for it to stop execution.
+
+ When the pdb debugger starts, you will see a (Pdb) prompt. You must
+ first enter 'c' (without qoutes) to start execution up to the first
+ breakpoint.
+
+ Entering 'help' gives information about the use of the debugger. You
+ can easily see pdb's full documentation with "import pdb;pdb.help()"
+ at a prompt.
+
+ -p: run program under the control of the Python profiler module (which
+ prints a detailed report of execution times, function calls, etc).
+
+ You can pass other options after -p which affect the behavior of the
+ profiler itself. See the docs for %prun for details.
+
+ In this mode, the program's variables do NOT propagate back to the
+ IPython interactive namespace (because they remain in the namespace
+ where the profiler executes them).
+
+ Internally this triggers a call to %prun, see its documentation for
+ details on the options available specifically for profiling.
+
+ There is one special usage for which the text above doesn't apply:
+ if the filename ends with .ipy, the file is run as ipython script,
+ just as if the commands were written on IPython prompt.
+ """
+
+ # get arguments and set sys.argv for program to be run.
+ opts,arg_lst = self.parse_options(parameter_s,'nidtN:b:pD:l:rs:T:e',
+ mode='list',list_all=1)
+
+ try:
+ filename = file_finder(arg_lst[0])
+ except IndexError:
+ warn('you must provide at least a filename.')
+ print '\n%run:\n',OInspect.getdoc(self.magic_run)
+ return
+ except IOError,msg:
+ error(msg)
+ return
+
+ if filename.lower().endswith('.ipy'):
+ self.api.runlines(open(filename).read())
+ return
+
+ # Control the response to exit() calls made by the script being run
+ exit_ignore = opts.has_key('e')
+
+ # Make sure that the running script gets a proper sys.argv as if it
+ # were run from a system shell.
+ save_argv = sys.argv # save it for later restoring
+ sys.argv = [filename]+ arg_lst[1:] # put in the proper filename
+
+ if opts.has_key('i'):
+ # Run in user's interactive namespace
+ prog_ns = self.shell.user_ns
+ __name__save = self.shell.user_ns['__name__']
+ prog_ns['__name__'] = '__main__'
+ main_mod = self.shell.new_main_mod(prog_ns)
+ else:
+ # Run in a fresh, empty namespace
+ if opts.has_key('n'):
+ name = os.path.splitext(os.path.basename(filename))[0]
+ else:
+ name = '__main__'
+
+ main_mod = self.shell.new_main_mod()
+ prog_ns = main_mod.__dict__
+ prog_ns['__name__'] = name
+
+ # Since '%run foo' emulates 'python foo.py' at the cmd line, we must
+ # set the __file__ global in the script's namespace
+ prog_ns['__file__'] = filename
+
+ # pickle fix. See iplib for an explanation. But we need to make sure
+ # that, if we overwrite __main__, we replace it at the end
+ main_mod_name = prog_ns['__name__']
+
+ if main_mod_name == '__main__':
+ restore_main = sys.modules['__main__']
+ else:
+ restore_main = False
+
+ # This needs to be undone at the end to prevent holding references to
+ # every single object ever created.
+ sys.modules[main_mod_name] = main_mod
+
+ stats = None
+ try:
+ self.shell.savehist()
+
+ if opts.has_key('p'):
+ stats = self.magic_prun('',0,opts,arg_lst,prog_ns)
+ else:
+ if opts.has_key('d'):
+ deb = Debugger.Pdb(self.shell.rc.colors)
+ # reset Breakpoint state, which is moronically kept
+ # in a class
+ bdb.Breakpoint.next = 1
+ bdb.Breakpoint.bplist = {}
+ bdb.Breakpoint.bpbynumber = [None]
+ # Set an initial breakpoint to stop execution
+ maxtries = 10
+ bp = int(opts.get('b',[1])[0])
+ checkline = deb.checkline(filename,bp)
+ if not checkline:
+ for bp in range(bp+1,bp+maxtries+1):
+ if deb.checkline(filename,bp):
+ break
+ else:
+ msg = ("\nI failed to find a valid line to set "
+ "a breakpoint\n"
+ "after trying up to line: %s.\n"
+ "Please set a valid breakpoint manually "
+ "with the -b option." % bp)
+ error(msg)
+ return
+ # if we find a good linenumber, set the breakpoint
+ deb.do_break('%s:%s' % (filename,bp))
+ # Start file run
+ print "NOTE: Enter 'c' at the",
+ print "%s prompt to start your script." % deb.prompt
+ try:
+ deb.run('execfile("%s")' % filename,prog_ns)
+
+ except:
+ etype, value, tb = sys.exc_info()
+ # Skip three frames in the traceback: the %run one,
+ # one inside bdb.py, and the command-line typed by the
+ # user (run by exec in pdb itself).
+ self.shell.InteractiveTB(etype,value,tb,tb_offset=3)
+ else:
+ if runner is None:
+ runner = self.shell.safe_execfile
+ if opts.has_key('t'):
+ # timed execution
+ try:
+ nruns = int(opts['N'][0])
+ if nruns < 1:
+ error('Number of runs must be >=1')
+ return
+ except (KeyError):
+ nruns = 1
+ if nruns == 1:
+ t0 = clock2()
+ runner(filename,prog_ns,prog_ns,
+ exit_ignore=exit_ignore)
+ t1 = clock2()
+ t_usr = t1[0]-t0[0]
+ t_sys = t1[1]-t0[1]
+ print "\nIPython CPU timings (estimated):"
+ print " User : %10s s." % t_usr
+ print " System: %10s s." % t_sys
+ else:
+ runs = range(nruns)
+ t0 = clock2()
+ for nr in runs:
+ runner(filename,prog_ns,prog_ns,
+ exit_ignore=exit_ignore)
+ t1 = clock2()
+ t_usr = t1[0]-t0[0]
+ t_sys = t1[1]-t0[1]
+ print "\nIPython CPU timings (estimated):"
+ print "Total runs performed:",nruns
+ print " Times : %10s %10s" % ('Total','Per run')
+ print " User : %10s s, %10s s." % (t_usr,t_usr/nruns)
+ print " System: %10s s, %10s s." % (t_sys,t_sys/nruns)
+
+ else:
+ # regular execution
+ runner(filename,prog_ns,prog_ns,exit_ignore=exit_ignore)
+
+ if opts.has_key('i'):
+ self.shell.user_ns['__name__'] = __name__save
+ else:
+ # The shell MUST hold a reference to prog_ns so after %run
+ # exits, the python deletion mechanism doesn't zero it out
+ # (leaving dangling references).
+ self.shell.cache_main_mod(prog_ns,filename)
+ # update IPython interactive namespace
+
+ # Some forms of read errors on the file may mean the
+ # __name__ key was never set; using pop we don't have to
+ # worry about a possible KeyError.
+ prog_ns.pop('__name__', None)
+
+ self.shell.user_ns.update(prog_ns)
+ finally:
+ # It's a bit of a mystery why, but __builtins__ can change from
+ # being a module to becoming a dict missing some key data after
+ # %run. As best I can see, this is NOT something IPython is doing
+ # at all, and similar problems have been reported before:
+ # http://coding.derkeiler.com/Archive/Python/comp.lang.python/2004-10/0188.html
+ # Since this seems to be done by the interpreter itself, the best
+ # we can do is to at least restore __builtins__ for the user on
+ # exit.
+ self.shell.user_ns['__builtins__'] = __builtin__
+
+ # Ensure key global structures are restored
+ sys.argv = save_argv
+ if restore_main:
+ sys.modules['__main__'] = restore_main
+ else:
+ # Remove from sys.modules the reference to main_mod we'd
+ # added. Otherwise it will trap references to objects
+ # contained therein.
+ del sys.modules[main_mod_name]
+
+ self.shell.reloadhist()
+
+ return stats
+
+ def magic_runlog(self, parameter_s =''):
+ """Run files as logs.
+
+ Usage:\\
+ %runlog file1 file2 ...
+
+ Run the named files (treating them as log files) in sequence inside
+ the interpreter, and return to the prompt. This is much slower than
+ %run because each line is executed in a try/except block, but it
+ allows running files with syntax errors in them.
+
+ Normally IPython will guess when a file is one of its own logfiles, so
+ you can typically use %run even for logs. This shorthand allows you to
+ force any file to be treated as a log file."""
+
+ for f in parameter_s.split():
+ self.shell.safe_execfile(f,self.shell.user_ns,
+ self.shell.user_ns,islog=1)
+
+ @testdec.skip_doctest
+ def magic_timeit(self, parameter_s =''):
+ """Time execution of a Python statement or expression
+
+ Usage:\\
+ %timeit [-n<N> -r<R> [-t|-c]] statement
+
+ Time execution of a Python statement or expression using the timeit
+ module.
+
+ Options:
+ -n<N>: execute the given statement <N> times in a loop. If this value
+ is not given, a fitting value is chosen.
+
+ -r<R>: repeat the loop iteration <R> times and take the best result.
+ Default: 3
+
+ -t: use time.time to measure the time, which is the default on Unix.
+ This function measures wall time.
+
+ -c: use time.clock to measure the time, which is the default on
+ Windows and measures wall time. On Unix, resource.getrusage is used
+ instead and returns the CPU user time.
+
+ -p<P>: use a precision of <P> digits to display the timing result.
+ Default: 3
+
+
+ Examples:
+
+ In [1]: %timeit pass
+ 10000000 loops, best of 3: 53.3 ns per loop
+
+ In [2]: u = None
+
+ In [3]: %timeit u is None
+ 10000000 loops, best of 3: 184 ns per loop
+
+ In [4]: %timeit -r 4 u == None
+ 1000000 loops, best of 4: 242 ns per loop
+
+ In [5]: import time
+
+ In [6]: %timeit -n1 time.sleep(2)
+ 1 loops, best of 3: 2 s per loop
+
+
+ The times reported by %timeit will be slightly higher than those
+ reported by the timeit.py script when variables are accessed. This is
+ due to the fact that %timeit executes the statement in the namespace
+ of the shell, compared with timeit.py, which uses a single setup
+ statement to import function or create variables. Generally, the bias
+ does not matter as long as results from timeit.py are not mixed with
+ those from %timeit."""
+
+ import timeit
+ import math
+
+ # XXX: Unfortunately the unicode 'micro' symbol can cause problems in
+ # certain terminals. Until we figure out a robust way of
+ # auto-detecting if the terminal can deal with it, use plain 'us' for
+ # microseconds. I am really NOT happy about disabling the proper
+ # 'micro' prefix, but crashing is worse... If anyone knows what the
+ # right solution for this is, I'm all ears...
+ #
+ # Note: using
+ #
+ # s = u'\xb5'
+ # s.encode(sys.getdefaultencoding())
+ #
+ # is not sufficient, as I've seen terminals where that fails but
+ # print s
+ #
+ # succeeds
+ #
+ # See bug: https://bugs.launchpad.net/ipython/+bug/348466
+
+ #units = [u"s", u"ms",u'\xb5',"ns"]
+ units = [u"s", u"ms",u'us',"ns"]
+
+ scaling = [1, 1e3, 1e6, 1e9]
+
+ opts, stmt = self.parse_options(parameter_s,'n:r:tcp:',
+ posix=False)
+ if stmt == "":
+ return
+ timefunc = timeit.default_timer
+ number = int(getattr(opts, "n", 0))
+ repeat = int(getattr(opts, "r", timeit.default_repeat))
+ precision = int(getattr(opts, "p", 3))
+ if hasattr(opts, "t"):
+ timefunc = time.time
+ if hasattr(opts, "c"):
+ timefunc = clock
+
+ timer = timeit.Timer(timer=timefunc)
+ # this code has tight coupling to the inner workings of timeit.Timer,
+ # but is there a better way to achieve that the code stmt has access
+ # to the shell namespace?
+
+ src = timeit.template % {'stmt': timeit.reindent(stmt, 8),
+ 'setup': "pass"}
+ # Track compilation time so it can be reported if too long
+ # Minimum time above which compilation time will be reported
+ tc_min = 0.1
+
+ t0 = clock()
+ code = compile(src, "<magic-timeit>", "exec")
+ tc = clock()-t0
+
+ ns = {}
+ exec code in self.shell.user_ns, ns
+ timer.inner = ns["inner"]
+
+ if number == 0:
+ # determine number so that 0.2 <= total time < 2.0
+ number = 1
+ for i in range(1, 10):
+ if timer.timeit(number) >= 0.2:
+ break
+ number *= 10
+
+ best = min(timer.repeat(repeat, number)) / number
+
+ if best > 0.0:
+ order = min(-int(math.floor(math.log10(best)) // 3), 3)
+ else:
+ order = 3
+ print u"%d loops, best of %d: %.*g %s per loop" % (number, repeat,
+ precision,
+ best * scaling[order],
+ units[order])
+ if tc > tc_min:
+ print "Compiler time: %.2f s" % tc
+
+ @testdec.skip_doctest
+ def magic_time(self,parameter_s = ''):
+ """Time execution of a Python statement or expression.
+
+ The CPU and wall clock times are printed, and the value of the
+ expression (if any) is returned. Note that under Win32, system time
+ is always reported as 0, since it can not be measured.
+
+ This function provides very basic timing functionality. In Python
+ 2.3, the timeit module offers more control and sophistication, so this
+ could be rewritten to use it (patches welcome).
+
+ Some examples:
+
+ In [1]: time 2**128
+ CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
+ Wall time: 0.00
+ Out[1]: 340282366920938463463374607431768211456L
+
+ In [2]: n = 1000000
+
+ In [3]: time sum(range(n))
+ CPU times: user 1.20 s, sys: 0.05 s, total: 1.25 s
+ Wall time: 1.37
+ Out[3]: 499999500000L
+
+ In [4]: time print 'hello world'
+ hello world
+ CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
+ Wall time: 0.00
+
+ Note that the time needed by Python to compile the given expression
+ will be reported if it is more than 0.1s. In this example, the
+ actual exponentiation is done by Python at compilation time, so while
+ the expression can take a noticeable amount of time to compute, that
+ time is purely due to the compilation:
+
+ In [5]: time 3**9999;
+ CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
+ Wall time: 0.00 s
+
+ In [6]: time 3**999999;
+ CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
+ Wall time: 0.00 s
+ Compiler : 0.78 s
+ """
+
+ # fail immediately if the given expression can't be compiled
+
+ expr = self.shell.prefilter(parameter_s,False)
+
+ # Minimum time above which compilation time will be reported
+ tc_min = 0.1
+
+ try:
+ mode = 'eval'
+ t0 = clock()
+ code = compile(expr,'<timed eval>',mode)
+ tc = clock()-t0
+ except SyntaxError:
+ mode = 'exec'
+ t0 = clock()
+ code = compile(expr,'<timed exec>',mode)
+ tc = clock()-t0
+ # skew measurement as little as possible
+ glob = self.shell.user_ns
+ clk = clock2
+ wtime = time.time
+ # time execution
+ wall_st = wtime()
+ if mode=='eval':
+ st = clk()
+ out = eval(code,glob)
+ end = clk()
+ else:
+ st = clk()
+ exec code in glob
+ end = clk()
+ out = None
+ wall_end = wtime()
+ # Compute actual times and report
+ wall_time = wall_end-wall_st
+ cpu_user = end[0]-st[0]
+ cpu_sys = end[1]-st[1]
+ cpu_tot = cpu_user+cpu_sys
+ print "CPU times: user %.2f s, sys: %.2f s, total: %.2f s" % \
+ (cpu_user,cpu_sys,cpu_tot)
+ print "Wall time: %.2f s" % wall_time
+ if tc > tc_min:
+ print "Compiler : %.2f s" % tc
+ return out
+
+ @testdec.skip_doctest
+ def magic_macro(self,parameter_s = ''):
+ """Define a set of input lines as a macro for future re-execution.
+
+ Usage:\\
+ %macro [options] name n1-n2 n3-n4 ... n5 .. n6 ...
+
+ Options:
+
+ -r: use 'raw' input. By default, the 'processed' history is used,
+ so that magics are loaded in their transformed version to valid
+ Python. If this option is given, the raw input as typed as the
+ command line is used instead.
+
+ This will define a global variable called `name` which is a string
+ made of joining the slices and lines you specify (n1,n2,... numbers
+ above) from your input history into a single string. This variable
+ acts like an automatic function which re-executes those lines as if
+ you had typed them. You just type 'name' at the prompt and the code
+ executes.
+
+ The notation for indicating number ranges is: n1-n2 means 'use line
+ numbers n1,...n2' (the endpoint is included). That is, '5-7' means
+ using the lines numbered 5,6 and 7.
+
+ Note: as a 'hidden' feature, you can also use traditional python slice
+ notation, where N:M means numbers N through M-1.
+
+ For example, if your history contains (%hist prints it):
+
+ 44: x=1
+ 45: y=3
+ 46: z=x+y
+ 47: print x
+ 48: a=5
+ 49: print 'x',x,'y',y
+
+ you can create a macro with lines 44 through 47 (included) and line 49
+ called my_macro with:
+
+ In [55]: %macro my_macro 44-47 49
+
+ Now, typing `my_macro` (without quotes) will re-execute all this code
+ in one pass.
+
+ You don't need to give the line-numbers in order, and any given line
+ number can appear multiple times. You can assemble macros with any
+ lines from your input history in any order.
+
+ The macro is a simple object which holds its value in an attribute,
+ but IPython's display system checks for macros and executes them as
+ code instead of printing them when you type their name.
+
+ You can view a macro's contents by explicitly printing it with:
+
+ 'print macro_name'.
+
+ For one-off cases which DON'T contain magic function calls in them you
+ can obtain similar results by explicitly executing slices from your
+ input history with:
+
+ In [60]: exec In[44:48]+In[49]"""
+
+ opts,args = self.parse_options(parameter_s,'r',mode='list')
+ if not args:
+ macs = [k for k,v in self.shell.user_ns.items() if isinstance(v, Macro)]
+ macs.sort()
+ return macs
+ if len(args) == 1:
+ raise UsageError(
+ "%macro insufficient args; usage '%macro name n1-n2 n3-4...")
+ name,ranges = args[0], args[1:]
+
+ #print 'rng',ranges # dbg
+ lines = self.extract_input_slices(ranges,opts.has_key('r'))
+ macro = Macro(lines)
+ self.shell.user_ns.update({name:macro})
+ print 'Macro `%s` created. To execute, type its name (without quotes).' % name
+ print 'Macro contents:'
+ print macro,
+
+ def magic_save(self,parameter_s = ''):
+ """Save a set of lines to a given filename.
+
+ Usage:\\
+ %save [options] filename n1-n2 n3-n4 ... n5 .. n6 ...
+
+ Options:
+
+ -r: use 'raw' input. By default, the 'processed' history is used,
+ so that magics are loaded in their transformed version to valid
+ Python. If this option is given, the raw input as typed as the
+ command line is used instead.
+
+ This function uses the same syntax as %macro for line extraction, but
+ instead of creating a macro it saves the resulting string to the
+ filename you specify.
+
+ It adds a '.py' extension to the file if you don't do so yourself, and
+ it asks for confirmation before overwriting existing files."""
+
+ opts,args = self.parse_options(parameter_s,'r',mode='list')
+ fname,ranges = args[0], args[1:]
+ if not fname.endswith('.py'):
+ fname += '.py'
+ if os.path.isfile(fname):
+ ans = raw_input('File `%s` exists. Overwrite (y/[N])? ' % fname)
+ if ans.lower() not in ['y','yes']:
+ print 'Operation cancelled.'
+ return
+ cmds = ''.join(self.extract_input_slices(ranges,opts.has_key('r')))
+ f = file(fname,'w')
+ f.write(cmds)
+ f.close()
+ print 'The following commands were written to file `%s`:' % fname
+ print cmds
+
+ def _edit_macro(self,mname,macro):
+ """open an editor with the macro data in a file"""
+ filename = self.shell.mktempfile(macro.value)
+ self.shell.hooks.editor(filename)
+
+ # and make a new macro object, to replace the old one
+ mfile = open(filename)
+ mvalue = mfile.read()
+ mfile.close()
+ self.shell.user_ns[mname] = Macro(mvalue)
+
+ def magic_ed(self,parameter_s=''):
+ """Alias to %edit."""
+ return self.magic_edit(parameter_s)
+
+ @testdec.skip_doctest
+ def magic_edit(self,parameter_s='',last_call=['','']):
+ """Bring up an editor and execute the resulting code.
+
+ Usage:
+ %edit [options] [args]
+
+ %edit runs IPython's editor hook. The default version of this hook is
+ set to call the __IPYTHON__.rc.editor command. This is read from your
+ environment variable $EDITOR. If this isn't found, it will default to
+ vi under Linux/Unix and to notepad under Windows. See the end of this
+ docstring for how to change the editor hook.
+
+ You can also set the value of this editor via the command line option
+ '-editor' or in your ipythonrc file. This is useful if you wish to use
+ specifically for IPython an editor different from your typical default
+ (and for Windows users who typically don't set environment variables).
+
+ This command allows you to conveniently edit multi-line code right in
+ your IPython session.
+
+ If called without arguments, %edit opens up an empty editor with a
+ temporary file and will execute the contents of this file when you
+ close it (don't forget to save it!).
+
+
+ Options:
+
+ -n <number>: open the editor at a specified line number. By default,
+ the IPython editor hook uses the unix syntax 'editor +N filename', but
+ you can configure this by providing your own modified hook if your
+ favorite editor supports line-number specifications with a different
+ syntax.
+
+ -p: this will call the editor with the same data as the previous time
+ it was used, regardless of how long ago (in your current session) it
+ was.
+
+ -r: use 'raw' input. This option only applies to input taken from the
+ user's history. By default, the 'processed' history is used, so that
+ magics are loaded in their transformed version to valid Python. If
+ this option is given, the raw input as typed as the command line is
+ used instead. When you exit the editor, it will be executed by
+ IPython's own processor.
+
+ -x: do not execute the edited code immediately upon exit. This is
+ mainly useful if you are editing programs which need to be called with
+ command line arguments, which you can then do using %run.
+
+
+ Arguments:
+
+ If arguments are given, the following possibilites exist:
+
+ - The arguments are numbers or pairs of colon-separated numbers (like
+ 1 4:8 9). These are interpreted as lines of previous input to be
+ loaded into the editor. The syntax is the same of the %macro command.
+
+ - If the argument doesn't start with a number, it is evaluated as a
+ variable and its contents loaded into the editor. You can thus edit
+ any string which contains python code (including the result of
+ previous edits).
+
+ - If the argument is the name of an object (other than a string),
+ IPython will try to locate the file where it was defined and open the
+ editor at the point where it is defined. You can use `%edit function`
+ to load an editor exactly at the point where 'function' is defined,
+ edit it and have the file be executed automatically.
+
+ If the object is a macro (see %macro for details), this opens up your
+ specified editor with a temporary file containing the macro's data.
+ Upon exit, the macro is reloaded with the contents of the file.
+
+ Note: opening at an exact line is only supported under Unix, and some
+ editors (like kedit and gedit up to Gnome 2.8) do not understand the
+ '+NUMBER' parameter necessary for this feature. Good editors like
+ (X)Emacs, vi, jed, pico and joe all do.
+
+ - If the argument is not found as a variable, IPython will look for a
+ file with that name (adding .py if necessary) and load it into the
+ editor. It will execute its contents with execfile() when you exit,
+ loading any code in the file into your interactive namespace.
+
+ After executing your code, %edit will return as output the code you
+ typed in the editor (except when it was an existing file). This way
+ you can reload the code in further invocations of %edit as a variable,
+ via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
+ the output.
+
+ Note that %edit is also available through the alias %ed.
+
+ This is an example of creating a simple function inside the editor and
+ then modifying it. First, start up the editor:
+
+ In [1]: ed
+ Editing... done. Executing edited code...
+ Out[1]: 'def foo():n print "foo() was defined in an editing session"n'
+
+ We can then call the function foo():
+
+ In [2]: foo()
+ foo() was defined in an editing session
+
+ Now we edit foo. IPython automatically loads the editor with the
+ (temporary) file where foo() was previously defined:
+
+ In [3]: ed foo
+ Editing... done. Executing edited code...
+
+ And if we call foo() again we get the modified version:
+
+ In [4]: foo()
+ foo() has now been changed!
+
+ Here is an example of how to edit a code snippet successive
+ times. First we call the editor:
+
+ In [5]: ed
+ Editing... done. Executing edited code...
+ hello
+ Out[5]: "print 'hello'n"
+
+ Now we call it again with the previous output (stored in _):
+
+ In [6]: ed _
+ Editing... done. Executing edited code...
+ hello world
+ Out[6]: "print 'hello world'n"
+
+ Now we call it with the output #8 (stored in _8, also as Out[8]):
+
+ In [7]: ed _8
+ Editing... done. Executing edited code...
+ hello again
+ Out[7]: "print 'hello again'n"
+
+
+ Changing the default editor hook:
+
+ If you wish to write your own editor hook, you can put it in a
+ configuration file which you load at startup time. The default hook
+ is defined in the IPython.hooks module, and you can use that as a
+ starting example for further modifications. That file also has
+ general instructions on how to set a new hook for use once you've
+ defined it."""
+
+ # FIXME: This function has become a convoluted mess. It needs a
+ # ground-up rewrite with clean, simple logic.
+
+ def make_filename(arg):
+ "Make a filename from the given args"
+ try:
+ filename = get_py_filename(arg)
+ except IOError:
+ if args.endswith('.py'):
+ filename = arg
+ else:
+ filename = None
+ return filename
+
+ # custom exceptions
+ class DataIsObject(Exception): pass
+
+ opts,args = self.parse_options(parameter_s,'prxn:')
+ # Set a few locals from the options for convenience:
+ opts_p = opts.has_key('p')
+ opts_r = opts.has_key('r')
+
+ # Default line number value
+ lineno = opts.get('n',None)
+
+ if opts_p:
+ args = '_%s' % last_call[0]
+ if not self.shell.user_ns.has_key(args):
+ args = last_call[1]
+
+ # use last_call to remember the state of the previous call, but don't
+ # let it be clobbered by successive '-p' calls.
+ try:
+ last_call[0] = self.shell.outputcache.prompt_count
+ if not opts_p:
+ last_call[1] = parameter_s
+ except:
+ pass
+
+ # by default this is done with temp files, except when the given
+ # arg is a filename
+ use_temp = 1
+
+ if re.match(r'\d',args):
+ # Mode where user specifies ranges of lines, like in %macro.
+ # This means that you can't edit files whose names begin with
+ # numbers this way. Tough.
+ ranges = args.split()
+ data = ''.join(self.extract_input_slices(ranges,opts_r))
+ elif args.endswith('.py'):
+ filename = make_filename(args)
+ data = ''
+ use_temp = 0
+ elif args:
+ try:
+ # Load the parameter given as a variable. If not a string,
+ # process it as an object instead (below)
+
+ #print '*** args',args,'type',type(args) # dbg
+ data = eval(args,self.shell.user_ns)
+ if not type(data) in StringTypes:
+ raise DataIsObject
+
+ except (NameError,SyntaxError):
+ # given argument is not a variable, try as a filename
+ filename = make_filename(args)
+ if filename is None:
+ warn("Argument given (%s) can't be found as a variable "
+ "or as a filename." % args)
+ return
+
+ data = ''
+ use_temp = 0
+ except DataIsObject:
+
+ # macros have a special edit function
+ if isinstance(data,Macro):
+ self._edit_macro(args,data)
+ return
+
+ # For objects, try to edit the file where they are defined
+ try:
+ filename = inspect.getabsfile(data)
+ if 'fakemodule' in filename.lower() and inspect.isclass(data):
+ # class created by %edit? Try to find source
+ # by looking for method definitions instead, the
+ # __module__ in those classes is FakeModule.
+ attrs = [getattr(data, aname) for aname in dir(data)]
+ for attr in attrs:
+ if not inspect.ismethod(attr):
+ continue
+ filename = inspect.getabsfile(attr)
+ if filename and 'fakemodule' not in filename.lower():
+ # change the attribute to be the edit target instead
+ data = attr
+ break
+
+ datafile = 1
+ except TypeError:
+ filename = make_filename(args)
+ datafile = 1
+ warn('Could not find file where `%s` is defined.\n'
+ 'Opening a file named `%s`' % (args,filename))
+ # Now, make sure we can actually read the source (if it was in
+ # a temp file it's gone by now).
+ if datafile:
+ try:
+ if lineno is None:
+ lineno = inspect.getsourcelines(data)[1]
+ except IOError:
+ filename = make_filename(args)
+ if filename is None:
+ warn('The file `%s` where `%s` was defined cannot '
+ 'be read.' % (filename,data))
+ return
+ use_temp = 0
+ else:
+ data = ''
+
+ if use_temp:
+ filename = self.shell.mktempfile(data)
+ print 'IPython will make a temporary file named:',filename
+
+ # do actual editing here
+ print 'Editing...',
+ sys.stdout.flush()
+ try:
+ self.shell.hooks.editor(filename,lineno)
+ except IPython.ipapi.TryNext:
+ warn('Could not open editor')
+ return
+
+ # XXX TODO: should this be generalized for all string vars?
+ # For now, this is special-cased to blocks created by cpaste
+ if args.strip() == 'pasted_block':
+ self.shell.user_ns['pasted_block'] = file_read(filename)
+
+ if opts.has_key('x'): # -x prevents actual execution
+ print
+ else:
+ print 'done. Executing edited code...'
+ if opts_r:
+ self.shell.runlines(file_read(filename))
+ else:
+ self.shell.safe_execfile(filename,self.shell.user_ns,
+ self.shell.user_ns)
+
+
+ if use_temp:
+ try:
+ return open(filename).read()
+ except IOError,msg:
+ if msg.filename == filename:
+ warn('File not found. Did you forget to save?')
+ return
+ else:
+ self.shell.showtraceback()
+
+ def magic_xmode(self,parameter_s = ''):
+ """Switch modes for the exception handlers.
+
+ Valid modes: Plain, Context and Verbose.
+
+ If called without arguments, acts as a toggle."""
+
+ def xmode_switch_err(name):
+ warn('Error changing %s exception modes.\n%s' %
+ (name,sys.exc_info()[1]))
+
+ shell = self.shell
+ new_mode = parameter_s.strip().capitalize()
+ try:
+ shell.InteractiveTB.set_mode(mode=new_mode)
+ print 'Exception reporting mode:',shell.InteractiveTB.mode
+ except:
+ xmode_switch_err('user')
+
+ # threaded shells use a special handler in sys.excepthook
+ if shell.isthreaded:
+ try:
+ shell.sys_excepthook.set_mode(mode=new_mode)
+ except:
+ xmode_switch_err('threaded')
+
+ def magic_colors(self,parameter_s = ''):
+ """Switch color scheme for prompts, info system and exception handlers.
+
+ Currently implemented schemes: NoColor, Linux, LightBG.
+
+ Color scheme names are not case-sensitive."""
+
+ def color_switch_err(name):
+ warn('Error changing %s color schemes.\n%s' %
+ (name,sys.exc_info()[1]))
+
+
+ new_scheme = parameter_s.strip()
+ if not new_scheme:
+ raise UsageError(
+ "%colors: you must specify a color scheme. See '%colors?'")
+ return
+ # local shortcut
+ shell = self.shell
+
+ import IPython.rlineimpl as readline
+
+ if not readline.have_readline and sys.platform == "win32":
+ msg = """\
+Proper color support under MS Windows requires the pyreadline library.
+You can find it at:
+http://ipython.scipy.org/moin/PyReadline/Intro
+Gary's readline needs the ctypes module, from:
+http://starship.python.net/crew/theller/ctypes
+(Note that ctypes is already part of Python versions 2.5 and newer).
+
+Defaulting color scheme to 'NoColor'"""
+ new_scheme = 'NoColor'
+ warn(msg)
+
+ # readline option is 0
+ if not shell.has_readline:
+ new_scheme = 'NoColor'
+
+ # Set prompt colors
+ try:
+ shell.outputcache.set_colors(new_scheme)
+ except:
+ color_switch_err('prompt')
+ else:
+ shell.rc.colors = \
+ shell.outputcache.color_table.active_scheme_name
+ # Set exception colors
+ try:
+ shell.InteractiveTB.set_colors(scheme = new_scheme)
+ shell.SyntaxTB.set_colors(scheme = new_scheme)
+ except:
+ color_switch_err('exception')
+
+ # threaded shells use a verbose traceback in sys.excepthook
+ if shell.isthreaded:
+ try:
+ shell.sys_excepthook.set_colors(scheme=new_scheme)
+ except:
+ color_switch_err('system exception handler')
+
+ # Set info (for 'object?') colors
+ if shell.rc.color_info:
+ try:
+ shell.inspector.set_active_scheme(new_scheme)
+ except:
+ color_switch_err('object inspector')
+ else:
+ shell.inspector.set_active_scheme('NoColor')
+
+ def magic_color_info(self,parameter_s = ''):
+ """Toggle color_info.
+
+ The color_info configuration parameter controls whether colors are
+ used for displaying object details (by things like %psource, %pfile or
+ the '?' system). This function toggles this value with each call.
+
+ Note that unless you have a fairly recent pager (less works better
+ than more) in your system, using colored object information displays
+ will not work properly. Test it and see."""
+
+ self.shell.rc.color_info = 1 - self.shell.rc.color_info
+ self.magic_colors(self.shell.rc.colors)
+ print 'Object introspection functions have now coloring:',
+ print ['OFF','ON'][self.shell.rc.color_info]
+
+ def magic_Pprint(self, parameter_s=''):
+ """Toggle pretty printing on/off."""
+
+ self.shell.rc.pprint = 1 - self.shell.rc.pprint
+ print 'Pretty printing has been turned', \
+ ['OFF','ON'][self.shell.rc.pprint]
+
+ def magic_exit(self, parameter_s=''):
+ """Exit IPython, confirming if configured to do so.
+
+ You can configure whether IPython asks for confirmation upon exit by
+ setting the confirm_exit flag in the ipythonrc file."""
+
+ self.shell.exit()
+
+ def magic_quit(self, parameter_s=''):
+ """Exit IPython, confirming if configured to do so (like %exit)"""
+
+ self.shell.exit()
+
+ def magic_Exit(self, parameter_s=''):
+ """Exit IPython without confirmation."""
+
+ self.shell.ask_exit()
+
+ #......................................................................
+ # Functions to implement unix shell-type things
+
+ @testdec.skip_doctest
+ def magic_alias(self, parameter_s = ''):
+ """Define an alias for a system command.
+
+ '%alias alias_name cmd' defines 'alias_name' as an alias for 'cmd'
+
+ Then, typing 'alias_name params' will execute the system command 'cmd
+ params' (from your underlying operating system).
+
+ Aliases have lower precedence than magic functions and Python normal
+ variables, so if 'foo' is both a Python variable and an alias, the
+ alias can not be executed until 'del foo' removes the Python variable.
+
+ You can use the %l specifier in an alias definition to represent the
+ whole line when the alias is called. For example:
+
+ In [2]: alias all echo "Input in brackets: <%l>"
+ In [3]: all hello world
+ Input in brackets: <hello world>
+
+ You can also define aliases with parameters using %s specifiers (one
+ per parameter):
+
+ In [1]: alias parts echo first %s second %s
+ In [2]: %parts A B
+ first A second B
+ In [3]: %parts A
+ Incorrect number of arguments: 2 expected.
+ parts is an alias to: 'echo first %s second %s'
+
+ Note that %l and %s are mutually exclusive. You can only use one or
+ the other in your aliases.
+
+ Aliases expand Python variables just like system calls using ! or !!
+ do: all expressions prefixed with '$' get expanded. For details of
+ the semantic rules, see PEP-215:
+ http://www.python.org/peps/pep-0215.html. This is the library used by
+ IPython for variable expansion. If you want to access a true shell
+ variable, an extra $ is necessary to prevent its expansion by IPython:
+
+ In [6]: alias show echo
+ In [7]: PATH='A Python string'
+ In [8]: show $PATH
+ A Python string
+ In [9]: show $$PATH
+ /usr/local/lf9560/bin:/usr/local/intel/compiler70/ia32/bin:...
+
+ You can use the alias facility to acess all of $PATH. See the %rehash
+ and %rehashx functions, which automatically create aliases for the
+ contents of your $PATH.
+
+ If called with no parameters, %alias prints the current alias table."""
+
+ par = parameter_s.strip()
+ if not par:
+ stored = self.db.get('stored_aliases', {} )
+ atab = self.shell.alias_table
+ aliases = atab.keys()
+ aliases.sort()
+ res = []
+ showlast = []
+ for alias in aliases:
+ special = False
+ try:
+ tgt = atab[alias][1]
+ except (TypeError, AttributeError):
+ # unsubscriptable? probably a callable
+ tgt = atab[alias]
+ special = True
+ # 'interesting' aliases
+ if (alias in stored or
+ special or
+ alias.lower() != os.path.splitext(tgt)[0].lower() or
+ ' ' in tgt):
+ showlast.append((alias, tgt))
+ else:
+ res.append((alias, tgt ))
+
+ # show most interesting aliases last
+ res.extend(showlast)
+ print "Total number of aliases:",len(aliases)
+ return res
+ try:
+ alias,cmd = par.split(None,1)
+ except:
+ print OInspect.getdoc(self.magic_alias)
+ else:
+ nargs = cmd.count('%s')
+ if nargs>0 and cmd.find('%l')>=0:
+ error('The %s and %l specifiers are mutually exclusive '
+ 'in alias definitions.')
+ else: # all looks OK
+ self.shell.alias_table[alias] = (nargs,cmd)
+ self.shell.alias_table_validate(verbose=0)
+ # end magic_alias
+
+ def magic_unalias(self, parameter_s = ''):
+ """Remove an alias"""
+
+ aname = parameter_s.strip()
+ if aname in self.shell.alias_table:
+ del self.shell.alias_table[aname]
+ stored = self.db.get('stored_aliases', {} )
+ if aname in stored:
+ print "Removing %stored alias",aname
+ del stored[aname]
+ self.db['stored_aliases'] = stored
+
+
+ def magic_rehashx(self, parameter_s = ''):
+ """Update the alias table with all executable files in $PATH.
+
+ This version explicitly checks that every entry in $PATH is a file
+ with execute access (os.X_OK), so it is much slower than %rehash.
+
+ Under Windows, it checks executability as a match agains a
+ '|'-separated string of extensions, stored in the IPython config
+ variable win_exec_ext. This defaults to 'exe|com|bat'.
+
+ This function also resets the root module cache of module completer,
+ used on slow filesystems.
+ """
+
+
+ ip = self.api
+
+ # for the benefit of module completer in ipy_completers.py
+ del ip.db['rootmodules']
+
+ path = [os.path.abspath(os.path.expanduser(p)) for p in
+ os.environ.get('PATH','').split(os.pathsep)]
+ path = filter(os.path.isdir,path)
+
+ alias_table = self.shell.alias_table
+ syscmdlist = []
+ if os.name == 'posix':
+ isexec = lambda fname:os.path.isfile(fname) and \
+ os.access(fname,os.X_OK)
+ else:
+
+ try:
+ winext = os.environ['pathext'].replace(';','|').replace('.','')
+ except KeyError:
+ winext = 'exe|com|bat|py'
+ if 'py' not in winext:
+ winext += '|py'
+ execre = re.compile(r'(.*)\.(%s)$' % winext,re.IGNORECASE)
+ isexec = lambda fname:os.path.isfile(fname) and execre.match(fname)
+ savedir = os.getcwd()
+ try:
+ # write the whole loop for posix/Windows so we don't have an if in
+ # the innermost part
+ if os.name == 'posix':
+ for pdir in path:
+ os.chdir(pdir)
+ for ff in os.listdir(pdir):
+ if isexec(ff) and ff not in self.shell.no_alias:
+ # each entry in the alias table must be (N,name),
+ # where N is the number of positional arguments of the
+ # alias.
+ # Dots will be removed from alias names, since ipython
+ # assumes names with dots to be python code
+ alias_table[ff.replace('.','')] = (0,ff)
+ syscmdlist.append(ff)
+ else:
+ for pdir in path:
+ os.chdir(pdir)
+ for ff in os.listdir(pdir):
+ base, ext = os.path.splitext(ff)
+ if isexec(ff) and base.lower() not in self.shell.no_alias:
+ if ext.lower() == '.exe':
+ ff = base
+ alias_table[base.lower().replace('.','')] = (0,ff)
+ syscmdlist.append(ff)
+ # Make sure the alias table doesn't contain keywords or builtins
+ self.shell.alias_table_validate()
+ # Call again init_auto_alias() so we get 'rm -i' and other
+ # modified aliases since %rehashx will probably clobber them
+
+ # no, we don't want them. if %rehashx clobbers them, good,
+ # we'll probably get better versions
+ # self.shell.init_auto_alias()
+ db = ip.db
+ db['syscmdlist'] = syscmdlist
+ finally:
+ os.chdir(savedir)
+
+ def magic_pwd(self, parameter_s = ''):
+ """Return the current working directory path."""
+ return os.getcwd()
+
+ def magic_cd(self, parameter_s=''):
+ """Change the current working directory.
+
+ This command automatically maintains an internal list of directories
+ you visit during your IPython session, in the variable _dh. The
+ command %dhist shows this history nicely formatted. You can also
+ do 'cd -<tab>' to see directory history conveniently.
+
+ Usage:
+
+ cd 'dir': changes to directory 'dir'.
+
+ cd -: changes to the last visited directory.
+
+ cd -<n>: changes to the n-th directory in the directory history.
+
+ cd --foo: change to directory that matches 'foo' in history
+
+ cd -b <bookmark_name>: jump to a bookmark set by %bookmark
+ (note: cd <bookmark_name> is enough if there is no
+ directory <bookmark_name>, but a bookmark with the name exists.)
+ 'cd -b <tab>' allows you to tab-complete bookmark names.
+
+ Options:
+
+ -q: quiet. Do not print the working directory after the cd command is
+ executed. By default IPython's cd command does print this directory,
+ since the default prompts do not display path information.
+
+ Note that !cd doesn't work for this purpose because the shell where
+ !command runs is immediately discarded after executing 'command'."""
+
+ parameter_s = parameter_s.strip()
+ #bkms = self.shell.persist.get("bookmarks",{})
+
+ oldcwd = os.getcwd()
+ numcd = re.match(r'(-)(\d+)$',parameter_s)
+ # jump in directory history by number
+ if numcd:
+ nn = int(numcd.group(2))
+ try:
+ ps = self.shell.user_ns['_dh'][nn]
+ except IndexError:
+ print 'The requested directory does not exist in history.'
+ return
+ else:
+ opts = {}
+ elif parameter_s.startswith('--'):
+ ps = None
+ fallback = None
+ pat = parameter_s[2:]
+ dh = self.shell.user_ns['_dh']
+ # first search only by basename (last component)
+ for ent in reversed(dh):
+ if pat in os.path.basename(ent) and os.path.isdir(ent):
+ ps = ent
+ break
+
+ if fallback is None and pat in ent and os.path.isdir(ent):
+ fallback = ent
+
+ # if we have no last part match, pick the first full path match
+ if ps is None:
+ ps = fallback
+
+ if ps is None:
+ print "No matching entry in directory history"
+ return
+ else:
+ opts = {}
+
+
+ else:
+ #turn all non-space-escaping backslashes to slashes,
+ # for c:\windows\directory\names\
+ parameter_s = re.sub(r'\\(?! )','/', parameter_s)
+ opts,ps = self.parse_options(parameter_s,'qb',mode='string')
+ # jump to previous
+ if ps == '-':
+ try:
+ ps = self.shell.user_ns['_dh'][-2]
+ except IndexError:
+ raise UsageError('%cd -: No previous directory to change to.')
+ # jump to bookmark if needed
+ else:
+ if not os.path.isdir(ps) or opts.has_key('b'):
+ bkms = self.db.get('bookmarks', {})
+
+ if bkms.has_key(ps):
+ target = bkms[ps]
+ print '(bookmark:%s) -> %s' % (ps,target)
+ ps = target
+ else:
+ if opts.has_key('b'):
+ raise UsageError("Bookmark '%s' not found. "
+ "Use '%%bookmark -l' to see your bookmarks." % ps)
+
+ # at this point ps should point to the target dir
+ if ps:
+ try:
+ os.chdir(os.path.expanduser(ps))
+ if self.shell.rc.term_title:
+ #print 'set term title:',self.shell.rc.term_title # dbg
+ platutils.set_term_title('IPy ' + abbrev_cwd())
+ except OSError:
+ print sys.exc_info()[1]
+ else:
+ cwd = os.getcwd()
+ dhist = self.shell.user_ns['_dh']
+ if oldcwd != cwd:
+ dhist.append(cwd)
+ self.db['dhist'] = compress_dhist(dhist)[-100:]
+
+ else:
+ os.chdir(self.shell.home_dir)
+ if self.shell.rc.term_title:
+ platutils.set_term_title("IPy ~")
+ cwd = os.getcwd()
+ dhist = self.shell.user_ns['_dh']
+
+ if oldcwd != cwd:
+ dhist.append(cwd)
+ self.db['dhist'] = compress_dhist(dhist)[-100:]
+ if not 'q' in opts and self.shell.user_ns['_dh']:
+ print self.shell.user_ns['_dh'][-1]
+
+
+ def magic_env(self, parameter_s=''):
+ """List environment variables."""
+
+ return os.environ.data
+
+ def magic_pushd(self, parameter_s=''):
+ """Place the current dir on stack and change directory.
+
+ Usage:\\
+ %pushd ['dirname']
+ """
+
+ dir_s = self.shell.dir_stack
+ tgt = os.path.expanduser(parameter_s)
+ cwd = os.getcwd().replace(self.home_dir,'~')
+ if tgt:
+ self.magic_cd(parameter_s)
+ dir_s.insert(0,cwd)
+ return self.magic_dirs()
+
+ def magic_popd(self, parameter_s=''):
+ """Change to directory popped off the top of the stack.
+ """
+ if not self.shell.dir_stack:
+ raise UsageError("%popd on empty stack")
+ top = self.shell.dir_stack.pop(0)
+ self.magic_cd(top)
+ print "popd ->",top
+
+ def magic_dirs(self, parameter_s=''):
+ """Return the current directory stack."""
+
+ return self.shell.dir_stack
+
+ def magic_dhist(self, parameter_s=''):
+ """Print your history of visited directories.
+
+ %dhist -> print full history\\
+ %dhist n -> print last n entries only\\
+ %dhist n1 n2 -> print entries between n1 and n2 (n1 not included)\\
+
+ This history is automatically maintained by the %cd command, and
+ always available as the global list variable _dh. You can use %cd -<n>
+ to go to directory number <n>.
+
+ Note that most of time, you should view directory history by entering
+ cd -<TAB>.
+
+ """
+
+ dh = self.shell.user_ns['_dh']
+ if parameter_s:
+ try:
+ args = map(int,parameter_s.split())
+ except:
+ self.arg_err(Magic.magic_dhist)
+ return
+ if len(args) == 1:
+ ini,fin = max(len(dh)-(args[0]),0),len(dh)
+ elif len(args) == 2:
+ ini,fin = args
+ else:
+ self.arg_err(Magic.magic_dhist)
+ return
+ else:
+ ini,fin = 0,len(dh)
+ nlprint(dh,
+ header = 'Directory history (kept in _dh)',
+ start=ini,stop=fin)
+
+ @testdec.skip_doctest
+ def magic_sc(self, parameter_s=''):
+ """Shell capture - execute a shell command and capture its output.
+
+ DEPRECATED. Suboptimal, retained for backwards compatibility.
+
+ You should use the form 'var = !command' instead. Example:
+
+ "%sc -l myfiles = ls ~" should now be written as
+
+ "myfiles = !ls ~"
+
+ myfiles.s, myfiles.l and myfiles.n still apply as documented
+ below.
+
+ --
+ %sc [options] varname=command
+
+ IPython will run the given command using commands.getoutput(), and
+ will then update the user's interactive namespace with a variable
+ called varname, containing the value of the call. Your command can
+ contain shell wildcards, pipes, etc.
+
+ The '=' sign in the syntax is mandatory, and the variable name you
+ supply must follow Python's standard conventions for valid names.
+
+ (A special format without variable name exists for internal use)
+
+ Options:
+
+ -l: list output. Split the output on newlines into a list before
+ assigning it to the given variable. By default the output is stored
+ as a single string.
+
+ -v: verbose. Print the contents of the variable.
+
+ In most cases you should not need to split as a list, because the
+ returned value is a special type of string which can automatically
+ provide its contents either as a list (split on newlines) or as a
+ space-separated string. These are convenient, respectively, either
+ for sequential processing or to be passed to a shell command.
+
+ For example:
+
+ # all-random
+
+ # Capture into variable a
+ In [1]: sc a=ls *py
+
+ # a is a string with embedded newlines
+ In [2]: a
+ Out[2]: 'setup.py\\nwin32_manual_post_install.py'
+
+ # which can be seen as a list:
+ In [3]: a.l
+ Out[3]: ['setup.py', 'win32_manual_post_install.py']
+
+ # or as a whitespace-separated string:
+ In [4]: a.s
+ Out[4]: 'setup.py win32_manual_post_install.py'
+
+ # a.s is useful to pass as a single command line:
+ In [5]: !wc -l $a.s
+ 146 setup.py
+ 130 win32_manual_post_install.py
+ 276 total
+
+ # while the list form is useful to loop over:
+ In [6]: for f in a.l:
+ ...: !wc -l $f
+ ...:
+ 146 setup.py
+ 130 win32_manual_post_install.py
+
+ Similiarly, the lists returned by the -l option are also special, in
+ the sense that you can equally invoke the .s attribute on them to
+ automatically get a whitespace-separated string from their contents:
+
+ In [7]: sc -l b=ls *py
+
+ In [8]: b
+ Out[8]: ['setup.py', 'win32_manual_post_install.py']
+
+ In [9]: b.s
+ Out[9]: 'setup.py win32_manual_post_install.py'
+
+ In summary, both the lists and strings used for ouptut capture have
+ the following special attributes:
+
+ .l (or .list) : value as list.
+ .n (or .nlstr): value as newline-separated string.
+ .s (or .spstr): value as space-separated string.
+ """
+
+ opts,args = self.parse_options(parameter_s,'lv')
+ # Try to get a variable name and command to run
+ try:
+ # the variable name must be obtained from the parse_options
+ # output, which uses shlex.split to strip options out.
+ var,_ = args.split('=',1)
+ var = var.strip()
+ # But the the command has to be extracted from the original input
+ # parameter_s, not on what parse_options returns, to avoid the
+ # quote stripping which shlex.split performs on it.
+ _,cmd = parameter_s.split('=',1)
+ except ValueError:
+ var,cmd = '',''
+ # If all looks ok, proceed
+ out,err = self.shell.getoutputerror(cmd)
+ if err:
+ print >> Term.cerr,err
+ if opts.has_key('l'):
+ out = SList(out.split('\n'))
+ else:
+ out = LSString(out)
+ if opts.has_key('v'):
+ print '%s ==\n%s' % (var,pformat(out))
+ if var:
+ self.shell.user_ns.update({var:out})
+ else:
+ return out
+
+ def magic_sx(self, parameter_s=''):
+ """Shell execute - run a shell command and capture its output.
+
+ %sx command
+
+ IPython will run the given command using commands.getoutput(), and
+ return the result formatted as a list (split on '\\n'). Since the
+ output is _returned_, it will be stored in ipython's regular output
+ cache Out[N] and in the '_N' automatic variables.
+
+ Notes:
+
+ 1) If an input line begins with '!!', then %sx is automatically
+ invoked. That is, while:
+ !ls
+ causes ipython to simply issue system('ls'), typing
+ !!ls
+ is a shorthand equivalent to:
+ %sx ls
+
+ 2) %sx differs from %sc in that %sx automatically splits into a list,
+ like '%sc -l'. The reason for this is to make it as easy as possible
+ to process line-oriented shell output via further python commands.
+ %sc is meant to provide much finer control, but requires more
+ typing.
+
+ 3) Just like %sc -l, this is a list with special attributes:
+
+ .l (or .list) : value as list.
+ .n (or .nlstr): value as newline-separated string.
+ .s (or .spstr): value as whitespace-separated string.
+
+ This is very useful when trying to use such lists as arguments to
+ system commands."""
+
+ if parameter_s:
+ out,err = self.shell.getoutputerror(parameter_s)
+ if err:
+ print >> Term.cerr,err
+ return SList(out.split('\n'))
+
+ def magic_bg(self, parameter_s=''):
+ """Run a job in the background, in a separate thread.
+
+ For example,
+
+ %bg myfunc(x,y,z=1)
+
+ will execute 'myfunc(x,y,z=1)' in a background thread. As soon as the
+ execution starts, a message will be printed indicating the job
+ number. If your job number is 5, you can use
+
+ myvar = jobs.result(5) or myvar = jobs[5].result
+
+ to assign this result to variable 'myvar'.
+
+ IPython has a job manager, accessible via the 'jobs' object. You can
+ type jobs? to get more information about it, and use jobs.<TAB> to see
+ its attributes. All attributes not starting with an underscore are
+ meant for public use.
+
+ In particular, look at the jobs.new() method, which is used to create
+ new jobs. This magic %bg function is just a convenience wrapper
+ around jobs.new(), for expression-based jobs. If you want to create a
+ new job with an explicit function object and arguments, you must call
+ jobs.new() directly.
+
+ The jobs.new docstring also describes in detail several important
+ caveats associated with a thread-based model for background job
+ execution. Type jobs.new? for details.
+
+ You can check the status of all jobs with jobs.status().
+
+ The jobs variable is set by IPython into the Python builtin namespace.
+ If you ever declare a variable named 'jobs', you will shadow this
+ name. You can either delete your global jobs variable to regain
+ access to the job manager, or make a new name and assign it manually
+ to the manager (stored in IPython's namespace). For example, to
+ assign the job manager to the Jobs name, use:
+
+ Jobs = __builtins__.jobs"""
+
+ self.shell.jobs.new(parameter_s,self.shell.user_ns)
+
+ def magic_r(self, parameter_s=''):
+ """Repeat previous input.
+
+ Note: Consider using the more powerfull %rep instead!
+
+ If given an argument, repeats the previous command which starts with
+ the same string, otherwise it just repeats the previous input.
+
+ Shell escaped commands (with ! as first character) are not recognized
+ by this system, only pure python code and magic commands.
+ """
+
+ start = parameter_s.strip()
+ esc_magic = self.shell.ESC_MAGIC
+ # Identify magic commands even if automagic is on (which means
+ # the in-memory version is different from that typed by the user).
+ if self.shell.rc.automagic:
+ start_magic = esc_magic+start
+ else:
+ start_magic = start
+ # Look through the input history in reverse
+ for n in range(len(self.shell.input_hist)-2,0,-1):
+ input = self.shell.input_hist[n]
+ # skip plain 'r' lines so we don't recurse to infinity
+ if input != '_ip.magic("r")\n' and \
+ (input.startswith(start) or input.startswith(start_magic)):
+ #print 'match',`input` # dbg
+ print 'Executing:',input,
+ self.shell.runlines(input)
+ return
+ print 'No previous input matching `%s` found.' % start
+
+
+ def magic_bookmark(self, parameter_s=''):
+ """Manage IPython's bookmark system.
+
+ %bookmark <name> - set bookmark to current dir
+ %bookmark <name> <dir> - set bookmark to <dir>
+ %bookmark -l - list all bookmarks
+ %bookmark -d <name> - remove bookmark
+ %bookmark -r - remove all bookmarks
+
+ You can later on access a bookmarked folder with:
+ %cd -b <name>
+ or simply '%cd <name>' if there is no directory called <name> AND
+ there is such a bookmark defined.
+
+ Your bookmarks persist through IPython sessions, but they are
+ associated with each profile."""
+
+ opts,args = self.parse_options(parameter_s,'drl',mode='list')
+ if len(args) > 2:
+ raise UsageError("%bookmark: too many arguments")
+
+ bkms = self.db.get('bookmarks',{})
+
+ if opts.has_key('d'):
+ try:
+ todel = args[0]
+ except IndexError:
+ raise UsageError(
+ "%bookmark -d: must provide a bookmark to delete")
+ else:
+ try:
+ del bkms[todel]
+ except KeyError:
+ raise UsageError(
+ "%%bookmark -d: Can't delete bookmark '%s'" % todel)
+
+ elif opts.has_key('r'):
+ bkms = {}
+ elif opts.has_key('l'):
+ bks = bkms.keys()
+ bks.sort()
+ if bks:
+ size = max(map(len,bks))
+ else:
+ size = 0
+ fmt = '%-'+str(size)+'s -> %s'
+ print 'Current bookmarks:'
+ for bk in bks:
+ print fmt % (bk,bkms[bk])
+ else:
+ if not args:
+ raise UsageError("%bookmark: You must specify the bookmark name")
+ elif len(args)==1:
+ bkms[args[0]] = os.getcwd()
+ elif len(args)==2:
+ bkms[args[0]] = args[1]
+ self.db['bookmarks'] = bkms
+
+ def magic_pycat(self, parameter_s=''):
+ """Show a syntax-highlighted file through a pager.
+
+ This magic is similar to the cat utility, but it will assume the file
+ to be Python source and will show it with syntax highlighting. """
+
+ try:
+ filename = get_py_filename(parameter_s)
+ cont = file_read(filename)
+ except IOError:
+ try:
+ cont = eval(parameter_s,self.user_ns)
+ except NameError:
+ cont = None
+ if cont is None:
+ print "Error: no such file or variable"
+ return
+
+ page(self.shell.pycolorize(cont),
+ screen_lines=self.shell.rc.screen_length)
+
+ def _rerun_pasted(self):
+ """ Rerun a previously pasted command.
+ """
+ b = self.user_ns.get('pasted_block', None)
+ if b is None:
+ raise UsageError('No previous pasted block available')
+ print "Re-executing '%s...' (%d chars)"% (b.split('\n',1)[0], len(b))
+ exec b in self.user_ns
+
+ def _get_pasted_lines(self, sentinel):
+ """ Yield pasted lines until the user enters the given sentinel value.
+ """
+ from IPython import iplib
+ print "Pasting code; enter '%s' alone on the line to stop." % sentinel
+ while True:
+ l = iplib.raw_input_original(':')
+ if l == sentinel:
+ return
+ else:
+ yield l
+
+ def _strip_pasted_lines_for_code(self, raw_lines):
+ """ Strip non-code parts of a sequence of lines to return a block of
+ code.
+ """
+ # Regular expressions that declare text we strip from the input:
+ strip_re = [r'^\s*In \[\d+\]:', # IPython input prompt
+ r'^\s*(\s?>)+', # Python input prompt
+ r'^\s*\.{3,}', # Continuation prompts
+ r'^\++',
+ ]
+
+ strip_from_start = map(re.compile,strip_re)
+
+ lines = []
+ for l in raw_lines:
+ for pat in strip_from_start:
+ l = pat.sub('',l)
+ lines.append(l)
+
+ block = "\n".join(lines) + '\n'
+ #print "block:\n",block
+ return block
+
+ def _execute_block(self, block, par):
+ """ Execute a block, or store it in a variable, per the user's request.
+ """
+ if not par:
+ b = textwrap.dedent(block)
+ self.user_ns['pasted_block'] = b
+ exec b in self.user_ns
+ else:
+ self.user_ns[par] = SList(block.splitlines())
+ print "Block assigned to '%s'" % par
+
+ def magic_cpaste(self, parameter_s=''):
+ """Allows you to paste & execute a pre-formatted code block from clipboard.
+
+ You must terminate the block with '--' (two minus-signs) alone on the
+ line. You can also provide your own sentinel with '%paste -s %%' ('%%'
+ is the new sentinel for this operation)
+
+ The block is dedented prior to execution to enable execution of method
+ definitions. '>' and '+' characters at the beginning of a line are
+ ignored, to allow pasting directly from e-mails, diff files and
+ doctests (the '...' continuation prompt is also stripped). The
+ executed block is also assigned to variable named 'pasted_block' for
+ later editing with '%edit pasted_block'.
+
+ You can also pass a variable name as an argument, e.g. '%cpaste foo'.
+ This assigns the pasted block to variable 'foo' as string, without
+ dedenting or executing it (preceding >>> and + is still stripped)
+
+ '%cpaste -r' re-executes the block previously entered by cpaste.
+
+ Do not be alarmed by garbled output on Windows (it's a readline bug).
+ Just press enter and type -- (and press enter again) and the block
+ will be what was just pasted.
+
+ IPython statements (magics, shell escapes) are not supported (yet).
+
+ See also
+ --------
+ paste: automatically pull code from clipboard.
+ """
+
+ opts,args = self.parse_options(parameter_s,'rs:',mode='string')
+ par = args.strip()
+ if opts.has_key('r'):
+ self._rerun_pasted()
+ return
+
+ sentinel = opts.get('s','--')
+
+ block = self._strip_pasted_lines_for_code(
+ self._get_pasted_lines(sentinel))
+
+ self._execute_block(block, par)
+
+ def magic_paste(self, parameter_s=''):
+ """Allows you to paste & execute a pre-formatted code block from clipboard.
+
+ The text is pulled directly from the clipboard without user
+ intervention.
+
+ The block is dedented prior to execution to enable execution of method
+ definitions. '>' and '+' characters at the beginning of a line are
+ ignored, to allow pasting directly from e-mails, diff files and
+ doctests (the '...' continuation prompt is also stripped). The
+ executed block is also assigned to variable named 'pasted_block' for
+ later editing with '%edit pasted_block'.
+
+ You can also pass a variable name as an argument, e.g. '%paste foo'.
+ This assigns the pasted block to variable 'foo' as string, without
+ dedenting or executing it (preceding >>> and + is still stripped)
+
+ '%paste -r' re-executes the block previously entered by cpaste.
+
+ IPython statements (magics, shell escapes) are not supported (yet).
+
+ See also
+ --------
+ cpaste: manually paste code into terminal until you mark its end.
+ """
+ opts,args = self.parse_options(parameter_s,'r:',mode='string')
+ par = args.strip()
+ if opts.has_key('r'):
+ self._rerun_pasted()
+ return
+
+ text = self.shell.hooks.clipboard_get()
+ block = self._strip_pasted_lines_for_code(text.splitlines())
+ self._execute_block(block, par)
+
+ def magic_quickref(self,arg):
+ """ Show a quick reference sheet """
+ import IPython.usage
+ qr = IPython.usage.quick_reference + self.magic_magic('-brief')
+
+ page(qr)
+
+ def magic_upgrade(self,arg):
+ """ Upgrade your IPython installation
+
+ This will copy the config files that don't yet exist in your
+ ipython dir from the system config dir. Use this after upgrading
+ IPython if you don't wish to delete your .ipython dir.
+
+ Call with -nolegacy to get rid of ipythonrc* files (recommended for
+ new users)
+
+ """
+ ip = self.getapi()
+ ipinstallation = path(IPython.__file__).dirname()
+ upgrade_script = '%s "%s"' % (sys.executable,ipinstallation / 'upgrade_dir.py')
+ src_config = ipinstallation / 'UserConfig'
+ userdir = path(ip.options.ipythondir)
+ cmd = '%s "%s" "%s"' % (upgrade_script, src_config, userdir)
+ print ">",cmd
+ shell(cmd)
+ if arg == '-nolegacy':
+ legacy = userdir.files('ipythonrc*')
+ print "Nuking legacy files:",legacy
+
+ [p.remove() for p in legacy]
+ suffix = (sys.platform == 'win32' and '.ini' or '')
+ (userdir / ('ipythonrc' + suffix)).write_text('# Empty, see ipy_user_conf.py\n')
+
+
+ def magic_doctest_mode(self,parameter_s=''):
+ """Toggle doctest mode on and off.
+
+ This mode allows you to toggle the prompt behavior between normal
+ IPython prompts and ones that are as similar to the default IPython
+ interpreter as possible.
+
+ It also supports the pasting of code snippets that have leading '>>>'
+ and '...' prompts in them. This means that you can paste doctests from
+ files or docstrings (even if they have leading whitespace), and the
+ code will execute correctly. You can then use '%history -tn' to see
+ the translated history without line numbers; this will give you the
+ input after removal of all the leading prompts and whitespace, which
+ can be pasted back into an editor.
+
+ With these features, you can switch into this mode easily whenever you
+ need to do testing and changes to doctests, without having to leave
+ your existing IPython session.
+ """
+
+ # XXX - Fix this to have cleaner activate/deactivate calls.
+ from IPython.Extensions import InterpreterPasteInput as ipaste
+ from IPython.ipstruct import Struct
+
+ # Shorthands
+ shell = self.shell
+ oc = shell.outputcache
+ rc = shell.rc
+ meta = shell.meta
+ # dstore is a data store kept in the instance metadata bag to track any
+ # changes we make, so we can undo them later.
+ dstore = meta.setdefault('doctest_mode',Struct())
+ save_dstore = dstore.setdefault
+
+ # save a few values we'll need to recover later
+ mode = save_dstore('mode',False)
+ save_dstore('rc_pprint',rc.pprint)
+ save_dstore('xmode',shell.InteractiveTB.mode)
+ save_dstore('rc_separate_out',rc.separate_out)
+ save_dstore('rc_separate_out2',rc.separate_out2)
+ save_dstore('rc_prompts_pad_left',rc.prompts_pad_left)
+ save_dstore('rc_separate_in',rc.separate_in)
+
+ if mode == False:
+ # turn on
+ ipaste.activate_prefilter()
+
+ oc.prompt1.p_template = '>>> '
+ oc.prompt2.p_template = '... '
+ oc.prompt_out.p_template = ''
+
+ # Prompt separators like plain python
+ oc.input_sep = oc.prompt1.sep = ''
+ oc.output_sep = ''
+ oc.output_sep2 = ''
+
+ oc.prompt1.pad_left = oc.prompt2.pad_left = \
+ oc.prompt_out.pad_left = False
+
+ rc.pprint = False
+
+ shell.magic_xmode('Plain')
+
+ else:
+ # turn off
+ ipaste.deactivate_prefilter()
+
+ oc.prompt1.p_template = rc.prompt_in1
+ oc.prompt2.p_template = rc.prompt_in2
+ oc.prompt_out.p_template = rc.prompt_out
+
+ oc.input_sep = oc.prompt1.sep = dstore.rc_separate_in
+
+ oc.output_sep = dstore.rc_separate_out
+ oc.output_sep2 = dstore.rc_separate_out2
+
+ oc.prompt1.pad_left = oc.prompt2.pad_left = \
+ oc.prompt_out.pad_left = dstore.rc_prompts_pad_left
+
+ rc.pprint = dstore.rc_pprint
+
+ shell.magic_xmode(dstore.xmode)
+
+ # Store new mode and inform
+ dstore.mode = bool(1-int(mode))
+ print 'Doctest mode is:',
+ print ['OFF','ON'][dstore.mode]
+
+# end Magic
diff --git a/IPython/OInspect.py b/IPython/OInspect.py
new file mode 100644
index 0000000..ecef640
--- /dev/null
+++ b/IPython/OInspect.py
@@ -0,0 +1,607 @@
+# -*- coding: utf-8 -*-
+"""Tools for inspecting Python objects.
+
+Uses syntax highlighting for presenting the various information elements.
+
+Similar in spirit to the inspect module, but all calls take a name argument to
+reference the name under which an object is being read.
+"""
+
+#*****************************************************************************
+# Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#*****************************************************************************
+
+__all__ = ['Inspector','InspectColors']
+
+# stdlib modules
+import __builtin__
+import StringIO
+import inspect
+import linecache
+import os
+import string
+import sys
+import types
+
+# IPython's own
+from IPython import PyColorize
+from IPython.genutils import page,indent,Term
+from IPython.Itpl import itpl
+from IPython.wildcard import list_namespace
+from IPython.ColorANSI import *
+
+#****************************************************************************
+# HACK!!! This is a crude fix for bugs in python 2.3's inspect module. We
+# simply monkeypatch inspect with code copied from python 2.4.
+if sys.version_info[:2] == (2,3):
+ from inspect import ismodule, getabsfile, modulesbyfile
+ def getmodule(object):
+ """Return the module an object was defined in, or None if not found."""
+ if ismodule(object):
+ return object
+ if hasattr(object, '__module__'):
+ return sys.modules.get(object.__module__)
+ try:
+ file = getabsfile(object)
+ except TypeError:
+ return None
+ if file in modulesbyfile:
+ return sys.modules.get(modulesbyfile[file])
+ for module in sys.modules.values():
+ if hasattr(module, '__file__'):
+ modulesbyfile[
+ os.path.realpath(
+ getabsfile(module))] = module.__name__
+ if file in modulesbyfile:
+ return sys.modules.get(modulesbyfile[file])
+ main = sys.modules['__main__']
+ if not hasattr(object, '__name__'):
+ return None
+ if hasattr(main, object.__name__):
+ mainobject = getattr(main, object.__name__)
+ if mainobject is object:
+ return main
+ builtin = sys.modules['__builtin__']
+ if hasattr(builtin, object.__name__):
+ builtinobject = getattr(builtin, object.__name__)
+ if builtinobject is object:
+ return builtin
+
+ inspect.getmodule = getmodule
+
+#****************************************************************************
+# Builtin color schemes
+
+Colors = TermColors # just a shorthand
+
+# Build a few color schemes
+NoColor = ColorScheme(
+ 'NoColor',{
+ 'header' : Colors.NoColor,
+ 'normal' : Colors.NoColor # color off (usu. Colors.Normal)
+ } )
+
+LinuxColors = ColorScheme(
+ 'Linux',{
+ 'header' : Colors.LightRed,
+ 'normal' : Colors.Normal # color off (usu. Colors.Normal)
+ } )
+
+LightBGColors = ColorScheme(
+ 'LightBG',{
+ 'header' : Colors.Red,
+ 'normal' : Colors.Normal # color off (usu. Colors.Normal)
+ } )
+
+# Build table of color schemes (needed by the parser)
+InspectColors = ColorSchemeTable([NoColor,LinuxColors,LightBGColors],
+ 'Linux')
+
+#****************************************************************************
+# Auxiliary functions
+def getdoc(obj):
+ """Stable wrapper around inspect.getdoc.
+
+ This can't crash because of attribute problems.
+
+ It also attempts to call a getdoc() method on the given object. This
+ allows objects which provide their docstrings via non-standard mechanisms
+ (like Pyro proxies) to still be inspected by ipython's ? system."""
+
+ ds = None # default return value
+ try:
+ ds = inspect.getdoc(obj)
+ except:
+ # Harden against an inspect failure, which can occur with
+ # SWIG-wrapped extensions.
+ pass
+ # Allow objects to offer customized documentation via a getdoc method:
+ try:
+ ds2 = obj.getdoc()
+ except:
+ pass
+ else:
+ # if we get extra info, we add it to the normal docstring.
+ if ds is None:
+ ds = ds2
+ else:
+ ds = '%s\n%s' % (ds,ds2)
+ return ds
+
+
+def getsource(obj,is_binary=False):
+ """Wrapper around inspect.getsource.
+
+ This can be modified by other projects to provide customized source
+ extraction.
+
+ Inputs:
+
+ - obj: an object whose source code we will attempt to extract.
+
+ Optional inputs:
+
+ - is_binary: whether the object is known to come from a binary source.
+ This implementation will skip returning any output for binary objects, but
+ custom extractors may know how to meaningfully process them."""
+
+ if is_binary:
+ return None
+ else:
+ try:
+ src = inspect.getsource(obj)
+ except TypeError:
+ if hasattr(obj,'__class__'):
+ src = inspect.getsource(obj.__class__)
+ return src
+
+def getargspec(obj):
+ """Get the names and default values of a function's arguments.
+
+ A tuple of four things is returned: (args, varargs, varkw, defaults).
+ 'args' is a list of the argument names (it may contain nested lists).
+ 'varargs' and 'varkw' are the names of the * and ** arguments or None.
+ 'defaults' is an n-tuple of the default values of the last n arguments.
+
+ Modified version of inspect.getargspec from the Python Standard
+ Library."""
+
+ if inspect.isfunction(obj):
+ func_obj = obj
+ elif inspect.ismethod(obj):
+ func_obj = obj.im_func
+ else:
+ raise TypeError, 'arg is not a Python function'
+ args, varargs, varkw = inspect.getargs(func_obj.func_code)
+ return args, varargs, varkw, func_obj.func_defaults
+
+#****************************************************************************
+# Class definitions
+
+class myStringIO(StringIO.StringIO):
+ """Adds a writeln method to normal StringIO."""
+ def writeln(self,*arg,**kw):
+ """Does a write() and then a write('\n')"""
+ self.write(*arg,**kw)
+ self.write('\n')
+
+
+class Inspector:
+ def __init__(self,color_table,code_color_table,scheme,
+ str_detail_level=0):
+ self.color_table = color_table
+ self.parser = PyColorize.Parser(code_color_table,out='str')
+ self.format = self.parser.format
+ self.str_detail_level = str_detail_level
+ self.set_active_scheme(scheme)
+
+ def __getdef(self,obj,oname=''):
+ """Return the definition header for any callable object.
+
+ If any exception is generated, None is returned instead and the
+ exception is suppressed."""
+
+ try:
+ return oname + inspect.formatargspec(*getargspec(obj))
+ except:
+ return None
+
+ def __head(self,h):
+ """Return a header string with proper colors."""
+ return '%s%s%s' % (self.color_table.active_colors.header,h,
+ self.color_table.active_colors.normal)
+
+ def set_active_scheme(self,scheme):
+ self.color_table.set_active_scheme(scheme)
+ self.parser.color_table.set_active_scheme(scheme)
+
+ def noinfo(self,msg,oname):
+ """Generic message when no information is found."""
+ print 'No %s found' % msg,
+ if oname:
+ print 'for %s' % oname
+ else:
+ print
+
+ def pdef(self,obj,oname=''):
+ """Print the definition header for any callable object.
+
+ If the object is a class, print the constructor information."""
+
+ if not callable(obj):
+ print 'Object is not callable.'
+ return
+
+ header = ''
+
+ if inspect.isclass(obj):
+ header = self.__head('Class constructor information:\n')
+ obj = obj.__init__
+ elif type(obj) is types.InstanceType:
+ obj = obj.__call__
+
+ output = self.__getdef(obj,oname)
+ if output is None:
+ self.noinfo('definition header',oname)
+ else:
+ print >>Term.cout, header,self.format(output),
+
+ def pdoc(self,obj,oname='',formatter = None):
+ """Print the docstring for any object.
+
+ Optional:
+ -formatter: a function to run the docstring through for specially
+ formatted docstrings."""
+
+ head = self.__head # so that itpl can find it even if private
+ ds = getdoc(obj)
+ if formatter:
+ ds = formatter(ds)
+ if inspect.isclass(obj):
+ init_ds = getdoc(obj.__init__)
+ output = itpl('$head("Class Docstring:")\n'
+ '$indent(ds)\n'
+ '$head("Constructor Docstring"):\n'
+ '$indent(init_ds)')
+ elif (type(obj) is types.InstanceType or isinstance(obj,object)) \
+ and hasattr(obj,'__call__'):
+ call_ds = getdoc(obj.__call__)
+ if call_ds:
+ output = itpl('$head("Class Docstring:")\n$indent(ds)\n'
+ '$head("Calling Docstring:")\n$indent(call_ds)')
+ else:
+ output = ds
+ else:
+ output = ds
+ if output is None:
+ self.noinfo('documentation',oname)
+ return
+ page(output)
+
+ def psource(self,obj,oname=''):
+ """Print the source code for an object."""
+
+ # Flush the source cache because inspect can return out-of-date source
+ linecache.checkcache()
+ try:
+ src = getsource(obj)
+ except:
+ self.noinfo('source',oname)
+ else:
+ page(self.format(src))
+
+ def pfile(self,obj,oname=''):
+ """Show the whole file where an object was defined."""
+
+ try:
+ try:
+ lineno = inspect.getsourcelines(obj)[1]
+ except TypeError:
+ # For instances, try the class object like getsource() does
+ if hasattr(obj,'__class__'):
+ lineno = inspect.getsourcelines(obj.__class__)[1]
+ # Adjust the inspected object so getabsfile() below works
+ obj = obj.__class__
+ except:
+ self.noinfo('file',oname)
+ return
+
+ # We only reach this point if object was successfully queried
+
+ # run contents of file through pager starting at line
+ # where the object is defined
+ ofile = inspect.getabsfile(obj)
+
+ if (ofile.endswith('.so') or ofile.endswith('.dll')):
+ print 'File %r is binary, not printing.' % ofile
+ elif not os.path.isfile(ofile):
+ print 'File %r does not exist, not printing.' % ofile
+ else:
+ # Print only text files, not extension binaries. Note that
+ # getsourcelines returns lineno with 1-offset and page() uses
+ # 0-offset, so we must adjust.
+ page(self.format(open(ofile).read()),lineno-1)
+
+ def pinfo(self,obj,oname='',formatter=None,info=None,detail_level=0):
+ """Show detailed information about an object.
+
+ Optional arguments:
+
+ - oname: name of the variable pointing to the object.
+
+ - formatter: special formatter for docstrings (see pdoc)
+
+ - info: a structure with some information fields which may have been
+ precomputed already.
+
+ - detail_level: if set to 1, more information is given.
+ """
+
+ obj_type = type(obj)
+
+ header = self.__head
+ if info is None:
+ ismagic = 0
+ isalias = 0
+ ospace = ''
+ else:
+ ismagic = info.ismagic
+ isalias = info.isalias
+ ospace = info.namespace
+ # Get docstring, special-casing aliases:
+ if isalias:
+ if not callable(obj):
+ try:
+ ds = "Alias to the system command:\n %s" % obj[1]
+ except:
+ ds = "Alias: " + str(obj)
+ else:
+ ds = "Alias to " + str(obj)
+ if obj.__doc__:
+ ds += "\nDocstring:\n" + obj.__doc__
+ else:
+ ds = getdoc(obj)
+ if ds is None:
+ ds = '<no docstring>'
+ if formatter is not None:
+ ds = formatter(ds)
+
+ # store output in a list which gets joined with \n at the end.
+ out = myStringIO()
+
+ string_max = 200 # max size of strings to show (snipped if longer)
+ shalf = int((string_max -5)/2)
+
+ if ismagic:
+ obj_type_name = 'Magic function'
+ elif isalias:
+ obj_type_name = 'System alias'
+ else:
+ obj_type_name = obj_type.__name__
+ out.writeln(header('Type:\t\t')+obj_type_name)
+
+ try:
+ bclass = obj.__class__
+ out.writeln(header('Base Class:\t')+str(bclass))
+ except: pass
+
+ # String form, but snip if too long in ? form (full in ??)
+ if detail_level >= self.str_detail_level:
+ try:
+ ostr = str(obj)
+ str_head = 'String Form:'
+ if not detail_level and len(ostr)>string_max:
+ ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:]
+ ostr = ("\n" + " " * len(str_head.expandtabs())).\
+ join(map(string.strip,ostr.split("\n")))
+ if ostr.find('\n') > -1:
+ # Print multi-line strings starting at the next line.
+ str_sep = '\n'
+ else:
+ str_sep = '\t'
+ out.writeln("%s%s%s" % (header(str_head),str_sep,ostr))
+ except:
+ pass
+
+ if ospace:
+ out.writeln(header('Namespace:\t')+ospace)
+
+ # Length (for strings and lists)
+ try:
+ length = str(len(obj))
+ out.writeln(header('Length:\t\t')+length)
+ except: pass
+
+ # Filename where object was defined
+ binary_file = False
+ try:
+ try:
+ fname = inspect.getabsfile(obj)
+ except TypeError:
+ # For an instance, the file that matters is where its class was
+ # declared.
+ if hasattr(obj,'__class__'):
+ fname = inspect.getabsfile(obj.__class__)
+ if fname.endswith('<string>'):
+ fname = 'Dynamically generated function. No source code available.'
+ if (fname.endswith('.so') or fname.endswith('.dll')):
+ binary_file = True
+ out.writeln(header('File:\t\t')+fname)
+ except:
+ # if anything goes wrong, we don't want to show source, so it's as
+ # if the file was binary
+ binary_file = True
+
+ # reconstruct the function definition and print it:
+ defln = self.__getdef(obj,oname)
+ if defln:
+ out.write(header('Definition:\t')+self.format(defln))
+
+ # Docstrings only in detail 0 mode, since source contains them (we
+ # avoid repetitions). If source fails, we add them back, see below.
+ if ds and detail_level == 0:
+ out.writeln(header('Docstring:\n') + indent(ds))
+
+ # Original source code for any callable
+ if detail_level:
+ # Flush the source cache because inspect can return out-of-date
+ # source
+ linecache.checkcache()
+ source_success = False
+ try:
+ try:
+ src = getsource(obj,binary_file)
+ except TypeError:
+ if hasattr(obj,'__class__'):
+ src = getsource(obj.__class__,binary_file)
+ if src is not None:
+ source = self.format(src)
+ out.write(header('Source:\n')+source.rstrip())
+ source_success = True
+ except Exception, msg:
+ pass
+
+ if ds and not source_success:
+ out.writeln(header('Docstring [source file open failed]:\n')
+ + indent(ds))
+
+ # Constructor docstring for classes
+ if inspect.isclass(obj):
+ # reconstruct the function definition and print it:
+ try:
+ obj_init = obj.__init__
+ except AttributeError:
+ init_def = init_ds = None
+ else:
+ init_def = self.__getdef(obj_init,oname)
+ init_ds = getdoc(obj_init)
+ # Skip Python's auto-generated docstrings
+ if init_ds and \
+ init_ds.startswith('x.__init__(...) initializes'):
+ init_ds = None
+
+ if init_def or init_ds:
+ out.writeln(header('\nConstructor information:'))
+ if init_def:
+ out.write(header('Definition:\t')+ self.format(init_def))
+ if init_ds:
+ out.writeln(header('Docstring:\n') + indent(init_ds))
+ # and class docstring for instances:
+ elif obj_type is types.InstanceType or \
+ isinstance(obj,object):
+
+ # First, check whether the instance docstring is identical to the
+ # class one, and print it separately if they don't coincide. In
+ # most cases they will, but it's nice to print all the info for
+ # objects which use instance-customized docstrings.
+ if ds:
+ try:
+ cls = getattr(obj,'__class__')
+ except:
+ class_ds = None
+ else:
+ class_ds = getdoc(cls)
+ # Skip Python's auto-generated docstrings
+ if class_ds and \
+ (class_ds.startswith('function(code, globals[,') or \
+ class_ds.startswith('instancemethod(function, instance,') or \
+ class_ds.startswith('module(name[,') ):
+ class_ds = None
+ if class_ds and ds != class_ds:
+ out.writeln(header('Class Docstring:\n') +
+ indent(class_ds))
+
+ # Next, try to show constructor docstrings
+ try:
+ init_ds = getdoc(obj.__init__)
+ # Skip Python's auto-generated docstrings
+ if init_ds and \
+ init_ds.startswith('x.__init__(...) initializes'):
+ init_ds = None
+ except AttributeError:
+ init_ds = None
+ if init_ds:
+ out.writeln(header('Constructor Docstring:\n') +
+ indent(init_ds))
+
+ # Call form docstring for callable instances
+ if hasattr(obj,'__call__'):
+ #out.writeln(header('Callable:\t')+'Yes')
+ call_def = self.__getdef(obj.__call__,oname)
+ #if call_def is None:
+ # out.writeln(header('Call def:\t')+
+ # 'Calling definition not available.')
+ if call_def is not None:
+ out.writeln(header('Call def:\t')+self.format(call_def))
+ call_ds = getdoc(obj.__call__)
+ # Skip Python's auto-generated docstrings
+ if call_ds and call_ds.startswith('x.__call__(...) <==> x(...)'):
+ call_ds = None
+ if call_ds:
+ out.writeln(header('Call docstring:\n') + indent(call_ds))
+
+ # Finally send to printer/pager
+ output = out.getvalue()
+ if output:
+ page(output)
+ # end pinfo
+
+ def psearch(self,pattern,ns_table,ns_search=[],
+ ignore_case=False,show_all=False):
+ """Search namespaces with wildcards for objects.
+
+ Arguments:
+
+ - pattern: string containing shell-like wildcards to use in namespace
+ searches and optionally a type specification to narrow the search to
+ objects of that type.
+
+ - ns_table: dict of name->namespaces for search.
+
+ Optional arguments:
+
+ - ns_search: list of namespace names to include in search.
+
+ - ignore_case(False): make the search case-insensitive.
+
+ - show_all(False): show all names, including those starting with
+ underscores.
+ """
+ #print 'ps pattern:<%r>' % pattern # dbg
+
+ # defaults
+ type_pattern = 'all'
+ filter = ''
+
+ cmds = pattern.split()
+ len_cmds = len(cmds)
+ if len_cmds == 1:
+ # Only filter pattern given
+ filter = cmds[0]
+ elif len_cmds == 2:
+ # Both filter and type specified
+ filter,type_pattern = cmds
+ else:
+ raise ValueError('invalid argument string for psearch: <%s>' %
+ pattern)
+
+ # filter search namespaces
+ for name in ns_search:
+ if name not in ns_table:
+ raise ValueError('invalid namespace <%s>. Valid names: %s' %
+ (name,ns_table.keys()))
+
+ #print 'type_pattern:',type_pattern # dbg
+ search_result = []
+ for ns_name in ns_search:
+ ns = ns_table[ns_name]
+ tmp_res = list(list_namespace(ns,type_pattern,filter,
+ ignore_case=ignore_case,
+ show_all=show_all))
+ search_result.extend(tmp_res)
+ search_result.sort()
+
+ page('\n'.join(search_result))
diff --git a/IPython/OutputTrap.py b/IPython/OutputTrap.py
new file mode 100644
index 0000000..c63c798
--- /dev/null
+++ b/IPython/OutputTrap.py
@@ -0,0 +1,258 @@
+# -*- coding: utf-8 -*-
+"""Class to trap stdout and stderr and log them separately.
+"""
+
+#*****************************************************************************
+# Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#*****************************************************************************
+
+import exceptions
+import sys
+from cStringIO import StringIO
+
+class OutputTrapError(exceptions.Exception):
+ """Exception for OutputTrap class."""
+
+ def __init__(self,args=None):
+ exceptions.Exception.__init__(self)
+ self.args = args
+
+class OutputTrap:
+
+ """Class to trap standard output and standard error. They get logged in
+ StringIO objects which are available as <instance>.out and
+ <instance>.err. The class also offers summary methods which format this
+ data a bit.
+
+ A word of caution: because it blocks messages, using this class can make
+ debugging very tricky. If you are having bizarre problems silently, try
+ turning your output traps off for a while. You can call the constructor
+ with the parameter debug=1 for these cases. This turns actual trapping
+ off, but you can keep the rest of your code unchanged (this has already
+ been a life saver).
+
+ Example:
+
+ # config: trapper with a line of dots as log separator (final '\\n' needed)
+ config = OutputTrap('Config','Out ','Err ','.'*80+'\\n')
+
+ # start trapping output
+ config.trap_all()
+
+ # now all output is logged ...
+ # do stuff...
+
+ # output back to normal:
+ config.release_all()
+
+ # print all that got logged:
+ print config.summary()
+
+ # print individual raw data:
+ print config.out.getvalue()
+ print config.err.getvalue()
+ """
+
+ def __init__(self,name='Generic Output Trap',
+ out_head='Standard Output. ',err_head='Standard Error. ',
+ sum_sep='\n',debug=0,trap_out=0,trap_err=0,
+ quiet_out=0,quiet_err=0):
+ self.name = name
+ self.out_head = out_head
+ self.err_head = err_head
+ self.sum_sep = sum_sep
+ self.out = StringIO()
+ self.err = StringIO()
+ self.out_save = None
+ self.err_save = None
+ self.debug = debug
+ self.quiet_out = quiet_out
+ self.quiet_err = quiet_err
+ if trap_out:
+ self.trap_out()
+ if trap_err:
+ self.trap_err()
+
+ def trap_out(self):
+ """Trap and log stdout."""
+ if sys.stdout is self.out:
+ raise OutputTrapError,'You are already trapping stdout.'
+ if not self.debug:
+ self._out_save = sys.stdout
+ sys.stdout = self.out
+
+ def release_out(self):
+ """Release stdout."""
+ if not self.debug:
+ if not sys.stdout is self.out:
+ raise OutputTrapError,'You are not trapping stdout.'
+ sys.stdout = self._out_save
+ self.out_save = None
+
+ def summary_out(self):
+ """Return as a string the log from stdout."""
+ out = self.out.getvalue()
+ if out:
+ if self.quiet_out:
+ return out
+ else:
+ return self.out_head + 'Log by '+ self.name + ':\n' + out
+ else:
+ return ''
+
+ def flush_out(self):
+ """Flush the stdout log. All data held in the log is lost."""
+
+ self.out.close()
+ self.out = StringIO()
+
+ def trap_err(self):
+ """Trap and log stderr."""
+ if sys.stderr is self.err:
+ raise OutputTrapError,'You are already trapping stderr.'
+ if not self.debug:
+ self._err_save = sys.stderr
+ sys.stderr = self.err
+
+ def release_err(self):
+ """Release stderr."""
+ if not self.debug:
+ if not sys.stderr is self.err:
+ raise OutputTrapError,'You are not trapping stderr.'
+ sys.stderr = self._err_save
+ self.err_save = None
+
+ def summary_err(self):
+ """Return as a string the log from stderr."""
+ err = self.err.getvalue()
+ if err:
+ if self.quiet_err:
+ return err
+ else:
+ return self.err_head + 'Log by '+ self.name + ':\n' + err
+ else:
+ return ''
+
+ def flush_err(self):
+ """Flush the stdout log. All data held in the log is lost."""
+
+ self.err.close()
+ self.err = StringIO()
+
+ def trap_all(self):
+ """Trap and log both stdout and stderr.
+
+ Cacthes and discards OutputTrapError exceptions raised."""
+ try:
+ self.trap_out()
+ except OutputTrapError:
+ pass
+ try:
+ self.trap_err()
+ except OutputTrapError:
+ pass
+
+ def release_all(self):
+ """Release both stdout and stderr.
+
+ Cacthes and discards OutputTrapError exceptions raised."""
+ try:
+ self.release_out()
+ except OutputTrapError:
+ pass
+ try:
+ self.release_err()
+ except OutputTrapError:
+ pass
+
+ def summary_all(self):
+ """Return as a string the log from stdout and stderr, prepending a separator
+ to each (defined in __init__ as sum_sep)."""
+ sum = ''
+ sout = self.summary_out()
+ if sout:
+ sum += self.sum_sep + sout
+ serr = self.summary_err()
+ if serr:
+ sum += '\n'+self.sum_sep + serr
+ return sum
+
+ def flush_all(self):
+ """Flush stdout and stderr"""
+ self.flush_out()
+ self.flush_err()
+
+ # a few shorthands
+ trap = trap_all
+ release = release_all
+ summary = summary_all
+ flush = flush_all
+# end OutputTrap
+
+
+#****************************************************************************
+# Module testing. Incomplete, I'm lazy...
+
+def _test_all():
+
+ """Module testing functions, activated when the module is called as a
+ script (not imported)."""
+
+ # Put tests for this module in here.
+ # Define them as nested functions so they don't clobber the
+ # pydoc-generated docs
+
+ def _test_():
+ name = ''
+ print '#'*50+'\nRunning test for ' + name
+ # ...
+ print 'Finished test for '+ name +'\n'+'#'*50
+
+ def _test_OutputTrap():
+ trap = OutputTrap(name = 'Test Trap', sum_sep = '.'*50+'\n',
+ out_head = 'SOut. ', err_head = 'SErr. ')
+
+ name = 'OutputTrap class'
+ print '#'*50+'\nRunning test for ' + name
+ print 'Trapping out'
+ trap.trap_out()
+ print >>sys.stdout, '>>stdout. stdout is trapped.'
+ print >>sys.stderr, '>>stderr. stdout is trapped.'
+ trap.release_out()
+ print trap.summary_out()
+
+ print 'Trapping err'
+ trap.trap_err()
+ print >>sys.stdout, '>>stdout. stderr is trapped.'
+ print >>sys.stderr, '>>stderr. stderr is trapped.'
+ trap.release_err()
+ print trap.summary_err()
+
+ print 'Trapping all (no flushing)'
+ trap.trap_all()
+ print >>sys.stdout, '>>stdout. stdout/err is trapped.'
+ print >>sys.stderr, '>>stderr. stdout/err is trapped.'
+ trap.release_all()
+ print trap.summary_all()
+
+ print 'Trapping all (flushing first)'
+ trap.flush()
+ trap.trap_all()
+ print >>sys.stdout, '>>stdout. stdout/err is trapped.'
+ print >>sys.stderr, '>>stderr. stdout/err is trapped.'
+ trap.release_all()
+ print trap.summary_all()
+ print 'Finished test for '+ name +'\n'+'#'*50
+
+ # call the actual tests here:
+ _test_OutputTrap()
+
+
+if __name__=="__main__":
+ # _test_all() # XXX BROKEN.
+ pass
+
+#************************ end of file <OutputTrap.py> ************************
diff --git a/IPython/Prompts.py b/IPython/Prompts.py
new file mode 100644
index 0000000..21f1086
--- /dev/null
+++ b/IPython/Prompts.py
@@ -0,0 +1,626 @@
+# -*- coding: utf-8 -*-
+"""
+Classes for handling input/output prompts.
+"""
+
+#*****************************************************************************
+# Copyright (C) 2008-2009 The IPython Development Team
+# Copyright (C) 2001-2007 Fernando Perez <fperez@colorado.edu>
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#*****************************************************************************
+
+#****************************************************************************
+# Required modules
+import __builtin__
+import os
+import socket
+import sys
+import time
+
+# IPython's own
+from IPython import ColorANSI
+from IPython import Release
+from IPython.external.Itpl import ItplNS
+from IPython.ipapi import TryNext
+from IPython.ipstruct import Struct
+from IPython.macro import Macro
+
+from IPython.genutils import *
+
+#****************************************************************************
+#Color schemes for Prompts.
+
+PromptColors = ColorANSI.ColorSchemeTable()
+InputColors = ColorANSI.InputTermColors # just a shorthand
+Colors = ColorANSI.TermColors # just a shorthand
+
+PromptColors.add_scheme(ColorANSI.ColorScheme(
+ 'NoColor',
+ in_prompt = InputColors.NoColor, # Input prompt
+ in_number = InputColors.NoColor, # Input prompt number
+ in_prompt2 = InputColors.NoColor, # Continuation prompt
+ in_normal = InputColors.NoColor, # color off (usu. Colors.Normal)
+
+ out_prompt = Colors.NoColor, # Output prompt
+ out_number = Colors.NoColor, # Output prompt number
+
+ normal = Colors.NoColor # color off (usu. Colors.Normal)
+ ))
+
+# make some schemes as instances so we can copy them for modification easily:
+__PColLinux = ColorANSI.ColorScheme(
+ 'Linux',
+ in_prompt = InputColors.Green,
+ in_number = InputColors.LightGreen,
+ in_prompt2 = InputColors.Green,
+ in_normal = InputColors.Normal, # color off (usu. Colors.Normal)
+
+ out_prompt = Colors.Red,
+ out_number = Colors.LightRed,
+
+ normal = Colors.Normal
+ )
+# Don't forget to enter it into the table!
+PromptColors.add_scheme(__PColLinux)
+
+# Slightly modified Linux for light backgrounds
+__PColLightBG = __PColLinux.copy('LightBG')
+
+__PColLightBG.colors.update(
+ in_prompt = InputColors.Blue,
+ in_number = InputColors.LightBlue,
+ in_prompt2 = InputColors.Blue
+)
+PromptColors.add_scheme(__PColLightBG)
+
+del Colors,InputColors
+
+#-----------------------------------------------------------------------------
+def multiple_replace(dict, text):
+ """ Replace in 'text' all occurences of any key in the given
+ dictionary by its corresponding value. Returns the new string."""
+
+ # Function by Xavier Defrang, originally found at:
+ # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/81330
+
+ # Create a regular expression from the dictionary keys
+ regex = re.compile("(%s)" % "|".join(map(re.escape, dict.keys())))
+ # For each match, look-up corresponding value in dictionary
+ return regex.sub(lambda mo: dict[mo.string[mo.start():mo.end()]], text)
+
+#-----------------------------------------------------------------------------
+# Special characters that can be used in prompt templates, mainly bash-like
+
+# If $HOME isn't defined (Windows), make it an absurd string so that it can
+# never be expanded out into '~'. Basically anything which can never be a
+# reasonable directory name will do, we just want the $HOME -> '~' operation
+# to become a no-op. We pre-compute $HOME here so it's not done on every
+# prompt call.
+
+# FIXME:
+
+# - This should be turned into a class which does proper namespace management,
+# since the prompt specials need to be evaluated in a certain namespace.
+# Currently it's just globals, which need to be managed manually by code
+# below.
+
+# - I also need to split up the color schemes from the prompt specials
+# somehow. I don't have a clean design for that quite yet.
+
+HOME = os.environ.get("HOME","//////:::::ZZZZZ,,,~~~")
+
+# We precompute a few more strings here for the prompt_specials, which are
+# fixed once ipython starts. This reduces the runtime overhead of computing
+# prompt strings.
+USER = os.environ.get("USER")
+HOSTNAME = socket.gethostname()
+HOSTNAME_SHORT = HOSTNAME.split(".")[0]
+ROOT_SYMBOL = "$#"[os.name=='nt' or os.getuid()==0]
+
+prompt_specials_color = {
+ # Prompt/history count
+ '%n' : '${self.col_num}' '${self.cache.prompt_count}' '${self.col_p}',
+ r'\#': '${self.col_num}' '${self.cache.prompt_count}' '${self.col_p}',
+ # Just the prompt counter number, WITHOUT any coloring wrappers, so users
+ # can get numbers displayed in whatever color they want.
+ r'\N': '${self.cache.prompt_count}',
+
+ # Prompt/history count, with the actual digits replaced by dots. Used
+ # mainly in continuation prompts (prompt_in2)
+ #r'\D': '${"."*len(str(self.cache.prompt_count))}',
+ # More robust form of the above expression, that uses __builtins__
+ r'\D': '${"."*__builtins__.len(__builtins__.str(self.cache.prompt_count))}',
+
+ # Current working directory
+ r'\w': '${os.getcwd()}',
+ # Current time
+ r'\t' : '${time.strftime("%H:%M:%S")}',
+ # Basename of current working directory.
+ # (use os.sep to make this portable across OSes)
+ r'\W' : '${os.getcwd().split("%s")[-1]}' % os.sep,
+ # These X<N> are an extension to the normal bash prompts. They return
+ # N terms of the path, after replacing $HOME with '~'
+ r'\X0': '${os.getcwd().replace("%s","~")}' % HOME,
+ r'\X1': '${self.cwd_filt(1)}',
+ r'\X2': '${self.cwd_filt(2)}',
+ r'\X3': '${self.cwd_filt(3)}',
+ r'\X4': '${self.cwd_filt(4)}',
+ r'\X5': '${self.cwd_filt(5)}',
+ # Y<N> are similar to X<N>, but they show '~' if it's the directory
+ # N+1 in the list. Somewhat like %cN in tcsh.
+ r'\Y0': '${self.cwd_filt2(0)}',
+ r'\Y1': '${self.cwd_filt2(1)}',
+ r'\Y2': '${self.cwd_filt2(2)}',
+ r'\Y3': '${self.cwd_filt2(3)}',
+ r'\Y4': '${self.cwd_filt2(4)}',
+ r'\Y5': '${self.cwd_filt2(5)}',
+ # Hostname up to first .
+ r'\h': HOSTNAME_SHORT,
+ # Full hostname
+ r'\H': HOSTNAME,
+ # Username of current user
+ r'\u': USER,
+ # Escaped '\'
+ '\\\\': '\\',
+ # Newline
+ r'\n': '\n',
+ # Carriage return
+ r'\r': '\r',
+ # Release version
+ r'\v': Release.version,
+ # Root symbol ($ or #)
+ r'\$': ROOT_SYMBOL,
+ }
+
+# A copy of the prompt_specials dictionary but with all color escapes removed,
+# so we can correctly compute the prompt length for the auto_rewrite method.
+prompt_specials_nocolor = prompt_specials_color.copy()
+prompt_specials_nocolor['%n'] = '${self.cache.prompt_count}'
+prompt_specials_nocolor[r'\#'] = '${self.cache.prompt_count}'
+
+# Add in all the InputTermColors color escapes as valid prompt characters.
+# They all get added as \\C_COLORNAME, so that we don't have any conflicts
+# with a color name which may begin with a letter used by any other of the
+# allowed specials. This of course means that \\C will never be allowed for
+# anything else.
+input_colors = ColorANSI.InputTermColors
+for _color in dir(input_colors):
+ if _color[0] != '_':
+ c_name = r'\C_'+_color
+ prompt_specials_color[c_name] = getattr(input_colors,_color)
+ prompt_specials_nocolor[c_name] = ''
+
+# we default to no color for safety. Note that prompt_specials is a global
+# variable used by all prompt objects.
+prompt_specials = prompt_specials_nocolor
+
+#-----------------------------------------------------------------------------
+def str_safe(arg):
+ """Convert to a string, without ever raising an exception.
+
+ If str(arg) fails, <ERROR: ... > is returned, where ... is the exception
+ error message."""
+
+ try:
+ out = str(arg)
+ except UnicodeError:
+ try:
+ out = arg.encode('utf_8','replace')
+ except Exception,msg:
+ # let's keep this little duplication here, so that the most common
+ # case doesn't suffer from a double try wrapping.
+ out = '<ERROR: %s>' % msg
+ except Exception,msg:
+ out = '<ERROR: %s>' % msg
+ return out
+
+class BasePrompt(object):
+ """Interactive prompt similar to Mathematica's."""
+
+ def _get_p_template(self):
+ return self._p_template
+
+ def _set_p_template(self,val):
+ self._p_template = val
+ self.set_p_str()
+
+ p_template = property(_get_p_template,_set_p_template,
+ doc='Template for prompt string creation')
+
+ def __init__(self,cache,sep,prompt,pad_left=False):
+
+ # Hack: we access information about the primary prompt through the
+ # cache argument. We need this, because we want the secondary prompt
+ # to be aligned with the primary one. Color table info is also shared
+ # by all prompt classes through the cache. Nice OO spaghetti code!
+ self.cache = cache
+ self.sep = sep
+
+ # regexp to count the number of spaces at the end of a prompt
+ # expression, useful for prompt auto-rewriting
+ self.rspace = re.compile(r'(\s*)$')
+ # Flag to left-pad prompt strings to match the length of the primary
+ # prompt
+ self.pad_left = pad_left
+
+ # Set template to create each actual prompt (where numbers change).
+ # Use a property
+ self.p_template = prompt
+ self.set_p_str()
+
+ def set_p_str(self):
+ """ Set the interpolating prompt strings.
+
+ This must be called every time the color settings change, because the
+ prompt_specials global may have changed."""
+
+ import os,time # needed in locals for prompt string handling
+ loc = locals()
+ try:
+ self.p_str = ItplNS('%s%s%s' %
+ ('${self.sep}${self.col_p}',
+ multiple_replace(prompt_specials, self.p_template),
+ '${self.col_norm}'),self.cache.user_ns,loc)
+
+ self.p_str_nocolor = ItplNS(multiple_replace(prompt_specials_nocolor,
+ self.p_template),
+ self.cache.user_ns,loc)
+ except:
+ print "Illegal prompt template (check $ usage!):",self.p_template
+ self.p_str = self.p_template
+ self.p_str_nocolor = self.p_template
+
+ def write(self,msg): # dbg
+ sys.stdout.write(msg)
+ return ''
+
+ def __str__(self):
+ """Return a string form of the prompt.
+
+ This for is useful for continuation and output prompts, since it is
+ left-padded to match lengths with the primary one (if the
+ self.pad_left attribute is set)."""
+
+ out_str = str_safe(self.p_str)
+ if self.pad_left:
+ # We must find the amount of padding required to match lengths,
+ # taking the color escapes (which are invisible on-screen) into
+ # account.
+ esc_pad = len(out_str) - len(str_safe(self.p_str_nocolor))
+ format = '%%%ss' % (len(str(self.cache.last_prompt))+esc_pad)
+ return format % out_str
+ else:
+ return out_str
+
+ # these path filters are put in as methods so that we can control the
+ # namespace where the prompt strings get evaluated
+ def cwd_filt(self,depth):
+ """Return the last depth elements of the current working directory.
+
+ $HOME is always replaced with '~'.
+ If depth==0, the full path is returned."""
+
+ cwd = os.getcwd().replace(HOME,"~")
+ out = os.sep.join(cwd.split(os.sep)[-depth:])
+ if out:
+ return out
+ else:
+ return os.sep
+
+ def cwd_filt2(self,depth):
+ """Return the last depth elements of the current working directory.
+
+ $HOME is always replaced with '~'.
+ If depth==0, the full path is returned."""
+
+ full_cwd = os.getcwd()
+ cwd = full_cwd.replace(HOME,"~").split(os.sep)
+ if '~' in cwd and len(cwd) == depth+1:
+ depth += 1
+ drivepart = ''
+ if sys.platform == 'win32' and len(cwd) > depth:
+ drivepart = os.path.splitdrive(full_cwd)[0]
+ out = drivepart + '/'.join(cwd[-depth:])
+
+ if out:
+ return out
+ else:
+ return os.sep
+
+ def __nonzero__(self):
+ """Implement boolean behavior.
+
+ Checks whether the p_str attribute is non-empty"""
+
+ return bool(self.p_template)
+
+class Prompt1(BasePrompt):
+ """Input interactive prompt similar to Mathematica's."""
+
+ def __init__(self,cache,sep='\n',prompt='In [\\#]: ',pad_left=True):
+ BasePrompt.__init__(self,cache,sep,prompt,pad_left)
+
+ def set_colors(self):
+ self.set_p_str()
+ Colors = self.cache.color_table.active_colors # shorthand
+ self.col_p = Colors.in_prompt
+ self.col_num = Colors.in_number
+ self.col_norm = Colors.in_normal
+ # We need a non-input version of these escapes for the '--->'
+ # auto-call prompts used in the auto_rewrite() method.
+ self.col_p_ni = self.col_p.replace('\001','').replace('\002','')
+ self.col_norm_ni = Colors.normal
+
+ def __str__(self):
+ self.cache.prompt_count += 1
+ self.cache.last_prompt = str_safe(self.p_str_nocolor).split('\n')[-1]
+ return str_safe(self.p_str)
+
+ def auto_rewrite(self):
+ """Print a string of the form '--->' which lines up with the previous
+ input string. Useful for systems which re-write the user input when
+ handling automatically special syntaxes."""
+
+ curr = str(self.cache.last_prompt)
+ nrspaces = len(self.rspace.search(curr).group())
+ return '%s%s>%s%s' % (self.col_p_ni,'-'*(len(curr)-nrspaces-1),
+ ' '*nrspaces,self.col_norm_ni)
+
+class PromptOut(BasePrompt):
+ """Output interactive prompt similar to Mathematica's."""
+
+ def __init__(self,cache,sep='',prompt='Out[\\#]: ',pad_left=True):
+ BasePrompt.__init__(self,cache,sep,prompt,pad_left)
+ if not self.p_template:
+ self.__str__ = lambda: ''
+
+ def set_colors(self):
+ self.set_p_str()
+ Colors = self.cache.color_table.active_colors # shorthand
+ self.col_p = Colors.out_prompt
+ self.col_num = Colors.out_number
+ self.col_norm = Colors.normal
+
+class Prompt2(BasePrompt):
+ """Interactive continuation prompt."""
+
+ def __init__(self,cache,prompt=' .\\D.: ',pad_left=True):
+ self.cache = cache
+ self.p_template = prompt
+ self.pad_left = pad_left
+ self.set_p_str()
+
+ def set_p_str(self):
+ import os,time # needed in locals for prompt string handling
+ loc = locals()
+ self.p_str = ItplNS('%s%s%s' %
+ ('${self.col_p2}',
+ multiple_replace(prompt_specials, self.p_template),
+ '$self.col_norm'),
+ self.cache.user_ns,loc)
+ self.p_str_nocolor = ItplNS(multiple_replace(prompt_specials_nocolor,
+ self.p_template),
+ self.cache.user_ns,loc)
+
+ def set_colors(self):
+ self.set_p_str()
+ Colors = self.cache.color_table.active_colors
+ self.col_p2 = Colors.in_prompt2
+ self.col_norm = Colors.in_normal
+ # FIXME (2004-06-16) HACK: prevent crashes for users who haven't
+ # updated their prompt_in2 definitions. Remove eventually.
+ self.col_p = Colors.out_prompt
+ self.col_num = Colors.out_number
+
+
+#-----------------------------------------------------------------------------
+class CachedOutput:
+ """Class for printing output from calculations while keeping a cache of
+ reults. It dynamically creates global variables prefixed with _ which
+ contain these results.
+
+ Meant to be used as a sys.displayhook replacement, providing numbered
+ prompts and cache services.
+
+ Initialize with initial and final values for cache counter (this defines
+ the maximum size of the cache."""
+
+ def __init__(self,shell,cache_size,Pprint,
+ colors='NoColor',input_sep='\n',
+ output_sep='\n',output_sep2='',
+ ps1 = None, ps2 = None,ps_out = None,pad_left=True):
+
+ cache_size_min = 3
+ if cache_size <= 0:
+ self.do_full_cache = 0
+ cache_size = 0
+ elif cache_size < cache_size_min:
+ self.do_full_cache = 0
+ cache_size = 0
+ warn('caching was disabled (min value for cache size is %s).' %
+ cache_size_min,level=3)
+ else:
+ self.do_full_cache = 1
+
+ self.cache_size = cache_size
+ self.input_sep = input_sep
+
+ # we need a reference to the user-level namespace
+ self.shell = shell
+ self.user_ns = shell.user_ns
+ # and to the user's input
+ self.input_hist = shell.input_hist
+ # and to the user's logger, for logging output
+ self.logger = shell.logger
+
+ # Set input prompt strings and colors
+ if cache_size == 0:
+ if ps1.find('%n') > -1 or ps1.find(r'\#') > -1 \
+ or ps1.find(r'\N') > -1:
+ ps1 = '>>> '
+ if ps2.find('%n') > -1 or ps2.find(r'\#') > -1 \
+ or ps2.find(r'\N') > -1:
+ ps2 = '... '
+ self.ps1_str = self._set_prompt_str(ps1,'In [\\#]: ','>>> ')
+ self.ps2_str = self._set_prompt_str(ps2,' .\\D.: ','... ')
+ self.ps_out_str = self._set_prompt_str(ps_out,'Out[\\#]: ','')
+
+ self.color_table = PromptColors
+ self.prompt1 = Prompt1(self,sep=input_sep,prompt=self.ps1_str,
+ pad_left=pad_left)
+ self.prompt2 = Prompt2(self,prompt=self.ps2_str,pad_left=pad_left)
+ self.prompt_out = PromptOut(self,sep='',prompt=self.ps_out_str,
+ pad_left=pad_left)
+ self.set_colors(colors)
+
+ # other more normal stuff
+ # b/c each call to the In[] prompt raises it by 1, even the first.
+ self.prompt_count = 0
+ # Store the last prompt string each time, we need it for aligning
+ # continuation and auto-rewrite prompts
+ self.last_prompt = ''
+ self.Pprint = Pprint
+ self.output_sep = output_sep
+ self.output_sep2 = output_sep2
+ self._,self.__,self.___ = '','',''
+ self.pprint_types = map(type,[(),[],{}])
+
+ # these are deliberately global:
+ to_user_ns = {'_':self._,'__':self.__,'___':self.___}
+ self.user_ns.update(to_user_ns)
+
+ def _set_prompt_str(self,p_str,cache_def,no_cache_def):
+ if p_str is None:
+ if self.do_full_cache:
+ return cache_def
+ else:
+ return no_cache_def
+ else:
+ return p_str
+
+ def set_colors(self,colors):
+ """Set the active color scheme and configure colors for the three
+ prompt subsystems."""
+
+ # FIXME: the prompt_specials global should be gobbled inside this
+ # class instead. Do it when cleaning up the whole 3-prompt system.
+ global prompt_specials
+ if colors.lower()=='nocolor':
+ prompt_specials = prompt_specials_nocolor
+ else:
+ prompt_specials = prompt_specials_color
+
+ self.color_table.set_active_scheme(colors)
+ self.prompt1.set_colors()
+ self.prompt2.set_colors()
+ self.prompt_out.set_colors()
+
+ def __call__(self,arg=None):
+ """Printing with history cache management.
+
+ This is invoked everytime the interpreter needs to print, and is
+ activated by setting the variable sys.displayhook to it."""
+
+ # If something injected a '_' variable in __builtin__, delete
+ # ipython's automatic one so we don't clobber that. gettext() in
+ # particular uses _, so we need to stay away from it.
+ if '_' in __builtin__.__dict__:
+ try:
+ del self.user_ns['_']
+ except KeyError:
+ pass
+ if arg is not None:
+ cout_write = Term.cout.write # fast lookup
+ # first handle the cache and counters
+
+ # do not print output if input ends in ';'
+ try:
+ if self.input_hist[self.prompt_count].endswith(';\n'):
+ return
+ except IndexError:
+ # some uses of ipshellembed may fail here
+ pass
+ # don't use print, puts an extra space
+ cout_write(self.output_sep)
+ outprompt = self.shell.hooks.generate_output_prompt()
+ if self.do_full_cache:
+ cout_write(outprompt)
+
+ # and now call a possibly user-defined print mechanism
+ manipulated_val = self.display(arg)
+
+ # user display hooks can change the variable to be stored in
+ # output history
+
+ if manipulated_val is not None:
+ arg = manipulated_val
+
+ # avoid recursive reference when displaying _oh/Out
+ if arg is not self.user_ns['_oh']:
+ self.update(arg)
+
+ if self.logger.log_output:
+ self.logger.log_write(repr(arg),'output')
+ cout_write(self.output_sep2)
+ Term.cout.flush()
+
+ def _display(self,arg):
+ """Default printer method, uses pprint.
+
+ Do ip.set_hook("result_display", my_displayhook) for custom result
+ display, e.g. when your own objects need special formatting.
+ """
+ try:
+ return IPython.generics.result_display(arg)
+ except TryNext:
+ return self.shell.hooks.result_display(arg)
+
+ # Assign the default display method:
+ display = _display
+
+ def update(self,arg):
+ #print '***cache_count', self.cache_count # dbg
+ if len(self.user_ns['_oh']) >= self.cache_size and self.do_full_cache:
+ warn('Output cache limit (currently '+
+ `self.cache_size`+' entries) hit.\n'
+ 'Flushing cache and resetting history counter...\n'
+ 'The only history variables available will be _,__,___ and _1\n'
+ 'with the current result.')
+
+ self.flush()
+ # Don't overwrite '_' and friends if '_' is in __builtin__ (otherwise
+ # we cause buggy behavior for things like gettext).
+ if '_' not in __builtin__.__dict__:
+ self.___ = self.__
+ self.__ = self._
+ self._ = arg
+ self.user_ns.update({'_':self._,'__':self.__,'___':self.___})
+
+ # hackish access to top-level namespace to create _1,_2... dynamically
+ to_main = {}
+ if self.do_full_cache:
+ new_result = '_'+`self.prompt_count`
+ to_main[new_result] = arg
+ self.user_ns.update(to_main)
+ self.user_ns['_oh'][self.prompt_count] = arg
+
+ def flush(self):
+ if not self.do_full_cache:
+ raise ValueError,"You shouldn't have reached the cache flush "\
+ "if full caching is not enabled!"
+ # delete auto-generated vars from global namespace
+
+ for n in range(1,self.prompt_count + 1):
+ key = '_'+`n`
+ try:
+ del self.user_ns[key]
+ except: pass
+ self.user_ns['_oh'].clear()
+
+ if '_' not in __builtin__.__dict__:
+ self.user_ns.update({'_':None,'__':None, '___':None})
+ import gc
+ gc.collect() # xxx needed?
+
diff --git a/IPython/PyColorize.py b/IPython/PyColorize.py
new file mode 100644
index 0000000..7d463ea
--- /dev/null
+++ b/IPython/PyColorize.py
@@ -0,0 +1,300 @@
+# -*- coding: utf-8 -*-
+"""
+Class and program to colorize python source code for ANSI terminals.
+
+Based on an HTML code highlighter by Jurgen Hermann found at:
+http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52298
+
+Modifications by Fernando Perez (fperez@colorado.edu).
+
+Information on the original HTML highlighter follows:
+
+MoinMoin - Python Source Parser
+
+Title: Colorize Python source using the built-in tokenizer
+
+Submitter: Jurgen Hermann
+Last Updated:2001/04/06
+
+Version no:1.2
+
+Description:
+
+This code is part of MoinMoin (http://moin.sourceforge.net/) and converts
+Python source code to HTML markup, rendering comments, keywords,
+operators, numeric and string literals in different colors.
+
+It shows how to use the built-in keyword, token and tokenize modules to
+scan Python source code and re-emit it with no changes to its original
+formatting (which is the hard part).
+"""
+
+__all__ = ['ANSICodeColors','Parser']
+
+_scheme_default = 'Linux'
+
+# Imports
+import cStringIO
+import keyword
+import os
+import optparse
+import string
+import sys
+import token
+import tokenize
+
+from IPython.ColorANSI import *
+
+#############################################################################
+### Python Source Parser (does Hilighting)
+#############################################################################
+
+_KEYWORD = token.NT_OFFSET + 1
+_TEXT = token.NT_OFFSET + 2
+
+#****************************************************************************
+# Builtin color schemes
+
+Colors = TermColors # just a shorthand
+
+# Build a few color schemes
+NoColor = ColorScheme(
+ 'NoColor',{
+ token.NUMBER : Colors.NoColor,
+ token.OP : Colors.NoColor,
+ token.STRING : Colors.NoColor,
+ tokenize.COMMENT : Colors.NoColor,
+ token.NAME : Colors.NoColor,
+ token.ERRORTOKEN : Colors.NoColor,
+
+ _KEYWORD : Colors.NoColor,
+ _TEXT : Colors.NoColor,
+
+ 'normal' : Colors.NoColor # color off (usu. Colors.Normal)
+ } )
+
+LinuxColors = ColorScheme(
+ 'Linux',{
+ token.NUMBER : Colors.LightCyan,
+ token.OP : Colors.Yellow,
+ token.STRING : Colors.LightBlue,
+ tokenize.COMMENT : Colors.LightRed,
+ token.NAME : Colors.White,
+ token.ERRORTOKEN : Colors.Red,
+
+ _KEYWORD : Colors.LightGreen,
+ _TEXT : Colors.Yellow,
+
+ 'normal' : Colors.Normal # color off (usu. Colors.Normal)
+ } )
+
+LightBGColors = ColorScheme(
+ 'LightBG',{
+ token.NUMBER : Colors.Cyan,
+ token.OP : Colors.Blue,
+ token.STRING : Colors.Blue,
+ tokenize.COMMENT : Colors.Red,
+ token.NAME : Colors.Black,
+ token.ERRORTOKEN : Colors.Red,
+
+ _KEYWORD : Colors.Green,
+ _TEXT : Colors.Blue,
+
+ 'normal' : Colors.Normal # color off (usu. Colors.Normal)
+ } )
+
+# Build table of color schemes (needed by the parser)
+ANSICodeColors = ColorSchemeTable([NoColor,LinuxColors,LightBGColors],
+ _scheme_default)
+
+class Parser:
+ """ Format colored Python source.
+ """
+
+ def __init__(self, color_table=None,out = sys.stdout):
+ """ Create a parser with a specified color table and output channel.
+
+ Call format() to process code.
+ """
+ self.color_table = color_table and color_table or ANSICodeColors
+ self.out = out
+
+ def format(self, raw, out = None, scheme = ''):
+ return self.format2(raw, out, scheme)[0]
+
+ def format2(self, raw, out = None, scheme = ''):
+ """ Parse and send the colored source.
+
+ If out and scheme are not specified, the defaults (given to
+ constructor) are used.
+
+ out should be a file-type object. Optionally, out can be given as the
+ string 'str' and the parser will automatically return the output in a
+ string."""
+
+ string_output = 0
+ if out == 'str' or self.out == 'str' or \
+ isinstance(self.out,cStringIO.OutputType):
+ # XXX - I don't really like this state handling logic, but at this
+ # point I don't want to make major changes, so adding the
+ # isinstance() check is the simplest I can do to ensure correct
+ # behavior.
+ out_old = self.out
+ self.out = cStringIO.StringIO()
+ string_output = 1
+ elif out is not None:
+ self.out = out
+
+ # Fast return of the unmodified input for NoColor scheme
+ if scheme == 'NoColor':
+ error = False
+ self.out.write(raw)
+ if string_output:
+ return raw,error
+ else:
+ return None,error
+
+ # local shorthands
+ colors = self.color_table[scheme].colors
+ self.colors = colors # put in object so __call__ sees it
+
+ # Remove trailing whitespace and normalize tabs
+ self.raw = raw.expandtabs().rstrip()
+
+ # store line offsets in self.lines
+ self.lines = [0, 0]
+ pos = 0
+ raw_find = self.raw.find
+ lines_append = self.lines.append
+ while 1:
+ pos = raw_find('\n', pos) + 1
+ if not pos: break
+ lines_append(pos)
+ lines_append(len(self.raw))
+
+ # parse the source and write it
+ self.pos = 0
+ text = cStringIO.StringIO(self.raw)
+
+ error = False
+ try:
+ tokenize.tokenize(text.readline, self)
+ except tokenize.TokenError, ex:
+ msg = ex[0]
+ line = ex[1][0]
+ self.out.write("%s\n\n*** ERROR: %s%s%s\n" %
+ (colors[token.ERRORTOKEN],
+ msg, self.raw[self.lines[line]:],
+ colors.normal)
+ )
+ error = True
+ self.out.write(colors.normal+'\n')
+ if string_output:
+ output = self.out.getvalue()
+ self.out = out_old
+ return (output, error)
+ return (None, error)
+
+ def __call__(self, toktype, toktext, (srow,scol), (erow,ecol), line):
+ """ Token handler, with syntax highlighting."""
+
+ # local shorthands
+ colors = self.colors
+ owrite = self.out.write
+
+ # line separator, so this works across platforms
+ linesep = os.linesep
+
+ # calculate new positions
+ oldpos = self.pos
+ newpos = self.lines[srow] + scol
+ self.pos = newpos + len(toktext)
+
+ # handle newlines
+ if toktype in [token.NEWLINE, tokenize.NL]:
+ owrite(linesep)
+ return
+
+ # send the original whitespace, if needed
+ if newpos > oldpos:
+ owrite(self.raw[oldpos:newpos])
+
+ # skip indenting tokens
+ if toktype in [token.INDENT, token.DEDENT]:
+ self.pos = newpos
+ return
+
+ # map token type to a color group
+ if token.LPAR <= toktype and toktype <= token.OP:
+ toktype = token.OP
+ elif toktype == token.NAME and keyword.iskeyword(toktext):
+ toktype = _KEYWORD
+ color = colors.get(toktype, colors[_TEXT])
+
+ #print '<%s>' % toktext, # dbg
+
+ # Triple quoted strings must be handled carefully so that backtracking
+ # in pagers works correctly. We need color terminators on _each_ line.
+ if linesep in toktext:
+ toktext = toktext.replace(linesep, '%s%s%s' %
+ (colors.normal,linesep,color))
+
+ # send text
+ owrite('%s%s%s' % (color,toktext,colors.normal))
+
+def main(argv=None):
+ """Run as a command-line script: colorize a python file or stdin using ANSI
+ color escapes and print to stdout.
+
+ Inputs:
+
+ - argv(None): a list of strings like sys.argv[1:] giving the command-line
+ arguments. If None, use sys.argv[1:].
+ """
+
+ usage_msg = """%prog [options] [filename]
+
+Colorize a python file or stdin using ANSI color escapes and print to stdout.
+If no filename is given, or if filename is -, read standard input."""
+
+ parser = optparse.OptionParser(usage=usage_msg)
+ newopt = parser.add_option
+ newopt('-s','--scheme',metavar='NAME',dest='scheme_name',action='store',
+ choices=['Linux','LightBG','NoColor'],default=_scheme_default,
+ help="give the color scheme to use. Currently only 'Linux'\
+ (default) and 'LightBG' and 'NoColor' are implemented (give without\
+ quotes)")
+
+ opts,args = parser.parse_args(argv)
+
+ if len(args) > 1:
+ parser.error("you must give at most one filename.")
+
+ if len(args) == 0:
+ fname = '-' # no filename given; setup to read from stdin
+ else:
+ fname = args[0]
+
+ if fname == '-':
+ stream = sys.stdin
+ else:
+ stream = file(fname)
+
+ parser = Parser()
+
+ # we need nested try blocks because pre-2.5 python doesn't support unified
+ # try-except-finally
+ try:
+ try:
+ # write colorized version to stdout
+ parser.format(stream.read(),scheme=opts.scheme_name)
+ except IOError,msg:
+ # if user reads through a pager and quits, don't print traceback
+ if msg.args != (32,'Broken pipe'):
+ raise
+ finally:
+ if stream is not sys.stdin:
+ stream.close() # in case a non-handled exception happened above
+
+if __name__ == "__main__":
+ main()
diff --git a/IPython/Release.py b/IPython/Release.py
new file mode 100644
index 0000000..e791202
--- /dev/null
+++ b/IPython/Release.py
@@ -0,0 +1,121 @@
+# -*- coding: utf-8 -*-
+"""Release data for the IPython project."""
+
+#*****************************************************************************
+# Copyright (C) 2008-2009 The IPython Development Team
+# Copyright (C) 2001-2008 Fernando Perez <fperez@colorado.edu>
+# Copyright (c) 2001 Janko Hauser <jhauser@zscout.de> and Nathaniel Gray
+# <n8gray@caltech.edu>
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#*****************************************************************************
+
+# Name of the package for release purposes. This is the name which labels
+# the tarballs and RPMs made by distutils, so it's best to lowercase it.
+name = 'ipython'
+
+# For versions with substrings (like 0.6.16.svn), use an extra . to separate
+# the new substring. We have to avoid using either dashes or underscores,
+# because bdist_rpm does not accept dashes (an RPM) convention, and
+# bdist_deb does not accept underscores (a Debian convention).
+
+development = False # change this to False to do a release
+version_base = '0.10'
+branch = 'ipython'
+revision = '1210'
+
+if development:
+ if branch == 'ipython':
+ version = '%s.bzr.r%s' % (version_base, revision)
+ else:
+ version = '%s.bzr.r%s.%s' % (version_base, revision, branch)
+else:
+ version = version_base
+
+
+description = "An interactive computing environment for Python"
+
+long_description = \
+"""
+The goal of IPython is to create a comprehensive environment for
+interactive and exploratory computing. To support this goal, IPython
+has two main components:
+
+* An enhanced interactive Python shell.
+
+* An architecture for interactive parallel computing.
+
+The enhanced interactive Python shell has the following main features:
+
+* Comprehensive object introspection.
+
+* Input history, persistent across sessions.
+
+* Caching of output results during a session with automatically generated
+ references.
+
+* Readline based name completion.
+
+* Extensible system of 'magic' commands for controlling the environment and
+ performing many tasks related either to IPython or the operating system.
+
+* Configuration system with easy switching between different setups (simpler
+ than changing $PYTHONSTARTUP environment variables every time).
+
+* Session logging and reloading.
+
+* Extensible syntax processing for special purpose situations.
+
+* Access to the system shell with user-extensible alias system.
+
+* Easily embeddable in other Python programs and wxPython GUIs.
+
+* Integrated access to the pdb debugger and the Python profiler.
+
+The parallel computing architecture has the following main features:
+
+* Quickly parallelize Python code from an interactive Python/IPython session.
+
+* A flexible and dynamic process model that be deployed on anything from
+ multicore workstations to supercomputers.
+
+* An architecture that supports many different styles of parallelism, from
+ message passing to task farming.
+
+* Both blocking and fully asynchronous interfaces.
+
+* High level APIs that enable many things to be parallelized in a few lines
+ of code.
+
+* Share live parallel jobs with other users securely.
+
+* Dynamically load balanced task farming system.
+
+* Robust error handling in parallel code.
+
+The latest development version is always available from IPython's `Launchpad
+site <http://launchpad.net/ipython>`_.
+"""
+
+license = 'BSD'
+
+authors = {'Fernando' : ('Fernando Perez','fperez.net@gmail.com'),
+ 'Janko' : ('Janko Hauser','jhauser@zscout.de'),
+ 'Nathan' : ('Nathaniel Gray','n8gray@caltech.edu'),
+ 'Ville' : ('Ville Vainio','vivainio@gmail.com'),
+ 'Brian' : ('Brian E Granger', 'ellisonbg@gmail.com'),
+ 'Min' : ('Min Ragan-Kelley', 'benjaminrk@gmail.com')
+ }
+
+author = 'The IPython Development Team'
+
+author_email = 'ipython-dev@scipy.org'
+
+url = 'http://ipython.scipy.org'
+
+download_url = 'http://ipython.scipy.org/dist'
+
+platforms = ['Linux','Mac OSX','Windows XP/2000/NT','Windows 95/98/ME']
+
+keywords = ['Interactive','Interpreter','Shell','Parallel','Distributed']
diff --git a/IPython/Shell.py b/IPython/Shell.py
new file mode 100644
index 0000000..2dd9dac
--- /dev/null
+++ b/IPython/Shell.py
@@ -0,0 +1,1246 @@
+# -*- coding: utf-8 -*-
+"""IPython Shell classes.
+
+All the matplotlib support code was co-developed with John Hunter,
+matplotlib's author.
+"""
+
+#*****************************************************************************
+# Copyright (C) 2001-2006 Fernando Perez <fperez@colorado.edu>
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#*****************************************************************************
+
+# Code begins
+# Stdlib imports
+import __builtin__
+import __main__
+import Queue
+import inspect
+import os
+import sys
+import thread
+import threading
+import time
+
+from signal import signal, SIGINT
+
+try:
+ import ctypes
+ HAS_CTYPES = True
+except ImportError:
+ HAS_CTYPES = False
+
+# IPython imports
+import IPython
+from IPython import ultraTB, ipapi
+from IPython.Magic import Magic
+from IPython.genutils import Term,warn,error,flag_calls, ask_yes_no
+from IPython.iplib import InteractiveShell
+from IPython.ipmaker import make_IPython
+from IPython.ipstruct import Struct
+from IPython.testing import decorators as testdec
+
+# Globals
+# global flag to pass around information about Ctrl-C without exceptions
+KBINT = False
+
+# global flag to turn on/off Tk support.
+USE_TK = False
+
+# ID for the main thread, used for cross-thread exceptions
+MAIN_THREAD_ID = thread.get_ident()
+
+# Tag when runcode() is active, for exception handling
+CODE_RUN = None
+
+# Default timeout for waiting for multithreaded shells (in seconds)
+GUI_TIMEOUT = 10
+
+#-----------------------------------------------------------------------------
+# This class is trivial now, but I want to have it in to publish a clean
+# interface. Later when the internals are reorganized, code that uses this
+# shouldn't have to change.
+
+class IPShell:
+ """Create an IPython instance."""
+
+ def __init__(self,argv=None,user_ns=None,user_global_ns=None,
+ debug=1,shell_class=InteractiveShell):
+ self.IP = make_IPython(argv,user_ns=user_ns,
+ user_global_ns=user_global_ns,
+ debug=debug,shell_class=shell_class)
+
+ def mainloop(self,sys_exit=0,banner=None):
+ self.IP.mainloop(banner)
+ if sys_exit:
+ sys.exit()
+
+#-----------------------------------------------------------------------------
+def kill_embedded(self,parameter_s=''):
+ """%kill_embedded : deactivate for good the current embedded IPython.
+
+ This function (after asking for confirmation) sets an internal flag so that
+ an embedded IPython will never activate again. This is useful to
+ permanently disable a shell that is being called inside a loop: once you've
+ figured out what you needed from it, you may then kill it and the program
+ will then continue to run without the interactive shell interfering again.
+ """
+
+ kill = ask_yes_no("Are you sure you want to kill this embedded instance "
+ "(y/n)? [y/N] ",'n')
+ if kill:
+ self.shell.embedded_active = False
+ print "This embedded IPython will not reactivate anymore once you exit."
+
+class IPShellEmbed:
+ """Allow embedding an IPython shell into a running program.
+
+ Instances of this class are callable, with the __call__ method being an
+ alias to the embed() method of an InteractiveShell instance.
+
+ Usage (see also the example-embed.py file for a running example):
+
+ ipshell = IPShellEmbed([argv,banner,exit_msg,rc_override])
+
+ - argv: list containing valid command-line options for IPython, as they
+ would appear in sys.argv[1:].
+
+ For example, the following command-line options:
+
+ $ ipython -prompt_in1 'Input <\\#>' -colors LightBG
+
+ would be passed in the argv list as:
+
+ ['-prompt_in1','Input <\\#>','-colors','LightBG']
+
+ - banner: string which gets printed every time the interpreter starts.
+
+ - exit_msg: string which gets printed every time the interpreter exits.
+
+ - rc_override: a dict or Struct of configuration options such as those
+ used by IPython. These options are read from your ~/.ipython/ipythonrc
+ file when the Shell object is created. Passing an explicit rc_override
+ dict with any options you want allows you to override those values at
+ creation time without having to modify the file. This way you can create
+ embeddable instances configured in any way you want without editing any
+ global files (thus keeping your interactive IPython configuration
+ unchanged).
+
+ Then the ipshell instance can be called anywhere inside your code:
+
+ ipshell(header='') -> Opens up an IPython shell.
+
+ - header: string printed by the IPython shell upon startup. This can let
+ you know where in your code you are when dropping into the shell. Note
+ that 'banner' gets prepended to all calls, so header is used for
+ location-specific information.
+
+ For more details, see the __call__ method below.
+
+ When the IPython shell is exited with Ctrl-D, normal program execution
+ resumes.
+
+ This functionality was inspired by a posting on comp.lang.python by cmkl
+ <cmkleffner@gmx.de> on Dec. 06/01 concerning similar uses of pyrepl, and
+ by the IDL stop/continue commands."""
+
+ def __init__(self,argv=None,banner='',exit_msg=None,rc_override=None,
+ user_ns=None):
+ """Note that argv here is a string, NOT a list."""
+ self.set_banner(banner)
+ self.set_exit_msg(exit_msg)
+ self.set_dummy_mode(0)
+
+ # sys.displayhook is a global, we need to save the user's original
+ # Don't rely on __displayhook__, as the user may have changed that.
+ self.sys_displayhook_ori = sys.displayhook
+
+ # save readline completer status
+ try:
+ #print 'Save completer',sys.ipcompleter # dbg
+ self.sys_ipcompleter_ori = sys.ipcompleter
+ except:
+ pass # not nested with IPython
+
+ self.IP = make_IPython(argv,rc_override=rc_override,
+ embedded=True,
+ user_ns=user_ns)
+
+ ip = ipapi.IPApi(self.IP)
+ ip.expose_magic("kill_embedded",kill_embedded)
+
+ # copy our own displayhook also
+ self.sys_displayhook_embed = sys.displayhook
+ # and leave the system's display hook clean
+ sys.displayhook = self.sys_displayhook_ori
+ # don't use the ipython crash handler so that user exceptions aren't
+ # trapped
+ sys.excepthook = ultraTB.FormattedTB(color_scheme = self.IP.rc.colors,
+ mode = self.IP.rc.xmode,
+ call_pdb = self.IP.rc.pdb)
+ self.restore_system_completer()
+
+ def restore_system_completer(self):
+ """Restores the readline completer which was in place.
+
+ This allows embedded IPython within IPython not to disrupt the
+ parent's completion.
+ """
+
+ try:
+ self.IP.readline.set_completer(self.sys_ipcompleter_ori)
+ sys.ipcompleter = self.sys_ipcompleter_ori
+ except:
+ pass
+
+ def __call__(self,header='',local_ns=None,global_ns=None,dummy=None):
+ """Activate the interactive interpreter.
+
+ __call__(self,header='',local_ns=None,global_ns,dummy=None) -> Start
+ the interpreter shell with the given local and global namespaces, and
+ optionally print a header string at startup.
+
+ The shell can be globally activated/deactivated using the
+ set/get_dummy_mode methods. This allows you to turn off a shell used
+ for debugging globally.
+
+ However, *each* time you call the shell you can override the current
+ state of dummy_mode with the optional keyword parameter 'dummy'. For
+ example, if you set dummy mode on with IPShell.set_dummy_mode(1), you
+ can still have a specific call work by making it as IPShell(dummy=0).
+
+ The optional keyword parameter dummy controls whether the call
+ actually does anything. """
+
+ # If the user has turned it off, go away
+ if not self.IP.embedded_active:
+ return
+
+ # Normal exits from interactive mode set this flag, so the shell can't
+ # re-enter (it checks this variable at the start of interactive mode).
+ self.IP.exit_now = False
+
+ # Allow the dummy parameter to override the global __dummy_mode
+ if dummy or (dummy != 0 and self.__dummy_mode):
+ return
+
+ # Set global subsystems (display,completions) to our values
+ sys.displayhook = self.sys_displayhook_embed
+ if self.IP.has_readline:
+ self.IP.set_completer()
+
+ if self.banner and header:
+ format = '%s\n%s\n'
+ else:
+ format = '%s%s\n'
+ banner = format % (self.banner,header)
+
+ # Call the embedding code with a stack depth of 1 so it can skip over
+ # our call and get the original caller's namespaces.
+ self.IP.embed_mainloop(banner,local_ns,global_ns,stack_depth=1)
+
+ if self.exit_msg:
+ print self.exit_msg
+
+ # Restore global systems (display, completion)
+ sys.displayhook = self.sys_displayhook_ori
+ self.restore_system_completer()
+
+ def set_dummy_mode(self,dummy):
+ """Sets the embeddable shell's dummy mode parameter.
+
+ set_dummy_mode(dummy): dummy = 0 or 1.
+
+ This parameter is persistent and makes calls to the embeddable shell
+ silently return without performing any action. This allows you to
+ globally activate or deactivate a shell you're using with a single call.
+
+ If you need to manually"""
+
+ if dummy not in [0,1,False,True]:
+ raise ValueError,'dummy parameter must be boolean'
+ self.__dummy_mode = dummy
+
+ def get_dummy_mode(self):
+ """Return the current value of the dummy mode parameter.
+ """
+ return self.__dummy_mode
+
+ def set_banner(self,banner):
+ """Sets the global banner.
+
+ This banner gets prepended to every header printed when the shell
+ instance is called."""
+
+ self.banner = banner
+
+ def set_exit_msg(self,exit_msg):
+ """Sets the global exit_msg.
+
+ This exit message gets printed upon exiting every time the embedded
+ shell is called. It is None by default. """
+
+ self.exit_msg = exit_msg
+
+#-----------------------------------------------------------------------------
+if HAS_CTYPES:
+ # Add async exception support. Trick taken from:
+ # http://sebulba.wikispaces.com/recipe+thread2
+ def _async_raise(tid, exctype):
+ """raises the exception, performs cleanup if needed"""
+ if not inspect.isclass(exctype):
+ raise TypeError("Only types can be raised (not instances)")
+ # Explicit cast to c_long is necessary for 64-bit support:
+ # See https://bugs.launchpad.net/ipython/+bug/237073
+ res = ctypes.pythonapi.PyThreadState_SetAsyncExc(ctypes.c_long(tid),
+ ctypes.py_object(exctype))
+ if res == 0:
+ raise ValueError("invalid thread id")
+ elif res != 1:
+ # If it returns a number greater than one, you're in trouble,
+ # and you should call it again with exc=NULL to revert the effect
+ ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, 0)
+ raise SystemError("PyThreadState_SetAsyncExc failed")
+
+ def sigint_handler(signum,stack_frame):
+ """Sigint handler for threaded apps.
+
+ This is a horrible hack to pass information about SIGINT _without_
+ using exceptions, since I haven't been able to properly manage
+ cross-thread exceptions in GTK/WX. In fact, I don't think it can be
+ done (or at least that's my understanding from a c.l.py thread where
+ this was discussed)."""
+
+ global KBINT
+
+ if CODE_RUN:
+ _async_raise(MAIN_THREAD_ID,KeyboardInterrupt)
+ else:
+ KBINT = True
+ print '\nKeyboardInterrupt - Press <Enter> to continue.',
+ Term.cout.flush()
+
+else:
+ def sigint_handler(signum,stack_frame):
+ """Sigint handler for threaded apps.
+
+ This is a horrible hack to pass information about SIGINT _without_
+ using exceptions, since I haven't been able to properly manage
+ cross-thread exceptions in GTK/WX. In fact, I don't think it can be
+ done (or at least that's my understanding from a c.l.py thread where
+ this was discussed)."""
+
+ global KBINT
+
+ print '\nKeyboardInterrupt - Press <Enter> to continue.',
+ Term.cout.flush()
+ # Set global flag so that runsource can know that Ctrl-C was hit
+ KBINT = True
+
+
+class MTInteractiveShell(InteractiveShell):
+ """Simple multi-threaded shell."""
+
+ # Threading strategy taken from:
+ # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/65109, by Brian
+ # McErlean and John Finlay. Modified with corrections by Antoon Pardon,
+ # from the pygtk mailing list, to avoid lockups with system calls.
+
+ # class attribute to indicate whether the class supports threads or not.
+ # Subclasses with thread support should override this as needed.
+ isthreaded = True
+
+ def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
+ user_ns=None,user_global_ns=None,banner2='',
+ gui_timeout=GUI_TIMEOUT,**kw):
+ """Similar to the normal InteractiveShell, but with threading control"""
+
+ InteractiveShell.__init__(self,name,usage,rc,user_ns,
+ user_global_ns,banner2)
+
+ # Timeout we wait for GUI thread
+ self.gui_timeout = gui_timeout
+
+ # A queue to hold the code to be executed.
+ self.code_queue = Queue.Queue()
+
+ # Stuff to do at closing time
+ self._kill = None
+ on_kill = kw.get('on_kill', [])
+ # Check that all things to kill are callable:
+ for t in on_kill:
+ if not callable(t):
+ raise TypeError,'on_kill must be a list of callables'
+ self.on_kill = on_kill
+ # thread identity of the "worker thread" (that may execute code directly)
+ self.worker_ident = None
+
+ def runsource(self, source, filename="<input>", symbol="single"):
+ """Compile and run some source in the interpreter.
+
+ Modified version of code.py's runsource(), to handle threading issues.
+ See the original for full docstring details."""
+
+ global KBINT
+
+ # If Ctrl-C was typed, we reset the flag and return right away
+ if KBINT:
+ KBINT = False
+ return False
+
+ if self._kill:
+ # can't queue new code if we are being killed
+ return True
+
+ try:
+ code = self.compile(source, filename, symbol)
+ except (OverflowError, SyntaxError, ValueError):
+ # Case 1
+ self.showsyntaxerror(filename)
+ return False
+
+ if code is None:
+ # Case 2
+ return True
+
+ # shortcut - if we are in worker thread, or the worker thread is not
+ # running, execute directly (to allow recursion and prevent deadlock if
+ # code is run early in IPython construction)
+
+ if (self.worker_ident is None
+ or self.worker_ident == thread.get_ident() ):
+ InteractiveShell.runcode(self,code)
+ return False
+
+ # Case 3
+ # Store code in queue, so the execution thread can handle it.
+
+ completed_ev, received_ev = threading.Event(), threading.Event()
+
+ self.code_queue.put((code,completed_ev, received_ev))
+ # first make sure the message was received, with timeout
+ received_ev.wait(self.gui_timeout)
+ if not received_ev.isSet():
+ # the mainloop is dead, start executing code directly
+ print "Warning: Timeout for mainloop thread exceeded"
+ print "switching to nonthreaded mode (until mainloop wakes up again)"
+ self.worker_ident = None
+ else:
+ completed_ev.wait()
+ return False
+
+ def runcode(self):
+ """Execute a code object.
+
+ Multithreaded wrapper around IPython's runcode()."""
+
+ global CODE_RUN
+
+ # we are in worker thread, stash out the id for runsource()
+ self.worker_ident = thread.get_ident()
+
+ if self._kill:
+ print >>Term.cout, 'Closing threads...',
+ Term.cout.flush()
+ for tokill in self.on_kill:
+ tokill()
+ print >>Term.cout, 'Done.'
+ # allow kill() to return
+ self._kill.set()
+ return True
+
+ # Install sigint handler. We do it every time to ensure that if user
+ # code modifies it, we restore our own handling.
+ try:
+ signal(SIGINT,sigint_handler)
+ except SystemError:
+ # This happens under Windows, which seems to have all sorts
+ # of problems with signal handling. Oh well...
+ pass
+
+ # Flush queue of pending code by calling the run methood of the parent
+ # class with all items which may be in the queue.
+ code_to_run = None
+ while 1:
+ try:
+ code_to_run, completed_ev, received_ev = self.code_queue.get_nowait()
+ except Queue.Empty:
+ break
+ received_ev.set()
+
+ # Exceptions need to be raised differently depending on which
+ # thread is active. This convoluted try/except is only there to
+ # protect against asynchronous exceptions, to ensure that a KBINT
+ # at the wrong time doesn't deadlock everything. The global
+ # CODE_TO_RUN is set to true/false as close as possible to the
+ # runcode() call, so that the KBINT handler is correctly informed.
+ try:
+ try:
+ CODE_RUN = True
+ InteractiveShell.runcode(self,code_to_run)
+ except KeyboardInterrupt:
+ print "Keyboard interrupted in mainloop"
+ while not self.code_queue.empty():
+ code, ev1,ev2 = self.code_queue.get_nowait()
+ ev1.set()
+ ev2.set()
+ break
+ finally:
+ CODE_RUN = False
+ # allow runsource() return from wait
+ completed_ev.set()
+
+
+ # This MUST return true for gtk threading to work
+ return True
+
+ def kill(self):
+ """Kill the thread, returning when it has been shut down."""
+ self._kill = threading.Event()
+ self._kill.wait()
+
+class MatplotlibShellBase:
+ """Mixin class to provide the necessary modifications to regular IPython
+ shell classes for matplotlib support.
+
+ Given Python's MRO, this should be used as the FIRST class in the
+ inheritance hierarchy, so that it overrides the relevant methods."""
+
+ def _matplotlib_config(self,name,user_ns,user_global_ns=None):
+ """Return items needed to setup the user's shell with matplotlib"""
+
+ # Initialize matplotlib to interactive mode always
+ import matplotlib
+ from matplotlib import backends
+ matplotlib.interactive(True)
+
+ def use(arg):
+ """IPython wrapper for matplotlib's backend switcher.
+
+ In interactive use, we can not allow switching to a different
+ interactive backend, since thread conflicts will most likely crash
+ the python interpreter. This routine does a safety check first,
+ and refuses to perform a dangerous switch. It still allows
+ switching to non-interactive backends."""
+
+ if arg in backends.interactive_bk and arg != self.mpl_backend:
+ m=('invalid matplotlib backend switch.\n'
+ 'This script attempted to switch to the interactive '
+ 'backend: `%s`\n'
+ 'Your current choice of interactive backend is: `%s`\n\n'
+ 'Switching interactive matplotlib backends at runtime\n'
+ 'would crash the python interpreter, '
+ 'and IPython has blocked it.\n\n'
+ 'You need to either change your choice of matplotlib backend\n'
+ 'by editing your .matplotlibrc file, or run this script as a \n'
+ 'standalone file from the command line, not using IPython.\n' %
+ (arg,self.mpl_backend) )
+ raise RuntimeError, m
+ else:
+ self.mpl_use(arg)
+ self.mpl_use._called = True
+
+ self.matplotlib = matplotlib
+ self.mpl_backend = matplotlib.rcParams['backend']
+
+ # we also need to block switching of interactive backends by use()
+ self.mpl_use = matplotlib.use
+ self.mpl_use._called = False
+ # overwrite the original matplotlib.use with our wrapper
+ matplotlib.use = use
+
+ # This must be imported last in the matplotlib series, after
+ # backend/interactivity choices have been made
+ import matplotlib.pylab as pylab
+ self.pylab = pylab
+
+ self.pylab.show._needmain = False
+ # We need to detect at runtime whether show() is called by the user.
+ # For this, we wrap it into a decorator which adds a 'called' flag.
+ self.pylab.draw_if_interactive = flag_calls(self.pylab.draw_if_interactive)
+
+ # Build a user namespace initialized with matplotlib/matlab features.
+ user_ns, user_global_ns = IPython.ipapi.make_user_namespaces(user_ns,
+ user_global_ns)
+
+ # Import numpy as np/pyplot as plt are conventions we're trying to
+ # somewhat standardize on. Making them available to users by default
+ # will greatly help this.
+ exec ("import numpy\n"
+ "import numpy as np\n"
+ "import matplotlib\n"
+ "import matplotlib.pylab as pylab\n"
+ "try:\n"
+ " import matplotlib.pyplot as plt\n"
+ "except ImportError:\n"
+ " pass\n"
+ ) in user_ns
+
+ # Build matplotlib info banner
+ b="""
+ Welcome to pylab, a matplotlib-based Python environment.
+ For more information, type 'help(pylab)'.
+"""
+ return user_ns,user_global_ns,b
+
+ def mplot_exec(self,fname,*where,**kw):
+ """Execute a matplotlib script.
+
+ This is a call to execfile(), but wrapped in safeties to properly
+ handle interactive rendering and backend switching."""
+
+ #print '*** Matplotlib runner ***' # dbg
+ # turn off rendering until end of script
+ isInteractive = self.matplotlib.rcParams['interactive']
+ self.matplotlib.interactive(False)
+ self.safe_execfile(fname,*where,**kw)
+ self.matplotlib.interactive(isInteractive)
+ # make rendering call now, if the user tried to do it
+ if self.pylab.draw_if_interactive.called:
+ self.pylab.draw()
+ self.pylab.draw_if_interactive.called = False
+
+ # if a backend switch was performed, reverse it now
+ if self.mpl_use._called:
+ self.matplotlib.rcParams['backend'] = self.mpl_backend
+
+ @testdec.skip_doctest
+ def magic_run(self,parameter_s=''):
+ Magic.magic_run(self,parameter_s,runner=self.mplot_exec)
+
+ # Fix the docstring so users see the original as well
+ magic_run.__doc__ = "%s\n%s" % (Magic.magic_run.__doc__,
+ "\n *** Modified %run for Matplotlib,"
+ " with proper interactive handling ***")
+
+# Now we provide 2 versions of a matplotlib-aware IPython base shells, single
+# and multithreaded. Note that these are meant for internal use, the IPShell*
+# classes below are the ones meant for public consumption.
+
+class MatplotlibShell(MatplotlibShellBase,InteractiveShell):
+ """Single-threaded shell with matplotlib support."""
+
+ def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
+ user_ns=None,user_global_ns=None,**kw):
+ user_ns,user_global_ns,b2 = self._matplotlib_config(name,user_ns,user_global_ns)
+ InteractiveShell.__init__(self,name,usage,rc,user_ns,user_global_ns,
+ banner2=b2,**kw)
+
+class MatplotlibMTShell(MatplotlibShellBase,MTInteractiveShell):
+ """Multi-threaded shell with matplotlib support."""
+
+ def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
+ user_ns=None,user_global_ns=None, **kw):
+ user_ns,user_global_ns,b2 = self._matplotlib_config(name,user_ns,user_global_ns)
+ MTInteractiveShell.__init__(self,name,usage,rc,user_ns,user_global_ns,
+ banner2=b2,**kw)
+
+#-----------------------------------------------------------------------------
+# Utility functions for the different GUI enabled IPShell* classes.
+
+def get_tk():
+ """Tries to import Tkinter and returns a withdrawn Tkinter root
+ window. If Tkinter is already imported or not available, this
+ returns None. This function calls `hijack_tk` underneath.
+ """
+ if not USE_TK or sys.modules.has_key('Tkinter'):
+ return None
+ else:
+ try:
+ import Tkinter
+ except ImportError:
+ return None
+ else:
+ hijack_tk()
+ r = Tkinter.Tk()
+ r.withdraw()
+ return r
+
+def hijack_tk():
+ """Modifies Tkinter's mainloop with a dummy so when a module calls
+ mainloop, it does not block.
+
+ """
+ def misc_mainloop(self, n=0):
+ pass
+ def tkinter_mainloop(n=0):
+ pass
+
+ import Tkinter
+ Tkinter.Misc.mainloop = misc_mainloop
+ Tkinter.mainloop = tkinter_mainloop
+
+def update_tk(tk):
+ """Updates the Tkinter event loop. This is typically called from
+ the respective WX or GTK mainloops.
+ """
+ if tk:
+ tk.update()
+
+def hijack_wx():
+ """Modifies wxPython's MainLoop with a dummy so user code does not
+ block IPython. The hijacked mainloop function is returned.
+ """
+ def dummy_mainloop(*args, **kw):
+ pass
+
+ try:
+ import wx
+ except ImportError:
+ # For very old versions of WX
+ import wxPython as wx
+
+ ver = wx.__version__
+ orig_mainloop = None
+ if ver[:3] >= '2.5':
+ import wx
+ if hasattr(wx, '_core_'): core = getattr(wx, '_core_')
+ elif hasattr(wx, '_core'): core = getattr(wx, '_core')
+ else: raise AttributeError('Could not find wx core module')
+ orig_mainloop = core.PyApp_MainLoop
+ core.PyApp_MainLoop = dummy_mainloop
+ elif ver[:3] == '2.4':
+ orig_mainloop = wx.wxc.wxPyApp_MainLoop
+ wx.wxc.wxPyApp_MainLoop = dummy_mainloop
+ else:
+ warn("Unable to find either wxPython version 2.4 or >= 2.5.")
+ return orig_mainloop
+
+def hijack_gtk():
+ """Modifies pyGTK's mainloop with a dummy so user code does not
+ block IPython. This function returns the original `gtk.mainloop`
+ function that has been hijacked.
+ """
+ def dummy_mainloop(*args, **kw):
+ pass
+ import gtk
+ if gtk.pygtk_version >= (2,4,0): orig_mainloop = gtk.main
+ else: orig_mainloop = gtk.mainloop
+ gtk.mainloop = dummy_mainloop
+ gtk.main = dummy_mainloop
+ return orig_mainloop
+
+def hijack_qt():
+ """Modifies PyQt's mainloop with a dummy so user code does not
+ block IPython. This function returns the original
+ `qt.qApp.exec_loop` function that has been hijacked.
+ """
+ def dummy_mainloop(*args, **kw):
+ pass
+ import qt
+ orig_mainloop = qt.qApp.exec_loop
+ qt.qApp.exec_loop = dummy_mainloop
+ qt.QApplication.exec_loop = dummy_mainloop
+ return orig_mainloop
+
+def hijack_qt4():
+ """Modifies PyQt4's mainloop with a dummy so user code does not
+ block IPython. This function returns the original
+ `QtGui.qApp.exec_` function that has been hijacked.
+ """
+ def dummy_mainloop(*args, **kw):
+ pass
+ from PyQt4 import QtGui, QtCore
+ orig_mainloop = QtGui.qApp.exec_
+ QtGui.qApp.exec_ = dummy_mainloop
+ QtGui.QApplication.exec_ = dummy_mainloop
+ QtCore.QCoreApplication.exec_ = dummy_mainloop
+ return orig_mainloop
+
+#-----------------------------------------------------------------------------
+# The IPShell* classes below are the ones meant to be run by external code as
+# IPython instances. Note that unless a specific threading strategy is
+# desired, the factory function start() below should be used instead (it
+# selects the proper threaded class).
+
+class IPThread(threading.Thread):
+ def run(self):
+ self.IP.mainloop(self._banner)
+ self.IP.kill()
+
+class IPShellGTK(IPThread):
+ """Run a gtk mainloop() in a separate thread.
+
+ Python commands can be passed to the thread where they will be executed.
+ This is implemented by periodically checking for passed code using a
+ GTK timeout callback."""
+
+ TIMEOUT = 100 # Millisecond interval between timeouts.
+
+ def __init__(self,argv=None,user_ns=None,user_global_ns=None,
+ debug=1,shell_class=MTInteractiveShell):
+
+ import gtk
+ # Check for set_interactive, coming up in new pygtk.
+ # Disable it so that this code works, but notify
+ # the user that he has a better option as well.
+ # XXX TODO better support when set_interactive is released
+ try:
+ gtk.set_interactive(False)
+ print "Your PyGtk has set_interactive(), so you can use the"
+ print "more stable single-threaded Gtk mode."
+ print "See https://bugs.launchpad.net/ipython/+bug/270856"
+ except AttributeError:
+ pass
+
+ self.gtk = gtk
+ self.gtk_mainloop = hijack_gtk()
+
+ # Allows us to use both Tk and GTK.
+ self.tk = get_tk()
+
+ if gtk.pygtk_version >= (2,4,0): mainquit = self.gtk.main_quit
+ else: mainquit = self.gtk.mainquit
+
+ self.IP = make_IPython(argv,user_ns=user_ns,
+ user_global_ns=user_global_ns,
+ debug=debug,
+ shell_class=shell_class,
+ on_kill=[mainquit])
+
+ # HACK: slot for banner in self; it will be passed to the mainloop
+ # method only and .run() needs it. The actual value will be set by
+ # .mainloop().
+ self._banner = None
+
+ threading.Thread.__init__(self)
+
+ def mainloop(self,sys_exit=0,banner=None):
+
+ self._banner = banner
+
+ if self.gtk.pygtk_version >= (2,4,0):
+ import gobject
+ gobject.idle_add(self.on_timer)
+ else:
+ self.gtk.idle_add(self.on_timer)
+
+ if sys.platform != 'win32':
+ try:
+ if self.gtk.gtk_version[0] >= 2:
+ self.gtk.gdk.threads_init()
+ except AttributeError:
+ pass
+ except RuntimeError:
+ error('Your pyGTK likely has not been compiled with '
+ 'threading support.\n'
+ 'The exception printout is below.\n'
+ 'You can either rebuild pyGTK with threads, or '
+ 'try using \n'
+ 'matplotlib with a different backend (like Tk or WX).\n'
+ 'Note that matplotlib will most likely not work in its '
+ 'current state!')
+ self.IP.InteractiveTB()
+
+ self.start()
+ self.gtk.gdk.threads_enter()
+ self.gtk_mainloop()
+ self.gtk.gdk.threads_leave()
+ self.join()
+
+ def on_timer(self):
+ """Called when GTK is idle.
+
+ Must return True always, otherwise GTK stops calling it"""
+
+ update_tk(self.tk)
+ self.IP.runcode()
+ time.sleep(0.01)
+ return True
+
+
+class IPShellWX(IPThread):
+ """Run a wx mainloop() in a separate thread.
+
+ Python commands can be passed to the thread where they will be executed.
+ This is implemented by periodically checking for passed code using a
+ GTK timeout callback."""
+
+ TIMEOUT = 100 # Millisecond interval between timeouts.
+
+ def __init__(self,argv=None,user_ns=None,user_global_ns=None,
+ debug=1,shell_class=MTInteractiveShell):
+
+ self.IP = make_IPython(argv,user_ns=user_ns,
+ user_global_ns=user_global_ns,
+ debug=debug,
+ shell_class=shell_class,
+ on_kill=[self.wxexit])
+
+ wantedwxversion=self.IP.rc.wxversion
+ if wantedwxversion!="0":
+ try:
+ import wxversion
+ except ImportError:
+ error('The wxversion module is needed for WX version selection')
+ else:
+ try:
+ wxversion.select(wantedwxversion)
+ except:
+ self.IP.InteractiveTB()
+ error('Requested wxPython version %s could not be loaded' %
+ wantedwxversion)
+
+ import wx
+
+ threading.Thread.__init__(self)
+ self.wx = wx
+ self.wx_mainloop = hijack_wx()
+
+ # Allows us to use both Tk and GTK.
+ self.tk = get_tk()
+
+ # HACK: slot for banner in self; it will be passed to the mainloop
+ # method only and .run() needs it. The actual value will be set by
+ # .mainloop().
+ self._banner = None
+
+ self.app = None
+
+ def wxexit(self, *args):
+ if self.app is not None:
+ self.app.agent.timer.Stop()
+ self.app.ExitMainLoop()
+
+ def mainloop(self,sys_exit=0,banner=None):
+
+ self._banner = banner
+
+ self.start()
+
+ class TimerAgent(self.wx.MiniFrame):
+ wx = self.wx
+ IP = self.IP
+ tk = self.tk
+ def __init__(self, parent, interval):
+ style = self.wx.DEFAULT_FRAME_STYLE | self.wx.TINY_CAPTION_HORIZ
+ self.wx.MiniFrame.__init__(self, parent, -1, ' ', pos=(200, 200),
+ size=(100, 100),style=style)
+ self.Show(False)
+ self.interval = interval
+ self.timerId = self.wx.NewId()
+
+ def StartWork(self):
+ self.timer = self.wx.Timer(self, self.timerId)
+ self.wx.EVT_TIMER(self, self.timerId, self.OnTimer)
+ self.timer.Start(self.interval)
+
+ def OnTimer(self, event):
+ update_tk(self.tk)
+ self.IP.runcode()
+
+ class App(self.wx.App):
+ wx = self.wx
+ TIMEOUT = self.TIMEOUT
+ def OnInit(self):
+ 'Create the main window and insert the custom frame'
+ self.agent = TimerAgent(None, self.TIMEOUT)
+ self.agent.Show(False)
+ self.agent.StartWork()
+ return True
+
+ self.app = App(redirect=False)
+ self.wx_mainloop(self.app)
+ self.join()
+
+
+class IPShellQt(IPThread):
+ """Run a Qt event loop in a separate thread.
+
+ Python commands can be passed to the thread where they will be executed.
+ This is implemented by periodically checking for passed code using a
+ Qt timer / slot."""
+
+ TIMEOUT = 100 # Millisecond interval between timeouts.
+
+ def __init__(self, argv=None, user_ns=None, user_global_ns=None,
+ debug=0, shell_class=MTInteractiveShell):
+
+ import qt
+
+ self.exec_loop = hijack_qt()
+
+ # Allows us to use both Tk and QT.
+ self.tk = get_tk()
+
+ self.IP = make_IPython(argv,
+ user_ns=user_ns,
+ user_global_ns=user_global_ns,
+ debug=debug,
+ shell_class=shell_class,
+ on_kill=[qt.qApp.exit])
+
+ # HACK: slot for banner in self; it will be passed to the mainloop
+ # method only and .run() needs it. The actual value will be set by
+ # .mainloop().
+ self._banner = None
+
+ threading.Thread.__init__(self)
+
+ def mainloop(self, sys_exit=0, banner=None):
+
+ import qt
+
+ self._banner = banner
+
+ if qt.QApplication.startingUp():
+ a = qt.QApplication(sys.argv)
+
+ self.timer = qt.QTimer()
+ qt.QObject.connect(self.timer,
+ qt.SIGNAL('timeout()'),
+ self.on_timer)
+
+ self.start()
+ self.timer.start(self.TIMEOUT, True)
+ while True:
+ if self.IP._kill: break
+ self.exec_loop()
+ self.join()
+
+ def on_timer(self):
+ update_tk(self.tk)
+ result = self.IP.runcode()
+ self.timer.start(self.TIMEOUT, True)
+ return result
+
+
+class IPShellQt4(IPThread):
+ """Run a Qt event loop in a separate thread.
+
+ Python commands can be passed to the thread where they will be executed.
+ This is implemented by periodically checking for passed code using a
+ Qt timer / slot."""
+
+ TIMEOUT = 100 # Millisecond interval between timeouts.
+
+ def __init__(self, argv=None, user_ns=None, user_global_ns=None,
+ debug=0, shell_class=MTInteractiveShell):
+
+ from PyQt4 import QtCore, QtGui
+
+ try:
+ # present in PyQt4-4.2.1 or later
+ QtCore.pyqtRemoveInputHook()
+ except AttributeError:
+ pass
+
+ if QtCore.PYQT_VERSION_STR == '4.3':
+ warn('''PyQt4 version 4.3 detected.
+If you experience repeated threading warnings, please update PyQt4.
+''')
+
+ self.exec_ = hijack_qt4()
+
+ # Allows us to use both Tk and QT.
+ self.tk = get_tk()
+
+ self.IP = make_IPython(argv,
+ user_ns=user_ns,
+ user_global_ns=user_global_ns,
+ debug=debug,
+ shell_class=shell_class,
+ on_kill=[QtGui.qApp.exit])
+
+ # HACK: slot for banner in self; it will be passed to the mainloop
+ # method only and .run() needs it. The actual value will be set by
+ # .mainloop().
+ self._banner = None
+
+ threading.Thread.__init__(self)
+
+ def mainloop(self, sys_exit=0, banner=None):
+
+ from PyQt4 import QtCore, QtGui
+
+ self._banner = banner
+
+ if QtGui.QApplication.startingUp():
+ a = QtGui.QApplication(sys.argv)
+
+ self.timer = QtCore.QTimer()
+ QtCore.QObject.connect(self.timer,
+ QtCore.SIGNAL('timeout()'),
+ self.on_timer)
+
+ self.start()
+ self.timer.start(self.TIMEOUT)
+ while True:
+ if self.IP._kill: break
+ self.exec_()
+ self.join()
+
+ def on_timer(self):
+ update_tk(self.tk)
+ result = self.IP.runcode()
+ self.timer.start(self.TIMEOUT)
+ return result
+
+
+# A set of matplotlib public IPython shell classes, for single-threaded (Tk*
+# and FLTK*) and multithreaded (GTK*, WX* and Qt*) backends to use.
+def _load_pylab(user_ns):
+ """Allow users to disable pulling all of pylab into the top-level
+ namespace.
+
+ This little utility must be called AFTER the actual ipython instance is
+ running, since only then will the options file have been fully parsed."""
+
+ ip = IPython.ipapi.get()
+ if ip.options.pylab_import_all:
+ ip.ex("from matplotlib.pylab import *")
+ ip.IP.user_config_ns.update(ip.user_ns)
+
+
+class IPShellMatplotlib(IPShell):
+ """Subclass IPShell with MatplotlibShell as the internal shell.
+
+ Single-threaded class, meant for the Tk* and FLTK* backends.
+
+ Having this on a separate class simplifies the external driver code."""
+
+ def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
+ IPShell.__init__(self,argv,user_ns,user_global_ns,debug,
+ shell_class=MatplotlibShell)
+ _load_pylab(self.IP.user_ns)
+
+class IPShellMatplotlibGTK(IPShellGTK):
+ """Subclass IPShellGTK with MatplotlibMTShell as the internal shell.
+
+ Multi-threaded class, meant for the GTK* backends."""
+
+ def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
+ IPShellGTK.__init__(self,argv,user_ns,user_global_ns,debug,
+ shell_class=MatplotlibMTShell)
+ _load_pylab(self.IP.user_ns)
+
+class IPShellMatplotlibWX(IPShellWX):
+ """Subclass IPShellWX with MatplotlibMTShell as the internal shell.
+
+ Multi-threaded class, meant for the WX* backends."""
+
+ def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
+ IPShellWX.__init__(self,argv,user_ns,user_global_ns,debug,
+ shell_class=MatplotlibMTShell)
+ _load_pylab(self.IP.user_ns)
+
+class IPShellMatplotlibQt(IPShellQt):
+ """Subclass IPShellQt with MatplotlibMTShell as the internal shell.
+
+ Multi-threaded class, meant for the Qt* backends."""
+
+ def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
+ IPShellQt.__init__(self,argv,user_ns,user_global_ns,debug,
+ shell_class=MatplotlibMTShell)
+ _load_pylab(self.IP.user_ns)
+
+class IPShellMatplotlibQt4(IPShellQt4):
+ """Subclass IPShellQt4 with MatplotlibMTShell as the internal shell.
+
+ Multi-threaded class, meant for the Qt4* backends."""
+
+ def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
+ IPShellQt4.__init__(self,argv,user_ns,user_global_ns,debug,
+ shell_class=MatplotlibMTShell)
+ _load_pylab(self.IP.user_ns)
+
+#-----------------------------------------------------------------------------
+# Factory functions to actually start the proper thread-aware shell
+
+def _select_shell(argv):
+ """Select a shell from the given argv vector.
+
+ This function implements the threading selection policy, allowing runtime
+ control of the threading mode, both for general users and for matplotlib.
+
+ Return:
+ Shell class to be instantiated for runtime operation.
+ """
+
+ global USE_TK
+
+ mpl_shell = {'gthread' : IPShellMatplotlibGTK,
+ 'wthread' : IPShellMatplotlibWX,
+ 'qthread' : IPShellMatplotlibQt,
+ 'q4thread' : IPShellMatplotlibQt4,
+ 'tkthread' : IPShellMatplotlib, # Tk is built-in
+ }
+
+ th_shell = {'gthread' : IPShellGTK,
+ 'wthread' : IPShellWX,
+ 'qthread' : IPShellQt,
+ 'q4thread' : IPShellQt4,
+ 'tkthread' : IPShell, # Tk is built-in
+ }
+
+ backends = {'gthread' : 'GTKAgg',
+ 'wthread' : 'WXAgg',
+ 'qthread' : 'QtAgg',
+ 'q4thread' :'Qt4Agg',
+ 'tkthread' :'TkAgg',
+ }
+
+ all_opts = set(['tk','pylab','gthread','qthread','q4thread','wthread',
+ 'tkthread'])
+ user_opts = set([s.replace('-','') for s in argv[:3]])
+ special_opts = user_opts & all_opts
+
+ if 'tk' in special_opts:
+ USE_TK = True
+ special_opts.remove('tk')
+
+ if 'pylab' in special_opts:
+
+ try:
+ import matplotlib
+ except ImportError:
+ error('matplotlib could NOT be imported! Starting normal IPython.')
+ return IPShell
+
+ special_opts.remove('pylab')
+ # If there's any option left, it means the user wants to force the
+ # threading backend, else it's auto-selected from the rc file
+ if special_opts:
+ th_mode = special_opts.pop()
+ matplotlib.rcParams['backend'] = backends[th_mode]
+ else:
+ backend = matplotlib.rcParams['backend']
+ if backend.startswith('GTK'):
+ th_mode = 'gthread'
+ elif backend.startswith('WX'):
+ th_mode = 'wthread'
+ elif backend.startswith('Qt4'):
+ th_mode = 'q4thread'
+ elif backend.startswith('Qt'):
+ th_mode = 'qthread'
+ else:
+ # Any other backend, use plain Tk
+ th_mode = 'tkthread'
+
+ return mpl_shell[th_mode]
+ else:
+ # No pylab requested, just plain threads
+ try:
+ th_mode = special_opts.pop()
+ except KeyError:
+ th_mode = 'tkthread'
+ return th_shell[th_mode]
+
+
+# This is the one which should be called by external code.
+def start(user_ns = None):
+ """Return a running shell instance, dealing with threading options.
+
+ This is a factory function which will instantiate the proper IPython shell
+ based on the user's threading choice. Such a selector is needed because
+ different GUI toolkits require different thread handling details."""
+
+ shell = _select_shell(sys.argv)
+ return shell(user_ns = user_ns)
+
+# Some aliases for backwards compatibility
+IPythonShell = IPShell
+IPythonShellEmbed = IPShellEmbed
+#************************ End of file <Shell.py> ***************************
diff --git a/IPython/UserConfig/__init__.py b/IPython/UserConfig/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/IPython/UserConfig/__init__.py
diff --git a/IPython/UserConfig/ipy_user_conf.py b/IPython/UserConfig/ipy_user_conf.py
new file mode 100644
index 0000000..6d6fbbd
--- /dev/null
+++ b/IPython/UserConfig/ipy_user_conf.py
@@ -0,0 +1,114 @@
+""" User configuration file for IPython
+
+This is a more flexible and safe way to configure ipython than *rc files
+(ipythonrc, ipythonrc-pysh etc.)
+
+This file is always imported on ipython startup. You can import the
+ipython extensions you need here (see IPython/Extensions directory).
+
+Feel free to edit this file to customize your ipython experience.
+
+Note that as such this file does nothing, for backwards compatibility.
+Consult e.g. file 'ipy_profile_sh.py' for an example of the things
+you can do here.
+
+See http://ipython.scipy.org/moin/IpythonExtensionApi for detailed
+description on what you could do here.
+"""
+
+# Most of your config files and extensions will probably start with this import
+
+import IPython.ipapi
+ip = IPython.ipapi.get()
+
+# You probably want to uncomment this if you did %upgrade -nolegacy
+# import ipy_defaults
+
+import os
+
+def main():
+
+ # uncomment if you want to get ipython -p sh behaviour
+ # without having to use command line switches
+ # import ipy_profile_sh
+
+ # Configure your favourite editor?
+ # Good idea e.g. for %edit os.path.isfile
+
+ #import ipy_editors
+
+ # Choose one of these:
+
+ #ipy_editors.scite()
+ #ipy_editors.scite('c:/opt/scite/scite.exe')
+ #ipy_editors.komodo()
+ #ipy_editors.idle()
+ # ... or many others, try 'ipy_editors??' after import to see them
+
+ # Or roll your own:
+ #ipy_editors.install_editor("c:/opt/jed +$line $file")
+
+
+ o = ip.options
+ # An example on how to set options
+ #o.autocall = 1
+ o.system_verbose = 0
+
+ #import_all("os sys")
+ #execf('~/_ipython/ns.py')
+
+
+ # -- prompt
+ # A different, more compact set of prompts from the default ones, that
+ # always show your current location in the filesystem:
+
+ #o.prompt_in1 = r'\C_LightBlue[\C_LightCyan\Y2\C_LightBlue]\C_Normal\n\C_Green|\#>'
+ #o.prompt_in2 = r'.\D: '
+ #o.prompt_out = r'[\#] '
+
+ # Try one of these color settings if you can't read the text easily
+ # autoexec is a list of IPython commands to execute on startup
+ #o.autoexec.append('%colors LightBG')
+ #o.autoexec.append('%colors NoColor')
+ #o.autoexec.append('%colors Linux')
+
+ # for sane integer division that converts to float (1/2 == 0.5)
+ #o.autoexec.append('from __future__ import division')
+
+ # For %tasks and %kill
+ #import jobctrl
+
+ # For autoreloading of modules (%autoreload, %aimport)
+ #import ipy_autoreload
+
+ # For winpdb support (%wdb)
+ #import ipy_winpdb
+
+ # For bzr completer, requires bzrlib (the python installation of bzr)
+ #ip.load('ipy_bzr')
+
+ # Tab completer that is not quite so picky (i.e.
+ # "foo".<TAB> and str(2).<TAB> will work). Complete
+ # at your own risk!
+ #import ipy_greedycompleter
+
+ # If you are on Linux, you may be annoyed by
+ # "Display all N possibilities? (y or n)" on tab completion,
+ # as well as the paging through "more". Uncomment the following
+ # lines to disable that behaviour
+ #import readline
+ #readline.parse_and_bind('set completion-query-items 1000')
+ #readline.parse_and_bind('set page-completions no')
+
+
+# some config helper functions you can use
+def import_all(modules):
+ """ Usage: import_all("os sys") """
+ for m in modules.split():
+ ip.ex("from %s import *" % m)
+
+def execf(fname):
+ """ Execute a file in user namespace """
+ ip.ex('execfile("%s")' % os.path.expanduser(fname))
+
+main()
diff --git a/IPython/UserConfig/ipythonrc b/IPython/UserConfig/ipythonrc
new file mode 100644
index 0000000..c90044f
--- /dev/null
+++ b/IPython/UserConfig/ipythonrc
@@ -0,0 +1,631 @@
+# -*- Mode: Shell-Script -*- Not really, but shows comments correctly
+
+#***************************************************************************
+#
+# Configuration file for IPython -- ipythonrc format
+#
+# ===========================================================
+# Deprecation note: you should look into modifying ipy_user_conf.py (located
+# in ~/.ipython or ~/_ipython, depending on your platform) instead, it's a
+# more flexible and robust (and better supported!) configuration
+# method.
+# ===========================================================
+#
+# The format of this file is simply one of 'key value' lines.
+# Lines containing only whitespace at the beginning and then a # are ignored
+# as comments. But comments can NOT be put on lines with data.
+
+# The meaning and use of each key are explained below.
+
+#---------------------------------------------------------------------------
+# Section: included files
+
+# Put one or more *config* files (with the syntax of this file) you want to
+# include. For keys with a unique value the outermost file has precedence. For
+# keys with multiple values, they all get assembled into a list which then
+# gets loaded by IPython.
+
+# In this file, all lists of things should simply be space-separated.
+
+# This allows you to build hierarchies of files which recursively load
+# lower-level services. If this is your main ~/.ipython/ipythonrc file, you
+# should only keep here basic things you always want available. Then you can
+# include it in every other special-purpose config file you create.
+include
+
+#---------------------------------------------------------------------------
+# Section: startup setup
+
+# These are mostly things which parallel a command line option of the same
+# name.
+
+# Keys in this section should only appear once. If any key from this section
+# is encountered more than once, the last value remains, all earlier ones get
+# discarded.
+
+
+# Automatic calling of callable objects. If set to 1 or 2, callable objects
+# are automatically called when invoked at the command line, even if you don't
+# type parentheses. IPython adds the parentheses for you. For example:
+
+#In [1]: str 45
+#------> str(45)
+#Out[1]: '45'
+
+# IPython reprints your line with '---->' indicating that it added
+# parentheses. While this option is very convenient for interactive use, it
+# may occasionally cause problems with objects which have side-effects if
+# called unexpectedly.
+
+# The valid values for autocall are:
+
+# autocall 0 -> disabled (you can toggle it at runtime with the %autocall magic)
+
+# autocall 1 -> active, but do not apply if there are no arguments on the line.
+
+# In this mode, you get:
+
+#In [1]: callable
+#Out[1]: <built-in function callable>
+
+#In [2]: callable 'hello'
+#------> callable('hello')
+#Out[2]: False
+
+# 2 -> Active always. Even if no arguments are present, the callable object
+# is called:
+
+#In [4]: callable
+#------> callable()
+
+# Note that even with autocall off, you can still use '/' at the start of a
+# line to treat the first argument on the command line as a function and add
+# parentheses to it:
+
+#In [8]: /str 43
+#------> str(43)
+#Out[8]: '43'
+
+autocall 1
+
+# Auto-edit syntax errors. When you use the %edit magic in ipython to edit
+# source code (see the 'editor' variable below), it is possible that you save
+# a file with syntax errors in it. If this variable is true, IPython will ask
+# you whether to re-open the editor immediately to correct such an error.
+
+autoedit_syntax 0
+
+# Auto-indent. IPython can recognize lines ending in ':' and indent the next
+# line, while also un-indenting automatically after 'raise' or 'return'.
+
+# This feature uses the readline library, so it will honor your ~/.inputrc
+# configuration (or whatever file your INPUTRC variable points to). Adding
+# the following lines to your .inputrc file can make indent/unindenting more
+# convenient (M-i indents, M-u unindents):
+
+# $if Python
+# "\M-i": " "
+# "\M-u": "\d\d\d\d"
+# $endif
+
+# The feature is potentially a bit dangerous, because it can cause problems
+# with pasting of indented code (the pasted code gets re-indented on each
+# line). But it's a huge time-saver when working interactively. The magic
+# function %autoindent allows you to toggle it on/off at runtime.
+
+autoindent 1
+
+# Auto-magic. This gives you access to all the magic functions without having
+# to prepend them with an % sign. If you define a variable with the same name
+# as a magic function (say who=1), you will need to access the magic function
+# with % (%who in this example). However, if later you delete your variable
+# (del who), you'll recover the automagic calling form.
+
+# Considering that many magic functions provide a lot of shell-like
+# functionality, automagic gives you something close to a full Python+system
+# shell environment (and you can extend it further if you want).
+
+automagic 1
+
+# Size of the output cache. After this many entries are stored, the cache will
+# get flushed. Depending on the size of your intermediate calculations, you
+# may have memory problems if you make it too big, since keeping things in the
+# cache prevents Python from reclaiming the memory for old results. Experiment
+# with a value that works well for you.
+
+# If you choose cache_size 0 IPython will revert to python's regular >>>
+# unnumbered prompt. You will still have _, __ and ___ for your last three
+# results, but that will be it. No dynamic _1, _2, etc. will be created. If
+# you are running on a slow machine or with very limited memory, this may
+# help.
+
+cache_size 1000
+
+# Classic mode: Setting 'classic 1' you lose many of IPython niceties,
+# but that's your choice! Classic 1 -> same as IPython -classic.
+# Note that this is _not_ the normal python interpreter, it's simply
+# IPython emulating most of the classic interpreter's behavior.
+classic 0
+
+# colors - Coloring option for prompts and traceback printouts.
+
+# Currently available schemes: NoColor, Linux, LightBG.
+
+# This option allows coloring the prompts and traceback printouts. This
+# requires a terminal which can properly handle color escape sequences. If you
+# are having problems with this, use the NoColor scheme (uses no color escapes
+# at all).
+
+# The Linux option works well in linux console type environments: dark
+# background with light fonts.
+
+# LightBG is similar to Linux but swaps dark/light colors to be more readable
+# in light background terminals.
+
+# keep uncommented only the one you want:
+colors Linux
+#colors LightBG
+#colors NoColor
+
+########################
+# Note to Windows users
+#
+# Color and readline support is avaialble to Windows users via Gary Bishop's
+# readline library. You can find Gary's tools at
+# http://sourceforge.net/projects/uncpythontools.
+# Note that his readline module requires in turn the ctypes library, available
+# at http://starship.python.net/crew/theller/ctypes.
+########################
+
+# color_info: IPython can display information about objects via a set of
+# functions, and optionally can use colors for this, syntax highlighting
+# source code and various other elements. This information is passed through a
+# pager (it defaults to 'less' if $PAGER is not set).
+
+# If your pager has problems, try to setting it to properly handle escapes
+# (see the less manpage for detail), or disable this option. The magic
+# function %color_info allows you to toggle this interactively for testing.
+
+color_info 1
+
+# confirm_exit: set to 1 if you want IPython to confirm when you try to exit
+# with an EOF (Control-d in Unix, Control-Z/Enter in Windows). Note that using
+# the magic functions %Exit or %Quit you can force a direct exit, bypassing
+# any confirmation.
+
+confirm_exit 1
+
+# Use deep_reload() as a substitute for reload() by default. deep_reload() is
+# still available as dreload() and appears as a builtin.
+
+deep_reload 0
+
+# Which editor to use with the %edit command. If you leave this at 0, IPython
+# will honor your EDITOR environment variable. Since this editor is invoked on
+# the fly by ipython and is meant for editing small code snippets, you may
+# want to use a small, lightweight editor here.
+
+# For Emacs users, setting up your Emacs server properly as described in the
+# manual is a good idea. An alternative is to use jed, a very light editor
+# with much of the feel of Emacs (though not as powerful for heavy-duty work).
+
+editor 0
+
+# log 1 -> same as ipython -log. This automatically logs to ./ipython.log
+log 0
+
+# Same as ipython -Logfile YourLogfileName.
+# Don't use with log 1 (use one or the other)
+logfile ''
+
+# banner 0 -> same as ipython -nobanner
+banner 1
+
+# messages 0 -> same as ipython -nomessages
+messages 1
+
+# Automatically call the pdb debugger after every uncaught exception. If you
+# are used to debugging using pdb, this puts you automatically inside of it
+# after any call (either in IPython or in code called by it) which triggers an
+# exception which goes uncaught.
+pdb 0
+
+# Enable the pprint module for printing. pprint tends to give a more readable
+# display (than print) for complex nested data structures.
+pprint 1
+
+# Prompt strings
+
+# Most bash-like escapes can be used to customize IPython's prompts, as well as
+# a few additional ones which are IPython-specific. All valid prompt escapes
+# are described in detail in the Customization section of the IPython HTML/PDF
+# manual.
+
+# Use \# to represent the current prompt number, and quote them to protect
+# spaces.
+prompt_in1 'In [\#]: '
+
+# \D is replaced by as many dots as there are digits in the
+# current value of \#.
+prompt_in2 ' .\D.: '
+
+prompt_out 'Out[\#]: '
+
+# Select whether to left-pad the output prompts to match the length of the
+# input ones. This allows you for example to use a simple '>' as an output
+# prompt, and yet have the output line up with the input. If set to false,
+# the output prompts will be unpadded (flush left).
+prompts_pad_left 1
+
+# Pylab support: when ipython is started with the -pylab switch, by default it
+# executes 'from matplotlib.pylab import *'. Set this variable to false if you
+# want to disable this behavior.
+
+# For details on pylab, see the matplotlib website:
+# http://matplotlib.sf.net
+pylab_import_all 1
+
+
+# quick 1 -> same as ipython -quick
+quick 0
+
+# Use the readline library (1) or not (0). Most users will want this on, but
+# if you experience strange problems with line management (mainly when using
+# IPython inside Emacs buffers) you may try disabling it. Not having it on
+# prevents you from getting command history with the arrow keys, searching and
+# name completion using TAB.
+
+readline 1
+
+# Screen Length: number of lines of your screen. This is used to control
+# printing of very long strings. Strings longer than this number of lines will
+# be paged with the less command instead of directly printed.
+
+# The default value for this is 0, which means IPython will auto-detect your
+# screen size every time it needs to print. If for some reason this isn't
+# working well (it needs curses support), specify it yourself. Otherwise don't
+# change the default.
+
+screen_length 0
+
+# Prompt separators for input and output.
+# Use \n for newline explicitly, without quotes.
+# Use 0 (like at the cmd line) to turn off a given separator.
+
+# The structure of prompt printing is:
+# (SeparateIn)Input....
+# (SeparateOut)Output...
+# (SeparateOut2), # that is, no newline is printed after Out2
+# By choosing these you can organize your output any way you want.
+
+separate_in \n
+separate_out 0
+separate_out2 0
+
+# 'nosep 1' is a shorthand for '-SeparateIn 0 -SeparateOut 0 -SeparateOut2 0'.
+# Simply removes all input/output separators, overriding the choices above.
+nosep 0
+
+# Wildcard searches - IPython has a system for searching names using
+# shell-like wildcards; type %psearch? for details. This variables sets
+# whether by default such searches should be case sensitive or not. You can
+# always override the default at the system command line or the IPython
+# prompt.
+
+wildcards_case_sensitive 1
+
+# Object information: at what level of detail to display the string form of an
+# object. If set to 0, ipython will compute the string form of any object X,
+# by calling str(X), when X? is typed. If set to 1, str(X) will only be
+# computed when X?? is given, and if set to 2 or higher, it will never be
+# computed (there is no X??? level of detail). This is mostly of use to
+# people who frequently manipulate objects whose string representation is
+# extremely expensive to compute.
+
+object_info_string_level 0
+
+# xmode - Exception reporting mode.
+
+# Valid modes: Plain, Context and Verbose.
+
+# Plain: similar to python's normal traceback printing.
+
+# Context: prints 5 lines of context source code around each line in the
+# traceback.
+
+# Verbose: similar to Context, but additionally prints the variables currently
+# visible where the exception happened (shortening their strings if too
+# long). This can potentially be very slow, if you happen to have a huge data
+# structure whose string representation is complex to compute. Your computer
+# may appear to freeze for a while with cpu usage at 100%. If this occurs, you
+# can cancel the traceback with Ctrl-C (maybe hitting it more than once).
+
+#xmode Plain
+xmode Context
+#xmode Verbose
+
+# multi_line_specials: if true, allow magics, aliases and shell escapes (via
+# !cmd) to be used in multi-line input (like for loops). For example, if you
+# have this active, the following is valid in IPython:
+#
+#In [17]: for i in range(3):
+# ....: mkdir $i
+# ....: !touch $i/hello
+# ....: ls -l $i
+
+multi_line_specials 1
+
+
+# System calls: When IPython makes system calls (e.g. via special syntax like
+# !cmd or !!cmd, or magics like %sc or %sx), it can print the command it is
+# executing to standard output, prefixed by a header string.
+
+system_header "IPython system call: "
+
+system_verbose 1
+
+# wxversion: request a specific wxPython version (used for -wthread)
+
+# Set this to the value of wxPython you want to use, but note that this
+# feature requires you to have the wxversion Python module to work. If you
+# don't have the wxversion module (try 'import wxversion' at the prompt to
+# check) or simply want to leave the system to pick up the default, leave this
+# variable at 0.
+
+wxversion 0
+
+#---------------------------------------------------------------------------
+# Section: Readline configuration (readline is not available for MS-Windows)
+
+# This is done via the following options:
+
+# (i) readline_parse_and_bind: this option can appear as many times as you
+# want, each time defining a string to be executed via a
+# readline.parse_and_bind() command. The syntax for valid commands of this
+# kind can be found by reading the documentation for the GNU readline library,
+# as these commands are of the kind which readline accepts in its
+# configuration file.
+
+# The TAB key can be used to complete names at the command line in one of two
+# ways: 'complete' and 'menu-complete'. The difference is that 'complete' only
+# completes as much as possible while 'menu-complete' cycles through all
+# possible completions. Leave the one you prefer uncommented.
+
+readline_parse_and_bind tab: complete
+#readline_parse_and_bind tab: menu-complete
+
+# This binds Control-l to printing the list of all possible completions when
+# there is more than one (what 'complete' does when hitting TAB twice, or at
+# the first TAB if show-all-if-ambiguous is on)
+readline_parse_and_bind "\C-l": possible-completions
+
+# This forces readline to automatically print the above list when tab
+# completion is set to 'complete'. You can still get this list manually by
+# using the key bound to 'possible-completions' (Control-l by default) or by
+# hitting TAB twice. Turning this on makes the printing happen at the first
+# TAB.
+readline_parse_and_bind set show-all-if-ambiguous on
+
+# If you have TAB set to complete names, you can rebind any key (Control-o by
+# default) to insert a true TAB character.
+readline_parse_and_bind "\C-o": tab-insert
+
+# These commands allow you to indent/unindent easily, with the 4-space
+# convention of the Python coding standards. Since IPython's internal
+# auto-indent system also uses 4 spaces, you should not change the number of
+# spaces in the code below.
+readline_parse_and_bind "\M-i": " "
+readline_parse_and_bind "\M-o": "\d\d\d\d"
+readline_parse_and_bind "\M-I": "\d\d\d\d"
+
+# Bindings for incremental searches in the history. These searches use the
+# string typed so far on the command line and search anything in the previous
+# input history containing them.
+readline_parse_and_bind "\C-r": reverse-search-history
+readline_parse_and_bind "\C-s": forward-search-history
+
+# Bindings for completing the current line in the history of previous
+# commands. This allows you to recall any previous command by typing its first
+# few letters and hitting Control-p, bypassing all intermediate commands which
+# may be in the history (much faster than hitting up-arrow 50 times!)
+readline_parse_and_bind "\C-p": history-search-backward
+readline_parse_and_bind "\C-n": history-search-forward
+
+# I also like to have the same functionality on the plain arrow keys. If you'd
+# rather have the arrows use all the history (and not just match what you've
+# typed so far), comment out or delete the next two lines.
+readline_parse_and_bind "\e[A": history-search-backward
+readline_parse_and_bind "\e[B": history-search-forward
+
+# These are typically on by default under *nix, but not win32.
+readline_parse_and_bind "\C-k": kill-line
+readline_parse_and_bind "\C-u": unix-line-discard
+
+# (ii) readline_remove_delims: a string of characters to be removed from the
+# default word-delimiters list used by readline, so that completions may be
+# performed on strings which contain them.
+
+readline_remove_delims -/~
+
+# (iii) readline_merge_completions: whether to merge the result of all
+# possible completions or not. If true, IPython will complete filenames,
+# python names and aliases and return all possible completions. If you set it
+# to false, each completer is used at a time, and only if it doesn't return
+# any completions is the next one used.
+
+# The default order is: [python_matches, file_matches, alias_matches]
+
+readline_merge_completions 1
+
+# (iv) readline_omit__names: normally hitting <tab> after a '.' in a name
+# will complete all attributes of an object, including all the special methods
+# whose names start with single or double underscores (like __getitem__ or
+# __class__).
+
+# This variable allows you to control this completion behavior:
+
+# readline_omit__names 1 -> completion will omit showing any names starting
+# with two __, but it will still show names starting with one _.
+
+# readline_omit__names 2 -> completion will omit all names beginning with one
+# _ (which obviously means filtering out the double __ ones).
+
+# Even when this option is set, you can still see those names by explicitly
+# typing a _ after the period and hitting <tab>: 'name._<tab>' will always
+# complete attribute names starting with '_'.
+
+# This option is off by default so that new users see all attributes of any
+# objects they are dealing with.
+
+readline_omit__names 0
+
+#---------------------------------------------------------------------------
+# Section: modules to be loaded with 'import ...'
+
+# List, separated by spaces, the names of the modules you want to import
+
+# Example:
+# import_mod sys os
+# will produce internally the statements
+# import sys
+# import os
+
+# Each import is executed in its own try/except block, so if one module
+# fails to load the others will still be ok.
+
+import_mod
+
+#---------------------------------------------------------------------------
+# Section: modules to import some functions from: 'from ... import ...'
+
+# List, one per line, the modules for which you want only to import some
+# functions. Give the module name first and then the name of functions to be
+# imported from that module.
+
+# Example:
+
+# import_some IPython.genutils timing timings
+# will produce internally the statement
+# from IPython.genutils import timing, timings
+
+# timing() and timings() are two IPython utilities for timing the execution of
+# your own functions, which you may find useful. Just commment out the above
+# line if you want to test them.
+
+# If you have more than one modules_some line, each gets its own try/except
+# block (like modules, see above).
+
+import_some
+
+#---------------------------------------------------------------------------
+# Section: modules to import all from : 'from ... import *'
+
+# List (same syntax as import_mod above) those modules for which you want to
+# import all functions. Remember, this is a potentially dangerous thing to do,
+# since it is very easy to overwrite names of things you need. Use with
+# caution.
+
+# Example:
+# import_all sys os
+# will produce internally the statements
+# from sys import *
+# from os import *
+
+# As before, each will be called in a separate try/except block.
+
+import_all
+
+#---------------------------------------------------------------------------
+# Section: Python code to execute.
+
+# Put here code to be explicitly executed (keep it simple!)
+# Put one line of python code per line. All whitespace is removed (this is a
+# feature, not a bug), so don't get fancy building loops here.
+# This is just for quick convenient creation of things you want available.
+
+# Example:
+# execute x = 1
+# execute print 'hello world'; y = z = 'a'
+# will produce internally
+# x = 1
+# print 'hello world'; y = z = 'a'
+# and each *line* (not each statement, we don't do python syntax parsing) is
+# executed in its own try/except block.
+
+execute
+
+# Note for the adventurous: you can use this to define your own names for the
+# magic functions, by playing some namespace tricks:
+
+# execute __IPYTHON__.magic_pf = __IPYTHON__.magic_profile
+
+# defines %pf as a new name for %profile.
+
+#---------------------------------------------------------------------------
+# Section: Pyhton files to load and execute.
+
+# Put here the full names of files you want executed with execfile(file). If
+# you want complicated initialization, just write whatever you want in a
+# regular python file and load it from here.
+
+# Filenames defined here (which *must* include the extension) are searched for
+# through all of sys.path. Since IPython adds your .ipython directory to
+# sys.path, they can also be placed in your .ipython dir and will be
+# found. Otherwise (if you want to execute things not in .ipyton nor in
+# sys.path) give a full path (you can use ~, it gets expanded)
+
+# Example:
+# execfile file1.py ~/file2.py
+# will generate
+# execfile('file1.py')
+# execfile('_path_to_your_home/file2.py')
+
+# As before, each file gets its own try/except block.
+
+execfile
+
+# If you are feeling adventurous, you can even add functionality to IPython
+# through here. IPython works through a global variable called __ip which
+# exists at the time when these files are read. If you know what you are doing
+# (read the source) you can add functions to __ip in files loaded here.
+
+# The file example-magic.py contains a simple but correct example. Try it:
+
+# execfile example-magic.py
+
+# Look at the examples in IPython/iplib.py for more details on how these magic
+# functions need to process their arguments.
+
+#---------------------------------------------------------------------------
+# Section: aliases for system shell commands
+
+# Here you can define your own names for system commands. The syntax is
+# similar to that of the builtin %alias function:
+
+# alias alias_name command_string
+
+# The resulting aliases are auto-generated magic functions (hence usable as
+# %alias_name)
+
+# For example:
+
+# alias myls ls -la
+
+# will define 'myls' as an alias for executing the system command 'ls -la'.
+# This allows you to customize IPython's environment to have the same aliases
+# you are accustomed to from your own shell.
+
+# You can also define aliases with parameters using %s specifiers (one per
+# parameter):
+
+# alias parts echo first %s second %s
+
+# will give you in IPython:
+# >>> %parts A B
+# first A second B
+
+# Use one 'alias' statement per alias you wish to define.
+
+# alias
+
+#************************* end of file <ipythonrc> ************************
diff --git a/IPython/UserConfig/ipythonrc-math b/IPython/UserConfig/ipythonrc-math
new file mode 100644
index 0000000..c32bcd1
--- /dev/null
+++ b/IPython/UserConfig/ipythonrc-math
@@ -0,0 +1,36 @@
+# -*- Mode: Shell-Script -*- Not really, but shows comments correctly
+#***************************************************************************
+#
+# Configuration file for ipython -- ipythonrc format
+#
+# The format of this file is one of 'key value' lines.
+# Lines containing only whitespace at the beginning and then a # are ignored
+# as comments. But comments can NOT be put on lines with data.
+#***************************************************************************
+
+# This is an example of a 'profile' file which includes a base file and adds
+# some customizaton for a particular purpose.
+
+# If this file is found in the user's ~/.ipython directory as ipythonrc-math,
+# it can be loaded by calling passing the '-profile math' (or '-p math')
+# option to IPython.
+
+# This example is a light customization to have ipython have basic math functions
+# readily available, effectively making the python prompt a very capable scientific
+# calculator
+
+# include base config and only add some extras
+include ipythonrc
+
+# load the complex math functions but keep them in a separate namespace
+import_mod cmath
+
+# from ... import *
+# load the real math functions in the global namespace for convenience
+import_all math
+
+# from ... import ...
+import_some
+
+# code to execute
+execute print "*** math functions available globally, cmath as a module"
diff --git a/IPython/UserConfig/ipythonrc-numeric b/IPython/UserConfig/ipythonrc-numeric
new file mode 100644
index 0000000..1700ca0
--- /dev/null
+++ b/IPython/UserConfig/ipythonrc-numeric
@@ -0,0 +1,57 @@
+# -*- Mode: Shell-Script -*- Not really, but shows comments correctly
+#***************************************************************************
+#
+# Configuration file for ipython -- ipythonrc format
+#
+# The format of this file is one of 'key value' lines.
+# Lines containing only whitespace at the beginning and then a # are ignored
+# as comments. But comments can NOT be put on lines with data.
+#***************************************************************************
+
+# This is an example of a 'profile' file which includes a base file and adds
+# some customizaton for a particular purpose.
+
+# If this file is found in the user's ~/.ipython directory as
+# ipythonrc-numeric, it can be loaded by calling passing the '-profile
+# numeric' (or '-p numeric') option to IPython.
+
+# A simple alias numpy -> 'ipython -p numeric' makes life very convenient.
+
+# This example is meant to load several modules to turn IPython into a very
+# capable environment for high-end numerical work, similar to IDL or MatLab
+# but with the beauty and flexibility of the Python language.
+
+# Load the user's basic configuration
+include ipythonrc
+
+# import ...
+
+# Load Numeric by itself so that 'help Numeric' works
+import_mod Numeric
+
+# from ... import *
+# GnuplotRuntime loads Gnuplot and adds enhancements for use in IPython
+import_all Numeric IPython.numutils IPython.GnuplotInteractive
+
+# a simple line at zero, often useful for an x-axis
+execute xaxis=gpfunc('0',title='',with='lines lt -1')
+
+# Below are optional things off by default. Uncomment them if desired.
+
+# MA (MaskedArray) modifies the Numeric printing mechanism so that huge arrays
+# are only summarized and not printed (which may freeze the machine for a
+# _long_ time).
+
+#import_mod MA
+
+
+# gracePlot is a Python interface to the plotting package Grace.
+# For more details go to: http://www.idyll.org/~n8gray/code/index.html
+# Uncomment lines below if you have grace and its python support code
+
+#import_mod gracePlot
+#execute grace = gracePlot.gracePlot # alias to make gracePlot instances
+#execute print '*** grace is an alias for gracePlot.gracePlot'
+
+# Files to execute
+execfile
diff --git a/IPython/UserConfig/ipythonrc-physics b/IPython/UserConfig/ipythonrc-physics
new file mode 100644
index 0000000..c7c25a3
--- /dev/null
+++ b/IPython/UserConfig/ipythonrc-physics
@@ -0,0 +1,45 @@
+# -*- Mode: Shell-Script -*- Not really, but shows comments correctly
+#***************************************************************************
+#
+# Configuration file for ipython -- ipythonrc format
+#
+# The format of this file is one of 'key value' lines.
+# Lines containing only whitespace at the beginning and then a # are ignored
+# as comments. But comments can NOT be put on lines with data.
+#***************************************************************************
+
+# If this file is found in the user's ~/.ipython directory as
+# ipythonrc-physics, it can be loaded by calling passing the '-profile
+# physics' (or '-p physics') option to IPython.
+
+# This profile loads modules useful for doing interactive calculations with
+# physical quantities (with units). It relies on modules from Konrad Hinsen's
+# ScientificPython (http://dirac.cnrs-orleans.fr/ScientificPython/)
+
+# First load basic user configuration
+include ipythonrc
+
+# import ...
+# Module with alternate input syntax for PhysicalQuantity objects.
+import_mod IPython.Extensions.PhysicalQInput
+
+# from ... import *
+# math CANNOT be imported after PhysicalQInteractive. It will override the
+# functions defined there.
+import_all math IPython.Extensions.PhysicalQInteractive
+
+# from ... import ...
+import_some
+
+# code
+execute q = PhysicalQuantityInteractive
+execute g = PhysicalQuantityInteractive('9.8 m/s**2')
+ececute rad = pi/180.
+execute print '*** q is an alias for PhysicalQuantityInteractive'
+execute print '*** g = 9.8 m/s^2 has been defined'
+execute print '*** rad = pi/180 has been defined'
+execute import ipy_constants as C
+execute print '*** C is the physical constants module'
+
+# Files to execute
+execfile
diff --git a/IPython/UserConfig/ipythonrc-pysh b/IPython/UserConfig/ipythonrc-pysh
new file mode 100644
index 0000000..2c7d204
--- /dev/null
+++ b/IPython/UserConfig/ipythonrc-pysh
@@ -0,0 +1,94 @@
+# -*- Mode: Shell-Script -*- Not really, but shows comments correctly
+#***************************************************************************
+# Configuration file for ipython -- ipythonrc format
+#
+# The format of this file is one of 'key value' lines.
+# Lines containing only whitespace at the beginning and then a # are ignored
+# as comments. But comments can NOT be put on lines with data.
+#***************************************************************************
+
+# If this file is found in the user's ~/.ipython directory as ipythonrc-pysh,
+# it can be loaded by calling passing the '-profile pysh' (or '-p pysh')
+# option to IPython.
+
+# This profile turns IPython into a lightweight system shell with python
+# syntax.
+
+# We only set a few options here, the rest is done in the companion pysh.py
+# file. In the future _all_ of IPython's configuration will be done via
+# proper python code.
+
+############################################################################
+# First load common user configuration
+include ipythonrc
+
+############################################################################
+# Load all the actual syntax extensions for shell-like operation, which live
+# in the InterpreterExec standard extension.
+import_all IPython.Extensions.InterpreterExec
+
+############################################################################
+# PROMPTS
+#
+# Configure prompt for more shell-like usage.
+
+# Most bash-like escapes can be used to customize IPython's prompts, as well as
+# a few additional ones which are IPython-specific. All valid prompt escapes
+# are described in detail in the Customization section of the IPython HTML/PDF
+# manual.
+
+prompt_in1 '\C_LightGreen\u@\h\C_LightBlue[\C_LightCyan\Y1\C_LightBlue]\C_Green|\#> '
+prompt_in2 '\C_Green|\C_LightGreen\D\C_Green> '
+prompt_out '<\#> '
+
+# Here's a more complex prompt, showing the hostname and more path depth (\Y3)
+#prompt_in1 '\C_LightRed\u\C_Blue@\C_Red\h\C_LightBlue[\C_LightCyan\Y3\C_LightBlue]\C_LightGreen\#> '
+
+# Select whether to left-pad the output prompts to match the length of the
+# input ones. This allows you for example to use a simple '>' as an output
+# prompt, and yet have the output line up with the input. If set to false,
+# the output prompts will be unpadded (flush left).
+prompts_pad_left 1
+
+
+# Remove all blank lines in between prompts, like a normal shell.
+separate_in 0
+separate_out 0
+separate_out2 0
+
+# Allow special syntax (!, magics and aliases) in multiline input
+multi_line_specials 1
+
+############################################################################
+# ALIASES
+
+# Declare some common aliases. Type alias? at an ipython prompt for details on
+# the syntax, use @unalias to delete existing aliases.
+
+# Don't go too crazy here, the file pysh.py called below runs @rehash, which
+# loads ALL of your $PATH as aliases (except for Python keywords and
+# builtins).
+
+# Some examples:
+
+# A simple alias without arguments
+#alias cl clear
+
+# An alias which expands the full line before the end of the alias. This
+# lists only directories:
+#alias ldir pwd;ls -oF --color %l | grep /$
+
+# An alias with two positional arguments:
+#alias parts echo 'First <%s> Second <%s>'
+
+# In use these two aliases give (note that ldir is already built into IPython
+# for Unix):
+
+#fperez[IPython]16> ldir
+#/usr/local/home/fperez/ipython/ipython/IPython
+#drwxr-xr-x 2 fperez 4096 Jun 21 01:01 CVS/
+#drwxr-xr-x 3 fperez 4096 Jun 21 01:10 Extensions/
+#drwxr-xr-x 3 fperez 4096 Jun 21 01:27 UserConfig/
+
+#fperez[IPython]17> parts Hello world and goodbye
+#First <Hello> Second <world> and goodbye
diff --git a/IPython/UserConfig/ipythonrc-tutorial b/IPython/UserConfig/ipythonrc-tutorial
new file mode 100644
index 0000000..6c97569
--- /dev/null
+++ b/IPython/UserConfig/ipythonrc-tutorial
@@ -0,0 +1,37 @@
+# -*- Mode: Shell-Script -*- Not really, but shows comments correctly
+#***************************************************************************
+#
+# Configuration file for ipython -- ipythonrc format
+#
+# The format of this file is one of 'key value' lines.
+# Lines containing only whitespace at the beginning and then a # are ignored
+# as comments. But comments can NOT be put on lines with data.
+#***************************************************************************
+
+# If this file is found in the user's ~/.ipython directory as
+# ipythonrc-tutorial, it can be loaded by calling passing the '-profile
+# tutorial' (or '-p tutorial') option to IPython.
+
+# This profile loads a special input line filter to allow typing lines which
+# begin with '>>> ' or '... '. These two strings, if present at the start of
+# the input line, are stripped. This allows for direct pasting of code from
+# examples such as those available in the standard Python tutorial.
+
+# First load basic user configuration
+include ipythonrc
+
+# import ...
+# Module with alternate input syntax for pasting python input
+import_mod IPython.Extensions.InterpreterPasteInput
+
+# from ... import *
+import_all
+
+# from ... import ...
+import_some
+
+# code
+execute
+
+# Files to execute
+execfile
diff --git a/IPython/__init__.py b/IPython/__init__.py
new file mode 100644
index 0000000..2fb3281
--- /dev/null
+++ b/IPython/__init__.py
@@ -0,0 +1,72 @@
+# -*- coding: utf-8 -*-
+"""
+IPython -- An enhanced Interactive Python
+
+One of Python's nicest features is its interactive interpreter. This allows
+very fast testing of ideas without the overhead of creating test files as is
+typical in most programming languages. However, the interpreter supplied with
+the standard Python distribution is fairly primitive (and IDLE isn't really
+much better).
+
+IPython tries to:
+
+ i - provide an efficient environment for interactive work in Python
+ programming. It tries to address what we see as shortcomings of the standard
+ Python prompt, and adds many features to make interactive work much more
+ efficient.
+
+ ii - offer a flexible framework so that it can be used as the base
+ environment for other projects and problems where Python can be the
+ underlying language. Specifically scientific environments like Mathematica,
+ IDL and Mathcad inspired its design, but similar ideas can be useful in many
+ fields. Python is a fabulous language for implementing this kind of system
+ (due to its dynamic and introspective features), and with suitable libraries
+ entire systems could be built leveraging Python's power.
+
+ iii - serve as an embeddable, ready to go interpreter for your own programs.
+
+IPython requires Python 2.4 or newer.
+"""
+
+#*****************************************************************************
+# Copyright (C) 2008-2009 The IPython Development Team
+# Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#*****************************************************************************
+
+# Enforce proper version requirements
+import sys
+
+if sys.version[0:3] < '2.4':
+ raise ImportError('Python Version 2.4 or above is required for IPython.')
+
+# Make it easy to import extensions - they are always directly on pythonpath.
+# Therefore, non-IPython modules can be added to Extensions directory
+import os
+sys.path.append(os.path.dirname(__file__) + "/Extensions")
+
+# Define what gets imported with a 'from IPython import *'
+__all__ = ['ipapi','generics','ipstruct','Release','Shell']
+
+# Load __all__ in IPython namespace so that a simple 'import IPython' gives
+# access to them via IPython.<name>
+glob,loc = globals(),locals()
+for name in __all__:
+ #print 'Importing: ',name # dbg
+ __import__(name,glob,loc,[])
+
+import Shell
+
+# Release data
+from IPython import Release # do it explicitly so pydoc can see it - pydoc bug
+__author__ = '%s <%s>\n%s <%s>\n%s <%s>' % \
+ ( Release.authors['Fernando'] + Release.authors['Janko'] + \
+ Release.authors['Nathan'] )
+__license__ = Release.license
+__version__ = Release.version
+__revision__ = Release.revision
+
+# Namespace cleanup
+del name,glob,loc
diff --git a/IPython/background_jobs.py b/IPython/background_jobs.py
new file mode 100644
index 0000000..c5998c3
--- /dev/null
+++ b/IPython/background_jobs.py
@@ -0,0 +1,490 @@
+# -*- coding: utf-8 -*-
+"""Manage background (threaded) jobs conveniently from an interactive shell.
+
+This module provides a BackgroundJobManager class. This is the main class
+meant for public usage, it implements an object which can create and manage
+new background jobs.
+
+It also provides the actual job classes managed by these BackgroundJobManager
+objects, see their docstrings below.
+
+
+This system was inspired by discussions with B. Granger and the
+BackgroundCommand class described in the book Python Scripting for
+Computational Science, by H. P. Langtangen:
+
+http://folk.uio.no/hpl/scripting
+
+(although ultimately no code from this text was used, as IPython's system is a
+separate implementation).
+"""
+
+#*****************************************************************************
+# Copyright (C) 2005-2006 Fernando Perez <fperez@colorado.edu>
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#*****************************************************************************
+
+# Code begins
+import sys
+import threading
+
+from IPython.ultraTB import AutoFormattedTB
+from IPython.genutils import warn,error
+
+class BackgroundJobManager:
+ """Class to manage a pool of backgrounded threaded jobs.
+
+ Below, we assume that 'jobs' is a BackgroundJobManager instance.
+
+ Usage summary (see the method docstrings for details):
+
+ jobs.new(...) -> start a new job
+
+ jobs() or jobs.status() -> print status summary of all jobs
+
+ jobs[N] -> returns job number N.
+
+ foo = jobs[N].result -> assign to variable foo the result of job N
+
+ jobs[N].traceback() -> print the traceback of dead job N
+
+ jobs.remove(N) -> remove (finished) job N
+
+ jobs.flush_finished() -> remove all finished jobs
+
+ As a convenience feature, BackgroundJobManager instances provide the
+ utility result and traceback methods which retrieve the corresponding
+ information from the jobs list:
+
+ jobs.result(N) <--> jobs[N].result
+ jobs.traceback(N) <--> jobs[N].traceback()
+
+ While this appears minor, it allows you to use tab completion
+ interactively on the job manager instance.
+
+ In interactive mode, IPython provides the magic fuction %bg for quick
+ creation of backgrounded expression-based jobs. Type bg? for details."""
+
+ def __init__(self):
+ # Lists for job management
+ self.jobs_run = []
+ self.jobs_comp = []
+ self.jobs_dead = []
+ # A dict of all jobs, so users can easily access any of them
+ self.jobs_all = {}
+ # For reporting
+ self._comp_report = []
+ self._dead_report = []
+ # Store status codes locally for fast lookups
+ self._s_created = BackgroundJobBase.stat_created_c
+ self._s_running = BackgroundJobBase.stat_running_c
+ self._s_completed = BackgroundJobBase.stat_completed_c
+ self._s_dead = BackgroundJobBase.stat_dead_c
+
+ def new(self,func_or_exp,*args,**kwargs):
+ """Add a new background job and start it in a separate thread.
+
+ There are two types of jobs which can be created:
+
+ 1. Jobs based on expressions which can be passed to an eval() call.
+ The expression must be given as a string. For example:
+
+ job_manager.new('myfunc(x,y,z=1)'[,glob[,loc]])
+
+ The given expression is passed to eval(), along with the optional
+ global/local dicts provided. If no dicts are given, they are
+ extracted automatically from the caller's frame.
+
+ A Python statement is NOT a valid eval() expression. Basically, you
+ can only use as an eval() argument something which can go on the right
+ of an '=' sign and be assigned to a variable.
+
+ For example,"print 'hello'" is not valid, but '2+3' is.
+
+ 2. Jobs given a function object, optionally passing additional
+ positional arguments:
+
+ job_manager.new(myfunc,x,y)
+
+ The function is called with the given arguments.
+
+ If you need to pass keyword arguments to your function, you must
+ supply them as a dict named kw:
+
+ job_manager.new(myfunc,x,y,kw=dict(z=1))
+
+ The reason for this assymmetry is that the new() method needs to
+ maintain access to its own keywords, and this prevents name collisions
+ between arguments to new() and arguments to your own functions.
+
+ In both cases, the result is stored in the job.result field of the
+ background job object.
+
+
+ Notes and caveats:
+
+ 1. All threads running share the same standard output. Thus, if your
+ background jobs generate output, it will come out on top of whatever
+ you are currently writing. For this reason, background jobs are best
+ used with silent functions which simply return their output.
+
+ 2. Threads also all work within the same global namespace, and this
+ system does not lock interactive variables. So if you send job to the
+ background which operates on a mutable object for a long time, and
+ start modifying that same mutable object interactively (or in another
+ backgrounded job), all sorts of bizarre behaviour will occur.
+
+ 3. If a background job is spending a lot of time inside a C extension
+ module which does not release the Python Global Interpreter Lock
+ (GIL), this will block the IPython prompt. This is simply because the
+ Python interpreter can only switch between threads at Python
+ bytecodes. While the execution is inside C code, the interpreter must
+ simply wait unless the extension module releases the GIL.
+
+ 4. There is no way, due to limitations in the Python threads library,
+ to kill a thread once it has started."""
+
+ if callable(func_or_exp):
+ kw = kwargs.get('kw',{})
+ job = BackgroundJobFunc(func_or_exp,*args,**kw)
+ elif isinstance(func_or_exp,basestring):
+ if not args:
+ frame = sys._getframe(1)
+ glob, loc = frame.f_globals, frame.f_locals
+ elif len(args)==1:
+ glob = loc = args[0]
+ elif len(args)==2:
+ glob,loc = args
+ else:
+ raise ValueError,\
+ 'Expression jobs take at most 2 args (globals,locals)'
+ job = BackgroundJobExpr(func_or_exp,glob,loc)
+ else:
+ raise
+ jkeys = self.jobs_all.keys()
+ if jkeys:
+ job.num = max(jkeys)+1
+ else:
+ job.num = 0
+ self.jobs_run.append(job)
+ self.jobs_all[job.num] = job
+ print 'Starting job # %s in a separate thread.' % job.num
+ job.start()
+ return job
+
+ def __getitem__(self,key):
+ return self.jobs_all[key]
+
+ def __call__(self):
+ """An alias to self.status(),
+
+ This allows you to simply call a job manager instance much like the
+ Unix jobs shell command."""
+
+ return self.status()
+
+ def _update_status(self):
+ """Update the status of the job lists.
+
+ This method moves finished jobs to one of two lists:
+ - self.jobs_comp: jobs which completed successfully
+ - self.jobs_dead: jobs which finished but died.
+
+ It also copies those jobs to corresponding _report lists. These lists
+ are used to report jobs completed/dead since the last update, and are
+ then cleared by the reporting function after each call."""
+
+ run,comp,dead = self._s_running,self._s_completed,self._s_dead
+ jobs_run = self.jobs_run
+ for num in range(len(jobs_run)):
+ job = jobs_run[num]
+ stat = job.stat_code
+ if stat == run:
+ continue
+ elif stat == comp:
+ self.jobs_comp.append(job)
+ self._comp_report.append(job)
+ jobs_run[num] = False
+ elif stat == dead:
+ self.jobs_dead.append(job)
+ self._dead_report.append(job)
+ jobs_run[num] = False
+ self.jobs_run = filter(None,self.jobs_run)
+
+ def _group_report(self,group,name):
+ """Report summary for a given job group.
+
+ Return True if the group had any elements."""
+
+ if group:
+ print '%s jobs:' % name
+ for job in group:
+ print '%s : %s' % (job.num,job)
+ print
+ return True
+
+ def _group_flush(self,group,name):
+ """Flush a given job group
+
+ Return True if the group had any elements."""
+
+ njobs = len(group)
+ if njobs:
+ plural = {1:''}.setdefault(njobs,'s')
+ print 'Flushing %s %s job%s.' % (njobs,name,plural)
+ group[:] = []
+ return True
+
+ def _status_new(self):
+ """Print the status of newly finished jobs.
+
+ Return True if any new jobs are reported.
+
+ This call resets its own state every time, so it only reports jobs
+ which have finished since the last time it was called."""
+
+ self._update_status()
+ new_comp = self._group_report(self._comp_report,'Completed')
+ new_dead = self._group_report(self._dead_report,
+ 'Dead, call jobs.traceback() for details')
+ self._comp_report[:] = []
+ self._dead_report[:] = []
+ return new_comp or new_dead
+
+ def status(self,verbose=0):
+ """Print a status of all jobs currently being managed."""
+
+ self._update_status()
+ self._group_report(self.jobs_run,'Running')
+ self._group_report(self.jobs_comp,'Completed')
+ self._group_report(self.jobs_dead,'Dead')
+ # Also flush the report queues
+ self._comp_report[:] = []
+ self._dead_report[:] = []
+
+ def remove(self,num):
+ """Remove a finished (completed or dead) job."""
+
+ try:
+ job = self.jobs_all[num]
+ except KeyError:
+ error('Job #%s not found' % num)
+ else:
+ stat_code = job.stat_code
+ if stat_code == self._s_running:
+ error('Job #%s is still running, it can not be removed.' % num)
+ return
+ elif stat_code == self._s_completed:
+ self.jobs_comp.remove(job)
+ elif stat_code == self._s_dead:
+ self.jobs_dead.remove(job)
+
+ def flush_finished(self):
+ """Flush all jobs finished (completed and dead) from lists.
+
+ Running jobs are never flushed.
+
+ It first calls _status_new(), to update info. If any jobs have
+ completed since the last _status_new() call, the flush operation
+ aborts."""
+
+ if self._status_new():
+ error('New jobs completed since last '\
+ '_status_new(), aborting flush.')
+ return
+
+ # Remove the finished jobs from the master dict
+ jobs_all = self.jobs_all
+ for job in self.jobs_comp+self.jobs_dead:
+ del(jobs_all[job.num])
+
+ # Now flush these lists completely
+ fl_comp = self._group_flush(self.jobs_comp,'Completed')
+ fl_dead = self._group_flush(self.jobs_dead,'Dead')
+ if not (fl_comp or fl_dead):
+ print 'No jobs to flush.'
+
+ def result(self,num):
+ """result(N) -> return the result of job N."""
+ try:
+ return self.jobs_all[num].result
+ except KeyError:
+ error('Job #%s not found' % num)
+
+ def traceback(self,num):
+ try:
+ self.jobs_all[num].traceback()
+ except KeyError:
+ error('Job #%s not found' % num)
+
+
+class BackgroundJobBase(threading.Thread):
+ """Base class to build BackgroundJob classes.
+
+ The derived classes must implement:
+
+ - Their own __init__, since the one here raises NotImplementedError. The
+ derived constructor must call self._init() at the end, to provide common
+ initialization.
+
+ - A strform attribute used in calls to __str__.
+
+ - A call() method, which will make the actual execution call and must
+ return a value to be held in the 'result' field of the job object."""
+
+ # Class constants for status, in string and as numerical codes (when
+ # updating jobs lists, we don't want to do string comparisons). This will
+ # be done at every user prompt, so it has to be as fast as possible
+ stat_created = 'Created'; stat_created_c = 0
+ stat_running = 'Running'; stat_running_c = 1
+ stat_completed = 'Completed'; stat_completed_c = 2
+ stat_dead = 'Dead (Exception), call jobs.traceback() for details'
+ stat_dead_c = -1
+
+ def __init__(self):
+ raise NotImplementedError, \
+ "This class can not be instantiated directly."
+
+ def _init(self):
+ """Common initialization for all BackgroundJob objects"""
+
+ for attr in ['call','strform']:
+ assert hasattr(self,attr), "Missing attribute <%s>" % attr
+
+ # The num tag can be set by an external job manager
+ self.num = None
+
+ self.status = BackgroundJobBase.stat_created
+ self.stat_code = BackgroundJobBase.stat_created_c
+ self.finished = False
+ self.result = '<BackgroundJob has not completed>'
+ # reuse the ipython traceback handler if we can get to it, otherwise
+ # make a new one
+ try:
+ self._make_tb = __IPYTHON__.InteractiveTB.text
+ except:
+ self._make_tb = AutoFormattedTB(mode = 'Context',
+ color_scheme='NoColor',
+ tb_offset = 1).text
+ # Hold a formatted traceback if one is generated.
+ self._tb = None
+
+ threading.Thread.__init__(self)
+
+ def __str__(self):
+ return self.strform
+
+ def __repr__(self):
+ return '<BackgroundJob: %s>' % self.strform
+
+ def traceback(self):
+ print self._tb
+
+ def run(self):
+ try:
+ self.status = BackgroundJobBase.stat_running
+ self.stat_code = BackgroundJobBase.stat_running_c
+ self.result = self.call()
+ except:
+ self.status = BackgroundJobBase.stat_dead
+ self.stat_code = BackgroundJobBase.stat_dead_c
+ self.finished = None
+ self.result = ('<BackgroundJob died, call jobs.traceback() for details>')
+ self._tb = self._make_tb()
+ else:
+ self.status = BackgroundJobBase.stat_completed
+ self.stat_code = BackgroundJobBase.stat_completed_c
+ self.finished = True
+
+class BackgroundJobExpr(BackgroundJobBase):
+ """Evaluate an expression as a background job (uses a separate thread)."""
+
+ def __init__(self,expression,glob=None,loc=None):
+ """Create a new job from a string which can be fed to eval().
+
+ global/locals dicts can be provided, which will be passed to the eval
+ call."""
+
+ # fail immediately if the given expression can't be compiled
+ self.code = compile(expression,'<BackgroundJob compilation>','eval')
+
+ if glob is None:
+ glob = {}
+ if loc is None:
+ loc = {}
+
+ self.expression = self.strform = expression
+ self.glob = glob
+ self.loc = loc
+ self._init()
+
+ def call(self):
+ return eval(self.code,self.glob,self.loc)
+
+class BackgroundJobFunc(BackgroundJobBase):
+ """Run a function call as a background job (uses a separate thread)."""
+
+ def __init__(self,func,*args,**kwargs):
+ """Create a new job from a callable object.
+
+ Any positional arguments and keyword args given to this constructor
+ after the initial callable are passed directly to it."""
+
+ assert callable(func),'first argument must be callable'
+
+ if args is None:
+ args = []
+ if kwargs is None:
+ kwargs = {}
+
+ self.func = func
+ self.args = args
+ self.kwargs = kwargs
+ # The string form will only include the function passed, because
+ # generating string representations of the arguments is a potentially
+ # _very_ expensive operation (e.g. with large arrays).
+ self.strform = str(func)
+ self._init()
+
+ def call(self):
+ return self.func(*self.args,**self.kwargs)
+
+
+if __name__=='__main__':
+
+ import time
+
+ def sleepfunc(interval=2,*a,**kw):
+ args = dict(interval=interval,
+ args=a,
+ kwargs=kw)
+ time.sleep(interval)
+ return args
+
+ def diefunc(interval=2,*a,**kw):
+ time.sleep(interval)
+ die
+
+ def printfunc(interval=1,reps=5):
+ for n in range(reps):
+ time.sleep(interval)
+ print 'In the background...'
+
+ jobs = BackgroundJobManager()
+ # first job will have # 0
+ jobs.new(sleepfunc,4)
+ jobs.new(sleepfunc,kw={'reps':2})
+ # This makes a job which will die
+ jobs.new(diefunc,1)
+ jobs.new('printfunc(1,3)')
+
+ # after a while, you can get the traceback of a dead job. Run the line
+ # below again interactively until it prints a traceback (check the status
+ # of the job):
+ print jobs[1].status
+ jobs[1].traceback()
+
+ # Run this line again until the printed result changes
+ print "The result of job #0 is:",jobs[0].result
diff --git a/IPython/clipboard.py b/IPython/clipboard.py
new file mode 100644
index 0000000..6607f6e
--- /dev/null
+++ b/IPython/clipboard.py
@@ -0,0 +1,56 @@
+""" Utilities for accessing the platform's clipboard.
+"""
+
+import subprocess
+import sys
+
+from IPython.ipapi import TryNext
+
+
+def win32_clipboard_get():
+ """ Get the current clipboard's text on Windows.
+
+ Requires Mark Hammond's pywin32 extensions.
+ """
+ try:
+ import win32clipboard
+ except ImportError:
+ message = ("Getting text from the clipboard requires the pywin32 "
+ "extensions: http://sourceforge.net/projects/pywin32/")
+ raise TryNext(message)
+ win32clipboard.OpenClipboard()
+ text = win32clipboard.GetClipboardData(win32clipboard.CF_TEXT)
+ # FIXME: convert \r\n to \n?
+ win32clipboard.CloseClipboard()
+ return text
+
+def osx_clipboard_get():
+ """ Get the clipboard's text on OS X.
+ """
+ p = subprocess.Popen(['pbpaste', '-Prefer', 'ascii'],
+ stdout=subprocess.PIPE)
+ text, stderr = p.communicate()
+ # Text comes in with old Mac \r line endings. Change them to \n.
+ text = text.replace('\r', '\n')
+ return text
+
+def tkinter_clipboard_get():
+ """ Get the clipboard's text using Tkinter.
+
+ This is the default on systems that are not Windows or OS X. It may
+ interfere with other UI toolkits and should be replaced with an
+ implementation that uses that toolkit.
+ """
+ try:
+ import Tkinter
+ except ImportError:
+ message = ("Getting text from the clipboard on this platform "
+ "requires Tkinter.")
+ raise TryNext(message)
+ root = Tkinter.Tk()
+ root.withdraw()
+ text = root.clipboard_get()
+ root.destroy()
+ return text
+
+
diff --git a/IPython/completer.py b/IPython/completer.py
new file mode 100644
index 0000000..b8b5334
--- /dev/null
+++ b/IPython/completer.py
@@ -0,0 +1,639 @@
+"""Word completion for IPython.
+
+This module is a fork of the rlcompleter module in the Python standard
+library. The original enhancements made to rlcompleter have been sent
+upstream and were accepted as of Python 2.3, but we need a lot more
+functionality specific to IPython, so this module will continue to live as an
+IPython-specific utility.
+
+Original rlcompleter documentation:
+
+This requires the latest extension to the readline module (the
+completes keywords, built-ins and globals in __main__; when completing
+NAME.NAME..., it evaluates (!) the expression up to the last dot and
+completes its attributes.
+
+It's very cool to do "import string" type "string.", hit the
+completion key (twice), and see the list of names defined by the
+string module!
+
+Tip: to use the tab key as the completion key, call
+
+ readline.parse_and_bind("tab: complete")
+
+Notes:
+
+- Exceptions raised by the completer function are *ignored* (and
+generally cause the completion to fail). This is a feature -- since
+readline sets the tty device in raw (or cbreak) mode, printing a
+traceback wouldn't work well without some complicated hoopla to save,
+reset and restore the tty state.
+
+- The evaluation of the NAME.NAME... form may cause arbitrary
+application defined code to be executed if an object with a
+__getattr__ hook is found. Since it is the responsibility of the
+application (or the user) to enable this feature, I consider this an
+acceptable risk. More complicated expressions (e.g. function calls or
+indexing operations) are *not* evaluated.
+
+- GNU readline is also used by the built-in functions input() and
+raw_input(), and thus these also benefit/suffer from the completer
+features. Clearly an interactive application can benefit by
+specifying its own completer function and using raw_input() for all
+its input.
+
+- When the original stdin is not a tty device, GNU readline is never
+used, and this module (and the readline module) are silently inactive.
+
+"""
+
+#*****************************************************************************
+#
+# Since this file is essentially a minimally modified copy of the rlcompleter
+# module which is part of the standard Python distribution, I assume that the
+# proper procedure is to maintain its copyright as belonging to the Python
+# Software Foundation (in addition to my own, for all new code).
+#
+# Copyright (C) 2001 Python Software Foundation, www.python.org
+# Copyright (C) 2001-2006 Fernando Perez. <fperez@colorado.edu>
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#
+#*****************************************************************************
+
+import __builtin__
+import __main__
+import glob
+import keyword
+import os
+import re
+import shlex
+import sys
+import IPython.rlineimpl as readline
+import itertools
+from IPython.ipstruct import Struct
+from IPython import ipapi
+from IPython import generics
+import types
+
+# Python 2.4 offers sets as a builtin
+try:
+ set()
+except NameError:
+ from sets import Set as set
+
+from IPython.genutils import debugx, dir2
+
+__all__ = ['Completer','IPCompleter']
+
+class Completer:
+ def __init__(self,namespace=None,global_namespace=None):
+ """Create a new completer for the command line.
+
+ Completer([namespace,global_namespace]) -> completer instance.
+
+ If unspecified, the default namespace where completions are performed
+ is __main__ (technically, __main__.__dict__). Namespaces should be
+ given as dictionaries.
+
+ An optional second namespace can be given. This allows the completer
+ to handle cases where both the local and global scopes need to be
+ distinguished.
+
+ Completer instances should be used as the completion mechanism of
+ readline via the set_completer() call:
+
+ readline.set_completer(Completer(my_namespace).complete)
+ """
+
+ # Don't bind to namespace quite yet, but flag whether the user wants a
+ # specific namespace or to use __main__.__dict__. This will allow us
+ # to bind to __main__.__dict__ at completion time, not now.
+ if namespace is None:
+ self.use_main_ns = 1
+ else:
+ self.use_main_ns = 0
+ self.namespace = namespace
+
+ # The global namespace, if given, can be bound directly
+ if global_namespace is None:
+ self.global_namespace = {}
+ else:
+ self.global_namespace = global_namespace
+
+ def complete(self, text, state):
+ """Return the next possible completion for 'text'.
+
+ This is called successively with state == 0, 1, 2, ... until it
+ returns None. The completion should begin with 'text'.
+
+ """
+ if self.use_main_ns:
+ self.namespace = __main__.__dict__
+
+ if state == 0:
+ if "." in text:
+ self.matches = self.attr_matches(text)
+ else:
+ self.matches = self.global_matches(text)
+ try:
+ return self.matches[state]
+ except IndexError:
+ return None
+
+ def global_matches(self, text):
+ """Compute matches when text is a simple name.
+
+ Return a list of all keywords, built-in functions and names currently
+ defined in self.namespace or self.global_namespace that match.
+
+ """
+ matches = []
+ match_append = matches.append
+ n = len(text)
+ for lst in [keyword.kwlist,
+ __builtin__.__dict__.keys(),
+ self.namespace.keys(),
+ self.global_namespace.keys()]:
+ for word in lst:
+ if word[:n] == text and word != "__builtins__":
+ match_append(word)
+ return matches
+
+ def attr_matches(self, text):
+ """Compute matches when text contains a dot.
+
+ Assuming the text is of the form NAME.NAME....[NAME], and is
+ evaluatable in self.namespace or self.global_namespace, it will be
+ evaluated and its attributes (as revealed by dir()) are used as
+ possible completions. (For class instances, class members are are
+ also considered.)
+
+ WARNING: this can still invoke arbitrary C code, if an object
+ with a __getattr__ hook is evaluated.
+
+ """
+ import re
+
+ # Another option, seems to work great. Catches things like ''.<tab>
+ m = re.match(r"(\S+(\.\w+)*)\.(\w*)$", text)
+
+ if not m:
+ return []
+
+ expr, attr = m.group(1, 3)
+ try:
+ obj = eval(expr, self.namespace)
+ except:
+ try:
+ obj = eval(expr, self.global_namespace)
+ except:
+ return []
+
+ words = dir2(obj)
+
+ try:
+ words = generics.complete_object(obj, words)
+ except ipapi.TryNext:
+ pass
+ # Build match list to return
+ n = len(attr)
+ res = ["%s.%s" % (expr, w) for w in words if w[:n] == attr ]
+ return res
+
+class IPCompleter(Completer):
+ """Extension of the completer class with IPython-specific features"""
+
+ def __init__(self,shell,namespace=None,global_namespace=None,
+ omit__names=0,alias_table=None):
+ """IPCompleter() -> completer
+
+ Return a completer object suitable for use by the readline library
+ via readline.set_completer().
+
+ Inputs:
+
+ - shell: a pointer to the ipython shell itself. This is needed
+ because this completer knows about magic functions, and those can
+ only be accessed via the ipython instance.
+
+ - namespace: an optional dict where completions are performed.
+
+ - global_namespace: secondary optional dict for completions, to
+ handle cases (such as IPython embedded inside functions) where
+ both Python scopes are visible.
+
+ - The optional omit__names parameter sets the completer to omit the
+ 'magic' names (__magicname__) for python objects unless the text
+ to be completed explicitly starts with one or more underscores.
+
+ - If alias_table is supplied, it should be a dictionary of aliases
+ to complete. """
+
+ Completer.__init__(self,namespace,global_namespace)
+ self.magic_prefix = shell.name+'.magic_'
+ self.magic_escape = shell.ESC_MAGIC
+ self.readline = readline
+ delims = self.readline.get_completer_delims()
+ delims = delims.replace(self.magic_escape,'')
+ self.readline.set_completer_delims(delims)
+ self.get_line_buffer = self.readline.get_line_buffer
+ self.get_endidx = self.readline.get_endidx
+ self.omit__names = omit__names
+ self.merge_completions = shell.rc.readline_merge_completions
+ if alias_table is None:
+ alias_table = {}
+ self.alias_table = alias_table
+ # Regexp to split filenames with spaces in them
+ self.space_name_re = re.compile(r'([^\\] )')
+ # Hold a local ref. to glob.glob for speed
+ self.glob = glob.glob
+
+ # Determine if we are running on 'dumb' terminals, like (X)Emacs
+ # buffers, to avoid completion problems.
+ term = os.environ.get('TERM','xterm')
+ self.dumb_terminal = term in ['dumb','emacs']
+
+ # Special handling of backslashes needed in win32 platforms
+ if sys.platform == "win32":
+ self.clean_glob = self._clean_glob_win32
+ else:
+ self.clean_glob = self._clean_glob
+ self.matchers = [self.python_matches,
+ self.file_matches,
+ self.alias_matches,
+ self.python_func_kw_matches]
+
+
+ # Code contributed by Alex Schmolck, for ipython/emacs integration
+ def all_completions(self, text):
+ """Return all possible completions for the benefit of emacs."""
+
+ completions = []
+ comp_append = completions.append
+ try:
+ for i in xrange(sys.maxint):
+ res = self.complete(text, i)
+
+ if not res: break
+
+ comp_append(res)
+ #XXX workaround for ``notDefined.<tab>``
+ except NameError:
+ pass
+ return completions
+ # /end Alex Schmolck code.
+
+ def _clean_glob(self,text):
+ return self.glob("%s*" % text)
+
+ def _clean_glob_win32(self,text):
+ return [f.replace("\\","/")
+ for f in self.glob("%s*" % text)]
+
+ def file_matches(self, text):
+ """Match filenames, expanding ~USER type strings.
+
+ Most of the seemingly convoluted logic in this completer is an
+ attempt to handle filenames with spaces in them. And yet it's not
+ quite perfect, because Python's readline doesn't expose all of the
+ GNU readline details needed for this to be done correctly.
+
+ For a filename with a space in it, the printed completions will be
+ only the parts after what's already been typed (instead of the
+ full completions, as is normally done). I don't think with the
+ current (as of Python 2.3) Python readline it's possible to do
+ better."""
+
+ #print 'Completer->file_matches: <%s>' % text # dbg
+
+ # chars that require escaping with backslash - i.e. chars
+ # that readline treats incorrectly as delimiters, but we
+ # don't want to treat as delimiters in filename matching
+ # when escaped with backslash
+
+ if sys.platform == 'win32':
+ protectables = ' '
+ else:
+ protectables = ' ()'
+
+ if text.startswith('!'):
+ text = text[1:]
+ text_prefix = '!'
+ else:
+ text_prefix = ''
+
+ def protect_filename(s):
+ return "".join([(ch in protectables and '\\' + ch or ch)
+ for ch in s])
+
+ def single_dir_expand(matches):
+ "Recursively expand match lists containing a single dir."
+
+ if len(matches) == 1 and os.path.isdir(matches[0]):
+ # Takes care of links to directories also. Use '/'
+ # explicitly, even under Windows, so that name completions
+ # don't end up escaped.
+ d = matches[0]
+ if d[-1] in ['/','\\']:
+ d = d[:-1]
+
+ subdirs = os.listdir(d)
+ if subdirs:
+ matches = [ (d + '/' + p) for p in subdirs]
+ return single_dir_expand(matches)
+ else:
+ return matches
+ else:
+ return matches
+
+ lbuf = self.lbuf
+ open_quotes = 0 # track strings with open quotes
+ try:
+ lsplit = shlex.split(lbuf)[-1]
+ except ValueError:
+ # typically an unmatched ", or backslash without escaped char.
+ if lbuf.count('"')==1:
+ open_quotes = 1
+ lsplit = lbuf.split('"')[-1]
+ elif lbuf.count("'")==1:
+ open_quotes = 1
+ lsplit = lbuf.split("'")[-1]
+ else:
+ return []
+ except IndexError:
+ # tab pressed on empty line
+ lsplit = ""
+
+ if lsplit != protect_filename(lsplit):
+ # if protectables are found, do matching on the whole escaped
+ # name
+ has_protectables = 1
+ text0,text = text,lsplit
+ else:
+ has_protectables = 0
+ text = os.path.expanduser(text)
+
+ if text == "":
+ return [text_prefix + protect_filename(f) for f in self.glob("*")]
+
+ m0 = self.clean_glob(text.replace('\\',''))
+ if has_protectables:
+ # If we had protectables, we need to revert our changes to the
+ # beginning of filename so that we don't double-write the part
+ # of the filename we have so far
+ len_lsplit = len(lsplit)
+ matches = [text_prefix + text0 +
+ protect_filename(f[len_lsplit:]) for f in m0]
+ else:
+ if open_quotes:
+ # if we have a string with an open quote, we don't need to
+ # protect the names at all (and we _shouldn't_, as it
+ # would cause bugs when the filesystem call is made).
+ matches = m0
+ else:
+ matches = [text_prefix +
+ protect_filename(f) for f in m0]
+
+ #print 'mm',matches # dbg
+ return single_dir_expand(matches)
+
+ def alias_matches(self, text):
+ """Match internal system aliases"""
+ #print 'Completer->alias_matches:',text,'lb',self.lbuf # dbg
+
+ # if we are not in the first 'item', alias matching
+ # doesn't make sense - unless we are starting with 'sudo' command.
+ if ' ' in self.lbuf.lstrip() and not self.lbuf.lstrip().startswith('sudo'):
+ return []
+ text = os.path.expanduser(text)
+ aliases = self.alias_table.keys()
+ if text == "":
+ return aliases
+ else:
+ return [alias for alias in aliases if alias.startswith(text)]
+
+ def python_matches(self,text):
+ """Match attributes or global python names"""
+
+ #print 'Completer->python_matches, txt=<%s>' % text # dbg
+ if "." in text:
+ try:
+ matches = self.attr_matches(text)
+ if text.endswith('.') and self.omit__names:
+ if self.omit__names == 1:
+ # true if txt is _not_ a __ name, false otherwise:
+ no__name = (lambda txt:
+ re.match(r'.*\.__.*?__',txt) is None)
+ else:
+ # true if txt is _not_ a _ name, false otherwise:
+ no__name = (lambda txt:
+ re.match(r'.*\._.*?',txt) is None)
+ matches = filter(no__name, matches)
+ except NameError:
+ # catches <undefined attributes>.<tab>
+ matches = []
+ else:
+ matches = self.global_matches(text)
+ # this is so completion finds magics when automagic is on:
+ if (matches == [] and
+ not text.startswith(os.sep) and
+ not ' ' in self.lbuf):
+ matches = self.attr_matches(self.magic_prefix+text)
+ return matches
+
+ def _default_arguments(self, obj):
+ """Return the list of default arguments of obj if it is callable,
+ or empty list otherwise."""
+
+ if not (inspect.isfunction(obj) or inspect.ismethod(obj)):
+ # for classes, check for __init__,__new__
+ if inspect.isclass(obj):
+ obj = (getattr(obj,'__init__',None) or
+ getattr(obj,'__new__',None))
+ # for all others, check if they are __call__able
+ elif hasattr(obj, '__call__'):
+ obj = obj.__call__
+ # XXX: is there a way to handle the builtins ?
+ try:
+ args,_,_1,defaults = inspect.getargspec(obj)
+ if defaults:
+ return args[-len(defaults):]
+ except TypeError: pass
+ return []
+
+ def python_func_kw_matches(self,text):
+ """Match named parameters (kwargs) of the last open function"""
+
+ if "." in text: # a parameter cannot be dotted
+ return []
+ try: regexp = self.__funcParamsRegex
+ except AttributeError:
+ regexp = self.__funcParamsRegex = re.compile(r'''
+ '.*?' | # single quoted strings or
+ ".*?" | # double quoted strings or
+ \w+ | # identifier
+ \S # other characters
+ ''', re.VERBOSE | re.DOTALL)
+ # 1. find the nearest identifier that comes before an unclosed
+ # parenthesis e.g. for "foo (1+bar(x), pa", the candidate is "foo"
+ tokens = regexp.findall(self.get_line_buffer())
+ tokens.reverse()
+ iterTokens = iter(tokens); openPar = 0
+ for token in iterTokens:
+ if token == ')':
+ openPar -= 1
+ elif token == '(':
+ openPar += 1
+ if openPar > 0:
+ # found the last unclosed parenthesis
+ break
+ else:
+ return []
+ # 2. Concatenate dotted names ("foo.bar" for "foo.bar(x, pa" )
+ ids = []
+ isId = re.compile(r'\w+$').match
+ while True:
+ try:
+ ids.append(iterTokens.next())
+ if not isId(ids[-1]):
+ ids.pop(); break
+ if not iterTokens.next() == '.':
+ break
+ except StopIteration:
+ break
+ # lookup the candidate callable matches either using global_matches
+ # or attr_matches for dotted names
+ if len(ids) == 1:
+ callableMatches = self.global_matches(ids[0])
+ else:
+ callableMatches = self.attr_matches('.'.join(ids[::-1]))
+ argMatches = []
+ for callableMatch in callableMatches:
+ try: namedArgs = self._default_arguments(eval(callableMatch,
+ self.namespace))
+ except: continue
+ for namedArg in namedArgs:
+ if namedArg.startswith(text):
+ argMatches.append("%s=" %namedArg)
+ return argMatches
+
+ def dispatch_custom_completer(self,text):
+ #print "Custom! '%s' %s" % (text, self.custom_completers) # dbg
+ line = self.full_lbuf
+ if not line.strip():
+ return None
+
+ event = Struct()
+ event.line = line
+ event.symbol = text
+ cmd = line.split(None,1)[0]
+ event.command = cmd
+ #print "\ncustom:{%s]\n" % event # dbg
+
+ # for foo etc, try also to find completer for %foo
+ if not cmd.startswith(self.magic_escape):
+ try_magic = self.custom_completers.s_matches(
+ self.magic_escape + cmd)
+ else:
+ try_magic = []
+
+
+ for c in itertools.chain(
+ self.custom_completers.s_matches(cmd),
+ try_magic,
+ self.custom_completers.flat_matches(self.lbuf)):
+ #print "try",c # dbg
+ try:
+ res = c(event)
+ # first, try case sensitive match
+ withcase = [r for r in res if r.startswith(text)]
+ if withcase:
+ return withcase
+ # if none, then case insensitive ones are ok too
+ return [r for r in res if r.lower().startswith(text.lower())]
+ except ipapi.TryNext:
+ pass
+
+ return None
+
+ def complete(self, text, state,line_buffer=None):
+ """Return the next possible completion for 'text'.
+
+ This is called successively with state == 0, 1, 2, ... until it
+ returns None. The completion should begin with 'text'.
+
+ :Keywords:
+ - line_buffer: string
+ If not given, the completer attempts to obtain the current line buffer
+ via readline. This keyword allows clients which are requesting for
+ text completions in non-readline contexts to inform the completer of
+ the entire text.
+ """
+
+ #print '\n*** COMPLETE: <%s> (%s)' % (text,state) # dbg
+
+ # if there is only a tab on a line with only whitespace, instead
+ # of the mostly useless 'do you want to see all million
+ # completions' message, just do the right thing and give the user
+ # his tab! Incidentally, this enables pasting of tabbed text from
+ # an editor (as long as autoindent is off).
+
+ # It should be noted that at least pyreadline still shows
+ # file completions - is there a way around it?
+
+ # don't apply this on 'dumb' terminals, such as emacs buffers, so we
+ # don't interfere with their own tab-completion mechanism.
+ if line_buffer is None:
+ self.full_lbuf = self.get_line_buffer()
+ else:
+ self.full_lbuf = line_buffer
+
+ if not (self.dumb_terminal or self.full_lbuf.strip()):
+ self.readline.insert_text('\t')
+ return None
+
+ magic_escape = self.magic_escape
+ magic_prefix = self.magic_prefix
+
+ self.lbuf = self.full_lbuf[:self.get_endidx()]
+
+ try:
+ if text.startswith(magic_escape):
+ text = text.replace(magic_escape,magic_prefix)
+ elif text.startswith('~'):
+ text = os.path.expanduser(text)
+ if state == 0:
+ custom_res = self.dispatch_custom_completer(text)
+ if custom_res is not None:
+ # did custom completers produce something?
+ self.matches = custom_res
+ else:
+ # Extend the list of completions with the results of each
+ # matcher, so we return results to the user from all
+ # namespaces.
+ if self.merge_completions:
+ self.matches = []
+ for matcher in self.matchers:
+ self.matches.extend(matcher(text))
+ else:
+ for matcher in self.matchers:
+ self.matches = matcher(text)
+ if self.matches:
+ break
+ def uniq(alist):
+ set = {}
+ return [set.setdefault(e,e) for e in alist if e not in set]
+ self.matches = uniq(self.matches)
+ try:
+ ret = self.matches[state].replace(magic_prefix,magic_escape)
+ return ret
+ except IndexError:
+ return None
+ except:
+ #from IPython.ultraTB import AutoFormattedTB; # dbg
+ #tb=AutoFormattedTB('Verbose');tb() #dbg
+
+ # If completion fails, don't annoy the user.
+ return None
diff --git a/IPython/config/__init__.py b/IPython/config/__init__.py
new file mode 100644
index 0000000..876b4f3
--- /dev/null
+++ b/IPython/config/__init__.py
@@ -0,0 +1,14 @@
+# encoding: utf-8
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#------------------------------------------------------------------------------- \ No newline at end of file
diff --git a/IPython/config/api.py b/IPython/config/api.py
new file mode 100644
index 0000000..6de3d3e
--- /dev/null
+++ b/IPython/config/api.py
@@ -0,0 +1,102 @@
+# encoding: utf-8
+
+"""This is the official entry point to IPython's configuration system. """
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+import os
+from os.path import join as pjoin
+
+from IPython.genutils import get_home_dir, get_ipython_dir
+from IPython.external.configobj import ConfigObj
+
+
+class ConfigObjManager(object):
+
+ def __init__(self, configObj, filename):
+ self.current = configObj
+ self.current.indent_type = ' '
+ self.filename = filename
+ # self.write_default_config_file()
+
+ def get_config_obj(self):
+ return self.current
+
+ def update_config_obj(self, newConfig):
+ self.current.merge(newConfig)
+
+ def update_config_obj_from_file(self, filename):
+ newConfig = ConfigObj(filename, file_error=False)
+ self.current.merge(newConfig)
+
+ def update_config_obj_from_default_file(self, ipythondir=None):
+ fname = self.resolve_file_path(self.filename, ipythondir)
+ self.update_config_obj_from_file(fname)
+
+ def write_config_obj_to_file(self, filename):
+ f = open(filename, 'w')
+ self.current.write(f)
+ f.close()
+
+ def write_default_config_file(self):
+ ipdir = get_ipython_dir()
+ fname = pjoin(ipdir, self.filename)
+ if not os.path.isfile(fname):
+ print "Writing the configuration file to: " + fname
+ self.write_config_obj_to_file(fname)
+
+ def _import(self, key):
+ package = '.'.join(key.split('.')[0:-1])
+ obj = key.split('.')[-1]
+ execString = 'from %s import %s' % (package, obj)
+ exec execString
+ exec 'temp = %s' % obj
+ return temp
+
+ def resolve_file_path(self, filename, ipythondir = None):
+ """Resolve filenames into absolute paths.
+
+ This function looks in the following directories in order:
+
+ 1. In the current working directory or by absolute path with ~ expanded
+ 2. In ipythondir if that is set
+ 3. In the IPYTHONDIR environment variable if it exists
+ 4. In the ~/.ipython directory
+
+ Note: The IPYTHONDIR is also used by the trunk version of IPython so
+ changing it will also affect it was well.
+ """
+
+ # In cwd or by absolute path with ~ expanded
+ trythis = os.path.expanduser(filename)
+ if os.path.isfile(trythis):
+ return trythis
+
+ # In ipythondir if it is set
+ if ipythondir is not None:
+ trythis = pjoin(ipythondir, filename)
+ if os.path.isfile(trythis):
+ return trythis
+
+ trythis = pjoin(get_ipython_dir(), filename)
+ if os.path.isfile(trythis):
+ return trythis
+
+ return None
+
+
+
+
+
+
diff --git a/IPython/config/cutils.py b/IPython/config/cutils.py
new file mode 100644
index 0000000..d72bcc9
--- /dev/null
+++ b/IPython/config/cutils.py
@@ -0,0 +1,34 @@
+# encoding: utf-8
+
+"""Configuration-related utilities for all IPython."""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+import os
+import sys
+
+#---------------------------------------------------------------------------
+# Normal code begins
+#---------------------------------------------------------------------------
+
+def import_item(key):
+ """
+ Import and return bar given the string foo.bar.
+ """
+ package = '.'.join(key.split('.')[0:-1])
+ obj = key.split('.')[-1]
+ execString = 'from %s import %s' % (package, obj)
+ exec execString
+ exec 'temp = %s' % obj
+ return temp
diff --git a/IPython/config/tests/__init__.py b/IPython/config/tests/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/IPython/config/tests/__init__.py
diff --git a/IPython/deep_reload.py b/IPython/deep_reload.py
new file mode 100644
index 0000000..c8685ba
--- /dev/null
+++ b/IPython/deep_reload.py
@@ -0,0 +1,182 @@
+# -*- coding: utf-8 -*-
+"""
+A module to change reload() so that it acts recursively.
+To enable it type:
+ >>> import __builtin__, deep_reload
+ >>> __builtin__.reload = deep_reload.reload
+
+You can then disable it with:
+ >>> __builtin__.reload = deep_reload.original_reload
+
+Alternatively, you can add a dreload builtin alongside normal reload with:
+ >>> __builtin__.dreload = deep_reload.reload
+
+This code is almost entirely based on knee.py from the standard library.
+"""
+
+#*****************************************************************************
+# Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#*****************************************************************************
+
+import __builtin__
+import imp
+import sys
+
+# Replacement for __import__()
+def deep_import_hook(name, globals=None, locals=None, fromlist=None, level=-1):
+ # For now level is ignored, it's just there to prevent crash
+ # with from __future__ import absolute_import
+ parent = determine_parent(globals)
+ q, tail = find_head_package(parent, name)
+ m = load_tail(q, tail)
+ if not fromlist:
+ return q
+ if hasattr(m, "__path__"):
+ ensure_fromlist(m, fromlist)
+ return m
+
+def determine_parent(globals):
+ if not globals or not globals.has_key("__name__"):
+ return None
+ pname = globals['__name__']
+ if globals.has_key("__path__"):
+ parent = sys.modules[pname]
+ assert globals is parent.__dict__
+ return parent
+ if '.' in pname:
+ i = pname.rfind('.')
+ pname = pname[:i]
+ parent = sys.modules[pname]
+ assert parent.__name__ == pname
+ return parent
+ return None
+
+def find_head_package(parent, name):
+ # Import the first
+ if '.' in name:
+ # 'some.nested.package' -> head = 'some', tail = 'nested.package'
+ i = name.find('.')
+ head = name[:i]
+ tail = name[i+1:]
+ else:
+ # 'packagename' -> head = 'packagename', tail = ''
+ head = name
+ tail = ""
+ if parent:
+ # If this is a subpackage then qname = parent's name + head
+ qname = "%s.%s" % (parent.__name__, head)
+ else:
+ qname = head
+ q = import_module(head, qname, parent)
+ if q: return q, tail
+ if parent:
+ qname = head
+ parent = None
+ q = import_module(head, qname, parent)
+ if q: return q, tail
+ raise ImportError, "No module named " + qname
+
+def load_tail(q, tail):
+ m = q
+ while tail:
+ i = tail.find('.')
+ if i < 0: i = len(tail)
+ head, tail = tail[:i], tail[i+1:]
+
+ # fperez: fix dotted.name reloading failures by changing:
+ #mname = "%s.%s" % (m.__name__, head)
+ # to:
+ mname = m.__name__
+ # This needs more testing!!! (I don't understand this module too well)
+
+ #print '** head,tail=|%s|->|%s|, mname=|%s|' % (head,tail,mname) # dbg
+ m = import_module(head, mname, m)
+ if not m:
+ raise ImportError, "No module named " + mname
+ return m
+
+def ensure_fromlist(m, fromlist, recursive=0):
+ for sub in fromlist:
+ if sub == "*":
+ if not recursive:
+ try:
+ all = m.__all__
+ except AttributeError:
+ pass
+ else:
+ ensure_fromlist(m, all, 1)
+ continue
+ if sub != "*" and not hasattr(m, sub):
+ subname = "%s.%s" % (m.__name__, sub)
+ submod = import_module(sub, subname, m)
+ if not submod:
+ raise ImportError, "No module named " + subname
+
+# Need to keep track of what we've already reloaded to prevent cyclic evil
+found_now = {}
+
+def import_module(partname, fqname, parent):
+ global found_now
+ if found_now.has_key(fqname):
+ try:
+ return sys.modules[fqname]
+ except KeyError:
+ pass
+
+ print 'Reloading', fqname #, sys.excepthook is sys.__excepthook__, \
+ #sys.displayhook is sys.__displayhook__
+
+ found_now[fqname] = 1
+ try:
+ fp, pathname, stuff = imp.find_module(partname,
+ parent and parent.__path__)
+ except ImportError:
+ return None
+
+ try:
+ m = imp.load_module(fqname, fp, pathname, stuff)
+ finally:
+ if fp: fp.close()
+
+ if parent:
+ setattr(parent, partname, m)
+
+ return m
+
+def deep_reload_hook(module):
+ name = module.__name__
+ if '.' not in name:
+ return import_module(name, name, None)
+ i = name.rfind('.')
+ pname = name[:i]
+ parent = sys.modules[pname]
+ return import_module(name[i+1:], name, parent)
+
+# Save the original hooks
+original_reload = __builtin__.reload
+
+# Replacement for reload()
+def reload(module, exclude=['sys', '__builtin__', '__main__']):
+ """Recursively reload all modules used in the given module. Optionally
+ takes a list of modules to exclude from reloading. The default exclude
+ list contains sys, __main__, and __builtin__, to prevent, e.g., resetting
+ display, exception, and io hooks.
+ """
+ global found_now
+ for i in exclude:
+ found_now[i] = 1
+ original_import = __builtin__.__import__
+ __builtin__.__import__ = deep_import_hook
+ try:
+ ret = deep_reload_hook(module)
+ finally:
+ __builtin__.__import__ = original_import
+ found_now = {}
+ return ret
+
+# Uncomment the following to automatically activate deep reloading whenever
+# this module is imported
+#__builtin__.reload = reload
diff --git a/IPython/demo.py b/IPython/demo.py
new file mode 100644
index 0000000..e889502
--- /dev/null
+++ b/IPython/demo.py
@@ -0,0 +1,554 @@
+"""Module for interactive demos using IPython.
+
+This module implements a few classes for running Python scripts interactively
+in IPython for demonstrations. With very simple markup (a few tags in
+comments), you can control points where the script stops executing and returns
+control to IPython.
+
+
+Provided classes
+================
+
+The classes are (see their docstrings for further details):
+
+ - Demo: pure python demos
+
+ - IPythonDemo: demos with input to be processed by IPython as if it had been
+ typed interactively (so magics work, as well as any other special syntax you
+ may have added via input prefilters).
+
+ - LineDemo: single-line version of the Demo class. These demos are executed
+ one line at a time, and require no markup.
+
+ - IPythonLineDemo: IPython version of the LineDemo class (the demo is
+ executed a line at a time, but processed via IPython).
+
+ - ClearMixin: mixin to make Demo classes with less visual clutter. It
+ declares an empty marquee and a pre_cmd that clears the screen before each
+ block (see Subclassing below).
+
+ - ClearDemo, ClearIPDemo: mixin-enabled versions of the Demo and IPythonDemo
+ classes.
+
+
+Subclassing
+===========
+
+The classes here all include a few methods meant to make customization by
+subclassing more convenient. Their docstrings below have some more details:
+
+ - marquee(): generates a marquee to provide visible on-screen markers at each
+ block start and end.
+
+ - pre_cmd(): run right before the execution of each block.
+
+ - post_cmd(): run right after the execution of each block. If the block
+ raises an exception, this is NOT called.
+
+
+Operation
+=========
+
+The file is run in its own empty namespace (though you can pass it a string of
+arguments as if in a command line environment, and it will see those as
+sys.argv). But at each stop, the global IPython namespace is updated with the
+current internal demo namespace, so you can work interactively with the data
+accumulated so far.
+
+By default, each block of code is printed (with syntax highlighting) before
+executing it and you have to confirm execution. This is intended to show the
+code to an audience first so you can discuss it, and only proceed with
+execution once you agree. There are a few tags which allow you to modify this
+behavior.
+
+The supported tags are:
+
+# <demo> stop
+
+ Defines block boundaries, the points where IPython stops execution of the
+ file and returns to the interactive prompt.
+
+ You can optionally mark the stop tag with extra dashes before and after the
+ word 'stop', to help visually distinguish the blocks in a text editor:
+
+ # <demo> --- stop ---
+
+
+# <demo> silent
+
+ Make a block execute silently (and hence automatically). Typically used in
+ cases where you have some boilerplate or initialization code which you need
+ executed but do not want to be seen in the demo.
+
+# <demo> auto
+
+ Make a block execute automatically, but still being printed. Useful for
+ simple code which does not warrant discussion, since it avoids the extra
+ manual confirmation.
+
+# <demo> auto_all
+
+ This tag can _only_ be in the first block, and if given it overrides the
+ individual auto tags to make the whole demo fully automatic (no block asks
+ for confirmation). It can also be given at creation time (or the attribute
+ set later) to override what's in the file.
+
+While _any_ python file can be run as a Demo instance, if there are no stop
+tags the whole file will run in a single block (no different that calling
+first %pycat and then %run). The minimal markup to make this useful is to
+place a set of stop tags; the other tags are only there to let you fine-tune
+the execution.
+
+This is probably best explained with the simple example file below. You can
+copy this into a file named ex_demo.py, and try running it via:
+
+from IPython.demo import Demo
+d = Demo('ex_demo.py')
+d() <--- Call the d object (omit the parens if you have autocall set to 2).
+
+Each time you call the demo object, it runs the next block. The demo object
+has a few useful methods for navigation, like again(), edit(), jump(), seek()
+and back(). It can be reset for a new run via reset() or reloaded from disk
+(in case you've edited the source) via reload(). See their docstrings below.
+
+Note: To make this simpler to explore, a file called "demo-exercizer.py" has
+been added to the "docs/examples/core" directory. Just cd to this directory in
+an IPython session, and type::
+
+ %run demo-exercizer.py
+
+and then follow the directions.
+
+Example
+=======
+
+The following is a very simple example of a valid demo file.
+
+#################### EXAMPLE DEMO <ex_demo.py> ###############################
+'''A simple interactive demo to illustrate the use of IPython's Demo class.'''
+
+print 'Hello, welcome to an interactive IPython demo.'
+
+# The mark below defines a block boundary, which is a point where IPython will
+# stop execution and return to the interactive prompt. The dashes are actually
+# optional and used only as a visual aid to clearly separate blocks while
+# editing the demo code.
+# <demo> stop
+
+x = 1
+y = 2
+
+# <demo> stop
+
+# the mark below makes this block as silent
+# <demo> silent
+
+print 'This is a silent block, which gets executed but not printed.'
+
+# <demo> stop
+# <demo> auto
+print 'This is an automatic block.'
+print 'It is executed without asking for confirmation, but printed.'
+z = x+y
+
+print 'z=',x
+
+# <demo> stop
+# This is just another normal block.
+print 'z is now:', z
+
+print 'bye!'
+################### END EXAMPLE DEMO <ex_demo.py> ############################
+"""
+
+#*****************************************************************************
+# Copyright (C) 2005-2006 Fernando Perez. <Fernando.Perez@colorado.edu>
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#
+#*****************************************************************************
+
+import exceptions
+import os
+import re
+import shlex
+import sys
+
+from IPython.PyColorize import Parser
+from IPython.genutils import marquee, file_read, file_readlines, Term
+
+__all__ = ['Demo','IPythonDemo','LineDemo','IPythonLineDemo','DemoError']
+
+class DemoError(exceptions.Exception): pass
+
+def re_mark(mark):
+ return re.compile(r'^\s*#\s+<demo>\s+%s\s*$' % mark,re.MULTILINE)
+
+class Demo(object):
+
+ re_stop = re_mark('-*\s?stop\s?-*')
+ re_silent = re_mark('silent')
+ re_auto = re_mark('auto')
+ re_auto_all = re_mark('auto_all')
+
+ def __init__(self,src,title='',arg_str='',auto_all=None):
+ """Make a new demo object. To run the demo, simply call the object.
+
+ See the module docstring for full details and an example (you can use
+ IPython.Demo? in IPython to see it).
+
+ Inputs:
+
+ - src is either a file, or file-like object, or a
+ string that can be resolved to a filename.
+
+ Optional inputs:
+
+ - title: a string to use as the demo name. Of most use when the demo
+ you are making comes from an object that has no filename, or if you
+ want an alternate denotation distinct from the filename.
+
+ - arg_str(''): a string of arguments, internally converted to a list
+ just like sys.argv, so the demo script can see a similar
+ environment.
+
+ - auto_all(None): global flag to run all blocks automatically without
+ confirmation. This attribute overrides the block-level tags and
+ applies to the whole demo. It is an attribute of the object, and
+ can be changed at runtime simply by reassigning it to a boolean
+ value.
+ """
+ if hasattr(src, "read"):
+ # It seems to be a file or a file-like object
+ self.fobj = src
+ self.fname = "from a file-like object"
+ if title == '':
+ self.title = "from a file-like object"
+ else:
+ self.title = title
+ else:
+ # Assume it's a string or something that can be converted to one
+ self.fobj = open(src)
+ self.fname = src
+ if title == '':
+ (filepath, filename) = os.path.split(src)
+ self.title = filename
+ else:
+ self.title = title
+ self.sys_argv = [src] + shlex.split(arg_str)
+ self.auto_all = auto_all
+
+ # get a few things from ipython. While it's a bit ugly design-wise,
+ # it ensures that things like color scheme and the like are always in
+ # sync with the ipython mode being used. This class is only meant to
+ # be used inside ipython anyways, so it's OK.
+ self.ip_ns = __IPYTHON__.user_ns
+ self.ip_colorize = __IPYTHON__.pycolorize
+ self.ip_showtb = __IPYTHON__.showtraceback
+ self.ip_runlines = __IPYTHON__.runlines
+ self.shell = __IPYTHON__
+
+ # load user data and initialize data structures
+ self.reload()
+
+ def reload(self):
+ """Reload source from disk and initialize state."""
+ # read data and parse into blocks
+ self.src = self.fobj.read()
+ src_b = [b.strip() for b in self.re_stop.split(self.src) if b]
+ self._silent = [bool(self.re_silent.findall(b)) for b in src_b]
+ self._auto = [bool(self.re_auto.findall(b)) for b in src_b]
+
+ # if auto_all is not given (def. None), we read it from the file
+ if self.auto_all is None:
+ self.auto_all = bool(self.re_auto_all.findall(src_b[0]))
+ else:
+ self.auto_all = bool(self.auto_all)
+
+ # Clean the sources from all markup so it doesn't get displayed when
+ # running the demo
+ src_blocks = []
+ auto_strip = lambda s: self.re_auto.sub('',s)
+ for i,b in enumerate(src_b):
+ if self._auto[i]:
+ src_blocks.append(auto_strip(b))
+ else:
+ src_blocks.append(b)
+ # remove the auto_all marker
+ src_blocks[0] = self.re_auto_all.sub('',src_blocks[0])
+
+ self.nblocks = len(src_blocks)
+ self.src_blocks = src_blocks
+
+ # also build syntax-highlighted source
+ self.src_blocks_colored = map(self.ip_colorize,self.src_blocks)
+
+ # ensure clean namespace and seek offset
+ self.reset()
+
+ def reset(self):
+ """Reset the namespace and seek pointer to restart the demo"""
+ self.user_ns = {}
+ self.finished = False
+ self.block_index = 0
+
+ def _validate_index(self,index):
+ if index<0 or index>=self.nblocks:
+ raise ValueError('invalid block index %s' % index)
+
+ def _get_index(self,index):
+ """Get the current block index, validating and checking status.
+
+ Returns None if the demo is finished"""
+
+ if index is None:
+ if self.finished:
+ print >>Term.cout, 'Demo finished. Use <demo_name>.reset() if you want to rerun it.'
+ return None
+ index = self.block_index
+ else:
+ self._validate_index(index)
+ return index
+
+ def seek(self,index):
+ """Move the current seek pointer to the given block.
+
+ You can use negative indices to seek from the end, with identical
+ semantics to those of Python lists."""
+ if index<0:
+ index = self.nblocks + index
+ self._validate_index(index)
+ self.block_index = index
+ self.finished = False
+
+ def back(self,num=1):
+ """Move the seek pointer back num blocks (default is 1)."""
+ self.seek(self.block_index-num)
+
+ def jump(self,num=1):
+ """Jump a given number of blocks relative to the current one.
+
+ The offset can be positive or negative, defaults to 1."""
+ self.seek(self.block_index+num)
+
+ def again(self):
+ """Move the seek pointer back one block and re-execute."""
+ self.back(1)
+ self()
+
+ def edit(self,index=None):
+ """Edit a block.
+
+ If no number is given, use the last block executed.
+
+ This edits the in-memory copy of the demo, it does NOT modify the
+ original source file. If you want to do that, simply open the file in
+ an editor and use reload() when you make changes to the file. This
+ method is meant to let you change a block during a demonstration for
+ explanatory purposes, without damaging your original script."""
+
+ index = self._get_index(index)
+ if index is None:
+ return
+ # decrease the index by one (unless we're at the very beginning), so
+ # that the default demo.edit() call opens up the sblock we've last run
+ if index>0:
+ index -= 1
+
+ filename = self.shell.mktempfile(self.src_blocks[index])
+ self.shell.hooks.editor(filename,1)
+ new_block = file_read(filename)
+ # update the source and colored block
+ self.src_blocks[index] = new_block
+ self.src_blocks_colored[index] = self.ip_colorize(new_block)
+ self.block_index = index
+ # call to run with the newly edited index
+ self()
+
+ def show(self,index=None):
+ """Show a single block on screen"""
+
+ index = self._get_index(index)
+ if index is None:
+ return
+
+ print >>Term.cout, self.marquee('<%s> block # %s (%s remaining)' %
+ (self.title,index,self.nblocks-index-1))
+ print >>Term.cout,(self.src_blocks_colored[index])
+ sys.stdout.flush()
+
+ def show_all(self):
+ """Show entire demo on screen, block by block"""
+
+ fname = self.title
+ title = self.title
+ nblocks = self.nblocks
+ silent = self._silent
+ marquee = self.marquee
+ for index,block in enumerate(self.src_blocks_colored):
+ if silent[index]:
+ print >>Term.cout, marquee('<%s> SILENT block # %s (%s remaining)' %
+ (title,index,nblocks-index-1))
+ else:
+ print >>Term.cout, marquee('<%s> block # %s (%s remaining)' %
+ (title,index,nblocks-index-1))
+ print >>Term.cout, block,
+ sys.stdout.flush()
+
+ def runlines(self,source):
+ """Execute a string with one or more lines of code"""
+
+ exec source in self.user_ns
+
+ def __call__(self,index=None):
+ """run a block of the demo.
+
+ If index is given, it should be an integer >=1 and <= nblocks. This
+ means that the calling convention is one off from typical Python
+ lists. The reason for the inconsistency is that the demo always
+ prints 'Block n/N, and N is the total, so it would be very odd to use
+ zero-indexing here."""
+
+ index = self._get_index(index)
+ if index is None:
+ return
+ try:
+ marquee = self.marquee
+ next_block = self.src_blocks[index]
+ self.block_index += 1
+ if self._silent[index]:
+ print >>Term.cout, marquee('Executing silent block # %s (%s remaining)' %
+ (index,self.nblocks-index-1))
+ else:
+ self.pre_cmd()
+ self.show(index)
+ if self.auto_all or self._auto[index]:
+ print >>Term.cout, marquee('output:')
+ else:
+ print >>Term.cout, marquee('Press <q> to quit, <Enter> to execute...'),
+ ans = raw_input().strip()
+ if ans:
+ print >>Term.cout, marquee('Block NOT executed')
+ return
+ try:
+ save_argv = sys.argv
+ sys.argv = self.sys_argv
+ self.runlines(next_block)
+ self.post_cmd()
+ finally:
+ sys.argv = save_argv
+
+ except:
+ self.ip_showtb(filename=self.fname)
+ else:
+ self.ip_ns.update(self.user_ns)
+
+ if self.block_index == self.nblocks:
+ mq1 = self.marquee('END OF DEMO')
+ if mq1:
+ # avoid spurious print >>Term.cout,s if empty marquees are used
+ print >>Term.cout
+ print >>Term.cout, mq1
+ print >>Term.cout, self.marquee('Use <demo_name>.reset() if you want to rerun it.')
+ self.finished = True
+
+ # These methods are meant to be overridden by subclasses who may wish to
+ # customize the behavior of of their demos.
+ def marquee(self,txt='',width=78,mark='*'):
+ """Return the input string centered in a 'marquee'."""
+ return marquee(txt,width,mark)
+
+ def pre_cmd(self):
+ """Method called before executing each block."""
+ pass
+
+ def post_cmd(self):
+ """Method called after executing each block."""
+ pass
+
+
+class IPythonDemo(Demo):
+ """Class for interactive demos with IPython's input processing applied.
+
+ This subclasses Demo, but instead of executing each block by the Python
+ interpreter (via exec), it actually calls IPython on it, so that any input
+ filters which may be in place are applied to the input block.
+
+ If you have an interactive environment which exposes special input
+ processing, you can use this class instead to write demo scripts which
+ operate exactly as if you had typed them interactively. The default Demo
+ class requires the input to be valid, pure Python code.
+ """
+
+ def runlines(self,source):
+ """Execute a string with one or more lines of code"""
+
+ self.shell.runlines(source)
+
+class LineDemo(Demo):
+ """Demo where each line is executed as a separate block.
+
+ The input script should be valid Python code.
+
+ This class doesn't require any markup at all, and it's meant for simple
+ scripts (with no nesting or any kind of indentation) which consist of
+ multiple lines of input to be executed, one at a time, as if they had been
+ typed in the interactive prompt."""
+
+ def reload(self):
+ """Reload source from disk and initialize state."""
+ # read data and parse into blocks
+ src_b = [l for l in self.fobj.readline() if l.strip()]
+ nblocks = len(src_b)
+ self.src = os.linesep.join(self.fobj.readlines())
+ self._silent = [False]*nblocks
+ self._auto = [True]*nblocks
+ self.auto_all = True
+ self.nblocks = nblocks
+ self.src_blocks = src_b
+
+ # also build syntax-highlighted source
+ self.src_blocks_colored = map(self.ip_colorize,self.src_blocks)
+
+ # ensure clean namespace and seek offset
+ self.reset()
+
+
+class IPythonLineDemo(IPythonDemo,LineDemo):
+ """Variant of the LineDemo class whose input is processed by IPython."""
+ pass
+
+
+class ClearMixin(object):
+ """Use this mixin to make Demo classes with less visual clutter.
+
+ Demos using this mixin will clear the screen before every block and use
+ blank marquees.
+
+ Note that in order for the methods defined here to actually override those
+ of the classes it's mixed with, it must go /first/ in the inheritance
+ tree. For example:
+
+ class ClearIPDemo(ClearMixin,IPythonDemo): pass
+
+ will provide an IPythonDemo class with the mixin's features.
+ """
+
+ def marquee(self,txt='',width=78,mark='*'):
+ """Blank marquee that returns '' no matter what the input."""
+ return ''
+
+ def pre_cmd(self):
+ """Method called before executing each block.
+
+ This one simply clears the screen."""
+ import IPython.platutils
+ IPython.platutils.term_clear()
+
+class ClearDemo(ClearMixin,Demo):
+ pass
+
+
+class ClearIPDemo(ClearMixin,IPythonDemo):
+ pass
diff --git a/IPython/dtutils.py b/IPython/dtutils.py
new file mode 100644
index 0000000..37e7aa2
--- /dev/null
+++ b/IPython/dtutils.py
@@ -0,0 +1,137 @@
+"""Doctest-related utilities for IPython.
+
+For most common uses, all you should need to run is::
+
+ from IPython.dtutils import idoctest
+
+See the idoctest docstring below for usage details.
+"""
+
+import doctest
+import sys
+
+import IPython.ipapi
+ip = IPython.ipapi.get()
+
+def rundoctest(text,ns=None,eraise=False):
+ """Run a the input source as a doctest, in the caller's namespace.
+
+ :Parameters:
+ text : str
+ Source to execute.
+
+ :Keywords:
+ ns : dict (None)
+ Namespace where the code should be executed. If not given, the
+ caller's locals and globals are used.
+ eraise : bool (False)
+ If true, immediately raise any exceptions instead of reporting them at
+ the end. This allows you to then do interactive debugging via
+ IPython's facilities (use %debug after the fact, or with %pdb for
+ automatic activation).
+ """
+
+ name = 'interactive doctest'
+ filename = '<IPython console>'
+
+ if eraise:
+ runner = doctest.DebugRunner()
+ else:
+ runner = doctest.DocTestRunner()
+
+ parser = doctest.DocTestParser()
+ if ns is None:
+ f = sys._getframe(1)
+ ns = f.f_globals.copy()
+ ns.update(f.f_locals)
+
+ test = parser.get_doctest(text,ns,name,filename,0)
+ runner.run(test)
+ runner.summarize(True)
+
+
+def idoctest(ns=None,eraise=False):
+ """Interactively prompt for input and run it as a doctest.
+
+ To finish entering input, enter two blank lines or Ctrl-D (EOF). If you
+ use Ctrl-C, the example is aborted and all input discarded.
+
+ :Keywords:
+ ns : dict (None)
+ Namespace where the code should be executed. If not given, the IPython
+ interactive namespace is used.
+ eraise : bool (False)
+ If true, immediately raise any exceptions instead of reporting them at
+ the end. This allows you to then do interactive debugging via
+ IPython's facilities (use %debug after the fact, or with %pdb for
+ automatic activation).
+ end_mark : str ('--')
+ String to explicitly indicate the end of input.
+
+ """
+
+ inlines = []
+ empty_lines = 0 # count consecutive empty lines
+ run_test = True
+
+ if ns is None:
+ ns = ip.user_ns
+
+ ip.IP.savehist()
+ try:
+ while True:
+ line = raw_input()
+ if not line or line.isspace():
+ empty_lines += 1
+ else:
+ empty_lines = 0
+
+ if empty_lines>=2:
+ break
+
+ inlines.append(line)
+ except EOFError:
+ pass
+ except KeyboardInterrupt:
+ print "KeyboardInterrupt - Discarding input."
+ run_test = False
+
+ ip.IP.reloadhist()
+
+ if run_test:
+ # Extra blank line at the end to ensure that the final docstring has a
+ # closing newline
+ inlines.append('')
+ rundoctest('\n'.join(inlines),ns,eraise)
+
+
+# For debugging of this module itself.
+if __name__ == "__main__":
+ t = """
+ >>> for i in range(10):
+ ... print i,
+ ...
+ 0 1 2 3 4 5 6 7 8 9
+ """
+
+ t2 = """
+ A simple example::
+
+ >>> for i in range(10):
+ ... print i,
+ ...
+ 0 1 2 3 4 5 6 7 8 9
+
+ Some more details::
+
+ >>> print "hello"
+ hello
+ """
+
+ t3 = """
+ A failing example::
+
+ >>> x=1
+ >>> x+1
+ 3
+ """
diff --git a/IPython/excolors.py b/IPython/excolors.py
new file mode 100644
index 0000000..0245eb5
--- /dev/null
+++ b/IPython/excolors.py
@@ -0,0 +1,137 @@
+# -*- coding: utf-8 -*-
+"""
+Color schemes for exception handling code in IPython.
+"""
+
+#*****************************************************************************
+# Copyright (C) 2005-2006 Fernando Perez <fperez@colorado.edu>
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#*****************************************************************************
+
+#****************************************************************************
+# Required modules
+from IPython.ColorANSI import ColorSchemeTable, TermColors, ColorScheme
+
+def exception_colors():
+ """Return a color table with fields for exception reporting.
+
+ The table is an instance of ColorSchemeTable with schemes added for
+ 'Linux', 'LightBG' and 'NoColor' and fields for exception handling filled
+ in.
+
+ Examples:
+
+ >>> ec = exception_colors()
+ >>> ec.active_scheme_name
+ ''
+ >>> print ec.active_colors
+ None
+
+ Now we activate a color scheme:
+ >>> ec.set_active_scheme('NoColor')
+ >>> ec.active_scheme_name
+ 'NoColor'
+ >>> ec.active_colors.keys()
+ ['em', 'caret', '__allownew', 'name', 'val', 'vName', 'Normal', 'normalEm',
+ 'filename', 'linenoEm', 'excName', 'lineno', 'valEm', 'filenameEm',
+ 'nameEm', 'line', 'topline']
+ """
+
+ ex_colors = ColorSchemeTable()
+
+ # Populate it with color schemes
+ C = TermColors # shorthand and local lookup
+ ex_colors.add_scheme(ColorScheme(
+ 'NoColor',
+ # The color to be used for the top line
+ topline = C.NoColor,
+
+ # The colors to be used in the traceback
+ filename = C.NoColor,
+ lineno = C.NoColor,
+ name = C.NoColor,
+ vName = C.NoColor,
+ val = C.NoColor,
+ em = C.NoColor,
+
+ # Emphasized colors for the last frame of the traceback
+ normalEm = C.NoColor,
+ filenameEm = C.NoColor,
+ linenoEm = C.NoColor,
+ nameEm = C.NoColor,
+ valEm = C.NoColor,
+
+ # Colors for printing the exception
+ excName = C.NoColor,
+ line = C.NoColor,
+ caret = C.NoColor,
+ Normal = C.NoColor
+ ))
+
+ # make some schemes as instances so we can copy them for modification easily
+ ex_colors.add_scheme(ColorScheme(
+ 'Linux',
+ # The color to be used for the top line
+ topline = C.LightRed,
+
+ # The colors to be used in the traceback
+ filename = C.Green,
+ lineno = C.Green,
+ name = C.Purple,
+ vName = C.Cyan,
+ val = C.Green,
+ em = C.LightCyan,
+
+ # Emphasized colors for the last frame of the traceback
+ normalEm = C.LightCyan,
+ filenameEm = C.LightGreen,
+ linenoEm = C.LightGreen,
+ nameEm = C.LightPurple,
+ valEm = C.LightBlue,
+
+ # Colors for printing the exception
+ excName = C.LightRed,
+ line = C.Yellow,
+ caret = C.White,
+ Normal = C.Normal
+ ))
+
+ # For light backgrounds, swap dark/light colors
+ ex_colors.add_scheme(ColorScheme(
+ 'LightBG',
+ # The color to be used for the top line
+ topline = C.Red,
+
+ # The colors to be used in the traceback
+ filename = C.LightGreen,
+ lineno = C.LightGreen,
+ name = C.LightPurple,
+ vName = C.Cyan,
+ val = C.LightGreen,
+ em = C.Cyan,
+
+ # Emphasized colors for the last frame of the traceback
+ normalEm = C.Cyan,
+ filenameEm = C.Green,
+ linenoEm = C.Green,
+ nameEm = C.Purple,
+ valEm = C.Blue,
+
+ # Colors for printing the exception
+ excName = C.Red,
+ #line = C.Brown, # brown often is displayed as yellow
+ line = C.Red,
+ caret = C.Normal,
+ Normal = C.Normal,
+ ))
+
+ return ex_colors
+
+
+# For backwards compatibility, keep around a single global object. Note that
+# this should NOT be used, the factory function should be used instead, since
+# these objects are stateful and it's very easy to get strange bugs if any code
+# modifies the module-level object's state.
+ExceptionColors = exception_colors()
diff --git a/IPython/external/Itpl.py b/IPython/external/Itpl.py
new file mode 100644
index 0000000..3423fe4
--- /dev/null
+++ b/IPython/external/Itpl.py
@@ -0,0 +1,276 @@
+# -*- coding: utf-8 -*-
+"""String interpolation for Python (by Ka-Ping Yee, 14 Feb 2000).
+
+This module lets you quickly and conveniently interpolate values into
+strings (in the flavour of Perl or Tcl, but with less extraneous
+punctuation). You get a bit more power than in the other languages,
+because this module allows subscripting, slicing, function calls,
+attribute lookup, or arbitrary expressions. Variables and expressions
+are evaluated in the namespace of the caller.
+
+The itpl() function returns the result of interpolating a string, and
+printpl() prints out an interpolated string. Here are some examples:
+
+ from Itpl import printpl
+ printpl("Here is a $string.")
+ printpl("Here is a $module.member.")
+ printpl("Here is an $object.member.")
+ printpl("Here is a $functioncall(with, arguments).")
+ printpl("Here is an ${arbitrary + expression}.")
+ printpl("Here is an $array[3] member.")
+ printpl("Here is a $dictionary['member'].")
+
+The filter() function filters a file object so that output through it
+is interpolated. This lets you produce the illusion that Python knows
+how to do interpolation:
+
+ import Itpl
+ sys.stdout = Itpl.filter()
+ f = "fancy"
+ print "Is this not $f?"
+ print "Standard output has been replaced with a $sys.stdout object."
+ sys.stdout = Itpl.unfilter()
+ print "Okay, back $to $normal."
+
+Under the hood, the Itpl class represents a string that knows how to
+interpolate values. An instance of the class parses the string once
+upon initialization; the evaluation and substitution can then be done
+each time the instance is evaluated with str(instance). For example:
+
+ from Itpl import Itpl
+ s = Itpl("Here is $foo.")
+ foo = 5
+ print str(s)
+ foo = "bar"
+ print str(s)
+"""
+
+#*****************************************************************************
+#
+# Copyright (c) 2001 Ka-Ping Yee <ping@lfw.org>
+#
+#
+# Published under the terms of the MIT license, hereby reproduced:
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+#
+#*****************************************************************************
+
+__author__ = 'Ka-Ping Yee <ping@lfw.org>'
+__license__ = 'MIT'
+
+import string
+import sys
+from tokenize import tokenprog
+from types import StringType
+
+class ItplError(ValueError):
+ def __init__(self, text, pos):
+ self.text = text
+ self.pos = pos
+ def __str__(self):
+ return "unfinished expression in %s at char %d" % (
+ repr(self.text), self.pos)
+
+def matchorfail(text, pos):
+ match = tokenprog.match(text, pos)
+ if match is None:
+ raise ItplError(text, pos)
+ return match, match.end()
+
+class Itpl:
+ """Class representing a string with interpolation abilities.
+
+ Upon creation, an instance works out what parts of the format
+ string are literal and what parts need to be evaluated. The
+ evaluation and substitution happens in the namespace of the
+ caller when str(instance) is called."""
+
+ def __init__(self, format,codec='utf_8',encoding_errors='backslashreplace'):
+ """The single mandatory argument to this constructor is a format
+ string.
+
+ The format string is parsed according to the following rules:
+
+ 1. A dollar sign and a name, possibly followed by any of:
+ - an open-paren, and anything up to the matching paren
+ - an open-bracket, and anything up to the matching bracket
+ - a period and a name
+ any number of times, is evaluated as a Python expression.
+
+ 2. A dollar sign immediately followed by an open-brace, and
+ anything up to the matching close-brace, is evaluated as
+ a Python expression.
+
+ 3. Outside of the expressions described in the above two rules,
+ two dollar signs in a row give you one literal dollar sign.
+
+ Optional arguments:
+
+ - codec('utf_8'): a string containing the name of a valid Python
+ codec.
+
+ - encoding_errors('backslashreplace'): a string with a valid error handling
+ policy. See the codecs module documentation for details.
+
+ These are used to encode the format string if a call to str() fails on
+ the expanded result."""
+
+ if not isinstance(format,basestring):
+ raise TypeError, "needs string initializer"
+ self.format = format
+ self.codec = codec
+ self.encoding_errors = encoding_errors
+
+ namechars = "abcdefghijklmnopqrstuvwxyz" \
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
+ chunks = []
+ pos = 0
+
+ while 1:
+ dollar = string.find(format, "$", pos)
+ if dollar < 0: break
+ nextchar = format[dollar+1]
+
+ if nextchar == "{":
+ chunks.append((0, format[pos:dollar]))
+ pos, level = dollar+2, 1
+ while level:
+ match, pos = matchorfail(format, pos)
+ tstart, tend = match.regs[3]
+ token = format[tstart:tend]
+ if token == "{": level = level+1
+ elif token == "}": level = level-1
+ chunks.append((1, format[dollar+2:pos-1]))
+
+ elif nextchar in namechars:
+ chunks.append((0, format[pos:dollar]))
+ match, pos = matchorfail(format, dollar+1)
+ while pos < len(format):
+ if format[pos] == "." and \
+ pos+1 < len(format) and format[pos+1] in namechars:
+ match, pos = matchorfail(format, pos+1)
+ elif format[pos] in "([":
+ pos, level = pos+1, 1
+ while level:
+ match, pos = matchorfail(format, pos)
+ tstart, tend = match.regs[3]
+ token = format[tstart:tend]
+ if token[0] in "([": level = level+1
+ elif token[0] in ")]": level = level-1
+ else: break
+ chunks.append((1, format[dollar+1:pos]))
+
+ else:
+ chunks.append((0, format[pos:dollar+1]))
+ pos = dollar + 1 + (nextchar == "$")
+
+ if pos < len(format): chunks.append((0, format[pos:]))
+ self.chunks = chunks
+
+ def __repr__(self):
+ return "<Itpl %s >" % repr(self.format)
+
+ def _str(self,glob,loc):
+ """Evaluate to a string in the given globals/locals.
+
+ The final output is built by calling str(), but if this fails, the
+ result is encoded with the instance's codec and error handling policy,
+ via a call to out.encode(self.codec,self.encoding_errors)"""
+ result = []
+ app = result.append
+ for live, chunk in self.chunks:
+ if live: app(str(eval(chunk,glob,loc)))
+ else: app(chunk)
+ out = ''.join(result)
+ try:
+ return str(out)
+ except UnicodeError:
+ return out.encode(self.codec,self.encoding_errors)
+
+ def __str__(self):
+ """Evaluate and substitute the appropriate parts of the string."""
+
+ # We need to skip enough frames to get to the actual caller outside of
+ # Itpl.
+ frame = sys._getframe(1)
+ while frame.f_globals["__name__"] == __name__: frame = frame.f_back
+ loc, glob = frame.f_locals, frame.f_globals
+
+ return self._str(glob,loc)
+
+class ItplNS(Itpl):
+ """Class representing a string with interpolation abilities.
+
+ This inherits from Itpl, but at creation time a namespace is provided
+ where the evaluation will occur. The interpolation becomes a bit more
+ efficient, as no traceback needs to be extracte. It also allows the
+ caller to supply a different namespace for the interpolation to occur than
+ its own."""
+
+ def __init__(self, format,globals,locals=None,
+ codec='utf_8',encoding_errors='backslashreplace'):
+ """ItplNS(format,globals[,locals]) -> interpolating string instance.
+
+ This constructor, besides a format string, takes a globals dictionary
+ and optionally a locals (which defaults to globals if not provided).
+
+ For further details, see the Itpl constructor."""
+
+ if locals is None:
+ locals = globals
+ self.globals = globals
+ self.locals = locals
+ Itpl.__init__(self,format,codec,encoding_errors)
+
+ def __str__(self):
+ """Evaluate and substitute the appropriate parts of the string."""
+ return self._str(self.globals,self.locals)
+
+ def __repr__(self):
+ return "<ItplNS %s >" % repr(self.format)
+
+# utilities for fast printing
+def itpl(text): return str(Itpl(text))
+def printpl(text): print itpl(text)
+# versions with namespace
+def itplns(text,globals,locals=None): return str(ItplNS(text,globals,locals))
+def printplns(text,globals,locals=None): print itplns(text,globals,locals)
+
+class ItplFile:
+ """A file object that filters each write() through an interpolator."""
+ def __init__(self, file): self.file = file
+ def __repr__(self): return "<interpolated " + repr(self.file) + ">"
+ def __getattr__(self, attr): return getattr(self.file, attr)
+ def write(self, text): self.file.write(str(Itpl(text)))
+
+def filter(file=sys.stdout):
+ """Return an ItplFile that filters writes to the given file object.
+
+ 'file = filter(file)' replaces 'file' with a filtered object that
+ has a write() method. When called with no argument, this creates
+ a filter to sys.stdout."""
+ return ItplFile(file)
+
+def unfilter(ifile=None):
+ """Return the original file that corresponds to the given ItplFile.
+
+ 'file = unfilter(file)' undoes the effect of 'file = filter(file)'.
+ 'sys.stdout = unfilter()' undoes the effect of 'sys.stdout = filter()'."""
+ return ifile and ifile.file or sys.stdout.file
diff --git a/IPython/external/__init__.py b/IPython/external/__init__.py
new file mode 100644
index 0000000..3104c19
--- /dev/null
+++ b/IPython/external/__init__.py
@@ -0,0 +1,5 @@
+"""
+This package contains all third-party modules bundled with IPython.
+"""
+
+__all__ = ["simplegeneric"]
diff --git a/IPython/external/argparse.py b/IPython/external/argparse.py
new file mode 100644
index 0000000..73b48b6
--- /dev/null
+++ b/IPython/external/argparse.py
@@ -0,0 +1,2216 @@
+# -*- coding: utf-8 -*-
+
+# Copyright © 2006-2009 Steven J. Bethard <steven.bethard@gmail.com>.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy
+# of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+"""Command-line parsing library
+
+This module is an optparse-inspired command-line parsing library that:
+
+ - handles both optional and positional arguments
+ - produces highly informative usage messages
+ - supports parsers that dispatch to sub-parsers
+
+The following is a simple usage example that sums integers from the
+command-line and writes the result to a file::
+
+ parser = argparse.ArgumentParser(
+ description='sum the integers at the command line')
+ parser.add_argument(
+ 'integers', metavar='int', nargs='+', type=int,
+ help='an integer to be summed')
+ parser.add_argument(
+ '--log', default=sys.stdout, type=argparse.FileType('w'),
+ help='the file where the sum should be written')
+ args = parser.parse_args()
+ args.log.write('%s' % sum(args.integers))
+ args.log.close()
+
+The module contains the following public classes:
+
+ - ArgumentParser -- The main entry point for command-line parsing. As the
+ example above shows, the add_argument() method is used to populate
+ the parser with actions for optional and positional arguments. Then
+ the parse_args() method is invoked to convert the args at the
+ command-line into an object with attributes.
+
+ - ArgumentError -- The exception raised by ArgumentParser objects when
+ there are errors with the parser's actions. Errors raised while
+ parsing the command-line are caught by ArgumentParser and emitted
+ as command-line messages.
+
+ - FileType -- A factory for defining types of files to be created. As the
+ example above shows, instances of FileType are typically passed as
+ the type= argument of add_argument() calls.
+
+ - Action -- The base class for parser actions. Typically actions are
+ selected by passing strings like 'store_true' or 'append_const' to
+ the action= argument of add_argument(). However, for greater
+ customization of ArgumentParser actions, subclasses of Action may
+ be defined and passed as the action= argument.
+
+ - HelpFormatter, RawDescriptionHelpFormatter, RawTextHelpFormatter,
+ ArgumentDefaultsHelpFormatter -- Formatter classes which
+ may be passed as the formatter_class= argument to the
+ ArgumentParser constructor. HelpFormatter is the default,
+ RawDescriptionHelpFormatter and RawTextHelpFormatter tell the parser
+ not to change the formatting for help text, and
+ ArgumentDefaultsHelpFormatter adds information about argument defaults
+ to the help.
+
+All other classes in this module are considered implementation details.
+(Also note that HelpFormatter and RawDescriptionHelpFormatter are only
+considered public as object names -- the API of the formatter objects is
+still considered an implementation detail.)
+"""
+
+__version__ = '1.0'
+__all__ = [
+ 'ArgumentParser',
+ 'ArgumentError',
+ 'Namespace',
+ 'Action',
+ 'FileType',
+ 'HelpFormatter',
+ 'RawDescriptionHelpFormatter',
+ 'RawTextHelpFormatter'
+ 'ArgumentDefaultsHelpFormatter',
+]
+
+
+import copy as _copy
+import os as _os
+import re as _re
+import sys as _sys
+import textwrap as _textwrap
+
+from gettext import gettext as _
+
+try:
+ _set = set
+except NameError:
+ from sets import Set as _set
+
+try:
+ _basestring = basestring
+except NameError:
+ _basestring = str
+
+try:
+ _sorted = sorted
+except NameError:
+
+ def _sorted(iterable, reverse=False):
+ result = list(iterable)
+ result.sort()
+ if reverse:
+ result.reverse()
+ return result
+
+
+SUPPRESS = '==SUPPRESS=='
+
+OPTIONAL = '?'
+ZERO_OR_MORE = '*'
+ONE_OR_MORE = '+'
+PARSER = '==PARSER=='
+
+# =============================
+# Utility functions and classes
+# =============================
+
+class _AttributeHolder(object):
+ """Abstract base class that provides __repr__.
+
+ The __repr__ method returns a string in the format::
+ ClassName(attr=name, attr=name, ...)
+ The attributes are determined either by a class-level attribute,
+ '_kwarg_names', or by inspecting the instance __dict__.
+ """
+
+ def __repr__(self):
+ type_name = type(self).__name__
+ arg_strings = []
+ for arg in self._get_args():
+ arg_strings.append(repr(arg))
+ for name, value in self._get_kwargs():
+ arg_strings.append('%s=%r' % (name, value))
+ return '%s(%s)' % (type_name, ', '.join(arg_strings))
+
+ def _get_kwargs(self):
+ return _sorted(self.__dict__.items())
+
+ def _get_args(self):
+ return []
+
+
+def _ensure_value(namespace, name, value):
+ if getattr(namespace, name, None) is None:
+ setattr(namespace, name, value)
+ return getattr(namespace, name)
+
+
+# ===============
+# Formatting Help
+# ===============
+
+class HelpFormatter(object):
+ """Formatter for generating usage messages and argument help strings.
+
+ Only the name of this class is considered a public API. All the methods
+ provided by the class are considered an implementation detail.
+ """
+
+ def __init__(self,
+ prog,
+ indent_increment=2,
+ max_help_position=24,
+ width=None):
+
+ # default setting for width
+ if width is None:
+ try:
+ width = int(_os.environ['COLUMNS'])
+ except (KeyError, ValueError):
+ width = 80
+ width -= 2
+
+ self._prog = prog
+ self._indent_increment = indent_increment
+ self._max_help_position = max_help_position
+ self._width = width
+
+ self._current_indent = 0
+ self._level = 0
+ self._action_max_length = 0
+
+ self._root_section = self._Section(self, None)
+ self._current_section = self._root_section
+
+ self._whitespace_matcher = _re.compile(r'\s+')
+ self._long_break_matcher = _re.compile(r'\n\n\n+')
+
+ # ===============================
+ # Section and indentation methods
+ # ===============================
+ def _indent(self):
+ self._current_indent += self._indent_increment
+ self._level += 1
+
+ def _dedent(self):
+ self._current_indent -= self._indent_increment
+ assert self._current_indent >= 0, 'Indent decreased below 0.'
+ self._level -= 1
+
+ class _Section(object):
+
+ def __init__(self, formatter, parent, heading=None):
+ self.formatter = formatter
+ self.parent = parent
+ self.heading = heading
+ self.items = []
+
+ def format_help(self):
+ # format the indented section
+ if self.parent is not None:
+ self.formatter._indent()
+ join = self.formatter._join_parts
+ for func, args in self.items:
+ func(*args)
+ item_help = join([func(*args) for func, args in self.items])
+ if self.parent is not None:
+ self.formatter._dedent()
+
+ # return nothing if the section was empty
+ if not item_help:
+ return ''
+
+ # add the heading if the section was non-empty
+ if self.heading is not SUPPRESS and self.heading is not None:
+ current_indent = self.formatter._current_indent
+ heading = '%*s%s:\n' % (current_indent, '', self.heading)
+ else:
+ heading = ''
+
+ # join the section-initial newline, the heading and the help
+ return join(['\n', heading, item_help, '\n'])
+
+ def _add_item(self, func, args):
+ self._current_section.items.append((func, args))
+
+ # ========================
+ # Message building methods
+ # ========================
+ def start_section(self, heading):
+ self._indent()
+ section = self._Section(self, self._current_section, heading)
+ self._add_item(section.format_help, [])
+ self._current_section = section
+
+ def end_section(self):
+ self._current_section = self._current_section.parent
+ self._dedent()
+
+ def add_text(self, text):
+ if text is not SUPPRESS and text is not None:
+ self._add_item(self._format_text, [text])
+
+ def add_usage(self, usage, actions, groups, prefix=None):
+ if usage is not SUPPRESS:
+ args = usage, actions, groups, prefix
+ self._add_item(self._format_usage, args)
+
+ def add_argument(self, action):
+ if action.help is not SUPPRESS:
+
+ # find all invocations
+ get_invocation = self._format_action_invocation
+ invocations = [get_invocation(action)]
+ for subaction in self._iter_indented_subactions(action):
+ invocations.append(get_invocation(subaction))
+
+ # update the maximum item length
+ invocation_length = max([len(s) for s in invocations])
+ action_length = invocation_length + self._current_indent
+ self._action_max_length = max(self._action_max_length,
+ action_length)
+
+ # add the item to the list
+ self._add_item(self._format_action, [action])
+
+ def add_arguments(self, actions):
+ for action in actions:
+ self.add_argument(action)
+
+ # =======================
+ # Help-formatting methods
+ # =======================
+ def format_help(self):
+ help = self._root_section.format_help() % dict(prog=self._prog)
+ if help:
+ help = self._long_break_matcher.sub('\n\n', help)
+ help = help.strip('\n') + '\n'
+ return help
+
+ def _join_parts(self, part_strings):
+ return ''.join([part
+ for part in part_strings
+ if part and part is not SUPPRESS])
+
+ def _format_usage(self, usage, actions, groups, prefix):
+ if prefix is None:
+ prefix = _('usage: ')
+
+ # if no optionals or positionals are available, usage is just prog
+ if usage is None and not actions:
+ usage = '%(prog)s'
+
+ # if optionals and positionals are available, calculate usage
+ elif usage is None:
+ usage = '%(prog)s' % dict(prog=self._prog)
+
+ # split optionals from positionals
+ optionals = []
+ positionals = []
+ for action in actions:
+ if action.option_strings:
+ optionals.append(action)
+ else:
+ positionals.append(action)
+
+ # determine width of "usage: PROG" and width of text
+ prefix_width = len(prefix) + len(usage) + 1
+ prefix_indent = self._current_indent + prefix_width
+ text_width = self._width - self._current_indent
+
+ # put them on one line if they're short enough
+ format = self._format_actions_usage
+ action_usage = format(optionals + positionals, groups)
+ if prefix_width + len(action_usage) + 1 < text_width:
+ usage = '%s %s' % (usage, action_usage)
+
+ # if they're long, wrap optionals and positionals individually
+ else:
+ optional_usage = format(optionals, groups)
+ positional_usage = format(positionals, groups)
+ indent = ' ' * prefix_indent
+
+ # usage is made of PROG, optionals and positionals
+ parts = [usage, ' ']
+
+ # options always get added right after PROG
+ if optional_usage:
+ parts.append(_textwrap.fill(
+ optional_usage, text_width,
+ initial_indent=indent,
+ subsequent_indent=indent).lstrip())
+
+ # if there were options, put arguments on the next line
+ # otherwise, start them right after PROG
+ if positional_usage:
+ part = _textwrap.fill(
+ positional_usage, text_width,
+ initial_indent=indent,
+ subsequent_indent=indent).lstrip()
+ if optional_usage:
+ part = '\n' + indent + part
+ parts.append(part)
+ usage = ''.join(parts)
+
+ # prefix with 'usage:'
+ return '%s%s\n\n' % (prefix, usage)
+
+ def _format_actions_usage(self, actions, groups):
+ # find group indices and identify actions in groups
+ group_actions = _set()
+ inserts = {}
+ for group in groups:
+ try:
+ start = actions.index(group._group_actions[0])
+ except ValueError:
+ continue
+ else:
+ end = start + len(group._group_actions)
+ if actions[start:end] == group._group_actions:
+ for action in group._group_actions:
+ group_actions.add(action)
+ if not group.required:
+ inserts[start] = '['
+ inserts[end] = ']'
+ else:
+ inserts[start] = '('
+ inserts[end] = ')'
+ for i in range(start + 1, end):
+ inserts[i] = '|'
+
+ # collect all actions format strings
+ parts = []
+ for i, action in enumerate(actions):
+
+ # suppressed arguments are marked with None
+ # remove | separators for suppressed arguments
+ if action.help is SUPPRESS:
+ parts.append(None)
+ if inserts.get(i) == '|':
+ inserts.pop(i)
+ elif inserts.get(i + 1) == '|':
+ inserts.pop(i + 1)
+
+ # produce all arg strings
+ elif not action.option_strings:
+ part = self._format_args(action, action.dest)
+
+ # if it's in a group, strip the outer []
+ if action in group_actions:
+ if part[0] == '[' and part[-1] == ']':
+ part = part[1:-1]
+
+ # add the action string to the list
+ parts.append(part)
+
+ # produce the first way to invoke the option in brackets
+ else:
+ option_string = action.option_strings[0]
+
+ # if the Optional doesn't take a value, format is:
+ # -s or --long
+ if action.nargs == 0:
+ part = '%s' % option_string
+
+ # if the Optional takes a value, format is:
+ # -s ARGS or --long ARGS
+ else:
+ default = action.dest.upper()
+ args_string = self._format_args(action, default)
+ part = '%s %s' % (option_string, args_string)
+
+ # make it look optional if it's not required or in a group
+ if not action.required and action not in group_actions:
+ part = '[%s]' % part
+
+ # add the action string to the list
+ parts.append(part)
+
+ # insert things at the necessary indices
+ for i in _sorted(inserts, reverse=True):
+ parts[i:i] = [inserts[i]]
+
+ # join all the action items with spaces
+ text = ' '.join([item for item in parts if item is not None])
+
+ # clean up separators for mutually exclusive groups
+ open = r'[\[(]'
+ close = r'[\])]'
+ text = _re.sub(r'(%s) ' % open, r'\1', text)
+ text = _re.sub(r' (%s)' % close, r'\1', text)
+ text = _re.sub(r'%s *%s' % (open, close), r'', text)
+ text = _re.sub(r'\(([^|]*)\)', r'\1', text)
+ text = text.strip()
+
+ # return the text
+ return text
+
+ def _format_text(self, text):
+ text_width = self._width - self._current_indent
+ indent = ' ' * self._current_indent
+ return self._fill_text(text, text_width, indent) + '\n\n'
+
+ def _format_action(self, action):
+ # determine the required width and the entry label
+ help_position = min(self._action_max_length + 2,
+ self._max_help_position)
+ help_width = self._width - help_position
+ action_width = help_position - self._current_indent - 2
+ action_header = self._format_action_invocation(action)
+
+ # ho nelp; start on same line and add a final newline
+ if not action.help:
+ tup = self._current_indent, '', action_header
+ action_header = '%*s%s\n' % tup
+
+ # short action name; start on the same line and pad two spaces
+ elif len(action_header) <= action_width:
+ tup = self._current_indent, '', action_width, action_header
+ action_header = '%*s%-*s ' % tup
+ indent_first = 0
+
+ # long action name; start on the next line
+ else:
+ tup = self._current_indent, '', action_header
+ action_header = '%*s%s\n' % tup
+ indent_first = help_position
+
+ # collect the pieces of the action help
+ parts = [action_header]
+
+ # if there was help for the action, add lines of help text
+ if action.help:
+ help_text = self._expand_help(action)
+ help_lines = self._split_lines(help_text, help_width)
+ parts.append('%*s%s\n' % (indent_first, '', help_lines[0]))
+ for line in help_lines[1:]:
+ parts.append('%*s%s\n' % (help_position, '', line))
+
+ # or add a newline if the description doesn't end with one
+ elif not action_header.endswith('\n'):
+ parts.append('\n')
+
+ # if there are any sub-actions, add their help as well
+ for subaction in self._iter_indented_subactions(action):
+ parts.append(self._format_action(subaction))
+
+ # return a single string
+ return self._join_parts(parts)
+
+ def _format_action_invocation(self, action):
+ if not action.option_strings:
+ metavar, = self._metavar_formatter(action, action.dest)(1)
+ return metavar
+
+ else:
+ parts = []
+
+ # if the Optional doesn't take a value, format is:
+ # -s, --long
+ if action.nargs == 0:
+ parts.extend(action.option_strings)
+
+ # if the Optional takes a value, format is:
+ # -s ARGS, --long ARGS
+ else:
+ default = action.dest.upper()
+ args_string = self._format_args(action, default)
+ for option_string in action.option_strings:
+ parts.append('%s %s' % (option_string, args_string))
+
+ return ', '.join(parts)
+
+ def _metavar_formatter(self, action, default_metavar):
+ if action.metavar is not None:
+ result = action.metavar
+ elif action.choices is not None:
+ choice_strs = [str(choice) for choice in action.choices]
+ result = '{%s}' % ','.join(choice_strs)
+ else:
+ result = default_metavar
+
+ def format(tuple_size):
+ if isinstance(result, tuple):
+ return result
+ else:
+ return (result, ) * tuple_size
+ return format
+
+ def _format_args(self, action, default_metavar):
+ get_metavar = self._metavar_formatter(action, default_metavar)
+ if action.nargs is None:
+ result = '%s' % get_metavar(1)
+ elif action.nargs == OPTIONAL:
+ result = '[%s]' % get_metavar(1)
+ elif action.nargs == ZERO_OR_MORE:
+ result = '[%s [%s ...]]' % get_metavar(2)
+ elif action.nargs == ONE_OR_MORE:
+ result = '%s [%s ...]' % get_metavar(2)
+ elif action.nargs is PARSER:
+ result = '%s ...' % get_metavar(1)
+ else:
+ formats = ['%s' for _ in range(action.nargs)]
+ result = ' '.join(formats) % get_metavar(action.nargs)
+ return result
+
+ def _expand_help(self, action):
+ params = dict(vars(action), prog=self._prog)
+ for name in list(params):
+ if params[name] is SUPPRESS:
+ del params[name]
+ if params.get('choices') is not None:
+ choices_str = ', '.join([str(c) for c in params['choices']])
+ params['choices'] = choices_str
+ return self._get_help_string(action) % params
+
+ def _iter_indented_subactions(self, action):
+ try:
+ get_subactions = action._get_subactions
+ except AttributeError:
+ pass
+ else:
+ self._indent()
+ for subaction in get_subactions():
+ yield subaction
+ self._dedent()
+
+ def _split_lines(self, text, width):
+ text = self._whitespace_matcher.sub(' ', text).strip()
+ return _textwrap.wrap(text, width)
+
+ def _fill_text(self, text, width, indent):
+ text = self._whitespace_matcher.sub(' ', text).strip()
+ return _textwrap.fill(text, width, initial_indent=indent,
+ subsequent_indent=indent)
+
+ def _get_help_string(self, action):
+ return action.help
+
+
+class RawDescriptionHelpFormatter(HelpFormatter):
+ """Help message formatter which retains any formatting in descriptions.
+
+ Only the name of this class is considered a public API. All the methods
+ provided by the class are considered an implementation detail.
+ """
+
+ def _fill_text(self, text, width, indent):
+ return ''.join([indent + line for line in text.splitlines(True)])
+
+
+class RawTextHelpFormatter(RawDescriptionHelpFormatter):
+ """Help message formatter which retains formatting of all help text.
+
+ Only the name of this class is considered a public API. All the methods
+ provided by the class are considered an implementation detail.
+ """
+
+ def _split_lines(self, text, width):
+ return text.splitlines()
+
+
+class ArgumentDefaultsHelpFormatter(HelpFormatter):
+ """Help message formatter which adds default values to argument help.
+
+ Only the name of this class is considered a public API. All the methods
+ provided by the class are considered an implementation detail.
+ """
+
+ def _get_help_string(self, action):
+ help = action.help
+ if '%(default)' not in action.help:
+ if action.default is not SUPPRESS:
+ defaulting_nargs = [OPTIONAL, ZERO_OR_MORE]
+ if action.option_strings or action.nargs in defaulting_nargs:
+ help += ' (default: %(default)s)'
+ return help
+
+
+# =====================
+# Options and Arguments
+# =====================
+
+def _get_action_name(argument):
+ if argument is None:
+ return None
+ elif argument.option_strings:
+ return '/'.join(argument.option_strings)
+ elif argument.metavar not in (None, SUPPRESS):
+ return argument.metavar
+ elif argument.dest not in (None, SUPPRESS):
+ return argument.dest
+ else:
+ return None
+
+
+class ArgumentError(Exception):
+ """An error from creating or using an argument (optional or positional).
+
+ The string value of this exception is the message, augmented with
+ information about the argument that caused it.
+ """
+
+ def __init__(self, argument, message):
+ self.argument_name = _get_action_name(argument)
+ self.message = message
+
+ def __str__(self):
+ if self.argument_name is None:
+ format = '%(message)s'
+ else:
+ format = 'argument %(argument_name)s: %(message)s'
+ return format % dict(message=self.message,
+ argument_name=self.argument_name)
+
+# ==============
+# Action classes
+# ==============
+
+class Action(_AttributeHolder):
+ """Information about how to convert command line strings to Python objects.
+
+ Action objects are used by an ArgumentParser to represent the information
+ needed to parse a single argument from one or more strings from the
+ command line. The keyword arguments to the Action constructor are also
+ all attributes of Action instances.
+
+ Keyword Arguments:
+
+ - option_strings -- A list of command-line option strings which
+ should be associated with this action.
+
+ - dest -- The name of the attribute to hold the created object(s)
+
+ - nargs -- The number of command-line arguments that should be
+ consumed. By default, one argument will be consumed and a single
+ value will be produced. Other values include:
+ - N (an integer) consumes N arguments (and produces a list)
+ - '?' consumes zero or one arguments
+ - '*' consumes zero or more arguments (and produces a list)
+ - '+' consumes one or more arguments (and produces a list)
+ Note that the difference between the default and nargs=1 is that
+ with the default, a single value will be produced, while with
+ nargs=1, a list containing a single value will be produced.
+
+ - const -- The value to be produced if the option is specified and the
+ option uses an action that takes no values.
+
+ - default -- The value to be produced if the option is not specified.
+
+ - type -- The type which the command-line arguments should be converted
+ to, should be one of 'string', 'int', 'float', 'complex' or a
+ callable object that accepts a single string argument. If None,
+ 'string' is assumed.
+
+ - choices -- A container of values that should be allowed. If not None,
+ after a command-line argument has been converted to the appropriate
+ type, an exception will be raised if it is not a member of this
+ collection.
+
+ - required -- True if the action must always be specified at the
+ command line. This is only meaningful for optional command-line
+ arguments.
+
+ - help -- The help string describing the argument.
+
+ - metavar -- The name to be used for the option's argument with the
+ help string. If None, the 'dest' value will be used as the name.
+ """
+
+ def __init__(self,
+ option_strings,
+ dest,
+ nargs=None,
+ const=None,
+ default=None,
+ type=None,
+ choices=None,
+ required=False,
+ help=None,
+ metavar=None):
+ self.option_strings = option_strings
+ self.dest = dest
+ self.nargs = nargs
+ self.const = const
+ self.default = default
+ self.type = type
+ self.choices = choices
+ self.required = required
+ self.help = help
+ self.metavar = metavar
+
+ def _get_kwargs(self):
+ names = [
+ 'option_strings',
+ 'dest',
+ 'nargs',
+ 'const',
+ 'default',
+ 'type',
+ 'choices',
+ 'help',
+ 'metavar',
+ ]
+ return [(name, getattr(self, name)) for name in names]
+
+ def __call__(self, parser, namespace, values, option_string=None):
+ raise NotImplementedError(_('.__call__() not defined'))
+
+
+class _StoreAction(Action):
+
+ def __init__(self,
+ option_strings,
+ dest,
+ nargs=None,
+ const=None,
+ default=None,
+ type=None,
+ choices=None,
+ required=False,
+ help=None,
+ metavar=None):
+ if nargs == 0:
+ raise ValueError('nargs must be > 0')
+ if const is not None and nargs != OPTIONAL:
+ raise ValueError('nargs must be %r to supply const' % OPTIONAL)
+ super(_StoreAction, self).__init__(
+ option_strings=option_strings,
+ dest=dest,
+ nargs=nargs,
+ const=const,
+ default=default,
+ type=type,
+ choices=choices,
+ required=required,
+ help=help,
+ metavar=metavar)
+
+ def __call__(self, parser, namespace, values, option_string=None):
+ setattr(namespace, self.dest, values)
+
+
+class _StoreConstAction(Action):
+
+ def __init__(self,
+ option_strings,
+ dest,
+ const,
+ default=None,
+ required=False,
+ help=None,
+ metavar=None):
+ super(_StoreConstAction, self).__init__(
+ option_strings=option_strings,
+ dest=dest,
+ nargs=0,
+ const=const,
+ default=default,
+ required=required,
+ help=help)
+
+ def __call__(self, parser, namespace, values, option_string=None):
+ setattr(namespace, self.dest, self.const)
+
+
+class _StoreTrueAction(_StoreConstAction):
+
+ def __init__(self,
+ option_strings,
+ dest,
+ default=False,
+ required=False,
+ help=None):
+ super(_StoreTrueAction, self).__init__(
+ option_strings=option_strings,
+ dest=dest,
+ const=True,
+ default=default,
+ required=required,
+ help=help)
+
+
+class _StoreFalseAction(_StoreConstAction):
+
+ def __init__(self,
+ option_strings,
+ dest,
+ default=True,
+ required=False,
+ help=None):
+ super(_StoreFalseAction, self).__init__(
+ option_strings=option_strings,
+ dest=dest,
+ const=False,
+ default=default,
+ required=required,
+ help=help)
+
+
+class _AppendAction(Action):
+
+ def __init__(self,
+ option_strings,
+ dest,
+ nargs=None,
+ const=None,
+ default=None,
+ type=None,
+ choices=None,
+ required=False,
+ help=None,
+ metavar=None):
+ if nargs == 0:
+ raise ValueError('nargs must be > 0')
+ if const is not None and nargs != OPTIONAL:
+ raise ValueError('nargs must be %r to supply const' % OPTIONAL)
+ super(_AppendAction, self).__init__(
+ option_strings=option_strings,
+ dest=dest,
+ nargs=nargs,
+ const=const,
+ default=default,
+ type=type,
+ choices=choices,
+ required=required,
+ help=help,
+ metavar=metavar)
+
+ def __call__(self, parser, namespace, values, option_string=None):
+ items = _copy.copy(_ensure_value(namespace, self.dest, []))
+ items.append(values)
+ setattr(namespace, self.dest, items)
+
+
+class _AppendConstAction(Action):
+
+ def __init__(self,
+ option_strings,
+ dest,
+ const,
+ default=None,
+ required=False,
+ help=None,
+ metavar=None):
+ super(_AppendConstAction, self).__init__(
+ option_strings=option_strings,
+ dest=dest,
+ nargs=0,
+ const=const,
+ default=default,
+ required=required,
+ help=help,
+ metavar=metavar)
+
+ def __call__(self, parser, namespace, values, option_string=None):
+ items = _copy.copy(_ensure_value(namespace, self.dest, []))
+ items.append(self.const)
+ setattr(namespace, self.dest, items)
+
+
+class _CountAction(Action):
+
+ def __init__(self,
+ option_strings,
+ dest,
+ default=None,
+ required=False,
+ help=None):
+ super(_CountAction, self).__init__(
+ option_strings=option_strings,
+ dest=dest,
+ nargs=0,
+ default=default,
+ required=required,
+ help=help)
+
+ def __call__(self, parser, namespace, values, option_string=None):
+ new_count = _ensure_value(namespace, self.dest, 0) + 1
+ setattr(namespace, self.dest, new_count)
+
+
+class _HelpAction(Action):
+
+ def __init__(self,
+ option_strings,
+ dest=SUPPRESS,
+ default=SUPPRESS,
+ help=None):
+ super(_HelpAction, self).__init__(
+ option_strings=option_strings,
+ dest=dest,
+ default=default,
+ nargs=0,
+ help=help)
+
+ def __call__(self, parser, namespace, values, option_string=None):
+ parser.print_help()
+ parser.exit()
+
+
+class _VersionAction(Action):
+
+ def __init__(self,
+ option_strings,
+ dest=SUPPRESS,
+ default=SUPPRESS,
+ help=None):
+ super(_VersionAction, self).__init__(
+ option_strings=option_strings,
+ dest=dest,
+ default=default,
+ nargs=0,
+ help=help)
+
+ def __call__(self, parser, namespace, values, option_string=None):
+ parser.print_version()
+ parser.exit()
+
+
+class _SubParsersAction(Action):
+
+ class _ChoicesPseudoAction(Action):
+
+ def __init__(self, name, help):
+ sup = super(_SubParsersAction._ChoicesPseudoAction, self)
+ sup.__init__(option_strings=[], dest=name, help=help)
+
+ def __init__(self,
+ option_strings,
+ prog,
+ parser_class,
+ dest=SUPPRESS,
+ help=None,
+ metavar=None):
+
+ self._prog_prefix = prog
+ self._parser_class = parser_class
+ self._name_parser_map = {}
+ self._choices_actions = []
+
+ super(_SubParsersAction, self).__init__(
+ option_strings=option_strings,
+ dest=dest,
+ nargs=PARSER,
+ choices=self._name_parser_map,
+ help=help,
+ metavar=metavar)
+
+ def add_parser(self, name, **kwargs):
+ # set prog from the existing prefix
+ if kwargs.get('prog') is None:
+ kwargs['prog'] = '%s %s' % (self._prog_prefix, name)
+
+ # create a pseudo-action to hold the choice help
+ if 'help' in kwargs:
+ help = kwargs.pop('help')
+ choice_action = self._ChoicesPseudoAction(name, help)
+ self._choices_actions.append(choice_action)
+
+ # create the parser and add it to the map
+ parser = self._parser_class(**kwargs)
+ self._name_parser_map[name] = parser
+ return parser
+
+ def _get_subactions(self):
+ return self._choices_actions
+
+ def __call__(self, parser, namespace, values, option_string=None):
+ parser_name = values[0]
+ arg_strings = values[1:]
+
+ # set the parser name if requested
+ if self.dest is not SUPPRESS:
+ setattr(namespace, self.dest, parser_name)
+
+ # select the parser
+ try:
+ parser = self._name_parser_map[parser_name]
+ except KeyError:
+ tup = parser_name, ', '.join(self._name_parser_map)
+ msg = _('unknown parser %r (choices: %s)' % tup)
+ raise ArgumentError(self, msg)
+
+ # parse all the remaining options into the namespace
+ parser.parse_args(arg_strings, namespace)
+
+
+# ==============
+# Type classes
+# ==============
+
+class FileType(object):
+ """Factory for creating file object types
+
+ Instances of FileType are typically passed as type= arguments to the
+ ArgumentParser add_argument() method.
+
+ Keyword Arguments:
+ - mode -- A string indicating how the file is to be opened. Accepts the
+ same values as the builtin open() function.
+ - bufsize -- The file's desired buffer size. Accepts the same values as
+ the builtin open() function.
+ """
+
+ def __init__(self, mode='r', bufsize=None):
+ self._mode = mode
+ self._bufsize = bufsize
+
+ def __call__(self, string):
+ # the special argument "-" means sys.std{in,out}
+ if string == '-':
+ if 'r' in self._mode:
+ return _sys.stdin
+ elif 'w' in self._mode:
+ return _sys.stdout
+ else:
+ msg = _('argument "-" with mode %r' % self._mode)
+ raise ValueError(msg)
+
+ # all other arguments are used as file names
+ if self._bufsize:
+ return open(string, self._mode, self._bufsize)
+ else:
+ return open(string, self._mode)
+
+ def __repr__(self):
+ args = [self._mode, self._bufsize]
+ args_str = ', '.join([repr(arg) for arg in args if arg is not None])
+ return '%s(%s)' % (type(self).__name__, args_str)
+
+# ===========================
+# Optional and Positional Parsing
+# ===========================
+
+class Namespace(_AttributeHolder):
+ """Simple object for storing attributes.
+
+ Implements equality by attribute names and values, and provides a simple
+ string representation.
+ """
+
+ def __init__(self, **kwargs):
+ for name in kwargs:
+ setattr(self, name, kwargs[name])
+
+ def __eq__(self, other):
+ return vars(self) == vars(other)
+
+ def __ne__(self, other):
+ return not (self == other)
+
+
+class _ActionsContainer(object):
+
+ def __init__(self,
+ description,
+ prefix_chars,
+ argument_default,
+ conflict_handler):
+ super(_ActionsContainer, self).__init__()
+
+ self.description = description
+ self.argument_default = argument_default
+ self.prefix_chars = prefix_chars
+ self.conflict_handler = conflict_handler
+
+ # set up registries
+ self._registries = {}
+
+ # register actions
+ self.register('action', None, _StoreAction)
+ self.register('action', 'store', _StoreAction)
+ self.register('action', 'store_const', _StoreConstAction)
+ self.register('action', 'store_true', _StoreTrueAction)
+ self.register('action', 'store_false', _StoreFalseAction)
+ self.register('action', 'append', _AppendAction)
+ self.register('action', 'append_const', _AppendConstAction)
+ self.register('action', 'count', _CountAction)
+ self.register('action', 'help', _HelpAction)
+ self.register('action', 'version', _VersionAction)
+ self.register('action', 'parsers', _SubParsersAction)
+
+ # raise an exception if the conflict handler is invalid
+ self._get_handler()
+
+ # action storage
+ self._actions = []
+ self._option_string_actions = {}
+
+ # groups
+ self._action_groups = []
+ self._mutually_exclusive_groups = []
+
+ # defaults storage
+ self._defaults = {}
+
+ # determines whether an "option" looks like a negative number
+ self._negative_number_matcher = _re.compile(r'^-\d+|-\d*.\d+$')
+
+ # whether or not there are any optionals that look like negative
+ # numbers -- uses a list so it can be shared and edited
+ self._has_negative_number_optionals = []
+
+ # ====================
+ # Registration methods
+ # ====================
+ def register(self, registry_name, value, object):
+ registry = self._registries.setdefault(registry_name, {})
+ registry[value] = object
+
+ def _registry_get(self, registry_name, value, default=None):
+ return self._registries[registry_name].get(value, default)
+
+ # ==================================
+ # Namespace default settings methods
+ # ==================================
+ def set_defaults(self, **kwargs):
+ self._defaults.update(kwargs)
+
+ # if these defaults match any existing arguments, replace
+ # the previous default on the object with the new one
+ for action in self._actions:
+ if action.dest in kwargs:
+ action.default = kwargs[action.dest]
+
+ # =======================
+ # Adding argument actions
+ # =======================
+ def add_argument(self, *args, **kwargs):
+ """
+ add_argument(dest, ..., name=value, ...)
+ add_argument(option_string, option_string, ..., name=value, ...)
+ """
+
+ # if no positional args are supplied or only one is supplied and
+ # it doesn't look like an option string, parse a positional
+ # argument
+ chars = self.prefix_chars
+ if not args or len(args) == 1 and args[0][0] not in chars:
+ kwargs = self._get_positional_kwargs(*args, **kwargs)
+
+ # otherwise, we're adding an optional argument
+ else:
+ kwargs = self._get_optional_kwargs(*args, **kwargs)
+
+ # if no default was supplied, use the parser-level default
+ if 'default' not in kwargs:
+ dest = kwargs['dest']
+ if dest in self._defaults:
+ kwargs['default'] = self._defaults[dest]
+ elif self.argument_default is not None:
+ kwargs['default'] = self.argument_default
+
+ # create the action object, and add it to the parser
+ action_class = self._pop_action_class(kwargs)
+ action = action_class(**kwargs)
+ return self._add_action(action)
+
+ def add_argument_group(self, *args, **kwargs):
+ group = _ArgumentGroup(self, *args, **kwargs)
+ self._action_groups.append(group)
+ return group
+
+ def add_mutually_exclusive_group(self, **kwargs):
+ group = _MutuallyExclusiveGroup(self, **kwargs)
+ self._mutually_exclusive_groups.append(group)
+ return group
+
+ def _add_action(self, action):
+ # resolve any conflicts
+ self._check_conflict(action)
+
+ # add to actions list
+ self._actions.append(action)
+ action.container = self
+
+ # index the action by any option strings it has
+ for option_string in action.option_strings:
+ self._option_string_actions[option_string] = action
+
+ # set the flag if any option strings look like negative numbers
+ for option_string in action.option_strings:
+ if self._negative_number_matcher.match(option_string):
+ if not self._has_negative_number_optionals:
+ self._has_negative_number_optionals.append(True)
+
+ # return the created action
+ return action
+
+ def _remove_action(self, action):
+ self._actions.remove(action)
+
+ def _add_container_actions(self, container):
+ # collect groups by titles
+ title_group_map = {}
+ for group in self._action_groups:
+ if group.title in title_group_map:
+ msg = _('cannot merge actions - two groups are named %r')
+ raise ValueError(msg % (group.title))
+ title_group_map[group.title] = group
+
+ # map each action to its group
+ group_map = {}
+ for group in container._action_groups:
+
+ # if a group with the title exists, use that, otherwise
+ # create a new group matching the container's group
+ if group.title not in title_group_map:
+ title_group_map[group.title] = self.add_argument_group(
+ title=group.title,
+ description=group.description,
+ conflict_handler=group.conflict_handler)
+
+ # map the actions to their new group
+ for action in group._group_actions:
+ group_map[action] = title_group_map[group.title]
+
+ # add all actions to this container or their group
+ for action in container._actions:
+ group_map.get(action, self)._add_action(action)
+
+ def _get_positional_kwargs(self, dest, **kwargs):
+ # make sure required is not specified
+ if 'required' in kwargs:
+ msg = _("'required' is an invalid argument for positionals")
+ raise TypeError(msg)
+
+ # mark positional arguments as required if at least one is
+ # always required
+ if kwargs.get('nargs') not in [OPTIONAL, ZERO_OR_MORE]:
+ kwargs['required'] = True
+ if kwargs.get('nargs') == ZERO_OR_MORE and 'default' not in kwargs:
+ kwargs['required'] = True
+
+ # return the keyword arguments with no option strings
+ return dict(kwargs, dest=dest, option_strings=[])
+
+ def _get_optional_kwargs(self, *args, **kwargs):
+ # determine short and long option strings
+ option_strings = []
+ long_option_strings = []
+ for option_string in args:
+ # error on one-or-fewer-character option strings
+ if len(option_string) < 2:
+ msg = _('invalid option string %r: '
+ 'must be at least two characters long')
+ raise ValueError(msg % option_string)
+
+ # error on strings that don't start with an appropriate prefix
+ if not option_string[0] in self.prefix_chars:
+ msg = _('invalid option string %r: '
+ 'must start with a character %r')
+ tup = option_string, self.prefix_chars
+ raise ValueError(msg % tup)
+
+ # error on strings that are all prefix characters
+ if not (_set(option_string) - _set(self.prefix_chars)):
+ msg = _('invalid option string %r: '
+ 'must contain characters other than %r')
+ tup = option_string, self.prefix_chars
+ raise ValueError(msg % tup)
+
+ # strings starting with two prefix characters are long options
+ option_strings.append(option_string)
+ if option_string[0] in self.prefix_chars:
+ if option_string[1] in self.prefix_chars:
+ long_option_strings.append(option_string)
+
+ # infer destination, '--foo-bar' -> 'foo_bar' and '-x' -> 'x'
+ dest = kwargs.pop('dest', None)
+ if dest is None:
+ if long_option_strings:
+ dest_option_string = long_option_strings[0]
+ else:
+ dest_option_string = option_strings[0]
+ dest = dest_option_string.lstrip(self.prefix_chars)
+ dest = dest.replace('-', '_')
+
+ # return the updated keyword arguments
+ return dict(kwargs, dest=dest, option_strings=option_strings)
+
+ def _pop_action_class(self, kwargs, default=None):
+ action = kwargs.pop('action', default)
+ return self._registry_get('action', action, action)
+
+ def _get_handler(self):
+ # determine function from conflict handler string
+ handler_func_name = '_handle_conflict_%s' % self.conflict_handler
+ try:
+ return getattr(self, handler_func_name)
+ except AttributeError:
+ msg = _('invalid conflict_resolution value: %r')
+ raise ValueError(msg % self.conflict_handler)
+
+ def _check_conflict(self, action):
+
+ # find all options that conflict with this option
+ confl_optionals = []
+ for option_string in action.option_strings:
+ if option_string in self._option_string_actions:
+ confl_optional = self._option_string_actions[option_string]
+ confl_optionals.append((option_string, confl_optional))
+
+ # resolve any conflicts
+ if confl_optionals:
+ conflict_handler = self._get_handler()
+ conflict_handler(action, confl_optionals)
+
+ def _handle_conflict_error(self, action, conflicting_actions):
+ message = _('conflicting option string(s): %s')
+ conflict_string = ', '.join([option_string
+ for option_string, action
+ in conflicting_actions])
+ raise ArgumentError(action, message % conflict_string)
+
+ def _handle_conflict_resolve(self, action, conflicting_actions):
+
+ # remove all conflicting options
+ for option_string, action in conflicting_actions:
+
+ # remove the conflicting option
+ action.option_strings.remove(option_string)
+ self._option_string_actions.pop(option_string, None)
+
+ # if the option now has no option string, remove it from the
+ # container holding it
+ if not action.option_strings:
+ action.container._remove_action(action)
+
+
+class _ArgumentGroup(_ActionsContainer):
+
+ def __init__(self, container, title=None, description=None, **kwargs):
+ # add any missing keyword arguments by checking the container
+ update = kwargs.setdefault
+ update('conflict_handler', container.conflict_handler)
+ update('prefix_chars', container.prefix_chars)
+ update('argument_default', container.argument_default)
+ super_init = super(_ArgumentGroup, self).__init__
+ super_init(description=description, **kwargs)
+
+ # group attributes
+ self.title = title
+ self._group_actions = []
+
+ # share most attributes with the container
+ self._registries = container._registries
+ self._actions = container._actions
+ self._option_string_actions = container._option_string_actions
+ self._defaults = container._defaults
+ self._has_negative_number_optionals = \
+ container._has_negative_number_optionals
+
+ def _add_action(self, action):
+ action = super(_ArgumentGroup, self)._add_action(action)
+ self._group_actions.append(action)
+ return action
+
+ def _remove_action(self, action):
+ super(_ArgumentGroup, self)._remove_action(action)
+ self._group_actions.remove(action)
+
+
+class _MutuallyExclusiveGroup(_ArgumentGroup):
+
+ def __init__(self, container, required=False):
+ super(_MutuallyExclusiveGroup, self).__init__(container)
+ self.required = required
+ self._container = container
+
+ def _add_action(self, action):
+ if action.required:
+ msg = _('mutually exclusive arguments must be optional')
+ raise ValueError(msg)
+ action = self._container._add_action(action)
+ self._group_actions.append(action)
+ return action
+
+ def _remove_action(self, action):
+ self._container._remove_action(action)
+ self._group_actions.remove(action)
+
+
+class ArgumentParser(_AttributeHolder, _ActionsContainer):
+ """Object for parsing command line strings into Python objects.
+
+ Keyword Arguments:
+ - prog -- The name of the program (default: sys.argv[0])
+ - usage -- A usage message (default: auto-generated from arguments)
+ - description -- A description of what the program does
+ - epilog -- Text following the argument descriptions
+ - version -- Add a -v/--version option with the given version string
+ - parents -- Parsers whose arguments should be copied into this one
+ - formatter_class -- HelpFormatter class for printing help messages
+ - prefix_chars -- Characters that prefix optional arguments
+ - fromfile_prefix_chars -- Characters that prefix files containing
+ additional arguments
+ - argument_default -- The default value for all arguments
+ - conflict_handler -- String indicating how to handle conflicts
+ - add_help -- Add a -h/-help option
+ """
+
+ def __init__(self,
+ prog=None,
+ usage=None,
+ description=None,
+ epilog=None,
+ version=None,
+ parents=[],
+ formatter_class=HelpFormatter,
+ prefix_chars='-',
+ fromfile_prefix_chars=None,
+ argument_default=None,
+ conflict_handler='error',
+ add_help=True):
+
+ superinit = super(ArgumentParser, self).__init__
+ superinit(description=description,
+ prefix_chars=prefix_chars,
+ argument_default=argument_default,
+ conflict_handler=conflict_handler)
+
+ # default setting for prog
+ if prog is None:
+ prog = _os.path.basename(_sys.argv[0])
+
+ self.prog = prog
+ self.usage = usage
+ self.epilog = epilog
+ self.version = version
+ self.formatter_class = formatter_class
+ self.fromfile_prefix_chars = fromfile_prefix_chars
+ self.add_help = add_help
+
+ add_group = self.add_argument_group
+ self._positionals = add_group(_('positional arguments'))
+ self._optionals = add_group(_('optional arguments'))
+ self._subparsers = None
+
+ # register types
+ def identity(string):
+ return string
+ self.register('type', None, identity)
+
+ # add help and version arguments if necessary
+ # (using explicit default to override global argument_default)
+ if self.add_help:
+ self.add_argument(
+ '-h', '--help', action='help', default=SUPPRESS,
+ help=_('show this help message and exit'))
+ if self.version:
+ self.add_argument(
+ '-v', '--version', action='version', default=SUPPRESS,
+ help=_("show program's version number and exit"))
+
+ # add parent arguments and defaults
+ for parent in parents:
+ self._add_container_actions(parent)
+ try:
+ defaults = parent._defaults
+ except AttributeError:
+ pass
+ else:
+ self._defaults.update(defaults)
+
+ # =======================
+ # Pretty __repr__ methods
+ # =======================
+ def _get_kwargs(self):
+ names = [
+ 'prog',
+ 'usage',
+ 'description',
+ 'version',
+ 'formatter_class',
+ 'conflict_handler',
+ 'add_help',
+ ]
+ return [(name, getattr(self, name)) for name in names]
+
+ # ==================================
+ # Optional/Positional adding methods
+ # ==================================
+ def add_subparsers(self, **kwargs):
+ if self._subparsers is not None:
+ self.error(_('cannot have multiple subparser arguments'))
+
+ # add the parser class to the arguments if it's not present
+ kwargs.setdefault('parser_class', type(self))
+
+ if 'title' in kwargs or 'description' in kwargs:
+ title = _(kwargs.pop('title', 'subcommands'))
+ description = _(kwargs.pop('description', None))
+ self._subparsers = self.add_argument_group(title, description)
+ else:
+ self._subparsers = self._positionals
+
+ # prog defaults to the usage message of this parser, skipping
+ # optional arguments and with no "usage:" prefix
+ if kwargs.get('prog') is None:
+ formatter = self._get_formatter()
+ positionals = self._get_positional_actions()
+ groups = self._mutually_exclusive_groups
+ formatter.add_usage(self.usage, positionals, groups, '')
+ kwargs['prog'] = formatter.format_help().strip()
+
+ # create the parsers action and add it to the positionals list
+ parsers_class = self._pop_action_class(kwargs, 'parsers')
+ action = parsers_class(option_strings=[], **kwargs)
+ self._subparsers._add_action(action)
+
+ # return the created parsers action
+ return action
+
+ def _add_action(self, action):
+ if action.option_strings:
+ self._optionals._add_action(action)
+ else:
+ self._positionals._add_action(action)
+ return action
+
+ def _get_optional_actions(self):
+ return [action
+ for action in self._actions
+ if action.option_strings]
+
+ def _get_positional_actions(self):
+ return [action
+ for action in self._actions
+ if not action.option_strings]
+
+ # =====================================
+ # Command line argument parsing methods
+ # =====================================
+ def parse_args(self, args=None, namespace=None):
+ args, argv = self.parse_known_args(args, namespace)
+ if argv:
+ msg = _('unrecognized arguments: %s')
+ self.error(msg % ' '.join(argv))
+ return args
+
+ def parse_known_args(self, args=None, namespace=None):
+ # args default to the system args
+ if args is None:
+ args = _sys.argv[1:]
+
+ # default Namespace built from parser defaults
+ if namespace is None:
+ namespace = Namespace()
+
+ # add any action defaults that aren't present
+ for action in self._actions:
+ if action.dest is not SUPPRESS:
+ if not hasattr(namespace, action.dest):
+ if action.default is not SUPPRESS:
+ default = action.default
+ if isinstance(action.default, _basestring):
+ default = self._get_value(action, default)
+ setattr(namespace, action.dest, default)
+
+ # add any parser defaults that aren't present
+ for dest in self._defaults:
+ if not hasattr(namespace, dest):
+ setattr(namespace, dest, self._defaults[dest])
+
+ # parse the arguments and exit if there are any errors
+ try:
+ return self._parse_known_args(args, namespace)
+ except ArgumentError:
+ err = _sys.exc_info()[1]
+ self.error(str(err))
+
+ def _parse_known_args(self, arg_strings, namespace):
+ # replace arg strings that are file references
+ if self.fromfile_prefix_chars is not None:
+ arg_strings = self._read_args_from_files(arg_strings)
+
+ # map all mutually exclusive arguments to the other arguments
+ # they can't occur with
+ action_conflicts = {}
+ for mutex_group in self._mutually_exclusive_groups:
+ group_actions = mutex_group._group_actions
+ for i, mutex_action in enumerate(mutex_group._group_actions):
+ conflicts = action_conflicts.setdefault(mutex_action, [])
+ conflicts.extend(group_actions[:i])
+ conflicts.extend(group_actions[i + 1:])
+
+ # find all option indices, and determine the arg_string_pattern
+ # which has an 'O' if there is an option at an index,
+ # an 'A' if there is an argument, or a '-' if there is a '--'
+ option_string_indices = {}
+ arg_string_pattern_parts = []
+ arg_strings_iter = iter(arg_strings)
+ for i, arg_string in enumerate(arg_strings_iter):
+
+ # all args after -- are non-options
+ if arg_string == '--':
+ arg_string_pattern_parts.append('-')
+ for arg_string in arg_strings_iter:
+ arg_string_pattern_parts.append('A')
+
+ # otherwise, add the arg to the arg strings
+ # and note the index if it was an option
+ else:
+ option_tuple = self._parse_optional(arg_string)
+ if option_tuple is None:
+ pattern = 'A'
+ else:
+ option_string_indices[i] = option_tuple
+ pattern = 'O'
+ arg_string_pattern_parts.append(pattern)
+
+ # join the pieces together to form the pattern
+ arg_strings_pattern = ''.join(arg_string_pattern_parts)
+
+ # converts arg strings to the appropriate and then takes the action
+ seen_actions = _set()
+ seen_non_default_actions = _set()
+
+ def take_action(action, argument_strings, option_string=None):
+ seen_actions.add(action)
+ argument_values = self._get_values(action, argument_strings)
+
+ # error if this argument is not allowed with other previously
+ # seen arguments, assuming that actions that use the default
+ # value don't really count as "present"
+ if argument_values is not action.default:
+ seen_non_default_actions.add(action)
+ for conflict_action in action_conflicts.get(action, []):
+ if conflict_action in seen_non_default_actions:
+ msg = _('not allowed with argument %s')
+ action_name = _get_action_name(conflict_action)
+ raise ArgumentError(action, msg % action_name)
+
+ # take the action if we didn't receive a SUPPRESS value
+ # (e.g. from a default)
+ if argument_values is not SUPPRESS:
+ action(self, namespace, argument_values, option_string)
+
+ # function to convert arg_strings into an optional action
+ def consume_optional(start_index):
+
+ # get the optional identified at this index
+ option_tuple = option_string_indices[start_index]
+ action, option_string, explicit_arg = option_tuple
+
+ # identify additional optionals in the same arg string
+ # (e.g. -xyz is the same as -x -y -z if no args are required)
+ match_argument = self._match_argument
+ action_tuples = []
+ while True:
+
+ # if we found no optional action, skip it
+ if action is None:
+ extras.append(arg_strings[start_index])
+ return start_index + 1
+
+ # if there is an explicit argument, try to match the
+ # optional's string arguments to only this
+ if explicit_arg is not None:
+ arg_count = match_argument(action, 'A')
+
+ # if the action is a single-dash option and takes no
+ # arguments, try to parse more single-dash options out
+ # of the tail of the option string
+ chars = self.prefix_chars
+ if arg_count == 0 and option_string[1] not in chars:
+ action_tuples.append((action, [], option_string))
+ for char in self.prefix_chars:
+ option_string = char + explicit_arg[0]
+ explicit_arg = explicit_arg[1:] or None
+ optionals_map = self._option_string_actions
+ if option_string in optionals_map:
+ action = optionals_map[option_string]
+ break
+ else:
+ msg = _('ignored explicit argument %r')
+ raise ArgumentError(action, msg % explicit_arg)
+
+ # if the action expect exactly one argument, we've
+ # successfully matched the option; exit the loop
+ elif arg_count == 1:
+ stop = start_index + 1
+ args = [explicit_arg]
+ action_tuples.append((action, args, option_string))
+ break
+
+ # error if a double-dash option did not use the
+ # explicit argument
+ else:
+ msg = _('ignored explicit argument %r')
+ raise ArgumentError(action, msg % explicit_arg)
+
+ # if there is no explicit argument, try to match the
+ # optional's string arguments with the following strings
+ # if successful, exit the loop
+ else:
+ start = start_index + 1
+ selected_patterns = arg_strings_pattern[start:]
+ arg_count = match_argument(action, selected_patterns)
+ stop = start + arg_count
+ args = arg_strings[start:stop]
+ action_tuples.append((action, args, option_string))
+ break
+
+ # add the Optional to the list and return the index at which
+ # the Optional's string args stopped
+ assert action_tuples
+ for action, args, option_string in action_tuples:
+ take_action(action, args, option_string)
+ return stop
+
+ # the list of Positionals left to be parsed; this is modified
+ # by consume_positionals()
+ positionals = self._get_positional_actions()
+
+ # function to convert arg_strings into positional actions
+ def consume_positionals(start_index):
+ # match as many Positionals as possible
+ match_partial = self._match_arguments_partial
+ selected_pattern = arg_strings_pattern[start_index:]
+ arg_counts = match_partial(positionals, selected_pattern)
+
+ # slice off the appropriate arg strings for each Positional
+ # and add the Positional and its args to the list
+ for action, arg_count in zip(positionals, arg_counts):
+ args = arg_strings[start_index: start_index + arg_count]
+ start_index += arg_count
+ take_action(action, args)
+
+ # slice off the Positionals that we just parsed and return the
+ # index at which the Positionals' string args stopped
+ positionals[:] = positionals[len(arg_counts):]
+ return start_index
+
+ # consume Positionals and Optionals alternately, until we have
+ # passed the last option string
+ extras = []
+ start_index = 0
+ if option_string_indices:
+ max_option_string_index = max(option_string_indices)
+ else:
+ max_option_string_index = -1
+ while start_index <= max_option_string_index:
+
+ # consume any Positionals preceding the next option
+ next_option_string_index = min([
+ index
+ for index in option_string_indices
+ if index >= start_index])
+ if start_index != next_option_string_index:
+ positionals_end_index = consume_positionals(start_index)
+
+ # only try to parse the next optional if we didn't consume
+ # the option string during the positionals parsing
+ if positionals_end_index > start_index:
+ start_index = positionals_end_index
+ continue
+ else:
+ start_index = positionals_end_index
+
+ # if we consumed all the positionals we could and we're not
+ # at the index of an option string, there were extra arguments
+ if start_index not in option_string_indices:
+ strings = arg_strings[start_index:next_option_string_index]
+ extras.extend(strings)
+ start_index = next_option_string_index
+
+ # consume the next optional and any arguments for it
+ start_index = consume_optional(start_index)
+
+ # consume any positionals following the last Optional
+ stop_index = consume_positionals(start_index)
+
+ # if we didn't consume all the argument strings, there were extras
+ extras.extend(arg_strings[stop_index:])
+
+ # if we didn't use all the Positional objects, there were too few
+ # arg strings supplied.
+ if positionals:
+ self.error(_('too few arguments'))
+
+ # make sure all required actions were present
+ for action in self._actions:
+ if action.required:
+ if action not in seen_actions:
+ name = _get_action_name(action)
+ self.error(_('argument %s is required') % name)
+
+ # make sure all required groups had one option present
+ for group in self._mutually_exclusive_groups:
+ if group.required:
+ for action in group._group_actions:
+ if action in seen_non_default_actions:
+ break
+
+ # if no actions were used, report the error
+ else:
+ names = [_get_action_name(action)
+ for action in group._group_actions
+ if action.help is not SUPPRESS]
+ msg = _('one of the arguments %s is required')
+ self.error(msg % ' '.join(names))
+
+ # return the updated namespace and the extra arguments
+ return namespace, extras
+
+ def _read_args_from_files(self, arg_strings):
+ # expand arguments referencing files
+ new_arg_strings = []
+ for arg_string in arg_strings:
+
+ # for regular arguments, just add them back into the list
+ if arg_string[0] not in self.fromfile_prefix_chars:
+ new_arg_strings.append(arg_string)
+
+ # replace arguments referencing files with the file content
+ else:
+ try:
+ args_file = open(arg_string[1:])
+ try:
+ arg_strings = args_file.read().splitlines()
+ arg_strings = self._read_args_from_files(arg_strings)
+ new_arg_strings.extend(arg_strings)
+ finally:
+ args_file.close()
+ except IOError:
+ err = _sys.exc_info()[1]
+ self.error(str(err))
+
+ # return the modified argument list
+ return new_arg_strings
+
+ def _match_argument(self, action, arg_strings_pattern):
+ # match the pattern for this action to the arg strings
+ nargs_pattern = self._get_nargs_pattern(action)
+ match = _re.match(nargs_pattern, arg_strings_pattern)
+
+ # raise an exception if we weren't able to find a match
+ if match is None:
+ nargs_errors = {
+ None: _('expected one argument'),
+ OPTIONAL: _('expected at most one argument'),
+ ONE_OR_MORE: _('expected at least one argument'),
+ }
+ default = _('expected %s argument(s)') % action.nargs
+ msg = nargs_errors.get(action.nargs, default)
+ raise ArgumentError(action, msg)
+
+ # return the number of arguments matched
+ return len(match.group(1))
+
+ def _match_arguments_partial(self, actions, arg_strings_pattern):
+ # progressively shorten the actions list by slicing off the
+ # final actions until we find a match
+ result = []
+ for i in range(len(actions), 0, -1):
+ actions_slice = actions[:i]
+ pattern = ''.join([self._get_nargs_pattern(action)
+ for action in actions_slice])
+ match = _re.match(pattern, arg_strings_pattern)
+ if match is not None:
+ result.extend([len(string) for string in match.groups()])
+ break
+
+ # return the list of arg string counts
+ return result
+
+ def _parse_optional(self, arg_string):
+ # if it's an empty string, it was meant to be a positional
+ if not arg_string:
+ return None
+
+ # if it doesn't start with a prefix, it was meant to be positional
+ if not arg_string[0] in self.prefix_chars:
+ return None
+
+ # if it's just dashes, it was meant to be positional
+ if not arg_string.strip('-'):
+ return None
+
+ # if the option string is present in the parser, return the action
+ if arg_string in self._option_string_actions:
+ action = self._option_string_actions[arg_string]
+ return action, arg_string, None
+
+ # search through all possible prefixes of the option string
+ # and all actions in the parser for possible interpretations
+ option_tuples = self._get_option_tuples(arg_string)
+
+ # if multiple actions match, the option string was ambiguous
+ if len(option_tuples) > 1:
+ options = ', '.join([option_string
+ for action, option_string, explicit_arg in option_tuples])
+ tup = arg_string, options
+ self.error(_('ambiguous option: %s could match %s') % tup)
+
+ # if exactly one action matched, this segmentation is good,
+ # so return the parsed action
+ elif len(option_tuples) == 1:
+ option_tuple, = option_tuples
+ return option_tuple
+
+ # if it was not found as an option, but it looks like a negative
+ # number, it was meant to be positional
+ # unless there are negative-number-like options
+ if self._negative_number_matcher.match(arg_string):
+ if not self._has_negative_number_optionals:
+ return None
+
+ # if it contains a space, it was meant to be a positional
+ if ' ' in arg_string:
+ return None
+
+ # it was meant to be an optional but there is no such option
+ # in this parser (though it might be a valid option in a subparser)
+ return None, arg_string, None
+
+ def _get_option_tuples(self, option_string):
+ result = []
+
+ # option strings starting with two prefix characters are only
+ # split at the '='
+ chars = self.prefix_chars
+ if option_string[0] in chars and option_string[1] in chars:
+ if '=' in option_string:
+ option_prefix, explicit_arg = option_string.split('=', 1)
+ else:
+ option_prefix = option_string
+ explicit_arg = None
+ for option_string in self._option_string_actions:
+ if option_string.startswith(option_prefix):
+ action = self._option_string_actions[option_string]
+ tup = action, option_string, explicit_arg
+ result.append(tup)
+
+ # single character options can be concatenated with their arguments
+ # but multiple character options always have to have their argument
+ # separate
+ elif option_string[0] in chars and option_string[1] not in chars:
+ option_prefix = option_string
+ explicit_arg = None
+ short_option_prefix = option_string[:2]
+ short_explicit_arg = option_string[2:]
+
+ for option_string in self._option_string_actions:
+ if option_string == short_option_prefix:
+ action = self._option_string_actions[option_string]
+ tup = action, option_string, short_explicit_arg
+ result.append(tup)
+ elif option_string.startswith(option_prefix):
+ action = self._option_string_actions[option_string]
+ tup = action, option_string, explicit_arg
+ result.append(tup)
+
+ # shouldn't ever get here
+ else:
+ self.error(_('unexpected option string: %s') % option_string)
+
+ # return the collected option tuples
+ return result
+
+ def _get_nargs_pattern(self, action):
+ # in all examples below, we have to allow for '--' args
+ # which are represented as '-' in the pattern
+ nargs = action.nargs
+
+ # the default (None) is assumed to be a single argument
+ if nargs is None:
+ nargs_pattern = '(-*A-*)'
+
+ # allow zero or one arguments
+ elif nargs == OPTIONAL:
+ nargs_pattern = '(-*A?-*)'
+
+ # allow zero or more arguments
+ elif nargs == ZERO_OR_MORE:
+ nargs_pattern = '(-*[A-]*)'
+
+ # allow one or more arguments
+ elif nargs == ONE_OR_MORE:
+ nargs_pattern = '(-*A[A-]*)'
+
+ # allow one argument followed by any number of options or arguments
+ elif nargs is PARSER:
+ nargs_pattern = '(-*A[-AO]*)'
+
+ # all others should be integers
+ else:
+ nargs_pattern = '(-*%s-*)' % '-*'.join('A' * nargs)
+
+ # if this is an optional action, -- is not allowed
+ if action.option_strings:
+ nargs_pattern = nargs_pattern.replace('-*', '')
+ nargs_pattern = nargs_pattern.replace('-', '')
+
+ # return the pattern
+ return nargs_pattern
+
+ # ========================
+ # Value conversion methods
+ # ========================
+ def _get_values(self, action, arg_strings):
+ # for everything but PARSER args, strip out '--'
+ if action.nargs is not PARSER:
+ arg_strings = [s for s in arg_strings if s != '--']
+
+ # optional argument produces a default when not present
+ if not arg_strings and action.nargs == OPTIONAL:
+ if action.option_strings:
+ value = action.const
+ else:
+ value = action.default
+ if isinstance(value, _basestring):
+ value = self._get_value(action, value)
+ self._check_value(action, value)
+
+ # when nargs='*' on a positional, if there were no command-line
+ # args, use the default if it is anything other than None
+ elif (not arg_strings and action.nargs == ZERO_OR_MORE and
+ not action.option_strings):
+ if action.default is not None:
+ value = action.default
+ else:
+ value = arg_strings
+ self._check_value(action, value)
+
+ # single argument or optional argument produces a single value
+ elif len(arg_strings) == 1 and action.nargs in [None, OPTIONAL]:
+ arg_string, = arg_strings
+ value = self._get_value(action, arg_string)
+ self._check_value(action, value)
+
+ # PARSER arguments convert all values, but check only the first
+ elif action.nargs is PARSER:
+ value = [self._get_value(action, v) for v in arg_strings]
+ self._check_value(action, value[0])
+
+ # all other types of nargs produce a list
+ else:
+ value = [self._get_value(action, v) for v in arg_strings]
+ for v in value:
+ self._check_value(action, v)
+
+ # return the converted value
+ return value
+
+ def _get_value(self, action, arg_string):
+ type_func = self._registry_get('type', action.type, action.type)
+ if not hasattr(type_func, '__call__'):
+ msg = _('%r is not callable')
+ raise ArgumentError(action, msg % type_func)
+
+ # convert the value to the appropriate type
+ try:
+ result = type_func(arg_string)
+
+ # TypeErrors or ValueErrors indicate errors
+ except (TypeError, ValueError):
+ name = getattr(action.type, '__name__', repr(action.type))
+ msg = _('invalid %s value: %r')
+ raise ArgumentError(action, msg % (name, arg_string))
+
+ # return the converted value
+ return result
+
+ def _check_value(self, action, value):
+ # converted value must be one of the choices (if specified)
+ if action.choices is not None and value not in action.choices:
+ tup = value, ', '.join(map(repr, action.choices))
+ msg = _('invalid choice: %r (choose from %s)') % tup
+ raise ArgumentError(action, msg)
+
+ # =======================
+ # Help-formatting methods
+ # =======================
+ def format_usage(self):
+ formatter = self._get_formatter()
+ formatter.add_usage(self.usage, self._actions,
+ self._mutually_exclusive_groups)
+ return formatter.format_help()
+
+ def format_help(self):
+ formatter = self._get_formatter()
+
+ # usage
+ formatter.add_usage(self.usage, self._actions,
+ self._mutually_exclusive_groups)
+
+ # description
+ formatter.add_text(self.description)
+
+ # positionals, optionals and user-defined groups
+ for action_group in self._action_groups:
+ formatter.start_section(action_group.title)
+ formatter.add_text(action_group.description)
+ formatter.add_arguments(action_group._group_actions)
+ formatter.end_section()
+
+ # epilog
+ formatter.add_text(self.epilog)
+
+ # determine help from format above
+ return formatter.format_help()
+
+ def format_version(self):
+ formatter = self._get_formatter()
+ formatter.add_text(self.version)
+ return formatter.format_help()
+
+ def _get_formatter(self):
+ return self.formatter_class(prog=self.prog)
+
+ # =====================
+ # Help-printing methods
+ # =====================
+ def print_usage(self, file=None):
+ self._print_message(self.format_usage(), file)
+
+ def print_help(self, file=None):
+ self._print_message(self.format_help(), file)
+
+ def print_version(self, file=None):
+ self._print_message(self.format_version(), file)
+
+ def _print_message(self, message, file=None):
+ if message:
+ if file is None:
+ file = _sys.stderr
+ file.write(message)
+
+ # ===============
+ # Exiting methods
+ # ===============
+ def exit(self, status=0, message=None):
+ if message:
+ _sys.stderr.write(message)
+ _sys.exit(status)
+
+ def error(self, message):
+ """error(message: string)
+
+ Prints a usage message incorporating the message to stderr and
+ exits.
+
+ If you override this in a subclass, it should not return -- it
+ should either exit or raise an exception.
+ """
+ self.print_usage(_sys.stderr)
+ self.exit(2, _('%s: error: %s\n') % (self.prog, message))
diff --git a/IPython/external/configobj.py b/IPython/external/configobj.py
new file mode 100644
index 0000000..9e64f18
--- /dev/null
+++ b/IPython/external/configobj.py
@@ -0,0 +1,2501 @@
+# configobj.py
+# A config file reader/writer that supports nested sections in config files.
+# Copyright (C) 2005-2008 Michael Foord, Nicola Larosa
+# E-mail: fuzzyman AT voidspace DOT org DOT uk
+# nico AT tekNico DOT net
+
+# ConfigObj 4
+# http://www.voidspace.org.uk/python/configobj.html
+
+# Released subject to the BSD License
+# Please see http://www.voidspace.org.uk/python/license.shtml
+
+# Scripts maintained at http://www.voidspace.org.uk/python/index.shtml
+# For information about bugfixes, updates and support, please join the
+# ConfigObj mailing list:
+# http://lists.sourceforge.net/lists/listinfo/configobj-develop
+# Comments, suggestions and bug reports welcome.
+
+from __future__ import generators
+
+import sys
+INTP_VER = sys.version_info[:2]
+if INTP_VER < (2, 2):
+ raise RuntimeError("Python v.2.2 or later needed")
+
+import os, re
+compiler = None
+try:
+ import compiler
+except ImportError:
+ # for IronPython
+ pass
+from types import StringTypes
+from warnings import warn
+try:
+ from codecs import BOM_UTF8, BOM_UTF16, BOM_UTF16_BE, BOM_UTF16_LE
+except ImportError:
+ # Python 2.2 does not have these
+ # UTF-8
+ BOM_UTF8 = '\xef\xbb\xbf'
+ # UTF-16, little endian
+ BOM_UTF16_LE = '\xff\xfe'
+ # UTF-16, big endian
+ BOM_UTF16_BE = '\xfe\xff'
+ if sys.byteorder == 'little':
+ # UTF-16, native endianness
+ BOM_UTF16 = BOM_UTF16_LE
+ else:
+ # UTF-16, native endianness
+ BOM_UTF16 = BOM_UTF16_BE
+
+# A dictionary mapping BOM to
+# the encoding to decode with, and what to set the
+# encoding attribute to.
+BOMS = {
+ BOM_UTF8: ('utf_8', None),
+ BOM_UTF16_BE: ('utf16_be', 'utf_16'),
+ BOM_UTF16_LE: ('utf16_le', 'utf_16'),
+ BOM_UTF16: ('utf_16', 'utf_16'),
+ }
+# All legal variants of the BOM codecs.
+# TODO: the list of aliases is not meant to be exhaustive, is there a
+# better way ?
+BOM_LIST = {
+ 'utf_16': 'utf_16',
+ 'u16': 'utf_16',
+ 'utf16': 'utf_16',
+ 'utf-16': 'utf_16',
+ 'utf16_be': 'utf16_be',
+ 'utf_16_be': 'utf16_be',
+ 'utf-16be': 'utf16_be',
+ 'utf16_le': 'utf16_le',
+ 'utf_16_le': 'utf16_le',
+ 'utf-16le': 'utf16_le',
+ 'utf_8': 'utf_8',
+ 'u8': 'utf_8',
+ 'utf': 'utf_8',
+ 'utf8': 'utf_8',
+ 'utf-8': 'utf_8',
+ }
+
+# Map of encodings to the BOM to write.
+BOM_SET = {
+ 'utf_8': BOM_UTF8,
+ 'utf_16': BOM_UTF16,
+ 'utf16_be': BOM_UTF16_BE,
+ 'utf16_le': BOM_UTF16_LE,
+ None: BOM_UTF8
+ }
+
+
+def match_utf8(encoding):
+ return BOM_LIST.get(encoding.lower()) == 'utf_8'
+
+
+# Quote strings used for writing values
+squot = "'%s'"
+dquot = '"%s"'
+noquot = "%s"
+wspace_plus = ' \r\t\n\v\t\'"'
+tsquot = '"""%s"""'
+tdquot = "'''%s'''"
+
+try:
+ enumerate
+except NameError:
+ def enumerate(obj):
+ """enumerate for Python 2.2."""
+ i = -1
+ for item in obj:
+ i += 1
+ yield i, item
+
+try:
+ True, False
+except NameError:
+ True, False = 1, 0
+
+
+__version__ = '4.5.2'
+
+__revision__ = '$Id: configobj.py 156 2006-01-31 14:57:08Z fuzzyman $'
+
+__docformat__ = "restructuredtext en"
+
+__all__ = (
+ '__version__',
+ 'DEFAULT_INDENT_TYPE',
+ 'DEFAULT_INTERPOLATION',
+ 'ConfigObjError',
+ 'NestingError',
+ 'ParseError',
+ 'DuplicateError',
+ 'ConfigspecError',
+ 'ConfigObj',
+ 'SimpleVal',
+ 'InterpolationError',
+ 'InterpolationLoopError',
+ 'MissingInterpolationOption',
+ 'RepeatSectionError',
+ 'ReloadError',
+ 'UnreprError',
+ 'UnknownType',
+ '__docformat__',
+ 'flatten_errors',
+)
+
+DEFAULT_INTERPOLATION = 'configparser'
+DEFAULT_INDENT_TYPE = ' '
+MAX_INTERPOL_DEPTH = 10
+
+OPTION_DEFAULTS = {
+ 'interpolation': True,
+ 'raise_errors': False,
+ 'list_values': True,
+ 'create_empty': False,
+ 'file_error': False,
+ 'configspec': None,
+ 'stringify': True,
+ # option may be set to one of ('', ' ', '\t')
+ 'indent_type': None,
+ 'encoding': None,
+ 'default_encoding': None,
+ 'unrepr': False,
+ 'write_empty_values': False,
+}
+
+
+
+def getObj(s):
+ s = "a=" + s
+ if compiler is None:
+ raise ImportError('compiler module not available')
+ p = compiler.parse(s)
+ return p.getChildren()[1].getChildren()[0].getChildren()[1]
+
+
+class UnknownType(Exception):
+ pass
+
+
+class Builder(object):
+
+ def build(self, o):
+ m = getattr(self, 'build_' + o.__class__.__name__, None)
+ if m is None:
+ raise UnknownType(o.__class__.__name__)
+ return m(o)
+
+ def build_List(self, o):
+ return map(self.build, o.getChildren())
+
+ def build_Const(self, o):
+ return o.value
+
+ def build_Dict(self, o):
+ d = {}
+ i = iter(map(self.build, o.getChildren()))
+ for el in i:
+ d[el] = i.next()
+ return d
+
+ def build_Tuple(self, o):
+ return tuple(self.build_List(o))
+
+ def build_Name(self, o):
+ if o.name == 'None':
+ return None
+ if o.name == 'True':
+ return True
+ if o.name == 'False':
+ return False
+
+ # An undefined Name
+ raise UnknownType('Undefined Name')
+
+ def build_Add(self, o):
+ real, imag = map(self.build_Const, o.getChildren())
+ try:
+ real = float(real)
+ except TypeError:
+ raise UnknownType('Add')
+ if not isinstance(imag, complex) or imag.real != 0.0:
+ raise UnknownType('Add')
+ return real+imag
+
+ def build_Getattr(self, o):
+ parent = self.build(o.expr)
+ return getattr(parent, o.attrname)
+
+ def build_UnarySub(self, o):
+ return -self.build_Const(o.getChildren()[0])
+
+ def build_UnaryAdd(self, o):
+ return self.build_Const(o.getChildren()[0])
+
+
+_builder = Builder()
+
+
+def unrepr(s):
+ if not s:
+ return s
+ return _builder.build(getObj(s))
+
+
+
+class ConfigObjError(SyntaxError):
+ """
+ This is the base class for all errors that ConfigObj raises.
+ It is a subclass of SyntaxError.
+ """
+ def __init__(self, message='', line_number=None, line=''):
+ self.line = line
+ self.line_number = line_number
+ self.message = message
+ SyntaxError.__init__(self, message)
+
+
+class NestingError(ConfigObjError):
+ """
+ This error indicates a level of nesting that doesn't match.
+ """
+
+
+class ParseError(ConfigObjError):
+ """
+ This error indicates that a line is badly written.
+ It is neither a valid ``key = value`` line,
+ nor a valid section marker line.
+ """
+
+
+class ReloadError(IOError):
+ """
+ A 'reload' operation failed.
+ This exception is a subclass of ``IOError``.
+ """
+ def __init__(self):
+ IOError.__init__(self, 'reload failed, filename is not set.')
+
+
+class DuplicateError(ConfigObjError):
+ """
+ The keyword or section specified already exists.
+ """
+
+
+class ConfigspecError(ConfigObjError):
+ """
+ An error occured whilst parsing a configspec.
+ """
+
+
+class InterpolationError(ConfigObjError):
+ """Base class for the two interpolation errors."""
+
+
+class InterpolationLoopError(InterpolationError):
+ """Maximum interpolation depth exceeded in string interpolation."""
+
+ def __init__(self, option):
+ InterpolationError.__init__(
+ self,
+ 'interpolation loop detected in value "%s".' % option)
+
+
+class RepeatSectionError(ConfigObjError):
+ """
+ This error indicates additional sections in a section with a
+ ``__many__`` (repeated) section.
+ """
+
+
+class MissingInterpolationOption(InterpolationError):
+ """A value specified for interpolation was missing."""
+
+ def __init__(self, option):
+ InterpolationError.__init__(
+ self,
+ 'missing option "%s" in interpolation.' % option)
+
+
+class UnreprError(ConfigObjError):
+ """An error parsing in unrepr mode."""
+
+
+
+class InterpolationEngine(object):
+ """
+ A helper class to help perform string interpolation.
+
+ This class is an abstract base class; its descendants perform
+ the actual work.
+ """
+
+ # compiled regexp to use in self.interpolate()
+ _KEYCRE = re.compile(r"%\(([^)]*)\)s")
+
+ def __init__(self, section):
+ # the Section instance that "owns" this engine
+ self.section = section
+
+
+ def interpolate(self, key, value):
+ def recursive_interpolate(key, value, section, backtrail):
+ """The function that does the actual work.
+
+ ``value``: the string we're trying to interpolate.
+ ``section``: the section in which that string was found
+ ``backtrail``: a dict to keep track of where we've been,
+ to detect and prevent infinite recursion loops
+
+ This is similar to a depth-first-search algorithm.
+ """
+ # Have we been here already?
+ if backtrail.has_key((key, section.name)):
+ # Yes - infinite loop detected
+ raise InterpolationLoopError(key)
+ # Place a marker on our backtrail so we won't come back here again
+ backtrail[(key, section.name)] = 1
+
+ # Now start the actual work
+ match = self._KEYCRE.search(value)
+ while match:
+ # The actual parsing of the match is implementation-dependent,
+ # so delegate to our helper function
+ k, v, s = self._parse_match(match)
+ if k is None:
+ # That's the signal that no further interpolation is needed
+ replacement = v
+ else:
+ # Further interpolation may be needed to obtain final value
+ replacement = recursive_interpolate(k, v, s, backtrail)
+ # Replace the matched string with its final value
+ start, end = match.span()
+ value = ''.join((value[:start], replacement, value[end:]))
+ new_search_start = start + len(replacement)
+ # Pick up the next interpolation key, if any, for next time
+ # through the while loop
+ match = self._KEYCRE.search(value, new_search_start)
+
+ # Now safe to come back here again; remove marker from backtrail
+ del backtrail[(key, section.name)]
+
+ return value
+
+ # Back in interpolate(), all we have to do is kick off the recursive
+ # function with appropriate starting values
+ value = recursive_interpolate(key, value, self.section, {})
+ return value
+
+
+ def _fetch(self, key):
+ """Helper function to fetch values from owning section.
+
+ Returns a 2-tuple: the value, and the section where it was found.
+ """
+ # switch off interpolation before we try and fetch anything !
+ save_interp = self.section.main.interpolation
+ self.section.main.interpolation = False
+
+ # Start at section that "owns" this InterpolationEngine
+ current_section = self.section
+ while True:
+ # try the current section first
+ val = current_section.get(key)
+ if val is not None:
+ break
+ # try "DEFAULT" next
+ val = current_section.get('DEFAULT', {}).get(key)
+ if val is not None:
+ break
+ # move up to parent and try again
+ # top-level's parent is itself
+ if current_section.parent is current_section:
+ # reached top level, time to give up
+ break
+ current_section = current_section.parent
+
+ # restore interpolation to previous value before returning
+ self.section.main.interpolation = save_interp
+ if val is None:
+ raise MissingInterpolationOption(key)
+ return val, current_section
+
+
+ def _parse_match(self, match):
+ """Implementation-dependent helper function.
+
+ Will be passed a match object corresponding to the interpolation
+ key we just found (e.g., "%(foo)s" or "$foo"). Should look up that
+ key in the appropriate config file section (using the ``_fetch()``
+ helper function) and return a 3-tuple: (key, value, section)
+
+ ``key`` is the name of the key we're looking for
+ ``value`` is the value found for that key
+ ``section`` is a reference to the section where it was found
+
+ ``key`` and ``section`` should be None if no further
+ interpolation should be performed on the resulting value
+ (e.g., if we interpolated "$$" and returned "$").
+ """
+ raise NotImplementedError()
+
+
+
+class ConfigParserInterpolation(InterpolationEngine):
+ """Behaves like ConfigParser."""
+ _KEYCRE = re.compile(r"%\(([^)]*)\)s")
+
+ def _parse_match(self, match):
+ key = match.group(1)
+ value, section = self._fetch(key)
+ return key, value, section
+
+
+
+class TemplateInterpolation(InterpolationEngine):
+ """Behaves like string.Template."""
+ _delimiter = '$'
+ _KEYCRE = re.compile(r"""
+ \$(?:
+ (?P<escaped>\$) | # Two $ signs
+ (?P<named>[_a-z][_a-z0-9]*) | # $name format
+ {(?P<braced>[^}]*)} # ${name} format
+ )
+ """, re.IGNORECASE | re.VERBOSE)
+
+ def _parse_match(self, match):
+ # Valid name (in or out of braces): fetch value from section
+ key = match.group('named') or match.group('braced')
+ if key is not None:
+ value, section = self._fetch(key)
+ return key, value, section
+ # Escaped delimiter (e.g., $$): return single delimiter
+ if match.group('escaped') is not None:
+ # Return None for key and section to indicate it's time to stop
+ return None, self._delimiter, None
+ # Anything else: ignore completely, just return it unchanged
+ return None, match.group(), None
+
+
+interpolation_engines = {
+ 'configparser': ConfigParserInterpolation,
+ 'template': TemplateInterpolation,
+}
+
+
+
+class Section(dict):
+ """
+ A dictionary-like object that represents a section in a config file.
+
+ It does string interpolation if the 'interpolation' attribute
+ of the 'main' object is set to True.
+
+ Interpolation is tried first from this object, then from the 'DEFAULT'
+ section of this object, next from the parent and its 'DEFAULT' section,
+ and so on until the main object is reached.
+
+ A Section will behave like an ordered dictionary - following the
+ order of the ``scalars`` and ``sections`` attributes.
+ You can use this to change the order of members.
+
+ Iteration follows the order: scalars, then sections.
+ """
+
+ def __init__(self, parent, depth, main, indict=None, name=None):
+ """
+ * parent is the section above
+ * depth is the depth level of this section
+ * main is the main ConfigObj
+ * indict is a dictionary to initialise the section with
+ """
+ if indict is None:
+ indict = {}
+ dict.__init__(self)
+ # used for nesting level *and* interpolation
+ self.parent = parent
+ # used for the interpolation attribute
+ self.main = main
+ # level of nesting depth of this Section
+ self.depth = depth
+ # purely for information
+ self.name = name
+ #
+ self._initialise()
+ # we do this explicitly so that __setitem__ is used properly
+ # (rather than just passing to ``dict.__init__``)
+ for entry, value in indict.iteritems():
+ self[entry] = value
+
+
+ def _initialise(self):
+ # the sequence of scalar values in this Section
+ self.scalars = []
+ # the sequence of sections in this Section
+ self.sections = []
+ # for comments :-)
+ self.comments = {}
+ self.inline_comments = {}
+ # for the configspec
+ self.configspec = {}
+ self._order = []
+ self._configspec_comments = {}
+ self._configspec_inline_comments = {}
+ self._cs_section_comments = {}
+ self._cs_section_inline_comments = {}
+ # for defaults
+ self.defaults = []
+ self.default_values = {}
+
+
+ def _interpolate(self, key, value):
+ try:
+ # do we already have an interpolation engine?
+ engine = self._interpolation_engine
+ except AttributeError:
+ # not yet: first time running _interpolate(), so pick the engine
+ name = self.main.interpolation
+ if name == True: # note that "if name:" would be incorrect here
+ # backwards-compatibility: interpolation=True means use default
+ name = DEFAULT_INTERPOLATION
+ name = name.lower() # so that "Template", "template", etc. all work
+ class_ = interpolation_engines.get(name, None)
+ if class_ is None:
+ # invalid value for self.main.interpolation
+ self.main.interpolation = False
+ return value
+ else:
+ # save reference to engine so we don't have to do this again
+ engine = self._interpolation_engine = class_(self)
+ # let the engine do the actual work
+ return engine.interpolate(key, value)
+
+
+ def __getitem__(self, key):
+ """Fetch the item and do string interpolation."""
+ val = dict.__getitem__(self, key)
+ if self.main.interpolation and isinstance(val, StringTypes):
+ return self._interpolate(key, val)
+ return val
+
+
+ def __setitem__(self, key, value, unrepr=False):
+ """
+ Correctly set a value.
+
+ Making dictionary values Section instances.
+ (We have to special case 'Section' instances - which are also dicts)
+
+ Keys must be strings.
+ Values need only be strings (or lists of strings) if
+ ``main.stringify`` is set.
+
+ `unrepr`` must be set when setting a value to a dictionary, without
+ creating a new sub-section.
+ """
+ if not isinstance(key, StringTypes):
+ raise ValueError('The key "%s" is not a string.' % key)
+
+ # add the comment
+ if not self.comments.has_key(key):
+ self.comments[key] = []
+ self.inline_comments[key] = ''
+ # remove the entry from defaults
+ if key in self.defaults:
+ self.defaults.remove(key)
+ #
+ if isinstance(value, Section):
+ if not self.has_key(key):
+ self.sections.append(key)
+ dict.__setitem__(self, key, value)
+ elif isinstance(value, dict) and not unrepr:
+ # First create the new depth level,
+ # then create the section
+ if not self.has_key(key):
+ self.sections.append(key)
+ new_depth = self.depth + 1
+ dict.__setitem__(
+ self,
+ key,
+ Section(
+ self,
+ new_depth,
+ self.main,
+ indict=value,
+ name=key))
+ else:
+ if not self.has_key(key):
+ self.scalars.append(key)
+ if not self.main.stringify:
+ if isinstance(value, StringTypes):
+ pass
+ elif isinstance(value, (list, tuple)):
+ for entry in value:
+ if not isinstance(entry, StringTypes):
+ raise TypeError('Value is not a string "%s".' % entry)
+ else:
+ raise TypeError('Value is not a string "%s".' % value)
+ dict.__setitem__(self, key, value)
+
+
+ def __delitem__(self, key):
+ """Remove items from the sequence when deleting."""
+ dict. __delitem__(self, key)
+ if key in self.scalars:
+ self.scalars.remove(key)
+ else:
+ self.sections.remove(key)
+ del self.comments[key]
+ del self.inline_comments[key]
+
+
+ def get(self, key, default=None):
+ """A version of ``get`` that doesn't bypass string interpolation."""
+ try:
+ return self[key]
+ except KeyError:
+ return default
+
+
+ def update(self, indict):
+ """
+ A version of update that uses our ``__setitem__``.
+ """
+ for entry in indict:
+ self[entry] = indict[entry]
+
+
+ def pop(self, key, *args):
+ """
+ 'D.pop(k[,d]) -> v, remove specified key and return the corresponding value.
+ If key is not found, d is returned if given, otherwise KeyError is raised'
+ """
+ val = dict.pop(self, key, *args)
+ if key in self.scalars:
+ del self.comments[key]
+ del self.inline_comments[key]
+ self.scalars.remove(key)
+ elif key in self.sections:
+ del self.comments[key]
+ del self.inline_comments[key]
+ self.sections.remove(key)
+ if self.main.interpolation and isinstance(val, StringTypes):
+ return self._interpolate(key, val)
+ return val
+
+
+ def popitem(self):
+ """Pops the first (key,val)"""
+ sequence = (self.scalars + self.sections)
+ if not sequence:
+ raise KeyError(": 'popitem(): dictionary is empty'")
+ key = sequence[0]
+ val = self[key]
+ del self[key]
+ return key, val
+
+
+ def clear(self):
+ """
+ A version of clear that also affects scalars/sections
+ Also clears comments and configspec.
+
+ Leaves other attributes alone :
+ depth/main/parent are not affected
+ """
+ dict.clear(self)
+ self.scalars = []
+ self.sections = []
+ self.comments = {}
+ self.inline_comments = {}
+ self.configspec = {}
+
+
+ def setdefault(self, key, default=None):
+ """A version of setdefault that sets sequence if appropriate."""
+ try:
+ return self[key]
+ except KeyError:
+ self[key] = default
+ return self[key]
+
+
+ def items(self):
+ """D.items() -> list of D's (key, value) pairs, as 2-tuples"""
+ return zip((self.scalars + self.sections), self.values())
+
+
+ def keys(self):
+ """D.keys() -> list of D's keys"""
+ return (self.scalars + self.sections)
+
+
+ def values(self):
+ """D.values() -> list of D's values"""
+ return [self[key] for key in (self.scalars + self.sections)]
+
+
+ def iteritems(self):
+ """D.iteritems() -> an iterator over the (key, value) items of D"""
+ return iter(self.items())
+
+
+ def iterkeys(self):
+ """D.iterkeys() -> an iterator over the keys of D"""
+ return iter((self.scalars + self.sections))
+
+ __iter__ = iterkeys
+
+
+ def itervalues(self):
+ """D.itervalues() -> an iterator over the values of D"""
+ return iter(self.values())
+
+
+ def __repr__(self):
+ """x.__repr__() <==> repr(x)"""
+ return '{%s}' % ', '.join([('%s: %s' % (repr(key), repr(self[key])))
+ for key in (self.scalars + self.sections)])
+
+ __str__ = __repr__
+ __str__.__doc__ = "x.__str__() <==> str(x)"
+
+
+ # Extra methods - not in a normal dictionary
+
+ def dict(self):
+ """
+ Return a deepcopy of self as a dictionary.
+
+ All members that are ``Section`` instances are recursively turned to
+ ordinary dictionaries - by calling their ``dict`` method.
+
+ >>> n = a.dict()
+ >>> n == a
+ 1
+ >>> n is a
+ 0
+ """
+ newdict = {}
+ for entry in self:
+ this_entry = self[entry]
+ if isinstance(this_entry, Section):
+ this_entry = this_entry.dict()
+ elif isinstance(this_entry, list):
+ # create a copy rather than a reference
+ this_entry = list(this_entry)
+ elif isinstance(this_entry, tuple):
+ # create a copy rather than a reference
+ this_entry = tuple(this_entry)
+ newdict[entry] = this_entry
+ return newdict
+
+
+ def merge(self, indict):
+ """
+ A recursive update - useful for merging config files.
+
+ >>> a = '''[section1]
+ ... option1 = True
+ ... [[subsection]]
+ ... more_options = False
+ ... # end of file'''.splitlines()
+ >>> b = '''# File is user.ini
+ ... [section1]
+ ... option1 = False
+ ... # end of file'''.splitlines()
+ >>> c1 = ConfigObj(b)
+ >>> c2 = ConfigObj(a)
+ >>> c2.merge(c1)
+ >>> c2
+ {'section1': {'option1': 'False', 'subsection': {'more_options': 'False'}}}
+ """
+ for key, val in indict.items():
+ if (key in self and isinstance(self[key], dict) and
+ isinstance(val, dict)):
+ self[key].merge(val)
+ else:
+ self[key] = val
+
+
+ def rename(self, oldkey, newkey):
+ """
+ Change a keyname to another, without changing position in sequence.
+
+ Implemented so that transformations can be made on keys,
+ as well as on values. (used by encode and decode)
+
+ Also renames comments.
+ """
+ if oldkey in self.scalars:
+ the_list = self.scalars
+ elif oldkey in self.sections:
+ the_list = self.sections
+ else:
+ raise KeyError('Key "%s" not found.' % oldkey)
+ pos = the_list.index(oldkey)
+ #
+ val = self[oldkey]
+ dict.__delitem__(self, oldkey)
+ dict.__setitem__(self, newkey, val)
+ the_list.remove(oldkey)
+ the_list.insert(pos, newkey)
+ comm = self.comments[oldkey]
+ inline_comment = self.inline_comments[oldkey]
+ del self.comments[oldkey]
+ del self.inline_comments[oldkey]
+ self.comments[newkey] = comm
+ self.inline_comments[newkey] = inline_comment
+
+
+ def walk(self, function, raise_errors=True,
+ call_on_sections=False, **keywargs):
+ """
+ Walk every member and call a function on the keyword and value.
+
+ Return a dictionary of the return values
+
+ If the function raises an exception, raise the errror
+ unless ``raise_errors=False``, in which case set the return value to
+ ``False``.
+
+ Any unrecognised keyword arguments you pass to walk, will be pased on
+ to the function you pass in.
+
+ Note: if ``call_on_sections`` is ``True`` then - on encountering a
+ subsection, *first* the function is called for the *whole* subsection,
+ and then recurses into it's members. This means your function must be
+ able to handle strings, dictionaries and lists. This allows you
+ to change the key of subsections as well as for ordinary members. The
+ return value when called on the whole subsection has to be discarded.
+
+ See the encode and decode methods for examples, including functions.
+
+ .. caution::
+
+ You can use ``walk`` to transform the names of members of a section
+ but you mustn't add or delete members.
+
+ >>> config = '''[XXXXsection]
+ ... XXXXkey = XXXXvalue'''.splitlines()
+ >>> cfg = ConfigObj(config)
+ >>> cfg
+ {'XXXXsection': {'XXXXkey': 'XXXXvalue'}}
+ >>> def transform(section, key):
+ ... val = section[key]
+ ... newkey = key.replace('XXXX', 'CLIENT1')
+ ... section.rename(key, newkey)
+ ... if isinstance(val, (tuple, list, dict)):
+ ... pass
+ ... else:
+ ... val = val.replace('XXXX', 'CLIENT1')
+ ... section[newkey] = val
+ >>> cfg.walk(transform, call_on_sections=True)
+ {'CLIENT1section': {'CLIENT1key': None}}
+ >>> cfg
+ {'CLIENT1section': {'CLIENT1key': 'CLIENT1value'}}
+ """
+ out = {}
+ # scalars first
+ for i in range(len(self.scalars)):
+ entry = self.scalars[i]
+ try:
+ val = function(self, entry, **keywargs)
+ # bound again in case name has changed
+ entry = self.scalars[i]
+ out[entry] = val
+ except Exception:
+ if raise_errors:
+ raise
+ else:
+ entry = self.scalars[i]
+ out[entry] = False
+ # then sections
+ for i in range(len(self.sections)):
+ entry = self.sections[i]
+ if call_on_sections:
+ try:
+ function(self, entry, **keywargs)
+ except Exception:
+ if raise_errors:
+ raise
+ else:
+ entry = self.sections[i]
+ out[entry] = False
+ # bound again in case name has changed
+ entry = self.sections[i]
+ # previous result is discarded
+ out[entry] = self[entry].walk(
+ function,
+ raise_errors=raise_errors,
+ call_on_sections=call_on_sections,
+ **keywargs)
+ return out
+
+
+ def decode(self, encoding):
+ """
+ Decode all strings and values to unicode, using the specified encoding.
+
+ Works with subsections and list values.
+
+ Uses the ``walk`` method.
+
+ Testing ``encode`` and ``decode``.
+ >>> m = ConfigObj(a)
+ >>> m.decode('ascii')
+ >>> def testuni(val):
+ ... for entry in val:
+ ... if not isinstance(entry, unicode):
+ ... print >> sys.stderr, type(entry)
+ ... raise AssertionError, 'decode failed.'
+ ... if isinstance(val[entry], dict):
+ ... testuni(val[entry])
+ ... elif not isinstance(val[entry], unicode):
+ ... raise AssertionError, 'decode failed.'
+ >>> testuni(m)
+ >>> m.encode('ascii')
+ >>> a == m
+ 1
+ """
+ warn('use of ``decode`` is deprecated.', DeprecationWarning)
+ def decode(section, key, encoding=encoding, warn=True):
+ """ """
+ val = section[key]
+ if isinstance(val, (list, tuple)):
+ newval = []
+ for entry in val:
+ newval.append(entry.decode(encoding))
+ elif isinstance(val, dict):
+ newval = val
+ else:
+ newval = val.decode(encoding)
+ newkey = key.decode(encoding)
+ section.rename(key, newkey)
+ section[newkey] = newval
+ # using ``call_on_sections`` allows us to modify section names
+ self.walk(decode, call_on_sections=True)
+
+
+ def encode(self, encoding):
+ """
+ Encode all strings and values from unicode,
+ using the specified encoding.
+
+ Works with subsections and list values.
+ Uses the ``walk`` method.
+ """
+ warn('use of ``encode`` is deprecated.', DeprecationWarning)
+ def encode(section, key, encoding=encoding):
+ """ """
+ val = section[key]
+ if isinstance(val, (list, tuple)):
+ newval = []
+ for entry in val:
+ newval.append(entry.encode(encoding))
+ elif isinstance(val, dict):
+ newval = val
+ else:
+ newval = val.encode(encoding)
+ newkey = key.encode(encoding)
+ section.rename(key, newkey)
+ section[newkey] = newval
+ self.walk(encode, call_on_sections=True)
+
+
+ def istrue(self, key):
+ """A deprecated version of ``as_bool``."""
+ warn('use of ``istrue`` is deprecated. Use ``as_bool`` method '
+ 'instead.', DeprecationWarning)
+ return self.as_bool(key)
+
+
+ def as_bool(self, key):
+ """
+ Accepts a key as input. The corresponding value must be a string or
+ the objects (``True`` or 1) or (``False`` or 0). We allow 0 and 1 to
+ retain compatibility with Python 2.2.
+
+ If the string is one of ``True``, ``On``, ``Yes``, or ``1`` it returns
+ ``True``.
+
+ If the string is one of ``False``, ``Off``, ``No``, or ``0`` it returns
+ ``False``.
+
+ ``as_bool`` is not case sensitive.
+
+ Any other input will raise a ``ValueError``.
+
+ >>> a = ConfigObj()
+ >>> a['a'] = 'fish'
+ >>> a.as_bool('a')
+ Traceback (most recent call last):
+ ValueError: Value "fish" is neither True nor False
+ >>> a['b'] = 'True'
+ >>> a.as_bool('b')
+ 1
+ >>> a['b'] = 'off'
+ >>> a.as_bool('b')
+ 0
+ """
+ val = self[key]
+ if val == True:
+ return True
+ elif val == False:
+ return False
+ else:
+ try:
+ if not isinstance(val, StringTypes):
+ # TODO: Why do we raise a KeyError here?
+ raise KeyError()
+ else:
+ return self.main._bools[val.lower()]
+ except KeyError:
+ raise ValueError('Value "%s" is neither True nor False' % val)
+
+
+ def as_int(self, key):
+ """
+ A convenience method which coerces the specified value to an integer.
+
+ If the value is an invalid literal for ``int``, a ``ValueError`` will
+ be raised.
+
+ >>> a = ConfigObj()
+ >>> a['a'] = 'fish'
+ >>> a.as_int('a')
+ Traceback (most recent call last):
+ ValueError: invalid literal for int(): fish
+ >>> a['b'] = '1'
+ >>> a.as_int('b')
+ 1
+ >>> a['b'] = '3.2'
+ >>> a.as_int('b')
+ Traceback (most recent call last):
+ ValueError: invalid literal for int(): 3.2
+ """
+ return int(self[key])
+
+
+ def as_float(self, key):
+ """
+ A convenience method which coerces the specified value to a float.
+
+ If the value is an invalid literal for ``float``, a ``ValueError`` will
+ be raised.
+
+ >>> a = ConfigObj()
+ >>> a['a'] = 'fish'
+ >>> a.as_float('a')
+ Traceback (most recent call last):
+ ValueError: invalid literal for float(): fish
+ >>> a['b'] = '1'
+ >>> a.as_float('b')
+ 1.0
+ >>> a['b'] = '3.2'
+ >>> a.as_float('b')
+ 3.2000000000000002
+ """
+ return float(self[key])
+
+
+ def restore_default(self, key):
+ """
+ Restore (and return) default value for the specified key.
+
+ This method will only work for a ConfigObj that was created
+ with a configspec and has been validated.
+
+ If there is no default value for this key, ``KeyError`` is raised.
+ """
+ default = self.default_values[key]
+ dict.__setitem__(self, key, default)
+ if key not in self.defaults:
+ self.defaults.append(key)
+ return default
+
+
+ def restore_defaults(self):
+ """
+ Recursively restore default values to all members
+ that have them.
+
+ This method will only work for a ConfigObj that was created
+ with a configspec and has been validated.
+
+ It doesn't delete or modify entries without default values.
+ """
+ for key in self.default_values:
+ self.restore_default(key)
+
+ for section in self.sections:
+ self[section].restore_defaults()
+
+
+class ConfigObj(Section):
+ """An object to read, create, and write config files."""
+
+ _keyword = re.compile(r'''^ # line start
+ (\s*) # indentation
+ ( # keyword
+ (?:".*?")| # double quotes
+ (?:'.*?')| # single quotes
+ (?:[^'"=].*?) # no quotes
+ )
+ \s*=\s* # divider
+ (.*) # value (including list values and comments)
+ $ # line end
+ ''',
+ re.VERBOSE)
+
+ _sectionmarker = re.compile(r'''^
+ (\s*) # 1: indentation
+ ((?:\[\s*)+) # 2: section marker open
+ ( # 3: section name open
+ (?:"\s*\S.*?\s*")| # at least one non-space with double quotes
+ (?:'\s*\S.*?\s*')| # at least one non-space with single quotes
+ (?:[^'"\s].*?) # at least one non-space unquoted
+ ) # section name close
+ ((?:\s*\])+) # 4: section marker close
+ \s*(\#.*)? # 5: optional comment
+ $''',
+ re.VERBOSE)
+
+ # this regexp pulls list values out as a single string
+ # or single values and comments
+ # FIXME: this regex adds a '' to the end of comma terminated lists
+ # workaround in ``_handle_value``
+ _valueexp = re.compile(r'''^
+ (?:
+ (?:
+ (
+ (?:
+ (?:
+ (?:".*?")| # double quotes
+ (?:'.*?')| # single quotes
+ (?:[^'",\#][^,\#]*?) # unquoted
+ )
+ \s*,\s* # comma
+ )* # match all list items ending in a comma (if any)
+ )
+ (
+ (?:".*?")| # double quotes
+ (?:'.*?')| # single quotes
+ (?:[^'",\#\s][^,]*?)| # unquoted
+ (?:(?<!,)) # Empty value
+ )? # last item in a list - or string value
+ )|
+ (,) # alternatively a single comma - empty list
+ )
+ \s*(\#.*)? # optional comment
+ $''',
+ re.VERBOSE)
+
+ # use findall to get the members of a list value
+ _listvalueexp = re.compile(r'''
+ (
+ (?:".*?")| # double quotes
+ (?:'.*?')| # single quotes
+ (?:[^'",\#].*?) # unquoted
+ )
+ \s*,\s* # comma
+ ''',
+ re.VERBOSE)
+
+ # this regexp is used for the value
+ # when lists are switched off
+ _nolistvalue = re.compile(r'''^
+ (
+ (?:".*?")| # double quotes
+ (?:'.*?')| # single quotes
+ (?:[^'"\#].*?)| # unquoted
+ (?:) # Empty value
+ )
+ \s*(\#.*)? # optional comment
+ $''',
+ re.VERBOSE)
+
+ # regexes for finding triple quoted values on one line
+ _single_line_single = re.compile(r"^'''(.*?)'''\s*(#.*)?$")
+ _single_line_double = re.compile(r'^"""(.*?)"""\s*(#.*)?$')
+ _multi_line_single = re.compile(r"^(.*?)'''\s*(#.*)?$")
+ _multi_line_double = re.compile(r'^(.*?)"""\s*(#.*)?$')
+
+ _triple_quote = {
+ "'''": (_single_line_single, _multi_line_single),
+ '"""': (_single_line_double, _multi_line_double),
+ }
+
+ # Used by the ``istrue`` Section method
+ _bools = {
+ 'yes': True, 'no': False,
+ 'on': True, 'off': False,
+ '1': True, '0': False,
+ 'true': True, 'false': False,
+ }
+
+
+ def __init__(self, infile=None, options=None, **kwargs):
+ """
+ Parse a config file or create a config file object.
+
+ ``ConfigObj(infile=None, options=None, **kwargs)``
+ """
+ # init the superclass
+ Section.__init__(self, self, 0, self)
+
+ if infile is None:
+ infile = []
+ if options is None:
+ options = {}
+ else:
+ options = dict(options)
+
+ # keyword arguments take precedence over an options dictionary
+ options.update(kwargs)
+
+ defaults = OPTION_DEFAULTS.copy()
+ # TODO: check the values too.
+ for entry in options:
+ if entry not in defaults:
+ raise TypeError('Unrecognised option "%s".' % entry)
+
+ # Add any explicit options to the defaults
+ defaults.update(options)
+ self._initialise(defaults)
+ configspec = defaults['configspec']
+ self._original_configspec = configspec
+ self._load(infile, configspec)
+
+
+ def _load(self, infile, configspec):
+ if isinstance(infile, StringTypes):
+ self.filename = infile
+ if os.path.isfile(infile):
+ h = open(infile, 'rb')
+ infile = h.read() or []
+ h.close()
+ elif self.file_error:
+ # raise an error if the file doesn't exist
+ raise IOError('Config file not found: "%s".' % self.filename)
+ else:
+ # file doesn't already exist
+ if self.create_empty:
+ # this is a good test that the filename specified
+ # isn't impossible - like on a non-existent device
+ h = open(infile, 'w')
+ h.write('')
+ h.close()
+ infile = []
+
+ elif isinstance(infile, (list, tuple)):
+ infile = list(infile)
+
+ elif isinstance(infile, dict):
+ # initialise self
+ # the Section class handles creating subsections
+ if isinstance(infile, ConfigObj):
+ # get a copy of our ConfigObj
+ infile = infile.dict()
+
+ for entry in infile:
+ self[entry] = infile[entry]
+ del self._errors
+
+ if configspec is not None:
+ self._handle_configspec(configspec)
+ else:
+ self.configspec = None
+ return
+
+ elif hasattr(infile, 'read'):
+ # This supports file like objects
+ infile = infile.read() or []
+ # needs splitting into lines - but needs doing *after* decoding
+ # in case it's not an 8 bit encoding
+ else:
+ raise TypeError('infile must be a filename, file like object, or list of lines.')
+
+ if infile:
+ # don't do it for the empty ConfigObj
+ infile = self._handle_bom(infile)
+ # infile is now *always* a list
+ #
+ # Set the newlines attribute (first line ending it finds)
+ # and strip trailing '\n' or '\r' from lines
+ for line in infile:
+ if (not line) or (line[-1] not in ('\r', '\n', '\r\n')):
+ continue
+ for end in ('\r\n', '\n', '\r'):
+ if line.endswith(end):
+ self.newlines = end
+ break
+ break
+
+ infile = [line.rstrip('\r\n') for line in infile]
+
+ self._parse(infile)
+ # if we had any errors, now is the time to raise them
+ if self._errors:
+ info = "at line %s." % self._errors[0].line_number
+ if len(self._errors) > 1:
+ msg = "Parsing failed with several errors.\nFirst error %s" % info
+ error = ConfigObjError(msg)
+ else:
+ error = self._errors[0]
+ # set the errors attribute; it's a list of tuples:
+ # (error_type, message, line_number)
+ error.errors = self._errors
+ # set the config attribute
+ error.config = self
+ raise error
+ # delete private attributes
+ del self._errors
+
+ if configspec is None:
+ self.configspec = None
+ else:
+ self._handle_configspec(configspec)
+
+
+ def _initialise(self, options=None):
+ if options is None:
+ options = OPTION_DEFAULTS
+
+ # initialise a few variables
+ self.filename = None
+ self._errors = []
+ self.raise_errors = options['raise_errors']
+ self.interpolation = options['interpolation']
+ self.list_values = options['list_values']
+ self.create_empty = options['create_empty']
+ self.file_error = options['file_error']
+ self.stringify = options['stringify']
+ self.indent_type = options['indent_type']
+ self.encoding = options['encoding']
+ self.default_encoding = options['default_encoding']
+ self.BOM = False
+ self.newlines = None
+ self.write_empty_values = options['write_empty_values']
+ self.unrepr = options['unrepr']
+
+ self.initial_comment = []
+ self.final_comment = []
+ self.configspec = {}
+
+ # Clear section attributes as well
+ Section._initialise(self)
+
+
+ def __repr__(self):
+ return ('ConfigObj({%s})' %
+ ', '.join([('%s: %s' % (repr(key), repr(self[key])))
+ for key in (self.scalars + self.sections)]))
+
+
+ def _handle_bom(self, infile):
+ """
+ Handle any BOM, and decode if necessary.
+
+ If an encoding is specified, that *must* be used - but the BOM should
+ still be removed (and the BOM attribute set).
+
+ (If the encoding is wrongly specified, then a BOM for an alternative
+ encoding won't be discovered or removed.)
+
+ If an encoding is not specified, UTF8 or UTF16 BOM will be detected and
+ removed. The BOM attribute will be set. UTF16 will be decoded to
+ unicode.
+
+ NOTE: This method must not be called with an empty ``infile``.
+
+ Specifying the *wrong* encoding is likely to cause a
+ ``UnicodeDecodeError``.
+
+ ``infile`` must always be returned as a list of lines, but may be
+ passed in as a single string.
+ """
+ if ((self.encoding is not None) and
+ (self.encoding.lower() not in BOM_LIST)):
+ # No need to check for a BOM
+ # the encoding specified doesn't have one
+ # just decode
+ return self._decode(infile, self.encoding)
+
+ if isinstance(infile, (list, tuple)):
+ line = infile[0]
+ else:
+ line = infile
+ if self.encoding is not None:
+ # encoding explicitly supplied
+ # And it could have an associated BOM
+ # TODO: if encoding is just UTF16 - we ought to check for both
+ # TODO: big endian and little endian versions.
+ enc = BOM_LIST[self.encoding.lower()]
+ if enc == 'utf_16':
+ # For UTF16 we try big endian and little endian
+ for BOM, (encoding, final_encoding) in BOMS.items():
+ if not final_encoding:
+ # skip UTF8
+ continue
+ if infile.startswith(BOM):
+ ### BOM discovered
+ ##self.BOM = True
+ # Don't need to remove BOM
+ return self._decode(infile, encoding)
+
+ # If we get this far, will *probably* raise a DecodeError
+ # As it doesn't appear to start with a BOM
+ return self._decode(infile, self.encoding)
+
+ # Must be UTF8
+ BOM = BOM_SET[enc]
+ if not line.startswith(BOM):
+ return self._decode(infile, self.encoding)
+
+ newline = line[len(BOM):]
+
+ # BOM removed
+ if isinstance(infile, (list, tuple)):
+ infile[0] = newline
+ else:
+ infile = newline
+ self.BOM = True
+ return self._decode(infile, self.encoding)
+
+ # No encoding specified - so we need to check for UTF8/UTF16
+ for BOM, (encoding, final_encoding) in BOMS.items():
+ if not line.startswith(BOM):
+ continue
+ else:
+ # BOM discovered
+ self.encoding = final_encoding
+ if not final_encoding:
+ self.BOM = True
+ # UTF8
+ # remove BOM
+ newline = line[len(BOM):]
+ if isinstance(infile, (list, tuple)):
+ infile[0] = newline
+ else:
+ infile = newline
+ # UTF8 - don't decode
+ if isinstance(infile, StringTypes):
+ return infile.splitlines(True)
+ else:
+ return infile
+ # UTF16 - have to decode
+ return self._decode(infile, encoding)
+
+ # No BOM discovered and no encoding specified, just return
+ if isinstance(infile, StringTypes):
+ # infile read from a file will be a single string
+ return infile.splitlines(True)
+ return infile
+
+
+ def _a_to_u(self, aString):
+ """Decode ASCII strings to unicode if a self.encoding is specified."""
+ if self.encoding:
+ return aString.decode('ascii')
+ else:
+ return aString
+
+
+ def _decode(self, infile, encoding):
+ """
+ Decode infile to unicode. Using the specified encoding.
+
+ if is a string, it also needs converting to a list.
+ """
+ if isinstance(infile, StringTypes):
+ # can't be unicode
+ # NOTE: Could raise a ``UnicodeDecodeError``
+ return infile.decode(encoding).splitlines(True)
+ for i, line in enumerate(infile):
+ if not isinstance(line, unicode):
+ # NOTE: The isinstance test here handles mixed lists of unicode/string
+ # NOTE: But the decode will break on any non-string values
+ # NOTE: Or could raise a ``UnicodeDecodeError``
+ infile[i] = line.decode(encoding)
+ return infile
+
+
+ def _decode_element(self, line):
+ """Decode element to unicode if necessary."""
+ if not self.encoding:
+ return line
+ if isinstance(line, str) and self.default_encoding:
+ return line.decode(self.default_encoding)
+ return line
+
+
+ def _str(self, value):
+ """
+ Used by ``stringify`` within validate, to turn non-string values
+ into strings.
+ """
+ if not isinstance(value, StringTypes):
+ return str(value)
+ else:
+ return value
+
+
+ def _parse(self, infile):
+ """Actually parse the config file."""
+ temp_list_values = self.list_values
+ if self.unrepr:
+ self.list_values = False
+
+ comment_list = []
+ done_start = False
+ this_section = self
+ maxline = len(infile) - 1
+ cur_index = -1
+ reset_comment = False
+
+ while cur_index < maxline:
+ if reset_comment:
+ comment_list = []
+ cur_index += 1
+ line = infile[cur_index]
+ sline = line.strip()
+ # do we have anything on the line ?
+ if not sline or sline.startswith('#'):
+ reset_comment = False
+ comment_list.append(line)
+ continue
+
+ if not done_start:
+ # preserve initial comment
+ self.initial_comment = comment_list
+ comment_list = []
+ done_start = True
+
+ reset_comment = True
+ # first we check if it's a section marker
+ mat = self._sectionmarker.match(line)
+ if mat is not None:
+ # is a section line
+ (indent, sect_open, sect_name, sect_close, comment) = mat.groups()
+ if indent and (self.indent_type is None):
+ self.indent_type = indent
+ cur_depth = sect_open.count('[')
+ if cur_depth != sect_close.count(']'):
+ self._handle_error("Cannot compute the section depth at line %s.",
+ NestingError, infile, cur_index)
+ continue
+
+ if cur_depth < this_section.depth:
+ # the new section is dropping back to a previous level
+ try:
+ parent = self._match_depth(this_section,
+ cur_depth).parent
+ except SyntaxError:
+ self._handle_error("Cannot compute nesting level at line %s.",
+ NestingError, infile, cur_index)
+ continue
+ elif cur_depth == this_section.depth:
+ # the new section is a sibling of the current section
+ parent = this_section.parent
+ elif cur_depth == this_section.depth + 1:
+ # the new section is a child the current section
+ parent = this_section
+ else:
+ self._handle_error("Section too nested at line %s.",
+ NestingError, infile, cur_index)
+
+ sect_name = self._unquote(sect_name)
+ if parent.has_key(sect_name):
+ self._handle_error('Duplicate section name at line %s.',
+ DuplicateError, infile, cur_index)
+ continue
+
+ # create the new section
+ this_section = Section(
+ parent,
+ cur_depth,
+ self,
+ name=sect_name)
+ parent[sect_name] = this_section
+ parent.inline_comments[sect_name] = comment
+ parent.comments[sect_name] = comment_list
+ continue
+ #
+ # it's not a section marker,
+ # so it should be a valid ``key = value`` line
+ mat = self._keyword.match(line)
+ if mat is None:
+ # it neither matched as a keyword
+ # or a section marker
+ self._handle_error(
+ 'Invalid line at line "%s".',
+ ParseError, infile, cur_index)
+ else:
+ # is a keyword value
+ # value will include any inline comment
+ (indent, key, value) = mat.groups()
+ if indent and (self.indent_type is None):
+ self.indent_type = indent
+ # check for a multiline value
+ if value[:3] in ['"""', "'''"]:
+ try:
+ (value, comment, cur_index) = self._multiline(
+ value, infile, cur_index, maxline)
+ except SyntaxError:
+ self._handle_error(
+ 'Parse error in value at line %s.',
+ ParseError, infile, cur_index)
+ continue
+ else:
+ if self.unrepr:
+ comment = ''
+ try:
+ value = unrepr(value)
+ except Exception, e:
+ if type(e) == UnknownType:
+ msg = 'Unknown name or type in value at line %s.'
+ else:
+ msg = 'Parse error in value at line %s.'
+ self._handle_error(msg, UnreprError, infile,
+ cur_index)
+ continue
+ else:
+ if self.unrepr:
+ comment = ''
+ try:
+ value = unrepr(value)
+ except Exception, e:
+ if isinstance(e, UnknownType):
+ msg = 'Unknown name or type in value at line %s.'
+ else:
+ msg = 'Parse error in value at line %s.'
+ self._handle_error(msg, UnreprError, infile,
+ cur_index)
+ continue
+ else:
+ # extract comment and lists
+ try:
+ (value, comment) = self._handle_value(value)
+ except SyntaxError:
+ self._handle_error(
+ 'Parse error in value at line %s.',
+ ParseError, infile, cur_index)
+ continue
+ #
+ key = self._unquote(key)
+ if this_section.has_key(key):
+ self._handle_error(
+ 'Duplicate keyword name at line %s.',
+ DuplicateError, infile, cur_index)
+ continue
+ # add the key.
+ # we set unrepr because if we have got this far we will never
+ # be creating a new section
+ this_section.__setitem__(key, value, unrepr=True)
+ this_section.inline_comments[key] = comment
+ this_section.comments[key] = comment_list
+ continue
+ #
+ if self.indent_type is None:
+ # no indentation used, set the type accordingly
+ self.indent_type = ''
+
+ # preserve the final comment
+ if not self and not self.initial_comment:
+ self.initial_comment = comment_list
+ elif not reset_comment:
+ self.final_comment = comment_list
+ self.list_values = temp_list_values
+
+
+ def _match_depth(self, sect, depth):
+ """
+ Given a section and a depth level, walk back through the sections
+ parents to see if the depth level matches a previous section.
+
+ Return a reference to the right section,
+ or raise a SyntaxError.
+ """
+ while depth < sect.depth:
+ if sect is sect.parent:
+ # we've reached the top level already
+ raise SyntaxError()
+ sect = sect.parent
+ if sect.depth == depth:
+ return sect
+ # shouldn't get here
+ raise SyntaxError()
+
+
+ def _handle_error(self, text, ErrorClass, infile, cur_index):
+ """
+ Handle an error according to the error settings.
+
+ Either raise the error or store it.
+ The error will have occured at ``cur_index``
+ """
+ line = infile[cur_index]
+ cur_index += 1
+ message = text % cur_index
+ error = ErrorClass(message, cur_index, line)
+ if self.raise_errors:
+ # raise the error - parsing stops here
+ raise error
+ # store the error
+ # reraise when parsing has finished
+ self._errors.append(error)
+
+
+ def _unquote(self, value):
+ """Return an unquoted version of a value"""
+ if (value[0] == value[-1]) and (value[0] in ('"', "'")):
+ value = value[1:-1]
+ return value
+
+
+ def _quote(self, value, multiline=True):
+ """
+ Return a safely quoted version of a value.
+
+ Raise a ConfigObjError if the value cannot be safely quoted.
+ If multiline is ``True`` (default) then use triple quotes
+ if necessary.
+
+ Don't quote values that don't need it.
+ Recursively quote members of a list and return a comma joined list.
+ Multiline is ``False`` for lists.
+ Obey list syntax for empty and single member lists.
+
+ If ``list_values=False`` then the value is only quoted if it contains
+ a ``\n`` (is multiline) or '#'.
+
+ If ``write_empty_values`` is set, and the value is an empty string, it
+ won't be quoted.
+ """
+ if multiline and self.write_empty_values and value == '':
+ # Only if multiline is set, so that it is used for values not
+ # keys, and not values that are part of a list
+ return ''
+
+ if multiline and isinstance(value, (list, tuple)):
+ if not value:
+ return ','
+ elif len(value) == 1:
+ return self._quote(value[0], multiline=False) + ','
+ return ', '.join([self._quote(val, multiline=False)
+ for val in value])
+ if not isinstance(value, StringTypes):
+ if self.stringify:
+ value = str(value)
+ else:
+ raise TypeError('Value "%s" is not a string.' % value)
+
+ if not value:
+ return '""'
+
+ no_lists_no_quotes = not self.list_values and '\n' not in value and '#' not in value
+ need_triple = multiline and ((("'" in value) and ('"' in value)) or ('\n' in value ))
+ hash_triple_quote = multiline and not need_triple and ("'" in value) and ('"' in value) and ('#' in value)
+ check_for_single = (no_lists_no_quotes or not need_triple) and not hash_triple_quote
+
+ if check_for_single:
+ if not self.list_values:
+ # we don't quote if ``list_values=False``
+ quot = noquot
+ # for normal values either single or double quotes will do
+ elif '\n' in value:
+ # will only happen if multiline is off - e.g. '\n' in key
+ raise ConfigObjError('Value "%s" cannot be safely quoted.' % value)
+ elif ((value[0] not in wspace_plus) and
+ (value[-1] not in wspace_plus) and
+ (',' not in value)):
+ quot = noquot
+ else:
+ quot = self._get_single_quote(value)
+ else:
+ # if value has '\n' or "'" *and* '"', it will need triple quotes
+ quot = self._get_triple_quote(value)
+
+ if quot == noquot and '#' in value and self.list_values:
+ quot = self._get_single_quote(value)
+
+ return quot % value
+
+
+ def _get_single_quote(self, value):
+ if ("'" in value) and ('"' in value):
+ raise ConfigObjError('Value "%s" cannot be safely quoted.' % value)
+ elif '"' in value:
+ quot = squot
+ else:
+ quot = dquot
+ return quot
+
+
+ def _get_triple_quote(self, value):
+ if (value.find('"""') != -1) and (value.find("'''") != -1):
+ raise ConfigObjError('Value "%s" cannot be safely quoted.' % value)
+ if value.find('"""') == -1:
+ quot = tdquot
+ else:
+ quot = tsquot
+ return quot
+
+
+ def _handle_value(self, value):
+ """
+ Given a value string, unquote, remove comment,
+ handle lists. (including empty and single member lists)
+ """
+ # do we look for lists in values ?
+ if not self.list_values:
+ mat = self._nolistvalue.match(value)
+ if mat is None:
+ raise SyntaxError()
+ # NOTE: we don't unquote here
+ return mat.groups()
+ #
+ mat = self._valueexp.match(value)
+ if mat is None:
+ # the value is badly constructed, probably badly quoted,
+ # or an invalid list
+ raise SyntaxError()
+ (list_values, single, empty_list, comment) = mat.groups()
+ if (list_values == '') and (single is None):
+ # change this if you want to accept empty values
+ raise SyntaxError()
+ # NOTE: note there is no error handling from here if the regex
+ # is wrong: then incorrect values will slip through
+ if empty_list is not None:
+ # the single comma - meaning an empty list
+ return ([], comment)
+ if single is not None:
+ # handle empty values
+ if list_values and not single:
+ # FIXME: the '' is a workaround because our regex now matches
+ # '' at the end of a list if it has a trailing comma
+ single = None
+ else:
+ single = single or '""'
+ single = self._unquote(single)
+ if list_values == '':
+ # not a list value
+ return (single, comment)
+ the_list = self._listvalueexp.findall(list_values)
+ the_list = [self._unquote(val) for val in the_list]
+ if single is not None:
+ the_list += [single]
+ return (the_list, comment)
+
+
+ def _multiline(self, value, infile, cur_index, maxline):
+ """Extract the value, where we are in a multiline situation."""
+ quot = value[:3]
+ newvalue = value[3:]
+ single_line = self._triple_quote[quot][0]
+ multi_line = self._triple_quote[quot][1]
+ mat = single_line.match(value)
+ if mat is not None:
+ retval = list(mat.groups())
+ retval.append(cur_index)
+ return retval
+ elif newvalue.find(quot) != -1:
+ # somehow the triple quote is missing
+ raise SyntaxError()
+ #
+ while cur_index < maxline:
+ cur_index += 1
+ newvalue += '\n'
+ line = infile[cur_index]
+ if line.find(quot) == -1:
+ newvalue += line
+ else:
+ # end of multiline, process it
+ break
+ else:
+ # we've got to the end of the config, oops...
+ raise SyntaxError()
+ mat = multi_line.match(line)
+ if mat is None:
+ # a badly formed line
+ raise SyntaxError()
+ (value, comment) = mat.groups()
+ return (newvalue + value, comment, cur_index)
+
+
+ def _handle_configspec(self, configspec):
+ """Parse the configspec."""
+ # FIXME: Should we check that the configspec was created with the
+ # correct settings ? (i.e. ``list_values=False``)
+ if not isinstance(configspec, ConfigObj):
+ try:
+ configspec = ConfigObj(configspec,
+ raise_errors=True,
+ file_error=True,
+ list_values=False)
+ except ConfigObjError, e:
+ # FIXME: Should these errors have a reference
+ # to the already parsed ConfigObj ?
+ raise ConfigspecError('Parsing configspec failed: %s' % e)
+ except IOError, e:
+ raise IOError('Reading configspec failed: %s' % e)
+
+ self._set_configspec_value(configspec, self)
+
+
+ def _set_configspec_value(self, configspec, section):
+ """Used to recursively set configspec values."""
+ if '__many__' in configspec.sections:
+ section.configspec['__many__'] = configspec['__many__']
+ if len(configspec.sections) > 1:
+ # FIXME: can we supply any useful information here ?
+ raise RepeatSectionError()
+
+ if hasattr(configspec, 'initial_comment'):
+ section._configspec_initial_comment = configspec.initial_comment
+ section._configspec_final_comment = configspec.final_comment
+ section._configspec_encoding = configspec.encoding
+ section._configspec_BOM = configspec.BOM
+ section._configspec_newlines = configspec.newlines
+ section._configspec_indent_type = configspec.indent_type
+
+ for entry in configspec.scalars:
+ section._configspec_comments[entry] = configspec.comments[entry]
+ section._configspec_inline_comments[entry] = configspec.inline_comments[entry]
+ section.configspec[entry] = configspec[entry]
+ section._order.append(entry)
+
+ for entry in configspec.sections:
+ if entry == '__many__':
+ continue
+
+ section._cs_section_comments[entry] = configspec.comments[entry]
+ section._cs_section_inline_comments[entry] = configspec.inline_comments[entry]
+ if not section.has_key(entry):
+ section[entry] = {}
+ self._set_configspec_value(configspec[entry], section[entry])
+
+
+ def _handle_repeat(self, section, configspec):
+ """Dynamically assign configspec for repeated section."""
+ try:
+ section_keys = configspec.sections
+ scalar_keys = configspec.scalars
+ except AttributeError:
+ section_keys = [entry for entry in configspec
+ if isinstance(configspec[entry], dict)]
+ scalar_keys = [entry for entry in configspec
+ if not isinstance(configspec[entry], dict)]
+
+ if '__many__' in section_keys and len(section_keys) > 1:
+ # FIXME: can we supply any useful information here ?
+ raise RepeatSectionError()
+
+ scalars = {}
+ sections = {}
+ for entry in scalar_keys:
+ val = configspec[entry]
+ scalars[entry] = val
+ for entry in section_keys:
+ val = configspec[entry]
+ if entry == '__many__':
+ scalars[entry] = val
+ continue
+ sections[entry] = val
+
+ section.configspec = scalars
+ for entry in sections:
+ if not section.has_key(entry):
+ section[entry] = {}
+ self._handle_repeat(section[entry], sections[entry])
+
+
+ def _write_line(self, indent_string, entry, this_entry, comment):
+ """Write an individual line, for the write method"""
+ # NOTE: the calls to self._quote here handles non-StringType values.
+ if not self.unrepr:
+ val = self._decode_element(self._quote(this_entry))
+ else:
+ val = repr(this_entry)
+ return '%s%s%s%s%s' % (indent_string,
+ self._decode_element(self._quote(entry, multiline=False)),
+ self._a_to_u(' = '),
+ val,
+ self._decode_element(comment))
+
+
+ def _write_marker(self, indent_string, depth, entry, comment):
+ """Write a section marker line"""
+ return '%s%s%s%s%s' % (indent_string,
+ self._a_to_u('[' * depth),
+ self._quote(self._decode_element(entry), multiline=False),
+ self._a_to_u(']' * depth),
+ self._decode_element(comment))
+
+
+ def _handle_comment(self, comment):
+ """Deal with a comment."""
+ if not comment:
+ return ''
+ start = self.indent_type
+ if not comment.startswith('#'):
+ start += self._a_to_u(' # ')
+ return (start + comment)
+
+
+ # Public methods
+
+ def write(self, outfile=None, section=None):
+ """
+ Write the current ConfigObj as a file
+
+ tekNico: FIXME: use StringIO instead of real files
+
+ >>> filename = a.filename
+ >>> a.filename = 'test.ini'
+ >>> a.write()
+ >>> a.filename = filename
+ >>> a == ConfigObj('test.ini', raise_errors=True)
+ 1
+ """
+ if self.indent_type is None:
+ # this can be true if initialised from a dictionary
+ self.indent_type = DEFAULT_INDENT_TYPE
+
+ out = []
+ cs = self._a_to_u('#')
+ csp = self._a_to_u('# ')
+ if section is None:
+ int_val = self.interpolation
+ self.interpolation = False
+ section = self
+ for line in self.initial_comment:
+ line = self._decode_element(line)
+ stripped_line = line.strip()
+ if stripped_line and not stripped_line.startswith(cs):
+ line = csp + line
+ out.append(line)
+
+ indent_string = self.indent_type * section.depth
+ for entry in (section.scalars + section.sections):
+ if entry in section.defaults:
+ # don't write out default values
+ continue
+ for comment_line in section.comments[entry]:
+ comment_line = self._decode_element(comment_line.lstrip())
+ if comment_line and not comment_line.startswith(cs):
+ comment_line = csp + comment_line
+ out.append(indent_string + comment_line)
+ this_entry = section[entry]
+ comment = self._handle_comment(section.inline_comments[entry])
+
+ if isinstance(this_entry, dict):
+ # a section
+ out.append(self._write_marker(
+ indent_string,
+ this_entry.depth,
+ entry,
+ comment))
+ out.extend(self.write(section=this_entry))
+ else:
+ out.append(self._write_line(
+ indent_string,
+ entry,
+ this_entry,
+ comment))
+
+ if section is self:
+ for line in self.final_comment:
+ line = self._decode_element(line)
+ stripped_line = line.strip()
+ if stripped_line and not stripped_line.startswith(cs):
+ line = csp + line
+ out.append(line)
+ self.interpolation = int_val
+
+ if section is not self:
+ return out
+
+ if (self.filename is None) and (outfile is None):
+ # output a list of lines
+ # might need to encode
+ # NOTE: This will *screw* UTF16, each line will start with the BOM
+ if self.encoding:
+ out = [l.encode(self.encoding) for l in out]
+ if (self.BOM and ((self.encoding is None) or
+ (BOM_LIST.get(self.encoding.lower()) == 'utf_8'))):
+ # Add the UTF8 BOM
+ if not out:
+ out.append('')
+ out[0] = BOM_UTF8 + out[0]
+ return out
+
+ # Turn the list to a string, joined with correct newlines
+ newline = self.newlines or os.linesep
+ output = self._a_to_u(newline).join(out)
+ if self.encoding:
+ output = output.encode(self.encoding)
+ if self.BOM and ((self.encoding is None) or match_utf8(self.encoding)):
+ # Add the UTF8 BOM
+ output = BOM_UTF8 + output
+
+ if not output.endswith(newline):
+ output += newline
+ if outfile is not None:
+ outfile.write(output)
+ else:
+ h = open(self.filename, 'wb')
+ h.write(output)
+ h.close()
+
+
+ def validate(self, validator, preserve_errors=False, copy=False,
+ section=None):
+ """
+ Test the ConfigObj against a configspec.
+
+ It uses the ``validator`` object from *validate.py*.
+
+ To run ``validate`` on the current ConfigObj, call: ::
+
+ test = config.validate(validator)
+
+ (Normally having previously passed in the configspec when the ConfigObj
+ was created - you can dynamically assign a dictionary of checks to the
+ ``configspec`` attribute of a section though).
+
+ It returns ``True`` if everything passes, or a dictionary of
+ pass/fails (True/False). If every member of a subsection passes, it
+ will just have the value ``True``. (It also returns ``False`` if all
+ members fail).
+
+ In addition, it converts the values from strings to their native
+ types if their checks pass (and ``stringify`` is set).
+
+ If ``preserve_errors`` is ``True`` (``False`` is default) then instead
+ of a marking a fail with a ``False``, it will preserve the actual
+ exception object. This can contain info about the reason for failure.
+ For example the ``VdtValueTooSmallError`` indicates that the value
+ supplied was too small. If a value (or section) is missing it will
+ still be marked as ``False``.
+
+ You must have the validate module to use ``preserve_errors=True``.
+
+ You can then use the ``flatten_errors`` function to turn your nested
+ results dictionary into a flattened list of failures - useful for
+ displaying meaningful error messages.
+ """
+ if section is None:
+ if self.configspec is None:
+ raise ValueError('No configspec supplied.')
+ if preserve_errors:
+ # We do this once to remove a top level dependency on the validate module
+ # Which makes importing configobj faster
+ from validate import VdtMissingValue
+ self._vdtMissingValue = VdtMissingValue
+ section = self
+ #
+ spec_section = section.configspec
+ if copy and hasattr(section, '_configspec_initial_comment'):
+ section.initial_comment = section._configspec_initial_comment
+ section.final_comment = section._configspec_final_comment
+ section.encoding = section._configspec_encoding
+ section.BOM = section._configspec_BOM
+ section.newlines = section._configspec_newlines
+ section.indent_type = section._configspec_indent_type
+
+ if '__many__' in section.configspec:
+ many = spec_section['__many__']
+ # dynamically assign the configspecs
+ # for the sections below
+ for entry in section.sections:
+ self._handle_repeat(section[entry], many)
+ #
+ out = {}
+ ret_true = True
+ ret_false = True
+ order = [k for k in section._order if k in spec_section]
+ order += [k for k in spec_section if k not in order]
+ for entry in order:
+ if entry == '__many__':
+ continue
+ if (not entry in section.scalars) or (entry in section.defaults):
+ # missing entries
+ # or entries from defaults
+ missing = True
+ val = None
+ if copy and not entry in section.scalars:
+ # copy comments
+ section.comments[entry] = (
+ section._configspec_comments.get(entry, []))
+ section.inline_comments[entry] = (
+ section._configspec_inline_comments.get(entry, ''))
+ #
+ else:
+ missing = False
+ val = section[entry]
+ try:
+ check = validator.check(spec_section[entry],
+ val,
+ missing=missing
+ )
+ except validator.baseErrorClass, e:
+ if not preserve_errors or isinstance(e, self._vdtMissingValue):
+ out[entry] = False
+ else:
+ # preserve the error
+ out[entry] = e
+ ret_false = False
+ ret_true = False
+ else:
+ try:
+ section.default_values.pop(entry, None)
+ except AttributeError:
+ # For Python 2.2 compatibility
+ try:
+ del section.default_values[entry]
+ except KeyError:
+ pass
+
+ if hasattr(validator, 'get_default_value'):
+ try:
+ section.default_values[entry] = validator.get_default_value(spec_section[entry])
+ except KeyError:
+ # No default
+ pass
+
+ ret_false = False
+ out[entry] = True
+ if self.stringify or missing:
+ # if we are doing type conversion
+ # or the value is a supplied default
+ if not self.stringify:
+ if isinstance(check, (list, tuple)):
+ # preserve lists
+ check = [self._str(item) for item in check]
+ elif missing and check is None:
+ # convert the None from a default to a ''
+ check = ''
+ else:
+ check = self._str(check)
+ if (check != val) or missing:
+ section[entry] = check
+ if not copy and missing and entry not in section.defaults:
+ section.defaults.append(entry)
+ # Missing sections will have been created as empty ones when the
+ # configspec was read.
+ for entry in section.sections:
+ # FIXME: this means DEFAULT is not copied in copy mode
+ if section is self and entry == 'DEFAULT':
+ continue
+ if copy:
+ section.comments[entry] = section._cs_section_comments[entry]
+ section.inline_comments[entry] = (
+ section._cs_section_inline_comments[entry])
+ check = self.validate(validator, preserve_errors=preserve_errors,
+ copy=copy, section=section[entry])
+ out[entry] = check
+ if check == False:
+ ret_true = False
+ elif check == True:
+ ret_false = False
+ else:
+ ret_true = False
+ ret_false = False
+ #
+ if ret_true:
+ return True
+ elif ret_false:
+ return False
+ return out
+
+
+ def reset(self):
+ """Clear ConfigObj instance and restore to 'freshly created' state."""
+ self.clear()
+ self._initialise()
+ # FIXME: Should be done by '_initialise', but ConfigObj constructor (and reload)
+ # requires an empty dictionary
+ self.configspec = None
+ # Just to be sure ;-)
+ self._original_configspec = None
+
+
+ def reload(self):
+ """
+ Reload a ConfigObj from file.
+
+ This method raises a ``ReloadError`` if the ConfigObj doesn't have
+ a filename attribute pointing to a file.
+ """
+ if not isinstance(self.filename, StringTypes):
+ raise ReloadError()
+
+ filename = self.filename
+ current_options = {}
+ for entry in OPTION_DEFAULTS:
+ if entry == 'configspec':
+ continue
+ current_options[entry] = getattr(self, entry)
+
+ configspec = self._original_configspec
+ current_options['configspec'] = configspec
+
+ self.clear()
+ self._initialise(current_options)
+ self._load(filename, configspec)
+
+
+
+class SimpleVal(object):
+ """
+ A simple validator.
+ Can be used to check that all members expected are present.
+
+ To use it, provide a configspec with all your members in (the value given
+ will be ignored). Pass an instance of ``SimpleVal`` to the ``validate``
+ method of your ``ConfigObj``. ``validate`` will return ``True`` if all
+ members are present, or a dictionary with True/False meaning
+ present/missing. (Whole missing sections will be replaced with ``False``)
+ """
+
+ def __init__(self):
+ self.baseErrorClass = ConfigObjError
+
+ def check(self, check, member, missing=False):
+ """A dummy check method, always returns the value unchanged."""
+ if missing:
+ raise self.baseErrorClass()
+ return member
+
+
+# Check / processing functions for options
+def flatten_errors(cfg, res, levels=None, results=None):
+ """
+ An example function that will turn a nested dictionary of results
+ (as returned by ``ConfigObj.validate``) into a flat list.
+
+ ``cfg`` is the ConfigObj instance being checked, ``res`` is the results
+ dictionary returned by ``validate``.
+
+ (This is a recursive function, so you shouldn't use the ``levels`` or
+ ``results`` arguments - they are used by the function.
+
+ Returns a list of keys that failed. Each member of the list is a tuple :
+ ::
+
+ ([list of sections...], key, result)
+
+ If ``validate`` was called with ``preserve_errors=False`` (the default)
+ then ``result`` will always be ``False``.
+
+ *list of sections* is a flattened list of sections that the key was found
+ in.
+
+ If the section was missing then key will be ``None``.
+
+ If the value (or section) was missing then ``result`` will be ``False``.
+
+ If ``validate`` was called with ``preserve_errors=True`` and a value
+ was present, but failed the check, then ``result`` will be the exception
+ object returned. You can use this as a string that describes the failure.
+
+ For example *The value "3" is of the wrong type*.
+
+ >>> import validate
+ >>> vtor = validate.Validator()
+ >>> my_ini = '''
+ ... option1 = True
+ ... [section1]
+ ... option1 = True
+ ... [section2]
+ ... another_option = Probably
+ ... [section3]
+ ... another_option = True
+ ... [[section3b]]
+ ... value = 3
+ ... value2 = a
+ ... value3 = 11
+ ... '''
+ >>> my_cfg = '''
+ ... option1 = boolean()
+ ... option2 = boolean()
+ ... option3 = boolean(default=Bad_value)
+ ... [section1]
+ ... option1 = boolean()
+ ... option2 = boolean()
+ ... option3 = boolean(default=Bad_value)
+ ... [section2]
+ ... another_option = boolean()
+ ... [section3]
+ ... another_option = boolean()
+ ... [[section3b]]
+ ... value = integer
+ ... value2 = integer
+ ... value3 = integer(0, 10)
+ ... [[[section3b-sub]]]
+ ... value = string
+ ... [section4]
+ ... another_option = boolean()
+ ... '''
+ >>> cs = my_cfg.split('\\n')
+ >>> ini = my_ini.split('\\n')
+ >>> cfg = ConfigObj(ini, configspec=cs)
+ >>> res = cfg.validate(vtor, preserve_errors=True)
+ >>> errors = []
+ >>> for entry in flatten_errors(cfg, res):
+ ... section_list, key, error = entry
+ ... section_list.insert(0, '[root]')
+ ... if key is not None:
+ ... section_list.append(key)
+ ... else:
+ ... section_list.append('[missing]')
+ ... section_string = ', '.join(section_list)
+ ... errors.append((section_string, ' = ', error))
+ >>> errors.sort()
+ >>> for entry in errors:
+ ... print entry[0], entry[1], (entry[2] or 0)
+ [root], option2 = 0
+ [root], option3 = the value "Bad_value" is of the wrong type.
+ [root], section1, option2 = 0
+ [root], section1, option3 = the value "Bad_value" is of the wrong type.
+ [root], section2, another_option = the value "Probably" is of the wrong type.
+ [root], section3, section3b, section3b-sub, [missing] = 0
+ [root], section3, section3b, value2 = the value "a" is of the wrong type.
+ [root], section3, section3b, value3 = the value "11" is too big.
+ [root], section4, [missing] = 0
+ """
+ if levels is None:
+ # first time called
+ levels = []
+ results = []
+ if res is True:
+ return results
+ if res is False:
+ results.append((levels[:], None, False))
+ if levels:
+ levels.pop()
+ return results
+ for (key, val) in res.items():
+ if val == True:
+ continue
+ if isinstance(cfg.get(key), dict):
+ # Go down one level
+ levels.append(key)
+ flatten_errors(cfg[key], val, levels, results)
+ continue
+ results.append((levels[:], key, val))
+ #
+ # Go up one level
+ if levels:
+ levels.pop()
+ #
+ return results
+
+
+"""*A programming language is a medium of expression.* - Paul Graham"""
diff --git a/IPython/external/guid.py b/IPython/external/guid.py
new file mode 100644
index 0000000..da1a226
--- /dev/null
+++ b/IPython/external/guid.py
@@ -0,0 +1,170 @@
+#!/usr/bin/env python
+# encoding: utf-8
+
+# GUID.py
+# Version 2.6
+#
+# Copyright (c) 2006 Conan C. Albrecht
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is furnished
+# to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+# FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+# DEALINGS IN THE SOFTWARE.
+
+
+
+##################################################################################################
+### A globally-unique identifier made up of time and ip and 8 digits for a counter:
+### each GUID is 40 characters wide
+###
+### A globally unique identifier that combines ip, time, and a counter. Since the
+### time is listed first, you can sort records by guid. You can also extract the time
+### and ip if needed.
+###
+### Since the counter has eight hex characters, you can create up to
+### 0xffffffff (4294967295) GUIDs every millisecond. If your processor
+### is somehow fast enough to create more than that in a millisecond (looking
+### toward the future, of course), the function will wait until the next
+### millisecond to return.
+###
+### GUIDs make wonderful database keys. They require no access to the
+### database (to get the max index number), they are extremely unique, and they sort
+### automatically by time. GUIDs prevent key clashes when merging
+### two databases together, combining data, or generating keys in distributed
+### systems.
+###
+### There is an Internet Draft for UUIDs, but this module does not implement it.
+### If the draft catches on, perhaps I'll conform the module to it.
+###
+
+
+# Changelog
+# Sometime, 1997 Created the Java version of GUID
+# Went through many versions in Java
+# Sometime, 2002 Created the Python version of GUID, mirroring the Java version
+# November 24, 2003 Changed Python version to be more pythonic, took out object and made just a module
+# December 2, 2003 Fixed duplicating GUIDs. Sometimes they duplicate if multiples are created
+# in the same millisecond (it checks the last 100 GUIDs now and has a larger random part)
+# December 9, 2003 Fixed MAX_RANDOM, which was going over sys.maxint
+# June 12, 2004 Allowed a custom IP address to be sent in rather than always using the
+# local IP address.
+# November 4, 2005 Changed the random part to a counter variable. Now GUIDs are totally
+# unique and more efficient, as long as they are created by only
+# on runtime on a given machine. The counter part is after the time
+# part so it sorts correctly.
+# November 8, 2005 The counter variable now starts at a random long now and cycles
+# around. This is in case two guids are created on the same
+# machine at the same millisecond (by different processes). Even though
+# it is possible the GUID can be created, this makes it highly unlikely
+# since the counter will likely be different.
+# November 11, 2005 Fixed a bug in the new IP getting algorithm. Also, use IPv6 range
+# for IP when we make it up (when it's no accessible)
+# November 21, 2005 Added better IP-finding code. It finds IP address better now.
+# January 5, 2006 Fixed a small bug caused in old versions of python (random module use)
+
+import math
+import socket
+import random
+import sys
+import time
+import threading
+
+
+
+#############################
+### global module variables
+
+#Makes a hex IP from a decimal dot-separated ip (eg: 127.0.0.1)
+make_hexip = lambda ip: ''.join(["%04x" % long(i) for i in ip.split('.')]) # leave space for ip v6 (65K in each sub)
+
+MAX_COUNTER = 0xfffffffe
+counter = 0L
+firstcounter = MAX_COUNTER
+lasttime = 0
+ip = ''
+lock = threading.RLock()
+try: # only need to get the IP addresss once
+ ip = socket.getaddrinfo(socket.gethostname(),0)[-1][-1][0]
+ hexip = make_hexip(ip)
+except: # if we don't have an ip, default to someting in the 10.x.x.x private range
+ ip = '10'
+ rand = random.Random()
+ for i in range(3):
+ ip += '.' + str(rand.randrange(1, 0xffff)) # might as well use IPv6 range if we're making it up
+ hexip = make_hexip(ip)
+
+
+#################################
+### Public module functions
+
+def generate(ip=None):
+ '''Generates a new guid. A guid is unique in space and time because it combines
+ the machine IP with the current time in milliseconds. Be careful about sending in
+ a specified IP address because the ip makes it unique in space. You could send in
+ the same IP address that is created on another machine.
+ '''
+ global counter, firstcounter, lasttime
+ lock.acquire() # can't generate two guids at the same time
+ try:
+ parts = []
+
+ # do we need to wait for the next millisecond (are we out of counters?)
+ now = long(time.time() * 1000)
+ while lasttime == now and counter == firstcounter:
+ time.sleep(.01)
+ now = long(time.time() * 1000)
+
+ # time part
+ parts.append("%016x" % now)
+
+ # counter part
+ if lasttime != now: # time to start counter over since we have a different millisecond
+ firstcounter = long(random.uniform(1, MAX_COUNTER)) # start at random position
+ counter = firstcounter
+ counter += 1
+ if counter > MAX_COUNTER:
+ counter = 0
+ lasttime = now
+ parts.append("%08x" % (counter))
+
+ # ip part
+ parts.append(hexip)
+
+ # put them all together
+ return ''.join(parts)
+ finally:
+ lock.release()
+
+
+def extract_time(guid):
+ '''Extracts the time portion out of the guid and returns the
+ number of seconds since the epoch as a float'''
+ return float(long(guid[0:16], 16)) / 1000.0
+
+
+def extract_counter(guid):
+ '''Extracts the counter from the guid (returns the bits in decimal)'''
+ return int(guid[16:24], 16)
+
+
+def extract_ip(guid):
+ '''Extracts the ip portion out of the guid and returns it
+ as a string like 10.10.10.10'''
+ # there's probably a more elegant way to do this
+ thisip = []
+ for index in range(24, 40, 4):
+ thisip.append(str(int(guid[index: index + 4], 16)))
+ return '.'.join(thisip)
+
diff --git a/IPython/external/mglob.py b/IPython/external/mglob.py
new file mode 100755
index 0000000..ed3679f
--- /dev/null
+++ b/IPython/external/mglob.py
@@ -0,0 +1,229 @@
+#!/usr/bin/env python
+
+r""" mglob - enhanced file list expansion module
+
+Use as stand-alone utility (for xargs, `backticks` etc.),
+or a globbing library for own python programs. Globbing the sys.argv is something
+that almost every Windows script has to perform manually, and this module is here
+to help with that task. Also Unix users will benefit from enhanced modes
+such as recursion, exclusion, directory omission...
+
+Unlike glob.glob, directories are not included in the glob unless specified
+with 'dir:'
+
+'expand' is the function to use in python programs. Typical use
+to expand argv (esp. in windows)::
+
+ try:
+ import mglob
+ files = mglob.expand(sys.argv[1:])
+ except ImportError:
+ print "mglob not found; try 'easy_install mglob' for extra features"
+ files = sys.argv[1:]
+
+Note that for unix, shell expands *normal* wildcards (*.cpp, etc.) in argv.
+Therefore, you might want to use quotes with normal wildcards to prevent this
+expansion, in order for mglob to see the wildcards and get the wanted behaviour.
+Not quoting the wildcards is harmless and typically has equivalent results, though.
+
+Author: Ville Vainio <vivainio@gmail.com>
+License: MIT Open Source license
+
+"""
+
+#Assigned in variable for "usage" printing convenience"
+
+globsyntax = """\
+ This program allows specifying filenames with "mglob" mechanism.
+ Supported syntax in globs (wilcard matching patterns)::
+
+ *.cpp ?ellowo*
+ - obvious. Differs from normal glob in that dirs are not included.
+ Unix users might want to write this as: "*.cpp" "?ellowo*"
+ rec:/usr/share=*.txt,*.doc
+ - get all *.txt and *.doc under /usr/share,
+ recursively
+ rec:/usr/share
+ - All files under /usr/share, recursively
+ rec:*.py
+ - All .py files under current working dir, recursively
+ foo
+ - File or dir foo
+ !*.bak readme*
+ - readme*, exclude files ending with .bak
+ !.svn/ !.hg/ !*_Data/ rec:.
+ - Skip .svn, .hg, foo_Data dirs (and their subdirs) in recurse.
+ Trailing / is the key, \ does not work! Use !.*/ for all hidden.
+ dir:foo
+ - the directory foo if it exists (not files in foo)
+ dir:*
+ - all directories in current folder
+ foo.py bar.* !h* rec:*.py
+ - Obvious. !h* exclusion only applies for rec:*.py.
+ foo.py is *not* included twice.
+ @filelist.txt
+ - All files listed in 'filelist.txt' file, on separate lines.
+ "cont:class \wak:" rec:*.py
+ - Match files containing regexp. Applies to subsequent files.
+ note quotes because of whitespace.
+ """
+
+
+__version__ = "0.2"
+
+
+import os,glob,fnmatch,sys,re
+
+def expand(flist,exp_dirs = False):
+ """ Expand the glob(s) in flist.
+
+ flist may be either a whitespace-separated list of globs/files
+ or an array of globs/files.
+
+ if exp_dirs is true, directory names in glob are expanded to the files
+ contained in them - otherwise, directory names are returned as is.
+
+ """
+ if isinstance(flist, basestring):
+ import shlex
+ flist = shlex.split(flist)
+ done_set = set()
+ denied_set = set()
+ cont_set = set()
+ cur_rejected_dirs = set()
+
+ def recfind(p, pats = ["*"]):
+ denied_dirs = [os.path.dirname(d) for d in denied_set if d.endswith("/")]
+ for (dp,dnames,fnames) in os.walk(p):
+ # see if we should ignore the whole directory
+ dp_norm = dp.replace("\\","/") + "/"
+ deny = False
+ # do not traverse under already rejected dirs
+ for d in cur_rejected_dirs:
+ if dp.startswith(d):
+ deny = True
+ break
+ if deny:
+ continue
+
+
+ #print "dp",dp
+ bname = os.path.basename(dp)
+ for deny_pat in denied_dirs:
+ if fnmatch.fnmatch( bname, deny_pat):
+ deny = True
+ cur_rejected_dirs.add(dp)
+ break
+ if deny:
+ continue
+
+
+ for f in fnames:
+ matched = False
+ for p in pats:
+ if fnmatch.fnmatch(f,p):
+ matched = True
+ break
+ if matched:
+ yield os.path.join(dp,f)
+
+ def once_filter(seq):
+ for it in seq:
+ p = os.path.abspath(it)
+ if p in done_set:
+ continue
+ done_set.add(p)
+ deny = False
+ for deny_pat in denied_set:
+ if fnmatch.fnmatch(os.path.basename(p), deny_pat):
+ deny = True
+ break
+ if cont_set:
+ try:
+ cont = open(p).read()
+ except IOError:
+ # deny
+ continue
+ for pat in cont_set:
+ if not re.search(pat,cont, re.IGNORECASE):
+ deny = True
+ break
+
+ if not deny:
+ yield it
+ return
+
+ res = []
+
+ for ent in flist:
+ ent = os.path.expanduser(os.path.expandvars(ent))
+ if ent.lower().startswith('rec:'):
+ fields = ent[4:].split('=')
+ if len(fields) == 2:
+ pth, patlist = fields
+ elif len(fields) == 1:
+ if os.path.isdir(fields[0]):
+ # single arg is dir
+ pth, patlist = fields[0], '*'
+ else:
+ # single arg is pattern
+ pth, patlist = '.', fields[0]
+
+ elif len(fields) == 0:
+ pth, pathlist = '.','*'
+
+ pats = patlist.split(',')
+ res.extend(once_filter(recfind(pth, pats)))
+ # filelist
+ elif ent.startswith('@') and os.path.isfile(ent[1:]):
+ res.extend(once_filter(open(ent[1:]).read().splitlines()))
+ # exclusion
+ elif ent.startswith('!'):
+ denied_set.add(ent[1:])
+ # glob only dirs
+ elif ent.lower().startswith('dir:'):
+ res.extend(once_filter(filter(os.path.isdir,glob.glob(ent[4:]))))
+ elif ent.lower().startswith('cont:'):
+ cont_set.add(ent[5:])
+ # get all files in the specified dir
+ elif os.path.isdir(ent) and exp_dirs:
+ res.extend(once_filter(filter(os.path.isfile,glob.glob(ent + os.sep+"*"))))
+
+ # glob only files
+
+ elif '*' in ent or '?' in ent:
+ res.extend(once_filter(filter(os.path.isfile,glob.glob(ent))))
+
+ else:
+ res.extend(once_filter([ent]))
+ return res
+
+
+def test():
+ assert (
+ expand("*.py ~/.ipython/*.py rec:/usr/share/doc-base") ==
+ expand( ['*.py', '~/.ipython/*.py', 'rec:/usr/share/doc-base'] )
+ )
+
+def main():
+ if len(sys.argv) < 2:
+ print globsyntax
+ return
+
+ print "\n".join(expand(sys.argv[1:])),
+
+def mglob_f(self, arg):
+ from IPython.genutils import SList
+ if arg.strip():
+ return SList(expand(arg))
+ print "Please specify pattern!"
+ print globsyntax
+
+def init_ipython(ip):
+ """ register %mglob for IPython """
+ mglob_f.__doc__ = globsyntax
+ ip.expose_magic("mglob",mglob_f)
+
+# test()
+if __name__ == "__main__":
+ main()
diff --git a/IPython/external/path.py b/IPython/external/path.py
new file mode 100644
index 0000000..6b0f952
--- /dev/null
+++ b/IPython/external/path.py
@@ -0,0 +1,973 @@
+""" path.py - An object representing a path to a file or directory.
+
+Example:
+
+from IPython.external.path import path
+d = path('/home/guido/bin')
+for f in d.files('*.py'):
+ f.chmod(0755)
+
+This module requires Python 2.2 or later.
+
+
+URL: http://www.jorendorff.com/articles/python/path
+Author: Jason Orendorff <jason.orendorff\x40gmail\x2ecom> (and others - see the url!)
+Date: 9 Mar 2007
+"""
+
+
+# TODO
+# - Tree-walking functions don't avoid symlink loops. Matt Harrison
+# sent me a patch for this.
+# - Bug in write_text(). It doesn't support Universal newline mode.
+# - Better error message in listdir() when self isn't a
+# directory. (On Windows, the error message really sucks.)
+# - Make sure everything has a good docstring.
+# - Add methods for regex find and replace.
+# - guess_content_type() method?
+# - Perhaps support arguments to touch().
+
+from __future__ import generators
+
+import sys, warnings, os, fnmatch, glob, shutil, codecs
+# deprecated in python 2.6
+warnings.filterwarnings('ignore', r'.*md5.*')
+import md5
+
+__version__ = '2.2'
+__all__ = ['path']
+
+# Platform-specific support for path.owner
+if os.name == 'nt':
+ try:
+ import win32security
+ except ImportError:
+ win32security = None
+else:
+ try:
+ import pwd
+ except ImportError:
+ pwd = None
+
+# Pre-2.3 support. Are unicode filenames supported?
+_base = str
+_getcwd = os.getcwd
+try:
+ if os.path.supports_unicode_filenames:
+ _base = unicode
+ _getcwd = os.getcwdu
+except AttributeError:
+ pass
+
+# Pre-2.3 workaround for booleans
+try:
+ True, False
+except NameError:
+ True, False = 1, 0
+
+# Pre-2.3 workaround for basestring.
+try:
+ basestring
+except NameError:
+ basestring = (str, unicode)
+
+# Universal newline support
+_textmode = 'r'
+if hasattr(file, 'newlines'):
+ _textmode = 'U'
+
+
+class TreeWalkWarning(Warning):
+ pass
+
+class path(_base):
+ """ Represents a filesystem path.
+
+ For documentation on individual methods, consult their
+ counterparts in os.path.
+ """
+
+ # --- Special Python methods.
+
+ def __repr__(self):
+ return 'path(%s)' % _base.__repr__(self)
+
+ # Adding a path and a string yields a path.
+ def __add__(self, more):
+ try:
+ resultStr = _base.__add__(self, more)
+ except TypeError: #Python bug
+ resultStr = NotImplemented
+ if resultStr is NotImplemented:
+ return resultStr
+ return self.__class__(resultStr)
+
+ def __radd__(self, other):
+ if isinstance(other, basestring):
+ return self.__class__(other.__add__(self))
+ else:
+ return NotImplemented
+
+ # The / operator joins paths.
+ def __div__(self, rel):
+ """ fp.__div__(rel) == fp / rel == fp.joinpath(rel)
+
+ Join two path components, adding a separator character if
+ needed.
+ """
+ return self.__class__(os.path.join(self, rel))
+
+ # Make the / operator work even when true division is enabled.
+ __truediv__ = __div__
+
+ def getcwd(cls):
+ """ Return the current working directory as a path object. """
+ return cls(_getcwd())
+ getcwd = classmethod(getcwd)
+
+
+ # --- Operations on path strings.
+
+ isabs = os.path.isabs
+ def abspath(self): return self.__class__(os.path.abspath(self))
+ def normcase(self): return self.__class__(os.path.normcase(self))
+ def normpath(self): return self.__class__(os.path.normpath(self))
+ def realpath(self): return self.__class__(os.path.realpath(self))
+ def expanduser(self): return self.__class__(os.path.expanduser(self))
+ def expandvars(self): return self.__class__(os.path.expandvars(self))
+ def dirname(self): return self.__class__(os.path.dirname(self))
+ basename = os.path.basename
+
+ def expand(self):
+ """ Clean up a filename by calling expandvars(),
+ expanduser(), and normpath() on it.
+
+ This is commonly everything needed to clean up a filename
+ read from a configuration file, for example.
+ """
+ return self.expandvars().expanduser().normpath()
+
+ def _get_namebase(self):
+ base, ext = os.path.splitext(self.name)
+ return base
+
+ def _get_ext(self):
+ f, ext = os.path.splitext(_base(self))
+ return ext
+
+ def _get_drive(self):
+ drive, r = os.path.splitdrive(self)
+ return self.__class__(drive)
+
+ parent = property(
+ dirname, None, None,
+ """ This path's parent directory, as a new path object.
+
+ For example, path('/usr/local/lib/libpython.so').parent == path('/usr/local/lib')
+ """)
+
+ name = property(
+ basename, None, None,
+ """ The name of this file or directory without the full path.
+
+ For example, path('/usr/local/lib/libpython.so').name == 'libpython.so'
+ """)
+
+ namebase = property(
+ _get_namebase, None, None,
+ """ The same as path.name, but with one file extension stripped off.
+
+ For example, path('/home/guido/python.tar.gz').name == 'python.tar.gz',
+ but path('/home/guido/python.tar.gz').namebase == 'python.tar'
+ """)
+
+ ext = property(
+ _get_ext, None, None,
+ """ The file extension, for example '.py'. """)
+
+ drive = property(
+ _get_drive, None, None,
+ """ The drive specifier, for example 'C:'.
+ This is always empty on systems that don't use drive specifiers.
+ """)
+
+ def splitpath(self):
+ """ p.splitpath() -> Return (p.parent, p.name). """
+ parent, child = os.path.split(self)
+ return self.__class__(parent), child
+
+ def splitdrive(self):
+ """ p.splitdrive() -> Return (p.drive, <the rest of p>).
+
+ Split the drive specifier from this path. If there is
+ no drive specifier, p.drive is empty, so the return value
+ is simply (path(''), p). This is always the case on Unix.
+ """
+ drive, rel = os.path.splitdrive(self)
+ return self.__class__(drive), rel
+
+ def splitext(self):
+ """ p.splitext() -> Return (p.stripext(), p.ext).
+
+ Split the filename extension from this path and return
+ the two parts. Either part may be empty.
+
+ The extension is everything from '.' to the end of the
+ last path segment. This has the property that if
+ (a, b) == p.splitext(), then a + b == p.
+ """
+ filename, ext = os.path.splitext(self)
+ return self.__class__(filename), ext
+
+ def stripext(self):
+ """ p.stripext() -> Remove one file extension from the path.
+
+ For example, path('/home/guido/python.tar.gz').stripext()
+ returns path('/home/guido/python.tar').
+ """
+ return self.splitext()[0]
+
+ if hasattr(os.path, 'splitunc'):
+ def splitunc(self):
+ unc, rest = os.path.splitunc(self)
+ return self.__class__(unc), rest
+
+ def _get_uncshare(self):
+ unc, r = os.path.splitunc(self)
+ return self.__class__(unc)
+
+ uncshare = property(
+ _get_uncshare, None, None,
+ """ The UNC mount point for this path.
+ This is empty for paths on local drives. """)
+
+ def joinpath(self, *args):
+ """ Join two or more path components, adding a separator
+ character (os.sep) if needed. Returns a new path
+ object.
+ """
+ return self.__class__(os.path.join(self, *args))
+
+ def splitall(self):
+ r""" Return a list of the path components in this path.
+
+ The first item in the list will be a path. Its value will be
+ either os.curdir, os.pardir, empty, or the root directory of
+ this path (for example, '/' or 'C:\\'). The other items in
+ the list will be strings.
+
+ path.path.joinpath(*result) will yield the original path.
+ """
+ parts = []
+ loc = self
+ while loc != os.curdir and loc != os.pardir:
+ prev = loc
+ loc, child = prev.splitpath()
+ if loc == prev:
+ break
+ parts.append(child)
+ parts.append(loc)
+ parts.reverse()
+ return parts
+
+ def relpath(self):
+ """ Return this path as a relative path,
+ based from the current working directory.
+ """
+ cwd = self.__class__(os.getcwd())
+ return cwd.relpathto(self)
+
+ def relpathto(self, dest):
+ """ Return a relative path from self to dest.
+
+ If there is no relative path from self to dest, for example if
+ they reside on different drives in Windows, then this returns
+ dest.abspath().
+ """
+ origin = self.abspath()
+ dest = self.__class__(dest).abspath()
+
+ orig_list = origin.normcase().splitall()
+ # Don't normcase dest! We want to preserve the case.
+ dest_list = dest.splitall()
+
+ if orig_list[0] != os.path.normcase(dest_list[0]):
+ # Can't get here from there.
+ return dest
+
+ # Find the location where the two paths start to differ.
+ i = 0
+ for start_seg, dest_seg in zip(orig_list, dest_list):
+ if start_seg != os.path.normcase(dest_seg):
+ break
+ i += 1
+
+ # Now i is the point where the two paths diverge.
+ # Need a certain number of "os.pardir"s to work up
+ # from the origin to the point of divergence.
+ segments = [os.pardir] * (len(orig_list) - i)
+ # Need to add the diverging part of dest_list.
+ segments += dest_list[i:]
+ if len(segments) == 0:
+ # If they happen to be identical, use os.curdir.
+ relpath = os.curdir
+ else:
+ relpath = os.path.join(*segments)
+ return self.__class__(relpath)
+
+ # --- Listing, searching, walking, and matching
+
+ def listdir(self, pattern=None):
+ """ D.listdir() -> List of items in this directory.
+
+ Use D.files() or D.dirs() instead if you want a listing
+ of just files or just subdirectories.
+
+ The elements of the list are path objects.
+
+ With the optional 'pattern' argument, this only lists
+ items whose names match the given pattern.
+ """
+ names = os.listdir(self)
+ if pattern is not None:
+ names = fnmatch.filter(names, pattern)
+ return [self / child for child in names]
+
+ def dirs(self, pattern=None):
+ """ D.dirs() -> List of this directory's subdirectories.
+
+ The elements of the list are path objects.
+ This does not walk recursively into subdirectories
+ (but see path.walkdirs).
+
+ With the optional 'pattern' argument, this only lists
+ directories whose names match the given pattern. For
+ example, d.dirs('build-*').
+ """
+ return [p for p in self.listdir(pattern) if p.isdir()]
+
+ def files(self, pattern=None):
+ """ D.files() -> List of the files in this directory.
+
+ The elements of the list are path objects.
+ This does not walk into subdirectories (see path.walkfiles).
+
+ With the optional 'pattern' argument, this only lists files
+ whose names match the given pattern. For example,
+ d.files('*.pyc').
+ """
+
+ return [p for p in self.listdir(pattern) if p.isfile()]
+
+ def walk(self, pattern=None, errors='strict'):
+ """ D.walk() -> iterator over files and subdirs, recursively.
+
+ The iterator yields path objects naming each child item of
+ this directory and its descendants. This requires that
+ D.isdir().
+
+ This performs a depth-first traversal of the directory tree.
+ Each directory is returned just before all its children.
+
+ The errors= keyword argument controls behavior when an
+ error occurs. The default is 'strict', which causes an
+ exception. The other allowed values are 'warn', which
+ reports the error via warnings.warn(), and 'ignore'.
+ """
+ if errors not in ('strict', 'warn', 'ignore'):
+ raise ValueError("invalid errors parameter")
+
+ try:
+ childList = self.listdir()
+ except Exception:
+ if errors == 'ignore':
+ return
+ elif errors == 'warn':
+ warnings.warn(
+ "Unable to list directory '%s': %s"
+ % (self, sys.exc_info()[1]),
+ TreeWalkWarning)
+ return
+ else:
+ raise
+
+ for child in childList:
+ if pattern is None or child.fnmatch(pattern):
+ yield child
+ try:
+ isdir = child.isdir()
+ except Exception:
+ if errors == 'ignore':
+ isdir = False
+ elif errors == 'warn':
+ warnings.warn(
+ "Unable to access '%s': %s"
+ % (child, sys.exc_info()[1]),
+ TreeWalkWarning)
+ isdir = False
+ else:
+ raise
+
+ if isdir:
+ for item in child.walk(pattern, errors):
+ yield item
+
+ def walkdirs(self, pattern=None, errors='strict'):
+ """ D.walkdirs() -> iterator over subdirs, recursively.
+
+ With the optional 'pattern' argument, this yields only
+ directories whose names match the given pattern. For
+ example, mydir.walkdirs('*test') yields only directories
+ with names ending in 'test'.
+
+ The errors= keyword argument controls behavior when an
+ error occurs. The default is 'strict', which causes an
+ exception. The other allowed values are 'warn', which
+ reports the error via warnings.warn(), and 'ignore'.
+ """
+ if errors not in ('strict', 'warn', 'ignore'):
+ raise ValueError("invalid errors parameter")
+
+ try:
+ dirs = self.dirs()
+ except Exception:
+ if errors == 'ignore':
+ return
+ elif errors == 'warn':
+ warnings.warn(
+ "Unable to list directory '%s': %s"
+ % (self, sys.exc_info()[1]),
+ TreeWalkWarning)
+ return
+ else:
+ raise
+
+ for child in dirs:
+ if pattern is None or child.fnmatch(pattern):
+ yield child
+ for subsubdir in child.walkdirs(pattern, errors):
+ yield subsubdir
+
+ def walkfiles(self, pattern=None, errors='strict'):
+ """ D.walkfiles() -> iterator over files in D, recursively.
+
+ The optional argument, pattern, limits the results to files
+ with names that match the pattern. For example,
+ mydir.walkfiles('*.tmp') yields only files with the .tmp
+ extension.
+ """
+ if errors not in ('strict', 'warn', 'ignore'):
+ raise ValueError("invalid errors parameter")
+
+ try:
+ childList = self.listdir()
+ except Exception:
+ if errors == 'ignore':
+ return
+ elif errors == 'warn':
+ warnings.warn(
+ "Unable to list directory '%s': %s"
+ % (self, sys.exc_info()[1]),
+ TreeWalkWarning)
+ return
+ else:
+ raise
+
+ for child in childList:
+ try:
+ isfile = child.isfile()
+ isdir = not isfile and child.isdir()
+ except:
+ if errors == 'ignore':
+ continue
+ elif errors == 'warn':
+ warnings.warn(
+ "Unable to access '%s': %s"
+ % (self, sys.exc_info()[1]),
+ TreeWalkWarning)
+ continue
+ else:
+ raise
+
+ if isfile:
+ if pattern is None or child.fnmatch(pattern):
+ yield child
+ elif isdir:
+ for f in child.walkfiles(pattern, errors):
+ yield f
+
+ def fnmatch(self, pattern):
+ """ Return True if self.name matches the given pattern.
+
+ pattern - A filename pattern with wildcards,
+ for example '*.py'.
+ """
+ return fnmatch.fnmatch(self.name, pattern)
+
+ def glob(self, pattern):
+ """ Return a list of path objects that match the pattern.
+
+ pattern - a path relative to this directory, with wildcards.
+
+ For example, path('/users').glob('*/bin/*') returns a list
+ of all the files users have in their bin directories.
+ """
+ cls = self.__class__
+ return [cls(s) for s in glob.glob(_base(self / pattern))]
+
+
+ # --- Reading or writing an entire file at once.
+
+ def open(self, mode='r'):
+ """ Open this file. Return a file object. """
+ return file(self, mode)
+
+ def bytes(self):
+ """ Open this file, read all bytes, return them as a string. """
+ f = self.open('rb')
+ try:
+ return f.read()
+ finally:
+ f.close()
+
+ def write_bytes(self, bytes, append=False):
+ """ Open this file and write the given bytes to it.
+
+ Default behavior is to overwrite any existing file.
+ Call p.write_bytes(bytes, append=True) to append instead.
+ """
+ if append:
+ mode = 'ab'
+ else:
+ mode = 'wb'
+ f = self.open(mode)
+ try:
+ f.write(bytes)
+ finally:
+ f.close()
+
+ def text(self, encoding=None, errors='strict'):
+ r""" Open this file, read it in, return the content as a string.
+
+ This uses 'U' mode in Python 2.3 and later, so '\r\n' and '\r'
+ are automatically translated to '\n'.
+
+ Optional arguments:
+
+ encoding - The Unicode encoding (or character set) of
+ the file. If present, the content of the file is
+ decoded and returned as a unicode object; otherwise
+ it is returned as an 8-bit str.
+ errors - How to handle Unicode errors; see help(str.decode)
+ for the options. Default is 'strict'.
+ """
+ if encoding is None:
+ # 8-bit
+ f = self.open(_textmode)
+ try:
+ return f.read()
+ finally:
+ f.close()
+ else:
+ # Unicode
+ f = codecs.open(self, 'r', encoding, errors)
+ # (Note - Can't use 'U' mode here, since codecs.open
+ # doesn't support 'U' mode, even in Python 2.3.)
+ try:
+ t = f.read()
+ finally:
+ f.close()
+ return (t.replace(u'\r\n', u'\n')
+ .replace(u'\r\x85', u'\n')
+ .replace(u'\r', u'\n')
+ .replace(u'\x85', u'\n')
+ .replace(u'\u2028', u'\n'))
+
+ def write_text(self, text, encoding=None, errors='strict', linesep=os.linesep, append=False):
+ r""" Write the given text to this file.
+
+ The default behavior is to overwrite any existing file;
+ to append instead, use the 'append=True' keyword argument.
+
+ There are two differences between path.write_text() and
+ path.write_bytes(): newline handling and Unicode handling.
+ See below.
+
+ Parameters:
+
+ - text - str/unicode - The text to be written.
+
+ - encoding - str - The Unicode encoding that will be used.
+ This is ignored if 'text' isn't a Unicode string.
+
+ - errors - str - How to handle Unicode encoding errors.
+ Default is 'strict'. See help(unicode.encode) for the
+ options. This is ignored if 'text' isn't a Unicode
+ string.
+
+ - linesep - keyword argument - str/unicode - The sequence of
+ characters to be used to mark end-of-line. The default is
+ os.linesep. You can also specify None; this means to
+ leave all newlines as they are in 'text'.
+
+ - append - keyword argument - bool - Specifies what to do if
+ the file already exists (True: append to the end of it;
+ False: overwrite it.) The default is False.
+
+
+ --- Newline handling.
+
+ write_text() converts all standard end-of-line sequences
+ ('\n', '\r', and '\r\n') to your platform's default end-of-line
+ sequence (see os.linesep; on Windows, for example, the
+ end-of-line marker is '\r\n').
+
+ If you don't like your platform's default, you can override it
+ using the 'linesep=' keyword argument. If you specifically want
+ write_text() to preserve the newlines as-is, use 'linesep=None'.
+
+ This applies to Unicode text the same as to 8-bit text, except
+ there are three additional standard Unicode end-of-line sequences:
+ u'\x85', u'\r\x85', and u'\u2028'.
+
+ (This is slightly different from when you open a file for
+ writing with fopen(filename, "w") in C or file(filename, 'w')
+ in Python.)
+
+
+ --- Unicode
+
+ If 'text' isn't Unicode, then apart from newline handling, the
+ bytes are written verbatim to the file. The 'encoding' and
+ 'errors' arguments are not used and must be omitted.
+
+ If 'text' is Unicode, it is first converted to bytes using the
+ specified 'encoding' (or the default encoding if 'encoding'
+ isn't specified). The 'errors' argument applies only to this
+ conversion.
+
+ """
+ if isinstance(text, unicode):
+ if linesep is not None:
+ # Convert all standard end-of-line sequences to
+ # ordinary newline characters.
+ text = (text.replace(u'\r\n', u'\n')
+ .replace(u'\r\x85', u'\n')
+ .replace(u'\r', u'\n')
+ .replace(u'\x85', u'\n')
+ .replace(u'\u2028', u'\n'))
+ text = text.replace(u'\n', linesep)
+ if encoding is None:
+ encoding = sys.getdefaultencoding()
+ bytes = text.encode(encoding, errors)
+ else:
+ # It is an error to specify an encoding if 'text' is
+ # an 8-bit string.
+ assert encoding is None
+
+ if linesep is not None:
+ text = (text.replace('\r\n', '\n')
+ .replace('\r', '\n'))
+ bytes = text.replace('\n', linesep)
+
+ self.write_bytes(bytes, append)
+
+ def lines(self, encoding=None, errors='strict', retain=True):
+ r""" Open this file, read all lines, return them in a list.
+
+ Optional arguments:
+ encoding - The Unicode encoding (or character set) of
+ the file. The default is None, meaning the content
+ of the file is read as 8-bit characters and returned
+ as a list of (non-Unicode) str objects.
+ errors - How to handle Unicode errors; see help(str.decode)
+ for the options. Default is 'strict'
+ retain - If true, retain newline characters; but all newline
+ character combinations ('\r', '\n', '\r\n') are
+ translated to '\n'. If false, newline characters are
+ stripped off. Default is True.
+
+ This uses 'U' mode in Python 2.3 and later.
+ """
+ if encoding is None and retain:
+ f = self.open(_textmode)
+ try:
+ return f.readlines()
+ finally:
+ f.close()
+ else:
+ return self.text(encoding, errors).splitlines(retain)
+
+ def write_lines(self, lines, encoding=None, errors='strict',
+ linesep=os.linesep, append=False):
+ r""" Write the given lines of text to this file.
+
+ By default this overwrites any existing file at this path.
+
+ This puts a platform-specific newline sequence on every line.
+ See 'linesep' below.
+
+ lines - A list of strings.
+
+ encoding - A Unicode encoding to use. This applies only if
+ 'lines' contains any Unicode strings.
+
+ errors - How to handle errors in Unicode encoding. This
+ also applies only to Unicode strings.
+
+ linesep - The desired line-ending. This line-ending is
+ applied to every line. If a line already has any
+ standard line ending ('\r', '\n', '\r\n', u'\x85',
+ u'\r\x85', u'\u2028'), that will be stripped off and
+ this will be used instead. The default is os.linesep,
+ which is platform-dependent ('\r\n' on Windows, '\n' on
+ Unix, etc.) Specify None to write the lines as-is,
+ like file.writelines().
+
+ Use the keyword argument append=True to append lines to the
+ file. The default is to overwrite the file. Warning:
+ When you use this with Unicode data, if the encoding of the
+ existing data in the file is different from the encoding
+ you specify with the encoding= parameter, the result is
+ mixed-encoding data, which can really confuse someone trying
+ to read the file later.
+ """
+ if append:
+ mode = 'ab'
+ else:
+ mode = 'wb'
+ f = self.open(mode)
+ try:
+ for line in lines:
+ isUnicode = isinstance(line, unicode)
+ if linesep is not None:
+ # Strip off any existing line-end and add the
+ # specified linesep string.
+ if isUnicode:
+ if line[-2:] in (u'\r\n', u'\x0d\x85'):
+ line = line[:-2]
+ elif line[-1:] in (u'\r', u'\n',
+ u'\x85', u'\u2028'):
+ line = line[:-1]
+ else:
+ if line[-2:] == '\r\n':
+ line = line[:-2]
+ elif line[-1:] in ('\r', '\n'):
+ line = line[:-1]
+ line += linesep
+ if isUnicode:
+ if encoding is None:
+ encoding = sys.getdefaultencoding()
+ line = line.encode(encoding, errors)
+ f.write(line)
+ finally:
+ f.close()
+
+ def read_md5(self):
+ """ Calculate the md5 hash for this file.
+
+ This reads through the entire file.
+ """
+ f = self.open('rb')
+ try:
+ m = md5.new()
+ while True:
+ d = f.read(8192)
+ if not d:
+ break
+ m.update(d)
+ finally:
+ f.close()
+ return m.digest()
+
+ # --- Methods for querying the filesystem.
+
+ exists = os.path.exists
+ isdir = os.path.isdir
+ isfile = os.path.isfile
+ islink = os.path.islink
+ ismount = os.path.ismount
+
+ if hasattr(os.path, 'samefile'):
+ samefile = os.path.samefile
+
+ getatime = os.path.getatime
+ atime = property(
+ getatime, None, None,
+ """ Last access time of the file. """)
+
+ getmtime = os.path.getmtime
+ mtime = property(
+ getmtime, None, None,
+ """ Last-modified time of the file. """)
+
+ if hasattr(os.path, 'getctime'):
+ getctime = os.path.getctime
+ ctime = property(
+ getctime, None, None,
+ """ Creation time of the file. """)
+
+ getsize = os.path.getsize
+ size = property(
+ getsize, None, None,
+ """ Size of the file, in bytes. """)
+
+ if hasattr(os, 'access'):
+ def access(self, mode):
+ """ Return true if current user has access to this path.
+
+ mode - One of the constants os.F_OK, os.R_OK, os.W_OK, os.X_OK
+ """
+ return os.access(self, mode)
+
+ def stat(self):
+ """ Perform a stat() system call on this path. """
+ return os.stat(self)
+
+ def lstat(self):
+ """ Like path.stat(), but do not follow symbolic links. """
+ return os.lstat(self)
+
+ def get_owner(self):
+ r""" Return the name of the owner of this file or directory.
+
+ This follows symbolic links.
+
+ On Windows, this returns a name of the form ur'DOMAIN\User Name'.
+ On Windows, a group can own a file or directory.
+ """
+ if os.name == 'nt':
+ if win32security is None:
+ raise Exception("path.owner requires win32all to be installed")
+ desc = win32security.GetFileSecurity(
+ self, win32security.OWNER_SECURITY_INFORMATION)
+ sid = desc.GetSecurityDescriptorOwner()
+ account, domain, typecode = win32security.LookupAccountSid(None, sid)
+ return domain + u'\\' + account
+ else:
+ if pwd is None:
+ raise NotImplementedError("path.owner is not implemented on this platform.")
+ st = self.stat()
+ return pwd.getpwuid(st.st_uid).pw_name
+
+ owner = property(
+ get_owner, None, None,
+ """ Name of the owner of this file or directory. """)
+
+ if hasattr(os, 'statvfs'):
+ def statvfs(self):
+ """ Perform a statvfs() system call on this path. """
+ return os.statvfs(self)
+
+ if hasattr(os, 'pathconf'):
+ def pathconf(self, name):
+ return os.pathconf(self, name)
+
+
+ # --- Modifying operations on files and directories
+
+ def utime(self, times):
+ """ Set the access and modified times of this file. """
+ os.utime(self, times)
+
+ def chmod(self, mode):
+ os.chmod(self, mode)
+
+ if hasattr(os, 'chown'):
+ def chown(self, uid, gid):
+ os.chown(self, uid, gid)
+
+ def rename(self, new):
+ os.rename(self, new)
+
+ def renames(self, new):
+ os.renames(self, new)
+
+
+ # --- Create/delete operations on directories
+
+ def mkdir(self, mode=0777):
+ os.mkdir(self, mode)
+
+ def makedirs(self, mode=0777):
+ os.makedirs(self, mode)
+
+ def rmdir(self):
+ os.rmdir(self)
+
+ def removedirs(self):
+ os.removedirs(self)
+
+
+ # --- Modifying operations on files
+
+ def touch(self):
+ """ Set the access/modified times of this file to the current time.
+ Create the file if it does not exist.
+ """
+ fd = os.open(self, os.O_WRONLY | os.O_CREAT, 0666)
+ os.close(fd)
+ os.utime(self, None)
+
+ def remove(self):
+ os.remove(self)
+
+ def unlink(self):
+ os.unlink(self)
+
+
+ # --- Links
+
+ if hasattr(os, 'link'):
+ def link(self, newpath):
+ """ Create a hard link at 'newpath', pointing to this file. """
+ os.link(self, newpath)
+
+ if hasattr(os, 'symlink'):
+ def symlink(self, newlink):
+ """ Create a symbolic link at 'newlink', pointing here. """
+ os.symlink(self, newlink)
+
+ if hasattr(os, 'readlink'):
+ def readlink(self):
+ """ Return the path to which this symbolic link points.
+
+ The result may be an absolute or a relative path.
+ """
+ return self.__class__(os.readlink(self))
+
+ def readlinkabs(self):
+ """ Return the path to which this symbolic link points.
+
+ The result is always an absolute path.
+ """
+ p = self.readlink()
+ if p.isabs():
+ return p
+ else:
+ return (self.parent / p).abspath()
+
+
+ # --- High-level functions from shutil
+
+ copyfile = shutil.copyfile
+ copymode = shutil.copymode
+ copystat = shutil.copystat
+ copy = shutil.copy
+ copy2 = shutil.copy2
+ copytree = shutil.copytree
+ if hasattr(shutil, 'move'):
+ move = shutil.move
+ rmtree = shutil.rmtree
+
+
+ # --- Special stuff from os
+
+ if hasattr(os, 'chroot'):
+ def chroot(self):
+ os.chroot(self)
+
+ if hasattr(os, 'startfile'):
+ def startfile(self):
+ os.startfile(self)
+
diff --git a/IPython/external/pretty.py b/IPython/external/pretty.py
new file mode 100644
index 0000000..6a7e855
--- /dev/null
+++ b/IPython/external/pretty.py
@@ -0,0 +1,705 @@
+# -*- coding: utf-8 -*-
+"""
+ pretty
+ ~~
+
+ Python advanced pretty printer. This pretty printer is intended to
+ replace the old `pprint` python module which does not allow developers
+ to provide their own pretty print callbacks.
+
+ This module is based on ruby's `prettyprint.rb` library by `Tanaka Akira`.
+
+
+ Example Usage
+ =============
+
+ To directly print the representation of an object use `pprint`::
+
+ from pretty import pprint
+ pprint(complex_object)
+
+ To get a string of the output use `pretty`::
+
+ from pretty import pretty
+ string = pretty(complex_object)
+
+
+ Extending
+ =========
+
+ The pretty library allows developers to add pretty printing rules for their
+ own objects. This process is straightforward. All you have to do is to
+ add a `__pretty__` method to your object and call the methods on the
+ pretty printer passed::
+
+ class MyObject(object):
+
+ def __pretty__(self, p, cycle):
+ ...
+
+ Depending on the python version you want to support you have two
+ possibilities. The following list shows the python 2.5 version and the
+ compatibility one.
+
+
+ Here the example implementation of a `__pretty__` method for a list
+ subclass for python 2.5 and higher (python 2.5 requires the with statement
+ __future__ import)::
+
+ class MyList(list):
+
+ def __pretty__(self, p, cycle):
+ if cycle:
+ p.text('MyList(...)')
+ else:
+ with p.group(8, 'MyList([', '])'):
+ for idx, item in enumerate(self):
+ if idx:
+ p.text(',')
+ p.breakable()
+ p.pretty(item)
+
+ The `cycle` parameter is `True` if pretty detected a cycle. You *have* to
+ react to that or the result is an infinite loop. `p.text()` just adds
+ non breaking text to the output, `p.breakable()` either adds a whitespace
+ or breaks here. If you pass it an argument it's used instead of the
+ default space. `p.pretty` prettyprints another object using the pretty print
+ method.
+
+ The first parameter to the `group` function specifies the extra indentation
+ of the next line. In this example the next item will either be not
+ breaked (if the items are short enough) or aligned with the right edge of
+ the opening bracked of `MyList`.
+
+ If you want to support python 2.4 and lower you can use this code::
+
+ class MyList(list):
+
+ def __pretty__(self, p, cycle):
+ if cycle:
+ p.text('MyList(...)')
+ else:
+ p.begin_group(8, 'MyList([')
+ for idx, item in enumerate(self):
+ if idx:
+ p.text(',')
+ p.breakable()
+ p.pretty(item)
+ p.end_group(8, '])')
+
+ If you just want to indent something you can use the group function
+ without open / close parameters. Under python 2.5 you can also use this
+ code::
+
+ with p.indent(2):
+ ...
+
+ Or under python2.4 you might want to modify ``p.indentation`` by hand but
+ this is rather ugly.
+
+ :copyright: 2007 by Armin Ronacher.
+ Portions (c) 2009 by Robert Kern.
+ :license: BSD License.
+"""
+import __future__
+import sys
+import types
+import re
+import datetime
+from StringIO import StringIO
+from collections import deque
+
+
+__all__ = ['pretty', 'pprint', 'PrettyPrinter', 'RepresentationPrinter',
+ 'for_type', 'for_type_by_name']
+
+
+_re_pattern_type = type(re.compile(''))
+
+
+def pretty(obj, verbose=False, max_width=79, newline='\n'):
+ """
+ Pretty print the object's representation.
+ """
+ stream = StringIO()
+ printer = RepresentationPrinter(stream, verbose, max_width, newline)
+ printer.pretty(obj)
+ printer.flush()
+ return stream.getvalue()
+
+
+def pprint(obj, verbose=False, max_width=79, newline='\n'):
+ """
+ Like `pretty` but print to stdout.
+ """
+ printer = RepresentationPrinter(sys.stdout, verbose, max_width, newline)
+ printer.pretty(obj)
+ printer.flush()
+ sys.stdout.write(newline)
+ sys.stdout.flush()
+
+
+# add python2.5 context managers if we have the with statement feature
+if hasattr(__future__, 'with_statement'): exec '''
+from __future__ import with_statement
+from contextlib import contextmanager
+
+class _PrettyPrinterBase(object):
+
+ @contextmanager
+ def indent(self, indent):
+ """with statement support for indenting/dedenting."""
+ self.indentation += indent
+ try:
+ yield
+ finally:
+ self.indentation -= indent
+
+ @contextmanager
+ def group(self, indent=0, open='', close=''):
+ """like begin_group / end_group but for the with statement."""
+ self.begin_group(indent, open)
+ try:
+ with self.indent(indent):
+ yield
+ finally:
+ self.end_group(indent, close)
+'''
+else:
+ class _PrettyPrinterBase(object):
+
+ def _unsupported(self, *a, **kw):
+ """unsupported operation"""
+ raise RuntimeError('not available in this python version')
+ group = indent = _unsupported
+ del _unsupported
+
+
+class PrettyPrinter(_PrettyPrinterBase):
+ """
+ Baseclass for the `RepresentationPrinter` prettyprinter that is used to
+ generate pretty reprs of objects. Contrary to the `RepresentationPrinter`
+ this printer knows nothing about the default pprinters or the `__pretty__`
+ callback method.
+ """
+
+ def __init__(self, output, max_width=79, newline='\n'):
+ self.output = output
+ self.max_width = max_width
+ self.newline = newline
+ self.output_width = 0
+ self.buffer_width = 0
+ self.buffer = deque()
+
+ root_group = Group(0)
+ self.group_stack = [root_group]
+ self.group_queue = GroupQueue(root_group)
+ self.indentation = 0
+
+ def _break_outer_groups(self):
+ while self.max_width < self.output_width + self.buffer_width:
+ group = self.group_queue.deq()
+ if not group:
+ return
+ while group.breakables:
+ x = self.buffer.popleft()
+ self.output_width = x.output(self.output, self.output_width)
+ self.buffer_width -= x.width
+ while self.buffer and isinstance(self.buffer[0], Text):
+ x = self.buffer.popleft()
+ self.output_width = x.output(self.output, self.output_width)
+ self.buffer_width -= x.width
+
+ def text(self, obj):
+ """Add literal text to the output."""
+ width = len(obj)
+ if self.buffer:
+ text = self.buffer[-1]
+ if not isinstance(text, Text):
+ text = Text()
+ self.buffer.append(text)
+ text.add(obj, width)
+ self.buffer_width += width
+ self._break_outer_groups()
+ else:
+ self.output.write(obj)
+ self.output_width += width
+
+ def breakable(self, sep=' '):
+ """
+ Add a breakable separator to the output. This does not mean that it
+ will automatically break here. If no breaking on this position takes
+ place the `sep` is inserted which default to one space.
+ """
+ width = len(sep)
+ group = self.group_stack[-1]
+ if group.want_break:
+ self.flush()
+ self.output.write(self.newline)
+ self.output.write(' ' * self.indentation)
+ self.output_width = self.indentation
+ self.buffer_width = 0
+ else:
+ self.buffer.append(Breakable(sep, width, self))
+ self.buffer_width += width
+ self._break_outer_groups()
+
+
+ def begin_group(self, indent=0, open=''):
+ """
+ Begin a group. If you want support for python < 2.5 which doesn't has
+ the with statement this is the preferred way:
+
+ p.begin_group(1, '{')
+ ...
+ p.end_group(1, '}')
+
+ The python 2.5 expression would be this:
+
+ with p.group(1, '{', '}'):
+ ...
+
+ The first parameter specifies the indentation for the next line (usually
+ the width of the opening text), the second the opening text. All
+ parameters are optional.
+ """
+ if open:
+ self.text(open)
+ group = Group(self.group_stack[-1].depth + 1)
+ self.group_stack.append(group)
+ self.group_queue.enq(group)
+ self.indentation += indent
+
+ def end_group(self, dedent=0, close=''):
+ """End a group. See `begin_group` for more details."""
+ self.indentation -= dedent
+ group = self.group_stack.pop()
+ if not group.breakables:
+ self.group_queue.remove(group)
+ if close:
+ self.text(close)
+
+ def flush(self):
+ """Flush data that is left in the buffer."""
+ for data in self.buffer:
+ self.output_width += data.output(self.output, self.output_width)
+ self.buffer.clear()
+ self.buffer_width = 0
+
+
+def _get_mro(obj_class):
+ """ Get a reasonable method resolution order of a class and its superclasses
+ for both old-style and new-style classes.
+ """
+ if not hasattr(obj_class, '__mro__'):
+ # Old-style class. Mix in object to make a fake new-style class.
+ try:
+ obj_class = type(obj_class.__name__, (obj_class, object), {})
+ except TypeError:
+ # Old-style extension type that does not descend from object.
+ # FIXME: try to construct a more thorough MRO.
+ mro = [obj_class]
+ else:
+ mro = obj_class.__mro__[1:-1]
+ else:
+ mro = obj_class.__mro__
+ return mro
+
+
+class RepresentationPrinter(PrettyPrinter):
+ """
+ Special pretty printer that has a `pretty` method that calls the pretty
+ printer for a python object.
+
+ This class stores processing data on `self` so you must *never* use
+ this class in a threaded environment. Always lock it or reinstanciate
+ it.
+
+ Instances also have a verbose flag callbacks can access to control their
+ output. For example the default instance repr prints all attributes and
+ methods that are not prefixed by an underscore if the printer is in
+ verbose mode.
+ """
+
+ def __init__(self, output, verbose=False, max_width=79, newline='\n'):
+ PrettyPrinter.__init__(self, output, max_width, newline)
+ self.verbose = verbose
+ self.stack = []
+
+ def pretty(self, obj):
+ """Pretty print the given object."""
+ obj_id = id(obj)
+ cycle = obj_id in self.stack
+ self.stack.append(obj_id)
+ self.begin_group()
+ try:
+ obj_class = getattr(obj, '__class__', None) or type(obj)
+ if hasattr(obj_class, '__pretty__'):
+ return obj_class.__pretty__(obj, self, cycle)
+ try:
+ printer = _singleton_pprinters[obj_id]
+ except (TypeError, KeyError):
+ pass
+ else:
+ return printer(obj, self, cycle)
+ for cls in _get_mro(obj_class):
+ if cls in _type_pprinters:
+ return _type_pprinters[cls](obj, self, cycle)
+ else:
+ printer = self._in_deferred_types(cls)
+ if printer is not None:
+ return printer(obj, self, cycle)
+ return _default_pprint(obj, self, cycle)
+ finally:
+ self.end_group()
+ self.stack.pop()
+
+ def _in_deferred_types(self, cls):
+ """
+ Check if the given class is specified in the deferred type registry.
+
+ Returns the printer from the registry if it exists, and None if the
+ class is not in the registry. Successful matches will be moved to the
+ regular type registry for future use.
+ """
+ mod = getattr(cls, '__module__', None)
+ name = getattr(cls, '__name__', None)
+ key = (mod, name)
+ printer = None
+ if key in _deferred_type_pprinters:
+ # Move the printer over to the regular registry.
+ printer = _deferred_type_pprinters.pop(key)
+ _type_pprinters[cls] = printer
+ return printer
+
+
+
+class Printable(object):
+
+ def output(self, stream, output_width):
+ return output_width
+
+
+class Text(Printable):
+
+ def __init__(self):
+ self.objs = []
+ self.width = 0
+
+ def output(self, stream, output_width):
+ for obj in self.objs:
+ stream.write(obj)
+ return output_width + self.width
+
+ def add(self, obj, width):
+ self.objs.append(obj)
+ self.width += width
+
+
+class Breakable(Printable):
+
+ def __init__(self, seq, width, pretty):
+ self.obj = seq
+ self.width = width
+ self.pretty = pretty
+ self.indentation = pretty.indentation
+ self.group = pretty.group_stack[-1]
+ self.group.breakables.append(self)
+
+ def output(self, stream, output_width):
+ self.group.breakables.popleft()
+ if self.group.want_break:
+ stream.write(self.pretty.newline)
+ stream.write(' ' * self.indentation)
+ return self.indentation
+ if not self.group.breakables:
+ self.pretty.group_queue.remove(self.group)
+ stream.write(self.obj)
+ return output_width + self.width
+
+
+class Group(Printable):
+
+ def __init__(self, depth):
+ self.depth = depth
+ self.breakables = deque()
+ self.want_break = False
+
+
+class GroupQueue(object):
+
+ def __init__(self, *groups):
+ self.queue = []
+ for group in groups:
+ self.enq(group)
+
+ def enq(self, group):
+ depth = group.depth
+ while depth > len(self.queue) - 1:
+ self.queue.append([])
+ self.queue[depth].append(group)
+
+ def deq(self):
+ for stack in self.queue:
+ for idx, group in enumerate(reversed(stack)):
+ if group.breakables:
+ del stack[idx]
+ group.want_break = True
+ return group
+ for group in stack:
+ group.want_break = True
+ del stack[:]
+
+ def remove(self, group):
+ try:
+ self.queue[group.depth].remove(group)
+ except ValueError:
+ pass
+
+
+_baseclass_reprs = (object.__repr__, types.InstanceType.__repr__)
+
+
+def _default_pprint(obj, p, cycle):
+ """
+ The default print function. Used if an object does not provide one and
+ it's none of the builtin objects.
+ """
+ klass = getattr(obj, '__class__', None) or type(obj)
+ if getattr(klass, '__repr__', None) not in _baseclass_reprs:
+ # A user-provided repr.
+ p.text(repr(obj))
+ return
+ p.begin_group(1, '<')
+ p.pretty(klass)
+ p.text(' at 0x%x' % id(obj))
+ if cycle:
+ p.text(' ...')
+ elif p.verbose:
+ first = True
+ for key in dir(obj):
+ if not key.startswith('_'):
+ try:
+ value = getattr(obj, key)
+ except AttributeError:
+ continue
+ if isinstance(value, types.MethodType):
+ continue
+ if not first:
+ p.text(',')
+ p.breakable()
+ p.text(key)
+ p.text('=')
+ step = len(key) + 1
+ p.indentation += step
+ p.pretty(value)
+ p.indentation -= step
+ first = False
+ p.end_group(1, '>')
+
+
+def _seq_pprinter_factory(start, end):
+ """
+ Factory that returns a pprint function useful for sequences. Used by
+ the default pprint for tuples, dicts, lists, sets and frozensets.
+ """
+ def inner(obj, p, cycle):
+ if cycle:
+ return p.text(start + '...' + end)
+ step = len(start)
+ p.begin_group(step, start)
+ for idx, x in enumerate(obj):
+ if idx:
+ p.text(',')
+ p.breakable()
+ p.pretty(x)
+ if len(obj) == 1 and type(obj) is tuple:
+ # Special case for 1-item tuples.
+ p.text(',')
+ p.end_group(step, end)
+ return inner
+
+
+def _dict_pprinter_factory(start, end):
+ """
+ Factory that returns a pprint function used by the default pprint of
+ dicts and dict proxies.
+ """
+ def inner(obj, p, cycle):
+ if cycle:
+ return p.text('{...}')
+ p.begin_group(1, start)
+ keys = obj.keys()
+ try:
+ keys.sort()
+ except Exception, e:
+ # Sometimes the keys don't sort.
+ pass
+ for idx, key in enumerate(keys):
+ if idx:
+ p.text(',')
+ p.breakable()
+ p.pretty(key)
+ p.text(': ')
+ p.pretty(obj[key])
+ p.end_group(1, end)
+ return inner
+
+
+def _super_pprint(obj, p, cycle):
+ """The pprint for the super type."""
+ p.begin_group(8, '<super: ')
+ p.pretty(obj.__self_class__)
+ p.text(',')
+ p.breakable()
+ p.pretty(obj.__self__)
+ p.end_group(8, '>')
+
+
+def _re_pattern_pprint(obj, p, cycle):
+ """The pprint function for regular expression patterns."""
+ p.text('re.compile(')
+ pattern = repr(obj.pattern)
+ if pattern[:1] in 'uU':
+ pattern = pattern[1:]
+ prefix = 'ur'
+ else:
+ prefix = 'r'
+ pattern = prefix + pattern.replace('\\\\', '\\')
+ p.text(pattern)
+ if obj.flags:
+ p.text(',')
+ p.breakable()
+ done_one = False
+ for flag in ('TEMPLATE', 'IGNORECASE', 'LOCALE', 'MULTILINE', 'DOTALL',
+ 'UNICODE', 'VERBOSE', 'DEBUG'):
+ if obj.flags & getattr(re, flag):
+ if done_one:
+ p.text('|')
+ p.text('re.' + flag)
+ done_one = True
+ p.text(')')
+
+
+def _type_pprint(obj, p, cycle):
+ """The pprint for classes and types."""
+ if obj.__module__ in ('__builtin__', 'exceptions'):
+ name = obj.__name__
+ else:
+ name = obj.__module__ + '.' + obj.__name__
+ p.text(name)
+
+
+def _repr_pprint(obj, p, cycle):
+ """A pprint that just redirects to the normal repr function."""
+ p.text(repr(obj))
+
+
+def _function_pprint(obj, p, cycle):
+ """Base pprint for all functions and builtin functions."""
+ if obj.__module__ in ('__builtin__', 'exceptions') or not obj.__module__:
+ name = obj.__name__
+ else:
+ name = obj.__module__ + '.' + obj.__name__
+ p.text('<function %s>' % name)
+
+
+def _exception_pprint(obj, p, cycle):
+ """Base pprint for all exceptions."""
+ if obj.__class__.__module__ == 'exceptions':
+ name = obj.__class__.__name__
+ else:
+ name = '%s.%s' % (
+ obj.__class__.__module__,
+ obj.__class__.__name__
+ )
+ step = len(name) + 1
+ p.begin_group(step, '(')
+ for idx, arg in enumerate(getattr(obj, 'args', ())):
+ if idx:
+ p.text(',')
+ p.breakable()
+ p.pretty(arg)
+ p.end_group(step, ')')
+
+
+#: the exception base
+try:
+ _exception_base = BaseException
+except NameError:
+ _exception_base = Exception
+
+
+#: printers for builtin types
+_type_pprinters = {
+ int: _repr_pprint,
+ long: _repr_pprint,
+ float: _repr_pprint,
+ str: _repr_pprint,
+ unicode: _repr_pprint,
+ tuple: _seq_pprinter_factory('(', ')'),
+ list: _seq_pprinter_factory('[', ']'),
+ dict: _dict_pprinter_factory('{', '}'),
+ types.DictProxyType: _dict_pprinter_factory('<dictproxy {', '}>'),
+ set: _seq_pprinter_factory('set([', '])'),
+ frozenset: _seq_pprinter_factory('frozenset([', '])'),
+ super: _super_pprint,
+ _re_pattern_type: _re_pattern_pprint,
+ type: _type_pprint,
+ types.ClassType: _type_pprint,
+ types.FunctionType: _function_pprint,
+ types.BuiltinFunctionType: _function_pprint,
+ types.SliceType: _repr_pprint,
+ types.MethodType: _repr_pprint,
+ xrange: _repr_pprint,
+ datetime.datetime: _repr_pprint,
+ datetime.timedelta: _repr_pprint,
+ _exception_base: _exception_pprint
+}
+
+#: printers for types specified by name
+_deferred_type_pprinters = {
+}
+
+def for_type(typ, func):
+ """
+ Add a pretty printer for a given type.
+ """
+ oldfunc = _type_pprinters.get(typ, None)
+ if func is not None:
+ # To support easy restoration of old pprinters, we need to ignore Nones.
+ _type_pprinters[typ] = func
+ return oldfunc
+
+def for_type_by_name(type_module, type_name, func):
+ """
+ Add a pretty printer for a type specified by the module and name of a type
+ rather than the type object itself.
+ """
+ key = (type_module, type_name)
+ oldfunc = _deferred_type_pprinters.get(key, None)
+ if func is not None:
+ # To support easy restoration of old pprinters, we need to ignore Nones.
+ _deferred_type_pprinters[key] = func
+ return oldfunc
+
+
+#: printers for the default singletons
+_singleton_pprinters = dict.fromkeys(map(id, [None, True, False, Ellipsis,
+ NotImplemented]), _repr_pprint)
+
+
+if __name__ == '__main__':
+ from random import randrange
+ class Foo(object):
+ def __init__(self):
+ self.foo = 1
+ self.bar = re.compile(r'\s+')
+ self.blub = dict.fromkeys(range(30), randrange(1, 40))
+ self.hehe = 23424.234234
+ self.list = ["blub", "blah", self]
+
+ def get_foo(self):
+ print "foo"
+
+ pprint(Foo(), verbose=True)
diff --git a/IPython/external/simplegeneric.py b/IPython/external/simplegeneric.py
new file mode 100644
index 0000000..556d6f2
--- /dev/null
+++ b/IPython/external/simplegeneric.py
@@ -0,0 +1,139 @@
+#Name: simplegeneric
+#Version: 0.6
+#Summary: Simple generic functions (similar to Python's own len(), pickle.dump(), etc.)
+#Home-page: http://cheeseshop.python.org/pypi/simplegeneric
+#Author: Phillip J. Eby
+#Author-email: peak@eby-sarna.com
+#License: PSF or ZPL
+
+# This is version 0.6 of Philip J. Eby's simplegeneric module
+# (http://cheeseshop.python.org/pypi/simplegeneric) patched to work
+# with Python 2.3 (which doesn't support assigning to __name__)
+
+__all__ = ["generic"]
+
+
+from types import ClassType, InstanceType
+classtypes = type, ClassType
+
+def generic(func):
+ """Create a simple generic function"""
+
+ _sentinel = object()
+
+ def _by_class(*args, **kw):
+ cls = args[0].__class__
+ for t in type(cls.__name__, (cls,object), {}).__mro__:
+ f = _gbt(t, _sentinel)
+ if f is not _sentinel:
+ return f(*args, **kw)
+ else:
+ return func(*args, **kw)
+
+ _by_type = {object: func, InstanceType: _by_class}
+ _gbt = _by_type.get
+
+ def when_type(t):
+ """Decorator to add a method that will be called for type `t`"""
+ if not isinstance(t, classtypes):
+ raise TypeError(
+ "%r is not a type or class" % (t,)
+ )
+ def decorate(f):
+ if _by_type.setdefault(t,f) is not f:
+ raise TypeError(
+ "%r already has method for type %r" % (func, t)
+ )
+ return f
+ return decorate
+
+
+
+
+
+
+ _by_object = {}
+ _gbo = _by_object.get
+
+ def when_object(o):
+ """Decorator to add a method that will be called for object `o`"""
+ def decorate(f):
+ if _by_object.setdefault(id(o), (o,f))[1] is not f:
+ raise TypeError(
+ "%r already has method for object %r" % (func, o)
+ )
+ return f
+ return decorate
+
+
+ def dispatch(*args, **kw):
+ f = _gbo(id(args[0]), _sentinel)
+ if f is _sentinel:
+ for t in type(args[0]).__mro__:
+ f = _gbt(t, _sentinel)
+ if f is not _sentinel:
+ return f(*args, **kw)
+ else:
+ return func(*args, **kw)
+ else:
+ return f[1](*args, **kw)
+
+ try:
+ dispatch.__name__ = func.__name__
+ except TypeError:
+ pass
+ dispatch.__dict__ = func.__dict__.copy()
+ dispatch.__doc__ = func.__doc__
+ dispatch.__module__ = func.__module__
+
+ dispatch.when_type = when_type
+ dispatch.when_object = when_object
+ dispatch.default = func
+ dispatch.has_object = lambda o: id(o) in _by_object
+ dispatch.has_type = lambda t: t in _by_type
+ return dispatch
+
+
+
+
+def test_suite():
+ import doctest
+ return doctest.DocFileSuite(
+ 'README.txt',
+ optionflags=doctest.ELLIPSIS|doctest.REPORT_ONLY_FIRST_FAILURE,
+ )
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/IPython/external/validate.py b/IPython/external/validate.py
new file mode 100644
index 0000000..764b18a
--- /dev/null
+++ b/IPython/external/validate.py
@@ -0,0 +1,1414 @@
+# validate.py
+# A Validator object
+# Copyright (C) 2005 Michael Foord, Mark Andrews, Nicola Larosa
+# E-mail: fuzzyman AT voidspace DOT org DOT uk
+# mark AT la-la DOT com
+# nico AT tekNico DOT net
+
+# This software is licensed under the terms of the BSD license.
+# http://www.voidspace.org.uk/python/license.shtml
+# Basically you're free to copy, modify, distribute and relicense it,
+# So long as you keep a copy of the license with it.
+
+# Scripts maintained at http://www.voidspace.org.uk/python/index.shtml
+# For information about bugfixes, updates and support, please join the
+# ConfigObj mailing list:
+# http://lists.sourceforge.net/lists/listinfo/configobj-develop
+# Comments, suggestions and bug reports welcome.
+
+"""
+ The Validator object is used to check that supplied values
+ conform to a specification.
+
+ The value can be supplied as a string - e.g. from a config file.
+ In this case the check will also *convert* the value to
+ the required type. This allows you to add validation
+ as a transparent layer to access data stored as strings.
+ The validation checks that the data is correct *and*
+ converts it to the expected type.
+
+ Some standard checks are provided for basic data types.
+ Additional checks are easy to write. They can be
+ provided when the ``Validator`` is instantiated or
+ added afterwards.
+
+ The standard functions work with the following basic data types :
+
+ * integers
+ * floats
+ * booleans
+ * strings
+ * ip_addr
+
+ plus lists of these datatypes
+
+ Adding additional checks is done through coding simple functions.
+
+ The full set of standard checks are :
+
+ * 'integer': matches integer values (including negative)
+ Takes optional 'min' and 'max' arguments : ::
+
+ integer()
+ integer(3, 9) # any value from 3 to 9
+ integer(min=0) # any positive value
+ integer(max=9)
+
+ * 'float': matches float values
+ Has the same parameters as the integer check.
+
+ * 'boolean': matches boolean values - ``True`` or ``False``
+ Acceptable string values for True are :
+ true, on, yes, 1
+ Acceptable string values for False are :
+ false, off, no, 0
+
+ Any other value raises an error.
+
+ * 'ip_addr': matches an Internet Protocol address, v.4, represented
+ by a dotted-quad string, i.e. '1.2.3.4'.
+
+ * 'string': matches any string.
+ Takes optional keyword args 'min' and 'max'
+ to specify min and max lengths of the string.
+
+ * 'list': matches any list.
+ Takes optional keyword args 'min', and 'max' to specify min and
+ max sizes of the list. (Always returns a list.)
+
+ * 'tuple': matches any tuple.
+ Takes optional keyword args 'min', and 'max' to specify min and
+ max sizes of the tuple. (Always returns a tuple.)
+
+ * 'int_list': Matches a list of integers.
+ Takes the same arguments as list.
+
+ * 'float_list': Matches a list of floats.
+ Takes the same arguments as list.
+
+ * 'bool_list': Matches a list of boolean values.
+ Takes the same arguments as list.
+
+ * 'ip_addr_list': Matches a list of IP addresses.
+ Takes the same arguments as list.
+
+ * 'string_list': Matches a list of strings.
+ Takes the same arguments as list.
+
+ * 'mixed_list': Matches a list with different types in
+ specific positions. List size must match
+ the number of arguments.
+
+ Each position can be one of :
+ 'integer', 'float', 'ip_addr', 'string', 'boolean'
+
+ So to specify a list with two strings followed
+ by two integers, you write the check as : ::
+
+ mixed_list('string', 'string', 'integer', 'integer')
+
+ * 'pass': This check matches everything ! It never fails
+ and the value is unchanged.
+
+ It is also the default if no check is specified.
+
+ * 'option': This check matches any from a list of options.
+ You specify this check with : ::
+
+ option('option 1', 'option 2', 'option 3')
+
+ You can supply a default value (returned if no value is supplied)
+ using the default keyword argument.
+
+ You specify a list argument for default using a list constructor syntax in
+ the check : ::
+
+ checkname(arg1, arg2, default=list('val 1', 'val 2', 'val 3'))
+
+ A badly formatted set of arguments will raise a ``VdtParamError``.
+"""
+
+__docformat__ = "restructuredtext en"
+
+__version__ = '0.3.2'
+
+__revision__ = '$Id: validate.py 123 2005-09-08 08:54:28Z fuzzyman $'
+
+__all__ = (
+ '__version__',
+ 'dottedQuadToNum',
+ 'numToDottedQuad',
+ 'ValidateError',
+ 'VdtUnknownCheckError',
+ 'VdtParamError',
+ 'VdtTypeError',
+ 'VdtValueError',
+ 'VdtValueTooSmallError',
+ 'VdtValueTooBigError',
+ 'VdtValueTooShortError',
+ 'VdtValueTooLongError',
+ 'VdtMissingValue',
+ 'Validator',
+ 'is_integer',
+ 'is_float',
+ 'is_boolean',
+ 'is_list',
+ 'is_tuple',
+ 'is_ip_addr',
+ 'is_string',
+ 'is_int_list',
+ 'is_bool_list',
+ 'is_float_list',
+ 'is_string_list',
+ 'is_ip_addr_list',
+ 'is_mixed_list',
+ 'is_option',
+ '__docformat__',
+)
+
+
+import sys
+INTP_VER = sys.version_info[:2]
+if INTP_VER < (2, 2):
+ raise RuntimeError("Python v.2.2 or later needed")
+
+import re
+StringTypes = (str, unicode)
+
+
+_list_arg = re.compile(r'''
+ (?:
+ ([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*list\(
+ (
+ (?:
+ \s*
+ (?:
+ (?:".*?")| # double quotes
+ (?:'.*?')| # single quotes
+ (?:[^'",\s\)][^,\)]*?) # unquoted
+ )
+ \s*,\s*
+ )*
+ (?:
+ (?:".*?")| # double quotes
+ (?:'.*?')| # single quotes
+ (?:[^'",\s\)][^,\)]*?) # unquoted
+ )? # last one
+ )
+ \)
+ )
+''', re.VERBOSE) # two groups
+
+_list_members = re.compile(r'''
+ (
+ (?:".*?")| # double quotes
+ (?:'.*?')| # single quotes
+ (?:[^'",\s=][^,=]*?) # unquoted
+ )
+ (?:
+ (?:\s*,\s*)|(?:\s*$) # comma
+ )
+''', re.VERBOSE) # one group
+
+_paramstring = r'''
+ (?:
+ (
+ (?:
+ [a-zA-Z_][a-zA-Z0-9_]*\s*=\s*list\(
+ (?:
+ \s*
+ (?:
+ (?:".*?")| # double quotes
+ (?:'.*?')| # single quotes
+ (?:[^'",\s\)][^,\)]*?) # unquoted
+ )
+ \s*,\s*
+ )*
+ (?:
+ (?:".*?")| # double quotes
+ (?:'.*?')| # single quotes
+ (?:[^'",\s\)][^,\)]*?) # unquoted
+ )? # last one
+ \)
+ )|
+ (?:
+ (?:".*?")| # double quotes
+ (?:'.*?')| # single quotes
+ (?:[^'",\s=][^,=]*?)| # unquoted
+ (?: # keyword argument
+ [a-zA-Z_][a-zA-Z0-9_]*\s*=\s*
+ (?:
+ (?:".*?")| # double quotes
+ (?:'.*?')| # single quotes
+ (?:[^'",\s=][^,=]*?) # unquoted
+ )
+ )
+ )
+ )
+ (?:
+ (?:\s*,\s*)|(?:\s*$) # comma
+ )
+ )
+ '''
+
+_matchstring = '^%s*' % _paramstring
+
+# Python pre 2.2.1 doesn't have bool
+try:
+ bool
+except NameError:
+ def bool(val):
+ """Simple boolean equivalent function. """
+ if val:
+ return 1
+ else:
+ return 0
+
+
+def dottedQuadToNum(ip):
+ """
+ Convert decimal dotted quad string to long integer
+
+ >>> dottedQuadToNum('1 ')
+ 1L
+ >>> dottedQuadToNum(' 1.2')
+ 16777218L
+ >>> dottedQuadToNum(' 1.2.3 ')
+ 16908291L
+ >>> dottedQuadToNum('1.2.3.4')
+ 16909060L
+ >>> dottedQuadToNum('1.2.3. 4')
+ Traceback (most recent call last):
+ ValueError: Not a good dotted-quad IP: 1.2.3. 4
+ >>> dottedQuadToNum('255.255.255.255')
+ 4294967295L
+ >>> dottedQuadToNum('255.255.255.256')
+ Traceback (most recent call last):
+ ValueError: Not a good dotted-quad IP: 255.255.255.256
+ """
+
+ # import here to avoid it when ip_addr values are not used
+ import socket, struct
+
+ try:
+ return struct.unpack('!L',
+ socket.inet_aton(ip.strip()))[0]
+ except socket.error:
+ # bug in inet_aton, corrected in Python 2.3
+ if ip.strip() == '255.255.255.255':
+ return 0xFFFFFFFFL
+ else:
+ raise ValueError('Not a good dotted-quad IP: %s' % ip)
+ return
+
+
+def numToDottedQuad(num):
+ """
+ Convert long int to dotted quad string
+
+ >>> numToDottedQuad(-1L)
+ Traceback (most recent call last):
+ ValueError: Not a good numeric IP: -1
+ >>> numToDottedQuad(1L)
+ '0.0.0.1'
+ >>> numToDottedQuad(16777218L)
+ '1.0.0.2'
+ >>> numToDottedQuad(16908291L)
+ '1.2.0.3'
+ >>> numToDottedQuad(16909060L)
+ '1.2.3.4'
+ >>> numToDottedQuad(4294967295L)
+ '255.255.255.255'
+ >>> numToDottedQuad(4294967296L)
+ Traceback (most recent call last):
+ ValueError: Not a good numeric IP: 4294967296
+ """
+
+ # import here to avoid it when ip_addr values are not used
+ import socket, struct
+
+ # no need to intercept here, 4294967295L is fine
+ try:
+ return socket.inet_ntoa(
+ struct.pack('!L', long(num)))
+ except (socket.error, struct.error, OverflowError):
+ raise ValueError('Not a good numeric IP: %s' % num)
+
+
+class ValidateError(Exception):
+ """
+ This error indicates that the check failed.
+ It can be the base class for more specific errors.
+
+ Any check function that fails ought to raise this error.
+ (or a subclass)
+
+ >>> raise ValidateError
+ Traceback (most recent call last):
+ ValidateError
+ """
+
+
+class VdtMissingValue(ValidateError):
+ """No value was supplied to a check that needed one."""
+
+
+class VdtUnknownCheckError(ValidateError):
+ """An unknown check function was requested"""
+
+ def __init__(self, value):
+ """
+ >>> raise VdtUnknownCheckError('yoda')
+ Traceback (most recent call last):
+ VdtUnknownCheckError: the check "yoda" is unknown.
+ """
+ ValidateError.__init__(self, 'the check "%s" is unknown.' % (value,))
+
+
+class VdtParamError(SyntaxError):
+ """An incorrect parameter was passed"""
+
+ def __init__(self, name, value):
+ """
+ >>> raise VdtParamError('yoda', 'jedi')
+ Traceback (most recent call last):
+ VdtParamError: passed an incorrect value "jedi" for parameter "yoda".
+ """
+ SyntaxError.__init__(self, 'passed an incorrect value "%s" for parameter "%s".' % (value, name))
+
+
+class VdtTypeError(ValidateError):
+ """The value supplied was of the wrong type"""
+
+ def __init__(self, value):
+ """
+ >>> raise VdtTypeError('jedi')
+ Traceback (most recent call last):
+ VdtTypeError: the value "jedi" is of the wrong type.
+ """
+ ValidateError.__init__(self, 'the value "%s" is of the wrong type.' % (value,))
+
+
+class VdtValueError(ValidateError):
+ """The value supplied was of the correct type, but was not an allowed value."""
+
+ def __init__(self, value):
+ """
+ >>> raise VdtValueError('jedi')
+ Traceback (most recent call last):
+ VdtValueError: the value "jedi" is unacceptable.
+ """
+ ValidateError.__init__(self, 'the value "%s" is unacceptable.' % (value,))
+
+
+class VdtValueTooSmallError(VdtValueError):
+ """The value supplied was of the correct type, but was too small."""
+
+ def __init__(self, value):
+ """
+ >>> raise VdtValueTooSmallError('0')
+ Traceback (most recent call last):
+ VdtValueTooSmallError: the value "0" is too small.
+ """
+ ValidateError.__init__(self, 'the value "%s" is too small.' % (value,))
+
+
+class VdtValueTooBigError(VdtValueError):
+ """The value supplied was of the correct type, but was too big."""
+
+ def __init__(self, value):
+ """
+ >>> raise VdtValueTooBigError('1')
+ Traceback (most recent call last):
+ VdtValueTooBigError: the value "1" is too big.
+ """
+ ValidateError.__init__(self, 'the value "%s" is too big.' % (value,))
+
+
+class VdtValueTooShortError(VdtValueError):
+ """The value supplied was of the correct type, but was too short."""
+
+ def __init__(self, value):
+ """
+ >>> raise VdtValueTooShortError('jed')
+ Traceback (most recent call last):
+ VdtValueTooShortError: the value "jed" is too short.
+ """
+ ValidateError.__init__(
+ self,
+ 'the value "%s" is too short.' % (value,))
+
+
+class VdtValueTooLongError(VdtValueError):
+ """The value supplied was of the correct type, but was too long."""
+
+ def __init__(self, value):
+ """
+ >>> raise VdtValueTooLongError('jedie')
+ Traceback (most recent call last):
+ VdtValueTooLongError: the value "jedie" is too long.
+ """
+ ValidateError.__init__(self, 'the value "%s" is too long.' % (value,))
+
+
+class Validator(object):
+ """
+ Validator is an object that allows you to register a set of 'checks'.
+ These checks take input and test that it conforms to the check.
+
+ This can also involve converting the value from a string into
+ the correct datatype.
+
+ The ``check`` method takes an input string which configures which
+ check is to be used and applies that check to a supplied value.
+
+ An example input string would be:
+ 'int_range(param1, param2)'
+
+ You would then provide something like:
+
+ >>> def int_range_check(value, min, max):
+ ... # turn min and max from strings to integers
+ ... min = int(min)
+ ... max = int(max)
+ ... # check that value is of the correct type.
+ ... # possible valid inputs are integers or strings
+ ... # that represent integers
+ ... if not isinstance(value, (int, long, StringTypes)):
+ ... raise VdtTypeError(value)
+ ... elif isinstance(value, StringTypes):
+ ... # if we are given a string
+ ... # attempt to convert to an integer
+ ... try:
+ ... value = int(value)
+ ... except ValueError:
+ ... raise VdtValueError(value)
+ ... # check the value is between our constraints
+ ... if not min <= value:
+ ... raise VdtValueTooSmallError(value)
+ ... if not value <= max:
+ ... raise VdtValueTooBigError(value)
+ ... return value
+
+ >>> fdict = {'int_range': int_range_check}
+ >>> vtr1 = Validator(fdict)
+ >>> vtr1.check('int_range(20, 40)', '30')
+ 30
+ >>> vtr1.check('int_range(20, 40)', '60')
+ Traceback (most recent call last):
+ VdtValueTooBigError: the value "60" is too big.
+
+ New functions can be added with : ::
+
+ >>> vtr2 = Validator()
+ >>> vtr2.functions['int_range'] = int_range_check
+
+ Or by passing in a dictionary of functions when Validator
+ is instantiated.
+
+ Your functions *can* use keyword arguments,
+ but the first argument should always be 'value'.
+
+ If the function doesn't take additional arguments,
+ the parentheses are optional in the check.
+ It can be written with either of : ::
+
+ keyword = function_name
+ keyword = function_name()
+
+ The first program to utilise Validator() was Michael Foord's
+ ConfigObj, an alternative to ConfigParser which supports lists and
+ can validate a config file using a config schema.
+ For more details on using Validator with ConfigObj see:
+ http://www.voidspace.org.uk/python/configobj.html
+ """
+
+ # this regex does the initial parsing of the checks
+ _func_re = re.compile(r'(.+?)\((.*)\)')
+
+ # this regex takes apart keyword arguments
+ _key_arg = re.compile(r'^([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*(.*)$')
+
+
+ # this regex finds keyword=list(....) type values
+ _list_arg = _list_arg
+
+ # this regex takes individual values out of lists - in one pass
+ _list_members = _list_members
+
+ # These regexes check a set of arguments for validity
+ # and then pull the members out
+ _paramfinder = re.compile(_paramstring, re.VERBOSE)
+ _matchfinder = re.compile(_matchstring, re.VERBOSE)
+
+
+ def __init__(self, functions=None):
+ """
+ >>> vtri = Validator()
+ """
+ self.functions = {
+ '': self._pass,
+ 'integer': is_integer,
+ 'float': is_float,
+ 'boolean': is_boolean,
+ 'ip_addr': is_ip_addr,
+ 'string': is_string,
+ 'list': is_list,
+ 'tuple': is_tuple,
+ 'int_list': is_int_list,
+ 'float_list': is_float_list,
+ 'bool_list': is_bool_list,
+ 'ip_addr_list': is_ip_addr_list,
+ 'string_list': is_string_list,
+ 'mixed_list': is_mixed_list,
+ 'pass': self._pass,
+ 'option': is_option,
+ }
+ if functions is not None:
+ self.functions.update(functions)
+ # tekNico: for use by ConfigObj
+ self.baseErrorClass = ValidateError
+ self._cache = {}
+
+
+ def check(self, check, value, missing=False):
+ """
+ Usage: check(check, value)
+
+ Arguments:
+ check: string representing check to apply (including arguments)
+ value: object to be checked
+ Returns value, converted to correct type if necessary
+
+ If the check fails, raises a ``ValidateError`` subclass.
+
+ >>> vtor.check('yoda', '')
+ Traceback (most recent call last):
+ VdtUnknownCheckError: the check "yoda" is unknown.
+ >>> vtor.check('yoda()', '')
+ Traceback (most recent call last):
+ VdtUnknownCheckError: the check "yoda" is unknown.
+
+ >>> vtor.check('string(default="")', '', missing=True)
+ ''
+ """
+ fun_name, fun_args, fun_kwargs, default = self._parse_with_caching(check)
+
+ if missing:
+ if default is None:
+ # no information needed here - to be handled by caller
+ raise VdtMissingValue()
+ value = self._handle_none(default)
+
+ if value is None:
+ return None
+
+ return self._check_value(value, fun_name, fun_args, fun_kwargs)
+
+
+ def _handle_none(self, value):
+ if value == 'None':
+ value = None
+ elif value in ("'None'", '"None"'):
+ # Special case a quoted None
+ value = self._unquote(value)
+ return value
+
+
+ def _parse_with_caching(self, check):
+ if check in self._cache:
+ fun_name, fun_args, fun_kwargs, default = self._cache[check]
+ # We call list and dict below to work with *copies* of the data
+ # rather than the original (which are mutable of course)
+ fun_args = list(fun_args)
+ fun_kwargs = dict(fun_kwargs)
+ else:
+ fun_name, fun_args, fun_kwargs, default = self._parse_check(check)
+ fun_kwargs = dict((str(key), value) for (key, value) in fun_kwargs.items())
+ self._cache[check] = fun_name, list(fun_args), dict(fun_kwargs), default
+ return fun_name, fun_args, fun_kwargs, default
+
+
+ def _check_value(self, value, fun_name, fun_args, fun_kwargs):
+ try:
+ fun = self.functions[fun_name]
+ except KeyError:
+ raise VdtUnknownCheckError(fun_name)
+ else:
+ return fun(value, *fun_args, **fun_kwargs)
+
+
+ def _parse_check(self, check):
+ fun_match = self._func_re.match(check)
+ if fun_match:
+ fun_name = fun_match.group(1)
+ arg_string = fun_match.group(2)
+ arg_match = self._matchfinder.match(arg_string)
+ if arg_match is None:
+ # Bad syntax
+ raise VdtParamError('Bad syntax in check "%s".' % check)
+ fun_args = []
+ fun_kwargs = {}
+ # pull out args of group 2
+ for arg in self._paramfinder.findall(arg_string):
+ # args may need whitespace removing (before removing quotes)
+ arg = arg.strip()
+ listmatch = self._list_arg.match(arg)
+ if listmatch:
+ key, val = self._list_handle(listmatch)
+ fun_kwargs[key] = val
+ continue
+ keymatch = self._key_arg.match(arg)
+ if keymatch:
+ val = keymatch.group(2)
+ if not val in ("'None'", '"None"'):
+ # Special case a quoted None
+ val = self._unquote(val)
+ fun_kwargs[keymatch.group(1)] = val
+ continue
+
+ fun_args.append(self._unquote(arg))
+ else:
+ # allows for function names without (args)
+ return check, (), {}, None
+
+ # Default must be deleted if the value is specified too,
+ # otherwise the check function will get a spurious "default" keyword arg
+ try:
+ default = fun_kwargs.pop('default', None)
+ except AttributeError:
+ # Python 2.2 compatibility
+ default = None
+ try:
+ default = fun_kwargs['default']
+ del fun_kwargs['default']
+ except KeyError:
+ pass
+
+ return fun_name, fun_args, fun_kwargs, default
+
+
+ def _unquote(self, val):
+ """Unquote a value if necessary."""
+ if (len(val) >= 2) and (val[0] in ("'", '"')) and (val[0] == val[-1]):
+ val = val[1:-1]
+ return val
+
+
+ def _list_handle(self, listmatch):
+ """Take apart a ``keyword=list('val, 'val')`` type string."""
+ out = []
+ name = listmatch.group(1)
+ args = listmatch.group(2)
+ for arg in self._list_members.findall(args):
+ out.append(self._unquote(arg))
+ return name, out
+
+
+ def _pass(self, value):
+ """
+ Dummy check that always passes
+
+ >>> vtor.check('', 0)
+ 0
+ >>> vtor.check('', '0')
+ '0'
+ """
+ return value
+
+
+ def get_default_value(self, check):
+ """
+ Given a check, return the default value for the check
+ (converted to the right type).
+
+ If the check doesn't specify a default value then a
+ ``KeyError`` will be raised.
+ """
+ fun_name, fun_args, fun_kwargs, default = self._parse_with_caching(check)
+ if default is None:
+ raise KeyError('Check "%s" has no default value.' % check)
+ value = self._handle_none(default)
+ if value is None:
+ return value
+ return self._check_value(value, fun_name, fun_args, fun_kwargs)
+
+
+def _is_num_param(names, values, to_float=False):
+ """
+ Return numbers from inputs or raise VdtParamError.
+
+ Lets ``None`` pass through.
+ Pass in keyword argument ``to_float=True`` to
+ use float for the conversion rather than int.
+
+ >>> _is_num_param(('', ''), (0, 1.0))
+ [0, 1]
+ >>> _is_num_param(('', ''), (0, 1.0), to_float=True)
+ [0.0, 1.0]
+ >>> _is_num_param(('a'), ('a'))
+ Traceback (most recent call last):
+ VdtParamError: passed an incorrect value "a" for parameter "a".
+ """
+ fun = to_float and float or int
+ out_params = []
+ for (name, val) in zip(names, values):
+ if val is None:
+ out_params.append(val)
+ elif isinstance(val, (int, long, float, StringTypes)):
+ try:
+ out_params.append(fun(val))
+ except ValueError, e:
+ raise VdtParamError(name, val)
+ else:
+ raise VdtParamError(name, val)
+ return out_params
+
+
+# built in checks
+# you can override these by setting the appropriate name
+# in Validator.functions
+# note: if the params are specified wrongly in your input string,
+# you will also raise errors.
+
+def is_integer(value, min=None, max=None):
+ """
+ A check that tests that a given value is an integer (int, or long)
+ and optionally, between bounds. A negative value is accepted, while
+ a float will fail.
+
+ If the value is a string, then the conversion is done - if possible.
+ Otherwise a VdtError is raised.
+
+ >>> vtor.check('integer', '-1')
+ -1
+ >>> vtor.check('integer', '0')
+ 0
+ >>> vtor.check('integer', 9)
+ 9
+ >>> vtor.check('integer', 'a')
+ Traceback (most recent call last):
+ VdtTypeError: the value "a" is of the wrong type.
+ >>> vtor.check('integer', '2.2')
+ Traceback (most recent call last):
+ VdtTypeError: the value "2.2" is of the wrong type.
+ >>> vtor.check('integer(10)', '20')
+ 20
+ >>> vtor.check('integer(max=20)', '15')
+ 15
+ >>> vtor.check('integer(10)', '9')
+ Traceback (most recent call last):
+ VdtValueTooSmallError: the value "9" is too small.
+ >>> vtor.check('integer(10)', 9)
+ Traceback (most recent call last):
+ VdtValueTooSmallError: the value "9" is too small.
+ >>> vtor.check('integer(max=20)', '35')
+ Traceback (most recent call last):
+ VdtValueTooBigError: the value "35" is too big.
+ >>> vtor.check('integer(max=20)', 35)
+ Traceback (most recent call last):
+ VdtValueTooBigError: the value "35" is too big.
+ >>> vtor.check('integer(0, 9)', False)
+ 0
+ """
+ (min_val, max_val) = _is_num_param(('min', 'max'), (min, max))
+ if not isinstance(value, (int, long, StringTypes)):
+ raise VdtTypeError(value)
+ if isinstance(value, StringTypes):
+ # if it's a string - does it represent an integer ?
+ try:
+ value = int(value)
+ except ValueError:
+ raise VdtTypeError(value)
+ if (min_val is not None) and (value < min_val):
+ raise VdtValueTooSmallError(value)
+ if (max_val is not None) and (value > max_val):
+ raise VdtValueTooBigError(value)
+ return value
+
+
+def is_float(value, min=None, max=None):
+ """
+ A check that tests that a given value is a float
+ (an integer will be accepted), and optionally - that it is between bounds.
+
+ If the value is a string, then the conversion is done - if possible.
+ Otherwise a VdtError is raised.
+
+ This can accept negative values.
+
+ >>> vtor.check('float', '2')
+ 2.0
+
+ From now on we multiply the value to avoid comparing decimals
+
+ >>> vtor.check('float', '-6.8') * 10
+ -68.0
+ >>> vtor.check('float', '12.2') * 10
+ 122.0
+ >>> vtor.check('float', 8.4) * 10
+ 84.0
+ >>> vtor.check('float', 'a')
+ Traceback (most recent call last):
+ VdtTypeError: the value "a" is of the wrong type.
+ >>> vtor.check('float(10.1)', '10.2') * 10
+ 102.0
+ >>> vtor.check('float(max=20.2)', '15.1') * 10
+ 151.0
+ >>> vtor.check('float(10.0)', '9.0')
+ Traceback (most recent call last):
+ VdtValueTooSmallError: the value "9.0" is too small.
+ >>> vtor.check('float(max=20.0)', '35.0')
+ Traceback (most recent call last):
+ VdtValueTooBigError: the value "35.0" is too big.
+ """
+ (min_val, max_val) = _is_num_param(
+ ('min', 'max'), (min, max), to_float=True)
+ if not isinstance(value, (int, long, float, StringTypes)):
+ raise VdtTypeError(value)
+ if not isinstance(value, float):
+ # if it's a string - does it represent a float ?
+ try:
+ value = float(value)
+ except ValueError:
+ raise VdtTypeError(value)
+ if (min_val is not None) and (value < min_val):
+ raise VdtValueTooSmallError(value)
+ if (max_val is not None) and (value > max_val):
+ raise VdtValueTooBigError(value)
+ return value
+
+
+bool_dict = {
+ True: True, 'on': True, '1': True, 'true': True, 'yes': True,
+ False: False, 'off': False, '0': False, 'false': False, 'no': False,
+}
+
+
+def is_boolean(value):
+ """
+ Check if the value represents a boolean.
+
+ >>> vtor.check('boolean', 0)
+ 0
+ >>> vtor.check('boolean', False)
+ 0
+ >>> vtor.check('boolean', '0')
+ 0
+ >>> vtor.check('boolean', 'off')
+ 0
+ >>> vtor.check('boolean', 'false')
+ 0
+ >>> vtor.check('boolean', 'no')
+ 0
+ >>> vtor.check('boolean', 'nO')
+ 0
+ >>> vtor.check('boolean', 'NO')
+ 0
+ >>> vtor.check('boolean', 1)
+ 1
+ >>> vtor.check('boolean', True)
+ 1
+ >>> vtor.check('boolean', '1')
+ 1
+ >>> vtor.check('boolean', 'on')
+ 1
+ >>> vtor.check('boolean', 'true')
+ 1
+ >>> vtor.check('boolean', 'yes')
+ 1
+ >>> vtor.check('boolean', 'Yes')
+ 1
+ >>> vtor.check('boolean', 'YES')
+ 1
+ >>> vtor.check('boolean', '')
+ Traceback (most recent call last):
+ VdtTypeError: the value "" is of the wrong type.
+ >>> vtor.check('boolean', 'up')
+ Traceback (most recent call last):
+ VdtTypeError: the value "up" is of the wrong type.
+
+ """
+ if isinstance(value, StringTypes):
+ try:
+ return bool_dict[value.lower()]
+ except KeyError:
+ raise VdtTypeError(value)
+ # we do an equality test rather than an identity test
+ # this ensures Python 2.2 compatibilty
+ # and allows 0 and 1 to represent True and False
+ if value == False:
+ return False
+ elif value == True:
+ return True
+ else:
+ raise VdtTypeError(value)
+
+
+def is_ip_addr(value):
+ """
+ Check that the supplied value is an Internet Protocol address, v.4,
+ represented by a dotted-quad string, i.e. '1.2.3.4'.
+
+ >>> vtor.check('ip_addr', '1 ')
+ '1'
+ >>> vtor.check('ip_addr', ' 1.2')
+ '1.2'
+ >>> vtor.check('ip_addr', ' 1.2.3 ')
+ '1.2.3'
+ >>> vtor.check('ip_addr', '1.2.3.4')
+ '1.2.3.4'
+ >>> vtor.check('ip_addr', '0.0.0.0')
+ '0.0.0.0'
+ >>> vtor.check('ip_addr', '255.255.255.255')
+ '255.255.255.255'
+ >>> vtor.check('ip_addr', '255.255.255.256')
+ Traceback (most recent call last):
+ VdtValueError: the value "255.255.255.256" is unacceptable.
+ >>> vtor.check('ip_addr', '1.2.3.4.5')
+ Traceback (most recent call last):
+ VdtValueError: the value "1.2.3.4.5" is unacceptable.
+ >>> vtor.check('ip_addr', '1.2.3. 4')
+ Traceback (most recent call last):
+ VdtValueError: the value "1.2.3. 4" is unacceptable.
+ >>> vtor.check('ip_addr', 0)
+ Traceback (most recent call last):
+ VdtTypeError: the value "0" is of the wrong type.
+ """
+ if not isinstance(value, StringTypes):
+ raise VdtTypeError(value)
+ value = value.strip()
+ try:
+ dottedQuadToNum(value)
+ except ValueError:
+ raise VdtValueError(value)
+ return value
+
+
+def is_list(value, min=None, max=None):
+ """
+ Check that the value is a list of values.
+
+ You can optionally specify the minimum and maximum number of members.
+
+ It does no check on list members.
+
+ >>> vtor.check('list', ())
+ []
+ >>> vtor.check('list', [])
+ []
+ >>> vtor.check('list', (1, 2))
+ [1, 2]
+ >>> vtor.check('list', [1, 2])
+ [1, 2]
+ >>> vtor.check('list(3)', (1, 2))
+ Traceback (most recent call last):
+ VdtValueTooShortError: the value "(1, 2)" is too short.
+ >>> vtor.check('list(max=5)', (1, 2, 3, 4, 5, 6))
+ Traceback (most recent call last):
+ VdtValueTooLongError: the value "(1, 2, 3, 4, 5, 6)" is too long.
+ >>> vtor.check('list(min=3, max=5)', (1, 2, 3, 4))
+ [1, 2, 3, 4]
+ >>> vtor.check('list', 0)
+ Traceback (most recent call last):
+ VdtTypeError: the value "0" is of the wrong type.
+ >>> vtor.check('list', '12')
+ Traceback (most recent call last):
+ VdtTypeError: the value "12" is of the wrong type.
+ """
+ (min_len, max_len) = _is_num_param(('min', 'max'), (min, max))
+ if isinstance(value, StringTypes):
+ raise VdtTypeError(value)
+ try:
+ num_members = len(value)
+ except TypeError:
+ raise VdtTypeError(value)
+ if min_len is not None and num_members < min_len:
+ raise VdtValueTooShortError(value)
+ if max_len is not None and num_members > max_len:
+ raise VdtValueTooLongError(value)
+ return list(value)
+
+
+def is_tuple(value, min=None, max=None):
+ """
+ Check that the value is a tuple of values.
+
+ You can optionally specify the minimum and maximum number of members.
+
+ It does no check on members.
+
+ >>> vtor.check('tuple', ())
+ ()
+ >>> vtor.check('tuple', [])
+ ()
+ >>> vtor.check('tuple', (1, 2))
+ (1, 2)
+ >>> vtor.check('tuple', [1, 2])
+ (1, 2)
+ >>> vtor.check('tuple(3)', (1, 2))
+ Traceback (most recent call last):
+ VdtValueTooShortError: the value "(1, 2)" is too short.
+ >>> vtor.check('tuple(max=5)', (1, 2, 3, 4, 5, 6))
+ Traceback (most recent call last):
+ VdtValueTooLongError: the value "(1, 2, 3, 4, 5, 6)" is too long.
+ >>> vtor.check('tuple(min=3, max=5)', (1, 2, 3, 4))
+ (1, 2, 3, 4)
+ >>> vtor.check('tuple', 0)
+ Traceback (most recent call last):
+ VdtTypeError: the value "0" is of the wrong type.
+ >>> vtor.check('tuple', '12')
+ Traceback (most recent call last):
+ VdtTypeError: the value "12" is of the wrong type.
+ """
+ return tuple(is_list(value, min, max))
+
+
+def is_string(value, min=None, max=None):
+ """
+ Check that the supplied value is a string.
+
+ You can optionally specify the minimum and maximum number of members.
+
+ >>> vtor.check('string', '0')
+ '0'
+ >>> vtor.check('string', 0)
+ Traceback (most recent call last):
+ VdtTypeError: the value "0" is of the wrong type.
+ >>> vtor.check('string(2)', '12')
+ '12'
+ >>> vtor.check('string(2)', '1')
+ Traceback (most recent call last):
+ VdtValueTooShortError: the value "1" is too short.
+ >>> vtor.check('string(min=2, max=3)', '123')
+ '123'
+ >>> vtor.check('string(min=2, max=3)', '1234')
+ Traceback (most recent call last):
+ VdtValueTooLongError: the value "1234" is too long.
+ """
+ if not isinstance(value, StringTypes):
+ raise VdtTypeError(value)
+ (min_len, max_len) = _is_num_param(('min', 'max'), (min, max))
+ try:
+ num_members = len(value)
+ except TypeError:
+ raise VdtTypeError(value)
+ if min_len is not None and num_members < min_len:
+ raise VdtValueTooShortError(value)
+ if max_len is not None and num_members > max_len:
+ raise VdtValueTooLongError(value)
+ return value
+
+
+def is_int_list(value, min=None, max=None):
+ """
+ Check that the value is a list of integers.
+
+ You can optionally specify the minimum and maximum number of members.
+
+ Each list member is checked that it is an integer.
+
+ >>> vtor.check('int_list', ())
+ []
+ >>> vtor.check('int_list', [])
+ []
+ >>> vtor.check('int_list', (1, 2))
+ [1, 2]
+ >>> vtor.check('int_list', [1, 2])
+ [1, 2]
+ >>> vtor.check('int_list', [1, 'a'])
+ Traceback (most recent call last):
+ VdtTypeError: the value "a" is of the wrong type.
+ """
+ return [is_integer(mem) for mem in is_list(value, min, max)]
+
+
+def is_bool_list(value, min=None, max=None):
+ """
+ Check that the value is a list of booleans.
+
+ You can optionally specify the minimum and maximum number of members.
+
+ Each list member is checked that it is a boolean.
+
+ >>> vtor.check('bool_list', ())
+ []
+ >>> vtor.check('bool_list', [])
+ []
+ >>> check_res = vtor.check('bool_list', (True, False))
+ >>> check_res == [True, False]
+ 1
+ >>> check_res = vtor.check('bool_list', [True, False])
+ >>> check_res == [True, False]
+ 1
+ >>> vtor.check('bool_list', [True, 'a'])
+ Traceback (most recent call last):
+ VdtTypeError: the value "a" is of the wrong type.
+ """
+ return [is_boolean(mem) for mem in is_list(value, min, max)]
+
+
+def is_float_list(value, min=None, max=None):
+ """
+ Check that the value is a list of floats.
+
+ You can optionally specify the minimum and maximum number of members.
+
+ Each list member is checked that it is a float.
+
+ >>> vtor.check('float_list', ())
+ []
+ >>> vtor.check('float_list', [])
+ []
+ >>> vtor.check('float_list', (1, 2.0))
+ [1.0, 2.0]
+ >>> vtor.check('float_list', [1, 2.0])
+ [1.0, 2.0]
+ >>> vtor.check('float_list', [1, 'a'])
+ Traceback (most recent call last):
+ VdtTypeError: the value "a" is of the wrong type.
+ """
+ return [is_float(mem) for mem in is_list(value, min, max)]
+
+
+def is_string_list(value, min=None, max=None):
+ """
+ Check that the value is a list of strings.
+
+ You can optionally specify the minimum and maximum number of members.
+
+ Each list member is checked that it is a string.
+
+ >>> vtor.check('string_list', ())
+ []
+ >>> vtor.check('string_list', [])
+ []
+ >>> vtor.check('string_list', ('a', 'b'))
+ ['a', 'b']
+ >>> vtor.check('string_list', ['a', 1])
+ Traceback (most recent call last):
+ VdtTypeError: the value "1" is of the wrong type.
+ >>> vtor.check('string_list', 'hello')
+ Traceback (most recent call last):
+ VdtTypeError: the value "hello" is of the wrong type.
+ """
+ if isinstance(value, StringTypes):
+ raise VdtTypeError(value)
+ return [is_string(mem) for mem in is_list(value, min, max)]
+
+
+def is_ip_addr_list(value, min=None, max=None):
+ """
+ Check that the value is a list of IP addresses.
+
+ You can optionally specify the minimum and maximum number of members.
+
+ Each list member is checked that it is an IP address.
+
+ >>> vtor.check('ip_addr_list', ())
+ []
+ >>> vtor.check('ip_addr_list', [])
+ []
+ >>> vtor.check('ip_addr_list', ('1.2.3.4', '5.6.7.8'))
+ ['1.2.3.4', '5.6.7.8']
+ >>> vtor.check('ip_addr_list', ['a'])
+ Traceback (most recent call last):
+ VdtValueError: the value "a" is unacceptable.
+ """
+ return [is_ip_addr(mem) for mem in is_list(value, min, max)]
+
+
+fun_dict = {
+ 'integer': is_integer,
+ 'float': is_float,
+ 'ip_addr': is_ip_addr,
+ 'string': is_string,
+ 'boolean': is_boolean,
+}
+
+
+def is_mixed_list(value, *args):
+ """
+ Check that the value is a list.
+ Allow specifying the type of each member.
+ Work on lists of specific lengths.
+
+ You specify each member as a positional argument specifying type
+
+ Each type should be one of the following strings :
+ 'integer', 'float', 'ip_addr', 'string', 'boolean'
+
+ So you can specify a list of two strings, followed by
+ two integers as :
+
+ mixed_list('string', 'string', 'integer', 'integer')
+
+ The length of the list must match the number of positional
+ arguments you supply.
+
+ >>> mix_str = "mixed_list('integer', 'float', 'ip_addr', 'string', 'boolean')"
+ >>> check_res = vtor.check(mix_str, (1, 2.0, '1.2.3.4', 'a', True))
+ >>> check_res == [1, 2.0, '1.2.3.4', 'a', True]
+ 1
+ >>> check_res = vtor.check(mix_str, ('1', '2.0', '1.2.3.4', 'a', 'True'))
+ >>> check_res == [1, 2.0, '1.2.3.4', 'a', True]
+ 1
+ >>> vtor.check(mix_str, ('b', 2.0, '1.2.3.4', 'a', True))
+ Traceback (most recent call last):
+ VdtTypeError: the value "b" is of the wrong type.
+ >>> vtor.check(mix_str, (1, 2.0, '1.2.3.4', 'a'))
+ Traceback (most recent call last):
+ VdtValueTooShortError: the value "(1, 2.0, '1.2.3.4', 'a')" is too short.
+ >>> vtor.check(mix_str, (1, 2.0, '1.2.3.4', 'a', 1, 'b'))
+ Traceback (most recent call last):
+ VdtValueTooLongError: the value "(1, 2.0, '1.2.3.4', 'a', 1, 'b')" is too long.
+ >>> vtor.check(mix_str, 0)
+ Traceback (most recent call last):
+ VdtTypeError: the value "0" is of the wrong type.
+
+ This test requires an elaborate setup, because of a change in error string
+ output from the interpreter between Python 2.2 and 2.3 .
+
+ >>> res_seq = (
+ ... 'passed an incorrect value "',
+ ... 'yoda',
+ ... '" for parameter "mixed_list".',
+ ... )
+ >>> if INTP_VER == (2, 2):
+ ... res_str = "".join(res_seq)
+ ... else:
+ ... res_str = "'".join(res_seq)
+ >>> try:
+ ... vtor.check('mixed_list("yoda")', ('a'))
+ ... except VdtParamError, err:
+ ... str(err) == res_str
+ 1
+ """
+ try:
+ length = len(value)
+ except TypeError:
+ raise VdtTypeError(value)
+ if length < len(args):
+ raise VdtValueTooShortError(value)
+ elif length > len(args):
+ raise VdtValueTooLongError(value)
+ try:
+ return [fun_dict[arg](val) for arg, val in zip(args, value)]
+ except KeyError, e:
+ raise VdtParamError('mixed_list', e)
+
+
+def is_option(value, *options):
+ """
+ This check matches the value to any of a set of options.
+
+ >>> vtor.check('option("yoda", "jedi")', 'yoda')
+ 'yoda'
+ >>> vtor.check('option("yoda", "jedi")', 'jed')
+ Traceback (most recent call last):
+ VdtValueError: the value "jed" is unacceptable.
+ >>> vtor.check('option("yoda", "jedi")', 0)
+ Traceback (most recent call last):
+ VdtTypeError: the value "0" is of the wrong type.
+ """
+ if not isinstance(value, StringTypes):
+ raise VdtTypeError(value)
+ if not value in options:
+ raise VdtValueError(value)
+ return value
+
+
+def _test(value, *args, **keywargs):
+ """
+ A function that exists for test purposes.
+
+ >>> checks = [
+ ... '3, 6, min=1, max=3, test=list(a, b, c)',
+ ... '3',
+ ... '3, 6',
+ ... '3,',
+ ... 'min=1, test="a b c"',
+ ... 'min=5, test="a, b, c"',
+ ... 'min=1, max=3, test="a, b, c"',
+ ... 'min=-100, test=-99',
+ ... 'min=1, max=3',
+ ... '3, 6, test="36"',
+ ... '3, 6, test="a, b, c"',
+ ... '3, max=3, test=list("a", "b", "c")',
+ ... '''3, max=3, test=list("'a'", 'b', "x=(c)")''',
+ ... "test='x=fish(3)'",
+ ... ]
+ >>> v = Validator({'test': _test})
+ >>> for entry in checks:
+ ... print v.check(('test(%s)' % entry), 3)
+ (3, ('3', '6'), {'test': ['a', 'b', 'c'], 'max': '3', 'min': '1'})
+ (3, ('3',), {})
+ (3, ('3', '6'), {})
+ (3, ('3',), {})
+ (3, (), {'test': 'a b c', 'min': '1'})
+ (3, (), {'test': 'a, b, c', 'min': '5'})
+ (3, (), {'test': 'a, b, c', 'max': '3', 'min': '1'})
+ (3, (), {'test': '-99', 'min': '-100'})
+ (3, (), {'max': '3', 'min': '1'})
+ (3, ('3', '6'), {'test': '36'})
+ (3, ('3', '6'), {'test': 'a, b, c'})
+ (3, ('3',), {'test': ['a', 'b', 'c'], 'max': '3'})
+ (3, ('3',), {'test': ["'a'", 'b', 'x=(c)'], 'max': '3'})
+ (3, (), {'test': 'x=fish(3)'})
+
+ >>> v = Validator()
+ >>> v.check('integer(default=6)', '3')
+ 3
+ >>> v.check('integer(default=6)', None, True)
+ 6
+ >>> v.get_default_value('integer(default=6)')
+ 6
+ >>> v.get_default_value('float(default=6)')
+ 6.0
+ >>> v.get_default_value('pass(default=None)')
+ >>> v.get_default_value("string(default='None')")
+ 'None'
+ >>> v.get_default_value('pass')
+ Traceback (most recent call last):
+ KeyError: 'Check "pass" has no default value.'
+ >>> v.get_default_value('pass(default=list(1, 2, 3, 4))')
+ ['1', '2', '3', '4']
+
+ >>> v = Validator()
+ >>> v.check("pass(default=None)", None, True)
+ >>> v.check("pass(default='None')", None, True)
+ 'None'
+ >>> v.check('pass(default="None")', None, True)
+ 'None'
+ >>> v.check('pass(default=list(1, 2, 3, 4))', None, True)
+ ['1', '2', '3', '4']
+
+ Bug test for unicode arguments
+ >>> v = Validator()
+ >>> v.check(u'string(min=4)', u'test')
+ u'test'
+
+ >>> v = Validator()
+ >>> v.get_default_value(u'string(min=4, default="1234")')
+ u'1234'
+ >>> v.check(u'string(min=4, default="1234")', u'test')
+ u'test'
+
+ >>> v = Validator()
+ >>> default = v.get_default_value('string(default=None)')
+ >>> default == None
+ 1
+ """
+ return (value, args, keywargs)
+
+
+if __name__ == '__main__':
+ # run the code tests in doctest format
+ import doctest
+ m = sys.modules.get('__main__')
+ globs = m.__dict__.copy()
+ globs.update({
+ 'INTP_VER': INTP_VER,
+ 'vtor': Validator(),
+ })
+ doctest.testmod(m, globs=globs)
diff --git a/IPython/frontend/__init__.py b/IPython/frontend/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/IPython/frontend/__init__.py
diff --git a/IPython/frontend/asyncfrontendbase.py b/IPython/frontend/asyncfrontendbase.py
new file mode 100644
index 0000000..1171a83
--- /dev/null
+++ b/IPython/frontend/asyncfrontendbase.py
@@ -0,0 +1,82 @@
+"""
+Base front end class for all async frontends.
+"""
+__docformat__ = "restructuredtext en"
+
+# Tell nose to skip this module
+__test__ = {}
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+# Third-party
+from twisted.python.failure import Failure
+from zope.interface import implements, classProvides
+
+# From IPython
+from IPython.external import guid
+
+from IPython.frontend.frontendbase import (FrontEndBase, IFrontEnd,
+ IFrontEndFactory)
+from IPython.kernel.core.history import FrontEndHistory
+from IPython.kernel.engineservice import IEngineCore
+
+#-----------------------------------------------------------------------------
+# Classes and functions
+#-----------------------------------------------------------------------------
+
+class AsyncFrontEndBase(FrontEndBase):
+ """
+ Overrides FrontEndBase to wrap execute in a deferred result.
+ All callbacks are made as callbacks on the deferred result.
+ """
+
+ implements(IFrontEnd)
+ classProvides(IFrontEndFactory)
+
+ def __init__(self, engine=None, history=None):
+ assert(engine==None or IEngineCore.providedBy(engine))
+ self.engine = IEngineCore(engine)
+ if history is None:
+ self.history = FrontEndHistory(input_cache=[''])
+ else:
+ self.history = history
+
+ def execute(self, block, blockID=None):
+ """Execute the block and return the deferred result.
+
+ Parameters:
+ block : {str, AST}
+ blockID : any
+ Caller may provide an ID to identify this block.
+ result['blockID'] := blockID
+
+ Result:
+ Deferred result of self.interpreter.execute
+ """
+
+ if(not self.is_complete(block)):
+ return Failure(Exception("Block is not compilable"))
+
+ if(blockID == None):
+ blockID = guid.generate()
+
+ d = self.engine.execute(block)
+ d.addCallback(self._add_history, block=block)
+ d.addCallbacks(self._add_block_id_for_result,
+ errback=self._add_block_id_for_failure,
+ callbackArgs=(blockID,),
+ errbackArgs=(blockID,))
+ d.addBoth(self.update_cell_prompt, blockID=blockID)
+ d.addCallbacks(self.render_result,
+ errback=self.render_error)
+
+ return d
diff --git a/IPython/frontend/cocoa/__init__.py b/IPython/frontend/cocoa/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/IPython/frontend/cocoa/__init__.py
diff --git a/IPython/frontend/cocoa/cocoa_frontend.py b/IPython/frontend/cocoa/cocoa_frontend.py
new file mode 100644
index 0000000..349e794
--- /dev/null
+++ b/IPython/frontend/cocoa/cocoa_frontend.py
@@ -0,0 +1,560 @@
+# encoding: utf-8
+# -*- test-case-name: IPython.frontend.cocoa.tests.test_cocoa_frontend -*-
+
+"""PyObjC classes to provide a Cocoa frontend to the
+IPython.kernel.engineservice.IEngineBase.
+
+To add an IPython interpreter to a cocoa app, instantiate an
+IPythonCocoaController in a XIB and connect its textView outlet to an
+NSTextView instance in your UI. That's it.
+
+Author: Barry Wark
+"""
+
+__docformat__ = "restructuredtext en"
+
+#-----------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+import sys
+import objc
+from IPython.external import guid
+
+from Foundation import NSObject, NSMutableArray, NSMutableDictionary,\
+ NSLog, NSNotificationCenter, NSMakeRange,\
+ NSLocalizedString, NSIntersectionRange,\
+ NSString, NSAutoreleasePool
+
+from AppKit import NSApplicationWillTerminateNotification, NSBeep,\
+ NSTextView, NSRulerView, NSVerticalRuler
+
+from pprint import saferepr
+
+import IPython
+from IPython.kernel.engineservice import ThreadedEngineService
+from IPython.frontend.asyncfrontendbase import AsyncFrontEndBase
+
+from twisted.internet.threads import blockingCallFromThread
+from twisted.python.failure import Failure
+
+#-----------------------------------------------------------------------------
+# Classes to implement the Cocoa frontend
+#-----------------------------------------------------------------------------
+
+# TODO:
+# 1. use MultiEngineClient and out-of-process engine rather than
+# ThreadedEngineService?
+# 2. integrate Xgrid launching of engines
+
+class AutoreleasePoolWrappedThreadedEngineService(ThreadedEngineService):
+ """Wrap all blocks in an NSAutoreleasePool"""
+
+ def wrapped_execute(self, msg, lines):
+ """wrapped_execute"""
+ try:
+ p = NSAutoreleasePool.alloc().init()
+ result = super(AutoreleasePoolWrappedThreadedEngineService,
+ self).wrapped_execute(msg, lines)
+ finally:
+ p.drain()
+
+ return result
+
+
+
+class Cell(NSObject):
+ """
+ Representation of the prompts, input and output of a cell in the
+ frontend
+ """
+
+ blockNumber = objc.ivar().unsigned_long()
+ blockID = objc.ivar()
+ inputBlock = objc.ivar()
+ output = objc.ivar()
+
+
+
+class CellBlock(object):
+ """
+ Storage for information about text ranges relating to a single cell
+ """
+
+
+ def __init__(self, inputPromptRange, inputRange=None, outputPromptRange=None,
+ outputRange=None):
+ super(CellBlock, self).__init__()
+ self.inputPromptRange = inputPromptRange
+ self.inputRange = inputRange
+ self.outputPromptRange = outputPromptRange
+ self.outputRange = outputRange
+
+ def update_ranges_for_insertion(self, text, textRange):
+ """Update ranges for text insertion at textRange"""
+
+ for r in [self.inputPromptRange,self.inputRange,
+ self.outputPromptRange, self.outputRange]:
+ if(r == None):
+ continue
+ intersection = NSIntersectionRange(r,textRange)
+ if(intersection.length == 0): #ranges don't intersect
+ if r.location >= textRange.location:
+ r.location += len(text)
+ else: #ranges intersect
+ if(r.location > textRange.location):
+ offset = len(text) - intersection.length
+ r.length -= offset
+ r.location += offset
+ elif(r.location == textRange.location):
+ r.length += len(text) - intersection.length
+ else:
+ r.length -= intersection.length
+
+
+ def update_ranges_for_deletion(self, textRange):
+ """Update ranges for text deletion at textRange"""
+
+ for r in [self.inputPromptRange,self.inputRange,
+ self.outputPromptRange, self.outputRange]:
+ if(r==None):
+ continue
+ intersection = NSIntersectionRange(r, textRange)
+ if(intersection.length == 0): #ranges don't intersect
+ if r.location >= textRange.location:
+ r.location -= textRange.length
+ else: #ranges intersect
+ if(r.location > textRange.location):
+ offset = intersection.length
+ r.length -= offset
+ r.location += offset
+ elif(r.location == textRange.location):
+ r.length += intersection.length
+ else:
+ r.length -= intersection.length
+
+ def __repr__(self):
+ return 'CellBlock('+ str((self.inputPromptRange,
+ self.inputRange,
+ self.outputPromptRange,
+ self.outputRange)) + ')'
+
+
+
+
+class IPythonCocoaController(NSObject, AsyncFrontEndBase):
+ userNS = objc.ivar() #mirror of engine.user_ns (key=>str(value))
+ waitingForEngine = objc.ivar().bool()
+ textView = objc.IBOutlet()
+
+ def init(self):
+ self = super(IPythonCocoaController, self).init()
+ AsyncFrontEndBase.__init__(self,
+ engine=AutoreleasePoolWrappedThreadedEngineService())
+ if(self != None):
+ self._common_init()
+
+ return self
+
+ def _common_init(self):
+ """_common_init"""
+
+ self.userNS = NSMutableDictionary.dictionary()
+ self.waitingForEngine = False
+
+ self.lines = {}
+ self.tabSpaces = 4
+ self.tabUsesSpaces = True
+ self.currentBlockID = self.next_block_ID()
+ self.blockRanges = {} # blockID=>CellBlock
+
+
+ def awakeFromNib(self):
+ """awakeFromNib"""
+
+ self._common_init()
+
+ # Start the IPython engine
+ self.engine.startService()
+ NSLog('IPython engine started')
+
+ # Register for app termination
+ nc = NSNotificationCenter.defaultCenter()
+ nc.addObserver_selector_name_object_(
+ self,
+ 'appWillTerminate:',
+ NSApplicationWillTerminateNotification,
+ None)
+
+ self.textView.setDelegate_(self)
+ self.textView.enclosingScrollView().setHasVerticalRuler_(True)
+ r = NSRulerView.alloc().initWithScrollView_orientation_(
+ self.textView.enclosingScrollView(),
+ NSVerticalRuler)
+ self.verticalRulerView = r
+ self.verticalRulerView.setClientView_(self.textView)
+ self._start_cli_banner()
+ self.start_new_block()
+
+
+ def appWillTerminate_(self, notification):
+ """appWillTerminate"""
+
+ self.engine.stopService()
+
+
+ def complete(self, token):
+ """Complete token in engine's user_ns
+
+ Parameters
+ ----------
+ token : string
+
+ Result
+ ------
+ Deferred result of
+ IPython.kernel.engineservice.IEngineBase.complete
+ """
+
+ return self.engine.complete(token)
+
+
+ def execute(self, block, blockID=None):
+ self.waitingForEngine = True
+ self.willChangeValueForKey_('commandHistory')
+ d = super(IPythonCocoaController, self).execute(block,
+ blockID)
+ d.addBoth(self._engine_done)
+ d.addCallback(self._update_user_ns)
+
+ return d
+
+
+ def push_(self, namespace):
+ """Push dictionary of key=>values to python namespace"""
+
+ self.waitingForEngine = True
+ self.willChangeValueForKey_('commandHistory')
+ d = self.engine.push(namespace)
+ d.addBoth(self._engine_done)
+ d.addCallback(self._update_user_ns)
+
+
+ def pull_(self, keys):
+ """Pull keys from python namespace"""
+
+ self.waitingForEngine = True
+ result = blockingCallFromThread(self.engine.pull, keys)
+ self.waitingForEngine = False
+
+ @objc.signature('v@:@I')
+ def executeFileAtPath_encoding_(self, path, encoding):
+ """Execute file at path in an empty namespace. Update the engine
+ user_ns with the resulting locals."""
+
+ lines,err = NSString.stringWithContentsOfFile_encoding_error_(
+ path,
+ encoding,
+ None)
+ self.engine.execute(lines)
+
+
+ def _engine_done(self, x):
+ self.waitingForEngine = False
+ self.didChangeValueForKey_('commandHistory')
+ return x
+
+ def _update_user_ns(self, result):
+ """Update self.userNS from self.engine's namespace"""
+ d = self.engine.keys()
+ d.addCallback(self._get_engine_namespace_values_for_keys)
+
+ return result
+
+
+ def _get_engine_namespace_values_for_keys(self, keys):
+ d = self.engine.pull(keys)
+ d.addCallback(self._store_engine_namespace_values, keys=keys)
+
+
+ def _store_engine_namespace_values(self, values, keys=[]):
+ assert(len(values) == len(keys))
+ self.willChangeValueForKey_('userNS')
+ for (k,v) in zip(keys,values):
+ self.userNS[k] = saferepr(v)
+ self.didChangeValueForKey_('userNS')
+
+
+ def update_cell_prompt(self, result, blockID=None):
+ print self.blockRanges
+ if(isinstance(result, Failure)):
+ prompt = self.input_prompt()
+
+ else:
+ prompt = self.input_prompt(number=result['number'])
+
+ r = self.blockRanges[blockID].inputPromptRange
+ self.insert_text(prompt,
+ textRange=r,
+ scrollToVisible=False
+ )
+
+ return result
+
+
+ def render_result(self, result):
+ blockID = result['blockID']
+ inputRange = self.blockRanges[blockID].inputRange
+ del self.blockRanges[blockID]
+
+ #print inputRange,self.current_block_range()
+ self.insert_text('\n' +
+ self.output_prompt(number=result['number']) +
+ result.get('display',{}).get('pprint','') +
+ '\n\n',
+ textRange=NSMakeRange(inputRange.location+inputRange.length,
+ 0))
+ return result
+
+
+ def render_error(self, failure):
+ print failure
+ blockID = failure.blockID
+ inputRange = self.blockRanges[blockID].inputRange
+ self.insert_text('\n' +
+ self.output_prompt() +
+ '\n' +
+ failure.getErrorMessage() +
+ '\n\n',
+ textRange=NSMakeRange(inputRange.location +
+ inputRange.length,
+ 0))
+ self.start_new_block()
+ return failure
+
+
+ def _start_cli_banner(self):
+ """Print banner"""
+
+ banner = """IPython1 %s -- An enhanced Interactive Python.""" % \
+ IPython.__version__
+
+ self.insert_text(banner + '\n\n')
+
+
+ def start_new_block(self):
+ """"""
+
+ self.currentBlockID = self.next_block_ID()
+ self.blockRanges[self.currentBlockID] = self.new_cell_block()
+ self.insert_text(self.input_prompt(),
+ textRange=self.current_block_range().inputPromptRange)
+
+
+
+ def next_block_ID(self):
+
+ return guid.generate()
+
+ def new_cell_block(self):
+ """A new CellBlock at the end of self.textView.textStorage()"""
+
+ return CellBlock(NSMakeRange(self.textView.textStorage().length(),
+ 0), #len(self.input_prompt())),
+ NSMakeRange(self.textView.textStorage().length(),# + len(self.input_prompt()),
+ 0))
+
+
+ def current_block_range(self):
+ return self.blockRanges.get(self.currentBlockID,
+ self.new_cell_block())
+
+ def current_block(self):
+ """The current block's text"""
+
+ return self.text_for_range(self.current_block_range().inputRange)
+
+ def text_for_range(self, textRange):
+ """text_for_range"""
+
+ ts = self.textView.textStorage()
+ return ts.string().substringWithRange_(textRange)
+
+ def current_line(self):
+ block = self.text_for_range(self.current_block_range().inputRange)
+ block = block.split('\n')
+ return block[-1]
+
+
+ def insert_text(self, string=None, textRange=None, scrollToVisible=True):
+ """Insert text into textView at textRange, updating blockRanges
+ as necessary
+ """
+ if(textRange == None):
+ #range for end of text
+ textRange = NSMakeRange(self.textView.textStorage().length(), 0)
+
+
+ self.textView.replaceCharactersInRange_withString_(
+ textRange, string)
+
+ for r in self.blockRanges.itervalues():
+ r.update_ranges_for_insertion(string, textRange)
+
+ self.textView.setSelectedRange_(textRange)
+ if(scrollToVisible):
+ self.textView.scrollRangeToVisible_(textRange)
+
+
+
+ def replace_current_block_with_string(self, textView, string):
+ textView.replaceCharactersInRange_withString_(
+ self.current_block_range().inputRange,
+ string)
+ self.current_block_range().inputRange.length = len(string)
+ r = NSMakeRange(textView.textStorage().length(), 0)
+ textView.scrollRangeToVisible_(r)
+ textView.setSelectedRange_(r)
+
+
+ def current_indent_string(self):
+ """returns string for indent or None if no indent"""
+
+ return self._indent_for_block(self.current_block())
+
+
+ def _indent_for_block(self, block):
+ lines = block.split('\n')
+ if(len(lines) > 1):
+ currentIndent = len(lines[-1]) - len(lines[-1].lstrip())
+ if(currentIndent == 0):
+ currentIndent = self.tabSpaces
+
+ if(self.tabUsesSpaces):
+ result = ' ' * currentIndent
+ else:
+ result = '\t' * (currentIndent/self.tabSpaces)
+ else:
+ result = None
+
+ return result
+
+
+ # NSTextView delegate methods...
+ def textView_doCommandBySelector_(self, textView, selector):
+ assert(textView == self.textView)
+ NSLog("textView_doCommandBySelector_: "+selector)
+
+
+ if(selector == 'insertNewline:'):
+ indent = self.current_indent_string()
+ if(indent):
+ line = indent + self.current_line()
+ else:
+ line = self.current_line()
+
+ if(self.is_complete(self.current_block())):
+ self.execute(self.current_block(),
+ blockID=self.currentBlockID)
+ self.start_new_block()
+
+ return True
+
+ return False
+
+ elif(selector == 'moveUp:'):
+ prevBlock = self.get_history_previous(self.current_block())
+ if(prevBlock != None):
+ self.replace_current_block_with_string(textView, prevBlock)
+ else:
+ NSBeep()
+ return True
+
+ elif(selector == 'moveDown:'):
+ nextBlock = self.get_history_next()
+ if(nextBlock != None):
+ self.replace_current_block_with_string(textView, nextBlock)
+ else:
+ NSBeep()
+ return True
+
+ elif(selector == 'moveToBeginningOfParagraph:'):
+ textView.setSelectedRange_(NSMakeRange(
+ self.current_block_range().inputRange.location,
+ 0))
+ return True
+ elif(selector == 'moveToEndOfParagraph:'):
+ textView.setSelectedRange_(NSMakeRange(
+ self.current_block_range().inputRange.location + \
+ self.current_block_range().inputRange.length, 0))
+ return True
+ elif(selector == 'deleteToEndOfParagraph:'):
+ if(textView.selectedRange().location <= \
+ self.current_block_range().location):
+ raise NotImplemented()
+
+ return False # don't actually handle the delete
+
+ elif(selector == 'insertTab:'):
+ if(len(self.current_line().strip()) == 0): #only white space
+ return False
+ else:
+ self.textView.complete_(self)
+ return True
+
+ elif(selector == 'deleteBackward:'):
+ #if we're at the beginning of the current block, ignore
+ if(textView.selectedRange().location == \
+ self.current_block_range().inputRange.location):
+ return True
+ else:
+ for r in self.blockRanges.itervalues():
+ deleteRange = textView.selectedRange
+ if(deleteRange.length == 0):
+ deleteRange.location -= 1
+ deleteRange.length = 1
+ r.update_ranges_for_deletion(deleteRange)
+ return False
+ return False
+
+
+ def textView_shouldChangeTextInRanges_replacementStrings_(self,
+ textView, ranges, replacementStrings):
+ """
+ Delegate method for NSTextView.
+
+ Refuse change text in ranges not at end, but make those changes at
+ end.
+ """
+
+ assert(len(ranges) == len(replacementStrings))
+ allow = True
+ for r,s in zip(ranges, replacementStrings):
+ r = r.rangeValue()
+ if(textView.textStorage().length() > 0 and
+ r.location < self.current_block_range().inputRange.location):
+ self.insert_text(s)
+ allow = False
+
+ return allow
+
+ def textView_completions_forPartialWordRange_indexOfSelectedItem_(self,
+ textView, words, charRange, index):
+ try:
+ ts = textView.textStorage()
+ token = ts.string().substringWithRange_(charRange)
+ completions = blockingCallFromThread(self.complete, token)
+ except:
+ completions = objc.nil
+ NSBeep()
+
+ return (completions,0)
+
+
diff --git a/IPython/frontend/cocoa/tests/__init__.py b/IPython/frontend/cocoa/tests/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/IPython/frontend/cocoa/tests/__init__.py
diff --git a/IPython/frontend/cocoa/tests/test_cocoa_frontend.py b/IPython/frontend/cocoa/tests/test_cocoa_frontend.py
new file mode 100644
index 0000000..58b78e4
--- /dev/null
+++ b/IPython/frontend/cocoa/tests/test_cocoa_frontend.py
@@ -0,0 +1,100 @@
+# encoding: utf-8
+"""This file contains unittests for the
+IPython.frontend.cocoa.cocoa_frontend module.
+"""
+__docformat__ = "restructuredtext en"
+
+#---------------------------------------------------------------------------
+# Copyright (C) 2005 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#---------------------------------------------------------------------------
+
+#---------------------------------------------------------------------------
+# Imports
+#---------------------------------------------------------------------------
+
+# Tell nose to skip this module
+__test__ = {}
+
+from twisted.trial import unittest
+from twisted.internet.defer import succeed
+
+from IPython.kernel.core.interpreter import Interpreter
+import IPython.kernel.engineservice as es
+
+try:
+ from IPython.frontend.cocoa.cocoa_frontend import IPythonCocoaController
+ from Foundation import NSMakeRect
+ from AppKit import NSTextView, NSScrollView
+except ImportError:
+ # This tells twisted.trial to skip this module if PyObjC is not found
+ skip = True
+
+#---------------------------------------------------------------------------
+# Tests
+#---------------------------------------------------------------------------
+class TestIPythonCocoaControler(unittest.TestCase):
+ """Tests for IPythonCocoaController"""
+
+ def setUp(self):
+ self.controller = IPythonCocoaController.alloc().init()
+ self.engine = es.EngineService()
+ self.engine.startService()
+
+ def tearDown(self):
+ self.controller = None
+ self.engine.stopService()
+
+ def testControllerExecutesCode(self):
+ code ="""5+5"""
+ expected = Interpreter().execute(code)
+ del expected['number']
+ def removeNumberAndID(result):
+ del result['number']
+ del result['id']
+ return result
+ d = self.controller.execute(code)
+ d.addCallback(removeNumberAndID)
+ d.addCallback(lambda r: self.assertEquals(r, expected))
+
+ def testControllerMirrorsUserNSWithValuesAsStrings(self):
+ code = """userns1=1;userns2=2"""
+ def testControllerUserNS(result):
+ self.assertEquals(self.controller.userNS['userns1'], 1)
+ self.assertEquals(self.controller.userNS['userns2'], 2)
+ self.controller.execute(code).addCallback(testControllerUserNS)
+
+ def testControllerInstantiatesIEngine(self):
+ self.assert_(es.IEngineBase.providedBy(self.controller.engine))
+
+ def testControllerCompletesToken(self):
+ code = """longNameVariable=10"""
+ def testCompletes(result):
+ self.assert_("longNameVariable" in result)
+
+ def testCompleteToken(result):
+ self.controller.complete("longNa").addCallback(testCompletes)
+
+ self.controller.execute(code).addCallback(testCompletes)
+
+
+ def testCurrentIndent(self):
+ """test that current_indent_string returns current indent or None.
+ Uses _indent_for_block for direct unit testing.
+ """
+
+ self.controller.tabUsesSpaces = True
+ self.assert_(self.controller._indent_for_block("""a=3""") == None)
+ self.assert_(self.controller._indent_for_block("") == None)
+ block = """def test():\n a=3"""
+ self.assert_(self.controller._indent_for_block(block) == \
+ ' ' * self.controller.tabSpaces)
+
+ block = """if(True):\n%sif(False):\n%spass""" % \
+ (' '*self.controller.tabSpaces,
+ 2*' '*self.controller.tabSpaces)
+ self.assert_(self.controller._indent_for_block(block) == \
+ 2*(' '*self.controller.tabSpaces))
+
diff --git a/IPython/frontend/frontendbase.py b/IPython/frontend/frontendbase.py
new file mode 100644
index 0000000..3ae6e78
--- /dev/null
+++ b/IPython/frontend/frontendbase.py
@@ -0,0 +1,343 @@
+# encoding: utf-8
+# -*- test-case-name: IPython.frontend.tests.test_frontendbase -*-
+"""
+frontendbase provides an interface and base class for GUI frontends for
+IPython.kernel/IPython.kernel.core.
+
+Frontend implementations will likely want to subclass FrontEndBase.
+
+Author: Barry Wark
+"""
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+import string
+import codeop
+from IPython.external import guid
+
+
+from IPython.frontend.zopeinterface import (
+ Interface,
+ Attribute,
+)
+from IPython.kernel.core.history import FrontEndHistory
+from IPython.kernel.core.util import Bunch
+
+##############################################################################
+# TEMPORARY!!! fake configuration, while we decide whether to use tconfig or
+# not
+
+rc = Bunch()
+rc.prompt_in1 = r'In [$number]: '
+rc.prompt_in2 = r'...'
+rc.prompt_out = r'Out [$number]: '
+
+##############################################################################
+# Interface definitions
+##############################################################################
+
+class IFrontEndFactory(Interface):
+ """Factory interface for frontends."""
+
+ def __call__(engine=None, history=None):
+ """
+ Parameters:
+ interpreter : IPython.kernel.engineservice.IEngineCore
+ """
+
+ pass
+
+
+class IFrontEnd(Interface):
+ """Interface for frontends. All methods return t.i.d.Deferred"""
+
+ Attribute("input_prompt_template", "string.Template instance\
+ substituteable with execute result.")
+ Attribute("output_prompt_template", "string.Template instance\
+ substituteable with execute result.")
+ Attribute("continuation_prompt_template", "string.Template instance\
+ substituteable with execute result.")
+
+ def update_cell_prompt(result, blockID=None):
+ """Subclass may override to update the input prompt for a block.
+
+ In asynchronous frontends, this method will be called as a
+ twisted.internet.defer.Deferred's callback/errback.
+ Implementations should thus return result when finished.
+
+ Result is a result dict in case of success, and a
+ twisted.python.util.failure.Failure in case of an error
+ """
+
+ pass
+
+ def render_result(result):
+ """Render the result of an execute call. Implementors may choose the
+ method of rendering.
+ For example, a notebook-style frontend might render a Chaco plot
+ inline.
+
+ Parameters:
+ result : dict (result of IEngineBase.execute )
+ blockID = result['blockID']
+
+ Result:
+ Output of frontend rendering
+ """
+
+ pass
+
+ def render_error(failure):
+ """Subclasses must override to render the failure.
+
+ In asynchronous frontend, since this method will be called as a
+ twisted.internet.defer.Deferred's callback. Implementations
+ should thus return result when finished.
+
+ blockID = failure.blockID
+ """
+
+ pass
+
+ def input_prompt(number=''):
+ """Returns the input prompt by subsituting into
+ self.input_prompt_template
+ """
+ pass
+
+ def output_prompt(number=''):
+ """Returns the output prompt by subsituting into
+ self.output_prompt_template
+ """
+
+ pass
+
+ def continuation_prompt():
+ """Returns the continuation prompt by subsituting into
+ self.continuation_prompt_template
+ """
+
+ pass
+
+ def is_complete(block):
+ """Returns True if block is complete, False otherwise."""
+
+ pass
+
+
+ def get_history_previous(current_block):
+ """Returns the block previous in the history. Saves currentBlock if
+ the history_cursor is currently at the end of the input history"""
+ pass
+
+ def get_history_next():
+ """Returns the next block in the history."""
+
+ pass
+
+ def complete(self, line):
+ """Returns the list of possible completions, and the completed
+ line.
+
+ The input argument is the full line to be completed. This method
+ returns both the line completed as much as possible, and the list
+ of further possible completions (full words).
+ """
+ pass
+
+
+##############################################################################
+# Base class for all the frontends.
+##############################################################################
+
+class FrontEndBase(object):
+ """
+ FrontEndBase manages the state tasks for a CLI frontend:
+ - Input and output history management
+ - Input/continuation and output prompt generation
+
+ Some issues (due to possibly unavailable engine):
+ - How do we get the current cell number for the engine?
+ - How do we handle completions?
+ """
+
+ history_cursor = 0
+
+ input_prompt_template = string.Template(rc.prompt_in1)
+ output_prompt_template = string.Template(rc.prompt_out)
+ continuation_prompt_template = string.Template(rc.prompt_in2)
+
+ def __init__(self, shell=None, history=None):
+ self.shell = shell
+ if history is None:
+ self.history = FrontEndHistory(input_cache=[''])
+ else:
+ self.history = history
+
+
+ def input_prompt(self, number=''):
+ """Returns the current input prompt
+
+ It would be great to use ipython1.core.prompts.Prompt1 here
+ """
+ return self.input_prompt_template.safe_substitute({'number':number})
+
+
+ def continuation_prompt(self):
+ """Returns the current continuation prompt"""
+
+ return self.continuation_prompt_template.safe_substitute()
+
+ def output_prompt(self, number=''):
+ """Returns the output prompt for result"""
+
+ return self.output_prompt_template.safe_substitute({'number':number})
+
+
+ def is_complete(self, block):
+ """Determine if block is complete.
+
+ Parameters
+ block : string
+
+ Result
+ True if block can be sent to the engine without compile errors.
+ False otherwise.
+ """
+
+ try:
+ is_complete = codeop.compile_command(block.rstrip() + '\n\n',
+ "<string>", "exec")
+ except:
+ return False
+
+ lines = block.split('\n')
+ return ((is_complete is not None)
+ and (len(lines)==1 or str(lines[-1])==''))
+
+
+ def execute(self, block, blockID=None):
+ """Execute the block and return the result.
+
+ Parameters:
+ block : {str, AST}
+ blockID : any
+ Caller may provide an ID to identify this block.
+ result['blockID'] := blockID
+
+ Result:
+ Deferred result of self.interpreter.execute
+ """
+
+ if(not self.is_complete(block)):
+ raise Exception("Block is not compilable")
+
+ if(blockID == None):
+ blockID = guid.generate()
+
+ try:
+ result = self.shell.execute(block)
+ except Exception,e:
+ e = self._add_block_id_for_failure(e, blockID=blockID)
+ e = self.update_cell_prompt(e, blockID=blockID)
+ e = self.render_error(e)
+ else:
+ result = self._add_block_id_for_result(result, blockID=blockID)
+ result = self.update_cell_prompt(result, blockID=blockID)
+ result = self.render_result(result)
+
+ return result
+
+
+ def _add_block_id_for_result(self, result, blockID):
+ """Add the blockID to result or failure. Unfortunatley, we have to
+ treat failures differently than result dicts.
+ """
+
+ result['blockID'] = blockID
+
+ return result
+
+ def _add_block_id_for_failure(self, failure, blockID):
+ """_add_block_id_for_failure"""
+ failure.blockID = blockID
+ return failure
+
+
+ def _add_history(self, result, block=None):
+ """Add block to the history"""
+
+ assert(block != None)
+ self.history.add_items([block])
+ self.history_cursor += 1
+
+ return result
+
+
+ def get_history_previous(self, current_block):
+ """ Returns previous history string and decrement history cursor.
+ """
+ command = self.history.get_history_item(self.history_cursor - 1)
+
+ if command is not None:
+ if(self.history_cursor+1 == len(self.history.input_cache)):
+ self.history.input_cache[self.history_cursor] = current_block
+ self.history_cursor -= 1
+ return command
+
+
+ def get_history_next(self):
+ """ Returns next history string and increment history cursor.
+ """
+ command = self.history.get_history_item(self.history_cursor+1)
+
+ if command is not None:
+ self.history_cursor += 1
+ return command
+
+ ###
+ # Subclasses probably want to override these methods...
+ ###
+
+ def update_cell_prompt(self, result, blockID=None):
+ """Subclass may override to update the input prompt for a block.
+
+ This method only really makes sens in asyncrhonous frontend.
+ Since this method will be called as a
+ twisted.internet.defer.Deferred's callback, implementations should
+ return result when finished.
+ """
+
+ raise NotImplementedError
+
+
+ def render_result(self, result):
+ """Subclasses must override to render result.
+
+ In asynchronous frontends, this method will be called as a
+ twisted.internet.defer.Deferred's callback. Implementations
+ should thus return result when finished.
+ """
+
+ raise NotImplementedError
+
+
+ def render_error(self, failure):
+ """Subclasses must override to render the failure.
+
+ In asynchronous frontends, this method will be called as a
+ twisted.internet.defer.Deferred's callback. Implementations
+ should thus return result when finished.
+ """
+
+ raise NotImplementedError
+
diff --git a/IPython/frontend/linefrontendbase.py b/IPython/frontend/linefrontendbase.py
new file mode 100644
index 0000000..18e0ba8
--- /dev/null
+++ b/IPython/frontend/linefrontendbase.py
@@ -0,0 +1,372 @@
+"""
+Base front end class for all line-oriented frontends, rather than
+block-oriented.
+
+Currently this focuses on synchronous frontends.
+"""
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+import re
+
+import sys
+import codeop
+
+from frontendbase import FrontEndBase
+from IPython.kernel.core.interpreter import Interpreter
+
+def common_prefix(strings):
+ """ Given a list of strings, return the common prefix between all
+ these strings.
+ """
+ ref = strings[0]
+ prefix = ''
+ for size in range(len(ref)):
+ test_prefix = ref[:size+1]
+ for string in strings[1:]:
+ if not string.startswith(test_prefix):
+ return prefix
+ prefix = test_prefix
+
+ return prefix
+
+#-------------------------------------------------------------------------------
+# Base class for the line-oriented front ends
+#-------------------------------------------------------------------------------
+class LineFrontEndBase(FrontEndBase):
+ """ Concrete implementation of the FrontEndBase class. This is meant
+ to be the base class behind all the frontend that are line-oriented,
+ rather than block-oriented.
+ """
+
+ # We need to keep the prompt number, to be able to increment
+ # it when there is an exception.
+ prompt_number = 1
+
+ # We keep a reference to the last result: it helps testing and
+ # programatic control of the frontend.
+ last_result = dict(number=0)
+
+ # The last prompt displayed. Useful for continuation prompts.
+ last_prompt = ''
+
+ # The input buffer being edited
+ input_buffer = ''
+
+ # Set to true for debug output
+ debug = False
+
+ # A banner to print at startup
+ banner = None
+
+ #--------------------------------------------------------------------------
+ # FrontEndBase interface
+ #--------------------------------------------------------------------------
+
+ def __init__(self, shell=None, history=None, banner=None, *args, **kwargs):
+ if shell is None:
+ shell = Interpreter()
+ FrontEndBase.__init__(self, shell=shell, history=history)
+
+ if banner is not None:
+ self.banner = banner
+
+ def start(self):
+ """ Put the frontend in a state where it is ready for user
+ interaction.
+ """
+ if self.banner is not None:
+ self.write(self.banner, refresh=False)
+
+ self.new_prompt(self.input_prompt_template.substitute(number=1))
+
+
+ def complete(self, line):
+ """Complete line in engine's user_ns
+
+ Parameters
+ ----------
+ line : string
+
+ Returns
+ -------
+ The replacement for the line and the list of possible completions.
+ """
+ completions = self.shell.complete(line)
+ complete_sep = re.compile('[\s\{\}\[\]\(\)\=]')
+ if completions:
+ prefix = common_prefix(completions)
+ residual = complete_sep.split(line)[:-1]
+ line = line[:-len(residual)] + prefix
+ return line, completions
+
+
+ def render_result(self, result):
+ """ Frontend-specific rendering of the result of a calculation
+ that has been sent to an engine.
+ """
+ if 'stdout' in result and result['stdout']:
+ self.write('\n' + result['stdout'])
+ if 'display' in result and result['display']:
+ self.write("%s%s\n" % (
+ self.output_prompt_template.substitute(
+ number=result['number']),
+ result['display']['pprint']
+ ) )
+
+
+ def render_error(self, failure):
+ """ Frontend-specific rendering of error.
+ """
+ self.write('\n\n'+str(failure)+'\n\n')
+ return failure
+
+
+ def is_complete(self, string):
+ """ Check if a string forms a complete, executable set of
+ commands.
+
+ For the line-oriented frontend, multi-line code is not executed
+ as soon as it is complete: the users has to enter two line
+ returns.
+ """
+ if string in ('', '\n'):
+ # Prefiltering, eg through ipython0, may return an empty
+ # string although some operations have been accomplished. We
+ # thus want to consider an empty string as a complete
+ # statement.
+ return True
+ elif ( len(self.input_buffer.split('\n'))>2
+ and not re.findall(r"\n[\t ]*\n[\t ]*$", string)):
+ return False
+ else:
+ self.capture_output()
+ try:
+ # Add line returns here, to make sure that the statement is
+ # complete (except if '\' was used).
+ # This should probably be done in a different place (like
+ # maybe 'prefilter_input' method? For now, this works.
+ clean_string = string.rstrip('\n')
+ if not clean_string.endswith('\\'): clean_string +='\n\n'
+ is_complete = codeop.compile_command(clean_string,
+ "<string>", "exec")
+ self.release_output()
+ except Exception, e:
+ # XXX: Hack: return True so that the
+ # code gets executed and the error captured.
+ is_complete = True
+ return is_complete
+
+
+ def write(self, string, refresh=True):
+ """ Write some characters to the display.
+
+ Subclass should overide this method.
+
+ The refresh keyword argument is used in frontends with an
+ event loop, to choose whether the write should trigget an UI
+ refresh, and thus be syncrhonous, or not.
+ """
+ print >>sys.__stderr__, string
+
+
+ def execute(self, python_string, raw_string=None):
+ """ Stores the raw_string in the history, and sends the
+ python string to the interpreter.
+ """
+ if raw_string is None:
+ raw_string = python_string
+ # Create a false result, in case there is an exception
+ self.last_result = dict(number=self.prompt_number)
+
+ try:
+ try:
+ self.history.input_cache[-1] = raw_string.rstrip()
+ result = self.shell.execute(python_string)
+ self.last_result = result
+ self.render_result(result)
+ except:
+ self.show_traceback()
+ finally:
+ self.after_execute()
+
+
+ #--------------------------------------------------------------------------
+ # LineFrontEndBase interface
+ #--------------------------------------------------------------------------
+
+ def prefilter_input(self, string):
+ """ Prefilter the input to turn it in valid python.
+ """
+ string = string.replace('\r\n', '\n')
+ string = string.replace('\t', 4*' ')
+ # Clean the trailing whitespace
+ string = '\n'.join(l.rstrip() for l in string.split('\n'))
+ return string
+
+
+ def after_execute(self):
+ """ All the operations required after an execution to put the
+ terminal back in a shape where it is usable.
+ """
+ self.prompt_number += 1
+ self.new_prompt(self.input_prompt_template.substitute(
+ number=(self.last_result['number'] + 1)))
+ # Start a new empty history entry
+ self._add_history(None, '')
+ self.history_cursor = len(self.history.input_cache) - 1
+
+
+ def complete_current_input(self):
+ """ Do code completion on current line.
+ """
+ if self.debug:
+ print >>sys.__stdout__, "complete_current_input",
+ line = self.input_buffer
+ new_line, completions = self.complete(line)
+ if len(completions)>1:
+ self.write_completion(completions, new_line=new_line)
+ elif not line == new_line:
+ self.input_buffer = new_line
+ if self.debug:
+ print >>sys.__stdout__, 'line', line
+ print >>sys.__stdout__, 'new_line', new_line
+ print >>sys.__stdout__, completions
+
+
+ def get_line_width(self):
+ """ Return the width of the line in characters.
+ """
+ return 80
+
+
+ def write_completion(self, possibilities, new_line=None):
+ """ Write the list of possible completions.
+
+ new_line is the completed input line that should be displayed
+ after the completion are writen. If None, the input_buffer
+ before the completion is used.
+ """
+ if new_line is None:
+ new_line = self.input_buffer
+
+ self.write('\n')
+ max_len = len(max(possibilities, key=len)) + 1
+
+ # Now we check how much symbol we can put on a line...
+ chars_per_line = self.get_line_width()
+ symbols_per_line = max(1, chars_per_line/max_len)
+
+ pos = 1
+ completion_string = []
+ for symbol in possibilities:
+ if pos < symbols_per_line:
+ completion_string.append(symbol.ljust(max_len))
+ pos += 1
+ else:
+ completion_string.append(symbol.rstrip() + '\n')
+ pos = 1
+ self.write(''.join(completion_string))
+ self.new_prompt(self.input_prompt_template.substitute(
+ number=self.last_result['number'] + 1))
+ self.input_buffer = new_line
+
+
+ def new_prompt(self, prompt):
+ """ Prints a prompt and starts a new editing buffer.
+
+ Subclasses should use this method to make sure that the
+ terminal is put in a state favorable for a new line
+ input.
+ """
+ self.input_buffer = ''
+ self.write(prompt)
+
+
+ def continuation_prompt(self):
+ """Returns the current continuation prompt.
+ """
+ return ("."*(len(self.last_prompt)-2) + ': ')
+
+
+ def execute_command(self, command, hidden=False):
+ """ Execute a command, not only in the model, but also in the
+ view, if any.
+ """
+ return self.shell.execute(command)
+
+ #--------------------------------------------------------------------------
+ # Private API
+ #--------------------------------------------------------------------------
+
+ def _on_enter(self, new_line_pos=0):
+ """ Called when the return key is pressed in a line editing
+ buffer.
+
+ Parameters
+ ----------
+ new_line_pos : integer, optional
+ Position of the new line to add, starting from the
+ end (0 adds a new line after the last line, -1 before
+ the last line...)
+
+ Returns
+ -------
+ True if execution is triggered
+ """
+ current_buffer = self.input_buffer
+ # XXX: This string replace is ugly, but there should be no way it
+ # fails.
+ prompt_less_buffer = re.sub('^' + self.continuation_prompt(),
+ '', current_buffer).replace('\n' + self.continuation_prompt(),
+ '\n')
+ cleaned_buffer = self.prefilter_input(prompt_less_buffer)
+ if self.is_complete(cleaned_buffer):
+ self.execute(cleaned_buffer, raw_string=current_buffer)
+ return True
+ else:
+ # Start a new line.
+ new_line_pos = -new_line_pos
+ lines = current_buffer.split('\n')[:-1]
+ prompt_less_lines = prompt_less_buffer.split('\n')
+ # Create the new line, with the continuation prompt, and the
+ # same amount of indent than the line above it.
+ new_line = self.continuation_prompt() + \
+ self._get_indent_string('\n'.join(
+ prompt_less_lines[:new_line_pos-1]))
+ if len(lines) == 1:
+ # We are starting a first continuation line. Indent it.
+ new_line += '\t'
+ elif current_buffer[:-1].split('\n')[-1].rstrip().endswith(':'):
+ # The last line ends with ":", autoindent the new line.
+ new_line += '\t'
+
+ if new_line_pos == 0:
+ lines.append(new_line)
+ else:
+ lines.insert(new_line_pos, new_line)
+ self.input_buffer = '\n'.join(lines)
+
+
+ def _get_indent_string(self, string):
+ """ Return the string of whitespace that prefixes a line. Used to
+ add the right amount of indendation when creating a new line.
+ """
+ string = string.replace('\t', ' '*4)
+ string = string.split('\n')[-1]
+ indent_chars = len(string) - len(string.lstrip())
+ indent_string = '\t'*(indent_chars // 4) + \
+ ' '*(indent_chars % 4)
+
+ return indent_string
+
+
diff --git a/IPython/frontend/prefilterfrontend.py b/IPython/frontend/prefilterfrontend.py
new file mode 100644
index 0000000..1f216e4
--- /dev/null
+++ b/IPython/frontend/prefilterfrontend.py
@@ -0,0 +1,285 @@
+"""
+Frontend class that uses IPython0 to prefilter the inputs.
+
+Using the IPython0 mechanism gives us access to the magics.
+
+This is a transitory class, used here to do the transition between
+ipython0 and ipython1. This class is meant to be short-lived as more
+functionnality is abstracted out of ipython0 in reusable functions and
+is added on the interpreter. This class can be a used to guide this
+refactoring.
+"""
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+import sys
+import pydoc
+import os
+import re
+import __builtin__
+
+from IPython.ipmaker import make_IPython
+from IPython.ipapi import IPApi
+from IPython.kernel.core.redirector_output_trap import RedirectorOutputTrap
+
+from IPython.kernel.core.sync_traceback_trap import SyncTracebackTrap
+
+from IPython.genutils import Term
+
+from linefrontendbase import LineFrontEndBase, common_prefix
+
+
+def mk_system_call(system_call_function, command):
+ """ given a os.system replacement, and a leading string command,
+ returns a function that will execute the command with the given
+ argument string.
+ """
+ def my_system_call(args):
+ system_call_function("%s %s" % (command, args))
+
+ my_system_call.__doc__ = "Calls %s" % command
+ return my_system_call
+
+#-------------------------------------------------------------------------------
+# Frontend class using ipython0 to do the prefiltering.
+#-------------------------------------------------------------------------------
+class PrefilterFrontEnd(LineFrontEndBase):
+ """ Class that uses ipython0 to do prefilter the input, do the
+ completion and the magics.
+
+ The core trick is to use an ipython0 instance to prefilter the
+ input, and share the namespace between the interpreter instance used
+ to execute the statements and the ipython0 used for code
+ completion...
+ """
+
+ debug = False
+
+ def __init__(self, ipython0=None, argv=None, *args, **kwargs):
+ """ Parameters
+ ----------
+
+ ipython0: an optional ipython0 instance to use for command
+ prefiltering and completion.
+
+ argv : list, optional
+ Used as the instance's argv value. If not given, [] is used.
+ """
+ if argv is None:
+ argv = []
+ # This is a hack to avoid the IPython exception hook to trigger
+ # on exceptions (https://bugs.launchpad.net/bugs/337105)
+ # XXX: This is horrible: module-leve monkey patching -> side
+ # effects.
+ from IPython import iplib
+ iplib.InteractiveShell.isthreaded = True
+
+ LineFrontEndBase.__init__(self, *args, **kwargs)
+ self.shell.output_trap = RedirectorOutputTrap(
+ out_callback=self.write,
+ err_callback=self.write,
+ )
+ self.shell.traceback_trap = SyncTracebackTrap(
+ formatters=self.shell.traceback_trap.formatters,
+ )
+
+ # Start the ipython0 instance:
+ self.save_output_hooks()
+ if ipython0 is None:
+ # Instanciate an IPython0 interpreter to be able to use the
+ # prefiltering.
+ # Suppress all key input, to avoid waiting
+ def my_rawinput(x=None):
+ return '\n'
+ old_rawinput = __builtin__.raw_input
+ __builtin__.raw_input = my_rawinput
+ # XXX: argv=[] is a bit bold.
+ ipython0 = make_IPython(argv=argv,
+ user_ns=self.shell.user_ns,
+ user_global_ns=self.shell.user_global_ns)
+ __builtin__.raw_input = old_rawinput
+ self.ipython0 = ipython0
+ # Set the pager:
+ self.ipython0.set_hook('show_in_pager',
+ lambda s, string: self.write("\n" + string))
+ self.ipython0.write = self.write
+ self._ip = _ip = IPApi(self.ipython0)
+ # Make sure the raw system call doesn't get called, as we don't
+ # have a stdin accessible.
+ self._ip.system = self.system_call
+ # XXX: Muck around with magics so that they work better
+ # in our environment
+ if not sys.platform.startswith('win'):
+ self.ipython0.magic_ls = mk_system_call(self.system_call,
+ 'ls -CF')
+ # And now clean up the mess created by ipython0
+ self.release_output()
+
+
+ if not 'banner' in kwargs and self.banner is None:
+ self.banner = self.ipython0.BANNER
+
+ # FIXME: __init__ and start should be two different steps
+ self.start()
+
+ #--------------------------------------------------------------------------
+ # FrontEndBase interface
+ #--------------------------------------------------------------------------
+
+ def show_traceback(self):
+ """ Use ipython0 to capture the last traceback and display it.
+ """
+ # Don't do the capture; the except_hook has already done some
+ # modifications to the IO streams, if we store them, we'll be
+ # storing the wrong ones.
+ #self.capture_output()
+ self.ipython0.showtraceback(tb_offset=-1)
+ self.release_output()
+
+
+ def execute(self, python_string, raw_string=None):
+ if self.debug:
+ print 'Executing Python code:', repr(python_string)
+ self.capture_output()
+ LineFrontEndBase.execute(self, python_string,
+ raw_string=raw_string)
+ self.release_output()
+
+
+ def save_output_hooks(self):
+ """ Store all the output hooks we can think of, to be able to
+ restore them.
+
+ We need to do this early, as starting the ipython0 instance will
+ screw ouput hooks.
+ """
+ self.__old_cout_write = Term.cout.write
+ self.__old_cerr_write = Term.cerr.write
+ self.__old_stdout = sys.stdout
+ self.__old_stderr= sys.stderr
+ self.__old_help_output = pydoc.help.output
+ self.__old_display_hook = sys.displayhook
+
+
+ def capture_output(self):
+ """ Capture all the output mechanisms we can think of.
+ """
+ self.save_output_hooks()
+ Term.cout.write = self.write
+ Term.cerr.write = self.write
+ sys.stdout = Term.cout
+ sys.stderr = Term.cerr
+ pydoc.help.output = self.shell.output_trap.out
+
+
+ def release_output(self):
+ """ Release all the different captures we have made.
+ """
+ Term.cout.write = self.__old_cout_write
+ Term.cerr.write = self.__old_cerr_write
+ sys.stdout = self.__old_stdout
+ sys.stderr = self.__old_stderr
+ pydoc.help.output = self.__old_help_output
+ sys.displayhook = self.__old_display_hook
+
+
+ def complete(self, line):
+ # FIXME: This should be factored out in the linefrontendbase
+ # method.
+ word = self._get_completion_text(line)
+ completions = self.ipython0.complete(word)
+ # FIXME: The proper sort should be done in the complete method.
+ key = lambda x: x.replace('_', '')
+ completions.sort(key=key)
+ if completions:
+ prefix = common_prefix(completions)
+ line = line[:-len(word)] + prefix
+ return line, completions
+
+
+ #--------------------------------------------------------------------------
+ # LineFrontEndBase interface
+ #--------------------------------------------------------------------------
+
+ def prefilter_input(self, input_string):
+ """ Using IPython0 to prefilter the commands to turn them
+ in executable statements that are valid Python strings.
+ """
+ input_string = LineFrontEndBase.prefilter_input(self, input_string)
+ filtered_lines = []
+ # The IPython0 prefilters sometime produce output. We need to
+ # capture it.
+ self.capture_output()
+ self.last_result = dict(number=self.prompt_number)
+
+ ## try:
+ ## for line in input_string.split('\n'):
+ ## filtered_lines.append(
+ ## self.ipython0.prefilter(line, False).rstrip())
+ ## except:
+ ## # XXX: probably not the right thing to do.
+ ## self.ipython0.showsyntaxerror()
+ ## self.after_execute()
+ ## finally:
+ ## self.release_output()
+
+
+ try:
+ try:
+ for line in input_string.split('\n'):
+ filtered_lines.append(
+ self.ipython0.prefilter(line, False).rstrip())
+ except:
+ # XXX: probably not the right thing to do.
+ self.ipython0.showsyntaxerror()
+ self.after_execute()
+ finally:
+ self.release_output()
+
+
+
+ # Clean up the trailing whitespace, to avoid indentation errors
+ filtered_string = '\n'.join(filtered_lines)
+ return filtered_string
+
+
+ #--------------------------------------------------------------------------
+ # PrefilterFrontEnd interface
+ #--------------------------------------------------------------------------
+
+ def system_call(self, command_string):
+ """ Allows for frontend to define their own system call, to be
+ able capture output and redirect input.
+ """
+ return os.system(command_string)
+
+
+ def do_exit(self):
+ """ Exit the shell, cleanup and save the history.
+ """
+ self.ipython0.atexit_operations()
+
+
+ def _get_completion_text(self, line):
+ """ Returns the text to be completed by breaking the line at specified
+ delimiters.
+ """
+ # Break at: spaces, '=', all parentheses (except if balanced).
+ # FIXME2: In the future, we need to make the implementation similar to
+ # that in the 'pyreadline' module (modes/basemode.py) where we break at
+ # each delimiter and try to complete the residual line, until we get a
+ # successful list of completions.
+ expression = '\s|=|,|:|\((?!.*\))|\[(?!.*\])|\{(?!.*\})'
+ complete_sep = re.compile(expression)
+ text = complete_sep.split(line)[-1]
+ return text
+
diff --git a/IPython/frontend/process/__init__.py b/IPython/frontend/process/__init__.py
new file mode 100644
index 0000000..af9be72
--- /dev/null
+++ b/IPython/frontend/process/__init__.py
@@ -0,0 +1,19 @@
+"""
+Package for dealing for process execution in a callback environment, in a
+portable way.
+
+killable_process.py is a wrapper of subprocess.Popen that allows the
+subprocess and its children to be killed in a reliable way, including
+under windows.
+
+winprocess.py is required by killable_process.py to kill processes under
+windows.
+
+piped_process.py wraps process execution with callbacks to print output,
+in a non-blocking way. It can be used to interact with a subprocess in eg
+a GUI event loop.
+"""
+
+from pipedprocess import PipedProcess
+
+
diff --git a/IPython/frontend/process/killableprocess.py b/IPython/frontend/process/killableprocess.py
new file mode 100644
index 0000000..399bd70
--- /dev/null
+++ b/IPython/frontend/process/killableprocess.py
@@ -0,0 +1,184 @@
+# Addapted from killableprocess.py.
+#______________________________________________________________________________
+#
+# killableprocess - subprocesses which can be reliably killed
+#
+# Parts of this module are copied from the subprocess.py file contained
+# in the Python distribution.
+#
+# Copyright (c) 2003-2004 by Peter Astrand <astrand@lysator.liu.se>
+#
+# Additions and modifications written by Benjamin Smedberg
+# <benjamin@smedbergs.us> are Copyright (c) 2006 by the Mozilla Foundation
+# <http://www.mozilla.org/>
+#
+# By obtaining, using, and/or copying this software and/or its
+# associated documentation, you agree that you have read, understood,
+# and will comply with the following terms and conditions:
+#
+# Permission to use, copy, modify, and distribute this software and
+# its associated documentation for any purpose and without fee is
+# hereby granted, provided that the above copyright notice appears in
+# all copies, and that both that copyright notice and this permission
+# notice appear in supporting documentation, and that the name of the
+# author not be used in advertising or publicity pertaining to
+# distribution of the software without specific, written prior
+# permission.
+#
+# THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+# OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+r"""killableprocess - Subprocesses which can be reliably killed
+
+This module is a subclass of the builtin "subprocess" module. It allows
+processes that launch subprocesses to be reliably killed on Windows (via the Popen.kill() method.
+
+It also adds a timeout argument to Wait() for a limited period of time before
+forcefully killing the process.
+
+Note: On Windows, this module requires Windows 2000 or higher (no support for
+Windows 95, 98, or NT 4.0). It also requires ctypes, which is bundled with
+Python 2.5+ or available from http://python.net/crew/theller/ctypes/
+"""
+
+import subprocess
+from subprocess import PIPE
+import sys
+import os
+import types
+
+try:
+ from subprocess import CalledProcessError
+except ImportError:
+ # Python 2.4 doesn't implement CalledProcessError
+ class CalledProcessError(Exception):
+ """This exception is raised when a process run by check_call() returns
+ a non-zero exit status. The exit status will be stored in the
+ returncode attribute."""
+ def __init__(self, returncode, cmd):
+ self.returncode = returncode
+ self.cmd = cmd
+ def __str__(self):
+ return "Command '%s' returned non-zero exit status %d" % (self.cmd, self.returncode)
+
+mswindows = (sys.platform == "win32")
+
+skip = False
+
+if mswindows:
+ import platform
+ if platform.uname()[3] == '' or platform.uname()[3] > '6.0.6000':
+ # Killable process does not work under vista when starting for
+ # something else than cmd.
+ skip = True
+ else:
+ import winprocess
+else:
+ import signal
+
+if not mswindows:
+ def DoNothing(*args):
+ pass
+
+
+if skip:
+ Popen = subprocess.Popen
+else:
+ class Popen(subprocess.Popen):
+ if not mswindows:
+ # Override __init__ to set a preexec_fn
+ def __init__(self, *args, **kwargs):
+ if len(args) >= 7:
+ raise Exception("Arguments preexec_fn and after must be passed by keyword.")
+
+ real_preexec_fn = kwargs.pop("preexec_fn", None)
+ def setpgid_preexec_fn():
+ os.setpgid(0, 0)
+ if real_preexec_fn:
+ apply(real_preexec_fn)
+
+ kwargs['preexec_fn'] = setpgid_preexec_fn
+
+ subprocess.Popen.__init__(self, *args, **kwargs)
+
+ if mswindows:
+ def _execute_child(self, args, executable, preexec_fn, close_fds,
+ cwd, env, universal_newlines, startupinfo,
+ creationflags, shell,
+ p2cread, p2cwrite,
+ c2pread, c2pwrite,
+ errread, errwrite):
+ if not isinstance(args, types.StringTypes):
+ args = subprocess.list2cmdline(args)
+
+ if startupinfo is None:
+ startupinfo = winprocess.STARTUPINFO()
+
+ if None not in (p2cread, c2pwrite, errwrite):
+ startupinfo.dwFlags |= winprocess.STARTF_USESTDHANDLES
+
+ startupinfo.hStdInput = int(p2cread)
+ startupinfo.hStdOutput = int(c2pwrite)
+ startupinfo.hStdError = int(errwrite)
+ if shell:
+ startupinfo.dwFlags |= winprocess.STARTF_USESHOWWINDOW
+ startupinfo.wShowWindow = winprocess.SW_HIDE
+ comspec = os.environ.get("COMSPEC", "cmd.exe")
+ args = comspec + " /c " + args
+
+ # We create a new job for this process, so that we can kill
+ # the process and any sub-processes
+ self._job = winprocess.CreateJobObject()
+
+ creationflags |= winprocess.CREATE_SUSPENDED
+ creationflags |= winprocess.CREATE_UNICODE_ENVIRONMENT
+
+ hp, ht, pid, tid = winprocess.CreateProcess(
+ executable, args,
+ None, None, # No special security
+ 1, # Must inherit handles!
+ creationflags,
+ winprocess.EnvironmentBlock(env),
+ cwd, startupinfo)
+
+ self._child_created = True
+ self._handle = hp
+ self._thread = ht
+ self.pid = pid
+
+ # XXX: A try/except to fix UAC-related problems under
+ # Windows Vista, when reparenting jobs.
+ try:
+ winprocess.AssignProcessToJobObject(self._job, hp)
+ except WindowsError:
+ pass
+ winprocess.ResumeThread(ht)
+
+ if p2cread is not None:
+ p2cread.Close()
+ if c2pwrite is not None:
+ c2pwrite.Close()
+ if errwrite is not None:
+ errwrite.Close()
+
+ def kill(self, group=True):
+ """Kill the process. If group=True, all sub-processes will also be killed."""
+ if mswindows:
+ if group:
+ winprocess.TerminateJobObject(self._job, 127)
+ else:
+ winprocess.TerminateProcess(self._handle, 127)
+ self.returncode = 127
+ else:
+ if group:
+ os.killpg(self.pid, signal.SIGKILL)
+ else:
+ os.kill(self.pid, signal.SIGKILL)
+ self.returncode = -9
+
+
diff --git a/IPython/frontend/process/pipedprocess.py b/IPython/frontend/process/pipedprocess.py
new file mode 100644
index 0000000..1b145af
--- /dev/null
+++ b/IPython/frontend/process/pipedprocess.py
@@ -0,0 +1,74 @@
+# encoding: utf-8
+"""
+Object for encapsulating process execution by using callbacks for stdout,
+stderr and stdin.
+"""
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+from killableprocess import Popen, PIPE
+from threading import Thread
+from time import sleep
+import os
+
+class PipedProcess(Thread):
+ """ Class that encapsulates process execution by using callbacks for
+ stdout, stderr and stdin, and providing a reliable way of
+ killing it.
+ """
+
+ def __init__(self, command_string, out_callback,
+ end_callback=None,):
+ """ command_string: the command line executed to start the
+ process.
+
+ out_callback: the python callable called on stdout/stderr.
+
+ end_callback: an optional callable called when the process
+ finishes.
+
+ These callbacks are called from a different thread as the
+ thread from which is started.
+ """
+ self.command_string = command_string
+ self.out_callback = out_callback
+ self.end_callback = end_callback
+ Thread.__init__(self)
+
+
+ def run(self):
+ """ Start the process and hook up the callbacks.
+ """
+ env = os.environ
+ env['TERM'] = 'xterm'
+ process = Popen(self.command_string + ' 2>&1', shell=True,
+ env=env,
+ universal_newlines=True,
+ stdout=PIPE, stdin=PIPE, )
+ self.process = process
+ while True:
+ out_char = process.stdout.read(1)
+ if out_char == '':
+ if process.poll() is not None:
+ # The process has finished
+ break
+ else:
+ # The process is not giving any interesting
+ # output. No use polling it immediatly.
+ sleep(0.1)
+ else:
+ self.out_callback(out_char)
+
+ if self.end_callback is not None:
+ self.end_callback()
+
+
diff --git a/IPython/frontend/process/winprocess.py b/IPython/frontend/process/winprocess.py
new file mode 100644
index 0000000..9114fcf
--- /dev/null
+++ b/IPython/frontend/process/winprocess.py
@@ -0,0 +1,264 @@
+# A module to expose various thread/process/job related structures and
+# methods from kernel32
+#
+# The MIT License
+#
+# Copyright (c) 2006 the Mozilla Foundation <http://www.mozilla.org>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+# DEALINGS IN THE SOFTWARE.
+
+from ctypes import c_void_p, POINTER, sizeof, Structure, windll, WinError, WINFUNCTYPE
+from ctypes.wintypes import BOOL, BYTE, DWORD, HANDLE, LPCWSTR, LPWSTR, UINT, WORD
+
+LPVOID = c_void_p
+LPBYTE = POINTER(BYTE)
+LPDWORD = POINTER(DWORD)
+
+SW_HIDE = 0
+
+def ErrCheckBool(result, func, args):
+ """errcheck function for Windows functions that return a BOOL True
+ on success"""
+ if not result:
+ raise WinError()
+ return args
+
+# CloseHandle()
+
+CloseHandleProto = WINFUNCTYPE(BOOL, HANDLE)
+CloseHandle = CloseHandleProto(("CloseHandle", windll.kernel32))
+CloseHandle.errcheck = ErrCheckBool
+
+# AutoHANDLE
+
+class AutoHANDLE(HANDLE):
+ """Subclass of HANDLE which will call CloseHandle() on deletion."""
+ def Close(self):
+ if self.value:
+ CloseHandle(self)
+ self.value = 0
+
+ def __del__(self):
+ self.Close()
+
+ def __int__(self):
+ return self.value
+
+def ErrCheckHandle(result, func, args):
+ """errcheck function for Windows functions that return a HANDLE."""
+ if not result:
+ raise WinError()
+ return AutoHANDLE(result)
+
+# PROCESS_INFORMATION structure
+
+class PROCESS_INFORMATION(Structure):
+ _fields_ = [("hProcess", HANDLE),
+ ("hThread", HANDLE),
+ ("dwProcessID", DWORD),
+ ("dwThreadID", DWORD)]
+
+ def __init__(self):
+ Structure.__init__(self)
+
+ self.cb = sizeof(self)
+
+LPPROCESS_INFORMATION = POINTER(PROCESS_INFORMATION)
+
+# STARTUPINFO structure
+
+class STARTUPINFO(Structure):
+ _fields_ = [("cb", DWORD),
+ ("lpReserved", LPWSTR),
+ ("lpDesktop", LPWSTR),
+ ("lpTitle", LPWSTR),
+ ("dwX", DWORD),
+ ("dwY", DWORD),
+ ("dwXSize", DWORD),
+ ("dwYSize", DWORD),
+ ("dwXCountChars", DWORD),
+ ("dwYCountChars", DWORD),
+ ("dwFillAttribute", DWORD),
+ ("dwFlags", DWORD),
+ ("wShowWindow", WORD),
+ ("cbReserved2", WORD),
+ ("lpReserved2", LPBYTE),
+ ("hStdInput", HANDLE),
+ ("hStdOutput", HANDLE),
+ ("hStdError", HANDLE)
+ ]
+LPSTARTUPINFO = POINTER(STARTUPINFO)
+
+STARTF_USESHOWWINDOW = 0x01
+STARTF_USESIZE = 0x02
+STARTF_USEPOSITION = 0x04
+STARTF_USECOUNTCHARS = 0x08
+STARTF_USEFILLATTRIBUTE = 0x10
+STARTF_RUNFULLSCREEN = 0x20
+STARTF_FORCEONFEEDBACK = 0x40
+STARTF_FORCEOFFFEEDBACK = 0x80
+STARTF_USESTDHANDLES = 0x100
+
+# EnvironmentBlock
+
+class EnvironmentBlock:
+ """An object which can be passed as the lpEnv parameter of CreateProcess.
+ It is initialized with a dictionary."""
+
+ def __init__(self, dict):
+ if not dict:
+ self._as_parameter_ = None
+ else:
+ values = ["%s=%s" % (key, value)
+ for (key, value) in dict.iteritems()]
+ values.append("")
+ self._as_parameter_ = LPCWSTR("\0".join(values))
+
+# CreateProcess()
+
+CreateProcessProto = WINFUNCTYPE(BOOL, # Return type
+ LPCWSTR, # lpApplicationName
+ LPWSTR, # lpCommandLine
+ LPVOID, # lpProcessAttributes
+ LPVOID, # lpThreadAttributes
+ BOOL, # bInheritHandles
+ DWORD, # dwCreationFlags
+ LPVOID, # lpEnvironment
+ LPCWSTR, # lpCurrentDirectory
+ LPSTARTUPINFO, # lpStartupInfo
+ LPPROCESS_INFORMATION # lpProcessInformation
+ )
+
+CreateProcessFlags = ((1, "lpApplicationName", None),
+ (1, "lpCommandLine"),
+ (1, "lpProcessAttributes", None),
+ (1, "lpThreadAttributes", None),
+ (1, "bInheritHandles", True),
+ (1, "dwCreationFlags", 0),
+ (1, "lpEnvironment", None),
+ (1, "lpCurrentDirectory", None),
+ (1, "lpStartupInfo"),
+ (2, "lpProcessInformation"))
+
+def ErrCheckCreateProcess(result, func, args):
+ ErrCheckBool(result, func, args)
+ # return a tuple (hProcess, hThread, dwProcessID, dwThreadID)
+ pi = args[9]
+ return AutoHANDLE(pi.hProcess), AutoHANDLE(pi.hThread), pi.dwProcessID, pi.dwThreadID
+
+CreateProcess = CreateProcessProto(("CreateProcessW", windll.kernel32),
+ CreateProcessFlags)
+CreateProcess.errcheck = ErrCheckCreateProcess
+
+CREATE_BREAKAWAY_FROM_JOB = 0x01000000
+CREATE_DEFAULT_ERROR_MODE = 0x04000000
+CREATE_NEW_CONSOLE = 0x00000010
+CREATE_NEW_PROCESS_GROUP = 0x00000200
+CREATE_NO_WINDOW = 0x08000000
+CREATE_SUSPENDED = 0x00000004
+CREATE_UNICODE_ENVIRONMENT = 0x00000400
+DEBUG_ONLY_THIS_PROCESS = 0x00000002
+DEBUG_PROCESS = 0x00000001
+DETACHED_PROCESS = 0x00000008
+
+# CreateJobObject()
+
+CreateJobObjectProto = WINFUNCTYPE(HANDLE, # Return type
+ LPVOID, # lpJobAttributes
+ LPCWSTR # lpName
+ )
+
+CreateJobObjectFlags = ((1, "lpJobAttributes", None),
+ (1, "lpName", None))
+
+CreateJobObject = CreateJobObjectProto(("CreateJobObjectW", windll.kernel32),
+ CreateJobObjectFlags)
+CreateJobObject.errcheck = ErrCheckHandle
+
+# AssignProcessToJobObject()
+
+AssignProcessToJobObjectProto = WINFUNCTYPE(BOOL, # Return type
+ HANDLE, # hJob
+ HANDLE # hProcess
+ )
+AssignProcessToJobObjectFlags = ((1, "hJob"),
+ (1, "hProcess"))
+AssignProcessToJobObject = AssignProcessToJobObjectProto(
+ ("AssignProcessToJobObject", windll.kernel32),
+ AssignProcessToJobObjectFlags)
+AssignProcessToJobObject.errcheck = ErrCheckBool
+
+# ResumeThread()
+
+def ErrCheckResumeThread(result, func, args):
+ if result == -1:
+ raise WinError()
+
+ return args
+
+ResumeThreadProto = WINFUNCTYPE(DWORD, # Return type
+ HANDLE # hThread
+ )
+ResumeThreadFlags = ((1, "hThread"),)
+ResumeThread = ResumeThreadProto(("ResumeThread", windll.kernel32),
+ ResumeThreadFlags)
+ResumeThread.errcheck = ErrCheckResumeThread
+
+# TerminateJobObject()
+
+TerminateJobObjectProto = WINFUNCTYPE(BOOL, # Return type
+ HANDLE, # hJob
+ UINT # uExitCode
+ )
+TerminateJobObjectFlags = ((1, "hJob"),
+ (1, "uExitCode", 127))
+TerminateJobObject = TerminateJobObjectProto(
+ ("TerminateJobObject", windll.kernel32),
+ TerminateJobObjectFlags)
+TerminateJobObject.errcheck = ErrCheckBool
+
+# WaitForSingleObject()
+
+WaitForSingleObjectProto = WINFUNCTYPE(DWORD, # Return type
+ HANDLE, # hHandle
+ DWORD, # dwMilliseconds
+ )
+WaitForSingleObjectFlags = ((1, "hHandle"),
+ (1, "dwMilliseconds", -1))
+WaitForSingleObject = WaitForSingleObjectProto(
+ ("WaitForSingleObject", windll.kernel32),
+ WaitForSingleObjectFlags)
+
+INFINITE = -1
+WAIT_TIMEOUT = 0x0102
+WAIT_OBJECT_0 = 0x0
+WAIT_ABANDONED = 0x0080
+
+# GetExitCodeProcess()
+
+GetExitCodeProcessProto = WINFUNCTYPE(BOOL, # Return type
+ HANDLE, # hProcess
+ LPDWORD, # lpExitCode
+ )
+GetExitCodeProcessFlags = ((1, "hProcess"),
+ (2, "lpExitCode"))
+GetExitCodeProcess = GetExitCodeProcessProto(
+ ("GetExitCodeProcess", windll.kernel32),
+ GetExitCodeProcessFlags)
+GetExitCodeProcess.errcheck = ErrCheckBool
diff --git a/IPython/frontend/tests/__init__.py b/IPython/frontend/tests/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/IPython/frontend/tests/__init__.py
diff --git a/IPython/frontend/tests/test_asyncfrontendbase.py b/IPython/frontend/tests/test_asyncfrontendbase.py
new file mode 100644
index 0000000..b52659b
--- /dev/null
+++ b/IPython/frontend/tests/test_asyncfrontendbase.py
@@ -0,0 +1,112 @@
+# encoding: utf-8
+
+"""This file contains unittests for the asyncfrontendbase module."""
+
+__docformat__ = "restructuredtext en"
+
+# Tell nose to skip this module
+__test__ = {}
+
+#---------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#---------------------------------------------------------------------------
+
+#---------------------------------------------------------------------------
+# Imports
+#---------------------------------------------------------------------------
+
+from twisted.trial import unittest
+
+from IPython.frontend.asyncfrontendbase import AsyncFrontEndBase
+from IPython.frontend import frontendbase
+from IPython.kernel.engineservice import EngineService
+from IPython.testing.parametric import Parametric, parametric
+
+#-----------------------------------------------------------------------------
+# Classes and functions
+#-----------------------------------------------------------------------------
+
+class FrontEndCallbackChecker(AsyncFrontEndBase):
+ """FrontEndBase subclass for checking callbacks"""
+ def __init__(self, engine=None, history=None):
+ super(FrontEndCallbackChecker, self).__init__(engine=engine,
+ history=history)
+ self.updateCalled = False
+ self.renderResultCalled = False
+ self.renderErrorCalled = False
+
+ def update_cell_prompt(self, result, blockID=None):
+ self.updateCalled = True
+ return result
+
+ def render_result(self, result):
+ self.renderResultCalled = True
+ return result
+
+ def render_error(self, failure):
+ self.renderErrorCalled = True
+ return failure
+
+
+class TestAsyncFrontendBase(unittest.TestCase):
+ def setUp(self):
+ """Setup the EngineService and FrontEndBase"""
+
+ self.fb = FrontEndCallbackChecker(engine=EngineService())
+
+ def test_implements_IFrontEnd(self):
+ self.assert_(frontendbase.IFrontEnd.implementedBy(
+ AsyncFrontEndBase))
+
+ def test_is_complete_returns_False_for_incomplete_block(self):
+ block = """def test(a):"""
+ self.assert_(self.fb.is_complete(block) == False)
+
+ def test_is_complete_returns_True_for_complete_block(self):
+ block = """def test(a): pass"""
+ self.assert_(self.fb.is_complete(block))
+ block = """a=3"""
+ self.assert_(self.fb.is_complete(block))
+
+ def test_blockID_added_to_result(self):
+ block = """3+3"""
+ d = self.fb.execute(block, blockID='TEST_ID')
+ d.addCallback(lambda r: self.assert_(r['blockID']=='TEST_ID'))
+ return d
+
+ def test_blockID_added_to_failure(self):
+ block = "raise Exception()"
+ d = self.fb.execute(block,blockID='TEST_ID')
+ d.addErrback(lambda f: self.assert_(f.blockID=='TEST_ID'))
+ return d
+
+ def test_callbacks_added_to_execute(self):
+ d = self.fb.execute("10+10")
+ d.addCallback(lambda r: self.assert_(self.fb.updateCalled and self.fb.renderResultCalled))
+ return d
+
+ def test_error_callback_added_to_execute(self):
+ """Test that render_error called on execution error."""
+
+ d = self.fb.execute("raise Exception()")
+ d.addErrback(lambda f: self.assert_(self.fb.renderErrorCalled))
+ return d
+
+ def test_history_returns_expected_block(self):
+ """Make sure history browsing doesn't fail."""
+
+ blocks = ["a=1","a=2","a=3"]
+ d = self.fb.execute(blocks[0])
+ d.addCallback(lambda _: self.fb.execute(blocks[1]))
+ d.addCallback(lambda _: self.fb.execute(blocks[2]))
+ d.addCallback(lambda _: self.assert_(self.fb.get_history_previous("")==blocks[-2]))
+ d.addCallback(lambda _: self.assert_(self.fb.get_history_previous("")==blocks[-3]))
+ d.addCallback(lambda _: self.assert_(self.fb.get_history_next()==blocks[-2]))
+ return d
+
+ def test_history_returns_none_at_startup(self):
+ self.assert_(self.fb.get_history_previous("")==None)
+ self.assert_(self.fb.get_history_next()==None)
diff --git a/IPython/frontend/tests/test_frontendbase.py b/IPython/frontend/tests/test_frontendbase.py
new file mode 100644
index 0000000..f3f4e5a
--- /dev/null
+++ b/IPython/frontend/tests/test_frontendbase.py
@@ -0,0 +1,32 @@
+# encoding: utf-8
+"""
+Test the basic functionality of frontendbase.
+"""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is
+# in the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+from IPython.frontend.frontendbase import FrontEndBase
+
+def test_iscomplete():
+ """ Check that is_complete works.
+ """
+ f = FrontEndBase()
+ assert f.is_complete('(a + a)')
+ assert not f.is_complete('(a + a')
+ assert f.is_complete('1')
+ assert not f.is_complete('1 + ')
+ assert not f.is_complete('1 + \n\n')
+ assert f.is_complete('if True:\n print 1\n')
+ assert not f.is_complete('if True:\n print 1')
+ assert f.is_complete('def f():\n print 1\n')
+
+if __name__ == '__main__':
+ test_iscomplete()
+
diff --git a/IPython/frontend/tests/test_linefrontend.py b/IPython/frontend/tests/test_linefrontend.py
new file mode 100644
index 0000000..d0d53ac
--- /dev/null
+++ b/IPython/frontend/tests/test_linefrontend.py
@@ -0,0 +1,37 @@
+# encoding: utf-8
+"""
+Test the LineFrontEnd
+"""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is
+# in the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+from IPython.frontend.linefrontendbase import LineFrontEndBase
+from copy import deepcopy
+import nose.tools as nt
+
+class ConcreteLineFrontEnd(LineFrontEndBase):
+ """ A concrete class to test the LineFrontEndBase.
+ """
+ def capture_output(self):
+ pass
+
+ def release_output(self):
+ pass
+
+
+def test_is_complete():
+ """ Tests line completion heuristic.
+ """
+ frontend = ConcreteLineFrontEnd()
+ yield nt.assert_true, not frontend.is_complete('for x in \\')
+ yield nt.assert_true, not frontend.is_complete('for x in (1, ):')
+ yield nt.assert_true, frontend.is_complete('for x in (1, ):\n pass')
+
+
diff --git a/IPython/frontend/tests/test_prefilterfrontend.py b/IPython/frontend/tests/test_prefilterfrontend.py
new file mode 100644
index 0000000..a636029
--- /dev/null
+++ b/IPython/frontend/tests/test_prefilterfrontend.py
@@ -0,0 +1,266 @@
+# encoding: utf-8
+"""
+Test process execution and IO redirection.
+"""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is
+# in the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+from copy import copy, deepcopy
+from cStringIO import StringIO
+import string
+import sys
+
+from nose.tools import assert_equal
+
+from IPython.frontend.prefilterfrontend import PrefilterFrontEnd
+from IPython.ipapi import get as get_ipython0
+from IPython.testing.plugin.ipdoctest import default_argv
+
+
+class TestPrefilterFrontEnd(PrefilterFrontEnd):
+
+ input_prompt_template = string.Template('')
+ output_prompt_template = string.Template('')
+ banner = ''
+
+ def __init__(self):
+ self.out = StringIO()
+ PrefilterFrontEnd.__init__(self,argv=default_argv())
+ # Some more code for isolation (yeah, crazy)
+ self._on_enter()
+ self.out.flush()
+ self.out.reset()
+ self.out.truncate()
+
+ def write(self, string, *args, **kwargs):
+ self.out.write(string)
+
+ def _on_enter(self):
+ self.input_buffer += '\n'
+ PrefilterFrontEnd._on_enter(self)
+
+
+def isolate_ipython0(func):
+ """ Decorator to isolate execution that involves an iptyhon0.
+
+ Notes
+ -----
+
+ Apply only to functions with no arguments. Nose skips functions
+ with arguments.
+ """
+ def my_func():
+ ip0 = get_ipython0()
+ if ip0 is None:
+ return func()
+ # We have a real ipython running...
+ user_ns = ip0.IP.user_ns
+ user_global_ns = ip0.IP.user_global_ns
+
+ # Previously the isolation was attempted with a deep copy of the user
+ # dicts, but we found cases where this didn't work correctly. I'm not
+ # quite sure why, but basically it did damage the user namespace, such
+ # that later tests stopped working correctly. Instead we use a simpler
+ # approach, just computing the list of added keys to the namespace and
+ # eliminating those afterwards. Existing keys that may have been
+ # modified remain modified. So far this has proven to be robust.
+
+ # Compute set of old local/global keys
+ old_locals = set(user_ns.keys())
+ old_globals = set(user_global_ns.keys())
+ try:
+ out = func()
+ finally:
+ # Find new keys, and if any, remove them
+ new_locals = set(user_ns.keys()) - old_locals
+ new_globals = set(user_global_ns.keys()) - old_globals
+ for k in new_locals:
+ del user_ns[k]
+ for k in new_globals:
+ del user_global_ns[k]
+ # Undo the hack at creation of PrefilterFrontEnd
+ from IPython import iplib
+ iplib.InteractiveShell.isthreaded = False
+ return out
+
+ my_func.__name__ = func.__name__
+ return my_func
+
+
+@isolate_ipython0
+def test_execution():
+ """ Test execution of a command.
+ """
+ f = TestPrefilterFrontEnd()
+ f.input_buffer = 'print(1)'
+ f._on_enter()
+ out_value = f.out.getvalue()
+ assert_equal(out_value, '1\n')
+
+
+@isolate_ipython0
+def test_multiline():
+ """ Test execution of a multiline command.
+ """
+ f = TestPrefilterFrontEnd()
+ f.input_buffer = 'if True:'
+ f._on_enter()
+ f.input_buffer += 'print 1'
+ f._on_enter()
+ out_value = f.out.getvalue()
+ yield assert_equal, out_value, ''
+ f._on_enter()
+ out_value = f.out.getvalue()
+ yield assert_equal, out_value, '1\n'
+ f = TestPrefilterFrontEnd()
+ f.input_buffer='(1 +'
+ f._on_enter()
+ f.input_buffer += '0)'
+ f._on_enter()
+ out_value = f.out.getvalue()
+ yield assert_equal, out_value, ''
+ f._on_enter()
+ out_value = f.out.getvalue()
+ yield assert_equal, out_value, '1\n'
+
+
+@isolate_ipython0
+def test_capture():
+ """ Test the capture of output in different channels.
+ """
+ # Test on the OS-level stdout, stderr.
+ f = TestPrefilterFrontEnd()
+ f.input_buffer = \
+ 'import os; out=os.fdopen(1, "w"); out.write("1") ; out.flush()'
+ f._on_enter()
+ out_value = f.out.getvalue()
+ yield assert_equal, out_value, '1'
+ f = TestPrefilterFrontEnd()
+ f.input_buffer = \
+ 'import os; out=os.fdopen(2, "w"); out.write("1") ; out.flush()'
+ f._on_enter()
+ out_value = f.out.getvalue()
+ yield assert_equal, out_value, '1'
+
+
+@isolate_ipython0
+def test_magic():
+ """ Test the magic expansion and history.
+
+ This test is fairly fragile and will break when magics change.
+ """
+ f = TestPrefilterFrontEnd()
+ # Before checking the interactive namespace, make sure it's clear (it can
+ # otherwise pick up things stored in the user's local db)
+ f.input_buffer += '%reset -f'
+ f._on_enter()
+ f.complete_current_input()
+ # Now, run the %who magic and check output
+ f.input_buffer += '%who'
+ f._on_enter()
+ out_value = f.out.getvalue()
+ assert_equal(out_value, 'Interactive namespace is empty.\n')
+
+
+@isolate_ipython0
+def test_help():
+ """ Test object inspection.
+ """
+ f = TestPrefilterFrontEnd()
+ f.input_buffer += "def f():"
+ f._on_enter()
+ f.input_buffer += "'foobar'"
+ f._on_enter()
+ f.input_buffer += "pass"
+ f._on_enter()
+ f._on_enter()
+ f.input_buffer += "f?"
+ f._on_enter()
+ assert 'traceback' not in f.last_result
+ ## XXX: ipython doctest magic breaks this. I have no clue why
+ #out_value = f.out.getvalue()
+ #assert out_value.split()[-1] == 'foobar'
+
+
+@isolate_ipython0
+def test_completion_simple():
+ """ Test command-line completion on trivial examples.
+ """
+ f = TestPrefilterFrontEnd()
+ f.input_buffer = 'zzza = 1'
+ f._on_enter()
+ f.input_buffer = 'zzzb = 2'
+ f._on_enter()
+ f.input_buffer = 'zz'
+ f.complete_current_input()
+ out_value = f.out.getvalue()
+ yield assert_equal, out_value, '\nzzza zzzb '
+ yield assert_equal, f.input_buffer, 'zzz'
+
+
+@isolate_ipython0
+def test_completion_parenthesis():
+ """ Test command-line completion when a parenthesis is open.
+ """
+ f = TestPrefilterFrontEnd()
+ f.input_buffer = 'zzza = 1'
+ f._on_enter()
+ f.input_buffer = 'zzzb = 2'
+ f._on_enter()
+ f.input_buffer = 'map(zz'
+ f.complete_current_input()
+ out_value = f.out.getvalue()
+ yield assert_equal, out_value, '\nzzza zzzb '
+ yield assert_equal, f.input_buffer, 'map(zzz'
+
+
+@isolate_ipython0
+def test_completion_indexing():
+ """ Test command-line completion when indexing on objects.
+ """
+ f = TestPrefilterFrontEnd()
+ f.input_buffer = 'a = [0]'
+ f._on_enter()
+ f.input_buffer = 'a[0].'
+ f.complete_current_input()
+
+ if sys.version_info[:2] >= (2,6):
+ # In Python 2.6, ints picked up a few non __ methods, so now there are
+ # no completions.
+ assert_equal(f.input_buffer, 'a[0].')
+ else:
+ # Right answer for 2.4/2.5
+ assert_equal(f.input_buffer, 'a[0].__')
+
+
+@isolate_ipython0
+def test_completion_equal():
+ """ Test command-line completion when the delimiter is "=", not " ".
+ """
+ f = TestPrefilterFrontEnd()
+ f.input_buffer = 'a=1.'
+ f.complete_current_input()
+ if sys.version_info[:2] >= (2,6):
+ # In Python 2.6, ints picked up a few non __ methods, so now there are
+ # no completions.
+ assert_equal(f.input_buffer, 'a=1.')
+ else:
+ # Right answer for 2.4/2.5
+ assert_equal(f.input_buffer, 'a=1.__')
+
+
+if __name__ == '__main__':
+ test_magic()
+ test_help()
+ test_execution()
+ test_multiline()
+ test_capture()
+ test_completion_simple()
+ test_completion_complex()
diff --git a/IPython/frontend/tests/test_process.py b/IPython/frontend/tests/test_process.py
new file mode 100644
index 0000000..0b7adf8
--- /dev/null
+++ b/IPython/frontend/tests/test_process.py
@@ -0,0 +1,67 @@
+# encoding: utf-8
+"""
+Test process execution and IO redirection.
+"""
+
+__docformat__ = "restructuredtext en"
+
+#-----------------------------------------------------------------------------
+# Copyright (C) 2008-2009 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is
+# in the file COPYING, distributed as part of this software.
+#-----------------------------------------------------------------------------
+
+from cStringIO import StringIO
+from time import sleep
+import sys
+
+from IPython.frontend.process import PipedProcess
+from IPython.testing import decorators as testdec
+
+
+def test_capture_out():
+ """ A simple test to see if we can execute a process and get the output.
+ """
+ s = StringIO()
+ p = PipedProcess('echo 1', out_callback=s.write, )
+ p.start()
+ p.join()
+ result = s.getvalue().rstrip()
+ assert result == '1'
+
+
+def test_io():
+ """ Checks that we can send characters on stdin to the process.
+ """
+ s = StringIO()
+ p = PipedProcess(sys.executable + ' -c "a = raw_input(); print a"',
+ out_callback=s.write, )
+ p.start()
+ test_string = '12345\n'
+ while not hasattr(p, 'process'):
+ sleep(0.1)
+ p.process.stdin.write(test_string)
+ p.join()
+ result = s.getvalue()
+ assert result == test_string
+
+
+def test_kill():
+ """ Check that we can kill a process, and its subprocess.
+ """
+ s = StringIO()
+ p = PipedProcess(sys.executable + ' -c "a = raw_input();"',
+ out_callback=s.write, )
+ p.start()
+ while not hasattr(p, 'process'):
+ sleep(0.1)
+ p.process.kill()
+ assert p.process.poll() is not None
+
+
+if __name__ == '__main__':
+ test_capture_out()
+ test_io()
+ test_kill()
+
diff --git a/IPython/frontend/wx/__init__.py b/IPython/frontend/wx/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/IPython/frontend/wx/__init__.py
diff --git a/IPython/frontend/wx/console_widget.py b/IPython/frontend/wx/console_widget.py
new file mode 100644
index 0000000..8c7967f
--- /dev/null
+++ b/IPython/frontend/wx/console_widget.py
@@ -0,0 +1,624 @@
+# encoding: utf-8
+"""
+A Wx widget to act as a console and input commands.
+
+This widget deals with prompts and provides an edit buffer
+restricted to after the last prompt.
+"""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is
+# in the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+import wx
+import wx.stc as stc
+
+from wx.py import editwindow
+import time
+import sys
+import string
+
+LINESEP = '\n'
+if sys.platform == 'win32':
+ LINESEP = '\n\r'
+
+import re
+
+# FIXME: Need to provide an API for non user-generated display on the
+# screen: this should not be editable by the user.
+#-------------------------------------------------------------------------------
+# Constants
+#-------------------------------------------------------------------------------
+_COMPLETE_BUFFER_MARKER = 31
+_ERROR_MARKER = 30
+_INPUT_MARKER = 29
+
+_DEFAULT_SIZE = 10
+if sys.platform == 'darwin':
+ _DEFAULT_SIZE = 12
+
+_DEFAULT_STYLE = {
+ #background definition
+ 'default' : 'size:%d' % _DEFAULT_SIZE,
+ 'bracegood' : 'fore:#00AA00,back:#000000,bold',
+ 'bracebad' : 'fore:#FF0000,back:#000000,bold',
+
+ # Edge column: a number of None
+ 'edge_column' : -1,
+
+ # properties for the various Python lexer styles
+ 'comment' : 'fore:#007F00',
+ 'number' : 'fore:#007F7F',
+ 'string' : 'fore:#7F007F,italic',
+ 'char' : 'fore:#7F007F,italic',
+ 'keyword' : 'fore:#00007F,bold',
+ 'triple' : 'fore:#7F0000',
+ 'tripledouble' : 'fore:#7F0000',
+ 'class' : 'fore:#0000FF,bold,underline',
+ 'def' : 'fore:#007F7F,bold',
+ 'operator' : 'bold',
+
+ # Default colors
+ 'trace' : '#FAFAF1', # Nice green
+ 'stdout' : '#FDFFD3', # Nice yellow
+ 'stderr' : '#FFF1F1', # Nice red
+
+ # Default scintilla settings
+ 'antialiasing' : True,
+ 'carret_color' : 'BLACK',
+ 'background_color' :'WHITE',
+
+ #prompt definition
+ 'prompt_in1' : \
+ '\n\x01\x1b[0;34m\x02In [\x01\x1b[1;34m\x02$number\x01\x1b[0;34m\x02]: \x01\x1b[0m\x02',
+
+ 'prompt_out': \
+ '\x01\x1b[0;31m\x02Out[\x01\x1b[1;31m\x02$number\x01\x1b[0;31m\x02]: \x01\x1b[0m\x02',
+ }
+
+# new style numbers
+_STDOUT_STYLE = 15
+_STDERR_STYLE = 16
+_TRACE_STYLE = 17
+
+
+# system colors
+#SYS_COLOUR_BACKGROUND = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BACKGROUND)
+
+# Translation table from ANSI escape sequences to color.
+ANSI_STYLES = {'0;30': [0, 'BLACK'], '0;31': [1, 'RED'],
+ '0;32': [2, 'GREEN'], '0;33': [3, 'BROWN'],
+ '0;34': [4, 'BLUE'], '0;35': [5, 'PURPLE'],
+ '0;36': [6, 'CYAN'], '0;37': [7, 'LIGHT GREY'],
+ '1;30': [8, 'DARK GREY'], '1;31': [9, 'RED'],
+ '1;32': [10, 'SEA GREEN'], '1;33': [11, 'YELLOW'],
+ '1;34': [12, 'LIGHT BLUE'], '1;35':
+ [13, 'MEDIUM VIOLET RED'],
+ '1;36': [14, 'LIGHT STEEL BLUE'], '1;37': [15, 'YELLOW']}
+
+# XXX: Maybe one day we should factor this code with ColorANSI. Right now
+# ColorANSI is hard to reuse and makes our code more complex.
+
+#we define platform specific fonts
+if wx.Platform == '__WXMSW__':
+ FACES = { 'times': 'Times New Roman',
+ 'mono' : 'Courier New',
+ 'helv' : 'Arial',
+ 'other': 'Comic Sans MS',
+ 'size' : 10,
+ 'size2': 8,
+ }
+elif wx.Platform == '__WXMAC__':
+ FACES = { 'times': 'Times New Roman',
+ 'mono' : 'Monaco',
+ 'helv' : 'Arial',
+ 'other': 'Comic Sans MS',
+ 'size' : 10,
+ 'size2': 8,
+ }
+else:
+ FACES = { 'times': 'Times',
+ 'mono' : 'Courier',
+ 'helv' : 'Helvetica',
+ 'other': 'new century schoolbook',
+ 'size' : 10,
+ 'size2': 8,
+ }
+
+
+#-------------------------------------------------------------------------------
+# The console widget class
+#-------------------------------------------------------------------------------
+class ConsoleWidget(editwindow.EditWindow):
+ """ Specialized styled text control view for console-like workflow.
+
+ This widget is mainly interested in dealing with the prompt and
+ keeping the cursor inside the editing line.
+ """
+
+ # This is where the title captured from the ANSI escape sequences are
+ # stored.
+ title = 'Console'
+
+ # Last prompt printed
+ last_prompt = ''
+
+ # The buffer being edited.
+ def _set_input_buffer(self, string):
+ self.SetSelection(self.current_prompt_pos, self.GetLength())
+ self.ReplaceSelection(string)
+ self.GotoPos(self.GetLength())
+
+ def _get_input_buffer(self):
+ """ Returns the text in current edit buffer.
+ """
+ input_buffer = self.GetTextRange(self.current_prompt_pos,
+ self.GetLength())
+ input_buffer = input_buffer.replace(LINESEP, '\n')
+ return input_buffer
+
+ input_buffer = property(_get_input_buffer, _set_input_buffer)
+
+ style = _DEFAULT_STYLE.copy()
+
+ # Translation table from ANSI escape sequences to color. Override
+ # this to specify your colors.
+ ANSI_STYLES = ANSI_STYLES.copy()
+
+ # Font faces
+ faces = FACES.copy()
+
+ # Store the last time a refresh was done
+ _last_refresh_time = 0
+
+ #--------------------------------------------------------------------------
+ # Public API
+ #--------------------------------------------------------------------------
+
+ def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
+ size=wx.DefaultSize, style=wx.WANTS_CHARS, ):
+ editwindow.EditWindow.__init__(self, parent, id, pos, size, style)
+ self.configure_scintilla()
+ # Track if 'enter' key as ever been processed
+ # This variable will only be reallowed until key goes up
+ self.enter_catched = False
+ self.current_prompt_pos = 0
+
+ self.Bind(wx.EVT_KEY_DOWN, self._on_key_down)
+ self.Bind(wx.EVT_KEY_UP, self._on_key_up)
+
+
+ def write(self, text, refresh=True):
+ """ Write given text to buffer, while translating the ansi escape
+ sequences.
+ """
+ # XXX: do not put print statements to sys.stdout/sys.stderr in
+ # this method, the print statements will call this method, as
+ # you will end up with an infinit loop
+ title = self.title_pat.split(text)
+ if len(title)>1:
+ self.title = title[-2]
+
+ text = self.title_pat.sub('', text)
+ segments = self.color_pat.split(text)
+ segment = segments.pop(0)
+ self.GotoPos(self.GetLength())
+ self.StartStyling(self.GetLength(), 0xFF)
+ try:
+ self.AppendText(segment)
+ except UnicodeDecodeError:
+ # XXX: Do I really want to skip the exception?
+ pass
+
+ if segments:
+ for ansi_tag, text in zip(segments[::2], segments[1::2]):
+ self.StartStyling(self.GetLength(), 0xFF)
+ try:
+ self.AppendText(text)
+ except UnicodeDecodeError:
+ # XXX: Do I really want to skip the exception?
+ pass
+
+ if ansi_tag not in self.ANSI_STYLES:
+ style = 0
+ else:
+ style = self.ANSI_STYLES[ansi_tag][0]
+
+ self.SetStyling(len(text), style)
+
+ self.GotoPos(self.GetLength())
+ if refresh:
+ current_time = time.time()
+ if current_time - self._last_refresh_time > 0.03:
+ if sys.platform == 'win32':
+ wx.SafeYield()
+ else:
+ wx.Yield()
+ # self.ProcessEvent(wx.PaintEvent())
+ self._last_refresh_time = current_time
+
+
+ def new_prompt(self, prompt):
+ """ Prints a prompt at start of line, and move the start of the
+ current block there.
+
+ The prompt can be given with ascii escape sequences.
+ """
+ self.write(prompt, refresh=False)
+ # now we update our cursor giving end of prompt
+ self.current_prompt_pos = self.GetLength()
+ self.current_prompt_line = self.GetCurrentLine()
+ self.EnsureCaretVisible()
+ self.last_prompt = prompt
+
+
+ def continuation_prompt(self):
+ """ Returns the current continuation prompt.
+ We need to implement this method here to deal with the
+ ascii escape sequences cleaning up.
+ """
+ # ASCII-less prompt
+ ascii_less = ''.join(self.color_pat.split(self.last_prompt)[2::2])
+ return "."*(len(ascii_less)-2) + ': '
+
+
+ def scroll_to_bottom(self):
+ maxrange = self.GetScrollRange(wx.VERTICAL)
+ self.ScrollLines(maxrange)
+
+
+ def pop_completion(self, possibilities, offset=0):
+ """ Pops up an autocompletion menu. Offset is the offset
+ in characters of the position at which the menu should
+ appear, relativ to the cursor.
+ """
+ self.AutoCompSetIgnoreCase(False)
+ self.AutoCompSetAutoHide(False)
+ self.AutoCompSetMaxHeight(len(possibilities))
+ self.AutoCompShow(offset, " ".join(possibilities))
+
+
+ def get_line_width(self):
+ """ Return the width of the line in characters.
+ """
+ return self.GetSize()[0]/self.GetCharWidth()
+
+
+ def configure_scintilla(self):
+ """ Set up all the styling option of the embedded scintilla
+ widget.
+ """
+ p = self.style.copy()
+
+ # Marker for complete buffer.
+ self.MarkerDefine(_COMPLETE_BUFFER_MARKER, stc.STC_MARK_BACKGROUND,
+ background=p['trace'])
+
+ # Marker for current input buffer.
+ self.MarkerDefine(_INPUT_MARKER, stc.STC_MARK_BACKGROUND,
+ background=p['stdout'])
+ # Marker for tracebacks.
+ self.MarkerDefine(_ERROR_MARKER, stc.STC_MARK_BACKGROUND,
+ background=p['stderr'])
+
+ self.SetEOLMode(stc.STC_EOL_LF)
+
+ # Ctrl"+" or Ctrl "-" can be used to zoomin/zoomout the text inside
+ # the widget
+ self.CmdKeyAssign(ord('+'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
+ self.CmdKeyAssign(ord('-'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)
+ # Also allow Ctrl Shift "=" for poor non US keyboard users.
+ self.CmdKeyAssign(ord('='), stc.STC_SCMOD_CTRL|stc.STC_SCMOD_SHIFT,
+ stc.STC_CMD_ZOOMIN)
+
+ # Keys: we need to clear some of the keys the that don't play
+ # well with a console.
+ self.CmdKeyClear(ord('D'), stc.STC_SCMOD_CTRL)
+ self.CmdKeyClear(ord('L'), stc.STC_SCMOD_CTRL)
+ self.CmdKeyClear(ord('T'), stc.STC_SCMOD_CTRL)
+ self.CmdKeyClear(ord('A'), stc.STC_SCMOD_CTRL)
+
+ self.SetEOLMode(stc.STC_EOL_CRLF)
+ self.SetWrapMode(stc.STC_WRAP_CHAR)
+ self.SetWrapMode(stc.STC_WRAP_WORD)
+ self.SetBufferedDraw(True)
+
+ self.SetUseAntiAliasing(p['antialiasing'])
+
+ self.SetLayoutCache(stc.STC_CACHE_PAGE)
+ self.SetUndoCollection(False)
+ self.SetUseTabs(True)
+ self.SetIndent(4)
+ self.SetTabWidth(4)
+
+ # we don't want scintilla's autocompletion to choose
+ # automaticaly out of a single choice list, as we pop it up
+ # automaticaly
+ self.AutoCompSetChooseSingle(False)
+ self.AutoCompSetMaxHeight(10)
+ # XXX: this doesn't seem to have an effect.
+ self.AutoCompSetFillUps('\n')
+
+ self.SetMargins(3, 3) #text is moved away from border with 3px
+ # Suppressing Scintilla margins
+ self.SetMarginWidth(0, 0)
+ self.SetMarginWidth(1, 0)
+ self.SetMarginWidth(2, 0)
+
+ # Xterm escape sequences
+ self.color_pat = re.compile('\x01?\x1b\[(.*?)m\x02?')
+ self.title_pat = re.compile('\x1b]0;(.*?)\x07')
+
+ # styles
+
+ self.SetCaretForeground(p['carret_color'])
+
+ background_color = p['background_color']
+
+ if 'default' in p:
+ if 'back' not in p['default']:
+ p['default'] += ',back:%s' % background_color
+ if 'size' not in p['default']:
+ p['default'] += ',size:%s' % self.faces['size']
+ if 'face' not in p['default']:
+ p['default'] += ',face:%s' % self.faces['mono']
+
+ self.StyleSetSpec(stc.STC_STYLE_DEFAULT, p['default'])
+ else:
+ self.StyleSetSpec(stc.STC_STYLE_DEFAULT,
+ "fore:%s,back:%s,size:%d,face:%s"
+ % (self.ANSI_STYLES['0;30'][1],
+ background_color,
+ self.faces['size'], self.faces['mono']))
+
+ self.StyleClearAll()
+
+ # XXX: two lines below are usefull if not using the lexer
+ #for style in self.ANSI_STYLES.values():
+ # self.StyleSetSpec(style[0], "bold,fore:%s" % style[1])
+
+ # prompt definition
+ self.prompt_in1 = p['prompt_in1']
+ self.prompt_out = p['prompt_out']
+
+ self.output_prompt_template = string.Template(self.prompt_out)
+ self.input_prompt_template = string.Template(self.prompt_in1)
+
+ self.StyleSetSpec(_STDOUT_STYLE, p['stdout'])
+ self.StyleSetSpec(_STDERR_STYLE, p['stderr'])
+ self.StyleSetSpec(_TRACE_STYLE, p['trace'])
+ self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, p['bracegood'])
+ self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, p['bracebad'])
+ self.StyleSetSpec(stc.STC_P_COMMENTLINE, p['comment'])
+ self.StyleSetSpec(stc.STC_P_NUMBER, p['number'])
+ self.StyleSetSpec(stc.STC_P_STRING, p['string'])
+ self.StyleSetSpec(stc.STC_P_CHARACTER, p['char'])
+ self.StyleSetSpec(stc.STC_P_WORD, p['keyword'])
+ self.StyleSetSpec(stc.STC_P_WORD2, p['keyword'])
+ self.StyleSetSpec(stc.STC_P_TRIPLE, p['triple'])
+ self.StyleSetSpec(stc.STC_P_TRIPLEDOUBLE, p['tripledouble'])
+ self.StyleSetSpec(stc.STC_P_CLASSNAME, p['class'])
+ self.StyleSetSpec(stc.STC_P_DEFNAME, p['def'])
+ self.StyleSetSpec(stc.STC_P_OPERATOR, p['operator'])
+ self.StyleSetSpec(stc.STC_P_COMMENTBLOCK, p['comment'])
+
+ edge_column = p['edge_column']
+ if edge_column is not None and edge_column > 0:
+ #we add a vertical line to console widget
+ self.SetEdgeMode(stc.STC_EDGE_LINE)
+ self.SetEdgeColumn(edge_column)
+
+
+ #--------------------------------------------------------------------------
+ # EditWindow API
+ #--------------------------------------------------------------------------
+
+ def OnUpdateUI(self, event):
+ """ Override the OnUpdateUI of the EditWindow class, to prevent
+ syntax highlighting both for faster redraw, and for more
+ consistent look and feel.
+ """
+
+
+ #--------------------------------------------------------------------------
+ # Private API
+ #--------------------------------------------------------------------------
+
+ def _on_key_down(self, event, skip=True):
+ """ Key press callback used for correcting behavior for
+ console-like interfaces: the cursor is constraint to be after
+ the last prompt.
+
+ Return True if event as been catched.
+ """
+ catched = True
+ # XXX: Would the right way to do this be to have a
+ # dictionary at the instance level associating keys with
+ # callbacks? How would we deal with inheritance? And Do the
+ # different callbacks share local variables?
+
+ # Intercept some specific keys.
+ key_code = event.GetKeyCode()
+ if key_code == ord('L') and event.ControlDown() :
+ self.scroll_to_bottom()
+ elif key_code == ord('K') and event.ControlDown() :
+ self.input_buffer = ''
+ elif key_code == ord('A') and event.ControlDown() :
+ self.GotoPos(self.GetLength())
+ self.SetSelectionStart(self.current_prompt_pos)
+ self.SetSelectionEnd(self.GetCurrentPos())
+ catched = True
+ elif key_code == ord('E') and event.ControlDown() :
+ self.GotoPos(self.GetLength())
+ catched = True
+ elif key_code == wx.WXK_PAGEUP:
+ self.ScrollPages(-1)
+ elif key_code == wx.WXK_PAGEDOWN:
+ self.ScrollPages(1)
+ elif key_code == wx.WXK_HOME:
+ self.GotoPos(self.GetLength())
+ elif key_code == wx.WXK_END:
+ self.GotoPos(self.GetLength())
+ elif key_code == wx.WXK_UP and event.ShiftDown():
+ self.ScrollLines(-1)
+ elif key_code == wx.WXK_DOWN and event.ShiftDown():
+ self.ScrollLines(1)
+ else:
+ catched = False
+
+ if self.AutoCompActive():
+ event.Skip()
+ else:
+ if key_code in (13, wx.WXK_NUMPAD_ENTER):
+ # XXX: not catching modifiers, to be wx2.6-compatible
+ catched = True
+ if not self.enter_catched:
+ self.CallTipCancel()
+ if event.ShiftDown():
+ # Try to force execution
+ self.GotoPos(self.GetLength())
+ self.write('\n' + self.continuation_prompt(),
+ refresh=False)
+ self._on_enter()
+ else:
+ self._on_enter()
+ self.enter_catched = True
+
+ elif key_code == wx.WXK_HOME:
+ if not event.ShiftDown():
+ self.GotoPos(self.current_prompt_pos)
+ catched = True
+ else:
+ # FIXME: This behavior is not ideal: if the selection
+ # is already started, it will jump.
+ self.SetSelectionStart(self.current_prompt_pos)
+ self.SetSelectionEnd(self.GetCurrentPos())
+ catched = True
+
+ elif key_code == wx.WXK_UP:
+ if self.GetCurrentLine() > self.current_prompt_line:
+ if self.GetCurrentLine() == self.current_prompt_line + 1 \
+ and self.GetColumn(self.GetCurrentPos()) < \
+ self.GetColumn(self.current_prompt_pos):
+ self.GotoPos(self.current_prompt_pos)
+ else:
+ event.Skip()
+ catched = True
+
+ elif key_code in (wx.WXK_LEFT, wx.WXK_BACK):
+ if not self._keep_cursor_in_buffer(self.GetCurrentPos() - 1):
+ event.Skip()
+ catched = True
+
+ elif key_code == wx.WXK_RIGHT:
+ if not self._keep_cursor_in_buffer(self.GetCurrentPos() + 1):
+ event.Skip()
+ catched = True
+
+
+ elif key_code == wx.WXK_DELETE:
+ if not self._keep_cursor_in_buffer(self.GetCurrentPos() - 1):
+ event.Skip()
+ catched = True
+
+ if skip and not catched:
+ # Put the cursor back in the edit region
+ if not self._keep_cursor_in_buffer():
+ if not (self.GetCurrentPos() == self.GetLength()
+ and key_code == wx.WXK_DELETE):
+ event.Skip()
+ catched = True
+
+ return catched
+
+
+ def _on_key_up(self, event, skip=True):
+ """ If cursor is outside the editing region, put it back.
+ """
+ if skip:
+ event.Skip()
+ self._keep_cursor_in_buffer()
+
+
+ # XXX: I need to avoid the problem of having an empty glass;
+ def _keep_cursor_in_buffer(self, pos=None):
+ """ Checks if the cursor is where it is allowed to be. If not,
+ put it back.
+
+ Returns
+ -------
+ cursor_moved: Boolean
+ whether or not the cursor was moved by this routine.
+
+ Notes
+ ------
+ WARNING: This does proper checks only for horizontal
+ movements.
+ """
+ if pos is None:
+ current_pos = self.GetCurrentPos()
+ else:
+ current_pos = pos
+ if current_pos < self.current_prompt_pos:
+ self.GotoPos(self.current_prompt_pos)
+ return True
+ line_num = self.LineFromPosition(current_pos)
+ if not current_pos > self.GetLength():
+ line_pos = self.GetColumn(current_pos)
+ else:
+ line_pos = self.GetColumn(self.GetLength())
+ line = self.GetLine(line_num)
+ # Jump the continuation prompt
+ continuation_prompt = self.continuation_prompt()
+ if ( line.startswith(continuation_prompt)
+ and line_pos < len(continuation_prompt)):
+ if line_pos < 2:
+ # We are at the beginning of the line, trying to move
+ # forward: jump forward.
+ self.GotoPos(current_pos + 1 +
+ len(continuation_prompt) - line_pos)
+ else:
+ # Jump back up
+ self.GotoPos(self.GetLineEndPosition(line_num-1))
+ return True
+ elif ( current_pos > self.GetLineEndPosition(line_num)
+ and not current_pos == self.GetLength()):
+ # Jump to next line
+ self.GotoPos(current_pos + 1 +
+ len(continuation_prompt))
+ return True
+
+ # We re-allow enter event processing
+ self.enter_catched = False
+ return False
+
+
+if __name__ == '__main__':
+ # Some simple code to test the console widget.
+ class MainWindow(wx.Frame):
+ def __init__(self, parent, id, title):
+ wx.Frame.__init__(self, parent, id, title, size=(300, 250))
+ self._sizer = wx.BoxSizer(wx.VERTICAL)
+ self.console_widget = ConsoleWidget(self)
+ self._sizer.Add(self.console_widget, 1, wx.EXPAND)
+ self.SetSizer(self._sizer)
+ self.SetAutoLayout(1)
+ self.Show(True)
+
+ app = wx.PySimpleApp()
+ w = MainWindow(None, wx.ID_ANY, 'ConsoleWidget')
+ w.SetSize((780, 460))
+ w.Show()
+
+ app.MainLoop()
+
+
diff --git a/IPython/frontend/wx/ipythonx.py b/IPython/frontend/wx/ipythonx.py
new file mode 100644
index 0000000..af7d322
--- /dev/null
+++ b/IPython/frontend/wx/ipythonx.py
@@ -0,0 +1,119 @@
+"""
+Entry point for a simple application giving a graphical frontend to
+ipython.
+"""
+
+try:
+ import wx
+except ImportError, e:
+ e.message = """%s
+________________________________________________________________________________
+You need wxPython to run this application.
+""" % e.message
+ e.args = (e.message, ) + e.args[1:]
+ raise e
+
+from wx_frontend import WxController
+import __builtin__
+
+
+class IPythonXController(WxController):
+ """ Sub class of WxController that adds some application-specific
+ bindings.
+ """
+
+ debug = False
+
+ def __init__(self, *args, **kwargs):
+ WxController.__init__(self, *args, **kwargs)
+ self.ipython0.ask_exit = self.do_exit
+ # Scroll to top
+ maxrange = self.GetScrollRange(wx.VERTICAL)
+ self.ScrollLines(-maxrange)
+
+
+ def _on_key_down(self, event, skip=True):
+ # Intercept Ctrl-D to quit
+ if event.KeyCode == ord('D') and event.ControlDown() and \
+ self.input_buffer == '' and \
+ self._input_state == 'readline':
+ wx.CallAfter(self.ask_exit)
+ else:
+ WxController._on_key_down(self, event, skip=skip)
+
+
+ def ask_exit(self):
+ """ Ask the user whether to exit.
+ """
+ self._input_state = 'subprocess'
+ self.write('\n', refresh=False)
+ self.capture_output()
+ self.ipython0.shell.exit()
+ self.release_output()
+ if not self.ipython0.exit_now:
+ wx.CallAfter(self.new_prompt,
+ self.input_prompt_template.substitute(
+ number=self.last_result['number'] + 1))
+ else:
+ wx.CallAfter(wx.GetApp().Exit)
+ self.write('Exiting ...', refresh=False)
+
+
+ def do_exit(self):
+ """ Exits the interpreter, kills the windows.
+ """
+ WxController.do_exit(self)
+ self.release_output()
+ wx.CallAfter(wx.Exit)
+
+
+
+class IPythonX(wx.Frame):
+ """ Main frame of the IPythonX app.
+ """
+
+ def __init__(self, parent, id, title, debug=False):
+ wx.Frame.__init__(self, parent, id, title, size=(300,250))
+ self._sizer = wx.BoxSizer(wx.VERTICAL)
+ self.shell = IPythonXController(self, debug=debug)
+ self._sizer.Add(self.shell, 1, wx.EXPAND)
+ self.SetSizer(self._sizer)
+ self.SetAutoLayout(1)
+ self.Show(True)
+ wx.EVT_CLOSE(self, self.on_close)
+
+
+ def on_close(self, event):
+ """ Called on closing the windows.
+
+ Stops the event loop, to close all the child windows.
+ """
+ wx.CallAfter(wx.Exit)
+
+
+def main():
+ from optparse import OptionParser
+ usage = """usage: %prog [options]
+
+Simple graphical frontend to IPython, using WxWidgets."""
+ parser = OptionParser(usage=usage)
+ parser.add_option("-d", "--debug",
+ action="store_true", dest="debug", default=False,
+ help="Enable debug message for the wx frontend.")
+
+ options, args = parser.parse_args()
+
+ # Clear the options, to avoid having the ipython0 instance complain
+ import sys
+ sys.argv = sys.argv[:1]
+
+ app = wx.PySimpleApp()
+ frame = IPythonX(None, wx.ID_ANY, 'IPythonX', debug=options.debug)
+ frame.shell.SetFocus()
+ frame.shell.app = app
+ frame.SetSize((680, 460))
+
+ app.MainLoop()
+
+if __name__ == '__main__':
+ main()
diff --git a/IPython/frontend/wx/wx_frontend.py b/IPython/frontend/wx/wx_frontend.py
new file mode 100644
index 0000000..e22c91e
--- /dev/null
+++ b/IPython/frontend/wx/wx_frontend.py
@@ -0,0 +1,602 @@
+# encoding: utf-8 -*- test-case-name:
+# FIXME: Need to add tests.
+# ipython1.frontend.wx.tests.test_wx_frontend -*-
+
+"""Classes to provide a Wx frontend to the
+IPython.kernel.core.interpreter.
+
+This class inherits from ConsoleWidget, that provides a console-like
+widget to provide a text-rendering widget suitable for a terminal.
+"""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+# Major library imports
+import re
+import __builtin__
+import sys
+from threading import Lock
+
+import wx
+from wx import stc
+
+# Ipython-specific imports.
+from IPython.frontend.process import PipedProcess
+from console_widget import ConsoleWidget, _COMPLETE_BUFFER_MARKER, \
+ _ERROR_MARKER, _INPUT_MARKER
+from IPython.frontend.prefilterfrontend import PrefilterFrontEnd
+
+#-------------------------------------------------------------------------------
+# Classes to implement the Wx frontend
+#-------------------------------------------------------------------------------
+class WxController(ConsoleWidget, PrefilterFrontEnd):
+ """Classes to provide a Wx frontend to the
+ IPython.kernel.core.interpreter.
+
+ This class inherits from ConsoleWidget, that provides a console-like
+ widget to provide a text-rendering widget suitable for a terminal.
+ """
+
+ # Print debug info on what is happening to the console.
+ debug = False
+
+ # The title of the terminal, as captured through the ANSI escape
+ # sequences.
+ def _set_title(self, title):
+ return self.Parent.SetTitle(title)
+
+ def _get_title(self):
+ return self.Parent.GetTitle()
+
+ title = property(_get_title, _set_title)
+
+
+ # The buffer being edited.
+ # We are duplicating the definition here because of multiple
+ # inheritence
+ def _set_input_buffer(self, string):
+ ConsoleWidget._set_input_buffer(self, string)
+ self._colorize_input_buffer()
+
+ def _get_input_buffer(self):
+ """ Returns the text in current edit buffer.
+ """
+ return ConsoleWidget._get_input_buffer(self)
+
+ input_buffer = property(_get_input_buffer, _set_input_buffer)
+
+
+ #--------------------------------------------------------------------------
+ # Private Attributes
+ #--------------------------------------------------------------------------
+
+ # A flag governing the behavior of the input. Can be:
+ #
+ # 'readline' for readline-like behavior with a prompt
+ # and an edit buffer.
+ # 'raw_input' similar to readline, but triggered by a raw-input
+ # call. Can be used by subclasses to act differently.
+ # 'subprocess' for sending the raw input directly to a
+ # subprocess.
+ # 'buffering' for buffering of the input, that will be used
+ # when the input state switches back to another state.
+ _input_state = 'readline'
+
+ # Attribute to store reference to the pipes of a subprocess, if we
+ # are running any.
+ _running_process = False
+
+ # A queue for writing fast streams to the screen without flooding the
+ # event loop
+ _out_buffer = []
+
+ # A lock to lock the _out_buffer to make sure we don't empty it
+ # while it is being swapped
+ _out_buffer_lock = Lock()
+
+ # The different line markers used to higlight the prompts.
+ _markers = dict()
+
+ #--------------------------------------------------------------------------
+ # Public API
+ #--------------------------------------------------------------------------
+
+ def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
+ size=wx.DefaultSize,
+ style=wx.CLIP_CHILDREN|wx.WANTS_CHARS,
+ styledef=None,
+ *args, **kwds):
+ """ Create Shell instance.
+
+ Parameters
+ -----------
+ styledef : dict, optional
+ styledef is the dictionary of options used to define the
+ style.
+ """
+ if styledef is not None:
+ self.style = styledef
+ ConsoleWidget.__init__(self, parent, id, pos, size, style)
+ PrefilterFrontEnd.__init__(self, **kwds)
+
+ # Stick in our own raw_input:
+ self.ipython0.raw_input = self.raw_input
+
+ # A time for flushing the write buffer
+ BUFFER_FLUSH_TIMER_ID = 100
+ self._buffer_flush_timer = wx.Timer(self, BUFFER_FLUSH_TIMER_ID)
+ wx.EVT_TIMER(self, BUFFER_FLUSH_TIMER_ID, self._buffer_flush)
+
+ if 'debug' in kwds:
+ self.debug = kwds['debug']
+ kwds.pop('debug')
+
+ # Inject self in namespace, for debug
+ if self.debug:
+ self.shell.user_ns['self'] = self
+ # Inject our own raw_input in namespace
+ self.shell.user_ns['raw_input'] = self.raw_input
+
+ def raw_input(self, prompt=''):
+ """ A replacement from python's raw_input.
+ """
+ self.new_prompt(prompt)
+ self._input_state = 'raw_input'
+ if hasattr(self, '_cursor'):
+ del self._cursor
+ self.SetCursor(wx.StockCursor(wx.CURSOR_CROSS))
+ self.__old_on_enter = self._on_enter
+ event_loop = wx.EventLoop()
+ def my_on_enter():
+ event_loop.Exit()
+ self._on_enter = my_on_enter
+ # XXX: Running a separate event_loop. Ugly.
+ event_loop.Run()
+ self._on_enter = self.__old_on_enter
+ self._input_state = 'buffering'
+ self._cursor = wx.BusyCursor()
+ return self.input_buffer.rstrip('\n')
+
+
+ def system_call(self, command_string):
+ self._input_state = 'subprocess'
+ event_loop = wx.EventLoop()
+ def _end_system_call():
+ self._input_state = 'buffering'
+ self._running_process = False
+ event_loop.Exit()
+
+ self._running_process = PipedProcess(command_string,
+ out_callback=self.buffered_write,
+ end_callback = _end_system_call)
+ self._running_process.start()
+ # XXX: Running a separate event_loop. Ugly.
+ event_loop.Run()
+ # Be sure to flush the buffer.
+ self._buffer_flush(event=None)
+
+
+ def do_calltip(self):
+ """ Analyse current and displays useful calltip for it.
+ """
+ if self.debug:
+ print >>sys.__stdout__, "do_calltip"
+ separators = re.compile('[\s\{\}\[\]\(\)\= ,:]')
+ symbol = self.input_buffer
+ symbol_string = separators.split(symbol)[-1]
+ base_symbol_string = symbol_string.split('.')[0]
+ if base_symbol_string in self.shell.user_ns:
+ symbol = self.shell.user_ns[base_symbol_string]
+ elif base_symbol_string in self.shell.user_global_ns:
+ symbol = self.shell.user_global_ns[base_symbol_string]
+ elif base_symbol_string in __builtin__.__dict__:
+ symbol = __builtin__.__dict__[base_symbol_string]
+ else:
+ return False
+ try:
+ for name in symbol_string.split('.')[1:] + ['__doc__']:
+ symbol = getattr(symbol, name)
+ self.AutoCompCancel()
+ # Check that the symbol can indeed be converted to a string:
+ symbol += ''
+ wx.CallAfter(self.CallTipShow, self.GetCurrentPos(), symbol)
+ except:
+ # The retrieve symbol couldn't be converted to a string
+ pass
+
+
+ def _popup_completion(self, create=False):
+ """ Updates the popup completion menu if it exists. If create is
+ true, open the menu.
+ """
+ if self.debug:
+ print >>sys.__stdout__, "_popup_completion"
+ line = self.input_buffer
+ if (self.AutoCompActive() and line and not line[-1] == '.') \
+ or create==True:
+ suggestion, completions = self.complete(line)
+ if completions:
+ offset = len(self._get_completion_text(line))
+ self.pop_completion(completions, offset=offset)
+ if self.debug:
+ print >>sys.__stdout__, completions
+
+
+ def buffered_write(self, text):
+ """ A write method for streams, that caches the stream in order
+ to avoid flooding the event loop.
+
+ This can be called outside of the main loop, in separate
+ threads.
+ """
+ self._out_buffer_lock.acquire()
+ self._out_buffer.append(text)
+ self._out_buffer_lock.release()
+ if not self._buffer_flush_timer.IsRunning():
+ wx.CallAfter(self._buffer_flush_timer.Start,
+ milliseconds=100, oneShot=True)
+
+
+ def clear_screen(self):
+ """ Empty completely the widget.
+ """
+ self.ClearAll()
+ self.new_prompt(self.input_prompt_template.substitute(
+ number=(self.last_result['number'] + 1)))
+
+
+ #--------------------------------------------------------------------------
+ # LineFrontEnd interface
+ #--------------------------------------------------------------------------
+
+ def execute(self, python_string, raw_string=None):
+ self._input_state = 'buffering'
+ self.CallTipCancel()
+ self._cursor = wx.BusyCursor()
+ if raw_string is None:
+ raw_string = python_string
+ end_line = self.current_prompt_line \
+ + max(1, len(raw_string.split('\n'))-1)
+ for i in range(self.current_prompt_line, end_line):
+ if i in self._markers:
+ self.MarkerDeleteHandle(self._markers[i])
+ self._markers[i] = self.MarkerAdd(i, _COMPLETE_BUFFER_MARKER)
+ # Use a callafter to update the display robustly under windows
+ def callback():
+ self.GotoPos(self.GetLength())
+ PrefilterFrontEnd.execute(self, python_string,
+ raw_string=raw_string)
+ wx.CallAfter(callback)
+
+
+ def execute_command(self, command, hidden=False):
+ """ Execute a command, not only in the model, but also in the
+ view.
+ """
+ # XXX: This method needs to be integrated in the base fronted
+ # interface
+ if hidden:
+ return self.shell.execute(command)
+ else:
+ # XXX: we are not storing the input buffer previous to the
+ # execution, as this forces us to run the execution
+ # input_buffer a yield, which is not good.
+ ##current_buffer = self.shell.control.input_buffer
+ command = command.rstrip()
+ if len(command.split('\n')) > 1:
+ # The input command is several lines long, we need to
+ # force the execution to happen
+ command += '\n'
+ cleaned_command = self.prefilter_input(command)
+ self.input_buffer = command
+ # Do not use wx.Yield() (aka GUI.process_events()) to avoid
+ # recursive yields.
+ self.ProcessEvent(wx.PaintEvent())
+ self.write('\n')
+ if not self.is_complete(cleaned_command + '\n'):
+ self._colorize_input_buffer()
+ self.render_error('Incomplete or invalid input')
+ self.new_prompt(self.input_prompt_template.substitute(
+ number=(self.last_result['number'] + 1)))
+ return False
+ self._on_enter()
+ return True
+
+
+ def save_output_hooks(self):
+ self.__old_raw_input = __builtin__.raw_input
+ PrefilterFrontEnd.save_output_hooks(self)
+
+ def capture_output(self):
+ self.SetLexer(stc.STC_LEX_NULL)
+ PrefilterFrontEnd.capture_output(self)
+ __builtin__.raw_input = self.raw_input
+
+
+ def release_output(self):
+ __builtin__.raw_input = self.__old_raw_input
+ PrefilterFrontEnd.release_output(self)
+ self.SetLexer(stc.STC_LEX_PYTHON)
+
+
+ def after_execute(self):
+ PrefilterFrontEnd.after_execute(self)
+ # Clear the wait cursor
+ if hasattr(self, '_cursor'):
+ del self._cursor
+ self.SetCursor(wx.StockCursor(wx.CURSOR_CHAR))
+
+
+ def show_traceback(self):
+ start_line = self.GetCurrentLine()
+ PrefilterFrontEnd.show_traceback(self)
+ self.ProcessEvent(wx.PaintEvent())
+ #wx.Yield()
+ for i in range(start_line, self.GetCurrentLine()):
+ self._markers[i] = self.MarkerAdd(i, _ERROR_MARKER)
+
+
+ #--------------------------------------------------------------------------
+ # FrontEndBase interface
+ #--------------------------------------------------------------------------
+
+ def render_error(self, e):
+ start_line = self.GetCurrentLine()
+ self.write('\n' + e + '\n')
+ for i in range(start_line, self.GetCurrentLine()):
+ self._markers[i] = self.MarkerAdd(i, _ERROR_MARKER)
+
+
+ #--------------------------------------------------------------------------
+ # ConsoleWidget interface
+ #--------------------------------------------------------------------------
+
+ def new_prompt(self, prompt):
+ """ Display a new prompt, and start a new input buffer.
+ """
+ self._input_state = 'readline'
+ ConsoleWidget.new_prompt(self, prompt)
+ i = self.current_prompt_line
+ self._markers[i] = self.MarkerAdd(i, _INPUT_MARKER)
+
+
+ def continuation_prompt(self, *args, **kwargs):
+ # Avoid multiple inheritence, be explicit about which
+ # parent method class gets called
+ return ConsoleWidget.continuation_prompt(self, *args, **kwargs)
+
+
+ def write(self, *args, **kwargs):
+ # Avoid multiple inheritence, be explicit about which
+ # parent method class gets called
+ return ConsoleWidget.write(self, *args, **kwargs)
+
+
+ def _on_key_down(self, event, skip=True):
+ """ Capture the character events, let the parent
+ widget handle them, and put our logic afterward.
+ """
+ # FIXME: This method needs to be broken down in smaller ones.
+ current_line_num = self.GetCurrentLine()
+ key_code = event.GetKeyCode()
+ if key_code in (ord('c'), ord('C')) and event.ControlDown():
+ # Capture Control-C
+ if self._input_state == 'subprocess':
+ if self.debug:
+ print >>sys.__stderr__, 'Killing running process'
+ if hasattr(self._running_process, 'process'):
+ self._running_process.process.kill()
+ elif self._input_state == 'buffering':
+ if self.debug:
+ print >>sys.__stderr__, 'Raising KeyboardInterrupt'
+ raise KeyboardInterrupt
+ # XXX: We need to make really sure we
+ # get back to a prompt.
+ elif self._input_state == 'subprocess' and (
+ ( key_code <256 and not event.ControlDown() )
+ or
+ ( key_code in (ord('d'), ord('D')) and
+ event.ControlDown())):
+ # We are running a process, we redirect keys.
+ ConsoleWidget._on_key_down(self, event, skip=skip)
+ char = chr(key_code)
+ # Deal with some inconsistency in wx keycodes:
+ if char == '\r':
+ char = '\n'
+ elif not event.ShiftDown():
+ char = char.lower()
+ if event.ControlDown() and key_code in (ord('d'), ord('D')):
+ char = '\04'
+ self._running_process.process.stdin.write(char)
+ self._running_process.process.stdin.flush()
+ elif key_code in (ord('('), 57, 53):
+ # Calltips
+ event.Skip()
+ self.do_calltip()
+ elif self.AutoCompActive() and not key_code == ord('\t'):
+ event.Skip()
+ if key_code in (wx.WXK_BACK, wx.WXK_DELETE):
+ wx.CallAfter(self._popup_completion, create=True)
+ elif not key_code in (wx.WXK_UP, wx.WXK_DOWN, wx.WXK_LEFT,
+ wx.WXK_RIGHT, wx.WXK_ESCAPE):
+ wx.CallAfter(self._popup_completion)
+ else:
+ # Up history
+ if key_code == wx.WXK_UP and (
+ event.ControlDown() or
+ current_line_num == self.current_prompt_line
+ ):
+ new_buffer = self.get_history_previous(
+ self.input_buffer)
+ if new_buffer is not None:
+ self.input_buffer = new_buffer
+ if self.GetCurrentLine() > self.current_prompt_line:
+ # Go to first line, for seemless history up.
+ self.GotoPos(self.current_prompt_pos)
+ # Down history
+ elif key_code == wx.WXK_DOWN and (
+ event.ControlDown() or
+ current_line_num == self.LineCount -1
+ ):
+ new_buffer = self.get_history_next()
+ if new_buffer is not None:
+ self.input_buffer = new_buffer
+ # Tab-completion
+ elif key_code == ord('\t'):
+ current_line, current_line_num = self.CurLine
+ if not re.match(r'^%s\s*$' % self.continuation_prompt(),
+ current_line):
+ self.complete_current_input()
+ if self.AutoCompActive():
+ wx.CallAfter(self._popup_completion, create=True)
+ else:
+ event.Skip()
+ elif key_code == wx.WXK_BACK:
+ # If characters where erased, check if we have to
+ # remove a line.
+ # XXX: What about DEL?
+ # FIXME: This logics should be in ConsoleWidget, as it is
+ # independant of IPython
+ current_line, _ = self.CurLine
+ current_pos = self.GetCurrentPos()
+ current_line_num = self.LineFromPosition(current_pos)
+ current_col = self.GetColumn(current_pos)
+ len_prompt = len(self.continuation_prompt())
+ if ( current_line.startswith(self.continuation_prompt())
+ and current_col == len_prompt):
+ new_lines = []
+ for line_num, line in enumerate(
+ self.input_buffer.split('\n')):
+ if (line_num + self.current_prompt_line ==
+ current_line_num):
+ new_lines.append(line[len_prompt:])
+ else:
+ new_lines.append('\n'+line)
+ # The first character is '\n', due to the above
+ # code:
+ self.input_buffer = ''.join(new_lines)[1:]
+ self.GotoPos(current_pos - 1 - len_prompt)
+ else:
+ ConsoleWidget._on_key_down(self, event, skip=skip)
+ else:
+ ConsoleWidget._on_key_down(self, event, skip=skip)
+
+
+
+ def _on_key_up(self, event, skip=True):
+ """ Called when any key is released.
+ """
+ if event.GetKeyCode() in (59, ord('.')):
+ # Intercepting '.'
+ event.Skip()
+ wx.CallAfter(self._popup_completion, create=True)
+ else:
+ ConsoleWidget._on_key_up(self, event, skip=skip)
+ # Make sure the continuation_prompts are always followed by a
+ # whitespace
+ new_lines = []
+ if self._input_state == 'readline':
+ position = self.GetCurrentPos()
+ continuation_prompt = self.continuation_prompt()[:-1]
+ for line in self.input_buffer.split('\n'):
+ if not line == continuation_prompt:
+ new_lines.append(line)
+ self.input_buffer = '\n'.join(new_lines)
+ self.GotoPos(position)
+
+
+ def _on_enter(self):
+ """ Called on return key down, in readline input_state.
+ """
+ last_line_num = self.LineFromPosition(self.GetLength())
+ current_line_num = self.LineFromPosition(self.GetCurrentPos())
+ new_line_pos = (last_line_num - current_line_num)
+ if self.debug:
+ print >>sys.__stdout__, repr(self.input_buffer)
+ self.write('\n', refresh=False)
+ # Under windows scintilla seems to be doing funny
+ # stuff to the line returns here, but the getter for
+ # input_buffer filters this out.
+ if sys.platform == 'win32':
+ self.input_buffer = self.input_buffer
+ old_prompt_num = self.current_prompt_pos
+ has_executed = PrefilterFrontEnd._on_enter(self,
+ new_line_pos=new_line_pos)
+ if old_prompt_num == self.current_prompt_pos:
+ # No execution has happened
+ self.GotoPos(self.GetLineEndPosition(current_line_num + 1))
+ return has_executed
+
+
+ #--------------------------------------------------------------------------
+ # EditWindow API
+ #--------------------------------------------------------------------------
+
+ def OnUpdateUI(self, event):
+ """ Override the OnUpdateUI of the EditWindow class, to prevent
+ syntax highlighting both for faster redraw, and for more
+ consistent look and feel.
+ """
+ if not self._input_state == 'readline':
+ ConsoleWidget.OnUpdateUI(self, event)
+
+ #--------------------------------------------------------------------------
+ # Private API
+ #--------------------------------------------------------------------------
+
+ def _buffer_flush(self, event):
+ """ Called by the timer to flush the write buffer.
+
+ This is always called in the mainloop, by the wx timer.
+ """
+ self._out_buffer_lock.acquire()
+ _out_buffer = self._out_buffer
+ self._out_buffer = []
+ self._out_buffer_lock.release()
+ self.write(''.join(_out_buffer), refresh=False)
+
+
+ def _colorize_input_buffer(self):
+ """ Keep the input buffer lines at a bright color.
+ """
+ if not self._input_state in ('readline', 'raw_input'):
+ return
+ end_line = self.GetCurrentLine()
+ if not sys.platform == 'win32':
+ end_line += 1
+ for i in range(self.current_prompt_line, end_line):
+ if i in self._markers:
+ self.MarkerDeleteHandle(self._markers[i])
+ self._markers[i] = self.MarkerAdd(i, _INPUT_MARKER)
+
+
+if __name__ == '__main__':
+ class MainWindow(wx.Frame):
+ def __init__(self, parent, id, title):
+ wx.Frame.__init__(self, parent, id, title, size=(300,250))
+ self._sizer = wx.BoxSizer(wx.VERTICAL)
+ self.shell = WxController(self)
+ self._sizer.Add(self.shell, 1, wx.EXPAND)
+ self.SetSizer(self._sizer)
+ self.SetAutoLayout(1)
+ self.Show(True)
+
+ app = wx.PySimpleApp()
+ frame = MainWindow(None, wx.ID_ANY, 'Ipython')
+ frame.shell.SetFocus()
+ frame.SetSize((680, 460))
+ self = frame.shell
+
+ app.MainLoop()
+
diff --git a/IPython/frontend/zopeinterface.py b/IPython/frontend/zopeinterface.py
new file mode 100644
index 0000000..2081be3
--- /dev/null
+++ b/IPython/frontend/zopeinterface.py
@@ -0,0 +1,27 @@
+# encoding: utf-8
+# -*- test-case-name: IPython.frontend.tests.test_frontendbase -*-
+"""
+zope.interface mock. If zope is installed, this module provides a zope
+interface classes, if not it provides mocks for them.
+
+Classes provided:
+Interface, Attribute, implements, classProvides
+"""
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+try:
+ from zope.interface import Interface, Attribute, implements, classProvides
+except ImportError:
+ #zope.interface is not available
+ Interface = object
+ def Attribute(name, doc): pass
+ def implements(interface): pass
+ def classProvides(interface): pass
+
diff --git a/IPython/generics.py b/IPython/generics.py
new file mode 100644
index 0000000..b38b978
--- /dev/null
+++ b/IPython/generics.py
@@ -0,0 +1,54 @@
+''' 'Generic' functions for extending IPython.
+
+See http://cheeseshop.python.org/pypi/simplegeneric.
+
+Here is an example from genutils.py:
+
+ def print_lsstring(arg):
+ "Prettier (non-repr-like) and more informative printer for LSString"
+ print "LSString (.p, .n, .l, .s available). Value:"
+ print arg
+
+ print_lsstring = result_display.when_type(LSString)(print_lsstring)
+
+(Yes, the nasty syntax is for python 2.3 compatibility. Your own extensions
+can use the niftier decorator syntax introduced in Python 2.4).
+'''
+
+from IPython.ipapi import TryNext
+from IPython.external.simplegeneric import generic
+
+def result_display(result):
+ """ print the result of computation """
+ raise TryNext
+
+result_display = generic(result_display)
+
+def inspect_object(obj):
+ """ Called when you do obj? """
+ raise TryNext
+inspect_object = generic(inspect_object)
+
+def complete_object(obj, prev_completions):
+ """ Custom completer dispatching for python objects
+
+ obj is the object itself.
+ prev_completions is the list of attributes discovered so far.
+
+ This should return the list of attributes in obj. If you only wish to
+ add to the attributes already discovered normally, return
+ own_attrs + prev_completions.
+ """
+
+ raise TryNext
+complete_object = generic(complete_object)
+
+#import os
+#def my_demo_complete_object(obj, prev_completions):
+# """ Demo completer that adds 'foobar' to the completions suggested
+# for any object that has attribute (path), e.g. 'os'"""
+# if hasattr(obj,'path'):
+# return prev_completions + ['foobar']
+# raise TryNext
+#
+#my_demo_complete_object = complete_object.when_type(type(os))(my_demo_complete_object)
diff --git a/IPython/genutils.py b/IPython/genutils.py
new file mode 100644
index 0000000..00fa170
--- /dev/null
+++ b/IPython/genutils.py
@@ -0,0 +1,2171 @@
+# -*- coding: utf-8 -*-
+"""General purpose utilities.
+
+This is a grab-bag of stuff I find useful in most programs I write. Some of
+these things are also convenient when working at the command line.
+"""
+
+#*****************************************************************************
+# Copyright (C) 2001-2006 Fernando Perez. <fperez@colorado.edu>
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#*****************************************************************************
+
+#****************************************************************************
+# required modules from the Python standard library
+import __main__
+import commands
+try:
+ import doctest
+except ImportError:
+ pass
+import os
+import platform
+import re
+import shlex
+import shutil
+import subprocess
+import sys
+import tempfile
+import time
+import types
+import warnings
+
+# Curses and termios are Unix-only modules
+try:
+ import curses
+ # We need termios as well, so if its import happens to raise, we bail on
+ # using curses altogether.
+ import termios
+except ImportError:
+ USE_CURSES = False
+else:
+ # Curses on Solaris may not be complete, so we can't use it there
+ USE_CURSES = hasattr(curses,'initscr')
+
+# Other IPython utilities
+import IPython
+from IPython.Itpl import Itpl,itpl,printpl
+from IPython import DPyGetOpt, platutils
+from IPython.generics import result_display
+import IPython.ipapi
+from IPython.external.path import path
+if os.name == "nt":
+ from IPython.winconsole import get_console_size
+
+try:
+ set
+except:
+ from sets import Set as set
+
+
+#****************************************************************************
+# Exceptions
+class Error(Exception):
+ """Base class for exceptions in this module."""
+ pass
+
+#----------------------------------------------------------------------------
+class IOStream:
+ def __init__(self,stream,fallback):
+ if not hasattr(stream,'write') or not hasattr(stream,'flush'):
+ stream = fallback
+ self.stream = stream
+ self._swrite = stream.write
+ self.flush = stream.flush
+
+ def write(self,data):
+ try:
+ self._swrite(data)
+ except:
+ try:
+ # print handles some unicode issues which may trip a plain
+ # write() call. Attempt to emulate write() by using a
+ # trailing comma
+ print >> self.stream, data,
+ except:
+ # if we get here, something is seriously broken.
+ print >> sys.stderr, \
+ 'ERROR - failed to write data to stream:', self.stream
+
+ def close(self):
+ pass
+
+
+class IOTerm:
+ """ Term holds the file or file-like objects for handling I/O operations.
+
+ These are normally just sys.stdin, sys.stdout and sys.stderr but for
+ Windows they can can replaced to allow editing the strings before they are
+ displayed."""
+
+ # In the future, having IPython channel all its I/O operations through
+ # this class will make it easier to embed it into other environments which
+ # are not a normal terminal (such as a GUI-based shell)
+ def __init__(self,cin=None,cout=None,cerr=None):
+ self.cin = IOStream(cin,sys.stdin)
+ self.cout = IOStream(cout,sys.stdout)
+ self.cerr = IOStream(cerr,sys.stderr)
+
+# Global variable to be used for all I/O
+Term = IOTerm()
+
+import IPython.rlineimpl as readline
+# Remake Term to use the readline i/o facilities
+if sys.platform == 'win32' and readline.have_readline:
+
+ Term = IOTerm(cout=readline._outputfile,cerr=readline._outputfile)
+
+
+#****************************************************************************
+# Generic warning/error printer, used by everything else
+def warn(msg,level=2,exit_val=1):
+ """Standard warning printer. Gives formatting consistency.
+
+ Output is sent to Term.cerr (sys.stderr by default).
+
+ Options:
+
+ -level(2): allows finer control:
+ 0 -> Do nothing, dummy function.
+ 1 -> Print message.
+ 2 -> Print 'WARNING:' + message. (Default level).
+ 3 -> Print 'ERROR:' + message.
+ 4 -> Print 'FATAL ERROR:' + message and trigger a sys.exit(exit_val).
+
+ -exit_val (1): exit value returned by sys.exit() for a level 4
+ warning. Ignored for all other levels."""
+
+ if level>0:
+ header = ['','','WARNING: ','ERROR: ','FATAL ERROR: ']
+ print >> Term.cerr, '%s%s' % (header[level],msg)
+ if level == 4:
+ print >> Term.cerr,'Exiting.\n'
+ sys.exit(exit_val)
+
+def info(msg):
+ """Equivalent to warn(msg,level=1)."""
+
+ warn(msg,level=1)
+
+def error(msg):
+ """Equivalent to warn(msg,level=3)."""
+
+ warn(msg,level=3)
+
+def fatal(msg,exit_val=1):
+ """Equivalent to warn(msg,exit_val=exit_val,level=4)."""
+
+ warn(msg,exit_val=exit_val,level=4)
+
+#---------------------------------------------------------------------------
+# Debugging routines
+#
+def debugx(expr,pre_msg=''):
+ """Print the value of an expression from the caller's frame.
+
+ Takes an expression, evaluates it in the caller's frame and prints both
+ the given expression and the resulting value (as well as a debug mark
+ indicating the name of the calling function. The input must be of a form
+ suitable for eval().
+
+ An optional message can be passed, which will be prepended to the printed
+ expr->value pair."""
+
+ cf = sys._getframe(1)
+ print '[DBG:%s] %s%s -> %r' % (cf.f_code.co_name,pre_msg,expr,
+ eval(expr,cf.f_globals,cf.f_locals))
+
+# deactivate it by uncommenting the following line, which makes it a no-op
+#def debugx(expr,pre_msg=''): pass
+
+#----------------------------------------------------------------------------
+StringTypes = types.StringTypes
+
+# Basic timing functionality
+
+# If possible (Unix), use the resource module instead of time.clock()
+try:
+ import resource
+ def clocku():
+ """clocku() -> floating point number
+
+ Return the *USER* CPU time in seconds since the start of the process.
+ This is done via a call to resource.getrusage, so it avoids the
+ wraparound problems in time.clock()."""
+
+ return resource.getrusage(resource.RUSAGE_SELF)[0]
+
+ def clocks():
+ """clocks() -> floating point number
+
+ Return the *SYSTEM* CPU time in seconds since the start of the process.
+ This is done via a call to resource.getrusage, so it avoids the
+ wraparound problems in time.clock()."""
+
+ return resource.getrusage(resource.RUSAGE_SELF)[1]
+
+ def clock():
+ """clock() -> floating point number
+
+ Return the *TOTAL USER+SYSTEM* CPU time in seconds since the start of
+ the process. This is done via a call to resource.getrusage, so it
+ avoids the wraparound problems in time.clock()."""
+
+ u,s = resource.getrusage(resource.RUSAGE_SELF)[:2]
+ return u+s
+
+ def clock2():
+ """clock2() -> (t_user,t_system)
+
+ Similar to clock(), but return a tuple of user/system times."""
+ return resource.getrusage(resource.RUSAGE_SELF)[:2]
+
+except ImportError:
+ # There is no distinction of user/system time under windows, so we just use
+ # time.clock() for everything...
+ clocku = clocks = clock = time.clock
+ def clock2():
+ """Under windows, system CPU time can't be measured.
+
+ This just returns clock() and zero."""
+ return time.clock(),0.0
+
+def timings_out(reps,func,*args,**kw):
+ """timings_out(reps,func,*args,**kw) -> (t_total,t_per_call,output)
+
+ Execute a function reps times, return a tuple with the elapsed total
+ CPU time in seconds, the time per call and the function's output.
+
+ Under Unix, the return value is the sum of user+system time consumed by
+ the process, computed via the resource module. This prevents problems
+ related to the wraparound effect which the time.clock() function has.
+
+ Under Windows the return value is in wall clock seconds. See the
+ documentation for the time module for more details."""
+
+ reps = int(reps)
+ assert reps >=1, 'reps must be >= 1'
+ if reps==1:
+ start = clock()
+ out = func(*args,**kw)
+ tot_time = clock()-start
+ else:
+ rng = xrange(reps-1) # the last time is executed separately to store output
+ start = clock()
+ for dummy in rng: func(*args,**kw)
+ out = func(*args,**kw) # one last time
+ tot_time = clock()-start
+ av_time = tot_time / reps
+ return tot_time,av_time,out
+
+def timings(reps,func,*args,**kw):
+ """timings(reps,func,*args,**kw) -> (t_total,t_per_call)
+
+ Execute a function reps times, return a tuple with the elapsed total CPU
+ time in seconds and the time per call. These are just the first two values
+ in timings_out()."""
+
+ return timings_out(reps,func,*args,**kw)[0:2]
+
+def timing(func,*args,**kw):
+ """timing(func,*args,**kw) -> t_total
+
+ Execute a function once, return the elapsed total CPU time in
+ seconds. This is just the first value in timings_out()."""
+
+ return timings_out(1,func,*args,**kw)[0]
+
+#****************************************************************************
+# file and system
+
+def arg_split(s,posix=False):
+ """Split a command line's arguments in a shell-like manner.
+
+ This is a modified version of the standard library's shlex.split()
+ function, but with a default of posix=False for splitting, so that quotes
+ in inputs are respected."""
+
+ # XXX - there may be unicode-related problems here!!! I'm not sure that
+ # shlex is truly unicode-safe, so it might be necessary to do
+ #
+ # s = s.encode(sys.stdin.encoding)
+ #
+ # first, to ensure that shlex gets a normal string. Input from anyone who
+ # knows more about unicode and shlex than I would be good to have here...
+ lex = shlex.shlex(s, posix=posix)
+ lex.whitespace_split = True
+ return list(lex)
+
+def system(cmd,verbose=0,debug=0,header=''):
+ """Execute a system command, return its exit status.
+
+ Options:
+
+ - verbose (0): print the command to be executed.
+
+ - debug (0): only print, do not actually execute.
+
+ - header (''): Header to print on screen prior to the executed command (it
+ is only prepended to the command, no newlines are added).
+
+ Note: a stateful version of this function is available through the
+ SystemExec class."""
+
+ stat = 0
+ if verbose or debug: print header+cmd
+ sys.stdout.flush()
+ if not debug: stat = os.system(cmd)
+ return stat
+
+def abbrev_cwd():
+ """ Return abbreviated version of cwd, e.g. d:mydir """
+ cwd = os.getcwd().replace('\\','/')
+ drivepart = ''
+ tail = cwd
+ if sys.platform == 'win32':
+ if len(cwd) < 4:
+ return cwd
+ drivepart,tail = os.path.splitdrive(cwd)
+
+
+ parts = tail.split('/')
+ if len(parts) > 2:
+ tail = '/'.join(parts[-2:])
+
+ return (drivepart + (
+ cwd == '/' and '/' or tail))
+
+
+# This function is used by ipython in a lot of places to make system calls.
+# We need it to be slightly different under win32, due to the vagaries of
+# 'network shares'. A win32 override is below.
+
+def shell(cmd,verbose=0,debug=0,header=''):
+ """Execute a command in the system shell, always return None.
+
+ Options:
+
+ - verbose (0): print the command to be executed.
+
+ - debug (0): only print, do not actually execute.
+
+ - header (''): Header to print on screen prior to the executed command (it
+ is only prepended to the command, no newlines are added).
+
+ Note: this is similar to genutils.system(), but it returns None so it can
+ be conveniently used in interactive loops without getting the return value
+ (typically 0) printed many times."""
+
+ stat = 0
+ if verbose or debug: print header+cmd
+ # flush stdout so we don't mangle python's buffering
+ sys.stdout.flush()
+
+ if not debug:
+ platutils.set_term_title("IPy " + cmd)
+ os.system(cmd)
+ platutils.set_term_title("IPy " + abbrev_cwd())
+
+# override shell() for win32 to deal with network shares
+if os.name in ('nt','dos'):
+
+ shell_ori = shell
+
+ def shell(cmd,verbose=0,debug=0,header=''):
+ if os.getcwd().startswith(r"\\"):
+ path = os.getcwd()
+ # change to c drive (cannot be on UNC-share when issuing os.system,
+ # as cmd.exe cannot handle UNC addresses)
+ os.chdir("c:")
+ # issue pushd to the UNC-share and then run the command
+ try:
+ shell_ori('"pushd %s&&"'%path+cmd,verbose,debug,header)
+ finally:
+ os.chdir(path)
+ else:
+ shell_ori(cmd,verbose,debug,header)
+
+ shell.__doc__ = shell_ori.__doc__
+
+def getoutput(cmd,verbose=0,debug=0,header='',split=0):
+ """Dummy substitute for perl's backquotes.
+
+ Executes a command and returns the output.
+
+ Accepts the same arguments as system(), plus:
+
+ - split(0): if true, the output is returned as a list split on newlines.
+
+ Note: a stateful version of this function is available through the
+ SystemExec class.
+
+ This is pretty much deprecated and rarely used,
+ genutils.getoutputerror may be what you need.
+
+ """
+
+ if verbose or debug: print header+cmd
+ if not debug:
+ output = os.popen(cmd).read()
+ # stipping last \n is here for backwards compat.
+ if output.endswith('\n'):
+ output = output[:-1]
+ if split:
+ return output.split('\n')
+ else:
+ return output
+
+def getoutputerror(cmd,verbose=0,debug=0,header='',split=0):
+ """Return (standard output,standard error) of executing cmd in a shell.
+
+ Accepts the same arguments as system(), plus:
+
+ - split(0): if true, each of stdout/err is returned as a list split on
+ newlines.
+
+ Note: a stateful version of this function is available through the
+ SystemExec class."""
+
+ if verbose or debug: print header+cmd
+ if not cmd:
+ if split:
+ return [],[]
+ else:
+ return '',''
+ if not debug:
+ pin,pout,perr = os.popen3(cmd)
+ tout = pout.read().rstrip()
+ terr = perr.read().rstrip()
+ pin.close()
+ pout.close()
+ perr.close()
+ if split:
+ return tout.split('\n'),terr.split('\n')
+ else:
+ return tout,terr
+
+# for compatibility with older naming conventions
+xsys = system
+bq = getoutput
+
+class SystemExec:
+ """Access the system and getoutput functions through a stateful interface.
+
+ Note: here we refer to the system and getoutput functions from this
+ library, not the ones from the standard python library.
+
+ This class offers the system and getoutput functions as methods, but the
+ verbose, debug and header parameters can be set for the instance (at
+ creation time or later) so that they don't need to be specified on each
+ call.
+
+ For efficiency reasons, there's no way to override the parameters on a
+ per-call basis other than by setting instance attributes. If you need
+ local overrides, it's best to directly call system() or getoutput().
+
+ The following names are provided as alternate options:
+ - xsys: alias to system
+ - bq: alias to getoutput
+
+ An instance can then be created as:
+ >>> sysexec = SystemExec(verbose=1,debug=0,header='Calling: ')
+ """
+
+ def __init__(self,verbose=0,debug=0,header='',split=0):
+ """Specify the instance's values for verbose, debug and header."""
+ setattr_list(self,'verbose debug header split')
+
+ def system(self,cmd):
+ """Stateful interface to system(), with the same keyword parameters."""
+
+ system(cmd,self.verbose,self.debug,self.header)
+
+ def shell(self,cmd):
+ """Stateful interface to shell(), with the same keyword parameters."""
+
+ shell(cmd,self.verbose,self.debug,self.header)
+
+ xsys = system # alias
+
+ def getoutput(self,cmd):
+ """Stateful interface to getoutput()."""
+
+ return getoutput(cmd,self.verbose,self.debug,self.header,self.split)
+
+ def getoutputerror(self,cmd):
+ """Stateful interface to getoutputerror()."""
+
+ return getoutputerror(cmd,self.verbose,self.debug,self.header,self.split)
+
+ bq = getoutput # alias
+
+#-----------------------------------------------------------------------------
+def mutex_opts(dict,ex_op):
+ """Check for presence of mutually exclusive keys in a dict.
+
+ Call: mutex_opts(dict,[[op1a,op1b],[op2a,op2b]...]"""
+ for op1,op2 in ex_op:
+ if op1 in dict and op2 in dict:
+ raise ValueError,'\n*** ERROR in Arguments *** '\
+ 'Options '+op1+' and '+op2+' are mutually exclusive.'
+
+#-----------------------------------------------------------------------------
+def get_py_filename(name):
+ """Return a valid python filename in the current directory.
+
+ If the given name is not a file, it adds '.py' and searches again.
+ Raises IOError with an informative message if the file isn't found."""
+
+ name = os.path.expanduser(name)
+ if not os.path.isfile(name) and not name.endswith('.py'):
+ name += '.py'
+ if os.path.isfile(name):
+ return name
+ else:
+ raise IOError,'File `%s` not found.' % name
+
+#-----------------------------------------------------------------------------
+def filefind(fname,alt_dirs = None):
+ """Return the given filename either in the current directory, if it
+ exists, or in a specified list of directories.
+
+ ~ expansion is done on all file and directory names.
+
+ Upon an unsuccessful search, raise an IOError exception."""
+
+ if alt_dirs is None:
+ try:
+ alt_dirs = get_home_dir()
+ except HomeDirError:
+ alt_dirs = os.getcwd()
+ search = [fname] + list_strings(alt_dirs)
+ search = map(os.path.expanduser,search)
+ #print 'search list for',fname,'list:',search # dbg
+ fname = search[0]
+ if os.path.isfile(fname):
+ return fname
+ for direc in search[1:]:
+ testname = os.path.join(direc,fname)
+ #print 'testname',testname # dbg
+ if os.path.isfile(testname):
+ return testname
+ raise IOError,'File' + `fname` + \
+ ' not found in current or supplied directories:' + `alt_dirs`
+
+#----------------------------------------------------------------------------
+def file_read(filename):
+ """Read a file and close it. Returns the file source."""
+ fobj = open(filename,'r');
+ source = fobj.read();
+ fobj.close()
+ return source
+
+def file_readlines(filename):
+ """Read a file and close it. Returns the file source using readlines()."""
+ fobj = open(filename,'r');
+ lines = fobj.readlines();
+ fobj.close()
+ return lines
+
+#----------------------------------------------------------------------------
+def target_outdated(target,deps):
+ """Determine whether a target is out of date.
+
+ target_outdated(target,deps) -> 1/0
+
+ deps: list of filenames which MUST exist.
+ target: single filename which may or may not exist.
+
+ If target doesn't exist or is older than any file listed in deps, return
+ true, otherwise return false.
+ """
+ try:
+ target_time = os.path.getmtime(target)
+ except os.error:
+ return 1
+ for dep in deps:
+ dep_time = os.path.getmtime(dep)
+ if dep_time > target_time:
+ #print "For target",target,"Dep failed:",dep # dbg
+ #print "times (dep,tar):",dep_time,target_time # dbg
+ return 1
+ return 0
+
+#-----------------------------------------------------------------------------
+def target_update(target,deps,cmd):
+ """Update a target with a given command given a list of dependencies.
+
+ target_update(target,deps,cmd) -> runs cmd if target is outdated.
+
+ This is just a wrapper around target_outdated() which calls the given
+ command if target is outdated."""
+
+ if target_outdated(target,deps):
+ xsys(cmd)
+
+#----------------------------------------------------------------------------
+def unquote_ends(istr):
+ """Remove a single pair of quotes from the endpoints of a string."""
+
+ if not istr:
+ return istr
+ if (istr[0]=="'" and istr[-1]=="'") or \
+ (istr[0]=='"' and istr[-1]=='"'):
+ return istr[1:-1]
+ else:
+ return istr
+
+#----------------------------------------------------------------------------
+def process_cmdline(argv,names=[],defaults={},usage=''):
+ """ Process command-line options and arguments.
+
+ Arguments:
+
+ - argv: list of arguments, typically sys.argv.
+
+ - names: list of option names. See DPyGetOpt docs for details on options
+ syntax.
+
+ - defaults: dict of default values.
+
+ - usage: optional usage notice to print if a wrong argument is passed.
+
+ Return a dict of options and a list of free arguments."""
+
+ getopt = DPyGetOpt.DPyGetOpt()
+ getopt.setIgnoreCase(0)
+ getopt.parseConfiguration(names)
+
+ try:
+ getopt.processArguments(argv)
+ except DPyGetOpt.ArgumentError, exc:
+ print usage
+ warn('"%s"' % exc,level=4)
+
+ defaults.update(getopt.optionValues)
+ args = getopt.freeValues
+
+ return defaults,args
+
+#----------------------------------------------------------------------------
+def optstr2types(ostr):
+ """Convert a string of option names to a dict of type mappings.
+
+ optstr2types(str) -> {None:'string_opts',int:'int_opts',float:'float_opts'}
+
+ This is used to get the types of all the options in a string formatted
+ with the conventions of DPyGetOpt. The 'type' None is used for options
+ which are strings (they need no further conversion). This function's main
+ use is to get a typemap for use with read_dict().
+ """
+
+ typeconv = {None:'',int:'',float:''}
+ typemap = {'s':None,'i':int,'f':float}
+ opt_re = re.compile(r'([\w]*)([^:=]*:?=?)([sif]?)')
+
+ for w in ostr.split():
+ oname,alias,otype = opt_re.match(w).groups()
+ if otype == '' or alias == '!': # simple switches are integers too
+ otype = 'i'
+ typeconv[typemap[otype]] += oname + ' '
+ return typeconv
+
+#----------------------------------------------------------------------------
+def read_dict(filename,type_conv=None,**opt):
+ r"""Read a dictionary of key=value pairs from an input file, optionally
+ performing conversions on the resulting values.
+
+ read_dict(filename,type_conv,**opt) -> dict
+
+ Only one value per line is accepted, the format should be
+ # optional comments are ignored
+ key value\n
+
+ Args:
+
+ - type_conv: A dictionary specifying which keys need to be converted to
+ which types. By default all keys are read as strings. This dictionary
+ should have as its keys valid conversion functions for strings
+ (int,long,float,complex, or your own). The value for each key
+ (converter) should be a whitespace separated string containing the names
+ of all the entries in the file to be converted using that function. For
+ keys to be left alone, use None as the conversion function (only needed
+ with purge=1, see below).
+
+ - opt: dictionary with extra options as below (default in parens)
+
+ purge(0): if set to 1, all keys *not* listed in type_conv are purged out
+ of the dictionary to be returned. If purge is going to be used, the
+ set of keys to be left as strings also has to be explicitly specified
+ using the (non-existent) conversion function None.
+
+ fs(None): field separator. This is the key/value separator to be used
+ when parsing the file. The None default means any whitespace [behavior
+ of string.split()].
+
+ strip(0): if 1, strip string values of leading/trailinig whitespace.
+
+ warn(1): warning level if requested keys are not found in file.
+ - 0: silently ignore.
+ - 1: inform but proceed.
+ - 2: raise KeyError exception.
+
+ no_empty(0): if 1, remove keys with whitespace strings as a value.
+
+ unique([]): list of keys (or space separated string) which can't be
+ repeated. If one such key is found in the file, each new instance
+ overwrites the previous one. For keys not listed here, the behavior is
+ to make a list of all appearances.
+
+ Example:
+
+ If the input file test.ini contains (we put it in a string to keep the test
+ self-contained):
+
+ >>> test_ini = '''\
+ ... i 3
+ ... x 4.5
+ ... y 5.5
+ ... s hi ho'''
+
+ Then we can use it as follows:
+ >>> type_conv={int:'i',float:'x',None:'s'}
+
+ >>> d = read_dict(test_ini)
+
+ >>> sorted(d.items())
+ [('i', '3'), ('s', 'hi ho'), ('x', '4.5'), ('y', '5.5')]
+
+ >>> d = read_dict(test_ini,type_conv)
+
+ >>> sorted(d.items())
+ [('i', 3), ('s', 'hi ho'), ('x', 4.5), ('y', '5.5')]
+
+ >>> d = read_dict(test_ini,type_conv,purge=True)
+
+ >>> sorted(d.items())
+ [('i', 3), ('s', 'hi ho'), ('x', 4.5)]
+ """
+
+ # starting config
+ opt.setdefault('purge',0)
+ opt.setdefault('fs',None) # field sep defaults to any whitespace
+ opt.setdefault('strip',0)
+ opt.setdefault('warn',1)
+ opt.setdefault('no_empty',0)
+ opt.setdefault('unique','')
+ if type(opt['unique']) in StringTypes:
+ unique_keys = qw(opt['unique'])
+ elif type(opt['unique']) in (types.TupleType,types.ListType):
+ unique_keys = opt['unique']
+ else:
+ raise ValueError, 'Unique keys must be given as a string, List or Tuple'
+
+ dict = {}
+
+ # first read in table of values as strings
+ if '\n' in filename:
+ lines = filename.splitlines()
+ file = None
+ else:
+ file = open(filename,'r')
+ lines = file.readlines()
+ for line in lines:
+ line = line.strip()
+ if len(line) and line[0]=='#': continue
+ if len(line)>0:
+ lsplit = line.split(opt['fs'],1)
+ try:
+ key,val = lsplit
+ except ValueError:
+ key,val = lsplit[0],''
+ key = key.strip()
+ if opt['strip']: val = val.strip()
+ if val == "''" or val == '""': val = ''
+ if opt['no_empty'] and (val=='' or val.isspace()):
+ continue
+ # if a key is found more than once in the file, build a list
+ # unless it's in the 'unique' list. In that case, last found in file
+ # takes precedence. User beware.
+ try:
+ if dict[key] and key in unique_keys:
+ dict[key] = val
+ elif type(dict[key]) is types.ListType:
+ dict[key].append(val)
+ else:
+ dict[key] = [dict[key],val]
+ except KeyError:
+ dict[key] = val
+ # purge if requested
+ if opt['purge']:
+ accepted_keys = qwflat(type_conv.values())
+ for key in dict.keys():
+ if key in accepted_keys: continue
+ del(dict[key])
+ # now convert if requested
+ if type_conv==None: return dict
+ conversions = type_conv.keys()
+ try: conversions.remove(None)
+ except: pass
+ for convert in conversions:
+ for val in qw(type_conv[convert]):
+ try:
+ dict[val] = convert(dict[val])
+ except KeyError,e:
+ if opt['warn'] == 0:
+ pass
+ elif opt['warn'] == 1:
+ print >>sys.stderr, 'Warning: key',val,\
+ 'not found in file',filename
+ elif opt['warn'] == 2:
+ raise KeyError,e
+ else:
+ raise ValueError,'Warning level must be 0,1 or 2'
+
+ return dict
+
+#----------------------------------------------------------------------------
+def flag_calls(func):
+ """Wrap a function to detect and flag when it gets called.
+
+ This is a decorator which takes a function and wraps it in a function with
+ a 'called' attribute. wrapper.called is initialized to False.
+
+ The wrapper.called attribute is set to False right before each call to the
+ wrapped function, so if the call fails it remains False. After the call
+ completes, wrapper.called is set to True and the output is returned.
+
+ Testing for truth in wrapper.called allows you to determine if a call to
+ func() was attempted and succeeded."""
+
+ def wrapper(*args,**kw):
+ wrapper.called = False
+ out = func(*args,**kw)
+ wrapper.called = True
+ return out
+
+ wrapper.called = False
+ wrapper.__doc__ = func.__doc__
+ return wrapper
+
+#----------------------------------------------------------------------------
+def dhook_wrap(func,*a,**k):
+ """Wrap a function call in a sys.displayhook controller.
+
+ Returns a wrapper around func which calls func, with all its arguments and
+ keywords unmodified, using the default sys.displayhook. Since IPython
+ modifies sys.displayhook, it breaks the behavior of certain systems that
+ rely on the default behavior, notably doctest.
+ """
+
+ def f(*a,**k):
+
+ dhook_s = sys.displayhook
+ sys.displayhook = sys.__displayhook__
+ try:
+ out = func(*a,**k)
+ finally:
+ sys.displayhook = dhook_s
+
+ return out
+
+ f.__doc__ = func.__doc__
+ return f
+
+#----------------------------------------------------------------------------
+def doctest_reload():
+ """Properly reload doctest to reuse it interactively.
+
+ This routine:
+
+ - imports doctest but does NOT reload it (see below).
+
+ - resets its global 'master' attribute to None, so that multiple uses of
+ the module interactively don't produce cumulative reports.
+
+ - Monkeypatches its core test runner method to protect it from IPython's
+ modified displayhook. Doctest expects the default displayhook behavior
+ deep down, so our modification breaks it completely. For this reason, a
+ hard monkeypatch seems like a reasonable solution rather than asking
+ users to manually use a different doctest runner when under IPython.
+
+ Notes
+ -----
+
+ This function *used to* reload doctest, but this has been disabled because
+ reloading doctest unconditionally can cause massive breakage of other
+ doctest-dependent modules already in memory, such as those for IPython's
+ own testing system. The name wasn't changed to avoid breaking people's
+ code, but the reload call isn't actually made anymore."""
+
+ import doctest
+ doctest.master = None
+ doctest.DocTestRunner.run = dhook_wrap(doctest.DocTestRunner.run)
+
+#----------------------------------------------------------------------------
+class HomeDirError(Error):
+ pass
+
+def get_home_dir():
+ """Return the closest possible equivalent to a 'home' directory.
+
+ We first try $HOME. Absent that, on NT it's $HOMEDRIVE\$HOMEPATH.
+
+ Currently only Posix and NT are implemented, a HomeDirError exception is
+ raised for all other OSes. """
+
+ isdir = os.path.isdir
+ env = os.environ
+
+ # first, check py2exe distribution root directory for _ipython.
+ # This overrides all. Normally does not exist.
+
+ if hasattr(sys, "frozen"): #Is frozen by py2exe
+ if '\\library.zip\\' in IPython.__file__.lower():#libraries compressed to zip-file
+ root, rest = IPython.__file__.lower().split('library.zip')
+ else:
+ root=os.path.join(os.path.split(IPython.__file__)[0],"../../")
+ root=os.path.abspath(root).rstrip('\\')
+ if isdir(os.path.join(root, '_ipython')):
+ os.environ["IPYKITROOT"] = root
+ return root
+ try:
+ homedir = env['HOME']
+ if not isdir(homedir):
+ # in case a user stuck some string which does NOT resolve to a
+ # valid path, it's as good as if we hadn't foud it
+ raise KeyError
+ return homedir
+ except KeyError:
+ if os.name == 'posix':
+ raise HomeDirError,'undefined $HOME, IPython can not proceed.'
+ elif os.name == 'nt':
+ # For some strange reason, win9x returns 'nt' for os.name.
+ try:
+ homedir = os.path.join(env['HOMEDRIVE'],env['HOMEPATH'])
+ if not isdir(homedir):
+ homedir = os.path.join(env['USERPROFILE'])
+ if not isdir(homedir):
+ raise HomeDirError
+ return homedir
+ except KeyError:
+ try:
+ # Use the registry to get the 'My Documents' folder.
+ import _winreg as wreg
+ key = wreg.OpenKey(wreg.HKEY_CURRENT_USER,
+ "Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders")
+ homedir = wreg.QueryValueEx(key,'Personal')[0]
+ key.Close()
+ if not isdir(homedir):
+ e = ('Invalid "Personal" folder registry key '
+ 'typically "My Documents".\n'
+ 'Value: %s\n'
+ 'This is not a valid directory on your system.' %
+ homedir)
+ raise HomeDirError(e)
+ return homedir
+ except HomeDirError:
+ raise
+ except:
+ return 'C:\\'
+ elif os.name == 'dos':
+ # Desperate, may do absurd things in classic MacOS. May work under DOS.
+ return 'C:\\'
+ else:
+ raise HomeDirError,'support for your operating system not implemented.'
+
+
+def get_ipython_dir():
+ """Get the IPython directory for this platform and user.
+
+ This uses the logic in `get_home_dir` to find the home directory
+ and the adds either .ipython or _ipython to the end of the path.
+ """
+ if os.name == 'posix':
+ ipdir_def = '.ipython'
+ else:
+ ipdir_def = '_ipython'
+ home_dir = get_home_dir()
+ ipdir = os.path.abspath(os.environ.get('IPYTHONDIR',
+ os.path.join(home_dir, ipdir_def)))
+ return ipdir.decode(sys.getfilesystemencoding())
+
+def get_security_dir():
+ """Get the IPython security directory.
+
+ This directory is the default location for all security related files,
+ including SSL/TLS certificates and FURL files.
+
+ If the directory does not exist, it is created with 0700 permissions.
+ If it exists, permissions are set to 0700.
+ """
+ security_dir = os.path.join(get_ipython_dir(), 'security')
+ if not os.path.isdir(security_dir):
+ os.mkdir(security_dir, 0700)
+ else:
+ os.chmod(security_dir, 0700)
+ return security_dir
+
+def get_log_dir():
+ """Get the IPython log directory.
+
+ If the log directory does not exist, it is created.
+ """
+ log_dir = os.path.join(get_ipython_dir(), 'log')
+ if not os.path.isdir(log_dir):
+ os.mkdir(log_dir, 0777)
+ return log_dir
+
+#****************************************************************************
+# strings and text
+
+class LSString(str):
+ """String derivative with a special access attributes.
+
+ These are normal strings, but with the special attributes:
+
+ .l (or .list) : value as list (split on newlines).
+ .n (or .nlstr): original value (the string itself).
+ .s (or .spstr): value as whitespace-separated string.
+ .p (or .paths): list of path objects
+
+ Any values which require transformations are computed only once and
+ cached.
+
+ Such strings are very useful to efficiently interact with the shell, which
+ typically only understands whitespace-separated options for commands."""
+
+ def get_list(self):
+ try:
+ return self.__list
+ except AttributeError:
+ self.__list = self.split('\n')
+ return self.__list
+
+ l = list = property(get_list)
+
+ def get_spstr(self):
+ try:
+ return self.__spstr
+ except AttributeError:
+ self.__spstr = self.replace('\n',' ')
+ return self.__spstr
+
+ s = spstr = property(get_spstr)
+
+ def get_nlstr(self):
+ return self
+
+ n = nlstr = property(get_nlstr)
+
+ def get_paths(self):
+ try:
+ return self.__paths
+ except AttributeError:
+ self.__paths = [path(p) for p in self.split('\n') if os.path.exists(p)]
+ return self.__paths
+
+ p = paths = property(get_paths)
+
+def print_lsstring(arg):
+ """ Prettier (non-repr-like) and more informative printer for LSString """
+ print "LSString (.p, .n, .l, .s available). Value:"
+ print arg
+
+print_lsstring = result_display.when_type(LSString)(print_lsstring)
+
+#----------------------------------------------------------------------------
+class SList(list):
+ """List derivative with a special access attributes.
+
+ These are normal lists, but with the special attributes:
+
+ .l (or .list) : value as list (the list itself).
+ .n (or .nlstr): value as a string, joined on newlines.
+ .s (or .spstr): value as a string, joined on spaces.
+ .p (or .paths): list of path objects
+
+ Any values which require transformations are computed only once and
+ cached."""
+
+ def get_list(self):
+ return self
+
+ l = list = property(get_list)
+
+ def get_spstr(self):
+ try:
+ return self.__spstr
+ except AttributeError:
+ self.__spstr = ' '.join(self)
+ return self.__spstr
+
+ s = spstr = property(get_spstr)
+
+ def get_nlstr(self):
+ try:
+ return self.__nlstr
+ except AttributeError:
+ self.__nlstr = '\n'.join(self)
+ return self.__nlstr
+
+ n = nlstr = property(get_nlstr)
+
+ def get_paths(self):
+ try:
+ return self.__paths
+ except AttributeError:
+ self.__paths = [path(p) for p in self if os.path.exists(p)]
+ return self.__paths
+
+ p = paths = property(get_paths)
+
+ def grep(self, pattern, prune = False, field = None):
+ """ Return all strings matching 'pattern' (a regex or callable)
+
+ This is case-insensitive. If prune is true, return all items
+ NOT matching the pattern.
+
+ If field is specified, the match must occur in the specified
+ whitespace-separated field.
+
+ Examples::
+
+ a.grep( lambda x: x.startswith('C') )
+ a.grep('Cha.*log', prune=1)
+ a.grep('chm', field=-1)
+ """
+
+ def match_target(s):
+ if field is None:
+ return s
+ parts = s.split()
+ try:
+ tgt = parts[field]
+ return tgt
+ except IndexError:
+ return ""
+
+ if isinstance(pattern, basestring):
+ pred = lambda x : re.search(pattern, x, re.IGNORECASE)
+ else:
+ pred = pattern
+ if not prune:
+ return SList([el for el in self if pred(match_target(el))])
+ else:
+ return SList([el for el in self if not pred(match_target(el))])
+ def fields(self, *fields):
+ """ Collect whitespace-separated fields from string list
+
+ Allows quick awk-like usage of string lists.
+
+ Example data (in var a, created by 'a = !ls -l')::
+ -rwxrwxrwx 1 ville None 18 Dec 14 2006 ChangeLog
+ drwxrwxrwx+ 6 ville None 0 Oct 24 18:05 IPython
+
+ a.fields(0) is ['-rwxrwxrwx', 'drwxrwxrwx+']
+ a.fields(1,0) is ['1 -rwxrwxrwx', '6 drwxrwxrwx+']
+ (note the joining by space).
+ a.fields(-1) is ['ChangeLog', 'IPython']
+
+ IndexErrors are ignored.
+
+ Without args, fields() just split()'s the strings.
+ """
+ if len(fields) == 0:
+ return [el.split() for el in self]
+
+ res = SList()
+ for el in [f.split() for f in self]:
+ lineparts = []
+
+ for fd in fields:
+ try:
+ lineparts.append(el[fd])
+ except IndexError:
+ pass
+ if lineparts:
+ res.append(" ".join(lineparts))
+
+ return res
+ def sort(self,field= None, nums = False):
+ """ sort by specified fields (see fields())
+
+ Example::
+ a.sort(1, nums = True)
+
+ Sorts a by second field, in numerical order (so that 21 > 3)
+
+ """
+
+ #decorate, sort, undecorate
+ if field is not None:
+ dsu = [[SList([line]).fields(field), line] for line in self]
+ else:
+ dsu = [[line, line] for line in self]
+ if nums:
+ for i in range(len(dsu)):
+ numstr = "".join([ch for ch in dsu[i][0] if ch.isdigit()])
+ try:
+ n = int(numstr)
+ except ValueError:
+ n = 0;
+ dsu[i][0] = n
+
+
+ dsu.sort()
+ return SList([t[1] for t in dsu])
+
+def print_slist(arg):
+ """ Prettier (non-repr-like) and more informative printer for SList """
+ print "SList (.p, .n, .l, .s, .grep(), .fields(), sort() available):"
+ if hasattr(arg, 'hideonce') and arg.hideonce:
+ arg.hideonce = False
+ return
+
+ nlprint(arg)
+
+print_slist = result_display.when_type(SList)(print_slist)
+
+
+
+#----------------------------------------------------------------------------
+def esc_quotes(strng):
+ """Return the input string with single and double quotes escaped out"""
+
+ return strng.replace('"','\\"').replace("'","\\'")
+
+#----------------------------------------------------------------------------
+def make_quoted_expr(s):
+ """Return string s in appropriate quotes, using raw string if possible.
+
+ XXX - example removed because it caused encoding errors in documentation
+ generation. We need a new example that doesn't contain invalid chars.
+
+ Note the use of raw string and padding at the end to allow trailing
+ backslash.
+ """
+
+ tail = ''
+ tailpadding = ''
+ raw = ''
+ if "\\" in s:
+ raw = 'r'
+ if s.endswith('\\'):
+ tail = '[:-1]'
+ tailpadding = '_'
+ if '"' not in s:
+ quote = '"'
+ elif "'" not in s:
+ quote = "'"
+ elif '"""' not in s and not s.endswith('"'):
+ quote = '"""'
+ elif "'''" not in s and not s.endswith("'"):
+ quote = "'''"
+ else:
+ # give up, backslash-escaped string will do
+ return '"%s"' % esc_quotes(s)
+ res = raw + quote + s + tailpadding + quote + tail
+ return res
+
+
+#----------------------------------------------------------------------------
+def raw_input_multi(header='', ps1='==> ', ps2='..> ',terminate_str = '.'):
+ """Take multiple lines of input.
+
+ A list with each line of input as a separate element is returned when a
+ termination string is entered (defaults to a single '.'). Input can also
+ terminate via EOF (^D in Unix, ^Z-RET in Windows).
+
+ Lines of input which end in \\ are joined into single entries (and a
+ secondary continuation prompt is issued as long as the user terminates
+ lines with \\). This allows entering very long strings which are still
+ meant to be treated as single entities.
+ """
+
+ try:
+ if header:
+ header += '\n'
+ lines = [raw_input(header + ps1)]
+ except EOFError:
+ return []
+ terminate = [terminate_str]
+ try:
+ while lines[-1:] != terminate:
+ new_line = raw_input(ps1)
+ while new_line.endswith('\\'):
+ new_line = new_line[:-1] + raw_input(ps2)
+ lines.append(new_line)
+
+ return lines[:-1] # don't return the termination command
+ except EOFError:
+ print
+ return lines
+
+#----------------------------------------------------------------------------
+def raw_input_ext(prompt='', ps2='... '):
+ """Similar to raw_input(), but accepts extended lines if input ends with \\."""
+
+ line = raw_input(prompt)
+ while line.endswith('\\'):
+ line = line[:-1] + raw_input(ps2)
+ return line
+
+#----------------------------------------------------------------------------
+def ask_yes_no(prompt,default=None):
+ """Asks a question and returns a boolean (y/n) answer.
+
+ If default is given (one of 'y','n'), it is used if the user input is
+ empty. Otherwise the question is repeated until an answer is given.
+
+ An EOF is treated as the default answer. If there is no default, an
+ exception is raised to prevent infinite loops.
+
+ Valid answers are: y/yes/n/no (match is not case sensitive)."""
+
+ answers = {'y':True,'n':False,'yes':True,'no':False}
+ ans = None
+ while ans not in answers.keys():
+ try:
+ ans = raw_input(prompt+' ').lower()
+ if not ans: # response was an empty string
+ ans = default
+ except KeyboardInterrupt:
+ pass
+ except EOFError:
+ if default in answers.keys():
+ ans = default
+ print
+ else:
+ raise
+
+ return answers[ans]
+
+#----------------------------------------------------------------------------
+def marquee(txt='',width=78,mark='*'):
+ """Return the input string centered in a 'marquee'."""
+ if not txt:
+ return (mark*width)[:width]
+ nmark = (width-len(txt)-2)/len(mark)/2
+ if nmark < 0: nmark =0
+ marks = mark*nmark
+ return '%s %s %s' % (marks,txt,marks)
+
+#----------------------------------------------------------------------------
+class EvalDict:
+ """
+ Emulate a dict which evaluates its contents in the caller's frame.
+
+ Usage:
+ >>> number = 19
+
+ >>> text = "python"
+
+ >>> print "%(text.capitalize())s %(number/9.0).1f rules!" % EvalDict()
+ Python 2.1 rules!
+ """
+
+ # This version is due to sismex01@hebmex.com on c.l.py, and is basically a
+ # modified (shorter) version of:
+ # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66018 by
+ # Skip Montanaro (skip@pobox.com).
+
+ def __getitem__(self, name):
+ frame = sys._getframe(1)
+ return eval(name, frame.f_globals, frame.f_locals)
+
+EvalString = EvalDict # for backwards compatibility
+#----------------------------------------------------------------------------
+def qw(words,flat=0,sep=None,maxsplit=-1):
+ """Similar to Perl's qw() operator, but with some more options.
+
+ qw(words,flat=0,sep=' ',maxsplit=-1) -> words.split(sep,maxsplit)
+
+ words can also be a list itself, and with flat=1, the output will be
+ recursively flattened.
+
+ Examples:
+
+ >>> qw('1 2')
+ ['1', '2']
+
+ >>> qw(['a b','1 2',['m n','p q']])
+ [['a', 'b'], ['1', '2'], [['m', 'n'], ['p', 'q']]]
+
+ >>> qw(['a b','1 2',['m n','p q']],flat=1)
+ ['a', 'b', '1', '2', 'm', 'n', 'p', 'q']
+ """
+
+ if type(words) in StringTypes:
+ return [word.strip() for word in words.split(sep,maxsplit)
+ if word and not word.isspace() ]
+ if flat:
+ return flatten(map(qw,words,[1]*len(words)))
+ return map(qw,words)
+
+#----------------------------------------------------------------------------
+def qwflat(words,sep=None,maxsplit=-1):
+ """Calls qw(words) in flat mode. It's just a convenient shorthand."""
+ return qw(words,1,sep,maxsplit)
+
+#----------------------------------------------------------------------------
+def qw_lol(indata):
+ """qw_lol('a b') -> [['a','b']],
+ otherwise it's just a call to qw().
+
+ We need this to make sure the modules_some keys *always* end up as a
+ list of lists."""
+
+ if type(indata) in StringTypes:
+ return [qw(indata)]
+ else:
+ return qw(indata)
+
+#-----------------------------------------------------------------------------
+def list_strings(arg):
+ """Always return a list of strings, given a string or list of strings
+ as input."""
+
+ if type(arg) in StringTypes: return [arg]
+ else: return arg
+
+#----------------------------------------------------------------------------
+def grep(pat,list,case=1):
+ """Simple minded grep-like function.
+ grep(pat,list) returns occurrences of pat in list, None on failure.
+
+ It only does simple string matching, with no support for regexps. Use the
+ option case=0 for case-insensitive matching."""
+
+ # This is pretty crude. At least it should implement copying only references
+ # to the original data in case it's big. Now it copies the data for output.
+ out=[]
+ if case:
+ for term in list:
+ if term.find(pat)>-1: out.append(term)
+ else:
+ lpat=pat.lower()
+ for term in list:
+ if term.lower().find(lpat)>-1: out.append(term)
+
+ if len(out): return out
+ else: return None
+
+#----------------------------------------------------------------------------
+def dgrep(pat,*opts):
+ """Return grep() on dir()+dir(__builtins__).
+
+ A very common use of grep() when working interactively."""
+
+ return grep(pat,dir(__main__)+dir(__main__.__builtins__),*opts)
+
+#----------------------------------------------------------------------------
+def idgrep(pat):
+ """Case-insensitive dgrep()"""
+
+ return dgrep(pat,0)
+
+#----------------------------------------------------------------------------
+def igrep(pat,list):
+ """Synonym for case-insensitive grep."""
+
+ return grep(pat,list,case=0)
+
+#----------------------------------------------------------------------------
+def indent(str,nspaces=4,ntabs=0):
+ """Indent a string a given number of spaces or tabstops.
+
+ indent(str,nspaces=4,ntabs=0) -> indent str by ntabs+nspaces.
+ """
+ if str is None:
+ return
+ ind = '\t'*ntabs+' '*nspaces
+ outstr = '%s%s' % (ind,str.replace(os.linesep,os.linesep+ind))
+ if outstr.endswith(os.linesep+ind):
+ return outstr[:-len(ind)]
+ else:
+ return outstr
+
+#-----------------------------------------------------------------------------
+def native_line_ends(filename,backup=1):
+ """Convert (in-place) a file to line-ends native to the current OS.
+
+ If the optional backup argument is given as false, no backup of the
+ original file is left. """
+
+ backup_suffixes = {'posix':'~','dos':'.bak','nt':'.bak','mac':'.bak'}
+
+ bak_filename = filename + backup_suffixes[os.name]
+
+ original = open(filename).read()
+ shutil.copy2(filename,bak_filename)
+ try:
+ new = open(filename,'wb')
+ new.write(os.linesep.join(original.splitlines()))
+ new.write(os.linesep) # ALWAYS put an eol at the end of the file
+ new.close()
+ except:
+ os.rename(bak_filename,filename)
+ if not backup:
+ try:
+ os.remove(bak_filename)
+ except:
+ pass
+
+#----------------------------------------------------------------------------
+def get_pager_cmd(pager_cmd = None):
+ """Return a pager command.
+
+ Makes some attempts at finding an OS-correct one."""
+
+ if os.name == 'posix':
+ default_pager_cmd = 'less -r' # -r for color control sequences
+ elif os.name in ['nt','dos']:
+ default_pager_cmd = 'type'
+
+ if pager_cmd is None:
+ try:
+ pager_cmd = os.environ['PAGER']
+ except:
+ pager_cmd = default_pager_cmd
+ return pager_cmd
+
+#-----------------------------------------------------------------------------
+def get_pager_start(pager,start):
+ """Return the string for paging files with an offset.
+
+ This is the '+N' argument which less and more (under Unix) accept.
+ """
+
+ if pager in ['less','more']:
+ if start:
+ start_string = '+' + str(start)
+ else:
+ start_string = ''
+ else:
+ start_string = ''
+ return start_string
+
+#----------------------------------------------------------------------------
+# (X)emacs on W32 doesn't like to be bypassed with msvcrt.getch()
+if os.name == 'nt' and os.environ.get('TERM','dumb') != 'emacs':
+ import msvcrt
+ def page_more():
+ """ Smart pausing between pages
+
+ @return: True if need print more lines, False if quit
+ """
+ Term.cout.write('---Return to continue, q to quit--- ')
+ ans = msvcrt.getch()
+ if ans in ("q", "Q"):
+ result = False
+ else:
+ result = True
+ Term.cout.write("\b"*37 + " "*37 + "\b"*37)
+ return result
+else:
+ def page_more():
+ ans = raw_input('---Return to continue, q to quit--- ')
+ if ans.lower().startswith('q'):
+ return False
+ else:
+ return True
+
+esc_re = re.compile(r"(\x1b[^m]+m)")
+
+def page_dumb(strng,start=0,screen_lines=25):
+ """Very dumb 'pager' in Python, for when nothing else works.
+
+ Only moves forward, same interface as page(), except for pager_cmd and
+ mode."""
+
+ out_ln = strng.splitlines()[start:]
+ screens = chop(out_ln,screen_lines-1)
+ if len(screens) == 1:
+ print >>Term.cout, os.linesep.join(screens[0])
+ else:
+ last_escape = ""
+ for scr in screens[0:-1]:
+ hunk = os.linesep.join(scr)
+ print >>Term.cout, last_escape + hunk
+ if not page_more():
+ return
+ esc_list = esc_re.findall(hunk)
+ if len(esc_list) > 0:
+ last_escape = esc_list[-1]
+ print >>Term.cout, last_escape + os.linesep.join(screens[-1])
+
+#----------------------------------------------------------------------------
+def page(strng,start=0,screen_lines=0,pager_cmd = None):
+ """Print a string, piping through a pager after a certain length.
+
+ The screen_lines parameter specifies the number of *usable* lines of your
+ terminal screen (total lines minus lines you need to reserve to show other
+ information).
+
+ If you set screen_lines to a number <=0, page() will try to auto-determine
+ your screen size and will only use up to (screen_size+screen_lines) for
+ printing, paging after that. That is, if you want auto-detection but need
+ to reserve the bottom 3 lines of the screen, use screen_lines = -3, and for
+ auto-detection without any lines reserved simply use screen_lines = 0.
+
+ If a string won't fit in the allowed lines, it is sent through the
+ specified pager command. If none given, look for PAGER in the environment,
+ and ultimately default to less.
+
+ If no system pager works, the string is sent through a 'dumb pager'
+ written in python, very simplistic.
+ """
+
+ # Some routines may auto-compute start offsets incorrectly and pass a
+ # negative value. Offset to 0 for robustness.
+ start = max(0,start)
+
+ # first, try the hook
+ ip = IPython.ipapi.get()
+ if ip:
+ try:
+ ip.IP.hooks.show_in_pager(strng)
+ return
+ except IPython.ipapi.TryNext:
+ pass
+
+ # Ugly kludge, but calling curses.initscr() flat out crashes in emacs
+ TERM = os.environ.get('TERM','dumb')
+ if TERM in ['dumb','emacs'] and os.name != 'nt':
+ print strng
+ return
+ # chop off the topmost part of the string we don't want to see
+ str_lines = strng.split(os.linesep)[start:]
+ str_toprint = os.linesep.join(str_lines)
+ num_newlines = len(str_lines)
+ len_str = len(str_toprint)
+
+ # Dumb heuristics to guesstimate number of on-screen lines the string
+ # takes. Very basic, but good enough for docstrings in reasonable
+ # terminals. If someone later feels like refining it, it's not hard.
+ numlines = max(num_newlines,int(len_str/80)+1)
+
+ if os.name == "nt":
+ screen_lines_def = get_console_size(defaulty=25)[1]
+ else:
+ screen_lines_def = 25 # default value if we can't auto-determine
+
+ # auto-determine screen size
+ if screen_lines <= 0:
+ if TERM=='xterm':
+ use_curses = USE_CURSES
+ else:
+ # curses causes problems on many terminals other than xterm.
+ use_curses = False
+ if use_curses:
+ # There is a bug in curses, where *sometimes* it fails to properly
+ # initialize, and then after the endwin() call is made, the
+ # terminal is left in an unusable state. Rather than trying to
+ # check everytime for this (by requesting and comparing termios
+ # flags each time), we just save the initial terminal state and
+ # unconditionally reset it every time. It's cheaper than making
+ # the checks.
+ term_flags = termios.tcgetattr(sys.stdout)
+ scr = curses.initscr()
+ screen_lines_real,screen_cols = scr.getmaxyx()
+ curses.endwin()
+ # Restore terminal state in case endwin() didn't.
+ termios.tcsetattr(sys.stdout,termios.TCSANOW,term_flags)
+ # Now we have what we needed: the screen size in rows/columns
+ screen_lines += screen_lines_real
+ #print '***Screen size:',screen_lines_real,'lines x',\
+ #screen_cols,'columns.' # dbg
+ else:
+ screen_lines += screen_lines_def
+
+ #print 'numlines',numlines,'screenlines',screen_lines # dbg
+ if numlines <= screen_lines :
+ #print '*** normal print' # dbg
+ print >>Term.cout, str_toprint
+ else:
+ # Try to open pager and default to internal one if that fails.
+ # All failure modes are tagged as 'retval=1', to match the return
+ # value of a failed system command. If any intermediate attempt
+ # sets retval to 1, at the end we resort to our own page_dumb() pager.
+ pager_cmd = get_pager_cmd(pager_cmd)
+ pager_cmd += ' ' + get_pager_start(pager_cmd,start)
+ if os.name == 'nt':
+ if pager_cmd.startswith('type'):
+ # The default WinXP 'type' command is failing on complex strings.
+ retval = 1
+ else:
+ tmpname = tempfile.mktemp('.txt')
+ tmpfile = file(tmpname,'wt')
+ tmpfile.write(strng)
+ tmpfile.close()
+ cmd = "%s < %s" % (pager_cmd,tmpname)
+ if os.system(cmd):
+ retval = 1
+ else:
+ retval = None
+ os.remove(tmpname)
+ else:
+ try:
+ retval = None
+ # if I use popen4, things hang. No idea why.
+ #pager,shell_out = os.popen4(pager_cmd)
+ pager = os.popen(pager_cmd,'w')
+ pager.write(strng)
+ pager.close()
+ retval = pager.close() # success returns None
+ except IOError,msg: # broken pipe when user quits
+ if msg.args == (32,'Broken pipe'):
+ retval = None
+ else:
+ retval = 1
+ except OSError:
+ # Other strange problems, sometimes seen in Win2k/cygwin
+ retval = 1
+ if retval is not None:
+ page_dumb(strng,screen_lines=screen_lines)
+
+#----------------------------------------------------------------------------
+def page_file(fname,start = 0, pager_cmd = None):
+ """Page a file, using an optional pager command and starting line.
+ """
+
+ pager_cmd = get_pager_cmd(pager_cmd)
+ pager_cmd += ' ' + get_pager_start(pager_cmd,start)
+
+ try:
+ if os.environ['TERM'] in ['emacs','dumb']:
+ raise EnvironmentError
+ xsys(pager_cmd + ' ' + fname)
+ except:
+ try:
+ if start > 0:
+ start -= 1
+ page(open(fname).read(),start)
+ except:
+ print 'Unable to show file',`fname`
+
+
+#----------------------------------------------------------------------------
+def snip_print(str,width = 75,print_full = 0,header = ''):
+ """Print a string snipping the midsection to fit in width.
+
+ print_full: mode control:
+ - 0: only snip long strings
+ - 1: send to page() directly.
+ - 2: snip long strings and ask for full length viewing with page()
+ Return 1 if snipping was necessary, 0 otherwise."""
+
+ if print_full == 1:
+ page(header+str)
+ return 0
+
+ print header,
+ if len(str) < width:
+ print str
+ snip = 0
+ else:
+ whalf = int((width -5)/2)
+ print str[:whalf] + ' <...> ' + str[-whalf:]
+ snip = 1
+ if snip and print_full == 2:
+ if raw_input(header+' Snipped. View (y/n)? [N]').lower() == 'y':
+ page(str)
+ return snip
+
+#****************************************************************************
+# lists, dicts and structures
+
+def belong(candidates,checklist):
+ """Check whether a list of items appear in a given list of options.
+
+ Returns a list of 1 and 0, one for each candidate given."""
+
+ return [x in checklist for x in candidates]
+
+#----------------------------------------------------------------------------
+def uniq_stable(elems):
+ """uniq_stable(elems) -> list
+
+ Return from an iterable, a list of all the unique elements in the input,
+ but maintaining the order in which they first appear.
+
+ A naive solution to this problem which just makes a dictionary with the
+ elements as keys fails to respect the stability condition, since
+ dictionaries are unsorted by nature.
+
+ Note: All elements in the input must be valid dictionary keys for this
+ routine to work, as it internally uses a dictionary for efficiency
+ reasons."""
+
+ unique = []
+ unique_dict = {}
+ for nn in elems:
+ if nn not in unique_dict:
+ unique.append(nn)
+ unique_dict[nn] = None
+ return unique
+
+#----------------------------------------------------------------------------
+class NLprinter:
+ """Print an arbitrarily nested list, indicating index numbers.
+
+ An instance of this class called nlprint is available and callable as a
+ function.
+
+ nlprint(list,indent=' ',sep=': ') -> prints indenting each level by 'indent'
+ and using 'sep' to separate the index from the value. """
+
+ def __init__(self):
+ self.depth = 0
+
+ def __call__(self,lst,pos='',**kw):
+ """Prints the nested list numbering levels."""
+ kw.setdefault('indent',' ')
+ kw.setdefault('sep',': ')
+ kw.setdefault('start',0)
+ kw.setdefault('stop',len(lst))
+ # we need to remove start and stop from kw so they don't propagate
+ # into a recursive call for a nested list.
+ start = kw['start']; del kw['start']
+ stop = kw['stop']; del kw['stop']
+ if self.depth == 0 and 'header' in kw.keys():
+ print kw['header']
+
+ for idx in range(start,stop):
+ elem = lst[idx]
+ if type(elem)==type([]):
+ self.depth += 1
+ self.__call__(elem,itpl('$pos$idx,'),**kw)
+ self.depth -= 1
+ else:
+ printpl(kw['indent']*self.depth+'$pos$idx$kw["sep"]$elem')
+
+nlprint = NLprinter()
+#----------------------------------------------------------------------------
+def all_belong(candidates,checklist):
+ """Check whether a list of items ALL appear in a given list of options.
+
+ Returns a single 1 or 0 value."""
+
+ return 1-(0 in [x in checklist for x in candidates])
+
+#----------------------------------------------------------------------------
+def sort_compare(lst1,lst2,inplace = 1):
+ """Sort and compare two lists.
+
+ By default it does it in place, thus modifying the lists. Use inplace = 0
+ to avoid that (at the cost of temporary copy creation)."""
+ if not inplace:
+ lst1 = lst1[:]
+ lst2 = lst2[:]
+ lst1.sort(); lst2.sort()
+ return lst1 == lst2
+
+#----------------------------------------------------------------------------
+def list2dict(lst):
+ """Takes a list of (key,value) pairs and turns it into a dict."""
+
+ dic = {}
+ for k,v in lst: dic[k] = v
+ return dic
+
+#----------------------------------------------------------------------------
+def list2dict2(lst,default=''):
+ """Takes a list and turns it into a dict.
+ Much slower than list2dict, but more versatile. This version can take
+ lists with sublists of arbitrary length (including sclars)."""
+
+ dic = {}
+ for elem in lst:
+ if type(elem) in (types.ListType,types.TupleType):
+ size = len(elem)
+ if size == 0:
+ pass
+ elif size == 1:
+ dic[elem] = default
+ else:
+ k,v = elem[0], elem[1:]
+ if len(v) == 1: v = v[0]
+ dic[k] = v
+ else:
+ dic[elem] = default
+ return dic
+
+#----------------------------------------------------------------------------
+def flatten(seq):
+ """Flatten a list of lists (NOT recursive, only works for 2d lists)."""
+
+ return [x for subseq in seq for x in subseq]
+
+#----------------------------------------------------------------------------
+def get_slice(seq,start=0,stop=None,step=1):
+ """Get a slice of a sequence with variable step. Specify start,stop,step."""
+ if stop == None:
+ stop = len(seq)
+ item = lambda i: seq[i]
+ return map(item,xrange(start,stop,step))
+
+#----------------------------------------------------------------------------
+def chop(seq,size):
+ """Chop a sequence into chunks of the given size."""
+ chunk = lambda i: seq[i:i+size]
+ return map(chunk,xrange(0,len(seq),size))
+
+#----------------------------------------------------------------------------
+# with is a keyword as of python 2.5, so this function is renamed to withobj
+# from its old 'with' name.
+def with_obj(object, **args):
+ """Set multiple attributes for an object, similar to Pascal's with.
+
+ Example:
+ with_obj(jim,
+ born = 1960,
+ haircolour = 'Brown',
+ eyecolour = 'Green')
+
+ Credit: Greg Ewing, in
+ http://mail.python.org/pipermail/python-list/2001-May/040703.html.
+
+ NOTE: up until IPython 0.7.2, this was called simply 'with', but 'with'
+ has become a keyword for Python 2.5, so we had to rename it."""
+
+ object.__dict__.update(args)
+
+#----------------------------------------------------------------------------
+def setattr_list(obj,alist,nspace = None):
+ """Set a list of attributes for an object taken from a namespace.
+
+ setattr_list(obj,alist,nspace) -> sets in obj all the attributes listed in
+ alist with their values taken from nspace, which must be a dict (something
+ like locals() will often do) If nspace isn't given, locals() of the
+ *caller* is used, so in most cases you can omit it.
+
+ Note that alist can be given as a string, which will be automatically
+ split into a list on whitespace. If given as a list, it must be a list of
+ *strings* (the variable names themselves), not of variables."""
+
+ # this grabs the local variables from the *previous* call frame -- that is
+ # the locals from the function that called setattr_list().
+ # - snipped from weave.inline()
+ if nspace is None:
+ call_frame = sys._getframe().f_back
+ nspace = call_frame.f_locals
+
+ if type(alist) in StringTypes:
+ alist = alist.split()
+ for attr in alist:
+ val = eval(attr,nspace)
+ setattr(obj,attr,val)
+
+#----------------------------------------------------------------------------
+def getattr_list(obj,alist,*args):
+ """getattr_list(obj,alist[, default]) -> attribute list.
+
+ Get a list of named attributes for an object. When a default argument is
+ given, it is returned when the attribute doesn't exist; without it, an
+ exception is raised in that case.
+
+ Note that alist can be given as a string, which will be automatically
+ split into a list on whitespace. If given as a list, it must be a list of
+ *strings* (the variable names themselves), not of variables."""
+
+ if type(alist) in StringTypes:
+ alist = alist.split()
+ if args:
+ if len(args)==1:
+ default = args[0]
+ return map(lambda attr: getattr(obj,attr,default),alist)
+ else:
+ raise ValueError,'getattr_list() takes only one optional argument'
+ else:
+ return map(lambda attr: getattr(obj,attr),alist)
+
+#----------------------------------------------------------------------------
+def map_method(method,object_list,*argseq,**kw):
+ """map_method(method,object_list,*args,**kw) -> list
+
+ Return a list of the results of applying the methods to the items of the
+ argument sequence(s). If more than one sequence is given, the method is
+ called with an argument list consisting of the corresponding item of each
+ sequence. All sequences must be of the same length.
+
+ Keyword arguments are passed verbatim to all objects called.
+
+ This is Python code, so it's not nearly as fast as the builtin map()."""
+
+ out_list = []
+ idx = 0
+ for object in object_list:
+ try:
+ handler = getattr(object, method)
+ except AttributeError:
+ out_list.append(None)
+ else:
+ if argseq:
+ args = map(lambda lst:lst[idx],argseq)
+ #print 'ob',object,'hand',handler,'ar',args # dbg
+ out_list.append(handler(args,**kw))
+ else:
+ out_list.append(handler(**kw))
+ idx += 1
+ return out_list
+
+#----------------------------------------------------------------------------
+def get_class_members(cls):
+ ret = dir(cls)
+ if hasattr(cls,'__bases__'):
+ for base in cls.__bases__:
+ ret.extend(get_class_members(base))
+ return ret
+
+#----------------------------------------------------------------------------
+def dir2(obj):
+ """dir2(obj) -> list of strings
+
+ Extended version of the Python builtin dir(), which does a few extra
+ checks, and supports common objects with unusual internals that confuse
+ dir(), such as Traits and PyCrust.
+
+ This version is guaranteed to return only a list of true strings, whereas
+ dir() returns anything that objects inject into themselves, even if they
+ are later not really valid for attribute access (many extension libraries
+ have such bugs).
+ """
+
+ # Start building the attribute list via dir(), and then complete it
+ # with a few extra special-purpose calls.
+ words = dir(obj)
+
+ if hasattr(obj,'__class__'):
+ words.append('__class__')
+ words.extend(get_class_members(obj.__class__))
+ #if '__base__' in words: 1/0
+
+ # Some libraries (such as traits) may introduce duplicates, we want to
+ # track and clean this up if it happens
+ may_have_dupes = False
+
+ # this is the 'dir' function for objects with Enthought's traits
+ if hasattr(obj, 'trait_names'):
+ try:
+ words.extend(obj.trait_names())
+ may_have_dupes = True
+ except TypeError:
+ # This will happen if `obj` is a class and not an instance.
+ pass
+
+ # Support for PyCrust-style _getAttributeNames magic method.
+ if hasattr(obj, '_getAttributeNames'):
+ try:
+ words.extend(obj._getAttributeNames())
+ may_have_dupes = True
+ except TypeError:
+ # `obj` is a class and not an instance. Ignore
+ # this error.
+ pass
+
+ if may_have_dupes:
+ # eliminate possible duplicates, as some traits may also
+ # appear as normal attributes in the dir() call.
+ words = list(set(words))
+ words.sort()
+
+ # filter out non-string attributes which may be stuffed by dir() calls
+ # and poor coding in third-party modules
+ return [w for w in words if isinstance(w, basestring)]
+
+#----------------------------------------------------------------------------
+def import_fail_info(mod_name,fns=None):
+ """Inform load failure for a module."""
+
+ if fns == None:
+ warn("Loading of %s failed.\n" % (mod_name,))
+ else:
+ warn("Loading of %s from %s failed.\n" % (fns,mod_name))
+
+#----------------------------------------------------------------------------
+# Proposed popitem() extension, written as a method
+
+
+class NotGiven: pass
+
+def popkey(dct,key,default=NotGiven):
+ """Return dct[key] and delete dct[key].
+
+ If default is given, return it if dct[key] doesn't exist, otherwise raise
+ KeyError. """
+
+ try:
+ val = dct[key]
+ except KeyError:
+ if default is NotGiven:
+ raise
+ else:
+ return default
+ else:
+ del dct[key]
+ return val
+
+def wrap_deprecated(func, suggest = '<nothing>'):
+ def newFunc(*args, **kwargs):
+ warnings.warn("Call to deprecated function %s, use %s instead" %
+ ( func.__name__, suggest),
+ category=DeprecationWarning,
+ stacklevel = 2)
+ return func(*args, **kwargs)
+ return newFunc
+
+
+def _num_cpus_unix():
+ """Return the number of active CPUs on a Unix system."""
+ return os.sysconf("SC_NPROCESSORS_ONLN")
+
+
+def _num_cpus_darwin():
+ """Return the number of active CPUs on a Darwin system."""
+ p = subprocess.Popen(['sysctl','-n','hw.ncpu'],stdout=subprocess.PIPE)
+ return p.stdout.read()
+
+
+def _num_cpus_windows():
+ """Return the number of active CPUs on a Windows system."""
+ return os.environ.get("NUMBER_OF_PROCESSORS")
+
+
+def num_cpus():
+ """Return the effective number of CPUs in the system as an integer.
+
+ This cross-platform function makes an attempt at finding the total number of
+ available CPUs in the system, as returned by various underlying system and
+ python calls.
+
+ If it can't find a sensible answer, it returns 1 (though an error *may* make
+ it return a large positive number that's actually incorrect).
+ """
+
+ # Many thanks to the Parallel Python project (http://www.parallelpython.com)
+ # for the names of the keys we needed to look up for this function. This
+ # code was inspired by their equivalent function.
+
+ ncpufuncs = {'Linux':_num_cpus_unix,
+ 'Darwin':_num_cpus_darwin,
+ 'Windows':_num_cpus_windows,
+ # On Vista, python < 2.5.2 has a bug and returns 'Microsoft'
+ # See http://bugs.python.org/issue1082 for details.
+ 'Microsoft':_num_cpus_windows,
+ }
+
+ ncpufunc = ncpufuncs.get(platform.system(),
+ # default to unix version (Solaris, AIX, etc)
+ _num_cpus_unix)
+
+ try:
+ ncpus = max(1,int(ncpufunc()))
+ except:
+ ncpus = 1
+ return ncpus
+
+#*************************** end of file <genutils.py> **********************
diff --git a/IPython/gui/__init__.py b/IPython/gui/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/IPython/gui/__init__.py
diff --git a/IPython/gui/wx/__init__.py b/IPython/gui/wx/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/IPython/gui/wx/__init__.py
diff --git a/IPython/gui/wx/ipshell_nonblocking.py b/IPython/gui/wx/ipshell_nonblocking.py
new file mode 100644
index 0000000..63b8086
--- /dev/null
+++ b/IPython/gui/wx/ipshell_nonblocking.py
@@ -0,0 +1,525 @@
+#!/usr/bin/python
+# -*- coding: iso-8859-15 -*-
+'''
+Provides IPython remote instance.
+
+@author: Laurent Dufrechou
+laurent.dufrechou _at_ gmail.com
+@license: BSD
+
+All rights reserved. This program and the accompanying materials are made
+available under the terms of the BSD which accompanies this distribution, and
+is available at U{http://www.opensource.org/licenses/bsd-license.php}
+'''
+
+__version__ = 0.9
+__author__ = "Laurent Dufrechou"
+__email__ = "laurent.dufrechou _at_ gmail.com"
+__license__ = "BSD"
+
+import re
+import sys
+import os
+import locale
+from thread_ex import ThreadEx
+
+try:
+ import IPython
+except Exception,e:
+ print "Error importing IPython (%s)" % str(e)
+ raise Exception, e
+
+##############################################################################
+class _Helper(object):
+ """Redefine the built-in 'help'.
+ This is a wrapper around pydoc.help (with a twist).
+ """
+
+ def __init__(self, pager):
+ self._pager = pager
+
+ def __repr__(self):
+ return "Type help() for interactive help, " \
+ "or help(object) for help about object."
+
+ def __call__(self, *args, **kwds):
+ class DummyWriter(object):
+ '''Dumy class to handle help output'''
+ def __init__(self, pager):
+ self._pager = pager
+
+ def write(self, data):
+ '''hook to fill self._pager'''
+ self._pager(data)
+
+ import pydoc
+ pydoc.help.output = DummyWriter(self._pager)
+ pydoc.help.interact = lambda :1
+
+ return pydoc.help(*args, **kwds)
+
+
+##############################################################################
+class _CodeExecutor(ThreadEx):
+ ''' Thread that execute ipython code '''
+ def __init__(self, instance):
+ ThreadEx.__init__(self)
+ self.instance = instance
+
+ def run(self):
+ '''Thread main loop'''
+ try:
+ self.instance._doc_text = None
+ self.instance._help_text = None
+ self.instance._execute()
+ # used for uper class to generate event after execution
+ self.instance._after_execute()
+
+ except KeyboardInterrupt:
+ pass
+
+
+##############################################################################
+class NonBlockingIPShell(object):
+ '''
+ Create an IPython instance, running the commands in a separate,
+ non-blocking thread.
+ This allows embedding in any GUI without blockage.
+
+ Note: The ThreadEx class supports asynchroneous function call
+ via raise_exc()
+ '''
+
+ def __init__(self, argv=[], user_ns={}, user_global_ns=None,
+ cin=None, cout=None, cerr=None,
+ ask_exit_handler=None):
+ '''
+ @param argv: Command line options for IPython
+ @type argv: list
+ @param user_ns: User namespace.
+ @type user_ns: dictionary
+ @param user_global_ns: User global namespace.
+ @type user_global_ns: dictionary.
+ @param cin: Console standard input.
+ @type cin: IO stream
+ @param cout: Console standard output.
+ @type cout: IO stream
+ @param cerr: Console standard error.
+ @type cerr: IO stream
+ @param exit_handler: Replacement for builtin exit() function
+ @type exit_handler: function
+ @param time_loop: Define the sleep time between two thread's loop
+ @type int
+ '''
+ #ipython0 initialisation
+ self._IP = None
+ self.init_ipython0(argv, user_ns, user_global_ns,
+ cin, cout, cerr,
+ ask_exit_handler)
+
+ #vars used by _execute
+ self._iter_more = 0
+ self._history_level = 0
+ self._complete_sep = re.compile('[\s\{\}\[\]\(\)\=]')
+ self._prompt = str(self._IP.outputcache.prompt1).strip()
+
+ #thread working vars
+ self._line_to_execute = ''
+ self._threading = True
+
+ #vars that will be checked by GUI loop to handle thread states...
+ #will be replaced later by PostEvent GUI funtions...
+ self._doc_text = None
+ self._help_text = None
+ self._add_button = None
+
+ def init_ipython0(self, argv=[], user_ns={}, user_global_ns=None,
+ cin=None, cout=None, cerr=None,
+ ask_exit_handler=None):
+ ''' Initialize an ipython0 instance '''
+
+ #first we redefine in/out/error functions of IPython
+ #BUG: we've got a limitation form ipython0 there
+ #only one instance can be instanciated else tehre will be
+ #cin/cout/cerr clash...
+ if cin:
+ IPython.genutils.Term.cin = cin
+ if cout:
+ IPython.genutils.Term.cout = cout
+ if cerr:
+ IPython.genutils.Term.cerr = cerr
+
+ excepthook = sys.excepthook
+
+ #Hack to save sys.displayhook, because ipython seems to overwrite it...
+ self.sys_displayhook_ori = sys.displayhook
+
+ self._IP = IPython.Shell.make_IPython(
+ argv,user_ns=user_ns,
+ user_global_ns=user_global_ns,
+ embedded=True,
+ shell_class=IPython.Shell.InteractiveShell)
+
+ #we save ipython0 displayhook and we restore sys.displayhook
+ self.displayhook = sys.displayhook
+ sys.displayhook = self.sys_displayhook_ori
+
+ #we replace IPython default encoding by wx locale encoding
+ loc = locale.getpreferredencoding()
+ if loc:
+ self._IP.stdin_encoding = loc
+ #we replace the ipython default pager by our pager
+ self._IP.set_hook('show_in_pager', self._pager)
+
+ #we replace the ipython default shell command caller
+ #by our shell handler
+ self._IP.set_hook('shell_hook', self._shell)
+
+ #we replace the ipython default input command caller by our method
+ IPython.iplib.raw_input_original = self._raw_input_original
+ #we replace the ipython default exit command by our method
+ self._IP.exit = ask_exit_handler
+ #we replace the help command
+ self._IP.user_ns['help'] = _Helper(self._pager_help)
+
+ #we disable cpase magic... until we found a way to use it properly.
+ #import IPython.ipapi
+ ip = IPython.ipapi.get()
+ def bypass_magic(self, arg):
+ print '%this magic is currently disabled.'
+ ip.expose_magic('cpaste', bypass_magic)
+
+ import __builtin__
+ __builtin__.raw_input = self._raw_input
+
+ sys.excepthook = excepthook
+
+ #----------------------- Thread management section ----------------------
+ def do_execute(self, line):
+ """
+ Tell the thread to process the 'line' command
+ """
+
+ self._line_to_execute = line
+
+ if self._threading:
+ #we launch the ipython line execution in a thread to make it
+ #interruptible with include it in self namespace to be able
+ #to call ce.raise_exc(KeyboardInterrupt)
+ self.ce = _CodeExecutor(self)
+ self.ce.start()
+ else:
+ try:
+ self._doc_text = None
+ self._help_text = None
+ self._execute()
+ # used for uper class to generate event after execution
+ self._after_execute()
+
+ except KeyboardInterrupt:
+ pass
+
+ #----------------------- IPython management section ----------------------
+ def get_threading(self):
+ """
+ Returns threading status, is set to True, then each command sent to
+ the interpreter will be executed in a separated thread allowing,
+ for example, breaking a long running commands.
+ Disallowing it, permits better compatibilty with instance that is embedding
+ IPython instance.
+
+ @return: Execution method
+ @rtype: bool
+ """
+ return self._threading
+
+ def set_threading(self, state):
+ """
+ Sets threading state, if set to True, then each command sent to
+ the interpreter will be executed in a separated thread allowing,
+ for example, breaking a long running commands.
+ Disallowing it, permits better compatibilty with instance that is embedding
+ IPython instance.
+
+ @param state: Sets threading state
+ @type bool
+ """
+ self._threading = state
+
+ def get_doc_text(self):
+ """
+ Returns the output of the processing that need to be paged (if any)
+
+ @return: The std output string.
+ @rtype: string
+ """
+ return self._doc_text
+
+ def get_help_text(self):
+ """
+ Returns the output of the processing that need to be paged via help pager(if any)
+
+ @return: The std output string.
+ @rtype: string
+ """
+ return self._help_text
+
+ def get_banner(self):
+ """
+ Returns the IPython banner for useful info on IPython instance
+
+ @return: The banner string.
+ @rtype: string
+ """
+ return self._IP.BANNER
+
+ def get_prompt_count(self):
+ """
+ Returns the prompt number.
+ Each time a user execute a line in the IPython shell the prompt count is increased
+
+ @return: The prompt number
+ @rtype: int
+ """
+ return self._IP.outputcache.prompt_count
+
+ def get_prompt(self):
+ """
+ Returns current prompt inside IPython instance
+ (Can be In [...]: ot ...:)
+
+ @return: The current prompt.
+ @rtype: string
+ """
+ return self._prompt
+
+ def get_indentation(self):
+ """
+ Returns the current indentation level
+ Usefull to put the caret at the good start position if we want to do autoindentation.
+
+ @return: The indentation level.
+ @rtype: int
+ """
+ return self._IP.indent_current_nsp
+
+ def update_namespace(self, ns_dict):
+ '''
+ Add the current dictionary to the shell namespace.
+
+ @param ns_dict: A dictionary of symbol-values.
+ @type ns_dict: dictionary
+ '''
+ self._IP.user_ns.update(ns_dict)
+
+ def complete(self, line):
+ '''
+ Returns an auto completed line and/or posibilities for completion.
+
+ @param line: Given line so far.
+ @type line: string
+
+ @return: Line completed as for as possible,
+ and possible further completions.
+ @rtype: tuple
+ '''
+ split_line = self._complete_sep.split(line)
+ possibilities = self._IP.complete(split_line[-1])
+ if possibilities:
+
+ def _common_prefix(str1, str2):
+ '''
+ Reduction function. returns common prefix of two given strings.
+
+ @param str1: First string.
+ @type str1: string
+ @param str2: Second string
+ @type str2: string
+
+ @return: Common prefix to both strings.
+ @rtype: string
+ '''
+ for i in range(len(str1)):
+ if not str2.startswith(str1[:i+1]):
+ return str1[:i]
+ return str1
+ common_prefix = reduce(_common_prefix, possibilities)
+ completed = line[:-len(split_line[-1])]+common_prefix
+ else:
+ completed = line
+ return completed, possibilities
+
+ def history_back(self):
+ '''
+ Provides one history command back.
+
+ @return: The command string.
+ @rtype: string
+ '''
+ history = ''
+ #the below while loop is used to suppress empty history lines
+ while((history == '' or history == '\n') and self._history_level >0):
+ if self._history_level >= 1:
+ self._history_level -= 1
+ history = self._get_history()
+ return history
+
+ def history_forward(self):
+ '''
+ Provides one history command forward.
+
+ @return: The command string.
+ @rtype: string
+ '''
+ history = ''
+ #the below while loop is used to suppress empty history lines
+ while((history == '' or history == '\n') \
+ and self._history_level <= self._get_history_max_index()):
+ if self._history_level < self._get_history_max_index():
+ self._history_level += 1
+ history = self._get_history()
+ else:
+ if self._history_level == self._get_history_max_index():
+ history = self._get_history()
+ self._history_level += 1
+ else:
+ history = ''
+ return history
+
+ def init_history_index(self):
+ '''
+ set history to last command entered
+ '''
+ self._history_level = self._get_history_max_index()+1
+
+ #----------------------- IPython PRIVATE management section --------------
+ def _after_execute(self):
+ '''
+ Can be redefined to generate post event after excution is done
+ '''
+ pass
+
+ def _ask_exit(self):
+ '''
+ Can be redefined to generate post event to exit the Ipython shell
+ '''
+ pass
+
+ def _get_history_max_index(self):
+ '''
+ returns the max length of the history buffer
+
+ @return: history length
+ @rtype: int
+ '''
+ return len(self._IP.input_hist_raw)-1
+
+ def _get_history(self):
+ '''
+ Get's the command string of the current history level.
+
+ @return: Historic command stri
+ @rtype: string
+ '''
+ rv = self._IP.input_hist_raw[self._history_level].strip('\n')
+ return rv
+
+ def _pager_help(self, text):
+ '''
+ This function is used as a callback replacment to IPython help pager function
+
+ It puts the 'text' value inside the self._help_text string that can be retrived via
+ get_help_text function.
+ '''
+ if self._help_text == None:
+ self._help_text = text
+ else:
+ self._help_text += text
+
+ def _pager(self, IP, text):
+ '''
+ This function is used as a callback replacment to IPython pager function
+
+ It puts the 'text' value inside the self._doc_text string that can be retrived via
+ get_doc_text function.
+ '''
+ self._doc_text = text
+
+ def _raw_input_original(self, prompt=''):
+ '''
+ Custom raw_input() replacement. Get's current line from console buffer.
+
+ @param prompt: Prompt to print. Here for compatability as replacement.
+ @type prompt: string
+
+ @return: The current command line text.
+ @rtype: string
+ '''
+ return self._line_to_execute
+
+ def _raw_input(self, prompt=''):
+ """ A replacement from python's raw_input.
+ """
+ raise NotImplementedError
+
+ def _execute(self):
+ '''
+ Executes the current line provided by the shell object.
+ '''
+
+ orig_stdout = sys.stdout
+ sys.stdout = IPython.Shell.Term.cout
+ #self.sys_displayhook_ori = sys.displayhook
+ #sys.displayhook = self.displayhook
+
+ try:
+ line = self._IP.raw_input(None, self._iter_more)
+ if self._IP.autoindent:
+ self._IP.readline_startup_hook(None)
+
+ except KeyboardInterrupt:
+ self._IP.write('\nKeyboardInterrupt\n')
+ self._IP.resetbuffer()
+ # keep cache in sync with the prompt counter:
+ self._IP.outputcache.prompt_count -= 1
+
+ if self._IP.autoindent:
+ self._IP.indent_current_nsp = 0
+ self._iter_more = 0
+ except:
+ self._IP.showtraceback()
+ else:
+ self._IP.write(str(self._IP.outputcache.prompt_out).strip())
+ self._iter_more = self._IP.push(line)
+ if (self._IP.SyntaxTB.last_syntax_error and \
+ self._IP.rc.autoedit_syntax):
+ self._IP.edit_syntax_error()
+ if self._iter_more:
+ self._prompt = str(self._IP.outputcache.prompt2).strip()
+ if self._IP.autoindent:
+ self._IP.readline_startup_hook(self._IP.pre_readline)
+ else:
+ self._prompt = str(self._IP.outputcache.prompt1).strip()
+ self._IP.indent_current_nsp = 0 #we set indentation to 0
+
+ sys.stdout = orig_stdout
+ #sys.displayhook = self.sys_displayhook_ori
+
+ def _shell(self, ip, cmd):
+ '''
+ Replacement method to allow shell commands without them blocking.
+
+ @param ip: Ipython instance, same as self._IP
+ @type cmd: Ipython instance
+ @param cmd: Shell command to execute.
+ @type cmd: string
+ '''
+ stdin, stdout = os.popen4(cmd)
+ result = stdout.read().decode('cp437').\
+ encode(locale.getpreferredencoding())
+ #we use print command because the shell command is called
+ #inside IPython instance and thus is redirected to thread cout
+ #"\x01\x1b[1;36m\x02" <-- add colour to the text...
+ print "\x01\x1b[1;36m\x02"+result
+ stdout.close()
+ stdin.close()
diff --git a/IPython/gui/wx/ipython_history.py b/IPython/gui/wx/ipython_history.py
new file mode 100644
index 0000000..91f8769
--- /dev/null
+++ b/IPython/gui/wx/ipython_history.py
@@ -0,0 +1,509 @@
+#!/usr/bin/python
+# -*- coding: iso-8859-15 -*-
+import wx
+import wx.stc as stc
+import keyword
+
+#-----------------------------------------
+# History widget for IPython
+__version__ = 0.5
+__author__ = "Laurent Dufrechou"
+__email__ = "laurent.dufrechou _at_ gmail.com"
+__license__ = "BSD"
+#-----------------------------------------
+class IPythonHistoryPanel(wx.Panel):
+
+ def __init__(self, parent,flt_empty=True,
+ flt_doc=True,flt_cmd=True,flt_magic=True):
+
+ wx.Panel.__init__(self,parent,-1)
+ #text_ctrl = wx.TextCtrl(self, -1, style=wx.TE_MULTILINE)
+ text_ctrl = PythonSTC(self, -1)
+
+
+ st_filt = wx.StaticText(self, -1, " Filter:")
+
+ self.filter_empty = wx.CheckBox(self, -1, "Empty commands")
+ self.filter_doc = wx.CheckBox(self, -1, "?: Doc commands")
+ self.filter_cmd = wx.CheckBox(self, -1, "!: Sys commands")
+ self.filter_magic = wx.CheckBox(self, -1, "%: Magic keys")
+
+ self.options={'filter_empty':{'value':'True',
+ 'checkbox':self.filter_empty, \
+ 'True':True,'False':False,
+ 'setfunc':lambda x:None},
+ 'filter_doc':{'value':'True',
+ 'checkbox':self.filter_doc, \
+ 'True':True,'False':False,
+ 'setfunc':lambda x:None},
+ 'filter_cmd':{'value':'True',
+ 'checkbox':self.filter_cmd, \
+ 'True':True,'False':False,
+ 'setfunc':lambda x:None},
+ 'filter_magic':{'value':'True',
+ 'checkbox':self.filter_magic, \
+ 'True':True,'False':False,
+ 'setfunc':lambda x:None},
+ }
+ self.reloadOptions(self.options)
+
+ self.filter_empty.Bind(wx.EVT_CHECKBOX, self.evtCheckEmptyFilter)
+ self.filter_doc.Bind(wx.EVT_CHECKBOX, self.evtCheckDocFilter)
+ self.filter_cmd.Bind(wx.EVT_CHECKBOX, self.evtCheckCmdFilter)
+ self.filter_magic.Bind(wx.EVT_CHECKBOX, self.evtCheckMagicFilter)
+
+ #self.filter_empty.SetValue(flt_empty)
+ #self.filter_doc.SetValue(flt_doc)
+ #self.filter_cmd.SetValue(flt_cmd)
+ #self.filter_magic.SetValue(flt_magic)
+
+ sizer = wx.BoxSizer(wx.VERTICAL)
+
+ sizer.Add(text_ctrl, 1, wx.EXPAND)
+ sizer.AddMany( [(5,5),
+ st_filt,
+ (10,10),
+ self.filter_empty,
+ self.filter_doc,
+ self.filter_cmd,
+ self.filter_magic,
+ (10,10),
+ ])
+ self.SetAutoLayout(True)
+ sizer.Fit(self)
+ sizer.SetSizeHints(self)
+ self.SetSizer(sizer)
+ self.text_ctrl=text_ctrl
+ #text_ctrl.SetText(demoText + open('Main.py').read())
+ text_ctrl.EmptyUndoBuffer()
+ text_ctrl.Colourise(0, -1)
+
+ # line numbers in the margin
+ text_ctrl.SetMarginType(1, stc.STC_MARGIN_NUMBER)
+ text_ctrl.SetMarginWidth(1, 15)
+
+
+ def write(self,history_line):
+ add = True
+ if self.filter_empty.GetValue() == True and history_line == '':
+ add = False
+ if len(history_line)>0:
+ if self.filter_doc.GetValue() == True and history_line[-1:] == '?':
+ add = False
+ if self.filter_cmd.GetValue() == True and history_line[0] == '!':
+ add = False
+ if self.filter_magic.GetValue() == True and history_line[0] == '%':
+ add = False
+ if add:
+ self.text_ctrl.AppendText(history_line+'\n')
+
+#------------------------ Option Section -----------------------------------
+ def processOptionCheckedEvt(self, event, name):
+ if event.IsChecked():
+ self.options[name]['value']='True'
+ else:
+ self.options[name]['value']='False'
+ self.updateOptionTracker(name,
+ self.options[name]['value'])
+
+ def evtCheckEmptyFilter(self, event):
+ self.processOptionCheckedEvt(event, 'filter_empty')
+
+ def evtCheckDocFilter(self, event):
+ self.processOptionCheckedEvt(event, 'filter_doc')
+
+ def evtCheckCmdFilter(self, event):
+ self.processOptionCheckedEvt(event, 'filter_cmd')
+
+ def evtCheckMagicFilter(self, event):
+ self.processOptionCheckedEvt(event, 'filter_magic')
+
+ def getOptions(self):
+ return self.options
+
+ def reloadOptions(self,options):
+ self.options = options
+ for key in self.options.keys():
+ value = self.options[key]['value']
+ self.options[key]['checkbox'].SetValue(self.options[key][value])
+ self.options[key]['setfunc'](value)
+
+#------------------------ Hook Section -----------------------------------
+ def updateOptionTracker(self,name,value):
+ '''
+ Default history tracker (does nothing)
+ '''
+ pass
+
+ def setOptionTrackerHook(self,func):
+ '''
+ Define a new history tracker
+ '''
+ self.updateOptionTracker = func
+
+
+#----------------------------------------------------------------------
+# Font definition for Styled Text Control
+
+if wx.Platform == '__WXMSW__':
+ faces = { 'times': 'Times New Roman',
+ 'mono' : 'Courier New',
+ 'helv' : 'Arial',
+ 'other': 'Comic Sans MS',
+ 'size' : 8,
+ 'size2': 6,
+ }
+elif wx.Platform == '__WXMAC__':
+ faces = { 'times': 'Times New Roman',
+ 'mono' : 'Monaco',
+ 'helv' : 'Arial',
+ 'other': 'Comic Sans MS',
+ 'size' : 8,
+ 'size2': 6,
+ }
+else:
+ faces = { 'times': 'Times',
+ 'mono' : 'Courier',
+ 'helv' : 'Helvetica',
+ 'other': 'new century schoolbook',
+ 'size' : 8,
+ 'size2': 6,
+ }
+
+
+#----------------------------------------------------------------------
+
+class PythonSTC(stc.StyledTextCtrl):
+
+ fold_symbols = 3
+
+ def __init__(self, parent, ID,
+ pos=wx.DefaultPosition, size=wx.DefaultSize,
+ style=0):
+ stc.StyledTextCtrl.__init__(self, parent, ID, pos, size, style)
+ #self.CmdKeyAssign(ord('B'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
+ #self.CmdKeyAssign(ord('N'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)
+
+ self.SetLexer(stc.STC_LEX_PYTHON)
+ self.SetKeyWords(0, " ".join(keyword.kwlist))
+
+ #self.SetProperty("fold", "1")
+ #self.SetProperty("tab.timmy.whinge.level", "1")
+ #self.SetMargins(0,0)
+
+ #self.SetViewWhiteSpace(False)
+ #self.SetBufferedDraw(False)
+ #self.SetViewEOL(True)
+ self.SetEOLMode(stc.STC_EOL_CRLF)
+ #self.SetUseAntiAliasing(True)
+
+ self.SetEdgeMode(stc.STC_EDGE_LINE)
+ self.SetEdgeColumn(80)
+ self.SetEdgeColour(wx.LIGHT_GREY)
+ self.SetLayoutCache(stc.STC_CACHE_PAGE)
+
+ # Setup a margin to hold fold markers
+ #self.SetFoldFlags(16)
+ ### WHAT IS THIS VALUE? WHAT ARE THE OTHER FLAGS? DOES IT MATTER?
+ self.SetMarginType(2, stc.STC_MARGIN_SYMBOL)
+ self.SetMarginMask(2, stc.STC_MASK_FOLDERS)
+ self.SetMarginSensitive(2, True)
+ self.SetMarginWidth(2, 12)
+
+ if self.fold_symbols == 0:
+ # Arrow pointing right for contracted folders,
+ # arrow pointing down for expanded
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, \
+ stc.STC_MARK_ARROWDOWN, "black", "black")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDER, \
+ stc.STC_MARK_ARROW, "black", "black")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, \
+ stc.STC_MARK_EMPTY, "black", "black")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, \
+ stc.STC_MARK_EMPTY, "black", "black")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, \
+ stc.STC_MARK_EMPTY, "white", "black")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, \
+ stc.STC_MARK_EMPTY, "white", "black")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, \
+ stc.STC_MARK_EMPTY, "white", "black")
+
+ elif self.fold_symbols == 1:
+ # Plus for contracted folders, minus for expanded
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, \
+ stc.STC_MARK_MINUS, "white", "black")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDER, \
+ stc.STC_MARK_PLUS, "white", "black")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, \
+ stc.STC_MARK_EMPTY, "white", "black")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, \
+ stc.STC_MARK_EMPTY, "white", "black")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, \
+ stc.STC_MARK_EMPTY, "white", "black")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, \
+ stc.STC_MARK_EMPTY, "white", "black")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, \
+ stc.STC_MARK_EMPTY, "white", "black")
+
+ elif self.fold_symbols == 2:
+ # Like a flattened tree control using circular headers and curved joins
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, \
+ stc.STC_MARK_CIRCLEMINUS, "white", "#404040")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDER, \
+ stc.STC_MARK_CIRCLEPLUS, "white", "#404040")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, \
+ stc.STC_MARK_VLINE, "white", "#404040")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, \
+ stc.STC_MARK_LCORNERCURVE, "white", "#404040")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, \
+ stc.STC_MARK_CIRCLEPLUSCONNECTED, "white", "#404040")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, \
+ stc.STC_MARK_CIRCLEMINUSCONNECTED, "white", "#404040")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, \
+ stc.STC_MARK_TCORNERCURVE, "white", "#404040")
+
+ elif self.fold_symbols == 3:
+ # Like a flattened tree control using square headers
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, \
+ stc.STC_MARK_BOXMINUS, "white", "#808080")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDER, \
+ stc.STC_MARK_BOXPLUS, "white", "#808080")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, \
+ stc.STC_MARK_VLINE, "white", "#808080")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, \
+ stc.STC_MARK_LCORNER, "white", "#808080")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, \
+ stc.STC_MARK_BOXPLUSCONNECTED, "white", "#808080")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, \
+ stc.STC_MARK_BOXMINUSCONNECTED, "white", "#808080")
+ self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, \
+ stc.STC_MARK_TCORNER, "white", "#808080")
+
+
+ self.Bind(stc.EVT_STC_UPDATEUI, self.OnUpdateUI)
+ self.Bind(stc.EVT_STC_MARGINCLICK, self.OnMarginClick)
+ self.Bind(wx.EVT_KEY_DOWN, self.OnKeyPressed)
+
+ # Make some styles, The lexer defines what each style is used for, we
+ # just have to define what each style looks like. This set is adapted from
+ # Scintilla sample property files.
+
+ # Global default styles for all languages
+ self.StyleSetSpec(stc.STC_STYLE_DEFAULT, "face:%(helv)s,size:%(size)d" % faces)
+ self.StyleClearAll() # Reset all to be like the default
+
+ # Global default styles for all languages
+ self.StyleSetSpec(stc.STC_STYLE_DEFAULT, "face:%(helv)s,size:%(size)d" % faces)
+ self.StyleSetSpec(stc.STC_STYLE_LINENUMBER, "back:#C0C0C0,face:%(helv)s,size:%(size2)d" % faces)
+ self.StyleSetSpec(stc.STC_STYLE_CONTROLCHAR, "face:%(other)s" % faces)
+ self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, "fore:#FFFFFF,back:#0000FF,bold")
+ self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, "fore:#000000,back:#FF0000,bold")
+
+ # Python styles
+ # Default
+ self.StyleSetSpec(stc.STC_P_DEFAULT, "fore:#000000,face:%(helv)s,size:%(size)d" % faces)
+ # Comments
+ self.StyleSetSpec(stc.STC_P_COMMENTLINE, "fore:#007F00,face:%(other)s,size:%(size)d" % faces)
+ # Number
+ self.StyleSetSpec(stc.STC_P_NUMBER, "fore:#007F7F,size:%(size)d" % faces)
+ # String
+ self.StyleSetSpec(stc.STC_P_STRING, "fore:#7F007F,face:%(helv)s,size:%(size)d" % faces)
+ # Single quoted string
+ self.StyleSetSpec(stc.STC_P_CHARACTER, "fore:#7F007F,face:%(helv)s,size:%(size)d" % faces)
+ # Keyword
+ self.StyleSetSpec(stc.STC_P_WORD, "fore:#00007F,bold,size:%(size)d" % faces)
+ # Triple quotes
+ self.StyleSetSpec(stc.STC_P_TRIPLE, "fore:#7F0000,size:%(size)d" % faces)
+ # Triple double quotes
+ self.StyleSetSpec(stc.STC_P_TRIPLEDOUBLE, "fore:#7F0000,size:%(size)d" % faces)
+ # Class name definition
+ self.StyleSetSpec(stc.STC_P_CLASSNAME, "fore:#0000FF,bold,underline,size:%(size)d" % faces)
+ # Function or method name definition
+ self.StyleSetSpec(stc.STC_P_DEFNAME, "fore:#007F7F,bold,size:%(size)d" % faces)
+ # Operators
+ self.StyleSetSpec(stc.STC_P_OPERATOR, "bold,size:%(size)d" % faces)
+ # Identifiers
+ self.StyleSetSpec(stc.STC_P_IDENTIFIER, "fore:#000000,face:%(helv)s,size:%(size)d" % faces)
+ # Comment-blocks
+ self.StyleSetSpec(stc.STC_P_COMMENTBLOCK, "fore:#7F7F7F,size:%(size)d" % faces)
+ # End of line where string is not closed
+ self.StyleSetSpec(stc.STC_P_STRINGEOL, "fore:#000000,face:%(mono)s,back:#E0C0E0,eol,size:%(size)d" % faces)
+
+ self.SetCaretForeground("BLUE")
+
+
+ # register some images for use in the AutoComplete box.
+ #self.RegisterImage(1, images.getSmilesBitmap())
+ #self.RegisterImage(2,
+ # wx.ArtProvider.GetBitmap(wx.ART_NEW, size=(16,16)))
+ #self.RegisterImage(3,
+ # wx.ArtProvider.GetBitmap(wx.ART_COPY, size=(16,16)))
+
+
+ def OnKeyPressed(self, event):
+ if self.CallTipActive():
+ self.CallTipCancel()
+ key = event.GetKeyCode()
+
+ if key == 32 and event.ControlDown():
+ pos = self.GetCurrentPos()
+
+ # Tips
+ if event.ShiftDown():
+ self.CallTipSetBackground("yellow")
+ self.CallTipShow(pos, 'lots of of text: blah, blah, blah\n\n'
+ 'show some suff, maybe parameters..\n\n'
+ 'fubar(param1, param2)')
+ # Code completion
+ else:
+ #lst = []
+ #for x in range(50000):
+ # lst.append('%05d' % x)
+ #st = " ".join(lst)
+ #print len(st)
+ #self.AutoCompShow(0, st)
+
+ kw = keyword.kwlist[:]
+
+ kw.sort() # Python sorts are case sensitive
+ self.AutoCompSetIgnoreCase(False) # so this needs to match
+
+ # Images are specified with a appended "?type"
+ for i in range(len(kw)):
+ if kw[i] in keyword.kwlist:
+ kw[i] = kw[i]# + "?1"
+
+ self.AutoCompShow(0, " ".join(kw))
+ else:
+ event.Skip()
+
+
+ def OnUpdateUI(self, evt):
+ # check for matching braces
+ braceAtCaret = -1
+ braceOpposite = -1
+ charBefore = None
+ caretPos = self.GetCurrentPos()
+
+ if caretPos > 0:
+ charBefore = self.GetCharAt(caretPos - 1)
+ styleBefore = self.GetStyleAt(caretPos - 1)
+
+ # check before
+ if charBefore and chr(charBefore) in "[]{}()" and styleBefore == stc.STC_P_OPERATOR:
+ braceAtCaret = caretPos - 1
+
+ # check after
+ if braceAtCaret < 0:
+ charAfter = self.GetCharAt(caretPos)
+ styleAfter = self.GetStyleAt(caretPos)
+
+ if charAfter and chr(charAfter) in "[]{}()" and styleAfter == stc.STC_P_OPERATOR:
+ braceAtCaret = caretPos
+
+ if braceAtCaret >= 0:
+ braceOpposite = self.BraceMatch(braceAtCaret)
+
+ if braceAtCaret != -1 and braceOpposite == -1:
+ self.BraceBadLight(braceAtCaret)
+ else:
+ self.BraceHighlight(braceAtCaret, braceOpposite)
+ #pt = self.PointFromPosition(braceOpposite)
+ #self.Refresh(True, wxRect(pt.x, pt.y, 5,5))
+ #print pt
+ #self.Refresh(False)
+
+
+ def OnMarginClick(self, evt):
+ # fold and unfold as needed
+ if evt.GetMargin() == 2:
+ if evt.GetShift() and evt.GetControl():
+ self.FoldAll()
+ else:
+ lineClicked = self.LineFromPosition(evt.GetPosition())
+
+ if self.GetFoldLevel(lineClicked) & stc.STC_FOLDLEVELHEADERFLAG:
+ if evt.GetShift():
+ self.SetFoldExpanded(lineClicked, True)
+ self.Expand(lineClicked, True, True, 1)
+ elif evt.GetControl():
+ if self.GetFoldExpanded(lineClicked):
+ self.SetFoldExpanded(lineClicked, False)
+ self.Expand(lineClicked, False, True, 0)
+ else:
+ self.SetFoldExpanded(lineClicked, True)
+ self.Expand(lineClicked, True, True, 100)
+ else:
+ self.ToggleFold(lineClicked)
+
+
+ def FoldAll(self):
+ lineCount = self.GetLineCount()
+ expanding = True
+
+ # find out if we are folding or unfolding
+ for lineNum in range(lineCount):
+ if self.GetFoldLevel(lineNum) & stc.STC_FOLDLEVELHEADERFLAG:
+ expanding = not self.GetFoldExpanded(lineNum)
+ break
+
+ lineNum = 0
+
+ while lineNum < lineCount:
+ level = self.GetFoldLevel(lineNum)
+ if level & stc.STC_FOLDLEVELHEADERFLAG and \
+ (level & stc.STC_FOLDLEVELNUMBERMASK) == stc.STC_FOLDLEVELBASE:
+
+ if expanding:
+ self.SetFoldExpanded(lineNum, True)
+ lineNum = self.Expand(lineNum, True)
+ lineNum = lineNum - 1
+ else:
+ lastChild = self.GetLastChild(lineNum, -1)
+ self.SetFoldExpanded(lineNum, False)
+
+ if lastChild > lineNum:
+ self.HideLines(lineNum+1, lastChild)
+
+ lineNum = lineNum + 1
+
+
+
+ def Expand(self, line, doExpand, force=False, visLevels=0, level=-1):
+ lastChild = self.GetLastChild(line, level)
+ line = line + 1
+
+ while line <= lastChild:
+ if force:
+ if visLevels > 0:
+ self.ShowLines(line, line)
+ else:
+ self.HideLines(line, line)
+ else:
+ if doExpand:
+ self.ShowLines(line, line)
+
+ if level == -1:
+ level = self.GetFoldLevel(line)
+
+ if level & stc.STC_FOLDLEVELHEADERFLAG:
+ if force:
+ if visLevels > 1:
+ self.SetFoldExpanded(line, True)
+ else:
+ self.SetFoldExpanded(line, False)
+
+ line = self.Expand(line, doExpand, force, visLevels-1)
+
+ else:
+ if doExpand and self.GetFoldExpanded(line):
+ line = self.Expand(line, True, force, visLevels-1)
+ else:
+ line = self.Expand(line, False, force, visLevels-1)
+ else:
+ line = line + 1
+
+ return line
+
+
+#----------------------------------------------------------------------
diff --git a/IPython/gui/wx/ipython_view.py b/IPython/gui/wx/ipython_view.py
new file mode 100644
index 0000000..2fc44c3
--- /dev/null
+++ b/IPython/gui/wx/ipython_view.py
@@ -0,0 +1,942 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+'''
+Provides IPython WX console widgets.
+
+@author: Laurent Dufrechou
+laurent.dufrechou _at_ gmail.com
+This WX widget is based on the original work of Eitan Isaacson
+that provided the console for the GTK toolkit.
+
+Original work from:
+@author: Eitan Isaacson
+@organization: IBM Corporation
+@copyright: Copyright (c) 2007 IBM Corporation
+@license: BSD
+
+All rights reserved. This program and the accompanying materials are made
+available under the terms of the BSD which accompanies this distribution, and
+is available at U{http://www.opensource.org/licenses/bsd-license.php}
+'''
+
+__version__ = 0.9
+__author__ = "Laurent Dufrechou"
+__email__ = "laurent.dufrechou _at_ gmail.com"
+__license__ = "BSD"
+
+import wx
+import wx.stc as stc
+
+import re
+from StringIO import StringIO
+
+import sys
+import codecs
+import locale
+import time
+
+for enc in (locale.getpreferredencoding(),
+ sys.getfilesystemencoding(),
+ sys.getdefaultencoding()):
+ try:
+ codecs.lookup(enc)
+ ENCODING = enc
+ break
+ except LookupError:
+ pass
+else:
+ ENCODING = 'utf-8'
+
+from ipshell_nonblocking import NonBlockingIPShell
+
+class WxNonBlockingIPShell(NonBlockingIPShell):
+ '''
+ An NonBlockingIPShell Thread that is WX dependent.
+ '''
+ def __init__(self, parent,
+ argv=[],user_ns={},user_global_ns=None,
+ cin=None, cout=None, cerr=None,
+ ask_exit_handler=None):
+
+ NonBlockingIPShell.__init__(self, argv, user_ns, user_global_ns,
+ cin, cout, cerr,
+ ask_exit_handler)
+
+ self.parent = parent
+
+ self.ask_exit_callback = ask_exit_handler
+ self._IP.exit = self._ask_exit
+
+ def addGUIShortcut(self, text, func):
+ wx.CallAfter(self.parent.add_button_handler,
+ button_info={ 'text':text,
+ 'func':self.parent.doExecuteLine(func)})
+
+ def _raw_input(self, prompt=''):
+ """ A replacement from python's raw_input.
+ """
+ self.answer = None
+ if(self._threading == True):
+ wx.CallAfter(self._yesNoBox, prompt)
+ while self.answer is None:
+ time.sleep(.1)
+ else:
+ self._yesNoBox(prompt)
+ return self.answer
+
+ def _yesNoBox(self, prompt):
+ """ yes/no box managed with wx.CallAfter jsut in case caler is executed in a thread"""
+ dlg = wx.TextEntryDialog(
+ self.parent, prompt,
+ 'Input requested', 'Python')
+ dlg.SetValue("")
+
+ answer = ''
+ if dlg.ShowModal() == wx.ID_OK:
+ answer = dlg.GetValue()
+
+ dlg.Destroy()
+ self.answer = answer
+
+ def _ask_exit(self):
+ wx.CallAfter(self.ask_exit_callback, ())
+
+ def _after_execute(self):
+ wx.CallAfter(self.parent.evtStateExecuteDone, ())
+
+
+class WxConsoleView(stc.StyledTextCtrl):
+ '''
+ Specialized styled text control view for console-like workflow.
+ We use here a scintilla frontend thus it can be reused in any GUI that
+ supports scintilla with less work.
+
+ @cvar ANSI_COLORS_BLACK: Mapping of terminal colors to X11 names.
+ (with Black background)
+ @type ANSI_COLORS_BLACK: dictionary
+
+ @cvar ANSI_COLORS_WHITE: Mapping of terminal colors to X11 names.
+ (with White background)
+ @type ANSI_COLORS_WHITE: dictionary
+
+ @ivar color_pat: Regex of terminal color pattern
+ @type color_pat: _sre.SRE_Pattern
+ '''
+ ANSI_STYLES_BLACK = {'0;30': [0, 'WHITE'], '0;31': [1, 'RED'],
+ '0;32': [2, 'GREEN'], '0;33': [3, 'BROWN'],
+ '0;34': [4, 'BLUE'], '0;35': [5, 'PURPLE'],
+ '0;36': [6, 'CYAN'], '0;37': [7, 'LIGHT GREY'],
+ '1;30': [8, 'DARK GREY'], '1;31': [9, 'RED'],
+ '1;32': [10, 'SEA GREEN'], '1;33': [11, 'YELLOW'],
+ '1;34': [12, 'LIGHT BLUE'], '1;35':
+ [13, 'MEDIUM VIOLET RED'],
+ '1;36': [14, 'LIGHT STEEL BLUE'], '1;37': [15, 'YELLOW']}
+
+ ANSI_STYLES_WHITE = {'0;30': [0, 'BLACK'], '0;31': [1, 'RED'],
+ '0;32': [2, 'GREEN'], '0;33': [3, 'BROWN'],
+ '0;34': [4, 'BLUE'], '0;35': [5, 'PURPLE'],
+ '0;36': [6, 'CYAN'], '0;37': [7, 'LIGHT GREY'],
+ '1;30': [8, 'DARK GREY'], '1;31': [9, 'RED'],
+ '1;32': [10, 'SEA GREEN'], '1;33': [11, 'YELLOW'],
+ '1;34': [12, 'LIGHT BLUE'], '1;35':
+ [13, 'MEDIUM VIOLET RED'],
+ '1;36': [14, 'LIGHT STEEL BLUE'], '1;37': [15, 'YELLOW']}
+
+ def __init__(self, parent, prompt, intro="", background_color="BLACK",
+ pos=wx.DefaultPosition, ID = -1, size=wx.DefaultSize,
+ style=0, autocomplete_mode = 'IPYTHON'):
+ '''
+ Initialize console view.
+
+ @param parent: Parent widget
+ @param prompt: User specified prompt
+ @type intro: string
+ @param intro: User specified startup introduction string
+ @type intro: string
+ @param background_color: Can be BLACK or WHITE
+ @type background_color: string
+ @param other: init param of styledTextControl (can be used as-is)
+ @param autocomplete_mode: Can be 'IPYTHON' or 'STC'
+ 'IPYTHON' show autocompletion the ipython way
+ 'STC" show it scintilla text control way
+ '''
+ stc.StyledTextCtrl.__init__(self, parent, ID, pos, size, style)
+
+ ####### Scintilla configuration ###################################
+
+ # Ctrl + B or Ctrl + N can be used to zoomin/zoomout the text inside
+ # the widget
+ self.CmdKeyAssign(ord('B'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
+ self.CmdKeyAssign(ord('N'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)
+
+ #We draw a line at position 80
+ self.SetEdgeMode(stc.STC_EDGE_LINE)
+ self.SetEdgeColumn(80)
+ self.SetEdgeColour(wx.LIGHT_GREY)
+
+ #self.SetViewWhiteSpace(True)
+ #self.SetViewEOL(True)
+ self.SetEOLMode(stc.STC_EOL_CRLF)
+ #self.SetWrapMode(stc.STC_WRAP_CHAR)
+ #self.SetWrapMode(stc.STC_WRAP_WORD)
+ self.SetBufferedDraw(True)
+ #self.SetUseAntiAliasing(True)
+ self.SetLayoutCache(stc.STC_CACHE_PAGE)
+ self.SetUndoCollection(False)
+ self.SetUseTabs(True)
+ self.SetIndent(4)
+ self.SetTabWidth(4)
+
+ self.EnsureCaretVisible()
+
+ self.SetMargins(3, 3) #text is moved away from border with 3px
+ # Suppressing Scintilla margins
+ self.SetMarginWidth(0, 0)
+ self.SetMarginWidth(1, 0)
+ self.SetMarginWidth(2, 0)
+
+ self.background_color = background_color
+ self.buildStyles()
+
+ self.indent = 0
+ self.prompt_count = 0
+ self.color_pat = re.compile('\x01?\x1b\[(.*?)m\x02?')
+
+ self.write(intro)
+ self.setPrompt(prompt)
+ self.showPrompt()
+
+ self.autocomplete_mode = autocomplete_mode
+
+ self.Bind(wx.EVT_KEY_DOWN, self._onKeypress)
+
+ def buildStyles(self):
+ #we define platform specific fonts
+ if wx.Platform == '__WXMSW__':
+ faces = { 'times': 'Times New Roman',
+ 'mono' : 'Courier New',
+ 'helv' : 'Arial',
+ 'other': 'Comic Sans MS',
+ 'size' : 10,
+ 'size2': 8,
+ }
+ elif wx.Platform == '__WXMAC__':
+ faces = { 'times': 'Times New Roman',
+ 'mono' : 'Monaco',
+ 'helv' : 'Arial',
+ 'other': 'Comic Sans MS',
+ 'size' : 10,
+ 'size2': 8,
+ }
+ else:
+ faces = { 'times': 'Times',
+ 'mono' : 'Courier',
+ 'helv' : 'Helvetica',
+ 'other': 'new century schoolbook',
+ 'size' : 10,
+ 'size2': 8,
+ }
+
+ # make some styles
+ if self.background_color != "BLACK":
+ self.background_color = "WHITE"
+ self.SetCaretForeground("BLACK")
+ self.ANSI_STYLES = self.ANSI_STYLES_WHITE
+ else:
+ self.SetCaretForeground("WHITE")
+ self.ANSI_STYLES = self.ANSI_STYLES_BLACK
+
+ self.StyleSetSpec(stc.STC_STYLE_DEFAULT,
+ "fore:%s,back:%s,size:%d,face:%s"
+ % (self.ANSI_STYLES['0;30'][1],
+ self.background_color,
+ faces['size'], faces['mono']))
+ self.StyleClearAll()
+ self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT,
+ "fore:#FF0000,back:#0000FF,bold")
+ self.StyleSetSpec(stc.STC_STYLE_BRACEBAD,
+ "fore:#000000,back:#FF0000,bold")
+
+ for style in self.ANSI_STYLES.values():
+ self.StyleSetSpec(style[0], "bold,fore:%s" % style[1])
+
+ #######################################################################
+
+ def setBackgroundColor(self, color):
+ self.background_color = color
+ self.buildStyles()
+
+ def getBackgroundColor(self, color):
+ return self.background_color
+
+ def asyncWrite(self, text):
+ '''
+ Write given text to buffer in an asynchroneous way.
+ It is used from another thread to be able to acces the GUI.
+ @param text: Text to append
+ @type text: string
+ '''
+ try:
+ wx.MutexGuiEnter()
+
+ #be sure not to be interrutpted before the MutexGuiLeave!
+ self.write(text)
+
+ except KeyboardInterrupt:
+ wx.MutexGuiLeave()
+ raise KeyboardInterrupt
+ wx.MutexGuiLeave()
+
+
+ def write(self, text):
+ '''
+ Write given text to buffer.
+
+ @param text: Text to append.
+ @type text: string
+ '''
+ segments = self.color_pat.split(text)
+ segment = segments.pop(0)
+ self.StartStyling(self.getCurrentLineEnd(), 0xFF)
+ self.AppendText(segment)
+
+ if segments:
+ ansi_tags = self.color_pat.findall(text)
+
+ for tag in ansi_tags:
+ i = segments.index(tag)
+ self.StartStyling(self.getCurrentLineEnd(), 0xFF)
+ self.AppendText(segments[i+1])
+
+ if tag != '0':
+ self.SetStyling(len(segments[i+1]), self.ANSI_STYLES[tag][0])
+
+ segments.pop(i)
+
+ self.moveCursor(self.getCurrentLineEnd())
+
+ def getPromptLen(self):
+ '''
+ Return the length of current prompt
+ '''
+ return len(str(self.prompt_count)) + 7
+
+ def setPrompt(self, prompt):
+ self.prompt = prompt
+
+ def setIndentation(self, indentation):
+ self.indent = indentation
+
+ def setPromptCount(self, count):
+ self.prompt_count = count
+
+ def showPrompt(self):
+ '''
+ Prints prompt at start of line.
+
+ @param prompt: Prompt to print.
+ @type prompt: string
+ '''
+ self.write(self.prompt)
+ #now we update the position of end of prompt
+ self.current_start = self.getCurrentLineEnd()
+
+ autoindent = self.indent*' '
+ autoindent = autoindent.replace(' ','\t')
+ self.write(autoindent)
+
+ def changeLine(self, text):
+ '''
+ Replace currently entered command line with given text.
+
+ @param text: Text to use as replacement.
+ @type text: string
+ '''
+ self.SetSelection(self.getCurrentPromptStart(), self.getCurrentLineEnd())
+ self.ReplaceSelection(text)
+ self.moveCursor(self.getCurrentLineEnd())
+
+ def getCurrentPromptStart(self):
+ return self.current_start
+
+ def getCurrentLineStart(self):
+ return self.GotoLine(self.LineFromPosition(self.GetCurrentPos()))
+
+ def getCurrentLineEnd(self):
+ return self.GetLength()
+
+ def getCurrentLine(self):
+ '''
+ Get text in current command line.
+
+ @return: Text of current command line.
+ @rtype: string
+ '''
+ return self.GetTextRange(self.getCurrentPromptStart(),
+ self.getCurrentLineEnd())
+
+ def moveCursorOnNewValidKey(self):
+ #If cursor is at wrong position put it at last line...
+ if self.GetCurrentPos() < self.getCurrentPromptStart():
+ self.GotoPos(self.getCurrentPromptStart())
+
+ def removeFromTo(self, from_pos, to_pos):
+ if from_pos < to_pos:
+ self.SetSelection(from_pos, to_pos)
+ self.DeleteBack()
+
+ def removeCurrentLine(self):
+ self.LineDelete()
+
+ def moveCursor(self, position):
+ self.GotoPos(position)
+
+ def getCursorPos(self):
+ return self.GetCurrentPos()
+
+ def selectFromTo(self, from_pos, to_pos):
+ self.SetSelectionStart(from_pos)
+ self.SetSelectionEnd(to_pos)
+
+ def writeHistory(self, history):
+ self.removeFromTo(self.getCurrentPromptStart(), self.getCurrentLineEnd())
+ self.changeLine(history)
+
+ def setCompletionMethod(self, completion):
+ if completion in ['IPYTHON', 'STC']:
+ self.autocomplete_mode = completion
+ else:
+ raise AttributeError
+
+ def getCompletionMethod(self, completion):
+ return self.autocomplete_mode
+
+ def writeCompletion(self, possibilities):
+ if self.autocomplete_mode == 'IPYTHON':
+ max_len = len(max(possibilities, key=len))
+ max_symbol = ' '*max_len
+
+ #now we check how much symbol we can put on a line...
+ test_buffer = max_symbol + ' '*4
+
+ allowed_symbols = 80/len(test_buffer)
+ if allowed_symbols == 0:
+ allowed_symbols = 1
+
+ pos = 1
+ buf = ''
+ for symbol in possibilities:
+ #buf += symbol+'\n'#*spaces)
+ if pos < allowed_symbols:
+ spaces = max_len - len(symbol) + 4
+ buf += symbol+' '*spaces
+ pos += 1
+ else:
+ buf += symbol+'\n'
+ pos = 1
+ self.write(buf)
+ else:
+ possibilities.sort() # Python sorts are case sensitive
+ self.AutoCompSetIgnoreCase(False)
+ self.AutoCompSetAutoHide(False)
+ #let compute the length ot last word
+ splitter = [' ', '(', '[', '{','=']
+ last_word = self.getCurrentLine()
+ for breaker in splitter:
+ last_word = last_word.split(breaker)[-1]
+ self.AutoCompShow(len(last_word), " ".join(possibilities))
+
+ def _onKeypress(self, event, skip=True):
+ '''
+ Key press callback used for correcting behavior for console-like
+ interfaces. For example 'home' should go to prompt, not to begining of
+ line.
+
+ @param widget: Widget that key press accored in.
+ @type widget: gtk.Widget
+ @param event: Event object
+ @type event: gtk.gdk.Event
+
+ @return: Return True if event as been catched.
+ @rtype: boolean
+ '''
+ if not self.AutoCompActive():
+ if event.GetKeyCode() == wx.WXK_HOME:
+ if event.Modifiers == wx.MOD_NONE:
+ self.moveCursorOnNewValidKey()
+ self.moveCursor(self.getCurrentPromptStart())
+ return True
+ elif event.Modifiers == wx.MOD_SHIFT:
+ self.moveCursorOnNewValidKey()
+ self.selectFromTo(self.getCurrentPromptStart(), self.getCursorPos())
+ return True
+ else:
+ return False
+
+ elif event.GetKeyCode() == wx.WXK_LEFT:
+ if event.Modifiers == wx.MOD_NONE:
+ self.moveCursorOnNewValidKey()
+
+ self.moveCursor(self.getCursorPos()-1)
+ if self.getCursorPos() < self.getCurrentPromptStart():
+ self.moveCursor(self.getCurrentPromptStart())
+ return True
+
+ elif event.GetKeyCode() == wx.WXK_BACK:
+ self.moveCursorOnNewValidKey()
+ if self.getCursorPos() > self.getCurrentPromptStart():
+ event.Skip()
+ return True
+
+ if skip:
+ if event.GetKeyCode() not in [wx.WXK_PAGEUP, wx.WXK_PAGEDOWN]\
+ and event.Modifiers == wx.MOD_NONE:
+ self.moveCursorOnNewValidKey()
+
+ event.Skip()
+ return True
+ return False
+ else:
+ event.Skip()
+
+ def OnUpdateUI(self, evt):
+ # check for matching braces
+ braceAtCaret = -1
+ braceOpposite = -1
+ charBefore = None
+ caretPos = self.GetCurrentPos()
+
+ if caretPos > 0:
+ charBefore = self.GetCharAt(caretPos - 1)
+ styleBefore = self.GetStyleAt(caretPos - 1)
+
+ # check before
+ if charBefore and chr(charBefore) in "[]{}()" and styleBefore == stc.STC_P_OPERATOR:
+ braceAtCaret = caretPos - 1
+
+ # check after
+ if braceAtCaret < 0:
+ charAfter = self.GetCharAt(caretPos)
+ styleAfter = self.GetStyleAt(caretPos)
+
+ if charAfter and chr(charAfter) in "[]{}()" and styleAfter == stc.STC_P_OPERATOR:
+ braceAtCaret = caretPos
+
+ if braceAtCaret >= 0:
+ braceOpposite = self.BraceMatch(braceAtCaret)
+
+ if braceAtCaret != -1 and braceOpposite == -1:
+ self.BraceBadLight(braceAtCaret)
+ else:
+ self.BraceHighlight(braceAtCaret, braceOpposite)
+ #pt = self.PointFromPosition(braceOpposite)
+ #self.Refresh(True, wxRect(pt.x, pt.y, 5,5))
+ #print pt
+ #self.Refresh(False)
+
+class IPShellWidget(wx.Panel):
+ '''
+ This is wx.Panel that embbed the IPython Thread and the wx.StyledTextControl
+ If you want to port this to any other GUI toolkit, just replace the
+ WxConsoleView by YOURGUIConsoleView and make YOURGUIIPythonView derivate
+ from whatever container you want. I've choosed to derivate from a wx.Panel
+ because it seems to be more useful
+ Any idea to make it more 'generic' welcomed.
+ '''
+
+ def __init__(self, parent, intro=None,
+ background_color="BLACK", add_button_handler=None,
+ wx_ip_shell=None, user_ns={},user_global_ns=None,
+ ):
+ '''
+ Initialize.
+ Instanciate an IPython thread.
+ Instanciate a WxConsoleView.
+ Redirect I/O to console.
+ '''
+ wx.Panel.__init__(self,parent,wx.ID_ANY)
+
+ self.parent = parent
+ ### IPython non blocking shell instanciation ###
+ self.cout = StringIO()
+ self.add_button_handler = add_button_handler
+
+ if wx_ip_shell is not None:
+ self.IP = wx_ip_shell
+ else:
+ self.IP = WxNonBlockingIPShell(self,
+ cout = self.cout, cerr = self.cout,
+ ask_exit_handler = self.askExitCallback)
+
+ ### IPython wx console view instanciation ###
+ #If user didn't defined an intro text, we create one for him
+ #If you really wnat an empty intro just call wxIPythonViewPanel
+ #with intro=''
+ if intro is None:
+ welcome_text = "Welcome to WxIPython Shell.\n\n"
+ welcome_text+= self.IP.get_banner()
+ welcome_text+= "!command -> Execute command in shell\n"
+ welcome_text+= "TAB -> Autocompletion\n"
+ else:
+ welcome_text = intro
+
+ self.text_ctrl = WxConsoleView(self,
+ self.IP.get_prompt(),
+ intro=welcome_text,
+ background_color=background_color)
+
+ option_text = wx.StaticText(self, -1, "Options:")
+ self.completion_option = wx.CheckBox(self, -1, "Scintilla Completion")
+ self.completion_option.SetToolTip(wx.ToolTip(
+ "Selects the completion type:\nEither Ipython default style or Scintilla one"))
+ #self.completion_option.SetValue(False)
+ self.background_option = wx.CheckBox(self, -1, "White Background")
+ self.background_option.SetToolTip(wx.ToolTip(
+ "Selects the back ground color: BLACK or WHITE"))
+ #self.background_option.SetValue(False)
+ self.threading_option = wx.CheckBox(self, -1, "Execute in thread")
+ self.threading_option.SetToolTip(wx.ToolTip(
+ "Use threading: infinite loop don't freeze the GUI and commands can be breaked\nNo threading: maximum compatibility"))
+ #self.threading_option.SetValue(False)
+
+ self.options={'completion':{'value':'IPYTHON',
+ 'checkbox':self.completion_option,'STC':True,'IPYTHON':False,
+ 'setfunc':self.text_ctrl.setCompletionMethod},
+ 'background_color':{'value':'BLACK',
+ 'checkbox':self.background_option,'WHITE':True,'BLACK':False,
+ 'setfunc':self.text_ctrl.setBackgroundColor},
+ 'threading':{'value':'True',
+ 'checkbox':self.threading_option,'True':True,'False':False,
+ 'setfunc':self.IP.set_threading},
+ }
+
+ #self.cout.write dEfault option is asynchroneous because default sate is threading ON
+ self.cout.write = self.text_ctrl.asyncWrite
+ #we reloard options
+ self.reloadOptions(self.options)
+
+ self.text_ctrl.Bind(wx.EVT_KEY_DOWN, self.keyPress)
+ self.completion_option.Bind(wx.EVT_CHECKBOX, self.evtCheckOptionCompletion)
+ self.background_option.Bind(wx.EVT_CHECKBOX, self.evtCheckOptionBackgroundColor)
+ self.threading_option.Bind(wx.EVT_CHECKBOX, self.evtCheckOptionThreading)
+
+ ### making the layout of the panel ###
+ sizer = wx.BoxSizer(wx.VERTICAL)
+ sizer.Add(self.text_ctrl, 1, wx.EXPAND)
+ option_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ sizer.Add(option_sizer, 0)
+ option_sizer.AddMany([(10, 20),
+ (option_text, 0, wx.ALIGN_CENTER_VERTICAL),
+ (5, 5),
+ (self.completion_option, 0, wx.ALIGN_CENTER_VERTICAL),
+ (8, 8),
+ (self.background_option, 0, wx.ALIGN_CENTER_VERTICAL),
+ (8, 8),
+ (self.threading_option, 0, wx.ALIGN_CENTER_VERTICAL)
+ ])
+ self.SetAutoLayout(True)
+ sizer.Fit(self)
+ sizer.SetSizeHints(self)
+ self.SetSizer(sizer)
+ #and we focus on the widget :)
+ self.SetFocus()
+
+ #widget state management (for key handling different cases)
+ self.setCurrentState('IDLE')
+ self.pager_state = 'DONE'
+ self.raw_input_current_line = 0
+
+ def askExitCallback(self, event):
+ self.askExitHandler(event)
+
+ #---------------------- IPython Thread Management ------------------------
+ def stateDoExecuteLine(self):
+ lines=self.text_ctrl.getCurrentLine()
+ self.text_ctrl.write('\n')
+ lines_to_execute = lines.replace('\t',' '*4)
+ lines_to_execute = lines_to_execute.replace('\r','')
+ self.IP.do_execute(lines_to_execute.encode(ENCODING))
+ self.updateHistoryTracker(lines)
+ if(self.text_ctrl.getCursorPos()!=0):
+ self.text_ctrl.removeCurrentLine()
+ self.setCurrentState('WAIT_END_OF_EXECUTION')
+
+ def evtStateExecuteDone(self,evt):
+ self.doc = self.IP.get_doc_text()
+ self.help = self.IP.get_help_text()
+ if self.doc:
+ self.pager_lines = self.doc[7:].split('\n')
+ self.pager_state = 'INIT'
+ self.setCurrentState('SHOW_DOC')
+ self.pager(self.doc)
+ elif self.help:
+ self.pager_lines = self.help.split('\n')
+ self.pager_state = 'INIT'
+ self.setCurrentState('SHOW_DOC')
+ self.pager(self.help)
+ else:
+ if(self.text_ctrl.getCursorPos()!=0):
+ self.text_ctrl.removeCurrentLine()
+ self.stateShowPrompt()
+
+ def stateShowPrompt(self):
+ self.setCurrentState('SHOW_PROMPT')
+ self.text_ctrl.setPrompt(self.IP.get_prompt())
+ self.text_ctrl.setIndentation(self.IP.get_indentation())
+ self.text_ctrl.setPromptCount(self.IP.get_prompt_count())
+ self.text_ctrl.showPrompt()
+ self.IP.init_history_index()
+ self.setCurrentState('IDLE')
+
+ def setCurrentState(self, state):
+ self.cur_state = state
+ self.updateStatusTracker(self.cur_state)
+
+ def pager(self,text):
+
+ if self.pager_state == 'INIT':
+ #print >>sys.__stdout__,"PAGER state:",self.pager_state
+ self.pager_nb_lines = len(self.pager_lines)
+ self.pager_index = 0
+ self.pager_do_remove = False
+ self.text_ctrl.write('\n')
+ self.pager_state = 'PROCESS_LINES'
+
+ if self.pager_state == 'PROCESS_LINES':
+ #print >>sys.__stdout__,"PAGER state:",self.pager_state
+ if self.pager_do_remove == True:
+ self.text_ctrl.removeCurrentLine()
+ self.pager_do_remove = False
+
+ if self.pager_nb_lines > 10:
+ #print >>sys.__stdout__,"PAGER processing 10 lines"
+ if self.pager_index > 0:
+ self.text_ctrl.write(">\x01\x1b[1;36m\x02"+self.pager_lines[self.pager_index]+'\n')
+ else:
+ self.text_ctrl.write("\x01\x1b[1;36m\x02 "+self.pager_lines[self.pager_index]+'\n')
+
+ for line in self.pager_lines[self.pager_index+1:self.pager_index+9]:
+ self.text_ctrl.write("\x01\x1b[1;36m\x02 "+line+'\n')
+ self.pager_index += 10
+ self.pager_nb_lines -= 10
+ self.text_ctrl.write("--- Push Enter to continue or 'Q' to quit---")
+ self.pager_do_remove = True
+ self.pager_state = 'WAITING'
+ return
+ else:
+ #print >>sys.__stdout__,"PAGER processing last lines"
+ if self.pager_nb_lines > 0:
+ if self.pager_index > 0:
+ self.text_ctrl.write(">\x01\x1b[1;36m\x02"+self.pager_lines[self.pager_index]+'\n')
+ else:
+ self.text_ctrl.write("\x01\x1b[1;36m\x02 "+self.pager_lines[self.pager_index]+'\n')
+
+ self.pager_index += 1
+ self.pager_nb_lines -= 1
+ if self.pager_nb_lines > 0:
+ for line in self.pager_lines[self.pager_index:]:
+ self.text_ctrl.write("\x01\x1b[1;36m\x02 "+line+'\n')
+ self.pager_nb_lines = 0
+ self.pager_state = 'DONE'
+ self.stateShowPrompt()
+
+ #------------------------ Key Handler ------------------------------------
+ def keyPress(self, event):
+ '''
+ Key press callback with plenty of shell goodness, like history,
+ autocompletions, etc.
+ '''
+ if event.GetKeyCode() == ord('C'):
+ if event.Modifiers == wx.MOD_CONTROL or event.Modifiers == wx.MOD_ALT:
+ if self.cur_state == 'WAIT_END_OF_EXECUTION':
+ #we raise an exception inside the IPython thread container
+ self.IP.ce.raise_exc(KeyboardInterrupt)
+ return
+
+ #let this before 'wx.WXK_RETURN' because we have to put 'IDLE'
+ #mode if AutoComp has been set as inactive
+ if self.cur_state == 'COMPLETING':
+ if not self.text_ctrl.AutoCompActive():
+ self.cur_state = 'IDLE'
+ else:
+ event.Skip()
+
+ if event.KeyCode == wx.WXK_RETURN:
+ if self.cur_state == 'IDLE':
+ #we change the state ot the state machine
+ self.setCurrentState('DO_EXECUTE_LINE')
+ self.stateDoExecuteLine()
+ return
+
+ if self.pager_state == 'WAITING':
+ self.pager_state = 'PROCESS_LINES'
+ self.pager(self.doc)
+ return
+
+ if self.cur_state == 'WAITING_USER_INPUT':
+ line=self.text_ctrl.getCurrentLine()
+ self.text_ctrl.write('\n')
+ self.setCurrentState('WAIT_END_OF_EXECUTION')
+ return
+
+ if event.GetKeyCode() in [ord('q'),ord('Q')]:
+ if self.pager_state == 'WAITING':
+ self.pager_state = 'DONE'
+ self.text_ctrl.write('\n')
+ self.stateShowPrompt()
+ return
+
+ if self.cur_state == 'WAITING_USER_INPUT':
+ event.Skip()
+
+ if self.cur_state == 'IDLE':
+ if event.KeyCode == wx.WXK_UP:
+ history = self.IP.history_back()
+ self.text_ctrl.writeHistory(history)
+ return
+ if event.KeyCode == wx.WXK_DOWN:
+ history = self.IP.history_forward()
+ self.text_ctrl.writeHistory(history)
+ return
+ if event.KeyCode == wx.WXK_TAB:
+ #if line empty we disable tab completion
+ if not self.text_ctrl.getCurrentLine().strip():
+ self.text_ctrl.write('\t')
+ return
+ completed, possibilities = self.IP.complete(self.text_ctrl.getCurrentLine())
+ if len(possibilities) > 1:
+ if self.text_ctrl.autocomplete_mode == 'IPYTHON':
+ cur_slice = self.text_ctrl.getCurrentLine()
+ self.text_ctrl.write('\n')
+ self.text_ctrl.writeCompletion(possibilities)
+ self.text_ctrl.write('\n')
+
+ self.text_ctrl.showPrompt()
+ self.text_ctrl.write(cur_slice)
+ self.text_ctrl.changeLine(completed or cur_slice)
+ else:
+ self.cur_state = 'COMPLETING'
+ self.text_ctrl.writeCompletion(possibilities)
+ else:
+ self.text_ctrl.changeLine(completed or cur_slice)
+ return
+ event.Skip()
+
+ #------------------------ Option Section ---------------------------------
+ def evtCheckOptionCompletion(self, event):
+ if event.IsChecked():
+ self.options['completion']['value']='STC'
+ else:
+ self.options['completion']['value']='IPYTHON'
+ self.text_ctrl.setCompletionMethod(self.options['completion']['value'])
+ self.updateOptionTracker('completion',
+ self.options['completion']['value'])
+ self.text_ctrl.SetFocus()
+
+ def evtCheckOptionBackgroundColor(self, event):
+ if event.IsChecked():
+ self.options['background_color']['value']='WHITE'
+ else:
+ self.options['background_color']['value']='BLACK'
+ self.text_ctrl.setBackgroundColor(self.options['background_color']['value'])
+ self.updateOptionTracker('background_color',
+ self.options['background_color']['value'])
+ self.text_ctrl.SetFocus()
+
+ def evtCheckOptionThreading(self, event):
+ if event.IsChecked():
+ self.options['threading']['value']='True'
+ self.IP.set_threading(True)
+ self.cout.write = self.text_ctrl.asyncWrite
+ else:
+ self.options['threading']['value']='False'
+ self.IP.set_threading(False)
+ self.cout.write = self.text_ctrl.write
+ self.updateOptionTracker('threading',
+ self.options['threading']['value'])
+ self.text_ctrl.SetFocus()
+
+ def getOptions(self):
+ return self.options
+
+ def reloadOptions(self,options):
+ self.options = options
+ for key in self.options.keys():
+ value = self.options[key]['value']
+ self.options[key]['checkbox'].SetValue(self.options[key][value])
+ self.options[key]['setfunc'](value)
+
+ if self.options['threading']['value']=='True':
+ self.IP.set_threading(True)
+ self.cout.write = self.text_ctrl.asyncWrite
+ else:
+ self.IP.set_threading(False)
+ self.cout.write = self.text_ctrl.write
+
+ #------------------------ Hook Section -----------------------------------
+ def updateOptionTracker(self,name,value):
+ '''
+ Default history tracker (does nothing)
+ '''
+ pass
+
+ def setOptionTrackerHook(self,func):
+ '''
+ Define a new history tracker
+ '''
+ self.updateOptionTracker = func
+
+ def updateHistoryTracker(self,command_line):
+ '''
+ Default history tracker (does nothing)
+ '''
+ pass
+
+ def setHistoryTrackerHook(self,func):
+ '''
+ Define a new history tracker
+ '''
+ self.updateHistoryTracker = func
+
+ def updateStatusTracker(self,status):
+ '''
+ Default status tracker (does nothing)
+ '''
+ pass
+
+ def setStatusTrackerHook(self,func):
+ '''
+ Define a new status tracker
+ '''
+ self.updateStatusTracker = func
+
+ def askExitHandler(self, event):
+ '''
+ Default exit handler
+ '''
+ self.text_ctrl.write('\nExit callback has not been set.')
+
+ def setAskExitHandler(self, func):
+ '''
+ Define an exit handler
+ '''
+ self.askExitHandler = func
+
+if __name__ == '__main__':
+ # Some simple code to test the shell widget.
+ class MainWindow(wx.Frame):
+ def __init__(self, parent, id, title):
+ wx.Frame.__init__(self, parent, id, title, size=(300,250))
+ self._sizer = wx.BoxSizer(wx.VERTICAL)
+ self.shell = IPShellWidget(self)
+ self._sizer.Add(self.shell, 1, wx.EXPAND)
+ self.SetSizer(self._sizer)
+ self.SetAutoLayout(1)
+ self.Show(True)
+
+ app = wx.PySimpleApp()
+ frame = MainWindow(None, wx.ID_ANY, 'Ipython')
+ frame.SetSize((780, 460))
+ shell = frame.shell
+
+ app.MainLoop()
diff --git a/IPython/gui/wx/thread_ex.py b/IPython/gui/wx/thread_ex.py
new file mode 100644
index 0000000..0af86d0
--- /dev/null
+++ b/IPython/gui/wx/thread_ex.py
@@ -0,0 +1,50 @@
+"""
+Thread subclass that can deal with asynchronously function calls via
+raise_exc.
+"""
+
+import threading
+import inspect
+import ctypes
+
+
+def _async_raise(tid, exctype):
+ """raises the exception, performs cleanup if needed"""
+ if not inspect.isclass(exctype):
+ raise TypeError("Only types can be raised (not instances)")
+ res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype))
+ if res == 0:
+ raise ValueError("invalid thread id")
+ elif res != 1:
+ # """if it returns a number greater than one, you're in trouble,
+ # and you should call it again with exc=NULL to revert the effect"""
+ ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, 0)
+ raise SystemError("PyThreadState_SetAsyncExc failed")
+
+
+class ThreadEx(threading.Thread):
+ def _get_my_tid(self):
+ """determines this (self's) thread id"""
+ if not self.isAlive():
+ raise threading.ThreadError("the thread is not active")
+
+ # do we have it cached?
+ if hasattr(self, "_thread_id"):
+ return self._thread_id
+
+ # no, look for it in the _active dict
+ for tid, tobj in threading._active.items():
+ if tobj is self:
+ self._thread_id = tid
+ return tid
+
+ raise AssertionError("could not determine the thread's id")
+
+ def raise_exc(self, exctype):
+ """raises the given exception type in the context of this thread"""
+ _async_raise(self._get_my_tid(), exctype)
+
+ def kill(self):
+ """raises SystemExit in the context of the given thread, which should
+ cause the thread to exit silently (unless caught)"""
+ self.raise_exc(SystemExit)
diff --git a/IPython/gui/wx/wxIPython.py b/IPython/gui/wx/wxIPython.py
new file mode 100644
index 0000000..b724e53
--- /dev/null
+++ b/IPython/gui/wx/wxIPython.py
@@ -0,0 +1,266 @@
+#!/usr/bin/python
+# -*- coding: iso-8859-15 -*-
+
+import wx.aui
+import sys
+#used for about dialog
+from wx.lib.wordwrap import wordwrap
+
+#used for ipython GUI objects
+from IPython.gui.wx.ipython_view import IPShellWidget
+from IPython.gui.wx.ipython_history import IPythonHistoryPanel
+
+#used to invoke ipython1 wx implementation
+### FIXME ### temporary disabled due to interference with 'show_in_pager' hook
+is_sync_frontend_ok = False
+try:
+ from IPython.frontend.wx.ipythonx import IPythonXController
+except ImportError:
+ is_sync_frontend_ok = False
+
+#used to create options.conf file in user directory
+from IPython.ipapi import get
+
+__version__ = 0.91
+__author__ = "Laurent Dufrechou"
+__email__ = "laurent.dufrechou _at_ gmail.com"
+__license__ = "BSD"
+
+#-----------------------------------------
+# Creating one main frame for our
+# application with movables windows
+#-----------------------------------------
+class MyFrame(wx.Frame):
+ """Creating one main frame for our
+ application with movables windows"""
+ def __init__(self, parent=None, id=-1, title="WxIPython",
+ pos=wx.DefaultPosition,
+ size=(800, 600), style=wx.DEFAULT_FRAME_STYLE, sync_ok=False):
+ wx.Frame.__init__(self, parent, id, title, pos, size, style)
+ self._mgr = wx.aui.AuiManager()
+
+ # notify PyAUI which frame to use
+ self._mgr.SetManagedWindow(self)
+
+ #create differents panels and make them persistant
+ self.history_panel = IPythonHistoryPanel(self)
+
+ self.history_panel.setOptionTrackerHook(self.optionSave)
+
+ self.ipython_panel = IPShellWidget(self,background_color = "BLACK")
+ #self.ipython_panel = IPShellWidget(self,background_color = "WHITE")
+ if(sync_ok):
+ self.ipython_panel2 = IPythonXController(self)
+ else:
+ self.ipython_panel2 = None
+ self.ipython_panel.setHistoryTrackerHook(self.history_panel.write)
+ self.ipython_panel.setStatusTrackerHook(self.updateStatus)
+ self.ipython_panel.setAskExitHandler(self.OnExitDlg)
+ self.ipython_panel.setOptionTrackerHook(self.optionSave)
+
+ #Create a notebook to display different IPython shell implementations
+ self.nb = wx.aui.AuiNotebook(self)
+
+ self.optionLoad()
+
+ self.statusbar = self.createStatus()
+ self.createMenu()
+
+ ########################################################################
+ ### add the panes to the manager
+ # main panels
+ self._mgr.AddPane(self.nb , wx.CENTER, "IPython Shells")
+ self.nb.AddPage(self.ipython_panel , "IPython0 Shell")
+ if(sync_ok):
+ self.nb.AddPage(self.ipython_panel2, "IPython1 Synchroneous Shell")
+
+ self._mgr.AddPane(self.history_panel , wx.RIGHT, "IPython history")
+
+ # now we specify some panel characteristics
+ self._mgr.GetPane(self.ipython_panel).CaptionVisible(True);
+ self._mgr.GetPane(self.history_panel).CaptionVisible(True);
+ self._mgr.GetPane(self.history_panel).MinSize((200,400));
+
+ # tell the manager to "commit" all the changes just made
+ self._mgr.Update()
+
+ #global event handling
+ self.Bind(wx.EVT_CLOSE, self.OnClose)
+ self.Bind(wx.EVT_MENU, self.OnClose,id=wx.ID_EXIT)
+ self.Bind(wx.EVT_MENU, self.OnShowIPythonPanel,id=wx.ID_HIGHEST+1)
+ self.Bind(wx.EVT_MENU, self.OnShowHistoryPanel,id=wx.ID_HIGHEST+2)
+ self.Bind(wx.EVT_MENU, self.OnShowAbout, id=wx.ID_HIGHEST+3)
+ self.Bind(wx.EVT_MENU, self.OnShowAllPanel,id=wx.ID_HIGHEST+6)
+
+ warn_text = 'Hello from IPython and wxPython.\n'
+ warn_text +='Please Note that this work is still EXPERIMENTAL\n'
+ warn_text +='It does NOT emulate currently all the IPython functions.\n'
+ warn_text +="\nIf you use MATPLOTLIB with show() you'll need to deactivate the THREADING option.\n"
+ if(not sync_ok):
+ warn_text +="\n->No twisted package detected, IPython1 example deactivated."
+
+ dlg = wx.MessageDialog(self,
+ warn_text,
+ 'Warning Box',
+ wx.OK | wx.ICON_INFORMATION
+ )
+ dlg.ShowModal()
+ dlg.Destroy()
+
+ def optionSave(self, name, value):
+ ip = get()
+ path = ip.IP.rc.ipythondir
+ opt = open(path + '/options.conf','w')
+
+ try:
+ options_ipython_panel = self.ipython_panel.getOptions()
+ options_history_panel = self.history_panel.getOptions()
+
+ for key in options_ipython_panel.keys():
+ opt.write(key + '=' + options_ipython_panel[key]['value']+'\n')
+ for key in options_history_panel.keys():
+ opt.write(key + '=' + options_history_panel[key]['value']+'\n')
+ finally:
+ opt.close()
+
+ def optionLoad(self):
+ try:
+ ip = get()
+ path = ip.IP.rc.ipythondir
+ opt = open(path + '/options.conf','r')
+ lines = opt.readlines()
+ opt.close()
+
+ options_ipython_panel = self.ipython_panel.getOptions()
+ options_history_panel = self.history_panel.getOptions()
+
+ for line in lines:
+ key = line.split('=')[0]
+ value = line.split('=')[1].replace('\n','').replace('\r','')
+ if key in options_ipython_panel.keys():
+ options_ipython_panel[key]['value'] = value
+ elif key in options_history_panel.keys():
+ options_history_panel[key]['value'] = value
+ else:
+ print >>sys.__stdout__,"Warning: key ",key,"not found in widget options. Check Options.conf"
+ self.ipython_panel.reloadOptions(options_ipython_panel)
+ self.history_panel.reloadOptions(options_history_panel)
+
+ except IOError:
+ print >>sys.__stdout__,"Could not open Options.conf, defaulting to default values."
+
+
+ def createMenu(self):
+ """local method used to create one menu bar"""
+
+ mb = wx.MenuBar()
+
+ file_menu = wx.Menu()
+ file_menu.Append(wx.ID_EXIT, "Exit")
+
+ view_menu = wx.Menu()
+ view_menu.Append(wx.ID_HIGHEST+1, "Show IPython Panel")
+ view_menu.Append(wx.ID_HIGHEST+2, "Show History Panel")
+ view_menu.AppendSeparator()
+ view_menu.Append(wx.ID_HIGHEST+6, "Show All")
+
+ about_menu = wx.Menu()
+ about_menu.Append(wx.ID_HIGHEST+3, "About")
+
+ mb.Append(file_menu, "File")
+ mb.Append(view_menu, "View")
+ mb.Append(about_menu, "About")
+ #mb.Append(options_menu, "Options")
+
+ self.SetMenuBar(mb)
+
+ def createStatus(self):
+ statusbar = self.CreateStatusBar(2, wx.ST_SIZEGRIP)
+ statusbar.SetStatusWidths([-2, -3])
+ statusbar.SetStatusText("Ready", 0)
+ statusbar.SetStatusText("WxIPython "+str(__version__), 1)
+ return statusbar
+
+ def updateStatus(self,text):
+ states = {'IDLE':'Idle',
+ 'DO_EXECUTE_LINE':'Send command',
+ 'WAIT_END_OF_EXECUTION':'Running command',
+ 'WAITING_USER_INPUT':'Waiting user input',
+ 'SHOW_DOC':'Showing doc',
+ 'SHOW_PROMPT':'Showing prompt'}
+ self.statusbar.SetStatusText(states[text], 0)
+
+ def OnClose(self, event):
+ """#event used to close program """
+ # deinitialize the frame manager
+ self._mgr.UnInit()
+ self.Destroy()
+ event.Skip()
+
+ def OnExitDlg(self, event):
+ dlg = wx.MessageDialog(self, 'Are you sure you want to quit WxIPython',
+ 'WxIPython exit',
+ wx.ICON_QUESTION |
+ wx.YES_NO | wx.NO_DEFAULT
+ )
+ if dlg.ShowModal() == wx.ID_YES:
+ dlg.Destroy()
+ self._mgr.UnInit()
+ self.Destroy()
+ dlg.Destroy()
+
+ #event to display IPython pannel
+ def OnShowIPythonPanel(self,event):
+ """ #event to display Boxpannel """
+ self._mgr.GetPane(self.ipython_panel).Show(True)
+ self._mgr.Update()
+ #event to display History pannel
+ def OnShowHistoryPanel(self,event):
+ self._mgr.GetPane(self.history_panel).Show(True)
+ self._mgr.Update()
+
+ def OnShowAllPanel(self,event):
+ """#event to display all Pannels"""
+ self._mgr.GetPane(self.ipython_panel).Show(True)
+ self._mgr.GetPane(self.history_panel).Show(True)
+ self._mgr.Update()
+
+ def OnShowAbout(self, event):
+ # First we create and fill the info object
+ info = wx.AboutDialogInfo()
+ info.Name = "WxIPython"
+ info.Version = str(__version__)
+ info.Copyright = "(C) 2007 Laurent Dufrechou"
+ info.Description = wordwrap(
+ "A Gui that embbed a multithreaded IPython Shell",
+ 350, wx.ClientDC(self))
+ info.WebSite = ("http://ipython.scipy.org/", "IPython home page")
+ info.Developers = [ "Laurent Dufrechou" ]
+ licenseText="BSD License.\nAll rights reserved. This program and the accompanying materials are made available under the terms of the BSD which accompanies this distribution, and is available at http://www.opensource.org/licenses/bsd-license.php"
+ info.License = wordwrap(licenseText, 500, wx.ClientDC(self))
+
+ # Then we call wx.AboutBox giving it that info object
+ wx.AboutBox(info)
+
+#-----------------------------------------
+#Creating our application
+#-----------------------------------------
+class MyApp(wx.PySimpleApp):
+ """Creating our application"""
+ def __init__(self, sync_ok=False):
+ wx.PySimpleApp.__init__(self)
+
+ self.frame = MyFrame(sync_ok=sync_ok)
+ self.frame.Show()
+
+#-----------------------------------------
+#Main loop
+#-----------------------------------------
+def main():
+ app = MyApp(is_sync_frontend_ok)
+ app.SetTopWindow(app.frame)
+ app.MainLoop()
+
+#if launched as main program run this
+if __name__ == '__main__':
+ main()
diff --git a/IPython/history.py b/IPython/history.py
new file mode 100644
index 0000000..40508c8
--- /dev/null
+++ b/IPython/history.py
@@ -0,0 +1,258 @@
+# -*- coding: utf-8 -*-
+""" History related magics and functionality """
+
+# Stdlib imports
+import fnmatch
+import os
+
+# IPython imports
+from IPython.genutils import Term, ask_yes_no, warn
+import IPython.ipapi
+
+def magic_history(self, parameter_s = ''):
+ """Print input history (_i<n> variables), with most recent last.
+
+ %history -> print at most 40 inputs (some may be multi-line)\\
+ %history n -> print at most n inputs\\
+ %history n1 n2 -> print inputs between n1 and n2 (n2 not included)\\
+
+ Each input's number <n> is shown, and is accessible as the
+ automatically generated variable _i<n>. Multi-line statements are
+ printed starting at a new line for easy copy/paste.
+
+
+ Options:
+
+ -n: do NOT print line numbers. This is useful if you want to get a
+ printout of many lines which can be directly pasted into a text
+ editor.
+
+ This feature is only available if numbered prompts are in use.
+
+ -t: (default) print the 'translated' history, as IPython understands it.
+ IPython filters your input and converts it all into valid Python source
+ before executing it (things like magics or aliases are turned into
+ function calls, for example). With this option, you'll see the native
+ history instead of the user-entered version: '%cd /' will be seen as
+ '_ip.magic("%cd /")' instead of '%cd /'.
+
+ -r: print the 'raw' history, i.e. the actual commands you typed.
+
+ -g: treat the arg as a pattern to grep for in (full) history.
+ This includes the "shadow history" (almost all commands ever written).
+ Use '%hist -g' to show full shadow history (may be very long).
+ In shadow history, every index nuwber starts with 0.
+
+ -f FILENAME: instead of printing the output to the screen, redirect it to
+ the given file. The file is always overwritten, though IPython asks for
+ confirmation first if it already exists.
+ """
+
+ ip = self.api
+ shell = self.shell
+ if not shell.outputcache.do_full_cache:
+ print 'This feature is only available if numbered prompts are in use.'
+ return
+ opts,args = self.parse_options(parameter_s,'gntsrf:',mode='list')
+
+ # Check if output to specific file was requested.
+ try:
+ outfname = opts['f']
+ except KeyError:
+ outfile = Term.cout # default
+ # We don't want to close stdout at the end!
+ close_at_end = False
+ else:
+ if os.path.exists(outfname):
+ if not ask_yes_no("File %r exists. Overwrite?" % outfname):
+ print 'Aborting.'
+ return
+
+ outfile = open(outfname,'w')
+ close_at_end = True
+
+ if 't' in opts:
+ input_hist = shell.input_hist
+ elif 'r' in opts:
+ input_hist = shell.input_hist_raw
+ else:
+ input_hist = shell.input_hist
+
+ default_length = 40
+ pattern = None
+ if 'g' in opts:
+ init = 1
+ final = len(input_hist)
+ parts = parameter_s.split(None,1)
+ if len(parts) == 1:
+ parts += '*'
+ head, pattern = parts
+ pattern = "*" + pattern + "*"
+ elif len(args) == 0:
+ final = len(input_hist)
+ init = max(1,final-default_length)
+ elif len(args) == 1:
+ final = len(input_hist)
+ init = max(1,final-int(args[0]))
+ elif len(args) == 2:
+ init,final = map(int,args)
+ else:
+ warn('%hist takes 0, 1 or 2 arguments separated by spaces.')
+ print self.magic_hist.__doc__
+ return
+ width = len(str(final))
+ line_sep = ['','\n']
+ print_nums = not opts.has_key('n')
+
+ found = False
+ if pattern is not None:
+ sh = ip.IP.shadowhist.all()
+ for idx, s in sh:
+ if fnmatch.fnmatch(s, pattern):
+ print "0%d: %s" %(idx, s)
+ found = True
+
+ if found:
+ print "==="
+ print "shadow history ends, fetch by %rep <number> (must start with 0)"
+ print "=== start of normal history ==="
+
+ for in_num in range(init,final):
+ inline = input_hist[in_num]
+ if pattern is not None and not fnmatch.fnmatch(inline, pattern):
+ continue
+
+ multiline = int(inline.count('\n') > 1)
+ if print_nums:
+ print >> outfile, \
+ '%s:%s' % (str(in_num).ljust(width),line_sep[multiline]),
+ print >> outfile, inline,
+
+ if close_at_end:
+ outfile.close()
+
+
+def magic_hist(self, parameter_s=''):
+ """Alternate name for %history."""
+ return self.magic_history(parameter_s)
+
+
+def rep_f(self, arg):
+ r""" Repeat a command, or get command to input line for editing
+
+ - %rep (no arguments):
+
+ Place a string version of last computation result (stored in the special '_'
+ variable) to the next input prompt. Allows you to create elaborate command
+ lines without using copy-paste::
+
+ $ l = ["hei", "vaan"]
+ $ "".join(l)
+ ==> heivaan
+ $ %rep
+ $ heivaan_ <== cursor blinking
+
+ %rep 45
+
+ Place history line 45 to next input prompt. Use %hist to find out the
+ number.
+
+ %rep 1-4 6-7 3
+
+ Repeat the specified lines immediately. Input slice syntax is the same as
+ in %macro and %save.
+
+ %rep foo
+
+ Place the most recent line that has the substring "foo" to next input.
+ (e.g. 'svn ci -m foobar').
+ """
+
+ opts,args = self.parse_options(arg,'',mode='list')
+ ip = self.api
+ if not args:
+ ip.set_next_input(str(ip.user_ns["_"]))
+ return
+
+ if len(args) == 1 and not '-' in args[0]:
+ arg = args[0]
+ if len(arg) > 1 and arg.startswith('0'):
+ # get from shadow hist
+ num = int(arg[1:])
+ line = self.shadowhist.get(num)
+ ip.set_next_input(str(line))
+ return
+ try:
+ num = int(args[0])
+ ip.set_next_input(str(ip.IP.input_hist_raw[num]).rstrip())
+ return
+ except ValueError:
+ pass
+
+ for h in reversed(self.shell.input_hist_raw):
+ if 'rep' in h:
+ continue
+ if fnmatch.fnmatch(h,'*' + arg + '*'):
+ ip.set_next_input(str(h).rstrip())
+ return
+
+ try:
+ lines = self.extract_input_slices(args, True)
+ print "lines",lines
+ ip.runlines(lines)
+ except ValueError:
+ print "Not found in recent history:", args
+
+
+_sentinel = object()
+
+class ShadowHist:
+ def __init__(self,db):
+ # cmd => idx mapping
+ self.curidx = 0
+ self.db = db
+ self.disabled = False
+
+ def inc_idx(self):
+ idx = self.db.get('shadowhist_idx', 1)
+ self.db['shadowhist_idx'] = idx + 1
+ return idx
+
+ def add(self, ent):
+ if self.disabled:
+ return
+ try:
+ old = self.db.hget('shadowhist', ent, _sentinel)
+ if old is not _sentinel:
+ return
+ newidx = self.inc_idx()
+ #print "new",newidx # dbg
+ self.db.hset('shadowhist',ent, newidx)
+ except:
+ IPython.ipapi.get().IP.showtraceback()
+ print "WARNING: disabling shadow history"
+ self.disabled = True
+
+ def all(self):
+ d = self.db.hdict('shadowhist')
+ items = [(i,s) for (s,i) in d.items()]
+ items.sort()
+ return items
+
+ def get(self, idx):
+ all = self.all()
+
+ for k, v in all:
+ #print k,v
+ if k == idx:
+ return v
+
+
+def init_ipython(ip):
+ import ipy_completers
+
+ ip.expose_magic("rep",rep_f)
+ ip.expose_magic("hist",magic_hist)
+ ip.expose_magic("history",magic_history)
+
+ ipy_completers.quick_completer('%hist' ,'-g -t -r -n')
diff --git a/IPython/hooks.py b/IPython/hooks.py
new file mode 100644
index 0000000..6e07079
--- /dev/null
+++ b/IPython/hooks.py
@@ -0,0 +1,264 @@
+"""hooks for IPython.
+
+In Python, it is possible to overwrite any method of any object if you really
+want to. But IPython exposes a few 'hooks', methods which are _designed_ to
+be overwritten by users for customization purposes. This module defines the
+default versions of all such hooks, which get used by IPython if not
+overridden by the user.
+
+hooks are simple functions, but they should be declared with 'self' as their
+first argument, because when activated they are registered into IPython as
+instance methods. The self argument will be the IPython running instance
+itself, so hooks have full access to the entire IPython object.
+
+If you wish to define a new hook and activate it, you need to put the
+necessary code into a python file which can be either imported or execfile()'d
+from within your ipythonrc configuration.
+
+For example, suppose that you have a module called 'myiphooks' in your
+PYTHONPATH, which contains the following definition:
+
+import os
+import IPython.ipapi
+ip = IPython.ipapi.get()
+
+def calljed(self,filename, linenum):
+ "My editor hook calls the jed editor directly."
+ print "Calling my own editor, jed ..."
+ if os.system('jed +%d %s' % (linenum,filename)) != 0:
+ raise ipapi.TryNext()
+
+ip.set_hook('editor', calljed)
+
+You can then enable the functionality by doing 'import myiphooks'
+somewhere in your configuration files or ipython command line.
+"""
+
+#*****************************************************************************
+# Copyright (C) 2005 Fernando Perez. <fperez@colorado.edu>
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#*****************************************************************************
+
+from IPython import ipapi
+
+import os,bisect
+import sys
+from genutils import Term,shell
+from pprint import PrettyPrinter
+
+# List here all the default hooks. For now it's just the editor functions
+# but over time we'll move here all the public API for user-accessible things.
+# vds: >>
+__all__ = ['editor', 'fix_error_editor', 'synchronize_with_editor', 'result_display',
+ 'input_prefilter', 'shutdown_hook', 'late_startup_hook',
+ 'generate_prompt', 'generate_output_prompt','shell_hook',
+ 'show_in_pager','pre_prompt_hook', 'pre_runcode_hook',
+ 'clipboard_get']
+# vds: <<
+
+pformat = PrettyPrinter().pformat
+
+def editor(self,filename, linenum=None):
+ """Open the default editor at the given filename and linenumber.
+
+ This is IPython's default editor hook, you can use it as an example to
+ write your own modified one. To set your own editor function as the
+ new editor hook, call ip.set_hook('editor',yourfunc)."""
+
+ # IPython configures a default editor at startup by reading $EDITOR from
+ # the environment, and falling back on vi (unix) or notepad (win32).
+ editor = self.rc.editor
+
+ # marker for at which line to open the file (for existing objects)
+ if linenum is None or editor=='notepad':
+ linemark = ''
+ else:
+ linemark = '+%d' % int(linenum)
+
+ # Enclose in quotes if necessary and legal
+ if ' ' in editor and os.path.isfile(editor) and editor[0] != '"':
+ editor = '"%s"' % editor
+
+ # Call the actual editor
+ if os.system('%s %s %s' % (editor,linemark,filename)) != 0:
+ raise ipapi.TryNext()
+
+import tempfile
+def fix_error_editor(self,filename,linenum,column,msg):
+ """Open the editor at the given filename, linenumber, column and
+ show an error message. This is used for correcting syntax errors.
+ The current implementation only has special support for the VIM editor,
+ and falls back on the 'editor' hook if VIM is not used.
+
+ Call ip.set_hook('fix_error_editor',youfunc) to use your own function,
+ """
+ def vim_quickfix_file():
+ t = tempfile.NamedTemporaryFile()
+ t.write('%s:%d:%d:%s\n' % (filename,linenum,column,msg))
+ t.flush()
+ return t
+ if os.path.basename(self.rc.editor) != 'vim':
+ self.hooks.editor(filename,linenum)
+ return
+ t = vim_quickfix_file()
+ try:
+ if os.system('vim --cmd "set errorformat=%f:%l:%c:%m" -q ' + t.name):
+ raise ipapi.TryNext()
+ finally:
+ t.close()
+
+# vds: >>
+def synchronize_with_editor(self, filename, linenum, column):
+ pass
+# vds: <<
+
+class CommandChainDispatcher:
+ """ Dispatch calls to a chain of commands until some func can handle it
+
+ Usage: instantiate, execute "add" to add commands (with optional
+ priority), execute normally via f() calling mechanism.
+
+ """
+ def __init__(self,commands=None):
+ if commands is None:
+ self.chain = []
+ else:
+ self.chain = commands
+
+
+ def __call__(self,*args, **kw):
+ """ Command chain is called just like normal func.
+
+ This will call all funcs in chain with the same args as were given to this
+ function, and return the result of first func that didn't raise
+ TryNext """
+
+ for prio,cmd in self.chain:
+ #print "prio",prio,"cmd",cmd #dbg
+ try:
+ ret = cmd(*args, **kw)
+ return ret
+ except ipapi.TryNext, exc:
+ if exc.args or exc.kwargs:
+ args = exc.args
+ kw = exc.kwargs
+ # if no function will accept it, raise TryNext up to the caller
+ raise ipapi.TryNext
+
+ def __str__(self):
+ return str(self.chain)
+
+ def add(self, func, priority=0):
+ """ Add a func to the cmd chain with given priority """
+ bisect.insort(self.chain,(priority,func))
+
+ def __iter__(self):
+ """ Return all objects in chain.
+
+ Handy if the objects are not callable.
+ """
+ return iter(self.chain)
+
+def result_display(self,arg):
+ """ Default display hook.
+
+ Called for displaying the result to the user.
+ """
+
+ if self.rc.pprint:
+ out = pformat(arg)
+ if '\n' in out:
+ # So that multi-line strings line up with the left column of
+ # the screen, instead of having the output prompt mess up
+ # their first line.
+ Term.cout.write('\n')
+ print >>Term.cout, out
+ else:
+ # By default, the interactive prompt uses repr() to display results,
+ # so we should honor this. Users who'd rather use a different
+ # mechanism can easily override this hook.
+ print >>Term.cout, repr(arg)
+ # the default display hook doesn't manipulate the value to put in history
+ return None
+
+def input_prefilter(self,line):
+ """ Default input prefilter
+
+ This returns the line as unchanged, so that the interpreter
+ knows that nothing was done and proceeds with "classic" prefiltering
+ (%magics, !shell commands etc.).
+
+ Note that leading whitespace is not passed to this hook. Prefilter
+ can't alter indentation.
+
+ """
+ #print "attempt to rewrite",line #dbg
+ return line
+
+def shutdown_hook(self):
+ """ default shutdown hook
+
+ Typically, shotdown hooks should raise TryNext so all shutdown ops are done
+ """
+
+ #print "default shutdown hook ok" # dbg
+ return
+
+def late_startup_hook(self):
+ """ Executed after ipython has been constructed and configured
+
+ """
+ #print "default startup hook ok" # dbg
+
+def generate_prompt(self, is_continuation):
+ """ calculate and return a string with the prompt to display """
+ ip = self.api
+ if is_continuation:
+ return str(ip.IP.outputcache.prompt2)
+ return str(ip.IP.outputcache.prompt1)
+
+def generate_output_prompt(self):
+ ip = self.api
+ return str(ip.IP.outputcache.prompt_out)
+
+def shell_hook(self,cmd):
+ """ Run system/shell command a'la os.system() """
+
+ shell(cmd, header=self.rc.system_header, verbose=self.rc.system_verbose)
+
+def show_in_pager(self,s):
+ """ Run a string through pager """
+ # raising TryNext here will use the default paging functionality
+ raise ipapi.TryNext
+
+def pre_prompt_hook(self):
+ """ Run before displaying the next prompt
+
+ Use this e.g. to display output from asynchronous operations (in order
+ to not mess up text entry)
+ """
+
+ return None
+
+def pre_runcode_hook(self):
+ """ Executed before running the (prefiltered) code in IPython """
+ return None
+
+def clipboard_get(self):
+ """ Get text from the clipboard.
+ """
+ from IPython.clipboard import (osx_clipboard_get, tkinter_clipboard_get,
+ win32_clipboard_get)
+ if sys.platform == 'win32':
+ chain = [win32_clipboard_get, tkinter_clipboard_get]
+ elif sys.platform == 'darwin':
+ chain = [osx_clipboard_get, tkinter_clipboard_get]
+ else:
+ chain = [tkinter_clipboard_get]
+ dispatcher = CommandChainDispatcher()
+ for func in chain:
+ dispatcher.add(func)
+ text = dispatcher()
+ return text
diff --git a/IPython/ipapi.py b/IPython/ipapi.py
new file mode 100644
index 0000000..da6bcf4
--- /dev/null
+++ b/IPython/ipapi.py
@@ -0,0 +1,685 @@
+"""IPython customization API
+
+Your one-stop module for configuring & extending ipython
+
+The API will probably break when ipython 1.0 is released, but so
+will the other configuration method (rc files).
+
+All names prefixed by underscores are for internal use, not part
+of the public api.
+
+Below is an example that you can just put to a module and import from ipython.
+
+A good practice is to install the config script below as e.g.
+
+~/.ipython/my_private_conf.py
+
+And do
+
+import_mod my_private_conf
+
+in ~/.ipython/ipythonrc
+
+That way the module is imported at startup and you can have all your
+personal configuration (as opposed to boilerplate ipythonrc-PROFILENAME
+stuff) in there.
+
+import IPython.ipapi
+ip = IPython.ipapi.get()
+
+def ankka_f(self, arg):
+ print 'Ankka',self,'says uppercase:',arg.upper()
+
+ip.expose_magic('ankka',ankka_f)
+
+ip.magic('alias sayhi echo "Testing, hi ok"')
+ip.magic('alias helloworld echo "Hello world"')
+ip.system('pwd')
+
+ip.ex('import re')
+ip.ex('''
+def funcci(a,b):
+ print a+b
+print funcci(3,4)
+''')
+ip.ex('funcci(348,9)')
+
+def jed_editor(self,filename, linenum=None):
+ print 'Calling my own editor, jed ... via hook!'
+ import os
+ if linenum is None: linenum = 0
+ os.system('jed +%d %s' % (linenum, filename))
+ print 'exiting jed'
+
+ip.set_hook('editor',jed_editor)
+
+o = ip.options
+o.autocall = 2 # FULL autocall mode
+
+print 'done!'
+"""
+
+#-----------------------------------------------------------------------------
+# Modules and globals
+
+# stdlib imports
+import __builtin__
+import sys
+
+# contains the most recently instantiated IPApi
+_RECENT_IP = None
+
+#-----------------------------------------------------------------------------
+# Code begins
+
+class TryNext(Exception):
+ """Try next hook exception.
+
+ Raise this in your hook function to indicate that the next hook handler
+ should be used to handle the operation. If you pass arguments to the
+ constructor those arguments will be used by the next hook instead of the
+ original ones.
+ """
+
+ def __init__(self, *args, **kwargs):
+ self.args = args
+ self.kwargs = kwargs
+
+
+class UsageError(Exception):
+ """ Error in magic function arguments, etc.
+
+ Something that probably won't warrant a full traceback, but should
+ nevertheless interrupt a macro / batch file.
+ """
+
+
+class IPyAutocall:
+ """ Instances of this class are always autocalled
+
+ This happens regardless of 'autocall' variable state. Use this to
+ develop macro-like mechanisms.
+ """
+
+ def set_ip(self,ip):
+ """ Will be used to set _ip point to current ipython instance b/f call
+
+ Override this method if you don't want this to happen.
+
+ """
+ self._ip = ip
+
+
+class IPythonNotRunning:
+ """Dummy do-nothing class.
+
+ Instances of this class return a dummy attribute on all accesses, which
+ can be called and warns. This makes it easier to write scripts which use
+ the ipapi.get() object for informational purposes to operate both with and
+ without ipython. Obviously code which uses the ipython object for
+ computations will not work, but this allows a wider range of code to
+ transparently work whether ipython is being used or not."""
+
+ def __init__(self,warn=True):
+ if warn:
+ self.dummy = self._dummy_warn
+ else:
+ self.dummy = self._dummy_silent
+
+ def __str__(self):
+ return "<IPythonNotRunning>"
+
+ __repr__ = __str__
+
+ def __getattr__(self,name):
+ return self.dummy
+
+ def _dummy_warn(self,*args,**kw):
+ """Dummy function, which doesn't do anything but warn."""
+
+ print ("IPython is not running, this is a dummy no-op function")
+
+ def _dummy_silent(self,*args,**kw):
+ """Dummy function, which doesn't do anything and emits no warnings."""
+ pass
+
+
+def get(allow_dummy=False,dummy_warn=True):
+ """Get an IPApi object.
+
+ If allow_dummy is true, returns an instance of IPythonNotRunning
+ instead of None if not running under IPython.
+
+ If dummy_warn is false, the dummy instance will be completely silent.
+
+ Running this should be the first thing you do when writing extensions that
+ can be imported as normal modules. You can then direct all the
+ configuration operations against the returned object.
+ """
+ global _RECENT_IP
+ if allow_dummy and not _RECENT_IP:
+ _RECENT_IP = IPythonNotRunning(dummy_warn)
+ return _RECENT_IP
+
+
+class IPApi(object):
+ """ The actual API class for configuring IPython
+
+ You should do all of the IPython configuration by getting an IPApi object
+ with IPython.ipapi.get() and using the attributes and methods of the
+ returned object."""
+
+ def __init__(self,ip):
+
+ global _RECENT_IP
+
+ # All attributes exposed here are considered to be the public API of
+ # IPython. As needs dictate, some of these may be wrapped as
+ # properties.
+
+ self.magic = ip.ipmagic
+
+ self.system = ip.system
+
+ self.set_hook = ip.set_hook
+
+ self.set_custom_exc = ip.set_custom_exc
+
+ self.user_ns = ip.user_ns
+
+ self.set_crash_handler = ip.set_crash_handler
+
+ # Session-specific data store, which can be used to store
+ # data that should persist through the ipython session.
+ self.meta = ip.meta
+
+ # The ipython instance provided
+ self.IP = ip
+
+ self.extensions = {}
+
+ self.dbg = DebugTools(self)
+
+ _RECENT_IP = self
+
+ # Use a property for some things which are added to the instance very
+ # late. I don't have time right now to disentangle the initialization
+ # order issues, so a property lets us delay item extraction while
+ # providing a normal attribute API.
+ def get_db(self):
+ """A handle to persistent dict-like database (a PickleShareDB object)"""
+ return self.IP.db
+
+ db = property(get_db,None,None,get_db.__doc__)
+
+ def get_options(self):
+ """All configurable variables."""
+
+ # catch typos by disabling new attribute creation. If new attr creation
+ # is in fact wanted (e.g. when exposing new options), do
+ # allow_new_attr(True) for the received rc struct.
+
+ self.IP.rc.allow_new_attr(False)
+ return self.IP.rc
+
+ options = property(get_options,None,None,get_options.__doc__)
+
+ def expose_magic(self,magicname, func):
+ """Expose own function as magic function for ipython
+
+ def foo_impl(self,parameter_s=''):
+ 'My very own magic!. (Use docstrings, IPython reads them).'
+ print 'Magic function. Passed parameter is between < >:'
+ print '<%s>' % parameter_s
+ print 'The self object is:',self
+
+ ipapi.expose_magic('foo',foo_impl)
+ """
+
+ import new
+ im = new.instancemethod(func,self.IP, self.IP.__class__)
+ old = getattr(self.IP, "magic_" + magicname, None)
+ if old:
+ self.dbg.debug_stack("Magic redefinition '%s', old %s" %
+ (magicname,old) )
+
+ setattr(self.IP, "magic_" + magicname, im)
+
+ def ex(self,cmd):
+ """ Execute a normal python statement in user namespace """
+ exec cmd in self.user_ns
+
+ def ev(self,expr):
+ """ Evaluate python expression expr in user namespace
+
+ Returns the result of evaluation"""
+ return eval(expr,self.user_ns)
+
+ def runlines(self,lines):
+ """ Run the specified lines in interpreter, honoring ipython directives.
+
+ This allows %magic and !shell escape notations.
+
+ Takes either all lines in one string or list of lines.
+ """
+
+ def cleanup_ipy_script(script):
+ """ Make a script safe for _ip.runlines()
+
+ - Removes empty lines Suffixes all indented blocks that end with
+ - unindented lines with empty lines
+ """
+
+ res = []
+ lines = script.splitlines()
+
+ level = 0
+ for l in lines:
+ lstripped = l.lstrip()
+ stripped = l.strip()
+ if not stripped:
+ continue
+ newlevel = len(l) - len(lstripped)
+ def is_secondary_block_start(s):
+ if not s.endswith(':'):
+ return False
+ if (s.startswith('elif') or
+ s.startswith('else') or
+ s.startswith('except') or
+ s.startswith('finally')):
+ return True
+
+ if level > 0 and newlevel == 0 and \
+ not is_secondary_block_start(stripped):
+ # add empty line
+ res.append('')
+
+ res.append(l)
+ level = newlevel
+ return '\n'.join(res) + '\n'
+
+ if isinstance(lines,basestring):
+ script = lines
+ else:
+ script = '\n'.join(lines)
+ clean=cleanup_ipy_script(script)
+ # print "_ip.runlines() script:\n",clean # dbg
+ self.IP.runlines(clean)
+
+ def to_user_ns(self,vars, interactive = True):
+ """Inject a group of variables into the IPython user namespace.
+
+ Inputs:
+
+ - vars: string with variable names separated by whitespace, or a
+ dict with name/value pairs.
+
+ - interactive: if True (default), the var will be listed with
+ %whos et. al.
+
+ This utility routine is meant to ease interactive debugging work,
+ where you want to easily propagate some internal variable in your code
+ up to the interactive namespace for further exploration.
+
+ When you run code via %run, globals in your script become visible at
+ the interactive prompt, but this doesn't happen for locals inside your
+ own functions and methods. Yet when debugging, it is common to want
+ to explore some internal variables further at the interactive propmt.
+
+ Examples:
+
+ To use this, you first must obtain a handle on the ipython object as
+ indicated above, via:
+
+ import IPython.ipapi
+ ip = IPython.ipapi.get()
+
+ Once this is done, inside a routine foo() where you want to expose
+ variables x and y, you do the following:
+
+ def foo():
+ ...
+ x = your_computation()
+ y = something_else()
+
+ # This pushes x and y to the interactive prompt immediately, even
+ # if this routine crashes on the next line after:
+ ip.to_user_ns('x y')
+ ...
+
+ # To expose *ALL* the local variables from the function, use:
+ ip.to_user_ns(locals())
+
+ ...
+ # return
+
+
+ If you need to rename variables, the dict input makes it easy. For
+ example, this call exposes variables 'foo' as 'x' and 'bar' as 'y'
+ in IPython user namespace:
+
+ ip.to_user_ns(dict(x=foo,y=bar))
+ """
+
+ # print 'vars given:',vars # dbg
+
+ # We need a dict of name/value pairs to do namespace updates.
+ if isinstance(vars,dict):
+ # If a dict was given, no need to change anything.
+ vdict = vars
+ elif isinstance(vars,basestring):
+ # If a string with names was given, get the caller's frame to
+ # evaluate the given names in
+ cf = sys._getframe(1)
+ vdict = {}
+ for name in vars.split():
+ try:
+ vdict[name] = eval(name,cf.f_globals,cf.f_locals)
+ except:
+ print ('could not get var. %s from %s' %
+ (name,cf.f_code.co_name))
+ else:
+ raise ValueError('vars must be a string or a dict')
+
+ # Propagate variables to user namespace
+ self.user_ns.update(vdict)
+
+ # And configure interactive visibility
+ config_ns = self.IP.user_config_ns
+ if interactive:
+ for name,val in vdict.iteritems():
+ config_ns.pop(name,None)
+ else:
+ for name,val in vdict.iteritems():
+ config_ns[name] = val
+
+ def expand_alias(self,line):
+ """ Expand an alias in the command line
+
+ Returns the provided command line, possibly with the first word
+ (command) translated according to alias expansion rules.
+
+ [ipython]|16> _ip.expand_aliases("np myfile.txt")
+ <16> 'q:/opt/np/notepad++.exe myfile.txt'
+ """
+
+ pre,fn,rest = self.IP.split_user_input(line)
+ res = pre + self.IP.expand_aliases(fn,rest)
+ return res
+
+ def itpl(self, s, depth = 1):
+ """ Expand Itpl format string s.
+
+ Only callable from command line (i.e. prefilter results);
+ If you use in your scripts, you need to use a bigger depth!
+ """
+ return self.IP.var_expand(s, depth)
+
+ def defalias(self, name, cmd):
+ """ Define a new alias
+
+ _ip.defalias('bb','bldmake bldfiles')
+
+ Creates a new alias named 'bb' in ipython user namespace
+ """
+
+ self.dbg.check_hotname(name)
+
+ if name in self.IP.alias_table:
+ self.dbg.debug_stack("Alias redefinition: '%s' => '%s' (old '%s')"
+ % (name, cmd, self.IP.alias_table[name]))
+
+ if callable(cmd):
+ self.IP.alias_table[name] = cmd
+ import IPython.shadowns
+ setattr(IPython.shadowns, name,cmd)
+ return
+
+ if isinstance(cmd,basestring):
+ nargs = cmd.count('%s')
+ if nargs>0 and cmd.find('%l')>=0:
+ raise Exception('The %s and %l specifiers are mutually '
+ 'exclusive in alias definitions.')
+
+ self.IP.alias_table[name] = (nargs,cmd)
+ return
+
+ # just put it in - it's probably (0,'foo')
+ self.IP.alias_table[name] = cmd
+
+ def defmacro(self, *args):
+ """ Define a new macro
+
+ 2 forms of calling:
+
+ mac = _ip.defmacro('print "hello"\nprint "world"')
+
+ (doesn't put the created macro on user namespace)
+
+ _ip.defmacro('build', 'bldmake bldfiles\nabld build winscw udeb')
+
+ (creates a macro named 'build' in user namespace)
+ """
+
+ import IPython.macro
+
+ if len(args) == 1:
+ return IPython.macro.Macro(args[0])
+ elif len(args) == 2:
+ self.user_ns[args[0]] = IPython.macro.Macro(args[1])
+ else:
+ return Exception("_ip.defmacro must be called with 1 or 2 arguments")
+
+ def set_next_input(self, s):
+ """ Sets the 'default' input string for the next command line.
+
+ Requires readline.
+
+ Example:
+
+ [D:\ipython]|1> _ip.set_next_input("Hello Word")
+ [D:\ipython]|2> Hello Word_ # cursor is here
+ """
+
+ self.IP.rl_next_input = s
+
+ def load(self, mod):
+ """ Load an extension.
+
+ Some modules should (or must) be 'load()':ed, rather than just imported.
+
+ Loading will do:
+
+ - run init_ipython(ip)
+ - run ipython_firstrun(ip)
+ """
+
+ if mod in self.extensions:
+ # just to make sure we don't init it twice
+ # note that if you 'load' a module that has already been
+ # imported, init_ipython gets run anyway
+
+ return self.extensions[mod]
+ __import__(mod)
+ m = sys.modules[mod]
+ if hasattr(m,'init_ipython'):
+ m.init_ipython(self)
+
+ if hasattr(m,'ipython_firstrun'):
+ already_loaded = self.db.get('firstrun_done', set())
+ if mod not in already_loaded:
+ m.ipython_firstrun(self)
+ already_loaded.add(mod)
+ self.db['firstrun_done'] = already_loaded
+
+ self.extensions[mod] = m
+ return m
+
+
+class DebugTools:
+ """ Used for debugging mishaps in api usage
+
+ So far, tracing redefinitions is supported.
+ """
+
+ def __init__(self, ip):
+ self.ip = ip
+ self.debugmode = False
+ self.hotnames = set()
+
+ def hotname(self, name_to_catch):
+ self.hotnames.add(name_to_catch)
+
+ def debug_stack(self, msg = None):
+ if not self.debugmode:
+ return
+
+ import traceback
+ if msg is not None:
+ print '====== %s ========' % msg
+ traceback.print_stack()
+
+ def check_hotname(self,name):
+ if name in self.hotnames:
+ self.debug_stack( "HotName '%s' caught" % name)
+
+
+def launch_new_instance(user_ns = None,shellclass = None):
+ """ Make and start a new ipython instance.
+
+ This can be called even without having an already initialized
+ ipython session running.
+
+ This is also used as the egg entry point for the 'ipython' script.
+
+ """
+ ses = make_session(user_ns,shellclass)
+ ses.mainloop()
+
+
+def make_user_ns(user_ns = None):
+ """Return a valid user interactive namespace.
+
+ This builds a dict with the minimal information needed to operate as a
+ valid IPython user namespace, which you can pass to the various embedding
+ classes in ipython.
+
+ This API is currently deprecated. Use ipapi.make_user_namespaces() instead
+ to make both the local and global namespace objects simultaneously.
+
+ :Parameters:
+ user_ns : dict-like, optional
+ The current user namespace. The items in this namespace should be
+ included in the output. If None, an appropriate blank namespace
+ should be created.
+
+ :Returns:
+ A dictionary-like object to be used as the local namespace of the
+ interpreter.
+ """
+
+ raise NotImplementedError
+
+
+def make_user_global_ns(ns = None):
+ """Return a valid user global namespace.
+
+ Similar to make_user_ns(), but global namespaces are really only needed in
+ embedded applications, where there is a distinction between the user's
+ interactive namespace and the global one where ipython is running.
+
+ This API is currently deprecated. Use ipapi.make_user_namespaces() instead
+ to make both the local and global namespace objects simultaneously.
+
+ :Parameters:
+ ns : dict, optional
+ The current user global namespace. The items in this namespace
+ should be included in the output. If None, an appropriate blank
+ namespace should be created.
+
+ :Returns:
+ A true dict to be used as the global namespace of the interpreter.
+ """
+
+ raise NotImplementedError
+
+# Record the true objects in order to be able to test if the user has overridden
+# these API functions.
+_make_user_ns = make_user_ns
+_make_user_global_ns = make_user_global_ns
+
+
+def make_user_namespaces(user_ns = None,user_global_ns = None):
+ """Return a valid local and global user interactive namespaces.
+
+ This builds a dict with the minimal information needed to operate as a
+ valid IPython user namespace, which you can pass to the various embedding
+ classes in ipython. The default implementation returns the same dict for
+ both the locals and the globals to allow functions to refer to variables in
+ the namespace. Customized implementations can return different dicts. The
+ locals dictionary can actually be anything following the basic mapping
+ protocol of a dict, but the globals dict must be a true dict, not even
+ a subclass. It is recommended that any custom object for the locals
+ namespace synchronize with the globals dict somehow.
+
+ Raises TypeError if the provided globals namespace is not a true dict.
+
+ :Parameters:
+ user_ns : dict-like, optional
+ The current user namespace. The items in this namespace should be
+ included in the output. If None, an appropriate blank namespace
+ should be created.
+ user_global_ns : dict, optional
+ The current user global namespace. The items in this namespace
+ should be included in the output. If None, an appropriate blank
+ namespace should be created.
+
+ :Returns:
+ A tuple pair of dictionary-like object to be used as the local namespace
+ of the interpreter and a dict to be used as the global namespace.
+ """
+
+ if user_ns is None:
+ if make_user_ns is not _make_user_ns:
+ # Old API overridden.
+ # FIXME: Issue DeprecationWarning, or just let the old API live on?
+ user_ns = make_user_ns(user_ns)
+ else:
+ # Set __name__ to __main__ to better match the behavior of the
+ # normal interpreter.
+ user_ns = {'__name__' :'__main__',
+ '__builtins__' : __builtin__,
+ }
+ else:
+ user_ns.setdefault('__name__','__main__')
+ user_ns.setdefault('__builtins__',__builtin__)
+
+ if user_global_ns is None:
+ if make_user_global_ns is not _make_user_global_ns:
+ # Old API overridden.
+ user_global_ns = make_user_global_ns(user_global_ns)
+ else:
+ user_global_ns = user_ns
+ if type(user_global_ns) is not dict:
+ raise TypeError("user_global_ns must be a true dict; got %r"
+ % type(user_global_ns))
+
+ return user_ns, user_global_ns
+
+
+def make_session(user_ns = None, shellclass = None):
+ """Makes, but does not launch an IPython session.
+
+ Later on you can call obj.mainloop() on the returned object.
+
+ Inputs:
+
+ - user_ns(None): a dict to be used as the user's namespace with initial
+ data.
+
+ WARNING: This should *not* be run when a session exists already."""
+
+ import IPython.Shell
+ if shellclass is None:
+ return IPython.Shell.start(user_ns)
+ return shellclass(user_ns = user_ns)
diff --git a/IPython/iplib.py b/IPython/iplib.py
new file mode 100644
index 0000000..1bc4cea
--- /dev/null
+++ b/IPython/iplib.py
@@ -0,0 +1,2870 @@
+# -*- coding: utf-8 -*-
+"""
+IPython -- An enhanced Interactive Python
+
+Requires Python 2.4 or newer.
+
+This file contains all the classes and helper functions specific to IPython.
+"""
+
+#*****************************************************************************
+# Copyright (C) 2001 Janko Hauser <jhauser@zscout.de> and
+# Copyright (C) 2001-2006 Fernando Perez. <fperez@colorado.edu>
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#
+# Note: this code originally subclassed code.InteractiveConsole from the
+# Python standard library. Over time, all of that class has been copied
+# verbatim here for modifications which could not be accomplished by
+# subclassing. At this point, there are no dependencies at all on the code
+# module anymore (it is not even imported). The Python License (sec. 2)
+# allows for this, but it's always nice to acknowledge credit where credit is
+# due.
+#*****************************************************************************
+
+#****************************************************************************
+# Modules and globals
+
+# Python standard modules
+import __main__
+import __builtin__
+import StringIO
+import bdb
+import cPickle as pickle
+import codeop
+import exceptions
+import glob
+import inspect
+import keyword
+import new
+import os
+import pydoc
+import re
+import shutil
+import string
+import sys
+import tempfile
+import traceback
+import types
+from pprint import pprint, pformat
+
+# IPython's own modules
+#import IPython
+from IPython import Debugger,OInspect,PyColorize,ultraTB
+from IPython.ColorANSI import ColorScheme,ColorSchemeTable # too long names
+from IPython.Extensions import pickleshare
+from IPython.FakeModule import FakeModule, init_fakemod_dict
+from IPython.Itpl import Itpl,itpl,printpl,ItplNS,itplns
+from IPython.Logger import Logger
+from IPython.Magic import Magic
+from IPython.Prompts import CachedOutput
+from IPython.ipstruct import Struct
+from IPython.background_jobs import BackgroundJobManager
+from IPython.usage import cmd_line_usage,interactive_usage
+from IPython.genutils import *
+from IPython.strdispatch import StrDispatch
+import IPython.ipapi
+import IPython.history
+import IPython.prefilter as prefilter
+import IPython.shadowns
+# Globals
+
+# store the builtin raw_input globally, and use this always, in case user code
+# overwrites it (like wx.py.PyShell does)
+raw_input_original = raw_input
+
+# compiled regexps for autoindent management
+dedent_re = re.compile(r'^\s+raise|^\s+return|^\s+pass')
+
+
+#****************************************************************************
+# Some utility function definitions
+
+ini_spaces_re = re.compile(r'^(\s+)')
+
+def num_ini_spaces(strng):
+ """Return the number of initial spaces in a string"""
+
+ ini_spaces = ini_spaces_re.match(strng)
+ if ini_spaces:
+ return ini_spaces.end()
+ else:
+ return 0
+
+def softspace(file, newvalue):
+ """Copied from code.py, to remove the dependency"""
+
+ oldvalue = 0
+ try:
+ oldvalue = file.softspace
+ except AttributeError:
+ pass
+ try:
+ file.softspace = newvalue
+ except (AttributeError, TypeError):
+ # "attribute-less object" or "read-only attributes"
+ pass
+ return oldvalue
+
+
+def user_setup(ipythondir,rc_suffix,mode='install',interactive=True):
+ """Install or upgrade the user configuration directory.
+
+ Can be called when running for the first time or to upgrade the user's
+ .ipython/ directory.
+
+ Parameters
+ ----------
+ ipythondir : path
+ The directory to be used for installation/upgrade. In 'install' mode,
+ if this path already exists, the function exits immediately.
+
+ rc_suffix : str
+ Extension for the config files. On *nix platforms it is typically the
+ empty string, while Windows normally uses '.ini'.
+
+ mode : str, optional
+ Valid modes are 'install' and 'upgrade'.
+
+ interactive : bool, optional
+ If False, do not wait for user input on any errors. Normally after
+ printing its status information, this function waits for the user to
+ hit Return before proceeding. This is because the default use case is
+ when first installing the IPython configuration, so we want the user to
+ acknowledge the initial message, which contains some useful
+ information.
+ """
+
+ # For automatic use, deactivate all i/o
+ if interactive:
+ def wait():
+ try:
+ raw_input("Please press <RETURN> to start IPython.")
+ except EOFError:
+ print >> Term.cout
+ print '*'*70
+
+ def printf(s):
+ print s
+ else:
+ wait = lambda : None
+ printf = lambda s : None
+
+ # Install mode should be re-entrant: if the install dir already exists,
+ # bail out cleanly.
+ # XXX. This is too hasty to return. We need to check to make sure that
+ # all the expected config files and directories are actually there. We
+ # currently have a failure mode if someone deletes a needed config file
+ # but still has the ipythondir.
+ if mode == 'install' and os.path.isdir(ipythondir):
+ return
+
+ cwd = os.getcwd() # remember where we started
+ glb = glob.glob
+
+ printf('*'*70)
+ if mode == 'install':
+ printf(
+"""Welcome to IPython. I will try to create a personal configuration directory
+where you can customize many aspects of IPython's functionality in:\n""")
+ else:
+ printf('I am going to upgrade your configuration in:')
+
+ printf(ipythondir)
+
+ rcdirend = os.path.join('IPython','UserConfig')
+ cfg = lambda d: os.path.join(d,rcdirend)
+ try:
+ rcdir = filter(os.path.isdir,map(cfg,sys.path))[0]
+ printf("Initializing from configuration: %s" % rcdir)
+ except IndexError:
+ warning = """
+Installation error. IPython's directory was not found.
+
+Check the following:
+
+The ipython/IPython directory should be in a directory belonging to your
+PYTHONPATH environment variable (that is, it should be in a directory
+belonging to sys.path). You can copy it explicitly there or just link to it.
+
+IPython will create a minimal default configuration for you.
+
+"""
+ warn(warning)
+ wait()
+
+ if sys.platform =='win32':
+ inif = 'ipythonrc.ini'
+ else:
+ inif = 'ipythonrc'
+ minimal_setup = {'ipy_user_conf.py' : 'import ipy_defaults',
+ inif : '# intentionally left blank' }
+ os.makedirs(ipythondir, mode = 0777)
+ for f, cont in minimal_setup.items():
+ # In 2.5, this can be more cleanly done using 'with'
+ fobj = file(ipythondir + '/' + f,'w')
+ fobj.write(cont)
+ fobj.close()
+
+ return
+
+ if mode == 'install':
+ try:
+ shutil.copytree(rcdir,ipythondir)
+ os.chdir(ipythondir)
+ rc_files = glb("ipythonrc*")
+ for rc_file in rc_files:
+ os.rename(rc_file,rc_file+rc_suffix)
+ except:
+ warning = """
+
+There was a problem with the installation:
+%s
+Try to correct it or contact the developers if you think it's a bug.
+IPython will proceed with builtin defaults.""" % sys.exc_info()[1]
+ warn(warning)
+ wait()
+ return
+
+ elif mode == 'upgrade':
+ try:
+ os.chdir(ipythondir)
+ except:
+ printf("""
+Can not upgrade: changing to directory %s failed. Details:
+%s
+""" % (ipythondir,sys.exc_info()[1]) )
+ wait()
+ return
+ else:
+ sources = glb(os.path.join(rcdir,'[A-Za-z]*'))
+ for new_full_path in sources:
+ new_filename = os.path.basename(new_full_path)
+ if new_filename.startswith('ipythonrc'):
+ new_filename = new_filename + rc_suffix
+ # The config directory should only contain files, skip any
+ # directories which may be there (like CVS)
+ if os.path.isdir(new_full_path):
+ continue
+ if os.path.exists(new_filename):
+ old_file = new_filename+'.old'
+ if os.path.exists(old_file):
+ os.remove(old_file)
+ os.rename(new_filename,old_file)
+ shutil.copy(new_full_path,new_filename)
+ else:
+ raise ValueError('unrecognized mode for install: %r' % mode)
+
+ # Fix line-endings to those native to each platform in the config
+ # directory.
+ try:
+ os.chdir(ipythondir)
+ except:
+ printf("""
+Problem: changing to directory %s failed.
+Details:
+%s
+
+Some configuration files may have incorrect line endings. This should not
+cause any problems during execution. """ % (ipythondir,sys.exc_info()[1]) )
+ wait()
+ else:
+ for fname in glb('ipythonrc*'):
+ try:
+ native_line_ends(fname,backup=0)
+ except IOError:
+ pass
+
+ if mode == 'install':
+ printf("""
+Successful installation!
+
+Please read the sections 'Initial Configuration' and 'Quick Tips' in the
+IPython manual (there are both HTML and PDF versions supplied with the
+distribution) to make sure that your system environment is properly configured
+to take advantage of IPython's features.
+
+Important note: the configuration system has changed! The old system is
+still in place, but its setting may be partly overridden by the settings in
+"~/.ipython/ipy_user_conf.py" config file. Please take a look at the file
+if some of the new settings bother you.
+
+""")
+ else:
+ printf("""
+Successful upgrade!
+
+All files in your directory:
+%(ipythondir)s
+which would have been overwritten by the upgrade were backed up with a .old
+extension. If you had made particular customizations in those files you may
+want to merge them back into the new files.""" % locals() )
+ wait()
+ os.chdir(cwd)
+
+#****************************************************************************
+# Local use exceptions
+class SpaceInInput(exceptions.Exception): pass
+
+
+#****************************************************************************
+# Local use classes
+class Bunch: pass
+
+class Undefined: pass
+
+class Quitter(object):
+ """Simple class to handle exit, similar to Python 2.5's.
+
+ It handles exiting in an ipython-safe manner, which the one in Python 2.5
+ doesn't do (obviously, since it doesn't know about ipython)."""
+
+ def __init__(self,shell,name):
+ self.shell = shell
+ self.name = name
+
+ def __repr__(self):
+ return 'Type %s() to exit.' % self.name
+ __str__ = __repr__
+
+ def __call__(self):
+ self.shell.exit()
+
+class InputList(list):
+ """Class to store user input.
+
+ It's basically a list, but slices return a string instead of a list, thus
+ allowing things like (assuming 'In' is an instance):
+
+ exec In[4:7]
+
+ or
+
+ exec In[5:9] + In[14] + In[21:25]"""
+
+ def __getslice__(self,i,j):
+ return ''.join(list.__getslice__(self,i,j))
+
+class SyntaxTB(ultraTB.ListTB):
+ """Extension which holds some state: the last exception value"""
+
+ def __init__(self,color_scheme = 'NoColor'):
+ ultraTB.ListTB.__init__(self,color_scheme)
+ self.last_syntax_error = None
+
+ def __call__(self, etype, value, elist):
+ self.last_syntax_error = value
+ ultraTB.ListTB.__call__(self,etype,value,elist)
+
+ def clear_err_state(self):
+ """Return the current error state and clear it"""
+ e = self.last_syntax_error
+ self.last_syntax_error = None
+ return e
+
+#****************************************************************************
+# Main IPython class
+
+# FIXME: the Magic class is a mixin for now, and will unfortunately remain so
+# until a full rewrite is made. I've cleaned all cross-class uses of
+# attributes and methods, but too much user code out there relies on the
+# equlity %foo == __IP.magic_foo, so I can't actually remove the mixin usage.
+#
+# But at least now, all the pieces have been separated and we could, in
+# principle, stop using the mixin. This will ease the transition to the
+# chainsaw branch.
+
+# For reference, the following is the list of 'self.foo' uses in the Magic
+# class as of 2005-12-28. These are names we CAN'T use in the main ipython
+# class, to prevent clashes.
+
+# ['self.__class__', 'self.__dict__', 'self._inspect', 'self._ofind',
+# 'self.arg_err', 'self.extract_input', 'self.format_', 'self.lsmagic',
+# 'self.magic_', 'self.options_table', 'self.parse', 'self.shell',
+# 'self.value']
+
+class InteractiveShell(object,Magic):
+ """An enhanced console for Python."""
+
+ # class attribute to indicate whether the class supports threads or not.
+ # Subclasses with thread support should override this as needed.
+ isthreaded = False
+
+ def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
+ user_ns=None,user_global_ns=None,banner2='',
+ custom_exceptions=((),None),embedded=False):
+
+ # log system
+ self.logger = Logger(self,logfname='ipython_log.py',logmode='rotate')
+
+ # Job manager (for jobs run as background threads)
+ self.jobs = BackgroundJobManager()
+
+ # Store the actual shell's name
+ self.name = name
+ self.more = False
+
+ # We need to know whether the instance is meant for embedding, since
+ # global/local namespaces need to be handled differently in that case
+ self.embedded = embedded
+ if embedded:
+ # Control variable so users can, from within the embedded instance,
+ # permanently deactivate it.
+ self.embedded_active = True
+
+ # command compiler
+ self.compile = codeop.CommandCompiler()
+
+ # User input buffer
+ self.buffer = []
+
+ # Default name given in compilation of code
+ self.filename = '<ipython console>'
+
+ # Install our own quitter instead of the builtins. For python2.3-2.4,
+ # this brings in behavior like 2.5, and for 2.5 it's identical.
+ __builtin__.exit = Quitter(self,'exit')
+ __builtin__.quit = Quitter(self,'quit')
+
+ # Make an empty namespace, which extension writers can rely on both
+ # existing and NEVER being used by ipython itself. This gives them a
+ # convenient location for storing additional information and state
+ # their extensions may require, without fear of collisions with other
+ # ipython names that may develop later.
+ self.meta = Struct()
+
+ # Create the namespace where the user will operate. user_ns is
+ # normally the only one used, and it is passed to the exec calls as
+ # the locals argument. But we do carry a user_global_ns namespace
+ # given as the exec 'globals' argument, This is useful in embedding
+ # situations where the ipython shell opens in a context where the
+ # distinction between locals and globals is meaningful. For
+ # non-embedded contexts, it is just the same object as the user_ns dict.
+
+ # FIXME. For some strange reason, __builtins__ is showing up at user
+ # level as a dict instead of a module. This is a manual fix, but I
+ # should really track down where the problem is coming from. Alex
+ # Schmolck reported this problem first.
+
+ # A useful post by Alex Martelli on this topic:
+ # Re: inconsistent value from __builtins__
+ # Von: Alex Martelli <aleaxit@yahoo.com>
+ # Datum: Freitag 01 Oktober 2004 04:45:34 nachmittags/abends
+ # Gruppen: comp.lang.python
+
+ # Michael Hohn <hohn@hooknose.lbl.gov> wrote:
+ # > >>> print type(builtin_check.get_global_binding('__builtins__'))
+ # > <type 'dict'>
+ # > >>> print type(__builtins__)
+ # > <type 'module'>
+ # > Is this difference in return value intentional?
+
+ # Well, it's documented that '__builtins__' can be either a dictionary
+ # or a module, and it's been that way for a long time. Whether it's
+ # intentional (or sensible), I don't know. In any case, the idea is
+ # that if you need to access the built-in namespace directly, you
+ # should start with "import __builtin__" (note, no 's') which will
+ # definitely give you a module. Yeah, it's somewhat confusing:-(.
+
+ # These routines return properly built dicts as needed by the rest of
+ # the code, and can also be used by extension writers to generate
+ # properly initialized namespaces.
+ user_ns, user_global_ns = IPython.ipapi.make_user_namespaces(user_ns,
+ user_global_ns)
+
+ # Assign namespaces
+ # This is the namespace where all normal user variables live
+ self.user_ns = user_ns
+ self.user_global_ns = user_global_ns
+
+ # An auxiliary namespace that checks what parts of the user_ns were
+ # loaded at startup, so we can list later only variables defined in
+ # actual interactive use. Since it is always a subset of user_ns, it
+ # doesn't need to be seaparately tracked in the ns_table
+ self.user_config_ns = {}
+
+ # A namespace to keep track of internal data structures to prevent
+ # them from cluttering user-visible stuff. Will be updated later
+ self.internal_ns = {}
+
+ # Namespace of system aliases. Each entry in the alias
+ # table must be a 2-tuple of the form (N,name), where N is the number
+ # of positional arguments of the alias.
+ self.alias_table = {}
+
+ # Now that FakeModule produces a real module, we've run into a nasty
+ # problem: after script execution (via %run), the module where the user
+ # code ran is deleted. Now that this object is a true module (needed
+ # so docetst and other tools work correctly), the Python module
+ # teardown mechanism runs over it, and sets to None every variable
+ # present in that module. Top-level references to objects from the
+ # script survive, because the user_ns is updated with them. However,
+ # calling functions defined in the script that use other things from
+ # the script will fail, because the function's closure had references
+ # to the original objects, which are now all None. So we must protect
+ # these modules from deletion by keeping a cache.
+ #
+ # To avoid keeping stale modules around (we only need the one from the
+ # last run), we use a dict keyed with the full path to the script, so
+ # only the last version of the module is held in the cache. Note,
+ # however, that we must cache the module *namespace contents* (their
+ # __dict__). Because if we try to cache the actual modules, old ones
+ # (uncached) could be destroyed while still holding references (such as
+ # those held by GUI objects that tend to be long-lived)>
+ #
+ # The %reset command will flush this cache. See the cache_main_mod()
+ # and clear_main_mod_cache() methods for details on use.
+
+ # This is the cache used for 'main' namespaces
+ self._main_ns_cache = {}
+ # And this is the single instance of FakeModule whose __dict__ we keep
+ # copying and clearing for reuse on each %run
+ self._user_main_module = FakeModule()
+
+ # A table holding all the namespaces IPython deals with, so that
+ # introspection facilities can search easily.
+ self.ns_table = {'user':user_ns,
+ 'user_global':user_global_ns,
+ 'alias':self.alias_table,
+ 'internal':self.internal_ns,
+ 'builtin':__builtin__.__dict__
+ }
+
+ # Similarly, track all namespaces where references can be held and that
+ # we can safely clear (so it can NOT include builtin). This one can be
+ # a simple list.
+ self.ns_refs_table = [ user_ns, user_global_ns, self.user_config_ns,
+ self.alias_table, self.internal_ns,
+ self._main_ns_cache ]
+
+ # We need to insert into sys.modules something that looks like a
+ # module but which accesses the IPython namespace, for shelve and
+ # pickle to work interactively. Normally they rely on getting
+ # everything out of __main__, but for embedding purposes each IPython
+ # instance has its own private namespace, so we can't go shoving
+ # everything into __main__.
+
+ # note, however, that we should only do this for non-embedded
+ # ipythons, which really mimic the __main__.__dict__ with their own
+ # namespace. Embedded instances, on the other hand, should not do
+ # this because they need to manage the user local/global namespaces
+ # only, but they live within a 'normal' __main__ (meaning, they
+ # shouldn't overtake the execution environment of the script they're
+ # embedded in).
+
+ if not embedded:
+ try:
+ main_name = self.user_ns['__name__']
+ except KeyError:
+ raise KeyError,'user_ns dictionary MUST have a "__name__" key'
+ else:
+ #print "pickle hack in place" # dbg
+ #print 'main_name:',main_name # dbg
+ sys.modules[main_name] = FakeModule(self.user_ns)
+
+ # List of input with multi-line handling.
+ self.input_hist = InputList()
+ # This one will hold the 'raw' input history, without any
+ # pre-processing. This will allow users to retrieve the input just as
+ # it was exactly typed in by the user, with %hist -r.
+ self.input_hist_raw = InputList()
+
+ # list of visited directories
+ try:
+ self.dir_hist = [os.getcwd()]
+ except OSError:
+ self.dir_hist = []
+
+ # dict of output history
+ self.output_hist = {}
+
+ # Get system encoding at startup time. Certain terminals (like Emacs
+ # under Win32 have it set to None, and we need to have a known valid
+ # encoding to use in the raw_input() method
+ try:
+ self.stdin_encoding = sys.stdin.encoding or 'ascii'
+ except AttributeError:
+ self.stdin_encoding = 'ascii'
+
+ # dict of things NOT to alias (keywords, builtins and some magics)
+ no_alias = {}
+ no_alias_magics = ['cd','popd','pushd','dhist','alias','unalias']
+ for key in keyword.kwlist + no_alias_magics:
+ no_alias[key] = 1
+ no_alias.update(__builtin__.__dict__)
+ self.no_alias = no_alias
+
+ # Object variable to store code object waiting execution. This is
+ # used mainly by the multithreaded shells, but it can come in handy in
+ # other situations. No need to use a Queue here, since it's a single
+ # item which gets cleared once run.
+ self.code_to_run = None
+
+ # escapes for automatic behavior on the command line
+ self.ESC_SHELL = '!'
+ self.ESC_SH_CAP = '!!'
+ self.ESC_HELP = '?'
+ self.ESC_MAGIC = '%'
+ self.ESC_QUOTE = ','
+ self.ESC_QUOTE2 = ';'
+ self.ESC_PAREN = '/'
+
+ # And their associated handlers
+ self.esc_handlers = {self.ESC_PAREN : self.handle_auto,
+ self.ESC_QUOTE : self.handle_auto,
+ self.ESC_QUOTE2 : self.handle_auto,
+ self.ESC_MAGIC : self.handle_magic,
+ self.ESC_HELP : self.handle_help,
+ self.ESC_SHELL : self.handle_shell_escape,
+ self.ESC_SH_CAP : self.handle_shell_escape,
+ }
+
+ # class initializations
+ Magic.__init__(self,self)
+
+ # Python source parser/formatter for syntax highlighting
+ pyformat = PyColorize.Parser().format
+ self.pycolorize = lambda src: pyformat(src,'str',self.rc['colors'])
+
+ # hooks holds pointers used for user-side customizations
+ self.hooks = Struct()
+
+ self.strdispatchers = {}
+
+ # Set all default hooks, defined in the IPython.hooks module.
+ hooks = IPython.hooks
+ for hook_name in hooks.__all__:
+ # default hooks have priority 100, i.e. low; user hooks should have
+ # 0-100 priority
+ self.set_hook(hook_name,getattr(hooks,hook_name), 100)
+ #print "bound hook",hook_name
+
+ # Flag to mark unconditional exit
+ self.exit_now = False
+
+ self.usage_min = """\
+ An enhanced console for Python.
+ Some of its features are:
+ - Readline support if the readline library is present.
+ - Tab completion in the local namespace.
+ - Logging of input, see command-line options.
+ - System shell escape via ! , eg !ls.
+ - Magic commands, starting with a % (like %ls, %pwd, %cd, etc.)
+ - Keeps track of locally defined variables via %who, %whos.
+ - Show object information with a ? eg ?x or x? (use ?? for more info).
+ """
+ if usage: self.usage = usage
+ else: self.usage = self.usage_min
+
+ # Storage
+ self.rc = rc # This will hold all configuration information
+ self.pager = 'less'
+ # temporary files used for various purposes. Deleted at exit.
+ self.tempfiles = []
+
+ # Keep track of readline usage (later set by init_readline)
+ self.has_readline = False
+
+ # template for logfile headers. It gets resolved at runtime by the
+ # logstart method.
+ self.loghead_tpl = \
+"""#log# Automatic Logger file. *** THIS MUST BE THE FIRST LINE ***
+#log# DO NOT CHANGE THIS LINE OR THE TWO BELOW
+#log# opts = %s
+#log# args = %s
+#log# It is safe to make manual edits below here.
+#log#-----------------------------------------------------------------------
+"""
+ # for pushd/popd management
+ try:
+ self.home_dir = get_home_dir()
+ except HomeDirError,msg:
+ fatal(msg)
+
+ self.dir_stack = []
+
+ # Functions to call the underlying shell.
+
+ # The first is similar to os.system, but it doesn't return a value,
+ # and it allows interpolation of variables in the user's namespace.
+ self.system = lambda cmd: \
+ self.hooks.shell_hook(self.var_expand(cmd,depth=2))
+
+ # These are for getoutput and getoutputerror:
+ self.getoutput = lambda cmd: \
+ getoutput(self.var_expand(cmd,depth=2),
+ header=self.rc.system_header,
+ verbose=self.rc.system_verbose)
+
+ self.getoutputerror = lambda cmd: \
+ getoutputerror(self.var_expand(cmd,depth=2),
+ header=self.rc.system_header,
+ verbose=self.rc.system_verbose)
+
+
+ # keep track of where we started running (mainly for crash post-mortem)
+ self.starting_dir = os.getcwd()
+
+ # Various switches which can be set
+ self.CACHELENGTH = 5000 # this is cheap, it's just text
+ self.BANNER = "Python %(version)s on %(platform)s\n" % sys.__dict__
+ self.banner2 = banner2
+
+ # TraceBack handlers:
+
+ # Syntax error handler.
+ self.SyntaxTB = SyntaxTB(color_scheme='NoColor')
+
+ # The interactive one is initialized with an offset, meaning we always
+ # want to remove the topmost item in the traceback, which is our own
+ # internal code. Valid modes: ['Plain','Context','Verbose']
+ self.InteractiveTB = ultraTB.AutoFormattedTB(mode = 'Plain',
+ color_scheme='NoColor',
+ tb_offset = 1)
+
+ # IPython itself shouldn't crash. This will produce a detailed
+ # post-mortem if it does. But we only install the crash handler for
+ # non-threaded shells, the threaded ones use a normal verbose reporter
+ # and lose the crash handler. This is because exceptions in the main
+ # thread (such as in GUI code) propagate directly to sys.excepthook,
+ # and there's no point in printing crash dumps for every user exception.
+ if self.isthreaded:
+ ipCrashHandler = ultraTB.FormattedTB()
+ else:
+ from IPython import CrashHandler
+ ipCrashHandler = CrashHandler.IPythonCrashHandler(self)
+ self.set_crash_handler(ipCrashHandler)
+
+ # and add any custom exception handlers the user may have specified
+ self.set_custom_exc(*custom_exceptions)
+
+ # indentation management
+ self.autoindent = False
+ self.indent_current_nsp = 0
+
+ # Make some aliases automatically
+ # Prepare list of shell aliases to auto-define
+ if os.name == 'posix':
+ auto_alias = ('mkdir mkdir', 'rmdir rmdir',
+ 'mv mv -i','rm rm -i','cp cp -i',
+ 'cat cat','less less','clear clear',
+ # a better ls
+ 'ls ls -F',
+ # long ls
+ 'll ls -lF')
+ # Extra ls aliases with color, which need special treatment on BSD
+ # variants
+ ls_extra = ( # color ls
+ 'lc ls -F -o --color',
+ # ls normal files only
+ 'lf ls -F -o --color %l | grep ^-',
+ # ls symbolic links
+ 'lk ls -F -o --color %l | grep ^l',
+ # directories or links to directories,
+ 'ldir ls -F -o --color %l | grep /$',
+ # things which are executable
+ 'lx ls -F -o --color %l | grep ^-..x',
+ )
+ # The BSDs don't ship GNU ls, so they don't understand the
+ # --color switch out of the box
+ if 'bsd' in sys.platform:
+ ls_extra = ( # ls normal files only
+ 'lf ls -lF | grep ^-',
+ # ls symbolic links
+ 'lk ls -lF | grep ^l',
+ # directories or links to directories,
+ 'ldir ls -lF | grep /$',
+ # things which are executable
+ 'lx ls -lF | grep ^-..x',
+ )
+ auto_alias = auto_alias + ls_extra
+ elif os.name in ['nt','dos']:
+ auto_alias = ('ls dir /on',
+ 'ddir dir /ad /on', 'ldir dir /ad /on',
+ 'mkdir mkdir','rmdir rmdir','echo echo',
+ 'ren ren','cls cls','copy copy')
+ else:
+ auto_alias = ()
+ self.auto_alias = [s.split(None,1) for s in auto_alias]
+
+ # Produce a public API instance
+ self.api = IPython.ipapi.IPApi(self)
+
+ # Initialize all user-visible namespaces
+ self.init_namespaces()
+
+ # Call the actual (public) initializer
+ self.init_auto_alias()
+
+ # track which builtins we add, so we can clean up later
+ self.builtins_added = {}
+ # This method will add the necessary builtins for operation, but
+ # tracking what it did via the builtins_added dict.
+
+ #TODO: remove this, redundant
+ self.add_builtins()
+ # end __init__
+
+ def var_expand(self,cmd,depth=0):
+ """Expand python variables in a string.
+
+ The depth argument indicates how many frames above the caller should
+ be walked to look for the local namespace where to expand variables.
+
+ The global namespace for expansion is always the user's interactive
+ namespace.
+ """
+
+ return str(ItplNS(cmd,
+ self.user_ns, # globals
+ # Skip our own frame in searching for locals:
+ sys._getframe(depth+1).f_locals # locals
+ ))
+
+ def pre_config_initialization(self):
+ """Pre-configuration init method
+
+ This is called before the configuration files are processed to
+ prepare the services the config files might need.
+
+ self.rc already has reasonable default values at this point.
+ """
+ rc = self.rc
+ try:
+ self.db = pickleshare.PickleShareDB(rc.ipythondir + "/db")
+ except exceptions.UnicodeDecodeError:
+ print "Your ipythondir can't be decoded to unicode!"
+ print "Please set HOME environment variable to something that"
+ print r"only has ASCII characters, e.g. c:\home"
+ print "Now it is",rc.ipythondir
+ sys.exit()
+ self.shadowhist = IPython.history.ShadowHist(self.db)
+
+ def post_config_initialization(self):
+ """Post configuration init method
+
+ This is called after the configuration files have been processed to
+ 'finalize' the initialization."""
+
+ rc = self.rc
+
+ # Object inspector
+ self.inspector = OInspect.Inspector(OInspect.InspectColors,
+ PyColorize.ANSICodeColors,
+ 'NoColor',
+ rc.object_info_string_level)
+
+ self.rl_next_input = None
+ self.rl_do_indent = False
+ # Load readline proper
+ if rc.readline:
+ self.init_readline()
+
+ # local shortcut, this is used a LOT
+ self.log = self.logger.log
+
+ # Initialize cache, set in/out prompts and printing system
+ self.outputcache = CachedOutput(self,
+ rc.cache_size,
+ rc.pprint,
+ input_sep = rc.separate_in,
+ output_sep = rc.separate_out,
+ output_sep2 = rc.separate_out2,
+ ps1 = rc.prompt_in1,
+ ps2 = rc.prompt_in2,
+ ps_out = rc.prompt_out,
+ pad_left = rc.prompts_pad_left)
+
+ # user may have over-ridden the default print hook:
+ try:
+ self.outputcache.__class__.display = self.hooks.display
+ except AttributeError:
+ pass
+
+ # I don't like assigning globally to sys, because it means when
+ # embedding instances, each embedded instance overrides the previous
+ # choice. But sys.displayhook seems to be called internally by exec,
+ # so I don't see a way around it. We first save the original and then
+ # overwrite it.
+ self.sys_displayhook = sys.displayhook
+ sys.displayhook = self.outputcache
+
+ # Do a proper resetting of doctest, including the necessary displayhook
+ # monkeypatching
+ try:
+ doctest_reload()
+ except ImportError:
+ warn("doctest module does not exist.")
+
+ # Set user colors (don't do it in the constructor above so that it
+ # doesn't crash if colors option is invalid)
+ self.magic_colors(rc.colors)
+
+ # Set calling of pdb on exceptions
+ self.call_pdb = rc.pdb
+
+ # Load user aliases
+ for alias in rc.alias:
+ self.magic_alias(alias)
+
+ self.hooks.late_startup_hook()
+
+ for cmd in self.rc.autoexec:
+ #print "autoexec>",cmd #dbg
+ self.api.runlines(cmd)
+
+ batchrun = False
+ for batchfile in [path(arg) for arg in self.rc.args
+ if arg.lower().endswith('.ipy')]:
+ if not batchfile.isfile():
+ print "No such batch file:", batchfile
+ continue
+ self.api.runlines(batchfile.text())
+ batchrun = True
+ # without -i option, exit after running the batch file
+ if batchrun and not self.rc.interact:
+ self.ask_exit()
+
+ def init_namespaces(self):
+ """Initialize all user-visible namespaces to their minimum defaults.
+
+ Certain history lists are also initialized here, as they effectively
+ act as user namespaces.
+
+ Notes
+ -----
+ All data structures here are only filled in, they are NOT reset by this
+ method. If they were not empty before, data will simply be added to
+ therm.
+ """
+ # The user namespace MUST have a pointer to the shell itself.
+ self.user_ns[self.name] = self
+
+ # Store the public api instance
+ self.user_ns['_ip'] = self.api
+
+ # make global variables for user access to the histories
+ self.user_ns['_ih'] = self.input_hist
+ self.user_ns['_oh'] = self.output_hist
+ self.user_ns['_dh'] = self.dir_hist
+
+ # user aliases to input and output histories
+ self.user_ns['In'] = self.input_hist
+ self.user_ns['Out'] = self.output_hist
+
+ self.user_ns['_sh'] = IPython.shadowns
+
+ # Fill the history zero entry, user counter starts at 1
+ self.input_hist.append('\n')
+ self.input_hist_raw.append('\n')
+
+ def add_builtins(self):
+ """Store ipython references into the builtin namespace.
+
+ Some parts of ipython operate via builtins injected here, which hold a
+ reference to IPython itself."""
+
+ # TODO: deprecate all of these, they are unsafe
+ builtins_new = dict(__IPYTHON__ = self,
+ ip_set_hook = self.set_hook,
+ jobs = self.jobs,
+ ipmagic = wrap_deprecated(self.ipmagic,'_ip.magic()'),
+ ipalias = wrap_deprecated(self.ipalias),
+ ipsystem = wrap_deprecated(self.ipsystem,'_ip.system()'),
+ #_ip = self.api
+ )
+ for biname,bival in builtins_new.items():
+ try:
+ # store the orignal value so we can restore it
+ self.builtins_added[biname] = __builtin__.__dict__[biname]
+ except KeyError:
+ # or mark that it wasn't defined, and we'll just delete it at
+ # cleanup
+ self.builtins_added[biname] = Undefined
+ __builtin__.__dict__[biname] = bival
+
+ # Keep in the builtins a flag for when IPython is active. We set it
+ # with setdefault so that multiple nested IPythons don't clobber one
+ # another. Each will increase its value by one upon being activated,
+ # which also gives us a way to determine the nesting level.
+ __builtin__.__dict__.setdefault('__IPYTHON__active',0)
+
+ def clean_builtins(self):
+ """Remove any builtins which might have been added by add_builtins, or
+ restore overwritten ones to their previous values."""
+ for biname,bival in self.builtins_added.items():
+ if bival is Undefined:
+ del __builtin__.__dict__[biname]
+ else:
+ __builtin__.__dict__[biname] = bival
+ self.builtins_added.clear()
+
+ def set_hook(self,name,hook, priority = 50, str_key = None, re_key = None):
+ """set_hook(name,hook) -> sets an internal IPython hook.
+
+ IPython exposes some of its internal API as user-modifiable hooks. By
+ adding your function to one of these hooks, you can modify IPython's
+ behavior to call at runtime your own routines."""
+
+ # At some point in the future, this should validate the hook before it
+ # accepts it. Probably at least check that the hook takes the number
+ # of args it's supposed to.
+
+ f = new.instancemethod(hook,self,self.__class__)
+
+ # check if the hook is for strdispatcher first
+ if str_key is not None:
+ sdp = self.strdispatchers.get(name, StrDispatch())
+ sdp.add_s(str_key, f, priority )
+ self.strdispatchers[name] = sdp
+ return
+ if re_key is not None:
+ sdp = self.strdispatchers.get(name, StrDispatch())
+ sdp.add_re(re.compile(re_key), f, priority )
+ self.strdispatchers[name] = sdp
+ return
+
+ dp = getattr(self.hooks, name, None)
+ if name not in IPython.hooks.__all__:
+ print "Warning! Hook '%s' is not one of %s" % (name, IPython.hooks.__all__ )
+ if not dp:
+ dp = IPython.hooks.CommandChainDispatcher()
+
+ try:
+ dp.add(f,priority)
+ except AttributeError:
+ # it was not commandchain, plain old func - replace
+ dp = f
+
+ setattr(self.hooks,name, dp)
+
+
+ #setattr(self.hooks,name,new.instancemethod(hook,self,self.__class__))
+
+ def set_crash_handler(self,crashHandler):
+ """Set the IPython crash handler.
+
+ This must be a callable with a signature suitable for use as
+ sys.excepthook."""
+
+ # Install the given crash handler as the Python exception hook
+ sys.excepthook = crashHandler
+
+ # The instance will store a pointer to this, so that runtime code
+ # (such as magics) can access it. This is because during the
+ # read-eval loop, it gets temporarily overwritten (to deal with GUI
+ # frameworks).
+ self.sys_excepthook = sys.excepthook
+
+
+ def set_custom_exc(self,exc_tuple,handler):
+ """set_custom_exc(exc_tuple,handler)
+
+ Set a custom exception handler, which will be called if any of the
+ exceptions in exc_tuple occur in the mainloop (specifically, in the
+ runcode() method.
+
+ Inputs:
+
+ - exc_tuple: a *tuple* of valid exceptions to call the defined
+ handler for. It is very important that you use a tuple, and NOT A
+ LIST here, because of the way Python's except statement works. If
+ you only want to trap a single exception, use a singleton tuple:
+
+ exc_tuple == (MyCustomException,)
+
+ - handler: this must be defined as a function with the following
+ basic interface: def my_handler(self,etype,value,tb).
+
+ This will be made into an instance method (via new.instancemethod)
+ of IPython itself, and it will be called if any of the exceptions
+ listed in the exc_tuple are caught. If the handler is None, an
+ internal basic one is used, which just prints basic info.
+
+ WARNING: by putting in your own exception handler into IPython's main
+ execution loop, you run a very good chance of nasty crashes. This
+ facility should only be used if you really know what you are doing."""
+
+ assert type(exc_tuple)==type(()) , \
+ "The custom exceptions must be given AS A TUPLE."
+
+ def dummy_handler(self,etype,value,tb):
+ print '*** Simple custom exception handler ***'
+ print 'Exception type :',etype
+ print 'Exception value:',value
+ print 'Traceback :',tb
+ print 'Source code :','\n'.join(self.buffer)
+
+ if handler is None: handler = dummy_handler
+
+ self.CustomTB = new.instancemethod(handler,self,self.__class__)
+ self.custom_exceptions = exc_tuple
+
+ def set_custom_completer(self,completer,pos=0):
+ """set_custom_completer(completer,pos=0)
+
+ Adds a new custom completer function.
+
+ The position argument (defaults to 0) is the index in the completers
+ list where you want the completer to be inserted."""
+
+ newcomp = new.instancemethod(completer,self.Completer,
+ self.Completer.__class__)
+ self.Completer.matchers.insert(pos,newcomp)
+
+ def set_completer(self):
+ """reset readline's completer to be our own."""
+ self.readline.set_completer(self.Completer.complete)
+
+ def _get_call_pdb(self):
+ return self._call_pdb
+
+ def _set_call_pdb(self,val):
+
+ if val not in (0,1,False,True):
+ raise ValueError,'new call_pdb value must be boolean'
+
+ # store value in instance
+ self._call_pdb = val
+
+ # notify the actual exception handlers
+ self.InteractiveTB.call_pdb = val
+ if self.isthreaded:
+ try:
+ self.sys_excepthook.call_pdb = val
+ except:
+ warn('Failed to activate pdb for threaded exception handler')
+
+ call_pdb = property(_get_call_pdb,_set_call_pdb,None,
+ 'Control auto-activation of pdb at exceptions')
+
+ # These special functions get installed in the builtin namespace, to
+ # provide programmatic (pure python) access to magics, aliases and system
+ # calls. This is important for logging, user scripting, and more.
+
+ # We are basically exposing, via normal python functions, the three
+ # mechanisms in which ipython offers special call modes (magics for
+ # internal control, aliases for direct system access via pre-selected
+ # names, and !cmd for calling arbitrary system commands).
+
+ def ipmagic(self,arg_s):
+ """Call a magic function by name.
+
+ Input: a string containing the name of the magic function to call and any
+ additional arguments to be passed to the magic.
+
+ ipmagic('name -opt foo bar') is equivalent to typing at the ipython
+ prompt:
+
+ In[1]: %name -opt foo bar
+
+ To call a magic without arguments, simply use ipmagic('name').
+
+ This provides a proper Python function to call IPython's magics in any
+ valid Python code you can type at the interpreter, including loops and
+ compound statements. It is added by IPython to the Python builtin
+ namespace upon initialization."""
+
+ args = arg_s.split(' ',1)
+ magic_name = args[0]
+ magic_name = magic_name.lstrip(self.ESC_MAGIC)
+
+ try:
+ magic_args = args[1]
+ except IndexError:
+ magic_args = ''
+ fn = getattr(self,'magic_'+magic_name,None)
+ if fn is None:
+ error("Magic function `%s` not found." % magic_name)
+ else:
+ magic_args = self.var_expand(magic_args,1)
+ return fn(magic_args)
+
+ def ipalias(self,arg_s):
+ """Call an alias by name.
+
+ Input: a string containing the name of the alias to call and any
+ additional arguments to be passed to the magic.
+
+ ipalias('name -opt foo bar') is equivalent to typing at the ipython
+ prompt:
+
+ In[1]: name -opt foo bar
+
+ To call an alias without arguments, simply use ipalias('name').
+
+ This provides a proper Python function to call IPython's aliases in any
+ valid Python code you can type at the interpreter, including loops and
+ compound statements. It is added by IPython to the Python builtin
+ namespace upon initialization."""
+
+ args = arg_s.split(' ',1)
+ alias_name = args[0]
+ try:
+ alias_args = args[1]
+ except IndexError:
+ alias_args = ''
+ if alias_name in self.alias_table:
+ self.call_alias(alias_name,alias_args)
+ else:
+ error("Alias `%s` not found." % alias_name)
+
+ def ipsystem(self,arg_s):
+ """Make a system call, using IPython."""
+
+ self.system(arg_s)
+
+ def complete(self,text):
+ """Return a sorted list of all possible completions on text.
+
+ Inputs:
+
+ - text: a string of text to be completed on.
+
+ This is a wrapper around the completion mechanism, similar to what
+ readline does at the command line when the TAB key is hit. By
+ exposing it as a method, it can be used by other non-readline
+ environments (such as GUIs) for text completion.
+
+ Simple usage example:
+
+ In [7]: x = 'hello'
+
+ In [8]: x
+ Out[8]: 'hello'
+
+ In [9]: print x
+ hello
+
+ In [10]: _ip.IP.complete('x.l')
+ Out[10]: ['x.ljust', 'x.lower', 'x.lstrip']
+ """
+
+ complete = self.Completer.complete
+ state = 0
+ # use a dict so we get unique keys, since ipyhton's multiple
+ # completers can return duplicates. When we make 2.4 a requirement,
+ # start using sets instead, which are faster.
+ comps = {}
+ while True:
+ newcomp = complete(text,state,line_buffer=text)
+ if newcomp is None:
+ break
+ comps[newcomp] = 1
+ state += 1
+ outcomps = comps.keys()
+ outcomps.sort()
+ #print "T:",text,"OC:",outcomps # dbg
+ #print "vars:",self.user_ns.keys()
+ return outcomps
+
+ def set_completer_frame(self, frame=None):
+ if frame:
+ self.Completer.namespace = frame.f_locals
+ self.Completer.global_namespace = frame.f_globals
+ else:
+ self.Completer.namespace = self.user_ns
+ self.Completer.global_namespace = self.user_global_ns
+
+ def init_auto_alias(self):
+ """Define some aliases automatically.
+
+ These are ALL parameter-less aliases"""
+
+ for alias,cmd in self.auto_alias:
+ self.getapi().defalias(alias,cmd)
+
+
+ def alias_table_validate(self,verbose=0):
+ """Update information about the alias table.
+
+ In particular, make sure no Python keywords/builtins are in it."""
+
+ no_alias = self.no_alias
+ for k in self.alias_table.keys():
+ if k in no_alias:
+ del self.alias_table[k]
+ if verbose:
+ print ("Deleting alias <%s>, it's a Python "
+ "keyword or builtin." % k)
+
+ def set_autoindent(self,value=None):
+ """Set the autoindent flag, checking for readline support.
+
+ If called with no arguments, it acts as a toggle."""
+
+ if not self.has_readline:
+ if os.name == 'posix':
+ warn("The auto-indent feature requires the readline library")
+ self.autoindent = 0
+ return
+ if value is None:
+ self.autoindent = not self.autoindent
+ else:
+ self.autoindent = value
+
+ def rc_set_toggle(self,rc_field,value=None):
+ """Set or toggle a field in IPython's rc config. structure.
+
+ If called with no arguments, it acts as a toggle.
+
+ If called with a non-existent field, the resulting AttributeError
+ exception will propagate out."""
+
+ rc_val = getattr(self.rc,rc_field)
+ if value is None:
+ value = not rc_val
+ setattr(self.rc,rc_field,value)
+
+ def user_setup(self,ipythondir,rc_suffix,mode='install'):
+ """Install the user configuration directory.
+
+ Notes
+ -----
+ DEPRECATED: use the top-level user_setup() function instead.
+ """
+ return user_setup(ipythondir,rc_suffix,mode)
+
+ def atexit_operations(self):
+ """This will be executed at the time of exit.
+
+ Saving of persistent data should be performed here. """
+
+ #print '*** IPython exit cleanup ***' # dbg
+ # input history
+ self.savehist()
+
+ # Cleanup all tempfiles left around
+ for tfile in self.tempfiles:
+ try:
+ os.unlink(tfile)
+ except OSError:
+ pass
+
+ # Clear all user namespaces to release all references cleanly.
+ self.reset()
+
+ # Run user hooks
+ self.hooks.shutdown_hook()
+
+ def reset(self):
+ """Clear all internal namespaces.
+
+ Note that this is much more aggressive than %reset, since it clears
+ fully all namespaces, as well as all input/output lists.
+ """
+ for ns in self.ns_refs_table:
+ ns.clear()
+
+ # Clear input and output histories
+ self.input_hist[:] = []
+ self.input_hist_raw[:] = []
+ self.output_hist.clear()
+ # Restore the user namespaces to minimal usability
+ self.init_namespaces()
+
+ def savehist(self):
+ """Save input history to a file (via readline library)."""
+
+ if not self.has_readline:
+ return
+
+ try:
+ self.readline.write_history_file(self.histfile)
+ except:
+ print 'Unable to save IPython command history to file: ' + \
+ `self.histfile`
+
+ def reloadhist(self):
+ """Reload the input history from disk file."""
+
+ if self.has_readline:
+ try:
+ self.readline.clear_history()
+ self.readline.read_history_file(self.shell.histfile)
+ except AttributeError:
+ pass
+
+
+ def history_saving_wrapper(self, func):
+ """ Wrap func for readline history saving
+
+ Convert func into callable that saves & restores
+ history around the call """
+
+ if not self.has_readline:
+ return func
+
+ def wrapper():
+ self.savehist()
+ try:
+ func()
+ finally:
+ readline.read_history_file(self.histfile)
+ return wrapper
+
+ def pre_readline(self):
+ """readline hook to be used at the start of each line.
+
+ Currently it handles auto-indent only."""
+
+ #debugx('self.indent_current_nsp','pre_readline:')
+
+ if self.rl_do_indent:
+ self.readline.insert_text(self.indent_current_str())
+ if self.rl_next_input is not None:
+ self.readline.insert_text(self.rl_next_input)
+ self.rl_next_input = None
+
+ def init_readline(self):
+ """Command history completion/saving/reloading."""
+
+
+ import IPython.rlineimpl as readline
+
+ if not readline.have_readline:
+ self.has_readline = 0
+ self.readline = None
+ # no point in bugging windows users with this every time:
+ warn('Readline services not available on this platform.')
+ else:
+ sys.modules['readline'] = readline
+ import atexit
+ from IPython.completer import IPCompleter
+ self.Completer = IPCompleter(self,
+ self.user_ns,
+ self.user_global_ns,
+ self.rc.readline_omit__names,
+ self.alias_table)
+ sdisp = self.strdispatchers.get('complete_command', StrDispatch())
+ self.strdispatchers['complete_command'] = sdisp
+ self.Completer.custom_completers = sdisp
+ # Platform-specific configuration
+ if os.name == 'nt':
+ self.readline_startup_hook = readline.set_pre_input_hook
+ else:
+ self.readline_startup_hook = readline.set_startup_hook
+
+ # Load user's initrc file (readline config)
+ # Or if libedit is used, load editrc.
+ inputrc_name = os.environ.get('INPUTRC')
+ if inputrc_name is None:
+ home_dir = get_home_dir()
+ if home_dir is not None:
+ inputrc_name = '.inputrc'
+ if readline.uses_libedit:
+ inputrc_name = '.editrc'
+ inputrc_name = os.path.join(home_dir, inputrc_name)
+ if os.path.isfile(inputrc_name):
+ try:
+ readline.read_init_file(inputrc_name)
+ except:
+ warn('Problems reading readline initialization file <%s>'
+ % inputrc_name)
+
+ self.has_readline = 1
+ self.readline = readline
+ # save this in sys so embedded copies can restore it properly
+ sys.ipcompleter = self.Completer.complete
+ self.set_completer()
+
+ # Configure readline according to user's prefs
+ # This is only done if GNU readline is being used. If libedit
+ # is being used (as on Leopard) the readline config is
+ # not run as the syntax for libedit is different.
+ if not readline.uses_libedit:
+ for rlcommand in self.rc.readline_parse_and_bind:
+ #print "loading rl:",rlcommand # dbg
+ readline.parse_and_bind(rlcommand)
+
+ # Remove some chars from the delimiters list. If we encounter
+ # unicode chars, discard them.
+ delims = readline.get_completer_delims().encode("ascii", "ignore")
+ delims = delims.translate(string._idmap,
+ self.rc.readline_remove_delims)
+ readline.set_completer_delims(delims)
+ # otherwise we end up with a monster history after a while:
+ readline.set_history_length(1000)
+ try:
+ #print '*** Reading readline history' # dbg
+ readline.read_history_file(self.histfile)
+ except IOError:
+ pass # It doesn't exist yet.
+
+ atexit.register(self.atexit_operations)
+ del atexit
+
+ # Configure auto-indent for all platforms
+ self.set_autoindent(self.rc.autoindent)
+
+ def ask_yes_no(self,prompt,default=True):
+ if self.rc.quiet:
+ return True
+ return ask_yes_no(prompt,default)
+
+ def new_main_mod(self,ns=None):
+ """Return a new 'main' module object for user code execution.
+ """
+ main_mod = self._user_main_module
+ init_fakemod_dict(main_mod,ns)
+ return main_mod
+
+ def cache_main_mod(self,ns,fname):
+ """Cache a main module's namespace.
+
+ When scripts are executed via %run, we must keep a reference to the
+ namespace of their __main__ module (a FakeModule instance) around so
+ that Python doesn't clear it, rendering objects defined therein
+ useless.
+
+ This method keeps said reference in a private dict, keyed by the
+ absolute path of the module object (which corresponds to the script
+ path). This way, for multiple executions of the same script we only
+ keep one copy of the namespace (the last one), thus preventing memory
+ leaks from old references while allowing the objects from the last
+ execution to be accessible.
+
+ Note: we can not allow the actual FakeModule instances to be deleted,
+ because of how Python tears down modules (it hard-sets all their
+ references to None without regard for reference counts). This method
+ must therefore make a *copy* of the given namespace, to allow the
+ original module's __dict__ to be cleared and reused.
+
+
+ Parameters
+ ----------
+ ns : a namespace (a dict, typically)
+
+ fname : str
+ Filename associated with the namespace.
+
+ Examples
+ --------
+
+ In [10]: import IPython
+
+ In [11]: _ip.IP.cache_main_mod(IPython.__dict__,IPython.__file__)
+
+ In [12]: IPython.__file__ in _ip.IP._main_ns_cache
+ Out[12]: True
+ """
+ self._main_ns_cache[os.path.abspath(fname)] = ns.copy()
+
+ def clear_main_mod_cache(self):
+ """Clear the cache of main modules.
+
+ Mainly for use by utilities like %reset.
+
+ Examples
+ --------
+
+ In [15]: import IPython
+
+ In [16]: _ip.IP.cache_main_mod(IPython.__dict__,IPython.__file__)
+
+ In [17]: len(_ip.IP._main_ns_cache) > 0
+ Out[17]: True
+
+ In [18]: _ip.IP.clear_main_mod_cache()
+
+ In [19]: len(_ip.IP._main_ns_cache) == 0
+ Out[19]: True
+ """
+ self._main_ns_cache.clear()
+
+ def _should_recompile(self,e):
+ """Utility routine for edit_syntax_error"""
+
+ if e.filename in ('<ipython console>','<input>','<string>',
+ '<console>','<BackgroundJob compilation>',
+ None):
+
+ return False
+ try:
+ if (self.rc.autoedit_syntax and
+ not self.ask_yes_no('Return to editor to correct syntax error? '
+ '[Y/n] ','y')):
+ return False
+ except EOFError:
+ return False
+
+ def int0(x):
+ try:
+ return int(x)
+ except TypeError:
+ return 0
+ # always pass integer line and offset values to editor hook
+ try:
+ self.hooks.fix_error_editor(e.filename,
+ int0(e.lineno),int0(e.offset),e.msg)
+ except IPython.ipapi.TryNext:
+ warn('Could not open editor')
+ return False
+ return True
+
+ def edit_syntax_error(self):
+ """The bottom half of the syntax error handler called in the main loop.
+
+ Loop until syntax error is fixed or user cancels.
+ """
+
+ while self.SyntaxTB.last_syntax_error:
+ # copy and clear last_syntax_error
+ err = self.SyntaxTB.clear_err_state()
+ if not self._should_recompile(err):
+ return
+ try:
+ # may set last_syntax_error again if a SyntaxError is raised
+ self.safe_execfile(err.filename,self.user_ns)
+ except:
+ self.showtraceback()
+ else:
+ try:
+ f = file(err.filename)
+ try:
+ sys.displayhook(f.read())
+ finally:
+ f.close()
+ except:
+ self.showtraceback()
+
+ def showsyntaxerror(self, filename=None):
+ """Display the syntax error that just occurred.
+
+ This doesn't display a stack trace because there isn't one.
+
+ If a filename is given, it is stuffed in the exception instead
+ of what was there before (because Python's parser always uses
+ "<string>" when reading from a string).
+ """
+ etype, value, last_traceback = sys.exc_info()
+
+ # See note about these variables in showtraceback() below
+ sys.last_type = etype
+ sys.last_value = value
+ sys.last_traceback = last_traceback
+
+ if filename and etype is SyntaxError:
+ # Work hard to stuff the correct filename in the exception
+ try:
+ msg, (dummy_filename, lineno, offset, line) = value
+ except:
+ # Not the format we expect; leave it alone
+ pass
+ else:
+ # Stuff in the right filename
+ try:
+ # Assume SyntaxError is a class exception
+ value = SyntaxError(msg, (filename, lineno, offset, line))
+ except:
+ # If that failed, assume SyntaxError is a string
+ value = msg, (filename, lineno, offset, line)
+ self.SyntaxTB(etype,value,[])
+
+ def debugger(self,force=False):
+ """Call the pydb/pdb debugger.
+
+ Keywords:
+
+ - force(False): by default, this routine checks the instance call_pdb
+ flag and does not actually invoke the debugger if the flag is false.
+ The 'force' option forces the debugger to activate even if the flag
+ is false.
+ """
+
+ if not (force or self.call_pdb):
+ return
+
+ if not hasattr(sys,'last_traceback'):
+ error('No traceback has been produced, nothing to debug.')
+ return
+
+ # use pydb if available
+ if Debugger.has_pydb:
+ from pydb import pm
+ else:
+ # fallback to our internal debugger
+ pm = lambda : self.InteractiveTB.debugger(force=True)
+ self.history_saving_wrapper(pm)()
+
+ def showtraceback(self,exc_tuple = None,filename=None,tb_offset=None):
+ """Display the exception that just occurred.
+
+ If nothing is known about the exception, this is the method which
+ should be used throughout the code for presenting user tracebacks,
+ rather than directly invoking the InteractiveTB object.
+
+ A specific showsyntaxerror() also exists, but this method can take
+ care of calling it if needed, so unless you are explicitly catching a
+ SyntaxError exception, don't try to analyze the stack manually and
+ simply call this method."""
+
+
+ # Though this won't be called by syntax errors in the input line,
+ # there may be SyntaxError cases whith imported code.
+
+ try:
+ if exc_tuple is None:
+ etype, value, tb = sys.exc_info()
+ else:
+ etype, value, tb = exc_tuple
+
+ if etype is SyntaxError:
+ self.showsyntaxerror(filename)
+ elif etype is IPython.ipapi.UsageError:
+ print "UsageError:", value
+ else:
+ # WARNING: these variables are somewhat deprecated and not
+ # necessarily safe to use in a threaded environment, but tools
+ # like pdb depend on their existence, so let's set them. If we
+ # find problems in the field, we'll need to revisit their use.
+ sys.last_type = etype
+ sys.last_value = value
+ sys.last_traceback = tb
+
+ if etype in self.custom_exceptions:
+ self.CustomTB(etype,value,tb)
+ else:
+ self.InteractiveTB(etype,value,tb,tb_offset=tb_offset)
+ if self.InteractiveTB.call_pdb and self.has_readline:
+ # pdb mucks up readline, fix it back
+ self.set_completer()
+ except KeyboardInterrupt:
+ self.write("\nKeyboardInterrupt\n")
+
+ def mainloop(self,banner=None):
+ """Creates the local namespace and starts the mainloop.
+
+ If an optional banner argument is given, it will override the
+ internally created default banner."""
+
+ if self.rc.c: # Emulate Python's -c option
+ self.exec_init_cmd()
+ if banner is None:
+ if not self.rc.banner:
+ banner = ''
+ # banner is string? Use it directly!
+ elif isinstance(self.rc.banner,basestring):
+ banner = self.rc.banner
+ else:
+ banner = self.BANNER+self.banner2
+
+ # if you run stuff with -c <cmd>, raw hist is not updated
+ # ensure that it's in sync
+ if len(self.input_hist) != len (self.input_hist_raw):
+ self.input_hist_raw = InputList(self.input_hist)
+
+ while 1:
+ try:
+ self.interact(banner)
+ #self.interact_with_readline()
+
+ # XXX for testing of a readline-decoupled repl loop, call
+ # interact_with_readline above
+
+ break
+ except KeyboardInterrupt:
+ # this should not be necessary, but KeyboardInterrupt
+ # handling seems rather unpredictable...
+ self.write("\nKeyboardInterrupt in interact()\n")
+
+ def exec_init_cmd(self):
+ """Execute a command given at the command line.
+
+ This emulates Python's -c option."""
+
+ #sys.argv = ['-c']
+ self.push(self.prefilter(self.rc.c, False))
+ if not self.rc.interact:
+ self.ask_exit()
+
+ def embed_mainloop(self,header='',local_ns=None,global_ns=None,stack_depth=0):
+ """Embeds IPython into a running python program.
+
+ Input:
+
+ - header: An optional header message can be specified.
+
+ - local_ns, global_ns: working namespaces. If given as None, the
+ IPython-initialized one is updated with __main__.__dict__, so that
+ program variables become visible but user-specific configuration
+ remains possible.
+
+ - stack_depth: specifies how many levels in the stack to go to
+ looking for namespaces (when local_ns and global_ns are None). This
+ allows an intermediate caller to make sure that this function gets
+ the namespace from the intended level in the stack. By default (0)
+ it will get its locals and globals from the immediate caller.
+
+ Warning: it's possible to use this in a program which is being run by
+ IPython itself (via %run), but some funny things will happen (a few
+ globals get overwritten). In the future this will be cleaned up, as
+ there is no fundamental reason why it can't work perfectly."""
+
+ # Get locals and globals from caller
+ if local_ns is None or global_ns is None:
+ call_frame = sys._getframe(stack_depth).f_back
+
+ if local_ns is None:
+ local_ns = call_frame.f_locals
+ if global_ns is None:
+ global_ns = call_frame.f_globals
+
+ # Update namespaces and fire up interpreter
+
+ # The global one is easy, we can just throw it in
+ self.user_global_ns = global_ns
+
+ # but the user/local one is tricky: ipython needs it to store internal
+ # data, but we also need the locals. We'll copy locals in the user
+ # one, but will track what got copied so we can delete them at exit.
+ # This is so that a later embedded call doesn't see locals from a
+ # previous call (which most likely existed in a separate scope).
+ local_varnames = local_ns.keys()
+ self.user_ns.update(local_ns)
+ #self.user_ns['local_ns'] = local_ns # dbg
+
+ # Patch for global embedding to make sure that things don't overwrite
+ # user globals accidentally. Thanks to Richard <rxe@renre-europe.com>
+ # FIXME. Test this a bit more carefully (the if.. is new)
+ if local_ns is None and global_ns is None:
+ self.user_global_ns.update(__main__.__dict__)
+
+ # make sure the tab-completer has the correct frame information, so it
+ # actually completes using the frame's locals/globals
+ self.set_completer_frame()
+
+ # before activating the interactive mode, we need to make sure that
+ # all names in the builtin namespace needed by ipython point to
+ # ourselves, and not to other instances.
+ self.add_builtins()
+
+ self.interact(header)
+
+ # now, purge out the user namespace from anything we might have added
+ # from the caller's local namespace
+ delvar = self.user_ns.pop
+ for var in local_varnames:
+ delvar(var,None)
+ # and clean builtins we may have overridden
+ self.clean_builtins()
+
+ def interact_prompt(self):
+ """ Print the prompt (in read-eval-print loop)
+
+ Provided for those who want to implement their own read-eval-print loop (e.g. GUIs), not
+ used in standard IPython flow.
+ """
+ if self.more:
+ try:
+ prompt = self.hooks.generate_prompt(True)
+ except:
+ self.showtraceback()
+ if self.autoindent:
+ self.rl_do_indent = True
+
+ else:
+ try:
+ prompt = self.hooks.generate_prompt(False)
+ except:
+ self.showtraceback()
+ self.write(prompt)
+
+ def interact_handle_input(self,line):
+ """ Handle the input line (in read-eval-print loop)
+
+ Provided for those who want to implement their own read-eval-print loop (e.g. GUIs), not
+ used in standard IPython flow.
+ """
+ if line.lstrip() == line:
+ self.shadowhist.add(line.strip())
+ lineout = self.prefilter(line,self.more)
+
+ if line.strip():
+ if self.more:
+ self.input_hist_raw[-1] += '%s\n' % line
+ else:
+ self.input_hist_raw.append('%s\n' % line)
+
+
+ self.more = self.push(lineout)
+ if (self.SyntaxTB.last_syntax_error and
+ self.rc.autoedit_syntax):
+ self.edit_syntax_error()
+
+ def interact_with_readline(self):
+ """ Demo of using interact_handle_input, interact_prompt
+
+ This is the main read-eval-print loop. If you need to implement your own (e.g. for GUI),
+ it should work like this.
+ """
+ self.readline_startup_hook(self.pre_readline)
+ while not self.exit_now:
+ self.interact_prompt()
+ if self.more:
+ self.rl_do_indent = True
+ else:
+ self.rl_do_indent = False
+ line = raw_input_original().decode(self.stdin_encoding)
+ self.interact_handle_input(line)
+
+
+ def interact(self, banner=None):
+ """Closely emulate the interactive Python console.
+
+ The optional banner argument specify the banner to print
+ before the first interaction; by default it prints a banner
+ similar to the one printed by the real Python interpreter,
+ followed by the current class name in parentheses (so as not
+ to confuse this with the real interpreter -- since it's so
+ close!).
+
+ """
+
+ if self.exit_now:
+ # batch run -> do not interact
+ return
+ cprt = 'Type "copyright", "credits" or "license" for more information.'
+ if banner is None:
+ self.write("Python %s on %s\n%s\n(%s)\n" %
+ (sys.version, sys.platform, cprt,
+ self.__class__.__name__))
+ else:
+ self.write(banner)
+
+ more = 0
+
+ # Mark activity in the builtins
+ __builtin__.__dict__['__IPYTHON__active'] += 1
+
+ if self.has_readline:
+ self.readline_startup_hook(self.pre_readline)
+ # exit_now is set by a call to %Exit or %Quit, through the
+ # ask_exit callback.
+
+ while not self.exit_now:
+ self.hooks.pre_prompt_hook()
+ if more:
+ try:
+ prompt = self.hooks.generate_prompt(True)
+ except:
+ self.showtraceback()
+ if self.autoindent:
+ self.rl_do_indent = True
+
+ else:
+ try:
+ prompt = self.hooks.generate_prompt(False)
+ except:
+ self.showtraceback()
+ try:
+ line = self.raw_input(prompt,more)
+ if self.exit_now:
+ # quick exit on sys.std[in|out] close
+ break
+ if self.autoindent:
+ self.rl_do_indent = False
+
+ except KeyboardInterrupt:
+ #double-guard against keyboardinterrupts during kbdint handling
+ try:
+ self.write('\nKeyboardInterrupt\n')
+ self.resetbuffer()
+ # keep cache in sync with the prompt counter:
+ self.outputcache.prompt_count -= 1
+
+ if self.autoindent:
+ self.indent_current_nsp = 0
+ more = 0
+ except KeyboardInterrupt:
+ pass
+ except EOFError:
+ if self.autoindent:
+ self.rl_do_indent = False
+ self.readline_startup_hook(None)
+ self.write('\n')
+ self.exit()
+ except bdb.BdbQuit:
+ warn('The Python debugger has exited with a BdbQuit exception.\n'
+ 'Because of how pdb handles the stack, it is impossible\n'
+ 'for IPython to properly format this particular exception.\n'
+ 'IPython will resume normal operation.')
+ except:
+ # exceptions here are VERY RARE, but they can be triggered
+ # asynchronously by signal handlers, for example.
+ self.showtraceback()
+ else:
+ more = self.push(line)
+ if (self.SyntaxTB.last_syntax_error and
+ self.rc.autoedit_syntax):
+ self.edit_syntax_error()
+
+ # We are off again...
+ __builtin__.__dict__['__IPYTHON__active'] -= 1
+
+ def excepthook(self, etype, value, tb):
+ """One more defense for GUI apps that call sys.excepthook.
+
+ GUI frameworks like wxPython trap exceptions and call
+ sys.excepthook themselves. I guess this is a feature that
+ enables them to keep running after exceptions that would
+ otherwise kill their mainloop. This is a bother for IPython
+ which excepts to catch all of the program exceptions with a try:
+ except: statement.
+
+ Normally, IPython sets sys.excepthook to a CrashHandler instance, so if
+ any app directly invokes sys.excepthook, it will look to the user like
+ IPython crashed. In order to work around this, we can disable the
+ CrashHandler and replace it with this excepthook instead, which prints a
+ regular traceback using our InteractiveTB. In this fashion, apps which
+ call sys.excepthook will generate a regular-looking exception from
+ IPython, and the CrashHandler will only be triggered by real IPython
+ crashes.
+
+ This hook should be used sparingly, only in places which are not likely
+ to be true IPython errors.
+ """
+ self.showtraceback((etype,value,tb),tb_offset=0)
+
+ def expand_aliases(self,fn,rest):
+ """ Expand multiple levels of aliases:
+
+ if:
+
+ alias foo bar /tmp
+ alias baz foo
+
+ then:
+
+ baz huhhahhei -> bar /tmp huhhahhei
+
+ """
+ line = fn + " " + rest
+
+ done = set()
+ while 1:
+ pre,fn,rest = prefilter.splitUserInput(line,
+ prefilter.shell_line_split)
+ if fn in self.alias_table:
+ if fn in done:
+ warn("Cyclic alias definition, repeated '%s'" % fn)
+ return ""
+ done.add(fn)
+
+ l2 = self.transform_alias(fn,rest)
+ # dir -> dir
+ # print "alias",line, "->",l2 #dbg
+ if l2 == line:
+ break
+ # ls -> ls -F should not recurse forever
+ if l2.split(None,1)[0] == line.split(None,1)[0]:
+ line = l2
+ break
+
+ line=l2
+
+
+ # print "al expand to",line #dbg
+ else:
+ break
+
+ return line
+
+ def transform_alias(self, alias,rest=''):
+ """ Transform alias to system command string.
+ """
+ trg = self.alias_table[alias]
+
+ nargs,cmd = trg
+ # print trg #dbg
+ if ' ' in cmd and os.path.isfile(cmd):
+ cmd = '"%s"' % cmd
+
+ # Expand the %l special to be the user's input line
+ if cmd.find('%l') >= 0:
+ cmd = cmd.replace('%l',rest)
+ rest = ''
+ if nargs==0:
+ # Simple, argument-less aliases
+ cmd = '%s %s' % (cmd,rest)
+ else:
+ # Handle aliases with positional arguments
+ args = rest.split(None,nargs)
+ if len(args)< nargs:
+ error('Alias <%s> requires %s arguments, %s given.' %
+ (alias,nargs,len(args)))
+ return None
+ cmd = '%s %s' % (cmd % tuple(args[:nargs]),' '.join(args[nargs:]))
+ # Now call the macro, evaluating in the user's namespace
+ #print 'new command: <%r>' % cmd # dbg
+ return cmd
+
+ def call_alias(self,alias,rest=''):
+ """Call an alias given its name and the rest of the line.
+
+ This is only used to provide backwards compatibility for users of
+ ipalias(), use of which is not recommended for anymore."""
+
+ # Now call the macro, evaluating in the user's namespace
+ cmd = self.transform_alias(alias, rest)
+ try:
+ self.system(cmd)
+ except:
+ self.showtraceback()
+
+ def indent_current_str(self):
+ """return the current level of indentation as a string"""
+ return self.indent_current_nsp * ' '
+
+ def autoindent_update(self,line):
+ """Keep track of the indent level."""
+
+ #debugx('line')
+ #debugx('self.indent_current_nsp')
+ if self.autoindent:
+ if line:
+ inisp = num_ini_spaces(line)
+ if inisp < self.indent_current_nsp:
+ self.indent_current_nsp = inisp
+
+ if line[-1] == ':':
+ self.indent_current_nsp += 4
+ elif dedent_re.match(line):
+ self.indent_current_nsp -= 4
+ else:
+ self.indent_current_nsp = 0
+
+ def runlines(self,lines):
+ """Run a string of one or more lines of source.
+
+ This method is capable of running a string containing multiple source
+ lines, as if they had been entered at the IPython prompt. Since it
+ exposes IPython's processing machinery, the given strings can contain
+ magic calls (%magic), special shell access (!cmd), etc."""
+
+ # We must start with a clean buffer, in case this is run from an
+ # interactive IPython session (via a magic, for example).
+ self.resetbuffer()
+ lines = lines.split('\n')
+ more = 0
+
+ for line in lines:
+ # skip blank lines so we don't mess up the prompt counter, but do
+ # NOT skip even a blank line if we are in a code block (more is
+ # true)
+
+ if line or more:
+ # push to raw history, so hist line numbers stay in sync
+ self.input_hist_raw.append("# " + line + "\n")
+ more = self.push(self.prefilter(line,more))
+ # IPython's runsource returns None if there was an error
+ # compiling the code. This allows us to stop processing right
+ # away, so the user gets the error message at the right place.
+ if more is None:
+ break
+ else:
+ self.input_hist_raw.append("\n")
+ # final newline in case the input didn't have it, so that the code
+ # actually does get executed
+ if more:
+ self.push('\n')
+
+ def runsource(self, source, filename='<input>', symbol='single'):
+ """Compile and run some source in the interpreter.
+
+ Arguments are as for compile_command().
+
+ One several things can happen:
+
+ 1) The input is incorrect; compile_command() raised an
+ exception (SyntaxError or OverflowError). A syntax traceback
+ will be printed by calling the showsyntaxerror() method.
+
+ 2) The input is incomplete, and more input is required;
+ compile_command() returned None. Nothing happens.
+
+ 3) The input is complete; compile_command() returned a code
+ object. The code is executed by calling self.runcode() (which
+ also handles run-time exceptions, except for SystemExit).
+
+ The return value is:
+
+ - True in case 2
+
+ - False in the other cases, unless an exception is raised, where
+ None is returned instead. This can be used by external callers to
+ know whether to continue feeding input or not.
+
+ The return value can be used to decide whether to use sys.ps1 or
+ sys.ps2 to prompt the next line."""
+
+ # if the source code has leading blanks, add 'if 1:\n' to it
+ # this allows execution of indented pasted code. It is tempting
+ # to add '\n' at the end of source to run commands like ' a=1'
+ # directly, but this fails for more complicated scenarios
+ source=source.encode(self.stdin_encoding)
+ if source[:1] in [' ', '\t']:
+ source = 'if 1:\n%s' % source
+
+ try:
+ code = self.compile(source,filename,symbol)
+ except (OverflowError, SyntaxError, ValueError, TypeError, MemoryError):
+ # Case 1
+ self.showsyntaxerror(filename)
+ return None
+
+ if code is None:
+ # Case 2
+ return True
+
+ # Case 3
+ # We store the code object so that threaded shells and
+ # custom exception handlers can access all this info if needed.
+ # The source corresponding to this can be obtained from the
+ # buffer attribute as '\n'.join(self.buffer).
+ self.code_to_run = code
+ # now actually execute the code object
+ if self.runcode(code) == 0:
+ return False
+ else:
+ return None
+
+ def runcode(self,code_obj):
+ """Execute a code object.
+
+ When an exception occurs, self.showtraceback() is called to display a
+ traceback.
+
+ Return value: a flag indicating whether the code to be run completed
+ successfully:
+
+ - 0: successful execution.
+ - 1: an error occurred.
+ """
+
+ # Set our own excepthook in case the user code tries to call it
+ # directly, so that the IPython crash handler doesn't get triggered
+ old_excepthook,sys.excepthook = sys.excepthook, self.excepthook
+
+ # we save the original sys.excepthook in the instance, in case config
+ # code (such as magics) needs access to it.
+ self.sys_excepthook = old_excepthook
+ outflag = 1 # happens in more places, so it's easier as default
+ try:
+ try:
+ self.hooks.pre_runcode_hook()
+ exec code_obj in self.user_global_ns, self.user_ns
+ finally:
+ # Reset our crash handler in place
+ sys.excepthook = old_excepthook
+ except SystemExit:
+ self.resetbuffer()
+ self.showtraceback()
+ warn("Type %exit or %quit to exit IPython "
+ "(%Exit or %Quit do so unconditionally).",level=1)
+ except self.custom_exceptions:
+ etype,value,tb = sys.exc_info()
+ self.CustomTB(etype,value,tb)
+ except:
+ self.showtraceback()
+ else:
+ outflag = 0
+ if softspace(sys.stdout, 0):
+ print
+ # Flush out code object which has been run (and source)
+ self.code_to_run = None
+ return outflag
+
+ def push(self, line):
+ """Push a line to the interpreter.
+
+ The line should not have a trailing newline; it may have
+ internal newlines. The line is appended to a buffer and the
+ interpreter's runsource() method is called with the
+ concatenated contents of the buffer as source. If this
+ indicates that the command was executed or invalid, the buffer
+ is reset; otherwise, the command is incomplete, and the buffer
+ is left as it was after the line was appended. The return
+ value is 1 if more input is required, 0 if the line was dealt
+ with in some way (this is the same as runsource()).
+ """
+
+ # autoindent management should be done here, and not in the
+ # interactive loop, since that one is only seen by keyboard input. We
+ # need this done correctly even for code run via runlines (which uses
+ # push).
+
+ #print 'push line: <%s>' % line # dbg
+ for subline in line.splitlines():
+ self.autoindent_update(subline)
+ self.buffer.append(line)
+ more = self.runsource('\n'.join(self.buffer), self.filename)
+ if not more:
+ self.resetbuffer()
+ return more
+
+ def split_user_input(self, line):
+ # This is really a hold-over to support ipapi and some extensions
+ return prefilter.splitUserInput(line)
+
+ def resetbuffer(self):
+ """Reset the input buffer."""
+ self.buffer[:] = []
+
+ def raw_input(self,prompt='',continue_prompt=False):
+ """Write a prompt and read a line.
+
+ The returned line does not include the trailing newline.
+ When the user enters the EOF key sequence, EOFError is raised.
+
+ Optional inputs:
+
+ - prompt(''): a string to be printed to prompt the user.
+
+ - continue_prompt(False): whether this line is the first one or a
+ continuation in a sequence of inputs.
+ """
+
+ # Code run by the user may have modified the readline completer state.
+ # We must ensure that our completer is back in place.
+ if self.has_readline:
+ self.set_completer()
+
+ try:
+ line = raw_input_original(prompt).decode(self.stdin_encoding)
+ except ValueError:
+ warn("\n********\nYou or a %run:ed script called sys.stdin.close()"
+ " or sys.stdout.close()!\nExiting IPython!")
+ self.ask_exit()
+ return ""
+
+ # Try to be reasonably smart about not re-indenting pasted input more
+ # than necessary. We do this by trimming out the auto-indent initial
+ # spaces, if the user's actual input started itself with whitespace.
+ #debugx('self.buffer[-1]')
+
+ if self.autoindent:
+ if num_ini_spaces(line) > self.indent_current_nsp:
+ line = line[self.indent_current_nsp:]
+ self.indent_current_nsp = 0
+
+ # store the unfiltered input before the user has any chance to modify
+ # it.
+ if line.strip():
+ if continue_prompt:
+ self.input_hist_raw[-1] += '%s\n' % line
+ if self.has_readline: # and some config option is set?
+ try:
+ histlen = self.readline.get_current_history_length()
+ if histlen > 1:
+ newhist = self.input_hist_raw[-1].rstrip()
+ self.readline.remove_history_item(histlen-1)
+ self.readline.replace_history_item(histlen-2,
+ newhist.encode(self.stdin_encoding))
+ except AttributeError:
+ pass # re{move,place}_history_item are new in 2.4.
+ else:
+ self.input_hist_raw.append('%s\n' % line)
+ # only entries starting at first column go to shadow history
+ if line.lstrip() == line:
+ self.shadowhist.add(line.strip())
+ elif not continue_prompt:
+ self.input_hist_raw.append('\n')
+ try:
+ lineout = self.prefilter(line,continue_prompt)
+ except:
+ # blanket except, in case a user-defined prefilter crashes, so it
+ # can't take all of ipython with it.
+ self.showtraceback()
+ return ''
+ else:
+ return lineout
+
+ def _prefilter(self, line, continue_prompt):
+ """Calls different preprocessors, depending on the form of line."""
+
+ # All handlers *must* return a value, even if it's blank ('').
+
+ # Lines are NOT logged here. Handlers should process the line as
+ # needed, update the cache AND log it (so that the input cache array
+ # stays synced).
+
+ #.....................................................................
+ # Code begins
+
+ #if line.startswith('%crash'): raise RuntimeError,'Crash now!' # dbg
+
+ # save the line away in case we crash, so the post-mortem handler can
+ # record it
+ self._last_input_line = line
+
+ #print '***line: <%s>' % line # dbg
+
+ if not line:
+ # Return immediately on purely empty lines, so that if the user
+ # previously typed some whitespace that started a continuation
+ # prompt, he can break out of that loop with just an empty line.
+ # This is how the default python prompt works.
+
+ # Only return if the accumulated input buffer was just whitespace!
+ if ''.join(self.buffer).isspace():
+ self.buffer[:] = []
+ return ''
+
+ line_info = prefilter.LineInfo(line, continue_prompt)
+
+ # the input history needs to track even empty lines
+ stripped = line.strip()
+
+ if not stripped:
+ if not continue_prompt:
+ self.outputcache.prompt_count -= 1
+ return self.handle_normal(line_info)
+
+ # print '***cont',continue_prompt # dbg
+ # special handlers are only allowed for single line statements
+ if continue_prompt and not self.rc.multi_line_specials:
+ return self.handle_normal(line_info)
+
+
+ # See whether any pre-existing handler can take care of it
+ rewritten = self.hooks.input_prefilter(stripped)
+ if rewritten != stripped: # ok, some prefilter did something
+ rewritten = line_info.pre + rewritten # add indentation
+ return self.handle_normal(prefilter.LineInfo(rewritten,
+ continue_prompt))
+
+ #print 'pre <%s> iFun <%s> rest <%s>' % (pre,iFun,theRest) # dbg
+
+ return prefilter.prefilter(line_info, self)
+
+
+ def _prefilter_dumb(self, line, continue_prompt):
+ """simple prefilter function, for debugging"""
+ return self.handle_normal(line,continue_prompt)
+
+
+ def multiline_prefilter(self, line, continue_prompt):
+ """ Run _prefilter for each line of input
+
+ Covers cases where there are multiple lines in the user entry,
+ which is the case when the user goes back to a multiline history
+ entry and presses enter.
+
+ """
+ out = []
+ for l in line.rstrip('\n').split('\n'):
+ out.append(self._prefilter(l, continue_prompt))
+ return '\n'.join(out)
+
+ # Set the default prefilter() function (this can be user-overridden)
+ prefilter = multiline_prefilter
+
+ def handle_normal(self,line_info):
+ """Handle normal input lines. Use as a template for handlers."""
+
+ # With autoindent on, we need some way to exit the input loop, and I
+ # don't want to force the user to have to backspace all the way to
+ # clear the line. The rule will be in this case, that either two
+ # lines of pure whitespace in a row, or a line of pure whitespace but
+ # of a size different to the indent level, will exit the input loop.
+ line = line_info.line
+ continue_prompt = line_info.continue_prompt
+
+ if (continue_prompt and self.autoindent and line.isspace() and
+ (0 < abs(len(line) - self.indent_current_nsp) <= 2 or
+ (self.buffer[-1]).isspace() )):
+ line = ''
+
+ self.log(line,line,continue_prompt)
+ return line
+
+ def handle_alias(self,line_info):
+ """Handle alias input lines. """
+ tgt = self.alias_table[line_info.iFun]
+ # print "=>",tgt #dbg
+ if callable(tgt):
+ if '$' in line_info.line:
+ call_meth = '(_ip, _ip.itpl(%s))'
+ else:
+ call_meth = '(_ip,%s)'
+ line_out = ("%s_sh.%s" + call_meth) % (line_info.preWhitespace,
+ line_info.iFun,
+ make_quoted_expr(line_info.line))
+ else:
+ transformed = self.expand_aliases(line_info.iFun,line_info.theRest)
+
+ # pre is needed, because it carries the leading whitespace. Otherwise
+ # aliases won't work in indented sections.
+ line_out = '%s_ip.system(%s)' % (line_info.preWhitespace,
+ make_quoted_expr( transformed ))
+
+ self.log(line_info.line,line_out,line_info.continue_prompt)
+ #print 'line out:',line_out # dbg
+ return line_out
+
+ def handle_shell_escape(self, line_info):
+ """Execute the line in a shell, empty return value"""
+ #print 'line in :', `line` # dbg
+ line = line_info.line
+ if line.lstrip().startswith('!!'):
+ # rewrite LineInfo's line, iFun and theRest to properly hold the
+ # call to %sx and the actual command to be executed, so
+ # handle_magic can work correctly. Note that this works even if
+ # the line is indented, so it handles multi_line_specials
+ # properly.
+ new_rest = line.lstrip()[2:]
+ line_info.line = '%ssx %s' % (self.ESC_MAGIC,new_rest)
+ line_info.iFun = 'sx'
+ line_info.theRest = new_rest
+ return self.handle_magic(line_info)
+ else:
+ cmd = line.lstrip().lstrip('!')
+ line_out = '%s_ip.system(%s)' % (line_info.preWhitespace,
+ make_quoted_expr(cmd))
+ # update cache/log and return
+ self.log(line,line_out,line_info.continue_prompt)
+ return line_out
+
+ def handle_magic(self, line_info):
+ """Execute magic functions."""
+ iFun = line_info.iFun
+ theRest = line_info.theRest
+ cmd = '%s_ip.magic(%s)' % (line_info.preWhitespace,
+ make_quoted_expr(iFun + " " + theRest))
+ self.log(line_info.line,cmd,line_info.continue_prompt)
+ #print 'in handle_magic, cmd=<%s>' % cmd # dbg
+ return cmd
+
+ def handle_auto(self, line_info):
+ """Hande lines which can be auto-executed, quoting if requested."""
+
+ line = line_info.line
+ iFun = line_info.iFun
+ theRest = line_info.theRest
+ pre = line_info.pre
+ continue_prompt = line_info.continue_prompt
+ obj = line_info.ofind(self)['obj']
+
+ #print 'pre <%s> iFun <%s> rest <%s>' % (pre,iFun,theRest) # dbg
+
+ # This should only be active for single-line input!
+ if continue_prompt:
+ self.log(line,line,continue_prompt)
+ return line
+
+ force_auto = isinstance(obj, IPython.ipapi.IPyAutocall)
+ auto_rewrite = True
+
+ if pre == self.ESC_QUOTE:
+ # Auto-quote splitting on whitespace
+ newcmd = '%s("%s")' % (iFun,'", "'.join(theRest.split()) )
+ elif pre == self.ESC_QUOTE2:
+ # Auto-quote whole string
+ newcmd = '%s("%s")' % (iFun,theRest)
+ elif pre == self.ESC_PAREN:
+ newcmd = '%s(%s)' % (iFun,",".join(theRest.split()))
+ else:
+ # Auto-paren.
+ # We only apply it to argument-less calls if the autocall
+ # parameter is set to 2. We only need to check that autocall is <
+ # 2, since this function isn't called unless it's at least 1.
+ if not theRest and (self.rc.autocall < 2) and not force_auto:
+ newcmd = '%s %s' % (iFun,theRest)
+ auto_rewrite = False
+ else:
+ if not force_auto and theRest.startswith('['):
+ if hasattr(obj,'__getitem__'):
+ # Don't autocall in this case: item access for an object
+ # which is BOTH callable and implements __getitem__.
+ newcmd = '%s %s' % (iFun,theRest)
+ auto_rewrite = False
+ else:
+ # if the object doesn't support [] access, go ahead and
+ # autocall
+ newcmd = '%s(%s)' % (iFun.rstrip(),theRest)
+ elif theRest.endswith(';'):
+ newcmd = '%s(%s);' % (iFun.rstrip(),theRest[:-1])
+ else:
+ newcmd = '%s(%s)' % (iFun.rstrip(), theRest)
+
+ if auto_rewrite:
+ rw = self.outputcache.prompt1.auto_rewrite() + newcmd
+
+ try:
+ # plain ascii works better w/ pyreadline, on some machines, so
+ # we use it and only print uncolored rewrite if we have unicode
+ rw = str(rw)
+ print >>Term.cout, rw
+ except UnicodeEncodeError:
+ print "-------------->" + newcmd
+
+ # log what is now valid Python, not the actual user input (without the
+ # final newline)
+ self.log(line,newcmd,continue_prompt)
+ return newcmd
+
+ def handle_help(self, line_info):
+ """Try to get some help for the object.
+
+ obj? or ?obj -> basic information.
+ obj?? or ??obj -> more details.
+ """
+
+ line = line_info.line
+ # We need to make sure that we don't process lines which would be
+ # otherwise valid python, such as "x=1 # what?"
+ try:
+ codeop.compile_command(line)
+ except SyntaxError:
+ # We should only handle as help stuff which is NOT valid syntax
+ if line[0]==self.ESC_HELP:
+ line = line[1:]
+ elif line[-1]==self.ESC_HELP:
+ line = line[:-1]
+ self.log(line,'#?'+line,line_info.continue_prompt)
+ if line:
+ #print 'line:<%r>' % line # dbg
+ self.magic_pinfo(line)
+ else:
+ page(self.usage,screen_lines=self.rc.screen_length)
+ return '' # Empty string is needed here!
+ except:
+ # Pass any other exceptions through to the normal handler
+ return self.handle_normal(line_info)
+ else:
+ # If the code compiles ok, we should handle it normally
+ return self.handle_normal(line_info)
+
+ def getapi(self):
+ """ Get an IPApi object for this shell instance
+
+ Getting an IPApi object is always preferable to accessing the shell
+ directly, but this holds true especially for extensions.
+
+ It should always be possible to implement an extension with IPApi
+ alone. If not, contact maintainer to request an addition.
+
+ """
+ return self.api
+
+ def handle_emacs(self, line_info):
+ """Handle input lines marked by python-mode."""
+
+ # Currently, nothing is done. Later more functionality can be added
+ # here if needed.
+
+ # The input cache shouldn't be updated
+ return line_info.line
+
+
+ def mktempfile(self,data=None):
+ """Make a new tempfile and return its filename.
+
+ This makes a call to tempfile.mktemp, but it registers the created
+ filename internally so ipython cleans it up at exit time.
+
+ Optional inputs:
+
+ - data(None): if data is given, it gets written out to the temp file
+ immediately, and the file is closed again."""
+
+ filename = tempfile.mktemp('.py','ipython_edit_')
+ self.tempfiles.append(filename)
+
+ if data:
+ tmp_file = open(filename,'w')
+ tmp_file.write(data)
+ tmp_file.close()
+ return filename
+
+ def write(self,data):
+ """Write a string to the default output"""
+ Term.cout.write(data)
+
+ def write_err(self,data):
+ """Write a string to the default error output"""
+ Term.cerr.write(data)
+
+ def ask_exit(self):
+ """ Call for exiting. Can be overiden and used as a callback. """
+ self.exit_now = True
+
+ def exit(self):
+ """Handle interactive exit.
+
+ This method calls the ask_exit callback."""
+
+ if self.rc.confirm_exit:
+ if self.ask_yes_no('Do you really want to exit ([y]/n)?','y'):
+ self.ask_exit()
+ else:
+ self.ask_exit()
+
+ def safe_execfile(self,fname,*where,**kw):
+ """A safe version of the builtin execfile().
+
+ This version will never throw an exception, and knows how to handle
+ ipython logs as well.
+
+ :Parameters:
+ fname : string
+ Name of the file to be executed.
+
+ where : tuple
+ One or two namespaces, passed to execfile() as (globals,locals).
+ If only one is given, it is passed as both.
+
+ :Keywords:
+ islog : boolean (False)
+
+ quiet : boolean (True)
+
+ exit_ignore : boolean (False)
+ """
+
+ def syspath_cleanup():
+ """Internal cleanup routine for sys.path."""
+ if add_dname:
+ try:
+ sys.path.remove(dname)
+ except ValueError:
+ # For some reason the user has already removed it, ignore.
+ pass
+
+ fname = os.path.expanduser(fname)
+
+ # Find things also in current directory. This is needed to mimic the
+ # behavior of running a script from the system command line, where
+ # Python inserts the script's directory into sys.path
+ dname = os.path.dirname(os.path.abspath(fname))
+ add_dname = False
+ if dname not in sys.path:
+ sys.path.insert(0,dname)
+ add_dname = True
+
+ try:
+ xfile = open(fname)
+ except:
+ print >> Term.cerr, \
+ 'Could not open file <%s> for safe execution.' % fname
+ syspath_cleanup()
+ return None
+
+ kw.setdefault('islog',0)
+ kw.setdefault('quiet',1)
+ kw.setdefault('exit_ignore',0)
+
+ first = xfile.readline()
+ loghead = str(self.loghead_tpl).split('\n',1)[0].strip()
+ xfile.close()
+ # line by line execution
+ if first.startswith(loghead) or kw['islog']:
+ print 'Loading log file <%s> one line at a time...' % fname
+ if kw['quiet']:
+ stdout_save = sys.stdout
+ sys.stdout = StringIO.StringIO()
+ try:
+ globs,locs = where[0:2]
+ except:
+ try:
+ globs = locs = where[0]
+ except:
+ globs = locs = globals()
+ badblocks = []
+
+ # we also need to identify indented blocks of code when replaying
+ # logs and put them together before passing them to an exec
+ # statement. This takes a bit of regexp and look-ahead work in the
+ # file. It's easiest if we swallow the whole thing in memory
+ # first, and manually walk through the lines list moving the
+ # counter ourselves.
+ indent_re = re.compile('\s+\S')
+ xfile = open(fname)
+ filelines = xfile.readlines()
+ xfile.close()
+ nlines = len(filelines)
+ lnum = 0
+ while lnum < nlines:
+ line = filelines[lnum]
+ lnum += 1
+ # don't re-insert logger status info into cache
+ if line.startswith('#log#'):
+ continue
+ else:
+ # build a block of code (maybe a single line) for execution
+ block = line
+ try:
+ next = filelines[lnum] # lnum has already incremented
+ except:
+ next = None
+ while next and indent_re.match(next):
+ block += next
+ lnum += 1
+ try:
+ next = filelines[lnum]
+ except:
+ next = None
+ # now execute the block of one or more lines
+ try:
+ exec block in globs,locs
+ except SystemExit:
+ pass
+ except:
+ badblocks.append(block.rstrip())
+ if kw['quiet']: # restore stdout
+ sys.stdout.close()
+ sys.stdout = stdout_save
+ print 'Finished replaying log file <%s>' % fname
+ if badblocks:
+ print >> sys.stderr, ('\nThe following lines/blocks in file '
+ '<%s> reported errors:' % fname)
+
+ for badline in badblocks:
+ print >> sys.stderr, badline
+ else: # regular file execution
+ try:
+ if sys.platform == 'win32' and sys.version_info < (2,5,1):
+ # Work around a bug in Python for Windows. The bug was
+ # fixed in in Python 2.5 r54159 and 54158, but that's still
+ # SVN Python as of March/07. For details, see:
+ # http://projects.scipy.org/ipython/ipython/ticket/123
+ try:
+ globs,locs = where[0:2]
+ except:
+ try:
+ globs = locs = where[0]
+ except:
+ globs = locs = globals()
+ exec file(fname) in globs,locs
+ else:
+ execfile(fname,*where)
+ except SyntaxError:
+ self.showsyntaxerror()
+ warn('Failure executing file: <%s>' % fname)
+ except SystemExit,status:
+ # Code that correctly sets the exit status flag to success (0)
+ # shouldn't be bothered with a traceback. Note that a plain
+ # sys.exit() does NOT set the message to 0 (it's empty) so that
+ # will still get a traceback. Note that the structure of the
+ # SystemExit exception changed between Python 2.4 and 2.5, so
+ # the checks must be done in a version-dependent way.
+ show = False
+
+ if sys.version_info[:2] > (2,5):
+ if status.message!=0 and not kw['exit_ignore']:
+ show = True
+ else:
+ if status.code and not kw['exit_ignore']:
+ show = True
+ if show:
+ self.showtraceback()
+ warn('Failure executing file: <%s>' % fname)
+ except:
+ self.showtraceback()
+ warn('Failure executing file: <%s>' % fname)
+
+ syspath_cleanup()
+
+#************************* end of file <iplib.py> *****************************
diff --git a/IPython/ipmaker.py b/IPython/ipmaker.py
new file mode 100644
index 0000000..f514338
--- /dev/null
+++ b/IPython/ipmaker.py
@@ -0,0 +1,773 @@
+# -*- coding: utf-8 -*-
+"""
+IPython -- An enhanced Interactive Python
+
+Requires Python 2.1 or better.
+
+This file contains the main make_IPython() starter function.
+"""
+
+#*****************************************************************************
+# Copyright (C) 2008-2009 The IPython Development Team
+# Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#*****************************************************************************
+
+try:
+ credits._Printer__data = """
+ Python: %s
+
+ IPython: The IPython Development Team.
+ See http://ipython.scipy.org for more information.""" \
+ % credits._Printer__data
+
+ copyright._Printer__data += """
+
+ Copyright (c) 2008-2009 The IPython Development Team.
+ Copyright (c) 2001-2007 Fernando Perez, Janko Hauser, Nathan Gray.
+ All Rights Reserved."""
+except NameError:
+ # Can happen if ipython was started with 'python -S', so that site.py is
+ # not loaded
+ pass
+
+#****************************************************************************
+# Required modules
+
+# From the standard library
+import __main__
+import __builtin__
+import os
+import re
+import sys
+import types
+from pprint import pprint,pformat
+
+# Our own
+from IPython import DPyGetOpt
+from IPython import Release
+from IPython.ipstruct import Struct
+from IPython.OutputTrap import OutputTrap
+from IPython.ConfigLoader import ConfigLoader
+from IPython.iplib import InteractiveShell
+from IPython.usage import cmd_line_usage,interactive_usage
+from IPython.genutils import *
+
+def force_import(modname,force_reload=False):
+ if modname in sys.modules and force_reload:
+ info("reloading: %s" % modname)
+ reload(sys.modules[modname])
+ else:
+ __import__(modname)
+
+
+#-----------------------------------------------------------------------------
+def make_IPython(argv=None,user_ns=None,user_global_ns=None,debug=1,
+ rc_override=None,shell_class=InteractiveShell,
+ embedded=False,**kw):
+ """This is a dump of IPython into a single function.
+
+ Later it will have to be broken up in a sensible manner.
+
+ Arguments:
+
+ - argv: a list similar to sys.argv[1:]. It should NOT contain the desired
+ script name, b/c DPyGetOpt strips the first argument only for the real
+ sys.argv.
+
+ - user_ns: a dict to be used as the user's namespace."""
+
+ #----------------------------------------------------------------------
+ # Defaults and initialization
+
+ # For developer debugging, deactivates crash handler and uses pdb.
+ DEVDEBUG = False
+
+ if argv is None:
+ argv = sys.argv
+
+ # __IP is the main global that lives throughout and represents the whole
+ # application. If the user redefines it, all bets are off as to what
+ # happens.
+
+ # __IP is the name of he global which the caller will have accessible as
+ # __IP.name. We set its name via the first parameter passed to
+ # InteractiveShell:
+
+ IP = shell_class('__IP',user_ns=user_ns,user_global_ns=user_global_ns,
+ embedded=embedded,**kw)
+
+ # Put 'help' in the user namespace
+ try:
+ from site import _Helper
+ IP.user_ns['help'] = _Helper()
+ except ImportError:
+ warn('help() not available - check site.py')
+
+ if DEVDEBUG:
+ # For developer debugging only (global flag)
+ from IPython import ultraTB
+ sys.excepthook = ultraTB.VerboseTB(call_pdb=1)
+
+ IP.BANNER_PARTS = ['Python %s\n'
+ 'Type "copyright", "credits" or "license" '
+ 'for more information.\n'
+ % (sys.version.split('\n')[0],),
+ "IPython %s -- An enhanced Interactive Python."
+ % (Release.version,),
+"""\
+? -> Introduction and overview of IPython's features.
+%quickref -> Quick reference.
+help -> Python's own help system.
+object? -> Details about 'object'. ?object also works, ?? prints more.
+""" ]
+
+ IP.usage = interactive_usage
+
+ # Platform-dependent suffix.
+ if os.name == 'posix':
+ rc_suffix = ''
+ else:
+ rc_suffix = '.ini'
+
+ # default directory for configuration
+ ipythondir_def = get_ipython_dir()
+
+ sys.path.insert(0, '') # add . to sys.path. Fix from Prabhu Ramachandran
+
+ # we need the directory where IPython itself is installed
+ import IPython
+ IPython_dir = os.path.dirname(IPython.__file__)
+ del IPython
+
+ #-------------------------------------------------------------------------
+ # Command line handling
+
+ # Valid command line options (uses DPyGetOpt syntax, like Perl's
+ # GetOpt::Long)
+
+ # Any key not listed here gets deleted even if in the file (like session
+ # or profile). That's deliberate, to maintain the rc namespace clean.
+
+ # Each set of options appears twice: under _conv only the names are
+ # listed, indicating which type they must be converted to when reading the
+ # ipythonrc file. And under DPyGetOpt they are listed with the regular
+ # DPyGetOpt syntax (=s,=i,:f,etc).
+
+ # Make sure there's a space before each end of line (they get auto-joined!)
+ cmdline_opts = ('autocall=i autoindent! automagic! banner! cache_size|cs=i '
+ 'c=s classic|cl color_info! colors=s confirm_exit! '
+ 'debug! deep_reload! editor=s log|l messages! nosep '
+ 'object_info_string_level=i pdb! '
+ 'pprint! prompt_in1|pi1=s prompt_in2|pi2=s prompt_out|po=s '
+ 'pydb! '
+ 'pylab_import_all! '
+ 'quick screen_length|sl=i prompts_pad_left=i '
+ 'logfile|lf=s logplay|lp=s profile|p=s '
+ 'readline! readline_merge_completions! '
+ 'readline_omit__names! '
+ 'rcfile=s separate_in|si=s separate_out|so=s '
+ 'separate_out2|so2=s xmode=s wildcards_case_sensitive! '
+ 'magic_docstrings system_verbose! '
+ 'multi_line_specials! '
+ 'term_title! wxversion=s '
+ 'autoedit_syntax!')
+
+ # Options that can *only* appear at the cmd line (not in rcfiles).
+
+ cmdline_only = ('help interact|i ipythondir=s Version upgrade '
+ 'gthread! qthread! q4thread! wthread! tkthread! pylab! tk! '
+ # 'twisted!' # disabled for now.
+ )
+
+ # Build the actual name list to be used by DPyGetOpt
+ opts_names = qw(cmdline_opts) + qw(cmdline_only)
+
+ # Set sensible command line defaults.
+ # This should have everything from cmdline_opts and cmdline_only
+ opts_def = Struct(autocall = 1,
+ autoedit_syntax = 0,
+ autoindent = 0,
+ automagic = 1,
+ autoexec = [],
+ banner = 1,
+ c = '',
+ cache_size = 1000,
+ classic = 0,
+ color_info = 0,
+ colors = 'NoColor',
+ confirm_exit = 1,
+ debug = 0,
+ deep_reload = 0,
+ editor = '0',
+ gthread = 0,
+ help = 0,
+ interact = 0,
+ ipythondir = ipythondir_def,
+ log = 0,
+ logfile = '',
+ logplay = '',
+ messages = 1,
+ multi_line_specials = 1,
+ nosep = 0,
+ object_info_string_level = 0,
+ pdb = 0,
+ pprint = 0,
+ profile = '',
+ prompt_in1 = 'In [\\#]: ',
+ prompt_in2 = ' .\\D.: ',
+ prompt_out = 'Out[\\#]: ',
+ prompts_pad_left = 1,
+ pydb = 0,
+ pylab = 0,
+ pylab_import_all = 1,
+ q4thread = 0,
+ qthread = 0,
+ quick = 0,
+ quiet = 0,
+ rcfile = 'ipythonrc' + rc_suffix,
+ readline = 1,
+ readline_merge_completions = 1,
+ readline_omit__names = 0,
+ screen_length = 0,
+ separate_in = '\n',
+ separate_out = '\n',
+ separate_out2 = '',
+ system_header = 'IPython system call: ',
+ system_verbose = 0,
+ term_title = 1,
+ tk = 0,
+ #twisted= 0, # disabled for now
+ upgrade = 0,
+ Version = 0,
+ wildcards_case_sensitive = 1,
+ wthread = 0,
+ wxversion = '0',
+ xmode = 'Context',
+ magic_docstrings = 0, # undocumented, for doc generation
+ )
+
+ # Things that will *only* appear in rcfiles (not at the command line).
+ # Make sure there's a space before each end of line (they get auto-joined!)
+ rcfile_opts = { qwflat: 'include import_mod import_all execfile ',
+ qw_lol: 'import_some ',
+ # for things with embedded whitespace:
+ list_strings:'execute alias readline_parse_and_bind ',
+ # Regular strings need no conversion:
+ None:'readline_remove_delims ',
+ }
+ # Default values for these
+ rc_def = Struct(include = [],
+ import_mod = [],
+ import_all = [],
+ import_some = [[]],
+ execute = [],
+ execfile = [],
+ alias = [],
+ readline_parse_and_bind = [],
+ readline_remove_delims = '',
+ )
+
+ # Build the type conversion dictionary from the above tables:
+ typeconv = rcfile_opts.copy()
+ typeconv.update(optstr2types(cmdline_opts))
+
+ # FIXME: the None key appears in both, put that back together by hand. Ugly!
+ typeconv[None] += ' ' + rcfile_opts[None]
+
+ # Remove quotes at ends of all strings (used to protect spaces)
+ typeconv[unquote_ends] = typeconv[None]
+ del typeconv[None]
+
+ # Build the list we'll use to make all config decisions with defaults:
+ opts_all = opts_def.copy()
+ opts_all.update(rc_def)
+
+ # Build conflict resolver for recursive loading of config files:
+ # - preserve means the outermost file maintains the value, it is not
+ # overwritten if an included file has the same key.
+ # - add_flip applies + to the two values, so it better make sense to add
+ # those types of keys. But it flips them first so that things loaded
+ # deeper in the inclusion chain have lower precedence.
+ conflict = {'preserve': ' '.join([ typeconv[int],
+ typeconv[unquote_ends] ]),
+ 'add_flip': ' '.join([ typeconv[qwflat],
+ typeconv[qw_lol],
+ typeconv[list_strings] ])
+ }
+
+ # Now actually process the command line
+ getopt = DPyGetOpt.DPyGetOpt()
+ getopt.setIgnoreCase(0)
+
+ getopt.parseConfiguration(opts_names)
+
+ try:
+ getopt.processArguments(argv)
+ except DPyGetOpt.ArgumentError, exc:
+ print cmd_line_usage
+ warn('\nError in Arguments: "%s"' % exc)
+ sys.exit(1)
+
+ # convert the options dict to a struct for much lighter syntax later
+ opts = Struct(getopt.optionValues)
+ args = getopt.freeValues
+
+ # this is the struct (which has default values at this point) with which
+ # we make all decisions:
+ opts_all.update(opts)
+
+ # Options that force an immediate exit
+ if opts_all.help:
+ page(cmd_line_usage)
+ sys.exit()
+
+ if opts_all.Version:
+ print Release.version
+ sys.exit()
+
+ if opts_all.magic_docstrings:
+ IP.magic_magic('-latex')
+ sys.exit()
+
+ # add personal ipythondir to sys.path so that users can put things in
+ # there for customization
+ sys.path.append(os.path.abspath(opts_all.ipythondir))
+
+ # Create user config directory if it doesn't exist. This must be done
+ # *after* getting the cmd line options.
+ if not os.path.isdir(opts_all.ipythondir):
+ IP.user_setup(opts_all.ipythondir,rc_suffix,'install')
+
+ # upgrade user config files while preserving a copy of the originals
+ if opts_all.upgrade:
+ IP.user_setup(opts_all.ipythondir,rc_suffix,'upgrade')
+
+ # check mutually exclusive options in the *original* command line
+ mutex_opts(opts,[qw('log logfile'),qw('rcfile profile'),
+ qw('classic profile'),qw('classic rcfile')])
+
+ #---------------------------------------------------------------------------
+ # Log replay
+
+ # if -logplay, we need to 'become' the other session. That basically means
+ # replacing the current command line environment with that of the old
+ # session and moving on.
+
+ # this is needed so that later we know we're in session reload mode, as
+ # opts_all will get overwritten:
+ load_logplay = 0
+
+ if opts_all.logplay:
+ load_logplay = opts_all.logplay
+ opts_debug_save = opts_all.debug
+ try:
+ logplay = open(opts_all.logplay)
+ except IOError:
+ if opts_all.debug: IP.InteractiveTB()
+ warn('Could not open logplay file '+`opts_all.logplay`)
+ # restore state as if nothing had happened and move on, but make
+ # sure that later we don't try to actually load the session file
+ logplay = None
+ load_logplay = 0
+ del opts_all.logplay
+ else:
+ try:
+ logplay.readline()
+ logplay.readline();
+ # this reloads that session's command line
+ cmd = logplay.readline()[6:]
+ exec cmd
+ # restore the true debug flag given so that the process of
+ # session loading itself can be monitored.
+ opts.debug = opts_debug_save
+ # save the logplay flag so later we don't overwrite the log
+ opts.logplay = load_logplay
+ # now we must update our own structure with defaults
+ opts_all.update(opts)
+ # now load args
+ cmd = logplay.readline()[6:]
+ exec cmd
+ logplay.close()
+ except:
+ logplay.close()
+ if opts_all.debug: IP.InteractiveTB()
+ warn("Logplay file lacking full configuration information.\n"
+ "I'll try to read it, but some things may not work.")
+
+ #-------------------------------------------------------------------------
+ # set up output traps: catch all output from files, being run, modules
+ # loaded, etc. Then give it to the user in a clean form at the end.
+
+ msg_out = 'Output messages. '
+ msg_err = 'Error messages. '
+ msg_sep = '\n'
+ msg = Struct(config = OutputTrap('Configuration Loader',msg_out,
+ msg_err,msg_sep,debug,
+ quiet_out=1),
+ user_exec = OutputTrap('User File Execution',msg_out,
+ msg_err,msg_sep,debug),
+ logplay = OutputTrap('Log Loader',msg_out,
+ msg_err,msg_sep,debug),
+ summary = ''
+ )
+
+ #-------------------------------------------------------------------------
+ # Process user ipythonrc-type configuration files
+
+ # turn on output trapping and log to msg.config
+ # remember that with debug on, trapping is actually disabled
+ msg.config.trap_all()
+
+ # look for rcfile in current or default directory
+ try:
+ opts_all.rcfile = filefind(opts_all.rcfile,opts_all.ipythondir)
+ except IOError:
+ if opts_all.debug: IP.InteractiveTB()
+ warn('Configuration file %s not found. Ignoring request.'
+ % (opts_all.rcfile) )
+
+ # 'profiles' are a shorthand notation for config filenames
+ profile_handled_by_legacy = False
+ if opts_all.profile:
+
+ try:
+ opts_all.rcfile = filefind('ipythonrc-' + opts_all.profile
+ + rc_suffix,
+ opts_all.ipythondir)
+ profile_handled_by_legacy = True
+ except IOError:
+ if opts_all.debug: IP.InteractiveTB()
+ opts.profile = '' # remove profile from options if invalid
+ # We won't warn anymore, primary method is ipy_profile_PROFNAME
+ # which does trigger a warning.
+
+ # load the config file
+ rcfiledata = None
+ if opts_all.quick:
+ print 'Launching IPython in quick mode. No config file read.'
+ elif opts_all.rcfile:
+ try:
+ cfg_loader = ConfigLoader(conflict)
+ rcfiledata = cfg_loader.load(opts_all.rcfile,typeconv,
+ 'include',opts_all.ipythondir,
+ purge = 1,
+ unique = conflict['preserve'])
+ except:
+ IP.InteractiveTB()
+ warn('Problems loading configuration file '+
+ `opts_all.rcfile`+
+ '\nStarting with default -bare bones- configuration.')
+ else:
+ warn('No valid configuration file found in either currrent directory\n'+
+ 'or in the IPython config. directory: '+`opts_all.ipythondir`+
+ '\nProceeding with internal defaults.')
+
+ #------------------------------------------------------------------------
+ # Set exception handlers in mode requested by user.
+ otrap = OutputTrap(trap_out=1) # trap messages from magic_xmode
+ IP.magic_xmode(opts_all.xmode)
+ otrap.release_out()
+
+ #------------------------------------------------------------------------
+ # Execute user config
+
+ # Create a valid config structure with the right precedence order:
+ # defaults < rcfile < command line. This needs to be in the instance, so
+ # that method calls below that rely on it find it.
+ IP.rc = rc_def.copy()
+
+ # Work with a local alias inside this routine to avoid unnecessary
+ # attribute lookups.
+ IP_rc = IP.rc
+
+ IP_rc.update(opts_def)
+ if rcfiledata:
+ # now we can update
+ IP_rc.update(rcfiledata)
+ IP_rc.update(opts)
+ IP_rc.update(rc_override)
+
+ # Store the original cmd line for reference:
+ IP_rc.opts = opts
+ IP_rc.args = args
+
+ # create a *runtime* Struct like rc for holding parameters which may be
+ # created and/or modified by runtime user extensions.
+ IP.runtime_rc = Struct()
+
+ # from this point on, all config should be handled through IP_rc,
+ # opts* shouldn't be used anymore.
+
+
+ # update IP_rc with some special things that need manual
+ # tweaks. Basically options which affect other options. I guess this
+ # should just be written so that options are fully orthogonal and we
+ # wouldn't worry about this stuff!
+
+ if IP_rc.classic:
+ IP_rc.quick = 1
+ IP_rc.cache_size = 0
+ IP_rc.pprint = 0
+ IP_rc.prompt_in1 = '>>> '
+ IP_rc.prompt_in2 = '... '
+ IP_rc.prompt_out = ''
+ IP_rc.separate_in = IP_rc.separate_out = IP_rc.separate_out2 = '0'
+ IP_rc.colors = 'NoColor'
+ IP_rc.xmode = 'Plain'
+
+ IP.pre_config_initialization()
+ # configure readline
+
+ # update exception handlers with rc file status
+ otrap.trap_out() # I don't want these messages ever.
+ IP.magic_xmode(IP_rc.xmode)
+ otrap.release_out()
+
+ # activate logging if requested and not reloading a log
+ if IP_rc.logplay:
+ IP.magic_logstart(IP_rc.logplay + ' append')
+ elif IP_rc.logfile:
+ IP.magic_logstart(IP_rc.logfile)
+ elif IP_rc.log:
+ IP.magic_logstart()
+
+ # find user editor so that it we don't have to look it up constantly
+ if IP_rc.editor.strip()=='0':
+ try:
+ ed = os.environ['EDITOR']
+ except KeyError:
+ if os.name == 'posix':
+ ed = 'vi' # the only one guaranteed to be there!
+ else:
+ ed = 'notepad' # same in Windows!
+ IP_rc.editor = ed
+
+ # Keep track of whether this is an embedded instance or not (useful for
+ # post-mortems).
+ IP_rc.embedded = IP.embedded
+
+ # Recursive reload
+ try:
+ from IPython import deep_reload
+ if IP_rc.deep_reload:
+ __builtin__.reload = deep_reload.reload
+ else:
+ __builtin__.dreload = deep_reload.reload
+ del deep_reload
+ except ImportError:
+ pass
+
+ # Save the current state of our namespace so that the interactive shell
+ # can later know which variables have been created by us from config files
+ # and loading. This way, loading a file (in any way) is treated just like
+ # defining things on the command line, and %who works as expected.
+
+ # DON'T do anything that affects the namespace beyond this point!
+ IP.internal_ns.update(__main__.__dict__)
+
+ #IP.internal_ns.update(locals()) # so our stuff doesn't show up in %who
+
+ # Now run through the different sections of the users's config
+ if IP_rc.debug:
+ print 'Trying to execute the following configuration structure:'
+ print '(Things listed first are deeper in the inclusion tree and get'
+ print 'loaded first).\n'
+ pprint(IP_rc.__dict__)
+
+ for mod in IP_rc.import_mod:
+ try:
+ exec 'import '+mod in IP.user_ns
+ except :
+ IP.InteractiveTB()
+ import_fail_info(mod)
+
+ for mod_fn in IP_rc.import_some:
+ if not mod_fn == []:
+ mod,fn = mod_fn[0],','.join(mod_fn[1:])
+ try:
+ exec 'from '+mod+' import '+fn in IP.user_ns
+ except :
+ IP.InteractiveTB()
+ import_fail_info(mod,fn)
+
+ for mod in IP_rc.import_all:
+ try:
+ exec 'from '+mod+' import *' in IP.user_ns
+ except :
+ IP.InteractiveTB()
+ import_fail_info(mod)
+
+ for code in IP_rc.execute:
+ try:
+ exec code in IP.user_ns
+ except:
+ IP.InteractiveTB()
+ warn('Failure executing code: ' + `code`)
+
+ # Execute the files the user wants in ipythonrc
+ for file in IP_rc.execfile:
+ try:
+ file = filefind(file,sys.path+[IPython_dir])
+ except IOError:
+ warn(itpl('File $file not found. Skipping it.'))
+ else:
+ IP.safe_execfile(os.path.expanduser(file),IP.user_ns)
+
+ # finally, try importing ipy_*_conf for final configuration
+ try:
+ import ipy_system_conf
+ except ImportError:
+ if opts_all.debug: IP.InteractiveTB()
+ warn("Could not import 'ipy_system_conf'")
+ except:
+ IP.InteractiveTB()
+ import_fail_info('ipy_system_conf')
+
+ # only import prof module if ipythonrc-PROF was not found
+ if opts_all.profile and not profile_handled_by_legacy:
+ profmodname = 'ipy_profile_' + opts_all.profile
+ try:
+ force_import(profmodname)
+ except:
+ IP.InteractiveTB()
+ print "Error importing",profmodname,\
+ "- perhaps you should run %upgrade?"
+ import_fail_info(profmodname)
+ else:
+ opts.profile = opts_all.profile
+ else:
+ force_import('ipy_profile_none')
+ # XXX - this is wrong: ipy_user_conf should not be loaded unconditionally,
+ # since the user could have specified a config file path by hand.
+ try:
+ force_import('ipy_user_conf')
+ except:
+ conf = opts_all.ipythondir + "/ipy_user_conf.py"
+ IP.InteractiveTB()
+ if not os.path.isfile(conf):
+ warn(conf + ' does not exist, please run %upgrade!')
+
+ import_fail_info("ipy_user_conf")
+
+ # Define the history file for saving commands in between sessions
+ try:
+ histfname = 'history-%s' % opts.profile
+ except AttributeError:
+ histfname = 'history'
+ IP.histfile = os.path.join(opts_all.ipythondir,histfname)
+
+ # finally, push the argv to options again to ensure highest priority
+ IP_rc.update(opts)
+
+ # release stdout and stderr and save config log into a global summary
+ msg.config.release_all()
+ if IP_rc.messages:
+ msg.summary += msg.config.summary_all()
+
+ #------------------------------------------------------------------------
+ # Setup interactive session
+
+ # Now we should be fully configured. We can then execute files or load
+ # things only needed for interactive use. Then we'll open the shell.
+
+ # Take a snapshot of the user namespace before opening the shell. That way
+ # we'll be able to identify which things were interactively defined and
+ # which were defined through config files.
+ IP.user_config_ns.update(IP.user_ns)
+
+ # Force reading a file as if it were a session log. Slower but safer.
+ if load_logplay:
+ print 'Replaying log...'
+ try:
+ if IP_rc.debug:
+ logplay_quiet = 0
+ else:
+ logplay_quiet = 1
+
+ msg.logplay.trap_all()
+ IP.safe_execfile(load_logplay,IP.user_ns,
+ islog = 1, quiet = logplay_quiet)
+ msg.logplay.release_all()
+ if IP_rc.messages:
+ msg.summary += msg.logplay.summary_all()
+ except:
+ warn('Problems replaying logfile %s.' % load_logplay)
+ IP.InteractiveTB()
+
+ # Load remaining files in command line
+ msg.user_exec.trap_all()
+
+ # Do NOT execute files named in the command line as scripts to be loaded
+ # by embedded instances. Doing so has the potential for an infinite
+ # recursion if there are exceptions thrown in the process.
+
+ # XXX FIXME: the execution of user files should be moved out to after
+ # ipython is fully initialized, just as if they were run via %run at the
+ # ipython prompt. This would also give them the benefit of ipython's
+ # nice tracebacks.
+
+ if (not embedded and IP_rc.args and
+ not IP_rc.args[0].lower().endswith('.ipy')):
+ name_save = IP.user_ns['__name__']
+ IP.user_ns['__name__'] = '__main__'
+ # Set our own excepthook in case the user code tries to call it
+ # directly. This prevents triggering the IPython crash handler.
+ old_excepthook,sys.excepthook = sys.excepthook, IP.excepthook
+
+ save_argv = sys.argv[1:] # save it for later restoring
+
+ sys.argv = args
+
+ try:
+ IP.safe_execfile(args[0], IP.user_ns)
+ finally:
+ # Reset our crash handler in place
+ sys.excepthook = old_excepthook
+ sys.argv[:] = save_argv
+ IP.user_ns['__name__'] = name_save
+
+ msg.user_exec.release_all()
+
+ if IP_rc.messages:
+ msg.summary += msg.user_exec.summary_all()
+
+ # since we can't specify a null string on the cmd line, 0 is the equivalent:
+ if IP_rc.nosep:
+ IP_rc.separate_in = IP_rc.separate_out = IP_rc.separate_out2 = '0'
+ if IP_rc.separate_in == '0': IP_rc.separate_in = ''
+ if IP_rc.separate_out == '0': IP_rc.separate_out = ''
+ if IP_rc.separate_out2 == '0': IP_rc.separate_out2 = ''
+ IP_rc.separate_in = IP_rc.separate_in.replace('\\n','\n')
+ IP_rc.separate_out = IP_rc.separate_out.replace('\\n','\n')
+ IP_rc.separate_out2 = IP_rc.separate_out2.replace('\\n','\n')
+
+ # Determine how many lines at the bottom of the screen are needed for
+ # showing prompts, so we can know wheter long strings are to be printed or
+ # paged:
+ num_lines_bot = IP_rc.separate_in.count('\n')+1
+ IP_rc.screen_length = IP_rc.screen_length - num_lines_bot
+
+ # configure startup banner
+ if IP_rc.c: # regular python doesn't print the banner with -c
+ IP_rc.banner = 0
+ if IP_rc.banner:
+ BANN_P = IP.BANNER_PARTS
+ else:
+ BANN_P = []
+
+ if IP_rc.profile: BANN_P.append('IPython profile: %s\n' % IP_rc.profile)
+
+ # add message log (possibly empty)
+ if msg.summary: BANN_P.append(msg.summary)
+ # Final banner is a string
+ IP.BANNER = '\n'.join(BANN_P)
+
+ # Finalize the IPython instance. This assumes the rc structure is fully
+ # in place.
+ IP.post_config_initialization()
+
+ return IP
+#************************ end of file <ipmaker.py> **************************
diff --git a/IPython/ipstruct.py b/IPython/ipstruct.py
new file mode 100644
index 0000000..ef11c47
--- /dev/null
+++ b/IPython/ipstruct.py
@@ -0,0 +1,416 @@
+# -*- coding: utf-8 -*-
+"""Mimic C structs with lots of extra functionality.
+"""
+
+#*****************************************************************************
+# Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#*****************************************************************************
+
+__all__ = ['Struct']
+
+import types
+import pprint
+
+from IPython.genutils import list2dict2
+
+class Struct:
+ """Class to mimic C structs but also provide convenient dictionary-like
+ functionality.
+
+ Instances can be initialized with a dictionary, a list of key=value pairs
+ or both. If both are present, the dictionary must come first.
+
+ Because Python classes provide direct assignment to their members, it's
+ easy to overwrite normal methods (S.copy = 1 would destroy access to
+ S.copy()). For this reason, all builtin method names are protected and
+ can't be assigned to. An attempt to do s.copy=1 or s['copy']=1 will raise
+ a KeyError exception. If you really want to, you can bypass this
+ protection by directly assigning to __dict__: s.__dict__['copy']=1 will
+ still work. Doing this will break functionality, though. As in most of
+ Python, namespace protection is weakly enforced, so feel free to shoot
+ yourself if you really want to.
+
+ Note that this class uses more memory and is *much* slower than a regular
+ dictionary, so be careful in situations where memory or performance are
+ critical. But for day to day use it should behave fine. It is particularly
+ convenient for storing configuration data in programs.
+
+ +,+=,- and -= are implemented. +/+= do merges (non-destructive updates),
+ -/-= remove keys from the original. See the method descripitions.
+
+ This class allows a quick access syntax: both s.key and s['key'] are
+ valid. This syntax has a limitation: each 'key' has to be explicitly
+ accessed by its original name. The normal s.key syntax doesn't provide
+ access to the keys via variables whose values evaluate to the desired
+ keys. An example should clarify this:
+
+ Define a dictionary and initialize both with dict and k=v pairs:
+ >>> d={'a':1,'b':2}
+ >>> s=Struct(d,hi=10,ho=20)
+
+ The return of __repr__ can be used to create a new instance:
+ >>> s
+ Struct({'__allownew': True, 'a': 1, 'b': 2, 'hi': 10, 'ho': 20})
+
+ Note: the special '__allownew' key is used for internal purposes.
+
+ __str__ (called by print) shows it's not quite a regular dictionary:
+ >>> print s
+ Struct({'__allownew': True, 'a': 1, 'b': 2, 'hi': 10, 'ho': 20})
+
+ Access by explicitly named key with dot notation:
+ >>> s.a
+ 1
+
+ Or like a dictionary:
+ >>> s['a']
+ 1
+
+ If you want a variable to hold the key value, only dictionary access works:
+ >>> key='hi'
+ >>> s.key
+ Traceback (most recent call last):
+ File "<stdin>", line 1, in ?
+ AttributeError: Struct instance has no attribute 'key'
+
+ >>> s[key]
+ 10
+
+ Another limitation of the s.key syntax (and Struct(key=val)
+ initialization): keys can't be numbers. But numeric keys can be used and
+ accessed using the dictionary syntax. Again, an example:
+
+ This doesn't work (prompt changed to avoid confusing the test system):
+ ->> s=Struct(4='hi')
+ Traceback (most recent call last):
+ ...
+ SyntaxError: keyword can't be an expression
+
+ But this does:
+ >>> s=Struct()
+ >>> s[4]='hi'
+ >>> s
+ Struct({4: 'hi', '__allownew': True})
+ >>> s[4]
+ 'hi'
+ """
+
+ # Attributes to which __setitem__ and __setattr__ will block access.
+ # Note: much of this will be moot in Python 2.2 and will be done in a much
+ # cleaner way.
+ __protected = ('copy dict dictcopy get has_attr has_key items keys '
+ 'merge popitem setdefault update values '
+ '__make_dict __dict_invert ').split()
+
+ def __init__(self,dict=None,**kw):
+ """Initialize with a dictionary, another Struct, or by giving
+ explicitly the list of attributes.
+
+ Both can be used, but the dictionary must come first:
+ Struct(dict), Struct(k1=v1,k2=v2) or Struct(dict,k1=v1,k2=v2).
+ """
+ self.__dict__['__allownew'] = True
+ if dict is None:
+ dict = {}
+ if isinstance(dict,Struct):
+ dict = dict.dict()
+ elif dict and type(dict) is not types.DictType:
+ raise TypeError,\
+ 'Initialize with a dictionary or key=val pairs.'
+ dict.update(kw)
+ # do the updating by hand to guarantee that we go through the
+ # safety-checked __setitem__
+ for k,v in dict.items():
+ self[k] = v
+
+
+ def __setitem__(self,key,value):
+ """Used when struct[key] = val calls are made."""
+ if key in Struct.__protected:
+ raise KeyError,'Key '+`key`+' is a protected key of class Struct.'
+ if not self['__allownew'] and key not in self.__dict__:
+ raise KeyError(
+ "Can't create unknown attribute %s - Check for typos, or use allow_new_attr to create new attributes!" %
+ key)
+
+ self.__dict__[key] = value
+
+ def __setattr__(self, key, value):
+ """Used when struct.key = val calls are made."""
+ self.__setitem__(key,value)
+
+ def __str__(self):
+ """Gets called by print."""
+
+ return 'Struct('+ pprint.pformat(self.__dict__)+')'
+
+ def __repr__(self):
+ """Gets called by repr.
+
+ A Struct can be recreated with S_new=eval(repr(S_old))."""
+ return self.__str__()
+
+ def __getitem__(self,key):
+ """Allows struct[key] access."""
+ return self.__dict__[key]
+
+ def __contains__(self,key):
+ """Allows use of the 'in' operator.
+
+ Examples:
+ >>> s = Struct(x=1)
+ >>> 'x' in s
+ True
+ >>> 'y' in s
+ False
+ >>> s[4] = None
+ >>> 4 in s
+ True
+ >>> s.z = None
+ >>> 'z' in s
+ True
+ """
+ return key in self.__dict__
+
+ def __iadd__(self,other):
+ """S += S2 is a shorthand for S.merge(S2)."""
+ self.merge(other)
+ return self
+
+ def __add__(self,other):
+ """S + S2 -> New Struct made form S and S.merge(S2)"""
+ Sout = self.copy()
+ Sout.merge(other)
+ return Sout
+
+ def __sub__(self,other):
+ """Return S1-S2, where all keys in S2 have been deleted (if present)
+ from S1."""
+ Sout = self.copy()
+ Sout -= other
+ return Sout
+
+ def __isub__(self,other):
+ """Do in place S = S - S2, meaning all keys in S2 have been deleted
+ (if present) from S1."""
+
+ for k in other.keys():
+ if self.has_key(k):
+ del self.__dict__[k]
+
+ def __make_dict(self,__loc_data__,**kw):
+ "Helper function for update and merge. Return a dict from data."
+
+ if __loc_data__ == None:
+ dict = {}
+ elif type(__loc_data__) is types.DictType:
+ dict = __loc_data__
+ elif isinstance(__loc_data__,Struct):
+ dict = __loc_data__.__dict__
+ else:
+ raise TypeError, 'Update with a dict, a Struct or key=val pairs.'
+ if kw:
+ dict.update(kw)
+ return dict
+
+ def __dict_invert(self,dict):
+ """Helper function for merge. Takes a dictionary whose values are
+ lists and returns a dict. with the elements of each list as keys and
+ the original keys as values."""
+
+ outdict = {}
+ for k,lst in dict.items():
+ if type(lst) is types.StringType:
+ lst = lst.split()
+ for entry in lst:
+ outdict[entry] = k
+ return outdict
+
+ def clear(self):
+ """Clear all attributes."""
+ self.__dict__.clear()
+
+ def copy(self):
+ """Return a (shallow) copy of a Struct."""
+ return Struct(self.__dict__.copy())
+
+ def dict(self):
+ """Return the Struct's dictionary."""
+ return self.__dict__
+
+ def dictcopy(self):
+ """Return a (shallow) copy of the Struct's dictionary."""
+ return self.__dict__.copy()
+
+ def popitem(self):
+ """S.popitem() -> (k, v), remove and return some (key, value) pair as
+ a 2-tuple; but raise KeyError if S is empty."""
+ return self.__dict__.popitem()
+
+ def update(self,__loc_data__=None,**kw):
+ """Update (merge) with data from another Struct or from a dictionary.
+ Optionally, one or more key=value pairs can be given at the end for
+ direct update."""
+
+ # The funny name __loc_data__ is to prevent a common variable name
+ # which could be a fieled of a Struct to collide with this
+ # parameter. The problem would arise if the function is called with a
+ # keyword with this same name that a user means to add as a Struct
+ # field.
+ newdict = Struct.__make_dict(self,__loc_data__,**kw)
+ for k,v in newdict.iteritems():
+ self[k] = v
+
+ def merge(self,__loc_data__=None,__conflict_solve=None,**kw):
+ """S.merge(data,conflict,k=v1,k=v2,...) -> merge data and k=v into S.
+
+ This is similar to update(), but much more flexible. First, a dict is
+ made from data+key=value pairs. When merging this dict with the Struct
+ S, the optional dictionary 'conflict' is used to decide what to do.
+
+ If conflict is not given, the default behavior is to preserve any keys
+ with their current value (the opposite of the update method's
+ behavior).
+
+ conflict is a dictionary of binary functions which will be used to
+ solve key conflicts. It must have the following structure:
+
+ conflict == { fn1 : [Skey1,Skey2,...], fn2 : [Skey3], etc }
+
+ Values must be lists or whitespace separated strings which are
+ automatically converted to lists of strings by calling string.split().
+
+ Each key of conflict is a function which defines a policy for
+ resolving conflicts when merging with the input data. Each fn must be
+ a binary function which returns the desired outcome for a key
+ conflict. These functions will be called as fn(old,new).
+
+ An example is probably in order. Suppose you are merging the struct S
+ with a dict D and the following conflict policy dict:
+
+ S.merge(D,{fn1:['a','b',4], fn2:'key_c key_d'})
+
+ If the key 'a' is found in both S and D, the merge method will call:
+
+ S['a'] = fn1(S['a'],D['a'])
+
+ As a convenience, merge() provides five (the most commonly needed)
+ pre-defined policies: preserve, update, add, add_flip and add_s. The
+ easiest explanation is their implementation:
+
+ preserve = lambda old,new: old
+ update = lambda old,new: new
+ add = lambda old,new: old + new
+ add_flip = lambda old,new: new + old # note change of order!
+ add_s = lambda old,new: old + ' ' + new # only works for strings!
+
+ You can use those four words (as strings) as keys in conflict instead
+ of defining them as functions, and the merge method will substitute
+ the appropriate functions for you. That is, the call
+
+ S.merge(D,{'preserve':'a b c','add':[4,5,'d'],my_function:[6]})
+
+ will automatically substitute the functions preserve and add for the
+ names 'preserve' and 'add' before making any function calls.
+
+ For more complicated conflict resolution policies, you still need to
+ construct your own functions. """
+
+ data_dict = Struct.__make_dict(self,__loc_data__,**kw)
+
+ # policies for conflict resolution: two argument functions which return
+ # the value that will go in the new struct
+ preserve = lambda old,new: old
+ update = lambda old,new: new
+ add = lambda old,new: old + new
+ add_flip = lambda old,new: new + old # note change of order!
+ add_s = lambda old,new: old + ' ' + new
+
+ # default policy is to keep current keys when there's a conflict
+ conflict_solve = list2dict2(self.keys(),default = preserve)
+
+ # the conflict_solve dictionary is given by the user 'inverted': we
+ # need a name-function mapping, it comes as a function -> names
+ # dict. Make a local copy (b/c we'll make changes), replace user
+ # strings for the three builtin policies and invert it.
+ if __conflict_solve:
+ inv_conflict_solve_user = __conflict_solve.copy()
+ for name, func in [('preserve',preserve), ('update',update),
+ ('add',add), ('add_flip',add_flip),
+ ('add_s',add_s)]:
+ if name in inv_conflict_solve_user.keys():
+ inv_conflict_solve_user[func] = inv_conflict_solve_user[name]
+ del inv_conflict_solve_user[name]
+ conflict_solve.update(Struct.__dict_invert(self,inv_conflict_solve_user))
+ #print 'merge. conflict_solve: '; pprint(conflict_solve) # dbg
+ #print '*'*50,'in merger. conflict_solver:'; pprint(conflict_solve)
+ for key in data_dict:
+ if key not in self:
+ self[key] = data_dict[key]
+ else:
+ self[key] = conflict_solve[key](self[key],data_dict[key])
+
+ def has_key(self,key):
+ """Like has_key() dictionary method."""
+ return self.__dict__.has_key(key)
+
+ def hasattr(self,key):
+ """hasattr function available as a method.
+
+ Implemented like has_key, to make sure that all available keys in the
+ internal dictionary of the Struct appear also as attributes (even
+ numeric keys)."""
+ return self.__dict__.has_key(key)
+
+ def items(self):
+ """Return the items in the Struct's dictionary, in the same format
+ as a call to {}.items()."""
+ return self.__dict__.items()
+
+ def keys(self):
+ """Return the keys in the Struct's dictionary, in the same format
+ as a call to {}.keys()."""
+ return self.__dict__.keys()
+
+ def values(self,keys=None):
+ """Return the values in the Struct's dictionary, in the same format
+ as a call to {}.values().
+
+ Can be called with an optional argument keys, which must be a list or
+ tuple of keys. In this case it returns only the values corresponding
+ to those keys (allowing a form of 'slicing' for Structs)."""
+ if not keys:
+ return self.__dict__.values()
+ else:
+ ret=[]
+ for k in keys:
+ ret.append(self[k])
+ return ret
+
+ def get(self,attr,val=None):
+ """S.get(k[,d]) -> S[k] if k in S, else d. d defaults to None."""
+ try:
+ return self[attr]
+ except KeyError:
+ return val
+
+ def setdefault(self,attr,val=None):
+ """S.setdefault(k[,d]) -> S.get(k,d), also set S[k]=d if k not in S"""
+ if not self.has_key(attr):
+ self[attr] = val
+ return self.get(attr,val)
+
+ def allow_new_attr(self, allow = True):
+ """ Set whether new attributes can be created inside struct
+
+ This can be used to catch typos by verifying that the attribute user
+ tries to change already exists in this Struct.
+ """
+ self['__allownew'] = allow
+
+
+# end class Struct
+
diff --git a/IPython/irunner.py b/IPython/irunner.py
new file mode 100644
index 0000000..7539802
--- /dev/null
+++ b/IPython/irunner.py
@@ -0,0 +1,441 @@
+#!/usr/bin/env python
+"""Module for interactively running scripts.
+
+This module implements classes for interactively running scripts written for
+any system with a prompt which can be matched by a regexp suitable for
+pexpect. It can be used to run as if they had been typed up interactively, an
+arbitrary series of commands for the target system.
+
+The module includes classes ready for IPython (with the default prompts),
+plain Python and SAGE, but making a new one is trivial. To see how to use it,
+simply run the module as a script:
+
+./irunner.py --help
+
+
+This is an extension of Ken Schutte <kschutte-AT-csail.mit.edu>'s script
+contributed on the ipython-user list:
+
+http://scipy.net/pipermail/ipython-user/2006-May/001705.html
+
+
+NOTES:
+
+ - This module requires pexpect, available in most linux distros, or which can
+ be downloaded from
+
+ http://pexpect.sourceforge.net
+
+ - Because pexpect only works under Unix or Windows-Cygwin, this has the same
+ limitations. This means that it will NOT work under native windows Python.
+"""
+
+# Stdlib imports
+import optparse
+import os
+import sys
+
+# Third-party modules.
+import pexpect
+
+# Global usage strings, to avoid indentation issues when typing it below.
+USAGE = """
+Interactive script runner, type: %s
+
+runner [opts] script_name
+"""
+
+def pexpect_monkeypatch():
+ """Patch pexpect to prevent unhandled exceptions at VM teardown.
+
+ Calling this function will monkeypatch the pexpect.spawn class and modify
+ its __del__ method to make it more robust in the face of failures that can
+ occur if it is called when the Python VM is shutting down.
+
+ Since Python may fire __del__ methods arbitrarily late, it's possible for
+ them to execute during the teardown of the Python VM itself. At this
+ point, various builtin modules have been reset to None. Thus, the call to
+ self.close() will trigger an exception because it tries to call os.close(),
+ and os is now None.
+ """
+
+ if pexpect.__version__[:3] >= '2.2':
+ # No need to patch, fix is already the upstream version.
+ return
+
+ def __del__(self):
+ """This makes sure that no system resources are left open.
+ Python only garbage collects Python objects. OS file descriptors
+ are not Python objects, so they must be handled explicitly.
+ If the child file descriptor was opened outside of this class
+ (passed to the constructor) then this does not close it.
+ """
+ if not self.closed:
+ try:
+ self.close()
+ except AttributeError:
+ pass
+
+ pexpect.spawn.__del__ = __del__
+
+pexpect_monkeypatch()
+
+# The generic runner class
+class InteractiveRunner(object):
+ """Class to run a sequence of commands through an interactive program."""
+
+ def __init__(self,program,prompts,args=None,out=sys.stdout,echo=True):
+ """Construct a runner.
+
+ Inputs:
+
+ - program: command to execute the given program.
+
+ - prompts: a list of patterns to match as valid prompts, in the
+ format used by pexpect. This basically means that it can be either
+ a string (to be compiled as a regular expression) or a list of such
+ (it must be a true list, as pexpect does type checks).
+
+ If more than one prompt is given, the first is treated as the main
+ program prompt and the others as 'continuation' prompts, like
+ python's. This means that blank lines in the input source are
+ ommitted when the first prompt is matched, but are NOT ommitted when
+ the continuation one matches, since this is how python signals the
+ end of multiline input interactively.
+
+ Optional inputs:
+
+ - args(None): optional list of strings to pass as arguments to the
+ child program.
+
+ - out(sys.stdout): if given, an output stream to be used when writing
+ output. The only requirement is that it must have a .write() method.
+
+ Public members not parameterized in the constructor:
+
+ - delaybeforesend(0): Newer versions of pexpect have a delay before
+ sending each new input. For our purposes here, it's typically best
+ to just set this to zero, but if you encounter reliability problems
+ or want an interactive run to pause briefly at each prompt, just
+ increase this value (it is measured in seconds). Note that this
+ variable is not honored at all by older versions of pexpect.
+ """
+
+ self.program = program
+ self.prompts = prompts
+ if args is None: args = []
+ self.args = args
+ self.out = out
+ self.echo = echo
+ # Other public members which we don't make as parameters, but which
+ # users may occasionally want to tweak
+ self.delaybeforesend = 0
+
+ # Create child process and hold on to it so we don't have to re-create
+ # for every single execution call
+ c = self.child = pexpect.spawn(self.program,self.args,timeout=None)
+ c.delaybeforesend = self.delaybeforesend
+ # pexpect hard-codes the terminal size as (24,80) (rows,columns).
+ # This causes problems because any line longer than 80 characters gets
+ # completely overwrapped on the printed outptut (even though
+ # internally the code runs fine). We reset this to 99 rows X 200
+ # columns (arbitrarily chosen), which should avoid problems in all
+ # reasonable cases.
+ c.setwinsize(99,200)
+
+ def close(self):
+ """close child process"""
+
+ self.child.close()
+
+ def run_file(self,fname,interact=False,get_output=False):
+ """Run the given file interactively.
+
+ Inputs:
+
+ -fname: name of the file to execute.
+
+ See the run_source docstring for the meaning of the optional
+ arguments."""
+
+ fobj = open(fname,'r')
+ try:
+ out = self.run_source(fobj,interact,get_output)
+ finally:
+ fobj.close()
+ if get_output:
+ return out
+
+ def run_source(self,source,interact=False,get_output=False):
+ """Run the given source code interactively.
+
+ Inputs:
+
+ - source: a string of code to be executed, or an open file object we
+ can iterate over.
+
+ Optional inputs:
+
+ - interact(False): if true, start to interact with the running
+ program at the end of the script. Otherwise, just exit.
+
+ - get_output(False): if true, capture the output of the child process
+ (filtering the input commands out) and return it as a string.
+
+ Returns:
+ A string containing the process output, but only if requested.
+ """
+
+ # if the source is a string, chop it up in lines so we can iterate
+ # over it just as if it were an open file.
+ if not isinstance(source,file):
+ source = source.splitlines(True)
+
+ if self.echo:
+ # normalize all strings we write to use the native OS line
+ # separators.
+ linesep = os.linesep
+ stdwrite = self.out.write
+ write = lambda s: stdwrite(s.replace('\r\n',linesep))
+ else:
+ # Quiet mode, all writes are no-ops
+ write = lambda s: None
+
+ c = self.child
+ prompts = c.compile_pattern_list(self.prompts)
+ prompt_idx = c.expect_list(prompts)
+
+ # Flag whether the script ends normally or not, to know whether we can
+ # do anything further with the underlying process.
+ end_normal = True
+
+ # If the output was requested, store it in a list for return at the end
+ if get_output:
+ output = []
+ store_output = output.append
+
+ for cmd in source:
+ # skip blank lines for all matches to the 'main' prompt, while the
+ # secondary prompts do not
+ if prompt_idx==0 and \
+ (cmd.isspace() or cmd.lstrip().startswith('#')):
+ write(cmd)
+ continue
+
+ #write('AFTER: '+c.after) # dbg
+ write(c.after)
+ c.send(cmd)
+ try:
+ prompt_idx = c.expect_list(prompts)
+ except pexpect.EOF:
+ # this will happen if the child dies unexpectedly
+ write(c.before)
+ end_normal = False
+ break
+
+ write(c.before)
+
+ # With an echoing process, the output we get in c.before contains
+ # the command sent, a newline, and then the actual process output
+ if get_output:
+ store_output(c.before[len(cmd+'\n'):])
+ #write('CMD: <<%s>>' % cmd) # dbg
+ #write('OUTPUT: <<%s>>' % output[-1]) # dbg
+
+ self.out.flush()
+ if end_normal:
+ if interact:
+ c.send('\n')
+ print '<< Starting interactive mode >>',
+ try:
+ c.interact()
+ except OSError:
+ # This is what fires when the child stops. Simply print a
+ # newline so the system prompt is aligned. The extra
+ # space is there to make sure it gets printed, otherwise
+ # OS buffering sometimes just suppresses it.
+ write(' \n')
+ self.out.flush()
+ else:
+ if interact:
+ e="Further interaction is not possible: child process is dead."
+ print >> sys.stderr, e
+
+ # Leave the child ready for more input later on, otherwise select just
+ # hangs on the second invocation.
+ c.send('\n')
+
+ # Return any requested output
+ if get_output:
+ return ''.join(output)
+
+ def main(self,argv=None):
+ """Run as a command-line script."""
+
+ parser = optparse.OptionParser(usage=USAGE % self.__class__.__name__)
+ newopt = parser.add_option
+ newopt('-i','--interact',action='store_true',default=False,
+ help='Interact with the program after the script is run.')
+
+ opts,args = parser.parse_args(argv)
+
+ if len(args) != 1:
+ print >> sys.stderr,"You must supply exactly one file to run."
+ sys.exit(1)
+
+ self.run_file(args[0],opts.interact)
+
+
+# Specific runners for particular programs
+class IPythonRunner(InteractiveRunner):
+ """Interactive IPython runner.
+
+ This initalizes IPython in 'nocolor' mode for simplicity. This lets us
+ avoid having to write a regexp that matches ANSI sequences, though pexpect
+ does support them. If anyone contributes patches for ANSI color support,
+ they will be welcome.
+
+ It also sets the prompts manually, since the prompt regexps for
+ pexpect need to be matched to the actual prompts, so user-customized
+ prompts would break this.
+ """
+
+ def __init__(self,program = 'ipython',args=None,out=sys.stdout,echo=True):
+ """New runner, optionally passing the ipython command to use."""
+
+ args0 = ['-colors','NoColor',
+ '-pi1','In [\\#]: ',
+ '-pi2',' .\\D.: ',
+ '-noterm_title',
+ '-noautoindent']
+ if args is None: args = args0
+ else: args = args0 + args
+ prompts = [r'In \[\d+\]: ',r' \.*: ']
+ InteractiveRunner.__init__(self,program,prompts,args,out,echo)
+
+
+class PythonRunner(InteractiveRunner):
+ """Interactive Python runner."""
+
+ def __init__(self,program='python',args=None,out=sys.stdout,echo=True):
+ """New runner, optionally passing the python command to use."""
+
+ prompts = [r'>>> ',r'\.\.\. ']
+ InteractiveRunner.__init__(self,program,prompts,args,out,echo)
+
+
+class SAGERunner(InteractiveRunner):
+ """Interactive SAGE runner.
+
+ WARNING: this runner only works if you manually configure your SAGE copy
+ to use 'colors NoColor' in the ipythonrc config file, since currently the
+ prompt matching regexp does not identify color sequences."""
+
+ def __init__(self,program='sage',args=None,out=sys.stdout,echo=True):
+ """New runner, optionally passing the sage command to use."""
+
+ prompts = ['sage: ',r'\s*\.\.\. ']
+ InteractiveRunner.__init__(self,program,prompts,args,out,echo)
+
+
+class RunnerFactory(object):
+ """Code runner factory.
+
+ This class provides an IPython code runner, but enforces that only one
+ runner is ever instantiated. The runner is created based on the extension
+ of the first file to run, and it raises an exception if a runner is later
+ requested for a different extension type.
+
+ This ensures that we don't generate example files for doctest with a mix of
+ python and ipython syntax.
+ """
+
+ def __init__(self,out=sys.stdout):
+ """Instantiate a code runner."""
+
+ self.out = out
+ self.runner = None
+ self.runnerClass = None
+
+ def _makeRunner(self,runnerClass):
+ self.runnerClass = runnerClass
+ self.runner = runnerClass(out=self.out)
+ return self.runner
+
+ def __call__(self,fname):
+ """Return a runner for the given filename."""
+
+ if fname.endswith('.py'):
+ runnerClass = PythonRunner
+ elif fname.endswith('.ipy'):
+ runnerClass = IPythonRunner
+ else:
+ raise ValueError('Unknown file type for Runner: %r' % fname)
+
+ if self.runner is None:
+ return self._makeRunner(runnerClass)
+ else:
+ if runnerClass==self.runnerClass:
+ return self.runner
+ else:
+ e='A runner of type %r can not run file %r' % \
+ (self.runnerClass,fname)
+ raise ValueError(e)
+
+
+# Global usage string, to avoid indentation issues if typed in a function def.
+MAIN_USAGE = """
+%prog [options] file_to_run
+
+This is an interface to the various interactive runners available in this
+module. If you want to pass specific options to one of the runners, you need
+to first terminate the main options with a '--', and then provide the runner's
+options. For example:
+
+irunner.py --python -- --help
+
+will pass --help to the python runner. Similarly,
+
+irunner.py --ipython -- --interact script.ipy
+
+will run the script.ipy file under the IPython runner, and then will start to
+interact with IPython at the end of the script (instead of exiting).
+
+The already implemented runners are listed below; adding one for a new program
+is a trivial task, see the source for examples.
+
+WARNING: the SAGE runner only works if you manually configure your SAGE copy
+to use 'colors NoColor' in the ipythonrc config file, since currently the
+prompt matching regexp does not identify color sequences.
+"""
+
+def main():
+ """Run as a command-line script."""
+
+ parser = optparse.OptionParser(usage=MAIN_USAGE)
+ newopt = parser.add_option
+ parser.set_defaults(mode='ipython')
+ newopt('--ipython',action='store_const',dest='mode',const='ipython',
+ help='IPython interactive runner (default).')
+ newopt('--python',action='store_const',dest='mode',const='python',
+ help='Python interactive runner.')
+ newopt('--sage',action='store_const',dest='mode',const='sage',
+ help='SAGE interactive runner.')
+
+ opts,args = parser.parse_args()
+ runners = dict(ipython=IPythonRunner,
+ python=PythonRunner,
+ sage=SAGERunner)
+
+ try:
+ ext = os.path.splitext(args[0])[-1]
+ except IndexError:
+ ext = ''
+ modes = {'.ipy':'ipython',
+ '.py':'python',
+ '.sage':'sage'}
+ mode = modes.get(ext,opts.mode)
+ runners[mode]().main(args)
+
+if __name__ == '__main__':
+ main()
diff --git a/IPython/kernel/__init__.py b/IPython/kernel/__init__.py
new file mode 100755
index 0000000..cd8d856
--- /dev/null
+++ b/IPython/kernel/__init__.py
@@ -0,0 +1,25 @@
+# encoding: utf-8
+"""The IPython1 kernel.
+
+The IPython kernel actually refers to three things:
+
+ * The IPython Engine
+ * The IPython Controller
+ * Clients to the IPython Controller
+
+The kernel module implements the engine, controller and client and all the
+network protocols needed for the various entities to talk to each other.
+
+An end user should probably begin by looking at the `client.py` module
+if they need blocking clients or in `asyncclient.py` if they want asynchronous,
+deferred/Twisted using clients.
+"""
+__docformat__ = "restructuredtext en"
+#-----------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-----------------------------------------------------------------------------
+
+from IPython.kernel.error import TaskRejectError \ No newline at end of file
diff --git a/IPython/kernel/asyncclient.py b/IPython/kernel/asyncclient.py
new file mode 100644
index 0000000..586202b
--- /dev/null
+++ b/IPython/kernel/asyncclient.py
@@ -0,0 +1,41 @@
+# encoding: utf-8
+
+"""Asynchronous clients for the IPython controller.
+
+This module has clients for using the various interfaces of the controller
+in a fully asynchronous manner. This means that you will need to run the
+Twisted reactor yourself and that all methods of the client classes return
+deferreds to the result.
+
+The main methods are are `get_*_client` and `get_client`.
+"""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+from IPython.kernel import codeutil
+from IPython.kernel.clientconnector import ClientConnector
+
+# Other things that the user will need
+from IPython.kernel.task import MapTask, StringTask
+from IPython.kernel.error import CompositeError
+
+#-------------------------------------------------------------------------------
+# Code
+#-------------------------------------------------------------------------------
+
+_client_tub = ClientConnector()
+get_multiengine_client = _client_tub.get_multiengine_client
+get_task_client = _client_tub.get_task_client
+get_client = _client_tub.get_client
+
diff --git a/IPython/kernel/client.py b/IPython/kernel/client.py
new file mode 100644
index 0000000..efbc160
--- /dev/null
+++ b/IPython/kernel/client.py
@@ -0,0 +1,96 @@
+# encoding: utf-8
+
+"""This module contains blocking clients for the controller interfaces.
+
+Unlike the clients in `asyncclient.py`, the clients in this module are fully
+blocking. This means that methods on the clients return the actual results
+rather than a deferred to the result. Also, we manage the Twisted reactor
+for you. This is done by running the reactor in a thread.
+
+The main classes in this module are:
+
+ * MultiEngineClient
+ * TaskClient
+ * Task
+ * CompositeError
+"""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+import sys
+
+# from IPython.tools import growl
+# growl.start("IPython1 Client")
+
+
+from twisted.internet import reactor
+from IPython.kernel.clientconnector import ClientConnector
+from IPython.kernel.twistedutil import ReactorInThread
+from IPython.kernel.twistedutil import blockingCallFromThread
+
+# These enable various things
+from IPython.kernel import codeutil
+import IPython.kernel.magic
+
+# Other things that the user will need
+from IPython.kernel.task import MapTask, StringTask
+from IPython.kernel.error import CompositeError
+
+#-------------------------------------------------------------------------------
+# Code
+#-------------------------------------------------------------------------------
+
+_client_tub = ClientConnector()
+
+
+def get_multiengine_client(furl_or_file=''):
+ """Get the blocking MultiEngine client.
+
+ :Parameters:
+ furl_or_file : str
+ A furl or a filename containing a furl. If empty, the
+ default furl_file will be used
+
+ :Returns:
+ The connected MultiEngineClient instance
+ """
+ client = blockingCallFromThread(_client_tub.get_multiengine_client,
+ furl_or_file)
+ return client.adapt_to_blocking_client()
+
+def get_task_client(furl_or_file=''):
+ """Get the blocking Task client.
+
+ :Parameters:
+ furl_or_file : str
+ A furl or a filename containing a furl. If empty, the
+ default furl_file will be used
+
+ :Returns:
+ The connected TaskClient instance
+ """
+ client = blockingCallFromThread(_client_tub.get_task_client,
+ furl_or_file)
+ return client.adapt_to_blocking_client()
+
+
+MultiEngineClient = get_multiengine_client
+TaskClient = get_task_client
+
+
+
+# Now we start the reactor in a thread
+rit = ReactorInThread()
+rit.setDaemon(True)
+rit.start() \ No newline at end of file
diff --git a/IPython/kernel/clientconnector.py b/IPython/kernel/clientconnector.py
new file mode 100644
index 0000000..595a353
--- /dev/null
+++ b/IPython/kernel/clientconnector.py
@@ -0,0 +1,150 @@
+# encoding: utf-8
+
+"""A class for handling client connections to the controller."""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+from twisted.internet import defer
+
+from IPython.kernel.fcutil import Tub, UnauthenticatedTub
+
+from IPython.kernel.config import config_manager as kernel_config_manager
+from IPython.config.cutils import import_item
+from IPython.kernel.fcutil import find_furl
+
+co = kernel_config_manager.get_config_obj()
+client_co = co['client']
+
+#-------------------------------------------------------------------------------
+# The ClientConnector class
+#-------------------------------------------------------------------------------
+
+class ClientConnector(object):
+ """
+ This class gets remote references from furls and returns the wrapped clients.
+
+ This class is also used in `client.py` and `asyncclient.py` to create
+ a single per client-process Tub.
+ """
+
+ def __init__(self):
+ self._remote_refs = {}
+ self.tub = Tub()
+ self.tub.startService()
+
+ def get_reference(self, furl_or_file):
+ """
+ Get a remote reference using a furl or a file containing a furl.
+
+ Remote references are cached locally so once a remote reference
+ has been retrieved for a given furl, the cached version is
+ returned.
+
+ :Parameters:
+ furl_or_file : str
+ A furl or a filename containing a furl
+
+ :Returns:
+ A deferred to a remote reference
+ """
+ furl = find_furl(furl_or_file)
+ if furl in self._remote_refs:
+ d = defer.succeed(self._remote_refs[furl])
+ else:
+ d = self.tub.getReference(furl)
+ d.addCallback(self.save_ref, furl)
+ return d
+
+ def save_ref(self, ref, furl):
+ """
+ Cache a remote reference by its furl.
+ """
+ self._remote_refs[furl] = ref
+ return ref
+
+ def get_task_client(self, furl_or_file=''):
+ """
+ Get the task controller client.
+
+ This method is a simple wrapper around `get_client` that allow
+ `furl_or_file` to be empty, in which case, the furls is taken
+ from the default furl file given in the configuration.
+
+ :Parameters:
+ furl_or_file : str
+ A furl or a filename containing a furl. If empty, the
+ default furl_file will be used
+
+ :Returns:
+ A deferred to the actual client class
+ """
+ task_co = client_co['client_interfaces']['task']
+ if furl_or_file:
+ ff = furl_or_file
+ else:
+ ff = task_co['furl_file']
+ return self.get_client(ff)
+
+ def get_multiengine_client(self, furl_or_file=''):
+ """
+ Get the multiengine controller client.
+
+ This method is a simple wrapper around `get_client` that allow
+ `furl_or_file` to be empty, in which case, the furls is taken
+ from the default furl file given in the configuration.
+
+ :Parameters:
+ furl_or_file : str
+ A furl or a filename containing a furl. If empty, the
+ default furl_file will be used
+
+ :Returns:
+ A deferred to the actual client class
+ """
+ task_co = client_co['client_interfaces']['multiengine']
+ if furl_or_file:
+ ff = furl_or_file
+ else:
+ ff = task_co['furl_file']
+ return self.get_client(ff)
+
+ def get_client(self, furl_or_file):
+ """
+ Get a remote reference and wrap it in a client by furl.
+
+ This method first gets a remote reference and then calls its
+ `get_client_name` method to find the apprpriate client class
+ that should be used to wrap the remote reference.
+
+ :Parameters:
+ furl_or_file : str
+ A furl or a filename containing a furl
+
+ :Returns:
+ A deferred to the actual client class
+ """
+ furl = find_furl(furl_or_file)
+ d = self.get_reference(furl)
+ def wrap_remote_reference(rr):
+ d = rr.callRemote('get_client_name')
+ d.addCallback(lambda name: import_item(name))
+ def adapt(client_interface):
+ client = client_interface(rr)
+ client.tub = self.tub
+ return client
+ d.addCallback(adapt)
+
+ return d
+ d.addCallback(wrap_remote_reference)
+ return d
diff --git a/IPython/kernel/clientinterfaces.py b/IPython/kernel/clientinterfaces.py
new file mode 100644
index 0000000..248e511
--- /dev/null
+++ b/IPython/kernel/clientinterfaces.py
@@ -0,0 +1,32 @@
+# encoding: utf-8
+
+"""General client interfaces."""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+from zope.interface import Interface, implements
+
+class IFCClientInterfaceProvider(Interface):
+
+ def remote_get_client_name():
+ """Return a string giving the class which implements a client-side interface.
+
+ The client side of any foolscap connection initially gets a remote reference.
+ Some class is needed to adapt that reference to an interface. This...
+ """
+
+class IBlockingClientAdaptor(Interface):
+
+ def adapt_to_blocking_client():
+ """""" \ No newline at end of file
diff --git a/IPython/kernel/codeutil.py b/IPython/kernel/codeutil.py
new file mode 100644
index 0000000..31e0361
--- /dev/null
+++ b/IPython/kernel/codeutil.py
@@ -0,0 +1,39 @@
+# encoding: utf-8
+
+"""Utilities to enable code objects to be pickled.
+
+Any process that import this module will be able to pickle code objects. This
+includes the func_code attribute of any function. Once unpickled, new
+functions can be built using new.function(code, globals()). Eventually
+we need to automate all of this so that functions themselves can be pickled.
+
+Reference: A. Tremols, P Cogolo, "Python Cookbook," p 302-305
+"""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+import new, types, copy_reg
+
+def code_ctor(*args):
+ return new.code(*args)
+
+def reduce_code(co):
+ if co.co_freevars or co.co_cellvars:
+ raise ValueError("Sorry, cannot pickle code objects with closures")
+ return code_ctor, (co.co_argcount, co.co_nlocals, co.co_stacksize,
+ co.co_flags, co.co_code, co.co_consts, co.co_names,
+ co.co_varnames, co.co_filename, co.co_name, co.co_firstlineno,
+ co.co_lnotab)
+
+copy_reg.pickle(types.CodeType, reduce_code) \ No newline at end of file
diff --git a/IPython/kernel/config/__init__.py b/IPython/kernel/config/__init__.py
new file mode 100644
index 0000000..b4845dc
--- /dev/null
+++ b/IPython/kernel/config/__init__.py
@@ -0,0 +1,126 @@
+# encoding: utf-8
+
+"""Default kernel configuration."""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+import os, sys
+from os.path import join as pjoin
+
+from IPython.external.configobj import ConfigObj
+from IPython.config.api import ConfigObjManager
+from IPython.genutils import get_ipython_dir, get_security_dir
+
+default_kernel_config = ConfigObj()
+
+# This will raise OSError if ipythondir doesn't exist.
+security_dir = get_security_dir()
+
+#-------------------------------------------------------------------------------
+# Engine Configuration
+#-------------------------------------------------------------------------------
+
+engine_config = dict(
+ logfile = '', # Empty means log to stdout
+ furl_file = pjoin(security_dir, 'ipcontroller-engine.furl')
+)
+
+#-------------------------------------------------------------------------------
+# MPI Configuration
+#-------------------------------------------------------------------------------
+
+mpi_config = dict(
+ mpi4py = """from mpi4py import MPI as mpi
+mpi.size = mpi.COMM_WORLD.Get_size()
+mpi.rank = mpi.COMM_WORLD.Get_rank()
+""",
+ pytrilinos = """from PyTrilinos import Epetra
+class SimpleStruct:
+ pass
+mpi = SimpleStruct()
+mpi.rank = 0
+mpi.size = 0
+""",
+ default = ''
+)
+
+#-------------------------------------------------------------------------------
+# Controller Configuration
+#-------------------------------------------------------------------------------
+
+controller_config = dict(
+
+ logfile = '', # Empty means log to stdout
+ import_statement = '',
+ reuse_furls = False, # If False, old furl files are deleted
+
+ engine_tub = dict(
+ ip = '', # Empty string means all interfaces
+ port = 0, # 0 means pick a port for me
+ location = '', # Empty string means try to set automatically
+ secure = True,
+ cert_file = pjoin(security_dir, 'ipcontroller-engine.pem'),
+ ),
+ engine_fc_interface = 'IPython.kernel.enginefc.IFCControllerBase',
+ engine_furl_file = pjoin(security_dir, 'ipcontroller-engine.furl'),
+
+ controller_interfaces = dict(
+ # multiengine = dict(
+ # controller_interface = 'IPython.kernel.multiengine.IMultiEngine',
+ # fc_interface = 'IPython.kernel.multienginefc.IFCMultiEngine',
+ # furl_file = 'ipcontroller-mec.furl'
+ # ),
+ task = dict(
+ controller_interface = 'IPython.kernel.task.ITaskController',
+ fc_interface = 'IPython.kernel.taskfc.IFCTaskController',
+ furl_file = pjoin(security_dir, 'ipcontroller-tc.furl')
+ ),
+ multiengine = dict(
+ controller_interface = 'IPython.kernel.multiengine.IMultiEngine',
+ fc_interface = 'IPython.kernel.multienginefc.IFCSynchronousMultiEngine',
+ furl_file = pjoin(security_dir, 'ipcontroller-mec.furl')
+ )
+ ),
+
+ client_tub = dict(
+ ip = '', # Empty string means all interfaces
+ port = 0, # 0 means pick a port for me
+ location = '', # Empty string means try to set automatically
+ secure = True,
+ cert_file = pjoin(security_dir, 'ipcontroller-client.pem')
+ )
+)
+
+#-------------------------------------------------------------------------------
+# Client Configuration
+#-------------------------------------------------------------------------------
+
+client_config = dict(
+ client_interfaces = dict(
+ task = dict(
+ furl_file = pjoin(security_dir, 'ipcontroller-tc.furl')
+ ),
+ multiengine = dict(
+ furl_file = pjoin(security_dir, 'ipcontroller-mec.furl')
+ )
+ )
+)
+
+default_kernel_config['engine'] = engine_config
+default_kernel_config['mpi'] = mpi_config
+default_kernel_config['controller'] = controller_config
+default_kernel_config['client'] = client_config
+
+
+config_manager = ConfigObjManager(default_kernel_config, 'IPython.kernel.ini') \ No newline at end of file
diff --git a/IPython/kernel/contexts.py b/IPython/kernel/contexts.py
new file mode 100644
index 0000000..949688e
--- /dev/null
+++ b/IPython/kernel/contexts.py
@@ -0,0 +1,141 @@
+# encoding: utf-8
+# -*- test-case-name: IPython.kernel.test.test_contexts -*-
+"""Context managers for IPython.
+
+Python 2.5 introduced the `with` statement, which is based on the context
+manager protocol. This module offers a few context managers for common cases,
+which can also be useful as templates for writing new, application-specific
+managers.
+"""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+import linecache
+import sys
+
+from twisted.internet.error import ConnectionRefusedError
+
+from IPython.ultraTB import _fixed_getinnerframes, findsource
+from IPython import ipapi
+
+from IPython.kernel import error
+
+#---------------------------------------------------------------------------
+# Utility functions needed by all context managers.
+#---------------------------------------------------------------------------
+
+def remote():
+ """Raises a special exception meant to be caught by context managers.
+ """
+ m = 'Special exception to stop local execution of parallel code.'
+ raise error.StopLocalExecution(m)
+
+
+def strip_whitespace(source,require_remote=True):
+ """strip leading whitespace from input source.
+
+ :Parameters:
+
+ """
+ remote_mark = 'remote()'
+ # Expand tabs to avoid any confusion.
+ wsource = [l.expandtabs(4) for l in source]
+ # Detect the indentation level
+ done = False
+ for line in wsource:
+ if line.isspace():
+ continue
+ for col,char in enumerate(line):
+ if char != ' ':
+ done = True
+ break
+ if done:
+ break
+ # Now we know how much leading space there is in the code. Next, we
+ # extract up to the first line that has less indentation.
+ # WARNINGS: we skip comments that may be misindented, but we do NOT yet
+ # detect triple quoted strings that may have flush left text.
+ for lno,line in enumerate(wsource):
+ lead = line[:col]
+ if lead.isspace():
+ continue
+ else:
+ if not lead.lstrip().startswith('#'):
+ break
+ # The real 'with' source is up to lno
+ src_lines = [l[col:] for l in wsource[:lno+1]]
+
+ # Finally, check that the source's first non-comment line begins with the
+ # special call 'remote()'
+ if require_remote:
+ for nline,line in enumerate(src_lines):
+ if line.isspace() or line.startswith('#'):
+ continue
+ if line.startswith(remote_mark):
+ break
+ else:
+ raise ValueError('%s call missing at the start of code' %
+ remote_mark)
+ out_lines = src_lines[nline+1:]
+ else:
+ # If the user specified that the remote() call wasn't mandatory
+ out_lines = src_lines
+
+ # src = ''.join(out_lines) # dbg
+ #print 'SRC:\n<<<<<<<>>>>>>>\n%s<<<<<>>>>>>' % src # dbg
+ return ''.join(out_lines)
+
+class RemoteContextBase(object):
+ def __init__(self):
+ self.ip = ipapi.get()
+
+ def _findsource_file(self,f):
+ linecache.checkcache()
+ s = findsource(f.f_code)
+ lnum = f.f_lineno
+ wsource = s[0][f.f_lineno:]
+ return strip_whitespace(wsource)
+
+ def _findsource_ipython(self,f):
+ from IPython import ipapi
+ self.ip = ipapi.get()
+ buf = self.ip.IP.input_hist_raw[-1].splitlines()[1:]
+ wsource = [l+'\n' for l in buf ]
+
+ return strip_whitespace(wsource)
+
+ def findsource(self,frame):
+ local_ns = frame.f_locals
+ global_ns = frame.f_globals
+ if frame.f_code.co_filename == '<ipython console>':
+ src = self._findsource_ipython(frame)
+ else:
+ src = self._findsource_file(frame)
+ return src
+
+ def __enter__(self):
+ raise NotImplementedError
+
+ def __exit__ (self, etype, value, tb):
+ if issubclass(etype,error.StopLocalExecution):
+ return True
+
+class RemoteMultiEngine(RemoteContextBase):
+ def __init__(self,mec):
+ self.mec = mec
+ RemoteContextBase.__init__(self)
+
+ def __enter__(self):
+ src = self.findsource(sys._getframe(1))
+ return self.mec.execute(src)
diff --git a/IPython/kernel/controllerservice.py b/IPython/kernel/controllerservice.py
new file mode 100644
index 0000000..3fe5f41
--- /dev/null
+++ b/IPython/kernel/controllerservice.py
@@ -0,0 +1,376 @@
+# encoding: utf-8
+# -*- test-case-name: IPython.kernel.test.test_controllerservice -*-
+
+"""A Twisted Service for the IPython Controller.
+
+The IPython Controller:
+
+* Listens for Engines to connect and then manages access to those engines.
+* Listens for clients and passes commands from client to the Engines.
+* Exposes an asynchronous interfaces to the Engines which themselves can block.
+* Acts as a gateway to the Engines.
+
+The design of the controller is somewhat abstract to allow flexibility in how
+the controller is presented to clients. This idea is that there is a basic
+ControllerService class that allows engines to connect to it. But, this
+basic class has no client interfaces. To expose client interfaces developers
+provide an adapter that makes the ControllerService look like something. For
+example, one client interface might support task farming and another might
+support interactive usage. The important thing is that by using interfaces
+and adapters, a single controller can be accessed from multiple interfaces.
+Furthermore, by adapting various client interfaces to various network
+protocols, each client interface can be exposed to multiple network protocols.
+See multiengine.py for an example of how to adapt the ControllerService
+to a client interface.
+"""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+import os, sys
+
+from twisted.application import service
+from twisted.internet import defer, reactor
+from twisted.python import log, components
+from zope.interface import Interface, implements, Attribute
+import zope.interface as zi
+
+from IPython.kernel.engineservice import \
+ IEngineCore, \
+ IEngineSerialized, \
+ IEngineQueued
+
+from IPython.genutils import get_ipython_dir
+from IPython.kernel import codeutil
+
+#-------------------------------------------------------------------------------
+# Interfaces for the Controller
+#-------------------------------------------------------------------------------
+
+class IControllerCore(Interface):
+ """Basic methods any controller must have.
+
+ This is basically the aspect of the controller relevant to the
+ engines and does not assume anything about how the engines will
+ be presented to a client.
+ """
+
+ engines = Attribute("A dict of engine ids and engine instances.")
+
+ def register_engine(remoteEngine, id=None, ip=None, port=None,
+ pid=None):
+ """Register new remote engine.
+
+ The controller can use the ip, port, pid of the engine to do useful things
+ like kill the engines.
+
+ :Parameters:
+ remoteEngine
+ An implementer of IEngineCore, IEngineSerialized and IEngineQueued.
+ id : int
+ Requested id.
+ ip : str
+ IP address the engine is running on.
+ port : int
+ Port the engine is on.
+ pid : int
+ pid of the running engine.
+
+ :Returns: A dict of {'id':id} and possibly other key, value pairs.
+ """
+
+ def unregister_engine(id):
+ """Handle a disconnecting engine.
+
+ :Parameters:
+ id
+ The integer engine id of the engine to unregister.
+ """
+
+ def on_register_engine_do(f, includeID, *args, **kwargs):
+ """Call ``f(*args, **kwargs)`` when an engine is registered.
+
+ :Parameters:
+ includeID : int
+ If True the first argument to f will be the id of the engine.
+ """
+
+ def on_unregister_engine_do(f, includeID, *args, **kwargs):
+ """Call ``f(*args, **kwargs)`` when an engine is unregistered.
+
+ :Parameters:
+ includeID : int
+ If True the first argument to f will be the id of the engine.
+ """
+
+ def on_register_engine_do_not(f):
+ """Stop calling f on engine registration"""
+
+ def on_unregister_engine_do_not(f):
+ """Stop calling f on engine unregistration"""
+
+ def on_n_engines_registered_do(n, f, *arg, **kwargs):
+ """Call f(*args, **kwargs) the first time the nth engine registers."""
+
+class IControllerBase(IControllerCore):
+ """The basic controller interface."""
+ pass
+
+
+#-------------------------------------------------------------------------------
+# Implementation of the ControllerService
+#-------------------------------------------------------------------------------
+
+class ControllerService(object, service.Service):
+ """A basic Controller represented as a Twisted Service.
+
+ This class doesn't implement any client notification mechanism. That
+ is up to adapted subclasses.
+ """
+
+ # I also pick up the IService interface by inheritance from service.Service
+ implements(IControllerBase)
+ name = 'ControllerService'
+
+ def __init__(self, maxEngines=511, saveIDs=False):
+ self.saveIDs = saveIDs
+ self.engines = {}
+ self.availableIDs = range(maxEngines,-1,-1) # [511,...,0]
+ self._onRegister = []
+ self._onUnregister = []
+ self._onNRegistered = []
+
+ #---------------------------------------------------------------------------
+ # Methods used to save the engine info to a log file
+ #---------------------------------------------------------------------------
+
+ def _buildEngineInfoString(self, id, ip, port, pid):
+ if id is None:
+ id = -99
+ if ip is None:
+ ip = "-99"
+ if port is None:
+ port = -99
+ if pid is None:
+ pid = -99
+ return "Engine Info: %d %s %d %d" % (id, ip , port, pid)
+
+ def _logEngineInfo(self, id, ip, port, pid):
+ log.msg(self._buildEngineInfoString(id,ip,port,pid))
+
+ def _getEngineInfoLogFile(self):
+ # Store all logs inside the ipython directory
+ ipdir = get_ipython_dir()
+ pjoin = os.path.join
+ logdir_base = pjoin(ipdir,'log')
+ if not os.path.isdir(logdir_base):
+ os.makedirs(logdir_base)
+ logfile = os.path.join(logdir_base,'ipcontroller-%s-engine-info.log' % os.getpid())
+ return logfile
+
+ def _logEngineInfoToFile(self, id, ip, port, pid):
+ """Log info about an engine to a log file.
+
+ When an engine registers with a ControllerService, the ControllerService
+ saves information about the engine to a log file. That information
+ can be useful for various purposes, such as killing hung engines, etc.
+
+ This method takes the assigned id, ip/port and pid of the engine
+ and saves it to a file of the form:
+
+ ~/.ipython/log/ipcontroller-###-engine-info.log
+
+ where ### is the pid of the controller.
+
+ Each line of this file has the form:
+
+ Engine Info: ip ip port pid
+
+ If any of the entries are not known, they are replaced by -99.
+ """
+
+ fname = self._getEngineInfoLogFile()
+ f = open(fname, 'a')
+ s = self._buildEngineInfoString(id,ip,port,pid)
+ f.write(s + '\n')
+ f.close()
+
+ #---------------------------------------------------------------------------
+ # IControllerCore methods
+ #---------------------------------------------------------------------------
+
+ def register_engine(self, remoteEngine, id=None,
+ ip=None, port=None, pid=None):
+ """Register new engine connection"""
+
+ # What happens if these assertions fail?
+ assert IEngineCore.providedBy(remoteEngine), \
+ "engine passed to register_engine doesn't provide IEngineCore"
+ assert IEngineSerialized.providedBy(remoteEngine), \
+ "engine passed to register_engine doesn't provide IEngineSerialized"
+ assert IEngineQueued.providedBy(remoteEngine), \
+ "engine passed to register_engine doesn't provide IEngineQueued"
+ assert isinstance(id, int) or id is None, \
+ "id to register_engine must be an integer or None"
+ assert isinstance(ip, str) or ip is None, \
+ "ip to register_engine must be a string or None"
+ assert isinstance(port, int) or port is None, \
+ "port to register_engine must be an integer or None"
+ assert isinstance(pid, int) or pid is None, \
+ "pid to register_engine must be an integer or None"
+
+ desiredID = id
+ if desiredID in self.engines.keys():
+ desiredID = None
+
+ if desiredID in self.availableIDs:
+ getID = desiredID
+ self.availableIDs.remove(desiredID)
+ else:
+ getID = self.availableIDs.pop()
+ remoteEngine.id = getID
+ remoteEngine.service = self
+ self.engines[getID] = remoteEngine
+
+ # Log the Engine Information for monitoring purposes
+ self._logEngineInfoToFile(getID, ip, port, pid)
+
+ msg = "registered engine with id: %i" %getID
+ log.msg(msg)
+
+ for i in range(len(self._onRegister)):
+ (f,args,kwargs,ifid) = self._onRegister[i]
+ try:
+ if ifid:
+ f(getID, *args, **kwargs)
+ else:
+ f(*args, **kwargs)
+ except:
+ self._onRegister.pop(i)
+
+ # Call functions when the nth engine is registered and them remove them
+ for i, (n, f, args, kwargs) in enumerate(self._onNRegistered):
+ if len(self.engines.keys()) == n:
+ try:
+ try:
+ f(*args, **kwargs)
+ except:
+ log.msg("Function %r failed when the %ith engine registered" % (f, n))
+ finally:
+ self._onNRegistered.pop(i)
+
+ return {'id':getID}
+
+ def unregister_engine(self, id):
+ """Unregister engine by id."""
+
+ assert isinstance(id, int) or id is None, \
+ "id to unregister_engine must be an integer or None"
+
+ msg = "unregistered engine with id: %i" %id
+ log.msg(msg)
+ try:
+ del self.engines[id]
+ except KeyError:
+ log.msg("engine with id %i was not registered" % id)
+ else:
+ if not self.saveIDs:
+ self.availableIDs.append(id)
+ # Sort to assign lower ids first
+ self.availableIDs.sort(reverse=True)
+ else:
+ log.msg("preserving id %i" %id)
+
+ for i in range(len(self._onUnregister)):
+ (f,args,kwargs,ifid) = self._onUnregister[i]
+ try:
+ if ifid:
+ f(id, *args, **kwargs)
+ else:
+ f(*args, **kwargs)
+ except:
+ self._onUnregister.pop(i)
+
+ def on_register_engine_do(self, f, includeID, *args, **kwargs):
+ assert callable(f), "f must be callable"
+ self._onRegister.append((f,args,kwargs,includeID))
+
+ def on_unregister_engine_do(self, f, includeID, *args, **kwargs):
+ assert callable(f), "f must be callable"
+ self._onUnregister.append((f,args,kwargs,includeID))
+
+ def on_register_engine_do_not(self, f):
+ for i in range(len(self._onRegister)):
+ g = self._onRegister[i][0]
+ if f == g:
+ self._onRegister.pop(i)
+ return
+
+ def on_unregister_engine_do_not(self, f):
+ for i in range(len(self._onUnregister)):
+ g = self._onUnregister[i][0]
+ if f == g:
+ self._onUnregister.pop(i)
+ return
+
+ def on_n_engines_registered_do(self, n, f, *args, **kwargs):
+ if len(self.engines.keys()) >= n:
+ f(*args, **kwargs)
+ else:
+ self._onNRegistered.append((n,f,args,kwargs))
+
+
+#-------------------------------------------------------------------------------
+# Base class for adapting controller to different client APIs
+#-------------------------------------------------------------------------------
+
+class ControllerAdapterBase(object):
+ """All Controller adapters should inherit from this class.
+
+ This class provides a wrapped version of the IControllerBase interface that
+ can be used to easily create new custom controllers. Subclasses of this
+ will provide a full implementation of IControllerBase.
+
+ This class doesn't implement any client notification mechanism. That
+ is up to subclasses.
+ """
+
+ implements(IControllerBase)
+
+ def __init__(self, controller):
+ self.controller = controller
+ # Needed for IControllerCore
+ self.engines = self.controller.engines
+
+ def register_engine(self, remoteEngine, id=None,
+ ip=None, port=None, pid=None):
+ return self.controller.register_engine(remoteEngine,
+ id, ip, port, pid)
+
+ def unregister_engine(self, id):
+ return self.controller.unregister_engine(id)
+
+ def on_register_engine_do(self, f, includeID, *args, **kwargs):
+ return self.controller.on_register_engine_do(f, includeID, *args, **kwargs)
+
+ def on_unregister_engine_do(self, f, includeID, *args, **kwargs):
+ return self.controller.on_unregister_engine_do(f, includeID, *args, **kwargs)
+
+ def on_register_engine_do_not(self, f):
+ return self.controller.on_register_engine_do_not(f)
+
+ def on_unregister_engine_do_not(self, f):
+ return self.controller.on_unregister_engine_do_not(f)
+
+ def on_n_engines_registered_do(self, n, f, *args, **kwargs):
+ return self.controller.on_n_engines_registered_do(n, f, *args, **kwargs)
diff --git a/IPython/kernel/core/__init__.py b/IPython/kernel/core/__init__.py
new file mode 100644
index 0000000..0aad75d
--- /dev/null
+++ b/IPython/kernel/core/__init__.py
@@ -0,0 +1,16 @@
+# encoding: utf-8
+
+"""The IPython Core."""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#------------------------------------------------------------------------------- \ No newline at end of file
diff --git a/IPython/kernel/core/config/__init__.py b/IPython/kernel/core/config/__init__.py
new file mode 100644
index 0000000..6f60906
--- /dev/null
+++ b/IPython/kernel/core/config/__init__.py
@@ -0,0 +1,25 @@
+# encoding: utf-8
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+from IPython.external.configobj import ConfigObj
+from IPython.config.api import ConfigObjManager
+
+default_core_config = ConfigObj()
+default_core_config['shell'] = dict(
+ shell_class = 'IPython.kernel.core.interpreter.Interpreter',
+ import_statement = ''
+)
+
+config_manager = ConfigObjManager(default_core_config, 'IPython.kernel.core.ini') \ No newline at end of file
diff --git a/IPython/kernel/core/display_formatter.py b/IPython/kernel/core/display_formatter.py
new file mode 100644
index 0000000..55a04a9
--- /dev/null
+++ b/IPython/kernel/core/display_formatter.py
@@ -0,0 +1,70 @@
+# encoding: utf-8
+
+"""Objects for replacing sys.displayhook()."""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+class IDisplayFormatter(object):
+ """ Objects conforming to this interface will be responsible for formatting
+ representations of objects that pass through sys.displayhook() during an
+ interactive interpreter session.
+ """
+
+ # The kind of formatter.
+ kind = 'display'
+
+ # The unique identifier for this formatter.
+ identifier = None
+
+
+ def __call__(self, obj):
+ """ Return a formatted representation of an object.
+
+ Return None if one cannot return a representation in this format.
+ """
+
+ raise NotImplementedError
+
+
+class ReprDisplayFormatter(IDisplayFormatter):
+ """ Return the repr() string representation of an object.
+ """
+
+ # The unique identifier for this formatter.
+ identifier = 'repr'
+
+
+ def __call__(self, obj):
+ """ Return a formatted representation of an object.
+ """
+
+ return repr(obj)
+
+
+class PPrintDisplayFormatter(IDisplayFormatter):
+ """ Return a pretty-printed string representation of an object.
+ """
+
+ # The unique identifier for this formatter.
+ identifier = 'pprint'
+
+
+ def __call__(self, obj):
+ """ Return a formatted representation of an object.
+ """
+
+ import pprint
+ return pprint.pformat(obj)
+
+
diff --git a/IPython/kernel/core/display_trap.py b/IPython/kernel/core/display_trap.py
new file mode 100644
index 0000000..2d276c3
--- /dev/null
+++ b/IPython/kernel/core/display_trap.py
@@ -0,0 +1,100 @@
+# encoding: utf-8
+
+"""Manager for replacing sys.displayhook()."""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+# Standard library imports.
+import sys
+
+
+
+class DisplayTrap(object):
+ """ Object to trap and format objects passing through sys.displayhook().
+
+ This trap maintains two lists of callables: formatters and callbacks. The
+ formatters take the *last* object that has gone through since the trap was
+ set and returns a string representation. Callbacks are executed on *every*
+ object that passes through the displayhook and does not return anything.
+ """
+
+ def __init__(self, formatters=None, callbacks=None):
+ # A list of formatters to apply. Each should be an instance conforming
+ # to the IDisplayFormatter interface.
+ if formatters is None:
+ formatters = []
+ self.formatters = formatters
+
+ # A list of callables, each of which should be executed *every* time an
+ # object passes through sys.displayhook().
+ if callbacks is None:
+ callbacks = []
+ self.callbacks = callbacks
+
+ # The last object to pass through the displayhook.
+ self.obj = None
+
+ # The previous hook before we replace it.
+ self.old_hook = None
+
+ def hook(self, obj):
+ """ This method actually implements the hook.
+ """
+
+ # Run through the list of callbacks and trigger all of them.
+ for callback in self.callbacks:
+ callback(obj)
+
+ # Store the object for formatting.
+ self.obj = obj
+
+ def set(self):
+ """ Set the hook.
+ """
+
+ if sys.displayhook is not self.hook:
+ self.old_hook = sys.displayhook
+ sys.displayhook = self.hook
+
+ def unset(self):
+ """ Unset the hook.
+ """
+
+ sys.displayhook = self.old_hook
+
+ def clear(self):
+ """ Reset the stored object.
+ """
+
+ self.obj = None
+
+ def add_to_message(self, message):
+ """ Add the formatted display of the objects to the message dictionary
+ being returned from the interpreter to its listeners.
+ """
+
+ # If there was no displayed object (or simply None), then don't add
+ # anything.
+ if self.obj is None:
+ return
+
+ # Go through the list of formatters and let them add their formatting.
+ display = {}
+ for formatter in self.formatters:
+ representation = formatter(self.obj)
+ if representation is not None:
+ display[formatter.identifier] = representation
+
+ message['display'] = display
+
diff --git a/IPython/kernel/core/error.py b/IPython/kernel/core/error.py
new file mode 100644
index 0000000..50c2591
--- /dev/null
+++ b/IPython/kernel/core/error.py
@@ -0,0 +1,41 @@
+# encoding: utf-8
+
+"""
+error.py
+
+We declare here a class hierarchy for all exceptions produced by IPython, in
+cases where we don't just raise one from the standard library.
+"""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+
+class IPythonError(Exception):
+ """Base exception that all of our exceptions inherit from.
+
+ This can be raised by code that doesn't have any more specific
+ information."""
+
+ pass
+
+# Exceptions associated with the controller objects
+class ControllerError(IPythonError): pass
+
+class ControllerCreationError(ControllerError): pass
+
+
+# Exceptions associated with the Engines
+class EngineError(IPythonError): pass
+
+class EngineCreationError(EngineError): pass
diff --git a/IPython/kernel/core/fd_redirector.py b/IPython/kernel/core/fd_redirector.py
new file mode 100644
index 0000000..510a439
--- /dev/null
+++ b/IPython/kernel/core/fd_redirector.py
@@ -0,0 +1,81 @@
+# encoding: utf-8
+
+"""
+Stdout/stderr redirector, at the OS level, using file descriptors.
+
+This also works under windows.
+"""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+
+import os
+import sys
+
+STDOUT = 1
+STDERR = 2
+
+class FDRedirector(object):
+ """ Class to redirect output (stdout or stderr) at the OS level using
+ file descriptors.
+ """
+
+ def __init__(self, fd=STDOUT):
+ """ fd is the file descriptor of the outpout you want to capture.
+ It can be STDOUT or STERR.
+ """
+ self.fd = fd
+ self.started = False
+ self.piper = None
+ self.pipew = None
+
+ def start(self):
+ """ Setup the redirection.
+ """
+ if not self.started:
+ self.oldhandle = os.dup(self.fd)
+ self.piper, self.pipew = os.pipe()
+ os.dup2(self.pipew, self.fd)
+ os.close(self.pipew)
+
+ self.started = True
+
+ def flush(self):
+ """ Flush the captured output, similar to the flush method of any
+ stream.
+ """
+ if self.fd == STDOUT:
+ sys.stdout.flush()
+ elif self.fd == STDERR:
+ sys.stderr.flush()
+
+ def stop(self):
+ """ Unset the redirection and return the captured output.
+ """
+ if self.started:
+ self.flush()
+ os.dup2(self.oldhandle, self.fd)
+ os.close(self.oldhandle)
+ f = os.fdopen(self.piper, 'r')
+ output = f.read()
+ f.close()
+
+ self.started = False
+ return output
+ else:
+ return ''
+
+ def getvalue(self):
+ """ Return the output captured since the last getvalue, or the
+ start of the redirection.
+ """
+ output = self.stop()
+ self.start()
+ return output
diff --git a/IPython/kernel/core/file_like.py b/IPython/kernel/core/file_like.py
new file mode 100644
index 0000000..f984451
--- /dev/null
+++ b/IPython/kernel/core/file_like.py
@@ -0,0 +1,66 @@
+# encoding: utf-8
+
+""" File like object that redirects its write calls to a given callback."""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+import sys
+
+class FileLike(object):
+ """ FileLike object that redirects all write to a callback.
+
+ Only the write-related methods are implemented, as well as those
+ required to read a StringIO.
+ """
+ closed = False
+
+ def __init__(self, write_callback):
+ self.write = write_callback
+
+ def flush(self):
+ """ This method is there for compatibility with other file-like
+ objects.
+ """
+ pass
+
+ def close(self):
+ """ This method is there for compatibility with other file-like
+ objects.
+ """
+ pass
+
+ def writelines(self, lines):
+ map(self.write, lines)
+
+ def isatty(self):
+ """ This method is there for compatibility with other file-like
+ objects.
+ """
+ return False
+
+ def getvalue(self):
+ """ This method is there for compatibility with other file-like
+ objects.
+ """
+ return ''
+
+ def reset(self):
+ """ This method is there for compatibility with other file-like
+ objects.
+ """
+ pass
+
+ def truncate(self):
+ """ This method is there for compatibility with other file-like
+ objects.
+ """
+ pass
+
+
diff --git a/IPython/kernel/core/history.py b/IPython/kernel/core/history.py
new file mode 100644
index 0000000..736aac6
--- /dev/null
+++ b/IPython/kernel/core/history.py
@@ -0,0 +1,137 @@
+# encoding: utf-8
+
+""" Manage the input and output history of the interpreter and the
+frontend.
+
+There are 2 different history objects, one that lives in the interpreter,
+and one that lives in the frontend. They are synced with a diff at each
+execution of a command, as the interpreter history is a real stack, its
+existing entries are not mutable.
+"""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+from copy import copy
+
+# Local imports.
+from util import InputList
+
+
+##############################################################################
+class History(object):
+ """ An object managing the input and output history.
+ """
+
+ def __init__(self, input_cache=None, output_cache=None):
+
+ # Stuff that IPython adds to the namespace.
+ self.namespace_additions = dict(
+ _ = None,
+ __ = None,
+ ___ = None,
+ )
+
+ # A list to store input commands.
+ if input_cache is None:
+ input_cache =InputList([])
+ self.input_cache = input_cache
+
+ # A dictionary to store trapped output.
+ if output_cache is None:
+ output_cache = {}
+ self.output_cache = output_cache
+
+ def get_history_item(self, index):
+ """ Returns the history string at index, where index is the
+ distance from the end (positive).
+ """
+ if index>=0 and index<len(self.input_cache):
+ return self.input_cache[index]
+
+
+##############################################################################
+class InterpreterHistory(History):
+ """ An object managing the input and output history at the interpreter
+ level.
+ """
+
+ def setup_namespace(self, namespace):
+ """ Add the input and output caches into the interpreter's namespace
+ with IPython-conventional names.
+
+ Parameters
+ ----------
+ namespace : dict
+ """
+
+ namespace['In'] = self.input_cache
+ namespace['_ih'] = self.input_cache
+ namespace['Out'] = self.output_cache
+ namespace['_oh'] = self.output_cache
+
+ def update_history(self, interpreter, python):
+ """ Update the history objects that this object maintains and the
+ interpreter's namespace.
+
+ Parameters
+ ----------
+ interpreter : Interpreter
+ python : str
+ The real Python code that was translated and actually executed.
+ """
+
+ number = interpreter.current_cell_number
+
+ new_obj = interpreter.display_trap.obj
+ if new_obj is not None:
+ self.namespace_additions['___'] = self.namespace_additions['__']
+ self.namespace_additions['__'] = self.namespace_additions['_']
+ self.namespace_additions['_'] = new_obj
+ self.output_cache[number] = new_obj
+
+ interpreter.user_ns.update(self.namespace_additions)
+ self.input_cache.add(number, python)
+
+
+ def get_history_item(self, index):
+ """ Returns the history string at index, where index is the
+ distance from the end (positive).
+ """
+ if index>0 and index<(len(self.input_cache)-1):
+ return self.input_cache[-index]
+
+ def get_input_cache(self):
+ return copy(self.input_cache)
+
+ def get_input_after(self, index):
+ """ Returns the list of the commands entered after index.
+ """
+ # We need to call directly list.__getslice__, because this object
+ # is not a real list.
+ return list.__getslice__(self.input_cache, index,
+ len(self.input_cache))
+
+
+##############################################################################
+class FrontEndHistory(History):
+ """ An object managing the input and output history at the frontend.
+ It is used as a local cache to reduce network latency problems
+ and multiple users editing the same thing.
+ """
+
+ def add_items(self, item_list):
+ """ Adds the given command list to the stack of executed
+ commands.
+ """
+ self.input_cache.extend(item_list)
diff --git a/IPython/kernel/core/interpreter.py b/IPython/kernel/core/interpreter.py
new file mode 100644
index 0000000..94eeca7
--- /dev/null
+++ b/IPython/kernel/core/interpreter.py
@@ -0,0 +1,761 @@
+# encoding: utf-8
+
+"""Central interpreter object for an IPython engine.
+
+The interpreter is the object whose job is to process lines of user input and
+actually execute them in the user's namespace.
+"""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+# Standard library imports.
+from types import FunctionType
+
+import __builtin__
+import codeop
+import compiler
+import sys
+import traceback
+
+# Local imports.
+from IPython import ultraTB
+from IPython.kernel.core.display_trap import DisplayTrap
+from IPython.kernel.core.macro import Macro
+from IPython.kernel.core.prompts import CachedOutput
+from IPython.kernel.core.traceback_trap import TracebackTrap
+from IPython.kernel.core.util import Bunch, system_shell
+from IPython.external.Itpl import ItplNS
+
+# Global constants
+COMPILER_ERROR = 'error'
+INCOMPLETE_INPUT = 'incomplete'
+COMPLETE_INPUT = 'complete'
+
+##############################################################################
+# TEMPORARY!!! fake configuration, while we decide whether to use tconfig or
+# not
+
+rc = Bunch()
+rc.cache_size = 100
+rc.pprint = True
+rc.separate_in = '\n'
+rc.separate_out = '\n'
+rc.separate_out2 = ''
+rc.prompt_in1 = r'In [\#]: '
+rc.prompt_in2 = r' .\\D.: '
+rc.prompt_out = ''
+rc.prompts_pad_left = False
+
+##############################################################################
+
+# Top-level utilities
+def default_display_formatters():
+ """ Return a list of default display formatters.
+ """
+
+ from display_formatter import PPrintDisplayFormatter, ReprDisplayFormatter
+ return [PPrintDisplayFormatter(), ReprDisplayFormatter()]
+
+def default_traceback_formatters():
+ """ Return a list of default traceback formatters.
+ """
+
+ from traceback_formatter import PlainTracebackFormatter
+ return [PlainTracebackFormatter()]
+
+# Top-level classes
+class NotDefined(object): pass
+
+class Interpreter(object):
+ """ An interpreter object.
+
+ fixme: needs to negotiate available formatters with frontends.
+
+ Important: the interpeter should be built so that it exposes a method
+ for each attribute/method of its sub-object. This way it can be
+ replaced by a network adapter.
+ """
+
+ def __init__(self, user_ns=None, global_ns=None,translator=None,
+ magic=None, display_formatters=None,
+ traceback_formatters=None, output_trap=None, history=None,
+ message_cache=None, filename='<string>', config=None):
+
+ # The local/global namespaces for code execution
+ local_ns = user_ns # compatibility name
+ if local_ns is None:
+ local_ns = {}
+ self.user_ns = local_ns
+ # The local namespace
+ if global_ns is None:
+ global_ns = {}
+ self.user_global_ns = global_ns
+
+ # An object that will translate commands into executable Python.
+ # The current translator does not work properly so for now we are going
+ # without!
+ # if translator is None:
+ # from IPython.kernel.core.translator import IPythonTranslator
+ # translator = IPythonTranslator()
+ self.translator = translator
+
+ # An object that maintains magic commands.
+ if magic is None:
+ from IPython.kernel.core.magic import Magic
+ magic = Magic(self)
+ self.magic = magic
+
+ # A list of formatters for the displayhook.
+ if display_formatters is None:
+ display_formatters = default_display_formatters()
+ self.display_formatters = display_formatters
+
+ # A list of formatters for tracebacks.
+ if traceback_formatters is None:
+ traceback_formatters = default_traceback_formatters()
+ self.traceback_formatters = traceback_formatters
+
+ # The object trapping stdout/stderr.
+ if output_trap is None:
+ from IPython.kernel.core.output_trap import OutputTrap
+ output_trap = OutputTrap()
+ self.output_trap = output_trap
+
+ # An object that manages the history.
+ if history is None:
+ from IPython.kernel.core.history import InterpreterHistory
+ history = InterpreterHistory()
+ self.history = history
+ self.get_history_item = history.get_history_item
+ self.get_history_input_cache = history.get_input_cache
+ self.get_history_input_after = history.get_input_after
+
+ # An object that caches all of the return messages.
+ if message_cache is None:
+ from IPython.kernel.core.message_cache import SimpleMessageCache
+ message_cache = SimpleMessageCache()
+ self.message_cache = message_cache
+
+ # The "filename" of the code that is executed in this interpreter.
+ self.filename = filename
+
+ # An object that contains much configuration information.
+ if config is None:
+ # fixme: Move this constant elsewhere!
+ config = Bunch(ESC_MAGIC='%')
+ self.config = config
+
+ # Hook managers.
+ # fixme: make the display callbacks configurable. In the meantime,
+ # enable macros.
+ self.display_trap = DisplayTrap(
+ formatters=self.display_formatters,
+ callbacks=[self._possible_macro],
+ )
+ self.traceback_trap = TracebackTrap(
+ formatters=self.traceback_formatters)
+
+ # This is used temporarily for reformating exceptions in certain
+ # cases. It will go away once the ultraTB stuff is ported
+ # to ipython1
+ self.tbHandler = ultraTB.FormattedTB(color_scheme='NoColor',
+ mode='Context',
+ tb_offset=2)
+
+ # An object that can compile commands and remember __future__
+ # statements.
+ self.command_compiler = codeop.CommandCompiler()
+
+ # A replacement for the raw_input() and input() builtins. Change these
+ # attributes later to configure them.
+ self.raw_input_builtin = raw_input
+ self.input_builtin = input
+
+ # The number of the current cell.
+ self.current_cell_number = 1
+
+ # Initialize cache, set in/out prompts and printing system
+ self.outputcache = CachedOutput(self,
+ rc.cache_size,
+ rc.pprint,
+ input_sep = rc.separate_in,
+ output_sep = rc.separate_out,
+ output_sep2 = rc.separate_out2,
+ ps1 = rc.prompt_in1,
+ ps2 = rc.prompt_in2,
+ ps_out = rc.prompt_out,
+ pad_left = rc.prompts_pad_left)
+
+ # Need to decide later if this is the right approach, but clients
+ # commonly use sys.ps1/2, so it may be best to just set them here
+ sys.ps1 = self.outputcache.prompt1.p_str
+ sys.ps2 = self.outputcache.prompt2.p_str
+
+ # This is the message dictionary assigned temporarily when running the
+ # code.
+ self.message = None
+
+ self.setup_namespace()
+
+
+ #### Public 'Interpreter' interface ########################################
+
+ def formatTraceback(self, et, ev, tb, message=''):
+ """Put a formatted version of the traceback into value and reraise.
+
+ When exceptions have to be sent over the network, the traceback
+ needs to be put into the value of the exception in a nicely
+ formatted way. The method takes the type, value and tb of an
+ exception and puts a string representation of the tb into the
+ value of the exception and reraises it.
+
+ Currently this method uses the ultraTb formatter from IPython trunk.
+ Eventually it should simply use the traceback formatters in core
+ that are loaded into self.tracback_trap.formatters.
+ """
+ tbinfo = self.tbHandler.text(et,ev,tb)
+ ev._ipython_traceback_text = tbinfo
+ return et, ev, tb
+
+ def execute(self, commands, raiseException=True):
+ """ Execute some IPython commands.
+
+ 1. Translate them into Python.
+ 2. Run them.
+ 3. Trap stdout/stderr.
+ 4. Trap sys.displayhook().
+ 5. Trap exceptions.
+ 6. Return a message object.
+
+ Parameters
+ ----------
+ commands : str
+ The raw commands that the user typed into the prompt.
+
+ Returns
+ -------
+ message : dict
+ The dictionary of responses. See the README.txt in this directory
+ for an explanation of the format.
+ """
+
+ # Create a message dictionary with all of the information we will be
+ # returning to the frontend and other listeners.
+ message = self.setup_message()
+
+ # Massage the input and store the raw and translated commands into
+ # a dict.
+ user_input = dict(raw=commands)
+ if self.translator is not None:
+ python = self.translator(commands, message)
+ if python is None:
+ # Something went wrong with the translation. The translator
+ # should have added an appropriate entry to the message object.
+ return message
+ else:
+ python = commands
+ user_input['translated'] = python
+ message['input'] = user_input
+
+ # Set the message object so that any magics executed in the code have
+ # access.
+ self.message = message
+
+ # Set all of the output/exception traps.
+ self.set_traps()
+
+ # Actually execute the Python code.
+ status = self.execute_python(python)
+
+ # Unset all of the traps.
+ self.unset_traps()
+
+ # Unset the message object.
+ self.message = None
+
+ # Update the history variables in the namespace.
+ # E.g. In, Out, _, __, ___
+ if self.history is not None:
+ self.history.update_history(self, python)
+
+ # Let all of the traps contribute to the message and then clear their
+ # stored information.
+ self.output_trap.add_to_message(message)
+ self.output_trap.clear()
+ self.display_trap.add_to_message(message)
+ self.display_trap.clear()
+ self.traceback_trap.add_to_message(message)
+ # Pull out the type, value and tb of the current exception
+ # before clearing it.
+ einfo = self.traceback_trap.args
+ self.traceback_trap.clear()
+
+ # Cache the message.
+ self.message_cache.add_message(self.current_cell_number, message)
+
+ # Bump the number.
+ self.current_cell_number += 1
+
+ # This conditional lets the execute method either raise any
+ # exception that has occured in user code OR return the message
+ # dict containing the traceback and other useful info.
+ if raiseException and einfo:
+ raise einfo[0],einfo[1],einfo[2]
+ else:
+ return message
+
+ def generate_prompt(self, is_continuation):
+ """Calculate and return a string with the prompt to display.
+
+ :Parameters:
+ is_continuation : bool
+ Whether the input line is continuing multiline input or not, so
+ that a proper continuation prompt can be computed."""
+
+ if is_continuation:
+ return str(self.outputcache.prompt2)
+ else:
+ return str(self.outputcache.prompt1)
+
+ def execute_python(self, python):
+ """ Actually run the Python code in the namespace.
+
+ :Parameters:
+
+ python : str
+ Pure, exec'able Python code. Special IPython commands should have
+ already been translated into pure Python.
+ """
+
+ # We use a CommandCompiler instance to compile the code so as to keep
+ # track of __future__ imports.
+ try:
+ commands = self.split_commands(python)
+ except (SyntaxError, IndentationError), e:
+ # Save the exc_info so compilation related exceptions can be
+ # reraised
+ self.traceback_trap.args = sys.exc_info()
+ self.pack_exception(self.message,e)
+ return None
+
+ for cmd in commands:
+ try:
+ code = self.command_compiler(cmd, self.filename, 'single')
+ except (SyntaxError, OverflowError, ValueError), e:
+ self.traceback_trap.args = sys.exc_info()
+ self.pack_exception(self.message,e)
+ # No point in continuing if one block raised
+ return None
+ else:
+ self.execute_block(code)
+
+ def execute_block(self,code):
+ """Execute a single block of code in the user namespace.
+
+ Return value: a flag indicating whether the code to be run completed
+ successfully:
+
+ - 0: successful execution.
+ - 1: an error occurred.
+ """
+
+ outflag = 1 # start by assuming error, success will reset it
+ try:
+ exec code in self.user_ns
+ outflag = 0
+ except SystemExit:
+ self.resetbuffer()
+ self.traceback_trap.args = sys.exc_info()
+ except:
+ self.traceback_trap.args = sys.exc_info()
+
+ return outflag
+
+ def execute_macro(self, macro):
+ """ Execute the value of a macro.
+
+ Parameters
+ ----------
+ macro : Macro
+ """
+
+ python = macro.value
+ if self.translator is not None:
+ python = self.translator(python)
+ self.execute_python(python)
+
+ def getCommand(self, i=None):
+ """Gets the ith message in the message_cache.
+
+ This is implemented here for compatibility with the old ipython1 shell
+ I am not sure we need this though. I even seem to remember that we
+ were going to get rid of it.
+ """
+ return self.message_cache.get_message(i)
+
+ def reset(self):
+ """Reset the interpreter.
+
+ Currently this only resets the users variables in the namespace.
+ In the future we might want to also reset the other stateful
+ things like that the Interpreter has, like In, Out, etc.
+ """
+ self.user_ns.clear()
+ self.setup_namespace()
+
+ def complete(self,line,text=None, pos=None):
+ """Complete the given text.
+
+ :Parameters:
+
+ text : str
+ Text fragment to be completed on. Typically this is
+ """
+ # fixme: implement
+ raise NotImplementedError
+
+ def push(self, ns):
+ """ Put value into the namespace with name key.
+
+ Parameters
+ ----------
+ **kwds
+ """
+
+ self.user_ns.update(ns)
+
+ def push_function(self, ns):
+ # First set the func_globals for all functions to self.user_ns
+ new_kwds = {}
+ for k, v in ns.iteritems():
+ if not isinstance(v, FunctionType):
+ raise TypeError("function object expected")
+ new_kwds[k] = FunctionType(v.func_code, self.user_ns)
+ self.user_ns.update(new_kwds)
+
+ def pack_exception(self,message,exc):
+ message['exception'] = exc.__class__
+ message['exception_value'] = \
+ traceback.format_exception_only(exc.__class__, exc)
+
+ def feed_block(self, source, filename='<input>', symbol='single'):
+ """Compile some source in the interpreter.
+
+ One several things can happen:
+
+ 1) The input is incorrect; compile_command() raised an
+ exception (SyntaxError or OverflowError).
+
+ 2) The input is incomplete, and more input is required;
+ compile_command() returned None. Nothing happens.
+
+ 3) The input is complete; compile_command() returned a code
+ object. The code is executed by calling self.runcode() (which
+ also handles run-time exceptions, except for SystemExit).
+
+ The return value is:
+
+ - True in case 2
+
+ - False in the other cases, unless an exception is raised, where
+ None is returned instead. This can be used by external callers to
+ know whether to continue feeding input or not.
+
+ The return value can be used to decide whether to use sys.ps1 or
+ sys.ps2 to prompt the next line."""
+
+ self.message = self.setup_message()
+
+ try:
+ code = self.command_compiler(source,filename,symbol)
+ except (OverflowError, SyntaxError, IndentationError, ValueError ), e:
+ # Case 1
+ self.traceback_trap.args = sys.exc_info()
+ self.pack_exception(self.message,e)
+ return COMPILER_ERROR,False
+
+ if code is None:
+ # Case 2: incomplete input. This means that the input can span
+ # multiple lines. But we still need to decide when to actually
+ # stop taking user input. Later we'll add auto-indentation support
+ # somehow. In the meantime, we'll just stop if there are two lines
+ # of pure whitespace at the end.
+ last_two = source.rsplit('\n',2)[-2:]
+ print 'last two:',last_two # dbg
+ if len(last_two)==2 and all(s.isspace() for s in last_two):
+ return COMPLETE_INPUT,False
+ else:
+ return INCOMPLETE_INPUT, True
+ else:
+ # Case 3
+ return COMPLETE_INPUT, False
+
+ def pull(self, keys):
+ """ Get an item out of the namespace by key.
+
+ Parameters
+ ----------
+ key : str
+
+ Returns
+ -------
+ value : object
+
+ Raises
+ ------
+ TypeError if the key is not a string.
+ NameError if the object doesn't exist.
+ """
+
+ if isinstance(keys, str):
+ result = self.user_ns.get(keys, NotDefined())
+ if isinstance(result, NotDefined):
+ raise NameError('name %s is not defined' % keys)
+ elif isinstance(keys, (list, tuple)):
+ result = []
+ for key in keys:
+ if not isinstance(key, str):
+ raise TypeError("objects must be keyed by strings.")
+ else:
+ r = self.user_ns.get(key, NotDefined())
+ if isinstance(r, NotDefined):
+ raise NameError('name %s is not defined' % key)
+ else:
+ result.append(r)
+ if len(keys)==1:
+ result = result[0]
+ else:
+ raise TypeError("keys must be a strong or a list/tuple of strings")
+ return result
+
+ def pull_function(self, keys):
+ return self.pull(keys)
+
+ #### Interactive user API ##################################################
+
+ def ipsystem(self, command):
+ """ Execute a command in a system shell while expanding variables in the
+ current namespace.
+
+ Parameters
+ ----------
+ command : str
+ """
+
+ # Expand $variables.
+ command = self.var_expand(command)
+
+ system_shell(command,
+ header='IPython system call: ',
+ verbose=self.rc.system_verbose,
+ )
+
+ def ipmagic(self, arg_string):
+ """ Call a magic function by name.
+
+ ipmagic('name -opt foo bar') is equivalent to typing at the ipython
+ prompt:
+
+ In[1]: %name -opt foo bar
+
+ To call a magic without arguments, simply use ipmagic('name').
+
+ This provides a proper Python function to call IPython's magics in any
+ valid Python code you can type at the interpreter, including loops and
+ compound statements. It is added by IPython to the Python builtin
+ namespace upon initialization.
+
+ Parameters
+ ----------
+ arg_string : str
+ A string containing the name of the magic function to call and any
+ additional arguments to be passed to the magic.
+
+ Returns
+ -------
+ something : object
+ The return value of the actual object.
+ """
+
+ # Taken from IPython.
+ raise NotImplementedError('Not ported yet')
+
+ args = arg_string.split(' ', 1)
+ magic_name = args[0]
+ magic_name = magic_name.lstrip(self.config.ESC_MAGIC)
+
+ try:
+ magic_args = args[1]
+ except IndexError:
+ magic_args = ''
+ fn = getattr(self.magic, 'magic_'+magic_name, None)
+ if fn is None:
+ self.error("Magic function `%s` not found." % magic_name)
+ else:
+ magic_args = self.var_expand(magic_args)
+ return fn(magic_args)
+
+
+ #### Private 'Interpreter' interface #######################################
+
+ def setup_message(self):
+ """Return a message object.
+
+ This method prepares and returns a message dictionary. This dict
+ contains the various fields that are used to transfer information about
+ execution, results, tracebacks, etc, to clients (either in or out of
+ process ones). Because of the need to work with possibly out of
+ process clients, this dict MUST contain strictly pickle-safe values.
+ """
+
+ return dict(number=self.current_cell_number)
+
+ def setup_namespace(self):
+ """ Add things to the namespace.
+ """
+
+ self.user_ns.setdefault('__name__', '__main__')
+ self.user_ns.setdefault('__builtins__', __builtin__)
+ self.user_ns['__IP'] = self
+ if self.raw_input_builtin is not None:
+ self.user_ns['raw_input'] = self.raw_input_builtin
+ if self.input_builtin is not None:
+ self.user_ns['input'] = self.input_builtin
+
+ builtin_additions = dict(
+ ipmagic=self.ipmagic,
+ )
+ __builtin__.__dict__.update(builtin_additions)
+
+ if self.history is not None:
+ self.history.setup_namespace(self.user_ns)
+
+ def set_traps(self):
+ """ Set all of the output, display, and traceback traps.
+ """
+
+ self.output_trap.set()
+ self.display_trap.set()
+ self.traceback_trap.set()
+
+ def unset_traps(self):
+ """ Unset all of the output, display, and traceback traps.
+ """
+
+ self.output_trap.unset()
+ self.display_trap.unset()
+ self.traceback_trap.unset()
+
+ def split_commands(self, python):
+ """ Split multiple lines of code into discrete commands that can be
+ executed singly.
+
+ Parameters
+ ----------
+ python : str
+ Pure, exec'able Python code.
+
+ Returns
+ -------
+ commands : list of str
+ Separate commands that can be exec'ed independently.
+ """
+
+ # compiler.parse treats trailing spaces after a newline as a
+ # SyntaxError. This is different than codeop.CommandCompiler, which
+ # will compile the trailng spaces just fine. We simply strip any
+ # trailing whitespace off. Passing a string with trailing whitespace
+ # to exec will fail however. There seems to be some inconsistency in
+ # how trailing whitespace is handled, but this seems to work.
+ python = python.strip()
+
+ # The compiler module does not like unicode. We need to convert
+ # it encode it:
+ if isinstance(python, unicode):
+ # Use the utf-8-sig BOM so the compiler detects this a UTF-8
+ # encode string.
+ python = '\xef\xbb\xbf' + python.encode('utf-8')
+
+ # The compiler module will parse the code into an abstract syntax tree.
+ # This has a bug with str("a\nb"), but not str("""a\nb""")!!!
+ ast = compiler.parse(python)
+
+ # Uncomment to help debug the ast tree
+ # for n in ast.node:
+ # print n.lineno,'->',n
+
+ # Each separate command is available by iterating over ast.node. The
+ # lineno attribute is the line number (1-indexed) beginning the commands
+ # suite.
+ # lines ending with ";" yield a Discard Node that doesn't have a lineno
+ # attribute. These nodes can and should be discarded. But there are
+ # other situations that cause Discard nodes that shouldn't be discarded.
+ # We might eventually discover other cases where lineno is None and have
+ # to put in a more sophisticated test.
+ linenos = [x.lineno-1 for x in ast.node if x.lineno is not None]
+
+ # When we finally get the slices, we will need to slice all the way to
+ # the end even though we don't have a line number for it. Fortunately,
+ # None does the job nicely.
+ linenos.append(None)
+
+ # Same problem at the other end: sometimes the ast tree has its
+ # first complete statement not starting on line 0. In this case
+ # we might miss part of it. This fixes ticket 266993. Thanks Gael!
+ linenos[0] = 0
+
+ lines = python.splitlines()
+
+ # Create a list of atomic commands.
+ cmds = []
+ for i, j in zip(linenos[:-1], linenos[1:]):
+ cmd = lines[i:j]
+ if cmd:
+ cmds.append('\n'.join(cmd)+'\n')
+
+ return cmds
+
+ def error(self, text):
+ """ Pass an error message back to the shell.
+
+ Notes
+ -----
+ This should only be called when self.message is set. In other words,
+ when code is being executed.
+
+ Parameters
+ ----------
+ text : str
+ """
+
+ errors = self.message.get('IPYTHON_ERROR', [])
+ errors.append(text)
+
+ def var_expand(self, template):
+ """ Expand $variables in the current namespace using Itpl.
+
+ Parameters
+ ----------
+ template : str
+ """
+
+ return str(ItplNS(template, self.user_ns))
+
+ def _possible_macro(self, obj):
+ """ If the object is a macro, execute it.
+ """
+
+ if isinstance(obj, Macro):
+ self.execute_macro(obj)
+
diff --git a/IPython/kernel/core/macro.py b/IPython/kernel/core/macro.py
new file mode 100644
index 0000000..56d2b44
--- /dev/null
+++ b/IPython/kernel/core/macro.py
@@ -0,0 +1,34 @@
+# encoding: utf-8
+
+"""Support for interactive macros in IPython"""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+class Macro:
+ """Simple class to store the value of macros as strings.
+
+ This allows us to later exec them by checking when something is an
+ instance of this class."""
+
+ def __init__(self,data):
+
+ # store the macro value, as a single string which can be evaluated by
+ # runlines()
+ self.value = ''.join(data).rstrip()+'\n'
+
+ def __str__(self):
+ return self.value
+
+ def __repr__(self):
+ return 'IPython.macro.Macro(%s)' % repr(self.value) \ No newline at end of file
diff --git a/IPython/kernel/core/magic.py b/IPython/kernel/core/magic.py
new file mode 100644
index 0000000..967ce73
--- /dev/null
+++ b/IPython/kernel/core/magic.py
@@ -0,0 +1,147 @@
+# encoding: utf-8
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+import os
+import __builtin__
+
+# Local imports.
+from util import Bunch
+
+
+# fixme: RTK thinks magics should be implemented as separate classes rather than
+# methods on a single class. This would give us the ability to plug new magics
+# in and configure them separately.
+
+class Magic(object):
+ """ An object that maintains magic functions.
+ """
+
+ def __init__(self, interpreter, config=None):
+ # A reference to the interpreter.
+ self.interpreter = interpreter
+
+ # A reference to the configuration object.
+ if config is None:
+ # fixme: we need a better place to store this information.
+ config = Bunch(ESC_MAGIC='%')
+ self.config = config
+
+ def has_magic(self, name):
+ """ Return True if this object provides a given magic.
+
+ Parameters
+ ----------
+ name : str
+ """
+
+ return hasattr(self, 'magic_' + name)
+
+ def object_find(self, name):
+ """ Find an object in the available namespaces.
+
+ fixme: this should probably be moved elsewhere. The interpreter?
+ """
+
+ name = name.strip()
+
+ # Namespaces to search.
+ # fixme: implement internal and alias namespaces.
+ user_ns = self.interpreter.user_ns
+ internal_ns = {}
+ builtin_ns = __builtin__.__dict__
+ alias_ns = {}
+
+ # Order the namespaces.
+ namespaces = [
+ ('Interactive', user_ns),
+ ('IPython internal', internal_ns),
+ ('Python builtin', builtin_ns),
+ ('Alias', alias_ns),
+ ]
+
+ # Initialize all results.
+ found = False
+ obj = None
+ space = None
+ ds = None
+ ismagic = False
+ isalias = False
+
+ # Look for the given name by splitting it in parts. If the head is
+ # found, then we look for all the remaining parts as members, and only
+ # declare success if we can find them all.
+ parts = name.split('.')
+ head, rest = parts[0], parts[1:]
+ for nsname, ns in namespaces:
+ try:
+ obj = ns[head]
+ except KeyError:
+ continue
+ else:
+ for part in rest:
+ try:
+ obj = getattr(obj, part)
+ except:
+ # Blanket except b/c some badly implemented objects
+ # allow __getattr__ to raise exceptions other than
+ # AttributeError, which then crashes us.
+ break
+ else:
+ # If we finish the for loop (no break), we got all members
+ found = True
+ space = nsname
+ isalias = (ns == alias_ns)
+ break # namespace loop
+
+ # Try to see if it is a magic.
+ if not found:
+ if name.startswith(self.config.ESC_MAGIC):
+ name = name[1:]
+ obj = getattr(self, 'magic_' + name, None)
+ if obj is not None:
+ found = True
+ space = 'IPython internal'
+ ismagic = True
+
+ # Last try: special-case some literals like '', [], {}, etc:
+ if not found and head in ["''", '""', '[]', '{}', '()']:
+ obj = eval(head)
+ found = True
+ space = 'Interactive'
+
+ return dict(
+ found=found,
+ obj=obj,
+ namespace=space,
+ ismagic=ismagic,
+ isalias=isalias,
+ )
+
+
+
+
+
+ def magic_pwd(self, parameter_s=''):
+ """ Return the current working directory path.
+ """
+ return os.getcwd()
+
+ def magic_env(self, parameter_s=''):
+ """ List environment variables.
+ """
+
+ return os.environ.data
+
+
diff --git a/IPython/kernel/core/message_cache.py b/IPython/kernel/core/message_cache.py
new file mode 100644
index 0000000..f0385f5
--- /dev/null
+++ b/IPython/kernel/core/message_cache.py
@@ -0,0 +1,98 @@
+# encoding: utf-8
+
+"""Storage for the responses from the interpreter."""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+
+class IMessageCache(object):
+ """ Storage for the response from the interpreter.
+ """
+
+ def add_message(self, i, message):
+ """ Add a message dictionary to the cache.
+
+ Parameters
+ ----------
+ i : int
+ message : dict
+ """
+
+ def get_message(self, i=None):
+ """ Get the message from the cache.
+
+ Parameters
+ ----------
+ i : int, optional
+ The number of the message. If not provided, return the
+ highest-numbered message.
+
+ Returns
+ -------
+ message : dict
+
+ Raises
+ ------
+ IndexError if the message does not exist in the cache.
+ """
+
+
+class SimpleMessageCache(object):
+ """ Simple dictionary-based, in-memory storage of the responses from the
+ interpreter.
+ """
+
+ def __init__(self):
+ self.cache = {}
+
+ def add_message(self, i, message):
+ """ Add a message dictionary to the cache.
+
+ Parameters
+ ----------
+ i : int
+ message : dict
+ """
+
+ self.cache[i] = message
+
+ def get_message(self, i=None):
+ """ Get the message from the cache.
+
+ Parameters
+ ----------
+ i : int, optional
+ The number of the message. If not provided, return the
+ highest-numbered message.
+
+ Returns
+ -------
+ message : dict
+
+ Raises
+ ------
+ IndexError if the message does not exist in the cache.
+ """
+ if i is None:
+ keys = self.cache.keys()
+ if len(keys) == 0:
+ raise IndexError("index %r out of range" % i)
+ else:
+ i = max(self.cache.keys())
+ try:
+ return self.cache[i]
+ except KeyError:
+ # IndexError is more appropriate, here.
+ raise IndexError("index %r out of range" % i)
+
diff --git a/IPython/kernel/core/notification.py b/IPython/kernel/core/notification.py
new file mode 100644
index 0000000..ee9701e
--- /dev/null
+++ b/IPython/kernel/core/notification.py
@@ -0,0 +1,125 @@
+# encoding: utf-8
+
+"""The IPython Core Notification Center.
+
+See docs/source/development/notification_blueprint.txt for an overview of the
+notification module.
+"""
+
+__docformat__ = "restructuredtext en"
+
+#-----------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-----------------------------------------------------------------------------
+
+# Tell nose to skip the testing of this module
+__test__ = {}
+
+class NotificationCenter(object):
+ """Synchronous notification center
+
+ Examples
+ --------
+ >>> import IPython.kernel.core.notification as notification
+ >>> def callback(theType, theSender, args={}):
+ ... print theType,theSender,args
+ ...
+ >>> notification.sharedCenter.add_observer(callback, 'NOTIFICATION_TYPE', None)
+ >>> notification.sharedCenter.post_notification('NOTIFICATION_TYPE', object()) # doctest:+ELLIPSIS
+ NOTIFICATION_TYPE ...
+
+ """
+ def __init__(self):
+ super(NotificationCenter, self).__init__()
+ self._init_observers()
+
+
+ def _init_observers(self):
+ """Initialize observer storage"""
+
+ self.registered_types = set() #set of types that are observed
+ self.registered_senders = set() #set of senders that are observed
+ self.observers = {} #map (type,sender) => callback (callable)
+
+
+ def post_notification(self, theType, sender, **kwargs):
+ """Post notification (type,sender,**kwargs) to all registered
+ observers.
+
+ Implementation notes:
+
+ * If no registered observers, performance is O(1).
+ * Notificaiton order is undefined.
+ * Notifications are posted synchronously.
+ """
+
+ if(theType==None or sender==None):
+ raise Exception("NotificationCenter.post_notification requires \
+ type and sender.")
+
+ # If there are no registered observers for the type/sender pair
+ if((theType not in self.registered_types and
+ None not in self.registered_types) or
+ (sender not in self.registered_senders and
+ None not in self.registered_senders)):
+ return
+
+ for o in self._observers_for_notification(theType, sender):
+ o(theType, sender, args=kwargs)
+
+
+ def _observers_for_notification(self, theType, sender):
+ """Find all registered observers that should recieve notification"""
+
+ keys = (
+ (theType,sender),
+ (theType, None),
+ (None, sender),
+ (None,None)
+ )
+
+
+ obs = set()
+ for k in keys:
+ obs.update(self.observers.get(k, set()))
+
+ return obs
+
+
+ def add_observer(self, callback, theType, sender):
+ """Add an observer callback to this notification center.
+
+ The given callback will be called upon posting of notifications of
+ the given type/sender and will receive any additional kwargs passed
+ to post_notification.
+
+ Parameters
+ ----------
+ observerCallback : callable
+ Callable. Must take at least two arguments::
+ observerCallback(type, sender, args={})
+
+ theType : hashable
+ The notification type. If None, all notifications from sender
+ will be posted.
+
+ sender : hashable
+ The notification sender. If None, all notifications of theType
+ will be posted.
+ """
+ assert(callback != None)
+ self.registered_types.add(theType)
+ self.registered_senders.add(sender)
+ self.observers.setdefault((theType,sender), set()).add(callback)
+
+ def remove_all_observers(self):
+ """Removes all observers from this notification center"""
+
+ self._init_observers()
+
+
+
+sharedCenter = NotificationCenter()
diff --git a/IPython/kernel/core/output_trap.py b/IPython/kernel/core/output_trap.py
new file mode 100644
index 0000000..3c1b4c2
--- /dev/null
+++ b/IPython/kernel/core/output_trap.py
@@ -0,0 +1,107 @@
+# encoding: utf-8
+
+""" Trap stdout/stderr."""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+import sys
+from cStringIO import StringIO
+
+
+class OutputTrap(object):
+ """ Object which can trap text sent to stdout and stderr.
+ """
+
+ def __init__(self, out=None, err=None):
+ # Filelike objects to store stdout/stderr text.
+ if out is None:
+ self.out = StringIO()
+ else:
+ self.out = out
+ if err is None:
+ self.err = StringIO()
+ else:
+ self.err = err
+
+ # Boolean to check if the stdout/stderr hook is set.
+ self.out_set = False
+ self.err_set = False
+
+ @property
+ def out_text(self):
+ """ Return the text currently in the stdout buffer.
+ """
+ return self.out.getvalue()
+
+ @property
+ def err_text(self):
+ """ Return the text currently in the stderr buffer.
+ """
+ return self.err.getvalue()
+
+ def set(self):
+ """ Set the hooks.
+ """
+
+ if sys.stdout is not self.out:
+ self._out_save = sys.stdout
+ sys.stdout = self.out
+ self.out_set = True
+
+ if sys.stderr is not self.err:
+ self._err_save = sys.stderr
+ sys.stderr = self.err
+ self.err_set = True
+
+ def unset(self):
+ """ Remove the hooks.
+ """
+
+ if self.out_set:
+ sys.stdout = self._out_save
+ self.out_set = False
+
+ if self.err_set:
+ sys.stderr = self._err_save
+ self.err_set = False
+
+ def clear(self):
+ """ Clear out the buffers.
+ """
+
+ self.out.reset()
+ self.out.truncate()
+
+ self.err.reset()
+ self.err.truncate()
+
+ def add_to_message(self, message):
+ """ Add the text from stdout and stderr to the message from the
+ interpreter to its listeners.
+
+ Parameters
+ ----------
+ message : dict
+ """
+
+ out_text = self.out_text
+ if out_text:
+ message['stdout'] = out_text
+
+ err_text = self.err_text
+ if err_text:
+ message['stderr'] = err_text
+
+
+
diff --git a/IPython/kernel/core/prompts.py b/IPython/kernel/core/prompts.py
new file mode 100644
index 0000000..be654ac
--- /dev/null
+++ b/IPython/kernel/core/prompts.py
@@ -0,0 +1,588 @@
+# encoding: utf-8
+"""Classes for handling input/output prompts.
+
+Authors
+-------
+- Fernando Perez <Fernando.Perez@berkeley.edu>
+"""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+# Required modules
+import __builtin__
+import os
+import socket
+import sys
+import time
+
+# IPython's own
+from IPython.external.Itpl import ItplNS
+from macro import Macro
+
+from IPython import ColorANSI
+from IPython import Release
+from IPython.ipapi import TryNext
+from IPython.ipstruct import Struct
+from IPython.genutils import *
+
+#****************************************************************************
+#Color schemes for Prompts.
+
+PromptColors = ColorANSI.ColorSchemeTable()
+InputColors = ColorANSI.InputTermColors # just a shorthand
+Colors = ColorANSI.TermColors # just a shorthand
+
+
+__PColNoColor = ColorANSI.ColorScheme(
+ 'NoColor',
+ in_prompt = InputColors.NoColor, # Input prompt
+ in_number = InputColors.NoColor, # Input prompt number
+ in_prompt2 = InputColors.NoColor, # Continuation prompt
+ in_normal = InputColors.NoColor, # color off (usu. Colors.Normal)
+
+ out_prompt = Colors.NoColor, # Output prompt
+ out_number = Colors.NoColor, # Output prompt number
+
+ normal = Colors.NoColor # color off (usu. Colors.Normal)
+ )
+
+PromptColors.add_scheme(__PColNoColor)
+
+# make some schemes as instances so we can copy them for modification easily:
+__PColLinux = __PColNoColor.copy('Linux')
+# Don't forget to enter it into the table!
+PromptColors.add_scheme(__PColLinux)
+__PColLightBG = __PColLinux.copy('LightBG')
+PromptColors.add_scheme(__PColLightBG)
+
+del Colors,InputColors
+
+#-----------------------------------------------------------------------------
+def multiple_replace(dict, text):
+ """ Replace in 'text' all occurences of any key in the given
+ dictionary by its corresponding value. Returns the new string."""
+
+ # Function by Xavier Defrang, originally found at:
+ # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/81330
+
+ # Create a regular expression from the dictionary keys
+ regex = re.compile("(%s)" % "|".join(map(re.escape, dict.keys())))
+ # For each match, look-up corresponding value in dictionary
+ return regex.sub(lambda mo: dict[mo.string[mo.start():mo.end()]], text)
+
+#-----------------------------------------------------------------------------
+# Special characters that can be used in prompt templates, mainly bash-like
+
+# If $HOME isn't defined (Windows), make it an absurd string so that it can
+# never be expanded out into '~'. Basically anything which can never be a
+# reasonable directory name will do, we just want the $HOME -> '~' operation
+# to become a no-op. We pre-compute $HOME here so it's not done on every
+# prompt call.
+
+# FIXME:
+
+# - This should be turned into a class which does proper namespace management,
+# since the prompt specials need to be evaluated in a certain namespace.
+# Currently it's just globals, which need to be managed manually by code
+# below.
+
+# - I also need to split up the color schemes from the prompt specials
+# somehow. I don't have a clean design for that quite yet.
+
+HOME = os.environ.get("HOME","//////:::::ZZZZZ,,,~~~")
+
+# We precompute a few more strings here for the prompt_specials, which are
+# fixed once ipython starts. This reduces the runtime overhead of computing
+# prompt strings.
+USER = os.environ.get("USER")
+HOSTNAME = socket.gethostname()
+HOSTNAME_SHORT = HOSTNAME.split(".")[0]
+ROOT_SYMBOL = "$#"[os.name=='nt' or os.getuid()==0]
+
+prompt_specials_color = {
+ # Prompt/history count
+ '%n' : '${self.col_num}' '${self.cache.prompt_count}' '${self.col_p}',
+ r'\#': '${self.col_num}' '${self.cache.prompt_count}' '${self.col_p}',
+ # Just the prompt counter number, WITHOUT any coloring wrappers, so users
+ # can get numbers displayed in whatever color they want.
+ r'\N': '${self.cache.prompt_count}',
+ # Prompt/history count, with the actual digits replaced by dots. Used
+ # mainly in continuation prompts (prompt_in2)
+ r'\D': '${"."*len(str(self.cache.prompt_count))}',
+ # Current working directory
+ r'\w': '${os.getcwd()}',
+ # Current time
+ r'\t' : '${time.strftime("%H:%M:%S")}',
+ # Basename of current working directory.
+ # (use os.sep to make this portable across OSes)
+ r'\W' : '${os.getcwd().split("%s")[-1]}' % os.sep,
+ # These X<N> are an extension to the normal bash prompts. They return
+ # N terms of the path, after replacing $HOME with '~'
+ r'\X0': '${os.getcwd().replace("%s","~")}' % HOME,
+ r'\X1': '${self.cwd_filt(1)}',
+ r'\X2': '${self.cwd_filt(2)}',
+ r'\X3': '${self.cwd_filt(3)}',
+ r'\X4': '${self.cwd_filt(4)}',
+ r'\X5': '${self.cwd_filt(5)}',
+ # Y<N> are similar to X<N>, but they show '~' if it's the directory
+ # N+1 in the list. Somewhat like %cN in tcsh.
+ r'\Y0': '${self.cwd_filt2(0)}',
+ r'\Y1': '${self.cwd_filt2(1)}',
+ r'\Y2': '${self.cwd_filt2(2)}',
+ r'\Y3': '${self.cwd_filt2(3)}',
+ r'\Y4': '${self.cwd_filt2(4)}',
+ r'\Y5': '${self.cwd_filt2(5)}',
+ # Hostname up to first .
+ r'\h': HOSTNAME_SHORT,
+ # Full hostname
+ r'\H': HOSTNAME,
+ # Username of current user
+ r'\u': USER,
+ # Escaped '\'
+ '\\\\': '\\',
+ # Newline
+ r'\n': '\n',
+ # Carriage return
+ r'\r': '\r',
+ # Release version
+ r'\v': Release.version,
+ # Root symbol ($ or #)
+ r'\$': ROOT_SYMBOL,
+ }
+
+# A copy of the prompt_specials dictionary but with all color escapes removed,
+# so we can correctly compute the prompt length for the auto_rewrite method.
+prompt_specials_nocolor = prompt_specials_color.copy()
+prompt_specials_nocolor['%n'] = '${self.cache.prompt_count}'
+prompt_specials_nocolor[r'\#'] = '${self.cache.prompt_count}'
+
+# Add in all the InputTermColors color escapes as valid prompt characters.
+# They all get added as \\C_COLORNAME, so that we don't have any conflicts
+# with a color name which may begin with a letter used by any other of the
+# allowed specials. This of course means that \\C will never be allowed for
+# anything else.
+input_colors = ColorANSI.InputTermColors
+for _color in dir(input_colors):
+ if _color[0] != '_':
+ c_name = r'\C_'+_color
+ prompt_specials_color[c_name] = getattr(input_colors,_color)
+ prompt_specials_nocolor[c_name] = ''
+
+# we default to no color for safety. Note that prompt_specials is a global
+# variable used by all prompt objects.
+prompt_specials = prompt_specials_nocolor
+
+#-----------------------------------------------------------------------------
+def str_safe(arg):
+ """Convert to a string, without ever raising an exception.
+
+ If str(arg) fails, <ERROR: ... > is returned, where ... is the exception
+ error message."""
+
+ try:
+ out = str(arg)
+ except UnicodeError:
+ try:
+ out = arg.encode('utf_8','replace')
+ except Exception,msg:
+ # let's keep this little duplication here, so that the most common
+ # case doesn't suffer from a double try wrapping.
+ out = '<ERROR: %s>' % msg
+ except Exception,msg:
+ out = '<ERROR: %s>' % msg
+ return out
+
+class BasePrompt(object):
+ """Interactive prompt similar to Mathematica's."""
+
+ def _get_p_template(self):
+ return self._p_template
+
+ def _set_p_template(self,val):
+ self._p_template = val
+ self.set_p_str()
+
+ p_template = property(_get_p_template,_set_p_template,
+ doc='Template for prompt string creation')
+
+ def __init__(self,cache,sep,prompt,pad_left=False):
+
+ # Hack: we access information about the primary prompt through the
+ # cache argument. We need this, because we want the secondary prompt
+ # to be aligned with the primary one. Color table info is also shared
+ # by all prompt classes through the cache. Nice OO spaghetti code!
+ self.cache = cache
+ self.sep = sep
+
+ # regexp to count the number of spaces at the end of a prompt
+ # expression, useful for prompt auto-rewriting
+ self.rspace = re.compile(r'(\s*)$')
+ # Flag to left-pad prompt strings to match the length of the primary
+ # prompt
+ self.pad_left = pad_left
+
+ # Set template to create each actual prompt (where numbers change).
+ # Use a property
+ self.p_template = prompt
+ self.set_p_str()
+
+ def set_p_str(self):
+ """ Set the interpolating prompt strings.
+
+ This must be called every time the color settings change, because the
+ prompt_specials global may have changed."""
+
+ import os,time # needed in locals for prompt string handling
+ loc = locals()
+ self.p_str = ItplNS('%s%s%s' %
+ ('${self.sep}${self.col_p}',
+ multiple_replace(prompt_specials, self.p_template),
+ '${self.col_norm}'),self.cache.user_ns,loc)
+
+ self.p_str_nocolor = ItplNS(multiple_replace(prompt_specials_nocolor,
+ self.p_template),
+ self.cache.user_ns,loc)
+
+ def write(self,msg): # dbg
+ sys.stdout.write(msg)
+ return ''
+
+ def __str__(self):
+ """Return a string form of the prompt.
+
+ This for is useful for continuation and output prompts, since it is
+ left-padded to match lengths with the primary one (if the
+ self.pad_left attribute is set)."""
+
+ out_str = str_safe(self.p_str)
+ if self.pad_left:
+ # We must find the amount of padding required to match lengths,
+ # taking the color escapes (which are invisible on-screen) into
+ # account.
+ esc_pad = len(out_str) - len(str_safe(self.p_str_nocolor))
+ format = '%%%ss' % (len(str(self.cache.last_prompt))+esc_pad)
+ return format % out_str
+ else:
+ return out_str
+
+ # these path filters are put in as methods so that we can control the
+ # namespace where the prompt strings get evaluated
+ def cwd_filt(self,depth):
+ """Return the last depth elements of the current working directory.
+
+ $HOME is always replaced with '~'.
+ If depth==0, the full path is returned."""
+
+ cwd = os.getcwd().replace(HOME,"~")
+ out = os.sep.join(cwd.split(os.sep)[-depth:])
+ if out:
+ return out
+ else:
+ return os.sep
+
+ def cwd_filt2(self,depth):
+ """Return the last depth elements of the current working directory.
+
+ $HOME is always replaced with '~'.
+ If depth==0, the full path is returned."""
+
+ cwd = os.getcwd().replace(HOME,"~").split(os.sep)
+ if '~' in cwd and len(cwd) == depth+1:
+ depth += 1
+ out = os.sep.join(cwd[-depth:])
+ if out:
+ return out
+ else:
+ return os.sep
+
+class Prompt1(BasePrompt):
+ """Input interactive prompt similar to Mathematica's."""
+
+ def __init__(self,cache,sep='\n',prompt='In [\\#]: ',pad_left=True):
+ BasePrompt.__init__(self,cache,sep,prompt,pad_left)
+
+ def set_colors(self):
+ self.set_p_str()
+ Colors = self.cache.color_table.active_colors # shorthand
+ self.col_p = Colors.in_prompt
+ self.col_num = Colors.in_number
+ self.col_norm = Colors.in_normal
+ # We need a non-input version of these escapes for the '--->'
+ # auto-call prompts used in the auto_rewrite() method.
+ self.col_p_ni = self.col_p.replace('\001','').replace('\002','')
+ self.col_norm_ni = Colors.normal
+
+ def __str__(self):
+ self.cache.prompt_count += 1
+ self.cache.last_prompt = str_safe(self.p_str_nocolor).split('\n')[-1]
+ return str_safe(self.p_str)
+
+ def auto_rewrite(self):
+ """Print a string of the form '--->' which lines up with the previous
+ input string. Useful for systems which re-write the user input when
+ handling automatically special syntaxes."""
+
+ curr = str(self.cache.last_prompt)
+ nrspaces = len(self.rspace.search(curr).group())
+ return '%s%s>%s%s' % (self.col_p_ni,'-'*(len(curr)-nrspaces-1),
+ ' '*nrspaces,self.col_norm_ni)
+
+class PromptOut(BasePrompt):
+ """Output interactive prompt similar to Mathematica's."""
+
+ def __init__(self,cache,sep='',prompt='Out[\\#]: ',pad_left=True):
+ BasePrompt.__init__(self,cache,sep,prompt,pad_left)
+ if not self.p_template:
+ self.__str__ = lambda: ''
+
+ def set_colors(self):
+ self.set_p_str()
+ Colors = self.cache.color_table.active_colors # shorthand
+ self.col_p = Colors.out_prompt
+ self.col_num = Colors.out_number
+ self.col_norm = Colors.normal
+
+class Prompt2(BasePrompt):
+ """Interactive continuation prompt."""
+
+ def __init__(self,cache,prompt=' .\\D.: ',pad_left=True):
+ self.cache = cache
+ self.p_template = prompt
+ self.pad_left = pad_left
+ self.set_p_str()
+
+ def set_p_str(self):
+ import os,time # needed in locals for prompt string handling
+ loc = locals()
+ self.p_str = ItplNS('%s%s%s' %
+ ('${self.col_p2}',
+ multiple_replace(prompt_specials, self.p_template),
+ '$self.col_norm'),
+ self.cache.user_ns,loc)
+ self.p_str_nocolor = ItplNS(multiple_replace(prompt_specials_nocolor,
+ self.p_template),
+ self.cache.user_ns,loc)
+
+ def set_colors(self):
+ self.set_p_str()
+ Colors = self.cache.color_table.active_colors
+ self.col_p2 = Colors.in_prompt2
+ self.col_norm = Colors.in_normal
+ # FIXME (2004-06-16) HACK: prevent crashes for users who haven't
+ # updated their prompt_in2 definitions. Remove eventually.
+ self.col_p = Colors.out_prompt
+ self.col_num = Colors.out_number
+
+
+#-----------------------------------------------------------------------------
+class CachedOutput:
+ """Class for printing output from calculations while keeping a cache of
+ reults. It dynamically creates global variables prefixed with _ which
+ contain these results.
+
+ Meant to be used as a sys.displayhook replacement, providing numbered
+ prompts and cache services.
+
+ Initialize with initial and final values for cache counter (this defines
+ the maximum size of the cache."""
+
+ def __init__(self,shell,cache_size,Pprint,
+ colors='NoColor',input_sep='\n',
+ output_sep='\n',output_sep2='',
+ ps1 = None, ps2 = None,ps_out = None,pad_left=True):
+
+ cache_size_min = 3
+ if cache_size <= 0:
+ self.do_full_cache = 0
+ cache_size = 0
+ elif cache_size < cache_size_min:
+ self.do_full_cache = 0
+ cache_size = 0
+ warn('caching was disabled (min value for cache size is %s).' %
+ cache_size_min,level=3)
+ else:
+ self.do_full_cache = 1
+
+ self.cache_size = cache_size
+ self.input_sep = input_sep
+
+ # we need a reference to the user-level namespace
+ self.shell = shell
+ self.user_ns = shell.user_ns
+ # and to the user's input
+ self.input_hist = shell.history.input_cache
+
+ # Set input prompt strings and colors
+ if cache_size == 0:
+ if ps1.find('%n') > -1 or ps1.find(r'\#') > -1 \
+ or ps1.find(r'\N') > -1:
+ ps1 = '>>> '
+ if ps2.find('%n') > -1 or ps2.find(r'\#') > -1 \
+ or ps2.find(r'\N') > -1:
+ ps2 = '... '
+ self.ps1_str = self._set_prompt_str(ps1,'In [\\#]: ','>>> ')
+ self.ps2_str = self._set_prompt_str(ps2,' .\\D.: ','... ')
+ self.ps_out_str = self._set_prompt_str(ps_out,'Out[\\#]: ','')
+
+ self.color_table = PromptColors
+ self.prompt1 = Prompt1(self,sep=input_sep,prompt=self.ps1_str,
+ pad_left=pad_left)
+ self.prompt2 = Prompt2(self,prompt=self.ps2_str,pad_left=pad_left)
+ self.prompt_out = PromptOut(self,sep='',prompt=self.ps_out_str,
+ pad_left=pad_left)
+ self.set_colors(colors)
+
+ # other more normal stuff
+ # b/c each call to the In[] prompt raises it by 1, even the first.
+ self.prompt_count = 0
+ # Store the last prompt string each time, we need it for aligning
+ # continuation and auto-rewrite prompts
+ self.last_prompt = ''
+ self.Pprint = Pprint
+ self.output_sep = output_sep
+ self.output_sep2 = output_sep2
+ self._,self.__,self.___ = '','',''
+ self.pprint_types = map(type,[(),[],{}])
+
+ # these are deliberately global:
+ to_user_ns = {'_':self._,'__':self.__,'___':self.___}
+ self.user_ns.update(to_user_ns)
+
+ def _set_prompt_str(self,p_str,cache_def,no_cache_def):
+ if p_str is None:
+ if self.do_full_cache:
+ return cache_def
+ else:
+ return no_cache_def
+ else:
+ return p_str
+
+ def set_colors(self,colors):
+ """Set the active color scheme and configure colors for the three
+ prompt subsystems."""
+
+ # FIXME: the prompt_specials global should be gobbled inside this
+ # class instead. Do it when cleaning up the whole 3-prompt system.
+ global prompt_specials
+ if colors.lower()=='nocolor':
+ prompt_specials = prompt_specials_nocolor
+ else:
+ prompt_specials = prompt_specials_color
+
+ self.color_table.set_active_scheme(colors)
+ self.prompt1.set_colors()
+ self.prompt2.set_colors()
+ self.prompt_out.set_colors()
+
+ def __call__(self,arg=None):
+ """Printing with history cache management.
+
+ This is invoked everytime the interpreter needs to print, and is
+ activated by setting the variable sys.displayhook to it."""
+
+ # If something injected a '_' variable in __builtin__, delete
+ # ipython's automatic one so we don't clobber that. gettext() in
+ # particular uses _, so we need to stay away from it.
+ if '_' in __builtin__.__dict__:
+ try:
+ del self.user_ns['_']
+ except KeyError:
+ pass
+ if arg is not None:
+ cout_write = Term.cout.write # fast lookup
+ # first handle the cache and counters
+
+ # do not print output if input ends in ';'
+ if self.input_hist[self.prompt_count].endswith(';\n'):
+ return
+ # don't use print, puts an extra space
+ cout_write(self.output_sep)
+ outprompt = self.shell.hooks.generate_output_prompt()
+ if self.do_full_cache:
+ cout_write(outprompt)
+
+ # and now call a possibly user-defined print mechanism
+ manipulated_val = self.display(arg)
+
+ # user display hooks can change the variable to be stored in
+ # output history
+
+ if manipulated_val is not None:
+ arg = manipulated_val
+
+ # avoid recursive reference when displaying _oh/Out
+ if arg is not self.user_ns['_oh']:
+ self.update(arg)
+
+ cout_write(self.output_sep2)
+ Term.cout.flush()
+
+ def _display(self,arg):
+ """Default printer method, uses pprint.
+
+ Do ip.set_hook("result_display", my_displayhook) for custom result
+ display, e.g. when your own objects need special formatting.
+ """
+ try:
+ return IPython.generics.result_display(arg)
+ except TryNext:
+ return self.shell.hooks.result_display(arg)
+
+ # Assign the default display method:
+ display = _display
+
+ def update(self,arg):
+ #print '***cache_count', self.cache_count # dbg
+ if len(self.user_ns['_oh']) >= self.cache_size and self.do_full_cache:
+ warn('Output cache limit (currently '+
+ `self.cache_size`+' entries) hit.\n'
+ 'Flushing cache and resetting history counter...\n'
+ 'The only history variables available will be _,__,___ and _1\n'
+ 'with the current result.')
+
+ self.flush()
+ # Don't overwrite '_' and friends if '_' is in __builtin__ (otherwise
+ # we cause buggy behavior for things like gettext).
+ if '_' not in __builtin__.__dict__:
+ self.___ = self.__
+ self.__ = self._
+ self._ = arg
+ self.user_ns.update({'_':self._,'__':self.__,'___':self.___})
+
+ # hackish access to top-level namespace to create _1,_2... dynamically
+ to_main = {}
+ if self.do_full_cache:
+ new_result = '_'+`self.prompt_count`
+ to_main[new_result] = arg
+ self.user_ns.update(to_main)
+ self.user_ns['_oh'][self.prompt_count] = arg
+
+ def flush(self):
+ if not self.do_full_cache:
+ raise ValueError,"You shouldn't have reached the cache flush "\
+ "if full caching is not enabled!"
+ # delete auto-generated vars from global namespace
+
+ for n in range(1,self.prompt_count + 1):
+ key = '_'+`n`
+ try:
+ del self.user_ns[key]
+ except: pass
+ self.user_ns['_oh'].clear()
+
+ if '_' not in __builtin__.__dict__:
+ self.user_ns.update({'_':None,'__':None, '___':None})
+ import gc
+ gc.collect() # xxx needed?
+
diff --git a/IPython/kernel/core/redirector_output_trap.py b/IPython/kernel/core/redirector_output_trap.py
new file mode 100644
index 0000000..fcc3f71
--- /dev/null
+++ b/IPython/kernel/core/redirector_output_trap.py
@@ -0,0 +1,97 @@
+# encoding: utf-8
+
+"""
+Trap stdout/stderr, including at the OS level. Calls a callback with
+the output each time Python tries to write to the stdout or stderr.
+"""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+from fd_redirector import FDRedirector, STDOUT, STDERR
+
+from IPython.kernel.core.file_like import FileLike
+from IPython.kernel.core.output_trap import OutputTrap
+
+class RedirectorOutputTrap(OutputTrap):
+ """ Object which can trap text sent to stdout and stderr.
+ """
+
+ #------------------------------------------------------------------------
+ # OutputTrap interface.
+ #------------------------------------------------------------------------
+ def __init__(self, out_callback, err_callback):
+ """
+ out_callback : callable called when there is output in the stdout
+ err_callback : callable called when there is output in the stderr
+ """
+ # Callback invoked on write to stdout and stderr
+ self.out_callback = out_callback
+ self.err_callback = err_callback
+
+ # File descriptor redirectors, to capture non-Python
+ # output.
+ self.out_redirector = FDRedirector(STDOUT)
+ self.err_redirector = FDRedirector(STDERR)
+
+ # Call the base class with file like objects that will trigger
+ # our callbacks
+ OutputTrap.__init__(self, out=FileLike(self.on_out_write),
+ err=FileLike(self.on_err_write), )
+
+
+ def set(self):
+ """ Set the hooks: set the redirectors and call the base class.
+ """
+ self.out_redirector.start()
+ self.err_redirector.start()
+ OutputTrap.set(self)
+
+
+ def unset(self):
+ """ Remove the hooks: call the base class and stop the
+ redirectors.
+ """
+ OutputTrap.unset(self)
+ # Flush the redirectors before stopping them
+ self.on_err_write('')
+ self.err_redirector.stop()
+ self.on_out_write('')
+ self.out_redirector.stop()
+
+
+ #------------------------------------------------------------------------
+ # Callbacks for synchronous output
+ #------------------------------------------------------------------------
+ def on_out_write(self, string):
+ """ Callback called when there is some Python output on stdout.
+ """
+ try:
+ self.out_callback(self.out_redirector.getvalue() + string)
+ except:
+ # If tracebacks are happening and we can't see them, it is
+ # quasy impossible to debug
+ self.unset()
+ raise
+
+ def on_err_write(self, string):
+ """ Callback called when there is some Python output on stderr.
+ """
+ try:
+ self.err_callback(self.err_redirector.getvalue() + string)
+ except:
+ # If tracebacks are happening and we can't see them, it is
+ # quasy impossible to debug
+ self.unset()
+ raise
+
diff --git a/IPython/kernel/core/sync_traceback_trap.py b/IPython/kernel/core/sync_traceback_trap.py
new file mode 100644
index 0000000..cf9e1bf
--- /dev/null
+++ b/IPython/kernel/core/sync_traceback_trap.py
@@ -0,0 +1,53 @@
+# encoding: utf-8
+
+"""Object to manage sys.excepthook().
+
+Synchronous version: prints errors when called.
+"""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+from traceback_trap import TracebackTrap
+from IPython.ultraTB import ColorTB
+
+class SyncTracebackTrap(TracebackTrap):
+ """ TracebackTrap that displays immediatly the traceback in addition
+ to capturing it. Useful in frontends, as without this traceback trap,
+ some tracebacks never get displayed.
+ """
+
+ def __init__(self, sync_formatter=None, formatters=None,
+ raiseException=True):
+ """
+ sync_formatter: Callable to display the traceback.
+ formatters: A list of formatters to apply.
+ """
+ TracebackTrap.__init__(self, formatters=formatters)
+ if sync_formatter is None:
+ sync_formatter = ColorTB(color_scheme='LightBG')
+ self.sync_formatter = sync_formatter
+ self.raiseException = raiseException
+
+
+ def hook(self, *args):
+ """ This method actually implements the hook.
+ """
+ self.args = args
+ if not self.raiseException:
+ print self.sync_formatter(*self.args)
+ else:
+ raise
+
+
+
+
diff --git a/IPython/kernel/core/tests/__init__.py b/IPython/kernel/core/tests/__init__.py
new file mode 100644
index 0000000..9a4495f
--- /dev/null
+++ b/IPython/kernel/core/tests/__init__.py
@@ -0,0 +1,10 @@
+# encoding: utf-8
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#------------------------------------------------------------------------------- \ No newline at end of file
diff --git a/IPython/kernel/core/tests/test_interpreter.py b/IPython/kernel/core/tests/test_interpreter.py
new file mode 100644
index 0000000..bee4d9a
--- /dev/null
+++ b/IPython/kernel/core/tests/test_interpreter.py
@@ -0,0 +1,62 @@
+# encoding: utf-8
+
+"""This file contains unittests for the interpreter.py module."""
+
+#-----------------------------------------------------------------------------
+# Copyright (C) 2008-2009 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is
+# in the file COPYING, distributed as part of this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+# Tell nose to skip this module
+__test__ = {}
+
+from twisted.trial import unittest
+from IPython.kernel.core.interpreter import Interpreter
+
+#-----------------------------------------------------------------------------
+# Tests
+#-----------------------------------------------------------------------------
+
+class TestInterpreter(unittest.TestCase):
+
+ def test_unicode(self):
+ """ Test unicode handling with the interpreter."""
+ i = Interpreter()
+ i.execute_python(u'print "ù"')
+ i.execute_python('print "ù"')
+
+ def test_ticket266993(self):
+ """ Test for ticket 266993."""
+ i = Interpreter()
+ i.execute('str("""a\nb""")')
+
+ def test_ticket364347(self):
+ """Test for ticket 364347."""
+ i = Interpreter()
+ i.split_commands('str("a\\nb")')
+
+ def test_split_commands(self):
+ """ Test that commands are indeed individually split."""
+ i = Interpreter()
+ test_atoms = [('(1\n + 1)', ),
+ ('1', '1', ),
+ ]
+ for atoms in test_atoms:
+ atoms = [atom.rstrip() + '\n' for atom in atoms]
+ self.assertEquals(i.split_commands(''.join(atoms)),atoms)
+
+ def test_long_lines(self):
+ """ Test for spurious syntax error created by the interpreter."""
+ test_strings = [u'( 1 +\n 1\n )\n\n',
+ u'(1 \n + 1\n )\n\n',
+ ]
+ i = Interpreter()
+ for s in test_strings:
+ i.execute(s)
+
diff --git a/IPython/kernel/core/tests/test_notification.py b/IPython/kernel/core/tests/test_notification.py
new file mode 100644
index 0000000..2744049
--- /dev/null
+++ b/IPython/kernel/core/tests/test_notification.py
@@ -0,0 +1,161 @@
+# encoding: utf-8
+
+"""This file contains unittests for the notification.py module."""
+
+#-----------------------------------------------------------------------------
+# Copyright (C) 2008-2009 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is
+# in the file COPYING, distributed as part of this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+# Tell nose to skip this module
+__test__ = {}
+
+from twisted.trial import unittest
+import IPython.kernel.core.notification as notification
+
+#-----------------------------------------------------------------------------
+# Support Classes
+#-----------------------------------------------------------------------------
+
+class Observer(object):
+ """docstring for Observer"""
+ def __init__(self, expectedType, expectedSender,
+ center=notification.sharedCenter, **kwargs):
+ super(Observer, self).__init__()
+ self.expectedType = expectedType
+ self.expectedSender = expectedSender
+ self.expectedKwArgs = kwargs
+ self.recieved = False
+ center.add_observer(self.callback,
+ self.expectedType,
+ self.expectedSender)
+
+ def callback(self, theType, sender, args={}):
+ """callback"""
+
+ assert(theType == self.expectedType or
+ self.expectedType == None)
+ assert(sender == self.expectedSender or
+ self.expectedSender == None)
+ assert(args == self.expectedKwArgs)
+ self.recieved = True
+
+ def verify(self):
+ """verify"""
+
+ assert(self.recieved)
+
+ def reset(self):
+ """reset"""
+
+ self.recieved = False
+
+
+class Notifier(object):
+ """docstring for Notifier"""
+ def __init__(self, theType, **kwargs):
+ super(Notifier, self).__init__()
+ self.theType = theType
+ self.kwargs = kwargs
+
+ def post(self, center=notification.sharedCenter):
+ """fire"""
+
+ center.post_notification(self.theType, self,
+ **self.kwargs)
+
+#-----------------------------------------------------------------------------
+# Tests
+#-----------------------------------------------------------------------------
+
+class NotificationTests(unittest.TestCase):
+ """docstring for NotificationTests"""
+
+ def tearDown(self):
+ notification.sharedCenter.remove_all_observers()
+
+ def test_notification_delivered(self):
+ """Test that notifications are delivered"""
+ expectedType = 'EXPECTED_TYPE'
+ sender = Notifier(expectedType)
+ observer = Observer(expectedType, sender)
+
+ sender.post()
+
+ observer.verify()
+
+ def test_type_specificity(self):
+ """Test that observers are registered by type"""
+
+ expectedType = 1
+ unexpectedType = "UNEXPECTED_TYPE"
+ sender = Notifier(expectedType)
+ unexpectedSender = Notifier(unexpectedType)
+ observer = Observer(expectedType, sender)
+
+ sender.post()
+ unexpectedSender.post()
+
+ observer.verify()
+
+ def test_sender_specificity(self):
+ """Test that observers are registered by sender"""
+
+ expectedType = "EXPECTED_TYPE"
+ sender1 = Notifier(expectedType)
+ sender2 = Notifier(expectedType)
+ observer = Observer(expectedType, sender1)
+
+ sender1.post()
+ sender2.post()
+
+ observer.verify()
+
+ def test_remove_all_observers(self):
+ """White-box test for remove_all_observers"""
+
+ for i in xrange(10):
+ Observer('TYPE', None, center=notification.sharedCenter)
+
+ self.assert_(len(notification.sharedCenter.observers[('TYPE',None)]) >= 10,
+ "observers registered")
+
+ notification.sharedCenter.remove_all_observers()
+
+ self.assert_(len(notification.sharedCenter.observers) == 0, "observers removed")
+
+ def test_any_sender(self):
+ """test_any_sender"""
+
+ expectedType = "EXPECTED_TYPE"
+ sender1 = Notifier(expectedType)
+ sender2 = Notifier(expectedType)
+ observer = Observer(expectedType, None)
+
+
+ sender1.post()
+ observer.verify()
+
+ observer.reset()
+ sender2.post()
+ observer.verify()
+
+ def test_post_performance(self):
+ """Test that post_notification, even with many registered irrelevant
+ observers is fast"""
+
+ for i in xrange(10):
+ Observer("UNRELATED_TYPE", None)
+
+ o = Observer('EXPECTED_TYPE', None)
+
+ notification.sharedCenter.post_notification('EXPECTED_TYPE', self)
+
+ o.verify()
+
diff --git a/IPython/kernel/core/tests/test_redirectors.py b/IPython/kernel/core/tests/test_redirectors.py
new file mode 100644
index 0000000..3b0e416
--- /dev/null
+++ b/IPython/kernel/core/tests/test_redirectors.py
@@ -0,0 +1,78 @@
+# encoding: utf-8
+"""
+Test the output capture at the OS level, using file descriptors.
+"""
+#-----------------------------------------------------------------------------
+# Copyright (C) 2008-2009 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is
+# in the file COPYING, distributed as part of this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+# Tell nose to skip this module
+__test__ = {}
+
+from cStringIO import StringIO
+import os
+
+from twisted.trial import unittest
+
+from IPython.testing import decorators_trial as dec
+
+#-----------------------------------------------------------------------------
+# Tests
+#-----------------------------------------------------------------------------
+
+
+class TestRedirector(unittest.TestCase):
+
+ @dec.skip_win32
+ def test_redirector(self):
+ """Checks that the redirector can be used to do synchronous capture.
+ """
+ from IPython.kernel.core.fd_redirector import FDRedirector
+ r = FDRedirector()
+ out = StringIO()
+ try:
+ r.start()
+ for i in range(10):
+ os.system('echo %ic' % i)
+ print >>out, r.getvalue(),
+ print >>out, i
+ except:
+ r.stop()
+ raise
+ r.stop()
+ result1 = out.getvalue()
+ result2 = "".join("%ic\n%i\n" %(i, i) for i in range(10))
+ self.assertEquals(result1, result2)
+
+ @dec.skip_win32
+ def test_redirector_output_trap(self):
+ """Check the greedy trapping behavior of the traps.
+
+ This test check not only that the redirector_output_trap does
+ trap the output, but also that it does it in a gready way, that
+ is by calling the callback ASAP.
+ """
+ from IPython.kernel.core.redirector_output_trap import RedirectorOutputTrap
+ out = StringIO()
+ trap = RedirectorOutputTrap(out.write, out.write)
+ try:
+ trap.set()
+ for i in range(10):
+ os.system('echo %ic' % i)
+ print "%ip" % i
+ print >>out, i
+ except:
+ trap.unset()
+ raise
+ trap.unset()
+ result1 = out.getvalue()
+ result2 = "".join("%ic\n%ip\n%i\n" %(i, i, i) for i in range(10))
+ self.assertEquals(result1, result2)
+
diff --git a/IPython/kernel/core/traceback_formatter.py b/IPython/kernel/core/traceback_formatter.py
new file mode 100644
index 0000000..05628e7
--- /dev/null
+++ b/IPython/kernel/core/traceback_formatter.py
@@ -0,0 +1,62 @@
+# encoding: utf-8
+
+"""Some formatter objects to extract traceback information by replacing
+sys.excepthook()."""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+import traceback
+
+
+class ITracebackFormatter(object):
+ """ Objects conforming to this interface will format tracebacks into other
+ objects.
+ """
+
+ # The kind of formatter.
+ kind = 'traceback'
+
+ # The unique identifier for this formatter.
+ identifier = None
+
+
+ def __call__(self, exc_type, exc_value, exc_traceback):
+ """ Return a formatted representation of a traceback.
+ """
+
+ raise NotImplementedError
+
+
+class PlainTracebackFormatter(ITracebackFormatter):
+ """ Return a string with the regular traceback information.
+ """
+
+ # The unique identifier for this formatter.
+ identifier = 'plain'
+
+
+ def __init__(self, limit=None):
+ # The maximum number of stack levels to go back.
+ # None implies all stack levels are returned.
+ self.limit = limit
+
+ def __call__(self, exc_type, exc_value, exc_traceback):
+ """ Return a string with the regular traceback information.
+ """
+
+ lines = traceback.format_tb(exc_traceback, self.limit)
+ lines.append('%s: %s' % (exc_type.__name__, exc_value))
+ return '\n'.join(lines)
+
+
diff --git a/IPython/kernel/core/traceback_trap.py b/IPython/kernel/core/traceback_trap.py
new file mode 100644
index 0000000..6b1ad21
--- /dev/null
+++ b/IPython/kernel/core/traceback_trap.py
@@ -0,0 +1,85 @@
+# encoding: utf-8
+
+"""Object to manage sys.excepthook()."""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+import sys
+from traceback import format_list
+
+class TracebackTrap(object):
+ """ Object to trap and format tracebacks.
+ """
+
+ def __init__(self, formatters=None):
+ # A list of formatters to apply.
+ if formatters is None:
+ formatters = []
+ self.formatters = formatters
+
+ # All of the traceback information provided to sys.excepthook().
+ self.args = None
+
+ # The previous hook before we replace it.
+ self.old_hook = None
+
+
+ def hook(self, *args):
+ """ This method actually implements the hook.
+ """
+ self.args = args
+
+ def set(self):
+ """ Set the hook.
+ """
+
+ if sys.excepthook is not self.hook:
+ self.old_hook = sys.excepthook
+ sys.excepthook = self.hook
+
+ def unset(self):
+ """ Unset the hook.
+ """
+
+ sys.excepthook = self.old_hook
+
+ def clear(self):
+ """ Remove the stored traceback.
+ """
+
+ self.args = None
+
+ def add_to_message(self, message):
+ """ Add the formatted display of the traceback to the message dictionary
+ being returned from the interpreter to its listeners.
+
+ Parameters
+ ----------
+ message : dict
+ """
+
+ # If there was no traceback, then don't add anything.
+ if self.args is None:
+ return
+
+ # Go through the list of formatters and let them add their formatting.
+ traceback = {}
+ try:
+ for formatter in self.formatters:
+ traceback[formatter.identifier] = formatter(*self.args)
+ except:
+ # This works always, including with string exceptions.
+ traceback['fallback'] = repr(self.args)
+
+ message['traceback'] = traceback
+
diff --git a/IPython/kernel/core/util.py b/IPython/kernel/core/util.py
new file mode 100644
index 0000000..ae69642
--- /dev/null
+++ b/IPython/kernel/core/util.py
@@ -0,0 +1,195 @@
+# encoding: utf-8
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+import os
+import sys
+
+
+# This class is mostly taken from IPython.
+class InputList(list):
+ """ Class to store user input.
+
+ It's basically a list, but slices return a string instead of a list, thus
+ allowing things like (assuming 'In' is an instance):
+
+ exec In[4:7]
+
+ or
+
+ exec In[5:9] + In[14] + In[21:25]
+ """
+
+ def __getslice__(self, i, j):
+ return ''.join(list.__getslice__(self, i, j))
+
+ def add(self, index, command):
+ """ Add a command to the list with the appropriate index.
+
+ If the index is greater than the current length of the list, empty
+ strings are added in between.
+ """
+
+ length = len(self)
+ if length == index:
+ self.append(command)
+ elif length > index:
+ self[index] = command
+ else:
+ extras = index - length
+ self.extend([''] * extras)
+ self.append(command)
+
+
+class Bunch(dict):
+ """ A dictionary that exposes its keys as attributes.
+ """
+
+ def __init__(self, *args, **kwds):
+ dict.__init__(self, *args, **kwds)
+ self.__dict__ = self
+
+
+def esc_quotes(strng):
+ """ Return the input string with single and double quotes escaped out.
+ """
+
+ return strng.replace('"', '\\"').replace("'", "\\'")
+
+def make_quoted_expr(s):
+ """Return string s in appropriate quotes, using raw string if possible.
+
+ XXX - example removed because it caused encoding errors in documentation
+ generation. We need a new example that doesn't contain invalid chars.
+
+ Note the use of raw string and padding at the end to allow trailing
+ backslash.
+ """
+
+ tail = ''
+ tailpadding = ''
+ raw = ''
+ if "\\" in s:
+ raw = 'r'
+ if s.endswith('\\'):
+ tail = '[:-1]'
+ tailpadding = '_'
+ if '"' not in s:
+ quote = '"'
+ elif "'" not in s:
+ quote = "'"
+ elif '"""' not in s and not s.endswith('"'):
+ quote = '"""'
+ elif "'''" not in s and not s.endswith("'"):
+ quote = "'''"
+ else:
+ # Give up, backslash-escaped string will do
+ return '"%s"' % esc_quotes(s)
+ res = ''.join([raw, quote, s, tailpadding, quote, tail])
+ return res
+
+# This function is used by ipython in a lot of places to make system calls.
+# We need it to be slightly different under win32, due to the vagaries of
+# 'network shares'. A win32 override is below.
+
+def system_shell(cmd, verbose=False, debug=False, header=''):
+ """ Execute a command in the system shell; always return None.
+
+ This returns None so it can be conveniently used in interactive loops
+ without getting the return value (typically 0) printed many times.
+
+ Parameters
+ ----------
+ cmd : str
+ The command to execute.
+ verbose : bool
+ If True, print the command to be executed.
+ debug : bool
+ Only print, do not actually execute.
+ header : str
+ Header to print to screen prior to the executed command. No extra
+ newlines are added.
+ """
+
+ if verbose or debug:
+ print header + cmd
+
+ # Flush stdout so we don't mangle python's buffering.
+ sys.stdout.flush()
+ if not debug:
+ os.system(cmd)
+
+# Override shell() for win32 to deal with network shares.
+if os.name in ('nt', 'dos'):
+
+ system_shell_ori = system_shell
+
+ def system_shell(cmd, verbose=False, debug=False, header=''):
+ if os.getcwd().startswith(r"\\"):
+ path = os.getcwd()
+ # Change to c drive (cannot be on UNC-share when issuing os.system,
+ # as cmd.exe cannot handle UNC addresses).
+ os.chdir("c:")
+ # Issue pushd to the UNC-share and then run the command.
+ try:
+ system_shell_ori('"pushd %s&&"'%path+cmd,verbose,debug,header)
+ finally:
+ os.chdir(path)
+ else:
+ system_shell_ori(cmd,verbose,debug,header)
+
+ system_shell.__doc__ = system_shell_ori.__doc__
+
+def getoutputerror(cmd, verbose=False, debug=False, header='', split=False):
+ """ Executes a command and returns the output.
+
+ Parameters
+ ----------
+ cmd : str
+ The command to execute.
+ verbose : bool
+ If True, print the command to be executed.
+ debug : bool
+ Only print, do not actually execute.
+ header : str
+ Header to print to screen prior to the executed command. No extra
+ newlines are added.
+ split : bool
+ If True, return the output as a list split on newlines.
+
+ """
+
+ if verbose or debug:
+ print header+cmd
+
+ if not cmd:
+ # Return empty lists or strings.
+ if split:
+ return [], []
+ else:
+ return '', ''
+
+ if not debug:
+ # fixme: use subprocess.
+ pin,pout,perr = os.popen3(cmd)
+ tout = pout.read().rstrip()
+ terr = perr.read().rstrip()
+ pin.close()
+ pout.close()
+ perr.close()
+ if split:
+ return tout.split('\n'), terr.split('\n')
+ else:
+ return tout, terr
+
diff --git a/IPython/kernel/engineconnector.py b/IPython/kernel/engineconnector.py
new file mode 100644
index 0000000..389a26d
--- /dev/null
+++ b/IPython/kernel/engineconnector.py
@@ -0,0 +1,92 @@
+# encoding: utf-8
+
+"""A class that manages the engines connection to the controller."""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+import os
+import cPickle as pickle
+
+from twisted.python import log, failure
+from twisted.internet import defer
+
+from IPython.kernel.fcutil import find_furl
+from IPython.kernel.enginefc import IFCEngine
+
+#-------------------------------------------------------------------------------
+# The ClientConnector class
+#-------------------------------------------------------------------------------
+
+class EngineConnector(object):
+ """Manage an engines connection to a controller.
+
+ This class takes a foolscap `Tub` and provides a `connect_to_controller`
+ method that will use the `Tub` to connect to a controller and register
+ the engine with the controller.
+ """
+
+ def __init__(self, tub):
+ self.tub = tub
+
+ def connect_to_controller(self, engine_service, furl_or_file):
+ """
+ Make a connection to a controller specified by a furl.
+
+ This method takes an `IEngineBase` instance and a foolcap URL and uses
+ the `tub` attribute to make a connection to the controller. The
+ foolscap URL contains all the information needed to connect to the
+ controller, including the ip and port as well as any encryption and
+ authentication information needed for the connection.
+
+ After getting a reference to the controller, this method calls the
+ `register_engine` method of the controller to actually register the
+ engine.
+
+ :Parameters:
+ engine_service : IEngineBase
+ An instance of an `IEngineBase` implementer
+ furl_or_file : str
+ A furl or a filename containing a furl
+ """
+ if not self.tub.running:
+ self.tub.startService()
+ self.engine_service = engine_service
+ self.engine_reference = IFCEngine(self.engine_service)
+ try:
+ self.furl = find_furl(furl_or_file)
+ except ValueError:
+ return defer.fail(failure.Failure())
+ else:
+ d = self.tub.getReference(self.furl)
+ d.addCallbacks(self._register, self._log_failure)
+ return d
+
+ def _log_failure(self, reason):
+ log.err('EngineConnector: engine registration failed:')
+ log.err(reason)
+ return reason
+
+ def _register(self, rr):
+ self.remote_ref = rr
+ # Now register myself with the controller
+ desired_id = self.engine_service.id
+ d = self.remote_ref.callRemote('register_engine', self.engine_reference,
+ desired_id, os.getpid(), pickle.dumps(self.engine_service.properties,2))
+ return d.addCallbacks(self._reference_sent, self._log_failure)
+
+ def _reference_sent(self, registration_dict):
+ self.engine_service.id = registration_dict['id']
+ log.msg("engine registration succeeded, got id: %r" % self.engine_service.id)
+ return self.engine_service.id
+
diff --git a/IPython/kernel/enginefc.py b/IPython/kernel/enginefc.py
new file mode 100644
index 0000000..ebeff5c
--- /dev/null
+++ b/IPython/kernel/enginefc.py
@@ -0,0 +1,548 @@
+# encoding: utf-8
+# -*- test-case-name: IPython.kernel.test.test_enginepb -*-
+
+"""
+Expose the IPython EngineService using the Foolscap network protocol.
+
+Foolscap is a high-performance and secure network protocol.
+"""
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+import os, time
+import cPickle as pickle
+
+from twisted.python import components, log, failure
+from twisted.python.failure import Failure
+from twisted.internet import defer, reactor, threads
+from twisted.internet.interfaces import IProtocolFactory
+from zope.interface import Interface, implements, Attribute
+
+from twisted.internet.base import DelayedCall
+DelayedCall.debug = True
+
+from foolscap import Referenceable, DeadReferenceError
+from foolscap.referenceable import RemoteReference
+
+from IPython.kernel.pbutil import packageFailure, unpackageFailure
+from IPython.kernel.util import printer
+from IPython.kernel.twistedutil import gatherBoth
+from IPython.kernel import newserialized
+from IPython.kernel.error import ProtocolError
+from IPython.kernel import controllerservice
+from IPython.kernel.controllerservice import IControllerBase
+from IPython.kernel.engineservice import \
+ IEngineBase, \
+ IEngineQueued, \
+ EngineService, \
+ StrictDict
+from IPython.kernel.pickleutil import \
+ can, \
+ canDict, \
+ canSequence, \
+ uncan, \
+ uncanDict, \
+ uncanSequence
+
+
+#-------------------------------------------------------------------------------
+# The client (Engine) side of things
+#-------------------------------------------------------------------------------
+
+# Expose a FC interface to the EngineService
+
+class IFCEngine(Interface):
+ """An interface that exposes an EngineService over Foolscap.
+
+ The methods in this interface are similar to those from IEngine,
+ but their arguments and return values slightly different to reflect
+ that FC cannot send arbitrary objects. We handle this by pickling/
+ unpickling that the two endpoints.
+
+ If a remote or local exception is raised, the appropriate Failure
+ will be returned instead.
+ """
+ pass
+
+
+class FCEngineReferenceFromService(Referenceable, object):
+ """Adapt an `IEngineBase` to an `IFCEngine` implementer.
+
+ This exposes an `IEngineBase` to foolscap by adapting it to a
+ `foolscap.Referenceable`.
+
+ See the documentation of the `IEngineBase` methods for more details.
+ """
+
+ implements(IFCEngine)
+
+ def __init__(self, service):
+ assert IEngineBase.providedBy(service), \
+ "IEngineBase is not provided by" + repr(service)
+ self.service = service
+ self.collectors = {}
+
+ def remote_get_id(self):
+ return self.service.id
+
+ def remote_set_id(self, id):
+ self.service.id = id
+
+ def _checkProperties(self, result):
+ dosync = self.service.properties.modified
+ self.service.properties.modified = False
+ return (dosync and pickle.dumps(self.service.properties, 2)), result
+
+ def remote_execute(self, lines):
+ d = self.service.execute(lines)
+ d.addErrback(packageFailure)
+ d.addCallback(self._checkProperties)
+ d.addErrback(packageFailure)
+ #d.addCallback(lambda r: log.msg("Got result: " + str(r)))
+ return d
+
+ #---------------------------------------------------------------------------
+ # Old version of push
+ #---------------------------------------------------------------------------
+
+ def remote_push(self, pNamespace):
+ try:
+ namespace = pickle.loads(pNamespace)
+ except:
+ return defer.fail(failure.Failure()).addErrback(packageFailure)
+ else:
+ return self.service.push(namespace).addErrback(packageFailure)
+
+ #---------------------------------------------------------------------------
+ # pull
+ #---------------------------------------------------------------------------
+
+ def remote_pull(self, keys):
+ d = self.service.pull(keys)
+ d.addCallback(pickle.dumps, 2)
+ d.addErrback(packageFailure)
+ return d
+
+ #---------------------------------------------------------------------------
+ # push/pullFuction
+ #---------------------------------------------------------------------------
+
+ def remote_push_function(self, pNamespace):
+ try:
+ namespace = pickle.loads(pNamespace)
+ except:
+ return defer.fail(failure.Failure()).addErrback(packageFailure)
+ else:
+ # The usage of globals() here is an attempt to bind any pickled functions
+ # to the globals of this module. What we really want is to have it bound
+ # to the globals of the callers module. This will require walking the
+ # stack. BG 10/3/07.
+ namespace = uncanDict(namespace, globals())
+ return self.service.push_function(namespace).addErrback(packageFailure)
+
+ def remote_pull_function(self, keys):
+ d = self.service.pull_function(keys)
+ if len(keys)>1:
+ d.addCallback(canSequence)
+ elif len(keys)==1:
+ d.addCallback(can)
+ d.addCallback(pickle.dumps, 2)
+ d.addErrback(packageFailure)
+ return d
+
+ #---------------------------------------------------------------------------
+ # Other methods
+ #---------------------------------------------------------------------------
+
+ def remote_get_result(self, i=None):
+ return self.service.get_result(i).addErrback(packageFailure)
+
+ def remote_reset(self):
+ return self.service.reset().addErrback(packageFailure)
+
+ def remote_kill(self):
+ return self.service.kill().addErrback(packageFailure)
+
+ def remote_keys(self):
+ return self.service.keys().addErrback(packageFailure)
+
+ #---------------------------------------------------------------------------
+ # push/pull_serialized
+ #---------------------------------------------------------------------------
+
+ def remote_push_serialized(self, pNamespace):
+ try:
+ namespace = pickle.loads(pNamespace)
+ except:
+ return defer.fail(failure.Failure()).addErrback(packageFailure)
+ else:
+ d = self.service.push_serialized(namespace)
+ return d.addErrback(packageFailure)
+
+ def remote_pull_serialized(self, keys):
+ d = self.service.pull_serialized(keys)
+ d.addCallback(pickle.dumps, 2)
+ d.addErrback(packageFailure)
+ return d
+
+ #---------------------------------------------------------------------------
+ # Properties interface
+ #---------------------------------------------------------------------------
+
+ def remote_set_properties(self, pNamespace):
+ try:
+ namespace = pickle.loads(pNamespace)
+ except:
+ return defer.fail(failure.Failure()).addErrback(packageFailure)
+ else:
+ return self.service.set_properties(namespace).addErrback(packageFailure)
+
+ def remote_get_properties(self, keys=None):
+ d = self.service.get_properties(keys)
+ d.addCallback(pickle.dumps, 2)
+ d.addErrback(packageFailure)
+ return d
+
+ def remote_has_properties(self, keys):
+ d = self.service.has_properties(keys)
+ d.addCallback(pickle.dumps, 2)
+ d.addErrback(packageFailure)
+ return d
+
+ def remote_del_properties(self, keys):
+ d = self.service.del_properties(keys)
+ d.addErrback(packageFailure)
+ return d
+
+ def remote_clear_properties(self):
+ d = self.service.clear_properties()
+ d.addErrback(packageFailure)
+ return d
+
+
+components.registerAdapter(FCEngineReferenceFromService,
+ IEngineBase,
+ IFCEngine)
+
+
+#-------------------------------------------------------------------------------
+# Now the server (Controller) side of things
+#-------------------------------------------------------------------------------
+
+class EngineFromReference(object):
+ """Adapt a `RemoteReference` to an `IEngineBase` implementing object.
+
+ When an engine connects to a controller, it calls the `register_engine`
+ method of the controller and passes the controller a `RemoteReference` to
+ itself. This class is used to adapt this `RemoteReference` to an object
+ that implements the full `IEngineBase` interface.
+
+ See the documentation of `IEngineBase` for details on the methods.
+ """
+
+ implements(IEngineBase)
+
+ def __init__(self, reference):
+ self.reference = reference
+ self._id = None
+ self._properties = StrictDict()
+ self.currentCommand = None
+
+ def callRemote(self, *args, **kwargs):
+ try:
+ return self.reference.callRemote(*args, **kwargs)
+ except DeadReferenceError:
+ self.notifier()
+ self.stopNotifying(self.notifier)
+ return defer.fail()
+
+ def get_id(self):
+ """Return the Engines id."""
+ return self._id
+
+ def set_id(self, id):
+ """Set the Engines id."""
+ self._id = id
+ return self.callRemote('set_id', id)
+
+ id = property(get_id, set_id)
+
+ def syncProperties(self, r):
+ try:
+ psync, result = r
+ except (ValueError, TypeError):
+ return r
+ else:
+ if psync:
+ log.msg("sync properties")
+ pick = self.checkReturnForFailure(psync)
+ if isinstance(pick, failure.Failure):
+ self.properties = pick
+ return pick
+ else:
+ self.properties = pickle.loads(pick)
+ return result
+
+ def _set_properties(self, dikt):
+ self._properties.clear()
+ self._properties.update(dikt)
+
+ def _get_properties(self):
+ if isinstance(self._properties, failure.Failure):
+ self._properties.raiseException()
+ return self._properties
+
+ properties = property(_get_properties, _set_properties)
+
+ #---------------------------------------------------------------------------
+ # Methods from IEngine
+ #---------------------------------------------------------------------------
+
+ #---------------------------------------------------------------------------
+ # execute
+ #---------------------------------------------------------------------------
+
+ def execute(self, lines):
+ # self._needProperties = True
+ d = self.callRemote('execute', lines)
+ d.addCallback(self.syncProperties)
+ return d.addCallback(self.checkReturnForFailure)
+
+ #---------------------------------------------------------------------------
+ # push
+ #---------------------------------------------------------------------------
+
+ def push(self, namespace):
+ try:
+ package = pickle.dumps(namespace, 2)
+ except:
+ return defer.fail(failure.Failure())
+ else:
+ if isinstance(package, failure.Failure):
+ return defer.fail(package)
+ else:
+ d = self.callRemote('push', package)
+ return d.addCallback(self.checkReturnForFailure)
+
+ #---------------------------------------------------------------------------
+ # pull
+ #---------------------------------------------------------------------------
+
+ def pull(self, keys):
+ d = self.callRemote('pull', keys)
+ d.addCallback(self.checkReturnForFailure)
+ d.addCallback(pickle.loads)
+ return d
+
+ #---------------------------------------------------------------------------
+ # push/pull_function
+ #---------------------------------------------------------------------------
+
+ def push_function(self, namespace):
+ try:
+ package = pickle.dumps(canDict(namespace), 2)
+ except:
+ return defer.fail(failure.Failure())
+ else:
+ if isinstance(package, failure.Failure):
+ return defer.fail(package)
+ else:
+ d = self.callRemote('push_function', package)
+ return d.addCallback(self.checkReturnForFailure)
+
+ def pull_function(self, keys):
+ d = self.callRemote('pull_function', keys)
+ d.addCallback(self.checkReturnForFailure)
+ d.addCallback(pickle.loads)
+ # The usage of globals() here is an attempt to bind any pickled functions
+ # to the globals of this module. What we really want is to have it bound
+ # to the globals of the callers module. This will require walking the
+ # stack. BG 10/3/07.
+ if len(keys)==1:
+ d.addCallback(uncan, globals())
+ elif len(keys)>1:
+ d.addCallback(uncanSequence, globals())
+ return d
+
+ #---------------------------------------------------------------------------
+ # Other methods
+ #---------------------------------------------------------------------------
+
+ def get_result(self, i=None):
+ return self.callRemote('get_result', i).addCallback(self.checkReturnForFailure)
+
+ def reset(self):
+ self._refreshProperties = True
+ d = self.callRemote('reset')
+ d.addCallback(self.syncProperties)
+ return d.addCallback(self.checkReturnForFailure)
+
+ def kill(self):
+ #this will raise pb.PBConnectionLost on success
+ d = self.callRemote('kill')
+ d.addCallback(self.syncProperties)
+ d.addCallback(self.checkReturnForFailure)
+ d.addErrback(self.killBack)
+ return d
+
+ def killBack(self, f):
+ log.msg('filling engine: %s' % f)
+ return None
+
+ def keys(self):
+ return self.callRemote('keys').addCallback(self.checkReturnForFailure)
+
+ #---------------------------------------------------------------------------
+ # Properties methods
+ #---------------------------------------------------------------------------
+
+ def set_properties(self, properties):
+ try:
+ package = pickle.dumps(properties, 2)
+ except:
+ return defer.fail(failure.Failure())
+ else:
+ if isinstance(package, failure.Failure):
+ return defer.fail(package)
+ else:
+ d = self.callRemote('set_properties', package)
+ return d.addCallback(self.checkReturnForFailure)
+ return d
+
+ def get_properties(self, keys=None):
+ d = self.callRemote('get_properties', keys)
+ d.addCallback(self.checkReturnForFailure)
+ d.addCallback(pickle.loads)
+ return d
+
+ def has_properties(self, keys):
+ d = self.callRemote('has_properties', keys)
+ d.addCallback(self.checkReturnForFailure)
+ d.addCallback(pickle.loads)
+ return d
+
+ def del_properties(self, keys):
+ d = self.callRemote('del_properties', keys)
+ d.addCallback(self.checkReturnForFailure)
+ # d.addCallback(pickle.loads)
+ return d
+
+ def clear_properties(self):
+ d = self.callRemote('clear_properties')
+ d.addCallback(self.checkReturnForFailure)
+ return d
+
+ #---------------------------------------------------------------------------
+ # push/pull_serialized
+ #---------------------------------------------------------------------------
+
+ def push_serialized(self, namespace):
+ """Older version of pushSerialize."""
+ try:
+ package = pickle.dumps(namespace, 2)
+ except:
+ return defer.fail(failure.Failure())
+ else:
+ if isinstance(package, failure.Failure):
+ return defer.fail(package)
+ else:
+ d = self.callRemote('push_serialized', package)
+ return d.addCallback(self.checkReturnForFailure)
+
+ def pull_serialized(self, keys):
+ d = self.callRemote('pull_serialized', keys)
+ d.addCallback(self.checkReturnForFailure)
+ d.addCallback(pickle.loads)
+ return d
+
+ #---------------------------------------------------------------------------
+ # Misc
+ #---------------------------------------------------------------------------
+
+ def checkReturnForFailure(self, r):
+ """See if a returned value is a pickled Failure object.
+
+ To distinguish between general pickled objects and pickled Failures, the
+ other side should prepend the string FAILURE: to any pickled Failure.
+ """
+ return unpackageFailure(r)
+
+
+components.registerAdapter(EngineFromReference,
+ RemoteReference,
+ IEngineBase)
+
+
+#-------------------------------------------------------------------------------
+# Now adapt an IControllerBase to incoming FC connections
+#-------------------------------------------------------------------------------
+
+
+class IFCControllerBase(Interface):
+ """
+ Interface that tells how an Engine sees a Controller.
+
+ In our architecture, the Controller listens for Engines to connect
+ and register. This interface defines that registration method as it is
+ exposed over the Foolscap network protocol
+ """
+
+ def remote_register_engine(self, engineReference, id=None, pid=None, pproperties=None):
+ """
+ Register new engine on the controller.
+
+ Engines must call this upon connecting to the controller if they
+ want to do work for the controller.
+
+ See the documentation of `IControllerCore` for more details.
+ """
+
+
+class FCRemoteEngineRefFromService(Referenceable):
+ """
+ Adapt an `IControllerBase` to an `IFCControllerBase`.
+ """
+
+ implements(IFCControllerBase)
+
+ def __init__(self, service):
+ assert IControllerBase.providedBy(service), \
+ "IControllerBase is not provided by " + repr(service)
+ self.service = service
+
+ def remote_register_engine(self, engine_reference, id=None, pid=None, pproperties=None):
+ # First adapt the engine_reference to a basic non-queued engine
+ engine = IEngineBase(engine_reference)
+ if pproperties:
+ engine.properties = pickle.loads(pproperties)
+ # Make it an IQueuedEngine before registration
+ remote_engine = IEngineQueued(engine)
+ # Get the ip/port of the remote side
+ peer_address = engine_reference.tracker.broker.transport.getPeer()
+ ip = peer_address.host
+ port = peer_address.port
+ reg_dict = self.service.register_engine(remote_engine, id, ip, port, pid)
+ # Now setup callback for disconnect and unregistering the engine
+ def notify(*args):
+ return self.service.unregister_engine(reg_dict['id'])
+ engine_reference.tracker.broker.notifyOnDisconnect(notify)
+
+ engine.notifier = notify
+ engine.stopNotifying = engine_reference.tracker.broker.dontNotifyOnDisconnect
+
+ return reg_dict
+
+
+components.registerAdapter(FCRemoteEngineRefFromService,
+ IControllerBase,
+ IFCControllerBase)
diff --git a/IPython/kernel/engineservice.py b/IPython/kernel/engineservice.py
new file mode 100644
index 0000000..0f313dc
--- /dev/null
+++ b/IPython/kernel/engineservice.py
@@ -0,0 +1,902 @@
+# encoding: utf-8
+# -*- test-case-name: IPython.kernel.tests.test_engineservice -*-
+
+"""A Twisted Service Representation of the IPython core.
+
+The IPython Core exposed to the network is called the Engine. Its
+representation in Twisted in the EngineService. Interfaces and adapters
+are used to abstract out the details of the actual network protocol used.
+The EngineService is an Engine that knows nothing about the actual protocol
+used.
+
+The EngineService is exposed with various network protocols in modules like:
+
+enginepb.py
+enginevanilla.py
+
+As of 12/12/06 the classes in this module have been simplified greatly. It was
+felt that we had over-engineered things. To improve the maintainability of the
+code we have taken out the ICompleteEngine interface and the completeEngine
+method that automatically added methods to engines.
+
+"""
+
+__docformat__ = "restructuredtext en"
+
+# Tell nose to skip this module
+__test__ = {}
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+import copy
+import sys
+import cPickle as pickle
+
+from twisted.application import service
+from twisted.internet import defer, reactor
+from twisted.python import log, failure, components
+import zope.interface as zi
+
+from IPython.kernel.core.interpreter import Interpreter
+from IPython.kernel import newserialized, error
+
+#-------------------------------------------------------------------------------
+# Interface specification for the Engine
+#-------------------------------------------------------------------------------
+
+class IEngineCore(zi.Interface):
+ """The minimal required interface for the IPython Engine.
+
+ This interface provides a formal specification of the IPython core.
+ All these methods should return deferreds regardless of what side of a
+ network connection they are on.
+
+ In general, this class simply wraps a shell class and wraps its return
+ values as Deferred objects. If the underlying shell class method raises
+ an exception, this class should convert it to a twisted.failure.Failure
+ that will be propagated along the Deferred's errback chain.
+
+ In addition, Failures are aggressive. By this, we mean that if a method
+ is performing multiple actions (like pulling multiple object) if any
+ single one fails, the entire method will fail with that Failure. It is
+ all or nothing.
+ """
+
+ id = zi.interface.Attribute("the id of the Engine object")
+ properties = zi.interface.Attribute("A dict of properties of the Engine")
+
+ def execute(lines):
+ """Execute lines of Python code.
+
+ Returns a dictionary with keys (id, number, stdin, stdout, stderr)
+ upon success.
+
+ Returns a failure object if the execution of lines raises an exception.
+ """
+
+ def push(namespace):
+ """Push dict namespace into the user's namespace.
+
+ Returns a deferred to None or a failure.
+ """
+
+ def pull(keys):
+ """Pulls values out of the user's namespace by keys.
+
+ Returns a deferred to a tuple objects or a single object.
+
+ Raises NameError if any one of objects doess not exist.
+ """
+
+ def push_function(namespace):
+ """Push a dict of key, function pairs into the user's namespace.
+
+ Returns a deferred to None or a failure."""
+
+ def pull_function(keys):
+ """Pulls functions out of the user's namespace by keys.
+
+ Returns a deferred to a tuple of functions or a single function.
+
+ Raises NameError if any one of the functions does not exist.
+ """
+
+ def get_result(i=None):
+ """Get the stdin/stdout/stderr of command i.
+
+ Returns a deferred to a dict with keys
+ (id, number, stdin, stdout, stderr).
+
+ Raises IndexError if command i does not exist.
+ Raises TypeError if i in not an int.
+ """
+
+ def reset():
+ """Reset the shell.
+
+ This clears the users namespace. Won't cause modules to be
+ reloaded. Should also re-initialize certain variables like id.
+ """
+
+ def kill():
+ """Kill the engine by stopping the reactor."""
+
+ def keys():
+ """Return the top level variables in the users namspace.
+
+ Returns a deferred to a dict."""
+
+
+class IEngineSerialized(zi.Interface):
+ """Push/Pull methods that take Serialized objects.
+
+ All methods should return deferreds.
+ """
+
+ def push_serialized(namespace):
+ """Push a dict of keys and Serialized objects into the user's namespace."""
+
+ def pull_serialized(keys):
+ """Pull objects by key from the user's namespace as Serialized.
+
+ Returns a list of or one Serialized.
+
+ Raises NameError is any one of the objects does not exist.
+ """
+
+
+class IEngineProperties(zi.Interface):
+ """Methods for access to the properties object of an Engine"""
+
+ properties = zi.Attribute("A StrictDict object, containing the properties")
+
+ def set_properties(properties):
+ """set properties by key and value"""
+
+ def get_properties(keys=None):
+ """get a list of properties by `keys`, if no keys specified, get all"""
+
+ def del_properties(keys):
+ """delete properties by `keys`"""
+
+ def has_properties(keys):
+ """get a list of bool values for whether `properties` has `keys`"""
+
+ def clear_properties():
+ """clear the properties dict"""
+
+class IEngineBase(IEngineCore, IEngineSerialized, IEngineProperties):
+ """The basic engine interface that EngineService will implement.
+
+ This exists so it is easy to specify adapters that adapt to and from the
+ API that the basic EngineService implements.
+ """
+ pass
+
+class IEngineQueued(IEngineBase):
+ """Interface for adding a queue to an IEngineBase.
+
+ This interface extends the IEngineBase interface to add methods for managing
+ the engine's queue. The implicit details of this interface are that the
+ execution of all methods declared in IEngineBase should appropriately be
+ put through a queue before execution.
+
+ All methods should return deferreds.
+ """
+
+ def clear_queue():
+ """Clear the queue."""
+
+ def queue_status():
+ """Get the queued and pending commands in the queue."""
+
+ def register_failure_observer(obs):
+ """Register an observer of pending Failures.
+
+ The observer must implement IFailureObserver.
+ """
+
+ def unregister_failure_observer(obs):
+ """Unregister an observer of pending Failures."""
+
+
+class IEngineThreaded(zi.Interface):
+ """A place holder for threaded commands.
+
+ All methods should return deferreds.
+ """
+ pass
+
+
+#-------------------------------------------------------------------------------
+# Functions and classes to implement the EngineService
+#-------------------------------------------------------------------------------
+
+
+class StrictDict(dict):
+ """This is a strict copying dictionary for use as the interface to the
+ properties of an Engine.
+
+ :IMPORTANT:
+ This object copies the values you set to it, and returns copies to you
+ when you request them. The only way to change properties os explicitly
+ through the setitem and getitem of the dictionary interface.
+
+ Example:
+ >>> e = get_engine(id)
+ >>> L = [1,2,3]
+ >>> e.properties['L'] = L
+ >>> L == e.properties['L']
+ True
+ >>> L.append(99)
+ >>> L == e.properties['L']
+ False
+
+ Note that getitem copies, so calls to methods of objects do not affect
+ the properties, as seen here:
+
+ >>> e.properties[1] = range(2)
+ >>> print e.properties[1]
+ [0, 1]
+ >>> e.properties[1].append(2)
+ >>> print e.properties[1]
+ [0, 1]
+ """
+ def __init__(self, *args, **kwargs):
+ dict.__init__(self, *args, **kwargs)
+ self.modified = True
+
+ def __getitem__(self, key):
+ return copy.deepcopy(dict.__getitem__(self, key))
+
+ def __setitem__(self, key, value):
+ # check if this entry is valid for transport around the network
+ # and copying
+ try:
+ pickle.dumps(key, 2)
+ pickle.dumps(value, 2)
+ newvalue = copy.deepcopy(value)
+ except Exception, e:
+ raise error.InvalidProperty("can't be a value: %r" % value)
+ dict.__setitem__(self, key, newvalue)
+ self.modified = True
+
+ def __delitem__(self, key):
+ dict.__delitem__(self, key)
+ self.modified = True
+
+ def update(self, dikt):
+ for k,v in dikt.iteritems():
+ self[k] = v
+
+ def pop(self, key):
+ self.modified = True
+ return dict.pop(self, key)
+
+ def popitem(self):
+ self.modified = True
+ return dict.popitem(self)
+
+ def clear(self):
+ self.modified = True
+ dict.clear(self)
+
+ def subDict(self, *keys):
+ d = {}
+ for key in keys:
+ d[key] = self[key]
+ return d
+
+
+
+class EngineAPI(object):
+ """This is the object through which the user can edit the `properties`
+ attribute of an Engine.
+ The Engine Properties object copies all object in and out of itself.
+ See the EngineProperties object for details.
+ """
+ _fix=False
+ def __init__(self, id):
+ self.id = id
+ self.properties = StrictDict()
+ self._fix=True
+
+ def __setattr__(self, k,v):
+ if self._fix:
+ raise error.KernelError("I am protected!")
+ else:
+ object.__setattr__(self, k, v)
+
+ def __delattr__(self, key):
+ raise error.KernelError("I am protected!")
+
+
+_apiDict = {}
+
+def get_engine(id):
+ """Get the Engine API object, whcih currently just provides the properties
+ object, by ID"""
+ global _apiDict
+ if not _apiDict.get(id):
+ _apiDict[id] = EngineAPI(id)
+ return _apiDict[id]
+
+def drop_engine(id):
+ """remove an engine"""
+ global _apiDict
+ if _apiDict.has_key(id):
+ del _apiDict[id]
+
+class EngineService(object, service.Service):
+ """Adapt a IPython shell into a IEngine implementing Twisted Service."""
+
+ zi.implements(IEngineBase)
+ name = 'EngineService'
+
+ def __init__(self, shellClass=Interpreter, mpi=None):
+ """Create an EngineService.
+
+ shellClass: something that implements IInterpreter or core1
+ mpi: an mpi module that has rank and size attributes
+ """
+ self.shellClass = shellClass
+ self.shell = self.shellClass()
+ self.mpi = mpi
+ self.id = None
+ self.properties = get_engine(self.id).properties
+ if self.mpi is not None:
+ log.msg("MPI started with rank = %i and size = %i" %
+ (self.mpi.rank, self.mpi.size))
+ self.id = self.mpi.rank
+ self._seedNamespace()
+
+ # Make id a property so that the shell can get the updated id
+
+ def _setID(self, id):
+ self._id = id
+ self.properties = get_engine(id).properties
+ self.shell.push({'id': id})
+
+ def _getID(self):
+ return self._id
+
+ id = property(_getID, _setID)
+
+ def _seedNamespace(self):
+ self.shell.push({'mpi': self.mpi, 'id' : self.id})
+
+ def executeAndRaise(self, msg, callable, *args, **kwargs):
+ """Call a method of self.shell and wrap any exception."""
+ d = defer.Deferred()
+ try:
+ result = callable(*args, **kwargs)
+ except:
+ # This gives the following:
+ # et=exception class
+ # ev=exception class instance
+ # tb=traceback object
+ et,ev,tb = sys.exc_info()
+ # This call adds attributes to the exception value
+ et,ev,tb = self.shell.formatTraceback(et,ev,tb,msg)
+ # Add another attribute
+ ev._ipython_engine_info = msg
+ f = failure.Failure(ev,et,None)
+ d.errback(f)
+ else:
+ d.callback(result)
+
+ return d
+
+
+ # The IEngine methods. See the interface for documentation.
+
+ def execute(self, lines):
+ msg = {'engineid':self.id,
+ 'method':'execute',
+ 'args':[lines]}
+ d = self.executeAndRaise(msg, self.shell.execute, lines)
+ d.addCallback(self.addIDToResult)
+ return d
+
+ def addIDToResult(self, result):
+ result['id'] = self.id
+ return result
+
+ def push(self, namespace):
+ msg = {'engineid':self.id,
+ 'method':'push',
+ 'args':[repr(namespace.keys())]}
+ d = self.executeAndRaise(msg, self.shell.push, namespace)
+ return d
+
+ def pull(self, keys):
+ msg = {'engineid':self.id,
+ 'method':'pull',
+ 'args':[repr(keys)]}
+ d = self.executeAndRaise(msg, self.shell.pull, keys)
+ return d
+
+ def push_function(self, namespace):
+ msg = {'engineid':self.id,
+ 'method':'push_function',
+ 'args':[repr(namespace.keys())]}
+ d = self.executeAndRaise(msg, self.shell.push_function, namespace)
+ return d
+
+ def pull_function(self, keys):
+ msg = {'engineid':self.id,
+ 'method':'pull_function',
+ 'args':[repr(keys)]}
+ d = self.executeAndRaise(msg, self.shell.pull_function, keys)
+ return d
+
+ def get_result(self, i=None):
+ msg = {'engineid':self.id,
+ 'method':'get_result',
+ 'args':[repr(i)]}
+ d = self.executeAndRaise(msg, self.shell.getCommand, i)
+ d.addCallback(self.addIDToResult)
+ return d
+
+ def reset(self):
+ msg = {'engineid':self.id,
+ 'method':'reset',
+ 'args':[]}
+ del self.shell
+ self.shell = self.shellClass()
+ self.properties.clear()
+ d = self.executeAndRaise(msg, self._seedNamespace)
+ return d
+
+ def kill(self):
+ drop_engine(self.id)
+ try:
+ reactor.stop()
+ except RuntimeError:
+ log.msg('The reactor was not running apparently.')
+ return defer.fail()
+ else:
+ return defer.succeed(None)
+
+ def keys(self):
+ """Return a list of variables names in the users top level namespace.
+
+ This used to return a dict of all the keys/repr(values) in the
+ user's namespace. This was too much info for the ControllerService
+ to handle so it is now just a list of keys.
+ """
+
+ remotes = []
+ for k in self.shell.user_ns.iterkeys():
+ if k not in ['__name__', '_ih', '_oh', '__builtins__',
+ 'In', 'Out', '_', '__', '___', '__IP', 'input', 'raw_input']:
+ remotes.append(k)
+ return defer.succeed(remotes)
+
+ def set_properties(self, properties):
+ msg = {'engineid':self.id,
+ 'method':'set_properties',
+ 'args':[repr(properties.keys())]}
+ return self.executeAndRaise(msg, self.properties.update, properties)
+
+ def get_properties(self, keys=None):
+ msg = {'engineid':self.id,
+ 'method':'get_properties',
+ 'args':[repr(keys)]}
+ if keys is None:
+ keys = self.properties.keys()
+ return self.executeAndRaise(msg, self.properties.subDict, *keys)
+
+ def _doDel(self, keys):
+ for key in keys:
+ del self.properties[key]
+
+ def del_properties(self, keys):
+ msg = {'engineid':self.id,
+ 'method':'del_properties',
+ 'args':[repr(keys)]}
+ return self.executeAndRaise(msg, self._doDel, keys)
+
+ def _doHas(self, keys):
+ return [self.properties.has_key(key) for key in keys]
+
+ def has_properties(self, keys):
+ msg = {'engineid':self.id,
+ 'method':'has_properties',
+ 'args':[repr(keys)]}
+ return self.executeAndRaise(msg, self._doHas, keys)
+
+ def clear_properties(self):
+ msg = {'engineid':self.id,
+ 'method':'clear_properties',
+ 'args':[]}
+ return self.executeAndRaise(msg, self.properties.clear)
+
+ def push_serialized(self, sNamespace):
+ msg = {'engineid':self.id,
+ 'method':'push_serialized',
+ 'args':[repr(sNamespace.keys())]}
+ ns = {}
+ for k,v in sNamespace.iteritems():
+ try:
+ unserialized = newserialized.IUnSerialized(v)
+ ns[k] = unserialized.getObject()
+ except:
+ return defer.fail()
+ return self.executeAndRaise(msg, self.shell.push, ns)
+
+ def pull_serialized(self, keys):
+ msg = {'engineid':self.id,
+ 'method':'pull_serialized',
+ 'args':[repr(keys)]}
+ if isinstance(keys, str):
+ keys = [keys]
+ if len(keys)==1:
+ d = self.executeAndRaise(msg, self.shell.pull, keys)
+ d.addCallback(newserialized.serialize)
+ return d
+ elif len(keys)>1:
+ d = self.executeAndRaise(msg, self.shell.pull, keys)
+ @d.addCallback
+ def packThemUp(values):
+ serials = []
+ for v in values:
+ try:
+ serials.append(newserialized.serialize(v))
+ except:
+ return defer.fail(failure.Failure())
+ return serials
+ return packThemUp
+
+
+def queue(methodToQueue):
+ def queuedMethod(this, *args, **kwargs):
+ name = methodToQueue.__name__
+ return this.submitCommand(Command(name, *args, **kwargs))
+ return queuedMethod
+
+class QueuedEngine(object):
+ """Adapt an IEngineBase to an IEngineQueued by wrapping it.
+
+ The resulting object will implement IEngineQueued which extends
+ IEngineCore which extends (IEngineBase, IEngineSerialized).
+
+ This seems like the best way of handling it, but I am not sure. The
+ other option is to have the various base interfaces be used like
+ mix-in intefaces. The problem I have with this is adpatation is
+ more difficult and complicated because there can be can multiple
+ original and final Interfaces.
+ """
+
+ zi.implements(IEngineQueued)
+
+ def __init__(self, engine):
+ """Create a QueuedEngine object from an engine
+
+ engine: An implementor of IEngineCore and IEngineSerialized
+ keepUpToDate: whether to update the remote status when the
+ queue is empty. Defaults to False.
+ """
+
+ # This is the right way to do these tests rather than
+ # IEngineCore in list(zi.providedBy(engine)) which will only
+ # picks of the interfaces that are directly declared by engine.
+ assert IEngineBase.providedBy(engine), \
+ "engine passed to QueuedEngine doesn't provide IEngineBase"
+
+ self.engine = engine
+ self.id = engine.id
+ self.queued = []
+ self.history = {}
+ self.engineStatus = {}
+ self.currentCommand = None
+ self.failureObservers = []
+
+ def _get_properties(self):
+ return self.engine.properties
+
+ properties = property(_get_properties, lambda self, _: None)
+ # Queue management methods. You should not call these directly
+
+ def submitCommand(self, cmd):
+ """Submit command to queue."""
+
+ d = defer.Deferred()
+ cmd.setDeferred(d)
+ if self.currentCommand is not None:
+ if self.currentCommand.finished:
+ # log.msg("Running command immediately: %r" % cmd)
+ self.currentCommand = cmd
+ self.runCurrentCommand()
+ else: # command is still running
+ # log.msg("Command is running: %r" % self.currentCommand)
+ # log.msg("Queueing: %r" % cmd)
+ self.queued.append(cmd)
+ else:
+ # log.msg("No current commands, running: %r" % cmd)
+ self.currentCommand = cmd
+ self.runCurrentCommand()
+ return d
+
+ def runCurrentCommand(self):
+ """Run current command."""
+
+ cmd = self.currentCommand
+ f = getattr(self.engine, cmd.remoteMethod, None)
+ if f:
+ d = f(*cmd.args, **cmd.kwargs)
+ if cmd.remoteMethod is 'execute':
+ d.addCallback(self.saveResult)
+ d.addCallback(self.finishCommand)
+ d.addErrback(self.abortCommand)
+ else:
+ return defer.fail(AttributeError(cmd.remoteMethod))
+
+ def _flushQueue(self):
+ """Pop next command in queue and run it."""
+
+ if len(self.queued) > 0:
+ self.currentCommand = self.queued.pop(0)
+ self.runCurrentCommand()
+
+ def saveResult(self, result):
+ """Put the result in the history."""
+ self.history[result['number']] = result
+ return result
+
+ def finishCommand(self, result):
+ """Finish currrent command."""
+
+ # The order of these commands is absolutely critical.
+ self.currentCommand.handleResult(result)
+ self.currentCommand.finished = True
+ self._flushQueue()
+ return result
+
+ def abortCommand(self, reason):
+ """Abort current command.
+
+ This eats the Failure but first passes it onto the Deferred that the
+ user has.
+
+ It also clear out the queue so subsequence commands don't run.
+ """
+
+ # The order of these 3 commands is absolutely critical. The currentCommand
+ # must first be marked as finished BEFORE the queue is cleared and before
+ # the current command is sent the failure.
+ # Also, the queue must be cleared BEFORE the current command is sent the Failure
+ # otherwise the errback chain could trigger new commands to be added to the
+ # queue before we clear it. We should clear ONLY the commands that were in
+ # the queue when the error occured.
+ self.currentCommand.finished = True
+ s = "%r %r %r" % (self.currentCommand.remoteMethod, self.currentCommand.args, self.currentCommand.kwargs)
+ self.clear_queue(msg=s)
+ self.currentCommand.handleError(reason)
+
+ return None
+
+ #---------------------------------------------------------------------------
+ # IEngineCore methods
+ #---------------------------------------------------------------------------
+
+ @queue
+ def execute(self, lines):
+ pass
+
+ @queue
+ def push(self, namespace):
+ pass
+
+ @queue
+ def pull(self, keys):
+ pass
+
+ @queue
+ def push_function(self, namespace):
+ pass
+
+ @queue
+ def pull_function(self, keys):
+ pass
+
+ def get_result(self, i=None):
+ if i is None:
+ i = max(self.history.keys()+[None])
+
+ cmd = self.history.get(i, None)
+ # Uncomment this line to disable chaching of results
+ #cmd = None
+ if cmd is None:
+ return self.submitCommand(Command('get_result', i))
+ else:
+ return defer.succeed(cmd)
+
+ def reset(self):
+ self.clear_queue()
+ self.history = {} # reset the cache - I am not sure we should do this
+ return self.submitCommand(Command('reset'))
+
+ def kill(self):
+ self.clear_queue()
+ return self.submitCommand(Command('kill'))
+
+ @queue
+ def keys(self):
+ pass
+
+ #---------------------------------------------------------------------------
+ # IEngineSerialized methods
+ #---------------------------------------------------------------------------
+
+ @queue
+ def push_serialized(self, namespace):
+ pass
+
+ @queue
+ def pull_serialized(self, keys):
+ pass
+
+ #---------------------------------------------------------------------------
+ # IEngineProperties methods
+ #---------------------------------------------------------------------------
+
+ @queue
+ def set_properties(self, namespace):
+ pass
+
+ @queue
+ def get_properties(self, keys=None):
+ pass
+
+ @queue
+ def del_properties(self, keys):
+ pass
+
+ @queue
+ def has_properties(self, keys):
+ pass
+
+ @queue
+ def clear_properties(self):
+ pass
+
+ #---------------------------------------------------------------------------
+ # IQueuedEngine methods
+ #---------------------------------------------------------------------------
+
+ def clear_queue(self, msg=''):
+ """Clear the queue, but doesn't cancel the currently running commmand."""
+
+ for cmd in self.queued:
+ cmd.deferred.errback(failure.Failure(error.QueueCleared(msg)))
+ self.queued = []
+ return defer.succeed(None)
+
+ def queue_status(self):
+ if self.currentCommand is not None:
+ if self.currentCommand.finished:
+ pending = repr(None)
+ else:
+ pending = repr(self.currentCommand)
+ else:
+ pending = repr(None)
+ dikt = {'queue':map(repr,self.queued), 'pending':pending}
+ return defer.succeed(dikt)
+
+ def register_failure_observer(self, obs):
+ self.failureObservers.append(obs)
+
+ def unregister_failure_observer(self, obs):
+ self.failureObservers.remove(obs)
+
+
+# Now register QueuedEngine as an adpater class that makes an IEngineBase into a
+# IEngineQueued.
+components.registerAdapter(QueuedEngine, IEngineBase, IEngineQueued)
+
+
+class Command(object):
+ """A command object that encapslates queued commands.
+
+ This class basically keeps track of a command that has been queued
+ in a QueuedEngine. It manages the deferreds and hold the method to be called
+ and the arguments to that method.
+ """
+
+
+ def __init__(self, remoteMethod, *args, **kwargs):
+ """Build a new Command object."""
+
+ self.remoteMethod = remoteMethod
+ self.args = args
+ self.kwargs = kwargs
+ self.finished = False
+
+ def setDeferred(self, d):
+ """Sets the deferred attribute of the Command."""
+
+ self.deferred = d
+
+ def __repr__(self):
+ if not self.args:
+ args = ''
+ else:
+ args = str(self.args)[1:-2] #cut off (...,)
+ for k,v in self.kwargs.iteritems():
+ if args:
+ args += ', '
+ args += '%s=%r' %(k,v)
+ return "%s(%s)" %(self.remoteMethod, args)
+
+ def handleResult(self, result):
+ """When the result is ready, relay it to self.deferred."""
+
+ self.deferred.callback(result)
+
+ def handleError(self, reason):
+ """When an error has occured, relay it to self.deferred."""
+
+ self.deferred.errback(reason)
+
+class ThreadedEngineService(EngineService):
+ """An EngineService subclass that defers execute commands to a separate
+ thread.
+
+ ThreadedEngineService uses twisted.internet.threads.deferToThread to
+ defer execute requests to a separate thread. GUI frontends may want to
+ use ThreadedEngineService as the engine in an
+ IPython.frontend.frontendbase.FrontEndBase subclass to prevent
+ block execution from blocking the GUI thread.
+ """
+
+ zi.implements(IEngineBase)
+
+ def __init__(self, shellClass=Interpreter, mpi=None):
+ EngineService.__init__(self, shellClass, mpi)
+
+ def wrapped_execute(self, msg, lines):
+ """Wrap self.shell.execute to add extra information to tracebacks"""
+
+ try:
+ result = self.shell.execute(lines)
+ except Exception,e:
+ # This gives the following:
+ # et=exception class
+ # ev=exception class instance
+ # tb=traceback object
+ et,ev,tb = sys.exc_info()
+ # This call adds attributes to the exception value
+ et,ev,tb = self.shell.formatTraceback(et,ev,tb,msg)
+ # Add another attribute
+
+ # Create a new exception with the new attributes
+ e = et(ev._ipython_traceback_text)
+ e._ipython_engine_info = msg
+
+ # Re-raise
+ raise e
+
+ return result
+
+
+ def execute(self, lines):
+ # Only import this if we are going to use this class
+ from twisted.internet import threads
+
+ msg = {'engineid':self.id,
+ 'method':'execute',
+ 'args':[lines]}
+
+ d = threads.deferToThread(self.wrapped_execute, msg, lines)
+ d.addCallback(self.addIDToResult)
+ return d
diff --git a/IPython/kernel/error.py b/IPython/kernel/error.py
new file mode 100644
index 0000000..77db614
--- /dev/null
+++ b/IPython/kernel/error.py
@@ -0,0 +1,205 @@
+# encoding: utf-8
+
+"""Classes and functions for kernel related errors and exceptions."""
+
+__docformat__ = "restructuredtext en"
+
+# Tell nose to skip this module
+__test__ = {}
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+from twisted.python import failure
+
+from IPython.kernel.core import error
+
+#-------------------------------------------------------------------------------
+# Error classes
+#-------------------------------------------------------------------------------
+
+class KernelError(error.IPythonError):
+ pass
+
+class NotDefined(KernelError):
+ def __init__(self, name):
+ self.name = name
+ self.args = (name,)
+
+ def __repr__(self):
+ return '<NotDefined: %s>' % self.name
+
+ __str__ = __repr__
+
+class QueueCleared(KernelError):
+ pass
+
+class IdInUse(KernelError):
+ pass
+
+class ProtocolError(KernelError):
+ pass
+
+class ConnectionError(KernelError):
+ pass
+
+class InvalidEngineID(KernelError):
+ pass
+
+class NoEnginesRegistered(KernelError):
+ pass
+
+class InvalidClientID(KernelError):
+ pass
+
+class InvalidDeferredID(KernelError):
+ pass
+
+class SerializationError(KernelError):
+ pass
+
+class MessageSizeError(KernelError):
+ pass
+
+class PBMessageSizeError(MessageSizeError):
+ pass
+
+class ResultNotCompleted(KernelError):
+ pass
+
+class ResultAlreadyRetrieved(KernelError):
+ pass
+
+class ClientError(KernelError):
+ pass
+
+class TaskAborted(KernelError):
+ pass
+
+class TaskTimeout(KernelError):
+ pass
+
+class NotAPendingResult(KernelError):
+ pass
+
+class UnpickleableException(KernelError):
+ pass
+
+class AbortedPendingDeferredError(KernelError):
+ pass
+
+class InvalidProperty(KernelError):
+ pass
+
+class MissingBlockArgument(KernelError):
+ pass
+
+class StopLocalExecution(KernelError):
+ pass
+
+class SecurityError(KernelError):
+ pass
+
+class FileTimeoutError(KernelError):
+ pass
+
+class TaskRejectError(KernelError):
+ """Exception to raise when a task should be rejected by an engine.
+
+ This exception can be used to allow a task running on an engine to test
+ if the engine (or the user's namespace on the engine) has the needed
+ task dependencies. If not, the task should raise this exception. For
+ the task to be retried on another engine, the task should be created
+ with the `retries` argument > 1.
+
+ The advantage of this approach over our older properties system is that
+ tasks have full access to the user's namespace on the engines and the
+ properties don't have to be managed or tested by the controller.
+ """
+
+class CompositeError(KernelError):
+ def __init__(self, message, elist):
+ Exception.__init__(self, *(message, elist))
+ self.message = message
+ self.elist = elist
+
+ def _get_engine_str(self, ev):
+ try:
+ ei = ev._ipython_engine_info
+ except AttributeError:
+ return '[Engine Exception]'
+ else:
+ return '[%i:%s]: ' % (ei['engineid'], ei['method'])
+
+ def _get_traceback(self, ev):
+ try:
+ tb = ev._ipython_traceback_text
+ except AttributeError:
+ return 'No traceback available'
+ else:
+ return tb
+
+ def __str__(self):
+ s = str(self.message)
+ for et, ev, etb in self.elist:
+ engine_str = self._get_engine_str(ev)
+ s = s + '\n' + engine_str + str(et.__name__) + ': ' + str(ev)
+ return s
+
+ def print_tracebacks(self, excid=None):
+ if excid is None:
+ for (et,ev,etb) in self.elist:
+ print self._get_engine_str(ev)
+ print self._get_traceback(ev)
+ print
+ else:
+ try:
+ et,ev,etb = self.elist[excid]
+ except:
+ raise IndexError("an exception with index %i does not exist"%excid)
+ else:
+ print self._get_engine_str(ev)
+ print self._get_traceback(ev)
+
+ def raise_exception(self, excid=0):
+ try:
+ et,ev,etb = self.elist[excid]
+ except:
+ raise IndexError("an exception with index %i does not exist"%excid)
+ else:
+ raise et, ev, etb
+
+def collect_exceptions(rlist, method):
+ elist = []
+ for r in rlist:
+ if isinstance(r, failure.Failure):
+ r.cleanFailure()
+ et, ev, etb = r.type, r.value, r.tb
+ # Sometimes we could have CompositeError in our list. Just take
+ # the errors out of them and put them in our new list. This
+ # has the effect of flattening lists of CompositeErrors into one
+ # CompositeError
+ if et==CompositeError:
+ for e in ev.elist:
+ elist.append(e)
+ else:
+ elist.append((et, ev, etb))
+ if len(elist)==0:
+ return rlist
+ else:
+ msg = "one or more exceptions from call to method: %s" % (method)
+ # This silliness is needed so the debugger has access to the exception
+ # instance (e in this case)
+ try:
+ raise CompositeError(msg, elist)
+ except CompositeError, e:
+ raise e
+
+
diff --git a/IPython/kernel/fcutil.py b/IPython/kernel/fcutil.py
new file mode 100644
index 0000000..9f7c730
--- /dev/null
+++ b/IPython/kernel/fcutil.py
@@ -0,0 +1,69 @@
+# encoding: utf-8
+
+"""Foolscap related utilities."""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+import os
+
+from foolscap import Tub, UnauthenticatedTub
+
+def check_furl_file_security(furl_file, secure):
+ """Remove the old furl_file if changing security modes."""
+
+ if os.path.isfile(furl_file):
+ f = open(furl_file, 'r')
+ oldfurl = f.read().strip()
+ f.close()
+ if (oldfurl.startswith('pb://') and not secure) or (oldfurl.startswith('pbu://') and secure):
+ os.remove(furl_file)
+
+def is_secure(furl):
+ if is_valid(furl):
+ if furl.startswith("pb://"):
+ return True
+ elif furl.startswith("pbu://"):
+ return False
+ else:
+ raise ValueError("invalid furl: %s" % furl)
+
+def is_valid(furl):
+ if isinstance(furl, str):
+ if furl.startswith("pb://") or furl.startswith("pbu://"):
+ return True
+ else:
+ return False
+
+def find_furl(furl_or_file):
+ if isinstance(furl_or_file, str):
+ if is_valid(furl_or_file):
+ return furl_or_file
+ if os.path.isfile(furl_or_file):
+ furl = open(furl_or_file, 'r').read().strip()
+ if is_valid(furl):
+ return furl
+ raise ValueError("not a furl or a file containing a furl: %s" % furl_or_file)
+
+# We do this so if a user doesn't have OpenSSL installed, it will try to use
+# an UnauthenticatedTub. But, they will still run into problems if they
+# try to use encrypted furls.
+try:
+ import OpenSSL
+except:
+ Tub = UnauthenticatedTub
+ have_crypto = False
+else:
+ have_crypto = True
+
+
diff --git a/IPython/kernel/magic.py b/IPython/kernel/magic.py
new file mode 100644
index 0000000..980c63b
--- /dev/null
+++ b/IPython/kernel/magic.py
@@ -0,0 +1,171 @@
+# encoding: utf-8
+
+"""Magic command interface for interactive parallel work."""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+import new
+
+from IPython.iplib import InteractiveShell
+from IPython.Shell import MTInteractiveShell
+
+from twisted.internet.defer import Deferred
+
+
+#-------------------------------------------------------------------------------
+# Definitions of magic functions for use with IPython
+#-------------------------------------------------------------------------------
+
+NO_ACTIVE_CONTROLLER = """
+Error: No Controller is activated
+Use activate() on a RemoteController object to activate it for magics.
+"""
+
+def magic_result(self,parameter_s=''):
+ """Print the result of command i on all engines of the active controller.
+
+ To activate a controller in IPython, first create it and then call
+ the activate() method.
+
+ Then you can do the following:
+
+ >>> result # Print the latest result
+ Printing result...
+ [127.0.0.1:0] In [1]: b = 10
+ [127.0.0.1:1] In [1]: b = 10
+
+ >>> result 0 # Print result 0
+ In [14]: result 0
+ Printing result...
+ [127.0.0.1:0] In [0]: a = 5
+ [127.0.0.1:1] In [0]: a = 5
+ """
+ try:
+ activeController = __IPYTHON__.activeController
+ except AttributeError:
+ print NO_ACTIVE_CONTROLLER
+ else:
+ try:
+ index = int(parameter_s)
+ except:
+ index = None
+ result = activeController.get_result(index)
+ return result
+
+def magic_px(self,parameter_s=''):
+ """Executes the given python command on the active IPython Controller.
+
+ To activate a Controller in IPython, first create it and then call
+ the activate() method.
+
+ Then you can do the following:
+
+ >>> %px a = 5 # Runs a = 5 on all nodes
+ """
+
+ try:
+ activeController = __IPYTHON__.activeController
+ except AttributeError:
+ print NO_ACTIVE_CONTROLLER
+ else:
+ print "Parallel execution on engines: %s" % activeController.targets
+ result = activeController.execute(parameter_s)
+ return result
+
+def pxrunsource(self, source, filename="<input>", symbol="single"):
+
+ try:
+ code = self.compile(source, filename, symbol)
+ except (OverflowError, SyntaxError, ValueError):
+ # Case 1
+ self.showsyntaxerror(filename)
+ return None
+
+ if code is None:
+ # Case 2
+ return True
+
+ # Case 3
+ # Because autopx is enabled, we now call executeAll or disable autopx if
+ # %autopx or autopx has been called
+ if '_ip.magic("%autopx' in source or '_ip.magic("autopx' in source:
+ _disable_autopx(self)
+ return False
+ else:
+ try:
+ result = self.activeController.execute(source)
+ except:
+ self.showtraceback()
+ else:
+ print result.__repr__()
+ return False
+
+def magic_autopx(self, parameter_s=''):
+ """Toggles auto parallel mode for the active IPython Controller.
+
+ To activate a Controller in IPython, first create it and then call
+ the activate() method.
+
+ Then you can do the following:
+
+ >>> %autopx # Now all commands are executed in parallel
+ Auto Parallel Enabled
+ Type %autopx to disable
+ ...
+ >>> %autopx # Now all commands are locally executed
+ Auto Parallel Disabled
+ """
+
+ if hasattr(self, 'autopx'):
+ if self.autopx == True:
+ _disable_autopx(self)
+ else:
+ _enable_autopx(self)
+ else:
+ _enable_autopx(self)
+
+def _enable_autopx(self):
+ """Enable %autopx mode by saving the original runsource and installing
+ pxrunsource.
+ """
+ try:
+ activeController = __IPYTHON__.activeController
+ except AttributeError:
+ print "No active RemoteController found, use RemoteController.activate()."
+ else:
+ self._original_runsource = self.runsource
+ self.runsource = new.instancemethod(pxrunsource, self, self.__class__)
+ self.autopx = True
+ print "Auto Parallel Enabled\nType %autopx to disable"
+
+def _disable_autopx(self):
+ """Disable %autopx by restoring the original runsource."""
+ if hasattr(self, 'autopx'):
+ if self.autopx == True:
+ self.runsource = self._original_runsource
+ self.autopx = False
+ print "Auto Parallel Disabled"
+
+# Add the new magic function to the class dict:
+
+InteractiveShell.magic_result = magic_result
+InteractiveShell.magic_px = magic_px
+InteractiveShell.magic_autopx = magic_autopx
+
+# And remove the global name to keep global namespace clean. Don't worry, the
+# copy bound to IPython stays, we're just removing the global name.
+del magic_result
+del magic_px
+del magic_autopx
+
diff --git a/IPython/kernel/map.py b/IPython/kernel/map.py
new file mode 100644
index 0000000..6183176
--- /dev/null
+++ b/IPython/kernel/map.py
@@ -0,0 +1,121 @@
+# encoding: utf-8
+
+"""Classes used in scattering and gathering sequences.
+
+Scattering consists of partitioning a sequence and sending the various
+pieces to individual nodes in a cluster.
+"""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+import types
+
+from IPython.genutils import flatten as genutil_flatten
+
+#-------------------------------------------------------------------------------
+# Figure out which array packages are present and their array types
+#-------------------------------------------------------------------------------
+
+arrayModules = []
+try:
+ import Numeric
+except ImportError:
+ pass
+else:
+ arrayModules.append({'module':Numeric, 'type':Numeric.arraytype})
+try:
+ import numpy
+except ImportError:
+ pass
+else:
+ arrayModules.append({'module':numpy, 'type':numpy.ndarray})
+try:
+ import numarray
+except ImportError:
+ pass
+else:
+ arrayModules.append({'module':numarray,
+ 'type':numarray.numarraycore.NumArray})
+
+class Map:
+ """A class for partitioning a sequence using a map."""
+
+ def getPartition(self, seq, p, q):
+ """Returns the pth partition of q partitions of seq."""
+
+ # Test for error conditions here
+ if p<0 or p>=q:
+ print "No partition exists."
+ return
+
+ remainder = len(seq)%q
+ basesize = len(seq)/q
+ hi = []
+ lo = []
+ for n in range(q):
+ if n < remainder:
+ lo.append(n * (basesize + 1))
+ hi.append(lo[-1] + basesize + 1)
+ else:
+ lo.append(n*basesize + remainder)
+ hi.append(lo[-1] + basesize)
+
+
+ result = seq[lo[p]:hi[p]]
+ return result
+
+ def joinPartitions(self, listOfPartitions):
+ return self.concatenate(listOfPartitions)
+
+ def concatenate(self, listOfPartitions):
+ testObject = listOfPartitions[0]
+ # First see if we have a known array type
+ for m in arrayModules:
+ #print m
+ if isinstance(testObject, m['type']):
+ return m['module'].concatenate(listOfPartitions)
+ # Next try for Python sequence types
+ if isinstance(testObject, (types.ListType, types.TupleType)):
+ return genutil_flatten(listOfPartitions)
+ # If we have scalars, just return listOfPartitions
+ return listOfPartitions
+
+class RoundRobinMap(Map):
+ """Partitions a sequence in a roun robin fashion.
+
+ This currently does not work!
+ """
+
+ def getPartition(self, seq, p, q):
+ return seq[p:len(seq):q]
+ #result = []
+ #for i in range(p,len(seq),q):
+ # result.append(seq[i])
+ #return result
+
+ def joinPartitions(self, listOfPartitions):
+ #lengths = [len(x) for x in listOfPartitions]
+ #maxPartitionLength = len(listOfPartitions[0])
+ #numberOfPartitions = len(listOfPartitions)
+ #concat = self.concatenate(listOfPartitions)
+ #totalLength = len(concat)
+ #result = []
+ #for i in range(maxPartitionLength):
+ # result.append(concat[i:totalLength:maxPartitionLength])
+ return self.concatenate(listOfPartitions)
+
+dists = {'b':Map}
+
+
+
diff --git a/IPython/kernel/mapper.py b/IPython/kernel/mapper.py
new file mode 100644
index 0000000..e732b53
--- /dev/null
+++ b/IPython/kernel/mapper.py
@@ -0,0 +1,233 @@
+# encoding: utf-8
+
+"""A parallelized version of Python's builtin map."""
+
+__docformat__ = "restructuredtext en"
+
+#----------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#----------------------------------------------------------------------------
+
+#----------------------------------------------------------------------------
+# Imports
+#----------------------------------------------------------------------------
+
+from types import FunctionType
+from zope.interface import Interface, implements
+from IPython.kernel.task import MapTask
+from IPython.kernel.twistedutil import DeferredList, gatherBoth
+from IPython.kernel.util import printer
+from IPython.kernel.error import collect_exceptions
+
+#----------------------------------------------------------------------------
+# Code
+#----------------------------------------------------------------------------
+
+class IMapper(Interface):
+ """The basic interface for a Mapper.
+
+ This defines a generic interface for mapping. The idea of this is
+ similar to that of Python's builtin `map` function, which applies a function
+ elementwise to a sequence.
+ """
+
+ def map(func, *seqs):
+ """Do map in parallel.
+
+ Equivalent to map(func, *seqs) or:
+
+ [func(seqs[0][0], seqs[1][0],...), func(seqs[0][1], seqs[1][1],...),...]
+
+ :Parameters:
+ func : FunctionType
+ The function to apply to the sequence
+ sequences : tuple of iterables
+ A sequence of iterables that are used for sucessive function
+ arguments. This work just like map
+ """
+
+class IMultiEngineMapperFactory(Interface):
+ """
+ An interface for something that creates `IMapper` instances.
+ """
+
+ def mapper(dist='b', targets='all', block=True):
+ """
+ Create an `IMapper` implementer with a given set of arguments.
+
+ The `IMapper` created using a multiengine controller is
+ not load balanced.
+ """
+
+class ITaskMapperFactory(Interface):
+ """
+ An interface for something that creates `IMapper` instances.
+ """
+
+ def mapper(clear_before=False, clear_after=False, retries=0,
+ recovery_task=None, depend=None, block=True):
+ """
+ Create an `IMapper` implementer with a given set of arguments.
+
+ The `IMapper` created using a task controller is load balanced.
+
+ See the documentation for `IPython.kernel.task.BaseTask` for
+ documentation on the arguments to this method.
+ """
+
+
+class MultiEngineMapper(object):
+ """
+ A Mapper for `IMultiEngine` implementers.
+ """
+
+ implements(IMapper)
+
+ def __init__(self, multiengine, dist='b', targets='all', block=True):
+ """
+ Create a Mapper for a multiengine.
+
+ The value of all arguments are used for all calls to `map`. This
+ class allows these arguemnts to be set for a series of map calls.
+
+ :Parameters:
+ multiengine : `IMultiEngine` implementer
+ The multiengine to use for running the map commands
+ dist : str
+ The type of decomposition to use. Only block ('b') is
+ supported currently
+ targets : (str, int, tuple of ints)
+ The engines to use in the map
+ block : boolean
+ Whether to block when the map is applied
+ """
+ self.multiengine = multiengine
+ self.dist = dist
+ self.targets = targets
+ self.block = block
+
+ def map(self, func, *sequences):
+ """
+ Apply func to *sequences elementwise. Like Python's builtin map.
+
+ This version is not load balanced.
+ """
+ max_len = max(len(s) for s in sequences)
+ for s in sequences:
+ if len(s)!=max_len:
+ raise ValueError('all sequences must have equal length')
+ assert isinstance(func, (str, FunctionType)), "func must be a fuction or str"
+ return self.multiengine.raw_map(func, sequences, dist=self.dist,
+ targets=self.targets, block=self.block)
+
+class TaskMapper(object):
+ """
+ Make an `ITaskController` look like an `IMapper`.
+
+ This class provides a load balanced version of `map`.
+ """
+
+ def __init__(self, task_controller, clear_before=False, clear_after=False, retries=0,
+ recovery_task=None, depend=None, block=True):
+ """
+ Create a `IMapper` given a `TaskController` and arguments.
+
+ The additional arguments are those that are common to all types of
+ tasks and are described in the documentation for
+ `IPython.kernel.task.BaseTask`.
+
+ :Parameters:
+ task_controller : an `IBlockingTaskClient` implementer
+ The `TaskController` to use for calls to `map`
+ """
+ self.task_controller = task_controller
+ self.clear_before = clear_before
+ self.clear_after = clear_after
+ self.retries = retries
+ self.recovery_task = recovery_task
+ self.depend = depend
+ self.block = block
+
+ def map(self, func, *sequences):
+ """
+ Apply func to *sequences elementwise. Like Python's builtin map.
+
+ This version is load balanced.
+ """
+ max_len = max(len(s) for s in sequences)
+ for s in sequences:
+ if len(s)!=max_len:
+ raise ValueError('all sequences must have equal length')
+ task_args = zip(*sequences)
+ task_ids = []
+ dlist = []
+ for ta in task_args:
+ task = MapTask(func, ta, clear_before=self.clear_before,
+ clear_after=self.clear_after, retries=self.retries,
+ recovery_task=self.recovery_task, depend=self.depend)
+ dlist.append(self.task_controller.run(task))
+ dlist = gatherBoth(dlist, consumeErrors=1)
+ dlist.addCallback(collect_exceptions,'map')
+ if self.block:
+ def get_results(task_ids):
+ d = self.task_controller.barrier(task_ids)
+ d.addCallback(lambda _: gatherBoth([self.task_controller.get_task_result(tid) for tid in task_ids], consumeErrors=1))
+ d.addCallback(collect_exceptions, 'map')
+ return d
+ dlist.addCallback(get_results)
+ return dlist
+
+class SynchronousTaskMapper(object):
+ """
+ Make an `IBlockingTaskClient` look like an `IMapper`.
+
+ This class provides a load balanced version of `map`.
+ """
+
+ def __init__(self, task_controller, clear_before=False, clear_after=False, retries=0,
+ recovery_task=None, depend=None, block=True):
+ """
+ Create a `IMapper` given a `IBlockingTaskClient` and arguments.
+
+ The additional arguments are those that are common to all types of
+ tasks and are described in the documentation for
+ `IPython.kernel.task.BaseTask`.
+
+ :Parameters:
+ task_controller : an `IBlockingTaskClient` implementer
+ The `TaskController` to use for calls to `map`
+ """
+ self.task_controller = task_controller
+ self.clear_before = clear_before
+ self.clear_after = clear_after
+ self.retries = retries
+ self.recovery_task = recovery_task
+ self.depend = depend
+ self.block = block
+
+ def map(self, func, *sequences):
+ """
+ Apply func to *sequences elementwise. Like Python's builtin map.
+
+ This version is load balanced.
+ """
+ max_len = max(len(s) for s in sequences)
+ for s in sequences:
+ if len(s)!=max_len:
+ raise ValueError('all sequences must have equal length')
+ task_args = zip(*sequences)
+ task_ids = []
+ for ta in task_args:
+ task = MapTask(func, ta, clear_before=self.clear_before,
+ clear_after=self.clear_after, retries=self.retries,
+ recovery_task=self.recovery_task, depend=self.depend)
+ task_ids.append(self.task_controller.run(task))
+ if self.block:
+ self.task_controller.barrier(task_ids)
+ task_results = [self.task_controller.get_task_result(tid) for tid in task_ids]
+ return task_results
+ else:
+ return task_ids \ No newline at end of file
diff --git a/IPython/kernel/multiengine.py b/IPython/kernel/multiengine.py
new file mode 100644
index 0000000..4d1fe6c
--- /dev/null
+++ b/IPython/kernel/multiengine.py
@@ -0,0 +1,753 @@
+# encoding: utf-8
+# -*- test-case-name: IPython.kernel.test.test_multiengine -*-
+
+"""Adapt the IPython ControllerServer to IMultiEngine.
+
+This module provides classes that adapt a ControllerService to the
+IMultiEngine interface. This interface is a basic interactive interface
+for working with a set of engines where it is desired to have explicit
+access to each registered engine.
+
+The classes here are exposed to the network in files like:
+
+* multienginevanilla.py
+* multienginepb.py
+"""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+from new import instancemethod
+from types import FunctionType
+
+from twisted.application import service
+from twisted.internet import defer, reactor
+from twisted.python import log, components, failure
+from zope.interface import Interface, implements, Attribute
+
+from IPython.tools import growl
+from IPython.kernel.util import printer
+from IPython.kernel.twistedutil import gatherBoth
+from IPython.kernel import map as Map
+from IPython.kernel import error
+from IPython.kernel.pendingdeferred import PendingDeferredManager, two_phase
+from IPython.kernel.controllerservice import \
+ ControllerAdapterBase, \
+ ControllerService, \
+ IControllerBase
+
+
+#-------------------------------------------------------------------------------
+# Interfaces for the MultiEngine representation of a controller
+#-------------------------------------------------------------------------------
+
+class IEngineMultiplexer(Interface):
+ """Interface to multiple engines implementing IEngineCore/Serialized/Queued.
+
+ This class simply acts as a multiplexer of methods that are in the
+ various IEngines* interfaces. Thus the methods here are jut like those
+ in the IEngine* interfaces, but with an extra first argument, targets.
+ The targets argument can have the following forms:
+
+ * targets = 10 # Engines are indexed by ints
+ * targets = [0,1,2,3] # A list of ints
+ * targets = 'all' # A string to indicate all targets
+
+ If targets is bad in any way, an InvalidEngineID will be raised. This
+ includes engines not being registered.
+
+ All IEngineMultiplexer multiplexer methods must return a Deferred to a list
+ with length equal to the number of targets. The elements of the list will
+ correspond to the return of the corresponding IEngine method.
+
+ Failures are aggressive, meaning that if an action fails for any target,
+ the overall action will fail immediately with that Failure.
+
+ :Parameters:
+ targets : int, list of ints, or 'all'
+ Engine ids the action will apply to.
+
+ :Returns: Deferred to a list of results for each engine.
+
+ :Exception:
+ InvalidEngineID
+ If the targets argument is bad or engines aren't registered.
+ NoEnginesRegistered
+ If there are no engines registered and targets='all'
+ """
+
+ #---------------------------------------------------------------------------
+ # Mutiplexed methods
+ #---------------------------------------------------------------------------
+
+ def execute(lines, targets='all'):
+ """Execute lines of Python code on targets.
+
+ See the class docstring for information about targets and possible
+ exceptions this method can raise.
+
+ :Parameters:
+ lines : str
+ String of python code to be executed on targets.
+ """
+
+ def push(namespace, targets='all'):
+ """Push dict namespace into the user's namespace on targets.
+
+ See the class docstring for information about targets and possible
+ exceptions this method can raise.
+
+ :Parameters:
+ namspace : dict
+ Dict of key value pairs to be put into the users namspace.
+ """
+
+ def pull(keys, targets='all'):
+ """Pull values out of the user's namespace on targets by keys.
+
+ See the class docstring for information about targets and possible
+ exceptions this method can raise.
+
+ :Parameters:
+ keys : tuple of strings
+ Sequence of keys to be pulled from user's namespace.
+ """
+
+ def push_function(namespace, targets='all'):
+ """"""
+
+ def pull_function(keys, targets='all'):
+ """"""
+
+ def get_result(i=None, targets='all'):
+ """Get the result for command i from targets.
+
+ See the class docstring for information about targets and possible
+ exceptions this method can raise.
+
+ :Parameters:
+ i : int or None
+ Command index or None to indicate most recent command.
+ """
+
+ def reset(targets='all'):
+ """Reset targets.
+
+ This clears the users namespace of the Engines, but won't cause
+ modules to be reloaded.
+ """
+
+ def keys(targets='all'):
+ """Get variable names defined in user's namespace on targets."""
+
+ def kill(controller=False, targets='all'):
+ """Kill the targets Engines and possibly the controller.
+
+ :Parameters:
+ controller : boolean
+ Should the controller be killed as well. If so all the
+ engines will be killed first no matter what targets is.
+ """
+
+ def push_serialized(namespace, targets='all'):
+ """Push a namespace of Serialized objects to targets.
+
+ :Parameters:
+ namespace : dict
+ A dict whose keys are the variable names and whose values
+ are serialized version of the objects.
+ """
+
+ def pull_serialized(keys, targets='all'):
+ """Pull Serialized objects by keys from targets.
+
+ :Parameters:
+ keys : tuple of strings
+ Sequence of variable names to pull as serialized objects.
+ """
+
+ def clear_queue(targets='all'):
+ """Clear the queue of pending command for targets."""
+
+ def queue_status(targets='all'):
+ """Get the status of the queue on the targets."""
+
+ def set_properties(properties, targets='all'):
+ """set properties by key and value"""
+
+ def get_properties(keys=None, targets='all'):
+ """get a list of properties by `keys`, if no keys specified, get all"""
+
+ def del_properties(keys, targets='all'):
+ """delete properties by `keys`"""
+
+ def has_properties(keys, targets='all'):
+ """get a list of bool values for whether `properties` has `keys`"""
+
+ def clear_properties(targets='all'):
+ """clear the properties dict"""
+
+
+class IMultiEngine(IEngineMultiplexer):
+ """A controller that exposes an explicit interface to all of its engines.
+
+ This is the primary inteface for interactive usage.
+ """
+
+ def get_ids():
+ """Return list of currently registered ids.
+
+ :Returns: A Deferred to a list of registered engine ids.
+ """
+
+
+
+#-------------------------------------------------------------------------------
+# Implementation of the core MultiEngine classes
+#-------------------------------------------------------------------------------
+
+class MultiEngine(ControllerAdapterBase):
+ """The representation of a ControllerService as a IMultiEngine.
+
+ Although it is not implemented currently, this class would be where a
+ client/notification API is implemented. It could inherit from something
+ like results.NotifierParent and then use the notify method to send
+ notifications.
+ """
+
+ implements(IMultiEngine)
+
+ def __init(self, controller):
+ ControllerAdapterBase.__init__(self, controller)
+
+ #---------------------------------------------------------------------------
+ # Helper methods
+ #---------------------------------------------------------------------------
+
+ def engineList(self, targets):
+ """Parse the targets argument into a list of valid engine objects.
+
+ :Parameters:
+ targets : int, list of ints or 'all'
+ The targets argument to be parsed.
+
+ :Returns: List of engine objects.
+
+ :Exception:
+ InvalidEngineID
+ If targets is not valid or if an engine is not registered.
+ """
+ if isinstance(targets, int):
+ if targets not in self.engines.keys():
+ log.msg("Engine with id %i is not registered" % targets)
+ raise error.InvalidEngineID("Engine with id %i is not registered" % targets)
+ else:
+ return [self.engines[targets]]
+ elif isinstance(targets, (list, tuple)):
+ for id in targets:
+ if id not in self.engines.keys():
+ log.msg("Engine with id %r is not registered" % id)
+ raise error.InvalidEngineID("Engine with id %r is not registered" % id)
+ return map(self.engines.get, targets)
+ elif targets == 'all':
+ eList = self.engines.values()
+ if len(eList) == 0:
+ msg = """There are no engines registered.
+ Check the logs in ~/.ipython/log if you think there should have been."""
+ raise error.NoEnginesRegistered(msg)
+ else:
+ return eList
+ else:
+ raise error.InvalidEngineID("targets argument is not an int, list of ints or 'all': %r"%targets)
+
+ def _performOnEngines(self, methodName, *args, **kwargs):
+ """Calls a method on engines and returns deferred to list of results.
+
+ :Parameters:
+ methodName : str
+ Name of the method to be called.
+ targets : int, list of ints, 'all'
+ The targets argument to be parsed into a list of engine objects.
+ args
+ The positional keyword arguments to be passed to the engines.
+ kwargs
+ The keyword arguments passed to the method
+
+ :Returns: List of deferreds to the results on each engine
+
+ :Exception:
+ InvalidEngineID
+ If the targets argument is bad in any way.
+ AttributeError
+ If the method doesn't exist on one of the engines.
+ """
+ targets = kwargs.pop('targets')
+ log.msg("Performing %s on %r" % (methodName, targets))
+ # log.msg("Performing %s(%r, %r) on %r" % (methodName, args, kwargs, targets))
+ # This will and should raise if targets is not valid!
+ engines = self.engineList(targets)
+ dList = []
+ for e in engines:
+ meth = getattr(e, methodName, None)
+ if meth is not None:
+ dList.append(meth(*args, **kwargs))
+ else:
+ raise AttributeError("Engine %i does not have method %s" % (e.id, methodName))
+ return dList
+
+ def _performOnEnginesAndGatherBoth(self, methodName, *args, **kwargs):
+ """Called _performOnEngines and wraps result/exception into deferred."""
+ try:
+ dList = self._performOnEngines(methodName, *args, **kwargs)
+ except (error.InvalidEngineID, AttributeError, KeyError, error.NoEnginesRegistered):
+ return defer.fail(failure.Failure())
+ else:
+ # Having fireOnOneErrback is causing problems with the determinacy
+ # of the system. Basically, once a single engine has errbacked, this
+ # method returns. In some cases, this will cause client to submit
+ # another command. Because the previous command is still running
+ # on some engines, this command will be queued. When those commands
+ # then errback, the second command will raise QueueCleared. Ahhh!
+ d = gatherBoth(dList,
+ fireOnOneErrback=0,
+ consumeErrors=1,
+ logErrors=0)
+ d.addCallback(error.collect_exceptions, methodName)
+ return d
+
+ #---------------------------------------------------------------------------
+ # General IMultiEngine methods
+ #---------------------------------------------------------------------------
+
+ def get_ids(self):
+ return defer.succeed(self.engines.keys())
+
+ #---------------------------------------------------------------------------
+ # IEngineMultiplexer methods
+ #---------------------------------------------------------------------------
+
+ def execute(self, lines, targets='all'):
+ return self._performOnEnginesAndGatherBoth('execute', lines, targets=targets)
+
+ def push(self, ns, targets='all'):
+ return self._performOnEnginesAndGatherBoth('push', ns, targets=targets)
+
+ def pull(self, keys, targets='all'):
+ return self._performOnEnginesAndGatherBoth('pull', keys, targets=targets)
+
+ def push_function(self, ns, targets='all'):
+ return self._performOnEnginesAndGatherBoth('push_function', ns, targets=targets)
+
+ def pull_function(self, keys, targets='all'):
+ return self._performOnEnginesAndGatherBoth('pull_function', keys, targets=targets)
+
+ def get_result(self, i=None, targets='all'):
+ return self._performOnEnginesAndGatherBoth('get_result', i, targets=targets)
+
+ def reset(self, targets='all'):
+ return self._performOnEnginesAndGatherBoth('reset', targets=targets)
+
+ def keys(self, targets='all'):
+ return self._performOnEnginesAndGatherBoth('keys', targets=targets)
+
+ def kill(self, controller=False, targets='all'):
+ if controller:
+ targets = 'all'
+ d = self._performOnEnginesAndGatherBoth('kill', targets=targets)
+ if controller:
+ log.msg("Killing controller")
+ d.addCallback(lambda _: reactor.callLater(2.0, reactor.stop))
+ # Consume any weird stuff coming back
+ d.addBoth(lambda _: None)
+ return d
+
+ def push_serialized(self, namespace, targets='all'):
+ for k, v in namespace.iteritems():
+ log.msg("Pushed object %s is %f MB" % (k, v.getDataSize()))
+ d = self._performOnEnginesAndGatherBoth('push_serialized', namespace, targets=targets)
+ return d
+
+ def pull_serialized(self, keys, targets='all'):
+ try:
+ dList = self._performOnEngines('pull_serialized', keys, targets=targets)
+ except (error.InvalidEngineID, AttributeError, error.NoEnginesRegistered):
+ return defer.fail(failure.Failure())
+ else:
+ for d in dList:
+ d.addCallback(self._logSizes)
+ d = gatherBoth(dList,
+ fireOnOneErrback=0,
+ consumeErrors=1,
+ logErrors=0)
+ d.addCallback(error.collect_exceptions, 'pull_serialized')
+ return d
+
+ def _logSizes(self, listOfSerialized):
+ if isinstance(listOfSerialized, (list, tuple)):
+ for s in listOfSerialized:
+ log.msg("Pulled object is %f MB" % s.getDataSize())
+ else:
+ log.msg("Pulled object is %f MB" % listOfSerialized.getDataSize())
+ return listOfSerialized
+
+ def clear_queue(self, targets='all'):
+ return self._performOnEnginesAndGatherBoth('clear_queue', targets=targets)
+
+ def queue_status(self, targets='all'):
+ log.msg("Getting queue status on %r" % targets)
+ try:
+ engines = self.engineList(targets)
+ except (error.InvalidEngineID, AttributeError, error.NoEnginesRegistered):
+ return defer.fail(failure.Failure())
+ else:
+ dList = []
+ for e in engines:
+ dList.append(e.queue_status().addCallback(lambda s:(e.id, s)))
+ d = gatherBoth(dList,
+ fireOnOneErrback=0,
+ consumeErrors=1,
+ logErrors=0)
+ d.addCallback(error.collect_exceptions, 'queue_status')
+ return d
+
+ def get_properties(self, keys=None, targets='all'):
+ log.msg("Getting properties on %r" % targets)
+ try:
+ engines = self.engineList(targets)
+ except (error.InvalidEngineID, AttributeError, error.NoEnginesRegistered):
+ return defer.fail(failure.Failure())
+ else:
+ dList = [e.get_properties(keys) for e in engines]
+ d = gatherBoth(dList,
+ fireOnOneErrback=0,
+ consumeErrors=1,
+ logErrors=0)
+ d.addCallback(error.collect_exceptions, 'get_properties')
+ return d
+
+ def set_properties(self, properties, targets='all'):
+ log.msg("Setting properties on %r" % targets)
+ try:
+ engines = self.engineList(targets)
+ except (error.InvalidEngineID, AttributeError, error.NoEnginesRegistered):
+ return defer.fail(failure.Failure())
+ else:
+ dList = [e.set_properties(properties) for e in engines]
+ d = gatherBoth(dList,
+ fireOnOneErrback=0,
+ consumeErrors=1,
+ logErrors=0)
+ d.addCallback(error.collect_exceptions, 'set_properties')
+ return d
+
+ def has_properties(self, keys, targets='all'):
+ log.msg("Checking properties on %r" % targets)
+ try:
+ engines = self.engineList(targets)
+ except (error.InvalidEngineID, AttributeError, error.NoEnginesRegistered):
+ return defer.fail(failure.Failure())
+ else:
+ dList = [e.has_properties(keys) for e in engines]
+ d = gatherBoth(dList,
+ fireOnOneErrback=0,
+ consumeErrors=1,
+ logErrors=0)
+ d.addCallback(error.collect_exceptions, 'has_properties')
+ return d
+
+ def del_properties(self, keys, targets='all'):
+ log.msg("Deleting properties on %r" % targets)
+ try:
+ engines = self.engineList(targets)
+ except (error.InvalidEngineID, AttributeError, error.NoEnginesRegistered):
+ return defer.fail(failure.Failure())
+ else:
+ dList = [e.del_properties(keys) for e in engines]
+ d = gatherBoth(dList,
+ fireOnOneErrback=0,
+ consumeErrors=1,
+ logErrors=0)
+ d.addCallback(error.collect_exceptions, 'del_properties')
+ return d
+
+ def clear_properties(self, targets='all'):
+ log.msg("Clearing properties on %r" % targets)
+ try:
+ engines = self.engineList(targets)
+ except (error.InvalidEngineID, AttributeError, error.NoEnginesRegistered):
+ return defer.fail(failure.Failure())
+ else:
+ dList = [e.clear_properties() for e in engines]
+ d = gatherBoth(dList,
+ fireOnOneErrback=0,
+ consumeErrors=1,
+ logErrors=0)
+ d.addCallback(error.collect_exceptions, 'clear_properties')
+ return d
+
+
+components.registerAdapter(MultiEngine,
+ IControllerBase,
+ IMultiEngine)
+
+
+#-------------------------------------------------------------------------------
+# Interfaces for the Synchronous MultiEngine
+#-------------------------------------------------------------------------------
+
+class ISynchronousEngineMultiplexer(Interface):
+ pass
+
+
+class ISynchronousMultiEngine(ISynchronousEngineMultiplexer):
+ """Synchronous, two-phase version of IMultiEngine.
+
+ Methods in this interface are identical to those of IMultiEngine, but they
+ take one additional argument:
+
+ execute(lines, targets='all') -> execute(lines, targets='all, block=True)
+
+ :Parameters:
+ block : boolean
+ Should the method return a deferred to a deferredID or the
+ actual result. If block=False a deferred to a deferredID is
+ returned and the user must call `get_pending_deferred` at a later
+ point. If block=True, a deferred to the actual result comes back.
+ """
+ def get_pending_deferred(deferredID, block=True):
+ """"""
+
+ def clear_pending_deferreds():
+ """"""
+
+
+#-------------------------------------------------------------------------------
+# Implementation of the Synchronous MultiEngine
+#-------------------------------------------------------------------------------
+
+class SynchronousMultiEngine(PendingDeferredManager):
+ """Adapt an `IMultiEngine` -> `ISynchronousMultiEngine`
+
+ Warning, this class uses a decorator that currently uses **kwargs.
+ Because of this block must be passed as a kwarg, not positionally.
+ """
+
+ implements(ISynchronousMultiEngine)
+
+ def __init__(self, multiengine):
+ self.multiengine = multiengine
+ PendingDeferredManager.__init__(self)
+
+ #---------------------------------------------------------------------------
+ # Decorated pending deferred methods
+ #---------------------------------------------------------------------------
+
+ @two_phase
+ def execute(self, lines, targets='all'):
+ d = self.multiengine.execute(lines, targets)
+ return d
+
+ @two_phase
+ def push(self, namespace, targets='all'):
+ return self.multiengine.push(namespace, targets)
+
+ @two_phase
+ def pull(self, keys, targets='all'):
+ d = self.multiengine.pull(keys, targets)
+ return d
+
+ @two_phase
+ def push_function(self, namespace, targets='all'):
+ return self.multiengine.push_function(namespace, targets)
+
+ @two_phase
+ def pull_function(self, keys, targets='all'):
+ d = self.multiengine.pull_function(keys, targets)
+ return d
+
+ @two_phase
+ def get_result(self, i=None, targets='all'):
+ return self.multiengine.get_result(i, targets='all')
+
+ @two_phase
+ def reset(self, targets='all'):
+ return self.multiengine.reset(targets)
+
+ @two_phase
+ def keys(self, targets='all'):
+ return self.multiengine.keys(targets)
+
+ @two_phase
+ def kill(self, controller=False, targets='all'):
+ return self.multiengine.kill(controller, targets)
+
+ @two_phase
+ def push_serialized(self, namespace, targets='all'):
+ return self.multiengine.push_serialized(namespace, targets)
+
+ @two_phase
+ def pull_serialized(self, keys, targets='all'):
+ return self.multiengine.pull_serialized(keys, targets)
+
+ @two_phase
+ def clear_queue(self, targets='all'):
+ return self.multiengine.clear_queue(targets)
+
+ @two_phase
+ def queue_status(self, targets='all'):
+ return self.multiengine.queue_status(targets)
+
+ @two_phase
+ def set_properties(self, properties, targets='all'):
+ return self.multiengine.set_properties(properties, targets)
+
+ @two_phase
+ def get_properties(self, keys=None, targets='all'):
+ return self.multiengine.get_properties(keys, targets)
+
+ @two_phase
+ def has_properties(self, keys, targets='all'):
+ return self.multiengine.has_properties(keys, targets)
+
+ @two_phase
+ def del_properties(self, keys, targets='all'):
+ return self.multiengine.del_properties(keys, targets)
+
+ @two_phase
+ def clear_properties(self, targets='all'):
+ return self.multiengine.clear_properties(targets)
+
+ #---------------------------------------------------------------------------
+ # IMultiEngine methods
+ #---------------------------------------------------------------------------
+
+ def get_ids(self):
+ """Return a list of registered engine ids.
+
+ Never use the two phase block/non-block stuff for this.
+ """
+ return self.multiengine.get_ids()
+
+
+components.registerAdapter(SynchronousMultiEngine, IMultiEngine, ISynchronousMultiEngine)
+
+
+#-------------------------------------------------------------------------------
+# Various high-level interfaces that can be used as MultiEngine mix-ins
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# IMultiEngineCoordinator
+#-------------------------------------------------------------------------------
+
+class IMultiEngineCoordinator(Interface):
+ """Methods that work on multiple engines explicitly."""
+
+ def scatter(key, seq, dist='b', flatten=False, targets='all'):
+ """Partition and distribute a sequence to targets."""
+
+ def gather(key, dist='b', targets='all'):
+ """Gather object key from targets."""
+
+ def raw_map(func, seqs, dist='b', targets='all'):
+ """
+ A parallelized version of Python's builtin `map` function.
+
+ This has a slightly different syntax than the builtin `map`.
+ This is needed because we need to have keyword arguments and thus
+ can't use *args to capture all the sequences. Instead, they must
+ be passed in a list or tuple.
+
+ The equivalence is:
+
+ raw_map(func, seqs) -> map(func, seqs[0], seqs[1], ...)
+
+ Most users will want to use parallel functions or the `mapper`
+ and `map` methods for an API that follows that of the builtin
+ `map`.
+ """
+
+
+class ISynchronousMultiEngineCoordinator(IMultiEngineCoordinator):
+ """Methods that work on multiple engines explicitly."""
+
+ def scatter(key, seq, dist='b', flatten=False, targets='all', block=True):
+ """Partition and distribute a sequence to targets."""
+
+ def gather(key, dist='b', targets='all', block=True):
+ """Gather object key from targets"""
+
+ def raw_map(func, seqs, dist='b', targets='all', block=True):
+ """
+ A parallelized version of Python's builtin map.
+
+ This has a slightly different syntax than the builtin `map`.
+ This is needed because we need to have keyword arguments and thus
+ can't use *args to capture all the sequences. Instead, they must
+ be passed in a list or tuple.
+
+ raw_map(func, seqs) -> map(func, seqs[0], seqs[1], ...)
+
+ Most users will want to use parallel functions or the `mapper`
+ and `map` methods for an API that follows that of the builtin
+ `map`.
+ """
+
+
+#-------------------------------------------------------------------------------
+# IMultiEngineExtras
+#-------------------------------------------------------------------------------
+
+class IMultiEngineExtras(Interface):
+
+ def zip_pull(targets, keys):
+ """
+ Pull, but return results in a different format from `pull`.
+
+ This method basically returns zip(pull(targets, *keys)), with a few
+ edge cases handled differently. Users of chainsaw will find this format
+ familiar.
+ """
+
+ def run(targets, fname):
+ """Run a .py file on targets."""
+
+
+class ISynchronousMultiEngineExtras(IMultiEngineExtras):
+ def zip_pull(targets, keys, block=True):
+ """
+ Pull, but return results in a different format from `pull`.
+
+ This method basically returns zip(pull(targets, *keys)), with a few
+ edge cases handled differently. Users of chainsaw will find this format
+ familiar.
+ """
+
+ def run(targets, fname, block=True):
+ """Run a .py file on targets."""
+
+#-------------------------------------------------------------------------------
+# The full MultiEngine interface
+#-------------------------------------------------------------------------------
+
+class IFullMultiEngine(IMultiEngine,
+ IMultiEngineCoordinator,
+ IMultiEngineExtras):
+ pass
+
+
+class IFullSynchronousMultiEngine(ISynchronousMultiEngine,
+ ISynchronousMultiEngineCoordinator,
+ ISynchronousMultiEngineExtras):
+ pass
+
diff --git a/IPython/kernel/multiengineclient.py b/IPython/kernel/multiengineclient.py
new file mode 100644
index 0000000..37106ee
--- /dev/null
+++ b/IPython/kernel/multiengineclient.py
@@ -0,0 +1,964 @@
+# encoding: utf-8
+# -*- test-case-name: IPython.kernel.test.test_multiengineclient -*-
+
+"""General Classes for IMultiEngine clients."""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+import sys
+import cPickle as pickle
+from types import FunctionType
+import linecache
+import warnings
+
+from twisted.internet import reactor
+from twisted.python import components, log
+from twisted.python.failure import Failure
+from zope.interface import Interface, implements, Attribute
+
+from IPython.ColorANSI import TermColors
+
+from IPython.kernel.twistedutil import blockingCallFromThread
+from IPython.kernel import error
+from IPython.kernel.parallelfunction import ParallelFunction
+from IPython.kernel.mapper import (
+ MultiEngineMapper,
+ IMultiEngineMapperFactory,
+ IMapper
+)
+from IPython.kernel import map as Map
+from IPython.kernel import multiengine as me
+from IPython.kernel.multiengine import (IFullMultiEngine,
+ IFullSynchronousMultiEngine)
+
+
+#-------------------------------------------------------------------------------
+# Pending Result things
+#-------------------------------------------------------------------------------
+
+class IPendingResult(Interface):
+ """A representation of a result that is pending.
+
+ This class is similar to Twisted's `Deferred` object, but is designed to be
+ used in a synchronous context.
+ """
+
+ result_id=Attribute("ID of the deferred on the other side")
+ client=Attribute("A client that I came from")
+ r=Attribute("An attribute that is a property that calls and returns get_result")
+
+ def get_result(default=None, block=True):
+ """
+ Get a result that is pending.
+
+ :Parameters:
+ default
+ The value to return if the result is not ready.
+ block : boolean
+ Should I block for the result.
+
+ :Returns: The actual result or the default value.
+ """
+
+ def add_callback(f, *args, **kwargs):
+ """
+ Add a callback that is called with the result.
+
+ If the original result is foo, adding a callback will cause
+ f(foo, *args, **kwargs) to be returned instead. If multiple
+ callbacks are registered, they are chained together: the result of
+ one is passed to the next and so on.
+
+ Unlike Twisted's Deferred object, there is no errback chain. Thus
+ any exception raised will not be caught and handled. User must
+ catch these by hand when calling `get_result`.
+ """
+
+
+class PendingResult(object):
+ """A representation of a result that is not yet ready.
+
+ A user should not create a `PendingResult` instance by hand.
+
+ Methods:
+
+ * `get_result`
+ * `add_callback`
+
+ Properties:
+
+ * `r`
+ """
+
+ def __init__(self, client, result_id):
+ """Create a PendingResult with a result_id and a client instance.
+
+ The client should implement `_getPendingResult(result_id, block)`.
+ """
+ self.client = client
+ self.result_id = result_id
+ self.called = False
+ self.raised = False
+ self.callbacks = []
+
+ def get_result(self, default=None, block=True):
+ """Get a result that is pending.
+
+ This method will connect to an IMultiEngine adapted controller
+ and see if the result is ready. If the action triggers an exception
+ raise it and record it. This method records the result/exception once it is
+ retrieved. Calling `get_result` again will get this cached result or will
+ re-raise the exception. The .r attribute is a property that calls
+ `get_result` with block=True.
+
+ :Parameters:
+ default
+ The value to return if the result is not ready.
+ block : boolean
+ Should I block for the result.
+
+ :Returns: The actual result or the default value.
+ """
+
+ if self.called:
+ if self.raised:
+ raise self.result[0], self.result[1], self.result[2]
+ else:
+ return self.result
+ try:
+ result = self.client.get_pending_deferred(self.result_id, block)
+ except error.ResultNotCompleted:
+ return default
+ except:
+ # Reraise other error, but first record them so they can be reraised
+ # later if .r or get_result is called again.
+ self.result = sys.exc_info()
+ self.called = True
+ self.raised = True
+ raise
+ else:
+ for cb in self.callbacks:
+ result = cb[0](result, *cb[1], **cb[2])
+ self.result = result
+ self.called = True
+ return result
+
+ def add_callback(self, f, *args, **kwargs):
+ """Add a callback that is called with the result.
+
+ If the original result is result, adding a callback will cause
+ f(result, *args, **kwargs) to be returned instead. If multiple
+ callbacks are registered, they are chained together: the result of
+ one is passed to the next and so on.
+
+ Unlike Twisted's Deferred object, there is no errback chain. Thus
+ any exception raised will not be caught and handled. User must
+ catch these by hand when calling `get_result`.
+ """
+ assert callable(f)
+ self.callbacks.append((f, args, kwargs))
+
+ def __cmp__(self, other):
+ if self.result_id < other.result_id:
+ return -1
+ else:
+ return 1
+
+ def _get_r(self):
+ return self.get_result(block=True)
+
+ r = property(_get_r)
+ """This property is a shortcut to a `get_result(block=True)`."""
+
+
+#-------------------------------------------------------------------------------
+# Pretty printing wrappers for certain lists
+#-------------------------------------------------------------------------------
+
+class ResultList(list):
+ """A subclass of list that pretty prints the output of `execute`/`get_result`."""
+
+ def __repr__(self):
+ output = []
+ # These colored prompts were not working on Windows
+ if sys.platform == 'win32':
+ blue = normal = red = green = ''
+ else:
+ blue = TermColors.Blue
+ normal = TermColors.Normal
+ red = TermColors.Red
+ green = TermColors.Green
+ output.append("<Results List>\n")
+ for cmd in self:
+ if isinstance(cmd, Failure):
+ output.append(cmd)
+ else:
+ target = cmd.get('id',None)
+ cmd_num = cmd.get('number',None)
+ cmd_stdin = cmd.get('input',{}).get('translated','No Input')
+ cmd_stdout = cmd.get('stdout', None)
+ cmd_stderr = cmd.get('stderr', None)
+ output.append("%s[%i]%s In [%i]:%s %s\n" % \
+ (green, target,
+ blue, cmd_num, normal, cmd_stdin))
+ if cmd_stdout:
+ output.append("%s[%i]%s Out[%i]:%s %s\n" % \
+ (green, target,
+ red, cmd_num, normal, cmd_stdout))
+ if cmd_stderr:
+ output.append("%s[%i]%s Err[%i]:\n%s %s" % \
+ (green, target,
+ red, cmd_num, normal, cmd_stderr))
+ return ''.join(output)
+
+
+def wrapResultList(result):
+ """A function that wraps the output of `execute`/`get_result` -> `ResultList`."""
+ if len(result) == 0:
+ result = [result]
+ return ResultList(result)
+
+
+class QueueStatusList(list):
+ """A subclass of list that pretty prints the output of `queue_status`."""
+
+ def __repr__(self):
+ output = []
+ output.append("<Queue Status List>\n")
+ for e in self:
+ output.append("Engine: %s\n" % repr(e[0]))
+ output.append(" Pending: %s\n" % repr(e[1]['pending']))
+ for q in e[1]['queue']:
+ output.append(" Command: %s\n" % repr(q))
+ return ''.join(output)
+
+
+#-------------------------------------------------------------------------------
+# InteractiveMultiEngineClient
+#-------------------------------------------------------------------------------
+
+class InteractiveMultiEngineClient(object):
+ """A mixin class that add a few methods to a multiengine client.
+
+ The methods in this mixin class are designed for interactive usage.
+ """
+
+ def activate(self):
+ """Make this `MultiEngineClient` active for parallel magic commands.
+
+ IPython has a magic command syntax to work with `MultiEngineClient` objects.
+ In a given IPython session there is a single active one. While
+ there can be many `MultiEngineClient` created and used by the user,
+ there is only one active one. The active `MultiEngineClient` is used whenever
+ the magic commands %px and %autopx are used.
+
+ The activate() method is called on a given `MultiEngineClient` to make it
+ active. Once this has been done, the magic commands can be used.
+ """
+
+ try:
+ __IPYTHON__.activeController = self
+ except NameError:
+ print "The IPython Controller magics only work within IPython."
+
+ def __setitem__(self, key, value):
+ """Add a dictionary interface for pushing/pulling.
+
+ This functions as a shorthand for `push`.
+
+ :Parameters:
+ key : str
+ What to call the remote object.
+ value : object
+ The local Python object to push.
+ """
+ targets, block = self._findTargetsAndBlock()
+ return self.push({key:value}, targets=targets, block=block)
+
+ def __getitem__(self, key):
+ """Add a dictionary interface for pushing/pulling.
+
+ This functions as a shorthand to `pull`.
+
+ :Parameters:
+ - `key`: A string representing the key.
+ """
+ if isinstance(key, str):
+ targets, block = self._findTargetsAndBlock()
+ return self.pull(key, targets=targets, block=block)
+ else:
+ raise TypeError("__getitem__ only takes strs")
+
+ def __len__(self):
+ """Return the number of available engines."""
+ return len(self.get_ids())
+
+ #---------------------------------------------------------------------------
+ # Make this a context manager for with
+ #---------------------------------------------------------------------------
+
+ def findsource_file(self,f):
+ linecache.checkcache()
+ s = findsource(f.f_code)
+ lnum = f.f_lineno
+ wsource = s[0][f.f_lineno:]
+ return strip_whitespace(wsource)
+
+ def findsource_ipython(self,f):
+ from IPython import ipapi
+ self.ip = ipapi.get()
+ wsource = [l+'\n' for l in
+ self.ip.IP.input_hist_raw[-1].splitlines()[1:]]
+ return strip_whitespace(wsource)
+
+ def __enter__(self):
+ f = sys._getframe(1)
+ local_ns = f.f_locals
+ global_ns = f.f_globals
+ if f.f_code.co_filename == '<ipython console>':
+ s = self.findsource_ipython(f)
+ else:
+ s = self.findsource_file(f)
+
+ self._with_context_result = self.execute(s)
+
+ def __exit__ (self, etype, value, tb):
+ if issubclass(etype,error.StopLocalExecution):
+ return True
+
+
+def remote():
+ m = 'Special exception to stop local execution of parallel code.'
+ raise error.StopLocalExecution(m)
+
+def strip_whitespace(source):
+ # Expand tabs to avoid any confusion.
+ wsource = [l.expandtabs(4) for l in source]
+ # Detect the indentation level
+ done = False
+ for line in wsource:
+ if line.isspace():
+ continue
+ for col,char in enumerate(line):
+ if char != ' ':
+ done = True
+ break
+ if done:
+ break
+ # Now we know how much leading space there is in the code. Next, we
+ # extract up to the first line that has less indentation.
+ # WARNINGS: we skip comments that may be misindented, but we do NOT yet
+ # detect triple quoted strings that may have flush left text.
+ for lno,line in enumerate(wsource):
+ lead = line[:col]
+ if lead.isspace():
+ continue
+ else:
+ if not lead.lstrip().startswith('#'):
+ break
+ # The real 'with' source is up to lno
+ src_lines = [l[col:] for l in wsource[:lno+1]]
+
+ # Finally, check that the source's first non-comment line begins with the
+ # special call 'remote()'
+ for nline,line in enumerate(src_lines):
+ if line.isspace() or line.startswith('#'):
+ continue
+ if 'remote()' in line:
+ break
+ else:
+ raise ValueError('remote() call missing at the start of code')
+ src = ''.join(src_lines[nline+1:])
+ #print 'SRC:\n<<<<<<<>>>>>>>\n%s<<<<<>>>>>>' % src # dbg
+ return src
+
+
+#-------------------------------------------------------------------------------
+# The top-level MultiEngine client adaptor
+#-------------------------------------------------------------------------------
+
+
+_prop_warn = """\
+
+We are currently refactoring the task dependency system. This might
+involve the removal of this method and other methods related to engine
+properties. Please see the docstrings for IPython.kernel.TaskRejectError
+for more information."""
+
+
+class IFullBlockingMultiEngineClient(Interface):
+ pass
+
+
+class FullBlockingMultiEngineClient(InteractiveMultiEngineClient):
+ """
+ A blocking client to the `IMultiEngine` controller interface.
+
+ This class allows users to use a set of engines for a parallel
+ computation through the `IMultiEngine` interface. In this interface,
+ each engine has a specific id (an int) that is used to refer to the
+ engine, run code on it, etc.
+ """
+
+ implements(
+ IFullBlockingMultiEngineClient,
+ IMultiEngineMapperFactory,
+ IMapper
+ )
+
+ def __init__(self, smultiengine):
+ self.smultiengine = smultiengine
+ self.block = True
+ self.targets = 'all'
+
+ def _findBlock(self, block=None):
+ if block is None:
+ return self.block
+ else:
+ if block in (True, False):
+ return block
+ else:
+ raise ValueError("block must be True or False")
+
+ def _findTargets(self, targets=None):
+ if targets is None:
+ return self.targets
+ else:
+ if not isinstance(targets, (str,list,tuple,int)):
+ raise ValueError("targets must be a str, list, tuple or int")
+ return targets
+
+ def _findTargetsAndBlock(self, targets=None, block=None):
+ return self._findTargets(targets), self._findBlock(block)
+
+ def _blockFromThread(self, function, *args, **kwargs):
+ block = kwargs.get('block', None)
+ if block is None:
+ raise error.MissingBlockArgument("'block' keyword argument is missing")
+ result = blockingCallFromThread(function, *args, **kwargs)
+ if not block:
+ result = PendingResult(self, result)
+ return result
+
+ def get_pending_deferred(self, deferredID, block):
+ return blockingCallFromThread(self.smultiengine.get_pending_deferred, deferredID, block)
+
+ def barrier(self, pendingResults):
+ """Synchronize a set of `PendingResults`.
+
+ This method is a synchronization primitive that waits for a set of
+ `PendingResult` objects to complete. More specifically, barier does
+ the following.
+
+ * The `PendingResult`s are sorted by result_id.
+ * The `get_result` method is called for each `PendingResult` sequentially
+ with block=True.
+ * If a `PendingResult` gets a result that is an exception, it is
+ trapped and can be re-raised later by calling `get_result` again.
+ * The `PendingResult`s are flushed from the controller.
+
+ After barrier has been called on a `PendingResult`, its results can
+ be retrieved by calling `get_result` again or accesing the `r` attribute
+ of the instance.
+ """
+
+ # Convert to list for sorting and check class type
+ prList = list(pendingResults)
+ for pr in prList:
+ if not isinstance(pr, PendingResult):
+ raise error.NotAPendingResult("Objects passed to barrier must be PendingResult instances")
+
+ # Sort the PendingResults so they are in order
+ prList.sort()
+ # Block on each PendingResult object
+ for pr in prList:
+ try:
+ result = pr.get_result(block=True)
+ except Exception:
+ pass
+
+ def flush(self):
+ """
+ Clear all pending deferreds/results from the controller.
+
+ For each `PendingResult` that is created by this client, the controller
+ holds on to the result for that `PendingResult`. This can be a problem
+ if there are a large number of `PendingResult` objects that are created.
+
+ Once the result of the `PendingResult` has been retrieved, the result
+ is removed from the controller, but if a user doesn't get a result (
+ they just ignore the `PendingResult`) the result is kept forever on the
+ controller. This method allows the user to clear out all un-retrieved
+ results on the controller.
+ """
+ r = blockingCallFromThread(self.smultiengine.clear_pending_deferreds)
+ return r
+
+ clear_pending_results = flush
+
+ #---------------------------------------------------------------------------
+ # IEngineMultiplexer related methods
+ #---------------------------------------------------------------------------
+
+ def execute(self, lines, targets=None, block=None):
+ """
+ Execute code on a set of engines.
+
+ :Parameters:
+ lines : str
+ The Python code to execute as a string
+ targets : id or list of ids
+ The engine to use for the execution
+ block : boolean
+ If False, this method will return the actual result. If False,
+ a `PendingResult` is returned which can be used to get the result
+ at a later time.
+ """
+ targets, block = self._findTargetsAndBlock(targets, block)
+ result = blockingCallFromThread(self.smultiengine.execute, lines,
+ targets=targets, block=block)
+ if block:
+ result = ResultList(result)
+ else:
+ result = PendingResult(self, result)
+ result.add_callback(wrapResultList)
+ return result
+
+ def push(self, namespace, targets=None, block=None):
+ """
+ Push a dictionary of keys and values to engines namespace.
+
+ Each engine has a persistent namespace. This method is used to push
+ Python objects into that namespace.
+
+ The objects in the namespace must be pickleable.
+
+ :Parameters:
+ namespace : dict
+ A dict that contains Python objects to be injected into
+ the engine persistent namespace.
+ targets : id or list of ids
+ The engine to use for the execution
+ block : boolean
+ If False, this method will return the actual result. If False,
+ a `PendingResult` is returned which can be used to get the result
+ at a later time.
+ """
+ targets, block = self._findTargetsAndBlock(targets, block)
+ return self._blockFromThread(self.smultiengine.push, namespace,
+ targets=targets, block=block)
+
+ def pull(self, keys, targets=None, block=None):
+ """
+ Pull Python objects by key out of engines namespaces.
+
+ :Parameters:
+ keys : str or list of str
+ The names of the variables to be pulled
+ targets : id or list of ids
+ The engine to use for the execution
+ block : boolean
+ If False, this method will return the actual result. If False,
+ a `PendingResult` is returned which can be used to get the result
+ at a later time.
+ """
+ targets, block = self._findTargetsAndBlock(targets, block)
+ return self._blockFromThread(self.smultiengine.pull, keys, targets=targets, block=block)
+
+ def push_function(self, namespace, targets=None, block=None):
+ """
+ Push a Python function to an engine.
+
+ This method is used to push a Python function to an engine. This
+ method can then be used in code on the engines. Closures are not supported.
+
+ :Parameters:
+ namespace : dict
+ A dict whose values are the functions to be pushed. The keys give
+ that names that the function will appear as in the engines
+ namespace.
+ targets : id or list of ids
+ The engine to use for the execution
+ block : boolean
+ If False, this method will return the actual result. If False,
+ a `PendingResult` is returned which can be used to get the result
+ at a later time.
+ """
+ targets, block = self._findTargetsAndBlock(targets, block)
+ return self._blockFromThread(self.smultiengine.push_function, namespace, targets=targets, block=block)
+
+ def pull_function(self, keys, targets=None, block=None):
+ """
+ Pull a Python function from an engine.
+
+ This method is used to pull a Python function from an engine.
+ Closures are not supported.
+
+ :Parameters:
+ keys : str or list of str
+ The names of the functions to be pulled
+ targets : id or list of ids
+ The engine to use for the execution
+ block : boolean
+ If False, this method will return the actual result. If False,
+ a `PendingResult` is returned which can be used to get the result
+ at a later time.
+ """
+ targets, block = self._findTargetsAndBlock(targets, block)
+ return self._blockFromThread(self.smultiengine.pull_function, keys, targets=targets, block=block)
+
+ def push_serialized(self, namespace, targets=None, block=None):
+ targets, block = self._findTargetsAndBlock(targets, block)
+ return self._blockFromThread(self.smultiengine.push_serialized, namespace, targets=targets, block=block)
+
+ def pull_serialized(self, keys, targets=None, block=None):
+ targets, block = self._findTargetsAndBlock(targets, block)
+ return self._blockFromThread(self.smultiengine.pull_serialized, keys, targets=targets, block=block)
+
+ def get_result(self, i=None, targets=None, block=None):
+ """
+ Get a previous result.
+
+ When code is executed in an engine, a dict is created and returned. This
+ method retrieves that dict for previous commands.
+
+ :Parameters:
+ i : int
+ The number of the result to get
+ targets : id or list of ids
+ The engine to use for the execution
+ block : boolean
+ If False, this method will return the actual result. If False,
+ a `PendingResult` is returned which can be used to get the result
+ at a later time.
+ """
+ targets, block = self._findTargetsAndBlock(targets, block)
+ result = blockingCallFromThread(self.smultiengine.get_result, i, targets=targets, block=block)
+ if block:
+ result = ResultList(result)
+ else:
+ result = PendingResult(self, result)
+ result.add_callback(wrapResultList)
+ return result
+
+ def reset(self, targets=None, block=None):
+ """
+ Reset an engine.
+
+ This method clears out the namespace of an engine.
+
+ :Parameters:
+ targets : id or list of ids
+ The engine to use for the execution
+ block : boolean
+ If False, this method will return the actual result. If False,
+ a `PendingResult` is returned which can be used to get the result
+ at a later time.
+ """
+ targets, block = self._findTargetsAndBlock(targets, block)
+ return self._blockFromThread(self.smultiengine.reset, targets=targets, block=block)
+
+ def keys(self, targets=None, block=None):
+ """
+ Get a list of all the variables in an engine's namespace.
+
+ :Parameters:
+ targets : id or list of ids
+ The engine to use for the execution
+ block : boolean
+ If False, this method will return the actual result. If False,
+ a `PendingResult` is returned which can be used to get the result
+ at a later time.
+ """
+ targets, block = self._findTargetsAndBlock(targets, block)
+ return self._blockFromThread(self.smultiengine.keys, targets=targets, block=block)
+
+ def kill(self, controller=False, targets=None, block=None):
+ """
+ Kill the engines and controller.
+
+ This method is used to stop the engine and controller by calling
+ `reactor.stop`.
+
+ :Parameters:
+ controller : boolean
+ If True, kill the engines and controller. If False, just the
+ engines
+ targets : id or list of ids
+ The engine to use for the execution
+ block : boolean
+ If False, this method will return the actual result. If False,
+ a `PendingResult` is returned which can be used to get the result
+ at a later time.
+ """
+ targets, block = self._findTargetsAndBlock(targets, block)
+ return self._blockFromThread(self.smultiengine.kill, controller, targets=targets, block=block)
+
+ def clear_queue(self, targets=None, block=None):
+ """
+ Clear out the controller's queue for an engine.
+
+ The controller maintains a queue for each engine. This clear it out.
+
+ :Parameters:
+ targets : id or list of ids
+ The engine to use for the execution
+ block : boolean
+ If False, this method will return the actual result. If False,
+ a `PendingResult` is returned which can be used to get the result
+ at a later time.
+ """
+ targets, block = self._findTargetsAndBlock(targets, block)
+ return self._blockFromThread(self.smultiengine.clear_queue, targets=targets, block=block)
+
+ def queue_status(self, targets=None, block=None):
+ """
+ Get the status of an engines queue.
+
+ :Parameters:
+ targets : id or list of ids
+ The engine to use for the execution
+ block : boolean
+ If False, this method will return the actual result. If False,
+ a `PendingResult` is returned which can be used to get the result
+ at a later time.
+ """
+ targets, block = self._findTargetsAndBlock(targets, block)
+ return self._blockFromThread(self.smultiengine.queue_status, targets=targets, block=block)
+
+ def set_properties(self, properties, targets=None, block=None):
+ warnings.warn(_prop_warn)
+ targets, block = self._findTargetsAndBlock(targets, block)
+ return self._blockFromThread(self.smultiengine.set_properties, properties, targets=targets, block=block)
+
+ def get_properties(self, keys=None, targets=None, block=None):
+ warnings.warn(_prop_warn)
+ targets, block = self._findTargetsAndBlock(targets, block)
+ return self._blockFromThread(self.smultiengine.get_properties, keys, targets=targets, block=block)
+
+ def has_properties(self, keys, targets=None, block=None):
+ warnings.warn(_prop_warn)
+ targets, block = self._findTargetsAndBlock(targets, block)
+ return self._blockFromThread(self.smultiengine.has_properties, keys, targets=targets, block=block)
+
+ def del_properties(self, keys, targets=None, block=None):
+ warnings.warn(_prop_warn)
+ targets, block = self._findTargetsAndBlock(targets, block)
+ return self._blockFromThread(self.smultiengine.del_properties, keys, targets=targets, block=block)
+
+ def clear_properties(self, targets=None, block=None):
+ warnings.warn(_prop_warn)
+ targets, block = self._findTargetsAndBlock(targets, block)
+ return self._blockFromThread(self.smultiengine.clear_properties, targets=targets, block=block)
+
+ #---------------------------------------------------------------------------
+ # IMultiEngine related methods
+ #---------------------------------------------------------------------------
+
+ def get_ids(self):
+ """
+ Returns the ids of currently registered engines.
+ """
+ result = blockingCallFromThread(self.smultiengine.get_ids)
+ return result
+
+ #---------------------------------------------------------------------------
+ # IMultiEngineCoordinator
+ #---------------------------------------------------------------------------
+
+ def scatter(self, key, seq, dist='b', flatten=False, targets=None, block=None):
+ """
+ Partition a Python sequence and send the partitions to a set of engines.
+ """
+ targets, block = self._findTargetsAndBlock(targets, block)
+ return self._blockFromThread(self.smultiengine.scatter, key, seq,
+ dist, flatten, targets=targets, block=block)
+
+ def gather(self, key, dist='b', targets=None, block=None):
+ """
+ Gather a partitioned sequence on a set of engines as a single local seq.
+ """
+ targets, block = self._findTargetsAndBlock(targets, block)
+ return self._blockFromThread(self.smultiengine.gather, key, dist,
+ targets=targets, block=block)
+
+ def raw_map(self, func, seq, dist='b', targets=None, block=None):
+ """
+ A parallelized version of Python's builtin map.
+
+ This has a slightly different syntax than the builtin `map`.
+ This is needed because we need to have keyword arguments and thus
+ can't use *args to capture all the sequences. Instead, they must
+ be passed in a list or tuple.
+
+ raw_map(func, seqs) -> map(func, seqs[0], seqs[1], ...)
+
+ Most users will want to use parallel functions or the `mapper`
+ and `map` methods for an API that follows that of the builtin
+ `map`.
+ """
+ targets, block = self._findTargetsAndBlock(targets, block)
+ return self._blockFromThread(self.smultiengine.raw_map, func, seq,
+ dist, targets=targets, block=block)
+
+ def map(self, func, *sequences):
+ """
+ A parallel version of Python's builtin `map` function.
+
+ This method applies a function to sequences of arguments. It
+ follows the same syntax as the builtin `map`.
+
+ This method creates a mapper objects by calling `self.mapper` with
+ no arguments and then uses that mapper to do the mapping. See
+ the documentation of `mapper` for more details.
+ """
+ return self.mapper().map(func, *sequences)
+
+ def mapper(self, dist='b', targets='all', block=None):
+ """
+ Create a mapper object that has a `map` method.
+
+ This method returns an object that implements the `IMapper`
+ interface. This method is a factory that is used to control how
+ the map happens.
+
+ :Parameters:
+ dist : str
+ What decomposition to use, 'b' is the only one supported
+ currently
+ targets : str, int, sequence of ints
+ Which engines to use for the map
+ block : boolean
+ Should calls to `map` block or not
+ """
+ return MultiEngineMapper(self, dist, targets, block)
+
+ def parallel(self, dist='b', targets=None, block=None):
+ """
+ A decorator that turns a function into a parallel function.
+
+ This can be used as:
+
+ @parallel()
+ def f(x, y)
+ ...
+
+ f(range(10), range(10))
+
+ This causes f(0,0), f(1,1), ... to be called in parallel.
+
+ :Parameters:
+ dist : str
+ What decomposition to use, 'b' is the only one supported
+ currently
+ targets : str, int, sequence of ints
+ Which engines to use for the map
+ block : boolean
+ Should calls to `map` block or not
+ """
+ targets, block = self._findTargetsAndBlock(targets, block)
+ mapper = self.mapper(dist, targets, block)
+ pf = ParallelFunction(mapper)
+ return pf
+
+ #---------------------------------------------------------------------------
+ # IMultiEngineExtras
+ #---------------------------------------------------------------------------
+
+ def zip_pull(self, keys, targets=None, block=None):
+ targets, block = self._findTargetsAndBlock(targets, block)
+ return self._blockFromThread(self.smultiengine.zip_pull, keys,
+ targets=targets, block=block)
+
+ def run(self, filename, targets=None, block=None):
+ """
+ Run a Python code in a file on the engines.
+
+ :Parameters:
+ filename : str
+ The name of the local file to run
+ targets : id or list of ids
+ The engine to use for the execution
+ block : boolean
+ If False, this method will return the actual result. If False,
+ a `PendingResult` is returned which can be used to get the result
+ at a later time.
+ """
+ targets, block = self._findTargetsAndBlock(targets, block)
+ return self._blockFromThread(self.smultiengine.run, filename,
+ targets=targets, block=block)
+
+ def benchmark(self, push_size=10000):
+ """
+ Run performance benchmarks for the current IPython cluster.
+
+ This method tests both the latency of sending command and data to the
+ engines as well as the throughput of sending large objects to the
+ engines using push. The latency is measured by having one or more
+ engines execute the command 'pass'. The throughput is measure by
+ sending an NumPy array of size `push_size` to one or more engines.
+
+ These benchmarks will vary widely on different hardware and networks
+ and thus can be used to get an idea of the performance characteristics
+ of a particular configuration of an IPython controller and engines.
+
+ This function is not testable within our current testing framework.
+ """
+ import timeit, __builtin__
+ __builtin__._mec_self = self
+ benchmarks = {}
+ repeat = 3
+ count = 10
+
+ timer = timeit.Timer('_mec_self.execute("pass",0)')
+ result = 1000*min(timer.repeat(repeat,count))/count
+ benchmarks['single_engine_latency'] = (result,'msec')
+
+ timer = timeit.Timer('_mec_self.execute("pass")')
+ result = 1000*min(timer.repeat(repeat,count))/count
+ benchmarks['all_engine_latency'] = (result,'msec')
+
+ try:
+ import numpy as np
+ except:
+ pass
+ else:
+ timer = timeit.Timer(
+ "_mec_self.push(d)",
+ "import numpy as np; d = dict(a=np.zeros(%r,dtype='float64'))" % push_size
+ )
+ result = min(timer.repeat(repeat,count))/count
+ benchmarks['all_engine_push'] = (1e-6*push_size*8/result, 'MB/sec')
+
+ try:
+ import numpy as np
+ except:
+ pass
+ else:
+ timer = timeit.Timer(
+ "_mec_self.push(d,0)",
+ "import numpy as np; d = dict(a=np.zeros(%r,dtype='float64'))" % push_size
+ )
+ result = min(timer.repeat(repeat,count))/count
+ benchmarks['single_engine_push'] = (1e-6*push_size*8/result, 'MB/sec')
+
+ return benchmarks
+
+
+components.registerAdapter(FullBlockingMultiEngineClient,
+ IFullSynchronousMultiEngine, IFullBlockingMultiEngineClient)
+
+
+
+
diff --git a/IPython/kernel/multienginefc.py b/IPython/kernel/multienginefc.py
new file mode 100644
index 0000000..30de28d
--- /dev/null
+++ b/IPython/kernel/multienginefc.py
@@ -0,0 +1,757 @@
+# encoding: utf-8
+
+"""
+Expose the multiengine controller over the Foolscap network protocol.
+"""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+import cPickle as pickle
+from types import FunctionType
+
+from zope.interface import Interface, implements
+from twisted.internet import defer
+from twisted.python import components, failure, log
+
+from foolscap import Referenceable
+
+from IPython.kernel import error
+from IPython.kernel.util import printer
+from IPython.kernel import map as Map
+from IPython.kernel.parallelfunction import ParallelFunction
+from IPython.kernel.mapper import (
+ MultiEngineMapper,
+ IMultiEngineMapperFactory,
+ IMapper
+)
+from IPython.kernel.twistedutil import gatherBoth
+from IPython.kernel.multiengine import (MultiEngine,
+ IMultiEngine,
+ IFullSynchronousMultiEngine,
+ ISynchronousMultiEngine)
+from IPython.kernel.multiengineclient import wrapResultList
+from IPython.kernel.pendingdeferred import PendingDeferredManager
+from IPython.kernel.pickleutil import (can, canDict,
+ canSequence, uncan, uncanDict, uncanSequence)
+
+from IPython.kernel.clientinterfaces import (
+ IFCClientInterfaceProvider,
+ IBlockingClientAdaptor
+)
+
+# Needed to access the true globals from __main__.__dict__
+import __main__
+
+#-------------------------------------------------------------------------------
+# The Controller side of things
+#-------------------------------------------------------------------------------
+
+def packageResult(wrappedMethod):
+
+ def wrappedPackageResult(self, *args, **kwargs):
+ d = wrappedMethod(self, *args, **kwargs)
+ d.addCallback(self.packageSuccess)
+ d.addErrback(self.packageFailure)
+ return d
+ return wrappedPackageResult
+
+
+class IFCSynchronousMultiEngine(Interface):
+ """Foolscap interface to `ISynchronousMultiEngine`.
+
+ The methods in this interface are similar to those of
+ `ISynchronousMultiEngine`, but their arguments and return values are pickled
+ if they are not already simple Python types that can be send over XML-RPC.
+
+ See the documentation of `ISynchronousMultiEngine` and `IMultiEngine` for
+ documentation about the methods.
+
+ Most methods in this interface act like the `ISynchronousMultiEngine`
+ versions and can be called in blocking or non-blocking mode.
+ """
+ pass
+
+
+class FCSynchronousMultiEngineFromMultiEngine(Referenceable):
+ """Adapt `IMultiEngine` -> `ISynchronousMultiEngine` -> `IFCSynchronousMultiEngine`.
+ """
+
+ implements(IFCSynchronousMultiEngine, IFCClientInterfaceProvider)
+
+ addSlash = True
+
+ def __init__(self, multiengine):
+ # Adapt the raw multiengine to `ISynchronousMultiEngine` before saving
+ # it. This allow this class to do two adaptation steps.
+ self.smultiengine = ISynchronousMultiEngine(multiengine)
+ self._deferredIDCallbacks = {}
+
+ #---------------------------------------------------------------------------
+ # Non interface methods
+ #---------------------------------------------------------------------------
+
+ def packageFailure(self, f):
+ f.cleanFailure()
+ return self.packageSuccess(f)
+
+ def packageSuccess(self, obj):
+ serial = pickle.dumps(obj, 2)
+ return serial
+
+ #---------------------------------------------------------------------------
+ # Things related to PendingDeferredManager
+ #---------------------------------------------------------------------------
+
+ @packageResult
+ def remote_get_pending_deferred(self, deferredID, block):
+ d = self.smultiengine.get_pending_deferred(deferredID, block)
+ try:
+ callback = self._deferredIDCallbacks.pop(deferredID)
+ except KeyError:
+ callback = None
+ if callback is not None:
+ d.addCallback(callback[0], *callback[1], **callback[2])
+ return d
+
+ @packageResult
+ def remote_clear_pending_deferreds(self):
+ return defer.maybeDeferred(self.smultiengine.clear_pending_deferreds)
+
+ def _addDeferredIDCallback(self, did, callback, *args, **kwargs):
+ self._deferredIDCallbacks[did] = (callback, args, kwargs)
+ return did
+
+ #---------------------------------------------------------------------------
+ # IEngineMultiplexer related methods
+ #---------------------------------------------------------------------------
+
+ @packageResult
+ def remote_execute(self, lines, targets, block):
+ return self.smultiengine.execute(lines, targets=targets, block=block)
+
+ @packageResult
+ def remote_push(self, binaryNS, targets, block):
+ try:
+ namespace = pickle.loads(binaryNS)
+ except:
+ d = defer.fail(failure.Failure())
+ else:
+ d = self.smultiengine.push(namespace, targets=targets, block=block)
+ return d
+
+ @packageResult
+ def remote_pull(self, keys, targets, block):
+ d = self.smultiengine.pull(keys, targets=targets, block=block)
+ return d
+
+ @packageResult
+ def remote_push_function(self, binaryNS, targets, block):
+ try:
+ namespace = pickle.loads(binaryNS)
+ except:
+ d = defer.fail(failure.Failure())
+ else:
+ namespace = uncanDict(namespace)
+ d = self.smultiengine.push_function(namespace, targets=targets, block=block)
+ return d
+
+ def _canMultipleKeys(self, result):
+ return [canSequence(r) for r in result]
+
+ @packageResult
+ def remote_pull_function(self, keys, targets, block):
+ def can_functions(r, keys):
+ if len(keys)==1 or isinstance(keys, str):
+ result = canSequence(r)
+ elif len(keys)>1:
+ result = [canSequence(s) for s in r]
+ return result
+ d = self.smultiengine.pull_function(keys, targets=targets, block=block)
+ if block:
+ d.addCallback(can_functions, keys)
+ else:
+ d.addCallback(lambda did: self._addDeferredIDCallback(did, can_functions, keys))
+ return d
+
+ @packageResult
+ def remote_push_serialized(self, binaryNS, targets, block):
+ try:
+ namespace = pickle.loads(binaryNS)
+ except:
+ d = defer.fail(failure.Failure())
+ else:
+ d = self.smultiengine.push_serialized(namespace, targets=targets, block=block)
+ return d
+
+ @packageResult
+ def remote_pull_serialized(self, keys, targets, block):
+ d = self.smultiengine.pull_serialized(keys, targets=targets, block=block)
+ return d
+
+ @packageResult
+ def remote_get_result(self, i, targets, block):
+ if i == 'None':
+ i = None
+ return self.smultiengine.get_result(i, targets=targets, block=block)
+
+ @packageResult
+ def remote_reset(self, targets, block):
+ return self.smultiengine.reset(targets=targets, block=block)
+
+ @packageResult
+ def remote_keys(self, targets, block):
+ return self.smultiengine.keys(targets=targets, block=block)
+
+ @packageResult
+ def remote_kill(self, controller, targets, block):
+ return self.smultiengine.kill(controller, targets=targets, block=block)
+
+ @packageResult
+ def remote_clear_queue(self, targets, block):
+ return self.smultiengine.clear_queue(targets=targets, block=block)
+
+ @packageResult
+ def remote_queue_status(self, targets, block):
+ return self.smultiengine.queue_status(targets=targets, block=block)
+
+ @packageResult
+ def remote_set_properties(self, binaryNS, targets, block):
+ try:
+ ns = pickle.loads(binaryNS)
+ except:
+ d = defer.fail(failure.Failure())
+ else:
+ d = self.smultiengine.set_properties(ns, targets=targets, block=block)
+ return d
+
+ @packageResult
+ def remote_get_properties(self, keys, targets, block):
+ if keys=='None':
+ keys=None
+ return self.smultiengine.get_properties(keys, targets=targets, block=block)
+
+ @packageResult
+ def remote_has_properties(self, keys, targets, block):
+ return self.smultiengine.has_properties(keys, targets=targets, block=block)
+
+ @packageResult
+ def remote_del_properties(self, keys, targets, block):
+ return self.smultiengine.del_properties(keys, targets=targets, block=block)
+
+ @packageResult
+ def remote_clear_properties(self, targets, block):
+ return self.smultiengine.clear_properties(targets=targets, block=block)
+
+ #---------------------------------------------------------------------------
+ # IMultiEngine related methods
+ #---------------------------------------------------------------------------
+
+ def remote_get_ids(self):
+ """Get the ids of the registered engines.
+
+ This method always blocks.
+ """
+ return self.smultiengine.get_ids()
+
+ #---------------------------------------------------------------------------
+ # IFCClientInterfaceProvider related methods
+ #---------------------------------------------------------------------------
+
+ def remote_get_client_name(self):
+ return 'IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient'
+
+
+# The __init__ method of `FCMultiEngineFromMultiEngine` first adapts the
+# `IMultiEngine` to `ISynchronousMultiEngine` so this is actually doing a
+# two phase adaptation.
+components.registerAdapter(FCSynchronousMultiEngineFromMultiEngine,
+ IMultiEngine, IFCSynchronousMultiEngine)
+
+
+#-------------------------------------------------------------------------------
+# The Client side of things
+#-------------------------------------------------------------------------------
+
+
+class FCFullSynchronousMultiEngineClient(object):
+
+ implements(
+ IFullSynchronousMultiEngine,
+ IBlockingClientAdaptor,
+ IMultiEngineMapperFactory,
+ IMapper
+ )
+
+ def __init__(self, remote_reference):
+ self.remote_reference = remote_reference
+ self._deferredIDCallbacks = {}
+ # This class manages some pending deferreds through this instance. This
+ # is required for methods like gather/scatter as it enables us to
+ # create our own pending deferreds for composite operations.
+ self.pdm = PendingDeferredManager()
+
+ #---------------------------------------------------------------------------
+ # Non interface methods
+ #---------------------------------------------------------------------------
+
+ def unpackage(self, r):
+ return pickle.loads(r)
+
+ #---------------------------------------------------------------------------
+ # Things related to PendingDeferredManager
+ #---------------------------------------------------------------------------
+
+ def get_pending_deferred(self, deferredID, block=True):
+
+ # Because we are managing some pending deferreds locally (through
+ # self.pdm) and some remotely (on the controller), we first try the
+ # local one and then the remote one.
+ if self.pdm.quick_has_id(deferredID):
+ d = self.pdm.get_pending_deferred(deferredID, block)
+ return d
+ else:
+ d = self.remote_reference.callRemote('get_pending_deferred', deferredID, block)
+ d.addCallback(self.unpackage)
+ try:
+ callback = self._deferredIDCallbacks.pop(deferredID)
+ except KeyError:
+ callback = None
+ if callback is not None:
+ d.addCallback(callback[0], *callback[1], **callback[2])
+ return d
+
+ def clear_pending_deferreds(self):
+
+ # This clear both the local (self.pdm) and remote pending deferreds
+ self.pdm.clear_pending_deferreds()
+ d2 = self.remote_reference.callRemote('clear_pending_deferreds')
+ d2.addCallback(self.unpackage)
+ return d2
+
+ def _addDeferredIDCallback(self, did, callback, *args, **kwargs):
+ self._deferredIDCallbacks[did] = (callback, args, kwargs)
+ return did
+
+ #---------------------------------------------------------------------------
+ # IEngineMultiplexer related methods
+ #---------------------------------------------------------------------------
+
+ def execute(self, lines, targets='all', block=True):
+ d = self.remote_reference.callRemote('execute', lines, targets, block)
+ d.addCallback(self.unpackage)
+ return d
+
+ def push(self, namespace, targets='all', block=True):
+ serial = pickle.dumps(namespace, 2)
+ d = self.remote_reference.callRemote('push', serial, targets, block)
+ d.addCallback(self.unpackage)
+ return d
+
+ def pull(self, keys, targets='all', block=True):
+ d = self.remote_reference.callRemote('pull', keys, targets, block)
+ d.addCallback(self.unpackage)
+ return d
+
+ def push_function(self, namespace, targets='all', block=True):
+ cannedNamespace = canDict(namespace)
+ serial = pickle.dumps(cannedNamespace, 2)
+ d = self.remote_reference.callRemote('push_function', serial, targets, block)
+ d.addCallback(self.unpackage)
+ return d
+
+ def pull_function(self, keys, targets='all', block=True):
+ def uncan_functions(r, keys):
+ if len(keys)==1 or isinstance(keys, str):
+ return uncanSequence(r)
+ elif len(keys)>1:
+ return [uncanSequence(s) for s in r]
+ d = self.remote_reference.callRemote('pull_function', keys, targets, block)
+ if block:
+ d.addCallback(self.unpackage)
+ d.addCallback(uncan_functions, keys)
+ else:
+ d.addCallback(self.unpackage)
+ d.addCallback(lambda did: self._addDeferredIDCallback(did, uncan_functions, keys))
+ return d
+
+ def push_serialized(self, namespace, targets='all', block=True):
+ cannedNamespace = canDict(namespace)
+ serial = pickle.dumps(cannedNamespace, 2)
+ d = self.remote_reference.callRemote('push_serialized', serial, targets, block)
+ d.addCallback(self.unpackage)
+ return d
+
+ def pull_serialized(self, keys, targets='all', block=True):
+ d = self.remote_reference.callRemote('pull_serialized', keys, targets, block)
+ d.addCallback(self.unpackage)
+ return d
+
+ def get_result(self, i=None, targets='all', block=True):
+ if i is None: # This is because None cannot be marshalled by xml-rpc
+ i = 'None'
+ d = self.remote_reference.callRemote('get_result', i, targets, block)
+ d.addCallback(self.unpackage)
+ return d
+
+ def reset(self, targets='all', block=True):
+ d = self.remote_reference.callRemote('reset', targets, block)
+ d.addCallback(self.unpackage)
+ return d
+
+ def keys(self, targets='all', block=True):
+ d = self.remote_reference.callRemote('keys', targets, block)
+ d.addCallback(self.unpackage)
+ return d
+
+ def kill(self, controller=False, targets='all', block=True):
+ d = self.remote_reference.callRemote('kill', controller, targets, block)
+ d.addCallback(self.unpackage)
+ return d
+
+ def clear_queue(self, targets='all', block=True):
+ d = self.remote_reference.callRemote('clear_queue', targets, block)
+ d.addCallback(self.unpackage)
+ return d
+
+ def queue_status(self, targets='all', block=True):
+ d = self.remote_reference.callRemote('queue_status', targets, block)
+ d.addCallback(self.unpackage)
+ return d
+
+ def set_properties(self, properties, targets='all', block=True):
+ serial = pickle.dumps(properties, 2)
+ d = self.remote_reference.callRemote('set_properties', serial, targets, block)
+ d.addCallback(self.unpackage)
+ return d
+
+ def get_properties(self, keys=None, targets='all', block=True):
+ if keys==None:
+ keys='None'
+ d = self.remote_reference.callRemote('get_properties', keys, targets, block)
+ d.addCallback(self.unpackage)
+ return d
+
+ def has_properties(self, keys, targets='all', block=True):
+ d = self.remote_reference.callRemote('has_properties', keys, targets, block)
+ d.addCallback(self.unpackage)
+ return d
+
+ def del_properties(self, keys, targets='all', block=True):
+ d = self.remote_reference.callRemote('del_properties', keys, targets, block)
+ d.addCallback(self.unpackage)
+ return d
+
+ def clear_properties(self, targets='all', block=True):
+ d = self.remote_reference.callRemote('clear_properties', targets, block)
+ d.addCallback(self.unpackage)
+ return d
+
+ #---------------------------------------------------------------------------
+ # IMultiEngine related methods
+ #---------------------------------------------------------------------------
+
+ def get_ids(self):
+ d = self.remote_reference.callRemote('get_ids')
+ return d
+
+ #---------------------------------------------------------------------------
+ # ISynchronousMultiEngineCoordinator related methods
+ #---------------------------------------------------------------------------
+
+ def _process_targets(self, targets):
+ def create_targets(ids):
+ if isinstance(targets, int):
+ engines = [targets]
+ elif targets=='all':
+ engines = ids
+ elif isinstance(targets, (list, tuple)):
+ engines = targets
+ for t in engines:
+ if not t in ids:
+ raise error.InvalidEngineID("engine with id %r does not exist"%t)
+ return engines
+
+ d = self.get_ids()
+ d.addCallback(create_targets)
+ return d
+
+ def scatter(self, key, seq, dist='b', flatten=False, targets='all', block=True):
+
+ # Note: scatter and gather handle pending deferreds locally through self.pdm.
+ # This enables us to collect a bunch fo deferred ids and make a secondary
+ # deferred id that corresponds to the entire group. This logic is extremely
+ # difficult to get right though.
+ def do_scatter(engines):
+ nEngines = len(engines)
+ mapClass = Map.dists[dist]
+ mapObject = mapClass()
+ d_list = []
+ # Loop through and push to each engine in non-blocking mode.
+ # This returns a set of deferreds to deferred_ids
+ for index, engineid in enumerate(engines):
+ partition = mapObject.getPartition(seq, index, nEngines)
+ if flatten and len(partition) == 1:
+ d = self.push({key: partition[0]}, targets=engineid, block=False)
+ else:
+ d = self.push({key: partition}, targets=engineid, block=False)
+ d_list.append(d)
+ # Collect the deferred to deferred_ids
+ d = gatherBoth(d_list,
+ fireOnOneErrback=0,
+ consumeErrors=1,
+ logErrors=0)
+ # Now d has a list of deferred_ids or Failures coming
+ d.addCallback(error.collect_exceptions, 'scatter')
+ def process_did_list(did_list):
+ """Turn a list of deferred_ids into a final result or failure."""
+ new_d_list = [self.get_pending_deferred(did, True) for did in did_list]
+ final_d = gatherBoth(new_d_list,
+ fireOnOneErrback=0,
+ consumeErrors=1,
+ logErrors=0)
+ final_d.addCallback(error.collect_exceptions, 'scatter')
+ final_d.addCallback(lambda lop: [i[0] for i in lop])
+ return final_d
+ # Now, depending on block, we need to handle the list deferred_ids
+ # coming down the pipe diferently.
+ if block:
+ # If we are blocking register a callback that will transform the
+ # list of deferred_ids into the final result.
+ d.addCallback(process_did_list)
+ return d
+ else:
+ # Here we are going to use a _local_ PendingDeferredManager.
+ deferred_id = self.pdm.get_deferred_id()
+ # This is the deferred we will return to the user that will fire
+ # with the local deferred_id AFTER we have received the list of
+ # primary deferred_ids
+ d_to_return = defer.Deferred()
+ def do_it(did_list):
+ """Produce a deferred to the final result, but first fire the
+ deferred we will return to the user that has the local
+ deferred id."""
+ d_to_return.callback(deferred_id)
+ return process_did_list(did_list)
+ d.addCallback(do_it)
+ # Now save the deferred to the final result
+ self.pdm.save_pending_deferred(d, deferred_id)
+ return d_to_return
+
+ d = self._process_targets(targets)
+ d.addCallback(do_scatter)
+ return d
+
+ def gather(self, key, dist='b', targets='all', block=True):
+
+ # Note: scatter and gather handle pending deferreds locally through self.pdm.
+ # This enables us to collect a bunch fo deferred ids and make a secondary
+ # deferred id that corresponds to the entire group. This logic is extremely
+ # difficult to get right though.
+ def do_gather(engines):
+ nEngines = len(engines)
+ mapClass = Map.dists[dist]
+ mapObject = mapClass()
+ d_list = []
+ # Loop through and push to each engine in non-blocking mode.
+ # This returns a set of deferreds to deferred_ids
+ for index, engineid in enumerate(engines):
+ d = self.pull(key, targets=engineid, block=False)
+ d_list.append(d)
+ # Collect the deferred to deferred_ids
+ d = gatherBoth(d_list,
+ fireOnOneErrback=0,
+ consumeErrors=1,
+ logErrors=0)
+ # Now d has a list of deferred_ids or Failures coming
+ d.addCallback(error.collect_exceptions, 'scatter')
+ def process_did_list(did_list):
+ """Turn a list of deferred_ids into a final result or failure."""
+ new_d_list = [self.get_pending_deferred(did, True) for did in did_list]
+ final_d = gatherBoth(new_d_list,
+ fireOnOneErrback=0,
+ consumeErrors=1,
+ logErrors=0)
+ final_d.addCallback(error.collect_exceptions, 'gather')
+ final_d.addCallback(lambda lop: [i[0] for i in lop])
+ final_d.addCallback(mapObject.joinPartitions)
+ return final_d
+ # Now, depending on block, we need to handle the list deferred_ids
+ # coming down the pipe diferently.
+ if block:
+ # If we are blocking register a callback that will transform the
+ # list of deferred_ids into the final result.
+ d.addCallback(process_did_list)
+ return d
+ else:
+ # Here we are going to use a _local_ PendingDeferredManager.
+ deferred_id = self.pdm.get_deferred_id()
+ # This is the deferred we will return to the user that will fire
+ # with the local deferred_id AFTER we have received the list of
+ # primary deferred_ids
+ d_to_return = defer.Deferred()
+ def do_it(did_list):
+ """Produce a deferred to the final result, but first fire the
+ deferred we will return to the user that has the local
+ deferred id."""
+ d_to_return.callback(deferred_id)
+ return process_did_list(did_list)
+ d.addCallback(do_it)
+ # Now save the deferred to the final result
+ self.pdm.save_pending_deferred(d, deferred_id)
+ return d_to_return
+
+ d = self._process_targets(targets)
+ d.addCallback(do_gather)
+ return d
+
+ def raw_map(self, func, sequences, dist='b', targets='all', block=True):
+ """
+ A parallelized version of Python's builtin map.
+
+ This has a slightly different syntax than the builtin `map`.
+ This is needed because we need to have keyword arguments and thus
+ can't use *args to capture all the sequences. Instead, they must
+ be passed in a list or tuple.
+
+ raw_map(func, seqs) -> map(func, seqs[0], seqs[1], ...)
+
+ Most users will want to use parallel functions or the `mapper`
+ and `map` methods for an API that follows that of the builtin
+ `map`.
+ """
+ if not isinstance(sequences, (list, tuple)):
+ raise TypeError('sequences must be a list or tuple')
+ max_len = max(len(s) for s in sequences)
+ for s in sequences:
+ if len(s)!=max_len:
+ raise ValueError('all sequences must have equal length')
+ if isinstance(func, FunctionType):
+ d = self.push_function(dict(_ipython_map_func=func), targets=targets, block=False)
+ d.addCallback(lambda did: self.get_pending_deferred(did, True))
+ sourceToRun = '_ipython_map_seq_result = map(_ipython_map_func, *zip(*_ipython_map_seq))'
+ elif isinstance(func, str):
+ d = defer.succeed(None)
+ sourceToRun = \
+ '_ipython_map_seq_result = map(%s, *zip(*_ipython_map_seq))' % func
+ else:
+ raise TypeError("func must be a function or str")
+
+ d.addCallback(lambda _: self.scatter('_ipython_map_seq', zip(*sequences), dist, targets=targets))
+ d.addCallback(lambda _: self.execute(sourceToRun, targets=targets, block=False))
+ d.addCallback(lambda did: self.get_pending_deferred(did, True))
+ d.addCallback(lambda _: self.gather('_ipython_map_seq_result', dist, targets=targets, block=block))
+ return d
+
+ def map(self, func, *sequences):
+ """
+ A parallel version of Python's builtin `map` function.
+
+ This method applies a function to sequences of arguments. It
+ follows the same syntax as the builtin `map`.
+
+ This method creates a mapper objects by calling `self.mapper` with
+ no arguments and then uses that mapper to do the mapping. See
+ the documentation of `mapper` for more details.
+ """
+ return self.mapper().map(func, *sequences)
+
+ def mapper(self, dist='b', targets='all', block=True):
+ """
+ Create a mapper object that has a `map` method.
+
+ This method returns an object that implements the `IMapper`
+ interface. This method is a factory that is used to control how
+ the map happens.
+
+ :Parameters:
+ dist : str
+ What decomposition to use, 'b' is the only one supported
+ currently
+ targets : str, int, sequence of ints
+ Which engines to use for the map
+ block : boolean
+ Should calls to `map` block or not
+ """
+ return MultiEngineMapper(self, dist, targets, block)
+
+ def parallel(self, dist='b', targets='all', block=True):
+ """
+ A decorator that turns a function into a parallel function.
+
+ This can be used as:
+
+ @parallel()
+ def f(x, y)
+ ...
+
+ f(range(10), range(10))
+
+ This causes f(0,0), f(1,1), ... to be called in parallel.
+
+ :Parameters:
+ dist : str
+ What decomposition to use, 'b' is the only one supported
+ currently
+ targets : str, int, sequence of ints
+ Which engines to use for the map
+ block : boolean
+ Should calls to `map` block or not
+ """
+ mapper = self.mapper(dist, targets, block)
+ pf = ParallelFunction(mapper)
+ return pf
+
+ #---------------------------------------------------------------------------
+ # ISynchronousMultiEngineExtras related methods
+ #---------------------------------------------------------------------------
+
+ def _transformPullResult(self, pushResult, multitargets, lenKeys):
+ if not multitargets:
+ result = pushResult[0]
+ elif lenKeys > 1:
+ result = zip(*pushResult)
+ elif lenKeys is 1:
+ result = list(pushResult)
+ return result
+
+ def zip_pull(self, keys, targets='all', block=True):
+ multitargets = not isinstance(targets, int) and len(targets) > 1
+ lenKeys = len(keys)
+ d = self.pull(keys, targets=targets, block=block)
+ if block:
+ d.addCallback(self._transformPullResult, multitargets, lenKeys)
+ else:
+ d.addCallback(lambda did: self._addDeferredIDCallback(did, self._transformPullResult, multitargets, lenKeys))
+ return d
+
+ def run(self, fname, targets='all', block=True):
+ fileobj = open(fname,'r')
+ source = fileobj.read()
+ fileobj.close()
+ # if the compilation blows, we get a local error right away
+ try:
+ code = compile(source,fname,'exec')
+ except:
+ return defer.fail(failure.Failure())
+ # Now run the code
+ d = self.execute(source, targets=targets, block=block)
+ return d
+
+ #---------------------------------------------------------------------------
+ # IBlockingClientAdaptor related methods
+ #---------------------------------------------------------------------------
+
+ def adapt_to_blocking_client(self):
+ from IPython.kernel.multiengineclient import IFullBlockingMultiEngineClient
+ return IFullBlockingMultiEngineClient(self)
diff --git a/IPython/kernel/newserialized.py b/IPython/kernel/newserialized.py
new file mode 100644
index 0000000..155ed0c
--- /dev/null
+++ b/IPython/kernel/newserialized.py
@@ -0,0 +1,170 @@
+# encoding: utf-8
+# -*- test-case-name: IPython.kernel.test.test_newserialized -*-
+
+"""Refactored serialization classes and interfaces."""
+
+__docformat__ = "restructuredtext en"
+
+# Tell nose to skip this module
+__test__ = {}
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+import cPickle as pickle
+
+from twisted.python import components
+from zope.interface import Interface, implements
+
+try:
+ import numpy
+except ImportError:
+ pass
+
+from IPython.kernel.error import SerializationError
+
+#-----------------------------------------------------------------------------
+# Classes and functions
+#-----------------------------------------------------------------------------
+
+class ISerialized(Interface):
+
+ def getData():
+ """"""
+
+ def getDataSize(units=10.0**6):
+ """"""
+
+ def getTypeDescriptor():
+ """"""
+
+ def getMetadata():
+ """"""
+
+
+class IUnSerialized(Interface):
+
+ def getObject():
+ """"""
+
+class Serialized(object):
+
+ implements(ISerialized)
+
+ def __init__(self, data, typeDescriptor, metadata={}):
+ self.data = data
+ self.typeDescriptor = typeDescriptor
+ self.metadata = metadata
+
+ def getData(self):
+ return self.data
+
+ def getDataSize(self, units=10.0**6):
+ return len(self.data)/units
+
+ def getTypeDescriptor(self):
+ return self.typeDescriptor
+
+ def getMetadata(self):
+ return self.metadata
+
+
+class UnSerialized(object):
+
+ implements(IUnSerialized)
+
+ def __init__(self, obj):
+ self.obj = obj
+
+ def getObject(self):
+ return self.obj
+
+
+class SerializeIt(object):
+
+ implements(ISerialized)
+
+ def __init__(self, unSerialized):
+ self.data = None
+ self.obj = unSerialized.getObject()
+ if globals().has_key('numpy'):
+ if isinstance(self.obj, numpy.ndarray):
+ if len(self.obj) == 0: # length 0 arrays can't be reconstructed
+ raise SerializationError("You cannot send a length 0 array")
+ self.obj = numpy.ascontiguousarray(self.obj, dtype=None)
+ self.typeDescriptor = 'ndarray'
+ self.metadata = {'shape':self.obj.shape,
+ 'dtype':self.obj.dtype.str}
+ else:
+ self.typeDescriptor = 'pickle'
+ self.metadata = {}
+ else:
+ self.typeDescriptor = 'pickle'
+ self.metadata = {}
+ self._generateData()
+
+ def _generateData(self):
+ if self.typeDescriptor == 'ndarray':
+ self.data = numpy.getbuffer(self.obj)
+ elif self.typeDescriptor == 'pickle':
+ self.data = pickle.dumps(self.obj, 2)
+ else:
+ raise SerializationError("Really wierd serialization error.")
+ del self.obj
+
+ def getData(self):
+ return self.data
+
+ def getDataSize(self, units=10.0**6):
+ return len(self.data)/units
+
+ def getTypeDescriptor(self):
+ return self.typeDescriptor
+
+ def getMetadata(self):
+ return self.metadata
+
+
+class UnSerializeIt(UnSerialized):
+
+ implements(IUnSerialized)
+
+ def __init__(self, serialized):
+ self.serialized = serialized
+
+ def getObject(self):
+ typeDescriptor = self.serialized.getTypeDescriptor()
+ if globals().has_key('numpy'):
+ if typeDescriptor == 'ndarray':
+ result = numpy.frombuffer(self.serialized.getData(), dtype = self.serialized.metadata['dtype'])
+ result.shape = self.serialized.metadata['shape']
+ # This is a hack to make the array writable. We are working with
+ # the numpy folks to address this issue.
+ result = result.copy()
+ elif typeDescriptor == 'pickle':
+ result = pickle.loads(self.serialized.getData())
+ else:
+ raise SerializationError("Really wierd serialization error.")
+ elif typeDescriptor == 'pickle':
+ result = pickle.loads(self.serialized.getData())
+ else:
+ raise SerializationError("Really wierd serialization error.")
+ return result
+
+components.registerAdapter(UnSerializeIt, ISerialized, IUnSerialized)
+
+components.registerAdapter(SerializeIt, IUnSerialized, ISerialized)
+
+def serialize(obj):
+ return ISerialized(UnSerialized(obj))
+
+def unserialize(serialized):
+ return IUnSerialized(serialized).getObject()
diff --git a/IPython/kernel/parallelfunction.py b/IPython/kernel/parallelfunction.py
new file mode 100644
index 0000000..077081a
--- /dev/null
+++ b/IPython/kernel/parallelfunction.py
@@ -0,0 +1,107 @@
+# encoding: utf-8
+
+"""A parallelized function that does scatter/execute/gather."""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+from types import FunctionType
+from zope.interface import Interface, implements
+
+
+class IMultiEngineParallelDecorator(Interface):
+ """A decorator that creates a parallel function."""
+
+ def parallel(dist='b', targets=None, block=None):
+ """
+ A decorator that turns a function into a parallel function.
+
+ This can be used as:
+
+ @parallel()
+ def f(x, y)
+ ...
+
+ f(range(10), range(10))
+
+ This causes f(0,0), f(1,1), ... to be called in parallel.
+
+ :Parameters:
+ dist : str
+ What decomposition to use, 'b' is the only one supported
+ currently
+ targets : str, int, sequence of ints
+ Which engines to use for the map
+ block : boolean
+ Should calls to `map` block or not
+ """
+
+class ITaskParallelDecorator(Interface):
+ """A decorator that creates a parallel function."""
+
+ def parallel(clear_before=False, clear_after=False, retries=0,
+ recovery_task=None, depend=None, block=True):
+ """
+ A decorator that turns a function into a parallel function.
+
+ This can be used as:
+
+ @parallel()
+ def f(x, y)
+ ...
+
+ f(range(10), range(10))
+
+ This causes f(0,0), f(1,1), ... to be called in parallel.
+
+ See the documentation for `IPython.kernel.task.BaseTask` for
+ documentation on the arguments to this method.
+ """
+
+class IParallelFunction(Interface):
+ pass
+
+class ParallelFunction(object):
+ """
+ The implementation of a parallel function.
+
+ A parallel function is similar to Python's map function:
+
+ map(func, *sequences) -> pfunc(*sequences)
+
+ Parallel functions should be created by using the @parallel decorator.
+ """
+
+ implements(IParallelFunction)
+
+ def __init__(self, mapper):
+ """
+ Create a parallel function from an `IMapper`.
+
+ :Parameters:
+ mapper : an `IMapper` implementer.
+ The mapper to use for the parallel function
+ """
+ self.mapper = mapper
+
+ def __call__(self, func):
+ """
+ Decorate a function to make it run in parallel.
+ """
+ assert isinstance(func, (str, FunctionType)), "func must be a fuction or str"
+ self.func = func
+ def call_function(*sequences):
+ return self.mapper.map(self.func, *sequences)
+ return call_function
+
+ \ No newline at end of file
diff --git a/IPython/kernel/pbconfig.py b/IPython/kernel/pbconfig.py
new file mode 100644
index 0000000..5fb5e4d
--- /dev/null
+++ b/IPython/kernel/pbconfig.py
@@ -0,0 +1,34 @@
+# encoding: utf-8
+
+"""Low level configuration for Twisted's Perspective Broker protocol."""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+from twisted.spread import banana
+
+
+#-------------------------------------------------------------------------------
+# This is where you configure the size limit of the banana protocol that
+# PB uses. WARNING, this only works if you are NOT using cBanana, which is
+# faster than banana.py.
+#-------------------------------------------------------------------------------
+
+
+
+#banana.SIZE_LIMIT = 640*1024 # The default of 640 kB
+banana.SIZE_LIMIT = 10*1024*1024 # 10 MB
+#banana.SIZE_LIMIT = 50*1024*1024 # 50 MB
+
+# This sets the size of chunks used when paging is used.
+CHUNK_SIZE = 64*1024
diff --git a/IPython/kernel/pbutil.py b/IPython/kernel/pbutil.py
new file mode 100644
index 0000000..6ce8050
--- /dev/null
+++ b/IPython/kernel/pbutil.py
@@ -0,0 +1,93 @@
+# encoding: utf-8
+
+"""Utilities for PB using modules."""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+import cPickle as pickle
+
+from twisted.python.failure import Failure
+from twisted.python import failure
+import threading, sys
+
+from IPython.kernel import pbconfig
+from IPython.kernel.error import PBMessageSizeError, UnpickleableException
+
+
+#-------------------------------------------------------------------------------
+# The actual utilities
+#-------------------------------------------------------------------------------
+
+def packageFailure(f):
+ """Clean and pickle a failure preappending the string FAILURE:"""
+
+ f.cleanFailure()
+ # This is sometimes helpful in debugging
+ #f.raiseException()
+ try:
+ pString = pickle.dumps(f, 2)
+ except pickle.PicklingError:
+ # Certain types of exceptions are not pickleable, for instance ones
+ # from Boost.Python. We try to wrap them in something that is
+ f.type = UnpickleableException
+ f.value = UnpickleableException(str(f.type) + ": " + str(f.value))
+ pString = pickle.dumps(f, 2)
+ return 'FAILURE:' + pString
+
+def unpackageFailure(r):
+ """
+ See if a returned value is a pickled Failure object.
+
+ To distinguish between general pickled objects and pickled Failures, the
+ other side should prepend the string FAILURE: to any pickled Failure.
+ """
+ if isinstance(r, str):
+ if r.startswith('FAILURE:'):
+ try:
+ result = pickle.loads(r[8:])
+ except pickle.PickleError:
+ return failure.Failure( \
+ FailureUnpickleable("Could not unpickle failure."))
+ else:
+ return result
+ return r
+
+def checkMessageSize(m, info):
+ """Check string m to see if it violates banana.SIZE_LIMIT.
+
+ This should be used on the client side of things for push, scatter
+ and push_serialized and on the other end for pull, gather and pull_serialized.
+
+ :Parameters:
+ `m` : string
+ Message whose size will be checked.
+ `info` : string
+ String describing what object the message refers to.
+
+ :Exceptions:
+ - `PBMessageSizeError`: Raised in the message is > banana.SIZE_LIMIT
+
+ :returns: The original message or a Failure wrapping a PBMessageSizeError
+ """
+
+ if len(m) > pbconfig.banana.SIZE_LIMIT:
+ s = """Objects too big to transfer:
+Names: %s
+Actual Size (kB): %d
+SIZE_LIMIT (kB): %d
+* SIZE_LIMIT can be set in kernel.pbconfig""" \
+ % (info, len(m)/1024, pbconfig.banana.SIZE_LIMIT/1024)
+ return Failure(PBMessageSizeError(s))
+ else:
+ return m \ No newline at end of file
diff --git a/IPython/kernel/pendingdeferred.py b/IPython/kernel/pendingdeferred.py
new file mode 100644
index 0000000..40c890b
--- /dev/null
+++ b/IPython/kernel/pendingdeferred.py
@@ -0,0 +1,178 @@
+# encoding: utf-8
+# -*- test-case-name: IPython.kernel.test.test_pendingdeferred -*-
+
+"""Classes to manage pending Deferreds.
+
+A pending deferred is a deferred that may or may not have fired. This module
+is useful for taking a class whose methods return deferreds and wrapping it to
+provide API that keeps track of those deferreds for later retrieval. See the
+tests for examples of its usage.
+"""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+from twisted.application import service
+from twisted.internet import defer, reactor
+from twisted.python import log, components, failure
+from zope.interface import Interface, implements, Attribute
+
+from IPython.kernel.twistedutil import gatherBoth
+from IPython.kernel import error
+from IPython.external import guid
+from IPython.tools import growl
+
+class PendingDeferredManager(object):
+ """A class to track pending deferreds.
+
+ To track a pending deferred, the user of this class must first
+ get a deferredID by calling `get_next_deferred_id`. Then the user
+ calls `save_pending_deferred` passing that id and the deferred to
+ be tracked. To later retrieve it, the user calls
+ `get_pending_deferred` passing the id.
+ """
+
+ def __init__(self):
+ """Manage pending deferreds."""
+
+ self.results = {} # Populated when results are ready
+ self.deferred_ids = [] # List of deferred ids I am managing
+ self.deferreds_to_callback = {} # dict of lists of deferreds to callback
+
+ def get_deferred_id(self):
+ return guid.generate()
+
+ def quick_has_id(self, deferred_id):
+ return deferred_id in self.deferred_ids
+
+ def _save_result(self, result, deferred_id):
+ if self.quick_has_id(deferred_id):
+ self.results[deferred_id] = result
+ self._trigger_callbacks(deferred_id)
+
+ def _trigger_callbacks(self, deferred_id):
+ # Go through and call the waiting callbacks
+ result = self.results.get(deferred_id)
+ if result is not None: # Only trigger if there is a result
+ try:
+ d = self.deferreds_to_callback.pop(deferred_id)
+ except KeyError:
+ d = None
+ if d is not None:
+ if isinstance(result, failure.Failure):
+ d.errback(result)
+ else:
+ d.callback(result)
+ self.delete_pending_deferred(deferred_id)
+
+ def save_pending_deferred(self, d, deferred_id=None):
+ """Save the result of a deferred for later retrieval.
+
+ This works even if the deferred has not fired.
+
+ Only callbacks and errbacks applied to d before this method
+ is called will be called no the final result.
+ """
+ if deferred_id is None:
+ deferred_id = self.get_deferred_id()
+ self.deferred_ids.append(deferred_id)
+ d.addBoth(self._save_result, deferred_id)
+ return deferred_id
+
+ def _protected_del(self, key, container):
+ try:
+ del container[key]
+ except Exception:
+ pass
+
+ def delete_pending_deferred(self, deferred_id):
+ """Remove a deferred I am tracking and add a null Errback.
+
+ :Parameters:
+ deferredID : str
+ The id of a deferred that I am tracking.
+ """
+ if self.quick_has_id(deferred_id):
+ # First go through a errback any deferreds that are still waiting
+ d = self.deferreds_to_callback.get(deferred_id)
+ if d is not None:
+ d.errback(failure.Failure(error.AbortedPendingDeferredError("pending deferred has been deleted: %r"%deferred_id)))
+ # Now delete all references to this deferred_id
+ ind = self.deferred_ids.index(deferred_id)
+ self._protected_del(ind, self.deferred_ids)
+ self._protected_del(deferred_id, self.deferreds_to_callback)
+ self._protected_del(deferred_id, self.results)
+ else:
+ raise error.InvalidDeferredID('invalid deferred_id: %r' % deferred_id)
+
+ def clear_pending_deferreds(self):
+ """Remove all the deferreds I am tracking."""
+ for did in self.deferred_ids:
+ self.delete_pending_deferred(did)
+
+ def _delete_and_pass_through(self, r, deferred_id):
+ self.delete_pending_deferred(deferred_id)
+ return r
+
+ def get_pending_deferred(self, deferred_id, block):
+ if not self.quick_has_id(deferred_id) or self.deferreds_to_callback.get(deferred_id) is not None:
+ return defer.fail(failure.Failure(error.InvalidDeferredID('invalid deferred_id: %r' + deferred_id)))
+ result = self.results.get(deferred_id)
+ if result is not None:
+ self.delete_pending_deferred(deferred_id)
+ if isinstance(result, failure.Failure):
+ return defer.fail(result)
+ else:
+ return defer.succeed(result)
+ else: # Result is not ready
+ if block:
+ d = defer.Deferred()
+ self.deferreds_to_callback[deferred_id] = d
+ return d
+ else:
+ return defer.fail(failure.Failure(error.ResultNotCompleted("result not completed: %r" % deferred_id)))
+
+def two_phase(wrapped_method):
+ """Wrap methods that return a deferred into a two phase process.
+
+ This transforms::
+
+ foo(arg1, arg2, ...) -> foo(arg1, arg2,...,block=True).
+
+ The wrapped method will then return a deferred to a deferred id. This will
+ only work on method of classes that inherit from `PendingDeferredManager`,
+ as that class provides an API for
+
+ block is a boolean to determine if we should use the two phase process or
+ just simply call the wrapped method. At this point block does not have a
+ default and it probably won't.
+ """
+
+ def wrapper_two_phase(pdm, *args, **kwargs):
+ try:
+ block = kwargs.pop('block')
+ except KeyError:
+ block = True # The default if not specified
+ if block:
+ return wrapped_method(pdm, *args, **kwargs)
+ else:
+ d = wrapped_method(pdm, *args, **kwargs)
+ deferred_id=pdm.save_pending_deferred(d)
+ return defer.succeed(deferred_id)
+
+ return wrapper_two_phase
+
+
+
+
+
diff --git a/IPython/kernel/pickleutil.py b/IPython/kernel/pickleutil.py
new file mode 100644
index 0000000..087a61c
--- /dev/null
+++ b/IPython/kernel/pickleutil.py
@@ -0,0 +1,83 @@
+# encoding: utf-8
+
+"""Pickle related utilities."""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+from types import FunctionType
+from twisted.python import log
+
+class CannedObject(object):
+ pass
+
+class CannedFunction(CannedObject):
+
+ def __init__(self, f):
+ self._checkType(f)
+ self.code = f.func_code
+
+ def _checkType(self, obj):
+ assert isinstance(obj, FunctionType), "Not a function type"
+
+ def getFunction(self, g=None):
+ if g is None:
+ g = globals()
+ newFunc = FunctionType(self.code, g)
+ return newFunc
+
+def can(obj):
+ if isinstance(obj, FunctionType):
+ return CannedFunction(obj)
+ else:
+ return obj
+
+def canDict(obj):
+ if isinstance(obj, dict):
+ for k, v in obj.iteritems():
+ obj[k] = can(v)
+ return obj
+ else:
+ return obj
+
+def canSequence(obj):
+ if isinstance(obj, (list, tuple)):
+ t = type(obj)
+ return t([can(i) for i in obj])
+ else:
+ return obj
+
+def uncan(obj, g=None):
+ if isinstance(obj, CannedFunction):
+ return obj.getFunction(g)
+ else:
+ return obj
+
+def uncanDict(obj, g=None):
+ if isinstance(obj, dict):
+ for k, v in obj.iteritems():
+ obj[k] = uncan(v,g)
+ return obj
+ else:
+ return obj
+
+def uncanSequence(obj, g=None):
+ if isinstance(obj, (list, tuple)):
+ t = type(obj)
+ return t([uncan(i,g) for i in obj])
+ else:
+ return obj
+
+
+def rebindFunctionGlobals(f, glbls):
+ return FunctionType(f.func_code, glbls)
diff --git a/IPython/kernel/scripts/__init__.py b/IPython/kernel/scripts/__init__.py
new file mode 100644
index 0000000..4e77672
--- /dev/null
+++ b/IPython/kernel/scripts/__init__.py
@@ -0,0 +1,16 @@
+# encoding: utf-8
+
+""""""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#------------------------------------------------------------------------------- \ No newline at end of file
diff --git a/IPython/kernel/scripts/ipcluster b/IPython/kernel/scripts/ipcluster
new file mode 100755
index 0000000..362a725
--- /dev/null
+++ b/IPython/kernel/scripts/ipcluster
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+# encoding: utf-8
+
+"""ipcluster script"""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+if __name__ == '__main__':
+ from IPython.kernel.scripts import ipcluster
+ ipcluster.main()
+
diff --git a/IPython/kernel/scripts/ipcluster.py b/IPython/kernel/scripts/ipcluster.py
new file mode 100644
index 0000000..34b2d61
--- /dev/null
+++ b/IPython/kernel/scripts/ipcluster.py
@@ -0,0 +1,813 @@
+ #!/usr/bin/env python
+# encoding: utf-8
+
+"""Start an IPython cluster = (controller + engines)."""
+
+#-----------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+import os
+import re
+import sys
+import signal
+import tempfile
+pjoin = os.path.join
+
+from twisted.internet import reactor, defer
+from twisted.internet.protocol import ProcessProtocol
+from twisted.internet.error import ProcessDone, ProcessTerminated
+from twisted.internet.utils import getProcessOutput
+from twisted.python import failure, log
+
+from IPython.external import argparse
+from IPython.external import Itpl
+from IPython.genutils import (
+ get_ipython_dir,
+ get_log_dir,
+ get_security_dir,
+ num_cpus
+)
+from IPython.kernel.fcutil import have_crypto
+
+# Create various ipython directories if they don't exist.
+# This must be done before IPython.kernel.config is imported.
+from IPython.iplib import user_setup
+if os.name == 'posix':
+ rc_suffix = ''
+else:
+ rc_suffix = '.ini'
+user_setup(get_ipython_dir(), rc_suffix, mode='install', interactive=False)
+get_log_dir()
+get_security_dir()
+
+from IPython.kernel.config import config_manager as kernel_config_manager
+from IPython.kernel.error import SecurityError, FileTimeoutError
+from IPython.kernel.fcutil import have_crypto
+from IPython.kernel.twistedutil import gatherBoth, wait_for_file
+from IPython.kernel.util import printer
+
+#-----------------------------------------------------------------------------
+# General process handling code
+#-----------------------------------------------------------------------------
+
+
+class ProcessStateError(Exception):
+ pass
+
+class UnknownStatus(Exception):
+ pass
+
+class LauncherProcessProtocol(ProcessProtocol):
+ """
+ A ProcessProtocol to go with the ProcessLauncher.
+ """
+ def __init__(self, process_launcher):
+ self.process_launcher = process_launcher
+
+ def connectionMade(self):
+ self.process_launcher.fire_start_deferred(self.transport.pid)
+
+ def processEnded(self, status):
+ value = status.value
+ if isinstance(value, ProcessDone):
+ self.process_launcher.fire_stop_deferred(0)
+ elif isinstance(value, ProcessTerminated):
+ self.process_launcher.fire_stop_deferred(
+ {'exit_code':value.exitCode,
+ 'signal':value.signal,
+ 'status':value.status
+ }
+ )
+ else:
+ raise UnknownStatus("unknown exit status, this is probably a bug in Twisted")
+
+ def outReceived(self, data):
+ log.msg(data)
+
+ def errReceived(self, data):
+ log.err(data)
+
+class ProcessLauncher(object):
+ """
+ Start and stop an external process in an asynchronous manner.
+
+ Currently this uses deferreds to notify other parties of process state
+ changes. This is an awkward design and should be moved to using
+ a formal NotificationCenter.
+ """
+ def __init__(self, cmd_and_args):
+ self.cmd = cmd_and_args[0]
+ self.args = cmd_and_args
+ self._reset()
+
+ def _reset(self):
+ self.process_protocol = None
+ self.pid = None
+ self.start_deferred = None
+ self.stop_deferreds = []
+ self.state = 'before' # before, running, or after
+
+ @property
+ def running(self):
+ if self.state == 'running':
+ return True
+ else:
+ return False
+
+ def fire_start_deferred(self, pid):
+ self.pid = pid
+ self.state = 'running'
+ log.msg('Process %r has started with pid=%i' % (self.args, pid))
+ self.start_deferred.callback(pid)
+
+ def start(self):
+ if self.state == 'before':
+ self.process_protocol = LauncherProcessProtocol(self)
+ self.start_deferred = defer.Deferred()
+ self.process_transport = reactor.spawnProcess(
+ self.process_protocol,
+ self.cmd,
+ self.args,
+ env=os.environ
+ )
+ return self.start_deferred
+ else:
+ s = 'the process has already been started and has state: %r' % \
+ self.state
+ return defer.fail(ProcessStateError(s))
+
+ def get_stop_deferred(self):
+ if self.state == 'running' or self.state == 'before':
+ d = defer.Deferred()
+ self.stop_deferreds.append(d)
+ return d
+ else:
+ s = 'this process is already complete'
+ return defer.fail(ProcessStateError(s))
+
+ def fire_stop_deferred(self, exit_code):
+ log.msg('Process %r has stopped with %r' % (self.args, exit_code))
+ self.state = 'after'
+ for d in self.stop_deferreds:
+ d.callback(exit_code)
+
+ def signal(self, sig):
+ """
+ Send a signal to the process.
+
+ The argument sig can be ('KILL','INT', etc.) or any signal number.
+ """
+ if self.state == 'running':
+ self.process_transport.signalProcess(sig)
+
+ # def __del__(self):
+ # self.signal('KILL')
+
+ def interrupt_then_kill(self, delay=1.0):
+ self.signal('INT')
+ reactor.callLater(delay, self.signal, 'KILL')
+
+
+#-----------------------------------------------------------------------------
+# Code for launching controller and engines
+#-----------------------------------------------------------------------------
+
+
+class ControllerLauncher(ProcessLauncher):
+
+ def __init__(self, extra_args=None):
+ if sys.platform == 'win32':
+ # This logic is needed because the ipcontroller script doesn't
+ # always get installed in the same way or in the same location.
+ from IPython.kernel.scripts import ipcontroller
+ script_location = ipcontroller.__file__.replace('.pyc', '.py')
+ # The -u option here turns on unbuffered output, which is required
+ # on Win32 to prevent wierd conflict and problems with Twisted.
+ # Also, use sys.executable to make sure we are picking up the
+ # right python exe.
+ args = [sys.executable, '-u', script_location]
+ else:
+ args = ['ipcontroller']
+ self.extra_args = extra_args
+ if extra_args is not None:
+ args.extend(extra_args)
+
+ ProcessLauncher.__init__(self, args)
+
+
+class EngineLauncher(ProcessLauncher):
+
+ def __init__(self, extra_args=None):
+ if sys.platform == 'win32':
+ # This logic is needed because the ipcontroller script doesn't
+ # always get installed in the same way or in the same location.
+ from IPython.kernel.scripts import ipengine
+ script_location = ipengine.__file__.replace('.pyc', '.py')
+ # The -u option here turns on unbuffered output, which is required
+ # on Win32 to prevent wierd conflict and problems with Twisted.
+ # Also, use sys.executable to make sure we are picking up the
+ # right python exe.
+ args = [sys.executable, '-u', script_location]
+ else:
+ args = ['ipengine']
+ self.extra_args = extra_args
+ if extra_args is not None:
+ args.extend(extra_args)
+
+ ProcessLauncher.__init__(self, args)
+
+
+class LocalEngineSet(object):
+
+ def __init__(self, extra_args=None):
+ self.extra_args = extra_args
+ self.launchers = []
+
+ def start(self, n):
+ dlist = []
+ for i in range(n):
+ el = EngineLauncher(extra_args=self.extra_args)
+ d = el.start()
+ self.launchers.append(el)
+ dlist.append(d)
+ dfinal = gatherBoth(dlist, consumeErrors=True)
+ dfinal.addCallback(self._handle_start)
+ return dfinal
+
+ def _handle_start(self, r):
+ log.msg('Engines started with pids: %r' % r)
+ return r
+
+ def _handle_stop(self, r):
+ log.msg('Engines received signal: %r' % r)
+ return r
+
+ def signal(self, sig):
+ dlist = []
+ for el in self.launchers:
+ d = el.get_stop_deferred()
+ dlist.append(d)
+ el.signal(sig)
+ dfinal = gatherBoth(dlist, consumeErrors=True)
+ dfinal.addCallback(self._handle_stop)
+ return dfinal
+
+ def interrupt_then_kill(self, delay=1.0):
+ dlist = []
+ for el in self.launchers:
+ d = el.get_stop_deferred()
+ dlist.append(d)
+ el.interrupt_then_kill(delay)
+ dfinal = gatherBoth(dlist, consumeErrors=True)
+ dfinal.addCallback(self._handle_stop)
+ return dfinal
+
+
+class BatchEngineSet(object):
+
+ # Subclasses must fill these in. See PBSEngineSet
+ submit_command = ''
+ delete_command = ''
+ job_id_regexp = ''
+
+ def __init__(self, template_file, **kwargs):
+ self.template_file = template_file
+ self.context = {}
+ self.context.update(kwargs)
+ self.batch_file = self.template_file+'-run'
+
+ def parse_job_id(self, output):
+ m = re.match(self.job_id_regexp, output)
+ if m is not None:
+ job_id = m.group()
+ else:
+ raise Exception("job id couldn't be determined: %s" % output)
+ self.job_id = job_id
+ log.msg('Job started with job id: %r' % job_id)
+ return job_id
+
+ def write_batch_script(self, n):
+ self.context['n'] = n
+ template = open(self.template_file, 'r').read()
+ log.msg('Using template for batch script: %s' % self.template_file)
+ script_as_string = Itpl.itplns(template, self.context)
+ log.msg('Writing instantiated batch script: %s' % self.batch_file)
+ f = open(self.batch_file,'w')
+ f.write(script_as_string)
+ f.close()
+
+ def handle_error(self, f):
+ f.printTraceback()
+ f.raiseException()
+
+ def start(self, n):
+ self.write_batch_script(n)
+ d = getProcessOutput(self.submit_command,
+ [self.batch_file],env=os.environ)
+ d.addCallback(self.parse_job_id)
+ d.addErrback(self.handle_error)
+ return d
+
+ def kill(self):
+ d = getProcessOutput(self.delete_command,
+ [self.job_id],env=os.environ)
+ return d
+
+class PBSEngineSet(BatchEngineSet):
+
+ submit_command = 'qsub'
+ delete_command = 'qdel'
+ job_id_regexp = '\d+'
+
+ def __init__(self, template_file, **kwargs):
+ BatchEngineSet.__init__(self, template_file, **kwargs)
+
+
+sshx_template="""#!/bin/sh
+"$@" &> /dev/null &
+echo $!
+"""
+
+engine_killer_template="""#!/bin/sh
+ps -fu `whoami` | grep '[i]pengine' | awk '{print $2}' | xargs kill -TERM
+"""
+
+class SSHEngineSet(object):
+ sshx_template=sshx_template
+ engine_killer_template=engine_killer_template
+
+ def __init__(self, engine_hosts, sshx=None, ipengine="ipengine"):
+ """Start a controller on localhost and engines using ssh.
+
+ The engine_hosts argument is a dict with hostnames as keys and
+ the number of engine (int) as values. sshx is the name of a local
+ file that will be used to run remote commands. This file is used
+ to setup the environment properly.
+ """
+
+ self.temp_dir = tempfile.gettempdir()
+ if sshx is not None:
+ self.sshx = sshx
+ else:
+ # Write the sshx.sh file locally from our template.
+ self.sshx = os.path.join(
+ self.temp_dir,
+ '%s-main-sshx.sh' % os.environ['USER']
+ )
+ f = open(self.sshx, 'w')
+ f.writelines(self.sshx_template)
+ f.close()
+ self.engine_command = ipengine
+ self.engine_hosts = engine_hosts
+ # Write the engine killer script file locally from our template.
+ self.engine_killer = os.path.join(
+ self.temp_dir,
+ '%s-local-engine_killer.sh' % os.environ['USER']
+ )
+ f = open(self.engine_killer, 'w')
+ f.writelines(self.engine_killer_template)
+ f.close()
+
+ def start(self, send_furl=False):
+ dlist = []
+ for host in self.engine_hosts.keys():
+ count = self.engine_hosts[host]
+ d = self._start(host, count, send_furl)
+ dlist.append(d)
+ return gatherBoth(dlist, consumeErrors=True)
+
+ def _start(self, hostname, count=1, send_furl=False):
+ if send_furl:
+ d = self._scp_furl(hostname)
+ else:
+ d = defer.succeed(None)
+ d.addCallback(lambda r: self._scp_sshx(hostname))
+ d.addCallback(lambda r: self._ssh_engine(hostname, count))
+ return d
+
+ def _scp_furl(self, hostname):
+ scp_cmd = "scp ~/.ipython/security/ipcontroller-engine.furl %s:.ipython/security/" % (hostname)
+ cmd_list = scp_cmd.split()
+ cmd_list[1] = os.path.expanduser(cmd_list[1])
+ log.msg('Copying furl file: %s' % scp_cmd)
+ d = getProcessOutput(cmd_list[0], cmd_list[1:], env=os.environ)
+ return d
+
+ def _scp_sshx(self, hostname):
+ scp_cmd = "scp %s %s:%s/%s-sshx.sh" % (
+ self.sshx, hostname,
+ self.temp_dir, os.environ['USER']
+ )
+ print
+ log.msg("Copying sshx: %s" % scp_cmd)
+ sshx_scp = scp_cmd.split()
+ d = getProcessOutput(sshx_scp[0], sshx_scp[1:], env=os.environ)
+ return d
+
+ def _ssh_engine(self, hostname, count):
+ exec_engine = "ssh %s sh %s/%s-sshx.sh %s" % (
+ hostname, self.temp_dir,
+ os.environ['USER'], self.engine_command
+ )
+ cmds = exec_engine.split()
+ dlist = []
+ log.msg("about to start engines...")
+ for i in range(count):
+ log.msg('Starting engines: %s' % exec_engine)
+ d = getProcessOutput(cmds[0], cmds[1:], env=os.environ)
+ dlist.append(d)
+ return gatherBoth(dlist, consumeErrors=True)
+
+ def kill(self):
+ dlist = []
+ for host in self.engine_hosts.keys():
+ d = self._killall(host)
+ dlist.append(d)
+ return gatherBoth(dlist, consumeErrors=True)
+
+ def _killall(self, hostname):
+ d = self._scp_engine_killer(hostname)
+ d.addCallback(lambda r: self._ssh_kill(hostname))
+ # d.addErrback(self._exec_err)
+ return d
+
+ def _scp_engine_killer(self, hostname):
+ scp_cmd = "scp %s %s:%s/%s-engine_killer.sh" % (
+ self.engine_killer,
+ hostname,
+ self.temp_dir,
+ os.environ['USER']
+ )
+ cmds = scp_cmd.split()
+ log.msg('Copying engine_killer: %s' % scp_cmd)
+ d = getProcessOutput(cmds[0], cmds[1:], env=os.environ)
+ return d
+
+ def _ssh_kill(self, hostname):
+ kill_cmd = "ssh %s sh %s/%s-engine_killer.sh" % (
+ hostname,
+ self.temp_dir,
+ os.environ['USER']
+ )
+ log.msg('Killing engine: %s' % kill_cmd)
+ kill_cmd = kill_cmd.split()
+ d = getProcessOutput(kill_cmd[0], kill_cmd[1:], env=os.environ)
+ return d
+
+ def _exec_err(self, r):
+ log.msg(r)
+
+#-----------------------------------------------------------------------------
+# Main functions for the different types of clusters
+#-----------------------------------------------------------------------------
+
+# TODO:
+# The logic in these codes should be moved into classes like LocalCluster
+# MpirunCluster, PBSCluster, etc. This would remove alot of the duplications.
+# The main functions should then just parse the command line arguments, create
+# the appropriate class and call a 'start' method.
+
+
+def check_security(args, cont_args):
+ """Check to see if we should run with SSL support."""
+ if (not args.x or not args.y) and not have_crypto:
+ log.err("""
+OpenSSL/pyOpenSSL is not available, so we can't run in secure mode.
+Try running ipcluster with the -xy flags: ipcluster local -xy -n 4""")
+ reactor.stop()
+ return False
+ if args.x:
+ cont_args.append('-x')
+ if args.y:
+ cont_args.append('-y')
+ return True
+
+
+def check_reuse(args, cont_args):
+ """Check to see if we should try to resuse FURL files."""
+ if args.r:
+ cont_args.append('-r')
+ if args.client_port == 0 or args.engine_port == 0:
+ log.err("""
+To reuse FURL files, you must also set the client and engine ports using
+the --client-port and --engine-port options.""")
+ reactor.stop()
+ return False
+ cont_args.append('--client-port=%i' % args.client_port)
+ cont_args.append('--engine-port=%i' % args.engine_port)
+ return True
+
+
+def _err_and_stop(f):
+ """Errback to log a failure and halt the reactor on a fatal error."""
+ log.err(f)
+ reactor.stop()
+
+
+def _delay_start(cont_pid, start_engines, furl_file, reuse):
+ """Wait for controller to create FURL files and the start the engines."""
+ if not reuse:
+ if os.path.isfile(furl_file):
+ os.unlink(furl_file)
+ log.msg('Waiting for controller to finish starting...')
+ d = wait_for_file(furl_file, delay=0.2, max_tries=50)
+ d.addCallback(lambda _: log.msg('Controller started'))
+ d.addCallback(lambda _: start_engines(cont_pid))
+ return d
+
+
+def main_local(args):
+ cont_args = []
+ cont_args.append('--logfile=%s' % pjoin(args.logdir,'ipcontroller'))
+
+ # Check security settings before proceeding
+ if not check_security(args, cont_args):
+ return
+
+ # See if we are reusing FURL files
+ if not check_reuse(args, cont_args):
+ return
+
+ cl = ControllerLauncher(extra_args=cont_args)
+ dstart = cl.start()
+ def start_engines(cont_pid):
+ engine_args = []
+ engine_args.append('--logfile=%s' % \
+ pjoin(args.logdir,'ipengine%s-' % cont_pid))
+ eset = LocalEngineSet(extra_args=engine_args)
+ def shutdown(signum, frame):
+ log.msg('Stopping local cluster')
+ # We are still playing with the times here, but these seem
+ # to be reliable in allowing everything to exit cleanly.
+ eset.interrupt_then_kill(0.5)
+ cl.interrupt_then_kill(0.5)
+ reactor.callLater(1.0, reactor.stop)
+ signal.signal(signal.SIGINT,shutdown)
+ d = eset.start(args.n)
+ return d
+ config = kernel_config_manager.get_config_obj()
+ furl_file = config['controller']['engine_furl_file']
+ dstart.addCallback(_delay_start, start_engines, furl_file, args.r)
+ dstart.addErrback(_err_and_stop)
+
+
+def main_mpi(args):
+ cont_args = []
+ cont_args.append('--logfile=%s' % pjoin(args.logdir,'ipcontroller'))
+
+ # Check security settings before proceeding
+ if not check_security(args, cont_args):
+ return
+
+ # See if we are reusing FURL files
+ if not check_reuse(args, cont_args):
+ return
+
+ cl = ControllerLauncher(extra_args=cont_args)
+ dstart = cl.start()
+ def start_engines(cont_pid):
+ raw_args = [args.cmd]
+ raw_args.extend(['-n',str(args.n)])
+ raw_args.append('ipengine')
+ raw_args.append('-l')
+ raw_args.append(pjoin(args.logdir,'ipengine%s-' % cont_pid))
+ if args.mpi:
+ raw_args.append('--mpi=%s' % args.mpi)
+ eset = ProcessLauncher(raw_args)
+ def shutdown(signum, frame):
+ log.msg('Stopping local cluster')
+ # We are still playing with the times here, but these seem
+ # to be reliable in allowing everything to exit cleanly.
+ eset.interrupt_then_kill(1.0)
+ cl.interrupt_then_kill(1.0)
+ reactor.callLater(2.0, reactor.stop)
+ signal.signal(signal.SIGINT,shutdown)
+ d = eset.start()
+ return d
+ config = kernel_config_manager.get_config_obj()
+ furl_file = config['controller']['engine_furl_file']
+ dstart.addCallback(_delay_start, start_engines, furl_file, args.r)
+ dstart.addErrback(_err_and_stop)
+
+
+def main_pbs(args):
+ cont_args = []
+ cont_args.append('--logfile=%s' % pjoin(args.logdir,'ipcontroller'))
+
+ # Check security settings before proceeding
+ if not check_security(args, cont_args):
+ return
+
+ # See if we are reusing FURL files
+ if not check_reuse(args, cont_args):
+ return
+
+ cl = ControllerLauncher(extra_args=cont_args)
+ dstart = cl.start()
+ def start_engines(r):
+ pbs_set = PBSEngineSet(args.pbsscript)
+ def shutdown(signum, frame):
+ log.msg('Stopping pbs cluster')
+ d = pbs_set.kill()
+ d.addBoth(lambda _: cl.interrupt_then_kill(1.0))
+ d.addBoth(lambda _: reactor.callLater(2.0, reactor.stop))
+ signal.signal(signal.SIGINT,shutdown)
+ d = pbs_set.start(args.n)
+ return d
+ config = kernel_config_manager.get_config_obj()
+ furl_file = config['controller']['engine_furl_file']
+ dstart.addCallback(_delay_start, start_engines, furl_file, args.r)
+ dstart.addErrback(_err_and_stop)
+
+
+def main_ssh(args):
+ """Start a controller on localhost and engines using ssh.
+
+ Your clusterfile should look like::
+
+ send_furl = False # True, if you want
+ engines = {
+ 'engine_host1' : engine_count,
+ 'engine_host2' : engine_count2
+ }
+ """
+ clusterfile = {}
+ execfile(args.clusterfile, clusterfile)
+ if not clusterfile.has_key('send_furl'):
+ clusterfile['send_furl'] = False
+
+ cont_args = []
+ cont_args.append('--logfile=%s' % pjoin(args.logdir,'ipcontroller'))
+
+ # Check security settings before proceeding
+ if not check_security(args, cont_args):
+ return
+
+ # See if we are reusing FURL files
+ if not check_reuse(args, cont_args):
+ return
+
+ cl = ControllerLauncher(extra_args=cont_args)
+ dstart = cl.start()
+ def start_engines(cont_pid):
+ ssh_set = SSHEngineSet(clusterfile['engines'], sshx=args.sshx)
+ def shutdown(signum, frame):
+ d = ssh_set.kill()
+ cl.interrupt_then_kill(1.0)
+ reactor.callLater(2.0, reactor.stop)
+ signal.signal(signal.SIGINT,shutdown)
+ d = ssh_set.start(clusterfile['send_furl'])
+ return d
+ config = kernel_config_manager.get_config_obj()
+ furl_file = config['controller']['engine_furl_file']
+ dstart.addCallback(_delay_start, start_engines, furl_file, args.r)
+ dstart.addErrback(_err_and_stop)
+
+
+def get_args():
+ base_parser = argparse.ArgumentParser(add_help=False)
+ base_parser.add_argument(
+ '-r',
+ action='store_true',
+ dest='r',
+ help='try to reuse FURL files. Use with --client-port and --engine-port'
+ )
+ base_parser.add_argument(
+ '--client-port',
+ type=int,
+ dest='client_port',
+ help='the port the controller will listen on for client connections',
+ default=0
+ )
+ base_parser.add_argument(
+ '--engine-port',
+ type=int,
+ dest='engine_port',
+ help='the port the controller will listen on for engine connections',
+ default=0
+ )
+ base_parser.add_argument(
+ '-x',
+ action='store_true',
+ dest='x',
+ help='turn off client security'
+ )
+ base_parser.add_argument(
+ '-y',
+ action='store_true',
+ dest='y',
+ help='turn off engine security'
+ )
+ base_parser.add_argument(
+ "--logdir",
+ type=str,
+ dest="logdir",
+ help="directory to put log files (default=$IPYTHONDIR/log)",
+ default=pjoin(get_ipython_dir(),'log')
+ )
+ base_parser.add_argument(
+ "-n",
+ "--num",
+ type=int,
+ dest="n",
+ default=2,
+ help="the number of engines to start"
+ )
+
+ parser = argparse.ArgumentParser(
+ description='IPython cluster startup. This starts a controller and\
+ engines using various approaches. Use the IPYTHONDIR environment\
+ variable to change your IPython directory from the default of\
+ .ipython or _ipython. The log and security subdirectories of your\
+ IPython directory will be used by this script for log files and\
+ security files.'
+ )
+ subparsers = parser.add_subparsers(
+ help='available cluster types. For help, do "ipcluster TYPE --help"')
+
+ parser_local = subparsers.add_parser(
+ 'local',
+ help='run a local cluster',
+ parents=[base_parser]
+ )
+ parser_local.set_defaults(func=main_local)
+
+ parser_mpirun = subparsers.add_parser(
+ 'mpirun',
+ help='run a cluster using mpirun (mpiexec also works)',
+ parents=[base_parser]
+ )
+ parser_mpirun.add_argument(
+ "--mpi",
+ type=str,
+ dest="mpi", # Don't put a default here to allow no MPI support
+ help="how to call MPI_Init (default=mpi4py)"
+ )
+ parser_mpirun.set_defaults(func=main_mpi, cmd='mpirun')
+
+ parser_mpiexec = subparsers.add_parser(
+ 'mpiexec',
+ help='run a cluster using mpiexec (mpirun also works)',
+ parents=[base_parser]
+ )
+ parser_mpiexec.add_argument(
+ "--mpi",
+ type=str,
+ dest="mpi", # Don't put a default here to allow no MPI support
+ help="how to call MPI_Init (default=mpi4py)"
+ )
+ parser_mpiexec.set_defaults(func=main_mpi, cmd='mpiexec')
+
+ parser_pbs = subparsers.add_parser(
+ 'pbs',
+ help='run a pbs cluster',
+ parents=[base_parser]
+ )
+ parser_pbs.add_argument(
+ '--pbs-script',
+ type=str,
+ dest='pbsscript',
+ help='PBS script template',
+ default='pbs.template'
+ )
+ parser_pbs.set_defaults(func=main_pbs)
+
+ parser_ssh = subparsers.add_parser(
+ 'ssh',
+ help='run a cluster using ssh, should have ssh-keys setup',
+ parents=[base_parser]
+ )
+ parser_ssh.add_argument(
+ '--clusterfile',
+ type=str,
+ dest='clusterfile',
+ help='python file describing the cluster',
+ default='clusterfile.py',
+ )
+ parser_ssh.add_argument(
+ '--sshx',
+ type=str,
+ dest='sshx',
+ help='sshx launcher helper'
+ )
+ parser_ssh.set_defaults(func=main_ssh)
+
+ args = parser.parse_args()
+ return args
+
+def main():
+ args = get_args()
+ reactor.callWhenRunning(args.func, args)
+ log.startLogging(sys.stdout)
+ reactor.run()
+
+if __name__ == '__main__':
+ main()
diff --git a/IPython/kernel/scripts/ipcontroller b/IPython/kernel/scripts/ipcontroller
new file mode 100755
index 0000000..b4c86a4
--- /dev/null
+++ b/IPython/kernel/scripts/ipcontroller
@@ -0,0 +1,20 @@
+#!/usr/bin/env python
+# encoding: utf-8
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+if __name__ == '__main__':
+ from IPython.kernel.scripts import ipcontroller
+ ipcontroller.main()
+
diff --git a/IPython/kernel/scripts/ipcontroller.py b/IPython/kernel/scripts/ipcontroller.py
new file mode 100755
index 0000000..496b139
--- /dev/null
+++ b/IPython/kernel/scripts/ipcontroller.py
@@ -0,0 +1,416 @@
+#!/usr/bin/env python
+# encoding: utf-8
+
+"""The IPython controller."""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+# Python looks for an empty string at the beginning of sys.path to enable
+# importing from the cwd.
+import sys
+sys.path.insert(0, '')
+
+from optparse import OptionParser
+import os
+import time
+import tempfile
+
+from twisted.application import internet, service
+from twisted.internet import reactor, error, defer
+from twisted.python import log
+
+from IPython.kernel.fcutil import Tub, UnauthenticatedTub, have_crypto
+
+# from IPython.tools import growl
+# growl.start("IPython1 Controller")
+
+from IPython.kernel.error import SecurityError
+from IPython.kernel import controllerservice
+from IPython.kernel.fcutil import check_furl_file_security
+
+# Create various ipython directories if they don't exist.
+# This must be done before IPython.kernel.config is imported.
+from IPython.iplib import user_setup
+from IPython.genutils import get_ipython_dir, get_log_dir, get_security_dir
+if os.name == 'posix':
+ rc_suffix = ''
+else:
+ rc_suffix = '.ini'
+user_setup(get_ipython_dir(), rc_suffix, mode='install', interactive=False)
+get_log_dir()
+get_security_dir()
+
+from IPython.kernel.config import config_manager as kernel_config_manager
+from IPython.config.cutils import import_item
+
+
+#-------------------------------------------------------------------------------
+# Code
+#-------------------------------------------------------------------------------
+
+def get_temp_furlfile(filename):
+ return tempfile.mktemp(dir=os.path.dirname(filename),
+ prefix=os.path.basename(filename))
+
+def make_tub(ip, port, secure, cert_file):
+ """
+ Create a listening tub given an ip, port, and cert_file location.
+
+ :Parameters:
+ ip : str
+ The ip address that the tub should listen on. Empty means all
+ port : int
+ The port that the tub should listen on. A value of 0 means
+ pick a random port
+ secure: boolean
+ Will the connection be secure (in the foolscap sense)
+ cert_file:
+ A filename of a file to be used for theSSL certificate
+ """
+ if secure:
+ if have_crypto:
+ tub = Tub(certFile=cert_file)
+ else:
+ raise SecurityError("""
+OpenSSL/pyOpenSSL is not available, so we can't run in secure mode.
+Try running without security using 'ipcontroller -xy'.
+""")
+ else:
+ tub = UnauthenticatedTub()
+
+ # Set the strport based on the ip and port and start listening
+ if ip == '':
+ strport = "tcp:%i" % port
+ else:
+ strport = "tcp:%i:interface=%s" % (port, ip)
+ listener = tub.listenOn(strport)
+
+ return tub, listener
+
+def make_client_service(controller_service, config):
+ """
+ Create a service that will listen for clients.
+
+ This service is simply a `foolscap.Tub` instance that has a set of Referenceables
+ registered with it.
+ """
+
+ # Now create the foolscap tub
+ ip = config['controller']['client_tub']['ip']
+ port = config['controller']['client_tub'].as_int('port')
+ location = config['controller']['client_tub']['location']
+ secure = config['controller']['client_tub']['secure']
+ cert_file = config['controller']['client_tub']['cert_file']
+ client_tub, client_listener = make_tub(ip, port, secure, cert_file)
+
+ # Set the location in the trivial case of localhost
+ if ip == 'localhost' or ip == '127.0.0.1':
+ location = "127.0.0.1"
+
+ if not secure:
+ log.msg("WARNING: you are running the controller with no client security")
+
+ def set_location_and_register():
+ """Set the location for the tub and return a deferred."""
+
+ def register(empty, ref, furl_file):
+ # We create and then move to make sure that when the file
+ # appears to other processes, the buffer has the flushed
+ # and the file has been closed
+ temp_furl_file = get_temp_furlfile(furl_file)
+ client_tub.registerReference(ref, furlFile=temp_furl_file)
+ os.rename(temp_furl_file, furl_file)
+
+ if location == '':
+ d = client_tub.setLocationAutomatically()
+ else:
+ d = defer.maybeDeferred(client_tub.setLocation, "%s:%i" % (location, client_listener.getPortnum()))
+
+ for ciname, ci in config['controller']['controller_interfaces'].iteritems():
+ log.msg("Adapting Controller to interface: %s" % ciname)
+ furl_file = ci['furl_file']
+ log.msg("Saving furl for interface [%s] to file: %s" % (ciname, furl_file))
+ check_furl_file_security(furl_file, secure)
+ adapted_controller = import_item(ci['controller_interface'])(controller_service)
+ d.addCallback(register, import_item(ci['fc_interface'])(adapted_controller),
+ furl_file=ci['furl_file'])
+
+ reactor.callWhenRunning(set_location_and_register)
+ return client_tub
+
+
+def make_engine_service(controller_service, config):
+ """
+ Create a service that will listen for engines.
+
+ This service is simply a `foolscap.Tub` instance that has a set of Referenceables
+ registered with it.
+ """
+
+ # Now create the foolscap tub
+ ip = config['controller']['engine_tub']['ip']
+ port = config['controller']['engine_tub'].as_int('port')
+ location = config['controller']['engine_tub']['location']
+ secure = config['controller']['engine_tub']['secure']
+ cert_file = config['controller']['engine_tub']['cert_file']
+ engine_tub, engine_listener = make_tub(ip, port, secure, cert_file)
+
+ # Set the location in the trivial case of localhost
+ if ip == 'localhost' or ip == '127.0.0.1':
+ location = "127.0.0.1"
+
+ if not secure:
+ log.msg("WARNING: you are running the controller with no engine security")
+
+ def set_location_and_register():
+ """Set the location for the tub and return a deferred."""
+
+ def register(empty, ref, furl_file):
+ # We create and then move to make sure that when the file
+ # appears to other processes, the buffer has the flushed
+ # and the file has been closed
+ temp_furl_file = get_temp_furlfile(furl_file)
+ engine_tub.registerReference(ref, furlFile=temp_furl_file)
+ os.rename(temp_furl_file, furl_file)
+
+ if location == '':
+ d = engine_tub.setLocationAutomatically()
+ else:
+ d = defer.maybeDeferred(engine_tub.setLocation, "%s:%i" % (location, engine_listener.getPortnum()))
+
+ furl_file = config['controller']['engine_furl_file']
+ engine_fc_interface = import_item(config['controller']['engine_fc_interface'])
+ log.msg("Saving furl for the engine to file: %s" % furl_file)
+ check_furl_file_security(furl_file, secure)
+ fc_controller = engine_fc_interface(controller_service)
+ d.addCallback(register, fc_controller, furl_file=furl_file)
+
+ reactor.callWhenRunning(set_location_and_register)
+ return engine_tub
+
+def start_controller():
+ """
+ Start the controller by creating the service hierarchy and starting the reactor.
+
+ This method does the following:
+
+ * It starts the controller logging
+ * In execute an import statement for the controller
+ * It creates 2 `foolscap.Tub` instances for the client and the engines
+ and registers `foolscap.Referenceables` with the tubs to expose the
+ controller to engines and clients.
+ """
+ config = kernel_config_manager.get_config_obj()
+
+ # Start logging
+ logfile = config['controller']['logfile']
+ if logfile:
+ logfile = logfile + str(os.getpid()) + '.log'
+ try:
+ openLogFile = open(logfile, 'w')
+ except:
+ openLogFile = sys.stdout
+ else:
+ openLogFile = sys.stdout
+ log.startLogging(openLogFile)
+
+ # Execute any user defined import statements
+ cis = config['controller']['import_statement']
+ if cis:
+ try:
+ exec cis in globals(), locals()
+ except:
+ log.msg("Error running import_statement: %s" % cis)
+
+ # Delete old furl files unless the reuse_furls is set
+ reuse = config['controller']['reuse_furls']
+ if not reuse:
+ paths = (config['controller']['engine_furl_file'],
+ config['controller']['controller_interfaces']['task']['furl_file'],
+ config['controller']['controller_interfaces']['multiengine']['furl_file']
+ )
+ for p in paths:
+ if os.path.isfile(p):
+ os.remove(p)
+
+ # Create the service hierarchy
+ main_service = service.MultiService()
+ # The controller service
+ controller_service = controllerservice.ControllerService()
+ controller_service.setServiceParent(main_service)
+ # The client tub and all its refereceables
+ client_service = make_client_service(controller_service, config)
+ client_service.setServiceParent(main_service)
+ # The engine tub
+ engine_service = make_engine_service(controller_service, config)
+ engine_service.setServiceParent(main_service)
+ # Start the controller service and set things running
+ main_service.startService()
+ reactor.run()
+
+def init_config():
+ """
+ Initialize the configuration using default and command line options.
+ """
+
+ parser = OptionParser("""ipcontroller [options]
+
+Start an IPython controller.
+
+Use the IPYTHONDIR environment variable to change your IPython directory
+from the default of .ipython or _ipython. The log and security
+subdirectories of your IPython directory will be used by this script
+for log files and security files.""")
+
+ # Client related options
+ parser.add_option(
+ "--client-ip",
+ type="string",
+ dest="client_ip",
+ help="the IP address or hostname the controller will listen on for client connections"
+ )
+ parser.add_option(
+ "--client-port",
+ type="int",
+ dest="client_port",
+ help="the port the controller will listen on for client connections"
+ )
+ parser.add_option(
+ '--client-location',
+ type="string",
+ dest="client_location",
+ help="hostname or ip for clients to connect to"
+ )
+ parser.add_option(
+ "-x",
+ action="store_false",
+ dest="client_secure",
+ help="turn off all client security"
+ )
+ parser.add_option(
+ '--client-cert-file',
+ type="string",
+ dest="client_cert_file",
+ help="file to store the client SSL certificate"
+ )
+ parser.add_option(
+ '--task-furl-file',
+ type="string",
+ dest="task_furl_file",
+ help="file to store the FURL for task clients to connect with"
+ )
+ parser.add_option(
+ '--multiengine-furl-file',
+ type="string",
+ dest="multiengine_furl_file",
+ help="file to store the FURL for multiengine clients to connect with"
+ )
+ # Engine related options
+ parser.add_option(
+ "--engine-ip",
+ type="string",
+ dest="engine_ip",
+ help="the IP address or hostname the controller will listen on for engine connections"
+ )
+ parser.add_option(
+ "--engine-port",
+ type="int",
+ dest="engine_port",
+ help="the port the controller will listen on for engine connections"
+ )
+ parser.add_option(
+ '--engine-location',
+ type="string",
+ dest="engine_location",
+ help="hostname or ip for engines to connect to"
+ )
+ parser.add_option(
+ "-y",
+ action="store_false",
+ dest="engine_secure",
+ help="turn off all engine security"
+ )
+ parser.add_option(
+ '--engine-cert-file',
+ type="string",
+ dest="engine_cert_file",
+ help="file to store the engine SSL certificate"
+ )
+ parser.add_option(
+ '--engine-furl-file',
+ type="string",
+ dest="engine_furl_file",
+ help="file to store the FURL for engines to connect with"
+ )
+ parser.add_option(
+ "-l", "--logfile",
+ type="string",
+ dest="logfile",
+ help="log file name (default is stdout)"
+ )
+ parser.add_option(
+ "-r",
+ action="store_true",
+ dest="reuse_furls",
+ help="try to reuse all furl files"
+ )
+
+ (options, args) = parser.parse_args()
+
+ config = kernel_config_manager.get_config_obj()
+
+ # Update with command line options
+ if options.client_ip is not None:
+ config['controller']['client_tub']['ip'] = options.client_ip
+ if options.client_port is not None:
+ config['controller']['client_tub']['port'] = options.client_port
+ if options.client_location is not None:
+ config['controller']['client_tub']['location'] = options.client_location
+ if options.client_secure is not None:
+ config['controller']['client_tub']['secure'] = options.client_secure
+ if options.client_cert_file is not None:
+ config['controller']['client_tub']['cert_file'] = options.client_cert_file
+ if options.task_furl_file is not None:
+ config['controller']['controller_interfaces']['task']['furl_file'] = options.task_furl_file
+ if options.multiengine_furl_file is not None:
+ config['controller']['controller_interfaces']['multiengine']['furl_file'] = options.multiengine_furl_file
+ if options.engine_ip is not None:
+ config['controller']['engine_tub']['ip'] = options.engine_ip
+ if options.engine_port is not None:
+ config['controller']['engine_tub']['port'] = options.engine_port
+ if options.engine_location is not None:
+ config['controller']['engine_tub']['location'] = options.engine_location
+ if options.engine_secure is not None:
+ config['controller']['engine_tub']['secure'] = options.engine_secure
+ if options.engine_cert_file is not None:
+ config['controller']['engine_tub']['cert_file'] = options.engine_cert_file
+ if options.engine_furl_file is not None:
+ config['controller']['engine_furl_file'] = options.engine_furl_file
+ if options.reuse_furls is not None:
+ config['controller']['reuse_furls'] = options.reuse_furls
+
+ if options.logfile is not None:
+ config['controller']['logfile'] = options.logfile
+
+ kernel_config_manager.update_config_obj(config)
+
+def main():
+ """
+ After creating the configuration information, start the controller.
+ """
+ init_config()
+ start_controller()
+
+if __name__ == "__main__":
+ main()
diff --git a/IPython/kernel/scripts/ipengine b/IPython/kernel/scripts/ipengine
new file mode 100755
index 0000000..92eab1c
--- /dev/null
+++ b/IPython/kernel/scripts/ipengine
@@ -0,0 +1,20 @@
+#!/usr/bin/env python
+# encoding: utf-8
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+if __name__ == '__main__':
+ from IPython.kernel.scripts import ipengine
+ ipengine.main()
+
diff --git a/IPython/kernel/scripts/ipengine.py b/IPython/kernel/scripts/ipengine.py
new file mode 100755
index 0000000..a70ec6a
--- /dev/null
+++ b/IPython/kernel/scripts/ipengine.py
@@ -0,0 +1,193 @@
+#!/usr/bin/env python
+# encoding: utf-8
+
+"""Start the IPython Engine."""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+# Python looks for an empty string at the beginning of sys.path to enable
+# importing from the cwd.
+import sys
+sys.path.insert(0, '')
+
+from optparse import OptionParser
+import os
+
+from twisted.application import service
+from twisted.internet import reactor
+from twisted.python import log
+
+from IPython.kernel.fcutil import Tub, UnauthenticatedTub
+
+from IPython.kernel.core.config import config_manager as core_config_manager
+from IPython.config.cutils import import_item
+from IPython.kernel.engineservice import EngineService
+
+# Create various ipython directories if they don't exist.
+# This must be done before IPython.kernel.config is imported.
+from IPython.iplib import user_setup
+from IPython.genutils import get_ipython_dir, get_log_dir, get_security_dir
+if os.name == 'posix':
+ rc_suffix = ''
+else:
+ rc_suffix = '.ini'
+user_setup(get_ipython_dir(), rc_suffix, mode='install', interactive=False)
+get_log_dir()
+get_security_dir()
+
+from IPython.kernel.config import config_manager as kernel_config_manager
+from IPython.kernel.engineconnector import EngineConnector
+
+
+#-------------------------------------------------------------------------------
+# Code
+#-------------------------------------------------------------------------------
+
+def start_engine():
+ """
+ Start the engine, by creating it and starting the Twisted reactor.
+
+ This method does:
+
+ * If it exists, runs the `mpi_import_statement` to call `MPI_Init`
+ * Starts the engine logging
+ * Creates an IPython shell and wraps it in an `EngineService`
+ * Creates a `foolscap.Tub` to use in connecting to a controller.
+ * Uses the tub and the `EngineService` along with a Foolscap URL
+ (or FURL) to connect to the controller and register the engine
+ with the controller
+ """
+ kernel_config = kernel_config_manager.get_config_obj()
+ core_config = core_config_manager.get_config_obj()
+
+
+ # Execute the mpi import statement that needs to call MPI_Init
+ global mpi
+ mpikey = kernel_config['mpi']['default']
+ mpi_import_statement = kernel_config['mpi'].get(mpikey, None)
+ if mpi_import_statement is not None:
+ try:
+ exec mpi_import_statement in globals()
+ except:
+ mpi = None
+ else:
+ mpi = None
+
+ # Start logging
+ logfile = kernel_config['engine']['logfile']
+ if logfile:
+ logfile = logfile + str(os.getpid()) + '.log'
+ try:
+ openLogFile = open(logfile, 'w')
+ except:
+ openLogFile = sys.stdout
+ else:
+ openLogFile = sys.stdout
+ log.startLogging(openLogFile)
+
+ # Create the underlying shell class and EngineService
+ shell_class = import_item(core_config['shell']['shell_class'])
+ engine_service = EngineService(shell_class, mpi=mpi)
+ shell_import_statement = core_config['shell']['import_statement']
+ if shell_import_statement:
+ try:
+ engine_service.execute(shell_import_statement)
+ except:
+ log.msg("Error running import_statement: %s" % shell_import_statement)
+
+ # Create the service hierarchy
+ main_service = service.MultiService()
+ engine_service.setServiceParent(main_service)
+ tub_service = Tub()
+ tub_service.setServiceParent(main_service)
+ # This needs to be called before the connection is initiated
+ main_service.startService()
+
+ # This initiates the connection to the controller and calls
+ # register_engine to tell the controller we are ready to do work
+ engine_connector = EngineConnector(tub_service)
+ furl_file = kernel_config['engine']['furl_file']
+ log.msg("Using furl file: %s" % furl_file)
+
+ def call_connect(engine_service, furl_file):
+ d = engine_connector.connect_to_controller(engine_service, furl_file)
+ def handle_error(f):
+ # If this print statement is replaced by a log.err(f) I get
+ # an unhandled error, which makes no sense. I shouldn't have
+ # to use a print statement here. My only thought is that
+ # at the beginning of the process the logging is still starting up
+ print "error connecting to controller:", f.getErrorMessage()
+ reactor.callLater(0.1, reactor.stop)
+ d.addErrback(handle_error)
+
+ reactor.callWhenRunning(call_connect, engine_service, furl_file)
+ reactor.run()
+
+
+def init_config():
+ """
+ Initialize the configuration using default and command line options.
+ """
+
+ parser = OptionParser("""ipengine [options]
+
+Start an IPython engine.
+
+Use the IPYTHONDIR environment variable to change your IPython directory
+from the default of .ipython or _ipython. The log and security
+subdirectories of your IPython directory will be used by this script
+for log files and security files.""")
+
+ parser.add_option(
+ "--furl-file",
+ type="string",
+ dest="furl_file",
+ help="The filename containing the FURL of the controller"
+ )
+ parser.add_option(
+ "--mpi",
+ type="string",
+ dest="mpi",
+ help="How to enable MPI (mpi4py, pytrilinos, or empty string to disable)"
+ )
+ parser.add_option(
+ "-l",
+ "--logfile",
+ type="string",
+ dest="logfile",
+ help="log file name (default is stdout)"
+ )
+
+ (options, args) = parser.parse_args()
+
+ kernel_config = kernel_config_manager.get_config_obj()
+ # Now override with command line options
+ if options.furl_file is not None:
+ kernel_config['engine']['furl_file'] = options.furl_file
+ if options.logfile is not None:
+ kernel_config['engine']['logfile'] = options.logfile
+ if options.mpi is not None:
+ kernel_config['mpi']['default'] = options.mpi
+
+
+def main():
+ """
+ After creating the configuration information, start the engine.
+ """
+ init_config()
+ start_engine()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/IPython/kernel/task.py b/IPython/kernel/task.py
new file mode 100644
index 0000000..924d052
--- /dev/null
+++ b/IPython/kernel/task.py
@@ -0,0 +1,1116 @@
+# encoding: utf-8
+# -*- test-case-name: IPython.kernel.tests.test_task -*-
+
+"""Task farming representation of the ControllerService."""
+
+__docformat__ = "restructuredtext en"
+
+#-----------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+# Tell nose to skip the testing of this module
+__test__ = {}
+
+import copy, time
+from types import FunctionType
+
+import zope.interface as zi, string
+from twisted.internet import defer, reactor
+from twisted.python import components, log, failure
+
+from IPython.kernel.util import printer
+from IPython.kernel import engineservice as es, error
+from IPython.kernel import controllerservice as cs
+from IPython.kernel.twistedutil import gatherBoth, DeferredList
+
+from IPython.kernel.pickleutil import can, uncan, CannedFunction
+
+#-----------------------------------------------------------------------------
+# Definition of the Task objects
+#-----------------------------------------------------------------------------
+
+time_format = '%Y/%m/%d %H:%M:%S'
+
+class ITask(zi.Interface):
+ """
+ This interface provides a generic definition of what constitutes a task.
+
+ There are two sides to a task. First a task needs to take input from
+ a user to determine what work is performed by the task. Second, the
+ task needs to have the logic that knows how to turn that information
+ info specific calls to a worker, through the `IQueuedEngine` interface.
+
+ Many method in this class get two things passed to them: a Deferred
+ and an IQueuedEngine implementer. Such methods should register callbacks
+ on the Deferred that use the IQueuedEngine to accomplish something. See
+ the existing task objects for examples.
+ """
+
+ zi.Attribute('retries','How many times to retry the task')
+ zi.Attribute('recovery_task','A task to try if the initial one fails')
+ zi.Attribute('taskid','the id of the task')
+
+ def start_time(result):
+ """
+ Do anything needed to start the timing of the task.
+
+ Must simply return the result after starting the timers.
+ """
+
+ def stop_time(result):
+ """
+ Do anything needed to stop the timing of the task.
+
+ Must simply return the result after stopping the timers. This
+ method will usually set attributes that are used by `process_result`
+ in building result of the task.
+ """
+
+ def pre_task(d, queued_engine):
+ """Do something with the queued_engine before the task is run.
+
+ This method should simply add callbacks to the input Deferred
+ that do something with the `queued_engine` before the task is run.
+
+ :Parameters:
+ d : Deferred
+ The deferred that actions should be attached to
+ queued_engine : IQueuedEngine implementer
+ The worker that has been allocated to perform the task
+ """
+
+ def post_task(d, queued_engine):
+ """Do something with the queued_engine after the task is run.
+
+ This method should simply add callbacks to the input Deferred
+ that do something with the `queued_engine` before the task is run.
+
+ :Parameters:
+ d : Deferred
+ The deferred that actions should be attached to
+ queued_engine : IQueuedEngine implementer
+ The worker that has been allocated to perform the task
+ """
+
+ def submit_task(d, queued_engine):
+ """Submit a task using the `queued_engine` we have been allocated.
+
+ When a task is ready to run, this method is called. This method
+ must take the internal information of the task and make suitable
+ calls on the queued_engine to have the actual work done.
+
+ This method should simply add callbacks to the input Deferred
+ that do something with the `queued_engine` before the task is run.
+
+ :Parameters:
+ d : Deferred
+ The deferred that actions should be attached to
+ queued_engine : IQueuedEngine implementer
+ The worker that has been allocated to perform the task
+ """
+
+ def process_result(d, result, engine_id):
+ """Take a raw task result.
+
+ Objects that implement `ITask` can choose how the result of running
+ the task is presented. This method takes the raw result and
+ does this logic. Two example are the `MapTask` which simply returns
+ the raw result or a `Failure` object and the `StringTask` which
+ returns a `TaskResult` object.
+
+ :Parameters:
+ d : Deferred
+ The deferred that actions should be attached to
+ result : object
+ The raw task result that needs to be wrapped
+ engine_id : int
+ The id of the engine that did the task
+
+ :Returns:
+ The result, as a tuple of the form: (success, result).
+ Here, success is a boolean indicating if the task
+ succeeded or failed and result is the result.
+ """
+
+ def check_depend(properties):
+ """Check properties to see if the task should be run.
+
+ :Parameters:
+ properties : dict
+ A dictionary of properties that an engine has set
+
+ :Returns:
+ True if the task should be run, False otherwise
+ """
+
+ def can_task(self):
+ """Serialize (can) any functions in the task for pickling.
+
+ Subclasses must override this method and make sure that all
+ functions in the task are canned by calling `can` on the
+ function.
+ """
+
+ def uncan_task(self):
+ """Unserialize (uncan) any canned function in the task."""
+
+class BaseTask(object):
+ """
+ Common fuctionality for all objects implementing `ITask`.
+ """
+
+ zi.implements(ITask)
+
+ def __init__(self, clear_before=False, clear_after=False, retries=0,
+ recovery_task=None, depend=None):
+ """
+ Make a generic task.
+
+ :Parameters:
+ clear_before : boolean
+ Should the engines namespace be cleared before the task
+ is run
+ clear_after : boolean
+ Should the engines namespace be clear after the task is run
+ retries : int
+ The number of times a task should be retries upon failure
+ recovery_task : any task object
+ If a task fails and it has a recovery_task, that is run
+ upon a retry
+ depend : FunctionType
+ A function that is called to test for properties. This function
+ must take one argument, the properties dict and return a boolean
+ """
+ self.clear_before = clear_before
+ self.clear_after = clear_after
+ self.retries = retries
+ self.recovery_task = recovery_task
+ self.depend = depend
+ self.taskid = None
+
+ def start_time(self, result):
+ """
+ Start the basic timers.
+ """
+ self.start = time.time()
+ self.start_struct = time.localtime()
+ return result
+
+ def stop_time(self, result):
+ """
+ Stop the basic timers.
+ """
+ self.stop = time.time()
+ self.stop_struct = time.localtime()
+ self.duration = self.stop - self.start
+ self.submitted = time.strftime(time_format, self.start_struct)
+ self.completed = time.strftime(time_format)
+ return result
+
+ def pre_task(self, d, queued_engine):
+ """
+ Clear the engine before running the task if clear_before is set.
+ """
+ if self.clear_before:
+ d.addCallback(lambda r: queued_engine.reset())
+
+ def post_task(self, d, queued_engine):
+ """
+ Clear the engine after running the task if clear_after is set.
+ """
+ def reseter(result):
+ queued_engine.reset()
+ return result
+ if self.clear_after:
+ d.addBoth(reseter)
+
+ def submit_task(self, d, queued_engine):
+ raise NotImplementedError('submit_task must be implemented in a subclass')
+
+ def process_result(self, result, engine_id):
+ """
+ Process a task result.
+
+ This is the default `process_result` that just returns the raw
+ result or a `Failure`.
+ """
+ if isinstance(result, failure.Failure):
+ return (False, result)
+ else:
+ return (True, result)
+
+ def check_depend(self, properties):
+ """
+ Calls self.depend(properties) to see if a task should be run.
+ """
+ if self.depend is not None:
+ return self.depend(properties)
+ else:
+ return True
+
+ def can_task(self):
+ self.depend = can(self.depend)
+ if isinstance(self.recovery_task, BaseTask):
+ self.recovery_task.can_task()
+
+ def uncan_task(self):
+ self.depend = uncan(self.depend)
+ if isinstance(self.recovery_task, BaseTask):
+ self.recovery_task.uncan_task()
+
+class MapTask(BaseTask):
+ """
+ A task that consists of a function and arguments.
+ """
+
+ zi.implements(ITask)
+
+ def __init__(self, function, args=None, kwargs=None, clear_before=False,
+ clear_after=False, retries=0, recovery_task=None, depend=None):
+ """
+ Create a task based on a function, args and kwargs.
+
+ This is a simple type of task that consists of calling:
+ function(*args, **kwargs) and wrapping the result in a `TaskResult`.
+
+ The return value of the function, or a `Failure` wrapping an
+ exception is the task result for this type of task.
+ """
+ BaseTask.__init__(self, clear_before, clear_after, retries,
+ recovery_task, depend)
+ if not isinstance(function, FunctionType):
+ raise TypeError('a task function must be a FunctionType')
+ self.function = function
+ if args is None:
+ self.args = ()
+ else:
+ self.args = args
+ if not isinstance(self.args, (list, tuple)):
+ raise TypeError('a task args must be a list or tuple')
+ if kwargs is None:
+ self.kwargs = {}
+ else:
+ self.kwargs = kwargs
+ if not isinstance(self.kwargs, dict):
+ raise TypeError('a task kwargs must be a dict')
+
+ def submit_task(self, d, queued_engine):
+ d.addCallback(lambda r: queued_engine.push_function(
+ dict(_ipython_task_function=self.function))
+ )
+ d.addCallback(lambda r: queued_engine.push(
+ dict(_ipython_task_args=self.args,_ipython_task_kwargs=self.kwargs))
+ )
+ d.addCallback(lambda r: queued_engine.execute(
+ '_ipython_task_result = _ipython_task_function(*_ipython_task_args,**_ipython_task_kwargs)')
+ )
+ d.addCallback(lambda r: queued_engine.pull('_ipython_task_result'))
+
+ def can_task(self):
+ self.function = can(self.function)
+ BaseTask.can_task(self)
+
+ def uncan_task(self):
+ self.function = uncan(self.function)
+ BaseTask.uncan_task(self)
+
+
+class StringTask(BaseTask):
+ """
+ A task that consists of a string of Python code to run.
+ """
+
+ def __init__(self, expression, pull=None, push=None,
+ clear_before=False, clear_after=False, retries=0,
+ recovery_task=None, depend=None):
+ """
+ Create a task based on a Python expression and variables
+
+ This type of task lets you push a set of variables to the engines
+ namespace, run a Python string in that namespace and then bring back
+ a different set of Python variables as the result.
+
+ Because this type of task can return many results (through the
+ `pull` keyword argument) it returns a special `TaskResult` object
+ that wraps the pulled variables, statistics about the run and
+ any exceptions raised.
+ """
+ if not isinstance(expression, str):
+ raise TypeError('a task expression must be a string')
+ self.expression = expression
+
+ if pull==None:
+ self.pull = ()
+ elif isinstance(pull, str):
+ self.pull = (pull,)
+ elif isinstance(pull, (list, tuple)):
+ self.pull = pull
+ else:
+ raise TypeError('pull must be str or a sequence of strs')
+
+ if push==None:
+ self.push = {}
+ elif isinstance(push, dict):
+ self.push = push
+ else:
+ raise TypeError('push must be a dict')
+
+ BaseTask.__init__(self, clear_before, clear_after, retries,
+ recovery_task, depend)
+
+ def submit_task(self, d, queued_engine):
+ if self.push is not None:
+ d.addCallback(lambda r: queued_engine.push(self.push))
+
+ d.addCallback(lambda r: queued_engine.execute(self.expression))
+
+ if self.pull is not None:
+ d.addCallback(lambda r: queued_engine.pull(self.pull))
+ else:
+ d.addCallback(lambda r: None)
+
+ def process_result(self, result, engine_id):
+ if isinstance(result, failure.Failure):
+ tr = TaskResult(result, engine_id)
+ else:
+ if self.pull is None:
+ resultDict = {}
+ elif len(self.pull) == 1:
+ resultDict = {self.pull[0]:result}
+ else:
+ resultDict = dict(zip(self.pull, result))
+ tr = TaskResult(resultDict, engine_id)
+ # Assign task attributes
+ tr.submitted = self.submitted
+ tr.completed = self.completed
+ tr.duration = self.duration
+ if hasattr(self,'taskid'):
+ tr.taskid = self.taskid
+ else:
+ tr.taskid = None
+ if isinstance(result, failure.Failure):
+ return (False, tr)
+ else:
+ return (True, tr)
+
+class ResultNS(object):
+ """
+ A dict like object for holding the results of a task.
+
+ The result namespace object for use in `TaskResult` objects as tr.ns.
+ It builds an object from a dictionary, such that it has attributes
+ according to the key,value pairs of the dictionary.
+
+ This works by calling setattr on ALL key,value pairs in the dict. If a user
+ chooses to overwrite the `__repr__` or `__getattr__` attributes, they can.
+ This can be a bad idea, as it may corrupt standard behavior of the
+ ns object.
+
+ Examples
+ --------
+
+ >>> ns = ResultNS({'a':17,'foo':range(3)})
+ >>> print ns
+ NS{'a': 17, 'foo': [0, 1, 2]}
+ >>> ns.a
+ 17
+ >>> ns['foo']
+ [0, 1, 2]
+ """
+ def __init__(self, dikt):
+ for k,v in dikt.iteritems():
+ setattr(self,k,v)
+
+ def __repr__(self):
+ l = dir(self)
+ d = {}
+ for k in l:
+ # do not print private objects
+ if k[:2] != '__' and k[-2:] != '__':
+ d[k] = getattr(self, k)
+ return "NS"+repr(d)
+
+ def __getitem__(self, key):
+ return getattr(self, key)
+
+class TaskResult(object):
+ """
+ An object for returning task results for certain types of tasks.
+
+ This object encapsulates the results of a task. On task
+ success it will have a keys attribute that will have a list
+ of the variables that have been pulled back. These variables
+ are accessible as attributes of this class as well. On
+ success the failure attribute will be None.
+
+ In task failure, keys will be empty, but failure will contain
+ the failure object that encapsulates the remote exception.
+ One can also simply call the `raise_exception` method of
+ this class to re-raise any remote exception in the local
+ session.
+
+ The `TaskResult` has a `.ns` member, which is a property for access
+ to the results. If the Task had pull=['a', 'b'], then the
+ Task Result will have attributes `tr.ns.a`, `tr.ns.b` for those values.
+ Accessing `tr.ns` will raise the remote failure if the task failed.
+
+ The `engineid` attribute should have the `engineid` of the engine
+ that ran the task. But, because engines can come and go,
+ the `engineid` may not continue to be
+ valid or accurate.
+
+ The `taskid` attribute simply gives the `taskid` that the task
+ is tracked under.
+ """
+ taskid = None
+
+ def _getNS(self):
+ if isinstance(self.failure, failure.Failure):
+ return self.failure.raiseException()
+ else:
+ return self._ns
+
+ def _setNS(self, v):
+ raise Exception("the ns attribute cannot be changed")
+
+ ns = property(_getNS, _setNS)
+
+ def __init__(self, results, engineid):
+ self.engineid = engineid
+ if isinstance(results, failure.Failure):
+ self.failure = results
+ self.results = {}
+ else:
+ self.results = results
+ self.failure = None
+
+ self._ns = ResultNS(self.results)
+
+ self.keys = self.results.keys()
+
+ def __repr__(self):
+ if self.failure is not None:
+ contents = self.failure
+ else:
+ contents = self.results
+ return "TaskResult[ID:%r]:%r"%(self.taskid, contents)
+
+ def __getitem__(self, key):
+ if self.failure is not None:
+ self.raise_exception()
+ return self.results[key]
+
+ def raise_exception(self):
+ """Re-raise any remote exceptions in the local python session."""
+ if self.failure is not None:
+ self.failure.raiseException()
+
+
+#-----------------------------------------------------------------------------
+# The controller side of things
+#-----------------------------------------------------------------------------
+
+class IWorker(zi.Interface):
+ """The Basic Worker Interface.
+
+ A worked is a representation of an Engine that is ready to run tasks.
+ """
+
+ zi.Attribute("workerid", "the id of the worker")
+
+ def run(task):
+ """Run task in worker's namespace.
+
+ :Parameters:
+ task : a `Task` object
+
+ :Returns: `Deferred` to a tuple of (success, result) where
+ success if a boolean that signifies success or failure
+ and result is the task result.
+ """
+
+
+class WorkerFromQueuedEngine(object):
+ """Adapt an `IQueuedEngine` to an `IWorker` object"""
+
+ zi.implements(IWorker)
+
+ def __init__(self, qe):
+ self.queuedEngine = qe
+ self.workerid = None
+
+ def _get_properties(self):
+ return self.queuedEngine.properties
+
+ properties = property(_get_properties, lambda self, _:None)
+
+ def run(self, task):
+ """Run task in worker's namespace.
+
+ This takes a task and calls methods on the task that actually
+ cause `self.queuedEngine` to do the task. See the methods of
+ `ITask` for more information about how these methods are called.
+
+ :Parameters:
+ task : a `Task` object
+
+ :Returns: `Deferred` to a tuple of (success, result) where
+ success if a boolean that signifies success or failure
+ and result is the task result.
+ """
+ d = defer.succeed(None)
+ d.addCallback(task.start_time)
+ task.pre_task(d, self.queuedEngine)
+ task.submit_task(d, self.queuedEngine)
+ task.post_task(d, self.queuedEngine)
+ d.addBoth(task.stop_time)
+ d.addBoth(task.process_result, self.queuedEngine.id)
+ # At this point, there will be (success, result) coming down the line
+ return d
+
+
+components.registerAdapter(WorkerFromQueuedEngine, es.IEngineQueued, IWorker)
+
+class IScheduler(zi.Interface):
+ """The interface for a Scheduler.
+ """
+ zi.Attribute("nworkers", "the number of unassigned workers")
+ zi.Attribute("ntasks", "the number of unscheduled tasks")
+ zi.Attribute("workerids", "a list of the worker ids")
+ zi.Attribute("taskids", "a list of the task ids")
+
+ def add_task(task, **flags):
+ """Add a task to the queue of the Scheduler.
+
+ :Parameters:
+ task : an `ITask` implementer
+ The task to be queued.
+ flags : dict
+ General keywords for more sophisticated scheduling
+ """
+
+ def pop_task(id=None):
+ """Pops a task object from the queue.
+
+ This gets the next task to be run. If no `id` is requested, the highest priority
+ task is returned.
+
+ :Parameters:
+ id
+ The id of the task to be popped. The default (None) is to return
+ the highest priority task.
+
+ :Returns: an `ITask` implementer
+
+ :Exceptions:
+ IndexError : raised if no taskid in queue
+ """
+
+ def add_worker(worker, **flags):
+ """Add a worker to the worker queue.
+
+ :Parameters:
+ worker : an `IWorker` implementer
+ flags : dict
+ General keywords for more sophisticated scheduling
+ """
+
+ def pop_worker(id=None):
+ """Pops an IWorker object that is ready to do work.
+
+ This gets the next IWorker that is ready to do work.
+
+ :Parameters:
+ id : if specified, will pop worker with workerid=id, else pops
+ highest priority worker. Defaults to None.
+
+ :Returns:
+ an IWorker object
+
+ :Exceptions:
+ IndexError : raised if no workerid in queue
+ """
+
+ def ready():
+ """Returns True if there is something to do, False otherwise"""
+
+ def schedule():
+ """Returns (worker,task) pair for the next task to be run."""
+
+
+class FIFOScheduler(object):
+ """
+ A basic First-In-First-Out (Queue) Scheduler.
+
+ This is the default Scheduler for the `TaskController`.
+ See the docstrings for `IScheduler` for interface details.
+ """
+
+ zi.implements(IScheduler)
+
+ def __init__(self):
+ self.tasks = []
+ self.workers = []
+
+ def _ntasks(self):
+ return len(self.tasks)
+
+ def _nworkers(self):
+ return len(self.workers)
+
+ ntasks = property(_ntasks, lambda self, _:None)
+ nworkers = property(_nworkers, lambda self, _:None)
+
+ def _taskids(self):
+ return [t.taskid for t in self.tasks]
+
+ def _workerids(self):
+ return [w.workerid for w in self.workers]
+
+ taskids = property(_taskids, lambda self,_:None)
+ workerids = property(_workerids, lambda self,_:None)
+
+ def add_task(self, task, **flags):
+ self.tasks.append(task)
+
+ def pop_task(self, id=None):
+ if id is None:
+ return self.tasks.pop(0)
+ else:
+ for i in range(len(self.tasks)):
+ taskid = self.tasks[i].taskid
+ if id == taskid:
+ return self.tasks.pop(i)
+ raise IndexError("No task #%i"%id)
+
+ def add_worker(self, worker, **flags):
+ self.workers.append(worker)
+
+ def pop_worker(self, id=None):
+ if id is None:
+ return self.workers.pop(0)
+ else:
+ for i in range(len(self.workers)):
+ workerid = self.workers[i].workerid
+ if id == workerid:
+ return self.workers.pop(i)
+ raise IndexError("No worker #%i"%id)
+
+ def schedule(self):
+ for t in self.tasks:
+ for w in self.workers:
+ try:# do not allow exceptions to break this
+ # Allow the task to check itself using its
+ # check_depend method.
+ cando = t.check_depend(w.properties)
+ except:
+ cando = False
+ if cando:
+ return self.pop_worker(w.workerid), self.pop_task(t.taskid)
+ return None, None
+
+
+
+class LIFOScheduler(FIFOScheduler):
+ """
+ A Last-In-First-Out (Stack) Scheduler.
+
+ This scheduler should naively reward fast engines by giving
+ them more jobs. This risks starvation, but only in cases with
+ low load, where starvation does not really matter.
+ """
+
+ def add_task(self, task, **flags):
+ # self.tasks.reverse()
+ self.tasks.insert(0, task)
+ # self.tasks.reverse()
+
+ def add_worker(self, worker, **flags):
+ # self.workers.reverse()
+ self.workers.insert(0, worker)
+ # self.workers.reverse()
+
+
+class ITaskController(cs.IControllerBase):
+ """
+ The Task based interface to a `ControllerService` object
+
+ This adapts a `ControllerService` to the ITaskController interface.
+ """
+
+ def run(task):
+ """
+ Run a task.
+
+ :Parameters:
+ task : an IPython `Task` object
+
+ :Returns: the integer ID of the task
+ """
+
+ def get_task_result(taskid, block=False):
+ """
+ Get the result of a task by its ID.
+
+ :Parameters:
+ taskid : int
+ the id of the task whose result is requested
+
+ :Returns: `Deferred` to the task result if the task is done, and None
+ if not.
+
+ :Exceptions:
+ actualResult will be an `IndexError` if no such task has been submitted
+ """
+
+ def abort(taskid):
+ """Remove task from queue if task is has not been submitted.
+
+ If the task has already been submitted, wait for it to finish and discard
+ results and prevent resubmission.
+
+ :Parameters:
+ taskid : the id of the task to be aborted
+
+ :Returns:
+ `Deferred` to abort attempt completion. Will be None on success.
+
+ :Exceptions:
+ deferred will fail with `IndexError` if no such task has been submitted
+ or the task has already completed.
+ """
+
+ def barrier(taskids):
+ """
+ Block until the list of taskids are completed.
+
+ Returns None on success.
+ """
+
+ def spin():
+ """
+ Touch the scheduler, to resume scheduling without submitting a task.
+ """
+
+ def queue_status(verbose=False):
+ """
+ Get a dictionary with the current state of the task queue.
+
+ If verbose is True, then return lists of taskids, otherwise,
+ return the number of tasks with each status.
+ """
+
+ def clear():
+ """
+ Clear all previously run tasks from the task controller.
+
+ This is needed because the task controller keep all task results
+ in memory. This can be a problem is there are many completed
+ tasks. Users should call this periodically to clean out these
+ cached task results.
+ """
+
+
+class TaskController(cs.ControllerAdapterBase):
+ """The Task based interface to a Controller object.
+
+ If you want to use a different scheduler, just subclass this and set
+ the `SchedulerClass` member to the *class* of your chosen scheduler.
+ """
+
+ zi.implements(ITaskController)
+ SchedulerClass = FIFOScheduler
+
+ timeout = 30
+
+ def __init__(self, controller):
+ self.controller = controller
+ self.controller.on_register_engine_do(self.registerWorker, True)
+ self.controller.on_unregister_engine_do(self.unregisterWorker, True)
+ self.taskid = 0
+ self.failurePenalty = 1 # the time in seconds to penalize
+ # a worker for failing a task
+ self.pendingTasks = {} # dict of {workerid:(taskid, task)}
+ self.deferredResults = {} # dict of {taskid:deferred}
+ self.finishedResults = {} # dict of {taskid:actualResult}
+ self.workers = {} # dict of {workerid:worker}
+ self.abortPending = [] # dict of {taskid:abortDeferred}
+ self.idleLater = None # delayed call object for timeout
+ self.scheduler = self.SchedulerClass()
+
+ for id in self.controller.engines.keys():
+ self.workers[id] = IWorker(self.controller.engines[id])
+ self.workers[id].workerid = id
+ self.schedule.add_worker(self.workers[id])
+
+ def registerWorker(self, id):
+ """Called by controller.register_engine."""
+ if self.workers.get(id):
+ raise ValueError("worker with id %s already exists. This should not happen." % id)
+ self.workers[id] = IWorker(self.controller.engines[id])
+ self.workers[id].workerid = id
+ if not self.pendingTasks.has_key(id):# if not working
+ self.scheduler.add_worker(self.workers[id])
+ self.distributeTasks()
+
+ def unregisterWorker(self, id):
+ """Called by controller.unregister_engine"""
+
+ if self.workers.has_key(id):
+ try:
+ self.scheduler.pop_worker(id)
+ except IndexError:
+ pass
+ self.workers.pop(id)
+
+ def _pendingTaskIDs(self):
+ return [t.taskid for t in self.pendingTasks.values()]
+
+ #---------------------------------------------------------------------------
+ # Interface methods
+ #---------------------------------------------------------------------------
+
+ def run(self, task):
+ """
+ Run a task and return `Deferred` to its taskid.
+ """
+ task.taskid = self.taskid
+ task.start = time.localtime()
+ self.taskid += 1
+ d = defer.Deferred()
+ self.scheduler.add_task(task)
+ log.msg('Queuing task: %i' % task.taskid)
+
+ self.deferredResults[task.taskid] = []
+ self.distributeTasks()
+ return defer.succeed(task.taskid)
+
+ def get_task_result(self, taskid, block=False):
+ """
+ Returns a `Deferred` to the task result, or None.
+ """
+ log.msg("Getting task result: %i" % taskid)
+ if self.finishedResults.has_key(taskid):
+ tr = self.finishedResults[taskid]
+ return defer.succeed(tr)
+ elif self.deferredResults.has_key(taskid):
+ if block:
+ d = defer.Deferred()
+ self.deferredResults[taskid].append(d)
+ return d
+ else:
+ return defer.succeed(None)
+ else:
+ return defer.fail(IndexError("task ID not registered: %r" % taskid))
+
+ def abort(self, taskid):
+ """
+ Remove a task from the queue if it has not been run already.
+ """
+ if not isinstance(taskid, int):
+ return defer.fail(failure.Failure(TypeError("an integer task id expected: %r" % taskid)))
+ try:
+ self.scheduler.pop_task(taskid)
+ except IndexError, e:
+ if taskid in self.finishedResults.keys():
+ d = defer.fail(IndexError("Task Already Completed"))
+ elif taskid in self.abortPending:
+ d = defer.fail(IndexError("Task Already Aborted"))
+ elif taskid in self._pendingTaskIDs():# task is pending
+ self.abortPending.append(taskid)
+ d = defer.succeed(None)
+ else:
+ d = defer.fail(e)
+ else:
+ d = defer.execute(self._doAbort, taskid)
+
+ return d
+
+ def barrier(self, taskids):
+ dList = []
+ if isinstance(taskids, int):
+ taskids = [taskids]
+ for id in taskids:
+ d = self.get_task_result(id, block=True)
+ dList.append(d)
+ d = DeferredList(dList, consumeErrors=1)
+ d.addCallbacks(lambda r: None)
+ return d
+
+ def spin(self):
+ return defer.succeed(self.distributeTasks())
+
+ def queue_status(self, verbose=False):
+ pending = self._pendingTaskIDs()
+ failed = []
+ succeeded = []
+ for k,v in self.finishedResults.iteritems():
+ if not isinstance(v, failure.Failure):
+ if hasattr(v,'failure'):
+ if v.failure is None:
+ succeeded.append(k)
+ else:
+ failed.append(k)
+ scheduled = self.scheduler.taskids
+ if verbose:
+ result = dict(pending=pending, failed=failed,
+ succeeded=succeeded, scheduled=scheduled)
+ else:
+ result = dict(pending=len(pending),failed=len(failed),
+ succeeded=len(succeeded),scheduled=len(scheduled))
+ return defer.succeed(result)
+
+ #---------------------------------------------------------------------------
+ # Queue methods
+ #---------------------------------------------------------------------------
+
+ def _doAbort(self, taskid):
+ """
+ Helper function for aborting a pending task.
+ """
+ log.msg("Task aborted: %i" % taskid)
+ result = failure.Failure(error.TaskAborted())
+ self._finishTask(taskid, result)
+ if taskid in self.abortPending:
+ self.abortPending.remove(taskid)
+
+ def _finishTask(self, taskid, result):
+ dlist = self.deferredResults.pop(taskid)
+ # result.taskid = taskid # The TaskResult should save the taskid
+ self.finishedResults[taskid] = result
+ for d in dlist:
+ d.callback(result)
+
+ def distributeTasks(self):
+ """
+ Distribute tasks while self.scheduler has things to do.
+ """
+ log.msg("distributing Tasks")
+ worker, task = self.scheduler.schedule()
+ if not worker and not task:
+ if self.idleLater and self.idleLater.called:# we are inside failIdle
+ self.idleLater = None
+ else:
+ self.checkIdle()
+ return False
+ # else something to do:
+ while worker and task:
+ # get worker and task
+ # add to pending
+ self.pendingTasks[worker.workerid] = task
+ # run/link callbacks
+ d = worker.run(task)
+ log.msg("Running task %i on worker %i" %(task.taskid, worker.workerid))
+ d.addBoth(self.taskCompleted, task.taskid, worker.workerid)
+ worker, task = self.scheduler.schedule()
+ # check for idle timeout:
+ self.checkIdle()
+ return True
+
+ def checkIdle(self):
+ if self.idleLater and not self.idleLater.called:
+ self.idleLater.cancel()
+ if self.scheduler.ntasks and self.workers and \
+ self.scheduler.nworkers == len(self.workers):
+ self.idleLater = reactor.callLater(self.timeout, self.failIdle)
+ else:
+ self.idleLater = None
+
+ def failIdle(self):
+ if not self.distributeTasks():
+ while self.scheduler.ntasks:
+ t = self.scheduler.pop_task()
+ msg = "task %i failed to execute due to unmet dependencies"%t.taskid
+ msg += " for %i seconds"%self.timeout
+ log.msg("Task aborted by timeout: %i" % t.taskid)
+ f = failure.Failure(error.TaskTimeout(msg))
+ self._finishTask(t.taskid, f)
+ self.idleLater = None
+
+
+ def taskCompleted(self, success_and_result, taskid, workerid):
+ """This is the err/callback for a completed task."""
+ success, result = success_and_result
+ try:
+ task = self.pendingTasks.pop(workerid)
+ except:
+ # this should not happen
+ log.msg("Tried to pop bad pending task %i from worker %i"%(taskid, workerid))
+ log.msg("Result: %r"%result)
+ log.msg("Pending tasks: %s"%self.pendingTasks)
+ return
+
+ # Check if aborted while pending
+ aborted = False
+ if taskid in self.abortPending:
+ self._doAbort(taskid)
+ aborted = True
+
+ if not aborted:
+ if not success:
+ log.msg("Task %i failed on worker %i"% (taskid, workerid))
+ if task.retries > 0: # resubmit
+ task.retries -= 1
+ self.scheduler.add_task(task)
+ s = "Resubmitting task %i, %i retries remaining" %(taskid, task.retries)
+ log.msg(s)
+ self.distributeTasks()
+ elif isinstance(task.recovery_task, BaseTask) and \
+ task.recovery_task.retries > -1:
+ # retries = -1 is to prevent infinite recovery_task loop
+ task.retries = -1
+ task.recovery_task.taskid = taskid
+ task = task.recovery_task
+ self.scheduler.add_task(task)
+ s = "Recovering task %i, %i retries remaining" %(taskid, task.retries)
+ log.msg(s)
+ self.distributeTasks()
+ else: # done trying
+ self._finishTask(taskid, result)
+ # wait a second before readmitting a worker that failed
+ # it may have died, and not yet been unregistered
+ reactor.callLater(self.failurePenalty, self.readmitWorker, workerid)
+ else: # we succeeded
+ log.msg("Task completed: %i"% taskid)
+ self._finishTask(taskid, result)
+ self.readmitWorker(workerid)
+ else: # we aborted the task
+ if not success:
+ reactor.callLater(self.failurePenalty, self.readmitWorker, workerid)
+ else:
+ self.readmitWorker(workerid)
+
+ def readmitWorker(self, workerid):
+ """
+ Readmit a worker to the scheduler.
+
+ This is outside `taskCompleted` because of the `failurePenalty` being
+ implemented through `reactor.callLater`.
+ """
+
+ if workerid in self.workers.keys() and workerid not in self.pendingTasks.keys():
+ self.scheduler.add_worker(self.workers[workerid])
+ self.distributeTasks()
+
+ def clear(self):
+ """
+ Clear all previously run tasks from the task controller.
+
+ This is needed because the task controller keep all task results
+ in memory. This can be a problem is there are many completed
+ tasks. Users should call this periodically to clean out these
+ cached task results.
+ """
+ self.finishedResults = {}
+ return defer.succeed(None)
+
+
+components.registerAdapter(TaskController, cs.IControllerBase, ITaskController)
diff --git a/IPython/kernel/taskclient.py b/IPython/kernel/taskclient.py
new file mode 100644
index 0000000..69225fb
--- /dev/null
+++ b/IPython/kernel/taskclient.py
@@ -0,0 +1,180 @@
+# encoding: utf-8
+# -*- test-case-name: IPython.kernel.tests.test_taskcontrollerxmlrpc -*-
+
+"""
+A blocking version of the task client.
+"""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+from zope.interface import Interface, implements
+from twisted.python import components, log
+
+from IPython.kernel.twistedutil import blockingCallFromThread
+from IPython.kernel import task, error
+from IPython.kernel.mapper import (
+ SynchronousTaskMapper,
+ ITaskMapperFactory,
+ IMapper
+)
+from IPython.kernel.parallelfunction import (
+ ParallelFunction,
+ ITaskParallelDecorator
+)
+
+#-------------------------------------------------------------------------------
+# The task client
+#-------------------------------------------------------------------------------
+
+class IBlockingTaskClient(Interface):
+ """
+ A vague interface of the blocking task client
+ """
+ pass
+
+class BlockingTaskClient(object):
+ """
+ A blocking task client that adapts a non-blocking one.
+ """
+
+ implements(
+ IBlockingTaskClient,
+ ITaskMapperFactory,
+ IMapper,
+ ITaskParallelDecorator
+ )
+
+ def __init__(self, task_controller):
+ self.task_controller = task_controller
+ self.block = True
+
+ def run(self, task, block=False):
+ """Run a task on the `TaskController`.
+
+ See the documentation of the `MapTask` and `StringTask` classes for
+ details on how to build a task of different types.
+
+ :Parameters:
+ task : an `ITask` implementer
+
+ :Returns: The int taskid of the submitted task. Pass this to
+ `get_task_result` to get the `TaskResult` object.
+ """
+ tid = blockingCallFromThread(self.task_controller.run, task)
+ if block:
+ return self.get_task_result(tid, block=True)
+ else:
+ return tid
+
+ def get_task_result(self, taskid, block=False):
+ """
+ Get a task result by taskid.
+
+ :Parameters:
+ taskid : int
+ The taskid of the task to be retrieved.
+ block : boolean
+ Should I block until the task is done?
+
+ :Returns: A `TaskResult` object that encapsulates the task result.
+ """
+ return blockingCallFromThread(self.task_controller.get_task_result,
+ taskid, block)
+
+ def abort(self, taskid):
+ """
+ Abort a task by taskid.
+
+ :Parameters:
+ taskid : int
+ The taskid of the task to be aborted.
+ """
+ return blockingCallFromThread(self.task_controller.abort, taskid)
+
+ def barrier(self, taskids):
+ """Block until a set of tasks are completed.
+
+ :Parameters:
+ taskids : list, tuple
+ A sequence of taskids to block on.
+ """
+ return blockingCallFromThread(self.task_controller.barrier, taskids)
+
+ def spin(self):
+ """
+ Touch the scheduler, to resume scheduling without submitting a task.
+
+ This method only needs to be called in unusual situations where the
+ scheduler is idle for some reason.
+ """
+ return blockingCallFromThread(self.task_controller.spin)
+
+ def queue_status(self, verbose=False):
+ """
+ Get a dictionary with the current state of the task queue.
+
+ :Parameters:
+ verbose : boolean
+ If True, return a list of taskids. If False, simply give
+ the number of tasks with each status.
+
+ :Returns:
+ A dict with the queue status.
+ """
+ return blockingCallFromThread(self.task_controller.queue_status, verbose)
+
+ def clear(self):
+ """
+ Clear all previously run tasks from the task controller.
+
+ This is needed because the task controller keep all task results
+ in memory. This can be a problem is there are many completed
+ tasks. Users should call this periodically to clean out these
+ cached task results.
+ """
+ return blockingCallFromThread(self.task_controller.clear)
+
+ def map(self, func, *sequences):
+ """
+ Apply func to *sequences elementwise. Like Python's builtin map.
+
+ This version is load balanced.
+ """
+ return self.mapper().map(func, *sequences)
+
+ def mapper(self, clear_before=False, clear_after=False, retries=0,
+ recovery_task=None, depend=None, block=True):
+ """
+ Create an `IMapper` implementer with a given set of arguments.
+
+ The `IMapper` created using a task controller is load balanced.
+
+ See the documentation for `IPython.kernel.task.BaseTask` for
+ documentation on the arguments to this method.
+ """
+ return SynchronousTaskMapper(self, clear_before=clear_before,
+ clear_after=clear_after, retries=retries,
+ recovery_task=recovery_task, depend=depend, block=block)
+
+ def parallel(self, clear_before=False, clear_after=False, retries=0,
+ recovery_task=None, depend=None, block=True):
+ mapper = self.mapper(clear_before, clear_after, retries,
+ recovery_task, depend, block)
+ pf = ParallelFunction(mapper)
+ return pf
+
+components.registerAdapter(BlockingTaskClient,
+ task.ITaskController, IBlockingTaskClient)
+
+
diff --git a/IPython/kernel/taskfc.py b/IPython/kernel/taskfc.py
new file mode 100644
index 0000000..c559f64
--- /dev/null
+++ b/IPython/kernel/taskfc.py
@@ -0,0 +1,329 @@
+# encoding: utf-8
+# -*- test-case-name: IPython.kernel.tests.test_taskxmlrpc -*-
+"""A Foolscap interface to a TaskController.
+
+This class lets Foolscap clients talk to a TaskController.
+"""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+import cPickle as pickle
+import xmlrpclib, copy
+
+from zope.interface import Interface, implements
+from twisted.internet import defer
+from twisted.python import components, failure
+
+from foolscap import Referenceable
+
+from IPython.kernel.twistedutil import blockingCallFromThread
+from IPython.kernel import error, task as taskmodule, taskclient
+from IPython.kernel.pickleutil import can, uncan
+from IPython.kernel.clientinterfaces import (
+ IFCClientInterfaceProvider,
+ IBlockingClientAdaptor
+)
+from IPython.kernel.mapper import (
+ TaskMapper,
+ ITaskMapperFactory,
+ IMapper
+)
+from IPython.kernel.parallelfunction import (
+ ParallelFunction,
+ ITaskParallelDecorator
+)
+
+#-------------------------------------------------------------------------------
+# The Controller side of things
+#-------------------------------------------------------------------------------
+
+
+class IFCTaskController(Interface):
+ """Foolscap interface to task controller.
+
+ See the documentation of `ITaskController` for more information.
+ """
+ def remote_run(binTask):
+ """"""
+
+ def remote_abort(taskid):
+ """"""
+
+ def remote_get_task_result(taskid, block=False):
+ """"""
+
+ def remote_barrier(taskids):
+ """"""
+
+ def remote_spin():
+ """"""
+
+ def remote_queue_status(verbose):
+ """"""
+
+ def remote_clear():
+ """"""
+
+
+class FCTaskControllerFromTaskController(Referenceable):
+ """
+ Adapt a `TaskController` to an `IFCTaskController`
+
+ This class is used to expose a `TaskController` over the wire using
+ the Foolscap network protocol.
+ """
+
+ implements(IFCTaskController, IFCClientInterfaceProvider)
+
+ def __init__(self, taskController):
+ self.taskController = taskController
+
+ #---------------------------------------------------------------------------
+ # Non interface methods
+ #---------------------------------------------------------------------------
+
+ def packageFailure(self, f):
+ f.cleanFailure()
+ return self.packageSuccess(f)
+
+ def packageSuccess(self, obj):
+ serial = pickle.dumps(obj, 2)
+ return serial
+
+ #---------------------------------------------------------------------------
+ # ITaskController related methods
+ #---------------------------------------------------------------------------
+
+ def remote_run(self, ptask):
+ try:
+ task = pickle.loads(ptask)
+ task.uncan_task()
+ except:
+ d = defer.fail(pickle.UnpickleableError("Could not unmarshal task"))
+ else:
+ d = self.taskController.run(task)
+ d.addCallback(self.packageSuccess)
+ d.addErrback(self.packageFailure)
+ return d
+
+ def remote_abort(self, taskid):
+ d = self.taskController.abort(taskid)
+ d.addCallback(self.packageSuccess)
+ d.addErrback(self.packageFailure)
+ return d
+
+ def remote_get_task_result(self, taskid, block=False):
+ d = self.taskController.get_task_result(taskid, block)
+ d.addCallback(self.packageSuccess)
+ d.addErrback(self.packageFailure)
+ return d
+
+ def remote_barrier(self, taskids):
+ d = self.taskController.barrier(taskids)
+ d.addCallback(self.packageSuccess)
+ d.addErrback(self.packageFailure)
+ return d
+
+ def remote_spin(self):
+ d = self.taskController.spin()
+ d.addCallback(self.packageSuccess)
+ d.addErrback(self.packageFailure)
+ return d
+
+ def remote_queue_status(self, verbose):
+ d = self.taskController.queue_status(verbose)
+ d.addCallback(self.packageSuccess)
+ d.addErrback(self.packageFailure)
+ return d
+
+ def remote_clear(self):
+ return self.taskController.clear()
+
+ def remote_get_client_name(self):
+ return 'IPython.kernel.taskfc.FCTaskClient'
+
+components.registerAdapter(FCTaskControllerFromTaskController,
+ taskmodule.ITaskController, IFCTaskController)
+
+
+#-------------------------------------------------------------------------------
+# The Client side of things
+#-------------------------------------------------------------------------------
+
+class FCTaskClient(object):
+ """
+ Client class for Foolscap exposed `TaskController`.
+
+ This class is an adapter that makes a `RemoteReference` to a
+ `TaskController` look like an actual `ITaskController` on the client side.
+
+ This class also implements `IBlockingClientAdaptor` so that clients can
+ automatically get a blocking version of this class.
+ """
+
+ implements(
+ taskmodule.ITaskController,
+ IBlockingClientAdaptor,
+ ITaskMapperFactory,
+ IMapper,
+ ITaskParallelDecorator
+ )
+
+ def __init__(self, remote_reference):
+ self.remote_reference = remote_reference
+
+ #---------------------------------------------------------------------------
+ # Non interface methods
+ #---------------------------------------------------------------------------
+
+ def unpackage(self, r):
+ return pickle.loads(r)
+
+ #---------------------------------------------------------------------------
+ # ITaskController related methods
+ #---------------------------------------------------------------------------
+ def run(self, task):
+ """Run a task on the `TaskController`.
+
+ See the documentation of the `MapTask` and `StringTask` classes for
+ details on how to build a task of different types.
+
+ :Parameters:
+ task : an `ITask` implementer
+
+ :Returns: The int taskid of the submitted task. Pass this to
+ `get_task_result` to get the `TaskResult` object.
+ """
+ assert isinstance(task, taskmodule.BaseTask), "task must be a Task object!"
+ task.can_task()
+ ptask = pickle.dumps(task, 2)
+ task.uncan_task()
+ d = self.remote_reference.callRemote('run', ptask)
+ d.addCallback(self.unpackage)
+ return d
+
+ def get_task_result(self, taskid, block=False):
+ """
+ Get a task result by taskid.
+
+ :Parameters:
+ taskid : int
+ The taskid of the task to be retrieved.
+ block : boolean
+ Should I block until the task is done?
+
+ :Returns: A `TaskResult` object that encapsulates the task result.
+ """
+ d = self.remote_reference.callRemote('get_task_result', taskid, block)
+ d.addCallback(self.unpackage)
+ return d
+
+ def abort(self, taskid):
+ """
+ Abort a task by taskid.
+
+ :Parameters:
+ taskid : int
+ The taskid of the task to be aborted.
+ """
+ d = self.remote_reference.callRemote('abort', taskid)
+ d.addCallback(self.unpackage)
+ return d
+
+ def barrier(self, taskids):
+ """Block until a set of tasks are completed.
+
+ :Parameters:
+ taskids : list, tuple
+ A sequence of taskids to block on.
+ """
+ d = self.remote_reference.callRemote('barrier', taskids)
+ d.addCallback(self.unpackage)
+ return d
+
+ def spin(self):
+ """
+ Touch the scheduler, to resume scheduling without submitting a task.
+
+ This method only needs to be called in unusual situations where the
+ scheduler is idle for some reason.
+ """
+ d = self.remote_reference.callRemote('spin')
+ d.addCallback(self.unpackage)
+ return d
+
+ def queue_status(self, verbose=False):
+ """
+ Get a dictionary with the current state of the task queue.
+
+ :Parameters:
+ verbose : boolean
+ If True, return a list of taskids. If False, simply give
+ the number of tasks with each status.
+
+ :Returns:
+ A dict with the queue status.
+ """
+ d = self.remote_reference.callRemote('queue_status', verbose)
+ d.addCallback(self.unpackage)
+ return d
+
+ def clear(self):
+ """
+ Clear all previously run tasks from the task controller.
+
+ This is needed because the task controller keep all task results
+ in memory. This can be a problem is there are many completed
+ tasks. Users should call this periodically to clean out these
+ cached task results.
+ """
+ d = self.remote_reference.callRemote('clear')
+ return d
+
+ def adapt_to_blocking_client(self):
+ """
+ Wrap self in a blocking version that implements `IBlockingTaskClient.
+ """
+ from IPython.kernel.taskclient import IBlockingTaskClient
+ return IBlockingTaskClient(self)
+
+ def map(self, func, *sequences):
+ """
+ Apply func to *sequences elementwise. Like Python's builtin map.
+
+ This version is load balanced.
+ """
+ return self.mapper().map(func, *sequences)
+
+ def mapper(self, clear_before=False, clear_after=False, retries=0,
+ recovery_task=None, depend=None, block=True):
+ """
+ Create an `IMapper` implementer with a given set of arguments.
+
+ The `IMapper` created using a task controller is load balanced.
+
+ See the documentation for `IPython.kernel.task.BaseTask` for
+ documentation on the arguments to this method.
+ """
+ return TaskMapper(self, clear_before=clear_before,
+ clear_after=clear_after, retries=retries,
+ recovery_task=recovery_task, depend=depend, block=block)
+
+ def parallel(self, clear_before=False, clear_after=False, retries=0,
+ recovery_task=None, depend=None, block=True):
+ mapper = self.mapper(clear_before, clear_after, retries,
+ recovery_task, depend, block)
+ pf = ParallelFunction(mapper)
+ return pf
+
diff --git a/IPython/kernel/tests/__init__.py b/IPython/kernel/tests/__init__.py
new file mode 100644
index 0000000..bef7dcc
--- /dev/null
+++ b/IPython/kernel/tests/__init__.py
@@ -0,0 +1,10 @@
+# encoding: utf-8
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
diff --git a/IPython/kernel/tests/controllertest.py b/IPython/kernel/tests/controllertest.py
new file mode 100644
index 0000000..5ebfaab
--- /dev/null
+++ b/IPython/kernel/tests/controllertest.py
@@ -0,0 +1,102 @@
+# encoding: utf-8
+
+"""This file contains unittests for the kernel.engineservice.py module.
+
+Things that should be tested:
+
+ - Should the EngineService return Deferred objects?
+ - Run the same tests that are run in shell.py.
+ - Make sure that the Interface is really implemented.
+ - The startService and stopService methods.
+"""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+from twisted.internet import defer
+import zope.interface as zi
+
+from IPython.kernel import engineservice as es
+from IPython.kernel import error
+from IPython.testing.util import DeferredTestCase
+from IPython.kernel.controllerservice import \
+ IControllerCore
+
+
+class IControllerCoreTestCase(object):
+ """Tests for objects that implement IControllerCore.
+
+ This test assumes that self.controller is defined and implements
+ IControllerCore.
+ """
+
+ def testIControllerCoreInterface(self):
+ """Does self.engine claim to implement IEngineCore?"""
+ self.assert_(IControllerCore.providedBy(self.controller))
+
+ def testIControllerCoreInterfaceMethods(self):
+ """Does self.engine have the methods and attributes in IEngireCore."""
+ for m in list(IControllerCore):
+ self.assert_(hasattr(self.controller, m))
+
+ def testRegisterUnregisterEngine(self):
+ engine = es.EngineService()
+ qengine = es.QueuedEngine(engine)
+ regDict = self.controller.register_engine(qengine, 0)
+ self.assert_(isinstance(regDict, dict))
+ self.assert_(regDict.has_key('id'))
+ self.assert_(regDict['id']==0)
+ self.controller.unregister_engine(0)
+ self.assert_(self.controller.engines.get(0, None) == None)
+
+ def testRegisterUnregisterMultipleEngines(self):
+ e1 = es.EngineService()
+ qe1 = es.QueuedEngine(e1)
+ e2 = es.EngineService()
+ qe2 = es.QueuedEngine(e2)
+ rd1 = self.controller.register_engine(qe1, 0)
+ self.assertEquals(rd1['id'], 0)
+ rd2 = self.controller.register_engine(qe2, 1)
+ self.assertEquals(rd2['id'], 1)
+ self.controller.unregister_engine(0)
+ rd1 = self.controller.register_engine(qe1, 0)
+ self.assertEquals(rd1['id'], 0)
+ self.controller.unregister_engine(1)
+ rd2 = self.controller.register_engine(qe2, 0)
+ self.assertEquals(rd2['id'], 1)
+ self.controller.unregister_engine(0)
+ self.controller.unregister_engine(1)
+ self.assertEquals(self.controller.engines,{})
+
+ def testRegisterCallables(self):
+ e1 = es.EngineService()
+ qe1 = es.QueuedEngine(e1)
+ self.registerCallableCalled = ';lkj'
+ self.unregisterCallableCalled = ';lkj'
+ self.controller.on_register_engine_do(self._registerCallable, False)
+ self.controller.on_unregister_engine_do(self._unregisterCallable, False)
+ self.controller.register_engine(qe1, 0)
+ self.assertEquals(self.registerCallableCalled, 'asdf')
+ self.controller.unregister_engine(0)
+ self.assertEquals(self.unregisterCallableCalled, 'asdf')
+ self.controller.on_register_engine_do_not(self._registerCallable)
+ self.controller.on_unregister_engine_do_not(self._unregisterCallable)
+
+ def _registerCallable(self):
+ self.registerCallableCalled = 'asdf'
+
+ def _unregisterCallable(self):
+ self.unregisterCallableCalled = 'asdf'
+
+ def testBadUnregister(self):
+ self.assertRaises(AssertionError, self.controller.unregister_engine, 'foo') \ No newline at end of file
diff --git a/IPython/kernel/tests/engineservicetest.py b/IPython/kernel/tests/engineservicetest.py
new file mode 100644
index 0000000..a107f13
--- /dev/null
+++ b/IPython/kernel/tests/engineservicetest.py
@@ -0,0 +1,377 @@
+# encoding: utf-8
+
+"""Test template for complete engine object"""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+import cPickle as pickle
+
+from twisted.internet import defer, reactor
+from twisted.python import failure
+from twisted.application import service
+import zope.interface as zi
+
+from IPython.kernel import newserialized
+from IPython.kernel import error
+from IPython.kernel.pickleutil import can, uncan
+import IPython.kernel.engineservice as es
+from IPython.kernel.core.interpreter import Interpreter
+from IPython.testing.parametric import Parametric, parametric
+
+#-------------------------------------------------------------------------------
+# Tests
+#-------------------------------------------------------------------------------
+
+
+# A sequence of valid commands run through execute
+validCommands = ['a=5',
+ 'b=10',
+ 'a=5; b=10; c=a+b',
+ 'import math; 2.0*math.pi',
+ """def f():
+ result = 0.0
+ for i in range(10):
+ result += i
+""",
+ 'if 1<2: a=5',
+ """import time
+time.sleep(0.1)""",
+ """from math import cos;
+x = 1.0*cos(0.5)""", # Semicolons lead to Discard ast nodes that should be discarded
+ """s = 1
+s = set()
+ """, # Trailing whitespace should be allowed.
+ """import math
+math.cos(1.0)""", # Test a method call with a discarded return value
+ """x=1.0234
+a=5; b=10""", # Test an embedded semicolon
+ """x=1.0234
+a=5; b=10;""" # Test both an embedded and trailing semicolon
+ ]
+
+# A sequence of commands that raise various exceptions
+invalidCommands = [('a=1/0',ZeroDivisionError),
+ ('print v',NameError),
+ ('l=[];l[0]',IndexError),
+ ("d={};d['a']",KeyError),
+ ("assert 1==0",AssertionError),
+ ("import abababsdbfsbaljasdlja",ImportError),
+ ("raise Exception()",Exception)]
+
+def testf(x):
+ return 2.0*x
+
+globala = 99
+
+def testg(x):
+ return globala*x
+
+class IEngineCoreTestCase(object):
+ """Test an IEngineCore implementer."""
+
+ def createShell(self):
+ return Interpreter()
+
+ def catchQueueCleared(self, f):
+ try:
+ f.raiseException()
+ except error.QueueCleared:
+ pass
+
+ def testIEngineCoreInterface(self):
+ """Does self.engine claim to implement IEngineCore?"""
+ self.assert_(es.IEngineCore.providedBy(self.engine))
+
+ def testIEngineCoreInterfaceMethods(self):
+ """Does self.engine have the methods and attributes in IEngineCore."""
+ for m in list(es.IEngineCore):
+ self.assert_(hasattr(self.engine, m))
+
+ def testIEngineCoreDeferreds(self):
+ d = self.engine.execute('a=5')
+ d.addCallback(lambda _: self.engine.pull('a'))
+ d.addCallback(lambda _: self.engine.get_result())
+ d.addCallback(lambda _: self.engine.keys())
+ d.addCallback(lambda _: self.engine.push(dict(a=10)))
+ return d
+
+ def runTestExecute(self, cmd):
+ self.shell = Interpreter()
+ actual = self.shell.execute(cmd)
+ def compare(computed):
+ actual['id'] = computed['id']
+ self.assertEquals(actual, computed)
+ d = self.engine.execute(cmd)
+ d.addCallback(compare)
+ return d
+
+ @parametric
+ def testExecute(cls):
+ return [(cls.runTestExecute, cmd) for cmd in validCommands]
+
+ def runTestExecuteFailures(self, cmd, exc):
+ def compare(f):
+ self.assertRaises(exc, f.raiseException)
+ d = self.engine.execute(cmd)
+ d.addErrback(compare)
+ return d
+
+ @parametric
+ def testExecuteFailuresEngineService(cls):
+ return [(cls.runTestExecuteFailures, cmd, exc)
+ for cmd, exc in invalidCommands]
+
+ def runTestPushPull(self, o):
+ d = self.engine.push(dict(a=o))
+ d.addCallback(lambda r: self.engine.pull('a'))
+ d.addCallback(lambda r: self.assertEquals(o,r))
+ return d
+
+ @parametric
+ def testPushPull(cls):
+ objs = [10,"hi there",1.2342354,{"p":(1,2)},None]
+ return [(cls.runTestPushPull, o) for o in objs]
+
+ def testPullNameError(self):
+ d = self.engine.push(dict(a=5))
+ d.addCallback(lambda _:self.engine.reset())
+ d.addCallback(lambda _: self.engine.pull("a"))
+ d.addErrback(lambda f: self.assertRaises(NameError, f.raiseException))
+ return d
+
+ def testPushPullFailures(self):
+ d = self.engine.pull('a')
+ d.addErrback(lambda f: self.assertRaises(NameError, f.raiseException))
+ d.addCallback(lambda _: self.engine.execute('l = lambda x: x'))
+ d.addCallback(lambda _: self.engine.pull('l'))
+ d.addErrback(lambda f: self.assertRaises(pickle.PicklingError, f.raiseException))
+ d.addCallback(lambda _: self.engine.push(dict(l=lambda x: x)))
+ d.addErrback(lambda f: self.assertRaises(pickle.PicklingError, f.raiseException))
+ return d
+
+ def testPushPullArray(self):
+ try:
+ import numpy
+ except:
+ return
+ a = numpy.random.random(1000)
+ d = self.engine.push(dict(a=a))
+ d.addCallback(lambda _: self.engine.pull('a'))
+ d.addCallback(lambda b: b==a)
+ d.addCallback(lambda c: c.all())
+ return self.assertDeferredEquals(d, True)
+
+ def testPushFunction(self):
+
+ d = self.engine.push_function(dict(f=testf))
+ d.addCallback(lambda _: self.engine.execute('result = f(10)'))
+ d.addCallback(lambda _: self.engine.pull('result'))
+ d.addCallback(lambda r: self.assertEquals(r, testf(10)))
+ return d
+
+ def testPullFunction(self):
+ d = self.engine.push_function(dict(f=testf, g=testg))
+ d.addCallback(lambda _: self.engine.pull_function(('f','g')))
+ d.addCallback(lambda r: self.assertEquals(r[0](10), testf(10)))
+ return d
+
+ def testPushFunctionGlobal(self):
+ """Make sure that pushed functions pick up the user's namespace for globals."""
+ d = self.engine.push(dict(globala=globala))
+ d.addCallback(lambda _: self.engine.push_function(dict(g=testg)))
+ d.addCallback(lambda _: self.engine.execute('result = g(10)'))
+ d.addCallback(lambda _: self.engine.pull('result'))
+ d.addCallback(lambda r: self.assertEquals(r, testg(10)))
+ return d
+
+ def testGetResultFailure(self):
+ d = self.engine.get_result(None)
+ d.addErrback(lambda f: self.assertRaises(IndexError, f.raiseException))
+ d.addCallback(lambda _: self.engine.get_result(10))
+ d.addErrback(lambda f: self.assertRaises(IndexError, f.raiseException))
+ return d
+
+ def runTestGetResult(self, cmd):
+ self.shell = Interpreter()
+ actual = self.shell.execute(cmd)
+ def compare(computed):
+ actual['id'] = computed['id']
+ self.assertEquals(actual, computed)
+ d = self.engine.execute(cmd)
+ d.addCallback(lambda r: self.engine.get_result(r['number']))
+ d.addCallback(compare)
+ return d
+
+ @parametric
+ def testGetResult(cls):
+ return [(cls.runTestGetResult, cmd) for cmd in validCommands]
+
+ def testGetResultDefault(self):
+ cmd = 'a=5'
+ shell = self.createShell()
+ shellResult = shell.execute(cmd)
+ def popit(dikt, key):
+ dikt.pop(key)
+ return dikt
+ d = self.engine.execute(cmd)
+ d.addCallback(lambda _: self.engine.get_result())
+ d.addCallback(lambda r: self.assertEquals(shellResult, popit(r,'id')))
+ return d
+
+ def testKeys(self):
+ d = self.engine.keys()
+ d.addCallback(lambda s: isinstance(s, list))
+ d.addCallback(lambda r: self.assertEquals(r, True))
+ return d
+
+Parametric(IEngineCoreTestCase)
+
+class IEngineSerializedTestCase(object):
+ """Test an IEngineCore implementer."""
+
+ def testIEngineSerializedInterface(self):
+ """Does self.engine claim to implement IEngineCore?"""
+ self.assert_(es.IEngineSerialized.providedBy(self.engine))
+
+ def testIEngineSerializedInterfaceMethods(self):
+ """Does self.engine have the methods and attributes in IEngineCore."""
+ for m in list(es.IEngineSerialized):
+ self.assert_(hasattr(self.engine, m))
+
+ def testIEngineSerializedDeferreds(self):
+ dList = []
+ d = self.engine.push_serialized(dict(key=newserialized.serialize(12345)))
+ self.assert_(isinstance(d, defer.Deferred))
+ dList.append(d)
+ d = self.engine.pull_serialized('key')
+ self.assert_(isinstance(d, defer.Deferred))
+ dList.append(d)
+ D = defer.DeferredList(dList)
+ return D
+
+ def testPushPullSerialized(self):
+ objs = [10,"hi there",1.2342354,{"p":(1,2)}]
+ d = defer.succeed(None)
+ for o in objs:
+ self.engine.push_serialized(dict(key=newserialized.serialize(o)))
+ value = self.engine.pull_serialized('key')
+ value.addCallback(lambda serial: newserialized.IUnSerialized(serial).getObject())
+ d = self.assertDeferredEquals(value,o,d)
+ return d
+
+ def testPullSerializedFailures(self):
+ d = self.engine.pull_serialized('a')
+ d.addErrback(lambda f: self.assertRaises(NameError, f.raiseException))
+ d.addCallback(lambda _: self.engine.execute('l = lambda x: x'))
+ d.addCallback(lambda _: self.engine.pull_serialized('l'))
+ d.addErrback(lambda f: self.assertRaises(pickle.PicklingError, f.raiseException))
+ return d
+
+Parametric(IEngineSerializedTestCase)
+
+class IEngineQueuedTestCase(object):
+ """Test an IEngineQueued implementer."""
+
+ def testIEngineQueuedInterface(self):
+ """Does self.engine claim to implement IEngineQueued?"""
+ self.assert_(es.IEngineQueued.providedBy(self.engine))
+
+ def testIEngineQueuedInterfaceMethods(self):
+ """Does self.engine have the methods and attributes in IEngineQueued."""
+ for m in list(es.IEngineQueued):
+ self.assert_(hasattr(self.engine, m))
+
+ def testIEngineQueuedDeferreds(self):
+ dList = []
+ d = self.engine.clear_queue()
+ self.assert_(isinstance(d, defer.Deferred))
+ dList.append(d)
+ d = self.engine.queue_status()
+ self.assert_(isinstance(d, defer.Deferred))
+ dList.append(d)
+ D = defer.DeferredList(dList)
+ return D
+
+ def testClearQueue(self):
+ result = self.engine.clear_queue()
+ d1 = self.assertDeferredEquals(result, None)
+ d1.addCallback(lambda _: self.engine.queue_status())
+ d2 = self.assertDeferredEquals(d1, {'queue':[], 'pending':'None'})
+ return d2
+
+ def testQueueStatus(self):
+ result = self.engine.queue_status()
+ result.addCallback(lambda r: 'queue' in r and 'pending' in r)
+ d = self.assertDeferredEquals(result, True)
+ return d
+
+Parametric(IEngineQueuedTestCase)
+
+class IEnginePropertiesTestCase(object):
+ """Test an IEngineProperties implementor."""
+
+ def testIEnginePropertiesInterface(self):
+ """Does self.engine claim to implement IEngineProperties?"""
+ self.assert_(es.IEngineProperties.providedBy(self.engine))
+
+ def testIEnginePropertiesInterfaceMethods(self):
+ """Does self.engine have the methods and attributes in IEngineProperties."""
+ for m in list(es.IEngineProperties):
+ self.assert_(hasattr(self.engine, m))
+
+ def testGetSetProperties(self):
+ dikt = dict(a=5, b='asdf', c=True, d=None, e=range(5))
+ d = self.engine.set_properties(dikt)
+ d.addCallback(lambda r: self.engine.get_properties())
+ d = self.assertDeferredEquals(d, dikt)
+ d.addCallback(lambda r: self.engine.get_properties(('c',)))
+ d = self.assertDeferredEquals(d, {'c': dikt['c']})
+ d.addCallback(lambda r: self.engine.set_properties(dict(c=False)))
+ d.addCallback(lambda r: self.engine.get_properties(('c', 'd')))
+ d = self.assertDeferredEquals(d, dict(c=False, d=None))
+ return d
+
+ def testClearProperties(self):
+ dikt = dict(a=5, b='asdf', c=True, d=None, e=range(5))
+ d = self.engine.set_properties(dikt)
+ d.addCallback(lambda r: self.engine.clear_properties())
+ d.addCallback(lambda r: self.engine.get_properties())
+ d = self.assertDeferredEquals(d, {})
+ return d
+
+ def testDelHasProperties(self):
+ dikt = dict(a=5, b='asdf', c=True, d=None, e=range(5))
+ d = self.engine.set_properties(dikt)
+ d.addCallback(lambda r: self.engine.del_properties(('b','e')))
+ d.addCallback(lambda r: self.engine.has_properties(('a','b','c','d','e')))
+ d = self.assertDeferredEquals(d, [True, False, True, True, False])
+ return d
+
+ def testStrictDict(self):
+ s = """from IPython.kernel.engineservice import get_engine; p = get_engine(%s).properties"""%self.engine.id
+ d = self.engine.execute(s)
+ # These 3 lines cause a weird testing error on some platforms (OS X).
+ # I am leaving them here in case they are masking some really
+ # weird reactor issue. For now I will just keep my eye on this.
+ d.addCallback(lambda r: self.engine.execute("p['a'] = lambda _:None"))
+ d.addErrback(lambda f: self.assertRaises(error.InvalidProperty,
+ f.raiseException))
+ # Below here seems to be fine
+ d.addCallback(lambda r: self.engine.execute("p['a'] = range(5)"))
+ d.addCallback(lambda r: self.engine.execute("p['a'].append(5)"))
+ d.addCallback(lambda r: self.engine.get_properties('a'))
+ d = self.assertDeferredEquals(d, dict(a=range(5)))
+ return d
+
+Parametric(IEnginePropertiesTestCase)
diff --git a/IPython/kernel/tests/multienginetest.py b/IPython/kernel/tests/multienginetest.py
new file mode 100644
index 0000000..39fa2c0
--- /dev/null
+++ b/IPython/kernel/tests/multienginetest.py
@@ -0,0 +1,827 @@
+# encoding: utf-8
+
+""""""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+from twisted.internet import defer
+
+from IPython.kernel import engineservice as es
+from IPython.kernel import multiengine as me
+from IPython.kernel import newserialized
+from IPython.testing import util
+from IPython.testing.parametric import parametric, Parametric
+from IPython.kernel import newserialized
+from IPython.kernel.util import printer
+from IPython.kernel.error import (InvalidEngineID,
+ NoEnginesRegistered,
+ CompositeError,
+ InvalidDeferredID)
+from IPython.kernel.tests.engineservicetest import validCommands, invalidCommands
+from IPython.kernel.core.interpreter import Interpreter
+
+
+#-------------------------------------------------------------------------------
+# Base classes and utilities
+#-------------------------------------------------------------------------------
+
+class IMultiEngineBaseTestCase(object):
+ """Basic utilities for working with multiengine tests.
+
+ Some subclass should define:
+
+ * self.multiengine
+ * self.engines to keep track of engines for clean up"""
+
+ def createShell(self):
+ return Interpreter()
+
+ def addEngine(self, n=1):
+ for i in range(n):
+ e = es.EngineService()
+ e.startService()
+ regDict = self.controller.register_engine(es.QueuedEngine(e), None)
+ e.id = regDict['id']
+ self.engines.append(e)
+
+
+def testf(x):
+ return 2.0*x
+
+
+globala = 99
+
+
+def testg(x):
+ return globala*x
+
+
+def isdid(did):
+ if not isinstance(did, str):
+ return False
+ if not len(did)==40:
+ return False
+ return True
+
+
+def _raise_it(f):
+ try:
+ f.raiseException()
+ except CompositeError, e:
+ e.raise_exception()
+
+#-------------------------------------------------------------------------------
+# IMultiEngineTestCase
+#-------------------------------------------------------------------------------
+
+class IMultiEngineTestCase(IMultiEngineBaseTestCase):
+ """A test for any object that implements IEngineMultiplexer.
+
+ self.multiengine must be defined and implement IEngineMultiplexer.
+ """
+
+ def testIMultiEngineInterface(self):
+ """Does self.engine claim to implement IEngineCore?"""
+ self.assert_(me.IEngineMultiplexer.providedBy(self.multiengine))
+ self.assert_(me.IMultiEngine.providedBy(self.multiengine))
+
+ def testIEngineMultiplexerInterfaceMethods(self):
+ """Does self.engine have the methods and attributes in IEngineCore."""
+ for m in list(me.IEngineMultiplexer):
+ self.assert_(hasattr(self.multiengine, m))
+
+ def testIEngineMultiplexerDeferreds(self):
+ self.addEngine(1)
+ d= self.multiengine.execute('a=5', targets=0)
+ d.addCallback(lambda _: self.multiengine.push(dict(a=5),targets=0))
+ d.addCallback(lambda _: self.multiengine.push(dict(a=5, b='asdf', c=[1,2,3]),targets=0))
+ d.addCallback(lambda _: self.multiengine.pull(('a','b','c'),targets=0))
+ d.addCallback(lambda _: self.multiengine.get_result(targets=0))
+ d.addCallback(lambda _: self.multiengine.reset(targets=0))
+ d.addCallback(lambda _: self.multiengine.keys(targets=0))
+ d.addCallback(lambda _: self.multiengine.push_serialized(dict(a=newserialized.serialize(10)),targets=0))
+ d.addCallback(lambda _: self.multiengine.pull_serialized('a',targets=0))
+ d.addCallback(lambda _: self.multiengine.clear_queue(targets=0))
+ d.addCallback(lambda _: self.multiengine.queue_status(targets=0))
+ return d
+
+ def testInvalidEngineID(self):
+ self.addEngine(1)
+ badID = 100
+ d = self.multiengine.execute('a=5', targets=badID)
+ d.addErrback(lambda f: self.assertRaises(InvalidEngineID, f.raiseException))
+ d.addCallback(lambda _: self.multiengine.push(dict(a=5), targets=badID))
+ d.addErrback(lambda f: self.assertRaises(InvalidEngineID, f.raiseException))
+ d.addCallback(lambda _: self.multiengine.pull('a', targets=badID))
+ d.addErrback(lambda f: self.assertRaises(InvalidEngineID, f.raiseException))
+ d.addCallback(lambda _: self.multiengine.reset(targets=badID))
+ d.addErrback(lambda f: self.assertRaises(InvalidEngineID, f.raiseException))
+ d.addCallback(lambda _: self.multiengine.keys(targets=badID))
+ d.addErrback(lambda f: self.assertRaises(InvalidEngineID, f.raiseException))
+ d.addCallback(lambda _: self.multiengine.push_serialized(dict(a=newserialized.serialize(10)), targets=badID))
+ d.addErrback(lambda f: self.assertRaises(InvalidEngineID, f.raiseException))
+ d.addCallback(lambda _: self.multiengine.pull_serialized('a', targets=badID))
+ d.addErrback(lambda f: self.assertRaises(InvalidEngineID, f.raiseException))
+ d.addCallback(lambda _: self.multiengine.queue_status(targets=badID))
+ d.addErrback(lambda f: self.assertRaises(InvalidEngineID, f.raiseException))
+ return d
+
+ def testNoEnginesRegistered(self):
+ badID = 'all'
+ d= self.multiengine.execute('a=5', targets=badID)
+ d.addErrback(lambda f: self.assertRaises(NoEnginesRegistered, f.raiseException))
+ d.addCallback(lambda _: self.multiengine.push(dict(a=5), targets=badID))
+ d.addErrback(lambda f: self.assertRaises(NoEnginesRegistered, f.raiseException))
+ d.addCallback(lambda _: self.multiengine.pull('a', targets=badID))
+ d.addErrback(lambda f: self.assertRaises(NoEnginesRegistered, f.raiseException))
+ d.addCallback(lambda _: self.multiengine.get_result(targets=badID))
+ d.addErrback(lambda f: self.assertRaises(NoEnginesRegistered, f.raiseException))
+ d.addCallback(lambda _: self.multiengine.reset(targets=badID))
+ d.addErrback(lambda f: self.assertRaises(NoEnginesRegistered, f.raiseException))
+ d.addCallback(lambda _: self.multiengine.keys(targets=badID))
+ d.addErrback(lambda f: self.assertRaises(NoEnginesRegistered, f.raiseException))
+ d.addCallback(lambda _: self.multiengine.push_serialized(dict(a=newserialized.serialize(10)), targets=badID))
+ d.addErrback(lambda f: self.assertRaises(NoEnginesRegistered, f.raiseException))
+ d.addCallback(lambda _: self.multiengine.pull_serialized('a', targets=badID))
+ d.addErrback(lambda f: self.assertRaises(NoEnginesRegistered, f.raiseException))
+ d.addCallback(lambda _: self.multiengine.queue_status(targets=badID))
+ d.addErrback(lambda f: self.assertRaises(NoEnginesRegistered, f.raiseException))
+ return d
+
+ def runExecuteAll(self, d, cmd, shell):
+ actual = shell.execute(cmd)
+ d.addCallback(lambda _: self.multiengine.execute(cmd))
+ def compare(result):
+ for r in result:
+ actual['id'] = r['id']
+ self.assertEquals(r, actual)
+ d.addCallback(compare)
+
+ def testExecuteAll(self):
+ self.addEngine(4)
+ d= defer.Deferred()
+ shell = Interpreter()
+ for cmd in validCommands:
+ self.runExecuteAll(d, cmd, shell)
+ d.callback(None)
+ return d
+
+ # The following two methods show how to do parametrized
+ # tests. This is really slick! Same is used above.
+ def runExecuteFailures(self, cmd, exc):
+ self.addEngine(4)
+ d= self.multiengine.execute(cmd)
+ d.addErrback(lambda f: self.assertRaises(exc, _raise_it, f))
+ return d
+
+ @parametric
+ def testExecuteFailuresMultiEng(cls):
+ return [(cls.runExecuteFailures,cmd,exc) for
+ cmd,exc in invalidCommands]
+
+ def testPushPull(self):
+ self.addEngine(1)
+ objs = [10,"hi there",1.2342354,{"p":(1,2)}]
+ d= self.multiengine.push(dict(key=objs[0]), targets=0)
+ d.addCallback(lambda _: self.multiengine.pull('key', targets=0))
+ d.addCallback(lambda r: self.assertEquals(r, [objs[0]]))
+ d.addCallback(lambda _: self.multiengine.push(dict(key=objs[1]), targets=0))
+ d.addCallback(lambda _: self.multiengine.pull('key', targets=0))
+ d.addCallback(lambda r: self.assertEquals(r, [objs[1]]))
+ d.addCallback(lambda _: self.multiengine.push(dict(key=objs[2]), targets=0))
+ d.addCallback(lambda _: self.multiengine.pull('key', targets=0))
+ d.addCallback(lambda r: self.assertEquals(r, [objs[2]]))
+ d.addCallback(lambda _: self.multiengine.push(dict(key=objs[3]), targets=0))
+ d.addCallback(lambda _: self.multiengine.pull('key', targets=0))
+ d.addCallback(lambda r: self.assertEquals(r, [objs[3]]))
+ d.addCallback(lambda _: self.multiengine.reset(targets=0))
+ d.addCallback(lambda _: self.multiengine.pull('a', targets=0))
+ d.addErrback(lambda f: self.assertRaises(NameError, _raise_it, f))
+ d.addCallback(lambda _: self.multiengine.push(dict(a=10,b=20)))
+ d.addCallback(lambda _: self.multiengine.pull(('a','b')))
+ d.addCallback(lambda r: self.assertEquals(r, [[10,20]]))
+ return d
+
+ def testPushPullAll(self):
+ self.addEngine(4)
+ d= self.multiengine.push(dict(a=10))
+ d.addCallback(lambda _: self.multiengine.pull('a'))
+ d.addCallback(lambda r: self.assert_(r==[10,10,10,10]))
+ d.addCallback(lambda _: self.multiengine.push(dict(a=10, b=20)))
+ d.addCallback(lambda _: self.multiengine.pull(('a','b')))
+ d.addCallback(lambda r: self.assert_(r==4*[[10,20]]))
+ d.addCallback(lambda _: self.multiengine.push(dict(a=10, b=20), targets=0))
+ d.addCallback(lambda _: self.multiengine.pull(('a','b'), targets=0))
+ d.addCallback(lambda r: self.assert_(r==[[10,20]]))
+ d.addCallback(lambda _: self.multiengine.push(dict(a=None, b=None), targets=0))
+ d.addCallback(lambda _: self.multiengine.pull(('a','b'), targets=0))
+ d.addCallback(lambda r: self.assert_(r==[[None,None]]))
+ return d
+
+ def testPushPullSerialized(self):
+ self.addEngine(1)
+ objs = [10,"hi there",1.2342354,{"p":(1,2)}]
+ d= self.multiengine.push_serialized(dict(key=newserialized.serialize(objs[0])), targets=0)
+ d.addCallback(lambda _: self.multiengine.pull_serialized('key', targets=0))
+ d.addCallback(lambda serial: newserialized.IUnSerialized(serial[0]).getObject())
+ d.addCallback(lambda r: self.assertEquals(r, objs[0]))
+ d.addCallback(lambda _: self.multiengine.push_serialized(dict(key=newserialized.serialize(objs[1])), targets=0))
+ d.addCallback(lambda _: self.multiengine.pull_serialized('key', targets=0))
+ d.addCallback(lambda serial: newserialized.IUnSerialized(serial[0]).getObject())
+ d.addCallback(lambda r: self.assertEquals(r, objs[1]))
+ d.addCallback(lambda _: self.multiengine.push_serialized(dict(key=newserialized.serialize(objs[2])), targets=0))
+ d.addCallback(lambda _: self.multiengine.pull_serialized('key', targets=0))
+ d.addCallback(lambda serial: newserialized.IUnSerialized(serial[0]).getObject())
+ d.addCallback(lambda r: self.assertEquals(r, objs[2]))
+ d.addCallback(lambda _: self.multiengine.push_serialized(dict(key=newserialized.serialize(objs[3])), targets=0))
+ d.addCallback(lambda _: self.multiengine.pull_serialized('key', targets=0))
+ d.addCallback(lambda serial: newserialized.IUnSerialized(serial[0]).getObject())
+ d.addCallback(lambda r: self.assertEquals(r, objs[3]))
+ d.addCallback(lambda _: self.multiengine.push(dict(a=10,b=range(5)), targets=0))
+ d.addCallback(lambda _: self.multiengine.pull_serialized(('a','b'), targets=0))
+ d.addCallback(lambda serial: [newserialized.IUnSerialized(s).getObject() for s in serial[0]])
+ d.addCallback(lambda r: self.assertEquals(r, [10, range(5)]))
+ d.addCallback(lambda _: self.multiengine.reset(targets=0))
+ d.addCallback(lambda _: self.multiengine.pull_serialized('a', targets=0))
+ d.addErrback(lambda f: self.assertRaises(NameError, _raise_it, f))
+ return d
+
+ objs = [10,"hi there",1.2342354,{"p":(1,2)}]
+ d= defer.succeed(None)
+ for o in objs:
+ self.multiengine.push_serialized(0, key=newserialized.serialize(o))
+ value = self.multiengine.pull_serialized(0, 'key')
+ value.addCallback(lambda serial: newserialized.IUnSerialized(serial[0]).getObject())
+ d = self.assertDeferredEquals(value,o,d)
+ return d
+
+ def runGetResultAll(self, d, cmd, shell):
+ actual = shell.execute(cmd)
+ d.addCallback(lambda _: self.multiengine.execute(cmd))
+ d.addCallback(lambda _: self.multiengine.get_result())
+ def compare(result):
+ for r in result:
+ actual['id'] = r['id']
+ self.assertEquals(r, actual)
+ d.addCallback(compare)
+
+ def testGetResultAll(self):
+ self.addEngine(4)
+ d= defer.Deferred()
+ shell = Interpreter()
+ for cmd in validCommands:
+ self.runGetResultAll(d, cmd, shell)
+ d.callback(None)
+ return d
+
+ def testGetResultDefault(self):
+ self.addEngine(1)
+ target = 0
+ cmd = 'a=5'
+ shell = self.createShell()
+ shellResult = shell.execute(cmd)
+ def popit(dikt, key):
+ dikt.pop(key)
+ return dikt
+ d= self.multiengine.execute(cmd, targets=target)
+ d.addCallback(lambda _: self.multiengine.get_result(targets=target))
+ d.addCallback(lambda r: self.assertEquals(shellResult, popit(r[0],'id')))
+ return d
+
+ def testGetResultFailure(self):
+ self.addEngine(1)
+ d= self.multiengine.get_result(None, targets=0)
+ d.addErrback(lambda f: self.assertRaises(IndexError, _raise_it, f))
+ d.addCallback(lambda _: self.multiengine.get_result(10, targets=0))
+ d.addErrback(lambda f: self.assertRaises(IndexError, _raise_it, f))
+ return d
+
+ def testPushFunction(self):
+ self.addEngine(1)
+ d= self.multiengine.push_function(dict(f=testf), targets=0)
+ d.addCallback(lambda _: self.multiengine.execute('result = f(10)', targets=0))
+ d.addCallback(lambda _: self.multiengine.pull('result', targets=0))
+ d.addCallback(lambda r: self.assertEquals(r[0], testf(10)))
+ d.addCallback(lambda _: self.multiengine.push(dict(globala=globala), targets=0))
+ d.addCallback(lambda _: self.multiengine.push_function(dict(g=testg), targets=0))
+ d.addCallback(lambda _: self.multiengine.execute('result = g(10)', targets=0))
+ d.addCallback(lambda _: self.multiengine.pull('result', targets=0))
+ d.addCallback(lambda r: self.assertEquals(r[0], testg(10)))
+ return d
+
+ def testPullFunction(self):
+ self.addEngine(1)
+ d= self.multiengine.push(dict(a=globala), targets=0)
+ d.addCallback(lambda _: self.multiengine.push_function(dict(f=testf), targets=0))
+ d.addCallback(lambda _: self.multiengine.pull_function('f', targets=0))
+ d.addCallback(lambda r: self.assertEquals(r[0](10), testf(10)))
+ d.addCallback(lambda _: self.multiengine.execute("def g(x): return x*x", targets=0))
+ d.addCallback(lambda _: self.multiengine.pull_function(('f','g'),targets=0))
+ d.addCallback(lambda r: self.assertEquals((r[0][0](10),r[0][1](10)), (testf(10), 100)))
+ return d
+
+ def testPushFunctionAll(self):
+ self.addEngine(4)
+ d= self.multiengine.push_function(dict(f=testf))
+ d.addCallback(lambda _: self.multiengine.execute('result = f(10)'))
+ d.addCallback(lambda _: self.multiengine.pull('result'))
+ d.addCallback(lambda r: self.assertEquals(r, 4*[testf(10)]))
+ d.addCallback(lambda _: self.multiengine.push(dict(globala=globala)))
+ d.addCallback(lambda _: self.multiengine.push_function(dict(testg=testg)))
+ d.addCallback(lambda _: self.multiengine.execute('result = testg(10)'))
+ d.addCallback(lambda _: self.multiengine.pull('result'))
+ d.addCallback(lambda r: self.assertEquals(r, 4*[testg(10)]))
+ return d
+
+ def testPullFunctionAll(self):
+ self.addEngine(4)
+ d= self.multiengine.push_function(dict(f=testf))
+ d.addCallback(lambda _: self.multiengine.pull_function('f'))
+ d.addCallback(lambda r: self.assertEquals([func(10) for func in r], 4*[testf(10)]))
+ return d
+
+ def testGetIDs(self):
+ self.addEngine(1)
+ d= self.multiengine.get_ids()
+ d.addCallback(lambda r: self.assertEquals(r, [0]))
+ d.addCallback(lambda _: self.addEngine(3))
+ d.addCallback(lambda _: self.multiengine.get_ids())
+ d.addCallback(lambda r: self.assertEquals(r, [0,1,2,3]))
+ return d
+
+ def testClearQueue(self):
+ self.addEngine(4)
+ d= self.multiengine.clear_queue()
+ d.addCallback(lambda r: self.assertEquals(r,4*[None]))
+ return d
+
+ def testQueueStatus(self):
+ self.addEngine(4)
+ d= self.multiengine.queue_status(targets=0)
+ d.addCallback(lambda r: self.assert_(isinstance(r[0],tuple)))
+ return d
+
+ def testGetSetProperties(self):
+ self.addEngine(4)
+ dikt = dict(a=5, b='asdf', c=True, d=None, e=range(5))
+ d= self.multiengine.set_properties(dikt)
+ d.addCallback(lambda r: self.multiengine.get_properties())
+ d.addCallback(lambda r: self.assertEquals(r, 4*[dikt]))
+ d.addCallback(lambda r: self.multiengine.get_properties(('c',)))
+ d.addCallback(lambda r: self.assertEquals(r, 4*[{'c': dikt['c']}]))
+ d.addCallback(lambda r: self.multiengine.set_properties(dict(c=False)))
+ d.addCallback(lambda r: self.multiengine.get_properties(('c', 'd')))
+ d.addCallback(lambda r: self.assertEquals(r, 4*[dict(c=False, d=None)]))
+ return d
+
+ def testClearProperties(self):
+ self.addEngine(4)
+ dikt = dict(a=5, b='asdf', c=True, d=None, e=range(5))
+ d= self.multiengine.set_properties(dikt)
+ d.addCallback(lambda r: self.multiengine.clear_properties())
+ d.addCallback(lambda r: self.multiengine.get_properties())
+ d.addCallback(lambda r: self.assertEquals(r, 4*[{}]))
+ return d
+
+ def testDelHasProperties(self):
+ self.addEngine(4)
+ dikt = dict(a=5, b='asdf', c=True, d=None, e=range(5))
+ d= self.multiengine.set_properties(dikt)
+ d.addCallback(lambda r: self.multiengine.del_properties(('b','e')))
+ d.addCallback(lambda r: self.multiengine.has_properties(('a','b','c','d','e')))
+ d.addCallback(lambda r: self.assertEquals(r, 4*[[True, False, True, True, False]]))
+ return d
+
+Parametric(IMultiEngineTestCase)
+
+#-------------------------------------------------------------------------------
+# ISynchronousMultiEngineTestCase
+#-------------------------------------------------------------------------------
+
+class ISynchronousMultiEngineTestCase(IMultiEngineBaseTestCase):
+
+ def testISynchronousMultiEngineInterface(self):
+ """Does self.engine claim to implement IEngineCore?"""
+ self.assert_(me.ISynchronousEngineMultiplexer.providedBy(self.multiengine))
+ self.assert_(me.ISynchronousMultiEngine.providedBy(self.multiengine))
+
+ def testExecute(self):
+ self.addEngine(4)
+ execute = self.multiengine.execute
+ d= execute('a=5', targets=0, block=True)
+ d.addCallback(lambda r: self.assert_(len(r)==1))
+ d.addCallback(lambda _: execute('b=10'))
+ d.addCallback(lambda r: self.assert_(len(r)==4))
+ d.addCallback(lambda _: execute('c=30', block=False))
+ d.addCallback(lambda did: self.assert_(isdid(did)))
+ d.addCallback(lambda _: execute('d=[0,1,2]', block=False))
+ d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True))
+ d.addCallback(lambda r: self.assert_(len(r)==4))
+ return d
+
+ def testPushPull(self):
+ data = dict(a=10, b=1.05, c=range(10), d={'e':(1,2),'f':'hi'})
+ self.addEngine(4)
+ push = self.multiengine.push
+ pull = self.multiengine.pull
+ d= push({'data':data}, targets=0)
+ d.addCallback(lambda r: pull('data', targets=0))
+ d.addCallback(lambda r: self.assertEqual(r,[data]))
+ d.addCallback(lambda _: push({'data':data}))
+ d.addCallback(lambda r: pull('data'))
+ d.addCallback(lambda r: self.assertEqual(r,4*[data]))
+ d.addCallback(lambda _: push({'data':data}, block=False))
+ d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True))
+ d.addCallback(lambda _: pull('data', block=False))
+ d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True))
+ d.addCallback(lambda r: self.assertEqual(r,4*[data]))
+ d.addCallback(lambda _: push(dict(a=10,b=20)))
+ d.addCallback(lambda _: pull(('a','b')))
+ d.addCallback(lambda r: self.assertEquals(r, 4*[[10,20]]))
+ return d
+
+ def testPushPullFunction(self):
+ self.addEngine(4)
+ pushf = self.multiengine.push_function
+ pullf = self.multiengine.pull_function
+ push = self.multiengine.push
+ pull = self.multiengine.pull
+ execute = self.multiengine.execute
+ d= pushf({'testf':testf}, targets=0)
+ d.addCallback(lambda r: pullf('testf', targets=0))
+ d.addCallback(lambda r: self.assertEqual(r[0](1.0), testf(1.0)))
+ d.addCallback(lambda _: execute('r = testf(10)', targets=0))
+ d.addCallback(lambda _: pull('r', targets=0))
+ d.addCallback(lambda r: self.assertEquals(r[0], testf(10)))
+ d.addCallback(lambda _: pushf({'testf':testf}, block=False))
+ d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True))
+ d.addCallback(lambda _: pullf('testf', block=False))
+ d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True))
+ d.addCallback(lambda r: self.assertEqual(r[0](1.0), testf(1.0)))
+ d.addCallback(lambda _: execute("def g(x): return x*x", targets=0))
+ d.addCallback(lambda _: pullf(('testf','g'),targets=0))
+ d.addCallback(lambda r: self.assertEquals((r[0][0](10),r[0][1](10)), (testf(10), 100)))
+ return d
+
+ def testGetResult(self):
+ shell = Interpreter()
+ result1 = shell.execute('a=10')
+ result1['id'] = 0
+ result2 = shell.execute('b=20')
+ result2['id'] = 0
+ execute= self.multiengine.execute
+ get_result = self.multiengine.get_result
+ self.addEngine(1)
+ d= execute('a=10')
+ d.addCallback(lambda _: get_result())
+ d.addCallback(lambda r: self.assertEquals(r[0], result1))
+ d.addCallback(lambda _: execute('b=20'))
+ d.addCallback(lambda _: get_result(1))
+ d.addCallback(lambda r: self.assertEquals(r[0], result1))
+ d.addCallback(lambda _: get_result(2, block=False))
+ d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True))
+ d.addCallback(lambda r: self.assertEquals(r[0], result2))
+ return d
+
+ def testResetAndKeys(self):
+ self.addEngine(1)
+
+ #Blocking mode
+ d= self.multiengine.push(dict(a=10, b=20, c=range(10)), targets=0)
+ d.addCallback(lambda _: self.multiengine.keys(targets=0))
+ def keys_found(keys):
+ self.assert_('a' in keys[0])
+ self.assert_('b' in keys[0])
+ self.assert_('b' in keys[0])
+ d.addCallback(keys_found)
+ d.addCallback(lambda _: self.multiengine.reset(targets=0))
+ d.addCallback(lambda _: self.multiengine.keys(targets=0))
+ def keys_not_found(keys):
+ self.assert_('a' not in keys[0])
+ self.assert_('b' not in keys[0])
+ self.assert_('b' not in keys[0])
+ d.addCallback(keys_not_found)
+
+ #Non-blocking mode
+ d.addCallback(lambda _: self.multiengine.push(dict(a=10, b=20, c=range(10)), targets=0))
+ d.addCallback(lambda _: self.multiengine.keys(targets=0, block=False))
+ d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True))
+ def keys_found(keys):
+ self.assert_('a' in keys[0])
+ self.assert_('b' in keys[0])
+ self.assert_('b' in keys[0])
+ d.addCallback(keys_found)
+ d.addCallback(lambda _: self.multiengine.reset(targets=0, block=False))
+ d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True))
+ d.addCallback(lambda _: self.multiengine.keys(targets=0, block=False))
+ d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True))
+ def keys_not_found(keys):
+ self.assert_('a' not in keys[0])
+ self.assert_('b' not in keys[0])
+ self.assert_('b' not in keys[0])
+ d.addCallback(keys_not_found)
+
+ return d
+
+ def testPushPullSerialized(self):
+ self.addEngine(1)
+ dikt = dict(a=10,b='hi there',c=1.2345,d={'p':(1,2)})
+ sdikt = {}
+ for k,v in dikt.iteritems():
+ sdikt[k] = newserialized.serialize(v)
+ d= self.multiengine.push_serialized(dict(a=sdikt['a']), targets=0)
+ d.addCallback(lambda _: self.multiengine.pull('a',targets=0))
+ d.addCallback(lambda r: self.assertEquals(r[0], dikt['a']))
+ d.addCallback(lambda _: self.multiengine.pull_serialized('a', targets=0))
+ d.addCallback(lambda serial: newserialized.IUnSerialized(serial[0]).getObject())
+ d.addCallback(lambda r: self.assertEquals(r, dikt['a']))
+ d.addCallback(lambda _: self.multiengine.push_serialized(sdikt, targets=0))
+ d.addCallback(lambda _: self.multiengine.pull_serialized(sdikt.keys(), targets=0))
+ d.addCallback(lambda serial: [newserialized.IUnSerialized(s).getObject() for s in serial[0]])
+ d.addCallback(lambda r: self.assertEquals(r, dikt.values()))
+ d.addCallback(lambda _: self.multiengine.reset(targets=0))
+ d.addCallback(lambda _: self.multiengine.pull_serialized('a', targets=0))
+ d.addErrback(lambda f: self.assertRaises(NameError, _raise_it, f))
+
+ #Non-blocking mode
+ d.addCallback(lambda r: self.multiengine.push_serialized(dict(a=sdikt['a']), targets=0, block=False))
+ d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True))
+ d.addCallback(lambda _: self.multiengine.pull('a',targets=0))
+ d.addCallback(lambda r: self.assertEquals(r[0], dikt['a']))
+ d.addCallback(lambda _: self.multiengine.pull_serialized('a', targets=0, block=False))
+ d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True))
+ d.addCallback(lambda serial: newserialized.IUnSerialized(serial[0]).getObject())
+ d.addCallback(lambda r: self.assertEquals(r, dikt['a']))
+ d.addCallback(lambda _: self.multiengine.push_serialized(sdikt, targets=0, block=False))
+ d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True))
+ d.addCallback(lambda _: self.multiengine.pull_serialized(sdikt.keys(), targets=0, block=False))
+ d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True))
+ d.addCallback(lambda serial: [newserialized.IUnSerialized(s).getObject() for s in serial[0]])
+ d.addCallback(lambda r: self.assertEquals(r, dikt.values()))
+ d.addCallback(lambda _: self.multiengine.reset(targets=0))
+ d.addCallback(lambda _: self.multiengine.pull_serialized('a', targets=0, block=False))
+ d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True))
+ d.addErrback(lambda f: self.assertRaises(NameError, _raise_it, f))
+ return d
+
+ def testClearQueue(self):
+ self.addEngine(4)
+ d= self.multiengine.clear_queue()
+ d.addCallback(lambda r: self.multiengine.clear_queue(block=False))
+ d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True))
+ d.addCallback(lambda r: self.assertEquals(r,4*[None]))
+ return d
+
+ def testQueueStatus(self):
+ self.addEngine(4)
+ d= self.multiengine.queue_status(targets=0)
+ d.addCallback(lambda r: self.assert_(isinstance(r[0],tuple)))
+ d.addCallback(lambda r: self.multiengine.queue_status(targets=0, block=False))
+ d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True))
+ d.addCallback(lambda r: self.assert_(isinstance(r[0],tuple)))
+ return d
+
+ def testGetIDs(self):
+ self.addEngine(1)
+ d= self.multiengine.get_ids()
+ d.addCallback(lambda r: self.assertEquals(r, [0]))
+ d.addCallback(lambda _: self.addEngine(3))
+ d.addCallback(lambda _: self.multiengine.get_ids())
+ d.addCallback(lambda r: self.assertEquals(r, [0,1,2,3]))
+ return d
+
+ def testGetSetProperties(self):
+ self.addEngine(4)
+ dikt = dict(a=5, b='asdf', c=True, d=None, e=range(5))
+ d= self.multiengine.set_properties(dikt)
+ d.addCallback(lambda r: self.multiengine.get_properties())
+ d.addCallback(lambda r: self.assertEquals(r, 4*[dikt]))
+ d.addCallback(lambda r: self.multiengine.get_properties(('c',)))
+ d.addCallback(lambda r: self.assertEquals(r, 4*[{'c': dikt['c']}]))
+ d.addCallback(lambda r: self.multiengine.set_properties(dict(c=False)))
+ d.addCallback(lambda r: self.multiengine.get_properties(('c', 'd')))
+ d.addCallback(lambda r: self.assertEquals(r, 4*[dict(c=False, d=None)]))
+
+ #Non-blocking
+ d.addCallback(lambda r: self.multiengine.set_properties(dikt, block=False))
+ d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True))
+ d.addCallback(lambda r: self.multiengine.get_properties(block=False))
+ d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True))
+ d.addCallback(lambda r: self.assertEquals(r, 4*[dikt]))
+ d.addCallback(lambda r: self.multiengine.get_properties(('c',), block=False))
+ d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True))
+ d.addCallback(lambda r: self.assertEquals(r, 4*[{'c': dikt['c']}]))
+ d.addCallback(lambda r: self.multiengine.set_properties(dict(c=False), block=False))
+ d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True))
+ d.addCallback(lambda r: self.multiengine.get_properties(('c', 'd'), block=False))
+ d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True))
+ d.addCallback(lambda r: self.assertEquals(r, 4*[dict(c=False, d=None)]))
+ return d
+
+ def testClearProperties(self):
+ self.addEngine(4)
+ dikt = dict(a=5, b='asdf', c=True, d=None, e=range(5))
+ d= self.multiengine.set_properties(dikt)
+ d.addCallback(lambda r: self.multiengine.clear_properties())
+ d.addCallback(lambda r: self.multiengine.get_properties())
+ d.addCallback(lambda r: self.assertEquals(r, 4*[{}]))
+
+ #Non-blocking
+ d.addCallback(lambda r: self.multiengine.set_properties(dikt, block=False))
+ d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True))
+ d.addCallback(lambda r: self.multiengine.clear_properties(block=False))
+ d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True))
+ d.addCallback(lambda r: self.multiengine.get_properties(block=False))
+ d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True))
+ d.addCallback(lambda r: self.assertEquals(r, 4*[{}]))
+ return d
+
+ def testDelHasProperties(self):
+ self.addEngine(4)
+ dikt = dict(a=5, b='asdf', c=True, d=None, e=range(5))
+ d= self.multiengine.set_properties(dikt)
+ d.addCallback(lambda r: self.multiengine.del_properties(('b','e')))
+ d.addCallback(lambda r: self.multiengine.has_properties(('a','b','c','d','e')))
+ d.addCallback(lambda r: self.assertEquals(r, 4*[[True, False, True, True, False]]))
+
+ #Non-blocking
+ d.addCallback(lambda r: self.multiengine.set_properties(dikt, block=False))
+ d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True))
+ d.addCallback(lambda r: self.multiengine.del_properties(('b','e'), block=False))
+ d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True))
+ d.addCallback(lambda r: self.multiengine.has_properties(('a','b','c','d','e'), block=False))
+ d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True))
+ d.addCallback(lambda r: self.assertEquals(r, 4*[[True, False, True, True, False]]))
+ return d
+
+ def test_clear_pending_deferreds(self):
+ self.addEngine(4)
+ did_list = []
+ d= self.multiengine.execute('a=10',block=False)
+ d.addCallback(lambda did: did_list.append(did))
+ d.addCallback(lambda _: self.multiengine.push(dict(b=10),block=False))
+ d.addCallback(lambda did: did_list.append(did))
+ d.addCallback(lambda _: self.multiengine.pull(('a','b'),block=False))
+ d.addCallback(lambda did: did_list.append(did))
+ d.addCallback(lambda _: self.multiengine.clear_pending_deferreds())
+ d.addCallback(lambda _: self.multiengine.get_pending_deferred(did_list[0],True))
+ d.addErrback(lambda f: self.assertRaises(InvalidDeferredID, f.raiseException))
+ d.addCallback(lambda _: self.multiengine.get_pending_deferred(did_list[1],True))
+ d.addErrback(lambda f: self.assertRaises(InvalidDeferredID, f.raiseException))
+ d.addCallback(lambda _: self.multiengine.get_pending_deferred(did_list[2],True))
+ d.addErrback(lambda f: self.assertRaises(InvalidDeferredID, f.raiseException))
+ return d
+
+#-------------------------------------------------------------------------------
+# Coordinator test cases
+#-------------------------------------------------------------------------------
+
+class IMultiEngineCoordinatorTestCase(object):
+
+ def testScatterGather(self):
+ self.addEngine(4)
+ d= self.multiengine.scatter('a', range(16))
+ d.addCallback(lambda r: self.multiengine.gather('a'))
+ d.addCallback(lambda r: self.assertEquals(r, range(16)))
+ d.addCallback(lambda _: self.multiengine.gather('asdf'))
+ d.addErrback(lambda f: self.assertRaises(NameError, _raise_it, f))
+ return d
+
+ def testScatterGatherNumpy(self):
+ try:
+ import numpy
+ from numpy.testing.utils import assert_array_equal, assert_array_almost_equal
+ except:
+ return
+ else:
+ self.addEngine(4)
+ a = numpy.arange(16)
+ d = self.multiengine.scatter('a', a)
+ d.addCallback(lambda r: self.multiengine.gather('a'))
+ d.addCallback(lambda r: assert_array_equal(r, a))
+ return d
+
+ def testMap(self):
+ self.addEngine(4)
+ def f(x):
+ return x**2
+ data = range(16)
+ d= self.multiengine.map(f, data)
+ d.addCallback(lambda r: self.assertEquals(r,[f(x) for x in data]))
+ return d
+
+
+class ISynchronousMultiEngineCoordinatorTestCase(IMultiEngineCoordinatorTestCase):
+
+ def testScatterGatherNonblocking(self):
+ self.addEngine(4)
+ d= self.multiengine.scatter('a', range(16), block=False)
+ d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True))
+ d.addCallback(lambda r: self.multiengine.gather('a', block=False))
+ d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True))
+ d.addCallback(lambda r: self.assertEquals(r, range(16)))
+ return d
+
+ def testScatterGatherNumpyNonblocking(self):
+ try:
+ import numpy
+ from numpy.testing.utils import assert_array_equal, assert_array_almost_equal
+ except:
+ return
+ else:
+ self.addEngine(4)
+ a = numpy.arange(16)
+ d = self.multiengine.scatter('a', a, block=False)
+ d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True))
+ d.addCallback(lambda r: self.multiengine.gather('a', block=False))
+ d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True))
+ d.addCallback(lambda r: assert_array_equal(r, a))
+ return d
+
+ def test_clear_pending_deferreds(self):
+ self.addEngine(4)
+ did_list = []
+ d= self.multiengine.scatter('a',range(16),block=False)
+ d.addCallback(lambda did: did_list.append(did))
+ d.addCallback(lambda _: self.multiengine.gather('a',block=False))
+ d.addCallback(lambda did: did_list.append(did))
+ d.addCallback(lambda _: self.multiengine.map(lambda x: x, range(16),block=False))
+ d.addCallback(lambda did: did_list.append(did))
+ d.addCallback(lambda _: self.multiengine.clear_pending_deferreds())
+ d.addCallback(lambda _: self.multiengine.get_pending_deferred(did_list[0],True))
+ d.addErrback(lambda f: self.assertRaises(InvalidDeferredID, f.raiseException))
+ d.addCallback(lambda _: self.multiengine.get_pending_deferred(did_list[1],True))
+ d.addErrback(lambda f: self.assertRaises(InvalidDeferredID, f.raiseException))
+ d.addCallback(lambda _: self.multiengine.get_pending_deferred(did_list[2],True))
+ d.addErrback(lambda f: self.assertRaises(InvalidDeferredID, f.raiseException))
+ return d
+
+#-------------------------------------------------------------------------------
+# Extras test cases
+#-------------------------------------------------------------------------------
+
+class IMultiEngineExtrasTestCase(object):
+
+ def testZipPull(self):
+ self.addEngine(4)
+ d= self.multiengine.push(dict(a=10,b=20))
+ d.addCallback(lambda r: self.multiengine.zip_pull(('a','b')))
+ d.addCallback(lambda r: self.assert_(r, [4*[10],4*[20]]))
+ return d
+
+ def testRun(self):
+ self.addEngine(4)
+ import tempfile
+ fname = tempfile.mktemp('foo.py')
+ f= open(fname, 'w')
+ f.write('a = 10\nb=30')
+ f.close()
+ d= self.multiengine.run(fname)
+ d.addCallback(lambda r: self.multiengine.pull(('a','b')))
+ d.addCallback(lambda r: self.assertEquals(r, 4*[[10,30]]))
+ return d
+
+
+class ISynchronousMultiEngineExtrasTestCase(IMultiEngineExtrasTestCase):
+
+ def testZipPullNonblocking(self):
+ self.addEngine(4)
+ d= self.multiengine.push(dict(a=10,b=20))
+ d.addCallback(lambda r: self.multiengine.zip_pull(('a','b'), block=False))
+ d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True))
+ d.addCallback(lambda r: self.assert_(r, [4*[10],4*[20]]))
+ return d
+
+ def testRunNonblocking(self):
+ self.addEngine(4)
+ import tempfile
+ fname = tempfile.mktemp('foo.py')
+ f= open(fname, 'w')
+ f.write('a = 10\nb=30')
+ f.close()
+ d= self.multiengine.run(fname, block=False)
+ d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True))
+ d.addCallback(lambda r: self.multiengine.pull(('a','b')))
+ d.addCallback(lambda r: self.assertEquals(r, 4*[[10,30]]))
+ return d
+
+
+#-------------------------------------------------------------------------------
+# IFullSynchronousMultiEngineTestCase
+#-------------------------------------------------------------------------------
+
+class IFullSynchronousMultiEngineTestCase(ISynchronousMultiEngineTestCase,
+ ISynchronousMultiEngineCoordinatorTestCase,
+ ISynchronousMultiEngineExtrasTestCase):
+ pass
diff --git a/IPython/kernel/tests/tasktest.py b/IPython/kernel/tests/tasktest.py
new file mode 100644
index 0000000..bddc8aa
--- /dev/null
+++ b/IPython/kernel/tests/tasktest.py
@@ -0,0 +1,187 @@
+#!/usr/bin/env python
+# encoding: utf-8
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+import time
+
+from IPython.kernel import task, engineservice as es
+from IPython.kernel.util import printer
+from IPython.kernel import error
+
+#-------------------------------------------------------------------------------
+# Tests
+#-------------------------------------------------------------------------------
+
+def _raise_it(f):
+ try:
+ f.raiseException()
+ except CompositeError, e:
+ e.raise_exception()
+
+class TaskTestBase(object):
+
+ def addEngine(self, n=1):
+ for i in range(n):
+ e = es.EngineService()
+ e.startService()
+ regDict = self.controller.register_engine(es.QueuedEngine(e), None)
+ e.id = regDict['id']
+ self.engines.append(e)
+
+
+class ITaskControllerTestCase(TaskTestBase):
+
+ def test_task_ids(self):
+ self.addEngine(1)
+ d = self.tc.run(task.StringTask('a=5'))
+ d.addCallback(lambda r: self.assertEquals(r, 0))
+ d.addCallback(lambda r: self.tc.run(task.StringTask('a=5')))
+ d.addCallback(lambda r: self.assertEquals(r, 1))
+ d.addCallback(lambda r: self.tc.run(task.StringTask('a=5')))
+ d.addCallback(lambda r: self.assertEquals(r, 2))
+ d.addCallback(lambda r: self.tc.run(task.StringTask('a=5')))
+ d.addCallback(lambda r: self.assertEquals(r, 3))
+ return d
+
+ def test_abort(self):
+ """Cannot do a proper abort test, because blocking execution prevents
+ abort from being called before task completes"""
+ self.addEngine(1)
+ t = task.StringTask('a=5')
+ d = self.tc.abort(0)
+ d.addErrback(lambda f: self.assertRaises(IndexError, f.raiseException))
+ d.addCallback(lambda _:self.tc.run(t))
+ d.addCallback(self.tc.abort)
+ d.addErrback(lambda f: self.assertRaises(IndexError, f.raiseException))
+ return d
+
+ def test_abort_type(self):
+ self.addEngine(1)
+ d = self.tc.abort('asdfadsf')
+ d.addErrback(lambda f: self.assertRaises(TypeError, f.raiseException))
+ return d
+
+ def test_clear_before_and_after(self):
+ self.addEngine(1)
+ t = task.StringTask('a=1', clear_before=True, pull='b', clear_after=True)
+ d = self.multiengine.execute('b=1', targets=0)
+ d.addCallback(lambda _: self.tc.run(t))
+ d.addCallback(lambda tid: self.tc.get_task_result(tid,block=True))
+ d.addCallback(lambda tr: tr.failure)
+ d.addErrback(lambda f: self.assertRaises(NameError, f.raiseException))
+ d.addCallback(lambda _:self.multiengine.pull('a', targets=0))
+ d.addErrback(lambda f: self.assertRaises(NameError, _raise_it, f))
+ return d
+
+ def test_simple_retries(self):
+ self.addEngine(1)
+ t = task.StringTask("i += 1\nassert i == 16", pull='i',retries=10)
+ t2 = task.StringTask("i += 1\nassert i == 16", pull='i',retries=10)
+ d = self.multiengine.execute('i=0', targets=0)
+ d.addCallback(lambda r: self.tc.run(t))
+ d.addCallback(self.tc.get_task_result, block=True)
+ d.addCallback(lambda tr: tr.ns.i)
+ d.addErrback(lambda f: self.assertRaises(AssertionError, f.raiseException))
+
+ d.addCallback(lambda r: self.tc.run(t2))
+ d.addCallback(self.tc.get_task_result, block=True)
+ d.addCallback(lambda tr: tr.ns.i)
+ d.addCallback(lambda r: self.assertEquals(r, 16))
+ return d
+
+ def test_recovery_tasks(self):
+ self.addEngine(1)
+ t = task.StringTask("i=16", pull='i')
+ t2 = task.StringTask("raise Exception", recovery_task=t, retries = 2)
+
+ d = self.tc.run(t2)
+ d.addCallback(self.tc.get_task_result, block=True)
+ d.addCallback(lambda tr: tr.ns.i)
+ d.addCallback(lambda r: self.assertEquals(r, 16))
+ return d
+
+ def test_setup_ns(self):
+ self.addEngine(1)
+ d = self.multiengine.execute('a=0', targets=0)
+ ns = dict(a=1, b=0)
+ t = task.StringTask("", push=ns, pull=['a','b'])
+ d.addCallback(lambda r: self.tc.run(t))
+ d.addCallback(self.tc.get_task_result, block=True)
+ d.addCallback(lambda tr: {'a':tr.ns.a, 'b':tr['b']})
+ d.addCallback(lambda r: self.assertEquals(r, ns))
+ return d
+
+ def test_string_task_results(self):
+ self.addEngine(1)
+ t1 = task.StringTask('a=5', pull='a')
+ d = self.tc.run(t1)
+ d.addCallback(self.tc.get_task_result, block=True)
+ d.addCallback(lambda tr: (tr.ns.a,tr['a'],tr.failure, tr.raise_exception()))
+ d.addCallback(lambda r: self.assertEquals(r, (5,5,None,None)))
+
+ t2 = task.StringTask('7=5')
+ d.addCallback(lambda r: self.tc.run(t2))
+ d.addCallback(self.tc.get_task_result, block=True)
+ d.addCallback(lambda tr: tr.ns)
+ d.addErrback(lambda f: self.assertRaises(SyntaxError, f.raiseException))
+
+ t3 = task.StringTask('', pull='b')
+ d.addCallback(lambda r: self.tc.run(t3))
+ d.addCallback(self.tc.get_task_result, block=True)
+ d.addCallback(lambda tr: tr.ns)
+ d.addErrback(lambda f: self.assertRaises(NameError, f.raiseException))
+ return d
+
+ def test_map_task(self):
+ self.addEngine(1)
+ t1 = task.MapTask(lambda x: 2*x,(10,))
+ d = self.tc.run(t1)
+ d.addCallback(self.tc.get_task_result, block=True)
+ d.addCallback(lambda r: self.assertEquals(r,20))
+
+ t2 = task.MapTask(lambda : 20)
+ d.addCallback(lambda _: self.tc.run(t2))
+ d.addCallback(self.tc.get_task_result, block=True)
+ d.addCallback(lambda r: self.assertEquals(r,20))
+
+ t3 = task.MapTask(lambda x: x,(),{'x':20})
+ d.addCallback(lambda _: self.tc.run(t3))
+ d.addCallback(self.tc.get_task_result, block=True)
+ d.addCallback(lambda r: self.assertEquals(r,20))
+ return d
+
+ def test_map_task_failure(self):
+ self.addEngine(1)
+ t1 = task.MapTask(lambda x: 1/0,(10,))
+ d = self.tc.run(t1)
+ d.addCallback(self.tc.get_task_result, block=True)
+ d.addErrback(lambda f: self.assertRaises(ZeroDivisionError, f.raiseException))
+ return d
+
+ def test_map_task_args(self):
+ self.assertRaises(TypeError, task.MapTask, 'asdfasdf')
+ self.assertRaises(TypeError, task.MapTask, lambda x: x, 10)
+ self.assertRaises(TypeError, task.MapTask, lambda x: x, (10,),30)
+
+ def test_clear(self):
+ self.addEngine(1)
+ t1 = task.MapTask(lambda x: 2*x,(10,))
+ d = self.tc.run(t1)
+ d.addCallback(lambda _: self.tc.get_task_result(0, block=True))
+ d.addCallback(lambda r: self.assertEquals(r,20))
+ d.addCallback(lambda _: self.tc.clear())
+ d.addCallback(lambda _: self.tc.get_task_result(0, block=True))
+ d.addErrback(lambda f: self.assertRaises(IndexError, f.raiseException))
+ return d
diff --git a/IPython/kernel/tests/test_contexts.py b/IPython/kernel/tests/test_contexts.py
new file mode 100644
index 0000000..fe726c3
--- /dev/null
+++ b/IPython/kernel/tests/test_contexts.py
@@ -0,0 +1,46 @@
+# Tell nose to skip this module
+__test__ = {}
+
+#from __future__ import with_statement
+
+# XXX This file is currently disabled to preserve 2.4 compatibility.
+
+#def test_simple():
+if 0:
+
+ # XXX - for now, we need a running cluster to be started separately. The
+ # daemon work is almost finished, and will make much of this unnecessary.
+ from IPython.kernel import client
+ mec = client.MultiEngineClient(('127.0.0.1',10105))
+
+ try:
+ mec.get_ids()
+ except ConnectionRefusedError:
+ import os, time
+ os.system('ipcluster -n 2 &')
+ time.sleep(2)
+ mec = client.MultiEngineClient(('127.0.0.1',10105))
+
+ mec.block = False
+
+ import itertools
+ c = itertools.count()
+
+ parallel = RemoteMultiEngine(mec)
+
+ mec.pushAll()
+
+ ## with parallel as pr:
+ ## # A comment
+ ## remote() # this means the code below only runs remotely
+ ## print 'Hello remote world'
+ ## x = range(10)
+ ## # Comments are OK
+ ## # Even misindented.
+ ## y = x+1
+
+
+ ## with pfor('i',sequence) as pr:
+ ## print x[i]
+
+ print pr.x + pr.y
diff --git a/IPython/kernel/tests/test_controllerservice.py b/IPython/kernel/tests/test_controllerservice.py
new file mode 100644
index 0000000..749fac7
--- /dev/null
+++ b/IPython/kernel/tests/test_controllerservice.py
@@ -0,0 +1,44 @@
+# encoding: utf-8
+
+"""This file contains unittests for the kernel.engineservice.py module.
+
+Things that should be tested:
+
+ - Should the EngineService return Deferred objects?
+ - Run the same tests that are run in shell.py.
+ - Make sure that the Interface is really implemented.
+ - The startService and stopService methods.
+"""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+# Tell nose to skip this module
+__test__ = {}
+
+from twisted.application.service import IService
+from IPython.kernel.controllerservice import ControllerService
+from IPython.kernel.tests import multienginetest as met
+from controllertest import IControllerCoreTestCase
+from IPython.testing.util import DeferredTestCase
+
+
+class BasicControllerServiceTest(DeferredTestCase,
+ IControllerCoreTestCase):
+
+ def setUp(self):
+ self.controller = ControllerService()
+ self.controller.startService()
+
+ def tearDown(self):
+ self.controller.stopService()
diff --git a/IPython/kernel/tests/test_enginefc.py b/IPython/kernel/tests/test_enginefc.py
new file mode 100644
index 0000000..502b421
--- /dev/null
+++ b/IPython/kernel/tests/test_enginefc.py
@@ -0,0 +1,92 @@
+# encoding: utf-8
+
+"""This file contains unittests for the enginepb.py module."""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+# Tell nose to skip this module
+__test__ = {}
+
+from twisted.python import components
+from twisted.internet import reactor, defer
+from twisted.spread import pb
+from twisted.internet.base import DelayedCall
+DelayedCall.debug = True
+
+import zope.interface as zi
+
+from IPython.kernel.fcutil import Tub, UnauthenticatedTub
+from IPython.kernel import engineservice as es
+from IPython.testing.util import DeferredTestCase
+from IPython.kernel.controllerservice import IControllerBase
+from IPython.kernel.enginefc import FCRemoteEngineRefFromService, IEngineBase
+from IPython.kernel.engineservice import IEngineQueued
+from IPython.kernel.engineconnector import EngineConnector
+
+from IPython.kernel.tests.engineservicetest import \
+ IEngineCoreTestCase, \
+ IEngineSerializedTestCase, \
+ IEngineQueuedTestCase
+
+
+class EngineFCTest(DeferredTestCase,
+ IEngineCoreTestCase,
+ IEngineSerializedTestCase,
+ IEngineQueuedTestCase
+ ):
+
+ zi.implements(IControllerBase)
+
+ def setUp(self):
+
+ # Start a server and append to self.servers
+ self.controller_reference = FCRemoteEngineRefFromService(self)
+ self.controller_tub = Tub()
+ self.controller_tub.listenOn('tcp:10105:interface=127.0.0.1')
+ self.controller_tub.setLocation('127.0.0.1:10105')
+
+ furl = self.controller_tub.registerReference(self.controller_reference)
+ self.controller_tub.startService()
+
+ # Start an EngineService and append to services/client
+ self.engine_service = es.EngineService()
+ self.engine_service.startService()
+ self.engine_tub = Tub()
+ self.engine_tub.startService()
+ engine_connector = EngineConnector(self.engine_tub)
+ d = engine_connector.connect_to_controller(self.engine_service, furl)
+ # This deferred doesn't fire until after register_engine has returned and
+ # thus, self.engine has been defined and the tets can proceed.
+ return d
+
+ def tearDown(self):
+ dlist = []
+ # Shut down the engine
+ d = self.engine_tub.stopService()
+ dlist.append(d)
+ # Shut down the controller
+ d = self.controller_tub.stopService()
+ dlist.append(d)
+ return defer.DeferredList(dlist)
+
+ #---------------------------------------------------------------------------
+ # Make me look like a basic controller
+ #---------------------------------------------------------------------------
+
+ def register_engine(self, engine_ref, id=None, ip=None, port=None, pid=None):
+ self.engine = IEngineQueued(IEngineBase(engine_ref))
+ return {'id':id}
+
+ def unregister_engine(self, id):
+ pass \ No newline at end of file
diff --git a/IPython/kernel/tests/test_engineservice.py b/IPython/kernel/tests/test_engineservice.py
new file mode 100644
index 0000000..a455030
--- /dev/null
+++ b/IPython/kernel/tests/test_engineservice.py
@@ -0,0 +1,79 @@
+# encoding: utf-8
+
+"""This file contains unittests for the kernel.engineservice.py module.
+
+Things that should be tested:
+
+ - Should the EngineService return Deferred objects?
+ - Run the same tests that are run in shell.py.
+ - Make sure that the Interface is really implemented.
+ - The startService and stopService methods.
+"""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+# Tell nose to skip this module
+__test__ = {}
+
+from twisted.internet import defer
+from twisted.application.service import IService
+
+from IPython.kernel import engineservice as es
+from IPython.testing.util import DeferredTestCase
+from IPython.kernel.tests.engineservicetest import \
+ IEngineCoreTestCase, \
+ IEngineSerializedTestCase, \
+ IEngineQueuedTestCase, \
+ IEnginePropertiesTestCase
+
+
+class BasicEngineServiceTest(DeferredTestCase,
+ IEngineCoreTestCase,
+ IEngineSerializedTestCase,
+ IEnginePropertiesTestCase):
+
+ def setUp(self):
+ self.engine = es.EngineService()
+ self.engine.startService()
+
+ def tearDown(self):
+ return self.engine.stopService()
+
+class ThreadedEngineServiceTest(DeferredTestCase,
+ IEngineCoreTestCase,
+ IEngineSerializedTestCase,
+ IEnginePropertiesTestCase):
+
+ def setUp(self):
+ self.engine = es.ThreadedEngineService()
+ self.engine.startService()
+
+ def tearDown(self):
+ return self.engine.stopService()
+
+class QueuedEngineServiceTest(DeferredTestCase,
+ IEngineCoreTestCase,
+ IEngineSerializedTestCase,
+ IEnginePropertiesTestCase,
+ IEngineQueuedTestCase):
+
+ def setUp(self):
+ self.rawEngine = es.EngineService()
+ self.rawEngine.startService()
+ self.engine = es.IEngineQueued(self.rawEngine)
+
+ def tearDown(self):
+ return self.rawEngine.stopService()
+
+
diff --git a/IPython/kernel/tests/test_multiengine.py b/IPython/kernel/tests/test_multiengine.py
new file mode 100644
index 0000000..3fe397f
--- /dev/null
+++ b/IPython/kernel/tests/test_multiengine.py
@@ -0,0 +1,55 @@
+# encoding: utf-8
+
+""""""
+
+__docformat__ = "restructuredtext en"
+
+#-----------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+# Tell nose to skip this module
+__test__ = {}
+
+from twisted.internet import defer
+from IPython.testing.util import DeferredTestCase
+from IPython.kernel.controllerservice import ControllerService
+from IPython.kernel import multiengine as me
+from IPython.kernel.tests.multienginetest import (IMultiEngineTestCase,
+ ISynchronousMultiEngineTestCase)
+
+
+class BasicMultiEngineTestCase(DeferredTestCase, IMultiEngineTestCase):
+
+ def setUp(self):
+ self.controller = ControllerService()
+ self.controller.startService()
+ self.multiengine = me.IMultiEngine(self.controller)
+ self.engines = []
+
+ def tearDown(self):
+ self.controller.stopService()
+ for e in self.engines:
+ e.stopService()
+
+
+class SynchronousMultiEngineTestCase(DeferredTestCase, ISynchronousMultiEngineTestCase):
+
+ def setUp(self):
+ self.controller = ControllerService()
+ self.controller.startService()
+ self.multiengine = me.ISynchronousMultiEngine(me.IMultiEngine(self.controller))
+ self.engines = []
+
+ def tearDown(self):
+ self.controller.stopService()
+ for e in self.engines:
+ e.stopService()
+
diff --git a/IPython/kernel/tests/test_multienginefc.py b/IPython/kernel/tests/test_multienginefc.py
new file mode 100644
index 0000000..97d69e1
--- /dev/null
+++ b/IPython/kernel/tests/test_multienginefc.py
@@ -0,0 +1,144 @@
+#!/usr/bin/env python
+# encoding: utf-8
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+# Tell nose to skip this module
+__test__ = {}
+
+from twisted.internet import defer, reactor
+
+from IPython.kernel.fcutil import Tub, UnauthenticatedTub
+
+from IPython.testing.util import DeferredTestCase
+from IPython.kernel.controllerservice import ControllerService
+from IPython.kernel.multiengine import IMultiEngine
+from IPython.kernel.tests.multienginetest import IFullSynchronousMultiEngineTestCase
+from IPython.kernel.multienginefc import IFCSynchronousMultiEngine
+from IPython.kernel import multiengine as me
+from IPython.kernel.clientconnector import ClientConnector
+from IPython.kernel.parallelfunction import ParallelFunction
+from IPython.kernel.error import CompositeError
+from IPython.kernel.util import printer
+
+
+def _raise_it(f):
+ try:
+ f.raiseException()
+ except CompositeError, e:
+ e.raise_exception()
+
+
+class FullSynchronousMultiEngineTestCase(DeferredTestCase, IFullSynchronousMultiEngineTestCase):
+
+ def setUp(self):
+
+ self.engines = []
+
+ self.controller = ControllerService()
+ self.controller.startService()
+ self.imultiengine = IMultiEngine(self.controller)
+ self.mec_referenceable = IFCSynchronousMultiEngine(self.imultiengine)
+
+ self.controller_tub = Tub()
+ self.controller_tub.listenOn('tcp:10105:interface=127.0.0.1')
+ self.controller_tub.setLocation('127.0.0.1:10105')
+
+ furl = self.controller_tub.registerReference(self.mec_referenceable)
+ self.controller_tub.startService()
+
+ self.client_tub = ClientConnector()
+ d = self.client_tub.get_multiengine_client(furl)
+ d.addCallback(self.handle_got_client)
+ return d
+
+ def handle_got_client(self, client):
+ self.multiengine = client
+
+ def tearDown(self):
+ dlist = []
+ # Shut down the multiengine client
+ d = self.client_tub.tub.stopService()
+ dlist.append(d)
+ # Shut down the engines
+ for e in self.engines:
+ e.stopService()
+ # Shut down the controller
+ d = self.controller_tub.stopService()
+ d.addBoth(lambda _: self.controller.stopService())
+ dlist.append(d)
+ return defer.DeferredList(dlist)
+
+ def test_mapper(self):
+ self.addEngine(4)
+ m = self.multiengine.mapper()
+ self.assertEquals(m.multiengine,self.multiengine)
+ self.assertEquals(m.dist,'b')
+ self.assertEquals(m.targets,'all')
+ self.assertEquals(m.block,True)
+
+ def test_map_default(self):
+ self.addEngine(4)
+ m = self.multiengine.mapper()
+ d = m.map(lambda x: 2*x, range(10))
+ d.addCallback(lambda r: self.assertEquals(r,[2*x for x in range(10)]))
+ d.addCallback(lambda _: self.multiengine.map(lambda x: 2*x, range(10)))
+ d.addCallback(lambda r: self.assertEquals(r,[2*x for x in range(10)]))
+ return d
+
+ def test_map_noblock(self):
+ self.addEngine(4)
+ m = self.multiengine.mapper(block=False)
+ d = m.map(lambda x: 2*x, range(10))
+ d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True))
+ d.addCallback(lambda r: self.assertEquals(r,[2*x for x in range(10)]))
+ return d
+
+ def test_mapper_fail(self):
+ self.addEngine(4)
+ m = self.multiengine.mapper()
+ d = m.map(lambda x: 1/0, range(10))
+ d.addBoth(lambda f: self.assertRaises(ZeroDivisionError, _raise_it, f))
+ return d
+
+ def test_parallel(self):
+ self.addEngine(4)
+ p = self.multiengine.parallel()
+ self.assert_(isinstance(p, ParallelFunction))
+ @p
+ def f(x): return 2*x
+ d = f(range(10))
+ d.addCallback(lambda r: self.assertEquals(r,[2*x for x in range(10)]))
+ return d
+
+ def test_parallel_noblock(self):
+ self.addEngine(1)
+ p = self.multiengine.parallel(block=False)
+ self.assert_(isinstance(p, ParallelFunction))
+ @p
+ def f(x): return 2*x
+ d = f(range(10))
+ d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True))
+ d.addCallback(lambda r: self.assertEquals(r,[2*x for x in range(10)]))
+ return d
+
+ def test_parallel_fail(self):
+ self.addEngine(4)
+ p = self.multiengine.parallel()
+ self.assert_(isinstance(p, ParallelFunction))
+ @p
+ def f(x): return 1/0
+ d = f(range(10))
+ d.addBoth(lambda f: self.assertRaises(ZeroDivisionError, _raise_it, f))
+ return d \ No newline at end of file
diff --git a/IPython/kernel/tests/test_newserialized.py b/IPython/kernel/tests/test_newserialized.py
new file mode 100644
index 0000000..57b6d7b
--- /dev/null
+++ b/IPython/kernel/tests/test_newserialized.py
@@ -0,0 +1,102 @@
+# encoding: utf-8
+
+"""This file contains unittests for the shell.py module."""
+
+__docformat__ = "restructuredtext en"
+
+#-----------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+# Tell nose to skip this module
+__test__ = {}
+
+import zope.interface as zi
+from twisted.trial import unittest
+from IPython.testing.util import DeferredTestCase
+
+from IPython.kernel.newserialized import \
+ ISerialized, \
+ IUnSerialized, \
+ Serialized, \
+ UnSerialized, \
+ SerializeIt, \
+ UnSerializeIt
+
+
+#-----------------------------------------------------------------------------
+# Tests
+#-----------------------------------------------------------------------------
+
+class SerializedTestCase(unittest.TestCase):
+
+ def setUp(self):
+ pass
+
+ def tearDown(self):
+ pass
+
+ def testSerializedInterfaces(self):
+
+ us = UnSerialized({'a':10, 'b':range(10)})
+ s = ISerialized(us)
+ uss = IUnSerialized(s)
+ self.assert_(ISerialized.providedBy(s))
+ self.assert_(IUnSerialized.providedBy(us))
+ self.assert_(IUnSerialized.providedBy(uss))
+ for m in list(ISerialized):
+ self.assert_(hasattr(s, m))
+ for m in list(IUnSerialized):
+ self.assert_(hasattr(us, m))
+ for m in list(IUnSerialized):
+ self.assert_(hasattr(uss, m))
+
+ def testPickleSerialized(self):
+ obj = {'a':1.45345, 'b':'asdfsdf', 'c':10000L}
+ original = UnSerialized(obj)
+ originalSer = ISerialized(original)
+ firstData = originalSer.getData()
+ firstTD = originalSer.getTypeDescriptor()
+ firstMD = originalSer.getMetadata()
+ self.assert_(firstTD == 'pickle')
+ self.assert_(firstMD == {})
+ unSerialized = IUnSerialized(originalSer)
+ secondObj = unSerialized.getObject()
+ for k, v in secondObj.iteritems():
+ self.assert_(obj[k] == v)
+ secondSer = ISerialized(UnSerialized(secondObj))
+ self.assert_(firstData == secondSer.getData())
+ self.assert_(firstTD == secondSer.getTypeDescriptor() )
+ self.assert_(firstMD == secondSer.getMetadata())
+
+ def testNDArraySerialized(self):
+ try:
+ import numpy
+ except ImportError:
+ pass
+ else:
+ a = numpy.linspace(0.0, 1.0, 1000)
+ unSer1 = UnSerialized(a)
+ ser1 = ISerialized(unSer1)
+ td = ser1.getTypeDescriptor()
+ self.assert_(td == 'ndarray')
+ md = ser1.getMetadata()
+ self.assert_(md['shape'] == a.shape)
+ self.assert_(md['dtype'] == a.dtype.str)
+ buff = ser1.getData()
+ self.assert_(buff == numpy.getbuffer(a))
+ s = Serialized(buff, td, md)
+ us = IUnSerialized(s)
+ final = us.getObject()
+ self.assert_(numpy.getbuffer(a) == numpy.getbuffer(final))
+ self.assert_(a.dtype.str == final.dtype.str)
+ self.assert_(a.shape == final.shape)
+
+
diff --git a/IPython/kernel/tests/test_pendingdeferred.py b/IPython/kernel/tests/test_pendingdeferred.py
new file mode 100644
index 0000000..e12b56b
--- /dev/null
+++ b/IPython/kernel/tests/test_pendingdeferred.py
@@ -0,0 +1,186 @@
+#!/usr/bin/env python
+# encoding: utf-8
+
+"""Tests for pendingdeferred.py"""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+# Tell nose to skip this module
+__test__ = {}
+
+from twisted.internet import defer
+from twisted.python import failure
+
+from IPython.testing.util import DeferredTestCase
+import IPython.kernel.pendingdeferred as pd
+from IPython.kernel import error
+from IPython.kernel.util import printer
+
+
+class Foo(object):
+
+ def bar(self, bahz):
+ return defer.succeed('blahblah: %s' % bahz)
+
+class TwoPhaseFoo(pd.PendingDeferredManager):
+
+ def __init__(self, foo):
+ self.foo = foo
+ pd.PendingDeferredManager.__init__(self)
+
+ @pd.two_phase
+ def bar(self, bahz):
+ return self.foo.bar(bahz)
+
+class PendingDeferredManagerTest(DeferredTestCase):
+
+ def setUp(self):
+ self.pdm = pd.PendingDeferredManager()
+
+ def tearDown(self):
+ pass
+
+ def testBasic(self):
+ dDict = {}
+ # Create 10 deferreds and save them
+ for i in range(10):
+ d = defer.Deferred()
+ did = self.pdm.save_pending_deferred(d)
+ dDict[did] = d
+ # Make sure they are begin saved
+ for k in dDict.keys():
+ self.assert_(self.pdm.quick_has_id(k))
+ # Get the pending deferred (block=True), then callback with 'foo' and compare
+ for did in dDict.keys()[0:5]:
+ d = self.pdm.get_pending_deferred(did,block=True)
+ dDict[did].callback('foo')
+ d.addCallback(lambda r: self.assert_(r=='foo'))
+ # Get the pending deferreds with (block=False) and make sure ResultNotCompleted is raised
+ for did in dDict.keys()[5:10]:
+ d = self.pdm.get_pending_deferred(did,block=False)
+ d.addErrback(lambda f: self.assertRaises(error.ResultNotCompleted, f.raiseException))
+ # Now callback the last 5, get them and compare.
+ for did in dDict.keys()[5:10]:
+ dDict[did].callback('foo')
+ d = self.pdm.get_pending_deferred(did,block=False)
+ d.addCallback(lambda r: self.assert_(r=='foo'))
+
+ def test_save_then_delete(self):
+ d = defer.Deferred()
+ did = self.pdm.save_pending_deferred(d)
+ self.assert_(self.pdm.quick_has_id(did))
+ self.pdm.delete_pending_deferred(did)
+ self.assert_(not self.pdm.quick_has_id(did))
+
+ def test_save_get_delete(self):
+ d = defer.Deferred()
+ did = self.pdm.save_pending_deferred(d)
+ d2 = self.pdm.get_pending_deferred(did,True)
+ d2.addErrback(lambda f: self.assertRaises(error.AbortedPendingDeferredError, f.raiseException))
+ self.pdm.delete_pending_deferred(did)
+ return d2
+
+ def test_double_get(self):
+ d = defer.Deferred()
+ did = self.pdm.save_pending_deferred(d)
+ d2 = self.pdm.get_pending_deferred(did,True)
+ d3 = self.pdm.get_pending_deferred(did,True)
+ d3.addErrback(lambda f: self.assertRaises(error.InvalidDeferredID, f.raiseException))
+
+ def test_get_after_callback(self):
+ d = defer.Deferred()
+ did = self.pdm.save_pending_deferred(d)
+ d.callback('foo')
+ d2 = self.pdm.get_pending_deferred(did,True)
+ d2.addCallback(lambda r: self.assertEquals(r,'foo'))
+ self.assert_(not self.pdm.quick_has_id(did))
+
+ def test_get_before_callback(self):
+ d = defer.Deferred()
+ did = self.pdm.save_pending_deferred(d)
+ d2 = self.pdm.get_pending_deferred(did,True)
+ d.callback('foo')
+ d2.addCallback(lambda r: self.assertEquals(r,'foo'))
+ self.assert_(not self.pdm.quick_has_id(did))
+ d = defer.Deferred()
+ did = self.pdm.save_pending_deferred(d)
+ d2 = self.pdm.get_pending_deferred(did,True)
+ d2.addCallback(lambda r: self.assertEquals(r,'foo'))
+ d.callback('foo')
+ self.assert_(not self.pdm.quick_has_id(did))
+
+ def test_get_after_errback(self):
+ class MyError(Exception):
+ pass
+ d = defer.Deferred()
+ did = self.pdm.save_pending_deferred(d)
+ d.errback(failure.Failure(MyError('foo')))
+ d2 = self.pdm.get_pending_deferred(did,True)
+ d2.addErrback(lambda f: self.assertRaises(MyError, f.raiseException))
+ self.assert_(not self.pdm.quick_has_id(did))
+
+ def test_get_before_errback(self):
+ class MyError(Exception):
+ pass
+ d = defer.Deferred()
+ did = self.pdm.save_pending_deferred(d)
+ d2 = self.pdm.get_pending_deferred(did,True)
+ d.errback(failure.Failure(MyError('foo')))
+ d2.addErrback(lambda f: self.assertRaises(MyError, f.raiseException))
+ self.assert_(not self.pdm.quick_has_id(did))
+ d = defer.Deferred()
+ did = self.pdm.save_pending_deferred(d)
+ d2 = self.pdm.get_pending_deferred(did,True)
+ d2.addErrback(lambda f: self.assertRaises(MyError, f.raiseException))
+ d.errback(failure.Failure(MyError('foo')))
+ self.assert_(not self.pdm.quick_has_id(did))
+
+ def test_noresult_noblock(self):
+ d = defer.Deferred()
+ did = self.pdm.save_pending_deferred(d)
+ d2 = self.pdm.get_pending_deferred(did,False)
+ d2.addErrback(lambda f: self.assertRaises(error.ResultNotCompleted, f.raiseException))
+
+ def test_with_callbacks(self):
+ d = defer.Deferred()
+ d.addCallback(lambda r: r+' foo')
+ d.addCallback(lambda r: r+' bar')
+ did = self.pdm.save_pending_deferred(d)
+ d2 = self.pdm.get_pending_deferred(did,True)
+ d.callback('bam')
+ d2.addCallback(lambda r: self.assertEquals(r,'bam foo bar'))
+
+ def test_with_errbacks(self):
+ class MyError(Exception):
+ pass
+ d = defer.Deferred()
+ d.addCallback(lambda r: 'foo')
+ d.addErrback(lambda f: 'caught error')
+ did = self.pdm.save_pending_deferred(d)
+ d2 = self.pdm.get_pending_deferred(did,True)
+ d.errback(failure.Failure(MyError('bam')))
+ d2.addErrback(lambda f: self.assertRaises(MyError, f.raiseException))
+
+ def test_nested_deferreds(self):
+ d = defer.Deferred()
+ d2 = defer.Deferred()
+ d.addCallback(lambda r: d2)
+ did = self.pdm.save_pending_deferred(d)
+ d.callback('foo')
+ d3 = self.pdm.get_pending_deferred(did,False)
+ d3.addErrback(lambda f: self.assertRaises(error.ResultNotCompleted, f.raiseException))
+ d2.callback('bar')
+ d3 = self.pdm.get_pending_deferred(did,False)
+ d3.addCallback(lambda r: self.assertEquals(r,'bar'))
+
diff --git a/IPython/kernel/tests/test_task.py b/IPython/kernel/tests/test_task.py
new file mode 100644
index 0000000..7060579
--- /dev/null
+++ b/IPython/kernel/tests/test_task.py
@@ -0,0 +1,51 @@
+# encoding: utf-8
+
+"""This file contains unittests for the kernel.task.py module."""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+# Tell nose to skip this module
+__test__ = {}
+
+import time
+
+from twisted.internet import defer
+from twisted.trial import unittest
+
+from IPython.kernel import task, controllerservice as cs, engineservice as es
+from IPython.kernel.multiengine import IMultiEngine
+from IPython.testing.util import DeferredTestCase
+from IPython.kernel.tests.tasktest import ITaskControllerTestCase
+
+
+#-------------------------------------------------------------------------------
+# Tests
+#-------------------------------------------------------------------------------
+
+class BasicTaskControllerTestCase(DeferredTestCase, ITaskControllerTestCase):
+
+ def setUp(self):
+ self.controller = cs.ControllerService()
+ self.controller.startService()
+ self.multiengine = IMultiEngine(self.controller)
+ self.tc = task.ITaskController(self.controller)
+ self.tc.failurePenalty = 0
+ self.engines=[]
+
+ def tearDown(self):
+ self.controller.stopService()
+ for e in self.engines:
+ e.stopService()
+
+
diff --git a/IPython/kernel/tests/test_taskfc.py b/IPython/kernel/tests/test_taskfc.py
new file mode 100644
index 0000000..371d800
--- /dev/null
+++ b/IPython/kernel/tests/test_taskfc.py
@@ -0,0 +1,161 @@
+#!/usr/bin/env python
+# encoding: utf-8
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+# Tell nose to skip this module
+__test__ = {}
+
+import time
+
+from twisted.internet import defer, reactor
+
+from IPython.kernel.fcutil import Tub, UnauthenticatedTub
+
+from IPython.kernel import task as taskmodule
+from IPython.kernel import controllerservice as cs
+import IPython.kernel.multiengine as me
+from IPython.testing.util import DeferredTestCase
+from IPython.kernel.multienginefc import IFCSynchronousMultiEngine
+from IPython.kernel.taskfc import IFCTaskController
+from IPython.kernel.util import printer
+from IPython.kernel.tests.tasktest import ITaskControllerTestCase
+from IPython.kernel.clientconnector import ClientConnector
+from IPython.kernel.error import CompositeError
+from IPython.kernel.parallelfunction import ParallelFunction
+
+
+#-------------------------------------------------------------------------------
+# Tests
+#-------------------------------------------------------------------------------
+
+def _raise_it(f):
+ try:
+ f.raiseException()
+ except CompositeError, e:
+ e.raise_exception()
+
+class TaskTest(DeferredTestCase, ITaskControllerTestCase):
+
+ def setUp(self):
+
+ self.engines = []
+
+ self.controller = cs.ControllerService()
+ self.controller.startService()
+ self.imultiengine = me.IMultiEngine(self.controller)
+ self.itc = taskmodule.ITaskController(self.controller)
+ self.itc.failurePenalty = 0
+
+ self.mec_referenceable = IFCSynchronousMultiEngine(self.imultiengine)
+ self.tc_referenceable = IFCTaskController(self.itc)
+
+ self.controller_tub = Tub()
+ self.controller_tub.listenOn('tcp:10105:interface=127.0.0.1')
+ self.controller_tub.setLocation('127.0.0.1:10105')
+
+ mec_furl = self.controller_tub.registerReference(self.mec_referenceable)
+ tc_furl = self.controller_tub.registerReference(self.tc_referenceable)
+ self.controller_tub.startService()
+
+ self.client_tub = ClientConnector()
+ d = self.client_tub.get_multiengine_client(mec_furl)
+ d.addCallback(self.handle_mec_client)
+ d.addCallback(lambda _: self.client_tub.get_task_client(tc_furl))
+ d.addCallback(self.handle_tc_client)
+ return d
+
+ def handle_mec_client(self, client):
+ self.multiengine = client
+
+ def handle_tc_client(self, client):
+ self.tc = client
+
+ def tearDown(self):
+ dlist = []
+ # Shut down the multiengine client
+ d = self.client_tub.tub.stopService()
+ dlist.append(d)
+ # Shut down the engines
+ for e in self.engines:
+ e.stopService()
+ # Shut down the controller
+ d = self.controller_tub.stopService()
+ d.addBoth(lambda _: self.controller.stopService())
+ dlist.append(d)
+ return defer.DeferredList(dlist)
+
+ def test_mapper(self):
+ self.addEngine(1)
+ m = self.tc.mapper()
+ self.assertEquals(m.task_controller,self.tc)
+ self.assertEquals(m.clear_before,False)
+ self.assertEquals(m.clear_after,False)
+ self.assertEquals(m.retries,0)
+ self.assertEquals(m.recovery_task,None)
+ self.assertEquals(m.depend,None)
+ self.assertEquals(m.block,True)
+
+ def test_map_default(self):
+ self.addEngine(1)
+ m = self.tc.mapper()
+ d = m.map(lambda x: 2*x, range(10))
+ d.addCallback(lambda r: self.assertEquals(r,[2*x for x in range(10)]))
+ d.addCallback(lambda _: self.tc.map(lambda x: 2*x, range(10)))
+ d.addCallback(lambda r: self.assertEquals(r,[2*x for x in range(10)]))
+ return d
+
+ def test_map_noblock(self):
+ self.addEngine(1)
+ m = self.tc.mapper(block=False)
+ d = m.map(lambda x: 2*x, range(10))
+ d.addCallback(lambda r: self.assertEquals(r,[x for x in range(10)]))
+ return d
+
+ def test_mapper_fail(self):
+ self.addEngine(1)
+ m = self.tc.mapper()
+ d = m.map(lambda x: 1/0, range(10))
+ d.addBoth(lambda f: self.assertRaises(ZeroDivisionError, _raise_it, f))
+ return d
+
+ def test_parallel(self):
+ self.addEngine(1)
+ p = self.tc.parallel()
+ self.assert_(isinstance(p, ParallelFunction))
+ @p
+ def f(x): return 2*x
+ d = f(range(10))
+ d.addCallback(lambda r: self.assertEquals(r,[2*x for x in range(10)]))
+ return d
+
+ def test_parallel_noblock(self):
+ self.addEngine(1)
+ p = self.tc.parallel(block=False)
+ self.assert_(isinstance(p, ParallelFunction))
+ @p
+ def f(x): return 2*x
+ d = f(range(10))
+ d.addCallback(lambda r: self.assertEquals(r,[x for x in range(10)]))
+ return d
+
+ def test_parallel_fail(self):
+ self.addEngine(1)
+ p = self.tc.parallel()
+ self.assert_(isinstance(p, ParallelFunction))
+ @p
+ def f(x): return 1/0
+ d = f(range(10))
+ d.addBoth(lambda f: self.assertRaises(ZeroDivisionError, _raise_it, f))
+ return d \ No newline at end of file
diff --git a/IPython/kernel/tests/test_twistedutil.py b/IPython/kernel/tests/test_twistedutil.py
new file mode 100644
index 0000000..9838ff3
--- /dev/null
+++ b/IPython/kernel/tests/test_twistedutil.py
@@ -0,0 +1,51 @@
+#!/usr/bin/env python
+# encoding: utf-8
+
+#-----------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+# Tell nose to skip this module
+__test__ = {}
+
+import tempfile
+import os, sys
+
+from twisted.internet import reactor
+from twisted.trial import unittest
+
+from IPython.kernel.error import FileTimeoutError
+from IPython.kernel.twistedutil import wait_for_file
+
+#-----------------------------------------------------------------------------
+# Tests
+#-----------------------------------------------------------------------------
+
+class TestWaitForFile(unittest.TestCase):
+
+ def test_delay(self):
+ filename = tempfile.mktemp()
+ def _create_file():
+ open(filename,'w').write('####')
+ dcall = reactor.callLater(0.5, _create_file)
+ d = wait_for_file(filename,delay=0.1)
+ d.addCallback(lambda r: self.assert_(r))
+ def _cancel_dcall(r):
+ if dcall.active():
+ dcall.cancel()
+ d.addCallback(_cancel_dcall)
+ return d
+
+ def test_timeout(self):
+ filename = tempfile.mktemp()
+ d = wait_for_file(filename,delay=0.1,max_tries=1)
+ d.addErrback(lambda f: self.assertRaises(FileTimeoutError,f.raiseException))
+ return d
+ \ No newline at end of file
diff --git a/IPython/kernel/twistedutil.py b/IPython/kernel/twistedutil.py
new file mode 100644
index 0000000..33dc429
--- /dev/null
+++ b/IPython/kernel/twistedutil.py
@@ -0,0 +1,249 @@
+#!/usr/bin/env python
+# encoding: utf-8
+
+"""Things directly related to all of twisted."""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+import os, sys
+import threading, Queue, atexit
+
+import twisted
+from twisted.internet import defer, reactor
+from twisted.python import log, failure
+
+from IPython.kernel.error import FileTimeoutError
+
+#-------------------------------------------------------------------------------
+# Classes related to twisted and threads
+#-------------------------------------------------------------------------------
+
+
+class ReactorInThread(threading.Thread):
+ """Run the twisted reactor in a different thread.
+
+ For the process to be able to exit cleanly, do the following:
+
+ rit = ReactorInThread()
+ rit.setDaemon(True)
+ rit.start()
+
+ """
+
+ def run(self):
+ reactor.run(installSignalHandlers=0)
+ # self.join()
+
+ def stop(self):
+ # I don't think this does anything useful.
+ blockingCallFromThread(reactor.stop)
+ self.join()
+
+if(twisted.version.major >= 8):
+ import twisted.internet.threads
+ def blockingCallFromThread(f, *a, **kw):
+ """
+ Run a function in the reactor from a thread, and wait for the result
+ synchronously, i.e. until the callback chain returned by the function get a
+ result.
+
+ Delegates to twisted.internet.threads.blockingCallFromThread(reactor, f, *a, **kw),
+ passing twisted.internet.reactor for the first argument.
+
+ @param f: the callable to run in the reactor thread
+ @type f: any callable.
+ @param a: the arguments to pass to C{f}.
+ @param kw: the keyword arguments to pass to C{f}.
+
+ @return: the result of the callback chain.
+ @raise: any error raised during the callback chain.
+ """
+ return twisted.internet.threads.blockingCallFromThread(reactor, f, *a, **kw)
+
+else:
+ def blockingCallFromThread(f, *a, **kw):
+ """
+ Run a function in the reactor from a thread, and wait for the result
+ synchronously, i.e. until the callback chain returned by the function get a
+ result.
+
+ @param f: the callable to run in the reactor thread
+ @type f: any callable.
+ @param a: the arguments to pass to C{f}.
+ @param kw: the keyword arguments to pass to C{f}.
+
+ @return: the result of the callback chain.
+ @raise: any error raised during the callback chain.
+ """
+ from twisted.internet import reactor
+ queue = Queue.Queue()
+ def _callFromThread():
+ result = defer.maybeDeferred(f, *a, **kw)
+ result.addBoth(queue.put)
+
+ reactor.callFromThread(_callFromThread)
+ result = queue.get()
+ if isinstance(result, failure.Failure):
+ # This makes it easier for the debugger to get access to the instance
+ try:
+ result.raiseException()
+ except Exception, e:
+ raise e
+ return result
+
+
+
+#-------------------------------------------------------------------------------
+# Things for managing deferreds
+#-------------------------------------------------------------------------------
+
+
+def parseResults(results):
+ """Pull out results/Failures from a DeferredList."""
+ return [x[1] for x in results]
+
+def gatherBoth(dlist, fireOnOneCallback=0,
+ fireOnOneErrback=0,
+ consumeErrors=0,
+ logErrors=0):
+ """This is like gatherBoth, but sets consumeErrors=1."""
+ d = DeferredList(dlist, fireOnOneCallback, fireOnOneErrback,
+ consumeErrors, logErrors)
+ if not fireOnOneCallback:
+ d.addCallback(parseResults)
+ return d
+
+SUCCESS = True
+FAILURE = False
+
+class DeferredList(defer.Deferred):
+ """I combine a group of deferreds into one callback.
+
+ I track a list of L{Deferred}s for their callbacks, and make a single
+ callback when they have all completed, a list of (success, result)
+ tuples, 'success' being a boolean.
+
+ Note that you can still use a L{Deferred} after putting it in a
+ DeferredList. For example, you can suppress 'Unhandled error in Deferred'
+ messages by adding errbacks to the Deferreds *after* putting them in the
+ DeferredList, as a DeferredList won't swallow the errors. (Although a more
+ convenient way to do this is simply to set the consumeErrors flag)
+
+ Note: This is a modified version of the twisted.internet.defer.DeferredList
+ """
+
+ fireOnOneCallback = 0
+ fireOnOneErrback = 0
+
+ def __init__(self, deferredList, fireOnOneCallback=0, fireOnOneErrback=0,
+ consumeErrors=0, logErrors=0):
+ """Initialize a DeferredList.
+
+ @type deferredList: C{list} of L{Deferred}s
+ @param deferredList: The list of deferreds to track.
+ @param fireOnOneCallback: (keyword param) a flag indicating that
+ only one callback needs to be fired for me to call
+ my callback
+ @param fireOnOneErrback: (keyword param) a flag indicating that
+ only one errback needs to be fired for me to call
+ my errback
+ @param consumeErrors: (keyword param) a flag indicating that any errors
+ raised in the original deferreds should be
+ consumed by this DeferredList. This is useful to
+ prevent spurious warnings being logged.
+ """
+ self.resultList = [None] * len(deferredList)
+ defer.Deferred.__init__(self)
+ if len(deferredList) == 0 and not fireOnOneCallback:
+ self.callback(self.resultList)
+
+ # These flags need to be set *before* attaching callbacks to the
+ # deferreds, because the callbacks use these flags, and will run
+ # synchronously if any of the deferreds are already fired.
+ self.fireOnOneCallback = fireOnOneCallback
+ self.fireOnOneErrback = fireOnOneErrback
+ self.consumeErrors = consumeErrors
+ self.logErrors = logErrors
+ self.finishedCount = 0
+
+ index = 0
+ for deferred in deferredList:
+ deferred.addCallbacks(self._cbDeferred, self._cbDeferred,
+ callbackArgs=(index,SUCCESS),
+ errbackArgs=(index,FAILURE))
+ index = index + 1
+
+ def _cbDeferred(self, result, index, succeeded):
+ """(internal) Callback for when one of my deferreds fires.
+ """
+ self.resultList[index] = (succeeded, result)
+
+ self.finishedCount += 1
+ if not self.called:
+ if succeeded == SUCCESS and self.fireOnOneCallback:
+ self.callback((result, index))
+ elif succeeded == FAILURE and self.fireOnOneErrback:
+ # We have modified this to fire the errback chain with the actual
+ # Failure instance the originally occured rather than twisted's
+ # FirstError which wraps the failure
+ self.errback(result)
+ elif self.finishedCount == len(self.resultList):
+ self.callback(self.resultList)
+
+ if succeeded == FAILURE and self.logErrors:
+ log.err(result)
+ if succeeded == FAILURE and self.consumeErrors:
+ result = None
+
+ return result
+
+
+def wait_for_file(filename, delay=0.1, max_tries=10):
+ """Wait (poll) for a file to be created.
+
+ This method returns a Deferred that will fire when a file exists. It
+ works by polling os.path.isfile in time intervals specified by the
+ delay argument. If `max_tries` is reached, it will errback with a
+ `FileTimeoutError`.
+
+ Parameters
+ ----------
+ filename : str
+ The name of the file to wait for.
+ delay : float
+ The time to wait between polls.
+ max_tries : int
+ The max number of attempts before raising `FileTimeoutError`
+
+ Returns
+ -------
+ d : Deferred
+ A Deferred instance that will fire when the file exists.
+ """
+
+ d = defer.Deferred()
+
+ def _test_for_file(filename, attempt=0):
+ if attempt >= max_tries:
+ d.errback(FileTimeoutError(
+ 'timeout waiting for file to be created: %s' % filename
+ ))
+ else:
+ if os.path.isfile(filename):
+ d.callback(True)
+ else:
+ reactor.callLater(delay, _test_for_file, filename, attempt+1)
+
+ _test_for_file(filename)
+ return d
diff --git a/IPython/kernel/util.py b/IPython/kernel/util.py
new file mode 100644
index 0000000..5a5b8eb
--- /dev/null
+++ b/IPython/kernel/util.py
@@ -0,0 +1,102 @@
+# encoding: utf-8
+
+"""General utilities for kernel related things."""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+import os, types
+
+
+#-------------------------------------------------------------------------------
+# Code
+#-------------------------------------------------------------------------------
+
+def tarModule(mod):
+ """Makes a tarball (as a string) of a locally imported module.
+
+ This method looks at the __file__ attribute of an imported module
+ and makes a tarball of the top level of the module. It then
+ reads the tarball into a binary string.
+
+ The method returns the tarball's name and the binary string
+ representing the tarball.
+
+ Notes:
+
+ - It will handle both single module files, as well as packages.
+ - The byte code files (\*.pyc) are not deleted.
+ - It has not been tested with modules containing extension code, but
+ it should work in most cases.
+ - There are cross platform issues.
+
+ """
+
+ if not isinstance(mod, types.ModuleType):
+ raise TypeError, "Pass an imported module to push_module"
+ module_dir, module_file = os.path.split(mod.__file__)
+
+ # Figure out what the module is called and where it is
+ print "Locating the module..."
+ if "__init__.py" in module_file: # package
+ module_name = module_dir.split("/")[-1]
+ module_dir = "/".join(module_dir.split("/")[:-1])
+ module_file = module_name
+ else: # Simple module
+ module_name = module_file.split(".")[0]
+ module_dir = module_dir
+ print "Module (%s) found in:\n%s" % (module_name, module_dir)
+
+ # Make a tarball of the module in the cwd
+ if module_dir:
+ os.system('tar -cf %s.tar -C %s %s' % \
+ (module_name, module_dir, module_file))
+ else: # must be the cwd
+ os.system('tar -cf %s.tar %s' % \
+ (module_name, module_file))
+
+ # Read the tarball into a binary string
+ tarball_name = module_name + ".tar"
+ tar_file = open(tarball_name,'rb')
+ fileString = tar_file.read()
+ tar_file.close()
+
+ # Remove the local copy of the tarball
+ #os.system("rm %s" % tarball_name)
+
+ return tarball_name, fileString
+
+#from the Python Cookbook:
+
+def curry(f, *curryArgs, **curryKWargs):
+ """Curry the function f with curryArgs and curryKWargs."""
+
+ def curried(*args, **kwargs):
+ dikt = dict(kwargs)
+ dikt.update(curryKWargs)
+ return f(*(curryArgs+args), **dikt)
+
+ return curried
+
+#useful callbacks
+
+def catcher(r):
+ pass
+
+def printer(r, msg=''):
+ print "%s\n%r" % (msg, r)
+ return r
+
+
+
+
diff --git a/IPython/macro.py b/IPython/macro.py
new file mode 100644
index 0000000..30cf4fb
--- /dev/null
+++ b/IPython/macro.py
@@ -0,0 +1,43 @@
+"""Support for interactive macros in IPython"""
+
+#*****************************************************************************
+# Copyright (C) 2001-2005 Fernando Perez <fperez@colorado.edu>
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#*****************************************************************************
+
+import IPython.ipapi
+
+from IPython.genutils import Term
+from IPython.ipapi import IPyAutocall
+
+class Macro(IPyAutocall):
+ """Simple class to store the value of macros as strings.
+
+ Macro is just a callable that executes a string of IPython
+ input when called.
+
+ Args to macro are available in _margv list if you need them.
+ """
+
+ def __init__(self,data):
+
+ # store the macro value, as a single string which can be evaluated by
+ # runlines()
+ self.value = ''.join(data).rstrip()+'\n'
+
+ def __str__(self):
+ return self.value
+
+ def __repr__(self):
+ return 'IPython.macro.Macro(%s)' % repr(self.value)
+
+ def __call__(self,*args):
+ Term.cout.flush()
+ self._ip.user_ns['_margv'] = args
+ self._ip.runlines(self.value)
+
+ def __getstate__(self):
+ """ needed for safe pickling via %store """
+ return {'value': self.value}
diff --git a/IPython/numutils.py b/IPython/numutils.py
new file mode 100644
index 0000000..977d7ee
--- /dev/null
+++ b/IPython/numutils.py
@@ -0,0 +1,302 @@
+# -*- coding: utf-8 -*-
+"""
+A set of convenient utilities for numerical work.
+
+Most of this module requires Numerical Python or is meant to be used with it.
+See http://www.pfdubois.com/numpy for details.
+"""
+
+#*****************************************************************************
+# Copyright (C) 2001-2005 Fernando Perez <fperez@colorado.edu>
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#*****************************************************************************
+
+__all__ = ['sum_flat','mean_flat','rms_flat','base_repr','binary_repr',
+ 'amin','amax','amap','zeros_like','empty_like',
+ 'frange','diagonal_matrix','identity',
+ 'fromfunction_kw','log2','ispower2',
+ 'norm','l1norm','l2norm','exp_safe',
+ 'inf','infty','Infinity',
+ 'Numeric']
+
+#****************************************************************************
+# required modules
+import __main__
+import math
+import operator
+import sys
+
+import Numeric
+from Numeric import *
+
+#*****************************************************************************
+# Globals
+
+# useful for testing infinities in results of array divisions (which don't
+# raise an exception)
+# Python, LaTeX and Mathematica names.
+inf = infty = Infinity = (array([1])/0.0)[0]
+
+#****************************************************************************
+# function definitions
+exp_safe_MIN = math.log(2.2250738585072014e-308)
+exp_safe_MAX = 1.7976931348623157e+308
+
+def exp_safe(x):
+ """Compute exponentials which safely underflow to zero.
+
+ Slow but convenient to use. Note that NumArray will introduce proper
+ floating point exception handling with access to the underlying
+ hardware."""
+
+ if type(x) is ArrayType:
+ return exp(clip(x,exp_safe_MIN,exp_safe_MAX))
+ else:
+ return math.exp(x)
+
+def amap(fn,*args):
+ """amap(function, sequence[, sequence, ...]) -> array.
+
+ Works like map(), but it returns an array. This is just a convenient
+ shorthand for Numeric.array(map(...))"""
+ return array(map(fn,*args))
+
+def amin(m,axis=0):
+ """amin(m,axis=0) returns the minimum of m along dimension axis.
+ """
+ return minimum.reduce(asarray(m),axis)
+
+def amax(m,axis=0):
+ """amax(m,axis=0) returns the maximum of m along dimension axis.
+ """
+ return maximum.reduce(asarray(m),axis)
+
+def zeros_like(a):
+ """Return an array of zeros of the shape and typecode of a.
+
+ If you don't explicitly need the array to be zeroed, you should instead
+ use empty_like(), which is faster as it only allocates memory."""
+
+ return zeros(a.shape,a.typecode())
+
+def empty_like(a):
+ """Return an empty (uninitialized) array of the shape and typecode of a.
+
+ Note that this does NOT initialize the returned array. If you require
+ your array to be initialized, you should use zeros_like().
+
+ This requires Numeric.empty(), which appeared in Numeric 23.7."""
+
+ return empty(a.shape,a.typecode())
+
+def sum_flat(a):
+ """Return the sum of all the elements of a, flattened out.
+
+ It uses a.flat, and if a is not contiguous, a call to ravel(a) is made."""
+
+ if a.iscontiguous():
+ return Numeric.sum(a.flat)
+ else:
+ return Numeric.sum(ravel(a))
+
+def mean_flat(a):
+ """Return the mean of all the elements of a, flattened out."""
+
+ return sum_flat(a)/float(size(a))
+
+def rms_flat(a):
+ """Return the root mean square of all the elements of a, flattened out."""
+
+ return math.sqrt(sum_flat(absolute(a)**2)/float(size(a)))
+
+def l1norm(a):
+ """Return the l1 norm of a, flattened out.
+
+ Implemented as a separate function (not a call to norm() for speed).
+
+ Ref: http://mathworld.wolfram.com/L1-Norm.html"""
+
+ return sum_flat(absolute(a))
+
+def l2norm(a):
+ """Return the l2 norm of a, flattened out.
+
+ Implemented as a separate function (not a call to norm() for speed).
+
+ Ref: http://mathworld.wolfram.com/L2-Norm.html"""
+
+ return math.sqrt(sum_flat(absolute(a)**2))
+
+def norm(a,p=2):
+ """norm(a,p=2) -> l-p norm of a.flat
+
+ Return the l-p norm of a, considered as a flat array. This is NOT a true
+ matrix norm, since arrays of arbitrary rank are always flattened.
+
+ p can be a number or one of the strings ('inf','Infinity') to get the
+ L-infinity norm.
+
+ Ref: http://mathworld.wolfram.com/VectorNorm.html
+ http://mathworld.wolfram.com/L-Infinity-Norm.html"""
+
+ if p in ('inf','Infinity'):
+ return max(absolute(a).flat)
+ else:
+ return (sum_flat(absolute(a)**p))**(1.0/p)
+
+def frange(xini,xfin=None,delta=None,**kw):
+ """frange([start,] stop[, step, keywords]) -> array of floats
+
+ Return a Numeric array() containing a progression of floats. Similar to
+ arange(), but defaults to a closed interval.
+
+ frange(x0, x1) returns [x0, x0+1, x0+2, ..., x1]; start defaults to 0, and
+ the endpoint *is included*. This behavior is different from that of
+ range() and arange(). This is deliberate, since frange will probably be
+ more useful for generating lists of points for function evaluation, and
+ endpoints are often desired in this use. The usual behavior of range() can
+ be obtained by setting the keyword 'closed=0', in this case frange()
+ basically becomes arange().
+
+ When step is given, it specifies the increment (or decrement). All
+ arguments can be floating point numbers.
+
+ frange(x0,x1,d) returns [x0,x0+d,x0+2d,...,xfin] where xfin<=x1.
+
+ frange can also be called with the keyword 'npts'. This sets the number of
+ points the list should contain (and overrides the value 'step' might have
+ been given). arange() doesn't offer this option.
+
+ Examples:
+ >>> frange(3)
+ array([ 0., 1., 2., 3.])
+ >>> frange(3,closed=0)
+ array([ 0., 1., 2.])
+ >>> frange(1,6,2)
+ array([1, 3, 5])
+ >>> frange(1,6.5,npts=5)
+ array([ 1. , 2.375, 3.75 , 5.125, 6.5 ])
+ """
+
+ #defaults
+ kw.setdefault('closed',1)
+ endpoint = kw['closed'] != 0
+
+ # funny logic to allow the *first* argument to be optional (like range())
+ # This was modified with a simpler version from a similar frange() found
+ # at http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66472
+ if xfin == None:
+ xfin = xini + 0.0
+ xini = 0.0
+
+ if delta == None:
+ delta = 1.0
+
+ # compute # of points, spacing and return final list
+ try:
+ npts=kw['npts']
+ delta=(xfin-xini)/float(npts-endpoint)
+ except KeyError:
+ # round() gets npts right even with the vagaries of floating point.
+ npts=int(round((xfin-xini)/delta+endpoint))
+
+ return arange(npts)*delta+xini
+
+def diagonal_matrix(diag):
+ """Return square diagonal matrix whose non-zero elements are given by the
+ input array."""
+
+ return diag*identity(len(diag))
+
+def identity(n,rank=2,typecode='l'):
+ """identity(n,r) returns the identity matrix of shape (n,n,...,n) (rank r).
+
+ For ranks higher than 2, this object is simply a multi-index Kronecker
+ delta:
+ / 1 if i0=i1=...=iR,
+ id[i0,i1,...,iR] = -|
+ \ 0 otherwise.
+
+ Optionally a typecode may be given (it defaults to 'l').
+
+ Since rank defaults to 2, this function behaves in the default case (when
+ only n is given) like the Numeric identity function."""
+
+ iden = zeros((n,)*rank,typecode=typecode)
+ for i in range(n):
+ idx = (i,)*rank
+ iden[idx] = 1
+ return iden
+
+def base_repr (number, base = 2, padding = 0):
+ """Return the representation of a number in any given base."""
+ chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+ if number < base: \
+ return (padding - 1) * chars [0] + chars [int (number)]
+ max_exponent = int (math.log (number)/math.log (base))
+ max_power = long (base) ** max_exponent
+ lead_digit = int (number/max_power)
+ return chars [lead_digit] + \
+ base_repr (number - max_power * lead_digit, base, \
+ max (padding - 1, max_exponent))
+
+def binary_repr(number, max_length = 1025):
+ """Return the binary representation of the input number as a string.
+
+ This is more efficient than using base_repr with base 2.
+
+ Increase the value of max_length for very large numbers. Note that on
+ 32-bit machines, 2**1023 is the largest integer power of 2 which can be
+ converted to a Python float."""
+
+ assert number < 2L << max_length
+ shifts = map (operator.rshift, max_length * [number], \
+ range (max_length - 1, -1, -1))
+ digits = map (operator.mod, shifts, max_length * [2])
+ if not digits.count (1): return 0
+ digits = digits [digits.index (1):]
+ return ''.join (map (repr, digits)).replace('L','')
+
+def log2(x,ln2 = math.log(2.0)):
+ """Return the log(x) in base 2.
+
+ This is a _slow_ function but which is guaranteed to return the correct
+ integer value if the input is an ineger exact power of 2."""
+
+ try:
+ bin_n = binary_repr(x)[1:]
+ except (AssertionError,TypeError):
+ return math.log(x)/ln2
+ else:
+ if '1' in bin_n:
+ return math.log(x)/ln2
+ else:
+ return len(bin_n)
+
+def ispower2(n):
+ """Returns the log base 2 of n if n is a power of 2, zero otherwise.
+
+ Note the potential ambiguity if n==1: 2**0==1, interpret accordingly."""
+
+ bin_n = binary_repr(n)[1:]
+ if '1' in bin_n:
+ return 0
+ else:
+ return len(bin_n)
+
+def fromfunction_kw(function, dimensions, **kwargs):
+ """Drop-in replacement for fromfunction() from Numerical Python.
+
+ Allows passing keyword arguments to the desired function.
+
+ Call it as (keywords are optional):
+ fromfunction_kw(MyFunction, dimensions, keywords)
+
+ The function MyFunction() is responsible for handling the dictionary of
+ keywords it will recieve."""
+
+ return function(tuple(indices(dimensions)),**kwargs)
+
+#**************************** end file <numutils.py> ************************
diff --git a/IPython/platutils.py b/IPython/platutils.py
new file mode 100644
index 0000000..ab5c2a7
--- /dev/null
+++ b/IPython/platutils.py
@@ -0,0 +1,103 @@
+# -*- coding: utf-8 -*-
+""" Proxy module for accessing platform specific utility functions.
+
+Importing this module should give you the implementations that are correct
+for your operation system, from platutils_PLATFORMNAME module.
+"""
+
+#*****************************************************************************
+# Copyright (C) 2001-2006 Fernando Perez <fperez@colorado.edu>
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#*****************************************************************************
+
+import os
+import sys
+import warnings
+
+# Import the platform-specific implementations
+if os.name == 'posix':
+ import platutils_posix as _platutils
+elif sys.platform == 'win32':
+ import platutils_win32 as _platutils
+else:
+ import platutils_dummy as _platutils
+
+# Functionality that's logically common to all platforms goes here, each
+# platform-specific module only provides the bits that are OS-dependent.
+
+# XXX - I'm still not happy with a module global for this, but at least now
+# there is a public, cross-platform way of toggling the term title control on
+# and off. We should make this a stateful object later on so that each user
+# can have its own instance if needed.
+def term_clear():
+ _platutils.term_clear()
+
+def toggle_set_term_title(val):
+ """Control whether set_term_title is active or not.
+
+ set_term_title() allows writing to the console titlebar. In embedded
+ widgets this can cause problems, so this call can be used to toggle it on
+ or off as needed.
+
+ The default state of the module is for the function to be disabled.
+
+ Parameters
+ ----------
+ val : bool
+ If True, set_term_title() actually writes to the terminal (using the
+ appropriate platform-specific module). If False, it is a no-op.
+ """
+ _platutils.ignore_termtitle = not(val)
+
+
+def set_term_title(title):
+ """Set terminal title using the necessary platform-dependent calls."""
+
+ if _platutils.ignore_termtitle:
+ return
+ _platutils.set_term_title(title)
+
+
+class FindCmdError(Exception):
+ pass
+
+def find_cmd(cmd):
+ """Find full path to executable cmd in a cross platform manner.
+
+ This function tries to determine the full path to a command line program
+ using `which` on Unix/Linux/OS X and `win32api` on Windows. Most of the
+ time it will use the version that is first on the users `PATH`. If
+ cmd is `python` return `sys.executable`.
+
+ Parameters
+ ----------
+ cmd : str
+ The command line program to look for.
+ """
+ if cmd == 'python':
+ return sys.executable
+ try:
+ path = _platutils.find_cmd(cmd)
+ except:
+ raise FindCmdError('command could not be found: %s' % cmd)
+ # which returns empty if not found
+ if path == '':
+ raise FindCmdError('command could not be found: %s' % cmd)
+ return path
+
+def get_long_path_name(path):
+ """Expand a path into its long form.
+
+ On Windows this expands any ~ in the paths. On other platforms, it is
+ a null operation.
+ """
+ return _platutils.get_long_path_name(path)
+
+#-----------------------------------------------------------------------------
+# Deprecated functions
+#-----------------------------------------------------------------------------
+def freeze_term_title():
+ warnings.warn("This function is deprecated, use toggle_set_term_title()")
+ _platutils.ignore_termtitle = True
diff --git a/IPython/platutils_dummy.py b/IPython/platutils_dummy.py
new file mode 100644
index 0000000..0cb8965
--- /dev/null
+++ b/IPython/platutils_dummy.py
@@ -0,0 +1,33 @@
+# -*- coding: utf-8 -*-
+""" Platform specific utility functions, dummy version
+
+This has empty implementation of the platutils functions, used for
+unsupported operating systems.
+
+Authors
+-------
+- Ville Vainio <vivainio@gmail.com>
+"""
+
+#*****************************************************************************
+# Copyright (C) 2008-2009 The IPython Development Team
+# Copyright (C) 2001-2007 Fernando Perez <fperez@colorado.edu>
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#*****************************************************************************
+
+# This variable is part of the expected API of the module:
+ignore_termtitle = True
+
+def set_term_title(*args,**kw):
+ """Dummy no-op."""
+ pass
+
+def find_cmd(cmd):
+ """Find the full path to a command using which."""
+ return os.popen('which %s' % cmd).read().strip()
+
+def get_long_path_name(path):
+ """Dummy no-op."""
+ return path
diff --git a/IPython/platutils_posix.py b/IPython/platutils_posix.py
new file mode 100644
index 0000000..3c38dba
--- /dev/null
+++ b/IPython/platutils_posix.py
@@ -0,0 +1,47 @@
+# -*- coding: utf-8 -*-
+""" Platform specific utility functions, posix version
+
+Importing this module directly is not portable - rather, import platutils
+to use these functions in platform agnostic fashion.
+"""
+
+#*****************************************************************************
+# Copyright (C) 2001-2006 Fernando Perez <fperez@colorado.edu>
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#*****************************************************************************
+
+import sys
+import os
+
+ignore_termtitle = True
+
+def _dummy_op(*a, **b):
+ """ A no-op function """
+
+
+def _set_term_title_xterm(title):
+ """ Change virtual terminal title in xterm-workalikes """
+
+ sys.stdout.write('\033]0;%s\007' % title)
+
+
+if os.environ.get('TERM','') == 'xterm':
+ set_term_title = _set_term_title_xterm
+else:
+ set_term_title = _dummy_op
+
+
+def find_cmd(cmd):
+ """Find the full path to a command using which."""
+ return os.popen('which %s' % cmd).read().strip()
+
+
+def get_long_path_name(path):
+ """Dummy no-op."""
+ return path
+
+
+def term_clear():
+ os.system('clear')
diff --git a/IPython/platutils_win32.py b/IPython/platutils_win32.py
new file mode 100644
index 0000000..9afc060
--- /dev/null
+++ b/IPython/platutils_win32.py
@@ -0,0 +1,94 @@
+# -*- coding: utf-8 -*-
+""" Platform specific utility functions, win32 version
+
+Importing this module directly is not portable - rather, import platutils
+to use these functions in platform agnostic fashion.
+"""
+
+#*****************************************************************************
+# Copyright (C) 2001-2006 Fernando Perez <fperez@colorado.edu>
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#*****************************************************************************
+
+import os
+
+ignore_termtitle = True
+
+try:
+ import ctypes
+
+ SetConsoleTitleW = ctypes.windll.kernel32.SetConsoleTitleW
+ SetConsoleTitleW.argtypes = [ctypes.c_wchar_p]
+
+ def set_term_title(title):
+ """Set terminal title using ctypes to access the Win32 APIs."""
+ SetConsoleTitleW(title)
+
+except ImportError:
+ def set_term_title(title):
+ """Set terminal title using the 'title' command."""
+ global ignore_termtitle
+
+ try:
+ # Cannot be on network share when issuing system commands
+ curr = os.getcwd()
+ os.chdir("C:")
+ ret = os.system("title " + title)
+ finally:
+ os.chdir(curr)
+ if ret:
+ # non-zero return code signals error, don't try again
+ ignore_termtitle = True
+
+
+def find_cmd(cmd):
+ """Find the full path to a .bat or .exe using the win32api module."""
+ try:
+ from win32api import SearchPath
+ except ImportError:
+ raise ImportError('you need to have pywin32 installed for this to work')
+ else:
+ PATH = os.environ['PATH']
+ extensions = ['.exe', '.com', '.bat', '.py']
+ path = None
+ for ext in extensions:
+ try:
+ path = SearchPath(PATH,cmd + ext)[0]
+ except:
+ pass
+ if path is None:
+ raise OSError("command %r not found" % cmd)
+ else:
+ return path
+
+
+def get_long_path_name(path):
+ """Get a long path name (expand ~) on Windows using ctypes.
+
+ Examples
+ --------
+
+ >>> get_long_path_name('c:\\docume~1')
+ u'c:\\\\Documents and Settings'
+
+ """
+ try:
+ import ctypes
+ except ImportError:
+ raise ImportError('you need to have ctypes installed for this to work')
+ _GetLongPathName = ctypes.windll.kernel32.GetLongPathNameW
+ _GetLongPathName.argtypes = [ctypes.c_wchar_p, ctypes.c_wchar_p,
+ ctypes.c_uint ]
+
+ buf = ctypes.create_unicode_buffer(260)
+ rv = _GetLongPathName(path, buf, 260)
+ if rv == 0 or rv > 260:
+ return path
+ else:
+ return buf.value
+
+
+def term_clear():
+ os.system('cls')
diff --git a/IPython/prefilter.py b/IPython/prefilter.py
new file mode 100644
index 0000000..44ab9c7
--- /dev/null
+++ b/IPython/prefilter.py
@@ -0,0 +1,320 @@
+# -*- coding: utf-8 -*-
+"""
+Classes and functions for prefiltering (transforming) a line of user input.
+This module is responsible, primarily, for breaking the line up into useful
+pieces and triggering the appropriate handlers in iplib to do the actual
+transforming work.
+"""
+__docformat__ = "restructuredtext en"
+
+import re
+import IPython.ipapi
+
+class LineInfo(object):
+ """A single line of input and associated info.
+
+ Includes the following as properties:
+
+ line
+ The original, raw line
+
+ continue_prompt
+ Is this line a continuation in a sequence of multiline input?
+
+ pre
+ The initial esc character or whitespace.
+
+ preChar
+ The escape character(s) in pre or the empty string if there isn't one.
+ Note that '!!' is a possible value for preChar. Otherwise it will
+ always be a single character.
+
+ preWhitespace
+ The leading whitespace from pre if it exists. If there is a preChar,
+ this is just ''.
+
+ iFun
+ The 'function part', which is basically the maximal initial sequence
+ of valid python identifiers and the '.' character. This is what is
+ checked for alias and magic transformations, used for auto-calling,
+ etc.
+
+ theRest
+ Everything else on the line.
+ """
+ def __init__(self, line, continue_prompt):
+ self.line = line
+ self.continue_prompt = continue_prompt
+ self.pre, self.iFun, self.theRest = splitUserInput(line)
+
+ self.preChar = self.pre.strip()
+ if self.preChar:
+ self.preWhitespace = '' # No whitespace allowd before esc chars
+ else:
+ self.preWhitespace = self.pre
+
+ self._oinfo = None
+
+ def ofind(self, ip):
+ """Do a full, attribute-walking lookup of the iFun in the various
+ namespaces for the given IPython InteractiveShell instance.
+
+ Return a dict with keys: found,obj,ospace,ismagic
+
+ Note: can cause state changes because of calling getattr, but should
+ only be run if autocall is on and if the line hasn't matched any
+ other, less dangerous handlers.
+
+ Does cache the results of the call, so can be called multiple times
+ without worrying about *further* damaging state.
+ """
+ if not self._oinfo:
+ self._oinfo = ip._ofind(self.iFun)
+ return self._oinfo
+ def __str__(self):
+ return "Lineinfo [%s|%s|%s]" %(self.pre,self.iFun,self.theRest)
+
+def splitUserInput(line, pattern=None):
+ """Split user input into pre-char/whitespace, function part and rest.
+
+ Mostly internal to this module, but also used by iplib.expand_aliases,
+ which passes in a shell pattern.
+ """
+ # It seems to me that the shell splitting should be a separate method.
+
+ if not pattern:
+ pattern = line_split
+ match = pattern.match(line)
+ if not match:
+ #print "match failed for line '%s'" % line
+ try:
+ iFun,theRest = line.split(None,1)
+ except ValueError:
+ #print "split failed for line '%s'" % line
+ iFun,theRest = line,''
+ pre = re.match('^(\s*)(.*)',line).groups()[0]
+ else:
+ pre,iFun,theRest = match.groups()
+
+ # iFun has to be a valid python identifier, so it better be only pure
+ # ascii, no unicode:
+ try:
+ iFun = iFun.encode('ascii')
+ except UnicodeEncodeError:
+ theRest = iFun + u' ' + theRest
+ iFun = u''
+
+ #print 'line:<%s>' % line # dbg
+ #print 'pre <%s> iFun <%s> rest <%s>' % (pre,iFun.strip(),theRest) # dbg
+ return pre,iFun.strip(),theRest.lstrip()
+
+
+# RegExp for splitting line contents into pre-char//first word-method//rest.
+# For clarity, each group in on one line.
+
+# WARNING: update the regexp if the escapes in iplib are changed, as they
+# are hardwired in.
+
+# Although it's not solely driven by the regex, note that:
+# ,;/% only trigger if they are the first character on the line
+# ! and !! trigger if they are first char(s) *or* follow an indent
+# ? triggers as first or last char.
+
+# The three parts of the regex are:
+# 1) pre: pre_char *or* initial whitespace
+# 2) iFun: first word/method (mix of \w and '.')
+# 3) theRest: rest of line (separated from iFun by space if non-empty)
+line_split = re.compile(r'^([,;/%?]|!!?|\s*)'
+ r'\s*([\w\.]+)'
+ r'(\s+.*$|$)')
+
+shell_line_split = re.compile(r'^(\s*)(\S*\s*)(.*$)')
+
+def prefilter(line_info, ip):
+ """Call one of the passed-in InteractiveShell's handler preprocessors,
+ depending on the form of the line. Return the results, which must be a
+ value, even if it's a blank ('')."""
+ # Note: the order of these checks does matter.
+ for check in [ checkEmacs,
+ checkShellEscape,
+ checkIPyAutocall,
+ checkMultiLineMagic,
+ checkEscChars,
+ checkAssignment,
+ checkAutomagic,
+ checkAlias,
+ checkPythonOps,
+ checkAutocall,
+ ]:
+ handler = check(line_info, ip)
+ if handler:
+ return handler(line_info)
+
+ return ip.handle_normal(line_info)
+
+# Handler checks
+#
+# All have the same interface: they take a LineInfo object and a ref to the
+# iplib.InteractiveShell object. They check the line to see if a particular
+# handler should be called, and return either a handler or None. The
+# handlers which they return are *bound* methods of the InteractiveShell
+# object.
+#
+# In general, these checks should only take responsibility for their 'own'
+# handler. If it doesn't get triggered, they should just return None and
+# let the rest of the check sequence run.
+
+def checkShellEscape(l_info,ip):
+ if l_info.line.lstrip().startswith(ip.ESC_SHELL):
+ return ip.handle_shell_escape
+
+def checkEmacs(l_info,ip):
+ "Emacs ipython-mode tags certain input lines."
+ if l_info.line.endswith('# PYTHON-MODE'):
+ return ip.handle_emacs
+ else:
+ return None
+
+def checkIPyAutocall(l_info,ip):
+ "Instances of IPyAutocall in user_ns get autocalled immediately"
+ obj = ip.user_ns.get(l_info.iFun, None)
+ if isinstance(obj, IPython.ipapi.IPyAutocall):
+ obj.set_ip(ip.api)
+ return ip.handle_auto
+ else:
+ return None
+
+
+def checkMultiLineMagic(l_info,ip):
+ "Allow ! and !! in multi-line statements if multi_line_specials is on"
+ # Note that this one of the only places we check the first character of
+ # iFun and *not* the preChar. Also note that the below test matches
+ # both ! and !!.
+ if l_info.continue_prompt \
+ and ip.rc.multi_line_specials:
+ if l_info.iFun.startswith(ip.ESC_MAGIC):
+ return ip.handle_magic
+ else:
+ return None
+
+def checkEscChars(l_info,ip):
+ """Check for escape character and return either a handler to handle it,
+ or None if there is no escape char."""
+ if l_info.line[-1] == ip.ESC_HELP \
+ and l_info.preChar != ip.ESC_SHELL \
+ and l_info.preChar != ip.ESC_SH_CAP:
+ # the ? can be at the end, but *not* for either kind of shell escape,
+ # because a ? can be a vaild final char in a shell cmd
+ return ip.handle_help
+ elif l_info.preChar in ip.esc_handlers:
+ return ip.esc_handlers[l_info.preChar]
+ else:
+ return None
+
+
+def checkAssignment(l_info,ip):
+ """Check to see if user is assigning to a var for the first time, in
+ which case we want to avoid any sort of automagic / autocall games.
+
+ This allows users to assign to either alias or magic names true python
+ variables (the magic/alias systems always take second seat to true
+ python code). E.g. ls='hi', or ls,that=1,2"""
+ if l_info.theRest and l_info.theRest[0] in '=,':
+ return ip.handle_normal
+ else:
+ return None
+
+
+def checkAutomagic(l_info,ip):
+ """If the iFun is magic, and automagic is on, run it. Note: normal,
+ non-auto magic would already have been triggered via '%' in
+ check_esc_chars. This just checks for automagic. Also, before
+ triggering the magic handler, make sure that there is nothing in the
+ user namespace which could shadow it."""
+ if not ip.rc.automagic or not hasattr(ip,'magic_'+l_info.iFun):
+ return None
+
+ # We have a likely magic method. Make sure we should actually call it.
+ if l_info.continue_prompt and not ip.rc.multi_line_specials:
+ return None
+
+ head = l_info.iFun.split('.',1)[0]
+ if isShadowed(head,ip):
+ return None
+
+ return ip.handle_magic
+
+
+def checkAlias(l_info,ip):
+ "Check if the initital identifier on the line is an alias."
+ # Note: aliases can not contain '.'
+ head = l_info.iFun.split('.',1)[0]
+
+ if l_info.iFun not in ip.alias_table \
+ or head not in ip.alias_table \
+ or isShadowed(head,ip):
+ return None
+
+ return ip.handle_alias
+
+
+def checkPythonOps(l_info,ip):
+ """If the 'rest' of the line begins with a function call or pretty much
+ any python operator, we should simply execute the line (regardless of
+ whether or not there's a possible autocall expansion). This avoids
+ spurious (and very confusing) geattr() accesses."""
+ if l_info.theRest and l_info.theRest[0] in '!=()<>,+*/%^&|':
+ return ip.handle_normal
+ else:
+ return None
+
+
+def checkAutocall(l_info,ip):
+ "Check if the initial word/function is callable and autocall is on."
+ if not ip.rc.autocall:
+ return None
+
+ oinfo = l_info.ofind(ip) # This can mutate state via getattr
+ if not oinfo['found']:
+ return None
+
+ if callable(oinfo['obj']) \
+ and (not re_exclude_auto.match(l_info.theRest)) \
+ and re_fun_name.match(l_info.iFun):
+ #print 'going auto' # dbg
+ return ip.handle_auto
+ else:
+ #print 'was callable?', callable(l_info.oinfo['obj']) # dbg
+ return None
+
+# RegExp to identify potential function names
+re_fun_name = re.compile(r'[a-zA-Z_]([a-zA-Z0-9_.]*) *$')
+
+# RegExp to exclude strings with this start from autocalling. In
+# particular, all binary operators should be excluded, so that if foo is
+# callable, foo OP bar doesn't become foo(OP bar), which is invalid. The
+# characters '!=()' don't need to be checked for, as the checkPythonChars
+# routine explicitely does so, to catch direct calls and rebindings of
+# existing names.
+
+# Warning: the '-' HAS TO BE AT THE END of the first group, otherwise
+# it affects the rest of the group in square brackets.
+re_exclude_auto = re.compile(r'^[,&^\|\*/\+-]'
+ r'|^is |^not |^in |^and |^or ')
+
+# try to catch also methods for stuff in lists/tuples/dicts: off
+# (experimental). For this to work, the line_split regexp would need
+# to be modified so it wouldn't break things at '['. That line is
+# nasty enough that I shouldn't change it until I can test it _well_.
+#self.re_fun_name = re.compile (r'[a-zA-Z_]([a-zA-Z0-9_.\[\]]*) ?$')
+
+# Handler Check Utilities
+def isShadowed(identifier,ip):
+ """Is the given identifier defined in one of the namespaces which shadow
+ the alias and magic namespaces? Note that an identifier is different
+ than iFun, because it can not contain a '.' character."""
+ # This is much safer than calling ofind, which can change state
+ return (identifier in ip.user_ns \
+ or identifier in ip.internal_ns \
+ or identifier in ip.ns_table['builtin'])
+
diff --git a/IPython/rlineimpl.py b/IPython/rlineimpl.py
new file mode 100644
index 0000000..aa0ba63
--- /dev/null
+++ b/IPython/rlineimpl.py
@@ -0,0 +1,55 @@
+# -*- coding: utf-8 -*-
+""" Imports and provides the 'correct' version of readline for the platform.
+
+Readline is used throughout IPython as 'import IPython.rlineimpl as readline'.
+
+In addition to normal readline stuff, this module provides have_readline
+boolean and _outputfile variable used in genutils.
+"""
+
+import sys
+
+try:
+ from readline import *
+ import readline as _rl
+ have_readline = True
+except ImportError:
+ try:
+ from pyreadline import *
+ import pyreadline as _rl
+ have_readline = True
+ except ImportError:
+ have_readline = False
+
+if sys.platform == 'win32' and have_readline:
+ try:
+ _outputfile=_rl.GetOutputFile()
+ except AttributeError:
+ print "Failed GetOutputFile"
+ have_readline = False
+
+# Test to see if libedit is being used instead of GNU readline.
+# Thanks to Boyd Waters for this patch.
+uses_libedit = False
+if sys.platform == 'darwin' and have_readline:
+ import commands
+ (status, result) = commands.getstatusoutput( "otool -L %s | grep libedit" % _rl.__file__ )
+ if status == 0 and len(result) > 0:
+ # we are bound to libedit - new in Leopard
+ _rl.parse_and_bind("bind ^I rl_complete")
+ print "Leopard libedit detected."
+ uses_libedit = True
+
+
+# the clear_history() function was only introduced in Python 2.4 and is
+# actually optional in the readline API, so we must explicitly check for its
+# existence. Some known platforms actually don't have it. This thread:
+# http://mail.python.org/pipermail/python-dev/2003-August/037845.html
+# has the original discussion.
+
+if have_readline:
+ try:
+ _rl.clear_history
+ except AttributeError:
+ def clear_history(): pass
+ _rl.clear_history = clear_history
diff --git a/IPython/shadowns.py b/IPython/shadowns.py
new file mode 100644
index 0000000..d2d93b6
--- /dev/null
+++ b/IPython/shadowns.py
@@ -0,0 +1 @@
+""" Shadow namespace """ \ No newline at end of file
diff --git a/IPython/shellglobals.py b/IPython/shellglobals.py
new file mode 100644
index 0000000..34ce467
--- /dev/null
+++ b/IPython/shellglobals.py
@@ -0,0 +1,101 @@
+"""Some globals used by the main Shell classes.
+"""
+
+#-----------------------------------------------------------------------------
+# Module imports
+#-----------------------------------------------------------------------------
+
+# stdlib
+import inspect
+import thread
+
+try:
+ import ctypes
+ HAS_CTYPES = True
+except ImportError:
+ HAS_CTYPES = False
+
+# our own
+from IPython.genutils import Term,warn,error,flag_calls, ask_yes_no
+
+#-----------------------------------------------------------------------------
+# Globals
+#-----------------------------------------------------------------------------
+# global flag to pass around information about Ctrl-C without exceptions
+KBINT = False
+
+# global flag to turn on/off Tk support.
+USE_TK = False
+
+# ID for the main thread, used for cross-thread exceptions
+MAIN_THREAD_ID = thread.get_ident()
+
+# Tag when runcode() is active, for exception handling
+CODE_RUN = None
+
+#-----------------------------------------------------------------------------
+# This class is trivial now, but I want to have it in to publish a clean
+# interface. Later when the internals are reorganized, code that uses this
+# shouldn't have to change.
+
+if HAS_CTYPES:
+ # Add async exception support. Trick taken from:
+ # http://sebulba.wikispaces.com/recipe+thread2
+ def _async_raise(tid, exctype):
+ """raises the exception, performs cleanup if needed"""
+ if not inspect.isclass(exctype):
+ raise TypeError("Only types can be raised (not instances)")
+ res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid,
+ ctypes.py_object(exctype))
+ if res == 0:
+ raise ValueError("invalid thread id")
+ elif res != 1:
+ # """if it returns a number greater than one, you're in trouble,
+ # and you should call it again with exc=NULL to revert the effect"""
+ ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, 0)
+ raise SystemError("PyThreadState_SetAsyncExc failed")
+
+ def sigint_handler (signum,stack_frame):
+ """Sigint handler for threaded apps.
+
+ This is a horrible hack to pass information about SIGINT _without_
+ using exceptions, since I haven't been able to properly manage
+ cross-thread exceptions in GTK/WX. In fact, I don't think it can be
+ done (or at least that's my understanding from a c.l.py thread where
+ this was discussed)."""
+
+ global KBINT
+
+ if CODE_RUN:
+ _async_raise(MAIN_THREAD_ID,KeyboardInterrupt)
+ else:
+ KBINT = True
+ print '\nKeyboardInterrupt - Press <Enter> to continue.',
+ Term.cout.flush()
+
+else:
+ def sigint_handler (signum,stack_frame):
+ """Sigint handler for threaded apps.
+
+ This is a horrible hack to pass information about SIGINT _without_
+ using exceptions, since I haven't been able to properly manage
+ cross-thread exceptions in GTK/WX. In fact, I don't think it can be
+ done (or at least that's my understanding from a c.l.py thread where
+ this was discussed)."""
+
+ global KBINT
+
+ print '\nKeyboardInterrupt - Press <Enter> to continue.',
+ Term.cout.flush()
+ # Set global flag so that runsource can know that Ctrl-C was hit
+ KBINT = True
+
+
+def run_in_frontend(src):
+ """ Check if source snippet can be run in the REPL thread, as opposed to
+ GUI mainloop (to prevent unnecessary hanging of mainloop).
+ """
+
+ if src.startswith('_ip.system(') and not '\n' in src:
+ return True
+ return False
diff --git a/IPython/strdispatch.py b/IPython/strdispatch.py
new file mode 100644
index 0000000..7113537
--- /dev/null
+++ b/IPython/strdispatch.py
@@ -0,0 +1,69 @@
+"""String dispatch class to match regexps and dispatch commands.
+"""
+
+# Stdlib imports
+import re
+
+# Our own modules
+from IPython.hooks import CommandChainDispatcher
+import IPython.hooks
+
+# Code begins
+class StrDispatch(object):
+ """Dispatch (lookup) a set of strings / regexps for match.
+
+ Example:
+
+ >>> dis = StrDispatch()
+ >>> dis.add_s('hei',34, priority = 4)
+ >>> dis.add_s('hei',123, priority = 2)
+ >>> dis.add_re('h.i', 686)
+ >>> print list(dis.flat_matches('hei'))
+ [123, 34, 686]
+ """
+
+ def __init__(self):
+ self.strs = {}
+ self.regexs = {}
+
+ def add_s(self, s, obj, priority= 0 ):
+ """ Adds a target 'string' for dispatching """
+
+ chain = self.strs.get(s, CommandChainDispatcher())
+ chain.add(obj,priority)
+ self.strs[s] = chain
+
+ def add_re(self, regex, obj, priority= 0 ):
+ """ Adds a target regexp for dispatching """
+
+ chain = self.regexs.get(regex, CommandChainDispatcher())
+ chain.add(obj,priority)
+ self.regexs[regex] = chain
+
+ def dispatch(self, key):
+ """ Get a seq of Commandchain objects that match key """
+ if key in self.strs:
+ yield self.strs[key]
+
+ for r, obj in self.regexs.items():
+ if re.match(r, key):
+ yield obj
+ else:
+ #print "nomatch",key # dbg
+ pass
+
+ def __repr__(self):
+ return "<Strdispatch %s, %s>" % (self.strs, self.regexs)
+
+ def s_matches(self, key):
+ if key not in self.strs:
+ return
+ for el in self.strs[key]:
+ yield el[1]
+
+ def flat_matches(self, key):
+ """ Yield all 'value' targets, without priority """
+ for val in self.dispatch(key):
+ for el in val:
+ yield el[1] # only value, no priority
+ return
diff --git a/IPython/testing/__init__.py b/IPython/testing/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/IPython/testing/__init__.py
diff --git a/IPython/testing/decorator_msim.py b/IPython/testing/decorator_msim.py
new file mode 100644
index 0000000..8915cf0
--- /dev/null
+++ b/IPython/testing/decorator_msim.py
@@ -0,0 +1,146 @@
+## The basic trick is to generate the source code for the decorated function
+## with the right signature and to evaluate it.
+## Uncomment the statement 'print >> sys.stderr, func_src' in _decorate
+## to understand what is going on.
+
+__all__ = ["decorator", "update_wrapper", "getinfo"]
+
+import inspect, sys
+
+def getinfo(func):
+ """
+ Returns an info dictionary containing:
+ - name (the name of the function : str)
+ - argnames (the names of the arguments : list)
+ - defaults (the values of the default arguments : tuple)
+ - signature (the signature : str)
+ - doc (the docstring : str)
+ - module (the module name : str)
+ - dict (the function __dict__ : str)
+
+ >>> def f(self, x=1, y=2, *args, **kw): pass
+
+ >>> info = getinfo(f)
+
+ >>> info["name"]
+ 'f'
+ >>> info["argnames"]
+ ['self', 'x', 'y', 'args', 'kw']
+
+ >>> info["defaults"]
+ (1, 2)
+
+ >>> info["signature"]
+ 'self, x, y, *args, **kw'
+ """
+ assert inspect.ismethod(func) or inspect.isfunction(func)
+ regargs, varargs, varkwargs, defaults = inspect.getargspec(func)
+ argnames = list(regargs)
+ if varargs:
+ argnames.append(varargs)
+ if varkwargs:
+ argnames.append(varkwargs)
+ signature = inspect.formatargspec(regargs, varargs, varkwargs, defaults,
+ formatvalue=lambda value: "")[1:-1]
+ return dict(name=func.__name__, argnames=argnames, signature=signature,
+ defaults = func.func_defaults, doc=func.__doc__,
+ module=func.__module__, dict=func.__dict__,
+ globals=func.func_globals, closure=func.func_closure)
+
+def update_wrapper(wrapper, wrapped, create=False):
+ """
+ An improvement over functools.update_wrapper. By default it works the
+ same, but if the 'create' flag is set, generates a copy of the wrapper
+ with the right signature and update the copy, not the original.
+ Moreovoer, 'wrapped' can be a dictionary with keys 'name', 'doc', 'module',
+ 'dict', 'defaults'.
+ """
+ if isinstance(wrapped, dict):
+ infodict = wrapped
+ else: # assume wrapped is a function
+ infodict = getinfo(wrapped)
+ assert not '_wrapper_' in infodict["argnames"], \
+ '"_wrapper_" is a reserved argument name!'
+ if create: # create a brand new wrapper with the right signature
+ src = "lambda %(signature)s: _wrapper_(%(signature)s)" % infodict
+ # import sys; print >> sys.stderr, src # for debugging purposes
+ wrapper = eval(src, dict(_wrapper_=wrapper))
+ try:
+ wrapper.__name__ = infodict['name']
+ except: # Python version < 2.4
+ pass
+ wrapper.__doc__ = infodict['doc']
+ wrapper.__module__ = infodict['module']
+ wrapper.__dict__.update(infodict['dict'])
+ wrapper.func_defaults = infodict['defaults']
+ return wrapper
+
+# the real meat is here
+def _decorator(caller, func):
+ infodict = getinfo(func)
+ argnames = infodict['argnames']
+ assert not ('_call_' in argnames or '_func_' in argnames), \
+ 'You cannot use _call_ or _func_ as argument names!'
+ src = "lambda %(signature)s: _call_(_func_, %(signature)s)" % infodict
+ dec_func = eval(src, dict(_func_=func, _call_=caller))
+ return update_wrapper(dec_func, func)
+
+def decorator(caller, func=None):
+ """
+ General purpose decorator factory: takes a caller function as
+ input and returns a decorator with the same attributes.
+ A caller function is any function like this::
+
+ def caller(func, *args, **kw):
+ # do something
+ return func(*args, **kw)
+
+ Here is an example of usage:
+
+ >>> @decorator
+ ... def chatty(f, *args, **kw):
+ ... print "Calling %r" % f.__name__
+ ... return f(*args, **kw)
+
+ >>> chatty.__name__
+ 'chatty'
+
+ >>> @chatty
+ ... def f(): pass
+ ...
+ >>> f()
+ Calling 'f'
+
+ For sake of convenience, the decorator factory can also be called with
+ two arguments. In this casem ``decorator(caller, func)`` is just a
+ shortcut for ``decorator(caller)(func)``.
+ """
+ if func is None: # return a decorator function
+ return update_wrapper(lambda f : _decorator(caller, f), caller)
+ else: # return a decorated function
+ return _decorator(caller, func)
+
+if __name__ == "__main__":
+ import doctest; doctest.testmod()
+
+####################### LEGALESE ##################################
+
+## Redistributions of source code must retain the above copyright
+## notice, this list of conditions and the following disclaimer.
+## Redistributions in bytecode form must reproduce the above copyright
+## notice, this list of conditions and the following disclaimer in
+## the documentation and/or other materials provided with the
+## distribution.
+
+## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+## HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+## INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+## BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+## OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+## ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+## TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+## USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+## DAMAGE.
diff --git a/IPython/testing/decorators.py b/IPython/testing/decorators.py
new file mode 100644
index 0000000..10eefd4
--- /dev/null
+++ b/IPython/testing/decorators.py
@@ -0,0 +1,254 @@
+"""Decorators for labeling test objects.
+
+Decorators that merely return a modified version of the original function
+object are straightforward. Decorators that return a new function object need
+to use nose.tools.make_decorator(original_function)(decorator) in returning the
+decorator, in order to preserve metadata such as function name, setup and
+teardown functions and so on - see nose.tools for more information.
+
+This module provides a set of useful decorators meant to be ready to use in
+your own tests. See the bottom of the file for the ready-made ones, and if you
+find yourself writing a new one that may be of generic use, add it here.
+
+NOTE: This file contains IPython-specific decorators and imports the
+numpy.testing.decorators file, which we've copied verbatim. Any of our own
+code will be added at the bottom if we end up extending this.
+"""
+
+# Stdlib imports
+import inspect
+import sys
+
+# Third-party imports
+
+# This is Michele Simionato's decorator module, also kept verbatim.
+from decorator_msim import decorator, update_wrapper
+
+# Grab the numpy-specific decorators which we keep in a file that we
+# occasionally update from upstream: decorators_numpy.py is an IDENTICAL copy
+# of numpy.testing.decorators.
+from decorators_numpy import *
+
+##############################################################################
+# Local code begins
+
+# Utility functions
+
+def apply_wrapper(wrapper,func):
+ """Apply a wrapper to a function for decoration.
+
+ This mixes Michele Simionato's decorator tool with nose's make_decorator,
+ to apply a wrapper in a decorator so that all nose attributes, as well as
+ function signature and other properties, survive the decoration cleanly.
+ This will ensure that wrapped functions can still be well introspected via
+ IPython, for example.
+ """
+ import nose.tools
+
+ return decorator(wrapper,nose.tools.make_decorator(func)(wrapper))
+
+
+def make_label_dec(label,ds=None):
+ """Factory function to create a decorator that applies one or more labels.
+
+ :Parameters:
+ label : string or sequence
+ One or more labels that will be applied by the decorator to the functions
+ it decorates. Labels are attributes of the decorated function with their
+ value set to True.
+
+ :Keywords:
+ ds : string
+ An optional docstring for the resulting decorator. If not given, a
+ default docstring is auto-generated.
+
+ :Returns:
+ A decorator.
+
+ :Examples:
+
+ A simple labeling decorator:
+ >>> slow = make_label_dec('slow')
+ >>> print slow.__doc__
+ Labels a test as 'slow'.
+
+ And one that uses multiple labels and a custom docstring:
+ >>> rare = make_label_dec(['slow','hard'],
+ ... "Mix labels 'slow' and 'hard' for rare tests.")
+ >>> print rare.__doc__
+ Mix labels 'slow' and 'hard' for rare tests.
+
+ Now, let's test using this one:
+ >>> @rare
+ ... def f(): pass
+ ...
+ >>>
+ >>> f.slow
+ True
+ >>> f.hard
+ True
+ """
+
+ if isinstance(label,basestring):
+ labels = [label]
+ else:
+ labels = label
+
+ # Validate that the given label(s) are OK for use in setattr() by doing a
+ # dry run on a dummy function.
+ tmp = lambda : None
+ for label in labels:
+ setattr(tmp,label,True)
+
+ # This is the actual decorator we'll return
+ def decor(f):
+ for label in labels:
+ setattr(f,label,True)
+ return f
+
+ # Apply the user's docstring, or autogenerate a basic one
+ if ds is None:
+ ds = "Labels a test as %r." % label
+ decor.__doc__ = ds
+
+ return decor
+
+
+# Inspired by numpy's skipif, but uses the full apply_wrapper utility to
+# preserve function metadata better and allows the skip condition to be a
+# callable.
+def skipif(skip_condition, msg=None):
+ ''' Make function raise SkipTest exception if skip_condition is true
+
+ Parameters
+ ----------
+ skip_condition : bool or callable.
+ Flag to determine whether to skip test. If the condition is a
+ callable, it is used at runtime to dynamically make the decision. This
+ is useful for tests that may require costly imports, to delay the cost
+ until the test suite is actually executed.
+ msg : string
+ Message to give on raising a SkipTest exception
+
+ Returns
+ -------
+ decorator : function
+ Decorator, which, when applied to a function, causes SkipTest
+ to be raised when the skip_condition was True, and the function
+ to be called normally otherwise.
+
+ Notes
+ -----
+ You will see from the code that we had to further decorate the
+ decorator with the nose.tools.make_decorator function in order to
+ transmit function name, and various other metadata.
+ '''
+
+ def skip_decorator(f):
+ # Local import to avoid a hard nose dependency and only incur the
+ # import time overhead at actual test-time.
+ import nose
+
+ # Allow for both boolean or callable skip conditions.
+ if callable(skip_condition):
+ skip_val = lambda : skip_condition()
+ else:
+ skip_val = lambda : skip_condition
+
+ def get_msg(func,msg=None):
+ """Skip message with information about function being skipped."""
+ if msg is None: out = 'Test skipped due to test condition.'
+ else: out = msg
+ return "Skipping test: %s. %s" % (func.__name__,out)
+
+ # We need to define *two* skippers because Python doesn't allow both
+ # return with value and yield inside the same function.
+ def skipper_func(*args, **kwargs):
+ """Skipper for normal test functions."""
+ if skip_val():
+ raise nose.SkipTest(get_msg(f,msg))
+ else:
+ return f(*args, **kwargs)
+
+ def skipper_gen(*args, **kwargs):
+ """Skipper for test generators."""
+ if skip_val():
+ raise nose.SkipTest(get_msg(f,msg))
+ else:
+ for x in f(*args, **kwargs):
+ yield x
+
+ # Choose the right skipper to use when building the actual generator.
+ if nose.util.isgenerator(f):
+ skipper = skipper_gen
+ else:
+ skipper = skipper_func
+
+ return nose.tools.make_decorator(f)(skipper)
+
+ return skip_decorator
+
+# A version with the condition set to true, common case just to attacha message
+# to a skip decorator
+def skip(msg=None):
+ """Decorator factory - mark a test function for skipping from test suite.
+
+ :Parameters:
+ msg : string
+ Optional message to be added.
+
+ :Returns:
+ decorator : function
+ Decorator, which, when applied to a function, causes SkipTest
+ to be raised, with the optional message added.
+ """
+
+ return skipif(True,msg)
+
+
+#-----------------------------------------------------------------------------
+# Utility functions for decorators
+def numpy_not_available():
+ """Can numpy be imported? Returns true if numpy does NOT import.
+
+ This is used to make a decorator to skip tests that require numpy to be
+ available, but delay the 'import numpy' to test execution time.
+ """
+ try:
+ import numpy
+ np_not_avail = False
+ except ImportError:
+ np_not_avail = True
+
+ return np_not_avail
+
+#-----------------------------------------------------------------------------
+# Decorators for public use
+
+skip_doctest = make_label_dec('skip_doctest',
+ """Decorator - mark a function or method for skipping its doctest.
+
+ This decorator allows you to mark a function whose docstring you wish to
+ omit from testing, while preserving the docstring for introspection, help,
+ etc.""")
+
+# Decorators to skip certain tests on specific platforms.
+skip_win32 = skipif(sys.platform == 'win32',
+ "This test does not run under Windows")
+skip_linux = skipif(sys.platform == 'linux2',
+ "This test does not run under Linux")
+skip_osx = skipif(sys.platform == 'darwin',"This test does not run under OS X")
+
+
+# Decorators to skip tests if not on specific platforms.
+skip_if_not_win32 = skipif(sys.platform != 'win32',
+ "This test only runs under Windows")
+skip_if_not_linux = skipif(sys.platform != 'linux2',
+ "This test only runs under Linux")
+skip_if_not_osx = skipif(sys.platform != 'darwin',
+ "This test only runs under OSX")
+
+# Other skip decorators
+skipif_not_numpy = skipif(numpy_not_available,"This test requires numpy")
+
+skipknownfailure = skip('This test is known to fail')
diff --git a/IPython/testing/decorators_numpy.py b/IPython/testing/decorators_numpy.py
new file mode 100644
index 0000000..540f3c7
--- /dev/null
+++ b/IPython/testing/decorators_numpy.py
@@ -0,0 +1,90 @@
+"""Decorators for labeling test objects
+
+Decorators that merely return a modified version of the original
+function object are straightforward. Decorators that return a new
+function object need to use
+nose.tools.make_decorator(original_function)(decorator) in returning
+the decorator, in order to preserve metadata such as function name,
+setup and teardown functions and so on - see nose.tools for more
+information.
+
+"""
+
+def slow(t):
+ """Labels a test as 'slow'.
+
+ The exact definition of a slow test is obviously both subjective and
+ hardware-dependent, but in general any individual test that requires more
+ than a second or two should be labeled as slow (the whole suite consits of
+ thousands of tests, so even a second is significant)."""
+
+ t.slow = True
+ return t
+
+def setastest(tf=True):
+ ''' Signals to nose that this function is or is not a test
+
+ Parameters
+ ----------
+ tf : bool
+ If True specifies this is a test, not a test otherwise
+
+ This decorator cannot use the nose namespace, because it can be
+ called from a non-test module. See also istest and nottest in
+ nose.tools
+
+ '''
+ def set_test(t):
+ t.__test__ = tf
+ return t
+ return set_test
+
+def skipif(skip_condition=True, msg=None):
+ ''' Make function raise SkipTest exception if skip_condition is true
+
+ Parameters
+ ----------
+ skip_condition : bool or callable.
+ Flag to determine whether to skip test. If the condition is a
+ callable, it is used at runtime to dynamically make the decision. This
+ is useful for tests that may require costly imports, to delay the cost
+ until the test suite is actually executed.
+ msg : string
+ Message to give on raising a SkipTest exception
+
+ Returns
+ -------
+ decorator : function
+ Decorator, which, when applied to a function, causes SkipTest
+ to be raised when the skip_condition was True, and the function
+ to be called normally otherwise.
+
+ Notes
+ -----
+ You will see from the code that we had to further decorate the
+ decorator with the nose.tools.make_decorator function in order to
+ transmit function name, and various other metadata.
+ '''
+ if msg is None:
+ msg = 'Test skipped due to test condition'
+ def skip_decorator(f):
+ # Local import to avoid a hard nose dependency and only incur the
+ # import time overhead at actual test-time.
+ import nose
+ def skipper(*args, **kwargs):
+ if skip_condition:
+ raise nose.SkipTest, msg
+ else:
+ return f(*args, **kwargs)
+ return nose.tools.make_decorator(f)(skipper)
+ return skip_decorator
+
+def skipknownfailure(f):
+ ''' Decorator to raise SkipTest for test known to fail
+ '''
+ # Local import to avoid a hard nose dependency and only incur the
+ # import time overhead at actual test-time.
+ import nose
+ def skipper(*args, **kwargs):
+ raise nose.SkipTest, 'This test is known to fail'
+ return nose.tools.make_decorator(f)(skipper)
diff --git a/IPython/testing/decorators_trial.py b/IPython/testing/decorators_trial.py
new file mode 100644
index 0000000..231054b
--- /dev/null
+++ b/IPython/testing/decorators_trial.py
@@ -0,0 +1,132 @@
+# encoding: utf-8
+"""
+Testing related decorators for use with twisted.trial.
+
+The decorators in this files are designed to follow the same API as those
+in the decorators module (in this same directory). But they can be used
+with twisted.trial
+"""
+
+#-----------------------------------------------------------------------------
+# Copyright (C) 2008-2009 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+import os
+import sys
+
+from IPython.testing.decorators import make_label_dec
+
+#-----------------------------------------------------------------------------
+# Testing decorators
+#-----------------------------------------------------------------------------
+
+
+def skipif(skip_condition, msg=None):
+ """Create a decorator that marks a test function for skipping.
+
+ The is a decorator factory that returns a decorator that will
+ conditionally skip a test based on the value of skip_condition. The
+ skip_condition argument can either be a boolean or a callable that returns
+ a boolean.
+
+ Parameters
+ ----------
+ skip_condition : boolean or callable
+ If this evaluates to True, the test is skipped.
+ msg : str
+ The message to print if the test is skipped.
+
+ Returns
+ -------
+ decorator : function
+ The decorator function that can be applied to the test function.
+ """
+
+ def skip_decorator(f):
+
+ # Allow for both boolean or callable skip conditions.
+ if callable(skip_condition):
+ skip_val = lambda : skip_condition()
+ else:
+ skip_val = lambda : skip_condition
+
+ if msg is None:
+ out = 'Test skipped due to test condition.'
+ else:
+ out = msg
+ final_msg = "Skipping test: %s. %s" % (f.__name__,out)
+
+ if skip_val():
+ f.skip = final_msg
+
+ return f
+ return skip_decorator
+
+
+def skip(msg=None):
+ """Create a decorator that marks a test function for skipping.
+
+ This is a decorator factory that returns a decorator that will cause
+ tests to be skipped.
+
+ Parameters
+ ----------
+ msg : str
+ Optional message to be added.
+
+ Returns
+ -------
+ decorator : function
+ Decorator, which, when applied to a function, sets the skip
+ attribute of the function causing `twisted.trial` to skip it.
+ """
+
+ return skipif(True,msg)
+
+
+def numpy_not_available():
+ """Can numpy be imported? Returns true if numpy does NOT import.
+
+ This is used to make a decorator to skip tests that require numpy to be
+ available, but delay the 'import numpy' to test execution time.
+ """
+ try:
+ import numpy
+ np_not_avail = False
+ except ImportError:
+ np_not_avail = True
+
+ return np_not_avail
+
+#-----------------------------------------------------------------------------
+# Decorators for public use
+#-----------------------------------------------------------------------------
+
+# Decorators to skip certain tests on specific platforms.
+skip_win32 = skipif(sys.platform == 'win32',
+ "This test does not run under Windows")
+skip_linux = skipif(sys.platform == 'linux2',
+ "This test does not run under Linux")
+skip_osx = skipif(sys.platform == 'darwin',"This test does not run under OS X")
+
+# Decorators to skip tests if not on specific platforms.
+skip_if_not_win32 = skipif(sys.platform != 'win32',
+ "This test only runs under Windows")
+skip_if_not_linux = skipif(sys.platform != 'linux2',
+ "This test only runs under Linux")
+skip_if_not_osx = skipif(sys.platform != 'darwin',
+ "This test only runs under OSX")
+
+# Other skip decorators
+skipif_not_numpy = skipif(numpy_not_available,"This test requires numpy")
+
+skipknownfailure = skip('This test is known to fail')
+
+
diff --git a/IPython/testing/iptest.py b/IPython/testing/iptest.py
new file mode 100644
index 0000000..48ed1e7
--- /dev/null
+++ b/IPython/testing/iptest.py
@@ -0,0 +1,346 @@
+# -*- coding: utf-8 -*-
+"""IPython Test Suite Runner.
+
+This module provides a main entry point to a user script to test IPython
+itself from the command line. There are two ways of running this script:
+
+1. With the syntax `iptest all`. This runs our entire test suite by
+ calling this script (with different arguments) or trial recursively. This
+ causes modules and package to be tested in different processes, using nose
+ or trial where appropriate.
+2. With the regular nose syntax, like `iptest -vvs IPython`. In this form
+ the script simply calls nose, but with special command line flags and
+ plugins loaded.
+
+For now, this script requires that both nose and twisted are installed. This
+will change in the future.
+"""
+
+#-----------------------------------------------------------------------------
+# Module imports
+#-----------------------------------------------------------------------------
+
+import os
+import os.path as path
+import sys
+import subprocess
+import tempfile
+import time
+import warnings
+
+import nose.plugins.builtin
+from nose.core import TestProgram
+
+from IPython.platutils import find_cmd
+from IPython.testing.plugin.ipdoctest import IPythonDoctest
+
+pjoin = path.join
+
+#-----------------------------------------------------------------------------
+# Logic for skipping doctests
+#-----------------------------------------------------------------------------
+
+def test_for(mod):
+ """Test to see if mod is importable."""
+ try:
+ __import__(mod)
+ except ImportError:
+ return False
+ else:
+ return True
+
+have_curses = test_for('_curses')
+have_wx = test_for('wx')
+have_wx_aui = test_for('wx.aui')
+have_zi = test_for('zope.interface')
+have_twisted = test_for('twisted')
+have_foolscap = test_for('foolscap')
+have_objc = test_for('objc')
+have_pexpect = test_for('pexpect')
+
+# For the IPythonDoctest plugin, we need to exclude certain patterns that cause
+# testing problems. We should strive to minimize the number of skipped
+# modules, since this means untested code. As the testing machinery
+# solidifies, this list should eventually become empty.
+EXCLUDE = [pjoin('IPython', 'external'),
+ pjoin('IPython', 'frontend', 'process', 'winprocess.py'),
+ pjoin('IPython_doctest_plugin'),
+ pjoin('IPython', 'Gnuplot'),
+ pjoin('IPython', 'Extensions', 'ipy_'),
+ pjoin('IPython', 'Extensions', 'PhysicalQInput'),
+ pjoin('IPython', 'Extensions', 'PhysicalQInteractive'),
+ pjoin('IPython', 'Extensions', 'InterpreterPasteInput'),
+ pjoin('IPython', 'Extensions', 'scitedirector'),
+ pjoin('IPython', 'Extensions', 'numeric_formats'),
+ pjoin('IPython', 'testing', 'attic'),
+ pjoin('IPython', 'testing', 'tutils'),
+ pjoin('IPython', 'testing', 'tools'),
+ pjoin('IPython', 'testing', 'mkdoctests'),
+ ]
+
+if not have_wx:
+ EXCLUDE.append(pjoin('IPython', 'Extensions', 'igrid'))
+ EXCLUDE.append(pjoin('IPython', 'gui'))
+ EXCLUDE.append(pjoin('IPython', 'frontend', 'wx'))
+
+if not have_wx_aui:
+ EXCLUDE.append(pjoin('IPython', 'gui', 'wx', 'wxIPython'))
+
+if not have_objc:
+ EXCLUDE.append(pjoin('IPython', 'frontend', 'cocoa'))
+
+if not have_curses:
+ EXCLUDE.append(pjoin('IPython', 'Extensions', 'ibrowse'))
+
+if not sys.platform == 'win32':
+ EXCLUDE.append(pjoin('IPython', 'platutils_win32'))
+
+# These have to be skipped on win32 because the use echo, rm, cd, etc.
+# See ticket https://bugs.launchpad.net/bugs/366982
+if sys.platform == 'win32':
+ EXCLUDE.append(pjoin('IPython', 'testing', 'plugin', 'test_exampleip'))
+ EXCLUDE.append(pjoin('IPython', 'testing', 'plugin', 'dtexample'))
+
+if not os.name == 'posix':
+ EXCLUDE.append(pjoin('IPython', 'platutils_posix'))
+
+if not have_pexpect:
+ EXCLUDE.append(pjoin('IPython', 'irunner'))
+
+if not have_twisted:
+ EXCLUDE.append(pjoin('IPython', 'frontend', 'asyncfrontendbase'))
+ EXCLUDE.append(pjoin('IPython', 'frontend', 'prefilterfrontend'))
+ EXCLUDE.append(pjoin('IPython', 'frontend', 'frontendbase'))
+ EXCLUDE.append(pjoin('IPython', 'frontend', 'linefrontendbase'))
+ EXCLUDE.append(pjoin('IPython', 'frontend', 'tests', 'test_linefrontend'))
+ EXCLUDE.append(pjoin('IPython', 'frontend', 'tests', 'test_frontendbase'))
+ EXCLUDE.append(pjoin('IPython', 'frontend', 'tests',
+ 'test_prefilterfrontend'))
+ EXCLUDE.append(pjoin('IPython', 'frontend', 'tests',
+ 'test_asyncfrontendbase'))
+ EXCLUDE.append(pjoin('IPython', 'kernel', 'error'))
+ EXCLUDE.append(pjoin('IPython', 'testing', 'parametric'))
+ EXCLUDE.append(pjoin('IPython', 'testing', 'util'))
+ EXCLUDE.append(pjoin('IPython', 'testing', 'tests', 'test_decorators_trial'))
+
+
+# This is needed for the reg-exp to match on win32 in the ipdoctest plugin.
+if sys.platform == 'win32':
+ EXCLUDE = [s.replace('\\','\\\\') for s in EXCLUDE]
+
+
+#-----------------------------------------------------------------------------
+# Functions and classes
+#-----------------------------------------------------------------------------
+
+def run_iptest():
+ """Run the IPython test suite using nose.
+
+ This function is called when this script is **not** called with the form
+ `iptest all`. It simply calls nose with appropriate command line flags
+ and accepts all of the standard nose arguments.
+ """
+
+ warnings.filterwarnings('ignore',
+ 'This will be removed soon. Use IPython.testing.util instead')
+
+ argv = sys.argv + [
+ # Loading ipdoctest causes problems with Twisted.
+ # I am removing this as a temporary fix to get the
+ # test suite back into working shape. Our nose
+ # plugin needs to be gone through with a fine
+ # toothed comb to find what is causing the problem.
+ '--with-ipdoctest',
+ '--ipdoctest-tests','--ipdoctest-extension=txt',
+ '--detailed-errors',
+
+ # We add --exe because of setuptools' imbecility (it
+ # blindly does chmod +x on ALL files). Nose does the
+ # right thing and it tries to avoid executables,
+ # setuptools unfortunately forces our hand here. This
+ # has been discussed on the distutils list and the
+ # setuptools devs refuse to fix this problem!
+ '--exe',
+ ]
+
+ # Detect if any tests were required by explicitly calling an IPython
+ # submodule or giving a specific path
+ has_tests = False
+ for arg in sys.argv:
+ if 'IPython' in arg or arg.endswith('.py') or \
+ (':' in arg and '.py' in arg):
+ has_tests = True
+ break
+
+ # If nothing was specifically requested, test full IPython
+ if not has_tests:
+ argv.append('IPython')
+
+ # Construct list of plugins, omitting the existing doctest plugin, which
+ # ours replaces (and extends).
+ plugins = [IPythonDoctest(EXCLUDE)]
+ for p in nose.plugins.builtin.plugins:
+ plug = p()
+ if plug.name == 'doctest':
+ continue
+
+ #print '*** adding plugin:',plug.name # dbg
+ plugins.append(plug)
+
+ TestProgram(argv=argv,plugins=plugins)
+
+
+class IPTester(object):
+ """Call that calls iptest or trial in a subprocess.
+ """
+ def __init__(self,runner='iptest',params=None):
+ """ """
+ if runner == 'iptest':
+ self.runner = ['iptest','-v']
+ else:
+ self.runner = [find_cmd('trial')]
+ if params is None:
+ params = []
+ if isinstance(params,str):
+ params = [params]
+ self.params = params
+
+ # Assemble call
+ self.call_args = self.runner+self.params
+
+ if sys.platform == 'win32':
+ def run(self):
+ """Run the stored commands"""
+ # On Windows, cd to temporary directory to run tests. Otherwise,
+ # Twisted's trial may not be able to execute 'trial IPython', since
+ # it will confuse the IPython module name with the ipython
+ # execution scripts, because the windows file system isn't case
+ # sensitive.
+ # We also use os.system instead of subprocess.call, because I was
+ # having problems with subprocess and I just don't know enough
+ # about win32 to debug this reliably. Os.system may be the 'old
+ # fashioned' way to do it, but it works just fine. If someone
+ # later can clean this up that's fine, as long as the tests run
+ # reliably in win32.
+ curdir = os.getcwd()
+ os.chdir(tempfile.gettempdir())
+ stat = os.system(' '.join(self.call_args))
+ os.chdir(curdir)
+ return stat
+ else:
+ def run(self):
+ """Run the stored commands"""
+ return subprocess.call(self.call_args)
+
+
+def make_runners():
+ """Define the modules and packages that need to be tested.
+ """
+
+ # This omits additional top-level modules that should not be doctested.
+ # XXX: Shell.py is also ommited because of a bug in the skip_doctest
+ # decorator. See ticket https://bugs.launchpad.net/bugs/366209
+ top_mod = \
+ ['background_jobs.py', 'ColorANSI.py', 'completer.py', 'ConfigLoader.py',
+ 'CrashHandler.py', 'Debugger.py', 'deep_reload.py', 'demo.py',
+ 'DPyGetOpt.py', 'dtutils.py', 'excolors.py', 'FakeModule.py',
+ 'generics.py', 'genutils.py', 'history.py', 'hooks.py', 'ipapi.py',
+ 'iplib.py', 'ipmaker.py', 'ipstruct.py', 'Itpl.py',
+ 'Logger.py', 'macro.py', 'Magic.py', 'OInspect.py',
+ 'OutputTrap.py', 'platutils.py', 'prefilter.py', 'Prompts.py',
+ 'PyColorize.py', 'Release.py', 'rlineimpl.py', 'shadowns.py',
+ 'shellglobals.py', 'strdispatch.py',
+ 'ultraTB.py', 'upgrade_dir.py', 'usage.py', 'wildcard.py',
+ # See note above for why this is skipped
+ # 'Shell.py',
+ 'winconsole.py']
+
+ if have_twisted:
+ top_mod.append('twshell.py')
+
+ if have_pexpect:
+ top_mod.append('irunner.py')
+
+ if sys.platform == 'win32':
+ top_mod.append('platutils_win32.py')
+ elif os.name == 'posix':
+ top_mod.append('platutils_posix.py')
+ else:
+ top_mod.append('platutils_dummy.py')
+
+ # These are tested by nose, so skip IPython.kernel
+ top_pack = ['config','Extensions','frontend',
+ 'testing','tests','tools','UserConfig']
+
+ if have_wx:
+ top_pack.append('gui')
+
+ modules = ['IPython.%s' % m[:-3] for m in top_mod ]
+ packages = ['IPython.%s' % m for m in top_pack ]
+
+ # Make runners
+ runners = dict(zip(top_pack, [IPTester(params=v) for v in packages]))
+
+ # Test IPython.kernel using trial if twisted is installed
+ if have_zi and have_twisted and have_foolscap:
+ runners['trial'] = IPTester('trial',['IPython'])
+
+ runners['modules'] = IPTester(params=modules)
+
+ return runners
+
+
+def run_iptestall():
+ """Run the entire IPython test suite by calling nose and trial.
+
+ This function constructs :class:`IPTester` instances for all IPython
+ modules and package and then runs each of them. This causes the modules
+ and packages of IPython to be tested each in their own subprocess using
+ nose or twisted.trial appropriately.
+ """
+ runners = make_runners()
+ # Run all test runners, tracking execution time
+ failed = {}
+ t_start = time.time()
+ for name,runner in runners.iteritems():
+ print '*'*77
+ print 'IPython test group:',name
+ res = runner.run()
+ if res:
+ failed[name] = res
+ t_end = time.time()
+ t_tests = t_end - t_start
+ nrunners = len(runners)
+ nfail = len(failed)
+ # summarize results
+ print
+ print '*'*77
+ print 'Ran %s test groups in %.3fs' % (nrunners, t_tests)
+ print
+ if not failed:
+ print 'OK'
+ else:
+ # If anything went wrong, point out what command to rerun manually to
+ # see the actual errors and individual summary
+ print 'ERROR - %s out of %s test groups failed.' % (nfail, nrunners)
+ for name in failed:
+ failed_runner = runners[name]
+ print '-'*40
+ print 'Runner failed:',name
+ print 'You may wish to rerun this one individually, with:'
+ print ' '.join(failed_runner.call_args)
+ print
+
+
+def main():
+ if len(sys.argv) == 1:
+ run_iptestall()
+ else:
+ if sys.argv[1] == 'all':
+ run_iptestall()
+ else:
+ run_iptest()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/IPython/testing/mkdoctests.py b/IPython/testing/mkdoctests.py
new file mode 100644
index 0000000..142f1cc
--- /dev/null
+++ b/IPython/testing/mkdoctests.py
@@ -0,0 +1,244 @@
+#!/usr/bin/env python
+"""Utility for making a doctest file out of Python or IPython input.
+
+ %prog [options] input_file [output_file]
+
+This script is a convenient generator of doctest files that uses IPython's
+irunner script to execute valid Python or IPython input in a separate process,
+capture all of the output, and write it to an output file.
+
+It can be used in one of two ways:
+
+1. With a plain Python or IPython input file (denoted by extensions '.py' or
+ '.ipy'. In this case, the output is an auto-generated reST file with a
+ basic header, and the captured Python input and output contained in an
+ indented code block.
+
+ If no output filename is given, the input name is used, with the extension
+ replaced by '.txt'.
+
+2. With an input template file. Template files are simply plain text files
+ with special directives of the form
+
+ %run filename
+
+ to include the named file at that point.
+
+ If no output filename is given and the input filename is of the form
+ 'base.tpl.txt', the output will be automatically named 'base.txt'.
+"""
+
+# Standard library imports
+
+import optparse
+import os
+import re
+import sys
+import tempfile
+
+# IPython-specific libraries
+from IPython import irunner
+from IPython.genutils import fatal
+
+class IndentOut(object):
+ """A simple output stream that indents all output by a fixed amount.
+
+ Instances of this class trap output to a given stream and first reformat it
+ to indent every input line."""
+
+ def __init__(self,out=sys.stdout,indent=4):
+ """Create an indented writer.
+
+ :Keywords:
+
+ - `out` : stream (sys.stdout)
+ Output stream to actually write to after indenting.
+
+ - `indent` : int
+ Number of spaces to indent every input line by.
+ """
+
+ self.indent_text = ' '*indent
+ self.indent = re.compile('^',re.MULTILINE).sub
+ self.out = out
+ self._write = out.write
+ self.buffer = []
+ self._closed = False
+
+ def write(self,data):
+ """Write a string to the output stream."""
+
+ if self._closed:
+ raise ValueError('I/O operation on closed file')
+ self.buffer.append(data)
+
+ def flush(self):
+ if self.buffer:
+ data = ''.join(self.buffer)
+ self.buffer[:] = []
+ self._write(self.indent(self.indent_text,data))
+
+ def close(self):
+ self.flush()
+ self._closed = True
+
+class RunnerFactory(object):
+ """Code runner factory.
+
+ This class provides an IPython code runner, but enforces that only one
+ runner is every instantiated. The runner is created based on the extension
+ of the first file to run, and it raises an exception if a runner is later
+ requested for a different extension type.
+
+ This ensures that we don't generate example files for doctest with a mix of
+ python and ipython syntax.
+ """
+
+ def __init__(self,out=sys.stdout):
+ """Instantiate a code runner."""
+
+ self.out = out
+ self.runner = None
+ self.runnerClass = None
+
+ def _makeRunner(self,runnerClass):
+ self.runnerClass = runnerClass
+ self.runner = runnerClass(out=self.out)
+ return self.runner
+
+ def __call__(self,fname):
+ """Return a runner for the given filename."""
+
+ if fname.endswith('.py'):
+ runnerClass = irunner.PythonRunner
+ elif fname.endswith('.ipy'):
+ runnerClass = irunner.IPythonRunner
+ else:
+ raise ValueError('Unknown file type for Runner: %r' % fname)
+
+ if self.runner is None:
+ return self._makeRunner(runnerClass)
+ else:
+ if runnerClass==self.runnerClass:
+ return self.runner
+ else:
+ e='A runner of type %r can not run file %r' % \
+ (self.runnerClass,fname)
+ raise ValueError(e)
+
+TPL = """
+=========================
+ Auto-generated doctests
+=========================
+
+This file was auto-generated by IPython in its entirety. If you need finer
+control over the contents, simply make a manual template. See the
+mkdoctests.py script for details.
+
+%%run %s
+"""
+
+def main():
+ """Run as a script."""
+
+ # Parse options and arguments.
+ parser = optparse.OptionParser(usage=__doc__)
+ newopt = parser.add_option
+ newopt('-f','--force',action='store_true',dest='force',default=False,
+ help='Force overwriting of the output file.')
+ newopt('-s','--stdout',action='store_true',dest='stdout',default=False,
+ help='Use stdout instead of a file for output.')
+
+ opts,args = parser.parse_args()
+ if len(args) < 1:
+ parser.error("incorrect number of arguments")
+
+ # Input filename
+ fname = args[0]
+
+ # We auto-generate the output file based on a trivial template to make it
+ # really easy to create simple doctests.
+
+ auto_gen_output = False
+ try:
+ outfname = args[1]
+ except IndexError:
+ outfname = None
+
+ if fname.endswith('.tpl.txt') and outfname is None:
+ outfname = fname.replace('.tpl.txt','.txt')
+ else:
+ bname, ext = os.path.splitext(fname)
+ if ext in ['.py','.ipy']:
+ auto_gen_output = True
+ if outfname is None:
+ outfname = bname+'.txt'
+
+ # Open input file
+
+ # In auto-gen mode, we actually change the name of the input file to be our
+ # auto-generated template
+ if auto_gen_output:
+ infile = tempfile.TemporaryFile()
+ infile.write(TPL % fname)
+ infile.flush()
+ infile.seek(0)
+ else:
+ infile = open(fname)
+
+ # Now open the output file. If opts.stdout was given, this overrides any
+ # explicit choice of output filename and just directs all output to
+ # stdout.
+ if opts.stdout:
+ outfile = sys.stdout
+ else:
+ # Argument processing finished, start main code
+ if os.path.isfile(outfname) and not opts.force:
+ fatal("Output file %r exists, use --force (-f) to overwrite."
+ % outfname)
+ outfile = open(outfname,'w')
+
+
+ # all output from included files will be indented
+ indentOut = IndentOut(outfile,4)
+ getRunner = RunnerFactory(indentOut)
+
+ # Marker in reST for transition lines
+ rst_transition = '\n'+'-'*76+'\n\n'
+
+ # local shorthand for loop
+ write = outfile.write
+
+ # Process input, simply writing back out all normal lines and executing the
+ # files in lines marked as '%run filename'.
+ for line in infile:
+ if line.startswith('%run '):
+ # We don't support files with spaces in their names.
+ incfname = line.split()[1]
+
+ # We make the output of the included file appear bracketed between
+ # clear reST transition marks, and indent it so that if anyone
+ # makes an HTML or PDF out of the file, all doctest input and
+ # output appears in proper literal blocks.
+ write(rst_transition)
+ write('Begin included file %s::\n\n' % incfname)
+
+ # I deliberately do NOT trap any exceptions here, so that if
+ # there's any problem, the user running this at the command line
+ # finds out immediately by the code blowing up, rather than ending
+ # up silently with an incomplete or incorrect file.
+ getRunner(incfname).run_file(incfname)
+
+ write('\nEnd included file %s\n' % incfname)
+ write(rst_transition)
+ else:
+ # The rest of the input file is just written out
+ write(line)
+ infile.close()
+
+ # Don't close sys.stdout!!!
+ if outfile is not sys.stdout:
+ outfile.close()
+
+if __name__ == '__main__':
+ main()
diff --git a/IPython/testing/parametric.py b/IPython/testing/parametric.py
new file mode 100644
index 0000000..cd2bf81
--- /dev/null
+++ b/IPython/testing/parametric.py
@@ -0,0 +1,55 @@
+"""Parametric testing on top of twisted.trial.unittest.
+
+"""
+
+__all__ = ['parametric','Parametric']
+
+from twisted.trial.unittest import TestCase
+
+def partial(f, *partial_args, **partial_kwargs):
+ """Generate a partial class method.
+
+ """
+ def partial_func(self, *args, **kwargs):
+ dikt = dict(kwargs)
+ dikt.update(partial_kwargs)
+ return f(self, *(partial_args+args), **dikt)
+
+ return partial_func
+
+def parametric(f):
+ """Mark f as a parametric test.
+
+ """
+ f._parametric = True
+ return classmethod(f)
+
+def Parametric(cls):
+ """Register parametric tests with a class.
+
+ """
+ # Walk over all tests marked with @parametric
+ test_generators = [getattr(cls,f) for f in dir(cls)
+ if f.startswith('test')]
+ test_generators = [m for m in test_generators if hasattr(m,'_parametric')]
+ for test_gen in test_generators:
+ test_name = test_gen.func_name
+
+ # Insert a new test for each parameter
+ for n,test_and_params in enumerate(test_gen()):
+ test_method = test_and_params[0]
+ test_params = test_and_params[1:]
+
+ # Here we use partial (defined above), which returns a
+ # class method of type ``types.FunctionType``, unlike
+ # functools.partial which returns a function of type
+ # ``functools.partial``.
+ partial_func = partial(test_method,*test_params)
+ # rename the test to look like a testcase
+ partial_func.__name__ = 'test_' + partial_func.__name__
+
+ # insert the new function into the class as a test
+ setattr(cls, test_name + '_%s' % n, partial_func)
+
+ # rename test generator so it isn't called again by nose
+ test_gen.im_func.func_name = '__done_' + test_name
diff --git a/IPython/testing/plugin/Makefile b/IPython/testing/plugin/Makefile
new file mode 100644
index 0000000..dd65022
--- /dev/null
+++ b/IPython/testing/plugin/Makefile
@@ -0,0 +1,74 @@
+# Set this prefix to where you want to install the plugin
+PREFIX=/usr/local
+
+NOSE0=nosetests -vs --with-doctest --doctest-tests --detailed-errors
+NOSE=nosetests -vvs --with-ipdoctest --doctest-tests --doctest-extension=txt \
+--detailed-errors
+
+SRC=ipdoctest.py setup.py ../decorators.py
+
+# Default target for clean 'make'
+default: iplib
+
+# The actual plugin installation
+plugin: IPython_doctest_plugin.egg-info
+
+# Simple targets that test one thing
+simple: plugin simple.py
+ $(NOSE) simple.py
+
+dtest: plugin dtexample.py
+ $(NOSE) dtexample.py
+
+rtest: plugin test_refs.py
+ $(NOSE) test_refs.py
+
+test: plugin dtexample.py
+ $(NOSE) dtexample.py test*.py test*.txt
+
+deb: plugin dtexample.py
+ $(NOSE) test_combo.txt
+
+# IPython tests
+deco:
+ $(NOSE0) IPython.testing.decorators
+
+magic: plugin
+ $(NOSE) IPython.Magic
+
+excolors: plugin
+ $(NOSE) IPython.excolors
+
+iplib: plugin
+ $(NOSE) IPython.iplib
+
+strd: plugin
+ $(NOSE) IPython.strdispatch
+
+engine: plugin
+ $(NOSE) IPython.kernel
+
+tf: plugin
+ $(NOSE) IPython.config.traitlets
+
+# All of ipython itself
+ipython: plugin
+ $(NOSE) IPython
+
+
+# Combined targets
+sr: rtest strd
+
+base: dtest rtest test strd deco
+
+quick: base iplib ipipe
+
+all: base ipython
+
+# Main plugin and cleanup
+IPython_doctest_plugin.egg-info: $(SRC)
+ python setup.py install --prefix=$(PREFIX)
+ touch $@
+
+clean:
+ rm -rf IPython_doctest_plugin.egg-info *~ *pyc build/ dist/
diff --git a/IPython/testing/plugin/README.txt b/IPython/testing/plugin/README.txt
new file mode 100644
index 0000000..6b34f9e
--- /dev/null
+++ b/IPython/testing/plugin/README.txt
@@ -0,0 +1,39 @@
+=======================================================
+ Nose plugin with IPython and extension module support
+=======================================================
+
+This directory provides the key functionality for test support that IPython
+needs as a nose plugin, which can be installed for use in projects other than
+IPython.
+
+The presence of a Makefile here is mostly for development and debugging
+purposes as it only provides a few shorthand commands. You can manually
+install the plugin by using standard Python procedures (``setup.py install``
+with appropriate arguments).
+
+To install the plugin using the Makefile, edit its first line to reflect where
+you'd like the installation. If you want it system-wide, you may want to edit
+the install line in the plugin target to use sudo and no prefix::
+
+ sudo python setup.py install
+
+instead of the code using `--prefix` that's in there.
+
+Once you've set the prefix, simply build/install the plugin with::
+
+ make
+
+and run the tests with::
+
+ make test
+
+You should see output similar to::
+
+ maqroll[plugin]> make test
+ nosetests -s --with-ipdoctest --doctest-tests dtexample.py
+ ..
+ ----------------------------------------------------------------------
+ Ran 2 tests in 0.016s
+
+ OK
+
diff --git a/IPython/testing/plugin/__init__.py b/IPython/testing/plugin/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/IPython/testing/plugin/__init__.py
diff --git a/IPython/testing/plugin/dtexample.py b/IPython/testing/plugin/dtexample.py
new file mode 100644
index 0000000..453aac3
--- /dev/null
+++ b/IPython/testing/plugin/dtexample.py
@@ -0,0 +1,162 @@
+"""Simple example using doctests.
+
+This file just contains doctests both using plain python and IPython prompts.
+All tests should be loaded by nose.
+"""
+
+def pyfunc():
+ """Some pure python tests...
+
+ >>> pyfunc()
+ 'pyfunc'
+
+ >>> import os
+
+ >>> 2+3
+ 5
+
+ >>> for i in range(3):
+ ... print i,
+ ... print i+1,
+ ...
+ 0 1 1 2 2 3
+ """
+ return 'pyfunc'
+
+
+def ipfunc():
+ """Some ipython tests...
+
+ In [1]: import os
+
+ In [3]: 2+3
+ Out[3]: 5
+
+ In [26]: for i in range(3):
+ ....: print i,
+ ....: print i+1,
+ ....:
+ 0 1 1 2 2 3
+
+
+ Examples that access the operating system work:
+
+ In [1]: !echo hello
+ hello
+
+ In [2]: !echo hello > /tmp/foo
+
+ In [3]: !cat /tmp/foo
+ hello
+
+ In [4]: rm -f /tmp/foo
+
+ It's OK to use '_' for the last result, but do NOT try to use IPython's
+ numbered history of _NN outputs, since those won't exist under the
+ doctest environment:
+
+ In [7]: 'hi'
+ Out[7]: 'hi'
+
+ In [8]: print repr(_)
+ 'hi'
+
+ In [7]: 3+4
+ Out[7]: 7
+
+ In [8]: _+3
+ Out[8]: 10
+
+ In [9]: ipfunc()
+ Out[9]: 'ipfunc'
+ """
+ return 'ipfunc'
+
+
+def ranfunc():
+ """A function with some random output.
+
+ Normal examples are verified as usual:
+ >>> 1+3
+ 4
+
+ But if you put '# random' in the output, it is ignored:
+ >>> 1+3
+ junk goes here... # random
+
+ >>> 1+2
+ again, anything goes #random
+ if multiline, the random mark is only needed once.
+
+ >>> 1+2
+ You can also put the random marker at the end:
+ # random
+
+ >>> 1+2
+ # random
+ .. or at the beginning.
+
+ More correct input is properly verified:
+ >>> ranfunc()
+ 'ranfunc'
+ """
+ return 'ranfunc'
+
+
+def random_all():
+ """A function where we ignore the output of ALL examples.
+
+ Examples:
+
+ # all-random
+
+ This mark tells the testing machinery that all subsequent examples should
+ be treated as random (ignoring their output). They are still executed,
+ so if a they raise an error, it will be detected as such, but their
+ output is completely ignored.
+
+ >>> 1+3
+ junk goes here...
+
+ >>> 1+3
+ klasdfj;
+
+ >>> 1+2
+ again, anything goes
+ blah...
+ """
+ pass
+
+
+def iprand():
+ """Some ipython tests with random output.
+
+ In [7]: 3+4
+ Out[7]: 7
+
+ In [8]: print 'hello'
+ world # random
+
+ In [9]: iprand()
+ Out[9]: 'iprand'
+ """
+ return 'iprand'
+
+
+def iprand_all():
+ """Some ipython tests with fully random output.
+
+ # all-random
+
+ In [7]: 1
+ Out[7]: 99
+
+ In [8]: print 'hello'
+ world
+
+ In [9]: iprand_all()
+ Out[9]: 'junk'
+ """
+ return 'iprand_all'
+
+
diff --git a/IPython/testing/plugin/ipdoctest.py b/IPython/testing/plugin/ipdoctest.py
new file mode 100644
index 0000000..de9980e
--- /dev/null
+++ b/IPython/testing/plugin/ipdoctest.py
@@ -0,0 +1,939 @@
+"""Nose Plugin that supports IPython doctests.
+
+Limitations:
+
+- When generating examples for use as doctests, make sure that you have
+ pretty-printing OFF. This can be done either by starting ipython with the
+ flag '--nopprint', by setting pprint to 0 in your ipythonrc file, or by
+ interactively disabling it with %Pprint. This is required so that IPython
+ output matches that of normal Python, which is used by doctest for internal
+ execution.
+
+- Do not rely on specific prompt numbers for results (such as using
+ '_34==True', for example). For IPython tests run via an external process the
+ prompt numbers may be different, and IPython tests run as normal python code
+ won't even have these special _NN variables set at all.
+"""
+
+#-----------------------------------------------------------------------------
+# Module imports
+
+# From the standard library
+import __builtin__
+import commands
+import doctest
+import inspect
+import logging
+import os
+import re
+import sys
+import traceback
+import unittest
+
+from inspect import getmodule
+from StringIO import StringIO
+
+# We are overriding the default doctest runner, so we need to import a few
+# things from doctest directly
+from doctest import (REPORTING_FLAGS, REPORT_ONLY_FIRST_FAILURE,
+ _unittest_reportflags, DocTestRunner,
+ _extract_future_flags, pdb, _OutputRedirectingPdb,
+ _exception_traceback,
+ linecache)
+
+# Third-party modules
+import nose.core
+
+from nose.plugins import doctests, Plugin
+from nose.util import anyp, getpackage, test_address, resolve_name, tolist
+
+#-----------------------------------------------------------------------------
+# Module globals and other constants
+
+log = logging.getLogger(__name__)
+
+###########################################################################
+# *** HACK ***
+# We must start our own ipython object and heavily muck with it so that all the
+# modifications IPython makes to system behavior don't send the doctest
+# machinery into a fit. This code should be considered a gross hack, but it
+# gets the job done.
+
+def default_argv():
+ """Return a valid default argv for creating testing instances of ipython"""
+
+ # Get the install directory for the user configuration and tell ipython to
+ # use the default profile from there.
+ from IPython import UserConfig
+ ipcdir = os.path.dirname(UserConfig.__file__)
+ #ipconf = os.path.join(ipcdir,'ipy_user_conf.py')
+ ipconf = os.path.join(ipcdir,'ipythonrc')
+ #print 'conf:',ipconf # dbg
+
+ return ['--colors=NoColor','--noterm_title','-rcfile=%s' % ipconf]
+
+
+# Hack to modify the %run command so we can sync the user's namespace with the
+# test globals. Once we move over to a clean magic system, this will be done
+# with much less ugliness.
+
+class py_file_finder(object):
+ def __init__(self,test_filename):
+ self.test_filename = test_filename
+
+ def __call__(self,name):
+ from IPython.genutils import get_py_filename
+ try:
+ return get_py_filename(name)
+ except IOError:
+ test_dir = os.path.dirname(self.test_filename)
+ new_path = os.path.join(test_dir,name)
+ return get_py_filename(new_path)
+
+
+def _run_ns_sync(self,arg_s,runner=None):
+ """Modified version of %run that syncs testing namespaces.
+
+ This is strictly needed for running doctests that call %run.
+ """
+
+ # When tests call %run directly (not via doctest) these function attributes
+ # are not set
+ try:
+ fname = _run_ns_sync.test_filename
+ except AttributeError:
+ fname = arg_s
+
+ finder = py_file_finder(fname)
+ out = _ip.IP.magic_run_ori(arg_s,runner,finder)
+
+ # Simliarly, there is no test_globs when a test is NOT a doctest
+ if hasattr(_run_ns_sync,'test_globs'):
+ _run_ns_sync.test_globs.update(_ip.user_ns)
+ return out
+
+
+class ipnsdict(dict):
+ """A special subclass of dict for use as an IPython namespace in doctests.
+
+ This subclass adds a simple checkpointing capability so that when testing
+ machinery clears it (we use it as the test execution context), it doesn't
+ get completely destroyed.
+ """
+
+ def __init__(self,*a):
+ dict.__init__(self,*a)
+ self._savedict = {}
+
+ def clear(self):
+ dict.clear(self)
+ self.update(self._savedict)
+
+ def _checkpoint(self):
+ self._savedict.clear()
+ self._savedict.update(self)
+
+ def update(self,other):
+ self._checkpoint()
+ dict.update(self,other)
+
+ # If '_' is in the namespace, python won't set it when executing code,
+ # and we have examples that test it. So we ensure that the namespace
+ # is always 'clean' of it before it's used for test code execution.
+ self.pop('_',None)
+
+ # The builtins namespace must *always* be the real __builtin__ module,
+ # else weird stuff happens. The main ipython code does have provisions
+ # to ensure this after %run, but since in this class we do some
+ # aggressive low-level cleaning of the execution namespace, we need to
+ # correct for that ourselves, to ensure consitency with the 'real'
+ # ipython.
+ self['__builtins__'] = __builtin__
+
+
+def start_ipython():
+ """Start a global IPython shell, which we need for IPython-specific syntax.
+ """
+
+ # This function should only ever run once!
+ if hasattr(start_ipython,'already_called'):
+ return
+ start_ipython.already_called = True
+
+ # Ok, first time we're called, go ahead
+ import new
+
+ import IPython
+
+ def xsys(cmd):
+ """Execute a command and print its output.
+
+ This is just a convenience function to replace the IPython system call
+ with one that is more doctest-friendly.
+ """
+ cmd = _ip.IP.var_expand(cmd,depth=1)
+ sys.stdout.write(commands.getoutput(cmd))
+ sys.stdout.flush()
+
+ # Store certain global objects that IPython modifies
+ _displayhook = sys.displayhook
+ _excepthook = sys.excepthook
+ _main = sys.modules.get('__main__')
+
+ argv = default_argv()
+
+ # Start IPython instance. We customize it to start with minimal frills.
+ user_ns,global_ns = IPython.ipapi.make_user_namespaces(ipnsdict(),dict())
+ IPython.Shell.IPShell(argv,user_ns,global_ns)
+
+ # Deactivate the various python system hooks added by ipython for
+ # interactive convenience so we don't confuse the doctest system
+ sys.modules['__main__'] = _main
+ sys.displayhook = _displayhook
+ sys.excepthook = _excepthook
+
+ # So that ipython magics and aliases can be doctested (they work by making
+ # a call into a global _ip object)
+ _ip = IPython.ipapi.get()
+ __builtin__._ip = _ip
+
+ # Modify the IPython system call with one that uses getoutput, so that we
+ # can capture subcommands and print them to Python's stdout, otherwise the
+ # doctest machinery would miss them.
+ _ip.system = xsys
+
+ # Also patch our %run function in.
+ im = new.instancemethod(_run_ns_sync,_ip.IP, _ip.IP.__class__)
+ _ip.IP.magic_run_ori = _ip.IP.magic_run
+ _ip.IP.magic_run = im
+
+ # XXX - For some very bizarre reason, the loading of %history by default is
+ # failing. This needs to be fixed later, but for now at least this ensures
+ # that tests that use %hist run to completion.
+ from IPython import history
+ history.init_ipython(_ip)
+ if not hasattr(_ip.IP,'magic_history'):
+ raise RuntimeError("Can't load magics, aborting")
+
+
+# The start call MUST be made here. I'm not sure yet why it doesn't work if
+# it is made later, at plugin initialization time, but in all my tests, that's
+# the case.
+start_ipython()
+
+# *** END HACK ***
+###########################################################################
+
+# Classes and functions
+
+def is_extension_module(filename):
+ """Return whether the given filename is an extension module.
+
+ This simply checks that the extension is either .so or .pyd.
+ """
+ return os.path.splitext(filename)[1].lower() in ('.so','.pyd')
+
+
+class DocTestSkip(object):
+ """Object wrapper for doctests to be skipped."""
+
+ ds_skip = """Doctest to skip.
+ >>> 1 #doctest: +SKIP
+ """
+
+ def __init__(self,obj):
+ self.obj = obj
+
+ def __getattribute__(self,key):
+ if key == '__doc__':
+ return DocTestSkip.ds_skip
+ else:
+ return getattr(object.__getattribute__(self,'obj'),key)
+
+# Modified version of the one in the stdlib, that fixes a python bug (doctests
+# not found in extension modules, http://bugs.python.org/issue3158)
+class DocTestFinder(doctest.DocTestFinder):
+
+ def _from_module(self, module, object):
+ """
+ Return true if the given object is defined in the given
+ module.
+ """
+ if module is None:
+ return True
+ elif inspect.isfunction(object):
+ return module.__dict__ is object.func_globals
+ elif inspect.isbuiltin(object):
+ return module.__name__ == object.__module__
+ elif inspect.isclass(object):
+ return module.__name__ == object.__module__
+ elif inspect.ismethod(object):
+ # This one may be a bug in cython that fails to correctly set the
+ # __module__ attribute of methods, but since the same error is easy
+ # to make by extension code writers, having this safety in place
+ # isn't such a bad idea
+ return module.__name__ == object.im_class.__module__
+ elif inspect.getmodule(object) is not None:
+ return module is inspect.getmodule(object)
+ elif hasattr(object, '__module__'):
+ return module.__name__ == object.__module__
+ elif isinstance(object, property):
+ return True # [XX] no way not be sure.
+ else:
+ raise ValueError("object must be a class or function")
+
+ def _find(self, tests, obj, name, module, source_lines, globs, seen):
+ """
+ Find tests for the given object and any contained objects, and
+ add them to `tests`.
+ """
+
+ if hasattr(obj,"skip_doctest"):
+ #print 'SKIPPING DOCTEST FOR:',obj # dbg
+ obj = DocTestSkip(obj)
+
+ doctest.DocTestFinder._find(self,tests, obj, name, module,
+ source_lines, globs, seen)
+
+ # Below we re-run pieces of the above method with manual modifications,
+ # because the original code is buggy and fails to correctly identify
+ # doctests in extension modules.
+
+ # Local shorthands
+ from inspect import isroutine, isclass, ismodule
+
+ # Look for tests in a module's contained objects.
+ if inspect.ismodule(obj) and self._recurse:
+ for valname, val in obj.__dict__.items():
+ valname1 = '%s.%s' % (name, valname)
+ if ( (isroutine(val) or isclass(val))
+ and self._from_module(module, val) ):
+
+ self._find(tests, val, valname1, module, source_lines,
+ globs, seen)
+
+ # Look for tests in a class's contained objects.
+ if inspect.isclass(obj) and self._recurse:
+ #print 'RECURSE into class:',obj # dbg
+ for valname, val in obj.__dict__.items():
+ # Special handling for staticmethod/classmethod.
+ if isinstance(val, staticmethod):
+ val = getattr(obj, valname)
+ if isinstance(val, classmethod):
+ val = getattr(obj, valname).im_func
+
+ # Recurse to methods, properties, and nested classes.
+ if ((inspect.isfunction(val) or inspect.isclass(val) or
+ inspect.ismethod(val) or
+ isinstance(val, property)) and
+ self._from_module(module, val)):
+ valname = '%s.%s' % (name, valname)
+ self._find(tests, val, valname, module, source_lines,
+ globs, seen)
+
+
+class IPDoctestOutputChecker(doctest.OutputChecker):
+ """Second-chance checker with support for random tests.
+
+ If the default comparison doesn't pass, this checker looks in the expected
+ output string for flags that tell us to ignore the output.
+ """
+
+ random_re = re.compile(r'#\s*random\s+')
+
+ def check_output(self, want, got, optionflags):
+ """Check output, accepting special markers embedded in the output.
+
+ If the output didn't pass the default validation but the special string
+ '#random' is included, we accept it."""
+
+ # Let the original tester verify first, in case people have valid tests
+ # that happen to have a comment saying '#random' embedded in.
+ ret = doctest.OutputChecker.check_output(self, want, got,
+ optionflags)
+ if not ret and self.random_re.search(want):
+ #print >> sys.stderr, 'RANDOM OK:',want # dbg
+ return True
+
+ return ret
+
+
+class DocTestCase(doctests.DocTestCase):
+ """Proxy for DocTestCase: provides an address() method that
+ returns the correct address for the doctest case. Otherwise
+ acts as a proxy to the test case. To provide hints for address(),
+ an obj may also be passed -- this will be used as the test object
+ for purposes of determining the test address, if it is provided.
+ """
+
+ # Note: this method was taken from numpy's nosetester module.
+
+ # Subclass nose.plugins.doctests.DocTestCase to work around a bug in
+ # its constructor that blocks non-default arguments from being passed
+ # down into doctest.DocTestCase
+
+ def __init__(self, test, optionflags=0, setUp=None, tearDown=None,
+ checker=None, obj=None, result_var='_'):
+ self._result_var = result_var
+ doctests.DocTestCase.__init__(self, test,
+ optionflags=optionflags,
+ setUp=setUp, tearDown=tearDown,
+ checker=checker)
+ # Now we must actually copy the original constructor from the stdlib
+ # doctest class, because we can't call it directly and a bug in nose
+ # means it never gets passed the right arguments.
+
+ self._dt_optionflags = optionflags
+ self._dt_checker = checker
+ self._dt_test = test
+ self._dt_setUp = setUp
+ self._dt_tearDown = tearDown
+
+ # XXX - store this runner once in the object!
+ runner = IPDocTestRunner(optionflags=optionflags,
+ checker=checker, verbose=False)
+ self._dt_runner = runner
+
+
+ # Each doctest should remember what directory it was loaded from...
+ self._ori_dir = os.getcwd()
+
+ # Modified runTest from the default stdlib
+ def runTest(self):
+ test = self._dt_test
+ runner = self._dt_runner
+
+ old = sys.stdout
+ new = StringIO()
+ optionflags = self._dt_optionflags
+
+ if not (optionflags & REPORTING_FLAGS):
+ # The option flags don't include any reporting flags,
+ # so add the default reporting flags
+ optionflags |= _unittest_reportflags
+
+ try:
+ # Save our current directory and switch out to the one where the
+ # test was originally created, in case another doctest did a
+ # directory change. We'll restore this in the finally clause.
+ curdir = os.getcwd()
+ os.chdir(self._ori_dir)
+
+ runner.DIVIDER = "-"*70
+ failures, tries = runner.run(test,out=new.write,
+ clear_globs=False)
+ finally:
+ sys.stdout = old
+ os.chdir(curdir)
+
+ if failures:
+ raise self.failureException(self.format_failure(new.getvalue()))
+
+ def setUp(self):
+ """Modified test setup that syncs with ipython namespace"""
+
+ if isinstance(self._dt_test.examples[0],IPExample):
+ # for IPython examples *only*, we swap the globals with the ipython
+ # namespace, after updating it with the globals (which doctest
+ # fills with the necessary info from the module being tested).
+ _ip.IP.user_ns.update(self._dt_test.globs)
+ self._dt_test.globs = _ip.IP.user_ns
+
+ super(DocTestCase, self).setUp()
+
+ def tearDown(self):
+ # XXX - fperez: I am not sure if this is truly a bug in nose 0.11, but
+ # it does look like one to me: its tearDown method tries to run
+ #
+ # delattr(__builtin__, self._result_var)
+ #
+ # without checking that the attribute really is there; it implicitly
+ # assumes it should have been set via displayhook. But if the
+ # displayhook was never called, this doesn't necessarily happen. I
+ # haven't been able to find a little self-contained example outside of
+ # ipython that would show the problem so I can report it to the nose
+ # team, but it does happen a lot in our code.
+ #
+ # So here, we just protect as narrowly as possible by trapping an
+ # attribute error whose message would be the name of self._result_var,
+ # and letting any other error propagate.
+ try:
+ super(DocTestCase, self).tearDown()
+ except AttributeError, exc:
+ if exc.args[0] != self._result_var:
+ raise
+
+
+# A simple subclassing of the original with a different class name, so we can
+# distinguish and treat differently IPython examples from pure python ones.
+class IPExample(doctest.Example): pass
+
+
+class IPExternalExample(doctest.Example):
+ """Doctest examples to be run in an external process."""
+
+ def __init__(self, source, want, exc_msg=None, lineno=0, indent=0,
+ options=None):
+ # Parent constructor
+ doctest.Example.__init__(self,source,want,exc_msg,lineno,indent,options)
+
+ # An EXTRA newline is needed to prevent pexpect hangs
+ self.source += '\n'
+
+
+class IPDocTestParser(doctest.DocTestParser):
+ """
+ A class used to parse strings containing doctest examples.
+
+ Note: This is a version modified to properly recognize IPython input and
+ convert any IPython examples into valid Python ones.
+ """
+ # This regular expression is used to find doctest examples in a
+ # string. It defines three groups: `source` is the source code
+ # (including leading indentation and prompts); `indent` is the
+ # indentation of the first (PS1) line of the source code; and
+ # `want` is the expected output (including leading indentation).
+
+ # Classic Python prompts or default IPython ones
+ _PS1_PY = r'>>>'
+ _PS2_PY = r'\.\.\.'
+
+ _PS1_IP = r'In\ \[\d+\]:'
+ _PS2_IP = r'\ \ \ \.\.\.+:'
+
+ _RE_TPL = r'''
+ # Source consists of a PS1 line followed by zero or more PS2 lines.
+ (?P<source>
+ (?:^(?P<indent> [ ]*) (?P<ps1> %s) .*) # PS1 line
+ (?:\n [ ]* (?P<ps2> %s) .*)*) # PS2 lines
+ \n? # a newline
+ # Want consists of any non-blank lines that do not start with PS1.
+ (?P<want> (?:(?![ ]*$) # Not a blank line
+ (?![ ]*%s) # Not a line starting with PS1
+ (?![ ]*%s) # Not a line starting with PS2
+ .*$\n? # But any other line
+ )*)
+ '''
+
+ _EXAMPLE_RE_PY = re.compile( _RE_TPL % (_PS1_PY,_PS2_PY,_PS1_PY,_PS2_PY),
+ re.MULTILINE | re.VERBOSE)
+
+ _EXAMPLE_RE_IP = re.compile( _RE_TPL % (_PS1_IP,_PS2_IP,_PS1_IP,_PS2_IP),
+ re.MULTILINE | re.VERBOSE)
+
+ # Mark a test as being fully random. In this case, we simply append the
+ # random marker ('#random') to each individual example's output. This way
+ # we don't need to modify any other code.
+ _RANDOM_TEST = re.compile(r'#\s*all-random\s+')
+
+ # Mark tests to be executed in an external process - currently unsupported.
+ _EXTERNAL_IP = re.compile(r'#\s*ipdoctest:\s*EXTERNAL')
+
+ def ip2py(self,source):
+ """Convert input IPython source into valid Python."""
+ out = []
+ newline = out.append
+ #print 'IPSRC:\n',source,'\n###' # dbg
+ # The input source must be first stripped of all bracketing whitespace
+ # and turned into lines, so it looks to the parser like regular user
+ # input
+ for lnum,line in enumerate(source.strip().splitlines()):
+ newline(_ip.IP.prefilter(line,lnum>0))
+ newline('') # ensure a closing newline, needed by doctest
+ #print "PYSRC:", '\n'.join(out) # dbg
+ return '\n'.join(out)
+
+ def parse(self, string, name='<string>'):
+ """
+ Divide the given string into examples and intervening text,
+ and return them as a list of alternating Examples and strings.
+ Line numbers for the Examples are 0-based. The optional
+ argument `name` is a name identifying this string, and is only
+ used for error messages.
+ """
+
+ #print 'Parse string:\n',string # dbg
+
+ string = string.expandtabs()
+ # If all lines begin with the same indentation, then strip it.
+ min_indent = self._min_indent(string)
+ if min_indent > 0:
+ string = '\n'.join([l[min_indent:] for l in string.split('\n')])
+
+ output = []
+ charno, lineno = 0, 0
+
+ # We make 'all random' tests by adding the '# random' mark to every
+ # block of output in the test.
+ if self._RANDOM_TEST.search(string):
+ random_marker = '\n# random'
+ else:
+ random_marker = ''
+
+ # Whether to convert the input from ipython to python syntax
+ ip2py = False
+ # Find all doctest examples in the string. First, try them as Python
+ # examples, then as IPython ones
+ terms = list(self._EXAMPLE_RE_PY.finditer(string))
+ if terms:
+ # Normal Python example
+ #print '-'*70 # dbg
+ #print 'PyExample, Source:\n',string # dbg
+ #print '-'*70 # dbg
+ Example = doctest.Example
+ else:
+ # It's an ipython example. Note that IPExamples are run
+ # in-process, so their syntax must be turned into valid python.
+ # IPExternalExamples are run out-of-process (via pexpect) so they
+ # don't need any filtering (a real ipython will be executing them).
+ terms = list(self._EXAMPLE_RE_IP.finditer(string))
+ if self._EXTERNAL_IP.search(string):
+ #print '-'*70 # dbg
+ #print 'IPExternalExample, Source:\n',string # dbg
+ #print '-'*70 # dbg
+ Example = IPExternalExample
+ else:
+ #print '-'*70 # dbg
+ #print 'IPExample, Source:\n',string # dbg
+ #print '-'*70 # dbg
+ Example = IPExample
+ ip2py = True
+
+ for m in terms:
+ # Add the pre-example text to `output`.
+ output.append(string[charno:m.start()])
+ # Update lineno (lines before this example)
+ lineno += string.count('\n', charno, m.start())
+ # Extract info from the regexp match.
+ (source, options, want, exc_msg) = \
+ self._parse_example(m, name, lineno,ip2py)
+
+ # Append the random-output marker (it defaults to empty in most
+ # cases, it's only non-empty for 'all-random' tests):
+ want += random_marker
+
+ if Example is IPExternalExample:
+ options[doctest.NORMALIZE_WHITESPACE] = True
+ want += '\n'
+
+ # Create an Example, and add it to the list.
+ if not self._IS_BLANK_OR_COMMENT(source):
+ output.append(Example(source, want, exc_msg,
+ lineno=lineno,
+ indent=min_indent+len(m.group('indent')),
+ options=options))
+ # Update lineno (lines inside this example)
+ lineno += string.count('\n', m.start(), m.end())
+ # Update charno.
+ charno = m.end()
+ # Add any remaining post-example text to `output`.
+ output.append(string[charno:])
+ return output
+
+ def _parse_example(self, m, name, lineno,ip2py=False):
+ """
+ Given a regular expression match from `_EXAMPLE_RE` (`m`),
+ return a pair `(source, want)`, where `source` is the matched
+ example's source code (with prompts and indentation stripped);
+ and `want` is the example's expected output (with indentation
+ stripped).
+
+ `name` is the string's name, and `lineno` is the line number
+ where the example starts; both are used for error messages.
+
+ Optional:
+ `ip2py`: if true, filter the input via IPython to convert the syntax
+ into valid python.
+ """
+
+ # Get the example's indentation level.
+ indent = len(m.group('indent'))
+
+ # Divide source into lines; check that they're properly
+ # indented; and then strip their indentation & prompts.
+ source_lines = m.group('source').split('\n')
+
+ # We're using variable-length input prompts
+ ps1 = m.group('ps1')
+ ps2 = m.group('ps2')
+ ps1_len = len(ps1)
+
+ self._check_prompt_blank(source_lines, indent, name, lineno,ps1_len)
+ if ps2:
+ self._check_prefix(source_lines[1:], ' '*indent + ps2, name, lineno)
+
+ source = '\n'.join([sl[indent+ps1_len+1:] for sl in source_lines])
+
+ if ip2py:
+ # Convert source input from IPython into valid Python syntax
+ source = self.ip2py(source)
+
+ # Divide want into lines; check that it's properly indented; and
+ # then strip the indentation. Spaces before the last newline should
+ # be preserved, so plain rstrip() isn't good enough.
+ want = m.group('want')
+ want_lines = want.split('\n')
+ if len(want_lines) > 1 and re.match(r' *$', want_lines[-1]):
+ del want_lines[-1] # forget final newline & spaces after it
+ self._check_prefix(want_lines, ' '*indent, name,
+ lineno + len(source_lines))
+
+ # Remove ipython output prompt that might be present in the first line
+ want_lines[0] = re.sub(r'Out\[\d+\]: \s*?\n?','',want_lines[0])
+
+ want = '\n'.join([wl[indent:] for wl in want_lines])
+
+ # If `want` contains a traceback message, then extract it.
+ m = self._EXCEPTION_RE.match(want)
+ if m:
+ exc_msg = m.group('msg')
+ else:
+ exc_msg = None
+
+ # Extract options from the source.
+ options = self._find_options(source, name, lineno)
+
+ return source, options, want, exc_msg
+
+ def _check_prompt_blank(self, lines, indent, name, lineno, ps1_len):
+ """
+ Given the lines of a source string (including prompts and
+ leading indentation), check to make sure that every prompt is
+ followed by a space character. If any line is not followed by
+ a space character, then raise ValueError.
+
+ Note: IPython-modified version which takes the input prompt length as a
+ parameter, so that prompts of variable length can be dealt with.
+ """
+ space_idx = indent+ps1_len
+ min_len = space_idx+1
+ for i, line in enumerate(lines):
+ if len(line) >= min_len and line[space_idx] != ' ':
+ raise ValueError('line %r of the docstring for %s '
+ 'lacks blank after %s: %r' %
+ (lineno+i+1, name,
+ line[indent:space_idx], line))
+
+
+SKIP = doctest.register_optionflag('SKIP')
+
+
+class IPDocTestRunner(doctest.DocTestRunner,object):
+ """Test runner that synchronizes the IPython namespace with test globals.
+ """
+
+ def run(self, test, compileflags=None, out=None, clear_globs=True):
+
+ # Hack: ipython needs access to the execution context of the example,
+ # so that it can propagate user variables loaded by %run into
+ # test.globs. We put them here into our modified %run as a function
+ # attribute. Our new %run will then only make the namespace update
+ # when called (rather than unconconditionally updating test.globs here
+ # for all examples, most of which won't be calling %run anyway).
+ _run_ns_sync.test_globs = test.globs
+ _run_ns_sync.test_filename = test.filename
+
+ return super(IPDocTestRunner,self).run(test,
+ compileflags,out,clear_globs)
+
+
+class DocFileCase(doctest.DocFileCase):
+ """Overrides to provide filename
+ """
+ def address(self):
+ return (self._dt_test.filename, None, None)
+
+
+class ExtensionDoctest(doctests.Doctest):
+ """Nose Plugin that supports doctests in extension modules.
+ """
+ name = 'extdoctest' # call nosetests with --with-extdoctest
+ enabled = True
+
+ def __init__(self,exclude_patterns=None):
+ """Create a new ExtensionDoctest plugin.
+
+ Parameters
+ ----------
+
+ exclude_patterns : sequence of strings, optional
+ These patterns are compiled as regular expressions, subsequently used
+ to exclude any filename which matches them from inclusion in the test
+ suite (using pattern.search(), NOT pattern.match() ).
+ """
+
+ if exclude_patterns is None:
+ exclude_patterns = []
+ self.exclude_patterns = map(re.compile,exclude_patterns)
+ doctests.Doctest.__init__(self)
+
+ def options(self, parser, env=os.environ):
+ Plugin.options(self, parser, env)
+ parser.add_option('--doctest-tests', action='store_true',
+ dest='doctest_tests',
+ default=env.get('NOSE_DOCTEST_TESTS',True),
+ help="Also look for doctests in test modules. "
+ "Note that classes, methods and functions should "
+ "have either doctests or non-doctest tests, "
+ "not both. [NOSE_DOCTEST_TESTS]")
+ parser.add_option('--doctest-extension', action="append",
+ dest="doctestExtension",
+ help="Also look for doctests in files with "
+ "this extension [NOSE_DOCTEST_EXTENSION]")
+ # Set the default as a list, if given in env; otherwise
+ # an additional value set on the command line will cause
+ # an error.
+ env_setting = env.get('NOSE_DOCTEST_EXTENSION')
+ if env_setting is not None:
+ parser.set_defaults(doctestExtension=tolist(env_setting))
+
+
+ def configure(self, options, config):
+ Plugin.configure(self, options, config)
+ self.doctest_tests = options.doctest_tests
+ self.extension = tolist(options.doctestExtension)
+
+ self.parser = doctest.DocTestParser()
+ self.finder = DocTestFinder()
+ self.checker = IPDoctestOutputChecker()
+ self.globs = None
+ self.extraglobs = None
+
+
+ def loadTestsFromExtensionModule(self,filename):
+ bpath,mod = os.path.split(filename)
+ modname = os.path.splitext(mod)[0]
+ try:
+ sys.path.append(bpath)
+ module = __import__(modname)
+ tests = list(self.loadTestsFromModule(module))
+ finally:
+ sys.path.pop()
+ return tests
+
+ # NOTE: the method below is almost a copy of the original one in nose, with
+ # a few modifications to control output checking.
+
+ def loadTestsFromModule(self, module):
+ #print '*** ipdoctest - lTM',module # dbg
+
+ if not self.matches(module.__name__):
+ log.debug("Doctest doesn't want module %s", module)
+ return
+
+ tests = self.finder.find(module,globs=self.globs,
+ extraglobs=self.extraglobs)
+ if not tests:
+ return
+
+ # always use whitespace and ellipsis options
+ optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
+
+ tests.sort()
+ module_file = module.__file__
+ if module_file[-4:] in ('.pyc', '.pyo'):
+ module_file = module_file[:-1]
+ for test in tests:
+ if not test.examples:
+ continue
+ if not test.filename:
+ test.filename = module_file
+
+ yield DocTestCase(test,
+ optionflags=optionflags,
+ checker=self.checker)
+
+
+ def loadTestsFromFile(self, filename):
+ if is_extension_module(filename):
+ for t in self.loadTestsFromExtensionModule(filename):
+ yield t
+ else:
+ if self.extension and anyp(filename.endswith, self.extension):
+ name = os.path.basename(filename)
+ dh = open(filename)
+ try:
+ doc = dh.read()
+ finally:
+ dh.close()
+ test = self.parser.get_doctest(
+ doc, globs={'__file__': filename}, name=name,
+ filename=filename, lineno=0)
+ if test.examples:
+ #print 'FileCase:',test.examples # dbg
+ yield DocFileCase(test)
+ else:
+ yield False # no tests to load
+
+ def wantFile(self,filename):
+ """Return whether the given filename should be scanned for tests.
+
+ Modified version that accepts extension modules as valid containers for
+ doctests.
+ """
+ # print '*** ipdoctest- wantFile:',filename # dbg
+
+ for pat in self.exclude_patterns:
+ if pat.search(filename):
+ # print '###>>> SKIP:',filename # dbg
+ return False
+
+ if is_extension_module(filename):
+ return True
+ else:
+ return doctests.Doctest.wantFile(self,filename)
+
+
+class IPythonDoctest(ExtensionDoctest):
+ """Nose Plugin that supports doctests in extension modules.
+ """
+ name = 'ipdoctest' # call nosetests with --with-ipdoctest
+ enabled = True
+
+ def makeTest(self, obj, parent):
+ """Look for doctests in the given object, which will be a
+ function, method or class.
+ """
+ # always use whitespace and ellipsis options
+ optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
+
+ doctests = self.finder.find(obj, module=getmodule(parent))
+ if doctests:
+ for test in doctests:
+ if len(test.examples) == 0:
+ continue
+
+ yield DocTestCase(test, obj=obj,
+ optionflags=optionflags,
+ checker=self.checker)
+
+ def options(self, parser, env=os.environ):
+ Plugin.options(self, parser, env)
+ parser.add_option('--ipdoctest-tests', action='store_true',
+ dest='ipdoctest_tests',
+ default=env.get('NOSE_IPDOCTEST_TESTS',True),
+ help="Also look for doctests in test modules. "
+ "Note that classes, methods and functions should "
+ "have either doctests or non-doctest tests, "
+ "not both. [NOSE_IPDOCTEST_TESTS]")
+ parser.add_option('--ipdoctest-extension', action="append",
+ dest="ipdoctest_extension",
+ help="Also look for doctests in files with "
+ "this extension [NOSE_IPDOCTEST_EXTENSION]")
+ # Set the default as a list, if given in env; otherwise
+ # an additional value set on the command line will cause
+ # an error.
+ env_setting = env.get('NOSE_IPDOCTEST_EXTENSION')
+ if env_setting is not None:
+ parser.set_defaults(ipdoctest_extension=tolist(env_setting))
+
+ def configure(self, options, config):
+ Plugin.configure(self, options, config)
+ self.doctest_tests = options.ipdoctest_tests
+ self.extension = tolist(options.ipdoctest_extension)
+
+ self.parser = IPDocTestParser()
+ self.finder = DocTestFinder(parser=self.parser)
+ self.checker = IPDoctestOutputChecker()
+ self.globs = None
+ self.extraglobs = None
diff --git a/IPython/testing/plugin/iptest.py b/IPython/testing/plugin/iptest.py
new file mode 100755
index 0000000..390c422
--- /dev/null
+++ b/IPython/testing/plugin/iptest.py
@@ -0,0 +1,18 @@
+#!/usr/bin/env python
+"""Nose-based test runner.
+"""
+
+from nose.core import main
+from nose.plugins.builtin import plugins
+from nose.plugins.doctests import Doctest
+
+import ipdoctest
+from ipdoctest import IPDocTestRunner
+
+if __name__ == '__main__':
+ print 'WARNING: this code is incomplete!'
+ print
+
+ pp = [x() for x in plugins] # activate all builtin plugins first
+ main(testRunner=IPDocTestRunner(),
+ plugins=pp+[ipdoctest.IPythonDoctest(),Doctest()])
diff --git a/IPython/testing/plugin/setup.py b/IPython/testing/plugin/setup.py
new file mode 100755
index 0000000..a3281d3
--- /dev/null
+++ b/IPython/testing/plugin/setup.py
@@ -0,0 +1,18 @@
+#!/usr/bin/env python
+"""A Nose plugin to support IPython doctests.
+"""
+
+from setuptools import setup
+
+setup(name='IPython doctest plugin',
+ version='0.1',
+ author='The IPython Team',
+ description = 'Nose plugin to load IPython-extended doctests',
+ license = 'LGPL',
+ py_modules = ['ipdoctest'],
+ entry_points = {
+ 'nose.plugins.0.10': ['ipdoctest = ipdoctest:IPythonDoctest',
+ 'extdoctest = ipdoctest:ExtensionDoctest',
+ ],
+ },
+ )
diff --git a/IPython/testing/plugin/show_refs.py b/IPython/testing/plugin/show_refs.py
new file mode 100644
index 0000000..d829644
--- /dev/null
+++ b/IPython/testing/plugin/show_refs.py
@@ -0,0 +1,19 @@
+"""Simple script to show reference holding behavior.
+
+This is used by a companion test case.
+"""
+
+import gc
+
+class C(object):
+ def __del__(self):
+ pass
+ #print 'deleting object...' # dbg
+
+if __name__ == '__main__':
+ c = C()
+
+ c_refs = gc.get_referrers(c)
+ ref_ids = map(id,c_refs)
+
+ print 'c referrers:',map(type,c_refs)
diff --git a/IPython/testing/plugin/simple.py b/IPython/testing/plugin/simple.py
new file mode 100644
index 0000000..e3482d6
--- /dev/null
+++ b/IPython/testing/plugin/simple.py
@@ -0,0 +1,33 @@
+"""Simple example using doctests.
+
+This file just contains doctests both using plain python and IPython prompts.
+All tests should be loaded by nose.
+"""
+
+def pyfunc():
+ """Some pure python tests...
+
+ >>> pyfunc()
+ 'pyfunc'
+
+ >>> import os
+
+ >>> 2+3
+ 5
+
+ >>> for i in range(3):
+ ... print i,
+ ... print i+1,
+ ...
+ 0 1 1 2 2 3
+ """
+ return 'pyfunc'
+
+
+def ipyfunc2():
+ """Some pure python tests...
+
+ >>> 1+1
+ 2
+ """
+ return 'pyfunc2'
diff --git a/IPython/testing/plugin/simplevars.py b/IPython/testing/plugin/simplevars.py
new file mode 100644
index 0000000..b9286c7
--- /dev/null
+++ b/IPython/testing/plugin/simplevars.py
@@ -0,0 +1,2 @@
+x = 1
+print 'x is:',x
diff --git a/IPython/testing/plugin/test_combo.txt b/IPython/testing/plugin/test_combo.txt
new file mode 100644
index 0000000..6c8759f
--- /dev/null
+++ b/IPython/testing/plugin/test_combo.txt
@@ -0,0 +1,36 @@
+=======================
+ Combo testing example
+=======================
+
+This is a simple example that mixes ipython doctests::
+
+ In [1]: import code
+
+ In [2]: 2**12
+ Out[2]: 4096
+
+with command-line example information that does *not* get executed::
+
+ $ mpirun -n 4 ipengine --controller-port=10000 --controller-ip=host0
+
+and with literal examples of Python source code::
+
+ controller = dict(host='myhost',
+ engine_port=None, # default is 10105
+ control_port=None,
+ )
+
+ # keys are hostnames, values are the number of engine on that host
+ engines = dict(node1=2,
+ node2=2,
+ node3=2,
+ node3=2,
+ )
+
+ # Force failure to detect that this test is being run.
+ 1/0
+
+These source code examples are executed but no output is compared at all. An
+error or failure is reported only if an exception is raised.
+
+NOTE: the execution of pure python blocks is not yet working!
diff --git a/IPython/testing/plugin/test_example.txt b/IPython/testing/plugin/test_example.txt
new file mode 100644
index 0000000..d8bc6fd
--- /dev/null
+++ b/IPython/testing/plugin/test_example.txt
@@ -0,0 +1,24 @@
+=====================================
+ Tests in example form - pure python
+=====================================
+
+This file contains doctest examples embedded as code blocks, using normal
+Python prompts. See the accompanying file for similar examples using IPython
+prompts (you can't mix both types within one file). The following will be run
+as a test::
+
+ >>> 1+1
+ 2
+ >>> print "hello"
+ hello
+
+More than one example works::
+
+ >>> s="Hello World"
+
+ >>> s.upper()
+ 'HELLO WORLD'
+
+but you should note that the *entire* test file is considered to be a single
+test. Individual code blocks that fail are printed separately as ``example
+failures``, but the whole file is still counted and reported as one test.
diff --git a/IPython/testing/plugin/test_exampleip.txt b/IPython/testing/plugin/test_exampleip.txt
new file mode 100644
index 0000000..8afcbfd
--- /dev/null
+++ b/IPython/testing/plugin/test_exampleip.txt
@@ -0,0 +1,30 @@
+=================================
+ Tests in example form - IPython
+=================================
+
+You can write text files with examples that use IPython prompts (as long as you
+use the nose ipython doctest plugin), but you can not mix and match prompt
+styles in a single file. That is, you either use all ``>>>`` prompts or all
+IPython-style prompts. Your test suite *can* have both types, you just need to
+put each type of example in a separate. Using IPython prompts, you can paste
+directly from your session::
+
+ In [5]: s="Hello World"
+
+ In [6]: s.upper()
+ Out[6]: 'HELLO WORLD'
+
+Another example::
+
+ In [8]: 1+3
+ Out[8]: 4
+
+Just like in IPython docstrings, you can use all IPython syntax and features::
+
+ In [9]: !echo "hello"
+ hello
+
+ In [10]: a='hi'
+
+ In [11]: !echo $a
+ hi
diff --git a/IPython/testing/plugin/test_ipdoctest.py b/IPython/testing/plugin/test_ipdoctest.py
new file mode 100644
index 0000000..f5a6a4e
--- /dev/null
+++ b/IPython/testing/plugin/test_ipdoctest.py
@@ -0,0 +1,94 @@
+"""Tests for the ipdoctest machinery itself.
+
+Note: in a file named test_X, functions whose only test is their docstring (as
+a doctest) and which have no test functionality of their own, should be called
+'doctest_foo' instead of 'test_foo', otherwise they get double-counted (the
+empty function call is counted as a test, which just inflates tests numbers
+artificially).
+"""
+
+def doctest_simple():
+ """ipdoctest must handle simple inputs
+
+ In [1]: 1
+ Out[1]: 1
+
+ In [2]: print 1
+ 1
+ """
+
+
+def doctest_run_builtins():
+ """Check that %run doesn't damage __builtins__ via a doctest.
+
+ This is similar to the test_run_builtins, but I want *both* forms of the
+ test to catch any possible glitches in our testing machinery, since that
+ modifies %run somewhat. So for this, we have both a normal test (below)
+ and a doctest (this one).
+
+ In [1]: import tempfile
+
+ In [3]: f = tempfile.NamedTemporaryFile()
+
+ In [4]: f.write('pass\\n')
+
+ In [5]: f.flush()
+
+ In [7]: %run $f.name
+ """
+
+def doctest_multiline1():
+ """The ipdoctest machinery must handle multiline examples gracefully.
+
+ In [2]: for i in range(10):
+ ...: print i,
+ ...:
+ 0 1 2 3 4 5 6 7 8 9
+ """
+
+
+def doctest_multiline2():
+ """Multiline examples that define functions and print output.
+
+ In [7]: def f(x):
+ ...: return x+1
+ ...:
+
+ In [8]: f(1)
+ Out[8]: 2
+
+ In [9]: def g(x):
+ ...: print 'x is:',x
+ ...:
+
+ In [10]: g(1)
+ x is: 1
+
+ In [11]: g('hello')
+ x is: hello
+ """
+
+
+def doctest_multiline3():
+ """Multiline examples with blank lines.
+
+ In [12]: def h(x):
+ ....: if x>1:
+ ....: return x**2
+ ....: # To leave a blank line in the input, you must mark it
+ ....: # with a comment character:
+ ....: #
+ ....: # otherwise the doctest parser gets confused.
+ ....: else:
+ ....: return -1
+ ....:
+
+ In [13]: h(5)
+ Out[13]: 25
+
+ In [14]: h(1)
+ Out[14]: -1
+
+ In [15]: h(0)
+ Out[15]: -1
+ """
diff --git a/IPython/testing/plugin/test_refs.py b/IPython/testing/plugin/test_refs.py
new file mode 100644
index 0000000..599bdcc
--- /dev/null
+++ b/IPython/testing/plugin/test_refs.py
@@ -0,0 +1,48 @@
+"""Some simple tests for the plugin while running scripts.
+"""
+# Module imports
+# Std lib
+import inspect
+
+# Our own
+from IPython.testing import decorators as dec
+
+#-----------------------------------------------------------------------------
+# Testing functions
+
+def test_trivial():
+ """A trivial passing test."""
+ pass
+
+def doctest_run():
+ """Test running a trivial script.
+
+ In [13]: run simplevars.py
+ x is: 1
+ """
+
+def doctest_runvars():
+ """Test that variables defined in scripts get loaded correcly via %run.
+
+ In [13]: run simplevars.py
+ x is: 1
+
+ In [14]: x
+ Out[14]: 1
+ """
+
+def doctest_ivars():
+ """Test that variables defined interactively are picked up.
+ In [5]: zz=1
+
+ In [6]: zz
+ Out[6]: 1
+ """
+
+#@dec.skip_doctest
+def doctest_refs():
+ """DocTest reference holding issues when running scripts.
+
+ In [32]: run show_refs.py
+ c referrers: [<type 'dict'>]
+ """
diff --git a/IPython/testing/tests/__init__.py b/IPython/testing/tests/__init__.py
new file mode 100644
index 0000000..f751f68
--- /dev/null
+++ b/IPython/testing/tests/__init__.py
@@ -0,0 +1,10 @@
+# encoding: utf-8
+__docformat__ = "restructuredtext en"
+#-------------------------------------------------------------------------------
+# Copyright (C) 2005 Fernando Perez <fperez@colorado.edu>
+# Brian E Granger <ellisonbg@gmail.com>
+# Benjamin Ragan-Kelley <benjaminrk@gmail.com>
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
diff --git a/IPython/testing/tests/test_decorators.py b/IPython/testing/tests/test_decorators.py
new file mode 100644
index 0000000..5f7e688
--- /dev/null
+++ b/IPython/testing/tests/test_decorators.py
@@ -0,0 +1,161 @@
+"""Tests for the decorators we've created for IPython.
+"""
+
+# Module imports
+# Std lib
+import inspect
+import sys
+
+# Third party
+import nose.tools as nt
+
+# Our own
+from IPython.testing import decorators as dec
+
+
+#-----------------------------------------------------------------------------
+# Utilities
+
+# Note: copied from OInspect, kept here so the testing stuff doesn't create
+# circular dependencies and is easier to reuse.
+def getargspec(obj):
+ """Get the names and default values of a function's arguments.
+
+ A tuple of four things is returned: (args, varargs, varkw, defaults).
+ 'args' is a list of the argument names (it may contain nested lists).
+ 'varargs' and 'varkw' are the names of the * and ** arguments or None.
+ 'defaults' is an n-tuple of the default values of the last n arguments.
+
+ Modified version of inspect.getargspec from the Python Standard
+ Library."""
+
+ if inspect.isfunction(obj):
+ func_obj = obj
+ elif inspect.ismethod(obj):
+ func_obj = obj.im_func
+ else:
+ raise TypeError, 'arg is not a Python function'
+ args, varargs, varkw = inspect.getargs(func_obj.func_code)
+ return args, varargs, varkw, func_obj.func_defaults
+
+#-----------------------------------------------------------------------------
+# Testing functions
+
+@dec.skip
+def test_deliberately_broken():
+ """A deliberately broken test - we want to skip this one."""
+ 1/0
+
+@dec.skip('Testing the skip decorator')
+def test_deliberately_broken2():
+ """Another deliberately broken test - we want to skip this one."""
+ 1/0
+
+
+# Verify that we can correctly skip the doctest for a function at will, but
+# that the docstring itself is NOT destroyed by the decorator.
+@dec.skip_doctest
+def doctest_bad(x,y=1,**k):
+ """A function whose doctest we need to skip.
+
+ >>> 1+1
+ 3
+ """
+ print 'x:',x
+ print 'y:',y
+ print 'k:',k
+
+
+def call_doctest_bad():
+ """Check that we can still call the decorated functions.
+
+ >>> doctest_bad(3,y=4)
+ x: 3
+ y: 4
+ k: {}
+ """
+ pass
+
+
+def test_skip_dt_decorator():
+ """Doctest-skipping decorator should preserve the docstring.
+ """
+ # Careful: 'check' must be a *verbatim* copy of the doctest_bad docstring!
+ check = """A function whose doctest we need to skip.
+
+ >>> 1+1
+ 3
+ """
+ # Fetch the docstring from doctest_bad after decoration.
+ val = doctest_bad.__doc__
+
+ assert check==val,"doctest_bad docstrings don't match"
+
+# Doctest skipping should work for class methods too
+class foo(object):
+ """Foo
+
+ Example:
+
+ >>> 1+1
+ 2
+ """
+
+ @dec.skip_doctest
+ def __init__(self,x):
+ """Make a foo.
+
+ Example:
+
+ >>> f = foo(3)
+ junk
+ """
+ print 'Making a foo.'
+ self.x = x
+
+ @dec.skip_doctest
+ def bar(self,y):
+ """Example:
+
+ >>> f = foo(3)
+ >>> f.bar(0)
+ boom!
+ >>> 1/0
+ bam!
+ """
+ return 1/y
+
+ def baz(self,y):
+ """Example:
+
+ >>> f = foo(3)
+ Making a foo.
+ >>> f.baz(3)
+ True
+ """
+ return self.x==y
+
+
+
+def test_skip_dt_decorator2():
+ """Doctest-skipping decorator should preserve function signature.
+ """
+ # Hardcoded correct answer
+ dtargs = (['x', 'y'], None, 'k', (1,))
+ # Introspect out the value
+ dtargsr = getargspec(doctest_bad)
+ assert dtargsr==dtargs, \
+ "Incorrectly reconstructed args for doctest_bad: %s" % (dtargsr,)
+
+
+@dec.skip_linux
+def test_linux():
+ nt.assert_not_equals(sys.platform,'linux2',"This test can't run under linux")
+
+@dec.skip_win32
+def test_win32():
+ nt.assert_not_equals(sys.platform,'win32',"This test can't run under windows")
+
+@dec.skip_osx
+def test_osx():
+ nt.assert_not_equals(sys.platform,'darwin',"This test can't run under osx")
diff --git a/IPython/testing/tests/test_decorators_trial.py b/IPython/testing/tests/test_decorators_trial.py
new file mode 100644
index 0000000..6462285
--- /dev/null
+++ b/IPython/testing/tests/test_decorators_trial.py
@@ -0,0 +1,52 @@
+# encoding: utf-8
+"""
+Tests for decorators_trial.py
+"""
+
+#-----------------------------------------------------------------------------
+# Copyright (C) 2008-2009 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+# Tell nose to skip this module
+__test__ = {}
+
+import os
+import sys
+
+from twisted.trial import unittest
+import IPython.testing.decorators_trial as dec
+
+#-----------------------------------------------------------------------------
+# Tests
+#-----------------------------------------------------------------------------
+
+class TestDecoratorsTrial(unittest.TestCase):
+
+ @dec.skip()
+ def test_deliberately_broken(self):
+ """A deliberately broken test - we want to skip this one."""
+ 1/0
+
+ @dec.skip('Testing the skip decorator')
+ def test_deliberately_broken2(self):
+ """Another deliberately broken test - we want to skip this one."""
+ 1/0
+
+ @dec.skip_linux
+ def test_linux(self):
+ self.assertNotEquals(sys.platform,'linux2',"This test can't run under linux")
+
+ @dec.skip_win32
+ def test_win32(self):
+ self.assertNotEquals(sys.platform,'win32',"This test can't run under windows")
+
+ @dec.skip_osx
+ def test_osx(self):
+ self.assertNotEquals(sys.platform,'darwin',"This test can't run under osx") \ No newline at end of file
diff --git a/IPython/testing/tests/test_tools.py b/IPython/testing/tests/test_tools.py
new file mode 100644
index 0000000..8245c99
--- /dev/null
+++ b/IPython/testing/tests/test_tools.py
@@ -0,0 +1,52 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+Tests for testing.tools
+"""
+
+#-----------------------------------------------------------------------------
+# Copyright (C) 2008-2009 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+import os
+import sys
+
+import nose.tools as nt
+
+from IPython.testing import decorators as dec
+from IPython.testing.tools import full_path
+
+#-----------------------------------------------------------------------------
+# Tests
+#-----------------------------------------------------------------------------
+
+
+@dec.skip_win32
+def test_full_path_posix():
+ spath = '/foo/bar.py'
+ result = full_path(spath,['a.txt','b.txt'])
+ nt.assert_equal(result, ['/foo/a.txt', '/foo/b.txt'])
+ spath = '/foo'
+ result = full_path(spath,['a.txt','b.txt'])
+ nt.assert_equal(result, ['/a.txt', '/b.txt'])
+ result = full_path(spath,'a.txt')
+ nt.assert_equal(result, ['/a.txt'])
+
+
+@dec.skip_if_not_win32
+def test_full_path_win32():
+ spath = 'c:\\foo\\bar.py'
+ result = full_path(spath,['a.txt','b.txt'])
+ nt.assert_equal(result, ['c:\\foo\\a.txt', 'c:\\foo\\b.txt'])
+ spath = 'c:\\foo'
+ result = full_path(spath,['a.txt','b.txt'])
+ nt.assert_equal(result, ['c:\\a.txt', 'c:\\b.txt'])
+ result = full_path(spath,'a.txt')
+ nt.assert_equal(result, ['c:\\a.txt']) \ No newline at end of file
diff --git a/IPython/testing/tools.py b/IPython/testing/tools.py
new file mode 100644
index 0000000..c43754c
--- /dev/null
+++ b/IPython/testing/tools.py
@@ -0,0 +1,89 @@
+"""Generic testing tools that do NOT depend on Twisted.
+
+In particular, this module exposes a set of top-level assert* functions that
+can be used in place of nose.tools.assert* in method generators (the ones in
+nose can not, at least as of nose 0.10.4).
+
+Note: our testing package contains testing.util, which does depend on Twisted
+and provides utilities for tests that manage Deferreds. All testing support
+tools that only depend on nose, IPython or the standard library should go here
+instead.
+
+
+Authors
+-------
+- Fernando Perez <Fernando.Perez@berkeley.edu>
+"""
+
+#*****************************************************************************
+# Copyright (C) 2009 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#*****************************************************************************
+
+#-----------------------------------------------------------------------------
+# Required modules and packages
+#-----------------------------------------------------------------------------
+
+import os
+import sys
+
+import nose.tools as nt
+
+from IPython.tools import utils
+from IPython.testing import decorators as dec
+
+#-----------------------------------------------------------------------------
+# Globals
+#-----------------------------------------------------------------------------
+
+# Make a bunch of nose.tools assert wrappers that can be used in test
+# generators. This will expose an assert* function for each one in nose.tools.
+
+_tpl = """
+def %(name)s(*a,**kw):
+ return nt.%(name)s(*a,**kw)
+"""
+
+for _x in [a for a in dir(nt) if a.startswith('assert')]:
+ exec _tpl % dict(name=_x)
+
+#-----------------------------------------------------------------------------
+# Functions and classes
+#-----------------------------------------------------------------------------
+
+
+def full_path(startPath,files):
+ """Make full paths for all the listed files, based on startPath.
+
+ Only the base part of startPath is kept, since this routine is typically
+ used with a script's __file__ variable as startPath. The base of startPath
+ is then prepended to all the listed files, forming the output list.
+
+ Parameters
+ ----------
+ startPath : string
+ Initial path to use as the base for the results. This path is split
+ using os.path.split() and only its first component is kept.
+
+ files : string or list
+ One or more files.
+
+ Examples
+ --------
+
+ >>> full_path('/foo/bar.py',['a.txt','b.txt'])
+ ['/foo/a.txt', '/foo/b.txt']
+
+ >>> full_path('/foo',['a.txt','b.txt'])
+ ['/a.txt', '/b.txt']
+
+ If a single file is given, the output is still a list:
+ >>> full_path('/foo','a.txt')
+ ['/a.txt']
+ """
+
+ files = utils.list_strings(files)
+ base = os.path.split(startPath)[0]
+ return [ os.path.join(base,f) for f in files ]
diff --git a/IPython/testing/util.py b/IPython/testing/util.py
new file mode 100644
index 0000000..5c4253f
--- /dev/null
+++ b/IPython/testing/util.py
@@ -0,0 +1,64 @@
+# encoding: utf-8
+"""This file contains utility classes for performing tests with Deferreds.
+"""
+__docformat__ = "restructuredtext en"
+#-------------------------------------------------------------------------------
+# Copyright (C) 2005 Fernando Perez <fperez@colorado.edu>
+# Brian E Granger <ellisonbg@gmail.com>
+# Benjamin Ragan-Kelley <benjaminrk@gmail.com>
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Imports
+#-------------------------------------------------------------------------------
+
+from twisted.trial import unittest
+from twisted.internet import defer
+
+class DeferredTestCase(unittest.TestCase):
+
+ def assertDeferredEquals(self, deferred, expectedResult,
+ chainDeferred=None):
+ """Calls assertEquals on the result of the deferred and expectedResult.
+
+ chainDeferred can be used to pass in previous Deferred objects that
+ have tests being run on them. This chaining of Deferred's in tests
+ is needed to insure that all Deferred's are cleaned up at the end of
+ a test.
+ """
+
+ if chainDeferred is None:
+ chainDeferred = defer.succeed(None)
+
+ def gotResult(actualResult):
+ self.assertEquals(actualResult, expectedResult)
+
+ deferred.addCallback(gotResult)
+
+ return chainDeferred.addCallback(lambda _: deferred)
+
+ def assertDeferredRaises(self, deferred, expectedException,
+ chainDeferred=None):
+ """Calls assertRaises on the Failure of the deferred and expectedException.
+
+ chainDeferred can be used to pass in previous Deferred objects that
+ have tests being run on them. This chaining of Deferred's in tests
+ is needed to insure that all Deferred's are cleaned up at the end of
+ a test.
+ """
+
+ if chainDeferred is None:
+ chainDeferred = defer.succeed(None)
+
+ def gotFailure(f):
+ #f.printTraceback()
+ self.assertRaises(expectedException, f.raiseException)
+ #return f
+
+ deferred.addBoth(gotFailure)
+
+ return chainDeferred.addCallback(lambda _: deferred)
+
diff --git a/IPython/tests/__init__.py b/IPython/tests/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/IPython/tests/__init__.py
diff --git a/IPython/tests/obj_del.py b/IPython/tests/obj_del.py
new file mode 100644
index 0000000..8ea9d18
--- /dev/null
+++ b/IPython/tests/obj_del.py
@@ -0,0 +1,34 @@
+"""Test code for https://bugs.launchpad.net/ipython/+bug/239054
+
+WARNING: this script exits IPython! It MUST be run in a subprocess.
+
+When you run the following script from CPython it prints:
+__init__ is here
+__del__ is here
+
+and creates the __del__.txt file
+
+When you run it from IPython it prints:
+__init__ is here
+
+When you exit() or Exit from IPython neothing is printed and no file is created
+(the file thing is to make sure __del__ is really never called and not that
+just the output is eaten).
+
+Note that if you call %reset in IPython then everything is Ok.
+
+IPython should do the equivalent of %reset and release all the references it
+holds before exit. This behavior is important when working with binding objects
+that rely on __del__. If the current behavior has some use case then I suggest
+to add a configuration option to IPython to control it.
+"""
+import sys
+
+class A(object):
+ def __del__(self):
+ print 'obj_del.py: object A deleted'
+
+a = A()
+
+# Now, we force an exit, the caller will check that the del printout was given
+_ip.IP.ask_exit()
diff --git a/IPython/tests/refbug.py b/IPython/tests/refbug.py
new file mode 100644
index 0000000..99aca19
--- /dev/null
+++ b/IPython/tests/refbug.py
@@ -0,0 +1,41 @@
+"""Minimal script to reproduce our nasty reference counting bug.
+
+The problem is related to https://bugs.launchpad.net/ipython/+bug/269966
+
+The original fix for that appeared to work, but John D. Hunter found a
+matplotlib example which, when run twice in a row, would break. The problem
+were references held by open figures to internals of Tkinter.
+
+This code reproduces the problem that John saw, without matplotlib.
+
+This script is meant to be called by other parts of the test suite that call it
+via %run as if it were executed interactively by the user. As of 2009-04-13,
+test_magic.py calls it.
+"""
+
+#-----------------------------------------------------------------------------
+# Module imports
+#-----------------------------------------------------------------------------
+import sys
+
+from IPython import ipapi
+
+#-----------------------------------------------------------------------------
+# Globals
+#-----------------------------------------------------------------------------
+ip = ipapi.get()
+
+if not '_refbug_cache' in ip.user_ns:
+ ip.user_ns['_refbug_cache'] = []
+
+
+aglobal = 'Hello'
+def f():
+ return aglobal
+
+cache = ip.user_ns['_refbug_cache']
+cache.append(f)
+
+def call_f():
+ for func in cache:
+ print 'lowercased:',func().lower()
diff --git a/IPython/tests/tclass.py b/IPython/tests/tclass.py
new file mode 100644
index 0000000..5f3bb24
--- /dev/null
+++ b/IPython/tests/tclass.py
@@ -0,0 +1,27 @@
+"""Simple script to instantiate a class for testing %run"""
+
+import sys
+
+# An external test will check that calls to f() work after %run
+class foo: pass
+
+def f():
+ return foo()
+
+# We also want to ensure that while objects remain available for immediate
+# access, objects from *previous* runs of the same script get collected, to
+# avoid accumulating massive amounts of old references.
+class C(object):
+ def __init__(self,name):
+ self.name = name
+
+ def __del__(self):
+ print 'tclass.py: deleting object:',self.name
+
+try:
+ name = sys.argv[1]
+except IndexError:
+ pass
+else:
+ if name.startswith('C'):
+ c = C(name)
diff --git a/IPython/tests/test_fakemodule.py b/IPython/tests/test_fakemodule.py
new file mode 100644
index 0000000..6325439
--- /dev/null
+++ b/IPython/tests/test_fakemodule.py
@@ -0,0 +1,17 @@
+"""Tests for the FakeModule objects.
+"""
+
+import nose.tools as nt
+
+from IPython.FakeModule import FakeModule, init_fakemod_dict
+
+# Make a fakemod and check a few properties
+def test_mk_fakemod():
+ fm = FakeModule()
+ yield nt.assert_true,fm
+ yield nt.assert_true,lambda : hasattr(fm,'__file__')
+
+def test_mk_fakemod_fromdict():
+ """Test making a FakeModule object with initial data"""
+ fm = FakeModule(dict(hello=True))
+ nt.assert_true(fm.hello)
diff --git a/IPython/tests/test_genutils.py b/IPython/tests/test_genutils.py
new file mode 100644
index 0000000..17d9449
--- /dev/null
+++ b/IPython/tests/test_genutils.py
@@ -0,0 +1,306 @@
+# encoding: utf-8
+
+"""Tests for genutils.py"""
+
+__docformat__ = "restructuredtext en"
+
+#-----------------------------------------------------------------------------
+# Copyright (C) 2008 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+# stdlib
+import os
+import shutil
+import sys
+import tempfile
+
+from os.path import join, abspath, split
+
+# third-party
+import nose.tools as nt
+
+from nose import with_setup
+from nose.tools import raises
+
+# Our own
+import IPython
+from IPython import genutils
+from IPython.testing.decorators import skipif, skip_if_not_win32
+
+# Platform-dependent imports
+try:
+ import _winreg as wreg
+except ImportError:
+ #Fake _winreg module on none windows platforms
+ import new
+ sys.modules["_winreg"] = new.module("_winreg")
+ import _winreg as wreg
+ #Add entries that needs to be stubbed by the testing code
+ (wreg.OpenKey, wreg.QueryValueEx,) = (None, None)
+
+#-----------------------------------------------------------------------------
+# Globals
+#-----------------------------------------------------------------------------
+env = os.environ
+TEST_FILE_PATH = split(abspath(__file__))[0]
+TMP_TEST_DIR = tempfile.mkdtemp()
+HOME_TEST_DIR = join(TMP_TEST_DIR, "home_test_dir")
+IP_TEST_DIR = join(HOME_TEST_DIR,'_ipython')
+#
+# Setup/teardown functions/decorators
+#
+
+def setup():
+ """Setup testenvironment for the module:
+
+ - Adds dummy home dir tree
+ """
+ # Do not mask exceptions here. In particular, catching WindowsError is a
+ # problem because that exception is only defined on Windows...
+ os.makedirs(IP_TEST_DIR)
+
+def teardown():
+ """Teardown testenvironment for the module:
+
+ - Remove dummy home dir tree
+ """
+ # Note: we remove the parent test dir, which is the root of all test
+ # subdirs we may have created. Use shutil instead of os.removedirs, so
+ # that non-empty directories are all recursively removed.
+ shutil.rmtree(TMP_TEST_DIR)
+
+
+def setup_environment():
+ """Setup testenvironment for some functions that are tested
+ in this module. In particular this functions stores attributes
+ and other things that we need to stub in some test functions.
+ This needs to be done on a function level and not module level because
+ each testfunction needs a pristine environment.
+ """
+ global oldstuff, platformstuff
+ oldstuff = (env.copy(), os.name, genutils.get_home_dir, IPython.__file__,)
+
+ if os.name == 'nt':
+ platformstuff = (wreg.OpenKey, wreg.QueryValueEx,)
+
+ if 'IPYTHONDIR' in env:
+ del env['IPYTHONDIR']
+
+def teardown_environment():
+ """Restore things that were remebered by the setup_environment function
+ """
+ (oldenv, os.name, genutils.get_home_dir, IPython.__file__,) = oldstuff
+ for key in env.keys():
+ if key not in oldenv:
+ del env[key]
+ env.update(oldenv)
+ if hasattr(sys, 'frozen'):
+ del sys.frozen
+ if os.name == 'nt':
+ (wreg.OpenKey, wreg.QueryValueEx,) = platformstuff
+
+# Build decorator that uses the setup_environment/setup_environment
+with_enivronment = with_setup(setup_environment, teardown_environment)
+
+
+#
+# Tests for get_home_dir
+#
+
+@skip_if_not_win32
+@with_enivronment
+def test_get_home_dir_1():
+ """Testcase for py2exe logic, un-compressed lib
+ """
+ sys.frozen = True
+
+ #fake filename for IPython.__init__
+ IPython.__file__ = abspath(join(HOME_TEST_DIR, "Lib/IPython/__init__.py"))
+
+ home_dir = genutils.get_home_dir()
+ nt.assert_equal(home_dir, abspath(HOME_TEST_DIR))
+
+@skip_if_not_win32
+@with_enivronment
+def test_get_home_dir_2():
+ """Testcase for py2exe logic, compressed lib
+ """
+ sys.frozen = True
+ #fake filename for IPython.__init__
+ IPython.__file__ = abspath(join(HOME_TEST_DIR, "Library.zip/IPython/__init__.py")).lower()
+
+ home_dir = genutils.get_home_dir()
+ nt.assert_equal(home_dir, abspath(HOME_TEST_DIR).lower())
+
+@with_enivronment
+def test_get_home_dir_3():
+ """Testcase $HOME is set, then use its value as home directory."""
+ env["HOME"] = HOME_TEST_DIR
+ home_dir = genutils.get_home_dir()
+ nt.assert_equal(home_dir, env["HOME"])
+
+@with_enivronment
+def test_get_home_dir_4():
+ """Testcase $HOME is not set, os=='poix'.
+ This should fail with HomeDirError"""
+
+ os.name = 'posix'
+ if 'HOME' in env: del env['HOME']
+ nt.assert_raises(genutils.HomeDirError, genutils.get_home_dir)
+
+@skip_if_not_win32
+@with_enivronment
+def test_get_home_dir_5():
+ """Testcase $HOME is not set, os=='nt'
+ env['HOMEDRIVE'],env['HOMEPATH'] points to path."""
+
+ os.name = 'nt'
+ if 'HOME' in env: del env['HOME']
+ env['HOMEDRIVE'], env['HOMEPATH'] = os.path.splitdrive(HOME_TEST_DIR)
+
+ home_dir = genutils.get_home_dir()
+ nt.assert_equal(home_dir, abspath(HOME_TEST_DIR))
+
+@skip_if_not_win32
+@with_enivronment
+def test_get_home_dir_6():
+ """Testcase $HOME is not set, os=='nt'
+ env['HOMEDRIVE'],env['HOMEPATH'] do not point to path.
+ env['USERPROFILE'] points to path
+ """
+
+ os.name = 'nt'
+ if 'HOME' in env: del env['HOME']
+ env['HOMEDRIVE'], env['HOMEPATH'] = os.path.abspath(TEST_FILE_PATH), "DOES NOT EXIST"
+ env["USERPROFILE"] = abspath(HOME_TEST_DIR)
+
+ home_dir = genutils.get_home_dir()
+ nt.assert_equal(home_dir, abspath(HOME_TEST_DIR))
+
+# Should we stub wreg fully so we can run the test on all platforms?
+@skip_if_not_win32
+@with_enivronment
+def test_get_home_dir_7():
+ """Testcase $HOME is not set, os=='nt'
+ env['HOMEDRIVE'],env['HOMEPATH'], env['USERPROFILE'] missing
+ """
+ os.name = 'nt'
+ if 'HOME' in env: del env['HOME']
+ if 'HOMEDRIVE' in env: del env['HOMEDRIVE']
+
+ #Stub windows registry functions
+ def OpenKey(x, y):
+ class key:
+ def Close(self):
+ pass
+ return key()
+ def QueryValueEx(x, y):
+ return [abspath(HOME_TEST_DIR)]
+
+ wreg.OpenKey = OpenKey
+ wreg.QueryValueEx = QueryValueEx
+
+ home_dir = genutils.get_home_dir()
+ nt.assert_equal(home_dir, abspath(HOME_TEST_DIR))
+
+#
+# Tests for get_ipython_dir
+#
+
+@with_enivronment
+def test_get_ipython_dir_1():
+ """test_get_ipython_dir_1, Testcase to see if we can call get_ipython_dir without Exceptions."""
+ env['IPYTHONDIR'] = "someplace/.ipython"
+ ipdir = genutils.get_ipython_dir()
+ nt.assert_equal(ipdir, os.path.abspath("someplace/.ipython"))
+
+
+@with_enivronment
+def test_get_ipython_dir_2():
+ """test_get_ipython_dir_2, Testcase to see if we can call get_ipython_dir without Exceptions."""
+ genutils.get_home_dir = lambda : "someplace"
+ os.name = "posix"
+ ipdir = genutils.get_ipython_dir()
+ nt.assert_equal(ipdir, os.path.abspath(os.path.join("someplace", ".ipython")))
+
+@with_enivronment
+def test_get_ipython_dir_3():
+ """test_get_ipython_dir_3, Testcase to see if we can call get_ipython_dir without Exceptions."""
+ genutils.get_home_dir = lambda : "someplace"
+ os.name = "nt"
+ ipdir = genutils.get_ipython_dir()
+ nt.assert_equal(ipdir, os.path.abspath(os.path.join("someplace", "_ipython")))
+
+#
+# Tests for get_security_dir
+#
+
+@with_enivronment
+def test_get_security_dir():
+ """Testcase to see if we can call get_security_dir without Exceptions."""
+ sdir = genutils.get_security_dir()
+
+#
+# Tests for get_log_dir
+#
+
+@with_enivronment
+def test_get_log_dir():
+ """Testcase to see if we can call get_log_dir without Exceptions."""
+ sdir = genutils.get_log_dir()
+
+#
+# Tests for popkey
+#
+
+def test_popkey_1():
+ """test_popkey_1, Basic usage test of popkey
+ """
+ dct = dict(a=1, b=2, c=3)
+ nt.assert_equal(genutils.popkey(dct, "a"), 1)
+ nt.assert_equal(dct, dict(b=2, c=3))
+ nt.assert_equal(genutils.popkey(dct, "b"), 2)
+ nt.assert_equal(dct, dict(c=3))
+ nt.assert_equal(genutils.popkey(dct, "c"), 3)
+ nt.assert_equal(dct, dict())
+
+def test_popkey_2():
+ """test_popkey_2, Test to see that popkey of non occuring keys
+ generates a KeyError exception
+ """
+ dct = dict(a=1, b=2, c=3)
+ nt.assert_raises(KeyError, genutils.popkey, dct, "d")
+
+def test_popkey_3():
+ """test_popkey_3, Tests to see that popkey calls returns the correct value
+ and that the key/value was removed from the dict.
+ """
+ dct = dict(a=1, b=2, c=3)
+ nt.assert_equal(genutils.popkey(dct, "A", 13), 13)
+ nt.assert_equal(dct, dict(a=1, b=2, c=3))
+ nt.assert_equal(genutils.popkey(dct, "B", 14), 14)
+ nt.assert_equal(dct, dict(a=1, b=2, c=3))
+ nt.assert_equal(genutils.popkey(dct, "C", 15), 15)
+ nt.assert_equal(dct, dict(a=1, b=2, c=3))
+ nt.assert_equal(genutils.popkey(dct, "a"), 1)
+ nt.assert_equal(dct, dict(b=2, c=3))
+ nt.assert_equal(genutils.popkey(dct, "b"), 2)
+ nt.assert_equal(dct, dict(c=3))
+ nt.assert_equal(genutils.popkey(dct, "c"), 3)
+ nt.assert_equal(dct, dict())
+
+
+def test_filefind():
+ """Various tests for filefind"""
+ f = tempfile.NamedTemporaryFile()
+ print 'fname:',f.name
+ alt_dirs = genutils.get_ipython_dir()
+ t = genutils.filefind(f.name,alt_dirs)
+ print 'found:',t
diff --git a/IPython/tests/test_iplib.py b/IPython/tests/test_iplib.py
new file mode 100644
index 0000000..723343c
--- /dev/null
+++ b/IPython/tests/test_iplib.py
@@ -0,0 +1,80 @@
+"""Tests for the key iplib module, where the main ipython class is defined.
+"""
+#-----------------------------------------------------------------------------
+# Module imports
+#-----------------------------------------------------------------------------
+
+# stdlib
+import os
+import shutil
+import tempfile
+
+# third party
+import nose.tools as nt
+
+# our own packages
+from IPython import ipapi, iplib
+
+#-----------------------------------------------------------------------------
+# Globals
+#-----------------------------------------------------------------------------
+
+# Useful global ipapi object and main IPython one. Unfortunately we have a
+# long precedent of carrying the 'ipapi' global object which is injected into
+# the system namespace as _ip, but that keeps a pointer to the actual IPython
+# InteractiveShell instance, which is named IP. Since in testing we do need
+# access to the real thing (we want to probe beyond what ipapi exposes), make
+# here a global reference to each. In general, things that are exposed by the
+# ipapi instance should be read from there, but we also will often need to use
+# the actual IPython one.
+
+# Get the public instance of IPython, and if it's None, make one so we can use
+# it for testing
+ip = ipapi.get()
+if ip is None:
+ # IPython not running yet, make one from the testing machinery for
+ # consistency when the test suite is being run via iptest
+ from IPython.testing.plugin import ipdoctest
+ ip = ipapi.get()
+
+IP = ip.IP # This is the actual IPython shell 'raw' object.
+
+#-----------------------------------------------------------------------------
+# Test functions
+#-----------------------------------------------------------------------------
+
+def test_reset():
+ """reset must clear most namespaces."""
+ IP.reset() # first, it should run without error
+ # Then, check that most namespaces end up empty
+ for ns in IP.ns_refs_table:
+ if ns is IP.user_ns:
+ # The user namespace is reset with some data, so we can't check for
+ # it being empty
+ continue
+ nt.assert_equals(len(ns),0)
+
+
+# make sure that user_setup can be run re-entrantly in 'install' mode.
+def test_user_setup():
+ # use a lambda to pass kwargs to the generator
+ user_setup = lambda a,k: iplib.user_setup(*a,**k)
+ kw = dict(mode='install', interactive=False)
+
+ # Call the user setup and verify that the directory exists
+ yield user_setup, (ip.options.ipythondir,''), kw
+ yield os.path.isdir, ip.options.ipythondir
+
+ # Now repeat the operation with a non-existent directory. Check both that
+ # the call succeeds and that the directory is created.
+ tmpdir = tempfile.mktemp(prefix='ipython-test-')
+ # Use a try with an empty except because try/finally doesn't work with a
+ # yield in Python 2.4.
+ try:
+ yield user_setup, (tmpdir,''), kw
+ yield os.path.isdir, tmpdir
+ except:
+ pass
+ # Clean up the temp dir once done
+ shutil.rmtree(tmpdir)
+ \ No newline at end of file
diff --git a/IPython/tests/test_magic.py b/IPython/tests/test_magic.py
new file mode 100644
index 0000000..a17f130
--- /dev/null
+++ b/IPython/tests/test_magic.py
@@ -0,0 +1,302 @@
+"""Tests for various magic functions.
+
+Needs to be run by nose (to make ipython session available).
+"""
+
+import os
+import sys
+import tempfile
+import types
+
+import nose.tools as nt
+
+from IPython.platutils import find_cmd, get_long_path_name
+from IPython.testing import decorators as dec
+from IPython.testing import tools as tt
+
+#-----------------------------------------------------------------------------
+# Test functions begin
+
+def test_rehashx():
+ # clear up everything
+ _ip.IP.alias_table.clear()
+ del _ip.db['syscmdlist']
+
+ _ip.magic('rehashx')
+ # Practically ALL ipython development systems will have more than 10 aliases
+
+ yield (nt.assert_true, len(_ip.IP.alias_table) > 10)
+ for key, val in _ip.IP.alias_table.items():
+ # we must strip dots from alias names
+ nt.assert_true('.' not in key)
+
+ # rehashx must fill up syscmdlist
+ scoms = _ip.db['syscmdlist']
+ yield (nt.assert_true, len(scoms) > 10)
+
+
+def doctest_hist_f():
+ """Test %hist -f with temporary filename.
+
+ In [9]: import tempfile
+
+ In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
+
+ In [11]: %hist -n -f $tfile 3
+ """
+
+
+def doctest_hist_r():
+ """Test %hist -r
+
+ XXX - This test is not recording the output correctly. Not sure why...
+
+ In [20]: 'hist' in _ip.IP.lsmagic()
+ Out[20]: True
+
+ In [6]: x=1
+
+ In [7]: %hist -n -r 2
+ x=1 # random
+ hist -n -r 2 # random
+ """
+
+# This test is known to fail on win32.
+# See ticket https://bugs.launchpad.net/bugs/366334
+def test_obj_del():
+ """Test that object's __del__ methods are called on exit."""
+ test_dir = os.path.dirname(__file__)
+ del_file = os.path.join(test_dir,'obj_del.py')
+ ipython_cmd = find_cmd('ipython')
+ out = _ip.IP.getoutput('%s %s' % (ipython_cmd, del_file))
+ nt.assert_equals(out,'obj_del.py: object A deleted')
+
+
+def test_shist():
+ # Simple tests of ShadowHist class - test generator.
+ import os, shutil, tempfile
+
+ from IPython.Extensions import pickleshare
+ from IPython.history import ShadowHist
+
+ tfile = tempfile.mktemp('','tmp-ipython-')
+
+ db = pickleshare.PickleShareDB(tfile)
+ s = ShadowHist(db)
+ s.add('hello')
+ s.add('world')
+ s.add('hello')
+ s.add('hello')
+ s.add('karhu')
+
+ yield nt.assert_equals,s.all(),[(1, 'hello'), (2, 'world'), (3, 'karhu')]
+
+ yield nt.assert_equal,s.get(2),'world'
+
+ shutil.rmtree(tfile)
+
+@dec.skipif_not_numpy
+def test_numpy_clear_array_undec():
+ from IPython.Extensions import clearcmd
+
+ _ip.ex('import numpy as np')
+ _ip.ex('a = np.empty(2)')
+ yield (nt.assert_true, 'a' in _ip.user_ns)
+ _ip.magic('clear array')
+ yield (nt.assert_false, 'a' in _ip.user_ns)
+
+
+@dec.skip()
+def test_fail_dec(*a,**k):
+ yield nt.assert_true, False
+
+@dec.skip('This one shouldn not run')
+def test_fail_dec2(*a,**k):
+ yield nt.assert_true, False
+
+@dec.skipknownfailure
+def test_fail_dec3(*a,**k):
+ yield nt.assert_true, False
+
+
+def doctest_refbug():
+ """Very nasty problem with references held by multiple runs of a script.
+ See: https://bugs.launchpad.net/ipython/+bug/269966
+
+ In [1]: _ip.IP.clear_main_mod_cache()
+
+ In [2]: run refbug
+
+ In [3]: call_f()
+ lowercased: hello
+
+ In [4]: run refbug
+
+ In [5]: call_f()
+ lowercased: hello
+ lowercased: hello
+ """
+
+#-----------------------------------------------------------------------------
+# Tests for %run
+#-----------------------------------------------------------------------------
+
+# %run is critical enough that it's a good idea to have a solid collection of
+# tests for it, some as doctests and some as normal tests.
+
+def doctest_run_ns():
+ """Classes declared %run scripts must be instantiable afterwards.
+
+ In [11]: run tclass foo
+
+ In [12]: isinstance(f(),foo)
+ Out[12]: True
+ """
+
+
+def doctest_run_ns2():
+ """Classes declared %run scripts must be instantiable afterwards.
+
+ In [4]: run tclass C-first_pass
+
+ In [5]: run tclass C-second_pass
+ tclass.py: deleting object: C-first_pass
+ """
+
+def doctest_run_builtins():
+ """Check that %run doesn't damage __builtins__ via a doctest.
+
+ This is similar to the test_run_builtins, but I want *both* forms of the
+ test to catch any possible glitches in our testing machinery, since that
+ modifies %run somewhat. So for this, we have both a normal test (below)
+ and a doctest (this one).
+
+ In [1]: import tempfile
+
+ In [2]: bid1 = id(__builtins__)
+
+ In [3]: fname = tempfile.mkstemp()[1]
+
+ In [3]: f = open(fname,'w')
+
+ In [4]: f.write('pass\\n')
+
+ In [5]: f.flush()
+
+ In [6]: print type(__builtins__)
+ <type 'module'>
+
+ In [7]: %run "$fname"
+
+ In [7]: f.close()
+
+ In [8]: bid2 = id(__builtins__)
+
+ In [9]: print type(__builtins__)
+ <type 'module'>
+
+ In [10]: bid1 == bid2
+ Out[10]: True
+
+ In [12]: try:
+ ....: os.unlink(fname)
+ ....: except:
+ ....: pass
+ ....:
+ """
+
+# For some tests, it will be handy to organize them in a class with a common
+# setup that makes a temp file
+
+class TestMagicRun(object):
+
+ def setup(self):
+ """Make a valid python temp file."""
+ fname = tempfile.mkstemp()[1]
+ f = open(fname,'w')
+ f.write('pass\n')
+ f.flush()
+ self.tmpfile = f
+ self.fname = fname
+
+ def run_tmpfile(self):
+ # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
+ # See below and ticket https://bugs.launchpad.net/bugs/366353
+ _ip.magic('run "%s"' % self.fname)
+
+ def test_builtins_id(self):
+ """Check that %run doesn't damage __builtins__ """
+
+ # Test that the id of __builtins__ is not modified by %run
+ bid1 = id(_ip.user_ns['__builtins__'])
+ self.run_tmpfile()
+ bid2 = id(_ip.user_ns['__builtins__'])
+ tt.assert_equals(bid1, bid2)
+
+ def test_builtins_type(self):
+ """Check that the type of __builtins__ doesn't change with %run.
+
+ However, the above could pass if __builtins__ was already modified to
+ be a dict (it should be a module) by a previous use of %run. So we
+ also check explicitly that it really is a module:
+ """
+ self.run_tmpfile()
+ tt.assert_equals(type(_ip.user_ns['__builtins__']),type(sys))
+
+ def test_prompts(self):
+ """Test that prompts correctly generate after %run"""
+ self.run_tmpfile()
+ p2 = str(_ip.IP.outputcache.prompt2).strip()
+ nt.assert_equals(p2[:3], '...')
+
+ def teardown(self):
+ self.tmpfile.close()
+ try:
+ os.unlink(self.fname)
+ except:
+ # On Windows, even though we close the file, we still can't delete
+ # it. I have no clue why
+ pass
+
+# Multiple tests for clipboard pasting
+def test_paste():
+
+ def paste(txt):
+ hooks.clipboard_get = lambda : txt
+ _ip.magic('paste')
+
+ # Inject fake clipboard hook but save original so we can restore it later
+ hooks = _ip.IP.hooks
+ user_ns = _ip.user_ns
+ original_clip = hooks.clipboard_get
+
+ try:
+ # This try/except with an emtpy except clause is here only because
+ # try/yield/finally is invalid syntax in Python 2.4. This will be
+ # removed when we drop 2.4-compatibility, and the emtpy except below
+ # will be changed to a finally.
+
+ # Run tests with fake clipboard function
+ user_ns.pop('x', None)
+ paste('x=1')
+ yield (nt.assert_equal, user_ns['x'], 1)
+
+ user_ns.pop('x', None)
+ paste('>>> x=2')
+ yield (nt.assert_equal, user_ns['x'], 2)
+
+ paste("""
+ >>> x = [1,2,3]
+ >>> y = []
+ >>> for i in x:
+ ... y.append(i**2)
+ ...
+ """)
+ yield (nt.assert_equal, user_ns['x'], [1,2,3])
+ yield (nt.assert_equal, user_ns['y'], [1,4,9])
+ except:
+ pass
+
+ # This should be in a finally clause, instead of the bare except above.
+ # Restore original hook
+ hooks.clipboard_get = original_clip
diff --git a/IPython/tests/test_platutils.py b/IPython/tests/test_platutils.py
new file mode 100644
index 0000000..36d189f
--- /dev/null
+++ b/IPython/tests/test_platutils.py
@@ -0,0 +1,59 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+Tests for platutils.py
+"""
+
+#-----------------------------------------------------------------------------
+# Copyright (C) 2008-2009 The IPython Development Team
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+
+import os
+import sys
+
+import nose.tools as nt
+
+from IPython.platutils import find_cmd, FindCmdError, get_long_path_name
+from IPython.testing import decorators as dec
+
+#-----------------------------------------------------------------------------
+# Tests
+#-----------------------------------------------------------------------------
+
+def test_find_cmd_python():
+ """Make sure we find sys.exectable for python."""
+ nt.assert_equals(find_cmd('python'), sys.executable)
+
+@dec.skip_win32
+def test_find_cmd():
+ """Make sure we can find the full path to ls."""
+ path = find_cmd('ls')
+ nt.assert_true(path.endswith('ls'))
+
+@dec.skip_if_not_win32
+def test_find_cmd():
+ """Try to find pythonw on Windows."""
+ path = find_cmd('pythonw')
+ nt.assert_true(path.endswith('pythonw.exe'))
+
+def test_find_cmd_fail():
+ """Make sure that FindCmdError is raised if we can't find the cmd."""
+ nt.assert_raises(FindCmdError,find_cmd,'asdfasdf')
+
+@dec.skip_if_not_win32
+def test_get_long_path_name_win32():
+ p = get_long_path_name('c:\\docume~1')
+ nt.assert_equals(p,u'c:\\Documents and Settings')
+
+@dec.skip_win32
+def test_get_long_path_name():
+ p = get_long_path_name('/usr/local')
+ nt.assert_equals(p,'/usr/local')
+
diff --git a/IPython/tools/__init__.py b/IPython/tools/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/IPython/tools/__init__.py
diff --git a/IPython/tools/growl.py b/IPython/tools/growl.py
new file mode 100644
index 0000000..cc4613c
--- /dev/null
+++ b/IPython/tools/growl.py
@@ -0,0 +1,49 @@
+#!/usr/bin/env python
+# encoding: utf-8
+
+
+class IPythonGrowlError(Exception):
+ pass
+
+class Notifier(object):
+
+ def __init__(self, app_name):
+ try:
+ import Growl
+ except ImportError:
+ self.g_notifier = None
+ else:
+ self.g_notifier = Growl.GrowlNotifier(app_name, ['kernel', 'core'])
+ self.g_notifier.register()
+
+ def _notify(self, title, msg):
+ if self.g_notifier is not None:
+ self.g_notifier.notify('kernel', title, msg)
+
+ def notify(self, title, msg):
+ self._notify(title, msg)
+
+ def notify_deferred(self, r, msg):
+ title = "Deferred Result"
+ msg = msg + '\n' + repr(r)
+ self._notify(title, msg)
+ return r
+
+_notifier = None
+
+def notify(title, msg):
+ pass
+
+def notify_deferred(r, msg):
+ return r
+
+def start(app_name):
+ global _notifier, notify, notify_deferred
+ if _notifier is not None:
+ raise IPythonGrowlError("this process is already registered with Growl")
+ else:
+ _notifier = Notifier(app_name)
+ notify = _notifier.notify
+ notify_deferred = _notifier.notify_deferred
+
+
diff --git a/IPython/tools/tests/__init__.py b/IPython/tools/tests/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/IPython/tools/tests/__init__.py
diff --git a/IPython/tools/tests/test_tools_utils.txt b/IPython/tools/tests/test_tools_utils.txt
new file mode 100644
index 0000000..60235bc
--- /dev/null
+++ b/IPython/tools/tests/test_tools_utils.txt
@@ -0,0 +1,17 @@
+=========================================
+ Doctests for the ``tools.utils`` module
+=========================================
+
+The way doctest loads these, the entire document is applied as a single test
+rather than multiple individual ones, unfortunately::
+
+ >>> from IPython.tools import utils
+
+ # Some other tests for utils
+
+ >>> utils.marquee('Testing marquee')
+ '****************************** Testing marquee ******************************'
+
+ >>> utils.marquee('Another test',30,'.')
+ '........ Another test ........'
+
diff --git a/IPython/tools/utils.py b/IPython/tools/utils.py
new file mode 100644
index 0000000..f34cf5a
--- /dev/null
+++ b/IPython/tools/utils.py
@@ -0,0 +1,128 @@
+# encoding: utf-8
+"""Generic utilities for use by IPython's various subsystems.
+"""
+
+__docformat__ = "restructuredtext en"
+
+#-------------------------------------------------------------------------------
+# Copyright (C) 2006 Fernando Perez <fperez@colorado.edu>
+# Brian E Granger <ellisonbg@gmail.com>
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#-------------------------------------------------------------------------------
+
+#---------------------------------------------------------------------------
+# Stdlib imports
+#---------------------------------------------------------------------------
+
+import os
+import sys
+
+#---------------------------------------------------------------------------
+# Other IPython utilities
+#---------------------------------------------------------------------------
+
+
+#---------------------------------------------------------------------------
+# Normal code begins
+#---------------------------------------------------------------------------
+
+def extractVars(*names,**kw):
+ """Extract a set of variables by name from another frame.
+
+ :Parameters:
+ - `*names`: strings
+ One or more variable names which will be extracted from the caller's
+ frame.
+
+ :Keywords:
+ - `depth`: integer (0)
+ How many frames in the stack to walk when looking for your variables.
+
+
+ Examples:
+
+ In [2]: def func(x):
+ ...: y = 1
+ ...: print extractVars('x','y')
+ ...:
+
+ In [3]: func('hello')
+ {'y': 1, 'x': 'hello'}
+ """
+
+ depth = kw.get('depth',0)
+
+ callerNS = sys._getframe(depth+1).f_locals
+ return dict((k,callerNS[k]) for k in names)
+
+
+def extractVarsAbove(*names):
+ """Extract a set of variables by name from another frame.
+
+ Similar to extractVars(), but with a specified depth of 1, so that names
+ are exctracted exactly from above the caller.
+
+ This is simply a convenience function so that the very common case (for us)
+ of skipping exactly 1 frame doesn't have to construct a special dict for
+ keyword passing."""
+
+ callerNS = sys._getframe(2).f_locals
+ return dict((k,callerNS[k]) for k in names)
+
+def shexp(s):
+ """Expand $VARS and ~names in a string, like a shell
+
+ :Examples:
+
+ In [2]: os.environ['FOO']='test'
+
+ In [3]: shexp('variable FOO is $FOO')
+ Out[3]: 'variable FOO is test'
+ """
+ return os.path.expandvars(os.path.expanduser(s))
+
+
+def list_strings(arg):
+ """Always return a list of strings, given a string or list of strings
+ as input.
+
+ :Examples:
+
+ In [7]: list_strings('A single string')
+ Out[7]: ['A single string']
+
+ In [8]: list_strings(['A single string in a list'])
+ Out[8]: ['A single string in a list']
+
+ In [9]: list_strings(['A','list','of','strings'])
+ Out[9]: ['A', 'list', 'of', 'strings']
+ """
+
+ if isinstance(arg,basestring): return [arg]
+ else: return arg
+
+def marquee(txt='',width=78,mark='*'):
+ """Return the input string centered in a 'marquee'.
+
+ :Examples:
+
+ In [16]: marquee('A test',40)
+ Out[16]: '**************** A test ****************'
+
+ In [17]: marquee('A test',40,'-')
+ Out[17]: '---------------- A test ----------------'
+
+ In [18]: marquee('A test',40,' ')
+ Out[18]: ' A test '
+
+ """
+ if not txt:
+ return (mark*width)[:width]
+ nmark = (width-len(txt)-2)/len(mark)/2
+ if nmark < 0: nmark =0
+ marks = mark*nmark
+ return '%s %s %s' % (marks,txt,marks)
+
+
diff --git a/IPython/twshell.py b/IPython/twshell.py
new file mode 100644
index 0000000..1b750ed
--- /dev/null
+++ b/IPython/twshell.py
@@ -0,0 +1,285 @@
+"""Twisted shell support.
+
+XXX - This module is missing proper docs.
+"""
+# Tell nose to skip this module
+__test__ = {}
+
+import sys
+
+from twisted.internet import reactor, threads
+
+from IPython.ipmaker import make_IPython
+from IPython.iplib import InteractiveShell
+from IPython.ipstruct import Struct
+import Queue,thread,threading,signal
+from signal import signal, SIGINT
+from IPython.genutils import Term,warn,error,flag_calls, ask_yes_no
+import shellglobals
+
+def install_gtk2():
+ """ Install gtk2 reactor, needs to be called bef """
+ from twisted.internet import gtk2reactor
+ gtk2reactor.install()
+
+
+def hijack_reactor():
+ """Modifies Twisted's reactor with a dummy so user code does
+ not block IPython. This function returns the original
+ 'twisted.internet.reactor' that has been hijacked.
+
+ NOTE: Make sure you call this *AFTER* you've installed
+ the reactor of your choice.
+ """
+ from twisted import internet
+ orig_reactor = internet.reactor
+
+ class DummyReactor(object):
+ def run(self):
+ pass
+ def __getattr__(self, name):
+ return getattr(orig_reactor, name)
+ def __setattr__(self, name, value):
+ return setattr(orig_reactor, name, value)
+
+ internet.reactor = DummyReactor()
+ return orig_reactor
+
+class TwistedInteractiveShell(InteractiveShell):
+ """Simple multi-threaded shell."""
+
+ # Threading strategy taken from:
+ # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/65109, by Brian
+ # McErlean and John Finlay. Modified with corrections by Antoon Pardon,
+ # from the pygtk mailing list, to avoid lockups with system calls.
+
+ # class attribute to indicate whether the class supports threads or not.
+ # Subclasses with thread support should override this as needed.
+ isthreaded = True
+
+ def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
+ user_ns=None,user_global_ns=None,banner2='',**kw):
+ """Similar to the normal InteractiveShell, but with threading control"""
+
+ InteractiveShell.__init__(self,name,usage,rc,user_ns,
+ user_global_ns,banner2)
+
+
+ # A queue to hold the code to be executed.
+ self.code_queue = Queue.Queue()
+
+ # Stuff to do at closing time
+ self._kill = None
+ on_kill = kw.get('on_kill', [])
+ # Check that all things to kill are callable:
+ for t in on_kill:
+ if not callable(t):
+ raise TypeError,'on_kill must be a list of callables'
+ self.on_kill = on_kill
+ # thread identity of the "worker thread" (that may execute code directly)
+ self.worker_ident = None
+ self.reactor_started = False
+ self.first_run = True
+
+ def runsource(self, source, filename="<input>", symbol="single"):
+ """Compile and run some source in the interpreter.
+
+ Modified version of code.py's runsource(), to handle threading issues.
+ See the original for full docstring details."""
+
+ # If Ctrl-C was typed, we reset the flag and return right away
+ if shellglobals.KBINT:
+ shellglobals.KBINT = False
+ return False
+
+ if self._kill:
+ # can't queue new code if we are being killed
+ return True
+
+ try:
+ code = self.compile(source, filename, symbol)
+ except (OverflowError, SyntaxError, ValueError):
+ # Case 1
+ self.showsyntaxerror(filename)
+ return False
+
+ if code is None:
+ # Case 2
+ return True
+
+ # shortcut - if we are in worker thread, or the worker thread is not running,
+ # execute directly (to allow recursion and prevent deadlock if code is run early
+ # in IPython construction)
+
+ if (not self.reactor_started or (self.worker_ident is None and not self.first_run)
+ or self.worker_ident == thread.get_ident() or shellglobals.run_in_frontend(source)):
+ InteractiveShell.runcode(self,code)
+ return
+
+ # Case 3
+ # Store code in queue, so the execution thread can handle it.
+
+ self.first_run = False
+ completed_ev, received_ev = threading.Event(), threading.Event()
+
+ self.code_queue.put((code,completed_ev, received_ev))
+
+ reactor.callLater(0.0,self.runcode)
+ received_ev.wait(5)
+ if not received_ev.isSet():
+ # the mainloop is dead, start executing code directly
+ print "Warning: Timeout for mainloop thread exceeded"
+ print "switching to nonthreaded mode (until mainloop wakes up again)"
+ self.worker_ident = None
+ else:
+ completed_ev.wait()
+
+ return False
+
+ def runcode(self):
+ """Execute a code object.
+
+ Multithreaded wrapper around IPython's runcode()."""
+
+
+ # we are in worker thread, stash out the id for runsource()
+ self.worker_ident = thread.get_ident()
+
+ if self._kill:
+ print >>Term.cout, 'Closing threads...',
+ Term.cout.flush()
+ for tokill in self.on_kill:
+ tokill()
+ print >>Term.cout, 'Done.'
+ # allow kill() to return
+ self._kill.set()
+ return True
+
+ # Install SIGINT handler. We do it every time to ensure that if user
+ # code modifies it, we restore our own handling.
+ try:
+ pass
+ signal(SIGINT,shellglobals.sigint_handler)
+ except SystemError:
+ # This happens under Windows, which seems to have all sorts
+ # of problems with signal handling. Oh well...
+ pass
+
+ # Flush queue of pending code by calling the run methood of the parent
+ # class with all items which may be in the queue.
+ code_to_run = None
+ while 1:
+ try:
+ code_to_run, completed_ev, received_ev = self.code_queue.get_nowait()
+ except Queue.Empty:
+ break
+ received_ev.set()
+
+
+ # Exceptions need to be raised differently depending on which
+ # thread is active. This convoluted try/except is only there to
+ # protect against asynchronous exceptions, to ensure that a shellglobals.KBINT
+ # at the wrong time doesn't deadlock everything. The global
+ # CODE_TO_RUN is set to true/false as close as possible to the
+ # runcode() call, so that the KBINT handler is correctly informed.
+ try:
+ try:
+ shellglobals.CODE_RUN = True
+ InteractiveShell.runcode(self,code_to_run)
+ except KeyboardInterrupt:
+ print "Keyboard interrupted in mainloop"
+ while not self.code_queue.empty():
+ code = self.code_queue.get_nowait()
+ break
+ finally:
+ shellglobals.CODE_RUN = False
+ # allow runsource() return from wait
+ completed_ev.set()
+
+ # This MUST return true for gtk threading to work
+ return True
+
+ def kill(self):
+ """Kill the thread, returning when it has been shut down."""
+ self._kill = threading.Event()
+ reactor.callLater(0.0,self.runcode)
+ self._kill.wait()
+
+
+
+class IPShellTwisted:
+ """Run a Twisted reactor while in an IPython session.
+
+ Python commands can be passed to the thread where they will be
+ executed. This is implemented by periodically checking for
+ passed code using a Twisted reactor callback.
+ """
+
+ TIMEOUT = 0.01 # Millisecond interval between reactor runs.
+
+ def __init__(self, argv=None, user_ns=None, debug=1,
+ shell_class=TwistedInteractiveShell):
+
+ from twisted.internet import reactor
+ self.reactor = hijack_reactor()
+
+ mainquit = self.reactor.stop
+
+ # Make sure IPython keeps going after reactor stop.
+ def reactorstop():
+ pass
+ self.reactor.stop = reactorstop
+ reactorrun_orig = self.reactor.run
+ self.quitting = False
+ def reactorrun():
+ while True and not self.quitting:
+ reactorrun_orig()
+ self.reactor.run = reactorrun
+
+ self.IP = make_IPython(argv, user_ns=user_ns, debug=debug,
+ shell_class=shell_class,
+ on_kill=[mainquit])
+
+ # threading.Thread.__init__(self)
+
+ def run(self):
+ self.IP.mainloop()
+ self.quitting = True
+ self.IP.kill()
+
+ def mainloop(self):
+ def mainLoopThreadDeath(r):
+ print "mainLoopThreadDeath: ", str(r)
+ def spawnMainloopThread():
+ d=threads.deferToThread(self.run)
+ d.addBoth(mainLoopThreadDeath)
+ reactor.callWhenRunning(spawnMainloopThread)
+ self.IP.reactor_started = True
+ self.reactor.run()
+ print "mainloop ending...."
+
+exists = True
+
+
+if __name__ == '__main__':
+ # Sample usage.
+
+ # Create the shell object. This steals twisted.internet.reactor
+ # for its own purposes, to make sure you've already installed a
+ # reactor of your choice.
+ shell = IPShellTwisted(
+ argv=[],
+ user_ns={'__name__': '__example__',
+ 'hello': 'world',
+ },
+ )
+
+ # Run the mainloop. This runs the actual reactor.run() method.
+ # The twisted.internet.reactor object at this point is a dummy
+ # object that passes through to the actual reactor, but prevents
+ # run() from being called on it again.
+ shell.mainloop()
+
+ # You must exit IPython to terminate your program.
+ print 'Goodbye!'
+
diff --git a/IPython/ultraTB.py b/IPython/ultraTB.py
new file mode 100644
index 0000000..36f09cf
--- /dev/null
+++ b/IPython/ultraTB.py
@@ -0,0 +1,1061 @@
+# -*- coding: utf-8 -*-
+"""
+ultraTB.py -- Spice up your tracebacks!
+
+* ColorTB
+I've always found it a bit hard to visually parse tracebacks in Python. The
+ColorTB class is a solution to that problem. It colors the different parts of a
+traceback in a manner similar to what you would expect from a syntax-highlighting
+text editor.
+
+Installation instructions for ColorTB:
+ import sys,ultraTB
+ sys.excepthook = ultraTB.ColorTB()
+
+* VerboseTB
+I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
+of useful info when a traceback occurs. Ping originally had it spit out HTML
+and intended it for CGI programmers, but why should they have all the fun? I
+altered it to spit out colored text to the terminal. It's a bit overwhelming,
+but kind of neat, and maybe useful for long-running programs that you believe
+are bug-free. If a crash *does* occur in that type of program you want details.
+Give it a shot--you'll love it or you'll hate it.
+
+Note:
+
+ The Verbose mode prints the variables currently visible where the exception
+ happened (shortening their strings if too long). This can potentially be
+ very slow, if you happen to have a huge data structure whose string
+ representation is complex to compute. Your computer may appear to freeze for
+ a while with cpu usage at 100%. If this occurs, you can cancel the traceback
+ with Ctrl-C (maybe hitting it more than once).
+
+ If you encounter this kind of situation often, you may want to use the
+ Verbose_novars mode instead of the regular Verbose, which avoids formatting
+ variables (but otherwise includes the information and context given by
+ Verbose).
+
+
+Installation instructions for ColorTB:
+ import sys,ultraTB
+ sys.excepthook = ultraTB.VerboseTB()
+
+Note: Much of the code in this module was lifted verbatim from the standard
+library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
+
+* Color schemes
+The colors are defined in the class TBTools through the use of the
+ColorSchemeTable class. Currently the following exist:
+
+ - NoColor: allows all of this module to be used in any terminal (the color
+ escapes are just dummy blank strings).
+
+ - Linux: is meant to look good in a terminal like the Linux console (black
+ or very dark background).
+
+ - LightBG: similar to Linux but swaps dark/light colors to be more readable
+ in light background terminals.
+
+You can implement other color schemes easily, the syntax is fairly
+self-explanatory. Please send back new schemes you develop to the author for
+possible inclusion in future releases.
+"""
+
+#*****************************************************************************
+# Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
+# Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#*****************************************************************************
+
+# Required modules
+import inspect
+import keyword
+import linecache
+import os
+import pydoc
+import re
+import string
+import sys
+import time
+import tokenize
+import traceback
+import types
+
+# For purposes of monkeypatching inspect to fix a bug in it.
+from inspect import getsourcefile, getfile, getmodule,\
+ ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode
+
+
+# IPython's own modules
+# Modified pdb which doesn't damage IPython's readline handling
+from IPython import Debugger, PyColorize, ipapi
+from IPython.ipstruct import Struct
+from IPython.excolors import exception_colors
+from IPython.genutils import Term,uniq_stable,error,info
+
+# Globals
+# amount of space to put line numbers before verbose tracebacks
+INDENT_SIZE = 8
+
+# Default color scheme. This is used, for example, by the traceback
+# formatter. When running in an actual IPython instance, the user's rc.colors
+# value is used, but havinga module global makes this functionality available
+# to users of ultraTB who are NOT running inside ipython.
+DEFAULT_SCHEME = 'NoColor'
+
+#---------------------------------------------------------------------------
+# Code begins
+
+# Utility functions
+def inspect_error():
+ """Print a message about internal inspect errors.
+
+ These are unfortunately quite common."""
+
+ error('Internal Python error in the inspect module.\n'
+ 'Below is the traceback from this internal error.\n')
+
+
+def findsource(object):
+ """Return the entire source file and starting line number for an object.
+
+ The argument may be a module, class, method, function, traceback, frame,
+ or code object. The source code is returned as a list of all the lines
+ in the file and the line number indexes a line in that list. An IOError
+ is raised if the source code cannot be retrieved.
+
+ FIXED version with which we monkeypatch the stdlib to work around a bug."""
+
+ file = getsourcefile(object) or getfile(object)
+ # If the object is a frame, then trying to get the globals dict from its
+ # module won't work. Instead, the frame object itself has the globals
+ # dictionary.
+ globals_dict = None
+ if inspect.isframe(object):
+ # XXX: can this ever be false?
+ globals_dict = object.f_globals
+ else:
+ module = getmodule(object, file)
+ if module:
+ globals_dict = module.__dict__
+ lines = linecache.getlines(file, globals_dict)
+ if not lines:
+ raise IOError('could not get source code')
+
+ if ismodule(object):
+ return lines, 0
+
+ if isclass(object):
+ name = object.__name__
+ pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
+ # make some effort to find the best matching class definition:
+ # use the one with the least indentation, which is the one
+ # that's most probably not inside a function definition.
+ candidates = []
+ for i in range(len(lines)):
+ match = pat.match(lines[i])
+ if match:
+ # if it's at toplevel, it's already the best one
+ if lines[i][0] == 'c':
+ return lines, i
+ # else add whitespace to candidate list
+ candidates.append((match.group(1), i))
+ if candidates:
+ # this will sort by whitespace, and by line number,
+ # less whitespace first
+ candidates.sort()
+ return lines, candidates[0][1]
+ else:
+ raise IOError('could not find class definition')
+
+ if ismethod(object):
+ object = object.im_func
+ if isfunction(object):
+ object = object.func_code
+ if istraceback(object):
+ object = object.tb_frame
+ if isframe(object):
+ object = object.f_code
+ if iscode(object):
+ if not hasattr(object, 'co_firstlineno'):
+ raise IOError('could not find function definition')
+ pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
+ pmatch = pat.match
+ # fperez - fix: sometimes, co_firstlineno can give a number larger than
+ # the length of lines, which causes an error. Safeguard against that.
+ lnum = min(object.co_firstlineno,len(lines))-1
+ while lnum > 0:
+ if pmatch(lines[lnum]): break
+ lnum -= 1
+
+ return lines, lnum
+ raise IOError('could not find code object')
+
+# Monkeypatch inspect to apply our bugfix. This code only works with py25
+if sys.version_info[:2] >= (2,5):
+ inspect.findsource = findsource
+
+def fix_frame_records_filenames(records):
+ """Try to fix the filenames in each record from inspect.getinnerframes().
+
+ Particularly, modules loaded from within zip files have useless filenames
+ attached to their code object, and inspect.getinnerframes() just uses it.
+ """
+ fixed_records = []
+ for frame, filename, line_no, func_name, lines, index in records:
+ # Look inside the frame's globals dictionary for __file__, which should
+ # be better.
+ better_fn = frame.f_globals.get('__file__', None)
+ if isinstance(better_fn, str):
+ # Check the type just in case someone did something weird with
+ # __file__. It might also be None if the error occurred during
+ # import.
+ filename = better_fn
+ fixed_records.append((frame, filename, line_no, func_name, lines, index))
+ return fixed_records
+
+
+def _fixed_getinnerframes(etb, context=1,tb_offset=0):
+ import linecache
+ LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
+
+ records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
+
+ # If the error is at the console, don't build any context, since it would
+ # otherwise produce 5 blank lines printed out (there is no file at the
+ # console)
+ rec_check = records[tb_offset:]
+ try:
+ rname = rec_check[0][1]
+ if rname == '<ipython console>' or rname.endswith('<string>'):
+ return rec_check
+ except IndexError:
+ pass
+
+ aux = traceback.extract_tb(etb)
+ assert len(records) == len(aux)
+ for i, (file, lnum, _, _) in zip(range(len(records)), aux):
+ maybeStart = lnum-1 - context//2
+ start = max(maybeStart, 0)
+ end = start + context
+ lines = linecache.getlines(file)[start:end]
+ # pad with empty lines if necessary
+ if maybeStart < 0:
+ lines = (['\n'] * -maybeStart) + lines
+ if len(lines) < context:
+ lines += ['\n'] * (context - len(lines))
+ buf = list(records[i])
+ buf[LNUM_POS] = lnum
+ buf[INDEX_POS] = lnum - 1 - start
+ buf[LINES_POS] = lines
+ records[i] = tuple(buf)
+ return records[tb_offset:]
+
+# Helper function -- largely belongs to VerboseTB, but we need the same
+# functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
+# can be recognized properly by ipython.el's py-traceback-line-re
+# (SyntaxErrors have to be treated specially because they have no traceback)
+
+_parser = PyColorize.Parser()
+
+def _formatTracebackLines(lnum, index, lines, Colors, lvals=None,scheme=None):
+ numbers_width = INDENT_SIZE - 1
+ res = []
+ i = lnum - index
+
+ # This lets us get fully syntax-highlighted tracebacks.
+ if scheme is None:
+ ipinst = ipapi.get()
+ if ipinst is not None:
+ scheme = ipinst.IP.rc.colors
+ else:
+ scheme = DEFAULT_SCHEME
+ _line_format = _parser.format2
+
+ for line in lines:
+ new_line, err = _line_format(line,'str',scheme)
+ if not err: line = new_line
+
+ if i == lnum:
+ # This is the line with the error
+ pad = numbers_width - len(str(i))
+ if pad >= 3:
+ marker = '-'*(pad-3) + '-> '
+ elif pad == 2:
+ marker = '> '
+ elif pad == 1:
+ marker = '>'
+ else:
+ marker = ''
+ num = marker + str(i)
+ line = '%s%s%s %s%s' %(Colors.linenoEm, num,
+ Colors.line, line, Colors.Normal)
+ else:
+ num = '%*s' % (numbers_width,i)
+ line = '%s%s%s %s' %(Colors.lineno, num,
+ Colors.Normal, line)
+
+ res.append(line)
+ if lvals and i == lnum:
+ res.append(lvals + '\n')
+ i = i + 1
+ return res
+
+
+#---------------------------------------------------------------------------
+# Module classes
+class TBTools:
+ """Basic tools used by all traceback printer classes."""
+
+ def __init__(self,color_scheme = 'NoColor',call_pdb=False):
+ # Whether to call the interactive pdb debugger after printing
+ # tracebacks or not
+ self.call_pdb = call_pdb
+
+ # Create color table
+ self.color_scheme_table = exception_colors()
+
+ self.set_colors(color_scheme)
+ self.old_scheme = color_scheme # save initial value for toggles
+
+ if call_pdb:
+ self.pdb = Debugger.Pdb(self.color_scheme_table.active_scheme_name)
+ else:
+ self.pdb = None
+
+ def set_colors(self,*args,**kw):
+ """Shorthand access to the color table scheme selector method."""
+
+ # Set own color table
+ self.color_scheme_table.set_active_scheme(*args,**kw)
+ # for convenience, set Colors to the active scheme
+ self.Colors = self.color_scheme_table.active_colors
+ # Also set colors of debugger
+ if hasattr(self,'pdb') and self.pdb is not None:
+ self.pdb.set_colors(*args,**kw)
+
+ def color_toggle(self):
+ """Toggle between the currently active color scheme and NoColor."""
+
+ if self.color_scheme_table.active_scheme_name == 'NoColor':
+ self.color_scheme_table.set_active_scheme(self.old_scheme)
+ self.Colors = self.color_scheme_table.active_colors
+ else:
+ self.old_scheme = self.color_scheme_table.active_scheme_name
+ self.color_scheme_table.set_active_scheme('NoColor')
+ self.Colors = self.color_scheme_table.active_colors
+
+#---------------------------------------------------------------------------
+class ListTB(TBTools):
+ """Print traceback information from a traceback list, with optional color.
+
+ Calling: requires 3 arguments:
+ (etype, evalue, elist)
+ as would be obtained by:
+ etype, evalue, tb = sys.exc_info()
+ if tb:
+ elist = traceback.extract_tb(tb)
+ else:
+ elist = None
+
+ It can thus be used by programs which need to process the traceback before
+ printing (such as console replacements based on the code module from the
+ standard library).
+
+ Because they are meant to be called without a full traceback (only a
+ list), instances of this class can't call the interactive pdb debugger."""
+
+ def __init__(self,color_scheme = 'NoColor'):
+ TBTools.__init__(self,color_scheme = color_scheme,call_pdb=0)
+
+ def __call__(self, etype, value, elist):
+ Term.cout.flush()
+ print >> Term.cerr, self.text(etype,value,elist)
+ Term.cerr.flush()
+
+ def text(self,etype, value, elist,context=5):
+ """Return a color formatted string with the traceback info."""
+
+ Colors = self.Colors
+ out_string = ['%s%s%s\n' % (Colors.topline,'-'*60,Colors.Normal)]
+ if elist:
+ out_string.append('Traceback %s(most recent call last)%s:' % \
+ (Colors.normalEm, Colors.Normal) + '\n')
+ out_string.extend(self._format_list(elist))
+ lines = self._format_exception_only(etype, value)
+ for line in lines[:-1]:
+ out_string.append(" "+line)
+ out_string.append(lines[-1])
+ return ''.join(out_string)
+
+ def _format_list(self, extracted_list):
+ """Format a list of traceback entry tuples for printing.
+
+ Given a list of tuples as returned by extract_tb() or
+ extract_stack(), return a list of strings ready for printing.
+ Each string in the resulting list corresponds to the item with the
+ same index in the argument list. Each string ends in a newline;
+ the strings may contain internal newlines as well, for those items
+ whose source text line is not None.
+
+ Lifted almost verbatim from traceback.py
+ """
+
+ Colors = self.Colors
+ list = []
+ for filename, lineno, name, line in extracted_list[:-1]:
+ item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
+ (Colors.filename, filename, Colors.Normal,
+ Colors.lineno, lineno, Colors.Normal,
+ Colors.name, name, Colors.Normal)
+ if line:
+ item = item + ' %s\n' % line.strip()
+ list.append(item)
+ # Emphasize the last entry
+ filename, lineno, name, line = extracted_list[-1]
+ item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
+ (Colors.normalEm,
+ Colors.filenameEm, filename, Colors.normalEm,
+ Colors.linenoEm, lineno, Colors.normalEm,
+ Colors.nameEm, name, Colors.normalEm,
+ Colors.Normal)
+ if line:
+ item = item + '%s %s%s\n' % (Colors.line, line.strip(),
+ Colors.Normal)
+ list.append(item)
+ return list
+
+ def _format_exception_only(self, etype, value):
+ """Format the exception part of a traceback.
+
+ The arguments are the exception type and value such as given by
+ sys.exc_info()[:2]. The return value is a list of strings, each ending
+ in a newline. Normally, the list contains a single string; however,
+ for SyntaxError exceptions, it contains several lines that (when
+ printed) display detailed information about where the syntax error
+ occurred. The message indicating which exception occurred is the
+ always last string in the list.
+
+ Also lifted nearly verbatim from traceback.py
+ """
+
+ have_filedata = False
+ Colors = self.Colors
+ list = []
+ try:
+ stype = Colors.excName + etype.__name__ + Colors.Normal
+ except AttributeError:
+ stype = etype # String exceptions don't get special coloring
+ if value is None:
+ list.append( str(stype) + '\n')
+ else:
+ if etype is SyntaxError:
+ try:
+ msg, (filename, lineno, offset, line) = value
+ except:
+ have_filedata = False
+ else:
+ have_filedata = True
+ #print 'filename is',filename # dbg
+ if not filename: filename = "<string>"
+ list.append('%s File %s"%s"%s, line %s%d%s\n' % \
+ (Colors.normalEm,
+ Colors.filenameEm, filename, Colors.normalEm,
+ Colors.linenoEm, lineno, Colors.Normal ))
+ if line is not None:
+ i = 0
+ while i < len(line) and line[i].isspace():
+ i = i+1
+ list.append('%s %s%s\n' % (Colors.line,
+ line.strip(),
+ Colors.Normal))
+ if offset is not None:
+ s = ' '
+ for c in line[i:offset-1]:
+ if c.isspace():
+ s = s + c
+ else:
+ s = s + ' '
+ list.append('%s%s^%s\n' % (Colors.caret, s,
+ Colors.Normal) )
+ value = msg
+ s = self._some_str(value)
+ if s:
+ list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
+ Colors.Normal, s))
+ else:
+ list.append('%s\n' % str(stype))
+
+ # vds:>>
+ if have_filedata:
+ ipinst = ipapi.get()
+ if ipinst is not None:
+ ipinst.IP.hooks.synchronize_with_editor(filename, lineno, 0)
+ # vds:<<
+
+ return list
+
+ def _some_str(self, value):
+ # Lifted from traceback.py
+ try:
+ return str(value)
+ except:
+ return '<unprintable %s object>' % type(value).__name__
+
+#----------------------------------------------------------------------------
+class VerboseTB(TBTools):
+ """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
+ of HTML. Requires inspect and pydoc. Crazy, man.
+
+ Modified version which optionally strips the topmost entries from the
+ traceback, to be used with alternate interpreters (because their own code
+ would appear in the traceback)."""
+
+ def __init__(self,color_scheme = 'Linux',tb_offset=0,long_header=0,
+ call_pdb = 0, include_vars=1):
+ """Specify traceback offset, headers and color scheme.
+
+ Define how many frames to drop from the tracebacks. Calling it with
+ tb_offset=1 allows use of this handler in interpreters which will have
+ their own code at the top of the traceback (VerboseTB will first
+ remove that frame before printing the traceback info)."""
+ TBTools.__init__(self,color_scheme=color_scheme,call_pdb=call_pdb)
+ self.tb_offset = tb_offset
+ self.long_header = long_header
+ self.include_vars = include_vars
+
+ def text(self, etype, evalue, etb, context=5):
+ """Return a nice text document describing the traceback."""
+
+ # some locals
+ try:
+ etype = etype.__name__
+ except AttributeError:
+ pass
+ Colors = self.Colors # just a shorthand + quicker name lookup
+ ColorsNormal = Colors.Normal # used a lot
+ col_scheme = self.color_scheme_table.active_scheme_name
+ indent = ' '*INDENT_SIZE
+ em_normal = '%s\n%s%s' % (Colors.valEm, indent,ColorsNormal)
+ undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
+ exc = '%s%s%s' % (Colors.excName,etype,ColorsNormal)
+
+ # some internal-use functions
+ def text_repr(value):
+ """Hopefully pretty robust repr equivalent."""
+ # this is pretty horrible but should always return *something*
+ try:
+ return pydoc.text.repr(value)
+ except KeyboardInterrupt:
+ raise
+ except:
+ try:
+ return repr(value)
+ except KeyboardInterrupt:
+ raise
+ except:
+ try:
+ # all still in an except block so we catch
+ # getattr raising
+ name = getattr(value, '__name__', None)
+ if name:
+ # ick, recursion
+ return text_repr(name)
+ klass = getattr(value, '__class__', None)
+ if klass:
+ return '%s instance' % text_repr(klass)
+ except KeyboardInterrupt:
+ raise
+ except:
+ return 'UNRECOVERABLE REPR FAILURE'
+ def eqrepr(value, repr=text_repr): return '=%s' % repr(value)
+ def nullrepr(value, repr=text_repr): return ''
+
+ # meat of the code begins
+ try:
+ etype = etype.__name__
+ except AttributeError:
+ pass
+
+ if self.long_header:
+ # Header with the exception type, python version, and date
+ pyver = 'Python ' + string.split(sys.version)[0] + ': ' + sys.executable
+ date = time.ctime(time.time())
+
+ head = '%s%s%s\n%s%s%s\n%s' % (Colors.topline, '-'*75, ColorsNormal,
+ exc, ' '*(75-len(str(etype))-len(pyver)),
+ pyver, string.rjust(date, 75) )
+ head += "\nA problem occured executing Python code. Here is the sequence of function"\
+ "\ncalls leading up to the error, with the most recent (innermost) call last."
+ else:
+ # Simplified header
+ head = '%s%s%s\n%s%s' % (Colors.topline, '-'*75, ColorsNormal,exc,
+ string.rjust('Traceback (most recent call last)',
+ 75 - len(str(etype)) ) )
+ frames = []
+ # Flush cache before calling inspect. This helps alleviate some of the
+ # problems with python 2.3's inspect.py.
+ linecache.checkcache()
+ # Drop topmost frames if requested
+ try:
+ # Try the default getinnerframes and Alex's: Alex's fixes some
+ # problems, but it generates empty tracebacks for console errors
+ # (5 blanks lines) where none should be returned.
+ #records = inspect.getinnerframes(etb, context)[self.tb_offset:]
+ #print 'python records:', records # dbg
+ records = _fixed_getinnerframes(etb, context,self.tb_offset)
+ #print 'alex records:', records # dbg
+ except:
+
+ # FIXME: I've been getting many crash reports from python 2.3
+ # users, traceable to inspect.py. If I can find a small test-case
+ # to reproduce this, I should either write a better workaround or
+ # file a bug report against inspect (if that's the real problem).
+ # So far, I haven't been able to find an isolated example to
+ # reproduce the problem.
+ inspect_error()
+ traceback.print_exc(file=Term.cerr)
+ info('\nUnfortunately, your original traceback can not be constructed.\n')
+ return ''
+
+ # build some color string templates outside these nested loops
+ tpl_link = '%s%%s%s' % (Colors.filenameEm,ColorsNormal)
+ tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
+ ColorsNormal)
+ tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
+ (Colors.vName, Colors.valEm, ColorsNormal)
+ tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
+ tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
+ Colors.vName, ColorsNormal)
+ tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
+ tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
+ tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm,Colors.line,
+ ColorsNormal)
+
+ # now, loop over all records printing context and info
+ abspath = os.path.abspath
+ for frame, file, lnum, func, lines, index in records:
+ #print '*** record:',file,lnum,func,lines,index # dbg
+ try:
+ file = file and abspath(file) or '?'
+ except OSError:
+ # if file is '<console>' or something not in the filesystem,
+ # the abspath call will throw an OSError. Just ignore it and
+ # keep the original file string.
+ pass
+ link = tpl_link % file
+ try:
+ args, varargs, varkw, locals = inspect.getargvalues(frame)
+ except:
+ # This can happen due to a bug in python2.3. We should be
+ # able to remove this try/except when 2.4 becomes a
+ # requirement. Bug details at http://python.org/sf/1005466
+ inspect_error()
+ traceback.print_exc(file=Term.cerr)
+ info("\nIPython's exception reporting continues...\n")
+
+ if func == '?':
+ call = ''
+ else:
+ # Decide whether to include variable details or not
+ var_repr = self.include_vars and eqrepr or nullrepr
+ try:
+ call = tpl_call % (func,inspect.formatargvalues(args,
+ varargs, varkw,
+ locals,formatvalue=var_repr))
+ except KeyError:
+ # Very odd crash from inspect.formatargvalues(). The
+ # scenario under which it appeared was a call to
+ # view(array,scale) in NumTut.view.view(), where scale had
+ # been defined as a scalar (it should be a tuple). Somehow
+ # inspect messes up resolving the argument list of view()
+ # and barfs out. At some point I should dig into this one
+ # and file a bug report about it.
+ inspect_error()
+ traceback.print_exc(file=Term.cerr)
+ info("\nIPython's exception reporting continues...\n")
+ call = tpl_call_fail % func
+
+ # Initialize a list of names on the current line, which the
+ # tokenizer below will populate.
+ names = []
+
+ def tokeneater(token_type, token, start, end, line):
+ """Stateful tokeneater which builds dotted names.
+
+ The list of names it appends to (from the enclosing scope) can
+ contain repeated composite names. This is unavoidable, since
+ there is no way to disambguate partial dotted structures until
+ the full list is known. The caller is responsible for pruning
+ the final list of duplicates before using it."""
+
+ # build composite names
+ if token == '.':
+ try:
+ names[-1] += '.'
+ # store state so the next token is added for x.y.z names
+ tokeneater.name_cont = True
+ return
+ except IndexError:
+ pass
+ if token_type == tokenize.NAME and token not in keyword.kwlist:
+ if tokeneater.name_cont:
+ # Dotted names
+ names[-1] += token
+ tokeneater.name_cont = False
+ else:
+ # Regular new names. We append everything, the caller
+ # will be responsible for pruning the list later. It's
+ # very tricky to try to prune as we go, b/c composite
+ # names can fool us. The pruning at the end is easy
+ # to do (or the caller can print a list with repeated
+ # names if so desired.
+ names.append(token)
+ elif token_type == tokenize.NEWLINE:
+ raise IndexError
+ # we need to store a bit of state in the tokenizer to build
+ # dotted names
+ tokeneater.name_cont = False
+
+ def linereader(file=file, lnum=[lnum], getline=linecache.getline):
+ line = getline(file, lnum[0])
+ lnum[0] += 1
+ return line
+
+ # Build the list of names on this line of code where the exception
+ # occurred.
+ try:
+ # This builds the names list in-place by capturing it from the
+ # enclosing scope.
+ tokenize.tokenize(linereader, tokeneater)
+ except IndexError:
+ # signals exit of tokenizer
+ pass
+ except tokenize.TokenError,msg:
+ _m = ("An unexpected error occurred while tokenizing input\n"
+ "The following traceback may be corrupted or invalid\n"
+ "The error message is: %s\n" % msg)
+ error(_m)
+
+ # prune names list of duplicates, but keep the right order
+ unique_names = uniq_stable(names)
+
+ # Start loop over vars
+ lvals = []
+ if self.include_vars:
+ for name_full in unique_names:
+ name_base = name_full.split('.',1)[0]
+ if name_base in frame.f_code.co_varnames:
+ if locals.has_key(name_base):
+ try:
+ value = repr(eval(name_full,locals))
+ except:
+ value = undefined
+ else:
+ value = undefined
+ name = tpl_local_var % name_full
+ else:
+ if frame.f_globals.has_key(name_base):
+ try:
+ value = repr(eval(name_full,frame.f_globals))
+ except:
+ value = undefined
+ else:
+ value = undefined
+ name = tpl_global_var % name_full
+ lvals.append(tpl_name_val % (name,value))
+ if lvals:
+ lvals = '%s%s' % (indent,em_normal.join(lvals))
+ else:
+ lvals = ''
+
+ level = '%s %s\n' % (link,call)
+
+ if index is None:
+ frames.append(level)
+ else:
+ frames.append('%s%s' % (level,''.join(
+ _formatTracebackLines(lnum,index,lines,Colors,lvals,
+ col_scheme))))
+
+ # Get (safely) a string form of the exception info
+ try:
+ etype_str,evalue_str = map(str,(etype,evalue))
+ except:
+ # User exception is improperly defined.
+ etype,evalue = str,sys.exc_info()[:2]
+ etype_str,evalue_str = map(str,(etype,evalue))
+ # ... and format it
+ exception = ['%s%s%s: %s' % (Colors.excName, etype_str,
+ ColorsNormal, evalue_str)]
+ if type(evalue) is types.InstanceType:
+ try:
+ names = [w for w in dir(evalue) if isinstance(w, basestring)]
+ except:
+ # Every now and then, an object with funny inernals blows up
+ # when dir() is called on it. We do the best we can to report
+ # the problem and continue
+ _m = '%sException reporting error (object with broken dir())%s:'
+ exception.append(_m % (Colors.excName,ColorsNormal))
+ etype_str,evalue_str = map(str,sys.exc_info()[:2])
+ exception.append('%s%s%s: %s' % (Colors.excName,etype_str,
+ ColorsNormal, evalue_str))
+ names = []
+ for name in names:
+ value = text_repr(getattr(evalue, name))
+ exception.append('\n%s%s = %s' % (indent, name, value))
+
+ # vds: >>
+ if records:
+ filepath, lnum = records[-1][1:3]
+ #print "file:", str(file), "linenb", str(lnum) # dbg
+ filepath = os.path.abspath(filepath)
+ ipinst = ipapi.get()
+ if ipinst is not None:
+ ipinst.IP.hooks.synchronize_with_editor(filepath, lnum, 0)
+ # vds: <<
+
+ # return all our info assembled as a single string
+ return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
+
+ def debugger(self,force=False):
+ """Call up the pdb debugger if desired, always clean up the tb
+ reference.
+
+ Keywords:
+
+ - force(False): by default, this routine checks the instance call_pdb
+ flag and does not actually invoke the debugger if the flag is false.
+ The 'force' option forces the debugger to activate even if the flag
+ is false.
+
+ If the call_pdb flag is set, the pdb interactive debugger is
+ invoked. In all cases, the self.tb reference to the current traceback
+ is deleted to prevent lingering references which hamper memory
+ management.
+
+ Note that each call to pdb() does an 'import readline', so if your app
+ requires a special setup for the readline completers, you'll have to
+ fix that by hand after invoking the exception handler."""
+
+ if force or self.call_pdb:
+ if self.pdb is None:
+ self.pdb = Debugger.Pdb(
+ self.color_scheme_table.active_scheme_name)
+ # the system displayhook may have changed, restore the original
+ # for pdb
+ dhook = sys.displayhook
+ sys.displayhook = sys.__displayhook__
+ self.pdb.reset()
+ # Find the right frame so we don't pop up inside ipython itself
+ if hasattr(self,'tb'):
+ etb = self.tb
+ else:
+ etb = self.tb = sys.last_traceback
+ while self.tb.tb_next is not None:
+ self.tb = self.tb.tb_next
+ try:
+ if etb and etb.tb_next:
+ etb = etb.tb_next
+ self.pdb.botframe = etb.tb_frame
+ self.pdb.interaction(self.tb.tb_frame, self.tb)
+ finally:
+ sys.displayhook = dhook
+
+ if hasattr(self,'tb'):
+ del self.tb
+
+ def handler(self, info=None):
+ (etype, evalue, etb) = info or sys.exc_info()
+ self.tb = etb
+ Term.cout.flush()
+ print >> Term.cerr, self.text(etype, evalue, etb)
+ Term.cerr.flush()
+
+ # Changed so an instance can just be called as VerboseTB_inst() and print
+ # out the right info on its own.
+ def __call__(self, etype=None, evalue=None, etb=None):
+ """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
+ if etb is None:
+ self.handler()
+ else:
+ self.handler((etype, evalue, etb))
+ try:
+ self.debugger()
+ except KeyboardInterrupt:
+ print "\nKeyboardInterrupt"
+
+#----------------------------------------------------------------------------
+class FormattedTB(VerboseTB,ListTB):
+ """Subclass ListTB but allow calling with a traceback.
+
+ It can thus be used as a sys.excepthook for Python > 2.1.
+
+ Also adds 'Context' and 'Verbose' modes, not available in ListTB.
+
+ Allows a tb_offset to be specified. This is useful for situations where
+ one needs to remove a number of topmost frames from the traceback (such as
+ occurs with python programs that themselves execute other python code,
+ like Python shells). """
+
+ def __init__(self, mode = 'Plain', color_scheme='Linux',
+ tb_offset = 0,long_header=0,call_pdb=0,include_vars=0):
+
+ # NEVER change the order of this list. Put new modes at the end:
+ self.valid_modes = ['Plain','Context','Verbose']
+ self.verbose_modes = self.valid_modes[1:3]
+
+ VerboseTB.__init__(self,color_scheme,tb_offset,long_header,
+ call_pdb=call_pdb,include_vars=include_vars)
+ self.set_mode(mode)
+
+ def _extract_tb(self,tb):
+ if tb:
+ return traceback.extract_tb(tb)
+ else:
+ return None
+
+ def text(self, etype, value, tb,context=5,mode=None):
+ """Return formatted traceback.
+
+ If the optional mode parameter is given, it overrides the current
+ mode."""
+
+ if mode is None:
+ mode = self.mode
+ if mode in self.verbose_modes:
+ # verbose modes need a full traceback
+ return VerboseTB.text(self,etype, value, tb,context=5)
+ else:
+ # We must check the source cache because otherwise we can print
+ # out-of-date source code.
+ linecache.checkcache()
+ # Now we can extract and format the exception
+ elist = self._extract_tb(tb)
+ if len(elist) > self.tb_offset:
+ del elist[:self.tb_offset]
+ return ListTB.text(self,etype,value,elist)
+
+ def set_mode(self,mode=None):
+ """Switch to the desired mode.
+
+ If mode is not specified, cycles through the available modes."""
+
+ if not mode:
+ new_idx = ( self.valid_modes.index(self.mode) + 1 ) % \
+ len(self.valid_modes)
+ self.mode = self.valid_modes[new_idx]
+ elif mode not in self.valid_modes:
+ raise ValueError, 'Unrecognized mode in FormattedTB: <'+mode+'>\n'\
+ 'Valid modes: '+str(self.valid_modes)
+ else:
+ self.mode = mode
+ # include variable details only in 'Verbose' mode
+ self.include_vars = (self.mode == self.valid_modes[2])
+
+ # some convenient shorcuts
+ def plain(self):
+ self.set_mode(self.valid_modes[0])
+
+ def context(self):
+ self.set_mode(self.valid_modes[1])
+
+ def verbose(self):
+ self.set_mode(self.valid_modes[2])
+
+#----------------------------------------------------------------------------
+class AutoFormattedTB(FormattedTB):
+ """A traceback printer which can be called on the fly.
+
+ It will find out about exceptions by itself.
+
+ A brief example:
+
+ AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
+ try:
+ ...
+ except:
+ AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
+ """
+ def __call__(self,etype=None,evalue=None,etb=None,
+ out=None,tb_offset=None):
+ """Print out a formatted exception traceback.
+
+ Optional arguments:
+ - out: an open file-like object to direct output to.
+
+ - tb_offset: the number of frames to skip over in the stack, on a
+ per-call basis (this overrides temporarily the instance's tb_offset
+ given at initialization time. """
+
+ if out is None:
+ out = Term.cerr
+ Term.cout.flush()
+ if tb_offset is not None:
+ tb_offset, self.tb_offset = self.tb_offset, tb_offset
+ print >> out, self.text(etype, evalue, etb)
+ self.tb_offset = tb_offset
+ else:
+ print >> out, self.text(etype, evalue, etb)
+ out.flush()
+ try:
+ self.debugger()
+ except KeyboardInterrupt:
+ print "\nKeyboardInterrupt"
+
+ def text(self,etype=None,value=None,tb=None,context=5,mode=None):
+ if etype is None:
+ etype,value,tb = sys.exc_info()
+ self.tb = tb
+ return FormattedTB.text(self,etype,value,tb,context=5,mode=mode)
+
+#---------------------------------------------------------------------------
+# A simple class to preserve Nathan's original functionality.
+class ColorTB(FormattedTB):
+ """Shorthand to initialize a FormattedTB in Linux colors mode."""
+ def __init__(self,color_scheme='Linux',call_pdb=0):
+ FormattedTB.__init__(self,color_scheme=color_scheme,
+ call_pdb=call_pdb)
+
+#----------------------------------------------------------------------------
+# module testing (minimal)
+if __name__ == "__main__":
+ def spam(c, (d, e)):
+ x = c + d
+ y = c * d
+ foo(x, y)
+
+ def foo(a, b, bar=1):
+ eggs(a, b + bar)
+
+ def eggs(f, g, z=globals()):
+ h = f + g
+ i = f - g
+ return h / i
+
+ print ''
+ print '*** Before ***'
+ try:
+ print spam(1, (2, 3))
+ except:
+ traceback.print_exc()
+ print ''
+
+ handler = ColorTB()
+ print '*** ColorTB ***'
+ try:
+ print spam(1, (2, 3))
+ except:
+ apply(handler, sys.exc_info() )
+ print ''
+
+ handler = VerboseTB()
+ print '*** VerboseTB ***'
+ try:
+ print spam(1, (2, 3))
+ except:
+ apply(handler, sys.exc_info() )
+ print ''
+
diff --git a/IPython/upgrade_dir.py b/IPython/upgrade_dir.py
new file mode 100644
index 0000000..2f31e93
--- /dev/null
+++ b/IPython/upgrade_dir.py
@@ -0,0 +1,92 @@
+#!/usr/bin/env python
+""" A script/util to upgrade all files in a directory
+
+This is rather conservative in its approach, only copying/overwriting
+new and unedited files.
+
+To be used by "upgrade" feature.
+"""
+try:
+ from IPython.external.path import path
+except ImportError:
+ from path import path
+
+import md5,pickle
+
+def showdiff(old,new):
+ import difflib
+ d = difflib.Differ()
+ lines = d.compare(old.lines(),new.lines())
+ realdiff = False
+ for l in lines:
+ print l,
+ if not realdiff and not l[0].isspace():
+ realdiff = True
+ return realdiff
+
+def upgrade_dir(srcdir, tgtdir):
+ """ Copy over all files in srcdir to tgtdir w/ native line endings
+
+ Creates .upgrade_report in tgtdir that stores md5sums of all files
+ to notice changed files b/w upgrades.
+ """
+
+ def pr(s):
+ print s
+ junk = ['.svn','ipythonrc*','*.pyc', '*.pyo', '*~', '.hg']
+
+ def ignorable(p):
+ for pat in junk:
+ if p.startswith(pat) or p.fnmatch(pat):
+ return True
+ return False
+
+ modded = []
+ files = [path(srcdir).relpathto(p) for p in path(srcdir).walkfiles()]
+ #print files
+ rep = tgtdir / '.upgrade_report'
+ try:
+ rpt = pickle.load(rep.open())
+ except:
+ rpt = {}
+
+ for f in files:
+ if ignorable(f):
+ continue
+ src = srcdir / f
+ tgt = tgtdir / f
+ if not tgt.isfile():
+ pr("Creating %s" % str(tgt))
+
+ tgt.write_text(src.text())
+ rpt[str(tgt)] = md5.new(tgt.text()).hexdigest()
+ else:
+ cont = tgt.text()
+ sum = rpt.get(str(tgt), None)
+ #print sum
+ if sum and md5.new(cont).hexdigest() == sum:
+ pr("%s: Unedited, installing new version" % tgt)
+ tgt.write_text(src.text())
+ rpt[str(tgt)] = md5.new(tgt.text()).hexdigest()
+ else:
+ pr(' == Modified, skipping %s, diffs below == ' % tgt)
+ #rpt[str(tgt)] = md5.new(tgt.bytes()).hexdigest()
+ real = showdiff(tgt,src)
+ pr('') # empty line
+ if not real:
+ pr("(Ok, it was identical, only upgrading checksum)")
+ rpt[str(tgt)] = md5.new(tgt.text()).hexdigest()
+ else:
+ modded.append(tgt)
+
+ #print rpt
+ pickle.dump(rpt, rep.open('w'))
+ if modded:
+ print "\n\nDelete the following files manually (and rerun %upgrade)\nif you need a full upgrade:"
+ for m in modded:
+ print m
+
+
+import sys
+if __name__ == "__main__":
+ upgrade_dir(path(sys.argv[1]), path(sys.argv[2]))
diff --git a/IPython/usage.py b/IPython/usage.py
new file mode 100644
index 0000000..7620d96
--- /dev/null
+++ b/IPython/usage.py
@@ -0,0 +1,645 @@
+# -*- coding: utf-8 -*-
+#*****************************************************************************
+# Copyright (C) 2001-2004 Fernando Perez. <fperez@colorado.edu>
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#*****************************************************************************
+
+__doc__ = """
+IPython -- An enhanced Interactive Python
+=========================================
+
+A Python shell with automatic history (input and output), dynamic object
+introspection, easier configuration, command completion, access to the system
+shell and more.
+
+IPython can also be embedded in running programs. See EMBEDDING below.
+
+
+USAGE
+ ipython [options] files
+
+ If invoked with no options, it executes all the files listed in
+ sequence and drops you into the interpreter while still acknowledging
+ any options you may have set in your ipythonrc file. This behavior is
+ different from standard Python, which when called as python -i will
+ only execute one file and will ignore your configuration setup.
+
+ Please note that some of the configuration options are not available at
+ the command line, simply because they are not practical here. Look into
+ your ipythonrc configuration file for details on those. This file
+ typically installed in the $HOME/.ipython directory.
+
+ For Windows users, $HOME resolves to C:\\Documents and
+ Settings\\YourUserName in most instances, and _ipython is used instead
+ of .ipython, since some Win32 programs have problems with dotted names
+ in directories.
+
+ In the rest of this text, we will refer to this directory as
+ IPYTHONDIR.
+
+
+SPECIAL THREADING OPTIONS
+ The following special options are ONLY valid at the beginning of the
+ command line, and not later. This is because they control the initial-
+ ization of ipython itself, before the normal option-handling mechanism
+ is active.
+
+ -gthread, -qthread, -q4thread, -wthread, -pylab
+
+ Only ONE of these can be given, and it can only be given as the
+ first option passed to IPython (it will have no effect in any
+ other position). They provide threading support for the GTK, QT
+ and WXWidgets toolkits, and for the matplotlib library.
+
+ With any of the first four options, IPython starts running a
+ separate thread for the graphical toolkit's operation, so that
+ you can open and control graphical elements from within an
+ IPython command line, without blocking. All four provide
+ essentially the same functionality, respectively for GTK, QT3,
+ QT4 and WXWidgets (via their Python interfaces).
+
+ Note that with -wthread, you can additionally use the -wxversion
+ option to request a specific version of wx to be used. This
+ requires that you have the 'wxversion' Python module installed,
+ which is part of recent wxPython distributions.
+
+ If -pylab is given, IPython loads special support for the mat-
+ plotlib library (http://matplotlib.sourceforge.net), allowing
+ interactive usage of any of its backends as defined in the
+ user's .matplotlibrc file. It automatically activates GTK, QT
+ or WX threading for IPyhton if the choice of matplotlib backend
+ requires it. It also modifies the %run command to correctly
+ execute (without blocking) any matplotlib-based script which
+ calls show() at the end.
+
+ -tk The -g/q/q4/wthread options, and -pylab (if matplotlib is
+ configured to use GTK, QT or WX), will normally block Tk
+ graphical interfaces. This means that when GTK, QT or WX
+ threading is active, any attempt to open a Tk GUI will result in
+ a dead window, and possibly cause the Python interpreter to
+ crash. An extra option, -tk, is available to address this
+ issue. It can ONLY be given as a SECOND option after any of the
+ above (-gthread, -qthread, q4thread, -wthread or -pylab).
+
+ If -tk is given, IPython will try to coordinate Tk threading
+ with GTK, QT or WX. This is however potentially unreliable, and
+ you will have to test on your platform and Python configuration
+ to determine whether it works for you. Debian users have
+ reported success, apparently due to the fact that Debian builds
+ all of Tcl, Tk, Tkinter and Python with pthreads support. Under
+ other Linux environments (such as Fedora Core 2/3), this option
+ has caused random crashes and lockups of the Python interpreter.
+ Under other operating systems (Mac OSX and Windows), you'll need
+ to try it to find out, since currently no user reports are
+ available.
+
+ There is unfortunately no way for IPython to determine at run-
+ time whether -tk will work reliably or not, so you will need to
+ do some experiments before relying on it for regular work.
+
+A WARNING ABOUT SIGNALS AND THREADS
+
+ When any of the thread systems (GTK, QT or WX) are active, either
+ directly or via -pylab with a threaded backend, it is impossible to
+ interrupt long-running Python code via Ctrl-C. IPython can not pass
+ the KeyboardInterrupt exception (or the underlying SIGINT) across
+ threads, so any long-running process started from IPython will run to
+ completion, or will have to be killed via an external (OS-based)
+ mechanism.
+
+ To the best of my knowledge, this limitation is imposed by the Python
+ interpreter itself, and it comes from the difficulty of writing
+ portable signal/threaded code. If any user is an expert on this topic
+ and can suggest a better solution, I would love to hear about it. In
+ the IPython sources, look at the Shell.py module, and in particular at
+ the runcode() method.
+
+REGULAR OPTIONS
+ After the above threading options have been given, regular options can
+ follow in any order. All options can be abbreviated to their shortest
+ non-ambiguous form and are case-sensitive. One or two dashes can be
+ used. Some options have an alternate short form, indicated after a |.
+
+ Most options can also be set from your ipythonrc configuration file.
+ See the provided examples for assistance. Options given on the comman-
+ dline override the values set in the ipythonrc file.
+
+ All options with a [no] prepended can be specified in negated form
+ (using -nooption instead of -option) to turn the feature off.
+
+ -h, --help
+ Show summary of options.
+
+ -pylab This can only be given as the first option passed to IPython (it
+ will have no effect in any other position). It adds special sup-
+ port for the matplotlib library (http://matplotlib.source-
+ forge.net), allowing interactive usage of any of its backends as
+ defined in the user's .matplotlibrc file. It automatically
+ activates GTK or WX threading for IPyhton if the choice of mat-
+ plotlib backend requires it. It also modifies the @run command
+ to correctly execute (without blocking) any matplotlib-based
+ script which calls show() at the end.
+
+ -autocall <val>
+ Make IPython automatically call any callable object even if you
+ didn't type explicit parentheses. For example, 'str 43' becomes
+ 'str(43)' automatically. The value can be '0' to disable the
+ feature, '1' for 'smart' autocall, where it is not applied if
+ there are no more arguments on the line, and '2' for 'full'
+ autocall, where all callable objects are automatically called
+ (even if no arguments are present). The default is '1'.
+
+ -[no]autoindent
+ Turn automatic indentation on/off.
+
+ -[no]automagic
+ Make magic commands automatic (without needing their first char-
+ acter to be %). Type %magic at the IPython prompt for more
+ information.
+
+ -[no]autoedit_syntax
+ When a syntax error occurs after editing a file, automatically
+ open the file to the trouble causing line for convenient fixing.
+
+ -[no]banner
+ Print the intial information banner (default on).
+
+ -c <command>
+ Execute the given command string, and set sys.argv to ['c'].
+ This is similar to the -c option in the normal Python inter-
+ preter.
+
+ -cache_size|cs <n>
+ Size of the output cache (maximum number of entries to hold in
+ memory). The default is 1000, you can change it permanently in
+ your config file. Setting it to 0 completely disables the
+ caching system, and the minimum value accepted is 20 (if you
+ provide a value less than 20, it is reset to 0 and a warning is
+ issued). This limit is defined because otherwise you'll spend
+ more time re-flushing a too small cache than working.
+
+ -classic|cl
+ Gives IPython a similar feel to the classic Python prompt.
+
+ -colors <scheme>
+ Color scheme for prompts and exception reporting. Currently
+ implemented: NoColor, Linux, and LightBG.
+
+ -[no]color_info
+ IPython can display information about objects via a set of func-
+ tions, and optionally can use colors for this, syntax highlight-
+ ing source code and various other elements. However, because
+ this information is passed through a pager (like 'less') and
+ many pagers get confused with color codes, this option is off by
+ default. You can test it and turn it on permanently in your
+ ipythonrc file if it works for you. As a reference, the 'less'
+ pager supplied with Mandrake 8.2 works ok, but that in RedHat
+ 7.2 doesn't.
+
+ Test it and turn it on permanently if it works with your system.
+ The magic function @color_info allows you to toggle this inter-
+ actively for testing.
+
+ -[no]confirm_exit
+ Set to confirm when you try to exit IPython with an EOF (Con-
+ trol-D in Unix, Control-Z/Enter in Windows). Note that using the
+ magic functions @Exit or @Quit you can force a direct exit,
+ bypassing any confirmation.
+
+ -[no]debug
+ Show information about the loading process. Very useful to pin
+ down problems with your configuration files or to get details
+ about session restores.
+
+ -[no]deep_reload
+ IPython can use the deep_reload module which reloads changes in
+ modules recursively (it replaces the reload() function, so you
+ don't need to change anything to use it). deep_reload() forces a
+ full reload of modules whose code may have changed, which the
+ default reload() function does not.
+
+ When deep_reload is off, IPython will use the normal reload(),
+ but deep_reload will still be available as dreload(). This fea-
+ ture is off by default [which means that you have both normal
+ reload() and dreload()].
+
+ -editor <name>
+ Which editor to use with the @edit command. By default, IPython
+ will honor your EDITOR environment variable (if not set, vi is
+ the Unix default and notepad the Windows one). Since this editor
+ is invoked on the fly by IPython and is meant for editing small
+ code snippets, you may want to use a small, lightweight editor
+ here (in case your default EDITOR is something like Emacs).
+
+ -ipythondir <name>
+ The name of your IPython configuration directory IPYTHONDIR.
+ This can also be specified through the environment variable
+ IPYTHONDIR.
+
+ -log|l Generate a log file of all input. The file is named
+ ipython_log.py in your current directory (which prevents logs
+ from multiple IPython sessions from trampling each other). You
+ can use this to later restore a session by loading your logfile
+ as a file to be executed with option -logplay (see below).
+
+ -logfile|lf
+ Specify the name of your logfile.
+
+ -logplay|lp
+ Replay a previous log. For restoring a session as close as pos-
+ sible to the state you left it in, use this option (don't just
+ run the logfile). With -logplay, IPython will try to reconstruct
+ the previous working environment in full, not just execute the
+ commands in the logfile.
+ When a session is restored, logging is automatically turned on
+ again with the name of the logfile it was invoked with (it is
+ read from the log header). So once you've turned logging on for
+ a session, you can quit IPython and reload it as many times as
+ you want and it will continue to log its history and restore
+ from the beginning every time.
+
+ Caveats: there are limitations in this option. The history vari-
+ ables _i*,_* and _dh don't get restored properly. In the future
+ we will try to implement full session saving by writing and
+ retrieving a failed because of inherent limitations of Python's
+ Pickle module, so this may have to wait.
+
+ -[no]messages
+ Print messages which IPython collects about its startup process
+ (default on).
+
+ -[no]pdb
+ Automatically call the pdb debugger after every uncaught excep-
+ tion. If you are used to debugging using pdb, this puts you
+ automatically inside of it after any call (either in IPython or
+ in code called by it) which triggers an exception which goes
+ uncaught.
+
+ -[no]pprint
+ IPython can optionally use the pprint (pretty printer) module
+ for displaying results. pprint tends to give a nicer display of
+ nested data structures. If you like it, you can turn it on per-
+ manently in your config file (default off).
+
+ -profile|p <name>
+ Assume that your config file is ipythonrc-<name> (looks in cur-
+ rent dir first, then in IPYTHONDIR). This is a quick way to keep
+ and load multiple config files for different tasks, especially
+ if you use the include option of config files. You can keep a
+ basic IPYTHONDIR/ipythonrc file and then have other 'profiles'
+ which include this one and load extra things for particular
+ tasks. For example:
+
+ 1) $HOME/.ipython/ipythonrc : load basic things you always want.
+ 2) $HOME/.ipython/ipythonrc-math : load (1) and basic math-
+ related modules.
+ 3) $HOME/.ipython/ipythonrc-numeric : load (1) and Numeric and
+ plotting modules.
+
+ Since it is possible to create an endless loop by having circu-
+ lar file inclusions, IPython will stop if it reaches 15 recur-
+ sive inclusions.
+
+ -prompt_in1|pi1 <string>
+ Specify the string used for input prompts. Note that if you are
+ using numbered prompts, the number is represented with a '\#' in
+ the string. Don't forget to quote strings with spaces embedded
+ in them. Default: 'In [\#]: '.
+
+ Most bash-like escapes can be used to customize IPython's
+ prompts, as well as a few additional ones which are IPython-spe-
+ cific. All valid prompt escapes are described in detail in the
+ Customization section of the IPython HTML/PDF manual.
+
+ -prompt_in2|pi2 <string>
+ Similar to the previous option, but used for the continuation
+ prompts. The special sequence '\D' is similar to '\#', but with
+ all digits replaced dots (so you can have your continuation
+ prompt aligned with your input prompt). Default: ' .\D.: '
+ (note three spaces at the start for alignment with 'In [\#]').
+
+ -prompt_out|po <string>
+ String used for output prompts, also uses numbers like
+ prompt_in1. Default: 'Out[\#]:'.
+
+ -quick Start in bare bones mode (no config file loaded).
+
+ -rcfile <name>
+ Name of your IPython resource configuration file. normally
+ IPython loads ipythonrc (from current directory) or
+ IPYTHONDIR/ipythonrc. If the loading of your config file fails,
+ IPython starts with a bare bones configuration (no modules
+ loaded at all).
+
+ -[no]readline
+ Use the readline library, which is needed to support name com-
+ pletion and command history, among other things. It is enabled
+ by default, but may cause problems for users of X/Emacs in
+ Python comint or shell buffers.
+
+ Note that emacs 'eterm' buffers (opened with M-x term) support
+ IPython's readline and syntax coloring fine, only 'emacs' (M-x
+ shell and C-c !) buffers do not.
+
+ -screen_length|sl <n>
+ Number of lines of your screen. This is used to control print-
+ ing of very long strings. Strings longer than this number of
+ lines will be sent through a pager instead of directly printed.
+
+ The default value for this is 0, which means IPython will auto-
+ detect your screen size every time it needs to print certain
+ potentially long strings (this doesn't change the behavior of
+ the 'print' keyword, it's only triggered internally). If for
+ some reason this isn't working well (it needs curses support),
+ specify it yourself. Otherwise don't change the default.
+
+ -separate_in|si <string>
+ Separator before input prompts. Default '0.
+
+ -separate_out|so <string>
+ Separator before output prompts. Default: 0 (nothing).
+
+ -separate_out2|so2 <string>
+ Separator after output prompts. Default: 0 (nothing).
+
+ -nosep Shorthand for '-separate_in 0 -separate_out 0 -separate_out2 0'.
+ Simply removes all input/output separators.
+
+ -upgrade
+ Allows you to upgrade your IPYTHONDIR configuration when you
+ install a new version of IPython. Since new versions may
+ include new command lines options or example files, this copies
+ updated ipythonrc-type files. However, it backs up (with a .old
+ extension) all files which it overwrites so that you can merge
+ back any custimizations you might have in your personal files.
+
+ -Version
+ Print version information and exit.
+
+ -wxversion <string>
+ Select a specific version of wxPython (used in conjunction with
+ -wthread). Requires the wxversion module, part of recent
+ wxPython distributions.
+
+ -xmode <modename>
+ Mode for exception reporting. The valid modes are Plain, Con-
+ text, and Verbose.
+
+ - Plain: similar to python's normal traceback printing.
+
+ - Context: prints 5 lines of context source code around each
+ line in the traceback.
+
+ - Verbose: similar to Context, but additionally prints the vari-
+ ables currently visible where the exception happened (shortening
+ their strings if too long). This can potentially be very slow,
+ if you happen to have a huge data structure whose string repre-
+ sentation is complex to compute. Your computer may appear to
+ freeze for a while with cpu usage at 100%. If this occurs, you
+ can cancel the traceback with Ctrl-C (maybe hitting it more than
+ once).
+
+
+EMBEDDING
+ It is possible to start an IPython instance inside your own Python pro-
+ grams. In the documentation example files there are some illustrations
+ on how to do this.
+
+ This feature allows you to evalutate dynamically the state of your
+ code, operate with your variables, analyze them, etc. Note however
+ that any changes you make to values while in the shell do NOT propagate
+ back to the running code, so it is safe to modify your values because
+ you won't break your code in bizarre ways by doing so.
+"""
+
+cmd_line_usage = __doc__
+
+#---------------------------------------------------------------------------
+interactive_usage = """
+IPython -- An enhanced Interactive Python
+=========================================
+
+IPython offers a combination of convenient shell features, special commands
+and a history mechanism for both input (command history) and output (results
+caching, similar to Mathematica). It is intended to be a fully compatible
+replacement for the standard Python interpreter, while offering vastly
+improved functionality and flexibility.
+
+At your system command line, type 'ipython -help' to see the command line
+options available. This document only describes interactive features.
+
+Warning: IPython relies on the existence of a global variable called __IP which
+controls the shell itself. If you redefine __IP to anything, bizarre behavior
+will quickly occur.
+
+MAIN FEATURES
+
+* Access to the standard Python help. As of Python 2.1, a help system is
+ available with access to object docstrings and the Python manuals. Simply
+ type 'help' (no quotes) to access it.
+
+* Magic commands: type %magic for information on the magic subsystem.
+
+* System command aliases, via the %alias command or the ipythonrc config file.
+
+* Dynamic object information:
+
+ Typing ?word or word? prints detailed information about an object. If
+ certain strings in the object are too long (docstrings, code, etc.) they get
+ snipped in the center for brevity.
+
+ Typing ??word or word?? gives access to the full information without
+ snipping long strings. Long strings are sent to the screen through the less
+ pager if longer than the screen, printed otherwise.
+
+ The ?/?? system gives access to the full source code for any object (if
+ available), shows function prototypes and other useful information.
+
+ If you just want to see an object's docstring, type '%pdoc object' (without
+ quotes, and without % if you have automagic on).
+
+ Both %pdoc and ?/?? give you access to documentation even on things which are
+ not explicitely defined. Try for example typing {}.get? or after import os,
+ type os.path.abspath??. The magic functions %pdef, %source and %file operate
+ similarly.
+
+* Completion in the local namespace, by typing TAB at the prompt.
+
+ At any time, hitting tab will complete any available python commands or
+ variable names, and show you a list of the possible completions if there's
+ no unambiguous one. It will also complete filenames in the current directory.
+
+ This feature requires the readline and rlcomplete modules, so it won't work
+ if your Python lacks readline support (such as under Windows).
+
+* Search previous command history in two ways (also requires readline):
+
+ - Start typing, and then use Ctrl-p (previous,up) and Ctrl-n (next,down) to
+ search through only the history items that match what you've typed so
+ far. If you use Ctrl-p/Ctrl-n at a blank prompt, they just behave like
+ normal arrow keys.
+
+ - Hit Ctrl-r: opens a search prompt. Begin typing and the system searches
+ your history for lines that match what you've typed so far, completing as
+ much as it can.
+
+* Persistent command history across sessions (readline required).
+
+* Logging of input with the ability to save and restore a working session.
+
+* System escape with !. Typing !ls will run 'ls' in the current directory.
+
+* The reload command does a 'deep' reload of a module: changes made to the
+ module since you imported will actually be available without having to exit.
+
+* Verbose and colored exception traceback printouts. See the magic xmode and
+ xcolor functions for details (just type %magic).
+
+* Input caching system:
+
+ IPython offers numbered prompts (In/Out) with input and output caching. All
+ input is saved and can be retrieved as variables (besides the usual arrow
+ key recall).
+
+ The following GLOBAL variables always exist (so don't overwrite them!):
+ _i: stores previous input.
+ _ii: next previous.
+ _iii: next-next previous.
+ _ih : a list of all input _ih[n] is the input from line n.
+
+ Additionally, global variables named _i<n> are dynamically created (<n>
+ being the prompt counter), such that _i<n> == _ih[<n>]
+
+ For example, what you typed at prompt 14 is available as _i14 and _ih[14].
+
+ You can create macros which contain multiple input lines from this history,
+ for later re-execution, with the %macro function.
+
+ The history function %hist allows you to see any part of your input history
+ by printing a range of the _i variables. Note that inputs which contain
+ magic functions (%) appear in the history with a prepended comment. This is
+ because they aren't really valid Python code, so you can't exec them.
+
+* Output caching system:
+
+ For output that is returned from actions, a system similar to the input
+ cache exists but using _ instead of _i. Only actions that produce a result
+ (NOT assignments, for example) are cached. If you are familiar with
+ Mathematica, IPython's _ variables behave exactly like Mathematica's %
+ variables.
+
+ The following GLOBAL variables always exist (so don't overwrite them!):
+ _ (one underscore): previous output.
+ __ (two underscores): next previous.
+ ___ (three underscores): next-next previous.
+
+ Global variables named _<n> are dynamically created (<n> being the prompt
+ counter), such that the result of output <n> is always available as _<n>.
+
+ Finally, a global dictionary named _oh exists with entries for all lines
+ which generated output.
+
+* Directory history:
+
+ Your history of visited directories is kept in the global list _dh, and the
+ magic %cd command can be used to go to any entry in that list.
+
+* Auto-parentheses and auto-quotes (adapted from Nathan Gray's LazyPython)
+
+ 1. Auto-parentheses
+ Callable objects (i.e. functions, methods, etc) can be invoked like
+ this (notice the commas between the arguments):
+ >>> callable_ob arg1, arg2, arg3
+ and the input will be translated to this:
+ --> callable_ob(arg1, arg2, arg3)
+ You can force auto-parentheses by using '/' as the first character
+ of a line. For example:
+ >>> /globals # becomes 'globals()'
+ Note that the '/' MUST be the first character on the line! This
+ won't work:
+ >>> print /globals # syntax error
+
+ In most cases the automatic algorithm should work, so you should
+ rarely need to explicitly invoke /. One notable exception is if you
+ are trying to call a function with a list of tuples as arguments (the
+ parenthesis will confuse IPython):
+ In [1]: zip (1,2,3),(4,5,6) # won't work
+ but this will work:
+ In [2]: /zip (1,2,3),(4,5,6)
+ ------> zip ((1,2,3),(4,5,6))
+ Out[2]= [(1, 4), (2, 5), (3, 6)]
+
+ IPython tells you that it has altered your command line by
+ displaying the new command line preceded by -->. e.g.:
+ In [18]: callable list
+ -------> callable (list)
+
+ 2. Auto-Quoting
+ You can force auto-quoting of a function's arguments by using ',' as
+ the first character of a line. For example:
+ >>> ,my_function /home/me # becomes my_function("/home/me")
+
+ If you use ';' instead, the whole argument is quoted as a single
+ string (while ',' splits on whitespace):
+ >>> ,my_function a b c # becomes my_function("a","b","c")
+ >>> ;my_function a b c # becomes my_function("a b c")
+
+ Note that the ',' MUST be the first character on the line! This
+ won't work:
+ >>> x = ,my_function /home/me # syntax error
+"""
+
+quick_reference = r"""
+IPython -- An enhanced Interactive Python - Quick Reference Card
+================================================================
+
+obj?, obj?? : Get help, or more help for object (also works as
+ ?obj, ??obj).
+?foo.*abc* : List names in 'foo' containing 'abc' in them.
+%magic : Information about IPython's 'magic' % functions.
+
+Magic functions are prefixed by %, and typically take their arguments without
+parentheses, quotes or even commas for convenience.
+
+Example magic function calls:
+
+%alias d ls -F : 'd' is now an alias for 'ls -F'
+alias d ls -F : Works if 'alias' not a python name
+alist = %alias : Get list of aliases to 'alist'
+cd /usr/share : Obvious. cd -<tab> to choose from visited dirs.
+%cd?? : See help AND source for magic %cd
+
+System commands:
+
+!cp a.txt b/ : System command escape, calls os.system()
+cp a.txt b/ : after %rehashx, most system commands work without !
+cp ${f}.txt $bar : Variable expansion in magics and system commands
+files = !ls /usr : Capture sytem command output
+files.s, files.l, files.n: "a b c", ['a','b','c'], 'a\nb\nc'
+
+History:
+
+_i, _ii, _iii : Previous, next previous, next next previous input
+_i4, _ih[2:5] : Input history line 4, lines 2-4
+exec _i81 : Execute input history line #81 again
+%rep 81 : Edit input history line #81
+_, __, ___ : previous, next previous, next next previous output
+_dh : Directory history
+_oh : Output history
+%hist : Command history. '%hist -g foo' search history for 'foo'
+
+Autocall:
+
+f 1,2 : f(1,2)
+/f 1,2 : f(1,2) (forced autoparen)
+,f 1 2 : f("1","2")
+;f 1 2 : f("1 2")
+
+Remember: TAB completion works in many contexts, not just file names
+or python names.
+
+The following magic functions are currently available:
+
+"""
diff --git a/IPython/wildcard.py b/IPython/wildcard.py
new file mode 100644
index 0000000..3e62d8a
--- /dev/null
+++ b/IPython/wildcard.py
@@ -0,0 +1,149 @@
+# -*- coding: utf-8 -*-
+"""Support for wildcard pattern matching in object inspection.
+
+Authors
+-------
+- Jörgen Stenarson <jorgen.stenarson@bostream.nu>
+"""
+
+#*****************************************************************************
+# Copyright (C) 2005 Jörgen Stenarson <jorgen.stenarson@bostream.nu>
+#
+# Distributed under the terms of the BSD License. The full license is in
+# the file COPYING, distributed as part of this software.
+#*****************************************************************************
+
+import __builtin__
+import exceptions
+import pdb
+import pprint
+import re
+import types
+
+from IPython.genutils import dir2
+
+def create_typestr2type_dicts(dont_include_in_type2type2str=["lambda"]):
+ """Return dictionaries mapping lower case typename to type objects, from
+ the types package, and vice versa."""
+ typenamelist=[]
+ for tname in dir(types):
+ if tname[-4:]=="Type":
+ typenamelist.append(tname)
+ typestr2type={}
+ type2typestr={}
+ for tname in typenamelist:
+ name=tname[:-4].lower()
+ obj=getattr(types,tname)
+ typestr2type[name]=getattr(types,tname)
+ if name in dont_include_in_type2type2str:
+ type2typestr[obj]=name
+ return typestr2type,type2typestr
+
+typestr2type,type2typestr=create_typestr2type_dicts()
+
+def is_type(obj,typestr_or_type):
+ """is_type(obj,typestr_or_type) verifies if obj is of a certain type or
+ group of types takes strings as parameters of the for 'tuple'<->TupleType
+ 'all' matches all types. TODO: Should be extended for choosing more than
+ one type
+ """
+ if typestr_or_type=="all":
+ return True
+ if type(typestr_or_type)==types.TypeType:
+ test_type=typestr_or_type
+ else:
+ test_type=typestr2type.get(typestr_or_type,False)
+ if test_type:
+ return isinstance(obj,test_type)
+ else:
+ return False
+
+def show_hidden(str,show_all=False):
+ """Return true for strings starting with single _ if show_all is true."""
+ return show_all or str.startswith("__") or not str.startswith("_")
+
+class NameSpace(object):
+ """NameSpace holds the dictionary for a namespace and implements filtering
+ on name and types"""
+ def __init__(self,obj,name_pattern="*",type_pattern="all",ignore_case=True,
+ show_all=True):
+ self.show_all = show_all #Hide names beginning with single _
+ self.object = obj
+ self.name_pattern = name_pattern
+ self.type_pattern = type_pattern
+ self.ignore_case = ignore_case
+
+ # We should only match EXACT dicts here, so DON'T use isinstance()
+ if type(obj) == types.DictType:
+ self._ns = obj
+ else:
+ kv = []
+ for key in dir2(obj):
+ if isinstance(key, basestring):
+ # This seemingly unnecessary try/except is actually needed
+ # because there is code out there with metaclasses that
+ # create 'write only' attributes, where a getattr() call
+ # will fail even if the attribute appears listed in the
+ # object's dictionary. Properties can actually do the same
+ # thing. In particular, Traits use this pattern
+ try:
+ kv.append((key,getattr(obj,key)))
+ except AttributeError:
+ pass
+ self._ns = dict(kv)
+
+ def get_ns(self):
+ """Return name space dictionary with objects matching type and name patterns."""
+ return self.filter(self.name_pattern,self.type_pattern)
+ ns=property(get_ns)
+
+ def get_ns_names(self):
+ """Return list of object names in namespace that match the patterns."""
+ return self.ns.keys()
+ ns_names=property(get_ns_names,doc="List of objects in name space that "
+ "match the type and name patterns.")
+
+ def filter(self,name_pattern,type_pattern):
+ """Return dictionary of filtered namespace."""
+ def glob_filter(lista,name_pattern,hidehidden,ignore_case):
+ """Return list of elements in lista that match pattern."""
+ pattern=name_pattern.replace("*",".*").replace("?",".")
+ if ignore_case:
+ reg=re.compile(pattern+"$",re.I)
+ else:
+ reg=re.compile(pattern+"$")
+ result=[x for x in lista if reg.match(x) and show_hidden(x,hidehidden)]
+ return result
+ ns=self._ns
+ #Filter namespace by the name_pattern
+ all=[(x,ns[x]) for x in glob_filter(ns.keys(),name_pattern,
+ self.show_all,self.ignore_case)]
+ #Filter namespace by type_pattern
+ all=[(key,obj) for key,obj in all if is_type(obj,type_pattern)]
+ all=dict(all)
+ return all
+
+ #TODO: Implement dictionary like access to filtered name space?
+
+def list_namespace(namespace,type_pattern,filter,ignore_case=False,show_all=False):
+ """Return dictionary of all objects in namespace that matches type_pattern
+ and filter."""
+ pattern_list=filter.split(".")
+ if len(pattern_list)==1:
+ ns=NameSpace(namespace,name_pattern=pattern_list[0],type_pattern=type_pattern,
+ ignore_case=ignore_case,show_all=show_all)
+ return ns.ns
+ else:
+ # This is where we can change if all objects should be searched or
+ # only modules. Just change the type_pattern to module to search only
+ # modules
+ ns=NameSpace(namespace,name_pattern=pattern_list[0],type_pattern="all",
+ ignore_case=ignore_case,show_all=show_all)
+ res={}
+ nsdict=ns.ns
+ for name,obj in nsdict.iteritems():
+ ns=list_namespace(obj,type_pattern,".".join(pattern_list[1:]),
+ ignore_case=ignore_case,show_all=show_all)
+ for inner_name,inner_obj in ns.iteritems():
+ res["%s.%s"%(name,inner_name)]=inner_obj
+ return res
diff --git a/IPython/winconsole.py b/IPython/winconsole.py
new file mode 100644
index 0000000..91cb26c
--- /dev/null
+++ b/IPython/winconsole.py
@@ -0,0 +1,46 @@
+"""Set of functions to work with console on Windows.
+"""
+
+#*****************************************************************************
+# Copyright (C) 2005 Alexander Belchenko <bialix@ukr.net>
+#
+# This file is placed in the public domain.
+#
+#*****************************************************************************
+
+__author__ = 'Alexander Belchenko (e-mail: bialix AT ukr.net)'
+__license__ = 'Public domain'
+
+import struct
+
+try:
+ import ctypes
+except ImportError:
+ ctypes = None
+
+def get_console_size(defaultx=80, defaulty=25):
+ """ Return size of current console.
+
+ This function try to determine actual size of current working
+ console window and return tuple (sizex, sizey) if success,
+ or default size (defaultx, defaulty) otherwise.
+
+ Dependencies: ctypes should be installed.
+ """
+ if ctypes is None:
+ # no ctypes is found
+ return (defaultx, defaulty)
+
+ h = ctypes.windll.kernel32.GetStdHandle(-11)
+ csbi = ctypes.create_string_buffer(22)
+ res = ctypes.windll.kernel32.GetConsoleScreenBufferInfo(h, csbi)
+
+ if res:
+ (bufx, bufy, curx, cury, wattr,
+ left, top, right, bottom, maxx, maxy) = struct.unpack("hhhhHhhhhhh",
+ csbi.raw)
+ sizex = right - left + 1
+ sizey = bottom - top + 1
+ return (sizex, sizey)
+ else:
+ return (defaultx, defaulty)
diff --git a/MANIFEST b/MANIFEST
new file mode 100644
index 0000000..c0b90a3
--- /dev/null
+++ b/MANIFEST
@@ -0,0 +1,1125 @@
+progresslistener.py
+stub.py
+webview.py
+terminal_pd.py
+\
+project.glade
+help_pd.py
+browser.py
+webdownloader.py
+rpc_test.py
+md5test.py
+rpyc-2.60.zip
+pydebug.py
+sourceview_editor.py
+datastoretree.py
+setup.py
+helloworld.py
+filetree.py
+rpc_server.py
+notebook.py
+help/PythonExamples.xol
+help/Pygtk2Tutorial.xol
+help/PyDebug.htm
+help/PythonTutorial.xol
+help/PythonTutorial/modindex.html
+help/PythonTutorial/genindex.html
+help/PythonTutorial/glossary.html
+help/PythonTutorial/index.html
+help/PythonTutorial/copyright.html
+help/PythonTutorial/about.html
+help/PythonTutorial/whatsnew/2.0.html
+help/PythonTutorial/_sources/tutorial/index.txt
+help/PythonTutorial/_static/minus.png
+help/PythonTutorial/_static/py.png
+help/PythonTutorial/_static/pygments.css
+help/PythonTutorial/_static/jquery.js
+help/PythonTutorial/_static/opensearch.xml
+help/PythonTutorial/_static/doctools.js
+help/PythonTutorial/_static/default.css
+help/PythonTutorial/tutorial/controlflow.html
+help/PythonTutorial/tutorial/classes.html
+help/PythonTutorial/tutorial/inputoutput.html
+help/PythonTutorial/tutorial/interactive.html
+help/PythonTutorial/tutorial/stdlib2.html
+help/PythonTutorial/tutorial/stdlib.html
+help/PythonTutorial/tutorial/datastructures.html
+help/PythonTutorial/tutorial/whatnow.html
+help/PythonTutorial/tutorial/appetite.html
+help/PythonTutorial/tutorial/interpreter.html
+help/PythonTutorial/tutorial/introduction.html
+help/PythonTutorial/tutorial/modules.html
+help/PythonTutorial/tutorial/errors.html
+help/PythonTutorial/tutorial/index.html
+help/PythonTutorial/tutorial/floatingpoint.html
+help/PythonTutorial/library/library.info
+help/images/3080617962_604fcfe2ed.jpg
+help/images/Your Program Output Page.jpg
+help/images/Edit Page.jpg
+help/images/Project Page.jpg
+help/images/Help Page.jpg
+help/images/Terminal_Ipython Page.jpg
+help/PythonExamples/pleac.css
+help/PythonExamples/index.html
+help/PythonExamples/library/library.info
+help/PythonExamples/pleac_python/datesandtimes.html
+help/PythonExamples/pleac_python/directories.html
+help/PythonExamples/pleac_python/filecontents.html
+help/PythonExamples/pleac_python/a1102.html
+help/PythonExamples/pleac_python/fileaccess.html
+help/PythonExamples/pleac_python/processmanagementetc.html
+help/PythonExamples/pleac_python/sockets.html
+help/PythonExamples/pleac_python/internetservices.html
+help/PythonExamples/pleac_python/packagesetc.html
+help/PythonExamples/pleac_python/numbers.html
+help/PythonExamples/pleac_python/userinterfaces.html
+help/PythonExamples/pleac_python/classesetc.html
+help/PythonExamples/pleac_python/referencesandrecords.html
+help/PythonExamples/pleac_python/index.html
+help/PythonExamples/pleac_python/dbaccess.html
+help/PythonExamples/pleac_python/cgiprogramming.html
+help/PythonExamples/pleac_python/hashes.html
+help/PythonExamples/pleac_python/strings.html
+help/PythonExamples/pleac_python/webautomation.html
+help/PythonExamples/pleac_python/arrays.html
+help/PythonExamples/pleac_python/subroutines.html
+help/PythonExamples/pleac_python/patternmatching.html
+help/CSS/Accessible_Design.css
+help/Pygtk2Tutorial/library/library.info
+help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkNotebook.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-TablePackingExample.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-Curves.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-PlugsAndSockets.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-GenericTreeModel.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-MenuItems.html
+help/Pygtk2Tutorial/pygtk2tutorial/ch-Introduction.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-Toolbar.html
+help/Pygtk2Tutorial/pygtk2tutorial/ch-DragAndDrop.html
+help/Pygtk2Tutorial/pygtk2tutorial/ch-TipsForWritingPyGTKApplications.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-DNDProperties.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-RadioButtons.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-WidgetsWithoutWindows.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkCurve.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-DrawingMethods.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkList.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-GenericCellRenderer.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-WidgetAccelerators.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-Layout.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-ComboBoxAndComboboxEntry.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-EventHandling.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-ScaleWidgets.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkWidget.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-ButtonBoxes.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkWindow.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-ManipulatingTreeViews.html
+help/Pygtk2Tutorial/pygtk2tutorial/ch-TextViewWidget.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-GammaCurve.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-ToggleButtons.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-Notebooks.html
+help/Pygtk2Tutorial/pygtk2tutorial/ch-ContainerWidgets.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-Dialogs.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-EntryCompletion.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-ExampleRcFile.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-TextMarks.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkData.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-UsingAdjustmentsTheEasyWay.html
+help/Pygtk2Tutorial/pygtk2tutorial/ch-RangeWidgets.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-UpgradedHelloWorld.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-OriginalGTK+Credits.html
+help/Pygtk2Tutorial/pygtk2tutorial/ch-PackingWidgets.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkHandleBox.html
+help/Pygtk2Tutorial/pygtk2tutorial/ch-TimeoutsIOAndIdleFunctions.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-TreeViewDragAndDrop.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-SteppingThroughHelloWorld.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-ColorButtonAndFontButton.html
+help/Pygtk2Tutorial/pygtk2tutorial/ch-AdvancedEventAndSignalHandling.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkColorSelection.html
+help/Pygtk2Tutorial/pygtk2tutorial/ch-TreeViewWidget.html
+help/Pygtk2Tutorial/pygtk2tutorial/app-GtkSignals.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-TreeViewColumns.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-Events.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-Fixed.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-TreeModelInterface.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-FontSelectionDialog.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-MonitoringIO.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-Arrows.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-IdleFunctions.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-Calendar.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-FileChoosers.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-ProgressBars.html
+help/Pygtk2Tutorial/pygtk2tutorial/ch-Credits.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-GTKRcFileFormat.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-AdjustmentInternals.html
+help/Pygtk2Tutorial/pygtk2tutorial/ch-Contributing.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-SignalEmissionAndPropagation.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-FileSelections.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-Alignment.html
+help/Pygtk2Tutorial/pygtk2tutorial/ch-NewInPyGTK2.2.html
+help/Pygtk2Tutorial/pygtk2tutorial/ch-MiscellaneousWidgets.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkItem.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-CellRenderers.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-Frames.html
+help/Pygtk2Tutorial/pygtk2tutorial/ch-Adjustments.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkMenuItem.html
+help/Pygtk2Tutorial/pygtk2tutorial/ch-DrawingArea.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-WidgetDisplayMethods.html
+help/Pygtk2Tutorial/pygtk2tutorial/ch-UndocumentedWidgets.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkButton.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-Statusbars.html
+help/Pygtk2Tutorial/pygtk2tutorial/ch-SettingWidgetAttributes.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-Images.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-UsingItemFactory.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkInputDialog.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-SupplyingTheSelection.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-TreeViews.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-TextIters.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-WidgetNameMethods.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-CheckButtons.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-OptionMenu.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkToggleButton.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-MessageDialog.html
+help/Pygtk2Tutorial/pygtk2tutorial/ch-ManagingSelections.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-RetrievingTheSelection.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-TextTagsAndTextTagTables.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkMenuShell.html
+help/Pygtk2Tutorial/pygtk2tutorial/index.html
+help/Pygtk2Tutorial/pygtk2tutorial/ch-GtkRcFiles.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-TooltipsObject.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-DetailsOfBoxes.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-WidgetStyles.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-TextViewExample.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-ColorSelection.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkAdjustment.html
+help/Pygtk2Tutorial/pygtk2tutorial/ch-Copyright.html
+help/Pygtk2Tutorial/pygtk2tutorial/app-CodeExamples.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-TextEntries.html
+help/Pygtk2Tutorial/pygtk2tutorial/ch-Scribble.html
+help/Pygtk2Tutorial/pygtk2tutorial/ch-MenuWidget.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkContainer.html
+help/Pygtk2Tutorial/pygtk2tutorial/ch-MovingOn.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-TheoryOfSignalsAndCallbacks.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-Rulers.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-UIManager.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-TreeModelSortAndTreeModelFilter.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkStatusBar.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-PackingDemonstrationProgram.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-AspectFrames.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-DrawingAreaWidgetAndDrawing.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-TextViews.html
+help/Pygtk2Tutorial/pygtk2tutorial/ch-WidgetOverview.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-DNDMethods.html
+help/Pygtk2Tutorial/pygtk2tutorial/ch-NewInPyGTK2.4.html
+help/Pygtk2Tutorial/pygtk2tutorial/pygtk-tut-changelog.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-SpinButtons.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-RangeWidgetEample.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-ScrolledWindows.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-ComboWidget.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkToolbar.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-ManualMenuExample.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-CommonRangeMethods.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-TreeViewSignals.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkCalendar.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-ExpanderWidget.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkEditable.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-KeyAndMouseBindings.html
+help/Pygtk2Tutorial/pygtk2tutorial/ch-ButtonWidget.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-PanedWindowWidgets.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-PackingUsingTables.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkCheckMenuItem.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-Viewports.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-TextBuffers.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-ItemFactoryExample.html
+help/Pygtk2Tutorial/pygtk2tutorial/sec-TreeSelections.html
+help/Pygtk2Tutorial/pygtk2tutorial/ch-GettingStarted.html
+help/Pygtk2Tutorial/pygtk2tutorial/figures/base.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/basicaction.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/setselection.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/comboboxbasic.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/actions.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/actiongroup.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/treeviewcolumn.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/entry.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/menu.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/celldatafunc.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/testtext.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/textview-basic.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/tooltips.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/celltextmarkup.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/checkbutton.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/statusbar.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/fontbutton.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/toolbar.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/button.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/labels.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/table.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/packbox1.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/fontselection.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/getselection.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/spinbutton.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/comboboxentrybasic.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/packbox3.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/colorbutton.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/pixmap.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/eventbox.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/cellrenderer.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/colorselection.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/treeviewdnd.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/scrolledwin.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/uimanager.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/scribblesimple.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/fixed.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/paned.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/filelisting-gtm.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/layout.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/comboboxwrap.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/expander.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/frame.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/basictreeview.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/packbox2.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/treemodelfilter.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/radiobutton.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/calendar.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/buttonbox.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/images.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/toggle.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/treemodelsort.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/notebook.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/progressbar.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/drawingarea.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/treeviewcolumn1expander.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/filechooser.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/entrycompletion.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/fileselection.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/simpleaction.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/rangewidgets.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/clipboard.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/uimerge.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/aspectframe.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/helloworld.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/filelisting.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/rulers.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/arrows.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/helloworld2.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/dragndrop.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/itemfactory.png
+help/Pygtk2Tutorial/pygtk2tutorial/figures/wheelbarrow.png
+git/pippy-activity/activity.py
+git/pippy-activity/NEWS
+git/pippy-activity/pippy_app.py
+git/pippy-activity/setup.py
+git/pippy-activity/.git/index
+git/pippy-activity/.git/HEAD
+git/pippy-activity/.git/description
+git/pippy-activity/.git/config
+git/pippy-activity/.git/packed-refs
+git/pippy-activity/.git/info/exclude
+git/pippy-activity/.git/logs/HEAD
+git/pippy-activity/.git/logs/refs/heads/master
+git/pippy-activity/.git/logs/refs/remotes/origin/HEAD
+git/pippy-activity/.git/refs/heads/master
+git/pippy-activity/.git/refs/remotes/origin/HEAD
+git/pippy-activity/.git/objects/pack/pack-35078d80eff5548f8bff56e4e9d1e1398c5ee9c3.idx
+git/pippy-activity/.git/objects/pack/pack-35078d80eff5548f8bff56e4e9d1e1398c5ee9c3.pack
+git/pippy-activity/.git/hooks/pre-applypatch.sample
+git/pippy-activity/.git/hooks/commit-msg.sample
+git/pippy-activity/.git/hooks/applypatch-msg.sample
+git/pippy-activity/.git/hooks/update.sample
+git/pippy-activity/.git/hooks/post-commit.sample
+git/pippy-activity/.git/hooks/prepare-commit-msg.sample
+git/pippy-activity/.git/hooks/pre-rebase.sample
+git/pippy-activity/.git/hooks/pre-commit.sample
+git/pippy-activity/.git/hooks/post-update.sample
+git/pippy-activity/.git/hooks/post-receive.sample
+git/pippy-activity/library/pippy/__init__.py
+git/pippy-activity/library/pippy/sound.py
+git/pippy-activity/library/pippy/query.py
+git/pippy-activity/library/pippy/console.py
+git/pippy-activity/library/pippy/game.py
+git/pippy-activity/library/pippy/physics/locals.py
+git/pippy-activity/library/pippy/physics/__init__.py
+git/pippy-activity/library/pippy/physics/camera.py
+git/pippy-activity/library/pippy/physics/tools_poly.py
+git/pippy-activity/library/pippy/physics/tools.py
+git/pippy-activity/library/pippy/physics/elements.py
+git/pippy-activity/library/pippy/physics/callbacks.py
+git/pippy-activity/library/pippy/physics/Box2D2.py
+git/pippy-activity/library/pippy/physics/add_objects.py
+git/pippy-activity/library/pippy/physics/menu.py
+git/pippy-activity/library/pippy/physics/drawing.py
+git/pippy-activity/library/pippy/physics/box2d/__init__.py
+git/pippy-activity/library/pippy/physics/box2d/box2d_linux32/__init__.py
+git/pippy-activity/library/pippy/physics/box2d/box2d_linux32/Box2D2.py
+git/pippy-activity/library/pippy/physics/box2d/box2d_linux32/_Box2D2.so
+git/pippy-activity/library/pippy/physics/box2d/box2d_linux64/__init__.py
+git/pippy-activity/library/pippy/physics/box2d/box2d_linux64/Box2D2.py
+git/pippy-activity/library/pippy/physics/box2d/box2d_linux64/_Box2D2.so
+git/pippy-activity/data/python/interpreter
+git/pippy-activity/data/python/recursion
+git/pippy-activity/data/python/if
+git/pippy-activity/data/python/function
+git/pippy-activity/data/sound/sequence
+git/pippy-activity/data/sound/playSine
+git/pippy-activity/data/sound/getSoundList
+git/pippy-activity/data/sound/playWave
+git/pippy-activity/data/graphics/pong
+git/pippy-activity/data/graphics/camera
+git/pippy-activity/data/graphics/physics
+git/pippy-activity/data/graphics/bounce
+git/pippy-activity/data/graphics/lines
+git/pippy-activity/data/graphics/jump
+git/pippy-activity/data/graphics/slideshow
+git/pippy-activity/data/graphics/tree
+git/pippy-activity/data/graphics/snow
+git/pippy-activity/data/string/hello
+git/pippy-activity/data/string/thanks
+git/pippy-activity/data/math/fibonacci
+git/pippy-activity/data/math/times
+git/pippy-activity/data/math/sierpinski
+git/pippy-activity/data/math/pascal
+git/pippy-activity/data/math/guess
+git/pippy-activity/po/rw.po
+git/pippy-activity/po/pap.po
+git/pippy-activity/po/th.po
+git/pippy-activity/po/zh_CN.po
+git/pippy-activity/po/ug.po
+git/pippy-activity/po/fi.po
+git/pippy-activity/po/ay.po
+git/pippy-activity/po/wa.po
+git/pippy-activity/po/af.po
+git/pippy-activity/po/pa.po
+git/pippy-activity/po/mg.po
+git/pippy-activity/po/sw.po
+git/pippy-activity/po/ur.po
+git/pippy-activity/po/fr.po
+git/pippy-activity/po/tzo.po
+git/pippy-activity/po/nl.po
+git/pippy-activity/po/ml.po
+git/pippy-activity/po/gu.po
+git/pippy-activity/po/sq.po
+git/pippy-activity/po/mk.po
+git/pippy-activity/po/sd.po
+git/pippy-activity/po/kos.po
+git/pippy-activity/po/ja.po
+git/pippy-activity/po/mvo.po
+git/pippy-activity/po/cs.po
+git/pippy-activity/po/ar.po
+git/pippy-activity/po/ko.po
+git/pippy-activity/po/Pippy.pot
+git/pippy-activity/po/mr.po
+git/pippy-activity/po/mn.po
+git/pippy-activity/po/he.po
+git/pippy-activity/po/en.po
+git/pippy-activity/po/ht.po
+git/pippy-activity/po/fa.po
+git/pippy-activity/po/mi.po
+git/pippy-activity/po/bn_IN.po
+git/pippy-activity/po/es.po
+git/pippy-activity/po/id.po
+git/pippy-activity/po/bg.po
+git/pippy-activity/po/da.po
+git/pippy-activity/po/is.po
+git/pippy-activity/po/en_US.po
+git/pippy-activity/po/ta.po
+git/pippy-activity/po/ps.po
+git/pippy-activity/po/am.po
+git/pippy-activity/po/ha.po
+git/pippy-activity/po/pis.po
+git/pippy-activity/po/te.po
+git/pippy-activity/po/cpp.po
+git/pippy-activity/po/hi.po
+git/pippy-activity/po/qu.po
+git/pippy-activity/po/bi.po
+git/pippy-activity/po/ca.po
+git/pippy-activity/po/pt.po
+git/pippy-activity/po/ms.po
+git/pippy-activity/po/ro.po
+git/pippy-activity/po/ff.po
+git/pippy-activity/po/sl.po
+git/pippy-activity/po/km.po
+git/pippy-activity/po/bn.po
+git/pippy-activity/po/tr.po
+git/pippy-activity/po/pt_BR.po
+git/pippy-activity/po/yo.po
+git/pippy-activity/po/si.po
+git/pippy-activity/po/sk.po
+git/pippy-activity/po/vi.po
+git/pippy-activity/po/zh_TW.po
+git/pippy-activity/po/el.po
+git/pippy-activity/po/hu.po
+git/pippy-activity/po/tpi.po
+git/pippy-activity/po/ru.po
+git/pippy-activity/po/nb.po
+git/pippy-activity/po/dz.po
+git/pippy-activity/po/ne.po
+git/pippy-activity/po/it.po
+git/pippy-activity/po/fa_AF.po
+git/pippy-activity/po/de.po
+git/pippy-activity/po/sv.po
+git/pippy-activity/po/pl.po
+git/pippy-activity/po/ig.po
+git/pippy-activity/activity/activity-default.svg
+git/pippy-activity/activity/activity-icon.svg
+git/pippy-activity/activity/activity.info
+locale/th/activity.linfo
+locale/th/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/ne/activity.linfo
+locale/ne/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/sk/activity.linfo
+locale/sk/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/el/activity.linfo
+locale/el/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/ig/activity.linfo
+locale/ig/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/en/activity.linfo
+locale/en/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/bi/activity.linfo
+locale/bi/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/sl/activity.linfo
+locale/sl/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/mk/activity.linfo
+locale/mk/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/yo/activity.linfo
+locale/yo/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/en_US/activity.linfo
+locale/en_US/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/ro/activity.linfo
+locale/ro/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/zh_TW/activity.linfo
+locale/zh_TW/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/mi/activity.linfo
+locale/mi/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/ml/activity.linfo
+locale/ml/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/ms/activity.linfo
+locale/ms/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/ff/activity.linfo
+locale/ff/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/ja/activity.linfo
+locale/ja/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/pt/activity.linfo
+locale/pt/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/bn_IN/activity.linfo
+locale/bn_IN/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/ps/activity.linfo
+locale/ps/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/zh_CN/activity.linfo
+locale/zh_CN/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/dz/activity.linfo
+locale/dz/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/fa_AF/activity.linfo
+locale/fa_AF/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/hu/activity.linfo
+locale/hu/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/am/activity.linfo
+locale/am/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/te/activity.linfo
+locale/te/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/is/activity.linfo
+locale/is/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/sw/activity.linfo
+locale/sw/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/gu/activity.linfo
+locale/gu/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/bg/activity.linfo
+locale/bg/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/ha/activity.linfo
+locale/ha/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/sv/activity.linfo
+locale/sv/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/es/activity.linfo
+locale/es/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/mn/activity.linfo
+locale/mn/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/wa/activity.linfo
+locale/wa/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/pis/activity.linfo
+locale/pis/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/it/activity.linfo
+locale/it/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/bn/activity.linfo
+locale/bn/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/ko/activity.linfo
+locale/ko/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/mvo/activity.linfo
+locale/mvo/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/ht/activity.linfo
+locale/ht/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/pap/activity.linfo
+locale/pap/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/km/activity.linfo
+locale/km/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/ug/activity.linfo
+locale/ug/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/fr/activity.linfo
+locale/fr/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/ar/activity.linfo
+locale/ar/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/fi/activity.linfo
+locale/fi/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/he/activity.linfo
+locale/he/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/sd/activity.linfo
+locale/sd/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/hi/activity.linfo
+locale/hi/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/pa/activity.linfo
+locale/pa/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/tpi/activity.linfo
+locale/tpi/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/mr/activity.linfo
+locale/mr/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/cpp/activity.linfo
+locale/cpp/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/ru/activity.linfo
+locale/ru/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/vi/activity.linfo
+locale/vi/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/cs/activity.linfo
+locale/cs/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/qu/activity.linfo
+locale/qu/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/af/activity.linfo
+locale/af/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/ca/activity.linfo
+locale/ca/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/pt_BR/activity.linfo
+locale/pt_BR/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/rw/activity.linfo
+locale/rw/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/nl/activity.linfo
+locale/nl/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/nb/activity.linfo
+locale/nb/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/ay/activity.linfo
+locale/ay/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/fa/activity.linfo
+locale/fa/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/ur/activity.linfo
+locale/ur/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/de/activity.linfo
+locale/de/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/pl/activity.linfo
+locale/pl/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/si/activity.linfo
+locale/si/LC_MESSAGES/com.gmail.georgejhunt.mo
+locale/tr/activity.linfo
+locale/tr/LC_MESSAGES/com.gmail.georgejhunt.mo
+lib/python2.5/site-packages/sugar/graphics/colorbutton.py
+lib/python2.6/site-packages/terminal.py
+lib/python2.6/site-packages/browser.py
+lib/python2.6/site-packages/sugar.save/activity/activityshim.py
+lib/python2.6/site-packages/sugar.save/activity/olpcactivity.pth
+examples/bundle-2.xo
+examples/HelloWorld.activity/HelloWorldActivity.py
+examples/HelloWorld.activity/setup.py
+examples/HelloWorld.activity/activity/activity-helloworld.svg
+examples/HelloWorld.activity/activity/activity.info
+examples/Aide.activity/progresslistener.py
+examples/Aide.activity/LICENSE
+examples/Aide.activity/browser.py
+examples/Aide.activity/NEWS
+examples/Aide.activity/helpactivity.py
+examples/Aide.activity/setup.py
+examples/Aide.activity/README
+examples/Aide.activity/TODO
+examples/Aide.activity/help/XO_Comment_Flasher.html
+examples/Aide.activity/help/XO_FAQ.html
+examples/Aide.activity/help/XO_Charger_la_batterie.html
+examples/Aide.activity/help/Sugar_Collaborer.html
+examples/Aide.activity/help/XO_Apropos_Reseaux_Internet.html
+examples/Aide.activity/help/XO_Materiel_Externe.html
+examples/Aide.activity/help/XO_Apropos_de_ce_Manuel.html
+examples/Aide.activity/help/Sugar_Installer_Activites.html
+examples/Aide.activity/help/Remerciements.html
+examples/Aide.activity/help/Sugar_Trouver_Activites.html
+examples/Aide.activity/help/XO_Specifications_Materielles.html
+examples/Aide.activity/help/XO_Resolution_Problemes.html
+examples/Aide.activity/help/XO_Reparer.html
+examples/Aide.activity/help/Sugar_Sauvegarde.html
+examples/Aide.activity/help/manuel.css
+examples/Aide.activity/help/Sugar_Vue_Voisinage.html
+examples/Aide.activity/help/XO_Prendre_soin_du_XO.html
+examples/Aide.activity/help/Sugar_Basculer_Activites.html
+examples/Aide.activity/help/XO_Ecran_Ecouteurs.html
+examples/Aide.activity/help/XO_Introduction.html
+examples/Aide.activity/help/Sugar_Vue_Groupe.html
+examples/Aide.activity/help/XO_Tableau_Sans_Fil.html
+examples/Aide.activity/help/Sugar_Vue_Activite.html
+examples/Aide.activity/help/Sugar_Glossaire.html
+examples/Aide.activity/help/Sugar_Lancer_Activites.html
+examples/Aide.activity/help/XO_Raccourcis_Clavier.html
+examples/Aide.activity/help/Sugar_Conserver_Espace_Disque.html
+examples/Aide.activity/help/XO_Connectique.html
+examples/Aide.activity/help/Sugar_Audela_Activites.html
+examples/Aide.activity/help/Sugar_Le_Cadre.html
+examples/Aide.activity/help/XO_Stockage_Externe.html
+examples/Aide.activity/help/XO_Support.html
+examples/Aide.activity/help/XO_Apropos_Ordinateurs.html
+examples/Aide.activity/help/Sugar_Vue_Accueil.html
+examples/Aide.activity/help/XO_Pour_commencer.html
+examples/Aide.activity/help/XO_Maintenance.html
+examples/Aide.activity/help/Sugar_Connecter_Reseaux.html
+examples/Aide.activity/help/index.html
+examples/Aide.activity/help/Sugar_Quitter_Activites.html
+examples/Aide.activity/help/Sugar_Le_Journal.html
+examples/Aide.activity/help/index.css
+examples/Aide.activity/help/XO_Apropos_de_OLPC.html
+examples/Aide.activity/help/XO_Demarrage.html
+examples/Aide.activity/help/XO_Remplacer_Batterie.html
+examples/Aide.activity/help/GPL.html
+examples/Aide.activity/help/XO_Clavier.html
+examples/Aide.activity/help/Licence.html
+examples/Aide.activity/help/XO_Ouvrir_XO.html
+examples/Aide.activity/help/Sugar_Activite.html
+examples/Aide.activity/help/XO_Energie_Avance.html
+examples/Aide.activity/help/XO_Comment_Participer.html
+examples/Aide.activity/help/Sugar_Personnaliser.html
+examples/Aide.activity/help/Sugar_Introduction.html
+examples/Aide.activity/help/XO_Donnez_moi_Internet.html
+examples/Aide.activity/help/XO/leftports.jpg
+examples/Aide.activity/help/XO/.resized_600x231_800px_Keyboard_english.png
+examples/Aide.activity/help/XO/rightports2.jpg
+examples/Aide.activity/help/XO/resized_400x300_plainjournal.png
+examples/Aide.activity/help/XO/xolaptop_open_flat_2.png
+examples/Aide.activity/help/XO/keyboard.jpg
+examples/Aide.activity/help/XO/resized_600x150_spin_xo.jpg
+examples/Aide.activity/help/XO/.resized_400x147_broadbandroutersettings.jpg
+examples/Aide.activity/help/XO/.resized_600x398_topobox.jpg
+examples/Aide.activity/help/XO/leftsidefeatures.jpg
+examples/Aide.activity/help/XO/resized_76x76_unmountsd.png
+examples/Aide.activity/help/XO/resized_100x93_frameindicator.jpg
+examples/Aide.activity/help/XO/resized_400x147_broadbandroutersettings.jpg
+examples/Aide.activity/help/XO/resized_600x163_olpclogo.jpg
+examples/Aide.activity/help/XO/resized_400x154_Four_finger_salute.jpg
+examples/Aide.activity/help/XO/resized_600x398_xobattery.jpg
+examples/Aide.activity/help/XO/resized_400x300_highlightedssid.png
+examples/Aide.activity/help/XO/resized_600x398_sdcardinsertion.png
+examples/Aide.activity/help/XO/.resized_600x398_xobattery.jpg
+examples/Aide.activity/help/XO/.resized_400x174_wirelessroutersettings.jpg
+examples/Aide.activity/help/XO/Picture_67.png
+examples/Aide.activity/help/XO/volume_light.png
+examples/Aide.activity/help/XO/resized_303x154_journalfreespace.png
+examples/Aide.activity/help/XO/resized_400x174_wirelessroutersettings.jpg
+examples/Aide.activity/help/XO/.resized_400x300_highlightedssid.png
+examples/Aide.activity/help/XO/rightsidefeatures.jpg
+examples/Aide.activity/help/XO/.resized_600x398_xoboxcontents.jpg
+examples/Aide.activity/help/XO/.resized_400x300_8.2neighborhoodview.png
+examples/Aide.activity/help/XO/resized_400x300_erase.png
+examples/Aide.activity/help/XO/resized_600x398_topobox.jpg
+examples/Aide.activity/help/XO/resized_600x398_xoboxcontents.jpg
+examples/Aide.activity/help/XO/resized_400x26_journal_launch.png
+examples/Aide.activity/help/XO/.resized_600x150_spin_xo.jpg
+examples/Aide.activity/help/XO/.resized_600x163_olpclogo.jpg
+examples/Aide.activity/help/XO/resized_400x300_8.2neighborhoodview.png
+examples/Aide.activity/help/XO/starting/shutdown.png
+examples/Aide.activity/help/XO/GiveMeTheInternet/Picture 71_1.png
+examples/Aide.activity/help/XO/GiveMeTheInternet/Picture_63.png
+examples/Aide.activity/help/XO/GiveMeTheInternet/Picture_60.png
+examples/Aide.activity/help/XO/GiveMeTheInternet/Picture_59.png
+examples/Aide.activity/help/XO/GiveMeTheInternet/Picture_56.png
+examples/Aide.activity/help/XO/GiveMeTheInternet/resized_100x93_frameindicator.jpg
+examples/Aide.activity/help/XO/GiveMeTheInternet/Picture_64.png
+examples/Aide.activity/help/XO/GiveMeTheInternet/resized_84x62_needsconnecting.jpg
+examples/Aide.activity/help/XO/GiveMeTheInternet/resized_79x63_alreadyconnected.jpg
+examples/Aide.activity/help/XO/GiveMeTheInternet/Picture_57.png
+examples/Aide.activity/help/XO/GiveMeTheInternet/Picture_54.png
+examples/Aide.activity/help/XO/GiveMeTheInternet/Picture_50.png
+examples/Aide.activity/help/XO/GiveMeTheInternet/simple_mesh.png
+examples/Aide.activity/help/XO/GiveMeTheInternet/.resized_100x93_frameindicator.jpg
+examples/Aide.activity/help/XO/GiveMeTheInternet/Picture_61.png
+examples/Aide.activity/help/XO/GiveMeTheInternet/Picture_58.png
+examples/Aide.activity/help/XO/GiveMeTheInternet/infrustructure.png
+examples/Aide.activity/help/XO/GiveMeTheInternet/Picture_49.png
+examples/Aide.activity/help/XO/GiveMeTheInternet/Picture_48.png
+examples/Aide.activity/help/XO/Troubleshooting/resized_400x147_broadbandroutersettings.jpg
+examples/Aide.activity/help/XO/Troubleshooting/resized_400x300_highlightedssid.png
+examples/Aide.activity/help/XO/Troubleshooting/Picture_67.png
+examples/Aide.activity/help/XO/Troubleshooting/resized_400x174_wirelessroutersettings.jpg
+examples/Aide.activity/help/XO/Troubleshooting/resized_400x300_8.2neighborhoodview.png
+examples/Aide.activity/help/Sugar/switch2.png
+examples/Aide.activity/help/Sugar/activity_view_6_1.png
+examples/Aide.activity/help/Sugar/frame_menu_small.png
+examples/Aide.activity/help/Sugar/stop2.png
+examples/Aide.activity/help/Sugar/launch_from_ring.png
+examples/Aide.activity/help/Sugar/connected.png
+examples/Aide.activity/help/Sugar/neighborhood_view_connected_menu_1.png
+examples/Aide.activity/help/Sugar/view_buttons_neighborhood_selected.png
+examples/Aide.activity/help/Sugar/launching_from_invitation_1.png
+examples/Aide.activity/help/Sugar/200px_Frame_detail_status.png
+examples/Aide.activity/help/Sugar/journal_USB.png
+examples/Aide.activity/help/Sugar/resized_400x300_filelittlebopeep.png
+examples/Aide.activity/help/Sugar/view_buttons_activity_selected.png
+examples/Aide.activity/help/Sugar/copy_to_USB.png
+examples/Aide.activity/help/Sugar/resized_400x300_Terminalmvfile.png
+examples/Aide.activity/help/Sugar/activity_view_4.png
+examples/Aide.activity/help/Sugar/view_buttons_group_selected.png
+examples/Aide.activity/help/Sugar/launch_from_list.png
+examples/Aide.activity/help/Sugar/AP_blink.gif
+examples/Aide.activity/help/Sugar/friend_2.png
+examples/Aide.activity/help/Sugar/home_view_ring_view_menu_small.png
+examples/Aide.activity/help/Sugar/journal_detail_view.png
+examples/Aide.activity/help/Sugar/activity_view_3_1.png
+examples/Aide.activity/help/Sugar/journal_main_screen.png
+examples/Aide.activity/help/Sugar/home_view_menu.png
+examples/Aide.activity/help/Sugar/600px_Neighborhood_view_selecting_AP.png
+examples/Aide.activity/help/Sugar/activity_view_5_1.png
+examples/Aide.activity/help/Sugar/lock_badge.png
+examples/Aide.activity/help/Sugar/AP_lock.png
+examples/Aide.activity/help/Sugar/resized_400x300_469_600w.png
+examples/Aide.activity/help/Sugar/launch_from_journal.png
+examples/Aide.activity/help/Sugar/600px_Neighborhood_view_with_hover_menu.png
+examples/Aide.activity/help/Sugar/view_buttons_home_selected.png
+examples/Aide.activity/help/Sugar/resized_75x75_unmount.png
+examples/Aide.activity/help/Sugar/600px_Startup.png
+examples/Aide.activity/help/Sugar/Wireless_key_required.png
+examples/Aide.activity/help/Sugar/neighborhood_view_checking_newtork_status_with_hover_menu_small.png
+examples/Aide.activity/help/Sugar/friend_invite.png
+examples/Aide.activity/help/Sugar/600px_Neighborhood_view.png
+examples/Aide.activity/help/Sugar/journal1.png
+examples/Aide.activity/help/Sugar/Home_View_List.png
+examples/Aide.activity/help/Sugar/resized_600x231_800px_Keyboard_english.png
+examples/Aide.activity/help/Sugar/activity_view_1_3.png
+examples/Aide.activity/help/Sugar/connectedframeindicator.png
+examples/Aide.activity/help/Sugar/Screenshot3.png
+examples/Aide.activity/help/Sugar/Mesh_icon.png
+examples/Aide.activity/help/Sugar/Neighborhood_key.png
+examples/Aide.activity/help/Sugar/activity_view_2a_1.png
+examples/Aide.activity/help/Sugar/Freeformview.png
+examples/Aide.activity/help/Sugar/neighborhoodview_fromhome_resized_240px_1.png
+examples/Aide.activity/help/Sugar/600px_Neighborhood_view_with_frame_showing_connection_with_hover_menu.png
+examples/Aide.activity/help/Sugar/friend_1.png
+examples/Aide.activity/help/Sugar/launch_from_join.png
+examples/Aide.activity/help/Sugar/clipboard.png
+examples/Aide.activity/help/Sugar/stop_activity.png
+examples/Aide.activity/help/Sugar/neighborhood_view_with_frame_connection_hover_details_small.png
+examples/Aide.activity/help/Sugar/copy_from_USB.png
+examples/Aide.activity/help/Sugar/friend_remove.png
+examples/Aide.activity/help/Sugar/favorite_connection.png
+examples/Aide.activity/help/Sugar/resized_400x300_snee.com.png
+examples/Aide.activity/help/Sugar/switch3.png
+examples/Aide.activity/help/Sugar/AP_level.png
+examples/Aide.activity/help/Sugar/unmount.png
+examples/Aide.activity/help/Sugar/switch4.png
+examples/Aide.activity/help/Sugar/switch1.png
+examples/Aide.activity/help/Sugar/make_a_friend.png
+examples/Aide.activity/help/Sugar/Journal_resume.png
+examples/Aide.activity/help/Sugar/Personalising/network_s.png
+examples/Aide.activity/help/Sugar/Personalising/about_me_s.png
+examples/Aide.activity/help/Sugar/Personalising/Langue_1.png
+examples/Aide.activity/help/Sugar/Personalising/frame_s.png
+examples/Aide.activity/help/Sugar/Personalising/language_s.png
+examples/Aide.activity/help/Sugar/Personalising/Alimentation_1.png
+examples/Aide.activity/help/Sugar/Personalising/su_modify_s.png
+examples/Aide.activity/help/Sugar/Personalising/Panneau_de_controle.png
+examples/Aide.activity/help/Sugar/Personalising/su_checking_s.png
+examples/Aide.activity/help/Sugar/Personalising/Acc__s_panneau_de_controle.png
+examples/Aide.activity/help/Sugar/Personalising/power_s.png
+examples/Aide.activity/help/Sugar/Personalising/Date et heure_1.png
+examples/Aide.activity/help/Sugar/Personalising/Mon XO_1.png
+examples/Aide.activity/help/Sugar/Personalising/scp_s.png
+examples/Aide.activity/help/Sugar/Personalising/Cadre_1.png
+examples/Aide.activity/help/Sugar/Personalising/about_my_xo_s.png
+examples/Aide.activity/help/Sugar/Personalising/su_downloading_s.png
+examples/Aide.activity/help/Sugar/Personalising/su_updated_s.png
+examples/Aide.activity/help/Sugar/Personalising/datetime_s.png
+examples/Aide.activity/help/Sugar/Personalising/Moi_1.png
+examples/Aide.activity/help/Sugar/Personalising/Picture_76.png
+examples/Aide.activity/help/Sugar/Personalising/su_choose_s.png
+examples/Aide.activity/help/Sugar/Personalising/open.png
+examples/Aide.activity/help/Sugar/Browse/ContributeToWikipedia/wikbike.png
+examples/Aide.activity/help/Sugar/Browse/ContributeToWikipedia/save.png
+examples/Aide.activity/help/Sugar/Browse/ContributeToWikipedia/edit.png
+examples/Aide.activity/help/Sugar/Browse/ContributeToWikipedia/edit2.png
+examples/Aide.activity/help/Sugar/Browse/Bookmarks/sugar.png
+examples/Aide.activity/help/Sugar/Browse/Bookmarks/bookmarked.png
+examples/Aide.activity/help/Sugar/Browse/Search/search.png
+examples/Aide.activity/help/Sugar/Browse/BrowsingWeb/min.png
+examples/Aide.activity/help/Sugar/Browse/BrowsingWeb/browsebigtext.png
+examples/Aide.activity/help/Sugar/Browse/BrowsingWeb/wikipedia.png
+examples/Aide.activity/help/Sugar/Browse/BrowsingWeb/magnifying.png
+examples/Aide.activity/help/Sugar/Browse/BrowsingWeb/hand.png
+examples/Aide.activity/help/Sugar/Browse/BrowsingWeb/fullscreen.png
+examples/Aide.activity/help/Sugar/Browse/BrowsingWeb/locatationbar.png
+examples/Aide.activity/help/Sugar/Browse/BrowsingWeb/view.png
+examples/Aide.activity/help/Sugar/Browse/BrowsingWeb/enwiki.png
+examples/Aide.activity/help/Sugar/Browse/ArtinAllofUs/countryquiz.png
+examples/Aide.activity/help/Sugar/Browse/UsingWikipedia/searchwiki.png
+examples/Aide.activity/help/Sugar/Browse/UsingWikipedia/enwiki2.png
+examples/Aide.activity/help/Sugar/Browse/UsingWikipedia/wikipedia.png
+examples/Aide.activity/help/Sugar/Browse/StartingBrowse/startbrowse_2_1.png
+examples/Aide.activity/help/Sugar/Browse/StartingBrowse/listview.png
+examples/Aide.activity/help/Sugar/Browse/StartingBrowse/.resized_400x300_browse_homeolpcfiles.jpg
+examples/Aide.activity/help/Sugar/Browse/StartingBrowse/browselist.png
+examples/Aide.activity/help/Sugar/Browse/StartingBrowse/startbrowse_1_1.png
+examples/Aide.activity/help/Sugar/Browse/StartingBrowse/homeview_1.png
+examples/Aide.activity/help/Sugar/Browse/SharingLinks/share.png
+examples/Aide.activity/help/Sugar/Browse/SharingLinks/activity.png
+examples/Aide.activity/help/Sugar/Browse/Introduction/browse.png
+examples/Aide.activity/help/Sugar/casestudies/resized_400x300_fbreader.png
+examples/Aide.activity/help/Sugar/casestudies/resized_106x91_turtle_art_samples.png
+examples/Aide.activity/help/Sugar/casestudies/photoframe.JPG
+examples/Aide.activity/help/Sugar/casestudies/resized_400x300_turtle_art_birds.png
+examples/Aide.activity/help/Sugar/casestudies/resized_400x178_8.2browsestartcrop.png
+examples/Aide.activity/help/Sugar/casestudies/resized_400x40_turtle_art_projects.png
+examples/Aide.activity/help/Sugar/casestudies/resized_400x300_turtle_art_started_1.png
+examples/Aide.activity/help/Sugar/casestudies/xo_school.JPG
+examples/Aide.activity/help/Sugar/casestudies/resized_303x236_turtle_art_load.png
+examples/Aide.activity/help/Sugar/InstallingActivities/measure.gif
+examples/Aide.activity/help/Sugar/InstallingActivities/tamtammini.gif
+examples/Aide.activity/help/Sugar/InstallingActivities/calculate_1.gif
+examples/Aide.activity/help/Sugar/InstallingActivities/sugar_x11.gif
+examples/Aide.activity/help/Sugar/InstallingActivities/etoys.gif
+examples/Aide.activity/help/Sugar/InstallingActivities/activity-icons_1.png
+examples/Aide.activity/help/Sugar/InstallingActivities/memorize.gif
+examples/Aide.activity/help/Sugar/InstallingActivities/synthLab.gif
+examples/Aide.activity/help/Sugar/InstallingActivities/pippy.gif
+examples/Aide.activity/help/Sugar/InstallingActivities/browse.gif
+examples/Aide.activity/help/Sugar/InstallingActivities/chat_1.gif
+examples/Aide.activity/help/Sugar/InstallingActivities/distance.gif
+examples/Aide.activity/help/Sugar/InstallingActivities/ebook_reader.gif
+examples/Aide.activity/help/Sugar/InstallingActivities/record2.gif
+examples/Aide.activity/help/Sugar/InstallingActivities/draw.gif
+examples/Aide.activity/help/Sugar/InstallingActivities/journal.gif
+examples/Aide.activity/help/Sugar/InstallingActivities/tamtamjam_2.gif
+examples/Aide.activity/help/Sugar/InstallingActivities/tamtamedit.gif
+examples/Aide.activity/help/Sugar/InstallingActivities/write.gif
+examples/Aide.activity/help/Sugar/InstallingActivities/turtleArt.gif
+examples/Aide.activity/help/Sugar/share/sharing_2.png
+examples/Aide.activity/help/Sugar/share/chat_image_9.png
+examples/Aide.activity/help/Sugar/share/chat_invite_5.png
+examples/Aide.activity/help/Sugar/share/chat_image_7.png
+examples/Aide.activity/help/Sugar/share/sharing_5.png
+examples/Aide.activity/help/Sugar/share/sharing_4.png
+examples/Aide.activity/help/Sugar/share/chat_invite_5a.png
+examples/Aide.activity/help/Sugar/share/chat_invite_12.png
+examples/Aide.activity/help/Sugar/share/chat_image_8.png
+examples/Aide.activity/help/Sugar/share/chat_invite_13.png
+examples/Aide.activity/help/Sugar/share/chat_invite_2.png
+examples/Aide.activity/help/Sugar/share/chat_invite_6.png
+examples/Aide.activity/help/Sugar/share/chat_invite_1.png
+examples/Aide.activity/help/Sugar/share/chat_image_10.png
+examples/Aide.activity/help/Sugar/share/sharing_7a.png
+examples/Aide.activity/help/Sugar/share/chat_invite_4.png
+examples/Aide.activity/help/Sugar/share/sharing_1.png
+examples/Aide.activity/help/Sugar/share/sharing_6.png
+examples/Aide.activity/help/Sugar/share/chat_invite_3.png
+examples/Aide.activity/help/Sugar/share/sharing_3.png
+examples/Aide.activity/help/Sugar/Introduction/Home_sharing.png
+examples/Aide.activity/help/Sugar/Introduction/Home_journal.png
+examples/Aide.activity/help/Sugar/Introduction/Home_backup.png
+examples/Aide.activity/help/Sugar/Introduction/RGB_logo_orange_300.png
+examples/Aide.activity/help/Sugar/Introduction/Home_activities.png
+examples/Aide.activity/help/Sugar/Introduction/Home_opensource.png
+examples/Aide.activity/help/Sugar/Introduction/Home_activities_1.png
+examples/Aide.activity/help/Sugar/Interface/zoom.png
+examples/Aide.activity/help/Sugar/Journal/journal_start.png
+examples/Aide.activity/help/Sugar/Journal/download_in_progress.png
+examples/Aide.activity/help/Sugar/Journal/resized_300x19_journal_launch.jpg
+examples/Aide.activity/help/Sugar/Journal/.resized_300x19_journal_launch.jpg
+examples/Aide.activity/help/Sugar/Journal/download_open_in_journal.png
+examples/Aide.activity/help/Sugar/Journal/activities.png
+examples/Aide.activity/help/Sugar/Journal/.resized_400x300_plainjournal.png
+examples/Aide.activity/help/Sugar/Journal/.resized_400x300_erase.png
+examples/Aide.activity/help/XO_for_kids/Feet_and_smile_1_1.jpg
+examples/Aide.activity/help/OLPC_simple/Battery/.resized_200x162_4Battery.png
+examples/Aide.activity/help/OLPC_simple/Battery/resized_200x162_1Battery.png
+examples/Aide.activity/help/OLPC_simple/Battery/.resized_200x162_3Battery.png
+examples/Aide.activity/help/OLPC_simple/Battery/resized_200x162_2Battery.png
+examples/Aide.activity/help/OLPC_simple/Battery/.resized_200x162_1Battery.png
+examples/Aide.activity/help/OLPC_simple/Battery/.resized_200x162_2Battery.png
+examples/Aide.activity/help/OLPC_simple/Battery/resized_200x162_3Battery.png
+examples/Aide.activity/help/OLPC_simple/Battery/resized_200x162_4Battery.png
+examples/Aide.activity/help/OLPC_simple/HowToFlash/Power_button.jpg
+examples/Aide.activity/help/OLPC_simple/TuteBackingUp/.resized_400x300_sdcard.png
+examples/Aide.activity/help/OLPC_simple/TuteBackingUp/resized_400x300_sdcard.png
+examples/Aide.activity/help/OLPC_simple/TuteBackingUp/resized_400x200_terminal_ls.jpg
+examples/Aide.activity/help/OLPC_simple/TuteBackingUp/.resized_400x52_sdicon.png
+examples/Aide.activity/help/OLPC_simple/TuteBackingUp/resized_400x52_sdicon.png
+examples/Aide.activity/help/OLPC_simple/TuteBackingUp/.resized_400x200_terminal_ls.jpg
+examples/Aide.activity/help/OLPC_simple/StartingXO/resized_400x300_Simple_Manual_03_Choosing_Color.png
+examples/Aide.activity/help/OLPC_simple/StartingXO/resized_400x300_Simple_Manual_02_Entered_Name.png
+examples/Aide.activity/help/OLPC_simple/StartingXO/.resized_400x300_Simple_Manual_01_Entering_Name.png
+examples/Aide.activity/help/OLPC_simple/StartingXO/417_600w.png
+examples/Aide.activity/help/OLPC_simple/StartingXO/resized_400x300_Simple_Manual_01_Entering_Name.png
+examples/Aide.activity/help/OLPC_simple/StartingXO/.resized_400x300_Simple_Manual_03_Choosing_Color.png
+examples/Aide.activity/help/OLPC_simple/StartingXO/resized_400x300_Simple_Manual_04_Chose_Color.png
+examples/Aide.activity/help/OLPC_simple/StartingXO/.resized_500x375_Hiking02.jpg
+examples/Aide.activity/help/OLPC_simple/StartingXO/.resized_400x300_Simple_Manual_04_Chose_Color.png
+examples/Aide.activity/help/OLPC_simple/StartingXO/.resized_400x300_Simple_Manual_02_Entered_Name.png
+examples/Aide.activity/help/OLPC_simple/StartingXO/resized_500x375_Hiking02.jpg
+examples/Aide.activity/help/OLPC_simple/InstallNewActivity/.resized_400x300_wikilaptopActivities.jpg
+examples/Aide.activity/help/OLPC_simple/InstallNewActivity/resized_400x300_wikilaptopActivities.jpg
+examples/Aide.activity/help/OLPC_simple/InstallNewActivity/resized_400x300_jigsawpuzzleactivity.jpg
+examples/Aide.activity/help/OLPC_simple/InstallNewActivity/.resized_200x150_browsedownloadok.jpg
+examples/Aide.activity/help/OLPC_simple/InstallNewActivity/resized_200x150_browsedownloadok.jpg
+examples/Aide.activity/help/OLPC_simple/InstallNewActivity/.resized_400x300_versjigsawxo.jpg
+examples/Aide.activity/help/OLPC_simple/InstallNewActivity/.resized_400x300_jigsawxo.jpg
+examples/Aide.activity/help/OLPC_simple/InstallNewActivity/resized_400x300_jigsawxo.jpg
+examples/Aide.activity/help/OLPC_simple/InstallNewActivity/.resized_400x300_jigsawpuzzleactivity.jpg
+examples/Aide.activity/help/OLPC_simple/InstallNewActivity/resized_400x300_versjigsawxo.jpg
+examples/Aide.activity/help/OLPC_simple/OpeningOLPC/resized_570x322_415_600w.png
+examples/Aide.activity/help/OLPC_simple/OpeningOLPC/570px_OpenB3.svg_1.png
+examples/Aide.activity/help/OLPC_simple/OpeningOLPC/.resized_570x322_415_600w.png
+examples/Aide.activity/help/OLPC_simple/Interface/neighborhoodview_fromhome_resized_240px.png
+examples/Aide.activity/help/OLPC_simple/TuteLearningWithTurtleArt/Turtle_Art_img_7.jpg
+examples/Aide.activity/help/OLPC_simple/TuteLearningWithTurtleArt/Turtle_Art_img_21.jpg
+examples/Aide.activity/help/OLPC_simple/TuteLearningWithTurtleArt/Turtle_Art_img_14.jpg
+examples/Aide.activity/help/OLPC_simple/TuteLearningWithTurtleArt/Turtle_Art_img_36.jpg
+examples/Aide.activity/help/OLPC_simple/TuteLearningWithTurtleArt/Turtle_Art_img_44.jpg
+examples/Aide.activity/help/OLPC_simple/TuteLearningWithTurtleArt/Turtle_Art_img_3.jpg
+examples/Aide.activity/help/OLPC_simple/TuteLearningWithTurtleArt/turtlemenu.jpg
+examples/Aide.activity/help/OLPC_simple/TuteLearningWithTurtleArt/Turtle_Art_img_29.jpg
+examples/Aide.activity/help/OLPC_simple/TuteLearningWithTurtleArt/Turtle_Art_img_30.jpg
+examples/Aide.activity/help/OLPC_simple/TuteLearningWithTurtleArt/Turtle_Art_img_26.jpg
+examples/Aide.activity/help/OLPC_simple/TuteLearningWithTurtleArt/Turtle_Art_img_46.jpg
+examples/Aide.activity/help/OLPC_simple/TuteLearningWithTurtleArt/Turtle_Art_img_17.jpg
+examples/Aide.activity/help/OLPC_simple/TuteLearningWithTurtleArt/Turtle_Art_img_39.jpg
+examples/Aide.activity/help/OLPC_simple/TuteLearningWithTurtleArt/Turtle_Art_img_8.jpg
+examples/Aide.activity/help/OLPC_simple/TuteLearningWithTurtleArt/Turtle_Art_img_31.jpg
+examples/Aide.activity/help/OLPC_simple/TuteLearningWithTurtleArt/Turtle_Art_img_37.jpg
+examples/Aide.activity/help/OLPC_simple/TuteLearningWithTurtleArt/401.png
+examples/Aide.activity/help/OLPC_simple/TuteLearningWithTurtleArt/Turtle_Art_img_45.jpg
+examples/Aide.activity/help/OLPC_simple/TuteLearningWithTurtleArt/Turtle_Art_img_42.jpg
+examples/Aide.activity/help/OLPC_simple/TuteLearningWithTurtleArt/Turtle_Art_img_13.jpg
+examples/Aide.activity/help/OLPC_simple/TuteLearningWithTurtleArt/Turtle_Art_img_24.jpg
+examples/Aide.activity/help/OLPC_simple/TuteLearningWithTurtleArt/Turtle_Art_img_38.jpg
+examples/Aide.activity/help/OLPC_simple/TuteLearningWithTurtleArt/Turtle_Art_img_25.jpg
+examples/Aide.activity/help/OLPC_simple/TuteLearningWithTurtleArt/260.png
+examples/Aide.activity/help/OLPC_simple/TuteLearningWithTurtleArt/Turtle_Art_img_27.jpg
+examples/Aide.activity/help/OLPC_simple/TuteLearningWithTurtleArt/Turtle_Art_img_6.jpg
+examples/Aide.activity/help/OLPC_simple/TuteLearningWithTurtleArt/Turtle_Art_img_34.jpg
+examples/Aide.activity/help/OLPC_simple/TuteLearningWithTurtleArt/Turtle_Art_img_28.jpg
+examples/Aide.activity/help/OLPC_simple/TuteLearningWithTurtleArt/Turtle_Art_img_10.jpg
+examples/Aide.activity/help/OLPC_simple/TuteLearningWithTurtleArt/Turtle_Art_img_4.jpg
+examples/Aide.activity/help/OLPC_simple/TuteLearningWithTurtleArt/Turtle_Art_img_15.jpg
+examples/Aide.activity/help/OLPC_simple/TuteLearningWithTurtleArt/Turtle_Art_img_22.jpg
+examples/Aide.activity/help/OLPC_simple/TuteLearningWithTurtleArt/Turtle_Art_img_12.jpg
+examples/Aide.activity/help/OLPC_simple/TuteLearningWithTurtleArt/Turtle_Art_img_33.jpg
+examples/Aide.activity/help/OLPC_simple/TuteLearningWithTurtleArt/Turtle_Art_img_43.jpg
+examples/Aide.activity/help/OLPC_simple/TuteLearningWithTurtleArt/Turtle_Art_img_9.jpg
+examples/Aide.activity/help/OLPC_simple/TuteLearningWithTurtleArt/Turtle_Art_img_23.jpg
+examples/Aide.activity/help/OLPC_simple/TuteLearningWithTurtleArt/Turtle_Art_img_5.jpg
+examples/Aide.activity/help/OLPC_simple/TuteLearningWithTurtleArt/Turtle_Art_img_32.jpg
+examples/Aide.activity/help/OLPC_simple/TuteLearningWithTurtleArt/Turtle_Art_img_11.jpg
+examples/Aide.activity/help/OLPC_simple/TuteLearningWithTurtleArt/Turtle_Art_img_16.jpg
+examples/Aide.activity/activity/activity-help.svg
+examples/Aide.activity/activity/activity.info
+icons/activity-become-root.svg
+Rpyc/Connection.py
+Rpyc/Stream.py
+Rpyc/__init__.py
+Rpyc/ModuleNetProxy.py
+Rpyc/AsyncNetProxy.py
+Rpyc/NetProxy.py
+Rpyc/Lib.py
+Rpyc/Channel.py
+Rpyc/Boxing.py
+Rpyc/Demo/demo-3.py
+Rpyc/Demo/__init__.py
+Rpyc/Demo/demo-4.py
+Rpyc/Demo/demo-1.py
+Rpyc/Demo/pipe-parent.py
+Rpyc/Demo/testmodule.py
+Rpyc/Demo/demo-2.py
+Rpyc/Demo/demo-6.py
+Rpyc/Demo/demo-5.py
+Rpyc/Demo/pipe-child.py
+Rpyc/Demo/testsuite.bat
+Rpyc/Utils/Discovery.py
+Rpyc/Utils/__init__.py
+Rpyc/Utils/Factories.py
+Rpyc/Utils/Builtins.py
+Rpyc/Utils/Interpreter.py
+Rpyc/Utils/Files.py
+Rpyc/Utils/Serving.py
+Rpyc/Utils/Helpers.py
+Rpyc/Utils/Dist.py
+Rpyc/tests/isinstance.py
+Rpyc/Servers/__init__.py
+Rpyc/Servers/selecting_server.py
+Rpyc/Servers/std_server.py
+Rpyc/Servers/threaded_server.py
+Rpyc/Servers/simple_server.py
+Rpyc/Servers/Users.py
+Rpyc/Servers/tls_server.py
+Rpyc/Servers/forking_server.py
+bin/sugar-launch-path
+bin/sugar_start
+bin/sugar-launch
+bin/PyDebug.sh
+po/rw.po
+po/pap.po
+po/th.po
+po/zh_CN.po
+po/ug.po
+po/fi.po
+po/ay.po
+po/wa.po
+po/af.po
+po/pa.po
+po/sw.po
+po/ur.po
+po/fr.po
+po/nl.po
+po/ml.po
+po/gu.po
+po/Terminal.pot
+po/mk.po
+po/sd.po
+po/ja.po
+po/mvo.po
+po/cs.po
+po/ar.po
+po/ko.po
+po/mr.po
+po/mn.po
+po/he.po
+po/en.po
+po/ht.po
+po/fa.po
+po/mi.po
+po/bn_IN.po
+po/es.po
+po/bg.po
+po/is.po
+po/en_US.po
+po/ps.po
+po/am.po
+po/ha.po
+po/pis.po
+po/te.po
+po/cpp.po
+po/hi.po
+po/qu.po
+po/bi.po
+po/ca.po
+po/pt.po
+po/ms.po
+po/ro.po
+po/ff.po
+po/sl.po
+po/km.po
+po/bn.po
+po/tr.po
+po/pt_BR.po
+po/yo.po
+po/si.po
+po/sk.po
+po/vi.po
+po/zh_TW.po
+po/el.po
+po/hu.po
+po/tpi.po
+po/ru.po
+po/nb.po
+po/dz.po
+po/ne.po
+po/it.po
+po/fa_AF.po
+po/de.po
+po/sv.po
+po/pl.po
+po/ig.po
+activity/activity-terminal.svg
+activity/PyDebug.svg
+activity/activity.info
diff --git a/Rpyc/AsyncNetProxy.py b/Rpyc/AsyncNetProxy.py
new file mode 100644
index 0000000..06b230a
--- /dev/null
+++ b/Rpyc/AsyncNetProxy.py
@@ -0,0 +1,85 @@
+from NetProxy import NetProxyWrapper, _get_conn, _get_oid
+from Lib import raise_exception
+
+
+class AsyncNetProxy(NetProxyWrapper):
+ """wraps an exiting synchronous netproxy to make is asynchronous
+ (remote operations return AsyncResult objects)"""
+ __slots__ = []
+
+ def __request__(self, handler, *args):
+ res = AsyncResult(_get_conn(self))
+ _get_conn(self).async_request(res.callback, handler, _get_oid(self), *args)
+ return res
+
+ # must return a string... and it's not meaningful to return the repr of an async result
+ def __repr__(self, *args):
+ return self.__request__("handle_repr", *args).result
+ def __str__(self, *args):
+ return self.__request__("handle_str", *args).result
+
+
+class AsyncResult(object):
+ """represents the result of an asynchronous operation"""
+ STATE_PENDING = "pending"
+ STATE_READY = "ready"
+ STATE_EXCEPTION = "exception"
+ __slots__ = ["conn", "_state", "_result", "_on_ready"]
+
+ def __init__(self, conn):
+ self.conn = conn
+ self._state = self.STATE_PENDING
+ self._result = None
+ self._on_ready = None
+
+ def __repr__(self):
+ return "<AsyncResult (%s) at 0x%08x>" % (self._state, id(self))
+
+ def callback(self, obj, is_exception):
+ self._result = obj
+ if is_exception:
+ self._state = self.STATE_EXCEPTION
+ else:
+ self._state = self.STATE_READY
+ if self._on_ready is not None:
+ self._on_ready(self)
+
+ def _get_on_ready(self):
+ return self._ready_callback
+
+ def _set_on_ready(self, obj):
+ self._on_ready = obj
+ if self._state != self.STATE_PENDING:
+ self._on_ready(self)
+
+ def _get_is_ready(self):
+ if self._state == self.STATE_PENDING:
+ self.conn.poll()
+ return self._state != self.STATE_PENDING
+
+ def _get_result(self):
+ while self._state == self.STATE_PENDING:
+ self.conn.serve()
+ if self._state == self.STATE_READY:
+ return self._result
+ elif self._state == self.STATE_EXCEPTION:
+ raise_exception(*self._result)
+
+ is_ready = property(_get_is_ready,
+ doc = "indicates whether or not the result is ready")
+ result = property(_get_result,
+ doc = "the value of the async result (may block)")
+ on_ready = property(_get_on_ready, _set_on_ready,
+ doc = "if not None, specifies a callback which is called when the result is ready")
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Rpyc/Boxing.py b/Rpyc/Boxing.py
new file mode 100644
index 0000000..4797f2a
--- /dev/null
+++ b/Rpyc/Boxing.py
@@ -0,0 +1,123 @@
+import sys
+import traceback
+import cPickle as pickle
+from weakref import WeakValueDictionary
+from Lib import ImmDict
+from NetProxy import NetProxy, SyncNetProxy, _get_conn, _get_oid
+from Lib import orig_isinstance
+
+
+class BoxingError(Exception):
+ pass
+class NestedException(Exception):
+ pass
+
+PICKLE_PROTOCOL = pickle.HIGHEST_PROTOCOL
+TYPE_SIMPLE = 0
+TYPE_PROXY = 1
+TYPE_TUPLE = 2
+TYPE_SLICE = 3
+TYPE_LOCAL_PROXY = 4
+TYPE_IMMDICT = 5
+simple_types = (
+ bool,
+ int,
+ long,
+ float,
+ complex,
+ basestring,
+ type(None),
+)
+
+def dump_exception(typ, val, tb):
+ """dumps the given exception using pickle (since not all exceptions are picklable)"""
+ tbtext = "".join(traceback.format_exception(typ, val, tb))
+ sys.last_type, sys.last_value, sys.last_traceback = typ, val, tb
+ try:
+ pickled_exc = pickle.dumps((typ, val, tbtext), protocol = PICKLE_PROTOCOL)
+ except pickle.PicklingError, ex:
+ newval = NestedException("pickling error %s\nexception type: %r\nexception object: %s" % (ex, typ, val))
+ pickled_exc = pickle.dumps((NestedException, newval, tbtext), protocol = PICKLE_PROTOCOL)
+ return pickled_exc
+
+def load_exception(package):
+ """returns an exception object"""
+ try:
+ return pickle.loads(package)
+ except pickle.PicklingError, ex:
+ return NestedException("failed to unpickle remote exception -- %r" % (ex,))
+
+class Box(object):
+ """a box is where local objects are stored, and remote proxies are created"""
+ __slots__ = ["conn", "objects", "proxy_cache"]
+
+ def __init__(self, conn):
+ self.conn = conn
+ self.objects = {}
+ self.proxy_cache = WeakValueDictionary()
+
+ def close(self):
+ del self.conn
+ del self.objects
+ del self.proxy_cache
+
+ def __getitem__(self, oid):
+ return self.objects[oid][1]
+
+ def _box(self, obj):
+ if orig_isinstance(obj, simple_types):
+ return TYPE_SIMPLE, obj
+ elif orig_isinstance(obj, slice):
+ return TYPE_SLICE, (obj.start, obj.stop, obj.step)
+ elif orig_isinstance(obj, NetProxy) and _get_conn(obj) is self.conn:
+ return TYPE_LOCAL_PROXY, _get_oid(obj)
+ elif orig_isinstance(obj, tuple):
+ if obj:
+ return TYPE_TUPLE, [self._box(subobj) for subobj in obj]
+ else:
+ return TYPE_SIMPLE, ()
+ elif orig_isinstance(obj, ImmDict):
+ if not obj.dict:
+ return TYPE_SIMPLE, {}
+ else:
+ return TYPE_IMMDICT, [(self._box(k), self._box(v)) for k, v in obj.items()]
+ else:
+ oid = id(obj)
+ self.objects.setdefault(oid, [0, obj])[0] += 1
+ return TYPE_PROXY, oid
+
+ def _unbox(self, (type, value)):
+ if type == TYPE_SIMPLE:
+ return value
+ elif type == TYPE_TUPLE:
+ return tuple(self._unbox(subobj) for subobj in value)
+ elif type == TYPE_SLICE:
+ return slice(*value)
+ elif type == TYPE_LOCAL_PROXY:
+ return self[value]
+ elif type == TYPE_IMMDICT:
+ return dict((self._unbox(k), self._unbox(v)) for k, v in value)
+ elif type == TYPE_PROXY:
+ if value in self.proxy_cache:
+ proxy = self.proxy_cache[value]
+ else:
+ proxy = SyncNetProxy(self.conn, value)
+ self.proxy_cache[value] = proxy
+ return proxy
+ else:
+ raise BoxingError("invalid boxed object type", type, value)
+
+ def decref(self, oid):
+ self.objects[oid][0] -= 1
+ if self.objects[oid][0] <= 0:
+ del self.objects[oid]
+
+ def pack(self, obj):
+ """packs an object (returns a package)"""
+ return pickle.dumps(self._box(obj), protocol = PICKLE_PROTOCOL)
+
+ def unpack(self, package):
+ """unpacks a package (returns an object)"""
+ return self._unbox(pickle.loads(package))
+
+
diff --git a/Rpyc/Channel.py b/Rpyc/Channel.py
new file mode 100644
index 0000000..8db2f6f
--- /dev/null
+++ b/Rpyc/Channel.py
@@ -0,0 +1,57 @@
+from threading import RLock
+import struct
+
+
+class Channel(object):
+ """
+ a channel transfers frames over a stream. a frame is any blob of data,
+ up to 4GB in size. it is made of a type field (byte), a sequence number
+ (dword), and a length field (dword), followed by raw data. at the end
+ of the frame, a new line marker (\\r\\n) is appended, to make sure the
+ transport layer will send the message without buffering (to overcome
+ newline buffering). apart from that, channels are duplex, and can do both
+ sending and receiving in a thread-safe manner.
+ """
+ HEADER_FORMAT = "<BLL"
+ HEADER_SIZE = struct.calcsize(HEADER_FORMAT)
+ __slots__ = ["send_lock", "recv_lock", "stream", "seq"]
+
+ def __init__(self, stream):
+ self.send_lock = RLock()
+ self.recv_lock = RLock()
+ self.stream = stream
+ self.seq = 0
+ def __repr__(self):
+ return "<%s(%r)>" % (self.__class__.__name__, self.stream)
+ def close(self):
+ self.stream.close()
+ def fileno(self):
+ return self.stream.fileno()
+ def is_available(self):
+ return self.stream.is_available()
+
+ def send(self, type, seq, data):
+ """sends the given (type, seq, data) frame"""
+ try:
+ self.send_lock.acquire()
+ if seq is None:
+ seq = self.seq
+ self.seq += 1
+ header = struct.pack(self.HEADER_FORMAT, type, seq, len(data))
+ self.stream.write(header + data + "\r\n")
+ return seq
+ finally:
+ self.send_lock.release()
+
+ def recv(self):
+ """returns the next (type, seq, data) frame (blocking)"""
+ try:
+ self.recv_lock.acquire()
+ type, seq, length = struct.unpack(self.HEADER_FORMAT, self.stream.read(self.HEADER_SIZE))
+ data = self.stream.read(length)
+ self.stream.read(2)
+ return type, seq, data
+ finally:
+ self.recv_lock.release()
+
+
diff --git a/Rpyc/Connection.py b/Rpyc/Connection.py
new file mode 100644
index 0000000..c2ce4c4
--- /dev/null
+++ b/Rpyc/Connection.py
@@ -0,0 +1,212 @@
+import sys
+from Boxing import Box, dump_exception, load_exception
+from ModuleNetProxy import RootImporter
+from Lib import raise_exception, AttrFrontend
+
+
+FRAME_REQUEST = 1
+FRAME_RESULT = 2
+FRAME_EXCEPTION = 3
+
+class Connection(object):
+ """
+ the rpyc connection layer (protocol and APIs). generally speaking, the only
+ things you'll need to access directly from this object are:
+ * modules - represents the remote python interprerer's modules namespace
+ * execute - executes the given code on the other side of the connection
+ * namespace - the namespace in which the code you `execute` resides
+
+ the rest of the attributes should be of no intresent to you, except maybe
+ for `remote_conn`, which represents the other side of the connection. it is
+ unlikely, however, you'll need to use it (it is used interally).
+
+ when you are done using a connection, and wish to release the resources it
+ holds, you should call close(). you don't have to, but if you don't, the gc
+ can't release the memory because of cyclic references.
+ """
+ __slots__ = ["_closed", "_local_namespace", "channel", "box", "async_replies",
+ "sync_replies", "module_cache", "remote_conn", "modules", "namespace"]
+
+ def __init__(self, channel):
+ self._closed = False
+ self._local_namespace = {}
+ self.channel = channel
+ self.box = Box(self)
+ self.async_replies = {}
+ self.sync_replies = {}
+ self.module_cache = {}
+ self.remote_conn = self.sync_request("handle_getconn")
+ # user APIs:
+ self.modules = RootImporter(self)
+ self.namespace = AttrFrontend(self.remote_conn._local_namespace)
+ self.execute("")
+
+ def __repr__(self):
+ if self._closed:
+ return "<%s.%s(closed)>" % (self.__class__.__module__, self.__class__.__name__)
+ else:
+ return "<%s.%s(%r)>" % (self.__class__.__module__, self.__class__.__name__, self.channel)
+
+ #
+ # file api layer
+ #
+ def close(self):
+ """closes down the connection and releases all cyclic dependecies"""
+ if not self._closed:
+ self.box.close()
+ self.channel.close()
+ self._closed = True
+ self._local_namespace = None
+ self.channel = None
+ self.box = None
+ self.async_replies = None
+ self.sync_replies = None
+ self.module_cache = None
+ self.modules = None
+ self.remote_conn = None
+ self.namespace = None
+
+ def fileno(self):
+ """connections are select()able"""
+ return self.channel.fileno()
+
+ #
+ # protocol
+ #
+ def send(self, type, seq, obj):
+ if self._closed:
+ raise EOFError("the connection is closed")
+ return self.channel.send(type, seq, self.box.pack(obj))
+
+ def send_request(self, handlername, *args):
+ return self.send(FRAME_REQUEST, None, (handlername, args))
+
+ def send_exception(self, seq, exc_info):
+ self.send(FRAME_EXCEPTION, seq, dump_exception(*exc_info))
+
+ def send_result(self, seq, obj):
+ self.send(FRAME_RESULT, seq, obj)
+
+ #
+ # dispatching
+ #
+ def dispatch_result(self, seq, obj):
+ if seq in self.async_replies:
+ self.async_replies.pop(seq)(obj, False)
+ else:
+ self.sync_replies[seq] = obj
+
+ def dispatch_exception(self, seq, obj):
+ excobj = load_exception(obj)
+ if seq in self.async_replies:
+ self.async_replies.pop(seq)(excobj, True)
+ else:
+ raise_exception(*excobj)
+
+ def dispatch_request(self, seq, handlername, args):
+ try:
+ res = getattr(self, handlername)(*args)
+ except SystemExit:
+ raise
+ except:
+ self.send_exception(seq, sys.exc_info())
+ else:
+ self.send_result(seq, res)
+
+ def poll(self):
+ """if available, serves a single request, otherwise returns (non-blocking serve)"""
+ if self.channel.is_available():
+ self.serve()
+ return True
+ else:
+ return False
+
+ def serve(self):
+ """serves a single request (may block)"""
+ type, seq, data = self.channel.recv()
+ if type == FRAME_RESULT:
+ self.dispatch_result(seq, self.box.unpack(data))
+ elif type == FRAME_REQUEST:
+ self.dispatch_request(seq, *self.box.unpack(data))
+ elif type == FRAME_EXCEPTION:
+ self.dispatch_exception(seq, self.box.unpack(data))
+ else:
+ raise ValueError("invalid frame type (%d)" % (type,))
+
+ #
+ # requests
+ #
+ def sync_request(self, handlername, *args):
+ """performs a synchronous (blocking) request"""
+ seq = self.send_request(handlername, *args)
+ while seq not in self.sync_replies:
+ self.serve()
+ return self.sync_replies.pop(seq)
+
+ def async_request(self, callback, handlername, *args):
+ """performs an asynchronous (non-blocking) request"""
+ seq = self.send_request(handlername, *args)
+ self.async_replies[seq] = callback
+
+ #
+ # root requests (not through NetProxies)
+ #
+ def rimport(self, modulename):
+ """imports a module by name (as a string)"""
+ if modulename not in self.module_cache:
+ module = self.sync_request("handle_import", modulename)
+ self.module_cache[modulename] = module
+ return self.module_cache[modulename]
+
+ def execute(self, expr, mode = "exec"):
+ """executes the given code at the remote side of the connection"""
+ return self.sync_request("handle_execute", expr, mode)
+
+ #
+ # handlers
+ #
+ def handle_decref(self, oid):
+ self.box.decref(oid)
+
+ def handle_delattr(self, oid, name):
+ delattr(self.box[oid], name)
+
+ def handle_getattr(self, oid, name):
+ return getattr(self.box[oid], name)
+
+ def handle_setattr(self, oid, name, value):
+ setattr(self.box[oid], name, value)
+
+ def handle_delitem(self, oid, index):
+ del self.box[oid][index]
+
+ def handle_getitem(self, oid, index):
+ return self.box[oid][index]
+
+ def handle_setitem(self, oid, index, value):
+ self.box[oid][index] = value
+
+ def handle_call(self, oid, args, kwargs):
+ return self.box[oid](*args, **kwargs)
+
+ def handle_repr(self, oid):
+ return repr(self.box[oid])
+
+ def handle_str(self, oid):
+ return str(self.box[oid])
+
+ def handle_bool(self, oid):
+ return bool(self.box[oid])
+
+ def handle_import(self, modulename):
+ return __import__(modulename, None, None, modulename.split(".")[-1])
+
+ def handle_getconn(self):
+ return self
+
+ def handle_execute(self, expr, mode):
+ codeobj = compile(expr, "<from %s>" % (self,), mode)
+ return eval(codeobj, self._local_namespace)
+
+
+
diff --git a/Rpyc/Demo/__init__.py b/Rpyc/Demo/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Rpyc/Demo/__init__.py
diff --git a/Rpyc/Demo/demo-1.py b/Rpyc/Demo/demo-1.py
new file mode 100644
index 0000000..6a9a3a8
--- /dev/null
+++ b/Rpyc/Demo/demo-1.py
@@ -0,0 +1,156 @@
+#
+# welcome to RPyC. this demo serves as an introduction. i believe in learning through
+# showcases, and that's why this package comes with a demo subpackage, instead of
+# documentation
+#
+# so, the first thing we're gonna do is import the SocketConnection. this is a factory
+# function that returns us a new Connection object over a socket stream. we dont need
+# to get into details here.
+#
+from Rpyc import *
+
+#
+# next, we'll get all the helpful utilities. the utilities include wrappers for builtin
+# functions, like dir(), so they'd work as expected with netproxies.
+#
+from Rpyc.Utils import *
+
+#
+# by now you should have an rpyc server running. if you dont, go to the Servers directory
+# and choose your favorite version of a socket server. for unixes i'd recommend the
+# forking server; for windows -- the threaded server.
+#
+# so let's connect to the server
+#
+c = SocketConnection("localhost")
+
+#
+# now it's time to explain a little about how rpyc works. it's quite simple really. the
+# magic comes from a concept called NetProxy. a NetProxy object delivers all of the
+# operations performed on it to the remote object. so if you get a list from your host,
+# what you're are really getting is a NetProxy to that list. it looks and works just
+# like a real list -- but everytime you do something on it, it actually performs a
+# request on the list object stored on the host. this is called boxing. this means
+# you can change the object you get locally, and the remote object changes, etc.
+#
+# however, for efficiency and other reason, not all objects you get are NetProxies.
+# all immutable and pickle-able objects pass by value (through pickle). these types
+# of objects include ints, longs, strings, and some other types. all other types are
+# passed by boxing.
+#
+# this boxing mechanism works on everything -- objects, functions, classes, and modules,
+# which is why rpyc is considered transparent. your code looks just as if it was meant
+# to run locally.
+#
+
+#
+# let's start with something simple -- getting a remote module. accessing the remote
+# namespace always starts with the `modules` attribute, then the module (or package)
+# name, and then the attribute you want to get.
+#
+
+print c.modules.sys
+print c.modules.sys.path
+c.modules.sys.path.append("lucy")
+print c.modules.sys.path[-1]
+
+#
+# these remote objects are first class objects, like all others in python. this means
+# you can store them in variables, pass them as parameters, etc.
+#
+rsys = c.modules.sys
+rpath = rsys.path
+rpath.pop(-1)
+
+#
+# and as you might expect, netproxies also look like the real objects
+#
+print dir(rpath)
+
+#
+# but there are a couple of issues with netproxies. the type(), isinstance(), and
+# issubclass() classes dont work on them... as they query the underlying object, not
+# the remote one. so:
+#
+print type(rsys.maxint) # <int> -- because it's a simple type which is passed by value)
+print type(rsys.path) # <SyncNetProxy> -- because, after all, it's a netproxy, not a list
+
+#
+# now for a demo of packages
+# (which looks very much like 'from xml.dom.minidom import parseString')
+#
+parseString = c.modules.xml.dom.minidom.parseString
+x = parseString("<a>lala</a>")
+print x
+x.toxml()
+print x.firstChild.nodeName
+
+#
+# however, there's a catch when working with packages like that. the way it works is
+# trying to find an attribute with that name, and if not found, trying to import a sub-
+# module.
+#
+# now in english:
+# c.module.xml is the xml module of the server. when you do c.module.xml.dom, rpyc looks
+# for an attribute named 'dom' inside the xml module. since there's no such attribute,
+# it tries to import a subpackage called xml.dom, which succeeds. then it does the same
+# for xml.dom.minidom, and xml.dom.minidom.parseString.
+#
+# but there are times when that's ambiguous. this mean that the module has both a sub-
+# module called 'X', and an attribute called 'X'. according to rpyc's algorithm, the
+# attribute 'X' is returned, not the sub-module.
+#
+# but if you need to be explicit, you can, and it works like this:
+#
+
+c.modules["xml.dom.minidom"].parseString("<a></a>")
+
+#
+# this will make sure the module 'xml.dom.minidom' is returned, and not an attribute.
+# in general, it's better to use this form, unless you know there are no such conflicts.
+# remeber that "Explicit is better than implicit", although it requires four more key
+# strokes. perhaps in a later version it will raise an exception if there's a conflict.
+#
+
+#
+# and now for a little demo of working with files (a common task)
+#
+f = c.modules.__builtin__.open("lala.txt", "w")
+f.write("lucy")
+f.close()
+c.modules.os.remove("lala.txt")
+
+#
+# now to a bitter part of life: exceptions. as you could expect, they work just like
+# regular exceptions
+#
+try:
+ a = c.modules.sys.nonexistent_attribute
+except AttributeError:
+ pass
+else:
+ assert False
+
+try:
+ a = c.modules.__builtin__.open("**\\//##~~..::!@#$%^&*()_+\n <,>?")
+except IOError:
+ pass
+else:
+ assert False
+
+print "goodbye"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Rpyc/Demo/demo-2.py b/Rpyc/Demo/demo-2.py
new file mode 100644
index 0000000..49d94ca
--- /dev/null
+++ b/Rpyc/Demo/demo-2.py
@@ -0,0 +1,81 @@
+#
+# okay, this demo is more advanced. here we'll learn about:
+# * redirecting standard files
+# * synchronous callbacks
+# * the ulitities module
+#
+import sys
+import os
+from Rpyc import *
+from Rpyc.Utils import remote_interpreter
+
+c = SocketConnection("localhost")
+
+#
+# redirect our stdout to the server
+#
+sys.stdout = c.modules.sys.stdout
+print "this time we focus on `the seatle music`"
+
+#
+# and the other way round
+#
+sys.stdout = sys.__stdout__
+c.modules.sys.stdout = sys.stdout
+c.modules.sys.stdout.write("alice in chains\n")
+
+#
+# but you dont believe me, so
+#
+c.modules["Rpyc.Demo.testmodule"].printer("tool")
+
+#
+# and restore that
+#
+c.modules.sys.stdout = c.modules.sys.__stdout__
+
+#
+# now let's play with callbacks
+#
+def f(text):
+ print text
+
+c.modules["Rpyc.Demo.testmodule"].caller(f, "nirvana")
+
+#
+# and if you insist
+#
+def g(func, text):
+ c.modules["Rpyc.Demo.testmodule"].caller(func, text)
+
+c.modules["Rpyc.Demo.testmodule"].caller(g, f, "soundgarden")
+
+#
+# now for the utilities module. it gives us the following cool functions:
+# * dir, getattr, hasattr, help, reload -- overriding builtins
+# * upload, download -- transfering files/directories to/from the client/server (all the permutations)
+# * remote_shell, remote_interpreter -- running remote processess and debugging
+#
+print hasattr(sys, "path")
+print hasattr(c.modules.sys, "path")
+
+print getattr(sys, "maxint")
+print getattr(c.modules.sys, "maxint")
+
+print reload(sys)
+print reload(c.modules.sys)
+
+f=open("lala.txt", "w")
+f.write("king crimson")
+f.close()
+upload(c, "lala.txt", "../lala.txt")
+os.remove("lala.txt")
+c.modules.os.remove("../lala.txt")
+
+remote_interpreter(c)
+
+
+print "goodbye"
+
+
+
diff --git a/Rpyc/Demo/demo-3.py b/Rpyc/Demo/demo-3.py
new file mode 100644
index 0000000..bd0689e
--- /dev/null
+++ b/Rpyc/Demo/demo-3.py
@@ -0,0 +1,129 @@
+#
+# asynchronous proxies as super-events
+#
+from Rpyc import *
+
+c = SocketConnection("localhost")
+
+#
+# this is the remote int type
+#
+rint = c.modules.__builtin__.int
+
+#
+# and we'll wrap it in an asynchronous wrapper
+#
+rint = Async(rint)
+
+#
+# now it still looks like a normal proxy... but operations on it return something called
+# an AsyncResult -- it's an object that represents the would-be result of the operation.
+# it has a .is_ready property, which indicates whether or not the result is ready, and
+# a .result property, which holds the result of the operations. when you access the .result
+# property, it will block until the result is returned
+#
+a = rint("123")
+b = rint("metallica")
+print a
+print b.is_ready
+print a.result
+print a
+
+#
+# and when an exception occurs, it looks like that
+#
+try:
+ print b.result
+except ValueError:
+ pass
+
+#
+# only when you access the result you get the exception, which may look weird, but hey,
+# it's an asynchronous world out there.
+#
+
+#
+# there's another methodology for async proxies -- on_ready callbacks. instead of
+# getting the async result, you can register a callback to collect it, when it arrives.
+#
+def f(res):
+ print "the result is",
+ try:
+ print res.result
+ except:
+ print "an exception"
+
+rint = Async(c.modules.__builtin__.int)
+
+ar = rint("123")
+ar.on_ready = f
+
+# this will cause an exception
+ar = rint("a perfect circle")
+ar.on_ready = f
+
+# or when you dont need to keep the async result
+rint("456").on_ready = f
+
+# and it's not limited to calling it. anything you do to the async proxy is asynchronous.
+# for example, you can also get attributes asynchronously:
+ar = rint.__str__
+
+#
+# now we'll do some other request, which will cause the results to arrive, and the callback
+# to be called.
+#
+print c.modules.sys
+
+############################################################################################
+#
+# this is where we get hardcore: threads and event callbacks
+#
+xxx = 0
+def blah():
+ global xxx
+ xxx += 1
+
+#
+# we'll start a thread on the server which on threadfunc (which is defined in the testmodule).
+# this function will call the callback we give it every second, but will ignore the result.
+# this practically means it's like an event -- trigger and forget. on the client side, the
+# callback will increment `xxx` every time it's called
+#
+c.modules.thread.start_new_thread(c.modules["Rpyc.Demo.testmodule"].threadfunc, (blah,))
+
+#
+# we'll wait a little
+#
+import time
+time.sleep(5)
+
+#
+# and do some operation, which, along with it, will pull all incoming requests
+#
+print c.modules.sys
+print xxx
+
+#
+# and we can start a thread of our own to pull the requests in the background
+#
+#import thread
+#worker_running = True
+#
+#def worker(conn):
+# while worker_running:
+# conn.serve()
+#
+#thread.start_new_thread(worker, (c,))
+#
+#time.sleep(5)
+#worker_running = False
+#
+#print xxx
+#print "goodbye"
+
+#
+# L33TN3SS
+#
+
+
diff --git a/Rpyc/Demo/demo-4.py b/Rpyc/Demo/demo-4.py
new file mode 100644
index 0000000..5467e5c
--- /dev/null
+++ b/Rpyc/Demo/demo-4.py
@@ -0,0 +1,41 @@
+import time
+from Rpyc import SocketConnection, Async
+
+c = SocketConnection("localhost")
+c2 = SocketConnection("localhost")
+
+huge_xml = "<blah a='5' b='6'> " * 50000 + " </blah> " * 50000
+parseString = Async(c.modules.xml.dom.minidom.parseString)
+res = parseString(huge_xml)
+
+print "while we're waiting for the server to complete, we do other stuff"
+t = time.time()
+while not res.is_ready:
+ time.sleep(0.5)
+ # we dont want to use `c`, because it would block us (as the server is blocking)
+ # but `c2` runs on another thread/process, so it wouldn't block
+ print c2.modules.os.getpid()
+
+t = time.time() - t
+print "it took %d seconds" % (t,)
+
+print res.result
+
+
+#
+# note: to improve performance, delete the result when you no longer need it.
+# this should be done because the server might (as in this case) hold enormous
+# amounts of memory, which will slow it down
+#
+# if you do this:
+# res = parseString(huge_xml)
+# res = parseString(huge_xml)
+# res will be deleted only after the second operation finishes, because only when
+# the second result is assigned, the first is released -- server still holds
+# around 160MB of the old xml tree for nothing. so it's a good idea to `del res`
+# when you dont need it.
+#
+# also, there's a memory leak on the server, which i'm working on solving.
+#
+
+
diff --git a/Rpyc/Demo/demo-5.py b/Rpyc/Demo/demo-5.py
new file mode 100644
index 0000000..7a21688
--- /dev/null
+++ b/Rpyc/Demo/demo-5.py
@@ -0,0 +1,66 @@
+#
+# this demo will show you working with asynch proxies and callback
+# verison 2.3 removes the AsyncCallback factory, and instead provides a mechanism
+# where async results can provide a callback. it simplifies the design, so i
+# went for it.
+#
+import time
+from Rpyc import SocketConnection, Async
+
+c1 = SocketConnection("localhost")
+
+# f1 is an async proxy to the server's sleep function
+f1 = Async(c1.modules.time.sleep)
+
+# this would block the server for 9 seconds
+r1 = f1(9)
+# and this would block it for 11
+r2 = f1(11)
+
+# of course the client isnt affected (that's the whole point of Async)
+# but since the same server can't block simultaneously, the second request is
+# queued. this is a good example of queuing.
+
+# now we'll wait for both results to finish. this should print around 20 lines
+# (more or less, depending on the phase)
+while not r1.is_ready or not r2.is_ready:
+ print "!"
+ time.sleep(1)
+
+print "---"
+
+# now we'll dig in the h4xx0r shit -- running things simultaneously
+# for this, we'll need another connection, and another proxy:
+c2 = SocketConnection("localhost")
+f2 = Async(c2.modules.time.sleep)
+
+# now we'll do the same as the above, but this time, it will happen simulatenously
+# becuase f1 and f2 work on different connections
+r1 = f1(9)
+r2 = f2(11)
+
+# so this time, it will print around 11 lines
+while not r1.is_ready or not r2.is_ready:
+ print "!"
+ time.sleep(1)
+
+print "---"
+
+# very haxxor indeed. now, we'll see how to use the on_ready callback
+r1 = f1(9)
+r2 = f2(11)
+
+def blah(res):
+ print "look mama, no hands! res = %r" % (res.result,)
+
+# set the on_ready callback -- when r1 is becomes ready, the callback will
+# be called automagically
+r1.on_ready = blah
+
+# this should print 9 "!", then "look mama", then two more "!"
+while not r1.is_ready or not r2.is_ready:
+ print "!"
+ time.sleep(1)
+
+
+
diff --git a/Rpyc/Demo/demo-6.py b/Rpyc/Demo/demo-6.py
new file mode 100644
index 0000000..1c34039
--- /dev/null
+++ b/Rpyc/Demo/demo-6.py
@@ -0,0 +1,130 @@
+# as you can see - the import line now requires even less typing!
+from Rpyc import *
+c = SocketConnection("localhost")
+
+#------------------------------------------------------------------------------
+# this demo shows the new `execute` and `namespace` features of rpyc
+#------------------------------------------------------------------------------
+
+
+# the code below will run AT THE OTHER SIDE OF THE CONNECTION... so you'll see
+# 'hello world' on the server's console
+c.execute("print 'hello world'")
+
+import sys
+c.modules.sys.stdout = sys.stdout
+
+# and this time, on our console
+c.execute("print 'brave new world'")
+
+# restore that
+c.modules.sys.stdout = c.modules.sys.__stdout__
+
+# anyway, the `execute` method runs the given code at the other side of the connection
+# and works in the `namespace` dict. what?
+c.execute("x = [1,2,3]")
+print c.namespace.x
+
+# now it makes sense, doesn't it? the 'namespace' attribute is something i called
+# AttrFrontend -- it wraps a dict with the attribute protocol, so you can access
+# it with the dot notation, instead of the braces notation (more intuitive).
+# this namespace works both ways -- executing code affects the namespace, while
+# altering the namespace directly also affects it:
+c.namespace.x.append(4)
+c.execute("x.append(5)")
+print c.namespace.x
+
+# but you should not assign complex objects (not int/float/str, etc) to this namespace
+# directy, or NetProxies will be created. there's nothing wrong with that, but keep
+# in mind it might cause blocking (and even deadlocks), as i'll explain later.
+
+# another cool thing i want to show is the second, optional parameter to execute: mode.
+# the mode controls how the code is compiled. the default mode is "exec", which means
+# it executes the code as a module. the other option is "eval" which returns a value.
+# so if you want to _do_ something, like printing of assigning a variable, you do it
+# with "exec", and if you want to evaluate something, you do it with "eval"
+# for example:
+
+# this will print None
+print c.execute("1+2")
+
+# while this will print 3
+print c.execute("1+2", "eval")
+
+# but there's a time in a man's life when he asks himself, why the heck? you can, as i
+# showed in other places, just do this:
+# c.modules.__builtin__.eval("1+2")
+# so what's the point?
+#
+# well, i've been waiting for this question. the rationale behind this seemingly useless
+# feature is for times you NEED to have the code executing remotely, but writing a
+# dedicated module for it is overdoing it:
+# * more files to update ==> more chance that you'll forget to update
+# * distributing the module to all of the machines
+# * making a mess on the file system
+# * it's really not a module... it's just some code that logically belongs to one single
+# module, but technical difficulties prevent it
+#
+# and to show you what i mean -- i want to start a thread on the server, like it did in
+# several places over the demos. this thread will send me an event every second. what i
+# used to do was, creating another module, like testmodule.py to define the thread
+# function, so it will exist on the server, and i could call it.
+# if i defined thread_func at the client side, then the thread will block when trying
+# to execute the code, because the client holds it. so this new mechanism lets you
+# distribute code in a volatile fashion:
+# * when the connection is closed, everything you defined is gone
+# * no file-system mess
+# * no need to distribute files across the network
+# * only one place to maintain
+
+c.execute("""
+my_thread_active = True
+
+def my_thread_func(callback):
+ import time
+ from Rpyc import Async
+
+ callback = Async(callback)
+ while my_thread_active:
+ callback(time.time())
+ time.sleep(1)
+ print "the thread says goodbye"
+""")
+
+def callback(timestamp):
+ print "the timestamp is", timestamp
+
+c.modules.thread.start_new_thread(c.namespace.my_thread_func, (callback,))
+c.modules.time.sleep(5)
+c.namespace.my_thread_active = False
+c.close()
+
+# it's not only for threads of course. there are many times when you NEED the code/objects
+# on the remote side. for example:
+# * situations that would block (like having the thread func on the client)
+# * code that check the type of the object (type or isinstance), and a NetProxy would make
+# it cry. DONT CHECK THE TYPE OF OBJECTS, PEOPLE, JUST USE THEM! that's why they invented
+# duck-typing. argh.
+# * other places i didnt think of as of yet. i want to sleep. leave me alone ;) zzzZZZ
+#
+# so enjoy!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Rpyc/Demo/pipe-child.py b/Rpyc/Demo/pipe-child.py
new file mode 100644
index 0000000..517d0ef
--- /dev/null
+++ b/Rpyc/Demo/pipe-child.py
@@ -0,0 +1,8 @@
+import sys
+from Rpyc import PipeConnection
+
+c = PipeConnection(sys.stdin, sys.stdout)
+c.modules.sys.path.append("i love lucy")
+
+
+# child dies \ No newline at end of file
diff --git a/Rpyc/Demo/pipe-parent.py b/Rpyc/Demo/pipe-parent.py
new file mode 100644
index 0000000..bd8cc89
--- /dev/null
+++ b/Rpyc/Demo/pipe-parent.py
@@ -0,0 +1,17 @@
+# a demo for parent/child over pipes
+
+import sys
+from popen2 import popen3
+from Rpyc import PipeConnection
+
+cout, cin, cerr = popen3("python pipe-child.py")
+conn = PipeConnection(cout, cin)
+
+try:
+ while True:
+ conn.serve()
+except EOFError:
+ print "goodbye child"
+
+print sys.path[-1]
+
diff --git a/Rpyc/Demo/testmodule.py b/Rpyc/Demo/testmodule.py
new file mode 100644
index 0000000..d4bcb31
--- /dev/null
+++ b/Rpyc/Demo/testmodule.py
@@ -0,0 +1,19 @@
+import time
+from Rpyc import Async
+
+def threadfunc(callback):
+ """this function will call the callback every second"""
+ callback = Async(callback)
+ try:
+ while True:
+ print "!"
+ callback()
+ time.sleep(1)
+ except:
+ print "thread exiting"
+
+def printer(text):
+ print text
+
+def caller(func, *args):
+ func(*args)
diff --git a/Rpyc/Demo/testsuite.bat b/Rpyc/Demo/testsuite.bat
new file mode 100644
index 0000000..fa46892
--- /dev/null
+++ b/Rpyc/Demo/testsuite.bat
@@ -0,0 +1,6 @@
+python demo-1.py
+python demo-2.py
+python demo-3.py
+python demo-4.py
+python demo-5.py
+python demo-6.py
diff --git a/Rpyc/Lib.py b/Rpyc/Lib.py
new file mode 100644
index 0000000..ade15ee
--- /dev/null
+++ b/Rpyc/Lib.py
@@ -0,0 +1,71 @@
+"""
+shared types, functions and constants.
+important - don't reload() this module, or things are likely to break
+"""
+from sys import excepthook, stderr
+
+#
+# the original version of the __builtins__, in case you do
+# __builtin__.x = rpyc_version_of_x
+#
+orig_isinstance = isinstance
+orig_getattr = getattr
+orig_hasttr = hasattr
+orig_issubclass = issubclass
+orig_help = help
+orig_reload = reload
+orig_dir = dir
+orig_excepthook = excepthook
+orig_type = type
+
+
+def raise_exception(typ, val, tbtext):
+ """a helper for raising remote exceptions"""
+ if orig_type(typ) == str:
+ raise typ
+ else:
+ val._remote_traceback = tbtext
+ raise val
+
+class ImmDict(object):
+ """immutable dict (passed by value)"""
+ __slots__ = ["dict"]
+ def __init__(self, dict):
+ self.dict = dict
+ def items(self):
+ return self.dict.items()
+
+def _get_dict(obj):
+ return object.__getattribute__(obj, "____dict__")
+
+class AttrFrontend(object):
+ """a wrapper that implements the attribute protocol for a dict backend"""
+ __slots__ = ["____dict__"]
+
+ def __init__(self, dict):
+ object.__setattr__(self, "____dict__", dict)
+
+ def __delitem__(self, name):
+ del _get_dict(self)[name]
+ def __getitem__(self, name):
+ return _get_dict(self)[name]
+ def __setitem__(self, name, value):
+ _get_dict(self)[name] = value
+
+ __delattr__ = __delitem__
+ __getattr__ = __getitem__
+ __setattr__ = __setitem__
+
+ def __repr__(self):
+ return "<AttrFrontend(%s)>" % (", ".join(_get_dict(self).keys()),)
+
+
+def rpyc_excepthook(exctype, value, traceback):
+ if hasattr(value, "_remote_traceback"):
+ print >> stderr, "======= Remote traceback ======="
+ print >> stderr, value._remote_traceback
+ print >> stderr, "======= Local exception ======="
+ orig_excepthook(exctype, value, traceback)
+ else:
+ orig_excepthook(exctype, value, traceback)
+
diff --git a/Rpyc/ModuleNetProxy.py b/Rpyc/ModuleNetProxy.py
new file mode 100644
index 0000000..6c20582
--- /dev/null
+++ b/Rpyc/ModuleNetProxy.py
@@ -0,0 +1,55 @@
+from NetProxy import NetProxyWrapper, _get_conn, _get_oid
+
+
+class ModuleNetProxy(NetProxyWrapper):
+ """a netproxy specialzied for exposing remote modules (first tries to getattr,
+ if it fails tries to import)"""
+ __slots__ = ["____base__", "____cache__"]
+
+ def __init__(self, proxy, base):
+ NetProxyWrapper.__init__(self, proxy)
+ object.__setattr__(self, "____base__", base)
+ object.__setattr__(self, "____cache__", {})
+
+ def __request__(self, handler, *args):
+ return _get_conn(self).sync_request(handler, _get_oid(self), *args)
+
+ def __getattr__(self, name):
+ cache = object.__getattribute__(self, "____cache__")
+ try:
+ return cache[name]
+ except KeyError:
+ pass
+
+ try:
+ return self.__request__("handle_getattr", name)
+ except AttributeError:
+ pass
+
+ try:
+ fullname = object.__getattribute__(self, "____base__") + "." + name
+ module = ModuleNetProxy(_get_conn(self).rimport(fullname), fullname)
+ cache[name] = module
+ return module
+ except ImportError:
+ raise AttributeError("'module' object has not attribute or submodule %r" % (name,))
+
+
+class RootImporter(object):
+ """the root of the interpreter's import hierarchy"""
+ __slots__ = ["____conn__"]
+
+ def __init__(self, conn):
+ object.__setattr__(self, "____conn__", conn)
+
+ def __getitem__(self, name):
+ return _get_conn(self).rimport(name)
+
+ def __getattr__(self, name):
+ return ModuleNetProxy(self[name], name)
+
+ def __setattr__(self, name, value):
+ raise TypeError("read only type")
+
+
+
diff --git a/Rpyc/NetProxy.py b/Rpyc/NetProxy.py
new file mode 100644
index 0000000..4469fdc
--- /dev/null
+++ b/Rpyc/NetProxy.py
@@ -0,0 +1,117 @@
+from Lib import ImmDict
+
+
+class FullyDynamicMetaclass(type):
+ """
+ a meta class that enables special methods to be accessed like regular names
+ (via __getattr__), like it used to be in old-style classes.
+ """
+
+ def __new__(cls, name, bases, namespace):
+ special_methods = [
+ "__hash__", "__len__", "__iter__", "next", "__reversed__",
+ "__add__", "__iadd__", "__radd__", "__sub__", "__isub__", "__rsub__",
+ "__mul__", "__imul__", "__rmul__", "__div__", "__idiv__", "__rdiv__",
+ "__truediv__", "__itruediv__", "__rtruediv__", "__floordiv__",
+ "__ifloordiv__", "__rfloorfiv__", "__pow__", "__ipow__", "__rpow__",
+ "__lshift__", "__ilshift__", "__rlshift__", "__rshift__", "__irshift__",
+ "__rrshift__", "__and__", "__iand__", "__rand__", "__or__", "__ior__",
+ "__ror__", "__xor__", "__ixor__", "__rxor__", "__mod__", "__imod__",
+ "__rmod__", "__divmod__", "__idivmod__", "__rdivmod__", "__pos__",
+ "__neg__", "__int__", "__float__", "__long__", "__oct__", "__hex__", "__coerce__",
+ "__eq__", "__ne__", "__le__", "__ge__", "__lt__", "__gt__", "__cmp__",
+ ]
+
+ def make_method(name):
+ def method(self, *a, **k):
+ return self.__getattr__(name)(*a, **k)
+ return method
+
+ special_attributes = ["__doc__", "__module__", "__file__", "__name__"]
+
+ def make_property(name):
+ def getter(self):
+ return self.__getattr__(name)
+ def setter(self, value):
+ self.__setattr__(name, value)
+ def deller(self):
+ self.__delattr__(name)
+ return property(getter, setter, deller)
+
+ for sm in special_methods:
+ namespace[sm] = make_method(sm)
+ for sa in special_attributes:
+ namespace[sa] = make_property(sa)
+ return type.__new__(cls, name, bases, namespace)
+
+def _get_conn(proxy):
+ return object.__getattribute__(proxy, "____conn__")
+def _get_oid(proxy):
+ return object.__getattribute__(proxy, "____oid__")
+
+class NetProxy(object):
+ """NetProxy - convey local operations to the remote object. this is an abstract class"""
+ __metaclass__ = FullyDynamicMetaclass
+ __slots__ = ["____conn__", "____oid__", "__weakref__"]
+
+ def __init__(self, conn, oid):
+ object.__setattr__(self, "____conn__", conn)
+ object.__setattr__(self, "____oid__", oid)
+
+ def __request__(self, handler, *args):
+ raise NotImplementedError()
+
+ def __call__(self, *args, **kwargs):
+ return self.__request__("handle_call", args, ImmDict(kwargs))
+
+ def __delattr__(self, *args):
+ return self.__request__("handle_delattr", *args)
+ def __getattr__(self, *args):
+ return self.__request__("handle_getattr", *args)
+ def __setattr__(self, *args):
+ return self.__request__("handle_setattr", *args)
+
+ def __delitem__(self, *args):
+ return self.__request__("handle_delitem", *args)
+ def __getitem__(self, *args):
+ return self.__request__("handle_getitem", *args)
+ def __setitem__(self, *args):
+ return self.__request__("handle_setitem", *args)
+
+ def __repr__(self, *args):
+ return self.__request__("handle_repr", *args)
+ def __str__(self, *args):
+ return self.__request__("handle_str", *args)
+ def __nonzero__(self, *args):
+ return self.__request__("handle_bool", *args)
+
+class NetProxyWrapper(NetProxy):
+ """a netproxy that wraps an inner netproxy"""
+ __slots__ = ["____original__"]
+
+ def __init__(self, proxy):
+ NetProxy.__init__(self, _get_conn(proxy), _get_oid(proxy))
+ object.__setattr__(self, "____original__", proxy)
+
+def _dummy_callback(*args, **kw):
+ pass
+
+class SyncNetProxy(NetProxy):
+ """the default, synchronous netproxy"""
+ __slots__ = []
+
+ def __del__(self):
+ # decref'ing is done asynchronously, because we dont need to wait for the remote
+ # object to die. moreover, we dont care if it fails, because that would mean the
+ # connection is broken, so the remote object is already dead
+ try:
+ _get_conn(self).async_request(_dummy_callback, "handle_decref", _get_oid(self))
+ except:
+ pass
+
+ def __request__(self, handler, *args):
+ return _get_conn(self).sync_request(handler, _get_oid(self), *args)
+
+
+
+
diff --git a/Rpyc/Servers/Users.py b/Rpyc/Servers/Users.py
new file mode 100644
index 0000000..1060e0c
--- /dev/null
+++ b/Rpyc/Servers/Users.py
@@ -0,0 +1,9 @@
+#
+# chmod this file securely and be sure to remove the default users
+#
+users = {
+ "frodo" : "1ring",
+ "yossarian" : "catch22",
+ "ayla" : "jondalar",
+}
+
diff --git a/Rpyc/Servers/__init__.py b/Rpyc/Servers/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Rpyc/Servers/__init__.py
diff --git a/Rpyc/Servers/forking_server.py b/Rpyc/Servers/forking_server.py
new file mode 100644
index 0000000..1d55d01
--- /dev/null
+++ b/Rpyc/Servers/forking_server.py
@@ -0,0 +1,32 @@
+import sys
+import os
+from Rpyc.Utils.Serving import (
+ serve_socket,
+ create_listener_socket,
+ DEFAULT_PORT,
+ start_discovery_agent_thread)
+
+
+def serve_in_child(sock):
+ """forks a child to run the server in. the parent doesnt wait() for the child,
+ so if you do a `ps`, you'll see zombies. but who cares. i used to do a doublefork()
+ for that, but it's really meaningless. anyway, when the parent dies, the zombies
+ die as well."""
+ if os.fork() == 0:
+ try:
+ serve_socket(sock)
+ finally:
+ sys.exit()
+
+def main(port = DEFAULT_PORT):
+ # comment this out to disable broadcast queries
+ start_discovery_agent_thread(rpyc_port = port)
+
+ sock = create_listener_socket(port)
+ while True:
+ newsock, name = sock.accept()
+ serve_in_child(newsock)
+
+if __name__ == "__main__":
+ main()
+
diff --git a/Rpyc/Servers/selecting_server.py b/Rpyc/Servers/selecting_server.py
new file mode 100644
index 0000000..c39cf2b
--- /dev/null
+++ b/Rpyc/Servers/selecting_server.py
@@ -0,0 +1,35 @@
+import select
+import socket
+from Rpyc.Utils.Serving import (
+ log,
+ create_listener_socket,
+ DEFAULT_PORT,
+ SocketStream,
+ Channel,
+ Connection)
+
+
+def main(port = DEFAULT_PORT):
+ sock = create_listener_socket(port)
+ connections = []
+
+ while True:
+ rlist, wlist, xlist = select.select([sock] + connections, [], [])
+
+ if sock in rlist:
+ rlist.remove(sock)
+ newsock, name = sock.accept()
+ conn = Connection(Channel(SocketStream(newsock)))
+ conn.sockname = name
+ connections.append(conn)
+ log("welcome", conn.sockname)
+
+ for conn in rlist:
+ try:
+ conn.serve()
+ except (EOFError, socket.error):
+ connections.remove(conn)
+ log("goodbyte", conn.sockname)
+
+if __name__ == "__main__":
+ main()
diff --git a/Rpyc/Servers/simple_server.py b/Rpyc/Servers/simple_server.py
new file mode 100644
index 0000000..ba7b19b
--- /dev/null
+++ b/Rpyc/Servers/simple_server.py
@@ -0,0 +1,13 @@
+from Rpyc.Utils.Serving import serve_socket, create_listener_socket, DEFAULT_PORT
+
+
+def main(port = DEFAULT_PORT):
+ sock = create_listener_socket(port)
+ while True:
+ newsock, name = sock.accept()
+ serve_socket(newsock)
+
+if __name__ == "__main__":
+ main()
+
+ \ No newline at end of file
diff --git a/Rpyc/Servers/std_server.py b/Rpyc/Servers/std_server.py
new file mode 100644
index 0000000..0bf4475
--- /dev/null
+++ b/Rpyc/Servers/std_server.py
@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+#
+# installation instructions
+# * add a service in /etc/services for rpyc: tcp port 18812
+# * add "rpyc .... /usr/lib/pythonXX/site-packages/Rpyc/Servers/std_server.py"
+# to /etc/inetd.conf (i dont remember syntax, rtfm)
+# * dont forget to chmod +x this file
+# * restart inetd with sighup
+#
+import sys
+import time
+from traceback import format_exception
+from Rpyc.Utils.Serving import log, serve_pipes
+
+
+def main(filename = "/tmp/rpyc-server.log"):
+ log.logfile = open(filename, "a")
+ log("-" * 80)
+ log("started serving at", time.asctime())
+ try:
+ try:
+ serve_pipes(sys.stdin, sys.stdout)
+ except:
+ log(*format_exception(*sys.exc_info()))
+ finally:
+ log("server exits at", time.asctime())
+
+if __name__ == "__main__":
+ main()
+
+ \ No newline at end of file
diff --git a/Rpyc/Servers/threaded_server.py b/Rpyc/Servers/threaded_server.py
new file mode 100644
index 0000000..0885aba
--- /dev/null
+++ b/Rpyc/Servers/threaded_server.py
@@ -0,0 +1,10 @@
+from Rpyc.Utils.Serving import DEFAULT_PORT, threaded_server, start_discovery_agent_thread
+
+
+def main(port = DEFAULT_PORT):
+ start_discovery_agent_thread(rpyc_port = port)
+ threaded_server(port = port)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/Rpyc/Servers/tls_server.py b/Rpyc/Servers/tls_server.py
new file mode 100644
index 0000000..7b6189c
--- /dev/null
+++ b/Rpyc/Servers/tls_server.py
@@ -0,0 +1,20 @@
+from Rpyc.Utils.Serving import DEFAULT_PORT, threaded_server, start_discovery_agent_thread
+from Users import users
+from tlslite.api import VerifierDB
+
+
+#
+# creates the verifier db
+#
+vdb = VerifierDB()
+for username, password in users.iteritems():
+ vdb[username] = vdb.makeVerifier(username, password, 2048)
+
+def main(port = DEFAULT_PORT):
+ start_discovery_agent_thread(rpyc_port = port)
+ threaded_server(port = port, secure = True, vdb = vdb)
+
+
+if __name__ == "__main__":
+ main()
+
diff --git a/Rpyc/Stream.py b/Rpyc/Stream.py
new file mode 100644
index 0000000..f7e42b9
--- /dev/null
+++ b/Rpyc/Stream.py
@@ -0,0 +1,113 @@
+import select
+import socket
+
+
+class Stream(object):
+ """
+ a stream is a file-like object that is used to expose a consistent and uniform
+ interface to the underlying 'physical' file-like object (like sockets and pipes),
+ which have many quirks (sockets may recv() less than `count`, pipes are simplex
+ and don't flush, etc.). a stream is always in blocking mode.
+ """
+ __slots__ = []
+ def close(self):
+ raise NotImplementedError()
+ def fileno(self):
+ raise NotImplementedError()
+ def is_available(self):
+ rlist, wlist, xlist = select.select([self], [], [], 0)
+ return bool(rlist)
+ def read(self, count):
+ raise NotImplementedError()
+ def write(self, data):
+ raise NotImplementedError()
+
+class SocketStream(Stream):
+ """
+ a stream that operates over a socket. the socket is expected to be in
+ blocking mode and reliable (i.e., TCP)
+ """
+ CONNECT_TIMEOUT = 5
+ __slots__ = ["sock"]
+ def __init__(self, sock):
+ self.sock = sock
+ def __repr__(self):
+ host, port = self.sock.getpeername()
+ return "<%s(%s:%d)>" % (self.__class__.__name__, host, port)
+ def fileno(self):
+ return self.sock.fileno()
+ def close(self):
+ self.sock.close()
+ def read(self, count):
+ data = []
+ while count > 0:
+ buf = self.sock.recv(count)
+ if not buf:
+ raise EOFError()
+ count -= len(buf)
+ data.append(buf)
+ return "".join(data)
+ def write(self, data):
+ while data:
+ count = self.sock.send(data)
+ data = data[count:]
+ @classmethod
+ def from_new_socket(cls, host, port):
+ sock = socket.socket()
+ sock.settimeout(cls.CONNECT_TIMEOUT)
+ sock.connect((host, port))
+ sock.settimeout(None)
+ return cls(sock)
+ @classmethod
+ def from_new_secure_socket(cls, host, port, username, password):
+ from tlslite.api import TLSConnection
+ stream = cls.from_new_socket(host, port)
+ stream.sock = TLSConnection(stream.sock)
+ stream.sock.handshakeClientSRP(username, password)
+ return stream
+ @classmethod
+ def from_secure_server_socket(cls, sock, vdb):
+ from tlslite.api import TLSConnection
+ sock = TLSConnection(sock)
+ sock.handshakeServer(verifierDB=vdb)
+ return cls(sock)
+
+class PipeStream(Stream):
+ """
+ a stream that operates over two simplex pipes. the pipes are expected
+ to be in blocking mode
+ """
+ __slots__ = ["incoming", "outgoing"]
+ def __init__(self, incoming, outgoing):
+ self.incoming = incoming
+ self.outgoing = outgoing
+ def fileno(self):
+ return self.incoming.fileno()
+ def close(self):
+ self.incoming.close()
+ self.outgoing.close()
+ def read(self, count):
+ data = []
+ while count > 0:
+ buf = self.incoming.read(count)
+ if not buf:
+ raise EOFError()
+ count -= len(buf)
+ data.append(buf)
+ return "".join(data)
+ def write(self, data):
+ self.outgoing.write(data)
+ self.outgoing.flush()
+
+ #
+ # win32 stub (can't select() on pipes) -- this stub causes problems with
+ # Async objects: doing obj.is_ready blocks. but it's better to have at
+ # least some functionality with pipes on win32 than none at all.
+ #
+ from sys import platform
+
+ if platform == "win32":
+ def is_available(self):
+ return True
+
+
diff --git a/Rpyc/Utils/Builtins.py b/Rpyc/Utils/Builtins.py
new file mode 100644
index 0000000..7826c98
--- /dev/null
+++ b/Rpyc/Utils/Builtins.py
@@ -0,0 +1,152 @@
+"""
+replacements for the builtin functions, so they operate correctly on NetProxies
+"""
+import sys
+import inspect
+from Rpyc.NetProxy import NetProxy, _get_conn
+from Rpyc.Lib import (
+ orig_isinstance,
+ orig_issubclass,
+ orig_dir,
+ orig_getattr,
+ orig_reload,
+ orig_help,
+ orig_type)
+
+
+__all__ = ["dir", "getattr", "hasattr", "reload", "help", "isinstance", "issubclass"]
+
+def dir(*obj):
+ """a version of dir() that supports NetProxies"""
+ if not obj:
+ return sorted(inspect.stack()[1][0].f_locals.keys())
+ if not len(obj) == 1:
+ raise TypeError("dir expected at most 1 arguments, got %d" % (len(obj),))
+ obj = obj[0]
+ if orig_isinstance(obj, NetProxy):
+ return _get_conn(obj).modules.__builtin__.dir(obj)
+ else:
+ return orig_dir(obj)
+
+def getattr(obj, name, *default):
+ """a version of getattr() that supports NetProxies"""
+ if len(default) > 1:
+ raise TypeError("getattr expected at most 3 arguments, got %d" % (2 + len(default),))
+ if orig_isinstance(obj, NetProxy):
+ try:
+ return obj.__getattr__(name)
+ except AttributeError:
+ if not default:
+ raise
+ return default[0]
+ else:
+ return orig_getattr(obj, name, *default)
+
+def hasattr(obj, name):
+ """a version of hasattr() that supports NetProxies"""
+ try:
+ getattr(obj, name)
+ except AttributeError:
+ return False
+ else:
+ return True
+
+def _get_fullname(cls):
+ """
+ a heuristic to generate a unique identifier for classes, that is not
+ machine-, platform-, or runtime-dependent
+ """
+ if orig_isinstance(cls, NetProxy):
+ modules = _get_conn(cls).modules.sys.modules
+ else:
+ modules = sys.modules
+ try:
+ filename = modules[cls.__module__].__file__
+ except (KeyError, AttributeError):
+ filename = cls.__module__
+ return (filename, cls.__name__)
+
+def _recursive_issubclass(cls, fullname):
+ for base in cls.__bases__:
+ if _get_fullname(base) == fullname:
+ return True
+ if _recursive_issubclass(base, fullname):
+ return True
+ return False
+
+def _remote_issubclass(cls, bases):
+ cls_fullname = _get_fullname(cls)
+ for base in bases:
+ base_fullname = _get_fullname(base)
+ if cls_fullname == base_fullname:
+ return True
+ if _recursive_issubclass(cls, base_fullname):
+ return True
+ return False
+
+def issubclass(cls, bases):
+ """a version of issubclass that supports NetProxies"""
+ if not orig_isinstance(bases, tuple):
+ bases = (bases,)
+
+ # is cls a proxy?
+ if orig_isinstance(cls, NetProxy):
+ return _remote_issubclass(cls, bases)
+
+ # is one of the bases a proxy?
+ for base in bases:
+ if orig_isinstance(base, NetProxy):
+ return _remote_issubclass(cls, bases)
+
+ # plain old issubclass
+ return orig_issubclass(cls, bases)
+
+def isinstance(obj, bases):
+ """a version of isinstance that supports NetProxies"""
+ try:
+ cls = obj.__getattr__("__class__")
+ except AttributeError:
+ try:
+ cls = obj.__class__
+ except AttributeError:
+ cls = orig_type(obj)
+ return issubclass(cls, bases)
+
+def reload(module):
+ """a version of reload() that supports NetProxies"""
+ if orig_isinstance(module, NetProxy):
+ return _get_conn(module).modules.__builtin__.reload(module)
+ else:
+ return orig_reload(module)
+
+class _Helper(object):
+ """a version of help() that supports NetProxies"""
+ __repr__ = orig_help.__repr__
+
+ def __call__(self, obj = None):
+ if orig_isinstance(obj, NetProxy):
+ print "Help on NetProxy object for an instance of %r:" % (obj.__getattr__("__class__").__name__,)
+ print
+ print "Doc:"
+ print obj.__getattr__("__doc__")
+ print
+ print "Members:"
+ print dir(obj)
+ else:
+ orig_help(obj)
+help = _Helper()
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Rpyc/Utils/Discovery.py b/Rpyc/Utils/Discovery.py
new file mode 100644
index 0000000..538b38c
--- /dev/null
+++ b/Rpyc/Utils/Discovery.py
@@ -0,0 +1,38 @@
+"""
+Discovery: broadcasts a query, attempting to discover all running RPyC servers
+over the local network/specific subnet.
+"""
+import socket
+import select
+import struct
+
+
+__all__ = ["discover_servers"]
+UDP_DISCOVERY_PORT = 18813
+QUERY_MAGIC = "RPYC_QUERY"
+MAX_DGRAM_SIZE = 100
+
+
+def discover_servers(subnet = "255.255.255.255", timeout = 1):
+ """broadcasts a query and returns a list of (addr, port) of running servers"""
+ # broadcast
+ s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
+ s.sendto(QUERY_MAGIC, (subnet, UDP_DISCOVERY_PORT))
+
+ # wait for replies
+ replies = []
+ while True:
+ rlist, dummy, dummy = select.select([s], [], [], timeout)
+ if not rlist:
+ break
+ data, (addr, port) = s.recvfrom(MAX_DGRAM_SIZE)
+ rpyc_port, = struct.unpack("<H", data)
+ replies.append((addr, rpyc_port))
+
+ return list(set(replies))
+
+
+
+
+
diff --git a/Rpyc/Utils/Dist.py b/Rpyc/Utils/Dist.py
new file mode 100644
index 0000000..30ed3eb
--- /dev/null
+++ b/Rpyc/Utils/Dist.py
@@ -0,0 +1,37 @@
+"""
+functions for distributing package and modules across hosts
+"""
+import inspect
+from Files import upload_dir
+from Builtins import reload
+
+
+__all__ = ["upload_package", "update_module"]
+
+def upload_package(conn, module, remotepath = None):
+ """
+ uploads the given package to the server, storing it in `remotepath`. if
+ remotepath is None, it defaults to the server's site-packages. if the package
+ already exists, it is overwritten.
+ usage:
+ import xml
+ upload_package(conn, xml)
+ """
+ if remotepath is None:
+ remotepath = conn.modules["distutils.sysconfig"].get_python_lib()
+ localpath = os.path.dirname(module.__file__)
+ upload_dir(conn, localpath, remotepath, [".py", ".pyd", ".dll", ".so", ".zip"])
+
+def update_module(conn, module):
+ """
+ updates an existing module on the server. the local module is transfered to the
+ server, overwriting the old one, and is reloaded.
+ usage:
+ import xml.dom.minidom
+ update_module(conn, xml.dom.minidom)
+ """
+ remote_module = conn.modules[module.__name__]
+ local_file = inspect.getsourcefile(module)
+ remote_file = inspect.getsourcefile(remote_module)
+ upload_file(conn, local_filem, remote_file)
+ reload(remote_module) \ No newline at end of file
diff --git a/Rpyc/Utils/Factories.py b/Rpyc/Utils/Factories.py
new file mode 100644
index 0000000..8519beb
--- /dev/null
+++ b/Rpyc/Utils/Factories.py
@@ -0,0 +1,56 @@
+"""
+the factory:
+exposes a nice and easy interface to the internals of rpyc.
+this module, along with Utils, are the only modules most clients will need.
+"""
+from weakref import WeakValueDictionary
+from Serving import DEFAULT_PORT
+from Rpyc.Stream import SocketStream, PipeStream
+from Rpyc.Channel import Channel
+from Rpyc.Connection import Connection
+from Rpyc.AsyncNetProxy import AsyncNetProxy
+
+
+__all__ = ["SocketConnection", "PipeConnection", "SecSocketConnection", "Async",
+ "LoginError"]
+
+#
+# connection factories
+#
+def SocketConnection(host, port = DEFAULT_PORT):
+ """shorthand for creating a conneciton over a socket to a server"""
+ return Connection(Channel(SocketStream.from_new_socket(host, port)))
+
+def PipeConnection(incoming, outgoing):
+ """shorthand for creating a conneciton over a pipe"""
+ return Connection(Channel(PipeStream(incoming, outgoing)))
+
+class LoginError(Exception):
+ pass
+
+def SecSocketConnection(host, username, password, port = DEFAULT_PORT):
+ """shorthand for creating secure socket connections"""
+ try:
+ stream = SocketStream.from_new_secure_socket(host, port, username, password)
+ except:
+ raise LoginError("authentication failure")
+ return Connection(Channel(stream))
+
+#
+# Async factory
+#
+_async_proxy_cache = WeakValueDictionary()
+
+def Async(proxy):
+ """a factory for creating asynchronous proxies for existing synchronous ones"""
+ key = id(proxy)
+ if key in _async_proxy_cache:
+ return _async_proxy_cache[key]
+ else:
+ new_proxy = AsyncNetProxy(proxy)
+ _async_proxy_cache[key] = new_proxy
+ return new_proxy
+
+
+
+
diff --git a/Rpyc/Utils/Files.py b/Rpyc/Utils/Files.py
new file mode 100644
index 0000000..17c1112
--- /dev/null
+++ b/Rpyc/Utils/Files.py
@@ -0,0 +1,112 @@
+"""
+file convenience routines
+"""
+import os
+
+
+__all__ = ["upload", "download"]
+CHUNK_SIZE = 1300 # to fit in one ethernet frame
+
+#
+# exceptions
+#
+class UploadError(Exception):
+ pass
+class DownloadError(Exception):
+ pass
+
+#
+# API
+#
+def upload(conn, localpath, remotepath, *a, **k):
+ """
+ uploads a file or a directory recursively (depending on what `localpath` is)
+ an optional `extentions` keyword argument may be given, specifying the
+ extensions of the files to be uploaded (relevant to directories only). if
+ no extentions are given, all files will be uploaded.
+ """
+ if os.path.isdir(localpath):
+ upload_dir(conn, localpath, remotepath, *a, **k)
+ elif os.path.isfile(localpath):
+ upload_file(conn, localpath, remotepath, *a, **k)
+ else:
+ raise UploadError("can only upload files or directories")
+
+def download(conn, remotepath, localpath, *a, **k):
+ """
+ downloads a file or a directory recursively (depending on what `remotepath` is)
+ an optional `extentions` keyword argument may be given, specifying the
+ extensions of the files to be downloaded (relevant to directories only). if
+ no extentions are given, all files will be downloaded.
+ """
+ if conn.modules.os.path.isdir(remotepath):
+ download_dir(conn, remotepath, localpath, *a, **k)
+ elif conn.modules.os.path.isfile(remotepath):
+ download_file(conn, remotepath, localpath, *a, **k)
+ else:
+ raise DownloadError("can only download files or directories")
+
+#
+# internal
+#
+def upload_file(conn, localpath, remotepath):
+ lf = open(localpath, "rb")
+ rf = conn.modules.__builtin__.open(remotepath, "wb")
+ while True:
+ chunk = lf.read(CHUNK_SIZE)
+ if not chunk:
+ break
+ rf.write(chunk)
+ lf.close()
+ rf.close()
+
+def download_file(conn, remotepath, localpath):
+ lf = open(localpath, "wb")
+ rf = conn.modules.__builtin__.open(remotepath, "rb")
+ while True:
+ chunk = rf.read(CHUNK_SIZE)
+ if not chunk:
+ break
+ lf.write(chunk)
+ lf.close()
+ rf.close()
+
+def upload_dir(conn, localpath, remotepath, extensions = [""]):
+ # create the remote path
+ if not conn.modules.os.path.exists(remotepath):
+ conn.modules.os.makedirs(remotepath)
+
+ # upload files and directories
+ for fn in os.listdir(localpath):
+ lfn = os.path.join(localpath, fn)
+ rfn = conn.modules.os.path.join(remotepath, fn)
+
+ if os.path.isdir(lfn):
+ upload_dir(conn, lfn, rfn, extensions)
+
+ elif os.path.isfile(lfn):
+ for ext in extensions:
+ if fn.endswith(ext):
+ upload_file(conn, lfn, rfn)
+ break
+
+def download_dir(conn, remotepath, localpath, extensions = [""]):
+ # create the local path
+ if not os.path.exists(localpath):
+ os.makedirs(localpath)
+
+ # download files and directories
+ for fn in conn.modules.os.listdir(remotepath):
+ lfn = os.path.join(localpath, fn)
+ rfn = conn.modules.os.path.join(remotepath, fn)
+
+ if conn.modules.os.path.isdir(lfn):
+ download_dir(conn, rfn, lfn, extensions)
+
+ elif conn.modules.os.path.isfile(lfn):
+ for ext in extensions:
+ if fn.endswith(ext):
+ download_file(conn, rfn, lfn)
+ break
+
+
diff --git a/Rpyc/Utils/Helpers.py b/Rpyc/Utils/Helpers.py
new file mode 100644
index 0000000..ef18d23
--- /dev/null
+++ b/Rpyc/Utils/Helpers.py
@@ -0,0 +1,149 @@
+"""
+various helper functions
+"""
+import sys
+import cPickle as pickle
+from Builtins import isinstance
+from Rpyc.Lib import orig_isinstance
+from Rpyc.NetProxy import NetProxy, _get_conn
+from types import CodeType as code, FunctionType as function
+
+
+__all__ = ["obtain", "deliver", "isproxy", "getconn", "RedirectedStd", "DeliveringNamespace"]
+
+def isproxy(obj):
+ """indicates whether the given object is a NetProxy"""
+ return orig_isinstance(obj, NetProxy)
+
+def getconn(obj):
+ """returns the connection of a NetProxy"""
+ if not isproxy(obj):
+ raise TypeError("`obj` is not a NetProxy")
+ return _get_conn(obj)
+
+def _dump_function(func):
+ """serializes a function"""
+ func_info = (
+ func.func_name,
+ func.func_defaults,
+ func.func_closure,
+ )
+ code_info = (
+ func.func_code.co_argcount,
+ func.func_code.co_nlocals,
+ func.func_code.co_stacksize,
+ func.func_code.co_flags,
+ func.func_code.co_code,
+ func.func_code.co_consts,
+ func.func_code.co_names,
+ func.func_code.co_varnames,
+ func.func_code.co_filename,
+ func.func_code.co_name,
+ func.func_code.co_firstlineno,
+ func.func_code.co_lnotab,
+ func.func_code.co_freevars,
+ func.func_code.co_cellvars,
+ )
+ return pickle.dumps((code_info, func_info, func.func_doc), pickle.HIGHEST_PROTOCOL)
+
+def _load_function(pickled_func, globals):
+ """recreates a serialized function"""
+ code_info, func_info, doc = pickle.loads(pickled_func)
+ func = function(code(*code_info), globals, *func_info)
+ func.func_doc = doc
+ return func
+
+def obtain(proxy):
+ """
+ obtains (brings forth) a remote object. the object can be a function or
+ any picklable object. obtaining objects creates a local copy of the remote
+ object, so changes made to the local copy are not reflected on the remote
+ one. keep this in mind.
+
+ proxy - any proxy to a remote object
+ returns a "real" object
+ """
+ if not isproxy(proxy):
+ raise TypeError("object must be a proxy")
+ if isinstance(proxy, function):
+ globals = getconn(proxy)._local_namespace
+ return _load_function(_dump_function(proxy), globals)
+ else:
+ return pickle.loads(getconn(proxy).modules.cPickle.dumps(proxy, pickle.HIGHEST_PROTOCOL))
+
+def deliver(obj, conn):
+ """
+ delivers a local object to the other side of the connection. the object
+ can be a function or any picklable object. deliver objects creates a remote
+ copy of the objectm so changes made to the remote copy are not reflected on
+ the local one. keep this in mind.
+
+ obj - the object to deliver
+ conn - the connection which obtains the object
+ returns a proxy to the delivered object
+ """
+ if isproxy(obj):
+ raise TypeError("can't deliver proxies")
+ if orig_isinstance(obj, function):
+ globals = conn.remote_conn._local_namespace
+ dumped = _dump_function(obj)
+ return conn.modules[__name__]._load_function(dumped, globals)
+ else:
+ return conn.modules.cPickle.loads(pickle.dumps(obj, pickle.HIGHEST_PROTOCOL))
+
+class DeliveringNamespace(object):
+ """delivering namesapce: getattr`ing from this object returns a proxy,
+ while setattr`ing this object delivers the given object to the remote side
+ of the connection"""
+ __slots__ = ["____conn__"]
+ def __init__(self, conn):
+ object.__setattr__(self, "____conn__", conn)
+ def __getattr__(self, name):
+ return _get_conn(self).namespace[name]
+ def __setattr__(self, name, value):
+ if isproxy(value):
+ if _get_conn(value) is not _get_conn(self):
+ raise TypeError("proxies must belong to the namespace's connection")
+ _get_conn(self).namespace[name] = value
+ else:
+ _get_conn(self).namespace[name] = deliver(value, _get_conn(self))
+
+class RedirectedStd(object):
+ """redirected std[in|out|err] context"""
+ __slots__ = ["conn", "redirected", "orig_stdin", "orig_stdout", "orig_strerr"]
+ def __init__(self, conn):
+ self.conn = conn
+ self.redirected = False
+ def __del__(self):
+ self.restore()
+ def redirect(self):
+ if self.redirected:
+ return
+ self.orig_stdin = self.conn.modules.sys.stdin
+ self.orig_stdout = self.conn.modules.sys.stdout
+ self.orig_strerr = self.conn.modules.sys.stderr
+ self.conn.modules.sys.stdin = sys.stdin
+ self.conn.modules.sys.stdout = sys.stdout
+ self.conn.modules.sys.stderr = sys.stderr
+ self.redirected = True
+ def restore(self):
+ if not self.redirected:
+ return
+ self.conn.modules.sys.stdin = self.orig_stdin
+ self.conn.modules.sys.stdout = self.orig_stdout
+ self.conn.modules.sys.stderr = self.orig_strerr
+ self.redirected = False
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Rpyc/Utils/Interpreter.py b/Rpyc/Utils/Interpreter.py
new file mode 100644
index 0000000..0960d07
--- /dev/null
+++ b/Rpyc/Utils/Interpreter.py
@@ -0,0 +1,39 @@
+"""
+remote interpreter functions
+"""
+import sys
+from Helpers import RedirectedStd
+
+
+__all__ = ["remote_interpreter", "remote_pm"]
+
+def remote_interpreter(conn, namespace = None):
+ """starts an interactive interpreter on the server"""
+ if namespace is None:
+ namespace = {"conn" : conn}
+
+ std = RedirectedStd(conn)
+ try:
+ std.redirect()
+ conn.modules[__name__]._remote_interpreter_server_side(**namespace)
+ finally:
+ std.restore()
+
+def _remote_interpreter_server_side(**namespace):
+ import code
+ namespace.update(globals())
+ code.interact(local = namespace)
+
+def remote_pm(conn):
+ """a version of pdb.pm() that operates on exceptions at the remote side of the connection"""
+ import pdb
+ pdb.post_mortem(conn.modules.sys.last_traceback)
+
+
+
+
+
+
+
+
+
diff --git a/Rpyc/Utils/Serving.py b/Rpyc/Utils/Serving.py
new file mode 100644
index 0000000..b726428
--- /dev/null
+++ b/Rpyc/Utils/Serving.py
@@ -0,0 +1,126 @@
+import os
+import socket
+import sys
+import gc
+import struct
+from threading import Thread
+from Rpyc.Connection import Connection
+from Rpyc.Stream import SocketStream, PipeStream
+from Rpyc.Channel import Channel
+from Discovery import UDP_DISCOVERY_PORT, MAX_DGRAM_SIZE, QUERY_MAGIC
+
+DEFAULT_PORT = 18812
+
+
+#
+# utilities
+#
+class _Logger(object):
+ def __init__(self, logfile = None, active = True):
+ self.logfile = logfile
+ self.active = active
+ def __call__(self, *args):
+ if self.active and self.logfile:
+ text = " ".join(str(a) for a in args)
+ self.logfile.write("[%d] %s\n" % (os.getpid(), text))
+ self.logfile.flush()
+
+log = _Logger(sys.stdout)
+
+def create_listener_socket(port):
+ sock = socket.socket()
+ sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+ sock.bind(("", port))
+ sock.listen(4)
+ log("listening on", sock.getsockname())
+ return sock
+
+#
+# serving
+#
+def serve_channel(chan):
+ conn = Connection(chan)
+ try:
+ try:
+ while True:
+ conn.serve()
+ except EOFError:
+ pass
+ finally:
+ conn.close()
+ gc.collect()
+
+def serve_socket_helper(sock, secure = False, vdb = None):
+ if secure:
+ log("requiring authentication")
+ try:
+ stream = SocketStream.from_secure_server_socket(sock, vdb)
+ except:
+ log("authenication failed")
+ sock.close()
+ else:
+ log("authentication successful")
+ serve_channel(Channel(stream))
+ else:
+ serve_channel(Channel(SocketStream(sock)))
+
+def serve_socket(sock, **kw):
+ sockname = sock.getpeername()
+ log("welcome", sockname)
+ try:
+ try:
+ serve_socket_helper(sock, **kw)
+ except socket.error:
+ pass
+ finally:
+ log("goodbye", sockname)
+
+def serve_pipes(incoming, outgoing):
+ serve_channel(Channel(PipeStream(incoming, outgoing)))
+
+#
+# threaded utilities
+#
+def threaded_server(port = DEFAULT_PORT, **kw):
+ sock = create_listener_socket(port)
+ while True:
+ newsock, name = sock.accept()
+ t = Thread(target = serve_socket, args = (newsock,), kwargs = kw)
+ t.setDaemon(True)
+ t.start()
+
+def start_threaded_server(*args, **kwargs):
+ """starts the threaded_server on a separate thread. this turns the
+ threaded_server into a mix-in you can place anywhere in your code"""
+ t = Thread(target = threaded_server, args = args, kwargs = kwargs)
+ t.setDaemon(True)
+ t.start()
+
+#
+# discovery
+#
+def discovery_agent(rpyc_port):
+ """
+ answers broadcasted queries with the port of the RPyC server on this machine.
+ run this agent on a separate thread
+ """
+ data = struct.pack("<H", rpyc_port)
+
+ # listen
+ s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ s.bind(("", UDP_DISCOVERY_PORT))
+ log("discovery_agent: started")
+
+ # serve
+ while True:
+ query, addr = s.recvfrom(MAX_DGRAM_SIZE)
+ if query == QUERY_MAGIC:
+ log("discovery_agent: now answering", addr)
+ s.sendto(data, addr)
+
+def start_discovery_agent_thread(*args, **kwargs):
+ t = Thread(target = discovery_agent, args = args, kwargs = kwargs)
+ t.setDaemon(True)
+ t.start()
+
+
diff --git a/Rpyc/Utils/__init__.py b/Rpyc/Utils/__init__.py
new file mode 100644
index 0000000..6bd09d9
--- /dev/null
+++ b/Rpyc/Utils/__init__.py
@@ -0,0 +1,7 @@
+from Builtins import *
+from Helpers import *
+from Files import *
+from Interpreter import *
+from Dist import *
+from Discovery import *
+from Factories import *
diff --git a/Rpyc/__init__.py b/Rpyc/__init__.py
new file mode 100644
index 0000000..6a495ef
--- /dev/null
+++ b/Rpyc/__init__.py
@@ -0,0 +1,33 @@
+"""
+RPyC -- Remote Python Call
+http://rpyc.sourceforge.net
+by Tomer Filiba (tomerfiliba at gmail dot com)
+"""
+import sys
+from Lib import rpyc_excepthook
+from Utils import *
+
+
+#
+# API
+#
+__all__ = [
+ # Factories
+ "SocketConnection", "PipeConnection", "SecSocketConnection", "Async",
+ # Builtins
+ "dir", "getattr", "hasattr", "reload", "help", "isinstance", "issubclass",
+ # Helpers
+ "obtain", "deliver", "isproxy", "getconn",
+ # Files
+ "upload", "download",
+ # Discovery
+ "discover_servers",
+]
+
+__version__ = (2, 60)
+
+
+#
+# install custom exception hook
+#
+sys.excepthook = rpyc_excepthook
diff --git a/Rpyc/tests/isinstance.py b/Rpyc/tests/isinstance.py
new file mode 100644
index 0000000..aa5e2cb
--- /dev/null
+++ b/Rpyc/tests/isinstance.py
@@ -0,0 +1,53 @@
+from Rpyc import *
+import time
+c=SocketConnection("localhost")
+
+t=time.time()
+assert isinstance(1, int) == True
+assert isinstance(1, float) == False
+assert isinstance(1, (int, float)) == True
+assert isinstance(1, (str, float)) == False
+
+assert isinstance(c.modules.sys.path, list) == True
+assert isinstance(c.modules.sys.path, str) == False
+assert isinstance(c.modules.sys.path, (list, str)) == True
+assert isinstance(c.modules.sys.path, (int, str)) == False
+
+assert isinstance(c.modules.sys.path, c.modules.__builtin__.list) == True
+assert isinstance(c.modules.sys.path, (str, c.modules.__builtin__.list)) == True
+assert isinstance(c.modules.sys.path, c.modules.__builtin__.int) == False
+assert isinstance(c.modules.sys.path, (str, c.modules.__builtin__.int)) == False
+
+assert isinstance([1,2,3], c.modules.__builtin__.list) == True
+assert isinstance([1,2,3], c.modules.__builtin__.int) == False
+assert isinstance([1,2,3], (c.modules.__builtin__.list, int)) == True
+assert isinstance([1,2,3], (c.modules.__builtin__.int, int)) == False
+
+assert issubclass(str, str) == True
+assert issubclass(str, basestring) == True
+assert issubclass(str, (int, basestring)) == True
+assert issubclass(str, int) == False
+assert issubclass(str, (int, float)) == False
+
+assert issubclass(c.modules.__builtin__.str, str) == True
+assert issubclass(c.modules.__builtin__.str, basestring) == True
+assert issubclass(c.modules.__builtin__.str, (list, basestring)) == True
+assert issubclass(c.modules.__builtin__.str, int) == False
+assert issubclass(c.modules.__builtin__.str, (int, float)) == False
+
+assert issubclass(c.modules.__builtin__.str, c.modules.__builtin__.str) == True
+assert issubclass(c.modules.__builtin__.str, c.modules.__builtin__.basestring) == True
+assert issubclass(c.modules.__builtin__.str, (list, c.modules.__builtin__.basestring)) == True
+assert issubclass(c.modules.__builtin__.str, c.modules.__builtin__.int) == False
+assert issubclass(c.modules.__builtin__.str, (c.modules.__builtin__.int, c.modules.__builtin__.float)) == False
+
+assert issubclass(str, c.modules.__builtin__.str) == True
+assert issubclass(str, c.modules.__builtin__.basestring) == True
+assert issubclass(str, (int, c.modules.__builtin__.basestring)) == True
+assert issubclass(int, c.modules.__builtin__.str) == False
+assert issubclass(int, (c.modules.__builtin__.str, float)) == False
+
+t=time.time()-t
+print "all okay", t
+
+
diff --git a/activity/PyDebug.svg b/activity/PyDebug.svg
new file mode 100644
index 0000000..6b4c824
--- /dev/null
+++ b/activity/PyDebug.svg
@@ -0,0 +1,38 @@
+<?xml version="1.0" ?><!-- Created with Inkscape (http://www.inkscape.org/) --><!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd' [
+ <!ENTITY stroke_color "#666666">
+ <!ENTITY fill_color "#ffffff">
+]><svg height="55px" id="svg4502" inkscape:output_extension="org.inkscape.output.svg.inkscape" inkscape:version="0.46" sodipodi:docbase="/Users/eben/Desktop" sodipodi:docname="nobug1.svg" sodipodi:version="0.32" version="1.0" width="55px" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:svg="http://www.w3.org/2000/svg">
+ <defs id="defs4504">
+ <inkscape:perspective id="perspective2408" inkscape:persp3d-origin="27.5 : 18.333333 : 1" inkscape:vp_x="0 : 27.5 : 1" inkscape:vp_y="0 : 1000 : 0" inkscape:vp_z="55 : 27.5 : 1" sodipodi:type="inkscape:persp3d"/>
+ </defs>
+ <sodipodi:namedview bordercolor="#666666" borderopacity="1.0" gridtolerance="10000" guidetolerance="10" height="55px" id="base" inkscape:current-layer="layer1" inkscape:cx="42.071601" inkscape:cy="43.886629" inkscape:document-units="px" inkscape:guide-bbox="true" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:window-height="722" inkscape:window-width="1060" inkscape:window-x="-5" inkscape:window-y="25" inkscape:zoom="3.959798" objecttolerance="10" pagecolor="#ffffff" showgrid="false" showguides="true" width="55px">
+ <inkscape:grid color="#0000ff" empcolor="#0000ff" empopacity="0.4" empspacing="5" id="GridFromPre046Settings" opacity="0.2" originx="0px" originy="0px" spacingx="15px" spacingy="15px" type="xygrid"/>
+ </sodipodi:namedview>
+ <metadata id="metadata4507">
+ <rdf:RDF>
+ <cc:Work rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+
+
+ <g id="layer4" inkscape:groupmode="layer" inkscape:label="icon" style="display:inline">
+ <path d="M 45.419766,27.725882 A 15.620267,16.667517 0 1 1 45.378403,26.513714" id="path3180" sodipodi:cx="29.7995" sodipodi:cy="27.725882" sodipodi:end="6.2103947" sodipodi:open="true" sodipodi:rx="15.620267" sodipodi:ry="16.667517" sodipodi:start="0" sodipodi:type="arc" style="opacity:1;fill:&fill_color;;fill-opacity:1;stroke:&stroke_color;;stroke-width:3.21601844000000003;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" transform="matrix(1.0578636,-0.6107578,0.5723828,0.9913961,-18.350837,18.943785)"/>
+ <path d="M 27.02158,27.85215 A 4.6719556,3.1567266 0 1 1 27.009209,27.622573" id="path3184" sodipodi:cx="22.349625" sodipodi:cy="27.85215" sodipodi:end="6.2103947" sodipodi:open="true" sodipodi:rx="4.6719556" sodipodi:ry="3.1567266" sodipodi:start="0" sodipodi:type="arc" style="opacity:1;fill:&fill_color;;fill-opacity:1;stroke:&stroke_color;;stroke-width:1.52999996999999999;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" transform="matrix(1.5515534,-0.8957898,0.7257689,1.2570686,-31.568224,15.958659)"/>
+ <path d="M 39.143411,27.473343 A 4.1668792,2.7779195 0 1 1 39.132377,27.271315" id="path3186" sodipodi:cx="34.976532" sodipodi:cy="27.473343" sodipodi:end="6.2103947" sodipodi:open="true" sodipodi:rx="4.1668792" sodipodi:ry="2.7779195" sodipodi:start="0" sodipodi:type="arc" style="opacity:1;fill:&fill_color;;fill-opacity:1;stroke:&stroke_color;;stroke-width:1.52999996999999999;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" transform="matrix(0.8660254,-0.4999999,0.4999999,0.8660254,-8.3139656,18.075285)"/>
+ <path d="M 14.694245,15.814087 L 44.399678,38.627524" id="path5903" style="fill:&fill_color;;fill-opacity:1;fill-rule:evenodd;stroke:&stroke_color;;stroke-width:3.85435009000000006;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"/>
+ <path d="M 36.839412,20.52179 L 38.007239,15.473456" id="path5905" style="fill:&fill_color;;fill-opacity:1;fill-rule:evenodd;stroke:&stroke_color;;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"/>
+ <path d="M 40.113343,24.172097 L 44.96774,23.993864" id="path5907" style="fill:&fill_color;;fill-opacity:1;fill-rule:evenodd;stroke:&stroke_color;;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"/>
+ <path d="M 20.968852,36.974809 L 22.157239,43.578843" id="path5909" style="fill:&fill_color;;fill-opacity:1;fill-rule:evenodd;stroke:&stroke_color;;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"/>
+ <path d="M 16.617102,30.447509 L 11.21473,27.15124" id="path5911" style="fill:&fill_color;;fill-opacity:1;fill-rule:evenodd;stroke:&stroke_color;;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"/>
+ <path d="M 21.924611,26.508401 L 16.630375,19.358822" id="path5913" style="fill:&fill_color;;fill-opacity:1;fill-rule:evenodd;stroke:&stroke_color;;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"/>
+ <path d="M 27.804862,24.571464 L 27.078653,16.242565" id="path5915" style="fill:&fill_color;;fill-opacity:1;fill-rule:evenodd;stroke:&stroke_color;;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"/>
+ <path d="M 31.214128,30.476485 L 38.584842,32.636332" id="path5917" style="fill:&fill_color;;fill-opacity:1;fill-rule:evenodd;stroke:&stroke_color;;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"/>
+ <path d="M 26.377862,34.726734 L 31.672098,41.876313" id="path5919" style="fill:&fill_color;;fill-opacity:1;fill-rule:evenodd;stroke:&stroke_color;;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"/>
+ <path d="M -6.3733532,-20.668102 A 0.41037458,0.41037455 0 1 1 -6.3733196,-20.668117" id="path5929" sodipodi:cx="-6.5344243" sodipodi:cy="-21.045546" sodipodi:end="7.4505469" sodipodi:open="true" sodipodi:rx="0.41037458" sodipodi:ry="0.41037455" sodipodi:start="1.1674506" sodipodi:type="arc" style="opacity:1;fill:&fill_color;;fill-opacity:1;stroke:&stroke_color;;stroke-width:0.46700001000000002;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" transform="translate(44.509846,45.677835)"/>
+ <path d="M -8.6221674,-21.077112 A 0.99436891,0 0 1 1 -9.012455,-21.077112 L -9.012455,-21.077112 z" id="path5931" sodipodi:cx="-9.012455" sodipodi:cy="-21.077112" sodipodi:end="4.712389" sodipodi:rx="0.99436891" sodipodi:ry="0" sodipodi:start="1.1674506" sodipodi:type="arc" style="opacity:1;fill:#f02d10;fill-opacity:1;stroke:#1015f0;stroke-width:0.46700001;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"/>
+ <path d="M -6.3733532,-20.668102 A 0.41037458,0.41037455 0 1 1 -6.3733196,-20.668117" id="path7025" sodipodi:cx="-6.5344243" sodipodi:cy="-21.045546" sodipodi:end="7.4505469" sodipodi:open="true" sodipodi:rx="0.41037458" sodipodi:ry="0.41037455" sodipodi:start="1.1674506" sodipodi:type="arc" style="opacity:1;fill:&fill_color;;fill-opacity:1;stroke:&stroke_color;;stroke-width:0.46700001000000002;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" transform="translate(42.742079,43.625963)"/>
+ </g>
+</svg> \ No newline at end of file
diff --git a/activity/PyDebug.svg.save b/activity/PyDebug.svg.save
new file mode 100644
index 0000000..ca51c6e
--- /dev/null
+++ b/activity/PyDebug.svg.save
@@ -0,0 +1,1632 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="55"
+ height="55"
+ id="svg4502"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ version="1.0"
+ sodipodi:docbase="/Users/eben/Desktop"
+ sodipodi:docname="nobug.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape">
+ <defs
+ id="defs4504">
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 27.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="55 : 27.5 : 1"
+ inkscape:persp3d-origin="27.5 : 18.333333 : 1"
+ id="perspective2422" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ gridtolerance="10000"
+ guidetolerance="10"
+ objecttolerance="10"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="5.4545455"
+ inkscape:cx="55"
+ inkscape:cy="9.6827731"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer4"
+ width="55px"
+ height="55px"
+ inkscape:window-width="701"
+ inkscape:window-height="722"
+ inkscape:window-x="233"
+ inkscape:window-y="25"
+ showgrid="false"
+ borderlayer="false"
+ showborder="false"
+ inkscape:showpageshadow="false">
+ <inkscape:grid
+ id="GridFromPre046Settings"
+ type="xygrid"
+ originx="0px"
+ originy="0px"
+ spacingx="15px"
+ spacingy="15px"
+ color="#0000ff"
+ empcolor="#0000ff"
+ opacity="0.2"
+ empopacity="0.4"
+ empspacing="5"
+ visible="true"
+ enabled="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata4507">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="_guide"
+ inkscape:groupmode="layer"
+ id="layer1"
+ style="display:none">
+ <g
+ id="_x5F_guide">
+ <rect
+ x="0"
+ width="55"
+ height="55"
+ id="rect2336"
+ y="0"
+ style="fill:#282828;fill-opacity:1" />
+ <rect
+ x="5"
+ y="5"
+ width="45"
+ height="45"
+ id="rect2338"
+ style="fill:none;stroke:#000000;stroke-opacity:1" />
+ <flowRoot
+ xml:space="preserve"
+ id="flowRoot4579"><flowRegion
+ id="flowRegion4581"><rect
+ id="rect4583"
+ width="47.72971"
+ height="44.194176"
+ x="62.124382"
+ y="-15.710678" /></flowRegion><flowPara
+ id="flowPara4585">r2r2r23r23r23r23r23r</flowPara></flowRoot> </g>
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="_swatches"
+ style="display:inline">
+ <g
+ id="_x5F_swatches">
+ <rect
+ x="84.695"
+ y="29.729"
+ width="8.783"
+ height="8.7819996"
+ id="rect2322"
+ style="fill:#ffffff;stroke:#ffffff;stroke-width:3.5" />
+ <rect
+ x="84.695"
+ y="3.3840001"
+ width="8.783"
+ height="8.7799997"
+ id="rect2328"
+ style="fill:none;stroke:#ffffff;stroke-width:3.5" />
+ <rect
+ x="58.349998"
+ y="29.729"
+ width="8.783"
+ height="8.7819996"
+ id="rect2330"
+ style="fill:#ffffff" />
+ <g
+ style="overflow:visible"
+ id="g3"
+ transform="matrix(0.1374764,0,0,0.1719563,9.4674357,9.2051423)">
+ <path
+ d="M 205.672,63.899 C 205.199,61.045 204.9,58.477 203.81,55.744 C 202.779,53.158 200.692,50.797 198.629,48.984 C 194.322,45.198 188.402,42.983 182.919,41.606 C 171.408,38.716 158.452,38.971 146.947,41.689 C 141.141,43.061 135.16,44.553 129.843,47.323 C 124.534,50.089 119.561,53.288 115,57.165 C 105.967,64.844 97.629,73.551 90.519,83.074 C 83.33,92.703 84.812,105.377 92.519,114.079 C 96.183,118.215 101.79,121.251 106.959,122.985 C 112.645,124.892 118.213,124.902 124.096,125.398 C 136.104,126.412 147.939,129.307 159.98,129.94 C 171.13,130.526 184.555,131.21 193.466,123.251 C 201.654,115.938 206.237,106.562 207.225,95.639 C 207.679,90.603 208.355,85.23 207.728,80.187 C 207.059,74.779 205.672,69.363 205.672,63.899"
+ id="path5"
+ style="fill-rule:evenodd" />
+
+
+ <path
+ d="M 205.141,63.899 C 204.423,59.594 203.703,56.009 201.016,52.402 C 198.433,48.934 194.504,46.693 190.662,44.938 C 186.622,43.093 182.541,41.855 178.134,41.172 C 176.095,40.857 174.05,40.702 171.993,40.543 C 170.624,40.437 165.731,40.855 166.293,39.034 C 175.55,39.747 183.993,40.581 192.531,44.479 C 196.473,46.279 199.602,49.048 202.213,52.401 C 204.974,55.947 205.485,59.563 206.203,63.898 C 205.875,63.899 205.454,63.988 205.141,63.899"
+ id="path7" />
+
+
+ <path
+ d="M 166.293,40.104 C 160.215,40.425 154.224,40.602 148.268,41.931 C 142.282,43.267 136.288,44.961 130.732,47.564 C 120.504,52.357 110.7,60.257 103.347,68.786 C 102.6,69.652 101.853,70.518 101.107,71.385 C 99.512,70.468 101.422,69.29 102.21,68.378 C 103.158,67.278 104.105,66.233 105.128,65.205 C 107.144,63.18 109.326,61.396 111.419,59.455 C 115.645,55.536 120.553,51.625 125.653,48.891 C 136.501,43.075 148.381,39.981 160.642,39.334 C 162.526,39.234 164.41,39.135 166.293,39.036 C 166.293,39.365 166.383,39.789 166.293,40.104"
+ id="path9" />
+
+
+ <path
+ d="M 166.293,39.035 C 166.293,39.391 166.293,39.747 166.293,40.104 C 166.293,39.747 166.293,39.391 166.293,39.035"
+ id="path11" />
+
+
+ <path
+ d="M 101.107,71.385 C 97.531,75.516 94.015,79.62 90.621,83.886 C 89.098,85.802 87.94,88.414 87.27,90.768 C 86.932,91.955 86.757,93.154 86.605,94.378 C 86.464,95.508 86.811,98.108 85.142,97.586 C 85.743,92.154 86.778,87.366 89.852,82.732 C 92.762,78.346 96.784,74.46 100.306,70.583 C 100.544,70.82 100.951,71.091 101.107,71.385"
+ id="path13" />
+
+
+ <path
+ d="M 100.308,70.583 C 100.575,70.85 100.841,71.118 101.108,71.385 C 100.841,71.118 100.574,70.85 100.308,70.583"
+ id="path15" />
+
+
+ <path
+ d="M 86.207,97.586 C 86.867,101.565 87.085,105.574 89.4,109.083 C 91.554,112.349 94.129,115.396 97.382,117.638 C 104.728,122.702 112.908,124.185 121.594,124.857 C 121.694,126.5 120.043,125.819 118.963,125.729 C 117.757,125.628 116.551,125.526 115.345,125.424 C 113.082,125.233 110.887,124.707 108.693,124.155 C 104.409,123.078 100.337,120.889 96.759,118.374 C 93.434,116.037 89.617,112.835 88.068,108.948 C 87.264,106.929 86.55,105.04 85.861,102.963 C 85.492,101.847 84.184,96.973 86.207,97.586"
+ id="path17" />
+
+
+ <path
+ d="M 85.143,97.586 C 85.497,97.586 85.852,97.586 86.206,97.586 C 85.852,97.586 85.498,97.586 85.143,97.586"
+ id="path19" />
+
+
+ <path
+ d="M 121.595,124.856 C 133.568,124.856 145.61,127.962 157.514,129.16 C 163.26,129.738 169.193,130.028 174.94,129.387 C 177.816,129.066 180.675,128.823 183.461,128.025 C 184.761,127.652 185.998,127.254 187.212,126.645 C 187.854,126.322 188.497,126.013 189.111,125.643 C 189.204,125.587 189.845,125.098 189.973,125.124 C 190.2,125.171 190.563,125.88 190.368,126.036 C 185.935,129.602 179.71,129.928 174.333,130.524 C 168.498,131.171 162.403,130.763 156.578,130.147 C 150.569,129.51 144.574,128.879 138.59,128.044 C 132.9,127.251 127.065,125.924 121.328,125.924 C 121.41,125.593 121.428,125.151 121.595,124.856"
+ id="path21" />
+
+
+ <path
+ d="M 121.595,124.856 C 121.506,125.212 121.417,125.568 121.327,125.924 C 121.417,125.568 121.505,125.213 121.595,124.856"
+ id="path23" />
+
+
+ <path
+ d="M 189.973,125.124 C 194.416,121.555 198.497,118.213 201.304,113.134 C 204.253,107.796 206.098,102.195 206.652,96.11 C 206.902,93.362 207.268,90.579 207.268,87.82 C 207.268,86.104 207.268,84.387 207.268,82.671 C 207.268,82.649 208.334,82.353 208.334,82.834 C 208.334,83.83 208.334,84.826 208.334,85.822 C 208.334,91.825 207.605,97.733 206.536,103.631 C 206.137,105.833 204.834,108.117 204.004,110.195 C 202.988,112.744 201.825,114.853 200.148,117.02 C 198.763,118.809 197.333,120.136 195.761,121.714 C 194.955,122.524 190.648,127.247 189.973,125.124"
+ id="path25" />
+
+
+ <path
+ d="M 190.506,125.925 C 190.328,125.658 190.151,125.391 189.973,125.124 C 190.151,125.391 190.329,125.658 190.506,125.925"
+ id="path27" />
+
+
+ <path
+ d="M 207.268,82.614 C 207.268,79.476 206.626,76.362 206.164,73.264 C 205.905,71.527 205.584,69.788 205.392,68.043 C 205.26,66.848 204.425,63.899 205.928,63.899 C 206.11,63.899 207.149,72.455 207.268,73.256 C 207.531,75.016 207.793,76.776 208.057,78.535 C 208.226,79.67 209.132,82.731 207.268,82.614"
+ id="path29" />
+
+
+ <path
+ d="M 208.334,82.614 C 208.205,82.227 207.73,82.37 207.268,82.614 C 207.623,82.614 207.981,82.632 208.334,82.614"
+ id="path31" />
+
+
+ <path
+ d="M 205.141,63.899 C 205.495,63.899 205.849,63.899 206.204,63.899 C 205.849,63.899 205.496,63.899 205.141,63.899"
+ id="path33" />
+
+
+ <path
+ d="M 87.004,89.03 C 82.978,93.076 79.145,97.621 73.06,98.13 C 70.373,98.355 66.677,99.065 64.093,98.2 C 61.284,97.26 58.554,96.212 55.875,94.912 C 53.177,93.603 50.629,92.109 47.834,90.985 C 44.66,89.708 43.276,90.865 42.108,93.799 C 39.969,99.173 38.498,104.747 36.451,110.151 C 34.383,115.61 31.259,120.33 26.872,124.187 C 22.511,128.023 16.774,129.843 12.238,133.411 C 9.998,135.173 8.779,137.807 8.779,140.6 C 8.779,142.295 8.932,143.162 10,144.5 C 10.391,144.989 10.656,145.673 10.909,146.244 C 10.967,146.375 11.466,148.137 11.441,148.115 C 12.114,148.695 14.16,148.55 15.066,149.003 C 16.375,149.657 17.504,150.009 18.891,150.254 C 21.403,150.697 24.397,150.108 26.506,148.524 C 29.921,145.957 32.609,142.378 32.726,137.958 C 32.786,135.702 32.612,134.631 30.997,133.011 C 29.677,131.686 27.435,130.651 25.807,129.669 C 36.62,125.325 37.779,111.491 45.372,103.861 C 47.197,102.027 49.699,100.795 52.356,100.795 C 53.733,100.795 55.058,100.732 56.405,101.062 C 57.837,101.413 59.109,102.248 60.53,102.532 C 66.062,103.641 71.999,102.552 77.218,100.678 C 83.797,98.317 89.897,94.733 96.049,91.437 C 93.035,90.634 90.02,89.832 87.004,89.03"
+ id="path35"
+ style="fill-rule:evenodd" />
+
+
+ <path
+ d="M 87.271,89.565 C 84.292,92.401 81.418,95.712 77.693,97.586 C 76.124,98.375 73.987,98.581 72.244,98.74 C 71.165,98.839 70.124,98.923 69.043,98.923 C 67.839,98.923 66.251,99.511 66.251,98.131 C 66.251,97.775 71.426,97.733 72.342,97.656 C 74.195,97.501 76.21,97.102 77.831,96.171 C 79.505,95.209 80.888,94.081 82.284,92.752 C 83.291,91.792 86.157,87.698 87.271,89.565"
+ id="path37" />
+
+
+ <path
+ d="M 66.251,98.923 C 61.95,98.923 57.359,96.394 53.645,94.384 C 51.61,93.283 44.827,88.734 43.371,92.238 C 40.725,91.655 44.81,89.236 46.505,89.916 C 48.693,90.793 50.9,91.54 52.984,92.668 C 55.3,93.921 57.689,94.886 60.033,96.065 C 61.212,96.657 62.371,97.087 63.621,97.506 C 64.687,97.864 66.719,97.378 66.251,98.923"
+ id="path39" />
+
+
+ <path
+ d="M 66.251,98.923 C 66.251,98.567 66.251,98.21 66.251,97.853 C 66.251,98.209 66.251,98.566 66.251,98.923"
+ id="path41" />
+
+
+ <path
+ d="M 43.37,92.238 C 42.148,95.304 40.956,98.348 39.803,101.439 C 38.692,104.417 38.175,107.624 36.925,110.557 C 35.57,113.735 34.017,116.682 32.193,119.619 C 31.421,120.861 30.091,121.889 29.059,122.928 C 28.184,123.809 26.461,126.311 25.543,124.589 C 30.168,120.522 33.978,115.743 35.947,109.805 C 37.969,103.705 39.931,97.67 42.305,91.704 C 42.624,91.864 43.11,91.998 43.37,92.238"
+ id="path43" />
+
+
+ <path
+ d="M 43.37,92.238 C 43.015,92.06 42.66,91.882 42.305,91.703 C 42.66,91.882 43.015,92.06 43.37,92.238"
+ id="path45" />
+
+
+ <path
+ d="M 26.34,125.39 C 22.948,128.119 18.715,129.576 15.166,132.076 C 13.4,133.32 11.797,134.632 10.51,136.354 C 9.835,137.258 9.57,138.259 9.353,139.353 C 9.098,140.639 9.8,141.491 7.982,141.166 C 8.322,139.112 8.402,136.732 9.954,135.174 C 11.4,133.722 12.7,132.279 14.459,131.219 C 16.519,129.977 18.604,128.805 20.713,127.649 C 21.845,127.029 22.968,126.41 24.073,125.744 C 24.971,125.202 25.581,123.959 26.34,125.39"
+ id="path47" />
+
+
+ <path
+ d="M 26.34,125.39 C 26.074,125.123 25.808,124.856 25.542,124.589 C 25.809,124.855 26.074,125.123 26.34,125.39"
+ id="path49" />
+
+
+ <path
+ d="M 9.312,141.165 C 9.128,142.575 9.912,143.672 10.654,144.79 C 10.912,145.179 12.833,148.116 11.697,148.116 C 10.282,148.116 8.411,142.761 7.982,141.165 C 8.397,141.165 8.908,141.076 9.312,141.165"
+ id="path51" />
+
+
+ <path
+ d="M 7.982,141.165 C 8.425,141.165 8.868,141.165 9.312,141.165 C 8.869,141.165 8.426,141.165 7.982,141.165"
+ id="path53" />
+
+
+ <path
+ d="M 11.708,147.583 C 13.296,147.9 14.765,148.243 16.231,148.921 C 16.723,149.149 17.609,149.722 18.103,149.722 C 19.185,149.722 20.222,149.56 20.222,150.781 C 20.222,151.675 12.401,148.846 11.442,148.65 C 11.523,148.321 11.539,147.872 11.708,147.583"
+ id="path55" />
+
+
+ <path
+ d="M 10.91,148.116 C 10.958,149.269 11.72,148.363 11.708,147.583 C 11.796,147.761 11.885,147.938 11.974,148.116 C 11.634,148.116 11.239,148.187 10.91,148.116"
+ id="path57" />
+
+
+ <path
+ d="M 20.222,149.987 C 21.994,149.633 24.045,149.651 25.543,148.518 C 27.033,147.391 28.078,146.37 29.409,145.034 C 30.563,143.876 31.309,142.142 31.622,140.571 C 31.801,139.672 32.035,138.854 32.195,137.958 C 32.245,137.679 32.015,136.812 32.195,136.62 C 32.805,135.968 33.259,136.848 33.259,137.289 C 33.259,141.295 31.432,143.966 29.134,147.048 C 28.124,148.403 26.427,149.367 24.877,149.988 C 23.933,150.367 19.538,152.3 20.222,149.987"
+ id="path59" />
+
+
+ <path
+ d="M 20.222,151.058 C 20.222,150.702 20.222,150.344 20.222,149.988 C 20.222,150.344 20.222,150.701 20.222,151.058"
+ id="path61" />
+
+
+ <path
+ d="M 32.195,136.62 C 32.509,134.673 31.012,133.86 29.733,132.894 C 28.75,132.152 27.953,131.545 26.816,131.088 C 25.616,130.605 25.312,130.049 26.34,129.133 C 27.967,130.36 29.784,131.261 31.397,132.475 C 32.252,133.119 34.721,137.374 32.195,136.62"
+ id="path63" />
+
+
+ <path
+ d="M 33.259,136.62 C 32.905,136.62 32.55,136.62 32.195,136.62 C 32.549,136.62 32.904,136.62 33.259,136.62"
+ id="path65" />
+
+
+ <path
+ d="M 25.542,129.134 C 36.828,124.598 36.531,110.148 45.231,103.2 C 47.249,101.589 49.642,100.26 52.357,100.26 C 52.73,100.26 54.457,100.405 53.479,101.329 C 53.319,101.48 51.838,101.392 51.484,101.463 C 50.276,101.706 48.412,101.878 47.502,102.791 C 46.669,103.626 45.683,104.083 44.841,104.93 C 43.85,105.927 43.202,107.286 42.378,108.445 C 40.758,110.722 39.571,113.509 38.327,116.008 C 36.719,119.238 34.983,122.097 32.85,124.958 C 31.963,126.147 30.826,127.289 29.632,128.189 C 28.578,128.984 26.056,131.258 25.542,129.134"
+ id="path67" />
+
+
+ <path
+ d="M 25.542,130.202 C 25.26,130.097 24.996,129.838 24.744,129.669 C 24.91,129.474 25.301,129.224 25.542,129.134 C 25.667,129.501 25.982,129.826 26.074,130.202 C 26.188,129.874 26.31,129.478 26.34,129.134 C 26.077,129.487 25.779,129.83 25.542,130.202"
+ id="path69" />
+
+
+ <path
+ d="M 53.48,100.26 C 55.443,100.26 57.453,100.519 59.233,101.412 C 60.237,101.915 61.218,102.136 62.318,102.357 C 63.5,102.594 64.2,102.054 63.858,103.735 C 61.997,103.36 60.088,103.179 58.369,102.315 C 57.424,101.84 56.509,101.67 55.475,101.462 C 54.482,101.263 53.031,101.778 53.48,100.26"
+ id="path71" />
+
+
+ <path
+ d="M 53.48,100.26 C 53.48,100.616 53.48,100.972 53.48,101.329 C 53.48,100.972 53.48,100.616 53.48,100.26"
+ id="path73" />
+
+
+ <path
+ d="M 63.858,102.398 C 69.773,102.398 74.894,101.075 80.354,98.922 C 85.716,96.808 90.707,93.622 95.785,90.901 C 97.145,92.425 94.353,93.023 93.226,93.627 C 91.896,94.34 90.566,95.053 89.235,95.766 C 86.578,97.19 83.856,98.5 81.161,99.853 C 75.711,102.59 69.767,103.073 63.857,103.735 C 63.858,103.303 63.794,102.825 63.858,102.398"
+ id="path75" />
+
+
+ <path
+ d="M 63.858,103.735 C 63.858,103.289 63.858,102.844 63.858,102.398 C 63.858,102.844 63.858,103.29 63.858,103.735"
+ id="path77" />
+
+
+ <path
+ d="M 96.051,91.972 C 97.084,90.291 93.803,90.253 92.727,89.975 C 90.819,89.482 88.912,88.989 87.005,88.496 C 85.972,90.176 89.254,90.215 90.329,90.493 C 92.236,90.986 94.144,91.479 96.051,91.972"
+ id="path79" />
+
+
+ <path
+ d="M 96.316,91.972 C 96.76,91.794 97.204,91.615 97.648,91.437 C 97.204,91.259 96.76,91.081 96.316,90.902 C 96.265,91.251 96.04,91.622 96.05,91.972 C 95.946,91.628 95.836,91.258 95.784,90.902 C 95.961,91.257 96.155,91.609 96.316,91.972"
+ id="path81" />
+
+
+ <path
+ d="M 87.004,88.496 C 86.22,88.674 86.651,89.216 87.27,89.565 C 87.093,89.565 86.916,89.565 86.738,89.565 C 86.823,89.227 86.847,88.804 87.004,88.496"
+ id="path83" />
+
+
+ <path
+ d="M 141.549,115.499 C 139.274,121.215 136.224,125.426 130.773,128.466 C 125.574,131.365 120.075,133.568 114.809,136.352 C 109.878,138.959 104.531,141.799 101.639,146.781 C 98.756,151.748 98.142,157.679 97.036,163.218 C 96.502,165.896 96.254,169.683 94.908,172.051 C 93.526,174.482 92.092,176.694 90.119,178.677 C 86.119,182.696 81.316,186.204 79.889,191.955 C 79.284,194.393 79.264,197.498 79.958,199.934 C 80.109,200.465 80.597,203.46 80.789,203.46 C 82.744,203.46 84.699,203.46 86.654,203.46 C 87.96,203.46 89.374,203.684 90.597,203.193 C 92.001,202.63 93.298,201.846 94.618,201.111 C 97.043,199.758 98.848,198.336 100.308,195.975 C 101.841,193.497 102.437,190.947 102.437,188.013 C 102.437,185.092 99.435,184.059 98.313,181.803 C 97.754,180.679 96.851,179.566 96.851,178.269 C 96.851,176.753 96.851,175.239 96.851,173.724 C 96.851,170.723 97.689,167.738 98.407,164.85 C 99.746,159.47 102.685,154.168 106.96,150.524 C 108.928,148.846 111.355,147.146 113.877,146.512 C 116.7,145.803 119.455,146.313 122.284,145.957 C 129.991,144.987 137.135,140.41 141.971,134.352 C 144.401,131.309 145.51,128.274 146.051,124.459 C 146.633,120.356 144.294,118.254 141.549,115.499"
+ id="path85"
+ style="fill-rule:evenodd" />
+
+
+ <path
+ d="M 142.083,115.765 C 139.311,122.717 134.59,127.932 127.653,131.033 C 120.846,134.076 113.396,136.823 107.493,141.433 C 107.209,141.137 106.898,140.72 106.695,140.363 C 109.963,138.394 113.231,136.513 116.604,134.729 C 119.834,133.02 123.398,131.838 126.684,130.187 C 133.434,126.795 138.2,122.316 141.017,115.232 C 141.335,115.391 141.822,115.524 142.083,115.765"
+ id="path87" />
+
+
+ <path
+ d="M 107.492,141.433 C 103.279,144.965 100.982,148.555 99.47,153.871 C 97.974,159.129 97.302,164.701 96.051,170.041 C 94.092,170.127 95.606,167.285 95.885,166.163 C 96.263,164.639 96.503,163.079 96.792,161.535 C 97.294,158.851 97.703,156.084 98.447,153.465 C 99.216,150.761 100.073,148.073 101.64,145.712 C 102.424,144.528 106.416,139.401 107.492,141.433"
+ id="path89" />
+
+
+ <path
+ d="M 106.694,140.362 C 106.779,140.783 107.089,141.176 107.492,141.432 C 107.227,141.076 106.968,140.713 106.694,140.362"
+ id="path91" />
+
+
+ <path
+ d="M 96.051,170.04 C 94.782,175.14 90.581,179.427 86.739,182.874 C 84.75,184.659 82.886,186.34 81.669,188.786 C 81.08,189.969 80.607,191.224 80.285,192.509 C 79.921,193.959 80.763,195.488 78.757,195.173 C 79.06,192.735 79.512,189.79 80.886,187.687 C 82.335,185.47 84.338,183.682 86.173,181.838 C 88.031,179.972 89.756,177.967 91.607,176.109 C 92.666,175.047 93.187,173.874 93.923,172.579 C 94.501,171.562 94.573,169.146 96.051,170.04"
+ id="path93" />
+
+
+ <path
+ d="M 96.051,170.04 C 95.697,169.951 95.342,169.863 94.987,169.774 C 95.341,169.863 95.696,169.951 96.051,170.04"
+ id="path95" />
+
+
+ <path
+ d="M 80.086,195.173 C 80.086,196.543 80.014,197.986 80.394,199.321 C 80.71,200.435 82.071,203.576 80.086,203.46 C 79.895,201.921 79.435,200.481 79.219,198.964 C 79.103,198.146 78.991,197.328 78.889,196.509 C 78.73,195.226 78.831,195.424 80.086,195.173"
+ id="path97" />
+
+
+ <path
+ d="M 78.756,195.173 C 78.928,195.638 79.529,195.284 80.086,195.173 C 79.644,195.173 79.199,195.158 78.756,195.173"
+ id="path99" />
+
+
+ <path
+ d="M 80.62,202.927 C 82.45,202.927 84.28,202.927 86.11,202.927 C 86.353,202.927 91.423,202.579 89.932,203.993 C 89.309,204.584 85.304,203.993 84.442,203.993 C 83.363,203.993 80.029,204.778 80.62,202.927"
+ id="path101" />
+
+
+ <path
+ d="M 80.086,203.46 C 80.41,204.454 80.883,203.814 80.62,202.927 C 80.797,203.016 80.974,203.104 81.152,203.193 C 80.804,203.279 80.442,203.423 80.086,203.46"
+ id="path103" />
+
+
+ <path
+ d="M 89.666,202.927 C 96.365,200.221 101.905,196.014 101.905,188.222 C 105.11,188.042 100.527,196.658 99.642,197.845 C 97.32,200.96 93.444,202.584 89.932,203.993 C 89.85,203.663 89.657,203.264 89.666,202.927"
+ id="path105" />
+
+
+ <path
+ d="M 89.932,203.993 C 89.772,203.689 89.75,203.263 89.666,202.927 C 89.755,202.927 89.843,202.927 89.932,202.927 C 89.932,203.282 89.937,203.638 89.932,203.993"
+ id="path107" />
+
+
+ <path
+ d="M 101.905,188.487 C 102.16,186.341 99.932,184.099 98.554,182.715 C 97.757,181.914 94.665,177.639 97.382,177.792 C 97.382,180.272 98.958,181.248 100.416,183.077 C 101.04,183.857 104.777,188.657 101.905,188.487"
+ id="path109" />
+
+
+ <path
+ d="M 102.969,188.487 C 102.84,188.102 102.366,188.244 101.905,188.487 C 101.905,188.398 101.905,188.31 101.905,188.221 C 102.24,188.306 102.666,188.327 102.969,188.487"
+ id="path111" />
+
+
+ <path
+ d="M 96.316,178.062 C 96.316,171.946 97.05,166.298 99.199,160.534 C 101.324,154.835 105.694,151.161 110.153,147.314 C 110.434,147.595 110.764,148.034 110.951,148.384 C 106.176,151.816 102.584,155.599 100.248,161.087 C 99.071,163.853 98.152,167.05 97.781,170.041 C 97.587,171.605 97.382,173.13 97.382,174.707 C 97.382,175.849 98.075,178.601 96.316,178.062"
+ id="path113" />
+
+
+ <path
+ d="M 96.316,178.062 C 96.671,178.067 97.026,178.062 97.382,178.062 C 97.382,177.972 97.382,177.882 97.382,177.792 C 97.047,177.877 96.62,177.9 96.316,178.062"
+ id="path115" />
+
+
+ <path
+ d="M 110.419,147.313 C 113.404,145.818 116.273,145.442 119.598,145.442 C 122.519,145.442 126.19,145.388 128.777,143.838 C 128.979,144.089 129.226,144.598 129.309,144.908 C 126.18,146.163 123.233,146.512 119.864,146.512 C 116.486,146.512 113.975,147.004 110.951,148.383 C 110.784,148.047 110.516,147.676 110.419,147.313"
+ id="path117" />
+
+
+ <path
+ d="M 110.153,147.313 C 110.555,147.441 110.843,147.879 110.951,148.383 C 110.686,148.027 110.409,147.678 110.153,147.313"
+ id="path119" />
+
+
+ <path
+ d="M 128.777,143.839 C 132.993,141.366 137.764,138.763 140.86,134.876 C 142.572,132.728 143.521,130.78 144.726,128.362 C 145.261,127.289 145.302,125.988 145.469,124.806 C 145.617,123.764 145.334,121.963 146.87,122.45 C 146.237,127.547 145.064,131.885 141.548,135.819 C 138.11,139.666 133.546,142.07 129.308,144.909 C 129.148,144.585 128.848,144.191 128.777,143.839"
+ id="path121" />
+
+
+ <path
+ d="M 129.309,144.909 C 129.132,144.553 128.955,144.195 128.777,143.839 C 128.955,144.195 129.132,144.553 129.309,144.909"
+ id="path123" />
+
+
+ <path
+ d="M 145.805,122.45 C 145.496,121.017 144.942,119.709 143.893,118.655 C 143.049,117.808 140.324,115.899 142.082,114.964 C 144.162,117.472 146.217,119.155 146.871,122.45 C 146.541,122.45 146.122,122.537 145.805,122.45"
+ id="path125" />
+
+
+ <path
+ d="M 146.872,122.45 C 146.517,122.45 146.161,122.45 145.806,122.45 C 146.161,122.45 146.516,122.45 146.872,122.45"
+ id="path127" />
+
+
+ <path
+ d="M 142.083,114.964 C 141.96,114.762 141.718,114.598 141.55,114.429 C 141.361,114.591 141.095,114.994 141.017,115.232 C 141.372,115.375 141.713,115.674 142.083,115.765 C 141.837,115.807 141.531,115.79 141.282,115.765 C 141.538,115.509 141.788,115.172 142.083,114.964"
+ id="path129" />
+
+
+ <path
+ d="M 204.608,78.603 C 210.383,77.774 215.852,75.843 220.505,72.208 C 225.013,68.687 229.301,64.458 234.451,61.871 C 239.43,59.371 245.06,56.793 250.637,58.551 C 251.904,58.95 253.032,58.523 253.032,59.991 C 253.032,62.104 253.032,64.218 253.032,66.331 C 253.032,68.956 252.618,71.574 251.951,74.123 C 248.972,85.499 244.805,96.447 241.593,107.745 C 244.396,103.05 247.471,97.708 252.5,95.18 C 254.539,94.155 257.99,93.136 260.216,94.111 C 260.767,94.352 261.324,94.945 261.814,95.314 C 262.063,95.502 263.358,95.916 263.41,95.983 C 263.871,96.585 264.474,99.35 264.474,100.127 C 264.474,106.287 261.911,110.578 257.023,114.162 C 253.266,116.917 245.933,119.929 241.535,116.975 C 238.642,115.033 237.704,110.166 237.103,106.95 C 236.389,103.128 236.356,98.843 237.296,95.072 C 239.266,87.169 241.118,78.947 242.124,70.852 C 238.884,72.478 235.991,74.549 233.007,76.602 C 230.644,78.227 227.532,80.308 224.696,80.878 C 221.593,81.502 218.014,81.012 214.841,81.012 C 211.253,81.01 207.802,80.208 204.608,78.603"
+ id="path131"
+ style="fill-rule:evenodd" />
+
+
+ <path
+ d="M 204.608,78.068 C 210.868,77.172 215.817,74.673 220.947,71.068 C 225.544,67.838 229.635,63.625 234.674,61.092 C 237.305,59.769 239.679,58.834 242.524,58.017 C 243.854,57.635 245.101,57.482 246.482,57.482 C 246.88,57.482 248.267,57.248 248.509,57.482 C 249.692,58.627 247.155,58.552 246.841,58.552 C 241.219,58.552 236.04,61.538 231.482,64.434 C 226.861,67.37 222.721,71.184 218.224,74.348 C 216.188,75.781 213.574,77.167 211.159,77.829 C 209.906,78.173 208.652,78.513 207.403,78.871 C 205.789,79.333 204.974,79.913 204.608,78.068"
+ id="path133" />
+
+
+ <path
+ d="M 248.508,57.481 C 249.779,57.349 253.443,58.12 253.031,59.621 C 251.563,59.325 249.708,58.332 248.242,58.551 C 248.327,58.213 248.35,57.789 248.508,57.481"
+ id="path135" />
+
+
+ <path
+ d="M 248.508,57.481 C 248.348,57.786 248.326,58.214 248.242,58.551 C 248.331,58.551 248.419,58.551 248.508,58.551 C 248.508,58.195 248.513,57.838 248.508,57.481"
+ id="path137" />
+
+
+ <path
+ d="M 252.5,59.086 C 254.325,58.507 253.564,61.621 253.564,62.693 C 253.564,63.47 254.134,67.951 253.564,68.443 C 252.023,69.77 252.5,65.21 252.5,64.836 C 252.5,62.919 252.5,61.003 252.5,59.086"
+ id="path139" />
+
+
+ <path
+ d="M 253.032,58.551 C 254.14,58.644 253.351,59.338 252.501,59.086 C 252.639,59.273 252.847,59.482 253.032,59.621 C 253.032,59.275 253.091,58.891 253.032,58.551"
+ id="path141" />
+
+
+ <path
+ d="M 253.565,68.443 C 252.282,75.214 250.616,81.927 248.508,88.496 C 247.466,91.743 246.202,94.918 245.128,98.154 C 244.598,99.751 244.034,101.341 243.553,102.954 C 243.19,104.17 242.827,108.504 241.061,107.477 C 244.976,94.359 249.943,81.666 252.5,68.176 C 252.825,68.258 253.283,68.271 253.565,68.443"
+ id="path143" />
+
+
+ <path
+ d="M 253.565,68.443 C 253.262,68.283 252.836,68.26 252.501,68.176 C 252.501,68.265 252.501,68.354 252.501,68.443 C 252.855,68.443 253.21,68.448 253.565,68.443"
+ id="path145" />
+
+
+ <path
+ d="M 241.061,107.211 C 245.045,100.534 250.234,93.308 258.721,93.308 C 258.973,93.308 259.041,94.24 258.887,94.377 C 258.662,94.577 257.613,94.344 257.289,94.377 C 256.413,94.466 255.235,94.668 254.421,94.995 C 252.435,95.793 250.906,96.983 249.206,98.262 C 246.127,100.577 244.026,104.896 241.857,108.012 C 241.618,107.771 241.227,107.506 241.061,107.211"
+ id="path147" />
+
+
+ <path
+ d="M 241.061,107.478 C 241.318,107.667 241.593,107.835 241.858,108.013 C 241.575,107.767 241.336,107.467 241.061,107.211 C 241.418,107.371 241.784,107.551 242.124,107.745 C 241.77,107.656 241.41,107.584 241.061,107.478"
+ id="path149" />
+
+
+ <path
+ d="M 258.887,93.308 C 260.87,93.07 261.725,95.438 263.408,95.447 C 263.448,98.021 259.975,94.152 258.619,94.377 C 258.703,94.045 258.721,93.604 258.887,93.308"
+ id="path151" />
+
+
+ <path
+ d="M 258.887,93.308 C 258.726,93.613 258.703,94.041 258.619,94.377 C 258.708,94.377 258.798,94.377 258.887,94.377 C 258.887,94.021 258.892,93.665 258.887,93.308"
+ id="path153" />
+
+
+ <path
+ d="M 263.942,95.982 C 264.248,97.212 266.091,100.83 263.942,100.795 C 264.169,99.553 261.676,95.879 263.942,95.982"
+ id="path155" />
+
+
+ <path
+ d="M 263.409,95.447 C 264.344,95.896 263.744,96.273 262.878,96.249 C 262.967,96.338 263.055,96.427 263.144,96.516 C 263.228,96.176 263.398,95.796 263.409,95.447"
+ id="path157" />
+
+
+ <path
+ d="M 265.004,100.794 C 265.004,106.113 262.557,110.676 258.419,114.002 C 256.385,115.638 254.086,116.915 251.568,117.636 C 250.346,117.986 249.099,118.125 247.842,118.305 C 246.738,118.462 244.676,119.376 244.782,117.637 C 249.529,117.04 254.395,116.156 258.087,112.824 C 261.682,109.58 263.941,105.407 263.941,100.525 C 264.272,100.609 264.711,100.628 265.004,100.794"
+ id="path159" />
+
+
+ <path
+ d="M 265.004,100.526 C 264.877,100.916 264.402,100.771 263.941,100.526 C 263.941,100.615 263.941,100.705 263.941,100.794 C 264.276,100.71 264.702,100.687 265.004,100.526"
+ id="path161" />
+
+
+ <path
+ d="M 244.784,118.708 C 241.685,118.025 239.875,116.739 238.606,113.757 C 237.99,112.31 234.842,104.968 237.335,105.072 C 237.835,107.917 238.263,110.967 239.464,113.627 C 239.902,114.597 240.948,115.98 241.859,116.567 C 242.913,117.249 245.671,117.082 244.784,118.708"
+ id="path163" />
+
+
+ <path
+ d="M 245.049,118.708 C 244.665,118.577 244.806,118.101 245.049,117.638 C 244.96,117.638 244.872,117.638 244.783,117.638 C 244.868,117.975 244.889,118.403 245.049,118.708"
+ id="path165" />
+
+
+ <path
+ d="M 236.27,105.339 C 236.27,102.559 235.96,99.832 236.27,97.051 C 236.599,94.094 237.437,91.116 238.133,88.228 C 239.522,82.469 240.862,76.734 241.592,70.85 C 243.376,70.744 242.334,73.427 242.193,74.573 C 241.993,76.185 241.658,77.784 241.378,79.384 C 240.848,82.406 239.914,85.43 239.214,88.42 C 238.531,91.337 237.653,94.335 237.335,97.318 C 237.214,98.455 236.934,100.375 237.089,101.467 C 237.243,102.555 238.174,105.918 236.27,105.339"
+ id="path167" />
+
+
+ <path
+ d="M 236.27,105.339 C 236.624,105.344 236.98,105.339 237.334,105.339 C 237.334,105.25 237.334,105.161 237.334,105.072 C 237,105.156 236.573,105.179 236.27,105.339"
+ id="path169" />
+
+
+ <path
+ d="M 242.389,71.385 C 239.029,73.072 236.193,75.389 232.988,77.322 C 231.688,78.105 222.912,83.593 222.966,80.475 C 226.526,80.783 229.915,77.866 232.737,76.075 C 234.376,75.035 236.142,74.088 237.692,72.92 C 238.514,72.3 241.825,69.385 242.389,71.385"
+ id="path171" />
+
+
+ <path
+ d="M 242.657,71.117 C 242.726,70.784 242.657,70.39 242.657,70.048 C 241.835,70.316 241.734,70.821 242.389,71.385 C 242.118,71.23 241.835,71.046 241.592,70.85 C 241.946,70.938 242.311,71.004 242.657,71.117"
+ id="path173" />
+
+
+ <path
+ d="M 223.233,81.543 C 216.921,81.897 210.118,82.043 204.342,79.138 C 204.74,77.752 207.604,79.356 208.708,79.633 C 210.331,80.041 211.979,80.379 213.654,80.474 C 215.262,80.565 216.913,80.474 218.524,80.474 C 219.743,80.475 223.797,79.624 223.233,81.543"
+ id="path175" />
+
+
+ <path
+ d="M 223.233,81.543 C 223.238,81.187 223.233,80.831 223.233,80.474 C 223.144,80.474 223.054,80.474 222.965,80.474 C 223.049,80.811 223.072,81.239 223.233,81.543"
+ id="path177" />
+
+
+ <path
+ d="M 204.342,79.138 C 203.81,78.87 203.277,78.603 202.744,78.336 C 204.37,78.102 204.542,77.74 204.873,79.405 C 204.917,79.062 204.889,78.682 204.873,78.336 C 204.699,78.599 204.483,78.856 204.342,79.138"
+ id="path179" />
+
+
+ <path
+ d="M 193.7,49.193 C 198.442,45.38 202.244,40.827 205.96,36.027 C 209.058,32.027 211.917,25.997 216.582,23.66 C 217.791,23.054 218.259,24.215 219.042,24.631 C 220.526,25.421 222.026,26.188 223.499,27.002 C 226.097,28.437 228.421,30.063 230.842,31.765 C 235.875,35.305 240.074,39.644 244.397,43.992 C 244.615,44.211 244.833,44.43 245.05,44.649 C 249.014,40.665 252.788,36.212 258.753,35.545 C 260.47,35.353 260.99,35.036 262.079,36.093 C 263.198,37.179 263.409,38.544 263.409,40.162 C 263.409,41.739 263.248,42.141 262.213,43.178 C 261.421,43.972 261.095,46.092 260.565,47.156 C 257.999,52.306 250.951,53.121 246.076,51.285 C 240.538,49.199 236.347,44.332 231.954,40.549 C 228.2,37.315 224.937,35.136 219.933,34.509 C 214.763,33.862 211.73,38.46 209.256,42.192 C 206.943,45.682 204.982,50.548 201.417,52.937 C 200.47,53.573 196.627,56.288 196.627,53.462 C 196.625,50.954 196.027,49.978 193.7,49.193"
+ id="path181"
+ style="fill-rule:evenodd" />
+
+
+ <path
+ d="M 193.432,48.926 C 198.423,44.472 202.913,39.437 206.764,33.958 C 208.9,30.919 211.187,28.108 213.556,25.25 C 214.413,24.215 215.733,23.052 217.114,22.992 C 218.222,22.944 220.416,24.197 218.71,25.131 C 217.866,24.282 217.67,23.969 216.583,24.329 C 215.208,24.784 214.209,26.178 213.221,27.171 C 210.845,29.558 208.97,32.759 207.044,35.501 C 203.356,40.75 198.96,45.713 193.966,49.729 C 193.8,49.48 193.524,49.208 193.432,48.926"
+ id="path183" />
+
+
+ <path
+ d="M 219.241,24.063 C 223.936,26.838 229.565,29.24 233.646,32.888 C 235.823,34.834 237.848,36.924 239.996,38.901 C 240.988,39.814 241.953,40.734 242.904,41.689 C 243.763,42.553 246.219,43.926 244.518,44.917 C 240.595,40.977 236.605,36.956 232.267,33.465 C 229.985,31.63 227.635,30.067 225.095,28.608 C 223.889,27.916 222.68,27.245 221.452,26.591 C 220.342,26 217.928,25.538 219.241,24.063"
+ id="path185" />
+
+
+ <path
+ d="M 218.709,25.131 C 218.813,24.767 219.071,24.402 219.24,24.062 C 219.56,24.471 219.232,24.837 218.709,25.131"
+ id="path187" />
+
+
+ <path
+ d="M 244.518,44.114 C 246.823,41.964 249.348,38.932 252.105,37.351 C 253.392,36.613 261.454,33.06 261.28,35.826 C 258.081,36.147 254.642,36.706 252.087,38.847 C 250.912,39.831 249.722,40.805 248.601,41.851 C 247.666,42.723 245.542,45.93 244.518,44.114"
+ id="path189" />
+
+
+ <path
+ d="M 244.518,44.916 C 244.641,45.118 244.881,45.282 245.049,45.451 C 245.442,44.892 245.098,44.452 244.518,44.114 C 244.755,44.074 245.08,44.074 245.317,44.114 C 245.061,44.371 244.813,44.707 244.518,44.916"
+ id="path191" />
+
+
+ <path
+ d="M 261.28,34.756 C 262.941,35.551 263.942,37.39 263.942,39.331 C 263.942,40.383 264.112,41.527 263.674,42.51 C 263.224,43.52 262.257,44.274 261.545,43.044 C 263.87,42.261 263.226,36.438 261.014,35.826 C 261.098,35.489 261.12,35.061 261.28,34.756"
+ id="path193" />
+
+
+ <path
+ d="M 261.014,34.756 C 261.398,34.886 261.257,35.363 261.014,35.826 C 261.103,35.826 261.191,35.826 261.28,35.826 C 261.196,35.489 261.174,35.061 261.014,34.756"
+ id="path195" />
+
+
+ <path
+ d="M 262.612,43.579 C 261.857,45.851 260.883,48.927 258.769,50.342 C 257.659,51.086 251.007,54.426 251.17,51.6 C 253.472,51.683 257.128,50.91 258.482,48.868 C 259.153,47.855 259.92,47.112 260.481,45.986 C 260.99,44.966 261.166,42.703 262.612,43.579"
+ id="path197" />
+
+
+ <path
+ d="M 261.545,43.044 C 261.655,43.435 262.107,43.593 262.611,43.579 C 262.522,43.668 262.434,43.758 262.345,43.847 C 262.106,43.605 261.71,43.339 261.545,43.044"
+ id="path199" />
+
+
+ <path
+ d="M 251.436,52.669 C 244.534,52.669 240.011,48.586 235.206,44.114 C 230.517,39.75 226.077,35.757 219.507,35.024 C 219.326,32.1 226.961,36.133 228.151,36.816 C 230.982,38.442 233.433,40.914 235.797,43.12 C 238.153,45.319 240.465,47.506 243.085,49.388 C 244.48,50.389 245.808,50.606 247.386,51.135 C 248.63,51.552 251.934,51.043 251.436,52.669"
+ id="path201" />
+
+
+ <path
+ d="M 251.436,52.669 C 251.441,52.313 251.436,51.956 251.436,51.6 C 251.347,51.6 251.259,51.6 251.17,51.6 C 251.254,51.937 251.276,52.364 251.436,52.669"
+ id="path203" />
+
+
+ <path
+ d="M 219.774,35.024 C 217.103,35.407 215.67,35.809 213.516,37.541 C 211.531,39.138 210.333,41.516 209.008,43.679 C 208.078,45.197 200.3,57.463 198.487,54.006 C 203.437,51.17 205.484,46.811 208.52,42.231 C 210.07,39.893 211.511,37.709 213.718,35.936 C 214.729,35.123 219.923,32.512 219.774,35.024"
+ id="path205" />
+
+
+ <path
+ d="M 219.774,33.954 C 219.386,34.083 219.53,34.56 219.774,35.024 C 219.685,35.024 219.595,35.024 219.506,35.024 C 219.59,34.688 219.613,34.259 219.774,33.954"
+ id="path207" />
+
+
+ <path
+ d="M 199.02,55.076 C 198.188,54.938 197.687,55.55 196.893,55.076 C 196.039,54.566 196.228,53.446 196.094,52.669 C 195.969,51.94 195.882,50.786 195.293,50.263 C 194.541,49.596 193.254,50.296 193.699,48.659 C 197.188,49.415 196.428,51.494 197.424,54.273 C 198.194,53.889 199.098,53.784 199.02,55.076"
+ id="path209" />
+
+
+ <path
+ d="M 199.286,54.809 C 199.197,54.898 199.109,54.987 199.02,55.076 C 199.035,54.571 198.876,54.118 198.487,54.006 C 198.745,54.265 198.992,54.593 199.286,54.809"
+ id="path211" />
+
+
+ <path
+ d="M 193.7,49.729 C 193.257,49.64 192.813,49.551 192.37,49.462 C 193.033,48.899 193.68,48.774 193.966,49.729 C 193.897,49.374 193.812,49.005 193.7,48.66 C 193.7,49.015 193.682,49.374 193.7,49.729"
+ id="path213" />
+
+
+ <path
+ d="M 141.549,46.788 C 136.348,45.584 134.527,37.056 133.3,32.751 C 131.8,27.487 131.054,21.745 131.507,16.279 C 131.714,13.79 131.982,10.218 134.1,8.555 C 136.298,6.829 138.021,8.395 140.345,8.176 C 147.978,7.457 155.611,6.738 163.243,6.019 C 165.675,5.79 167.191,4.178 168.873,2.487 C 170.802,0.548 173.969,0.342 176.374,1.149 C 181.185,2.763 183.981,9.22 180.001,13.23 C 175.9,17.36 169.493,15.511 164.829,13.636 C 162.518,12.707 160.669,11.933 158.182,12.257 C 154.089,12.791 149.995,13.325 145.903,13.86 C 144.036,14.104 142.169,14.347 140.3,14.591 C 138.903,14.773 139.378,15.588 139.312,16.989 C 139.149,20.438 138.944,23.881 138.681,27.323 C 138.162,34.117 139.529,40.355 141.549,46.788"
+ id="path215"
+ style="fill-rule:evenodd" />
+
+
+ <path
+ d="M 141.282,47.323 C 137.794,46.365 135.207,40.774 134.156,37.597 C 132.793,33.48 131.84,29.359 131.27,25.062 C 130.737,21.042 130.602,16.775 131.397,12.775 C 131.796,10.766 132.557,9.574 133.96,8.163 C 135.039,7.077 140.272,6.504 138.89,8.823 C 134.851,6.03 132.478,11.506 132.196,14.629 C 131.817,18.824 132.019,22.792 132.61,26.948 C 133.168,30.879 134.4,34.579 135.642,38.333 C 136.298,40.313 137.415,42.025 138.557,43.744 C 138.94,44.322 139.684,45.009 140.221,45.451 C 140.926,46.032 142.422,46.344 141.282,47.323"
+ id="path217" />
+
+
+ <path
+ d="M 139.155,7.753 C 139.055,8.056 139.155,8.5 139.155,8.823 C 143.689,8.396 148.224,7.969 152.759,7.541 C 155.707,7.264 158.655,6.986 161.602,6.708 C 162.633,6.611 165.293,7.048 164.699,5.346 C 156.183,6.148 147.669,6.951 139.155,7.753"
+ id="path219" />
+
+
+ <path
+ d="M 138.889,8.823 C 139.051,8.601 139.323,8.374 139.155,7.753 C 139.067,8.108 138.959,8.463 138.889,8.823"
+ id="path221" />
+
+
+ <path
+ d="M 164.432,5.346 C 165.906,4.235 167.38,3.124 168.854,2.013 C 170.548,0.737 171.936,0.346 174.008,0 C 174.319,1.749 173.663,1.115 172.412,1.337 C 171.293,1.536 170.609,2.187 169.693,2.802 C 168.052,3.903 166.517,5.2 164.963,6.416 C 164.802,6.092 164.503,5.699 164.432,5.346"
+ id="path223" />
+
+
+ <path
+ d="M 164.698,6.417 C 165.055,6.25 164.773,5.785 164.432,5.347 C 164.521,5.347 164.609,5.347 164.698,5.347 C 164.698,5.703 164.71,6.061 164.698,6.417"
+ id="path225" />
+
+
+ <path
+ d="M 174.008,0 C 176.156,0.359 178.546,1.019 179.974,2.813 C 180.666,3.682 184.165,8.97 181.459,8.823 C 180.763,4.618 178.29,1.337 173.742,1.337 C 173.832,0.891 173.919,0.446 174.008,0"
+ id="path227" />
+
+
+ <path
+ d="M 174.008,0 C 173.919,0.446 173.831,0.891 173.742,1.337 C 173.831,1.337 173.919,1.337 174.008,1.337 C 174.008,0.905 174.073,0.426 174.008,0"
+ id="path229" />
+
+
+ <path
+ d="M 182.524,8.823 C 182.736,10.607 181.231,13.105 179.864,14.17 C 178.863,14.949 173.604,17.661 173.743,15.24 C 175.912,14.876 177.845,14.593 179.46,12.972 C 180.106,12.324 180.65,11.255 181.062,10.428 C 181.461,9.621 180.93,7.865 182.524,8.823"
+ id="path231" />
+
+
+ <path
+ d="M 182.524,8.555 C 182.396,8.943 181.921,8.8 181.46,8.555 C 181.46,8.644 181.46,8.733 181.46,8.823 C 181.794,8.739 182.221,8.716 182.524,8.555"
+ id="path233" />
+
+
+ <path
+ d="M 174.008,16.308 C 171.649,16.071 168.866,16.129 166.726,15.055 C 164.489,13.932 162.073,13.109 159.643,12.566 C 159.543,10.788 161.676,11.796 162.724,12.191 C 164.121,12.717 165.464,13.299 166.827,13.903 C 168.143,14.486 169.453,14.7 170.867,14.903 C 172,15.064 174.544,14.601 174.008,16.308"
+ id="path235" />
+
+
+ <path
+ d="M 174.008,16.308 C 174.013,15.952 174.008,15.596 174.008,15.239 C 173.919,15.239 173.831,15.239 173.742,15.239 C 173.827,15.576 173.848,16.003 174.008,16.308"
+ id="path237" />
+
+
+ <path
+ d="M 159.909,12.565 C 160.037,10.945 158.602,11.631 157.583,11.764 C 155.22,12.072 152.857,12.381 150.495,12.689 C 146.715,13.182 142.935,13.676 139.155,14.169 C 139.027,15.789 140.462,15.103 141.481,14.97 C 143.844,14.662 146.207,14.353 148.569,14.045 C 152.349,13.552 156.128,13.059 159.909,12.565"
+ id="path239" />
+
+
+ <path
+ d="M 159.909,11.496 C 159.525,11.626 159.666,12.103 159.909,12.566 C 159.82,12.566 159.732,12.566 159.643,12.566 C 159.727,12.229 159.749,11.801 159.909,11.496"
+ id="path241" />
+
+
+ <path
+ d="M 139.954,14.704 C 139.692,20.187 139.155,25.683 139.155,31.17 C 139.155,36.621 140.531,41.593 142.083,46.787 C 140.441,47.732 140.335,44.885 139.982,43.763 C 139.546,42.376 139.148,41.003 138.889,39.568 C 138.391,36.806 137.853,34.111 137.823,31.28 C 137.792,28.37 138.31,25.368 138.491,22.458 C 138.583,20.974 138.624,19.522 138.624,18.035 C 138.624,16.274 137.842,14.536 139.954,14.704"
+ id="path243" />
+
+
+ <path
+ d="M 139.155,14.169 C 138.84,14.333 138.609,14.328 138.624,14.704 C 139.06,14.65 139.52,14.77 139.954,14.704 C 139.826,14.891 139.604,15.106 139.421,15.239 C 139.336,14.899 139.164,14.518 139.155,14.169"
+ id="path245" />
+
+
+ <path
+ d="M 142.083,46.788 C 142.299,47.111 142.441,47.509 142.614,47.857 C 142.17,47.679 141.726,47.501 141.282,47.323 C 141.474,47.081 141.586,46.724 141.815,46.52 C 141.543,46.675 141.26,46.859 141.016,47.055 C 141.37,46.966 141.736,46.9 142.083,46.788"
+ id="path247" />
+
+
+ <path
+ d="M 102.969,72.989 C 97.734,69.981 95.351,64.784 92.613,59.629 C 89.834,54.397 87.053,49.734 80.778,48.947 C 75.376,48.268 70.006,53.693 66.254,56.776 C 61.791,60.445 57.418,62.467 52.003,64.411 C 46.215,66.488 40.649,68.844 34.728,70.545 C 31.875,71.364 28.894,71.653 25.942,71.653 C 25.037,71.653 23.855,70.943 23.02,70.639 C 20.862,69.854 18.704,69.07 16.546,68.285 C 15.645,67.957 14.276,67.128 13.304,67.107 C 11.979,67.078 10.049,68.016 8.781,68.444 C 6.306,69.279 3.504,70.247 2.002,72.514 C -1.434,77.702 2.485,83.416 8.485,83.416 C 10.833,83.416 14.007,82.978 15.699,81.277 C 17.484,79.484 15.616,75.84 17.826,74.727 C 20.193,73.534 22.893,74.509 25.458,74.921 C 28.481,75.408 31.627,76.197 34.691,76.197 C 40.513,76.197 46.478,73.496 51.815,71.412 C 57.273,69.28 62.354,66.989 68.115,65.769 C 71.448,65.063 74.663,64.967 78.059,64.967 C 81.183,64.967 84.072,67.753 86.384,69.562 C 88.753,71.415 91.198,74.018 94.189,74.86 C 97.66,75.838 99.912,74.218 102.969,72.989"
+ id="path249"
+ style="fill-rule:evenodd" />
+
+
+ <path
+ d="M 102.703,73.523 C 97.466,70.514 94.691,65.175 92.081,59.931 C 90.745,57.247 88.99,54.995 87.349,52.52 C 86.779,51.661 85.136,50.527 84.138,50.193 C 82.998,49.812 80.11,50.001 80.62,48.391 C 83.722,48.782 86.328,49.502 88.413,52.016 C 90.361,54.363 91.912,57.033 93.339,59.724 C 94.773,62.428 96,65.274 97.913,67.641 C 98.711,68.628 99.468,69.568 100.455,70.394 C 101.43,71.209 103.979,72.18 102.703,73.523"
+ id="path251" />
+
+
+ <path
+ d="M 80.62,49.461 C 78.509,49.814 75.747,50.061 74.032,51.441 C 72.175,52.936 70.209,54.301 68.338,55.804 C 66.416,57.348 64.574,59.134 62.463,60.407 C 61.17,61.186 57.321,64.425 56.674,62.026 C 61.239,60.496 64.465,57.245 68.115,54.273 C 71.965,51.138 75.706,49.098 80.62,48.391 C 80.62,48.721 80.711,49.148 80.62,49.461"
+ id="path253" />
+
+
+ <path
+ d="M 80.62,48.392 C 80.62,48.748 80.62,49.105 80.62,49.462 C 80.62,49.105 80.62,48.748 80.62,48.392"
+ id="path255" />
+
+
+ <path
+ d="M 57.205,63.097 C 54.565,64.092 51.928,65.043 49.252,65.939 C 46.764,66.772 44.47,68.28 41.951,69.003 C 39.264,69.775 36.602,70.711 33.859,71.263 C 32.494,71.537 25.649,73.469 25.807,71.117 C 36.655,71.117 46.918,65.581 56.938,62.027 C 57.021,62.358 57.216,62.759 57.205,63.097"
+ id="path257" />
+
+
+ <path
+ d="M 57.205,63.097 C 57.22,62.593 57.061,62.139 56.673,62.027 C 56.841,62.364 56.975,62.801 57.205,63.097"
+ id="path259" />
+
+
+ <path
+ d="M 25.808,72.187 C 26.475,71.214 25.584,71.196 24.84,70.91 C 23.167,70.266 21.494,69.622 19.822,68.979 C 18.149,68.335 16.476,67.691 14.803,67.048 C 13.852,66.682 13.295,66.241 13.037,67.642 C 17.294,69.156 21.551,70.672 25.808,72.187"
+ id="path261" />
+
+
+ <path
+ d="M 26.074,72.187 C 26.018,72.035 26.016,71.511 25.808,71.117 C 25.896,71.468 25.946,71.849 26.074,72.187"
+ id="path263" />
+
+
+ <path
+ d="M 13.303,67.641 C 10.679,68.465 7.262,69.103 4.936,70.662 C 3.68,71.504 2.43,72.079 1.932,73.582 C 1.74,74.163 1.535,74.861 1.329,75.395 C 1.23,75.651 1.265,76.305 1.063,76.464 C 0.838,76.642 0,76.561 0,76.255 C 0,69.674 8.141,68.11 13.037,66.572 C 13.119,66.901 13.316,67.306 13.303,67.641"
+ id="path265" />
+
+
+ <path
+ d="M 13.569,66.572 C 13.402,66.545 13.206,66.572 13.037,66.572 C 13.203,66.887 13.137,67.325 13.303,67.641 C 13.214,67.641 13.126,67.641 13.037,67.641 C 13.205,67.304 13.338,66.868 13.569,66.572"
+ id="path267" />
+
+
+ <path
+ d="M 1.064,76.464 C 1.846,80.401 3.716,82.212 7.716,82.88 C 7.835,85.372 3.27,82.5 2.267,81.895 C 0.588,80.882 0.335,78.149 0,76.464 C 0.331,76.464 0.748,76.378 1.064,76.464"
+ id="path269" />
+
+
+ <path
+ d="M 0,76.464 C 0.354,76.464 0.709,76.464 1.064,76.464 C 0.709,76.464 0.354,76.464 0,76.464"
+ id="path271" />
+
+
+ <path
+ d="M 7.45,82.88 C 9.438,82.88 12.594,82.825 14.368,81.811 C 15.025,81.435 15.804,80.42 16.033,79.731 C 16.201,79.225 16.23,78.856 16.23,78.325 C 16.23,77.421 17.293,77.172 17.293,77.811 C 17.293,80.196 16.392,82.092 14.102,83.148 C 12.877,83.714 6.81,84.993 7.45,82.88"
+ id="path273" />
+
+
+ <path
+ d="M 7.45,83.95 C 7.445,83.594 7.45,83.237 7.45,82.88 C 7.539,82.88 7.627,82.88 7.716,82.88 C 7.632,83.217 7.61,83.646 7.45,83.95"
+ id="path275" />
+
+
+ <path
+ d="M 16.23,77.534 C 16.23,72.581 20.563,73.6 24.174,74.18 C 26.414,74.54 28.655,74.89 30.893,75.265 C 32.046,75.458 33.127,75.661 34.293,75.661 C 35.311,75.661 36.535,75.272 36.451,76.731 C 32.081,76.731 28.162,76.12 23.887,75.225 C 22.186,74.869 20.563,74.859 18.832,74.859 C 16.886,74.86 17.963,78.023 16.23,77.534"
+ id="path277" />
+
+
+ <path
+ d="M 16.23,77.534 C 16.584,77.534 16.939,77.534 17.293,77.534 C 16.939,77.534 16.585,77.534 16.23,77.534"
+ id="path279" />
+
+
+ <path
+ d="M 36.186,75.663 C 41.977,74.604 47.508,72.552 52.937,70.305 C 58.602,67.96 63.913,66.081 69.933,64.87 C 71.196,64.617 72.54,64.434 73.828,64.434 C 74.72,64.434 75.612,64.434 76.503,64.434 C 76.757,64.434 76.629,65.066 76.629,65.226 C 76.629,65.712 76.132,65.503 75.703,65.503 C 72.597,65.503 69.688,65.954 66.662,66.629 C 60.863,67.924 55.523,70.497 49.998,72.656 C 47.506,73.629 45.016,74.497 42.454,75.27 C 41.205,75.647 36.058,77.822 36.186,75.663"
+ id="path281" />
+
+
+ <path
+ d="M 36.452,76.732 C 36.364,76.376 36.275,76.019 36.186,75.662 C 36.274,76.019 36.363,76.376 36.452,76.732"
+ id="path283" />
+
+
+ <path
+ d="M 76.629,64.434 C 81.074,64.434 84.166,66.875 87.271,69.78 C 88.751,71.165 90.563,72.762 92.46,73.524 C 93.502,73.942 94.474,74.33 95.578,74.551 C 96.867,74.809 97.707,74.106 97.383,75.929 C 92.897,75.287 90.084,73.402 86.555,70.647 C 85.791,70.05 85.052,69.376 84.346,68.711 C 83.483,67.899 82.683,67.659 81.784,66.981 C 80.879,66.299 80.011,65.861 78.889,65.636 C 77.867,65.431 76.147,66.023 76.629,64.434"
+ id="path285" />
+
+
+ <path
+ d="M 76.629,64.434 C 76.629,64.79 76.629,65.146 76.629,65.503 C 76.629,65.146 76.629,64.79 76.629,64.434"
+ id="path287" />
+
+
+ <path
+ d="M 97.382,74.592 C 99.089,74.874 101.362,72.992 102.969,72.453 C 103.985,74.158 98.741,75.475 97.382,75.929 C 97.382,75.504 97.305,75.009 97.382,74.592"
+ id="path289" />
+
+
+ <path
+ d="M 97.382,75.929 C 97.382,75.483 97.382,75.038 97.382,74.592 C 97.382,75.038 97.382,75.483 97.382,75.929"
+ id="path291" />
+
+
+ <path
+ d="M 103.235,73.523 C 103.6,73.402 103.955,73.161 104.299,72.988 C 104.031,72.777 103.559,72.56 103.235,72.453 C 103.08,72.803 102.801,73.154 102.703,73.523 C 102.755,73.167 102.865,72.797 102.969,72.453 C 103.057,72.807 103.183,73.164 103.235,73.523"
+ id="path293" />
+
+
+ <path
+ d="M 132.768,75.261 C 132.768,66.238 138.293,55.075 148.6,55.075 C 158.907,55.075 164.432,66.237 164.432,75.261 C 164.432,84.285 158.907,95.447 148.6,95.447 C 138.293,95.447 132.768,84.285 132.768,75.261"
+ id="path295"
+ style="fill:#ffffff" />
+
+
+ <path
+ d="M 132.236,75.261 C 132.236,65.941 137.994,54.54 148.6,54.54 C 159.204,54.54 164.963,65.942 164.963,75.261 C 164.963,84.58 159.204,95.982 148.6,95.982 C 137.995,95.982 132.236,84.581 132.236,75.261"
+ id="path297"
+ style="fill:none;stroke:#000000;stroke-width:0.51050001;stroke-linecap:square;stroke-miterlimit:10" />
+
+
+ <path
+ d="M 164.432,70.048 C 164.432,60.946 170.488,50.798 180.528,50.798 C 190.568,50.798 196.626,60.945 196.626,70.048 C 196.626,79.15 190.568,89.298 180.528,89.298 C 170.488,89.298 164.432,79.149 164.432,70.048"
+ id="path299"
+ style="fill:#ffffff" />
+
+
+ <path
+ d="M 163.899,70.048 C 163.899,60.652 170.193,50.263 180.528,50.263 C 190.863,50.263 197.159,60.651 197.159,70.048 C 197.159,79.445 190.863,89.833 180.528,89.833 C 170.193,89.833 163.899,79.444 163.899,70.048"
+ id="path301"
+ style="fill:none;stroke:#000000;stroke-width:0.51050001;stroke-linecap:square;stroke-miterlimit:10" />
+
+
+ <path
+ d="M 120.529,83.95 C 121.491,89.756 123.208,95.024 125.585,100.392 C 127.909,105.643 132.481,109.869 137.173,113.013 C 146.191,119.056 159.364,117.308 169.047,114.317 C 176.368,112.056 182.468,108.311 188.91,104.27 C 184.667,108.228 180.528,112.09 175.31,114.711 C 170.246,117.256 164.182,116.951 158.692,117.124 C 152.482,117.319 146.456,117.473 140.275,116.782 C 135.053,116.198 127.602,115.009 124.968,109.717 C 121.172,102.087 121.167,92.291 120.529,83.95"
+ id="path303"
+ style="fill:#ffffff;fill-rule:evenodd" />
+
+
+ <path
+ d="M 121.061,83.95 C 122.972,94.48 126.724,105.299 135.961,111.488 C 135.761,111.841 135.45,112.269 135.164,112.557 C 125.929,105.347 121.871,95.247 119.997,83.95 C 120.325,83.95 120.749,83.86 121.061,83.95"
+ id="path305"
+ style="fill:#ffffff" />
+
+
+ <path
+ d="M 135.961,111.488 C 151.845,122.133 174.742,114.205 188.643,103.735 C 190.031,104.861 185.31,107.348 184.317,107.947 C 181.962,109.367 179.596,110.707 177.1,111.864 C 172.717,113.897 167.837,115.557 163.102,116.567 C 153.467,118.623 143.731,117.479 135.164,112.557 C 135.42,112.215 135.654,111.783 135.961,111.488"
+ id="path307"
+ style="fill:#ffffff" />
+
+
+ <path
+ d="M 135.165,112.558 C 135.431,112.202 135.696,111.845 135.962,111.489 C 135.696,111.845 135.43,112.201 135.165,112.558"
+ id="path309"
+ style="fill:#ffffff" />
+
+
+ <path
+ d="M 189.176,104.537 C 185.248,108.483 181.338,112.349 176.305,114.881 C 173.967,116.057 171.26,116.829 168.665,117.137 C 167.257,117.304 165.775,117.638 164.358,117.638 C 163.546,117.638 159.862,118.163 159.375,117.638 C 157.995,116.152 162.591,116.568 162.957,116.568 C 164.364,116.568 165.686,116.411 167.087,116.235 C 169.943,115.878 172.858,115.273 175.44,113.979 C 180.587,111.399 184.358,107.774 188.378,103.736 C 188.62,103.978 189.007,104.242 189.176,104.537"
+ id="path311"
+ style="fill:#ffffff" />
+
+
+ <path
+ d="M 188.643,103.735 C 188.832,103.993 188.998,104.27 189.176,104.537 C 188.91,104.27 188.632,104.012 188.377,103.735 C 188.632,104.011 188.91,104.27 189.176,104.537 C 188.999,104.271 188.833,103.994 188.643,103.735"
+ id="path313"
+ style="fill:#ffffff" />
+
+
+ <path
+ d="M 159.375,117.903 C 152.832,117.903 146.417,117.94 139.908,117.285 C 138.599,117.154 136.796,117.249 135.577,116.791 C 134.239,116.287 132.222,116.102 131.034,115.42 C 129.835,114.731 122.821,111.129 125.317,109.616 C 128.124,114.688 135.737,115.772 140.901,116.288 C 147.108,116.908 153.138,116.764 159.375,116.567 C 159.375,117.011 159.402,117.461 159.375,117.903"
+ id="path315"
+ style="fill:#ffffff" />
+
+
+ <path
+ d="M 159.375,117.638 C 159.375,118.323 159.375,116.784 159.375,116.568 C 159.375,116.924 159.375,117.281 159.375,117.638"
+ id="path317"
+ style="fill:#ffffff" />
+
+
+ <path
+ d="M 124.52,110.419 C 121.185,102.04 120.68,92.866 119.997,83.95 C 121.658,83.431 121.205,85.681 121.293,86.754 C 121.371,87.693 121.474,88.631 121.567,89.569 C 121.82,92.111 122.065,94.652 122.362,97.19 C 122.631,99.488 122.915,101.83 123.549,104.061 C 123.889,105.26 124.318,106.463 124.561,107.686 C 124.787,108.819 125.747,109.676 124.52,110.419"
+ id="path319"
+ style="fill:#ffffff" />
+
+
+ <path
+ d="M 124.52,110.419 C 124.786,110.151 125.052,109.884 125.318,109.616 C 125.052,109.884 124.786,110.151 124.52,110.419"
+ id="path321"
+ style="fill:#ffffff" />
+
+
+ <path
+ d="M 119.997,83.95 C 120.351,83.95 120.706,83.95 121.061,83.95 C 120.707,83.95 120.352,83.95 119.997,83.95 C 120.351,83.95 120.706,83.95 121.061,83.95 C 120.707,83.95 120.352,83.95 119.997,83.95"
+ id="path323"
+ style="fill:#ffffff" />
+
+
+ <path
+ d="M 125.852,71.385 C 126.788,74.074 128.149,76.335 127.182,79.138 C 126.378,81.467 124.444,83.352 122.097,84.138 C 119.5,85.008 116.743,84.408 114.279,83.415 C 113.009,82.904 111.827,82.21 110.583,81.642 C 109.764,81.268 108.945,80.894 108.126,80.52 C 107.96,80.444 107.355,81.598 107.228,81.811 C 112.55,83.324 117.719,87.567 123.725,85.02 C 125.865,84.112 128.248,81.875 128.248,79.395 C 128.248,77.95 128.522,76.756 128.051,75.335 C 127.607,74.006 126.523,72.621 125.852,71.385"
+ id="path325"
+ style="fill:#ffffff;fill-rule:evenodd" />
+
+
+ <path
+ d="M 126.384,71.385 C 126.052,71.367 125.644,71.571 125.318,71.652 C 125.749,72.887 126.513,77.82 128.246,76.733 C 127.625,74.95 127.004,73.167 126.384,71.385"
+ id="path327"
+ style="fill:#ffffff" />
+
+
+ <path
+ d="M 128.246,76.999 C 127.878,79.219 127.306,80.884 125.697,82.502 C 124.853,83.351 120.719,86.3 119.466,85.02 C 118.317,83.846 121.249,83.874 121.728,83.682 C 122.704,83.29 123.355,82.771 124.196,82.207 C 126.106,80.926 126.821,78.908 127.182,76.731 C 127.509,76.814 127.958,76.83 128.246,76.999"
+ id="path329"
+ style="fill:#ffffff" />
+
+
+ <path
+ d="M 128.246,76.732 C 128.711,77.135 127.59,76.972 127.182,76.732 C 127.182,76.821 127.182,76.91 127.182,76.999 C 127.517,76.915 127.942,76.893 128.246,76.732"
+ id="path331"
+ style="fill:#ffffff" />
+
+
+ <path
+ d="M 119.465,85.021 C 115.124,85.021 111.62,82.774 107.757,81.01 C 108.07,79.232 109.391,80.444 110.458,80.93 C 111.575,81.44 112.666,82.005 113.764,82.556 C 114.635,82.994 115.792,83.534 116.746,83.725 C 117.828,83.942 119.946,83.436 119.465,85.021"
+ id="path333"
+ style="fill:#ffffff" />
+
+
+ <path
+ d="M 119.465,85.021 C 119.465,84.664 119.465,84.308 119.465,83.951 C 119.465,84.307 119.465,84.664 119.465,85.021"
+ id="path335"
+ style="fill:#ffffff" />
+
+
+ <path
+ d="M 108.556,80.742 C 108.261,81.13 107.982,81.504 107.758,81.812 C 107.758,81.723 107.758,81.633 107.758,81.544 C 106.831,84.003 106.137,78.82 108.556,80.742"
+ id="path337"
+ style="fill:#ffffff" />
+
+
+ <path
+ d="M 108.29,79.94 C 108.113,79.851 107.935,79.762 107.758,79.673 C 107.329,80.306 107.863,80.589 108.556,80.742 C 108.333,80.862 108.008,80.971 107.758,81.01 C 107.931,80.662 108.072,80.261 108.29,79.94"
+ id="path339"
+ style="fill:#ffffff" />
+
+
+ <path
+ d="M 107.492,81.277 C 109.525,82.362 111.761,82.943 113.74,84.134 C 114.648,84.681 115.829,84.803 116.855,84.951 C 118.195,85.143 119.262,84.511 118.934,86.357 C 116.688,86.035 114.63,85.797 112.578,84.768 C 111.526,84.24 110.463,83.526 109.356,83.149 C 108.332,82.8 106.638,82.857 107.492,81.277"
+ id="path341"
+ style="fill:#ffffff" />
+
+
+ <path
+ d="M 107.226,82.347 C 107.237,81.998 107.407,81.618 107.492,81.277 C 107.892,81.694 107.536,81.881 107.226,82.347"
+ id="path343"
+ style="fill:#ffffff" />
+
+
+ <path
+ d="M 118.934,85.021 C 120.68,85.021 124.758,85.082 125.72,83.148 C 126.199,82.184 127.009,81.535 127.369,80.445 C 127.73,79.355 127.412,77.086 129.043,77.534 C 128.185,80.062 128.506,82.355 126.118,84.217 C 123.996,85.872 121.496,86.034 118.934,86.357 C 118.934,85.928 118.863,85.442 118.934,85.021"
+ id="path345"
+ style="fill:#ffffff" />
+
+
+ <path
+ d="M 118.934,86.357 C 118.934,85.912 118.934,85.466 118.934,85.021 C 118.934,85.466 118.934,85.912 118.934,86.357"
+ id="path347"
+ style="fill:#ffffff" />
+
+
+ <path
+ d="M 127.979,77.534 C 127.499,76.523 127.625,75.56 126.987,74.555 C 126.094,73.146 124.611,72.148 126.383,71.117 C 126.933,72.132 127.684,73.171 128.048,74.267 C 128.215,74.771 128.63,75.187 128.777,75.663 C 128.972,76.291 128.745,76.882 129.043,77.535 C 128.71,77.534 128.299,77.617 127.979,77.534"
+ id="path349"
+ style="fill:#ffffff" />
+
+
+ <path
+ d="M 129.043,77.534 C 128.689,77.534 128.334,77.534 127.98,77.534 C 128.334,77.534 128.688,77.534 129.043,77.534"
+ id="path351"
+ style="fill:#ffffff" />
+
+
+ <path
+ d="M 126.384,71.117 C 126.022,71.279 125.673,71.474 125.318,71.652 C 125.668,71.545 126.034,71.492 126.384,71.385 C 126.037,71.573 125.678,71.758 125.318,71.919 C 125.673,71.652 126.021,71.374 126.384,71.117"
+ id="path353"
+ style="fill:#ffffff" />
+
+
+ <path
+ d="M 184.653,91.972 C 183.889,93.367 184.97,96.439 185.244,97.903 C 185.755,100.638 185.626,102.643 188.635,103.398 C 193.061,104.509 196.579,98.333 199.552,96.249 C 197.697,98.114 196.147,100.203 194.311,102.052 C 192.255,104.121 190.468,104.804 187.59,104.804 C 185.565,104.804 184.281,101.222 184.028,99.695 C 183.549,96.803 183.488,94.706 184.653,91.972"
+ id="path355"
+ style="fill:#ffffff;fill-rule:evenodd" />
+
+
+ <path
+ d="M 185.184,91.972 C 184.546,93.144 185.412,95.593 185.602,96.835 C 185.861,98.519 186.203,100.189 186.514,101.863 C 184.706,102.422 184.799,98.471 184.585,97.181 C 184.394,96.022 184.217,94.861 183.988,93.709 C 183.75,92.51 183.604,91.599 185.184,91.972"
+ id="path357"
+ style="fill:#ffffff" />
+
+
+ <path
+ d="M 186.249,101.596 C 188.731,102.604 189.619,103.366 192.235,101.863 C 194.601,100.505 196.309,98.707 198.221,96.784 C 199.885,97.698 197.711,98.902 196.893,99.724 C 195.886,100.735 194.906,101.618 193.7,102.398 C 190.952,104.176 188.07,104.616 185.45,102.398 C 185.69,102.157 185.954,101.763 186.249,101.596"
+ id="path359"
+ style="fill:#ffffff" />
+
+
+ <path
+ d="M 185.45,101.863 C 185.435,102.038 185.45,102.222 185.45,102.398 C 185.626,102.083 186.035,101.888 186.249,101.596 C 186.338,101.685 186.426,101.774 186.515,101.863 C 186.169,101.863 185.789,101.921 185.45,101.863"
+ id="path361"
+ style="fill:#ffffff" />
+
+
+ <path
+ d="M 198.221,96.784 C 198.387,97.079 198.779,97.344 199.02,97.586 C 199.758,96.907 200.045,96.266 199.02,95.714 C 198.765,96.055 198.412,96.404 198.221,96.784"
+ id="path363"
+ style="fill:#ffffff" />
+
+
+ <path
+ d="M 198.221,96.784 C 198.488,97.051 198.753,97.319 199.02,97.586 C 198.753,97.319 198.488,97.051 198.221,96.784"
+ id="path365"
+ style="fill:#ffffff" />
+
+
+ <path
+ d="M 199.819,96.516 C 198.029,98.672 196.298,100.857 194.32,102.844 C 192.202,104.971 190.219,105.339 187.313,105.339 C 187.225,103.838 189.233,104.216 190.34,104.03 C 191.485,103.838 192.625,102.926 193.432,102.132 C 195.432,100.162 197.226,97.878 199.02,95.715 C 199.259,95.954 199.657,96.222 199.819,96.516"
+ id="path367"
+ style="fill:#ffffff" />
+
+
+ <path
+ d="M 199.02,95.714 C 199.287,95.982 199.552,96.249 199.819,96.516 C 199.552,96.249 199.287,95.981 199.02,95.714 C 199.287,95.982 199.552,96.249 199.819,96.516 C 199.552,96.249 199.287,95.981 199.02,95.714"
+ id="path369"
+ style="fill:#ffffff" />
+
+
+ <path
+ d="M 187.045,105.339 C 183.079,103.661 182.711,97.508 183.322,93.842 C 184.926,93.77 184.121,95.746 184.121,96.884 C 184.121,98.028 184.471,99.346 184.693,100.469 C 184.913,101.573 185.321,102.534 186.12,103.339 C 186.834,104.058 188.138,104.072 187.045,105.339"
+ id="path371"
+ style="fill:#ffffff" />
+
+
+ <path
+ d="M 187.313,105.339 C 187.178,105.33 187.045,104.849 187.045,105.205 C 187.045,105.46 187.497,104.481 187.58,104.27 C 187.492,104.625 187.419,104.989 187.313,105.339"
+ id="path373"
+ style="fill:#ffffff" />
+
+
+ <path
+ d="M 183.323,93.842 C 184.723,94.704 184.813,92.968 185.184,91.971 C 183.786,91.11 183.695,92.847 183.323,93.842"
+ id="path375"
+ style="fill:#ffffff" />
+
+
+ <path
+ d="M 183.323,93.842 C 183.677,93.931 184.033,94.021 184.387,94.11 C 184.033,94.021 183.677,93.932 183.323,93.842"
+ id="path377"
+ style="fill:#ffffff" />
+
+
+ <path
+ d="M 184.122,91.704 C 184.479,91.773 184.831,91.883 185.185,91.972 C 184.744,91.972 184.297,91.993 183.857,91.972 C 184.297,91.993 184.744,91.972 185.185,91.972 C 184.831,91.883 184.479,91.772 184.122,91.704"
+ id="path379"
+ style="fill:#ffffff" />
+
+
+ <path
+ d="M 136.227,68.978 C 136.227,63.745 139.893,58.284 145.54,58.284 C 151.187,58.284 154.854,63.744 154.854,68.978 C 154.854,74.212 151.187,79.673 145.54,79.673 C 139.893,79.673 136.227,74.212 136.227,68.978"
+ id="path381" />
+
+
+ <path
+ d="M 135.696,68.978 C 135.696,63.452 139.599,57.749 145.54,57.749 C 151.481,57.749 155.386,63.45 155.386,68.978 C 155.386,74.505 151.482,80.208 145.54,80.208 C 139.598,80.208 135.696,74.504 135.696,68.978"
+ id="path383"
+ style="fill:none;stroke:#000000;stroke-width:0.51050001;stroke-linecap:square;stroke-miterlimit:10" />
+
+
+ <path
+ d="M 171.084,65.102 C 171.084,59.859 174.699,54.274 180.395,54.274 C 186.091,54.274 189.708,59.858 189.708,65.102 C 189.708,70.346 186.092,75.93 180.395,75.93 C 174.7,75.929 171.084,70.344 171.084,65.102"
+ id="path385" />
+
+
+ <path
+ d="M 170.549,65.102 C 170.549,59.565 174.403,53.739 180.395,53.739 C 186.387,53.739 190.239,59.565 190.239,65.102 C 190.239,70.639 186.386,76.465 180.395,76.465 C 174.404,76.465 170.549,70.639 170.549,65.102"
+ id="path387"
+ style="fill:none;stroke:#000000;stroke-width:0.51050001;stroke-linecap:square;stroke-miterlimit:10" />
+
+
+ <path
+ d="M 96.051,107.745 C 93.799,109.725 91.514,111.433 89.134,113.225 C 86.871,114.931 83.606,115.505 80.928,116.313 C 78.069,117.175 74.937,116.834 71.979,116.834 C 69.034,116.834 66.642,115.553 63.858,114.963 C 62.615,114.699 61.047,114.695 59.767,114.695 C 58.07,114.695 57.58,115.107 56.201,115.567 C 53.832,116.355 52.639,119.531 52.023,121.696 C 51.236,124.461 52.645,126.726 53.018,129.35 C 53.424,132.204 54.141,135.001 54.838,137.797 C 56.338,143.815 59.371,149.085 62.67,154.298 C 64.155,156.644 65.442,159.051 66.565,161.587 C 67.129,162.861 67.697,164.132 68.284,165.396 C 68.659,166.204 69.034,167.011 69.41,167.819 C 69.429,167.86 68.18,168.639 67.989,168.832 C 65.71,171.126 62.282,182.338 67.796,182.338 C 73.714,182.338 79.478,181.454 82.484,175.654 C 83.373,173.938 84.794,169.959 83.149,168.301 C 80.774,165.907 79.52,169.225 76.956,168.365 C 74.798,167.641 75.037,164.898 74.19,162.983 C 73.016,160.326 71.888,157.683 70.872,154.961 C 69.926,152.428 69.386,149.861 68.177,147.43 C 66.909,144.882 66.024,142.053 64.97,139.408 C 62.919,134.258 61.302,128.969 59.335,123.785 C 66.891,123.785 74.685,124.919 81.952,122.181 C 85.347,120.903 88.423,118.65 91.411,116.645 C 92.764,115.738 93.962,113.943 94.723,112.556 C 95.652,110.86 95.779,109.655 96.051,107.745"
+ id="path389"
+ style="fill-rule:evenodd" />
+
+
+ <path
+ d="M 96.583,108.013 C 94.073,110.535 91.169,113.006 87.969,114.613 C 86.356,115.424 84.469,115.782 82.748,116.301 C 81.831,116.577 78.102,118.164 77.161,117.371 C 75.935,116.339 78.448,116.309 78.699,116.26 C 79.705,116.059 80.657,115.783 81.64,115.487 C 83.452,114.94 85.311,114.416 87.063,113.712 C 90.333,112.399 93.334,109.677 95.785,107.213 C 96.023,107.45 96.422,107.719 96.583,108.013"
+ id="path391" />
+
+
+ <path
+ d="M 70.774,116.3 C 72.187,116.3 73.601,116.3 75.014,116.3 C 75.657,116.3 76.299,116.3 76.941,116.3 C 77.307,116.3 77.343,117.432 77.16,117.638 C 76.781,118.065 73.512,117.638 72.92,117.638 C 71.302,117.638 70.644,118.118 70.774,116.3"
+ id="path393" />
+
+
+ <path
+ d="M 77.161,117.37 C 77.161,118.059 77.161,116.516 77.161,116.3 C 77.161,116.656 77.161,117.014 77.161,117.37"
+ id="path395" />
+
+
+ <path
+ d="M 70.508,117.37 C 68.65,117.03 66.466,116.811 64.755,115.95 C 63.784,115.462 63.01,115.58 61.964,115.405 C 60.864,115.22 59.6,115.673 59.6,114.438 C 59.6,113.344 69.889,116.088 71.039,116.299 C 70.878,116.625 70.746,117.099 70.508,117.37"
+ id="path397" />
+
+
+ <path
+ d="M 70.774,117.638 C 70.406,117.239 70.69,116.745 71.04,116.3 C 70.952,116.3 70.863,116.3 70.774,116.3 C 70.774,116.731 70.71,117.212 70.774,117.638"
+ id="path399" />
+
+
+ <path
+ d="M 59.601,115.231 C 57.454,115.231 55.343,116.117 54.195,118.042 C 53.506,119.198 53.027,120.341 52.604,121.617 C 52.379,122.297 52.417,122.899 52.417,123.619 C 52.417,123.942 51.353,124.025 51.353,123.301 C 51.353,120.845 52.305,118.355 54.012,116.568 C 54.719,115.827 59.786,112.285 59.601,115.231"
+ id="path401" />
+
+
+ <path
+ d="M 59.601,114.161 C 59.212,114.29 59.356,114.767 59.601,115.231 C 59.601,114.876 59.619,114.517 59.601,114.161"
+ id="path403" />
+
+
+ <path
+ d="M 52.417,123.786 C 52.417,125.185 52.563,126.1 53.004,127.43 C 53.349,128.471 54.608,131.118 52.683,131.005 C 52.485,129.609 52.131,128.396 51.747,127.045 C 51.47,126.072 50.5,123.199 52.417,123.786"
+ id="path405" />
+
+
+ <path
+ d="M 51.353,123.786 C 51.707,123.786 52.062,123.786 52.417,123.786 C 52.062,123.786 51.707,123.786 51.353,123.786"
+ id="path407" />
+
+
+ <path
+ d="M 53.746,130.737 C 54.747,135.098 55.576,139.382 57.426,143.47 C 59.284,147.578 61.358,151.302 63.858,155.069 C 62.309,156.508 60.521,152.014 59.723,150.756 C 58.392,148.656 57.385,146.54 56.541,144.209 C 55.767,142.068 54.835,140.187 54.277,137.957 C 53.679,135.567 53.194,133.145 52.681,130.736 C 53.012,130.737 53.431,130.65 53.746,130.737"
+ id="path409" />
+
+
+ <path
+ d="M 53.746,130.737 C 53.392,130.732 53.037,130.737 52.682,130.737 C 52.682,130.826 52.682,130.916 52.682,131.005 C 53.017,130.921 53.443,130.897 53.746,130.737"
+ id="path411" />
+
+
+ <path
+ d="M 63.858,155.069 C 65.084,157.225 66.212,159.328 67.215,161.593 C 67.739,162.778 68.269,163.957 68.815,165.131 C 69.327,166.235 70.776,167.811 68.913,168.168 C 66.938,163.919 65.11,159.674 62.792,155.6 C 63.114,155.44 63.507,155.139 63.858,155.069"
+ id="path413" />
+
+
+ <path
+ d="M 63.858,155.069 C 63.503,155.246 63.148,155.423 62.792,155.6 C 63.147,155.424 63.502,155.246 63.858,155.069"
+ id="path415" />
+
+
+ <path
+ d="M 69.71,168.437 C 67.766,168.51 66.864,171.57 66.251,173.114 C 65.821,174.195 65.721,175.377 65.495,176.517 C 65.24,177.803 65.942,178.655 64.123,178.33 C 64.54,175.817 64.757,173.661 65.719,171.244 C 66.15,170.16 69.005,165.531 69.71,168.437"
+ id="path417" />
+
+
+ <path
+ d="M 69.977,167.634 C 70.209,168.087 70.33,168.294 69.711,168.437 C 69.587,168.072 69.261,167.742 69.179,167.367 C 69.06,167.592 68.952,167.918 68.913,168.17 C 69.258,167.995 69.658,167.853 69.977,167.634"
+ id="path419" />
+
+
+ <path
+ d="M 65.454,178.062 C 65.306,179.779 66.105,180.742 67.049,182.072 C 65.693,183.107 65.425,181.746 64.839,180.567 C 64.108,179.1 63.69,178.416 65.454,178.062"
+ id="path421" />
+
+
+ <path
+ d="M 64.124,178.329 C 64.567,178.24 65.011,178.15 65.454,178.061 C 65.454,178.15 65.454,178.24 65.454,178.329 C 65.024,178.329 64.547,178.394 64.124,178.329"
+ id="path423" />
+
+
+ <path
+ d="M 66.517,181.804 C 67.804,181.804 69.092,181.804 70.379,181.804 C 70.707,181.804 73.889,181.489 72.638,182.874 C 72.284,183.266 69.318,182.874 68.776,182.874 C 67.758,182.874 66.006,183.409 66.517,181.804"
+ id="path425" />
+
+
+ <path
+ d="M 65.985,182.606 C 66.174,182.783 66.238,182.915 66.517,182.874 C 66.444,182.533 66.593,182.144 66.517,181.804 C 66.694,181.893 66.871,181.983 67.049,182.072 C 66.709,182.242 66.349,182.497 65.985,182.606"
+ id="path427" />
+
+
+ <path
+ d="M 72.372,181.804 C 75.631,181.148 77.867,180.014 80.211,177.667 C 81.165,176.712 82.218,175.379 82.55,174.041 C 82.77,173.156 82.99,172.272 83.21,171.388 C 83.286,171.081 83.12,170.216 83.279,170.04 C 83.448,169.852 84.345,169.949 84.345,170.249 C 84.345,173.52 83.118,176.26 80.886,178.595 C 78.404,181.192 76.009,181.954 72.638,182.874 C 72.555,182.54 72.368,182.146 72.372,181.804"
+ id="path429" />
+
+
+ <path
+ d="M 72.638,182.874 C 72.478,182.569 72.456,182.141 72.372,181.804 C 72.46,181.804 72.549,181.804 72.638,181.804 C 72.638,182.16 72.643,182.518 72.638,182.874"
+ id="path431" />
+
+
+ <path
+ d="M 83.279,170.04 C 82.919,169.281 83.12,168.753 82.481,168.169 C 81.811,167.556 80.606,168.008 81.418,166.564 C 83.277,167.5 83.921,167.923 84.345,170.041 C 84.014,170.04 83.596,170.126 83.279,170.04"
+ id="path433" />
+
+
+ <path
+ d="M 84.345,170.04 C 83.99,170.04 83.635,170.04 83.279,170.04 C 83.635,170.04 83.99,170.04 84.345,170.04"
+ id="path435" />
+
+
+ <path
+ d="M 81.418,167.634 C 80.081,167.814 78.778,168.628 77.427,168.972 C 76.575,167.547 79.944,166.75 81.152,166.564 C 81.235,166.897 81.422,167.292 81.418,167.634"
+ id="path437" />
+
+
+ <path
+ d="M 81.418,166.563 C 81.033,166.694 81.174,167.17 81.418,167.633 C 81.329,167.633 81.241,167.633 81.152,167.633 C 81.236,167.297 81.258,166.868 81.418,166.563"
+ id="path439" />
+
+
+ <path
+ d="M 77.161,168.972 C 74.505,168.228 74.476,165.701 73.702,163.357 C 75.196,162.459 75.422,165.069 75.774,166.129 C 75.879,166.447 76.116,167.634 76.496,167.634 C 77.405,167.634 77.635,168.178 77.161,168.972"
+ id="path441" />
+
+
+ <path
+ d="M 77.427,168.972 C 77.042,168.841 77.183,168.364 77.427,167.9 C 77.338,167.9 77.25,167.9 77.161,167.9 C 77.245,168.237 77.266,168.666 77.427,168.972"
+ id="path443" />
+
+
+ <path
+ d="M 73.702,163.356 C 72.378,160.359 70.877,157.34 69.954,154.188 C 69.433,152.41 69.055,150.542 68.227,148.879 C 67.634,147.688 65.499,144.734 67.581,144.373 C 70.008,150.459 71.597,157.084 74.765,162.822 C 74.448,162.982 74.048,163.293 73.702,163.356"
+ id="path445" />
+
+
+ <path
+ d="M 74.765,163.089 C 74.599,162.731 74.137,163.015 73.702,163.357 C 74.055,163.268 74.417,163.195 74.765,163.089"
+ id="path447" />
+
+
+ <path
+ d="M 66.517,144.909 C 65.109,141.368 63.637,137.834 62.437,134.215 C 61.847,132.435 61.297,130.637 60.632,128.883 C 60.124,127.542 57.732,123.986 59.866,123.521 C 61.16,127.097 62.414,130.675 63.613,134.285 C 64.233,136.152 64.797,138.045 65.524,139.873 C 66.046,141.185 68.54,144.548 66.517,144.909"
+ id="path449" />
+
+
+ <path
+ d="M 67.581,144.374 C 67.227,144.553 66.872,144.73 66.517,144.909 C 66.872,144.73 67.227,144.553 67.581,144.374"
+ id="path451" />
+
+
+ <path
+ d="M 59.333,123.251 C 59.945,123.251 65.759,122.848 64.39,124.321 C 64.098,124.634 61.759,124.321 61.323,124.321 C 60.283,124.321 58.889,124.789 59.333,123.251"
+ id="path453" />
+
+
+ <path
+ d="M 58.801,124.054 C 58.66,123.831 58.619,123.503 58.535,123.251 C 59.357,123.043 59.563,123.551 59.332,124.321 C 59.529,124.09 59.729,123.792 59.866,123.52 C 59.516,123.696 59.132,123.846 58.801,124.054"
+ id="path455" />
+
+
+ <path
+ d="M 64.39,123.251 C 65.684,123.311 70.861,122.659 70.243,124.589 C 68.947,124.529 63.771,125.184 64.39,123.251"
+ id="path457" />
+
+
+ <path
+ d="M 64.39,123.251 C 64.39,123.607 64.39,123.965 64.39,124.321 C 64.39,123.965 64.39,123.607 64.39,123.251"
+ id="path459" />
+
+
+ <path
+ d="M 70.242,123.521 C 73.714,123.521 76.75,122.888 80.106,122.044 C 81.917,121.589 83.519,121.03 85.103,120.035 C 85.812,119.59 86.521,119.144 87.231,118.698 C 87.984,118.225 89.098,118.6 88.27,119.224 C 86.944,120.222 85.713,120.961 84.228,121.706 C 82.603,122.521 81.07,122.779 79.399,123.409 C 77.712,124.046 76.144,124.225 74.356,124.426 C 73.196,124.557 69.665,125.409 70.242,123.521"
+ id="path461" />
+
+
+ <path
+ d="M 70.242,124.589 C 70.242,124.233 70.242,123.877 70.242,123.521 C 70.242,123.877 70.242,124.232 70.242,124.589"
+ id="path463" />
+
+
+ <path
+ d="M 88.068,118.173 C 89.977,116.894 92.069,115.545 93.391,113.627 C 94.827,111.543 95.173,109.916 95.518,107.478 C 97.972,107.334 95.37,112.946 94.563,113.958 C 92.847,116.113 90.875,117.449 88.602,118.974 C 88.439,118.729 88.152,118.452 88.068,118.173"
+ id="path465" />
+
+
+ <path
+ d="M 88.602,118.974 C 88.424,118.707 88.246,118.44 88.068,118.173 C 88.246,118.439 88.424,118.707 88.602,118.974"
+ id="path467" />
+
+
+ <path
+ d="M 96.583,107.745 C 96.672,107.21 96.762,106.676 96.851,106.141 C 96.143,106.852 95.31,107.32 96.583,108.013 C 96.226,107.852 95.859,107.672 95.519,107.478 C 95.872,107.566 96.234,107.639 96.583,107.745"
+ id="path469" />
+
+
+ <path
+ d="M 174.542,41.173 C 177.254,40.545 178.868,38.479 180.505,36.424 C 182.29,34.183 184.723,32.529 186.559,30.221 C 188.277,28.061 189.51,25.128 190.906,22.724 C 192.3,20.324 193.804,17.782 194.831,15.205 C 195.989,12.295 197.145,9.383 198.306,6.474 C 199.601,3.227 202.055,2.674 205.276,2.674 C 210.664,2.674 216.933,5.955 221.397,8.715 C 223.741,10.164 226.283,11.376 228.862,12.347 C 231.508,13.344 234.426,13.53 237.021,14.646 C 239.215,15.59 242.536,17.215 243.525,14.23 C 244.263,11.999 248.184,11.229 250.253,11.229 C 250.762,11.229 251.704,10.93 251.704,11.546 C 251.704,12.497 251.704,13.447 251.704,14.398 C 251.704,15.837 251.704,17.276 251.704,18.715 C 251.704,21.564 251.179,24.055 248.245,24.864 C 245.837,25.528 242.761,26.212 241.063,24.062 C 239.249,21.764 238.904,18.981 235.324,18.981 C 229.285,18.981 223.528,17.22 217.647,16.04 C 214.94,15.497 212.033,14.423 209.565,13.183 C 208.055,12.424 203.852,9.592 202.215,10.961 C 201.643,11.44 201.255,13.774 200.968,14.494 C 200.49,15.694 199.362,16.735 198.756,17.912 C 197.536,20.28 196.068,22.764 195.148,25.263 C 194.019,28.328 192.94,31.397 191.619,34.385 C 190.509,36.896 188.496,38.903 187.058,41.212 C 185.528,43.67 183.806,46.519 180.604,46.519 C 177.789,46.52 176.667,42.641 174.542,41.173"
+ id="path471"
+ style="fill-rule:evenodd" />
+
+
+ <path
+ d="M 174.276,40.638 C 176.919,39.752 178.105,38.478 179.864,36.361 C 182.249,37.635 175.987,41.511 174.542,41.707 C 174.458,41.373 174.272,40.979 174.276,40.638"
+ id="path473" />
+
+
+ <path
+ d="M 179.864,36.361 C 181.249,34.97 182.741,33.734 184.122,32.35 C 185.572,33.14 184.214,33.935 183.388,34.599 C 182.407,35.386 181.549,36.271 180.663,37.163 C 180.425,36.924 180.022,36.655 179.864,36.361"
+ id="path475" />
+
+
+ <path
+ d="M 179.864,36.361 C 180.131,36.628 180.396,36.896 180.663,37.163 C 180.396,36.896 180.13,36.628 179.864,36.361"
+ id="path477" />
+
+
+ <path
+ d="M 184.122,32.35 C 186.781,28.674 189.028,24.777 191.304,20.853 C 192.889,21.32 191.14,23.048 190.643,23.904 C 190.035,24.949 189.577,26.065 189.08,27.167 C 188.128,29.275 186.272,31.282 184.92,33.152 C 184.678,32.91 184.288,32.646 184.122,32.35"
+ id="path479" />
+
+
+ <path
+ d="M 184.918,33.152 C 184.652,32.884 184.387,32.617 184.121,32.35 C 184.387,32.618 184.653,32.885 184.918,33.152"
+ id="path481" />
+
+
+ <path
+ d="M 191.303,20.854 C 193.299,17.513 194.656,14.041 196.094,10.427 C 198.259,10.887 195.657,14.727 195.119,16.079 C 194.355,17.995 193.235,19.681 192.103,21.389 C 191.859,21.225 191.487,21.079 191.303,20.854"
+ id="path483" />
+
+
+ <path
+ d="M 192.104,21.389 C 191.837,21.211 191.57,21.032 191.303,20.854 C 191.57,21.032 191.837,21.21 192.104,21.389"
+ id="path485" />
+
+
+ <path
+ d="M 196.094,10.427 C 196.847,8.536 197.526,6.689 198.57,4.941 C 199.721,3.015 200.822,2.505 203.01,2.139 C 203.49,3.705 202.223,2.93 201.547,3.61 C 201.057,4.103 200.25,4.323 199.685,5.08 C 198.48,6.694 197.901,9.096 197.159,10.963 C 196.84,10.802 196.354,10.667 196.094,10.427"
+ id="path487" />
+
+
+ <path
+ d="M 197.159,10.962 C 196.805,10.784 196.449,10.605 196.095,10.427 C 196.449,10.605 196.804,10.784 197.159,10.962"
+ id="path489" />
+
+
+ <path
+ d="M 203.01,2.139 C 208.953,2.139 214.159,4.202 219.321,6.995 C 221.962,8.424 224.597,9.906 227.357,11.095 C 228.59,11.626 229.779,12.216 231.092,12.509 C 231.622,12.627 236.165,13.457 234.408,14.438 C 233.845,14.751 230.716,13.577 230.042,13.408 C 228.674,13.064 227.323,12.381 226.03,11.824 C 223.413,10.696 221.151,8.806 218.571,7.694 C 215.915,6.55 213.263,4.982 210.46,4.278 C 209.184,3.958 207.898,3.784 206.592,3.638 C 205.434,3.508 202.475,3.844 203.01,2.139"
+ id="path491" />
+
+
+ <path
+ d="M 203.01,2.139 C 203.01,2.495 203.01,2.851 203.01,3.208 C 203.01,2.851 203.01,2.495 203.01,2.139"
+ id="path493" />
+
+
+ <path
+ d="M 234.674,13.368 C 236.165,13.743 237.437,14.428 238.881,14.843 C 239.42,14.998 243.333,15.372 242.123,16.576 C 241.604,17.093 238.5,15.959 237.967,15.691 C 236.844,15.126 233.782,14.86 234.674,13.368"
+ id="path495" />
+
+
+ <path
+ d="M 234.674,13.368 C 234.585,13.724 234.497,14.081 234.408,14.438 C 234.498,14.081 234.585,13.724 234.674,13.368"
+ id="path497" />
+
+
+ <path
+ d="M 242.124,15.506 C 242.679,14.879 242.95,14.051 243.454,13.367 C 244.818,14.113 243.272,16.204 242.124,16.575 C 242.124,16.235 242.052,15.838 242.124,15.506"
+ id="path499" />
+
+
+ <path
+ d="M 242.124,16.576 C 242.124,16.22 242.124,15.863 242.124,15.506 C 242.124,15.863 242.124,16.22 242.124,16.576"
+ id="path501" />
+
+
+ <path
+ d="M 243.454,13.368 C 244.832,11.65 247.246,11.04 249.309,10.694 C 249.657,12.602 248.491,11.954 247.178,12.299 C 245.973,12.615 245.102,13.315 244.252,14.17 C 244.014,13.931 243.613,13.662 243.454,13.368"
+ id="path503" />
+
+
+ <path
+ d="M 243.454,13.368 C 243.721,13.635 243.986,13.903 244.253,14.17 C 243.986,13.902 243.72,13.635 243.454,13.368"
+ id="path505" />
+
+
+ <path
+ d="M 249.309,10.694 C 249.949,10.694 250.588,10.694 251.227,10.694 C 251.765,10.694 252.134,11.602 251.702,12.031 C 251.498,12.234 250.084,12.031 249.784,12.031 C 249.055,12.031 249.206,11.38 249.309,10.694"
+ id="path507" />
+
+
+ <path
+ d="M 249.309,10.694 C 249.309,11.14 249.309,11.585 249.309,12.031 C 249.309,11.585 249.309,11.14 249.309,10.694"
+ id="path509" />
+
+
+ <path
+ d="M 252.233,11.229 C 252.233,11.788 252.68,16.828 251.17,15.507 C 250.904,15.275 251.17,13.2 251.17,12.839 C 251.17,11.858 250.824,10.811 252.233,11.229"
+ id="path511" />
+
+
+ <path
+ d="M 251.702,10.694 C 252.691,11.018 252.058,11.491 251.171,11.229 C 251.3,11.491 251.497,11.825 251.702,12.031 C 251.702,11.592 251.748,11.13 251.702,10.694"
+ id="path513" />
+
+
+ <path
+ d="M 252.233,15.506 C 252.233,17.762 252.285,19.956 251.967,22.19 C 251.524,22.101 251.08,22.012 250.637,21.923 C 251.04,20.709 251.17,19.881 251.17,18.605 C 251.17,17.52 250.483,14.971 252.233,15.506"
+ id="path515" />
+
+
+ <path
+ d="M 251.17,15.506 C 251.524,15.506 251.878,15.506 252.233,15.506 C 251.878,15.506 251.525,15.506 251.17,15.506"
+ id="path517" />
+
+
+ <path
+ d="M 251.967,22.19 C 251.183,23.934 250.26,24.798 248.508,25.398 C 247.316,25.807 243.316,26.903 243.453,24.863 C 245.196,24.863 246.776,24.819 248.449,24.259 C 249.824,23.8 250.651,21.473 251.967,22.19"
+ id="path519" />
+
+
+ <path
+ d="M 251.967,22.19 C 251.878,22.279 251.79,22.368 251.701,22.457 C 251.791,22.369 251.878,22.279 251.967,22.19 C 251.538,22.041 251.085,21.949 250.637,21.923 C 251.081,22.012 251.524,22.102 251.967,22.19"
+ id="path521" />
+
+
+ <path
+ d="M 243.454,25.934 C 241.996,26.016 240.486,24.679 239.935,23.389 C 239.522,22.42 239.258,21.719 238.524,20.979 C 237.852,20.303 237.213,19.896 238.399,19.25 C 239.848,20.549 241.404,25.416 243.719,24.864 C 243.635,25.203 243.612,25.626 243.454,25.934"
+ id="path523" />
+
+
+ <path
+ d="M 243.719,25.934 C 243.335,25.804 243.476,25.327 243.719,24.864 C 243.63,24.864 243.542,24.864 243.453,24.864 C 243.538,25.201 243.559,25.629 243.719,25.934"
+ id="path525" />
+
+
+ <path
+ d="M 237.868,20.319 C 237.236,19.944 236.373,19.517 235.623,19.517 C 234.45,19.517 233.079,20.065 233.079,18.725 C 233.079,17.634 237.717,18.975 238.399,19.25 C 238.233,19.583 238.1,20.03 237.868,20.319"
+ id="path527" />
+
+
+ <path
+ d="M 238.399,19.25 C 238.295,19.614 238.037,19.979 237.868,20.319 C 237.544,19.91 237.875,19.544 238.399,19.25"
+ id="path529" />
+
+
+ <path
+ d="M 233.079,19.517 C 229.384,19.181 225.806,18.377 222.169,17.645 C 222.099,15.584 226.387,17.37 227.688,17.631 C 229.59,18.013 231.412,18.271 233.345,18.447 C 233.262,18.777 233.248,19.226 233.079,19.517"
+ id="path531" />
+
+
+ <path
+ d="M 233.079,19.517 C 233.239,19.212 233.261,18.785 233.345,18.448 C 233.256,18.448 233.168,18.448 233.079,18.448 C 233.079,18.804 233.074,19.161 233.079,19.517"
+ id="path533" />
+
+
+ <path
+ d="M 222.168,17.645 C 218.064,16.615 214.208,15.514 210.195,14.169 C 210.56,12.048 214.881,14.662 216.2,15.193 C 217.412,15.68 223.341,15.689 222.168,17.645"
+ id="path535" />
+
+
+ <path
+ d="M 222.168,17.645 C 222.257,17.289 222.345,16.933 222.434,16.576 C 222.345,16.933 222.257,17.289 222.168,17.645"
+ id="path537" />
+
+
+ <path
+ d="M 210.196,14.169 C 208.954,13.545 207.712,12.922 206.469,12.298 C 205.361,11.741 202.608,11.623 203.01,10.159 C 204.41,10.638 205.613,10.534 207.002,11.228 C 208.228,11.84 209.34,12.909 210.727,13.1 C 210.562,13.432 210.43,13.885 210.196,14.169"
+ id="path539" />
+
+
+ <path
+ d="M 210.196,14.169 C 210.373,13.813 210.55,13.457 210.727,13.1 C 210.55,13.457 210.373,13.813 210.196,14.169"
+ id="path541" />
+
+
+ <path
+ d="M 203.01,11.229 C 202.921,11.318 202.833,11.407 202.744,11.496 C 202.744,11.407 202.744,11.318 202.744,11.229 C 202.327,11.968 202.233,12.84 201.947,13.636 C 200.093,13.179 201.442,10.676 202.744,10.16 C 202.829,10.496 203.009,10.884 203.01,11.229"
+ id="path543" />
+
+
+ <path
+ d="M 203.01,10.16 C 202.625,10.29 202.767,10.766 203.01,11.229 C 203.01,10.873 203.028,10.515 203.01,10.16"
+ id="path545" />
+
+
+ <path
+ d="M 201.948,13.635 C 201.562,14.28 199.417,18.446 198.813,18.041 C 197.421,17.109 200.344,14.336 200.883,13.1 C 201.218,13.269 201.654,13.404 201.948,13.635"
+ id="path547" />
+
+
+ <path
+ d="M 201.948,13.635 C 201.594,13.457 201.238,13.279 200.884,13.1 C 201.238,13.279 201.593,13.457 201.948,13.635"
+ id="path549" />
+
+
+ <path
+ d="M 199.02,18.18 C 197.875,20.482 196.703,22.762 195.811,25.179 C 195.279,26.622 194.747,28.066 194.214,29.509 C 193.837,30.532 193.632,33.052 192.104,32.083 C 193.933,27.116 195.866,22.384 198.221,17.645 C 198.468,17.811 198.83,17.956 199.02,18.18"
+ id="path551" />
+
+
+ <path
+ d="M 198.221,17.645 C 198.488,17.823 198.753,18.002 199.02,18.18 C 198.753,18.002 198.488,17.823 198.221,17.645"
+ id="path553" />
+
+
+ <path
+ d="M 193.167,32.35 C 191.783,35.484 190.151,37.905 188.112,40.638 C 186.43,39.746 189.159,37.239 189.9,36.196 C 190.655,35.133 191.604,31.377 193.167,32.35"
+ id="path555" />
+
+
+ <path
+ d="M 193.167,32.35 C 192.813,32.261 192.459,32.172 192.104,32.082 C 192.458,32.172 192.812,32.261 193.167,32.35"
+ id="path557" />
+
+
+ <path
+ d="M 188.112,40.638 C 186.958,42.183 185.88,43.95 184.52,45.317 C 183.735,46.107 180.359,48.591 180.395,45.986 C 183.5,46.382 185.862,42.024 187.313,39.837 C 187.554,40.079 187.945,40.343 188.112,40.638"
+ id="path559" />
+
+
+ <path
+ d="M 187.313,39.836 C 187.58,40.103 187.845,40.371 188.112,40.638 C 187.845,40.371 187.58,40.104 187.313,39.836"
+ id="path561" />
+
+
+ <path
+ d="M 180.395,47.055 C 177.333,47.618 176.395,42.784 174.008,41.707 C 174.944,39.477 176.442,42.295 177.211,43.377 C 177.929,44.388 179.248,46.253 180.662,45.986 C 180.58,46.318 180.561,46.758 180.395,47.055"
+ id="path563" />
+
+
+ <path
+ d="M 180.663,47.055 C 180.275,46.926 180.419,46.449 180.663,45.986 C 180.574,45.986 180.484,45.986 180.395,45.986 C 180.479,46.322 180.501,46.75 180.663,47.055"
+ id="path565" />
+
+
+ <path
+ d="M 174.008,41.707 C 173.713,41.506 173.463,41.159 173.211,40.905 C 173.473,40.761 173.976,40.645 174.275,40.638 C 174.326,40.989 174.546,41.355 174.541,41.707 C 174.657,41.372 174.756,40.989 174.807,40.638 C 174.543,40.992 174.245,41.335 174.008,41.707"
+ id="path567" />
+
+
+</g>
+ </g>
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer4"
+ inkscape:label="icon"
+ style="opacity:1;display:inline">
+ <path
+ sodipodi:type="arc"
+ style="opacity:1;fill:none;fill-opacity:1;stroke:#1a18dc;stroke-width:4;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;overflow:visible"
+ id="path3690"
+ sodipodi:cx="22.96529"
+ sodipodi:cy="178.31873"
+ sodipodi:rx="22.450956"
+ sodipodi:ry="22.450956"
+ d="M 45.416246,178.31873 A 22.450956,22.450956 0 1 1 0.51433372,178.31873 A 22.450956,22.450956 0 1 1 45.416246,178.31873 z"
+ transform="matrix(0.9985366,0,0,1.0346393,5.6683173,-160.11222)" />
+ <path
+ style="opacity:1;fill:none;fill-rule:evenodd;stroke:#1110f2;stroke-width:4.27401018;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;overflow:visible"
+ d="M 13.915756,6.234955 L 41.267576,42.165045"
+ id="path4464" />
+ </g>
+</svg>
diff --git a/activity/activity-terminal.svg b/activity/activity-terminal.svg
new file mode 100644
index 0000000..db057f9
--- /dev/null
+++ b/activity/activity-terminal.svg
@@ -0,0 +1,11 @@
+<?xml version="1.0" ?><!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd' [
+ <!ENTITY stroke_color "#010101">
+ <!ENTITY fill_color "#FFFFFF">
+]><svg enable-background="new 0 0 55 55" height="55px" version="1.1" viewBox="0 0 55 55" width="55px" x="0px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" y="0px"><g display="block" id="activity-terminal">
+
+ <rect fill="&fill_color;" height="32.442" stroke="&stroke_color;" stroke-linecap="round" stroke-width="3.5" width="43.457" x="5.646" y="9.404"/>
+ <g>
+ <path d="M15.531,27.872h-1.187l-0.007-2.205 c-0.61-0.024-1.201-0.093-1.772-0.205s-1.128-0.269-1.67-0.469v-1.919c0.562,0.288,1.129,0.509,1.703,0.663 c0.573,0.153,1.156,0.24,1.747,0.26v-2.278l-0.242-0.044c-1.167-0.205-1.996-0.527-2.486-0.967 c-0.491-0.439-0.736-1.072-0.736-1.897c0-0.874,0.3-1.557,0.899-2.047c0.6-0.491,1.455-0.758,2.565-0.802l0.007-1.692h1.179v1.663 c0.488,0.039,0.977,0.1,1.465,0.183s0.979,0.19,1.473,0.322v1.86c-0.488-0.205-0.977-0.365-1.465-0.479s-0.979-0.185-1.472-0.209 v2.102l0.234,0.044c1.24,0.195,2.11,0.521,2.611,0.978c0.5,0.457,0.75,1.131,0.75,2.025c0,0.898-0.297,1.588-0.893,2.069 c-0.596,0.481-1.497,0.756-2.703,0.824V27.872z M14.345,19.544v-1.912c-0.347,0.02-0.624,0.114-0.832,0.282 c-0.208,0.169-0.311,0.382-0.311,0.641c0,0.288,0.095,0.514,0.286,0.677C13.678,19.396,13.964,19.5,14.345,19.544z M15.531,21.932 v2.036c0.425-0.005,0.744-0.088,0.956-0.249c0.213-0.161,0.319-0.403,0.319-0.725c0-0.332-0.098-0.58-0.293-0.744 C16.317,22.087,15.99,21.98,15.531,21.932z" fill="&stroke_color;" stroke="&stroke_color;" stroke-width="0.5"/>
+ <path d="M27.646,27.813v1.392h-7.501v-1.392H27.646z" fill="&stroke_color;" stroke="&stroke_color;" stroke-width="0.5"/>
+ </g>
+</g></svg> \ No newline at end of file
diff --git a/activity/activity.info b/activity/activity.info
new file mode 100644
index 0000000..a473d31
--- /dev/null
+++ b/activity/activity.info
@@ -0,0 +1,9 @@
+[Activity]
+name = PyDebug
+activity_version = 3
+service_name = org.laptop.PyDebug
+exec = PyDebug.sh
+icon = PyDebug
+mime_types =
+license = GPLv2+
+
diff --git a/bin/PyDebug.sh b/bin/PyDebug.sh
new file mode 100755
index 0000000..f052f73
--- /dev/null
+++ b/bin/PyDebug.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+echo comand line:"$@"
+CURDIR=`cd $(dirname $0)/..; pwd`
+echo current directory is $CURDIR
+export HOME=$SUGAR_ACTIVITY_ROOT/data
+export PYTHONPATH=$CURDIR:$CURDIR/lib/python2.6/site-packages:$PYTHONPATH
+export PATH=$CURDIR/bin:$PATH
+export SUGAR_BUNDLE_PATH=$CURDIR
+export IPYTHONDIR=$CURDIR
+#export LD_LIBRARY_PATH=$CURDIR/lib:$LD_LIBRARY_PATH
+export SUGAR_SCALING=xo
+exec sugar-activity pydebug.PyDebugActivity "$@"
diff --git a/bin/PyDebug.sh~ b/bin/PyDebug.sh~
new file mode 100644
index 0000000..52eaace
--- /dev/null
+++ b/bin/PyDebug.sh~
@@ -0,0 +1,11 @@
+#!/bin/sh
+echo comand line:"$@"
+CURDIR=`cd $(dirname $0)/..; pwd`
+echo current directory is $CURDIR
+export HOME=$SUGAR_ACTIVITY_ROOT/data
+export PYTHONPATH=$CURDIR:$CURDIR/lib/python2.6/site-packages:$PYTHONPATH
+export PATH=$CURDIR/bin:$PATH
+export SUGAR_BUNDLE_PATH=$CURDIR
+#export LD_LIBRARY_PATH=$CURDIR/lib:$LD_LIBRARY_PATH
+export SUGAR_SCALING=100
+exec sugar-activity pydebug.PyDebugActivity -c '"$@"'
diff --git a/bin/continue_debug.py b/bin/continue_debug.py
new file mode 100644
index 0000000..a0267f8
--- /dev/null
+++ b/bin/continue_debug.py
@@ -0,0 +1,180 @@
+#!/usr/bin/env python
+from __future__ import with_statement
+#
+# Copyright (C) 2007, Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+import os
+import sys
+
+#debug tool to analyze the activity environment
+# Initialize logging.
+import logging
+from pydebug_logging import _logger, log_environment
+_logger.setLevel(logging.DEBUG)
+
+from sugar.activity import activityfactory
+from sugar.bundle.activitybundle import ActivityBundle
+
+#define the interface with the GUI
+from Rpyc import *
+try:
+ c = SocketConnection('localhost')
+ db = c.modules.pydebug.pydebug_instance
+except AttributeError:
+ print('cannot connect to localhost')
+except e:
+ print(e[1])
+ assert False
+
+#define interface with the command line ipython instance
+#from IPython.core import ipapi
+from IPython import ipapi
+ip = ipapi.get()
+global __IPYTHON__
+try:
+ __IPYTHON__
+ print('IPTHON is defined')
+except:
+ __IPYTHON__ = ip
+
+def edit_glue(self,filename,linenumber=0):
+ _logger.debug('position to editor file:%s. Line:%d'%(filename,linenumber))
+ if filename.endswith('.pyc'):
+ filename = filename[:-1]
+ if linenumber > 0:
+ linenumber -= 1
+ db.editor.position_to(filename,linenumber)
+
+ip.set_hook('editor',edit_glue)
+
+def sync_called(self,filename,linenumber,col):
+ if filename.endswith('.pyc'):
+ filename = filename[:-1]
+ if linenumber > 0:
+ linenumber -= 1
+ print('synchronize called. file:%s. line:%s. Col:%s'%(filename,linenumber,col))
+ db.editor.position_to(filename,linenumber)
+
+ip.set_hook('synchronize_with_editor',sync_called)
+
+#get the information about the Activity we are about to debug
+child_path = db.child_path
+_logger.debug('child path: %s'%child_path)
+
+#set the traceback level of detail
+ip.options.xmode = db.traceback
+
+""" if this were to work properly we should set go equal to object Macro
+go_cmd = 'run -d -b %s %s'%(os.path.join(db.pydebug_path,'bin','start_debug.py'),child_path)
+_logger.debug('defining go: %s'%go_cmd)
+ip.user_ns['go'] = go_cmd
+"""
+_logger.debug('pydebug home: %s'%db.debugger_home)
+path = child_path
+pydebug_home = db.debugger_home
+os.environ['PYDEBUG_HOME'] = pydebug_home
+os.chdir(path)
+os.environ['SUGAR_BUNDLE_PATH'] = path
+_logger.debug('sugar_bundle_path set to %s'%path)
+
+#set up module search path
+sys.path.insert(0,path)
+activity = ActivityBundle(path)
+cmd_args = activityfactory.get_command(activity)
+_logger.debug('command args:%r'%cmd_args)
+bundle_name = activity.get_name()
+os.environ['SUGAR_BUNDLE_NAME'] = bundle_name
+bundle_id = activity.get_bundle_id()
+os.environ['SUGAR_BUNDLE_ID'] = bundle_id
+
+#need to get activity root, but activity bases off of HOME which some applications need to change
+#following will not work if storage system changes with new OS
+#required because debugger needs to be able to change home so that foreign apps will work
+activity_root = os.path.join('/home/olpc/.sugar/default/',bundle_id)
+os.environ['SUGAR_ACTIVITY_ROOT'] = activity_root
+_logger.debug('sugar_activity_root set to %s'%activity_root)
+
+#following is useful for its side-effects
+info = activityfactory.get_environment(activity)
+
+_logger.debug("Command args:%s."%cmd_args)
+if not cmd_args[0].startswith('sugar-activity'):
+ #it is a batch file which will try to set up the environment
+ target = os.path.join(pydebug_home,os.path.basename(cmd_args[0]))
+ with open(target,'w') as write_script_fd:
+ #rewrite the batch file in the debugger home directory without exec line
+ with open(cmd_args[0],'r') as read_script_fd:
+ for line in read_script_fd.readlines():
+ if line.startswith('exec') or line.startswith('sugar-activity'):
+ pass
+ cmd_args[1] = line.split()[2]
+ else:
+ write_script_fd.write(line)
+ #write the environment variables to another file
+ line = 'export -p > %s_env\n'%target
+ write_script_fd.write(line)
+ #write_script_fd.close()
+ _logger.debug('Completed writing env script:%s'%target)
+ os.chmod(target,0755) #make it executable
+ os.system(target)
+
+ #read the environment back into the current process
+ with open('%s_env'%target,'r') as env_file:
+ env_dict = os.environ.copy()
+ for line in env_file.readlines():
+ skip_line = False
+ start_scan = 0
+ if not line.startswith('export'):
+ pass
+ payload = line.split()[1]
+ pair = payload.split('=')
+ if len(pair)> 1:
+ key = pair[0]
+ value = pair[1]
+ value = value[1:-1] #clip off quote marks
+ index = value.find(pydebug_home[:-6], start_scan)
+ while index > -1:
+ #the batch file commonly in use uses $0 to capture curdir
+ # this will be incorrect since we executed the script in pydebug_home
+ testvalue = value[index:index + len(path)]
+ if index > -1 and testvalue != path:
+ #substitute path for pydebug_home
+ testval = value[index + len(pydebug_home) - 5:]
+ value = value[:index] + path + testval
+ #permit repeated debug runs without creating monster environment strings
+ if os.environ.has_key(key):
+ if os.environ[key] == value: skip_line = True
+ if not skip_line: env_dict[key] = value
+ start_scan = index + len(path)
+ index = value.find(pydebug_home[:-6], start_scan)
+ os.environ = env_dict
+#bundle_id = cmd_args[5]
+#sys.argv = [None, cmd_args[1],'-s'] + cmd_args[1:]
+#sys.argv = [None, cmd_args[1],] + cmd_args[1:]
+#sys.argv = [None,] + cmd_args[1:]
+sys.argv = cmd_args
+
+log_environment()
+_logger.debug('about to call main.main() with args %r'%sys.argv)
+
+from sugar.activity import main
+main.main()
+
+
+
+
diff --git a/bin/continue_debug.py~ b/bin/continue_debug.py~
new file mode 100644
index 0000000..6fb3c1e
--- /dev/null
+++ b/bin/continue_debug.py~
@@ -0,0 +1,180 @@
+#!/usr/bin/env python
+from __future__ import with_statement
+#
+# Copyright (C) 2007, Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+import os
+import sys
+
+#debug tool to analyze the activity environment
+# Initialize logging.
+import logging
+from pydebug_logging import _logger, log_environment
+_logger.setLevel(logging.DEBUG)
+
+from sugar.activity import activityfactory
+from sugar.bundle.activitybundle import ActivityBundle
+
+#define the interface with the GUI
+from Rpyc import *
+try:
+ c = SocketConnection('localhost')
+ db = c.modules.pydebug.pydebug_instance
+except AttributeError:
+ print('cannot connect to localhost')
+except e:
+ print(e[1])
+ assert False
+
+#define interface with the command line ipython instance
+#from IPython.core import ipapi
+from IPython import ipapi
+ip = ipapi.get()
+global __IPYTHON__
+try:
+ __IPYTHON__
+ print('IPTHON is defined')
+except:
+ __IPYTHON__ = ip
+
+def edit_glue(self,filename,linenumber=0):
+ _logger.debug('position to editor file:%s. Line:%d'%(filename,linenumber))
+ if filename.endswith('.pyc'):
+ filename = filename[:-1]
+ if linenumber > 0:
+ linenumber -= 1
+ db.editor.position_to(filename,linenumber)
+
+ip.set_hook('editor',edit_glue)
+
+def sync_called(self,filename,linenumber,col):
+ if filename.endswith('.pyc'):
+ filename = filename[:-1]
+ if linenumber > 0:
+ linenumber -= 1
+ print('synchronize called. file:%s. line:%s. Col:%s'%(filename,linenumber,col))
+ db.editor.position_to(filename,linenumber)
+
+ip.set_hook('synchronize_with_editor',sync_called)
+
+#get the information about the Activity we are about to debug
+child_path = db.child_path
+_logger.debug('child path: %s'%child_path)
+
+#set the traceback level of detail
+ip.options.xmode = db.traceback
+
+""" if this were to work properly we should set go equal to object Macro
+go_cmd = 'run -d -b %s %s'%(os.path.join(db.pydebug_path,'bin','start_debug.py'),child_path)
+_logger.debug('defining go: %s'%go_cmd)
+ip.user_ns['go'] = go_cmd
+"""
+_logger.debug('pydebug home: %s'%db.debugger_home)
+path = child_path
+pydebug_home = db.debugger_home
+os.environ['PYDEBUG_HOME'] = pydebug_home
+os.chdir(path)
+os.environ['SUGAR_BUNDLE_PATH'] = path
+_logger.debug('sugar_bundle_path set to %s'%path)
+
+#set up module search path
+sys.path.insert(0,path)
+activity = ActivityBundle(path)
+cmd_args = activityfactory.get_command(activity)
+_logger.debug('command args:%r'%cmd_args)
+bundle_name = activity.get_name()
+os.environ['SUGAR_BUNDLE_NAME'] = bundle_name
+bundle_id = activity.get_bundle_id()
+os.environ['SUGAR_BUNDLE_ID'] = bundle_id
+
+#need to get activity root, but activity bases off of HOME which some applications need to change
+#following will not work if storage system changes with new OS
+#required because debugger needs to be able to change home so that foreign apps will work
+activity_root = os.path.join('/home/olpc/.sugar/default/',bundle_id)
+os.environ['SUGAR_ACTIVITY_ROOT'] = activity_root
+_logger.debug('sugar_activity_root set to %s'%activity_root)
+
+#following is useful for its side-effects
+info = activityfactory.get_environment(activity)
+
+_logger.debug("Command args:%s."%cmd_args)
+if not cmd_args[0].startswith('sugar-activity'):
+ #it is a batch file which will try to set up the environment
+ target = os.path.join(pydebug_home,os.path.basename(cmd_args[0]))
+ with open(target,'w') as write_script_fd:
+ #rewrite the batch file in the debugger home directory without exec line
+ with open(cmd_args[0],'r') as read_script_fd:
+ for line in read_script_fd.readlines():
+ if line.startswith('exec') or line.startswith('sugar-activity'):
+ pass
+ cmd_args[1] = line.split()[1]
+ else:
+ write_script_fd.write(line)
+ #write the environment variables to another file
+ line = 'export -p > %s_env\n'%target
+ write_script_fd.write(line)
+ #write_script_fd.close()
+ _logger.debug('Completed writing env script:%s'%target)
+ os.chmod(target,0755) #make it executable
+ os.system(target)
+
+ #read the environment back into the current process
+ with open('%s_env'%target,'r') as env_file:
+ env_dict = os.environ.copy()
+ for line in env_file.readlines():
+ skip_line = False
+ start_scan = 0
+ if not line.startswith('export'):
+ pass
+ payload = line.split()[1]
+ pair = payload.split('=')
+ if len(pair)> 1:
+ key = pair[0]
+ value = pair[1]
+ value = value[1:-1] #clip off quote marks
+ index = value.find(pydebug_home[:-6], start_scan)
+ while index > -1:
+ #the batch file commonly in use uses $0 to capture curdir
+ # this will be incorrect since we executed the script in pydebug_home
+ testvalue = value[index:index + len(path)]
+ if index > -1 and testvalue != path:
+ #substitute path for pydebug_home
+ testval = value[index + len(pydebug_home) - 5:]
+ value = value[:index] + path + testval
+ #permit repeated debug runs without creating monster environment strings
+ if os.environ.has_key(key):
+ if os.environ[key] == value: skip_line = True
+ if not skip_line: env_dict[key] = value
+ start_scan = index + len(path)
+ index = value.find(pydebug_home[:-6], start_scan)
+ os.environ = env_dict
+#bundle_id = cmd_args[5]
+#sys.argv = [None, cmd_args[1],'-s'] + cmd_args[1:]
+#sys.argv = [None, cmd_args[1],] + cmd_args[1:]
+#sys.argv = [None,] + cmd_args[1:]
+sys.argv = cmd_args
+
+log_environment()
+_logger.debug('about to call main.main() with args %r'%sys.argv)
+
+from sugar.activity import main
+main.main()
+
+
+
+
diff --git a/bin/git b/bin/git
new file mode 100755
index 0000000..00ba34c
--- /dev/null
+++ b/bin/git
Binary files differ
diff --git a/bin/ipython.py b/bin/ipython.py
new file mode 100755
index 0000000..5be0994
--- /dev/null
+++ b/bin/ipython.py
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""IPython -- An enhanced Interactive Python
+
+The actual ipython script to be installed with 'python setup.py install' is
+in './scripts' directory. This file is here (ipython source root directory)
+to facilitate non-root 'zero-installation' (just copy the source tree
+somewhere and run ipython.py) and development. """
+
+import IPython.Shell
+IPython.Shell.start().mainloop()
diff --git a/bin/python.save b/bin/python.save
new file mode 100755
index 0000000..3f3035a
--- /dev/null
+++ b/bin/python.save
@@ -0,0 +1,12 @@
+#!/usr/bin/env /usr/bin/python
+# -*- coding: utf-8 -*-
+"""IPython -- An enhanced Interactive Python
+
+The actual ipython script to be installed with 'python setup.py install' is
+in './scripts' directory. This file is here (ipython source root directory)
+to facilitate non-root 'zero-installation' (just copy the source tree
+somewhere and run ipython.py) and development. """
+
+from IPython.core.ipapp import launch_new_instance
+
+launch_new_instance()
diff --git a/bin/start_debug.py b/bin/start_debug.py
new file mode 100644
index 0000000..57921c3
--- /dev/null
+++ b/bin/start_debug.py
@@ -0,0 +1,54 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2009, George Hunt <georgejhunt@gmail.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import os
+
+# Initialize logging.
+import logging
+_logger = logging.getLogger('PyDebug')
+_logger.setLevel(logging.DEBUG)
+
+#establish a remote procedure call pipe connection with the PyDebug process
+from Rpyc import *
+try:
+ c = SocketConnection('localhost')
+ db = c.modules.pydebug.pydebug_instance
+except AttributeError:
+ _logger.error('cannot connect to localhost')
+except e:
+ print(e[1])
+ assert False
+pydebug_path = db.pydebug_path
+print('./bin/start_debug.py established connectioon. pydebug path: %s'%pydebug_path)
+
+#these alternative definitions are required for ipython v0.11 and greater
+#define interface with the command line ipython instance
+#from IPython.core import ipapi
+#from IPython.core.macro import Macro
+
+from IPython import ipapi
+from IPython.macro import Macro
+ip = ipapi.get()
+
+#define 2 macros, one which sets pdb on, the other off
+cmd = 'run -b 156 -d %s\n'% os.path.join(pydebug_path,'bin','continue_debug.py')
+if not ip.user_ns.has_key('gob'):
+ ip.user_ns['gb'] = Macro(cmd)
+cmd = 'run %s\n'% os.path.join(pydebug_path,'bin','continue_debug.py')
+if not ip.user_ns.has_key('go'):
+ ip.user_ns['go'] = Macro(cmd)
diff --git a/bin/startdb b/bin/startdb
new file mode 100644
index 0000000..a34f3dd
--- /dev/null
+++ b/bin/startdb
@@ -0,0 +1,116 @@
+#!/usr/bin/env python
+
+# Copyright (C) 2007, Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+from __future__ import with_statement
+
+import os
+import sys
+import dbus
+
+# Initialize logging.
+import logging
+from sugar import logger
+#Get the standard logging directory.
+std_log_dir = logger.get_logs_dir()
+_logger = logging.getLogger('PyDebug')
+"""
+#First log handler: outputs to a file called 'VideoEdit.activity.log'
+file_handler = logging.FileHandler(os.path.join(std_log_dir,'PyDebug.activity.log')
+file_formatter = logging.Formatter('%(name)s -- %(asctime)s %(funcName)s: %(lineno)d\n %(message)s\n')
+file_handler.setFormatter(file_formatter)
+_logger.addHandler(file_handler)
+"""
+_logger.setLevel(logging.DEBUG)
+
+#Second log handler: outputs to a the console, using a slightly different output structure
+console_handler = logging.StreamHandler()
+console_formatter = logging.Formatter('%(name)s %(levelname)s %(funcName)s: %(lineno)d||| %(message)s')
+console_handler.setFormatter(console_formatter)
+_logger.addHandler(console_handler)
+
+
+
+from sugar.activity import activityfactory
+from sugar.bundle.activitybundle import ActivityBundle
+
+path = sys.argv[1]
+pydebug_home = os.environ.get('PYDEBUG_HOME','/home/olpc/.sugar/default/org.laptop.PyDebug/data')
+os.environ['PYDEBUG_HOME'] = pydebug_home
+os.chdir(path)
+os.environ['SUGAR_BUNDLE_PATH'] = path
+_logger.debug('sugar_bundle_path set to %s'%path)
+
+#set up module search path
+sys.path.insert(0,path)
+activity = ActivityBundle(path)
+cmd_args = activityfactory.get_command(activity)
+_logger.debug('command args:%r'%cmd_args)
+bundle_name = activity.get_name()
+bundle_id = activity.get_bundle_id()
+
+#need to get activity root, but activity bases off of HOME which some applications need to change
+#following will not work if storage system changes with new OS
+#required because debugger needs to be able to change home so that foreign apps will work
+activity_root = os.path.join('/home/olpc/.sugar/default/',bundle_id)
+os.environ['SUGAR_ACTIVITY_ROOT'] = activity_root
+_logger.debug('sugar_activity_root set to %s'%activity_root)
+
+#following is useful for its side-effects
+info = activityfactory.get_environment(activity)
+
+_logger.debug("Command to execute:%s."%cmd_args[0])
+if not cmd_args[0].startswith('sugar-activity'):
+ target = os.path.join(pydebug_home,os.path.basename(cmd_args[0]))
+ with open(target,'w') as write_script_fd:
+ with open(cmd_args[0],'r') as read_script_fd:
+ for line in read_script_fd.readlines():
+ if line.startswith('exec') or line.startswith('sugar-activity'):
+ pass
+ else:
+ write_script_fd.write(line)
+ line = 'export -p > %s_env\n'%target
+ write_script_fd.write(line) #write the environment variables to another file
+ write_script_fd.close()
+
+ os.chmod(target,0755)
+ os.system(target)
+ _logger.debug('writing env script:%s'%target)
+ #read the environment back into the current process
+ with open('%s_env'%target,'r') as env_file:
+ env_dict = {}
+ for line in env_file.readlines():
+ if not line.startswith('export'):
+ pass
+ payload = line.split()[1]
+ pair = payload.split('=')
+ if len(pair)> 1:
+ key = pair[0]
+ value = pair[1]
+ env_dict[key] = value
+ _logger.debug('reading environment. %s => %s'%(key,value,))
+ os.environ = env_dict
+more_args = ['-a',bundle_name,'-b',bundle_id]
+sys.argv = cmd_args[:2] + more_args
+_logger.debug('about to call main.main() with args %r'%sys.argv)
+from sugar.activity import main
+
+main.main()
+
+
+
+
diff --git a/bin/sugar-launch b/bin/sugar-launch
new file mode 100755
index 0000000..8f2dec0
--- /dev/null
+++ b/bin/sugar-launch
@@ -0,0 +1,96 @@
+#!/usr/bin/env python
+
+# Copyright (C) 2007, Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import os
+import sys
+import dbus
+from optparse import OptionParser
+
+from sugar.activity import activityfactory
+from sugar.bundle.activitybundle import ActivityBundle
+
+usage = "usage: %prog [options] activity"
+parser = OptionParser(usage)
+parser.add_option("-d", "--debug", action="store_true", dest="debug",
+ help="launch activity inside gdb")
+(options, args) = parser.parse_args()
+
+if len(args) == 0:
+ path = os.environ('SUBAR_BUNDLE_PATH')
+ if not os.path.isdir(path):
+ print 'You need to specify the activity path on command line \nor set the SUGAR_BUNDLE_PATH environment variable.'
+ sys.exit(1)
+"""
+bus = dbus.SessionBus()
+proxy = bus.get_object('org.laptop.Shell', '/org/laptop/Shell')
+path = dbus.Interface(proxy, 'org.laptop.Shell').GetBundlePath(args[0])
+"""
+path = args[0]
+if not os.path.isdir(path):
+ path = os.path.join(os.environ('SUGAR_ACTIVITY_ROOT'),args[0])
+ if not os.path.isdir(path):
+ path = os.path.join(os.path.curdir(),args[0])
+ if not os.path.isdir(path):
+ print ' %s is not a valid Activity Directory.' % args[0]
+ sys.exit(1)
+
+activity = ActivityBundle(path)
+cmd_args = activityfactory.get_command(activity)
+
+def _which(exec_file):
+ if 'PATH' in os.environ:
+ envpath = os.environ['PATH']
+ else:
+ return None
+
+ for path in envpath.split(os.pathsep):
+ fullname = os.path.join(path, exec_file)
+ if os.path.exists(fullname):
+ return fullname
+
+ return None
+
+def _get_interpreter(exec_file):
+ if os.path.exists(exec_file):
+ abs_path = exec_file
+ else:
+ abs_path = _which(exec_file)
+ if not abs_path:
+ return exec_file
+
+ f = open(abs_path)
+ line = f.readline(100)
+ if line.startswith('#!'):
+ cmds = line[2:].strip().split(' ')
+ cmds.append(abs_path)
+
+ if '/usr/bin/env' in cmds:
+ cmds.remove('/usr/bin/env')
+
+ return cmds
+
+ return exec_file
+
+if options.debug:
+ act_args = cmd_args
+ cmd_args = ['gdb', '--args']
+ cmd_args.extend(_get_interpreter(act_args.pop(0)))
+ cmd_args.extend(act_args)
+
+os.execvpe(cmd_args[0], cmd_args, activityfactory.get_environment(activity))
+
diff --git a/bin/sugar-launch-path b/bin/sugar-launch-path
new file mode 100755
index 0000000..11f5ce5
--- /dev/null
+++ b/bin/sugar-launch-path
@@ -0,0 +1,134 @@
+#!/usr/bin/env python
+
+# Copyright (C) 2007, Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import os
+import sys
+import dbus
+from optparse import OptionParser
+import logging
+from sugar import logger
+#Get the standard logging directory.
+std_log_dir = logger.get_logs_dir()
+_logger = logging.getLogger('SugarLaunch')
+
+#First log handler: outputs to a file called 'VideoEdit.activity.log'
+file_handler = logging.FileHandler('/home/olpc/.sugar/default/logs/PyDebug.activity.log')
+file_formatter = logging.Formatter('%(name)s -- %(asctime)s %(funcName)s: %(lineno)d\n %(message)s\n')
+file_handler.setFormatter(file_formatter)
+_logger.addHandler(file_handler)
+_logger.setLevel(logging.DEBUG)
+
+#Second log handler: outputs to a the console, using a slightly different output structure
+console_handler = logging.StreamHandler()
+console_formatter = logging.Formatter('%(name)s %(levelname)s ||| %(message)s')
+console_handler.setFormatter(console_formatter)
+_logger.addHandler(console_handler)
+
+
+
+from sugar.activity import activityfactory
+from sugar.bundle.activitybundle import ActivityBundle
+
+usage = "usage: %prog [options] activity"
+parser = OptionParser(usage)
+parser.add_option("-d", "--debug", action="store_true", dest="debug",
+ help="launch activity inside gdb")
+(options, args) = parser.parse_args()
+
+if len(args) == 0:
+ path = os.environ('SUBAR_BUNDLE_PATH')
+ if not os.path.isdir(path):
+ print 'You need to specify the activity path on command line \nor set the SUGAR_BUNDLE_PATH environment variable.'
+ sys.exit(1)
+"""
+bus = dbus.SessionBus()
+proxy = bus.get_object('org.laptop.Shell', '/org/laptop/Shell')
+path = dbus.Interface(proxy, 'org.laptop.Shell').GetBundlePath(args[0])
+"""
+path = args[0]
+if not os.path.isdir(path):
+ path = os.path.join(os.environ('SUGAR_ACTIVITY_ROOT'),args[0])
+ if not os.path.isdir(path):
+ path = os.path.join(os.path.curdir(),args[0])
+ if not os.path.isdir(path):
+ print ' %s is not a valid Activity Directory.' % args[0]
+ sys.exit(1)
+
+os.chdir(path)
+activity = ActivityBundle(path)
+cmd_args = activityfactory.get_command(activity)
+
+def _which(exec_file):
+ if 'PATH' in os.environ:
+ envpath = os.environ['PATH']
+ else:
+ return None
+
+ for path in envpath.split(os.pathsep):
+ fullname = os.path.join(path, exec_file)
+ if os.path.exists(fullname):
+ return fullname
+
+ return None
+
+def _get_interpreter(exec_file):
+ if os.path.exists(exec_file):
+ abs_path = exec_file
+ else:
+ abs_path = _which(exec_file)
+ if not abs_path:
+ return exec_file
+
+ f = open(abs_path)
+ line = f.readline(100)
+ if line.startswith('#!'):
+ cmds = line[2:].strip().split(' ')
+ cmds.append(abs_path)
+
+ if '/usr/bin/env' in cmds:
+ cmds.remove('/usr/bin/env')
+
+ return cmds
+
+ return exec_file
+
+if options.debug:
+ act_args = cmd_args
+ cmd_args = ['gdb', '--args']
+ cmd_args.extend(_get_interpreter(act_args.pop(0)))
+ cmd_args.extend(act_args)
+
+info = activityfactory.get_environment(activity)
+#os.execvpe(cmd_args[0], cmd_args, activityfactory.get_environment(activity))
+_logger.debug("Command to execute:%s."%cmd_args[0])
+print("Command to execute:%s."%cmd_args[0])
+if not cmd_args[0].startswith('sugar-activity'):
+ for line in open(cmd_args[0],'r'):
+ if line.startswith('exec') or line.startswith('sugar-activity'):
+ cmd_args = line.split()
+ cmd_args.pop(0)
+#cmd_args.pop(0)
+cmd_args = cmd_args + ['-s',] #run the debugger in a single process
+sys.argv = cmd_args
+from sugar.activity import main
+
+main.main()
+
+
+
+
diff --git a/bin/sugar_start b/bin/sugar_start
new file mode 100755
index 0000000..7765ff1
--- /dev/null
+++ b/bin/sugar_start
@@ -0,0 +1,85 @@
+#!/usr/bin/env python
+
+# Copyright (C) 2007, Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import os
+import sys
+from optparse import OptionParser
+
+from sugar.activity import activityfactory
+from sugar.activity.registry import get_registry
+
+usage = "usage: %prog [options] activity"
+parser = OptionParser(usage)
+parser.add_option("-d", "--debug", action="store_true", dest="debug",
+ help="launch activity inside gdb")
+(options, args) = parser.parse_args()
+
+if len(args) == 0:
+ print 'You need to specify the activity name or part of it.'
+ sys.exit(1)
+
+registry = get_registry()
+activities = registry.find_activity(args[0])
+if len(activities) == 0:
+ print 'Activity not found.'
+
+activity = activities[0]
+cmd_args = activityfactory.get_command(activity)
+
+def _which(exec_file):
+ if 'PATH' in os.environ:
+ envpath = os.environ['PATH']
+ else:
+ return None
+
+ for path in envpath.split(os.pathsep):
+ fullname = os.path.join(path, exec_file)
+ if os.path.exists(fullname):
+ return fullname
+
+ return None
+
+def _get_interpreter(exec_file):
+ if os.path.exists(exec_file):
+ abs_path = exec_file
+ else:
+ abs_path = _which(exec_file)
+ if not abs_path:
+ return exec_file
+
+ f = open(abs_path)
+ line = f.readline(100)
+ if line.startswith('#!'):
+ cmds = line[2:].strip().split(' ')
+ cmds.append(abs_path)
+
+ if '/usr/bin/env' in cmds:
+ cmds.remove('/usr/bin/env')
+
+ return cmds
+
+ return exec_file
+
+if options.debug:
+ act_args = cmd_args
+ cmd_args = ['gdb', '--args']
+ cmd_args.extend(_get_interpreter(act_args.pop(0)))
+ cmd_args.extend(act_args)
+
+os.execvpe(cmd_args[0], cmd_args, activityfactory.get_environment(activity))
+
diff --git a/bin/sugarun b/bin/sugarun
new file mode 100755
index 0000000..c0b453d
--- /dev/null
+++ b/bin/sugarun
@@ -0,0 +1,160 @@
+#!/usr/bin/env python
+
+# Copyright (C) 2007, Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import os
+import sys
+import dbus
+from optparse import OptionParser
+import logging
+from sugar import logger
+from sugar import env
+
+#Get the standard logging directory.
+std_log_dir = logger.get_logs_dir()
+_logger = logging.getLogger('PyDebug')
+
+#First log handler: outputs to a file called 'VideoEdit.activity.log'
+file_handler = logging.FileHandler('/home/olpc/.sugar/default/logs/PyDebug.activity.log')
+file_formatter = logging.Formatter('%(name)s -- %(asctime)s %(funcName)s: %(lineno)d\n %(message)s\n')
+file_handler.setFormatter(file_formatter)
+_logger.addHandler(file_handler)
+_logger.setLevel(logging.DEBUG)
+
+#Second log handler: outputs to a the console, using a slightly different output structure
+console_handler = logging.StreamHandler()
+console_formatter = logging.Formatter('%(name)s %(levelname)s ||| %(message)s')
+console_handler.setFormatter(console_formatter)
+_logger.addHandler(console_handler)
+
+
+
+from sugar.activity import activityfactory
+from sugar.bundle.activitybundle import ActivityBundle
+
+usage = "usage: %prog [options] SUGAR-BUNDLE-PATH"
+parser = OptionParser(usage)
+parser.add_option("-d", "--debug", action="store_true", dest="debug",
+ help="launch activity inside gdb")
+(options, args) = parser.parse_args()
+
+if len(args) == 0:
+ path = os.environ('SUGAR_BUNDLE_PATH')
+ if not os.path.isdir(path):
+ print 'You need to specify the activity path on command line \nor set the SUGAR_BUNDLE_PATH environment variable.'
+ sys.exit(1)
+"""
+bus = dbus.SessionBus()
+proxy = bus.get_object('org.laptop.Shell', '/org/laptop/Shell')
+path = dbus.Interface(proxy, 'org.laptop.Shell').GetBundlePath(args[0])
+"""
+if os.getcwd().endswith(args[0]):
+ path = os.getcwd()
+else:
+ path = args[0]
+if not os.path.isdir(path):
+ path = os.path.join(os.environ['SUGAR_ACTIVITY_ROOT'],'data/pydebug',args[0])
+ if not os.path.isdir(path):
+ path = os.path.join(os.environ['SUGAR_ACTIVITY_ROOT'],'data/pydebug/playpen',args[0])
+ if not os.path.isdir(path):
+ path = os.path.join(os.getcwd(),args[0])
+ if not os.path.isdir(path):
+ print ' %s is not a valid Activity Directory.' % args[0]
+ sys.exit(1)
+path = os.path.abspath(path)
+_logger.debug('sugar_bundle_path set to %s'%path)
+os.chdir(path)
+os.environ['SUGAR_BUNDLE_PATH'] = path
+sys.path.insert(0,path)
+activity = ActivityBundle(path)
+cmd_args = activityfactory.get_command(activity)
+_logger.debug('cmd_args:%r'%cmd_args)
+bundle_name = activity.get_name()
+bundle_id = activity.get_bundle_id()
+
+#os.environ['SUGAR_BUNDLE_PATH'] = activity.get_path()
+
+#following will not work if storage system changes with new OS
+#required because debugger needs to be able to change home so that foreign apps will work
+activity_root = os.path.join('/home/olpc/.sugar/default/',bundle_id)
+os.environ['SUGAR_ACTIVITY_ROOT'] = activity_root
+_logger.debug('sugar_activity_root set to %s'%activity_root)
+def _which(exec_file):
+ if 'PATH' in os.environ:
+ envpath = os.environ['PATH']
+ else:
+ return None
+
+ for path in envpath.split(os.pathsep):
+ fullname = os.path.join(path, exec_file)
+ if os.path.exists(fullname):
+ return fullname
+
+ return None
+
+def _get_interpreter(exec_file):
+ if os.path.exists(exec_file):
+ abs_path = exec_file
+ else:
+ abs_path = _which(exec_file)
+ if not abs_path:
+ return exec_file
+
+ f = open(abs_path)
+ line = f.readline(100)
+ if line.startswith('#!'):
+ cmds = line[2:].strip().split(' ')
+ cmds.append(abs_path)
+
+ if '/usr/bin/env' in cmds:
+ cmds.remove('/usr/bin/env')
+
+ return cmds
+
+ return exec_file
+
+if options.debug:
+ act_args = cmd_args
+ cmd_args = ['gdb', '--args']
+ cmd_args.extend(_get_interpreter(act_args.pop(0)))
+ cmd_args.extend(act_args)
+
+#following is useful for its side-effects
+info = activityfactory.get_environment(activity)
+#os.execvpe(cmd_args[0], cmd_args, activityfactory.get_environment(activity))
+_logger.debug("Command to execute:%s."%cmd_args[0])
+print("Command to execute:%s."%cmd_args[0])
+if not cmd_args[0].startswith('sugar-activity'):
+ for line in open(cmd_args[0],'r'):
+ if line.startswith('exec') or line.startswith('sugar-activity'):
+ act_args = line.split()
+ act_args.pop(0)
+ else:
+ os.system(line)
+else:
+ pass
+ #cmd_args.pop(0)
+#more_args = ['-a',bundle_name,'-b',bundle_id]
+sys.argv = act_args[:2] +['-s',]+ cmd_args[1:]
+_logger.debug('about to call main.main() with args %r'%sys.argv)
+from sugar.activity import main
+
+main.main()
+
+
+
+
diff --git a/bkuppydb b/bkuppydb
new file mode 100755
index 0000000..5fec274
--- /dev/null
+++ b/bkuppydb
@@ -0,0 +1,3 @@
+#copy the remote pydebug tree to the git tree
+rsync -p -r root@10.4.75.99:/home/olpc/.sugar/default/org.laptop.PyDebug/data/pydebug/PyDebug.activity/ /home/ghunt/git/pydebug/PyDebug.activity
+
diff --git a/browser.py b/browser.py
new file mode 100644
index 0000000..66baec3
--- /dev/null
+++ b/browser.py
@@ -0,0 +1,64 @@
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import os
+import time
+import logging
+from gettext import gettext as _
+
+import gobject
+import gtk
+import hulahop
+import xpcom
+from xpcom.nsError import *
+from xpcom import components
+from xpcom.components import interfaces
+from webview import WebView
+
+from sugar.datastore import datastore
+from sugar import profile
+from sugar import env
+from sugar.activity import activity
+from sugar.graphics import style
+
+from progresslistener import ProgressListener
+
+_ZOOM_AMOUNT = 0.1
+
+class Browser(WebView):
+ def __init__(self):
+ WebView.__init__(self)
+
+ self.progress = ProgressListener()
+
+ def do_setup(self):
+ WebView.do_setup(self)
+ self.progress.setup(self)
+
+ def zoom_in(self):
+ contentViewer = self.doc_shell.queryInterface( \
+ interfaces.nsIDocShell).contentViewer
+ if contentViewer is not None:
+ markupDocumentViewer = contentViewer.queryInterface( \
+ interfaces.nsIMarkupDocumentViewer)
+ markupDocumentViewer.fullZoom += _ZOOM_AMOUNT
+
+ def zoom_out(self):
+ contentViewer = self.doc_shell.queryInterface( \
+ interfaces.nsIDocShell).contentViewer
+ if contentViewer is not None:
+ markupDocumentViewer = contentViewer.queryInterface( \
+ interfaces.nsIMarkupDocumentViewer)
+ markupDocumentViewer.fullZoom -= _ZOOM_AMOUNT
+
diff --git a/continue_debug.py b/continue_debug.py
new file mode 100644
index 0000000..9ca606d
--- /dev/null
+++ b/continue_debug.py
@@ -0,0 +1,138 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2007, Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+from __future__ import with_statement
+
+import os
+import sys
+
+#debug tool to analyze the activity environment
+# Initialize logging.
+import logging
+from pydebug_logging import _logger, log_environment
+_logger.setLevel(logging.DEBUG)
+
+from sugar.activity import activityfactory
+from sugar.bundle.activitybundle import ActivityBundle
+
+#define the interface with the GUI
+from Rpyc import *
+try:
+ c = SocketConnection('localhost')
+ db = c.modules.pydebug.pydebug_instance
+except AttributeError:
+ print('cannot connect to localhost')
+except e:
+ print(e[1])
+ assert False
+
+#define interface with the command line ipython instance
+from IPython.core import ipapi
+ip = ipapi.get()
+global __IPYTHON__
+try:
+ __IPYTHON__
+ print('IPTHON is defined')
+except:
+ __IPYTHON__ = ip
+o = ip.options
+o.xmode = db.traceback
+
+def edit_glue(self,filename,linenumber):
+ _logger.debug('position to editor file:%s. Line:%d'%(filename,linenumber))
+ip.set_hook('editor',edit_glue)
+
+def sync_called(self,filename,line,col):
+ print('synchronize called. file:%s. line:%s. Col:%s'%(filename,line,col))
+ip.set_hook('synchronize_with_editor',sync_called)
+
+#get the information about the Activity we are about to debug
+child_path = db.child_path
+_logger.debug('child path: %s'%child_path)
+print('child path starting activity: %s'%child_path)
+go_cmd = 'run -d -b %s %s'%(os.path.join(db.pydebug_path,'bin','start_debug.py'),child_path)
+_logger.debug('defining go: %s'%go_cmd)
+ip.user_ns['go'] = go_cmd
+_logger.debug('pydebug home: %s'%db.debugger_home)
+path = child_path
+pydebug_home = db.debugger_home
+os.environ['PYDEBUG_HOME'] = pydebug_home
+os.chdir(path)
+os.environ['SUGAR_BUNDLE_PATH'] = path
+_logger.debug('sugar_bundle_path set to %s'%path)
+
+#set up module search path
+sys.path.insert(0,path)
+activity = ActivityBundle(path)
+cmd_args = activityfactory.get_command(activity)
+_logger.debug('command args:%r'%cmd_args)
+bundle_name = activity.get_name()
+bundle_id = activity.get_bundle_id()
+
+#need to get activity root, but activity bases off of HOME which some applications need to change
+#following will not work if storage system changes with new OS
+#required because debugger needs to be able to change home so that foreign apps will work
+activity_root = os.path.join('/home/olpc/.sugar/default/',bundle_id)
+os.environ['SUGAR_ACTIVITY_ROOT'] = activity_root
+_logger.debug('sugar_activity_root set to %s'%activity_root)
+
+#following is useful for its side-effects
+info = activityfactory.get_environment(activity)
+
+_logger.debug("Command to execute:%s."%cmd_args[0])
+if not cmd_args[0].startswith('sugar-activity'):
+ target = os.path.join(pydebug_home,os.path.basename(cmd_args[0]))
+ with open(target,'w') as write_script_fd:
+ with open(cmd_args[0],'r') as read_script_fd:
+ for line in read_script_fd.readlines():
+ if line.startswith('exec') or line.startswith('sugar-activity'):
+ pass
+ else:
+ write_script_fd.write(line)
+ line = 'export -p > %s_env\n'%target
+ write_script_fd.write(line) #write the environment variables to another file
+ write_script_fd.close()
+
+ os.chmod(target,0755)
+ os.system(target)
+ _logger.debug('writing env script:%s'%target)
+ #read the environment back into the current process
+ with open('%s_env'%target,'r') as env_file:
+ env_dict = {}
+ for line in env_file.readlines():
+ if not line.startswith('export'):
+ pass
+ payload = line.split()[1]
+ pair = payload.split('=')
+ if len(pair)> 1:
+ key = pair[0]
+ value = pair[1]
+ env_dict[key] = value
+ _logger.debug('reading environment. %s => %s'%(key,value,))
+ os.environ = env_dict
+more_args = ['-a',bundle_name,'-b',bundle_id]
+sys.argv = cmd_args[:2] + more_args
+_logger.debug('about to call main.main() with args %r'%sys.argv)
+log_environment()
+
+from sugar.activity import main
+main.main()
+
+
+
+
diff --git a/datastoretree.py b/datastoretree.py
new file mode 100644
index 0000000..9cd80f4
--- /dev/null
+++ b/datastoretree.py
@@ -0,0 +1,228 @@
+#!/usr/bin/env python
+# Copyright (C) 2008, One Laptop Per Child
+#
+# This program is jobjectree software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import os, sys, time
+
+from sugar.datastore import datastore
+from sugar import profile
+from sugar import util
+
+from gettext import gettext as _
+
+#major packages
+import gtk
+import gtk.glade
+#import pydebug
+#from pydebug import pydebug_instance
+
+# Initialize logging.
+import logging
+from sugar import logger
+#Get the standard logging directory.
+std_log_dir = logger.get_logs_dir()
+_logger = logging.getLogger('PyDebug')
+
+class DataStoreTree():
+ column_names = [_('Name'), _('Size'), _('Last Changed')]
+
+ def __init__(self, parent, widget=None,wTree=None):
+ self.parent = parent
+ self.treeview = widget
+ self.wTree = wTree
+ self.init_model()
+ self.init_columns()
+ self.connect_object()
+ self.limit=10
+ self.journal_page_size =10
+ self.journal_page_num = 0
+ self.journal_max = 0
+ self.new_directory()
+ button = self.wTree.get_widget('from_journal')
+ button.set_tooltip_text(_('Load the selected Journal XO file to the debug workplace'))
+ button = self.wTree.get_widget('to_journal')
+ button.set_tooltip_text(_('Zip up all the files in your debug workplace and store them in the Journal'))
+
+
+ def connect_object(self, wTree=None):
+ mdict = {
+ 'younger_clicked_cb':self.newer_in_journal_cb,
+ 'older_clicked_cb':self.older_in_journal_cb,
+ 'from_journal_clicked_cb':self.load_from_journal_cb,
+ 'to_journal_clicked_cb':self.save_to_journal_cb ,
+ }
+ self.wTree.signal_autoconnect(mdict)
+
+ def init_model(self):
+ #plan for the store: pixbuf,title,size,last-updated,tooltip,jobject-id
+ self.journal_model = gtk.TreeStore(gtk.gdk.Pixbuf, str,str,str,str,str,str,str,str,str,str)
+ if not self.treeview:
+ self.treeview = gtk.TreeView()
+ self.treeview.set_model(self.journal_model)
+ self.treeview.show()
+ #self.treeview.has_tooltip = True
+ self.treeview.set_tooltip_column(10)
+ #self.treeview.connect('query-tooltip',self.display_tooltip)
+ self.show_hidden = False
+
+ def init_columns(self):
+ col = gtk.TreeViewColumn()
+ col.set_title(self.column_names[0])
+ render_pixbuf = gtk.CellRendererPixbuf()
+ col.pack_start(render_pixbuf, expand=False)
+ col.add_attribute(render_pixbuf, 'pixbuf', 0)
+ render_text = gtk.CellRendererText()
+ col.pack_start(render_text, expand=True)
+ col.add_attribute(render_text, 'text', 1)
+ col.set_fixed_width(20)
+ self.treeview.append_column(col)
+ cell = gtk.CellRendererText()
+ col = gtk.TreeViewColumn(self.column_names[1], cell)
+ col.add_attribute(cell, 'text', 2)
+ self.treeview.append_column(col)
+ cell = gtk.CellRendererText()
+ col = gtk.TreeViewColumn(self.column_names[2], cell)
+ col.add_attribute(cell, 'text', 3)
+ self.treeview.append_column(col)
+
+
+ def get_datastore_list(self, next=False):
+ dslist = []
+ """
+ if not next:
+ self.journal_page_num -= 1
+ else:
+ self.journal_page_num += 1
+ if self.journal_page_num < 0: self.journal_page_num = 0
+ if self.journal_max != 0:
+ if self.journal_page_num * self.journal_page_size >= self.journal_max:
+ self.journal_page_num -= 1
+ #_logger.debug('fetch datastore data. limit:%s. offset: %s'%(self.limit,self.journal_page_num * self.journal_page_size))
+ #(results,count)=datastore.find({'limit':self.limit,'offset':self.journal_page_num * self.journal_page_size})
+ """
+ results,count=datastore.find({'Activity':'org.laptop.PyDebug'})
+ if count < self.limit:
+ self.journal_max = self.journal_page_num * self.journal_page_size + count
+ _logger.debug( 'datastoretree-get_datastore_list: count= %s'%count)
+ keys = ('title','size','timestamp','activity','package','mime_type','file_path')
+ for jobject in results:
+ itemlist = [None,]
+ datastoredict=jobject.get_metadata().get_dictionary() #get the property dictionary
+ src = jobject.get_file_path() #returns the full path of the file
+ datastoredict['object_id'] = jobject.object_id
+ if src == '': #if null, there is no file related to this meta data
+ jobject.destroy()
+ continue #go get the next iterations
+ info = os.stat(src) #get the directory information about this file
+ #add in the info that we intend to use
+ datastoredict['size'] = info.st_size
+ datastoredict['file_path'] = src
+ for key in keys:
+ if datastoredict.has_key(key):
+ if key == 'timestamp':
+ pkg = time.strftime('%Y-%m-%d %H:%M:%S',time.gmtime(float(datastoredict[key])))
+ elif key == 'title':
+ pkg = datastoredict[key][:18]
+ else:
+ pkg = '%s'%(datastoredict[key])
+ else:
+ pkg = ''
+ itemlist.append(pkg)
+ itemlist.append(datastoredict['title'])
+ itemlist.append(jobject.object_id)
+ text = 'Mime_type: %s, Activity: %s, Package: %s'%(datastoredict.get('mime_type',''),
+ datastoredict.get('activity','').split('.')[-1:][0],
+ datastoredict.get('package',''))
+ itemlist.append(text)
+ #_logger.debug('journal tooltip:%s'%text)
+ dslist.append(itemlist)
+ jobject.destroy()
+ return dslist
+
+ def new_directory(self,piter = None, next=True):
+ journal_list = self.get_datastore_list(next)
+ for journal_selected_data in journal_list:
+ appended_iter = self.journal_model.append(piter, journal_selected_data )
+ model=self.journal_model
+ appended_path = model.get_path(appended_iter)
+
+ def file_pixbuf(self, filename):
+ folderpb = self.get_icon_pixbuf('STOCK_DIRECTORY')
+ filepb = self.get_icon_pixbuf('STOCK_FILE')
+ if os.path.isdir(filename):
+ pb = folderpb
+ else:
+ pb = filepb
+ return pb
+
+ def get_icon_pixbuf(self, stock):
+ return self.treeview.render_icon(stock_id=getattr(gtk, stock),
+ size=gtk.ICON_SIZE_MENU,
+ detail=None)
+
+ def get_treeview(self):
+ return self.treeview
+
+ def newer_in_journal_cb(self,button):
+ _logger.debug('younger call back')
+ self.get_datastore_list(next=False)
+
+ def older_in_journal_cb(self,button):
+ _logger.debug('older call back')
+ self.get_datastore_list(next=True)
+
+ def save_to_journal_cb(self,button):
+ self.parent.write_binary_to_datastore()
+
+ def load_from_journal_cb(self,button):
+ selection=self.treeview.get_selection()
+ (model,iter)=selection.get_selected()
+ if iter == None:
+ self.parent.alert(_('Must select Journal item to Load'))
+ return
+ object_id = model.get(iter,9)
+ _logger.debug('object id %s from journal'%object_id)
+ self.parent.try_to_load_from_journal(object_id)
+
+ def datastore_row_activated_cb(self):
+ self.load_from_journal_cb()
+
+ def display_tooltip(self, widget,x,y,mode,tooltip):
+ _logger.debug('in display_tooltip')
+ tooltip.show()
+ return True
+
+def main():
+ gtk.main()
+
+if __name__ == "__main__":
+ # Create a new window
+ """window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ window.set_size_request(400, 300)
+ window.show()
+ """
+ wTree=gtk.glade.XML('/home/olpc/Activities/PyDebug.activity/project.glade')
+ top = wTree.get_widget('toplevel')
+ top.show()
+ file_system = wTree.get_widget('journal')
+
+ #pydebug.Activity.set_canvas(pydebug_instance,self.contents)
+ flcdexample = DataStoreTree(None, file_system,wTree)
+
+ #flcdexample.connect_object(mdict)
+ main()
+
+
diff --git a/db/shadowhist/07 b/db/shadowhist/07
new file mode 100644
index 0000000..d5d79e0
--- /dev/null
+++ b/db/shadowhist/07
@@ -0,0 +1,5 @@
+(dp1
+Vo=-ip.options
+p2
+I22
+s. \ No newline at end of file
diff --git a/db/shadowhist/0a b/db/shadowhist/0a
new file mode 100644
index 0000000..9d19941
--- /dev/null
+++ b/db/shadowhist/0a
@@ -0,0 +1,5 @@
+(dp1
+Vlist = dm.list_displays()
+p2
+I48
+s. \ No newline at end of file
diff --git a/db/shadowhist/0e b/db/shadowhist/0e
new file mode 100644
index 0000000..48afa4f
--- /dev/null
+++ b/db/shadowhist/0e
@@ -0,0 +1,8 @@
+(dp1
+Vinfo(gtk.gdk)
+p2
+I26
+sVp go
+p3
+I4
+s. \ No newline at end of file
diff --git a/db/shadowhist/15 b/db/shadowhist/15
new file mode 100644
index 0000000..b3b5991
--- /dev/null
+++ b/db/shadowhist/15
@@ -0,0 +1,5 @@
+(dp1
+Vgb
+p2
+I19
+s. \ No newline at end of file
diff --git a/db/shadowhist/18 b/db/shadowhist/18
new file mode 100644
index 0000000..dcb830d
--- /dev/null
+++ b/db/shadowhist/18
@@ -0,0 +1,5 @@
+(dp1
+Vgo
+p2
+I1
+s. \ No newline at end of file
diff --git a/db/shadowhist/1c b/db/shadowhist/1c
new file mode 100644
index 0000000..9576f47
--- /dev/null
+++ b/db/shadowhist/1c
@@ -0,0 +1,5 @@
+(dp1
+Vdl = dm.list_displays()
+p2
+I36
+s. \ No newline at end of file
diff --git a/db/shadowhist/1e b/db/shadowhist/1e
new file mode 100644
index 0000000..5c6a7ee
--- /dev/null
+++ b/db/shadowhist/1e
@@ -0,0 +1,5 @@
+(dp1
+Vdisplay = dm.get_display()
+p2
+I40
+s. \ No newline at end of file
diff --git a/db/shadowhist/20 b/db/shadowhist/20
new file mode 100644
index 0000000..451cc50
--- /dev/null
+++ b/db/shadowhist/20
@@ -0,0 +1,5 @@
+(dp1
+Vo.xmode='Plain'
+p2
+I18
+s. \ No newline at end of file
diff --git a/db/shadowhist/2a b/db/shadowhist/2a
new file mode 100644
index 0000000..e7d47f5
--- /dev/null
+++ b/db/shadowhist/2a
@@ -0,0 +1,5 @@
+(dp1
+Vll
+p2
+I2
+s. \ No newline at end of file
diff --git a/db/shadowhist/2b b/db/shadowhist/2b
new file mode 100644
index 0000000..d9ad3c4
--- /dev/null
+++ b/db/shadowhist/2b
@@ -0,0 +1,5 @@
+(dp1
+Vfrom apihelper import info
+p2
+I28
+s. \ No newline at end of file
diff --git a/db/shadowhist/2d b/db/shadowhist/2d
new file mode 100644
index 0000000..c1365f5
--- /dev/null
+++ b/db/shadowhist/2d
@@ -0,0 +1,5 @@
+(dp1
+Vo = _ip.options
+p2
+I15
+s. \ No newline at end of file
diff --git a/db/shadowhist/3c b/db/shadowhist/3c
new file mode 100644
index 0000000..baebc79
--- /dev/null
+++ b/db/shadowhist/3c
@@ -0,0 +1,5 @@
+(dp1
+Vdir(gtk.gdk)
+p2
+I25
+s. \ No newline at end of file
diff --git a/db/shadowhist/3d b/db/shadowhist/3d
new file mode 100644
index 0000000..df1d0ec
--- /dev/null
+++ b/db/shadowhist/3d
@@ -0,0 +1,5 @@
+(dp1
+Vpinfo(gtk.gdk)
+p2
+I27
+s. \ No newline at end of file
diff --git a/db/shadowhist/3f b/db/shadowhist/3f
new file mode 100644
index 0000000..50ea8bb
--- /dev/null
+++ b/db/shadowhist/3f
@@ -0,0 +1,5 @@
+(dp1
+Vdm?
+p2
+I32
+s. \ No newline at end of file
diff --git a/db/shadowhist/42 b/db/shadowhist/42
new file mode 100644
index 0000000..90e084f
--- /dev/null
+++ b/db/shadowhist/42
@@ -0,0 +1,5 @@
+(dp1
+Vdl
+p2
+I35
+s. \ No newline at end of file
diff --git a/db/shadowhist/49 b/db/shadowhist/49
new file mode 100644
index 0000000..1ca0e40
--- /dev/null
+++ b/db/shadowhist/49
@@ -0,0 +1,5 @@
+(dp1
+Vo.xmode=
+p2
+I17
+s. \ No newline at end of file
diff --git a/db/shadowhist/4a b/db/shadowhist/4a
new file mode 100644
index 0000000..bdfeaeb
--- /dev/null
+++ b/db/shadowhist/4a
@@ -0,0 +1,5 @@
+(dp1
+Vdi = list[0]
+p2
+I50
+s. \ No newline at end of file
diff --git a/db/shadowhist/4d b/db/shadowhist/4d
new file mode 100644
index 0000000..429ddc6
--- /dev/null
+++ b/db/shadowhist/4d
@@ -0,0 +1,11 @@
+(dp1
+Vp o.xmode
+p2
+I23
+sVdl = dm.list_displays(dm)
+p3
+I44
+sVimport gtk
+p4
+I29
+s. \ No newline at end of file
diff --git a/db/shadowhist/50 b/db/shadowhist/50
new file mode 100644
index 0000000..f475545
--- /dev/null
+++ b/db/shadowhist/50
@@ -0,0 +1,5 @@
+(dp1
+Vdm = gtk.gdk.DisplayManager
+p2
+I30
+s. \ No newline at end of file
diff --git a/db/shadowhist/51 b/db/shadowhist/51
new file mode 100644
index 0000000..00d38e6
--- /dev/null
+++ b/db/shadowhist/51
@@ -0,0 +1,5 @@
+(dp1
+Vdi.get_n_screens()
+p2
+I51
+s. \ No newline at end of file
diff --git a/db/shadowhist/59 b/db/shadowhist/59
new file mode 100644
index 0000000..1244ead
--- /dev/null
+++ b/db/shadowhist/59
@@ -0,0 +1,11 @@
+(dp1
+Vbundle_id
+p2
+I11
+sVlen(list)
+p3
+I49
+sVdm.list_displays?
+p4
+I37
+s. \ No newline at end of file
diff --git a/db/shadowhist/5a b/db/shadowhist/5a
new file mode 100644
index 0000000..3d5c8bf
--- /dev/null
+++ b/db/shadowhist/5a
@@ -0,0 +1,5 @@
+(dp1
+Vgb\u005C
+p2
+I20
+s. \ No newline at end of file
diff --git a/db/shadowhist/6c b/db/shadowhist/6c
new file mode 100644
index 0000000..ffc3417
--- /dev/null
+++ b/db/shadowhist/6c
@@ -0,0 +1,5 @@
+(dp1
+Vlist
+p2
+I10
+s. \ No newline at end of file
diff --git a/db/shadowhist/70 b/db/shadowhist/70
new file mode 100644
index 0000000..be8bf56
--- /dev/null
+++ b/db/shadowhist/70
@@ -0,0 +1,5 @@
+(dp1
+Vdl = dm.list_displays(':0.0')
+p2
+I43
+s. \ No newline at end of file
diff --git a/db/shadowhist/78 b/db/shadowhist/78
new file mode 100644
index 0000000..72dc2cd
--- /dev/null
+++ b/db/shadowhist/78
@@ -0,0 +1,5 @@
+(dp1
+Vdebug
+p2
+I7
+s. \ No newline at end of file
diff --git a/db/shadowhist/79 b/db/shadowhist/79
new file mode 100644
index 0000000..9cc19eb
--- /dev/null
+++ b/db/shadowhist/79
@@ -0,0 +1,5 @@
+(dp1
+Vdir(o)
+p2
+I14
+s. \ No newline at end of file
diff --git a/db/shadowhist/7c b/db/shadowhist/7c
new file mode 100644
index 0000000..a14b1a4
--- /dev/null
+++ b/db/shadowhist/7c
@@ -0,0 +1,5 @@
+(dp1
+Vdir(dm)
+p2
+I33
+s. \ No newline at end of file
diff --git a/db/shadowhist/7e b/db/shadowhist/7e
new file mode 100644
index 0000000..8d809b5
--- /dev/null
+++ b/db/shadowhist/7e
@@ -0,0 +1,8 @@
+(dp1
+Vdisplay = gtk.gdk.get_display()
+p2
+I41
+sVchild_path
+p3
+I9
+s. \ No newline at end of file
diff --git a/db/shadowhist/89 b/db/shadowhist/89
new file mode 100644
index 0000000..bf2d3b1
--- /dev/null
+++ b/db/shadowhist/89
@@ -0,0 +1,5 @@
+(dp1
+Ved
+p2
+I21
+s. \ No newline at end of file
diff --git a/db/shadowhist/8f b/db/shadowhist/8f
new file mode 100644
index 0000000..0438e99
--- /dev/null
+++ b/db/shadowhist/8f
@@ -0,0 +1,5 @@
+(dp1
+Vdm??
+p2
+I31
+s. \ No newline at end of file
diff --git a/db/shadowhist/97 b/db/shadowhist/97
new file mode 100644
index 0000000..8b21754
--- /dev/null
+++ b/db/shadowhist/97
@@ -0,0 +1,5 @@
+(dp1
+Vimport gtk.gdk
+p2
+I24
+s. \ No newline at end of file
diff --git a/db/shadowhist/9f b/db/shadowhist/9f
new file mode 100644
index 0000000..da84f63
--- /dev/null
+++ b/db/shadowhist/9f
@@ -0,0 +1,5 @@
+(dp1
+Vdl = dm.list_displays
+p2
+I34
+s. \ No newline at end of file
diff --git a/db/shadowhist/af b/db/shadowhist/af
new file mode 100644
index 0000000..2bbcabe
--- /dev/null
+++ b/db/shadowhist/af
@@ -0,0 +1,5 @@
+(dp1
+Vgob
+p2
+I6
+s. \ No newline at end of file
diff --git a/db/shadowhist/b0 b/db/shadowhist/b0
new file mode 100644
index 0000000..c744ac9
--- /dev/null
+++ b/db/shadowhist/b0
@@ -0,0 +1,5 @@
+(dp1
+Vhist
+p2
+I39
+s. \ No newline at end of file
diff --git a/db/shadowhist/b9 b/db/shadowhist/b9
new file mode 100644
index 0000000..ddd3e98
--- /dev/null
+++ b/db/shadowhist/b9
@@ -0,0 +1,5 @@
+(dp1
+Vbundle_name
+p2
+I12
+s. \ No newline at end of file
diff --git a/db/shadowhist/c0 b/db/shadowhist/c0
new file mode 100644
index 0000000..b7a67a9
--- /dev/null
+++ b/db/shadowhist/c0
@@ -0,0 +1,5 @@
+(dp1
+Vstr(display)
+p2
+I42
+s. \ No newline at end of file
diff --git a/db/shadowhist/cb b/db/shadowhist/cb
new file mode 100644
index 0000000..258791f
--- /dev/null
+++ b/db/shadowhist/cb
@@ -0,0 +1,5 @@
+(dp1
+Vwho
+p2
+I8
+s. \ No newline at end of file
diff --git a/db/shadowhist/d3 b/db/shadowhist/d3
new file mode 100644
index 0000000..d7553f9
--- /dev/null
+++ b/db/shadowhist/d3
@@ -0,0 +1,5 @@
+(dp1
+Vo.xmode
+p2
+I16
+s. \ No newline at end of file
diff --git a/db/shadowhist/dd b/db/shadowhist/dd
new file mode 100644
index 0000000..c379cbe
--- /dev/null
+++ b/db/shadowhist/dd
@@ -0,0 +1,5 @@
+(dp1
+Vo=_ip.options
+p2
+I13
+s. \ No newline at end of file
diff --git a/db/shadowhist/e5 b/db/shadowhist/e5
new file mode 100644
index 0000000..00718ff
--- /dev/null
+++ b/db/shadowhist/e5
@@ -0,0 +1,5 @@
+(dp1
+Vhist 1-
+p2
+I45
+s. \ No newline at end of file
diff --git a/db/shadowhist/e6 b/db/shadowhist/e6
new file mode 100644
index 0000000..6ee5fe1
--- /dev/null
+++ b/db/shadowhist/e6
@@ -0,0 +1,4 @@
+(dp1
+Vg
+I52
+s. \ No newline at end of file
diff --git a/db/shadowhist/e9 b/db/shadowhist/e9
new file mode 100644
index 0000000..87216f4
--- /dev/null
+++ b/db/shadowhist/e9
@@ -0,0 +1,5 @@
+(dp1
+Vmacro
+p2
+I3
+s. \ No newline at end of file
diff --git a/db/shadowhist/ef b/db/shadowhist/ef
new file mode 100644
index 0000000..a8ea40d
--- /dev/null
+++ b/db/shadowhist/ef
@@ -0,0 +1,5 @@
+(dp1
+Vdm = gtk.gdk.DisplayManager()
+p2
+I47
+s. \ No newline at end of file
diff --git a/db/shadowhist/f5 b/db/shadowhist/f5
new file mode 100644
index 0000000..8222bd7
--- /dev/null
+++ b/db/shadowhist/f5
@@ -0,0 +1,5 @@
+(dp1
+Vdm.list_displays??
+p2
+I38
+s. \ No newline at end of file
diff --git a/db/shadowhist/f8 b/db/shadowhist/f8
new file mode 100644
index 0000000..5d57685
--- /dev/null
+++ b/db/shadowhist/f8
@@ -0,0 +1,5 @@
+(dp1
+Vhist 10
+p2
+I46
+s. \ No newline at end of file
diff --git a/db/shadowhist/f9 b/db/shadowhist/f9
new file mode 100644
index 0000000..021d40a
--- /dev/null
+++ b/db/shadowhist/f9
@@ -0,0 +1,5 @@
+(dp1
+Vp gob
+p2
+I5
+s. \ No newline at end of file
diff --git a/db/shadowhist_idx b/db/shadowhist_idx
new file mode 100644
index 0000000..b917ad3
--- /dev/null
+++ b/db/shadowhist_idx
@@ -0,0 +1,2 @@
+I53
+. \ No newline at end of file
diff --git a/examples/HelloWorld.activity/HelloWorldActivity.py b/examples/HelloWorld.activity/HelloWorldActivity.py
new file mode 100644
index 0000000..bf73963
--- /dev/null
+++ b/examples/HelloWorld.activity/HelloWorldActivity.py
@@ -0,0 +1,40 @@
+from sugar.activity import activity
+import logging
+
+import sys, os
+import gtk
+
+class HelloWorldActivity(activity.Activity):
+ def hello(self, widget, data=None):
+ logging.info('Hello World')
+
+ def __init__(self, handle):
+ print "running activity init", handle
+ activity.Activity.__init__(self, handle)
+ print "activity running"
+
+ self.set_title('Hello World')
+
+ # Creates the Toolbox. It contains the Activity Toolbar, which is the
+ # bar that appears on every Sugar window and contains essential
+ # functionalities, such as the 'Collaborate' and 'Close' buttons.
+ toolbox = activity.ActivityToolbox(self)
+ self.set_toolbox(toolbox)
+ toolbox.show()
+
+ # Creates a new button with the label "Hello World".
+ self.button = gtk.Button("Hello World")
+
+ # When the button receives the "clicked" signal, it will call the
+ # function hello() passing it None as its argument. The hello()
+ # function is defined above.
+ self.button.connect("clicked", self.hello, None)
+
+ # Set the button to be our canvas. The canvas is the main section of
+ # every Sugar Window. It fills all the area below the toolbox.
+ self.set_canvas(self.button)
+
+ # The final step is to display this newly created widget.
+ self.button.show()
+
+ print "AT END OF THE CLASS"
diff --git a/examples/HelloWorld.activity/MANIFEST b/examples/HelloWorld.activity/MANIFEST
new file mode 100644
index 0000000..5ce3fa1
--- /dev/null
+++ b/examples/HelloWorld.activity/MANIFEST
@@ -0,0 +1,4 @@
+setup.py
+HelloWorldActivity.py
+activity/activity.info
+activity/activity-helloworld.svg
diff --git a/examples/HelloWorld.activity/activity/activity-helloworld.svg b/examples/HelloWorld.activity/activity/activity-helloworld.svg
new file mode 100644
index 0000000..b9278b0
--- /dev/null
+++ b/examples/HelloWorld.activity/activity/activity-helloworld.svg
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
+ <!ENTITY fill_color "#FFFFFF">
+ <!ENTITY stroke_color "#000000">
+]>
+<svg xmlns="http://www.w3.org/2000/svg" width="50" height="50">
+<rect x="1" y="1" width="48" height="48" style="fill:&fill_color;;stroke:&stroke_color;;stroke-width:2"/>
+</svg>
diff --git a/examples/HelloWorld.activity/activity/activity.info b/examples/HelloWorld.activity/activity/activity.info
new file mode 100644
index 0000000..d44edf5
--- /dev/null
+++ b/examples/HelloWorld.activity/activity/activity.info
@@ -0,0 +1,7 @@
+[Activity]
+name = HelloWorld
+service_name = com.ywwg.HelloWorldActivity
+class = HelloWorldActivity.HelloWorldActivity
+icon = activity-helloworld
+activity_version = 1
+show_launcher = yes
diff --git a/examples/HelloWorld.activity/setup.py b/examples/HelloWorld.activity/setup.py
new file mode 100755
index 0000000..6ea61a6
--- /dev/null
+++ b/examples/HelloWorld.activity/setup.py
@@ -0,0 +1,3 @@
+#!/usr/bin/python
+from sugar.activity import bundlebuilder
+bundlebuilder.start()
diff --git a/examples/bundle-2.xo b/examples/bundle-2.xo
new file mode 100644
index 0000000..c715ac1
--- /dev/null
+++ b/examples/bundle-2.xo
Binary files differ
diff --git a/filetree.py b/filetree.py
new file mode 100644
index 0000000..8d23911
--- /dev/null
+++ b/filetree.py
@@ -0,0 +1,221 @@
+#!/usr/bin/env python
+# Copyright (C) 2008, One Laptop Per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import os, sys, time
+
+from gettext import gettext as _
+
+#major packages
+import gtk
+import gtk.glade
+#import pydebug
+#from pydebug import pydebug_instance
+
+class FileTree():
+ column_names = [_('Name'), _('Size'), _('Last Changed')]
+
+ def __init__(self,parent,widget=None,wTree=None):
+ self.parent = parent
+ self.treeview = widget
+ self.wTree = wTree
+ self.init_model()
+ self.init_columns()
+ self.connect_object()
+ self.path = None
+
+ def connect_object(self, wTree=None): #caller should over-ride this
+ """if wTree:
+ self.wTree=wTree
+ if self.wTree:"""
+ mdict = {
+ 'file_system_row_selected_cb':self.file_system_row_selected_cb,
+ 'file_system_row_activated_cb':self.file_system_row_activated_cb,
+ 'file_system_toggle_cursor_row_cb':self.file_system_toggle_cursor_row_cb,
+ }
+ self.wTree.signal_autoconnect(mdict)
+
+
+ def init_model(self):
+ self.ft_model = gtk.TreeStore(gtk.gdk.Pixbuf, str,str,str,str)
+ if not self.treeview:
+ self.treeview = gtk.TreeView()
+ self.treeview.set_model(self.ft_model)
+ self.treeview.show()
+ self.show_hidden = False
+
+ def init_columns(self):
+ col = gtk.TreeViewColumn()
+ col.set_title(self.column_names[0])
+ render_pixbuf = gtk.CellRendererPixbuf()
+ col.pack_start(render_pixbuf, expand=False)
+ col.add_attribute(render_pixbuf, 'pixbuf', 0)
+ render_text = gtk.CellRendererText()
+ col.pack_start(render_text, expand=True)
+ col.add_attribute(render_text, 'text', 1)
+ self.treeview.append_column(col)
+ cell = gtk.CellRendererText()
+ col = gtk.TreeViewColumn(self.column_names[1], cell)
+ col.add_attribute(cell, 'text', 2)
+ self.treeview.append_column(col)
+ cell = gtk.CellRendererText()
+ col = gtk.TreeViewColumn(self.column_names[2], cell)
+ col.add_attribute(cell, 'text', 3)
+ self.treeview.append_column(col)
+ self.treeview.show()
+
+
+ def get_filenames_list(self, dname=None, show_hidden=False):
+ if not dname:
+ self.dirname = os.path.expanduser('~')
+ else:
+ self.dirname = os.path.abspath(dname)
+ if not os.path.isdir(self.dirname):
+ return None
+ files = [f for f in os.listdir(self.dirname) if f[0] <> '.' or show_hidden]
+ files.sort()
+ #if not show_hidden: files = ['..'] + files
+ return files
+
+ def new_directory(self,fullpath=None,piter=None):
+ dirlist = self.get_filenames_list(fullpath)
+ if not dirlist: return
+ for file in dirlist:
+ if file.endswith('.pyc'): continue
+ if file.endswith('~'): continue
+ fullname = os.path.join(self.dirname,file)
+ if len(file)>16:
+ short_file = file[:10] + '...' + file[-5:]
+ else: short_file = file
+ self.ft_model.append(piter,[self.file_pixbuf(fullname),short_file,
+ self.file_size(fullname),self.file_last_changed(fullname),
+ fullname,] )
+ if piter:
+ tvpath = self.ft_model.get_path(piter)
+ if tvpath:
+ self.treeview.expand_row(tvpath,False)
+
+ def set_file_sys_root(self,root):
+ self.file_sys_root = root
+ self.dirname = root
+ self.ft_model.clear()
+ self.new_directory(root)
+ #self.current_citer = self.ft_model.append(None,[None,os.path.basename(self.file_sys_root),
+ #None,None,self.file_sys_root,])
+
+ def file_system_row_activated_cb(self,widget,iter=None,path=None):
+ selection=widget.get_selection()
+ (model,iter)=selection.get_selected()
+ childiter = model.iter_children(iter)
+ if childiter != None: #there are children
+ childpath = model.get_path(childiter)
+ if self.treeview.row_expanded(childpath):
+ self.treeview.collapse_row(model.get_path(iter))
+ else:
+ self.treeview.expand_row(model.get_path(iter),False)
+ return
+ fullpath = model.get(iter,4)
+ self.new_directory(fullpath[0],iter)
+
+ def file_system_toggle_cursor_row_cb(self,widget,iter=None,path=None):
+ selection=widget.get_selection()
+ (model,iter)=selection.get_selected()
+ childiter = model.iter_children(iter)
+ if childiter != None: #there are children
+ childpath = model.get_path(childiter)
+ if self.treeview.row_expanded(childpath):
+ self.treeview.collapse_row(model.get_path(iter))
+ else:
+ self.treeview.expand_row(model.get_path(iter),False)
+ return
+
+ def file_system_row_selected_cb(self,widget):
+ selection=widget.get_selection()
+ (model,iter)=selection.get_selected()
+ fullpath = model.get(iter,4)
+ if fullpath[0].endswith('.activity'):
+ self.parent.child_path = fullpath[0]
+ self.parent.read_activity_info()
+
+ def position_to(self,fullpath):
+ self.iter = None
+ self.ft_model.foreach(self.fn_compare,fullpath)
+ if self.iter != None:
+ self.path = self.ft_model.get_path(self.iter)
+ self.treeview.scroll_to_cell(self.path,use_align=True,row_align=0.2)
+
+ def position_recent(self,path = None):
+ if not path: self.path = path
+ if self.path:
+ self.treeview.scroll_to_cell(self.path,use_align=True,row_align=0.2)
+
+
+ def fn_compare(self,model,path,iter,fullpath):
+ if model.get(iter,4) == fullpath:
+ self.iter = iter
+ return True
+ return False
+
+ def file_pixbuf(self, filename):
+ folderpb = self.get_icon_pixbuf('STOCK_DIRECTORY')
+ filepb = self.get_icon_pixbuf('STOCK_FILE')
+ if os.path.isdir(filename):
+ pb = folderpb
+ else:
+ pb = filepb
+ return pb
+
+ def get_icon_pixbuf(self, stock):
+ return self.treeview.render_icon(stock_id=getattr(gtk, stock),
+ size=gtk.ICON_SIZE_MENU,
+ detail=None)
+
+ def file_size(self, filename):
+ filestat = os.stat(filename)
+ return filestat.st_size
+
+
+ def file_last_changed(self, filename):
+ filestat = os.stat(filename)
+ rtn = time.strftime('%Y-%m-%d %H:%M:%S',time.gmtime(filestat.st_mtime))
+ return rtn
+
+ def get_treeview(self):
+ return self.treeview
+
+
+def main():
+ gtk.main()
+
+if __name__ == "__main__":
+ # Create a new window
+ """window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ window.set_size_request(400, 300)
+ window.show()
+ """
+ wTree=gtk.glade.XML('/home/ghunt/PyDebugger/project.glade')
+ top = wTree.get_widget('toplevel')
+ top.show()
+ file_system = wTree.get_widget('file_system')
+
+ #pydebug.Activity.set_canvas(pydebug_instance,self.contents)
+ flcdexample = FileTree(file_system,wTree)
+
+ #flcdexample.connect_object(mdict)
+ flcdexample.set_file_sys_root('/home/ghunt')
+ main()
+
+
diff --git a/git/pippy-activity b/git/pippy-activity
new file mode 160000
+Subproject 8e20319a883c8afb5ccfdddde326246e8961f0d
diff --git a/help/ActivityBook/ActivitiesGuideSugar/AddRefinements b/help/ActivityBook/ActivitiesGuideSugar/AddRefinements
new file mode 100644
index 0000000..23297c9
--- /dev/null
+++ b/help/ActivityBook/ActivitiesGuideSugar/AddRefinements
@@ -0,0 +1,917 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html>
+ <head>
+ <title>ActivitiesGuideSugar (en)</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <!--
+ <link rel="alternate" type="application/rss+xml" title="RSS Feed" href="WebRss.html" />
+ -->
+ <link rel="icon" href="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/fl2.ico" type="image/x-icon" /> <link rel="shortcut icon" href="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/fl2.ico" type="image/x-icon" />
+ <link rel=StyleSheet href="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/typography.css" type="text/css" media="screen">
+<style>
+#index {
+ color: #ff7f00;
+ font-family: trebuchet,sans-serif;
+ font-size: 10px;
+ line-height:11px;
+}
+#index UL {
+ width: 159px;
+ list-style-type: None;
+ padding-left: 0px;
+ border: 14px solid #ff7f00;
+ background-color: #ff7f00;
+ margin: 0px 0px 0px 0px;
+ }
+#index LI {
+ padding-left: 0px;
+ padding-right: 10px;
+ padding-top: 4px;
+ padding-bottom: 4px;
+ color: #ffffff;
+ margin: 0px 0px 0px 0px;
+ background-color: #ff7f00;
+ border-top: 1px solid #ff7f00;
+ }
+#index LI:hover {
+ background-color: #F99B1C;
+}
+#index LI.heading {
+ background-color: #ff7f00;
+ color: #000000;
+ border-top:1px solid #FFE5CC;
+ padding-top: 7px;
+ font-weight: bold;
+}
+#index LI.title {
+ border-bottom: 2px solid #FFE5CC;
+ background-color: #ff7f00;
+ color: #FBF4E9;
+ font-weight: bolder;
+ font-size:10px;
+ line-height:18px;
+ padding-bottom: 40px;
+ }
+#index A {
+ text-decoration: none;
+ color: #FBF4E9;
+ font-weight: bold;
+}
+#ds-layout .imgcontainer {
+ position:relative;
+ }
+#ds-layout .caption {
+ position:relative;
+ bottom:1;
+ left:0;
+ text-align:center;
+ background:#ffe7cb;
+ width:100%;
+ opacity:.75;
+ filter:alpha(opacity=85);
+ color:#000;
+ font-style: italic;
+ font-size: 9px;
+ line-height:11px;
+ }
+</style>
+<script type="text/javascript">
+function addLoadEvent(func) {
+ var oldonload = window.onload;
+ if (typeof window.onload != 'function') {
+ window.onload = func;
+ } else {
+ window.onload = function() {
+ oldonload();
+ func();
+ }
+ }
+}
+
+function insertAfter(newElement,targetElement) {
+ var parent = targetElement.parentNode;
+ if (parent.lastChild == targetElement) {
+ parent.appendChild(newElement);
+ } else {
+ parent.insertBefore(newElement,targetElement.nextSibling);
+ }
+}
+
+function captionizeImages() {
+ if (!document.getElementsByTagName) return false;
+ if (!document.createElement) return false;
+ var images = document.getElementsByTagName("img");
+ if (images.length < 1) return false;
+ for (var i=0; i<images.length; i++) {
+ if (images[i].className != "non") {
+ var title = images[i].getAttribute("title");
+ var width = images[i].width;
+ var divCaption = document.createElement("div");
+ divCaption.className="caption";
+ divCaption.style.width=width+'px';
+ if (title) divCaption.style.padding='2px 0px 3px 0px';
+ divCaption.style.display='block';
+ var divCaption_text = document.createTextNode(title);
+ divCaption.appendChild(divCaption_text);
+ var divContainer = document.createElement("div");
+ divContainer.className="imgcontainer";
+ if (title) divContainer.style.padding='0px 0px 10px 0px';
+ images[i].parentNode.insertBefore(divContainer,images[i]);
+ divContainer.appendChild(images[i]);
+ insertAfter(divCaption,images[i]);
+ }
+ }
+}
+//addLoadEvent(captionizeImages);
+
+function next () {
+var onode, otarget;
+onode=document.getElementById("AddRefinements");
+if (onode.id=="Credits") die;
+//alert (onode.id);
+onode=onode.nextSibling;
+if (onode.id=="heading") onode=onode.nextSibling;
+while (onode) {
+ //onode=onode.nextSibling;
+ if (onode.nodeType==1) {
+ //alert (onode.id);
+ otarget=onode;
+ break;
+ }
+ onode=onode.nextSibling;
+}
+if (otarget) {
+ //you actually have found one, and do something here
+ //alert(otarget.id + "\n" + otarget.tagName); //just to verify
+ top.location = "/ActivitiesGuideSugar/" + otarget.id;
+} else {
+ //you don't find one
+//alert("nada" + otarget.id);
+}
+}
+
+function previous () {
+var onode, otarget;
+onode=document.getElementById("AddRefinements");
+if (onode.id=="Introduction") die;
+//alert (onode.id);
+onode=onode.previousSibling;
+if (onode.id=="heading") onode=onode.previousSibling;
+if (onode.id=="title") die;
+while (onode) {
+ //onode=onode.previousSibling;
+ if (onode.nodeType==1) {
+ //alert (onode.id);
+ otarget=onode;
+ break;
+ }
+ onode=onode.previousSibling;
+}
+if (otarget) {
+ //you actually have found one, and do something here
+ //alert(otarget.id + "\n" + otarget.tagName); //just to verify
+ top.location = otarget.id;
+} else {
+ //you don't find one
+//alert("nada" + otarget.id);
+}
+}
+
+</script>
+ </head>
+ <body background="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/background.gif" style="margin:0;color:#000000;">
+<div id="home" style="position:absolute;left:0px;top:10px;">
+<a href="/"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/top_read_back.gif" border="0"></a>
+</div>
+<div id="index" style="position:absolute;left:0px;top:150px;">
+<ul>
+<li class="title">MAKING SUGAR ACTIVITIES</li><li id="Introduction"><a href="/ActivitiesGuideSugar/Introduction">INTRODUCTION</a></li><li id="WhatIsSugar"><a href="/ActivitiesGuideSugar/WhatIsSugar">WHAT IS SUGAR?</a></li><li id="WhatisanActivity"><a href="/ActivitiesGuideSugar/WhatisanActivity">WHAT IS A SUGAR ACTIVITY?</a></li><li id="NeedtoKnowWriteSugarActivity"><a href="/ActivitiesGuideSugar/NeedtoKnowWriteSugarActivity">WHAT DO I NEED TO KNOW TO WRITE A SUGAR ACTIVITY?</a></li><li id="SetUpDevEnvironment"><a href="/ActivitiesGuideSugar/SetUpDevEnvironment">SETTING UP A DEVELOPMENT ENVIRONMENT</a></li><li id="CreateFirstActivity"><a href="/ActivitiesGuideSugar/CreateFirstActivity">CREATING YOUR FIRST ACTIVITY</a></li><li id="StandalonePythonReadEtexts"><a href="/ActivitiesGuideSugar/StandalonePythonReadEtexts">MAKING A STANDALONE PYTHON PROGRAM</a></li><li id="InheritFromActivity"><a href="/ActivitiesGuideSugar/InheritFromActivity">INHERIT FROM SUGAR.ACTIVITY.ACTIVITY</a></li><li id="PackageTheActivity"><a href="/ActivitiesGuideSugar/PackageTheActivity">PACKAGE THE ACTIVITY</a></li><li id="AddRefinements"><a href="/ActivitiesGuideSugar/AddRefinements">ADD REFINEMENTS</a></li><li id="UsingVersionControl"><a href="/ActivitiesGuideSugar/UsingVersionControl">ADD YOUR ACTIVITY CODE TO VERSION CONTROL</a></li><li id="Credits"><a href="/ActivitiesGuideSugar/Credits">CREDITS</a></li></ul>
+</div>
+<div id="pdf" style="position:absolute;left:13px;top:190px;">
+<a href="/ActivitiesGuideSugar/FM_06Jan10.pdf"><img class ="non" src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/makepdf.gif" border=0></a>
+<!-- <a href="/ActivitiesGuideSugar/FM_ActivitiesGuideSugar_06Jan10.pdf"><img class ="non" src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/makepdf.gif" border=0></a> -->
+<a href="/ActivitiesGuideSugar/print"><img class="non" src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/viewprint.gif" border=0></a>
+</div>
+ <div style="position:absolute;left:240px;top:11px;">
+ <table id="ds-layout" cellpadding="0" cellspacing="0" sumtop:5px;mary="" style="table-layout:fixed;width:670px;border: 5px solid #666666;padding-right: 0px;padding-left: 0px;padding-bottom: 0px;padding-top: 0px;margin-left : 10px;margin-top:10;background:#FFF7F0;">
+ <tr>
+ <td width=100%>
+<div class="arrow" style="position:relative;left:10px;top:5px;width:50px;float:left;"><a href="#" onClick="previous();"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/lefttext.png" height=20></a></div>
+<div class="arrow" style="position:relative;left:528px;width:50px;top:5px;float:left;"><a href="#" onClick="next();"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/righttext.png" height=20></a></div>
+ <div class="ds-contentcontainer">
+ <div style="margin-left:1.2em;float:right">
+ <br>
+ <div class="huh" style='decoration:none;color:black;border:1;position:absolute;top:60px;left:502px;'>
+ <a href='http://www.flossmanuals.net/bin/view/ActivitiesGuideSugar/AddRefinements' onClick="alert('You will now be forwarded to the FLOSS Manuals editing interface')"><b><font color=#ff7f00><small>Edit this page</small></font></b></a> :: <a href='http://www.flossmanuals.net/bin/view/ActivitiesGuideSugar/FMComments?skin=floss2'><b><font color=#ff7f00><small>Discussion</small></font></b></a>
+ </div>
+ <h1>Adding Refinements
+</h1>
+<h2>Toolbars
+</h2>
+<p>It is a truth universally acknowledged that a first rate Activity needs good Toolbars.&nbsp; In this chapter we'll learn how to make them.&nbsp; We're going to put the toolbar classes in a separate file from the rest, because there are two styles of toolbar (old and new) and we may want to support both in our Activity.&nbsp; If we have two different files containing toolbar classes our code can decide at runtime which one it wants to use.&nbsp; For now, this code supports the old style, which works with every version of Sugar.&nbsp; The new style is currently only supported by <em>Sugar on a Stick. </em>
+</p>
+<p>Add a file to your Eric project called <strong>toolbar.py</strong> and copy this code into it:
+</p>
+<pre>from gettext import gettext as _
+import re
+
+import pango
+import gobject
+import gtk
+
+from sugar.graphics.toolbutton import ToolButton
+from sugar.activity import activity
+
+class ReadToolbar(gtk.Toolbar):
+ __gtype_name__ = 'ReadToolbar'
+
+ def __init__(self):
+ gtk.Toolbar.__init__(self)
+
+ self.back = ToolButton('go-previous')
+ self.back.set_tooltip(_('Back'))
+ self.back.props.sensitive = False
+ self.insert(self.back, -1)
+ self.back.show()
+
+ self.forward = ToolButton('go-next')
+ self.forward.set_tooltip(_('Forward'))
+ self.forward.props.sensitive = False
+ self.insert(self.forward, -1)
+ self.forward.show()
+
+ num_page_item = gtk.ToolItem()
+
+ self.num_page_entry = gtk.Entry()
+ self.num_page_entry.set_text('0')
+ self.num_page_entry.set_alignment(1)
+ self.num_page_entry.connect('insert-text',
+ self.num_page_entry_insert_text_cb)
+
+ self.num_page_entry.set_width_chars(4)
+
+ num_page_item.add(self.num_page_entry)
+ self.num_page_entry.show()
+
+ self.insert(num_page_item, -1)
+ num_page_item.show()
+
+ total_page_item = gtk.ToolItem()
+
+ self.total_page_label = gtk.Label()
+
+ label_attributes = pango.AttrList()
+ label_attributes.insert(pango.AttrSize(14000, 0, -1))
+ label_attributes.insert(pango.AttrForeground(65535, 65535, 65535, 0, -1))
+ self.total_page_label.set_attributes(label_attributes)
+
+ self.total_page_label.set_text(' / 0')
+ total_page_item.add(self.total_page_label)
+ self.total_page_label.show()
+
+ self.insert(total_page_item, -1)
+ total_page_item.show()
+
+ def num_page_entry_insert_text_cb(self, entry, text, length, position):
+ if not re.match('[0-9]', text):
+ entry.emit_stop_by_name('insert-text')
+ return True
+ return False
+
+ def update_nav_buttons(self):
+ current_page = self.current_page
+ self.back.props.sensitive = current_page &gt; 0
+ self.forward.props.sensitive = \
+ current_page &lt; self.total_pages - 1
+
+ self.num_page_entry.props.text = str(current_page + 1)
+ self.total_page_label.props.label = \
+ ' / ' + str(self.total_pages)
+
+ def set_total_pages(self, pages):
+ self.total_pages = pages
+
+ def set_current_page(self, page):
+ self.current_page = page
+ self.update_nav_buttons()
+
+class ViewToolbar(gtk.Toolbar):
+ __gtype_name__ = 'ViewToolbar'
+
+ __gsignals__ = {
+ 'needs-update-size': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE,
+ ([])),
+ 'go-fullscreen': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE,
+ ([]))
+ }
+
+ def __init__(self):
+ gtk.Toolbar.__init__(self)
+ self.zoom_out = ToolButton('zoom-out')
+ self.zoom_out.set_tooltip(_('Zoom out'))
+ self.insert(self.zoom_out, -1)
+ self.zoom_out.show()
+
+ self.zoom_in = ToolButton('zoom-in')
+ self.zoom_in.set_tooltip(_('Zoom in'))
+ self.insert(self.zoom_in, -1)
+ self.zoom_in.show()
+
+ spacer = gtk.SeparatorToolItem()
+ spacer.props.draw = False
+ self.insert(spacer, -1)
+ spacer.show()
+
+ self.fullscreen = ToolButton('view-fullscreen')
+ self.fullscreen.set_tooltip(_('Fullscreen'))
+ self.fullscreen.connect('clicked', self.fullscreen_cb)
+ self.insert(self.fullscreen, -1)
+ self.fullscreen.show()
+
+ def fullscreen_cb(self, button):
+ self.emit('go-fullscreen')
+</pre>
+<p>Create another file in the project named <strong>ReadEtextsActivity2.py</strong> and copy this code into it:
+</p>
+<pre>import sys
+import os
+import zipfile
+import pygtk
+import gtk
+import pango
+from sugar.activity import activity
+from sugar.graphics import style
+from toolbar import ReadToolbar, ViewToolbar
+from gettext import gettext as _
+
+page=0
+PAGE_SIZE = 45
+TOOLBAR_READ = 2
+
+class ReadEtextsActivity(activity.Activity):
+ def __init__(self, handle):
+ "The entry point to the Activity"
+ global page
+ activity.Activity.__init__(self, handle)
+
+ toolbox = activity.ActivityToolbox(self)
+ activity_toolbar = toolbox.get_activity_toolbar()
+ activity_toolbar.keep.props.visible = False
+ activity_toolbar.share.props.visible = False
+
+ self.edit_toolbar = activity.EditToolbar()
+ self.edit_toolbar.undo.props.visible = False
+ self.edit_toolbar.redo.props.visible = False
+ self.edit_toolbar.separator.props.visible = False
+ self.edit_toolbar.copy.set_sensitive(False)
+ self.edit_toolbar.copy.connect('clicked', self.edit_toolbar_copy_cb)
+ self.edit_toolbar.paste.props.visible = False
+ toolbox.add_toolbar(_('Edit'), self.edit_toolbar)
+ self.edit_toolbar.show()
+
+ self.read_toolbar = ReadToolbar()
+ toolbox.add_toolbar(_('Read'), self.read_toolbar)
+ self.read_toolbar.back.connect('clicked', self.go_back_cb)
+ self.read_toolbar.forward.connect('clicked', self.go_forward_cb)
+ self.read_toolbar.num_page_entry.connect('activate', \
+ self.num_page_entry_activate_cb)
+ self.read_toolbar.show()
+
+ self.view_toolbar = ViewToolbar()
+ toolbox.add_toolbar(_('View'), self.view_toolbar)
+ self.view_toolbar.connect('go-fullscreen',
+ self.view_toolbar_go_fullscreen_cb)
+ self.view_toolbar.zoom_in.connect('clicked', self.zoom_in_cb)
+ self.view_toolbar.zoom_out.connect('clicked', self.zoom_out_cb)
+ self.view_toolbar.show()
+
+ self.set_toolbox(toolbox)
+ toolbox.show()
+ self.scrolled_window = gtk.ScrolledWindow()
+ self.scrolled_window.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
+ self.scrolled_window.props.shadow_type = gtk.SHADOW_NONE
+
+ self.textview = gtk.TextView()
+ self.textview.set_editable(False)
+ self.textview.set_cursor_visible(False)
+ self.textview.set_left_margin(50)
+ self.textview.connect("key_press_event", self.keypress_cb)
+
+ self.scrolled_window.add(self.textview)
+ self.set_canvas(self.scrolled_window)
+ self.textview.show()
+ self.scrolled_window.show()
+ page = 0
+ self.clipboard = gtk.Clipboard(display=gtk.gdk.display_get_default(), \
+ selection="CLIPBOARD")
+ self.textview.grab_focus()
+ self.font_desc = pango.FontDescription("sans %d" % style.zoom(10))
+ self.textview.modify_font(self.font_desc)
+
+ buffer = self.textview.get_buffer()
+ self.markset_id = buffer.connect("mark-set", self.mark_set_cb)
+ self.toolbox.set_current_toolbar(TOOLBAR_READ)
+
+ def keypress_cb(self, widget, event):
+ "Respond when the user presses one of the arrow keys"
+ keyname = gtk.gdk.keyval_name(event.keyval)
+ print keyname
+ if keyname == 'plus':
+ self.font_increase()
+ return True
+ if keyname == 'minus':
+ self.font_decrease()
+ return True
+ if keyname == 'Page_Up' :
+ self.page_previous()
+ return True
+ if keyname == 'Page_Down':
+ self.page_next()
+ return True
+ if keyname == 'Up' or keyname == 'KP_Up' \
+ or keyname == 'KP_Left':
+ self.scroll_up()
+ return True
+ if keyname == 'Down' or keyname == 'KP_Down' \
+ or keyname == 'KP_Right':
+ self.scroll_down()
+ return True
+ return False
+
+ def num_page_entry_activate_cb(self, entry):
+ global page
+ if entry.props.text:
+ new_page = int(entry.props.text) - 1
+ else:
+ new_page = 0
+
+ if new_page &gt;= self.read_toolbar.total_pages:
+ new_page = self.read_toolbar.total_pages - 1
+ elif new_page &lt; 0:
+ new_page = 0
+
+ self.read_toolbar.current_page = new_page
+ self.read_toolbar.set_current_page(new_page)
+ self.show_page(new_page)
+ entry.props.text = str(new_page + 1)
+ self.read_toolbar.update_nav_buttons()
+ page = new_page
+
+ def go_back_cb(self, button):
+ self.page_previous()
+
+ def go_forward_cb(self, button):
+ self.page_next()
+
+ def page_previous(self):
+ global page
+ page=page-1
+ if page &lt; 0: page=0
+ self.read_toolbar.set_current_page(page)
+ self.show_page(page)
+ v_adjustment = self.scrolled_window.get_vadjustment()
+ v_adjustment.value = v_adjustment.upper - v_adjustment.page_size
+
+ def page_next(self):
+ global page
+ page=page+1
+ if page &gt;= len(self.page_index): page=0
+ self.read_toolbar.set_current_page(page)
+ self.show_page(page)
+ v_adjustment = self.scrolled_window.get_vadjustment()
+ v_adjustment.value = v_adjustment.lower
+
+ def zoom_in_cb(self, button):
+ self.font_increase()
+
+ def zoom_out_cb(self, button):
+ self.font_decrease()
+
+ def font_decrease(self):
+ font_size = self.font_desc.get_size() / 1024
+ font_size = font_size - 1
+ if font_size &lt; 1:
+ font_size = 1
+ self.font_desc.set_size(font_size * 1024)
+ self.textview.modify_font(self.font_desc)
+
+ def font_increase(self):
+ font_size = self.font_desc.get_size() / 1024
+ font_size = font_size + 1
+ self.font_desc.set_size(font_size * 1024)
+ self.textview.modify_font(self.font_desc)
+
+ def mark_set_cb(self, textbuffer, iter, textmark):
+
+ if textbuffer.get_has_selection():
+ begin, end = textbuffer.get_selection_bounds()
+ self.edit_toolbar.copy.set_sensitive(True)
+ else:
+ self.edit_toolbar.copy.set_sensitive(False)
+
+ def edit_toolbar_copy_cb(self, button):
+ textbuffer = self.textview.get_buffer()
+ begin, end = textbuffer.get_selection_bounds()
+ copy_text = textbuffer.get_text(begin, end)
+ self.clipboard.set_text(copy_text)
+
+ def view_toolbar_go_fullscreen_cb(self, view_toolbar):
+ self.fullscreen()
+
+ def scroll_down(self):
+ v_adjustment = self.scrolled_window.get_vadjustment()
+ if v_adjustment.value == v_adjustment.upper - \
+ v_adjustment.page_size:
+ self.page_next()
+ return
+ if v_adjustment.value &lt; v_adjustment.upper - \
+ v_adjustment.page_size:
+ new_value = v_adjustment.value + v_adjustment.step_increment
+ if new_value &gt; v_adjustment.upper - v_adjustment.page_size:
+ new_value = v_adjustment.upper - v_adjustment.page_size
+ v_adjustment.value = new_value
+
+ def scroll_up(self):
+ v_adjustment = self.scrolled_window.get_vadjustment()
+ if v_adjustment.value == v_adjustment.lower:
+ self.page_previous()
+ return
+ if v_adjustment.value &gt; v_adjustment.lower:
+ new_value = v_adjustment.value - \
+ v_adjustment.step_increment
+ if new_value &lt; v_adjustment.lower:
+ new_value = v_adjustment.lower
+ v_adjustment.value = new_value
+
+ def show_page(self, page_number):
+ global PAGE_SIZE, current_word
+ position = self.page_index[page_number]
+ self.etext_file.seek(position)
+ linecount = 0
+ label_text = '\n\n\n'
+ textbuffer = self.textview.get_buffer()
+ while linecount &lt; PAGE_SIZE:
+ line = self.etext_file.readline()
+ label_text = label_text + unicode(line, 'iso-8859-1')
+ linecount = linecount + 1
+ label_text = label_text + '\n\n\n'
+ textbuffer.set_text(label_text)
+ self.textview.set_buffer(textbuffer)
+
+ def save_extracted_file(self, zipfile, filename):
+ "Extract the file to a temp directory for viewing"
+ filebytes = zipfile.read(filename)
+ outfn = self.make_new_filename(filename)
+ if (outfn == ''):
+ return False
+ f = open(os.path.join(self.get_activity_root(), 'tmp', outfn), 'w')
+ try:
+ f.write(filebytes)
+ finally:
+ f.close
+
+ def get_saved_page_number(self):
+ global page
+ title = self.metadata.get('title', '')
+ if title == '' or not title[len(title)- 1].isdigit():
+ page = 0
+ else:
+ i = len(title) - 1
+ newPage = ''
+ while (title[i].isdigit() and i &gt; 0):
+ newPage = title[i] + newPage
+ i = i - 1
+ if title[i] == 'P':
+ page = int(newPage) - 1
+ else:
+ # not a page number; maybe a volume number.
+ page = 0
+
+ def save_page_number(self):
+ global page
+ title = self.metadata.get('title', '')
+ if title == '' or not title[len(title)- 1].isdigit():
+ title = title + ' P' + str(page + 1)
+ else:
+ i = len(title) - 1
+ while (title[i].isdigit() and i &gt; 0):
+ i = i - 1
+ if title[i] == 'P':
+ title = title[0:i] + 'P' + str(page + 1)
+ else:
+ title = title + ' P' + str(page + 1)
+ self.metadata['title'] = title
+
+ def read_file(self, filename):
+ "Read the Etext file"
+ global PAGE_SIZE, page
+
+ if zipfile.is_zipfile(filename):
+ self.zf = zipfile.ZipFile(filename, 'r')
+ self.book_files = self.zf.namelist()
+ self.save_extracted_file(self.zf, self.book_files[0])
+ currentFileName = os.path.join(self.get_activity_root(), \
+ 'tmp', self.book_files[0])
+ else:
+ currentFileName = filename
+
+ self.etext_file = open(currentFileName,"r")
+ self.page_index = [ 0 ]
+ pagecount = 0
+ linecount = 0
+ while self.etext_file:
+ line = self.etext_file.readline()
+ if not line:
+ break
+ linecount = linecount + 1
+ if linecount &gt;= PAGE_SIZE:
+ position = self.etext_file.tell()
+ self.page_index.append(position)
+ linecount = 0
+ pagecount = pagecount + 1
+ if filename.endswith(".zip"):
+ os.remove(currentFileName)
+ self.get_saved_page_number()
+ self.show_page(page)
+ self.read_toolbar.set_total_pages(pagecount + 1)
+ self.read_toolbar.set_current_page(page)
+
+ def make_new_filename(self, filename):
+ partition_tuple = filename.rpartition('/')
+ return partition_tuple[2]
+
+ def write_file(self, filename):
+ "Save meta data for the file."
+ self.metadata['activity'] = self.get_bundle_id()
+ self.save_page_number()
+</pre>
+<p>Before you can run this example you'll need to change <strong>activity.info</strong> too:
+</p>
+<pre>[Activity]
+name = Read ETexts II
+service_name = net.flossmanuals.ReadEtextsActivity
+icon = read-etexts
+<strong>exec = sugar-activity ReadEtextsActivity2.ReadEtextsActivity</strong>
+show_launcher = no
+activity_version = 1
+mime_types = text/plain;application/zip
+license = GPLv2+
+
+</pre>
+<p>The line in <strong>bold</strong> is the only one that needs changing.&nbsp; When we run this new version this is what we'll see:
+</p>
+<p><img alt="ReadEtexts_05.jpg" src="/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/ReadEtexts_05.jpg" height="480" width="640" />
+</p>
+<p>There are a few things worth pointing out in this code.&nbsp; First, have a look at this import:
+</p>
+<pre>from gettext import gettext as _
+</pre>
+<p> We'll be using the <em>gettext</em> module of Python to support translating our Activity into other languages. We'll be using it in statements like this one:
+</p>
+<pre> self.back.set_tooltip(_('Back'))</pre>
+<p>The underscore acts the same way as the gettext function because of the way we imported gettext.&nbsp; The effect of this statement will be to look in a special translation file for a word or phrase that matches the key "Back" and replace it with its translation.&nbsp; If there is no translation file for the language we want then it will simply use the word "Back".&nbsp; We'll explore setting up these translation files later, but for now using gettext for all of the words and phrases we will show to our Activity users lays some important groundwork.
+</p>
+<p>The second thing worth pointing out is that while our revised Activity has four toolbars we only had to create two of them.&nbsp; The other two, <strong>Activity</strong> and <strong>Edit</strong>, are part of the Sugar Python library.&nbsp; We can use those toolbars as is, hide the controls we don't need, or even extend them by adding new controls.&nbsp; In the example we're hiding the <strong>Keep</strong> and <strong>Share</strong> controls of the Activity toolbar and the <strong>Undo</strong>, <strong>Redo</strong>, and <strong>Paste</strong> buttons of the Edit toolbar.&nbsp; We currently do not support sharing books or modifying the text in books so these controls are not needed.&nbsp; Note too that the Activity toolbar is part of the <strong>ActivityToolbox</strong>.&nbsp; There is no way to give your Activity a toolbox that does not contain the Activity toolbar as its first entry.
+</p>
+<p>Another thing to notice is that the Activity class doesn't just provide us with a window.&nbsp; The window has a VBox to hold our toolbars and the body of our Activity.&nbsp; We install the toolbox using <em>set_toolbox()</em> and the body of the Activity using <em>set_canvas()</em>.
+</p>
+<p>The <strong>Read</strong> and <strong>View</strong> toolbars are regular PyGtk programming, but notice that there is a special button for Sugar toolbars that can have a tooltip attached to it, plus the <strong>View</strong> toolbar has code to hide the toolbox and <strong>ReadEtextsActivity2</strong> has code to unhide it.&nbsp; This is an easy function to add to your own Activities and many games and other kinds of Activities can benefit from the increased screen area you get when you hide the toolbox.
+</p>
+<h2>MetadataAnd Journal Entries
+ <br />
+</h2>
+<p>Every Journal entry represents a single file plus metadata, or information describing the file.&nbsp; There are standard metadata entries that all Journal entries have and you can also create your own custom metadata.
+</p>
+<p> Unlike ReadEtextsActivity, this version has a <em>write_file()</em> method.
+</p>
+<pre> def write_file(self, filename):
+ "Save meta data for the file."
+ self.metadata['activity'] = self.get_bundle_id()
+ self.save_page_number()
+</pre>
+<p> We didn't have a <em>write_file()</em> method before because we weren't going to update the file the book is in, and we still aren't.&nbsp; We will, however, be updating the metadata for the Journal entry.&nbsp; Specifically, we'll be doing two things:
+</p>
+<ul>
+ <li>Save the page number our Activity user stopped reading on so when he launches the Activity again we can return to that page.</li>
+ <li>Tell the Journal entry that it belongs to our Activity, so that in the future it will use our Activity's icon and can launch our Activity with one click.</li>
+</ul>
+<p>The way the <strong>Read</strong> Activity saves page number is to use a custom metadata property.&nbsp;
+</p>
+<pre> self.metadata['Read_current_page'] = \
+ str(self._document.get_page_cache().get_current_page())
+</pre>
+<p><strong>Read</strong> creates a custom metadata property named <em>Read_current_page </em>to store the current page number.&nbsp; You can create any number of custom metadata properties just this easily, so you may wonder why we aren't doing that with <strong>Read Etexts</strong>.&nbsp; Actually, the first version of <strong>Read Etexts</strong> did use a custom property, but in Sugar .82 or lower there was a bug in the Journal such that custom metadata did not survive after the computer was turned off.&nbsp; As a result my Activity would remember pages numbers while the computer was running, but would forget them as soon as it was shut down.&nbsp; XO laptops currently cannot upgrade to anything newer than .82, and when it is possible to upgrade it will be a big job for the schools.
+</p>
+<p>To get around this problem I created the following two methods:
+ <br />
+</p>
+<pre> def get_saved_page_number(self):
+ global page
+ title = self.metadata.get('title', '')
+ if title == '' or not title[len(title)- 1].isdigit():
+ page = 0
+ else:
+ i = len(title) - 1
+ newPage = ''
+ while (title[i].isdigit() and i &gt; 0):
+ newPage = title[i] + newPage
+ i = i - 1
+ if title[i] == 'P':
+ page = int(newPage) - 1
+ else:
+ # not a page number; maybe a volume number.
+ page = 0
+
+ def save_page_number(self):
+ global page
+ title = self.metadata.get('title', '')
+ if title == '' or not title[len(title)- 1].isdigit():
+ title = title + ' P' + str(page + 1)
+ else:
+ i = len(title) - 1
+ while (title[i].isdigit() and i &gt; 0):
+ i = i - 1
+ if title[i] == 'P':
+ title = title[0:i] + 'P' + str(page + 1)
+ else:
+ title = title + ' P' + str(page + 1)
+ self.metadata['title'] = title
+</pre>
+<p> <em>save_page_number()</em> looks at the current title metadata and either adds a page number to the end of it or updates the page number already there.&nbsp; Since title is standard metadata for all Journal entries the Journal bug does not affect it.
+</p>
+<p>These examples show how to read metadata too. &nbsp;
+ <br />
+</p>
+<pre> title = self.metadata.get('title', '')
+</pre>
+<p> This line of code says "Get the metadata property named <em>title</em> and put it in the variable named <em>title</em>, If there is no title property put an empty string in <em>title</em>.
+</p>
+<p>Generally&nbsp; you will save metadata in the <em>write_file()</em> method and read it in the <em>read_file()</em> method.
+</p>
+<p>In a normal Activity that writes out a file in write_file() this next line would be unnecessary:
+</p>
+<p>
+</p>
+<pre> self.metadata['activity'] = self.get_bundle_id()
+</pre>
+<p> Any Journal entry created by an Activity will automatically have this property set. In the case of <em>Pride and Prejudice</em>, our Activity did not create it.&nbsp; We are able to read it because our Activity supports its <em>MIME type</em>.&nbsp; Unfortunately, that MIME type, <em>application/zip</em>, is used by other Activities.&nbsp; I found it very frustrating to want to open a book in <strong>Read Etexts</strong> and accidentally have it opened in <strong>EToys</strong> instead.&nbsp; This line of code solves that problem.&nbsp; You only need to use <em>Start Using...</em> the first time you read a book.&nbsp; After that the book will use the <strong>Read Etexts</strong> icon and can be resumed with a single click.
+</p>
+<p>This does not at all affect the MIME type of the Journal entry, so if you wanted to deliberately open <em>Pride and Prejudice</em> with <strong>Etoys</strong> it is still possible.
+</p>
+<p>Before we leave the subject of Journal metadata let's look at all the standard metadata that every Activity has.&nbsp; Here is some code that creates a new Journal entry and updates a bunch of standard properties:
+</p>
+<pre> def create_journal_entry(self, tempfile):
+ journal_entry = datastore.create()
+ journal_title = self.selected_title
+ if self.selected_volume != '':
+ journal_title += ' ' + _('Volume') + ' ' + self.selected_volume
+ if self.selected_author != '':
+ journal_title = journal_title + ', by ' + self.selected_author
+ journal_entry.metadata['title'] = journal_title
+ journal_entry.metadata['title_set_by_user'] = '1'
+ journal_entry.metadata['keep'] = '0'
+ format = self._books_toolbar.format_combo.props.value
+ if format == '.djvu':
+ journal_entry.metadata['mime_type'] = 'image/vnd.djvu'
+ if format == '.pdf' or format == '_bw.pdf':
+ journal_entry.metadata['mime_type'] = 'application/pdf'
+ journal_entry.metadata['buddies'] = ''
+ journal_entry.metadata['preview'] = ''
+ journal_entry.metadata['icon-color'] = profile.get_color().to_string()
+ textbuffer = self.textview.get_buffer()
+ journal_entry.metadata['description'] = \
+ textbuffer.get_text(textbuffer.get_start_iter(), \
+ textbuffer.get_end_iter())
+ journal_entry.file_path = tempfile
+ datastore.write(journal_entry)
+ os.remove(tempfile)
+ self._alert(_('Success'), self.selected_title + _(' added to Journal.'))
+</pre>
+<p>This code is taken from an Activity I wrote that downloads books from a website and creates Journal entries for them.&nbsp; The Journal entries contain a friendly title and a full description of the book.
+</p>
+<p>Most Activities will only deal with one Journal entry by using the <em>read_file()</em> and <em>write_file()</em> methods but you are not limited to that.&nbsp; You can create new Journal entries using code like this example, and you can also list out and read any entries in the Journal. Here is some code to list out image files that have Journal entries:
+</p>
+<pre> def load_journal_table(self):
+ ds_objects, num_objects = datastore.find({\
+ 'mime_type':['image/jpeg', 'image/gif', \
+ 'image/tiff', 'image/png']})
+ for i in xrange (0, num_objects, 1):
+ title = ds_objects[i].metadata['title']
+ mime_type = ds_objects[i].metadata['mime_type']
+ if mime_type == 'image/jpeg' and not title.endswith('.jpg')\
+ and not title.endswith('.jpeg') \
+ and not title.endswith('.JPG') and not title.endswith('.JPEG') :
+ title = title + '.jpg'
+ if mime_type == 'image/png' and not title.endswith('.png')\
+ and not title.endswith('.PNG'):
+ title = title + '.png'
+ if mime_type == 'image/gif' and not title.endswith('.gif')\
+ and not title.endswith('.GIF'):
+ title = title + '.gif'
+ if mime_type == 'image/tiff' and not title.endswith('.tiff')\
+ and not title.endswith('.TIFF'):
+ title = title + '.tiff'
+ jobject_wrapper = JobjectWrapper()
+ jobject_wrapper.set_jobject(ds_objects[i])
+<em> ... add the jobject wrapper to a list here ...</em>
+
+ valid_endings = ('.jpg', '.jpeg', '.JPEG', '.JPG', '.gif',\
+ '.GIF', '.tiff', '.TIFF', '.png', '.PNG')
+ ds_mounts = datastore.mounts()
+ if len(ds_mounts) == 1 and ds_mounts[0]['id'] == 1:
+ # datastore.mounts() is stubbed out, we're running .84 or better
+ for dirname, dirnames, filenames in os.walk('/media'):
+ if '.olpc.store' in dirnames:
+ dirnames.remove('.olpc.store')
+ # don't visit .olpc.store directories
+ for filename in filenames:
+ if filename.endswith(valid_endings):
+ jobject_wrapper = JobjectWrapper()
+ jobject_wrapper.set_file_path(os.path.join(\
+ dirname, filename))
+<em> ... Add these jobject wrappers to the same list ...</em>
+</pre>
+<p>If this code seems complicated you should understand that most of this code is needed to give an identical experience under Sugar .82 and later versions.&nbsp; Really the only code you need to list Journal objects is this:
+ <br />
+</p>
+<pre> ds_objects, num_objects = datastore.find({\
+ 'mime_type':['image/jpeg', 'image/gif', \
+ 'image/tiff', 'image/png']})
+ for i in xrange (0, num_objects, 1):
+ title = ds_objects[i].metadata['title']
+ mime_type = ds_objects[i].metadata['mime_type']
+</pre>
+<p>This code will list out all the image files in an array and you can loop through it and find out what you need to know about those images.&nbsp; When you're ready to read one of those image files you can use code like this to get the path to the file:
+</p>
+<pre>path = ds_objects[i].get_file_path()
+</pre>
+<p> It is important to use the <em>get_file_path()</em> method immediately before you read the file.&nbsp; The reason is that the path does not exist before you call <em>get_file_path()</em> and will not exist long afterwards.&nbsp; Remember that Sugar does not let you deal with the Journal directly, in order to prevent malicious Activities from harming each other.&nbsp; Instead you are given paths of files to read and write to and Sugar deals with getting them to and from the Journal.
+</p>
+<p>So why use the complex code I wrote when something simpler will do the same thing?&nbsp; There are several reasons:
+</p>
+<ul>
+ <li>In Sugar .82 the simpler code will list all image files in your Journal, plus all image files in your SD card if your XO has one, plus any image files in any USB thumb drives you may have mounted.&nbsp; In later versions of Sugar only image files in the Journal proper are listed.&nbsp; I liked the Sugar .82 behavior and this code gives that behavior in all Sugar versions.</li>
+ <li>In one of the Sugar versions the title of the Journal entry is just the first part of the filename, without the .gif, .png, or .jpg suffix.&nbsp; I wanted the title to always be the complete filename with suffix so I use the MIME type to figure out what the suffix should be and if it's missing I add it.</li>
+</ul>
+<p>To make ds objects work the same way as regular files on thumb drives I create a wrapper class to contain both:
+</p>
+<pre>class JobjectWrapper():
+ def __init__(self):
+ self.__jobject = None
+ self.__file_path = None
+
+ def set_jobject(self, jobject):
+ self.__jobject = jobject
+
+ def set_file_path(self, file_path):
+ self.__file_path = file_path
+
+ def get_file_path(self):
+ if self.__jobject != None:
+ return self.__jobject.get_file_path()
+ else:
+ return self.__file_path
+</pre>
+<p> As you can see when I read a file on an SD card or a thumb drive I'm reading the actual file using its actual path, not a temporary one.&nbsp; Even so my Activity cannot <em>write</em> to an SD card or a thumb drive.&nbsp; It can only read from them.&nbsp; If you want to export data to a file on a thumb drive the best you can do is to create a Journal entry with the appropriate MIME type.&nbsp; The Activity user can then copy this entry to the thumb drive using the Journal.
+</p>
+<p>We've covered a lot of technical information in this chapter and there's more to come, but before we get to that we need to look at some other important topics:
+</p>
+<ul>
+ <li>Putting your Activity in version control.&nbsp; This will enable you to share your code with the world and get other people to help work on it.</li>
+ <li>Getting your Activity translated into other languages.</li>
+ <li>Distributing your finished Activity.&nbsp; (Or your not quite finished but still useful Activity).
+ <br /></li>
+</ul>
+<p />
+ </p></div>
+ </div>
+<div class="arrow" style="position:relative;left:10px;width:50px;float:left;bottom:5px;"><a href="#" onClick="previous();"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/lefttext.png" height=20></a></div>
+<div class="arrow" style="position:relative;left:528px;width:50px;float:left;bottom:5px;"><a href="#" onClick="next();"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/righttext.png" height=20></a></div>
+ <br>
+ <br>
+ <br>
+ <br>
+ </td>
+ </tr>
+ </table>
+ </div>
+<!-- Piwik -->
+<a href="http://piwik.org" title="Web analytics" onclick="window.open(this.href);return(false);">
+<script language="javascript" src="http://adam.engagetv.com/piwik/piwik.js" type="text/javascript"></script>
+<script type="text/javascript">
+<!--
+piwik_action_name = '';
+piwik_idsite = 1;
+piwik_url = 'http://adam.engagetv.com/piwik/piwik.php';
+piwik_log(piwik_action_name, piwik_idsite, piwik_url);
+//-->
+</script>
+<!-- /Piwik -->
+<script language="Javascript">
+document.getElementById("AddRefinements").style.backgroundColor="#F99B1C";
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/help/ActivityBook/ActivitiesGuideSugar/CreateFirstActivity b/help/ActivityBook/ActivitiesGuideSugar/CreateFirstActivity
new file mode 100644
index 0000000..69b9d9c
--- /dev/null
+++ b/help/ActivityBook/ActivitiesGuideSugar/CreateFirstActivity
@@ -0,0 +1,290 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html>
+ <head>
+ <title>ActivitiesGuideSugar (en)</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <!--
+ <link rel="alternate" type="application/rss+xml" title="RSS Feed" href="WebRss.html" />
+ -->
+ <link rel="icon" href="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/fl2.ico" type="image/x-icon" /> <link rel="shortcut icon" href="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/fl2.ico" type="image/x-icon" />
+ <link rel=StyleSheet href="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/typography.css" type="text/css" media="screen">
+<style>
+#index {
+ color: #ff7f00;
+ font-family: trebuchet,sans-serif;
+ font-size: 10px;
+ line-height:11px;
+}
+#index UL {
+ width: 159px;
+ list-style-type: None;
+ padding-left: 0px;
+ border: 14px solid #ff7f00;
+ background-color: #ff7f00;
+ margin: 0px 0px 0px 0px;
+ }
+#index LI {
+ padding-left: 0px;
+ padding-right: 10px;
+ padding-top: 4px;
+ padding-bottom: 4px;
+ color: #ffffff;
+ margin: 0px 0px 0px 0px;
+ background-color: #ff7f00;
+ border-top: 1px solid #ff7f00;
+ }
+#index LI:hover {
+ background-color: #F99B1C;
+}
+#index LI.heading {
+ background-color: #ff7f00;
+ color: #000000;
+ border-top:1px solid #FFE5CC;
+ padding-top: 7px;
+ font-weight: bold;
+}
+#index LI.title {
+ border-bottom: 2px solid #FFE5CC;
+ background-color: #ff7f00;
+ color: #FBF4E9;
+ font-weight: bolder;
+ font-size:10px;
+ line-height:18px;
+ padding-bottom: 40px;
+ }
+#index A {
+ text-decoration: none;
+ color: #FBF4E9;
+ font-weight: bold;
+}
+#ds-layout .imgcontainer {
+ position:relative;
+ }
+#ds-layout .caption {
+ position:relative;
+ bottom:1;
+ left:0;
+ text-align:center;
+ background:#ffe7cb;
+ width:100%;
+ opacity:.75;
+ filter:alpha(opacity=85);
+ color:#000;
+ font-style: italic;
+ font-size: 9px;
+ line-height:11px;
+ }
+</style>
+<script type="text/javascript">
+function addLoadEvent(func) {
+ var oldonload = window.onload;
+ if (typeof window.onload != 'function') {
+ window.onload = func;
+ } else {
+ window.onload = function() {
+ oldonload();
+ func();
+ }
+ }
+}
+
+function insertAfter(newElement,targetElement) {
+ var parent = targetElement.parentNode;
+ if (parent.lastChild == targetElement) {
+ parent.appendChild(newElement);
+ } else {
+ parent.insertBefore(newElement,targetElement.nextSibling);
+ }
+}
+
+function captionizeImages() {
+ if (!document.getElementsByTagName) return false;
+ if (!document.createElement) return false;
+ var images = document.getElementsByTagName("img");
+ if (images.length < 1) return false;
+ for (var i=0; i<images.length; i++) {
+ if (images[i].className != "non") {
+ var title = images[i].getAttribute("title");
+ var width = images[i].width;
+ var divCaption = document.createElement("div");
+ divCaption.className="caption";
+ divCaption.style.width=width+'px';
+ if (title) divCaption.style.padding='2px 0px 3px 0px';
+ divCaption.style.display='block';
+ var divCaption_text = document.createTextNode(title);
+ divCaption.appendChild(divCaption_text);
+ var divContainer = document.createElement("div");
+ divContainer.className="imgcontainer";
+ if (title) divContainer.style.padding='0px 0px 10px 0px';
+ images[i].parentNode.insertBefore(divContainer,images[i]);
+ divContainer.appendChild(images[i]);
+ insertAfter(divCaption,images[i]);
+ }
+ }
+}
+//addLoadEvent(captionizeImages);
+
+function next () {
+var onode, otarget;
+onode=document.getElementById("CreateFirstActivity");
+if (onode.id=="Credits") die;
+//alert (onode.id);
+onode=onode.nextSibling;
+if (onode.id=="heading") onode=onode.nextSibling;
+while (onode) {
+ //onode=onode.nextSibling;
+ if (onode.nodeType==1) {
+ //alert (onode.id);
+ otarget=onode;
+ break;
+ }
+ onode=onode.nextSibling;
+}
+if (otarget) {
+ //you actually have found one, and do something here
+ //alert(otarget.id + "\n" + otarget.tagName); //just to verify
+ top.location = "/ActivitiesGuideSugar/" + otarget.id;
+} else {
+ //you don't find one
+//alert("nada" + otarget.id);
+}
+}
+
+function previous () {
+var onode, otarget;
+onode=document.getElementById("CreateFirstActivity");
+if (onode.id=="Introduction") die;
+//alert (onode.id);
+onode=onode.previousSibling;
+if (onode.id=="heading") onode=onode.previousSibling;
+if (onode.id=="title") die;
+while (onode) {
+ //onode=onode.previousSibling;
+ if (onode.nodeType==1) {
+ //alert (onode.id);
+ otarget=onode;
+ break;
+ }
+ onode=onode.previousSibling;
+}
+if (otarget) {
+ //you actually have found one, and do something here
+ //alert(otarget.id + "\n" + otarget.tagName); //just to verify
+ top.location = otarget.id;
+} else {
+ //you don't find one
+//alert("nada" + otarget.id);
+}
+}
+
+</script>
+ </head>
+ <body background="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/background.gif" style="margin:0;color:#000000;">
+<div id="home" style="position:absolute;left:0px;top:10px;">
+<a href="/"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/top_read_back.gif" border="0"></a>
+</div>
+<div id="index" style="position:absolute;left:0px;top:150px;">
+<ul>
+<li class="title">MAKING SUGAR ACTIVITIES</li><li id="Introduction"><a href="/ActivitiesGuideSugar/Introduction">INTRODUCTION</a></li><li id="WhatIsSugar"><a href="/ActivitiesGuideSugar/WhatIsSugar">WHAT IS SUGAR?</a></li><li id="WhatisanActivity"><a href="/ActivitiesGuideSugar/WhatisanActivity">WHAT IS A SUGAR ACTIVITY?</a></li><li id="NeedtoKnowWriteSugarActivity"><a href="/ActivitiesGuideSugar/NeedtoKnowWriteSugarActivity">WHAT DO I NEED TO KNOW TO WRITE A SUGAR ACTIVITY?</a></li><li id="SetUpDevEnvironment"><a href="/ActivitiesGuideSugar/SetUpDevEnvironment">SETTING UP A DEVELOPMENT ENVIRONMENT</a></li><li id="CreateFirstActivity"><a href="/ActivitiesGuideSugar/CreateFirstActivity">CREATING YOUR FIRST ACTIVITY</a></li><li id="StandalonePythonReadEtexts"><a href="/ActivitiesGuideSugar/StandalonePythonReadEtexts">MAKING A STANDALONE PYTHON PROGRAM</a></li><li id="InheritFromActivity"><a href="/ActivitiesGuideSugar/InheritFromActivity">INHERIT FROM SUGAR.ACTIVITY.ACTIVITY</a></li><li id="PackageTheActivity"><a href="/ActivitiesGuideSugar/PackageTheActivity">PACKAGE THE ACTIVITY</a></li><li id="AddRefinements"><a href="/ActivitiesGuideSugar/AddRefinements">ADD REFINEMENTS</a></li><li id="UsingVersionControl"><a href="/ActivitiesGuideSugar/UsingVersionControl">ADD YOUR ACTIVITY CODE TO VERSION CONTROL</a></li><li id="Credits"><a href="/ActivitiesGuideSugar/Credits">CREDITS</a></li></ul>
+</div>
+<div id="pdf" style="position:absolute;left:13px;top:190px;">
+<a href="/ActivitiesGuideSugar/FM_06Jan10.pdf"><img class ="non" src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/makepdf.gif" border=0></a>
+<!-- <a href="/ActivitiesGuideSugar/FM_ActivitiesGuideSugar_06Jan10.pdf"><img class ="non" src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/makepdf.gif" border=0></a> -->
+<a href="/ActivitiesGuideSugar/print"><img class="non" src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/viewprint.gif" border=0></a>
+</div>
+ <div style="position:absolute;left:240px;top:11px;">
+ <table id="ds-layout" cellpadding="0" cellspacing="0" sumtop:5px;mary="" style="table-layout:fixed;width:670px;border: 5px solid #666666;padding-right: 0px;padding-left: 0px;padding-bottom: 0px;padding-top: 0px;margin-left : 10px;margin-top:10;background:#FFF7F0;">
+ <tr>
+ <td width=100%>
+<div class="arrow" style="position:relative;left:10px;top:5px;width:50px;float:left;"><a href="#" onClick="previous();"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/lefttext.png" height=20></a></div>
+<div class="arrow" style="position:relative;left:528px;width:50px;top:5px;float:left;"><a href="#" onClick="next();"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/righttext.png" height=20></a></div>
+ <div class="ds-contentcontainer">
+ <div style="margin-left:1.2em;float:right">
+ <br>
+ <div class="huh" style='decoration:none;color:black;border:1;position:absolute;top:60px;left:502px;'>
+ <a href='http://www.flossmanuals.net/bin/view/ActivitiesGuideSugar/CreateFirstActivity' onClick="alert('You will now be forwarded to the FLOSS Manuals editing interface')"><b><font color=#ff7f00><small>Edit this page</small></font></b></a> :: <a href='http://www.flossmanuals.net/bin/view/ActivitiesGuideSugar/FMComments?skin=floss2'><b><font color=#ff7f00><small>Discussion</small></font></b></a>
+ </div>
+ <h1>Creating your First Sugar Activity
+</h1>
+<h2 class="western">Make A Standalone Python Program First
+</h2>
+<p class="western">The best advice I could give a beginning Activity developer is to make a version of your Activity that can run on its own, outside of the Sugar environment. Testing and debugging a Python program that stands alone is faster, easier and less tedious than doing the same thing with a similar Activity. You'll understand why when you start testing your first Activity.
+</p>
+<p class="western">The more bugs you find before you turn your code into an Activity the better. In fact, it's a good idea to keep a standalone version of your program around even after you have the Activity version well underway. I used my standalone version of Read Etexts to develop the text to speech with highlighting feature. This saved me a <em>lot</em> of time, which was especially important because I was figuring things out as I went.
+</p>
+<p>Our first project will be a version of the Read Etexts Activity I wrote.
+ <br />
+</p>
+<h2 class="western">Inherit From The sugar.activity.Activity Class
+</h2>
+<p>Next we're going to take our standalone Python program and make an Activity out of it.&nbsp; To do this we need to understand the concept of <em>inheritance</em>.&nbsp; In everyday speech inheritance means getting something from your parents that you didn't work for.&nbsp; A king will take his son to a castle window and say, "Someday, lad, this will all be yours!"&nbsp; That's inheritance.
+</p> In the world of computers programs can have parents and inherit things from them.&nbsp; Instead of inheriting property, they inherit code. There is a piece of Python code called sugar.activity.Activity that's the best parent an Activity could hope to have, and we're going to convince it to adopt our program.&nbsp; This doesn't mean that our program will never have to work again,&nbsp; but it won't have to work as much.
+<br />
+<h2>Package The Activity
+</h2>
+<p>Now we have to package up our code to make it something that can be run under Sugar and distributed as an .xo file.&nbsp; This involves setting up a MANIFEST, activity.info, setup.py, and creating a suitable icon with Inkscape.
+ <br />
+</p>
+<h2 class="western">Add Refinements
+</h2>
+<p class="western">Every Activity will have the basic Activity toolbar. For most Activities this will not be enough, so we'll need to create some custom toolbars as well. Then we need to hook them up to the rest of the Activity code so that what happens to the toolbar triggers actions in the Activity and what happens outside the toolbar is reflected in the state of the toolbar.
+</p>
+<p class="western">In addition to toolbars we'll look at some other ways to spiff up your Activity.
+ <br />
+</p>
+<h2> Put The Project Code In Version Control
+ <br />
+</h2>
+<p>By this time we'll have enough code written that it's worth protecting and sharing with the world.&nbsp; To do that we need to create a Git repository and add our code to it.&nbsp; We'll also go over the basics of using Git.
+ <br />
+</p>
+<h2> Going International With Pootle
+</h2>
+<p>Now that our code is in Git we can request help from our first collaborator: the Pootle translation system.&nbsp; With a little setup work we can get volunteers to make translated versions of our Activity available.
+</p>
+<h2>Distributing The Activity
+</h2>
+<p>In this task we'll take our Activity and set it up on <a href="http://activities.sugarlabs.org">http://activities.sugarlabs.org</a>&nbsp; plus we'll package up the source code so it can be included in Linux distributions.
+ <br />
+</p>
+<h2> Add Collaboration
+</h2>
+<p>Next we'll add code to share e-books with Friends and the Neighborhood.
+ <br />
+</p>
+<h2>Add Text To Speech
+</h2>
+<p>Text to Speech with word highlighting is next.&nbsp; Our simple project will become a Kindle-killer!
+ <br />
+</p>
+<p />
+ </p></div>
+ </div>
+<div class="arrow" style="position:relative;left:10px;width:50px;float:left;bottom:5px;"><a href="#" onClick="previous();"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/lefttext.png" height=20></a></div>
+<div class="arrow" style="position:relative;left:528px;width:50px;float:left;bottom:5px;"><a href="#" onClick="next();"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/righttext.png" height=20></a></div>
+ <br>
+ <br>
+ <br>
+ <br>
+ </td>
+ </tr>
+ </table>
+ </div>
+<!-- Piwik -->
+<a href="http://piwik.org" title="Web analytics" onclick="window.open(this.href);return(false);">
+<script language="javascript" src="http://adam.engagetv.com/piwik/piwik.js" type="text/javascript"></script>
+<script type="text/javascript">
+<!--
+piwik_action_name = '';
+piwik_idsite = 1;
+piwik_url = 'http://adam.engagetv.com/piwik/piwik.php';
+piwik_log(piwik_action_name, piwik_idsite, piwik_url);
+//-->
+</script>
+<!-- /Piwik -->
+<script language="Javascript">
+document.getElementById("CreateFirstActivity").style.backgroundColor="#F99B1C";
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/help/ActivityBook/ActivitiesGuideSugar/Credits b/help/ActivityBook/ActivitiesGuideSugar/Credits
new file mode 100644
index 0000000..097e896
--- /dev/null
+++ b/help/ActivityBook/ActivitiesGuideSugar/Credits
@@ -0,0 +1,369 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html>
+ <head>
+ <title>ActivitiesGuideSugar (en)</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <!--
+ <link rel="alternate" type="application/rss+xml" title="RSS Feed" href="WebRss.html" />
+ -->
+ <link rel="icon" href="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/fl2.ico" type="image/x-icon" /> <link rel="shortcut icon" href="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/fl2.ico" type="image/x-icon" />
+ <link rel=StyleSheet href="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/typography.css" type="text/css" media="screen">
+<style>
+#index {
+ color: #ff7f00;
+ font-family: trebuchet,sans-serif;
+ font-size: 10px;
+ line-height:11px;
+}
+#index UL {
+ width: 159px;
+ list-style-type: None;
+ padding-left: 0px;
+ border: 14px solid #ff7f00;
+ background-color: #ff7f00;
+ margin: 0px 0px 0px 0px;
+ }
+#index LI {
+ padding-left: 0px;
+ padding-right: 10px;
+ padding-top: 4px;
+ padding-bottom: 4px;
+ color: #ffffff;
+ margin: 0px 0px 0px 0px;
+ background-color: #ff7f00;
+ border-top: 1px solid #ff7f00;
+ }
+#index LI:hover {
+ background-color: #F99B1C;
+}
+#index LI.heading {
+ background-color: #ff7f00;
+ color: #000000;
+ border-top:1px solid #FFE5CC;
+ padding-top: 7px;
+ font-weight: bold;
+}
+#index LI.title {
+ border-bottom: 2px solid #FFE5CC;
+ background-color: #ff7f00;
+ color: #FBF4E9;
+ font-weight: bolder;
+ font-size:10px;
+ line-height:18px;
+ padding-bottom: 40px;
+ }
+#index A {
+ text-decoration: none;
+ color: #FBF4E9;
+ font-weight: bold;
+}
+#ds-layout .imgcontainer {
+ position:relative;
+ }
+#ds-layout .caption {
+ position:relative;
+ bottom:1;
+ left:0;
+ text-align:center;
+ background:#ffe7cb;
+ width:100%;
+ opacity:.75;
+ filter:alpha(opacity=85);
+ color:#000;
+ font-style: italic;
+ font-size: 9px;
+ line-height:11px;
+ }
+</style>
+<script type="text/javascript">
+function addLoadEvent(func) {
+ var oldonload = window.onload;
+ if (typeof window.onload != 'function') {
+ window.onload = func;
+ } else {
+ window.onload = function() {
+ oldonload();
+ func();
+ }
+ }
+}
+
+function insertAfter(newElement,targetElement) {
+ var parent = targetElement.parentNode;
+ if (parent.lastChild == targetElement) {
+ parent.appendChild(newElement);
+ } else {
+ parent.insertBefore(newElement,targetElement.nextSibling);
+ }
+}
+
+function captionizeImages() {
+ if (!document.getElementsByTagName) return false;
+ if (!document.createElement) return false;
+ var images = document.getElementsByTagName("img");
+ if (images.length < 1) return false;
+ for (var i=0; i<images.length; i++) {
+ if (images[i].className != "non") {
+ var title = images[i].getAttribute("title");
+ var width = images[i].width;
+ var divCaption = document.createElement("div");
+ divCaption.className="caption";
+ divCaption.style.width=width+'px';
+ if (title) divCaption.style.padding='2px 0px 3px 0px';
+ divCaption.style.display='block';
+ var divCaption_text = document.createTextNode(title);
+ divCaption.appendChild(divCaption_text);
+ var divContainer = document.createElement("div");
+ divContainer.className="imgcontainer";
+ if (title) divContainer.style.padding='0px 0px 10px 0px';
+ images[i].parentNode.insertBefore(divContainer,images[i]);
+ divContainer.appendChild(images[i]);
+ insertAfter(divCaption,images[i]);
+ }
+ }
+}
+//addLoadEvent(captionizeImages);
+
+function next () {
+var onode, otarget;
+onode=document.getElementById("Credits");
+if (onode.id=="Credits") die;
+//alert (onode.id);
+onode=onode.nextSibling;
+if (onode.id=="heading") onode=onode.nextSibling;
+while (onode) {
+ //onode=onode.nextSibling;
+ if (onode.nodeType==1) {
+ //alert (onode.id);
+ otarget=onode;
+ break;
+ }
+ onode=onode.nextSibling;
+}
+if (otarget) {
+ //you actually have found one, and do something here
+ //alert(otarget.id + "\n" + otarget.tagName); //just to verify
+ top.location = "/ActivitiesGuideSugar/" + otarget.id;
+} else {
+ //you don't find one
+//alert("nada" + otarget.id);
+}
+}
+
+function previous () {
+var onode, otarget;
+onode=document.getElementById("Credits");
+if (onode.id=="Introduction") die;
+//alert (onode.id);
+onode=onode.previousSibling;
+if (onode.id=="heading") onode=onode.previousSibling;
+if (onode.id=="title") die;
+while (onode) {
+ //onode=onode.previousSibling;
+ if (onode.nodeType==1) {
+ //alert (onode.id);
+ otarget=onode;
+ break;
+ }
+ onode=onode.previousSibling;
+}
+if (otarget) {
+ //you actually have found one, and do something here
+ //alert(otarget.id + "\n" + otarget.tagName); //just to verify
+ top.location = otarget.id;
+} else {
+ //you don't find one
+//alert("nada" + otarget.id);
+}
+}
+
+</script>
+ </head>
+ <body background="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/background.gif" style="margin:0;color:#000000;">
+<div id="home" style="position:absolute;left:0px;top:10px;">
+<a href="/"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/top_read_back.gif" border="0"></a>
+</div>
+<div id="index" style="position:absolute;left:0px;top:150px;">
+<ul>
+<li class="title">MAKING SUGAR ACTIVITIES</li><li id="Introduction"><a href="/ActivitiesGuideSugar/Introduction">INTRODUCTION</a></li><li id="WhatIsSugar"><a href="/ActivitiesGuideSugar/WhatIsSugar">WHAT IS SUGAR?</a></li><li id="WhatisanActivity"><a href="/ActivitiesGuideSugar/WhatisanActivity">WHAT IS A SUGAR ACTIVITY?</a></li><li id="NeedtoKnowWriteSugarActivity"><a href="/ActivitiesGuideSugar/NeedtoKnowWriteSugarActivity">WHAT DO I NEED TO KNOW TO WRITE A SUGAR ACTIVITY?</a></li><li id="SetUpDevEnvironment"><a href="/ActivitiesGuideSugar/SetUpDevEnvironment">SETTING UP A DEVELOPMENT ENVIRONMENT</a></li><li id="CreateFirstActivity"><a href="/ActivitiesGuideSugar/CreateFirstActivity">CREATING YOUR FIRST ACTIVITY</a></li><li id="StandalonePythonReadEtexts"><a href="/ActivitiesGuideSugar/StandalonePythonReadEtexts">MAKING A STANDALONE PYTHON PROGRAM</a></li><li id="InheritFromActivity"><a href="/ActivitiesGuideSugar/InheritFromActivity">INHERIT FROM SUGAR.ACTIVITY.ACTIVITY</a></li><li id="PackageTheActivity"><a href="/ActivitiesGuideSugar/PackageTheActivity">PACKAGE THE ACTIVITY</a></li><li id="AddRefinements"><a href="/ActivitiesGuideSugar/AddRefinements">ADD REFINEMENTS</a></li><li id="UsingVersionControl"><a href="/ActivitiesGuideSugar/UsingVersionControl">ADD YOUR ACTIVITY CODE TO VERSION CONTROL</a></li><li id="Credits"><a href="/ActivitiesGuideSugar/Credits">CREDITS</a></li></ul>
+</div>
+<div id="pdf" style="position:absolute;left:13px;top:190px;">
+<a href="/ActivitiesGuideSugar/FM_06Jan10.pdf"><img class ="non" src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/makepdf.gif" border=0></a>
+<!-- <a href="/ActivitiesGuideSugar/FM_ActivitiesGuideSugar_06Jan10.pdf"><img class ="non" src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/makepdf.gif" border=0></a> -->
+<a href="/ActivitiesGuideSugar/print"><img class="non" src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/viewprint.gif" border=0></a>
+</div>
+ <div style="position:absolute;left:240px;top:11px;">
+ <table id="ds-layout" cellpadding="0" cellspacing="0" sumtop:5px;mary="" style="table-layout:fixed;width:670px;border: 5px solid #666666;padding-right: 0px;padding-left: 0px;padding-bottom: 0px;padding-top: 0px;margin-left : 10px;margin-top:10;background:#FFF7F0;">
+ <tr>
+ <td width=100%>
+<div class="arrow" style="position:relative;left:10px;top:5px;width:50px;float:left;"><a href="#" onClick="previous();"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/lefttext.png" height=20></a></div>
+<div class="arrow" style="position:relative;left:528px;width:50px;top:5px;float:left;"><a href="#" onClick="next();"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/righttext.png" height=20></a></div>
+ <div class="ds-contentcontainer">
+ <div style="margin-left:1.2em;float:right">
+ <br>
+ <div class="huh" style='decoration:none;color:black;border:1;position:absolute;top:60px;left:502px;'>
+ <a href='http://www.flossmanuals.net/bin/view/ActivitiesGuideSugar/Credits' onClick="alert('You will now be forwarded to the FLOSS Manuals editing interface')"><b><font color=#ff7f00><small>Edit this page</small></font></b></a> :: <a href='http://www.flossmanuals.net/bin/view/ActivitiesGuideSugar/FMComments?skin=floss2'><b><font color=#ff7f00><small>Discussion</small></font></b></a>
+ </div>
+ <h1>License</h1>
+<p>All chapters copyright of the authors (see below). Unless otherwise stated all chapters in this manual licensed with <strong>GNU General Public License version 2</strong>
+</p>
+This documentation is free documentation; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+<p>
+This documentation is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+<p>
+You should have received a copy of the GNU General Public License
+along with this documentation; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+<p />
+<h1><a name="Authors"></a> Authors </h1>
+<p>
+</p><i>ADD REFINEMENTS</i><br/>&copy; James Simmons 2009, 2010<hr/><i>CREATING YOUR FIRST ACTIVITY</i><br/>&copy; Anne Gentle 2009<br/>Modifications:<br/>James Simmons 2009<br/><hr/><i>CREDITS</i><br/>&copy; adam hyde 2006, 2007<hr/><i>INHERIT FROM SUGAR.ACTIVITY.ACTIVITY</i><br/>&copy; James Simmons 2009<hr/><i>INTRODUCTION</i><br/>&copy; adam hyde 2006, 2007<br/>Modifications:<br/>James Simmons 2009<br/><hr/><i>WHAT DO I NEED TO KNOW TO WRITE A SUGAR ACTIVITY?</i><br/>&copy; Anne Gentle 2009<br/>Modifications:<br/>James Simmons 2009<br/><hr/><i>PACKAGE THE ACTIVITY</i><br/>&copy; James Simmons 2009<hr/><i>SETTING UP A DEVELOPMENT ENVIRONMENT</i><br/>&copy; Anne Gentle 2009<br/>Modifications:<br/>James Simmons 2009<br/><hr/><i>MAKING A STANDALONE PYTHON PROGRAM</i><br/>&copy; James Simmons 2009<hr/><i>ADD YOUR ACTIVITY CODE TO VERSION CONTROL</i><br/>&copy; James Simmons 2010<hr/><i>WHAT IS SUGAR?</i><br/>&copy; Anne Gentle 2009<br/>Modifications:<br/>James Simmons 2009<br/><hr/><i>WHAT IS A SUGAR ACTIVITY?</i><br/>&copy; Anne Gentle 2009<br/>Modifications:<br/>James Simmons 2009<br/><hr/>&nbsp;
+<p>
+<a href="http://www.flossmanuals.net/"><img alt="100.gif" src="/floss/publish/ActivitiesGuideSugar/rsrc/Floss/100.gif" height="54" width="110" border=0/></a>
+<br /><strong></strong>
+</p>
+<p><sub>Free manuals for free software</sub>
+</p>
+<p>
+</p>
+<p>&nbsp;
+</p>
+<p>&nbsp;
+</p>
+<h1><a name="General Public License"></a> General Public License </h1>
+<p>Version 2, June 1991
+</p>
+<p>Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+<br>51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+<br>
+<br>Everyone is permitted to copy and distribute verbatim copies
+<br>of this license document, but changing it is not allowed.
+<br>
+</p>
+<p><strong>Preamble</strong>
+</p>
+<p> The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too.
+</p>
+<p> When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things.
+<p />
+</p>
+<p> To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it.
+</p>
+<p> For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.
+</p>
+<p> We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software.
+</p>
+<p> Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations.
+</p>
+<p> Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all.
+</p>
+<p> The precise terms and conditions for copying, distribution and modification follow.
+<p />
+</p>
+<p><strong>TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION</strong>
+</p>
+<p> <strong>0.</strong> This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you".
+</p>
+<p> Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.
+</p>
+<p> <strong>1.</strong> You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program.
+</p>
+<p />
+<p> You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.
+</p>
+<p> <strong>2.</strong> You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:
+</p> <dl> <dt>
+<br></dt> <dd> <strong>a)</strong> You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. </dd> <dt>
+<p />
+<br></dt> <dd> <strong>b)</strong> You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. </dd> <dt>
+<br></dt> <dd> <strong>c)</strong> If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) </dd> </dl>
+<p> These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.
+</p>
+<p />
+<p> Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program.
+</p>
+<p> In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.
+</p>
+<p> <strong>3.</strong> You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:
+</p> <!-- we use this doubled UL to get the sub-sections indented, --> <!-- while making the bullets as unobvious as possible. --> <dl> <dt>
+<br></dt> <dd> <strong>a)</strong> Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, </dd> <dt>
+<p />
+<br></dt> <dd> <strong>b)</strong> Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, </dd> <dt>
+<br></dt> <dd> <strong>c)</strong> Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) </dd> </dl>
+<p> The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.
+</p>
+<p />
+<p> If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.
+</p>
+<p> <strong>4.</strong> You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.
+</p>
+<p> <strong>5.</strong> You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.
+</p>
+<p> <strong>6.</strong> Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License.
+<p />
+</p>
+<p> <strong>7.</strong> If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program.
+</p>
+<p> If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances.
+</p>
+<p> It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.
+</p>
+<p> This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.
+</p>
+<p> <strong>8.</strong> If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.
+<p />
+</p>
+<p> <strong>9.</strong> The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
+</p>
+<p> Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.
+</p>
+<p> <strong>10.</strong> If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.
+</p>
+<p><strong>NO WARRANTY</strong>
+</p>
+<p />
+<p> <strong>11.</strong> BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+</p>
+<p> <strong>12.</strong> IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+</p>
+<p><strong>END OF TERMS AND CONDITIONS</strong>
+</p>
+<p>
+<p />
+<p />
+ </p></div>
+ </div>
+<div class="arrow" style="position:relative;left:10px;width:50px;float:left;bottom:5px;"><a href="#" onClick="previous();"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/lefttext.png" height=20></a></div>
+<div class="arrow" style="position:relative;left:528px;width:50px;float:left;bottom:5px;"><a href="#" onClick="next();"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/righttext.png" height=20></a></div>
+ <br>
+ <br>
+ <br>
+ <br>
+ </td>
+ </tr>
+ </table>
+ </div>
+<!-- Piwik -->
+<a href="http://piwik.org" title="Web analytics" onclick="window.open(this.href);return(false);">
+<script language="javascript" src="http://adam.engagetv.com/piwik/piwik.js" type="text/javascript"></script>
+<script type="text/javascript">
+<!--
+piwik_action_name = '';
+piwik_idsite = 1;
+piwik_url = 'http://adam.engagetv.com/piwik/piwik.php';
+piwik_log(piwik_action_name, piwik_idsite, piwik_url);
+//-->
+</script>
+<!-- /Piwik -->
+<script language="Javascript">
+document.getElementById("Credits").style.backgroundColor="#F99B1C";
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/help/ActivityBook/ActivitiesGuideSugar/InheritFromActivity b/help/ActivityBook/ActivitiesGuideSugar/InheritFromActivity
new file mode 100644
index 0000000..93b0506
--- /dev/null
+++ b/help/ActivityBook/ActivitiesGuideSugar/InheritFromActivity
@@ -0,0 +1,498 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html>
+ <head>
+ <title>ActivitiesGuideSugar (en)</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <!--
+ <link rel="alternate" type="application/rss+xml" title="RSS Feed" href="WebRss.html" />
+ -->
+ <link rel="icon" href="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/fl2.ico" type="image/x-icon" /> <link rel="shortcut icon" href="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/fl2.ico" type="image/x-icon" />
+ <link rel=StyleSheet href="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/typography.css" type="text/css" media="screen">
+<style>
+#index {
+ color: #ff7f00;
+ font-family: trebuchet,sans-serif;
+ font-size: 10px;
+ line-height:11px;
+}
+#index UL {
+ width: 159px;
+ list-style-type: None;
+ padding-left: 0px;
+ border: 14px solid #ff7f00;
+ background-color: #ff7f00;
+ margin: 0px 0px 0px 0px;
+ }
+#index LI {
+ padding-left: 0px;
+ padding-right: 10px;
+ padding-top: 4px;
+ padding-bottom: 4px;
+ color: #ffffff;
+ margin: 0px 0px 0px 0px;
+ background-color: #ff7f00;
+ border-top: 1px solid #ff7f00;
+ }
+#index LI:hover {
+ background-color: #F99B1C;
+}
+#index LI.heading {
+ background-color: #ff7f00;
+ color: #000000;
+ border-top:1px solid #FFE5CC;
+ padding-top: 7px;
+ font-weight: bold;
+}
+#index LI.title {
+ border-bottom: 2px solid #FFE5CC;
+ background-color: #ff7f00;
+ color: #FBF4E9;
+ font-weight: bolder;
+ font-size:10px;
+ line-height:18px;
+ padding-bottom: 40px;
+ }
+#index A {
+ text-decoration: none;
+ color: #FBF4E9;
+ font-weight: bold;
+}
+#ds-layout .imgcontainer {
+ position:relative;
+ }
+#ds-layout .caption {
+ position:relative;
+ bottom:1;
+ left:0;
+ text-align:center;
+ background:#ffe7cb;
+ width:100%;
+ opacity:.75;
+ filter:alpha(opacity=85);
+ color:#000;
+ font-style: italic;
+ font-size: 9px;
+ line-height:11px;
+ }
+</style>
+<script type="text/javascript">
+function addLoadEvent(func) {
+ var oldonload = window.onload;
+ if (typeof window.onload != 'function') {
+ window.onload = func;
+ } else {
+ window.onload = function() {
+ oldonload();
+ func();
+ }
+ }
+}
+
+function insertAfter(newElement,targetElement) {
+ var parent = targetElement.parentNode;
+ if (parent.lastChild == targetElement) {
+ parent.appendChild(newElement);
+ } else {
+ parent.insertBefore(newElement,targetElement.nextSibling);
+ }
+}
+
+function captionizeImages() {
+ if (!document.getElementsByTagName) return false;
+ if (!document.createElement) return false;
+ var images = document.getElementsByTagName("img");
+ if (images.length < 1) return false;
+ for (var i=0; i<images.length; i++) {
+ if (images[i].className != "non") {
+ var title = images[i].getAttribute("title");
+ var width = images[i].width;
+ var divCaption = document.createElement("div");
+ divCaption.className="caption";
+ divCaption.style.width=width+'px';
+ if (title) divCaption.style.padding='2px 0px 3px 0px';
+ divCaption.style.display='block';
+ var divCaption_text = document.createTextNode(title);
+ divCaption.appendChild(divCaption_text);
+ var divContainer = document.createElement("div");
+ divContainer.className="imgcontainer";
+ if (title) divContainer.style.padding='0px 0px 10px 0px';
+ images[i].parentNode.insertBefore(divContainer,images[i]);
+ divContainer.appendChild(images[i]);
+ insertAfter(divCaption,images[i]);
+ }
+ }
+}
+//addLoadEvent(captionizeImages);
+
+function next () {
+var onode, otarget;
+onode=document.getElementById("InheritFromActivity");
+if (onode.id=="Credits") die;
+//alert (onode.id);
+onode=onode.nextSibling;
+if (onode.id=="heading") onode=onode.nextSibling;
+while (onode) {
+ //onode=onode.nextSibling;
+ if (onode.nodeType==1) {
+ //alert (onode.id);
+ otarget=onode;
+ break;
+ }
+ onode=onode.nextSibling;
+}
+if (otarget) {
+ //you actually have found one, and do something here
+ //alert(otarget.id + "\n" + otarget.tagName); //just to verify
+ top.location = "/ActivitiesGuideSugar/" + otarget.id;
+} else {
+ //you don't find one
+//alert("nada" + otarget.id);
+}
+}
+
+function previous () {
+var onode, otarget;
+onode=document.getElementById("InheritFromActivity");
+if (onode.id=="Introduction") die;
+//alert (onode.id);
+onode=onode.previousSibling;
+if (onode.id=="heading") onode=onode.previousSibling;
+if (onode.id=="title") die;
+while (onode) {
+ //onode=onode.previousSibling;
+ if (onode.nodeType==1) {
+ //alert (onode.id);
+ otarget=onode;
+ break;
+ }
+ onode=onode.previousSibling;
+}
+if (otarget) {
+ //you actually have found one, and do something here
+ //alert(otarget.id + "\n" + otarget.tagName); //just to verify
+ top.location = otarget.id;
+} else {
+ //you don't find one
+//alert("nada" + otarget.id);
+}
+}
+
+</script>
+ </head>
+ <body background="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/background.gif" style="margin:0;color:#000000;">
+<div id="home" style="position:absolute;left:0px;top:10px;">
+<a href="/"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/top_read_back.gif" border="0"></a>
+</div>
+<div id="index" style="position:absolute;left:0px;top:150px;">
+<ul>
+<li class="title">MAKING SUGAR ACTIVITIES</li><li id="Introduction"><a href="/ActivitiesGuideSugar/Introduction">INTRODUCTION</a></li><li id="WhatIsSugar"><a href="/ActivitiesGuideSugar/WhatIsSugar">WHAT IS SUGAR?</a></li><li id="WhatisanActivity"><a href="/ActivitiesGuideSugar/WhatisanActivity">WHAT IS A SUGAR ACTIVITY?</a></li><li id="NeedtoKnowWriteSugarActivity"><a href="/ActivitiesGuideSugar/NeedtoKnowWriteSugarActivity">WHAT DO I NEED TO KNOW TO WRITE A SUGAR ACTIVITY?</a></li><li id="SetUpDevEnvironment"><a href="/ActivitiesGuideSugar/SetUpDevEnvironment">SETTING UP A DEVELOPMENT ENVIRONMENT</a></li><li id="CreateFirstActivity"><a href="/ActivitiesGuideSugar/CreateFirstActivity">CREATING YOUR FIRST ACTIVITY</a></li><li id="StandalonePythonReadEtexts"><a href="/ActivitiesGuideSugar/StandalonePythonReadEtexts">MAKING A STANDALONE PYTHON PROGRAM</a></li><li id="InheritFromActivity"><a href="/ActivitiesGuideSugar/InheritFromActivity">INHERIT FROM SUGAR.ACTIVITY.ACTIVITY</a></li><li id="PackageTheActivity"><a href="/ActivitiesGuideSugar/PackageTheActivity">PACKAGE THE ACTIVITY</a></li><li id="AddRefinements"><a href="/ActivitiesGuideSugar/AddRefinements">ADD REFINEMENTS</a></li><li id="UsingVersionControl"><a href="/ActivitiesGuideSugar/UsingVersionControl">ADD YOUR ACTIVITY CODE TO VERSION CONTROL</a></li><li id="Credits"><a href="/ActivitiesGuideSugar/Credits">CREDITS</a></li></ul>
+</div>
+<div id="pdf" style="position:absolute;left:13px;top:190px;">
+<a href="/ActivitiesGuideSugar/FM_06Jan10.pdf"><img class ="non" src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/makepdf.gif" border=0></a>
+<!-- <a href="/ActivitiesGuideSugar/FM_ActivitiesGuideSugar_06Jan10.pdf"><img class ="non" src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/makepdf.gif" border=0></a> -->
+<a href="/ActivitiesGuideSugar/print"><img class="non" src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/viewprint.gif" border=0></a>
+</div>
+ <div style="position:absolute;left:240px;top:11px;">
+ <table id="ds-layout" cellpadding="0" cellspacing="0" sumtop:5px;mary="" style="table-layout:fixed;width:670px;border: 5px solid #666666;padding-right: 0px;padding-left: 0px;padding-bottom: 0px;padding-top: 0px;margin-left : 10px;margin-top:10;background:#FFF7F0;">
+ <tr>
+ <td width=100%>
+<div class="arrow" style="position:relative;left:10px;top:5px;width:50px;float:left;"><a href="#" onClick="previous();"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/lefttext.png" height=20></a></div>
+<div class="arrow" style="position:relative;left:528px;width:50px;top:5px;float:left;"><a href="#" onClick="next();"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/righttext.png" height=20></a></div>
+ <div class="ds-contentcontainer">
+ <div style="margin-left:1.2em;float:right">
+ <br>
+ <div class="huh" style='decoration:none;color:black;border:1;position:absolute;top:60px;left:502px;'>
+ <a href='http://www.flossmanuals.net/bin/view/ActivitiesGuideSugar/InheritFromActivity' onClick="alert('You will now be forwarded to the FLOSS Manuals editing interface')"><b><font color=#ff7f00><small>Edit this page</small></font></b></a> :: <a href='http://www.flossmanuals.net/bin/view/ActivitiesGuideSugar/FMComments?skin=floss2'><b><font color=#ff7f00><small>Discussion</small></font></b></a>
+ </div>
+ <h1>Inherit From sugar.activity.Activity
+</h1>
+<h2>Object Oriented Python
+ <br />
+</h2>
+<p class="western">Python supports two styles of programming: <em>procedural</em> and <em>object oriented</em>. Procedural programming is when you have some input data, do some processing on it, and produce an output. If you want to calculate all the prime numbers under a hundred or convert a Word document into a plain text file you'll probably use the procedural style to do that.
+</p>
+<p class="western">Object oriented programs are built up from units called <em>objects</em>. An object is described as a collection of fields or attributes containing data along with methods for doing things with that data. In addition to doing work and storing data objects can send messages to one another.
+</p>
+<p class="western">Consider a word processing program. It doesn't have just one input, some process, and one output. It can receive input from the keyboard, from the mouse buttons, from the mouse traveling over something, from the clipboard, etc. It can send output to the screen, to a file, to a printer, to the clipboard, etc. A word processor can edit several documents at the same time too. Any program with a GUI is a natural fit for the object oriented style of programming.
+</p>
+<p class="western">Objects are described by <em>classes</em>. When you create an object you are creating an <em>instance</em> of a class.
+</p>
+<p class="western">There's one other thing that a class can do, which is to <em>inherit</em> methods and attributes from another class. When you define a class you can say it <em>extends</em> some class, and by doing that in effect your class has the functionality of the other class plus its own functionality. The extended class becomes its parent.
+ <br />
+</p>
+<p class="western">All Sugar Activities extend a Python class called <em>sugar.activity.Activity</em>. This class provides methods that all Activities need. In addition to that, there are methods that you can override in your own class that the parent class will call when it needs to. For the beginning Activity writer three methods are important:
+</p>
+<p class="western"><em>__init__()</em>
+</p>
+<p class="western">This is called when your Activity is started up. This is where you will set up the user interface for your Activity, including toolbars.
+</p>
+<p class="western"><em>read_file(self, file_path)</em>
+</p>
+<p class="western">This is called when you resume an Activity from a Journal entry. It is called after the <em>__init__()</em> method is called. The file_path parameter contains the name of a temporary file that is a copy of the file in the Journal entry. The file is deleted as soon as this method finishes, but because Sugar runs on Linux if you open the file for reading your program can continue to read it even after it is deleted and it the file will not actually go away until you close it.
+</p>
+<p class="western"><em>write_file(self, file_path)</em>
+</p>
+<p class="western">This is called when the Activity updates the Journal entry. Just like with <em>read_file()</em> your Activity does not work with the Journal directly. Instead it opens the file named in file_path for output and writes to it. That file in turn is copied to the Journal entry.
+</p>
+<p class="western">There are three things that can cause <em>write_file()</em> to be executed:
+</p>
+<ul>
+ <li>
+ <p class="western">Your Activity closes.
+ </p> </li>
+ <li>
+ <p class="western">Someone presses the <strong>Keep</strong> button in the Activity toolbar.
+ </p> </li>
+ <li>
+ <p class="western">Your Activity ceases to be the active Activity, or someone moves from the Activity View to some other View.
+ </p> </li>
+</ul>
+<p class="western">In addition to updating the file in the Journal entry the <em>read_file()</em> and <em>write_file()</em> methods are used to read and update the metadata in the Journal entry.
+</p>
+<p> When we convert our standalone Python program to an Activity we'll take out much of the code we wrote and replace it with code inherited from the sugar.activity.Activity&nbsp; class.
+</p>
+<h2>Extending The Activity Class
+</h2>
+<p>Here's a version of our program that extends Activity:
+</p>
+<pre>import sys
+import os
+import zipfile
+import pygtk
+import gtk
+import pango
+from sugar.activity import activity
+from sugar.graphics import style
+
+page=0
+PAGE_SIZE = 45
+
+class ReadEtextsActivity(activity.Activity):
+ def __init__(self, handle):
+ "The entry point to the Activity"
+ global page
+ activity.Activity.__init__(self, handle)
+
+ toolbox = activity.ActivityToolbox(self)
+ activity_toolbar = toolbox.get_activity_toolbar()
+ activity_toolbar.keep.props.visible = False
+ activity_toolbar.share.props.visible = False
+ self.set_toolbox(toolbox)
+
+ toolbox.show()
+ self.scrolled_window = gtk.ScrolledWindow()
+ self.scrolled_window.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
+ self.scrolled_window.props.shadow_type = gtk.SHADOW_NONE
+
+ self.textview = gtk.TextView()
+ self.textview.set_editable(False)
+ self.textview.set_cursor_visible(False)
+ self.textview.set_left_margin(50)
+ self.textview.connect("key_press_event", self.keypress_cb)
+
+ self.scrolled_window.add(self.textview)
+ self.set_canvas(self.scrolled_window)
+ self.textview.show()
+ self.scrolled_window.show()
+ page = 0
+ self.textview.grab_focus()
+ self.font_desc = pango.FontDescription("sans %d" % style.zoom(10))
+ self.textview.modify_font(self.font_desc)
+
+ def keypress_cb(self, widget, event):
+ "Respond when the user presses one of the arrow keys"
+ keyname = gtk.gdk.keyval_name(event.keyval)
+ print keyname
+ if keyname == 'plus':
+ self.font_increase()
+ return True
+ if keyname == 'minus':
+ self.font_decrease()
+ return True
+ if keyname == 'Page_Up' :
+ self.page_previous()
+ return True
+ if keyname == 'Page_Down':
+ self.page_next()
+ return True
+ if keyname == 'Up' or keyname == 'KP_Up' \
+ or keyname == 'KP_Left':
+ self.scroll_up()
+ return True
+ if keyname == 'Down' or keyname == 'KP_Down' \
+ or keyname == 'KP_Right':
+ self.scroll_down()
+ return True
+ return False
+
+ def page_previous(self):
+ global page
+ page=page-1
+ if page &lt; 0: page=0
+ self.show_page(page)
+ v_adjustment = self.scrolled_window.get_vadjustment()
+ v_adjustment.value = v_adjustment.upper - v_adjustment.page_size
+
+ def page_next(self):
+ global page
+ page=page+1
+ if page &gt;= len(self.page_index): page=0
+ self.show_page(page)
+ v_adjustment = self.scrolled_window.get_vadjustment()
+ v_adjustment.value = v_adjustment.lower
+
+ def font_decrease(self):
+ font_size = self.font_desc.get_size() / 1024
+ font_size = font_size - 1
+ if font_size &lt; 1:
+ font_size = 1
+ self.font_desc.set_size(font_size * 1024)
+ self.textview.modify_font(self.font_desc)
+
+ def font_increase(self):
+ font_size = self.font_desc.get_size() / 1024
+ font_size = font_size + 1
+ self.font_desc.set_size(font_size * 1024)
+ self.textview.modify_font(self.font_desc)
+
+ def scroll_down(self):
+ v_adjustment = self.scrolled_window.get_vadjustment()
+ if v_adjustment.value == v_adjustment.upper - \
+ v_adjustment.page_size:
+ self.page_next()
+ return
+ if v_adjustment.value &lt; v_adjustment.upper - v_adjustment.page_size:
+ new_value = v_adjustment.value + v_adjustment.step_increment
+ if new_value &gt; v_adjustment.upper - v_adjustment.page_size:
+ new_value = v_adjustment.upper - v_adjustment.page_size
+ v_adjustment.value = new_value
+
+ def scroll_up(self):
+ v_adjustment = self.scrolled_window.get_vadjustment()
+ if v_adjustment.value == v_adjustment.lower:
+ self.page_previous()
+ return
+ if v_adjustment.value &gt; v_adjustment.lower:
+ new_value = v_adjustment.value - \
+ v_adjustment.step_increment
+ if new_value &lt; v_adjustment.lower:
+ new_value = v_adjustment.lower
+ v_adjustment.value = new_value
+
+ def show_page(self, page_number):
+ global PAGE_SIZE, current_word
+ position = self.page_index[page_number]
+ self.etext_file.seek(position)
+ linecount = 0
+ label_text = '\n\n\n'
+ textbuffer = self.textview.get_buffer()
+ while linecount &lt; PAGE_SIZE:
+ line = self.etext_file.readline()
+ label_text = label_text + unicode(line, 'iso-8859-1')
+ linecount = linecount + 1
+ label_text = label_text + '\n\n\n'
+ textbuffer.set_text(label_text)
+ self.textview.set_buffer(textbuffer)
+
+ def save_extracted_file(self, zipfile, filename):
+ "Extract the file to a temp directory for viewing"
+ filebytes = zipfile.read(filename)
+ outfn = self.make_new_filename(filename)
+ if (outfn == ''):
+ return False
+ f = open(os.path.join(self.get_activity_root(), 'instance', outfn), 'w')
+ try:
+ f.write(filebytes)
+ finally:
+ f.close
+
+ def read_file(self, filename):
+ "Read the Etext file"
+ global PAGE_SIZE
+
+ if zipfile.is_zipfile(filename):
+ self.zf = zipfile.ZipFile(filename, 'r')
+ self.book_files = self.zf.namelist()
+ self.save_extracted_file(self.zf, self.book_files[0])
+ currentFileName = os.path.join(self.get_activity_root(),\
+ 'instance', self.book_files[0])
+ else:
+ currentFileName = filename
+
+ self.etext_file = open(currentFileName,"r")
+ self.page_index = [ 0 ]
+ linecount = 0
+ while self.etext_file:
+ line = self.etext_file.readline()
+ if not line:
+ break
+ linecount = linecount + 1
+ if linecount &gt;= PAGE_SIZE:
+ position = self.etext_file.tell()
+ self.page_index.append(position)
+ linecount = 0
+ if filename.endswith(".zip"):
+ os.remove(currentFileName)
+ self.show_page(0)
+
+ def make_new_filename(self, filename):
+ partition_tuple = filename.rpartition('/')
+ return partition_tuple[2]
+
+
+</pre>
+<p>This program has some significant differences from the standalone version.&nbsp; First, note that this line:
+</p>
+<pre>#! /usr/bin/env python
+</pre>
+<p>has been removed.&nbsp; We are no longer running the program directly from the Python interpreter.&nbsp; Now Sugar is running it as an Activity.&nbsp; Notice that much (but not all) of what was in the main() method has been moved to the <em>__init__()</em> method and the <em>main()</em> method has been removed.
+</p>
+<p>Notice too that the <em>class</em> statement has changed:
+</p>
+<p>
+</p>
+<pre>class ReadEtextsActivity(activity.Activity)
+</pre>
+<p>This statement now tells us that class ReadEtextsActivity extends the class <strong>sugar.activity.Activity</strong>.&nbsp;&nbsp; As a result it inherits the code that is in that class.&nbsp; Therefore we no longer need a GTK main loop, or to define a window.&nbsp; The code in this class we extend will do that for us.
+</p>
+<p> While we gain much from this inheritance, we lose something too: a title bar for the main window.&nbsp; In a graphical operating environment a piece of software called a <em>window manager</em> is responsible for putting borders on windows, making them resizeable, reducing them to icons, maximizing them, etc.&nbsp; Sugar uses a window manager named Matchbox which makes each window fill the whole screen and puts no border, title bar, or any other window decorations on the windows.&nbsp;&nbsp; As a result of that we can't close our application by clicking on the "X" in the title bar as before.&nbsp; To make up for this we need to have a toolbar that contains a Close button.&nbsp; Thus every Activity has an Activity toolbar that contains some standard controls and buttons.&nbsp; If you look at the code you'll see I'm hiding a couple of controls which we have no use for yet.
+</p>
+<p>The <em>read_file()</em> method is no longer called from the main() method and doesn't seem to be called from anywhere in the program.&nbsp; Of course it does get called, by some of the Activity code we inherited from our new parent class.&nbsp; Similarly the <em>__init__() </em>and <em>write_file() </em>methods (if we had a <em>write_file()</em> method) get called by the parent Activity class.
+</p>
+<p>If you're especially observant you might have noticed another change.&nbsp; Our original standalone program created a temporary file when it needed to extract something from a Zip file.&nbsp; It put that file in a directory called /tmp.&nbsp; Our new Activity still creates the file but puts it in a different directory, one specific to the Activity.
+ <br />
+</p>
+<p>Making these changes to the code is not enough to make our program an Activity.&nbsp; We have to do some packaging work and get it set up to run from the Sugar emulator.&nbsp; We also need to learn how to run the Sugar emulator.&nbsp; That comes next!
+ <br />
+</p>
+<p />
+ </p></div>
+ </div>
+<div class="arrow" style="position:relative;left:10px;width:50px;float:left;bottom:5px;"><a href="#" onClick="previous();"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/lefttext.png" height=20></a></div>
+<div class="arrow" style="position:relative;left:528px;width:50px;float:left;bottom:5px;"><a href="#" onClick="next();"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/righttext.png" height=20></a></div>
+ <br>
+ <br>
+ <br>
+ <br>
+ </td>
+ </tr>
+ </table>
+ </div>
+<!-- Piwik -->
+<a href="http://piwik.org" title="Web analytics" onclick="window.open(this.href);return(false);">
+<script language="javascript" src="http://adam.engagetv.com/piwik/piwik.js" type="text/javascript"></script>
+<script type="text/javascript">
+<!--
+piwik_action_name = '';
+piwik_idsite = 1;
+piwik_url = 'http://adam.engagetv.com/piwik/piwik.php';
+piwik_log(piwik_action_name, piwik_idsite, piwik_url);
+//-->
+</script>
+<!-- /Piwik -->
+<script language="Javascript">
+document.getElementById("InheritFromActivity").style.backgroundColor="#F99B1C";
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/help/ActivityBook/ActivitiesGuideSugar/Introduction b/help/ActivityBook/ActivitiesGuideSugar/Introduction
new file mode 100644
index 0000000..2c50d7f
--- /dev/null
+++ b/help/ActivityBook/ActivitiesGuideSugar/Introduction
@@ -0,0 +1,252 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html>
+ <head>
+ <title>ActivitiesGuideSugar (en)</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <!--
+ <link rel="alternate" type="application/rss+xml" title="RSS Feed" href="WebRss.html" />
+ -->
+ <link rel="icon" href="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/fl2.ico" type="image/x-icon" /> <link rel="shortcut icon" href="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/fl2.ico" type="image/x-icon" />
+ <link rel=StyleSheet href="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/typography.css" type="text/css" media="screen">
+<style>
+#index {
+ color: #ff7f00;
+ font-family: trebuchet,sans-serif;
+ font-size: 10px;
+ line-height:11px;
+}
+#index UL {
+ width: 159px;
+ list-style-type: None;
+ padding-left: 0px;
+ border: 14px solid #ff7f00;
+ background-color: #ff7f00;
+ margin: 0px 0px 0px 0px;
+ }
+#index LI {
+ padding-left: 0px;
+ padding-right: 10px;
+ padding-top: 4px;
+ padding-bottom: 4px;
+ color: #ffffff;
+ margin: 0px 0px 0px 0px;
+ background-color: #ff7f00;
+ border-top: 1px solid #ff7f00;
+ }
+#index LI:hover {
+ background-color: #F99B1C;
+}
+#index LI.heading {
+ background-color: #ff7f00;
+ color: #000000;
+ border-top:1px solid #FFE5CC;
+ padding-top: 7px;
+ font-weight: bold;
+}
+#index LI.title {
+ border-bottom: 2px solid #FFE5CC;
+ background-color: #ff7f00;
+ color: #FBF4E9;
+ font-weight: bolder;
+ font-size:10px;
+ line-height:18px;
+ padding-bottom: 40px;
+ }
+#index A {
+ text-decoration: none;
+ color: #FBF4E9;
+ font-weight: bold;
+}
+#ds-layout .imgcontainer {
+ position:relative;
+ }
+#ds-layout .caption {
+ position:relative;
+ bottom:1;
+ left:0;
+ text-align:center;
+ background:#ffe7cb;
+ width:100%;
+ opacity:.75;
+ filter:alpha(opacity=85);
+ color:#000;
+ font-style: italic;
+ font-size: 9px;
+ line-height:11px;
+ }
+</style>
+<script type="text/javascript">
+function addLoadEvent(func) {
+ var oldonload = window.onload;
+ if (typeof window.onload != 'function') {
+ window.onload = func;
+ } else {
+ window.onload = function() {
+ oldonload();
+ func();
+ }
+ }
+}
+
+function insertAfter(newElement,targetElement) {
+ var parent = targetElement.parentNode;
+ if (parent.lastChild == targetElement) {
+ parent.appendChild(newElement);
+ } else {
+ parent.insertBefore(newElement,targetElement.nextSibling);
+ }
+}
+
+function captionizeImages() {
+ if (!document.getElementsByTagName) return false;
+ if (!document.createElement) return false;
+ var images = document.getElementsByTagName("img");
+ if (images.length < 1) return false;
+ for (var i=0; i<images.length; i++) {
+ if (images[i].className != "non") {
+ var title = images[i].getAttribute("title");
+ var width = images[i].width;
+ var divCaption = document.createElement("div");
+ divCaption.className="caption";
+ divCaption.style.width=width+'px';
+ if (title) divCaption.style.padding='2px 0px 3px 0px';
+ divCaption.style.display='block';
+ var divCaption_text = document.createTextNode(title);
+ divCaption.appendChild(divCaption_text);
+ var divContainer = document.createElement("div");
+ divContainer.className="imgcontainer";
+ if (title) divContainer.style.padding='0px 0px 10px 0px';
+ images[i].parentNode.insertBefore(divContainer,images[i]);
+ divContainer.appendChild(images[i]);
+ insertAfter(divCaption,images[i]);
+ }
+ }
+}
+//addLoadEvent(captionizeImages);
+
+function next () {
+var onode, otarget;
+onode=document.getElementById("Introduction");
+if (onode.id=="Credits") die;
+//alert (onode.id);
+onode=onode.nextSibling;
+if (onode.id=="heading") onode=onode.nextSibling;
+while (onode) {
+ //onode=onode.nextSibling;
+ if (onode.nodeType==1) {
+ //alert (onode.id);
+ otarget=onode;
+ break;
+ }
+ onode=onode.nextSibling;
+}
+if (otarget) {
+ //you actually have found one, and do something here
+ //alert(otarget.id + "\n" + otarget.tagName); //just to verify
+ top.location = "/ActivitiesGuideSugar/" + otarget.id;
+} else {
+ //you don't find one
+//alert("nada" + otarget.id);
+}
+}
+
+function previous () {
+var onode, otarget;
+onode=document.getElementById("Introduction");
+if (onode.id=="Introduction") die;
+//alert (onode.id);
+onode=onode.previousSibling;
+if (onode.id=="heading") onode=onode.previousSibling;
+if (onode.id=="title") die;
+while (onode) {
+ //onode=onode.previousSibling;
+ if (onode.nodeType==1) {
+ //alert (onode.id);
+ otarget=onode;
+ break;
+ }
+ onode=onode.previousSibling;
+}
+if (otarget) {
+ //you actually have found one, and do something here
+ //alert(otarget.id + "\n" + otarget.tagName); //just to verify
+ top.location = otarget.id;
+} else {
+ //you don't find one
+//alert("nada" + otarget.id);
+}
+}
+
+</script>
+ </head>
+ <body background="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/background.gif" style="margin:0;color:#000000;">
+<div id="home" style="position:absolute;left:0px;top:10px;">
+<a href="/"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/top_read_back.gif" border="0"></a>
+</div>
+<div id="index" style="position:absolute;left:0px;top:150px;">
+<ul>
+<li class="title">MAKING SUGAR ACTIVITIES</li><li id="Introduction"><a href="/ActivitiesGuideSugar/Introduction">INTRODUCTION</a></li><li id="WhatIsSugar"><a href="/ActivitiesGuideSugar/WhatIsSugar">WHAT IS SUGAR?</a></li><li id="WhatisanActivity"><a href="/ActivitiesGuideSugar/WhatisanActivity">WHAT IS A SUGAR ACTIVITY?</a></li><li id="NeedtoKnowWriteSugarActivity"><a href="/ActivitiesGuideSugar/NeedtoKnowWriteSugarActivity">WHAT DO I NEED TO KNOW TO WRITE A SUGAR ACTIVITY?</a></li><li id="SetUpDevEnvironment"><a href="/ActivitiesGuideSugar/SetUpDevEnvironment">SETTING UP A DEVELOPMENT ENVIRONMENT</a></li><li id="CreateFirstActivity"><a href="/ActivitiesGuideSugar/CreateFirstActivity">CREATING YOUR FIRST ACTIVITY</a></li><li id="StandalonePythonReadEtexts"><a href="/ActivitiesGuideSugar/StandalonePythonReadEtexts">MAKING A STANDALONE PYTHON PROGRAM</a></li><li id="InheritFromActivity"><a href="/ActivitiesGuideSugar/InheritFromActivity">INHERIT FROM SUGAR.ACTIVITY.ACTIVITY</a></li><li id="PackageTheActivity"><a href="/ActivitiesGuideSugar/PackageTheActivity">PACKAGE THE ACTIVITY</a></li><li id="AddRefinements"><a href="/ActivitiesGuideSugar/AddRefinements">ADD REFINEMENTS</a></li><li id="UsingVersionControl"><a href="/ActivitiesGuideSugar/UsingVersionControl">ADD YOUR ACTIVITY CODE TO VERSION CONTROL</a></li><li id="Credits"><a href="/ActivitiesGuideSugar/Credits">CREDITS</a></li></ul>
+</div>
+<div id="pdf" style="position:absolute;left:13px;top:190px;">
+<a href="/ActivitiesGuideSugar/FM_06Jan10.pdf"><img class ="non" src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/makepdf.gif" border=0></a>
+<!-- <a href="/ActivitiesGuideSugar/FM_ActivitiesGuideSugar_06Jan10.pdf"><img class ="non" src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/makepdf.gif" border=0></a> -->
+<a href="/ActivitiesGuideSugar/print"><img class="non" src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/viewprint.gif" border=0></a>
+</div>
+ <div style="position:absolute;left:240px;top:11px;">
+ <table id="ds-layout" cellpadding="0" cellspacing="0" sumtop:5px;mary="" style="table-layout:fixed;width:670px;border: 5px solid #666666;padding-right: 0px;padding-left: 0px;padding-bottom: 0px;padding-top: 0px;margin-left : 10px;margin-top:10;background:#FFF7F0;">
+ <tr>
+ <td width=100%>
+<div class="arrow" style="position:relative;left:10px;top:5px;width:50px;float:left;"><a href="#" onClick="previous();"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/lefttext.png" height=20></a></div>
+<div class="arrow" style="position:relative;left:528px;width:50px;top:5px;float:left;"><a href="#" onClick="next();"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/righttext.png" height=20></a></div>
+ <div class="ds-contentcontainer">
+ <div style="margin-left:1.2em;float:right">
+ <br>
+ <div class="huh" style='decoration:none;color:black;border:1;position:absolute;top:60px;left:502px;'>
+ <a href='http://www.flossmanuals.net/bin/view/ActivitiesGuideSugar/Introduction' onClick="alert('You will now be forwarded to the FLOSS Manuals editing interface')"><b><font color=#ff7f00><small>Edit this page</small></font></b></a> :: <a href='http://www.flossmanuals.net/bin/view/ActivitiesGuideSugar/FMComments?skin=floss2'><b><font color=#ff7f00><small>Discussion</small></font></b></a>
+ </div>
+ <h1>Introduction
+</h1>
+<p>The purpose of this book is to teach you what you need to know to write Activities for Sugar, the operating environment developed for the One Laptop Per Child project. This book does not assume that you know how to program a computer. It is my hope that this book will be helpful to those just starting out in programming.
+</p>
+<p>If you just want to learn how to write computer programs Sugar provides many Activities to help you do that: Etoys, Turtle Art, Scratch, and Pippy. None of these are really suitable for creating Activities so I won't cover them in this book, but they're a great way to learn about programming. If you decide after playing with these that you'd like to try writing an Activity after all you'll have a good foundation of knowledge to build on.
+</p>
+<p>If you have done some programming then you know how satisfying it can be to use a program that you made yourself, one that does exactly what you want it to do.&nbsp; Creating a Sugar Activity takes that enjoyment to the next level.&nbsp; A useful Sugar Activity can be translated by volunteers into every language, be downloaded hundreds of times a week and used every day by students all over the world.
+ <br />
+</p>
+<p>A book that teaches <em>everything</em> you need to know to write Activities would be really, really long and would duplicate material that is already available elsewhere. Because of this, I am going to write this as sort of a guided tour of Activity development. That means, for example, that I'll teach you what Python is and why it's important to learn it but I won't teach you the Python language itself. There is an excellent tutorial on the Internet that will do that, and I'll refer you to that tutorial.
+</p>
+<p>I started writing Activities shortly after I received my XO laptop. When I started I didn't know <em>any</em> of the material that will be in this book. I had a hard time knowing where to begin. What I did have going for me though was a little less than 30 years as a professional programmer. As a result of that I think like a programmer. A good programmer can take a complex task and divide it up into manageable pieces. He can figure out how things <em>must</em> work, and from that figure out how they <em>do</em> work. He knows how to ask for help and where. If there is no obvious place to begin he can begin <em>somewhere</em> and eventually get where he needs to go.
+</p>
+<p>Because I went through this process I think I can be a pretty good guide to writing Sugar Activities. I hope to also teach you how to think like a programmer does.
+</p>
+<p />
+ </p></div>
+ </div>
+<div class="arrow" style="position:relative;left:10px;width:50px;float:left;bottom:5px;"><a href="#" onClick="previous();"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/lefttext.png" height=20></a></div>
+<div class="arrow" style="position:relative;left:528px;width:50px;float:left;bottom:5px;"><a href="#" onClick="next();"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/righttext.png" height=20></a></div>
+ <br>
+ <br>
+ <br>
+ <br>
+ </td>
+ </tr>
+ </table>
+ </div>
+<!-- Piwik -->
+<a href="http://piwik.org" title="Web analytics" onclick="window.open(this.href);return(false);">
+<script language="javascript" src="http://adam.engagetv.com/piwik/piwik.js" type="text/javascript"></script>
+<script type="text/javascript">
+<!--
+piwik_action_name = '';
+piwik_idsite = 1;
+piwik_url = 'http://adam.engagetv.com/piwik/piwik.php';
+piwik_log(piwik_action_name, piwik_idsite, piwik_url);
+//-->
+</script>
+<!-- /Piwik -->
+<script language="Javascript">
+document.getElementById("Introduction").style.backgroundColor="#F99B1C";
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/help/ActivityBook/ActivitiesGuideSugar/NeedtoKnowWriteSugarActivity b/help/ActivityBook/ActivitiesGuideSugar/NeedtoKnowWriteSugarActivity
new file mode 100644
index 0000000..6c2bdae
--- /dev/null
+++ b/help/ActivityBook/ActivitiesGuideSugar/NeedtoKnowWriteSugarActivity
@@ -0,0 +1,284 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html>
+ <head>
+ <title>ActivitiesGuideSugar (en)</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <!--
+ <link rel="alternate" type="application/rss+xml" title="RSS Feed" href="WebRss.html" />
+ -->
+ <link rel="icon" href="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/fl2.ico" type="image/x-icon" /> <link rel="shortcut icon" href="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/fl2.ico" type="image/x-icon" />
+ <link rel=StyleSheet href="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/typography.css" type="text/css" media="screen">
+<style>
+#index {
+ color: #ff7f00;
+ font-family: trebuchet,sans-serif;
+ font-size: 10px;
+ line-height:11px;
+}
+#index UL {
+ width: 159px;
+ list-style-type: None;
+ padding-left: 0px;
+ border: 14px solid #ff7f00;
+ background-color: #ff7f00;
+ margin: 0px 0px 0px 0px;
+ }
+#index LI {
+ padding-left: 0px;
+ padding-right: 10px;
+ padding-top: 4px;
+ padding-bottom: 4px;
+ color: #ffffff;
+ margin: 0px 0px 0px 0px;
+ background-color: #ff7f00;
+ border-top: 1px solid #ff7f00;
+ }
+#index LI:hover {
+ background-color: #F99B1C;
+}
+#index LI.heading {
+ background-color: #ff7f00;
+ color: #000000;
+ border-top:1px solid #FFE5CC;
+ padding-top: 7px;
+ font-weight: bold;
+}
+#index LI.title {
+ border-bottom: 2px solid #FFE5CC;
+ background-color: #ff7f00;
+ color: #FBF4E9;
+ font-weight: bolder;
+ font-size:10px;
+ line-height:18px;
+ padding-bottom: 40px;
+ }
+#index A {
+ text-decoration: none;
+ color: #FBF4E9;
+ font-weight: bold;
+}
+#ds-layout .imgcontainer {
+ position:relative;
+ }
+#ds-layout .caption {
+ position:relative;
+ bottom:1;
+ left:0;
+ text-align:center;
+ background:#ffe7cb;
+ width:100%;
+ opacity:.75;
+ filter:alpha(opacity=85);
+ color:#000;
+ font-style: italic;
+ font-size: 9px;
+ line-height:11px;
+ }
+</style>
+<script type="text/javascript">
+function addLoadEvent(func) {
+ var oldonload = window.onload;
+ if (typeof window.onload != 'function') {
+ window.onload = func;
+ } else {
+ window.onload = function() {
+ oldonload();
+ func();
+ }
+ }
+}
+
+function insertAfter(newElement,targetElement) {
+ var parent = targetElement.parentNode;
+ if (parent.lastChild == targetElement) {
+ parent.appendChild(newElement);
+ } else {
+ parent.insertBefore(newElement,targetElement.nextSibling);
+ }
+}
+
+function captionizeImages() {
+ if (!document.getElementsByTagName) return false;
+ if (!document.createElement) return false;
+ var images = document.getElementsByTagName("img");
+ if (images.length < 1) return false;
+ for (var i=0; i<images.length; i++) {
+ if (images[i].className != "non") {
+ var title = images[i].getAttribute("title");
+ var width = images[i].width;
+ var divCaption = document.createElement("div");
+ divCaption.className="caption";
+ divCaption.style.width=width+'px';
+ if (title) divCaption.style.padding='2px 0px 3px 0px';
+ divCaption.style.display='block';
+ var divCaption_text = document.createTextNode(title);
+ divCaption.appendChild(divCaption_text);
+ var divContainer = document.createElement("div");
+ divContainer.className="imgcontainer";
+ if (title) divContainer.style.padding='0px 0px 10px 0px';
+ images[i].parentNode.insertBefore(divContainer,images[i]);
+ divContainer.appendChild(images[i]);
+ insertAfter(divCaption,images[i]);
+ }
+ }
+}
+//addLoadEvent(captionizeImages);
+
+function next () {
+var onode, otarget;
+onode=document.getElementById("NeedtoKnowWriteSugarActivity");
+if (onode.id=="Credits") die;
+//alert (onode.id);
+onode=onode.nextSibling;
+if (onode.id=="heading") onode=onode.nextSibling;
+while (onode) {
+ //onode=onode.nextSibling;
+ if (onode.nodeType==1) {
+ //alert (onode.id);
+ otarget=onode;
+ break;
+ }
+ onode=onode.nextSibling;
+}
+if (otarget) {
+ //you actually have found one, and do something here
+ //alert(otarget.id + "\n" + otarget.tagName); //just to verify
+ top.location = "/ActivitiesGuideSugar/" + otarget.id;
+} else {
+ //you don't find one
+//alert("nada" + otarget.id);
+}
+}
+
+function previous () {
+var onode, otarget;
+onode=document.getElementById("NeedtoKnowWriteSugarActivity");
+if (onode.id=="Introduction") die;
+//alert (onode.id);
+onode=onode.previousSibling;
+if (onode.id=="heading") onode=onode.previousSibling;
+if (onode.id=="title") die;
+while (onode) {
+ //onode=onode.previousSibling;
+ if (onode.nodeType==1) {
+ //alert (onode.id);
+ otarget=onode;
+ break;
+ }
+ onode=onode.previousSibling;
+}
+if (otarget) {
+ //you actually have found one, and do something here
+ //alert(otarget.id + "\n" + otarget.tagName); //just to verify
+ top.location = otarget.id;
+} else {
+ //you don't find one
+//alert("nada" + otarget.id);
+}
+}
+
+</script>
+ </head>
+ <body background="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/background.gif" style="margin:0;color:#000000;">
+<div id="home" style="position:absolute;left:0px;top:10px;">
+<a href="/"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/top_read_back.gif" border="0"></a>
+</div>
+<div id="index" style="position:absolute;left:0px;top:150px;">
+<ul>
+<li class="title">MAKING SUGAR ACTIVITIES</li><li id="Introduction"><a href="/ActivitiesGuideSugar/Introduction">INTRODUCTION</a></li><li id="WhatIsSugar"><a href="/ActivitiesGuideSugar/WhatIsSugar">WHAT IS SUGAR?</a></li><li id="WhatisanActivity"><a href="/ActivitiesGuideSugar/WhatisanActivity">WHAT IS A SUGAR ACTIVITY?</a></li><li id="NeedtoKnowWriteSugarActivity"><a href="/ActivitiesGuideSugar/NeedtoKnowWriteSugarActivity">WHAT DO I NEED TO KNOW TO WRITE A SUGAR ACTIVITY?</a></li><li id="SetUpDevEnvironment"><a href="/ActivitiesGuideSugar/SetUpDevEnvironment">SETTING UP A DEVELOPMENT ENVIRONMENT</a></li><li id="CreateFirstActivity"><a href="/ActivitiesGuideSugar/CreateFirstActivity">CREATING YOUR FIRST ACTIVITY</a></li><li id="StandalonePythonReadEtexts"><a href="/ActivitiesGuideSugar/StandalonePythonReadEtexts">MAKING A STANDALONE PYTHON PROGRAM</a></li><li id="InheritFromActivity"><a href="/ActivitiesGuideSugar/InheritFromActivity">INHERIT FROM SUGAR.ACTIVITY.ACTIVITY</a></li><li id="PackageTheActivity"><a href="/ActivitiesGuideSugar/PackageTheActivity">PACKAGE THE ACTIVITY</a></li><li id="AddRefinements"><a href="/ActivitiesGuideSugar/AddRefinements">ADD REFINEMENTS</a></li><li id="UsingVersionControl"><a href="/ActivitiesGuideSugar/UsingVersionControl">ADD YOUR ACTIVITY CODE TO VERSION CONTROL</a></li><li id="Credits"><a href="/ActivitiesGuideSugar/Credits">CREDITS</a></li></ul>
+</div>
+<div id="pdf" style="position:absolute;left:13px;top:190px;">
+<a href="/ActivitiesGuideSugar/FM_06Jan10.pdf"><img class ="non" src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/makepdf.gif" border=0></a>
+<!-- <a href="/ActivitiesGuideSugar/FM_ActivitiesGuideSugar_06Jan10.pdf"><img class ="non" src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/makepdf.gif" border=0></a> -->
+<a href="/ActivitiesGuideSugar/print"><img class="non" src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/viewprint.gif" border=0></a>
+</div>
+ <div style="position:absolute;left:240px;top:11px;">
+ <table id="ds-layout" cellpadding="0" cellspacing="0" sumtop:5px;mary="" style="table-layout:fixed;width:670px;border: 5px solid #666666;padding-right: 0px;padding-left: 0px;padding-bottom: 0px;padding-top: 0px;margin-left : 10px;margin-top:10;background:#FFF7F0;">
+ <tr>
+ <td width=100%>
+<div class="arrow" style="position:relative;left:10px;top:5px;width:50px;float:left;"><a href="#" onClick="previous();"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/lefttext.png" height=20></a></div>
+<div class="arrow" style="position:relative;left:528px;width:50px;top:5px;float:left;"><a href="#" onClick="next();"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/righttext.png" height=20></a></div>
+ <div class="ds-contentcontainer">
+ <div style="margin-left:1.2em;float:right">
+ <br>
+ <div class="huh" style='decoration:none;color:black;border:1;position:absolute;top:60px;left:502px;'>
+ <a href='http://www.flossmanuals.net/bin/view/ActivitiesGuideSugar/NeedtoKnowWriteSugarActivity' onClick="alert('You will now be forwarded to the FLOSS Manuals editing interface')"><b><font color=#ff7f00><small>Edit this page</small></font></b></a> :: <a href='http://www.flossmanuals.net/bin/view/ActivitiesGuideSugar/FMComments?skin=floss2'><b><font color=#ff7f00><small>Discussion</small></font></b></a>
+ </div>
+ <h1>What Do I Need To Know To Write A Sugar Activity?&nbsp;
+</h1>
+<p class="western">If you are going to write Sugar Activities you should learn something about the topics described in this chapter. There is no need to become an expert in any of them, but you should bookmark their websites and skim through their tutorials. This will help you to understand the code samples we'll be looking at.
+</p>
+<h2 class="western">Python
+</h2>
+<p class="western">Python is the most used language for writing Activities. Every Activity has at least some Python in it.
+</p>
+<p class="western">There are compiled languages and interpreted languages. In a compiled language the code you write is translated into the language of the chip it will run on and it is this translation that is actually run by the OS. In an interpreted language there is a program called an interpreter that reads the code you write and does what the code tells it to do. (This is over simplified, but close enough to the truth for this chapter).
+</p>
+<p class="western">Python is an interpreted language. There are advantages to having a language that is compiled and there are advantages to having an interpreted language. The advantages Python has for developing Activities are:
+</p>
+<ul>
+ <li>
+ <p class="western">It is portable. In other words, you can make your program run on any chip and any OS without making a version specific to each one. Compiled programs only run on the OS and chip they are compiled for.
+ </p> </li>
+ <li>
+ <p class="western">Since the source code is the thing being run, you can't give someone a Python program without giving them the source code. You can learn a lot about Activity programming by studying other people's code, and there is plenty of it to study.
+ </p> </li>
+ <li>
+ <p class="western">It is an easy language for new programmers to learn, but has language features that experienced programmers demand.
+ </p> </li>
+ <li>
+ <p class="western">It is widely used. One of the best known Python users is Google. They use it enough that they have started a project named “Unladen Swallow†to make Python programs run faster.
+ </p> </li>
+</ul>
+<p class="western">The big advantage of a compiled language is that it can run much faster than an interpreted language. In actual practice a Python program can perform as well as a compiled program. To understand why this is you need to understand how a Python program is made.
+</p>
+<p class="western">Python is known as a “glue†language. The idea is that you have components written in various languages (usually C and C++) and they have Python bindings. Python is used to “glue†these components together to create applications. In most applications the bulk of the application's function is done by these compiled components, and the application spends relatively little time running the Python code that glues the components together.
+</p>
+<p class="western">In addition to Activities using Python most of the Sugar environment itself is written in Python.
+</p>
+<p class="western">If you have programmed in other languages before there is a good tutorial for learning Python at the Python website: <a href="http://docs.python.org/tutorial/">http://docs.python.org/tutorial/</a>.&nbsp; If you're just starting out in programming you might check out <em>Invent Your Own Computer Games With Python</em>, which you can read for free at <a href="http://inventwithpython.com/" target="_top">http://inventwithpython.com/</a>.
+ <br />
+</p>
+<h2 class="western">PyGTK
+</h2>
+<p class="western">GTK+ is a set of components for creating user interfaces. These components include things like buttons, scroll bars, list boxes, and so on. It is used by GNOME desktop environment and the applications that run under it. Sugar Activities use a special GNOME theme that give GTK+ controls a unique look.
+</p>
+<p class="western">PyGTK is a set of Python bindings that let you use GTK+ components in Python programs. There is a tutorial showing how to use it at the PyGTK website: <a href="http://www.pygtk.org/tutorial.html">http://www.pygtk.org/tutorial.html</a>.
+</p>
+<h2 class="western">PyGame
+</h2>
+<p class="western">The alternative to using PyGTK for your Activity is PyGame. PyGame can create images called sprites and move them around on the screen. As you might expect, PyGame is mostly used for writing games. It is less commonly used in Activities than PyGTK.
+</p>
+<p class="western">The tutorial to learn about PyGame is at the PyGame website: <a href="http://www.pygame.org/wiki/tutorials">http://www.pygame.org/wiki/tutorials</a>. The website also has a bunch of pygame projects you can download and try out.
+</p>
+<p />
+ </p></div>
+ </div>
+<div class="arrow" style="position:relative;left:10px;width:50px;float:left;bottom:5px;"><a href="#" onClick="previous();"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/lefttext.png" height=20></a></div>
+<div class="arrow" style="position:relative;left:528px;width:50px;float:left;bottom:5px;"><a href="#" onClick="next();"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/righttext.png" height=20></a></div>
+ <br>
+ <br>
+ <br>
+ <br>
+ </td>
+ </tr>
+ </table>
+ </div>
+<!-- Piwik -->
+<a href="http://piwik.org" title="Web analytics" onclick="window.open(this.href);return(false);">
+<script language="javascript" src="http://adam.engagetv.com/piwik/piwik.js" type="text/javascript"></script>
+<script type="text/javascript">
+<!--
+piwik_action_name = '';
+piwik_idsite = 1;
+piwik_url = 'http://adam.engagetv.com/piwik/piwik.php';
+piwik_log(piwik_action_name, piwik_idsite, piwik_url);
+//-->
+</script>
+<!-- /Piwik -->
+<script language="Javascript">
+document.getElementById("NeedtoKnowWriteSugarActivity").style.backgroundColor="#F99B1C";
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/help/ActivityBook/ActivitiesGuideSugar/PackageTheActivity b/help/ActivityBook/ActivitiesGuideSugar/PackageTheActivity
new file mode 100644
index 0000000..26d2aef
--- /dev/null
+++ b/help/ActivityBook/ActivitiesGuideSugar/PackageTheActivity
@@ -0,0 +1,462 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html>
+ <head>
+ <title>ActivitiesGuideSugar (en)</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <!--
+ <link rel="alternate" type="application/rss+xml" title="RSS Feed" href="WebRss.html" />
+ -->
+ <link rel="icon" href="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/fl2.ico" type="image/x-icon" /> <link rel="shortcut icon" href="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/fl2.ico" type="image/x-icon" />
+ <link rel=StyleSheet href="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/typography.css" type="text/css" media="screen">
+<style>
+#index {
+ color: #ff7f00;
+ font-family: trebuchet,sans-serif;
+ font-size: 10px;
+ line-height:11px;
+}
+#index UL {
+ width: 159px;
+ list-style-type: None;
+ padding-left: 0px;
+ border: 14px solid #ff7f00;
+ background-color: #ff7f00;
+ margin: 0px 0px 0px 0px;
+ }
+#index LI {
+ padding-left: 0px;
+ padding-right: 10px;
+ padding-top: 4px;
+ padding-bottom: 4px;
+ color: #ffffff;
+ margin: 0px 0px 0px 0px;
+ background-color: #ff7f00;
+ border-top: 1px solid #ff7f00;
+ }
+#index LI:hover {
+ background-color: #F99B1C;
+}
+#index LI.heading {
+ background-color: #ff7f00;
+ color: #000000;
+ border-top:1px solid #FFE5CC;
+ padding-top: 7px;
+ font-weight: bold;
+}
+#index LI.title {
+ border-bottom: 2px solid #FFE5CC;
+ background-color: #ff7f00;
+ color: #FBF4E9;
+ font-weight: bolder;
+ font-size:10px;
+ line-height:18px;
+ padding-bottom: 40px;
+ }
+#index A {
+ text-decoration: none;
+ color: #FBF4E9;
+ font-weight: bold;
+}
+#ds-layout .imgcontainer {
+ position:relative;
+ }
+#ds-layout .caption {
+ position:relative;
+ bottom:1;
+ left:0;
+ text-align:center;
+ background:#ffe7cb;
+ width:100%;
+ opacity:.75;
+ filter:alpha(opacity=85);
+ color:#000;
+ font-style: italic;
+ font-size: 9px;
+ line-height:11px;
+ }
+</style>
+<script type="text/javascript">
+function addLoadEvent(func) {
+ var oldonload = window.onload;
+ if (typeof window.onload != 'function') {
+ window.onload = func;
+ } else {
+ window.onload = function() {
+ oldonload();
+ func();
+ }
+ }
+}
+
+function insertAfter(newElement,targetElement) {
+ var parent = targetElement.parentNode;
+ if (parent.lastChild == targetElement) {
+ parent.appendChild(newElement);
+ } else {
+ parent.insertBefore(newElement,targetElement.nextSibling);
+ }
+}
+
+function captionizeImages() {
+ if (!document.getElementsByTagName) return false;
+ if (!document.createElement) return false;
+ var images = document.getElementsByTagName("img");
+ if (images.length < 1) return false;
+ for (var i=0; i<images.length; i++) {
+ if (images[i].className != "non") {
+ var title = images[i].getAttribute("title");
+ var width = images[i].width;
+ var divCaption = document.createElement("div");
+ divCaption.className="caption";
+ divCaption.style.width=width+'px';
+ if (title) divCaption.style.padding='2px 0px 3px 0px';
+ divCaption.style.display='block';
+ var divCaption_text = document.createTextNode(title);
+ divCaption.appendChild(divCaption_text);
+ var divContainer = document.createElement("div");
+ divContainer.className="imgcontainer";
+ if (title) divContainer.style.padding='0px 0px 10px 0px';
+ images[i].parentNode.insertBefore(divContainer,images[i]);
+ divContainer.appendChild(images[i]);
+ insertAfter(divCaption,images[i]);
+ }
+ }
+}
+//addLoadEvent(captionizeImages);
+
+function next () {
+var onode, otarget;
+onode=document.getElementById("PackageTheActivity");
+if (onode.id=="Credits") die;
+//alert (onode.id);
+onode=onode.nextSibling;
+if (onode.id=="heading") onode=onode.nextSibling;
+while (onode) {
+ //onode=onode.nextSibling;
+ if (onode.nodeType==1) {
+ //alert (onode.id);
+ otarget=onode;
+ break;
+ }
+ onode=onode.nextSibling;
+}
+if (otarget) {
+ //you actually have found one, and do something here
+ //alert(otarget.id + "\n" + otarget.tagName); //just to verify
+ top.location = "/ActivitiesGuideSugar/" + otarget.id;
+} else {
+ //you don't find one
+//alert("nada" + otarget.id);
+}
+}
+
+function previous () {
+var onode, otarget;
+onode=document.getElementById("PackageTheActivity");
+if (onode.id=="Introduction") die;
+//alert (onode.id);
+onode=onode.previousSibling;
+if (onode.id=="heading") onode=onode.previousSibling;
+if (onode.id=="title") die;
+while (onode) {
+ //onode=onode.previousSibling;
+ if (onode.nodeType==1) {
+ //alert (onode.id);
+ otarget=onode;
+ break;
+ }
+ onode=onode.previousSibling;
+}
+if (otarget) {
+ //you actually have found one, and do something here
+ //alert(otarget.id + "\n" + otarget.tagName); //just to verify
+ top.location = otarget.id;
+} else {
+ //you don't find one
+//alert("nada" + otarget.id);
+}
+}
+
+</script>
+ </head>
+ <body background="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/background.gif" style="margin:0;color:#000000;">
+<div id="home" style="position:absolute;left:0px;top:10px;">
+<a href="/"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/top_read_back.gif" border="0"></a>
+</div>
+<div id="index" style="position:absolute;left:0px;top:150px;">
+<ul>
+<li class="title">MAKING SUGAR ACTIVITIES</li><li id="Introduction"><a href="/ActivitiesGuideSugar/Introduction">INTRODUCTION</a></li><li id="WhatIsSugar"><a href="/ActivitiesGuideSugar/WhatIsSugar">WHAT IS SUGAR?</a></li><li id="WhatisanActivity"><a href="/ActivitiesGuideSugar/WhatisanActivity">WHAT IS A SUGAR ACTIVITY?</a></li><li id="NeedtoKnowWriteSugarActivity"><a href="/ActivitiesGuideSugar/NeedtoKnowWriteSugarActivity">WHAT DO I NEED TO KNOW TO WRITE A SUGAR ACTIVITY?</a></li><li id="SetUpDevEnvironment"><a href="/ActivitiesGuideSugar/SetUpDevEnvironment">SETTING UP A DEVELOPMENT ENVIRONMENT</a></li><li id="CreateFirstActivity"><a href="/ActivitiesGuideSugar/CreateFirstActivity">CREATING YOUR FIRST ACTIVITY</a></li><li id="StandalonePythonReadEtexts"><a href="/ActivitiesGuideSugar/StandalonePythonReadEtexts">MAKING A STANDALONE PYTHON PROGRAM</a></li><li id="InheritFromActivity"><a href="/ActivitiesGuideSugar/InheritFromActivity">INHERIT FROM SUGAR.ACTIVITY.ACTIVITY</a></li><li id="PackageTheActivity"><a href="/ActivitiesGuideSugar/PackageTheActivity">PACKAGE THE ACTIVITY</a></li><li id="AddRefinements"><a href="/ActivitiesGuideSugar/AddRefinements">ADD REFINEMENTS</a></li><li id="UsingVersionControl"><a href="/ActivitiesGuideSugar/UsingVersionControl">ADD YOUR ACTIVITY CODE TO VERSION CONTROL</a></li><li id="Credits"><a href="/ActivitiesGuideSugar/Credits">CREDITS</a></li></ul>
+</div>
+<div id="pdf" style="position:absolute;left:13px;top:190px;">
+<a href="/ActivitiesGuideSugar/FM_06Jan10.pdf"><img class ="non" src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/makepdf.gif" border=0></a>
+<!-- <a href="/ActivitiesGuideSugar/FM_ActivitiesGuideSugar_06Jan10.pdf"><img class ="non" src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/makepdf.gif" border=0></a> -->
+<a href="/ActivitiesGuideSugar/print"><img class="non" src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/viewprint.gif" border=0></a>
+</div>
+ <div style="position:absolute;left:240px;top:11px;">
+ <table id="ds-layout" cellpadding="0" cellspacing="0" sumtop:5px;mary="" style="table-layout:fixed;width:670px;border: 5px solid #666666;padding-right: 0px;padding-left: 0px;padding-bottom: 0px;padding-top: 0px;margin-left : 10px;margin-top:10;background:#FFF7F0;">
+ <tr>
+ <td width=100%>
+<div class="arrow" style="position:relative;left:10px;top:5px;width:50px;float:left;"><a href="#" onClick="previous();"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/lefttext.png" height=20></a></div>
+<div class="arrow" style="position:relative;left:528px;width:50px;top:5px;float:left;"><a href="#" onClick="next();"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/righttext.png" height=20></a></div>
+ <div class="ds-contentcontainer">
+ <div style="margin-left:1.2em;float:right">
+ <br>
+ <div class="huh" style='decoration:none;color:black;border:1;position:absolute;top:60px;left:502px;'>
+ <a href='http://www.flossmanuals.net/bin/view/ActivitiesGuideSugar/PackageTheActivity' onClick="alert('You will now be forwarded to the FLOSS Manuals editing interface')"><b><font color=#ff7f00><small>Edit this page</small></font></b></a> :: <a href='http://www.flossmanuals.net/bin/view/ActivitiesGuideSugar/FMComments?skin=floss2'><b><font color=#ff7f00><small>Discussion</small></font></b></a>
+ </div>
+ <h1>Package The Activity
+</h1>
+<h2>Add setup.py
+</h2>
+<p> You'll need to add a Python program called <strong>setup.py</strong> to the same directory that you Activity program is in.&nbsp; Every setup.py is exactly the same as every other setup.py, so you create a file called setup.py in Eric and paste the code below into it.
+ <br />
+</p>
+<pre>#!/usr/bin/env python
+
+# Copyright (C) 2006, Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+from sugar.activity import bundlebuilder
+
+bundlebuilder.start()</pre>
+<p>Be sure and copy the entire text above, including the comments.
+ <br />
+</p>
+<p>The setup.py program is used by sugar for a number of purposes.&nbsp; If you run setup.py from the command line you'll see the options that are used with it and what they do.
+</p>
+<pre>[jim@simmons bookexamples]$ ./setup.py
+/usr/lib/python2.6/site-packages/sugar/util.py:25: DeprecationWarning: the sha module is deprecated; use the hashlib module instead
+ import sha
+Available commands:
+
+build Build generated files
+dev Setup for development
+dist_xo Create a xo bundle package
+dist_source Create a tar source package
+fix_manifest Add missing files to the manifest
+genpot Generate the gettext pot file
+install Install the activity in the system
+
+(Type "./setup.py &lt;command&gt; --help" for help about a particular command's options.</pre>
+<p>We'll be running some of these commands later on.&nbsp; Don't be concerned about the <em>DeprecationWarning</em> message.&nbsp; That is just Python's way of telling us that it has a new way of doing something that is better but the old way we are using still works.&nbsp; The error is coming from code in Sugar itself and should be fixed in some future Sugar release.
+ <br />
+</p>
+<h2>Create activity.info
+</h2>
+<p> Next create a directory within the one your progam is in and name it <strong>activity</strong>.&nbsp; Create a file named <strong>activity.info</strong> within that directory and copy the lines below into it.
+ <br />
+</p>
+<pre>[Activity]
+name = Read ETexts II
+service_name = net.flossmanuals.ReadEtextsActivity
+icon = read-etexts
+exec = sugar-activity ReadEtextsActivity.ReadEtextsActivity
+show_launcher = no
+activity_version = 1
+mime_types = text/plain;application/zip
+license = GPLv2+</pre>
+<p>This file tell Sugar how to run your Activity.&nbsp; The properties needed in this file are:
+</p>
+<p>
+ <table style="width: 100%;" border="0" cellpadding="4" cellspacing="0"><tbody>
+ <tr>
+ <td style="width: 25%;">&nbsp;<strong>name</strong></td>
+ <td style="width: 75%;">The name of your Activity as it will appear to the user.
+ <br /></td>
+ </tr>
+ <tr>
+ <td>&nbsp;<strong>service_name</strong></td>
+ <td>A unique name that Sugar will use to refer to your Activity.&nbsp; Any Journal entry created by your Activity will have this name stored in its metadata, so that when someone resumes the Journal entry Sugar knows to use the program that created it to read it.
+ <br /></td>
+ </tr>
+ <tr>
+ <td><strong>icon </strong>
+ <br /></td>
+ <td>The name of the icon file you have created for the Activity.&nbsp; Since icons are always .svg files the icon file in the example is named read-etexts.svg.
+ <br /></td>
+ </tr>
+ <tr>
+ <td>&nbsp;<strong>exec</strong></td>
+ <td>This tells Sugar how to launch your Activity.&nbsp; What it says is to create an instance of the class <strong>ReadEtextsActivity </strong>which it will find in file <strong>ReadEtextsActivity.py</strong>.
+ <br /></td>
+ </tr>
+ <tr>
+ <td>&nbsp;<strong>show_launcher</strong></td>
+ <td>There are two ways to launch an Activity.&nbsp; The first is to click on the icon in the Activity view.&nbsp; The second is to resume an entry in the Journal. Activities that don't create Journal entries can only be resumed from the Journal, so there is no point in putting an icon in the Activity ring for them.&nbsp; Read Etexts is an Activity like that.
+ <br /></td>
+ </tr>
+ <tr>
+ <td>&nbsp;<strong>activity_version</strong></td>
+ <td>An integer that represents the version number of your program.&nbsp; The first version is 1, the next is 2, and so on.
+ <br /></td>
+ </tr>
+ <tr>
+ <td>&nbsp;<strong>mime_types</strong></td>
+ <td>Generally when you resume a Journal entry it launches the Activity that created it.&nbsp; In the case of an e-book it wasn't created by any Activity, so we need another way to tell the Journal which Activity it can use.&nbsp; A MIME type is the name of a common file format.&nbsp; Some examples are text/plain, text/html, application/zip and application/pdf.&nbsp; In this entry we're telling the Journal that our program can handle either plain text files or Zip archive files.
+ <br /></td>
+ </tr>
+ <tr>
+ <td>&nbsp;<strong>license</strong></td>
+ <td>Owning a computer program is not like buying a car.&nbsp; With a car, you're the owner and you can do what you like with it.&nbsp; You can sell it, rent it out, make it into a hot rod, whatever.&nbsp; With a computer program there is always a license that tells the person receiving the program what he is allowed to do with it.&nbsp; GPLv2+ is a popular standard license that can be used for Activities, and since this is <em>my</em> program that is what goes here.&nbsp; When you're ready to distribute one of <em>your</em> Activities I'll have more to say about licenses.
+ <br /></td>
+ </tr></tbody>
+ </table>
+</p>
+<h2>Create An Icon
+</h2>
+<p> Next we need to create an icon named <strong>read-etexts.svg</strong> and put it in the <strong>activity</strong> subdirectory.&nbsp; We're going to use Inkscape to create the icon.&nbsp; From the <strong>New</strong> menu in Inkscape select <strong>icon_48x48</strong>.&nbsp; This will create a drawing area that is a good size.
+</p>
+<p>You don't need to be an expert in Inkscape to create an icon.&nbsp; In fact the less fancy your icon is the better.&nbsp; When drawing your icon remember the following points:
+</p>
+<ul>
+ <li>Your icon needs to look good in sizes ranging from really, really small to large.</li>
+ <li>It needs to be recognizeable when its really, really small.</li>
+ <li>You only get to use two colors: a stroke color and a fill color.&nbsp; It doesn't matter which ones you choose because Sugar will need to override your choices anyway, so just use black strokes on a white background.</li>
+ <li>A fill color is only applied to an area that is contained within an unbroken stroke.&nbsp; If you draw a box and one of the corners doesn't quite connect the area inside that box will not be filled.&nbsp; Free hand drawing is only for the talented.&nbsp; Circles, boxes, and arcs are easy to draw with Inkscape so use them when you can.</li>
+ <li>Inkscape will also draw 3D boxes using two point perspective.&nbsp; Don't use them.&nbsp; Icons should be flat images.&nbsp; 3D just doesn't look good in an icon.</li>
+ <li>Coming up with good ideas for icons is tough.&nbsp; I once came up with a rather nice picture of a library card catalog drawer for <em>Get Internet Archive Books</em>.&nbsp; The problem is, no child under the age of forty has ever seen a card catalog and fewer still understand its purpose.</li>
+</ul>
+<p>When you're done making your icon you need to modify it so it can work with Sugar.&nbsp; Specifically, you need to make it show Sugar can use its own choice of stroke color and fill color.&nbsp; The SVG file format is based on XML, which means it is a text file with some special tags in it.&nbsp; This means that once we have finished editing it in Inkscape we can load the file into Eric and edit it as a text file.
+</p>
+<p>I'm not going to put the entire file in this chapter because most of it you'll just leave alone.&nbsp; The first part you need to modify is at the very beginning.
+</p>
+<p>Before:
+</p>
+<pre>&lt;?xml version="1.0" encoding="UTF-8" standalone="no"?&gt;
+&lt;!-- Created with Inkscape (http://www.inkscape.org/) --&gt;
+&lt;svg
+</pre>
+<p> After:
+</p>
+<pre>&lt;?xml version="1.0" ?&gt;&lt;!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd' [
+ &lt;!ENTITY stroke_color "#000000"&gt;
+ &lt;!ENTITY fill_color "#FFFFFF"&gt;
+]&gt;&lt;svg
+</pre>
+<p>Now in the body of the document you'll find references to <em>fill</em> and <em>stroke</em> as part of an attribute called <em>style</em>.&nbsp; Every line or shape you draw will have these, like this:
+</p>
+<pre> &lt;rect
+ style="fill:#ffffff;stroke:#000000;stroke-opacity:1"
+ id="rect904"
+ width="36.142857"
+ height="32.142857"
+ x="4.1428571"
+ y="7.1428571" /&gt;</pre>
+<p>You need to change each one to look like this:
+</p>
+<pre> &lt;rect
+ style="fill:&amp;fill_color;;stroke:&amp;stroke_color;;stroke-opacity:1"
+ id="rect904"
+ width="36.142857"
+ height="32.142857"
+ x="4.1428571"
+ y="7.1428571" /&gt;</pre>
+<p>Note that <em>&amp;stroke_color;</em> and <em>&amp;fill_color;</em> both end with semicolons (;), and semicolons are also used to separate the properties for style.&nbsp; Because of this it is an extremely common beginner's mistake to leave off the trailing semicolon because two semicolons in a row don't look right.&nbsp; Be assured that the two semicolons in a row are intentional and absolutely necessary!
+</p>
+<h2>Make a MANIFEST File
+</h2>
+<p> You should remember that setup.py has an option to update a manifest.&nbsp; Let's try it:
+</p>
+<pre>./setup.py fix_manifest
+/usr/lib/python2.6/site-packages/sugar/util.py:25: DeprecationWarning: the sha module is deprecated; use the hashlib module instead
+ import sha
+WARNING:root:Missing po/ dir, cannot build_locale
+WARNING:root:Activity directory lacks a MANIFEST file.
+</pre>
+<p>This actually will build a MANIFEST file containing everything in the directory and its subdirectories.&nbsp; The /po directory it is complaining about is used to translate Activities into different languages.&nbsp; We can ignore that for now.
+</p>
+<p> The MANIFEST file it creates will contain some extra stuff, so we need to get rid of the extra lines using Eric.&nbsp; The corrected MANIFEST should look like this:
+</p>
+<pre>setup.py
+ReadEtextsActivity.py
+activity/read-etexts.svg
+activity/activity.info</pre>
+<h2>Install The Activity
+</h2>
+<p> There's just one more thing to do before we can test our Activity under the Sugar emulator.&nbsp; We need to install it, which in this case means making a symbolic link between the directory we're using for our code in the ~/Activities/ directory.&nbsp; The symbol ~ refers to the "home" directory of the user we're running Sugar under, and a symbolic link is a way to make a file or directory appear to be located in more than one place without copying it.&nbsp; We make this symbolic link by running setup.py again:
+</p>
+<pre>./setup.py dev
+</pre>
+<h2>Running Our Activity
+</h2>
+<p>Now at last we can run our Activity under Sugar.&nbsp; To do that we need to lear how to run the Sugar emulator.
+</p>
+<p>Fedora doesn't make a menu option for Sugar Emulator, but it's easy to add one yourself.&nbsp; The command to run is simply
+</p>
+<pre>sugar-emulator</pre>
+<p>If your screen resolution is smaller than the default size sugar-emulator runs at it will run full screen.&nbsp; This is not convenient for testing, so you may want to specify your own size:
+</p>
+<pre>sugar-emulator -i 800x600</pre>
+<p>Note that this option only exists in Fedora 11 and later.
+</p>
+<p>When you run sugar-emulator a window opens up and the Sugar environment starts up and runs inside it.&nbsp; It looks like this:
+</p>
+<p><img alt="ReadEtexts_02.jpg" src="/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/ReadEtexts_02.jpg" height="480" width="640" />
+</p>
+<p>There are a couple of other tricks we can do with sugar-emulator.&nbsp; For example we can simulate multiple Sugar users on a network by running a second instance of Sugar with this command line:
+</p>
+<pre>SUGAR_PROFILE=<em>some_name</em> sugar-emulator
+</pre>
+<p>We can also tell the emulator we want more detailed logging for debugging purposes.&nbsp; (We haven't used logging code in our Activity yet but we'll get there):
+</p>
+<pre>SUGAR_LOGGER_LEVEL=debug PRESENSESERVICE_DEBUG=1 sugar-emulator
+</pre>
+<p>To test our Activity we're going to need to have a book in the Journal, so use the Browse Activity to visit Project Gutenberg again and download the book of your choice.&nbsp; This time it's important to download the book in Zip format, because Browse cannot download a plain text file to the Journal.&nbsp; Instead, it opens the file for viewing as if it was a web page.&nbsp; If you try the same thing with the Zip file it will create an entry in the Journal.
+</p>
+<p>We can't just open the file with one click in the Journal because our program did not create the Journal entry and there are several Activities that support the MIME type of the Journal entry.&nbsp; We need to use the Start With menu option like this:
+</p>
+<p><img alt="ReadEtexts_03.jpg" src="/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/ReadEtexts_03.jpg" height="480" width="640" />
+</p>
+<p>When we do open the Journal entry this is what we see:
+</p>
+<p><img alt="ReadEtexts_04.jpg" src="/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/ReadEtexts_04.jpg" height="480" width="640" />
+</p>
+<p>Technically, this is the first <em>iteration</em> of our Activity.&nbsp; (Iteration is a vastly useful word meaning something you do more than once.&nbsp; In this book we're building our Activity a bit at a time so I can demonstrate Activity writing principles, but actually building a program in pieces, testing it, getting feedback, and building a bit more can be a highly productive way of creating software.&nbsp; Using the word iteration to describe each step in the process makes the process sound more formal than it really is).
+</p>
+<p>While this Activity might be good enough to show your own mother, we really should improve it a bit before we do that.&nbsp; That part comes next.
+ <br />
+</p>
+<p />
+ </p></div>
+ </div>
+<div class="arrow" style="position:relative;left:10px;width:50px;float:left;bottom:5px;"><a href="#" onClick="previous();"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/lefttext.png" height=20></a></div>
+<div class="arrow" style="position:relative;left:528px;width:50px;float:left;bottom:5px;"><a href="#" onClick="next();"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/righttext.png" height=20></a></div>
+ <br>
+ <br>
+ <br>
+ <br>
+ </td>
+ </tr>
+ </table>
+ </div>
+<!-- Piwik -->
+<a href="http://piwik.org" title="Web analytics" onclick="window.open(this.href);return(false);">
+<script language="javascript" src="http://adam.engagetv.com/piwik/piwik.js" type="text/javascript"></script>
+<script type="text/javascript">
+<!--
+piwik_action_name = '';
+piwik_idsite = 1;
+piwik_url = 'http://adam.engagetv.com/piwik/piwik.php';
+piwik_log(piwik_action_name, piwik_idsite, piwik_url);
+//-->
+</script>
+<!-- /Piwik -->
+<script language="Javascript">
+document.getElementById("PackageTheActivity").style.backgroundColor="#F99B1C";
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/help/ActivityBook/ActivitiesGuideSugar/SetUpDevEnvironment b/help/ActivityBook/ActivitiesGuideSugar/SetUpDevEnvironment
new file mode 100644
index 0000000..b5a5516
--- /dev/null
+++ b/help/ActivityBook/ActivitiesGuideSugar/SetUpDevEnvironment
@@ -0,0 +1,314 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html>
+ <head>
+ <title>ActivitiesGuideSugar (en)</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <!--
+ <link rel="alternate" type="application/rss+xml" title="RSS Feed" href="WebRss.html" />
+ -->
+ <link rel="icon" href="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/fl2.ico" type="image/x-icon" /> <link rel="shortcut icon" href="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/fl2.ico" type="image/x-icon" />
+ <link rel=StyleSheet href="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/typography.css" type="text/css" media="screen">
+<style>
+#index {
+ color: #ff7f00;
+ font-family: trebuchet,sans-serif;
+ font-size: 10px;
+ line-height:11px;
+}
+#index UL {
+ width: 159px;
+ list-style-type: None;
+ padding-left: 0px;
+ border: 14px solid #ff7f00;
+ background-color: #ff7f00;
+ margin: 0px 0px 0px 0px;
+ }
+#index LI {
+ padding-left: 0px;
+ padding-right: 10px;
+ padding-top: 4px;
+ padding-bottom: 4px;
+ color: #ffffff;
+ margin: 0px 0px 0px 0px;
+ background-color: #ff7f00;
+ border-top: 1px solid #ff7f00;
+ }
+#index LI:hover {
+ background-color: #F99B1C;
+}
+#index LI.heading {
+ background-color: #ff7f00;
+ color: #000000;
+ border-top:1px solid #FFE5CC;
+ padding-top: 7px;
+ font-weight: bold;
+}
+#index LI.title {
+ border-bottom: 2px solid #FFE5CC;
+ background-color: #ff7f00;
+ color: #FBF4E9;
+ font-weight: bolder;
+ font-size:10px;
+ line-height:18px;
+ padding-bottom: 40px;
+ }
+#index A {
+ text-decoration: none;
+ color: #FBF4E9;
+ font-weight: bold;
+}
+#ds-layout .imgcontainer {
+ position:relative;
+ }
+#ds-layout .caption {
+ position:relative;
+ bottom:1;
+ left:0;
+ text-align:center;
+ background:#ffe7cb;
+ width:100%;
+ opacity:.75;
+ filter:alpha(opacity=85);
+ color:#000;
+ font-style: italic;
+ font-size: 9px;
+ line-height:11px;
+ }
+</style>
+<script type="text/javascript">
+function addLoadEvent(func) {
+ var oldonload = window.onload;
+ if (typeof window.onload != 'function') {
+ window.onload = func;
+ } else {
+ window.onload = function() {
+ oldonload();
+ func();
+ }
+ }
+}
+
+function insertAfter(newElement,targetElement) {
+ var parent = targetElement.parentNode;
+ if (parent.lastChild == targetElement) {
+ parent.appendChild(newElement);
+ } else {
+ parent.insertBefore(newElement,targetElement.nextSibling);
+ }
+}
+
+function captionizeImages() {
+ if (!document.getElementsByTagName) return false;
+ if (!document.createElement) return false;
+ var images = document.getElementsByTagName("img");
+ if (images.length < 1) return false;
+ for (var i=0; i<images.length; i++) {
+ if (images[i].className != "non") {
+ var title = images[i].getAttribute("title");
+ var width = images[i].width;
+ var divCaption = document.createElement("div");
+ divCaption.className="caption";
+ divCaption.style.width=width+'px';
+ if (title) divCaption.style.padding='2px 0px 3px 0px';
+ divCaption.style.display='block';
+ var divCaption_text = document.createTextNode(title);
+ divCaption.appendChild(divCaption_text);
+ var divContainer = document.createElement("div");
+ divContainer.className="imgcontainer";
+ if (title) divContainer.style.padding='0px 0px 10px 0px';
+ images[i].parentNode.insertBefore(divContainer,images[i]);
+ divContainer.appendChild(images[i]);
+ insertAfter(divCaption,images[i]);
+ }
+ }
+}
+//addLoadEvent(captionizeImages);
+
+function next () {
+var onode, otarget;
+onode=document.getElementById("SetUpDevEnvironment");
+if (onode.id=="Credits") die;
+//alert (onode.id);
+onode=onode.nextSibling;
+if (onode.id=="heading") onode=onode.nextSibling;
+while (onode) {
+ //onode=onode.nextSibling;
+ if (onode.nodeType==1) {
+ //alert (onode.id);
+ otarget=onode;
+ break;
+ }
+ onode=onode.nextSibling;
+}
+if (otarget) {
+ //you actually have found one, and do something here
+ //alert(otarget.id + "\n" + otarget.tagName); //just to verify
+ top.location = "/ActivitiesGuideSugar/" + otarget.id;
+} else {
+ //you don't find one
+//alert("nada" + otarget.id);
+}
+}
+
+function previous () {
+var onode, otarget;
+onode=document.getElementById("SetUpDevEnvironment");
+if (onode.id=="Introduction") die;
+//alert (onode.id);
+onode=onode.previousSibling;
+if (onode.id=="heading") onode=onode.previousSibling;
+if (onode.id=="title") die;
+while (onode) {
+ //onode=onode.previousSibling;
+ if (onode.nodeType==1) {
+ //alert (onode.id);
+ otarget=onode;
+ break;
+ }
+ onode=onode.previousSibling;
+}
+if (otarget) {
+ //you actually have found one, and do something here
+ //alert(otarget.id + "\n" + otarget.tagName); //just to verify
+ top.location = otarget.id;
+} else {
+ //you don't find one
+//alert("nada" + otarget.id);
+}
+}
+
+</script>
+ </head>
+ <body background="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/background.gif" style="margin:0;color:#000000;">
+<div id="home" style="position:absolute;left:0px;top:10px;">
+<a href="/"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/top_read_back.gif" border="0"></a>
+</div>
+<div id="index" style="position:absolute;left:0px;top:150px;">
+<ul>
+<li class="title">MAKING SUGAR ACTIVITIES</li><li id="Introduction"><a href="/ActivitiesGuideSugar/Introduction">INTRODUCTION</a></li><li id="WhatIsSugar"><a href="/ActivitiesGuideSugar/WhatIsSugar">WHAT IS SUGAR?</a></li><li id="WhatisanActivity"><a href="/ActivitiesGuideSugar/WhatisanActivity">WHAT IS A SUGAR ACTIVITY?</a></li><li id="NeedtoKnowWriteSugarActivity"><a href="/ActivitiesGuideSugar/NeedtoKnowWriteSugarActivity">WHAT DO I NEED TO KNOW TO WRITE A SUGAR ACTIVITY?</a></li><li id="SetUpDevEnvironment"><a href="/ActivitiesGuideSugar/SetUpDevEnvironment">SETTING UP A DEVELOPMENT ENVIRONMENT</a></li><li id="CreateFirstActivity"><a href="/ActivitiesGuideSugar/CreateFirstActivity">CREATING YOUR FIRST ACTIVITY</a></li><li id="StandalonePythonReadEtexts"><a href="/ActivitiesGuideSugar/StandalonePythonReadEtexts">MAKING A STANDALONE PYTHON PROGRAM</a></li><li id="InheritFromActivity"><a href="/ActivitiesGuideSugar/InheritFromActivity">INHERIT FROM SUGAR.ACTIVITY.ACTIVITY</a></li><li id="PackageTheActivity"><a href="/ActivitiesGuideSugar/PackageTheActivity">PACKAGE THE ACTIVITY</a></li><li id="AddRefinements"><a href="/ActivitiesGuideSugar/AddRefinements">ADD REFINEMENTS</a></li><li id="UsingVersionControl"><a href="/ActivitiesGuideSugar/UsingVersionControl">ADD YOUR ACTIVITY CODE TO VERSION CONTROL</a></li><li id="Credits"><a href="/ActivitiesGuideSugar/Credits">CREDITS</a></li></ul>
+</div>
+<div id="pdf" style="position:absolute;left:13px;top:190px;">
+<a href="/ActivitiesGuideSugar/FM_06Jan10.pdf"><img class ="non" src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/makepdf.gif" border=0></a>
+<!-- <a href="/ActivitiesGuideSugar/FM_ActivitiesGuideSugar_06Jan10.pdf"><img class ="non" src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/makepdf.gif" border=0></a> -->
+<a href="/ActivitiesGuideSugar/print"><img class="non" src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/viewprint.gif" border=0></a>
+</div>
+ <div style="position:absolute;left:240px;top:11px;">
+ <table id="ds-layout" cellpadding="0" cellspacing="0" sumtop:5px;mary="" style="table-layout:fixed;width:670px;border: 5px solid #666666;padding-right: 0px;padding-left: 0px;padding-bottom: 0px;padding-top: 0px;margin-left : 10px;margin-top:10;background:#FFF7F0;">
+ <tr>
+ <td width=100%>
+<div class="arrow" style="position:relative;left:10px;top:5px;width:50px;float:left;"><a href="#" onClick="previous();"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/lefttext.png" height=20></a></div>
+<div class="arrow" style="position:relative;left:528px;width:50px;top:5px;float:left;"><a href="#" onClick="next();"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/righttext.png" height=20></a></div>
+ <div class="ds-contentcontainer">
+ <div style="margin-left:1.2em;float:right">
+ <br>
+ <div class="huh" style='decoration:none;color:black;border:1;position:absolute;top:60px;left:502px;'>
+ <a href='http://www.flossmanuals.net/bin/view/ActivitiesGuideSugar/SetUpDevEnvironment' onClick="alert('You will now be forwarded to the FLOSS Manuals editing interface')"><b><font color=#ff7f00><small>Edit this page</small></font></b></a> :: <a href='http://www.flossmanuals.net/bin/view/ActivitiesGuideSugar/FMComments?skin=floss2'><b><font color=#ff7f00><small>Discussion</small></font></b></a>
+ </div>
+ <h1>Setting Up a Sugar Development Environment
+</h1>
+<p class="western">It is not currently practical to develop Activities for the XO on the XO. It's not so much that you can't do it, but that it's easier and more productive to do your development and testing on another machine running a more conventional OS. This gives you access to better tools and it also enables you to simulate collaboration between two computers running Sugar using only one computer.
+</p>
+<h2 class="western">Install Linux Or Use A Virtual Machine?
+</h2>
+<p class="western">Even though Sugar runs on Linux it is possible to do development in Windows running a complete instance of Sugar in a virtual machine. A virtual machine is a way to run one operating system on top of another one. The operating system being run is fooled into thinking it has the whole computer to itself. (Computer industry pundits will tell you that using virtual machines is the newest new thing out there. Old timers like me know that IBM was doing it on their mainframe computers back in the 1970's).
+</p>
+<p class="western">For awhile this was actually the recommended way to develop Activities. The version of Linux that Sugar used was different enough from regular Linux distributions that even Linux users were running Sugar in a virtual machine on top of Linux.
+</p>
+<p class="western">The situation has improved, and most current Linux distributions have a usable Sugar environment.
+</p>
+<p class="western">If you're used to Windows you might think that running Sugar in a VM from Windows instead of installing Linux might be the easier option. In practice it is not. Linux running in a VM is still Linux, so you're still going to have to learn some things about Linux to do Activity development. Also, running a second OS in a VM requires a really powerful machine with gigabytes of memory. On the other hand, I do my Sugar development using Linux on an IBM NetVista Pentium IV I bought used for a little over a hundred dollars, shipping included. It is more than adequate.
+</p>
+<p class="western">Installing Linux is not the test of manhood it once was. Anyone can do it. The GNOME desktop provided with Linux is very much like Windows so you'll feel right at home using it.
+</p>
+<p class="western">When you install Linux you have the option to do a dual boot, running Linux and Windows on the same computer (but not at the same time). This means you set aside a disk partition for use by Linux and when you start the computer a menu appears asking which OS you want to start up. The Linux install will even create the partition for you, and a couple of gigabytes is more than enough disk space. Sharing a computer with a Linux installation will not affect your Windows installation at all.
+ <br />
+</p>
+<p class="western">Sugar Labs has been working to get Sugar included with all Linux distributions. If you already have a favorite distribution, chances are the latest version of it includes Sugar. Fedora, openSuse, Debian, and Ubuntu all include Sugar. If you already use Linux, see if Sugar is included in your distribution. If not, Fedora is what is used by the XO computer so Fedora 10 or later might be your best bet. You can download the Fedora install CD or DVD here: <a href="https://fedoraproject.org/get-fedora">https://fedoraproject.org/get-fedora</a>.
+</p>
+<p class="western">It is worth pointing out that all of the other tools I'm recommending are included in every Linux distribution, and they can be installed with no more effort than checking a check box. The same tools often will run on Windows, but installing them there is more work than you would expect for Windows programs.
+</p>
+<p class="western">If you want to do development on a Macintosh emulation is still your only option. If you want to try the emulation option details will be found here: <a href="http://wiki.laptop.org/go/Developers/Setup">http://wiki.laptop.org/go/Developers/Setup.</a>
+</p>
+<h2 class="western">What About Using sugar-jhbuild?
+</h2>
+<p class="western">Sugar-jhbuild is a script that downloads the source code for the latest version of all the Sugar modules and compiles it in such a way that it doesn't interfere with the modules that make up your normal desktop. If you are developing Sugar itself, or if you are developing Activities that depend on the very latest Sugar features you'll need to run sugar-jhbuild.
+</p>
+<p class="western">Running this script can take hours and occasionally it will fail leaving you with an unusable Sugar environment.
+</p>
+<p class="western">Should you consider using it? The short answer is no. A longer answer is <em>probably not yet</em>.
+</p>
+<p class="western">If you want your Activities to reach the widest possible audience you <em>don't</em> want the latest Sugar. In fact, if you want a test environment that mimics what is on most XO computers right now you need to use Fedora 10. Because updating operating systems in the field can be a major undertaking for a school most XO's will be running Sugar .82 or older for quite some time.
+</p>
+<p class="western">Of course it is also important to have developers that want to push the boundaries of what Sugar can do. If after developing some Activities you decide you need to be one of them you can learn about running sugar-jhbuild here: <a href="http://wiki.sugarlabs.org/go/DevelopmentTeam/Jhbuild">http://wiki.sugarlabs.org/go/DevelopmentTeam/Jhbuild.</a>
+</p>
+<h2 class="western">Eric
+</h2>
+<p class="western">Developers today expect their languages to be supported by an Integrated Development Environment and Python is no exception. An IDE helps to organize your work and provides text editing and a built in set of programming and debugging tools.
+</p>
+<p class="western">There are two Python IDE's I'm aware of: Eric and Idle. Eric is the fancier of the two and I recommend it. Every Linux distribution should include it. It looks like it might work on Windows too. You can learn more about it at the Eric website: <a href="http://eric-ide.python-projects.org/">http://eric-ide.python-projects.org/</a>.
+</p>
+<h2 class="western">Inkscape
+</h2>
+<p class="western">Inkscape is a tool for creating images in SVG format. Sugar uses SVG for Activity icons and other kinds of artwork. The “XO†icon that represents each child in the Neighborhood view is an SVG file that can be modified.
+</p>
+<p class="western">Inkscape comes with every Linux distribution, and can be installed on Windows as well. You can learn more about it here: <a href="http://www.inkscape.org/">http://www.inkscape.org/</a>.
+</p>
+<h2 class="western">Git
+</h2>
+<p class="western">Git is a version control system. It stores versions of your program code in a way that makes them easy to get back. Whenever you make changes to your code you ask Git to store your code in its repository. If you need to look at an old version of that code later you can. Even better, if some problem shows up in your code you can compare your latest code to an old, working version and see exactly what lines you changed.
+</p>
+<p class="western">If there are two people working on the same program independently a version control system will merge their changes together automatically.
+</p>
+<p class="western">Suppose you're working on a major new version of your Activity when someone finds a really embarrassing bug in the version you just released. If you use Git you don't need to tell people to live with it until the next release, which could be months away. Instead you can create a branch of the previous version and work on it alongside the version you're enhancing. In effect Git treats the old version you're fixing and the version you're improving as two separate projects.
+</p>
+<p class="western">You can learn more about Git at the Git website: <a href="http://git-scm.com/">http://git-scm.com/</a>.
+</p>
+<p class="western">When you're ready for a Git repository for your project you can learn how to set that up here: <a href="http://git.sugarlabs.org/">http://git.sugarlabs.org/</a>.
+</p>
+<h2 class="western">The GIMP
+</h2>
+<p class="western">The GIMP is one of the most useful and badly named programs ever developed. You can think of it as a free version of Adobe Photoshop. If you need to work with image files (other than SVG's) you need this program.
+</p>
+<p class="western">You may never need this program to develop the Activity itself, but when it's time to distribute the Activity you'll use it to create screen shots of your Activity in action. Nothing sells an Activity to a potential user like good screen shots.
+</p>
+<h2 class="western">Sugar Emulation
+</h2>
+<p class="western">Most Linux distributions should have Sugar included. In Fedora you can run Sugar as an alternative desktop environment. When you log in to GDM Sugar appears as a desktop selection alongside GNOME, KDE, Window Maker, and any other window managers you have installed.
+</p>
+<p class="western">This is not the normal way to use Sugar for testing. The normal way uses a tool called Xephyr to run a Sugar environment in a window on your desktop. In effect, Xephyr runs an X session inside a window and Sugar runs in that. You can easily take screen shots of Sugar in action, stop and restart Sugar sessions without restarting the computer, and run multiple copies of Sugar to test collaboration.
+</p>
+<p class="western">I'll have more to say about this when it's time to test your first Activity.
+</p> &nbsp;
+<p>
+</p>
+<p />
+ </p></div>
+ </div>
+<div class="arrow" style="position:relative;left:10px;width:50px;float:left;bottom:5px;"><a href="#" onClick="previous();"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/lefttext.png" height=20></a></div>
+<div class="arrow" style="position:relative;left:528px;width:50px;float:left;bottom:5px;"><a href="#" onClick="next();"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/righttext.png" height=20></a></div>
+ <br>
+ <br>
+ <br>
+ <br>
+ </td>
+ </tr>
+ </table>
+ </div>
+<!-- Piwik -->
+<a href="http://piwik.org" title="Web analytics" onclick="window.open(this.href);return(false);">
+<script language="javascript" src="http://adam.engagetv.com/piwik/piwik.js" type="text/javascript"></script>
+<script type="text/javascript">
+<!--
+piwik_action_name = '';
+piwik_idsite = 1;
+piwik_url = 'http://adam.engagetv.com/piwik/piwik.php';
+piwik_log(piwik_action_name, piwik_idsite, piwik_url);
+//-->
+</script>
+<!-- /Piwik -->
+<script language="Javascript">
+document.getElementById("SetUpDevEnvironment").style.backgroundColor="#F99B1C";
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/help/ActivityBook/ActivitiesGuideSugar/StandalonePythonReadEtexts b/help/ActivityBook/ActivitiesGuideSugar/StandalonePythonReadEtexts
new file mode 100644
index 0000000..eab7d74
--- /dev/null
+++ b/help/ActivityBook/ActivitiesGuideSugar/StandalonePythonReadEtexts
@@ -0,0 +1,461 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html>
+ <head>
+ <title>ActivitiesGuideSugar (en)</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <!--
+ <link rel="alternate" type="application/rss+xml" title="RSS Feed" href="WebRss.html" />
+ -->
+ <link rel="icon" href="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/fl2.ico" type="image/x-icon" /> <link rel="shortcut icon" href="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/fl2.ico" type="image/x-icon" />
+ <link rel=StyleSheet href="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/typography.css" type="text/css" media="screen">
+<style>
+#index {
+ color: #ff7f00;
+ font-family: trebuchet,sans-serif;
+ font-size: 10px;
+ line-height:11px;
+}
+#index UL {
+ width: 159px;
+ list-style-type: None;
+ padding-left: 0px;
+ border: 14px solid #ff7f00;
+ background-color: #ff7f00;
+ margin: 0px 0px 0px 0px;
+ }
+#index LI {
+ padding-left: 0px;
+ padding-right: 10px;
+ padding-top: 4px;
+ padding-bottom: 4px;
+ color: #ffffff;
+ margin: 0px 0px 0px 0px;
+ background-color: #ff7f00;
+ border-top: 1px solid #ff7f00;
+ }
+#index LI:hover {
+ background-color: #F99B1C;
+}
+#index LI.heading {
+ background-color: #ff7f00;
+ color: #000000;
+ border-top:1px solid #FFE5CC;
+ padding-top: 7px;
+ font-weight: bold;
+}
+#index LI.title {
+ border-bottom: 2px solid #FFE5CC;
+ background-color: #ff7f00;
+ color: #FBF4E9;
+ font-weight: bolder;
+ font-size:10px;
+ line-height:18px;
+ padding-bottom: 40px;
+ }
+#index A {
+ text-decoration: none;
+ color: #FBF4E9;
+ font-weight: bold;
+}
+#ds-layout .imgcontainer {
+ position:relative;
+ }
+#ds-layout .caption {
+ position:relative;
+ bottom:1;
+ left:0;
+ text-align:center;
+ background:#ffe7cb;
+ width:100%;
+ opacity:.75;
+ filter:alpha(opacity=85);
+ color:#000;
+ font-style: italic;
+ font-size: 9px;
+ line-height:11px;
+ }
+</style>
+<script type="text/javascript">
+function addLoadEvent(func) {
+ var oldonload = window.onload;
+ if (typeof window.onload != 'function') {
+ window.onload = func;
+ } else {
+ window.onload = function() {
+ oldonload();
+ func();
+ }
+ }
+}
+
+function insertAfter(newElement,targetElement) {
+ var parent = targetElement.parentNode;
+ if (parent.lastChild == targetElement) {
+ parent.appendChild(newElement);
+ } else {
+ parent.insertBefore(newElement,targetElement.nextSibling);
+ }
+}
+
+function captionizeImages() {
+ if (!document.getElementsByTagName) return false;
+ if (!document.createElement) return false;
+ var images = document.getElementsByTagName("img");
+ if (images.length < 1) return false;
+ for (var i=0; i<images.length; i++) {
+ if (images[i].className != "non") {
+ var title = images[i].getAttribute("title");
+ var width = images[i].width;
+ var divCaption = document.createElement("div");
+ divCaption.className="caption";
+ divCaption.style.width=width+'px';
+ if (title) divCaption.style.padding='2px 0px 3px 0px';
+ divCaption.style.display='block';
+ var divCaption_text = document.createTextNode(title);
+ divCaption.appendChild(divCaption_text);
+ var divContainer = document.createElement("div");
+ divContainer.className="imgcontainer";
+ if (title) divContainer.style.padding='0px 0px 10px 0px';
+ images[i].parentNode.insertBefore(divContainer,images[i]);
+ divContainer.appendChild(images[i]);
+ insertAfter(divCaption,images[i]);
+ }
+ }
+}
+//addLoadEvent(captionizeImages);
+
+function next () {
+var onode, otarget;
+onode=document.getElementById("StandalonePythonReadEtexts");
+if (onode.id=="Credits") die;
+//alert (onode.id);
+onode=onode.nextSibling;
+if (onode.id=="heading") onode=onode.nextSibling;
+while (onode) {
+ //onode=onode.nextSibling;
+ if (onode.nodeType==1) {
+ //alert (onode.id);
+ otarget=onode;
+ break;
+ }
+ onode=onode.nextSibling;
+}
+if (otarget) {
+ //you actually have found one, and do something here
+ //alert(otarget.id + "\n" + otarget.tagName); //just to verify
+ top.location = "/ActivitiesGuideSugar/" + otarget.id;
+} else {
+ //you don't find one
+//alert("nada" + otarget.id);
+}
+}
+
+function previous () {
+var onode, otarget;
+onode=document.getElementById("StandalonePythonReadEtexts");
+if (onode.id=="Introduction") die;
+//alert (onode.id);
+onode=onode.previousSibling;
+if (onode.id=="heading") onode=onode.previousSibling;
+if (onode.id=="title") die;
+while (onode) {
+ //onode=onode.previousSibling;
+ if (onode.nodeType==1) {
+ //alert (onode.id);
+ otarget=onode;
+ break;
+ }
+ onode=onode.previousSibling;
+}
+if (otarget) {
+ //you actually have found one, and do something here
+ //alert(otarget.id + "\n" + otarget.tagName); //just to verify
+ top.location = otarget.id;
+} else {
+ //you don't find one
+//alert("nada" + otarget.id);
+}
+}
+
+</script>
+ </head>
+ <body background="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/background.gif" style="margin:0;color:#000000;">
+<div id="home" style="position:absolute;left:0px;top:10px;">
+<a href="/"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/top_read_back.gif" border="0"></a>
+</div>
+<div id="index" style="position:absolute;left:0px;top:150px;">
+<ul>
+<li class="title">MAKING SUGAR ACTIVITIES</li><li id="Introduction"><a href="/ActivitiesGuideSugar/Introduction">INTRODUCTION</a></li><li id="WhatIsSugar"><a href="/ActivitiesGuideSugar/WhatIsSugar">WHAT IS SUGAR?</a></li><li id="WhatisanActivity"><a href="/ActivitiesGuideSugar/WhatisanActivity">WHAT IS A SUGAR ACTIVITY?</a></li><li id="NeedtoKnowWriteSugarActivity"><a href="/ActivitiesGuideSugar/NeedtoKnowWriteSugarActivity">WHAT DO I NEED TO KNOW TO WRITE A SUGAR ACTIVITY?</a></li><li id="SetUpDevEnvironment"><a href="/ActivitiesGuideSugar/SetUpDevEnvironment">SETTING UP A DEVELOPMENT ENVIRONMENT</a></li><li id="CreateFirstActivity"><a href="/ActivitiesGuideSugar/CreateFirstActivity">CREATING YOUR FIRST ACTIVITY</a></li><li id="StandalonePythonReadEtexts"><a href="/ActivitiesGuideSugar/StandalonePythonReadEtexts">MAKING A STANDALONE PYTHON PROGRAM</a></li><li id="InheritFromActivity"><a href="/ActivitiesGuideSugar/InheritFromActivity">INHERIT FROM SUGAR.ACTIVITY.ACTIVITY</a></li><li id="PackageTheActivity"><a href="/ActivitiesGuideSugar/PackageTheActivity">PACKAGE THE ACTIVITY</a></li><li id="AddRefinements"><a href="/ActivitiesGuideSugar/AddRefinements">ADD REFINEMENTS</a></li><li id="UsingVersionControl"><a href="/ActivitiesGuideSugar/UsingVersionControl">ADD YOUR ACTIVITY CODE TO VERSION CONTROL</a></li><li id="Credits"><a href="/ActivitiesGuideSugar/Credits">CREDITS</a></li></ul>
+</div>
+<div id="pdf" style="position:absolute;left:13px;top:190px;">
+<a href="/ActivitiesGuideSugar/FM_06Jan10.pdf"><img class ="non" src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/makepdf.gif" border=0></a>
+<!-- <a href="/ActivitiesGuideSugar/FM_ActivitiesGuideSugar_06Jan10.pdf"><img class ="non" src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/makepdf.gif" border=0></a> -->
+<a href="/ActivitiesGuideSugar/print"><img class="non" src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/viewprint.gif" border=0></a>
+</div>
+ <div style="position:absolute;left:240px;top:11px;">
+ <table id="ds-layout" cellpadding="0" cellspacing="0" sumtop:5px;mary="" style="table-layout:fixed;width:670px;border: 5px solid #666666;padding-right: 0px;padding-left: 0px;padding-bottom: 0px;padding-top: 0px;margin-left : 10px;margin-top:10;background:#FFF7F0;">
+ <tr>
+ <td width=100%>
+<div class="arrow" style="position:relative;left:10px;top:5px;width:50px;float:left;"><a href="#" onClick="previous();"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/lefttext.png" height=20></a></div>
+<div class="arrow" style="position:relative;left:528px;width:50px;top:5px;float:left;"><a href="#" onClick="next();"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/righttext.png" height=20></a></div>
+ <div class="ds-contentcontainer">
+ <div style="margin-left:1.2em;float:right">
+ <br>
+ <div class="huh" style='decoration:none;color:black;border:1;position:absolute;top:60px;left:502px;'>
+ <a href='http://www.flossmanuals.net/bin/view/ActivitiesGuideSugar/StandalonePythonReadEtexts' onClick="alert('You will now be forwarded to the FLOSS Manuals editing interface')"><b><font color=#ff7f00><small>Edit this page</small></font></b></a> :: <a href='http://www.flossmanuals.net/bin/view/ActivitiesGuideSugar/FMComments?skin=floss2'><b><font color=#ff7f00><small>Discussion</small></font></b></a>
+ </div>
+ <h1> A Standalone Python Program For Reading Etexts
+</h1>
+<h2>The Program
+ <br />
+</h2>
+<p>Our example program is based on the first Activity I wrote, Read Etexts.&nbsp; This is a program for reading free e-books.
+ <br />
+</p>
+<p>The oldest and best source of free e-books is a website called Project Gutenberg <a href="http://www.gutenberg.org/wiki/Main_Page).">(<a href="http://www.gutenberg.org/wiki/Main_Page" target="_top">http://www.gutenberg.org/wiki/Main_Page</a>).</a>&nbsp; They create books in plain text format, in other words the kind of file you could make if you typed a book into Notepad and hit the Enter key at the end of each line.&nbsp; They have thousands of books that are out of copyright, including some of the best ever written.&nbsp; Before you read further go to that website and pick out a book that interests you.&nbsp; Check out the "Top 100" list to see the most popular books and authors.
+</p>
+<p>The program we're going to create will read books in plain text format only.&nbsp; Fire up <em>Eric</em>, create a new Project named <em>BookExamples</em>, and create a new file called <strong>ReadEtexts.py</strong>.&nbsp; Then use copy and paste to get the code below into that file and save it.
+</p>
+<pre>#! /usr/bin/env python
+import sys
+import os
+import zipfile
+import pygtk
+import gtk
+import getopt
+import pango
+
+page=0
+PAGE_SIZE = 45
+
+class ReadEtexts():
+
+ def keypress_cb(self, widget, event):
+ "Respond when the user presses one of the arrow keys"
+ keyname = gtk.gdk.keyval_name(event.keyval)
+ if keyname == 'plus':
+ self.font_increase()
+ return True
+ if keyname == 'minus':
+ self.font_decrease()
+ return True
+ if keyname == 'Page_Up' :
+ self.page_previous()
+ return True
+ if keyname == 'Page_Down':
+ self.page_next()
+ return True
+ if keyname == 'Up' or keyname == 'KP_Up' \
+ or keyname == 'KP_Left':
+ self.scroll_up()
+ return True
+ if keyname == 'Down' or keyname == 'KP_Down' \
+ or keyname == 'KP_Right':
+ self.scroll_down()
+ return True
+ return False
+
+ def page_previous(self):
+ global page
+ page=page-1
+ if page &lt; 0: page=0
+ self.show_page(page)
+ v_adjustment = self.scrolled_window.get_vadjustment()
+ v_adjustment.value = v_adjustment.upper - v_adjustment.page_size
+
+ def page_next(self):
+ global page
+ page=page+1
+ if page &gt;= len(self.page_index): page=0
+ self.show_page(page)
+ v_adjustment = self.scrolled_window.get_vadjustment()
+ v_adjustment.value = v_adjustment.lower
+
+ def font_decrease(self):
+ font_size = self.font_desc.get_size() / 1024
+ font_size = font_size - 1
+ if font_size &lt; 1:
+ font_size = 1
+ self.font_desc.set_size(font_size * 1024)
+ self.textview.modify_font(self.font_desc)
+
+ def font_increase(self):
+ font_size = self.font_desc.get_size() / 1024
+ font_size = font_size + 1
+ self.font_desc.set_size(font_size * 1024)
+ self.textview.modify_font(self.font_desc)
+
+ def scroll_down(self):
+ v_adjustment = self.scrolled_window.get_vadjustment()
+ if v_adjustment.value == v_adjustment.upper - \
+ v_adjustment.page_size:
+ self.page_next()
+ return
+ if v_adjustment.value &lt; v_adjustment.upper - v_adjustment.page_size:
+ new_value = v_adjustment.value + v_adjustment.step_increment
+ if new_value &gt; v_adjustment.upper - v_adjustment.page_size:
+ new_value = v_adjustment.upper - v_adjustment.page_size
+ v_adjustment.value = new_value
+
+ def scroll_up(self):
+ v_adjustment = self.scrolled_window.get_vadjustment()
+ if v_adjustment.value == v_adjustment.lower:
+ self.page_previous()
+ return
+ if v_adjustment.value &gt; v_adjustment.lower:
+ new_value = v_adjustment.value - \
+ v_adjustment.step_increment
+ if new_value &lt; v_adjustment.lower:
+ new_value = v_adjustment.lower
+ v_adjustment.value = new_value
+
+ def show_page(self, page_number):
+ global PAGE_SIZE, current_word
+ position = self.page_index[page_number]
+ self.etext_file.seek(position)
+ linecount = 0
+ label_text = '\n\n\n'
+ textbuffer = self.textview.get_buffer()
+ while linecount &lt; PAGE_SIZE:
+ line = self.etext_file.readline()
+ label_text = label_text + unicode(line, 'iso-8859-1')
+ linecount = linecount + 1
+ label_text = label_text + '\n\n\n'
+ textbuffer.set_text(label_text)
+ self.textview.set_buffer(textbuffer)
+
+ def save_extracted_file(self, zipfile, filename):
+ "Extract the file to a temp directory for viewing"
+ filebytes = zipfile.read(filename)
+ f = open("/tmp/" + filename, 'w')
+ try:
+ f.write(filebytes)
+ finally:
+ f.close
+
+ def read_file(self, filename):
+ "Read the Etext file"
+ global PAGE_SIZE
+
+ if zipfile.is_zipfile(filename):
+ self.zf = zipfile.ZipFile(filename, 'r')
+ self.book_files = self.zf.namelist()
+ self.save_extracted_file(self.zf, self.book_files[0])
+ currentFileName = "/tmp/" + self.book_files[0]
+ else:
+ currentFileName = filename
+
+ self.etext_file = open(currentFileName,"r")
+ self.page_index = [ 0 ]
+ linecount = 0
+ while self.etext_file:
+ line = self.etext_file.readline()
+ if not line:
+ break
+ linecount = linecount + 1
+ if linecount &gt;= PAGE_SIZE:
+ position = self.etext_file.tell()
+ self.page_index.append(position)
+ linecount = 0
+ if filename.endswith(".zip"):
+ os.remove(currentFileName)
+
+ def destroy_cb(self, widget, data=None):
+ gtk.main_quit()
+
+ def main(self, file_path):
+ self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ self.window.connect("destroy", self.destroy_cb)
+ self.window.set_title("Read Etexts")
+ self.window.set_size_request(640, 480)
+ self.window.set_border_width(0)
+ self.read_file(file_path)
+ self.scrolled_window = gtk.ScrolledWindow(hadjustment=None, \
+ vadjustment=None)
+ self.textview = gtk.TextView()
+ self.textview.set_editable(False)
+ self.textview.set_left_margin(50)
+ self.textview.set_cursor_visible(False)
+ self.textview.connect("key_press_event", self.keypress_cb)
+ buffer = self.textview.get_buffer()
+ self.font_desc = pango.FontDescription("sans 12")
+ font_size = self.font_desc.get_size()
+ self.textview.modify_font(self.font_desc)
+ self.show_page(0)
+ self.scrolled_window.add(self.textview)
+ self.window.add(self.scrolled_window)
+ self.textview.show()
+ self.scrolled_window.show()
+ v_adjustment = self.scrolled_window.get_vadjustment()
+ self.window.show()
+ gtk.main()
+
+if __name__ == "__main__":
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], "")
+ ReadEtexts().main(args[0])
+ except getopt.error, msg:
+ print msg
+ print "This program has no options"
+ sys.exit(2)
+</pre>
+<h2> Running The Program
+</h2>
+<p>To run the program you should first make it executeable.&nbsp; You only need to do this once:
+</p>
+<pre>chmod 755 ReadEtexts.py</pre>
+<p>For this example I downloaded the file for Pride and Prejudice.&nbsp; The program will work with either of the Plain text formats, which are either uncompressed text or a Zip file.&nbsp; The zip file is named 1342.zip, and we can read the book by running this from a terminal:
+</p>
+<pre>./ReadEtexts.py 1342.zip</pre>
+<p>This is what the program looks like in action:
+</p>
+<p><img alt="The standalone Read Etexts program in action." src="/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/ReadEtexts_01_1.jpg" height="503" width="646" />
+</p>
+<p>You can use the <em>Page Up, Page Down, Up, Down, Left</em>, and <em>Right</em> keys to navigate through the book and the '+' and '-' keys to adjust the font size.
+</p>
+<h2>How The Program Works
+</h2>
+<p>This program reads through the text file containing the book and divides it into pages of 45 lines each.&nbsp; We need to do this because the gtk.TextView component we use for viewing the text would need a lot of memory to scroll through the whole book and that would hurt performance.&nbsp; A second reason is that we want to make reading the e-book as much as possible like reading a regular book, and regular books have pages.&nbsp; If a teacher assigns reading from a book she might say "read pages 35-50 for tommorow".&nbsp; Finally, we want this program to remember what page you stopped reading on and bring you back to that page again when you read the book next time.&nbsp; (The program we have so far doesn't do that yet).
+</p>
+<p>To page through the book we use <em>random access</em> to read the file.&nbsp; To understand what random access means to a file, consider a VHS tape and a DVD.&nbsp; To get to a certain scene in a VHS tape you need to go through all the scenes that came before it, in order.&nbsp; Even though you do it at high speed you still have to look at all of them to find the place you want to start watching.&nbsp; This is <em>sequential access</em>.&nbsp; On the other hand a DVD has chapter stops and possibly a chapter menu.&nbsp; Using a chapter menu you can look at any scene in the movie right away, and you can skip around as you like.&nbsp; This is random access, and the chapter menu is like an <em>index</em>.&nbsp; Of course you can access the material in a DVD sequentially too.
+</p>
+<p>We need random access to skip to whatever page we like, and we need an index so that we know where each page begins.&nbsp; We make the index by reading the entire file one line at a time.&nbsp; Every 45 lines we make a note of how many characters into the file we've gotten and store this information in a Python list.&nbsp; Then we go back to the beginning of the file and display the first page.&nbsp; When the program user goes to the next or previous page we figure out what the new page number will be and look in the list entry for that page.&nbsp; This tells us that page starts 4,200 characters into the file.&nbsp; We use seek() on the file to go to that character and then we read 45 lines starting at that point and load them into the TextView.
+</p>
+<p>When you run this program notice how fast it is.&nbsp; Python programs take longer to run a line of code than a compiled language would, but in this program it doesn't matter because the heavy lifting in the program is done by the TextView, which was created in a compiled language.&nbsp; The Python parts don't do that much so the program doesn't spend much time running them.
+</p>
+<p>Sugar uses Python a lot, not just for Activities but for the Sugar environment itself.&nbsp; You may read somewhere that using so much Python is "a disaster" for performance.&nbsp; Don't believe it.
+</p>
+<p>There are no slow programming languages, only slow programmers.
+ <br />
+</p>
+<p />
+ </p></div>
+ </div>
+<div class="arrow" style="position:relative;left:10px;width:50px;float:left;bottom:5px;"><a href="#" onClick="previous();"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/lefttext.png" height=20></a></div>
+<div class="arrow" style="position:relative;left:528px;width:50px;float:left;bottom:5px;"><a href="#" onClick="next();"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/righttext.png" height=20></a></div>
+ <br>
+ <br>
+ <br>
+ <br>
+ </td>
+ </tr>
+ </table>
+ </div>
+<!-- Piwik -->
+<a href="http://piwik.org" title="Web analytics" onclick="window.open(this.href);return(false);">
+<script language="javascript" src="http://adam.engagetv.com/piwik/piwik.js" type="text/javascript"></script>
+<script type="text/javascript">
+<!--
+piwik_action_name = '';
+piwik_idsite = 1;
+piwik_url = 'http://adam.engagetv.com/piwik/piwik.php';
+piwik_log(piwik_action_name, piwik_idsite, piwik_url);
+//-->
+</script>
+<!-- /Piwik -->
+<script language="Javascript">
+document.getElementById("StandalonePythonReadEtexts").style.backgroundColor="#F99B1C";
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/help/ActivityBook/ActivitiesGuideSugar/UsingVersionControl b/help/ActivityBook/ActivitiesGuideSugar/UsingVersionControl
new file mode 100644
index 0000000..a6f9870
--- /dev/null
+++ b/help/ActivityBook/ActivitiesGuideSugar/UsingVersionControl
@@ -0,0 +1,544 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html>
+ <head>
+ <title>ActivitiesGuideSugar (en)</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <!--
+ <link rel="alternate" type="application/rss+xml" title="RSS Feed" href="WebRss.html" />
+ -->
+ <link rel="icon" href="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/fl2.ico" type="image/x-icon" /> <link rel="shortcut icon" href="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/fl2.ico" type="image/x-icon" />
+ <link rel=StyleSheet href="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/typography.css" type="text/css" media="screen">
+<style>
+#index {
+ color: #ff7f00;
+ font-family: trebuchet,sans-serif;
+ font-size: 10px;
+ line-height:11px;
+}
+#index UL {
+ width: 159px;
+ list-style-type: None;
+ padding-left: 0px;
+ border: 14px solid #ff7f00;
+ background-color: #ff7f00;
+ margin: 0px 0px 0px 0px;
+ }
+#index LI {
+ padding-left: 0px;
+ padding-right: 10px;
+ padding-top: 4px;
+ padding-bottom: 4px;
+ color: #ffffff;
+ margin: 0px 0px 0px 0px;
+ background-color: #ff7f00;
+ border-top: 1px solid #ff7f00;
+ }
+#index LI:hover {
+ background-color: #F99B1C;
+}
+#index LI.heading {
+ background-color: #ff7f00;
+ color: #000000;
+ border-top:1px solid #FFE5CC;
+ padding-top: 7px;
+ font-weight: bold;
+}
+#index LI.title {
+ border-bottom: 2px solid #FFE5CC;
+ background-color: #ff7f00;
+ color: #FBF4E9;
+ font-weight: bolder;
+ font-size:10px;
+ line-height:18px;
+ padding-bottom: 40px;
+ }
+#index A {
+ text-decoration: none;
+ color: #FBF4E9;
+ font-weight: bold;
+}
+#ds-layout .imgcontainer {
+ position:relative;
+ }
+#ds-layout .caption {
+ position:relative;
+ bottom:1;
+ left:0;
+ text-align:center;
+ background:#ffe7cb;
+ width:100%;
+ opacity:.75;
+ filter:alpha(opacity=85);
+ color:#000;
+ font-style: italic;
+ font-size: 9px;
+ line-height:11px;
+ }
+</style>
+<script type="text/javascript">
+function addLoadEvent(func) {
+ var oldonload = window.onload;
+ if (typeof window.onload != 'function') {
+ window.onload = func;
+ } else {
+ window.onload = function() {
+ oldonload();
+ func();
+ }
+ }
+}
+
+function insertAfter(newElement,targetElement) {
+ var parent = targetElement.parentNode;
+ if (parent.lastChild == targetElement) {
+ parent.appendChild(newElement);
+ } else {
+ parent.insertBefore(newElement,targetElement.nextSibling);
+ }
+}
+
+function captionizeImages() {
+ if (!document.getElementsByTagName) return false;
+ if (!document.createElement) return false;
+ var images = document.getElementsByTagName("img");
+ if (images.length < 1) return false;
+ for (var i=0; i<images.length; i++) {
+ if (images[i].className != "non") {
+ var title = images[i].getAttribute("title");
+ var width = images[i].width;
+ var divCaption = document.createElement("div");
+ divCaption.className="caption";
+ divCaption.style.width=width+'px';
+ if (title) divCaption.style.padding='2px 0px 3px 0px';
+ divCaption.style.display='block';
+ var divCaption_text = document.createTextNode(title);
+ divCaption.appendChild(divCaption_text);
+ var divContainer = document.createElement("div");
+ divContainer.className="imgcontainer";
+ if (title) divContainer.style.padding='0px 0px 10px 0px';
+ images[i].parentNode.insertBefore(divContainer,images[i]);
+ divContainer.appendChild(images[i]);
+ insertAfter(divCaption,images[i]);
+ }
+ }
+}
+//addLoadEvent(captionizeImages);
+
+function next () {
+var onode, otarget;
+onode=document.getElementById("UsingVersionControl");
+if (onode.id=="Credits") die;
+//alert (onode.id);
+onode=onode.nextSibling;
+if (onode.id=="heading") onode=onode.nextSibling;
+while (onode) {
+ //onode=onode.nextSibling;
+ if (onode.nodeType==1) {
+ //alert (onode.id);
+ otarget=onode;
+ break;
+ }
+ onode=onode.nextSibling;
+}
+if (otarget) {
+ //you actually have found one, and do something here
+ //alert(otarget.id + "\n" + otarget.tagName); //just to verify
+ top.location = "/ActivitiesGuideSugar/" + otarget.id;
+} else {
+ //you don't find one
+//alert("nada" + otarget.id);
+}
+}
+
+function previous () {
+var onode, otarget;
+onode=document.getElementById("UsingVersionControl");
+if (onode.id=="Introduction") die;
+//alert (onode.id);
+onode=onode.previousSibling;
+if (onode.id=="heading") onode=onode.previousSibling;
+if (onode.id=="title") die;
+while (onode) {
+ //onode=onode.previousSibling;
+ if (onode.nodeType==1) {
+ //alert (onode.id);
+ otarget=onode;
+ break;
+ }
+ onode=onode.previousSibling;
+}
+if (otarget) {
+ //you actually have found one, and do something here
+ //alert(otarget.id + "\n" + otarget.tagName); //just to verify
+ top.location = otarget.id;
+} else {
+ //you don't find one
+//alert("nada" + otarget.id);
+}
+}
+
+</script>
+ </head>
+ <body background="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/background.gif" style="margin:0;color:#000000;">
+<div id="home" style="position:absolute;left:0px;top:10px;">
+<a href="/"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/top_read_back.gif" border="0"></a>
+</div>
+<div id="index" style="position:absolute;left:0px;top:150px;">
+<ul>
+<li class="title">MAKING SUGAR ACTIVITIES</li><li id="Introduction"><a href="/ActivitiesGuideSugar/Introduction">INTRODUCTION</a></li><li id="WhatIsSugar"><a href="/ActivitiesGuideSugar/WhatIsSugar">WHAT IS SUGAR?</a></li><li id="WhatisanActivity"><a href="/ActivitiesGuideSugar/WhatisanActivity">WHAT IS A SUGAR ACTIVITY?</a></li><li id="NeedtoKnowWriteSugarActivity"><a href="/ActivitiesGuideSugar/NeedtoKnowWriteSugarActivity">WHAT DO I NEED TO KNOW TO WRITE A SUGAR ACTIVITY?</a></li><li id="SetUpDevEnvironment"><a href="/ActivitiesGuideSugar/SetUpDevEnvironment">SETTING UP A DEVELOPMENT ENVIRONMENT</a></li><li id="CreateFirstActivity"><a href="/ActivitiesGuideSugar/CreateFirstActivity">CREATING YOUR FIRST ACTIVITY</a></li><li id="StandalonePythonReadEtexts"><a href="/ActivitiesGuideSugar/StandalonePythonReadEtexts">MAKING A STANDALONE PYTHON PROGRAM</a></li><li id="InheritFromActivity"><a href="/ActivitiesGuideSugar/InheritFromActivity">INHERIT FROM SUGAR.ACTIVITY.ACTIVITY</a></li><li id="PackageTheActivity"><a href="/ActivitiesGuideSugar/PackageTheActivity">PACKAGE THE ACTIVITY</a></li><li id="AddRefinements"><a href="/ActivitiesGuideSugar/AddRefinements">ADD REFINEMENTS</a></li><li id="UsingVersionControl"><a href="/ActivitiesGuideSugar/UsingVersionControl">ADD YOUR ACTIVITY CODE TO VERSION CONTROL</a></li><li id="Credits"><a href="/ActivitiesGuideSugar/Credits">CREDITS</a></li></ul>
+</div>
+<div id="pdf" style="position:absolute;left:13px;top:190px;">
+<a href="/ActivitiesGuideSugar/FM_06Jan10.pdf"><img class ="non" src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/makepdf.gif" border=0></a>
+<!-- <a href="/ActivitiesGuideSugar/FM_ActivitiesGuideSugar_06Jan10.pdf"><img class ="non" src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/makepdf.gif" border=0></a> -->
+<a href="/ActivitiesGuideSugar/print"><img class="non" src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/viewprint.gif" border=0></a>
+</div>
+ <div style="position:absolute;left:240px;top:11px;">
+ <table id="ds-layout" cellpadding="0" cellspacing="0" sumtop:5px;mary="" style="table-layout:fixed;width:670px;border: 5px solid #666666;padding-right: 0px;padding-left: 0px;padding-bottom: 0px;padding-top: 0px;margin-left : 10px;margin-top:10;background:#FFF7F0;">
+ <tr>
+ <td width=100%>
+<div class="arrow" style="position:relative;left:10px;top:5px;width:50px;float:left;"><a href="#" onClick="previous();"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/lefttext.png" height=20></a></div>
+<div class="arrow" style="position:relative;left:528px;width:50px;top:5px;float:left;"><a href="#" onClick="next();"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/righttext.png" height=20></a></div>
+ <div class="ds-contentcontainer">
+ <div style="margin-left:1.2em;float:right">
+ <br>
+ <div class="huh" style='decoration:none;color:black;border:1;position:absolute;top:60px;left:502px;'>
+ <a href='http://www.flossmanuals.net/bin/view/ActivitiesGuideSugar/UsingVersionControl' onClick="alert('You will now be forwarded to the FLOSS Manuals editing interface')"><b><font color=#ff7f00><small>Edit this page</small></font></b></a> :: <a href='http://www.flossmanuals.net/bin/view/ActivitiesGuideSugar/FMComments?skin=floss2'><b><font color=#ff7f00><small>Discussion</small></font></b></a>
+ </div>
+ <h1>Putting Your Activity Code In Version Control
+</h1>
+<h2>What Is Version Control?
+</h2>
+<p> <em>"If I have seen further it is only by standing on the shoulders of giants."</em>
+</p>
+<p>Isaac Newton, in a letter to Robert Hooke.
+</p>
+<p>Writing an Activity is usually not something you do by yourself.&nbsp; You will usually have collaborators in one form or another.&nbsp; When I started writing <strong>Read Etexts</strong> I copied much of the code from the <strong>Read</strong> Activity.&nbsp; When I implemented text to speech I adapted a toolbar from the <strong>Speak</strong> Activity.&nbsp; When I finally got my copied file sharing code working the author of <strong>Image Viewer</strong> thought it was good enough to copy into that Activity.&nbsp; Another programmer saw the work I did for text to speech and thought he could do it better.&nbsp; He was right, and his improvements got merged into my own code.&nbsp; When I wrote <strong>Get Internet Archive Books</strong> someone else took the user interface I came up with and made a more powerful and versatile Activity called <strong>Get Books</strong>.&nbsp; Like Newton, everyone benefits from the work others have done before.
+ <br />
+</p>
+<p>Even if I wanted to write Activities without help I would still need collaborators to translate them into other languages.
+</p>
+<p>To make collaboration possible you need to have a place where everyone can post their code and share it.&nbsp; This is called a code repository.&nbsp; It isn't enough to just share the latest version of your code.&nbsp; What you really want to do is share <em>every</em> version of your code.&nbsp; Every time you make a significant change to your code you want to have the new version and the previous version available.&nbsp; Not only do you want to have every version of your code available, you want to be able to compare any two versions your code to see what changed between them.&nbsp; This is what version control software does.
+</p>
+<p>The three most popular version control tools are <em>CVS</em>, <em>Subversion</em>, and <em>Git</em>.&nbsp; Git is the newest and is the one used by Sugar Labs.&nbsp; While not every Activity has its code into the Sugar Labs Git repository (other free code repositories exist) there is no good reason not to do it and significant benefits if you do.&nbsp; If you want to get your Activity translated into other languages using a Sugar Labs Git repository is a must. &nbsp;
+ <br />
+</p>
+<h2>Git Along Little Dogies
+</h2>
+<p>Git is a <em>distributed</em> version control system.&nbsp; This means that not only are there copies of every version of your code in a central repository, the same copies exist on every user's computer.&nbsp; This means you can update your local repository while you are not connected to the Internet, then connect and share everything at one time.
+</p>
+<p> There are two ways you will interact with your Git repository: through Git commands and through the website at <a href="http://git.sugarlabs.org/.">http://git.sugarlabs.org/.</a>&nbsp;&nbsp; We'll look at this website first.
+</p>
+<p>Go to <a href="http://git.sugarlabs.org">http://git.sugarlabs.org/</a>&nbsp; and click on the <strong>Projects</strong> link in the upper right corner:
+</p>
+<p><img alt="git1.jpg" src="/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git1.jpg" height="194" width="473" />
+</p>
+<p>You will see a list of projects in the repository.&nbsp; They will be listed from newest to oldest.&nbsp; You'll also see a <strong>New Project</strong> link but you'll need to create an account to use that and we aren't ready to do that yet.
+ <br />
+</p>
+<p><img alt="git2.jpg" src="/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git2.jpg" height="453" width="535" />
+</p>
+<p>If you use the <strong>Search</strong> link in the upper right corner of the page you'll get a search form.&nbsp; Use it to search for "read etexts".&nbsp; Click on the link for that project when you find it.&nbsp; You should see something like this:
+ <br />
+</p>
+<p><img alt="git3.jpg" src="/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git3.jpg" height="571" width="571" />
+</p>
+<p>This page lists <em>some</em> of the activity for the project but I don't find it particularly useful.&nbsp; To get a much better look at your project start by clicking on the repository name on the right side of the page.&nbsp; In this case the repository is named <strong>mainline</strong>.
+</p>
+<p><img alt="git4.jpg" src="/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git4.jpg" height="236" width="399" />
+</p>
+<p>You'll see something like this at the top of the page:
+</p>
+<p><img alt="git5.jpg" src="/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git5.jpg" height="509" width="574" />
+</p>
+<p>This page has some useful information on it.&nbsp; First, have a look at the <strong>Public clone url</strong> and the <strong>HTTP clone url</strong>.&nbsp; You need to click on <strong>More info...</strong> to see either one.&nbsp; If you run either of these commands from the console you will get a copy of the git repository for the project copied to your computer.&nbsp; This copy will include every version of every piece of code in the project.&nbsp; You would need to modify it a bit before you could share your changes back to the main repository, but everything would be there.
+</p>
+<p>The list under <strong>Activities</strong> is not that useful, but if you click on the <strong>Source Tree</strong> link you'll see something really good:
+</p>
+<p><img alt="git6.jpg" src="/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git6.jpg" height="468" width="571" />
+</p>
+<p>Here is a list of every file in the project, the date it was last updated, and a comment on what was modified.&nbsp; Click on the link for <strong>ReadEtextsActivity.py</strong> and you'll see this:
+</p>
+<p><img alt="git7.jpg" src="/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git7.jpg" height="642" width="597" />
+</p>
+<p>This is the latest code in that file in pretty print format.&nbsp; Python keywords are shown in a different color, there are line numbers, etc.&nbsp; This is a good page for looking at code on the screen, but it doesn't print well and it's not much good for copying snippets of code into Eric windows either.&nbsp; For either of those things you'll want to click on <strong>raw blob data</strong> at the top of the listing:
+</p>
+<p><img alt="git8.jpg" src="/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git8.jpg" height="484" width="549" />
+</p>
+<p>We're not done yet.&nbsp; Use the <strong>Back</strong> button to get back to the pretty print listing and click on the <strong>Commits</strong> link.&nbsp; This will give us a list of everything that changed each time we committed code into Git:
+</p>
+<p><img alt="git9.jpg" src="/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git9.jpg" height="540" width="636" />
+</p>
+<p>You may have noticed the odd combination of letters and numbers after the words <strong>James Simmons committed</strong>.&nbsp; This is a kind of version number.&nbsp; The usual practice with version control systems is to give each version of code you check in a version number, usually a simple sequence number.&nbsp; Git is distributed, with many separate copies of the repository being modified independently and then merged.&nbsp; That makes using just a sequential number to identify versions unworkable.&nbsp; Instead, Git gives each version a really, really large random number.&nbsp; The number is expressed in base 16, which uses the symbols 0-9 and a-f.&nbsp; What you see in green is only a small part of the complete number.&nbsp; The number is a link, and if you click on it you'll see this:
+</p>
+<p><img alt="git10.jpg" src="/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git10.jpg" height="607" width="561" />
+</p>
+<p>At the top of the page we see the complete version number used for this commit.&nbsp; Below the gray box we see the full comment that was used to commit the changes.&nbsp; Below that is a listing of what files were changed.&nbsp;&nbsp; If we look further down the page we see this:
+</p>
+<p><img alt="git11_1.jpg" src="/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git11_1.jpg" height="530" width="581" />
+</p>
+<p>This is a <em>diff</em> report which shows the lines that have changed between this version and the previous version.&nbsp; For each change it shows a few lines before and after the change to give you a better idea of what the change does.&nbsp; Every change shows line numbers too.
+</p>
+<p>A report like this is a wonderful aid to programming.&nbsp; Sometimes when you're working on an enhancement to your program something that had been working mysteriously stops working.&nbsp; When that happens you will wonder just what you changed that could have caused the problem.&nbsp; A diff report can help you find the source of the problem.
+</p>
+<p>By now you must be convinced that you want your project code in Git.&nbsp; Before we can do that we need to create an account on this website.&nbsp; That is no more difficult than creating an account on any other website, but it will need an important piece of information from us that we don't have yet.&nbsp; Getting that information is our next task.
+</p>
+<h2>Setting Up SSH Keys
+</h2>
+<p>To send your code to the gitorious code repository you need an SSH public/private key pair.&nbsp; SSH is a way of sending data over the network in encrypted format.&nbsp; (In other words, it uses a secret code so nobody but the person getting the data can read it).&nbsp; Public/private key encryption is a way of encrypting data that provides a way to guarantee that the person who is sending you the data is who he claims to be.
+</p>
+<p>In simple terms it works like this: the SSH software generates two very large numbers that are used to encode and decode the data going over the network.&nbsp; The first number, called the <em>private key</em>, is kept secret and is only used by you to encode the data.&nbsp; The second number, called the <em>public key</em>, is given to anyone who needs to decode your data.&nbsp; He can decode it using the public key; there is no need for him to know the private key.&nbsp; He can also use the public key to encode a message to send back to you and you can decode it using your private key.
+</p>
+<p>Git uses SSH like an electronic signature to verify that code changes that are supposed to be coming from you actually are coming from you.&nbsp; The Git repository is given your public key.&nbsp; It knows that anything it decodes with that key must have been sent by you because only you have the private key needed to encode it.
+</p>
+<p> We will be using a tool called <strong>OpenSSH</strong> to generate the public and private keys.&nbsp; This is included with every version of Linux so you just need to verify that it has been installed.&nbsp; Then use the <strong>ssh-keygen</strong> utility that comes with OpenSSH to generate the keys:
+ <br />
+</p>
+<pre>[jim@olpc2 ~]$ ssh-keygen
+Generating public/private rsa key pair.
+Enter file in which to save the key (/home/jim/.ssh/id_rsa): </pre>
+<p>By default ssh-keygen generates an <strong>RSA</strong> key, which is the kind we want.&nbsp; By default it puts the keyfiles in a directory called <strong>/<em>yourhome</em>/.ssh</strong> and we want that too, so DO NOT enter a filename when it asks you to.&nbsp; Just hit the <strong>Enter</strong> key to continue.
+</p>
+<pre>[jim@olpc2 ~]$ ssh-keygen
+Generating public/private rsa key pair.
+Enter file in which to save the key (/home/jim/.ssh/id_rsa):
+Created directory '/home/jim/.ssh'.
+Enter passphrase (empty for no passphrase):
+</pre>
+<p>Now we DO want a passphrase here.&nbsp; A passphrase is like a password that is used with the public and private keys to do the encrypting.&nbsp; When you type it in you will not be able to see what you typed.&nbsp; Because of that it will ask you to type the same thing again, and it will check to see that you typed them in the same way both times.
+</p>
+<pre>[jim@olpc2 ~]$ ssh-keygen
+Generating public/private rsa key pair.
+Enter file in which to save the key (/home/jim/.ssh/id_rsa):
+Created directory '/home/jim/.ssh'.
+Enter passphrase (empty for no passphrase):
+Enter same passphrase again:
+Your identification has been saved in /home/jim/.ssh/id_rsa.
+Your public key has been saved in /home/jim/.ssh/id_rsa.pub.
+The key fingerprint is:
+d0:fe:c0:0c:1e:72:56:7a:19:cd:f3:85:c7:4c:9e:18 jim@olpc2.simmons
+The key's randomart image is:
++--[ RSA 2048]----+
+| oo E=. |
+| + o+ .+=. |
+| . B + o.oo |
+| = O . |
+| . S |
+| o |
+| . |
+| |
+| |
++-----------------+
+</pre>
+<p> When choosing a passphrase remember that it needs to be something you can type reliably without seeing it and it would be better if it was <em>not</em> a word you can find in the dictionary, because those are easily broken. When I need to make a password I use the tool at <a href="http://www.multicians.org/thvv/gpw.html.">http://www.multicians.org/thvv/gpw.html.</a>&nbsp; This tool generates a bunch of nonsense words that are pronounceable.&nbsp; Pick one that appeals to you and use that.
+</p>
+<p>Now have a look inside the .ssh directory.&nbsp; By convention every file or directory name that begins with a period is considered hidden by Linux, so it won't show up in a GNOME file browser window unless you use the option on the View menu to Show Hidden Files.&nbsp; When you display the contents of that directory you'll see two files: <strong>id_rsa</strong> and <strong>id_rsa.pub</strong>.&nbsp; The public key is in id_rsa.pub.&nbsp; Try opening that file with gedit (Open With Text Editor) and you'll see this:
+</p>
+<p><img alt="git12.jpg" src="/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git12.jpg" height="278" width="640" />
+</p>
+<p>When you create your account on <a href="http://git.sugarlabs.org">git.sugarlabs.org</a> there will be a place where you can add your public SSH key.&nbsp; To do that use Select All from the Edit menu in gedit, then Copy and Paste into the field provided on the web form.
+</p>
+<h2>Create A New Project
+</h2>
+<p>I'm going to create a new Project in Git for the examples for this book.&nbsp; I need to log in with my new account and click the <strong>New Project</strong> link we saw earlier.&nbsp; I get this form, which I have started filling in:
+</p>
+<p><img alt="git13.jpg" src="/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git13.jpg" height="343" width="398" />
+</p>
+<p>The <strong>Title</strong> is used on the website, the <strong>Slug</strong> is a shortened version of the title without spaces used to name the Git repository.&nbsp; <strong>Categories</strong> are optional.&nbsp; <strong>License</strong> is GPL v2 for my projects.&nbsp; You can choose from any of the licenses in the list for your own Projects, and you can change the license entry later if you want to.&nbsp; You will also need to enter a <strong>Description</strong> for your project.
+</p>
+<p>Once you have this set up you'll be able to click on the mainline entry for the Project (like we did with Read Etexts before) and see something like this:
+</p>
+<p><img alt="git14.jpg" src="/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git14.jpg" height="454" width="640" />
+</p>
+<p>The next step is to convert our project files into a local Git repository, add the files to it, then push it to the repository on <a href="http://git.sugarlabs.org">git.sugarlabs.org.</a>&nbsp; We need to do this because you cannot clone an empty repository, and our remote repository is currently empty.&nbsp; To get around that problem we'll push the local repository out to the new remote repository we just created, then clone the remote one and delete our existing project and its Git repository.&nbsp; From then on we'll do all our work in the cloned repository.
+ <br />
+</p>
+<p>This process may remind you of the Edward Albee quote, "<span class="body">Sometimes a person has to go a very long distance out of his way to come back a short distance correctly".</span> Fortunately we only need to do it once per project.&nbsp; Enter the commands shown below in <strong>bold</strong> after making you project directory the current one:
+ <br />
+</p>
+<pre><strong>git init</strong>
+Initialized empty Git repository in /home/jim/olpc/bookexamples/.git/
+<strong>git add *.py</strong>
+<strong>git add activity
+git add MANIFEST</strong>
+<strong>git add .gitignore
+git commit -a -m "Create repository and load"</strong>
+[master (root-commit) 727bfe8] Create repository and load
+ 9 files changed, 922 insertions(+), 0 deletions(-)
+ create mode 100644 .gitignore
+ create mode 100644 MANIFEST
+ create mode 100755 ReadEtexts.py
+ create mode 100644 ReadEtextsActivity.py
+ create mode 100644 ReadEtextsActivity2.py
+ create mode 100644 activity/activity.info
+ create mode 100644 activity/read-etexts.svg
+ create mode 100755 setup.py
+ create mode 100644 toolbar.py
+</pre>
+<p> I have made an empty local Git repository with <strong>git init</strong>, then I've used <strong>git add</strong> to add the important files to it.&nbsp; (In fact <strong>git add</strong> doesn't actually add anything itself; it just tells Git to add the file on the next <strong>git commit</strong>).&nbsp; Finally <strong>git commit</strong> with the options shown will actually put the latest version of these files in my new local repository.
+</p>
+<p>To push this local repository to <a href="http://git.sugarlabs.org">git.sugarlabs.org</a>&nbsp; we use the commands from the web page:
+</p>
+<pre><strong>git remote add origin gitorious@git.sugarlabs.org:myo-sugar-activities-examples/mainline.git
+git push origin master</strong>
+Counting objects: 17, done.
+Compressing objects: 100% (14/14), done.
+Writing objects: 100% (15/15), 7.51 KiB, done.
+Total 15 (delta 3), reused 0 (delta 0)
+To gitorious@git.sugarlabs.org:myo-sugar-activities-examples/mainline.git
+ 2cb3a1e..700789d master -&gt; master
+=&gt; Syncing Gitorious...
+Heads up: head of changed to 700789d3333a7257999d0a69bdcafb840e6adc09 on master
+Notify cia.vc of 727bfe819d5b7b70f4f2b31d02f5562709284ac4 on myo-sugar-activities-examples
+Notify cia.vc of 700789d3333a7257999d0a69bdcafb840e6adc09 on myo-sugar-activities-examples
+[OK]
+<strong>rm *</strong>
+<strong>rm activity -rf
+rm .git -rf</strong>
+<strong>cd ~</strong>
+<strong>mkdir olpc</strong>
+<strong>cd olpc</strong>
+<strong>mkdir bookexamples</strong>
+<strong>cd bookexamples
+git clone git://git.sugarlabs.org/myo-sugar-activities-examples/mainline.git</strong>
+Initialized empty Git repository in /home/jim/olpc/bookexamples/mainline/.git/
+remote: Counting objects: 18, done.
+remote: Compressing objects: 100% (16/16), done.
+remote: Total 18 (delta 3), reused 0 (delta 0)
+Receiving objects: 100% (18/18), 8.53 KiB, done.
+Resolving deltas: 100% (3/3), done.
+</pre>
+<p> The lines in <strong>bold</strong> are the commands to enter, and everything else is messages that Git sends to the console. It probably isn't clear what we're doing here and why, so let's take it step by step:
+</p>
+<ul>
+ <li>The first command <strong>git remote add origin</strong> tells the remote Git repository that we are going to send it stuff from our local repository.
+ <br /></li>
+ <li>The second command <strong>git push origin master</strong> actually sends your local Git repository to the remote one and its contents will be copied in.&nbsp; When you enter this command you will be asked to enter the SSH pass phrase you created in the last section.&nbsp; GNOME will remember this phrase for you and enter it for every Git command afterwards so you don't need to.&nbsp; It will keep doing this until you log out or turn off the computer.
+ <br /></li>
+ <li>The next step is to delete our existing files and our local Git repository (which is contained in the hidden directory .git).&nbsp; The <strong>rm .git -rf</strong> means "Delete the directory .git and everything in it".&nbsp; <strong>rm</strong> is a Unix command, not part of Git.&nbsp; If you like you can delete your existing files <em>after</em> you create the cloned repository in the next step.
+ <br /></li>
+ <li>Now we do the <strong>git clone</strong> command from the web page.&nbsp; This takes the remote Git repository we just added our MANIFEST file to and makes a new local repository in directory <strong>/<em>yourhome</em>/olpc/bookexamples/mainline.</strong></li>
+</ul>
+<p>Finally we have a local repository we can use.&nbsp; Well, not quite.&nbsp; We can commit our code to it but we cannot push anything back to the remote repository because our local repository isn't configured correctly yet.
+</p>
+<p>What we need to do is edit the file <strong>config</strong> in directory <strong>.git</strong> in <strong>/<em>yourhome</em>/olpc/bookexamples/mainline.&nbsp; </strong>We can use gedit to do that.&nbsp; We need to change the <strong>url=</strong> entry to point to the <strong>Push url</strong> shown on the mainline web page.&nbsp; When we're done our <strong>config</strong> file should look like this:
+</p>
+<pre>[core]
+ repositoryformatversion = 0
+ filemode = true
+ bare = false
+ logallrefupdates = true
+[remote "origin"]
+ <strong>url = gitorious@git.sugarlabs.org:myo-sugar-activities-examples/mainline.git</strong>
+ fetch = +refs/heads/*:refs/remotes/origin/*
+[branch "master"]
+ remote = origin
+ merge = refs/heads/master
+</pre>
+<p> The line in <strong>bold</strong> is the only one that gets changed.
+</p>
+<p>From now on anyone who wants to work on our project can get a local copy of the Git repository by doing this from within the directory where he wants the repository to go:
+</p>
+<p>
+</p>
+<pre><strong>git clone git://git.sugarlabs.org/myo-sugar-activities-examples/mainline.git</strong></pre>
+<p> He'll have to change his <strong>.git/config</strong> file just like we did, then he'll be ready to go.
+</p>
+<h2>Everyday Use Of Git
+</h2>
+<p> While getting the repositories set up to begin with is a chore, daily use is not.&nbsp; There are only a few commands you'll need to work with.&nbsp; When we left off we had a repository in <strong>/<em>yourhome</em>/olpc/bookexamples/mainline</strong> with our files in it.&nbsp; We will need to add any new files we create too.
+ <br />
+</p>
+<p>We use the <strong>git add</strong> command to tell Git that we want to use Git to store a particular file.&nbsp; This doesn't actually store anything, it just tells Git our intentions.&nbsp; The format of the command is simply:
+</p>
+<pre>git add <em>file_or_directory_name</em></pre>
+<p>There are files we <em>don't</em> want to add to Git, to begin with those files that end in <strong>.pyc</strong>.&nbsp; If we never do a <strong>git add</strong> on them they'll never get added, but Git will constantly ask us why we aren't adding them.&nbsp; Fortunately there is a way to tell Git that we really, really don't want to add those files.&nbsp; We need to create a file named <strong>.gitignore</strong> using gedit and put in entries like this:
+</p>
+<pre>*.pyc
+*.e4p
+*.zip
+.eric4project/
+.ropeproject/</pre>
+<p>These entries will also ignore project files used by Eric and zip files containing ebooks,&nbsp; Once we have this file created in the mainline directory we can add it to the repository:
+</p>
+<pre>git add .gitignore
+git commit -a -m "Add .gitignore file"
+</pre>
+<p>From now on Git will no longer ask us to add .pyc or other unwanted&nbsp; files that match our patterns. If there are other files we don't want in the repository we can add them to .gitignore either as full file names or directory names or as patterns like *.pyc.
+</p>
+<p>&nbsp;In addition to adding files to Git we can remove them too:
+</p>
+<pre>git rm <em>filename</em></pre>
+<p>Note that this just tells Git that from now on it will not be keeping track of a given filename, and that will take effect at the next commit.&nbsp; Old versions of the file are still in the repository.
+</p>
+<p>If you want to see what&nbsp;changes will be applied at the next commit run this:
+</p>
+<pre>git status</pre>
+<p>Finally, to put your latest changes in the repository use this:
+</p>
+<pre>git commit &nbsp;-a -m "Put a comment here"</pre>
+<p>If you leave off the -m an editor will open up and you can type in a comment, then save and exit. Unfortunately by default the editor is vi, an old text mode editor that is not friendly like gedit.
+</p>
+<p>When we have all our changes done we can send them to the central repository using <strong>git push</strong>:
+</p>
+<pre>git push</pre>
+<p>We can get the latest changes from other developers by doing <strong>git pull</strong>:
+</p>
+<pre><strong>git pull</strong>
+remote: Counting objects: 17, done.
+remote: Compressing objects: 100% (14/14), done.
+remote: Total 15 (delta 3), reused 0 (delta 0)
+Unpacking objects: 100% (15/15), done.
+From gitorious@git.sugarlabs.org:myo-sugar-activities-examples/mainline
+ 2cb3a1e..700789d master -&gt; origin/master
+Updating 2cb3a1e..700789d
+Fast forward
+ .gitignore | 6 +
+ MANIFEST | 244 +-----------------------------------
+ ReadEtexts.py | 182 +++++++++++++++++++++++++++
+ ReadEtextsActivity.py | 182 +++++++++++++++++++++++++++
+ ReadEtextsActivity2.py | 311 ++++++++++++++++++++++++++++++++++++++++++++++
+ activity/activity.info | 9 ++
+ activity/read-etexts.svg | 71 +++++++++++
+ setup.py | 21 +++
+ toolbar.py | 136 ++++++++++++++++++++
+ 9 files changed, 921 insertions(+), 241 deletions(-)
+ create mode 100644 .gitignore
+ create mode 100755 ReadEtexts.py
+ create mode 100644 ReadEtextsActivity.py
+ create mode 100644 ReadEtextsActivity2.py
+ create mode 100644 activity/activity.info
+ create mode 100644 activity/read-etexts.svg
+ create mode 100755 setup.py
+ create mode 100644 toolbar.py
+&nbsp;</pre>
+<p />
+ </p></div>
+ </div>
+<div class="arrow" style="position:relative;left:10px;width:50px;float:left;bottom:5px;"><a href="#" onClick="previous();"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/lefttext.png" height=20></a></div>
+<div class="arrow" style="position:relative;left:528px;width:50px;float:left;bottom:5px;"><a href="#" onClick="next();"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/righttext.png" height=20></a></div>
+ <br>
+ <br>
+ <br>
+ <br>
+ </td>
+ </tr>
+ </table>
+ </div>
+<!-- Piwik -->
+<a href="http://piwik.org" title="Web analytics" onclick="window.open(this.href);return(false);">
+<script language="javascript" src="http://adam.engagetv.com/piwik/piwik.js" type="text/javascript"></script>
+<script type="text/javascript">
+<!--
+piwik_action_name = '';
+piwik_idsite = 1;
+piwik_url = 'http://adam.engagetv.com/piwik/piwik.php';
+piwik_log(piwik_action_name, piwik_idsite, piwik_url);
+//-->
+</script>
+<!-- /Piwik -->
+<script language="Javascript">
+document.getElementById("UsingVersionControl").style.backgroundColor="#F99B1C";
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/help/ActivityBook/ActivitiesGuideSugar/WhatIsSugar b/help/ActivityBook/ActivitiesGuideSugar/WhatIsSugar
new file mode 100644
index 0000000..3ce9c1b
--- /dev/null
+++ b/help/ActivityBook/ActivitiesGuideSugar/WhatIsSugar
@@ -0,0 +1,311 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html>
+ <head>
+ <title>ActivitiesGuideSugar (en)</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <!--
+ <link rel="alternate" type="application/rss+xml" title="RSS Feed" href="WebRss.html" />
+ -->
+ <link rel="icon" href="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/fl2.ico" type="image/x-icon" /> <link rel="shortcut icon" href="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/fl2.ico" type="image/x-icon" />
+ <link rel=StyleSheet href="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/typography.css" type="text/css" media="screen">
+<style>
+#index {
+ color: #ff7f00;
+ font-family: trebuchet,sans-serif;
+ font-size: 10px;
+ line-height:11px;
+}
+#index UL {
+ width: 159px;
+ list-style-type: None;
+ padding-left: 0px;
+ border: 14px solid #ff7f00;
+ background-color: #ff7f00;
+ margin: 0px 0px 0px 0px;
+ }
+#index LI {
+ padding-left: 0px;
+ padding-right: 10px;
+ padding-top: 4px;
+ padding-bottom: 4px;
+ color: #ffffff;
+ margin: 0px 0px 0px 0px;
+ background-color: #ff7f00;
+ border-top: 1px solid #ff7f00;
+ }
+#index LI:hover {
+ background-color: #F99B1C;
+}
+#index LI.heading {
+ background-color: #ff7f00;
+ color: #000000;
+ border-top:1px solid #FFE5CC;
+ padding-top: 7px;
+ font-weight: bold;
+}
+#index LI.title {
+ border-bottom: 2px solid #FFE5CC;
+ background-color: #ff7f00;
+ color: #FBF4E9;
+ font-weight: bolder;
+ font-size:10px;
+ line-height:18px;
+ padding-bottom: 40px;
+ }
+#index A {
+ text-decoration: none;
+ color: #FBF4E9;
+ font-weight: bold;
+}
+#ds-layout .imgcontainer {
+ position:relative;
+ }
+#ds-layout .caption {
+ position:relative;
+ bottom:1;
+ left:0;
+ text-align:center;
+ background:#ffe7cb;
+ width:100%;
+ opacity:.75;
+ filter:alpha(opacity=85);
+ color:#000;
+ font-style: italic;
+ font-size: 9px;
+ line-height:11px;
+ }
+</style>
+<script type="text/javascript">
+function addLoadEvent(func) {
+ var oldonload = window.onload;
+ if (typeof window.onload != 'function') {
+ window.onload = func;
+ } else {
+ window.onload = function() {
+ oldonload();
+ func();
+ }
+ }
+}
+
+function insertAfter(newElement,targetElement) {
+ var parent = targetElement.parentNode;
+ if (parent.lastChild == targetElement) {
+ parent.appendChild(newElement);
+ } else {
+ parent.insertBefore(newElement,targetElement.nextSibling);
+ }
+}
+
+function captionizeImages() {
+ if (!document.getElementsByTagName) return false;
+ if (!document.createElement) return false;
+ var images = document.getElementsByTagName("img");
+ if (images.length < 1) return false;
+ for (var i=0; i<images.length; i++) {
+ if (images[i].className != "non") {
+ var title = images[i].getAttribute("title");
+ var width = images[i].width;
+ var divCaption = document.createElement("div");
+ divCaption.className="caption";
+ divCaption.style.width=width+'px';
+ if (title) divCaption.style.padding='2px 0px 3px 0px';
+ divCaption.style.display='block';
+ var divCaption_text = document.createTextNode(title);
+ divCaption.appendChild(divCaption_text);
+ var divContainer = document.createElement("div");
+ divContainer.className="imgcontainer";
+ if (title) divContainer.style.padding='0px 0px 10px 0px';
+ images[i].parentNode.insertBefore(divContainer,images[i]);
+ divContainer.appendChild(images[i]);
+ insertAfter(divCaption,images[i]);
+ }
+ }
+}
+//addLoadEvent(captionizeImages);
+
+function next () {
+var onode, otarget;
+onode=document.getElementById("WhatIsSugar");
+if (onode.id=="Credits") die;
+//alert (onode.id);
+onode=onode.nextSibling;
+if (onode.id=="heading") onode=onode.nextSibling;
+while (onode) {
+ //onode=onode.nextSibling;
+ if (onode.nodeType==1) {
+ //alert (onode.id);
+ otarget=onode;
+ break;
+ }
+ onode=onode.nextSibling;
+}
+if (otarget) {
+ //you actually have found one, and do something here
+ //alert(otarget.id + "\n" + otarget.tagName); //just to verify
+ top.location = "/ActivitiesGuideSugar/" + otarget.id;
+} else {
+ //you don't find one
+//alert("nada" + otarget.id);
+}
+}
+
+function previous () {
+var onode, otarget;
+onode=document.getElementById("WhatIsSugar");
+if (onode.id=="Introduction") die;
+//alert (onode.id);
+onode=onode.previousSibling;
+if (onode.id=="heading") onode=onode.previousSibling;
+if (onode.id=="title") die;
+while (onode) {
+ //onode=onode.previousSibling;
+ if (onode.nodeType==1) {
+ //alert (onode.id);
+ otarget=onode;
+ break;
+ }
+ onode=onode.previousSibling;
+}
+if (otarget) {
+ //you actually have found one, and do something here
+ //alert(otarget.id + "\n" + otarget.tagName); //just to verify
+ top.location = otarget.id;
+} else {
+ //you don't find one
+//alert("nada" + otarget.id);
+}
+}
+
+</script>
+ </head>
+ <body background="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/background.gif" style="margin:0;color:#000000;">
+<div id="home" style="position:absolute;left:0px;top:10px;">
+<a href="/"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/top_read_back.gif" border="0"></a>
+</div>
+<div id="index" style="position:absolute;left:0px;top:150px;">
+<ul>
+<li class="title">MAKING SUGAR ACTIVITIES</li><li id="Introduction"><a href="/ActivitiesGuideSugar/Introduction">INTRODUCTION</a></li><li id="WhatIsSugar"><a href="/ActivitiesGuideSugar/WhatIsSugar">WHAT IS SUGAR?</a></li><li id="WhatisanActivity"><a href="/ActivitiesGuideSugar/WhatisanActivity">WHAT IS A SUGAR ACTIVITY?</a></li><li id="NeedtoKnowWriteSugarActivity"><a href="/ActivitiesGuideSugar/NeedtoKnowWriteSugarActivity">WHAT DO I NEED TO KNOW TO WRITE A SUGAR ACTIVITY?</a></li><li id="SetUpDevEnvironment"><a href="/ActivitiesGuideSugar/SetUpDevEnvironment">SETTING UP A DEVELOPMENT ENVIRONMENT</a></li><li id="CreateFirstActivity"><a href="/ActivitiesGuideSugar/CreateFirstActivity">CREATING YOUR FIRST ACTIVITY</a></li><li id="StandalonePythonReadEtexts"><a href="/ActivitiesGuideSugar/StandalonePythonReadEtexts">MAKING A STANDALONE PYTHON PROGRAM</a></li><li id="InheritFromActivity"><a href="/ActivitiesGuideSugar/InheritFromActivity">INHERIT FROM SUGAR.ACTIVITY.ACTIVITY</a></li><li id="PackageTheActivity"><a href="/ActivitiesGuideSugar/PackageTheActivity">PACKAGE THE ACTIVITY</a></li><li id="AddRefinements"><a href="/ActivitiesGuideSugar/AddRefinements">ADD REFINEMENTS</a></li><li id="UsingVersionControl"><a href="/ActivitiesGuideSugar/UsingVersionControl">ADD YOUR ACTIVITY CODE TO VERSION CONTROL</a></li><li id="Credits"><a href="/ActivitiesGuideSugar/Credits">CREDITS</a></li></ul>
+</div>
+<div id="pdf" style="position:absolute;left:13px;top:190px;">
+<a href="/ActivitiesGuideSugar/FM_06Jan10.pdf"><img class ="non" src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/makepdf.gif" border=0></a>
+<!-- <a href="/ActivitiesGuideSugar/FM_ActivitiesGuideSugar_06Jan10.pdf"><img class ="non" src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/makepdf.gif" border=0></a> -->
+<a href="/ActivitiesGuideSugar/print"><img class="non" src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/viewprint.gif" border=0></a>
+</div>
+ <div style="position:absolute;left:240px;top:11px;">
+ <table id="ds-layout" cellpadding="0" cellspacing="0" sumtop:5px;mary="" style="table-layout:fixed;width:670px;border: 5px solid #666666;padding-right: 0px;padding-left: 0px;padding-bottom: 0px;padding-top: 0px;margin-left : 10px;margin-top:10;background:#FFF7F0;">
+ <tr>
+ <td width=100%>
+<div class="arrow" style="position:relative;left:10px;top:5px;width:50px;float:left;"><a href="#" onClick="previous();"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/lefttext.png" height=20></a></div>
+<div class="arrow" style="position:relative;left:528px;width:50px;top:5px;float:left;"><a href="#" onClick="next();"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/righttext.png" height=20></a></div>
+ <div class="ds-contentcontainer">
+ <div style="margin-left:1.2em;float:right">
+ <br>
+ <div class="huh" style='decoration:none;color:black;border:1;position:absolute;top:60px;left:502px;'>
+ <a href='http://www.flossmanuals.net/bin/view/ActivitiesGuideSugar/WhatIsSugar' onClick="alert('You will now be forwarded to the FLOSS Manuals editing interface')"><b><font color=#ff7f00><small>Edit this page</small></font></b></a> :: <a href='http://www.flossmanuals.net/bin/view/ActivitiesGuideSugar/FMComments?skin=floss2'><b><font color=#ff7f00><small>Discussion</small></font></b></a>
+ </div>
+ <h1>What is Sugar?
+</h1>
+<p>Sugar is the user interface designed for the XO laptop. It can now be installed on most PCs, including older models that can't run the latest Windows software. You can also install it on a thumb drive (Sugar on a Stick) and boot your PC from that.
+</p>
+<p>When the XO laptop first came out some people questioned the need for a new user interface. Wouldn't it be better for children to learn something more like what they would use as adults? Why not give them Microsoft Windows instead?
+</p>
+<p>This would be a reasonable question if the goal was to train children to use computers and nothing else. It would be even more reasonable if we could be sure that the software they would use as adults looked and worked like the Microsoft Windows of today.&nbsp; These are of course not reasonable assumptions.
+</p>
+<p>The OLPC project is not just about teaching computer literacy. It is about teaching <em>everything</em>: reading, writing, arithmetic, history, science, arts and crafts, computer programming, music composition, and everything else. Not only do we expect the child to use the computer for his schoolwork, we expect him to take it home and use it for his own explorations into subjects that interest him.&nbsp;
+</p>
+<p>This is a great deal more than anyone has done with computers for education, so it is reasonable to rethink how children should work with computers. Sugar is the result of that rethinking.
+</p>
+<p>Sugar has the following unique features:
+</p>
+<h2>The Journal
+</h2>
+<p>The Journal is where all the student's work goes. Instead of files and folders there is a list of Journal entries. The list is sorted in descending order by the date and time it was last worked on. In a way it's like the "Most Recently Used" document menu in Windows, except instead of containing just the last few items it contains everything and is the normal way to save and resume work on something.
+</p>
+<p>The Journal makes it easy to organize your work.&nbsp; If you've ever downloaded a file using a web browser, then had to look for it afterwards because it went in some directory other than the one you expected, or if you ever had to help your parents when they were in a similar situation, you can understand the value of the Journal.
+ <br />
+</p>
+<p>The Journal has metadata for each item in it. Metadata is information about information. Every Journal entry has a title, a description, a list of keywords, and a screen shot of what it looked like the last time it was used. It has an activity id that links it to the Activity that created it, and it may have a MIME type as well (which is a way of identifying Journal entries so that items not created by an Activity may still be used by an Activity that supports that MIME type).
+</p>
+<p>In addition to these common metadata items a Journal entry may be given custom metadata by an Activity. For instance, the Read Activity uses custom metadata to save the page number you were reading when you quit the Activity. When you resume reading later the Activity will put you on that page again.
+</p>
+<p>In addition to work created by Activities, the Journal can contain Activities themselves. To install an Activity you can use the Browse Activity to visit the website <a href="http://activities.sugarlabs.org/">http://activities.sugarlabs.org</a> and download it. It will automatically be saved to the Journal and be ready for use. If you don't want the Activity anymore, simply delete it from the Journal and it's <em>completely gone</em>. No uninstall programs, no dialog boxes telling you that such and such a .DLL doesn't seem to be needed anymore and do you want to delete it? No odd bits and pieces left behind.
+</p>
+<h2>Collaboration
+</h2>
+<p>The second unique feature Sugar is Collaboration. Collaboration means that Activities can be used by more than one person at the same time. While not every Activity needs collaboration and not every Activity that could use it supports it, a really first rate Activity will provide some way to interact with other Sugar users on the network. For instance, all the e-book reading Activities provide a way of giving a copy of the book you're reading to a friend or to the whole class. The Write Activity lets several students work on the same document together. The Distance Activity lets two students see how far apart from each other they are.
+</p>
+<p>There are five views of the system you can switch to at the push of a button (Function Keys F1-5). They are:
+</p>
+<ul>
+ <li>
+ <p>The Neighborhood View
+ </p> </li>
+ <li>
+ <p>The Friends View
+ </p> </li>
+ <li>
+ <p>The Activity Ring
+ </p> </li>
+ <li>
+ <p>The Journal
+ </p> </li>
+ <li>
+ <p>The Current Activity (you can run more than one Activity at a time and switch between them but one of them will be considered the current Activity and the others will be in the background).
+ </p> </li>
+</ul>
+<p>Of these Views, the first two are used for Collaboration.
+</p>
+<p>The Neighborhood View shows icons for everyone on the network. Every icon looks like a stick figure made by putting an “O†above an “Xâ€. Each icon has a name, chosen by the student when he sets up his computer. Every icon is displayed in two colors, also chosen by the student. In addition to these “XO†icons there will be icons representing mesh networks and others representing WiFi hot spots. Finally there will be icons representing Activities that their owners wish to share.
+</p>
+<p>To understand how this works consider the Chat Activity. The usual way applications do chat is to have all the participants start up a chat client and visit a particular chat room at the same time. With Sugar it's different. One student starts the Chat Activity on his own computer and goes to the Neighborhood View to invite others on the network to participate. They will see a Chat icon in their own Neighborhood View and they can accept. The act of accepting starts up their own Chat Activity and connects them to the other participants.
+</p>
+<p>The Friends View is similar to the Neighborhood View, but only contains icons for people you have designated as Friends. Collaboration can be offered at three levels: with individual persons, with the whole Neighborhood, and with Friends. Note that the student alone decides who his Friends are. There is no need to ask to be someone's Friend.
+</p>
+<h2>Security
+</h2>
+<p>Protecting computers from malicious users is very important, and if the computers belong to students it is doubly important. It is also more difficult, because we can't expect young students to remember passwords and keep them secret. Since Sugar runs on top of Linux viruses aren't much of a problem, but malicious Activities definitely are. If an Activity was allowed unrestricted access to the Journal, for instance, it could wipe it out completely. Somebody could write an Activity that seems to be harmless and amusing, but perhaps after some random number of uses it could wipe out a student's work.
+</p>
+<p>The most common way to prevent a program from doing malicious things is to make it run in a sandbox. A sandbox is a way to limit what a program is allowed to do. With the usual kind of sandbox you either have an untrusted program that can't do much of anything or a trusted program that is not restricted at all. An application becomes trusted when a third party vouches for it by giving it a “signatureâ€. The signature is a mathematical operation done on the program that only remains valid if the program is not modified.
+</p>
+<p>Sugar has a more sophisticated sandbox for Activities than that. No Activity needs to be trusted or is trusted. Every Activity can only work with the Journal in a limited, indirect way. Each Activity has directories specific to it that it can write to, and all other directories and files are limited to read-only access. In this way no Activity can interfere with the workings of any other Activity. In spite of this, an Activity can be made to do what it needs to do.
+</p>
+<p>Sugar's security mechanisms are called Rainbow and BitFrost.
+</p>
+<h2>Summary
+</h2>
+<p>Sugar is an operating environment designed to support the education of children. It organizes a child's work without needing files and folders. It supports collaboration between students. Finally, it provides a robust security model that prevents malicious programs from harming a student's work.
+</p>
+<p>It would not be surprising to see these features someday adopted by other desktop environments.
+</p>
+<p />
+ </p></div>
+ </div>
+<div class="arrow" style="position:relative;left:10px;width:50px;float:left;bottom:5px;"><a href="#" onClick="previous();"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/lefttext.png" height=20></a></div>
+<div class="arrow" style="position:relative;left:528px;width:50px;float:left;bottom:5px;"><a href="#" onClick="next();"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/righttext.png" height=20></a></div>
+ <br>
+ <br>
+ <br>
+ <br>
+ </td>
+ </tr>
+ </table>
+ </div>
+<!-- Piwik -->
+<a href="http://piwik.org" title="Web analytics" onclick="window.open(this.href);return(false);">
+<script language="javascript" src="http://adam.engagetv.com/piwik/piwik.js" type="text/javascript"></script>
+<script type="text/javascript">
+<!--
+piwik_action_name = '';
+piwik_idsite = 1;
+piwik_url = 'http://adam.engagetv.com/piwik/piwik.php';
+piwik_log(piwik_action_name, piwik_idsite, piwik_url);
+//-->
+</script>
+<!-- /Piwik -->
+<script language="Javascript">
+document.getElementById("WhatIsSugar").style.backgroundColor="#F99B1C";
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/help/ActivityBook/ActivitiesGuideSugar/WhatisanActivity b/help/ActivityBook/ActivitiesGuideSugar/WhatisanActivity
new file mode 100644
index 0000000..4827c04
--- /dev/null
+++ b/help/ActivityBook/ActivitiesGuideSugar/WhatisanActivity
@@ -0,0 +1,256 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html>
+ <head>
+ <title>ActivitiesGuideSugar (en)</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <!--
+ <link rel="alternate" type="application/rss+xml" title="RSS Feed" href="WebRss.html" />
+ -->
+ <link rel="icon" href="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/fl2.ico" type="image/x-icon" /> <link rel="shortcut icon" href="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/fl2.ico" type="image/x-icon" />
+ <link rel=StyleSheet href="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/typography.css" type="text/css" media="screen">
+<style>
+#index {
+ color: #ff7f00;
+ font-family: trebuchet,sans-serif;
+ font-size: 10px;
+ line-height:11px;
+}
+#index UL {
+ width: 159px;
+ list-style-type: None;
+ padding-left: 0px;
+ border: 14px solid #ff7f00;
+ background-color: #ff7f00;
+ margin: 0px 0px 0px 0px;
+ }
+#index LI {
+ padding-left: 0px;
+ padding-right: 10px;
+ padding-top: 4px;
+ padding-bottom: 4px;
+ color: #ffffff;
+ margin: 0px 0px 0px 0px;
+ background-color: #ff7f00;
+ border-top: 1px solid #ff7f00;
+ }
+#index LI:hover {
+ background-color: #F99B1C;
+}
+#index LI.heading {
+ background-color: #ff7f00;
+ color: #000000;
+ border-top:1px solid #FFE5CC;
+ padding-top: 7px;
+ font-weight: bold;
+}
+#index LI.title {
+ border-bottom: 2px solid #FFE5CC;
+ background-color: #ff7f00;
+ color: #FBF4E9;
+ font-weight: bolder;
+ font-size:10px;
+ line-height:18px;
+ padding-bottom: 40px;
+ }
+#index A {
+ text-decoration: none;
+ color: #FBF4E9;
+ font-weight: bold;
+}
+#ds-layout .imgcontainer {
+ position:relative;
+ }
+#ds-layout .caption {
+ position:relative;
+ bottom:1;
+ left:0;
+ text-align:center;
+ background:#ffe7cb;
+ width:100%;
+ opacity:.75;
+ filter:alpha(opacity=85);
+ color:#000;
+ font-style: italic;
+ font-size: 9px;
+ line-height:11px;
+ }
+</style>
+<script type="text/javascript">
+function addLoadEvent(func) {
+ var oldonload = window.onload;
+ if (typeof window.onload != 'function') {
+ window.onload = func;
+ } else {
+ window.onload = function() {
+ oldonload();
+ func();
+ }
+ }
+}
+
+function insertAfter(newElement,targetElement) {
+ var parent = targetElement.parentNode;
+ if (parent.lastChild == targetElement) {
+ parent.appendChild(newElement);
+ } else {
+ parent.insertBefore(newElement,targetElement.nextSibling);
+ }
+}
+
+function captionizeImages() {
+ if (!document.getElementsByTagName) return false;
+ if (!document.createElement) return false;
+ var images = document.getElementsByTagName("img");
+ if (images.length < 1) return false;
+ for (var i=0; i<images.length; i++) {
+ if (images[i].className != "non") {
+ var title = images[i].getAttribute("title");
+ var width = images[i].width;
+ var divCaption = document.createElement("div");
+ divCaption.className="caption";
+ divCaption.style.width=width+'px';
+ if (title) divCaption.style.padding='2px 0px 3px 0px';
+ divCaption.style.display='block';
+ var divCaption_text = document.createTextNode(title);
+ divCaption.appendChild(divCaption_text);
+ var divContainer = document.createElement("div");
+ divContainer.className="imgcontainer";
+ if (title) divContainer.style.padding='0px 0px 10px 0px';
+ images[i].parentNode.insertBefore(divContainer,images[i]);
+ divContainer.appendChild(images[i]);
+ insertAfter(divCaption,images[i]);
+ }
+ }
+}
+//addLoadEvent(captionizeImages);
+
+function next () {
+var onode, otarget;
+onode=document.getElementById("WhatisanActivity");
+if (onode.id=="Credits") die;
+//alert (onode.id);
+onode=onode.nextSibling;
+if (onode.id=="heading") onode=onode.nextSibling;
+while (onode) {
+ //onode=onode.nextSibling;
+ if (onode.nodeType==1) {
+ //alert (onode.id);
+ otarget=onode;
+ break;
+ }
+ onode=onode.nextSibling;
+}
+if (otarget) {
+ //you actually have found one, and do something here
+ //alert(otarget.id + "\n" + otarget.tagName); //just to verify
+ top.location = "/ActivitiesGuideSugar/" + otarget.id;
+} else {
+ //you don't find one
+//alert("nada" + otarget.id);
+}
+}
+
+function previous () {
+var onode, otarget;
+onode=document.getElementById("WhatisanActivity");
+if (onode.id=="Introduction") die;
+//alert (onode.id);
+onode=onode.previousSibling;
+if (onode.id=="heading") onode=onode.previousSibling;
+if (onode.id=="title") die;
+while (onode) {
+ //onode=onode.previousSibling;
+ if (onode.nodeType==1) {
+ //alert (onode.id);
+ otarget=onode;
+ break;
+ }
+ onode=onode.previousSibling;
+}
+if (otarget) {
+ //you actually have found one, and do something here
+ //alert(otarget.id + "\n" + otarget.tagName); //just to verify
+ top.location = otarget.id;
+} else {
+ //you don't find one
+//alert("nada" + otarget.id);
+}
+}
+
+</script>
+ </head>
+ <body background="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/background.gif" style="margin:0;color:#000000;">
+<div id="home" style="position:absolute;left:0px;top:10px;">
+<a href="/"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/top_read_back.gif" border="0"></a>
+</div>
+<div id="index" style="position:absolute;left:0px;top:150px;">
+<ul>
+<li class="title">MAKING SUGAR ACTIVITIES</li><li id="Introduction"><a href="/ActivitiesGuideSugar/Introduction">INTRODUCTION</a></li><li id="WhatIsSugar"><a href="/ActivitiesGuideSugar/WhatIsSugar">WHAT IS SUGAR?</a></li><li id="WhatisanActivity"><a href="/ActivitiesGuideSugar/WhatisanActivity">WHAT IS A SUGAR ACTIVITY?</a></li><li id="NeedtoKnowWriteSugarActivity"><a href="/ActivitiesGuideSugar/NeedtoKnowWriteSugarActivity">WHAT DO I NEED TO KNOW TO WRITE A SUGAR ACTIVITY?</a></li><li id="SetUpDevEnvironment"><a href="/ActivitiesGuideSugar/SetUpDevEnvironment">SETTING UP A DEVELOPMENT ENVIRONMENT</a></li><li id="CreateFirstActivity"><a href="/ActivitiesGuideSugar/CreateFirstActivity">CREATING YOUR FIRST ACTIVITY</a></li><li id="StandalonePythonReadEtexts"><a href="/ActivitiesGuideSugar/StandalonePythonReadEtexts">MAKING A STANDALONE PYTHON PROGRAM</a></li><li id="InheritFromActivity"><a href="/ActivitiesGuideSugar/InheritFromActivity">INHERIT FROM SUGAR.ACTIVITY.ACTIVITY</a></li><li id="PackageTheActivity"><a href="/ActivitiesGuideSugar/PackageTheActivity">PACKAGE THE ACTIVITY</a></li><li id="AddRefinements"><a href="/ActivitiesGuideSugar/AddRefinements">ADD REFINEMENTS</a></li><li id="UsingVersionControl"><a href="/ActivitiesGuideSugar/UsingVersionControl">ADD YOUR ACTIVITY CODE TO VERSION CONTROL</a></li><li id="Credits"><a href="/ActivitiesGuideSugar/Credits">CREDITS</a></li></ul>
+</div>
+<div id="pdf" style="position:absolute;left:13px;top:190px;">
+<a href="/ActivitiesGuideSugar/FM_06Jan10.pdf"><img class ="non" src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/makepdf.gif" border=0></a>
+<!-- <a href="/ActivitiesGuideSugar/FM_ActivitiesGuideSugar_06Jan10.pdf"><img class ="non" src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/makepdf.gif" border=0></a> -->
+<a href="/ActivitiesGuideSugar/print"><img class="non" src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/viewprint.gif" border=0></a>
+</div>
+ <div style="position:absolute;left:240px;top:11px;">
+ <table id="ds-layout" cellpadding="0" cellspacing="0" sumtop:5px;mary="" style="table-layout:fixed;width:670px;border: 5px solid #666666;padding-right: 0px;padding-left: 0px;padding-bottom: 0px;padding-top: 0px;margin-left : 10px;margin-top:10;background:#FFF7F0;">
+ <tr>
+ <td width=100%>
+<div class="arrow" style="position:relative;left:10px;top:5px;width:50px;float:left;"><a href="#" onClick="previous();"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/lefttext.png" height=20></a></div>
+<div class="arrow" style="position:relative;left:528px;width:50px;top:5px;float:left;"><a href="#" onClick="next();"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/righttext.png" height=20></a></div>
+ <div class="ds-contentcontainer">
+ <div style="margin-left:1.2em;float:right">
+ <br>
+ <div class="huh" style='decoration:none;color:black;border:1;position:absolute;top:60px;left:502px;'>
+ <a href='http://www.flossmanuals.net/bin/view/ActivitiesGuideSugar/WhatisanActivity' onClick="alert('You will now be forwarded to the FLOSS Manuals editing interface')"><b><font color=#ff7f00><small>Edit this page</small></font></b></a> :: <a href='http://www.flossmanuals.net/bin/view/ActivitiesGuideSugar/FMComments?skin=floss2'><b><font color=#ff7f00><small>Discussion</small></font></b></a>
+ </div>
+ <h1>What is a Sugar Activity?
+</h1>
+<meta http-equiv="CONTENT-TYPE" content="text/html; charset=utf-8" />
+<title></title>
+<p class="western">A Sugar Activity is a self-contained Sugar application packaged in a .xo bundle.
+</p>
+<p class="western">An .xo bundle is an archive file in the Zip format, which has a MANIFEST file listing everything in the bundle, plus an activity.info file that has attributes describing the Activity as name=value pairs.&nbsp; These attributes include the Activity name, its version number, an identifier, and other things we will discuss when we write your first Activity. An .xo bundle will also contain an icon file (in SVG format), files containing translations of the label text the Activity uses into many languages, and the program code to run the Activity.
+</p>
+<p>A Sugar Activity will generally have some Python code that extends a Python class called Activity.&nbsp; It may also make use of code written in other languages if that code is written in a way that allows it to be used from Python (this is called having Python bindings).
+ <br />
+</p>
+<p class="western">There are only a few things that an Activity can depend on being included with every version of Sugar. These include modules like Evince (PDF and other document viewing) and Gecko (rendering web pages). Everything needed to run the Activity that is <em>not</em> supplied by Sugar must go in the bundle file.
+</p>
+<p class="western">You can install an Activity by copying or downloading it to the Journal. You uninstall it by removing it from the Journal. There is no Install Shield to deal with, no deciding where you want the files installed, no “.DLL Hellâ€.
+</p>
+<p class="western">An Activity generally creates and reads objects in the Journal. A first rate Activity will support some kind of collaboration.
+</p>
+<p>
+</p>
+<p />
+ </p></div>
+ </div>
+<div class="arrow" style="position:relative;left:10px;width:50px;float:left;bottom:5px;"><a href="#" onClick="previous();"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/lefttext.png" height=20></a></div>
+<div class="arrow" style="position:relative;left:528px;width:50px;float:left;bottom:5px;"><a href="#" onClick="next();"><img src="/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/righttext.png" height=20></a></div>
+ <br>
+ <br>
+ <br>
+ <br>
+ </td>
+ </tr>
+ </table>
+ </div>
+<!-- Piwik -->
+<a href="http://piwik.org" title="Web analytics" onclick="window.open(this.href);return(false);">
+<script language="javascript" src="http://adam.engagetv.com/piwik/piwik.js" type="text/javascript"></script>
+<script type="text/javascript">
+<!--
+piwik_action_name = '';
+piwik_idsite = 1;
+piwik_url = 'http://adam.engagetv.com/piwik/piwik.php';
+piwik_log(piwik_action_name, piwik_idsite, piwik_url);
+//-->
+</script>
+<!-- /Piwik -->
+<script language="Javascript">
+document.getElementById("WhatisanActivity").style.backgroundColor="#F99B1C";
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/help/ActivityBook/ActivitiesGuideSugar/print b/help/ActivityBook/ActivitiesGuideSugar/print
new file mode 100644
index 0000000..4e18df5
--- /dev/null
+++ b/help/ActivityBook/ActivitiesGuideSugar/print
@@ -0,0 +1,2129 @@
+<html>
+<head>
+<title> _all &lt; ActivitiesGuideSugar &lt; TWiki</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="robots" content="noindex" /> <link rel="alternate" type="application/rss+xml" title="RSS Feed" href="/bin/view/ActivitiesGuideSugar/WebRss" />
+ <base href="http://en.flossmanuals.net/bin/view/ActivitiesGuideSugar/_all" />
+<style type="text/css" media="screen">
+@import url(/floss/pub/TWiki/BasicSkin/gray.theme.css);
+@import url(/floss/pub/TWiki/BasicSkin/typography.css);
+</style>
+
+<style type="text/css" media="screen">
+.twikiToc {
+float : left;
+position : relative;
+ background: white; display:block;
+ border-style:solid;border-width: 0px;border-color:black;
+ font-size: 10px;
+ color:black;
+}
+A:link {color:black;}
+<!--/*--><![CDATA[<!--*/
+%DS_TOPICCSS%
+/*]]>*/-->
+</style>
+</head><body><h1>Introduction
+</h1>
+<p>The purpose of this book is to teach you what you need to know to write Activities for Sugar, the operating environment developed for the One Laptop Per Child project. This book does not assume that you know how to program a computer. It is my hope that this book will be helpful to those just starting out in programming.
+</p>
+<p>If you just want to learn how to write computer programs Sugar provides many Activities to help you do that: Etoys, Turtle Art, Scratch, and Pippy. None of these are really suitable for creating Activities so I won't cover them in this book, but they're a great way to learn about programming. If you decide after playing with these that you'd like to try writing an Activity after all you'll have a good foundation of knowledge to build on.
+</p>
+<p>If you have done some programming then you know how satisfying it can be to use a program that you made yourself, one that does exactly what you want it to do.&nbsp; Creating a Sugar Activity takes that enjoyment to the next level.&nbsp; A useful Sugar Activity can be translated by volunteers into every language, be downloaded hundreds of times a week and used every day by students all over the world.
+ <br />
+</p>
+<p>A book that teaches <em>everything</em> you need to know to write Activities would be really, really long and would duplicate material that is already available elsewhere. Because of this, I am going to write this as sort of a guided tour of Activity development. That means, for example, that I'll teach you what Python is and why it's important to learn it but I won't teach you the Python language itself. There is an excellent tutorial on the Internet that will do that, and I'll refer you to that tutorial.
+</p>
+<p>I started writing Activities shortly after I received my XO laptop. When I started I didn't know <em>any</em> of the material that will be in this book. I had a hard time knowing where to begin. What I did have going for me though was a little less than 30 years as a professional programmer. As a result of that I think like a programmer. A good programmer can take a complex task and divide it up into manageable pieces. He can figure out how things <em>must</em> work, and from that figure out how they <em>do</em> work. He knows how to ask for help and where. If there is no obvious place to begin he can begin <em>somewhere</em> and eventually get where he needs to go.
+</p>
+<p>Because I went through this process I think I can be a pretty good guide to writing Sugar Activities. I hope to also teach you how to think like a programmer does.
+</p><h1>What is Sugar?
+</h1>
+<p>Sugar is the user interface designed for the XO laptop. It can now be installed on most PCs, including older models that can't run the latest Windows software. You can also install it on a thumb drive (Sugar on a Stick) and boot your PC from that.
+</p>
+<p>When the XO laptop first came out some people questioned the need for a new user interface. Wouldn't it be better for children to learn something more like what they would use as adults? Why not give them Microsoft Windows instead?
+</p>
+<p>This would be a reasonable question if the goal was to train children to use computers and nothing else. It would be even more reasonable if we could be sure that the software they would use as adults looked and worked like the Microsoft Windows of today.&nbsp; These are of course not reasonable assumptions.
+</p>
+<p>The OLPC project is not just about teaching computer literacy. It is about teaching <em>everything</em>: reading, writing, arithmetic, history, science, arts and crafts, computer programming, music composition, and everything else. Not only do we expect the child to use the computer for his schoolwork, we expect him to take it home and use it for his own explorations into subjects that interest him.&nbsp;
+</p>
+<p>This is a great deal more than anyone has done with computers for education, so it is reasonable to rethink how children should work with computers. Sugar is the result of that rethinking.
+</p>
+<p>Sugar has the following unique features:
+</p>
+<h2>The Journal
+</h2>
+<p>The Journal is where all the student's work goes. Instead of files and folders there is a list of Journal entries. The list is sorted in descending order by the date and time it was last worked on. In a way it's like the "Most Recently Used" document menu in Windows, except instead of containing just the last few items it contains everything and is the normal way to save and resume work on something.
+</p>
+<p>The Journal makes it easy to organize your work.&nbsp; If you've ever downloaded a file using a web browser, then had to look for it afterwards because it went in some directory other than the one you expected, or if you ever had to help your parents when they were in a similar situation, you can understand the value of the Journal.
+ <br />
+</p>
+<p>The Journal has metadata for each item in it. Metadata is information about information. Every Journal entry has a title, a description, a list of keywords, and a screen shot of what it looked like the last time it was used. It has an activity id that links it to the Activity that created it, and it may have a MIME type as well (which is a way of identifying Journal entries so that items not created by an Activity may still be used by an Activity that supports that MIME type).
+</p>
+<p>In addition to these common metadata items a Journal entry may be given custom metadata by an Activity. For instance, the Read Activity uses custom metadata to save the page number you were reading when you quit the Activity. When you resume reading later the Activity will put you on that page again.
+</p>
+<p>In addition to work created by Activities, the Journal can contain Activities themselves. To install an Activity you can use the Browse Activity to visit the website <a href="http://activities.sugarlabs.org/">http://activities.sugarlabs.org</a> and download it. It will automatically be saved to the Journal and be ready for use. If you don't want the Activity anymore, simply delete it from the Journal and it's <em>completely gone</em>. No uninstall programs, no dialog boxes telling you that such and such a .DLL doesn't seem to be needed anymore and do you want to delete it? No odd bits and pieces left behind.
+</p>
+<h2>Collaboration
+</h2>
+<p>The second unique feature Sugar is Collaboration. Collaboration means that Activities can be used by more than one person at the same time. While not every Activity needs collaboration and not every Activity that could use it supports it, a really first rate Activity will provide some way to interact with other Sugar users on the network. For instance, all the e-book reading Activities provide a way of giving a copy of the book you're reading to a friend or to the whole class. The Write Activity lets several students work on the same document together. The Distance Activity lets two students see how far apart from each other they are.
+</p>
+<p>There are five views of the system you can switch to at the push of a button (Function Keys F1-5). They are:
+</p>
+<ul>
+ <li>
+ <p>The Neighborhood View
+ </p> </li>
+ <li>
+ <p>The Friends View
+ </p> </li>
+ <li>
+ <p>The Activity Ring
+ </p> </li>
+ <li>
+ <p>The Journal
+ </p> </li>
+ <li>
+ <p>The Current Activity (you can run more than one Activity at a time and switch between them but one of them will be considered the current Activity and the others will be in the background).
+ </p> </li>
+</ul>
+<p>Of these Views, the first two are used for Collaboration.
+</p>
+<p>The Neighborhood View shows icons for everyone on the network. Every icon looks like a stick figure made by putting an “O†above an “Xâ€. Each icon has a name, chosen by the student when he sets up his computer. Every icon is displayed in two colors, also chosen by the student. In addition to these “XO†icons there will be icons representing mesh networks and others representing WiFi hot spots. Finally there will be icons representing Activities that their owners wish to share.
+</p>
+<p>To understand how this works consider the Chat Activity. The usual way applications do chat is to have all the participants start up a chat client and visit a particular chat room at the same time. With Sugar it's different. One student starts the Chat Activity on his own computer and goes to the Neighborhood View to invite others on the network to participate. They will see a Chat icon in their own Neighborhood View and they can accept. The act of accepting starts up their own Chat Activity and connects them to the other participants.
+</p>
+<p>The Friends View is similar to the Neighborhood View, but only contains icons for people you have designated as Friends. Collaboration can be offered at three levels: with individual persons, with the whole Neighborhood, and with Friends. Note that the student alone decides who his Friends are. There is no need to ask to be someone's Friend.
+</p>
+<h2>Security
+</h2>
+<p>Protecting computers from malicious users is very important, and if the computers belong to students it is doubly important. It is also more difficult, because we can't expect young students to remember passwords and keep them secret. Since Sugar runs on top of Linux viruses aren't much of a problem, but malicious Activities definitely are. If an Activity was allowed unrestricted access to the Journal, for instance, it could wipe it out completely. Somebody could write an Activity that seems to be harmless and amusing, but perhaps after some random number of uses it could wipe out a student's work.
+</p>
+<p>The most common way to prevent a program from doing malicious things is to make it run in a sandbox. A sandbox is a way to limit what a program is allowed to do. With the usual kind of sandbox you either have an untrusted program that can't do much of anything or a trusted program that is not restricted at all. An application becomes trusted when a third party vouches for it by giving it a “signatureâ€. The signature is a mathematical operation done on the program that only remains valid if the program is not modified.
+</p>
+<p>Sugar has a more sophisticated sandbox for Activities than that. No Activity needs to be trusted or is trusted. Every Activity can only work with the Journal in a limited, indirect way. Each Activity has directories specific to it that it can write to, and all other directories and files are limited to read-only access. In this way no Activity can interfere with the workings of any other Activity. In spite of this, an Activity can be made to do what it needs to do.
+</p>
+<p>Sugar's security mechanisms are called Rainbow and BitFrost.
+</p>
+<h2>Summary
+</h2>
+<p>Sugar is an operating environment designed to support the education of children. It organizes a child's work without needing files and folders. It supports collaboration between students. Finally, it provides a robust security model that prevents malicious programs from harming a student's work.
+</p>
+<p>It would not be surprising to see these features someday adopted by other desktop environments.
+</p><h1>What is a Sugar Activity?
+</h1>
+<meta http-equiv="CONTENT-TYPE" content="text/html; charset=utf-8" />
+<title></title>
+<p class="western">A Sugar Activity is a self-contained Sugar application packaged in a .xo bundle.
+</p>
+<p class="western">An .xo bundle is an archive file in the Zip format, which has a MANIFEST file listing everything in the bundle, plus an activity.info file that has attributes describing the Activity as name=value pairs.&nbsp; These attributes include the Activity name, its version number, an identifier, and other things we will discuss when we write your first Activity. An .xo bundle will also contain an icon file (in SVG format), files containing translations of the label text the Activity uses into many languages, and the program code to run the Activity.
+</p>
+<p>A Sugar Activity will generally have some Python code that extends a Python class called Activity.&nbsp; It may also make use of code written in other languages if that code is written in a way that allows it to be used from Python (this is called having Python bindings).
+ <br />
+</p>
+<p class="western">There are only a few things that an Activity can depend on being included with every version of Sugar. These include modules like Evince (PDF and other document viewing) and Gecko (rendering web pages). Everything needed to run the Activity that is <em>not</em> supplied by Sugar must go in the bundle file.
+</p>
+<p class="western">You can install an Activity by copying or downloading it to the Journal. You uninstall it by removing it from the Journal. There is no Install Shield to deal with, no deciding where you want the files installed, no “.DLL Hellâ€.
+</p>
+<p class="western">An Activity generally creates and reads objects in the Journal. A first rate Activity will support some kind of collaboration.
+</p>
+<p>
+</p><h1>What Do I Need To Know To Write A Sugar Activity?&nbsp;
+</h1>
+<p class="western">If you are going to write Sugar Activities you should learn something about the topics described in this chapter. There is no need to become an expert in any of them, but you should bookmark their websites and skim through their tutorials. This will help you to understand the code samples we'll be looking at.
+</p>
+<h2 class="western">Python
+</h2>
+<p class="western">Python is the most used language for writing Activities. Every Activity has at least some Python in it.
+</p>
+<p class="western">There are compiled languages and interpreted languages. In a compiled language the code you write is translated into the language of the chip it will run on and it is this translation that is actually run by the OS. In an interpreted language there is a program called an interpreter that reads the code you write and does what the code tells it to do. (This is over simplified, but close enough to the truth for this chapter).
+</p>
+<p class="western">Python is an interpreted language. There are advantages to having a language that is compiled and there are advantages to having an interpreted language. The advantages Python has for developing Activities are:
+</p>
+<ul>
+ <li>
+ <p class="western">It is portable. In other words, you can make your program run on any chip and any OS without making a version specific to each one. Compiled programs only run on the OS and chip they are compiled for.
+ </p> </li>
+ <li>
+ <p class="western">Since the source code is the thing being run, you can't give someone a Python program without giving them the source code. You can learn a lot about Activity programming by studying other people's code, and there is plenty of it to study.
+ </p> </li>
+ <li>
+ <p class="western">It is an easy language for new programmers to learn, but has language features that experienced programmers demand.
+ </p> </li>
+ <li>
+ <p class="western">It is widely used. One of the best known Python users is Google. They use it enough that they have started a project named “Unladen Swallow†to make Python programs run faster.
+ </p> </li>
+</ul>
+<p class="western">The big advantage of a compiled language is that it can run much faster than an interpreted language. In actual practice a Python program can perform as well as a compiled program. To understand why this is you need to understand how a Python program is made.
+</p>
+<p class="western">Python is known as a “glue†language. The idea is that you have components written in various languages (usually C and C++) and they have Python bindings. Python is used to “glue†these components together to create applications. In most applications the bulk of the application's function is done by these compiled components, and the application spends relatively little time running the Python code that glues the components together.
+</p>
+<p class="western">In addition to Activities using Python most of the Sugar environment itself is written in Python.
+</p>
+<p class="western">If you have programmed in other languages before there is a good tutorial for learning Python at the Python website: <a href="http://docs.python.org/tutorial/">http://docs.python.org/tutorial/</a>.&nbsp; If you're just starting out in programming you might check out <em>Invent Your Own Computer Games With Python</em>, which you can read for free at <a href="http://inventwithpython.com/" target="_top">http://inventwithpython.com/</a>.
+ <br />
+</p>
+<h2 class="western">PyGTK
+</h2>
+<p class="western">GTK+ is a set of components for creating user interfaces. These components include things like buttons, scroll bars, list boxes, and so on. It is used by GNOME desktop environment and the applications that run under it. Sugar Activities use a special GNOME theme that give GTK+ controls a unique look.
+</p>
+<p class="western">PyGTK is a set of Python bindings that let you use GTK+ components in Python programs. There is a tutorial showing how to use it at the PyGTK website: <a href="http://www.pygtk.org/tutorial.html">http://www.pygtk.org/tutorial.html</a>.
+</p>
+<h2 class="western">PyGame
+</h2>
+<p class="western">The alternative to using PyGTK for your Activity is PyGame. PyGame can create images called sprites and move them around on the screen. As you might expect, PyGame is mostly used for writing games. It is less commonly used in Activities than PyGTK.
+</p>
+<p class="western">The tutorial to learn about PyGame is at the PyGame website: <a href="http://www.pygame.org/wiki/tutorials">http://www.pygame.org/wiki/tutorials</a>. The website also has a bunch of pygame projects you can download and try out.
+</p><h1>Setting Up a Sugar Development Environment
+</h1>
+<p class="western">It is not currently practical to develop Activities for the XO on the XO. It's not so much that you can't do it, but that it's easier and more productive to do your development and testing on another machine running a more conventional OS. This gives you access to better tools and it also enables you to simulate collaboration between two computers running Sugar using only one computer.
+</p>
+<h2 class="western">Install Linux Or Use A Virtual Machine?
+</h2>
+<p class="western">Even though Sugar runs on Linux it is possible to do development in Windows running a complete instance of Sugar in a virtual machine. A virtual machine is a way to run one operating system on top of another one. The operating system being run is fooled into thinking it has the whole computer to itself. (Computer industry pundits will tell you that using virtual machines is the newest new thing out there. Old timers like me know that IBM was doing it on their mainframe computers back in the 1970's).
+</p>
+<p class="western">For awhile this was actually the recommended way to develop Activities. The version of Linux that Sugar used was different enough from regular Linux distributions that even Linux users were running Sugar in a virtual machine on top of Linux.
+</p>
+<p class="western">The situation has improved, and most current Linux distributions have a usable Sugar environment.
+</p>
+<p class="western">If you're used to Windows you might think that running Sugar in a VM from Windows instead of installing Linux might be the easier option. In practice it is not. Linux running in a VM is still Linux, so you're still going to have to learn some things about Linux to do Activity development. Also, running a second OS in a VM requires a really powerful machine with gigabytes of memory. On the other hand, I do my Sugar development using Linux on an IBM NetVista Pentium IV I bought used for a little over a hundred dollars, shipping included. It is more than adequate.
+</p>
+<p class="western">Installing Linux is not the test of manhood it once was. Anyone can do it. The GNOME desktop provided with Linux is very much like Windows so you'll feel right at home using it.
+</p>
+<p class="western">When you install Linux you have the option to do a dual boot, running Linux and Windows on the same computer (but not at the same time). This means you set aside a disk partition for use by Linux and when you start the computer a menu appears asking which OS you want to start up. The Linux install will even create the partition for you, and a couple of gigabytes is more than enough disk space. Sharing a computer with a Linux installation will not affect your Windows installation at all.
+ <br />
+</p>
+<p class="western">Sugar Labs has been working to get Sugar included with all Linux distributions. If you already have a favorite distribution, chances are the latest version of it includes Sugar. Fedora, openSuse, Debian, and Ubuntu all include Sugar. If you already use Linux, see if Sugar is included in your distribution. If not, Fedora is what is used by the XO computer so Fedora 10 or later might be your best bet. You can download the Fedora install CD or DVD here: <a href="https://fedoraproject.org/get-fedora">https://fedoraproject.org/get-fedora</a>.
+</p>
+<p class="western">It is worth pointing out that all of the other tools I'm recommending are included in every Linux distribution, and they can be installed with no more effort than checking a check box. The same tools often will run on Windows, but installing them there is more work than you would expect for Windows programs.
+</p>
+<p class="western">If you want to do development on a Macintosh emulation is still your only option. If you want to try the emulation option details will be found here: <a href="http://wiki.laptop.org/go/Developers/Setup">http://wiki.laptop.org/go/Developers/Setup.</a>
+</p>
+<h2 class="western">What About Using sugar-jhbuild?
+</h2>
+<p class="western">Sugar-jhbuild is a script that downloads the source code for the latest version of all the Sugar modules and compiles it in such a way that it doesn't interfere with the modules that make up your normal desktop. If you are developing Sugar itself, or if you are developing Activities that depend on the very latest Sugar features you'll need to run sugar-jhbuild.
+</p>
+<p class="western">Running this script can take hours and occasionally it will fail leaving you with an unusable Sugar environment.
+</p>
+<p class="western">Should you consider using it? The short answer is no. A longer answer is <em>probably not yet</em>.
+</p>
+<p class="western">If you want your Activities to reach the widest possible audience you <em>don't</em> want the latest Sugar. In fact, if you want a test environment that mimics what is on most XO computers right now you need to use Fedora 10. Because updating operating systems in the field can be a major undertaking for a school most XO's will be running Sugar .82 or older for quite some time.
+</p>
+<p class="western">Of course it is also important to have developers that want to push the boundaries of what Sugar can do. If after developing some Activities you decide you need to be one of them you can learn about running sugar-jhbuild here: <a href="http://wiki.sugarlabs.org/go/DevelopmentTeam/Jhbuild">http://wiki.sugarlabs.org/go/DevelopmentTeam/Jhbuild.</a>
+</p>
+<h2 class="western">Eric
+</h2>
+<p class="western">Developers today expect their languages to be supported by an Integrated Development Environment and Python is no exception. An IDE helps to organize your work and provides text editing and a built in set of programming and debugging tools.
+</p>
+<p class="western">There are two Python IDE's I'm aware of: Eric and Idle. Eric is the fancier of the two and I recommend it. Every Linux distribution should include it. It looks like it might work on Windows too. You can learn more about it at the Eric website: <a href="http://eric-ide.python-projects.org/">http://eric-ide.python-projects.org/</a>.
+</p>
+<h2 class="western">Inkscape
+</h2>
+<p class="western">Inkscape is a tool for creating images in SVG format. Sugar uses SVG for Activity icons and other kinds of artwork. The “XO†icon that represents each child in the Neighborhood view is an SVG file that can be modified.
+</p>
+<p class="western">Inkscape comes with every Linux distribution, and can be installed on Windows as well. You can learn more about it here: <a href="http://www.inkscape.org/">http://www.inkscape.org/</a>.
+</p>
+<h2 class="western">Git
+</h2>
+<p class="western">Git is a version control system. It stores versions of your program code in a way that makes them easy to get back. Whenever you make changes to your code you ask Git to store your code in its repository. If you need to look at an old version of that code later you can. Even better, if some problem shows up in your code you can compare your latest code to an old, working version and see exactly what lines you changed.
+</p>
+<p class="western">If there are two people working on the same program independently a version control system will merge their changes together automatically.
+</p>
+<p class="western">Suppose you're working on a major new version of your Activity when someone finds a really embarrassing bug in the version you just released. If you use Git you don't need to tell people to live with it until the next release, which could be months away. Instead you can create a branch of the previous version and work on it alongside the version you're enhancing. In effect Git treats the old version you're fixing and the version you're improving as two separate projects.
+</p>
+<p class="western">You can learn more about Git at the Git website: <a href="http://git-scm.com/">http://git-scm.com/</a>.
+</p>
+<p class="western">When you're ready for a Git repository for your project you can learn how to set that up here: <a href="http://git.sugarlabs.org/">http://git.sugarlabs.org/</a>.
+</p>
+<h2 class="western">The GIMP
+</h2>
+<p class="western">The GIMP is one of the most useful and badly named programs ever developed. You can think of it as a free version of Adobe Photoshop. If you need to work with image files (other than SVG's) you need this program.
+</p>
+<p class="western">You may never need this program to develop the Activity itself, but when it's time to distribute the Activity you'll use it to create screen shots of your Activity in action. Nothing sells an Activity to a potential user like good screen shots.
+</p>
+<h2 class="western">Sugar Emulation
+</h2>
+<p class="western">Most Linux distributions should have Sugar included. In Fedora you can run Sugar as an alternative desktop environment. When you log in to GDM Sugar appears as a desktop selection alongside GNOME, KDE, Window Maker, and any other window managers you have installed.
+</p>
+<p class="western">This is not the normal way to use Sugar for testing. The normal way uses a tool called Xephyr to run a Sugar environment in a window on your desktop. In effect, Xephyr runs an X session inside a window and Sugar runs in that. You can easily take screen shots of Sugar in action, stop and restart Sugar sessions without restarting the computer, and run multiple copies of Sugar to test collaboration.
+</p>
+<p class="western">I'll have more to say about this when it's time to test your first Activity.
+</p> &nbsp;
+<p>
+</p><h1>Creating your First Sugar Activity
+</h1>
+<h2 class="western">Make A Standalone Python Program First
+</h2>
+<p class="western">The best advice I could give a beginning Activity developer is to make a version of your Activity that can run on its own, outside of the Sugar environment. Testing and debugging a Python program that stands alone is faster, easier and less tedious than doing the same thing with a similar Activity. You'll understand why when you start testing your first Activity.
+</p>
+<p class="western">The more bugs you find before you turn your code into an Activity the better. In fact, it's a good idea to keep a standalone version of your program around even after you have the Activity version well underway. I used my standalone version of Read Etexts to develop the text to speech with highlighting feature. This saved me a <em>lot</em> of time, which was especially important because I was figuring things out as I went.
+</p>
+<p>Our first project will be a version of the Read Etexts Activity I wrote.
+ <br />
+</p>
+<h2 class="western">Inherit From The sugar.activity.Activity Class
+</h2>
+<p>Next we're going to take our standalone Python program and make an Activity out of it.&nbsp; To do this we need to understand the concept of <em>inheritance</em>.&nbsp; In everyday speech inheritance means getting something from your parents that you didn't work for.&nbsp; A king will take his son to a castle window and say, "Someday, lad, this will all be yours!"&nbsp; That's inheritance.
+</p> In the world of computers programs can have parents and inherit things from them.&nbsp; Instead of inheriting property, they inherit code. There is a piece of Python code called sugar.activity.Activity that's the best parent an Activity could hope to have, and we're going to convince it to adopt our program.&nbsp; This doesn't mean that our program will never have to work again,&nbsp; but it won't have to work as much.
+<br />
+<h2>Package The Activity
+</h2>
+<p>Now we have to package up our code to make it something that can be run under Sugar and distributed as an .xo file.&nbsp; This involves setting up a MANIFEST, activity.info, setup.py, and creating a suitable icon with Inkscape.
+ <br />
+</p>
+<h2 class="western">Add Refinements
+</h2>
+<p class="western">Every Activity will have the basic Activity toolbar. For most Activities this will not be enough, so we'll need to create some custom toolbars as well. Then we need to hook them up to the rest of the Activity code so that what happens to the toolbar triggers actions in the Activity and what happens outside the toolbar is reflected in the state of the toolbar.
+</p>
+<p class="western">In addition to toolbars we'll look at some other ways to spiff up your Activity.
+ <br />
+</p>
+<h2> Put The Project Code In Version Control
+ <br />
+</h2>
+<p>By this time we'll have enough code written that it's worth protecting and sharing with the world.&nbsp; To do that we need to create a Git repository and add our code to it.&nbsp; We'll also go over the basics of using Git.
+ <br />
+</p>
+<h2> Going International With Pootle
+</h2>
+<p>Now that our code is in Git we can request help from our first collaborator: the Pootle translation system.&nbsp; With a little setup work we can get volunteers to make translated versions of our Activity available.
+</p>
+<h2>Distributing The Activity
+</h2>
+<p>In this task we'll take our Activity and set it up on <a href="http://activities.sugarlabs.org">http://activities.sugarlabs.org</a>&nbsp; plus we'll package up the source code so it can be included in Linux distributions.
+ <br />
+</p>
+<h2> Add Collaboration
+</h2>
+<p>Next we'll add code to share e-books with Friends and the Neighborhood.
+ <br />
+</p>
+<h2>Add Text To Speech
+</h2>
+<p>Text to Speech with word highlighting is next.&nbsp; Our simple project will become a Kindle-killer!
+ <br />
+</p><h1> A Standalone Python Program For Reading Etexts
+</h1>
+<h2>The Program
+ <br />
+</h2>
+<p>Our example program is based on the first Activity I wrote, Read Etexts.&nbsp; This is a program for reading free e-books.
+ <br />
+</p>
+<p>The oldest and best source of free e-books is a website called Project Gutenberg <a href="http://www.gutenberg.org/wiki/Main_Page).">(<a href="http://www.gutenberg.org/wiki/Main_Page" target="_top">http://www.gutenberg.org/wiki/Main_Page</a>).</a>&nbsp; They create books in plain text format, in other words the kind of file you could make if you typed a book into Notepad and hit the Enter key at the end of each line.&nbsp; They have thousands of books that are out of copyright, including some of the best ever written.&nbsp; Before you read further go to that website and pick out a book that interests you.&nbsp; Check out the "Top 100" list to see the most popular books and authors.
+</p>
+<p>The program we're going to create will read books in plain text format only.&nbsp; Fire up <em>Eric</em>, create a new Project named <em>BookExamples</em>, and create a new file called <strong>ReadEtexts.py</strong>.&nbsp; Then use copy and paste to get the code below into that file and save it.
+</p>
+<pre>#! /usr/bin/env python
+import sys
+import os
+import zipfile
+import pygtk
+import gtk
+import getopt
+import pango
+
+page=0
+PAGE_SIZE = 45
+
+class ReadEtexts():
+
+ def keypress_cb(self, widget, event):
+ "Respond when the user presses one of the arrow keys"
+ keyname = gtk.gdk.keyval_name(event.keyval)
+ if keyname == 'plus':
+ self.font_increase()
+ return True
+ if keyname == 'minus':
+ self.font_decrease()
+ return True
+ if keyname == 'Page_Up' :
+ self.page_previous()
+ return True
+ if keyname == 'Page_Down':
+ self.page_next()
+ return True
+ if keyname == 'Up' or keyname == 'KP_Up' \
+ or keyname == 'KP_Left':
+ self.scroll_up()
+ return True
+ if keyname == 'Down' or keyname == 'KP_Down' \
+ or keyname == 'KP_Right':
+ self.scroll_down()
+ return True
+ return False
+
+ def page_previous(self):
+ global page
+ page=page-1
+ if page &lt; 0: page=0
+ self.show_page(page)
+ v_adjustment = self.scrolled_window.get_vadjustment()
+ v_adjustment.value = v_adjustment.upper - v_adjustment.page_size
+
+ def page_next(self):
+ global page
+ page=page+1
+ if page &gt;= len(self.page_index): page=0
+ self.show_page(page)
+ v_adjustment = self.scrolled_window.get_vadjustment()
+ v_adjustment.value = v_adjustment.lower
+
+ def font_decrease(self):
+ font_size = self.font_desc.get_size() / 1024
+ font_size = font_size - 1
+ if font_size &lt; 1:
+ font_size = 1
+ self.font_desc.set_size(font_size * 1024)
+ self.textview.modify_font(self.font_desc)
+
+ def font_increase(self):
+ font_size = self.font_desc.get_size() / 1024
+ font_size = font_size + 1
+ self.font_desc.set_size(font_size * 1024)
+ self.textview.modify_font(self.font_desc)
+
+ def scroll_down(self):
+ v_adjustment = self.scrolled_window.get_vadjustment()
+ if v_adjustment.value == v_adjustment.upper - \
+ v_adjustment.page_size:
+ self.page_next()
+ return
+ if v_adjustment.value &lt; v_adjustment.upper - v_adjustment.page_size:
+ new_value = v_adjustment.value + v_adjustment.step_increment
+ if new_value &gt; v_adjustment.upper - v_adjustment.page_size:
+ new_value = v_adjustment.upper - v_adjustment.page_size
+ v_adjustment.value = new_value
+
+ def scroll_up(self):
+ v_adjustment = self.scrolled_window.get_vadjustment()
+ if v_adjustment.value == v_adjustment.lower:
+ self.page_previous()
+ return
+ if v_adjustment.value &gt; v_adjustment.lower:
+ new_value = v_adjustment.value - \
+ v_adjustment.step_increment
+ if new_value &lt; v_adjustment.lower:
+ new_value = v_adjustment.lower
+ v_adjustment.value = new_value
+
+ def show_page(self, page_number):
+ global PAGE_SIZE, current_word
+ position = self.page_index[page_number]
+ self.etext_file.seek(position)
+ linecount = 0
+ label_text = '\n\n\n'
+ textbuffer = self.textview.get_buffer()
+ while linecount &lt; PAGE_SIZE:
+ line = self.etext_file.readline()
+ label_text = label_text + unicode(line, 'iso-8859-1')
+ linecount = linecount + 1
+ label_text = label_text + '\n\n\n'
+ textbuffer.set_text(label_text)
+ self.textview.set_buffer(textbuffer)
+
+ def save_extracted_file(self, zipfile, filename):
+ "Extract the file to a temp directory for viewing"
+ filebytes = zipfile.read(filename)
+ f = open("/tmp/" + filename, 'w')
+ try:
+ f.write(filebytes)
+ finally:
+ f.close
+
+ def read_file(self, filename):
+ "Read the Etext file"
+ global PAGE_SIZE
+
+ if zipfile.is_zipfile(filename):
+ self.zf = zipfile.ZipFile(filename, 'r')
+ self.book_files = self.zf.namelist()
+ self.save_extracted_file(self.zf, self.book_files[0])
+ currentFileName = "/tmp/" + self.book_files[0]
+ else:
+ currentFileName = filename
+
+ self.etext_file = open(currentFileName,"r")
+ self.page_index = [ 0 ]
+ linecount = 0
+ while self.etext_file:
+ line = self.etext_file.readline()
+ if not line:
+ break
+ linecount = linecount + 1
+ if linecount &gt;= PAGE_SIZE:
+ position = self.etext_file.tell()
+ self.page_index.append(position)
+ linecount = 0
+ if filename.endswith(".zip"):
+ os.remove(currentFileName)
+
+ def destroy_cb(self, widget, data=None):
+ gtk.main_quit()
+
+ def main(self, file_path):
+ self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ self.window.connect("destroy", self.destroy_cb)
+ self.window.set_title("Read Etexts")
+ self.window.set_size_request(640, 480)
+ self.window.set_border_width(0)
+ self.read_file(file_path)
+ self.scrolled_window = gtk.ScrolledWindow(hadjustment=None, \
+ vadjustment=None)
+ self.textview = gtk.TextView()
+ self.textview.set_editable(False)
+ self.textview.set_left_margin(50)
+ self.textview.set_cursor_visible(False)
+ self.textview.connect("key_press_event", self.keypress_cb)
+ buffer = self.textview.get_buffer()
+ self.font_desc = pango.FontDescription("sans 12")
+ font_size = self.font_desc.get_size()
+ self.textview.modify_font(self.font_desc)
+ self.show_page(0)
+ self.scrolled_window.add(self.textview)
+ self.window.add(self.scrolled_window)
+ self.textview.show()
+ self.scrolled_window.show()
+ v_adjustment = self.scrolled_window.get_vadjustment()
+ self.window.show()
+ gtk.main()
+
+if __name__ == "__main__":
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], "")
+ ReadEtexts().main(args[0])
+ except getopt.error, msg:
+ print msg
+ print "This program has no options"
+ sys.exit(2)
+</pre>
+<h2> Running The Program
+</h2>
+<p>To run the program you should first make it executeable.&nbsp; You only need to do this once:
+</p>
+<pre>chmod 755 ReadEtexts.py</pre>
+<p>For this example I downloaded the file for Pride and Prejudice.&nbsp; The program will work with either of the Plain text formats, which are either uncompressed text or a Zip file.&nbsp; The zip file is named 1342.zip, and we can read the book by running this from a terminal:
+</p>
+<pre>./ReadEtexts.py 1342.zip</pre>
+<p>This is what the program looks like in action:
+</p>
+<p><img alt="The standalone Read Etexts program in action." src="/floss/pub/ActivitiesGuideSugar/ReadEtexts_01_1.jpg" height="503" width="646" />
+</p>
+<p>You can use the <em>Page Up, Page Down, Up, Down, Left</em>, and <em>Right</em> keys to navigate through the book and the '+' and '-' keys to adjust the font size.
+</p>
+<h2>How The Program Works
+</h2>
+<p>This program reads through the text file containing the book and divides it into pages of 45 lines each.&nbsp; We need to do this because the gtk.TextView component we use for viewing the text would need a lot of memory to scroll through the whole book and that would hurt performance.&nbsp; A second reason is that we want to make reading the e-book as much as possible like reading a regular book, and regular books have pages.&nbsp; If a teacher assigns reading from a book she might say "read pages 35-50 for tommorow".&nbsp; Finally, we want this program to remember what page you stopped reading on and bring you back to that page again when you read the book next time.&nbsp; (The program we have so far doesn't do that yet).
+</p>
+<p>To page through the book we use <em>random access</em> to read the file.&nbsp; To understand what random access means to a file, consider a VHS tape and a DVD.&nbsp; To get to a certain scene in a VHS tape you need to go through all the scenes that came before it, in order.&nbsp; Even though you do it at high speed you still have to look at all of them to find the place you want to start watching.&nbsp; This is <em>sequential access</em>.&nbsp; On the other hand a DVD has chapter stops and possibly a chapter menu.&nbsp; Using a chapter menu you can look at any scene in the movie right away, and you can skip around as you like.&nbsp; This is random access, and the chapter menu is like an <em>index</em>.&nbsp; Of course you can access the material in a DVD sequentially too.
+</p>
+<p>We need random access to skip to whatever page we like, and we need an index so that we know where each page begins.&nbsp; We make the index by reading the entire file one line at a time.&nbsp; Every 45 lines we make a note of how many characters into the file we've gotten and store this information in a Python list.&nbsp; Then we go back to the beginning of the file and display the first page.&nbsp; When the program user goes to the next or previous page we figure out what the new page number will be and look in the list entry for that page.&nbsp; This tells us that page starts 4,200 characters into the file.&nbsp; We use seek() on the file to go to that character and then we read 45 lines starting at that point and load them into the TextView.
+</p>
+<p>When you run this program notice how fast it is.&nbsp; Python programs take longer to run a line of code than a compiled language would, but in this program it doesn't matter because the heavy lifting in the program is done by the TextView, which was created in a compiled language.&nbsp; The Python parts don't do that much so the program doesn't spend much time running them.
+</p>
+<p>Sugar uses Python a lot, not just for Activities but for the Sugar environment itself.&nbsp; You may read somewhere that using so much Python is "a disaster" for performance.&nbsp; Don't believe it.
+</p>
+<p>There are no slow programming languages, only slow programmers.
+ <br />
+</p><h1>Inherit From sugar.activity.Activity
+</h1>
+<h2>Object Oriented Python
+ <br />
+</h2>
+<p class="western">Python supports two styles of programming: <em>procedural</em> and <em>object oriented</em>. Procedural programming is when you have some input data, do some processing on it, and produce an output. If you want to calculate all the prime numbers under a hundred or convert a Word document into a plain text file you'll probably use the procedural style to do that.
+</p>
+<p class="western">Object oriented programs are built up from units called <em>objects</em>. An object is described as a collection of fields or attributes containing data along with methods for doing things with that data. In addition to doing work and storing data objects can send messages to one another.
+</p>
+<p class="western">Consider a word processing program. It doesn't have just one input, some process, and one output. It can receive input from the keyboard, from the mouse buttons, from the mouse traveling over something, from the clipboard, etc. It can send output to the screen, to a file, to a printer, to the clipboard, etc. A word processor can edit several documents at the same time too. Any program with a GUI is a natural fit for the object oriented style of programming.
+</p>
+<p class="western">Objects are described by <em>classes</em>. When you create an object you are creating an <em>instance</em> of a class.
+</p>
+<p class="western">There's one other thing that a class can do, which is to <em>inherit</em> methods and attributes from another class. When you define a class you can say it <em>extends</em> some class, and by doing that in effect your class has the functionality of the other class plus its own functionality. The extended class becomes its parent.
+ <br />
+</p>
+<p class="western">All Sugar Activities extend a Python class called <em>sugar.activity.Activity</em>. This class provides methods that all Activities need. In addition to that, there are methods that you can override in your own class that the parent class will call when it needs to. For the beginning Activity writer three methods are important:
+</p>
+<p class="western"><em>__init__()</em>
+</p>
+<p class="western">This is called when your Activity is started up. This is where you will set up the user interface for your Activity, including toolbars.
+</p>
+<p class="western"><em>read_file(self, file_path)</em>
+</p>
+<p class="western">This is called when you resume an Activity from a Journal entry. It is called after the <em>__init__()</em> method is called. The file_path parameter contains the name of a temporary file that is a copy of the file in the Journal entry. The file is deleted as soon as this method finishes, but because Sugar runs on Linux if you open the file for reading your program can continue to read it even after it is deleted and it the file will not actually go away until you close it.
+</p>
+<p class="western"><em>write_file(self, file_path)</em>
+</p>
+<p class="western">This is called when the Activity updates the Journal entry. Just like with <em>read_file()</em> your Activity does not work with the Journal directly. Instead it opens the file named in file_path for output and writes to it. That file in turn is copied to the Journal entry.
+</p>
+<p class="western">There are three things that can cause <em>write_file()</em> to be executed:
+</p>
+<ul>
+ <li>
+ <p class="western">Your Activity closes.
+ </p> </li>
+ <li>
+ <p class="western">Someone presses the <strong>Keep</strong> button in the Activity toolbar.
+ </p> </li>
+ <li>
+ <p class="western">Your Activity ceases to be the active Activity, or someone moves from the Activity View to some other View.
+ </p> </li>
+</ul>
+<p class="western">In addition to updating the file in the Journal entry the <em>read_file()</em> and <em>write_file()</em> methods are used to read and update the metadata in the Journal entry.
+</p>
+<p> When we convert our standalone Python program to an Activity we'll take out much of the code we wrote and replace it with code inherited from the sugar.activity.Activity&nbsp; class.
+</p>
+<h2>Extending The Activity Class
+</h2>
+<p>Here's a version of our program that extends Activity:
+</p>
+<pre>import sys
+import os
+import zipfile
+import pygtk
+import gtk
+import pango
+from sugar.activity import activity
+from sugar.graphics import style
+
+page=0
+PAGE_SIZE = 45
+
+class ReadEtextsActivity(activity.Activity):
+ def __init__(self, handle):
+ "The entry point to the Activity"
+ global page
+ activity.Activity.__init__(self, handle)
+
+ toolbox = activity.ActivityToolbox(self)
+ activity_toolbar = toolbox.get_activity_toolbar()
+ activity_toolbar.keep.props.visible = False
+ activity_toolbar.share.props.visible = False
+ self.set_toolbox(toolbox)
+
+ toolbox.show()
+ self.scrolled_window = gtk.ScrolledWindow()
+ self.scrolled_window.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
+ self.scrolled_window.props.shadow_type = gtk.SHADOW_NONE
+
+ self.textview = gtk.TextView()
+ self.textview.set_editable(False)
+ self.textview.set_cursor_visible(False)
+ self.textview.set_left_margin(50)
+ self.textview.connect("key_press_event", self.keypress_cb)
+
+ self.scrolled_window.add(self.textview)
+ self.set_canvas(self.scrolled_window)
+ self.textview.show()
+ self.scrolled_window.show()
+ page = 0
+ self.textview.grab_focus()
+ self.font_desc = pango.FontDescription("sans %d" % style.zoom(10))
+ self.textview.modify_font(self.font_desc)
+
+ def keypress_cb(self, widget, event):
+ "Respond when the user presses one of the arrow keys"
+ keyname = gtk.gdk.keyval_name(event.keyval)
+ print keyname
+ if keyname == 'plus':
+ self.font_increase()
+ return True
+ if keyname == 'minus':
+ self.font_decrease()
+ return True
+ if keyname == 'Page_Up' :
+ self.page_previous()
+ return True
+ if keyname == 'Page_Down':
+ self.page_next()
+ return True
+ if keyname == 'Up' or keyname == 'KP_Up' \
+ or keyname == 'KP_Left':
+ self.scroll_up()
+ return True
+ if keyname == 'Down' or keyname == 'KP_Down' \
+ or keyname == 'KP_Right':
+ self.scroll_down()
+ return True
+ return False
+
+ def page_previous(self):
+ global page
+ page=page-1
+ if page &lt; 0: page=0
+ self.show_page(page)
+ v_adjustment = self.scrolled_window.get_vadjustment()
+ v_adjustment.value = v_adjustment.upper - v_adjustment.page_size
+
+ def page_next(self):
+ global page
+ page=page+1
+ if page &gt;= len(self.page_index): page=0
+ self.show_page(page)
+ v_adjustment = self.scrolled_window.get_vadjustment()
+ v_adjustment.value = v_adjustment.lower
+
+ def font_decrease(self):
+ font_size = self.font_desc.get_size() / 1024
+ font_size = font_size - 1
+ if font_size &lt; 1:
+ font_size = 1
+ self.font_desc.set_size(font_size * 1024)
+ self.textview.modify_font(self.font_desc)
+
+ def font_increase(self):
+ font_size = self.font_desc.get_size() / 1024
+ font_size = font_size + 1
+ self.font_desc.set_size(font_size * 1024)
+ self.textview.modify_font(self.font_desc)
+
+ def scroll_down(self):
+ v_adjustment = self.scrolled_window.get_vadjustment()
+ if v_adjustment.value == v_adjustment.upper - \
+ v_adjustment.page_size:
+ self.page_next()
+ return
+ if v_adjustment.value &lt; v_adjustment.upper - v_adjustment.page_size:
+ new_value = v_adjustment.value + v_adjustment.step_increment
+ if new_value &gt; v_adjustment.upper - v_adjustment.page_size:
+ new_value = v_adjustment.upper - v_adjustment.page_size
+ v_adjustment.value = new_value
+
+ def scroll_up(self):
+ v_adjustment = self.scrolled_window.get_vadjustment()
+ if v_adjustment.value == v_adjustment.lower:
+ self.page_previous()
+ return
+ if v_adjustment.value &gt; v_adjustment.lower:
+ new_value = v_adjustment.value - \
+ v_adjustment.step_increment
+ if new_value &lt; v_adjustment.lower:
+ new_value = v_adjustment.lower
+ v_adjustment.value = new_value
+
+ def show_page(self, page_number):
+ global PAGE_SIZE, current_word
+ position = self.page_index[page_number]
+ self.etext_file.seek(position)
+ linecount = 0
+ label_text = '\n\n\n'
+ textbuffer = self.textview.get_buffer()
+ while linecount &lt; PAGE_SIZE:
+ line = self.etext_file.readline()
+ label_text = label_text + unicode(line, 'iso-8859-1')
+ linecount = linecount + 1
+ label_text = label_text + '\n\n\n'
+ textbuffer.set_text(label_text)
+ self.textview.set_buffer(textbuffer)
+
+ def save_extracted_file(self, zipfile, filename):
+ "Extract the file to a temp directory for viewing"
+ filebytes = zipfile.read(filename)
+ outfn = self.make_new_filename(filename)
+ if (outfn == ''):
+ return False
+ f = open(os.path.join(self.get_activity_root(), 'instance', outfn), 'w')
+ try:
+ f.write(filebytes)
+ finally:
+ f.close
+
+ def read_file(self, filename):
+ "Read the Etext file"
+ global PAGE_SIZE
+
+ if zipfile.is_zipfile(filename):
+ self.zf = zipfile.ZipFile(filename, 'r')
+ self.book_files = self.zf.namelist()
+ self.save_extracted_file(self.zf, self.book_files[0])
+ currentFileName = os.path.join(self.get_activity_root(),\
+ 'instance', self.book_files[0])
+ else:
+ currentFileName = filename
+
+ self.etext_file = open(currentFileName,"r")
+ self.page_index = [ 0 ]
+ linecount = 0
+ while self.etext_file:
+ line = self.etext_file.readline()
+ if not line:
+ break
+ linecount = linecount + 1
+ if linecount &gt;= PAGE_SIZE:
+ position = self.etext_file.tell()
+ self.page_index.append(position)
+ linecount = 0
+ if filename.endswith(".zip"):
+ os.remove(currentFileName)
+ self.show_page(0)
+
+ def make_new_filename(self, filename):
+ partition_tuple = filename.rpartition('/')
+ return partition_tuple[2]
+
+
+</pre>
+<p>This program has some significant differences from the standalone version.&nbsp; First, note that this line:
+</p>
+<pre>#! /usr/bin/env python
+</pre>
+<p>has been removed.&nbsp; We are no longer running the program directly from the Python interpreter.&nbsp; Now Sugar is running it as an Activity.&nbsp; Notice that much (but not all) of what was in the main() method has been moved to the <em>__init__()</em> method and the <em>main()</em> method has been removed.
+</p>
+<p>Notice too that the <em>class</em> statement has changed:
+</p>
+<p>
+</p>
+<pre>class ReadEtextsActivity(activity.Activity)
+</pre>
+<p>This statement now tells us that class ReadEtextsActivity extends the class <strong>sugar.activity.Activity</strong>.&nbsp;&nbsp; As a result it inherits the code that is in that class.&nbsp; Therefore we no longer need a GTK main loop, or to define a window.&nbsp; The code in this class we extend will do that for us.
+</p>
+<p> While we gain much from this inheritance, we lose something too: a title bar for the main window.&nbsp; In a graphical operating environment a piece of software called a <em>window manager</em> is responsible for putting borders on windows, making them resizeable, reducing them to icons, maximizing them, etc.&nbsp; Sugar uses a window manager named Matchbox which makes each window fill the whole screen and puts no border, title bar, or any other window decorations on the windows.&nbsp;&nbsp; As a result of that we can't close our application by clicking on the "X" in the title bar as before.&nbsp; To make up for this we need to have a toolbar that contains a Close button.&nbsp; Thus every Activity has an Activity toolbar that contains some standard controls and buttons.&nbsp; If you look at the code you'll see I'm hiding a couple of controls which we have no use for yet.
+</p>
+<p>The <em>read_file()</em> method is no longer called from the main() method and doesn't seem to be called from anywhere in the program.&nbsp; Of course it does get called, by some of the Activity code we inherited from our new parent class.&nbsp; Similarly the <em>__init__() </em>and <em>write_file() </em>methods (if we had a <em>write_file()</em> method) get called by the parent Activity class.
+</p>
+<p>If you're especially observant you might have noticed another change.&nbsp; Our original standalone program created a temporary file when it needed to extract something from a Zip file.&nbsp; It put that file in a directory called /tmp.&nbsp; Our new Activity still creates the file but puts it in a different directory, one specific to the Activity.
+ <br />
+</p>
+<p>Making these changes to the code is not enough to make our program an Activity.&nbsp; We have to do some packaging work and get it set up to run from the Sugar emulator.&nbsp; We also need to learn how to run the Sugar emulator.&nbsp; That comes next!
+ <br />
+</p><h1>Package The Activity
+</h1>
+<h2>Add setup.py
+</h2>
+<p> You'll need to add a Python program called <strong>setup.py</strong> to the same directory that you Activity program is in.&nbsp; Every setup.py is exactly the same as every other setup.py, so you create a file called setup.py in Eric and paste the code below into it.
+ <br />
+</p>
+<pre>#!/usr/bin/env python
+
+# Copyright (C) 2006, Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+from sugar.activity import bundlebuilder
+
+bundlebuilder.start()</pre>
+<p>Be sure and copy the entire text above, including the comments.
+ <br />
+</p>
+<p>The setup.py program is used by sugar for a number of purposes.&nbsp; If you run setup.py from the command line you'll see the options that are used with it and what they do.
+</p>
+<pre>[jim@simmons bookexamples]$ ./setup.py
+/usr/lib/python2.6/site-packages/sugar/util.py:25: DeprecationWarning: the sha module is deprecated; use the hashlib module instead
+ import sha
+Available commands:
+
+build Build generated files
+dev Setup for development
+dist_xo Create a xo bundle package
+dist_source Create a tar source package
+fix_manifest Add missing files to the manifest
+genpot Generate the gettext pot file
+install Install the activity in the system
+
+(Type "./setup.py &lt;command&gt; --help" for help about a particular command's options.</pre>
+<p>We'll be running some of these commands later on.&nbsp; Don't be concerned about the <em>DeprecationWarning</em> message.&nbsp; That is just Python's way of telling us that it has a new way of doing something that is better but the old way we are using still works.&nbsp; The error is coming from code in Sugar itself and should be fixed in some future Sugar release.
+ <br />
+</p>
+<h2>Create activity.info
+</h2>
+<p> Next create a directory within the one your progam is in and name it <strong>activity</strong>.&nbsp; Create a file named <strong>activity.info</strong> within that directory and copy the lines below into it.
+ <br />
+</p>
+<pre>[Activity]
+name = Read ETexts II
+service_name = net.flossmanuals.ReadEtextsActivity
+icon = read-etexts
+exec = sugar-activity ReadEtextsActivity.ReadEtextsActivity
+show_launcher = no
+activity_version = 1
+mime_types = text/plain;application/zip
+license = GPLv2+</pre>
+<p>This file tell Sugar how to run your Activity.&nbsp; The properties needed in this file are:
+</p>
+<p>
+ <table style="width: 100%;" border="0" cellpadding="4" cellspacing="0"><tbody>
+ <tr>
+ <td style="width: 25%;">&nbsp;<strong>name</strong></td>
+ <td style="width: 75%;">The name of your Activity as it will appear to the user.
+ <br /></td>
+ </tr>
+ <tr>
+ <td>&nbsp;<strong>service_name</strong></td>
+ <td>A unique name that Sugar will use to refer to your Activity.&nbsp; Any Journal entry created by your Activity will have this name stored in its metadata, so that when someone resumes the Journal entry Sugar knows to use the program that created it to read it.
+ <br /></td>
+ </tr>
+ <tr>
+ <td><strong>icon </strong>
+ <br /></td>
+ <td>The name of the icon file you have created for the Activity.&nbsp; Since icons are always .svg files the icon file in the example is named read-etexts.svg.
+ <br /></td>
+ </tr>
+ <tr>
+ <td>&nbsp;<strong>exec</strong></td>
+ <td>This tells Sugar how to launch your Activity.&nbsp; What it says is to create an instance of the class <strong>ReadEtextsActivity </strong>which it will find in file <strong>ReadEtextsActivity.py</strong>.
+ <br /></td>
+ </tr>
+ <tr>
+ <td>&nbsp;<strong>show_launcher</strong></td>
+ <td>There are two ways to launch an Activity.&nbsp; The first is to click on the icon in the Activity view.&nbsp; The second is to resume an entry in the Journal. Activities that don't create Journal entries can only be resumed from the Journal, so there is no point in putting an icon in the Activity ring for them.&nbsp; Read Etexts is an Activity like that.
+ <br /></td>
+ </tr>
+ <tr>
+ <td>&nbsp;<strong>activity_version</strong></td>
+ <td>An integer that represents the version number of your program.&nbsp; The first version is 1, the next is 2, and so on.
+ <br /></td>
+ </tr>
+ <tr>
+ <td>&nbsp;<strong>mime_types</strong></td>
+ <td>Generally when you resume a Journal entry it launches the Activity that created it.&nbsp; In the case of an e-book it wasn't created by any Activity, so we need another way to tell the Journal which Activity it can use.&nbsp; A MIME type is the name of a common file format.&nbsp; Some examples are text/plain, text/html, application/zip and application/pdf.&nbsp; In this entry we're telling the Journal that our program can handle either plain text files or Zip archive files.
+ <br /></td>
+ </tr>
+ <tr>
+ <td>&nbsp;<strong>license</strong></td>
+ <td>Owning a computer program is not like buying a car.&nbsp; With a car, you're the owner and you can do what you like with it.&nbsp; You can sell it, rent it out, make it into a hot rod, whatever.&nbsp; With a computer program there is always a license that tells the person receiving the program what he is allowed to do with it.&nbsp; GPLv2+ is a popular standard license that can be used for Activities, and since this is <em>my</em> program that is what goes here.&nbsp; When you're ready to distribute one of <em>your</em> Activities I'll have more to say about licenses.
+ <br /></td>
+ </tr></tbody>
+ </table>
+</p>
+<h2>Create An Icon
+</h2>
+<p> Next we need to create an icon named <strong>read-etexts.svg</strong> and put it in the <strong>activity</strong> subdirectory.&nbsp; We're going to use Inkscape to create the icon.&nbsp; From the <strong>New</strong> menu in Inkscape select <strong>icon_48x48</strong>.&nbsp; This will create a drawing area that is a good size.
+</p>
+<p>You don't need to be an expert in Inkscape to create an icon.&nbsp; In fact the less fancy your icon is the better.&nbsp; When drawing your icon remember the following points:
+</p>
+<ul>
+ <li>Your icon needs to look good in sizes ranging from really, really small to large.</li>
+ <li>It needs to be recognizeable when its really, really small.</li>
+ <li>You only get to use two colors: a stroke color and a fill color.&nbsp; It doesn't matter which ones you choose because Sugar will need to override your choices anyway, so just use black strokes on a white background.</li>
+ <li>A fill color is only applied to an area that is contained within an unbroken stroke.&nbsp; If you draw a box and one of the corners doesn't quite connect the area inside that box will not be filled.&nbsp; Free hand drawing is only for the talented.&nbsp; Circles, boxes, and arcs are easy to draw with Inkscape so use them when you can.</li>
+ <li>Inkscape will also draw 3D boxes using two point perspective.&nbsp; Don't use them.&nbsp; Icons should be flat images.&nbsp; 3D just doesn't look good in an icon.</li>
+ <li>Coming up with good ideas for icons is tough.&nbsp; I once came up with a rather nice picture of a library card catalog drawer for <em>Get Internet Archive Books</em>.&nbsp; The problem is, no child under the age of forty has ever seen a card catalog and fewer still understand its purpose.</li>
+</ul>
+<p>When you're done making your icon you need to modify it so it can work with Sugar.&nbsp; Specifically, you need to make it show Sugar can use its own choice of stroke color and fill color.&nbsp; The SVG file format is based on XML, which means it is a text file with some special tags in it.&nbsp; This means that once we have finished editing it in Inkscape we can load the file into Eric and edit it as a text file.
+</p>
+<p>I'm not going to put the entire file in this chapter because most of it you'll just leave alone.&nbsp; The first part you need to modify is at the very beginning.
+</p>
+<p>Before:
+</p>
+<pre>&lt;?xml version="1.0" encoding="UTF-8" standalone="no"?&gt;
+&lt;!-- Created with Inkscape (http://www.inkscape.org/) --&gt;
+&lt;svg
+</pre>
+<p> After:
+</p>
+<pre>&lt;?xml version="1.0" ?&gt;&lt;!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd' [
+ &lt;!ENTITY stroke_color "#000000"&gt;
+ &lt;!ENTITY fill_color "#FFFFFF"&gt;
+]&gt;&lt;svg
+</pre>
+<p>Now in the body of the document you'll find references to <em>fill</em> and <em>stroke</em> as part of an attribute called <em>style</em>.&nbsp; Every line or shape you draw will have these, like this:
+</p>
+<pre> &lt;rect
+ style="fill:#ffffff;stroke:#000000;stroke-opacity:1"
+ id="rect904"
+ width="36.142857"
+ height="32.142857"
+ x="4.1428571"
+ y="7.1428571" /&gt;</pre>
+<p>You need to change each one to look like this:
+</p>
+<pre> &lt;rect
+ style="fill:&amp;fill_color;;stroke:&amp;stroke_color;;stroke-opacity:1"
+ id="rect904"
+ width="36.142857"
+ height="32.142857"
+ x="4.1428571"
+ y="7.1428571" /&gt;</pre>
+<p>Note that <em>&amp;stroke_color;</em> and <em>&amp;fill_color;</em> both end with semicolons (;), and semicolons are also used to separate the properties for style.&nbsp; Because of this it is an extremely common beginner's mistake to leave off the trailing semicolon because two semicolons in a row don't look right.&nbsp; Be assured that the two semicolons in a row are intentional and absolutely necessary!
+</p>
+<h2>Make a MANIFEST File
+</h2>
+<p> You should remember that setup.py has an option to update a manifest.&nbsp; Let's try it:
+</p>
+<pre>./setup.py fix_manifest
+/usr/lib/python2.6/site-packages/sugar/util.py:25: DeprecationWarning: the sha module is deprecated; use the hashlib module instead
+ import sha
+WARNING:root:Missing po/ dir, cannot build_locale
+WARNING:root:Activity directory lacks a MANIFEST file.
+</pre>
+<p>This actually will build a MANIFEST file containing everything in the directory and its subdirectories.&nbsp; The /po directory it is complaining about is used to translate Activities into different languages.&nbsp; We can ignore that for now.
+</p>
+<p> The MANIFEST file it creates will contain some extra stuff, so we need to get rid of the extra lines using Eric.&nbsp; The corrected MANIFEST should look like this:
+</p>
+<pre>setup.py
+ReadEtextsActivity.py
+activity/read-etexts.svg
+activity/activity.info</pre>
+<h2>Install The Activity
+</h2>
+<p> There's just one more thing to do before we can test our Activity under the Sugar emulator.&nbsp; We need to install it, which in this case means making a symbolic link between the directory we're using for our code in the ~/Activities/ directory.&nbsp; The symbol ~ refers to the "home" directory of the user we're running Sugar under, and a symbolic link is a way to make a file or directory appear to be located in more than one place without copying it.&nbsp; We make this symbolic link by running setup.py again:
+</p>
+<pre>./setup.py dev
+</pre>
+<h2>Running Our Activity
+</h2>
+<p>Now at last we can run our Activity under Sugar.&nbsp; To do that we need to lear how to run the Sugar emulator.
+</p>
+<p>Fedora doesn't make a menu option for Sugar Emulator, but it's easy to add one yourself.&nbsp; The command to run is simply
+</p>
+<pre>sugar-emulator</pre>
+<p>If your screen resolution is smaller than the default size sugar-emulator runs at it will run full screen.&nbsp; This is not convenient for testing, so you may want to specify your own size:
+</p>
+<pre>sugar-emulator -i 800x600</pre>
+<p>Note that this option only exists in Fedora 11 and later.
+</p>
+<p>When you run sugar-emulator a window opens up and the Sugar environment starts up and runs inside it.&nbsp; It looks like this:
+</p>
+<p><img alt="ReadEtexts_02.jpg" src="/floss/pub/ActivitiesGuideSugar/ReadEtexts_02.jpg" height="480" width="640" />
+</p>
+<p>There are a couple of other tricks we can do with sugar-emulator.&nbsp; For example we can simulate multiple Sugar users on a network by running a second instance of Sugar with this command line:
+</p>
+<pre>SUGAR_PROFILE=<em>some_name</em> sugar-emulator
+</pre>
+<p>We can also tell the emulator we want more detailed logging for debugging purposes.&nbsp; (We haven't used logging code in our Activity yet but we'll get there):
+</p>
+<pre>SUGAR_LOGGER_LEVEL=debug PRESENSESERVICE_DEBUG=1 sugar-emulator
+</pre>
+<p>To test our Activity we're going to need to have a book in the Journal, so use the Browse Activity to visit Project Gutenberg again and download the book of your choice.&nbsp; This time it's important to download the book in Zip format, because Browse cannot download a plain text file to the Journal.&nbsp; Instead, it opens the file for viewing as if it was a web page.&nbsp; If you try the same thing with the Zip file it will create an entry in the Journal.
+</p>
+<p>We can't just open the file with one click in the Journal because our program did not create the Journal entry and there are several Activities that support the MIME type of the Journal entry.&nbsp; We need to use the Start With menu option like this:
+</p>
+<p><img alt="ReadEtexts_03.jpg" src="/floss/pub/ActivitiesGuideSugar/ReadEtexts_03.jpg" height="480" width="640" />
+</p>
+<p>When we do open the Journal entry this is what we see:
+</p>
+<p><img alt="ReadEtexts_04.jpg" src="/floss/pub/ActivitiesGuideSugar/ReadEtexts_04.jpg" height="480" width="640" />
+</p>
+<p>Technically, this is the first <em>iteration</em> of our Activity.&nbsp; (Iteration is a vastly useful word meaning something you do more than once.&nbsp; In this book we're building our Activity a bit at a time so I can demonstrate Activity writing principles, but actually building a program in pieces, testing it, getting feedback, and building a bit more can be a highly productive way of creating software.&nbsp; Using the word iteration to describe each step in the process makes the process sound more formal than it really is).
+</p>
+<p>While this Activity might be good enough to show your own mother, we really should improve it a bit before we do that.&nbsp; That part comes next.
+ <br />
+</p><h1>Adding Refinements
+</h1>
+<h2>Toolbars
+</h2>
+<p>It is a truth universally acknowledged that a first rate Activity needs good Toolbars.&nbsp; In this chapter we'll learn how to make them.&nbsp; We're going to put the toolbar classes in a separate file from the rest, because there are two styles of toolbar (old and new) and we may want to support both in our Activity.&nbsp; If we have two different files containing toolbar classes our code can decide at runtime which one it wants to use.&nbsp; For now, this code supports the old style, which works with every version of Sugar.&nbsp; The new style is currently only supported by <em>Sugar on a Stick. </em>
+</p>
+<p>Add a file to your Eric project called <strong>toolbar.py</strong> and copy this code into it:
+</p>
+<pre>from gettext import gettext as _
+import re
+
+import pango
+import gobject
+import gtk
+
+from sugar.graphics.toolbutton import ToolButton
+from sugar.activity import activity
+
+class ReadToolbar(gtk.Toolbar):
+ __gtype_name__ = 'ReadToolbar'
+
+ def __init__(self):
+ gtk.Toolbar.__init__(self)
+
+ self.back = ToolButton('go-previous')
+ self.back.set_tooltip(_('Back'))
+ self.back.props.sensitive = False
+ self.insert(self.back, -1)
+ self.back.show()
+
+ self.forward = ToolButton('go-next')
+ self.forward.set_tooltip(_('Forward'))
+ self.forward.props.sensitive = False
+ self.insert(self.forward, -1)
+ self.forward.show()
+
+ num_page_item = gtk.ToolItem()
+
+ self.num_page_entry = gtk.Entry()
+ self.num_page_entry.set_text('0')
+ self.num_page_entry.set_alignment(1)
+ self.num_page_entry.connect('insert-text',
+ self.num_page_entry_insert_text_cb)
+
+ self.num_page_entry.set_width_chars(4)
+
+ num_page_item.add(self.num_page_entry)
+ self.num_page_entry.show()
+
+ self.insert(num_page_item, -1)
+ num_page_item.show()
+
+ total_page_item = gtk.ToolItem()
+
+ self.total_page_label = gtk.Label()
+
+ label_attributes = pango.AttrList()
+ label_attributes.insert(pango.AttrSize(14000, 0, -1))
+ label_attributes.insert(pango.AttrForeground(65535, 65535, 65535, 0, -1))
+ self.total_page_label.set_attributes(label_attributes)
+
+ self.total_page_label.set_text(' / 0')
+ total_page_item.add(self.total_page_label)
+ self.total_page_label.show()
+
+ self.insert(total_page_item, -1)
+ total_page_item.show()
+
+ def num_page_entry_insert_text_cb(self, entry, text, length, position):
+ if not re.match('[0-9]', text):
+ entry.emit_stop_by_name('insert-text')
+ return True
+ return False
+
+ def update_nav_buttons(self):
+ current_page = self.current_page
+ self.back.props.sensitive = current_page &gt; 0
+ self.forward.props.sensitive = \
+ current_page &lt; self.total_pages - 1
+
+ self.num_page_entry.props.text = str(current_page + 1)
+ self.total_page_label.props.label = \
+ ' / ' + str(self.total_pages)
+
+ def set_total_pages(self, pages):
+ self.total_pages = pages
+
+ def set_current_page(self, page):
+ self.current_page = page
+ self.update_nav_buttons()
+
+class ViewToolbar(gtk.Toolbar):
+ __gtype_name__ = 'ViewToolbar'
+
+ __gsignals__ = {
+ 'needs-update-size': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE,
+ ([])),
+ 'go-fullscreen': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE,
+ ([]))
+ }
+
+ def __init__(self):
+ gtk.Toolbar.__init__(self)
+ self.zoom_out = ToolButton('zoom-out')
+ self.zoom_out.set_tooltip(_('Zoom out'))
+ self.insert(self.zoom_out, -1)
+ self.zoom_out.show()
+
+ self.zoom_in = ToolButton('zoom-in')
+ self.zoom_in.set_tooltip(_('Zoom in'))
+ self.insert(self.zoom_in, -1)
+ self.zoom_in.show()
+
+ spacer = gtk.SeparatorToolItem()
+ spacer.props.draw = False
+ self.insert(spacer, -1)
+ spacer.show()
+
+ self.fullscreen = ToolButton('view-fullscreen')
+ self.fullscreen.set_tooltip(_('Fullscreen'))
+ self.fullscreen.connect('clicked', self.fullscreen_cb)
+ self.insert(self.fullscreen, -1)
+ self.fullscreen.show()
+
+ def fullscreen_cb(self, button):
+ self.emit('go-fullscreen')
+</pre>
+<p>Create another file in the project named <strong>ReadEtextsActivity2.py</strong> and copy this code into it:
+</p>
+<pre>import sys
+import os
+import zipfile
+import pygtk
+import gtk
+import pango
+from sugar.activity import activity
+from sugar.graphics import style
+from toolbar import ReadToolbar, ViewToolbar
+from gettext import gettext as _
+
+page=0
+PAGE_SIZE = 45
+TOOLBAR_READ = 2
+
+class ReadEtextsActivity(activity.Activity):
+ def __init__(self, handle):
+ "The entry point to the Activity"
+ global page
+ activity.Activity.__init__(self, handle)
+
+ toolbox = activity.ActivityToolbox(self)
+ activity_toolbar = toolbox.get_activity_toolbar()
+ activity_toolbar.keep.props.visible = False
+ activity_toolbar.share.props.visible = False
+
+ self.edit_toolbar = activity.EditToolbar()
+ self.edit_toolbar.undo.props.visible = False
+ self.edit_toolbar.redo.props.visible = False
+ self.edit_toolbar.separator.props.visible = False
+ self.edit_toolbar.copy.set_sensitive(False)
+ self.edit_toolbar.copy.connect('clicked', self.edit_toolbar_copy_cb)
+ self.edit_toolbar.paste.props.visible = False
+ toolbox.add_toolbar(_('Edit'), self.edit_toolbar)
+ self.edit_toolbar.show()
+
+ self.read_toolbar = ReadToolbar()
+ toolbox.add_toolbar(_('Read'), self.read_toolbar)
+ self.read_toolbar.back.connect('clicked', self.go_back_cb)
+ self.read_toolbar.forward.connect('clicked', self.go_forward_cb)
+ self.read_toolbar.num_page_entry.connect('activate', \
+ self.num_page_entry_activate_cb)
+ self.read_toolbar.show()
+
+ self.view_toolbar = ViewToolbar()
+ toolbox.add_toolbar(_('View'), self.view_toolbar)
+ self.view_toolbar.connect('go-fullscreen',
+ self.view_toolbar_go_fullscreen_cb)
+ self.view_toolbar.zoom_in.connect('clicked', self.zoom_in_cb)
+ self.view_toolbar.zoom_out.connect('clicked', self.zoom_out_cb)
+ self.view_toolbar.show()
+
+ self.set_toolbox(toolbox)
+ toolbox.show()
+ self.scrolled_window = gtk.ScrolledWindow()
+ self.scrolled_window.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
+ self.scrolled_window.props.shadow_type = gtk.SHADOW_NONE
+
+ self.textview = gtk.TextView()
+ self.textview.set_editable(False)
+ self.textview.set_cursor_visible(False)
+ self.textview.set_left_margin(50)
+ self.textview.connect("key_press_event", self.keypress_cb)
+
+ self.scrolled_window.add(self.textview)
+ self.set_canvas(self.scrolled_window)
+ self.textview.show()
+ self.scrolled_window.show()
+ page = 0
+ self.clipboard = gtk.Clipboard(display=gtk.gdk.display_get_default(), \
+ selection="CLIPBOARD")
+ self.textview.grab_focus()
+ self.font_desc = pango.FontDescription("sans %d" % style.zoom(10))
+ self.textview.modify_font(self.font_desc)
+
+ buffer = self.textview.get_buffer()
+ self.markset_id = buffer.connect("mark-set", self.mark_set_cb)
+ self.toolbox.set_current_toolbar(TOOLBAR_READ)
+
+ def keypress_cb(self, widget, event):
+ "Respond when the user presses one of the arrow keys"
+ keyname = gtk.gdk.keyval_name(event.keyval)
+ print keyname
+ if keyname == 'plus':
+ self.font_increase()
+ return True
+ if keyname == 'minus':
+ self.font_decrease()
+ return True
+ if keyname == 'Page_Up' :
+ self.page_previous()
+ return True
+ if keyname == 'Page_Down':
+ self.page_next()
+ return True
+ if keyname == 'Up' or keyname == 'KP_Up' \
+ or keyname == 'KP_Left':
+ self.scroll_up()
+ return True
+ if keyname == 'Down' or keyname == 'KP_Down' \
+ or keyname == 'KP_Right':
+ self.scroll_down()
+ return True
+ return False
+
+ def num_page_entry_activate_cb(self, entry):
+ global page
+ if entry.props.text:
+ new_page = int(entry.props.text) - 1
+ else:
+ new_page = 0
+
+ if new_page &gt;= self.read_toolbar.total_pages:
+ new_page = self.read_toolbar.total_pages - 1
+ elif new_page &lt; 0:
+ new_page = 0
+
+ self.read_toolbar.current_page = new_page
+ self.read_toolbar.set_current_page(new_page)
+ self.show_page(new_page)
+ entry.props.text = str(new_page + 1)
+ self.read_toolbar.update_nav_buttons()
+ page = new_page
+
+ def go_back_cb(self, button):
+ self.page_previous()
+
+ def go_forward_cb(self, button):
+ self.page_next()
+
+ def page_previous(self):
+ global page
+ page=page-1
+ if page &lt; 0: page=0
+ self.read_toolbar.set_current_page(page)
+ self.show_page(page)
+ v_adjustment = self.scrolled_window.get_vadjustment()
+ v_adjustment.value = v_adjustment.upper - v_adjustment.page_size
+
+ def page_next(self):
+ global page
+ page=page+1
+ if page &gt;= len(self.page_index): page=0
+ self.read_toolbar.set_current_page(page)
+ self.show_page(page)
+ v_adjustment = self.scrolled_window.get_vadjustment()
+ v_adjustment.value = v_adjustment.lower
+
+ def zoom_in_cb(self, button):
+ self.font_increase()
+
+ def zoom_out_cb(self, button):
+ self.font_decrease()
+
+ def font_decrease(self):
+ font_size = self.font_desc.get_size() / 1024
+ font_size = font_size - 1
+ if font_size &lt; 1:
+ font_size = 1
+ self.font_desc.set_size(font_size * 1024)
+ self.textview.modify_font(self.font_desc)
+
+ def font_increase(self):
+ font_size = self.font_desc.get_size() / 1024
+ font_size = font_size + 1
+ self.font_desc.set_size(font_size * 1024)
+ self.textview.modify_font(self.font_desc)
+
+ def mark_set_cb(self, textbuffer, iter, textmark):
+
+ if textbuffer.get_has_selection():
+ begin, end = textbuffer.get_selection_bounds()
+ self.edit_toolbar.copy.set_sensitive(True)
+ else:
+ self.edit_toolbar.copy.set_sensitive(False)
+
+ def edit_toolbar_copy_cb(self, button):
+ textbuffer = self.textview.get_buffer()
+ begin, end = textbuffer.get_selection_bounds()
+ copy_text = textbuffer.get_text(begin, end)
+ self.clipboard.set_text(copy_text)
+
+ def view_toolbar_go_fullscreen_cb(self, view_toolbar):
+ self.fullscreen()
+
+ def scroll_down(self):
+ v_adjustment = self.scrolled_window.get_vadjustment()
+ if v_adjustment.value == v_adjustment.upper - \
+ v_adjustment.page_size:
+ self.page_next()
+ return
+ if v_adjustment.value &lt; v_adjustment.upper - \
+ v_adjustment.page_size:
+ new_value = v_adjustment.value + v_adjustment.step_increment
+ if new_value &gt; v_adjustment.upper - v_adjustment.page_size:
+ new_value = v_adjustment.upper - v_adjustment.page_size
+ v_adjustment.value = new_value
+
+ def scroll_up(self):
+ v_adjustment = self.scrolled_window.get_vadjustment()
+ if v_adjustment.value == v_adjustment.lower:
+ self.page_previous()
+ return
+ if v_adjustment.value &gt; v_adjustment.lower:
+ new_value = v_adjustment.value - \
+ v_adjustment.step_increment
+ if new_value &lt; v_adjustment.lower:
+ new_value = v_adjustment.lower
+ v_adjustment.value = new_value
+
+ def show_page(self, page_number):
+ global PAGE_SIZE, current_word
+ position = self.page_index[page_number]
+ self.etext_file.seek(position)
+ linecount = 0
+ label_text = '\n\n\n'
+ textbuffer = self.textview.get_buffer()
+ while linecount &lt; PAGE_SIZE:
+ line = self.etext_file.readline()
+ label_text = label_text + unicode(line, 'iso-8859-1')
+ linecount = linecount + 1
+ label_text = label_text + '\n\n\n'
+ textbuffer.set_text(label_text)
+ self.textview.set_buffer(textbuffer)
+
+ def save_extracted_file(self, zipfile, filename):
+ "Extract the file to a temp directory for viewing"
+ filebytes = zipfile.read(filename)
+ outfn = self.make_new_filename(filename)
+ if (outfn == ''):
+ return False
+ f = open(os.path.join(self.get_activity_root(), 'tmp', outfn), 'w')
+ try:
+ f.write(filebytes)
+ finally:
+ f.close
+
+ def get_saved_page_number(self):
+ global page
+ title = self.metadata.get('title', '')
+ if title == '' or not title[len(title)- 1].isdigit():
+ page = 0
+ else:
+ i = len(title) - 1
+ newPage = ''
+ while (title[i].isdigit() and i &gt; 0):
+ newPage = title[i] + newPage
+ i = i - 1
+ if title[i] == 'P':
+ page = int(newPage) - 1
+ else:
+ # not a page number; maybe a volume number.
+ page = 0
+
+ def save_page_number(self):
+ global page
+ title = self.metadata.get('title', '')
+ if title == '' or not title[len(title)- 1].isdigit():
+ title = title + ' P' + str(page + 1)
+ else:
+ i = len(title) - 1
+ while (title[i].isdigit() and i &gt; 0):
+ i = i - 1
+ if title[i] == 'P':
+ title = title[0:i] + 'P' + str(page + 1)
+ else:
+ title = title + ' P' + str(page + 1)
+ self.metadata['title'] = title
+
+ def read_file(self, filename):
+ "Read the Etext file"
+ global PAGE_SIZE, page
+
+ if zipfile.is_zipfile(filename):
+ self.zf = zipfile.ZipFile(filename, 'r')
+ self.book_files = self.zf.namelist()
+ self.save_extracted_file(self.zf, self.book_files[0])
+ currentFileName = os.path.join(self.get_activity_root(), \
+ 'tmp', self.book_files[0])
+ else:
+ currentFileName = filename
+
+ self.etext_file = open(currentFileName,"r")
+ self.page_index = [ 0 ]
+ pagecount = 0
+ linecount = 0
+ while self.etext_file:
+ line = self.etext_file.readline()
+ if not line:
+ break
+ linecount = linecount + 1
+ if linecount &gt;= PAGE_SIZE:
+ position = self.etext_file.tell()
+ self.page_index.append(position)
+ linecount = 0
+ pagecount = pagecount + 1
+ if filename.endswith(".zip"):
+ os.remove(currentFileName)
+ self.get_saved_page_number()
+ self.show_page(page)
+ self.read_toolbar.set_total_pages(pagecount + 1)
+ self.read_toolbar.set_current_page(page)
+
+ def make_new_filename(self, filename):
+ partition_tuple = filename.rpartition('/')
+ return partition_tuple[2]
+
+ def write_file(self, filename):
+ "Save meta data for the file."
+ self.metadata['activity'] = self.get_bundle_id()
+ self.save_page_number()
+</pre>
+<p>Before you can run this example you'll need to change <strong>activity.info</strong> too:
+</p>
+<pre>[Activity]
+name = Read ETexts II
+service_name = net.flossmanuals.ReadEtextsActivity
+icon = read-etexts
+<strong>exec = sugar-activity ReadEtextsActivity2.ReadEtextsActivity</strong>
+show_launcher = no
+activity_version = 1
+mime_types = text/plain;application/zip
+license = GPLv2+
+
+</pre>
+<p>The line in <strong>bold</strong> is the only one that needs changing.&nbsp; When we run this new version this is what we'll see:
+</p>
+<p><img alt="ReadEtexts_05.jpg" src="/floss/pub/ActivitiesGuideSugar/ReadEtexts_05.jpg" height="480" width="640" />
+</p>
+<p>There are a few things worth pointing out in this code.&nbsp; First, have a look at this import:
+</p>
+<pre>from gettext import gettext as _
+</pre>
+<p> We'll be using the <em>gettext</em> module of Python to support translating our Activity into other languages. We'll be using it in statements like this one:
+</p>
+<pre> self.back.set_tooltip(_('Back'))</pre>
+<p>The underscore acts the same way as the gettext function because of the way we imported gettext.&nbsp; The effect of this statement will be to look in a special translation file for a word or phrase that matches the key "Back" and replace it with its translation.&nbsp; If there is no translation file for the language we want then it will simply use the word "Back".&nbsp; We'll explore setting up these translation files later, but for now using gettext for all of the words and phrases we will show to our Activity users lays some important groundwork.
+</p>
+<p>The second thing worth pointing out is that while our revised Activity has four toolbars we only had to create two of them.&nbsp; The other two, <strong>Activity</strong> and <strong>Edit</strong>, are part of the Sugar Python library.&nbsp; We can use those toolbars as is, hide the controls we don't need, or even extend them by adding new controls.&nbsp; In the example we're hiding the <strong>Keep</strong> and <strong>Share</strong> controls of the Activity toolbar and the <strong>Undo</strong>, <strong>Redo</strong>, and <strong>Paste</strong> buttons of the Edit toolbar.&nbsp; We currently do not support sharing books or modifying the text in books so these controls are not needed.&nbsp; Note too that the Activity toolbar is part of the <strong>ActivityToolbox</strong>.&nbsp; There is no way to give your Activity a toolbox that does not contain the Activity toolbar as its first entry.
+</p>
+<p>Another thing to notice is that the Activity class doesn't just provide us with a window.&nbsp; The window has a VBox to hold our toolbars and the body of our Activity.&nbsp; We install the toolbox using <em>set_toolbox()</em> and the body of the Activity using <em>set_canvas()</em>.
+</p>
+<p>The <strong>Read</strong> and <strong>View</strong> toolbars are regular PyGtk programming, but notice that there is a special button for Sugar toolbars that can have a tooltip attached to it, plus the <strong>View</strong> toolbar has code to hide the toolbox and <strong>ReadEtextsActivity2</strong> has code to unhide it.&nbsp; This is an easy function to add to your own Activities and many games and other kinds of Activities can benefit from the increased screen area you get when you hide the toolbox.
+</p>
+<h2>MetadataAnd Journal Entries
+ <br />
+</h2>
+<p>Every Journal entry represents a single file plus metadata, or information describing the file.&nbsp; There are standard metadata entries that all Journal entries have and you can also create your own custom metadata.
+</p>
+<p> Unlike ReadEtextsActivity, this version has a <em>write_file()</em> method.
+</p>
+<pre> def write_file(self, filename):
+ "Save meta data for the file."
+ self.metadata['activity'] = self.get_bundle_id()
+ self.save_page_number()
+</pre>
+<p> We didn't have a <em>write_file()</em> method before because we weren't going to update the file the book is in, and we still aren't.&nbsp; We will, however, be updating the metadata for the Journal entry.&nbsp; Specifically, we'll be doing two things:
+</p>
+<ul>
+ <li>Save the page number our Activity user stopped reading on so when he launches the Activity again we can return to that page.</li>
+ <li>Tell the Journal entry that it belongs to our Activity, so that in the future it will use our Activity's icon and can launch our Activity with one click.</li>
+</ul>
+<p>The way the <strong>Read</strong> Activity saves page number is to use a custom metadata property.&nbsp;
+</p>
+<pre> self.metadata['Read_current_page'] = \
+ str(self._document.get_page_cache().get_current_page())
+</pre>
+<p><strong>Read</strong> creates a custom metadata property named <em>Read_current_page </em>to store the current page number.&nbsp; You can create any number of custom metadata properties just this easily, so you may wonder why we aren't doing that with <strong>Read Etexts</strong>.&nbsp; Actually, the first version of <strong>Read Etexts</strong> did use a custom property, but in Sugar .82 or lower there was a bug in the Journal such that custom metadata did not survive after the computer was turned off.&nbsp; As a result my Activity would remember pages numbers while the computer was running, but would forget them as soon as it was shut down.&nbsp; XO laptops currently cannot upgrade to anything newer than .82, and when it is possible to upgrade it will be a big job for the schools.
+</p>
+<p>To get around this problem I created the following two methods:
+ <br />
+</p>
+<pre> def get_saved_page_number(self):
+ global page
+ title = self.metadata.get('title', '')
+ if title == '' or not title[len(title)- 1].isdigit():
+ page = 0
+ else:
+ i = len(title) - 1
+ newPage = ''
+ while (title[i].isdigit() and i &gt; 0):
+ newPage = title[i] + newPage
+ i = i - 1
+ if title[i] == 'P':
+ page = int(newPage) - 1
+ else:
+ # not a page number; maybe a volume number.
+ page = 0
+
+ def save_page_number(self):
+ global page
+ title = self.metadata.get('title', '')
+ if title == '' or not title[len(title)- 1].isdigit():
+ title = title + ' P' + str(page + 1)
+ else:
+ i = len(title) - 1
+ while (title[i].isdigit() and i &gt; 0):
+ i = i - 1
+ if title[i] == 'P':
+ title = title[0:i] + 'P' + str(page + 1)
+ else:
+ title = title + ' P' + str(page + 1)
+ self.metadata['title'] = title
+</pre>
+<p> <em>save_page_number()</em> looks at the current title metadata and either adds a page number to the end of it or updates the page number already there.&nbsp; Since title is standard metadata for all Journal entries the Journal bug does not affect it.
+</p>
+<p>These examples show how to read metadata too. &nbsp;
+ <br />
+</p>
+<pre> title = self.metadata.get('title', '')
+</pre>
+<p> This line of code says "Get the metadata property named <em>title</em> and put it in the variable named <em>title</em>, If there is no title property put an empty string in <em>title</em>.
+</p>
+<p>Generally&nbsp; you will save metadata in the <em>write_file()</em> method and read it in the <em>read_file()</em> method.
+</p>
+<p>In a normal Activity that writes out a file in write_file() this next line would be unnecessary:
+</p>
+<p>
+</p>
+<pre> self.metadata['activity'] = self.get_bundle_id()
+</pre>
+<p> Any Journal entry created by an Activity will automatically have this property set. In the case of <em>Pride and Prejudice</em>, our Activity did not create it.&nbsp; We are able to read it because our Activity supports its <em>MIME type</em>.&nbsp; Unfortunately, that MIME type, <em>application/zip</em>, is used by other Activities.&nbsp; I found it very frustrating to want to open a book in <strong>Read Etexts</strong> and accidentally have it opened in <strong>EToys</strong> instead.&nbsp; This line of code solves that problem.&nbsp; You only need to use <em>Start Using...</em> the first time you read a book.&nbsp; After that the book will use the <strong>Read Etexts</strong> icon and can be resumed with a single click.
+</p>
+<p>This does not at all affect the MIME type of the Journal entry, so if you wanted to deliberately open <em>Pride and Prejudice</em> with <strong>Etoys</strong> it is still possible.
+</p>
+<p>Before we leave the subject of Journal metadata let's look at all the standard metadata that every Activity has.&nbsp; Here is some code that creates a new Journal entry and updates a bunch of standard properties:
+</p>
+<pre> def create_journal_entry(self, tempfile):
+ journal_entry = datastore.create()
+ journal_title = self.selected_title
+ if self.selected_volume != '':
+ journal_title += ' ' + _('Volume') + ' ' + self.selected_volume
+ if self.selected_author != '':
+ journal_title = journal_title + ', by ' + self.selected_author
+ journal_entry.metadata['title'] = journal_title
+ journal_entry.metadata['title_set_by_user'] = '1'
+ journal_entry.metadata['keep'] = '0'
+ format = self._books_toolbar.format_combo.props.value
+ if format == '.djvu':
+ journal_entry.metadata['mime_type'] = 'image/vnd.djvu'
+ if format == '.pdf' or format == '_bw.pdf':
+ journal_entry.metadata['mime_type'] = 'application/pdf'
+ journal_entry.metadata['buddies'] = ''
+ journal_entry.metadata['preview'] = ''
+ journal_entry.metadata['icon-color'] = profile.get_color().to_string()
+ textbuffer = self.textview.get_buffer()
+ journal_entry.metadata['description'] = \
+ textbuffer.get_text(textbuffer.get_start_iter(), \
+ textbuffer.get_end_iter())
+ journal_entry.file_path = tempfile
+ datastore.write(journal_entry)
+ os.remove(tempfile)
+ self._alert(_('Success'), self.selected_title + _(' added to Journal.'))
+</pre>
+<p>This code is taken from an Activity I wrote that downloads books from a website and creates Journal entries for them.&nbsp; The Journal entries contain a friendly title and a full description of the book.
+</p>
+<p>Most Activities will only deal with one Journal entry by using the <em>read_file()</em> and <em>write_file()</em> methods but you are not limited to that.&nbsp; You can create new Journal entries using code like this example, and you can also list out and read any entries in the Journal. Here is some code to list out image files that have Journal entries:
+</p>
+<pre> def load_journal_table(self):
+ ds_objects, num_objects = datastore.find({\
+ 'mime_type':['image/jpeg', 'image/gif', \
+ 'image/tiff', 'image/png']})
+ for i in xrange (0, num_objects, 1):
+ title = ds_objects[i].metadata['title']
+ mime_type = ds_objects[i].metadata['mime_type']
+ if mime_type == 'image/jpeg' and not title.endswith('.jpg')\
+ and not title.endswith('.jpeg') \
+ and not title.endswith('.JPG') and not title.endswith('.JPEG') :
+ title = title + '.jpg'
+ if mime_type == 'image/png' and not title.endswith('.png')\
+ and not title.endswith('.PNG'):
+ title = title + '.png'
+ if mime_type == 'image/gif' and not title.endswith('.gif')\
+ and not title.endswith('.GIF'):
+ title = title + '.gif'
+ if mime_type == 'image/tiff' and not title.endswith('.tiff')\
+ and not title.endswith('.TIFF'):
+ title = title + '.tiff'
+ jobject_wrapper = JobjectWrapper()
+ jobject_wrapper.set_jobject(ds_objects[i])
+<em> ... add the jobject wrapper to a list here ...</em>
+
+ valid_endings = ('.jpg', '.jpeg', '.JPEG', '.JPG', '.gif',\
+ '.GIF', '.tiff', '.TIFF', '.png', '.PNG')
+ ds_mounts = datastore.mounts()
+ if len(ds_mounts) == 1 and ds_mounts[0]['id'] == 1:
+ # datastore.mounts() is stubbed out, we're running .84 or better
+ for dirname, dirnames, filenames in os.walk('/media'):
+ if '.olpc.store' in dirnames:
+ dirnames.remove('.olpc.store')
+ # don't visit .olpc.store directories
+ for filename in filenames:
+ if filename.endswith(valid_endings):
+ jobject_wrapper = JobjectWrapper()
+ jobject_wrapper.set_file_path(os.path.join(\
+ dirname, filename))
+<em> ... Add these jobject wrappers to the same list ...</em>
+</pre>
+<p>If this code seems complicated you should understand that most of this code is needed to give an identical experience under Sugar .82 and later versions.&nbsp; Really the only code you need to list Journal objects is this:
+ <br />
+</p>
+<pre> ds_objects, num_objects = datastore.find({\
+ 'mime_type':['image/jpeg', 'image/gif', \
+ 'image/tiff', 'image/png']})
+ for i in xrange (0, num_objects, 1):
+ title = ds_objects[i].metadata['title']
+ mime_type = ds_objects[i].metadata['mime_type']
+</pre>
+<p>This code will list out all the image files in an array and you can loop through it and find out what you need to know about those images.&nbsp; When you're ready to read one of those image files you can use code like this to get the path to the file:
+</p>
+<pre>path = ds_objects[i].get_file_path()
+</pre>
+<p> It is important to use the <em>get_file_path()</em> method immediately before you read the file.&nbsp; The reason is that the path does not exist before you call <em>get_file_path()</em> and will not exist long afterwards.&nbsp; Remember that Sugar does not let you deal with the Journal directly, in order to prevent malicious Activities from harming each other.&nbsp; Instead you are given paths of files to read and write to and Sugar deals with getting them to and from the Journal.
+</p>
+<p>So why use the complex code I wrote when something simpler will do the same thing?&nbsp; There are several reasons:
+</p>
+<ul>
+ <li>In Sugar .82 the simpler code will list all image files in your Journal, plus all image files in your SD card if your XO has one, plus any image files in any USB thumb drives you may have mounted.&nbsp; In later versions of Sugar only image files in the Journal proper are listed.&nbsp; I liked the Sugar .82 behavior and this code gives that behavior in all Sugar versions.</li>
+ <li>In one of the Sugar versions the title of the Journal entry is just the first part of the filename, without the .gif, .png, or .jpg suffix.&nbsp; I wanted the title to always be the complete filename with suffix so I use the MIME type to figure out what the suffix should be and if it's missing I add it.</li>
+</ul>
+<p>To make ds objects work the same way as regular files on thumb drives I create a wrapper class to contain both:
+</p>
+<pre>class JobjectWrapper():
+ def __init__(self):
+ self.__jobject = None
+ self.__file_path = None
+
+ def set_jobject(self, jobject):
+ self.__jobject = jobject
+
+ def set_file_path(self, file_path):
+ self.__file_path = file_path
+
+ def get_file_path(self):
+ if self.__jobject != None:
+ return self.__jobject.get_file_path()
+ else:
+ return self.__file_path
+</pre>
+<p> As you can see when I read a file on an SD card or a thumb drive I'm reading the actual file using its actual path, not a temporary one.&nbsp; Even so my Activity cannot <em>write</em> to an SD card or a thumb drive.&nbsp; It can only read from them.&nbsp; If you want to export data to a file on a thumb drive the best you can do is to create a Journal entry with the appropriate MIME type.&nbsp; The Activity user can then copy this entry to the thumb drive using the Journal.
+</p>
+<p>We've covered a lot of technical information in this chapter and there's more to come, but before we get to that we need to look at some other important topics:
+</p>
+<ul>
+ <li>Putting your Activity in version control.&nbsp; This will enable you to share your code with the world and get other people to help work on it.</li>
+ <li>Getting your Activity translated into other languages.</li>
+ <li>Distributing your finished Activity.&nbsp; (Or your not quite finished but still useful Activity).
+ <br /></li>
+</ul><h1>Putting Your Activity Code In Version Control
+</h1>
+<h2>What Is Version Control?
+</h2>
+<p> <em>"If I have seen further it is only by standing on the shoulders of giants."</em>
+</p>
+<p>Isaac Newton, in a letter to Robert Hooke.
+</p>
+<p>Writing an Activity is usually not something you do by yourself.&nbsp; You will usually have collaborators in one form or another.&nbsp; When I started writing <strong>Read Etexts</strong> I copied much of the code from the <strong>Read</strong> Activity.&nbsp; When I implemented text to speech I adapted a toolbar from the <strong>Speak</strong> Activity.&nbsp; When I finally got my copied file sharing code working the author of <strong>Image Viewer</strong> thought it was good enough to copy into that Activity.&nbsp; Another programmer saw the work I did for text to speech and thought he could do it better.&nbsp; He was right, and his improvements got merged into my own code.&nbsp; When I wrote <strong>Get Internet Archive Books</strong> someone else took the user interface I came up with and made a more powerful and versatile Activity called <strong>Get Books</strong>.&nbsp; Like Newton, everyone benefits from the work others have done before.
+ <br />
+</p>
+<p>Even if I wanted to write Activities without help I would still need collaborators to translate them into other languages.
+</p>
+<p>To make collaboration possible you need to have a place where everyone can post their code and share it.&nbsp; This is called a code repository.&nbsp; It isn't enough to just share the latest version of your code.&nbsp; What you really want to do is share <em>every</em> version of your code.&nbsp; Every time you make a significant change to your code you want to have the new version and the previous version available.&nbsp; Not only do you want to have every version of your code available, you want to be able to compare any two versions your code to see what changed between them.&nbsp; This is what version control software does.
+</p>
+<p>The three most popular version control tools are <em>CVS</em>, <em>Subversion</em>, and <em>Git</em>.&nbsp; Git is the newest and is the one used by Sugar Labs.&nbsp; While not every Activity has its code into the Sugar Labs Git repository (other free code repositories exist) there is no good reason not to do it and significant benefits if you do.&nbsp; If you want to get your Activity translated into other languages using a Sugar Labs Git repository is a must. &nbsp;
+ <br />
+</p>
+<h2>Git Along Little Dogies
+</h2>
+<p>Git is a <em>distributed</em> version control system.&nbsp; This means that not only are there copies of every version of your code in a central repository, the same copies exist on every user's computer.&nbsp; This means you can update your local repository while you are not connected to the Internet, then connect and share everything at one time.
+</p>
+<p> There are two ways you will interact with your Git repository: through Git commands and through the website at <a href="http://git.sugarlabs.org/.">http://git.sugarlabs.org/.</a>&nbsp;&nbsp; We'll look at this website first.
+</p>
+<p>Go to <a href="http://git.sugarlabs.org">http://git.sugarlabs.org/</a>&nbsp; and click on the <strong>Projects</strong> link in the upper right corner:
+</p>
+<p><img alt="git1.jpg" src="/floss/pub/ActivitiesGuideSugar/git1.jpg" height="194" width="473" />
+</p>
+<p>You will see a list of projects in the repository.&nbsp; They will be listed from newest to oldest.&nbsp; You'll also see a <strong>New Project</strong> link but you'll need to create an account to use that and we aren't ready to do that yet.
+ <br />
+</p>
+<p><img alt="git2.jpg" src="/floss/pub/ActivitiesGuideSugar/git2.jpg" height="453" width="535" />
+</p>
+<p>If you use the <strong>Search</strong> link in the upper right corner of the page you'll get a search form.&nbsp; Use it to search for "read etexts".&nbsp; Click on the link for that project when you find it.&nbsp; You should see something like this:
+ <br />
+</p>
+<p><img alt="git3.jpg" src="/floss/pub/ActivitiesGuideSugar/git3.jpg" height="571" width="571" />
+</p>
+<p>This page lists <em>some</em> of the activity for the project but I don't find it particularly useful.&nbsp; To get a much better look at your project start by clicking on the repository name on the right side of the page.&nbsp; In this case the repository is named <strong>mainline</strong>.
+</p>
+<p><img alt="git4.jpg" src="/floss/pub/ActivitiesGuideSugar/git4.jpg" height="236" width="399" />
+</p>
+<p>You'll see something like this at the top of the page:
+</p>
+<p><img alt="git5.jpg" src="/floss/pub/ActivitiesGuideSugar/git5.jpg" height="509" width="574" />
+</p>
+<p>This page has some useful information on it.&nbsp; First, have a look at the <strong>Public clone url</strong> and the <strong>HTTP clone url</strong>.&nbsp; You need to click on <strong>More info...</strong> to see either one.&nbsp; If you run either of these commands from the console you will get a copy of the git repository for the project copied to your computer.&nbsp; This copy will include every version of every piece of code in the project.&nbsp; You would need to modify it a bit before you could share your changes back to the main repository, but everything would be there.
+</p>
+<p>The list under <strong>Activities</strong> is not that useful, but if you click on the <strong>Source Tree</strong> link you'll see something really good:
+</p>
+<p><img alt="git6.jpg" src="/floss/pub/ActivitiesGuideSugar/git6.jpg" height="468" width="571" />
+</p>
+<p>Here is a list of every file in the project, the date it was last updated, and a comment on what was modified.&nbsp; Click on the link for <strong>ReadEtextsActivity.py</strong> and you'll see this:
+</p>
+<p><img alt="git7.jpg" src="/floss/pub/ActivitiesGuideSugar/git7.jpg" height="642" width="597" />
+</p>
+<p>This is the latest code in that file in pretty print format.&nbsp; Python keywords are shown in a different color, there are line numbers, etc.&nbsp; This is a good page for looking at code on the screen, but it doesn't print well and it's not much good for copying snippets of code into Eric windows either.&nbsp; For either of those things you'll want to click on <strong>raw blob data</strong> at the top of the listing:
+</p>
+<p><img alt="git8.jpg" src="/floss/pub/ActivitiesGuideSugar/git8.jpg" height="484" width="549" />
+</p>
+<p>We're not done yet.&nbsp; Use the <strong>Back</strong> button to get back to the pretty print listing and click on the <strong>Commits</strong> link.&nbsp; This will give us a list of everything that changed each time we committed code into Git:
+</p>
+<p><img alt="git9.jpg" src="/floss/pub/ActivitiesGuideSugar/git9.jpg" height="540" width="636" />
+</p>
+<p>You may have noticed the odd combination of letters and numbers after the words <strong>James Simmons committed</strong>.&nbsp; This is a kind of version number.&nbsp; The usual practice with version control systems is to give each version of code you check in a version number, usually a simple sequence number.&nbsp; Git is distributed, with many separate copies of the repository being modified independently and then merged.&nbsp; That makes using just a sequential number to identify versions unworkable.&nbsp; Instead, Git gives each version a really, really large random number.&nbsp; The number is expressed in base 16, which uses the symbols 0-9 and a-f.&nbsp; What you see in green is only a small part of the complete number.&nbsp; The number is a link, and if you click on it you'll see this:
+</p>
+<p><img alt="git10.jpg" src="/floss/pub/ActivitiesGuideSugar/git10.jpg" height="607" width="561" />
+</p>
+<p>At the top of the page we see the complete version number used for this commit.&nbsp; Below the gray box we see the full comment that was used to commit the changes.&nbsp; Below that is a listing of what files were changed.&nbsp;&nbsp; If we look further down the page we see this:
+</p>
+<p><img alt="git11_1.jpg" src="/floss/pub/ActivitiesGuideSugar/git11_1.jpg" height="530" width="581" />
+</p>
+<p>This is a <em>diff</em> report which shows the lines that have changed between this version and the previous version.&nbsp; For each change it shows a few lines before and after the change to give you a better idea of what the change does.&nbsp; Every change shows line numbers too.
+</p>
+<p>A report like this is a wonderful aid to programming.&nbsp; Sometimes when you're working on an enhancement to your program something that had been working mysteriously stops working.&nbsp; When that happens you will wonder just what you changed that could have caused the problem.&nbsp; A diff report can help you find the source of the problem.
+</p>
+<p>By now you must be convinced that you want your project code in Git.&nbsp; Before we can do that we need to create an account on this website.&nbsp; That is no more difficult than creating an account on any other website, but it will need an important piece of information from us that we don't have yet.&nbsp; Getting that information is our next task.
+</p>
+<h2>Setting Up SSH Keys
+</h2>
+<p>To send your code to the gitorious code repository you need an SSH public/private key pair.&nbsp; SSH is a way of sending data over the network in encrypted format.&nbsp; (In other words, it uses a secret code so nobody but the person getting the data can read it).&nbsp; Public/private key encryption is a way of encrypting data that provides a way to guarantee that the person who is sending you the data is who he claims to be.
+</p>
+<p>In simple terms it works like this: the SSH software generates two very large numbers that are used to encode and decode the data going over the network.&nbsp; The first number, called the <em>private key</em>, is kept secret and is only used by you to encode the data.&nbsp; The second number, called the <em>public key</em>, is given to anyone who needs to decode your data.&nbsp; He can decode it using the public key; there is no need for him to know the private key.&nbsp; He can also use the public key to encode a message to send back to you and you can decode it using your private key.
+</p>
+<p>Git uses SSH like an electronic signature to verify that code changes that are supposed to be coming from you actually are coming from you.&nbsp; The Git repository is given your public key.&nbsp; It knows that anything it decodes with that key must have been sent by you because only you have the private key needed to encode it.
+</p>
+<p> We will be using a tool called <strong>OpenSSH</strong> to generate the public and private keys.&nbsp; This is included with every version of Linux so you just need to verify that it has been installed.&nbsp; Then use the <strong>ssh-keygen</strong> utility that comes with OpenSSH to generate the keys:
+ <br />
+</p>
+<pre>[jim@olpc2 ~]$ ssh-keygen
+Generating public/private rsa key pair.
+Enter file in which to save the key (/home/jim/.ssh/id_rsa): </pre>
+<p>By default ssh-keygen generates an <strong>RSA</strong> key, which is the kind we want.&nbsp; By default it puts the keyfiles in a directory called <strong>/<em>yourhome</em>/.ssh</strong> and we want that too, so DO NOT enter a filename when it asks you to.&nbsp; Just hit the <strong>Enter</strong> key to continue.
+</p>
+<pre>[jim@olpc2 ~]$ ssh-keygen
+Generating public/private rsa key pair.
+Enter file in which to save the key (/home/jim/.ssh/id_rsa):
+Created directory '/home/jim/.ssh'.
+Enter passphrase (empty for no passphrase):
+</pre>
+<p>Now we DO want a passphrase here.&nbsp; A passphrase is like a password that is used with the public and private keys to do the encrypting.&nbsp; When you type it in you will not be able to see what you typed.&nbsp; Because of that it will ask you to type the same thing again, and it will check to see that you typed them in the same way both times.
+</p>
+<pre>[jim@olpc2 ~]$ ssh-keygen
+Generating public/private rsa key pair.
+Enter file in which to save the key (/home/jim/.ssh/id_rsa):
+Created directory '/home/jim/.ssh'.
+Enter passphrase (empty for no passphrase):
+Enter same passphrase again:
+Your identification has been saved in /home/jim/.ssh/id_rsa.
+Your public key has been saved in /home/jim/.ssh/id_rsa.pub.
+The key fingerprint is:
+d0:fe:c0:0c:1e:72:56:7a:19:cd:f3:85:c7:4c:9e:18 jim@olpc2.simmons
+The key's randomart image is:
++--[ RSA 2048]----+
+| oo E=. |
+| + o+ .+=. |
+| . B + o.oo |
+| = O . |
+| . S |
+| o |
+| . |
+| |
+| |
++-----------------+
+</pre>
+<p> When choosing a passphrase remember that it needs to be something you can type reliably without seeing it and it would be better if it was <em>not</em> a word you can find in the dictionary, because those are easily broken. When I need to make a password I use the tool at <a href="http://www.multicians.org/thvv/gpw.html.">http://www.multicians.org/thvv/gpw.html.</a>&nbsp; This tool generates a bunch of nonsense words that are pronounceable.&nbsp; Pick one that appeals to you and use that.
+</p>
+<p>Now have a look inside the .ssh directory.&nbsp; By convention every file or directory name that begins with a period is considered hidden by Linux, so it won't show up in a GNOME file browser window unless you use the option on the View menu to Show Hidden Files.&nbsp; When you display the contents of that directory you'll see two files: <strong>id_rsa</strong> and <strong>id_rsa.pub</strong>.&nbsp; The public key is in id_rsa.pub.&nbsp; Try opening that file with gedit (Open With Text Editor) and you'll see this:
+</p>
+<p><img alt="git12.jpg" src="/floss/pub/ActivitiesGuideSugar/git12.jpg" height="278" width="640" />
+</p>
+<p>When you create your account on <a href="http://git.sugarlabs.org">git.sugarlabs.org</a> there will be a place where you can add your public SSH key.&nbsp; To do that use Select All from the Edit menu in gedit, then Copy and Paste into the field provided on the web form.
+</p>
+<h2>Create A New Project
+</h2>
+<p>I'm going to create a new Project in Git for the examples for this book.&nbsp; I need to log in with my new account and click the <strong>New Project</strong> link we saw earlier.&nbsp; I get this form, which I have started filling in:
+</p>
+<p><img alt="git13.jpg" src="/floss/pub/ActivitiesGuideSugar/git13.jpg" height="343" width="398" />
+</p>
+<p>The <strong>Title</strong> is used on the website, the <strong>Slug</strong> is a shortened version of the title without spaces used to name the Git repository.&nbsp; <strong>Categories</strong> are optional.&nbsp; <strong>License</strong> is GPL v2 for my projects.&nbsp; You can choose from any of the licenses in the list for your own Projects, and you can change the license entry later if you want to.&nbsp; You will also need to enter a <strong>Description</strong> for your project.
+</p>
+<p>Once you have this set up you'll be able to click on the mainline entry for the Project (like we did with Read Etexts before) and see something like this:
+</p>
+<p><img alt="git14.jpg" src="/floss/pub/ActivitiesGuideSugar/git14.jpg" height="454" width="640" />
+</p>
+<p>The next step is to convert our project files into a local Git repository, add the files to it, then push it to the repository on <a href="http://git.sugarlabs.org">git.sugarlabs.org.</a>&nbsp; We need to do this because you cannot clone an empty repository, and our remote repository is currently empty.&nbsp; To get around that problem we'll push the local repository out to the new remote repository we just created, then clone the remote one and delete our existing project and its Git repository.&nbsp; From then on we'll do all our work in the cloned repository.
+ <br />
+</p>
+<p>This process may remind you of the Edward Albee quote, "<span class="body">Sometimes a person has to go a very long distance out of his way to come back a short distance correctly".</span> Fortunately we only need to do it once per project.&nbsp; Enter the commands shown below in <strong>bold</strong> after making you project directory the current one:
+ <br />
+</p>
+<pre><strong>git init</strong>
+Initialized empty Git repository in /home/jim/olpc/bookexamples/.git/
+<strong>git add *.py</strong>
+<strong>git add activity
+git add MANIFEST</strong>
+<strong>git add .gitignore
+git commit -a -m "Create repository and load"</strong>
+[master (root-commit) 727bfe8] Create repository and load
+ 9 files changed, 922 insertions(+), 0 deletions(-)
+ create mode 100644 .gitignore
+ create mode 100644 MANIFEST
+ create mode 100755 ReadEtexts.py
+ create mode 100644 ReadEtextsActivity.py
+ create mode 100644 ReadEtextsActivity2.py
+ create mode 100644 activity/activity.info
+ create mode 100644 activity/read-etexts.svg
+ create mode 100755 setup.py
+ create mode 100644 toolbar.py
+</pre>
+<p> I have made an empty local Git repository with <strong>git init</strong>, then I've used <strong>git add</strong> to add the important files to it.&nbsp; (In fact <strong>git add</strong> doesn't actually add anything itself; it just tells Git to add the file on the next <strong>git commit</strong>).&nbsp; Finally <strong>git commit</strong> with the options shown will actually put the latest version of these files in my new local repository.
+</p>
+<p>To push this local repository to <a href="http://git.sugarlabs.org">git.sugarlabs.org</a>&nbsp; we use the commands from the web page:
+</p>
+<pre><strong>git remote add origin gitorious@git.sugarlabs.org:myo-sugar-activities-examples/mainline.git
+git push origin master</strong>
+Counting objects: 17, done.
+Compressing objects: 100% (14/14), done.
+Writing objects: 100% (15/15), 7.51 KiB, done.
+Total 15 (delta 3), reused 0 (delta 0)
+To gitorious@git.sugarlabs.org:myo-sugar-activities-examples/mainline.git
+ 2cb3a1e..700789d master -&gt; master
+=&gt; Syncing Gitorious...
+Heads up: head of changed to 700789d3333a7257999d0a69bdcafb840e6adc09 on master
+Notify cia.vc of 727bfe819d5b7b70f4f2b31d02f5562709284ac4 on myo-sugar-activities-examples
+Notify cia.vc of 700789d3333a7257999d0a69bdcafb840e6adc09 on myo-sugar-activities-examples
+[OK]
+<strong>rm *</strong>
+<strong>rm activity -rf
+rm .git -rf</strong>
+<strong>cd ~</strong>
+<strong>mkdir olpc</strong>
+<strong>cd olpc</strong>
+<strong>mkdir bookexamples</strong>
+<strong>cd bookexamples
+git clone git://git.sugarlabs.org/myo-sugar-activities-examples/mainline.git</strong>
+Initialized empty Git repository in /home/jim/olpc/bookexamples/mainline/.git/
+remote: Counting objects: 18, done.
+remote: Compressing objects: 100% (16/16), done.
+remote: Total 18 (delta 3), reused 0 (delta 0)
+Receiving objects: 100% (18/18), 8.53 KiB, done.
+Resolving deltas: 100% (3/3), done.
+</pre>
+<p> The lines in <strong>bold</strong> are the commands to enter, and everything else is messages that Git sends to the console. It probably isn't clear what we're doing here and why, so let's take it step by step:
+</p>
+<ul>
+ <li>The first command <strong>git remote add origin</strong> tells the remote Git repository that we are going to send it stuff from our local repository.
+ <br /></li>
+ <li>The second command <strong>git push origin master</strong> actually sends your local Git repository to the remote one and its contents will be copied in.&nbsp; When you enter this command you will be asked to enter the SSH pass phrase you created in the last section.&nbsp; GNOME will remember this phrase for you and enter it for every Git command afterwards so you don't need to.&nbsp; It will keep doing this until you log out or turn off the computer.
+ <br /></li>
+ <li>The next step is to delete our existing files and our local Git repository (which is contained in the hidden directory .git).&nbsp; The <strong>rm .git -rf</strong> means "Delete the directory .git and everything in it".&nbsp; <strong>rm</strong> is a Unix command, not part of Git.&nbsp; If you like you can delete your existing files <em>after</em> you create the cloned repository in the next step.
+ <br /></li>
+ <li>Now we do the <strong>git clone</strong> command from the web page.&nbsp; This takes the remote Git repository we just added our MANIFEST file to and makes a new local repository in directory <strong>/<em>yourhome</em>/olpc/bookexamples/mainline.</strong></li>
+</ul>
+<p>Finally we have a local repository we can use.&nbsp; Well, not quite.&nbsp; We can commit our code to it but we cannot push anything back to the remote repository because our local repository isn't configured correctly yet.
+</p>
+<p>What we need to do is edit the file <strong>config</strong> in directory <strong>.git</strong> in <strong>/<em>yourhome</em>/olpc/bookexamples/mainline.&nbsp; </strong>We can use gedit to do that.&nbsp; We need to change the <strong>url=</strong> entry to point to the <strong>Push url</strong> shown on the mainline web page.&nbsp; When we're done our <strong>config</strong> file should look like this:
+</p>
+<pre>[core]
+ repositoryformatversion = 0
+ filemode = true
+ bare = false
+ logallrefupdates = true
+[remote "origin"]
+ <strong>url = gitorious@git.sugarlabs.org:myo-sugar-activities-examples/mainline.git</strong>
+ fetch = +refs/heads/*:refs/remotes/origin/*
+[branch "master"]
+ remote = origin
+ merge = refs/heads/master
+</pre>
+<p> The line in <strong>bold</strong> is the only one that gets changed.
+</p>
+<p>From now on anyone who wants to work on our project can get a local copy of the Git repository by doing this from within the directory where he wants the repository to go:
+</p>
+<p>
+</p>
+<pre><strong>git clone git://git.sugarlabs.org/myo-sugar-activities-examples/mainline.git</strong></pre>
+<p> He'll have to change his <strong>.git/config</strong> file just like we did, then he'll be ready to go.
+</p>
+<h2>Everyday Use Of Git
+</h2>
+<p> While getting the repositories set up to begin with is a chore, daily use is not.&nbsp; There are only a few commands you'll need to work with.&nbsp; When we left off we had a repository in <strong>/<em>yourhome</em>/olpc/bookexamples/mainline</strong> with our files in it.&nbsp; We will need to add any new files we create too.
+ <br />
+</p>
+<p>We use the <strong>git add</strong> command to tell Git that we want to use Git to store a particular file.&nbsp; This doesn't actually store anything, it just tells Git our intentions.&nbsp; The format of the command is simply:
+</p>
+<pre>git add <em>file_or_directory_name</em></pre>
+<p>There are files we <em>don't</em> want to add to Git, to begin with those files that end in <strong>.pyc</strong>.&nbsp; If we never do a <strong>git add</strong> on them they'll never get added, but Git will constantly ask us why we aren't adding them.&nbsp; Fortunately there is a way to tell Git that we really, really don't want to add those files.&nbsp; We need to create a file named <strong>.gitignore</strong> using gedit and put in entries like this:
+</p>
+<pre>*.pyc
+*.e4p
+*.zip
+.eric4project/
+.ropeproject/</pre>
+<p>These entries will also ignore project files used by Eric and zip files containing ebooks,&nbsp; Once we have this file created in the mainline directory we can add it to the repository:
+</p>
+<pre>git add .gitignore
+git commit -a -m "Add .gitignore file"
+</pre>
+<p>From now on Git will no longer ask us to add .pyc or other unwanted&nbsp; files that match our patterns. If there are other files we don't want in the repository we can add them to .gitignore either as full file names or directory names or as patterns like *.pyc.
+</p>
+<p>&nbsp;In addition to adding files to Git we can remove them too:
+</p>
+<pre>git rm <em>filename</em></pre>
+<p>Note that this just tells Git that from now on it will not be keeping track of a given filename, and that will take effect at the next commit.&nbsp; Old versions of the file are still in the repository.
+</p>
+<p>If you want to see what&nbsp;changes will be applied at the next commit run this:
+</p>
+<pre>git status</pre>
+<p>Finally, to put your latest changes in the repository use this:
+</p>
+<pre>git commit &nbsp;-a -m "Put a comment here"</pre>
+<p>If you leave off the -m an editor will open up and you can type in a comment, then save and exit. Unfortunately by default the editor is vi, an old text mode editor that is not friendly like gedit.
+</p>
+<p>When we have all our changes done we can send them to the central repository using <strong>git push</strong>:
+</p>
+<pre>git push</pre>
+<p>We can get the latest changes from other developers by doing <strong>git pull</strong>:
+</p>
+<pre><strong>git pull</strong>
+remote: Counting objects: 17, done.
+remote: Compressing objects: 100% (14/14), done.
+remote: Total 15 (delta 3), reused 0 (delta 0)
+Unpacking objects: 100% (15/15), done.
+From gitorious@git.sugarlabs.org:myo-sugar-activities-examples/mainline
+ 2cb3a1e..700789d master -&gt; origin/master
+Updating 2cb3a1e..700789d
+Fast forward
+ .gitignore | 6 +
+ MANIFEST | 244 +-----------------------------------
+ ReadEtexts.py | 182 +++++++++++++++++++++++++++
+ ReadEtextsActivity.py | 182 +++++++++++++++++++++++++++
+ ReadEtextsActivity2.py | 311 ++++++++++++++++++++++++++++++++++++++++++++++
+ activity/activity.info | 9 ++
+ activity/read-etexts.svg | 71 +++++++++++
+ setup.py | 21 +++
+ toolbar.py | 136 ++++++++++++++++++++
+ 9 files changed, 921 insertions(+), 241 deletions(-)
+ create mode 100644 .gitignore
+ create mode 100755 ReadEtexts.py
+ create mode 100644 ReadEtextsActivity.py
+ create mode 100644 ReadEtextsActivity2.py
+ create mode 100644 activity/activity.info
+ create mode 100644 activity/read-etexts.svg
+ create mode 100755 setup.py
+ create mode 100644 toolbar.py
+&nbsp;</pre><h1>License</h1>
+<p>All chapters copyright of the authors (see below). Unless otherwise stated all chapters in this manual licensed with <strong>GNU General Public License version 2</strong>
+</p>
+This documentation is free documentation; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+<p>
+This documentation is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+<p>
+You should have received a copy of the GNU General Public License
+along with this documentation; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+<p />
+<h1><a name="Authors"></a> Authors </h1>
+<p>
+</p><i>ADD REFINEMENTS</i><br/>&copy; James Simmons 2009, 2010<hr/><i>CREATING YOUR FIRST ACTIVITY</i><br/>&copy; Anne Gentle 2009<br/>Modifications:<br/>James Simmons 2009<br/><hr/><i>CREDITS</i><br/>&copy; adam hyde 2006, 2007<hr/><i>INHERIT FROM SUGAR.ACTIVITY.ACTIVITY</i><br/>&copy; James Simmons 2009<hr/><i>INTRODUCTION</i><br/>&copy; adam hyde 2006, 2007<br/>Modifications:<br/>James Simmons 2009<br/><hr/><i>WHAT DO I NEED TO KNOW TO WRITE A SUGAR ACTIVITY?</i><br/>&copy; Anne Gentle 2009<br/>Modifications:<br/>James Simmons 2009<br/><hr/><i>PACKAGE THE ACTIVITY</i><br/>&copy; James Simmons 2009<hr/><i>SETTING UP A DEVELOPMENT ENVIRONMENT</i><br/>&copy; Anne Gentle 2009<br/>Modifications:<br/>James Simmons 2009<br/><hr/><i>MAKING A STANDALONE PYTHON PROGRAM</i><br/>&copy; James Simmons 2009<hr/><i>ADD YOUR ACTIVITY CODE TO VERSION CONTROL</i><br/>&copy; James Simmons 2010<hr/><i>WHAT IS SUGAR?</i><br/>&copy; Anne Gentle 2009<br/>Modifications:<br/>James Simmons 2009<br/><hr/><i>WHAT IS A SUGAR ACTIVITY?</i><br/>&copy; Anne Gentle 2009<br/>Modifications:<br/>James Simmons 2009<br/><hr/>&nbsp;
+<p>
+<a href="http://www.flossmanuals.net/"><img alt="100.gif" src="/floss/pub/Floss/100.gif" height="54" width="110" border=0/></a>
+<br /><strong></strong>
+</p>
+<p><sub>Free manuals for free software</sub>
+</p>
+<p>
+</p>
+<p>&nbsp;
+</p>
+<p>&nbsp;
+</p>
+<h1><a name="General Public License"></a> General Public License </h1>
+<p>Version 2, June 1991
+</p>
+<p>Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+<br>51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+<br>
+<br>Everyone is permitted to copy and distribute verbatim copies
+<br>of this license document, but changing it is not allowed.
+<br>
+</p>
+<p><strong>Preamble</strong>
+</p>
+<p> The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too.
+</p>
+<p> When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things.
+<p />
+</p>
+<p> To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it.
+</p>
+<p> For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.
+</p>
+<p> We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software.
+</p>
+<p> Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations.
+</p>
+<p> Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all.
+</p>
+<p> The precise terms and conditions for copying, distribution and modification follow.
+<p />
+</p>
+<p><strong>TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION</strong>
+</p>
+<p> <strong>0.</strong> This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you".
+</p>
+<p> Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.
+</p>
+<p> <strong>1.</strong> You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program.
+</p>
+<p />
+<p> You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.
+</p>
+<p> <strong>2.</strong> You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:
+</p> <dl> <dt>
+<br></dt> <dd> <strong>a)</strong> You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. </dd> <dt>
+<p />
+<br></dt> <dd> <strong>b)</strong> You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. </dd> <dt>
+<br></dt> <dd> <strong>c)</strong> If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) </dd> </dl>
+<p> These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.
+</p>
+<p />
+<p> Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program.
+</p>
+<p> In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.
+</p>
+<p> <strong>3.</strong> You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:
+</p> <!-- we use this doubled UL to get the sub-sections indented, --> <!-- while making the bullets as unobvious as possible. --> <dl> <dt>
+<br></dt> <dd> <strong>a)</strong> Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, </dd> <dt>
+<p />
+<br></dt> <dd> <strong>b)</strong> Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, </dd> <dt>
+<br></dt> <dd> <strong>c)</strong> Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) </dd> </dl>
+<p> The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.
+</p>
+<p />
+<p> If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.
+</p>
+<p> <strong>4.</strong> You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.
+</p>
+<p> <strong>5.</strong> You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.
+</p>
+<p> <strong>6.</strong> Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License.
+<p />
+</p>
+<p> <strong>7.</strong> If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program.
+</p>
+<p> If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances.
+</p>
+<p> It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.
+</p>
+<p> This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.
+</p>
+<p> <strong>8.</strong> If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.
+<p />
+</p>
+<p> <strong>9.</strong> The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
+</p>
+<p> Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.
+</p>
+<p> <strong>10.</strong> If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.
+</p>
+<p><strong>NO WARRANTY</strong>
+</p>
+<p />
+<p> <strong>11.</strong> BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+</p>
+<p> <strong>12.</strong> IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+</p>
+<p><strong>END OF TERMS AND CONDITIONS</strong>
+</p>
+<p>
+</body>
+</html> \ No newline at end of file
diff --git a/help/ActivityBook/bookstore/bookstore.gif b/help/ActivityBook/bookstore/bookstore.gif
new file mode 100644
index 0000000..36a85af
--- /dev/null
+++ b/help/ActivityBook/bookstore/bookstore.gif
Binary files differ
diff --git a/help/ActivityBook/bookstore/bookstore.js b/help/ActivityBook/bookstore/bookstore.js
new file mode 100644
index 0000000..3ba1cbe
--- /dev/null
+++ b/help/ActivityBook/bookstore/bookstore.js
@@ -0,0 +1,140 @@
+var fm_data = {"title":"FLOSS Manuals's Storefront","url":"http:\/\/stores.lulu.com\/flossmanuals","items":[{"title":"Inkscape","url":"http:\/\/www.lulu.com\/content\/4617381","description":"The premier vector graphic editor for OSX, Linux, Windows. The manual is written by the official Inkscape documentation team and friends.","thumb":"http:\/\/www.lulu.com\/items\/volume_64\/4617000\/4617381\/1\/preview\/promo_4617381.jpg","date":"Fri, 24 Oct 2008 18:21:59"},{"title":"How to Bypass Internet Censorship","url":"http:\/\/www.lulu.com\/content\/4904448","description":"Inform yourself on how internet censorship works and how to route around it with free software. Includes an excellent overview of the techniques and tools for beginners and advanced users..","thumb":"http:\/\/www.lulu.com\/items\/volume_64\/4904000\/4904448\/1\/preview\/promo_4904448.jpg","date":"Fri, 15 Nov 2008 18:21:59"},{"title":"FLOSS Manuals","url":"http:\/\/www.lulu.com\/content\/4582230","description":"Learn how to use FLOSS Manuals. Includes essay by founder Adam Hyde about why we need free documentation.","thumb":"http:\/\/www.lulu.com\/items\/volume_64\/4582000\/4582230\/1\/preview\/promo_4582230.jpg","date":"Tue, 21 Oct 2008 20:57:28"},{"title":"SUGAR USERS GUIDE","url":"http:\/\/www.lulu.com\/content\/3865497","description":"Sugar is most well known as being the Desktop on the One Laptop per Child computers. However you can also install Sugar on your own computer. Learn more about this exciting new approach to learning how to use a computer...","thumb":"http:\/\/www.lulu.com\/items\/volume_64\/3865000\/3865497\/6\/preview\/promo_3865497.jpg","date":"Fri, 10 Oct 2008 16:59:10"},{"title":"OLPC LAPTOP USERS GUIDE","url":"http:\/\/www.lulu.com\/content\/4439260","description":"The book to go with the OLPC hardware. Good with the Give 1 Get 1 program.","thumb":"http:\/\/www.lulu.com\/items\/volume_64\/3865000\/3865224\/9\/preview\/promo_3865224.jpg","date":"Fri, 10 Oct 2008 16:53:00"},{"title":"INTRODUCTION TO THE GNU/LINUX COMMAND LINE","url":"http:\/\/www.lulu.com\/content\/6521146","description":"Learn the power of the command line! Written for the beginner by friendly experts.","thumb":"http:\/\/www.lulu.com\/items\/volume_64\/6521000\/6521146\/1\/preview\/promo_6521146.jpg","date":"Fri, 10 Oct 2008 16:53:00"},{"title":"Open Translation Tools","url":"http:\/\/www.lulu.com\/content\/7339299","description":"A handbook for the Open Translation Movement","thumb":"http:\/\/www.lulu.com\/items\/volume_65\/7339000\/7339299\/1/preview\/promo_7339299.jpg","date":"Fri, 29 June 2009 18:00:00"},{"title":"Video Subtitling","url":"http:\/\/www.lulu.com\/content\/7339340","description":"A handbook for creating video subtitles","thumb":"http:\/\/www.lulu.com\/items\/volume_65\/7339000\/7339340\/1\/preview\/promo_7339340.jpg","date":"Fri, 29 June 2009 18:30:00"},{"title":"CiviCRM","url":"http:\/\/www.lulu.com\/content\/7098434","description":"A fantastic guide to learning how to use the premier Constituent Relationship Manager - CiviCRM. Ideally suited for non-profit organisations.","thumb":"http:\/\/www.lulu.com\/items\/volume_65\/7098000\/7098434\/1\/preview\/promo_7098434.jpg","date":"Fri, 9 May 2009 18:00:00"},{"title":"FIREFOX","url":"http:\/\/www.lulu.com\/content\/6480979","description":"Learn how to get more from the worlds best browser!","thumb":"http:\/\/www.lulu.com\/items\/volume_64\/6480000\/6480979\/3\/preview\/promo_6480979.jpg","date":"Fri, 10 Oct 2008 16:53:00"}]};
+
+var FM = {
+ 'config': {
+ 'show': 'normal', // normal, random
+ 'items': 2,
+ 'slideshow': false,
+ 'timeout': 5,
+ 'preferred': null,
+ 'paging': true,
+ 'next_desc': 'more books &gt;&gt;',
+ "prev_desc": "&lt;&lt; back"
+
+ },
+
+ current_page: 0,
+ first_run: true,
+
+ 'previous_page': function() {
+ if(!(FM.first_run && FM.config.preferred))
+ FM.current_page -= 1;
+
+ FM.redraw();
+ },
+
+ 'next_page': function() {
+ if(!(FM.first_run && FM.config.preferred))
+ FM.current_page += 1;
+
+ FM.redraw();
+ },
+
+ 'create_item': function(i) {
+ var s = '<li class="lulu-item">';
+ s += '<img class="lulu-item-thumbnail" src="' + fm_data.items[i].thumb + '" />';
+ s += '<h2 class="lulu-item-title"><a href="' + fm_data.items[i].url + '">' + fm_data.items[i].title + '</a></h2>';
+ s += '<div class="lulu-item-description">' + fm_data.items[i].description + '</div>';
+ s += '<a class="lulu-item-buynow" href="' + fm_data.items[i].url + '">Buy Now!</a>';
+ s += '</li>';
+
+ return s;
+ },
+
+ 'show': function () {
+ var s = '';
+
+ if(FM.config.preferred != null && FM.first_run == true) {
+ for(var i = 0; i < FM.config.preferred.length; i++) {
+ for(var k = 0; k < fm_data.items.length; k++ ) {
+ if(FM.config.preferred[i].toLowerCase() == fm_data.items[k]["title"].toLowerCase()) {
+ s += FM.create_item(k);
+ }
+ }
+ }
+ } else {
+ for (var i = FM.current_page*FM.config.items+0; i < FM.current_page*FM.config.items+FM.config.items; i++) {
+ if(fm_data.items[i])
+ s += FM.create_item(i);
+ }
+ }
+
+ if(FM.config.paging) {
+ s += '<div id="lulu-more">';
+ if(FM.current_page != 0)
+ s += '<a class="more" href="javascript:void(0)" onclick="FM.previous_page()">'+FM.config.prev_desc+'</a><br/>';
+
+ if((1+FM.current_page)*FM.config.items < fm_data.items.length)
+ s += '<a class="more" href="javascript:void(0)" onclick="FM.next_page()">'+FM.config.next_desc+'</a>';
+ s += '</div>';
+ }
+
+ return s;
+ },
+
+ 'redraw': function() {
+ FM.first_run = false;
+ var _elem = document.getElementById("lulu-storefront-items");
+
+ if(_elem) {
+ _elem.innerHTML = FM.show();
+ }
+ },
+
+ 'interval': function() {
+ if(!FM.first_run) {
+ if((FM.current_page+1)*FM.config.items < fm_data.items.length)
+ FM.current_page += 1;
+ else
+ FM.current_page = 0;
+ }
+
+ FM.redraw();
+ },
+
+ 'init': function(config) {
+ if(config) {
+ for(var k in config) {
+ FM.config[k] = config[k];
+ }
+ }
+
+ if(FM.config["show"] == "random") {
+ var new_list = new Array();
+
+ while(new_list.length != fm_data.items.length) {
+ while(1) {
+ var _r = Math.floor(Math.random()*fm_data.items.length);
+
+ if(fm_data.items[_r] != null) {
+ new_list.push(fm_data.items[_r]);
+ fm_data.items[_r] = null;
+ break;
+ }
+ }
+ }
+ fm_data.items = new_list;
+ }
+
+ FM.first_run = true;
+ document.write('<div id="lulu-storefront">')
+ document.write('<h1 id="lulu-storefront-title"><a href="' + fm_data.url + '">' + fm_data.title + '</a></h1>');
+ document.write('<ul id="lulu-storefront-items">');
+
+ document.write(FM.show());
+
+ document.write('</ul>');
+ document.write('</div>');
+
+ if(FM.config.slideshow) {
+ setInterval('FM.interval()', FM.config.timeout*1000);
+ }
+
+ if(FM.config.paging) {
+ FM.current_page = 0;
+ }
+
+ }
+};
+
+
diff --git a/help/ActivityBook/floss/pub/ActivitiesGuideSugar/ReadEtexts_01_1.jpg b/help/ActivityBook/floss/pub/ActivitiesGuideSugar/ReadEtexts_01_1.jpg
new file mode 100644
index 0000000..352effb
--- /dev/null
+++ b/help/ActivityBook/floss/pub/ActivitiesGuideSugar/ReadEtexts_01_1.jpg
Binary files differ
diff --git a/help/ActivityBook/floss/pub/ActivitiesGuideSugar/ReadEtexts_02.jpg b/help/ActivityBook/floss/pub/ActivitiesGuideSugar/ReadEtexts_02.jpg
new file mode 100644
index 0000000..dcf22b5
--- /dev/null
+++ b/help/ActivityBook/floss/pub/ActivitiesGuideSugar/ReadEtexts_02.jpg
Binary files differ
diff --git a/help/ActivityBook/floss/pub/ActivitiesGuideSugar/ReadEtexts_03.jpg b/help/ActivityBook/floss/pub/ActivitiesGuideSugar/ReadEtexts_03.jpg
new file mode 100644
index 0000000..9302035
--- /dev/null
+++ b/help/ActivityBook/floss/pub/ActivitiesGuideSugar/ReadEtexts_03.jpg
Binary files differ
diff --git a/help/ActivityBook/floss/pub/ActivitiesGuideSugar/ReadEtexts_04.jpg b/help/ActivityBook/floss/pub/ActivitiesGuideSugar/ReadEtexts_04.jpg
new file mode 100644
index 0000000..a24fd89
--- /dev/null
+++ b/help/ActivityBook/floss/pub/ActivitiesGuideSugar/ReadEtexts_04.jpg
Binary files differ
diff --git a/help/ActivityBook/floss/pub/ActivitiesGuideSugar/ReadEtexts_05.jpg b/help/ActivityBook/floss/pub/ActivitiesGuideSugar/ReadEtexts_05.jpg
new file mode 100644
index 0000000..e0bbe0c
--- /dev/null
+++ b/help/ActivityBook/floss/pub/ActivitiesGuideSugar/ReadEtexts_05.jpg
Binary files differ
diff --git a/help/ActivityBook/floss/pub/ActivitiesGuideSugar/git1.jpg b/help/ActivityBook/floss/pub/ActivitiesGuideSugar/git1.jpg
new file mode 100644
index 0000000..cae8fba
--- /dev/null
+++ b/help/ActivityBook/floss/pub/ActivitiesGuideSugar/git1.jpg
Binary files differ
diff --git a/help/ActivityBook/floss/pub/ActivitiesGuideSugar/git10.jpg b/help/ActivityBook/floss/pub/ActivitiesGuideSugar/git10.jpg
new file mode 100644
index 0000000..47c3278
--- /dev/null
+++ b/help/ActivityBook/floss/pub/ActivitiesGuideSugar/git10.jpg
Binary files differ
diff --git a/help/ActivityBook/floss/pub/ActivitiesGuideSugar/git11_1.jpg b/help/ActivityBook/floss/pub/ActivitiesGuideSugar/git11_1.jpg
new file mode 100644
index 0000000..23572f2
--- /dev/null
+++ b/help/ActivityBook/floss/pub/ActivitiesGuideSugar/git11_1.jpg
Binary files differ
diff --git a/help/ActivityBook/floss/pub/ActivitiesGuideSugar/git12.jpg b/help/ActivityBook/floss/pub/ActivitiesGuideSugar/git12.jpg
new file mode 100644
index 0000000..bb3aef1
--- /dev/null
+++ b/help/ActivityBook/floss/pub/ActivitiesGuideSugar/git12.jpg
Binary files differ
diff --git a/help/ActivityBook/floss/pub/ActivitiesGuideSugar/git13.jpg b/help/ActivityBook/floss/pub/ActivitiesGuideSugar/git13.jpg
new file mode 100644
index 0000000..7d8a902
--- /dev/null
+++ b/help/ActivityBook/floss/pub/ActivitiesGuideSugar/git13.jpg
Binary files differ
diff --git a/help/ActivityBook/floss/pub/ActivitiesGuideSugar/git14.jpg b/help/ActivityBook/floss/pub/ActivitiesGuideSugar/git14.jpg
new file mode 100644
index 0000000..ca3e795
--- /dev/null
+++ b/help/ActivityBook/floss/pub/ActivitiesGuideSugar/git14.jpg
Binary files differ
diff --git a/help/ActivityBook/floss/pub/ActivitiesGuideSugar/git2.jpg b/help/ActivityBook/floss/pub/ActivitiesGuideSugar/git2.jpg
new file mode 100644
index 0000000..bd80440
--- /dev/null
+++ b/help/ActivityBook/floss/pub/ActivitiesGuideSugar/git2.jpg
Binary files differ
diff --git a/help/ActivityBook/floss/pub/ActivitiesGuideSugar/git3.jpg b/help/ActivityBook/floss/pub/ActivitiesGuideSugar/git3.jpg
new file mode 100644
index 0000000..e9df4a7
--- /dev/null
+++ b/help/ActivityBook/floss/pub/ActivitiesGuideSugar/git3.jpg
Binary files differ
diff --git a/help/ActivityBook/floss/pub/ActivitiesGuideSugar/git4.jpg b/help/ActivityBook/floss/pub/ActivitiesGuideSugar/git4.jpg
new file mode 100644
index 0000000..3eff680
--- /dev/null
+++ b/help/ActivityBook/floss/pub/ActivitiesGuideSugar/git4.jpg
Binary files differ
diff --git a/help/ActivityBook/floss/pub/ActivitiesGuideSugar/git5.jpg b/help/ActivityBook/floss/pub/ActivitiesGuideSugar/git5.jpg
new file mode 100644
index 0000000..cb82bfe
--- /dev/null
+++ b/help/ActivityBook/floss/pub/ActivitiesGuideSugar/git5.jpg
Binary files differ
diff --git a/help/ActivityBook/floss/pub/ActivitiesGuideSugar/git6.jpg b/help/ActivityBook/floss/pub/ActivitiesGuideSugar/git6.jpg
new file mode 100644
index 0000000..d5ba0da
--- /dev/null
+++ b/help/ActivityBook/floss/pub/ActivitiesGuideSugar/git6.jpg
Binary files differ
diff --git a/help/ActivityBook/floss/pub/ActivitiesGuideSugar/git7.jpg b/help/ActivityBook/floss/pub/ActivitiesGuideSugar/git7.jpg
new file mode 100644
index 0000000..5c383bf
--- /dev/null
+++ b/help/ActivityBook/floss/pub/ActivitiesGuideSugar/git7.jpg
Binary files differ
diff --git a/help/ActivityBook/floss/pub/ActivitiesGuideSugar/git8.jpg b/help/ActivityBook/floss/pub/ActivitiesGuideSugar/git8.jpg
new file mode 100644
index 0000000..0940192
--- /dev/null
+++ b/help/ActivityBook/floss/pub/ActivitiesGuideSugar/git8.jpg
Binary files differ
diff --git a/help/ActivityBook/floss/pub/ActivitiesGuideSugar/git9.jpg b/help/ActivityBook/floss/pub/ActivitiesGuideSugar/git9.jpg
new file mode 100644
index 0000000..80cf84f
--- /dev/null
+++ b/help/ActivityBook/floss/pub/ActivitiesGuideSugar/git9.jpg
Binary files differ
diff --git a/help/ActivityBook/floss/pub/Floss/100.gif b/help/ActivityBook/floss/pub/Floss/100.gif
new file mode 100644
index 0000000..de26325
--- /dev/null
+++ b/help/ActivityBook/floss/pub/Floss/100.gif
Binary files differ
diff --git a/help/ActivityBook/floss/pub/TWiki/FlossSkin2/WHATDOIWANT2.gif b/help/ActivityBook/floss/pub/TWiki/FlossSkin2/WHATDOIWANT2.gif
new file mode 100644
index 0000000..cdb22cf
--- /dev/null
+++ b/help/ActivityBook/floss/pub/TWiki/FlossSkin2/WHATDOIWANT2.gif
Binary files differ
diff --git a/help/ActivityBook/floss/pub/TWiki/FlossSkin2/background.gif b/help/ActivityBook/floss/pub/TWiki/FlossSkin2/background.gif
new file mode 100644
index 0000000..355a464
--- /dev/null
+++ b/help/ActivityBook/floss/pub/TWiki/FlossSkin2/background.gif
Binary files differ
diff --git a/help/ActivityBook/floss/pub/TWiki/FlossSkin2/fl2.ico b/help/ActivityBook/floss/pub/TWiki/FlossSkin2/fl2.ico
new file mode 100644
index 0000000..d4ea6d2
--- /dev/null
+++ b/help/ActivityBook/floss/pub/TWiki/FlossSkin2/fl2.ico
Binary files differ
diff --git a/help/ActivityBook/floss/pub/TWiki/FlossSkin2/free.gif b/help/ActivityBook/floss/pub/TWiki/FlossSkin2/free.gif
new file mode 100644
index 0000000..c88c79e
--- /dev/null
+++ b/help/ActivityBook/floss/pub/TWiki/FlossSkin2/free.gif
Binary files differ
diff --git a/help/ActivityBook/floss/pub/TWiki/FlossSkin2/text_read.gif b/help/ActivityBook/floss/pub/TWiki/FlossSkin2/text_read.gif
new file mode 100644
index 0000000..568d61e
--- /dev/null
+++ b/help/ActivityBook/floss/pub/TWiki/FlossSkin2/text_read.gif
Binary files differ
diff --git a/help/ActivityBook/floss/pub/TWiki/FlossSkin2/top_read.gif b/help/ActivityBook/floss/pub/TWiki/FlossSkin2/top_read.gif
new file mode 100644
index 0000000..dced8fc
--- /dev/null
+++ b/help/ActivityBook/floss/pub/TWiki/FlossSkin2/top_read.gif
Binary files differ
diff --git a/help/ActivityBook/floss/pub/TWiki/FlossSkin2/typography_cover.css b/help/ActivityBook/floss/pub/TWiki/FlossSkin2/typography_cover.css
new file mode 100644
index 0000000..0056067
--- /dev/null
+++ b/help/ActivityBook/floss/pub/TWiki/FlossSkin2/typography_cover.css
@@ -0,0 +1,229 @@
+body {
+font-family : Trebuchet,verdana, sans-serif;
+line-height:17px;
+text-decoration:none;
+}
+table {
+font-size: 12px;
+color:black;
+font-family : Trebuchet,verdana, sans-serif;
+text-decoration:none;
+}
+
+
+.ds-note {
+border: 1px solid black;
+float: right;
+padding: .5em;
+margin: .5em 0 .5em 1em;
+width: 15em;
+background-color: #FFFFBF;
+}
+A:link {
+color:#777777;
+}
+A:visited {
+color:#777777;
+}
+A:active {
+color:#777777;
+}
+A:hover {
+color:#000000;
+}
+
+div {
+ border: 0px solid #000000;
+}
+
+div.container {
+ position: relative;
+ margin: 0 auto;
+ width: 780px;
+ height: 5000px;
+}
+
+div.left {
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ width: 200px;
+ height: 100%;
+}
+
+div.top {
+ position: absolute;
+ top: 0px;
+ left: 170px;
+ width: 500px;
+ height: 100%;
+}
+
+div.main {
+ position: absolute;
+ top: 150px;
+ left: 200px;
+ width: 580px;
+ height: 100%;
+}
+
+pre, span.Code, span.verbatim {
+font-size:0.9em;
+line-height:1.5em;
+background-color:#FFE5CC;
+border: 0px solid #000000;
+margin-left : 0.5em;
+margin-bottom : 20px;
+margin-right : 1em;
+padding-left: 1em;
+padding-right: 1em;
+padding-top: 0.2em;
+padding-bottom: 0.2em;
+color : black;
+}
+
+
+.ds-kbd {
+background-color: #efefef;
+margin-left: 2em;
+margin-right: 2em;
+padding: .5em 1em .5em 1em;
+font-family: monospace;
+}
+
+.ds-contentcontainer {
+padding: 0em .5em .5em 0em;
+}
+
+
+.ds-innercontentcontainer {
+line-height: 1.3;
+clear: both;
+padding-top: 1em;
+}
+
+.ds-nmcontent {
+line-height: 1.3;
+}
+
+
+.ds-innercontentcontainer ol, .ds-innercontentcontainer ul, .ds-innercontentcontainer li {
+line-height: 1.3em;
+margin-top: 0.2em;
+margin-bottom: 0.1em;
+}
+
+.ds-nmcontent ol, .ds-nmcontent ul, .ds-nmcontent li {
+line-height: 1.3em;
+margin-top: 0.2em;
+margin-bottom: 0.1em;
+}
+
+
+/*
+ * a modified version of
+ * http://www.thenoodleincident.com/tutorials/typography/css/real.css
+ *
+ * One could optionally remove everything below.
+ */
+
+hr {
+border : none;
+background-color : #361b13;
+color : #000000;
+height : 10px;
+margin-bottom: 20px;
+margin-top: 20px;
+}
+
+blockquote {
+}
+
+ul, li {
+margin-bottom: 5px;
+margin-top: 0px;
+}
+
+h1 {
+font-size: 24px;
+font-family : Arial,verdana, sans-serif;
+font-weight : Bold;
+margin-bottom: 10px;
+margin-top: 0px;
+line-height: 32px;
+letter-spacing: -1px;
+text-decoration:none;
+
+}
+
+h2 {
+font-size: 16px;
+font-family : Arial,verdana, sans-serif;
+margin-bottom: 5px;
+margin-top: 0px;
+padding-top : 15px;
+text-decoration:none;
+}
+
+h3 {
+font-size: 12px;
+font-family : Arial,verdana, sans-serif;
+margin-bottom: 5px;
+text-decoration:none;
+}
+
+h4 {
+font-size: 1em;
+font-family : Arial,verdana, sans-serif;
+font-weight : Bold;
+margin-bottom: -12px;
+}
+
+h5 {
+font-size: 1.0em;
+font-family : Arial Black;
+margin-bottom: 0em;
+}
+
+h6 {
+font-size: 0.8em;
+font-family : Arial Black;
+margin-bottom: 0em;
+}
+
+/*
+ * this might cause more problems that it solves, but fixed-width type
+ * is extremely tiny in Firefox with some sizing methods (eg with 76%
+ * font-sizing)
+*/
+
+body kbd, body tt, body code {
+font-size: x-small;
+}
+p {
+ margin-top: 1em;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/ReadEtexts_01_1.jpg b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/ReadEtexts_01_1.jpg
new file mode 100644
index 0000000..352effb
--- /dev/null
+++ b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/ReadEtexts_01_1.jpg
Binary files differ
diff --git a/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/ReadEtexts_02.jpg b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/ReadEtexts_02.jpg
new file mode 100644
index 0000000..dcf22b5
--- /dev/null
+++ b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/ReadEtexts_02.jpg
Binary files differ
diff --git a/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/ReadEtexts_03.jpg b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/ReadEtexts_03.jpg
new file mode 100644
index 0000000..9302035
--- /dev/null
+++ b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/ReadEtexts_03.jpg
Binary files differ
diff --git a/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/ReadEtexts_04.jpg b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/ReadEtexts_04.jpg
new file mode 100644
index 0000000..a24fd89
--- /dev/null
+++ b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/ReadEtexts_04.jpg
Binary files differ
diff --git a/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/ReadEtexts_05.jpg b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/ReadEtexts_05.jpg
new file mode 100644
index 0000000..e0bbe0c
--- /dev/null
+++ b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/ReadEtexts_05.jpg
Binary files differ
diff --git a/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git1.jpg b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git1.jpg
new file mode 100644
index 0000000..cae8fba
--- /dev/null
+++ b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git1.jpg
Binary files differ
diff --git a/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git10.jpg b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git10.jpg
new file mode 100644
index 0000000..47c3278
--- /dev/null
+++ b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git10.jpg
Binary files differ
diff --git a/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git11_1.jpg b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git11_1.jpg
new file mode 100644
index 0000000..23572f2
--- /dev/null
+++ b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git11_1.jpg
Binary files differ
diff --git a/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git12.jpg b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git12.jpg
new file mode 100644
index 0000000..bb3aef1
--- /dev/null
+++ b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git12.jpg
Binary files differ
diff --git a/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git13.jpg b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git13.jpg
new file mode 100644
index 0000000..7d8a902
--- /dev/null
+++ b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git13.jpg
Binary files differ
diff --git a/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git14.jpg b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git14.jpg
new file mode 100644
index 0000000..ca3e795
--- /dev/null
+++ b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git14.jpg
Binary files differ
diff --git a/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git2.jpg b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git2.jpg
new file mode 100644
index 0000000..bd80440
--- /dev/null
+++ b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git2.jpg
Binary files differ
diff --git a/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git3.jpg b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git3.jpg
new file mode 100644
index 0000000..e9df4a7
--- /dev/null
+++ b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git3.jpg
Binary files differ
diff --git a/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git4.jpg b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git4.jpg
new file mode 100644
index 0000000..3eff680
--- /dev/null
+++ b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git4.jpg
Binary files differ
diff --git a/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git5.jpg b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git5.jpg
new file mode 100644
index 0000000..cb82bfe
--- /dev/null
+++ b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git5.jpg
Binary files differ
diff --git a/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git6.jpg b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git6.jpg
new file mode 100644
index 0000000..d5ba0da
--- /dev/null
+++ b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git6.jpg
Binary files differ
diff --git a/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git7.jpg b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git7.jpg
new file mode 100644
index 0000000..5c383bf
--- /dev/null
+++ b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git7.jpg
Binary files differ
diff --git a/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git8.jpg b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git8.jpg
new file mode 100644
index 0000000..0940192
--- /dev/null
+++ b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git8.jpg
Binary files differ
diff --git a/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git9.jpg b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git9.jpg
new file mode 100644
index 0000000..80cf84f
--- /dev/null
+++ b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/ActivitiesGuideSugar/git9.jpg
Binary files differ
diff --git a/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/Floss/100.gif b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/Floss/100.gif
new file mode 100644
index 0000000..de26325
--- /dev/null
+++ b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/Floss/100.gif
Binary files differ
diff --git a/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/background.gif b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/background.gif
new file mode 100644
index 0000000..355a464
--- /dev/null
+++ b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/background.gif
Binary files differ
diff --git a/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/fl2.ico b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/fl2.ico
new file mode 100644
index 0000000..d4ea6d2
--- /dev/null
+++ b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/fl2.ico
Binary files differ
diff --git a/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/lefttext.png b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/lefttext.png
new file mode 100644
index 0000000..95f5485
--- /dev/null
+++ b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/lefttext.png
Binary files differ
diff --git a/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/makepdf.gif b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/makepdf.gif
new file mode 100644
index 0000000..8c9b3db
--- /dev/null
+++ b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/makepdf.gif
Binary files differ
diff --git a/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/righttext.png b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/righttext.png
new file mode 100644
index 0000000..33747c4
--- /dev/null
+++ b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/righttext.png
Binary files differ
diff --git a/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/top_read_back.gif b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/top_read_back.gif
new file mode 100644
index 0000000..9e6187a
--- /dev/null
+++ b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/top_read_back.gif
Binary files differ
diff --git a/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/typography.css b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/typography.css
new file mode 100644
index 0000000..83d2760
--- /dev/null
+++ b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/typography.css
@@ -0,0 +1,313 @@
+body {
+font-family : trebuchet,verdana, sans-serif;
+font-size: 12px;
+line-height:17px;
+}
+.case {
+border: 1px dotted #666666;
+padding: 6px 6px;
+background-color: #fcf4ea;
+}
+
+.warning {
+border: 1px dotted #666666;
+padding: 6px 6px;
+background-color: #fcf4ea;
+}
+
+.note {
+border: 1px dotted #666666;
+padding: 6px 6px;
+background-color: #fcf4ea;
+}
+
+
+
+.button
+{
+ border: 3px outset #F3F3F3;
+ background-color: #F3F3F3;
+ padding: 0px 2px;
+ cursor: default;
+}
+.dialog
+{
+ border-top: 3px solid #666;
+ border-right: 1px solid #666;
+ border-left: 1px solid #666;
+ border-bottom: 1px solid #666;
+ background-color: #F3F3F3;
+ padding: 0px 2px 0px 2px;
+ cursor: default;
+ line-height: 20px;
+}
+.menu
+{
+ border: 1px solid #666;
+ background-color: #ffa54d;
+ padding: 0px 2px 0px 2px;
+ cursor: default;
+ line-height: 20px;
+}
+.keyboard_shortcuts
+{
+ border: 3px outset #F3F3F3;
+ background-color: #F3F3F3;
+ padding: 0px 2px;
+ cursor: default;
+ line-height: 20px;
+}
+.image_placeholder
+{
+ border: 5px solid #ff7f00;
+ padding: 5px 5px 5px 5px;
+ height:90px;
+ width:120px;
+ background-image: url('/floss/pub/TWiki/FlossSkin2/image.png');
+ background-repeat : no;
+}
+
+p.writers_comment
+{
+ border: 5px solid #ff7f00;
+ background-color: #e1e1e1;
+ padding: 5px 5px 5px 5px;
+}
+div.tips
+{
+ border: 1px solid #e1e1e1;
+ background-color: #fff7f0;
+ padding: 5px 5px 5px 5px;
+}
+p.warning
+{
+ border: 5px solid red;
+ background-color: #fff7f0;
+ padding: 5px 5px 5px 5px;
+}
+div.definition
+{
+ border :1px solid #ff7f00;
+ border-style: dashed;
+ padding: 5px 5px 5px 5px;
+}
+table {
+border: outset 0px;
+font-family : trebuchet,verdana, sans-serif;
+font-size : 12px;
+}
+
+A:link {
+ color:#666666;
+}
+A:visited {
+ color:#000000;
+}
+A:active {
+ color:#000000;
+}
+A:hover {
+ color:#000000;
+}
+
+
+.ds-note {
+border: 1px solid black;
+float: right;
+padding: .5em;
+margin: .5em 0 .5em 1em;
+width: 15em;
+background-color: #FFFFBF;
+}
+
+
+div {
+ border: 0px solid #000000;
+}
+
+div.container {
+ position: relative;
+ margin: 0 auto;
+ width: 780px;
+ height: 5000px;
+}
+
+div.left {
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ width: 200px;
+ height: 100%;
+}
+
+div.top {
+ position: absolute;
+ top: 0px;
+ left: 170px;
+ width: 500px;
+ height: 100%;
+}
+
+div.main {
+ position: absolute;
+ top: 150px;
+ left: 200px;
+ width: 580px;
+ height: 100%;
+}
+
+pre, span.Code, span.verbatim {
+font-size:12px;
+line-height:1.5em;
+background-color:#FFE5CC;
+border: 0px solid #000000;
+margin-left : 0.5em;
+margin-bottom : 20px;
+margin-right : 1em;
+padding-left: 1em;
+padding-right: 1em;
+padding-top: 0.2em;
+padding-bottom: 0.2em;
+color : black;
+white-space: pre-wrap; /* css-3 */
+white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
+white-space: -pre-wrap; /* Opera 4-6 */
+white-space: -o-pre-wrap; /* Opera 7 */
+word-wrap: break-word; /* Internet Explorer 5.5+ */
+}
+
+img {
+border: 0px solid #361b13;
+margin-top: 0em;
+}
+
+.ds-kbd {
+background-color: #efefef;
+margin-left: 2em;
+margin-right: 2em;
+padding: .5em 1em .5em 1em;
+font-family: monospace;
+}
+
+.ds-contentcontainer {
+padding: 0em .5em .5em 0em;
+}
+
+
+.ds-innercontentcontainer {
+line-height: 1.3;
+clear: both;
+padding-top: 1em;
+}
+
+.ds-nmcontent {
+line-height: 1.3;
+}
+
+
+.ds-innercontentcontainer ol, .ds-innercontentcontainer ul, .ds-innercontentcontainer li {
+line-height: 1.3em;
+margin-top: 0.2em;
+margin-bottom: 0.1em;
+}
+
+.ds-nmcontent ol, .ds-nmcontent ul, .ds-nmcontent li {
+line-height: 1.3em;
+margin-top: 0.2em;
+margin-bottom: 0.1em;
+}
+
+
+/*
+ * a modified version of
+ * http://www.thenoodleincident.com/tutorials/typography/css/real.css
+ *
+ * One could optionally remove everything below.
+ */
+
+hr {
+border : none;
+background-color : #666666;
+color : #000000;
+height : 2px;
+width:120px;
+margin-left:0px;
+margin-bottom: 10px;
+margin-top: 10px;
+}
+
+blockquote {
+}
+
+ul, li {
+margin-bottom: 5px;
+margin-top: 0px;
+}
+
+h1 {
+font-size: 24px;
+font-family : Arial,verdana, sans-serif;
+font-weight : Bold;
+margin-bottom: 10px;
+margin-top: 0px;
+line-height: 32px;
+letter-spacing: -1px;
+}
+
+h2 {
+font-size: 18px;
+font-family : Arial,verdana, sans-serif;
+font-weight : Bold;
+margin-bottom: 10px;
+margin-top: 15px;
+padding-top : 15px;
+}
+
+h3 {
+font-size: 14px;
+font-family : Arial,verdana, sans-serif;
+font-weight : Bold;
+margin-bottom: 5px;
+}
+
+h4 {font-weight : Bold;font-size: 12px;}
+h5 {font-weight : Bold;font-size: 12px;}
+h6 {font-weight : Bold;font-size: 12px;}
+
+
+/*
+ * this might cause more problems that it solves, but fixed-width type
+ * is extremely tiny in Firefox with some sizing methods (eg with 76%
+ * font-sizing)
+*/
+
+body kbd, body tt, body code {
+font-size: x-small;
+}
+p {
+ margin-top: 1em;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/viewprint.gif b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/viewprint.gif
new file mode 100644
index 0000000..5efa5b7
--- /dev/null
+++ b/help/ActivityBook/floss/publish/ActivitiesGuideSugar/rsrc/TWiki/FlossSkin2/viewprint.gif
Binary files differ
diff --git a/help/ActivityBook/index.html b/help/ActivityBook/index.html
new file mode 100644
index 0000000..83558b1
--- /dev/null
+++ b/help/ActivityBook/index.html
@@ -0,0 +1,263 @@
+<html>
+ <head>
+ <title>FLOSS Manuals (en)</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <link rel="icon" href="http://en.flossmanuals.net/floss/pub/TWiki/FlossSkin2/fl2.ico" type="image/x-icon" /> <link rel="shortcut icon" href="http://en.flossmanuals.net/floss/pub/TWiki/FlossSkin2/fl2.ico" type="image/x-icon" />
+<link rel=StyleSheet href='http://en.flossmanuals.net/floss/pub/TWiki/FlossSkin2/typography_cover.css' type='text/css' media='screen'>
+<link rel="alternate" type="application/rss+xml" title="RSS Feed" href="/rss" />
+ </head>
+<body background="http://en.flossmanuals.net/floss/pub/TWiki/FlossSkin2/background.gif" style="margin:0;color:#000000;text-decoration:none;">
+<style>
+body
+{
+margin:0;
+padding:0
+}
+#header
+{
+position:absolute;
+top:23px;
+width:100%;
+background-image:
+url('http://en.flossmanuals.net/floss/pub/TWiki/FlossSkin2/header_bg.gif');
+background-position: 600px 0px; /* this places the orange background at
+an offset, making sure it doesn't underlap the left side of the gif */
+background-repeat: no-repeat;
+}
+#header_imagemap
+{
+margin-left: 352px;
+border: 0px
+}
+h1 {
+color:#ff7f00;
+}
+h2 {
+color:#ff7f00;
+}
+h3 {
+color:#000000;
+}
+</style>
+<div id="header"><img id="header_imagemap" width="465" height="95" alt="FlossManuals menu" src='http://en.flossmanuals.net/floss/pub/TWiki/FlossSkin2/top_read.gif' border=0 usemap='#map'></div>
+<p />
+<map name="map">
+<!-- #$-:Image Map file created by GIMP Imagemap Plugin -->
+<!-- #$-:GIMP Imagemap Plugin by Maurits Rijk -->
+<!-- #$-:Please do not edit lines starting with "#$" -->
+<!-- #$VERSION:2.0 -->
+<!-- #$AUTHOR:reset -->
+<area shape="rect" coords="90,57,152,84" href="/read" />
+<area shape="rect" coords="159,57,219,84" href="/write" />
+<area shape="rect" coords="226,58,287,84" href="/remix" />
+<area shape="rect" coords="293,58,353,84" href="/about" />
+<area shape="rect" coords="398,18,426,39" alt="all sorts" target="new" href="http://translate.flossmanuals.net" />
+<area shape="rect" coords="402,40,426,58" alt="Farsi" target="newish" href="http://fa.flossmanuals.net" />
+<area shape="rect" coords="431,41,450,59" alt="Finnish" target="newsish" href="http://fi.flossmanuals.net" />
+<area shape="rect" coords="401,62,423,80" href="#" />
+<area shape="rect" coords="428,62,452,81" alt="Nederlands" target="newsish" href="http://nl.flossmanuals.net" />
+</map>
+<p />
+<p />
+<p />
+<p />
+</div>
+<div style="position:absolute;left:20px;top:140px;">
+ <img src='http://en.flossmanuals.net/floss/pub/TWiki/FlossSkin2/free.gif' border=0><br> <img src='http://en.flossmanuals.net/floss/pub/TWiki/FlossSkin2/WHATDOIWANT2.gif' border=0>
+</div>
+ <div style="position:absolute;left:270px;top:130px;">
+ <table cellpadding="0" cellspacing="0" summary="" style="table-layout:fixed;width:670;border: 5px solid #666666;padding-right: 0px;padding-left: 0px;padding-bottom: 0px;padding-top: 0px;margin-left : 10px;margin-top:10;background:#FFF7F0;">
+ <tr>
+ <td width=100%>
+ <div class="ds-contentcontainer">
+ <div style="margin-left:1.2em;">
+<p />
+ <img src='http://en.flossmanuals.net/floss/pub/TWiki/FlossSkin2/text_read.gif' border=0 style='position:absolute;top:30px;'><br><br>
+<p /><script type="text/javascript">
+var divList = document.getElementsByTagName("h3");
+function HideByTitle(){
+var titleList ='win,lin,osx,all,winlin,winosx,linosx';
+ var titlesToHide = titleList.split(",");
+ for(var a = 0; a < divList.length; a++)
+ for(var b = 0; b < titlesToHide.length; b++)
+ if(divList[a].id == titlesToHide[b])
+ divList[a].style.display='none';
+}
+function ShowByTitle(titleList){
+HideByTitle();
+ var titlesToShow = titleList.split(",");
+ for(var a = 0; a < divList.length; a++)
+ for(var b = 0; b < titlesToShow.length; b++)
+ if(divList[a].id == titlesToShow[b])
+ divList[a].style.display='block';
+}
+</script>
+<div style="position:absolute;left:320px;top:65px;"><!-- Google CSE Search Box Begins --> <!-- Use of this code assumes agreement with the Google Custom Search Terms of Service. --> <!-- The terms of service are available at <a href="http://www.google.com/coop/docs/cse/tos.html" target="_top">http://www.google.com/coop/docs/cse/tos.html</a> --> <form enctype="multipart/form-data" id="cref_iframe" action="/bin/view/Floss/Search"> <input name="cref" value="http://adam.engagetv.com/cse/floss_fm_anno.xml" type="hidden" /> <input name="cof" value="FORID:11" type="hidden" /> <input name="q" size="28" type="text" /> <input type="hidden" name="selectedzone" value="0"/><input name="sa" value="Search" type="submit"/> <font color="#777777">
+</font> </form> <!-- Google CSE Search Box Ends --> <!-- Google Search Result Snippet Begins -->
+<div id="results_cref">
+</div>
+</div>
+<script type="text/javascript">
+ var googleSearchIframeName = "results_cref";
+ var googleSearchFormName = "searchbox_cref";
+ var googleSearchFrameWidth = 600;
+ var googleSearchFrameborder = 0;
+ var googleSearchDomain = "www.google.com";
+ var googleSearchPath = "/cse";
+</script>
+<script type="text/javascript" src="http://www.google.com/afsonline/show_afs_search.js">
+</script> <!-- Google Search Result Snippet Ends -->
+<br> <br> <br> <br>
+<font color="#777777">Click on any of the free manuals below to read online.
+View <a href="javascript:void(ShowByTitle('lin,linosx,winlin,osx,win,winosx,all'))">All</a>,
+<a href="javascript:void(ShowByTitle('lin,linosx,winlin,all'))"> GNU/Linux</a>,
+<a href="javascript:void(ShowByTitle('win,winosx,winlin,all'))"> Windows</a>,
+<a href="javascript:void(ShowByTitle('osx,winosx,linosx,all'))"> OSX</a></font>
+<br><br>
+<table style="width: 100%;" border="0" cellpadding="1" cellspacing="1"><tbody>
+<tr>
+<td style="width: 33%;" valign="top">
+<h2><a name="AUDIO EDITING"></a><a name="AUDIO EDITING "></a> AUDIO EDITING<span style="text-decoration: underline;"><span style="font-weight: bold;"> </span></span> </h2>
+<h3 id='all'><a href="/ardour/">Ardour</a> (NEW!)</h3>
+<h3 id='all'><a href="/audacity/">Audacity</a></h3>
+</td>
+<td style="width: 33%;" valign="top">
+<h2><a name="Free Software / Open Source"></a> Free Software / Open Source </h2>
+<h3 id='all'><a href="/GSoCMentoringGuide">GSoC MentoringGuide</a> (NEW!)</h3>
+</td>
+<td style="width: 33%;" valign="top">
+<h2><a name="GNU/LINUX"></a> GNU/LINUX </h2>
+<h3 id='all'><a href="/gnulinux">GNU/Linux Commands</a> (also : <a href="http://fi.flossmanuals.net/KomentorivinPerusteet">fi</a>)</h3>
+</td>
+</tr>
+<tr>
+<td style="width: 33%;" valign="top">
+<h2><a name="CRM"></a> CRM </h2>
+<h3 id='all'><a href="/civicrm">CiviCRM</a></h3>
+</td>
+<td style="width: 33%;" valign="top">
+<h2><a name="NET"></a> NET </h2>
+<h3 id='osx'><a href="/CircumventionTools">How to Bypass Internet Censorship</a></h3>
+</td>
+<td style="width: 33%;" valign="top">
+<h2><a name="TRANSLATION"></a> TRANSLATION </h2>
+<h3 id='all'><a href="/opentranslationtools">Open Translation Tools</a> (NEW!)</h3>
+<h3 id='all'><a href="/videotranslation">Video Subtitling</a></h3>
+</td>
+</tr><tr>
+<td style="width: 33%;" valign="top">
+<h2><a name="VIDEO"></a> VIDEO </h2>
+<h3 id ='all'><a href="/theoracookbook">Theora Cookbook</a> (MAJOR UPDATE!)</h3>
+<h3 id='lin'><a href="/kino">Kino</a></h3>
+<h3 id='all'><a href="/avidemux">Avidemux</a></h3>
+<h3 id='lin'><a href="/gtranscode">GTranscode</a></h3>
+<h3 id='lin'><a href="/ffmpeg2theora">ffmpeg2theora</a></h3>
+<h3 id='all'><a href="/handbrake">Handbrake</a></h3>
+</td>
+<td style="width: 33%;" valign="top">
+<h2><a name="FREE NETWORK SERVICES"></a> FREE NETWORK SERVICES </h2>
+<h3 id='all'><a href="/flossmanuals">FLOSS Manuals</a></h3>
+<h3 id='all'><a href="/booksprints">Book Sprints</a></h3>
+<h3 id='all'><a href="/wikimediacommons">Wikimedia Commons</a></h3>
+<h3 id='all'><a href="/archiveorg">Archive.org</a></h3>
+<br><br><br>
+</td>
+<td style="width: 33%;" valign="top">
+<h2><a name="OFFICE"></a> OFFICE </h2>
+<h3 id='all'><a href="/firefox">Firefox</a></h3>
+<h3 id='all'><a href="/openoffice">OpenOffice.org</a></h3>
+</td> </tr><tr>
+<td style="width: 33%;" valign="top">
+<h2><a name="GRAPHIC DESIGN"></a> GRAPHIC DESIGN </h2>
+<h3 id='all'><a href="/DigitalFoundations">Digital Foundations</a> (also : <a href="http://translate.flossmanuals.net/DigitalFoundations_es">es</a>)</h3>
+<h3 id='osx'><a href="/alchemy">Alchemy</a></h3>
+<h3 id='all'><a href="/Inkscape">Inkscape</a></h3>
+</td>
+<td style="width: 33%;" valign="top">
+<h2><a name="3D"></a> 3D </h2>
+<h3 id='all'><a href="/blender">Blender</a></h3>
+</td>
+<td style="width: 33%;" valign="top">
+<h2><a name="ONE LAPTOP PER CHILD SUGAR"></a> ONE LAPTOP PER CHILD &amp; SUGAR </h2>
+<h3 id='all'><a href="/xo">XO</a> (also : <a href="http://translate.flossmanuals.net/xo_el">el</a>)</h3>
+<h3 id='all'><a href="/sugar">Sugar</a> (also : <a href="http://translate.flossmanuals.net/sugar_el">el</a>)</h3>
+<h3 id='all'><a href="/write_activity">Write Activity</a></h3>
+<h3 id='all'><a href="/terminal">Terminal Activity</a></h3>
+<h3 id='all'><a href="/chat">Chat Activity</a></h3>
+<h3 id='all'><a href="/browse">Browse Activity</a></h3>
+<h3 id='all'><a href="/record">Record Activity</a></h3>
+<h3 id='all'><a href="/turtleart">TurtleArt Activity</a></h3>
+</td>
+</tr><tr>
+<td style="width: 33%;" valign="top">
+<h2><a name="HTML EDITING"></a> HTML EDITING </h2>
+<h3 id='lin'><a href="/NvU">NvU</a> </h3>
+</td>
+<td style="width: 33%;" valign="top">
+<h2><a name="BLOGGING"></a> BLOGGING </h2>
+<h3 id='all'><a href="/wordpress">WordPress</a></h3>
+</td>
+<td style="width: 33%;" valign="top">
+<h2><a name="MEDIA PLAYERS"></a> MEDIA PLAYERS </h2>
+<h3 id='all'><a href="/mplayer">MPlayer</a></h3>
+<h3 id='all'><a href="/vlc">VLC</a></h3>
+<h3 id='all'><a href="/miro">Miro</a></h3>
+</td>
+</tr><tr>
+<td style="width: 33%;" valign="top">
+<h2><a name="VOIP"></a> VOIP </h2>
+<h3 id='lin'><a href="/linphone">Linphone</a></h3>
+</td>
+<td style="width: 33%;" valign="top">
+<h2><a name="FILE SHARING"></a> FILE SHARING </h2>
+<h3 id='all'><a href="/azureus">Azureus</a></h3>
+</td>
+<td style="width: 33%;" valign="top">
+<h2><a name="STREAMING"></a> STREAMING </h2>
+<h3 id='linosx'><a href="/muse">MuSE</a></h3>
+<h3 id='win'><a href="/m3w">M3W</a></h3>
+<h3 id='winlin'><a href="/icecast">Icecast</a></h3>
+</td>
+</tr><tr>
+<td style="width: 33%;" valign="top">
+<h2><a name="VIDEO SUBTITLING"></a> VIDEO SUBTITLING </h2>
+<h3 id='all'><a href="/jubler">Jubler</a></h3>
+</td>
+</tr>
+<tr><td>
+<br><br><br>
+</td></tr>
+</tbody>
+</table>
+<Br><br>
+<p />
+<br><br>If you wish to keep up to date with the latest releases and news from us then you can read our <a href='/news'>news</a> (also available as a <a href='rss'>news feed</a>), or join our <a href='http://lists.flossmanuals.net/listinfo.cgi/discuss-flossmanuals.net'>discussion list</a>. <br><br>
+<div style="position:absolute;top:10px;left:700px;background-color:white;border:2px solid #666;padding:5px">
+<img src="http://en.flossmanuals.net/bookstore/bookstore.gif"/>
+<style>
+ @import url("http://en.flossmanuals.net/bookstore/bookstore.css");
+</style>
+ <script src="http://en.flossmanuals.net/bookstore/bookstore.js" type="text/javascript"></script>
+ <script type="text/javascript">
+ FM.init({"show":"random","items":10,"next_desc": "MORE &gt;&gt;", "prev_desc": "&lt;&lt; BACK", "paging": true});
+ </script>
+</div>
+ </div>
+ </div>
+ </td>
+ </tr>
+ </table>
+ </div>
+<!-- Piwik -->
+<a href="http://piwik.org" title="Web analytics" onclick="window.open(this.href);return(false);">
+<script language="javascript" src="http://adam.engagetv.com/piwik/piwik.js" type="text/javascript"></script>
+<script type="text/javascript">
+<!--
+piwik_action_name = '';
+piwik_idsite = 1;
+piwik_url = 'http://adam.engagetv.com/piwik/piwik.php';
+piwik_log(piwik_action_name, piwik_idsite, piwik_url);
+//-->
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/help/ActivityBook/library/library.info b/help/ActivityBook/library/library.info
new file mode 100644
index 0000000..aaec6c1
--- /dev/null
+++ b/help/ActivityBook/library/library.info
@@ -0,0 +1,9 @@
+[Library]
+name = ActivityBook
+global_name = ActivityBook
+long_name = ActivityBook
+category = media
+library_version = 1
+host_version = 1
+l10n = false
+locale = en
diff --git a/help/ActivityBook/robots.txt b/help/ActivityBook/robots.txt
new file mode 100644
index 0000000..2e43490
--- /dev/null
+++ b/help/ActivityBook/robots.txt
@@ -0,0 +1,35 @@
+User-agent: *
+Disallow: /bin/*
+Disallow: /bin/view
+Disallow: /bin/view/TWiki/
+Disallow: /bin/view/Main/
+Disallow: /bin/view/Sandbox/
+Disallow: /bin/genpdf
+Disallow: /bin/attach
+Disallow: /bin/changes
+Disallow: /bin/edit
+Disallow: /bin/geturl
+Disallow: /bin/installpasswd
+Disallow: /bin/mailnotify
+Disallow: /bin/manage
+Disallow: /bin/oops
+Disallow: /bin/passwd
+Disallow: /bin/preview
+Disallow: /bin/rdiff
+Disallow: /bin/rdiffauth
+Disallow: /bin/register
+Disallow: /bin/rename
+Disallow: /bin/save
+Disallow: /bin/savemulti
+Disallow: /bin/search
+Disallow: /bin/setlib.cfg
+Disallow: /bin/statistics
+Disallow: /bin/testenv
+Disallow: /bin/configure
+Disallow: /bin/upload
+Disallow: /bin/viewauth
+Disallow: /bin/viewfile
+Disallow: /list/
+Disallow: pub/Main/LarryLaffer/swingers.html
+Disallow: /floss/pub/Main/LarryLaffer/swingers.html
+Disallow: /pub/Main/LarryLaffer/swingers.html
diff --git a/help/BeginnerPython/library/library.info b/help/BeginnerPython/library/library.info
new file mode 100644
index 0000000..ecc7dbb
--- /dev/null
+++ b/help/BeginnerPython/library/library.info
@@ -0,0 +1,9 @@
+[Library]
+name = BeginnerPython
+global_name = BeginnerPython
+long_name = BeginnerPython
+category = media
+library_version = 1
+host_version = 1
+l10n = false
+locale = en
diff --git a/help/BeginnerPython/robots.txt b/help/BeginnerPython/robots.txt
new file mode 100644
index 0000000..fc4d02b
--- /dev/null
+++ b/help/BeginnerPython/robots.txt
@@ -0,0 +1,33 @@
+# Robots file listing html directories NOT to search on www.ibiblio.org
+
+User-agent: *
+Crawl-delay: 2
+Disallow: /dbarberi/wiki/
+Disallow: /designerunits/images/
+Disallow: /designerunits/image*/
+Disallow: /footy/tools/
+Disallow: /herbmed/getit.php
+Disallow: /mcmahon/emusic-l/
+Disallow: /ncdarts/bcdl/search/
+Disallow: /rtpnet/archives/
+Disallow: /schools/fpg/
+Disallow: /ser/cvs/
+
+User-agent: ia_archiver
+Disallow: /fred/
+Disallow: /herbmed/
+Disallow: /swsbm/
+Disallow: /designerunits/
+
+User-agent: Googlebot-Image
+Disallow: /designerunits/
+
+User-agent: Googlebot-News
+Disallow: /designerunits/
+
+User-agent: Mediapartners-Google
+Disallow: /designerunits/
+
+User-agent: psbot
+Disallow: /designerunits/
+
diff --git a/help/CSS/Accessible_Design.css b/help/CSS/Accessible_Design.css
new file mode 100644
index 0000000..315a5df
--- /dev/null
+++ b/help/CSS/Accessible_Design.css
@@ -0,0 +1,119 @@
+a {
+ color: #3366CC;
+ text-decoration: none
+}
+body {
+ background-color: #DCDCDC;
+ font-family: Arial, Helvetica, sans-serif;
+ font-size: 1em;
+ line-height: 1.5em;
+ color: #336699;
+ margin-top: 0.1em;
+ margin-right: 0.1em;
+ margin-bottom: 0.1em;
+ margin-left: 0.1em
+ }
+h2 {
+ color: #CCCCCC
+ }
+h3 {
+ font-family: Arial, Helvetica, sans-serif;
+ font-size: 1.15em;
+ background-color: #006666;
+ color: #DCDCDC
+ }
+h4 {
+ color: #000000
+ }
+table {
+ color: #FFFFFF
+ }
+td, th {
+ font-family: Arial, Helvetica, sans-serif;
+ font-size: 1em;
+ line-height: 2em;
+ color: #333333
+ }
+textarea {
+ font-family: Arial, Helvetica, sans-serif;
+ font-size: 1em
+ }
+ul {
+ font-family: Arial, Helvetica, sans-serif;
+ font-size: 1em;
+ list-style-type: square;
+ list-style-position: outside
+ }
+.BulletBackgroundColor {
+ color: #FFFFFF
+ }
+.DataColor {
+ color: #DEDECA
+ }
+.footer {
+ font-family: Arial, Helvetica, sans-serif;
+ font-size: 1.167em;
+ font-weight: bold;
+ line-height: 1.83em;
+ color: #333333;
+ background-color: #CCCCCC
+ }
+.FormBackgroundColor {
+ color: #CCCCCC
+ }
+.ImageTitleColor {
+ color: #CCCCCC
+ }
+.LabelColor {
+ color: #CCCCCC
+ }
+.ListColorEven {
+ color: #CCCCCC
+ }
+.ListFooterColor {
+ color: #333333
+ }
+.ListHeaderColor {
+ color: #333333
+ }
+.ListColorOdd {
+ color: #DEDECA
+ }
+.ListTitleColor {
+ color: #CCCCCC
+ }
+.NavigationBackgroundColor {
+ color: #666666
+ }
+.NavigationColor {
+ color: #CCCCCC
+ }
+.NewsDataColor {
+ color: #DEDECA
+ }
+.StoryTitle {
+ color: #000000;
+ font-weight: bold
+ }
+.StoryContentColor {
+ color: #000000
+ }
+.TitleColor {
+ color: #000000
+ }
+a:hover {
+ text-decoration: underline
+ }
+tr.ListHeaderColor th {
+ text-align: left;
+ }.small {
+ font-size: 85%;
+}
+img.right {
+float:right;
+margin:5px;
+}
+img.left {
+float:left;
+margin:10px;
+}
diff --git a/help/PyDebug.htm b/help/PyDebug.htm
new file mode 100644
index 0000000..c091d42
--- /dev/null
+++ b/help/PyDebug.htm
@@ -0,0 +1,32 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<title>Untitled Document</title>
+<link href="CSS/Accessible_Design.css" rel="stylesheet" type="text/css" />
+</head>
+
+<body>
+ <h3>PyDebug Help system</h3>
+<img class="right" src="images/3080617962_604fcfe2ed.jpg" width="271" height="202" align="top" /> <p><a href="application.html">Introduction to the Debgger Pages, features</a></p>
+ <p> How to use the Debugger -- set breakpoints, step, examine variables</p>
+ <p>Making Sugar Activities by Jim Simmons </p>
+ <p>Learning Python</p>
+ <ul>
+ <li><a href="byteofpython/read/index.html">Python for Beginners </a></li>
+ <li><a href="diveintopython-5.4/html/toc/index.html">Introduction to Python</a><a href="PythonTutorial/tutorial/index.html"></a> for people who have some experience with programming(&quot;Dive Into Python&quot;) </li>
+ <li><a href="PythonTutorial/tutorial/index.html">Python Tutorial</a> from the official python.org web site </li>
+ </ul>
+ <p><a href="PythonExamples/index.html">Learning to control the Graphics</a></p>
+ <ul>
+ <li><a href="PythonExamples/index.html">Python and GTK (Gnome tool Kit Examples)</a></li>
+ <li><a href="Pygtk2Tutorial/pygtk2tutorial/index.html">Pygtk2Tutorial</a><a href="Pygtk2Tutorial/pygtk2tutorial/index.html"></a></li>
+ </ul>
+ <p>Sugar Activites are written in python. Study the example programs for help in applying the programming language to the XO laptop. Follow the links on this page for an introduction to the programming language, the python interface to the GTK (Gnome Tool Kit) graphical utilities. </p>
+
+ <h1>&nbsp;</h1>
+ <p>&nbsp;</p>
+ <p>&nbsp;</p>
+ <p>&nbsp;</p>
+</body>
+</html>
diff --git a/help/Pygtk2Tutorial/library/library.info b/help/Pygtk2Tutorial/library/library.info
new file mode 100644
index 0000000..9e261a2
--- /dev/null
+++ b/help/Pygtk2Tutorial/library/library.info
@@ -0,0 +1,9 @@
+[Library]
+name = Pygtk2Tutorial
+global_name = Pygtk2Tutorial
+long_name = Pygtk2Tutorial
+category = media
+library_version = 1
+host_version = 1
+l10n = false
+locale = en
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/app-CodeExamples.html b/help/Pygtk2Tutorial/pygtk2tutorial/app-CodeExamples.html
new file mode 100644
index 0000000..f78bd0b
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/app-CodeExamples.html
@@ -0,0 +1,120 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>Appendix B. Code Examples</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="previous" href="sec-GtkAdjustment.html" title="A.22. GtkAdjustment"><link rel="next" href="pygtk-tut-changelog.html" title="Appendix C. ChangeLog"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Appendix B. Code Examples</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-GtkAdjustment.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="pygtk-tut-changelog.html">Next</a></td></tr></table><hr></div><div class="appendix" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="app-CodeExamples"></a>Appendix B. Code Examples</h2></div></div><div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="app-CodeExamples.html#sec-scribblesimple.py">B.1. scribblesimple.py</a></span></dt></dl></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-scribblesimple.py"></a>B.1. scribblesimple.py</h2></div></div><div></div></div><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 1 #!/usr/bin/env python
+ 2
+ 3 # example scribblesimple.py
+ 4
+ 5 # GTK - The GIMP Toolkit
+ 6 # Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ 7 # Copyright (C) 2001-2002 John Finlay
+ 8 #
+ 9 # This library is free software; you can redistribute it and/or
+ 10 # modify it under the terms of the GNU Library General Public
+ 11 # License as published by the Free Software Foundation; either
+ 12 # version 2 of the License, or (at your option) any later version.
+ 13 #
+ 14 # This library is distributed in the hope that it will be useful,
+ 15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
+ 16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ 17 # Library General Public License for more details.
+ 18 #
+ 19 # You should have received a copy of the GNU Library General Public
+ 20 # License along with this library; if not, write to the
+ 21 # Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ 22 # Boston, MA 02111-1307, USA.
+ 23
+ 24
+ 25 import gtk
+ 26
+ 27 # Backing pixmap for drawing area
+ 28 pixmap = None
+ 29
+ 30 # Create a new backing pixmap of the appropriate size
+ 31 def configure_event(widget, event):
+ 32 global pixmap
+ 33
+ 34 x, y, width, height = widget.get_allocation()
+ 35 pixmap = gtk.gdk.Pixmap(widget.window, width, height)
+ 36 pixmap.draw_rectangle(widget.get_style().white_gc,
+ 37 True, 0, 0, width, height)
+ 38
+ 39 return True
+ 40
+ 41 # Redraw the screen from the backing pixmap
+ 42 def expose_event(widget, event):
+ 43 x , y, width, height = event.area
+ 44 widget.window.draw_drawable(widget.get_style().fg_gc[gtk.STATE_NORMAL],
+ 45 pixmap, x, y, x, y, width, height)
+ 46 return False
+ 47
+ 48 # Draw a rectangle on the screen
+ 49 def draw_brush(widget, x, y):
+ 50 rect = (x - 5, y - 5, 10, 10)
+ 51 pixmap.draw_rectangle(widget.get_style().black_gc, True,
+ 52 rect[0], rect[1], rect[2], rect[3])
+ 53 widget.queue_draw_area(rect[0], rect[1], rect[2], rect[3])
+ 54
+ 55 def button_press_event(widget, event):
+ 56 if event.button == 1 and pixmap != None:
+ 57 draw_brush(widget, event.x, event.y)
+ 58 return True
+ 59
+ 60 def motion_notify_event(widget, event):
+ 61 if event.is_hint:
+ 62 x, y, state = event.window.get_pointer()
+ 63 else:
+ 64 x = event.x
+ 65 y = event.y
+ 66 state = event.state
+ 67
+ 68 if state &amp; gtk.gdk.BUTTON1_MASK and pixmap != None:
+ 69 draw_brush(widget, x, y)
+ 70
+ 71 return True
+ 72
+ 73 def main():
+ 74 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ 75 window.set_name ("Test Input")
+ 76
+ 77 vbox = gtk.VBox(False, 0)
+ 78 window.add(vbox)
+ 79 vbox.show()
+ 80
+ 81 window.connect("destroy", gtk.mainquit)
+ 82
+ 83 # Create the drawing area
+ 84 drawing_area = gtk.DrawingArea()
+ 85 drawing_area.set_size_request(200, 200)
+ 86 vbox.pack_start(drawing_area, True, True, 0)
+ 87
+ 88 drawing_area.show()
+ 89
+ 90 # Signals used to handle backing pixmap
+ 91 drawing_area.connect("expose_event", expose_event)
+ 92 drawing_area.connect("configure_event", configure_event)
+ 93
+ 94 # Event signals
+ 95 drawing_area.connect("motion_notify_event", motion_notify_event)
+ 96 drawing_area.connect("button_press_event", button_press_event)
+ 97
+ 98 drawing_area.set_events(gtk.gdk.EXPOSURE_MASK
+ 99 | gtk.gdk.LEAVE_NOTIFY_MASK
+ 100 | gtk.gdk.BUTTON_PRESS_MASK
+ 101 | gtk.gdk.POINTER_MOTION_MASK
+ 102 | gtk.gdk.POINTER_MOTION_HINT_MASK)
+ 103
+ 104 # .. And a quit button
+ 105 button = gtk.Button("Quit")
+ 106 vbox.pack_start(button, False, False, 0)
+ 107
+ 108 button.connect_object("clicked", lambda w: w.destroy(), window)
+ 109 button.show()
+ 110
+ 111 window.show()
+ 112
+ 113 gtk.main()
+ 114
+ 115 return 0
+ 116
+ 117 if __name__ == "__main__":
+ 118 main()
+</pre></td></tr></table></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-GtkAdjustment.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="index.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="pygtk-tut-changelog.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">A.22. GtkAdjustment </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Appendix C. ChangeLog</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/app-GtkSignals.html b/help/Pygtk2Tutorial/pygtk2tutorial/app-GtkSignals.html
new file mode 100644
index 0000000..d91e76d
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/app-GtkSignals.html
@@ -0,0 +1,6 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>Appendix A. GTK Signals</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="previous" href="ch-Copyright.html" title="Chapter 28. Tutorial Copyright and Permissions Notice"><link rel="next" href="sec-GtkWidget.html" title="A.2. GtkWidget"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Appendix A. GTK Signals</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch-Copyright.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="sec-GtkWidget.html">Next</a></td></tr></table><hr></div><div class="appendix" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="app-GtkSignals"></a>Appendix A. GTK Signals</h2></div></div><div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="app-GtkSignals.html#sec-GtkObject">A.1. GtkObject</a></span></dt><dt><span class="sect1"><a href="sec-GtkWidget.html">A.2. GtkWidget</a></span></dt><dt><span class="sect1"><a href="sec-GtkData.html">A.3. GtkData</a></span></dt><dt><span class="sect1"><a href="sec-GtkContainer.html">A.4. GtkContainer</a></span></dt><dt><span class="sect1"><a href="sec-GtkCalendar.html">A.5. GtkCalendar</a></span></dt><dt><span class="sect1"><a href="sec-GtkEditable.html">A.6. GtkEditable</a></span></dt><dt><span class="sect1"><a href="sec-GtkNotebook.html">A.7. GtkNotebook</a></span></dt><dt><span class="sect1"><a href="sec-GtkList.html">A.8. GtkList</a></span></dt><dt><span class="sect1"><a href="sec-GtkMenuShell.html">A.9. GtkMenuShell</a></span></dt><dt><span class="sect1"><a href="sec-GtkToolbar.html">A.10. GtkToolbar</a></span></dt><dt><span class="sect1"><a href="sec-GtkButton.html">A.11. GtkButton</a></span></dt><dt><span class="sect1"><a href="sec-GtkItem.html">A.12. GtkItem</a></span></dt><dt><span class="sect1"><a href="sec-GtkWindow.html">A.13. GtkWindow</a></span></dt><dt><span class="sect1"><a href="sec-GtkHandleBox.html">A.14. GtkHandleBox</a></span></dt><dt><span class="sect1"><a href="sec-GtkToggleButton.html">A.15. GtkToggleButton</a></span></dt><dt><span class="sect1"><a href="sec-GtkMenuItem.html">A.16. GtkMenuItem</a></span></dt><dt><span class="sect1"><a href="sec-GtkCheckMenuItem.html">A.17. GtkCheckMenuItem</a></span></dt><dt><span class="sect1"><a href="sec-GtkInputDialog.html">A.18. GtkInputDialog</a></span></dt><dt><span class="sect1"><a href="sec-GtkColorSelection.html">A.19. GtkColorSelection</a></span></dt><dt><span class="sect1"><a href="sec-GtkStatusBar.html">A.20. GtkStatusBar</a></span></dt><dt><span class="sect1"><a href="sec-GtkCurve.html">A.21. GtkCurve</a></span></dt><dt><span class="sect1"><a href="sec-GtkAdjustment.html">A.22. GtkAdjustment</a></span></dt></dl></div><p>As PyGTK is an object oriented widget set, it has a hierarchy of
+inheritance. This inheritance mechanism applies for signals. Therefore, you
+should refer to the widget hierarchy tree when using the signals listed in
+this section.</p><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-GtkObject"></a>A.1. GtkObject</h2></div></div><div></div></div><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ destroy(object, data)
+</pre></td></tr></table></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch-Copyright.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="index.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-GtkWidget.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 28. Tutorial Copyright and Permissions Notice </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> A.2. GtkWidget</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/ch-Adjustments.html b/help/Pygtk2Tutorial/pygtk2tutorial/ch-Adjustments.html
new file mode 100644
index 0000000..46d2c5b
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/ch-Adjustments.html
@@ -0,0 +1,46 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>Chapter 7. Adjustments</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="previous" href="sec-RadioButtons.html" title="6.4. Radio Buttons"><link rel="next" href="sec-UsingAdjustmentsTheEasyWay.html" title="7.2. Using Adjustments the Easy Way"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 7. Adjustments</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-RadioButtons.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="sec-UsingAdjustmentsTheEasyWay.html">Next</a></td></tr></table><hr></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="ch-Adjustments"></a>Chapter 7. Adjustments</h2></div></div><div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="ch-Adjustments.html#sec-CreatingAnAdjustment">7.1. Creating an Adjustment</a></span></dt><dt><span class="sect1"><a href="sec-UsingAdjustmentsTheEasyWay.html">7.2. Using Adjustments the Easy Way</a></span></dt><dt><span class="sect1"><a href="sec-AdjustmentInternals.html">7.3. Adjustment Internals</a></span></dt></dl></div><p>GTK has various widgets that can be visually adjusted by the user
+using the mouse or the keyboard, such as the range widgets, described in the
+Range Widgets section. There are also a few widgets that display some
+adjustable portion of a larger area of data, such as the text widget and the
+viewport widget.</p><p>Obviously, an application needs to be able to react to changes the
+user makes in range widgets. One way to do this would be to have each widget
+emit its own type of signal when its adjustment changes, and either pass the
+new value to the signal handler, or require it to look inside the widget's
+data structure in order to ascertain the value. But you may also want to
+connect the adjustments of several widgets together, so that adjusting one
+adjusts the others. The most obvious example of this is connecting a
+scrollbar to a panning viewport or a scrolling text area. If each widget has
+its own way of setting or getting the adjustment value, then the programmer
+may have to write their own signal handlers to translate between the output
+of one widget's signal and the "input" of another's adjustment setting
+method.</p><p>GTK solves this problem using the
+<tt class="classname">Adjustment</tt> object, which is not a widget but a way
+for widgets to store and pass adjustment information in an abstract and
+flexible form. The most obvious use of <tt class="classname">Adjustment</tt> is
+to store the configuration parameters and values of range widgets, such as
+scrollbars and scale controls. However, since
+<tt class="classname">Adjustment</tt>s are derived from
+<tt class="classname">Object</tt>, they have some special powers beyond those of
+normal data structures. Most importantly, they can emit signals, just like
+widgets, and these signals can be used not only to allow your program to
+react to user input on adjustable widgets, but also to propagate adjustment
+values transparently between adjustable widgets.</p><p>You will see how adjustments fit in when you see the other widgets
+that incorporate them: Progress Bars, Viewports, Scrolled Windows, and
+others.</p><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-CreatingAnAdjustment"></a>7.1. Creating an Adjustment</h2></div></div><div></div></div><p>Many of the widgets which use adjustment objects do so
+automatically, but some cases will be shown in later examples where you may
+need to create one yourself. You create an adjustment using:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ adjustment = gtk.Adjustment(<b class="parameter"><tt>value</tt></b>=0, <b class="parameter"><tt>lower</tt></b>=0, <b class="parameter"><tt>upper</tt></b>=0, <b class="parameter"><tt>step_incr</tt></b>=0, <b class="parameter"><tt>page_incr</tt></b>=0, <b class="parameter"><tt>page_size</tt></b>=0)
+</pre></td></tr></table><p>The <i class="parameter"><tt>value</tt></i> argument is the initial value
+you want to give to the <i class="parameter"><tt>adjustment</tt></i>, usually
+corresponding to the topmost or leftmost position of an adjustable
+widget. The <i class="parameter"><tt>lower</tt></i> argument specifies the lowest value
+which the <i class="parameter"><tt>adjustment</tt></i> can hold. The
+<i class="parameter"><tt>step_incr</tt></i> argument specifies the "smaller" of the two
+increments by which the user can change the value, while the
+<i class="parameter"><tt>page_incr</tt></i> is the "larger" one. The
+<i class="parameter"><tt>page_size</tt></i> argument usually corresponds somehow to the
+visible area of a panning widget. The <i class="parameter"><tt>upper</tt></i> argument
+is used to represent the bottom most or right most coordinate in a panning
+widget's child. Therefore it is not always the largest number that
+<i class="parameter"><tt>value</tt></i> can take, since the
+<i class="parameter"><tt>page_size</tt></i> of such widgets is usually non-zero.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-RadioButtons.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="index.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-UsingAdjustmentsTheEasyWay.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">6.4. Radio Buttons </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 7.2. Using Adjustments the Easy Way</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/ch-AdvancedEventAndSignalHandling.html b/help/Pygtk2Tutorial/pygtk2tutorial/ch-AdvancedEventAndSignalHandling.html
new file mode 100644
index 0000000..7fb05f6
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/ch-AdvancedEventAndSignalHandling.html
@@ -0,0 +1,57 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>Chapter 20. Advanced Event and Signal Handling</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="previous" href="sec-IdleFunctions.html" title="19.3. Idle Functions"><link rel="next" href="sec-SignalEmissionAndPropagation.html" title="20.2. Signal Emission and Propagation"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 20. Advanced Event and Signal Handling</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-IdleFunctions.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="sec-SignalEmissionAndPropagation.html">Next</a></td></tr></table><hr></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="ch-AdvancedEventAndSignalHandling"></a>Chapter 20. Advanced Event and Signal Handling</h2></div></div><div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="ch-AdvancedEventAndSignalHandling.html#sec-SignalMethods">20.1. Signal Methods</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch-AdvancedEventAndSignalHandling.html#id2837542">20.1.1. Connecting and Disconnecting Signal Handlers</a></span></dt><dt><span class="sect2"><a href="ch-AdvancedEventAndSignalHandling.html#id2871063">20.1.2. Blocking and Unblocking Signal Handlers</a></span></dt><dt><span class="sect2"><a href="ch-AdvancedEventAndSignalHandling.html#id2810158">20.1.3. Emitting and Stopping Signals</a></span></dt></dl></dd><dt><span class="sect1"><a href="sec-SignalEmissionAndPropagation.html">20.2. Signal Emission and Propagation</a></span></dt></dl></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-SignalMethods"></a>20.1. Signal Methods</h2></div></div><div></div></div><p> The signal methods are <tt class="classname">gobject.GObject</tt>
+methods that are inherited by the <tt class="classname">gtk.Object</tt>s
+including all the GTK+ widgets.</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2837542"></a>20.1.1. Connecting and Disconnecting Signal Handlers</h3></div></div><div></div></div><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ handler_id = object.connect(<i class="parameter"><tt>name</tt></i>, <i class="parameter"><tt>cb</tt></i>, <i class="parameter"><tt>cb_args</tt></i>)
+
+ handler_id = object.connect_after(<i class="parameter"><tt>name</tt></i>, <i class="parameter"><tt>cb</tt></i>, <i class="parameter"><tt>cb_args</tt></i>)
+
+ handler_id = object.connect_object(<i class="parameter"><tt>name</tt></i>, <i class="parameter"><tt>cb</tt></i>, <i class="parameter"><tt>slot_object</tt></i>, <i class="parameter"><tt>cb_args</tt></i>)
+
+ handler_id = object.connect_object_after(<i class="parameter"><tt>name</tt></i>, <i class="parameter"><tt>cb</tt></i>, <i class="parameter"><tt>slot_object</tt></i>, <i class="parameter"><tt>cb_args</tt></i>)
+
+ object.disconnect(<i class="parameter"><tt>handler_id</tt></i>)
+</pre></td></tr></table><p>The first four methods connect a signal handler
+(<i class="parameter"><tt>cb</tt></i>) to a <tt class="classname">gtk.Object</tt>
+(<i class="parameter"><tt>object</tt></i>) for the given signal name. and return a
+<i class="parameter"><tt>handler_id</tt></i> that identifies the connection.
+<i class="parameter"><tt>cb_args</tt></i> is zero or more arguments that will be passed
+last (in order) to <i class="parameter"><tt>cb</tt></i>. The
+<tt class="methodname">connect_after</tt>() and
+<tt class="methodname">connect_object_after</tt>() methods will have their
+signal handlers called after other signal handlers (including the default
+handlers) connected to the same object and signal name. Each object signal
+handler has its own set of arguments that it expects. You have to refer to
+the GTK+ documentation to figure out what arguments need to be handled by a
+signal handler though information for the common widgets is available in
+<a href="app-GtkSignals.html" title="Appendix A. GTK Signals">Appendix A, <i>GTK Signals</i></a>. The general signal handler is
+similar to:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def signal_handler(<i class="parameter"><tt>object</tt></i>, ...., <i class="parameter"><tt>cb_args</tt></i>):
+</pre></td></tr></table><p>Signal handlers that are defined as part of a Python object
+class (specified in the <tt class="methodname">connect</tt>() methods as
+<i class="parameter"><tt>self.cb</tt></i>) will have an additional argument passed as
+the first argument - the object instance <i class="parameter"><tt>self</tt></i>:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ signal_handler(self, <i class="parameter"><tt>object</tt></i>, ...., <i class="parameter"><tt>cb_args</tt></i>)
+</pre></td></tr></table><p>The <tt class="methodname">connect_object</tt>() and
+<tt class="methodname">connect_object_after</tt>() methods call the signal
+handler with the <i class="parameter"><tt>slot_object</tt></i> substituted in place of
+the <i class="parameter"><tt>object</tt></i> as the first argument:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def signal_handler(<i class="parameter"><tt>slot_object</tt></i>, ...., <b class="parameter"><tt>func_args</tt></b>):
+
+ def signal_handler(self, <i class="parameter"><tt>slot_object</tt></i>, ...., <i class="parameter"><tt>func_args</tt></i>):
+</pre></td></tr></table><p>The <tt class="methodname">disconnect</tt>() method destroys the
+connection between a signal handler and an object signal. The
+<i class="parameter"><tt>handler_id</tt></i> specifies which connection to
+destroy.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2871063"></a>20.1.2. Blocking and Unblocking Signal Handlers</h3></div></div><div></div></div><p>The following methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ object.handler_block(<i class="parameter"><tt>handler_id</tt></i>)
+
+ object.handler_unblock(<i class="parameter"><tt>handler_id</tt></i>)
+</pre></td></tr></table><p>block and unblock the signal handler specified by
+<i class="parameter"><tt>handler_id</tt></i>. When a signal handler is blocked it will
+not be invoked when the signal occurs.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2810158"></a>20.1.3. Emitting and Stopping Signals</h3></div></div><div></div></div><p>The following methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ object.emit(<i class="parameter"><tt>name</tt></i>, ...)
+
+ object.emit_stop_by_name(<i class="parameter"><tt>name</tt></i>)
+</pre></td></tr></table><p>emit and stop the signal <i class="parameter"><tt>name</tt></i>
+respectively. Emitting the signal causes its default and user defined
+handlers to be run. The <tt class="methodname">emit_stop_by_name</tt>() method
+will abort the current signal name emission.</p></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-IdleFunctions.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="index.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-SignalEmissionAndPropagation.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">19.3. Idle Functions </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 20.2. Signal Emission and Propagation</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/ch-ButtonWidget.html b/help/Pygtk2Tutorial/pygtk2tutorial/ch-ButtonWidget.html
new file mode 100644
index 0000000..1c98538
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/ch-ButtonWidget.html
@@ -0,0 +1,186 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>Chapter 6. The Button Widget</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="previous" href="sec-WidgetsWithoutWindows.html" title="5.2. Widgets Without Windows"><link rel="next" href="sec-ToggleButtons.html" title="6.2. Toggle Buttons"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 6. The Button Widget</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-WidgetsWithoutWindows.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="sec-ToggleButtons.html">Next</a></td></tr></table><hr></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="ch-ButtonWidget"></a>Chapter 6. The Button Widget</h2></div></div><div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="ch-ButtonWidget.html#sec-NormalButtons">6.1. Normal Buttons</a></span></dt><dt><span class="sect1"><a href="sec-ToggleButtons.html">6.2. Toggle Buttons</a></span></dt><dt><span class="sect1"><a href="sec-CheckButtons.html">6.3. Check Buttons</a></span></dt><dt><span class="sect1"><a href="sec-RadioButtons.html">6.4. Radio Buttons</a></span></dt></dl></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-NormalButtons"></a>6.1. Normal Buttons</h2></div></div><div></div></div><p>We've almost seen all there is to see of the button widget. It's
+pretty simple. You can use the <tt class="function">gtk.Button</tt>() function to
+create a button with a label by passing a string parameter, or to create a
+blank button by not specifying a label string. It's then up to you to pack a
+label or pixmap into this new button. To do this, create a new box, and then
+pack your objects into this box using the usual
+<tt class="methodname">pack_start</tt>() method, and then use the
+<tt class="methodname">add</tt>() method to pack the box into the
+button.</p><p>The function to create a button is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ button = <tt class="classname">gtk.Button</tt>(<b class="parameter"><tt>label</tt></b>=None, <b class="parameter"><tt>stock</tt></b>=None)
+</pre></td></tr></table><p>if label text is specified it is used as the text on the button.
+If stock is specified it is used to select a stock icon and text label for
+the button. The stock items are:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ STOCK_DIALOG_INFO
+ STOCK_DIALOG_WARNING
+ STOCK_DIALOG_ERROR
+ STOCK_DIALOG_QUESTION
+ STOCK_DND
+ STOCK_DND_MULTIPLE
+ STOCK_ADD
+ STOCK_APPLY
+ STOCK_BOLD
+ STOCK_CANCEL
+ STOCK_CDROM
+ STOCK_CLEAR
+ STOCK_CLOSE
+ STOCK_CONVERT
+ STOCK_COPY
+ STOCK_CUT
+ STOCK_DELETE
+ STOCK_EXECUTE
+ STOCK_FIND
+ STOCK_FIND_AND_REPLACE
+ STOCK_FLOPPY
+ STOCK_GOTO_BOTTOM
+ STOCK_GOTO_FIRST
+ STOCK_GOTO_LAST
+ STOCK_GOTO_TOP
+ STOCK_GO_BACK
+ STOCK_GO_DOWN
+ STOCK_GO_FORWARD
+ STOCK_GO_UP
+ STOCK_HELP
+ STOCK_HOME
+ STOCK_INDEX
+ STOCK_ITALIC
+ STOCK_JUMP_TO
+ STOCK_JUSTIFY_CENTER
+ STOCK_JUSTIFY_FILL
+ STOCK_JUSTIFY_LEFT
+ STOCK_JUSTIFY_RIGHT
+ STOCK_MISSING_IMAGE
+ STOCK_NEW
+ STOCK_NO
+ STOCK_OK
+ STOCK_OPEN
+ STOCK_PASTE
+ STOCK_PREFERENCES
+ STOCK_PRINT
+ STOCK_PRINT_PREVIEW
+ STOCK_PROPERTIES
+ STOCK_QUIT
+ STOCK_REDO
+ STOCK_REFRESH
+ STOCK_REMOVE
+ STOCK_REVERT_TO_SAVED
+ STOCK_SAVE
+ STOCK_SAVE_AS
+ STOCK_SELECT_COLOR
+ STOCK_SELECT_FONT
+ STOCK_SORT_ASCENDING
+ STOCK_SORT_DESCENDING
+ STOCK_SPELL_CHECK
+ STOCK_STOP
+ STOCK_STRIKETHROUGH
+ STOCK_UNDELETE
+ STOCK_UNDERLINE
+ STOCK_UNDO
+ STOCK_YES
+ STOCK_ZOOM_100
+ STOCK_ZOOM_FIT
+ STOCK_ZOOM_IN
+ STOCK_ZOOM_OUT
+</pre></td></tr></table><p>The <a href="examples/buttons.py" target="_top"><span><b class="command">buttons.py</b></span></a> program
+provides an example of using <tt class="function">gtk.Button</tt>() to create a
+button with an image and a label in it. I've broken up the code to create a
+box from the rest so you can use it in your programs. There are further
+examples of using images later in the tutorial. <a href="ch-ButtonWidget.html#buttonfig" title="Figure 6.1. Button with Pixmap and Label">Figure 6.1, “Button with Pixmap and Labelâ€</a>
+shows the window containing a button with both a pixmap and a label:</p><div class="figure"><a name="buttonfig"></a><p class="title"><b>Figure 6.1. Button with Pixmap and Label</b></p><div class="mediaobject" align="center"><img src="figures/button.png" align="middle" alt="Button with Pixmap and Label"></div></div><p>The source code for the <a href="examples/buttons.py" target="_top"><span><b class="command">buttons.py</b></span></a> program
+is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 1 #!/usr/bin/env python
+ 2
+ 3 # example-start buttons buttons.py
+ 4
+ 5 import pygtk
+ 6 pygtk.require('2.0')
+ 7 import gtk
+ 8
+ 9 # Create a new hbox with an image and a label packed into it
+ 10 # and return the box.
+ 11
+ 12 def xpm_label_box(parent, xpm_filename, label_text):
+ 13 # Create box for xpm and label
+ 14 box1 = gtk.HBox(False, 0)
+ 15 box1.set_border_width(2)
+ 16
+ 17 # Now on to the image stuff
+ 18 image = gtk.Image()
+ 19 image.set_from_file(xpm_filename)
+ 20
+ 21 # Create a label for the button
+ 22 label = gtk.Label(label_text)
+ 23
+ 24 # Pack the pixmap and label into the box
+ 25 box1.pack_start(image, False, False, 3)
+ 26 box1.pack_start(label, False, False, 3)
+ 27
+ 28 image.show()
+ 29 label.show()
+ 30 return box1
+ 31
+ 32 class Buttons:
+ 33 # Our usual callback method
+ 34 def callback(self, widget, data=None):
+ 35 print "Hello again - %s was pressed" % data
+ 36
+ 37 def __init__(self):
+ 38 # Create a new window
+ 39 self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ 40
+ 41 self.window.set_title("Image'd Buttons!")
+ 42
+ 43 # It's a good idea to do this for all windows.
+ 44 self.window.connect("destroy", lambda wid: gtk.main_quit())
+ 45 self.window.connect("delete_event", lambda a1,a2:gtk.main_quit())
+ 46
+ 47 # Sets the border width of the window.
+ 48 self.window.set_border_width(10)
+ 49
+ 50 # Create a new button
+ 51 button = gtk.Button()
+ 52
+ 53 # Connect the "clicked" signal of the button to our callback
+ 54 button.connect("clicked", self.callback, "cool button")
+ 55
+ 56 # This calls our box creating function
+ 57 box1 = xpm_label_box(self.window, "info.xpm", "cool button")
+ 58
+ 59 # Pack and show all our widgets
+ 60 button.add(box1)
+ 61
+ 62 box1.show()
+ 63 button.show()
+ 64
+ 65 self.window.add(button)
+ 66 self.window.show()
+ 67
+ 68 def main():
+ 69 gtk.main()
+ 70 return 0
+ 71
+ 72 if __name__ == "__main__":
+ 73 Buttons()
+ 74 main()
+</pre></td></tr></table><p>Lines 12-34 define the <tt class="function">xpm_label_box</tt>()
+helper function which creates a horizontal box with a border width of 2
+(lines 14-15), populates it with an image (lines 22-23) and a label (line
+26).</p><p>Lines 36-70 define the <tt class="classname">Buttons</tt> class.
+Lines 41-70 define the instance initialization method which creates a window
+(line 43), sets the title (line 45), connects the "delete_event" and
+"destroy" signals (lines 48-49). Line 55 creates the button without a label.
+Its "clicked" signal gets connected to the
+<tt class="methodname">callback</tt>() method in line 58. The
+<tt class="function">xpm_label_box</tt>() function is called in line 61 to create
+the image and label to put in the button in line 64.</p><p>The <tt class="function">xpm_label_box</tt>() function could be used
+to pack xpm's and labels into any widget that can be a container.</p><p>The Button widget has the following signals:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ pressed - emitted when pointer button is pressed within Button widget
+
+ released - emitted when pointer button is released within Button widget
+
+ clicked - emitted when pointer button is pressed and then released within Button widget
+
+ enter - emitted when pointer enters Button widget
+
+ leave - emitted when pointer leaves Button widget
+</pre></td></tr></table></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-WidgetsWithoutWindows.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="index.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-ToggleButtons.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">5.2. Widgets Without Windows </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 6.2. Toggle Buttons</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/ch-ContainerWidgets.html b/help/Pygtk2Tutorial/pygtk2tutorial/ch-ContainerWidgets.html
new file mode 100644
index 0000000..7cacab7
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/ch-ContainerWidgets.html
@@ -0,0 +1,76 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>Chapter 10. Container Widgets</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="previous" href="sec-FontSelectionDialog.html" title="9.15. Font Selection Dialog"><link rel="next" href="sec-Alignment.html" title="10.2. The Alignment widget"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 10. Container Widgets</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-FontSelectionDialog.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="sec-Alignment.html">Next</a></td></tr></table><hr></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="ch-ContainerWidgets"></a>Chapter 10. Container Widgets</h2></div></div><div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="ch-ContainerWidgets.html#sec-EventBox">10.1. The EventBox</a></span></dt><dt><span class="sect1"><a href="sec-Alignment.html">10.2. The Alignment widget</a></span></dt><dt><span class="sect1"><a href="sec-Fixed.html">10.3. Fixed Container</a></span></dt><dt><span class="sect1"><a href="sec-Layout.html">10.4. Layout Container</a></span></dt><dt><span class="sect1"><a href="sec-Frames.html">10.5. Frames</a></span></dt><dt><span class="sect1"><a href="sec-AspectFrames.html">10.6. Aspect Frames</a></span></dt><dt><span class="sect1"><a href="sec-PanedWindowWidgets.html">10.7. Paned Window Widgets</a></span></dt><dt><span class="sect1"><a href="sec-Viewports.html">10.8. Viewports</a></span></dt><dt><span class="sect1"><a href="sec-ScrolledWindows.html">10.9. Scrolled Windows</a></span></dt><dt><span class="sect1"><a href="sec-ButtonBoxes.html">10.10. Button Boxes</a></span></dt><dt><span class="sect1"><a href="sec-Toolbar.html">10.11. Toolbar</a></span></dt><dt><span class="sect1"><a href="sec-Notebooks.html">10.12. Notebooks</a></span></dt><dt><span class="sect1"><a href="sec-PlugsAndSockets.html">10.13. Plugs and Sockets</a></span></dt><dd><dl><dt><span class="sect2"><a href="sec-PlugsAndSockets.html#id2848120">10.13.1. Plugs</a></span></dt><dt><span class="sect2"><a href="sec-PlugsAndSockets.html#id2848244">10.13.2. Sockets</a></span></dt></dl></dd></dl></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-EventBox"></a>10.1. The EventBox</h2></div></div><div></div></div><p>Some GTK widgets don't have associated X windows, so they just
+draw on their parents. Because of this, they cannot receive events and if
+they are incorrectly sized, they don't clip so you can get messy
+overwriting, etc. If you require more from these widgets, the
+<tt class="classname">EventBox</tt> is for you.</p><p>At first glance, the <tt class="classname">EventBox</tt> widget
+might appear to be totally useless. It draws nothing on the screen and
+responds to no events. However, it does serve a function - it provides an X
+window for its child widget. This is important as many GTK widgets do not
+have an associated X window. Not having an X window saves memory and
+improves performance, but also has some drawbacks. A widget without an X
+window cannot receive events, does not perform any clipping on its contents
+and cannot set its background color. Although the name
+<tt class="classname">EventBox</tt> emphasizes the event-handling function, the
+widget can also be used for clipping. (and more, see the example
+below).</p><p>To create a new <tt class="classname">EventBox</tt> widget,
+use:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ event_box = gtk.EventBox()
+</pre></td></tr></table><p>A child widget can then be added to this
+<i class="parameter"><tt>event_box</tt></i>:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ event_box.add(<b class="parameter"><tt>widget</tt></b>)
+</pre></td></tr></table><p>The <a href="examples/eventbox.py" target="_top"><span><b class="command">eventbox.py</b></span></a> example
+program demonstrates both uses of an <tt class="classname">EventBox</tt> - a
+label is created that is clipped to a small box, has a green background and
+is set up so that a mouse-click on the label causes the program to exit.
+Resizing the window reveals varying amounts of the label.
+<a href="ch-ContainerWidgets.html#eventboxfig" title="Figure 10.1. Event Box Example">Figure 10.1, “Event Box Exampleâ€</a> illustrates the programs display:</p><div class="figure"><a name="eventboxfig"></a><p class="title"><b>Figure 10.1. Event Box Example</b></p><div class="mediaobject" align="center"><img src="figures/eventbox.png" align="middle" alt="Event Box Example"></div></div><p>The source code for <a href="examples/eventbox.py" target="_top"><span><b class="command">eventbox.py</b></span></a> is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 1 #!/usr/bin/env python
+ 2
+ 3 # example eventbox.py
+ 4
+ 5 import pygtk
+ 6 pygtk.require('2.0')
+ 7 import gtk
+ 8
+ 9 class EventBoxExample:
+ 10 def __init__(self):
+ 11 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ 12 window.set_title("Event Box")
+ 13 window.connect("destroy", lambda w: gtk.main_quit())
+ 14 window.set_border_width(10)
+ 15
+ 16 # Create an EventBox and add it to our toplevel window
+ 17 event_box = gtk.EventBox()
+ 18 window.add(event_box)
+ 19 event_box.show()
+ 20
+ 21 # Create a long label
+ 22 label = gtk.Label("Click here to quit, quit, quit, quit, quit")
+ 23 event_box.add(label)
+ 24 label.show()
+ 25
+ 26 # Clip it short.
+ 27 label.set_size_request(110, 20)
+ 28
+ 29 # And bind an action to it
+ 30 event_box.set_events(gtk.gdk.BUTTON_PRESS_MASK)
+ 31 event_box.connect("button_press_event", lambda w,e: gtk.main_quit())
+ 32
+ 33 # More things you need an X window for ...
+ 34 event_box.realize()
+ 35 event_box.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.HAND1))
+ 36
+ 37 # Set background color to green
+ 38 event_box.modify_bg(gtk.STATE_NORMAL,
+ 39 event_box.get_colormap().alloc_color("green"))
+ 40
+ 41 window.show()
+ 42
+ 43 def main():
+ 44 gtk.main()
+ 45 return 0
+ 46
+ 47 if __name__ == "__main__":
+ 48 EventBoxExample()
+ 49 main()
+</pre></td></tr></table></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-FontSelectionDialog.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="index.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-Alignment.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">9.15. Font Selection Dialog </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 10.2. The Alignment widget</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/ch-Contributing.html b/help/Pygtk2Tutorial/pygtk2tutorial/ch-Contributing.html
new file mode 100644
index 0000000..7626b46
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/ch-Contributing.html
@@ -0,0 +1,8 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>Chapter 26. Contributing</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="previous" href="ch-TipsForWritingPyGTKApplications.html" title="Chapter 25. Tips For Writing PyGTK Applications"><link rel="next" href="ch-Credits.html" title="Chapter 27. Credits"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 26. Contributing</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch-TipsForWritingPyGTKApplications.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="ch-Credits.html">Next</a></td></tr></table><hr></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="ch-Contributing"></a>Chapter 26. Contributing</h2></div></div><div></div></div><p>This document, like so much other great software out there, was
+created for free by volunteers. If you are at all knowledgeable about any
+aspect of PyGTK that does not already have documentation, please consider
+contributing to this document.</p><p>If you do decide to contribute, please mail your text to John Finlay (<a href="mailto:finlay@moeraki.com" target="_top">finlay@moeraki.com</a>).
+Also, be aware that the entirety of this document is free, and any addition
+by you provide must also be free. That is, people may use any portion of
+your examples in their programs, and copies of this document may be
+distributed at will, etc.</p><p>Thank you.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch-TipsForWritingPyGTKApplications.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="index.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch-Credits.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 25. Tips For Writing PyGTK Applications </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 27. Credits</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/ch-Copyright.html b/help/Pygtk2Tutorial/pygtk2tutorial/ch-Copyright.html
new file mode 100644
index 0000000..eff2af0
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/ch-Copyright.html
@@ -0,0 +1,14 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>Chapter 28. Tutorial Copyright and Permissions Notice</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="previous" href="sec-OriginalGTK+Credits.html" title="27.2. Original GTK+ Credits"><link rel="next" href="app-GtkSignals.html" title="Appendix A. GTK Signals"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 28. Tutorial Copyright and Permissions Notice</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-OriginalGTK+Credits.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="app-GtkSignals.html">Next</a></td></tr></table><hr></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="ch-Copyright"></a>Chapter 28. Tutorial Copyright and Permissions Notice</h2></div></div><div></div></div><p>The PyGTK Tutorial is Copyright (C) 2001-2005 John Finlay.</p><p>The GTK Tutorial is Copyright (C) 1997 Ian Main.</p><p>Copyright (C) 1998-1999 Tony Gale.</p><p>Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice are
+preserved on all copies.</p><p>Permission is granted to copy and distribute modified versions of
+this document under the conditions for verbatim copying, provided that this
+copyright notice is included exactly as in the original, and that the entire
+resulting derived work is distributed under the terms of a permission notice
+identical to this one.</p><p>Permission is granted to copy and distribute translations of this
+document into another language, under the above conditions for modified
+versions.</p><p>If you are intending to incorporate this document into a published
+work, please contact the maintainer, and we will make an effort to ensure
+that you have the most up to date information available.</p><p>There is no guarantee that this document lives up to its intended
+purpose. This is simply provided as a free resource. As such, the authors
+and maintainers of the information provided within can not make any
+guarantee that the information is even accurate.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-OriginalGTK+Credits.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="index.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="app-GtkSignals.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">27.2. Original GTK+ Credits </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Appendix A. GTK Signals</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/ch-Credits.html b/help/Pygtk2Tutorial/pygtk2tutorial/ch-Credits.html
new file mode 100644
index 0000000..46e376a
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/ch-Credits.html
@@ -0,0 +1,5 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>Chapter 27. Credits</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="previous" href="ch-Contributing.html" title="Chapter 26. Contributing"><link rel="next" href="sec-OriginalGTK+Credits.html" title="27.2. Original GTK+ Credits"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 27. Credits</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch-Contributing.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="sec-OriginalGTK+Credits.html">Next</a></td></tr></table><hr></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="ch-Credits"></a>Chapter 27. Credits</h2></div></div><div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="ch-Credits.html#sec-PyGTKCredits">27.1. PyGTK Credits</a></span></dt><dt><span class="sect1"><a href="sec-OriginalGTK+Credits.html">27.2. Original GTK+ Credits</a></span></dt></dl></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-PyGTKCredits"></a>27.1. PyGTK Credits</h2></div></div><div></div></div><p>Thanks to:</p><div class="itemizedlist"><ul type="disc"><li>Nathan Hurst for the <tt class="classname">Plugs</tt> and
+<tt class="classname">Sockets</tt> section.</li><li>Alex Roitman for the <tt class="classname">FileChooser</tt>
+section.</li><li>Steve George for the example program illustrating editable
+<tt class="classname">CellRendererText</tt> and activatable
+<tt class="classname">CellRendererToggle</tt>.</li></ul></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch-Contributing.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="index.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-OriginalGTK+Credits.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 26. Contributing </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 27.2. Original GTK+ Credits</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/ch-DragAndDrop.html b/help/Pygtk2Tutorial/pygtk2tutorial/ch-DragAndDrop.html
new file mode 100644
index 0000000..5b3b114
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/ch-DragAndDrop.html
@@ -0,0 +1,25 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>Chapter 22. Drag-and-drop (DND)</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="previous" href="sec-SupplyingTheSelection.html" title="21.3. Supplying the Selection"><link rel="next" href="sec-DNDProperties.html" title="22.2. DND Properties"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 22. Drag-and-drop (DND)</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-SupplyingTheSelection.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="sec-DNDProperties.html">Next</a></td></tr></table><hr></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="ch-DragAndDrop"></a>Chapter 22. Drag-and-drop (DND)</h2></div></div><div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="ch-DragAndDrop.html#sec-DNDOverview">22.1. DND Overview</a></span></dt><dt><span class="sect1"><a href="sec-DNDProperties.html">22.2. DND Properties</a></span></dt><dt><span class="sect1"><a href="sec-DNDMethods.html">22.3. DND Methods</a></span></dt><dd><dl><dt><span class="sect2"><a href="sec-DNDMethods.html#id2793141">22.3.1. Setting Up the Source Widget</a></span></dt><dt><span class="sect2"><a href="sec-DNDMethods.html#sec-SignalsOnSourceWidget">22.3.2. Signals On the Source Widget</a></span></dt><dt><span class="sect2"><a href="sec-DNDMethods.html#sec-SettingUpDestinationWidget">22.3.3. Setting Up a Destination Widget</a></span></dt><dt><span class="sect2"><a href="sec-DNDMethods.html#sec-SignalsOnDestinationWidget">22.3.4. Signals On the Destination Widget</a></span></dt></dl></dd></dl></div><p>PyGTK has a high level set of functions for doing inter-process
+communication via the drag-and-drop system. PyGTK can perform drag-and-drop
+on top of the low level Xdnd and Motif drag-and-drop protocols.</p><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-DNDOverview"></a>22.1. DND Overview</h2></div></div><div></div></div><p>An application capable of drag-and-drop first defines and sets up
+the widget(s) for drag-and-drop. Each widget can be a source and/or
+destination for drag-and-drop. Note that these widgets must have an
+associated X Window.</p><p>Source widgets can send out drag data, thus allowing the user to
+drag things off of them, while destination widgets can receive drag data.
+Drag-and-drop destinations can limit who they accept drag data from, e.g.
+the same application or any application (including itself).</p><p>Sending and receiving drop data makes use of signals. Dropping an
+item to a destination widget requires both a data request (for the source
+widget) and data received signal handler (for the target widget). Additional
+signal handers can be connected if you want to know when a drag begins (at
+the very instant it starts), to when a drop is made, and when the entire
+drag-and-drop procedure has ended (successfully or not).</p><p>Your application will need to provide data for source widgets when
+requested, that involves having a drag data request signal handler. For
+destination widgets they will need a drop data received signal
+handler.</p><p>So a typical drag-and-drop cycle would look as follows:</p><div class="itemizedlist"><ul type="disc"><li><p>Drag begins. Source can get "drag-begin" signal. Can set up
+drag icon, etc.</p></li><li><p>Drag moves over a drop area. Destination can get "drag-motion"
+signal.</p></li><li><p>Drop occurs. Destination can get "drag-drop"
+signal. Destination should ask for source data.</p></li><li><p>Drag data request (when a drop occurs). Source can get
+"drag-data-get" signal.</p></li><li><p>Drop data received (may be on same or different
+application). Destination can get "drag-data-received" signal.</p></li><li><p>Drag data delete (if the drag was a move). Source can get
+"drag-data-delete" signal</p></li><li><p>Drag-and-drop procedure done. Source can receive "drag-end"
+signal.</p></li></ul></div><p>There are a few minor steps that go in between here and there,
+but we will get into detail about that later.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-SupplyingTheSelection.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="index.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-DNDProperties.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">21.3. Supplying the Selection </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 22.2. DND Properties</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/ch-DrawingArea.html b/help/Pygtk2Tutorial/pygtk2tutorial/ch-DrawingArea.html
new file mode 100644
index 0000000..a1909b2
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/ch-DrawingArea.html
@@ -0,0 +1,217 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>Chapter 12. Drawing Area</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="previous" href="sec-ItemFactoryExample.html" title="11.4. Item Factory Example"><link rel="next" href="sec-DrawingMethods.html" title="12.2. Drawing Methods"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 12. Drawing Area</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-ItemFactoryExample.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="sec-DrawingMethods.html">Next</a></td></tr></table><hr></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="ch-DrawingArea"></a>Chapter 12. Drawing Area</h2></div></div><div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="ch-DrawingArea.html#sec-GraphicsContext">12.1. Graphics Context</a></span></dt><dt><span class="sect1"><a href="sec-DrawingMethods.html">12.2. Drawing Methods</a></span></dt></dl></div><p>The <tt class="classname">DrawingArea</tt> widget wraps a
+<tt class="classname">gtk.gdk.Window</tt> which is a subclass of
+<tt class="classname">gtk.gdk.Drawable</tt> (as is a
+<tt class="classname">gtk.gdk.Pixmap</tt>). In effect the
+<tt class="classname">DrawingArea</tt> provides a simple 'canvas' area (the
+wrapped <tt class="classname">gtk.gdk.Window</tt>) that can be drawn on using
+the methods of the <tt class="classname">gtk.gdk.Drawable</tt> class.</p><p>A <tt class="classname">DrawingArea</tt> is created using the
+constructor:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ drawing_area = gtk.DrawingArea()
+</pre></td></tr></table><p>A <tt class="classname">DrawingArea</tt> is initially created with a
+size of (0, 0) so you should use the following method to make the
+<i class="parameter"><tt>drawing_area</tt></i> visible by setting its width and height
+to useful values greater than zero:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ drawing_area.set_size_request(<b class="parameter"><tt>width</tt></b>, <b class="parameter"><tt>height</tt></b>)
+</pre></td></tr></table><p>To draw on a <tt class="classname">DrawingArea</tt> you must retrieve
+the wrapped <tt class="classname">gtk.gdk.Window</tt> using the
+<i class="parameter"><tt>window</tt></i> attribute of the
+<tt class="classname">DrawingArea</tt> as follows:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ drawable = drawing_area.window
+</pre></td></tr></table><p>Then you can draw on <i class="parameter"><tt>drawable</tt></i> using the
+<tt class="classname">gtk.gdk.Drawable</tt> methods described in <a href="sec-DrawingMethods.html" title="12.2. Drawing Methods">Section 12.2, “Drawing Methodsâ€</a>.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>The <tt class="classname">DrawingArea</tt> must be realized (i.e. the
+Widget methods <tt class="methodname">realize</tt>() or
+<tt class="methodname">show</tt>() have been called) to have an associated
+<tt class="classname">gtk.gdk.Window</tt> that can be used for drawing.</p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-GraphicsContext"></a>12.1. Graphics Context</h2></div></div><div></div></div><p>A variety of methods are available to draw onto the
+<tt class="classname">gtk.gdk.Window</tt> of a
+<tt class="classname">DrawingArea</tt>. All these methods require a graphics
+context (<tt class="classname">gtk.gdk.GC</tt>) to encapsulate, as attributes,
+the information required for drawing. The attributes of a
+<tt class="classname">gtk.gdk.GC</tt> are:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+background
+cap_style
+clip_mask
+clip_x_origin
+clip_y_origin
+fill
+font
+foreground
+function
+graphics_exposures
+join_style
+line_style
+line_width
+stipple
+sub_window
+tile
+ts_x_origin
+ts_y_origin
+</pre></td></tr></table><p><i class="parameter"><tt>background</tt></i> specifies an allocated
+<tt class="classname">gtk.gdk.Color</tt> that is used to draw the background
+color.</p><p><i class="parameter"><tt>foreground</tt></i> specifies an allocated
+<tt class="classname">gtk.gdk.Color</tt> that is used to draw the foreground
+color.</p><p>A <tt class="classname">gtk.gdk.Color</tt> represents a color that
+may be allocated or unallocated. An unallocated color can be created
+using the constructor:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ color = gtk.gdk.Color(<b class="parameter"><tt>red</tt></b>=0, <b class="parameter"><tt>green</tt></b>=0, <b class="parameter"><tt>blue</tt></b>=0, <b class="parameter"><tt>pixel</tt></b>=0)
+</pre></td></tr></table><p>where <i class="parameter"><tt>red</tt></i>, <i class="parameter"><tt>green</tt></i> and
+<i class="parameter"><tt>blue</tt></i> are integers in the range of 0 to
+65535. <i class="parameter"><tt>pixel</tt></i> is not usually specified because it is
+overwritten when the color is allocated.</p><p>Alternatively, an unallocated <tt class="classname">gtk.gdk.Color</tt>
+can be created using the function:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ color = gtk.gdk.color_parse(<b class="parameter"><tt>spec</tt></b>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>spec</tt></i> is a color specification string
+that can be either:</p><div class="itemizedlist"><ul type="disc"><li>a color name (e.g. "red", "orange", "navajo white" as
+defined in the X Window file <tt class="filename">rgb.txt</tt>), or</li><li>a hexadecimal string starting with '#' and containing three
+sets of hex digits of the same length (1, 2, 3 or 4 digits). For example,
+"#F0A", "#FF00AA", "#FFF000AAA" and "#FFFF0000AAAA" all represent the same
+color.</li></ul></div><p>A <tt class="classname">gtk.gdk.Color</tt> representing an allocated
+color is created using the <tt class="classname">gtk.gdk.Colormap</tt>
+<tt class="methodname">alloc_color</tt>() method which has three
+signatures:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ color = colormap.alloc_color(<b class="parameter"><tt>color</tt></b>, <b class="parameter"><tt>writeable</tt></b>=FALSE, <b class="parameter"><tt>best_match</tt></b>=TRUE)
+
+ color = colormap.alloc_color(<b class="parameter"><tt>spec</tt></b>, <b class="parameter"><tt>writeable</tt></b>=FALSE, <b class="parameter"><tt>best_match</tt></b>=TRUE)
+
+ color = colormap.alloc_color(<b class="parameter"><tt>red</tt></b>, <b class="parameter"><tt>green</tt></b>, <b class="parameter"><tt>blue</tt></b>, <b class="parameter"><tt>writeable</tt></b>=FALSE, <b class="parameter"><tt>best_match</tt></b>=TRUE)
+</pre></td></tr></table><p><i class="parameter"><tt>color</tt></i> is an unallocated
+<tt class="classname">gtk.gdk.Color</tt>. <i class="parameter"><tt>spec</tt></i> is a color
+specification string as described above for the
+<tt class="function">gtk.gdk.color_parse</tt>()
+function. <i class="parameter"><tt>red</tt></i>, <i class="parameter"><tt>green</tt></i> and
+<i class="parameter"><tt>blue</tt></i> are integer color values as described for the
+<tt class="function">gtk.gdk.Color</tt>() constructor. You can optionally specify
+whether the allocated color should be writeable (i.e. can be changed later
+but cannot be shared) or whether a best match with existing colors should be
+made if the exact color is not available. </p><p>For example:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ navajowhite = colormap.alloc('navajo white')
+
+ cyan = colormap.alloc(0, 65535, 65535)
+
+ red = colormap.alloc_color('#FF0000', True, True)
+</pre></td></tr></table><p>The colormap associated with a widget can be retrieved using the
+method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ colormap = widget.get_colormap()
+</pre></td></tr></table><p><i class="parameter"><tt>cap_style</tt></i> specifies the line ending style
+that is used when drawing the end of a line that is not joined to another
+line. The available cap styles are:</p><div class="informaltable"><table width="100%" border="1"><colgroup><col><col></colgroup><tbody><tr><td><tt class="literal">CAP_NOT_LAST</tt></td><td>draws line ends the same as <tt class="literal">CAP_BUTT</tt>
+for lines of non-zero width. For zero width lines, the final point on the
+line will not be drawn.</td></tr><tr><td><tt class="literal">CAP_BUTT</tt></td><td>the ends of the lines are drawn squared off and extending
+to the coordinates of the end point.</td></tr><tr><td><tt class="literal">CAP_ROUND</tt></td><td>the ends of the lines are drawn as semicircles with the
+diameter equal to the line width and centered at the end point.</td></tr><tr><td><tt class="literal">CAP_PROJECTING</tt></td><td>the ends of the lines are drawn squared off and extending
+half the width of the line beyond the end point.</td></tr></tbody></table></div><p><i class="parameter"><tt>clip_mask</tt></i> specifies a
+<tt class="classname">gtk.gdk.Pixmap</tt> that is used to clip the drawing in
+the <i class="parameter"><tt>drawing_area</tt></i>.</p><p><i class="parameter"><tt>clip_x_origin</tt></i> and
+<i class="parameter"><tt>clip_y_origin</tt></i> specify the origin x and y values relative
+to the upper left corner of the <i class="parameter"><tt>drawing_area</tt></i> for
+clipping.</p><p><i class="parameter"><tt>fill</tt></i> specifies the fill style to be used
+when drawing. The available fill styles are:</p><div class="informaltable"><table width="100%" border="1"><colgroup><col><col></colgroup><tbody><tr><td><tt class="literal">SOLID</tt></td><td>draw with the foreground color.</td></tr><tr><td><tt class="literal">TILED</tt></td><td>draw with a tiled pixmap.</td></tr><tr><td><tt class="literal">STIPPLED</tt></td><td>draw using the stipple bitmap. Pixels corresponding to
+bits in the stipple bitmap that are set will be drawn in the foreground
+color; pixels corresponding to bits that are not set will be left
+untouched.</td></tr><tr><td><tt class="literal">OPAQUE_STIPPLED</tt></td><td>draw using the stipple bitmap. Pixels corresponding to
+bits in the stipple bitmap that are set will be drawn in the foreground
+color; pixels corresponding to bits that are not set will be drawn with the
+background color.</td></tr></tbody></table></div><p><i class="parameter"><tt>font</tt></i> is a
+<tt class="classname">gtk.gdk.Font</tt> that is used as the default font for
+drawing text.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>The use of the <i class="parameter"><tt>font</tt></i> attribute is
+deprecated.</p></div><p><i class="parameter"><tt>function</tt></i> specifies how the bit values for
+the source pixels are combined with the bit values for destination pixels to
+produce the resulting pixels bits. The sixteen values here correspond to the
+16 different possible 2x2 truth tables but only a couple of these values are
+usually useful. For color images, only COPY, XOR and INVERT are generally
+useful while for bitmaps, AND and OR are also useful. The function values
+are:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ COPY
+ INVERT
+ XOR
+ CLEAR
+ AND
+ AND_REVERSE
+ AND_INVERT
+ NOOP
+ OR
+ EQUIV
+ OR_REVERSE
+ COPY_INVERT
+ OR_INVERT
+ NAND
+ SET
+</pre></td></tr></table><p><i class="parameter"><tt>graphics_exposures</tt></i> specifies whether
+graphics exposures are enabled (<tt class="literal">TRUE</tt>) or disabled
+(<tt class="literal">FALSE</tt>). When <i class="parameter"><tt>graphics_exposures</tt></i>
+is <tt class="literal">TRUE</tt>, a failure when copy pixels in a drawing
+operation will cause an expose event to be issued. If the copy succeeds, a
+noexpose event is issued.</p><p><i class="parameter"><tt>join_style</tt></i> specifies the style of joint to be
+used when lines meet at an angle. The available styles are:</p><div class="informaltable"><table width="100%" border="1"><colgroup><col><col></colgroup><tbody><tr><td><tt class="literal">JOIN_MITER</tt></td><td>the sides of each line are extended to meet at an
+angle.</td></tr><tr><td><tt class="literal">JOIN_ROUND</tt></td><td>the sides of the two lines are joined by a circular
+arc.</td></tr><tr><td><tt class="literal">JOIN_BEVEL</tt></td><td>the sides of the two lines are joined by a straight line
+which makes an equal angle with each line.</td></tr></tbody></table></div><p><i class="parameter"><tt>line_style</tt></i> specifies the style that a line
+will be drawn with. The available styles are:</p><div class="informaltable"><table width="100%" border="1"><colgroup><col><col></colgroup><tbody><tr><td><tt class="literal">LINE_SOLID</tt></td><td>lines are drawn as continuous segments.</td></tr><tr><td><tt class="literal">LINE_ON_OFF_DASH</tt></td><td>even segments are drawn; odd segments are not
+drawn.</td></tr><tr><td><tt class="literal">LINE_DOUBLE_DASH</tt></td><td>even segments are normally. Odd segments are drawn in the
+background color if the fill style is <tt class="literal">SOLID</tt>, or in the
+background color masked by the stipple if the fill style is
+<tt class="literal">STIPPLED</tt>.</td></tr></tbody></table></div><p><i class="parameter"><tt>line_width</tt></i> specifies the width that lines
+will be drawn with.</p><p><i class="parameter"><tt>stipple</tt></i> specifies the
+<tt class="classname">gtk.gdk.Pixmap</tt> that will be used for stippled drawing
+when the <i class="parameter"><tt>fill</tt></i> is set to either <tt class="literal">STIPPLED</tt> or <tt class="literal">OPAQUE_STIPPLED</tt>.</p><p><i class="parameter"><tt>sub_window</tt></i> specifies the mode of drawing
+into a <tt class="classname">gtk.gdk.Window</tt> that has child
+<tt class="classname">gtk.gdk.Window</tt>s. The possible values of
+<i class="parameter"><tt>sub_window</tt></i> are:</p><div class="informaltable"><table width="100%" border="1"><colgroup><col><col></colgroup><tbody><tr><td><tt class="literal">CLIP_BY_CHILDREN</tt></td><td>only draw onto the window itself but not its child
+windows</td></tr><tr><td><tt class="literal">INCLUDE_INFERIORS</tt></td><td>draw onto the window and its child windows.</td></tr></tbody></table></div><p><i class="parameter"><tt>tile</tt></i> specifies the
+<tt class="classname">gtk.gdk.Pixmap</tt> to used for tiled drawing when the
+<i class="parameter"><tt>fill</tt></i> is set to <tt class="literal">TILED</tt>.</p><p><i class="parameter"><tt>ts_x_origin</tt></i> and
+<i class="parameter"><tt>ts_y_origin</tt></i> specify the tiling/stippling origin (the
+starting position for the stippling bitmap or tiling pixmap).</p><p>A new Graphics Context is created by a call to the
+<tt class="methodname">gtk.gdk.Drawable.new_gc</tt>() method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+gc = drawable.new_gc(<b class="parameter"><tt>foreground</tt></b>=None, <b class="parameter"><tt>background</tt></b>=None, <b class="parameter"><tt>font</tt></b>=None,
+ <b class="parameter"><tt>function</tt></b>=-1, <b class="parameter"><tt>fill</tt></b>=-1, <b class="parameter"><tt>tile</tt></b>=None,
+ <b class="parameter"><tt>stipple</tt></b>=None, <b class="parameter"><tt>clip_mask</tt></b>=None, <b class="parameter"><tt>subwindow_mode</tt></b>=-1,
+ <b class="parameter"><tt>ts_x_origin</tt></b>=-1, <b class="parameter"><tt>ts_y_origin</tt></b>=-1, <b class="parameter"><tt>clip_x_origin</tt></b>=-1,
+ <b class="parameter"><tt>clip_y_origin</tt></b>=-1, <b class="parameter"><tt>graphics_exposures</tt></b>=-1,
+ <b class="parameter"><tt>line_width</tt></b>=-1, <b class="parameter"><tt>line_style</tt></b>=-1, <b class="parameter"><tt>cap_style</tt></b>=-1
+ <b class="parameter"><tt>join_style</tt></b>=-1)
+</pre></td></tr></table><p>In order for a new Graphics Context to be created with this
+method, the drawable must be:</p><div class="itemizedlist"><ul type="disc"><li><p>a <tt class="classname">gtk.gdk.Window</tt> which has been
+realized (created), or;</p></li><li><p>a <tt class="classname">gtk.gdk.Pixmap</tt> associated with a
+realized <tt class="classname">gtk.gdk.Window</tt>.</p></li></ul></div><p>The various attributes of the Graphics Context have default values
+if not set in the <tt class="methodname">new_gc</tt>() method. If you want to
+set the GC attributes using the <tt class="methodname">new_gc</tt>() method,
+it's much easier to use the Python keyword arguments.</p><p>The individual attributes of a <tt class="classname">gtk.gdk.GC</tt>
+can also be set by assigning a value to the GC object attribute. For
+example:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ gc.cap_style = CAP_BUTT
+ gc.line_width = 10
+ gc.fill = SOLD
+ gc.foreground = mycolor
+</pre></td></tr></table><p>or by using the following methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ gc.set_foreground(color)
+ gc.set_background(color)
+ gc.set_function(function)
+ gc.set_fill(fill)
+ gc.set_tile(tile)
+ gc.set_stipple(stipple)
+ gc.set_ts_origin(x, y)
+ gc.set_clip_origin(x, y)
+ gc.set_clip_mask(mask)
+ gc.set_clip_rectangle(rectangle)
+ gc.set_subwindow(mode)
+ gc.set_exposures(exposures)
+ gc.set_line_attributes(line_width, line_style, cap_style, join_style)
+</pre></td></tr></table><p>The dash pattern to be used when the
+<i class="parameter"><tt>line_style</tt></i> is <tt class="literal">LINE_ON_OFF_DASH</tt> or
+<tt class="literal">LINE_DOUBLE_DASH</tt> can be set using the following
+method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ gc.set_dashes(offset, dash_list)
+</pre></td></tr></table><p>where <i class="parameter"><tt>offset</tt></i> is the index of the starting
+dash value in <i class="parameter"><tt>dash_list</tt></i> and
+<i class="parameter"><tt>dash_list</tt></i> is a list or tuple containing numbers of
+pixels to be drawn or skipped to form the dashes. The dashes are drawn
+starting with the number of pixels at the offset position; then the next
+number of pixels is skipped; and then the next number is drawn; and so on
+rotating through all the dash_list numbers and starting over when the end is
+reached. For example, if the dash_list is (2, 4, 8, 16) and the offset is 1,
+the dashes will be drawn as: draw 4 pixels, skip 8 pixels, draw 16 pixels,
+skip 2 pixels, draw 4 pixels and so on.</p><p>A copy of an existing <tt class="classname">gtk.gdk.GC</tt> can be
+made using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ gc.copy(<b class="parameter"><tt>src_gc</tt></b>)
+</pre></td></tr></table><p>The attributes of <i class="parameter"><tt>gc</tt></i> will then be the same as
+<i class="parameter"><tt>src_gc</tt></i>.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-ItemFactoryExample.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="index.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-DrawingMethods.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">11.4. Item Factory Example </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 12.2. Drawing Methods</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/ch-GettingStarted.html b/help/Pygtk2Tutorial/pygtk2tutorial/ch-GettingStarted.html
new file mode 100644
index 0000000..c21cb5b
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/ch-GettingStarted.html
@@ -0,0 +1,173 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>Chapter 2. Getting Started</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="previous" href="ch-Introduction.html" title="Chapter 1. Introduction"><link rel="next" href="sec-TheoryOfSignalsAndCallbacks.html" title="2.2. Theory of Signals and Callbacks"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 2. Getting Started</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch-Introduction.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="sec-TheoryOfSignalsAndCallbacks.html">Next</a></td></tr></table><hr></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="ch-GettingStarted"></a>Chapter 2. Getting Started</h2></div></div><div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="ch-GettingStarted.html#sec-HelloWorld">2.1. Hello World in PyGTK</a></span></dt><dt><span class="sect1"><a href="sec-TheoryOfSignalsAndCallbacks.html">2.2. Theory of Signals and Callbacks</a></span></dt><dt><span class="sect1"><a href="sec-Events.html">2.3. Events</a></span></dt><dt><span class="sect1"><a href="sec-SteppingThroughHelloWorld.html">2.4. Stepping Through Hello World</a></span></dt></dl></div><p>To begin our introduction to PyGTK, we'll start with the simplest
+program possible. This program (<a href="examples/base.py" target="_top"><span><b class="command">base.py</b></span></a>) will create a
+200x200 pixel window and has no way of exiting except to be killed by using
+the shell.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 1 #!/usr/bin/env python
+ 2
+ 3 # example base.py
+ 4
+ 5 import pygtk
+ 6 pygtk.require('2.0')
+ 7 import gtk
+ 8
+ 9 class Base:
+ 10 def __init__(self):
+ 11 self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ 12 self.window.show()
+ 13
+ 14 def main(self):
+ 15 gtk.main()
+ 16
+ 17 print __name__
+ 18 if __name__ == "__main__":
+ 19 base = Base()
+ 20 base.main()
+</pre></td></tr></table><p>You can run the above program using:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ python base.py
+</pre></td></tr></table><p>If <a href="examples/base.py" target="_top"><span><b class="command">base.py</b></span></a> is made executable
+and can be found in your <tt class="varname">PATH</tt>, it can be run
+using:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ base.py
+</pre></td></tr></table><p>Line 1 will invoke python to run <a href="examples/base.py" target="_top"><span><b class="command">base.py</b></span></a> in this
+case. Lines 5-6 help differentiate between various versions of PyGTK that
+may be installed on your system. These lines specify that we want to use
+PyGTK version 2.0 which covers all versions of PyGTK with the major number
+2. This prevents the program from using the earlier version of PyGTK if it
+happens to be installed on your system. Lines 18-20 check if the
+<tt class="varname">__name__</tt> variable is <tt class="literal">"__main__"</tt> which
+indicates that the program is being run directly from python and not being
+imported into a running python interpreter. In this case the program creates
+a new instance of the Base class and saves a reference to it in the variable
+base. It then invokes the method <tt class="methodname">main</tt>() to start
+the GTK+ event processing loop.</p><p>A window similar to <a href="ch-GettingStarted.html#basefig" title="Figure 2.1. Simple PyGTK Window">Figure 2.1, “Simple PyGTK Windowâ€</a> should popup on your
+display.</p><div class="figure"><a name="basefig"></a><p class="title"><b>Figure 2.1. Simple PyGTK Window</b></p><div class="mediaobject" align="center"><img src="figures/base.png" align="middle" alt="Simple PyGTK Window"></div></div><p>The first line allows the program <a href="examples/base.py" target="_top"><span><b class="command">base.py</b></span></a> to be
+invoked from a Linux or Unix shell program assuming that
+<span><b class="command">python</b></span> is found your <tt class="varname">PATH</tt>. This line
+will be the first line in all the example programs.</p><p>Lines 5-7 import the PyGTK 2 module and initializes the GTK+
+environment. The PyGTK module defines the python interfaces to the GTK+
+functions that will be used in the program. For those familiar with GTK+ the
+initialization includes calling the <tt class="function">gtk_init</tt>() function.
+This sets up a few things for us such as the
+default visual and color map, default signal handlers, and checks the
+arguments passed to your application on the command line, looking for one or
+more of the following:</p><div class="itemizedlist"><ul type="disc"><li>--gtk-module</li><li>--g-fatal-warnings</li><li>--gtk-debug</li><li>--gtk-no-debug</li><li>--gdk-debug</li><li>--gdk-no-debug</li><li>--display</li><li>--sync</li><li>--name</li><li>--class</li></ul></div><p>It removes these from the argument list, leaving anything it does
+not recognize for your application to parse or ignore. These are a set of
+standard arguments accepted by all GTK+ applications.</p><p>Lines 9-15 define a python class named <tt class="classname">Base</tt>
+that defines a class instance initialization method<tt class="methodname">
+__init__</tt>(). The <tt class="methodname">__init__</tt>() function
+creates a top level window (line 11) and directs GTK+ to display it (line
+12). The <tt class="classname">gtk.Window</tt> is created in line 11 with the
+argument <tt class="varname">gtk.WINDOW_TOPLEVEL</tt> that specifies that we want
+the window to undergo window manager decoration and placement. Rather than
+create a window of 0x0 size, a window without children is set to 200x200 by
+default so you can still manipulate it.</p><p>Lines 14-15 define the <tt class="methodname">main</tt>() method that
+calls the PyGTK <tt class="function">main</tt>() function that, in turn, invokes
+the GTK+ main event processing loop to handle mouse and keyboard events as
+well as window events.</p><p>Lines 18-20 allow the program to start automatically if called
+directly or passed as an argument to the python interpreter; in these cases
+the program name contained in the python variable
+<tt class="varname">__name__</tt> will be the string <tt class="literal">"__main__"</tt>
+and the code in lines 18-20 will be executed. If the program is loaded into
+a running python interpreter using an import statement, lines 18-20 will not
+be executed.</p><p>Line 19 creates an instance of the <tt class="classname">Base</tt>
+class called base. A <tt class="classname">gtk.Window</tt> is created and
+displayed as a result.</p><p>Line 20 calls the <tt class="methodname">main</tt>() method of the
+<tt class="classname">Base</tt> class which starts the GTK+ event processing
+loop. When control reaches this point, GTK+ will sleep waiting for X events
+(such as button or key presses), timeouts, or file IO notifications to
+occur. In our simple example, however, events are ignored.
+</p><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-HelloWorld"></a>2.1. Hello World in PyGTK</h2></div></div><div></div></div><p>Now for a program with a widget (a button). It's the PyGTK
+version of the classic hello world program (<a href="examples/helloworld.py" target="_top"><span><b class="command">helloworld.py</b></span></a>
+).</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 1 #!/usr/bin/env python
+ 2
+ 3 # example helloworld.py
+ 4
+ 5 import pygtk
+ 6 pygtk.require('2.0')
+ 7 import gtk
+ 8
+ 9 class HelloWorld:
+ 10
+ 11 # This is a callback function. The data arguments are ignored
+ 12 # in this example. More on callbacks below.
+ 13 def hello(self, widget, data=None):
+ 14 print "Hello World"
+ 15
+ 16 def delete_event(self, widget, event, data=None):
+ 17 # If you return FALSE in the "delete_event" signal handler,
+ 18 # GTK will emit the "destroy" signal. Returning TRUE means
+ 19 # you don't want the window to be destroyed.
+ 20 # This is useful for popping up 'are you sure you want to quit?'
+ 21 # type dialogs.
+ 22 print "delete event occurred"
+ 23
+ 24 # Change FALSE to TRUE and the main window will not be destroyed
+ 25 # with a "delete_event".
+ 26 return False
+ 27
+ 28 # Another callback
+ 29 def destroy(self, widget, data=None):
+ 30 gtk.main_quit()
+ 31
+ 32 def __init__(self):
+ 33 # create a new window
+ 34 self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ 35
+ 36 # When the window is given the "delete_event" signal (this is given
+ 37 # by the window manager, usually by the "close" option, or on the
+ 38 # titlebar), we ask it to call the delete_event () function
+ 39 # as defined above. The data passed to the callback
+ 40 # function is NULL and is ignored in the callback function.
+ 41 self.window.connect("delete_event", self.delete_event)
+ 42
+ 43 # Here we connect the "destroy" event to a signal handler.
+ 44 # This event occurs when we call gtk_widget_destroy() on the window,
+ 45 # or if we return FALSE in the "delete_event" callback.
+ 46 self.window.connect("destroy", self.destroy)
+ 47
+ 48 # Sets the border width of the window.
+ 49 self.window.set_border_width(10)
+ 50
+ 51 # Creates a new button with the label "Hello World".
+ 52 self.button = gtk.Button("Hello World")
+ 53
+ 54 # When the button receives the "clicked" signal, it will call the
+ 55 # function hello() passing it None as its argument. The hello()
+ 56 # function is defined above.
+ 57 self.button.connect("clicked", self.hello, None)
+ 58
+ 59 # This will cause the window to be destroyed by calling
+ 60 # gtk_widget_destroy(window) when "clicked". Again, the destroy
+ 61 # signal could come from here, or the window manager.
+ 62 self.button.connect_object("clicked", gtk.Widget.destroy, self.window)
+ 63
+ 64 # This packs the button into the window (a GTK container).
+ 65 self.window.add(self.button)
+ 66
+ 67 # The final step is to display this newly created widget.
+ 68 self.button.show()
+ 69
+ 70 # and the window
+ 71 self.window.show()
+ 72
+ 73 def main(self):
+ 74 # All PyGTK applications must have a gtk.main(). Control ends here
+ 75 # and waits for an event to occur (like a key press or mouse event).
+ 76 gtk.main()
+ 77
+ 78 # If the program is run directly or passed as an argument to the python
+ 79 # interpreter then create a HelloWorld instance and show it
+ 80 if __name__ == "__main__":
+ 81 hello = HelloWorld()
+ 82 hello.main()
+</pre></td></tr></table><p><a href="ch-GettingStarted.html#helloworldfig" title="Figure 2.2. Hello World Example Program">Figure 2.2, “Hello World Example Programâ€</a> shows the window created by <a href="examples/helloworld.py" target="_top"><span><b class="command">helloworld.py</b></span></a>.</p><div class="figure"><a name="helloworldfig"></a><p class="title"><b>Figure 2.2. Hello World Example Program</b></p><div class="mediaobject" align="center"><img src="figures/helloworld.png" align="middle" alt="Hello World Example Program"></div></div><p> The variables and functions that are defined in the PyGTK
+module are named as <tt class="literal">gtk.*</tt>. For example, the <a href="examples/helloworld.py" target="_top"><span><b class="command">helloworld.py</b></span></a>
+program uses:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ False
+ gtk.mainquit()
+ gtk.Window()
+ gtk.Button()
+</pre></td></tr></table><p>from the PyGTK module. In future sections I will not specify the
+gtk module prefix but it will be assumed. The example programs will of
+course use the module prefixes.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch-Introduction.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="index.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-TheoryOfSignalsAndCallbacks.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 1. Introduction </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 2.2. Theory of Signals and Callbacks</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/ch-GtkRcFiles.html b/help/Pygtk2Tutorial/pygtk2tutorial/ch-GtkRcFiles.html
new file mode 100644
index 0000000..fb967a4
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/ch-GtkRcFiles.html
@@ -0,0 +1,33 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>Chapter 23. GTK's rc Files</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="previous" href="sec-DNDMethods.html" title="22.3. DND Methods"><link rel="next" href="sec-GTKRcFileFormat.html" title="23.2. GTK's rc File Format"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 23. GTK's rc Files</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-DNDMethods.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="sec-GTKRcFileFormat.html">Next</a></td></tr></table><hr></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="ch-GtkRcFiles"></a>Chapter 23. GTK's rc Files</h2></div></div><div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="ch-GtkRcFiles.html#sec-FunctionsForRcFiles">23.1. Functions For rc Files</a></span></dt><dt><span class="sect1"><a href="sec-GTKRcFileFormat.html">23.2. GTK's rc File Format</a></span></dt><dt><span class="sect1"><a href="sec-ExampleRcFile.html">23.3. Example rc file</a></span></dt></dl></div><p>GTK+ has its own way of dealing with application defaults, by
+using rc files. These can be used to set the colors of just about any
+widget, and can also be used to tile pixmaps onto the background of some
+widgets.</p><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-FunctionsForRcFiles"></a>23.1. Functions For rc Files</h2></div></div><div></div></div><p>When your application starts, you should include a call
+to:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ rc_parse(<b class="parameter"><tt>filename</tt></b>)
+</pre></td></tr></table><p>Passing in the <i class="parameter"><tt>filename</tt></i> of your rc file. This
+will cause GTK+ to parse this file, and use the style settings for the widget
+types defined there.</p><p>If you wish to have a special set of widgets that can take on a
+different style from others, or any other logical division of widgets, use a
+call to:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ widget.set_name(<b class="parameter"><tt>name</tt></b>)
+</pre></td></tr></table><p>Your newly created <i class="parameter"><tt>widget</tt></i> will be assigned
+the <i class="parameter"><tt>name</tt></i> you give. This will allow you to change the
+attributes of this <i class="parameter"><tt>widget</tt></i> by name through the rc
+file.</p><p>If we use a call something like this:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ button = gtk.Button("Special Button")
+
+ button.set_name("special button")
+</pre></td></tr></table><p>Then this <i class="parameter"><tt>button</tt></i> is given the name "special
+button" and may be addressed by name in the rc file as "special
+button.GtkButton". [--- Verify ME!]</p><p><a href="sec-ExampleRcFile.html" title="23.3. Example rc file">Section 23.3, “Example rc fileâ€</a> below, sets the
+properties of the main window, and lets all children of that main window
+inherit the style described by the "main button" style. The code used in the
+application is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+
+ window.set_name("main window")
+</pre></td></tr></table><p>And then the style is defined in the rc file using:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ widget "main window.*GtkButton*" style "main_button"
+</pre></td></tr></table><p>Which sets all the <tt class="classname">Button</tt> (see <a href="ch-ButtonWidget.html" title="Chapter 6. The Button Widget">Chapter 6, <i>The Button Widget</i></a> widgets in the "main window" to the
+"main_buttons" style as defined in the rc file.</p><p>As you can see, this is a fairly powerful and flexible system.
+Use your imagination as to how best to take advantage of this.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-DNDMethods.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="index.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-GTKRcFileFormat.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">22.3. DND Methods </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 23.2. GTK's rc File Format</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/ch-Introduction.html b/help/Pygtk2Tutorial/pygtk2tutorial/ch-Introduction.html
new file mode 100644
index 0000000..35cb06b
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/ch-Introduction.html
@@ -0,0 +1,101 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>Chapter 1. Introduction</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="previous" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="next" href="ch-GettingStarted.html" title="Chapter 2. Getting Started"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 1. Introduction</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="index.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="ch-GettingStarted.html">Next</a></td></tr></table><hr></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="ch-Introduction"></a>Chapter 1. Introduction</h2></div></div><div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="ch-Introduction.html#sec-ExploringPygtk">1.1. Exploring PyGTK</a></span></dt></dl></div><p>PyGTK 2.0 is a set of Python modules which provide a Python
+interface to GTK+ 2.X. Throughout the rest of this document PyGTK refers to
+the 2.X version of PyGTK and GTK and GTK+ refer to the 2.X version of GTK+.
+The primary web site for PyGTK is <a href="http://www.pygtk.org" target="_top">www.pygtk.org</a>. The primary author of
+PyGTK is:</p><div class="itemizedlist"><ul type="disc"><li>
+James Henstridge <a href="mailto:james@daa.com.au" target="_top">james@daa.com.au</a>
+</li></ul></div><p>who is assisted by the developers listed in the AUTHORS file in the
+PyGTK distribution and the PyGTK community.</p><p>Python is an extensible, object-oriented interpreted programming
+language which is provided with a rich set of modules providing access to a
+large number of operating system services, internet services (such as HTML,
+XML, FTP, etc.), graphics (including OpenGL, TK, etc.), string handling
+functions, mail services (IMAP, SMTP, POP3, etc.), multimedia (audio, JPEG)
+and cryptographic services. In addition there are many other modules
+available from third parties providing many other services. Python is
+licensed under terms similar to the LGPL license and is available for Linux,
+Unix , Windows and Macintosh operating systems. More information on Python
+is available at www.python.org . The primary Author of Python is:</p><div class="itemizedlist"><ul type="disc"><li>
+Guido van Rossum <a href="mailto:guido@python.org" target="_top">guido@python.org</a>
+</li></ul></div><p>GTK (GIMP Toolkit) is a library for creating graphical user
+interfaces. It is licensed using the LGPL license, so you can develop open
+software, free software, or even commercial non-free software using GTK
+without having to spend anything for licenses or royalties.</p><p>It's called the GIMP toolkit because it was originally written for
+developing the GNU Image Manipulation Program (GIMP), but GTK has now been
+used in a large number of software projects, including the GNU Network
+Object Model Environment (GNOME) project. GTK is built on top of GDK (GIMP
+Drawing Kit) which is basically a wrapper around the low-level functions for
+accessing the underlying windowing functions (Xlib in the case of the X
+windows system). The primary authors of GTK are:</p><div class="itemizedlist"><ul type="disc"><li>
+Peter Mattis <a href="mailto:petm@xcf.berkeley.edu" target="_top">petm@xcf.berkeley.edu</a>
+</li><li>
+ Spencer Kimball <a href="mailto:spencer@xcf.berkeley.edu" target="_top">spencer@xcf.berkeley.edu</a>
+</li><li>
+ Josh MacDonald <a href="mailto:jmacd@xcf.berkeley.edu" target="_top">jmacd@xcf.berkeley.edu</a>
+</li></ul></div><p>GTK is currently maintained by:</p><div class="itemizedlist"><ul type="disc"><li>
+Owen Taylor <a href="mailto:otaylor@redhat.com" target="_top">otaylor@redhat.com</a>
+</li><li>
+Tim Janik <a href="mailto:timj@gtk.org" target="_top">timj@gtk.org</a>
+</li></ul></div><p>GTK is essentially an object oriented application programmers
+interface (API). Although written completely in C, it is implemented using
+the idea of classes and callback functions (pointers to functions).</p><p>There is also a third component called GLib which contains a few
+replacements for some standard calls, as well as some additional functions
+for handling linked lists, etc. The replacement functions are used to
+increase GTK's portability, as some of the functions implemented here are
+not available or are nonstandard on other unixes such as
+<tt class="function">g_strerror</tt>(). Some also contain enhancements to the
+libc versions, such as <tt class="function">g_malloc</tt> that has enhanced
+debugging utilities.</p><p>In version 2.0, GLib has picked up the type system which forms the
+foundation for GTK's class hierarchy, the signal system which is used
+throughout GTK, a thread API which abstracts the different native thread
+APIs of the various platforms and a facility for loading modules.</p><p>As the last component, GTK uses the Pango library for
+internationalized text output.</p><p>This tutorial describes the Python interface to GTK+ and is based
+on the GTK+ 2.0 Tutorial written by Tony Gale and Ian Main. This tutorial
+attempts to document as much as possible of PyGTK, but is by no means
+complete.</p><p>This tutorial assumes some understanding of Python, and how to
+create and run Python programs. If you are not familiar with Python, please
+read the <a href="http://www.python.org/doc/current/tut/tut.html" target="_top">Python
+Tutorial</a> first. This tutorial does not assume an understanding of
+GTK; if you are learning PyGTK to learn GTK, please comment on how you found
+this tutorial, and what you had trouble with. This tutorial does not
+describe how to compile or install Python, GTK+ or PyGTK.</p><p>This tutorial is based on:</p><div class="itemizedlist"><ul type="disc"><li>GTK+ 2.0 through GTK+ 2.4</li><li>Python 2.2</li><li>PyGTK 2.0 through PyGTK 2.4</li></ul></div><p>The examples were written and tested on a RedHat 9.0 system.</p><p>This document is a "work in progress". Please look for updates on
+<a href="http://www.pygtk.org/pygtktutorial" target="_top">www.pygtk.org</a>.</p><p>I would very much like to hear of any problems you have learning PyGTK
+from this document, and would appreciate input as to how it may be improved.
+Please see the section on Contributing for further information. If you
+encounter bugs please file a bug at <a href="http://bugzilla.gnome.org" target="_top">bugzilla.gnome.org</a> against the pygtk
+project. The information at <a href="http://www.pygtk.org/feedback.html" target="_top">www.pygtk.org</a> about
+Bugzilla may help.</p><p>The PyGTK 2.0 Reference Manual is available at
+<a href="http://www.pygtk.org/pygtkreference" target="_top">http://www.pygtk.org/pygtkreference</a>. It describes in detail the PyGTK classes.</p><p>The PyGTK website (<a href="http://www.pygtk.org" target="_top">www.pygtk.org</a>) contains other resources
+useful for learning about PyGTK including a link to the extensive <a href="http://www.async.com.br/faq/pygtk/" target="_top">FAQ</a> and other articles and
+tutorials and an active maillist and IRC channel (see <a href="http://www.pygtk.org/feedback.html" target="_top">www.pygtk.org</a> for
+details).</p><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-ExploringPygtk"></a>1.1. Exploring PyGTK</h2></div></div><div></div></div><p>Johan Dahlin has written a small Python program (<a href="examples/pygtkconsole.py" target="_top"><span><b class="command">pygtkconsole.py</b></span></a>)
+that runs on Linux and allows interactive exploration of PyGTK. The program
+provides a Python-like interactive interpreter interface that communicates
+with a child process that executes that entered commands. The PyGTK modules
+are loaded by default. A simple example session is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="screen">
+<tt class="prompt"> moe: 96:1095$</tt> <span><b class="command">pygtkconsole.py</b></span>
+ Python 2.2.2, PyGTK 1.99.14 (Gtk+ 2.0.6)
+ Interactive console to manipulate GTK+ widgets.
+ &gt;&gt;&gt; w=Window()
+ &gt;&gt;&gt; b=Button('Hello')
+ &gt;&gt;&gt; w.add(b)
+ &gt;&gt;&gt; def hello(b):
+ ... print "Hello, World!"
+ ...
+ &gt;&gt;&gt; b.connect('clicked', hello)
+ 5
+ &gt;&gt;&gt; w.show_all()
+ &gt;&gt;&gt; Hello, World!
+ Hello, World!
+ Hello, World!
+
+ &gt;&gt;&gt; b.set_label("Hi There")
+ &gt;&gt;&gt;
+</pre></td></tr></table><p>This creates a window containing a button which prints a message
+('Hello, World!') when clicked. This program makes it easy to try out
+various GTK widgets and PyGTK interfaces.</p><p>I also use a program that was developed by Brian McErlean as
+<a href="http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/65109" target="_top">ActiveState
+recipe 65109</a> with some mods to make it run with PyGTK 2.X. I call it
+<a href="examples/gpython.py" target="_top"><span><b class="command">gpython.py</b></span></a>. It
+works similar to the <a href="examples/pygtkconsole.py" target="_top"><span><b class="command">pygtkconsole.py</b></span></a>
+program.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>Both of these programs are known not to work on Microsoft
+Windows because they rely on Unix specific interfaces.</p></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="index.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="index.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch-GettingStarted.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">PyGTK 2.0 Tutorial </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 2. Getting Started</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/ch-ManagingSelections.html b/help/Pygtk2Tutorial/pygtk2tutorial/ch-ManagingSelections.html
new file mode 100644
index 0000000..1317af9
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/ch-ManagingSelections.html
@@ -0,0 +1,21 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>Chapter 21. Managing Selections</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="previous" href="sec-SignalEmissionAndPropagation.html" title="20.2. Signal Emission and Propagation"><link rel="next" href="sec-RetrievingTheSelection.html" title="21.2. Retrieving the Selection"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 21. Managing Selections</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-SignalEmissionAndPropagation.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="sec-RetrievingTheSelection.html">Next</a></td></tr></table><hr></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="ch-ManagingSelections"></a>Chapter 21. Managing Selections</h2></div></div><div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="ch-ManagingSelections.html#sec-SelectionOverview">21.1. Selection Overview</a></span></dt><dt><span class="sect1"><a href="sec-RetrievingTheSelection.html">21.2. Retrieving the Selection</a></span></dt><dt><span class="sect1"><a href="sec-SupplyingTheSelection.html">21.3. Supplying the Selection</a></span></dt></dl></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-SelectionOverview"></a>21.1. Selection Overview</h2></div></div><div></div></div><p>One type of interprocess communication supported by X and GTK+ is
+selections. A selection identifies a chunk of data, for instance, a portion
+of text, selected by the user in some fashion, for instance, by dragging
+with the mouse. Only one application on a display (the owner) can own a
+particular selection at one time, so when a selection is claimed by one
+application, the previous owner must indicate to the user that selection has
+been relinquished. Other applications can request the contents of a
+selection in different forms, called targets. There can be any number of
+selections, but most X applications only handle one, the primary
+selection.</p><p>In most cases, it isn't necessary for a PyGTK application to deal
+with selections itself. The standard widgets, such as the
+<tt class="classname">Entry</tt> (see <a href="sec-TextEntries.html" title="9.9. Text Entries">Section 9.9, “Text Entriesâ€</a>)
+widget, already have the capability to claim the selection when appropriate
+(e.g., when the user drags over text), and to retrieve the contents of the
+selection owned by another widget or another application (e.g., when the
+user clicks the second mouse button). However, there may be cases in which
+you want to give other widgets the ability to supply the selection, or you
+wish to retrieve targets not supported by default.</p><p>A fundamental concept needed to understand selection handling is
+that of the atom. An atom is an integer that uniquely identifies a string
+(on a certain display). Certain atoms are predefined by the X server,
+GTK.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-SignalEmissionAndPropagation.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="index.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-RetrievingTheSelection.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">20.2. Signal Emission and Propagation </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 21.2. Retrieving the Selection</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/ch-MenuWidget.html b/help/Pygtk2Tutorial/pygtk2tutorial/ch-MenuWidget.html
new file mode 100644
index 0000000..3132d52
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/ch-MenuWidget.html
@@ -0,0 +1,116 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>Chapter 11. Menu Widget</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="previous" href="sec-PlugsAndSockets.html" title="10.13. Plugs and Sockets"><link rel="next" href="sec-ManualMenuExample.html" title="11.2. Manual Menu Example"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 11. Menu Widget</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-PlugsAndSockets.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="sec-ManualMenuExample.html">Next</a></td></tr></table><hr></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="ch-MenuWidget"></a>Chapter 11. Menu Widget</h2></div></div><div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="ch-MenuWidget.html#sec-ManualMenuCreation">11.1. Manual Menu Creation</a></span></dt><dt><span class="sect1"><a href="sec-ManualMenuExample.html">11.2. Manual Menu Example</a></span></dt><dt><span class="sect1"><a href="sec-UsingItemFactory.html">11.3. Using ItemFactory</a></span></dt><dt><span class="sect1"><a href="sec-ItemFactoryExample.html">11.4. Item Factory Example</a></span></dt></dl></div><p>There are two ways to create menus: there's the easy way, and
+there's the hard way. Both have their uses, but you can usually use the
+<tt class="classname">ItemFactory</tt> (the easy way). The "hard" way is to
+create all the menus using the calls directly. The easy way is to use the
+<tt class="classname">gtk.ItemFactory</tt> calls. This is much simpler, but there
+are advantages and disadvantages to each approach.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>In PyGTK 2.4 ItemFactory is deprecated - use the UIManager
+instead.</p></div><p>The <tt class="classname">ItemFactory</tt> is much easier to use, and
+to add new menus to, although writing a few wrapper functions to create
+menus using the manual method could go a long way towards usability. With
+the <tt class="classname">Itemfactory</tt>, it is not possible to add images or
+the character '/' to the menus.</p><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-ManualMenuCreation"></a>11.1. Manual Menu Creation</h2></div></div><div></div></div><p>In the true tradition of teaching, we'll show you the hard way
+first. :)</p><p>There are three widgets that go into making a menubar and
+submenus:</p><div class="itemizedlist"><ul type="none"><li style="list-style-type: none"><p>a menu item, which is what the user wants to select, e.g., "Save"</p></li><li style="list-style-type: none"><p>a menu, which acts as a container for the menu items, and</p></li><li style="list-style-type: none"><p>a menubar, which is a container for each of the individual menus.</p></li></ul></div><p>This is slightly complicated by the fact that menu item widgets
+are used for two different things. They are both the widgets that are packed
+into the menu, and the widget that is packed into the menubar, which, when
+selected, activates the menu.</p><p>Let's look at the functions that are used to create menus and
+menubars. This first function is used to create a new menubar:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ menu_bar = gtk.MenuBar()
+</pre></td></tr></table><p>This rather self explanatory function creates a new menubar. You
+use the <tt class="classname">gtk.Container</tt> <tt class="methodname">add</tt>()
+method to pack this into a window, or the <tt class="classname">gtk.Box</tt> pack
+methods to pack it into a box - the same as buttons.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ menu = gtk.Menu()
+</pre></td></tr></table><p>This function returns a reference to a new menu; it is never
+actually shown (with the <tt class="methodname">show</tt>() method), it is just a
+container for the menu items. I hope this will become more clear when you
+look at the example below.</p><p>The next function is used to create menu items that are packed
+into the menu (and menubar):</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ menu_item = gtk.MenuItem(<b class="parameter"><tt>label</tt></b>=None)
+</pre></td></tr></table><p>The <i class="parameter"><tt>label</tt></i>, if any, will be parsed for
+mnemonic characters. This call is used to create the menu items that are to
+be displayed. Remember to differentiate between a "menu" as created with
+<tt class="function">gtk.Menu</tt>() and a "menu item" as created by the
+<tt class="function">gtk.MenuItem</tt>() functions. The menu item will be an
+actual button with an associated action, whereas a menu will be a container
+holding menu items.</p><p>Once you've created a menu item you have to put it into a menu.
+This is done using the <tt class="methodname">append</tt>() method. In order to
+capture when the item is selected by the user, we need to connect to the
+"activate" signal in the usual way. So, if we wanted to create a standard
+<span class="guimenu">File</span> menu, with the options
+<span class="guimenuitem">Open</span>,
+<span class="guimenuitem"><span class="guimenuitem">Save</span>, and </span>Quit, the
+code would look something like:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ file_menu = gtk.Menu() # Don't need to show menus
+
+ # Create the menu items
+ open_item = gtk.MenuItem("Open")
+ save_item = gtk.MenuItem("Save")
+ quit_item = gtk.MenuItem("Quit")
+
+ # Add them to the menu
+ file_menu.append(open_item)
+ file_menu.append(save_item)
+ file_menu.append(quit_item)
+
+ # Attach the callback functions to the activate signal
+ open_item.connect_object("activate", menuitem_response, "file.open")
+ save_item.connect_object("activate", menuitem_response, "file.save")
+
+ # We can attach the Quit menu item to our exit function
+ quit_item.connect_object ("activate", destroy, "file.quit")
+
+ # We do need to show menu items
+ open_item.show()
+ save_item.show()
+ quit_item.show()
+</pre></td></tr></table><p>At this point we have our menu. Now we need to create a menubar
+and a menu item for the <span class="guimenu">File</span> entry, to which we add our
+menu. The code looks like this:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ menu_bar = gtk.MenuBar()
+ window.add(menu_bar)
+ menu_bar.show()
+
+ file_item = gtk.MenuItem("File")
+ file_item.show()
+</pre></td></tr></table><p>Now we need to associate the menu with
+<i class="parameter"><tt>file_item</tt></i>. This is done with the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ menu_item.set_submenu(<b class="parameter"><tt>submenu</tt></b>)
+</pre></td></tr></table><p>So, our example would continue with:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ file_item.set_submenu(file_menu)
+</pre></td></tr></table><p>All that is left to do is to add the menu to the menubar, which
+is accomplished using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ menu_bar.append(<b class="parameter"><tt>child</tt></b>)
+</pre></td></tr></table><p>which in our case looks like this:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ menu_bar.append(file_item)
+</pre></td></tr></table><p>If we wanted the menu right justified on the menubar, such as
+help menus often are, we can use the following method (again on
+<i class="parameter"><tt>file_item</tt></i> in the current example) before attaching it to
+the menubar.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ menu_item.set_right_justified(right_justified)
+</pre></td></tr></table><p>Here is a summary of the steps needed to create a menu bar with
+menus attached:</p><div class="itemizedlist"><ul type="none"><li style="list-style-type: none"><p>Create a new menu using <tt class="function">gtk.Menu</tt>()</p></li><li style="list-style-type: none"><p>Use multiple calls to <tt class="function">gtk.MenuItem</tt>()
+for each item you wish to have on your menu. And use the
+<tt class="methodname">append</tt>() method to put each of these new items on to
+the menu.</p></li><li style="list-style-type: none"><p>Create a menu item using
+<tt class="function">gtk.MenuItem</tt>(). This will be the root of the menu, the
+text appearing here will be on the menubar itself.</p></li><li style="list-style-type: none"><p>Use the <tt class="methodname">set_submenu</tt>() method to attach
+the menu to the root menu item (the one created in the above step).</p></li><li style="list-style-type: none"><p>Create a new menubar using
+<tt class="function">gtk.MenuBar</tt>(). This step only needs to be done once
+when creating a series of menus on one menu bar.</p></li><li style="list-style-type: none"><p> Use the <tt class="methodname">append</tt>() method to put the
+root menu onto the menubar.</p></li></ul></div><p>Creating a popup menu is nearly the same. The difference is that
+the menu is not posted "automatically" by a menubar, but explicitly by
+calling the <tt class="methodname">popup</tt>() method from a button-press
+event, for example. Take these steps:</p><div class="itemizedlist"><ul type="none"><li style="list-style-type: none"><p>Create an event handling callback. It needs to have the
+format:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def handler(widget, event):
+</pre></td></tr></table></li><li style="list-style-type: none"><p>and it will use the event to find out where to pop up the
+menu.</p></li><li style="list-style-type: none"><p>In the event handler, if the event is a mouse button press,
+treat event as a button event (which it is) and use it as shown in the
+sample code to pass information to the <tt class="methodname">popup</tt>()
+method.</p></li><li style="list-style-type: none"><p>Bind that event handler to a widget with:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ widget.connect_object("event", handler, menu)
+</pre></td></tr></table></li><li style="list-style-type: none"><p>where widget is the widget you are binding to, handler is
+the handling function, and menu is a menu created with
+<tt class="function">gtk.Menu</tt>(). This can be a menu which is also posted by a
+menu bar, as shown in the sample code.</p></li></ul></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-PlugsAndSockets.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="index.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-ManualMenuExample.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">10.13. Plugs and Sockets </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 11.2. Manual Menu Example</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/ch-MiscellaneousWidgets.html b/help/Pygtk2Tutorial/pygtk2tutorial/ch-MiscellaneousWidgets.html
new file mode 100644
index 0000000..5806cc1
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/ch-MiscellaneousWidgets.html
@@ -0,0 +1,145 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>Chapter 9. Miscellaneous Widgets</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="previous" href="sec-RangeWidgetEample.html" title="8.5. Range Widget Example"><link rel="next" href="sec-Arrows.html" title="9.2. Arrows"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 9. Miscellaneous Widgets</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-RangeWidgetEample.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="sec-Arrows.html">Next</a></td></tr></table><hr></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="ch-MiscellaneousWidgets"></a>Chapter 9. Miscellaneous Widgets</h2></div></div><div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="ch-MiscellaneousWidgets.html#sec-Labels">9.1. Labels</a></span></dt><dt><span class="sect1"><a href="sec-Arrows.html">9.2. Arrows</a></span></dt><dt><span class="sect1"><a href="sec-TooltipsObject.html">9.3. The Tooltips Object</a></span></dt><dt><span class="sect1"><a href="sec-ProgressBars.html">9.4. Progress Bars</a></span></dt><dt><span class="sect1"><a href="sec-Dialogs.html">9.5. Dialogs</a></span></dt><dt><span class="sect1"><a href="sec-Images.html">9.6. Images</a></span></dt><dd><dl><dt><span class="sect2"><a href="sec-Images.html#id2843382">9.6.1. Pixmaps</a></span></dt></dl></dd><dt><span class="sect1"><a href="sec-Rulers.html">9.7. Rulers</a></span></dt><dt><span class="sect1"><a href="sec-Statusbars.html">9.8. Statusbars</a></span></dt><dt><span class="sect1"><a href="sec-TextEntries.html">9.9. Text Entries</a></span></dt><dt><span class="sect1"><a href="sec-SpinButtons.html">9.10. Spin Buttons</a></span></dt><dt><span class="sect1"><a href="sec-ComboWidget.html">9.11. Combo Widget</a></span></dt><dt><span class="sect1"><a href="sec-Calendar.html">9.12. Calendar</a></span></dt><dt><span class="sect1"><a href="sec-ColorSelection.html">9.13. Color Selection</a></span></dt><dt><span class="sect1"><a href="sec-FileSelections.html">9.14. File Selections</a></span></dt><dt><span class="sect1"><a href="sec-FontSelectionDialog.html">9.15. Font Selection Dialog</a></span></dt></dl></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-Labels"></a>9.1. Labels</h2></div></div><div></div></div><p><tt class="classname">Labels</tt> are used a lot in GTK, and are
+relatively simple. <tt class="classname">Labels</tt> emit no signals as they do
+not have an associated X window. If you need to catch signals, or do
+clipping, place it inside a <tt class="classname">EventBox</tt> (see <a href="ch-ContainerWidgets.html#sec-EventBox" title="10.1. The EventBox">Section 10.1, “The EventBoxâ€</a>) widget or a <tt class="classname">Button</tt>
+(see <a href="ch-ButtonWidget.html#sec-NormalButtons" title="6.1. Normal Buttons">Section 6.1, “Normal Buttonsâ€</a>) widget.</p><p>To create a new label, use:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ label = gtk.Label(<b class="parameter"><tt>str</tt></b>)
+</pre></td></tr></table><p>The sole argument is the string you wish the label to
+display. To change the label's text after creation, use the
+method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ label.set_text(<b class="parameter"><tt>str</tt></b>)
+</pre></td></tr></table><p><i class="parameter"><tt>label</tt></i> is the label you created
+previously, and <i class="parameter"><tt>str</tt></i> is the new string. The space
+needed for the new string will be automatically adjusted if needed. You can
+produce multi-line labels by putting line breaks in the label string.</p><p>To retrieve the current string, use:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ str = label.get_text()
+</pre></td></tr></table><p><i class="parameter"><tt>label</tt></i> is the label you've created, and
+<i class="parameter"><tt>str</tt></i> is the return string. The
+<i class="parameter"><tt>label</tt></i> text can be justified using:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ label.set_justify(<b class="parameter"><tt>jtype</tt></b>)
+</pre></td></tr></table><p>Values for <i class="parameter"><tt>jtype</tt></i> are:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ JUSTIFY_LEFT # the default
+ JUSTIFY_RIGHT
+ JUSTIFY_CENTER
+ JUSTIFY_FILL # does not work
+</pre></td></tr></table><p>The label widget is also capable of line wrapping the text
+automatically. This can be activated using:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ label.set_line_wrap(<b class="parameter"><tt>wrap</tt></b>)
+</pre></td></tr></table><p>The <i class="parameter"><tt>wrap</tt></i> argument takes a
+<tt class="literal">TRUE</tt> or <tt class="literal">FALSE</tt> value.</p><p>If you want your label underlined, then you can set a pattern on
+the label:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ label.set_pattern(<b class="parameter"><tt>pattern</tt></b>)
+</pre></td></tr></table><p>The <i class="parameter"><tt>pattern</tt></i> argument indicates how the
+underlining should look. It consists of a string of underscore and space
+characters. An underscore indicates that the corresponding character in the
+label should be underlined. For example, the string <tt class="literal">"__
+__"</tt> would underline the first two characters and fourth and fifth
+characters. If you simply want to have an underlined accelerator
+("mnemonic") in your label, you should use
+<tt class="methodname">set_text_with_mnemonic</tt>(<b class="parameter"><tt>str</tt></b>), not
+<tt class="methodname">set_pattern</tt>().</p><p>The <a href="examples/label.py" target="_top"><span><b class="command">label.py</b></span></a> program is a
+short example to illustrate these methods. This example makes use of the
+<tt class="classname">Frame</tt> (see <a href="sec-Frames.html" title="10.5. Frames">Section 10.5, “Framesâ€</a>) widget
+to better demonstrate the label styles. You can ignore this for now as the
+<tt class="classname">Frame</tt> widget is explained later on.</p><p>In GTK+ 2.0, label text can contain markup for font and other
+text attribute changes, and labels may be selectable (for copy-and-paste).
+These advanced features won't be explained here.</p><p><a href="ch-MiscellaneousWidgets.html#labelexamplesfig" title="Figure 9.1. Label Examples">Figure 9.1, “Label Examplesâ€</a> illustrates the result of running the
+example program:</p><div class="figure"><a name="labelexamplesfig"></a><p class="title"><b>Figure 9.1. Label Examples</b></p><div class="mediaobject" align="center"><img src="figures/labels.png" align="middle" alt="Label Examples"></div></div><p>The <a href="examples/label.py" target="_top"><span><b class="command">label.py</b></span></a> source code
+is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 1 #!/usr/bin/env python
+ 2
+ 3 # example label.py
+ 4
+ 5 import pygtk
+ 6 pygtk.require('2.0')
+ 7 import gtk
+ 8
+ 9 class Labels:
+ 10 def __init__(self):
+ 11 self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ 12 self.window.connect("destroy", lambda w: gtk.main_quit())
+ 13
+ 14 self.window.set_title("Label")
+ 15 vbox = gtk.VBox(False, 5)
+ 16 hbox = gtk.HBox(False, 5)
+ 17 self.window.add(hbox)
+ 18 hbox.pack_start(vbox, False, False, 0)
+ 19 self.window.set_border_width(5)
+ 20
+ 21 frame = gtk.Frame("Normal Label")
+ 22 label = gtk.Label("This is a Normal label")
+ 23 frame.add(label)
+ 24 vbox.pack_start(frame, False, False, 0)
+ 25
+ 26 frame = gtk.Frame("Multi-line Label")
+ 27 label = gtk.Label("This is a Multi-line label.\nSecond line\n"
+ 28 "Third line")
+ 29 frame.add(label)
+ 30 vbox.pack_start(frame, False, False, 0)
+ 31
+ 32 frame = gtk.Frame("Left Justified Label")
+ 33 label = gtk.Label("This is a Left-Justified\n"
+ 34 "Multi-line label.\nThird line")
+ 35 label.set_justify(gtk.JUSTIFY_LEFT)
+ 36 frame.add(label)
+ 37 vbox.pack_start(frame, False, False, 0)
+ 38
+ 39 frame = gtk.Frame("Right Justified Label")
+ 40 label = gtk.Label("This is a Right-Justified\nMulti-line label.\n"
+ 41 "Fourth line, (j/k)")
+ 42 label.set_justify(gtk.JUSTIFY_RIGHT)
+ 43 frame.add(label)
+ 44 vbox.pack_start(frame, False, False, 0)
+ 45
+ 46 vbox = gtk.VBox(False, 5)
+ 47 hbox.pack_start(vbox, False, False, 0)
+ 48 frame = gtk.Frame("Line wrapped label")
+ 49 label = gtk.Label("This is an example of a line-wrapped label. It "
+ 50 "should not be taking up the entire "
+ 51 "width allocated to it, but automatically "
+ 52 "wraps the words to fit. "
+ 53 "The time has come, for all good men, to come to "
+ 54 "the aid of their party. "
+ 55 "The sixth sheik's six sheep's sick.\n"
+ 56 " It supports multiple paragraphs correctly, "
+ 57 "and correctly adds "
+ 58 "many extra spaces. ")
+ 59 label.set_line_wrap(True)
+ 60 frame.add(label)
+ 61 vbox.pack_start(frame, False, False, 0)
+ 62
+ 63 frame = gtk.Frame("Filled, wrapped label")
+ 64 label = gtk.Label("This is an example of a line-wrapped, filled label. "
+ 65 "It should be taking "
+ 66 "up the entire width allocated to it. "
+ 67 "Here is a sentence to prove "
+ 68 "my point. Here is another sentence. "
+ 69 "Here comes the sun, do de do de do.\n"
+ 70 " This is a new paragraph.\n"
+ 71 " This is another newer, longer, better "
+ 72 "paragraph. It is coming to an end, "
+ 73 "unfortunately.")
+ 74 label.set_justify(gtk.JUSTIFY_FILL)
+ 75 label.set_line_wrap(True)
+ 76 frame.add(label)
+ 77 vbox.pack_start(frame, False, False, 0)
+ 78
+ 79 frame = gtk.Frame("Underlined label")
+ 80 label = gtk.Label("This label is underlined!\n"
+ 81 "This one is underlined in quite a funky fashion")
+ 82 label.set_justify(gtk.JUSTIFY_LEFT)
+ 83 label.set_pattern(
+ 84 "_________________________ _ _________ _ ______ __ _______ ___")
+ 85 frame.add(label)
+ 86 vbox.pack_start(frame, False, False, 0)
+ 87 self.window.show_all ()
+ 88
+ 89 def main():
+ 90 gtk.main()
+ 91 return 0
+ 92
+ 93 if __name__ == "__main__":
+ 94 Labels()
+ 95 main()
+</pre></td></tr></table><p>Note that the "Filled, wrapped label" is not fill
+justified.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-RangeWidgetEample.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="index.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-Arrows.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">8.5. Range Widget Example </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 9.2. Arrows</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/ch-MovingOn.html b/help/Pygtk2Tutorial/pygtk2tutorial/ch-MovingOn.html
new file mode 100644
index 0000000..82f1934
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/ch-MovingOn.html
@@ -0,0 +1,15 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>Chapter 3. Moving On</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="previous" href="sec-SteppingThroughHelloWorld.html" title="2.4. Stepping Through Hello World"><link rel="next" href="sec-UpgradedHelloWorld.html" title="3.2. An Upgraded Hello World"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 3. Moving On</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-SteppingThroughHelloWorld.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="sec-UpgradedHelloWorld.html">Next</a></td></tr></table><hr></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="ch-MovingOn"></a>Chapter 3. Moving On</h2></div></div><div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="ch-MovingOn.html#sec-MoreOnSignalHandlers">3.1. More on Signal Handlers</a></span></dt><dt><span class="sect1"><a href="sec-UpgradedHelloWorld.html">3.2. An Upgraded Hello World</a></span></dt></dl></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-MoreOnSignalHandlers"></a>3.1. More on Signal Handlers</h2></div></div><div></div></div><p>Lets take another look at the connect() call.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ object.connect(name, func, func_data)
+</pre></td></tr></table><p>The return value from a <tt class="methodname">connect</tt>() call is
+an integer tag that identifies your callback. As stated above, you may have
+as many callbacks per signal and per object as you need, and each will be
+executed in turn, in the order they were attached.</p><p>This tag allows you to remove this callback from the list by using:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ object.disconnect(id)
+</pre></td></tr></table><p>So, by passing in the tag returned by one of the signal connect
+methods, you can disconnect a signal handler.</p><p>You can also temporarily disable signal handlers with the
+<tt class="methodname">signal_handler_block</tt>() and
+<tt class="methodname">signal_handler_unblock</tt>() pair of methods.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ object.signal_handler_block(handler_id)
+
+ object.signal_handler_unblock(handler_id)
+</pre></td></tr></table></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-SteppingThroughHelloWorld.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="index.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-UpgradedHelloWorld.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">2.4. Stepping Through Hello World </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 3.2. An Upgraded Hello World</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/ch-NewInPyGTK2.2.html b/help/Pygtk2Tutorial/pygtk2tutorial/ch-NewInPyGTK2.2.html
new file mode 100644
index 0000000..802f6da
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/ch-NewInPyGTK2.2.html
@@ -0,0 +1,183 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>Chapter 15. New Widgets in PyGTK 2.2</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="previous" href="sec-GenericCellRenderer.html" title="14.12. The Generic CellRenderer"><link rel="next" href="ch-NewInPyGTK2.4.html" title="Chapter 16. New Widgets in PyGTK 2.4"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 15. New Widgets in PyGTK 2.2</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-GenericCellRenderer.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="ch-NewInPyGTK2.4.html">Next</a></td></tr></table><hr></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="ch-NewInPyGTK2.2"></a>Chapter 15. New Widgets in PyGTK 2.2</h2></div></div><div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="ch-NewInPyGTK2.2.html#sec-Clipboards">15.1. Clipboards</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch-NewInPyGTK2.2.html#sec-CreatingClipboard">15.1.1. Creating A Clipboard</a></span></dt><dt><span class="sect2"><a href="ch-NewInPyGTK2.2.html#sec-UsingClipboards">15.1.2. Using Clipboards with Entry, Spinbutton and TextView</a></span></dt><dt><span class="sect2"><a href="ch-NewInPyGTK2.2.html#sec-SettingClipboardData">15.1.3. Setting Data on a Clipboard</a></span></dt><dt><span class="sect2"><a href="ch-NewInPyGTK2.2.html#sec-RetrievingClipboardContents">15.1.4. Retrieving the Clipboard Contents</a></span></dt><dt><span class="sect2"><a href="ch-NewInPyGTK2.2.html#sec-ClipboardExample">15.1.5. A Clipboard Example</a></span></dt></dl></dd></dl></div><p>The <tt class="classname">Clipboard</tt> object was added in PyGTK
+2.2. The <tt class="classname">GtkClipboard</tt> was available in GTK+ 2.0 but
+was not wrapped by PyGTK 2.0 because it was not a complete
+<tt class="classname">GObject</tt>. Some new objects were added to the gtk.gdk
+module in PyGTK 2.2 but they will not be described in this tutorial. See the
+<a href="http://www.pygtk.org/pygtk2reference/index.html" target="_top">PyGTK 2
+Reference Manual</a> for more information on the
+<tt class="classname">gtk.gdk.Display</tt>,
+<tt class="classname">gtk.gdk.DisplayManager</tt> and
+<tt class="classname">gtk.gdk.Screen</tt> objects.</p><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-Clipboards"></a>15.1. Clipboards</h2></div></div><div></div></div><p>A <tt class="classname">Clipboard</tt> provides a storage area for
+sharing data between processes or between different widgets in the same
+process. Each <tt class="classname">Clipboard</tt> is identified by a string
+name encoded as a <tt class="classname">gdk.Atom</tt>. You can use any name you
+want to identify a <tt class="classname">Clipboard</tt> and a new one will be
+created if it doesn't exist. If you want to share a
+<tt class="classname">Clipboard</tt> with other processes each process will need
+to know the <tt class="classname">Clipboard</tt>'s name.</p><p><tt class="classname">Clipboard</tt>s are built on the
+<tt class="classname">SelectionData</tt> and selection interfaces. The default
+<tt class="classname">Clipboard</tt> used by the
+<tt class="classname">TextView</tt>, <tt class="classname">Label</tt> and
+<tt class="classname">Entry</tt> widgets is "CLIPBOARD". Other common clipboards
+are "PRIMARY" and "SECONDARY" that correspond to the primary and secondary
+selections (Win32 ignores these). These can also be specified using the
+<tt class="classname">gtk.gdk.Atom</tt> objects:
+<tt class="literal">gtk.gdk.SELECTION_CLIPBOARD</tt>,
+<tt class="literal">gtk.gdk.SELECTION_PRIMARY</tt> and
+<tt class="literal">gtk.gdk.SELECTION_SECONDARY</tt>. See the <a href="http://www.pygtk.org/pygtk2reference/class-gdkatom.html" target="_top">gtk.gdk.Atom
+reference documentation</a> for more information.</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-CreatingClipboard"></a>15.1.1. Creating A Clipboard</h3></div></div><div></div></div><p>A <tt class="classname">Clipboard</tt> is created using the
+constructor:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ clipboard = gtk.Clipboard(<b class="parameter"><tt>display</tt></b>, <b class="parameter"><tt>selection</tt></b>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>display</tt></i> is the
+<tt class="classname">gtk.gdk.Display</tt> associated with the
+<tt class="classname">Clipboard</tt> named by
+<i class="parameter"><tt>selection</tt></i>. The following convenience function creates
+a <tt class="classname">Clipboard</tt> using the default
+<tt class="classname">gtk.gdk.Display</tt>:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ clipboard = gtk.clipboard_get(<b class="parameter"><tt>selection</tt></b>)
+</pre></td></tr></table><p>Finally, a <tt class="classname">Clipboard</tt> can also be
+created using the <tt class="classname">Widget</tt> method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ clipboard = widget.get_clipboard(<b class="parameter"><tt>selection</tt></b>)
+</pre></td></tr></table><p>The widget must be realized and be part of a toplevel window
+hierarchy.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-UsingClipboards"></a>15.1.2. Using Clipboards with Entry, Spinbutton and TextView</h3></div></div><div></div></div><p><tt class="classname">Entry</tt>,
+<tt class="classname">SpinButton</tt> and <tt class="classname">TextView</tt>
+widgets have popup menus that provide the ability to cut and copy the
+selected text to and paste from the "CLIPBOARD" clipboard. In addition key
+bindings are set to allow keyboard accelerators to cut, copy and paste. Cut
+is activated by <span><b class="keycap">Control</b></span>+<span><b class="keycap">X</b></span>; copy,
+by <span><b class="keycap">Control</b></span>+<span><b class="keycap">C</b></span>; and,
+paste, by <span><b class="keycap">Control</b></span>+<span><b class="keycap">V</b></span>.</p><p>The widgets (<tt class="classname">Entry</tt> and
+<tt class="classname">SpinButton</tt>) implement the
+<tt class="classname">Editable</tt> interface that has the following methods to
+cut, copy and paste to and from the "CLIPBOARD" clipboard:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ editable.cut_clipboard()
+ editable.copy_clipboard()
+ editable.paste_clipboard()
+</pre></td></tr></table><p>A <tt class="classname">Label</tt> that is selectable (the
+"selectable" property is <tt class="literal">TRUE</tt>) also supports copying the
+selected text to the "CLIPBOARD" clipboard using a popup menu or the
+<span><b class="keycap">Control</b></span>+<span><b class="keycap">C</b></span>
+keyboard accelerator.</p><p><tt class="classname">TextBuffer</tt>s have similar methods though
+they also allow specifying the clipboard to use:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ textbuffer.copy_clipboard(<b class="parameter"><tt>clipboard</tt></b>)
+</pre></td></tr></table><p>The selection text will be copied to the
+<tt class="classname">Clipboard</tt> specified by
+<i class="parameter"><tt>clipboard</tt></i>.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ textbuffer.cut_clipboard(<b class="parameter"><tt>clipboard</tt></b>, <b class="parameter"><tt>default_editable</tt></b>)
+</pre></td></tr></table><p>The selected text will be copied to
+<i class="parameter"><tt>clipboard</tt></i>. If <i class="parameter"><tt>default_editable</tt></i>
+is <tt class="literal">TRUE</tt> the selected text will also be deleted from the
+<tt class="classname">TextBuffer</tt>. Otherwise,
+<tt class="methodname">cut_clipboard</tt>() will act like the
+<tt class="methodname">copy_clipboard</tt>() method.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ textbuffer.paste_clipboard(<b class="parameter"><tt>clipboard</tt></b>, <b class="parameter"><tt>override_location</tt></b>, <b class="parameter"><tt>default_editable</tt></b>)
+</pre></td></tr></table><p>If <i class="parameter"><tt>default_editable</tt></i> is
+<tt class="literal">TRUE</tt>, the contents of <i class="parameter"><tt>clipboard</tt></i>
+will be inserted into the <tt class="classname">TextBuffer</tt> at the location
+specified by the <tt class="classname">TextIter</tt>
+<i class="parameter"><tt>override_location</tt></i>. If
+<i class="parameter"><tt>default_editable</tt></i> is <tt class="literal">FALSE</tt>,
+<tt class="methodname">paste_clipboard</tt>() will not insert the contents of
+<i class="parameter"><tt>clipboard</tt></i>. If
+<i class="parameter"><tt>override_location</tt></i> is <tt class="literal">None</tt> the
+contents of <i class="parameter"><tt>clipboard</tt></i> will be inserted at the cursor
+location.</p><p><tt class="classname">TextBuffer</tt>s also have two methods to
+manage a set of <tt class="classname">Clipboard</tt>s that are automatically set
+with the contents of the current selection:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ textbuffer.add_selection_clipboard(<b class="parameter"><tt>clipboard</tt></b>)
+ textbuffer.remove_selection_clipboard(<b class="parameter"><tt>clipboard</tt></b>)
+</pre></td></tr></table><p>When a <tt class="classname">TextBuffer</tt> is added to a
+<tt class="classname">TextView</tt> the "PRIMARY" clipboard is automatically
+added to the selection clipboards. Your application can add other clipboards
+(for example, the "CLIPBOARD" clipboard).</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-SettingClipboardData"></a>15.1.3. Setting Data on a Clipboard</h3></div></div><div></div></div><p>You can set the <tt class="classname">Clipboard</tt> data
+programmatically using either of:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ clipboard.set_with_data(<b class="parameter"><tt>targets</tt></b>, <b class="parameter"><tt>get_func</tt></b>, <b class="parameter"><tt>clear_func</tt></b>, <b class="parameter"><tt>user_data</tt></b>)
+
+ clipboard.set_text(<b class="parameter"><tt>text</tt></b>, <b class="parameter"><tt>len</tt></b>=-1)
+</pre></td></tr></table><p>The <tt class="methodname">set_with_data</tt>() method indicates
+which selection data targets are supported and provides functions
+(<i class="parameter"><tt>get_func</tt></i> and <i class="parameter"><tt>clear_func</tt></i>) that
+are called when the data is asked for or the clipboard data is
+changed. <i class="parameter"><tt>user_data</tt></i> is passed to
+<i class="parameter"><tt>get_func</tt></i> or <i class="parameter"><tt>clear_func</tt></i> when
+called. <i class="parameter"><tt>targets</tt></i> is a list of 3-tuples
+containing:</p><div class="itemizedlist"><ul type="disc"><li>a string representing a target supported by the
+clipboard.</li><li>a flags value used for drag and drop - use 0.</li><li>an application assigned integer that is passed as a
+parameter to a signal handler to help identify the target type.</li></ul></div><p>The signatures of <i class="parameter"><tt>get_func</tt></i> and
+<i class="parameter"><tt>clear_func</tt></i> are:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def get_func(clipboard, selectiondata, info, data):
+
+ def clear_func(clipboard, data):
+</pre></td></tr></table><p>where <i class="parameter"><tt>clipboard</tt></i> is the
+<tt class="classname">Clipboard</tt>, <i class="parameter"><tt>selectiondata</tt></i> is a
+<tt class="classname">SelectionData</tt> object to set the data in,
+<i class="parameter"><tt>info</tt></i> is the application assigned integer associated
+with a target, and <i class="parameter"><tt>data</tt></i> is
+<i class="parameter"><tt>user_data</tt></i>.</p><p><tt class="methodname">set_text</tt>() is a convenience method
+that uses the <tt class="methodname">set_with_data</tt>() method to set text
+data on a <tt class="classname">Clipboard</tt> with the targets: "STRING",
+"TEXT", "COMPOUND_TEXT", and "UTF8_STRING". It uses internal get and clear
+functions to manage the data. <tt class="methodname">set_text</tt>() is
+equivalent to the following:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def my_set_text(self, text, len=-1):
+ targets = [ ("STRING", 0, 0),
+ ("TEXT", 0, 1),
+ ("COMPOUND_TEXT", 0, 2),
+ ("UTF8_STRING", 0, 3) ]
+ def text_get_func(clipboard, selectiondata, info, data):
+ selectiondata.set_text(data)
+ return
+ def text_clear_func(clipboard, data):
+ del data
+ return
+ self.set_with_data(targets, text_get_func, text_clear_func, text)
+ return
+</pre></td></tr></table><p>Once data is set on a clipboard, it will be available until the
+application is finished or the clipboard data is changed.</p><p>To provide the behavior typical of cut to a clipboard, your
+application will have to delete the selected text or object after copying it
+to the clipboard.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-RetrievingClipboardContents"></a>15.1.4. Retrieving the Clipboard Contents</h3></div></div><div></div></div><p>The contents of a <tt class="classname">Clipboard</tt> can be
+retrieved using the following method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ clipboard.request_contents(<b class="parameter"><tt>target</tt></b>, <b class="parameter"><tt>callback</tt></b>, <b class="parameter"><tt>user_data</tt></b>=None)
+</pre></td></tr></table><p>The contents specified by <i class="parameter"><tt>target</tt></i> are
+retrieved asynchronously in the function specified by
+<i class="parameter"><tt>callback</tt></i> which is called with
+<i class="parameter"><tt>user_data</tt></i>. The signature of
+<i class="parameter"><tt>callback</tt></i> is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def callback(clipboard, selectiondata, data):
+</pre></td></tr></table><p>where <i class="parameter"><tt>selectiondata</tt></i> is a
+<tt class="classname">SelectionData</tt> object containing the contents of
+<i class="parameter"><tt>clipboard</tt></i>. <i class="parameter"><tt>data</tt></i> is
+<i class="parameter"><tt>user_data</tt></i>. The
+<tt class="methodname">request_contents</tt>() method is the most general way
+of retrieving the contents of a <tt class="classname">Clipboard</tt>. The
+following convenience method retrieves the text contents of a
+<tt class="classname">Clipboard</tt>:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ clipboard.request_text(<b class="parameter"><tt>callback</tt></b>, <b class="parameter"><tt>user_data</tt></b>=None)
+</pre></td></tr></table><p>The text string is returned to the callback function instead
+of a <tt class="classname">Selectiondata</tt> object. You can check which
+targets are available on the <tt class="classname">Clipboard</tt> by using the
+method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ clipboard.request_targets(<b class="parameter"><tt>callback</tt></b>, <b class="parameter"><tt>user_data</tt></b>=None)
+</pre></td></tr></table><p>The targets are returned as a tuple of
+<tt class="classname">gtk.gdk.Atom</tt> objects to the callback function.</p><p>Two convenience methods are provided to return the
+<tt class="classname">Clipboard</tt> contents synchronously:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ selectiondata = clipboard.wait_for_contents(target)
+
+ text = clipboard.wait_for_text()
+</pre></td></tr></table></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-ClipboardExample"></a>15.1.5. A Clipboard Example</h3></div></div><div></div></div><p>To illustrate the use of a <tt class="classname">Clipboard</tt>
+the <a href="examples/clipboard.py" target="_top">clipboard.py</a> example program
+tracks the text items that are cut or copied to the "CLIPBOARD" clipboard
+and saves the last ten clipboard entries. There are ten buttons that provide
+access to the text of the saved entries. The button label display the first
+sixteen characters of the saved text and the tooltips display the targets
+that the entry originally had. When an entry button is clicked the text
+window is loaded with the associated saved text which is editable. The
+button below the text window saves the current text window contents to the
+clipboard.</p><p><a href="ch-NewInPyGTK2.2.html#clipboardfig" title="Figure 15.1. Clipboard Example Program">Figure 15.1, “Clipboard Example Programâ€</a> illustrates the <a href="examples/clipboard.py" target="_top">clipboard.py</a> example program in
+operation:</p><div class="figure"><a name="clipboardfig"></a><p class="title"><b>Figure 15.1. Clipboard Example Program</b></p><div class="mediaobject" align="center"><img src="figures/clipboard.png" align="middle" alt="Clipboard Example Program"></div></div><p>The example program polls the clipboard every 1.5 seconds to
+see if the contents have changed. The program could be changed to duplicate
+the complete set of target contents and then take ownership of the clipboard
+using the <tt class="methodname">set_with_data</tt>() method. Later, when
+another program sets the contents of the clipboard, the
+<i class="parameter"><tt>clear_func</tt></i> will be called and it can be used to
+reload the clipboard contents and retake the clipboard ownership.</p></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-GenericCellRenderer.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="index.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch-NewInPyGTK2.4.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">14.12. The Generic CellRenderer </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 16. New Widgets in PyGTK 2.4</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/ch-NewInPyGTK2.4.html b/help/Pygtk2Tutorial/pygtk2tutorial/ch-NewInPyGTK2.4.html
new file mode 100644
index 0000000..37e84bc
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/ch-NewInPyGTK2.4.html
@@ -0,0 +1,591 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>Chapter 16. New Widgets in PyGTK 2.4</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="previous" href="ch-NewInPyGTK2.2.html" title="Chapter 15. New Widgets in PyGTK 2.2"><link rel="next" href="sec-ComboBoxAndComboboxEntry.html" title="16.2. ComboBox and ComboBoxEntry Widgets"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 16. New Widgets in PyGTK 2.4</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch-NewInPyGTK2.2.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="sec-ComboBoxAndComboboxEntry.html">Next</a></td></tr></table><hr></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="ch-NewInPyGTK2.4"></a>Chapter 16. New Widgets in PyGTK 2.4</h2></div></div><div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="ch-NewInPyGTK2.4.html#sec-ActionsAndActionGroups">16.1. The Action and ActionGroup Objects</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch-NewInPyGTK2.4.html#sec-Actions">16.1.1. Actions</a></span></dt><dt><span class="sect2"><a href="ch-NewInPyGTK2.4.html#sec-ActionGroups">16.1.2. ActionGroups</a></span></dt></dl></dd><dt><span class="sect1"><a href="sec-ComboBoxAndComboboxEntry.html">16.2. ComboBox and ComboBoxEntry Widgets</a></span></dt><dd><dl><dt><span class="sect2"><a href="sec-ComboBoxAndComboboxEntry.html#sec-ComboBox">16.2.1. ComboBox Widgets</a></span></dt><dt><span class="sect2"><a href="sec-ComboBoxAndComboboxEntry.html#sec-ComboBoxEntry">16.2.2. ComboBoxEntry Widgets</a></span></dt></dl></dd><dt><span class="sect1"><a href="sec-ColorButtonAndFontButton.html">16.3. ColorButton and FontButton Widgets</a></span></dt><dd><dl><dt><span class="sect2"><a href="sec-ColorButtonAndFontButton.html#sec-ColorButton">16.3.1. ColorButton Widgets</a></span></dt><dt><span class="sect2"><a href="sec-ColorButtonAndFontButton.html#sec-FontButton">16.3.2. FontButton Widgets</a></span></dt></dl></dd><dt><span class="sect1"><a href="sec-EntryCompletion.html">16.4. EntryCompletion Objects</a></span></dt><dt><span class="sect1"><a href="sec-ExpanderWidget.html">16.5. Expander Widgets</a></span></dt><dt><span class="sect1"><a href="sec-FileChoosers.html">16.6. File Selections using FileChooser-based Widgets</a></span></dt><dt><span class="sect1"><a href="sec-UIManager.html">16.7. The UIManager</a></span></dt><dd><dl><dt><span class="sect2"><a href="sec-UIManager.html#sec-UIManagerOverview">16.7.1. Overview</a></span></dt><dt><span class="sect2"><a href="sec-UIManager.html#sec-CreatingUIManager">16.7.2. Creating a UIManager</a></span></dt><dt><span class="sect2"><a href="sec-UIManager.html#sec-AddRemoveActionGroups">16.7.3. Adding and Removing ActionGroups</a></span></dt><dt><span class="sect2"><a href="sec-UIManager.html#sec-UIDescriptions">16.7.4. UI Descriptions</a></span></dt><dt><span class="sect2"><a href="sec-UIManager.html#sec-AddRemoveUIDescriptions">16.7.5. Adding and Removing UI Descriptions</a></span></dt><dt><span class="sect2"><a href="sec-UIManager.html#sec-AccessingUIWidgets">16.7.6. Accessing UI Widgets</a></span></dt><dt><span class="sect2"><a href="sec-UIManager.html#sec-SimpleUIManagerExample">16.7.7. A Simple UIManager Example</a></span></dt><dt><span class="sect2"><a href="sec-UIManager.html#sec-MergingUIDescriptions">16.7.8. Merging UI Descriptions</a></span></dt><dt><span class="sect2"><a href="sec-UIManager.html#sec-UIManagerSignals">16.7.9. UIManager Signals</a></span></dt></dl></dd></dl></div><p>Quite a few new widgets and support objects were added in PyGTK
+2.4 including:</p><div class="itemizedlist"><ul type="disc"><li><tt class="classname">Action</tt>,
+<tt class="classname">RadioAction</tt>, <tt class="classname">ToggleAction</tt> -
+objects that represent actions that a user can take. Actions contain
+information to be used to create proxy widgets ( for example, icons, menu
+items and toolbar items).</li><li><tt class="classname">ActionGroup</tt> - an object containing
+Actions that have some relationship, for example, actions to open, close and
+print a document.</li><li><tt class="classname">Border</tt> - an object containing the
+values for a border.</li><li><tt class="classname">ColorButton</tt> - a button used to
+launch a ColorSelectionDialog.</li><li><tt class="classname">ComboBox</tt> - a widget providing a list
+of items to choose from. It replaces the
+<tt class="classname">OptionMenu</tt>.</li><li><tt class="classname">ComboBoxEntry</tt> - a widget providing a
+text entry field with a dropdown list of items to choose from. It replaces
+the <tt class="classname">Combo</tt>.</li><li><tt class="classname">EntryCompletion</tt> - an object
+providing completion for an <tt class="classname">Entry</tt> widget.</li><li><tt class="classname">Expander</tt> - a container that can show
+and hide its child in response to its button click.</li><li><tt class="classname">FileChooser</tt> - an interface for
+ choosing files.</li><li><tt class="classname">FileChooserWidget</tt> - a widget
+implementing the <tt class="classname">FileChooser</tt> interface. It replaces
+the <tt class="classname">FileSelection</tt> widget.</li><li><tt class="classname">FileChooserDialog</tt> - a dialog used
+for "File/Open" and "File/Save" actions. It replaces the
+<tt class="classname">FileSelectionDialog</tt>.</li><li><tt class="classname">FileFilter</tt> - an object used to
+filter files based on an internal set of rules.</li><li><tt class="classname">FontButton</tt> - a button that launches
+the <tt class="classname">FontSelectionDialog</tt>.</li><li><tt class="classname">IconInfo</tt> - an object containing
+information about an icon in an <tt class="classname">IconTheme</tt>.</li><li><tt class="classname">IconTheme</tt> - an object providing
+lookup of icons by name and size.</li><li><tt class="classname">ToolItem</tt>,
+<tt class="classname">ToolButton</tt>, <tt class="classname">RadioToolButton</tt>,
+<tt class="classname">SeparatorToolItem</tt>,
+<tt class="classname">ToggleToolButton</tt> - widgets that can be added to a
+<tt class="classname">Toolbar</tt>. These replace the previous
+<tt class="classname">Toolbar</tt> items.</li><li><tt class="classname">TreeModelFilter</tt> - an object providing
+a powerful mechanism for revising the representation of an underlying
+<tt class="classname">TreeModel</tt>. This is described in <a href="sec-TreeModelSortAndTreeModelFilter.html#sec-TreeModelFilter" title="14.10.2. TreeModelFilter">Section 14.10.2, “TreeModelFilterâ€</a>.</li><li><tt class="classname">UIManager</tt> - an object providing a
+way to construct menus and toolbars from an XML UI description. It also has
+methods to manage the merging and separation of multiple UI
+descriptions.</li></ul></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-ActionsAndActionGroups"></a>16.1. The Action and ActionGroup Objects</h2></div></div><div></div></div><p>The <tt class="classname">Action</tt> and
+<tt class="classname">ActionGroup</tt> objects work together to provide the
+images, text, callbacks and accelerators for your application menus and
+toolbars. The <tt class="classname">UIManager</tt> uses
+<tt class="classname">Action</tt>s and <tt class="classname">ActionGroup</tt>s to
+build the menubars and toolbars automatically based on a XML
+specification. It's much easier to create and populate menus and toolbars
+using the <tt class="classname">UIManager</tt> described in a later section. The
+following sections on the <tt class="classname">Action</tt> and
+<tt class="classname">ActionGroup</tt> objects describe how to directly apply
+these objects but I recommend using the <tt class="classname">UIManager</tt>
+whenever possible.</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-Actions"></a>16.1.1. Actions</h3></div></div><div></div></div><p>An <tt class="classname">Action</tt> object represents an action that
+the user can take using an application user interface. It contains
+information used by proxy UI elements (for example,
+<tt class="classname">MenuItem</tt>s or <tt class="classname">Toolbar</tt> items) to
+present the action to the user. There are two subclasses of
+<tt class="classname">Action</tt>:</p><table border="0" width="100%" bgcolor="#FFECCE"><col align="left" valign="top" width="0*"><tbody><tr><td><span class="term">ToggleAction</span></td><td>An <tt class="classname">Action</tt> that can be toggled
+between two states.</td></tr><tr><td><span class="term">RadioAction</span></td><td>An <tt class="classname">Action</tt> that can be grouped so
+that only one can be active.</td></tr></tbody></table><p>For example, the standard <span class="guimenu">File</span>-&gt;<span class="guimenuitem">Quit</span> menu item can be represented
+with an icon, mnemonic text and accelerator. When activated, the menu item
+triggers a callback that could exit the application. Likewise a
+<tt class="classname">Toolbar</tt> <span class="guibutton">Quit</span> button could
+share the icon, mnemonic text and callback. Both of these UI elements could
+be proxies of the same <tt class="classname">Action</tt>.</p><p>Ordinary <tt class="classname">Button</tt>,
+<tt class="classname">ToggleButton</tt> and <tt class="classname">RadioButton</tt>
+widgets can also act as proxies for an <tt class="classname">Action</tt> though
+there is no support for these in the
+<tt class="classname">UIManager</tt>.</p><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="sec-CreatingActions"></a>16.1.1.1. Creating Actions</h4></div></div><div></div></div><p>An <tt class="classname">Action</tt> can be created using the
+constructor:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ action = gtk.Action(<b class="parameter"><tt>name</tt></b>, <b class="parameter"><tt>label</tt></b>, <b class="parameter"><tt>tooltip</tt></b>, <b class="parameter"><tt>stock_id</tt></b>)
+</pre></td></tr></table><p><i class="parameter"><tt>name</tt></i> is a string used to identify the
+<tt class="classname">Action</tt> in an <tt class="classname">ActionGroup</tt> or in
+a <tt class="classname">UIManager</tt>
+specification. <i class="parameter"><tt>label</tt></i> and
+<i class="parameter"><tt>tooltip</tt></i> are strings used as the label and tooltip in
+proxy widgets. If <i class="parameter"><tt>label</tt></i> is <tt class="literal">None</tt>
+then the <i class="parameter"><tt>stock_id</tt></i> must be a string specifying a Stock
+Item to get the label from. If <i class="parameter"><tt>tooltip</tt></i> is
+<tt class="literal">None</tt> the <tt class="classname">Action</tt> will not have a
+tooltip.</p><p>As we'll see in <a href="ch-NewInPyGTK2.4.html#sec-ActionGroups" title="16.1.2. ActionGroups">Section 16.1.2, “ActionGroupsâ€</a> it's
+much easier to create Action objects using the
+<tt class="classname">ActionGroup</tt> convenience methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ actiongroup.add_actions(<b class="parameter"><tt>entries</tt></b>, <b class="parameter"><tt>user_data</tt></b>=None)
+ actiongroup.add_toggle_actions(<b class="parameter"><tt>entries</tt></b>, <b class="parameter"><tt>user_data</tt></b>=None)
+ actiongroup.add_radio_actions(<b class="parameter"><tt>entries</tt></b>, <b class="parameter"><tt>value</tt></b>=0, <b class="parameter"><tt>on_change</tt></b>=None, <b class="parameter"><tt>user_data=None</tt></b>)
+</pre></td></tr></table><p>More about these later but first I'll describe how to use an
+<tt class="classname">Action</tt> with a <tt class="classname">Button</tt> to
+illustrate the basic operations of connecting an
+<tt class="classname">Action</tt> to a proxy widget.</p></div><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="sec-UsingActions"></a>16.1.1.2. Using Actions</h4></div></div><div></div></div><p>The basic procedure for using an <tt class="classname">Action</tt>
+with a <tt class="classname">Button</tt> proxy is illustrated by the <a href="examples/simpleaction.py" target="_top">simpleaction.py</a> example program. The
+<tt class="classname">Button</tt> is connected to the
+<tt class="classname">Action</tt> using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ action.connect_proxy(<b class="parameter"><tt>proxy</tt></b>)
+</pre></td></tr></table><p>where proxy is a <tt class="classname">MenuItem</tt>,
+<tt class="classname">ToolItem</tt> or <tt class="classname">Button</tt>
+widget.</p><p>An <tt class="classname">Action</tt> has one signal the "activate"
+signal that is triggered when the <tt class="classname">Action</tt> is activated
+usually as the result of a proxy widget being activated (for example a
+<tt class="classname">ToolButton</tt> is clicked). You just have connect a
+callback to this signal to handle the activation of any of the proxy
+widgets.</p><p>The source code for the <a href="examples/simpleaction.py" target="_top">simpleaction.py</a> example program
+is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 1 #!/usr/bin/env python
+ 2
+ 3 import pygtk
+ 4 pygtk.require('2.0')
+ 5 import gtk
+ 6
+ 7 class SimpleAction:
+ 8 def __init__(self):
+ 9 # Create the toplevel window
+ 10 window = gtk.Window()
+ 11 window.set_size_request(70, 30)
+ 12 window.connect('destroy', lambda w: gtk.main_quit())
+ 13
+ 14 # Create an accelerator group
+ 15 accelgroup = gtk.AccelGroup()
+ 16 # Add the accelerator group to the toplevel window
+ 17 window.add_accel_group(accelgroup)
+ 18
+ 19 # Create an action for quitting the program using a stock item
+ 20 action = gtk.Action('Quit', None, None, gtk.STOCK_QUIT)
+ 21 # Connect a callback to the action
+ 22 action.connect('activate', self.quit_cb)
+ 23
+ 24 # Create an ActionGroup named SimpleAction
+ 25 actiongroup = gtk.ActionGroup('SimpleAction')
+ 26 # Add the action to the actiongroup with an accelerator
+ 27 # None means use the stock item accelerator
+ 28 actiongroup.add_action_with_accel(action, None)
+ 29
+ 30 # Have the action use accelgroup
+ 31 action.set_accel_group(accelgroup)
+ 32
+ 33 # Connect the accelerator to the action
+ 34 action.connect_accelerator()
+ 35
+ 36 # Create the button to use as the action proxy widget
+ 37 quitbutton = gtk.Button()
+ 38 # add it to the window
+ 39 window.add(quitbutton)
+ 40
+ 41 # Connect the action to its proxy widget
+ 42 action.connect_proxy(quitbutton)
+ 43
+ 44 window.show_all()
+ 45 return
+ 46
+ 47 def quit_cb(self, b):
+ 48 print 'Quitting program'
+ 49 gtk.main_quit()
+ 50
+ 51 if __name__ == '__main__':
+ 52 sa = SimpleAction()
+ 53 gtk.main()
+</pre></td></tr></table><p>The example creates an <tt class="classname">Action</tt> (line 20)
+that uses a Stock Item to provide the label text with mnemonic, icon,
+accelerator and translation domain. If a Stock Item is not used you'll need
+to specify a label instead. Line 22 connects the "activate" signal of
+<i class="parameter"><tt>action</tt></i> to the <tt class="methodname">self.quit_cb</tt>()
+method so that it is invoked when the <tt class="classname">Action</tt> is
+activated by <i class="parameter"><tt>quitbutton</tt></i>. Line 42 connects
+<i class="parameter"><tt>quitbutton</tt></i> to <i class="parameter"><tt>action</tt></i> as a
+proxy widget. When <i class="parameter"><tt>quitbutton</tt></i> is clicked it will
+activate <i class="parameter"><tt>action</tt></i> and thereby invoke the
+<tt class="methodname">self.quit_cb</tt>() method. The <a href="examples/simpleaction.py" target="_top">simpleaction.py</a> example uses quite a
+bit of code (lines 15, 17, 31 and 34 to setup the accelerator for the
+<tt class="classname">Button</tt>. The procedure is similar for
+<tt class="classname">MenuItem</tt>s and <tt class="classname">Toolbar</tt>
+<tt class="classname">ToolItem</tt>s.</p><p><a href="ch-NewInPyGTK2.4.html#simpleactionfig" title="Figure 16.1. Simple Action Example">Figure 16.1, “Simple Action Exampleâ€</a> shows the <a href="examples/simpleaction.py" target="_top">simpleaction.py</a> example in
+operation.</p><div class="figure"><a name="simpleactionfig"></a><p class="title"><b>Figure 16.1. Simple Action Example</b></p><div class="mediaobject" align="center"><img src="figures/simpleaction.png" align="middle" alt="Simple Action Example"></div></div></div><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="sec-CreatingProxies"></a>16.1.1.3. Creating Proxy Widgets</h4></div></div><div></div></div><p>In the previous section we saw that an existing widget could be
+connected to an <tt class="classname">Action</tt> as a proxy. In this section
+we'll see how a proxy widget can be created using the
+<tt class="classname">Action</tt> methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ menuitem = action.create_menu_item()
+
+ toolitem = action.create_tool_item()
+</pre></td></tr></table><p>The <a href="examples/basicaction.py" target="_top">basicaction.py</a>
+example illustrates a <tt class="classname">MenuItem</tt>,
+<tt class="classname">ToolButton</tt> and a <tt class="classname">Button</tt>
+sharing an <tt class="classname">Action</tt>. The
+<tt class="classname">MenuItem</tt> and the <tt class="classname">ToolButton</tt>
+are created using the above methods. The <a href="examples/basicaction.py" target="_top">basicaction.py</a> example program source
+code is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 1 #!/usr/bin/env python
+ 2
+ 3 import pygtk
+ 4 pygtk.require('2.0')
+ 5 import gtk
+ 6
+ 7 class BasicAction:
+ 8 def __init__(self):
+ 9 # Create the toplevel window
+ 10 window = gtk.Window()
+ 11 window.connect('destroy', lambda w: gtk.main_quit())
+ 12 vbox = gtk.VBox()
+ 13 vbox.show()
+ 14 window.add(vbox)
+ 15
+ 16 # Create an accelerator group
+ 17 accelgroup = gtk.AccelGroup()
+ 18 # Add the accelerator group to the toplevel window
+ 19 window.add_accel_group(accelgroup)
+ 20
+ 21 # Create an action for quitting the program using a stock item
+ 22 action = gtk.Action('Quit', '_Quit me!', 'Quit the Program',
+ 23 gtk.STOCK_QUIT)
+ 24 action.set_property('short-label', '_Quit')
+ 25 # Connect a callback to the action
+ 26 action.connect('activate', self.quit_cb)
+ 27
+ 28 # Create an ActionGroup named BasicAction
+ 29 actiongroup = gtk.ActionGroup('BasicAction')
+ 30 # Add the action to the actiongroup with an accelerator
+ 31 # None means use the stock item accelerator
+ 32 actiongroup.add_action_with_accel(action, None)
+ 33
+ 34 # Have the action use accelgroup
+ 35 action.set_accel_group(accelgroup)
+ 36
+ 37 # Create a MenuBar
+ 38 menubar = gtk.MenuBar()
+ 39 menubar.show()
+ 40 vbox.pack_start(menubar, False)
+ 41
+ 42 # Create the File Action and MenuItem
+ 43 file_action = gtk.Action('File', '_File', None, None)
+ 44 actiongroup.add_action(file_action)
+ 45 file_menuitem = file_action.create_menu_item()
+ 46 menubar.append(file_menuitem)
+ 47
+ 48 # Create the File Menu
+ 49 file_menu = gtk.Menu()
+ 50 file_menuitem.set_submenu(file_menu)
+ 51
+ 52 # Create a proxy MenuItem
+ 53 menuitem = action.create_menu_item()
+ 54 file_menu.append(menuitem)
+ 55
+ 56 # Create a Toolbar
+ 57 toolbar = gtk.Toolbar()
+ 58 toolbar.show()
+ 59 vbox.pack_start(toolbar, False)
+ 60
+ 61 # Create a proxy ToolItem
+ 62 toolitem = action.create_tool_item()
+ 63 toolbar.insert(toolitem, 0)
+ 64
+ 65 # Create and pack a Label
+ 66 label = gtk.Label('''
+ 67 Select File-&gt;Quit me! or
+ 68 click the toolbar Quit button or
+ 69 click the Quit button below or
+ 70 press Control+q
+ 71 to quit.
+ 72 ''')
+ 73 label.show()
+ 74 vbox.pack_start(label)
+ 75
+ 76 # Create a button to use as another proxy widget
+ 77 quitbutton = gtk.Button()
+ 78 # add it to the window
+ 79 vbox.pack_start(quitbutton, False)
+ 80
+ 81 # Connect the action to its proxy widget
+ 82 action.connect_proxy(quitbutton)
+ 83 # Have to set tooltip after toolitem is added to toolbar
+ 84 action.set_property('tooltip', action.get_property('tooltip'))
+ 85 tooltips = gtk.Tooltips()
+ 86 tooltips.set_tip(quitbutton, action.get_property('tooltip'))
+ 87
+ 88 window.show()
+ 89 return
+ 90
+ 91 def quit_cb(self, b):
+ 92 print 'Quitting program'
+ 93 gtk.main_quit()
+ 94
+ 95 if __name__ == '__main__':
+ 96 ba = BasicAction()
+ 97 gtk.main()
+</pre></td></tr></table><p>This example introduces an <tt class="classname">ActionGroup</tt> to
+hold the <tt class="classname">Action</tt>s used in the program. <a href="ch-NewInPyGTK2.4.html#sec-ActionGroups" title="16.1.2. ActionGroups">Section 16.1.2, “ActionGroupsâ€</a> will go into more detail on the use of
+<tt class="classname">ActionGroup</tt>s.</p><p>The code in lines 9-14 sets up a top level window containing a
+<tt class="classname">VBox</tt>. Lines 16-35 set up the "Quit"
+<tt class="classname">Action</tt> similar to that in the <a href="examples/simpleaction.py" target="_top">simpleaction.py</a> example program and
+add it with the <tt class="literal">gtk.STOCK_QUIT</tt> Stock Item accelerator
+(line 32) to the "BasicAction" <tt class="classname">ActionGroup</tt> (created
+in line 29). Note that, unlike the <a href="examples/simpleaction.py" target="_top">simpleaction.py</a> example program, you
+don't have to call the <tt class="methodname">connect_accelerator</tt>() method
+for the action since it is called automatically when the
+<tt class="methodname">create_menu_item</tt>() method is called in line
+53.</p><p>Lines 38-40 create a <tt class="classname">MenuBar</tt> and pack it
+into the <tt class="classname">VBox</tt>. Lines 43-44 create an
+<tt class="classname">Action</tt> (<i class="parameter"><tt>file_action</tt></i>) for the
+<span class="guimenu">File</span> menu and add it to
+<i class="parameter"><tt>actiongroup</tt></i>. The <span class="guimenu">File</span> and
+<span class="guimenuitem">Quit</span> menu items are created in lines 45 and 53
+and added to <i class="parameter"><tt>menubar</tt></i> and
+<i class="parameter"><tt>file_menu</tt></i> respectively in lines 46 and 54.</p><p>Likewise a <tt class="classname">Toolbar</tt> is created and added
+to the <tt class="classname">VBox</tt> in lines 57-59. The proxy
+<tt class="classname">ToolItem</tt> is created and added to
+<i class="parameter"><tt>toolbar</tt></i> in lines 62-63. Note the
+<tt class="classname">Action</tt> tooltip must be set (line 84) after the
+<tt class="classname">ToolItem</tt> is added to the
+<tt class="classname">Toolbar</tt> for it to be used. Also the
+<tt class="classname">Button</tt> tooltip must be added manually (lines
+84-86).</p><p><a href="ch-NewInPyGTK2.4.html#basicactionfig" title="Figure 16.2. Basic Action Example">Figure 16.2, “Basic Action Exampleâ€</a> displays the <a href="examples/basicaction.py" target="_top">basicaction.py</a> example program in
+operation:</p><div class="figure"><a name="basicactionfig"></a><p class="title"><b>Figure 16.2. Basic Action Example</b></p><div class="mediaobject" align="center"><img src="figures/basicaction.png" align="middle" alt="Basic Action Example"></div></div><p>A proxy widget can be disconnected from an
+<tt class="classname">Action</tt> by using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ action.disconnect_proxy(<b class="parameter"><tt>proxy</tt></b>)
+</pre></td></tr></table></div><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="sec-ActionProperties"></a>16.1.1.4. Action Properties</h4></div></div><div></div></div><p>An <tt class="classname">Action</tt> has a number of properties that
+control the display and function of its proxy widgets. The most important of
+these are the "sensitive" and "visible" properties. The "sensitive" property
+determines the sensitivity of the proxy widgets. If "sensitive" is
+<tt class="literal">FALSE</tt> the proxy widgets are not activatable and will
+usually be displayed "grayed out". Likewise, the "visible" property
+determines whether the proxy widgets will be visible. If an
+<tt class="classname">Action</tt>'s "visible" property is
+<tt class="literal">FALSE</tt> its proxy widgets will be hidden.</p><p>As we'll see in the next section, an
+<tt class="classname">Action</tt>'s sensitivity or visibility is also controlled
+by the sensitivity or visibility of the <tt class="classname">ActionGroup</tt>
+it belongs to. Therefore, for an <tt class="classname">Action</tt> to be
+sensitive (or visible) both it and its <tt class="classname">ActionGroup</tt>
+must be sensitive (or visible). To determine the effective sensitivity or
+visibility of an <tt class="classname">Action</tt> you should use the following
+methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ result = action.is_sensitive()
+
+ result = action.is_visible()
+</pre></td></tr></table><p>The name assigned to an <tt class="classname">Action</tt> is
+contained in its "name" property which is set when the
+<tt class="classname">Action</tt> is created. You can retrieve that name using
+the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ name = action.get_name()
+</pre></td></tr></table><p>Other properties that control the display of the proxy widgets
+of an <tt class="classname">Action</tt> include:</p><table border="0" width="100%" bgcolor="#FFECCE"><col align="left" valign="top" width="0*"><tbody><tr><td><span class="term">"hide-if-empty"</span></td><td>If <tt class="literal">TRUE</tt>, empty menu proxies for this
+action are hidden.</td></tr><tr><td><span class="term">"is-important"</span></td><td>If <tt class="literal">TRUE</tt>,
+<tt class="classname">ToolItem</tt> proxies for this action show text in
+<tt class="literal">gtk.TOOLBAR_BOTH_HORIZ</tt> mode.</td></tr><tr><td><span class="term">"visible-horizontal"</span></td><td>If <tt class="literal">TRUE</tt>, the
+<tt class="classname">ToolItem</tt> is visible when the toolbar is in a
+horizontal orientation.</td></tr><tr><td><span class="term">"visible-vertical"</span></td><td>If <tt class="literal">TRUE</tt>, the
+<tt class="classname">ToolItem</tt> is visible when the toolbar is in a vertical
+orientation.</td></tr></tbody></table><p>Other properties of interest include:</p><table border="0" width="100%" bgcolor="#FFECCE"><col align="left" valign="top" width="0*"><tbody><tr><td><span class="term">"label"</span></td><td>The label used for menu items and buttons that activate
+this action.</td></tr><tr><td><span class="term">"short-label"</span></td><td>A shorter label that may be used on toolbar buttons and
+buttons.</td></tr><tr><td><span class="term">"stock-id"</span></td><td>The Stock Item to be used to retrieve the icon, label
+and accelerator to be used in widgets representing this action.</td></tr><tr><td><span class="term">"tooltip"</span></td><td>A tooltip for this action.</td></tr></tbody></table><p>Note that the <a href="examples/basicaction.py" target="_top">basicaction.py</a> example program
+overrides the <tt class="literal">gtk.STOCK_QUIT</tt> label with "_Quit me!" and
+sets the "short-label" property to "_Quit". The short label is used for the
+<tt class="classname">ToolButton</tt> and the <tt class="classname">Button</tt>
+labels but the full label is used for the <tt class="classname">MenuItem</tt>
+label. Also note that the tooltip cannot be set on a
+<tt class="classname">ToolItem</tt> until it is added to a
+<tt class="classname">Toolbar</tt>.</p></div><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="sec-ActionAccelerators"></a>16.1.1.5. Actions and Accelerators</h4></div></div><div></div></div><p>An <tt class="classname">Action</tt> has three methods that are used
+to set up an accelerator:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ action.set_accel_group(<b class="parameter"><tt>accel_group</tt></b>)
+
+ action.set_accel_path(<b class="parameter"><tt>accel_path</tt></b>)
+
+ action.connect_accelerator()
+</pre></td></tr></table><p>These, in conjunction with the
+<tt class="methodname">gtk.ActionGroup.add_action_with_accel</tt>() method,
+should cover most cases of accelerator set up.</p><p>An <tt class="classname">AccelGroup</tt> must always be set for an
+<tt class="classname">Action</tt>. The <tt class="methodname">set_accel_path</tt>()
+method is called by the
+<tt class="methodname">gtk.ActionGroup.add_action_with_accel</tt>() method. If
+<tt class="methodname">set_accel_path</tt>() is used the accelerator path
+should match the default format:
+"&lt;Actions&gt;/actiongroup_name/action_name". Finally, the
+<tt class="methodname">connect_accelerator</tt>() method is called to complete
+the accelerator set up.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>An <tt class="classname">Action</tt> must have an
+<tt class="classname">AccelGroup</tt> and an accelerator path associated with it
+before <tt class="methodname">connect_accelerator</tt>() is called.</p></div><p>Since the <tt class="methodname">connect_accelerator</tt>() method
+can be called several times (i.e. once for each proxy widget), the number of
+calls is counted so that an equal number of
+<tt class="methodname">disconnect_accelerator</tt>() calls must be made before
+removing the accelerator.</p><p>As illustrated in the previous example programs, an
+<tt class="classname">Action</tt> accelerator can be used by all the proxy
+widgets. An <tt class="classname">Action</tt> should be part of an
+<tt class="classname">ActionGroup</tt> in order to use the default accelerator
+path that has the format:
+"&lt;Actions&gt;/actiongroup_name/action_name". The easiest way to add an
+accelerator is to use the
+<tt class="methodname">gtk.ActionGroup.add_action_with_accel</tt>() method and
+the following general procedure:</p><div class="itemizedlist"><ul type="disc"><li>Create an <tt class="classname">AccelGroup</tt> and add it to
+the top level window.</li><li>Create a new <tt class="classname">ActionGroup</tt></li><li>Create an <tt class="classname">Action</tt> specifying a
+Stock Item with an accelerator.</li><li>Add the <tt class="classname">Action</tt> to the
+<tt class="classname">ActionGroup</tt> using the
+<tt class="methodname">gtk.ActionGroup.add_action_with_accel</tt>() method
+specifying <tt class="literal">None</tt> to use the Stock Item accelerator or an
+accelerator string acceptable to
+<tt class="function">gtk.accelerator_parse</tt>().</li><li>Set the <tt class="classname">AccelGroup</tt> for the
+<tt class="classname">Action</tt> using the
+<tt class="methodname">gtk.Action.set_accel_group</tt>() method.</li><li>Complete the accelerator set up using the
+<tt class="methodname">gtk.Action.connect_accelerator</tt>() method.</li></ul></div><p>Any proxy widgets created by or connected to the
+<tt class="classname">Action</tt> will use the accelerator.</p></div><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="sec-ToggleActions"></a>16.1.1.6. Toggle Actions</h4></div></div><div></div></div><p>As mentioned previously a <tt class="classname">ToggleAction</tt> is
+a subclass of <tt class="classname">Action</tt> that can be toggled between two
+states. The constructor for a <tt class="classname">ToggleAction</tt> takes the
+same parameters as an <tt class="classname">Action</tt>:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ toggleaction = gtk.ToggleAction(<b class="parameter"><tt>name</tt></b>, <b class="parameter"><tt>label</tt></b>, <b class="parameter"><tt>tooltip</tt></b>, <b class="parameter"><tt>stock_id</tt></b>)
+</pre></td></tr></table><p>In addition to the <tt class="classname">Action</tt> methods the
+following <tt class="classname">ToggleAction</tt> methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ toggleaction.set_active(<b class="parameter"><tt>is_active</tt></b>)
+ is_active = toggleaction.get_active()
+</pre></td></tr></table><p>set and get the current state of
+<i class="parameter"><tt>toggleaction</tt></i>. <i class="parameter"><tt>is_active</tt></i> is a
+boolean value.</p><p>You can connect to the "toggled" signal specifying a callback
+with the signature:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def toggled_cb(<i class="parameter"><tt>toggleaction</tt></i>, <i class="parameter"><tt>user_data</tt></i>)
+</pre></td></tr></table><p>The "toggled" signal is emitted when the
+<tt class="classname">ToggleAction</tt> changes state.</p><p>A <tt class="classname">MenuItem</tt> proxy widget of a
+<tt class="classname">ToggleAction</tt> will be displayed like a
+<tt class="classname">CheckMenuItem</tt> by default. To have the proxy
+<tt class="classname">MenuItem</tt> displayed like a
+<tt class="classname">RadioMenuItem</tt> set the "draw-as-radio" property to
+<tt class="literal">TRUE</tt> using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ toggleaction.set_draw_as_radio(<b class="parameter"><tt>draw_as_radio</tt></b>)
+</pre></td></tr></table><p>You can use the following method to determine whether the
+<tt class="classname">ToggleAction</tt> <tt class="classname">MenuItem</tt>s will be
+displayed like <tt class="classname">RadioMenuItem</tt>s:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ draw_as_radio = toggleaction.get_draw_as_radio()
+</pre></td></tr></table></div><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="sec-RadioActions"></a>16.1.1.7. Radio Actions</h4></div></div><div></div></div><p>A <tt class="classname">RadioAction</tt> is a subclass of
+<tt class="classname">ToggleAction</tt> that can be grouped so that only one
+<tt class="classname">RadioAction</tt> is active at a time. The corresponding
+proxy widgets are the <tt class="classname">RadioMenuItem</tt> and
+<tt class="classname">RadioToolButton</tt>.</p><p>The constructor for a <tt class="classname">RadioAction</tt> takes
+the same arguments as an <tt class="classname">Action</tt> with the addition of
+a unique integer value that is used to identify the active
+<tt class="classname">RadioAction</tt> in a group:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ radioaction = gtk.RadioAction(<tt class="classname">name</tt>, <tt class="classname">label</tt>, <tt class="classname">tooltip</tt>, <tt class="classname">stock_id</tt>, <tt class="classname">value</tt>)
+</pre></td></tr></table><p>The group for a <tt class="classname">RadioAction</tt> can be set
+using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ radioaction.set_group(<b class="parameter"><tt>group</tt></b>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>group</tt></i> is another
+<tt class="classname">RadioAction</tt> that <i class="parameter"><tt>radioaction</tt></i>
+should be grouped with. The group containing a
+<tt class="classname">RadioAction</tt> can be retrieved using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ group = radioaction.get_group()
+</pre></td></tr></table><p>that returns a list of the group of
+<tt class="classname">RadioAction</tt> objects that includes
+<i class="parameter"><tt>radioaction</tt></i>.</p><p>The value of the currently active group member can retrieved
+using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ active_value = radioaction.get_current_value()
+</pre></td></tr></table><p>You can connect a callback to the "changed" signal to be
+notified when the active member of the <tt class="classname">RadioAction</tt>
+group has been changed. Note that you only have to connect to one of the
+<tt class="classname">RadioAction</tt> objects to track changes. The callback
+signature is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def changed_cb(<i class="parameter"><tt>radioaction</tt></i>, <i class="parameter"><tt>current</tt></i>, <i class="parameter"><tt>user_data</tt></i>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>current</tt></i> is the currently active
+<tt class="classname">RadioAction</tt> in the group.</p></div><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="sec-ActionsExample"></a>16.1.1.8. An Actions Example</h4></div></div><div></div></div><p>The <a href="examples/actions.py" target="_top">actions.py</a> example
+program illustrates the use of the <tt class="classname">Action</tt>,
+<tt class="classname">ToggleAction</tt> and <tt class="classname">RadioAction</tt>
+objects. <a href="ch-NewInPyGTK2.4.html#actionsfig" title="Figure 16.3. Actions Example">Figure 16.3, “Actions Exampleâ€</a> displays the example
+program in operation:</p><div class="figure"><a name="actionsfig"></a><p class="title"><b>Figure 16.3. Actions Example</b></p><div class="mediaobject" align="center"><img src="figures/actions.png" align="middle" alt="Actions Example"></div></div><p>This example is similar enough to the <a href="examples/basicaction.py" target="_top">basicaction.py</a> example program that a
+detailed description is not necessary.</p></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-ActionGroups"></a>16.1.2. ActionGroups</h3></div></div><div></div></div><p>As mentioned in the previous section, related
+<tt class="classname">Action</tt> objects should be added to an
+<tt class="classname">ActionGroup</tt> to provide common control over their
+visibility and sensitivity. For example, in a text processing application
+the menu items and toolbar buttons for specifying the text justification
+could be contained in an <tt class="classname">ActionGroup</tt>. A user
+interface is expected to have multiple <tt class="classname">ActionGroup</tt>
+objects that cover various aspects of the application. For example, global
+actions like creating new documents, opening and saving a document and
+quitting the application likely form one <tt class="classname">ActionGroup</tt>
+while actions such as modifying the view of the document would form
+another.</p><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="sec-CreatingActionGroups"></a>16.1.2.1. Creating ActionGroups</h4></div></div><div></div></div><p>An <tt class="classname">ActionGroup</tt> is created using the
+constructor:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ actiongroup = gtk.ActionGroup(<b class="parameter"><tt>name</tt></b>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>name</tt></i> is a unique name for the
+<tt class="classname">ActionGroup</tt>. The name should be unique because it is
+used to form the default accelerator path for its
+<tt class="classname">Action</tt> objects.</p><p>The <i class="parameter"><tt>ActionGroup</tt></i> name can be retrieved
+using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ name = actiongroup.get_name()
+</pre></td></tr></table><p>or by retrieving the contents of the "name" property.</p></div><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="sec-AddingActions"></a>16.1.2.2. Adding Actions</h4></div></div><div></div></div><p>As illustrated in <a href="ch-NewInPyGTK2.4.html#sec-Actions" title="16.1.1. Actions">Section 16.1.1, “Actionsâ€</a> an
+existing <tt class="classname">Action</tt> can be added to an
+<tt class="classname">ActionGroup</tt> using one of the methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ actiongroup.add_action(<b class="parameter"><tt>action</tt></b>)
+
+ actiongroup.add_action_with_accel(<b class="parameter"><tt>action</tt></b>, <b class="parameter"><tt>accelerator</tt></b>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>action</tt></i> is the
+<tt class="classname">Action</tt> to be added and
+<i class="parameter"><tt>accelerator</tt></i> is a string accelerator specification
+acceptable to <tt class="function">gtk.accelerator_parse</tt>(). If
+<i class="parameter"><tt>accelerator</tt></i> is <tt class="literal">None</tt> the
+accelerator (if any) associated with the "stock-id" property of
+<i class="parameter"><tt>action</tt></i> will be used. As previously noted the
+<tt class="methodname">add_action_wih_accel</tt>() method is preferred if you
+want to use accelerators.</p><p>The <tt class="classname">ActionGroup</tt> offers three convenience
+methods that make the job of creating and adding
+<tt class="classname">Action</tt> objects to an
+<tt class="classname">ActionGroup</tt> much easier:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ actiongroup.add_actions(<b class="parameter"><tt>entries</tt></b>, <b class="parameter"><tt>user_data</tt></b>=None)
+
+ actiongroup.add_toggle_actions(<b class="parameter"><tt>entries</tt></b>, <b class="parameter"><tt>user_data</tt></b>=None)
+
+ actiongroup.add_radio_actions(<b class="parameter"><tt>entries</tt></b>, <b class="parameter"><tt>value</tt></b>=0, <b class="parameter"><tt>on_change</tt></b>=None, <b class="parameter"><tt>user_data</tt></b>=None)
+</pre></td></tr></table><p>The <i class="parameter"><tt>entries</tt></i> parameter is a sequence of
+action entry tuples that provide the information used to create the actions
+that are added to the <tt class="classname">ActionGroup</tt>. The
+<tt class="classname">RadioAction</tt> with the value of
+<i class="parameter"><tt>value</tt></i> is initially set
+active. <i class="parameter"><tt>on_change</tt></i> is a callback that is connected to
+the "changed" signal of the first <tt class="classname">RadioAction</tt> in the
+group. The signature of <i class="parameter"><tt>on_changed</tt></i> is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def on_changed_cb(<i class="parameter"><tt>radioaction</tt></i>, <i class="parameter"><tt>current</tt></i>, <i class="parameter"><tt>user_data</tt></i>)
+</pre></td></tr></table><p>The entry tuples for <tt class="classname">Action</tt> objects
+contain:</p><div class="itemizedlist"><ul type="disc"><li>The name of the action. Must be specified.</li><li>The stock id for the action. Optional with a default
+value of <tt class="literal">None</tt> if a label is specified.</li><li>The label for the action. Optional with a default value of
+<tt class="literal">None</tt> if a stock id is specified.</li><li>The accelerator for the action, in the format understood by
+the <tt class="function">gtk.accelerator_parse</tt>() function. Optional with a
+default value of <tt class="literal">None</tt>.</li><li>The tooltip for the action. Optional with a default value
+of <tt class="literal">None</tt>.</li><li>The callback function invoked when the action is
+activated. Optional with a default value of
+<tt class="literal">None</tt>.</li></ul></div><p>You must minimally specify a value for the
+<i class="parameter"><tt>name</tt></i> field and a value in either the <i class="parameter"><tt>stock
+id</tt></i> field or the <i class="parameter"><tt>label</tt></i> field. If you
+specify a label then you can specify <tt class="literal">None</tt> for the stock
+id if you aren't using one. For example the following method call:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ actiongroup.add_actions([('quit', gtk.STOCK_QUIT, '_Quit me!', None,
+ 'Quit the Program', quit_cb)])
+</pre></td></tr></table><p>adds an action to <i class="parameter"><tt>actiongroup</tt></i> for
+exiting a program.</p><p>The entry tuples for the <tt class="classname">ToggleAction</tt>
+objects are similar to the <tt class="classname">Action</tt> entry tuples except
+there is an additional optional <i class="parameter"><tt>flag</tt></i> field containing
+a boolean value indicating whether the action is active. The default value
+for the <i class="parameter"><tt>flag</tt></i> field is <tt class="literal">FALSE</tt>. For
+example the following method call:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ actiongroup.add_toggle_actions([('mute, None, '_Mute', '&lt;control&gt;m',
+ 'Mute the volume', mute_cb, True)])
+</pre></td></tr></table><p>adds a <tt class="classname">ToggleAction</tt> to
+<i class="parameter"><tt>actiongroup</tt></i> and sets it to be initially
+active.</p><p>The entry tuples for the <tt class="classname">RadioAction</tt>
+objects are similar to the <tt class="classname">Action</tt> entry tuples but
+specify a <i class="parameter"><tt>value</tt></i> field instead of a
+<i class="parameter"><tt>callback</tt></i> field:</p><div class="itemizedlist"><ul type="disc"><li>The name of the action. Must be specified.</li><li>The stock id for the action. Optional with a default
+value of <tt class="literal">None</tt> if a label is specified.</li><li>The label for the action.Optional with a default value of
+<tt class="literal">None</tt> if a stock id is specified.</li><li>The accelerator for the action, in the format understood by
+the <tt class="function">gtk.accelerator_parse</tt>() function. Optional with a
+default value of <tt class="literal">None</tt>.</li><li>The tooltip for the action. Optional with a default value
+of <tt class="literal">None</tt>.</li><li>The value to set on the radio action. Optional with a
+default value of <tt class="literal">0</tt>. Should always be specified in
+applications.</li></ul></div><p>For example the following code fragment:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ radioactionlist = [('am', None, '_AM', '&lt;control&gt;a', 'AM Radio', 0)
+ ('fm', None, '_FM', '&lt;control&gt;f', 'FM Radio', 1)
+ ('ssb', None, '_SSB', '&lt;control&gt;s', 'SSB Radio', 2)]
+ actiongroup.add_radio_actions(radioactionlist, 0, changed_cb)
+</pre></td></tr></table><p>creates three <tt class="classname">RadioAction</tt> objects and
+sets the initial active action to 'am' and the callback that is invoked when
+any of the actions is activated to <tt class="function">changed_cb</tt>.</p></div><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="sec-RetrievingActions"></a>16.1.2.3. Retrieving Actions</h4></div></div><div></div></div><p>An <tt class="classname">Action</tt> can be retrieved by name from
+an <tt class="classname">ActionGroup</tt> by using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ action = actiongroup.get_action(<b class="parameter"><tt>action_name</tt></b>)
+</pre></td></tr></table><p>A list of all the <tt class="classname">Action</tt> objects
+contained in an <tt class="classname">ActionGroup</tt> can be retrieved using
+the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ actionlist = actiongroup.list_actions()
+</pre></td></tr></table></div><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="sec-ControllingActions"></a>16.1.2.4. Controlling Actions</h4></div></div><div></div></div><p>The sensitivity and visibility of all
+<tt class="classname">Action</tt> objects in an
+<tt class="classname">ActionGroup</tt> can be controlled by setting the
+associated property values. The following convenience methods get and set
+the properties:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ is_sensitive = actiongroup.get_sensitive()
+ actiongroup.set_sensitive(sensitive)
+
+ is_visible = actiongroup.get_visible()
+ actiongroup.set_visible(visible)
+</pre></td></tr></table><p>Finally you can remove an <tt class="classname">Action</tt> from an
+<tt class="classname">ActionGroup</tt> using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ actiongroup.remove_action(<b class="parameter"><tt>action</tt></b>)
+</pre></td></tr></table></div><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="sec-ActionGroupExample"></a>16.1.2.5. An ActionGroup Example</h4></div></div><div></div></div><p>The <a href="examples/actiongroup.py" target="_top">actiongroup.py</a>
+example program duplicates the menubar and toolbar of the <a href="examples/actions.py" target="_top">actions.py</a> example program using the
+<tt class="classname">ActionGroup</tt> methods. In addition the program provides
+buttons to control the sensitivity and visibility of the menu items and
+toolbar items. <a href="ch-NewInPyGTK2.4.html#actiongroupfig" title="Figure 16.4. ActionGroup Example">Figure 16.4, “ActionGroup Exampleâ€</a> illustrates the
+program in operation:</p><div class="figure"><a name="actiongroupfig"></a><p class="title"><b>Figure 16.4. ActionGroup Example</b></p><div class="mediaobject" align="center"><img src="figures/actiongroup.png" align="middle" alt="ActionGroup Example"></div></div></div><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="sec-ActionGroupSignals"></a>16.1.2.6. ActionGroup Signals</h4></div></div><div></div></div><p>Your application can track the connection and removal of proxy
+widgets to the <tt class="classname">Action</tt> objects in an
+<tt class="classname">ActionGroup</tt> using the "connect-proxy" and
+disconnect-proxy" signals. The signatures of your signal handler callbacks
+should be:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def connect_proxy_cb(<i class="parameter"><tt>actiongroup</tt></i>, <i class="parameter"><tt>action</tt></i>, <i class="parameter"><tt>proxy</tt></i>, <i class="parameter"><tt>user_params</tt></i>)
+
+ def disconnect_proxy_cb(<i class="parameter"><tt>actiongroup</tt></i>, <i class="parameter"><tt>action</tt></i>, <i class="parameter"><tt>proxy</tt></i>, <i class="parameter"><tt>user_params</tt></i>)
+</pre></td></tr></table><p>For example, you might want to track these changes to make some
+additional changes to the properties of the new proxy widget when it is
+connected or to update some other part of the user interface when a proxy
+widget is disconnected.</p><p>The "pre-activate" and "post-activate" signals allow your
+application to do some additional processing immediately before or after an
+action is activated. The signatures of the signal handler callbacks should
+be:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def pre_activate_cb(actiongroup, action, user_params)
+
+ def post_activate_cb(actiongroup, action, user_params)
+</pre></td></tr></table><p>These signals are mostly used by the
+<tt class="classname">UIManager</tt> to provide global notification for all
+<tt class="classname">Action</tt> objects in <tt class="classname">ActionGroup</tt>
+objects used by it.</p></div></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch-NewInPyGTK2.2.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="index.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-ComboBoxAndComboboxEntry.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 15. New Widgets in PyGTK 2.2 </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 16.2. ComboBox and ComboBoxEntry Widgets</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/ch-PackingWidgets.html b/help/Pygtk2Tutorial/pygtk2tutorial/ch-PackingWidgets.html
new file mode 100644
index 0000000..350adf9
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/ch-PackingWidgets.html
@@ -0,0 +1,29 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>Chapter 4. Packing Widgets</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="previous" href="sec-UpgradedHelloWorld.html" title="3.2. An Upgraded Hello World"><link rel="next" href="sec-DetailsOfBoxes.html" title="4.2. Details of Boxes"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 4. Packing Widgets</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-UpgradedHelloWorld.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="sec-DetailsOfBoxes.html">Next</a></td></tr></table><hr></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="ch-PackingWidgets"></a>Chapter 4. Packing Widgets</h2></div></div><div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="ch-PackingWidgets.html#sec-TheoryOfPackingBoxes">4.1. Theory of Packing Boxes</a></span></dt><dt><span class="sect1"><a href="sec-DetailsOfBoxes.html">4.2. Details of Boxes</a></span></dt><dt><span class="sect1"><a href="sec-PackingDemonstrationProgram.html">4.3. Packing Demonstration Program</a></span></dt><dt><span class="sect1"><a href="sec-PackingUsingTables.html">4.4. Packing Using Tables</a></span></dt><dt><span class="sect1"><a href="sec-TablePackingExample.html">4.5. Table Packing Example</a></span></dt></dl></div><p>When creating an application, you'll want to put more than one
+widget inside a window. Our first helloworld example only used one widget so
+we could simply use the <tt class="classname">gtk.Container</tt>
+<tt class="methodname">add</tt>() method to "pack" the widget into the window. But
+when you want to put more than one widget into a window, how do you control
+where that widget is positioned? This is where packing comes in.</p><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-TheoryOfPackingBoxes"></a>4.1. Theory of Packing Boxes</h2></div></div><div></div></div><p>Most packing is done by creating boxes. These are invisible
+widget containers that we can pack our widgets into which come in two forms,
+a horizontal box, and a vertical box. When packing widgets into a horizontal
+box, the objects are inserted horizontally from left to right or right to
+left depending on the call used. In a vertical box, widgets are packed from
+top to bottom or vice versa. You may use any combination of boxes inside or
+beside other boxes to create the desired effect.</p><p>To create a new horizontal box, we use a call to
+<tt class="function">gtk.HBox</tt>(), and for vertical boxes,
+<tt class="function">gtk.VBox</tt>() . The <tt class="methodname">pack_start</tt>() and
+<tt class="methodname">pack_end</tt>() methods are used to place objects inside of
+these containers. The <tt class="methodname">pack_start</tt>() method will start at
+the top and work its way down in a vbox, and pack left to right in an hbox.
+The <tt class="methodname">pack_end</tt>() method will do the opposite, packing
+from bottom to top in a vbox, and right to left in an hbox. Using these
+methods allows us to right justify or left justify our widgets and may be
+mixed in any way to achieve the desired effect. We will use
+<tt class="methodname">pack_start</tt>() in most of our examples. An object may be
+another container or a widget. In fact, many widgets are actually containers
+themselves, including the button, but we usually only use a label inside a
+button.</p><p>By using these calls, GTK knows where you want to place your
+widgets so it can do automatic resizing and other nifty things. There are
+also a number of options as to how your widgets should be packed. As you can
+imagine, this method gives us a quite a bit of flexibility when placing and
+creating widgets.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-UpgradedHelloWorld.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="index.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-DetailsOfBoxes.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">3.2. An Upgraded Hello World </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 4.2. Details of Boxes</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/ch-RangeWidgets.html b/help/Pygtk2Tutorial/pygtk2tutorial/ch-RangeWidgets.html
new file mode 100644
index 0000000..3391cca
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/ch-RangeWidgets.html
@@ -0,0 +1,30 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>Chapter 8. Range Widgets</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="previous" href="sec-AdjustmentInternals.html" title="7.3. Adjustment Internals"><link rel="next" href="sec-ScaleWidgets.html" title="8.2. Scale Widgets"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 8. Range Widgets</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-AdjustmentInternals.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="sec-ScaleWidgets.html">Next</a></td></tr></table><hr></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="ch-RangeWidgets"></a>Chapter 8. Range Widgets</h2></div></div><div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="ch-RangeWidgets.html#sec-ScrollbarWidgets">8.1. Scrollbar Widgets</a></span></dt><dt><span class="sect1"><a href="sec-ScaleWidgets.html">8.2. Scale Widgets</a></span></dt><dd><dl><dt><span class="sect2"><a href="sec-ScaleWidgets.html#id2833070">8.2.1. Creating a Scale Widget</a></span></dt><dt><span class="sect2"><a href="sec-ScaleWidgets.html#id2833123">8.2.2. Methods and Signals (well, methods, at least)</a></span></dt></dl></dd><dt><span class="sect1"><a href="sec-CommonRangeMethods.html">8.3. Common Range Methods</a></span></dt><dd><dl><dt><span class="sect2"><a href="sec-CommonRangeMethods.html#id2785803">8.3.1. Setting the Update Policy</a></span></dt><dt><span class="sect2"><a href="sec-CommonRangeMethods.html#id2785875">8.3.2. Getting and Setting Adjustments</a></span></dt></dl></dd><dt><span class="sect1"><a href="sec-KeyAndMouseBindings.html">8.4. Key and Mouse Bindings</a></span></dt><dt><span class="sect1"><a href="sec-RangeWidgetEample.html">8.5. Range Widget Example</a></span></dt></dl></div><p>The category of range widgets includes the ubiquitous scrollbar
+widget and the less common "scale" widget. Though these two types of widgets
+are generally used for different purposes, they are quite similar in
+function and implementation. All range widgets share a set of common graphic
+elements, each of which has its own X window and receives events. They all
+contain a "trough" and a "slider" (what is sometimes called a "thumbwheel"
+in other GUI environments). Dragging the slider with the pointer moves it
+back and forth within the trough, while clicking in the trough advances the
+slider towards the location of the click, either completely, or by a
+designated amount, depending on which mouse button is used.</p><p>As mentioned in <a href="ch-Adjustments.html" title="Chapter 7. Adjustments">Chapter 7, <i>Adjustments</i></a> above, all
+range widgets are associated with an <tt class="classname">Adjustment</tt>
+object, from which they calculate the length of the slider and its position
+within the trough. When the user manipulates the slider, the range widget
+will change the value of the adjustment.</p><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-ScrollbarWidgets"></a>8.1. Scrollbar Widgets</h2></div></div><div></div></div><p>These are your standard, run-of-the-mill scrollbars. These
+should be used only for scrolling some other widget, such as a list, a text
+box, or a viewport (and it's generally easier to use the scrolled window
+widget in most cases). For other purposes, you should use scale widgets, as
+they are friendlier and more featureful.</p><p>There are separate types for horizontal and vertical scrollbars.
+There really isn't much to say about these. You create them with the
+following methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ hscrollbar = gtk.HSscrollbar(<b class="parameter"><tt>adjustment</tt></b>=None)
+
+ vscrollbar = gtk.VSscrollbar(<b class="parameter"><tt>adjustment</tt></b>=None)
+</pre></td></tr></table><p>and that's about it. The <i class="parameter"><tt>adjustment</tt></i>
+argument can either be a reference to an existing
+<tt class="classname">Adjustment</tt> (see <a href="ch-Adjustments.html" title="Chapter 7. Adjustments">Chapter 7, <i>Adjustments</i></a>), or nothing, in which case one will be
+created for you. Specifying nothing might be useful in the case, where you
+wish to pass the newly-created adjustment to the constructor function of
+some other widget which will configure it for you, such as a text
+widget.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-AdjustmentInternals.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="index.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-ScaleWidgets.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">7.3. Adjustment Internals </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 8.2. Scale Widgets</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/ch-Scribble.html b/help/Pygtk2Tutorial/pygtk2tutorial/ch-Scribble.html
new file mode 100644
index 0000000..0f0498b
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/ch-Scribble.html
@@ -0,0 +1,3 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>Chapter 24. Scribble, A Simple Example Drawing Program</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="previous" href="sec-ExampleRcFile.html" title="23.3. Example rc file"><link rel="next" href="sec-EventHandling.html" title="24.2. Event Handling"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 24. Scribble, A Simple Example Drawing Program</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-ExampleRcFile.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="sec-EventHandling.html">Next</a></td></tr></table><hr></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="ch-Scribble"></a>Chapter 24. Scribble, A Simple Example Drawing Program</h2></div></div><div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="ch-Scribble.html#sec-ScribbleOverview">24.1. Scribble Overview</a></span></dt><dt><span class="sect1"><a href="sec-EventHandling.html">24.2. Event Handling</a></span></dt><dd><dl><dt><span class="sect2"><a href="sec-EventHandling.html#id2867711">24.2.1. Scribble - Event Handling</a></span></dt></dl></dd><dt><span class="sect1"><a href="sec-DrawingAreaWidgetAndDrawing.html">24.3. The DrawingArea Widget, And Drawing</a></span></dt></dl></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-ScribbleOverview"></a>24.1. Scribble Overview</h2></div></div><div></div></div><p>In this section, we will build a simple drawing program. In the
+process, we will examine how to handle mouse events, how to draw in a
+window, and how to do drawing better by using a backing pixmap.</p><div class="figure"><a name="scribblesimplefig"></a><p class="title"><b>Figure 24.1. Scribble Drawing Program Example</b></p><div class="mediaobject" align="center"><img src="figures/scribblesimple.png" align="middle" alt="Scribble Drawing Program Example"></div></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-ExampleRcFile.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="index.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-EventHandling.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">23.3. Example rc file </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 24.2. Event Handling</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/ch-SettingWidgetAttributes.html b/help/Pygtk2Tutorial/pygtk2tutorial/ch-SettingWidgetAttributes.html
new file mode 100644
index 0000000..40e4a5c
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/ch-SettingWidgetAttributes.html
@@ -0,0 +1,47 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>Chapter 18. Setting Widget Attributes</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="previous" href="sec-GammaCurve.html" title="17.6. Gamma Curve"><link rel="next" href="sec-WidgetDisplayMethods.html" title="18.2. Widget Display Methods"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 18. Setting Widget Attributes</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-GammaCurve.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="sec-WidgetDisplayMethods.html">Next</a></td></tr></table><hr></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="ch-SettingWidgetAttributes"></a>Chapter 18. Setting Widget Attributes</h2></div></div><div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="ch-SettingWidgetAttributes.html#sec-WidgetFlagMethods">18.1. Widget Flag Methods</a></span></dt><dt><span class="sect1"><a href="sec-WidgetDisplayMethods.html">18.2. Widget Display Methods</a></span></dt><dt><span class="sect1"><a href="sec-WidgetAccelerators.html">18.3. Widget Accelerators</a></span></dt><dt><span class="sect1"><a href="sec-WidgetNameMethods.html">18.4. Widget Name Methods</a></span></dt><dt><span class="sect1"><a href="sec-WidgetStyles.html">18.5. Widget Styles</a></span></dt></dl></div><p>This describes the methods used to operate on widgets (and
+objects). These can be used to set style, padding, size, etc.</p><p>The method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ widget.activate()
+</pre></td></tr></table><p>causes the widget to emit the "activate" signal.</p><p>The method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ widget.set_sensitive(<b class="parameter"><tt>sensitive</tt></b>)
+</pre></td></tr></table><p>sets the sensitivity of the widget (i.e. does it react to events).
+if <i class="parameter"><tt>sensitive</tt></i> is <tt class="literal">TRUE</tt> the widget
+will receive events; if <tt class="literal">FALSE</tt> the widget will not receive
+events. A widget that is insensitive is usually displayed "grayed
+out".</p><p>The method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ widget.set_size_request(<b class="parameter"><tt>width</tt></b>, <b class="parameter"><tt>height</tt></b>)
+</pre></td></tr></table><p>sets the widget size to the given <i class="parameter"><tt>width</tt></i> and
+<i class="parameter"><tt>height</tt></i>.</p><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-WidgetFlagMethods"></a>18.1. Widget Flag Methods</h2></div></div><div></div></div><p>The methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ widget.set_flags(<b class="parameter"><tt>flags</tt></b>)
+
+ widget.unset_flags(<b class="parameter"><tt>flags</tt></b>)
+
+ flags = widget.flags()
+</pre></td></tr></table><p>set, unset and get the <tt class="classname">gtk.Object</tt> and
+<tt class="classname">gtk.Widget</tt> flags. <i class="parameter"><tt>flags</tt></i> can be
+any of the standard flags:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ IN_DESTRUCTION
+ FLOATING
+ RESERVED_1
+ RESERVED_2
+ TOPLEVEL
+ NO_WINDOW
+ REALIZED
+ MAPPED
+ VISIBLE
+ SENSITIVE
+ PARENT_SENSITIVE
+ CAN_FOCUS
+ HAS_FOCUS
+ CAN_DEFAULT
+ HAS_DEFAULT
+ HAS_GRAB
+ RC_STYLE
+ COMPOSITE_CHILD
+ NO_REPARENT
+ APP_PAINTABLE
+ RECEIVES_DEFAULT
+ DOUBLE_BUFFERED
+</pre></td></tr></table><p>The method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ widget.grab_focus()
+</pre></td></tr></table><p>allows a widget to grab the focus assuming that it has the
+<tt class="literal">CAN_FOCUS</tt> flag set.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-GammaCurve.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="index.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-WidgetDisplayMethods.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">17.6. Gamma Curve </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 18.2. Widget Display Methods</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/ch-TextViewWidget.html b/help/Pygtk2Tutorial/pygtk2tutorial/ch-TextViewWidget.html
new file mode 100644
index 0000000..1c7e76c
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/ch-TextViewWidget.html
@@ -0,0 +1,40 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>Chapter 13. TextView Widget</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="previous" href="sec-DrawingMethods.html" title="12.2. Drawing Methods"><link rel="next" href="sec-TextViews.html" title="13.2. TextViews"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 13. TextView Widget</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-DrawingMethods.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="sec-TextViews.html">Next</a></td></tr></table><hr></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="ch-TextViewWidget"></a>Chapter 13. TextView Widget</h2></div></div><div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="ch-TextViewWidget.html#sec-TextViewOverview">13.1. TextView Overview</a></span></dt><dt><span class="sect1"><a href="sec-TextViews.html">13.2. TextViews</a></span></dt><dt><span class="sect1"><a href="sec-TextBuffers.html">13.3. Text Buffers</a></span></dt><dd><dl><dt><span class="sect2"><a href="sec-TextBuffers.html#id2841804">13.3.1. TextBuffer Status Information</a></span></dt><dt><span class="sect2"><a href="sec-TextBuffers.html#id2841858">13.3.2. Creating TextIters</a></span></dt><dt><span class="sect2"><a href="sec-TextBuffers.html#id2855040">13.3.3. Text Insertion, Retrieval and Deletion</a></span></dt><dt><span class="sect2"><a href="sec-TextBuffers.html#id2855411">13.3.4. TextMarks</a></span></dt><dt><span class="sect2"><a href="sec-TextBuffers.html#id2855626">13.3.5. Creating and Applying TextTags</a></span></dt><dt><span class="sect2"><a href="sec-TextBuffers.html#id2855808">13.3.6. Inserting Images and Widgets</a></span></dt></dl></dd><dt><span class="sect1"><a href="sec-TextIters.html">13.4. Text Iters</a></span></dt><dd><dl><dt><span class="sect2"><a href="sec-TextIters.html#id2856073">13.4.1. TextIter Attributes</a></span></dt><dt><span class="sect2"><a href="sec-TextIters.html#id2856114">13.4.2. Text Attributes at a TextIter</a></span></dt><dt><span class="sect2"><a href="sec-TextIters.html#id2856416">13.4.3. Copying a TextIter</a></span></dt><dt><span class="sect2"><a href="sec-TextIters.html#id2856436">13.4.4. Retrieving Text and Objects</a></span></dt><dt><span class="sect2"><a href="sec-TextIters.html#id2856479">13.4.5. Checking Conditions at a TextIter</a></span></dt><dt><span class="sect2"><a href="sec-TextIters.html#id2856726">13.4.6. Checking Location in Text</a></span></dt><dt><span class="sect2"><a href="sec-TextIters.html#id2856824">13.4.7. Moving Through Text</a></span></dt><dt><span class="sect2"><a href="sec-TextIters.html#id2856958">13.4.8. Moving to a Specific Location</a></span></dt><dt><span class="sect2"><a href="sec-TextIters.html#id2857050">13.4.9. Searching in Text</a></span></dt></dl></dd><dt><span class="sect1"><a href="sec-TextMarks.html">13.5. Text Marks</a></span></dt><dt><span class="sect1"><a href="sec-TextTagsAndTextTagTables.html">13.6. Text Tags and Tag Tables</a></span></dt><dd><dl><dt><span class="sect2"><a href="sec-TextTagsAndTextTagTables.html#sec-TextTags">13.6.1. Text Tags</a></span></dt><dt><span class="sect2"><a href="sec-TextTagsAndTextTagTables.html#sec-TextTagTables">13.6.2. Text Tag Tables</a></span></dt></dl></dd><dt><span class="sect1"><a href="sec-TextViewExample.html">13.7. A TextView Example</a></span></dt></dl></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-TextViewOverview"></a>13.1. TextView Overview</h2></div></div><div></div></div><p><tt class="classname">TextView</tt> widgets and their associated
+objects (<tt class="classname">TextBuffer</tt>s,
+<tt class="classname">TextMark</tt>s, <tt class="classname">TextIter</tt>s,
+<tt class="classname">TextTag</tt>s and <tt class="classname">TextTagTable</tt>s)
+provide a powerful framework for multiline text editing.</p><p>A <tt class="classname">TextBuffer</tt> (see <a href="sec-TextBuffers.html" title="13.3. Text Buffers">Section 13.3, “Text Buffersâ€</a>) contains the text which is displayed by
+one or more <tt class="classname">TextView</tt> widgets.</p><p>Within GTK+ 2.0, text is encoded in UTF-8 which means that one
+character may be encoded as multiple bytes. Within a
+<tt class="classname">TextBuffer</tt> it is necessary to differentiate between
+the character counts (called offsets) and the byte counts (called
+indexes).</p><p><tt class="classname">TextIters</tt> provide a volatile representation
+of the position in a <tt class="classname">TextBuffer</tt> between two
+characters. <tt class="classname">TextIters</tt> are valid until the number of
+characters in the <tt class="classname">TextBuffer</tt> changes; i.e. any time
+characters are inserted or deleted from a <tt class="classname">TextBuffer</tt>
+all <tt class="classname">TextIters</tt> will become invalid.
+<tt class="classname">TextIters</tt> are the primary way to specify locations in
+a <tt class="classname">TextBuffer</tt> for manipulating text.</p><p><tt class="classname">TextMarks</tt> are provided to allow
+preservation of <tt class="classname">TextBuffer</tt> positions across buffer
+modifications. A mark is like a <tt class="classname">TextIter</tt> (see <a href="sec-TextIters.html" title="13.4. Text Iters">Section 13.4, “Text Itersâ€</a>) in that it represents a position between
+two characters in a <tt class="classname">TextBuffer</tt>) but if the text
+surrounding the mark is deleted the mark remains where the deleted text once
+was. Likewise, if text is inserted at the mark the mark ends up either to
+the left or right of the inserted text depending on the gravity of the mark
+- right gravity leaves the mark to the right of the inserted text while left
+gravity leaves it to the left. <tt class="classname">TextMark</tt>s (see <a href="sec-TextMarks.html" title="13.5. Text Marks">Section 13.5, “Text Marksâ€</a>) may be named or anonymous if not given a
+name. Each <tt class="classname">TextBuffer</tt> has two predefined named
+<tt class="classname">TextMark</tt>s (see <a href="sec-TextMarks.html" title="13.5. Text Marks">Section 13.5, “Text Marksâ€</a>)
+called <i class="parameter"><tt>insert</tt></i> and
+<i class="parameter"><tt>selection_bound</tt></i>. These refer to the insertion point
+and the boundary of the selection (the selection is between the
+<i class="parameter"><tt>insert</tt></i> and the <i class="parameter"><tt>selection_bound</tt></i>
+marks).</p><p><tt class="classname">TextTag</tt>s (see <a href="sec-TextTagsAndTextTagTables.html#sec-TextTags" title="13.6.1. Text Tags">Section 13.6.1, “Text Tagsâ€</a>) are objects that specify a set of attributes
+that can be applied to a range of text in a
+<tt class="classname">TextBuffer</tt>. Each <tt class="classname">TextBuffer</tt>
+has a <tt class="classname">TextTagTable</tt> (see <a href="sec-TextTagsAndTextTagTables.html#sec-TextTagTables" title="13.6.2. Text Tag Tables">Section 13.6.2, “Text Tag Tablesâ€</a>) which contains the tags that are
+available in that buffer. <tt class="classname">TextTagTable</tt>s can be shared
+between <tt class="classname">TextBuffer</tt>s to provide
+commonality. <tt class="classname">TextTag</tt>s are generally used to change
+the appearance of a range of text but can also be used to prevent a range of
+text from being edited.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-DrawingMethods.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="index.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-TextViews.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">12.2. Drawing Methods </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 13.2. TextViews</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/ch-TimeoutsIOAndIdleFunctions.html b/help/Pygtk2Tutorial/pygtk2tutorial/ch-TimeoutsIOAndIdleFunctions.html
new file mode 100644
index 0000000..554b25f
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/ch-TimeoutsIOAndIdleFunctions.html
@@ -0,0 +1,19 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>Chapter 19. Timeouts, IO and Idle Functions</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="previous" href="sec-WidgetStyles.html" title="18.5. Widget Styles"><link rel="next" href="sec-MonitoringIO.html" title="19.2. Monitoring IO"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 19. Timeouts, IO and Idle Functions</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-WidgetStyles.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="sec-MonitoringIO.html">Next</a></td></tr></table><hr></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="ch-TimeoutsIOAndIdleFunctions"></a>Chapter 19. Timeouts, IO and Idle Functions</h2></div></div><div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="ch-TimeoutsIOAndIdleFunctions.html#sec-Timeouts">19.1. Timeouts</a></span></dt><dt><span class="sect1"><a href="sec-MonitoringIO.html">19.2. Monitoring IO</a></span></dt><dt><span class="sect1"><a href="sec-IdleFunctions.html">19.3. Idle Functions</a></span></dt></dl></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-Timeouts"></a>19.1. Timeouts</h2></div></div><div></div></div><p>You may be wondering how you make GTK do useful work when in
+<tt class="function">main</tt>(). Well, you have several options. Using the
+following gobject module function you can create a timeout function that
+will be called every "interval" milliseconds.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ source_id = gobject.timeout_add(<i class="parameter"><tt>interval</tt></i>, <i class="parameter"><tt>function</tt></i>, ...)
+</pre></td></tr></table><p>The <i class="parameter"><tt>interval</tt></i> argument is the number of
+milliseconds between calls to your function. The
+<i class="parameter"><tt>function</tt></i> argument is the callback you wish to have
+called. Any arguments after the second are passed to the function as
+data. The return value is an integer "source_id" which may be used to stop
+the timeout by calling:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ gobject.source_remove(<i class="parameter"><tt>source_id</tt></i>)
+</pre></td></tr></table><p>You may also stop the timeout callback function from being
+called again by returning zero or <tt class="literal">FALSE</tt> from your
+callback. If you want your callback to be called again, it should return
+<tt class="literal">TRUE</tt>.</p><p>Your callback should look something like this:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def timeout_callback(...):
+</pre></td></tr></table><p>The number of arguments to the callback should match the number
+of data arguments specified in <tt class="function">timeout_add</tt>().</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-WidgetStyles.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="index.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-MonitoringIO.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">18.5. Widget Styles </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 19.2. Monitoring IO</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/ch-TipsForWritingPyGTKApplications.html b/help/Pygtk2Tutorial/pygtk2tutorial/ch-TipsForWritingPyGTKApplications.html
new file mode 100644
index 0000000..56659a2
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/ch-TipsForWritingPyGTKApplications.html
@@ -0,0 +1,4 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>Chapter 25. Tips For Writing PyGTK Applications</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="previous" href="sec-DrawingAreaWidgetAndDrawing.html" title="24.3. The DrawingArea Widget, And Drawing"><link rel="next" href="ch-Contributing.html" title="Chapter 26. Contributing"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 25. Tips For Writing PyGTK Applications</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-DrawingAreaWidgetAndDrawing.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="ch-Contributing.html">Next</a></td></tr></table><hr></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="ch-TipsForWritingPyGTKApplications"></a>Chapter 25. Tips For Writing PyGTK Applications</h2></div></div><div></div></div><p>This section is simply a gathering of wisdom, general style
+guidelines and hints to creating good PyGTK applications. Currently this
+section is very short, but I hope it will get longer in future editions of
+this tutorial.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-DrawingAreaWidgetAndDrawing.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="index.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch-Contributing.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">24.3. The DrawingArea Widget, And Drawing </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 26. Contributing</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/ch-TreeViewWidget.html b/help/Pygtk2Tutorial/pygtk2tutorial/ch-TreeViewWidget.html
new file mode 100644
index 0000000..1e58220
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/ch-TreeViewWidget.html
@@ -0,0 +1,166 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>Chapter 14. Tree View Widget</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="previous" href="sec-TextViewExample.html" title="13.7. A TextView Example"><link rel="next" href="sec-TreeModelInterface.html" title="14.2. The TreeModel Interface and Data Stores"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 14. Tree View Widget</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-TextViewExample.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="sec-TreeModelInterface.html">Next</a></td></tr></table><hr></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="ch-TreeViewWidget"></a>Chapter 14. Tree View Widget</h2></div></div><div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="ch-TreeViewWidget.html#sec-TreeViewOverview">14.1. Overview</a></span></dt><dt><span class="sect1"><a href="sec-TreeModelInterface.html">14.2. The TreeModel Interface and Data Stores</a></span></dt><dd><dl><dt><span class="sect2"><a href="sec-TreeModelInterface.html#sec-TreeModelIntroduction">14.2.1. Introduction</a></span></dt><dt><span class="sect2"><a href="sec-TreeModelInterface.html#sec-CreatingTreeStoreAndListStore">14.2.2. Creating TreeStore and ListStore Objects</a></span></dt><dt><span class="sect2"><a href="sec-TreeModelInterface.html#sec-ReferringToTreeModelRows">14.2.3. Referring to TreeModel Rows</a></span></dt><dt><span class="sect2"><a href="sec-TreeModelInterface.html#sec-AddingStoreRows">14.2.4. Adding Rows</a></span></dt><dt><span class="sect2"><a href="sec-TreeModelInterface.html#sec-RemovingStoreRows">14.2.5. Removing Rows</a></span></dt><dt><span class="sect2"><a href="sec-TreeModelInterface.html#sec-ManagingRowData">14.2.6. Managing Row Data</a></span></dt><dt><span class="sect2"><a href="sec-TreeModelInterface.html#sec-PythonProtocolSupport">14.2.7. Python Protocol Support</a></span></dt><dt><span class="sect2"><a href="sec-TreeModelInterface.html#sec-TreeModelSignals">14.2.8. TreeModel Signals</a></span></dt><dt><span class="sect2"><a href="sec-TreeModelInterface.html#sec-SortingTreeModelRows">14.2.9. Sorting TreeModel Rows</a></span></dt></dl></dd><dt><span class="sect1"><a href="sec-TreeViews.html">14.3. TreeViews</a></span></dt><dd><dl><dt><span class="sect2"><a href="sec-TreeViews.html#sec-CreatingTreeView">14.3.1. Creating a TreeView</a></span></dt><dt><span class="sect2"><a href="sec-TreeViews.html#sec-TreeViewModelAccess">14.3.2. Getting and Setting the TreeView Model</a></span></dt><dt><span class="sect2"><a href="sec-TreeViews.html#sec-TreeViewProperties">14.3.3. Setting TreeView Properties</a></span></dt></dl></dd><dt><span class="sect1"><a href="sec-CellRenderers.html">14.4. CellRenderers</a></span></dt><dd><dl><dt><span class="sect2"><a href="sec-CellRenderers.html#sec-CellRendererOverview">14.4.1. Overview</a></span></dt><dt><span class="sect2"><a href="sec-CellRenderers.html#sec-CellRendererTypes">14.4.2. CellRenderer Types</a></span></dt><dt><span class="sect2"><a href="sec-CellRenderers.html#sec-CellRendererProperties">14.4.3. CellRenderer Properties</a></span></dt><dt><span class="sect2"><a href="sec-CellRenderers.html#sec-CellRendererAttributes">14.4.4. CellRenderer Attributes</a></span></dt><dt><span class="sect2"><a href="sec-CellRenderers.html#sec-CellDataFunction">14.4.5. Cell Data Function</a></span></dt><dt><span class="sect2"><a href="sec-CellRenderers.html#sec-CellRendererTextMarkup">14.4.6. CellRendererText Markup</a></span></dt><dt><span class="sect2"><a href="sec-CellRenderers.html#EditableTextCells">14.4.7. Editable Text Cells</a></span></dt><dt><span class="sect2"><a href="sec-CellRenderers.html#sec-ActivatableToggleCells">14.4.8. Activatable Toggle Cells</a></span></dt><dt><span class="sect2"><a href="sec-CellRenderers.html#sec-EditableActivatableProgram">14.4.9. Editable and Activatable Cell Example Program</a></span></dt></dl></dd><dt><span class="sect1"><a href="sec-TreeViewColumns.html">14.5. TreeViewColumns</a></span></dt><dd><dl><dt><span class="sect2"><a href="sec-TreeViewColumns.html#sec-CreatingTreeViewColumns">14.5.1. Creating TreeViewColumns</a></span></dt><dt><span class="sect2"><a href="sec-TreeViewColumns.html#sec-ManagingCellRenderers">14.5.2. Managing CellRenderers</a></span></dt></dl></dd><dt><span class="sect1"><a href="sec-ManipulatingTreeViews.html">14.6. Manipulating TreeViews</a></span></dt><dd><dl><dt><span class="sect2"><a href="sec-ManipulatingTreeViews.html#sec-ManagingColumns">14.6.1. Managing Columns</a></span></dt><dt><span class="sect2"><a href="sec-ManipulatingTreeViews.html#sec-ExpandCollapseChildRows">14.6.2. Expanding and Collapsing Child Rows</a></span></dt></dl></dd><dt><span class="sect1"><a href="sec-TreeViewSignals.html">14.7. TreeView Signals</a></span></dt><dt><span class="sect1"><a href="sec-TreeSelections.html">14.8. TreeSelections</a></span></dt><dd><dl><dt><span class="sect2"><a href="sec-TreeSelections.html#sec-GettingTheTreeSelection">14.8.1. Getting the TreeSelection</a></span></dt><dt><span class="sect2"><a href="sec-TreeSelections.html#sec-TreeSelectionMode">14.8.2. TreeSelection Modes</a></span></dt><dt><span class="sect2"><a href="sec-TreeSelections.html#sec-RetrievingTheTreeSelection">14.8.3. Retrieving the Selection</a></span></dt><dt><span class="sect2"><a href="sec-TreeSelections.html#sec-TreeSelectionFunction">14.8.4. Using a TreeSelection Function</a></span></dt><dt><span class="sect2"><a href="sec-TreeSelections.html#sec-SelectingAndUnselectingRows">14.8.5. Selecting and Unselecting Rows</a></span></dt></dl></dd><dt><span class="sect1"><a href="sec-TreeViewDragAndDrop.html">14.9. TreeView Drag and Drop</a></span></dt><dd><dl><dt><span class="sect2"><a href="sec-TreeViewDragAndDrop.html#DragDropReordering">14.9.1. Drag and Drop Reordering</a></span></dt><dt><span class="sect2"><a href="sec-TreeViewDragAndDrop.html#sec-ExternalDragDrop">14.9.2. External Drag and Drop</a></span></dt><dt><span class="sect2"><a href="sec-TreeViewDragAndDrop.html#sec-TreeViewDnDExample">14.9.3. TreeView Drag and Drop Example</a></span></dt></dl></dd><dt><span class="sect1"><a href="sec-TreeModelSortAndTreeModelFilter.html">14.10. TreeModelSort and TreeModelFilter</a></span></dt><dd><dl><dt><span class="sect2"><a href="sec-TreeModelSortAndTreeModelFilter.html#sec-TreeModelSort">14.10.1. TreeModelSort</a></span></dt><dt><span class="sect2"><a href="sec-TreeModelSortAndTreeModelFilter.html#sec-TreeModelFilter">14.10.2. TreeModelFilter</a></span></dt></dl></dd><dt><span class="sect1"><a href="sec-GenericTreeModel.html">14.11. The Generic TreeModel</a></span></dt><dd><dl><dt><span class="sect2"><a href="sec-GenericTreeModel.html#sec-GenericTreeModelOverview">14.11.1. GenericTreeModel Overview</a></span></dt><dt><span class="sect2"><a href="sec-GenericTreeModel.html#sec-GenericTreeModelInterface">14.11.2. The GenericTreeModel Interface</a></span></dt><dt><span class="sect2"><a href="sec-GenericTreeModel.html#sec-AddRemoveGenericTreeModelRows">14.11.3. Adding and Removing Rows</a></span></dt><dt><span class="sect2"><a href="sec-GenericTreeModel.html#sec-GenericTreeModelMemoryManagement">14.11.4. Memory Management</a></span></dt><dt><span class="sect2"><a href="sec-GenericTreeModel.html#sec-OtherInterfaces">14.11.5. Other Interfaces</a></span></dt><dt><span class="sect2"><a href="sec-GenericTreeModel.html#sec-ApplyingGenericTreeModel">14.11.6. Applying The GenericTreeModel</a></span></dt></dl></dd><dt><span class="sect1"><a href="sec-GenericCellRenderer.html">14.12. The Generic CellRenderer</a></span></dt></dl></div><p>The <tt class="classname">TreeView</tt> widget displays lists and trees
+displaying multiple columns. It replaces the previous set of List,
+<tt class="classname">CList</tt>, <tt class="classname">Tree</tt> and
+<tt class="classname">CTree</tt> widgets with a much more powerful and flexible
+set of objects that use the Model-View-Controller (MVC) principle to provide
+the following features:</p><div class="itemizedlist"><ul type="disc"><li>two pre-defined models: one for lists and one for
+trees</li><li>multiple views of the same model are automatically
+updated when the model changes</li><li>selective display of the model data</li><li>use of model data to customize the TreeView display on a
+row-by-row basis</li><li>pre-defined data rendering objects for displaying text,
+images and boolean data</li><li>stackable models for providing sorted and filtered views of
+the underlying model data</li><li>reorderable and resizeable columns</li><li>automatic sort by clicking column headers</li><li>drag and drop support</li><li>support for custom models entirely written in
+Python</li><li>support for custom cell renderers entirely written in
+Python</li></ul></div><p>Of course, all this capability comes at the price of a significantly
+more complex set of objects and interfaces that appear overwhelming at
+first. In the rest of this chapter we'll explore the TreeView objects and
+interfaces to reach an understanding of common usage. The more esoteric
+aspects, you'll have to explore on your own.</p><p>We'll start with a quick overview tour of the objects and interfaces
+and then dive into the <tt class="classname">TreeModel</tt> interface and the
+predefined <tt class="classname">ListStore</tt> and
+<tt class="classname">TreeStore</tt> classes.</p><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-TreeViewOverview"></a>14.1. Overview</h2></div></div><div></div></div><p>A <tt class="classname">TreeView</tt> widget is the user interface
+object that displays the data stored in an object that implements the
+<tt class="classname">TreeModel</tt> interface. Two base tree model classes are
+provided in PyGTK 2.0:</p><div class="itemizedlist"><ul type="disc"><li>the <tt class="classname">TreeStore</tt> that provides
+hierarchical data storage organized as tree rows with columnar data. Each
+tree row can have zero or more child rows. All rows must have the same
+number of columns.</li><li>the <tt class="classname">ListStore</tt> that provides tabular
+data storage organized in rows and columns similar to a table in a
+relational database. The <tt class="classname">ListStore</tt> is really a
+simplified version of a <tt class="classname">TreeStore</tt> where the rows have
+no children. It has been created to provide a simpler (and presumably more
+efficient) interface to this common data model. And,</li></ul></div><p>The two additional tree models stack on top of (or interpose on)
+the base models:</p><div class="itemizedlist"><ul type="disc"><li>the <tt class="classname">TreeModelSort</tt> that provides a
+model where the data of the underlying tree model is maintained in a sorted
+order. And,</li><li>the <tt class="classname">TreeModelFilter</tt> that provides a
+model containing a subset of the data in the underlying model. Note this
+model is available only in PyGTK 2.4 and above.</li></ul></div><p>A <tt class="classname">TreeView</tt> displays all of the rows of a
+<tt class="classname">TreeModel</tt> but may display only some of the columns.
+Also the columns may be
+presented in a different order than the <tt class="classname">TreeModel</tt>
+stores them.</p><p>The <tt class="classname">TreeView</tt> uses
+<tt class="classname">TreeViewColumn</tt> objects to organize the display of the
+columnar data. Each <tt class="classname">TreeViewColumn</tt> displays one
+column with an optional header that may contain the data from several
+<tt class="classname">TreeModel</tt> columns. The individual
+<tt class="classname">TreeViewColumn</tt>s are packed (similar to
+<tt class="classname">HBox</tt> containers) with
+<tt class="classname">CellRenderer</tt> objects to render the display of the
+associated data from a <tt class="classname">TreeModel</tt> row and column
+location. There are three predefined <tt class="classname">CellRenderer</tt>
+classes:</p><div class="itemizedlist"><ul type="disc"><li>the <tt class="classname">CellRendererPixbuf</tt> that renders
+a pixbuf image into the cells of a
+<tt class="classname">TreeViewColumn</tt>.</li><li>the <tt class="classname">CellRendererText</tt> that renders a
+string into the cells of a <tt class="classname">TreeViewColumn</tt>. It will
+convert the column data to a string format if needed i.e. if displaying a
+model column containing float data, the
+<tt class="classname">CellRendererText</tt> will convert it to a string before
+rendering it.</li><li>the <tt class="classname">CellRendererToggle</tt> that renders
+a boolean value as a toggle button into the cells of a
+<tt class="classname">TreeViewColumn</tt>.</li></ul></div><p>A <tt class="classname">TreeViewColumn</tt> can contain several
+<tt class="classname">CellRenderer</tt> objects to provide a column that, for
+example, may have an image and text packed together.</p><p>Finally, the <tt class="classname">TreeIter</tt>,
+<tt class="classname">TreeRowReference</tt> and
+<tt class="classname">TreeSelection</tt> objects provide a transient pointer to
+a row in a <tt class="classname">TreeModel</tt>, a persistent pointer to a row
+in a <tt class="classname">TreeModel</tt> and an object managing the selections
+in a <tt class="classname">TreeView</tt>.</p><p>A <tt class="classname">TreeView</tt> display is composed using the
+following general operations not necessarily in this order:</p><div class="itemizedlist"><ul type="disc"><li>A tree model object is created usually a
+<tt class="classname">ListStore</tt> or <tt class="classname">TreeStore</tt> with
+one or more columns of a specified data type.</li><li>The tree model may be populated with one or more rows of
+data.</li><li>A <tt class="classname">TreeView</tt> widget is created and
+associated with the tree model.</li><li>One or more <tt class="classname">TreeViewColumn</tt>s are
+created and inserted in the <tt class="classname">TreeView</tt>. Each of these
+will present a single display column.</li><li>For each <tt class="classname">TreeViewColumn</tt> one or more
+<tt class="classname">CellRenderer</tt>s are created and added to the
+<tt class="classname">TreeViewColumn</tt>.</li><li>The attributes of each <tt class="classname">CellRenderer</tt>
+are set to indicate from which column of the tree model to retrieve the
+attribute data. for example the text to be rendered. This allows the
+<tt class="classname">CellRenderer</tt> to render each column in a row
+differently.</li><li>The <tt class="classname">TreeView</tt> is inserted and
+displayed in a <tt class="classname">Window</tt> or
+<tt class="classname">ScrolledWindow</tt>.</li><li>The data in the tree model is manipulated programmatically
+in response to user actions. The <tt class="classname">TreeView</tt> will
+automatically track the changes.</li></ul></div><p>The example program <a href="examples/basictreeview.py" target="_top"><span><b class="command">basictreeview.py</b></span></a>
+illustrates the creation and display of a simple
+<tt class="classname">TreeView</tt>:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 1 #!/usr/bin/env python
+ 2
+ 3 # example basictreeview.py
+ 4
+ 5 import pygtk
+ 6 pygtk.require('2.0')
+ 7 import gtk
+ 8
+ 9 class BasicTreeViewExample:
+ 10
+ 11 # close the window and quit
+ 12 def delete_event(self, widget, event, data=None):
+ 13 gtk.main_quit()
+ 14 return False
+ 15
+ 16 def __init__(self):
+ 17 # Create a new window
+ 18 self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ 19
+ 20 self.window.set_title("Basic TreeView Example")
+ 21
+ 22 self.window.set_size_request(200, 200)
+ 23
+ 24 self.window.connect("delete_event", self.delete_event)
+ 25
+ 26 # create a TreeStore with one string column to use as the model
+ 27 self.treestore = gtk.TreeStore(str)
+ 28
+ 29 # we'll add some data now - 4 rows with 3 child rows each
+ 30 for parent in range(4):
+ 31 piter = self.treestore.append(None, ['parent %i' % parent])
+ 32 for child in range(3):
+ 33 self.treestore.append(piter, ['child %i of parent %i' %
+ 34 (child, parent)])
+ 35
+ 36 # create the TreeView using treestore
+ 37 self.treeview = gtk.TreeView(self.treestore)
+ 38
+ 39 # create the TreeViewColumn to display the data
+ 40 self.tvcolumn = gtk.TreeViewColumn('Column 0')
+ 41
+ 42 # add tvcolumn to treeview
+ 43 self.treeview.append_column(self.tvcolumn)
+ 44
+ 45 # create a CellRendererText to render the data
+ 46 self.cell = gtk.CellRendererText()
+ 47
+ 48 # add the cell to the tvcolumn and allow it to expand
+ 49 self.tvcolumn.pack_start(self.cell, True)
+ 50
+ 51 # set the cell "text" attribute to column 0 - retrieve text
+ 52 # from that column in treestore
+ 53 self.tvcolumn.add_attribute(self.cell, 'text', 0)
+ 54
+ 55 # make it searchable
+ 56 self.treeview.set_search_column(0)
+ 57
+ 58 # Allow sorting on the column
+ 59 self.tvcolumn.set_sort_column_id(0)
+ 60
+ 61 # Allow drag and drop reordering of rows
+ 62 self.treeview.set_reorderable(True)
+ 63
+ 64 self.window.add(self.treeview)
+ 65
+ 66 self.window.show_all()
+ 67
+ 68 def main():
+ 69 gtk.main()
+ 70
+ 71 if __name__ == "__main__":
+ 72 tvexample = BasicTreeViewExample()
+ 73 main()
+</pre></td></tr></table><p>In real programs the <tt class="classname">TreeStore</tt> would likely
+be populated with data after the <tt class="classname">TreeView</tt> is
+displayed due to some user action. We'll look at the details of the
+<tt class="classname">TreeView</tt> interfaces in more detail in the sections to
+come. <a href="ch-TreeViewWidget.html#basictreeviewfig" title="Figure 14.1. Basic TreeView Example Program">Figure 14.1, “Basic TreeView Example Programâ€</a> shows the window created by the
+<a href="examples/basictreeview.py" target="_top"><span><b class="command">basictreeview.py</b></span></a>
+program after a couple of parent rows have been expanded.</p><div class="figure"><a name="basictreeviewfig"></a><p class="title"><b>Figure 14.1. Basic TreeView Example Program</b></p><div class="mediaobject" align="center"><img src="figures/basictreeview.png" align="middle" alt="Basic TreeView Example Program"></div></div><p>Next let's examine the <tt class="classname">TreeModel</tt> interface
+and the models that implement it.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-TextViewExample.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="index.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-TreeModelInterface.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">13.7. A TextView Example </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 14.2. The TreeModel Interface and Data Stores</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/ch-UndocumentedWidgets.html b/help/Pygtk2Tutorial/pygtk2tutorial/ch-UndocumentedWidgets.html
new file mode 100644
index 0000000..e22fe54
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/ch-UndocumentedWidgets.html
@@ -0,0 +1,9 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>Chapter 17. Undocumented Widgets</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="previous" href="sec-UIManager.html" title="16.7. The UIManager"><link rel="next" href="sec-OptionMenu.html" title="17.2. Option Menu"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 17. Undocumented Widgets</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-UIManager.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="sec-OptionMenu.html">Next</a></td></tr></table><hr></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="ch-UndocumentedWidgets"></a>Chapter 17. Undocumented Widgets</h2></div></div><div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="ch-UndocumentedWidgets.html#sec-AccelLabel">17.1. Accel Label</a></span></dt><dt><span class="sect1"><a href="sec-OptionMenu.html">17.2. Option Menu</a></span></dt><dt><span class="sect1"><a href="sec-MenuItems.html">17.3. Menu Items</a></span></dt><dd><dl><dt><span class="sect2"><a href="sec-MenuItems.html#id2834318">17.3.1. Check Menu Item</a></span></dt><dt><span class="sect2"><a href="sec-MenuItems.html#id2906601">17.3.2. Radio Menu Item</a></span></dt><dt><span class="sect2"><a href="sec-MenuItems.html#id2906613">17.3.3. Separator Menu Item</a></span></dt><dt><span class="sect2"><a href="sec-MenuItems.html#id2879329">17.3.4. Tearoff Menu Item</a></span></dt></dl></dd><dt><span class="sect1"><a href="sec-Curves.html">17.4. Curves</a></span></dt><dt><span class="sect1"><a href="sec-MessageDialog.html">17.5. Message Dialog</a></span></dt><dt><span class="sect1"><a href="sec-GammaCurve.html">17.6. Gamma Curve</a></span></dt></dl></div><p>These all require authors! :) Please consider contributing to our
+tutorial.</p><p>If you must use one of these widgets that are undocumented, I
+strongly suggest you take a look at the *.c files in the PyGTK distribution.
+PyGTK's method names are very descriptive. Once you have an understanding of
+how things work, it's not difficult to figure out how to use a widget simply
+by looking at its method definitions. This, along with a few examples from
+others' code, and it should be no problem.</p><p>When you do come to understand all the methods of a new
+undocumented widget, please consider writing a tutorial on it so others may
+benefit from your time.</p><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-AccelLabel"></a>17.1. Accel Label</h2></div></div><div></div></div><p></p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-UIManager.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="index.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-OptionMenu.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">16.7. The UIManager </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 17.2. Option Menu</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/ch-WidgetOverview.html b/help/Pygtk2Tutorial/pygtk2tutorial/ch-WidgetOverview.html
new file mode 100644
index 0000000..472d1fc
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/ch-WidgetOverview.html
@@ -0,0 +1,165 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>Chapter 5. Widget Overview</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="previous" href="sec-TablePackingExample.html" title="4.5. Table Packing Example"><link rel="next" href="sec-WidgetsWithoutWindows.html" title="5.2. Widgets Without Windows"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 5. Widget Overview</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-TablePackingExample.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="sec-WidgetsWithoutWindows.html">Next</a></td></tr></table><hr></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="ch-WidgetOverview"></a>Chapter 5. Widget Overview</h2></div></div><div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="ch-WidgetOverview.html#sec-WidgetHierarchy">5.1. Widget Hierarchy</a></span></dt><dt><span class="sect1"><a href="sec-WidgetsWithoutWindows.html">5.2. Widgets Without Windows</a></span></dt></dl></div><p>The general steps to using a widget in PyGTK are:</p><div class="itemizedlist"><ul type="disc"><li>invoke gtk.* - one of various functions to create a
+new widget. These are all detailed in this section.</li><li>Connect all signals and events we wish to use to
+the appropriate handlers.</li><li>Set the attributes of the
+widget.</li><li>Pack the widget into a container using the
+appropriate call such as gtk.Container.add() or gtk.Box.pack_start()
+.</li><li>gtk.Widget.show() the widget.</li></ul></div><p><tt class="function">show</tt>() lets GTK know that we are done setting
+the attributes of the widget, and it is ready to be displayed. You may also
+use <tt class="function">gtk.Widget.hide</tt>() to make it disappear again. The
+order in which you show the widgets is not important, but I suggest showing
+the window last so the whole window pops up at once rather than seeing the
+individual widgets come up on the screen as they're formed. The children of
+a widget (a window is a widget too) will not be displayed until the window
+itself is shown using the <tt class="function">show</tt>() method.</p><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-WidgetHierarchy"></a>5.1. Widget Hierarchy</h2></div></div><div></div></div><p>For your reference, here is the class hierarchy tree used to
+implement widgets. (Deprecated widgets and auxiliary classes have been
+omitted.)</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+gobject.GObject
+|
++gtk.Object
+| +gtk.Widget
+| | +gtk.Misc
+| | | +gtk.Label
+| | | | `gtk.AccelLabel
+| | | +gtk.Arrow
+| | | `gtk.Image
+| | +gtk.Container
+| | | +gtk.Bin
+| | | | +gtk.Alignment
+| | | | +gtk.Frame
+| | | | | `gtk.AspectFrame
+| | | | +gtk.Button
+| | | | | +gtk.ToggleButton
+| | | | | | `gtk.CheckButton
+| | | | | | `gtk.RadioButton
+| | | | | +gtk.ColorButton
+| | | | | +gtk.FontButton
+| | | | | `gtk.OptionMenu
+| | | | +gtk.Item
+| | | | | +gtk.MenuItem
+| | | | | +gtk.CheckMenuItem
+| | | | | | `gtk.RadioMenuItem
+| | | | | +gtk.ImageMenuItem
+| | | | | +gtk.SeparatorMenuItem
+| | | | | `gtk.TearoffMenuItem
+| | | | +gtk.Window
+| | | | | +gtk.Dialog
+| | | | | | +gtk.ColorSelectionDialog
+| | | | | | +gtk.FileChooserDialog
+| | | | | | +gtk.FileSelection
+| | | | | | +gtk.FontSelectionDialog
+| | | | | | +gtk.InputDialog
+| | | | | | `gtk.MessageDialog
+| | | | | `gtk.Plug
+| | | | +gtk.ComboBox
+| | | | | `gtk.ComboBoxEntry
+| | | | +gtk.EventBox
+| | | | +gtk.Expander
+| | | | +gtk.HandleBox
+| | | | +gtk.ToolItem
+| | | | | +gtk.ToolButton
+| | | | | | +gtk.ToggleToolButton
+| | | | | | | `gtk.RadioToolButton
+| | | | | `gtk.SeparatorTooItem
+| | | | +gtk.ScrolledWindow
+| | | | `gtk.Viewport
+| | | +gtk.Box
+| | | | +gtk.ButtonBox
+| | | | | +gtk.HButtonBox
+| | | | | `gtk.VButtonBox
+| | | | +gtk.VBox
+| | | | | +gtk.ColorSelection
+| | | | | +gtk.FontSelection
+| | | | | `gtk.GammaCurve
+| | | | `gtk.HBox
+| | | | +gtk.Combo
+| | | | `gtk.Statusbar
+| | | +gtk.Fixed
+| | | +gtk.Paned
+| | | | +gtk.HPaned
+| | | | `gtk.VPaned
+| | | +gtk.Layout
+| | | +gtk.MenuShell
+| | | | +gtk.MenuBar
+| | | | `gtk.Menu
+| | | +gtk.Notebook
+| | | +gtk.Socket
+| | | +gtk.Table
+| | | +gtk.TextView
+| | | +gtk.Toolbar
+| | | `gtk.TreeView
+| | +gtk.Calendar
+| | +gtk.DrawingArea
+| | | `gtk.Curve
+| | +gtk.Entry
+| | | `gtk.SpinButton
+| | +gtk.Ruler
+| | | +gtk.HRuler
+| | | `gtk.VRuler
+| | +gtk.Range
+| | | +gtk.Scale
+| | | | +gtk.HScale
+| | | | `gtk.VScale
+| | | `gtk.Scrollbar
+| | | +gtk.HScrollbar
+| | | `gtk.VScrollbar
+| | +gtk.Separator
+| | | +gtk.HSeparator
+| | | `gtk.VSeparator
+| | +gtk.Invisible
+| | +gtk.Progress
+| | | `gtk.ProgressBar
+| +gtk.Adjustment
+| +gtk.CellRenderer
+| | +gtk.CellRendererPixbuf
+| | +gtk.CellRendererText
+| | +gtk.CellRendererToggle
+| +gtk.FileFilter
+| +gtk.ItemFactory
+| +gtk.Tooltips
+| `gtk.TreeViewColumn
++gtk.Action
+| +gtk.ToggleAction
+| | `gtk.RadioAction
++gtk.ActionGroup
++gtk.EntryCompletion
++gtk.IconFactory
++gtk.IconTheme
++gtk.IMContext
+| +gtk.IMContextSimple
+| `gtk.IMMulticontext
++gtk.ListStore
++gtk.RcStyle
++gtk.Settings
++gtk.SizeGroup
++gtk.Style
++gtk.TextBuffer
++gtk.TextChildAnchor
++gtk.TextMark
++gtk.TextTag
++gtk.TextTagTable
++gtk.TreeModelFilter
++gtk.TreeModelSort
++gtk.TreeSelection
++gtk.TreeStore
++gtk.UIManager
++gtk.WindowGroup
++gtk.gdk.DragContext
++gtk.gdk.Screen
++gtk.gdk.Pixbuf
++gtk.gdk.Drawable
+| +gtk.gdk.Pixmap
++gtk.gdk.Image
++gtk.gdk.PixbufAnimation
++gtk.gdk.Device
+
+gobject.GObject
+|
++gtk.CellLayout
++gtk.Editable
++gtk.CellEditable
++gtk.FileChooser
++gtk.TreeModel
++gtk.TreeDragSource
++gtk.TreeDragDest
++gtk.TreeSortable
+</pre></td></tr></table></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-TablePackingExample.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="index.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-WidgetsWithoutWindows.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">4.5. Table Packing Example </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 5.2. Widgets Without Windows</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/actiongroup.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/actiongroup.png
new file mode 100644
index 0000000..78125ec
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/actiongroup.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/actions.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/actions.png
new file mode 100644
index 0000000..a1bbee8
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/actions.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/arrows.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/arrows.png
new file mode 100644
index 0000000..d27195a
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/arrows.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/aspectframe.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/aspectframe.png
new file mode 100644
index 0000000..508dba6
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/aspectframe.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/base.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/base.png
new file mode 100644
index 0000000..9ca0d6c
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/base.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/basicaction.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/basicaction.png
new file mode 100644
index 0000000..4686c65
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/basicaction.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/basictreeview.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/basictreeview.png
new file mode 100644
index 0000000..15697fd
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/basictreeview.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/button.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/button.png
new file mode 100644
index 0000000..a13a631
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/button.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/buttonbox.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/buttonbox.png
new file mode 100644
index 0000000..e8b344f
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/buttonbox.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/calendar.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/calendar.png
new file mode 100644
index 0000000..dfbf4cd
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/calendar.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/celldatafunc.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/celldatafunc.png
new file mode 100644
index 0000000..54e2eac
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/celldatafunc.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/cellrenderer.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/cellrenderer.png
new file mode 100644
index 0000000..e439a12
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/cellrenderer.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/celltextmarkup.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/celltextmarkup.png
new file mode 100644
index 0000000..6213846
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/celltextmarkup.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/checkbutton.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/checkbutton.png
new file mode 100644
index 0000000..2af3e54
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/checkbutton.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/clipboard.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/clipboard.png
new file mode 100644
index 0000000..26606d3
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/clipboard.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/colorbutton.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/colorbutton.png
new file mode 100644
index 0000000..06e6b31
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/colorbutton.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/colorselection.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/colorselection.png
new file mode 100644
index 0000000..4a44f35
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/colorselection.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/comboboxbasic.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/comboboxbasic.png
new file mode 100644
index 0000000..de665a4
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/comboboxbasic.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/comboboxentrybasic.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/comboboxentrybasic.png
new file mode 100644
index 0000000..6523a02
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/comboboxentrybasic.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/comboboxwrap.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/comboboxwrap.png
new file mode 100644
index 0000000..162599c
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/comboboxwrap.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/dragndrop.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/dragndrop.png
new file mode 100644
index 0000000..70c78d4
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/dragndrop.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/drawingarea.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/drawingarea.png
new file mode 100644
index 0000000..91d7021
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/drawingarea.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/entry.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/entry.png
new file mode 100644
index 0000000..8feb7e0
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/entry.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/entrycompletion.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/entrycompletion.png
new file mode 100644
index 0000000..349d25b
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/entrycompletion.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/eventbox.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/eventbox.png
new file mode 100644
index 0000000..bfc99b4
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/eventbox.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/expander.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/expander.png
new file mode 100644
index 0000000..f64b6c4
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/expander.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/filechooser.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/filechooser.png
new file mode 100644
index 0000000..b755b1c
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/filechooser.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/filelisting-gtm.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/filelisting-gtm.png
new file mode 100644
index 0000000..86e0672
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/filelisting-gtm.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/filelisting.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/filelisting.png
new file mode 100644
index 0000000..6d6c1da
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/filelisting.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/fileselection.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/fileselection.png
new file mode 100644
index 0000000..e468d4c
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/fileselection.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/fixed.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/fixed.png
new file mode 100644
index 0000000..f2dd5ad
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/fixed.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/fontbutton.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/fontbutton.png
new file mode 100644
index 0000000..7e9bb30
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/fontbutton.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/fontselection.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/fontselection.png
new file mode 100644
index 0000000..1d2bbab
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/fontselection.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/frame.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/frame.png
new file mode 100644
index 0000000..8b80b51
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/frame.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/getselection.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/getselection.png
new file mode 100644
index 0000000..5bc0032
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/getselection.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/helloworld.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/helloworld.png
new file mode 100644
index 0000000..f77d562
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/helloworld.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/helloworld2.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/helloworld2.png
new file mode 100644
index 0000000..543f81d
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/helloworld2.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/images.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/images.png
new file mode 100644
index 0000000..b90b2f8
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/images.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/itemfactory.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/itemfactory.png
new file mode 100644
index 0000000..11903ed
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/itemfactory.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/labels.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/labels.png
new file mode 100644
index 0000000..348cc9a
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/labels.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/layout.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/layout.png
new file mode 100644
index 0000000..48bff75
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/layout.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/menu.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/menu.png
new file mode 100644
index 0000000..2fb8de6
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/menu.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/notebook.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/notebook.png
new file mode 100644
index 0000000..801d2a1
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/notebook.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/packbox1.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/packbox1.png
new file mode 100644
index 0000000..22a7814
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/packbox1.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/packbox2.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/packbox2.png
new file mode 100644
index 0000000..9fa08a6
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/packbox2.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/packbox3.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/packbox3.png
new file mode 100644
index 0000000..e3a43c8
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/packbox3.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/paned.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/paned.png
new file mode 100644
index 0000000..1c9a3b9
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/paned.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/pixmap.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/pixmap.png
new file mode 100644
index 0000000..d0e2c44
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/pixmap.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/progressbar.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/progressbar.png
new file mode 100644
index 0000000..e9933d7
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/progressbar.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/radiobutton.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/radiobutton.png
new file mode 100644
index 0000000..5c63352
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/radiobutton.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/rangewidgets.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/rangewidgets.png
new file mode 100644
index 0000000..13d5709
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/rangewidgets.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/rulers.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/rulers.png
new file mode 100644
index 0000000..8fcf0c7
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/rulers.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/scribblesimple.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/scribblesimple.png
new file mode 100644
index 0000000..12dafbb
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/scribblesimple.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/scrolledwin.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/scrolledwin.png
new file mode 100644
index 0000000..fcac389
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/scrolledwin.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/setselection.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/setselection.png
new file mode 100644
index 0000000..b378682
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/setselection.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/simpleaction.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/simpleaction.png
new file mode 100644
index 0000000..3060586
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/simpleaction.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/spinbutton.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/spinbutton.png
new file mode 100644
index 0000000..274a93c
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/spinbutton.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/statusbar.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/statusbar.png
new file mode 100644
index 0000000..1d51ff3
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/statusbar.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/table.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/table.png
new file mode 100644
index 0000000..69e7226
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/table.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/testtext.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/testtext.png
new file mode 100644
index 0000000..155ed20
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/testtext.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/textview-basic.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/textview-basic.png
new file mode 100644
index 0000000..3598de4
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/textview-basic.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/toggle.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/toggle.png
new file mode 100644
index 0000000..5f72742
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/toggle.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/toolbar.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/toolbar.png
new file mode 100644
index 0000000..1191d49
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/toolbar.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/tooltips.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/tooltips.png
new file mode 100644
index 0000000..c06805d
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/tooltips.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/treemodelfilter.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/treemodelfilter.png
new file mode 100644
index 0000000..83e6788
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/treemodelfilter.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/treemodelsort.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/treemodelsort.png
new file mode 100644
index 0000000..3ccded9
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/treemodelsort.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/treeviewcolumn.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/treeviewcolumn.png
new file mode 100644
index 0000000..c504033
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/treeviewcolumn.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/treeviewcolumn1expander.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/treeviewcolumn1expander.png
new file mode 100644
index 0000000..f4ccf7f
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/treeviewcolumn1expander.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/treeviewdnd.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/treeviewdnd.png
new file mode 100644
index 0000000..dfe74c4
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/treeviewdnd.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/uimanager.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/uimanager.png
new file mode 100644
index 0000000..8e1d5d4
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/uimanager.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/uimerge.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/uimerge.png
new file mode 100644
index 0000000..dd8c60a
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/uimerge.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/figures/wheelbarrow.png b/help/Pygtk2Tutorial/pygtk2tutorial/figures/wheelbarrow.png
new file mode 100644
index 0000000..53facdc
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/figures/wheelbarrow.png
Binary files differ
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/index.html b/help/Pygtk2Tutorial/pygtk2tutorial/index.html
new file mode 100644
index 0000000..9435ef9
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/index.html
@@ -0,0 +1 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>PyGTK 2.0 Tutorial</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><meta name="description" content="This tutorial describes the use of the Python PyGTK module."><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="next" href="ch-Introduction.html" title="Chapter 1. Introduction"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">PyGTK 2.0 Tutorial</th></tr><tr><td width="20%" align="left"> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="ch-Introduction.html">Next</a></td></tr></table><hr></div><div class="book" lang="en"><div class="titlepage"><div><div><h1 class="title"><a name="pygtk-tut"></a>PyGTK 2.0 Tutorial</h1></div><div><div class="authorgroup"><div class="author"><h3 class="author"><span class="firstname">John</span> <span class="surname">Finlay</span></h3></div></div></div><div><p class="releaseinfo">Version 2.5</p></div><div><p class="pubdate">March 2, 2006</p></div><div><div class="revhistory"><table border="1" width="100%" summary="Revision history"><tr><th align="left" valign="top" colspan="2"><b>Revision History</b></th></tr><tr><td align="left">Revision 2.4</td><td align="left">April 13, 2005</td></tr><tr><td align="left" colspan="2">Update example programs</td></tr><tr><td align="left">Revision 2.3</td><td align="left">December 24, 2004</td></tr><tr><td align="left" colspan="2">Add more PyGTK 2.4 widgets</td></tr><tr><td align="left">Revision 2.2</td><td align="left">August 3, 2004</td></tr><tr><td align="left" colspan="2">Add new PyGTK 2.2 and some PyGTK 2.4 widgets</td></tr><tr><td align="left">Revision 2.1</td><td align="left">July 6, 2004</td></tr><tr><td align="left" colspan="2">More TreeView</td></tr><tr><td align="left">Revision 2.0</td><td align="left">May 24, 2004</td></tr><tr><td align="left" colspan="2">First release for PyGTK 2.0</td></tr></table></div></div><div><div class="abstract"><p class="title"><b>Abstract</b></p><p>This tutorial describes the use of the Python PyGTK module.</p></div></div></div><div></div><hr></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="chapter"><a href="ch-Introduction.html">1. Introduction</a></span></dt><dd><dl><dt><span class="sect1"><a href="ch-Introduction.html#sec-ExploringPygtk">1.1. Exploring PyGTK</a></span></dt></dl></dd><dt><span class="chapter"><a href="ch-GettingStarted.html">2. Getting Started</a></span></dt><dd><dl><dt><span class="sect1"><a href="ch-GettingStarted.html#sec-HelloWorld">2.1. Hello World in PyGTK</a></span></dt><dt><span class="sect1"><a href="sec-TheoryOfSignalsAndCallbacks.html">2.2. Theory of Signals and Callbacks</a></span></dt><dt><span class="sect1"><a href="sec-Events.html">2.3. Events</a></span></dt><dt><span class="sect1"><a href="sec-SteppingThroughHelloWorld.html">2.4. Stepping Through Hello World</a></span></dt></dl></dd><dt><span class="chapter"><a href="ch-MovingOn.html">3. Moving On</a></span></dt><dd><dl><dt><span class="sect1"><a href="ch-MovingOn.html#sec-MoreOnSignalHandlers">3.1. More on Signal Handlers</a></span></dt><dt><span class="sect1"><a href="sec-UpgradedHelloWorld.html">3.2. An Upgraded Hello World</a></span></dt></dl></dd><dt><span class="chapter"><a href="ch-PackingWidgets.html">4. Packing Widgets</a></span></dt><dd><dl><dt><span class="sect1"><a href="ch-PackingWidgets.html#sec-TheoryOfPackingBoxes">4.1. Theory of Packing Boxes</a></span></dt><dt><span class="sect1"><a href="sec-DetailsOfBoxes.html">4.2. Details of Boxes</a></span></dt><dt><span class="sect1"><a href="sec-PackingDemonstrationProgram.html">4.3. Packing Demonstration Program</a></span></dt><dt><span class="sect1"><a href="sec-PackingUsingTables.html">4.4. Packing Using Tables</a></span></dt><dt><span class="sect1"><a href="sec-TablePackingExample.html">4.5. Table Packing Example</a></span></dt></dl></dd><dt><span class="chapter"><a href="ch-WidgetOverview.html">5. Widget Overview</a></span></dt><dd><dl><dt><span class="sect1"><a href="ch-WidgetOverview.html#sec-WidgetHierarchy">5.1. Widget Hierarchy</a></span></dt><dt><span class="sect1"><a href="sec-WidgetsWithoutWindows.html">5.2. Widgets Without Windows</a></span></dt></dl></dd><dt><span class="chapter"><a href="ch-ButtonWidget.html">6. The Button Widget</a></span></dt><dd><dl><dt><span class="sect1"><a href="ch-ButtonWidget.html#sec-NormalButtons">6.1. Normal Buttons</a></span></dt><dt><span class="sect1"><a href="sec-ToggleButtons.html">6.2. Toggle Buttons</a></span></dt><dt><span class="sect1"><a href="sec-CheckButtons.html">6.3. Check Buttons</a></span></dt><dt><span class="sect1"><a href="sec-RadioButtons.html">6.4. Radio Buttons</a></span></dt></dl></dd><dt><span class="chapter"><a href="ch-Adjustments.html">7. Adjustments</a></span></dt><dd><dl><dt><span class="sect1"><a href="ch-Adjustments.html#sec-CreatingAnAdjustment">7.1. Creating an Adjustment</a></span></dt><dt><span class="sect1"><a href="sec-UsingAdjustmentsTheEasyWay.html">7.2. Using Adjustments the Easy Way</a></span></dt><dt><span class="sect1"><a href="sec-AdjustmentInternals.html">7.3. Adjustment Internals</a></span></dt></dl></dd><dt><span class="chapter"><a href="ch-RangeWidgets.html">8. Range Widgets</a></span></dt><dd><dl><dt><span class="sect1"><a href="ch-RangeWidgets.html#sec-ScrollbarWidgets">8.1. Scrollbar Widgets</a></span></dt><dt><span class="sect1"><a href="sec-ScaleWidgets.html">8.2. Scale Widgets</a></span></dt><dd><dl><dt><span class="sect2"><a href="sec-ScaleWidgets.html#id2833070">8.2.1. Creating a Scale Widget</a></span></dt><dt><span class="sect2"><a href="sec-ScaleWidgets.html#id2833123">8.2.2. Methods and Signals (well, methods, at least)</a></span></dt></dl></dd><dt><span class="sect1"><a href="sec-CommonRangeMethods.html">8.3. Common Range Methods</a></span></dt><dd><dl><dt><span class="sect2"><a href="sec-CommonRangeMethods.html#id2785803">8.3.1. Setting the Update Policy</a></span></dt><dt><span class="sect2"><a href="sec-CommonRangeMethods.html#id2785875">8.3.2. Getting and Setting Adjustments</a></span></dt></dl></dd><dt><span class="sect1"><a href="sec-KeyAndMouseBindings.html">8.4. Key and Mouse Bindings</a></span></dt><dt><span class="sect1"><a href="sec-RangeWidgetEample.html">8.5. Range Widget Example</a></span></dt></dl></dd><dt><span class="chapter"><a href="ch-MiscellaneousWidgets.html">9. Miscellaneous Widgets</a></span></dt><dd><dl><dt><span class="sect1"><a href="ch-MiscellaneousWidgets.html#sec-Labels">9.1. Labels</a></span></dt><dt><span class="sect1"><a href="sec-Arrows.html">9.2. Arrows</a></span></dt><dt><span class="sect1"><a href="sec-TooltipsObject.html">9.3. The Tooltips Object</a></span></dt><dt><span class="sect1"><a href="sec-ProgressBars.html">9.4. Progress Bars</a></span></dt><dt><span class="sect1"><a href="sec-Dialogs.html">9.5. Dialogs</a></span></dt><dt><span class="sect1"><a href="sec-Images.html">9.6. Images</a></span></dt><dd><dl><dt><span class="sect2"><a href="sec-Images.html#id2843382">9.6.1. Pixmaps</a></span></dt></dl></dd><dt><span class="sect1"><a href="sec-Rulers.html">9.7. Rulers</a></span></dt><dt><span class="sect1"><a href="sec-Statusbars.html">9.8. Statusbars</a></span></dt><dt><span class="sect1"><a href="sec-TextEntries.html">9.9. Text Entries</a></span></dt><dt><span class="sect1"><a href="sec-SpinButtons.html">9.10. Spin Buttons</a></span></dt><dt><span class="sect1"><a href="sec-ComboWidget.html">9.11. Combo Widget</a></span></dt><dt><span class="sect1"><a href="sec-Calendar.html">9.12. Calendar</a></span></dt><dt><span class="sect1"><a href="sec-ColorSelection.html">9.13. Color Selection</a></span></dt><dt><span class="sect1"><a href="sec-FileSelections.html">9.14. File Selections</a></span></dt><dt><span class="sect1"><a href="sec-FontSelectionDialog.html">9.15. Font Selection Dialog</a></span></dt></dl></dd><dt><span class="chapter"><a href="ch-ContainerWidgets.html">10. Container Widgets</a></span></dt><dd><dl><dt><span class="sect1"><a href="ch-ContainerWidgets.html#sec-EventBox">10.1. The EventBox</a></span></dt><dt><span class="sect1"><a href="sec-Alignment.html">10.2. The Alignment widget</a></span></dt><dt><span class="sect1"><a href="sec-Fixed.html">10.3. Fixed Container</a></span></dt><dt><span class="sect1"><a href="sec-Layout.html">10.4. Layout Container</a></span></dt><dt><span class="sect1"><a href="sec-Frames.html">10.5. Frames</a></span></dt><dt><span class="sect1"><a href="sec-AspectFrames.html">10.6. Aspect Frames</a></span></dt><dt><span class="sect1"><a href="sec-PanedWindowWidgets.html">10.7. Paned Window Widgets</a></span></dt><dt><span class="sect1"><a href="sec-Viewports.html">10.8. Viewports</a></span></dt><dt><span class="sect1"><a href="sec-ScrolledWindows.html">10.9. Scrolled Windows</a></span></dt><dt><span class="sect1"><a href="sec-ButtonBoxes.html">10.10. Button Boxes</a></span></dt><dt><span class="sect1"><a href="sec-Toolbar.html">10.11. Toolbar</a></span></dt><dt><span class="sect1"><a href="sec-Notebooks.html">10.12. Notebooks</a></span></dt><dt><span class="sect1"><a href="sec-PlugsAndSockets.html">10.13. Plugs and Sockets</a></span></dt><dd><dl><dt><span class="sect2"><a href="sec-PlugsAndSockets.html#id2848120">10.13.1. Plugs</a></span></dt><dt><span class="sect2"><a href="sec-PlugsAndSockets.html#id2848244">10.13.2. Sockets</a></span></dt></dl></dd></dl></dd><dt><span class="chapter"><a href="ch-MenuWidget.html">11. Menu Widget</a></span></dt><dd><dl><dt><span class="sect1"><a href="ch-MenuWidget.html#sec-ManualMenuCreation">11.1. Manual Menu Creation</a></span></dt><dt><span class="sect1"><a href="sec-ManualMenuExample.html">11.2. Manual Menu Example</a></span></dt><dt><span class="sect1"><a href="sec-UsingItemFactory.html">11.3. Using ItemFactory</a></span></dt><dt><span class="sect1"><a href="sec-ItemFactoryExample.html">11.4. Item Factory Example</a></span></dt></dl></dd><dt><span class="chapter"><a href="ch-DrawingArea.html">12. Drawing Area</a></span></dt><dd><dl><dt><span class="sect1"><a href="ch-DrawingArea.html#sec-GraphicsContext">12.1. Graphics Context</a></span></dt><dt><span class="sect1"><a href="sec-DrawingMethods.html">12.2. Drawing Methods</a></span></dt></dl></dd><dt><span class="chapter"><a href="ch-TextViewWidget.html">13. TextView Widget</a></span></dt><dd><dl><dt><span class="sect1"><a href="ch-TextViewWidget.html#sec-TextViewOverview">13.1. TextView Overview</a></span></dt><dt><span class="sect1"><a href="sec-TextViews.html">13.2. TextViews</a></span></dt><dt><span class="sect1"><a href="sec-TextBuffers.html">13.3. Text Buffers</a></span></dt><dd><dl><dt><span class="sect2"><a href="sec-TextBuffers.html#id2841804">13.3.1. TextBuffer Status Information</a></span></dt><dt><span class="sect2"><a href="sec-TextBuffers.html#id2841858">13.3.2. Creating TextIters</a></span></dt><dt><span class="sect2"><a href="sec-TextBuffers.html#id2855040">13.3.3. Text Insertion, Retrieval and Deletion</a></span></dt><dt><span class="sect2"><a href="sec-TextBuffers.html#id2855411">13.3.4. TextMarks</a></span></dt><dt><span class="sect2"><a href="sec-TextBuffers.html#id2855626">13.3.5. Creating and Applying TextTags</a></span></dt><dt><span class="sect2"><a href="sec-TextBuffers.html#id2855808">13.3.6. Inserting Images and Widgets</a></span></dt></dl></dd><dt><span class="sect1"><a href="sec-TextIters.html">13.4. Text Iters</a></span></dt><dd><dl><dt><span class="sect2"><a href="sec-TextIters.html#id2856073">13.4.1. TextIter Attributes</a></span></dt><dt><span class="sect2"><a href="sec-TextIters.html#id2856114">13.4.2. Text Attributes at a TextIter</a></span></dt><dt><span class="sect2"><a href="sec-TextIters.html#id2856416">13.4.3. Copying a TextIter</a></span></dt><dt><span class="sect2"><a href="sec-TextIters.html#id2856436">13.4.4. Retrieving Text and Objects</a></span></dt><dt><span class="sect2"><a href="sec-TextIters.html#id2856479">13.4.5. Checking Conditions at a TextIter</a></span></dt><dt><span class="sect2"><a href="sec-TextIters.html#id2856726">13.4.6. Checking Location in Text</a></span></dt><dt><span class="sect2"><a href="sec-TextIters.html#id2856824">13.4.7. Moving Through Text</a></span></dt><dt><span class="sect2"><a href="sec-TextIters.html#id2856958">13.4.8. Moving to a Specific Location</a></span></dt><dt><span class="sect2"><a href="sec-TextIters.html#id2857050">13.4.9. Searching in Text</a></span></dt></dl></dd><dt><span class="sect1"><a href="sec-TextMarks.html">13.5. Text Marks</a></span></dt><dt><span class="sect1"><a href="sec-TextTagsAndTextTagTables.html">13.6. Text Tags and Tag Tables</a></span></dt><dd><dl><dt><span class="sect2"><a href="sec-TextTagsAndTextTagTables.html#sec-TextTags">13.6.1. Text Tags</a></span></dt><dt><span class="sect2"><a href="sec-TextTagsAndTextTagTables.html#sec-TextTagTables">13.6.2. Text Tag Tables</a></span></dt></dl></dd><dt><span class="sect1"><a href="sec-TextViewExample.html">13.7. A TextView Example</a></span></dt></dl></dd><dt><span class="chapter"><a href="ch-TreeViewWidget.html">14. Tree View Widget</a></span></dt><dd><dl><dt><span class="sect1"><a href="ch-TreeViewWidget.html#sec-TreeViewOverview">14.1. Overview</a></span></dt><dt><span class="sect1"><a href="sec-TreeModelInterface.html">14.2. The TreeModel Interface and Data Stores</a></span></dt><dd><dl><dt><span class="sect2"><a href="sec-TreeModelInterface.html#sec-TreeModelIntroduction">14.2.1. Introduction</a></span></dt><dt><span class="sect2"><a href="sec-TreeModelInterface.html#sec-CreatingTreeStoreAndListStore">14.2.2. Creating TreeStore and ListStore Objects</a></span></dt><dt><span class="sect2"><a href="sec-TreeModelInterface.html#sec-ReferringToTreeModelRows">14.2.3. Referring to TreeModel Rows</a></span></dt><dt><span class="sect2"><a href="sec-TreeModelInterface.html#sec-AddingStoreRows">14.2.4. Adding Rows</a></span></dt><dt><span class="sect2"><a href="sec-TreeModelInterface.html#sec-RemovingStoreRows">14.2.5. Removing Rows</a></span></dt><dt><span class="sect2"><a href="sec-TreeModelInterface.html#sec-ManagingRowData">14.2.6. Managing Row Data</a></span></dt><dt><span class="sect2"><a href="sec-TreeModelInterface.html#sec-PythonProtocolSupport">14.2.7. Python Protocol Support</a></span></dt><dt><span class="sect2"><a href="sec-TreeModelInterface.html#sec-TreeModelSignals">14.2.8. TreeModel Signals</a></span></dt><dt><span class="sect2"><a href="sec-TreeModelInterface.html#sec-SortingTreeModelRows">14.2.9. Sorting TreeModel Rows</a></span></dt></dl></dd><dt><span class="sect1"><a href="sec-TreeViews.html">14.3. TreeViews</a></span></dt><dd><dl><dt><span class="sect2"><a href="sec-TreeViews.html#sec-CreatingTreeView">14.3.1. Creating a TreeView</a></span></dt><dt><span class="sect2"><a href="sec-TreeViews.html#sec-TreeViewModelAccess">14.3.2. Getting and Setting the TreeView Model</a></span></dt><dt><span class="sect2"><a href="sec-TreeViews.html#sec-TreeViewProperties">14.3.3. Setting TreeView Properties</a></span></dt></dl></dd><dt><span class="sect1"><a href="sec-CellRenderers.html">14.4. CellRenderers</a></span></dt><dd><dl><dt><span class="sect2"><a href="sec-CellRenderers.html#sec-CellRendererOverview">14.4.1. Overview</a></span></dt><dt><span class="sect2"><a href="sec-CellRenderers.html#sec-CellRendererTypes">14.4.2. CellRenderer Types</a></span></dt><dt><span class="sect2"><a href="sec-CellRenderers.html#sec-CellRendererProperties">14.4.3. CellRenderer Properties</a></span></dt><dt><span class="sect2"><a href="sec-CellRenderers.html#sec-CellRendererAttributes">14.4.4. CellRenderer Attributes</a></span></dt><dt><span class="sect2"><a href="sec-CellRenderers.html#sec-CellDataFunction">14.4.5. Cell Data Function</a></span></dt><dt><span class="sect2"><a href="sec-CellRenderers.html#sec-CellRendererTextMarkup">14.4.6. CellRendererText Markup</a></span></dt><dt><span class="sect2"><a href="sec-CellRenderers.html#EditableTextCells">14.4.7. Editable Text Cells</a></span></dt><dt><span class="sect2"><a href="sec-CellRenderers.html#sec-ActivatableToggleCells">14.4.8. Activatable Toggle Cells</a></span></dt><dt><span class="sect2"><a href="sec-CellRenderers.html#sec-EditableActivatableProgram">14.4.9. Editable and Activatable Cell Example Program</a></span></dt></dl></dd><dt><span class="sect1"><a href="sec-TreeViewColumns.html">14.5. TreeViewColumns</a></span></dt><dd><dl><dt><span class="sect2"><a href="sec-TreeViewColumns.html#sec-CreatingTreeViewColumns">14.5.1. Creating TreeViewColumns</a></span></dt><dt><span class="sect2"><a href="sec-TreeViewColumns.html#sec-ManagingCellRenderers">14.5.2. Managing CellRenderers</a></span></dt></dl></dd><dt><span class="sect1"><a href="sec-ManipulatingTreeViews.html">14.6. Manipulating TreeViews</a></span></dt><dd><dl><dt><span class="sect2"><a href="sec-ManipulatingTreeViews.html#sec-ManagingColumns">14.6.1. Managing Columns</a></span></dt><dt><span class="sect2"><a href="sec-ManipulatingTreeViews.html#sec-ExpandCollapseChildRows">14.6.2. Expanding and Collapsing Child Rows</a></span></dt></dl></dd><dt><span class="sect1"><a href="sec-TreeViewSignals.html">14.7. TreeView Signals</a></span></dt><dt><span class="sect1"><a href="sec-TreeSelections.html">14.8. TreeSelections</a></span></dt><dd><dl><dt><span class="sect2"><a href="sec-TreeSelections.html#sec-GettingTheTreeSelection">14.8.1. Getting the TreeSelection</a></span></dt><dt><span class="sect2"><a href="sec-TreeSelections.html#sec-TreeSelectionMode">14.8.2. TreeSelection Modes</a></span></dt><dt><span class="sect2"><a href="sec-TreeSelections.html#sec-RetrievingTheTreeSelection">14.8.3. Retrieving the Selection</a></span></dt><dt><span class="sect2"><a href="sec-TreeSelections.html#sec-TreeSelectionFunction">14.8.4. Using a TreeSelection Function</a></span></dt><dt><span class="sect2"><a href="sec-TreeSelections.html#sec-SelectingAndUnselectingRows">14.8.5. Selecting and Unselecting Rows</a></span></dt></dl></dd><dt><span class="sect1"><a href="sec-TreeViewDragAndDrop.html">14.9. TreeView Drag and Drop</a></span></dt><dd><dl><dt><span class="sect2"><a href="sec-TreeViewDragAndDrop.html#DragDropReordering">14.9.1. Drag and Drop Reordering</a></span></dt><dt><span class="sect2"><a href="sec-TreeViewDragAndDrop.html#sec-ExternalDragDrop">14.9.2. External Drag and Drop</a></span></dt><dt><span class="sect2"><a href="sec-TreeViewDragAndDrop.html#sec-TreeViewDnDExample">14.9.3. TreeView Drag and Drop Example</a></span></dt></dl></dd><dt><span class="sect1"><a href="sec-TreeModelSortAndTreeModelFilter.html">14.10. TreeModelSort and TreeModelFilter</a></span></dt><dd><dl><dt><span class="sect2"><a href="sec-TreeModelSortAndTreeModelFilter.html#sec-TreeModelSort">14.10.1. TreeModelSort</a></span></dt><dt><span class="sect2"><a href="sec-TreeModelSortAndTreeModelFilter.html#sec-TreeModelFilter">14.10.2. TreeModelFilter</a></span></dt></dl></dd><dt><span class="sect1"><a href="sec-GenericTreeModel.html">14.11. The Generic TreeModel</a></span></dt><dd><dl><dt><span class="sect2"><a href="sec-GenericTreeModel.html#sec-GenericTreeModelOverview">14.11.1. GenericTreeModel Overview</a></span></dt><dt><span class="sect2"><a href="sec-GenericTreeModel.html#sec-GenericTreeModelInterface">14.11.2. The GenericTreeModel Interface</a></span></dt><dt><span class="sect2"><a href="sec-GenericTreeModel.html#sec-AddRemoveGenericTreeModelRows">14.11.3. Adding and Removing Rows</a></span></dt><dt><span class="sect2"><a href="sec-GenericTreeModel.html#sec-GenericTreeModelMemoryManagement">14.11.4. Memory Management</a></span></dt><dt><span class="sect2"><a href="sec-GenericTreeModel.html#sec-OtherInterfaces">14.11.5. Other Interfaces</a></span></dt><dt><span class="sect2"><a href="sec-GenericTreeModel.html#sec-ApplyingGenericTreeModel">14.11.6. Applying The GenericTreeModel</a></span></dt></dl></dd><dt><span class="sect1"><a href="sec-GenericCellRenderer.html">14.12. The Generic CellRenderer</a></span></dt></dl></dd><dt><span class="chapter"><a href="ch-NewInPyGTK2.2.html">15. New Widgets in PyGTK 2.2</a></span></dt><dd><dl><dt><span class="sect1"><a href="ch-NewInPyGTK2.2.html#sec-Clipboards">15.1. Clipboards</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch-NewInPyGTK2.2.html#sec-CreatingClipboard">15.1.1. Creating A Clipboard</a></span></dt><dt><span class="sect2"><a href="ch-NewInPyGTK2.2.html#sec-UsingClipboards">15.1.2. Using Clipboards with Entry, Spinbutton and TextView</a></span></dt><dt><span class="sect2"><a href="ch-NewInPyGTK2.2.html#sec-SettingClipboardData">15.1.3. Setting Data on a Clipboard</a></span></dt><dt><span class="sect2"><a href="ch-NewInPyGTK2.2.html#sec-RetrievingClipboardContents">15.1.4. Retrieving the Clipboard Contents</a></span></dt><dt><span class="sect2"><a href="ch-NewInPyGTK2.2.html#sec-ClipboardExample">15.1.5. A Clipboard Example</a></span></dt></dl></dd></dl></dd><dt><span class="chapter"><a href="ch-NewInPyGTK2.4.html">16. New Widgets in PyGTK 2.4</a></span></dt><dd><dl><dt><span class="sect1"><a href="ch-NewInPyGTK2.4.html#sec-ActionsAndActionGroups">16.1. The Action and ActionGroup Objects</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch-NewInPyGTK2.4.html#sec-Actions">16.1.1. Actions</a></span></dt><dt><span class="sect2"><a href="ch-NewInPyGTK2.4.html#sec-ActionGroups">16.1.2. ActionGroups</a></span></dt></dl></dd><dt><span class="sect1"><a href="sec-ComboBoxAndComboboxEntry.html">16.2. ComboBox and ComboBoxEntry Widgets</a></span></dt><dd><dl><dt><span class="sect2"><a href="sec-ComboBoxAndComboboxEntry.html#sec-ComboBox">16.2.1. ComboBox Widgets</a></span></dt><dt><span class="sect2"><a href="sec-ComboBoxAndComboboxEntry.html#sec-ComboBoxEntry">16.2.2. ComboBoxEntry Widgets</a></span></dt></dl></dd><dt><span class="sect1"><a href="sec-ColorButtonAndFontButton.html">16.3. ColorButton and FontButton Widgets</a></span></dt><dd><dl><dt><span class="sect2"><a href="sec-ColorButtonAndFontButton.html#sec-ColorButton">16.3.1. ColorButton Widgets</a></span></dt><dt><span class="sect2"><a href="sec-ColorButtonAndFontButton.html#sec-FontButton">16.3.2. FontButton Widgets</a></span></dt></dl></dd><dt><span class="sect1"><a href="sec-EntryCompletion.html">16.4. EntryCompletion Objects</a></span></dt><dt><span class="sect1"><a href="sec-ExpanderWidget.html">16.5. Expander Widgets</a></span></dt><dt><span class="sect1"><a href="sec-FileChoosers.html">16.6. File Selections using FileChooser-based Widgets</a></span></dt><dt><span class="sect1"><a href="sec-UIManager.html">16.7. The UIManager</a></span></dt><dd><dl><dt><span class="sect2"><a href="sec-UIManager.html#sec-UIManagerOverview">16.7.1. Overview</a></span></dt><dt><span class="sect2"><a href="sec-UIManager.html#sec-CreatingUIManager">16.7.2. Creating a UIManager</a></span></dt><dt><span class="sect2"><a href="sec-UIManager.html#sec-AddRemoveActionGroups">16.7.3. Adding and Removing ActionGroups</a></span></dt><dt><span class="sect2"><a href="sec-UIManager.html#sec-UIDescriptions">16.7.4. UI Descriptions</a></span></dt><dt><span class="sect2"><a href="sec-UIManager.html#sec-AddRemoveUIDescriptions">16.7.5. Adding and Removing UI Descriptions</a></span></dt><dt><span class="sect2"><a href="sec-UIManager.html#sec-AccessingUIWidgets">16.7.6. Accessing UI Widgets</a></span></dt><dt><span class="sect2"><a href="sec-UIManager.html#sec-SimpleUIManagerExample">16.7.7. A Simple UIManager Example</a></span></dt><dt><span class="sect2"><a href="sec-UIManager.html#sec-MergingUIDescriptions">16.7.8. Merging UI Descriptions</a></span></dt><dt><span class="sect2"><a href="sec-UIManager.html#sec-UIManagerSignals">16.7.9. UIManager Signals</a></span></dt></dl></dd></dl></dd><dt><span class="chapter"><a href="ch-UndocumentedWidgets.html">17. Undocumented Widgets</a></span></dt><dd><dl><dt><span class="sect1"><a href="ch-UndocumentedWidgets.html#sec-AccelLabel">17.1. Accel Label</a></span></dt><dt><span class="sect1"><a href="sec-OptionMenu.html">17.2. Option Menu</a></span></dt><dt><span class="sect1"><a href="sec-MenuItems.html">17.3. Menu Items</a></span></dt><dd><dl><dt><span class="sect2"><a href="sec-MenuItems.html#id2834318">17.3.1. Check Menu Item</a></span></dt><dt><span class="sect2"><a href="sec-MenuItems.html#id2906601">17.3.2. Radio Menu Item</a></span></dt><dt><span class="sect2"><a href="sec-MenuItems.html#id2906613">17.3.3. Separator Menu Item</a></span></dt><dt><span class="sect2"><a href="sec-MenuItems.html#id2879329">17.3.4. Tearoff Menu Item</a></span></dt></dl></dd><dt><span class="sect1"><a href="sec-Curves.html">17.4. Curves</a></span></dt><dt><span class="sect1"><a href="sec-MessageDialog.html">17.5. Message Dialog</a></span></dt><dt><span class="sect1"><a href="sec-GammaCurve.html">17.6. Gamma Curve</a></span></dt></dl></dd><dt><span class="chapter"><a href="ch-SettingWidgetAttributes.html">18. Setting Widget Attributes</a></span></dt><dd><dl><dt><span class="sect1"><a href="ch-SettingWidgetAttributes.html#sec-WidgetFlagMethods">18.1. Widget Flag Methods</a></span></dt><dt><span class="sect1"><a href="sec-WidgetDisplayMethods.html">18.2. Widget Display Methods</a></span></dt><dt><span class="sect1"><a href="sec-WidgetAccelerators.html">18.3. Widget Accelerators</a></span></dt><dt><span class="sect1"><a href="sec-WidgetNameMethods.html">18.4. Widget Name Methods</a></span></dt><dt><span class="sect1"><a href="sec-WidgetStyles.html">18.5. Widget Styles</a></span></dt></dl></dd><dt><span class="chapter"><a href="ch-TimeoutsIOAndIdleFunctions.html">19. Timeouts, IO and Idle Functions</a></span></dt><dd><dl><dt><span class="sect1"><a href="ch-TimeoutsIOAndIdleFunctions.html#sec-Timeouts">19.1. Timeouts</a></span></dt><dt><span class="sect1"><a href="sec-MonitoringIO.html">19.2. Monitoring IO</a></span></dt><dt><span class="sect1"><a href="sec-IdleFunctions.html">19.3. Idle Functions</a></span></dt></dl></dd><dt><span class="chapter"><a href="ch-AdvancedEventAndSignalHandling.html">20. Advanced Event and Signal Handling</a></span></dt><dd><dl><dt><span class="sect1"><a href="ch-AdvancedEventAndSignalHandling.html#sec-SignalMethods">20.1. Signal Methods</a></span></dt><dd><dl><dt><span class="sect2"><a href="ch-AdvancedEventAndSignalHandling.html#id2837542">20.1.1. Connecting and Disconnecting Signal Handlers</a></span></dt><dt><span class="sect2"><a href="ch-AdvancedEventAndSignalHandling.html#id2871063">20.1.2. Blocking and Unblocking Signal Handlers</a></span></dt><dt><span class="sect2"><a href="ch-AdvancedEventAndSignalHandling.html#id2810158">20.1.3. Emitting and Stopping Signals</a></span></dt></dl></dd><dt><span class="sect1"><a href="sec-SignalEmissionAndPropagation.html">20.2. Signal Emission and Propagation</a></span></dt></dl></dd><dt><span class="chapter"><a href="ch-ManagingSelections.html">21. Managing Selections</a></span></dt><dd><dl><dt><span class="sect1"><a href="ch-ManagingSelections.html#sec-SelectionOverview">21.1. Selection Overview</a></span></dt><dt><span class="sect1"><a href="sec-RetrievingTheSelection.html">21.2. Retrieving the Selection</a></span></dt><dt><span class="sect1"><a href="sec-SupplyingTheSelection.html">21.3. Supplying the Selection</a></span></dt></dl></dd><dt><span class="chapter"><a href="ch-DragAndDrop.html">22. Drag-and-drop (DND)</a></span></dt><dd><dl><dt><span class="sect1"><a href="ch-DragAndDrop.html#sec-DNDOverview">22.1. DND Overview</a></span></dt><dt><span class="sect1"><a href="sec-DNDProperties.html">22.2. DND Properties</a></span></dt><dt><span class="sect1"><a href="sec-DNDMethods.html">22.3. DND Methods</a></span></dt><dd><dl><dt><span class="sect2"><a href="sec-DNDMethods.html#id2793141">22.3.1. Setting Up the Source Widget</a></span></dt><dt><span class="sect2"><a href="sec-DNDMethods.html#sec-SignalsOnSourceWidget">22.3.2. Signals On the Source Widget</a></span></dt><dt><span class="sect2"><a href="sec-DNDMethods.html#sec-SettingUpDestinationWidget">22.3.3. Setting Up a Destination Widget</a></span></dt><dt><span class="sect2"><a href="sec-DNDMethods.html#sec-SignalsOnDestinationWidget">22.3.4. Signals On the Destination Widget</a></span></dt></dl></dd></dl></dd><dt><span class="chapter"><a href="ch-GtkRcFiles.html">23. GTK's rc Files</a></span></dt><dd><dl><dt><span class="sect1"><a href="ch-GtkRcFiles.html#sec-FunctionsForRcFiles">23.1. Functions For rc Files</a></span></dt><dt><span class="sect1"><a href="sec-GTKRcFileFormat.html">23.2. GTK's rc File Format</a></span></dt><dt><span class="sect1"><a href="sec-ExampleRcFile.html">23.3. Example rc file</a></span></dt></dl></dd><dt><span class="chapter"><a href="ch-Scribble.html">24. Scribble, A Simple Example Drawing Program</a></span></dt><dd><dl><dt><span class="sect1"><a href="ch-Scribble.html#sec-ScribbleOverview">24.1. Scribble Overview</a></span></dt><dt><span class="sect1"><a href="sec-EventHandling.html">24.2. Event Handling</a></span></dt><dd><dl><dt><span class="sect2"><a href="sec-EventHandling.html#id2867711">24.2.1. Scribble - Event Handling</a></span></dt></dl></dd><dt><span class="sect1"><a href="sec-DrawingAreaWidgetAndDrawing.html">24.3. The DrawingArea Widget, And Drawing</a></span></dt></dl></dd><dt><span class="chapter"><a href="ch-TipsForWritingPyGTKApplications.html">25. Tips For Writing PyGTK Applications</a></span></dt><dt><span class="chapter"><a href="ch-Contributing.html">26. Contributing</a></span></dt><dt><span class="chapter"><a href="ch-Credits.html">27. Credits</a></span></dt><dd><dl><dt><span class="sect1"><a href="ch-Credits.html#sec-PyGTKCredits">27.1. PyGTK Credits</a></span></dt><dt><span class="sect1"><a href="sec-OriginalGTK+Credits.html">27.2. Original GTK+ Credits</a></span></dt></dl></dd><dt><span class="chapter"><a href="ch-Copyright.html">28. Tutorial Copyright and Permissions Notice</a></span></dt><dt><span class="appendix"><a href="app-GtkSignals.html">A. GTK Signals</a></span></dt><dd><dl><dt><span class="sect1"><a href="app-GtkSignals.html#sec-GtkObject">A.1. GtkObject</a></span></dt><dt><span class="sect1"><a href="sec-GtkWidget.html">A.2. GtkWidget</a></span></dt><dt><span class="sect1"><a href="sec-GtkData.html">A.3. GtkData</a></span></dt><dt><span class="sect1"><a href="sec-GtkContainer.html">A.4. GtkContainer</a></span></dt><dt><span class="sect1"><a href="sec-GtkCalendar.html">A.5. GtkCalendar</a></span></dt><dt><span class="sect1"><a href="sec-GtkEditable.html">A.6. GtkEditable</a></span></dt><dt><span class="sect1"><a href="sec-GtkNotebook.html">A.7. GtkNotebook</a></span></dt><dt><span class="sect1"><a href="sec-GtkList.html">A.8. GtkList</a></span></dt><dt><span class="sect1"><a href="sec-GtkMenuShell.html">A.9. GtkMenuShell</a></span></dt><dt><span class="sect1"><a href="sec-GtkToolbar.html">A.10. GtkToolbar</a></span></dt><dt><span class="sect1"><a href="sec-GtkButton.html">A.11. GtkButton</a></span></dt><dt><span class="sect1"><a href="sec-GtkItem.html">A.12. GtkItem</a></span></dt><dt><span class="sect1"><a href="sec-GtkWindow.html">A.13. GtkWindow</a></span></dt><dt><span class="sect1"><a href="sec-GtkHandleBox.html">A.14. GtkHandleBox</a></span></dt><dt><span class="sect1"><a href="sec-GtkToggleButton.html">A.15. GtkToggleButton</a></span></dt><dt><span class="sect1"><a href="sec-GtkMenuItem.html">A.16. GtkMenuItem</a></span></dt><dt><span class="sect1"><a href="sec-GtkCheckMenuItem.html">A.17. GtkCheckMenuItem</a></span></dt><dt><span class="sect1"><a href="sec-GtkInputDialog.html">A.18. GtkInputDialog</a></span></dt><dt><span class="sect1"><a href="sec-GtkColorSelection.html">A.19. GtkColorSelection</a></span></dt><dt><span class="sect1"><a href="sec-GtkStatusBar.html">A.20. GtkStatusBar</a></span></dt><dt><span class="sect1"><a href="sec-GtkCurve.html">A.21. GtkCurve</a></span></dt><dt><span class="sect1"><a href="sec-GtkAdjustment.html">A.22. GtkAdjustment</a></span></dt></dl></dd><dt><span class="appendix"><a href="app-CodeExamples.html">B. Code Examples</a></span></dt><dd><dl><dt><span class="sect1"><a href="app-CodeExamples.html#sec-scribblesimple.py">B.1. scribblesimple.py</a></span></dt></dl></dd><dt><span class="appendix"><a href="pygtk-tut-changelog.html">C. ChangeLog</a></span></dt></dl></div><div class="list-of-figures"><p><b>List of Figures</b></p><dl><dt>2.1. <a href="ch-GettingStarted.html#basefig">Simple PyGTK Window</a></dt><dt>2.2. <a href="ch-GettingStarted.html#helloworldfig">Hello World Example Program</a></dt><dt>3.1. <a href="sec-UpgradedHelloWorld.html#helloworld2fig">Upgraded Hello World Example</a></dt><dt>4.1. <a href="sec-DetailsOfBoxes.html#packbox1fig">Packing: Five Variations</a></dt><dt>4.2. <a href="sec-DetailsOfBoxes.html#packbox2fig">Packing with Spacing and Padding</a></dt><dt>4.3. <a href="sec-DetailsOfBoxes.html#packbox3fig">Packing with pack_end()</a></dt><dt>4.4. <a href="sec-TablePackingExample.html#tablefig">Packing using a Table</a></dt><dt>6.1. <a href="ch-ButtonWidget.html#buttonfig">Button with Pixmap and Label</a></dt><dt>6.2. <a href="sec-ToggleButtons.html#togglefig">Toggle Button Example</a></dt><dt>6.3. <a href="sec-CheckButtons.html#checkbuttonfig">Check Button Example</a></dt><dt>6.4. <a href="sec-RadioButtons.html#radiobuttonfig">Radio Buttons Example</a></dt><dt>8.1. <a href="sec-RangeWidgetEample.html#rangefig">Range Widgets Example</a></dt><dt>9.1. <a href="ch-MiscellaneousWidgets.html#labelexamplesfig">Label Examples</a></dt><dt>9.2. <a href="sec-Arrows.html#arrowsfig">Arrows Buttons Examples</a></dt><dt>9.3. <a href="sec-TooltipsObject.html#tooltipsfig">Tooltips Example</a></dt><dt>9.4. <a href="sec-ProgressBars.html#progressbarfig">ProgressBar Example</a></dt><dt>9.5. <a href="sec-Images.html#imagesfig">Example Images in Buttons</a></dt><dt>9.6. <a href="sec-Images.html#pixmapfig">Pixmap in a Button Example</a></dt><dt>9.7. <a href="sec-Images.html#wheelbarrowfig">Wheelbarrow Example Shaped Window</a></dt><dt>9.8. <a href="sec-Rulers.html#rulersfig">Rulers Example</a></dt><dt>9.9. <a href="sec-Statusbars.html#statusbarfig">Statusbar Example</a></dt><dt>9.10. <a href="sec-TextEntries.html#entryfig">Entry Example</a></dt><dt>9.11. <a href="sec-SpinButtons.html#spingbuttonfig">Spin Button Example</a></dt><dt>9.12. <a href="sec-Calendar.html#calendarfig">Calendar Example</a></dt><dt>9.13. <a href="sec-ColorSelection.html#colorselfig">Color Selection Dialog Example</a></dt><dt>9.14. <a href="sec-FileSelections.html#fileselfig">File Selection Example</a></dt><dt>9.15. <a href="sec-FontSelectionDialog.html#fontselfig">Font Selection Dialog</a></dt><dt>10.1. <a href="ch-ContainerWidgets.html#eventboxfig">Event Box Example</a></dt><dt>10.2. <a href="sec-Fixed.html#fixedfig">Fixed Example</a></dt><dt>10.3. <a href="sec-Layout.html#layoutfig">Layout Example</a></dt><dt>10.4. <a href="sec-Frames.html#framefig">Frame Example</a></dt><dt>10.5. <a href="sec-AspectFrames.html#aspectframefig">Aspect Frame Example</a></dt><dt>10.6. <a href="sec-PanedWindowWidgets.html#panedfig">Paned Example</a></dt><dt>10.7. <a href="sec-ScrolledWindows.html#scrolledwin">Scrolled Window Example</a></dt><dt>10.8. <a href="sec-Toolbar.html#toolbarfig">Toolbar Example</a></dt><dt>10.9. <a href="sec-Notebooks.html#notebookfig">Notebook Example</a></dt><dt>11.1. <a href="sec-ManualMenuExample.html#menufig">Menu Example</a></dt><dt>11.2. <a href="sec-ItemFactoryExample.html#itemfactoryfig">Item Factory Example</a></dt><dt>12.1. <a href="sec-DrawingMethods.html#drawingareafig">Drawing Area Example</a></dt><dt>13.1. <a href="sec-TextViews.html#textviewbasicfig">Basic TextView Example</a></dt><dt>13.2. <a href="sec-TextViewExample.html#testtextfig">TextView Example</a></dt><dt>14.1. <a href="ch-TreeViewWidget.html#basictreeviewfig">Basic TreeView Example Program</a></dt><dt>14.2. <a href="sec-CellRenderers.html#treeviewcolumnfig">TreeViewColumns with CellRenderers</a></dt><dt>14.3. <a href="sec-CellRenderers.html#celldatafuncfig">CellRenderer Data Function</a></dt><dt>14.4. <a href="sec-CellRenderers.html#filelistingfig">File Listing Example Using Cell Data Functions</a></dt><dt>14.5. <a href="sec-CellRenderers.html#celltextmarkupfig">CellRendererText Markup</a></dt><dt>14.6. <a href="sec-CellRenderers.html#cellrendererfig">Editable and Activatable Cells</a></dt><dt>14.7. <a href="sec-ManipulatingTreeViews.html#treeviewcolumn1expanderfig">Expander Arrow in Second Column</a></dt><dt>14.8. <a href="sec-TreeViewDragAndDrop.html#treeviewdndfig">TreeView Drag and Drop Example</a></dt><dt>14.9. <a href="sec-TreeModelSortAndTreeModelFilter.html#treemodelsortfig">TreeModelSort Example</a></dt><dt>14.10. <a href="sec-TreeModelSortAndTreeModelFilter.html#treemodelfilterfig">TreeModelFilter Visibility Example</a></dt><dt>14.11. <a href="sec-GenericTreeModel.html#filelistinggtmfig">Generic TreeModel Example Program</a></dt><dt>15.1. <a href="ch-NewInPyGTK2.2.html#clipboardfig">Clipboard Example Program</a></dt><dt>16.1. <a href="ch-NewInPyGTK2.4.html#simpleactionfig">Simple Action Example</a></dt><dt>16.2. <a href="ch-NewInPyGTK2.4.html#basicactionfig">Basic Action Example</a></dt><dt>16.3. <a href="ch-NewInPyGTK2.4.html#actionsfig">Actions Example</a></dt><dt>16.4. <a href="ch-NewInPyGTK2.4.html#actiongroupfig">ActionGroup Example</a></dt><dt>16.5. <a href="sec-ComboBoxAndComboboxEntry.html#comboboxbasicfig">Basic ComboBox</a></dt><dt>16.6. <a href="sec-ComboBoxAndComboboxEntry.html#comboboxwrapfig">ComboBox with Wrapped Layout</a></dt><dt>16.7. <a href="sec-ComboBoxAndComboboxEntry.html#comboboxentrybasicfig">Basic ComboBoxEntry</a></dt><dt>16.8. <a href="sec-ColorButtonAndFontButton.html#colorbuttonfig">ColorButton Example</a></dt><dt>16.9. <a href="sec-ColorButtonAndFontButton.html#fontbuttonfig">FontButton Example</a></dt><dt>16.10. <a href="sec-EntryCompletion.html#entrycompletionfig">EntryCompletion</a></dt><dt>16.11. <a href="sec-ExpanderWidget.html#expanderfig">Expander Widget</a></dt><dt>16.12. <a href="sec-FileChoosers.html#filechooserfig">File Selection Example</a></dt><dt>16.13. <a href="sec-UIManager.html#uimanagerfig">Simple UIManager Example</a></dt><dt>16.14. <a href="sec-UIManager.html#uimergefig">UIMerge Example</a></dt><dt>21.1. <a href="sec-RetrievingTheSelection.html#getselectionfig">Get Selection Example</a></dt><dt>21.2. <a href="sec-SupplyingTheSelection.html#setselectionfig">Set Selection Example</a></dt><dt>22.1. <a href="sec-DNDMethods.html#dragndropfig">Drag and Drop Example</a></dt><dt>24.1. <a href="ch-Scribble.html#scribblesimplefig">Scribble Drawing Program Example</a></dt><dt>24.2. <a href="sec-EventHandling.html#simplescribblefig">Simple Scribble Example</a></dt></dl></div><div class="list-of-tables"><p><b>List of Tables</b></p><dl><dt>22.1. <a href="sec-DNDMethods.html#id2878807">Source Widget Signals</a></dt><dt>22.2. <a href="sec-DNDMethods.html#id2873419">Destination Widget Signals</a></dt></dl></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="ch-Introduction.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top"> </td><td width="20%" align="center"> </td><td width="40%" align="right" valign="top"> Chapter 1. Introduction</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/pygtk-tut-changelog.html b/help/Pygtk2Tutorial/pygtk2tutorial/pygtk-tut-changelog.html
new file mode 100644
index 0000000..772d6a7
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/pygtk-tut-changelog.html
@@ -0,0 +1,370 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>Appendix C. ChangeLog</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="previous" href="app-CodeExamples.html" title="Appendix B. Code Examples"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Appendix C. ChangeLog</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="app-CodeExamples.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> </td></tr></table><hr></div><div class="appendix" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="pygtk-tut-changelog"></a>Appendix C. ChangeLog</h2></div></div><div></div></div><div class="literallayout"><p><br>
+<span class="bold"><b>2006-03-02  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * <tt class="filename">pygtk2-tut.xml:</tt> Bump revision number and date.<br>
+<br>
+        * <tt class="filename">DragAndDrop.xml:</tt> Add drag finish to dragtargets.py example.<br>
+<br>
+        ============== 2.4 ==================<br>
+<span class="bold"><b>2005-04-13  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * <tt class="filename">pygtk2-tut.xml:</tt> Set version number and pubdate.<br>
+<br>
+        * <tt class="filename">Copyright.xml:</tt> Update date.<br>
+<br>
+        * <tt class="filename">Replace</tt> gtk.TRUE and gtk.FALSE. Fix misc. other deprecations.<br>
+<br>
+<span class="bold"><b>2005-03-31  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * <tt class="filename">ComboBoxAndComboBoxEntry.xml:</tt> Convenience function is<br>
+        gtk.combo_box_entry_new_text(<span class="emphasis"><em></em></span>). (<span class="emphasis"><em>brett@belizebotanic.org</em></span>)<br>
+<br>
+<span class="bold"><b>2005-02-28  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * <tt class="filename">GettingStarted.xml</tt> (<span class="emphasis"><em>Stepping</em></span>) add print statement to destroy<br>
+        handler for illustrative purposes. (<span class="emphasis"><em>Rodolfo Gouveia</em></span>)<br>
+<br>
+        ============== 2.3 ==================<br>
+<span class="bold"><b>2004-12-24  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * <tt class="filename">pygtk2-tut.xml:</tt> Set version number and pubdate. Add revhistory.<br>
+<br>
+        * <tt class="filename">UIManager.xml:</tt> Add.<br>
+<br>
+<span class="bold"><b>2004-12-13  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * <tt class="filename">MovingOn.xml:</tt> Remove reference to WINODW_DIALOG (<span class="emphasis"><em>Jens Knutson</em></span>)<br>
+<br>
+<span class="bold"><b>2004-12-08  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * <tt class="filename">DragAndDrop.xml</tt> Patch from Rafael Villar Burke<br>
+<br>
+<span class="bold"><b>2004-12-01  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * <tt class="filename">Scribble.xml</tt> Patch by Rafael Villar Burke.<br>
+<br>
+<span class="bold"><b>2004-11-29  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * <tt class="filename">ComboBoxAndComboBoxEntry.xml</tt> Patch by Rafael Villar Burke.<br>
+        * <tt class="filename">TimeoutsIOAndIdleFunctions.xml</tt> Patch by Rafael Villar Burke.<br>
+<br>
+        * <tt class="filename">AdvancedEventAndSignalHandling.xml</tt> Add parameter tags to function<br>
+        and method defs. Patch by Rafael Villar Burke.<br>
+<br>
+<span class="bold"><b>2004-11-20  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * <tt class="filename">ColorButtonAndFontButton.xml:</tt> <br>
+        * <tt class="filename">SettingWidgetAttributes.xml:</tt> Fix xml tags. (<span class="emphasis"><em>Rafael Villar Burke</em></span>)<br>
+<br>
+<span class="bold"><b>2004-10-31  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * ExpanderWidget.xml<br>
+        * GenericTreeModel.xml<br>
+        * <tt class="filename">CellRenderers.xml</tt> Fixes by Rafael Villar Burke.<br>
+<br>
+<span class="bold"><b>2004-10-28  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * <tt class="filename">TreeViewWidget.xml</tt> Fixes by Rafael Villar Burke.<br>
+<br>
+<span class="bold"><b>2004-10-24  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * <tt class="filename">ContainerWidgets.xml</tt> Many fixes by Rafael Villar Burke.<br>
+<br>
+        * <tt class="filename">MiscellaneaousWidgets.xml</tt> Many fixes by Rafael Villar Burke.<br>
+<br>
+<span class="bold"><b>2004-10-13  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * <tt class="filename">PackingWidgets.xml</tt> ButtonWidget.xml Fix typos per kraai<br>
+        Fixes #155318.<br>
+<br>
+<span class="bold"><b>2004-09-20  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * <tt class="filename">TextViewWidget.xml</tt> Minor fixes by Rafael Villar Burke.<br>
+<br>
+        * <tt class="filename">ActionsAndActionGroups.xml</tt> Add.<br>
+        * <tt class="filename">NewInPyGTK2.4.xml</tt> Include ActionsAndActionGroups.xml<br>
+<br>
+<span class="bold"><b>2004-09-12  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * <tt class="filename">TreeModel.xml</tt> (<span class="emphasis"><em>sec-ManagingRowData</em></span>) Minor fix. Patch by<br>
+        Rafael Villar Burke<br>
+<br>
+<span class="bold"><b>2004-09-08  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * <tt class="filename">ContainerWidgets.xml</tt> (<span class="emphasis"><em>sec-AspectFrames</em></span>)<br>
+        (<span class="emphasis"><em>sec-Alignment</em></span>) Fix link to Ref manual.<br>
+<br>
+<span class="bold"><b>2004-08-31  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * <tt class="filename">DrawingArea.xml</tt> Rewrite portions based on patch by Rafael Villar <br>
+        Burke.<br>
+<br>
+        * <tt class="filename">DrawingArea.xml</tt> Add missing literal tags.<br>
+        Patch by Rafael Villar Burke.<br>
+<br>
+<span class="bold"><b>2004-08-21  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * <tt class="filename">ColorButtonAndFontButton.xml</tt> Add.<br>
+<br>
+        * <tt class="filename">NewInPyGTK24.xml</tt> Include ColorButtonAndFontButton.xml.<br>
+<br>
+<span class="bold"><b>2004-08-19  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * <tt class="filename">Scribble.xml</tt> (<span class="emphasis"><em>sec-DrawingAreaWidgetAndDrawing</em></span>)<br>
+        Update example description.<br>
+<br>
+<span class="bold"><b>2004-08-16  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * <tt class="filename">CellRenderers.xml</tt> Add cellrenderer.py example program section<br>
+<br>
+        * <tt class="filename">Credits.xml</tt> Credit Steve George for cellrenderer.py example<br>
+        program.<br>
+<br>
+<span class="bold"><b>2004-08-15  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * <tt class="filename">CellRenderers.xml</tt> (<span class="emphasis"><em>Activatable Toggle Cells</em></span>) Add info about<br>
+        setting the toggle from a column. (<span class="emphasis"><em>#150212</em></span>) (<span class="emphasis"><em>Steve George</em></span>)<br>
+<br>
+<span class="bold"><b>2004-08-13  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * <tt class="filename">TreeModel.xml</tt> Clean up Adding TreeStore rows section (<span class="emphasis"><em>Joey Tsai</em></span>)<br>
+        Add missing text in Large Data Stores section.. (<span class="emphasis"><em>Joey Tsai</em></span>)<br>
+<br>
+<span class="bold"><b>2004-08-08  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * TreeModel.xml<br>
+        * CellRenderers.xml<br>
+        * GenericTreeModel.xml<br>
+        * TreeViewWidget.xml<br>
+        * <tt class="filename">NewWidgetsAndObjects.xml</tt> Minor rewording and addition of tags.<br>
+<br>
+<span class="bold"><b>2004-08-06  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * <tt class="filename">ButtonWidget.xml</tt> Fix errors in examples.<br>
+        * <tt class="filename">DragAndDrop.xml</tt> Fix anchor.<br>
+        * <tt class="filename">MenuWidget.xml</tt> Fix typo.<br>
+        * <tt class="filename">PackingWidgets.xml</tt> Fix typo.<br>
+        * <tt class="filename">MiscellaneousWidgets.xml</tt> (<span class="emphasis"><em>Dialogs</em></span>) (<span class="emphasis"><em>Images</em></span>) (<span class="emphasis"><em>Pixmaps</em></span>) (<span class="emphasis"><em>Rulers</em></span>)<br>
+        (<span class="emphasis"><em>Progressbar</em></span>) (<span class="emphasis"><em>Label</em></span>)<br>
+        Fix faulty wording and errors (<span class="emphasis"><em>All thanks to Marc Verney</em></span>)<br>
+<br>
+<span class="bold"><b>2004-08-04  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * <tt class="filename">DrawingArea.xml</tt> Update example to use rulers and scrolled<br>
+        window.<br>
+<br>
+        * <tt class="filename">pygtk2-tut.xml</tt> Bump version number and pubdate.<br>
+<br>
+        ============== 2.2 ==================<br>
+<span class="bold"><b>2004-08-03  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * <tt class="filename">ComboBoxAndComboBoxEntry.xml</tt> Add.<br>
+<br>
+        * <tt class="filename">EntryCompletion.xml</tt> Add.<br>
+<br>
+        * <tt class="filename">ExpanderWidget.xml</tt> Add.<br>
+<br>
+        * <tt class="filename">NewInPyGTK24.xml</tt> Add.<br>
+<br>
+        * <tt class="filename">NewWidgetsAndObject.xml</tt> Rearrange and make as a chapter.<br>
+<br>
+        * <tt class="filename">pygtk2-tut.xml</tt> Add NewInPyGTK24.xml. Update date.<br>
+<br>
+<span class="bold"><b>2004-08-02  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * <tt class="filename">MiscellaneousWidgets.xml</tt> Change Combo Box to Combo Widget to avoid<br>
+        confusion with new ComboBox widget. Add deprecation note.<br>
+<br>
+<span class="bold"><b>2004-07-28  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * <tt class="filename">Credits.xml</tt> Add PyGTK section with credit to Nathan Durst and <br>
+        Alex Roitman.<br>
+<br>
+        * <tt class="filename">FileChooser.xml</tt> Create.<br>
+        * <tt class="filename">NewWidgetsAndObject.xml</tt> Add include for FileChooser.xml.<br>
+<br>
+        * <tt class="filename">NewWidgetsAndObject.xml</tt> Create.<br>
+<br>
+        * <tt class="filename">pygtk2-tut.xml</tt> Add NewWidgetsAndObject.xml file. Bump version<br>
+        number and set date.<br>
+<br>
+<span class="bold"><b>2004-07-20  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * <tt class="filename">TreeViewWidget.xml</tt> (<span class="emphasis"><em>sec-ManagingCellRenderers</em></span>) Fix title.<br>
+        More detail on set_sort_column_id(<span class="emphasis"><em></em></span>).<br>
+<br>
+<span class="bold"><b>2004-07-12  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * <tt class="filename">TreeViewWidget.xml</tt> (<span class="emphasis"><em>sec-CreatingTreeView</em></span>) Fix faulty capitalization.<br>
+        (<span class="emphasis"><em>thanks to Doug Quale</em></span>)<br>
+<br>
+<span class="bold"><b>2004-07-08  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * <tt class="filename">Adjustments.xml</tt> AdvancedEventAndSignalHandling.xml<br>
+        ButtonWidget.xml ChangeLog ContainerWidgets.xml<br>
+        DragAndDrop.xml DrawingArea.xml GettingStarted.xml<br>
+        ManagingSelections.xml MenuWidget.xml<br>
+        MiscellaneousWidgets.xml MovingOn.xml<br>
+        PackingWidgets.xml RangeWidgets.xml Scribble.xml<br>
+        SettingWidgetAttributes.xml TextViewWidget.xml<br>
+        TimeoutsIOAndIdleFunctions.xml WidgetOverview.xml<br>
+        Update files with example programs.<br>
+<br>
+<span class="bold"><b>2004-07-06  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * <tt class="filename">examples/*.py</tt> Update examples to eliminate deprecated methods<br>
+        and use import pygtk.<br>
+<br>
+        ============== 2.1 ==================<br>
+<span class="bold"><b>2004-07-06  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * <tt class="filename">pygtk2-tut.xml</tt> Bump version number to 2.1 and set<br>
+        pubdate.<br>
+<br>
+        * <tt class="filename">TreeViewWidgets.xml</tt> Revise the treeviewdnd.py example to<br>
+        illustrate row reordering with external drag and drop and<br>
+        add explanation.<br>
+<br>
+<span class="bold"><b>2004-07-03  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * <tt class="filename">TimeoutsIOAndIdleFunctions.xml</tt> Update descriptions to use<br>
+        the gobject functions.<br>
+<br>
+<span class="bold"><b>2004-06-30  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * <tt class="filename">TreeViewWidget.xml</tt> Extract the CellRenderers section into<br>
+        CellRenderers.xml.<br>
+<br>
+        * <tt class="filename">CellRenderers.xml</tt> Create and add section on editable<br>
+        CellRendererText.<br>
+<br>
+        * <tt class="filename">TreeViewWidget.xml</tt> Extract the TreeModel section and put into<br>
+        new file TreeModel.xml. Add detail to the TreeViewColumn use of<br>
+        its sort column ID.<br>
+<br>
+        * <tt class="filename">TreeModel.xml</tt> Create and add section on sorting TreeModel rows<br>
+        using the TreeSortable interface.<br>
+<br>
+<span class="bold"><b>2004-06-27  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * <tt class="filename">TreeViewWidget.xml</tt> (<span class="emphasis"><em>Cell Data Function</em></span>) Add filelisting example<br>
+        using cell data functions. Add XInclude header to include generic<br>
+        tree model and cell renderer subsections.<br>
+        Fix typos and errors in links. Fix bugs in example listings.<br>
+        Add section on TreeModel signals.<br>
+<br>
+<span class="bold"><b>2004-06-22  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * <tt class="filename">Introduction.xml</tt> Add note about pygtkconsole.py and gpython.py<br>
+        programs do not work on Windows. Thanks to vector180.<br>
+<br>
+<span class="bold"><b>2004-06-14  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * <tt class="filename">DragAndDrop.xml</tt> Fix signal lists for drag source and dest.<br>
+        Add detail to the overview drag cycle. Add detail about signal<br>
+        handler operation.<br>
+<br>
+        * <tt class="filename">DragAndDrop.xml</tt> Add small example program dragtargets.py to<br>
+        print out drag targets.<br>
+<br>
+<span class="bold"><b>2004-05-31  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * <tt class="filename">GettingStarted.xml</tt> Change wording in helloworld.py example<br>
+        program - delete_event(<span class="emphasis"><em></em></span>) comments confusing. Thanks to Ming Hua.<br>
+<br>
+<span class="bold"><b>2004-05-28  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * <tt class="filename">TreeViewWidget.xml</tt> (<span class="emphasis"><em>TreeModelFilter</em></span>) Replace 'file' with 'filter'.<br>
+        Thanks to Guilherme Salgado.<br>
+<br>
+<span class="bold"><b>2004-05-27  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * <tt class="filename">TreeViewWidget.xml</tt> (<span class="emphasis"><em>AccessingDataValues</em></span>) Fix store.set example<br>
+        column number wrong. Thanks to Rafael Villar Burke and Guilherme<br>
+        Salgado.<br>
+        (<span class="emphasis"><em>CellRendererAttributes</em></span>) Fix error. Thanks to Doug Quale.<br>
+        (<span class="emphasis"><em>TreeModelIntroduction</em></span>)<br>
+        (<span class="emphasis"><em>PythonProtocolSupport</em></span>) Fix grammatical and spelling errors.<br>
+        Thanks to Thomas Mills Hinkle.<br>
+<br>
+<span class="bold"><b>2004-05-25  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * <tt class="filename">Introduction.xml</tt> Add reference links to www.pygtk.org website<br>
+        and describe some of its resources.<br>
+<br>
+        ============ 2.0 ==============<br>
+<span class="bold"><b>2004-05-24  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * <tt class="filename">TreeViewWidget.xml</tt> Add beginning of tutorial chapter.<br>
+<br>
+        * <tt class="filename">Introduction.xml</tt> Add reference to gpython.py program.<br>
+<br>
+        * <tt class="filename">pygtk2-tut.xml</tt> Bump release number to 2.0.<br>
+<br>
+<span class="bold"><b>2004-03-31  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * <tt class="filename">MiscellaneousWidgets.xml</tt> Fix bug in calendar.py example causing<br>
+        date string to be off by one day in some time zones. Fixes #138487.<br>
+        (<span class="emphasis"><em>thanks to Eduard Luhtonen</em></span>)<br>
+<br>
+<span class="bold"><b>2004-01-28  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * <tt class="filename">DrawingArea.xml</tt> Modify description of DrawingArea to clarify that<br>
+        drawing is done on the wrapped gtk.gdk.Window. Modify GC description<br>
+        to clarify that new GCs created from drawables. (thanks to Antoon<br>
+        Pardon)<br>
+<br>
+        * <tt class="filename">UndocumentedWidgets.xml</tt> Remove the section on Plugs and Sockets -<br>
+        now in ContainerWidgets.xml.<br>
+        <br>
+        * <tt class="filename">ContainerWidgets.xml</tt> Add section on Plugs and Sockets written<br>
+        by Nathan Hurst.<br>
+<br>
+        * <tt class="filename">pygtk2-tut.xml</tt> Change date and version number.<br>
+<br>
+<span class="bold"><b>2003-11-05  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * <tt class="filename">Introduction.xml</tt> Add reference to the PyGTK 2.0 Reference Manual.<br>
+<br>
+<span class="bold"><b>2003-11-04  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * ContainerWidgets.xml<br>
+        * RangeWidgets.xml<br>
+        * <tt class="filename">WidgetOverview.xml</tt> Remove reference to testgtk.py since it doesn't<br>
+        exist in PyGTK 2.0 (<span class="emphasis"><em>thanks to Steve Chaplin</em></span>)<br>
+<br>
+<span class="bold"><b>2003-10-07  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * <tt class="filename">TextViewWidget.xml</tt> Change PANGO_ to pango. (<span class="emphasis"><em>thanks to Stephane Klein</em></span>)<br>
+        * <tt class="filename">pygtk2-tut.xml</tt> Change date and version number.<br>
+<br>
+<span class="bold"><b>2003-10-06  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * <tt class="filename">GettingStarted.xml</tt> Change third to second in description of signal<br>
+        handler arguments. (<span class="emphasis"><em>thanks to Kyle Smith</em></span>)<br>
+<br>
+<span class="bold"><b>2003-09-26  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * <tt class="filename">ContainerWidgets.xml</tt> Fix text layout error in frame shadow<br>
+        description (<span class="emphasis"><em>thanks to Steve Chaplin</em></span>)<br>
+<br>
+<span class="bold"><b>2003-09-19  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * ContainerWidgets.xml<br>
+        * <tt class="filename">layout.py</tt> Use random module instead of whrandom in<br>
+        layout.py example program (<span class="emphasis"><em>thanks to Steve Chaplin</em></span>)<br>
+<br>
+        * PackingWidgets.xml<br>
+        * <tt class="filename">packbox.py</tt> Use set_size_request(<span class="emphasis"><em></em></span>) instead of set_usize(<span class="emphasis"><em></em></span>) in<br>
+        packbox.py example (<span class="emphasis"><em>thanks to Steve Chaplin</em></span>)<br>
+<br>
+<span class="bold"><b>2003-07-11  John Finlay  &lt;finlay@moeraki.com&gt;</b></span><br>
+<br>
+        * <tt class="filename">ContainerWidgets.xml</tt> Fix link references to class-gtkalignment to<br>
+        use a ulink instead of a link.<br>
+<br>
+        * <tt class="filename">ChangeLog</tt> Add this change log file<br>
+<br>
+        * <tt class="filename">pygtk2-tut.xml</tt> Change date and add a version number. Add ChangeLog<br>
+        as an appendix.<br>
+</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="app-CodeExamples.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="index.html">Up</a></td><td width="40%" align="right"> </td></tr><tr><td width="40%" align="left" valign="top">Appendix B. Code Examples </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> </td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-AdjustmentInternals.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-AdjustmentInternals.html
new file mode 100644
index 0000000..966a833
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-AdjustmentInternals.html
@@ -0,0 +1,56 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>7.3. Adjustment Internals</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-Adjustments.html" title="Chapter 7. Adjustments"><link rel="previous" href="sec-UsingAdjustmentsTheEasyWay.html" title="7.2. Using Adjustments the Easy Way"><link rel="next" href="ch-RangeWidgets.html" title="Chapter 8. Range Widgets"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">7.3. Adjustment Internals</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-UsingAdjustmentsTheEasyWay.html">Prev</a> </td><th width="60%" align="center">Chapter 7. Adjustments</th><td width="20%" align="right"> <a accesskey="n" href="ch-RangeWidgets.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-AdjustmentInternals"></a>7.3. Adjustment Internals</h2></div></div><div></div></div><p>Ok, you say, that's nice, but what if I want to create my own
+handlers to respond when the user adjusts a range widget or a spin button,
+and how do I get at the value of the adjustment in these handlers? To answer
+these questions and more, let's start by taking a look at the attributes of
+a <tt class="classname">gtk.Adjustment</tt> itself:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ lower
+ upper
+ value
+ step_increment
+ page_increment
+ page_size
+</pre></td></tr></table><p>Given a <tt class="classname">gtk.Adjustment</tt> instance
+<i class="parameter"><tt>adj</tt></i>, each of the attributes are retrieved or set by
+<i class="parameter"><tt>adj.lower</tt></i>, <i class="parameter"><tt>adj.value</tt></i>,
+etc.</p><p>Since, when you set the value of an adjustment, you generally
+want the change to be reflected by every widget that uses this adjustment,
+PyGTK provides a method to do this:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ adjustment.set_value(<b class="parameter"><tt>value</tt></b>)
+</pre></td></tr></table><p>As mentioned earlier, <tt class="classname">Adjustment</tt> is a
+subclass of <tt class="classname">Object</tt> just like all the various widgets,
+and thus it is able to emit signals. This is, of course, why updates happen
+automagically when you share an adjustment object between a scrollbar and
+another adjustable widget; all adjustable widgets connect signal handlers to
+their adjustment's value_changed signal, as can your program. Here's the
+definition of this signal callback:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def value_changed(adjustment):
+</pre></td></tr></table><p>The various widgets that use the
+<tt class="classname">Adjustment</tt> object will emit this signal on an
+adjustment whenever they change its value. This happens both when user input
+causes the slider to move on a range widget, as well as when the program
+explicitly changes the value with the <tt class="methodname">set_value</tt>()
+method. So, for example, if you have a scale widget, and you want to change
+the rotation of a picture whenever its value changes, you would create a
+callback like this:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def cb_rotate_picture(adj, picture):
+ set_picture_rotation (picture, adj.value)
+ ...
+</pre></td></tr></table><p>and connect it to the scale widget's adjustment like
+this:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ adj.connect("value_changed", cb_rotate_picture, picture)
+</pre></td></tr></table><p>What about when a widget reconfigures the
+<i class="parameter"><tt>upper</tt></i> or <i class="parameter"><tt>lower</tt></i> fields of its
+adjustment, such as when a user adds more text to a text widget? In this
+case, it emits the changed signal, which looks like this:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def changed(adjustment):
+</pre></td></tr></table><p><tt class="classname">Range</tt> widgets typically connect a handler
+to this signal, which changes their appearance to reflect the change - for
+example, the size of the slider in a scrollbar will grow or shrink in
+inverse proportion to the difference between the lower and upper values of
+its adjustment.</p><p>You probably won't ever need to attach a handler to this signal,
+unless you're writing a new type of range widget. However, if you change any
+of the values in a <tt class="classname">Adjustment</tt> directly, you should
+emit this signal on it to reconfigure whatever widgets are using it, like
+this:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ adjustment.emit("changed")
+</pre></td></tr></table></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-UsingAdjustmentsTheEasyWay.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-Adjustments.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch-RangeWidgets.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">7.2. Using Adjustments the Easy Way </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 8. Range Widgets</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-Alignment.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-Alignment.html
new file mode 100644
index 0000000..294b079
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-Alignment.html
@@ -0,0 +1,32 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>10.2. The Alignment widget</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-ContainerWidgets.html" title="Chapter 10. Container Widgets"><link rel="previous" href="ch-ContainerWidgets.html" title="Chapter 10. Container Widgets"><link rel="next" href="sec-Fixed.html" title="10.3. Fixed Container"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">10.2. The Alignment widget</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch-ContainerWidgets.html">Prev</a> </td><th width="60%" align="center">Chapter 10. Container Widgets</th><td width="20%" align="right"> <a accesskey="n" href="sec-Fixed.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-Alignment"></a>10.2. The Alignment widget</h2></div></div><div></div></div><p>The <tt class="classname">Alignment</tt> widget allows you to place
+a widget within its window at a position and size relative to the size of
+the <tt class="classname">Alignment</tt> widget itself. For example, it can be
+very useful for centering a widget within the window.</p><p>There are only two calls associated with the
+<tt class="classname">Alignment</tt> widget:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ alignment = gtk.Alignment(<b class="parameter"><tt>xalign</tt></b>=0.0, <b class="parameter"><tt>yalign</tt></b>=0.0, <b class="parameter"><tt>xscale</tt></b>=0.0, <b class="parameter"><tt>yscale</tt></b>=0.0)
+
+ alignment.set(<b class="parameter"><tt>xalign</tt></b>, <b class="parameter"><tt>yalign</tt></b>, <b class="parameter"><tt>xscale</tt></b>, <b class="parameter"><tt>yscale</tt></b>)
+</pre></td></tr></table><p>The <tt class="function">gtk.Alignment</tt>() function creates a new
+<tt class="classname">Alignment</tt> widget with the specified parameters. The
+<tt class="methodname">set</tt>() method allows the alignment parameters of an
+existing <tt class="classname">Alignment</tt> widget to be altered.</p><p>All four alignment parameters are floating point numbers which
+can range from 0.0 to 1.0. The <i class="parameter"><tt>xalign</tt></i> and
+<i class="parameter"><tt>yalign</tt></i> arguments affect the position of the widget
+placed within the <a href="http://www.pygtk.org/pygtk2reference/class-gtkalignment.html" target="_top"><tt class="classname">gtk.Alignment</tt></a>
+widget. The align properties specify the fraction of
+<span class="emphasis"><em>free</em></span> space that will be placed above or to the left of
+the child widget. The values range from 0.0 (no <span class="emphasis"><em>free</em></span>
+space above or to the left of the child) to 1.0 (all
+<span class="emphasis"><em>free</em></span> space above or to the left of the child). Of
+course, if the scale properties are both set to 1.0, the alignment
+properties have no effect since the child widget will expand to fill the
+available space.</p><p>The <i class="parameter"><tt>xscale</tt></i> and
+<i class="parameter"><tt>yscale</tt></i> arguments specify the fraction of
+<span class="emphasis"><em>free</em></span> space absorbed by the child widget. The values can
+range from 0.0 (meaning the child absorbs none) to 1.0 (meaning the child
+absorbs all of the <span class="emphasis"><em>free</em></span> space).</p><p>A child widget can be added to this
+<tt class="classname">Alignment</tt> widget using:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ alignment.add(<b class="parameter"><tt>widget</tt></b>)
+</pre></td></tr></table><p>For an example of using an <tt class="classname">Alignment</tt>
+widget, refer to the <a href="examples/progressbar.py" target="_top"><span><b class="command">progressbar.py</b></span></a>
+example for the Progress Bar widget.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch-ContainerWidgets.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-ContainerWidgets.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-Fixed.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 10. Container Widgets </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 10.3. Fixed Container</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-Arrows.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-Arrows.html
new file mode 100644
index 0000000..82c5e06
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-Arrows.html
@@ -0,0 +1,88 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>9.2. Arrows</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-MiscellaneousWidgets.html" title="Chapter 9. Miscellaneous Widgets"><link rel="previous" href="ch-MiscellaneousWidgets.html" title="Chapter 9. Miscellaneous Widgets"><link rel="next" href="sec-TooltipsObject.html" title="9.3. The Tooltips Object"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">9.2. Arrows</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch-MiscellaneousWidgets.html">Prev</a> </td><th width="60%" align="center">Chapter 9. Miscellaneous Widgets</th><td width="20%" align="right"> <a accesskey="n" href="sec-TooltipsObject.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-Arrows"></a>9.2. Arrows</h2></div></div><div></div></div><p>The <tt class="classname">Arrow</tt> widget draws an arrowhead,
+facing in a number of possible directions and having a number of possible
+styles. It can be very useful when placed on a button in many applications.
+Like the <tt class="classname">Label</tt> widget, it emits no signals.</p><p>There are only two calls for manipulating an
+<tt class="classname">Arrow</tt> widget:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ arrow = gtk.Arrow(<b class="parameter"><tt>arrow_type</tt></b>, <b class="parameter"><tt>shadow_type</tt></b>)
+
+ arrow.set(<b class="parameter"><tt>arrow_type</tt></b>, <b class="parameter"><tt>shadow_type</tt></b>)
+</pre></td></tr></table><p>The first creates a new arrow widget with the indicated type and
+appearance. The second allows these values to be altered retrospectively.
+The <i class="parameter"><tt>arrow_type</tt></i> argument may take one of the following
+values:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ ARROW_UP
+ ARROW_DOWN
+ ARROW_LEFT
+ ARROW_RIGHT
+</pre></td></tr></table><p>These values obviously indicate the direction in which the arrow
+will point. The <i class="parameter"><tt>shadow_type</tt></i> argument may take one of
+these values:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ SHADOW_IN
+ SHADOW_OUT # the default
+ SHADOW_ETCHED_IN
+ SHADOW_ETCHED_OUT
+</pre></td></tr></table><p>The <a href="examples/arrow.py" target="_top"><span><b class="command">arrow.py</b></span></a> example program
+briefly illustrates their use.
+<a href="sec-Arrows.html#arrowsfig" title="Figure 9.2. Arrows Buttons Examples">Figure 9.2, “Arrows Buttons Examplesâ€</a> illustrates the result of running the
+program:</p><div class="figure"><a name="arrowsfig"></a><p class="title"><b>Figure 9.2. Arrows Buttons Examples</b></p><div class="mediaobject" align="center"><img src="figures/arrows.png" align="middle" alt="Arrows Buttons Examples"></div></div><p>The source code for <a href="examples/arrow.py" target="_top"><span><b class="command">arrow.py</b></span></a> is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 1 #!/usr/bin/env python
+ 2
+ 3 # example arrow.py
+ 4
+ 5 import pygtk
+ 6 pygtk.require('2.0')
+ 7 import gtk
+ 8
+ 9 # Create an Arrow widget with the specified parameters
+ 10 # and pack it into a button
+ 11 def create_arrow_button(arrow_type, shadow_type):
+ 12 button = gtk.Button();
+ 13 arrow = gtk.Arrow(arrow_type, shadow_type);
+ 14 button.add(arrow)
+ 15 button.show()
+ 16 arrow.show()
+ 17 return button
+ 18
+ 19 class Arrows:
+ 20 def __init__(self):
+ 21 # Create a new window
+ 22 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ 23
+ 24 window.set_title("Arrow Buttons")
+ 25
+ 26 # It's a good idea to do this for all windows.
+ 27 window.connect("destroy", lambda x: gtk.main_quit())
+ 28
+ 29 # Sets the border width of the window.
+ 30 window.set_border_width(10)
+ 31
+ 32 # Create a box to hold the arrows/buttons
+ 33 box = gtk.HBox(False, 0)
+ 34 box.set_border_width(2)
+ 35 window.add(box)
+ 36
+ 37 # Pack and show all our widgets
+ 38 box.show()
+ 39
+ 40 button = create_arrow_button(gtk.ARROW_UP, gtk.SHADOW_IN)
+ 41 box.pack_start(button, False, False, 3)
+ 42
+ 43 button = create_arrow_button(gtk.ARROW_DOWN, gtk.SHADOW_OUT)
+ 44 box.pack_start(button, False, False, 3)
+ 45
+ 46 button = create_arrow_button(gtk.ARROW_LEFT, gtk.SHADOW_ETCHED_IN)
+ 47 box.pack_start(button, False, False, 3)
+ 48
+ 49 button = create_arrow_button(gtk.ARROW_RIGHT, gtk.SHADOW_ETCHED_OUT)
+ 50 box.pack_start(button, False, False, 3)
+ 51
+ 52 window.show()
+ 53
+ 54 def main():
+ 55 gtk.main()
+ 56 return 0
+ 57
+ 58 if __name__ == "__main__":
+ 59 Arrows()
+ 60 main()
+</pre></td></tr></table></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch-MiscellaneousWidgets.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-MiscellaneousWidgets.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-TooltipsObject.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 9. Miscellaneous Widgets </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 9.3. The Tooltips Object</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-AspectFrames.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-AspectFrames.html
new file mode 100644
index 0000000..c3b04b8
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-AspectFrames.html
@@ -0,0 +1,65 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>10.6. Aspect Frames</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-ContainerWidgets.html" title="Chapter 10. Container Widgets"><link rel="previous" href="sec-Frames.html" title="10.5. Frames"><link rel="next" href="sec-PanedWindowWidgets.html" title="10.7. Paned Window Widgets"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">10.6. Aspect Frames</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-Frames.html">Prev</a> </td><th width="60%" align="center">Chapter 10. Container Widgets</th><td width="20%" align="right"> <a accesskey="n" href="sec-PanedWindowWidgets.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-AspectFrames"></a>10.6. Aspect Frames</h2></div></div><div></div></div><p>The aspect frame widget is like a frame widget, except that it
+also enforces the aspect ratio (that is, the ratio of the width to the
+height) of the child widget to have a certain value, adding extra space if
+necessary. This is useful, for instance, if you want to preview a larger
+image. The size of the preview should vary when the user resizes the window,
+but the aspect ratio needs to always match the original image.</p><p>To create a new aspect frame use:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ aspect_frame = gtk.AspectFrame(<b class="parameter"><tt>label</tt></b>=None, <b class="parameter"><tt>xalign</tt></b>=0.5, <b class="parameter"><tt>yalign</tt></b>=0.5, <b class="parameter"><tt>ratio</tt></b>=1.0, <b class="parameter"><tt>obey_child</tt></b>=TRUE)
+</pre></td></tr></table><p><i class="parameter"><tt>label</tt></i> specifies the text to be displayed
+as the label. <i class="parameter"><tt>xalign</tt></i> and
+<i class="parameter"><tt>yalign</tt></i> specify alignment as with <a href="http://www.pygtk.org/pygtk2reference/class-gtkalignment.html" target="_top"><tt class="classname">gtk.Alignment</tt></a>
+widgets. If <i class="parameter"><tt>obey_child</tt></i> is <tt class="literal">TRUE</tt>,
+the aspect ratio of a child widget will match the aspect ratio of the ideal
+size it requests. Otherwise, it is given by
+<i class="parameter"><tt>ratio</tt></i>.</p><p>To change the options of an existing aspect frame, you can
+use:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ aspect_frame.set(<b class="parameter"><tt>xalign</tt></b>=0.0, <b class="parameter"><tt>yalign</tt></b>=0.0, <b class="parameter"><tt>ratio</tt></b>=1.0, <b class="parameter"><tt>obey_child</tt></b>=TRUE)
+</pre></td></tr></table><p>As an example, the <a href="examples/aspectframe.py" target="_top"><span><b class="command">aspectframe.py</b></span></a>
+program uses an <tt class="classname">AspectFrame</tt> to present a drawing area
+whose aspect ratio will always be 2:1, no matter how the user resizes the
+top-level window.
+<a href="sec-AspectFrames.html#aspectframefig" title="Figure 10.5. Aspect Frame Example">Figure 10.5, “Aspect Frame Exampleâ€</a> illustrates the display of the
+program:</p><div class="figure"><a name="aspectframefig"></a><p class="title"><b>Figure 10.5. Aspect Frame Example</b></p><div class="mediaobject" align="center"><img src="figures/aspectframe.png" align="middle" alt="Aspect Frame Example"></div></div><p>The source code for <a href="examples/aspectframe.py" target="_top"><span><b class="command">aspectframe.py</b></span></a>
+is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 1 #!/usr/bin/env python
+ 2
+ 3 # example aspectframe.py
+ 4
+ 5 import pygtk
+ 6 pygtk.require('2.0')
+ 7 import gtk
+ 8
+ 9 class AspectFrameExample:
+ 10 def __init__(self):
+ 11 window = gtk.Window(gtk.WINDOW_TOPLEVEL);
+ 12 window.set_title("Aspect Frame")
+ 13 window.connect("destroy", lambda x: gtk.main_quit())
+ 14 window.set_border_width(10)
+ 15
+ 16 # Create an aspect_frame and add it to our toplevel window
+ 17 aspect_frame = gtk.AspectFrame("2x1", # label
+ 18 0.5, # center x
+ 19 0.5, # center y
+ 20 2, # xsize/ysize = 2
+ 21 False) # ignore child's aspect
+ 22 window.add(aspect_frame)
+ 23 aspect_frame.show()
+ 24
+ 25 # Now add a child widget to the aspect frame
+ 26 drawing_area = gtk.DrawingArea()
+ 27
+ 28 # Ask for a 200x200 window, but the AspectFrame will give us a 200x100
+ 29 # window since we are forcing a 2x1 aspect ratio
+ 30 drawing_area.set_size_request(200, 200)
+ 31 aspect_frame.add(drawing_area)
+ 32 drawing_area.show()
+ 33 window.show()
+ 34
+ 35 def main():
+ 36 gtk.main()
+ 37 return 0
+ 38
+ 39 if __name__ == "__main__":
+ 40 AspectFrameExample()
+ 41 main()
+</pre></td></tr></table></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-Frames.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-ContainerWidgets.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-PanedWindowWidgets.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">10.5. Frames </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 10.7. Paned Window Widgets</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-ButtonBoxes.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-ButtonBoxes.html
new file mode 100644
index 0000000..d36e761
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-ButtonBoxes.html
@@ -0,0 +1,133 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>10.10. Button Boxes</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-ContainerWidgets.html" title="Chapter 10. Container Widgets"><link rel="previous" href="sec-ScrolledWindows.html" title="10.9. Scrolled Windows"><link rel="next" href="sec-Toolbar.html" title="10.11. Toolbar"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">10.10. Button Boxes</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-ScrolledWindows.html">Prev</a> </td><th width="60%" align="center">Chapter 10. Container Widgets</th><td width="20%" align="right"> <a accesskey="n" href="sec-Toolbar.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-ButtonBoxes"></a>10.10. Button Boxes</h2></div></div><div></div></div><p><tt class="classname">ButtonBoxes</tt> are a convenient way to
+quickly layout a group of buttons. They come in both horizontal and vertical
+flavors. You create a new <tt class="classname">ButtonBox</tt> with one of the
+following calls, which create a horizontal or vertical box,
+respectively:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ hbutton_box = gtk.HButtonBox()
+
+ vbutton_box = gtk.VButtonBox()
+</pre></td></tr></table><p>The only methods pertaining to button boxes effect how the
+buttons are laid out.</p><p>The layout of the buttons within the box is set using:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ button_box.set_layout(<b class="parameter"><tt>layout_style</tt></b>)
+</pre></td></tr></table><p>The <i class="parameter"><tt>layout_style</tt></i> argument can take one of
+the following values:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ BUTTONBOX_DEFAULT_STYLE
+ BUTTONBOX_SPREAD
+ BUTTONBOX_EDGE
+ BUTTONBOX_START
+ BUTTONBOX_END
+</pre></td></tr></table><p>The current <i class="parameter"><tt>layout_style</tt></i> setting can be
+retrieved using:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ layout_style = button_box.get_layout()
+</pre></td></tr></table><p>Buttons are added to a <tt class="classname">ButtonBox</tt> using
+the usual <tt class="classname">Container</tt> method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ button_box.add(<b class="parameter"><tt>widget</tt></b>)
+</pre></td></tr></table><p>The <a href="examples/buttonbox.py" target="_top"><span><b class="command">buttonbox.py</b></span></a> example
+program illustrates all the different layout settings for
+<tt class="classname">ButtonBoxes</tt>.
+The resulting display is:</p><div class="informalfigure"><a name="buttonboxfig"></a><div class="mediaobject" align="center"><img src="figures/buttonbox.png" align="middle"></div></div><p>The source code for the <a href="examples/buttonbox.py" target="_top"><span><b class="command">buttonbox.py</b></span></a> program
+is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 1 #!/usr/bin/env python
+ 2
+ 3 # example buttonbox.py
+ 4
+ 5 import pygtk
+ 6 pygtk.require('2.0')
+ 7 import gtk
+ 8
+ 9 class ButtonBoxExample:
+ 10 # Create a Button Box with the specified parameters
+ 11 def create_bbox(self, horizontal, title, spacing, layout):
+ 12 frame = gtk.Frame(title)
+ 13
+ 14 if horizontal:
+ 15 bbox = gtk.HButtonBox()
+ 16 else:
+ 17 bbox = gtk.VButtonBox()
+ 18
+ 19 bbox.set_border_width(5)
+ 20 frame.add(bbox)
+ 21
+ 22 # Set the appearance of the Button Box
+ 23 bbox.set_layout(layout)
+ 24 bbox.set_spacing(spacing)
+ 25
+ 26 button = gtk.Button(stock=gtk.STOCK_OK)
+ 27 bbox.add(button)
+ 28
+ 29 button = gtk.Button(stock=gtk.STOCK_CANCEL)
+ 30 bbox.add(button)
+ 31
+ 32 button = gtk.Button(stock=gtk.STOCK_HELP)
+ 33 bbox.add(button)
+ 34
+ 35 return frame
+ 36
+ 37 def __init__(self):
+ 38 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ 39 window.set_title("Button Boxes")
+ 40
+ 41 window.connect("destroy", lambda x: gtk.main_quit())
+ 42
+ 43 window.set_border_width(10)
+ 44
+ 45 main_vbox = gtk.VBox(False, 0)
+ 46 window.add(main_vbox)
+ 47
+ 48 frame_horz = gtk.Frame("Horizontal Button Boxes")
+ 49 main_vbox.pack_start(frame_horz, True, True, 10)
+ 50
+ 51 vbox = gtk.VBox(False, 0)
+ 52 vbox.set_border_width(10)
+ 53 frame_horz.add(vbox)
+ 54
+ 55 vbox.pack_start(self.create_bbox(True, "Spread (spacing 40)",
+ 56 40, gtk.BUTTONBOX_SPREAD),
+ 57 True, True, 0)
+ 58
+ 59 vbox.pack_start(self.create_bbox(True, "Edge (spacing 30)",
+ 60 30, gtk.BUTTONBOX_EDGE),
+ 61 True, True, 5)
+ 62
+ 63 vbox.pack_start(self.create_bbox(True, "Start (spacing 20)",
+ 64 20, gtk.BUTTONBOX_START),
+ 65 True, True, 5)
+ 66
+ 67 vbox.pack_start(self.create_bbox(True, "End (spacing 10)",
+ 68 10, gtk.BUTTONBOX_END),
+ 69 True, True, 5)
+ 70
+ 71 frame_vert = gtk.Frame("Vertical Button Boxes")
+ 72 main_vbox.pack_start(frame_vert, True, True, 10)
+ 73
+ 74 hbox = gtk.HBox(False, 0)
+ 75 hbox.set_border_width(10)
+ 76 frame_vert.add(hbox)
+ 77
+ 78 hbox.pack_start(self.create_bbox(False, "Spread (spacing 5)",
+ 79 5, gtk.BUTTONBOX_SPREAD),
+ 80 True, True, 0)
+ 81
+ 82 hbox.pack_start(self.create_bbox(False, "Edge (spacing 30)",
+ 83 30, gtk.BUTTONBOX_EDGE),
+ 84 True, True, 5)
+ 85
+ 86 hbox.pack_start(self.create_bbox(False, "Start (spacing 20)",
+ 87 20, gtk.BUTTONBOX_START),
+ 88 True, True, 5)
+ 89
+ 90 hbox.pack_start(self.create_bbox(False, "End (spacing 20)",
+ 91 20, gtk.BUTTONBOX_END),
+ 92 True, True, 5)
+ 93
+ 94 window.show_all()
+ 95
+ 96 def main():
+ 97 # Enter the event loop
+ 98 gtk.main()
+ 99 return 0
+ 100
+ 101 if __name__ == "__main__":
+ 102 ButtonBoxExample()
+ 103 main()
+</pre></td></tr></table></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-ScrolledWindows.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-ContainerWidgets.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-Toolbar.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">10.9. Scrolled Windows </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 10.11. Toolbar</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-Calendar.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-Calendar.html
new file mode 100644
index 0000000..eb24894
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-Calendar.html
@@ -0,0 +1,332 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>9.12. Calendar</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-MiscellaneousWidgets.html" title="Chapter 9. Miscellaneous Widgets"><link rel="previous" href="sec-ComboWidget.html" title="9.11. Combo Widget"><link rel="next" href="sec-ColorSelection.html" title="9.13. Color Selection"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">9.12. Calendar</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-ComboWidget.html">Prev</a> </td><th width="60%" align="center">Chapter 9. Miscellaneous Widgets</th><td width="20%" align="right"> <a accesskey="n" href="sec-ColorSelection.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-Calendar"></a>9.12. Calendar</h2></div></div><div></div></div><p>The <tt class="classname">Calendar</tt> widget is an effective way
+to display and retrieve monthly date related information. It is a very
+simple widget to create and work with.</p><p>Creating a <tt class="classname">gtk.Calendar</tt> widget is as
+simple as:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ calendar = gtk.Calendar()
+</pre></td></tr></table><p>The calendar will display the current month and year by
+default.</p><p>There might be times where you need to change a lot of
+information within this widget and the following methods allow you to make
+multiple changes to a <tt class="classname">Calendar</tt> widget without the
+user seeing multiple on-screen updates.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ calendar.freeze()
+
+ calendar.thaw()
+</pre></td></tr></table><p>They work just like the freeze/thaw methods of every other
+widget.</p><p>The <tt class="classname">Calendar</tt> widget has a few options
+that allow you to change the way the widget both looks and operates by using
+the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ calendar.display_options(<b class="parameter"><tt>flags</tt></b>)
+</pre></td></tr></table><p>The <i class="parameter"><tt>flags</tt></i> argument can be formed by
+combining either of the following five options using the logical bitwise OR
+(|) operation:</p><div class="informaltable"><table width="100%" border="1"><colgroup><col><col></colgroup><tbody><tr><td>CALENDAR_SHOW_HEADING</td><td>this option specifies that the month and year should be
+shown when drawing the calendar.</td></tr><tr><td>CALENDAR_SHOW_DAY_NAMES</td><td>this option specifies that the three letter descriptions
+should be displayed for each day (e.g. Mon,Tue, etc.).</td></tr><tr><td>CALENDAR_NO_MONTH_CHANGE</td><td>this option states that the user should not and can not
+change the currently displayed month. This can be good if you only need to
+display a particular month such as if you are displaying 12 calendar widgets
+for every month in a particular year.</td></tr><tr><td>CALENDAR_SHOW_WEEK_NUMBERS</td><td>this option specifies that the number for each week should
+be displayed down the left side of the calendar. (e.g. Jan 1 = Week 1,Dec 31
+= Week 52).</td></tr><tr><td>CALENDAR_WEEK_START_MONDAY</td><td>this option states that the calender week will start on
+Monday instead of Sunday which is the default. This only affects the order
+in which days are displayed from left to right. Note that in PyGTK 2.4 and
+above this option is deprecated.</td></tr></tbody></table></div><p>The following methods are used to set the the currently
+displayed date:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ result = calendar.select_month(<b class="parameter"><tt>month</tt></b>, <b class="parameter"><tt>year</tt></b>)
+
+ calendar.select_day(<b class="parameter"><tt>day</tt></b>)
+</pre></td></tr></table><p>The return value from the
+<tt class="methodname">select_month</tt>() method is a boolean value indicating
+whether the selection was successful.</p><p>With the <tt class="methodname">select_day</tt>() method the
+specified day number is selected within the current month, if that is
+possible. A day value of 0 will deselect any current selection.</p><p>In addition to having a day selected, any number of days in the
+month may be "marked". A marked day is highlighted within the calendar
+display. The following methods are provided to manipulate marked
+days:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ result = calendar.mark_day(<b class="parameter"><tt>day</tt></b>)
+
+ result = calendar.unmark_day(<b class="parameter"><tt>day</tt></b>)
+
+ calendar.clear_marks()
+</pre></td></tr></table><p><tt class="methodname">mark_day</tt>() and
+<tt class="methodname">unmark_day</tt>() return a boolean indicating whether
+the method was successful. Note that marks are persistent across month and
+year changes.</p><p>The final <tt class="classname">Calendar</tt> widget method is used
+to retrieve the currently selected date, month and/or year.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ year, month, day = calendar.get_date()
+</pre></td></tr></table><p>The <tt class="classname">Calendar</tt> widget can generate a number
+of signals indicating date selection and change. The names of these signals
+are self explanatory, and are:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ month_changed
+
+ day_selected
+
+ day_selected_double_click
+
+ prev_month
+
+ next_month
+
+ prev_year
+
+ next_year
+</pre></td></tr></table><p>That just leaves us with the need to put all of this together
+into the <a href="examples/calendar.py" target="_top"><span><b class="command">calendar.py</b></span></a> example
+program. <a href="sec-Calendar.html#calendarfig" title="Figure 9.12. Calendar Example">Figure 9.12, “Calendar Exampleâ€</a> illustrates the program
+operation:</p><div class="figure"><a name="calendarfig"></a><p class="title"><b>Figure 9.12. Calendar Example</b></p><div class="mediaobject" align="center"><img src="figures/calendar.png" align="middle" alt="Calendar Example"></div></div><p>The <a href="examples/calendar.py" target="_top"><span><b class="command">calendar.py</b></span></a> source
+code is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 1 #!/usr/bin/env python
+ 2
+ 3 # example calendar.py
+ 4 #
+ 5 # Copyright (C) 1998 Cesar Miquel, Shawn T. Amundson, Mattias Gronlund
+ 6 # Copyright (C) 2000 Tony Gale
+ 7 # Copyright (C) 2001-2004 John Finlay
+ 8 #
+ 9 # This program is free software; you can redistribute it and/or modify
+ 10 # it under the terms of the GNU General Public License as published by
+ 11 # the Free Software Foundation; either version 2 of the License, or
+ 12 # (at your option) any later version.
+ 13 #
+ 14 # This program is distributed in the hope that it will be useful,
+ 15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
+ 16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ 17 # GNU General Public License for more details.
+ 18 #
+ 19 # You should have received a copy of the GNU General Public License
+ 20 # along with this program; if not, write to the Free Software
+ 21 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ 22
+ 23 import pygtk
+ 24 pygtk.require('2.0')
+ 25 import gtk, pango
+ 26 import time
+ 27
+ 28 class CalendarExample:
+ 29 DEF_PAD = 10
+ 30 DEF_PAD_SMALL = 5
+ 31 TM_YEAR_BASE = 1900
+ 32
+ 33 calendar_show_header = 0
+ 34 calendar_show_days = 1
+ 35 calendar_month_change = 2
+ 36 calendar_show_week = 3
+ 37
+ 38 def calendar_date_to_string(self):
+ 39 year, month, day = self.window.get_date()
+ 40 mytime = time.mktime((year, month+1, day, 0, 0, 0, 0, 0, -1))
+ 41 return time.strftime("%x", time.localtime(mytime))
+ 42
+ 43 def calendar_set_signal_strings(self, sig_str):
+ 44 prev_sig = self.prev_sig.get()
+ 45 self.prev2_sig.set_text(prev_sig)
+ 46
+ 47 prev_sig = self.last_sig.get()
+ 48 self.prev_sig.set_text(prev_sig)
+ 49 self.last_sig.set_text(sig_str)
+ 50
+ 51 def calendar_month_changed(self, widget):
+ 52 buffer = "month_changed: %s" % self.calendar_date_to_string()
+ 53 self.calendar_set_signal_strings(buffer)
+ 54
+ 55 def calendar_day_selected(self, widget):
+ 56 buffer = "day_selected: %s" % self.calendar_date_to_string()
+ 57 self.calendar_set_signal_strings(buffer)
+ 58
+ 59 def calendar_day_selected_double_click(self, widget):
+ 60 buffer = "day_selected_double_click: %s"
+ 61 buffer = buffer % self.calendar_date_to_string()
+ 62 self.calendar_set_signal_strings(buffer)
+ 63
+ 64 year, month, day = self.window.get_date()
+ 65
+ 66 if self.marked_date[day-1] == 0:
+ 67 self.window.mark_day(day)
+ 68 self.marked_date[day-1] = 1
+ 69 else:
+ 70 self.window.unmark_day(day)
+ 71 self.marked_date[day-1] = 0
+ 72
+ 73 def calendar_prev_month(self, widget):
+ 74 buffer = "prev_month: %s" % self.calendar_date_to_string()
+ 75 self.calendar_set_signal_strings(buffer)
+ 76
+ 77 def calendar_next_month(self, widget):
+ 78 buffer = "next_month: %s" % self.calendar_date_to_string()
+ 79 self.calendar_set_signal_strings(buffer)
+ 80
+ 81 def calendar_prev_year(self, widget):
+ 82 buffer = "prev_year: %s" % self.calendar_date_to_string()
+ 83 self.calendar_set_signal_strings(buffer)
+ 84
+ 85 def calendar_next_year(self, widget):
+ 86 buffer = "next_year: %s" % self.calendar_date_to_string()
+ 87 self.calendar_set_signal_strings(buffer)
+ 88
+ 89 def calendar_set_flags(self):
+ 90 options = 0
+ 91 for i in range(5):
+ 92 if self.settings[i]:
+ 93 options = options + (1&lt;&lt;i)
+ 94 if self.window:
+ 95 self.window.display_options(options)
+ 96
+ 97 def calendar_toggle_flag(self, toggle):
+ 98 j = 0
+ 99 for i in range(5):
+ 100 if self.flag_checkboxes[i] == toggle:
+ 101 j = i
+ 102
+ 103 self.settings[j] = not self.settings[j]
+ 104 self.calendar_set_flags()
+ 105
+ 106 def calendar_font_selection_ok(self, button):
+ 107 self.font = self.font_dialog.get_font_name()
+ 108 if self.window:
+ 109 font_desc = pango.FontDescription(self.font)
+ 110 if font_desc:
+ 111 self.window.modify_font(font_desc)
+ 112
+ 113 def calendar_select_font(self, button):
+ 114 if not self.font_dialog:
+ 115 window = gtk.FontSelectionDialog("Font Selection Dialog")
+ 116 self.font_dialog = window
+ 117
+ 118 window.set_position(gtk.WIN_POS_MOUSE)
+ 119
+ 120 window.connect("destroy", self.font_dialog_destroyed)
+ 121
+ 122 window.ok_button.connect("clicked",
+ 123 self.calendar_font_selection_ok)
+ 124 window.cancel_button.connect_object("clicked",
+ 125 lambda wid: wid.destroy(),
+ 126 self.font_dialog)
+ 127 window = self.font_dialog
+ 128 if not (window.flags() &amp; gtk.VISIBLE):
+ 129 window.show()
+ 130 else:
+ 131 window.destroy()
+ 132 self.font_dialog = None
+ 133
+ 134 def font_dialog_destroyed(self, data=None):
+ 135 self.font_dialog = None
+ 136
+ 137 def __init__(self):
+ 138 flags = [
+ 139 "Show Heading",
+ 140 "Show Day Names",
+ 141 "No Month Change",
+ 142 "Show Week Numbers",
+ 143 ]
+ 144 self.window = None
+ 145 self.font = None
+ 146 self.font_dialog = None
+ 147 self.flag_checkboxes = 5*[None]
+ 148 self.settings = 5*[0]
+ 149 self.marked_date = 31*[0]
+ 150
+ 151 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ 152 window.set_title("Calendar Example")
+ 153 window.set_border_width(5)
+ 154 window.connect("destroy", lambda x: gtk.main_quit())
+ 155
+ 156 window.set_resizable(False)
+ 157
+ 158 vbox = gtk.VBox(False, self.DEF_PAD)
+ 159 window.add(vbox)
+ 160
+ 161 # The top part of the window, Calendar, flags and fontsel.
+ 162 hbox = gtk.HBox(False, self.DEF_PAD)
+ 163 vbox.pack_start(hbox, True, True, self.DEF_PAD)
+ 164 hbbox = gtk.HButtonBox()
+ 165 hbox.pack_start(hbbox, False, False, self.DEF_PAD)
+ 166 hbbox.set_layout(gtk.BUTTONBOX_SPREAD)
+ 167 hbbox.set_spacing(5)
+ 168
+ 169 # Calendar widget
+ 170 frame = gtk.Frame("Calendar")
+ 171 hbbox.pack_start(frame, False, True, self.DEF_PAD)
+ 172 calendar = gtk.Calendar()
+ 173 self.window = calendar
+ 174 self.calendar_set_flags()
+ 175 calendar.mark_day(19)
+ 176 self.marked_date[19-1] = 1
+ 177 frame.add(calendar)
+ 178 calendar.connect("month_changed", self.calendar_month_changed)
+ 179 calendar.connect("day_selected", self.calendar_day_selected)
+ 180 calendar.connect("day_selected_double_click",
+ 181 self.calendar_day_selected_double_click)
+ 182 calendar.connect("prev_month", self.calendar_prev_month)
+ 183 calendar.connect("next_month", self.calendar_next_month)
+ 184 calendar.connect("prev_year", self.calendar_prev_year)
+ 185 calendar.connect("next_year", self.calendar_next_year)
+ 186
+ 187 separator = gtk.VSeparator()
+ 188 hbox.pack_start(separator, False, True, 0)
+ 189
+ 190 vbox2 = gtk.VBox(False, self.DEF_PAD)
+ 191 hbox.pack_start(vbox2, False, False, self.DEF_PAD)
+ 192
+ 193 # Build the Right frame with the flags in
+ 194 frame = gtk.Frame("Flags")
+ 195 vbox2.pack_start(frame, True, True, self.DEF_PAD)
+ 196 vbox3 = gtk.VBox(True, self.DEF_PAD_SMALL)
+ 197 frame.add(vbox3)
+ 198
+ 199 for i in range(len(flags)):
+ 200 toggle = gtk.CheckButton(flags[i])
+ 201 toggle.connect("toggled", self.calendar_toggle_flag)
+ 202 vbox3.pack_start(toggle, True, True, 0)
+ 203 self.flag_checkboxes[i] = toggle
+ 204
+ 205 # Build the right font-button
+ 206 button = gtk.Button("Font...")
+ 207 button.connect("clicked", self.calendar_select_font)
+ 208 vbox2.pack_start(button, False, False, 0)
+ 209
+ 210 # Build the Signal-event part.
+ 211 frame = gtk.Frame("Signal events")
+ 212 vbox.pack_start(frame, True, True, self.DEF_PAD)
+ 213
+ 214 vbox2 = gtk.VBox(True, self.DEF_PAD_SMALL)
+ 215 frame.add(vbox2)
+ 216
+ 217 hbox = gtk.HBox (False, 3)
+ 218 vbox2.pack_start(hbox, False, True, 0)
+ 219 label = gtk.Label("Signal:")
+ 220 hbox.pack_start(label, False, True, 0)
+ 221 self.last_sig = gtk.Label("")
+ 222 hbox.pack_start(self.last_sig, False, True, 0)
+ 223
+ 224 hbox = gtk.HBox (False, 3)
+ 225 vbox2.pack_start(hbox, False, True, 0)
+ 226 label = gtk.Label("Previous signal:")
+ 227 hbox.pack_start(label, False, True, 0)
+ 228 self.prev_sig = gtk.Label("")
+ 229 hbox.pack_start(self.prev_sig, False, True, 0)
+ 230
+ 231 hbox = gtk.HBox (False, 3)
+ 232 vbox2.pack_start(hbox, False, True, 0)
+ 233 label = gtk.Label("Second previous signal:")
+ 234 hbox.pack_start(label, False, True, 0)
+ 235 self.prev2_sig = gtk.Label("")
+ 236 hbox.pack_start(self.prev2_sig, False, True, 0)
+ 237
+ 238 bbox = gtk.HButtonBox ()
+ 239 vbox.pack_start(bbox, False, False, 0)
+ 240 bbox.set_layout(gtk.BUTTONBOX_END)
+ 241
+ 242 button = gtk.Button("Close")
+ 243 button.connect("clicked", lambda w: gtk.main_quit())
+ 244 bbox.add(button)
+ 245 button.set_flags(gtk.CAN_DEFAULT)
+ 246 button.grab_default()
+ 247
+ 248 window.show_all()
+ 249
+ 250 def main():
+ 251 gtk.main()
+ 252 return 0
+ 253
+ 254 if __name__ == "__main__":
+ 255 CalendarExample()
+ 256 main()
+</pre></td></tr></table></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-ComboWidget.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-MiscellaneousWidgets.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-ColorSelection.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">9.11. Combo Widget </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 9.13. Color Selection</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-CellRenderers.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-CellRenderers.html
new file mode 100644
index 0000000..d596d2f
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-CellRenderers.html
@@ -0,0 +1,411 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>14.4. CellRenderers</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-TreeViewWidget.html" title="Chapter 14. Tree View Widget"><link rel="previous" href="sec-TreeViews.html" title="14.3. TreeViews"><link rel="next" href="sec-TreeViewColumns.html" title="14.5. TreeViewColumns"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">14.4. CellRenderers</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-TreeViews.html">Prev</a> </td><th width="60%" align="center">Chapter 14. Tree View Widget</th><td width="20%" align="right"> <a accesskey="n" href="sec-TreeViewColumns.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-CellRenderers"></a>14.4. CellRenderers</h2></div></div><div></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-CellRendererOverview"></a>14.4.1. Overview</h3></div></div><div></div></div><p><tt class="classname">TreeViewColumn</tt>s and
+<tt class="classname">CellRenderer</tt>s work together to display a column of
+data in a <tt class="classname">TreeView</tt>. The
+<tt class="classname">TreeViewColumn</tt> provides the column title and a
+vertical space for the <tt class="classname">CellRenderer</tt>s to render a
+portion of the data from the <tt class="classname">TreeView</tt> data store. A
+<tt class="classname">CellRenderer</tt> handles the rendering of each row and
+column data within the confines of the
+<tt class="classname">TreeViewColumn</tt>. A
+<tt class="classname">TreeViewColumn</tt> can contain more than one
+<tt class="classname">CellRenderer</tt> to provide a row display similar to an
+<tt class="classname">HBox</tt>. A common use of multiple
+<tt class="classname">CellRenderer</tt>s is to combine a
+<tt class="classname">CellRendererPixbuf</tt> and a
+<tt class="classname">CellRendererText</tt> in one column.</p><p>An example illustrating the layout of two
+<tt class="classname">TreeViewColumn</tt>s: one with two<tt class="classname">
+CellRenderer</tt>s and one with one
+<tt class="classname">CellRenderer</tt> is shown in <a href="sec-CellRenderers.html#treeviewcolumnfig" title="Figure 14.2. TreeViewColumns with CellRenderers">Figure 14.2, “TreeViewColumns with CellRenderersâ€</a>:</p><div class="figure"><a name="treeviewcolumnfig"></a><p class="title"><b>Figure 14.2. TreeViewColumns with CellRenderers</b></p><div class="mediaobject" align="center"><img src="figures/treeviewcolumn.png" align="middle" alt="TreeViewColumns with CellRenderers"></div></div><p>The application of each <tt class="classname">CellRenderer</tt> is
+indicated with a different background color: yellow for the
+<tt class="classname">CellRendererPixbuf</tt>, cyan for one
+<tt class="classname">CellRendererText</tt>, and pink for the other
+<tt class="classname">CellRendererText</tt>. Note that the
+<tt class="classname">CellRendererPixbuf</tt> and the first
+<tt class="classname">CellRendererText</tt> are in the same column headed by the
+"Pixbuf and Text" header. The background color of the
+<tt class="classname">CellRendererText</tt> rendering "Print File" is the
+default color to show the application area in a single row.</p><p><a href="sec-CellRenderers.html#treeviewcolumnfig" title="Figure 14.2. TreeViewColumns with CellRenderers">Figure 14.2, “TreeViewColumns with CellRenderersâ€</a> was created by the <a href="examples/treeviewcolumn.py" target="_top"><span><b class="command">treeviewcolumn.py</b></span></a>
+program.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-CellRendererTypes"></a>14.4.2. CellRenderer Types</h3></div></div><div></div></div><p>The type of <tt class="classname">CellRenderer</tt> needed is
+determined by the type of tree model data display required; PyGTK has three
+pre-defined <tt class="classname">CellRenderer</tt>s:</p><table border="0" width="100%" bgcolor="#FFECCE"><col align="left" valign="top" width="0*"><tbody><tr><td><span class="term"><tt class="classname">CellRendererPixbuf</tt></span></td><td>renders pixbuf images either created by the program or
+one of the stock items.</td></tr><tr><td><span class="term"><tt class="classname">CellRendererText</tt></span></td><td>renders text strings, and numbers that can be converted
+to a string (including ints, floats, booleans).</td></tr><tr><td><span class="term"><tt class="classname">CellRendererToggle</tt></span></td><td>renders a boolean value as a toggle button or a radio
+button</td></tr></tbody></table></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-CellRendererProperties"></a>14.4.3. CellRenderer Properties</h3></div></div><div></div></div><p>The properties of a <tt class="classname">CellRenderer</tt> determine
+how the data will be rendered:</p><div class="informaltable"><table cellpadding="5" width="100%" border="0"><colgroup><col><col><col></colgroup><tbody><tr valign="top"><td valign="top">"mode"</td><td valign="top">Read-Write</td><td valign="top">The editable mode of the
+<tt class="classname">CellRenderer</tt>. One of:
+<tt class="literal">gtk.CELL_RENDERER_MODE_INERT</tt>,
+<tt class="literal">gtk.CELL_RENDERER_MODE_ACTIVATABLE</tt> or
+<tt class="literal">gtk.CELL_RENDERER_MODE_EDITABLE</tt></td></tr><tr valign="top"><td valign="top">"visible"</td><td valign="top">Read-Write</td><td valign="top">If <tt class="literal">TRUE</tt> the cell is displayed</td></tr><tr valign="top"><td valign="top">"xalign"</td><td valign="top">Read-Write</td><td valign="top">The fraction of <span class="emphasis"><em>free</em></span> space to the left
+of the cell in the range 0.0 to 1.0.</td></tr><tr valign="top"><td valign="top">"yalign"</td><td valign="top">Read-Write</td><td valign="top">The fraction of <span class="emphasis"><em>free</em></span> space above the
+cell in the range 0.0 to 1.0.</td></tr><tr valign="top"><td valign="top">"xpad"</td><td valign="top">Read-Write</td><td valign="top">The amount of padding to the left and right of the
+cell.</td></tr><tr valign="top"><td valign="top">"ypad"</td><td valign="top">Read-Write</td><td valign="top">The amount of padding above and below cell.</td></tr><tr valign="top"><td valign="top">"width"</td><td valign="top">Read-Write</td><td valign="top">The fixed width of the cell.</td></tr><tr valign="top"><td valign="top">"height"</td><td valign="top">Read-Write</td><td valign="top">The fixed height of the cell.</td></tr><tr valign="top"><td valign="top">"is-expander"</td><td valign="top">Read-Write</td><td valign="top">If <tt class="literal">TRUE</tt> the row has children</td></tr><tr valign="top"><td valign="top">"is-expanded"</td><td valign="top">Read-Write</td><td valign="top">If <tt class="literal">TRUE</tt> the row has children and it is
+expanded to show the children.</td></tr><tr valign="top"><td valign="top">"cell-background"</td><td valign="top">Write</td><td valign="top">The background color of the cell as a string.</td></tr><tr valign="top"><td valign="top">"cell-background-gdk"</td><td valign="top">Read-Write</td><td valign="top">The background color of the cell as a <tt class="classname">
+gtk.gdk.Color</tt>.</td></tr><tr valign="top"><td valign="top">"cell-background-set"</td><td valign="top">Read-Write</td><td valign="top">If <tt class="literal">TRUE</tt> the cell background color
+is set by this cellrenderer</td></tr></tbody></table></div><p>The above properties are available for all
+<tt class="classname">CellRenderer</tt> subclasses. The individual
+<tt class="classname">CellRenderer</tt> types also have their own
+properties.</p><p>The <tt class="classname">CellRendererPixbuf</tt> has these
+properties:</p><div class="informaltable"><table cellpadding="5" width="100%" border="0"><colgroup><col><col><col></colgroup><tbody><tr valign="top"><td valign="top">"pixbuf"</td><td valign="top">Read-Write</td><td valign="top">The pixbuf to render - overridden by "stock-id"</td></tr><tr valign="top"><td valign="top">"pixbuf-expander-open"</td><td valign="top">Read-Write</td><td valign="top">Pixbuf for open expander.</td></tr><tr valign="top"><td valign="top">"pixbuf-expander-closed"</td><td valign="top">Read-Write</td><td valign="top">Pixbuf for closed expander.</td></tr><tr valign="top"><td valign="top">"stock-id"</td><td valign="top">Read-Write</td><td valign="top">The stock ID of the stock icon to render</td></tr><tr valign="top"><td valign="top">"stock-size"</td><td valign="top">Read-Write</td><td valign="top">The size of the rendered icon</td></tr><tr valign="top"><td valign="top">"stock-detail"</td><td valign="top">Read-Write</td><td valign="top">Render detail to pass to the theme engine</td></tr></tbody></table></div><p>The <tt class="classname">CellRendererText</tt> has a large number of
+properties mostly dealing with style specification:</p><div class="informaltable"><table cellpadding="3" width="100%" border="0"><colgroup><col><col><col></colgroup><tbody><tr valign="top"><td valign="top">"text"</td><td valign="top">Read-Write</td><td valign="top">Text to render</td></tr><tr valign="top"><td valign="top">"markup"</td><td valign="top">Read-Write</td><td valign="top">Marked up text to render.</td></tr><tr valign="top"><td valign="top">"attributes"</td><td valign="top">Read-Write</td><td valign="top">A list of style attributes to apply to the text of the
+renderer.</td></tr><tr valign="top"><td valign="top">"background"</td><td valign="top">Write</td><td valign="top">Background color as a string</td></tr><tr valign="top"><td valign="top">"foreground"</td><td valign="top">Write</td><td valign="top">Foreground color as a string</td></tr><tr valign="top"><td valign="top">"background-gdk"</td><td valign="top">Read-Write</td><td valign="top">Background color as a
+<tt class="classname">gtk.gdk.Color</tt></td></tr><tr valign="top"><td valign="top">"foreground-gdk"</td><td valign="top">Read-Write</td><td valign="top">Foreground color as a
+<tt class="classname">gtk.gdk.Color</tt></td></tr><tr valign="top"><td valign="top">"font"</td><td valign="top">Read-Write</td><td valign="top">Font description as a string</td></tr><tr valign="top"><td valign="top">"font-desc"</td><td valign="top">Read-Write</td><td valign="top">Font description as a
+<tt class="classname">pango.FontDescription</tt></td></tr><tr valign="top"><td valign="top">"family"</td><td valign="top">Read-Write</td><td valign="top">Name of the font family, e.g. Sans, Helvetica, Times,
+Monospace</td></tr><tr valign="top"><td valign="top">"style"</td><td valign="top">Read-Write</td><td valign="top">Font style</td></tr><tr valign="top"><td valign="top">"variant"</td><td valign="top">Read-Write</td><td valign="top">Font variant</td></tr><tr valign="top"><td valign="top">"weight"</td><td valign="top">Read-Write</td><td valign="top">Font weight</td></tr><tr valign="top"><td valign="top">"stretch"</td><td valign="top">Read-Write</td><td valign="top">Font stretch</td></tr><tr valign="top"><td valign="top">"size"</td><td valign="top">Read-Write</td><td valign="top">Font size</td></tr><tr valign="top"><td valign="top">"size-points"</td><td valign="top">Read-Write</td><td valign="top">Font size in points</td></tr><tr valign="top"><td valign="top">"scale"</td><td valign="top">Read-Write</td><td valign="top">Font scaling factor</td></tr><tr valign="top"><td valign="top">"editable"</td><td valign="top">Read-Write</td><td valign="top">If <tt class="literal">TRUE</tt> the text can be modified by the
+user</td></tr><tr valign="top"><td valign="top">"strikethrough"</td><td valign="top">Read-Write</td><td valign="top">If <tt class="literal">TRUE</tt> strike through the text</td></tr><tr valign="top"><td valign="top">"underline"</td><td valign="top">Read-Write</td><td valign="top">Style of underline for this text</td></tr><tr valign="top"><td valign="top">"rise"</td><td valign="top">Read-Write</td><td valign="top">Offset of text above the baseline (below the baseline if
+rise is negative)</td></tr><tr valign="top"><td valign="top">"language"</td><td valign="top">Read-Write</td><td valign="top">The language this text is in, as an ISO code. Pango can use
+this as a hint when rendering the text. If you don't understand this parameter,
+you probably don't need it. GTK+ 2.4 and above.</td></tr><tr valign="top"><td valign="top">"single-paragraph-mode"</td><td valign="top">Read-Write</td><td valign="top">If <tt class="literal">TRUE</tt>, keep all text in a single
+paragraph. GTK+ 2.4 and above.</td></tr></tbody></table></div><div class="informaltable"><table cellpadding="3" width="100%" border="0"><colgroup><col><col><col></colgroup><tbody><tr valign="top"><td valign="top">"background-set"</td><td valign="top">Read-Write</td><td valign="top">If <tt class="literal">TRUE</tt> apply the background
+color</td></tr><tr valign="top"><td valign="top">"foreground-set"</td><td valign="top">Read-Write</td><td valign="top">If <tt class="literal">TRUE</tt> apply the foreground
+color</td></tr><tr valign="top"><td valign="top">"family-set"</td><td valign="top">Read-Write</td><td valign="top">If <tt class="literal">TRUE</tt> apply the font
+family</td></tr><tr valign="top"><td valign="top">"style-set"</td><td valign="top">Read-Write</td><td valign="top">If <tt class="literal">TRUE</tt> apply the font
+style</td></tr><tr valign="top"><td valign="top">"variant-set"</td><td valign="top">Read-Write</td><td valign="top">If <tt class="literal">TRUE</tt> apply the font
+variant</td></tr><tr valign="top"><td valign="top">"weight-set"</td><td valign="top">Read-Write</td><td valign="top">If <tt class="literal">TRUE</tt> apply the font
+weight</td></tr><tr valign="top"><td valign="top">"stretch-set"</td><td valign="top">Read-Write</td><td valign="top">If <tt class="literal">TRUE</tt> apply the font
+stretch</td></tr><tr valign="top"><td valign="top">"size-set"</td><td valign="top">Read-Write</td><td valign="top">If <tt class="literal">TRUE</tt> apply the font
+size</td></tr><tr valign="top"><td valign="top">"scale-set"</td><td valign="top">Read-Write</td><td valign="top">If <tt class="literal">TRUE</tt> scale the font</td></tr><tr valign="top"><td valign="top">"editable-set"</td><td valign="top">Read-Write</td><td valign="top">If <tt class="literal">TRUE</tt> apply the text
+editability</td></tr><tr valign="top"><td valign="top">"strikethrough-set"</td><td valign="top">Read-Write</td><td valign="top">If <tt class="literal">TRUE</tt> apply the
+strikethrough</td></tr><tr valign="top"><td valign="top">"underline-set"</td><td valign="top">Read-Write</td><td valign="top">If <tt class="literal">TRUE</tt> apply the text
+underlining</td></tr><tr valign="top"><td valign="top">"rise-set"</td><td valign="top">Read-Write</td><td valign="top">If <tt class="literal">TRUE</tt> apply the
+rise</td></tr><tr valign="top"><td valign="top">"language-set"</td><td valign="top">Read-Write</td><td valign="top">If <tt class="literal">TRUE</tt> apply the
+language used to render the text. GTK+ 2.4 and above.</td></tr></tbody></table></div><p>Almost every <tt class="classname">CellRendererText</tt> property has
+an associated boolean property (with the "-set" suffix) that indicates if
+the property is to be applied. This allows you to set a property globally
+and selectively enable and disable its application.</p><p>The <tt class="classname">CellRendererToggle</tt> has the following
+properties:</p><div class="informaltable"><table cellpadding="5" width="100%" border="0"><colgroup><col><col><col></colgroup><tbody><tr valign="top"><td valign="top">"activatable"</td><td valign="top">Read-Write</td><td valign="top">If <tt class="literal">TRUE</tt>, the toggle button can be
+activated</td></tr><tr valign="top"><td valign="top">"active"</td><td valign="top">Read-Write</td><td valign="top">If <tt class="literal">TRUE</tt>, the button is active.</td></tr><tr valign="top"><td valign="top">"radio"</td><td valign="top">Read-Write</td><td valign="top">If <tt class="literal">TRUE</tt>, draw the toggle button as a
+radio button</td></tr><tr valign="top"><td valign="top">"inconsistent"</td><td valign="top">Read-Write</td><td valign="top">If <tt class="literal">TRUE</tt>, the button is in an
+inconsistent state. GTK+ 2.2 and above.</td></tr></tbody></table></div><p>The properties can be set for all rows by using the
+<tt class="methodname">gobject.set_property</tt>() method. See the <a href="examples/treeviewcolumn.py" target="_top"><span><b class="command">treeviewcolumn.py</b></span></a>
+program for an example using this method.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-CellRendererAttributes"></a>14.4.4. CellRenderer Attributes</h3></div></div><div></div></div><p>An attribute associates a tree model column with a
+<tt class="classname">CellRenderer</tt> property; the
+<tt class="classname">CellRenderer</tt> sets the property from the row's column
+value before rendering the cell. This allows you to customize the cell
+display using tree model data. An attribute can be added to the current set
+by using:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treeviewcolumn.add_attribute(<b class="parameter"><tt>cell_renderer</tt></b>, <b class="parameter"><tt>attribute</tt></b>, <b class="parameter"><tt>column</tt></b>)
+</pre></td></tr></table><p>where the property specified by <i class="parameter"><tt>attribute</tt></i>
+is set for the <i class="parameter"><tt>cell_renderer</tt></i> from
+<i class="parameter"><tt>column</tt></i>. For example:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treeviewcolumn.add_attribute(cell, "cell-background", 1)
+</pre></td></tr></table><p>sets the <tt class="classname">CellRenderer</tt> background to the
+color specified by the string in the second column of the data store.</p><p>To clear all attributes and set several new attributes at once
+use:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treeviewcolumn.set_attributes(<i class="parameter"><tt>cell_renderer</tt></i>, ...)
+</pre></td></tr></table><p>where the attributes of <i class="parameter"><tt>cell_renderer</tt></i> are
+set by key-value pairs: property=column. For example, for a
+<tt class="classname">CellRendererText</tt>:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treeviewcolumn.set_attributes(cell, text=0, cell_background=1, xpad=3)
+</pre></td></tr></table><p>sets, for each row, the text from the first column, the
+background color from the second column and the horizontal padding from the
+fourth column. See the <a href="examples/treeviewcolumn.py" target="_top"><span><b class="command">treeviewcolumn.py</b></span></a>
+program for an example using these methods.</p><p>The attributes of a <tt class="classname">CellRenderer</tt> can be
+cleared using:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treeviewcolumn.clear_attributes(<b class="parameter"><tt>cell_renderer</tt></b>)
+</pre></td></tr></table></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-CellDataFunction"></a>14.4.5. Cell Data Function</h3></div></div><div></div></div><p>If setting attributes is not sufficient for your needs you can
+set a function to be called for each row to set the properties for that
+<tt class="classname">CellRenderer</tt> using:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treeviewcolumn.set_cell_data_func(<i class="parameter"><tt>cell_renderer</tt></i>, <i class="parameter"><tt>func</tt></i>, <i class="parameter"><tt>data</tt></i>=None)
+</pre></td></tr></table><p>where <i class="parameter"><tt>func</tt></i> has the signature:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def func(column, cell_renderer, tree_model, iter, user_data)
+</pre></td></tr></table><p>where <i class="parameter"><tt>column</tt></i> is the
+<tt class="classname">TreeViewColumn</tt> containing
+<i class="parameter"><tt>cell_renderer</tt></i>, <i class="parameter"><tt>tree_model</tt></i> is
+the data store and <i class="parameter"><tt>iter</tt></i> is a
+<tt class="classname">TreeIter</tt> pointing at a row in
+<i class="parameter"><tt>tree_model</tt></i>. <i class="parameter"><tt>user_data</tt></i> is the
+value of <i class="parameter"><tt>data</tt></i> that was passed to
+<tt class="methodname">set_cell_data_func</tt>().</p><p>In <i class="parameter"><tt>func</tt></i> you set whatever properties you
+want on <i class="parameter"><tt>cell_renderer</tt></i>. For example the following code
+fragment sets the text property to display PyGTK objects as an ID
+string.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ ...
+ def obj_id_str(treeviewcolumn, cell_renderer, model, iter):
+ pyobj = model.get_value(iter, 0)
+ cell.set_property('text', str(pyobj))
+ return
+ ...
+ treestore = gtk.TreeStore(object)
+ win = gtk.Window()
+ treeview = gtk.TreeView(treestore)
+ win.add(treeview)
+ cell = CellRendererText()
+ tvcolumn = gtk TreeViewColumn('Object ID', cell)
+ treeview.append_column(tvcolumn)
+ iter = treestore.append(None, [win])
+ iter = treestore.append(iter, [treeview])
+ iter = treestore.append(iter, [tvcolumn])
+ iter = treestore.append(iter, [cell])
+ iter = treestore.append(None, [treestore])
+ ...
+</pre></td></tr></table><p>The resulting display should be something like <a href="sec-CellRenderers.html#celldatafuncfig" title="Figure 14.3. CellRenderer Data Function">Figure 14.3, “CellRenderer Data Functionâ€</a>:</p><div class="figure"><a name="celldatafuncfig"></a><p class="title"><b>Figure 14.3. CellRenderer Data Function</b></p><div class="mediaobject" align="center"><img src="figures/celldatafunc.png" align="middle" alt="CellRenderer Data Function"></div></div><p>Another use of a cell data function is to control the formatting
+of a numerical text display e.g. a float value. A
+<tt class="classname">CellRendererText</tt> will display and automatically
+convert a float to a string but with a default format "%f".</p><p>With cell data functions you can even generate the cell data for
+the columns from external data. For example the <a href="examples/filelisting.py" target="_top"><span><b class="command">filelisting.py</b></span></a>
+program uses a <tt class="classname">ListStore</tt> with just one column that
+holds a list of file names. The <tt class="classname">TreeView</tt> displays
+columns that include a pixbuf, the file name and the file's size, mode and
+time of last change. The data is generated by the following cell data
+functions:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def file_pixbuf(self, column, cell, model, iter):
+ filename = os.path.join(self.dirname, model.get_value(iter, 0))
+ filestat = statcache.stat(filename)
+ if stat.S_ISDIR(filestat.st_mode):
+ pb = folderpb
+ else:
+ pb = filepb
+ cell.set_property('pixbuf', pb)
+ return
+
+ def file_name(self, column, cell, model, iter):
+ cell.set_property('text', model.get_value(iter, 0))
+ return
+
+ def file_size(self, column, cell, model, iter):
+ filename = os.path.join(self.dirname, model.get_value(iter, 0))
+ filestat = statcache.stat(filename)
+ cell.set_property('text', filestat.st_size)
+ return
+
+ def file_mode(self, column, cell, model, iter):
+ filename = os.path.join(self.dirname, model.get_value(iter, 0))
+ filestat = statcache.stat(filename)
+ cell.set_property('text', oct(stat.S_IMODE(filestat.st_mode)))
+ return
+
+
+ def file_last_changed(self, column, cell, model, iter):
+ filename = os.path.join(self.dirname, model.get_value(iter, 0))
+ filestat = statcache.stat(filename)
+ cell.set_property('text', time.ctime(filestat.st_mtime))
+ return
+</pre></td></tr></table><p>These cell data functions retrieve the file information using
+the name, extract the needed data and set the cell 'text' or 'pixbuf'
+property with the data. <a href="sec-CellRenderers.html#filelistingfig" title="Figure 14.4. File Listing Example Using Cell Data Functions">Figure 14.4, “File Listing Example Using Cell Data Functionsâ€</a> shows the example
+program in action:</p><div class="figure"><a name="filelistingfig"></a><p class="title"><b>Figure 14.4. File Listing Example Using Cell Data Functions</b></p><div class="mediaobject" align="center"><img src="figures/filelisting.png" align="middle" alt="File Listing Example Using Cell Data Functions"></div></div><p></p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-CellRendererTextMarkup"></a>14.4.6. CellRendererText Markup</h3></div></div><div></div></div><p>A <tt class="classname">CellRendererText</tt> can use Pango markup (by
+setting the "markup" property) instead of a plain text string to encode
+various text attributes and provide a rich text display with multiple font
+style changes. See the <a href="http://www.pygtk.org/pygtk2reference/pango-markup.html" target="_top">Pango
+Markup</a> reference in the <a href="http://www.pygtk.org/pygtk2reference" target="_top">PyGTK Reference Manual</a>
+for details on the Pango markup language.</p><p>The following code fragment illustrates the use of the
+"markup" property:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ ...
+ liststore = gtk.ListStore(str)
+ cell = gtk.CellRendererText()
+ tvcolumn = gtk.TreeViewColumn('Pango Markup', cell, markup=0)
+ ...
+ liststore.append(['&lt;span foreground="blue"&gt;&lt;b&gt;Pango&lt;/b&gt;&lt;/span&gt; markup can'
+' change\n&lt;i&gt;style&lt;/i&gt; &lt;big&gt;size&lt;/big&gt;, &lt;u&gt;underline,'
+ &lt;s&gt;strikethrough&lt;/s&gt;&lt;/u&gt;,\n'
+'and &lt;span font_family="URW Chancery L"&gt;&lt;big&gt;font family '
+'e.g. URW Chancery L&lt;/big&gt;&lt;/span&gt;\n&lt;span foreground="red"&gt;red'
+' foreground and &lt;span background="cyan"&gt;cyan background&lt;/span&gt;&lt;/span&gt;'])
+ ...
+</pre></td></tr></table><p>produces a display similar to <a href="sec-CellRenderers.html#celltextmarkupfig" title="Figure 14.5. CellRendererText Markup">Figure 14.5, “CellRendererText Markupâ€</a>:</p><div class="figure"><a name="celltextmarkupfig"></a><p class="title"><b>Figure 14.5. CellRendererText Markup</b></p><div class="mediaobject" align="center"><img src="figures/celltextmarkup.png" align="middle" alt="CellRendererText Markup"></div></div><p>If you create pango markup on the fly you have to be careful to
+replace the characters that are special to the markup language: "&lt;",
+"&gt;", "&amp;". The Python library function
+<tt class="function">cgi.escape</tt>() can do these basic conversions.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="EditableTextCells"></a>14.4.7. Editable Text Cells</h3></div></div><div></div></div><p><tt class="classname">CellRendererText</tt> cells can be made editable
+to allow a user to edit the contents of the cell that is selected by
+clicking it or pressing one of the <span><b class="keycap">Return</b></span>,
+<span><b class="keycap">Enter</b></span>, <span><b class="keycap">Space</b></span> or <span><b class="keycap">Shift</b></span>+<span><b class="keycap">Space</b></span>
+keys. A <tt class="classname">CellRendererText</tt> is made editable for all
+rows by setting its "editable" property to <tt class="literal">TRUE</tt> as
+follows:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ cellrenderertext.set_property('editable', True)
+</pre></td></tr></table><p>Individual cells can be set editable by adding an attribute to the
+<tt class="classname">TreeViewColumn</tt> using the
+<tt class="classname">CellRendererText</tt> similar to:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treeviewcolumn.add_attribute(cellrenderertext, "editable", 2)
+</pre></td></tr></table><p>which sets the "editable" property to the value contained in the
+third column of the data store.</p><p>Once the cell editing completes, your application should handle
+the "edited" signal to retrieve the new text and set the associated data
+store value. Otherwise the cell value reverts to its original value. The
+signature of the "edited" signal handler is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def edited_cb(<i class="parameter"><tt>cell</tt></i>, <i class="parameter"><tt>path</tt></i>, <i class="parameter"><tt>new_text</tt></i>, <i class="parameter"><tt>user_data</tt></i>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>cell</tt></i> is the
+<tt class="classname">CellRendererText</tt>, <i class="parameter"><tt>path</tt></i> is the
+tree path (as a string) to the row containing the edited cell,
+<i class="parameter"><tt>new_text</tt></i> is the edited text and
+<i class="parameter"><tt>user_data</tt></i> is context data. Since the
+<tt class="classname">TreeModel</tt> is needed to use
+<i class="parameter"><tt>path</tt></i> to set <i class="parameter"><tt>new_text</tt></i> in the
+data store you probably want to pass the <tt class="classname">TreeModel</tt> as
+<i class="parameter"><tt>user_data</tt></i> in the <tt class="methodname">connect</tt>()
+method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ cellrenderertext.connect('edited', edited_cb, model)
+</pre></td></tr></table><p>If you have two or more editable cells in a row, you could pass
+the <tt class="classname">TreeModel</tt> column number as part of
+<i class="parameter"><tt>user_data</tt></i> as well as the
+<tt class="classname">TreeModel</tt>:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ cellrenderertext.connect('edited', edited_cb, (model, col_num))
+</pre></td></tr></table><p>Then you can set the new text in the "edited" handler similar to
+this example using a <tt class="classname">ListStore</tt>:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def edited_cb(cell, path, new_text, user_data):
+ liststore, column = user_data
+ liststore[path][column] = new_text
+ return
+</pre></td></tr></table><p></p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-ActivatableToggleCells"></a>14.4.8. Activatable Toggle Cells</h3></div></div><div></div></div><p><tt class="classname">CellRendererToggle</tt> buttons can be made
+activatable by setting the "activatable" property to
+<tt class="literal">TRUE</tt>. Similar to editable
+<tt class="classname">CellRendererText</tt> cells the "activatable" property can
+be set for the entire <tt class="classname">CellRendererToggle</tt> set of cells
+using the <tt class="methodname">set_property</tt>() method or for individual
+cells by adding an attribute to the <tt class="classname">TreeViewColumn</tt>
+containing the <tt class="classname">CellRendererToggle</tt>.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ cellrenderertoggle.set_property('activatable', True)
+
+ treeviewcolumn.add_attribute(cellrenderertoggle, "activatable", 1)
+</pre></td></tr></table><p>The setting of the individual toggle buttons can be derived from
+the values in a <tt class="classname">TreeModel</tt> column by adding an
+attribute, for example:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treeviewcolumn.add_attribute(cellrenderertoggle, "active", 2)
+</pre></td></tr></table><p>You should connect to the "toggled" signal to get notification
+of user clicks on the toggle buttons so that your application can change the
+value in the data store. For example:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ cellrenderertoggle.connect("toggled", toggled_cb, (model, column))
+</pre></td></tr></table><p>The callback has the signature:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def toggled_cb(<i class="parameter"><tt>cellrenderertoggle</tt></i>, <i class="parameter"><tt>path</tt></i>, <i class="parameter"><tt>user_data</tt></i>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>path</tt></i> is the tree path, as a string,
+pointing to the row containing the toggle that was clicked. You should pass
+the <tt class="classname">TreeModel</tt> and possibly the column index as part
+of <i class="parameter"><tt>user_data</tt></i> to provide the necessary context for
+setting the data store values. For example, your application can toggle the
+data store value as follows:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def toggled_cb(cell, path, user_data):
+ model, column = user_data
+ model[path][column] = not model[path][column]
+ return
+</pre></td></tr></table><p>If your application wants to display the toggle buttons as radio
+buttons and have only one be set, it will have to scan the data store to
+deactivate the active radio button and then set the toggled button. For
+example:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def toggled_cb(cell, path, user_data):
+ model, column = user_data
+ for row in model:
+ row[column] = False
+ model[path][column] = True
+ return
+</pre></td></tr></table><p>takes the lazy approach of setting all data store values to
+<tt class="literal">FALSE</tt> before setting the value to <tt class="literal">TRUE</tt>
+for the row specified by <i class="parameter"><tt>path</tt></i>.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-EditableActivatableProgram"></a>14.4.9. Editable and Activatable Cell Example Program</h3></div></div><div></div></div><p>The <a href="examples/cellrenderer.py" target="_top">cellrenderer.py</a>
+program illustrates the application of editable
+<tt class="classname">CellRendererText</tt> and activatable
+<tt class="classname">CellRendererToggle</tt> cells in a
+<tt class="classname">TreeStore</tt>.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 1 #!/usr/bin/env python
+ 2 # vim: ts=4:sw=4:tw=78:nowrap
+ 3 """ Demonstration using editable and activatable CellRenderers """
+ 4 import pygtk
+ 5 pygtk.require("2.0")
+ 6 import gtk, gobject
+ 7
+ 8 tasks = {
+ 9 "Buy groceries": "Go to Asda after work",
+ 10 "Do some programming": "Remember to update your software",
+ 11 "Power up systems": "Turn on the client but leave the server",
+ 12 "Watch some tv": "Remember to catch ER"
+ 13 }
+ 14
+ 15 class GUI_Controller:
+ 16 """ The GUI class is the controller for our application """
+ 17 def __init__(self):
+ 18 # setup the main window
+ 19 self.root = gtk.Window(type=gtk.WINDOW_TOPLEVEL)
+ 20 self.root.set_title("CellRenderer Example")
+ 21 self.root.connect("destroy", self.destroy_cb)
+ 22 # Get the model and attach it to the view
+ 23 self.mdl = Store.get_model()
+ 24 self.view = Display.make_view( self.mdl )
+ 25 # Add our view into the main window
+ 26 self.root.add(self.view)
+ 27 self.root.show_all()
+ 28 return
+ 29 def destroy_cb(self, *kw):
+ 30 """ Destroy callback to shutdown the app """
+ 31 gtk.main_quit()
+ 32 return
+ 33 def run(self):
+ 34 """ run is called to set off the GTK mainloop """
+ 35 gtk.main()
+ 36 return
+ 37
+ 38 class InfoModel:
+ 39 """ The model class holds the information we want to display """
+ 40 def __init__(self):
+ 41 """ Sets up and populates our gtk.TreeStore """
+ 42 self.tree_store = gtk.TreeStore( gobject.TYPE_STRING,
+ 43 gobject.TYPE_BOOLEAN )
+ 44 # places the global people data into the list
+ 45 # we form a simple tree.
+ 46 for item in tasks.keys():
+ 47 parent = self.tree_store.append( None, (item, None) )
+ 48 self.tree_store.append( parent, (tasks[item],None) )
+ 49 return
+ 50 def get_model(self):
+ 51 """ Returns the model """
+ 52 if self.tree_store:
+ 53 return self.tree_store
+ 54 else:
+ 55 return None
+ 56
+ 57 class DisplayModel:
+ 58 """ Displays the Info_Model model in a view """
+ 59 def make_view( self, model ):
+ 60 """ Form a view for the Tree Model """
+ 61 self.view = gtk.TreeView( model )
+ 62 # setup the text cell renderer and allows these
+ 63 # cells to be edited.
+ 64 self.renderer = gtk.CellRendererText()
+ 65 self.renderer.set_property( 'editable', True )
+ 66 self.renderer.connect( 'edited', self.col0_edited_cb, model )
+ 67
+ 68 # The toggle cellrenderer is setup and we allow it to be
+ 69 # changed (toggled) by the user.
+ 70 self.renderer1 = gtk.CellRendererToggle()
+ 71 self.renderer1.set_property('activatable', True)
+ 72 self.renderer1.connect( 'toggled', self.col1_toggled_cb, model ) 73
+ 74 # Connect column0 of the display with column 0 in our list model 75 # The renderer will then display whatever is in column 0 of
+ 76 # our model .
+ 77 self.column0 = gtk.TreeViewColumn("Name", self.renderer, text=0) 78
+ 79 # The columns active state is attached to the second column
+ 80 # in the model. So when the model says True then the button
+ 81 # will show as active e.g on.
+ 82 self.column1 = gtk.TreeViewColumn("Complete", self.renderer1 )
+ 83 self.column1.add_attribute( self.renderer1, "active", 1)
+ 84 self.view.append_column( self.column0 )
+ 85 self.view.append_column( self.column1 )
+ 86 return self.view
+ 87 def col0_edited_cb( self, cell, path, new_text, model ):
+ 88 """
+ 89 Called when a text cell is edited. It puts the new text
+ 90 in the model so that it is displayed properly.
+ 91 """
+ 92 print "Change '%s' to '%s'" % (model[path][0], new_text)
+ 93 model[path][0] = new_text
+ 94 return
+ 95 def col1_toggled_cb( self, cell, path, model ):
+ 96 """
+ 97 Sets the toggled state on the toggle button to true or false.
+ 98 """
+ 99 model[path][1] = not model[path][1]
+ 100 print "Toggle '%s' to: %s" % (model[path][0], model[path][1],)
+ 101 return
+ 102
+ 103 if __name__ == '__main__':
+ 104 Store = InfoModel()
+ 105 Display = DisplayModel()
+ 106 myGUI = GUI_Controller()
+ 107 myGUI.run()
+</pre></td></tr></table><p>The program provides editable cells in the first column and
+activatable cells in the second column. Lines 64-66 create an editable
+<tt class="classname">CellRendererText</tt> and connect the "edited" signal to
+the <tt class="methodname">col0_edited_cb</tt>() callback (lines 87-94) that
+changes the appropriate row column value in the
+<tt class="classname">TreeStore</tt>. Likewise lines 70-72 create an activatable
+<tt class="classname">CellRendererToggle</tt> and connect the "toggled" signal
+to the <tt class="methodname">col1_toggled_cb</tt>() callback (lines 95-101) to
+change the appropriate row value. When an editable or activatable cell is
+changed, a message is printed to indicate what the change was.</p><p><a href="sec-CellRenderers.html#cellrendererfig" title="Figure 14.6. Editable and Activatable Cells">Figure 14.6, “Editable and Activatable Cellsâ€</a> illustrates the <a href="examples/cellrenderer.py" target="_top">cellrenderer.py</a> program in
+operation.</p><div class="figure"><a name="cellrendererfig"></a><p class="title"><b>Figure 14.6. Editable and Activatable Cells</b></p><div class="mediaobject" align="center"><img src="figures/cellrenderer.png" align="middle" alt="Editable and Activatable Cells"></div></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-TreeViews.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-TreeViewWidget.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-TreeViewColumns.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">14.3. TreeViews </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 14.5. TreeViewColumns</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-CheckButtons.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-CheckButtons.html
new file mode 100644
index 0000000..b6a62bb
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-CheckButtons.html
@@ -0,0 +1,100 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>6.3. Check Buttons</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-ButtonWidget.html" title="Chapter 6. The Button Widget"><link rel="previous" href="sec-ToggleButtons.html" title="6.2. Toggle Buttons"><link rel="next" href="sec-RadioButtons.html" title="6.4. Radio Buttons"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">6.3. Check Buttons</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-ToggleButtons.html">Prev</a> </td><th width="60%" align="center">Chapter 6. The Button Widget</th><td width="20%" align="right"> <a accesskey="n" href="sec-RadioButtons.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-CheckButtons"></a>6.3. Check Buttons</h2></div></div><div></div></div><p>Check buttons inherit many properties and methods from the the
+toggle buttons above, but look a little different. Rather than being buttons
+with text inside them, they are small squares with the text to the right of
+them. These are often used for toggling options on and off in
+applications.</p><p>The creation method is similar to that of the normal
+button.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ check_button = gtk.CheckButton(<b class="parameter"><tt>label</tt></b>=None)
+</pre></td></tr></table><p>If the <i class="parameter"><tt>label</tt></i> argument is specified the method
+creates a check button with a label beside it. The <i class="parameter"><tt>label</tt></i>
+text is parsed for '_'-prefixed mnemonic characters.</p><p>Checking and setting the state of the check button are
+identical to that of the toggle button.</p><p>The <a href="examples/checkbutton.py" target="_top"><span><b class="command">checkbutton.py</b></span></a>
+program provides an example of the use of the check buttons.
+<a href="sec-CheckButtons.html#checkbuttonfig" title="Figure 6.3. Check Button Example">Figure 6.3, “Check Button Exampleâ€</a> illustrates the resulting window:</p><div class="figure"><a name="checkbuttonfig"></a><p class="title"><b>Figure 6.3. Check Button Example</b></p><div class="mediaobject" align="center"><img src="figures/checkbutton.png" align="middle" alt="Check Button Example"></div></div><p>The source code for the <a href="examples/checkbutton.py" target="_top"><span><b class="command">checkbutton.py</b></span></a>
+program is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 1 #!/usr/bin/env python
+ 2
+ 3 # example checkbutton.py
+ 4
+ 5 import pygtk
+ 6 pygtk.require('2.0')
+ 7 import gtk
+ 8
+ 9 class CheckButton:
+ 10 # Our callback.
+ 11 # The data passed to this method is printed to stdout
+ 12 def callback(self, widget, data=None):
+ 13 print "%s was toggled %s" % (data, ("OFF", "ON")[widget.get_active()])
+ 14
+ 15 # This callback quits the program
+ 16 def delete_event(self, widget, event, data=None):
+ 17 gtk.main_quit()
+ 18 return False
+ 19
+ 20 def __init__(self):
+ 21 # Create a new window
+ 22 self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ 23
+ 24 # Set the window title
+ 25 self.window.set_title("Check Button")
+ 26
+ 27 # Set a handler for delete_event that immediately
+ 28 # exits GTK.
+ 29 self.window.connect("delete_event", self.delete_event)
+ 30
+ 31 # Sets the border width of the window.
+ 32 self.window.set_border_width(20)
+ 33
+ 34 # Create a vertical box
+ 35 vbox = gtk.VBox(True, 2)
+ 36
+ 37 # Put the vbox in the main window
+ 38 self.window.add(vbox)
+ 39
+ 40 # Create first button
+ 41 button = gtk.CheckButton("check button 1")
+ 42
+ 43 # When the button is toggled, we call the "callback" method
+ 44 # with a pointer to "button" as its argument
+ 45 button.connect("toggled", self.callback, "check button 1")
+ 46
+ 47
+ 48 # Insert button 1
+ 49 vbox.pack_start(button, True, True, 2)
+ 50
+ 51 button.show()
+ 52
+ 53 # Create second button
+ 54
+ 55 button = gtk.CheckButton("check button 2")
+ 56
+ 57 # When the button is toggled, we call the "callback" method
+ 58 # with a pointer to "button 2" as its argument
+ 59 button.connect("toggled", self.callback, "check button 2")
+ 60 # Insert button 2
+ 61 vbox.pack_start(button, True, True, 2)
+ 62
+ 63 button.show()
+ 64
+ 65 # Create "Quit" button
+ 66 button = gtk.Button("Quit")
+ 67
+ 68 # When the button is clicked, we call the mainquit function
+ 69 # and the program exits
+ 70 button.connect("clicked", lambda wid: gtk.main_quit())
+ 71
+ 72 # Insert the quit button
+ 73 vbox.pack_start(button, True, True, 2)
+ 74
+ 75 button.show()
+ 76 vbox.show()
+ 77 self.window.show()
+ 78
+ 79 def main():
+ 80 gtk.main()
+ 81 return 0
+ 82
+ 83 if __name__ == "__main__":
+ 84 CheckButton()
+ 85 main()
+</pre></td></tr></table></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-ToggleButtons.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-ButtonWidget.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-RadioButtons.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">6.2. Toggle Buttons </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 6.4. Radio Buttons</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-ColorButtonAndFontButton.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-ColorButtonAndFontButton.html
new file mode 100644
index 0000000..3e800f5
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-ColorButtonAndFontButton.html
@@ -0,0 +1,100 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>16.3. ColorButton and FontButton Widgets</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-NewInPyGTK2.4.html" title="Chapter 16. New Widgets in PyGTK 2.4"><link rel="previous" href="sec-ComboBoxAndComboboxEntry.html" title="16.2. ComboBox and ComboBoxEntry Widgets"><link rel="next" href="sec-EntryCompletion.html" title="16.4. EntryCompletion Objects"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">16.3. ColorButton and FontButton Widgets</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-ComboBoxAndComboboxEntry.html">Prev</a> </td><th width="60%" align="center">Chapter 16. New Widgets in PyGTK 2.4</th><td width="20%" align="right"> <a accesskey="n" href="sec-EntryCompletion.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-ColorButtonAndFontButton"></a>16.3. ColorButton and FontButton Widgets</h2></div></div><div></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-ColorButton"></a>16.3.1. ColorButton Widgets</h3></div></div><div></div></div><p>A <tt class="classname">ColorButton</tt> widget provides a convenient
+way of displaying a color in a button that can be clicked to open a
+<tt class="classname">ColorSelectionDialog</tt>. It's useful for displaying and
+setting colors in a user preference dialog. A
+<tt class="classname">ColorButton</tt> takes care of setting up, displaying and
+retrieving the result of a <tt class="classname">ColorSelectionDialog</tt>. A
+<tt class="classname">ColorButton</tt> is created using the constructor:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ colorbutton = gtk.ColorButton(<b class="parameter"><tt>color</tt></b>=gtk.gdk.Color(0,0,0))
+</pre></td></tr></table><p>The initial color can be specified using the
+<i class="parameter"><tt>color</tt></i> parameter or set later using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ colorbutton.set_color(<b class="parameter"><tt>color</tt></b>)
+</pre></td></tr></table><p>The title for the <tt class="classname">ColorSelectionDialog</tt> that
+is displayed when the button is clicked can be set and retrieved using the
+methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ colorbutton.set_title(<b class="parameter"><tt>title</tt></b>)
+
+ title = colorbutton.get_title()
+</pre></td></tr></table><p>The opacity of the color is set using the alpha channel. The
+following methods get and set the color opacity in the range from 0
+(transparent) to 65535 (opaque):</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ alpha = colorbutton.get_alpha()
+
+ colorbutton.set_alpha(<b class="parameter"><tt>alpha</tt></b>)
+</pre></td></tr></table><p>By default the alpha is ignored because the "use_alpha" property
+is <tt class="literal">FALSE</tt>. The value of the "use_alpha" property can be
+set and retrieved using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ colorbutton.set_use_alpha(<b class="parameter"><tt>use_alpha</tt></b>)
+
+ use_alpha = colorbutton.get_use_alpha()
+</pre></td></tr></table><p>If "use_alpha" is <tt class="literal">TRUE</tt> the
+<tt class="classname">ColorSelectionDialog</tt> displays a slider for setting
+the opacity and displays the color using a checkerboard background.</p><p>You can track changes in the selected color by connecting to the
+"color-set" signal that is emitted when the user sets the color. The signal
+callback signature is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def color_set_cb(colorbutton, user_data):
+</pre></td></tr></table><p>The example program <a href="examples/colorbutton.py" target="_top">colorbutton.py</a> illustrates the use of
+a <tt class="classname">ColorButton</tt>. <a href="sec-ColorButtonAndFontButton.html#colorbuttonfig" title="Figure 16.8. ColorButton Example">Figure 16.8, “ColorButton Exampleâ€</a> shows
+the program in operation.</p><div class="figure"><a name="colorbuttonfig"></a><p class="title"><b>Figure 16.8. ColorButton Example</b></p><div class="mediaobject" align="center"><img src="figures/colorbutton.png" align="middle" alt="ColorButton Example"></div></div><p></p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-FontButton"></a>16.3.2. FontButton Widgets</h3></div></div><div></div></div><p>Like the <tt class="classname">ColorButton</tt>, the
+<tt class="classname">FontButton</tt> is a convenience widget that provides a
+display of the currently selected font and, when clicked, opens a
+<tt class="classname">FontSelectionDialog</tt>. A
+<tt class="classname">FontButton</tt> takes care of setting up, displaying and
+retrieving the result of a <tt class="classname">FontSelectionDialog</tt>. A
+FontButton is created using the constructor:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ fontbutton = gtk.FontButton(<b class="parameter"><tt>fontname</tt></b>=None)
+</pre></td></tr></table><p>where <i class="parameter"><tt>fontname</tt></i> is a string specifying the
+current font for the <tt class="classname">FontSelectionDialog</tt>. For example
+the font name can be specified like 'Sans 12', 'Sans Bold 14', or 'Monospace
+Italic 14'. You need to specify the font family and size at minimum.</p><p>The current font can also be set and retrieved using the following
+methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ result = fontbutton.set_font_name(<b class="parameter"><tt>fontname</tt></b>)
+
+ fontname = fontbutton.get_font_name()
+</pre></td></tr></table><p>where <i class="parameter"><tt>result</tt></i> returns
+<tt class="literal">TRUE</tt> or <tt class="literal">FALSE</tt> to indicate whether the
+font was successfully set. The <tt class="classname">FontButton</tt> has a
+number of properties and associated methods that affect the display of the
+current font in the <tt class="classname">FontButton</tt>. The "show-size" and
+show-style" properties contain boolean values that control whether the font
+size and style will be displayed in the button label. The following methods
+set and retrieve the value of these properties:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ fontbutton.set_show_style(<b class="parameter"><tt>show_style</tt></b>)
+ show_style = fontbutton.get_show_style()
+
+ fontbutton.set_show_size(<b class="parameter"><tt>show_size</tt></b>)
+ show_size = fontbutton.get_show_size()
+</pre></td></tr></table><p>Alternatively, you can have the current font size and style used
+by the label to directly illustrate the font selection. The "use-size" and
+"use-font" properties and the associated methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ fontbutton.set_use_font(<b class="parameter"><tt>use_font</tt></b>)
+ use_font = fontbutton.get_use_font()
+
+ fontbutton.set_use_size(<b class="parameter"><tt>use_size</tt></b>)
+ use_size = fontbutton.get_use_size()
+</pre></td></tr></table><p>Using the current font in the label seems like a useful
+illustration technique in spite of the inevitable changes in size of the
+button but using the selected size doesn't seem as useful especially when
+using really large or small font sizes. Note if you set "use-font" or
+"use-size" to <tt class="literal">TRUE</tt> and later set them to
+<tt class="literal">FALSE</tt>, the last set font and size will be retained. For
+example, if "use-font" and "use-size" are <tt class="literal">TRUE</tt> and the
+current font is <tt class="literal">Monospace Italic 20</tt>, the
+<tt class="classname">FontButton</tt> label is displayed using
+<tt class="literal">Monospace Italic 20</tt>; then if "use-font" and "use-size"
+are set to <tt class="literal">FALSE</tt> and then the current font is changed to
+<tt class="literal">Sans 12</tt> the label will still be displayed in
+<tt class="literal">Monospace Italic 20</tt>. Use the example program <a href="examples/fontbutton.py" target="_top">fontbutton.py</a> to see how this
+works.</p><p>Finally, the title of the
+<tt class="classname">FontSelectionDialog</tt> can be set and retrieved using
+the methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ fontbutton.set_title(<b class="parameter"><tt>title</tt></b>)
+
+ title = fontbutton.get_title()
+</pre></td></tr></table><p>Like the <tt class="classname">ColorButton</tt>, you can track changes
+in the current font by connecting to the "font-set" signal that is emitted
+when the user sets the font. The signal callback signature is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def font_set_cb(fontbutton, user_data):
+</pre></td></tr></table><p>The example program <a href="examples/fontbutton.py" target="_top">fontbutton.py</a> illustrates the use of a
+<tt class="classname">FontButton</tt>. You can set the "use-font", "use-size",
+"show-size" and "show-style" properties using toggle buttons. <a href="sec-ColorButtonAndFontButton.html#fontbuttonfig" title="Figure 16.9. FontButton Example">Figure 16.9, “FontButton Exampleâ€</a> shows the program in operation.</p><div class="figure"><a name="fontbuttonfig"></a><p class="title"><b>Figure 16.9. FontButton Example</b></p><div class="mediaobject" align="center"><img src="figures/fontbutton.png" align="middle" alt="FontButton Example"></div></div><p></p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-ComboBoxAndComboboxEntry.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-NewInPyGTK2.4.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-EntryCompletion.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">16.2. ComboBox and ComboBoxEntry Widgets </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 16.4. EntryCompletion Objects</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-ColorSelection.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-ColorSelection.html
new file mode 100644
index 0000000..6857aa5
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-ColorSelection.html
@@ -0,0 +1,151 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>9.13. Color Selection</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-MiscellaneousWidgets.html" title="Chapter 9. Miscellaneous Widgets"><link rel="previous" href="sec-Calendar.html" title="9.12. Calendar"><link rel="next" href="sec-FileSelections.html" title="9.14. File Selections"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">9.13. Color Selection</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-Calendar.html">Prev</a> </td><th width="60%" align="center">Chapter 9. Miscellaneous Widgets</th><td width="20%" align="right"> <a accesskey="n" href="sec-FileSelections.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-ColorSelection"></a>9.13. Color Selection</h2></div></div><div></div></div><p>The color selection widget is, not surprisingly, a widget for
+interactive selection of colors. This composite widget lets the user select
+a color by manipulating RGB (Red, Green, Blue) and HSV (Hue, Saturation,
+Value) triples. This is done either by adjusting single values with sliders
+or entries, or by picking the desired color from a hue-saturation
+wheel/value bar. Optionally, the opacity of the color can also be
+set.</p><p>The color selection widget currently emits only one signal,
+"color_changed", which is emitted whenever the current color in the widget
+changes, either when the user changes it or if it's set explicitly through
+the <tt class="methodname">set_color</tt>() method.</p><p>Lets have a look at what the color selection widget has to offer us.
+The widget comes in two flavors: <tt class="classname">gtk.ColorSelection</tt>
+and <tt class="classname">gtk.ColorSelectionDialog</tt>.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ colorsel = gtk.ColorSelection()
+</pre></td></tr></table><p>You'll probably not be using this constructor directly. It
+creates an orphan <tt class="classname">ColorSelection</tt> widget which you'll
+have to parent yourself. The <tt class="classname">ColorSelection</tt> widget
+inherits from the <tt class="classname">VBox</tt> widget.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ colorseldlg = gtk.ColorSelectionDialog(<b class="parameter"><tt>title</tt></b>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>title</tt></i> is a string to be used in the
+titlebar of the dialog.</p><p>This is the most common color selection constructor. It creates
+a <tt class="classname">ColorSelectionDialog</tt>. It consists of a
+<tt class="classname">Frame</tt> containing a
+<tt class="classname">ColorSelection</tt> widget, an
+<tt class="classname">HSeparator</tt> and an <tt class="classname">HBox</tt> with
+three buttons, <span class="guibutton">Ok</span>, <span class="guibutton">Cancel</span> and
+<span class="guibutton">Help</span>. You can reach these buttons by accessing the
+<i class="parameter"><tt>ok_button</tt></i>, <i class="parameter"><tt>cancel_button</tt></i> and
+<i class="parameter"><tt>help_button</tt></i> attributes of the
+<tt class="classname">ColorSelectionDialog</tt>, (i.e.
+<i class="parameter"><tt>colorseldlg.ok_button</tt></i>). The
+<tt class="classname">ColorSelection</tt> widget is accessed using the attribute
+<i class="parameter"><tt>colorsel</tt></i>:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ colorsel = colorseldlg.colorsel
+</pre></td></tr></table><p>The <tt class="classname">ColorSelection</tt> widget has a number of
+methods that change its characteristics or provide access to the color
+selection.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ colorsel.set_has_opacity_control(<b class="parameter"><tt>has_opacity</tt></b>)
+</pre></td></tr></table><p>The color selection widget supports adjusting the opacity of a
+color (also known as the alpha channel). This is disabled by default.
+Calling this method with <i class="parameter"><tt>has_opacity</tt></i> set to
+<tt class="literal">TRUE</tt> enables opacity. Likewise, <i class="parameter"><tt>has_opacity
+</tt></i>set to <tt class="literal">FALSE</tt> will disable opacity.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ colorsel.set_current_color(<b class="parameter"><tt>color</tt></b>)
+ colorsel.set_current_alpha(<b class="parameter"><tt>alpha</tt></b>)
+</pre></td></tr></table><p>You can set the current color explicitly by calling the
+<tt class="methodname">set_current_color</tt>() method with a
+<tt class="classname">gtk.gdk.Color</tt>. Setting the opacity (alpha channel) is
+done with the <tt class="methodname">set_current_alpha</tt>() method. The
+<i class="parameter"><tt>alpha</tt></i> value should be between 0 (fully transparent)
+and 65636 (fully opaque).</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ color = colorsel.get_current_color()
+ alpha = colorsel.get_current_alpha()
+</pre></td></tr></table><p>When you need to query the current color, typically when you've
+received a "color_changed" signal, you use these methods.</p><p>The <a href="examples/colorsel.py" target="_top"><span><b class="command">colorsel.py</b></span></a> example
+program demonstrates the use of the
+<tt class="classname">ColorSelectionDialog</tt>. The program displays a window
+containing a drawing area. Clicking on it opens a color selection dialog,
+and changing the color in the color selection dialog changes the background
+color.
+<a href="sec-ColorSelection.html#colorselfig" title="Figure 9.13. Color Selection Dialog Example">Figure 9.13, “Color Selection Dialog Exampleâ€</a> illustrates this program in action:</p><div class="figure"><a name="colorselfig"></a><p class="title"><b>Figure 9.13. Color Selection Dialog Example</b></p><div class="mediaobject" align="center"><img src="figures/colorselection.png" align="middle" alt="Color Selection Dialog Example"></div></div><p>The source code for <a href="examples/colorsel.py" target="_top"><span><b class="command">colorsel.py</b></span></a> is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 1 #!/usr/bin/env python
+ 2
+ 3 # example colorsel.py
+ 4
+ 5 import pygtk
+ 6 pygtk.require('2.0')
+ 7 import gtk
+ 8
+ 9 class ColorSelectionExample:
+ 10 # Color changed handler
+ 11 def color_changed_cb(self, widget):
+ 12 # Get drawingarea colormap
+ 13 colormap = self.drawingarea.get_colormap()
+ 14
+ 15 # Get current color
+ 16 color = self.colorseldlg.colorsel.get_current_color()
+ 17
+ 18 # Set window background color
+ 19 self.drawingarea.modify_bg(gtk.STATE_NORMAL, color)
+ 20
+ 21 # Drawingarea event handler
+ 22 def area_event(self, widget, event):
+ 23 handled = False
+ 24
+ 25 # Check if we've received a button pressed event
+ 26 if event.type == gtk.gdk.BUTTON_PRESS:
+ 27 handled = True
+ 28
+ 29 # Create color selection dialog
+ 30 if self.colorseldlg == None:
+ 31 self.colorseldlg = gtk.ColorSelectionDialog(
+ 32 "Select background color")
+ 33
+ 34 # Get the ColorSelection widget
+ 35 colorsel = self.colorseldlg.colorsel
+ 36
+ 37 colorsel.set_previous_color(self.color)
+ 38 colorsel.set_current_color(self.color)
+ 39 colorsel.set_has_palette(True)
+ 40
+ 41 # Connect to the "color_changed" signal
+ 42 colorsel.connect("color_changed", self.color_changed_cb)
+ 43 # Show the dialog
+ 44 response = self.colorseldlg.run()
+ 45
+ 46 if response -- gtk.RESPONSE_OK:
+ 47 self.color = colorsel.get_current_color()
+ 48 else:
+ 49 self.drawingarea.modify_bg(gtk.STATE_NORMAL, self.color)
+ 50
+ 51 self.colorseldlg.hide()
+ 52
+ 53 return handled
+ 54
+ 55 # Close down and exit handler
+ 56 def destroy_window(self, widget, event):
+ 57 gtk.main_quit()
+ 58 return True
+ 59
+ 60 def __init__(self):
+ 61 self.colorseldlg = None
+ 62 # Create toplevel window, set title and policies
+ 63 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ 64 window.set_title("Color selection test")
+ 65 window.set_resizable(True)
+ 66
+ 67 # Attach to the "delete" and "destroy" events so we can exit
+ 68 window.connect("delete_event", self.destroy_window)
+ 69
+ 70 # Create drawingarea, set size and catch button events
+ 71 self.drawingarea = gtk.DrawingArea()
+ 72
+ 73 self.color = self.drawingarea.get_colormap().alloc_color(0, 65535, 0)
+ 74
+ 75 self.drawingarea.set_size_request(200, 200)
+ 76 self.drawingarea.set_events(gtk.gdk.BUTTON_PRESS_MASK)
+ 77 self.drawingarea.connect("event", self.area_event)
+ 78
+ 79 # Add drawingarea to window, then show them both
+ 80 window.add(self.drawingarea)
+ 81 self.drawingarea.show()
+ 82 window.show()
+ 83
+ 84 def main():
+ 85 gtk.main()
+ 86 return 0
+ 87
+ 88 if __name__ == "__main__":
+ 89 ColorSelectionExample()
+ 90 main()
+</pre></td></tr></table></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-Calendar.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-MiscellaneousWidgets.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-FileSelections.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">9.12. Calendar </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 9.14. File Selections</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-ComboBoxAndComboboxEntry.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-ComboBoxAndComboboxEntry.html
new file mode 100644
index 0000000..70a789e
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-ComboBoxAndComboboxEntry.html
@@ -0,0 +1,207 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>16.2. ComboBox and ComboBoxEntry Widgets</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-NewInPyGTK2.4.html" title="Chapter 16. New Widgets in PyGTK 2.4"><link rel="previous" href="ch-NewInPyGTK2.4.html" title="Chapter 16. New Widgets in PyGTK 2.4"><link rel="next" href="sec-ColorButtonAndFontButton.html" title="16.3. ColorButton and FontButton Widgets"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">16.2. ComboBox and ComboBoxEntry Widgets</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch-NewInPyGTK2.4.html">Prev</a> </td><th width="60%" align="center">Chapter 16. New Widgets in PyGTK 2.4</th><td width="20%" align="right"> <a accesskey="n" href="sec-ColorButtonAndFontButton.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-ComboBoxAndComboboxEntry"></a>16.2. ComboBox and ComboBoxEntry Widgets</h2></div></div><div></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-ComboBox"></a>16.2.1. ComboBox Widgets</h3></div></div><div></div></div><p>The <tt class="classname">ComboBox</tt> replaces the
+<tt class="classname">OptionMenu</tt> with a powerful widget that uses a
+<tt class="classname">TreeModel</tt> (usually a
+<tt class="classname">ListStore</tt>) to provide the list items to display. The
+<tt class="classname">ComboBox</tt> implements the
+<tt class="classname">CellLayout</tt> interface that provides a number of
+methods for managing the display of the list items. One or more
+<tt class="classname">CellRenderers</tt> can be packed into a
+<tt class="classname">ComboBox</tt> to customize the list item display.</p><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="sec-BasicComboBox"></a>16.2.1.1. Basic ComboBox Use</h4></div></div><div></div></div><p>The easy way to create and populate a
+<tt class="classname">ComboBox</tt> is to use the convenience function:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ combobox = gtk.combo_box_new_text()
+</pre></td></tr></table><p>This function creates a <tt class="classname">ComboBox</tt> and its
+associated <tt class="classname">ListStore</tt> and packs it with a
+<tt class="classname">CellRendererText</tt>. The following convenience methods
+are used to populate or remove the contents of the
+<tt class="classname">ComboBox</tt> and its
+<tt class="classname">ListStore</tt>:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ combobox.append_text(<b class="parameter"><tt>text</tt></b>)
+ combobox.prepend_text(<b class="parameter"><tt>text</tt></b>)
+ combobox.insert_text(<b class="parameter"><tt>position</tt></b>, <b class="parameter"><tt>text</tt></b>)
+ combobox.remove_text(<b class="parameter"><tt>position</tt></b>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>text</tt></i> is the string to be added to the
+<tt class="classname">ComboBox</tt> and <i class="parameter"><tt>position</tt></i> is the
+index where <i class="parameter"><tt>text</tt></i> is to be inserted or removed. In
+most cases the convenience function and methods are all you need.</p><p>The example program <a href="examples/comboboxbasic.py" target="_top">comboboxbasic.py</a> demonstrates the
+use of the above function and methods. <a href="sec-ComboBoxAndComboboxEntry.html#comboboxbasicfig" title="Figure 16.5. Basic ComboBox">Figure 16.5, “Basic ComboBoxâ€</a> illustrates the program in
+operation:</p><div class="figure"><a name="comboboxbasicfig"></a><p class="title"><b>Figure 16.5. Basic ComboBox</b></p><div class="mediaobject" align="center"><img src="figures/comboboxbasic.png" align="middle" alt="Basic ComboBox"></div></div><p>Unfortunately, the <tt class="literal">GTK</tt>+ developers did not
+provide a convenience method to retrieve the active text. That would seem to
+be a useful method. You'll have to create your own similar to:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def get_active_text(combobox):
+ model = combobox.get_model()
+ active = combobox.get_active()
+ if active &lt; 0:
+ return None
+ return model[active][0]
+</pre></td></tr></table><p>The index of the active item is retrieved using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ active = combobox.get_active()
+</pre></td></tr></table><p>The active item can be set using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ combobox.set_active(<b class="parameter"><tt>index</tt></b>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>index</tt></i> is an integer larger than
+-2. If <i class="parameter"><tt>index</tt></i> is -1 there is no active item and the
+ComboBox display will be blank. If <i class="parameter"><tt>index</tt></i> is less than
+-1, the call will be ignored. If <i class="parameter"><tt>index</tt></i> is greater
+than -1 the list item with that index value will be displayed.</p><p>You can connect to the "changed" signal of a
+<tt class="classname">ComboBox</tt> to be notified when the active item has been
+changed. The signature of the "changed" handler is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def changed_cb(combobox, ...):
+</pre></td></tr></table><p>where <i class="parameter"><tt>...</tt></i> represents the zero or more
+arguments passed to the <tt class="methodname">GObject.connect</tt>()
+method.</p></div><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="sec-AdvancedComboBox"></a>16.2.1.2. Advanced ComboBox Use</h4></div></div><div></div></div><p>Creating a <tt class="classname">ComboBox</tt> using the
+<tt class="function">gtk.combo_box_new_text</tt>() function is roughly
+equivalent to the following code:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ liststore = gtk.ListStore(str)
+ combobox = gtk.ComboBox(liststore)
+ cell = gtk.CellRendererText()
+ combobox.pack_start(cell, True)
+ combobox.add_attribute(cell, 'text', 0)
+</pre></td></tr></table><p>To make use of the power of the various
+<tt class="classname">TreeModel</tt> and <tt class="classname">CellRenderer</tt>
+objects you need to construct a <tt class="classname">ComboBox</tt> using the
+constructor:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ combobox = gtk.ComboBox(<b class="parameter"><tt>model</tt></b>=None)
+</pre></td></tr></table><p>where <i class="parameter"><tt>model</tt></i> is a
+<tt class="classname">TreeModel</tt>. If you create a
+<tt class="classname">ComboBox</tt> without associating a
+<tt class="classname">TreeModel</tt>, you can add one later using the
+method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ combobox.set_model(<b class="parameter"><tt>model</tt></b>)
+</pre></td></tr></table><p>The associated <tt class="classname">TreeModel</tt> can be retrieved
+using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ model = combobox.get_model()
+</pre></td></tr></table><p>Some of the things you can do with a
+<tt class="classname">ComboBox</tt> are:</p><div class="itemizedlist"><ul type="disc"><li>Share the same <tt class="classname">TreeModel</tt> with
+other <tt class="classname">ComboBox</tt>es and
+<tt class="classname">TreeView</tt>s.</li><li>Display images and text in the
+<tt class="classname">ComboBox</tt> list items.</li><li>Use an existing <tt class="classname">TreeStore</tt> or
+<tt class="classname">ListStore</tt> as the model for the
+<tt class="classname">ComboBox</tt> list items.</li><li>Use a <tt class="classname">TreeModelSort</tt> to provide a
+sorted <tt class="classname">ComboBox</tt> list.</li><li>Use a <tt class="classname">TreeModelFilter</tt> to use a
+subtree of a <tt class="classname">TreeStore</tt> as the source for a
+<tt class="classname">ComboBox</tt> list items.</li><li>Use a <tt class="classname">TreeModelFilter</tt> to use a
+subset of the rows in a <tt class="classname">TreeStore</tt> or
+<tt class="classname">ListStore</tt> as the <tt class="classname">ComboBox</tt> list
+items.</li><li>Use a cell data function to modify or synthesize the
+display for list items.</li></ul></div><p>The use of the <tt class="classname">TreeModel</tt> and
+<tt class="classname">CellRenderer</tt> objects is detailed in <a href="ch-TreeViewWidget.html" title="Chapter 14. Tree View Widget">Chapter 14, <i>Tree View Widget</i></a>.</p><p>The <tt class="classname">ComboBox</tt> list items can be displayed
+in a grid if you have a large number of items to display. Otherwise the list
+will have scroll arrows if the entire list cannot be displayed. The
+following method is used to set the number of columns to display:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ combobox.set_wrap_width(<b class="parameter"><tt>width</tt></b>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>width</tt></i> is the number of columns of
+the grid displaying the list items. For example, the <a href="examples/comboboxwrap.py" target="_top">comboboxwrap.py</a> program displays a
+list of 50 items in 5 columns. <a href="sec-ComboBoxAndComboboxEntry.html#comboboxwrapfig" title="Figure 16.6. ComboBox with Wrapped Layout">Figure 16.6, “ComboBox with Wrapped Layoutâ€</a>
+illustrates the program in operation:</p><div class="figure"><a name="comboboxwrapfig"></a><p class="title"><b>Figure 16.6. ComboBox with Wrapped Layout</b></p><div class="mediaobject" align="center"><img src="figures/comboboxwrap.png" align="middle" alt="ComboBox with Wrapped Layout"></div></div><p>With a large number of items, say more than 50, the use of the
+<tt class="methodname">set_wrap_width</tt>() method will have poor performance
+because of the computation for the grid layout. To get a feel for the affect
+modify the <a href="examples/comboboxwrap.py" target="_top">comboboxwrap.py</a>
+program line 18 to display 150 items.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ for n in range(150):
+</pre></td></tr></table><p>Run the program and get a time estimate for startup. Then modify
+ it by commenting out line 17:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ #combobox.set_wrap_width(5)
+</pre></td></tr></table><p>Run and time it again. It should start up significantly
+faster. My experience is about 20 times faster.</p><p>In addition to the <tt class="methodname">get_active</tt>() method
+described above, you can retrieve a <tt class="classname">TreeIter</tt> pointing
+at the active row by using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ iter = combobox.get_active_iter()
+</pre></td></tr></table><p>You can also set the active list item using a
+<tt class="classname">TreeIter</tt> with the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ combobox.set_active_iter(<b class="parameter"><tt>iter</tt></b>)
+</pre></td></tr></table><p>The <tt class="methodname">set_row_span_column</tt>() and
+<tt class="methodname">set_column_span_column</tt>() methods are supposed to
+allow the specification of a <tt class="classname">TreeModel</tt> column number
+that contains the number of rows or columns that the list item is supposed
+to span in a grid layout. Unfortunately, in GTK+ 2.4 these methods are
+broken.</p><p>Since the <tt class="classname">ComboBox</tt> implements the
+<tt class="classname">CellLayout</tt> interface which has similar capabilities
+as the <tt class="classname">TreeViewColumn</tt> (see <a href="sec-TreeViewColumns.html" title="14.5. TreeViewColumns">Section 14.5, “TreeViewColumnsâ€</a> for more information). Briefly, the
+interface provides:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ combobox.pack_start(<b class="parameter"><tt>cell</tt></b>, <b class="parameter"><tt>expand</tt></b>=True)
+ combobox.pack_end(<b class="parameter"><tt>cell</tt></b>, <b class="parameter"><tt>expand</tt></b>=True)
+ combobox.clear()
+</pre></td></tr></table><p>The first two methods pack a <tt class="classname">CellRenderer</tt>
+into the <tt class="classname">ComboBox</tt> and the
+<tt class="methodname">clear</tt>() method clears all attributes from all
+<tt class="classname">CellRenderer</tt>s.</p><p>The following methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ comboboxentry.add_attribute(<b class="parameter"><tt>cell</tt></b>, <b class="parameter"><tt>attribute</tt></b>, <b class="parameter"><tt>column</tt></b>)
+
+ comboboxentry.set_attributes(<i class="parameter"><tt>cell</tt></i>, <i class="parameter"><tt>...</tt></i>)
+</pre></td></tr></table><p>set attributes for the <tt class="classname">CellRenderer</tt>
+specified by <i class="parameter"><tt>cell</tt></i>. The
+<tt class="methodname">add_attribute</tt>() method takes a string
+<i class="parameter"><tt>attribute</tt></i> name (e.g. 'text') and an integer
+<i class="parameter"><tt>column</tt></i> number of the column in the
+<tt class="classname">TreeModel</tt> to use to set
+<i class="parameter"><tt>attribute</tt></i>. The additional arguments to the
+<tt class="methodname">set_attributes</tt>() method are
+<tt class="literal">attribute=column</tt> pairs (e.g text=1).</p></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-ComboBoxEntry"></a>16.2.2. ComboBoxEntry Widgets</h3></div></div><div></div></div><p>The <tt class="classname">ComboBoxEntry</tt> widget replaces the
+<tt class="classname">Combo</tt> widget. It is subclassed from the
+<tt class="classname">ComboBox</tt> widget and contains a child
+<tt class="classname">Entry</tt> widget that has its contents set by selecting
+an item in the dropdown list or by direct text entry either from the
+keyboard or by pasting from a <tt class="classname">Clipboard</tt> or a
+selection.</p><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="sec-BasicComboBoxEntry"></a>16.2.2.1. Basic ComboBoxEntry Use</h4></div></div><div></div></div><p>Like the <tt class="classname">ComboBox</tt>, the
+<tt class="classname">ComboBoxEntry</tt> can be created using the convenience
+function:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ comboboxentry = gtk.combo_box_entry_new_text()
+</pre></td></tr></table><p>The <tt class="classname">ComboBoxEntry</tt> should be populated
+using the <tt class="classname">ComboBox</tt> convenience methods described in
+<a href="sec-ComboBoxAndComboboxEntry.html#sec-BasicComboBox" title="16.2.1.1. Basic ComboBox Use">Section 16.2.1.1, “Basic ComboBox Useâ€</a>.</p><p>Since a <tt class="classname">ComboBoxEntry</tt> widget is a
+<tt class="classname">Bin</tt> widget its child <tt class="classname">Entry</tt>
+widget is available using the "child" attribute or the
+<tt class="methodname">get_child</tt>() method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ entry = comboboxentry.child
+ entry = comboboxentry.get_child()
+</pre></td></tr></table><p>You can retrieve the <tt class="classname">Entry</tt> text using its
+<tt class="methodname">get_text</tt>() method.</p><p>Like the <tt class="classname">ComboBox</tt>, you can track changes
+in the active list item by connecting to the "changed"
+signal. Unfortunately, this doesn't help track changes to the text in the
+<tt class="classname">Entry</tt> child that are direct entry. When a direct
+entry is made to the child <tt class="classname">Entry</tt> widget the "changed"
+signal will be emitted but the index returned by the
+<tt class="methodname">get_active</tt>() method will be -1. To track all
+changes to the <tt class="classname">Entry</tt> text, you'll have to use the
+<tt class="classname">Entry</tt> "changed" signal. For example:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def changed_cb(entry):
+ print entry.get_text()
+
+ comboboxentry.child.connect('changed', changed_cb)
+</pre></td></tr></table><p>will print out the text after every change in the child
+<tt class="classname">Entry</tt> widget. For example, the <a href="examples/comboboxentrybasic.py" target="_top">comboboxentrybasic.py</a> program
+demonstrates the use of the convenience API. <a href="sec-ComboBoxAndComboboxEntry.html#comboboxentrybasicfig" title="Figure 16.7. Basic ComboBoxEntry">Figure 16.7, “Basic ComboBoxEntryâ€</a> illustrates the program in
+operation:</p><div class="figure"><a name="comboboxentrybasicfig"></a><p class="title"><b>Figure 16.7. Basic ComboBoxEntry</b></p><div class="mediaobject" align="center"><img src="figures/comboboxentrybasic.png" align="middle" alt="Basic ComboBoxEntry"></div></div><p>Note that when the <tt class="classname">Entry</tt> text is changed
+due to the selection of a dropdown list item the "changed" handler is called
+twice: once when the text is cleared; and, once when the text is set with
+the selected list item text.</p></div><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="sec=AdvancedComboBoxEntry"></a>16.2.2.2. Advanced ComboBoxEntry Use</h4></div></div><div></div></div><p>The constructor for a ComboBoxEntry is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ comboboxentry = gtk.ComboBoxEntry(<b class="parameter"><tt>model</tt></b>=None, <b class="parameter"><tt>column</tt></b>=-1)
+</pre></td></tr></table><p>where <i class="parameter"><tt>model</tt></i> is a
+<tt class="classname">TreeModel</tt> and <i class="parameter"><tt>column</tt></i> is the
+number of the column in <i class="parameter"><tt>model</tt></i> to use for setting the
+list items. If column is not specified the default value is -1 which means
+the text column is unset.</p><p>Creating a <tt class="classname">ComboBoxEntry</tt> using the
+convenience function <tt class="function">gtk.combo_box_entry_new_text</tt>() is
+equivalent to the following:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ liststore = gtk.ListStore(str)
+ comboboxentry = gtk.ComboBoxEntry(liststore, 0)
+</pre></td></tr></table><p>The <tt class="classname">ComboBoxEntry</tt> adds a couple of
+methods that are used to set and retrieve the
+<tt class="classname">TreeModel</tt> column number to use for setting the list
+item strings:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ comboboxentry.set_text_column(<b class="parameter"><tt>text_column</tt></b>)
+ text_column = comboboxentry.get_text_column()
+</pre></td></tr></table><p>The text column can also be retrieved and set using the
+"text-column" property. See <a href="sec-ComboBoxAndComboboxEntry.html#sec-AdvancedComboBox" title="16.2.1.2. Advanced ComboBox Use">Section 16.2.1.2, “Advanced ComboBox Useâ€</a> for
+more information on the advanced use of the
+<tt class="classname">ComboBoxEntry</tt>.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>Your application must set the text column for the
+<tt class="classname">ComboBoxEntry</tt> to set the <tt class="classname">Entry</tt>
+contents from the dropdown list. The text column can only be set once,
+either by using the constructor or by using the
+<tt class="methodname">set_text_column</tt>() method.</p></div><p>When a <tt class="classname">ComboBoxEntry</tt> is created it is
+packed with a new <tt class="classname">CellRendererText</tt> which is not
+accessible. The 'text' attribute for the
+<tt class="classname">CellRendererText</tt> has to be set as a side effect of
+setting the text column using the <tt class="methodname">set_text_column</tt>()
+method. You can pack additional <tt class="classname">CellRenderer</tt>s into a
+<tt class="classname">ComboBoxEntry</tt> for display in the dropdown list. See
+<a href="sec-ComboBoxAndComboboxEntry.html#sec-AdvancedComboBox" title="16.2.1.2. Advanced ComboBox Use">Section 16.2.1.2, “Advanced ComboBox Useâ€</a> for more information.</p></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch-NewInPyGTK2.4.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-NewInPyGTK2.4.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-ColorButtonAndFontButton.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 16. New Widgets in PyGTK 2.4 </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 16.3. ColorButton and FontButton Widgets</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-ComboWidget.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-ComboWidget.html
new file mode 100644
index 0000000..d8e8ee6
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-ComboWidget.html
@@ -0,0 +1,80 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>9.11. Combo Widget</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-MiscellaneousWidgets.html" title="Chapter 9. Miscellaneous Widgets"><link rel="previous" href="sec-SpinButtons.html" title="9.10. Spin Buttons"><link rel="next" href="sec-Calendar.html" title="9.12. Calendar"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">9.11. Combo Widget</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-SpinButtons.html">Prev</a> </td><th width="60%" align="center">Chapter 9. Miscellaneous Widgets</th><td width="20%" align="right"> <a accesskey="n" href="sec-Calendar.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-ComboWidget"></a>9.11. Combo Widget</h2></div></div><div></div></div><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>The <tt class="classname">Combo</tt> widget is deprecated in PyGTK
+2.4 and above.</p></div><p>The <tt class="classname">Combo</tt> widget is another fairly simple
+widget that is really just a collection of other widgets. From the user's
+point of view, the widget consists of a text entry box and a pull down menu
+from which the user can select one of a set of predefined
+entries. Alternatively, the user can type a different option directly into
+the text box.</p><p>The <tt class="classname">Combo</tt> has two principal parts that
+you really care about: an <i class="parameter"><tt>entry</tt></i> and a
+<i class="parameter"><tt>list</tt></i>. These are accessed using the attributes:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ combo.entry
+
+ combo.list
+</pre></td></tr></table><p>First off, to create a <tt class="classname">Combo</tt>, use:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ combo = gtk.Combo()
+</pre></td></tr></table><p>Now, if you want to set the string in the entry section of the
+combo, this is done by manipulating the entry widget directly:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ combo.entry.set_text(<b class="parameter"><tt>text</tt></b>)
+</pre></td></tr></table><p>To set the values in the popdown <i class="parameter"><tt>list</tt></i>,
+one uses the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ combo.set_popdown_strings(<b class="parameter"><tt>strings</tt></b>)
+</pre></td></tr></table><p>Before you can do this, you have to assemble a list of the
+strings that you want.</p><p>Here's a typical code segment for creating a set of
+options:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ slist = [ "String 1", "String 2", "String 3", "String 4" ]
+
+ combo.set_popdown_strings(slist)
+</pre></td></tr></table><p>At this point you have set up a working
+<tt class="classname">Combo</tt>. There are a few aspects of its behavior that
+you can change. These are accomplished with the methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ combo.set_use_arrows(<b class="parameter"><tt>val</tt></b>)
+
+ combo.set_use_arrows_always(<b class="parameter"><tt>val</tt></b>)
+
+ combo.set_case_sensitive(<b class="parameter"><tt>val</tt></b>)
+</pre></td></tr></table><p>The <tt class="methodname">set_use_arrows</tt>() method lets the
+user change the value in the entry using the up/down arrow keys when
+<i class="parameter"><tt>val</tt></i> is set to <tt class="literal">TRUE</tt>. This doesn't
+bring up the list, but rather replaces the current text in the entry with
+the next list entry (up or down, as your key choice indicates). It does this
+by searching in the list for the item corresponding to the current value in
+the <i class="parameter"><tt>entry</tt></i> and selecting the previous/next item
+accordingly. Usually in an <i class="parameter"><tt>entry</tt></i> the arrow keys are
+used to change focus (you can do that anyway using
+<span><b class="keycap">Tab</b></span>). Note that when the current item is the last of the
+list and you press arrow-down it changes the focus (the same applies with
+the first item and arrow-up).</p><p>If the current value in the <i class="parameter"><tt>entry</tt></i> is not
+in the list, then the <tt class="methodname">set_use_arrows</tt>() method is
+disabled.</p><p>The <tt class="methodname">set_use_arrows_always</tt>() method,
+when <i class="parameter"><tt>val</tt></i> is <tt class="literal">TRUE</tt>, similarly allows
+the use of the up/down arrow keys to cycle through the choices in the
+dropdown list, except that it wraps around the values in the list,
+completely disabling the use of the up and down arrow keys for changing
+focus.</p><p>The <tt class="methodname">set_case_sensitive</tt>() method toggles
+whether or not GTK+ searches for entries in a case sensitive manner. This is
+used when the <tt class="classname">Combo</tt> widget is asked to find a value
+from the list using the current entry in the text box. This completion can
+be performed in either a case sensitive or insensitive manner, depending
+upon the setting of this method. The <tt class="classname">Combo</tt> widget can
+also simply complete the current entry if the user presses the key
+combination <span class="keysym">MOD-1</span>-<span><b class="keycap">Tab</b></span>. <span class="keysym">MOD-1</span> is often mapped to
+the <span><b class="keycap">Alt</b></span> key, by the <span><b class="command">xmodmap</b></span>
+utility. Note, however that some window managers also use this key
+combination, which will override its use within GTK.</p><p>Now that we have a combo, tailored to look and act how we want
+it, all that remains is being able to get data from the combo. This is
+relatively straightforward. The majority of the time, all you are going to
+care about getting data from is the entry. The entry is accessed simply as
+<i class="parameter"><tt>combo.entry</tt></i>. The two principal things that you are
+going to want to do with it are attach to the "activate" signal, which
+indicates that the user has pressed the <span><b class="keycap">Return</b></span> or
+<span><b class="keycap">Enter</b></span> key, and read the text. The first is accomplished
+using something like:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ combo.entry.connect("activate", my_callback, my_data)
+</pre></td></tr></table><p>Getting the text at any arbitrary time is accomplished by simply
+using the entry method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ string = combo.entry.get_text()
+</pre></td></tr></table><p>That's about all there is to it. There is a method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ combo.disable_activate()
+</pre></td></tr></table><p>that will disable the activate signal on the entry widget in the
+combo. Personally, I can't think of why you'd want to use it, but it does
+exist.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-SpinButtons.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-MiscellaneousWidgets.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-Calendar.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">9.10. Spin Buttons </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 9.12. Calendar</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-CommonRangeMethods.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-CommonRangeMethods.html
new file mode 100644
index 0000000..2e21799
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-CommonRangeMethods.html
@@ -0,0 +1,35 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>8.3. Common Range Methods</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-RangeWidgets.html" title="Chapter 8. Range Widgets"><link rel="previous" href="sec-ScaleWidgets.html" title="8.2. Scale Widgets"><link rel="next" href="sec-KeyAndMouseBindings.html" title="8.4. Key and Mouse Bindings"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">8.3. Common Range Methods</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-ScaleWidgets.html">Prev</a> </td><th width="60%" align="center">Chapter 8. Range Widgets</th><td width="20%" align="right"> <a accesskey="n" href="sec-KeyAndMouseBindings.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-CommonRangeMethods"></a>8.3. Common Range Methods</h2></div></div><div></div></div><p>The <tt class="classname">Range</tt> widget class is fairly
+complicated internally, but, like all the "base class" widgets, most of its
+complexity is only interesting if you want to hack on it. Also, almost all
+of the methods and signals it defines are only really used in writing
+derived widgets. There are, however, a few useful methods that will work on
+all range widgets.</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2785803"></a>8.3.1. Setting the Update Policy</h3></div></div><div></div></div><p>The "update policy" of a range widget defines at what points
+during user interaction it will change the value field of its
+<tt class="classname">Adjustment</tt> and emit the "value_changed" signal on
+this <tt class="classname">Adjustment</tt>. The update policies are:</p><table border="0" width="100%" bgcolor="#FFECCE"><col align="left" valign="top" width="0*"><tbody><tr><td><span class="term"> UPDATE_CONTINUOUS</span></td><td><p>This is the default. The "value_changed" signal is
+emitted continuously, i.e., whenever the slider is moved by even the tiniest
+amount.</p></td></tr><tr><td><span class="term">UPDATE_DISCONTINUOUS</span></td><td><p>The "value_changed" signal is only emitted once the
+slider has stopped moving and the user has released the mouse button.</p></td></tr><tr><td><span class="term">UPDATE_DELAYED</span></td><td><p>The "value_changed" signal is emitted when the user
+releases the mouse button, or if the slider stops moving for a short period
+of time.</p></td></tr></tbody></table><p>The update policy of a range widget can be set by passing it
+to this method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ range.set_update_policy(<b class="parameter"><tt>policy</tt></b>)
+</pre></td></tr></table></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2785875"></a>8.3.2. Getting and Setting Adjustments</h3></div></div><div></div></div><p>Getting and setting the adjustment for a range widget "on the
+fly" is done, predictably, with:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ adjustment = range.get_adjustment()
+
+ range.set_adjustment(<b class="parameter"><tt>adjustment</tt></b>)
+</pre></td></tr></table><p>The <tt class="methodname">get_adjustment</tt>() method returns a
+reference to the <i class="parameter"><tt>adjustment</tt></i> to which range is
+connected.</p><p>The <tt class="methodname">set_adjustment</tt>() method does
+absolutely nothing if you pass it the <i class="parameter"><tt>adjustment</tt></i> that
+<i class="parameter"><tt>range</tt></i> is already using, regardless of whether you
+changed any of its fields or not. If you pass it a new
+<tt class="classname">Adjustment</tt>, it will unreference the old one if it
+exists (possibly destroying it), connect the appropriate signals to the new
+one, and will recalculate the size and/or position of the slider and redraw
+if necessary. As mentioned in the section on adjustments, if you wish to
+reuse the same <tt class="classname">Adjustment</tt>, when you modify its values
+directly, you should emit the "changed" signal on it, like this:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ adjustment.emit("changed")
+</pre></td></tr></table></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-ScaleWidgets.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-RangeWidgets.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-KeyAndMouseBindings.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">8.2. Scale Widgets </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 8.4. Key and Mouse Bindings</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-Curves.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-Curves.html
new file mode 100644
index 0000000..69bf034
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-Curves.html
@@ -0,0 +1 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>17.4. Curves</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-UndocumentedWidgets.html" title="Chapter 17. Undocumented Widgets"><link rel="previous" href="sec-MenuItems.html" title="17.3. Menu Items"><link rel="next" href="sec-MessageDialog.html" title="17.5. Message Dialog"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">17.4. Curves</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-MenuItems.html">Prev</a> </td><th width="60%" align="center">Chapter 17. Undocumented Widgets</th><td width="20%" align="right"> <a accesskey="n" href="sec-MessageDialog.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-Curves"></a>17.4. Curves</h2></div></div><div></div></div><p></p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-MenuItems.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-UndocumentedWidgets.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-MessageDialog.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">17.3. Menu Items </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 17.5. Message Dialog</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-DNDMethods.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-DNDMethods.html
new file mode 100644
index 0000000..8355914
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-DNDMethods.html
@@ -0,0 +1,254 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>22.3. DND Methods</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-DragAndDrop.html" title="Chapter 22. Drag-and-drop (DND)"><link rel="previous" href="sec-DNDProperties.html" title="22.2. DND Properties"><link rel="next" href="ch-GtkRcFiles.html" title="Chapter 23. GTK's rc Files"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">22.3. DND Methods</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-DNDProperties.html">Prev</a> </td><th width="60%" align="center">Chapter 22. Drag-and-drop (DND)</th><td width="20%" align="right"> <a accesskey="n" href="ch-GtkRcFiles.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-DNDMethods"></a>22.3. DND Methods</h2></div></div><div></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2793141"></a>22.3.1. Setting Up the Source Widget</h3></div></div><div></div></div><p>The method <tt class="methodname">drag_source_set</tt>() specifies
+a set of target types for a drag operation on a widget.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ widget.drag_source_set(<b class="parameter"><tt>start_button_mask</tt></b>, <b class="parameter"><tt>targets</tt></b>, <b class="parameter"><tt>actions</tt></b>)
+</pre></td></tr></table><p>The parameters signify the following:</p><div class="itemizedlist"><ul type="disc"><li><p><i class="parameter"><tt>widget</tt></i> specifies the drag source
+widget</p></li><li><p><i class="parameter"><tt>start_button_mask</tt></i> specifies a bitmask
+of buttons that can start the drag (e.g.
+<tt class="literal">BUTTON1_MASK</tt>)</p></li><li><p><i class="parameter"><tt>targets</tt></i> specifies a list of target data
+types the drag will support</p></li><li><p><i class="parameter"><tt>actions</tt></i> specifies a bitmask of possible
+actions for a drag from this window</p></li></ul></div><p>The <i class="parameter"><tt>targets</tt></i> parameter is a list of tuples
+each similar to:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ (target, flags, info)
+</pre></td></tr></table><p><i class="parameter"><tt>target</tt></i> specifies a string representing the
+drag type.</p><p><i class="parameter"><tt>flags</tt></i> restrict the drag scope.
+<i class="parameter"><tt>flags</tt></i> can be set to 0 (no limitation of scope) or the
+following flags:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ gtk.TARGET_SAME_APP # Target will only be selected for drags within a single application.
+
+ gtk.TARGET_SAME_WIDGET # Target will only be selected for drags within a single widget.
+</pre></td></tr></table><p><i class="parameter"><tt>info</tt></i> is an application assigned integer
+identifier.</p><p>If a widget is no longer required to act as a source for
+drag-and-drop operations, the method
+<tt class="methodname">drag_source_unset</tt>() can be used to remove a set of
+drag-and-drop target types.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ widget.drag_source_unset()
+</pre></td></tr></table></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-SignalsOnSourceWidget"></a>22.3.2. Signals On the Source Widget</h3></div></div><div></div></div><p>The source widget is sent the following signals during a
+drag-and-drop operation.</p><div class="table"><a name="id2878807"></a><p class="title"><b>Table 22.1. Source Widget Signals</b></p><table summary="Source Widget Signals" width="100%" border="1"><colgroup><col><col></colgroup><tbody><tr><td>drag_begin</td><td>def drag_begin_cb(widget, drag_context, data):</td></tr><tr><td>drag_data_get</td><td>def drag_data_get_cb(widget, drag_context, selection_data, info, time, data):</td></tr><tr><td>drag_data_delete</td><td>def drag_data_delete_cb(widget, drag_context, data):</td></tr><tr><td>drag_end</td><td>def drag_end_cb(widget, drag_context, data):</td></tr></tbody></table></div><p>The "drag-begin" signal handler can be used to set up some
+inital conditions such as a drag icon using one of the
+<tt class="classname">Widget</tt> methods:
+<tt class="methodname">drag_source_set_icon</tt>(),
+<tt class="methodname">drag_source_set_icon_pixbuf</tt>(),
+<tt class="methodname">drag_source_set_icon_stock</tt>(). The "drag-end' signal
+handler can be used to undo the actions of the "drag-begin" signal
+ahndler.</p><p>The "drag-data-get" signal handler should return the drag data
+matching the target specified by <i class="parameter"><tt>info</tt></i>. It fills in
+the <tt class="classname">gtk.gdk.SelectionData</tt> with the drag data.</p><p>The "drag-delete" signal handler is used to delete the drag data
+for a <tt class="literal">gtk.gdk.ACTION_MOVE</tt> action after the data has been
+copied.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-SettingUpDestinationWidget"></a>22.3.3. Setting Up a Destination Widget</h3></div></div><div></div></div><p>The <tt class="methodname">drag_dest_set</tt>() method specifies
+that this widget can receive drops and specifies what types of drops it can
+receive.</p><p><tt class="methodname">drag_dest_unset</tt>() specifies that the
+widget can no longer receive drops.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ widget.drag_dest_set(<b class="parameter"><tt>flags</tt></b>, <b class="parameter"><tt>targets</tt></b>, <b class="parameter"><tt>actions</tt></b>)
+
+ widget.drag_dest_unset()
+</pre></td></tr></table><p><i class="parameter"><tt>flags</tt></i> specifies what actions GTK+ should
+take on behalf of widget for drops on it. The possible values of
+<i class="parameter"><tt>flags</tt></i> are:</p><table border="0" width="100%" bgcolor="#FFECCE"><col align="left" valign="top" width="0*"><tbody><tr><td><span class="term"><tt class="literal">gtk.DEST_DEFAULT_MOTION</tt></span></td><td><p>If set for a widget, GTK+, during a drag over this widget
+will check if the drag matches this widget's list of possible targets and
+actions. GTK+ will then call <tt class="methodname">drag_status</tt>() as
+appropriate.</p></td></tr><tr><td><span class="term"><tt class="literal">gtk.DEST_DEFAULT_HIGHLIGHT</tt></span></td><td><p>If set for a widget, GTK+ will draw a highlight on this
+widget as long as a drag is over this widget and the widget drag format and
+action is acceptable.</p></td></tr><tr><td><span class="term"><tt class="literal">gtk.DEST_DEFAULT_DROP</tt></span></td><td><p>If set for a widget, when a drop occurs, GTK+ will check
+if the drag matches this widget's list of possible targets and actions. If
+so, GTK+ will call <tt class="methodname">drag_get_data</tt>() on behalf of the
+widget. Whether or not the drop is succesful, GTK+ will call
+<tt class="methodname">drag_finish</tt>(). If the action was a move and the
+drag was succesful, then <tt class="literal">TRUE</tt> will be passed for the
+<i class="parameter"><tt>delete</tt></i> parameter to
+<tt class="methodname">drag_finish</tt>().</p></td></tr><tr><td><span class="term"><tt class="literal">gtk.DEST_DEFAULT_ALL</tt></span></td><td><p>If set, specifies that all default actions should be
+taken.</p></td></tr></tbody></table><p><i class="parameter"><tt>targets</tt></i> is a list of target information
+tuples as described above.</p><p><i class="parameter"><tt>actions</tt></i> is a bitmask of possible actions
+for a drag onto this widget. The possible values that can be or'd for
+actions are:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ gtk.gdk.ACTION_DEFAULT
+ gtk.gdk.ACTION_COPY
+ gtk.gdk.ACTION_MOVE
+ gtk.gdk.ACTION_LINK
+ gtk.gdk.ACTION_PRIVATE
+ gtk.gdk.ACTION_ASK
+</pre></td></tr></table><p><i class="parameter"><tt>targets</tt></i> and
+<i class="parameter"><tt>actions</tt></i> are ignored if <i class="parameter"><tt>flags</tt></i>
+does not contain <tt class="literal">gtk.DEST_DEFAULT_MOTION</tt> or
+<tt class="literal">gtk.DEST_DEFAULT_DROP</tt>. In that case the application must
+handle the "drag-motion" and "drag-drop" signals.</p><p>The "drag-motion" handler must determine if the drag data is
+appropriate by matching the destination targets with the
+<tt class="classname">gtk.gdk.DragContext</tt>
+targets and optionally by examining the drag data by calling the
+<tt class="methodname">drag_get_data</tt>() method. The
+<tt class="classname">gtk.gdk.DragContext</tt>.
+<tt class="methodname">drag_status</tt>() method must be called to update the
+<i class="parameter"><tt>drag_context</tt></i> status.</p><p>The "drag-drop" handler must determine the matching target using
+the Widget <tt class="methodname">drag_dest_find_target</tt>() method and then
+ask for the drag data using the Widget
+<tt class="methodname">drag_get_data</tt>() method. The data will be available
+in the "drag-data-received" handler.</p><p>The <a href="examples/dragtargets.py" target="_top"><tt class="filename">dragtargets.py</tt></a>
+program prints out the targets of a drag operation in a label:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 1 #!/usr/local/env python
+ 2
+ 3 import pygtk
+ 4 pygtk.require('2.0')
+ 5 import gtk
+ 6
+ 7 def motion_cb(wid, context, x, y, time):
+ 8 context.drag_status(gtk.gdk.ACTION_COPY, time)
+ 9 return True
+ 10
+ 11 def drop_cb(wid, context, x, y, time):
+ 12 l.set_text('\n'.join([str(t) for t in context.targets]))
+ 13 context.finish(True, False, time)
+ 14 return True
+ 15
+ 16 w = gtk.Window()
+ 17 w.set_size_request(200, 150)
+ 18 w.drag_dest_set(0, [], 0)
+ 19 w.connect('drag_motion', motion_cb)
+ 20 w.connect('drag_drop', drop_cb)
+ 21 w.connect('destroy', lambda w: gtk.main_quit())
+ 22 l = gtk.Label()
+ 23 w.add(l)
+ 24 w.show_all()
+ 25
+ 26 gtk.main()
+</pre></td></tr></table><p>The program creates a window and then sets it as a drag
+destination for no targets and actions by setting the flags to zero. The
+<tt class="function">motion_cb</tt>() and <tt class="function">drop_cb</tt>() handlers
+are connected to the "drag-motion" and "drag-drop" signals respectively. The
+<tt class="function">motion_cb</tt>() handler just sets the drag status for the
+drag context so that a drop will be enabled. The
+<tt class="function">drop_cb</tt>() sets the label text to a string containing
+the drag targets and finishes the drop leaving the source data intact.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-SignalsOnDestinationWidget"></a>22.3.4. Signals On the Destination Widget</h3></div></div><div></div></div><p>The destination widget is sent the following signals during a
+drag-and-drop operation.</p><div class="table"><a name="id2873419"></a><p class="title"><b>Table 22.2. Destination Widget Signals</b></p><table summary="Destination Widget Signals" width="100%" border="1"><colgroup><col><col></colgroup><tbody><tr><td>drag_motion</td><td>def drag_motion_cb(widget, drag_context, x, y, time, data):</td></tr><tr><td>drag_drop</td><td>def drag_drop_cb(widget, drag_context, x, y, time, data):</td></tr><tr><td>drag_data_received</td><td>def drag_data_received_cb(widget, drag_context,
+x, y, selection_data, info, time, data):</td></tr></tbody></table></div><p>The <a href="examples/dragndrop.py" target="_top"><span><b class="command">dragndrop.py</b></span></a> example
+program demonstrates the use of drag and drop in one application. A button
+with a xpm pixmap (in <a href="examples/gtkxpm.py" target="_top"><tt class="filename">gtkxpm.py</tt></a>) is the
+source for the drag; it provides both text and xpm data. A layout widget is
+the destination for the xpm drop while a button is the destination for the
+text drop. <a href="sec-DNDMethods.html#dragndropfig" title="Figure 22.1. Drag and Drop Example">Figure 22.1, “Drag and Drop Exampleâ€</a> illustrates the program display
+after an xpm drop has been made on the layout and a text drop has been made
+on the button:</p><div class="figure"><a name="dragndropfig"></a><p class="title"><b>Figure 22.1. Drag and Drop Example</b></p><div class="mediaobject" align="center"><img src="figures/dragndrop.png" align="middle" alt="Drag and Drop Example"></div></div><p>The <a href="examples/dragndrop.py" target="_top"><span><b class="command">dragndrop.py</b></span></a> source
+code is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 1 #!/usr/bin/env python
+ 2
+ 3 # example dragndrop.py
+ 4
+ 5 import pygtk
+ 6 pygtk.require('2.0')
+ 7 import gtk
+ 8 import string, time
+ 9
+ 10 import gtkxpm
+ 11
+ 12 class DragNDropExample:
+ 13 HEIGHT = 600
+ 14 WIDTH = 600
+ 15 TARGET_TYPE_TEXT = 80
+ 16 TARGET_TYPE_PIXMAP = 81
+ 17 fromImage = [ ( "text/plain", 0, TARGET_TYPE_TEXT ),
+ 18 ( "image/x-xpixmap", 0, TARGET_TYPE_PIXMAP ) ]
+ 19 toButton = [ ( "text/plain", 0, TARGET_TYPE_TEXT ) ]
+ 20 toCanvas = [ ( "image/x-xpixmap", 0, TARGET_TYPE_PIXMAP ) ]
+ 21
+ 22 def layout_resize(self, widget, event):
+ 23 x, y, width, height = widget.get_allocation()
+ 24 if width &gt; self.lwidth or height &gt; self.lheight:
+ 25 self.lwidth = max(width, self.lwidth)
+ 26 self.lheight = max(height, self.lheight)
+ 27 widget.set_size(self.lwidth, self.lheight)
+ 28
+ 29 def makeLayout(self):
+ 30 self.lwidth = self.WIDTH
+ 31 self.lheight = self.HEIGHT
+ 32 box = gtk.VBox(False,0)
+ 33 box.show()
+ 34 table = gtk.Table(2, 2, False)
+ 35 table.show()
+ 36 box.pack_start(table, True, True, 0)
+ 37 layout = gtk.Layout()
+ 38 self.layout = layout
+ 39 layout.set_size(self.lwidth, self.lheight)
+ 40 layout.connect("size-allocate", self.layout_resize)
+ 41 layout.show()
+ 42 table.attach(layout, 0, 1, 0, 1, gtk.FILL|gtk.EXPAND,
+ 43 gtk.FILL|gtk.EXPAND, 0, 0)
+ 44 # create the scrollbars and pack into the table
+ 45 vScrollbar = gtk.VScrollbar(None)
+ 46 vScrollbar.show()
+ 47 table.attach(vScrollbar, 1, 2, 0, 1, gtk.FILL|gtk.SHRINK,
+ 48 gtk.FILL|gtk.SHRINK, 0, 0)
+ 49 hScrollbar = gtk.HScrollbar(None)
+ 50 hScrollbar.show()
+ 51 table.attach(hScrollbar, 0, 1, 1, 2, gtk.FILL|gtk.SHRINK,
+ 52 gtk.FILL|gtk.SHRINK,
+ 53 0, 0)
+ 54 # tell the scrollbars to use the layout widget's adjustments
+ 55 vAdjust = layout.get_vadjustment()
+ 56 vScrollbar.set_adjustment(vAdjust)
+ 57 hAdjust = layout.get_hadjustment()
+ 58 hScrollbar.set_adjustment(hAdjust)
+ 59 layout.connect("drag_data_received", self.receiveCallback)
+ 60 layout.drag_dest_set(gtk.DEST_DEFAULT_MOTION |
+ 61 gtk.DEST_DEFAULT_HIGHLIGHT |
+ 62 gtk.DEST_DEFAULT_DROP,
+ 63 self.toCanvas, gtk.gdk.ACTION_COPY)
+ 64 self.addImage(gtkxpm.gtk_xpm, 0, 0)
+ 65 button = gtk.Button("Text Target")
+ 66 button.show()
+ 67 button.connect("drag_data_received", self.receiveCallback)
+ 68 button.drag_dest_set(gtk.DEST_DEFAULT_MOTION |
+ 69 gtk.DEST_DEFAULT_HIGHLIGHT |
+ 70 gtk.DEST_DEFAULT_DROP,
+ 71 self.toButton, gtk.gdk.ACTION_COPY)
+ 72 box.pack_start(button, False, False, 0)
+ 73 return box
+ 74
+ 75 def addImage(self, xpm, xd, yd):
+ 76 hadj = self.layout.get_hadjustment()
+ 77 vadj = self.layout.get_vadjustment()
+ 78 style = self.window.get_style()
+ 79 pixmap, mask = gtk.gdk.pixmap_create_from_xpm_d(
+ 80 self.window.window, style.bg[gtk.STATE_NORMAL], xpm)
+ 81 image = gtk.Image()
+ 82 image.set_from_pixmap(pixmap, mask)
+ 83 button = gtk.Button()
+ 84 button.add(image)
+ 85 button.connect("drag_data_get", self.sendCallback)
+ 86 button.drag_source_set(gtk.gdk.BUTTON1_MASK, self.fromImage,
+ 87 gtk.gdk.ACTION_COPY)
+ 88 button.show_all()
+ 89 # have to adjust for the scrolling of the layout - event location
+ 90 # is relative to the viewable not the layout size
+ 91 self.layout.put(button, int(xd+hadj.value), int(yd+vadj.value))
+ 92 return
+ 93
+ 94 def sendCallback(self, widget, context, selection, targetType, eventTime):
+ 95 if targetType == self.TARGET_TYPE_TEXT:
+ 96 now = time.time()
+ 97 str = time.ctime(now)
+ 98 selection.set(selection.target, 8, str)
+ 99 elif targetType == self.TARGET_TYPE_PIXMAP:
+ 100 selection.set(selection.target, 8,
+ 101 string.join(gtkxpm.gtk_xpm, '\n'))
+ 102
+ 103 def receiveCallback(self, widget, context, x, y, selection, targetType,
+ 104 time):
+ 105 if targetType == self.TARGET_TYPE_TEXT:
+ 106 label = widget.get_children()[0]
+ 107 label.set_text(selection.data)
+ 108 elif targetType == self.TARGET_TYPE_PIXMAP:
+ 109 self.addImage(string.split(selection.data, '\n'), x, y)
+ 110
+ 111 def __init__(self):
+ 112 self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ 113 self.window.set_default_size(300, 300)
+ 114 self.window.connect("destroy", lambda w: gtk.main_quit())
+ 115 self.window.show()
+ 116 layout = self.makeLayout()
+ 117 self.window.add(layout)
+ 118
+ 119 def main():
+ 120 gtk.main()
+ 121
+ 122 if __name__ == "__main__":
+ 123 DragNDropExample()
+ 124 main()
+</pre></td></tr></table></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-DNDProperties.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-DragAndDrop.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch-GtkRcFiles.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">22.2. DND Properties </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 23. GTK's rc Files</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-DNDProperties.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-DNDProperties.html
new file mode 100644
index 0000000..3c48f52
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-DNDProperties.html
@@ -0,0 +1,28 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>22.2. DND Properties</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-DragAndDrop.html" title="Chapter 22. Drag-and-drop (DND)"><link rel="previous" href="ch-DragAndDrop.html" title="Chapter 22. Drag-and-drop (DND)"><link rel="next" href="sec-DNDMethods.html" title="22.3. DND Methods"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">22.2. DND Properties</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch-DragAndDrop.html">Prev</a> </td><th width="60%" align="center">Chapter 22. Drag-and-drop (DND)</th><td width="20%" align="right"> <a accesskey="n" href="sec-DNDMethods.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-DNDProperties"></a>22.2. DND Properties</h2></div></div><div></div></div><p>Drag data has the following properties:</p><div class="itemizedlist"><ul type="disc"><li><p>Drag action type (ie <tt class="literal">ACTION_COPY</tt>,
+<tt class="literal">ACTION_MOVE</tt>).</p></li><li><p>Client specified arbitrary drag-and-drop type (a name and
+number pair).</p></li><li><p>Sent and received data format type.</p></li></ul></div><p>Drag actions are quite obvious, they specify if the widget can
+drag with the specified action(s),
+e.g. <tt class="literal">gtk.gdk.ACTION_COPY</tt> and/or
+<tt class="literal">gtk.gdk.ACTION_MOVE</tt>. An
+<tt class="literal">gtk.gdk.ACTION_COPY</tt> would be a typical drag-and-drop
+without the source data being deleted while
+<tt class="literal">gtk.gdk.ACTION_MOVE</tt> would be just like
+<tt class="literal">gtk.gdk.ACTION_COPY</tt> but the source data will be
+'suggested' to be deleted after the received signal handler is called. There
+are additional drag actions including <tt class="literal">gtk.gdk.ACTION_LINK</tt>
+which you may want to look into when you get to more advanced levels of
+drag-and-drop.</p><p>The client specified arbitrary drag-and-drop type is much more
+flexible, because your application will be defining and checking for that
+specifically. You will need to set up your destination widgets to receive
+certain drag-and-drop types by specifying a name and/or number. It would be
+more reliable to use a name since another application may just happen to use
+the same number for an entirely different meaning.</p><p>Sent and received data format types (<span class="emphasis"><em>selection
+target</em></span>) come into play only in your request and received data
+handler functions. The term <span class="emphasis"><em>selection target</em></span> is
+somewhat misleading. It is a term adapted from GTK+ selection (cut/copy and
+paste). What <span class="emphasis"><em>selection target</em></span> actually means is the
+data's format type (i.e. <tt class="classname">gtk.gdk.Atom</tt>, integer, or
+string) that is being sent or received. Your request data handler function
+needs to specify the type (<span class="emphasis"><em>selection target</em></span>) of data
+that it sends out and your received data handler needs to handle the type
+(<span class="emphasis"><em>selection target</em></span>) of data received.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch-DragAndDrop.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-DragAndDrop.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-DNDMethods.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 22. Drag-and-drop (DND) </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 22.3. DND Methods</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-DetailsOfBoxes.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-DetailsOfBoxes.html
new file mode 100644
index 0000000..2e73e02
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-DetailsOfBoxes.html
@@ -0,0 +1,56 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>4.2. Details of Boxes</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-PackingWidgets.html" title="Chapter 4. Packing Widgets"><link rel="previous" href="ch-PackingWidgets.html" title="Chapter 4. Packing Widgets"><link rel="next" href="sec-PackingDemonstrationProgram.html" title="4.3. Packing Demonstration Program"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">4.2. Details of Boxes</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch-PackingWidgets.html">Prev</a> </td><th width="60%" align="center">Chapter 4. Packing Widgets</th><td width="20%" align="right"> <a accesskey="n" href="sec-PackingDemonstrationProgram.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-DetailsOfBoxes"></a>4.2. Details of Boxes</h2></div></div><div></div></div><p>Because of this flexibility, packing boxes in GTK can be
+confusing at first. There are a lot of options, and it's not immediately
+obvious how they all fit together. In the end, however, there are basically
+five different styles. <a href="sec-DetailsOfBoxes.html#packbox1fig" title="Figure 4.1. Packing: Five Variations">Figure 4.1, “Packing: Five Variationsâ€</a> illustrates the result
+of running the program <a href="examples/packbox.py" target="_top"><span><b class="command">packbox.py</b></span></a> with an
+argument of 1:</p><div class="figure"><a name="packbox1fig"></a><p class="title"><b>Figure 4.1. Packing: Five Variations</b></p><div class="mediaobject" align="center"><img src="figures/packbox1.png" align="middle" alt="Packing: Five Variations"></div></div><p>Each line contains one horizontal box (hbox) with several
+buttons. The call to pack is shorthand for the call to pack each of the
+buttons into the hbox. Each of the buttons is packed into the hbox the same
+way (i.e., same arguments to the <tt class="methodname">pack_start</tt>()
+method).</p><p>This is an example of the pack_start() method.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ box.pack_start(child, expand, fill, padding)
+</pre></td></tr></table><p><i class="parameter"><tt>box</tt></i> is the box you are packing the object
+into; the first argument is the <i class="parameter"><tt>child</tt></i> object to be
+packed. The objects will all be buttons for now, so we'll be packing buttons
+into boxes.</p><p>The <i class="parameter"><tt>expand</tt></i> argument to
+<tt class="methodname">pack_start</tt>() and
+<tt class="methodname">pack_end</tt>() controls whether the widgets are laid
+out in the box to fill in all the extra space in the box so the box is
+expanded to fill the area allotted to it (<tt class="literal">True</tt>); or the
+box is shrunk to just fit the widgets (<tt class="literal">False</tt>). Setting
+expand to <tt class="literal">False</tt> will allow you to do right and left
+justification of your widgets. Otherwise, they will all expand to fit into
+the box, and the same effect could be achieved by using only one of
+<tt class="methodname">pack_start</tt>() or
+<tt class="methodname">pack_end</tt>().</p><p>The <i class="parameter"><tt>fill</tt></i> argument to the pack methods
+control whether the extra space is allocated to the objects themselves
+(<tt class="literal">True</tt>), or as extra padding in the box around these
+objects (<tt class="literal">False</tt>). It only has an effect if the expand
+argument is also <tt class="literal">True</tt>.</p><p>Python allows a method or function to be defined with default
+argument values and argument keywords. Throughout this tutorial I'll show
+the definition of the functions and methods with defaults and keywords
+bolded as applicable. For example the <tt class="methodname">pack_start</tt>()
+method is defined as:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ box.pack_start(<b class="parameter"><tt>child</tt></b>, <b class="parameter"><tt>expand</tt></b>=True, <b class="parameter"><tt>fill</tt></b>=True, <b class="parameter"><tt>padding</tt></b>=0)
+
+ box.pack_end(<b class="parameter"><tt>child</tt></b>, <b class="parameter"><tt>expand</tt></b>=True, <b class="parameter"><tt>fill</tt></b>=True, <b class="parameter"><tt>padding</tt></b>=0)
+</pre></td></tr></table><p><i class="parameter"><tt>child</tt></i>, <i class="parameter"><tt>expand</tt></i>,
+<i class="parameter"><tt>fill</tt></i> and <i class="parameter"><tt>padding</tt></i> are keywords. The
+<i class="parameter"><tt>expand</tt></i>, <i class="parameter"><tt>fill</tt></i> and
+<i class="parameter"><tt>padding</tt></i> arguments have the defaults shown. The
+<i class="parameter"><tt>child</tt></i> argument must be specified.</p><p>When creating a new box, the function looks like this:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ hbox = gtk.HBox(<b class="parameter"><tt>homogeneous</tt></b>=False, <b class="parameter"><tt>spacing</tt></b>=0)
+
+ vbox = gtk.VBox(<b class="parameter"><tt>homogeneous</tt></b>=False, <b class="parameter"><tt>spacing</tt></b>=0)
+</pre></td></tr></table><p>The <i class="parameter"><tt>homogeneous</tt></i> argument to
+<tt class="function">gtk.HBox</tt>() and <tt class="function">gtk.VBox</tt>() controls
+whether each object in the box has the same size (i.e., the same width in an
+hbox, or the same height in a vbox). If it is set, the pack routines
+function essentially as if the expand argument was always turned on.</p><p>What's the difference between <i class="parameter"><tt>spacing</tt></i>
+(set when the box is created) and <i class="parameter"><tt>padding</tt></i> (set when
+elements are packed)? Spacing is added between objects, and padding is added
+on either side of an object. <a href="sec-DetailsOfBoxes.html#packbox2fig" title="Figure 4.2. Packing with Spacing and Padding">Figure 4.2, “Packing with Spacing and Paddingâ€</a> illustrates the
+difference; pass an argument of 2 to <a href="examples/packbox.py" target="_top"><span><b class="command">packbox.py</b></span></a> :</p><div class="figure"><a name="packbox2fig"></a><p class="title"><b>Figure 4.2. Packing with Spacing and Padding</b></p><div class="mediaobject" align="center"><img src="figures/packbox2.png" align="middle" alt="Packing with Spacing and Padding"></div></div><p><a href="sec-DetailsOfBoxes.html#packbox3fig" title="Figure 4.3. Packing with pack_end()">Figure 4.3, “Packing with pack_end()â€</a> illustrates the use of the
+<tt class="methodname">pack_end</tt>() method (pass an argument of 3 to <a href="examples/packbox.py" target="_top"><span><b class="command">packbox.py</b></span></a>). The label
+"end" is packed with the <tt class="methodname">pack_end</tt>() method. It will
+stick to the right edge of the window when the window is resized.</p><div class="figure"><a name="packbox3fig"></a><p class="title"><b>Figure 4.3. Packing with pack_end()</b></p><div class="mediaobject" align="center"><img src="figures/packbox3.png" align="middle" alt="Packing with pack_end()"></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch-PackingWidgets.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-PackingWidgets.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-PackingDemonstrationProgram.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 4. Packing Widgets </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 4.3. Packing Demonstration Program</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-Dialogs.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-Dialogs.html
new file mode 100644
index 0000000..258ed92
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-Dialogs.html
@@ -0,0 +1,36 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>9.5. Dialogs</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-MiscellaneousWidgets.html" title="Chapter 9. Miscellaneous Widgets"><link rel="previous" href="sec-ProgressBars.html" title="9.4. Progress Bars"><link rel="next" href="sec-Images.html" title="9.6. Images"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">9.5. Dialogs</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-ProgressBars.html">Prev</a> </td><th width="60%" align="center">Chapter 9. Miscellaneous Widgets</th><td width="20%" align="right"> <a accesskey="n" href="sec-Images.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-Dialogs"></a>9.5. Dialogs</h2></div></div><div></div></div><p>The <tt class="classname">Dialog</tt> widget is very simple, and is
+actually just a window with a few things pre-packed into it for you. It
+simply creates a window, and then packs a <tt class="classname">VBox</tt> into
+the top, which contains a separator and then an <tt class="classname">HBox</tt>
+called the "action_area".</p><p>The <tt class="classname">Dialog</tt> widget can be used for pop-up
+messages to the user, and other similar tasks. It is really basic, and there
+is only one function for the dialog box, which is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ dialog = gtk.Dialog(<b class="parameter"><tt>title</tt></b>=None, <b class="parameter"><tt>parent</tt></b>=None, <b class="parameter"><tt>flags</tt></b>=0, <b class="parameter"><tt>buttons</tt></b>=None)
+</pre></td></tr></table><p>where <i class="parameter"><tt>title</tt></i> is the text to be used in the
+titlebar, <i class="parameter"><tt>parent</tt></i> is the main application window and
+<i class="parameter"><tt>flags</tt></i> set various modes of operation for the
+dialog:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ DIALOG_MODAL - make the dialog modal
+ DIALOG_DESTROY_WITH_PARENT - destroy dialog when its parent is destroyed
+ DIALOG_NO_SEPARATOR - omit the separator between the vbox and the action_area
+</pre></td></tr></table><p>The <i class="parameter"><tt>buttons</tt></i> argument is a tuple of button
+text and response pairs. All arguments have defaults and can be specified
+using keywords.</p><p>This will create the dialog box, and it is now up to you to use
+it. You could pack a button in the action_area:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ button = ...
+ dialog.action_area.pack_start(button, TRUE, TRUE, 0)
+ button.show()
+</pre></td></tr></table><p>And you could add to the <i class="parameter"><tt>vbox</tt></i> area by
+packing, for instance, a label in it, try something like this:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ label = gtk.Label("Dialogs are groovy")
+ dialog.vbox.pack_start(label, TRUE, TRUE, 0)
+ label.show()
+</pre></td></tr></table><p>As an example in using the dialog box, you could put two buttons
+in the <i class="parameter"><tt>action_area</tt></i>, a <span class="guibutton">Cancel</span>
+button and an <span class="guibutton">Ok</span> button, and a label in the
+<i class="parameter"><tt>vbox</tt></i> area, asking the user a question or giving an
+error, etc. Then you could attach a different signal to each of the buttons
+and perform the operation the user selects.</p><p>If the simple functionality provided by the default vertical and
+horizontal boxes in the two areas doesn't give you enough control for your
+application, then you can simply pack another layout widget into the boxes
+provided. For example, you could pack a table into the vertical box.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-ProgressBars.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-MiscellaneousWidgets.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-Images.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">9.4. Progress Bars </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 9.6. Images</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-DrawingAreaWidgetAndDrawing.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-DrawingAreaWidgetAndDrawing.html
new file mode 100644
index 0000000..0bbb0d9
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-DrawingAreaWidgetAndDrawing.html
@@ -0,0 +1,129 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>24.3. The DrawingArea Widget, And Drawing</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-Scribble.html" title="Chapter 24. Scribble, A Simple Example Drawing Program"><link rel="previous" href="sec-EventHandling.html" title="24.2. Event Handling"><link rel="next" href="ch-TipsForWritingPyGTKApplications.html" title="Chapter 25. Tips For Writing PyGTK Applications"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">24.3. The DrawingArea Widget, And Drawing</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-EventHandling.html">Prev</a> </td><th width="60%" align="center">Chapter 24. Scribble, A Simple Example Drawing Program</th><td width="20%" align="right"> <a accesskey="n" href="ch-TipsForWritingPyGTKApplications.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-DrawingAreaWidgetAndDrawing"></a>24.3. The DrawingArea Widget, And Drawing</h2></div></div><div></div></div><p>We now turn to the process of drawing on the screen. The widget
+we use for this is the <tt class="classname">DrawingArea</tt> (see <a href="ch-DrawingArea.html" title="Chapter 12. Drawing Area">Chapter 12, <i>Drawing Area</i></a>) widget. A drawing area widget is
+essentially an X window and nothing more. It is a blank canvas in which we
+can draw whatever we like. A drawing area is created using the call:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ darea = gtk.DrawingArea()
+</pre></td></tr></table><p>A default size for the widget can be specified by
+calling:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ darea.set_size_request(<b class="parameter"><tt>width</tt></b>, <b class="parameter"><tt>height</tt></b>)
+</pre></td></tr></table><p>This default size can be overridden, as is true for all widgets,
+by calling the <tt class="methodname">set_size_request</tt>() method, and that,
+in turn, can be overridden if the user manually resizes the the window
+containing the drawing area.</p><p>It should be noted that when we create a
+<tt class="classname">DrawingArea</tt> widget, we are completely responsible for
+drawing the contents. If our window is obscured then uncovered, we get an
+exposure event and must redraw what was previously hidden.</p><p>Having to remember everything that was drawn on the screen so we
+can properly redraw it can, to say the least, be a nuisance. In addition, it
+can be visually distracting if portions of the window are cleared, then
+redrawn step by step. The solution to this problem is to use an offscreen
+backing pixmap. Instead of drawing directly to the screen, we draw to an
+image stored in server memory but not displayed, then when the image changes
+or new portions of the image are displayed, we copy the relevant portions
+onto the screen.</p><p>To create an offscreen pixmap, we call the function:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ pixmap = gtk.gdk.Pixmap(<b class="parameter"><tt>window</tt></b>, <b class="parameter"><tt>width</tt></b>, <b class="parameter"><tt>height</tt></b>, <b class="parameter"><tt>depth</tt></b>=-1)
+</pre></td></tr></table><p>The <i class="parameter"><tt>window</tt></i> parameter specifies a
+<tt class="classname">gtk.gdk.Window</tt> that this <i class="parameter"><tt>pixmap</tt></i> takes some of its
+properties from. <i class="parameter"><tt>width</tt></i> and
+<i class="parameter"><tt>height</tt></i> specify the size of the
+<i class="parameter"><tt>pixmap</tt></i>. <i class="parameter"><tt>depth</tt></i> specifies the
+color depth, that is the number of bits per pixel, for the new window. If
+the <i class="parameter"><tt>depth</tt></i> is specified as -1 or omitted, it will
+match the depth of window.</p><p>We create the pixmap in our "configure_event" handler. This
+event is generated whenever the window changes size, including when it is
+originally created.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 32 # Create a new backing pixmap of the appropriate size
+ 33 def configure_event(widget, event):
+ 34 global pixmap
+ 35
+ 36 x, y, width, height = widget.get_allocation()
+ 37 pixmap = gtk.gdk.Pixmap(widget.window, width, height)
+ 38 pixmap.draw_rectangle(widget.get_style().white_gc,
+ 39 True, 0, 0, width, height)
+ 40
+ 41 return True
+ </pre></td></tr></table><p>The call to <tt class="methodname">draw_rectangle</tt>() clears the
+pixmap initially to white. We'll say more about that in a moment.</p><p>Our exposure event handler then simply copies the relevant
+portion of the pixmap onto the drawing area (widget) using the
+<tt class="methodname">draw_pixmap</tt>() method. (We determine the area we
+need to redraw by using the <i class="parameter"><tt>event.area</tt></i> attribute of
+the exposure event):</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 43 # Redraw the screen from the backing pixmap
+ 44 def expose_event(widget, event):
+ 45 x , y, width, height = event.area
+ 46 widget.window.draw_drawable(widget.get_style().fg_gc[gtk.STATE_NORMAL],
+ 47 pixmap, x, y, x, y, width, height)
+ 48 return False
+</pre></td></tr></table><p>We've now seen how to keep the screen up to date with our
+pixmap, but how do we actually draw interesting stuff on our pixmap? There
+are a large number of calls in PyGTK for drawing on drawables. A drawable is
+simply something that can be drawn upon. It can be a window, a pixmap, or a
+bitmap (a black and white image). We've already seen two such calls above,
+<tt class="methodname">draw_rectangle</tt>() and
+<tt class="methodname">draw_pixmap</tt>(). The complete list is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ drawable.draw_point(<b class="parameter"><tt>gc</tt></b>, <b class="parameter"><tt>x</tt></b>, <b class="parameter"><tt>y</tt></b>)
+
+ drawable.draw_line(<b class="parameter"><tt>gc</tt></b>, <b class="parameter"><tt>x1</tt></b>, <b class="parameter"><tt>y1</tt></b>, <b class="parameter"><tt>x2</tt></b>, <b class="parameter"><tt>y2</tt></b>)
+
+ drawable.draw_rectangle(<b class="parameter"><tt>gc</tt></b>, <b class="parameter"><tt>fill</tt></b>, <b class="parameter"><tt>x</tt></b>, <b class="parameter"><tt>y</tt></b>, <b class="parameter"><tt>width</tt></b>, <b class="parameter"><tt>height</tt></b>)
+
+ drawable.draw_arc(<b class="parameter"><tt>gc</tt></b>, <b class="parameter"><tt>fill</tt></b>, <b class="parameter"><tt>x</tt></b>, <b class="parameter"><tt>y</tt></b>, <b class="parameter"><tt>width</tt></b>, <b class="parameter"><tt>height</tt></b>, <b class="parameter"><tt>angle1</tt></b>, <b class="parameter"><tt>angle2</tt></b>)
+
+ drawable.draw_polygon(<b class="parameter"><tt>gc</tt></b>, <b class="parameter"><tt>fill</tt></b>, <b class="parameter"><tt>points</tt></b>)
+
+ drawable.draw_drawable(<b class="parameter"><tt>gc</tt></b>, <b class="parameter"><tt>src</tt></b>, <b class="parameter"><tt>xsrc</tt></b>, <b class="parameter"><tt>ysrc</tt></b>, <b class="parameter"><tt>xdest</tt></b>, <b class="parameter"><tt>ydest</tt></b>, <b class="parameter"><tt>width</tt></b>, <b class="parameter"><tt>height</tt></b>)
+
+ drawable.draw_points(<b class="parameter"><tt>gc</tt></b>, <b class="parameter"><tt>points</tt></b>)
+
+ drawable.draw_lines(<b class="parameter"><tt>gc</tt></b>, <b class="parameter"><tt>points</tt></b>)
+
+ drawable.draw_segments(<b class="parameter"><tt>gc</tt></b>, <b class="parameter"><tt>segments</tt></b>)
+
+ drawable.draw_rgb_image(<b class="parameter"><tt>gc</tt></b>, <b class="parameter"><tt>x</tt></b>, <b class="parameter"><tt>y</tt></b>, <b class="parameter"><tt>width</tt></b>, <b class="parameter"><tt>height</tt></b>, <b class="parameter"><tt>dither</tt></b>, <b class="parameter"><tt>buffer</tt></b>, <b class="parameter"><tt>rowstride</tt></b>)
+
+ drawable.draw_rgb_32_image(<b class="parameter"><tt>gc</tt></b>, <b class="parameter"><tt>x</tt></b>, <b class="parameter"><tt>y</tt></b>, <b class="parameter"><tt>width</tt></b>, <b class="parameter"><tt>height</tt></b>, <b class="parameter"><tt>dither</tt></b>, <b class="parameter"><tt>buffer</tt></b>, <b class="parameter"><tt>rowstride</tt></b>)
+
+ drawable.draw_gray_image(<b class="parameter"><tt>gc</tt></b>, <b class="parameter"><tt>x</tt></b>, <b class="parameter"><tt>y</tt></b>, <b class="parameter"><tt>width</tt></b>, <b class="parameter"><tt>height</tt></b>, <b class="parameter"><tt>dither</tt></b>, <b class="parameter"><tt>buffer</tt></b>, <b class="parameter"><tt>rowstride</tt></b>)
+</pre></td></tr></table><p>The drawing area methods are the same as the drawable drawing
+methods so you can use the methods described in <a href="sec-DrawingMethods.html" title="12.2. Drawing Methods">Section 12.2, “Drawing Methodsâ€</a> for further details on these
+methods. These methods all share the same first arguments. The first
+argument is a graphics context (<i class="parameter"><tt>gc</tt></i>).</p><p>A graphics context encapsulates information about things such as
+foreground and background color and line width. PyGTK has a full set of
+functions for creating and modifying graphics contexts, but to keep things
+simple we'll just use predefined graphics contexts. See <a href="ch-DrawingArea.html#sec-GraphicsContext" title="12.1. Graphics Context">Section 12.1, “Graphics Contextâ€</a> section for more information on
+graphics contexts. Each widget has an associated style. (Which can be
+modified in a <tt class="filename">gtkrc</tt> file, see <a href="ch-GtkRcFiles.html" title="Chapter 23. GTK's rc Files">Chapter 23, <i>GTK's rc Files</i></a>.) This, among other things, stores a number
+of graphics contexts. Some examples of accessing these graphics contexts
+are:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ widget.get_style().white_gc
+
+ widget.get_style().black_gc
+
+ widget.get_style().fg_gc[STATE_NORMAL]
+
+ widget.get_style().bg_gc[STATE_PRELIGHT]
+</pre></td></tr></table><p>The fields <i class="parameter"><tt>fg_gc</tt></i>, <i class="parameter"><tt>bg_gc</tt></i>,
+<i class="parameter"><tt>dark_gc</tt></i>, and <i class="parameter"><tt>light_gc</tt></i> are indexed by a
+parameter which can take on the values:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ STATE_NORMAL,
+ STATE_ACTIVE,
+ STATE_PRELIGHT,
+ STATE_SELECTED,
+ STATE_INSENSITIVE
+</pre></td></tr></table><p>For instance, for <tt class="literal">STATE_SELECTED</tt> the default
+foreground color is white and the default background color, dark
+blue.</p><p>Our function <tt class="methodname">draw_brush</tt>(), which does the
+actual drawing on the pixmap, is then:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 50 # Draw a rectangle on the screen
+ 51 def draw_brush(widget, x, y):
+ 52 rect = (int(x-5), int(y-5), 10, 10)
+ 53 pixmap.draw_rectangle(widget.get_style().black_gc, True,
+ 54 rect[0], rect[1], rect[2], rect[3])
+ 55 widget.queue_draw_area(rect[0], rect[1], rect[2], rect[3])
+</pre></td></tr></table><p>After we draw the rectangle representing the brush onto the
+pixmap, we call the function:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ widget.queue_draw_area(<b class="parameter"><tt>x</tt></b>, <b class="parameter"><tt>y</tt></b>, <b class="parameter"><tt>width</tt></b>, <b class="parameter"><tt>height</tt></b>)
+</pre></td></tr></table><p>which notifies X that the area given needs to be updated. X will
+eventually generate an expose event (possibly combining the areas passed in
+several calls to <tt class="methodname">draw</tt>()) which will cause our expose
+event handler to copy the relevant portions to the screen.</p><p>We have now covered the entire drawing program except for a few
+mundane details like creating the main window.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-EventHandling.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-Scribble.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch-TipsForWritingPyGTKApplications.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">24.2. Event Handling </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 25. Tips For Writing PyGTK Applications</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-DrawingMethods.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-DrawingMethods.html
new file mode 100644
index 0000000..4fd2ba7
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-DrawingMethods.html
@@ -0,0 +1,301 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>12.2. Drawing Methods</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-DrawingArea.html" title="Chapter 12. Drawing Area"><link rel="previous" href="ch-DrawingArea.html" title="Chapter 12. Drawing Area"><link rel="next" href="ch-TextViewWidget.html" title="Chapter 13. TextView Widget"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">12.2. Drawing Methods</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch-DrawingArea.html">Prev</a> </td><th width="60%" align="center">Chapter 12. Drawing Area</th><td width="20%" align="right"> <a accesskey="n" href="ch-TextViewWidget.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-DrawingMethods"></a>12.2. Drawing Methods</h2></div></div><div></div></div><p>There are a general set of methods that can be used to draw onto
+the drawing area 'canvas'. These drawing methods can be used for any
+<tt class="classname">gtk.gdk.Drawable</tt> subclass (either a
+<tt class="classname">gtk.gdk.Window</tt> or a
+<tt class="classname">gtk.gdk.Pixmap</tt>). The drawing methods are:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ drawable.draw_point(<b class="parameter"><tt>gc</tt></b>, <b class="parameter"><tt>x</tt></b>, <b class="parameter"><tt>y</tt></b>)
+</pre></td></tr></table><p><i class="parameter"><tt>gc</tt></i> is the Graphics Context to be used to do
+the drawing.</p><p><i class="parameter"><tt>x</tt></i> and <i class="parameter"><tt>y</tt></i> are the
+coordinates of the point.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ drawable.draw_line(<b class="parameter"><tt>gc</tt></b>, <b class="parameter"><tt>x1</tt></b>, <b class="parameter"><tt>y1</tt></b>, <b class="parameter"><tt>x2</tt></b>, <b class="parameter"><tt>y2</tt></b>)
+</pre></td></tr></table><p><i class="parameter"><tt>gc</tt></i> is the Graphics Context.</p><p><i class="parameter"><tt>x1</tt></i> and <i class="parameter"><tt>y1</tt></i> specify
+the starting point of the line. <i class="parameter"><tt>x2</tt></i> and
+<i class="parameter"><tt>y2</tt></i> specify the ending point of the line.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ drawable.draw_rectangle(<b class="parameter"><tt>gc</tt></b>, <b class="parameter"><tt>filled</tt></b>, <b class="parameter"><tt>x</tt></b>, <b class="parameter"><tt>y</tt></b>, <b class="parameter"><tt>width</tt></b>, <b class="parameter"><tt>height</tt></b>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>gc</tt></i> is the Graphics Context.</p><p><i class="parameter"><tt>filled</tt></i> is a boolean indicating the
+rectangle should be filled with the foreground color if
+<tt class="literal">TRUE</tt> or not filled, if <tt class="literal">FALSE</tt>.</p><p><i class="parameter"><tt>x</tt></i> and <i class="parameter"><tt>y</tt></i> are the top
+left corner of the rectangle.</p><p><i class="parameter"><tt>width</tt></i> and
+<i class="parameter"><tt>height</tt></i> are the width and height of the
+rectangle.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ drawable.draw_arc(<b class="parameter"><tt>gc</tt></b>, <b class="parameter"><tt>filled</tt></b>, <b class="parameter"><tt>x</tt></b>, <b class="parameter"><tt>y</tt></b>, <b class="parameter"><tt>width</tt></b>, <b class="parameter"><tt>height</tt></b>, <b class="parameter"><tt>angle1</tt></b>, <b class="parameter"><tt>angle2</tt></b>)
+</pre></td></tr></table><p><i class="parameter"><tt>gc</tt></i> is the Graphics Context.</p><p><i class="parameter"><tt>filled</tt></i> is a boolean indicating the arc
+should be filled with the foreground color if <tt class="literal">TRUE</tt> or not
+filled, if <tt class="literal">FALSE</tt>.</p><p><i class="parameter"><tt>x</tt></i> and <i class="parameter"><tt>y</tt></i> are the top
+left corner of the bounding rectangle. <i class="parameter"><tt>width</tt></i> and
+<i class="parameter"><tt>height</tt></i> are the width and height of the bounding
+rectangle.</p><p><i class="parameter"><tt>angle1</tt></i> is the start angle of the arc,
+relative to the 3 o'clock position, counter-clockwise, in 1/64ths of a
+degree.</p><p><i class="parameter"><tt>angle2</tt></i> is the end angle of the arc,
+relative to <i class="parameter"><tt>angle1</tt></i>, in 1/64ths of a degree counter
+clockwise.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ drawable.draw_polygon(<b class="parameter"><tt>gc</tt></b>, <b class="parameter"><tt>filled</tt></b>, <b class="parameter"><tt>points</tt></b>)
+</pre></td></tr></table><p><i class="parameter"><tt>gc</tt></i> is the Graphics Context.</p><p><i class="parameter"><tt>filled</tt></i> is a boolean indicating the polygon
+should be filled with the foreground color if <tt class="literal">TRUE</tt> or not filled, if <tt class="literal">FALSE</tt>.</p><p><i class="parameter"><tt>points</tt></i> is a list of coordinate pairs in
+tuples e.g. [ (0,0), (2,5), (3,7), (4,11) ] of the points to be drawn as a
+connected polygon.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ drawable.draw_string(<b class="parameter"><tt>font</tt></b>, <b class="parameter"><tt>gc</tt></b>, <b class="parameter"><tt>x</tt></b>, <b class="parameter"><tt>y</tt></b>, <b class="parameter"><tt>string</tt></b>)
+
+ drawable.draw_text(<b class="parameter"><tt>font</tt></b>, <b class="parameter"><tt>gc</tt></b>, <b class="parameter"><tt>x</tt></b>, <b class="parameter"><tt>y</tt></b>, <b class="parameter"><tt>string</tt></b>)
+</pre></td></tr></table><p><i class="parameter"><tt>font</tt></i> is the
+<tt class="classname">gtk.gdk.Font</tt> to use to render the string.</p><p><i class="parameter"><tt>gc</tt></i> is the Graphics Context.</p><p><i class="parameter"><tt>x</tt></i> and <i class="parameter"><tt>y</tt></i> are the
+coordinates of the point to start rendering the string i.e the left
+baseline.</p><p><i class="parameter"><tt>string</tt></i> is the string of characters to
+render.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>Both the <tt class="methodname">draw_string</tt>() and
+<tt class="methodname">draw_text</tt>() methods are deprecated - use a
+<tt class="classname">pango.Layout</tt> instead with the
+<tt class="methodname">draw_layout</tt>() method.</p></div><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ drawable.draw_layout(<b class="parameter"><tt>gc</tt></b>, <b class="parameter"><tt>x</tt></b>, <b class="parameter"><tt>y</tt></b>, <b class="parameter"><tt>layout</tt></b>)
+</pre></td></tr></table><p><i class="parameter"><tt>gc</tt></i> is the Graphics Context.</p><p><i class="parameter"><tt>x</tt></i> and <i class="parameter"><tt>y</tt></i> are the
+coordinates of the point to start rendering the layout.</p><p><i class="parameter"><tt>layout</tt></i> is the
+<tt class="classname">pango.Layout</tt> that is to be rendered.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ drawable.draw_drawable(<b class="parameter"><tt>gc</tt></b>, <b class="parameter"><tt>src</tt></b>, <b class="parameter"><tt>xsrc</tt></b>, <b class="parameter"><tt>ysrc</tt></b>, <b class="parameter"><tt>xdest</tt></b>, <b class="parameter"><tt>ydest</tt></b>, <b class="parameter"><tt>width</tt></b>, <b class="parameter"><tt>height</tt></b>)
+</pre></td></tr></table><p><i class="parameter"><tt>gc</tt></i> is the Graphics Context.</p><p><i class="parameter"><tt>src</tt></i> is the source drawable.</p><p><i class="parameter"><tt>xsrc</tt></i> and <i class="parameter"><tt>ysrc</tt></i> are the
+coordinates of the top left rectangle in the source drawable.</p><p><i class="parameter"><tt>xdest</tt></i> and <i class="parameter"><tt>ydest</tt></i> are the
+coordinates of the top left corner in the drawing area.</p><p><i class="parameter"><tt>width</tt></i> and <i class="parameter"><tt>height</tt></i> are
+the width and height of the source drawable area to be copied to the
+<i class="parameter"><tt>drawable</tt></i>. If <i class="parameter"><tt>width</tt></i> or
+<i class="parameter"><tt>height</tt></i> is -1 then the full width or height of the
+<i class="parameter"><tt>drawable</tt></i> is used.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ drawable.draw_image(<b class="parameter"><tt>gc</tt></b>, <b class="parameter"><tt>image</tt></b>, <b class="parameter"><tt>xsrc</tt></b>, <b class="parameter"><tt>ysrc</tt></b>, <b class="parameter"><tt>xdest</tt></b>, <b class="parameter"><tt>ydest</tt></b>, <b class="parameter"><tt>width</tt></b>, <b class="parameter"><tt>height</tt></b>)
+</pre></td></tr></table><p><i class="parameter"><tt>gc</tt></i> is the Graphics Context.</p><p><i class="parameter"><tt>image</tt></i> is the source image.</p><p><i class="parameter"><tt>xsrc</tt></i> and <i class="parameter"><tt>ysrc</tt></i> are the
+coordinates of the top left rectangle in the source drawable.</p><p><i class="parameter"><tt>xdest</tt></i> and <i class="parameter"><tt>ydest</tt></i> are the
+coordinates of the top left corner in the drawing area.</p><p><i class="parameter"><tt>width</tt></i> and <i class="parameter"><tt>height</tt></i> are
+the width and height of the source drawable area to be copied to the
+<i class="parameter"><tt>drawable</tt></i>. If <i class="parameter"><tt>width</tt></i> or
+<i class="parameter"><tt>height</tt></i> is -1 then the full width or height of the
+<i class="parameter"><tt>image</tt></i> is used.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ drawable.draw_points(<b class="parameter"><tt>gc</tt></b>, <b class="parameter"><tt>points</tt></b>)
+</pre></td></tr></table><p><i class="parameter"><tt>gc</tt></i> is the Graphics Context.</p><p><i class="parameter"><tt>points</tt></i> is a list or tuple of coordinate
+pairs in tuples e.g. [ (0,0), (2,5), (3,7), (4,11) ] of the points to be
+drawn.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ drawable.draw_segments(<b class="parameter"><tt>gc</tt></b>, <b class="parameter"><tt>segs</tt></b>)
+</pre></td></tr></table><p><i class="parameter"><tt>gc</tt></i> is the Graphics Context.</p><p><i class="parameter"><tt>segs</tt></i> is a list or tuple of start and end
+coordinate pairs in tuples e.g. [ (0,0, 1,5), (2,5, 1,7), (3,7, 1,11),
+(4,11, 1,13) ] of the line segments to be drawn.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ drawable.draw_lines(<b class="parameter"><tt>gc</tt></b>, <b class="parameter"><tt>points</tt></b>)
+</pre></td></tr></table><p><i class="parameter"><tt>gc</tt></i> is the Graphics Context.</p><p><i class="parameter"><tt>points</tt></i> is a list or tuple of coordinate
+pairs in tuples e.g. [ (0,0), (2,5), (3,7), (4,11) ] of the points to be
+connected with lines.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ drawable.draw_rgb_image(<b class="parameter"><tt>gc</tt></b>, <b class="parameter"><tt>x</tt></b>, <b class="parameter"><tt>y</tt></b>, <b class="parameter"><tt>width</tt></b>, <b class="parameter"><tt>height</tt></b>, <b class="parameter"><tt>dith</tt></b>, <b class="parameter"><tt>rgb_buf</tt></b>, <b class="parameter"><tt>rowstride</tt></b>)
+
+ drawable.draw_rgb_32_image(<b class="parameter"><tt>gc</tt></b>, <b class="parameter"><tt>x</tt></b>, <b class="parameter"><tt>y</tt></b>, <b class="parameter"><tt>width</tt></b>, <b class="parameter"><tt>height</tt></b>, <b class="parameter"><tt>dith</tt></b>, <b class="parameter"><tt>buf</tt></b>, <b class="parameter"><tt>rowstride</tt></b>)
+
+ drawable.draw_gray_image(<b class="parameter"><tt>gc</tt></b>, <b class="parameter"><tt>x</tt></b>, <b class="parameter"><tt>y</tt></b>, <b class="parameter"><tt>width</tt></b>, <b class="parameter"><tt>height</tt></b>, <b class="parameter"><tt>dith</tt></b>, <b class="parameter"><tt>buf</tt></b>, <b class="parameter"><tt>rowstride</tt></b>)
+</pre></td></tr></table><p><i class="parameter"><tt>gc</tt></i> is the Graphics Context.</p><p><i class="parameter"><tt>x</tt></i> and <i class="parameter"><tt>y</tt></i> are the top
+left corner of the image bounding rectangle.</p><p><i class="parameter"><tt>width</tt></i> and <i class="parameter"><tt>height</tt></i> are
+the width and height of the image bounding rectangle.</p><p><i class="parameter"><tt>dith</tt></i> is the dither mode as described
+below</p><p>For the <tt class="methodname">draw_rgb_image</tt>() method,
+<i class="parameter"><tt>rgb_buf</tt></i> is the RGB Image data packed in a string as a
+sequence of 8-bit RGB pixel triplets. For the
+<tt class="methodname">draw_rgb_32_image</tt>() method,
+<i class="parameter"><tt>buf</tt></i> is the RGB Image data packed in a string as a
+sequence of 8-bit RGB pixel triplets with 8-bit padding (4 characters per
+RGB pixel). For the <tt class="methodname">draw_gray_image</tt>() method,
+<i class="parameter"><tt>buf</tt></i> is the gray image data packed in a string as
+8-bit pixel data.</p><p><i class="parameter"><tt>rowstride</tt></i> is the number of characters from
+the start of one row to the start of the next row of the image.
+<i class="parameter"><tt>rowstride</tt></i> usually defaults to: 3 *
+<i class="parameter"><tt>width</tt></i> for the
+<tt class="methodname">draw_rgb_image</tt>() method; 4 *
+<i class="parameter"><tt>width</tt></i> for the
+<tt class="methodname">draw_rgb_32_image</tt>(); and,
+<i class="parameter"><tt>width</tt></i> for the
+<tt class="methodname">draw_gray_image</tt>() method. If
+<i class="parameter"><tt>rowstride</tt></i> is 0 the line will be replicated
+<i class="parameter"><tt>height</tt></i> times.</p><p>The <i class="parameter"><tt>dither</tt></i> modes are:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ RGB_DITHER_NONE # Never use dithering.
+
+ RGB_DITHER_NORMAL # Use dithering in 8 bits per pixel (and below) only.
+
+ RGB_DITHER_MAX # Use dithering in 16 bits per pixel and below.
+</pre></td></tr></table><p>The <a href="examples/drawingarea.py" target="_top"><span><b class="command">drawingarea.py</b></span></a>
+example program demonstrates the use of most of the
+<tt class="classname">DrawingArea</tt> methods. It also puts the
+<tt class="classname">DrawingArea</tt> inside a
+<tt class="classname">ScrolledWindow</tt> and adds horizontal and vertical
+<tt class="classname">Ruler</tt> widgets. <a href="sec-DrawingMethods.html#drawingareafig" title="Figure 12.1. Drawing Area Example">Figure 12.1, “Drawing Area Exampleâ€</a> shows
+the program in operation:</p><div class="figure"><a name="drawingareafig"></a><p class="title"><b>Figure 12.1. Drawing Area Example</b></p><div class="mediaobject" align="center"><img src="figures/drawingarea.png" align="middle" alt="Drawing Area Example"></div></div><p>The <a href="examples/drawingarea.py" target="_top"><span><b class="command">drawingarea.py</b></span></a>
+source code is below and uses the <a href="examples/gtk.xpm" target="_top"><tt class="filename">gtk.xpm</tt></a> pixmap:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 1 #!/usr/bin/env python
+ 2
+ 3 # example drawingarea.py
+ 4
+ 5 import pygtk
+ 6 pygtk.require('2.0')
+ 7 import gtk
+ 8 import operator
+ 9 import time
+ 10 import string
+ 11
+ 12 class DrawingAreaExample:
+ 13 def __init__(self):
+ 14 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ 15 window.set_title("Drawing Area Example")
+ 16 window.connect("destroy", lambda w: gtk.main_quit())
+ 17 self.area = gtk.DrawingArea()
+ 18 self.area.set_size_request(400, 300)
+ 19 self.pangolayout = self.area.create_pango_layout("")
+ 20 self.sw = gtk.ScrolledWindow()
+ 21 self.sw.add_with_viewport(self.area)
+ 22 self.table = gtk.Table(2,2)
+ 23 self.hruler = gtk.HRuler()
+ 24 self.vruler = gtk.VRuler()
+ 25 self.hruler.set_range(0, 400, 0, 400)
+ 26 self.vruler.set_range(0, 300, 0, 300)
+ 27 self.table.attach(self.hruler, 1, 2, 0, 1, yoptions=0)
+ 28 self.table.attach(self.vruler, 0, 1, 1, 2, xoptions=0)
+ 29 self.table.attach(self.sw, 1, 2, 1, 2)
+ 30 window.add(self.table)
+ 31 self.area.set_events(gtk.gdk.POINTER_MOTION_MASK |
+ 32 gtk.gdk.POINTER_MOTION_HINT_MASK )
+ 33 self.area.connect("expose-event", self.area_expose_cb)
+ 34 def motion_notify(ruler, event):
+ 35 return ruler.emit("motion_notify_event", event)
+ 36 self.area.connect_object("motion_notify_event", motion_notify,
+ 37 self.hruler)
+ 38 self.area.connect_object("motion_notify_event", motion_notify,
+ 39 self.vruler)
+ 40 self.hadj = self.sw.get_hadjustment()
+ 41 self.vadj = self.sw.get_vadjustment()
+ 42 def val_cb(adj, ruler, horiz):
+ 43 if horiz:
+ 44 span = self.sw.get_allocation()[3]
+ 45 else:
+ 46 span = self.sw.get_allocation()[2]
+ 47 l,u,p,m = ruler.get_range()
+ 48 v = adj.value
+ 49 ruler.set_range(v, v+span, p, m)
+ 50 while gtk.events_pending():
+ 51 gtk.main_iteration()
+ 52 self.hadj.connect('value-changed', val_cb, self.hruler, True)
+ 53 self.vadj.connect('value-changed', val_cb, self.vruler, False)
+ 54 def size_allocate_cb(wid, allocation):
+ 55 x, y, w, h = allocation
+ 56 l,u,p,m = self.hruler.get_range()
+ 57 m = max(m, w)
+ 58 self.hruler.set_range(l, l+w, p, m)
+ 59 l,u,p,m = self.vruler.get_range()
+ 60 m = max(m, h)
+ 61 self.vruler.set_range(l, l+h, p, m)
+ 62 self.sw.connect('size-allocate', size_allocate_cb)
+ 63 self.area.show()
+ 64 self.hruler.show()
+ 65 self.vruler.show()
+ 66 self.sw.show()
+ 67 self.table.show()
+ 68 window.show()
+ 69
+ 70 def area_expose_cb(self, area, event):
+ 71 self.style = self.area.get_style()
+ 72 self.gc = self.style.fg_gc[gtk.STATE_NORMAL]
+ 73 self.draw_point(10,10)
+ 74 self.draw_points(110, 10)
+ 75 self.draw_line(210, 10)
+ 76 self.draw_lines(310, 10)
+ 77 self.draw_segments(10, 100)
+ 78 self.draw_rectangles(110, 100)
+ 79 self.draw_arcs(210, 100)
+ 80 self.draw_pixmap(310, 100)
+ 81 self.draw_polygon(10, 200)
+ 82 self.draw_rgb_image(110, 200)
+ 83 return True
+ 84
+ 85 def draw_point(self, x, y):
+ 86 self.area.window.draw_point(self.gc, x+30, y+30)
+ 87 self.pangolayout.set_text("Point")
+ 88 self.area.window.draw_layout(self.gc, x+5, y+50, self.pangolayout)
+ 89 return
+ 90
+ 91 def draw_points(self, x, y):
+ 92 points = [(x+10,y+10), (x+10,y), (x+40,y+30),
+ 93 (x+30,y+10), (x+50,y+10)]
+ 94 self.area.window.draw_points(self.gc, points)
+ 95 self.pangolayout.set_text("Points")
+ 96 self.area.window.draw_layout(self.gc, x+5, y+50, self.pangolayout)
+ 97 return
+ 98
+ 99 def draw_line(self, x, y):
+ 100 self.area.window.draw_line(self.gc, x+10, y+10, x+20, y+30)
+ 101 self.pangolayout.set_text("Line")
+ 102 self.area.window.draw_layout(self.gc, x+5, y+50, self.pangolayout)
+ 103 return
+ 104
+ 105 def draw_lines(self, x, y):
+ 106 points = [(x+10,y+10), (x+10,y), (x+40,y+30),
+ 107 (x+30,y+10), (x+50,y+10)]
+ 108 self.area.window.draw_lines(self.gc, points)
+ 109 self.pangolayout.set_text("Lines")
+ 110 self.area.window.draw_layout(self.gc, x+5, y+50, self.pangolayout)
+ 111 return
+ 112
+ 113 def draw_segments(self, x, y):
+ 114 segments = ((x+20,y+10, x+20,y+70), (x+60,y+10, x+60,y+70),
+ 115 (x+10,y+30 , x+70,y+30), (x+10, y+50 , x+70, y+50))
+ 116 self.area.window.draw_segments(self.gc, segments)
+ 117 self.pangolayout.set_text("Segments")
+ 118 self.area.window.draw_layout(self.gc, x+5, y+80, self.pangolayout)
+ 119 return
+ 120
+ 121 def draw_rectangles(self, x, y):
+ 122 self.area.window.draw_rectangle(self.gc, False, x, y, 80, 70)
+ 123 self.area.window.draw_rectangle(self.gc, True, x+10, y+10, 20, 20)
+ 124 self.area.window.draw_rectangle(self.gc, True, x+50, y+10, 20, 20)
+ 125 self.area.window.draw_rectangle(self.gc, True, x+20, y+50, 40, 10)
+ 126 self.pangolayout.set_text("Rectangles")
+ 127 self.area.window.draw_layout(self.gc, x+5, y+80, self.pangolayout)
+ 128 return
+ 129
+ 130 def draw_arcs(self, x, y):
+ 131 self.area.window.draw_arc(self.gc, False, x+10, y, 70, 70,
+ 132 0, 360*64)
+ 133 self.area.window.draw_arc(self.gc, True, x+30, y+20, 10, 10,
+ 134 0, 360*64)
+ 135 self.area.window.draw_arc(self.gc, True, x+50, y+20, 10, 10,
+ 136 0, 360*64)
+ 137 self.area.window.draw_arc(self.gc, True, x+30, y+10, 30, 50,
+ 138 210*64, 120*64)
+ 139 self.pangolayout.set_text("Arcs")
+ 140 self.area.window.draw_layout(self.gc, x+5, y+80, self.pangolayout)
+ 141 return
+ 142
+ 143 def draw_pixmap(self, x, y):
+ 144 pixmap, mask = gtk.gdk.pixmap_create_from_xpm(
+ 145 self.area.window, self.style.bg[gtk.STATE_NORMAL], "gtk.xpm")
+ 146
+ 147 self.area.window.draw_drawable(self.gc, pixmap, 0, 0, x+15, y+25,
+ 148 -1, -1)
+ 149 self.pangolayout.set_text("Pixmap")
+ 150 self.area.window.draw_layout(self.gc, x+5, y+80, self.pangolayout)
+ 151 return
+ 152
+ 153 def draw_polygon(self, x, y):
+ 154 points = [(x+10,y+60), (x+10,y+20), (x+40,y+70),
+ 155 (x+30,y+30), (x+50,y+40)]
+ 156 self.area.window.draw_polygon(self.gc, True, points)
+ 157 self.pangolayout.set_text("Polygon")
+ 158 self.area.window.draw_layout(self.gc, x+5, y+80, self.pangolayout)
+ 159 return
+ 160
+ 161 def draw_rgb_image(self, x, y):
+ 162 b = 80*3*80*['\0']
+ 163 for i in range(80):
+ 164 for j in range(80):
+ 165 b[3*80*i+3*j] = chr(255-3*i)
+ 166 b[3*80*i+3*j+1] = chr(255-3*abs(i-j))
+ 167 b[3*80*i+3*j+2] = chr(255-3*j)
+ 168 buff = string.join(b, '')
+ 169 self.area.window.draw_rgb_image(self.gc, x, y, 80, 80,
+ 170 gtk.gdk.RGB_DITHER_NONE, buff, 80*3)
+ 171 self.pangolayout.set_text("RGB Image")
+ 172 self.area.window.draw_layout(self.gc, x+5, y+80, self.pangolayout)
+ 173 return
+ 174
+ 175 def main():
+ 176 gtk.main()
+ 177 return 0
+ 178
+ 179 if __name__ == "__main__":
+ 180 DrawingAreaExample()
+ 181 main()
+</pre></td></tr></table></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch-DrawingArea.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-DrawingArea.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch-TextViewWidget.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 12. Drawing Area </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 13. TextView Widget</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-EntryCompletion.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-EntryCompletion.html
new file mode 100644
index 0000000..096a6c1
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-EntryCompletion.html
@@ -0,0 +1,65 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>16.4. EntryCompletion Objects</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-NewInPyGTK2.4.html" title="Chapter 16. New Widgets in PyGTK 2.4"><link rel="previous" href="sec-ColorButtonAndFontButton.html" title="16.3. ColorButton and FontButton Widgets"><link rel="next" href="sec-ExpanderWidget.html" title="16.5. Expander Widgets"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">16.4. EntryCompletion Objects</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-ColorButtonAndFontButton.html">Prev</a> </td><th width="60%" align="center">Chapter 16. New Widgets in PyGTK 2.4</th><td width="20%" align="right"> <a accesskey="n" href="sec-ExpanderWidget.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-EntryCompletion"></a>16.4. EntryCompletion Objects</h2></div></div><div></div></div><p>An <tt class="classname">EntryCompletion</tt> is an object that is used
+with an <tt class="classname">Entry</tt> widget to provide completion
+functionality. As the user types into the <tt class="classname">Entry</tt> the
+<tt class="classname">EntryCompletion</tt> will popup a window with a set of
+strings matching the <tt class="classname">Entry</tt> text.</p><p>An <tt class="classname">EntryCompletion</tt> is created using the
+constructor:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ completion = gtk.EntryCompletion()
+</pre></td></tr></table><p>You can use the <tt class="classname">Entry</tt> method
+<tt class="methodname">set_completion</tt>() to associate an
+<tt class="classname">EntryCompletion</tt> with an
+<tt class="classname">Entry</tt>:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ entry.set_completion(<b class="parameter"><tt>completion</tt></b>)
+</pre></td></tr></table><p>The strings used by the <tt class="classname">EntryCompletion</tt> for
+matching are retrieved from a <tt class="classname">TreeModel</tt> (usually a
+<tt class="classname">ListStore</tt>) that must be set using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ completion.set_model(<b class="parameter"><tt>model</tt></b>)
+</pre></td></tr></table><p>The <tt class="classname">EntryCompletion</tt> implements the
+<tt class="classname">CellLayout</tt> interface that is similar to the
+<tt class="classname">TreeViewColumn</tt> in managing the display of the
+<tt class="classname">TreeModel</tt> data. The following convenience method sets
+up an <tt class="classname">EntryCompletion</tt> in the most common
+configuration - a list of strings:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ completion.set_text_column(column)
+</pre></td></tr></table><p>This method is equivalent to the following:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ cell = CellRendererText()
+ completion.pack_start(cell)
+ completion.add_attribute(cell, 'text', column)
+</pre></td></tr></table><p>To set the number of characters that must be entered before the
+<tt class="classname">EntryCompletion</tt> starts matching you can use the
+method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ completion.set_minimum_key_length(<b class="parameter"><tt>length</tt></b>)
+</pre></td></tr></table><p>The example program <a href="examples/entrycompletion.py" target="_top">entrycompletion.py</a> demonstrates
+the use of the <tt class="classname">EntryCompletion</tt>. <a href="sec-EntryCompletion.html#entrycompletionfig" title="Figure 16.10. EntryCompletion">Figure 16.10, “EntryCompletionâ€</a> illustrates the program in
+operation.</p><div class="figure"><a name="entrycompletionfig"></a><p class="title"><b>Figure 16.10. EntryCompletion</b></p><div class="mediaobject" align="center"><img src="figures/entrycompletion.png" align="middle" alt="EntryCompletion"></div></div><p>The example program starts with a small number of completion strings
+that can be increased by typing into the entry field and pressing the
+<span><b class="keycap">Enter</b></span> key. If the string is unique it is added to the list
+of completion strings.</p><p>The built-in match function is a case insensitive string comparison
+function. If you need a more specialized match function, you can use the
+following method to install your own match function:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ completion.set_match_func(<i class="parameter"><tt>func</tt></i>, <i class="parameter"><tt>user_data</tt></i>)
+</pre></td></tr></table><p>The signature of <i class="parameter"><tt>func</tt></i> is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def func(completion, key_string, iter, data):
+</pre></td></tr></table><p>where <i class="parameter"><tt>key_string</tt></i> contains the current
+contents of the <tt class="classname">Entry</tt>, <i class="parameter"><tt>iter</tt></i> is
+a <tt class="classname">TreeIter</tt> pointing at a row in the associated
+<tt class="classname">TreeModel</tt>, and <i class="parameter"><tt>data</tt></i> is
+<i class="parameter"><tt>user_data</tt></i>. <i class="parameter"><tt>func</tt></i> should return
+<tt class="literal">TRUE</tt> if the row's completion string should be
+displayed.</p><p>The simple example code snippet below uses a match function to
+display completion names that begin with the entry contents and have the
+given suffix, in this case, a name ending in <tt class="literal">.png</tt> for a
+<tt class="literal">PNG</tt> file.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ ...
+ completion.set_match_func(end_match, (0, '.png'))
+ ...
+ def end_match(completion, entrystr, iter, data):
+ column, suffix = data
+ model = completion.get_model()
+ modelstr = model[iter][column]
+ return modelstr.startswith(entrystr) and modelstr.endswith(suffix)
+ ...
+</pre></td></tr></table><p>For example if the user types 'foo' and the completion model
+contains strings like 'foobar.png', smiley.png', 'foot.png' and 'foo.tif', the
+'foobar.png' and 'foot.png' strings would be displayed as
+completions.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-ColorButtonAndFontButton.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-NewInPyGTK2.4.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-ExpanderWidget.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">16.3. ColorButton and FontButton Widgets </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 16.5. Expander Widgets</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-EventHandling.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-EventHandling.html
new file mode 100644
index 0000000..0538998
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-EventHandling.html
@@ -0,0 +1,345 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>24.2. Event Handling</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-Scribble.html" title="Chapter 24. Scribble, A Simple Example Drawing Program"><link rel="previous" href="ch-Scribble.html" title="Chapter 24. Scribble, A Simple Example Drawing Program"><link rel="next" href="sec-DrawingAreaWidgetAndDrawing.html" title="24.3. The DrawingArea Widget, And Drawing"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">24.2. Event Handling</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch-Scribble.html">Prev</a> </td><th width="60%" align="center">Chapter 24. Scribble, A Simple Example Drawing Program</th><td width="20%" align="right"> <a accesskey="n" href="sec-DrawingAreaWidgetAndDrawing.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-EventHandling"></a>24.2. Event Handling</h2></div></div><div></div></div><p>The GTK+ signals we have already discussed are for high-level
+actions, such as a menu item being selected. However, sometimes it is useful
+to learn about lower-level occurrences, such as the mouse being moved, or a
+key being pressed. There are also GTK+ signals corresponding to these
+low-level events. The handlers for these signals have an extra parameter
+which is a <tt class="classname">gtk.gdk.Event</tt> object containing
+information about the event. For instance, motion event handlers are passed
+a <tt class="classname">gtk.gdk.Event</tt> object containing EventMotion
+information which has (in part) attributes like:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ type
+ window
+ time
+ x
+ y
+ ...
+ state
+ ...
+</pre></td></tr></table><p><i class="parameter"><tt>window</tt></i> is the window in which the event
+occurred.</p><p><i class="parameter"><tt>x</tt></i> and <i class="parameter"><tt>y</tt></i> give the
+coordinates of the event.</p><p><i class="parameter"><tt>type</tt></i> will be set to the event type, in
+this case <tt class="literal">MOTION_NOTIFY</tt>. The types (in module gtk.gdk)
+are:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+NOTHING a special code to indicate a null event.
+
+DELETE the window manager has requested that the toplevel window be
+ hidden or destroyed, usually when the user clicks on a special
+ icon in the title bar.
+
+DESTROY the window has been destroyed.
+
+EXPOSE all or part of the window has become visible and needs to be
+ redrawn.
+
+MOTION_NOTIFY the pointer (usually a mouse) has moved.
+
+BUTTON_PRESS a mouse button has been pressed.
+
+_2BUTTON_PRESS a mouse button has been double-clicked (clicked twice within
+ a short period of time). Note that each click also generates a
+ BUTTON_PRESS event.
+
+_3BUTTON_PRESS a mouse button has been clicked 3 times in a short period of
+ time. Note that each click also generates a BUTTON_PRESS event.
+
+BUTTON_RELEASE a mouse button has been released.
+
+KEY_PRESS a key has been pressed.
+
+KEY_RELEASE a key has been released.
+
+ENTER_NOTIFY the pointer has entered the window.
+
+LEAVE_NOTIFY the pointer has left the window.
+
+FOCUS_CHANGE the keyboard focus has entered or left the window.
+
+CONFIGURE the size, position or stacking order of the window has changed.
+ Note that GTK+ discards these events for GDK_WINDOW_CHILD windows.
+
+MAP the window has been mapped.
+
+UNMAP the window has been unmapped.
+
+PROPERTY_NOTIFY a property on the window has been changed or deleted.
+
+SELECTION_CLEAR the application has lost ownership of a selection.
+
+SELECTION_REQUEST another application has requested a selection.
+
+SELECTION_NOTIFY a selection has been received.
+
+PROXIMITY_IN an input device has moved into contact with a sensing surface
+ (e.g. a touchscreen or graphics tablet).
+
+PROXIMITY_OUT an input device has moved out of contact with a sensing surface.
+
+DRAG_ENTER the mouse has entered the window while a drag is in progress.
+
+DRAG_LEAVE the mouse has left the window while a drag is in progress.
+
+DRAG_MOTION the mouse has moved in the window while a drag is in progress.
+
+DRAG_STATUS the status of the drag operation initiated by the window has changed.
+
+DROP_START a drop operation onto the window has started.
+
+DROP_FINISHED the drop operation initiated by the window has completed.
+
+CLIENT_EVENT a message has been received from another application.
+
+VISIBILITY_NOTIFY the window visibility status has changed.
+
+NO_EXPOSE indicates that the source region was completely available when parts
+ of a drawable were copied. This is not very useful.
+
+SCROLL ?
+
+WINDOW_STATE ?
+
+SETTING ?
+</pre></td></tr></table><p><i class="parameter"><tt>state</tt></i> specifies the modifier state when
+the <i class="parameter"><tt>event</tt></i> occurred (that is, it specifies which
+modifier keys and mouse buttons were pressed). It is the bitwise
+<tt class="literal">OR</tt> of some of the following (in module gtk.gdk):</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ SHIFT_MASK
+ LOCK_MASK
+ CONTROL_MASK
+ MOD1_MASK
+ MOD2_MASK
+ MOD3_MASK
+ MOD4_MASK
+ MOD5_MASK
+ BUTTON1_MASK
+ BUTTON2_MASK
+ BUTTON3_MASK
+ BUTTON4_MASK
+ BUTTON5_MASK
+</pre></td></tr></table><p>As for other signals, to determine what happens when an event
+occurs we call the <tt class="methodname">connect</tt>() method. But we also
+need to let GTK+ know which events we want to be notified about. To do this,
+we call the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ widget.set_events(<i class="parameter"><tt>events</tt></i>)
+</pre></td></tr></table><p>The <i class="parameter"><tt>events</tt></i> argument specifies the events
+we are interested in. It is the bitwise <tt class="literal">OR</tt> of constants
+that specify different types of events. For future reference, the event
+types (in module gtk.gdk) are:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ EXPOSURE_MASK
+ POINTER_MOTION_MASK
+ POINTER_MOTION_HINT_MASK
+ BUTTON_MOTION_MASK
+ BUTTON1_MOTION_MASK
+ BUTTON2_MOTION_MASK
+ BUTTON3_MOTION_MASK
+ BUTTON_PRESS_MASK
+ BUTTON_RELEASE_MASK
+ KEY_PRESS_MASK
+ KEY_RELEASE_MASK
+ ENTER_NOTIFY_MASK
+ LEAVE_NOTIFY_MASK
+ FOCUS_CHANGE_MASK
+ STRUCTURE_MASK
+ PROPERTY_CHANGE_MASK
+ VISIBILITY_NOTIFY_MASK
+ PROXIMITY_IN_MASK
+ PROXIMITY_OUT_MASK
+ SUBSTRUCTURE_MASK
+</pre></td></tr></table><p>There are a few subtle points that have to be observed when
+calling the <tt class="methodname">set_events</tt>() method. First, it must be
+called before the X window for a PyGTK widget is created. In practical
+terms, this means you should call it immediately after creating the widget.
+Second, the widget must be one which will be realized with an associated X
+window. For efficiency, many widget types do not have their own window, but
+draw in their parent's window. These widgets include:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ gtk.Alignment
+ gtk.Arrow
+ gtk.Bin
+ gtk.Box
+ gtk.Image
+ gtk.Item
+ gtk.Label
+ gtk.Layout
+ gtk.Pixmap
+ gtk.ScrolledWindow
+ gtk.Separator
+ gtk.Table
+ gtk.AspectFrame
+ gtk.Frame
+ gtk.VBox
+ gtk.HBox
+ gtk.VSeparator
+ gtk.HSeparator
+</pre></td></tr></table><p>To capture events for these widgets, you need to use an
+<tt class="classname">EventBox</tt> widget. See <a href="ch-ContainerWidgets.html#sec-EventBox" title="10.1. The EventBox">Section 10.1, “The EventBoxâ€</a> widget for details.</p><p>The event attributes that are set by PyGTK for each type of
+event are:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+every event type
+ window
+ send_event
+
+NOTHING
+DELETE
+DESTROY # no additional attributes
+
+EXPOSE area
+ count
+
+MOTION_NOTIFY time
+ x
+ y
+ pressure
+ xtilt
+ ytilt
+ state
+ is_hint
+ source
+ deviceid
+ x_root
+ y_root
+
+BUTTON_PRESS
+_2BUTTON_PRESS
+_3BUTTON_PRESS
+BUTTON_RELEASE time
+ x
+ y
+ pressure
+ xtilt
+ ytilt
+ state
+ button
+ source
+ deviceid
+ x_root
+ y_root
+
+KEY_PRESS
+KEY_RELEASE time
+ state
+ keyval
+ string
+
+ENTER_NOTIFY
+LEAVE_NOTIFY subwindow
+ time
+ x
+ y
+ x_root
+ y_root
+ mode
+ detail
+ focus
+ state
+
+FOCUS_CHANGE _in
+
+CONFIGURE x
+ y
+ width
+ height
+
+MAP
+UNMAP # no additional attributes
+
+PROPERTY_NOTIFY atom
+ time
+ state
+
+SELECTION_CLEAR
+SELECTION_REQUEST
+SELECTION_NOTIFY selection
+ target
+ property
+ requestor
+ time
+
+PROXIMITY_IN
+PROXIMITY_OUT time
+ source
+ deviceid
+
+DRAG_ENTER
+DRAG_LEAVE
+DRAG_MOTION
+DRAG_STATUS
+DROP_START
+DROP_FINISHED context
+ time
+ x_root
+ y_root
+
+CLIENT_EVENT message_type
+ data_format
+ data
+
+VISIBILTY_NOTIFY state
+
+NO_EXPOSE # no additional attributes
+</pre></td></tr></table><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2867711"></a>24.2.1. Scribble - Event Handling</h3></div></div><div></div></div><p>For our drawing program, we want to know when the mouse button
+is pressed and when the mouse is moved, so we specify
+<tt class="literal">POINTER_MOTION_MASK</tt> and
+<tt class="literal">BUTTON_PRESS_MASK</tt>. We also want to know when we need to
+redraw our window, so we specify <tt class="literal">EXPOSURE_MASK</tt>. Although
+we want to be notified via a Configure event when our window size changes,
+we don't have to specify the corresponding <tt class="literal">STRUCTURE_MASK</tt>
+flag, because it is automatically specified for all windows.</p><p>It turns out, however, that there is a problem with just
+specifying <tt class="literal">POINTER_MOTION_MASK</tt>. This will cause the
+server to add a new motion event to the event queue every time the user
+moves the mouse. Imagine that it takes us 0.1 seconds to handle a motion
+event, but the X server queues a new motion event every 0.05 seconds. We
+will soon get way behind the users drawing. If the user draws for 5 seconds,
+it will take us another 5 seconds to catch up after they release the mouse
+button! What we would like is to only get one motion event for each event we
+process. The way to do this is to specify
+<tt class="literal">POINTER_MOTION_HINT_MASK</tt>.</p><p>When we specify <tt class="literal">POINTER_MOTION_HINT_MASK</tt>, the
+server sends us a motion event the first time the pointer moves after
+entering our window, or after a button press or release event. Subsequent
+motion events will be suppressed until we explicitly ask for the position of
+the pointer using the <tt class="classname">gtk.gdk.Window</tt> method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ x, y, mask = window.get_pointer()
+</pre></td></tr></table><p><i class="parameter"><tt>window</tt></i> is a
+<tt class="classname">gtk.gdk.Window</tt> object. <i class="parameter"><tt>x</tt></i> and
+<i class="parameter"><tt>y</tt></i> are the coordinates of the pointer and
+<i class="parameter"><tt>mask</tt></i> is the modifier mask to detect which keys are
+pressed. (There is a <tt class="classname">gtk.Widget</tt> method,
+<tt class="methodname">get_pointer</tt>() which provides the same information
+as the <tt class="methodname">gtk.gdk.Window get_pointer</tt>() method but it
+does not return the mask information)</p><p>The <a href="examples/scribblesimple.py" target="_top"><span><b class="command">scribblesimple.py</b></span></a>
+example program demonstrates the basic use of events and event handlers.
+<a href="sec-EventHandling.html#simplescribblefig" title="Figure 24.2. Simple Scribble Example">Figure 24.2, “Simple Scribble Exampleâ€</a> illustrates the program in action:</p><div class="figure"><a name="simplescribblefig"></a><p class="title"><b>Figure 24.2. Simple Scribble Example</b></p><div class="mediaobject" align="center"><img src="figures/scribblesimple.png" align="middle" alt="Simple Scribble Example"></div></div><p>The event handlers are connected to the drawing_area by the
+following lines:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 92 # Signals used to handle backing pixmap
+ 93 drawing_area.connect("expose_event", expose_event)
+ 94 drawing_area.connect("configure_event", configure_event)
+ 95
+ 96 # Event signals
+ 97 drawing_area.connect("motion_notify_event", motion_notify_event)
+ 98 drawing_area.connect("button_press_event", button_press_event)
+ 99
+ 100 drawing_area.set_events(gtk.gdk.EXPOSURE_MASK
+ 101 | gtk.gdk.LEAVE_NOTIFY_MASK
+ 102 | gtk.gdk.BUTTON_PRESS_MASK
+ 103 | gtk.gdk.POINTER_MOTION_MASK
+ 104 | gtk.gdk.POINTER_MOTION_HINT_MASK)
+ </pre></td></tr></table><p>The <tt class="function">button_press_event</tt>() and<tt class="function">
+motion_notify_event</tt>() event handlers in <a href="examples/scribblesimple.py" target="_top"><span><b class="command">scribblesimple.py</b></span></a>
+are:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 57 def button_press_event(widget, event):
+ 58 if event.button == 1 and pixmap != None:
+ 59 draw_brush(widget, event.x, event.y)
+ 60 return True
+ 61
+ 62 def motion_notify_event(widget, event):
+ 63 if event.is_hint:
+ 64 x, y, state = event.window.get_pointer()
+ 65 else:
+ 66 x = event.x
+ 67 y = event.y
+ 68 state = event.state
+ 69
+ 70 if state &amp; gtk.gdk.BUTTON1_MASK and pixmap != None:
+ 71 draw_brush(widget, x, y)
+ 72
+ 73 return True
+</pre></td></tr></table><p>The <tt class="function">expose_event</tt>() and
+<tt class="function">configure_event</tt>() handlers will be described
+later.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch-Scribble.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-Scribble.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-DrawingAreaWidgetAndDrawing.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 24. Scribble, A Simple Example Drawing Program </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 24.3. The DrawingArea Widget, And Drawing</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-Events.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-Events.html
new file mode 100644
index 0000000..e374bfe
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-Events.html
@@ -0,0 +1,104 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>2.3. Events</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-GettingStarted.html" title="Chapter 2. Getting Started"><link rel="previous" href="sec-TheoryOfSignalsAndCallbacks.html" title="2.2. Theory of Signals and Callbacks"><link rel="next" href="sec-SteppingThroughHelloWorld.html" title="2.4. Stepping Through Hello World"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2.3. Events</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-TheoryOfSignalsAndCallbacks.html">Prev</a> </td><th width="60%" align="center">Chapter 2. Getting Started</th><td width="20%" align="right"> <a accesskey="n" href="sec-SteppingThroughHelloWorld.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-Events"></a>2.3. Events</h2></div></div><div></div></div><p>In addition to the signal mechanism described above, there is a
+set of events that reflect the X event mechanism. Callbacks may also be
+attached to these events. These events are:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ event
+ button_press_event
+ button_release_event
+ scroll_event
+ motion_notify_event
+ delete_event
+ destroy_event
+ expose_event
+ key_press_event
+ key_release_event
+ enter_notify_event
+ leave_notify_event
+ configure_event
+ focus_in_event
+ focus_out_event
+ map_event
+ unmap_event
+ property_notify_event
+ selection_clear_event
+ selection_request_event
+ selection_notify_event
+ proximity_in_event
+ proximity_out_event
+ visibility_notify_event
+ client_event
+ no_expose_event
+ window_state_event
+</pre></td></tr></table><p>In order to connect a callback function to one of these events
+you use the method <tt class="methodname">connect</tt>() , as described above,
+using one of the above event names as the <i class="parameter"><tt>name</tt></i> parameter.
+The callback function (or method) for events has a slightly different form
+than that for signals:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def callback_func(widget, event, callback_data ):
+
+ def callback_meth(self, widget, event, callback_data ):
+</pre></td></tr></table><p><tt class="classname">GdkEvent</tt> is a python object type whose
+type attribute will indicate which of the above events has occurred. The
+other attributes of the event will depend upon the type of the event.
+Possible values for the types are:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ NOTHING
+ DELETE
+ DESTROY
+ EXPOSE
+ MOTION_NOTIFY
+ BUTTON_PRESS
+ _2BUTTON_PRESS
+ _3BUTTON_PRESS
+ BUTTON_RELEASE
+ KEY_PRESS
+ KEY_RELEASE
+ ENTER_NOTIFY
+ LEAVE_NOTIFY
+ FOCUS_CHANGE
+ CONFIGURE
+ MAP
+ UNMAP
+ PROPERTY_NOTIFY
+ SELECTION_CLEAR
+ SELECTION_REQUEST
+ SELECTION_NOTIFY
+ PROXIMITY_IN
+ PROXIMITY_OUT
+ DRAG_ENTER
+ DRAG_LEAVE
+ DRAG_MOTION
+ DRAG_STATUS
+ DROP_START
+ DROP_FINISHED
+ CLIENT_EVENT
+ VISIBILITY_NOTIFY
+ NO_EXPOSE
+ SCROLL
+ WINDOW_STATE
+ SETTING
+</pre></td></tr></table><p>These values are accessed by prefacing the event type with
+gtk.gdk. for example <tt class="varname">gtk.gdk.DRAG_ENTER</tt>.</p><p>So, to connect a callback function to one of these events we
+would use something like:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ button.connect("button_press_event", button_press_callback)
+</pre></td></tr></table><p>This assumes that button is a <tt class="classname">GtkButton</tt>
+widget. Now, when the mouse is over the button and a mouse button is
+pressed, the function <i class="parameter"><tt>button_press_callback</tt></i> will be
+called. This function may be defined as:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def button_press_callback(widget, event, data ):
+</pre></td></tr></table><p>The value returned from this function indicates whether the
+event should be propagated further by the GTK+ event handling mechanism.
+Returning <tt class="varname">True</tt> indicates that the event has been
+handled, and that it should not propagate further. Returning
+<tt class="varname">False</tt> continues the normal event handling. See <a href="ch-AdvancedEventAndSignalHandling.html" title="Chapter 20. Advanced Event and Signal Handling">Chapter 20, <i>Advanced Event and Signal Handling</i></a> for more details on this
+propagation process.</p><p>The GDK selection and drag-and-drop APIs also emit a number of
+events which are reflected in GTK+ by signals. See <a href="sec-DNDMethods.html#sec-SignalsOnSourceWidget" title="22.3.2. Signals On the Source Widget">Section 22.3.2, “Signals On the Source Widgetâ€</a> and <a href="sec-DNDMethods.html#sec-SignalsOnDestinationWidget" title="22.3.4. Signals On the Destination Widget">Section 22.3.4, “Signals On the Destination Widgetâ€</a> for details on the
+signatures of the callback functions for these signals:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ selection_received
+ selection_get
+ drag_begin_event
+ drag_end_event
+ drag_data_delete
+ drag_motion
+ drag_drop
+ drag_data_get
+ drag_data_received
+</pre></td></tr></table></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-TheoryOfSignalsAndCallbacks.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-GettingStarted.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-SteppingThroughHelloWorld.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">2.2. Theory of Signals and Callbacks </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 2.4. Stepping Through Hello World</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-ExampleRcFile.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-ExampleRcFile.html
new file mode 100644
index 0000000..890f6f7
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-ExampleRcFile.html
@@ -0,0 +1,126 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>23.3. Example rc file</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-GtkRcFiles.html" title="Chapter 23. GTK's rc Files"><link rel="previous" href="sec-GTKRcFileFormat.html" title="23.2. GTK's rc File Format"><link rel="next" href="ch-Scribble.html" title="Chapter 24. Scribble, A Simple Example Drawing Program"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">23.3. Example rc file</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-GTKRcFileFormat.html">Prev</a> </td><th width="60%" align="center">Chapter 23. GTK's rc Files</th><td width="20%" align="right"> <a accesskey="n" href="ch-Scribble.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-ExampleRcFile"></a>23.3. Example rc file</h2></div></div><div></div></div><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+# pixmap_path "&lt;dir 1&gt;:&lt;dir 2&gt;:&lt;dir 3&gt;:..."
+#
+pixmap_path "/usr/include/X11R6/pixmaps:/home/imain/pixmaps"
+#
+# style &lt;name&gt; [= &lt;name&gt;]
+# {
+# &lt;option&gt;
+# }
+#
+# widget &lt;widget_set&gt; style &lt;style_name&gt;
+# widget_class &lt;widget_class_set&gt; style &lt;style_name&gt;
+
+# Here is a list of all the possible states. Note that some do not apply to
+# certain widgets.
+#
+# NORMAL - The normal state of a widget, without the mouse over top of
+# it, and not being pressed, etc.
+#
+# PRELIGHT - When the mouse is over top of the widget, colors defined
+# using this state will be in effect.
+#
+# ACTIVE - When the widget is pressed or clicked it will be active, and
+# the attributes assigned by this tag will be in effect.
+#
+# INSENSITIVE - When a widget is set insensitive, and cannot be
+# activated, it will take these attributes.
+#
+# SELECTED - When an object is selected, it takes these attributes.
+#
+# Given these states, we can set the attributes of the widgets in each of
+# these states using the following directives.
+#
+# fg - Sets the foreground color of a widget.
+# fg - Sets the background color of a widget.
+# bg_pixmap - Sets the background of a widget to a tiled pixmap.
+# font - Sets the font to be used with the given widget.
+#
+
+# This sets a style called "button". The name is not really important, as
+# it is assigned to the actual widgets at the bottom of the file.
+
+style "window"
+{
+ #This sets the padding around the window to the pixmap specified.
+ #bg_pixmap[&lt;STATE&gt;] = "&lt;pixmap filename&gt;"
+ bg_pixmap[NORMAL] = "warning.xpm"
+}
+
+style "scale"
+{
+ #Sets the foreground color (font color) to red when in the "NORMAL"
+ #state.
+
+ fg[NORMAL] = { 1.0, 0, 0 }
+
+ #Sets the background pixmap of this widget to that of its parent.
+ bg_pixmap[NORMAL] = "&lt;parent&gt;"
+}
+
+style "button"
+{
+ # This shows all the possible states for a button. The only one that
+ # doesn't apply is the SELECTED state.
+
+ fg[PRELIGHT] = { 0, 1.0, 1.0 }
+ bg[PRELIGHT] = { 0, 0, 1.0 }
+ bg[ACTIVE] = { 1.0, 0, 0 }
+ fg[ACTIVE] = { 0, 1.0, 0 }
+ bg[NORMAL] = { 1.0, 1.0, 0 }
+ fg[NORMAL] = { .99, 0, .99 }
+ bg[INSENSITIVE] = { 1.0, 1.0, 1.0 }
+ fg[INSENSITIVE] = { 1.0, 0, 1.0 }
+}
+
+# In this example, we inherit the attributes of the "button" style and then
+# override the font and background color when prelit to create a new
+# "main_button" style.
+
+style "main_button" = "button"
+{
+ font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
+ bg[PRELIGHT] = { 0.75, 0, 0 }
+}
+
+style "toggle_button" = "button"
+{
+ fg[NORMAL] = { 1.0, 0, 0 }
+ fg[ACTIVE] = { 1.0, 0, 0 }
+
+ # This sets the background pixmap of the toggle_button to that of its
+ # parent widget (as defined in the application).
+ bg_pixmap[NORMAL] = "&lt;parent&gt;"
+}
+
+style "text"
+{
+ bg_pixmap[NORMAL] = "marble.xpm"
+ fg[NORMAL] = { 1.0, 1.0, 1.0 }
+}
+
+style "ruler"
+{
+ font = "-adobe-helvetica-medium-r-normal--*-80-*-*-*-*-*-*"
+}
+
+# pixmap_path "~/.pixmaps"
+
+# These set the widget types to use the styles defined above.
+# The widget types are listed in the class hierarchy, but could probably be
+# just listed in this document for the users reference.
+
+widget_class "GtkWindow" style "window"
+widget_class "GtkDialog" style "window"
+widget_class "GtkFileSelection" style "window"
+widget_class "*Gtk*Scale" style "scale"
+widget_class "*GtkCheckButton*" style "toggle_button"
+widget_class "*GtkRadioButton*" style "toggle_button"
+widget_class "*GtkButton*" style "button"
+widget_class "*Ruler" style "ruler"
+widget_class "*GtkText" style "text"
+
+# This sets all the buttons that are children of the "main window" to
+# the main_button style. These must be documented to be taken advantage of.
+widget "main window.*GtkButton*" style "main_button"
+</pre></td></tr></table></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-GTKRcFileFormat.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-GtkRcFiles.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch-Scribble.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">23.2. GTK's rc File Format </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 24. Scribble, A Simple Example Drawing Program</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-ExpanderWidget.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-ExpanderWidget.html
new file mode 100644
index 0000000..dbaca4a
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-ExpanderWidget.html
@@ -0,0 +1,52 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>16.5. Expander Widgets</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-NewInPyGTK2.4.html" title="Chapter 16. New Widgets in PyGTK 2.4"><link rel="previous" href="sec-EntryCompletion.html" title="16.4. EntryCompletion Objects"><link rel="next" href="sec-FileChoosers.html" title="16.6. File Selections using FileChooser-based Widgets"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">16.5. Expander Widgets</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-EntryCompletion.html">Prev</a> </td><th width="60%" align="center">Chapter 16. New Widgets in PyGTK 2.4</th><td width="20%" align="right"> <a accesskey="n" href="sec-FileChoosers.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-ExpanderWidget"></a>16.5. Expander Widgets</h2></div></div><div></div></div><p>The <tt class="classname">Expander</tt> widget is a fairly simple
+container widget that can reveal or hide its child widget by clicking on a
+triangle similar to the triangle in a <tt class="classname">TreeView</tt>. A new
+<tt class="classname">Expander</tt> is created using the constructor:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ expander = gtk.Expander(<b class="parameter"><tt>label</tt></b>=None)
+</pre></td></tr></table><p>where <i class="parameter"><tt>label</tt></i> is a string to be used as the
+expander label. If <i class="parameter"><tt>label</tt></i> is <tt class="literal">None</tt>
+or not specified, no label is created. Alternatively, you can use the
+function:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ expander = gtk.expander_new_with_mnemonic(<b class="parameter"><tt>label</tt></b>=None)
+</pre></td></tr></table><p>that sets the character in label preceded by an underscore as a
+mnemonic keyboard accelerator.</p><p>The <tt class="classname">Expander</tt> widget uses the
+<tt class="classname">Container</tt> API to add and remove its child
+widget:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ expander.add(<b class="parameter"><tt>widget</tt></b>)
+
+ expander.remove(<b class="parameter"><tt>widget</tt></b>)
+</pre></td></tr></table><p>The child widget can be retrieved using the
+<tt class="classname">Bin</tt> "child" attribute or the
+<tt class="methodname">get_child</tt>() method.</p><p>The setting that controls the interpretation of label underscores
+can be retrieved and changed using the methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ use_underline = expander.get_use_underline()
+
+ expander.set_use_underline(use_underline)
+</pre></td></tr></table><p>If you want to use Pango markup (see the <a href="http://www.pygtk.org//pygtk2reference/pango-markup-language.html" target="_top">Pango
+Markup reference</a> for more detail) in the label string, use the
+following methods to set and retrieve the setting of the "use-markup"
+property:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ expander.set_use_markup(<b class="parameter"><tt>use_markup</tt></b>)
+
+ use_markup = expander.get_use_markup()
+</pre></td></tr></table><p>Finally, you can use any widget as the label widget using the
+following method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ expander.set_label_widget(<b class="parameter"><tt>label_widget</tt></b>)
+</pre></td></tr></table><p>This allows you, for example, to use an <tt class="classname">HBox</tt>
+packed with an <tt class="classname">Image</tt> and a
+<tt class="classname">Label</tt> as the <tt class="classname">Expander</tt>
+label.</p><p>The state of the <tt class="classname">Expander</tt> can be retrieved
+and set using the methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ expanded = expander.get_expanded()
+
+ expander.set_expanded(<b class="parameter"><tt>expanded</tt></b>)
+</pre></td></tr></table><p>If <i class="parameter"><tt>expanded</tt></i> is <tt class="literal">TRUE</tt> the
+child widget is revealed.</p><p>In most cases the <tt class="classname">Expander</tt> automatically does
+exactly what you want when revealing and hiding the child widget. In some
+cases your application might want to create a child widget at expansion
+time. The "notify::expanded" signal can be used to track changes in the
+state of the expander triangle. The signal handler can then create or change
+the child widget as needed.</p><p>The example program <a href="examples/expander.py" target="_top">expander.py</a> demonstrates the use of the
+<tt class="classname">Expander</tt>. <a href="sec-ExpanderWidget.html#expanderfig" title="Figure 16.11. Expander Widget">Figure 16.11, “Expander Widgetâ€</a> illustrates the program
+in operation:</p><div class="figure"><a name="expanderfig"></a><p class="title"><b>Figure 16.11. Expander Widget</b></p><div class="mediaobject" align="center"><img src="figures/expander.png" align="middle" alt="Expander Widget"></div></div><p>The program creates a <tt class="classname">Label</tt> containing the
+current time and shows it when the expander is expanded.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-EntryCompletion.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-NewInPyGTK2.4.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-FileChoosers.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">16.4. EntryCompletion Objects </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 16.6. File Selections using FileChooser-based Widgets</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-FileChoosers.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-FileChoosers.html
new file mode 100644
index 0000000..9f3feec
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-FileChoosers.html
@@ -0,0 +1,108 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>16.6. File Selections using FileChooser-based Widgets</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-NewInPyGTK2.4.html" title="Chapter 16. New Widgets in PyGTK 2.4"><link rel="previous" href="sec-ExpanderWidget.html" title="16.5. Expander Widgets"><link rel="next" href="sec-UIManager.html" title="16.7. The UIManager"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">16.6. File Selections using FileChooser-based Widgets</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-ExpanderWidget.html">Prev</a> </td><th width="60%" align="center">Chapter 16. New Widgets in PyGTK 2.4</th><td width="20%" align="right"> <a accesskey="n" href="sec-UIManager.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-FileChoosers"></a>16.6. File Selections using FileChooser-based Widgets</h2></div></div><div></div></div><p>The new way to select files in PyGTK 2.4 is to use the variants of
+the <tt class="classname">FileChooser</tt> widget. The two objects that
+implement this new interface in PyGTK 2.4 are
+<tt class="classname">FileChooserWidget</tt> and
+<tt class="classname">FileChooserDialog</tt>. The latter is the complete dialog
+with the window and easily defined buttons. The former is a widget useful
+for embedding within another widget.</p><p>Both the <tt class="classname">FileChooserWidget</tt> and
+<tt class="classname">FileChooserDialog</tt> possess the means for navigating
+the filesystem tree and selecting files. The view of the widgets depends on
+the action used to open a widget.</p><p>To create a new file chooser dialog to select an existing file (as
+in typical
+<span class="guimenu">File</span>-&gt;<span class="guimenuitem">Open</span>
+option of a typical application), use:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ chooser = gtk.FileChooserDialog(<b class="parameter"><tt>title</tt></b>=None,<b class="parameter"><tt>action</tt></b>=gtk.FILE_CHOOSER_ACTION_OPEN,
+ <b class="parameter"><tt>buttons</tt></b>=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN,gtk.RESPONSE_OK))
+</pre></td></tr></table><p>To create a new file chooser dialog to select a new file name (as in
+the typical
+<span class="guimenu">File</span>-&gt;<span class="guimenuitem">Save</span>
+as option of a typical application), use:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ chooser = gtk.FileChooserDialog(<b class="parameter"><tt>title</tt></b>=None,<b class="parameter"><tt>action</tt></b>=gtk.FILE_CHOOSER_ACTION_SAVE,
+ <b class="parameter"><tt>buttons</tt></b>=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN,gtk.RESPONSE_OK))
+</pre></td></tr></table><p>In the above examples, the two buttons (the stock
+<span class="guibutton">Cancel</span> and <span class="guibutton">Open</span> items) are
+created and connected to their respective responses (stock
+<span class="guibutton">Cancel</span> and <span class="guibutton">OK</span> responses).
+ </p><p>To set the folder displayed in the file chooser, use the
+method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ chooser.set_current_folder(<b class="parameter"><tt>pathname</tt></b>)
+</pre></td></tr></table><p>To set the suggested file name as if it was typed by a user (the
+typical <span class="guimenu">File</span>-&gt;<span class="guimenuitem">Save
+As</span>situation), use the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ chooser.set_current_name(<b class="parameter"><tt>name</tt></b>)
+</pre></td></tr></table><p>The above method does not require the filename to exist. If you want
+to preselect a particular existing file (as in the
+<span class="guimenu">File</span>-&gt;<span class="guimenuitem">Open</span>
+situation), you should use the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ chooser.set_filename(<b class="parameter"><tt>filename</tt></b>)
+</pre></td></tr></table><p>To obtain the filename that the user has entered or clicked
+on, use this method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ filename = chooser.get_filename()
+</pre></td></tr></table><p>It is possible to allow multiple file selections (only for the
+<tt class="literal">gtk.FILE_CHOOSER_ACTION_OPEN</tt> action) by using the
+method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ chooser.set_select_multiple(<b class="parameter"><tt>select_multiple</tt></b>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>select_mutiple</tt></i> should be
+<tt class="literal">TRUE</tt> to allow multiple selections. In this case, you will
+need to use the following method to retrieve a list of the selected
+filenames:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ filenames = chooser.get_filenames()
+</pre></td></tr></table><p>An important feature of all file choosers is the ability to add file
+selection filters. The filter may be added by the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ chooser.add_filter(<b class="parameter"><tt>filter</tt></b>)
+</pre></td></tr></table><p>In the example above, <i class="parameter"><tt>filter</tt></i> must be an
+instance of the <tt class="classname">FileFilter</tt>class.</p><p>The left panel of the file chooser lists some shortcut folders such
+as <span class="guilabel">Home</span>, <span class="guilabel">Filesystem</span>,
+<span class="guilabel">CDROM</span>, etc. You may add a folder to the list of these
+shortcuts and remove it from the list by using these methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ chooser.add_shortcut_folder(<b class="parameter"><tt>folder</tt></b>)
+ chooser.remove_shortcut_folder(<b class="parameter"><tt>folder</tt></b>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>folder</tt></i> is the pathname of folder. The
+<a href="examples/filechooser.py" target="_top"><span><b class="command">filechooser.py</b></span></a>
+example program illustrates the use of the filechooser widget. <a href="sec-FileChoosers.html#filechooserfig" title="Figure 16.12. File Selection Example">Figure 16.12, “File Selection Exampleâ€</a> shows the resulting display:</p><div class="figure"><a name="filechooserfig"></a><p class="title"><b>Figure 16.12. File Selection Example</b></p><div class="mediaobject" align="center"><img src="figures/filechooser.png" align="middle" alt="File Selection Example"></div></div><p>The source code for the <a href="examples/filechooser.py" target="_top"><span><b class="command">filechooser.py</b></span></a>
+example program is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 1 #!/usr/bin/env python
+ 2
+ 3 # example filechooser.py
+ 4
+ 5 import pygtk
+ 6 pygtk.require('2.0')
+ 7
+ 8 import gtk
+ 9
+ 10 # Check for new pygtk: this is new class in PyGtk 2.4
+ 11 if gtk.pygtk_version &lt; (2,3,90):
+ 12 print "PyGtk 2.3.90 or later required for this example"
+ 13 raise SystemExit
+ 14
+ 15 dialog = gtk.FileChooserDialog("Open..",
+ 16 None,
+ 17 gtk.FILE_CHOOSER_ACTION_OPEN,
+ 18 (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
+ 19 gtk.STOCK_OPEN, gtk.RESPONSE_OK))
+ 20 dialog.set_default_response(gtk.RESPONSE_OK)
+ 21
+ 22 filter = gtk.FileFilter()
+ 23 filter.set_name("All files")
+ 24 filter.add_pattern("*")
+ 25 dialog.add_filter(filter)
+ 26
+ 27 filter = gtk.FileFilter()
+ 28 filter.set_name("Images")
+ 29 filter.add_mime_type("image/png")
+ 30 filter.add_mime_type("image/jpeg")
+ 31 filter.add_mime_type("image/gif")
+ 32 filter.add_pattern("*.png")
+ 33 filter.add_pattern("*.jpg")
+ 34 filter.add_pattern("*.gif")
+ 35 filter.add_pattern("*.tif")
+ 36 filter.add_pattern("*.xpm")
+ 37 dialog.add_filter(filter)
+ 38
+ 39 response = dialog.run()
+ 40 if response == gtk.RESPONSE_OK:
+ 41 print dialog.get_filename(), 'selected'
+ 42 elif response == gtk.RESPONSE_CANCEL:
+ 43 print 'Closed, no files selected'
+ 44 dialog.destroy()
+</pre></td></tr></table></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-ExpanderWidget.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-NewInPyGTK2.4.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-UIManager.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">16.5. Expander Widgets </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 16.7. The UIManager</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-FileSelections.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-FileSelections.html
new file mode 100644
index 0000000..ec0c0f5
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-FileSelections.html
@@ -0,0 +1,81 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>9.14. File Selections</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-MiscellaneousWidgets.html" title="Chapter 9. Miscellaneous Widgets"><link rel="previous" href="sec-ColorSelection.html" title="9.13. Color Selection"><link rel="next" href="sec-FontSelectionDialog.html" title="9.15. Font Selection Dialog"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">9.14. File Selections</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-ColorSelection.html">Prev</a> </td><th width="60%" align="center">Chapter 9. Miscellaneous Widgets</th><td width="20%" align="right"> <a accesskey="n" href="sec-FontSelectionDialog.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-FileSelections"></a>9.14. File Selections</h2></div></div><div></div></div><p>The file selection widget is a quick and simple way to display a
+File dialog box. It comes complete with <span class="guibutton">Ok</span>,
+<span class="guibutton">Cancel</span>, and <span class="guibutton">Help</span> buttons, a
+great way to cut down on programming time.</p><p>To create a new file selection box use:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ filesel = gtk.FileSelection(<b class="parameter"><tt>title</tt></b>=None)
+</pre></td></tr></table><p>To set the filename, for example to bring up a specific
+directory, or give a default filename, use this method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ filesel.set_filename(<b class="parameter"><tt>filename</tt></b>)
+</pre></td></tr></table><p>To grab the filename text that the user has entered or clicked
+on, use this method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ filename = filesel.get_filename()
+</pre></td></tr></table><p>There are also references to the widgets contained within the file
+selection widget. These are the filesel attributes:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ filesel.dir_list
+ filesel.file_list
+ filesel.selection_entry
+ filesel.selection_text
+ filesel.main_vbox
+ filesel.ok_button
+ filesel.cancel_button
+ filesel.help_button
+ filesel.history_pulldown
+ filesel.history_menu
+ filesel.fileop_dialog
+ filesel.fileop_entry
+ filesel.fileop_file
+ filesel.fileop_c_dir
+ filesel.fileop_del_file
+ filesel.fileop_ren_file
+ filesel.button_area
+ filesel.action_area
+</pre></td></tr></table><p>Most likely you will want to use the
+<i class="parameter"><tt>ok_button</tt></i>, <i class="parameter"><tt>cancel_button</tt></i>, and
+<i class="parameter"><tt>help_button</tt></i> attributes to connect their widget
+signals to callbacks.</p><p>The <a href="examples/filesel.py" target="_top"><span><b class="command">filesel.py</b></span></a> example
+program illustrates the use of the FileSelection widget. As you will see,
+there is nothing much to creating a file selection widget. While in this
+example the <span class="guibutton">Help</span> button appears on the screen, it
+does nothing as there is not a signal attached to it. <a href="sec-FileSelections.html#fileselfig" title="Figure 9.14. File Selection Example">Figure 9.14, “File Selection Exampleâ€</a> shows the resulting display:</p><div class="figure"><a name="fileselfig"></a><p class="title"><b>Figure 9.14. File Selection Example</b></p><div class="mediaobject" align="center"><img src="figures/fileselection.png" align="middle" alt="File Selection Example"></div></div><p>The source code for filesel.py is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 1 #!/usr/bin/env python
+ 2
+ 3 # example filesel.py
+ 4
+ 5 import pygtk
+ 6 pygtk.require('2.0')
+ 7 import gtk
+ 8
+ 9 class FileSelectionExample:
+ 10 # Get the selected filename and print it to the console
+ 11 def file_ok_sel(self, w):
+ 12 print "%s" % self.filew.get_filename()
+ 13
+ 14 def destroy(self, widget):
+ 15 gtk.main_quit()
+ 16
+ 17 def __init__(self):
+ 18 # Create a new file selection widget
+ 19 self.filew = gtk.FileSelection("File selection")
+ 20
+ 21 self.filew.connect("destroy", self.destroy)
+ 22 # Connect the ok_button to file_ok_sel method
+ 23 self.filew.ok_button.connect("clicked", self.file_ok_sel)
+ 24
+ 25 # Connect the cancel_button to destroy the widget
+ 26 self.filew.cancel_button.connect("clicked",
+ 27 lambda w: self.filew.destroy())
+ 28
+ 29 # Lets set the filename, as if this were a save dialog,
+ 30 # and we are giving a default filename
+ 31 self.filew.set_filename("penguin.png")
+ 32
+ 33 self.filew.show()
+ 34
+ 35 def main():
+ 36 gtk.main()
+ 37 return 0
+ 38
+ 39 if __name__ == "__main__":
+ 40 FileSelectionExample()
+ 41 main()
+</pre></td></tr></table></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-ColorSelection.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-MiscellaneousWidgets.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-FontSelectionDialog.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">9.13. Color Selection </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 9.15. Font Selection Dialog</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-Fixed.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-Fixed.html
new file mode 100644
index 0000000..863c185
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-Fixed.html
@@ -0,0 +1,77 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>10.3. Fixed Container</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-ContainerWidgets.html" title="Chapter 10. Container Widgets"><link rel="previous" href="sec-Alignment.html" title="10.2. The Alignment widget"><link rel="next" href="sec-Layout.html" title="10.4. Layout Container"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">10.3. Fixed Container</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-Alignment.html">Prev</a> </td><th width="60%" align="center">Chapter 10. Container Widgets</th><td width="20%" align="right"> <a accesskey="n" href="sec-Layout.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-Fixed"></a>10.3. Fixed Container</h2></div></div><div></div></div><p>The <tt class="classname">Fixed</tt> container allows you to place
+widgets at a fixed position within it's window, relative to it's upper left
+hand corner. The position of the widgets can be changed dynamically.</p><p>There are only three calls associated with the fixed
+widget:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ fixed = gtk.Fixed()
+
+ fixed.put(<b class="parameter"><tt>widget</tt></b>, <b class="parameter"><tt>x</tt></b>, <b class="parameter"><tt>y</tt></b>)
+
+ fixed.move(<b class="parameter"><tt>widget</tt></b>, <b class="parameter"><tt>x</tt></b>, <b class="parameter"><tt>y</tt></b>)
+</pre></td></tr></table><p>The function <tt class="function">gtk.Fixed</tt>() allows you to
+create a new <tt class="classname">Fixed</tt> container.</p><p>The <tt class="methodname">put</tt>() method places widget in the
+container fixed at the position specified by <i class="parameter"><tt>x</tt></i> and
+<i class="parameter"><tt>y</tt></i>.</p><p>The <tt class="methodname">move</tt>() method allows the specified
+widget to be moved to a new position.</p><p>The <a href="examples/fixed.py" target="_top"><span><b class="command">fixed.py</b></span></a> example
+illustrates how to use the <tt class="classname">Fixed</tt> container.
+<a href="sec-Fixed.html#fixedfig" title="Figure 10.2. Fixed Example">Figure 10.2, “Fixed Exampleâ€</a> shows the result:</p><div class="figure"><a name="fixedfig"></a><p class="title"><b>Figure 10.2. Fixed Example</b></p><div class="mediaobject" align="center"><img src="figures/fixed.png" align="middle" alt="Fixed Example"></div></div><p>The source code for <a href="examples/fixed.py" target="_top"><span><b class="command">fixed.py</b></span></a>:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 1 #!/usr/bin/env python
+ 2
+ 3 # example fixed.py
+ 4
+ 5 import pygtk
+ 6 pygtk.require('2.0')
+ 7 import gtk
+ 8
+ 9 class FixedExample:
+ 10 # This callback method moves the button to a new position
+ 11 # in the Fixed container.
+ 12 def move_button(self, widget):
+ 13 self.x = (self.x+30)%300
+ 14 self.y = (self.y+50)%300
+ 15 self.fixed.move(widget, self.x, self.y)
+ 16
+ 17 def __init__(self):
+ 18 self.x = 50
+ 19 self.y = 50
+ 20
+ 21 # Create a new window
+ 22 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ 23 window.set_title("Fixed Container")
+ 24
+ 25 # Here we connect the "destroy" event to a signal handler
+ 26 window.connect("destroy", lambda w: gtk.main_quit())
+ 27
+ 28 # Sets the border width of the window.
+ 29 window.set_border_width(10)
+ 30
+ 31 # Create a Fixed Container
+ 32 self.fixed = gtk.Fixed()
+ 33 window.add(self.fixed)
+ 34 self.fixed.show()
+ 35
+ 36 for i in range(1, 4):
+ 37 # Creates a new button with the label "Press me"
+ 38 button = gtk.Button("Press me")
+ 39
+ 40 # When the button receives the "clicked" signal, it will call the
+ 41 # method move_button().
+ 42 button.connect("clicked", self.move_button)
+ 43
+ 44 # This packs the button into the fixed containers window.
+ 45 self.fixed.put(button, i*50, i*50)
+ 46
+ 47 # The final step is to display this newly created widget.
+ 48 button.show()
+ 49
+ 50 # Display the window
+ 51 window.show()
+ 52
+ 53 def main():
+ 54 # Enter the event loop
+ 55 gtk.main()
+ 56 return 0
+ 57
+ 58 if __name__ == "__main__":
+ 59 FixedExample()
+ 60 main()
+</pre></td></tr></table></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-Alignment.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-ContainerWidgets.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-Layout.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">10.2. The Alignment widget </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 10.4. Layout Container</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-FontSelectionDialog.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-FontSelectionDialog.html
new file mode 100644
index 0000000..903070a
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-FontSelectionDialog.html
@@ -0,0 +1,58 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>9.15. Font Selection Dialog</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-MiscellaneousWidgets.html" title="Chapter 9. Miscellaneous Widgets"><link rel="previous" href="sec-FileSelections.html" title="9.14. File Selections"><link rel="next" href="ch-ContainerWidgets.html" title="Chapter 10. Container Widgets"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">9.15. Font Selection Dialog</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-FileSelections.html">Prev</a> </td><th width="60%" align="center">Chapter 9. Miscellaneous Widgets</th><td width="20%" align="right"> <a accesskey="n" href="ch-ContainerWidgets.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-FontSelectionDialog"></a>9.15. Font Selection Dialog</h2></div></div><div></div></div><p>The Font Selection Dialog allows a user to interactively select
+a font for use within your program. The dialog contains a
+<tt class="classname">FontSelection</tt> widget and <span class="guibutton">OK</span>
+and <span class="guibutton">Cancel</span> buttons. An <span class="guibutton">Apply</span>
+button is also available in the dialog but is initially hidden. The Font
+Selection Dialog allows a user to select a font from the available system
+fonts (the same ones that can be retrieved using
+<span><b class="command">xlsfonts</b></span>).</p><p><a href="sec-FontSelectionDialog.html#fontselfig" title="Figure 9.15. Font Selection Dialog">Figure 9.15, “Font Selection Dialogâ€</a> illustrates the
+<tt class="classname">FontSelectionDialog</tt> display:</p><div class="figure"><a name="fontselfig"></a><p class="title"><b>Figure 9.15. Font Selection Dialog</b></p><div class="mediaobject" align="center"><img src="figures/fontselection.png" align="middle" alt="Font Selection Dialog"></div></div><p>The dialog contains a set of three notebook pages that
+provide:</p><div class="itemizedlist"><ul type="disc"><li><p>an interface to select the font, font style and font
+size</p></li><li><p>detailed information about the currently selected font</p></li><li><p>an interface to the font filter mechanism that restricts the
+fonts available for selection</p></li></ul></div><p>The function to create a
+<tt class="classname">FontSelectionDialog</tt> is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ fontseldlg = gtk.FontSelectionDialog(<b class="parameter"><tt>title</tt></b>)
+</pre></td></tr></table><p>The <i class="parameter"><tt>title</tt></i> is a string that will be used to
+set the titlebar text.</p><p>A Font Selection Dialog instance has several attributes:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ fontsel
+ main_vbox
+ action_area
+ ok_button
+ apply_button
+ cancel_button
+</pre></td></tr></table><p>The <i class="parameter"><tt>fontsel</tt></i> attribute provides a
+reference to the Font Selection widget.<i class="parameter"><tt> main_vbox</tt></i> is
+a reference to the <tt class="classname">gtk.VBox</tt> containing the
+<i class="parameter"><tt>fontsel</tt></i> and the <i class="parameter"><tt>action_area</tt></i> in
+the dialog. The <i class="parameter"><tt>action_area</tt></i> attribute is a reference
+to the <tt class="classname">gtk.HButtonBox</tt> that contains the
+<span class="guibutton">OK</span>, <span class="guibutton">Apply</span> and
+<span class="guibutton">Cancel</span> buttons. The <i class="parameter"><tt>ok_button</tt></i>,
+<i class="parameter"><tt>cancel_button</tt></i> and <i class="parameter"><tt>apply_button</tt></i>
+attributes provide references to the <span class="guibutton">OK</span>,
+<span class="guibutton">Apply</span> and <span class="guibutton">Cancel</span> buttons that
+can be used to set connections to the button signals. The
+<i class="parameter"><tt>apply_button</tt></i> reference can also be used to
+<tt class="methodname">show</tt>() the <span class="guibutton">Apply</span>
+button.</p><p>You can set the initial font to be displayed in the
+<i class="parameter"><tt>fontseldlg</tt></i> by using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ fontseldlg.set_font_name(<b class="parameter"><tt>fontname</tt></b>)
+</pre></td></tr></table><p>The <i class="parameter"><tt>fontname</tt></i> argument is the name of a
+completely specified or partially specified system font. For example:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ fontseldlg.set_font_name('-adobe-courier-bold-*-*-*-*-120-*-*-*-*-*-*')
+</pre></td></tr></table><p>partially specifies the initial font.</p><p>The font name of the currently selected font can be retrieved
+using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ font_name = fontseldlg.get_font_name()
+</pre></td></tr></table><p>The Font Selection Dialog has a Preview area that displays text
+using the currently selected font. The text that is used in the Preview area
+can be set with the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ fontseldlg.set_preview_text(<b class="parameter"><tt>text</tt></b>)
+</pre></td></tr></table><p>The preview text can be retrieved with the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ text = fontseldlg.get_preview_text()
+</pre></td></tr></table><p>The <a href="examples/calendar.py" target="_top"><span><b class="command">calendar.py</b></span></a> example
+program uses a Font Selection Dialog to select the font to display the
+calendar information. Lines 105-110 define a callback that retrieves the
+font name from the Font Selection Dialog and uses it to set the font for the
+calendar widget. Lines 112-131 defines the method that creates the Font
+Selection Dialog, sets up the callbacks for the <span class="guibutton">OK</span>
+and <span class="guibutton">Cancel</span> buttons and displays the dialog.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-FileSelections.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-MiscellaneousWidgets.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch-ContainerWidgets.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">9.14. File Selections </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 10. Container Widgets</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-Frames.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-Frames.html
new file mode 100644
index 0000000..114ed22
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-Frames.html
@@ -0,0 +1,80 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>10.5. Frames</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-ContainerWidgets.html" title="Chapter 10. Container Widgets"><link rel="previous" href="sec-Layout.html" title="10.4. Layout Container"><link rel="next" href="sec-AspectFrames.html" title="10.6. Aspect Frames"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">10.5. Frames</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-Layout.html">Prev</a> </td><th width="60%" align="center">Chapter 10. Container Widgets</th><td width="20%" align="right"> <a accesskey="n" href="sec-AspectFrames.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-Frames"></a>10.5. Frames</h2></div></div><div></div></div><p>Frames can be used to enclose one or a group of widgets with a
+box which can optionally be labeled. The position of the label and the
+style of the box can be altered to suit.</p><p>A <tt class="classname">Frame</tt> can be created with the following
+function:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ frame = gtk.Frame(<b class="parameter"><tt>label</tt></b>=None)
+</pre></td></tr></table><p>The <i class="parameter"><tt>label</tt></i> is by default placed in the
+upper left hand corner of the frame. Specifying a value of None for the
+<i class="parameter"><tt>label</tt></i> argument or specifying no
+<i class="parameter"><tt>label</tt></i> argument will result in no label being
+displayed. The text of the label can be changed using the method.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ frame.set_label(<b class="parameter"><tt>label</tt></b>)
+</pre></td></tr></table><p>The position of the label can be changed using this
+method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ frame.set_label_align(<b class="parameter"><tt>xalign</tt></b>, <b class="parameter"><tt>yalign</tt></b>)
+</pre></td></tr></table><p><i class="parameter"><tt>xalign</tt></i> and <i class="parameter"><tt>yalign</tt></i>
+take values between 0.0 and 1.0. <i class="parameter"><tt>xalign</tt></i> indicates the
+position of the label along the top horizontal of the frame.
+<i class="parameter"><tt>yalign</tt></i> is not currently used. The default value of
+<i class="parameter"><tt>xalign</tt></i> is 0.0 which places the label at the left hand
+end of the frame.</p><p>The next method alters the style of the box that is used to
+outline the frame.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ frame.set_shadow_type(<b class="parameter"><tt>type</tt></b>)
+</pre></td></tr></table><p>The <i class="parameter"><tt>type</tt></i> argument can take one of the
+following values:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ SHADOW_NONE
+ SHADOW_IN
+ SHADOW_OUT
+ SHADOW_ETCHED_IN # the default
+ SHADOW_ETCHED_OUT
+</pre></td></tr></table><p>The <a href="examples/frame.py" target="_top"><span><b class="command">frame.py</b></span></a> example
+illustrates the use of the Frame widget.
+<a href="sec-Frames.html#framefig" title="Figure 10.4. Frame Example">Figure 10.4, “Frame Exampleâ€</a> shows the resulting display:</p><div class="figure"><a name="framefig"></a><p class="title"><b>Figure 10.4. Frame Example</b></p><div class="mediaobject" align="center"><img src="figures/frame.png" align="middle" alt="Frame Example"></div></div><p>The source code of <a href="examples/frame.py" target="_top"><span><b class="command">frame.py</b></span></a> is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 1 #!/usr/bin/env python
+ 2
+ 3 # example frame.py
+ 4
+ 5 import pygtk
+ 6 pygtk.require('2.0')
+ 7 import gtk
+ 8
+ 9 class FrameExample:
+ 10 def __init__(self):
+ 11 # Create a new window
+ 12 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ 13 window.set_title("Frame Example")
+ 14
+ 15 # Here we connect the "destroy" event to a signal handler
+ 16 window.connect("destroy", lambda w: gtk.main_quit())
+ 17 window.set_size_request(300, 300)
+ 18
+ 19 # Sets the border width of the window.
+ 20 window.set_border_width(10)
+ 21
+ 22 # Create a Frame
+ 23 frame = gtk.Frame()
+ 24 window.add(frame)
+ 25
+ 26 # Set the frame's label
+ 27 frame.set_label("GTK Frame Widget")
+ 28
+ 29 # Align the label at the right of the frame
+ 30 frame.set_label_align(1.0, 0.0)
+ 31
+ 32 # Set the style of the frame
+ 33 frame.set_shadow_type(gtk.SHADOW_ETCHED_OUT)
+ 34 frame.show()
+ 35
+ 36 # Display the window
+ 37 window.show()
+ 38
+ 39 def main():
+ 40 # Enter the event loop
+ 41 gtk.main()
+ 42 return 0
+ 43
+ 44 if __name__ == "__main__":
+ 45 FrameExample()
+ 46 main()
+</pre></td></tr></table><p>The <a href="examples/calendar.py" target="_top"><span><b class="command">calendar.py</b></span></a>, <a href="examples/label.py" target="_top"><span><b class="command">label.py</b></span></a> and <a href="examples/spinbutton.py" target="_top"><span><b class="command">spinbutton.py</b></span></a>
+examples also use Frames.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-Layout.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-ContainerWidgets.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-AspectFrames.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">10.4. Layout Container </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 10.6. Aspect Frames</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-GTKRcFileFormat.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-GTKRcFileFormat.html
new file mode 100644
index 0000000..c9aa0c0
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-GTKRcFileFormat.html
@@ -0,0 +1,51 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>23.2. GTK's rc File Format</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-GtkRcFiles.html" title="Chapter 23. GTK's rc Files"><link rel="previous" href="ch-GtkRcFiles.html" title="Chapter 23. GTK's rc Files"><link rel="next" href="sec-ExampleRcFile.html" title="23.3. Example rc file"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">23.2. GTK's rc File Format</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch-GtkRcFiles.html">Prev</a> </td><th width="60%" align="center">Chapter 23. GTK's rc Files</th><td width="20%" align="right"> <a accesskey="n" href="sec-ExampleRcFile.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-GTKRcFileFormat"></a>23.2. GTK's rc File Format</h2></div></div><div></div></div><p>The format of the GTK+ rc file is illustrated in <a href="sec-ExampleRcFile.html" title="23.3. Example rc file">Section 23.3, “Example rc fileâ€</a> below. This is the
+<tt class="filename">testgtkrc</tt> file from the GTK+ distribution, but I've
+added a few comments and things. You may wish to include this explanation in
+your application to allow the user to fine tune his application.</p><p>There are several directives to change the attributes of a
+widget.</p><div class="itemizedlist"><ul type="none"><li style="list-style-type: none"><p><i class="parameter"><tt>fg</tt></i> - Sets the foreground color of a
+widget.</p></li><li style="list-style-type: none"><p><i class="parameter"><tt>bg</tt></i> - Sets the background color of a
+widget.</p></li><li style="list-style-type: none"><p><i class="parameter"><tt>bg_pixmap</tt></i> - Sets the background of a
+widget to a tiled pixmap.</p></li><li style="list-style-type: none"><p><i class="parameter"><tt>font</tt></i> - Sets the font to be used with the
+given widget.</p></li></ul></div><p>In addition to this, there are several states a widget can be
+in, and you can set different colors, pixmaps and fonts for each state.
+These states are:</p><table border="0" width="100%" bgcolor="#FFECCE"><col align="left" valign="top" width="0*"><tbody><tr><td><span class="term">NORMAL</span></td><td><p>The normal state of a widget, without the mouse over top
+of it, and not being pressed, etc.</p></td></tr><tr><td><span class="term">PRELIGHT</span></td><td><p>When the mouse is over top of the widget, colors defined
+using this state will be in effect.</p></td></tr><tr><td><span class="term">ACTIVE</span></td><td><p> When the widget is pressed or clicked it will be active,
+and the attributes assigned by this tag will be in effect.</p></td></tr><tr><td><span class="term">INSENSITIVE</span></td><td><p>When a widget is set insensitive, and cannot be activated,
+it will take these attributes.</p></td></tr><tr><td><span class="term">SELECTED</span></td><td><p>When an object is selected, it takes these
+attributes.</p></td></tr></tbody></table><p>When using the "fg" and "bg" keywords to set the colors of
+widgets, the format is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ fg[&lt;STATE&gt;] = { Red, Green, Blue }
+</pre></td></tr></table><p>Where <tt class="varname">STATE</tt> is one of the above states
+(PRELIGHT, ACTIVE, etc), and the <tt class="varname">Red</tt>,
+<tt class="varname">Green</tt> and <tt class="varname">Blue</tt> are values in the range
+of 0 - 1.0, { 1.0, 1.0, 1.0 } being white. They must be in float form, or
+they will register as 0, so a straight "1" will not work, it must be "1.0".
+A straight "0" is fine because it doesn't matter if it's not recognized.
+Unrecognized values are set to 0.</p><p><i class="parameter"><tt>bg_pixmap</tt></i> is very similar to the above,
+except the colors are replaced by a filename.</p><p><i class="parameter"><tt>pixmap_path</tt></i> is a list of paths separated by
+":"'s. These paths will be searched for any pixmap you specify.</p><p>The "font" directive is simply:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ font = "&lt;font name&gt;"
+</pre></td></tr></table><p>The only hard part is figuring out the <i class="parameter"><tt>font</tt></i>
+string. Using <span><b class="command">xfontsel</b></span> or a similar utility should
+help.</p><p>The "widget_class" sets the style of a class of widgets. These
+classes are listed in the widget overview in <a href="ch-WidgetOverview.html#sec-WidgetHierarchy" title="5.1. Widget Hierarchy">Section 5.1, “Widget Hierarchyâ€</a>.</p><p>The "widget" directive sets a specifically named set of widgets
+to a given style, overriding any style set for the given widget class. These
+widgets are registered inside the application using the
+<tt class="methodname">set_name</tt>() method. This allows you to specify the
+attributes of a widget on a per widget basis, rather than setting the
+attributes of an entire widget class. I urge you to document any of these
+special widgets so users may customize them.</p><p>When the keyword <i class="parameter"><tt>parent</tt></i> is used as an
+attribute, the widget will take on the attributes of its parent in the
+application.</p><p>When defining a style, you may assign the attributes of a
+previously defined style to this new one.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ style "main_button" = "button"
+ {
+ font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
+ bg[PRELIGHT] = { 0.75, 0, 0 }
+ }
+</pre></td></tr></table><p>This example takes the "button" style, and creates a new
+"main_button" style simply by changing the font and prelight background
+color of the "button" style.</p><p>Of course, many of these attributes don't apply to all widgets.
+It's a simple matter of common sense really. Anything that could apply,
+should.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch-GtkRcFiles.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-GtkRcFiles.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-ExampleRcFile.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 23. GTK's rc Files </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 23.3. Example rc file</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-GammaCurve.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-GammaCurve.html
new file mode 100644
index 0000000..2d834be
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-GammaCurve.html
@@ -0,0 +1 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>17.6. Gamma Curve</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-UndocumentedWidgets.html" title="Chapter 17. Undocumented Widgets"><link rel="previous" href="sec-MessageDialog.html" title="17.5. Message Dialog"><link rel="next" href="ch-SettingWidgetAttributes.html" title="Chapter 18. Setting Widget Attributes"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">17.6. Gamma Curve</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-MessageDialog.html">Prev</a> </td><th width="60%" align="center">Chapter 17. Undocumented Widgets</th><td width="20%" align="right"> <a accesskey="n" href="ch-SettingWidgetAttributes.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-GammaCurve"></a>17.6. Gamma Curve</h2></div></div><div></div></div><p></p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-MessageDialog.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-UndocumentedWidgets.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch-SettingWidgetAttributes.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">17.5. Message Dialog </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 18. Setting Widget Attributes</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-GenericCellRenderer.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-GenericCellRenderer.html
new file mode 100644
index 0000000..2b99eb4
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-GenericCellRenderer.html
@@ -0,0 +1 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>14.12. The Generic CellRenderer</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-TreeViewWidget.html" title="Chapter 14. Tree View Widget"><link rel="previous" href="sec-GenericTreeModel.html" title="14.11. The Generic TreeModel"><link rel="next" href="ch-NewInPyGTK2.2.html" title="Chapter 15. New Widgets in PyGTK 2.2"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">14.12. The Generic CellRenderer</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-GenericTreeModel.html">Prev</a> </td><th width="60%" align="center">Chapter 14. Tree View Widget</th><td width="20%" align="right"> <a accesskey="n" href="ch-NewInPyGTK2.2.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-GenericCellRenderer"></a>14.12. The Generic CellRenderer</h2></div></div><div></div></div><p></p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-GenericTreeModel.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-TreeViewWidget.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch-NewInPyGTK2.2.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">14.11. The Generic TreeModel </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 15. New Widgets in PyGTK 2.2</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-GenericTreeModel.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-GenericTreeModel.html
new file mode 100644
index 0000000..80a30e0
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-GenericTreeModel.html
@@ -0,0 +1,384 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>14.11. The Generic TreeModel</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-TreeViewWidget.html" title="Chapter 14. Tree View Widget"><link rel="previous" href="sec-TreeModelSortAndTreeModelFilter.html" title="14.10. TreeModelSort and TreeModelFilter"><link rel="next" href="sec-GenericCellRenderer.html" title="14.12. The Generic CellRenderer"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">14.11. The Generic TreeModel</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-TreeModelSortAndTreeModelFilter.html">Prev</a> </td><th width="60%" align="center">Chapter 14. Tree View Widget</th><td width="20%" align="right"> <a accesskey="n" href="sec-GenericCellRenderer.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-GenericTreeModel"></a>14.11. The Generic TreeModel</h2></div></div><div></div></div><p>When you find that the standard <tt class="classname">TreeModel</tt>s
+are not sufficiently powerful for your application needs, you can use the
+<tt class="classname">GenericTreeModel</tt> to build your own custom
+<tt class="classname">TreeModel</tt> in Python. Creating a
+<tt class="classname">GenericTreeModel</tt> may be useful when there are
+performance issues with the standard <tt class="classname">TreeStore</tt> and
+<tt class="classname">ListStore</tt> objects or when you want to directly
+interface to an external data source (say, a database or filesystem) to save
+copying the data into and out of a <tt class="classname">TreeStore</tt> or
+<tt class="classname">ListStore</tt>.</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-GenericTreeModelOverview"></a>14.11.1. GenericTreeModel Overview</h3></div></div><div></div></div><p> With the <tt class="classname">GenericTreeModel</tt> you build and
+manage your data model and provide external access though the standard
+<tt class="classname">TreeModel</tt> interface by defining a set of class
+methods. PyGTK implements the <tt class="classname">TreeModel</tt> interface and
+arranges for your <tt class="classname">TreeModel</tt> methods to be called to
+provide the actual model data.</p><p>The implementation details of your model should be kept completely
+hidden from the external application. This means that the way that your
+model identifies, stores and retrieves data is unknown to the
+application. In general the only information that is saved outside your
+<tt class="classname">GenericTreeModel</tt> are the row references that are
+wrapped by the external <tt class="classname">TreeIter</tt>s. And these
+references are not visible to the application.</p><p>Let's examine in detail the
+<tt class="classname">GenericTreeModel</tt> interface that you have to
+provide.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-GenericTreeModelInterface"></a>14.11.2. The GenericTreeModel Interface</h3></div></div><div></div></div><p>The <tt class="classname">GenericTreeModel</tt> interface consists of
+the following methods that must be implemented in your custom tree
+model:</p><code class="methodsynopsis"> def <span class="methodname">on_get_flags</span>(<span class="methodparam"><span class="parameter"><i class="parameter"><tt>self</tt></i></span></span>)</code><br><code class="methodsynopsis"> def <span class="methodname">on_get_n_columns</span>(<span class="methodparam"><span class="parameter"><i class="parameter"><tt>self</tt></i></span></span>)</code><br><code class="methodsynopsis"> def <span class="methodname">on_get_column_type</span>(<span class="methodparam"><span class="parameter"><i class="parameter"><tt>self</tt></i></span></span>, <span class="methodparam"><span class="parameter"><i class="parameter"><tt>index</tt></i></span></span>)</code><br><code class="methodsynopsis"> def <span class="methodname">on_get_iter</span>(<span class="methodparam"><span class="parameter"><i class="parameter"><tt>self</tt></i></span></span>, <span class="methodparam"><span class="parameter"><i class="parameter"><tt>path</tt></i></span></span>)</code><br><code class="methodsynopsis"> def <span class="methodname">on_get_path</span>(<span class="methodparam"><span class="parameter"><i class="parameter"><tt>self</tt></i></span></span>, <span class="methodparam"><span class="parameter"><i class="parameter"><tt>rowref</tt></i></span></span>)</code><br><code class="methodsynopsis"> def <span class="methodname">on_get_value</span>(<span class="methodparam"><span class="parameter"><i class="parameter"><tt>self</tt></i></span></span>, <span class="methodparam"><span class="parameter"><i class="parameter"><tt>rowref</tt></i></span></span>, <span class="methodparam"><span class="parameter"><i class="parameter"><tt>column</tt></i></span></span>)</code><br><code class="methodsynopsis"> def <span class="methodname">on_iter_next</span>(<span class="methodparam"><span class="parameter"><i class="parameter"><tt>self</tt></i></span></span>, <span class="methodparam"><span class="parameter"><i class="parameter"><tt>rowref</tt></i></span></span>)</code><br><code class="methodsynopsis"> def <span class="methodname">on_iter_children</span>(<span class="methodparam"><span class="parameter"><i class="parameter"><tt>self</tt></i></span></span>, <span class="methodparam"><span class="parameter"><i class="parameter"><tt>parent</tt></i></span></span>)</code><br><code class="methodsynopsis"> def <span class="methodname">on_iter_has_child</span>(<span class="methodparam"><span class="parameter"><i class="parameter"><tt>self</tt></i></span></span>, <span class="methodparam"><span class="parameter"><i class="parameter"><tt>rowref</tt></i></span></span>)</code><br><code class="methodsynopsis"> def <span class="methodname">on_iter_n_children</span>(<span class="methodparam"><span class="parameter"><i class="parameter"><tt>self</tt></i></span></span>, <span class="methodparam"><span class="parameter"><i class="parameter"><tt>rowref</tt></i></span></span>)</code><br><code class="methodsynopsis"> def <span class="methodname">on_iter_nth_child</span>(<span class="methodparam"><span class="parameter"><i class="parameter"><tt>self</tt></i></span></span>, <span class="methodparam"><span class="parameter"><i class="parameter"><tt>parent</tt></i></span></span>, <span class="methodparam"><span class="parameter"><i class="parameter"><tt>n</tt></i></span></span>)</code><br><code class="methodsynopsis"> def <span class="methodname">on_iter_parent</span>(<span class="methodparam"><span class="parameter"><i class="parameter"><tt>self</tt></i></span></span>, <span class="methodparam"><span class="parameter"><i class="parameter"><tt>child</tt></i></span></span>)</code><br><p>You should note that these methods support all of the
+<tt class="classname">TreeModel</tt> interface including:</p><code class="methodsynopsis"> def <span class="methodname">get_flags</span>(<span class="methodparam"></span>)</code><br><code class="methodsynopsis"> def <span class="methodname">get_n_columns</span>(<span class="methodparam"></span>)</code><br><code class="methodsynopsis"> def <span class="methodname">get_column_type</span>(<span class="methodparam"><span class="parameter"><b class="parameter"><tt>index</tt></b></span></span>)</code><br><code class="methodsynopsis"> def <span class="methodname">get_iter</span>(<span class="methodparam"><span class="parameter"><b class="parameter"><tt>path</tt></b></span></span>)</code><br><code class="methodsynopsis"> def <span class="methodname">get_iter_from_string</span>(<span class="methodparam"><span class="parameter"><b class="parameter"><tt>path_string</tt></b></span></span>)</code><br><code class="methodsynopsis"> def <span class="methodname">get_string_from_iter</span>(<span class="methodparam"><span class="parameter"><i class="parameter"><tt>iter</tt></i></span></span>)</code><br><code class="methodsynopsis"> def <span class="methodname">get_iter_root</span>(<span class="methodparam"></span>)</code><br><code class="methodsynopsis"> def <span class="methodname">get_iter_first</span>(<span class="methodparam"></span>)</code><br><code class="methodsynopsis"> def <span class="methodname">get_path</span>(<span class="methodparam"><span class="parameter"><b class="parameter"><tt>iter</tt></b></span></span>)</code><br><code class="methodsynopsis"> def <span class="methodname">get_value</span>(<span class="methodparam"><span class="parameter"><b class="parameter"><tt>iter</tt></b></span></span>, <span class="methodparam"><span class="parameter"><b class="parameter"><tt>column</tt></b></span></span>)</code><br><code class="methodsynopsis"> def <span class="methodname">iter_next</span>(<span class="methodparam"><span class="parameter"><b class="parameter"><tt>iter</tt></b></span></span>)</code><br><code class="methodsynopsis"> def <span class="methodname">iter_children</span>(<span class="methodparam"><span class="parameter"><b class="parameter"><tt>parent</tt></b></span></span>)</code><br><code class="methodsynopsis"> def <span class="methodname">iter_has_child</span>(<span class="methodparam"><span class="parameter"><b class="parameter"><tt>iter</tt></b></span></span>)</code><br><code class="methodsynopsis"> def <span class="methodname">iter_n_children</span>(<span class="methodparam"><span class="parameter"><b class="parameter"><tt>iter</tt></b></span></span>)</code><br><code class="methodsynopsis"> def <span class="methodname">iter_nth_child</span>(<span class="methodparam"><span class="parameter"><b class="parameter"><tt>parent</tt></b></span></span>, <span class="methodparam"><span class="parameter"><b class="parameter"><tt>n</tt></b></span></span>)</code><br><code class="methodsynopsis"> def <span class="methodname">iter_parent</span>(<span class="methodparam"><span class="parameter"><b class="parameter"><tt>child</tt></b></span></span>)</code><br><code class="methodsynopsis"> def <span class="methodname">get</span>(<span class="methodparam"><span class="parameter"><i class="parameter"><tt>iter</tt></i></span></span>, <span class="methodparam"><span class="parameter"><i class="parameter"><tt>column</tt></i></span></span>, <span class="methodparam"><span class="parameter"><i class="parameter"><tt>...</tt></i></span></span>)</code><br><code class="methodsynopsis"> def <span class="methodname">foreach</span>(<span class="methodparam"><span class="parameter"><i class="parameter"><tt>func</tt></i></span></span>, <span class="methodparam"><span class="parameter"><i class="parameter"><tt>user_data</tt></i></span></span>)</code><p>To illustrate the use of the
+<tt class="classname">GenericTreeModel</tt> I'll change the <a href="examples/filelisting.py" target="_top"><span><b class="command">filelisting.py</b></span></a>
+example program and show how the interface methods are created. The <a href="examples/filelisting-gtm.py" target="_top"><span><b class="command">filelisting-gtm.py</b></span></a>
+program displays the files in a folder with a pixbuf indicating if the file
+is a folder or not, the file name, the file size, mode and time of last
+change.</p><p>The <tt class="methodname">on_get_flags</tt>() method
+should return a value that is a combination of:</p><table border="0" width="100%" bgcolor="#FFECCE"><col align="left" valign="top" width="0*"><tbody><tr><td><span class="term"><tt class="literal">gtk.TREE_MODEL_ITERS_PERSIST</tt></span></td><td><tt class="classname">TreeIter</tt>s survive all signals
+emitted by the tree.</td></tr><tr><td><span class="term"><tt class="literal">gtk.TREE_MODEL_LIST_ONLY</tt></span></td><td>The model is a list only, and never has
+children</td></tr></tbody></table><p>If your model has row references that are valid over row changes
+(reorder, addition, deletion) then set
+<tt class="literal">gtk.TREE_MODEL_ITERS_PERSIST</tt>. Likewise if your model is a
+list only then set <tt class="literal">gtk.TREE_MODEL_LIST_ONLY</tt>. Otherwise,
+return 0 if your model doesn't have persistent row references and it's a
+tree model. For our example, the model is a list with persistent
+<tt class="classname">TreeIter</tt>s.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def on_get_flags(self):
+ return gtk.TREE_MODEL_LIST_ONLY|gtk.TREE_MODEL_ITERS_PERSIST
+</pre></td></tr></table><p>The <tt class="methodname">on_get_n_columns</tt>() method should
+return the number of columns that your model exports to the application. Our
+example maintains a list of column types so we return the length of the
+list:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+class FileListModel(gtk.GenericTreeModel):
+ ...
+ column_types = (gtk.gdk.Pixbuf, str, long, str, str)
+ ...
+ def on_get_n_columns(self):
+ return len(self.column_types)
+</pre></td></tr></table><p>The <tt class="methodname">on_get_column_type</tt>() method should
+return the type of the column with the specified
+<i class="parameter"><tt>index</tt></i>. This method is usually called from a
+<tt class="classname">TreeView</tt> when its model is set. You can either create
+a list or tuple containing the column data type info or generate it
+on-the-fly. In our example:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def on_get_column_type(self, n):
+ return self.column_types[n]
+</pre></td></tr></table><p>The <tt class="classname">GenericTreeModel</tt> interface converts the
+Python type to a GType so the following code:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ flm = FileListModel()
+ print flm.on_get_column_type(1), flm.get_column_type(1)
+</pre></td></tr></table><p>would print:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+&lt;type 'str'&gt; &lt;GType gchararray (64)&gt;
+</pre></td></tr></table><p>The following methods use row references that are kept as private
+data in a <tt class="classname">TreeIter</tt>. The application can't see the row
+reference in a <tt class="classname">TreeIter</tt> so you can use any unique
+item you want as a row reference. For example in a model containing rows as
+tuples you could use the tuple id as the row reference. Another example
+would be to use a filename as the row reference in a model representing
+files in a directory. In both these cases, the row reference is unchanged by
+model changes so the <tt class="classname">TreeIter</tt>s could be flagged as
+persistent. The PyGTK <tt class="classname">GenericTreeModel</tt> application
+interface will extract your row references from
+<tt class="classname">TreeIter</tt>s and wrap your row references in
+<tt class="classname">TreeIter</tt>s as needed.</p><p>In the following methods <tt class="literal">rowref</tt> refers to an
+internal row reference.</p><p>The <tt class="methodname">on_get_iter</tt>() method should return an
+rowref for the tree path specified by <i class="parameter"><tt>path</tt></i>. The tree
+path will always be represented using a tuple. Our example uses the file
+name string as the rowref. The file names are kept in a list in the model so
+we take the first index of the path as an index to the file name:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def on_get_iter(self, path):
+ return self.files[path[0]]
+</pre></td></tr></table><p>You have to be consistent in your row reference usage since you'll
+get a row reference back in method calls from the
+<tt class="classname">GenericTreeModel</tt> methods that take
+<tt class="classname">TreeIter</tt> arguments:
+<tt class="methodname">on_get_path</tt>(),
+<tt class="methodname">on_get_value</tt>(),
+<tt class="methodname">on_iter_next</tt>(),
+<tt class="methodname">on_iter_children</tt>(),
+<tt class="methodname">on_iter_has_child</tt>(),
+<tt class="methodname">on_iter_n_children</tt>(),
+<tt class="methodname">on_iter_nth_child</tt>() and
+<tt class="methodname">on_iter_parent</tt>().</p><p>The <tt class="methodname">on_get_path</tt>() method should return a
+tree path given a rowref. For example, continuing the above example where
+the file name is used as the rowref, you could define the
+<tt class="methodname">on_get_path</tt>() method as:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def on_get_path(self, rowref):
+ return self.files.index(rowref)
+</pre></td></tr></table><p>This method finds the index of the list containing the file name
+in <i class="parameter"><tt>rowref</tt></i>. It's obvious from this example that a
+judicious choice of row reference will make the implementation more
+efficient. You could, for example, use a Python dict to map
+<i class="parameter"><tt>rowref</tt></i> to a path.</p><p>The <tt class="methodname">on_get_value</tt>() method should return
+the data stored at the row and column specified by
+<i class="parameter"><tt>rowref</tt></i> and <i class="parameter"><tt>column</tt></i>. For our
+example:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def on_get_value(self, rowref, column):
+ fname = os.path.join(self.dirname, rowref)
+ try:
+ filestat = statcache.stat(fname)
+ except OSError:
+ return None
+ mode = filestat.st_mode
+ if column is 0:
+ if stat.S_ISDIR(mode):
+ return folderpb
+ else:
+ return filepb
+ elif column is 1:
+ return rowref
+ elif column is 2:
+ return filestat.st_size
+ elif column is 3:
+ return oct(stat.S_IMODE(mode))
+ return time.ctime(filestat.st_mtime)
+</pre></td></tr></table><p>has to extract the associated file information and return the
+appropriate value depending on which column is specified.</p><p>The <tt class="methodname">on_iter_next</tt>() method should return a
+row reference to the row (at the same level) after the row specified by
+<i class="parameter"><tt>rowref</tt></i>. For our example:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def on_iter_next(self, rowref):
+ try:
+ i = self.files.index(rowref)+1
+ return self.files[i]
+ except IndexError:
+ return None
+</pre></td></tr></table><p>The index of the <i class="parameter"><tt>rowref</tt></i> file name is
+determined and the next file name is returned or <tt class="literal">None</tt> is
+returned if there is no next file.</p><p>The <tt class="methodname">on_iter_children</tt>() method should
+return a row reference to the first child row of the row specified by
+<i class="parameter"><tt>rowref</tt></i>. If <i class="parameter"><tt>rowref</tt></i> is
+<tt class="literal">None</tt>, a reference to the first top level row is
+returned. If there is no child row <tt class="literal">None</tt> is returned. For
+our example:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def on_iter_children(self, rowref):
+ if rowref:
+ return None
+ return self.files[0]
+</pre></td></tr></table><p>Since the model is a list model only the top level
+(<i class="parameter"><tt>rowref</tt></i>=<tt class="literal">None</tt>) can have child
+rows. <tt class="literal">None</tt> is returned if <i class="parameter"><tt>rowref</tt></i>
+contains a file name.</p><p>The <tt class="methodname">on_iter_has_child</tt>() method should
+return <tt class="literal">TRUE</tt> if the row specified by
+<i class="parameter"><tt>rowref</tt></i> has child rows; <tt class="literal">FALSE</tt>
+otherwise. Our example returns <tt class="literal">FALSE</tt> since no row can
+have a child:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def on_iter_has_child(self, rowref):
+ return False
+</pre></td></tr></table><p>The <tt class="methodname">on_iter_n_children</tt>() method should
+return the number of child rows that the row specified by
+<i class="parameter"><tt>rowref</tt></i> has. If <i class="parameter"><tt>rowref</tt></i> is
+<tt class="literal">None</tt>, the number of top level rows is returned. Our
+example returns 0 if <i class="parameter"><tt>rowref</tt></i> is not
+<tt class="literal">None</tt>:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def on_iter_n_children(self, rowref):
+ if rowref:
+ return 0
+ return len(self.files)
+</pre></td></tr></table><p>The <tt class="methodname">on_iter_nth_child</tt>() method should
+return a row reference to the nth child row of the row specified by
+<i class="parameter"><tt>parent</tt></i>. If <i class="parameter"><tt>parent</tt></i> is
+<tt class="literal">None</tt>, a reference to the nth top level row is
+returned. Our example returns the nth top level row reference if
+<i class="parameter"><tt>parent</tt></i> is <tt class="literal">None</tt>. Otherwise
+<tt class="literal">None</tt> is returned:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def on_iter_nth_child(self, rowref, n):
+ if rowref:
+ return None
+ try:
+ return self.files[n]
+ except IndexError:
+ return None
+</pre></td></tr></table><p>The <tt class="methodname">on_iter_parent</tt>() method should return
+a row reference to the parent row of the row specified by
+<i class="parameter"><tt>rowref</tt></i>. If <i class="parameter"><tt>rowref</tt></i> points to a
+top level row, <tt class="literal">None</tt> should be returned. Our example
+always returns <tt class="literal">None</tt> assuming that
+<i class="parameter"><tt>rowref</tt></i> must point to a top level row:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def on_iter_parent(child):
+ return None
+</pre></td></tr></table><p>This example is put together in the <a href="examples/filelisting-gtm.py" target="_top">filelisting-gtm.py</a>
+program. <a href="sec-GenericTreeModel.html#filelistinggtmfig" title="Figure 14.11. Generic TreeModel Example Program">Figure 14.11, “Generic TreeModel Example Programâ€</a> shows the result of running
+the program.</p><div class="figure"><a name="filelistinggtmfig"></a><p class="title"><b>Figure 14.11. Generic TreeModel Example Program</b></p><div class="mediaobject" align="center"><img src="figures/filelisting-gtm.png" align="middle" alt="Generic TreeModel Example Program"></div></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-AddRemoveGenericTreeModelRows"></a>14.11.3. Adding and Removing Rows</h3></div></div><div></div></div><p>The <a href="examples/filelisting-gtm.py" target="_top">filelisting-gtm.py</a> program
+calculates the list of file names while creating a
+<tt class="classname">FileListModel</tt> instance. If you want to check for new
+files periodically and add or remove files from the model you could either
+create a new <tt class="classname">FileListModel</tt> for the same folder or you
+could add methods to add and remove rows in the model. Depending on the type
+of model you are creating you would need to add methods similar to those in
+the <tt class="classname">TreeStore</tt> and <tt class="classname">ListStore</tt>
+models:</p><div class="itemizedlist"><ul type="disc"><li><tt class="methodname">insert</tt>()</li><li><tt class="methodname">insert_before</tt>()</li><li><tt class="methodname">insert_after</tt>()</li><li><tt class="methodname">prepend</tt>()</li><li><tt class="methodname">append</tt>()</li><li><tt class="methodname">remove</tt>()</li><li><tt class="methodname">clear</tt>()</li></ul></div><p>Of course not all or any of these need to be implemented. You can
+create your own methods that are more closely related to your model.</p><p>Using the above example program to illustrate adding methods for
+removing and adding files, let's implement the methods:</p><code class="methodsynopsis"> def <span class="methodname">remove</span>(<span class="methodparam"><span class="parameter"><b class="parameter"><tt>iter</tt></b></span></span>)</code><br><code class="methodsynopsis"> def <span class="methodname">add</span>(<span class="methodparam"><span class="parameter"><b class="parameter"><tt>filename</tt></b></span></span>)</code><br><p>The <tt class="methodname">remove</tt>() method removes the file
+specified by <i class="parameter"><tt>iter</tt></i>. In addition to removing the row
+from the model the method also should remove the file from the folder. Of
+course, if the user doesn't have the permissions to remove the file then the
+row shouldn't be removed either. For example:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def remove(self, iter):
+ path = self.get_path(iter)
+ pathname = self.get_pathname(path)
+ try:
+ if os.path.exists(pathname):
+ os.remove(pathname)
+ del self.files[path[0]]
+ self.row_deleted(path)
+ except OSError:
+ pass
+ return
+</pre></td></tr></table><p>The method is passed a <tt class="classname">TreeIter</tt> that has to
+be converted to a path to use to retrieve the file path using the method
+<tt class="methodname">get_pathname</tt>(). It's possible that the file has
+already been removed so we check if it exists before trying to remove it. If
+an OSError exception is thrown during the file removal it's probably because
+the file is a directory or the user doesn't have sufficient privilege to
+remove it. Finally, the file is removed and the "row-deleted" signal is
+emitted from the <tt class="methodname">rows_deleted</tt>() method. The
+"file-deleted" signal notifies the <tt class="classname">TreeView</tt>s using
+the model that the model has changed so that they can update their internal
+state and display the revised model.</p><p>The <tt class="methodname">add</tt>() method needs to create a file
+with the given name in the current folder. If the file was created its name
+is added to the list of files in the model. For example:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def add(self, filename):
+ pathname = os.path.join(self.dirname, filename)
+ if os.path.exists(pathname):
+ return
+ try:
+ fd = file(pathname, 'w')
+ fd.close()
+ self.dir_ctime = os.stat(self.dirname).st_ctime
+ files = self.files[1:] + [filename]
+ files.sort()
+ self.files = ['..'] + files
+ path = (self.files.index(filename),)
+ iter = self.get_iter(path)
+ self.row_inserted(path, iter)
+ except OSError:
+ pass
+ return
+</pre></td></tr></table><p>This simple example makes sure that the file doesn't exist then
+tries to open the file for writing. If successful, the file is closed and
+the file name sorted into the list of files. The path and
+<tt class="classname">TreeIter</tt> for the added file row are retrieved to use
+in the <tt class="methodname">row_inserted</tt>() method that emits the
+"row-inserted" signal. The "row-inserted" signal is used to notify the
+<tt class="classname">TreeView</tt>s using the model that they need to update
+their internal state and revise their display.</p><p>The other methods mentioned above (for example,
+<tt class="methodname">append</tt> and <tt class="methodname">prepend</tt>) don't
+make sense for the example since the model keeps the file list
+sorted.</p><p>Other methods that may be worth implementing in a
+<tt class="classname">TreeModel</tt> subclassing the
+<tt class="classname">GenericTreeModel</tt> are:</p><div class="itemizedlist"><ul type="disc"><li><tt class="methodname">set_value</tt>()</li><li><tt class="methodname">reorder</tt>()</li><li><tt class="methodname">swap</tt>()</li><li><tt class="methodname">move_after</tt>()</li><li><tt class="methodname">move_before</tt>()</li></ul></div><p>Implementing these methods is similar to the above methods. You
+have to synchronize the model with the external state and then notify the
+<tt class="classname">TreeView</tt>s if the model has changed. The following
+methods are used to notify the <tt class="classname">TreeView</tt>s of model
+changes by emitting the appropriate signal:</p><code class="methodsynopsis"> def <span class="methodname">row_changed</span>(<span class="methodparam"><span class="parameter"><b class="parameter"><tt>path</tt></b></span></span>, <span class="methodparam"><span class="parameter"><b class="parameter"><tt>iter</tt></b></span></span>)</code><br><code class="methodsynopsis"> def <span class="methodname">row_inserted</span>(<span class="methodparam"><span class="parameter"><b class="parameter"><tt>path</tt></b></span></span>, <span class="methodparam"><span class="parameter"><b class="parameter"><tt>iter</tt></b></span></span>)</code><br><code class="methodsynopsis"> def <span class="methodname">row_has_child_toggled</span>(<span class="methodparam"><span class="parameter"><b class="parameter"><tt>path</tt></b></span></span>, <span class="methodparam"><span class="parameter"><b class="parameter"><tt>iter</tt></b></span></span>)</code><br><code class="methodsynopsis"> def <span class="methodname">row_deleted</span>(<span class="methodparam"><span class="parameter"><b class="parameter"><tt>path</tt></b></span></span>)</code><br><code class="methodsynopsis"> def <span class="methodname">rows_reordered</span>(<span class="methodparam"><span class="parameter"><b class="parameter"><tt>path</tt></b></span></span>, <span class="methodparam"><span class="parameter"><b class="parameter"><tt>iter</tt></b></span></span>, <span class="methodparam"><span class="parameter"><b class="parameter"><tt>new_order</tt></b></span></span>)</code><p></p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-GenericTreeModelMemoryManagement"></a>14.11.4. Memory Management</h3></div></div><div></div></div><p>One of the problems with the
+<tt class="classname">GenericTreeModel</tt> is that
+<tt class="classname">TreeIter</tt>s hold a reference to a Python object
+returned from your custom tree model. Since the
+<tt class="classname">TreeIter</tt> may be created and initialized in C code and
+live on the stack, it's not possible to know when the
+<tt class="classname">TreeIter</tt> has been destroyed and the Python object
+reference is no longer being used. Therefore, the Python object referenced
+in a <tt class="classname">TreeIter</tt> has by default its reference count
+incremented but it is not decremented when the
+<tt class="classname">TreeIter</tt> is destroyed. This ensures that the Python
+object will not be destroyed while being used by a
+<tt class="classname">TreeIter</tt> and possibly cause a segfault. Unfortunately
+the extra reference counts lead to the situation that, at best, the Python
+object will have an excessive reference count and, at worst, it will never
+be freed even when it is not being used. The latter case leads to memory
+leaks and the former to reference leaks.</p><p>To provide for the situation where the custom
+<tt class="classname">TreeModel</tt> holds a reference to the Python object
+until it is no longer available (i.e. the <tt class="classname">TreeIter</tt> is
+invalid because the model has changed) and there is no need to leak
+references, the <tt class="classname">GenericTreeModel</tt> has the
+"leak-references" property. By default "leak-references" is
+<tt class="literal">TRUE</tt> to indicate that the
+<tt class="classname">GenericTreeModel</tt> will leak references. If
+"leak-references" is set to <tt class="literal">FALSE</tt>, the reference count of
+the Python object will not be incremented when referenced in a
+<tt class="classname">TreeIter</tt>. This means that your custom
+<tt class="classname">TreeModel</tt> must keep a reference to all Python objects
+used in <tt class="classname">TreeIter</tt>s until the model is
+destroyed. Unfortunately, even this cannot protect against buggy code that
+attempts to use a saved <tt class="classname">TreeIter</tt> on a different
+<tt class="classname">GenericTreeModel</tt>. To protect against that case your
+application would have to keep references to all Python objects referenced
+from a <tt class="classname">TreeIter</tt> for any
+<tt class="classname">GenericTreeModel</tt> instance. Of course, this ultimately
+has the same result as leaking references.</p><p>In PyGTK 2.4 and above the
+<tt class="methodname">invalidate_iters</tt>() and
+<tt class="methodname">iter_is_valid</tt>() methods are available to help
+manage the <tt class="classname">TreeIter</tt>s and their Python object
+references:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ generictreemodel.invalidate_iters()
+
+ result = generictreemodel.iter_is_valid(<b class="parameter"><tt>iter</tt></b>)
+</pre></td></tr></table><p>These are particularly useful when the "leak-references" property
+is set to <tt class="literal">FALSE</tt>. Tree models derived from
+<tt class="classname">GenericTreeModel</tt> are protected from problems with out
+of date<tt class="classname"> TreeIters</tt> because the iters are automatically
+checked for validity with the tree model.</p><p>If a custom tree model doesn't support persistent iters
+(i.e. <tt class="literal">gtk.TREE_MODEL_ITERS_PERSIST</tt> is not set in the
+return from the <tt class="methodname">TreeModel.get_flags</tt>() method), it
+can call the <tt class="methodname">invalidate_iters</tt>() method to
+invalidate all its outstanding <tt class="classname">TreeIter</tt>s when it
+changes the model (e.g. after inserting a new row). The tree model can also
+dispose of any Python objects, that were referenced by
+<tt class="classname">TreeIter</tt>s, after calling the
+<tt class="methodname">invalidate_iters</tt>() method.</p><p>Applications can use the <tt class="methodname">iter_is_valid</tt>()
+method to determine if a <tt class="classname">TreeIter</tt> is still valid for
+the custom tree model.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-OtherInterfaces"></a>14.11.5. Other Interfaces</h3></div></div><div></div></div><p>The <tt class="classname">ListStore</tt> and
+<tt class="classname">TreeStore</tt> models support the
+<tt class="classname">TreeSortable</tt>, <tt class="classname">TreeDragSource</tt>
+and <tt class="classname">TreeDragDest</tt> interfaces in addition to the
+<tt class="classname">TreeModel</tt> interface. The
+<tt class="classname">GenericTreeModel</tt> only supports the
+<tt class="classname">TreeModel</tt> interface. I believe that this is because
+of the direct reference of the model at the C level by
+<tt class="classname">TreeView</tt>s and the
+<tt class="classname">TreeModelSort</tt> and
+<tt class="classname">TreeModelFilter</tt> models. To create and use
+<tt class="classname">TreeIter</tt>s requires C glue code to interface with the
+Python custom tree model that has the data. That glue code is provided by
+the <tt class="classname">GenericTreeModel</tt> and there appears to be no
+alternative purely Python way of doing it because the
+<tt class="classname">TreeView</tt>s and the other models call the GtkTreeModel
+functions in C passing their reference to the custom tree model.</p><p>The <tt class="classname">TreeSortable</tt> interface would need C
+glue code as well to work with the default
+<tt class="classname">TreeViewColumn</tt> sort mechanism as explained in <a href="sec-TreeModelInterface.html#sec-SortingTreeModelRows" title="14.2.9. Sorting TreeModel Rows">Section 14.2.9, “Sorting TreeModel Rowsâ€</a>. However a custom model can do
+its own sorting and an application can manage the use of sort criteria by
+handling the <tt class="classname">TreeViewColumn</tt> header clicks and calling
+the custom tree model sort methods. The model completes the update of the
+<tt class="classname">TreeView</tt>s by emitting the "rows-reordered" signal
+using the <tt class="classname">TreeModel</tt>'s
+<tt class="methodname">rows_reordered</tt>() method. Thus the
+<tt class="classname">GenericTreeModel</tt> probably doesn't need to implement
+the <tt class="classname">TreeSortable</tt> interface.</p><p>Likewise, the <tt class="classname">GenericTreeModel</tt> doesn't have
+to implement the <tt class="classname">TreeDragSource</tt> and
+<tt class="classname">TreeDragDest</tt> interfaces because the custom tree model
+can implement its own drag and drop interfaces and the application can
+handle the appropriate <tt class="classname">TreeView</tt> signals and call the
+custom tree model methods as needed.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-ApplyingGenericTreeModel"></a>14.11.6. Applying The GenericTreeModel</h3></div></div><div></div></div><p>I believe that the <tt class="classname">GenericTreeModel</tt> should
+only be used as a last resort. There are powerful mechanisms in the standard
+group of <tt class="classname">TreeView</tt> objects that should be sufficient
+for most applications. Undoubtedly there are applications which may require
+the use of the <tt class="classname">GenericTreeModel</tt> but you should
+attempt to first use the following instead:</p><table border="0" width="100%" bgcolor="#FFECCE"><col align="left" valign="top" width="0*"><tbody><tr><td><span class="term">Cell Data Functions</span></td><td><p>As illustrated in <a href="sec-CellRenderers.html#sec-CellDataFunction" title="14.4.5. Cell Data Function">Section 14.4.5, “Cell Data Functionâ€</a>, cell data functions can be used to
+modify and even synthesize the data for a <tt class="classname">TreeView</tt>
+column display. You can effectively create as many display columns with
+generated data as you wish. This gives you a great deal of control over the
+presentation of data from an underlying data source.</p></td></tr><tr><td><span class="term">TreeModelFilter</span></td><td><p>In PyGTK 2.4, the <tt class="classname">TreeModelFilter</tt> as
+described in <a href="sec-TreeModelSortAndTreeModelFilter.html#sec-TreeModelFilter" title="14.10.2. TreeModelFilter">Section 14.10.2, “TreeModelFilterâ€</a> provides a great
+degree of control over the display of the columns and rows of a child
+<tt class="classname">TreeModel</tt> including presenting just the child rows of
+a row. Data columns can be synthesized similar to using Cell Data Functions
+but here the model appears to be a <tt class="classname">TreeModel</tt> with the
+number and type of columns specified whereas a cell data function leaves the
+model columns unchanged and just modifies the display in a
+<tt class="classname">TreeView</tt>.</p></td></tr></tbody></table><p>If a <tt class="classname">GenericTreeModel</tt> must be used you
+should be aware that:</p><div class="itemizedlist"><ul type="disc"><li>the entire <tt class="classname">TreeModel</tt> interface must
+be created and made to work as documented. There are subtleties that can
+lead to bugs. By contrast, the standard <tt class="classname">TreeModel</tt>s
+are thoroughly tested.</li><li>managing the references of Python objects used by
+<tt class="classname">TreeIter</tt>s can be difficult especially for long
+running programs with lots of variety of display.</li><li>an interface has to be developed for adding, deleting and
+changing the contents of rows. There is some awkwardness with the mapping of
+<tt class="classname">TreeIter</tt>s to the Python objects and model rows in
+this interface.</li><li>there is significant effort in developing sortable and drag
+and drop interfaces. The application probably needs to be involved in making
+these interfaces fully functional.</li></ul></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-TreeModelSortAndTreeModelFilter.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-TreeViewWidget.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-GenericCellRenderer.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">14.10. TreeModelSort and TreeModelFilter </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 14.12. The Generic CellRenderer</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkAdjustment.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkAdjustment.html
new file mode 100644
index 0000000..518b26e
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkAdjustment.html
@@ -0,0 +1,5 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>A.22. GtkAdjustment</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="app-GtkSignals.html" title="Appendix A. GTK Signals"><link rel="previous" href="sec-GtkCurve.html" title="A.21. GtkCurve"><link rel="next" href="app-CodeExamples.html" title="Appendix B. Code Examples"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">A.22. GtkAdjustment</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-GtkCurve.html">Prev</a> </td><th width="60%" align="center">Appendix A. GTK Signals</th><td width="20%" align="right"> <a accesskey="n" href="app-CodeExamples.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-GtkAdjustment"></a>A.22. GtkAdjustment</h2></div></div><div></div></div><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+changed(adjustment, data)
+
+value-changed(adjustment, data)
+</pre></td></tr></table></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-GtkCurve.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="app-GtkSignals.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="app-CodeExamples.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">A.21. GtkCurve </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Appendix B. Code Examples</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkButton.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkButton.html
new file mode 100644
index 0000000..5b0b483
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkButton.html
@@ -0,0 +1,11 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>A.11. GtkButton</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="app-GtkSignals.html" title="Appendix A. GTK Signals"><link rel="previous" href="sec-GtkToolbar.html" title="A.10. GtkToolbar"><link rel="next" href="sec-GtkItem.html" title="A.12. GtkItem"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">A.11. GtkButton</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-GtkToolbar.html">Prev</a> </td><th width="60%" align="center">Appendix A. GTK Signals</th><td width="20%" align="right"> <a accesskey="n" href="sec-GtkItem.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-GtkButton"></a>A.11. GtkButton</h2></div></div><div></div></div><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+pressed(button, data)
+
+released(button, data)
+
+clicked(button, data)
+
+enter(button, data)
+
+leave(button, data)
+</pre></td></tr></table></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-GtkToolbar.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="app-GtkSignals.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-GtkItem.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">A.10. GtkToolbar </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> A.12. GtkItem</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkCalendar.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkCalendar.html
new file mode 100644
index 0000000..566fe36
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkCalendar.html
@@ -0,0 +1,15 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>A.5. GtkCalendar</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="app-GtkSignals.html" title="Appendix A. GTK Signals"><link rel="previous" href="sec-GtkContainer.html" title="A.4. GtkContainer"><link rel="next" href="sec-GtkEditable.html" title="A.6. GtkEditable"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">A.5. GtkCalendar</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-GtkContainer.html">Prev</a> </td><th width="60%" align="center">Appendix A. GTK Signals</th><td width="20%" align="right"> <a accesskey="n" href="sec-GtkEditable.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-GtkCalendar"></a>A.5. GtkCalendar</h2></div></div><div></div></div><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+month-changed(calendar, data)
+
+day-selected(calendar, data)
+
+day-selected-double-click(calendar, data)
+
+prev-month(calendar, data)
+
+next-month(calendar, data)
+
+prev-year(calendar, data)
+
+next-year(calendar, data)
+</pre></td></tr></table></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-GtkContainer.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="app-GtkSignals.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-GtkEditable.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">A.4. GtkContainer </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> A.6. GtkEditable</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkCheckMenuItem.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkCheckMenuItem.html
new file mode 100644
index 0000000..386c9e6
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkCheckMenuItem.html
@@ -0,0 +1,3 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>A.17. GtkCheckMenuItem</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="app-GtkSignals.html" title="Appendix A. GTK Signals"><link rel="previous" href="sec-GtkMenuItem.html" title="A.16. GtkMenuItem"><link rel="next" href="sec-GtkInputDialog.html" title="A.18. GtkInputDialog"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">A.17. GtkCheckMenuItem</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-GtkMenuItem.html">Prev</a> </td><th width="60%" align="center">Appendix A. GTK Signals</th><td width="20%" align="right"> <a accesskey="n" href="sec-GtkInputDialog.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-GtkCheckMenuItem"></a>A.17. GtkCheckMenuItem</h2></div></div><div></div></div><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+toggled(check_menu_item, data)
+</pre></td></tr></table></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-GtkMenuItem.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="app-GtkSignals.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-GtkInputDialog.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">A.16. GtkMenuItem </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> A.18. GtkInputDialog</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkColorSelection.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkColorSelection.html
new file mode 100644
index 0000000..4154497
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkColorSelection.html
@@ -0,0 +1,3 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>A.19. GtkColorSelection</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="app-GtkSignals.html" title="Appendix A. GTK Signals"><link rel="previous" href="sec-GtkInputDialog.html" title="A.18. GtkInputDialog"><link rel="next" href="sec-GtkStatusBar.html" title="A.20. GtkStatusBar"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">A.19. GtkColorSelection</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-GtkInputDialog.html">Prev</a> </td><th width="60%" align="center">Appendix A. GTK Signals</th><td width="20%" align="right"> <a accesskey="n" href="sec-GtkStatusBar.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-GtkColorSelection"></a>A.19. GtkColorSelection</h2></div></div><div></div></div><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+color-changed(color_selection, data)
+</pre></td></tr></table></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-GtkInputDialog.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="app-GtkSignals.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-GtkStatusBar.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">A.18. GtkInputDialog </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> A.20. GtkStatusBar</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkContainer.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkContainer.html
new file mode 100644
index 0000000..0479916
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkContainer.html
@@ -0,0 +1,11 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>A.4. GtkContainer</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="app-GtkSignals.html" title="Appendix A. GTK Signals"><link rel="previous" href="sec-GtkData.html" title="A.3. GtkData"><link rel="next" href="sec-GtkCalendar.html" title="A.5. GtkCalendar"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">A.4. GtkContainer</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-GtkData.html">Prev</a> </td><th width="60%" align="center">Appendix A. GTK Signals</th><td width="20%" align="right"> <a accesskey="n" href="sec-GtkCalendar.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-GtkContainer"></a>A.4. GtkContainer</h2></div></div><div></div></div><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+add(container, widget, data)
+
+remove(container, widget, data)
+
+check-resize(container, data)
+
+direction = focus(container, direction, data)
+
+set-focus-child(container, widget, data)
+</pre></td></tr></table></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-GtkData.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="app-GtkSignals.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-GtkCalendar.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">A.3. GtkData </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> A.5. GtkCalendar</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkCurve.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkCurve.html
new file mode 100644
index 0000000..da9caf6
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkCurve.html
@@ -0,0 +1,3 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>A.21. GtkCurve</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="app-GtkSignals.html" title="Appendix A. GTK Signals"><link rel="previous" href="sec-GtkStatusBar.html" title="A.20. GtkStatusBar"><link rel="next" href="sec-GtkAdjustment.html" title="A.22. GtkAdjustment"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">A.21. GtkCurve</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-GtkStatusBar.html">Prev</a> </td><th width="60%" align="center">Appendix A. GTK Signals</th><td width="20%" align="right"> <a accesskey="n" href="sec-GtkAdjustment.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-GtkCurve"></a>A.21. GtkCurve</h2></div></div><div></div></div><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+curve-type-changed(curve, data)
+</pre></td></tr></table></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-GtkStatusBar.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="app-GtkSignals.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-GtkAdjustment.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">A.20. GtkStatusBar </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> A.22. GtkAdjustment</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkData.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkData.html
new file mode 100644
index 0000000..f7ae708
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkData.html
@@ -0,0 +1,3 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>A.3. GtkData</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="app-GtkSignals.html" title="Appendix A. GTK Signals"><link rel="previous" href="sec-GtkWidget.html" title="A.2. GtkWidget"><link rel="next" href="sec-GtkContainer.html" title="A.4. GtkContainer"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">A.3. GtkData</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-GtkWidget.html">Prev</a> </td><th width="60%" align="center">Appendix A. GTK Signals</th><td width="20%" align="right"> <a accesskey="n" href="sec-GtkContainer.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-GtkData"></a>A.3. GtkData</h2></div></div><div></div></div><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ disconnect(data_obj, data)
+</pre></td></tr></table></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-GtkWidget.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="app-GtkSignals.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-GtkContainer.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">A.2. GtkWidget </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> A.4. GtkContainer</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkEditable.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkEditable.html
new file mode 100644
index 0000000..315bd44
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkEditable.html
@@ -0,0 +1,33 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>A.6. GtkEditable</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="app-GtkSignals.html" title="Appendix A. GTK Signals"><link rel="previous" href="sec-GtkCalendar.html" title="A.5. GtkCalendar"><link rel="next" href="sec-GtkNotebook.html" title="A.7. GtkNotebook"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">A.6. GtkEditable</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-GtkCalendar.html">Prev</a> </td><th width="60%" align="center">Appendix A. GTK Signals</th><td width="20%" align="right"> <a accesskey="n" href="sec-GtkNotebook.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-GtkEditable"></a>A.6. GtkEditable</h2></div></div><div></div></div><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+changed(editable, data)
+
+insert-text(editable, new_text, text_length, position, data)
+
+delete-text(editable, start_pos, end_pos, data)
+
+activate(editable, data)
+
+set-editable(editable, is_editable, data)
+
+move-cursor(editable, x, y, data)
+
+move-word(editable, num_words, data)
+
+move-page(editable, x, y, data)
+
+move-to-row(editable, row, data)
+
+move-to-column(editable, column, data)
+
+kill-char(editable, direction, data)
+
+kill-word(editable, drirection, data)
+
+kill-line(editable, direction, data)
+
+cut-clipboard(editable, data)
+
+copy-clipboard(editable, data)
+
+paste-clipboard(editable, data)
+</pre></td></tr></table></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-GtkCalendar.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="app-GtkSignals.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-GtkNotebook.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">A.5. GtkCalendar </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> A.7. GtkNotebook</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkHandleBox.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkHandleBox.html
new file mode 100644
index 0000000..64dcff5
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkHandleBox.html
@@ -0,0 +1,5 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>A.14. GtkHandleBox</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="app-GtkSignals.html" title="Appendix A. GTK Signals"><link rel="previous" href="sec-GtkWindow.html" title="A.13. GtkWindow"><link rel="next" href="sec-GtkToggleButton.html" title="A.15. GtkToggleButton"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">A.14. GtkHandleBox</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-GtkWindow.html">Prev</a> </td><th width="60%" align="center">Appendix A. GTK Signals</th><td width="20%" align="right"> <a accesskey="n" href="sec-GtkToggleButton.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-GtkHandleBox"></a>A.14. GtkHandleBox</h2></div></div><div></div></div><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+child-attached(handle_box, widget, data)
+
+child-detached(handle_box, widget, data)
+</pre></td></tr></table></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-GtkWindow.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="app-GtkSignals.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-GtkToggleButton.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">A.13. GtkWindow </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> A.15. GtkToggleButton</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkInputDialog.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkInputDialog.html
new file mode 100644
index 0000000..2c8cac2
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkInputDialog.html
@@ -0,0 +1,5 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>A.18. GtkInputDialog</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="app-GtkSignals.html" title="Appendix A. GTK Signals"><link rel="previous" href="sec-GtkCheckMenuItem.html" title="A.17. GtkCheckMenuItem"><link rel="next" href="sec-GtkColorSelection.html" title="A.19. GtkColorSelection"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">A.18. GtkInputDialog</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-GtkCheckMenuItem.html">Prev</a> </td><th width="60%" align="center">Appendix A. GTK Signals</th><td width="20%" align="right"> <a accesskey="n" href="sec-GtkColorSelection.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-GtkInputDialog"></a>A.18. GtkInputDialog</h2></div></div><div></div></div><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+enable-device(input_dialog, deviceid, data)
+
+disable-device(input_dialog, deviceid, data)
+</pre></td></tr></table></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-GtkCheckMenuItem.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="app-GtkSignals.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-GtkColorSelection.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">A.17. GtkCheckMenuItem </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> A.19. GtkColorSelection</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkItem.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkItem.html
new file mode 100644
index 0000000..a810b14
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkItem.html
@@ -0,0 +1,7 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>A.12. GtkItem</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="app-GtkSignals.html" title="Appendix A. GTK Signals"><link rel="previous" href="sec-GtkButton.html" title="A.11. GtkButton"><link rel="next" href="sec-GtkWindow.html" title="A.13. GtkWindow"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">A.12. GtkItem</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-GtkButton.html">Prev</a> </td><th width="60%" align="center">Appendix A. GTK Signals</th><td width="20%" align="right"> <a accesskey="n" href="sec-GtkWindow.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-GtkItem"></a>A.12. GtkItem</h2></div></div><div></div></div><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+select(item, data)
+
+deselect(item, data)
+
+toggle(item, data)
+</pre></td></tr></table></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-GtkButton.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="app-GtkSignals.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-GtkWindow.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">A.11. GtkButton </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> A.13. GtkWindow</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkList.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkList.html
new file mode 100644
index 0000000..dd9b1bf
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkList.html
@@ -0,0 +1,7 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>A.8. GtkList</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="app-GtkSignals.html" title="Appendix A. GTK Signals"><link rel="previous" href="sec-GtkNotebook.html" title="A.7. GtkNotebook"><link rel="next" href="sec-GtkMenuShell.html" title="A.9. GtkMenuShell"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">A.8. GtkList</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-GtkNotebook.html">Prev</a> </td><th width="60%" align="center">Appendix A. GTK Signals</th><td width="20%" align="right"> <a accesskey="n" href="sec-GtkMenuShell.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-GtkList"></a>A.8. GtkList</h2></div></div><div></div></div><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+selection-changed(list, data)
+
+select-child(list, widget, data)
+
+unselect-child(list, widget, data)
+</pre></td></tr></table></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-GtkNotebook.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="app-GtkSignals.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-GtkMenuShell.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">A.7. GtkNotebook </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> A.9. GtkMenuShell</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkMenuItem.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkMenuItem.html
new file mode 100644
index 0000000..2e35f15
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkMenuItem.html
@@ -0,0 +1,5 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>A.16. GtkMenuItem</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="app-GtkSignals.html" title="Appendix A. GTK Signals"><link rel="previous" href="sec-GtkToggleButton.html" title="A.15. GtkToggleButton"><link rel="next" href="sec-GtkCheckMenuItem.html" title="A.17. GtkCheckMenuItem"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">A.16. GtkMenuItem</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-GtkToggleButton.html">Prev</a> </td><th width="60%" align="center">Appendix A. GTK Signals</th><td width="20%" align="right"> <a accesskey="n" href="sec-GtkCheckMenuItem.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-GtkMenuItem"></a>A.16. GtkMenuItem</h2></div></div><div></div></div><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+activate(menu_item, data)
+
+activate-item(menu_item, data)
+</pre></td></tr></table></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-GtkToggleButton.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="app-GtkSignals.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-GtkCheckMenuItem.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">A.15. GtkToggleButton </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> A.17. GtkCheckMenuItem</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkMenuShell.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkMenuShell.html
new file mode 100644
index 0000000..89dd2b0
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkMenuShell.html
@@ -0,0 +1,11 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>A.9. GtkMenuShell</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="app-GtkSignals.html" title="Appendix A. GTK Signals"><link rel="previous" href="sec-GtkList.html" title="A.8. GtkList"><link rel="next" href="sec-GtkToolbar.html" title="A.10. GtkToolbar"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">A.9. GtkMenuShell</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-GtkList.html">Prev</a> </td><th width="60%" align="center">Appendix A. GTK Signals</th><td width="20%" align="right"> <a accesskey="n" href="sec-GtkToolbar.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-GtkMenuShell"></a>A.9. GtkMenuShell</h2></div></div><div></div></div><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+deactivate(menu_shell, data)
+
+selection-done(menu_shell, data)
+
+move-current(menu_shell, direction, data)
+
+activate-current(menu_shell, force_hide, data)
+
+cancel(menu_shell, data)
+</pre></td></tr></table></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-GtkList.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="app-GtkSignals.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-GtkToolbar.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">A.8. GtkList </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> A.10. GtkToolbar</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkNotebook.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkNotebook.html
new file mode 100644
index 0000000..d0432bb
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkNotebook.html
@@ -0,0 +1,3 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>A.7. GtkNotebook</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="app-GtkSignals.html" title="Appendix A. GTK Signals"><link rel="previous" href="sec-GtkEditable.html" title="A.6. GtkEditable"><link rel="next" href="sec-GtkList.html" title="A.8. GtkList"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">A.7. GtkNotebook</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-GtkEditable.html">Prev</a> </td><th width="60%" align="center">Appendix A. GTK Signals</th><td width="20%" align="right"> <a accesskey="n" href="sec-GtkList.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-GtkNotebook"></a>A.7. GtkNotebook</h2></div></div><div></div></div><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ switch-page(noteboook, page, page_num, data)
+</pre></td></tr></table></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-GtkEditable.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="app-GtkSignals.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-GtkList.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">A.6. GtkEditable </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> A.8. GtkList</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkStatusBar.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkStatusBar.html
new file mode 100644
index 0000000..5596af4
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkStatusBar.html
@@ -0,0 +1,5 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>A.20. GtkStatusBar</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="app-GtkSignals.html" title="Appendix A. GTK Signals"><link rel="previous" href="sec-GtkColorSelection.html" title="A.19. GtkColorSelection"><link rel="next" href="sec-GtkCurve.html" title="A.21. GtkCurve"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">A.20. GtkStatusBar</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-GtkColorSelection.html">Prev</a> </td><th width="60%" align="center">Appendix A. GTK Signals</th><td width="20%" align="right"> <a accesskey="n" href="sec-GtkCurve.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-GtkStatusBar"></a>A.20. GtkStatusBar</h2></div></div><div></div></div><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+text-pushed(statusbar, context_id, text, data)
+
+text-popped(statusbar, context_id, text, data)
+</pre></td></tr></table></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-GtkColorSelection.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="app-GtkSignals.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-GtkCurve.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">A.19. GtkColorSelection </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> A.21. GtkCurve</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkToggleButton.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkToggleButton.html
new file mode 100644
index 0000000..2ba15d0
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkToggleButton.html
@@ -0,0 +1,3 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>A.15. GtkToggleButton</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="app-GtkSignals.html" title="Appendix A. GTK Signals"><link rel="previous" href="sec-GtkHandleBox.html" title="A.14. GtkHandleBox"><link rel="next" href="sec-GtkMenuItem.html" title="A.16. GtkMenuItem"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">A.15. GtkToggleButton</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-GtkHandleBox.html">Prev</a> </td><th width="60%" align="center">Appendix A. GTK Signals</th><td width="20%" align="right"> <a accesskey="n" href="sec-GtkMenuItem.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-GtkToggleButton"></a>A.15. GtkToggleButton</h2></div></div><div></div></div><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+toggled(toggle_button, data)
+</pre></td></tr></table></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-GtkHandleBox.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="app-GtkSignals.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-GtkMenuItem.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">A.14. GtkHandleBox </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> A.16. GtkMenuItem</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkToolbar.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkToolbar.html
new file mode 100644
index 0000000..519f472
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkToolbar.html
@@ -0,0 +1,5 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>A.10. GtkToolbar</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="app-GtkSignals.html" title="Appendix A. GTK Signals"><link rel="previous" href="sec-GtkMenuShell.html" title="A.9. GtkMenuShell"><link rel="next" href="sec-GtkButton.html" title="A.11. GtkButton"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">A.10. GtkToolbar</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-GtkMenuShell.html">Prev</a> </td><th width="60%" align="center">Appendix A. GTK Signals</th><td width="20%" align="right"> <a accesskey="n" href="sec-GtkButton.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-GtkToolbar"></a>A.10. GtkToolbar</h2></div></div><div></div></div><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+orientation-changed(toolbar, orientation, data)
+
+style-changed(toolbar, toolbar_style, data)
+</pre></td></tr></table></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-GtkMenuShell.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="app-GtkSignals.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-GtkButton.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">A.9. GtkMenuShell </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> A.11. GtkButton</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkWidget.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkWidget.html
new file mode 100644
index 0000000..4c90e60
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkWidget.html
@@ -0,0 +1,107 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>A.2. GtkWidget</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="app-GtkSignals.html" title="Appendix A. GTK Signals"><link rel="previous" href="app-GtkSignals.html" title="Appendix A. GTK Signals"><link rel="next" href="sec-GtkData.html" title="A.3. GtkData"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">A.2. GtkWidget</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="app-GtkSignals.html">Prev</a> </td><th width="60%" align="center">Appendix A. GTK Signals</th><td width="20%" align="right"> <a accesskey="n" href="sec-GtkData.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-GtkWidget"></a>A.2. GtkWidget</h2></div></div><div></div></div><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+show(GtkWidget, data)
+
+hide(widget, data)
+
+map(widget, data)
+
+unmap(widget, data)
+
+realize(widget, data)
+
+unrealize(widget, data)
+
+draw(widget, area, data)
+
+draw-focus(widget, data)
+
+draw-default(widget, data)
+
+size-request(widget, requisition, data)
+
+size-allocate(widget, allocation, data)
+
+state-changed(widget, state, data)
+
+parent-set(widget, object, data)
+
+style-set(widget, style, data)
+
+add-accelerator(widget, accel_signal_id, accel_group, accel_key, accel_mods,
+ accel_flags, data)
+
+remove-accelerator(widget, accel_group, accel_key, accel_mods, data)
+
+bool = event(widget, event, data)
+
+bool = button-press-event(widget, event, data)
+
+bool = button-release-event(widget, event, data)
+
+bool = motion-notify-event(widget, event, data)
+
+bool = delete-event(widget, event, data)
+
+bool = destroy-event(widget, event, data)
+
+bool = expose-event(widget, event, data)
+
+bool = key-press-event(widget, event, data)
+
+bool = key-release-event(widget, event, data)
+
+bool = enter-notify-event(widget, event, data)
+
+bool = leave-notify-event(widget, event, data)
+
+bool = configure-event(widget, event, data)
+
+bool = focus-in-event(widget, event, data)
+
+bool = focus-out-event(widget, event, data)
+
+bool = map-event(widget, event, data)
+
+bool = unmap-event(widget, event, data)
+
+bool = property-notify-event(widget, event, data)
+
+bool = selection-clear-event(widget, event, data)
+
+bool = selection-request-event(widget, event, data)
+
+bool = selection-notify-event(widget, event, data)
+
+selection-get(widget, selection_data, info, time, data)
+
+selection-received(widget, selection_data, time, data)
+
+bool = proximity-in-event(widget, event, data)
+
+bool = proximity-out-event(widget, event, data)
+
+drag-begin(widget, context, data)
+
+drag-end(widget, context, data)
+
+drag-data-delete(widget, context, data)
+
+drag-leave(widget, context, time, data)
+
+bool = drag-motion(widget, context, x, y, time, data)
+
+bool = drag-drop(widget, context, x, y, time, data)
+
+drag-data-get(widget, context, selection_data, info, time, data)
+
+drag-data-received(widget, context, info, time, selection_data,
+ info, time, data)
+
+bool = client-event(widget, event, data)
+
+bool = no-expose-event(widget, event, data)
+
+bool = visibility-notify-event(widget, event, data)
+
+debug-msg(widget, string, data)
+</pre></td></tr></table></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="app-GtkSignals.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="app-GtkSignals.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-GtkData.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Appendix A. GTK Signals </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> A.3. GtkData</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkWindow.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkWindow.html
new file mode 100644
index 0000000..8ad6ccb
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-GtkWindow.html
@@ -0,0 +1,3 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>A.13. GtkWindow</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="app-GtkSignals.html" title="Appendix A. GTK Signals"><link rel="previous" href="sec-GtkItem.html" title="A.12. GtkItem"><link rel="next" href="sec-GtkHandleBox.html" title="A.14. GtkHandleBox"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">A.13. GtkWindow</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-GtkItem.html">Prev</a> </td><th width="60%" align="center">Appendix A. GTK Signals</th><td width="20%" align="right"> <a accesskey="n" href="sec-GtkHandleBox.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-GtkWindow"></a>A.13. GtkWindow</h2></div></div><div></div></div><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+set-focus(window, widget, data)
+</pre></td></tr></table></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-GtkItem.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="app-GtkSignals.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-GtkHandleBox.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">A.12. GtkItem </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> A.14. GtkHandleBox</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-IdleFunctions.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-IdleFunctions.html
new file mode 100644
index 0000000..48a7d22
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-IdleFunctions.html
@@ -0,0 +1,20 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>19.3. Idle Functions</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-TimeoutsIOAndIdleFunctions.html" title="Chapter 19. Timeouts, IO and Idle Functions"><link rel="previous" href="sec-MonitoringIO.html" title="19.2. Monitoring IO"><link rel="next" href="ch-AdvancedEventAndSignalHandling.html" title="Chapter 20. Advanced Event and Signal Handling"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">19.3. Idle Functions</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-MonitoringIO.html">Prev</a> </td><th width="60%" align="center">Chapter 19. Timeouts, IO and Idle Functions</th><td width="20%" align="right"> <a accesskey="n" href="ch-AdvancedEventAndSignalHandling.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-IdleFunctions"></a>19.3. Idle Functions</h2></div></div><div></div></div><p>What if you have a function which you want to be called when
+nothing else is happening ? Use the function:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ source_id = gobject.idle_add(<i class="parameter"><tt>callback</tt></i>, ...)
+</pre></td></tr></table><p>Any arguments beyond the first (indicated with ...) are passed to
+the <i class="parameter"><tt>callback</tt></i> in order. The
+<i class="parameter"><tt>source_id</tt></i> is returned to provide a reference to the
+handler.</p><p>This function causes GTK to call the specified
+<i class="parameter"><tt>callback</tt></i> function whenever nothing else is
+happening.</p><p>The <i class="parameter"><tt>callback</tt></i> signature is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def callback(...):
+</pre></td></tr></table><p>where the arguments passed to the <tt class="function">callback</tt>
+are the same as those specified in the
+<tt class="function">gobject.idle_add</tt>() function. As with the other callback
+functions, returning <tt class="literal">FALSE</tt> will stop the idle callback
+from being called and returning <tt class="literal">TRUE</tt> causes the callback
+function to be run at the next idle time.</p><p>An idle function can be removed from the queue by calling the
+function:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ gobject.source_remove(<i class="parameter"><tt>source_id</tt></i>)
+</pre></td></tr></table><p>with the <i class="parameter"><tt>source_id</tt></i> returned from the
+<tt class="function">gobject.idle_add</tt>() function.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-MonitoringIO.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-TimeoutsIOAndIdleFunctions.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch-AdvancedEventAndSignalHandling.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">19.2. Monitoring IO </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 20. Advanced Event and Signal Handling</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-Images.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-Images.html
new file mode 100644
index 0000000..07f49a7
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-Images.html
@@ -0,0 +1,477 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>9.6. Images</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-MiscellaneousWidgets.html" title="Chapter 9. Miscellaneous Widgets"><link rel="previous" href="sec-Dialogs.html" title="9.5. Dialogs"><link rel="next" href="sec-Rulers.html" title="9.7. Rulers"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">9.6. Images</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-Dialogs.html">Prev</a> </td><th width="60%" align="center">Chapter 9. Miscellaneous Widgets</th><td width="20%" align="right"> <a accesskey="n" href="sec-Rulers.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-Images"></a>9.6. Images</h2></div></div><div></div></div><p><tt class="classname">Images</tt> are data structures that contain
+pictures. These pictures can be used in various places.</p><p><tt class="classname">Images</tt> can be created from
+<tt class="classname">Pixbufs</tt>, <tt class="classname">Pixmaps</tt>, image files
+(e.g. XPM, PNG, JPEG, TIFF, etc.) and even animation files.</p><p><tt class="classname">Images</tt> are created using the
+function:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ image = gtk.Image()
+</pre></td></tr></table><p>The image is then loaded using one of the following
+methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ image.set_from_pixbuf(<b class="parameter"><tt>pixbuf</tt></b>)
+ image.set_from_pixmap(<b class="parameter"><tt>pixmap</tt></b>, <b class="parameter"><tt>mask</tt></b>)
+ image.set_from_image(<b class="parameter"><tt>image</tt></b>)
+ image.set_from_file(<b class="parameter"><tt>filename</tt></b>)
+ image.set_from_stock<b class="parameter"><tt>(stock_id</tt></b>, <b class="parameter"><tt>size</tt></b>)
+ image.set_from_icon_set(<b class="parameter"><tt>icon_set</tt></b>, <b class="parameter"><tt>size</tt></b>)
+ image.set_from_animation(<b class="parameter"><tt>animation</tt></b>)
+</pre></td></tr></table><p>Where <i class="parameter"><tt>pixbuf</tt></i> is a
+<tt class="classname">gtk.gdk.Pixbuf</tt>; <i class="parameter"><tt>pixmap</tt></i> and
+<i class="parameter"><tt>mask</tt></i> are <tt class="classname">gtk.gdk.Pixmaps</tt>;
+<i class="parameter"><tt>image</tt></i> is a <tt class="classname">gtk.gdk.Image</tt>;
+<i class="parameter"><tt>stock_id</tt></i> is the name of a
+<tt class="classname">gtk.StockItem</tt>; <i class="parameter"><tt>icon_set</tt></i> is a
+<tt class="classname">gtk.IconSet</tt>; and, <i class="parameter"><tt>animation</tt></i> is
+a <tt class="classname">gtk.gdk.PixbufAnimation</tt>. the
+<i class="parameter"><tt>size</tt></i> argument is one of:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ ICON_SIZE_MENU
+ ICON_SIZE_SMALL_TOOLBAR
+ ICON_SIZE_LARGE_TOOLBAR
+ ICON_SIZE_BUTTON
+ ICON_SIZE_DND
+ ICON_SIZE_DIALOG
+</pre></td></tr></table><p>The easiest way to create an image is using the
+<tt class="methodname">set_from_file</tt>() method which automatically
+determines the image type and loads it.</p><p>The program <a href="examples/images.py" target="_top"><span><b class="command">images.py</b></span></a> illustrates
+loading various image types (<a href="examples/goalie.gif" target="_top"><tt class="filename">goalie.gif</tt></a>, <a href="examples/apple-red.png" target="_top"><tt class="filename">apple-red.png</tt></a>,
+<a href="examples/chaos.jpg" target="_top"><tt class="filename">chaos.jpg</tt></a>,
+<a href="examples/important.tif" target="_top"><tt class="filename">important.tif</tt></a>,
+<a href="examples/soccerball.gif" target="_top"><tt class="filename">soccerball.gif</tt></a>)
+into images which are then put into buttons:</p><div class="figure"><a name="imagesfig"></a><p class="title"><b>Figure 9.5. Example Images in Buttons</b></p><div class="mediaobject" align="center"><img src="figures/images.png" align="middle" alt="Example Images in Buttons"></div></div><p>The source code is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 1 #!/usr/bin/env python
+ 2
+ 3 # example images.py
+ 4
+ 5 import pygtk
+ 6 pygtk.require('2.0')
+ 7 import gtk
+ 8
+ 9 class ImagesExample:
+ 10 # when invoked (via signal delete_event), terminates the application.
+ 11 def close_application(self, widget, event, data=None):
+ 12 gtk.main_quit()
+ 13 return False
+ 14
+ 15 # is invoked when the button is clicked. It just prints a message.
+ 16 def button_clicked(self, widget, data=None):
+ 17 print "button %s clicked" % data
+ 18
+ 19 def __init__(self):
+ 20 # create the main window, and attach delete_event signal to terminating
+ 21 # the application
+ 22 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ 23 window.connect("delete_event", self.close_application)
+ 24 window.set_border_width(10)
+ 25 window.show()
+ 26
+ 27 # a horizontal box to hold the buttons
+ 28 hbox = gtk.HBox()
+ 29 hbox.show()
+ 30 window.add(hbox)
+ 31
+ 32 pixbufanim = gtk.gdk.PixbufAnimation("goalie.gif")
+ 33 image = gtk.Image()
+ 34 image.set_from_animation(pixbufanim)
+ 35 image.show()
+ 36 # a button to contain the image widget
+ 37 button = gtk.Button()
+ 38 button.add(image)
+ 39 button.show()
+ 40 hbox.pack_start(button)
+ 41 button.connect("clicked", self.button_clicked, "1")
+ 42
+ 43 # create several images with data from files and load images into
+ 44 # buttons
+ 45 image = gtk.Image()
+ 46 image.set_from_file("apple-red.png")
+ 47 image.show()
+ 48 # a button to contain the image widget
+ 49 button = gtk.Button()
+ 50 button.add(image)
+ 51 button.show()
+ 52 hbox.pack_start(button)
+ 53 button.connect("clicked", self.button_clicked, "2")
+ 54
+ 55 image = gtk.Image()
+ 56 image.set_from_file("chaos.jpg")
+ 57 image.show()
+ 58 # a button to contain the image widget
+ 59 button = gtk.Button()
+ 60 button.add(image)
+ 61 button.show()
+ 62 hbox.pack_start(button)
+ 63 button.connect("clicked", self.button_clicked, "3")
+ 64
+ 65 image = gtk.Image()
+ 66 image.set_from_file("important.tif")
+ 67 image.show()
+ 68 # a button to contain the image widget
+ 69 button = gtk.Button()
+ 70 button.add(image)
+ 71 button.show()
+ 72 hbox.pack_start(button)
+ 73 button.connect("clicked", self.button_clicked, "4")
+ 74
+ 75 image = gtk.Image()
+ 76 image.set_from_file("soccerball.gif")
+ 77 image.show()
+ 78 # a button to contain the image widget
+ 79 button = gtk.Button()
+ 80 button.add(image)
+ 81 button.show()
+ 82 hbox.pack_start(button)
+ 83 button.connect("clicked", self.button_clicked, "5")
+ 84
+ 85
+ 86 def main():
+ 87 gtk.main()
+ 88 return 0
+ 89
+ 90 if __name__ == "__main__":
+ 91 ImagesExample()
+ 92 main()
+</pre></td></tr></table><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2843382"></a>9.6.1. Pixmaps</h3></div></div><div></div></div><p><tt class="classname">Pixmaps</tt> are data structures that
+contain pictures. These pictures can be used in various places, but most
+commonly as icons on the X desktop, or as cursors.</p><p>A pixmap which only has 2 colors is called a bitmap, and there
+are a few additional routines for handling this common special case.</p><p>To understand pixmaps, it would help to understand how X
+window system works. Under X, applications do not need to be running on the
+same computer that is interacting with the user. Instead, the various
+applications, called "clients", all communicate with a program which
+displays the graphics and handles the keyboard and mouse. This program which
+interacts directly with the user is called a "display server" or "X server."
+Since the communication might take place over a network, it's important to
+keep some information with the X server. <tt class="classname">Pixmaps</tt>, for
+example, are stored in the memory of the X server. This means that once
+pixmap values are set, they don't need to keep getting transmitted over the
+network; instead a command is sent to "display pixmap number XYZ here." Even
+if you aren't using X with GTK+ currently, using constructs such as
+<tt class="classname">Pixmaps</tt> will make your programs work acceptably under
+X.</p><p>To use pixmaps in PyGTK, we must first build a
+<tt class="classname">gtk.gdk.Pixmap</tt> using gtk.gdk functions in PyGTK.
+<tt class="classname">Pixmaps</tt> can either be created from in-memory data, or
+from data read from a file. We'll go through each of the calls to create a
+pixmap.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ pixmap = gtk.gdk.pixmap_create_from_data(<b class="parameter"><tt>window</tt></b>, <b class="parameter"><tt>data</tt></b>, <b class="parameter"><tt>width</tt></b>, <b class="parameter"><tt>height</tt></b>, <b class="parameter"><tt>depth</tt></b>, <b class="parameter"><tt>fg</tt></b>, <b class="parameter"><tt>bg</tt></b>)
+</pre></td></tr></table><p>This routine is used to create a <i class="parameter"><tt>pixmap</tt></i>
+from <i class="parameter"><tt>data</tt></i> in memory with the color depth given by
+<i class="parameter"><tt>depth</tt></i>. If <i class="parameter"><tt>depth</tt></i> is -1 the
+color depth is derived from the depth of <i class="parameter"><tt>window</tt></i>. Each
+pixel uses <i class="parameter"><tt>depth</tt></i> bits of data to represent the
+color. <i class="parameter"><tt>Width</tt></i> and <i class="parameter"><tt>height</tt></i> are in
+pixels. The <i class="parameter"><tt>window</tt></i> argument must refer to a realized
+<tt class="classname">gtk.gdk.Window</tt>, since a pixmap's resources are
+meaningful only in the context of the screen where it is to be
+displayed. <i class="parameter"><tt>fg</tt></i> and <i class="parameter"><tt>bg</tt></i> are the
+foreground and background colors of the pixmap.</p><p>Pixmaps can be created from XPM files using:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ pixmap, mask = gtk.gdk.pixmap_create_from_xpm(<b class="parameter"><tt>window</tt></b>, <b class="parameter"><tt>transparent_color</tt></b>, <b class="parameter"><tt>filename</tt></b>)
+</pre></td></tr></table><p>XPM format is a readable pixmap representation for the X
+Window System. It is widely used and many different utilities are available
+for creating image files in this format. In the
+<tt class="function">pixmap_create_from_xpm</tt>() function the first argument is
+a <tt class="classname">gtk.gdk.Window</tt> type. (Most GTK+ widgets have an
+underlying <tt class="classname">gtk.gdk.Window</tt> which can be retrieved by
+using the widget's window attribute.) The file, specified by
+<i class="parameter"><tt>filename</tt></i>, must contain an image in the XPM format and
+the image is loaded into the <i class="parameter"><tt>pixmap</tt></i> structure. The
+<i class="parameter"><tt>mask</tt></i> is a bitmap that specifies which bits of
+<i class="parameter"><tt>pixmap</tt></i> are opaque; it is created by the function. All
+other pixels are colored using the color specified by
+<i class="parameter"><tt>transparent_color</tt></i>. An example using this function is
+below.</p><p>Pixmaps can also be created from data in memory using the
+function:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ pixmap, mask = gtk.gdk.pixmap_create_from_xpm_d(<b class="parameter"><tt>window</tt></b>, <b class="parameter"><tt>transparent_color</tt></b>, <b class="parameter"><tt>data</tt></b>)
+</pre></td></tr></table><p>Small images can be incorporated into a program as data in the
+XPM format using the above function. A pixmap is created using this data,
+instead of reading it from a file. An example of such data is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ xpm_data = [
+ "16 16 3 1",
+ " c None",
+ ". c #000000000000",
+ "X c #FFFFFFFFFFFF",
+ " ",
+ " ...... ",
+ " .XXX.X. ",
+ " .XXX.XX. ",
+ " .XXX.XXX. ",
+ " .XXX..... ",
+ " .XXXXXXX. ",
+ " .XXXXXXX. ",
+ " .XXXXXXX. ",
+ " .XXXXXXX. ",
+ " .XXXXXXX. ",
+ " .XXXXXXX. ",
+ " .XXXXXXX. ",
+ " ......... ",
+ " ",
+ " "
+ ]
+</pre></td></tr></table><p>The final way to create a blank pixmap suitable for drawing
+operations is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ pixmap = gtk.gdk.Pixmap(<b class="parameter"><tt>window</tt></b>, <b class="parameter"><tt>width</tt></b>, <b class="parameter"><tt>height</tt></b>, <b class="parameter"><tt>depth</tt></b>=-1)
+</pre></td></tr></table><p><i class="parameter"><tt>window</tt></i> is either a
+<tt class="classname">gtk.gdk.Window</tt>. or <tt class="literal">None</tt>. If
+<i class="parameter"><tt>window</tt></i> is a <tt class="classname">gtk.gdk.Window</tt>
+then <i class="parameter"><tt>depth</tt></i> can be -1 to indicate that the depth
+should be determined from the window. If <i class="parameter"><tt>window</tt></i> is
+<tt class="literal">None</tt> then the <i class="parameter"><tt>depth</tt></i> must be
+specified.</p><p>The <a href="examples/pixmap.py" target="_top"><span><b class="command">pixmap.py</b></span></a> program is an
+example of using a pixmap in a button.
+<a href="sec-Images.html#pixmapfig" title="Figure 9.6. Pixmap in a Button Example">Figure 9.6, “Pixmap in a Button Exampleâ€</a> shows the result:</p><div class="figure"><a name="pixmapfig"></a><p class="title"><b>Figure 9.6. Pixmap in a Button Example</b></p><div class="mediaobject" align="center"><img src="figures/pixmap.png" align="middle" alt="Pixmap in a Button Example"></div></div><p>The source code is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 1 #!/usr/bin/env python
+ 2
+ 3 # example pixmap.py
+ 4
+ 5 import pygtk
+ 6 pygtk.require('2.0')
+ 7 import gtk
+ 8
+ 9 # XPM data of Open-File icon
+ 10 xpm_data = [
+ 11 "16 16 3 1",
+ 12 " c None",
+ 13 ". c #000000000000",
+ 14 "X c #FFFFFFFFFFFF",
+ 15 " ",
+ 16 " ...... ",
+ 17 " .XXX.X. ",
+ 18 " .XXX.XX. ",
+ 19 " .XXX.XXX. ",
+ 20 " .XXX..... ",
+ 21 " .XXXXXXX. ",
+ 22 " .XXXXXXX. ",
+ 23 " .XXXXXXX. ",
+ 24 " .XXXXXXX. ",
+ 25 " .XXXXXXX. ",
+ 26 " .XXXXXXX. ",
+ 27 " .XXXXXXX. ",
+ 28 " ......... ",
+ 29 " ",
+ 30 " "
+ 31 ]
+ 32
+ 33 class PixmapExample:
+ 34 # when invoked (via signal delete_event), terminates the application.
+ 35 def close_application(self, widget, event, data=None):
+ 36 gtk.main_quit()
+ 37 return False
+ 38
+ 39 # is invoked when the button is clicked. It just prints a message.
+ 40 def button_clicked(self, widget, data=None):
+ 41 print "button clicked"
+ 42
+ 43 def __init__(self):
+ 44 # create the main window, and attach delete_event signal to terminating
+ 45 # the application
+ 46 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ 47 window.connect("delete_event", self.close_application)
+ 48 window.set_border_width(10)
+ 49 window.show()
+ 50
+ 51 # now for the pixmap from XPM data
+ 52 pixmap, mask = gtk.gdk.pixmap_create_from_xpm_d(window.window,
+ 53 None,
+ 54 xpm_data)
+ 55
+ 56 # an image widget to contain the pixmap
+ 57 image = gtk.Image()
+ 58 image.set_from_pixmap(pixmap, mask)
+ 59 image.show()
+ 60
+ 61 # a button to contain the image widget
+ 62 button = gtk.Button()
+ 63 button.add(image)
+ 64 window.add(button)
+ 65 button.show()
+ 66
+ 67 button.connect("clicked", self.button_clicked)
+ 68
+ 69 def main():
+ 70 gtk.main()
+ 71 return 0
+ 72
+ 73 if __name__ == "__main__":
+ 74 PixmapExample()
+ 75 main()
+</pre></td></tr></table><p>A disadvantage of using pixmaps is that the displayed object
+is always rectangular, regardless of the image. We would like to create
+desktops and applications with icons that have more natural shapes. For
+example, for a game interface, we would like to have round buttons to push.
+The way to do this is using shaped windows.</p><p>A shaped window is simply a pixmap where the background pixels
+are transparent. This way, when the background image is multi-colored, we
+don't overwrite it with a rectangular, non-matching border around our icon.
+The <a href="examples/wheelbarrow.py" target="_top"><span><b class="command">wheelbarrow.py</b></span></a>
+example program displays a full wheelbarrow image on the desktop.
+<a href="sec-Images.html#wheelbarrowfig" title="Figure 9.7. Wheelbarrow Example Shaped Window">Figure 9.7, “Wheelbarrow Example Shaped Windowâ€</a> shows the wheelbarrow over a terminal
+window:</p><div class="figure"><a name="wheelbarrowfig"></a><p class="title"><b>Figure 9.7. Wheelbarrow Example Shaped Window</b></p><div class="mediaobject" align="center"><img src="figures/wheelbarrow.png" align="middle" alt="Wheelbarrow Example Shaped Window"></div></div><p>The source code for <a href="examples/wheelbarrow.py" target="_top"><span><b class="command">wheelbarrow.py</b></span></a>
+is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 1 #!/usr/bin/env python
+ 2
+ 3 # example wheelbarrow.py
+ 4
+ 5 import pygtk
+ 6 pygtk.require('2.0')
+ 7 import gtk
+ 8
+ 9 # XPM
+ 10 WheelbarrowFull_xpm = [
+ 11 "48 48 64 1",
+ 12 " c None",
+ 13 ". c #DF7DCF3CC71B",
+ 14 "X c #965875D669A6",
+ 15 "o c #71C671C671C6",
+ 16 "O c #A699A289A699",
+ 17 "+ c #965892489658",
+ 18 "@ c #8E38410330C2",
+ 19 "# c #D75C7DF769A6",
+ 20 "$ c #F7DECF3CC71B",
+ 21 "% c #96588A288E38",
+ 22 "&amp; c #A69992489E79",
+ 23 "* c #8E3886178E38",
+ 24 "= c #104008200820",
+ 25 "- c #596510401040",
+ 26 "; c #C71B30C230C2",
+ 27 ": c #C71B9A699658",
+ 28 "&gt; c #618561856185",
+ 29 ", c #20811C712081",
+ 30 "&lt; c #104000000000",
+ 31 "1 c #861720812081",
+ 32 "2 c #DF7D4D344103",
+ 33 "3 c #79E769A671C6",
+ 34 "4 c #861782078617",
+ 35 "5 c #41033CF34103",
+ 36 "6 c #000000000000",
+ 37 "7 c #49241C711040",
+ 38 "8 c #492445144924",
+ 39 "9 c #082008200820",
+ 40 "0 c #69A618611861",
+ 41 "q c #B6DA71C65144",
+ 42 "w c #410330C238E3",
+ 43 "e c #CF3CBAEAB6DA",
+ 44 "r c #71C6451430C2",
+ 45 "t c #EFBEDB6CD75C",
+ 46 "y c #28A208200820",
+ 47 "u c #186110401040",
+ 48 "i c #596528A21861",
+ 49 "p c #71C661855965",
+ 50 "a c #A69996589658",
+ 51 "s c #30C228A230C2",
+ 52 "d c #BEFBA289AEBA",
+ 53 "f c #596545145144",
+ 54 "g c #30C230C230C2",
+ 55 "h c #8E3882078617",
+ 56 "j c #208118612081",
+ 57 "k c #38E30C300820",
+ 58 "l c #30C2208128A2",
+ 59 "z c #38E328A238E3",
+ 60 "x c #514438E34924",
+ 61 "c c #618555555965",
+ 62 "v c #30C2208130C2",
+ 63 "b c #38E328A230C2",
+ 64 "n c #28A228A228A2",
+ 65 "m c #41032CB228A2",
+ 66 "M c #104010401040",
+ 67 "N c #492438E34103",
+ 68 "B c #28A2208128A2",
+ 69 "V c #A699596538E3",
+ 70 "C c #30C21C711040",
+ 71 "Z c #30C218611040",
+ 72 "A c #965865955965",
+ 73 "S c #618534D32081",
+ 74 "D c #38E31C711040",
+ 75 "F c #082000000820",
+ 76 " ",
+ 77 " .XoO ",
+ 78 " +@#$%o&amp; ",
+ 79 " *=-;#::o+ ",
+ 80 " &gt;,&lt;12#:34 ",
+ 81 " 45671#:X3 ",
+ 82 " +89&lt;02qwo ",
+ 83 "e* &gt;,67;ro ",
+ 84 "ty&gt; 459@&gt;+&amp;&amp; ",
+ 85 "$2u+ &gt;&lt;ipas8* ",
+ 86 "%$;=* *3:.Xa.dfg&gt; ",
+ 87 "Oh$;ya *3d.a8j,Xe.d3g8+ ",
+ 88 " Oh$;ka *3d$a8lz,,xxc:.e3g54 ",
+ 89 " Oh$;kO *pd$%svbzz,sxxxxfX..&amp;wn&gt; ",
+ 90 " Oh$@mO *3dthwlsslszjzxxxxxxx3:td8M4 ",
+ 91 " Oh$@g&amp; *3d$XNlvvvlllm,mNwxxxxxxxfa.:,B* ",
+ 92 " Oh$@,Od.czlllllzlmmqV@V#V@fxxxxxxxf:%j5&amp; ",
+ 93 " Oh$1hd5lllslllCCZrV#r#:#2AxxxxxxxxxcdwM* ",
+ 94 " OXq6c.%8vvvllZZiqqApA:mq:Xxcpcxxxxxfdc9* ",
+ 95 " 2r&lt;6gde3bllZZrVi7S@SV77A::qApxxxxxxfdcM ",
+ 96 " :,q-6MN.dfmZZrrSS:#riirDSAX@Af5xxxxxfevo",
+ 97 " +A26jguXtAZZZC7iDiCCrVVii7Cmmmxxxxxx%3g",
+ 98 " *#16jszN..3DZZZZrCVSA2rZrV7Dmmwxxxx&amp;en",
+ 99 " p2yFvzssXe:fCZZCiiD7iiZDiDSSZwwxx8e*&gt;",
+ 100 " OA1&lt;jzxwwc:$d%NDZZZZCCCZCCZZCmxxfd.B ",
+ 101 " 3206Bwxxszx%et.eaAp77m77mmmf3&amp;eeeg* ",
+ 102 " @26MvzxNzvlbwfpdettttttttttt.c,n&amp; ",
+ 103 " *;16=lsNwwNwgsvslbwwvccc3pcfu&lt;o ",
+ 104 " p;&lt;69BvwwsszslllbBlllllllu&lt;5+ ",
+ 105 " OS0y6FBlvvvzvzss,u=Blllj=54 ",
+ 106 " c1-699Blvlllllu7k96MMMg4 ",
+ 107 " *10y8n6FjvllllB&lt;166668 ",
+ 108 " S-kg+&gt;666&lt;M&lt;996-y6n&lt;8* ",
+ 109 " p71=4 m69996kD8Z-66698&amp;&amp; ",
+ 110 " &amp;i0ycm6n4 ogk17,0&lt;6666g ",
+ 111 " N-k-&lt;&gt; &gt;=01-kuu666&gt; ",
+ 112 " ,6ky&amp; &amp;46-10ul,66, ",
+ 113 " Ou0&lt;&gt; o66y&lt;ulw&lt;66&amp; ",
+ 114 " *kk5 &gt;66By7=xu664 ",
+ 115 " &lt;&lt;M4 466lj&lt;Mxu66o ",
+ 116 " *&gt;&gt; +66uv,zN666* ",
+ 117 " 566,xxj669 ",
+ 118 " 4666FF666&gt; ",
+ 119 " &gt;966666M ",
+ 120 " oM6668+ ",
+ 121 " *4 ",
+ 122 " ",
+ 123 " "
+ 124 ]
+ 125
+ 126 class WheelbarrowExample:
+ 127 # When invoked (via signal delete_event), terminates the application
+ 128 def close_application(self, widget, event, data=None):
+ 129 gtk.main_quit()
+ 130 return False
+ 131
+ 132 def __init__(self):
+ 133 # Create the main window, and attach delete_event signal to terminate
+ 134 # the application. Note that the main window will not have a titlebar
+ 135 # since we're making it a popup.
+ 136 window = gtk.Window(gtk.WINDOW_POPUP)
+ 137 window.connect("delete_event", self.close_application)
+ 138 window.set_events(window.get_events() | gtk.gdk.BUTTON_PRESS_MASK)
+ 139 window.connect("button_press_event", self.close_application)
+ 140 window.show()
+ 141
+ 142 # Now for the pixmap and the image widget
+ 143 pixmap, mask = gtk.gdk.pixmap_create_from_xpm_d(
+ 144 window.window, None, WheelbarrowFull_xpm)
+ 145 image = gtk.Image()
+ 146 image.set_from_pixmap(pixmap, mask)
+ 147 image.show()
+ 148
+ 149 # To display the image, we use a fixed widget to place the image
+ 150 fixed = gtk.Fixed()
+ 151 fixed.set_size_request(200, 200)
+ 152 fixed.put(image, 0, 0)
+ 153 window.add(fixed)
+ 154 fixed.show()
+ 155
+ 156 # This masks out everything except for the image itself
+ 157 window.shape_combine_mask(mask, 0, 0)
+ 158
+ 159 # show the window
+ 160 window.set_position(gtk.WIN_POS_CENTER_ALWAYS)
+ 161 window.show()
+ 162
+ 163 def main():
+ 164 gtk.main()
+ 165 return 0
+ 166
+ 167 if __name__ == "__main__":
+ 168 WheelbarrowExample()
+ 169 main()
+</pre></td></tr></table><p>To make the wheelbarrow image sensitive, we attached the
+"button_press_event" signal to make the program exit. Lines 138-139 make the
+picture sensitive to a mouse button being pressed and connect the
+<tt class="methodname">close_application</tt>() method.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-Dialogs.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-MiscellaneousWidgets.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-Rulers.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">9.5. Dialogs </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 9.7. Rulers</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-ItemFactoryExample.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-ItemFactoryExample.html
new file mode 100644
index 0000000..a9fcd97
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-ItemFactoryExample.html
@@ -0,0 +1,101 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>11.4. Item Factory Example</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-MenuWidget.html" title="Chapter 11. Menu Widget"><link rel="previous" href="sec-UsingItemFactory.html" title="11.3. Using ItemFactory"><link rel="next" href="ch-DrawingArea.html" title="Chapter 12. Drawing Area"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">11.4. Item Factory Example</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-UsingItemFactory.html">Prev</a> </td><th width="60%" align="center">Chapter 11. Menu Widget</th><td width="20%" align="right"> <a accesskey="n" href="ch-DrawingArea.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-ItemFactoryExample"></a>11.4. Item Factory Example</h2></div></div><div></div></div><p>The <a href="examples/itemfactory.py" target="_top"><span><b class="command">itemfactory.py</b></span></a>
+example program uses the <tt class="classname">gtk.ItemFactory</tt>.
+<a href="sec-ItemFactoryExample.html#itemfactoryfig" title="Figure 11.2. Item Factory Example">Figure 11.2, “Item Factory Exampleâ€</a> illustrates the program display:</p><div class="figure"><a name="itemfactoryfig"></a><p class="title"><b>Figure 11.2. Item Factory Example</b></p><div class="mediaobject" align="center"><img src="figures/itemfactory.png" align="middle" alt="Item Factory Example"></div></div><p>The source code for <a href="examples/itemfactory.py" target="_top"><span><b class="command">itemfactory.py</b></span></a>
+is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 1 #!/usr/bin/env python
+ 2
+ 3 # example itemfactory.py
+ 4
+ 5 import pygtk
+ 6 pygtk.require('2.0')
+ 7 import gtk
+ 8
+ 9 class ItemFactoryExample:
+ 10 # Obligatory basic callback
+ 11 def print_hello(self, w, data):
+ 12 print "Hello, World!"
+ 13
+ 14 # This is the ItemFactoryEntry structure used to generate new menus.
+ 15 # Item 1: The menu path. The letter after the underscore indicates an
+ 16 # accelerator key once the menu is open.
+ 17 # Item 2: The accelerator key for the entry
+ 18 # Item 3: The callback.
+ 19 # Item 4: The callback action. This changes the parameters with
+ 20 # which the callback is called. The default is 0.
+ 21 # Item 5: The item type, used to define what kind of an item it is.
+ 22 # Here are the possible values:
+ 23
+ 24 # NULL -&gt; "&lt;Item&gt;"
+ 25 # "" -&gt; "&lt;Item&gt;"
+ 26 # "&lt;Title&gt;" -&gt; create a title item
+ 27 # "&lt;Item&gt;" -&gt; create a simple item
+ 28 # "&lt;CheckItem&gt;" -&gt; create a check item
+ 29 # "&lt;ToggleItem&gt;" -&gt; create a toggle item
+ 30 # "&lt;RadioItem&gt;" -&gt; create a radio item
+ 31 # &lt;path&gt; -&gt; path of a radio item to link against
+ 32 # "&lt;Separator&gt;" -&gt; create a separator
+ 33 # "&lt;Branch&gt;" -&gt; create an item to hold sub items (optional)
+ 34 # "&lt;LastBranch&gt;" -&gt; create a right justified branch
+ 35
+ 36 def get_main_menu(self, window):
+ 37 accel_group = gtk.AccelGroup()
+ 38
+ 39 # This function initializes the item factory.
+ 40 # Param 1: The type of menu - can be MenuBar, Menu,
+ 41 # or OptionMenu.
+ 42 # Param 2: The path of the menu.
+ 43 # Param 3: A reference to an AccelGroup. The item factory sets up
+ 44 # the accelerator table while generating menus.
+ 45 item_factory = gtk.ItemFactory(gtk.MenuBar, "&lt;main&gt;", accel_group)
+ 46
+ 47 # This method generates the menu items. Pass to the item factory
+ 48 # the list of menu items
+ 49 item_factory.create_items(self.menu_items)
+ 50
+ 51 # Attach the new accelerator group to the window.
+ 52 window.add_accel_group(accel_group)
+ 53
+ 54 # need to keep a reference to item_factory to prevent its destruction
+ 55 self.item_factory = item_factory
+ 56 # Finally, return the actual menu bar created by the item factory.
+ 57 return item_factory.get_widget("&lt;main&gt;")
+ 58
+ 59 def __init__(self):
+ 60 self.menu_items = (
+ 61 ( "/_File", None, None, 0, "&lt;Branch&gt;" ),
+ 62 ( "/File/_New", "&lt;control&gt;N", self.print_hello, 0, None ),
+ 63 ( "/File/_Open", "&lt;control&gt;O", self.print_hello, 0, None ),
+ 64 ( "/File/_Save", "&lt;control&gt;S", self.print_hello, 0, None ),
+ 65 ( "/File/Save _As", None, None, 0, None ),
+ 66 ( "/File/sep1", None, None, 0, "&lt;Separator&gt;" ),
+ 67 ( "/File/Quit", "&lt;control&gt;Q", gtk.main_quit, 0, None ),
+ 68 ( "/_Options", None, None, 0, "&lt;Branch&gt;" ),
+ 69 ( "/Options/Test", None, None, 0, None ),
+ 70 ( "/_Help", None, None, 0, "&lt;LastBranch&gt;" ),
+ 71 ( "/_Help/About", None, None, 0, None ),
+ 72 )
+ 73 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ 74 window.connect("destroy", lambda w: gtk.main_quit(), "WM destroy")
+ 75 window.set_title("Item Factory")
+ 76 window.set_size_request(300, 200)
+ 77
+ 78 main_vbox = gtk.VBox(False, 1)
+ 79 main_vbox.set_border_width(1)
+ 80 window.add(main_vbox)
+ 81 main_vbox.show()
+ 82
+ 83 menubar = self.get_main_menu(window)
+ 84
+ 85 main_vbox.pack_start(menubar, False, True, 0)
+ 86 menubar.show()
+ 87 window.show()
+ 88
+ 89 def main():
+ 90 gtk.main()
+ 91 return 0
+ 92
+ 93 if __name__ == "__main__":
+ 94 ItemFactoryExample()
+ 95 main()
+</pre></td></tr></table><p>For now, there's only this example. An explanation and lots 'o'
+comments will follow later.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-UsingItemFactory.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-MenuWidget.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch-DrawingArea.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">11.3. Using ItemFactory </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 12. Drawing Area</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-KeyAndMouseBindings.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-KeyAndMouseBindings.html
new file mode 100644
index 0000000..a6ece19
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-KeyAndMouseBindings.html
@@ -0,0 +1,20 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>8.4. Key and Mouse Bindings</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-RangeWidgets.html" title="Chapter 8. Range Widgets"><link rel="previous" href="sec-CommonRangeMethods.html" title="8.3. Common Range Methods"><link rel="next" href="sec-RangeWidgetEample.html" title="8.5. Range Widget Example"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">8.4. Key and Mouse Bindings</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-CommonRangeMethods.html">Prev</a> </td><th width="60%" align="center">Chapter 8. Range Widgets</th><td width="20%" align="right"> <a accesskey="n" href="sec-RangeWidgetEample.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-KeyAndMouseBindings"></a>8.4. Key and Mouse Bindings</h2></div></div><div></div></div><p>All of the GTK+ range widgets react to mouse clicks in more or
+less the same way. Clicking <span class="mousebutton">button-1</span> in the
+trough will cause its adjustment's <i class="parameter"><tt>page_increment</tt></i> to
+be added or subtracted from its <i class="parameter"><tt>value</tt></i>, and the slider
+to be moved accordingly. Clicking mouse <span class="mousebutton">button-2</span>
+in the trough will jump the slider to the point at which the button was
+clicked. Clicking any button on a scrollbar's arrows will cause its
+adjustment's value to change <i class="parameter"><tt>step_increment</tt></i> at a
+time.</p><p>Scrollbars are not focusable, thus have no key bindings. The key
+bindings for the other range widgets (which are, of course, only active when
+the widget has focus) do not differentiate between horizontal and vertical
+range widgets.</p><p>All range widgets can be operated with the <span class="keysym">left
+arrow</span>, <span class="keysym">right arrow</span>, <span class="keysym">up arrow</span> and
+<span class="keysym">down arrow</span> keys, as well as with the <span><b class="keycap">Page
+Up</b></span> and <span><b class="keycap">Page Down</b></span> keys. The arrows move the slider
+by <i class="parameter"><tt>step_increment</tt></i>, while <span><b class="keycap">Page Up</b></span> and
+<span><b class="keycap">Page Down</b></span> move it by
+<i class="parameter"><tt>page_increment</tt></i>.</p><p>The user can also move the slider all the way to one end or the
+other of the trough using the keyboard. This is done with the
+<span><b class="keycap">Home</b></span> and <span><b class="keycap">End</b></span> keys.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-CommonRangeMethods.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-RangeWidgets.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-RangeWidgetEample.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">8.3. Common Range Methods </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 8.5. Range Widget Example</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-Layout.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-Layout.html
new file mode 100644
index 0000000..a7bee99
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-Layout.html
@@ -0,0 +1,112 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>10.4. Layout Container</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-ContainerWidgets.html" title="Chapter 10. Container Widgets"><link rel="previous" href="sec-Fixed.html" title="10.3. Fixed Container"><link rel="next" href="sec-Frames.html" title="10.5. Frames"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">10.4. Layout Container</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-Fixed.html">Prev</a> </td><th width="60%" align="center">Chapter 10. Container Widgets</th><td width="20%" align="right"> <a accesskey="n" href="sec-Frames.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-Layout"></a>10.4. Layout Container</h2></div></div><div></div></div><p>The <tt class="classname">Layout</tt> container is similar to the
+<tt class="classname">Fixed</tt> container except that it implements an infinite
+(where infinity is less than 2^32) scrolling area. The X window system has a
+limitation where windows can be at most 32767 pixels wide or tall. The
+<tt class="classname">Layout</tt> container gets around this limitation by doing
+some exotic stuff using window and bit gravities, so that you can have
+smooth scrolling even when you have many child widgets in your scrolling
+area.</p><p>A <tt class="classname">Layout</tt> container is created
+using:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ layout = gtk.Layout(<b class="parameter"><tt>hadjustment</tt></b>=None, <b class="parameter"><tt>vadjustment</tt></b>=None)
+</pre></td></tr></table><p>As you can see, you can optionally specify the
+<tt class="classname">Adjustment</tt> objects (see <a href="ch-Adjustments.html" title="Chapter 7. Adjustments">Chapter 7, <i>Adjustments</i></a>) that the <tt class="classname">Layout</tt>
+widget will use for its scrolling. If you don't specify the
+<tt class="classname">Adjustment</tt> objects, new ones will be created.</p><p>You can add and move widgets in the
+<tt class="classname">Layout</tt> container using the following two
+methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ layout.put(<b class="parameter"><tt>child_widget</tt></b>, <b class="parameter"><tt>x</tt></b>, <b class="parameter"><tt>y</tt></b>)
+
+ layout.move(<b class="parameter"><tt>child_widget</tt></b>, <b class="parameter"><tt>x</tt></b>, <b class="parameter"><tt>y</tt></b>)
+</pre></td></tr></table><p>The size of the <tt class="classname">Layout</tt> container can be
+set and retrieved using the next methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ layout.set_size(<b class="parameter"><tt>width</tt></b>, <b class="parameter"><tt>height</tt></b>)
+
+ size = layout.get_size()
+</pre></td></tr></table><p>The final four methods for use with
+<tt class="classname">Layout</tt> widgets are for manipulating the horizontal
+and vertical adjustment widgets:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ hadj = layout.get_hadjustment()
+
+ vadj = layout.get_vadjustment()
+
+ layout.set_hadjustment(<b class="parameter"><tt>adjustment</tt></b>)
+
+ layout.set_vadjustment(<b class="parameter"><tt>adjustment</tt></b>)
+</pre></td></tr></table><p>The <a href="examples/layout.py" target="_top"><span><b class="command">layout.py</b></span></a> example
+program creates three buttons and puts them in a layout widget. when a
+button is clicked, it is moved to a random location in the layout.
+<a href="sec-Layout.html#layoutfig" title="Figure 10.3. Layout Example">Figure 10.3, “Layout Exampleâ€</a> illustrates the starting display of the
+program:</p><div class="figure"><a name="layoutfig"></a><p class="title"><b>Figure 10.3. Layout Example</b></p><div class="mediaobject" align="center"><img src="figures/layout.png" align="middle" alt="Layout Example"></div></div><p>The <a href="examples/layout.py" target="_top"><span><b class="command">layout.py</b></span></a> source code
+is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 1 #!/usr/bin/env python
+ 2
+ 3 # example layout.py
+ 4
+ 5 import pygtk
+ 6 pygtk.require('2.0')
+ 7 import gtk
+ 8 import random
+ 9
+ 10 class LayoutExample:
+ 11 def WindowDeleteEvent(self, widget, event):
+ 12 # return false so that window will be destroyed
+ 13 return False
+ 14
+ 15 def WindowDestroy(self, widget, *data):
+ 16 # exit main loop
+ 17 gtk.main_quit()
+ 18
+ 19 def ButtonClicked(self, button):
+ 20 # move the button
+ 21 self.layout.move(button, random.randint(0,500),
+ 22 random.randint(0,500))
+ 23
+ 24 def __init__(self):
+ 25 # create the top level window
+ 26 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ 27 window.set_title("Layout Example")
+ 28 window.set_default_size(300, 300)
+ 29 window.connect("delete-event", self.WindowDeleteEvent)
+ 30 window.connect("destroy", self.WindowDestroy)
+ 31 # create the table and pack into the window
+ 32 table = gtk.Table(2, 2, False)
+ 33 window.add(table)
+ 34 # create the layout widget and pack into the table
+ 35 self.layout = gtk.Layout(None, None)
+ 36 self.layout.set_size(600, 600)
+ 37 table.attach(self.layout, 0, 1, 0, 1, gtk.FILL|gtk.EXPAND,
+ 38 gtk.FILL|gtk.EXPAND, 0, 0)
+ 39 # create the scrollbars and pack into the table
+ 40 vScrollbar = gtk.VScrollbar(None)
+ 41 table.attach(vScrollbar, 1, 2, 0, 1, gtk.FILL|gtk.SHRINK,
+ 42 gtk.FILL|gtk.SHRINK, 0, 0)
+ 43 hScrollbar = gtk.HScrollbar(None)
+ 44 table.attach(hScrollbar, 0, 1, 1, 2, gtk.FILL|gtk.SHRINK,
+ 45 gtk.FILL|gtk.SHRINK, 0, 0)
+ 46 # tell the scrollbars to use the layout widget's adjustments
+ 47 vAdjust = self.layout.get_vadjustment()
+ 48 vScrollbar.set_adjustment(vAdjust)
+ 49 hAdjust = self.layout.get_hadjustment()
+ 50 hScrollbar.set_adjustment(hAdjust)
+ 51 # create 3 buttons and put them into the layout widget
+ 52 button = gtk.Button("Press Me")
+ 53 button.connect("clicked", self.ButtonClicked)
+ 54 self.layout.put(button, 0, 0)
+ 55 button = gtk.Button("Press Me")
+ 56 button.connect("clicked", self.ButtonClicked)
+ 57 self.layout.put(button, 100, 0)
+ 58 button = gtk.Button("Press Me")
+ 59 button.connect("clicked", self.ButtonClicked)
+ 60 self.layout.put(button, 200, 0)
+ 61 # show all the widgets
+ 62 window.show_all()
+ 63
+ 64 def main():
+ 65 # enter the main loop
+ 66 gtk.main()
+ 67 return 0
+ 68
+ 69 if __name__ == "__main__":
+ 70 LayoutExample()
+ 71 main()
+</pre></td></tr></table></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-Fixed.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-ContainerWidgets.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-Frames.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">10.3. Fixed Container </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 10.5. Frames</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-ManipulatingTreeViews.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-ManipulatingTreeViews.html
new file mode 100644
index 0000000..4305d91
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-ManipulatingTreeViews.html
@@ -0,0 +1,34 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>14.6. Manipulating TreeViews</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-TreeViewWidget.html" title="Chapter 14. Tree View Widget"><link rel="previous" href="sec-TreeViewColumns.html" title="14.5. TreeViewColumns"><link rel="next" href="sec-TreeViewSignals.html" title="14.7. TreeView Signals"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">14.6. Manipulating TreeViews</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-TreeViewColumns.html">Prev</a> </td><th width="60%" align="center">Chapter 14. Tree View Widget</th><td width="20%" align="right"> <a accesskey="n" href="sec-TreeViewSignals.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-ManipulatingTreeViews"></a>14.6. Manipulating TreeViews</h2></div></div><div></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-ManagingColumns"></a>14.6.1. Managing Columns</h3></div></div><div></div></div><p>The <tt class="classname">TreeViewColumn</tt>s in a
+<tt class="classname">TreeView</tt> can be retrieved singly or as a list using
+the methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treeviewcolumn = treeview.get_column(<b class="parameter"><tt>n</tt></b>)
+ columnlist = treeview.get_columns()
+</pre></td></tr></table><p>where <i class="parameter"><tt>n</tt></i> is the index (starting from 0)
+of the column to retrieve. A column can be removed using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treeview.remove_column(<b class="parameter"><tt>column</tt></b>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>column</tt></i> is a
+<tt class="classname">TreeViewColumn</tt> in
+<i class="parameter"><tt>treeview</tt></i>.</p><p>Rows that have child rows are displayed in the
+<tt class="classname">TreeView</tt> with an expander arrow (see <a href="sec-CellRenderers.html#celldatafuncfig" title="Figure 14.3. CellRenderer Data Function">Figure 14.3, “CellRenderer Data Functionâ€</a>) that the user clicks on to hide or reveal the
+child row(s). The column that the expander arrow is displayed in can be
+changed using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treeview.set_expander_column(<b class="parameter"><tt>column</tt></b>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>column</tt></i> is a
+<tt class="classname">TreeViewColumn</tt> in treeview. This method is useful
+when you want the first column to not indent. For example, <a href="sec-ManipulatingTreeViews.html#treeviewcolumn1expanderfig" title="Figure 14.7. Expander Arrow in Second Column">Figure 14.7, “Expander Arrow in Second Columnâ€</a> illustrates the expander arrow in the
+second column:</p><div class="figure"><a name="treeviewcolumn1expanderfig"></a><p class="title"><b>Figure 14.7. Expander Arrow in Second Column</b></p><div class="mediaobject" align="center"><img src="figures/treeviewcolumn1expander.png" align="middle" alt="Expander Arrow in Second Column"></div></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-ExpandCollapseChildRows"></a>14.6.2. Expanding and Collapsing Child Rows</h3></div></div><div></div></div><p>All the rows displayed in a <tt class="classname">TreeView</tt> can
+be programmatically expanded or collapsed using the following
+methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treeview.expand_all()
+ treeview.collapse_all()
+</pre></td></tr></table><p>These methods are useful if you want to initialize the
+<tt class="classname">TreeView</tt> display to a known state. Individual rows
+can be expanded or collapsed using:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treeview.expand_row(<b class="parameter"><tt>path</tt></b>, <b class="parameter"><tt>open_all</tt></b>)
+ treeview.collapse_row(<b class="parameter"><tt>path</tt></b>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>path</tt></i> is the tree path to a row in
+treeview, and if <i class="parameter"><tt>open_all</tt></i> is <tt class="literal">TRUE</tt>
+all descendant rows of <i class="parameter"><tt>path</tt></i> are expanded; otherwise
+just the immediate children are expanded.</p><p>You can determine if a row is expanded using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ is_expanded = treeview.row_expanded(<b class="parameter"><tt>path</tt></b>)
+</pre></td></tr></table></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-TreeViewColumns.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-TreeViewWidget.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-TreeViewSignals.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">14.5. TreeViewColumns </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 14.7. TreeView Signals</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-ManualMenuExample.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-ManualMenuExample.html
new file mode 100644
index 0000000..efc730b
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-ManualMenuExample.html
@@ -0,0 +1,108 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>11.2. Manual Menu Example</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-MenuWidget.html" title="Chapter 11. Menu Widget"><link rel="previous" href="ch-MenuWidget.html" title="Chapter 11. Menu Widget"><link rel="next" href="sec-UsingItemFactory.html" title="11.3. Using ItemFactory"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">11.2. Manual Menu Example</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch-MenuWidget.html">Prev</a> </td><th width="60%" align="center">Chapter 11. Menu Widget</th><td width="20%" align="right"> <a accesskey="n" href="sec-UsingItemFactory.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-ManualMenuExample"></a>11.2. Manual Menu Example</h2></div></div><div></div></div><p>That should about do it. Let's take a look at the <a href="examples/menu.py" target="_top"><span><b class="command">menu.py</b></span></a> example program to
+help clarify the concepts.
+<a href="sec-ManualMenuExample.html#menufig" title="Figure 11.1. Menu Example">Figure 11.1, “Menu Exampleâ€</a> illustrates the program display:</p><div class="figure"><a name="menufig"></a><p class="title"><b>Figure 11.1. Menu Example</b></p><div class="mediaobject" align="center"><img src="figures/menu.png" align="middle" alt="Menu Example"></div></div><p>The <a href="examples/menu.py" target="_top"><span><b class="command">menu.py</b></span></a> program source
+code is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 1 #!/usr/bin/env python
+ 2
+ 3 # example menu.py
+ 4
+ 5 import pygtk
+ 6 pygtk.require('2.0')
+ 7 import gtk
+ 8
+ 9 class MenuExample:
+ 10 def __init__(self):
+ 11 # create a new window
+ 12 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ 13 window.set_size_request(200, 100)
+ 14 window.set_title("GTK Menu Test")
+ 15 window.connect("delete_event", lambda w,e: gtk.main_quit())
+ 16
+ 17 # Init the menu-widget, and remember -- never
+ 18 # show() the menu widget!!
+ 19 # This is the menu that holds the menu items, the one that
+ 20 # will pop up when you click on the "Root Menu" in the app
+ 21 menu = gtk.Menu()
+ 22
+ 23 # Next we make a little loop that makes three menu-entries for
+ 24 # "test-menu". Notice the call to gtk_menu_append. Here we are
+ 25 # adding a list of menu items to our menu. Normally, we'd also
+ 26 # catch the "clicked" signal on each of the menu items and setup a
+ 27 # callback for it, but it's omitted here to save space.
+ 28 for i in range(3):
+ 29 # Copy the names to the buf.
+ 30 buf = "Test-undermenu - %d" % i
+ 31
+ 32 # Create a new menu-item with a name...
+ 33 menu_items = gtk.MenuItem(buf)
+ 34
+ 35 # ...and add it to the menu.
+ 36 menu.append(menu_items)
+ 37
+ 38 # Do something interesting when the menuitem is selected
+ 39 menu_items.connect("activate", self.menuitem_response, buf)
+ 40
+ 41 # Show the widget
+ 42 menu_items.show()
+ 43
+ 44 # This is the root menu, and will be the label
+ 45 # displayed on the menu bar. There won't be a signal handler attached,
+ 46 # as it only pops up the rest of the menu when pressed.
+ 47 root_menu = gtk.MenuItem("Root Menu")
+ 48
+ 49 root_menu.show()
+ 50
+ 51 # Now we specify that we want our newly created "menu" to be the
+ 52 # menu for the "root menu"
+ 53 root_menu.set_submenu(menu)
+ 54
+ 55 # A vbox to put a menu and a button in:
+ 56 vbox = gtk.VBox(False, 0)
+ 57 window.add(vbox)
+ 58 vbox.show()
+ 59
+ 60 # Create a menu-bar to hold the menus and add it to our main window
+ 61 menu_bar = gtk.MenuBar()
+ 62 vbox.pack_start(menu_bar, False, False, 2)
+ 63 menu_bar.show()
+ 64
+ 65 # Create a button to which to attach menu as a popup
+ 66 button = gtk.Button("press me")
+ 67 button.connect_object("event", self.button_press, menu)
+ 68 vbox.pack_end(button, True, True, 2)
+ 69 button.show()
+ 70
+ 71 # And finally we append the menu-item to the menu-bar -- this is the
+ 72 # "root" menu-item I have been raving about =)
+ 73 menu_bar.append (root_menu)
+ 74
+ 75 # always display the window as the last step so it all splashes on
+ 76 # the screen at once.
+ 77 window.show()
+ 78
+ 79 # Respond to a button-press by posting a menu passed in as widget.
+ 80 #
+ 81 # Note that the "widget" argument is the menu being posted, NOT
+ 82 # the button that was pressed.
+ 83 def button_press(self, widget, event):
+ 84 if event.type == gtk.gdk.BUTTON_PRESS:
+ 85 widget.popup(None, None, None, event.button, event.time)
+ 86 # Tell calling code that we have handled this event the buck
+ 87 # stops here.
+ 88 return True
+ 89 # Tell calling code that we have not handled this event pass it on.
+ 90 return False
+ 91
+ 92 # Print a string when a menu item is selected
+ 93 def menuitem_response(self, widget, string):
+ 94 print "%s" % string
+ 95
+ 96 def main():
+ 97 gtk.main()
+ 98 return 0
+ 99
+ 100 if __name__ == "__main__":
+ 101 MenuExample()
+ 102 main()
+</pre></td></tr></table><p>You may also set a menu item to be insensitive and, using an
+accelerator table, bind keys to menu callbacks.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch-MenuWidget.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-MenuWidget.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-UsingItemFactory.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 11. Menu Widget </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 11.3. Using ItemFactory</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-MenuItems.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-MenuItems.html
new file mode 100644
index 0000000..642dee5
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-MenuItems.html
@@ -0,0 +1 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>17.3. Menu Items</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-UndocumentedWidgets.html" title="Chapter 17. Undocumented Widgets"><link rel="previous" href="sec-OptionMenu.html" title="17.2. Option Menu"><link rel="next" href="sec-Curves.html" title="17.4. Curves"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">17.3. Menu Items</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-OptionMenu.html">Prev</a> </td><th width="60%" align="center">Chapter 17. Undocumented Widgets</th><td width="20%" align="right"> <a accesskey="n" href="sec-Curves.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-MenuItems"></a>17.3. Menu Items</h2></div></div><div></div></div><p></p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2834318"></a>17.3.1. Check Menu Item</h3></div></div><div></div></div><p></p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2906601"></a>17.3.2. Radio Menu Item</h3></div></div><div></div></div><p></p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2906613"></a>17.3.3. Separator Menu Item</h3></div></div><div></div></div><p></p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2879329"></a>17.3.4. Tearoff Menu Item</h3></div></div><div></div></div><p></p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-OptionMenu.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-UndocumentedWidgets.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-Curves.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">17.2. Option Menu </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 17.4. Curves</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-MessageDialog.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-MessageDialog.html
new file mode 100644
index 0000000..9f54c71
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-MessageDialog.html
@@ -0,0 +1 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>17.5. Message Dialog</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-UndocumentedWidgets.html" title="Chapter 17. Undocumented Widgets"><link rel="previous" href="sec-Curves.html" title="17.4. Curves"><link rel="next" href="sec-GammaCurve.html" title="17.6. Gamma Curve"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">17.5. Message Dialog</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-Curves.html">Prev</a> </td><th width="60%" align="center">Chapter 17. Undocumented Widgets</th><td width="20%" align="right"> <a accesskey="n" href="sec-GammaCurve.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-MessageDialog"></a>17.5. Message Dialog</h2></div></div><div></div></div><p></p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-Curves.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-UndocumentedWidgets.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-GammaCurve.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">17.4. Curves </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 17.6. Gamma Curve</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-MonitoringIO.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-MonitoringIO.html
new file mode 100644
index 0000000..816e6b8
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-MonitoringIO.html
@@ -0,0 +1,38 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>19.2. Monitoring IO</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-TimeoutsIOAndIdleFunctions.html" title="Chapter 19. Timeouts, IO and Idle Functions"><link rel="previous" href="ch-TimeoutsIOAndIdleFunctions.html" title="Chapter 19. Timeouts, IO and Idle Functions"><link rel="next" href="sec-IdleFunctions.html" title="19.3. Idle Functions"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">19.2. Monitoring IO</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch-TimeoutsIOAndIdleFunctions.html">Prev</a> </td><th width="60%" align="center">Chapter 19. Timeouts, IO and Idle Functions</th><td width="20%" align="right"> <a accesskey="n" href="sec-IdleFunctions.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-MonitoringIO"></a>19.2. Monitoring IO</h2></div></div><div></div></div><p>You can check for the ability to read from or write to a file
+(either a Python file or a lower level OS file) and then automatically
+invoke a callback. This is especially useful for networking applications.
+The gobject module function:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ source_id = gobject.io_add_watch(<i class="parameter"><tt>source</tt></i>, <i class="parameter"><tt>condition</tt></i>, <i class="parameter"><tt>callback</tt></i>)
+</pre></td></tr></table><p>where the first argument (<i class="parameter"><tt>source</tt></i>) is the
+open file (Python file object or lower level file descriptor integer) you
+wish to have watched. The <tt class="function">gobject.io_add_watch</tt>()
+function uses the lower level file descriptor integer internally but the
+function will extract it from the Python file object using the
+<tt class="methodname">fileno</tt>() method as needed. The second argument
+(<i class="parameter"><tt>condition</tt></i>) specifies what you want to look for. This
+may be one of:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ gobject.IO_IN - There is data ready for reading from your file.
+
+ gobject.IO_OUT - The file is ready for writing.
+
+ gobject.IO_PRI - There is urgent data to read.
+
+ gobject.IO_ERR - Error condition.
+
+ gobject.IO_HUP - Hung up (the connection has been broken, usually for
+ pipes and sockets).
+</pre></td></tr></table><p>These are defined in the gobject module. As I'm sure you've
+figured out already, the third argument is the <i class="parameter"><tt>callback</tt></i>
+you wish to have called when the above conditions are satisfied.</p><p>The return value <i class="parameter"><tt>source_id</tt></i> may be used
+to stop the monitoring of the file by using the following function:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ gobject.source_remove(<i class="parameter"><tt>source_id</tt></i>)
+</pre></td></tr></table><p>The callback function should be similar to:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def input_callback(<i class="parameter"><tt>source</tt></i>, <i class="parameter"><tt>condition</tt></i>):
+</pre></td></tr></table><p>where <i class="parameter"><tt>source</tt></i> and
+<i class="parameter"><tt>condition</tt></i> are as specified above. The source value
+will be the lower level file descriptor integer and not the Python file
+object (i.e. the value that is returned from the Python file method
+<tt class="methodname">fileno</tt>()).</p><p>You may also stop the callback function from being called again
+by returning zero or <tt class="literal">FALSE</tt> from your callback. If you
+want your callback to be called again, it should return
+<tt class="literal">TRUE</tt>.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch-TimeoutsIOAndIdleFunctions.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-TimeoutsIOAndIdleFunctions.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-IdleFunctions.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 19. Timeouts, IO and Idle Functions </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 19.3. Idle Functions</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-Notebooks.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-Notebooks.html
new file mode 100644
index 0000000..7277378
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-Notebooks.html
@@ -0,0 +1,223 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>10.12. Notebooks</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-ContainerWidgets.html" title="Chapter 10. Container Widgets"><link rel="previous" href="sec-Toolbar.html" title="10.11. Toolbar"><link rel="next" href="sec-PlugsAndSockets.html" title="10.13. Plugs and Sockets"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">10.12. Notebooks</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-Toolbar.html">Prev</a> </td><th width="60%" align="center">Chapter 10. Container Widgets</th><td width="20%" align="right"> <a accesskey="n" href="sec-PlugsAndSockets.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-Notebooks"></a>10.12. Notebooks</h2></div></div><div></div></div><p>The <tt class="classname">NoteBook</tt> Widget is a collection of
+"pages" that overlap each other; each page contains different information
+with only one page visible at a time. This widget has become more common
+lately in GUI programming, and it is a good way to show blocks of similar
+information that warrant separation in their display.</p><p>The first function call you will need to know, as you can probably
+guess by now, is used to create a new notebook widget.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ notebook = gtk.Notebook()
+</pre></td></tr></table><p>Once the notebook has been created, there are a number of
+methods that operate on the notebook widget. Let's look at them
+individually.</p><p>The first one we will look at is how to position the page
+indicators. These page indicators or "tabs" as they are referred to, can be
+positioned in four ways: top, bottom, left, or right.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ notebook.set_tab_pos(<b class="parameter"><tt>pos</tt></b>)
+</pre></td></tr></table><p><i class="parameter"><tt>pos</tt></i> will be one of the following, which are
+pretty self explanatory:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ POS_LEFT
+ POS_RIGHT
+ POS_TOP
+ POS_BOTTOM
+</pre></td></tr></table><p><tt class="literal">POS_TOP</tt> is the default.</p><p>Next we will look at how to add pages to the notebook. There are
+three ways to add pages to a <tt class="classname">NoteBook</tt>. Let's look at
+the first two together as they are quite similar.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ notebook.append_page(<b class="parameter"><tt>child</tt></b>, <b class="parameter"><tt>tab_label</tt></b>)
+
+ notebook.prepend_page(<b class="parameter"><tt>child</tt></b>, <b class="parameter"><tt>tab_label</tt></b>)
+</pre></td></tr></table><p>These methods add pages to the notebook by inserting them from
+the back of the notebook (append), or the front of the notebook (prepend).
+<i class="parameter"><tt>child</tt></i> is the widget that is placed within the notebook
+page, and <i class="parameter"><tt>tab_label</tt></i> is the label for the page being
+added. The <i class="parameter"><tt>child</tt></i> widget must be created separately, and
+is typically a set of options setup within one of the other container
+widgets, such as a table.</p><p>The final method for adding a page to the notebook contains all
+of the properties of the previous two, but it allows you to specify what
+position you want the page to be in the notebook.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ notebook.insert_page(<b class="parameter"><tt>child</tt></b>, <b class="parameter"><tt>tab_label</tt></b>, <b class="parameter"><tt>position</tt></b>)
+</pre></td></tr></table><p>The parameters are the same as <tt class="methodname">append</tt>()
+and <tt class="methodname">prepend</tt>() except it contains an extra
+parameter, <i class="parameter"><tt>position</tt></i>. This parameter is used to
+specify what place this page will be inserted into; the first page having
+position zero.</p><p>Now that we know how to add a page, lets see how we can remove a
+page from the notebook.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ notebook.remove_page(<b class="parameter"><tt>page_num</tt></b>)
+</pre></td></tr></table><p>This method takes the page specified by
+<i class="parameter"><tt>page_num</tt></i> and removes it from the widget pointed to by
+<i class="parameter"><tt>notebook</tt></i>.</p><p>To find out what the current page is in a notebook use the
+method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ page = notebook.get_current_page()
+</pre></td></tr></table><p>These next two methods are simple calls to move the notebook
+page forward or backward. Simply provide the respective method call with the
+notebook widget you wish to operate on.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ notebook.next_page()
+
+ notebook.prev_page()
+</pre></td></tr></table><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>When the <i class="parameter"><tt>notebook</tt></i> is currently on the last
+page, and <tt class="methodname">next_page</tt>() is called, nothing happens.
+Likewise, if the <i class="parameter"><tt>notebook</tt></i> is on the first page, and
+<tt class="methodname">prev_page</tt>() is called, nothing happens.</p></div><p>This next method sets the "active" page. If you wish the
+notebook to be opened to page 5 for example, you would use this method.
+Without using this method, the notebook defaults to displaying the first
+page.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ notebook.set_current_page(<b class="parameter"><tt>page_num</tt></b>)
+</pre></td></tr></table><p>The next two methods add or remove the notebook page tabs and
+the notebook border respectively.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ notebook.set_show_tabs(<b class="parameter"><tt>show_tabs</tt></b>)
+
+ notebook.set_show_border(<b class="parameter"><tt>show_border</tt></b>)
+</pre></td></tr></table><p>The next method is useful when the you have a large number of
+pages, and the tabs don't fit on the page. It allows the tabs to be scrolled
+through using two arrow buttons.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ notebook.set_scrollable(<b class="parameter"><tt>scrollable</tt></b>)
+</pre></td></tr></table><p><i class="parameter"><tt>show_tabs</tt></i>,
+<i class="parameter"><tt>show_border</tt></i> and <i class="parameter"><tt>scrollable</tt></i> can
+be either <tt class="literal">TRUE</tt> or <tt class="literal">FALSE</tt>.</p><p>Now let's look at an example.
+The <a href="examples/notebook.py" target="_top"><span><b class="command">notebook.py</b></span></a>
+program creates a window with a notebook and six buttons. The notebook
+contains 11 pages, added in three different ways, appended, inserted, and
+prepended. The buttons allow you rotate the tab positions, add or remove the
+tabs and border, remove a page, change pages in both a forward and backward
+manner, and exit the program.
+<a href="sec-Notebooks.html#notebookfig" title="Figure 10.9. Notebook Example">Figure 10.9, “Notebook Exampleâ€</a> illustrates the program display:</p><div class="figure"><a name="notebookfig"></a><p class="title"><b>Figure 10.9. Notebook Example</b></p><div class="mediaobject" align="center"><img src="figures/notebook.png" align="middle" alt="Notebook Example"></div></div><p>The source code for <a href="examples/notebook.py" target="_top"><span><b class="command">notebook.py</b></span></a> is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 1 #!/usr/bin/env python
+ 2
+ 3 # example notebook.py
+ 4
+ 5 import pygtk
+ 6 pygtk.require('2.0')
+ 7 import gtk
+ 8
+ 9 class NotebookExample:
+ 10 # This method rotates the position of the tabs
+ 11 def rotate_book(self, button, notebook):
+ 12 notebook.set_tab_pos((notebook.get_tab_pos()+1) %4)
+ 13
+ 14 # Add/Remove the page tabs and the borders
+ 15 def tabsborder_book(self, button, notebook):
+ 16 tval = False
+ 17 bval = False
+ 18 if self.show_tabs == False:
+ 19 tval = True
+ 20 if self.show_border == False:
+ 21 bval = True
+ 22
+ 23 notebook.set_show_tabs(tval)
+ 24 self.show_tabs = tval
+ 25 notebook.set_show_border(bval)
+ 26 self.show_border = bval
+ 27
+ 28 # Remove a page from the notebook
+ 29 def remove_book(self, button, notebook):
+ 30 page = notebook.get_current_page()
+ 31 notebook.remove_page(page)
+ 32 # Need to refresh the widget --
+ 33 # This forces the widget to redraw itself.
+ 34 notebook.queue_draw_area(0,0,-1,-1)
+ 35
+ 36 def delete(self, widget, event=None):
+ 37 gtk.main_quit()
+ 38 return False
+ 39
+ 40 def __init__(self):
+ 41 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ 42 window.connect("delete_event", self.delete)
+ 43 window.set_border_width(10)
+ 44
+ 45 table = gtk.Table(3,6,False)
+ 46 window.add(table)
+ 47
+ 48 # Create a new notebook, place the position of the tabs
+ 49 notebook = gtk.Notebook()
+ 50 notebook.set_tab_pos(gtk.POS_TOP)
+ 51 table.attach(notebook, 0,6,0,1)
+ 52 notebook.show()
+ 53 self.show_tabs = True
+ 54 self.show_border = True
+ 55
+ 56 # Let's append a bunch of pages to the notebook
+ 57 for i in range(5):
+ 58 bufferf = "Append Frame %d" % (i+1)
+ 59 bufferl = "Page %d" % (i+1)
+ 60
+ 61 frame = gtk.Frame(bufferf)
+ 62 frame.set_border_width(10)
+ 63 frame.set_size_request(100, 75)
+ 64 frame.show()
+ 65
+ 66 label = gtk.Label(bufferf)
+ 67 frame.add(label)
+ 68 label.show()
+ 69
+ 70 label = gtk.Label(bufferl)
+ 71 notebook.append_page(frame, label)
+ 72
+ 73 # Now let's add a page to a specific spot
+ 74 checkbutton = gtk.CheckButton("Check me please!")
+ 75 checkbutton.set_size_request(100, 75)
+ 76 checkbutton.show ()
+ 77
+ 78 label = gtk.Label("Add page")
+ 79 notebook.insert_page(checkbutton, label, 2)
+ 80
+ 81 # Now finally let's prepend pages to the notebook
+ 82 for i in range(5):
+ 83 bufferf = "Prepend Frame %d" % (i+1)
+ 84 bufferl = "PPage %d" % (i+1)
+ 85
+ 86 frame = gtk.Frame(bufferf)
+ 87 frame.set_border_width(10)
+ 88 frame.set_size_request(100, 75)
+ 89 frame.show()
+ 90
+ 91 label = gtk.Label(bufferf)
+ 92 frame.add(label)
+ 93 label.show()
+ 94
+ 95 label = gtk.Label(bufferl)
+ 96 notebook.prepend_page(frame, label)
+ 97
+ 98 # Set what page to start at (page 4)
+ 99 notebook.set_current_page(3)
+ 100
+ 101 # Create a bunch of buttons
+ 102 button = gtk.Button("close")
+ 103 button.connect("clicked", self.delete)
+ 104 table.attach(button, 0,1,1,2)
+ 105 button.show()
+ 106
+ 107 button = gtk.Button("next page")
+ 108 button.connect("clicked", lambda w: notebook.next_page())
+ 109 table.attach(button, 1,2,1,2)
+ 110 button.show()
+ 111
+ 112 button = gtk.Button("prev page")
+ 113 button.connect("clicked", lambda w: notebook.prev_page())
+ 114 table.attach(button, 2,3,1,2)
+ 115 button.show()
+ 116
+ 117 button = gtk.Button("tab position")
+ 118 button.connect("clicked", self.rotate_book, notebook)
+ 119 table.attach(button, 3,4,1,2)
+ 120 button.show()
+ 121
+ 122 button = gtk.Button("tabs/border on/off")
+ 123 button.connect("clicked", self.tabsborder_book, notebook)
+ 124 table.attach(button, 4,5,1,2)
+ 125 button.show()
+ 126
+ 127 button = gtk.Button("remove page")
+ 128 button.connect("clicked", self.remove_book, notebook)
+ 129 table.attach(button, 5,6,1,2)
+ 130 button.show()
+ 131
+ 132 table.show()
+ 133 window.show()
+ 134
+ 135 def main():
+ 136 gtk.main()
+ 137 return 0
+ 138
+ 139 if __name__ == "__main__":
+ 140 NotebookExample()
+ 141 main()
+ </pre></td></tr></table><p>I hope this helps you on your way with creating notebooks for your
+PyGTK applications.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-Toolbar.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-ContainerWidgets.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-PlugsAndSockets.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">10.11. Toolbar </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 10.13. Plugs and Sockets</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-OptionMenu.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-OptionMenu.html
new file mode 100644
index 0000000..7c4ec25
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-OptionMenu.html
@@ -0,0 +1 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>17.2. Option Menu</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-UndocumentedWidgets.html" title="Chapter 17. Undocumented Widgets"><link rel="previous" href="ch-UndocumentedWidgets.html" title="Chapter 17. Undocumented Widgets"><link rel="next" href="sec-MenuItems.html" title="17.3. Menu Items"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">17.2. Option Menu</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch-UndocumentedWidgets.html">Prev</a> </td><th width="60%" align="center">Chapter 17. Undocumented Widgets</th><td width="20%" align="right"> <a accesskey="n" href="sec-MenuItems.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-OptionMenu"></a>17.2. Option Menu</h2></div></div><div></div></div><p></p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch-UndocumentedWidgets.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-UndocumentedWidgets.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-MenuItems.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 17. Undocumented Widgets </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 17.3. Menu Items</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-OriginalGTK+Credits.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-OriginalGTK+Credits.html
new file mode 100644
index 0000000..710c3a8
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-OriginalGTK+Credits.html
@@ -0,0 +1,24 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>27.2. Original GTK+ Credits</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-Credits.html" title="Chapter 27. Credits"><link rel="previous" href="ch-Credits.html" title="Chapter 27. Credits"><link rel="next" href="ch-Copyright.html" title="Chapter 28. Tutorial Copyright and Permissions Notice"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">27.2. Original GTK+ Credits</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch-Credits.html">Prev</a> </td><th width="60%" align="center">Chapter 27. Credits</th><td width="20%" align="right"> <a accesskey="n" href="ch-Copyright.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-OriginalGTK+Credits"></a>27.2. Original GTK+ Credits</h2></div></div><div></div></div><p>The following credits are from the original GTK+ 1.2 and GTK+
+2.0 Tutorials (from which this tutorial has mostly copied verbatim):</p><div class="itemizedlist"><ul type="disc"><li><p>Bawer Dagdeviren, <a href="mailto:chamele0n@geocities.com" target="_top">chamele0n@geocities.com</a> for the
+menus tutorial.</p></li><li><p>Raph Levien, <a href="mailto:raph@acm.org" target="_top">raph@acm.org</a> for hello world ala GTK,
+widget packing, and general all around wisdom. He's also generously donated
+a home for this tutorial.</p></li><li><p>Peter Mattis, <a href="mailto:petm@xcf.berkeley.edu" target="_top">petm@xcf.berkeley.edu</a> for the
+simplest GTK program.. and the ability to make it :)</p></li><li><p>Werner Koch<a href="mailto:%20werner.koch@guug.de" target="_top">
+werner.koch@guug.de</a> for converting the original plain text to SGML,
+and the widget class hierarchy.</p></li><li><p>Mark Crichton <a href="mailto:crichton@expert.cc.purdue.edu" target="_top">crichton@expert.cc.purdue.edu</a>
+for the menu factory code, and the table packing tutorial.</p></li><li><p>Owen Taylor <a href="mailto:owt1@cornell.edu" target="_top">owt1@cornell.edu</a> for the EventBox
+widget section (and the patch to the distro). He's also responsible for the
+selections code and tutorial, as well as the sections on writing your own
+GTK widgets, and the example application. Thanks a lot Owen for all you
+help!</p></li><li><p>Mark VanderBoom<a href="mailto:%20mvboom42@calvin.edu" target="_top">
+mvboom42@calvin.edu</a> for his wonderful work on the Notebook, Progress
+Bar, Dialogs, and File selection widgets. Thanks a lot Mark! You've been a
+great help.</p></li><li><p>Tim Janik <a href="mailto:timj@gtk.org" target="_top">timj@gtk.org</a> for his great job on the
+Lists Widget. His excellent work on automatically extracting the widget tree
+and signal information from GTK. Thanks Tim :)</p></li><li><p>Rajat Datta <a href="mailto:rajat@ix.netcom.com" target="_top">rajat@ix.netcom.com</a> for the
+excellent job on the Pixmap tutorial.</p></li><li><p>Michael K. Johnson <a href="mailto:johnsonm@redhat.com" target="_top">johnsonm@redhat.com</a> for info and
+code for popup menus.</p></li><li><p>David Huggins-Daines <a href="mailto:bn711@freenet.carleton.ca" target="_top">bn711@freenet.carleton.ca</a> for
+the Range Widgets and Tree Widget sections.</p></li><li><p>Stefan Mars mars@lysator.liu.se for the CList section.</p></li><li><p>David A. Wheeler <a href="mailto:dwheeler@ida.org" target="_top">dwheeler@ida.org</a> for portions of the
+text on GLib and various tutorial fixups and improvements. The GLib text was
+in turn based on material developed by Damon Chaplin
+DAChaplin@msn.com</p></li><li><p>David King for style checking the entire document.</p></li></ul></div><p>And to all of you who commented on and helped refine this document.</p><p>Thanks.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch-Credits.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-Credits.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch-Copyright.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 27. Credits </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 28. Tutorial Copyright and Permissions Notice</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-PackingDemonstrationProgram.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-PackingDemonstrationProgram.html
new file mode 100644
index 0000000..71b81a0
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-PackingDemonstrationProgram.html
@@ -0,0 +1,282 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>4.3. Packing Demonstration Program</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-PackingWidgets.html" title="Chapter 4. Packing Widgets"><link rel="previous" href="sec-DetailsOfBoxes.html" title="4.2. Details of Boxes"><link rel="next" href="sec-PackingUsingTables.html" title="4.4. Packing Using Tables"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">4.3. Packing Demonstration Program</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-DetailsOfBoxes.html">Prev</a> </td><th width="60%" align="center">Chapter 4. Packing Widgets</th><td width="20%" align="right"> <a accesskey="n" href="sec-PackingUsingTables.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-PackingDemonstrationProgram"></a>4.3. Packing Demonstration Program</h2></div></div><div></div></div><p><a href="examples/packbox.py" target="_top">Here</a> is the code
+used to create the above images. It's commented fairly heavily so I hope you
+won't have any problems following it. Run it yourself and play with
+it.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 1 #!/usr/bin/env python
+ 2
+ 3 # example packbox.py
+ 4
+ 5 import pygtk
+ 6 pygtk.require('2.0')
+ 7 import gtk
+ 8 import sys, string
+ 9
+ 10 # Helper function that makes a new hbox filled with button-labels. Arguments
+ 11 # for the variables we're interested are passed in to this function. We do
+ 12 # not show the box, but do show everything inside.
+ 13
+ 14 def make_box(homogeneous, spacing, expand, fill, padding):
+ 15
+ 16 # Create a new hbox with the appropriate homogeneous
+ 17 # and spacing settings
+ 18 box = gtk.HBox(homogeneous, spacing)
+ 19
+ 20 # Create a series of buttons with the appropriate settings
+ 21 button = gtk.Button("box.pack")
+ 22 box.pack_start(button, expand, fill, padding)
+ 23 button.show()
+ 24
+ 25 button = gtk.Button("(button,")
+ 26 box.pack_start(button, expand, fill, padding)
+ 27 button.show()
+ 28
+ 29 # Create a button with the label depending on the value of
+ 30 # expand.
+ 31 if expand == True:
+ 32 button = gtk.Button("True,")
+ 33 else:
+ 34 button = gtk.Button("False,")
+ 35
+ 36 box.pack_start(button, expand, fill, padding)
+ 37 button.show()
+ 38
+ 39 # This is the same as the button creation for "expand"
+ 40 # above, but uses the shorthand form.
+ 41 button = gtk.Button(("False,", "True,")[fill==True])
+ 42 box.pack_start(button, expand, fill, padding)
+ 43 button.show()
+ 44
+ 45 padstr = "%d)" % padding
+ 46
+ 47 button = gtk.Button(padstr)
+ 48 box.pack_start(button, expand, fill, padding)
+ 49 button.show()
+ 50 return box
+ 51
+ 52 class PackBox1:
+ 53 def delete_event(self, widget, event, data=None):
+ 54 gtk.main_quit()
+ 55 return False
+ 56
+ 57 def __init__(self, which):
+ 58
+ 59 # Create our window
+ 60 self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ 61
+ 62 # You should always remember to connect the delete_event signal
+ 63 # to the main window. This is very important for proper intuitive
+ 64 # behavior
+ 65 self.window.connect("delete_event", self.delete_event)
+ 66 self.window.set_border_width(10)
+ 67
+ 68 # We create a vertical box (vbox) to pack the horizontal boxes into.
+ 69 # This allows us to stack the horizontal boxes filled with buttons one
+ 70 # on top of the other in this vbox.
+ 71 box1 = gtk.VBox(False, 0)
+ 72
+ 73 # which example to show. These correspond to the pictures above.
+ 74 if which == 1:
+ 75 # create a new label.
+ 76 label = gtk.Label("HBox(False, 0)")
+ 77
+ 78 # Align the label to the left side. We'll discuss this method
+ 79 # and others in the section on Widget Attributes.
+ 80 label.set_alignment(0, 0)
+ 81
+ 82 # Pack the label into the vertical box (vbox box1). Remember that
+ 83 # widgets added to a vbox will be packed one on top of the other in
+ 84 # order.
+ 85 box1.pack_start(label, False, False, 0)
+ 86
+ 87 # Show the label
+ 88 label.show()
+ 89
+ 90 # Call our make box function - homogeneous = False, spacing = 0,
+ 91 # expand = False, fill = False, padding = 0
+ 92 box2 = make_box(False, 0, False, False, 0)
+ 93 box1.pack_start(box2, False, False, 0)
+ 94 box2.show()
+ 95
+ 96 # Call our make box function - homogeneous = False, spacing = 0,
+ 97 # expand = True, fill = False, padding = 0
+ 98 box2 = make_box(False, 0, True, False, 0)
+ 99 box1.pack_start(box2, False, False, 0)
+ 100 box2.show()
+ 101
+ 102 # Args are: homogeneous, spacing, expand, fill, padding
+ 103 box2 = make_box(False, 0, True, True, 0)
+ 104 box1.pack_start(box2, False, False, 0)
+ 105 box2.show()
+ 106
+ 107 # Creates a separator, we'll learn more about these later,
+ 108 # but they are quite simple.
+ 109 separator = gtk.HSeparator()
+ 110
+ 111 # Pack the separator into the vbox. Remember each of these
+ 112 # widgets is being packed into a vbox, so they'll be stacked
+ 113 # vertically.
+ 114 box1.pack_start(separator, False, True, 5)
+ 115 separator.show()
+ 116
+ 117 # Create another new label, and show it.
+ 118 label = gtk.Label("HBox(True, 0)")
+ 119 label.set_alignment(0, 0)
+ 120 box1.pack_start(label, False, False, 0)
+ 121 label.show()
+ 122
+ 123 # Args are: homogeneous, spacing, expand, fill, padding
+ 124 box2 = make_box(True, 0, True, False, 0)
+ 125 box1.pack_start(box2, False, False, 0)
+ 126 box2.show()
+ 127
+ 128 # Args are: homogeneous, spacing, expand, fill, padding
+ 129 box2 = make_box(True, 0, True, True, 0)
+ 130 box1.pack_start(box2, False, False, 0)
+ 131 box2.show()
+ 132
+ 133 # Another new separator.
+ 134 separator = gtk.HSeparator()
+ 135 # The last 3 arguments to pack_start are:
+ 136 # expand, fill, padding.
+ 137 box1.pack_start(separator, False, True, 5)
+ 138 separator.show()
+ 139 elif which == 2:
+ 140 # Create a new label, remember box1 is a vbox as created
+ 141 # near the beginning of __init__()
+ 142 label = gtk.Label("HBox(False, 10)")
+ 143 label.set_alignment( 0, 0)
+ 144 box1.pack_start(label, False, False, 0)
+ 145 label.show()
+ 146
+ 147 # Args are: homogeneous, spacing, expand, fill, padding
+ 148 box2 = make_box(False, 10, True, False, 0)
+ 149 box1.pack_start(box2, False, False, 0)
+ 150 box2.show()
+ 151
+ 152 # Args are: homogeneous, spacing, expand, fill, padding
+ 153 box2 = make_box(False, 10, True, True, 0)
+ 154 box1.pack_start(box2, False, False, 0)
+ 155 box2.show()
+ 156
+ 157 separator = gtk.HSeparator()
+ 158 # The last 3 arguments to pack_start are:
+ 159 # expand, fill, padding.
+ 160 box1.pack_start(separator, False, True, 5)
+ 161 separator.show()
+ 162
+ 163 label = gtk.Label("HBox(False, 0)")
+ 164 label.set_alignment(0, 0)
+ 165 box1.pack_start(label, False, False, 0)
+ 166 label.show()
+ 167
+ 168 # Args are: homogeneous, spacing, expand, fill, padding
+ 169 box2 = make_box(False, 0, True, False, 10)
+ 170 box1.pack_start(box2, False, False, 0)
+ 171 box2.show()
+ 172
+ 173 # Args are: homogeneous, spacing, expand, fill, padding
+ 174 box2 = make_box(False, 0, True, True, 10)
+ 175 box1.pack_start(box2, False, False, 0)
+ 176 box2.show()
+ 177
+ 178 separator = gtk.HSeparator()
+ 179 # The last 3 arguments to pack_start are:
+ 180 # expand, fill, padding.
+ 181 box1.pack_start(separator, False, True, 5)
+ 182 separator.show()
+ 183
+ 184 elif which == 3:
+ 185
+ 186 # This demonstrates the ability to use pack_end() to
+ 187 # right justify widgets. First, we create a new box as before.
+ 188 box2 = make_box(False, 0, False, False, 0)
+ 189
+ 190 # Create the label that will be put at the end.
+ 191 label = gtk.Label("end")
+ 192 # Pack it using pack_end(), so it is put on the right
+ 193 # side of the hbox created in the make_box() call.
+ 194 box2.pack_end(label, False, False, 0)
+ 195 # Show the label.
+ 196 label.show()
+ 197
+ 198 # Pack box2 into box1
+ 199 box1.pack_start(box2, False, False, 0)
+ 200 box2.show()
+ 201
+ 202 # A separator for the bottom.
+ 203 separator = gtk.HSeparator()
+ 204
+ 205 # This explicitly sets the separator to 400 pixels wide by 5
+ 206 # pixels high. This is so the hbox we created will also be 400
+ 207 # pixels wide, and the "end" label will be separated from the
+ 208 # other labels in the hbox. Otherwise, all the widgets in the
+ 209 # hbox would be packed as close together as possible.
+ 210 separator.set_size_request(400, 5)
+ 211 # pack the separator into the vbox (box1) created near the start
+ 212 # of __init__()
+ 213 box1.pack_start(separator, False, True, 5)
+ 214 separator.show()
+ 215
+ 216 # Create another new hbox.. remember we can use as many as we need!
+ 217 quitbox = gtk.HBox(False, 0)
+ 218
+ 219 # Our quit button.
+ 220 button = gtk.Button("Quit")
+ 221
+ 222 # Setup the signal to terminate the program when the button is clicked
+ 223 button.connect("clicked", lambda w: gtk.main_quit())
+ 224 # Pack the button into the quitbox.
+ 225 # The last 3 arguments to pack_start are:
+ 226 # expand, fill, padding.
+ 227 quitbox.pack_start(button, True, False, 0)
+ 228 # pack the quitbox into the vbox (box1)
+ 229 box1.pack_start(quitbox, False, False, 0)
+ 230
+ 231 # Pack the vbox (box1) which now contains all our widgets, into the
+ 232 # main window.
+ 233 self.window.add(box1)
+ 234
+ 235 # And show everything left
+ 236 button.show()
+ 237 quitbox.show()
+ 238
+ 239 box1.show()
+ 240 # Showing the window last so everything pops up at once.
+ 241 self.window.show()
+ 242
+ 243 def main():
+ 244 # And of course, our main loop.
+ 245 gtk.main()
+ 246 # Control returns here when main_quit() is called
+ 247 return 0
+ 248
+ 249 if __name__ =="__main__":
+ 250 if len(sys.argv) != 2:
+ 251 sys.stderr.write("usage: packbox.py num, where num is 1, 2, or 3.\n")
+ 252 sys.exit(1)
+ 253 PackBox1(string.atoi(sys.argv[1]))
+ 254 main()
+</pre></td></tr></table><p>A brief tour of the <a href="examples/packbox.py" target="_top"><span><b class="command">packbox.py</b></span></a> code starts
+with lines 14-50 which define a helper function
+<tt class="function">make_box</tt>() that creates a horizontal box and populates
+it with buttons according to the specified parameters. A reference to the
+horizontal box is returned.</p><p>Lines 52-241 define the <tt class="classname">PackBox1</tt> class
+initialization method <tt class="methodname">__init__</tt>() that creates a
+window and a child vertical box that is populated with a different widget
+arrangement depending on the argument passed to it. If a 1 is passed, lines
+75-138 create a window displaying the five unique packing arrangements that
+are available when varying the homogeneous, expand and fill parameters. If a
+2 is passed, lines 140-182 create a window displaying the various
+combinations of fill with spacing and padding. Finally, if a 3 is passed,
+lines 188-214 create a window displaying the use of the
+<tt class="methodname">pack_start</tt>() method to left justify the buttons and
+<tt class="methodname">pack_end</tt>() method to right justify a label. Lines
+215-235 create a horizontal box containing a button that is packed into the
+vertical box. The button "clicked" signal is connected to the PyGTK
+<tt class="function">main_quit</tt>() function to terminate the program.</p><p>Lines 250-252 check the command line arguments and exit the
+program using the <tt class="function">sys.exit</tt>() function if there isn't
+exactly one argument. Line 253 creates a PackBox1 instance. Line 254 invokes
+the <tt class="function">main</tt>() function to start the GTK event processing
+loop.</p><p>In this example program, the references to the various widgets
+(except the window) are not saved in the object instance attributes because
+they are not needed later.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-DetailsOfBoxes.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-PackingWidgets.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-PackingUsingTables.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">4.2. Details of Boxes </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 4.4. Packing Using Tables</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-PackingUsingTables.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-PackingUsingTables.html
new file mode 100644
index 0000000..4d37697
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-PackingUsingTables.html
@@ -0,0 +1,61 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>4.4. Packing Using Tables</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-PackingWidgets.html" title="Chapter 4. Packing Widgets"><link rel="previous" href="sec-PackingDemonstrationProgram.html" title="4.3. Packing Demonstration Program"><link rel="next" href="sec-TablePackingExample.html" title="4.5. Table Packing Example"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">4.4. Packing Using Tables</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-PackingDemonstrationProgram.html">Prev</a> </td><th width="60%" align="center">Chapter 4. Packing Widgets</th><td width="20%" align="right"> <a accesskey="n" href="sec-TablePackingExample.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-PackingUsingTables"></a>4.4. Packing Using Tables</h2></div></div><div></div></div><p>Let's take a look at another way of packing - Tables. These can
+be extremely useful in certain situations.</p><p>Using tables, we create a grid that we can place widgets in. The
+widgets may take up as many spaces as we specify.</p><p>The first thing to look at, of course, is the
+<tt class="function">gtk.Table</tt>() function:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ table = gtk.Table(<b class="parameter"><tt>rows</tt></b>=1, <b class="parameter"><tt>columns</tt></b>=1, <b class="parameter"><tt>homogeneous</tt></b>=False)
+</pre></td></tr></table><p>The first argument is the number of rows to make in the table,
+while the second, obviously, is the number of columns.</p><p>The <i class="parameter"><tt>homogeneous</tt></i> argument has to do with
+how the table's boxes are sized. If <i class="parameter"><tt>homogeneous</tt></i> is
+<tt class="literal">True</tt>, the table boxes are resized to the size of the
+largest widget in the table. If <i class="parameter"><tt>homogeneous</tt></i> is
+<tt class="literal">False</tt>, the size of a table boxes is dictated by the
+tallest widget in its same row, and the widest widget in its column.</p><p>The rows and columns are laid out from 0 to n, where n was the number
+specified in the call to <tt class="function">gtk.Table</tt>(). So, if you
+specify rows = 2 and columns = 2, the layout would look something like
+this:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 0 1 2
+ 0+----------+----------+
+ | | |
+ 1+----------+----------+
+ | | |
+ 2+----------+----------+
+</pre></td></tr></table><p>Note that the coordinate system starts in the upper left hand
+corner. To place a widget into a box, use the following method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ table.attach(<b class="parameter"><tt>child</tt></b>, <b class="parameter"><tt>left_attach</tt></b>, <b class="parameter"><tt>right_attach</tt></b>, <b class="parameter"><tt>top_attach</tt></b>, <b class="parameter"><tt>bottom_attach</tt></b>,
+ <b class="parameter"><tt>xoptions</tt></b>=EXPAND|FILL, <b class="parameter"><tt>yoptions</tt></b>=EXPAND|FILL, <b class="parameter"><tt>xpadding</tt></b>=0, <b class="parameter"><tt>ypadding</tt></b>=0)
+</pre></td></tr></table><p>The table instance is the table you created with
+<tt class="function">gtk.Table</tt>(). The first parameter ("child") is the
+widget you wish to place in the table.</p><p>The <i class="parameter"><tt>left_attach</tt></i>,
+<i class="parameter"><tt>right_attach</tt></i>, <i class="parameter"><tt>top_attach</tt></i> and
+<i class="parameter"><tt>bottom_attach</tt></i> arguments specify where to place the
+widget, and how many boxes to use. If you want a button in the lower right
+table entry of our 2x2 table, and want it to fill that entry ONLY,
+<i class="parameter"><tt>left_attach</tt></i> would be = 1,
+<i class="parameter"><tt>right_attach</tt></i> = 2, <i class="parameter"><tt>top_attach</tt></i> =
+1, <i class="parameter"><tt>bottom_attach</tt></i> = 2.</p><p>Now, if you wanted a widget to take up the whole top row of our
+2x2 table, you'd use <i class="parameter"><tt>left_attach</tt></i> = 0,
+<i class="parameter"><tt>right_attach</tt></i> = 2, <i class="parameter"><tt>top_attach</tt></i> =
+0, <i class="parameter"><tt>bottom_attach</tt></i> = 1.</p><p>The <i class="parameter"><tt>xoptions</tt></i> and
+<i class="parameter"><tt>yoptions</tt></i> are used to specify packing options and may
+be bitwise OR'ed together to allow multiple options.</p><p>These options are:</p><div class="informaltable"><table width="100%" border="1"><colgroup><col><col></colgroup><tbody><tr><td><tt class="literal">FILL</tt></td><td>If the table cell is larger than the widget, and
+<tt class="literal">FILL</tt> is specified, the widget will expand to use all the
+room available in the cell.</td></tr><tr><td><tt class="literal">SHRINK</tt></td><td>If the table widget was allocated less space then was
+requested (usually by the user resizing the window), then the widgets would
+normally just be pushed off the bottom of the window and disappear. If
+<tt class="literal">SHRINK</tt> is specified, the widgets will shrink with the
+table.</td></tr><tr><td><tt class="literal">EXPAND</tt></td><td>This will cause the table cell to expand to use up any
+remaining space allocated to the table.</td></tr></tbody></table></div><p>Padding is just like in boxes, creating a clear area around the
+widget specified in pixels.</p><p>We also have <tt class="methodname">set_row_spacing</tt>() and
+<tt class="methodname">set_col_spacing</tt>() methods. These add spacing
+between the rows at the specified row or column.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ table.set_row_spacing(<b class="parameter"><tt>row</tt></b>, <b class="parameter"><tt>spacing</tt></b>)
+</pre></td></tr></table><p>and</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ table.set_col_spacing(<b class="parameter"><tt>column</tt></b>, <b class="parameter"><tt>spacing</tt></b>)
+</pre></td></tr></table><p>Note that for columns, the space goes to the right of the
+column, and for rows, the space goes below the row.</p><p>You can also set a consistent spacing of all rows and/or columns
+with:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ table.set_row_spacings(<b class="parameter"><tt>spacing</tt></b>)
+</pre></td></tr></table><p>and,</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ table.set_col_spacings(<b class="parameter"><tt>spacing</tt></b>)
+</pre></td></tr></table><p>Note that with these calls, the last row and last column do not
+get any spacing.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-PackingDemonstrationProgram.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-PackingWidgets.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-TablePackingExample.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">4.3. Packing Demonstration Program </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 4.5. Table Packing Example</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-PanedWindowWidgets.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-PanedWindowWidgets.html
new file mode 100644
index 0000000..61d48e5
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-PanedWindowWidgets.html
@@ -0,0 +1,122 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>10.7. Paned Window Widgets</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-ContainerWidgets.html" title="Chapter 10. Container Widgets"><link rel="previous" href="sec-AspectFrames.html" title="10.6. Aspect Frames"><link rel="next" href="sec-Viewports.html" title="10.8. Viewports"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">10.7. Paned Window Widgets</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-AspectFrames.html">Prev</a> </td><th width="60%" align="center">Chapter 10. Container Widgets</th><td width="20%" align="right"> <a accesskey="n" href="sec-Viewports.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-PanedWindowWidgets"></a>10.7. Paned Window Widgets</h2></div></div><div></div></div><p>The paned window widgets are useful when you want to divide an
+area into two parts, with the relative size of the two parts controlled by
+the user. A groove is drawn between the two portions with a handle that the
+user can drag to change the ratio. The division can either be horizontal
+(<tt class="classname">HPaned</tt>) or vertical
+(<tt class="classname">VPaned</tt>).</p><p>To create a new paned window, call one of:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ hpane = gtk.HPaned()
+
+ vpane = gtk.VPaned()
+</pre></td></tr></table><p>After creating the paned window widget, you need to add child
+widgets to its two halves. To do this, use the methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ paned.add1(<b class="parameter"><tt>child</tt></b>)
+
+ paned.add2(<b class="parameter"><tt>child</tt></b>)
+</pre></td></tr></table><p>The <tt class="methodname">add1</tt>() method adds the
+<i class="parameter"><tt>child</tt></i> widget to
+the left or top half of the paned window. The <tt class="methodname">add2</tt>()
+method adds the <i class="parameter"><tt>child</tt></i> widget to the right or bottom
+half of the paned window.</p><p>The <a href="examples/paned.py" target="_top"><span><b class="command">paned.py</b></span></a> example program
+creates part of the user interface of an imaginary email program. A window
+is divided into two portions vertically, with the top portion being a list
+of email messages and the bottom portion the text of the email message. Most
+of the program is pretty straightforward. A couple of points to note: text
+can't be added to a Text widget until it is realized. This could be done by
+calling the <tt class="methodname">realize</tt>() method, but as a
+demonstration of an alternate technique, we connect a handler to the
+"realize" signal to add the text. Also, we need to add the
+<tt class="varname">SHRINK</tt> option to some of the items in the table
+containing the text window and its scrollbars, so that when the bottom
+portion is made smaller, the correct portions shrink instead of being pushed
+off the bottom of the window. <a href="sec-PanedWindowWidgets.html#panedfig" title="Figure 10.6. Paned Example">Figure 10.6, “Paned Exampleâ€</a> shows the result
+of running the program:</p><div class="figure"><a name="panedfig"></a><p class="title"><b>Figure 10.6. Paned Example</b></p><div class="mediaobject" align="center"><img src="figures/paned.png" align="middle" alt="Paned Example"></div></div><p>The source code of the <a href="examples/paned.py" target="_top"><span><b class="command">paned.py</b></span></a> program
+is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 1 #!/usr/bin/env python
+ 2
+ 3 # example paned.py
+ 4
+ 5 import pygtk
+ 6 pygtk.require('2.0')
+ 7 import gtk, gobject
+ 8
+ 9 class PanedExample:
+ 10 # Create the list of "messages"
+ 11 def create_list(self):
+ 12 # Create a new scrolled window, with scrollbars only if needed
+ 13 scrolled_window = gtk.ScrolledWindow()
+ 14 scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+ 15
+ 16 model = gtk.ListStore(gobject.TYPE_STRING)
+ 17 tree_view = gtk.TreeView(model)
+ 18 scrolled_window.add_with_viewport (tree_view)
+ 19 tree_view.show()
+ 20
+ 21 # Add some messages to the window
+ 22 for i in range(10):
+ 23 msg = "Message #%d" % i
+ 24 iter = model.append()
+ 25 model.set(iter, 0, msg)
+ 26
+ 27 cell = gtk.CellRendererText()
+ 28 column = gtk.TreeViewColumn("Messages", cell, text=0)
+ 29 tree_view.append_column(column)
+ 30
+ 31 return scrolled_window
+ 32
+ 33 # Add some text to our text widget - this is a callback that is invoked
+ 34 # when our window is realized. We could also force our window to be
+ 35 # realized with gtk.Widget.realize(), but it would have to be part of a
+ 36 # hierarchy first
+ 37 def insert_text(self, buffer):
+ 38 iter = buffer.get_iter_at_offset(0)
+ 39 buffer.insert(iter,
+ 40 "From: pathfinder@nasa.gov\n"
+ 41 "To: mom@nasa.gov\n"
+ 42 "Subject: Made it!\n"
+ 43 "\n"
+ 44 "We just got in this morning. The weather has been\n"
+ 45 "great - clear but cold, and there are lots of fun sights.\n"
+ 46 "Sojourner says hi. See you soon.\n"
+ 47 " -Path\n")
+ 48
+ 49 # Create a scrolled text area that displays a "message"
+ 50 def create_text(self):
+ 51 view = gtk.TextView()
+ 52 buffer = view.get_buffer()
+ 53 scrolled_window = gtk.ScrolledWindow()
+ 54 scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+ 55 scrolled_window.add(view)
+ 56 self.insert_text(buffer)
+ 57 scrolled_window.show_all()
+ 58 return scrolled_window
+ 59
+ 60 def __init__(self):
+ 61 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ 62 window.set_title("Paned Windows")
+ 63 window.connect("destroy", lambda w: gtk.main_quit())
+ 64 window.set_border_width(10)
+ 65 window.set_size_request(450, 400)
+ 66
+ 67 # create a vpaned widget and add it to our toplevel window
+ 68 vpaned = gtk.VPaned()
+ 69 window.add(vpaned)
+ 70 vpaned.show()
+ 71
+ 72 # Now create the contents of the two halves of the window
+ 73 list = self.create_list()
+ 74 vpaned.add1(list)
+ 75 list.show()
+ 76
+ 77 text = self.create_text()
+ 78 vpaned.add2(text)
+ 79 text.show()
+ 80 window.show()
+ 81
+ 82 def main():
+ 83 gtk.main()
+ 84 return 0
+ 85
+ 86 if __name__ == "__main__":
+ 87 PanedExample()
+ 88 main()
+</pre></td></tr></table></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-AspectFrames.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-ContainerWidgets.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-Viewports.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">10.6. Aspect Frames </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 10.8. Viewports</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-PlugsAndSockets.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-PlugsAndSockets.html
new file mode 100644
index 0000000..e5a4254
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-PlugsAndSockets.html
@@ -0,0 +1,148 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>10.13. Plugs and Sockets</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-ContainerWidgets.html" title="Chapter 10. Container Widgets"><link rel="previous" href="sec-Notebooks.html" title="10.12. Notebooks"><link rel="next" href="ch-MenuWidget.html" title="Chapter 11. Menu Widget"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">10.13. Plugs and Sockets</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-Notebooks.html">Prev</a> </td><th width="60%" align="center">Chapter 10. Container Widgets</th><td width="20%" align="right"> <a accesskey="n" href="ch-MenuWidget.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-PlugsAndSockets"></a>10.13. Plugs and Sockets</h2></div></div><div></div></div><p><tt class="classname">Plugs</tt> and <tt class="classname">Sockets</tt>
+cooperate to embed the user interface from one process into another process.
+This can also be accomplished using Bonobo.</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2848120"></a>10.13.1. Plugs</h3></div></div><div></div></div><p>A <tt class="classname">Plug</tt> encapsulates a user interface
+provided by one application so that it can be embedded in another
+application's user interface. The "embedded" signal alerts the plug
+application that the plug has been embedded in the other application's user
+interface.</p><p>A <tt class="classname">Plug</tt> is created using the following
+function:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ plug = gtk.Plug(socket_id)
+</pre></td></tr></table><p>which creates a new <tt class="classname">Plug</tt> and embeds it in
+the <tt class="classname">Socket</tt> identified by
+<i class="parameter"><tt>socket_id</tt></i>. If <i class="parameter"><tt>socket_id</tt></i> is 0L,
+the plug is left "unplugged" and can later be plugged into a
+<tt class="classname">Socket</tt> using the <tt class="classname">Socket</tt>
+<tt class="methodname">add_id</tt>() method.</p><p>The <tt class="classname">Plug</tt> method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ id = plug.get_id()
+</pre></td></tr></table><p>returns the window ID of a <tt class="classname">Plug</tt>, that can
+be used to embed it inside a <tt class="classname">Socket</tt> using the
+<tt class="classname">Socket</tt> <tt class="methodname">add_id</tt>()
+method.</p><p>The <a href="examples/plug.py" target="_top"><span><b class="command">plug.py</b></span></a> example
+program illustrates the use of a Plug:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 1 #!/usr/bin/python
+ 2
+ 3 import pygtk
+ 4 pygtk.require('2.0')
+ 5 import gtk,sys
+ 6
+ 7 Wid = 0L
+ 8 if len(sys.argv) == 2:
+ 9 Wid = long(sys.argv[1])
+ 10
+ 11 plug = gtk.Plug(Wid)
+ 12 print "Plug ID=", plug.get_id()
+ 13
+ 14 def embed_event(widget):
+ 15 print "I (",widget,") have just been embedded!"
+ 16
+ 17 plug.connect("embedded", embed_event)
+ 18
+ 19 entry = gtk.Entry()
+ 20 entry.set_text("hello")
+ 21 def entry_point(widget):
+ 22 print "You've changed my text to '%s'" % widget.get_text()
+ 23
+ 24 entry.connect("changed", entry_point)
+ 25 plug.connect("destroy", gtk.mainquit)
+ 26
+ 27 plug.add(entry)
+ 28 plug.show_all()
+ 29
+ 30
+ 31 gtk.mainloop()
+</pre></td></tr></table><p>The program is invoked like:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ plug.py [windowID]
+</pre></td></tr></table><p>where <i class="parameter"><tt>windowID</tt></i> is the ID of a
+<tt class="classname">Socket</tt> to connect the <tt class="classname">Plug</tt>
+to.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2848244"></a>10.13.2. Sockets</h3></div></div><div></div></div><p>A <tt class="classname">Socket</tt> provides the widget to embed a
+<tt class="classname">Plug</tt> widget from another application into your GUI
+transparently. An application creates a <tt class="classname">Socket</tt> widget
+and, passes that widget's window ID to another application, which then
+creates a <tt class="classname">Plug</tt> using that window ID as a
+parameter. Any widgets contained in the <tt class="classname">Plug</tt> appear
+inside the first application's window.</p><p>The <tt class="classname">Socket</tt> window ID is obtained by using
+the <tt class="classname">Socket</tt> method <tt class="methodname">get_id</tt>().
+Before using this method, the <tt class="classname">Socket</tt> must be
+realized, and added to its parent.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>If you pass the window ID of the <tt class="classname">Socket</tt>
+to another process that will create a <tt class="classname">Plug</tt> in the
+<tt class="classname">Socket</tt>, you must make sure that the
+<tt class="classname">Socket</tt> widget is not destroyed until that
+<tt class="classname">Plug</tt> is created.</p></div><p>When GTK+ is notified that the embedded window has been
+destroyed, then it will destroy the <tt class="classname">Socket</tt> as well.
+You should always, therefore, be prepared for your sockets to be destroyed
+at any time when the main event loop is running. Destroying a
+<tt class="classname">Socket</tt> will cause an embedded
+<tt class="classname">Plug</tt> to be destroyed as well.</p><p>The communication between a <tt class="classname">Socket</tt> and a
+<tt class="classname">Plug</tt> follows the XEmbed protocol. This protocol has
+also been implemented in other toolkits, e.g. Qt, allowing the same level of
+integration when embedding a Qt widget in GTK or vice versa.</p><p>Create a new empty <tt class="classname">Socket</tt>:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ socket = gtk.Socket()
+</pre></td></tr></table><p>The <tt class="classname">Socket</tt> must be contained in a
+toplevel window before you invoke the <tt class="methodname">add_id</tt>()
+method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ socket.add_id(window_id)
+</pre></td></tr></table><p>which adds an XEMBED client, such as a
+<tt class="classname">Plug</tt>, to the <tt class="classname">Socket</tt>. The
+client may be in the same process or in a different process.</p><p>To embed a <tt class="classname">Plug</tt> in a
+<tt class="classname">Socket</tt>, you can either create the
+<tt class="classname">Plug</tt> with:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ plug = gtk.Plug(0L)
+</pre></td></tr></table><p>and then pass the number returned by the
+<tt class="classname">Plug</tt> <tt class="methodname">get_id</tt>() method to the
+<tt class="classname">Socket</tt> <tt class="methodname">add_id</tt>()
+method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ socket.add_id(plug)
+</pre></td></tr></table><p>or you can invoke the <tt class="classname">Socket</tt>
+<tt class="methodname">get_id</tt>() method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ window_id = socket.get_id()
+</pre></td></tr></table><p>to get the window ID for the socket, and then create the plug
+with:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ plug = gtk.Plug(window_id)
+</pre></td></tr></table><p>The <tt class="classname">Socket</tt> must have already be added
+into a toplevel window before you can make this call.</p><p>The <a href="examples/socket.py" target="_top"><span><b class="command">socket.py</b></span></a> example
+program illustrates the use of a <tt class="classname">Socket</tt>:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 1 #!/usr/bin/python
+ 2
+ 3 import string
+ 4
+ 5 import pygtk
+ 6 pygtk.require('2.0')
+ 7 import gtk,sys
+ 8
+ 9 window = gtk.Window()
+ 10 window.show()
+ 11
+ 12 socket = gtk.Socket()
+ 13 socket.show()
+ 14 window.add(socket)
+ 15
+ 16 print "Socket ID=", socket.get_id()
+ 17 window.connect("destroy", gtk.mainquit)
+ 18
+ 19 def plugged_event(widget):
+ 20 print "I (",widget,") have just had a plug inserted!"
+ 21
+ 22 socket.connect("plug-added", plugged_event)
+ 23
+ 24 if len(sys.argv) == 2:
+ 25 socket.add_id(long(sys.argv[1]))
+ 26
+ 27 gtk.mainloop()
+</pre></td></tr></table><p>To run the example you can either run <a href="examples/plug.py" target="_top"><span><b class="command">plug.py</b></span></a> first:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ $ python plug.py
+ Plug ID= 20971522
+</pre></td></tr></table><p>and copy the output ID to the first arg of <a href="examples/socket.py" target="_top"><span><b class="command">socket.py</b></span></a>:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ $ python socket.py 20971522
+ Socket ID= 48234523
+ I ( &lt;gtk.Plug object (GtkPlug) at 0x3008dd78&gt; ) have just been embedded!
+ I ( &lt;gtk.Socket object (GtkSocket) at 0x3008ddf0&gt; ) have just had a plug inserted!
+</pre></td></tr></table><p>Or you can run <a href="examples/socket.py" target="_top"><span><b class="command">socket.py</b></span></a>:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ $ python socket.py
+ Socket ID= 20971547
+</pre></td></tr></table><p>and then run <a href="examples/plug.py" target="_top"><span><b class="command">plug.py</b></span></a>, copying across
+the window ID:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ $ python plug.py
+ 20971547
+ I ( &lt;gtk.Socket object (GtkSocket) at 0x3008ddf0&gt; ) have just had a plug inserted!
+ Plug ID= 48234498
+</pre></td></tr></table></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-Notebooks.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-ContainerWidgets.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch-MenuWidget.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">10.12. Notebooks </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 11. Menu Widget</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-ProgressBars.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-ProgressBars.html
new file mode 100644
index 0000000..5710e1e
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-ProgressBars.html
@@ -0,0 +1,188 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>9.4. Progress Bars</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-MiscellaneousWidgets.html" title="Chapter 9. Miscellaneous Widgets"><link rel="previous" href="sec-TooltipsObject.html" title="9.3. The Tooltips Object"><link rel="next" href="sec-Dialogs.html" title="9.5. Dialogs"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">9.4. Progress Bars</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-TooltipsObject.html">Prev</a> </td><th width="60%" align="center">Chapter 9. Miscellaneous Widgets</th><td width="20%" align="right"> <a accesskey="n" href="sec-Dialogs.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-ProgressBars"></a>9.4. Progress Bars</h2></div></div><div></div></div><p>Progress bars are used to show the status of an operation. They
+are pretty easy to use, as you will see with the code below. But first lets
+start out with the call to create a new progress bar.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ progressbar = gtk.ProgressBar(<b class="parameter"><tt>adjustment</tt></b>=None)
+</pre></td></tr></table><p>The <i class="parameter"><tt>adjustment</tt></i> argument specifies an
+adjustment to use with the <i class="parameter"><tt>progressbar</tt></i>. If not
+specified an adjustment will be created. Now that the progress bar has been
+created we can use it.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ progressbar.set_fraction(<b class="parameter"><tt>fraction</tt></b>) </pre></td></tr></table><p>The <i class="parameter"><tt>progressbar</tt></i> object is the progress bar
+you wish to operate on, and the argument (<i class="parameter"><tt>fraction</tt></i>) is
+the amount "completed", meaning the amount the progress bar has been filled
+from 0-100%. This is passed to the method as a real number ranging from 0 to
+1.</p><p>A progress bar may be set to one of a number of orientations
+using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ progressbar.set_orientation(<b class="parameter"><tt>orientation</tt></b>) </pre></td></tr></table><p>The <i class="parameter"><tt>orientation</tt></i> argument may take one of
+the following values to indicate the direction in which the progress bar
+moves:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ PROGRESS_LEFT_TO_RIGHT
+ PROGRESS_RIGHT_TO_LEFT
+ PROGRESS_BOTTOM_TO_TOP
+ PROGRESS_TOP_TO_BOTTOM
+</pre></td></tr></table><p>As well as indicating the amount of progress that has occurred,
+the progress bar may be set to just indicate that there is some activity.
+This can be useful in situations where progress cannot be measured against a
+value range. The following function indicates that some progress has been
+made.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ progressbar.pulse()
+</pre></td></tr></table><p>The step size of the activity indicator is set using the
+following function where fraction is between 0.0 and 1.0.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ progressbar.set_pulse_step(<b class="parameter"><tt>fraction</tt></b>)
+</pre></td></tr></table><p>When not in activity mode, the progress bar can also display a
+configurable text string within its trough, using the following
+method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ progressbar.set_text(<b class="parameter"><tt>text</tt></b>)
+</pre></td></tr></table><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>Note that <tt class="methodname">set_text</tt>() doesn't support
+the <tt class="function">printf</tt>()-like formatting of the GTK+ 1.2
+Progressbar.</p></div><p>You can turn off the display of the string by calling
+<tt class="methodname">set_text</tt>() again with no argument.</p><p>The current text setting of a progressbar can be retrieved with
+the following method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ text = progressbar.get_text()
+</pre></td></tr></table><p>Progress Bars are usually used with timeouts or other such
+functions (see <a href="ch-TimeoutsIOAndIdleFunctions.html" title="Chapter 19. Timeouts, IO and Idle Functions">Chapter 19, <i>Timeouts, IO and Idle Functions</i></a>) to
+give the illusion of multitasking. All will employ the
+<tt class="methodname">set_fraction</tt>() or <tt class="methodname">pulse</tt>()
+methods in the same manner.</p><p>The <a href="examples/progressbar.py" target="_top"><span><b class="command">progressbar.py</b></span></a>
+program provides an example of the progress bar, updated using timeouts.
+This code also shows you how to reset the Progress Bar.
+<a href="sec-ProgressBars.html#progressbarfig" title="Figure 9.4. ProgressBar Example">Figure 9.4, “ProgressBar Exampleâ€</a> illustrates the resulting display:</p><div class="figure"><a name="progressbarfig"></a><p class="title"><b>Figure 9.4. ProgressBar Example</b></p><div class="mediaobject" align="center"><img src="figures/progressbar.png" align="middle" alt="ProgressBar Example"></div></div><p>The source code for <a href="examples/progressbar.py" target="_top"><span><b class="command">progressbar.py</b></span></a>
+is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 1 #!/usr/bin/env python
+ 2
+ 3 # example progressbar.py
+ 4
+ 5 import pygtk
+ 6 pygtk.require('2.0')
+ 7 import gtk, gobject
+ 8
+ 9 # Update the value of the progress bar so that we get
+ 10 # some movement
+ 11 def progress_timeout(pbobj):
+ 12 if pbobj.activity_check.get_active():
+ 13 pbobj.pbar.pulse()
+ 14 else:
+ 15 # Calculate the value of the progress bar using the
+ 16 # value range set in the adjustment object
+ 17 new_val = pbobj.pbar.get_fraction() + 0.01
+ 18 if new_val &gt; 1.0:
+ 19 new_val = 0.0
+ 20 # Set the new value
+ 21 pbobj.pbar.set_fraction(new_val)
+ 22
+ 23 # As this is a timeout function, return TRUE so that it
+ 24 # continues to get called
+ 25 return True
+ 26
+ 27 class ProgressBar:
+ 28 # Callback that toggles the text display within the progress
+ 29 # bar trough
+ 30 def toggle_show_text(self, widget, data=None):
+ 31 if widget.get_active():
+ 32 self.pbar.set_text("some text")
+ 33 else:
+ 34 self.pbar.set_text("")
+ 35
+ 36 # Callback that toggles the activity mode of the progress
+ 37 # bar
+ 38 def toggle_activity_mode(self, widget, data=None):
+ 39 if widget.get_active():
+ 40 self.pbar.pulse()
+ 41 else:
+ 42 self.pbar.set_fraction(0.0)
+ 43
+ 44 # Callback that toggles the orientation of the progress bar
+ 45 def toggle_orientation(self, widget, data=None):
+ 46 if self.pbar.get_orientation() == gtk.PROGRESS_LEFT_TO_RIGHT:
+ 47 self.pbar.set_orientation(gtk.PROGRESS_RIGHT_TO_LEFT)
+ 48 elif self.pbar.get_orientation() == gtk.PROGRESS_RIGHT_TO_LEFT:
+ 49 self.pbar.set_orientation(gtk.PROGRESS_LEFT_TO_RIGHT)
+ 50
+ 51 # Clean up allocated memory and remove the timer
+ 52 def destroy_progress(self, widget, data=None):
+ 53 gobject.source_remove(self.timer)
+ 54 self.timer = 0
+ 55 gtk.main_quit()
+ 56
+ 57 def __init__(self):
+ 58 self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ 59 self.window.set_resizable(True)
+ 60
+ 61 self.window.connect("destroy", self.destroy_progress)
+ 62 self.window.set_title("ProgressBar")
+ 63 self.window.set_border_width(0)
+ 64
+ 65 vbox = gtk.VBox(False, 5)
+ 66 vbox.set_border_width(10)
+ 67 self.window.add(vbox)
+ 68 vbox.show()
+ 69
+ 70 # Create a centering alignment object
+ 71 align = gtk.Alignment(0.5, 0.5, 0, 0)
+ 72 vbox.pack_start(align, False, False, 5)
+ 73 align.show()
+ 74
+ 75 # Create the ProgressBar
+ 76 self.pbar = gtk.ProgressBar()
+ 77
+ 78 align.add(self.pbar)
+ 79 self.pbar.show()
+ 80
+ 81 # Add a timer callback to update the value of the progress bar
+ 82 self.timer = gobject.timeout_add (100, progress_timeout, self)
+ 83
+ 84 separator = gtk.HSeparator()
+ 85 vbox.pack_start(separator, False, False, 0)
+ 86 separator.show()
+ 87
+ 88 # rows, columns, homogeneous
+ 89 table = gtk.Table(2, 2, False)
+ 90 vbox.pack_start(table, False, True, 0)
+ 91 table.show()
+ 92
+ 93 # Add a check button to select displaying of the trough text
+ 94 check = gtk.CheckButton("Show text")
+ 95 table.attach(check, 0, 1, 0, 1,
+ 96 gtk.EXPAND | gtk.FILL, gtk.EXPAND | gtk.FILL,
+ 97 5, 5)
+ 98 check.connect("clicked", self.toggle_show_text)
+ 99 check.show()
+ 100
+ 101 # Add a check button to toggle activity mode
+ 102 self.activity_check = check = gtk.CheckButton("Activity mode")
+ 103 table.attach(check, 0, 1, 1, 2,
+ 104 gtk.EXPAND | gtk.FILL, gtk.EXPAND | gtk.FILL,
+ 105 5, 5)
+ 106 check.connect("clicked", self.toggle_activity_mode)
+ 107 check.show()
+ 108
+ 109 # Add a check button to toggle orientation
+ 110 check = gtk.CheckButton("Right to Left")
+ 111 table.attach(check, 0, 1, 2, 3,
+ 112 gtk.EXPAND | gtk.FILL, gtk.EXPAND | gtk.FILL,
+ 113 5, 5)
+ 114 check.connect("clicked", self.toggle_orientation)
+ 115 check.show()
+ 116
+ 117 # Add a button to exit the program
+ 118 button = gtk.Button("close")
+ 119 button.connect("clicked", self.destroy_progress)
+ 120 vbox.pack_start(button, False, False, 0)
+ 121
+ 122 # This makes it so the button is the default.
+ 123 button.set_flags(gtk.CAN_DEFAULT)
+ 124
+ 125 # This grabs this button to be the default button. Simply hitting
+ 126 # the "Enter" key will cause this button to activate.
+ 127 button.grab_default ()
+ 128 button.show()
+ 129
+ 130 self.window.show()
+ 131
+ 132 def main():
+ 133 gtk.main()
+ 134 return 0
+ 135
+ 136 if __name__ == "__main__":
+ 137 ProgressBar()
+ 138 main()
+</pre></td></tr></table></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-TooltipsObject.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-MiscellaneousWidgets.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-Dialogs.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">9.3. The Tooltips Object </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 9.5. Dialogs</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-RadioButtons.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-RadioButtons.html
new file mode 100644
index 0000000..e3caad7
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-RadioButtons.html
@@ -0,0 +1,101 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>6.4. Radio Buttons</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-ButtonWidget.html" title="Chapter 6. The Button Widget"><link rel="previous" href="sec-CheckButtons.html" title="6.3. Check Buttons"><link rel="next" href="ch-Adjustments.html" title="Chapter 7. Adjustments"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">6.4. Radio Buttons</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-CheckButtons.html">Prev</a> </td><th width="60%" align="center">Chapter 6. The Button Widget</th><td width="20%" align="right"> <a accesskey="n" href="ch-Adjustments.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-RadioButtons"></a>6.4. Radio Buttons</h2></div></div><div></div></div><p>Radio buttons are similar to check buttons except they are grouped
+so that only one may be selected/depressed at a time. This is good for
+places in your application where you need to select from a short list of
+options.</p><p>Creating a new radio button is done with this call:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ radio_button = gtk.RadioButton(<b class="parameter"><tt>group</tt></b>=None, <b class="parameter"><tt>label</tt></b>=None)
+</pre></td></tr></table><p>You'll notice the extra argument to this call. Radio buttons
+require a <i class="parameter"><tt>group</tt></i> to operate properly. The first call
+to <tt class="function">gtk.RadioButton</tt>() should pass
+<tt class="literal">None</tt> as the first argument and a new radio button group
+will be created with the new radio button as its only member.</p><p>To add more radio buttons to a group, pass in a reference to a
+radio button in <i class="parameter"><tt>group</tt></i> in subsequent calls to
+<tt class="function">gtk.RadioButton</tt>().</p><p>If a <i class="parameter"><tt>label</tt></i> argument is specified the text
+will be parsed for '_'-prefixed mnemonic characters.</p><p>It is also a good idea to explicitly set which button should be
+the default depressed button with:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ radio_button.set_active(<b class="parameter"><tt>is_active</tt></b>)
+</pre></td></tr></table><p>This is described in the section on toggle buttons, and works in
+exactly the same way. Once the radio buttons are grouped together, only one
+of the group may be active at a time. If the user clicks on one radio
+button, and then on another, the first radio button will first emit a
+"toggled" signal (to report becoming inactive), and then the second will
+emit its "toggled" signal (to report becoming active).</p><p>The example program <a href="examples/radiobuttons.py" target="_top"><span><b class="command">radiobuttons.py</b></span></a>
+creates a radio button group with three buttons.
+<a href="sec-RadioButtons.html#radiobuttonfig" title="Figure 6.4. Radio Buttons Example">Figure 6.4, “Radio Buttons Exampleâ€</a> illustrates the resulting window:</p><div class="figure"><a name="radiobuttonfig"></a><p class="title"><b>Figure 6.4. Radio Buttons Example</b></p><div class="mediaobject" align="center"><img src="figures/radiobutton.png" align="middle" alt="Radio Buttons Example"></div></div><p>The source code for the example program is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 1 #!/usr/bin/env python
+ 2
+ 3 # example radiobuttons.py
+ 4
+ 5 import pygtk
+ 6 pygtk.require('2.0')
+ 7 import gtk
+ 8
+ 9 class RadioButtons:
+ 10 def callback(self, widget, data=None):
+ 11 print "%s was toggled %s" % (data, ("OFF", "ON")[widget.get_active()])
+ 12
+ 13 def close_application(self, widget, event, data=None):
+ 14 gtk.main_quit()
+ 15 return False
+ 16
+ 17 def __init__(self):
+ 18 self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ 19
+ 20 self.window.connect("delete_event", self.close_application)
+ 21
+ 22 self.window.set_title("radio buttons")
+ 23 self.window.set_border_width(0)
+ 24
+ 25 box1 = gtk.VBox(False, 0)
+ 26 self.window.add(box1)
+ 27 box1.show()
+ 28
+ 29 box2 = gtk.VBox(False, 10)
+ 30 box2.set_border_width(10)
+ 31 box1.pack_start(box2, True, True, 0)
+ 32 box2.show()
+ 33
+ 34 button = gtk.RadioButton(None, "radio button1")
+ 35 button.connect("toggled", self.callback, "radio button 1")
+ 36 box2.pack_start(button, True, True, 0)
+ 37 button.show()
+ 38
+ 39 button = gtk.RadioButton(button, "radio button2")
+ 40 button.connect("toggled", self.callback, "radio button 2")
+ 41 button.set_active(True)
+ 42 box2.pack_start(button, True, True, 0)
+ 43 button.show()
+ 44
+ 45 button = gtk.RadioButton(button, "radio button3")
+ 46 button.connect("toggled", self.callback, "radio button 3")
+ 47 box2.pack_start(button, True, True, 0)
+ 48 button.show()
+ 49
+ 50 separator = gtk.HSeparator()
+ 51 box1.pack_start(separator, False, True, 0)
+ 52 separator.show()
+ 53
+ 54 box2 = gtk.VBox(False, 10)
+ 55 box2.set_border_width(10)
+ 56 box1.pack_start(box2, False, True, 0)
+ 57 box2.show()
+ 58
+ 59 button = gtk.Button("close")
+ 60 button.connect_object("clicked", self.close_application, self.window,
+ 61 None)
+ 62 box2.pack_start(button, True, True, 0)
+ 63 button.set_flags(gtk.CAN_DEFAULT)
+ 64 button.grab_default()
+ 65 button.show()
+ 66 self.window.show()
+ 67
+ 68 def main():
+ 69 gtk.main()
+ 70 return 0
+ 71
+ 72 if __name__ == "__main__":
+ 73 RadioButtons()
+ 74 main()
+</pre></td></tr></table><p>The code is fairly straight forward. Lines 63-64 make the
+"close" button the default widget so that pressing the "Enter" key when the
+window is active causes the "close" button to emit the "clicked"
+signal.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-CheckButtons.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-ButtonWidget.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch-Adjustments.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">6.3. Check Buttons </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 7. Adjustments</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-RangeWidgetEample.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-RangeWidgetEample.html
new file mode 100644
index 0000000..a9e8185
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-RangeWidgetEample.html
@@ -0,0 +1,248 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>8.5. Range Widget Example</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-RangeWidgets.html" title="Chapter 8. Range Widgets"><link rel="previous" href="sec-KeyAndMouseBindings.html" title="8.4. Key and Mouse Bindings"><link rel="next" href="ch-MiscellaneousWidgets.html" title="Chapter 9. Miscellaneous Widgets"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">8.5. Range Widget Example</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-KeyAndMouseBindings.html">Prev</a> </td><th width="60%" align="center">Chapter 8. Range Widgets</th><td width="20%" align="right"> <a accesskey="n" href="ch-MiscellaneousWidgets.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-RangeWidgetEample"></a>8.5. Range Widget Example</h2></div></div><div></div></div><p>The example program (<a href="examples/rangewidgets.py" target="_top"><span><b class="command">rangewidgets.py</b></span></a>)
+puts up a window with three range widgets all connected to the same
+adjustment, and a couple of controls for adjusting some of the parameters
+mentioned above and in the section on adjustments, so you can see how they
+affect the way these widgets work for the user. <a href="sec-RangeWidgetEample.html#rangefig" title="Figure 8.1. Range Widgets Example">Figure 8.1, “Range Widgets Exampleâ€</a>
+illustrates the result of running the program:</p><div class="figure"><a name="rangefig"></a><p class="title"><b>Figure 8.1. Range Widgets Example</b></p><div class="mediaobject" align="center"><img src="figures/rangewidgets.png" align="middle" alt="Range Widgets Example"></div></div><p>The <a href="examples/rangewidgets.py" target="_top"><span><b class="command">rangewidgets.py</b></span></a>
+source code is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 1 #!/usr/bin/env python
+ 2
+ 3 # example rangewidgets.py
+ 4
+ 5 import pygtk
+ 6 pygtk.require('2.0')
+ 7 import gtk
+ 8
+ 9 # Convenience functions
+ 10
+ 11 def make_menu_item(name, callback, data=None):
+ 12 item = gtk.MenuItem(name)
+ 13 item.connect("activate", callback, data)
+ 14 item.show()
+ 15 return item
+ 16
+ 17 def scale_set_default_values(scale):
+ 18 scale.set_update_policy(gtk.UPDATE_CONTINUOUS)
+ 19 scale.set_digits(1)
+ 20 scale.set_value_pos(gtk.POS_TOP)
+ 21 scale.set_draw_value(True)
+ 22
+ 23 class RangeWidgets:
+ 24 def cb_pos_menu_select(self, item, pos):
+ 25 # Set the value position on both scale widgets
+ 26 self.hscale.set_value_pos(pos)
+ 27 self.vscale.set_value_pos(pos)
+ 28
+ 29 def cb_update_menu_select(self, item, policy):
+ 30 # Set the update policy for both scale widgets
+ 31 self.hscale.set_update_policy(policy)
+ 32 self.vscale.set_update_policy(policy)
+ 33
+ 34 def cb_digits_scale(self, adj):
+ 35 # Set the number of decimal places to which adj-&gt;value is rounded
+ 36 self.hscale.set_digits(adj.value)
+ 37 self.vscale.set_digits(adj.value)
+ 38
+ 39 def cb_page_size(self, get, set):
+ 40 # Set the page size and page increment size of the sample
+ 41 # adjustment to the value specified by the "Page Size" scale
+ 42 set.page_size = get.value
+ 43 set.page_incr = get.value
+ 44 # Now emit the "changed" signal to reconfigure all the widgets that
+ 45 # are attached to this adjustment
+ 46 set.emit("changed")
+ 47
+ 48 def cb_draw_value(self, button):
+ 49 # Turn the value display on the scale widgets off or on depending
+ 50 # on the state of the checkbutton
+ 51 self.hscale.set_draw_value(button.get_active())
+ 52 self.vscale.set_draw_value(button.get_active())
+ 53
+ 54 # makes the sample window
+ 55
+ 56 def __init__(self):
+ 57 # Standard window-creating stuff
+ 58 self.window = gtk.Window (gtk.WINDOW_TOPLEVEL)
+ 59 self.window.connect("destroy", lambda w: gtk.main_quit())
+ 60 self.window.set_title("range controls")
+ 61
+ 62 box1 = gtk.VBox(False, 0)
+ 63 self.window.add(box1)
+ 64 box1.show()
+ 65
+ 66 box2 = gtk.HBox(False, 10)
+ 67 box2.set_border_width(10)
+ 68 box1.pack_start(box2, True, True, 0)
+ 69 box2.show()
+ 70
+ 71 # value, lower, upper, step_increment, page_increment, page_size
+ 72 # Note that the page_size value only makes a difference for
+ 73 # scrollbar widgets, and the highest value you'll get is actually
+ 74 # (upper - page_size).
+ 75 adj1 = gtk.Adjustment(0.0, 0.0, 101.0, 0.1, 1.0, 1.0)
+ 76
+ 77 self.vscale = gtk.VScale(adj1)
+ 78 scale_set_default_values(self.vscale)
+ 79 box2.pack_start(self.vscale, True, True, 0)
+ 80 self.vscale.show()
+ 81
+ 82 box3 = gtk.VBox(False, 10)
+ 83 box2.pack_start(box3, True, True, 0)
+ 84 box3.show()
+ 85
+ 86 # Reuse the same adjustment
+ 87 self.hscale = gtk.HScale(adj1)
+ 88 self.hscale.set_size_request(200, 30)
+ 89 scale_set_default_values(self.hscale)
+ 90 box3.pack_start(self.hscale, True, True, 0)
+ 91 self.hscale.show()
+ 92
+ 93 # Reuse the same adjustment again
+ 94 scrollbar = gtk.HScrollbar(adj1)
+ 95 # Notice how this causes the scales to always be updated
+ 96 # continuously when the scrollbar is moved
+ 97 scrollbar.set_update_policy(gtk.UPDATE_CONTINUOUS)
+ 98 box3.pack_start(scrollbar, True, True, 0)
+ 99 scrollbar.show()
+ 100
+ 101 box2 = gtk.HBox(False, 10)
+ 102 box2.set_border_width(10)
+ 103 box1.pack_start(box2, True, True, 0)
+ 104 box2.show()
+ 105
+ 106 # A checkbutton to control whether the value is displayed or not
+ 107 button = gtk.CheckButton("Display value on scale widgets")
+ 108 button.set_active(True)
+ 109 button.connect("toggled", self.cb_draw_value)
+ 110 box2.pack_start(button, True, True, 0)
+ 111 button.show()
+ 112
+ 113 box2 = gtk.HBox(False, 10)
+ 114 box2.set_border_width(10)
+ 115
+ 116 # An option menu to change the position of the value
+ 117 label = gtk.Label("Scale Value Position:")
+ 118 box2.pack_start(label, False, False, 0)
+ 119 label.show()
+ 120
+ 121 opt = gtk.OptionMenu()
+ 122 menu = gtk.Menu()
+ 123
+ 124 item = make_menu_item ("Top", self.cb_pos_menu_select, gtk.POS_TOP)
+ 125 menu.append(item)
+ 126
+ 127 item = make_menu_item ("Bottom", self.cb_pos_menu_select,
+ 128 gtk.POS_BOTTOM)
+ 129 menu.append(item)
+ 130
+ 131 item = make_menu_item ("Left", self.cb_pos_menu_select, gtk.POS_LEFT)
+ 132 menu.append(item)
+ 133
+ 134 item = make_menu_item ("Right", self.cb_pos_menu_select, gtk.POS_RIGHT)
+ 135 menu.append(item)
+ 136
+ 137 opt.set_menu(menu)
+ 138 box2.pack_start(opt, True, True, 0)
+ 139 opt.show()
+ 140
+ 141 box1.pack_start(box2, True, True, 0)
+ 142 box2.show()
+ 143
+ 144 box2 = gtk.HBox(False, 10)
+ 145 box2.set_border_width(10)
+ 146
+ 147 # Yet another option menu, this time for the update policy of the
+ 148 # scale widgets
+ 149 label = gtk.Label("Scale Update Policy:")
+ 150 box2.pack_start(label, False, False, 0)
+ 151 label.show()
+ 152
+ 153 opt = gtk.OptionMenu()
+ 154 menu = gtk.Menu()
+ 155
+ 156 item = make_menu_item("Continuous", self.cb_update_menu_select,
+ 157 gtk.UPDATE_CONTINUOUS)
+ 158 menu.append(item)
+ 159
+ 160 item = make_menu_item ("Discontinuous", self.cb_update_menu_select,
+ 161 gtk.UPDATE_DISCONTINUOUS)
+ 162 menu.append(item)
+ 163
+ 164 item = make_menu_item ("Delayed", self.cb_update_menu_select,
+ 165 gtk.UPDATE_DELAYED)
+ 166 menu.append(item)
+ 167
+ 168 opt.set_menu(menu)
+ 169 box2.pack_start(opt, True, True, 0)
+ 170 opt.show()
+ 171
+ 172 box1.pack_start(box2, True, True, 0)
+ 173 box2.show()
+ 174
+ 175 box2 = gtk.HBox(False, 10)
+ 176 box2.set_border_width(10)
+ 177
+ 178 # An HScale widget for adjusting the number of digits on the
+ 179 # sample scales.
+ 180 label = gtk.Label("Scale Digits:")
+ 181 box2.pack_start(label, False, False, 0)
+ 182 label.show()
+ 183
+ 184 adj2 = gtk.Adjustment(1.0, 0.0, 5.0, 1.0, 1.0, 0.0)
+ 185 adj2.connect("value_changed", self.cb_digits_scale)
+ 186 scale = gtk.HScale(adj2)
+ 187 scale.set_digits(0)
+ 188 box2.pack_start(scale, True, True, 0)
+ 189 scale.show()
+ 190
+ 191 box1.pack_start(box2, True, True, 0)
+ 192 box2.show()
+ 193
+ 194 box2 = gtk.HBox(False, 10)
+ 195 box2.set_border_width(10)
+ 196
+ 197 # And, one last HScale widget for adjusting the page size of the
+ 198 # scrollbar.
+ 199 label = gtk.Label("Scrollbar Page Size:")
+ 200 box2.pack_start(label, False, False, 0)
+ 201 label.show()
+ 202
+ 203 adj2 = gtk.Adjustment(1.0, 1.0, 101.0, 1.0, 1.0, 0.0)
+ 204 adj2.connect("value_changed", self.cb_page_size, adj1)
+ 205 scale = gtk.HScale(adj2)
+ 206 scale.set_digits(0)
+ 207 box2.pack_start(scale, True, True, 0)
+ 208 scale.show()
+ 209
+ 210 box1.pack_start(box2, True, True, 0)
+ 211 box2.show()
+ 212
+ 213 separator = gtk.HSeparator()
+ 214 box1.pack_start(separator, False, True, 0)
+ 215 separator.show()
+ 216
+ 217 box2 = gtk.VBox(False, 10)
+ 218 box2.set_border_width(10)
+ 219 box1.pack_start(box2, False, True, 0)
+ 220 box2.show()
+ 221
+ 222 button = gtk.Button("Quit")
+ 223 button.connect("clicked", lambda w: gtk.main_quit())
+ 224 box2.pack_start(button, True, True, 0)
+ 225 button.set_flags(gtk.CAN_DEFAULT)
+ 226 button.grab_default()
+ 227 button.show()
+ 228 self.window.show()
+ 229
+ 230 def main():
+ 231 gtk.main()
+ 232 return 0
+ 233
+ 234 if __name__ == "__main__":
+ 235 RangeWidgets()
+ 236 main()
+</pre></td></tr></table><p>You will notice that the program does not call the
+<tt class="methodname">connect</tt>() method for the "delete_event", but only for
+the "destroy" signal. This will still perform the desired operation, because
+an unhandled "delete_event" will result in a "destroy" signal being given to
+the window.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-KeyAndMouseBindings.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-RangeWidgets.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch-MiscellaneousWidgets.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">8.4. Key and Mouse Bindings </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 9. Miscellaneous Widgets</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-RetrievingTheSelection.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-RetrievingTheSelection.html
new file mode 100644
index 0000000..3e35bcb
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-RetrievingTheSelection.html
@@ -0,0 +1,212 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>21.2. Retrieving the Selection</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-ManagingSelections.html" title="Chapter 21. Managing Selections"><link rel="previous" href="ch-ManagingSelections.html" title="Chapter 21. Managing Selections"><link rel="next" href="sec-SupplyingTheSelection.html" title="21.3. Supplying the Selection"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">21.2. Retrieving the Selection</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch-ManagingSelections.html">Prev</a> </td><th width="60%" align="center">Chapter 21. Managing Selections</th><td width="20%" align="right"> <a accesskey="n" href="sec-SupplyingTheSelection.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-RetrievingTheSelection"></a>21.2. Retrieving the Selection</h2></div></div><div></div></div><p>Retrieving the selection is an asynchronous process. To start
+the process, you call:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ result = widget.selection_convert(<b class="parameter"><tt>selection</tt></b>, <b class="parameter"><tt>target</tt></b>, <b class="parameter"><tt>time</tt></b>=0)
+</pre></td></tr></table><p>This converts the <i class="parameter"><tt>selection</tt></i> into the form
+specified by <i class="parameter"><tt>target</tt></i>. <i class="parameter"><tt>selection</tt></i>
+is an atom corresponding to the selection type; the common selections are
+the strings:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ PRIMARY
+
+ SECONDARY
+</pre></td></tr></table><p>If at all possible, the <i class="parameter"><tt>time</tt></i> field should
+be the time from the event that triggered the
+<i class="parameter"><tt>selection</tt></i>. This helps make sure that events occur in
+the order that the user requested them. However, if it is not available (for
+instance, if the conversion was triggered by a "clicked" signal), then you
+can use 0 which means use the current time. <i class="parameter"><tt>result</tt></i> is
+<tt class="literal">TRUE</tt> if the conversion succeeded,
+<tt class="literal">FALSE</tt> otherwise.</p><p>When the selection owner responds to the request, a
+"selection_received" signal is sent to your application. The handler for
+this signal receives a <tt class="classname">gtk.SelectionData</tt> object,
+which has the following attributes:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ selection
+ target
+ type
+ format
+ data
+</pre></td></tr></table><p><i class="parameter"><tt>selection</tt></i> and <i class="parameter"><tt>target</tt></i>
+are the values you gave in your <tt class="methodname">selection_convert</tt>()
+method.</p><p><i class="parameter"><tt>type</tt></i> is an atom that identifies the type of
+data returned by the selection owner. Some possible values are "STRING", a
+string of latin-1 characters, "ATOM", a series of atoms, "INTEGER", an
+integer, "image/x-xpixmap", etc. Most targets can only return one
+type.</p><p>The list of standard atoms in X and GTK+ is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ PRIMARY
+ SECONDARY
+ ARC
+ ATOM
+ BITMAP
+ CARDINAL
+ COLORMAP
+ CURSOR
+ CUT_BUFFER0
+ CUT_BUFFER1
+ CUT_BUFFER2
+ CUT_BUFFER3
+ CUT_BUFFER4
+ CUT_BUFFER5
+ CUT_BUFFER6
+ CUT_BUFFER7
+ DRAWABLE
+ FONT
+ INTEGER
+ PIXMAP
+ POINT
+ RECTANGLE
+ RESOURCE_MANAGER
+ RGB_COLOR_MAP
+ RGB_BEST_MAP
+ RGB_BLUE_MAP
+ RGB_DEFAULT_MAP
+ RGB_GRAY_MAP
+ RGB_GREEN_MAP
+ RGB_RED_MAP
+ STRING
+ VISUALID
+ WINDOW
+ WM_COMMAND
+ WM_HINTS
+ WM_CLIENT_MACHINE
+ WM_ICON_NAME
+ WM_ICON_SIZE
+ WM_NAME
+ WM_NORMAL_HINTS
+ WM_SIZE_HINTS
+ WM_ZOOM_HINTS
+ MIN_SPACE
+ NORM_SPACE
+ MAX_SPACE END_SPACE,
+ SUPERSCRIPT_X
+ SUPERSCRIPT_Y
+ SUBSCRIPT_X
+ SUBSCRIPT_Y
+ UNDERLINE_POSITION
+ UNDERLINE_THICKNESS
+ STRIKEOUT_ASCENT
+ STRIKEOUT_DESCENT
+ ITALIC_ANGLE
+ X_HEIGHT
+ QUAD_WIDTH
+ WEIGHT
+ POINT_SIZE
+ RESOLUTION
+ COPYRIGHT
+ NOTICE
+ FONT_NAME
+ FAMILY_NAME
+ FULL_NAME
+ CAP_HEIGHT
+ WM_CLASS
+ WM_TRANSIENT_FOR
+ CLIPBOARD
+</pre></td></tr></table><p><i class="parameter"><tt>format</tt></i> gives the length of the units (for
+instance characters) in bits. Usually, you don't care about this when
+receiving data.</p><p><i class="parameter"><tt>data</tt></i> is the returned data in the form of a
+string.</p><p>PyGTK wraps all received data into a string. This makes it easy
+to handle string targets. To retrieve targets of other types (e.g. ATOM or
+INTEGER) the program must extract the information from the returned string.
+PyGTK provides two methods to retrieve text and a list of targets from the
+selection data:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ text = selection_data.get_text()
+
+ targets = selection_data.get_targets()
+</pre></td></tr></table><p>where <i class="parameter"><tt>text</tt></i> is a string containing the text
+of the selection and <i class="parameter"><tt>targets</tt></i> is a list of the targets
+supported by the selection.</p><p>Given a <tt class="classname">gtk.SelectionData</tt> containing a
+list of targets the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ has_text = selection_data.targets_include_text()
+</pre></td></tr></table><p>will return <tt class="literal">TRUE</tt> if one or more of the targets
+can provide text.</p><p>The <a href="examples/getselection.py" target="_top"><span><b class="command">getselection.py</b></span></a>
+example program demonstrates the retrieving of a "STRING" or "TARGETS"
+target from the primary selection and printing the corresponding data to the
+console when the associated button is "clicked". <a href="sec-RetrievingTheSelection.html#getselectionfig" title="Figure 21.1. Get Selection Example">Figure 21.1, “Get Selection Exampleâ€</a> illustrates the program display:</p><div class="figure"><a name="getselectionfig"></a><p class="title"><b>Figure 21.1. Get Selection Example</b></p><div class="mediaobject" align="center"><img src="figures/getselection.png" align="middle" alt="Get Selection Example"></div></div><p>The source code for the <a href="examples/getselection.py" target="_top"><span><b class="command">getselection.py</b></span></a>
+program is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 1 #!/usr/bin/env python
+ 2
+ 3 # example getselection.py
+ 4
+ 5 import pygtk
+ 6 pygtk.require('2.0')
+ 7 import gtk
+ 8
+ 9 class GetSelectionExample:
+ 10 # Signal handler invoked when user clicks on the
+ 11 # "Get String Target" button
+ 12 def get_stringtarget(self, widget):
+ 13 # And request the "STRING" target for the primary selection
+ 14 ret = widget.selection_convert("PRIMARY", "STRING")
+ 15 return
+ 16
+ 17 # Signal handler invoked when user clicks on the "Get Targets" button
+ 18 def get_targets(self, widget):
+ 19 # And request the "TARGETS" target for the primary selection
+ 20 ret = widget.selection_convert("PRIMARY", "TARGETS")
+ 21 return
+ 22
+ 23 # Signal handler called when the selections owner returns the data
+ 24 def selection_received(self, widget, selection_data, data):
+ 25 # Make sure we got the data in the expected form
+ 26 if str(selection_data.type) == "STRING":
+ 27 # Print out the string we received
+ 28 print "STRING TARGET: %s" % selection_data.get_text()
+ 29
+ 30 elif str(selection_data.type) == "ATOM":
+ 31 # Print out the target list we received
+ 32 targets = selection_data.get_targets()
+ 33 for target in targets:
+ 34 name = str(target)
+ 35 if name != None:
+ 36 print "%s" % name
+ 37 else:
+ 38 print "(bad target)"
+ 39 else:
+ 40 print "Selection was not returned as \"STRING\" or \"ATOM\"!"
+ 41
+ 42 return False
+ 43
+ 44
+ 45 def __init__(self):
+ 46 # Create the toplevel window
+ 47 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ 48 window.set_title("Get Selection")
+ 49 window.set_border_width(10)
+ 50 window.connect("destroy", lambda w: gtk.main_quit())
+ 51
+ 52 vbox = gtk.VBox(False, 0)
+ 53 window.add(vbox)
+ 54 vbox.show()
+ 55
+ 56 # Create a button the user can click to get the string target
+ 57 button = gtk.Button("Get String Target")
+ 58 eventbox = gtk.EventBox()
+ 59 eventbox.add(button)
+ 60 button.connect_object("clicked", self.get_stringtarget, eventbox)
+ 61 eventbox.connect("selection_received", self.selection_received)
+ 62 vbox.pack_start(eventbox)
+ 63 eventbox.show()
+ 64 button.show()
+ 65
+ 66 # Create a button the user can click to get targets
+ 67 button = gtk.Button("Get Targets")
+ 68 eventbox = gtk.EventBox()
+ 69 eventbox.add(button)
+ 70 button.connect_object("clicked", self.get_targets, eventbox)
+ 71 eventbox.connect("selection_received", self.selection_received)
+ 72 vbox.pack_start(eventbox)
+ 73 eventbox.show()
+ 74 button.show()
+ 75
+ 76 window.show()
+ 77
+ 78 def main():
+ 79 gtk.main()
+ 80 return 0
+ 81
+ 82 if __name__ == "__main__":
+ 83 GetSelectionExample()
+ 84 main()
+</pre></td></tr></table><p>Lines 30-38 handle the retrieval of the "TARGETS" selection data
+and print the list of target names. The buttons are enclosed in their own
+eventboxes because a selection must be associated with a
+<tt class="classname">gtk.gdkWindow</tt> and buttons are "windowless" widgets in
+GTK+2.0.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch-ManagingSelections.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-ManagingSelections.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-SupplyingTheSelection.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 21. Managing Selections </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 21.3. Supplying the Selection</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-Rulers.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-Rulers.html
new file mode 100644
index 0000000..244a510
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-Rulers.html
@@ -0,0 +1,125 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>9.7. Rulers</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-MiscellaneousWidgets.html" title="Chapter 9. Miscellaneous Widgets"><link rel="previous" href="sec-Images.html" title="9.6. Images"><link rel="next" href="sec-Statusbars.html" title="9.8. Statusbars"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">9.7. Rulers</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-Images.html">Prev</a> </td><th width="60%" align="center">Chapter 9. Miscellaneous Widgets</th><td width="20%" align="right"> <a accesskey="n" href="sec-Statusbars.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-Rulers"></a>9.7. Rulers</h2></div></div><div></div></div><p><tt class="classname">Ruler</tt> widgets are used to indicate the
+location of the mouse pointer in a given window. A window can have a
+horizontal ruler spanning across the width and a vertical ruler spanning
+down the height. A small triangular indicator on the ruler shows the exact
+location of the pointer relative to the ruler.</p><p>A ruler must first be created. Horizontal and vertical rulers are
+created using the functions:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ hruler = gtk.HRuler() # horizontal ruler
+
+ vruler = gtk.VRuler() # vertical ruler
+</pre></td></tr></table><p>Once a ruler is created, we can define the unit of measurement.
+Units of measure for rulers can be <tt class="varname">PIXELS</tt>,
+<tt class="varname">INCHES</tt> or <tt class="varname">CENTIMETERS</tt>. This is set
+using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ ruler.set_metric(<b class="parameter"><tt>metric</tt></b>)
+</pre></td></tr></table><p>The default measure is <tt class="varname">PIXELS</tt>.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ ruler.set_metric(gtk.PIXELS)
+</pre></td></tr></table><p>Other important characteristics of a ruler are how to mark the
+units of scale and where the position indicator is initially placed. These
+are set for a ruler using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ ruler.set_range(<b class="parameter"><tt>lower</tt></b>, <b class="parameter"><tt>upper</tt></b>, <b class="parameter"><tt>position</tt></b>,<b class="parameter"><tt> max_size</tt></b>)
+</pre></td></tr></table><p>The <i class="parameter"><tt>lower</tt></i> and
+<i class="parameter"><tt>upper</tt></i> arguments define the extent of the ruler, and
+<i class="parameter"><tt>max_size</tt></i> is the largest possible number that will be
+displayed. <i class="parameter"><tt>Position</tt></i> defines the initial position of
+the pointer indicator within the ruler.</p><p>A vertical ruler can span an 800 pixel wide window thus:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ vruler.set_range(0, 800, 0, 800)
+</pre></td></tr></table><p>The markings displayed on the ruler will be from 0 to 800, with
+a number for every 100 pixels. If instead we wanted the ruler to range from
+7 to 16, we would code:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ vruler.set_range(7, 16, 0, 20)
+</pre></td></tr></table><p>The indicator on the ruler is a small triangular mark that
+indicates the position of the pointer relative to the ruler. If the ruler is
+used to follow the mouse pointer, the "motion_notify_event" signal should be
+connected to the "motion_notify_event" method of the ruler. We need to setup
+a "motion_notify_event" callback for the area and use
+<tt class="methodname">connect_object</tt>() to get the ruler to emit a
+"motion_notify_signal":</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def motion_notify(ruler, event):
+ return ruler.emit("motion_notify_event", event)
+
+ area.connect_object("motion_notify_event", motion_notify, ruler)
+</pre></td></tr></table><p>The <a href="examples/rulers.py" target="_top"><span><b class="command">rulers.py</b></span></a> example
+program creates a drawing area with a horizontal ruler above it and a
+vertical ruler to the left of it. The size of the drawing area is 600 pixels
+wide by 400 pixels high. The horizontal ruler spans from 7 to 13 with a mark
+every 100 pixels, while the vertical ruler spans from 0 to 400 with a mark
+every 100 pixels. Placement of the drawing area and the rulers is done using
+a table. <a href="sec-Rulers.html#rulersfig" title="Figure 9.8. Rulers Example">Figure 9.8, “Rulers Exampleâ€</a> illustrates the result:</p><div class="figure"><a name="rulersfig"></a><p class="title"><b>Figure 9.8. Rulers Example</b></p><div class="mediaobject" align="center"><img src="figures/rulers.png" align="middle" alt="Rulers Example"></div></div><p>The <a href="examples/rulers.py" target="_top"><span><b class="command">rulers.py</b></span></a> source code
+is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 1 #!/usr/bin/env python
+ 2
+ 3 # example rulers.py
+ 4
+ 5 import pygtk
+ 6 pygtk.require('2.0')
+ 7 import gtk
+ 8
+ 9 class RulersExample:
+ 10 XSIZE = 400
+ 11 YSIZE = 400
+ 12
+ 13 # This routine gets control when the close button is clicked
+ 14 def close_application(self, widget, event, data=None):
+ 15 gtk.main_quit()
+ 16 return False
+ 17
+ 18 def __init__(self):
+ 19 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ 20 window.connect("delete_event", self.close_application)
+ 21 window.set_border_width(10)
+ 22
+ 23 # Create a table for placing the ruler and the drawing area
+ 24 table = gtk.Table(3, 2, False)
+ 25 window.add(table)
+ 26
+ 27 area = gtk.DrawingArea()
+ 28 area.set_size_request(self.XSIZE, self.YSIZE)
+ 29 table.attach(area, 1, 2, 1, 2,
+ 30 gtk.EXPAND|gtk.FILL, gtk.FILL, 0, 0 )
+ 31 area.set_events(gtk.gdk.POINTER_MOTION_MASK |
+ 32 gtk.gdk.POINTER_MOTION_HINT_MASK )
+ 33
+ 34 # The horizontal ruler goes on top. As the mouse moves across the
+ 35 # drawing area, a motion_notify_event is passed to the
+ 36 # appropriate event handler for the ruler.
+ 37 hrule = gtk.HRuler()
+ 38 hrule.set_metric(gtk.PIXELS)
+ 39 hrule.set_range(7, 13, 0, 20)
+ 40 def motion_notify(ruler, event):
+ 41 return ruler.emit("motion_notify_event", event)
+ 42 area.connect_object("motion_notify_event", motion_notify, hrule)
+ 43 table.attach(hrule, 1, 2, 0, 1,
+ 44 gtk.EXPAND|gtk.SHRINK|gtk.FILL, gtk.FILL, 0, 0 )
+ 45
+ 46 # The vertical ruler goes on the left. As the mouse moves across
+ 47 # the drawing area, a motion_notify_event is passed to the
+ 48 # appropriate event handler for the ruler.
+ 49 vrule = gtk.VRuler()
+ 50 vrule.set_metric(gtk.PIXELS)
+ 51 vrule.set_range(0, self.YSIZE, 10, self.YSIZE)
+ 52 area.connect_object("motion_notify_event", motion_notify, vrule)
+ 53 table.attach(vrule, 0, 1, 1, 2,
+ 54 gtk.FILL, gtk.EXPAND|gtk.SHRINK|gtk.FILL, 0, 0 )
+ 55
+ 56 # Now show everything
+ 57 area.show()
+ 58 hrule.show()
+ 59 vrule.show()
+ 60 table.show()
+ 61 window.show()
+ 62
+ 63 def main():
+ 64 gtk.main()
+ 65 return 0
+ 66
+ 67 if __name__ == "__main__":
+ 68 RulersExample()
+ 69 main()
+</pre></td></tr></table><p>Lines 42 and 52 connect the
+<tt class="methodname">motion_notify</tt>() callback to the area but passing
+<i class="parameter"><tt>hrule</tt></i> in line 42 and <i class="parameter"><tt>vrule</tt></i> in
+line 52 as user data. The <tt class="methodname">motion_notify</tt>() callback
+will be called twice each time the mouse moves - once with
+<i class="parameter"><tt>hrule</tt></i> and once with
+<i class="parameter"><tt>vrule</tt></i>.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-Images.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-MiscellaneousWidgets.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-Statusbars.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">9.6. Images </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 9.8. Statusbars</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-ScaleWidgets.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-ScaleWidgets.html
new file mode 100644
index 0000000..c6ef37b
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-ScaleWidgets.html
@@ -0,0 +1,46 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>8.2. Scale Widgets</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-RangeWidgets.html" title="Chapter 8. Range Widgets"><link rel="previous" href="ch-RangeWidgets.html" title="Chapter 8. Range Widgets"><link rel="next" href="sec-CommonRangeMethods.html" title="8.3. Common Range Methods"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">8.2. Scale Widgets</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch-RangeWidgets.html">Prev</a> </td><th width="60%" align="center">Chapter 8. Range Widgets</th><td width="20%" align="right"> <a accesskey="n" href="sec-CommonRangeMethods.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-ScaleWidgets"></a>8.2. Scale Widgets</h2></div></div><div></div></div><p><tt class="classname">Scale</tt> widgets are used to allow the user
+to visually select and manipulate a value within a specific range. You might
+want to use a scale widget, for example, to adjust the magnification level
+on a zoomed preview of a picture, or to control the brightness of a color,
+or to specify the number of minutes of inactivity before a screensaver takes
+over the screen.</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2833070"></a>8.2.1. Creating a Scale Widget</h3></div></div><div></div></div><p>As with scrollbars, there are separate widget types for
+horizontal and vertical scale widgets. (Most programmers seem to favour
+horizontal scale widgets.) Since they work essentially the same way, there's
+no need to treat them separately here. The following methods create vertical
+and horizontal scale widgets, respectively:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ vscale = gtk.VScale(<b class="parameter"><tt>adjustment</tt></b>=None)
+
+ hscale = gtk.HScale(<b class="parameter"><tt>adjustment</tt></b>=None)
+</pre></td></tr></table><p>The <i class="parameter"><tt>adjustment</tt></i> argument can either be
+an adjustment which has already been created with
+<tt class="function">gtk.Adjustment</tt>() , or nothing, in which case, an
+anonymous <tt class="classname">Adjustment</tt> is created with all of its
+values set to 0.0 (which isn't very useful in this case). In order to avoid
+confusing yourself, you probably want to create your adjustment with a
+<i class="parameter"><tt>page_size</tt></i> of 0.0 so that its
+<i class="parameter"><tt>upper</tt></i> value actually corresponds to the highest value
+the user can select. (If you're already thoroughly confused, read <a href="ch-Adjustments.html" title="Chapter 7. Adjustments">Chapter 7, <i>Adjustments</i></a> again for an explanation of what exactly
+adjustments do and how to create and manipulate them.)</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2833123"></a>8.2.2.  Methods and Signals (well, methods, at least)</h3></div></div><div></div></div><p>Scale widgets can display their current value as a number
+beside the trough. The default behaviour is to show the value, but you can
+change this with this method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ scale.set_draw_value(<b class="parameter"><tt>draw_value</tt></b>)
+</pre></td></tr></table><p>As you might have guessed, <i class="parameter"><tt>draw_value</tt></i>
+is either <tt class="literal">TRUE</tt> or <tt class="literal">FALSE</tt>, with
+predictable consequences for either one.</p><p>The value displayed by a scale widget is rounded to one
+decimal point by default, as is the value field in its
+<tt class="classname">Adjustment</tt>. You can change this with:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ scale.set_digits(<b class="parameter"><tt>digits</tt></b>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>digits</tt></i> is the number of decimal
+places you want. You can set digits to anything you like, but no more than
+13 decimal places will actually be drawn on screen.</p><p>Finally, the value can be drawn in different positions
+relative to the trough:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ scale.set_value_pos(<b class="parameter"><tt>pos</tt></b>)
+</pre></td></tr></table><p>The argument <i class="parameter"><tt>pos</tt></i> can take one of the
+following values:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ POS_LEFT
+ POS_RIGHT
+ POS_TOP
+ POS_BOTTOM
+</pre></td></tr></table><p>If you position the value on the "side" of the trough (e.g.,
+on the top or bottom of a horizontal scale widget), then it will follow the
+slider up and down the trough.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch-RangeWidgets.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-RangeWidgets.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-CommonRangeMethods.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 8. Range Widgets </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 8.3. Common Range Methods</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-ScrolledWindows.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-ScrolledWindows.html
new file mode 100644
index 0000000..e38aa36
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-ScrolledWindows.html
@@ -0,0 +1,104 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>10.9. Scrolled Windows</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-ContainerWidgets.html" title="Chapter 10. Container Widgets"><link rel="previous" href="sec-Viewports.html" title="10.8. Viewports"><link rel="next" href="sec-ButtonBoxes.html" title="10.10. Button Boxes"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">10.9. Scrolled Windows</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-Viewports.html">Prev</a> </td><th width="60%" align="center">Chapter 10. Container Widgets</th><td width="20%" align="right"> <a accesskey="n" href="sec-ButtonBoxes.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-ScrolledWindows"></a>10.9. Scrolled Windows</h2></div></div><div></div></div><p>Scrolled windows are used to create a scrollable area with
+another widget inside it. You may insert any type of widget into a scrolled
+window, and it will be accessible regardless of the size by using the
+scrollbars.</p><p>The following function is used to create a new scrolled
+window.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ scrolled_window = gtk.ScrolledWindow(<b class="parameter"><tt>hadjustment</tt></b>=None, <b class="parameter"><tt>vadjustment</tt></b>=None)
+</pre></td></tr></table><p>Where the first argument is the adjustment for the horizontal
+direction, and the second, the adjustment for the vertical direction. These
+are almost always set to <tt class="literal">None</tt> or not specified.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ scrolled_window.set_policy(<b class="parameter"><tt>hscrollbar_policy</tt></b>, <b class="parameter"><tt>vscrollbar_policy</tt></b>)
+</pre></td></tr></table><p>This method sets the policy to be used with respect to the
+scrollbars. The first argument sets the policy for the horizontal scrollbar,
+and the second, the policy for the vertical scrollbar.</p><p>The policy may be one of <tt class="literal">POLICY_AUTOMATIC</tt> or
+<tt class="literal">POLICY_ALWAYS</tt>. <tt class="literal">POLICY_AUTOMATIC</tt> will
+automatically decide whether you need scrollbars, whereas
+<tt class="literal">POLICY_ALWAYS</tt> will always leave the scrollbars
+there.</p><p>You can then place your object into the scrolled window using
+the following method.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ scrolled_window.add_with_viewport(<b class="parameter"><tt>child</tt></b>)
+</pre></td></tr></table><p>The <a href="examples/scrolledwin.py" target="_top"><span><b class="command">scrolledwin.py</b></span></a>
+example program packs a table with 100 toggle buttons into a scrolled
+window. I've only commented on the parts that may be new to you.
+<a href="sec-ScrolledWindows.html#scrolledwin" title="Figure 10.7. Scrolled Window Example">Figure 10.7, “Scrolled Window Exampleâ€</a> illustrates the program display:</p><div class="figure"><a name="scrolledwin"></a><p class="title"><b>Figure 10.7. Scrolled Window Example</b></p><div class="mediaobject" align="center"><img src="figures/scrolledwin.png" align="middle" alt="Scrolled Window Example"></div></div><p>The source code for the <a href="examples/scrolledwin.py" target="_top"><span><b class="command">scrolledwin.py</b></span></a>
+program is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 1 #!/usr/bin/env python
+ 2
+ 3 # example scrolledwin.py
+ 4
+ 5 import pygtk
+ 6 pygtk.require('2.0')
+ 7 import gtk
+ 8
+ 9 class ScrolledWindowExample:
+ 10 def destroy(self, widget):
+ 11 gtk.main_quit()
+ 12
+ 13 def __init__(self):
+ 14 # Create a new dialog window for the scrolled window to be
+ 15 # packed into.
+ 16 window = gtk.Dialog()
+ 17 window.connect("destroy", self.destroy)
+ 18 window.set_title("ScrolledWindow example")
+ 19 window.set_border_width(0)
+ 20 window.set_size_request(300, 300)
+ 21
+ 22 # create a new scrolled window.
+ 23 scrolled_window = gtk.ScrolledWindow()
+ 24 scrolled_window.set_border_width(10)
+ 25
+ 26 # the policy is one of POLICY AUTOMATIC, or POLICY_ALWAYS.
+ 27 # POLICY_AUTOMATIC will automatically decide whether you need
+ 28 # scrollbars, whereas POLICY_ALWAYS will always leave the scrollbars
+ 29 # there. The first one is the horizontal scrollbar, the second, the
+ 30 # vertical.
+ 31 scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
+ 32
+ 33 # The dialog window is created with a vbox packed into it.
+ 34 window.vbox.pack_start(scrolled_window, True, True, 0)
+ 35 scrolled_window.show()
+ 36
+ 37 # create a table of 10 by 10 squares.
+ 38 table = gtk.Table(10, 10, False)
+ 39
+ 40 # set the spacing to 10 on x and 10 on y
+ 41 table.set_row_spacings(10)
+ 42 table.set_col_spacings(10)
+ 43
+ 44 # pack the table into the scrolled window
+ 45 scrolled_window.add_with_viewport(table)
+ 46 table.show()
+ 47
+ 48 # this simply creates a grid of toggle buttons on the table
+ 49 # to demonstrate the scrolled window.
+ 50 for i in range(10):
+ 51 for j in range(10):
+ 52 buffer = "button (%d,%d)" % (i, j)
+ 53 button = gtk.ToggleButton(buffer)
+ 54 table.attach(button, i, i+1, j, j+1)
+ 55 button.show()
+ 56
+ 57 # Add a "close" button to the bottom of the dialog
+ 58 button = gtk.Button("close")
+ 59 button.connect_object("clicked", self.destroy, window)
+ 60
+ 61 # this makes it so the button is the default.
+ 62 button.set_flags(gtk.CAN_DEFAULT)
+ 63 window.action_area.pack_start( button, True, True, 0)
+ 64
+ 65 # This grabs this button to be the default button. Simply hitting
+ 66 # the "Enter" key will cause this button to activate.
+ 67 button.grab_default()
+ 68 button.show()
+ 69 window.show()
+ 70
+ 71 def main():
+ 72 gtk.main()
+ 73 return 0
+ 74
+ 75 if __name__ == "__main__":
+ 76 ScrolledWindowExample()
+ 77 main()
+</pre></td></tr></table><p>Try resizing the window. You'll notice how the scrollbars react.
+You may also wish to use the <tt class="methodname">set_size_request</tt>()
+method to set the default size of the window or other widgets.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-Viewports.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-ContainerWidgets.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-ButtonBoxes.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">10.8. Viewports </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 10.10. Button Boxes</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-SignalEmissionAndPropagation.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-SignalEmissionAndPropagation.html
new file mode 100644
index 0000000..9e8b941
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-SignalEmissionAndPropagation.html
@@ -0,0 +1,16 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>20.2. Signal Emission and Propagation</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-AdvancedEventAndSignalHandling.html" title="Chapter 20. Advanced Event and Signal Handling"><link rel="previous" href="ch-AdvancedEventAndSignalHandling.html" title="Chapter 20. Advanced Event and Signal Handling"><link rel="next" href="ch-ManagingSelections.html" title="Chapter 21. Managing Selections"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">20.2. Signal Emission and Propagation</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch-AdvancedEventAndSignalHandling.html">Prev</a> </td><th width="60%" align="center">Chapter 20. Advanced Event and Signal Handling</th><td width="20%" align="right"> <a accesskey="n" href="ch-ManagingSelections.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-SignalEmissionAndPropagation"></a>20.2. Signal Emission and Propagation</h2></div></div><div></div></div><p>Signal emission is the process whereby GTK+ runs all handlers for
+a specific object and signal.</p><p>First, note that the return value from a signal emission is the
+return value of the last handler executed. Since event signals are all of
+type <tt class="literal">RUN_LAST</tt>, this will be the default (GTK+ supplied)
+handler, unless you connect with the
+<tt class="methodname">connect_after</tt>() method.</p><p>The way an event (say "button_press_event") is handled,
+is:</p><div class="itemizedlist"><ul type="disc"><li><p>Start with the widget where the event occurred.</p></li><li><p>Emit the generic "event" signal. If that signal handler
+returns a value of <tt class="literal">TRUE</tt>, stop all processing.</p></li><li><p>Otherwise, emit a specific, "button_press_event" signal. If
+that returns <tt class="literal">TRUE</tt>, stop all processing.</p></li><li><p>Otherwise, go to the widget's parent, and repeat the above
+two steps.</p></li><li><p>Continue until some signal handler returns
+<tt class="literal">TRUE</tt>, or until the top-level widget is reached.</p></li></ul></div><p>Some consequences of the above are:</p><div class="itemizedlist"><ul type="disc"><li><p>Your handler's return value will have no effect if there is
+a default handler, unless you connect with
+<tt class="methodname">connect_after</tt>().</p></li><li><p>To prevent the default handler from being run, you need to
+connect with <tt class="methodname">connect</tt>() and use
+<tt class="methodname">emit_stop_by_name</tt>() - the return value only affects
+whether the signal is propagated, not the current emission.</p></li></ul></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch-AdvancedEventAndSignalHandling.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-AdvancedEventAndSignalHandling.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch-ManagingSelections.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 20. Advanced Event and Signal Handling </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 21. Managing Selections</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-SpinButtons.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-SpinButtons.html
new file mode 100644
index 0000000..61a2693
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-SpinButtons.html
@@ -0,0 +1,290 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>9.10. Spin Buttons</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-MiscellaneousWidgets.html" title="Chapter 9. Miscellaneous Widgets"><link rel="previous" href="sec-TextEntries.html" title="9.9. Text Entries"><link rel="next" href="sec-ComboWidget.html" title="9.11. Combo Widget"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">9.10. Spin Buttons</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-TextEntries.html">Prev</a> </td><th width="60%" align="center">Chapter 9. Miscellaneous Widgets</th><td width="20%" align="right"> <a accesskey="n" href="sec-ComboWidget.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-SpinButtons"></a>9.10. Spin Buttons</h2></div></div><div></div></div><p>The <tt class="classname">SpinButton</tt> widget is generally used
+to allow the user to select a value from a range of numeric values. It
+consists of a text entry box with up and down arrow buttons attached to the
+side. Selecting one of the buttons causes the value to "spin" up and down
+the range of possible values. The entry box may also be edited directly to
+enter a specific value.</p><p>The <tt class="classname">SpinButton</tt> allows the value to have
+zero or more decimal places and to be incremented/decremented in
+configurable steps. The action of holding down one of the buttons optionally
+results in an acceleration of change in the value according to how long it
+is depressed.</p><p>The <tt class="classname">SpinButton</tt> uses an
+<tt class="classname">Adjustment</tt> (see <a href="ch-Adjustments.html" title="Chapter 7. Adjustments">Chapter 7, <i>Adjustments</i></a>) object to hold information about the range
+of values that the spin button can take. This makes for a powerful
+<tt class="classname">SpinButton</tt> widget.</p><p>Recall that an <tt class="classname">Adjustment</tt> widget is
+created with the following function, which illustrates the information that
+it holds:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ adjustment = gtk.Adjustment(<b class="parameter"><tt>value</tt></b>=0, <b class="parameter"><tt>lower</tt></b>=0, <b class="parameter"><tt>upper</tt></b>=0, <b class="parameter"><tt>step_incr</tt></b>=0, <b class="parameter"><tt>page_incr</tt></b>=0, <b class="parameter"><tt>page_size</tt></b>=0)
+</pre></td></tr></table><p>These attributes of an <tt class="classname">Adjustment</tt> are
+used by the <tt class="classname">SpinButton</tt> in the following way:</p><div class="informaltable"><table width="100%" border="1"><colgroup><col><col></colgroup><tbody><tr><td><i class="parameter"><tt>value</tt></i></td><td>initial value for the Spin Button</td></tr><tr><td><i class="parameter"><tt>lower</tt></i></td><td>lower range value</td></tr><tr><td><i class="parameter"><tt>upper</tt></i></td><td><i class="parameter"><tt>upper</tt></i> range value</td></tr><tr><td><i class="parameter"><tt>step_increment</tt></i></td><td>value to increment/decrement when pressing mouse
+<span class="mousebutton">button-1</span> on a button</td></tr><tr><td><i class="parameter"><tt>page_increment</tt></i></td><td>value to increment/decrement when pressing mouse
+<span class="mousebutton">button-2</span> on a button</td></tr><tr><td><i class="parameter"><tt>page_size</tt></i></td><td>unused</td></tr></tbody></table></div><p>Additionally, mouse <span class="mousebutton">button-3</span> can be
+used to jump directly to the <i class="parameter"><tt>upper</tt></i> or
+<i class="parameter"><tt>lower</tt></i> values when used to select one of the
+buttons. Lets look at how to create a
+<tt class="classname">SpinButton</tt>:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ spin_button = gtk.SpinButton(<b class="parameter"><tt>adjustment</tt></b>=None, <b class="parameter"><tt>climb_rate</tt></b>=0.0, <b class="parameter"><tt>digits</tt></b>=0)
+</pre></td></tr></table><p>The <i class="parameter"><tt>climb_rate</tt></i> argument take a value
+between 0.0 and 1.0 and indicates the amount of acceleration that the
+<tt class="classname">SpinButton</tt> has. The <i class="parameter"><tt>digits</tt></i>
+argument specifies the number of decimal places to which the value will be
+displayed.</p><p>A <tt class="classname">SpinButton</tt> can be reconfigured after
+creation using the following method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ spin_button.configure(<b class="parameter"><tt>adjustment</tt></b>, <b class="parameter"><tt>climb_rate</tt></b>, <b class="parameter"><tt>digits</tt></b>)
+</pre></td></tr></table><p>The <i class="parameter"><tt>spin_button</tt></i> argument specifies the
+<tt class="classname">SpinButton</tt> widget that is to be reconfigured. The
+other arguments are as specified above.</p><p>The <i class="parameter"><tt>adjustment</tt></i> can be set and retrieved
+independently using the following two methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ spin_button.set_adjustment(<b class="parameter"><tt>adjustment</tt></b>)
+
+ adjustment = spin_button.get_adjustment()
+</pre></td></tr></table><p>The number of decimal places can also be altered using:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ spin_button.set_digits(<b class="parameter"><tt>digits</tt></b>)
+</pre></td></tr></table><p>The value that a <tt class="classname">SpinButton</tt> is currently
+displaying can be changed using the following method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ spin_button.set_value(<b class="parameter"><tt>value</tt></b>)
+</pre></td></tr></table><p>The current value of a <tt class="classname">SpinButton</tt> can be
+retrieved as either a floating point or integer value with the following
+methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ float_value = spin_button.get_value()
+
+ int_value = spin_button.get_value_as_int()
+</pre></td></tr></table><p>If you want to alter the value of a
+<tt class="classname">SpinButton</tt> relative to its current value, then the
+following method can be used:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ spin_button.spin(<b class="parameter"><tt>direction</tt></b>, <b class="parameter"><tt>increment</tt></b>)
+</pre></td></tr></table><p>The <i class="parameter"><tt>direction</tt></i> parameter can take one of
+the following values:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ SPIN_STEP_FORWARD
+ SPIN_STEP_BACKWARD
+ SPIN_PAGE_FORWARD
+ SPIN_PAGE_BACKWARD
+ SPIN_HOME
+ SPIN_END
+ SPIN_USER_DEFINED
+</pre></td></tr></table><p>This method packs in quite a bit of functionality, which I will
+attempt to clearly explain. Many of these settings use values from the
+<tt class="classname">Adjustment</tt> object that is associated with a
+<tt class="classname">SpinButton</tt>.</p><p><tt class="literal">SPIN_STEP_FORWARD</tt> and
+<tt class="literal">SPIN_STEP_BACKWARD</tt> change the value of the
+<tt class="classname">SpinButton</tt> by the amount specified by
+<i class="parameter"><tt>increment</tt></i>, unless <i class="parameter"><tt>increment</tt></i> is
+equal to 0, in which case the value is changed by the value of
+<i class="parameter"><tt>step_increment</tt></i> in the
+<tt class="classname">Adjustment</tt>.</p><p><tt class="literal">SPIN_PAGE_FORWARD</tt> and
+<tt class="literal">SPIN_PAGE_BACKWARD</tt> simply alter the value of the
+<tt class="classname">SpinButton</tt> by
+<i class="parameter"><tt>increment</tt></i>.</p><p><tt class="literal">SPIN_HOME</tt> sets the value of the
+<tt class="classname">SpinButton</tt> to the bottom of the
+<tt class="classname">Adjustment</tt> range.</p><p><tt class="literal">SPIN_END</tt> sets the value of the
+<tt class="classname">SpinButton</tt> to the top of the
+<tt class="classname">Adjustment</tt> range.</p><p><tt class="literal">SPIN_USER_DEFINED</tt> simply alters the value of
+the <tt class="classname">SpinButton</tt> by the specified amount.</p><p>We move away from methods for setting and retrieving the range
+attributes of the <tt class="classname">SpinButton</tt> now, and move onto
+methods that effect the appearance and behavior of the
+<tt class="classname">SpinButton</tt> widget itself.</p><p>The first of these methods is used to constrain the text box of
+the <tt class="classname">SpinButton</tt> such that it may only contain a
+numeric value. This prevents a user from typing anything other than numeric
+values into the text box of a <tt class="classname">SpinButton</tt>:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ spin_button.set_numeric(<b class="parameter"><tt>numeric</tt></b>)
+</pre></td></tr></table><p><i class="parameter"><tt>numeric</tt></i> is <tt class="literal">TRUE</tt> to
+constrain the text entry to numeric values or <tt class="literal">FALSE</tt> to
+unconstrain the text entry.</p><p>You can set whether a <tt class="classname">SpinButton</tt> will
+wrap around between the upper and lower range values with the following
+method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ spin_button.set_wrap(<b class="parameter"><tt>wrap</tt></b>)
+</pre></td></tr></table><p>The <tt class="classname">SpinButton</tt> will wrap when
+<i class="parameter"><tt>wrap</tt></i> is set to <tt class="literal">TRUE</tt>.</p><p>You can set a <tt class="classname">SpinButton</tt> to round the
+value to the nearest <i class="parameter"><tt>step_increment</tt></i>, which is set
+within the <tt class="classname">Adjustment</tt> object used with the
+<tt class="classname">SpinButton</tt>. This is accomplished with the following
+method when <i class="parameter"><tt>snap_to_ticks</tt></i> is
+<tt class="literal">TRUE</tt>:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ spin_button.set_snap_to_ticks(<b class="parameter"><tt>snap_to_ticks</tt></b>)
+</pre></td></tr></table><p>The update policy of a <tt class="classname">SpinButton</tt> can be
+changed with the following method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ spin_button.set_update_policy(<b class="parameter"><tt>policy</tt></b>)
+</pre></td></tr></table><p>The possible values of policy are:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ UPDATE_ALWAYS
+
+ UPDATE_IF_VALID
+</pre></td></tr></table><p>These policies affect the behavior of a
+<tt class="classname">SpinButton</tt> when parsing inserted text and syncing its
+value with the values of the <tt class="classname">Adjustment</tt>.</p><p>In the case of <tt class="literal">UPDATE_IF_VALID</tt> the
+<tt class="classname">SpinButton</tt> value only gets changed if the text input
+is a numeric value that is within the range specified by the
+<tt class="classname">Adjustment</tt>. Otherwise the text is reset to the
+current value.</p><p>In case of <tt class="literal">UPDATE_ALWAYS</tt> we ignore errors while
+converting text into a numeric value.</p><p>Finally, you can explicitly request that a
+<tt class="classname">SpinButton</tt> update itself:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ spin_button.update()
+</pre></td></tr></table><p>The <a href="examples/spinbutton.py" target="_top"><span><b class="command">spinbutton.py</b></span></a>
+example program illustrates the use of spinbuttons including setting a
+number of characteristics.
+<a href="sec-SpinButtons.html#spingbuttonfig" title="Figure 9.11. Spin Button Example">Figure 9.11, “Spin Button Exampleâ€</a> shows the result of running the example
+program:</p><div class="figure"><a name="spingbuttonfig"></a><p class="title"><b>Figure 9.11. Spin Button Example</b></p><div class="mediaobject" align="center"><img src="figures/spinbutton.png" align="middle" alt="Spin Button Example"></div></div><p>The <a href="examples/spinbutton.py" target="_top"><span><b class="command">spinbutton.py</b></span></a> source
+code is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 1 #!/usr/bin/env python
+ 2
+ 3 # example spinbutton.py
+ 4
+ 5 import pygtk
+ 6 pygtk.require('2.0')
+ 7 import gtk
+ 8
+ 9 class SpinButtonExample:
+ 10 def toggle_snap(self, widget, spin):
+ 11 spin.set_snap_to_ticks(widget.get_active())
+ 12
+ 13 def toggle_numeric(self, widget, spin):
+ 14 spin.set_numeric(widget.get_active())
+ 15
+ 16 def change_digits(self, widget, spin, spin1):
+ 17 spin1.set_digits(spin.get_value_as_int())
+ 18
+ 19 def get_value(self, widget, data, spin, spin2, label):
+ 20 if data == 1:
+ 21 buf = "%d" % spin.get_value_as_int()
+ 22 else:
+ 23 buf = "%0.*f" % (spin2.get_value_as_int(),
+ 24 spin.get_value())
+ 25 label.set_text(buf)
+ 26
+ 27 def __init__(self):
+ 28 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ 29 window.connect("destroy", lambda w: gtk.main_quit())
+ 30 window.set_title("Spin Button")
+ 31
+ 32 main_vbox = gtk.VBox(False, 5)
+ 33 main_vbox.set_border_width(10)
+ 34 window.add(main_vbox)
+ 35
+ 36 frame = gtk.Frame("Not accelerated")
+ 37 main_vbox.pack_start(frame, True, True, 0)
+ 38
+ 39 vbox = gtk.VBox(False, 0)
+ 40 vbox.set_border_width(5)
+ 41 frame.add(vbox)
+ 42
+ 43 # Day, month, year spinners
+ 44 hbox = gtk.HBox(False, 0)
+ 45 vbox.pack_start(hbox, True, True, 5)
+ 46
+ 47 vbox2 = gtk.VBox(False, 0)
+ 48 hbox.pack_start(vbox2, True, True, 5)
+ 49
+ 50 label = gtk.Label("Day :")
+ 51 label.set_alignment(0, 0.5)
+ 52 vbox2.pack_start(label, False, True, 0)
+ 53
+ 54 adj = gtk.Adjustment(1.0, 1.0, 31.0, 1.0, 5.0, 0.0)
+ 55 spinner = gtk.SpinButton(adj, 0, 0)
+ 56 spinner.set_wrap(True)
+ 57 vbox2.pack_start(spinner, False, True, 0)
+ 58
+ 59 vbox2 = gtk.VBox(False, 0)
+ 60 hbox.pack_start(vbox2, True, True, 5)
+ 61
+ 62 label = gtk.Label("Month :")
+ 63 label.set_alignment(0, 0.5)
+ 64 vbox2.pack_start(label, False, True, 0)
+ 65
+ 66 adj = gtk.Adjustment(1.0, 1.0, 12.0, 1.0, 5.0, 0.0)
+ 67 spinner = gtk.SpinButton(adj, 0, 0)
+ 68 spinner.set_wrap(True)
+ 69 vbox2.pack_start(spinner, False, True, 0)
+ 70
+ 71 vbox2 = gtk.VBox(False, 0)
+ 72 hbox.pack_start(vbox2, True, True, 5)
+ 73
+ 74 label = gtk.Label("Year :")
+ 75 label.set_alignment(0, 0.5)
+ 76 vbox2.pack_start(label, False, True, 0)
+ 77
+ 78 adj = gtk.Adjustment(1998.0, 0.0, 2100.0, 1.0, 100.0, 0.0)
+ 79 spinner = gtk.SpinButton(adj, 0, 0)
+ 80 spinner.set_wrap(False)
+ 81 spinner.set_size_request(55, -1)
+ 82 vbox2.pack_start(spinner, False, True, 0)
+ 83
+ 84 frame = gtk.Frame("Accelerated")
+ 85 main_vbox.pack_start(frame, True, True, 0)
+ 86
+ 87 vbox = gtk.VBox(False, 0)
+ 88 vbox.set_border_width(5)
+ 89 frame.add(vbox)
+ 90
+ 91 hbox = gtk.HBox(False, 0)
+ 92 vbox.pack_start(hbox, False, True, 5)
+ 93
+ 94 vbox2 = gtk.VBox(False, 0)
+ 95 hbox.pack_start(vbox2, True, True, 5)
+ 96
+ 97 label = gtk.Label("Value :")
+ 98 label.set_alignment(0, 0.5)
+ 99 vbox2.pack_start(label, False, True, 0)
+ 100
+ 101 adj = gtk.Adjustment(0.0, -10000.0, 10000.0, 0.5, 100.0, 0.0)
+ 102 spinner1 = gtk.SpinButton(adj, 1.0, 2)
+ 103 spinner1.set_wrap(True)
+ 104 spinner1.set_size_request(100, -1)
+ 105 vbox2.pack_start(spinner1, False, True, 0)
+ 106
+ 107 vbox2 = gtk.VBox(False, 0)
+ 108 hbox.pack_start(vbox2, True, True, 5)
+ 109
+ 110 label = gtk.Label("Digits :")
+ 111 label.set_alignment(0, 0.5)
+ 112 vbox2.pack_start(label, False, True, 0)
+ 113
+ 114 adj = gtk.Adjustment(2, 1, 5, 1, 1, 0)
+ 115 spinner2 = gtk.SpinButton(adj, 0.0, 0)
+ 116 spinner2.set_wrap(True)
+ 117 adj.connect("value_changed", self.change_digits, spinner2, spinner1)
+ 118 vbox2.pack_start(spinner2, False, True, 0)
+ 119
+ 120 hbox = gtk.HBox(False, 0)
+ 121 vbox.pack_start(hbox, False, True, 5)
+ 122
+ 123 button = gtk.CheckButton("Snap to 0.5-ticks")
+ 124 button.connect("clicked", self.toggle_snap, spinner1)
+ 125 vbox.pack_start(button, True, True, 0)
+ 126 button.set_active(True)
+ 127
+ 128 button = gtk.CheckButton("Numeric only input mode")
+ 129 button.connect("clicked", self.toggle_numeric, spinner1)
+ 130 vbox.pack_start(button, True, True, 0)
+ 131 button.set_active(True)
+ 132
+ 133 val_label = gtk.Label("")
+ 134
+ 135 hbox = gtk.HBox(False, 0)
+ 136 vbox.pack_start(hbox, False, True, 5)
+ 137 button = gtk.Button("Value as Int")
+ 138 button.connect("clicked", self.get_value, 1, spinner1, spinner2,
+ 139 val_label)
+ 140 hbox.pack_start(button, True, True, 5)
+ 141
+ 142 button = gtk.Button("Value as Float")
+ 143 button.connect("clicked", self.get_value, 2, spinner1, spinner2,
+ 144 val_label)
+ 145 hbox.pack_start(button, True, True, 5)
+ 146
+ 147 vbox.pack_start(val_label, True, True, 0)
+ 148 val_label.set_text("0")
+ 149
+ 150 hbox = gtk.HBox(False, 0)
+ 151 main_vbox.pack_start(hbox, False, True, 0)
+ 152
+ 153 button = gtk.Button("Close")
+ 154 button.connect("clicked", lambda w: gtk.main_quit())
+ 155 hbox.pack_start(button, True, True, 5)
+ 156 window.show_all()
+ 157
+ 158 def main():
+ 159 gtk.main()
+ 160 return 0
+ 161
+ 162 if __name__ == "__main__":
+ 163 SpinButtonExample()
+ 164 main()
+</pre></td></tr></table></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-TextEntries.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-MiscellaneousWidgets.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-ComboWidget.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">9.9. Text Entries </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 9.11. Combo Widget</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-Statusbars.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-Statusbars.html
new file mode 100644
index 0000000..bde89ee
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-Statusbars.html
@@ -0,0 +1,90 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>9.8. Statusbars</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-MiscellaneousWidgets.html" title="Chapter 9. Miscellaneous Widgets"><link rel="previous" href="sec-Rulers.html" title="9.7. Rulers"><link rel="next" href="sec-TextEntries.html" title="9.9. Text Entries"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">9.8. Statusbars</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-Rulers.html">Prev</a> </td><th width="60%" align="center">Chapter 9. Miscellaneous Widgets</th><td width="20%" align="right"> <a accesskey="n" href="sec-TextEntries.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-Statusbars"></a>9.8. Statusbars</h2></div></div><div></div></div><p><tt class="classname">Statusbars</tt> are simple widgets used to
+display a text message. They keep a stack of the messages pushed onto them,
+so that popping the current message will re-display the previous text
+message.</p><p>In order to allow different parts of an application to use the
+same statusbar to display messages, the statusbar widget issues Context
+Identifiers which are used to identify different "users". The message on top
+of the stack is the one displayed, no matter what context it is in. Messages
+are stacked in last-in-first-out order, not context identifier order.</p><p>A statusbar is created with a call to:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ statusbar = gtk.Statusbar()
+</pre></td></tr></table><p>A new Context Identifier is requested using a call to the following
+method with a short textual description of the context:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ context_id = statusbar.get_context_id(<b class="parameter"><tt>context_description</tt></b>)
+</pre></td></tr></table><p>There are three additional methods that operate on
+statusbars:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ message_id = statusbar.push(<b class="parameter"><tt>context_id</tt></b>, <b class="parameter"><tt>text</tt></b>)
+
+ statusbar.pop(<b class="parameter"><tt>context_id</tt></b>)
+
+ statusbar.remove(<b class="parameter"><tt>context_id</tt></b>, <b class="parameter"><tt>message_id</tt></b>)
+</pre></td></tr></table><p>The first, <tt class="methodname">push</tt>(), is used to add a new
+message to the <i class="parameter"><tt>statusbar</tt></i>. It returns a
+<i class="parameter"><tt>message_id</tt></i>, which can be passed later to the
+<tt class="methodname">remove</tt>() method to remove the message with the
+combination <i class="parameter"><tt>message_id</tt></i> and
+<i class="parameter"><tt>context_id</tt></i> from the
+<i class="parameter"><tt>statusbar</tt></i>'s stack.</p><p>The <tt class="methodname">pop</tt>() method removes the message
+highest in the stack with the given
+<i class="parameter"><tt>context_id</tt></i>.</p><p>The <a href="examples/statusbar.py" target="_top"><span><b class="command">statusbar.py</b></span></a> example
+program creates a statusbar and two buttons, one for pushing items onto the
+statusbar, and one for popping the last item back off.
+<a href="sec-Statusbars.html#statusbarfig" title="Figure 9.9. Statusbar Example">Figure 9.9, “Statusbar Exampleâ€</a> illustrates the result:</p><div class="figure"><a name="statusbarfig"></a><p class="title"><b>Figure 9.9. Statusbar Example</b></p><div class="mediaobject" align="center"><img src="figures/statusbar.png" align="middle" alt="Statusbar Example"></div></div><p>The statusbar.py source code is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 1 #!/usr/bin/env python
+ 2
+ 3 # example statusbar.py
+ 4
+ 5 import pygtk
+ 6 pygtk.require('2.0')
+ 7 import gtk
+ 8
+ 9 class StatusbarExample:
+ 10 def push_item(self, widget, data):
+ 11 buff = " Item %d" % self.count
+ 12 self.count = self.count + 1
+ 13 self.status_bar.push(data, buff)
+ 14 return
+ 15
+ 16 def pop_item(self, widget, data):
+ 17 self.status_bar.pop(data)
+ 18 return
+ 19
+ 20 def __init__(self):
+ 21 self.count = 1
+ 22 # create a new window
+ 23 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ 24 window.set_size_request(200, 100)
+ 25 window.set_title("PyGTK Statusbar Example")
+ 26 window.connect("delete_event", lambda w,e: gtk.main_quit())
+ 27
+ 28 vbox = gtk.VBox(False, 1)
+ 29 window.add(vbox)
+ 30 vbox.show()
+ 31
+ 32 self.status_bar = gtk.Statusbar()
+ 33 vbox.pack_start(self.status_bar, True, True, 0)
+ 34 self.status_bar.show()
+ 35
+ 36 context_id = self.status_bar.get_context_id("Statusbar example")
+ 37
+ 38 button = gtk.Button("push item")
+ 39 button.connect("clicked", self.push_item, context_id)
+ 40 vbox.pack_start(button, True, True, 2)
+ 41 button.show()
+ 42
+ 43 button = gtk.Button("pop last item")
+ 44 button.connect("clicked", self.pop_item, context_id)
+ 45 vbox.pack_start(button, True, True, 2)
+ 46 button.show()
+ 47
+ 48 # always display the window as the last step so it all splashes on
+ 49 # the screen at once.
+ 50 window.show()
+ 51
+ 52 def main():
+ 53 gtk.main()
+ 54 return 0
+ 55
+ 56 if __name__ == "__main__":
+ 57 StatusbarExample()
+ 58 main()
+</pre></td></tr></table></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-Rulers.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-MiscellaneousWidgets.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-TextEntries.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">9.7. Rulers </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 9.9. Text Entries</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-SteppingThroughHelloWorld.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-SteppingThroughHelloWorld.html
new file mode 100644
index 0000000..412b963
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-SteppingThroughHelloWorld.html
@@ -0,0 +1,140 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>2.4. Stepping Through Hello World</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-GettingStarted.html" title="Chapter 2. Getting Started"><link rel="previous" href="sec-Events.html" title="2.3. Events"><link rel="next" href="ch-MovingOn.html" title="Chapter 3. Moving On"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2.4. Stepping Through Hello World</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-Events.html">Prev</a> </td><th width="60%" align="center">Chapter 2. Getting Started</th><td width="20%" align="right"> <a accesskey="n" href="ch-MovingOn.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-SteppingThroughHelloWorld"></a>2.4. Stepping Through Hello World</h2></div></div><div></div></div><p>Now that we know the theory behind this, let's clarify by
+walking through the example <a href="examples/helloworld.py" target="_top"><span><b class="command">helloworld.py</b></span></a>
+program.</p><p>Lines 9-76 define the <tt class="classname">HelloWorld</tt> class
+that contains all the callbacks as object methods and the object instance
+initialization method. Let's examine the callback methods.</p><p>Lines 13-14 define the <tt class="methodname">hello</tt>() callback
+method that will be called when the button is "clicked". When called the
+method, prints "Hello World" to the console. We ignore the object instance,
+the widget and the data parameters in this example, but most callbacks use
+them. The <i class="parameter"><tt>data</tt></i> is defined with a default value of
+<tt class="varname">None</tt> because PyGTK will not pass a data value if it is
+not included in the <tt class="methodname">connect</tt>() call; this would
+trigger an error since the callback is expecting three parameters and may
+receive only two. Defining a default value of None allows the callback to be
+called with two or three parameters without error. In this case the data
+parameter could have been left out since the
+<tt class="methodname">hello</tt>() method will always be called with just two
+parameters (never called with user data). The next example will use the
+<i class="parameter"><tt>data argument</tt></i> to tell us which button was
+pressed.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def hello(self, widget, data=None):
+ print "Hello World"
+</pre></td></tr></table><p>The next callback (lines 16-26) is a bit special. The
+"delete_event" occurs when the window manager sends this event to the
+application. We have a choice here as to what to do about these events. We
+can ignore them, make some sort of response, or simply quit the
+application.</p><p>The value you return in this callback lets GTK+ know what action
+to take. By returning TRUE, we let it know that we don't want to have the
+"destroy" signal emitted, keeping our application running. By returning
+FALSE, we ask that "destroy" be emitted, which in turn will call our
+"destroy" signal handler. Note the comments have been removed for
+clarity.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def delete_event(widget, event, data=None):
+ print "delete event occurred"
+ return False
+</pre></td></tr></table><p>The <tt class="methodname">destroy</tt>() callback method (lines
+28-30) causes the program to quit by calling
+<tt class="function">gtk.main_quit</tt>() . This function tells GTK+ that it is
+to exit from <tt class="function">gtk.main</tt>() when control is returned to
+it.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def destroy(widget, data=None):
+ print "destroy signal occurred"
+ gtk.main_quit()
+</pre></td></tr></table><p>Lines 32-71 define the <tt class="classname">HelloWorld</tt> object
+instance initialization method <tt class="methodname">__init__</tt>() that creates
+the window and widgets used by the program.</p><p>Line 34 creates a new window, but it is not displayed until we
+direct GTK+ to show the window near the end of our program. The window
+reference is saved in an object instance attribute (self.window) for later
+access.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+</pre></td></tr></table><p>Lines 41 and 46 illustrate two examples of connecting a signal
+handler to an object, in this case, the <tt class="varname">window</tt>. Here, the
+"delete_event" and "destroy" signals are caught. The first is emitted when
+we use the window manager to kill the window, or when we use the
+<tt class="classname">GtkWidget</tt> <tt class="methodname">destroy</tt>() method
+call. The second is emitted when, in the "delete_event" handler, we return
+<tt class="varname">FALSE</tt>.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ self.window.connect("delete_event", self.delete_event)
+ self.window.connect("destroy", self.destroy)
+</pre></td></tr></table><p>Line 49 sets an attribute of a container object (in this case
+the <tt class="varname">window</tt>) to have a blank area along the inside of it
+10 pixels wide where no widgets will be placed. There are other similar
+methods that we will look at in <a href="ch-SettingWidgetAttributes.html" title="Chapter 18. Setting Widget Attributes">Chapter 18, <i>Setting Widget Attributes</i></a></p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ self.window.set_border_width(10)
+</pre></td></tr></table><p>Line 52 creates a new button and saves a reference to it in
+<tt class="varname">self.button</tt>. The button will have the label "Hello World"
+when displayed.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ self.button = gtk.Button("Hello World")
+</pre></td></tr></table><p>In line 57 we attach a signal handler to the button so when it
+emits the "clicked" signal, our <tt class="methodname">hello</tt>() callback
+method is called. We are not passing any data to
+<tt class="methodname">hello</tt>() so we just pass <tt class="varname">None</tt> as
+the data. Obviously, the "clicked" signal is emitted when we click the
+button with our mouse pointer. The user data parameter value
+<tt class="varname">None</tt> is not required and could be removed. The callback
+would then be called with one less parameter.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ self.button.connect("clicked", self.hello, None)
+</pre></td></tr></table><p>We are also going to use this button to exit our program. Line
+62 illustrates how the "destroy" signal may come from either the window
+manager, or from our program. When the button is "clicked", same as above,
+it calls the <tt class="methodname">hello</tt>() callback first, and then the
+following one in the order they are set up. You may have as many callbacks
+as you need, and all will be executed in the order you connected
+them.</p><p>Since we want to use the <tt class="classname">GtkWidget</tt>
+<tt class="methodname">destroy</tt>() method that accepts one argument (the
+widget to be destroyed - in this case the <tt class="varname">window</tt>), we use
+the <tt class="methodname">connect_object</tt>() method and pass it the
+reference to the window. The <tt class="methodname">connect_object</tt>()
+method arranges to pass the <i class="parameter"><tt>window</tt></i> as the first
+callback argument instead of the button.</p><p>When the <tt class="classname">gtk.Widget</tt>
+<tt class="methodname">destroy</tt>() method is called it will cause the
+"destroy" signal to be emitted from the window which will in turn cause the
+<tt class="classname">HelloWorld</tt> <tt class="methodname">destroy</tt>() method
+to be called to end the program.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ self.button.connect_object("clicked", gtk.Widget.destroy, self.window)
+</pre></td></tr></table><p>Line 65 is a packing call, which will be explained in depth
+later on in <a href="ch-PackingWidgets.html" title="Chapter 4. Packing Widgets">Chapter 4, <i>Packing Widgets</i></a> . But it is fairly
+easy to understand. It simply tells GTK+ that the button is to be placed in
+the window where it will be displayed. Note that a GTK+ container can only
+contain one widget. There are other widgets, described later, that are
+designed to layout multiple widgets in various ways.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ self.window.add(self.button)
+</pre></td></tr></table><p>Now we have everything set up the way we want it to be. With all
+the signal handlers in place, and the button placed in the window where it
+should be, we ask GTK+ (lines 66 and 69) to "show" the widgets on the screen.
+The window widget is shown last so the whole window will pop up at once
+rather than seeing the window pop up, and then the button forming inside of
+it. Although with such a simple example, you'd never notice.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ self.button.show()
+
+ self.window.show()
+</pre></td></tr></table><p>Lines 73-75 define the <tt class="methodname">main</tt>() method
+which calls the <tt class="function">gtk.main</tt>() function</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def main(self):
+ gtk.main()
+</pre></td></tr></table><p>Lines 80-82 allow the program to run automatically if called
+directly or as an argument of the python interpreter. Line 81 creates an
+instance of the <tt class="classname">HelloWorld</tt> class and saves a
+reference to it in the <tt class="varname">hello</tt> variable. Line 82 calls the
+<tt class="classname">HelloWorld</tt> class <tt class="methodname">main</tt>()
+method to start the GTK+ event processing loop.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ if __name__ == "__main__":
+ hello = HelloWorld()
+ hello.main()
+</pre></td></tr></table><p>Now, when we click the mouse button on a GTK+ button, the widget
+emits a "clicked" signal. In order for us to use this information, our
+program sets up a signal handler to catch that signal, which dispatches the
+function of our choice. In our example, when the button we created is
+"clicked", the <tt class="methodname">hello</tt>() method is called with the
+<tt class="literal">None</tt> argument, and then the next handler for this signal
+is called. The next handler calls the widget
+<tt class="methodname">destroy</tt>() function with the window as its argument
+thereby causing the window to emit the "destroy" signal, which is caught,
+and calls our <tt class="classname">HelloWorld</tt>
+<tt class="methodname">destroy</tt>() method</p><p>Another course of events is to use the window manager to kill
+the window, which will cause the "delete_event" to be emitted. This will
+call our "delete_event" handler. If we return <tt class="varname">TRUE</tt> here,
+the window will be left as is and nothing will happen. Returning
+<tt class="varname">FALSE</tt> will cause GTK+ to emit the "destroy" signal that
+causes the <tt class="classname">HelloWorld</tt> "destroy" callback to be
+called, exiting GTK.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-Events.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-GettingStarted.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch-MovingOn.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">2.3. Events </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 3. Moving On</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-SupplyingTheSelection.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-SupplyingTheSelection.html
new file mode 100644
index 0000000..1c0f06d
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-SupplyingTheSelection.html
@@ -0,0 +1,132 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>21.3. Supplying the Selection</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-ManagingSelections.html" title="Chapter 21. Managing Selections"><link rel="previous" href="sec-RetrievingTheSelection.html" title="21.2. Retrieving the Selection"><link rel="next" href="ch-DragAndDrop.html" title="Chapter 22. Drag-and-drop (DND)"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">21.3. Supplying the Selection</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-RetrievingTheSelection.html">Prev</a> </td><th width="60%" align="center">Chapter 21. Managing Selections</th><td width="20%" align="right"> <a accesskey="n" href="ch-DragAndDrop.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-SupplyingTheSelection"></a>21.3. Supplying the Selection</h2></div></div><div></div></div><p>Supplying the selection is a bit more complicated. You must
+register handlers that will be called when your selection is requested. For
+each selection-target pair you will handle, you make a call to:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ widget.selection_add_target(<b class="parameter"><tt>selection</tt></b>, <b class="parameter"><tt>target</tt></b>, <b class="parameter"><tt>info</tt></b>)
+</pre></td></tr></table><p><i class="parameter"><tt>widget</tt></i>, <i class="parameter"><tt>selection</tt></i>,
+and <i class="parameter"><tt>target</tt></i> identify the requests this handler will
+manage. When a request for a selection is received, the "selection_get"
+signal will be called. <i class="parameter"><tt>info</tt></i> is an integer that can be
+used as an enumerator to identify the specific target within the
+callback.</p><p>The callback has the signature:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def selection_get(widget, selection_data, info, time):
+</pre></td></tr></table><p>The <tt class="classname">gtk.SelectionData</tt> is the same as above,
+but this time, we're responsible for filling in the fields
+<i class="parameter"><tt>type</tt></i>, <i class="parameter"><tt>format</tt></i> and
+<i class="parameter"><tt>data</tt></i>. (The <i class="parameter"><tt>format</tt></i> field is
+actually important here - the X server uses it to figure out whether the
+<i class="parameter"><tt>data</tt></i> needs to be byte-swapped or not. Usually it will
+be 8 - i.e. a character - or 32 - i.e. a integer.) This is done by calling
+the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ selection_data.set(<b class="parameter"><tt>type</tt></b>, <b class="parameter"><tt>format</tt></b>, <b class="parameter"><tt>data</tt></b>)
+</pre></td></tr></table><p>This PyGTK method can only handle string data so the
+<i class="parameter"><tt>data</tt></i> must be loaded into a Python string but
+<i class="parameter"><tt>format</tt></i> will be whatever the appropriate size is
+(e.g. 32 for atoms and integers, 8 for strings). The Python
+<tt class="classname">struct</tt> or <tt class="classname">StringIO</tt> modules can
+be used to convert non-string data to string data. For example, you can
+convert a list of integers to a string and set the
+<i class="parameter"><tt>selection_data</tt></i> by:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ ilist = [1, 2, 3, 4, 5]
+
+ data = apply(struct.pack, ['%di'%len(ilist)] + ilist)
+
+ selection_data.set("INTEGER", 32, data)
+</pre></td></tr></table><p>The following method sets the selection data from the given
+string:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ selection_data.set_text(<b class="parameter"><tt>str</tt></b>, <b class="parameter"><tt>len</tt></b>)
+</pre></td></tr></table><p>When prompted by the user, you claim ownership of the selection
+by calling:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ result = widget.selection_owner_set(<b class="parameter"><tt>selection</tt></b>, <b class="parameter"><tt>time</tt></b>=0L)
+</pre></td></tr></table><p><i class="parameter"><tt>result</tt></i> will be <tt class="literal">TRUE</tt> if
+program successfully claimed the <i class="parameter"><tt>selection</tt></i>. If
+another application claims ownership of the
+<i class="parameter"><tt>selection</tt></i>, you will receive a
+"selection_clear_event".</p><p>As an example of supplying the selection, the <a href="examples/setselection.py" target="_top"><span><b class="command">setselection.py</b></span></a>
+program adds selection functionality to a toggle button enclosed in a
+<tt class="classname">gtk.EventBox</tt>. (The
+<tt class="classname">gtk.Eventbox</tt> is needed because the selection must be
+associated with a <tt class="classname">gtk.gdk.Window</tt> and a
+<tt class="classname">gtk.Button</tt> is a "windowless" object in GTK+ 2.0.)
+When the toggle button is depressed, the program claims the primary
+selection. The only target supported (aside from certain targets like
+"TARGETS" supplied by GTK+ itself), is the "STRING" target. When this target
+is requested, a string representation of the time is returned. <a href="sec-SupplyingTheSelection.html#setselectionfig" title="Figure 21.2. Set Selection Example">Figure 21.2, “Set Selection Exampleâ€</a> illustrates the program display when the program
+has taken the primary selection ownership:</p><div class="figure"><a name="setselectionfig"></a><p class="title"><b>Figure 21.2. Set Selection Example</b></p><div class="mediaobject" align="center"><img src="figures/setselection.png" align="middle" alt="Set Selection Example"></div></div><p>The <a href="examples/setselection.py" target="_top"><span><b class="command">setselection.py</b></span></a>
+source code is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 1 #!/usr/bin/env python
+ 2
+ 3 # example setselection.py
+ 4
+ 5 import pygtk
+ 6 pygtk.require('2.0')
+ 7 import gtk
+ 8 import time
+ 9
+ 10 class SetSelectionExample:
+ 11 # Callback when the user toggles the selection
+ 12 def selection_toggled(self, widget, window):
+ 13 if widget.get_active():
+ 14 self.have_selection = window.selection_owner_set("PRIMARY")
+ 15 # if claiming the selection failed, we return the button to
+ 16 # the out state
+ 17 if not self.have_selection:
+ 18 widget.set_active(False)
+ 19 else:
+ 20 if self.have_selection:
+ 21 # Not possible to release the selection in PyGTK
+ 22 # just mark that we don't have it
+ 23 self.have_selection = False
+ 24 return
+ 25
+ 26 # Called when another application claims the selection
+ 27 def selection_clear(self, widget, event):
+ 28 self.have_selection = False
+ 29 widget.set_active(False)
+ 30 return True
+ 31
+ 32 # Supplies the current time as the selection.
+ 33 def selection_handle(self, widget, selection_data, info, time_stamp):
+ 34 current_time = time.time()
+ 35 timestr = time.asctime(time.localtime(current_time))
+ 36
+ 37 # When we return a single string, it should not be null terminated.
+ 38 # That will be done for us
+ 39 selection_data.set_text(timestr, len(timestr))
+ 40 return
+ 41
+ 42 def __init__(self):
+ 43 self.have_selection = False
+ 44 # Create the toplevel window
+ 45 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ 46 window.set_title("Set Selection")
+ 47 window.set_border_width(10)
+ 48 window.connect("destroy", lambda w: gtk.main_quit())
+ 49 self.window = window
+ 50 # Create an eventbox to hold the button since it no longer has
+ 51 # a GdkWindow
+ 52 eventbox = gtk.EventBox()
+ 53 eventbox.show()
+ 54 window.add(eventbox)
+ 55
+ 56 # Create a toggle button to act as the selection
+ 57 selection_button = gtk.ToggleButton("Claim Selection")
+ 58 eventbox.add(selection_button)
+ 59
+ 60 selection_button.connect("toggled", self.selection_toggled, eventbox)
+ 61 eventbox.connect_object("selection_clear_event", self.selection_clear,
+ 62 selection_button)
+ 63
+ 64 eventbox.selection_add_target("PRIMARY", "STRING", 1)
+ 65 eventbox.selection_add_target("PRIMARY", "COMPOUND_TEXT", 1)
+ 66 eventbox.connect("selection_get", self.selection_handle)
+ 67 selection_button.show()
+ 68 window.show()
+ 69
+ 70 def main():
+ 71 gtk.main()
+ 72 return 0
+ 73
+ 74 if __name__ == "__main__":
+ 75 SetSelectionExample()
+ 76 main()
+</pre></td></tr></table></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-RetrievingTheSelection.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-ManagingSelections.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch-DragAndDrop.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">21.2. Retrieving the Selection </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 22. Drag-and-drop (DND)</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-TablePackingExample.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-TablePackingExample.html
new file mode 100644
index 0000000..c770a59
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-TablePackingExample.html
@@ -0,0 +1,108 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>4.5. Table Packing Example</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-PackingWidgets.html" title="Chapter 4. Packing Widgets"><link rel="previous" href="sec-PackingUsingTables.html" title="4.4. Packing Using Tables"><link rel="next" href="ch-WidgetOverview.html" title="Chapter 5. Widget Overview"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">4.5. Table Packing Example</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-PackingUsingTables.html">Prev</a> </td><th width="60%" align="center">Chapter 4. Packing Widgets</th><td width="20%" align="right"> <a accesskey="n" href="ch-WidgetOverview.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-TablePackingExample"></a>4.5. Table Packing Example</h2></div></div><div></div></div><p>The example program <a href="examples/table.py" target="_top"><span><b class="command">table.py</b></span></a> makes a window
+with three buttons in a 2x2 table. The first two buttons will be placed in
+the upper row. A third, quit button, is placed in the lower row, spanning
+both columns. <a href="sec-TablePackingExample.html#tablefig" title="Figure 4.4. Packing using a Table">Figure 4.4, “Packing using a Tableâ€</a> illustrates the resulting window:</p><div class="figure"><a name="tablefig"></a><p class="title"><b>Figure 4.4. Packing using a Table</b></p><div class="mediaobject" align="center"><img src="figures/table.png" align="middle" alt="Packing using a Table"></div></div><p>Here's the source code:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 1 #!/usr/bin/env python
+ 2
+ 3 # example table.py
+ 4
+ 5 import pygtk
+ 6 pygtk.require('2.0')
+ 7 import gtk
+ 8
+ 9 class Table:
+ 10 # Our callback.
+ 11 # The data passed to this method is printed to stdout
+ 12 def callback(self, widget, data=None):
+ 13 print "Hello again - %s was pressed" % data
+ 14
+ 15 # This callback quits the program
+ 16 def delete_event(self, widget, event, data=None):
+ 17 gtk.main_quit()
+ 18 return False
+ 19
+ 20 def __init__(self):
+ 21 # Create a new window
+ 22 self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ 23
+ 24 # Set the window title
+ 25 self.window.set_title("Table")
+ 26
+ 27 # Set a handler for delete_event that immediately
+ 28 # exits GTK.
+ 29 self.window.connect("delete_event", self.delete_event)
+ 30
+ 31 # Sets the border width of the window.
+ 32 self.window.set_border_width(20)
+ 33
+ 34 # Create a 2x2 table
+ 35 table = gtk.Table(2, 2, True)
+ 36
+ 37 # Put the table in the main window
+ 38 self.window.add(table)
+ 39
+ 40 # Create first button
+ 41 button = gtk.Button("button 1")
+ 42
+ 43 # When the button is clicked, we call the "callback" method
+ 44 # with a pointer to "button 1" as its argument
+ 45 button.connect("clicked", self.callback, "button 1")
+ 46
+ 47
+ 48 # Insert button 1 into the upper left quadrant of the table
+ 49 table.attach(button, 0, 1, 0, 1)
+ 50
+ 51 button.show()
+ 52
+ 53 # Create second button
+ 54
+ 55 button = gtk.Button("button 2")
+ 56
+ 57 # When the button is clicked, we call the "callback" method
+ 58 # with a pointer to "button 2" as its argument
+ 59 button.connect("clicked", self.callback, "button 2")
+ 60 # Insert button 2 into the upper right quadrant of the table
+ 61 table.attach(button, 1, 2, 0, 1)
+ 62
+ 63 button.show()
+ 64
+ 65 # Create "Quit" button
+ 66 button = gtk.Button("Quit")
+ 67
+ 68 # When the button is clicked, we call the main_quit function
+ 69 # and the program exits
+ 70 button.connect("clicked", lambda w: gtk.main_quit())
+ 71
+ 72 # Insert the quit button into the both lower quadrants of the table
+ 73 table.attach(button, 0, 2, 1, 2)
+ 74
+ 75 button.show()
+ 76
+ 77 table.show()
+ 78 self.window.show()
+ 79
+ 80 def main():
+ 81 gtk.main()
+ 82 return 0
+ 83
+ 84 if __name__ == "__main__":
+ 85 Table()
+ 86 main()
+</pre></td></tr></table><p>The <tt class="classname">Table</tt> class is defined in line 9-78.
+Lines 12-13 define the <tt class="methodname">callback</tt>() method which is
+called when two of the buttons are "clicked". The callback just prints a
+message to the console indicating which button was pressed using the passed
+in string data.</p><p>Lines 16-18 define the <tt class="methodname">delete_event</tt>()
+method which is called when the window is slated for deletion by the window
+manager.</p><p>Lines 20-78 define the <tt class="classname">Table</tt> instance
+initialization method <tt class="methodname">__init__</tt>() . It creates a
+window (line 22), sets the window title (line 25), connects the
+<tt class="methodname">delete_event</tt>() callback to the "delete_event"
+signal (line 29), and sets the border width (line 32). A
+<tt class="classname">gtk.Table</tt> is created in line 35 and added to the
+window in line 38.</p><p>The two upper buttons are created (lines 41 and 55), their
+"clicked" signals are connected to the <tt class="methodname">callback</tt>()
+method (lines 45 and 59), and attached to the table in the first row (lines
+49 and 61). Lines 66-72 create the "Quit" button, connect its "clicked"
+signal to the <tt class="function">main_quit</tt>() function and attach it to the
+table spanning the whole second row.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-PackingUsingTables.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-PackingWidgets.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch-WidgetOverview.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">4.4. Packing Using Tables </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 5. Widget Overview</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-TextBuffers.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-TextBuffers.html
new file mode 100644
index 0000000..71e008e
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-TextBuffers.html
@@ -0,0 +1,258 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>13.3. Text Buffers</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-TextViewWidget.html" title="Chapter 13. TextView Widget"><link rel="previous" href="sec-TextViews.html" title="13.2. TextViews"><link rel="next" href="sec-TextIters.html" title="13.4. Text Iters"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">13.3. Text Buffers</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-TextViews.html">Prev</a> </td><th width="60%" align="center">Chapter 13. TextView Widget</th><td width="20%" align="right"> <a accesskey="n" href="sec-TextIters.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-TextBuffers"></a>13.3. Text Buffers</h2></div></div><div></div></div><p>A <tt class="classname">TextBuffer</tt> is the core component of the
+PyGTK text editing system. It contains the text, the
+<tt class="classname">TextTag</tt>s in a <tt class="classname">TextTagTable</tt> and
+the <tt class="classname">TextMark</tt>s which together describe how the text is
+to be displayed and allow a user to interactively modify the text and text
+display. As noted in the previous section a
+<tt class="classname">TextBuffer</tt> is associated with one or more
+<tt class="classname">TextView</tt>s which display the
+<tt class="classname">TextBuffer</tt> contents.</p><p>A <tt class="classname">TextBuffer</tt> can be created automatically
+when a <tt class="classname">TextView</tt> is created or it can be created with
+the function:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ textbuffer = TextBuffer(<b class="parameter"><tt>table</tt></b>=None)
+</pre></td></tr></table><p>where <i class="parameter"><tt>table</tt></i> is a
+<tt class="classname">TextTagTable</tt>. If <i class="parameter"><tt>table</tt></i> is not
+specified (or is <tt class="literal">None</tt>) a
+<tt class="classname">TextTagTable</tt> will be created for the
+<tt class="classname">TextBuffer</tt>.</p><p>There are a large number of methods that can be used to:</p><div class="itemizedlist"><ul type="disc"><li>insert and remove text from a buffer</li><li>create, delete and manipulate marks</li><li>manipulate the cursor and the selection</li><li>create, apply and remove tags</li><li>specify and manipulate
+<tt class="classname">TextIter</tt>s</li><li>get status information</li></ul></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2841804"></a>13.3.1. TextBuffer Status Information</h3></div></div><div></div></div><p>You can retrieve the number of lines in a
+<i class="parameter"><tt>textbuffer</tt></i> by using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ line_count = textbuffer.get_line_count()
+</pre></td></tr></table><p>Likewise you can get the number of characters in the
+<i class="parameter"><tt>textbuffer</tt></i> using:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ char_count = textbuffer.get_char_count()
+</pre></td></tr></table><p>When the <i class="parameter"><tt>textbuffer</tt></i> contents are changed
+the modified flag in the textbuffer is set. The status of the modified flag
+can be retrieved using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ modified = textbuffer.get_modified()
+</pre></td></tr></table><p>If the program saves the contents of the textbuffer the
+following method can be used to reset the modified flag:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ textbuffer.set_modified(<b class="parameter"><tt>setting</tt></b>)
+</pre></td></tr></table></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2841858"></a>13.3.2. Creating TextIters</h3></div></div><div></div></div><p>A <tt class="classname">TextIter</tt> is used to specify a location
+within a <tt class="classname">TextBuffer</tt> between two
+characters. <tt class="classname">TextBuffer</tt> methods that manipulate text
+use <tt class="classname">TextIter</tt>s to specify where the method is to be
+applied. <tt class="classname">TextIter</tt>s have a large number of methods
+that will be described in the &gt;<tt class="classname">TextIter</tt>s
+section.</p><p>The basic <tt class="classname">TextBuffer</tt> methods used to
+create <tt class="classname">TextIter</tt>s
+are:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ iter = textbuffer.get_iter_at_offset(<b class="parameter"><tt>char_offset</tt></b>)
+
+ iter = textbuffer_get_iter_at_line(<b class="parameter"><tt>line_number</tt></b>)
+
+ iter = textbuffer.get_iter_at_line_offset(<b class="parameter"><tt>line_number</tt></b>, <b class="parameter"><tt>line_offset</tt></b>)
+
+ iter = textbuffer.get_iter_at_mark(<b class="parameter"><tt>mark</tt></b>)
+</pre></td></tr></table><p><tt class="methodname">get_iter_at_offset</tt>() creates an iter
+that is just after <i class="parameter"><tt>char_offset</tt></i> chars from the start
+of the textbuffer.</p><p><tt class="methodname">get_iter_at_line</tt>() creates an iter that
+is just before the first character in
+<i class="parameter"><tt>line_number</tt></i>.</p><p><tt class="methodname">get_iter_at_line_offset</tt>() creates an
+iter that is just after the <i class="parameter"><tt>line_offset</tt></i> character in
+<i class="parameter"><tt>line_number</tt></i>.</p><p><tt class="methodname">get_iter_at_mark</tt>() creates an iter that
+is at the same position as the given <i class="parameter"><tt>mark</tt></i>.</p><p>The following methods create one or more
+<tt class="classname">TextIter</tt>s at specific buffer locations:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ startiter = textbuffer.get_start_iter()
+
+ enditer = textbuffer_get_end_iter()
+
+ startiter, enditer = textbuffer.get_bounds()
+
+ start, end = textbuffer.get_selection_bounds()
+
+</pre></td></tr></table><p><tt class="methodname">get_start_iter</tt>() creates an iter that
+is just before the first character in the textbuffer.</p><p><tt class="methodname">get_end_iter</tt>() creates an iter that is
+just after the last character in the textbuffer.</p><p><tt class="methodname">get_bounds</tt>() creates a tuple of two
+iters that are just before the first character and just after the last
+character in the textbuffer respectively.</p><p><tt class="methodname">get_selection_bounds</tt>() creates a tuple
+of two iters that have the same location as the
+<i class="parameter"><tt>insert</tt></i> and <i class="parameter"><tt>selection_bound</tt></i>
+marks in the textbuffer.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2855040"></a>13.3.3. Text Insertion, Retrieval and Deletion</h3></div></div><div></div></div><p>The text in a <tt class="classname">TextBuffer</tt> can be set
+using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ textbuffer.set_text(<b class="parameter"><tt>text</tt></b>)
+</pre></td></tr></table><p>This method replaces the current contents of textbuffer with
+<i class="parameter"><tt>text</tt></i>.</p><p>The most general method to insert characters in a textbuffer
+is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ textbuffer.insert(<b class="parameter"><tt>iter</tt></b>, <b class="parameter"><tt>text</tt></b>)
+</pre></td></tr></table><p>which inserts <i class="parameter"><tt>text</tt></i> at the textbuffer
+location specified by <i class="parameter"><tt>iter</tt></i>.</p><p>If you want to simulate the insertion of text by an
+interactive user use the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ result = textbuffer.insert_interactive(<b class="parameter"><tt>iter</tt></b>, <b class="parameter"><tt>text</tt></b>, <b class="parameter"><tt>default_editable</tt></b>)
+</pre></td></tr></table><p>which inserts <i class="parameter"><tt>text</tt></i> in the textbuffer at
+the location specified by <i class="parameter"><tt>iter</tt></i> but only if the
+location is editable (i.e. does not have a tag that specifies the text is
+non-editable) and the <i class="parameter"><tt>default_editable</tt></i> value is
+<tt class="literal">TRUE</tt>. The result indicates whether the text was
+inserted.</p><p><i class="parameter"><tt>default_editable</tt></i> indicates the
+editability of text that doesn't have a tag affecting editability;
+<i class="parameter"><tt>default_editable</tt></i> is usually determined by a call to
+the <tt class="classname">TextView</tt> <tt class="methodname">get_editable</tt>()
+method.</p><p>Other methods that insert text are:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ textbuffer.insert_at_cursor(<b class="parameter"><tt>text</tt></b>)
+
+ result = textbuffer.insert_at_cursor_interactive(<b class="parameter"><tt>text</tt></b>, <b class="parameter"><tt>default_editable</tt></b>)
+
+ textbuffer.insert_range(<b class="parameter"><tt>iter</tt></b>, <b class="parameter"><tt>start</tt></b>, <b class="parameter"><tt>end</tt></b>)
+
+ result = textbuffer.insert_range_interactive(<b class="parameter"><tt>iter</tt></b>, <b class="parameter"><tt>start</tt></b>, <b class="parameter"><tt>end</tt></b>, <b class="parameter"><tt>default_editable</tt></b>)
+</pre></td></tr></table><p><tt class="methodname">insert_at_cursor</tt>() is a convenience
+method that inserts text at the current cursor
+(<i class="parameter"><tt>insert</tt></i>) location.</p><p><tt class="methodname">insert_range</tt>() copies text, pixbufs and
+tags between <i class="parameter"><tt>start</tt></i> and <i class="parameter"><tt>end</tt></i>
+from a <tt class="classname">TextBuffer</tt> (if different from textbuffer the
+tag table must be the same) and inserts the copy into textbuffer at
+<i class="parameter"><tt>iter</tt></i>'s location.</p><p>The interactive versions of these methods operate the same way
+except they will only insert if the location is editable.</p><p>Finally, text can be inserted and have tags applied at the
+same time using the methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ textbuffer.insert_with_tags(iter, text, tag1, tag2, ...)
+
+ textbuffer.insert_with_tags_by_name(iter, text, tagname1, tagname2, ...)
+</pre></td></tr></table><p><tt class="methodname">insert_with_tags</tt>() inserts the
+<i class="parameter"><tt>text</tt></i> in the textbuffer at the location specified by
+<i class="parameter"><tt>iter</tt></i> and applies the given tags.</p><p><tt class="methodname">insert_with_tags_by_name</tt>() does that
+same thing but allows you to specify the tags using the tag name.</p><p>The text in a textbuffer can be deleted by using the
+methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ textbuffer.delete(<b class="parameter"><tt>start</tt></b>, <b class="parameter"><tt>end</tt></b>)
+
+ result = textbuffer.delete_interactive(<b class="parameter"><tt>start</tt></b>, <b class="parameter"><tt>end</tt></b>, <b class="parameter"><tt>default_editable</tt></b>)
+</pre></td></tr></table><p><tt class="methodname">delete</tt>() removes the text between the
+<i class="parameter"><tt>start</tt></i> and <i class="parameter"><tt>end</tt></i>
+<tt class="classname">TextIter</tt> locations in textbuffer.</p><p><tt class="methodname">delete_interactive</tt>() removes all the
+editable (as determined by the applicable text tags and the
+<i class="parameter"><tt>default_editable</tt></i> argument) text between
+<i class="parameter"><tt>start</tt></i> and <i class="parameter"><tt>end</tt></i>.</p><p>You can retrieve a copy of the text from a textbuffer by using
+the methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ text = textbuffer.get_text(<b class="parameter"><tt>start</tt></b>, <b class="parameter"><tt>end</tt></b>, <b class="parameter"><tt>include_hidden_chars</tt></b>=TRUE)
+
+ text = textbuffer.get_slice(<b class="parameter"><tt>start</tt></b>, <b class="parameter"><tt>end</tt></b>, <b class="parameter"><tt>include_hidden_chars</tt></b>=TRUE)
+</pre></td></tr></table><p><tt class="methodname">get_text</tt>() returns a copy of the
+<i class="parameter"><tt>text</tt></i> in textbuffer between
+<i class="parameter"><tt>start</tt></i> and <i class="parameter"><tt>end</tt></i>; undisplayed
+text is excluded if <i class="parameter"><tt>include_hidden_chars</tt></i> is
+<tt class="literal">FALSE</tt>. Characters which represent embedded images or
+widgets are excluded.</p><p><tt class="methodname">get_slice</tt>() is the same as
+<tt class="methodname">get_text</tt>() except that the returned
+<i class="parameter"><tt>text</tt></i> includes a 0xFFFC character for each embedded
+image or widget.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2855411"></a>13.3.4. TextMarks</h3></div></div><div></div></div><p><tt class="classname">TextMark</tt>s are similar to
+<tt class="classname">TextIter</tt>s in that they specify a location in a
+<tt class="classname">TextBuffer</tt> between two characters. However,
+<tt class="classname">TextMark</tt>s maintain their location information across
+buffer modifications. The <tt class="classname">TextMark</tt> methods will be
+described in the <tt class="classname">TextMark</tt>s section.</p><p>A textbuffer contains two built-in marks: the
+<i class="parameter"><tt>insert</tt></i> (cursor) mark and the
+<i class="parameter"><tt>selection_bound</tt></i> mark. The
+<i class="parameter"><tt>insert</tt></i> mark is the default location for the insertion
+of text and the <i class="parameter"><tt>selection_bound</tt></i> mark combines with
+the <i class="parameter"><tt>insert</tt></i> mark to define a selection range.</p><p>The built-in marks can be retrieved by using the
+methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ insertmark = textbuffer.get_insert()
+
+ selection_boundmark = textbuffer.get_selection_bound()
+</pre></td></tr></table><p>The <i class="parameter"><tt>insert</tt></i> and
+<i class="parameter"><tt>selection_bound</tt></i> marks can be placed simultaneously at
+a location by using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ textbuffer.place_cursor(<b class="parameter"><tt>where</tt></b>)
+</pre></td></tr></table><p><i class="parameter"><tt>where</tt></i> is a textiter specifying the
+location. The <tt class="methodname">place_cursor</tt>() method is needed to
+avoid temporarily creating a selection if the marks were moved
+individually.</p><p><tt class="classname">TextMark</tt>s are created by using the
+method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ mark = textbuffer.create_mark(<b class="parameter"><tt>mark_name</tt></b>, <b class="parameter"><tt>where</tt></b>, <b class="parameter"><tt>left_gravity</tt></b>=FALSE)
+</pre></td></tr></table><p>where <i class="parameter"><tt>mark_name</tt></i> is the name assigned to
+the created mark (can be <tt class="literal">None</tt> to create an anonymous mark),
+<i class="parameter"><tt>where</tt></i> is the textiter specifying the location of the
+mark in textbuffer and <i class="parameter"><tt>left_gravity</tt></i> indicates where
+the mark will be located after text is inserted at the mark (left if
+<tt class="literal">TRUE</tt> or right if <tt class="literal">FALSE</tt>).</p><p>A mark can be moved in the textbuffer by using the
+methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ textbuffer.move_mark(<b class="parameter"><tt>mark</tt></b>, <b class="parameter"><tt>where</tt></b>)
+
+ textbuffer.move_mark_by_name(<b class="parameter"><tt>name</tt></b>, <b class="parameter"><tt>where</tt></b>)
+</pre></td></tr></table><p><i class="parameter"><tt>mark</tt></i> specifies the mark to be moved.
+<i class="parameter"><tt>name</tt></i> specifies the name of the mark to be moved.
+<i class="parameter"><tt>where</tt></i> is a textiter specifying the new
+location.</p><p>A mark can be deleted from a textbuffer by using the
+methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ textbuffer.delete_mark(<b class="parameter"><tt>mark</tt></b>)
+
+ textbuffer.delete_mark_by_name(<b class="parameter"><tt>name</tt></b>)
+</pre></td></tr></table><p>A mark can be retrieved by name using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ mark = textbuffer.get_mark(<b class="parameter"><tt>name</tt></b>)
+</pre></td></tr></table></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2855626"></a>13.3.5. Creating and Applying TextTags</h3></div></div><div></div></div><p><tt class="classname">TextTag</tt>s contain one or more attributes
+(e.g. foreground and background colors, font, editability) that can be
+applied to one or more ranges of text in a
+<tt class="classname">TextBuffer</tt>. The attributes that can be specified by
+<tt class="classname">TextTag</tt> properties will be described in <a href="sec-TextTagsAndTextTagTables.html#sec-TextTags" title="13.6.1. Text Tags">Section 13.6.1, “Text Tagsâ€</a>.</p><p>A <tt class="classname">TextTag</tt> can be created with attributes
+and installed in the <tt class="classname">TextTagTable</tt> of a
+<tt class="classname">TextBuffer</tt> by using the convenience method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ tag = textbuffer.create_tag(name=None, attr1=val1, attr2=val2, ...)
+</pre></td></tr></table><p>where <i class="parameter"><tt>name</tt></i> is a string specifying the
+name of the tag or <tt class="literal">None</tt> if the tag is an anonymous tag
+and the keyword-value pairs specify the attributes that the tag will
+have. See the <tt class="classname">TextTag</tt>&gt; section for information on
+what attributes can be set by the <tt class="classname">TextTag</tt>
+properties.</p><p>A tag can be applied to a range of text in a textbuffer by
+using the methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ textbuffer.apply_tag(<b class="parameter"><tt>tag</tt></b>, <b class="parameter"><tt>start</tt></b>, <b class="parameter"><tt>end</tt></b>)
+
+ textbuffer.apply_tag_by_name(<b class="parameter"><tt>name</tt></b>, <b class="parameter"><tt>start</tt></b>, <b class="parameter"><tt>end</tt></b>)
+</pre></td></tr></table><p><i class="parameter"><tt>tag</tt></i> is the tag to be applied to the text.
+<i class="parameter"><tt>name</tt></i> is the name of the tag to be applied.
+<i class="parameter"><tt>start</tt></i> and <i class="parameter"><tt>end</tt></i> are textiters
+that specify the range of text that the <i class="parameter"><tt>tag</tt></i> is to be
+applied to.</p><p>A tag can be removed from a range of text by using the
+methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ textbuffer.remove_tag(<b class="parameter"><tt>tag</tt></b>, <b class="parameter"><tt>start</tt></b>, <b class="parameter"><tt>end</tt></b>)
+
+ textbuffer.remove_tag_by_name(<b class="parameter"><tt>name</tt></b>, <b class="parameter"><tt>start</tt></b>, <b class="parameter"><tt>end</tt></b>)
+</pre></td></tr></table><p>All tags for a range of text can be removed by using the
+method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ textbuffer.remove_all_tags(<b class="parameter"><tt>start</tt></b>, <b class="parameter"><tt>end</tt></b>)
+</pre></td></tr></table></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2855808"></a>13.3.6. Inserting Images and Widgets</h3></div></div><div></div></div><p>In addition to text a <tt class="classname">TextBuffer</tt> can
+contain pixbuf images and an anchor location for widgets. A widget can be
+added to a <tt class="classname">TextView</tt> at an anchor location. A
+different widget can be added in each <tt class="classname">TextView</tt> which
+displays a buffer with an anchor.</p><p>A pixbuf can be inserted by using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ textbuffer.insert_pixbuf(<b class="parameter"><tt>iter</tt></b>, <b class="parameter"><tt>pixbuf</tt></b>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>iter</tt></i> specifies the location in the
+<i class="parameter"><tt>textbuffer</tt></i> to insert the
+<i class="parameter"><tt>pixbuf</tt></i>. The image will be counted as one character
+and will be represented in a <tt class="methodname">get_slice</tt>() return
+(but left out of a <tt class="methodname">get_text</tt>() return) as the
+Unicode character "0xFFFC".</p><p>A GTK+ widget can be inserted in a
+<tt class="classname">TextView</tt> at a buffer location specified with a
+<tt class="classname">TextChildAnchor</tt>. The
+<tt class="classname">TextChildAnchor</tt> will be counted as one character and
+represented as "0xFFFC" similar to a pixbuf.</p><p>The <tt class="classname">TextChildAnchor</tt> can be created and
+inserted in the buffer by using the convenience method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ anchor = text_buffer.create_child_anchor(<b class="parameter"><tt>iter</tt></b>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>iter</tt></i> is the location for the
+child_anchor.</p><p>A <tt class="classname">TextChildAnchor</tt> can also be created
+and inserted in two operations as:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ anchor = gtk.TextChildAnchor()
+
+ text_buffer.insert_child_anchor(<b class="parameter"><tt>iter</tt></b>, <b class="parameter"><tt>anchor</tt></b>)
+</pre></td></tr></table><p>Then the widget can be added to the
+<tt class="classname">TextView</tt> at an anchor location using the
+method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ text_view.add_child_at_anchor(<b class="parameter"><tt>child</tt></b>, <b class="parameter"><tt>anchor</tt></b>)
+</pre></td></tr></table><p>The list of widgets at a particular buffer anchor can be
+retrieved using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ widget_list = anchor.get_widgets()
+</pre></td></tr></table><p>A widget can also be added to a <tt class="classname">TextView</tt>
+using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ text_view.add_child_in_window(<b class="parameter"><tt>child</tt></b>, <b class="parameter"><tt>which_window</tt></b>, <b class="parameter"><tt>xpos</tt></b>, <b class="parameter"><tt>ypos</tt></b>)
+</pre></td></tr></table><p>where the <i class="parameter"><tt>child</tt></i> widget is placed in
+<i class="parameter"><tt>which_window</tt></i> at the location specified by
+<i class="parameter"><tt>xpos</tt></i> and <i class="parameter"><tt>ypos</tt></i>.
+<i class="parameter"><tt>which_window</tt></i> indicates in which of the windows that
+make up the <tt class="classname">TextView</tt> the widget is to be
+placed:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ gtk.TEXT_WINDOW_TOP
+ gtk.TEXT_WINDOW_BOTTOM
+ gtk.TEXT_WINDOW_LEFT
+ gtk.TEXT_WINDOW_RIGHT
+ gtk.TEXT_WINDOW_TEXT
+ gtk.TEXT_WINDOW_WIDGET
+</pre></td></tr></table></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-TextViews.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-TextViewWidget.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-TextIters.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">13.2. TextViews </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 13.4. Text Iters</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-TextEntries.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-TextEntries.html
new file mode 100644
index 0000000..51b479e
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-TextEntries.html
@@ -0,0 +1,123 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>9.9. Text Entries</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-MiscellaneousWidgets.html" title="Chapter 9. Miscellaneous Widgets"><link rel="previous" href="sec-Statusbars.html" title="9.8. Statusbars"><link rel="next" href="sec-SpinButtons.html" title="9.10. Spin Buttons"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">9.9. Text Entries</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-Statusbars.html">Prev</a> </td><th width="60%" align="center">Chapter 9. Miscellaneous Widgets</th><td width="20%" align="right"> <a accesskey="n" href="sec-SpinButtons.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-TextEntries"></a>9.9. Text Entries</h2></div></div><div></div></div><p>The <tt class="classname">Entry</tt> widget allows text to be typed
+and displayed in a single line text box. The text may be set with method
+calls that allow new text to replace, prepend or append the current contents
+of the <tt class="classname">Entry</tt> widget.</p><p>The function for creating an <tt class="classname">Entry</tt> widget
+is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ entry = gtk.Entry(<b class="parameter"><tt>max</tt></b>=0)
+</pre></td></tr></table><p>If the <i class="parameter"><tt>max</tt></i> argument is given it sets a
+limit on the length of the text within the <tt class="classname">Entry</tt>. If
+<i class="parameter"><tt>max</tt></i> is 0 then there is no limit.</p><p>The maximum length of the entry can be changed using the
+method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ entry.set_max_length(<b class="parameter"><tt>max</tt></b>)
+</pre></td></tr></table><p>The next method alters the text which is currently within the
+<tt class="classname">Entry</tt> widget.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ entry.set_text(<b class="parameter"><tt>text</tt></b>)
+</pre></td></tr></table><p>The <tt class="methodname">set_text</tt>() method sets the contents
+of the <tt class="classname">Entry</tt> widget to <i class="parameter"><tt>text</tt></i>,
+replacing the current contents. Note that the class
+<tt class="classname">Entry</tt> implements the <tt class="classname">Editable</tt>
+interface (yes, <tt class="classname">gobject</tt> supports Java-like
+interfaces) which contains some more functions for manipulating the
+contents. For example, the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ entry.insert_text(<b class="parameter"><tt>text</tt></b>, <b class="parameter"><tt>position</tt></b>=0)
+</pre></td></tr></table><p>inserts <i class="parameter"><tt>text</tt></i> at the given position within
+the <i class="parameter"><tt>entry</tt></i>.</p><p>The contents of the <tt class="classname">Entry</tt> can be
+retrieved by using a call to the following method. This is useful in the
+callback methods described below.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ text = entry.get_text()
+</pre></td></tr></table><p>If we don't want the contents of the
+<tt class="classname">Entry</tt> to be changed by someone typing into it, we can
+change its editable state.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ entry.set_editable(<b class="parameter"><tt>is_editable</tt></b>)
+</pre></td></tr></table><p>The above method allows us to toggle the editable state of the
+<tt class="classname">Entry</tt> widget by passing in a <tt class="literal">TRUE</tt>
+or <tt class="literal">FALSE</tt> value for the <i class="parameter"><tt>is_editable</tt></i>
+argument.</p><p>If we are using the <tt class="classname">Entry</tt> where we don't
+want the text entered to be visible, for example when a password is being
+entered, we can use the following method, which also takes a boolean
+flag.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ entry.set_visibility(<b class="parameter"><tt>visible</tt></b>)
+</pre></td></tr></table><p>A region of the text may be set as selected by using the
+following method. This would most often be used after setting some default
+text in an <tt class="classname">Entry</tt>, making it easy for the user to
+remove it.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ entry.select_region(<b class="parameter"><tt>start</tt></b>, <b class="parameter"><tt>end</tt></b>)
+</pre></td></tr></table><p>If we want to be notified when the user has entered text, we can
+connect to the "activate" or "changed" signal. Activate is raised when the
+user hits the enter key within the <tt class="classname">Entry</tt> widget.
+Changed is raised when the any change is made to the text, e.g. for every
+character entered or removed.</p><p>The <a href="examples/entry.py" target="_top"><span><b class="command">entry.py</b></span></a> example program
+illustrates the use of an <tt class="classname">Entry</tt> widget.
+<a href="sec-TextEntries.html#entryfig" title="Figure 9.10. Entry Example">Figure 9.10, “Entry Exampleâ€</a> shows the result of running the program:</p><div class="figure"><a name="entryfig"></a><p class="title"><b>Figure 9.10. Entry Example</b></p><div class="mediaobject" align="center"><img src="figures/entry.png" align="middle" alt="Entry Example"></div></div><p>The <a href="examples/entry.py" target="_top"><span><b class="command">entry.py</b></span></a> source code
+is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 1 #!/usr/bin/env python
+ 2
+ 3 # example entry.py
+ 4
+ 5 import pygtk
+ 6 pygtk.require('2.0')
+ 7 import gtk
+ 8
+ 9 class EntryExample:
+ 10 def enter_callback(self, widget, entry):
+ 11 entry_text = entry.get_text()
+ 12 print "Entry contents: %s\n" % entry_text
+ 13
+ 14 def entry_toggle_editable(self, checkbutton, entry):
+ 15 entry.set_editable(checkbutton.get_active())
+ 16
+ 17 def entry_toggle_visibility(self, checkbutton, entry):
+ 18 entry.set_visibility(checkbutton.get_active())
+ 19
+ 20 def __init__(self):
+ 21 # create a new window
+ 22 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ 23 window.set_size_request(200, 100)
+ 24 window.set_title("GTK Entry")
+ 25 window.connect("delete_event", lambda w,e: gtk.main_quit())
+ 26
+ 27 vbox = gtk.VBox(False, 0)
+ 28 window.add(vbox)
+ 29 vbox.show()
+ 30
+ 31 entry = gtk.Entry()
+ 32 entry.set_max_length(50)
+ 33 entry.connect("activate", self.enter_callback, entry)
+ 34 entry.set_text("hello")
+ 35 entry.insert_text(" world", len(entry.get_text()))
+ 36 entry.select_region(0, len(entry.get_text()))
+ 37 vbox.pack_start(entry, True, True, 0)
+ 38 entry.show()
+ 39
+ 40 hbox = gtk.HBox(False, 0)
+ 41 vbox.add(hbox)
+ 42 hbox.show()
+ 43
+ 44 check = gtk.CheckButton("Editable")
+ 45 hbox.pack_start(check, True, True, 0)
+ 46 check.connect("toggled", self.entry_toggle_editable, entry)
+ 47 check.set_active(True)
+ 48 check.show()
+ 49
+ 50 check = gtk.CheckButton("Visible")
+ 51 hbox.pack_start(check, True, True, 0)
+ 52 check.connect("toggled", self.entry_toggle_visibility, entry)
+ 53 check.set_active(True)
+ 54 check.show()
+ 55
+ 56 button = gtk.Button(stock=gtk.STOCK_CLOSE)
+ 57 button.connect("clicked", lambda w: gtk.main_quit())
+ 58 vbox.pack_start(button, True, True, 0)
+ 59 button.set_flags(gtk.CAN_DEFAULT)
+ 60 button.grab_default()
+ 61 button.show()
+ 62 window.show()
+ 63
+ 64 def main():
+ 65 gtk.main()
+ 66 return 0
+ 67
+ 68 if __name__ == "__main__":
+ 69 EntryExample()
+ 70 main()
+</pre></td></tr></table></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-Statusbars.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-MiscellaneousWidgets.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-SpinButtons.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">9.8. Statusbars </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 9.10. Spin Buttons</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-TextIters.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-TextIters.html
new file mode 100644
index 0000000..fbb1c8b
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-TextIters.html
@@ -0,0 +1,231 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>13.4. Text Iters</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-TextViewWidget.html" title="Chapter 13. TextView Widget"><link rel="previous" href="sec-TextBuffers.html" title="13.3. Text Buffers"><link rel="next" href="sec-TextMarks.html" title="13.5. Text Marks"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">13.4. Text Iters</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-TextBuffers.html">Prev</a> </td><th width="60%" align="center">Chapter 13. TextView Widget</th><td width="20%" align="right"> <a accesskey="n" href="sec-TextMarks.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-TextIters"></a>13.4. Text Iters</h2></div></div><div></div></div><p><tt class="classname">TextIters</tt> represent a position between two
+characters in a <tt class="classname">TextBuffer</tt>.
+<tt class="classname">TextIters</tt> are usually created by using a
+<tt class="classname">TextBuffer</tt> method. <tt class="classname">TextIters</tt>
+are invalidated when the number of characters in a
+<tt class="classname">TextBuffer</tt> is changed (except for the
+<tt class="classname">TextIter</tt> that is used for the insertion or
+deletion). Inserting or deleting pixbufs or anchors also counts as a
+<tt class="classname">TextIter</tt> invalidating change.</p><p>There are a large number of methods associated with a
+<tt class="classname">TextIter</tt> object. They are grouped together in the
+following sections by similar function.</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2856073"></a>13.4.1. TextIter Attributes</h3></div></div><div></div></div><p>The <tt class="classname">TextBuffer</tt> that contains the
+<tt class="classname">TextIter</tt> can be retrieved using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ buffer = iter.get_buffer()
+</pre></td></tr></table><p>The following methods can be used to get the location of the
+<tt class="classname">TextIter</tt> in the
+<tt class="classname">TextBuffer</tt>:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ offset = iter.get_offset() # returns offset in buffer of iter
+
+ line_number = iter.get_line() # returns number of line at iter
+
+ line_offset = iter.get_line_offset() # returns iter offset in line
+
+ numchars = iter.get_chars_in_line() # returns number of chars in line
+</pre></td></tr></table></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2856114"></a>13.4.2. Text Attributes at a TextIter</h3></div></div><div></div></div><p>The <tt class="classname">PangoLanguage</tt> used at a given iter
+location in the <tt class="classname">TextBuffer</tt> is obtained by calling the
+method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ language = iter.get_language()
+</pre></td></tr></table><p>The more general method used to get the text attributes at a
+<tt class="classname">TextIter</tt>'s location is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ result = iter.get_attributes(<b class="parameter"><tt>values</tt></b>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>result</tt></i> indicates whether the given
+<i class="parameter"><tt>values</tt></i> (<tt class="classname">TextAttributes</tt> object)
+were modified. The given <i class="parameter"><tt>values</tt></i> are obtained by using
+the <tt class="classname">TextView</tt> method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ values = textview.get_default_attributes()
+</pre></td></tr></table><p>The following attributes are accessible from a
+<tt class="classname">TextAttributes</tt> object (not implemented in PyGTK &lt;=
+1.99.15):</p><div class="informaltable"><table width="100%" border="1"><colgroup><col><col></colgroup><tbody><tr><td>bg_color</td><td>background color</td></tr><tr><td>fg_color</td><td>foreground color</td></tr><tr><td>bg_stipple</td><td>background stipple bitmap</td></tr><tr><td>fg_stipple</td><td>foreground stipple bitmap</td></tr><tr><td>rise</td><td>offset of text above baseline</td></tr><tr><td>underline</td><td>style of underline</td></tr><tr><td>strikethrough</td><td>whether text is strikethrough</td></tr><tr><td>draw_bg</td><td><tt class="literal">TRUE</tt> if some tags affect the drawing of the background</td></tr><tr><td>justification</td><td>style of justification</td></tr><tr><td>direction</td><td>which direction the text runs</td></tr><tr><td>font</td><td>PangoFontDescription in use</td></tr><tr><td>font_scale</td><td>scale of the font in use</td></tr><tr><td>left_margin</td><td>location of left margin</td></tr><tr><td>right_margin</td><td>location of right margin</td></tr><tr><td>pixels_above_lines</td><td>pixels spacing above a line</td></tr><tr><td>pixels_below_lines</td><td>pixel spacing below a line</td></tr><tr><td>pixels_inside_wrap</td><td>pixel spacing between wrapped lines</td></tr><tr><td>tabs</td><td>PangoTabArray in use</td></tr><tr><td>wrap_mode</td><td>mode of wrap in use</td></tr><tr><td>language</td><td>PangoLanguage in use</td></tr><tr><td>invisible</td><td>whether text is invisible (not implemented in GTK+ 2.0)</td></tr><tr><td>bg_full_height</td><td>whether background is fit to full line height</td></tr><tr><td>editable</td><td>whether the text is editable</td></tr><tr><td>realized</td><td>text is realized</td></tr><tr><td>pad1</td><td> </td></tr><tr><td>pad2</td><td> </td></tr><tr><td>pad3</td><td> </td></tr><tr><td>pad4</td><td> </td></tr></tbody></table></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2856416"></a>13.4.3. Copying a TextIter</h3></div></div><div></div></div><p>A <tt class="classname">TextIter</tt> can be duplicated using the
+method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ iter_copy = iter.copy()
+</pre></td></tr></table></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2856436"></a>13.4.4. Retrieving Text and Objects</h3></div></div><div></div></div><p>Various amounts of text and <tt class="classname">TextBuffer</tt>
+objects can be retrieved from a <tt class="classname">TextBuffer</tt> using the
+following methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ char = iter.get_char() # returns char or 0 if at end of buffer
+
+ text = start.get_slice(<b class="parameter"><tt>end</tt></b>) # returns the text between start and end iters
+
+ text = start.get_text(<b class="parameter"><tt>end</tt></b>) # returns the text between start and end iters
+
+ pixbuf = iter.get_pixbuf() # returns the pixbuf at the location (or None)
+
+ anchor = iter.get_child_anchor() # returns the child anchor (or None)
+
+ mark_list = iter.get_marks() # returns a list of marks
+
+ tag_list = iter.get_toggled_tags() # returns a list of tags that are toggled on or off
+
+ tag_list = iter.get_tags() # returns a prioritized list of tags
+</pre></td></tr></table></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2856479"></a>13.4.5. Checking Conditions at a TextIter</h3></div></div><div></div></div><p>Tag conditions at the <tt class="classname">TextIter</tt> location
+can be checked using the following methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ result = iter.begins_tag(<b class="parameter"><tt>tag</tt></b>=None) # TRUE if tag is toggled on at iter
+
+ result = iter.ends_tag(<b class="parameter"><tt>tag</tt></b>=None) # TRUE if tag is toggled off at iter
+
+ result = iter.toggles_tag(<b class="parameter"><tt>tag</tt></b>=None) # TRUE if tag is toggled on or off at iter
+
+ result = iter.has_tag(<b class="parameter"><tt>tag</tt></b>) # TRUE if tag is active at iter
+</pre></td></tr></table><p>These methods return <tt class="literal">TRUE</tt> if the given
+<i class="parameter"><tt>tag</tt></i> satisfies the condition at
+<i class="parameter"><tt>iter</tt></i>. If the <i class="parameter"><tt>tag</tt></i> is <tt class="literal">None</tt> for
+the first three methods then the result is <tt class="literal">TRUE</tt> if any
+tag satisfies the condition at <i class="parameter"><tt>iter</tt></i>.</p><p>The following methods indicate whether the text at the
+<tt class="classname">TextIter</tt> location is editable or allows text
+insertion:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ result = iter.editable()
+
+ result = iter.can_insert(<b class="parameter"><tt>default_editability</tt></b>)
+</pre></td></tr></table><p>The <tt class="methodname">editable</tt>() method indicates whether
+the <i class="parameter"><tt>iter</tt></i> is in an editable range of text while the
+<tt class="methodname">can_insert</tt>() method indicates whether text can be
+inserted at <i class="parameter"><tt>iter</tt></i> considering the default editability
+of the <tt class="classname">TextView</tt>, <tt class="classname">TextBuffer</tt>
+and applicable tags. The <i class="parameter"><tt>default_editability</tt></i> is
+usually determined by calling the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ default_editability = textview.get_editable()
+</pre></td></tr></table><p>The equivalence of two <tt class="classname">TextIter</tt>s can be
+determined with the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ are_equal = lhs.equal(<b class="parameter"><tt>rhs</tt></b>)
+</pre></td></tr></table><p>Two <tt class="classname">TextIter</tt>s can be compared with the
+method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ result = lhs.compare(<b class="parameter"><tt>rhs</tt></b>)
+</pre></td></tr></table><p><i class="parameter"><tt>result</tt></i> will be: -1 if
+<i class="parameter"><tt>lhs</tt></i> is less than <i class="parameter"><tt>rhs</tt></i>; 0 if
+<i class="parameter"><tt>lhs</tt></i> equals <i class="parameter"><tt>rhs</tt></i>; and, 1 if
+<i class="parameter"><tt>lhs</tt></i> is greater than <i class="parameter"><tt>rhs</tt></i>.</p><p>To determine whether a <tt class="classname">TextIter</tt> is
+located between two given <tt class="classname">TextIter</tt>s use the
+method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ result = iter.in_range(<b class="parameter"><tt>start</tt></b>, <b class="parameter"><tt>end</tt></b>)
+</pre></td></tr></table><p><i class="parameter"><tt>result</tt></i> is <tt class="literal">TRUE</tt> if
+<i class="parameter"><tt>iter</tt></i> is between <i class="parameter"><tt>start</tt></i> and
+<i class="parameter"><tt>end</tt></i>. Note: <i class="parameter"><tt>start</tt></i> and
+<i class="parameter"><tt>end</tt></i> must be in ascending order. This can be
+guaranteed using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ first.order(<b class="parameter"><tt>second</tt></b>)
+</pre></td></tr></table><p>which will reorder the <tt class="classname">TextIter</tt> offsets
+so that <i class="parameter"><tt>first</tt></i> is before
+<i class="parameter"><tt>second</tt></i>.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2856726"></a>13.4.6. Checking Location in Text</h3></div></div><div></div></div><p>The location of a <tt class="classname">TextIter</tt> with respect
+to the text in a <tt class="classname">TextBuffer</tt> can be determined by the
+following methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ result = iter.starts_word()
+
+ result = iter.ends_word()
+
+ result = iter.inside_word()
+
+ result = iter.starts_sentence()
+
+ result = iter.ends_sentence()
+
+ result = iter.inside_sentence()
+
+ result = starts_line()
+
+ result = iter.ends_line()
+</pre></td></tr></table><p><i class="parameter"><tt>result</tt></i> returns <tt class="literal">TRUE</tt> if
+the <tt class="classname">TextIter</tt> is at the given text location. These
+methods are somewhat self-explanatory. The definition of the text components
+and their boundaries is determined by the language used at the
+<tt class="classname">TextIter</tt>. Note that a line is a collection of
+sentences similar to a paragraph.</p><p>The following methods can be used to determine if a
+<tt class="classname">TextIter</tt> is at the start or end of the
+<tt class="classname">TextBuffer</tt>:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ result = iter.is_start()
+
+ result = iter.is_end()
+</pre></td></tr></table><p><i class="parameter"><tt>result</tt></i> is <tt class="literal">TRUE</tt> if the
+<tt class="classname">TextIter</tt> is at the start or end of the
+<tt class="classname">TextBuffer</tt>.</p><p>Since a <tt class="classname">TextBuffer</tt> may
+contain multiple characters which are effectively viewed as one cursor
+position (e.g. carriage return-linefeed combination or letter with an accent
+mark) it's possible that a <tt class="classname">TextIter</tt> could be in a
+location which is not a cursor position. The following method indicates
+whether a <tt class="classname">TextIter</tt> is at a cursor position:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ result = iter.is_cursor_position()
+</pre></td></tr></table></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2856824"></a>13.4.7. Moving Through Text</h3></div></div><div></div></div><p><tt class="classname">TextIter</tt>s can be moved through a
+<tt class="classname">TextBuffer</tt> in various text unit strides. The
+definition of the text units is set by the
+<tt class="classname">PangoLanguage</tt> in use at the
+<tt class="classname">TextIter</tt> location. The basic methods are:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ result = iter.forward_char() # forward by one character
+
+ result = iter.backward_char() # backward by one character
+
+ result = iter.forward_word_end() # forward to the end of the word
+
+ result = iter.backward_word_start() # backward to the start of the word
+
+ result = iter.forward_sentence_end() # forward to the end of the sentence
+
+ result = iter.backward_sentence_start() # backward to the start of the sentence
+
+ result = iter.forward_line() # forward to the start of the next line
+
+ result = iter.backward_line() # backward to the start of the previous line
+
+ result = iter.forward_to_line_end() # forward to the end of the line
+
+ result = iter.forward_cursor_position() # forward by one cursor position
+
+ result = iter.backward_cursor_position() # forward by one cursor position
+</pre></td></tr></table><p><i class="parameter"><tt>result</tt></i> is <tt class="literal">TRUE</tt> if the
+<tt class="classname">TextIter</tt> was moved and <tt class="literal">FALSE</tt> if
+the <tt class="classname">TextIter</tt> is at the start or end of the
+<tt class="classname">TextBuffer</tt>.</p><p>All of the above methods (except
+<tt class="methodname">forward_to_line_end</tt>()) have corresponding methods
+that take a count (that can be positive or negative) to move the
+<tt class="classname">TextIter</tt> in multiple text unit strides:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ result = iter.forward_chars(<b class="parameter"><tt>count</tt></b>)
+
+ result = iter.backward_chars(<b class="parameter"><tt>count</tt></b>)
+
+ result = iter.forward_word_ends(<b class="parameter"><tt>count</tt></b>)
+
+ result = iter.backward_word_starts(<b class="parameter"><tt>count</tt></b>)
+
+ result = iter.forward_sentence_ends(<b class="parameter"><tt>count</tt></b>)
+
+ result = iter.backward_sentence_starts(<b class="parameter"><tt>count</tt></b>)
+
+ result = iter.forward_lines(<b class="parameter"><tt>count</tt></b>)
+
+ result = iter.backward_lines(<b class="parameter"><tt>count</tt></b>)
+
+ result = iter.forward_cursor_positions(<b class="parameter"><tt>count</tt></b>)
+
+ result = iter.backward_cursor_positions(<b class="parameter"><tt>count</tt></b>)
+</pre></td></tr></table></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2856958"></a>13.4.8. Moving to a Specific Location</h3></div></div><div></div></div><p>A <tt class="classname">TextIter</tt> can be moved to a specific
+location in the <tt class="classname">TextBuffer</tt> using the
+following methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ iter.set_offset(<b class="parameter"><tt>char_offset</tt></b>) # move to given character offset
+
+ iter.set_line(<b class="parameter"><tt>line_number</tt></b>) # move to start of given line
+
+ iter.set_line_offset(<b class="parameter"><tt>char_on_line</tt></b>) # move to given character offset in current line
+
+ iter.forward_to_end() # move to end of the buffer
+</pre></td></tr></table><p>In addition, a <tt class="classname">TextIter</tt> can be moved to
+a location where a tag is toggled on or off by using the methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ result = iter.forward_to_tag_toggle(<b class="parameter"><tt>tag</tt></b>)
+
+ result = iter.backward_to_tag_taoggle(<b class="parameter"><tt>tag</tt></b>)
+</pre></td></tr></table><p><i class="parameter"><tt>result</tt></i> is <tt class="literal">TRUE</tt> if the
+<tt class="classname">TextIter</tt> was moved to a new location where
+<i class="parameter"><tt>tag</tt></i> is toggled. If <i class="parameter"><tt>tag</tt></i> is
+<tt class="literal">None</tt> then the <tt class="classname">TextIter</tt> will be
+moved to the next location where any tag is toggled.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id2857050"></a>13.4.9. Searching in Text</h3></div></div><div></div></div><p>A search for a string in a <tt class="classname">TextBuffer</tt> is
+done using the methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ match_start, match_end = iter.forward_search(<b class="parameter"><tt>str</tt></b>, <b class="parameter"><tt>flags</tt></b>, <b class="parameter"><tt>limit</tt></b>=None)
+
+ match_start, match_end = iter.backward_search(<b class="parameter"><tt>str</tt></b>, <b class="parameter"><tt>flags</tt></b>, <b class="parameter"><tt>limit</tt></b>=None)
+</pre></td></tr></table><p>The <i class="parameter"><tt>return</tt></i> value is a tuple containing
+<tt class="classname">TextIter</tt>s that indicate the location of the first
+character of the match and the first character after the match.
+<i class="parameter"><tt>str</tt></i> is the character string to be located.
+<i class="parameter"><tt>flags</tt></i> modifies the conditions of the search;
+<i class="parameter"><tt>flag</tt></i> values can be:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ gtk.TEXT_SEARCH_VISIBLE_ONLY # invisible characters are ignored
+
+ gtk.TEXT_SEARCH_TEXT_ONLY # pixbufs and child anchors are ignored
+</pre></td></tr></table><p><i class="parameter"><tt>limit</tt></i> is an optional
+<tt class="classname">TextIter</tt> that bounds the search range.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-TextBuffers.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-TextViewWidget.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-TextMarks.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">13.3. Text Buffers </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 13.5. Text Marks</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-TextMarks.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-TextMarks.html
new file mode 100644
index 0000000..a4f80ca
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-TextMarks.html
@@ -0,0 +1,31 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>13.5. Text Marks</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-TextViewWidget.html" title="Chapter 13. TextView Widget"><link rel="previous" href="sec-TextIters.html" title="13.4. Text Iters"><link rel="next" href="sec-TextTagsAndTextTagTables.html" title="13.6. Text Tags and Tag Tables"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">13.5. Text Marks</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-TextIters.html">Prev</a> </td><th width="60%" align="center">Chapter 13. TextView Widget</th><td width="20%" align="right"> <a accesskey="n" href="sec-TextTagsAndTextTagTables.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-TextMarks"></a>13.5. Text Marks</h2></div></div><div></div></div><p>A <tt class="classname">TextMark</tt> indicates a location in a
+<tt class="classname">TextBuffer</tt> between two characters that is preserved
+across buffer modifications. <tt class="classname">TextMark</tt>s are created,
+moved and deleted using the <tt class="classname">TextBuffer</tt> methods as
+described in the <tt class="classname">TextBuffer</tt> section.</p><p>A <tt class="classname">TextBuffer</tt> has two built-in
+<tt class="classname">TextMark</tt>s named: <i class="parameter"><tt>insert</tt></i> and
+<i class="parameter"><tt>selection_bound</tt></i> which refer to the insertion point
+and the boundary of the selection (these may refer to the same
+location).</p><p>The name of a <tt class="classname">TextMark</tt> can be retrieved
+using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ name = textmark.get_name()
+</pre></td></tr></table><p>By default marks other than insert are not visible (displayed as a
+vertical bar). The visibility of a mark can be set and retrieved using the
+methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ setting = textmark.get_visible()
+
+ textmark.set_visible(<b class="parameter"><tt>setting</tt></b>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>setting</tt></i> is <tt class="literal">TRUE</tt> if
+the mark is visible.</p><p>The <tt class="classname">TextBuffer</tt> that contains a
+<tt class="classname">TextMark</tt> can be obtained using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ buffer = textmark.get_buffer()
+</pre></td></tr></table><p>You can determine whether a <tt class="classname">TextMark</tt> has
+been deleted using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ setting = textmark.get_deleted()
+</pre></td></tr></table><p>The left gravity of a <tt class="classname">TextMark</tt> can be
+retrieved using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ setting = textmark.get_left_gravity()
+</pre></td></tr></table><p>The left gravity of a <tt class="classname">TextMark</tt> indicates
+where the mark will end up after an insertion. If left gravity is
+<tt class="literal">TRUE</tt> the mark will be to the left of the insertion; if
+<tt class="literal">FALSE</tt>, to the right of the insertion.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-TextIters.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-TextViewWidget.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-TextTagsAndTextTagTables.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">13.4. Text Iters </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 13.6. Text Tags and Tag Tables</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-TextTagsAndTextTagTables.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-TextTagsAndTextTagTables.html
new file mode 100644
index 0000000..486c8c8
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-TextTagsAndTextTagTables.html
@@ -0,0 +1,61 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>13.6. Text Tags and Tag Tables</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-TextViewWidget.html" title="Chapter 13. TextView Widget"><link rel="previous" href="sec-TextMarks.html" title="13.5. Text Marks"><link rel="next" href="sec-TextViewExample.html" title="13.7. A TextView Example"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">13.6. Text Tags and Tag Tables</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-TextMarks.html">Prev</a> </td><th width="60%" align="center">Chapter 13. TextView Widget</th><td width="20%" align="right"> <a accesskey="n" href="sec-TextViewExample.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-TextTagsAndTextTagTables"></a>13.6. Text Tags and Tag Tables</h2></div></div><div></div></div><p>TextTags specify attributes that can be applied to a range of text
+in a TextBuffer. Each <tt class="classname">TextBuffer</tt> has a
+<tt class="classname">TextTagTable</tt> that contains the
+<tt class="classname">TextTag</tt>s that can be applied within the
+<tt class="classname">TextBuffer</tt>. <tt class="classname">TextTagTable</tt>s can
+be used with more than one <tt class="classname">TextBuffer</tt> to provide
+consistent text styles.</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-TextTags"></a>13.6.1. Text Tags</h3></div></div><div></div></div><p><tt class="classname">TextTag</tt>s can be named or anonymous. A
+<tt class="classname">TextTag</tt> is created using the function:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ tag = gtk.TextTag(<b class="parameter"><tt>name</tt></b>=None)
+</pre></td></tr></table><p>If <i class="parameter"><tt>name</tt></i> is not specified or is
+<tt class="literal">None</tt> the <i class="parameter"><tt>tag</tt></i> will be
+anonymous. <tt class="classname">TextTag</tt>s can also be created using the
+<tt class="classname">TextBuffer</tt> convenience method
+<tt class="methodname">create_tag</tt>() which also allows you specify the
+<i class="parameter"><tt>tag</tt></i> attributes and adds the
+<i class="parameter"><tt>tag</tt></i> to the buffer's tag table (see <a href="sec-TextBuffers.html" title="13.3. Text Buffers">Section 13.3, “Text Buffersâ€</a>).</p><p>The attributes that can be contained in a
+<tt class="classname">TextTag</tt> are:</p><div class="informaltable"><table width="100%" border="1"><colgroup><col><col><col></colgroup><tbody><tr><td>name</td><td>Read / Write</td><td>Name of the text tag. <tt class="literal">None</tt> if anonymous.</td></tr><tr><td>background</td><td>Write</td><td>Background color as a string</td></tr><tr><td>foreground</td><td>Write</td><td>Foreground color as a string</td></tr><tr><td>background-gdk</td><td>Read / Write</td><td>Background color as a GdkColor</td></tr><tr><td>foreground-gdk</td><td>Read / Write</td><td>Foreground color as a GdkColor</td></tr><tr><td>background-stipple</td><td>Read / Write</td><td>Bitmap to use as a mask when drawing the text background</td></tr><tr><td>foreground-stipple</td><td>Read / Write</td><td>Bitmap to use as a mask when drawing the text foreground</td></tr><tr><td>font</td><td>Read / Write</td><td>Font description as a string, e.g. "Sans Italic 12"</td></tr><tr><td>font-desc</td><td>Read / Write</td><td>Font description as a PangoFontDescription </td></tr><tr><td>family</td><td>Read / Write</td><td>Name of the font family, e.g. Sans, Helvetica, Times, Monospace</td></tr><tr><td>style</td><td>Read / Write</td><td>Font style as a PangoStyle, e.g. pango.STYLE_ITALIC.</td></tr><tr><td>variant</td><td>Read / Write</td><td>Font variant as a PangoVariant, e.g. pango.VARIANT_SMALL_CAPS.</td></tr><tr><td>weight</td><td>Read / Write</td><td>Font weight as an integer, see predefined values in PangoWeight; for example, pango.WEIGHT_BOLD.</td></tr><tr><td>stretch</td><td>Read / Write</td><td>Font stretch as a PangoStretch, e.g. pango.STRETCH_CONDENSED.</td></tr><tr><td>size</td><td>Read / Write</td><td>Font size in Pango units.</td></tr><tr><td>size-points</td><td>Read / Write</td><td>Font size in points</td></tr><tr><td>scale</td><td>Read / Write</td><td>Font size as a scale factor relative to the default font size. This properly adapts to theme changes etc. so is recommended. Pango predefines some scales such as pango.SCALE_X_LARGE.</td></tr><tr><td>pixels-above-lines</td><td>Read / Write</td><td>Pixels of blank space above paragraphs</td></tr><tr><td>pixels-below-lines</td><td>Read / Write</td><td>Pixels of blank space below paragraphs</td></tr><tr><td>pixels-inside-wrap</td><td>Read / Write</td><td>Pixels of blank space between wrapped lines in a paragraph</td></tr><tr><td>editable</td><td>Read / Write</td><td>Whether the text can be modified by the user</td></tr><tr><td>wrap-mode</td><td>Read / Write</td><td>Whether to wrap lines never, at word boundaries, or at character boundaries</td></tr><tr><td>justification</td><td>Read / Write</td><td>Left, right, or center justification</td></tr><tr><td>direction</td><td>Read / Write</td><td>Text direction, e.g. right-to-left or left-to-right</td></tr><tr><td>left-margin</td><td>Read / Write</td><td>Width of the left margin in pixels</td></tr><tr><td>indent</td><td>Read / Write</td><td>Amount to indent the paragraph, in pixels</td></tr><tr><td>strikethrough</td><td>Read / Write</td><td>Whether to strike through the text</td></tr><tr><td>right-margin</td><td>Read / Write</td><td>Width of the right margin in pixels</td></tr><tr><td>underline</td><td>Read / Write</td><td>Style of underline for this text</td></tr><tr><td>rise</td><td>Read / Write</td><td>Offset of text above the baseline (below the baseline if rise is negative) in pixels</td></tr><tr><td>background-full-height</td><td>Read / Write</td><td>Whether the background color fills the entire line height or only the height of the tagged characters</td></tr><tr><td>language</td><td>Read / Write</td><td>The language this text is in, as an ISO code. Pango can use this as a hint when rendering the text. If you don't understand this parameter, you probably don't need it.</td></tr><tr><td>tabs</td><td>Read / Write</td><td>Custom tabs for this text</td></tr><tr><td>invisible</td><td>Read / Write</td><td>Whether this text is hidden. Not implemented in GTK+ 2.0</td></tr></tbody></table></div><p>The attributes can be set by using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ tag.set_property(name, value)
+</pre></td></tr></table><p>Where <i class="parameter"><tt>name</tt></i> is a string containing the
+name of the property and <i class="parameter"><tt>value</tt></i> is what the property
+should be set to.</p><p>Likewise the attribute value can be retrieved with the
+method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ value = tag.get_property(name)
+</pre></td></tr></table><p>Since the tag does not have a value set for every attribute
+there are a set of boolean properties that indicate whether the attribute
+has been set in the tag:</p><div class="informaltable"><table width="100%" border="1"><colgroup><col><col></colgroup><tbody><tr><td>background-set</td><td>Read / Write</td></tr><tr><td>foreground-set</td><td>Read / Write</td></tr><tr><td>background-stipple-set</td><td>Read / Write</td></tr><tr><td>foreground-stipple-set</td><td>Read / Write</td></tr><tr><td>family-set</td><td>Read / Write</td></tr><tr><td>style-set</td><td>Read / Write</td></tr><tr><td>variant-set</td><td>Read / Write</td></tr><tr><td>weight-set</td><td>Read / Write</td></tr><tr><td>stretch-set</td><td>Read / Write</td></tr><tr><td>size-set</td><td>Read / Write</td></tr><tr><td>scale-set</td><td>Read / Write</td></tr><tr><td>pixels-above-lines-set</td><td>Read / Write</td></tr><tr><td>pixels-below-lines-set</td><td>Read / Write</td></tr><tr><td>pixels-inside-wrap-set</td><td>Read / Write</td></tr><tr><td>editable-set</td><td>Read / Write</td></tr><tr><td>wrap-mode-set</td><td>Read / Write</td></tr><tr><td>justification-set</td><td>Read / Write</td></tr><tr><td>direction-set</td><td>Read / Write</td></tr><tr><td>left-margin-set</td><td>Read / Write</td></tr><tr><td>indent-set</td><td>Read / Write</td></tr><tr><td>strikethrough-set</td><td>Read / Write</td></tr><tr><td>right-margin-set</td><td>Read / Write</td></tr><tr><td>underline-set</td><td>Read / Write</td></tr><tr><td>rise-set</td><td>Read / Write</td></tr><tr><td>background-full-height-set</td><td>Read / Write</td></tr><tr><td>language-set</td><td>Read / Write</td></tr><tr><td>tabs-set</td><td>Read / Write</td></tr><tr><td>invisible-set</td><td>Read / Write</td></tr></tbody></table></div><p>Therefore to obtain the attribute from a tag, you have to
+first check whether the attribute has been set in the tag. For example to
+get a valid justification attribute you may have to do something
+like:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ if tag.get_property("justification-set"):
+ justification = tag.get_property("justification")
+</pre></td></tr></table><p>The priority of a tag is by default the order in which they are
+added to the <tt class="classname">TextTagTable</tt>. The higher priority tag
+takes precedence if multiple tags try to set the same attribute for a range
+of text. The priority can be obtained and set with the methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ priority = tag.get_priority()
+
+ tag.set_priority(<b class="parameter"><tt>priority</tt></b>)
+</pre></td></tr></table><p>The priority of a tag must be between 0 and one less than the
+<tt class="classname">TextTagTable</tt> size.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-TextTagTables"></a>13.6.2. Text Tag Tables</h3></div></div><div></div></div><p>A <tt class="classname">TextTagTable</tt> will be created by default
+when a <tt class="classname">TextBuffer</tt> is created. A
+<tt class="classname">TextTagTable</tt> can also be created with the
+function:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ table = TextTagTable()
+</pre></td></tr></table><p>A <tt class="classname">TextTag</tt> can be added to a
+<tt class="classname">TextTagTable</tt> using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ table.add(<b class="parameter"><tt>tag</tt></b>)
+</pre></td></tr></table><p>The <i class="parameter"><tt>tag</tt></i> must not be in the
+<i class="parameter"><tt>table</tt></i> and must not have the same name as another tag
+in the table.</p><p>You can find a <tt class="classname">TextTag</tt> in a
+<tt class="classname">TextTagTable</tt> using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ tag = table.lookup(<b class="parameter"><tt>name</tt></b>)
+</pre></td></tr></table><p>The method returns the <i class="parameter"><tt>tag</tt></i> in the table
+with the given <i class="parameter"><tt>name</tt></i> or <tt class="literal">None</tt> if no
+tag has that <i class="parameter"><tt>name</tt></i>.</p><p>A <tt class="classname">TextTag</tt> can be removed from a
+<tt class="classname">TextTagTable</tt> with the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ table.remove(<b class="parameter"><tt>tag</tt></b>)
+</pre></td></tr></table><p>The size of the <tt class="classname">TextTagTable</tt> can be
+obtained with the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ size = table.get_size()
+</pre></td></tr></table></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-TextMarks.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-TextViewWidget.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-TextViewExample.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">13.5. Text Marks </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 13.7. A TextView Example</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-TextViewExample.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-TextViewExample.html
new file mode 100644
index 0000000..f29ccab
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-TextViewExample.html
@@ -0,0 +1,75 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>13.7. A TextView Example</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-TextViewWidget.html" title="Chapter 13. TextView Widget"><link rel="previous" href="sec-TextTagsAndTextTagTables.html" title="13.6. Text Tags and Tag Tables"><link rel="next" href="ch-TreeViewWidget.html" title="Chapter 14. Tree View Widget"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">13.7. A TextView Example</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-TextTagsAndTextTagTables.html">Prev</a> </td><th width="60%" align="center">Chapter 13. TextView Widget</th><td width="20%" align="right"> <a accesskey="n" href="ch-TreeViewWidget.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-TextViewExample"></a>13.7. A TextView Example</h2></div></div><div></div></div><p>The <a href="examples/testtext.py" target="_top"><span><b class="command">testtext.py</b></span></a> example
+program (derived from the <tt class="filename">testtext.c</tt> program included
+in the GTK+ 2.0.x distribution) demonstrates the use of the
+<tt class="classname">TextView</tt> widget and its associated objects:
+<tt class="classname">TextBuffer</tt>s, <tt class="classname">TextIter</tt>s,
+<tt class="classname">TextMark</tt>s, <tt class="classname">TextTag</tt>s,
+<tt class="classname">TextTagTable</tt>s. <a href="sec-TextViewExample.html#testtextfig" title="Figure 13.2. TextView Example">Figure 13.2, “TextView Exampleâ€</a>
+illustrates its operation:</p><div class="figure"><a name="testtextfig"></a><p class="title"><b>Figure 13.2. TextView Example</b></p><div class="mediaobject" align="center"><img src="figures/testtext.png" align="middle" alt="TextView Example"></div></div><p>The <a href="examples/testtext.py" target="_top"><span><b class="command">testtext.py</b></span></a> program
+defines a number of classes in addition to the application class
+<tt class="classname">TestText</tt>:</p><div class="itemizedlist"><ul type="disc"><li><p><tt class="classname">Buffer</tt> class, lines 99-496, is
+subclassed from the <tt class="classname">gtk.TextBuffer</tt> type. It provides
+the editing buffer capabilities used by the <tt class="classname">View</tt>
+objects.</p></li><li><p><tt class="classname">View</tt> class, lines 498-1126, is
+subclassed from the <tt class="classname">gtk.Window</tt> type and wraps a
+<tt class="classname">gtk.TextView</tt> object that uses a
+<tt class="classname">Buffer</tt> object instead of a
+<tt class="classname">gtk.TextBuffer</tt> object. It provides a window and the
+visual display of the contents of a <tt class="classname">Buffer</tt> object as
+well as a menubar.</p></li><li><p><tt class="classname">FileSel</tt> class, lines 73-97, is
+subclassed from the <tt class="classname">gtk.FileSelection</tt> type to provide
+selection of filenames for the <tt class="classname">Buffer</tt>
+contents.</p></li><li><p><tt class="classname">Stack</tt> class to provide simple stack
+objects.</p></li></ul></div><p>The color cycle display is implemented by using text tags applied
+to a section of text in a buffer. Lines 109-115 (in the
+<tt class="methodname">__init__</tt>() method) create these tags and lines
+763-784 (<tt class="methodname">do_apply_colors</tt>() method) apply the color
+tags to a section of text two characters at a time. Lines 202-239 provide
+the methods (<tt class="methodname">color_cycle_timeout</tt>(),
+<tt class="methodname">set_colors</tt>() and
+<tt class="methodname">cycle_colors</tt>()) that produce the color cycle
+display when enabled. Color cycling is enabled by setting (line 220) the
+<i class="parameter"><tt>foreground_gdk</tt></i> property of the individual
+<i class="parameter"><tt>color_tags</tt></i> (which also sets the
+<i class="parameter"><tt>foreground_set</tt></i> property). Color cycling is disabled
+by setting the <i class="parameter"><tt>foreground_set</tt></i> property to
+<tt class="literal">FALSE</tt> (line 222). The colors are periodically changed by
+shifting the <i class="parameter"><tt>start_hue</tt></i> (line 237)</p><p>A new <tt class="classname">Buffer</tt> is filled with example content
+when the
+<span class="guimenu">Test</span>-&gt;<span class="guimenuitem">Example</span>
+menu item is selected (the <tt class="methodname">fill_example_buffer</tt>()
+method in lines 302-372). The example buffer contains text of various
+colors, styles and languages and pixbufs. The
+<tt class="methodname">init_tags</tt>() method (lines 260-300) sets up a
+variety of <tt class="classname">TextTag</tt>s for use with the example text.
+The event signal of these tags is connected to the
+<tt class="methodname">tag_event_handler</tt>() method (lines 241-256) to
+illustrate button and motion event capture.</p><p>The <tt class="classname">TextView</tt> wrap mode is set to WRAP_WORD
+(line 580) and the <tt class="classname">TextView</tt> border windows are
+displayed by setting their sizes in lines 587-588 and line 596-597. The left
+and right border windows are used to display line numbers and the top and
+bottom border windows display the tab locations when custom tabs are
+set. The border windows are updated when an "expose-event" signal is
+received by the <tt class="classname">TextView</tt> (lines 590 and 599). The
+<tt class="methodname">line_numbers_expose</tt>() method (lines 1079-1116)
+determines whether the left or right border window has an expose event and
+if so calculates the size of the expose area. Then the location of the line
+start and the line number for each line in the exposed area is calculated in
+the <tt class="methodname">get_lines</tt>() method (lines 1057-1077). The line
+numbers are then drawn in the border window at the location (transformed by
+line 1109).</p><p>The custom tab locations are displayed in the top and bottom
+border windows in a similar fashion (lines 1013-1055). They are displayed
+only when the cursor is moved inside a range of text that has the custom tab
+attribute set. This is detected by handling the "mark-set" signal in the
+<tt class="methodname">cursor_set_handler</tt>() method (lines 999-1011) and
+invalidating the top and bottom border windows if the mark set is the
+<i class="parameter"><tt>insert</tt></i> mark.</p><p>Movable widgets are added to a <tt class="classname">View</tt> with
+the <tt class="methodname">do_add_children</tt>() method (lines 892-899) which
+calls the <tt class="methodname">add_movable_children</tt>() method (lines
+874-890). The children are <tt class="classname">gtk.Label</tt>s that can be
+dragged around inside the various windows that are part of a
+<tt class="classname">TextView</tt> widget.</p><p>Likewise, widgets are added to the <tt class="classname">TextView</tt>
+windows of a <tt class="classname">View</tt> and the
+<tt class="classname">Buffer</tt> by using the
+<tt class="methodname">do_add_focus_children</tt>() method (lines
+901-949).</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-TextTagsAndTextTagTables.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-TextViewWidget.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch-TreeViewWidget.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">13.6. Text Tags and Tag Tables </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 14. Tree View Widget</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-TextViews.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-TextViews.html
new file mode 100644
index 0000000..b3d71d0
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-TextViews.html
@@ -0,0 +1,267 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>13.2. TextViews</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-TextViewWidget.html" title="Chapter 13. TextView Widget"><link rel="previous" href="ch-TextViewWidget.html" title="Chapter 13. TextView Widget"><link rel="next" href="sec-TextBuffers.html" title="13.3. Text Buffers"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">13.2. TextViews</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch-TextViewWidget.html">Prev</a> </td><th width="60%" align="center">Chapter 13. TextView Widget</th><td width="20%" align="right"> <a accesskey="n" href="sec-TextBuffers.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-TextViews"></a>13.2. TextViews</h2></div></div><div></div></div><p>There is only one function for creating a new
+<tt class="classname">TextView</tt> widget.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ textview = gtk.TextView(<b class="parameter"><tt>buffer</tt></b>=None)
+</pre></td></tr></table><p>When a <tt class="classname">TextView</tt> is created it will create
+an associated <tt class="classname">TextBuffer</tt> and
+<tt class="classname">TextTagTable</tt> by default. If you want to use an
+existing <tt class="classname">TextBuffer</tt> in a
+<tt class="classname">TextView</tt> specify it in the above method. To change
+the <tt class="classname">TextBuffer</tt> used by a
+<tt class="classname">TextView</tt> use the following method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ textview.set_buffer(<b class="parameter"><tt>buffer</tt></b>)
+</pre></td></tr></table><p>Use the following method to retrieve a reference to the
+<tt class="classname">TextBuffer</tt> from a
+<tt class="classname">TextView</tt>:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ buffer = textview.get_buffer()
+</pre></td></tr></table><p>A <tt class="classname">TextView</tt> widget doesn't have scrollbars
+to adjust the view in case the text is larger than the window. To provide
+scrollbars, you add the <tt class="classname">TextView</tt> to a
+<tt class="classname">ScrolledWindow</tt> (see <a href="sec-ScrolledWindows.html" title="10.9. Scrolled Windows">Section 10.9, “Scrolled Windowsâ€</a>).</p><p>A <tt class="classname">TextView</tt> can be used to allow the user
+to edit a body of text, or to display multiple lines of read-only text to
+the user. To switch between these modes of operation, the use the following
+method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ textview.set_editable(<b class="parameter"><tt>setting</tt></b>)
+</pre></td></tr></table><p>The <i class="parameter"><tt>setting</tt></i> argument is a
+<tt class="literal">TRUE</tt> or <tt class="literal">FALSE</tt> value that specifies
+whether the user is permitted to edit the contents of the
+<tt class="classname">TextView</tt> widget. The editable mode of the
+<tt class="classname">TextView</tt> can be overridden in text ranges within the
+<tt class="classname">TextBuffer</tt> by <tt class="classname">TextTag</tt>s.</p><p>You can retrieve the current editable setting using the
+method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ setting = textview.get_editable()
+</pre></td></tr></table><p>When the <tt class="classname">TextView</tt> is not editable, you
+probably should hide the cursor using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ textview.set_cursor_visible(<b class="parameter"><tt>setting</tt></b>)
+</pre></td></tr></table><p>The <i class="parameter"><tt>setting</tt></i> argument is a
+<tt class="literal">TRUE</tt> or <tt class="literal">FALSE</tt> value that specifies
+whether the cursor should be visible The <tt class="classname">TextView</tt> can
+wrap lines of text that are too long to fit onto a single line of the
+display window. Its default behavior is to not wrap lines. This can be
+changed using the next method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ textview.set_wrap_mode(<b class="parameter"><tt>wrap_mode</tt></b>)
+</pre></td></tr></table><p>This method allows you to specify that the text widget should
+wrap long lines on word or character boundaries. The
+<i class="parameter"><tt>word_wrap</tt></i> argument is one of:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ gtk.WRAP_NONE
+ gtk.WRAP_CHAR
+ gtk.WRAP_WORD
+</pre></td></tr></table><p>The default justification of the text in a
+<tt class="classname">TextView</tt> can be set and retrieved using the
+methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ textview.set_justification(<b class="parameter"><tt>justification</tt></b>)
+ justification = textview.get_justification()
+</pre></td></tr></table><p>where <i class="parameter"><tt>justification</tt></i> is one of:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ gtk.JUSTIFY_LEFT
+ gtk.JUSTIFY_RIGHT
+ gtk.JUSTIFY_CENTER
+</pre></td></tr></table><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>The <i class="parameter"><tt>justification</tt></i> will be
+<tt class="literal">JUSTIFY_LEFT</tt> if the <i class="parameter"><tt>wrap_mode</tt></i> is
+<tt class="literal">WRAP_NONE</tt>. Tags in the associated
+<tt class="classname">TextBuffer</tt> may override the default
+justification.</p></div><p>Other default attributes that can be set and retrieved in a
+<tt class="classname">TextView</tt> are: left margin, right margin, tabs, and
+paragraph indentation using the following methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ textview.set_left_margin(<b class="parameter"><tt>left_margin</tt></b>)
+ left_margin = textview.get_left_margin()
+
+ textview.set_right_margin(<b class="parameter"><tt>right_margin</tt></b>)
+ right_margin = textview.get_right_margin()
+
+ textview.set_indent(<b class="parameter"><tt>indent</tt></b>)
+ indent = textview.get_indent()
+
+ textview.set_pixels_above_lines(<b class="parameter"><tt>pixels_above_line</tt></b>)
+ pixels_above_line = textview.get_pixels_above_lines()
+
+ textview.set_pixels_below_lines(<b class="parameter"><tt>pixels_below_line</tt></b>)
+ pixels_below_line = textview.get_pixels_below_lines()
+
+ textview.set_pixels_inside_wrap(<b class="parameter"><tt>pixels_inside_wrap</tt></b>)
+ pixels_inside_wrap = textview.get_pixels_inside_wrap()
+
+ textview.set_tabs(<b class="parameter"><tt>tabs</tt></b>)
+ tabs = textview.get_tabs()
+</pre></td></tr></table><p><i class="parameter"><tt>left_margin</tt></i>,
+<i class="parameter"><tt>right_margin</tt></i>, <i class="parameter"><tt>indent</tt></i>,
+<i class="parameter"><tt>pixels_above_lines</tt></i>,
+<i class="parameter"><tt>pixels_below_lines</tt></i> and
+<i class="parameter"><tt>pixels_inside_wrap</tt></i> are specified in pixels. These
+default values may be overridden by tags in the associated
+<tt class="classname">TextBuffer</tt>. <i class="parameter"><tt>tabs</tt></i> is a
+<tt class="classname">pango.TabArray</tt>.</p><p>The <a href="examples/textview-basic.py" target="_top"><span><b class="command">textview-basic.py</b></span></a>
+example program illustrates basic use of the <tt class="classname">TextView</tt>
+widget:</p><div class="figure"><a name="textviewbasicfig"></a><p class="title"><b>Figure 13.1. Basic TextView Example</b></p><div class="mediaobject" align="center"><img src="figures/textview-basic.png" align="middle" alt="Basic TextView Example"></div></div><p>The source code for the program is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 1 #!/usr/bin/env python
+ 2
+ 3 # example textview-basic.py
+ 4
+ 5 import pygtk
+ 6 pygtk.require('2.0')
+ 7 import gtk
+ 8
+ 9 class TextViewExample:
+ 10 def toggle_editable(self, checkbutton, textview):
+ 11 textview.set_editable(checkbutton.get_active())
+ 12
+ 13 def toggle_cursor_visible(self, checkbutton, textview):
+ 14 textview.set_cursor_visible(checkbutton.get_active())
+ 15
+ 16 def toggle_left_margin(self, checkbutton, textview):
+ 17 if checkbutton.get_active():
+ 18 textview.set_left_margin(50)
+ 19 else:
+ 20 textview.set_left_margin(0)
+ 21
+ 22 def toggle_right_margin(self, checkbutton, textview):
+ 23 if checkbutton.get_active():
+ 24 textview.set_right_margin(50)
+ 25 else:
+ 26 textview.set_right_margin(0)
+ 27
+ 28 def new_wrap_mode(self, radiobutton, textview, val):
+ 29 if radiobutton.get_active():
+ 30 textview.set_wrap_mode(val)
+ 31
+ 32 def new_justification(self, radiobutton, textview, val):
+ 33 if radiobutton.get_active():
+ 34 textview.set_justification(val)
+ 35
+ 36 def close_application(self, widget):
+ 37 gtk.main_quit()
+ 38
+ 39 def __init__(self):
+ 40 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ 41 window.set_resizable(True)
+ 42 window.connect("destroy", self.close_application)
+ 43 window.set_title("TextView Widget Basic Example")
+ 44 window.set_border_width(0)
+ 45
+ 46 box1 = gtk.VBox(False, 0)
+ 47 window.add(box1)
+ 48 box1.show()
+ 49
+ 50 box2 = gtk.VBox(False, 10)
+ 51 box2.set_border_width(10)
+ 52 box1.pack_start(box2, True, True, 0)
+ 53 box2.show()
+ 54
+ 55 sw = gtk.ScrolledWindow()
+ 56 sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+ 57 textview = gtk.TextView()
+ 58 textbuffer = textview.get_buffer()
+ 59 sw.add(textview)
+ 60 sw.show()
+ 61 textview.show()
+ 62
+ 63 box2.pack_start(sw)
+ 64 # Load the file textview-basic.py into the text window
+ 65 infile = open("textview-basic.py", "r")
+ 66
+ 67 if infile:
+ 68 string = infile.read()
+ 69 infile.close()
+ 70 textbuffer.set_text(string)
+ 71
+ 72 hbox = gtk.HButtonBox()
+ 73 box2.pack_start(hbox, False, False, 0)
+ 74 hbox.show()
+ 75
+ 76 vbox = gtk.VBox()
+ 77 vbox.show()
+ 78 hbox.pack_start(vbox, False, False, 0)
+ 79 # check button to toggle editable mode
+ 80 check = gtk.CheckButton("Editable")
+ 81 vbox.pack_start(check, False, False, 0)
+ 82 check.connect("toggled", self.toggle_editable, textview)
+ 83 check.set_active(True)
+ 84 check.show()
+ 85 # check button to toggle cursor visiblity
+ 86 check = gtk.CheckButton("Cursor Visible")
+ 87 vbox.pack_start(check, False, False, 0)
+ 88 check.connect("toggled", self.toggle_cursor_visible, textview)
+ 89 check.set_active(True)
+ 90 check.show()
+ 91 # check button to toggle left margin
+ 92 check = gtk.CheckButton("Left Margin")
+ 93 vbox.pack_start(check, False, False, 0)
+ 94 check.connect("toggled", self.toggle_left_margin, textview)
+ 95 check.set_active(False)
+ 96 check.show()
+ 97 # check button to toggle right margin
+ 98 check = gtk.CheckButton("Right Margin")
+ 99 vbox.pack_start(check, False, False, 0)
+ 100 check.connect("toggled", self.toggle_right_margin, textview)
+ 101 check.set_active(False)
+ 102 check.show()
+ 103 # radio buttons to specify wrap mode
+ 104 vbox = gtk.VBox()
+ 105 vbox.show()
+ 106 hbox.pack_start(vbox, False, False, 0)
+ 107 radio = gtk.RadioButton(None, "WRAP__NONE")
+ 108 vbox.pack_start(radio, False, True, 0)
+ 109 radio.connect("toggled", self.new_wrap_mode, textview, gtk.WRAP_NONE)
+ 110 radio.set_active(True)
+ 111 radio.show()
+ 112 radio = gtk.RadioButton(radio, "WRAP__CHAR")
+ 113 vbox.pack_start(radio, False, True, 0)
+ 114 radio.connect("toggled", self.new_wrap_mode, textview, gtk.WRAP_CHAR)
+ 115 radio.show()
+ 116 radio = gtk.RadioButton(radio, "WRAP__WORD")
+ 117 vbox.pack_start(radio, False, True, 0)
+ 118 radio.connect("toggled", self.new_wrap_mode, textview, gtk.WRAP_WORD)
+ 119 radio.show()
+ 120
+ 121 # radio buttons to specify justification
+ 122 vbox = gtk.VBox()
+ 123 vbox.show()
+ 124 hbox.pack_start(vbox, False, False, 0)
+ 125 radio = gtk.RadioButton(None, "JUSTIFY__LEFT")
+ 126 vbox.pack_start(radio, False, True, 0)
+ 127 radio.connect("toggled", self.new_justification, textview,
+ 128 gtk.JUSTIFY_LEFT)
+ 129 radio.set_active(True)
+ 130 radio.show()
+ 131 radio = gtk.RadioButton(radio, "JUSTIFY__RIGHT")
+ 132 vbox.pack_start(radio, False, True, 0)
+ 133 radio.connect("toggled", self.new_justification, textview,
+ 134 gtk.JUSTIFY_RIGHT)
+ 135 radio.show()
+ 136 radio = gtk.RadioButton(radio, "JUSTIFY__CENTER")
+ 137 vbox.pack_start(radio, False, True, 0)
+ 138 radio.connect("toggled", self.new_justification, textview,
+ 139 gtk.JUSTIFY_CENTER)
+ 140 radio.show()
+ 141
+ 142 separator = gtk.HSeparator()
+ 143 box1.pack_start(separator, False, True, 0)
+ 144 separator.show()
+ 145
+ 146 box2 = gtk.VBox(False, 10)
+ 147 box2.set_border_width(10)
+ 148 box1.pack_start(box2, False, True, 0)
+ 149 box2.show()
+ 150
+ 151 button = gtk.Button("close")
+ 152 button.connect("clicked", self.close_application)
+ 153 box2.pack_start(button, True, True, 0)
+ 154 button.set_flags(gtk.CAN_DEFAULT)
+ 155 button.grab_default()
+ 156 button.show()
+ 157 window.show()
+ 158
+ 159 def main():
+ 160 gtk.main()
+ 161 return 0
+ 162
+ 163 if __name__ == "__main__":
+ 164 TextViewExample()
+ 165 main()
+</pre></td></tr></table><p>Lines 10-34 define the callbacks for the radio and check buttons
+used to change the default attributes of the
+<tt class="classname">TextView</tt>. Lines 55-63 create a
+<tt class="classname">ScrolledWindow</tt> to contain the
+<tt class="classname">TextView</tt>. The <tt class="classname">ScrolledWindow</tt>
+is packed into a <tt class="classname">VBox</tt> with the check and radio
+buttons created in lines 72-140. The <tt class="classname">TextBuffer</tt>
+associated with the <tt class="classname">TextView</tt> is loaded with the
+contents of the source file in lines 64-70.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch-TextViewWidget.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-TextViewWidget.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-TextBuffers.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 13. TextView Widget </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 13.3. Text Buffers</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-TheoryOfSignalsAndCallbacks.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-TheoryOfSignalsAndCallbacks.html
new file mode 100644
index 0000000..a4acccd
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-TheoryOfSignalsAndCallbacks.html
@@ -0,0 +1,50 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>2.2. Theory of Signals and Callbacks</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-GettingStarted.html" title="Chapter 2. Getting Started"><link rel="previous" href="ch-GettingStarted.html" title="Chapter 2. Getting Started"><link rel="next" href="sec-Events.html" title="2.3. Events"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2.2. Theory of Signals and Callbacks</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch-GettingStarted.html">Prev</a> </td><th width="60%" align="center">Chapter 2. Getting Started</th><td width="20%" align="right"> <a accesskey="n" href="sec-Events.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-TheoryOfSignalsAndCallbacks"></a>2.2. Theory of Signals and Callbacks</h2></div></div><div></div></div><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>In GTK+ version 2.0, the signal system has been moved from GTK
+to GLib. We won't go into details about the extensions which the GLib 2.0
+signal system has relative to the GTK+ 1.2 signal system. The differences
+should not be apparent to PyGTK users.</p></div><p> Before we look in detail at <a href="examples/helloworld.py" target="_top"><span><b class="command">helloworld.py</b></span></a>, we'll
+discuss signals and callbacks. GTK+ is an event driven toolkit, which means
+it will sleep in <tt class="function">gtk.main</tt>() until an event occurs and
+control is passed to the appropriate function.</p><p>This passing of control is done using the idea of "signals".
+(Note that these signals are not the same as the Unix system signals, and
+are not implemented using them, although the terminology is almost
+identical.) When an event occurs, such as the press of a mouse button, the
+appropriate signal will be "emitted" by the widget that was pressed. This is
+how GTK+ does most of its useful work. There are signals that all widgets
+inherit, such as "destroy", and there are signals that are widget specific,
+such as "toggled" on a toggle button.</p><p>To make a button perform an action, we set up a signal handler
+to catch these signals and call the appropriate function. This is done by
+using a <tt class="classname">GtkWidget</tt> (from the
+<tt class="classname">GObject</tt> class) method such as:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ handler_id = object.connect(name, func, func_data)
+</pre></td></tr></table><p>where object is the <tt class="classname">GtkWidget</tt> instance
+which will be emitting the signal, and the first argument
+<i class="parameter"><tt>name</tt></i> is a string containing the name of the signal you
+wish to catch. The second argument, <i class="parameter"><tt>func</tt></i>, is the
+function you wish to be called when it is caught, and the third,
+<i class="parameter"><tt>func_data</tt></i>, the data you wish to pass to this function.
+The method returns a <span class="returnvalue">handler_id</span> that can be used
+to disconnect or block the handler.</p><p>The function specified in the second argument is called a
+"callback function", and should generally be of the form:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def callback_func(widget, callback_data):
+</pre></td></tr></table><p>where the first argument will be a pointer to the
+<i class="parameter"><tt>widget</tt></i> that emitted the signal, and the second
+(<i class="parameter"><tt>callback_data</tt></i>) a pointer to the data given as the last
+argument to the <tt class="methodname">connect</tt>() method as shown above.</p><p>If the callback function is an object method then it will have
+the general form:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def callback_meth(self, widget, callback_data):
+</pre></td></tr></table><p>where <i class="parameter"><tt>self</tt></i> is the object instance
+invoking the method. This is the form used in the <a href="examples/helloworld.py" target="_top"><span><b class="command">helloworld.py</b></span></a>
+example program.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>The above form for a signal callback function declaration
+is only a general guide, as some widget specific signals generate different
+calling parameters.</p></div><p>Another call used in the <a href="examples/helloworld.py" target="_top"><span><b class="command">helloworld.py</b></span></a>
+example is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ handler_id = object.connect_object(name, func, slot_object)
+</pre></td></tr></table><p><tt class="methodname">connect_object</tt>() is the same as
+<tt class="methodname">connect</tt>() except a callback function only uses one
+argument and a callback method, two arguments:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def callback_func(object)
+ def callback_meth(self, object)
+</pre></td></tr></table><p>where <i class="parameter"><tt>object</tt></i> is usually a widget.
+<tt class="methodname">connect_object</tt>() allows the PyGTK widget methods
+that only take a single argument (<i class="parameter"><tt>self</tt></i>) to be used as
+signal handlers.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch-GettingStarted.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-GettingStarted.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-Events.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 2. Getting Started </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 2.3. Events</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-ToggleButtons.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-ToggleButtons.html
new file mode 100644
index 0000000..f6ba699
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-ToggleButtons.html
@@ -0,0 +1,130 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>6.2. Toggle Buttons</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-ButtonWidget.html" title="Chapter 6. The Button Widget"><link rel="previous" href="ch-ButtonWidget.html" title="Chapter 6. The Button Widget"><link rel="next" href="sec-CheckButtons.html" title="6.3. Check Buttons"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">6.2. Toggle Buttons</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch-ButtonWidget.html">Prev</a> </td><th width="60%" align="center">Chapter 6. The Button Widget</th><td width="20%" align="right"> <a accesskey="n" href="sec-CheckButtons.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-ToggleButtons"></a>6.2. Toggle Buttons</h2></div></div><div></div></div><p>Toggle buttons are derived from normal buttons and are very
+similar, except they will always be in one of two states, alternated by a
+click. They may be depressed, and when you click again, they will pop back
+up. Click again, and they will pop back down.</p><p>Toggle buttons are the basis for check buttons and radio
+buttons, as such, many of the calls used for toggle buttons are inherited by
+radio and check buttons. I will point these out when we come to them.</p><p>Creating a new toggle button:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ toggle_button = gtk.ToggleButton(<b class="parameter"><tt>label</tt></b>=None)
+</pre></td></tr></table><p>As you can imagine, these work identically to the normal button
+widget calls. If no label is specified the button will be blank. The label
+text will be parsed for '_'-prefixed mnemonic characters.</p><p>To retrieve the state of the toggle widget, including radio and
+check buttons, we use a construct as shown in our example below. This tests
+the state of the toggle, by calling the <tt class="methodname">get_active</tt>()
+method of the toggle button object. The signal of interest to us that is
+emitted by toggle buttons (the toggle button, check button, and radio button
+widgets) is the "toggled" signal. To check the state of these buttons, set
+up a signal handler to catch the toggled signal, and access the object
+attributes to determine its state. The callback will look something
+like:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def toggle_button_callback(widget, data):
+ if widget.get_active():
+ # If control reaches here, the toggle button is down
+ else:
+ # If control reaches here, the toggle button is up
+</pre></td></tr></table><p>To force the state of a toggle button, and its children, the
+radio and check buttons, use this method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ toggle_button.set_active(<b class="parameter"><tt>is_active</tt></b>)
+</pre></td></tr></table><p>The above method can be used to set the state of the toggle
+button, and its children the radio and check buttons. Specifying a
+<tt class="literal">TRUE</tt> or <tt class="literal">FALSE</tt> for the
+<i class="parameter"><tt>is_active</tt></i> argument indicates whether the button
+should be down (depressed) or up (released). When the toggle button is
+created its default is up or <tt class="literal">FALSE</tt>.</p><p>Note that when you use the <tt class="methodname">set_active</tt>()
+method, and the state is actually changed, it causes the "clicked" and
+"toggled" signals to be emitted from the button.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ toggle_button.get_active()
+</pre></td></tr></table><p>This method returns the current state of the toggle button as a
+boolean <tt class="literal">TRUE</tt> or <tt class="literal">FALSE</tt> value.</p><p>The <a href="examples/togglebutton.py" target="_top"><span><b class="command">togglebutton.py</b></span></a>
+program provides a simple example using toggle buttons.
+<a href="sec-ToggleButtons.html#togglefig" title="Figure 6.2. Toggle Button Example">Figure 6.2, “Toggle Button Exampleâ€</a> illustrates the resulting window with the second
+toggle button active:</p><div class="figure"><a name="togglefig"></a><p class="title"><b>Figure 6.2. Toggle Button Example</b></p><div class="mediaobject" align="center"><img src="figures/toggle.png" align="middle" alt="Toggle Button Example"></div></div><p>The source code for the program is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 1 #!/usr/bin/env python
+ 2
+ 3 # example togglebutton.py
+ 4
+ 5 import pygtk
+ 6 pygtk.require('2.0')
+ 7 import gtk
+ 8
+ 9 class ToggleButton:
+ 10 # Our callback.
+ 11 # The data passed to this method is printed to stdout
+ 12 def callback(self, widget, data=None):
+ 13 print "%s was toggled %s" % (data, ("OFF", "ON")[widget.get_active()])
+ 14
+ 15 # This callback quits the program
+ 16 def delete_event(self, widget, event, data=None):
+ 17 gtk.main_quit()
+ 18 return False
+ 19
+ 20 def __init__(self):
+ 21 # Create a new window
+ 22 self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ 23
+ 24 # Set the window title
+ 25 self.window.set_title("Toggle Button")
+ 26
+ 27 # Set a handler for delete_event that immediately
+ 28 # exits GTK.
+ 29 self.window.connect("delete_event", self.delete_event)
+ 30
+ 31 # Sets the border width of the window.
+ 32 self.window.set_border_width(20)
+ 33
+ 34 # Create a vertical box
+ 35 vbox = gtk.VBox(True, 2)
+ 36
+ 37 # Put the vbox in the main window
+ 38 self.window.add(vbox)
+ 39
+ 40 # Create first button
+ 41 button = gtk.ToggleButton("toggle button 1")
+ 42
+ 43 # When the button is toggled, we call the "callback" method
+ 44 # with a pointer to "button" as its argument
+ 45 button.connect("toggled", self.callback, "toggle button 1")
+ 46
+ 47
+ 48 # Insert button 1
+ 49 vbox.pack_start(button, True, True, 2)
+ 50
+ 51 button.show()
+ 52
+ 53 # Create second button
+ 54
+ 55 button = gtk.ToggleButton("toggle button 2")
+ 56
+ 57 # When the button is toggled, we call the "callback" method
+ 58 # with a pointer to "button 2" as its argument
+ 59 button.connect("toggled", self.callback, "toggle button 2")
+ 60 # Insert button 2
+ 61 vbox.pack_start(button, True, True, 2)
+ 62
+ 63 button.show()
+ 64
+ 65 # Create "Quit" button
+ 66 button = gtk.Button("Quit")
+ 67
+ 68 # When the button is clicked, we call the main_quit function
+ 69 # and the program exits
+ 70 button.connect("clicked", lambda wid: gtk.main_quit())
+ 71
+ 72 # Insert the quit button
+ 73 vbox.pack_start(button, True, True, 2)
+ 74
+ 75 button.show()
+ 76 vbox.show()
+ 77 self.window.show()
+ 78
+ 79 def main():
+ 80 gtk.main()
+ 81 return 0
+ 82
+ 83 if __name__ == "__main__":
+ 84 ToggleButton()
+ 85 main()
+</pre></td></tr></table><p>The interesting lines are 12-13 which define the
+<tt class="methodname">callback</tt>() method that prints the toggle button
+label and its state when it is toggled. Lines 45 and 59 connect the
+"toggled" signal of the toggle buttons to the
+<tt class="methodname">callback</tt>() method.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch-ButtonWidget.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-ButtonWidget.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-CheckButtons.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 6. The Button Widget </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 6.3. Check Buttons</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-Toolbar.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-Toolbar.html
new file mode 100644
index 0000000..59afc19
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-Toolbar.html
@@ -0,0 +1,258 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>10.11. Toolbar</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-ContainerWidgets.html" title="Chapter 10. Container Widgets"><link rel="previous" href="sec-ButtonBoxes.html" title="10.10. Button Boxes"><link rel="next" href="sec-Notebooks.html" title="10.12. Notebooks"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">10.11. Toolbar</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-ButtonBoxes.html">Prev</a> </td><th width="60%" align="center">Chapter 10. Container Widgets</th><td width="20%" align="right"> <a accesskey="n" href="sec-Notebooks.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-Toolbar"></a>10.11. Toolbar</h2></div></div><div></div></div><p><tt class="classname">Toolbars</tt> are usually used to group some
+number of widgets in order to simplify customization of their look and
+layout. Typically a toolbar consists of buttons with icons, labels and
+tooltips, but any other widget can also be put inside a toolbar. Finally,
+items can be arranged horizontally or vertically and buttons can be
+displayed with icons, labels, or both.</p><p>Creating a toolbar is (as one may already suspect) done with the
+following function:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ toolbar = gtk.Toolbar()
+</pre></td></tr></table><p>After creating a toolbar one can append, prepend and insert
+items (that means simple text strings) or elements (that means any widget
+types) into the toolbar. To describe an item we need a label text, a tooltip
+text, a private tooltip text, an icon for the button and a callback for it.
+For example, to append or prepend an item you may use the following
+methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ toolbar.append_item(<b class="parameter"><tt>text</tt></b>, <b class="parameter"><tt>tooltip_text</tt></b>, <b class="parameter"><tt>tooltip_private_text</tt></b>, <b class="parameter"><tt>icon</tt></b>, <b class="parameter"><tt>callback</tt></b>, <b class="parameter"><tt>user_data</tt></b>=None)
+
+ toolbar.prepend_item(<b class="parameter"><tt>text</tt></b>, <b class="parameter"><tt>tooltip_text</tt></b>, <b class="parameter"><tt>tooltip_private_text</tt></b>, <b class="parameter"><tt>icon</tt></b>, <b class="parameter"><tt>callback</tt></b>, <b class="parameter"><tt>user_data</tt></b>)
+</pre></td></tr></table><p>If you want to use the <tt class="methodname">insert_item</tt>()
+method, the only additional parameter which must be specified is the
+position in which the item should be inserted, thus:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ toolbar.insert_item(<b class="parameter"><tt>text</tt></b>, <b class="parameter"><tt>tooltip_text</tt></b>, <b class="parameter"><tt>tooltip_private_text</tt></b>, <b class="parameter"><tt>icon</tt></b>, <b class="parameter"><tt>callback</tt></b>,
+ <b class="parameter"><tt>user_data</tt></b>, <b class="parameter"><tt>position</tt></b>)
+</pre></td></tr></table><p>To simplify adding spaces between toolbar items, you may use the
+following methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ toolbar.append_space()
+
+ toolbar.prepend_space()
+
+ toolbar.insert_space(<b class="parameter"><tt>position</tt></b>)
+</pre></td></tr></table><p>If it's required, the orientation of a toolbar, its style and
+whether tooltips are available can be changed "on the fly" using the
+following methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ toolbar.set_orientation(<b class="parameter"><tt>orientation</tt></b>)
+
+ toolbar.set_style(<b class="parameter"><tt>style</tt></b>)
+
+ toolbar.set_tooltips(<b class="parameter"><tt>enable</tt></b>)
+</pre></td></tr></table><p>Where <i class="parameter"><tt>orientation</tt></i> is one of
+<tt class="literal">ORIENTATION_HORIZONTAL</tt> or
+<tt class="literal">ORIENTATION_VERTICAL</tt>. The <i class="parameter"><tt>style</tt></i> is
+used to set appearance of the toolbar items by using one of
+<tt class="literal">TOOLBAR_ICONS</tt>, <tt class="literal">TOOLBAR_TEXT</tt>, or
+<tt class="literal">TOOLBAR_BOTH</tt>. The <i class="parameter"><tt>enable</tt></i> argument
+is either <tt class="literal">TRUE</tt> or <tt class="literal">FALSE</tt>.</p><p>To show some other things that can be done with a toolbar, let's
+take the <a href="examples/toolbar.py" target="_top"><span><b class="command">toolbar.py</b></span></a> example
+program (we'll interrupt the listing with some additional
+explanations):</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 1 #!/usr/bin/env python
+ 2
+ 3 # example toolbar.py
+ 4
+ 5 import pygtk
+ 6 pygtk.require('2.0')
+ 7 import gtk
+ 8
+ 9 class ToolbarExample:
+ 10 # This method is connected to the Close button or
+ 11 # closing the window from the WM
+ 12 def delete_event(self, widget, event=None):
+ 13 gtk.main_quit()
+ 14 return False
+ 15
+ </pre></td></tr></table><p>The above beginning seems should be familiar to you if it's not your
+first PyGTK program. There is one additional thing though, we import a nice
+XPM picture (<a href="examples/gtk.xpm" target="_top"><tt class="filename">gtk.xpm</tt></a>)to serve as an
+icon for all of the buttons. Line 10 starts the
+<tt class="classname">ToolbarExample</tt> class and lines 12-14 define the
+callback method which will terminate the program.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 16 # that's easy... when one of the buttons is toggled, we just
+ 17 # check which one is active and set the style of the toolbar
+ 18 # accordingly
+ 19 def radio_event(self, widget, toolbar):
+ 20 if self.text_button.get_active():
+ 21 toolbar.set_style(gtk.TOOLBAR_TEXT)
+ 22 elif self.icon_button.get_active():
+ 23 toolbar.set_style(gtk.TOOLBAR_ICONS)
+ 24 elif self.both_button.get_active():
+ 25 toolbar.set_style(gtk.TOOLBAR_BOTH)
+ 26
+ 27 # even easier, just check given toggle button and enable/disable
+ 28 # tooltips
+ 29 def toggle_event(self, widget, toolbar):
+ 30 toolbar.set_tooltips(widget.get_active())
+ 31
+ </pre></td></tr></table><p>Lines 19-30 are two callback methods that will be called when
+one of the buttons on a toolbar is pressed. You should already be familiar
+with things like this if you've already used toggle buttons (and radio
+buttons).</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 32 def __init__(self):
+ 33 # Here is our main window (a dialog) and a handle for the handlebox
+ 34 # Ok, we need a toolbar, an icon with a mask (one for all of
+ 35 # the buttons) and an icon widget to put this icon in (but
+ 36 # we'll create a separate widget for each button)
+ 37 # create a new window with a given title, and nice size
+ 38 dialog = gtk.Dialog()
+ 39 dialog.set_title("GTKToolbar Tutorial")
+ 40 dialog.set_size_request(450, 250)
+ 41 dialog.set_resizable(True)
+ 42
+ 43 # typically we quit if someone tries to close us
+ 44 dialog.connect("delete_event", self.delete_event)
+ 45
+ 46 # to make it nice we'll put the toolbar into the handle box,
+ 47 # so that it can be detached from the main window
+ 48 handlebox = gtk.HandleBox()
+ 49 dialog.vbox.pack_start(handlebox, False, False, 5)
+ 50
+ </pre></td></tr></table><p>The above should be similar to any other PyGTK application. Just
+initialization of a <tt class="classname">ToolbarExample</tt> object instance
+creating the window, etc. There is only one thing that probably needs some
+explanation: a handle box. A handle box is just another box that can be used
+to pack widgets in to. The difference between it and typical boxes is that
+it can be detached from a parent window (or, in fact, the handle box remains
+in the parent, but it is reduced to a very small rectangle, while all of its
+contents are reparented to a new freely floating window). It is usually nice
+to have a detachable toolbar, so these two widgets occur together quite
+often.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 51 # toolbar will be horizontal, with both icons and text, and
+ 52 # with 5pxl spaces between items and finally,
+ 53 # we'll also put it into our handlebox
+ 54 toolbar = gtk.Toolbar()
+ 55 toolbar.set_orientation(gtk.ORIENTATION_HORIZONTAL)
+ 56 toolbar.set_style(gtk.TOOLBAR_BOTH)
+ 57 toolbar.set_border_width(5)
+ 58 handlebox.add(toolbar)
+ 59
+ </pre></td></tr></table><p>Well, what we do above is just a straightforward initialization
+of the toolbar widget.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 60 # our first item is &lt;close&gt; button
+ 61 iconw = gtk.Image() # icon widget
+ 62 iconw.set_from_file("gtk.xpm")
+ 63 close_button = toolbar.append_item(
+ 64 "Close", # button label
+ 65 "Closes this app", # this button's tooltip
+ 66 "Private", # tooltip private info
+ 67 iconw, # icon widget
+ 68 self.delete_event) # a signal
+ 69 toolbar.append_space() # space after item
+ </pre></td></tr></table><p>In the above code you see the simplest case: adding a button to
+toolbar. Just before appending a new item, we have to construct an image
+widget to serve as an icon for this item; this step will have to be repeated
+for each new item. Just after the item we also add a space, so the following
+items will not touch each other. As you see the
+<tt class="methodname">append_item</tt>() method returns a reference to our
+newly created button widget, so that we can work with it in the normal
+way.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 71 # now, let's make our radio buttons group...
+ 72 iconw = gtk.Image() # icon widget
+ 73 iconw.set_from_file("gtk.xpm")
+ 74 icon_button = toolbar.append_element(
+ 75 gtk.TOOLBAR_CHILD_RADIOBUTTON, # type of element
+ 76 None, # widget
+ 77 "Icon", # label
+ 78 "Only icons in toolbar", # tooltip
+ 79 "Private", # tooltip private string
+ 80 iconw, # icon
+ 81 self.radio_event, # signal
+ 82 toolbar) # data for signal
+ 83 toolbar.append_space()
+ 84 self.icon_button = icon_button
+ 85
+ </pre></td></tr></table><p>Here we begin creating a radio buttons group. To do this we use
+the <tt class="methodname">append_element</tt>() method. In fact, using this
+method one can also add simple items or even spaces
+(<i class="parameter"><tt>type</tt></i> = <tt class="literal">gtk.TOOLBAR_CHILD_SPACE</tt> or
+<tt class="literal">gtk.TOOLBAR_CHILD_BUTTON</tt>). In the above case we start
+creating a radio group. In creating other radio buttons for this group a
+reference to the previous button in the group is required, so that a list of
+buttons can be easily constructed (see <a href="sec-RadioButtons.html" title="6.4. Radio Buttons">Section 6.4, “Radio Buttonsâ€</a> earlier in this tutorial). We also save a
+reference to the button in the <tt class="classname">ToolbarExample</tt>
+instance for later access.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 86 # following radio buttons refer to previous ones
+ 87 iconw = gtk.Image() # icon widget
+ 88 iconw.set_from_file("gtk.xpm")
+ 89 text_button = toolbar.append_element(
+ 90 gtk.TOOLBAR_CHILD_RADIOBUTTON,
+ 91 icon_button,
+ 92 "Text",
+ 93 "Only texts in toolbar",
+ 94 "Private",
+ 95 iconw,
+ 96 self.radio_event,
+ 97 toolbar)
+ 98 toolbar.append_space()
+ 99 self.text_button = text_button
+ 100
+ 101 iconw = gtk.Image() # icon widget
+ 102 iconw.set_from_file("gtk.xpm")
+ 103 both_button = toolbar.append_element(
+ 104 gtk.TOOLBAR_CHILD_RADIOBUTTON,
+ 105 text_button,
+ 106 "Both",
+ 107 "Icons and text in toolbar",
+ 108 "Private",
+ 109 iconw,
+ 110 self.radio_event,
+ 111 toolbar)
+ 112 toolbar.append_space()
+ 113 self.both_button = both_button
+ 114 both_button.set_active(True)
+ 115
+ </pre></td></tr></table><p>We create the other radiobuttons the same way except we pass one
+of the created radio group buttons to the
+<tt class="methodname">append_element</tt>() method to specify the radio
+group.</p><p>In the end we have to set the state of one of the buttons
+manually (otherwise they all stay in active state, preventing us from
+switching between them).</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 116 # here we have just a simple toggle button
+ 117 iconw = gtk.Image() # icon widget
+ 118 iconw.set_from_file("gtk.xpm")
+ 119 tooltips_button = toolbar.append_element(
+ 120 gtk.TOOLBAR_CHILD_TOGGLEBUTTON,
+ 121 None,
+ 122 "Tooltips",
+ 123 "Toolbar with or without tips",
+ 124 "Private",
+ 125 iconw,
+ 126 self.toggle_event,
+ 127 toolbar)
+ 128 toolbar.append_space()
+ 129 tooltips_button.set_active(True)
+ 130
+ </pre></td></tr></table><p>A toggle button can be created in the obvious way (if one knows
+how to create radio buttons already).</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 131 # to pack a widget into toolbar, we only have to
+ 132 # create it and append it with an appropriate tooltip
+ 133 entry = gtk.Entry()
+ 134 toolbar.append_widget(entry, "This is just an entry", "Private")
+ 135
+ 136 # well, it isn't created within the toolbar, so we must still show it
+ 137 entry.show()
+ 138
+ </pre></td></tr></table><p>As you see, adding any kind of widget to a toolbar is simple.
+The one thing you have to remember is that this widget must be shown
+manually (contrary to items which will be shown together with the
+toolbar).</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 139 # that's it ! let's show everything.
+ 140 toolbar.show()
+ 141 handlebox.show()
+ 142 dialog.show()
+ 143
+ 144 def main():
+ 145 # rest in gtk_main and wait for the fun to begin!
+ 146 gtk.main()
+ 147 return 0
+ 148
+ 149 if __name__ == "__main__":
+ 150 ToolbarExample()
+ 151 main()
+</pre></td></tr></table><p>Line 142 ends the <tt class="classname">ToolbarExample</tt> class
+definition. Lines 144-147 define the <tt class="function">main</tt>() function
+which just calls the <tt class="function">gtk.main</tt>() function to start the
+event processing loop. Lines 149-151 arrange to create a
+<tt class="classname">ToolbarExample</tt> instance and then enter the event
+processing loop. So, here we are at the end of toolbar tutorial. Of course,
+to appreciate it in full you need also this nice XPM icon, <a href="examples/gtk.xpm" target="_top"><tt class="filename">gtk.xpm</tt></a>.
+<a href="sec-Toolbar.html#toolbarfig" title="Figure 10.8. Toolbar Example">Figure 10.8, “Toolbar Exampleâ€</a> illustrates the resulting
+display:</p><div class="figure"><a name="toolbarfig"></a><p class="title"><b>Figure 10.8. Toolbar Example</b></p><div class="mediaobject" align="center"><img src="figures/toolbar.png" align="middle" alt="Toolbar Example"></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-ButtonBoxes.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-ContainerWidgets.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-Notebooks.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">10.10. Button Boxes </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 10.12. Notebooks</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-TooltipsObject.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-TooltipsObject.html
new file mode 100644
index 0000000..43fc735
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-TooltipsObject.html
@@ -0,0 +1,99 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>9.3. The Tooltips Object</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-MiscellaneousWidgets.html" title="Chapter 9. Miscellaneous Widgets"><link rel="previous" href="sec-Arrows.html" title="9.2. Arrows"><link rel="next" href="sec-ProgressBars.html" title="9.4. Progress Bars"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">9.3. The Tooltips Object</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-Arrows.html">Prev</a> </td><th width="60%" align="center">Chapter 9. Miscellaneous Widgets</th><td width="20%" align="right"> <a accesskey="n" href="sec-ProgressBars.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-TooltipsObject"></a>9.3. The Tooltips Object</h2></div></div><div></div></div><p><tt class="classname">Tooltips</tt> are the little text strings that
+pop up when you leave your pointer over a button or other widget for a few
+seconds.</p><p>Widgets that do not receive events (widgets that do not have
+their own window) will not work with tooltips.</p><p>The first call you will use creates a new tooltip. You only need
+to do this once for a set of tooltips as the
+<tt class="classname">gtk.Tooltips</tt> object this function returns can be used
+to create multiple tooltips.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ tooltips = gtk.Tooltips()
+</pre></td></tr></table><p>Once you have created a new tooltip, and the widget you wish to use it
+on, simply use this call to set it:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ tooltips.set_tip(<b class="parameter"><tt>widget</tt></b>, <b class="parameter"><tt>tip_text</tt></b>, <b class="parameter"><tt>tip_private</tt></b>=None)
+</pre></td></tr></table><p>The object <i class="parameter"><tt>tooltips</tt></i> is the tooltip you've
+already created. The first argument (<i class="parameter"><tt>widget</tt></i>) is the
+widget you wish to have this tooltip pop up for; the second
+(<i class="parameter"><tt>tip_text</tt></i>), the text you wish it to display. The last
+argument (<i class="parameter"><tt>tip_private</tt></i>) is a text string that can be
+used as an identifier.</p><p>The <a href="examples/tooltip.py" target="_top"><span><b class="command">tooltip.py</b></span></a> example
+program modifies the <a href="examples/arrow.py" target="_top"><span><b class="command">arrow.py</b></span></a> program to add a
+tooltip for each button. <a href="sec-TooltipsObject.html#tooltipsfig" title="Figure 9.3. Tooltips Example">Figure 9.3, “Tooltips Exampleâ€</a> illustrates the
+resulting display with the tooltip for the second arrow button
+displayed:</p><div class="figure"><a name="tooltipsfig"></a><p class="title"><b>Figure 9.3. Tooltips Example</b></p><div class="mediaobject" align="center"><img src="figures/tooltips.png" align="middle" alt="Tooltips Example"></div></div><p>The source code for <a href="examples/tooltip.py" target="_top"><span><b class="command">tooltip.py</b></span></a> is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 1 #!/usr/bin/env python
+ 2
+ 3 # example tooltip.py
+ 4
+ 5 import pygtk
+ 6 pygtk.require('2.0')
+ 7 import gtk
+ 8
+ 9 # Create an Arrow widget with the specified parameters
+ 10 # and pack it into a button
+ 11 def create_arrow_button(arrow_type, shadow_type):
+ 12 button = gtk.Button()
+ 13 arrow = gtk.Arrow(arrow_type, shadow_type)
+ 14 button.add(arrow)
+ 15 button.show()
+ 16 arrow.show()
+ 17 return button
+ 18
+ 19 class Tooltips:
+ 20 def __init__(self):
+ 21 # Create a new window
+ 22 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ 23
+ 24 window.set_title("Tooltips")
+ 25
+ 26 # It's a good idea to do this for all windows.
+ 27 window.connect("destroy", lambda w: gtk.main_quit())
+ 28
+ 29 # Sets the border width of the window.
+ 30 window.set_border_width(10)
+ 31
+ 32 # Create a box to hold the arrows/buttons
+ 33 box = gtk.HBox(False, 0)
+ 34 box.set_border_width(2)
+ 35 window.add(box)
+ 36
+ 37 # create a tooltips object
+ 38 self.tooltips = gtk.Tooltips()
+ 39
+ 40 # Pack and show all our widgets
+ 41 box.show()
+ 42
+ 43 button = create_arrow_button(gtk.ARROW_UP, gtk.SHADOW_IN)
+ 44 box.pack_start(button, False, False, 3)
+ 45 self.tooltips.set_tip(button, "SHADOW_IN")
+ 46
+ 47 button = create_arrow_button(gtk.ARROW_DOWN, gtk.SHADOW_OUT)
+ 48 box.pack_start(button, False, False, 3)
+ 49 self.tooltips.set_tip(button, "SHADOW_OUT")
+ 50
+ 51 button = create_arrow_button(gtk.ARROW_LEFT, gtk.SHADOW_ETCHED_IN)
+ 52 box.pack_start(button, False, False, 3)
+ 53 self.tooltips.set_tip(button, "SHADOW_ETCHED_IN")
+ 54
+ 55 button = create_arrow_button(gtk.ARROW_RIGHT, gtk.SHADOW_ETCHED_OUT)
+ 56 box.pack_start(button, False, False, 3)
+ 57 self.tooltips.set_tip(button, "SHADOW_ETCHED_OUT")
+ 58
+ 59 window.show()
+ 60
+ 61 def main():
+ 62 gtk.main()
+ 63 return 0
+ 64
+ 65 if __name__ == "__main__":
+ 66 tt = Tooltips()
+ 67 main()
+</pre></td></tr></table><p>There are other methods that can be used with tooltips. I will
+just list them with a brief description of what they do.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ tooltips.enable()
+</pre></td></tr></table><p>Enable a disabled set of tooltips.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ tooltips.disable()
+</pre></td></tr></table><p>Disable an enabled set of tooltips.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ tooltips.set_delay(<b class="parameter"><tt>delay</tt></b>)
+</pre></td></tr></table><p>Sets how many milliseconds you have to hold your pointer over
+the widget before the tooltip will pop up. The default is 500 milliseconds
+(half a second).</p><p>And that's all the methods associated with tooltips. More than
+you'll ever want to know :-)</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-Arrows.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-MiscellaneousWidgets.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-ProgressBars.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">9.2. Arrows </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 9.4. Progress Bars</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-TreeModelInterface.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-TreeModelInterface.html
new file mode 100644
index 0000000..03b1d25
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-TreeModelInterface.html
@@ -0,0 +1,631 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>14.2. The TreeModel Interface and Data Stores</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-TreeViewWidget.html" title="Chapter 14. Tree View Widget"><link rel="previous" href="ch-TreeViewWidget.html" title="Chapter 14. Tree View Widget"><link rel="next" href="sec-TreeViews.html" title="14.3. TreeViews"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">14.2. The TreeModel Interface and Data Stores</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch-TreeViewWidget.html">Prev</a> </td><th width="60%" align="center">Chapter 14. Tree View Widget</th><td width="20%" align="right"> <a accesskey="n" href="sec-TreeViews.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-TreeModelInterface"></a>14.2. The TreeModel Interface and Data Stores</h2></div></div><div></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-TreeModelIntroduction"></a>14.2.1. Introduction</h3></div></div><div></div></div><p>The <tt class="classname">TreeModel</tt> interface is implemented by
+all the <tt class="classname">TreeModel</tt> subclasses and provides methods
+to:</p><div class="itemizedlist"><ul type="disc"><li>retrieve the characteristics of the data store such as
+the number of columns and the type of data in a column.</li><li>retrieve a <tt class="classname">TreeIter</tt> (a transient
+reference) that points at a row in the model</li><li>retrieve information about a node (or row) such as the
+number of its child nodes, a list of its child nodes, the contents of its
+columns and a pointer to its parent node</li><li>provide notification of <tt class="classname">TreeModel</tt>
+data changes</li></ul></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-CreatingTreeStoreAndListStore"></a>14.2.2. Creating TreeStore and ListStore Objects</h3></div></div><div></div></div><p>The base data store classes: <tt class="classname">ListStore</tt> and
+<tt class="classname">TreeStore</tt> provide the means to define and manage the
+rows and columns of data in the tree model. The constructors of both these
+objects require the column types to be specified as any of:</p><div class="itemizedlist"><ul type="disc"><li>Python types such as the built-in types: int, str, long,
+float and object</li><li>PyGTK types such as <tt class="classname">Button</tt>,
+<tt class="classname">VBox</tt>, <tt class="classname">gdk.Rectangle</tt>,
+<tt class="classname">gdk.Pixbuf</tt></li><li><p><tt class="classname">GObject</tt> types (GTK+ GTypes)
+specified either as GObject Type constants or as strings. Most GTypes are
+mapped to a Python type:</p><div class="itemizedlist"><ul type="circle"><li>gobject.TYPE_CHAR or 'gchar'</li><li>gobject.TYPE_UCHAR or 'guchar'</li><li>gobject.TYPE_BOOLEAN or 'gboolean'</li><li>gobject.TYPE_INT or 'gint'</li><li>gobject.TYPE_UINT or 'guint'</li><li>gobject.TYPE_LONG or 'glong</li><li>gobject.TYPE_ULONG or 'gulong</li><li>gobject.TYPE_INT64 or 'gint64'</li><li>gobject.TYPE_UINT64 or 'guint64'</li><li>gobject.TYPE_FLOAT or 'gfloat'</li><li>gobject.TYPE_DOUBLE or 'gdouble'</li><li>gobject.TYPE_STRING or 'gchararray'</li><li>gobject.TYPE_OBJECT or 'GObject</li></ul></div></li></ul></div><p>For example to create a <tt class="classname">ListStore</tt> or
+<tt class="classname">TreeStore</tt> with rows containing a
+<tt class="classname">gdk.Pixbuf</tt>, an integer, a string and boolean you
+could do something like:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ liststore = ListStore(gtk.gdk.Pixbuf, int, str, 'gboolean')
+
+ treestore = TreeStore(gtk.gdk.Pixbuf, int, str, 'gboolean')
+</pre></td></tr></table><p>Once a <tt class="classname">ListStore</tt> or
+<tt class="classname">TreeStore</tt> is created and its columns defined, they
+cannot be changed or modified. It's also important to realize that there is
+no preset relation between the columns in a <tt class="classname">TreeView</tt>
+and the columns of its <tt class="classname">TreeModel</tt>. That is, the fifth
+column of data in a <tt class="classname">TreeModel</tt> may be displayed in the
+first column of one <tt class="classname">TreeView</tt> and in the third column
+in another. So you don't have to worry about how the data will be displayed
+when creating the data store.</p><p>If these two data stores do not fit your application it is
+possible to define your own custom data store in Python as long as it
+implements the TreeModel interface. I'll talk more about this later in <a href="sec-GenericTreeModel.html" title="14.11. The Generic TreeModel">Section 14.11, “The Generic TreeModelâ€</a>.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-ReferringToTreeModelRows"></a>14.2.3. Referring to TreeModel Rows</h3></div></div><div></div></div><p>Before we can talk about managing the data rows in a
+<tt class="classname">TreeStore</tt> or <tt class="classname">ListStore</tt> we need
+a way of specifying which row we want to deal with. PyGTK has three ways of
+referring to <tt class="classname">TreeModel</tt> rows: a tree path, a
+<tt class="classname">TreeIter</tt> and a
+<tt class="classname">TreeRowReference</tt>.</p><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="sec-TreePaths"></a>14.2.3.1. Tree Paths</h4></div></div><div></div></div><p>A tree path is a int, string or tuple representation of the
+location of a row in the store. An int value specifies the top level row in
+the model starting from 0. For example, a tree path value of 4 would specify
+the fifth row in the store. By comparison, a string representation of the
+same row would be "4" and the tuple representation would be (4,). This is
+sufficient for specifying any row in a <tt class="classname">ListStore</tt> but
+for a TreeStore we have to be able to represent the child rows. For these
+cases we have to use either the string or tuple representations.</p><p>Since a <tt class="classname">TreeStore</tt> can have an arbitrarily
+deep hierarchy the string representation specifies the path from the top
+level to the designated row using ints separated by the ":"
+character. Similarly, the tuple representation specifies the tree path
+starting from the top level to the row as a sequence of ints. For example,
+valid tree path string representations are: "0:2" (specifies the row that is
+the third child of the first row) and "4:0:1" (specifies the row that is the
+second child of the first child of the fifth row). By comparison the same
+tree paths are represented by the tuples (0, 2) and (4, 0, 1)
+respectively.</p><p>A tree path provides the only way to map from a
+<tt class="classname">TreeView</tt> row to a <tt class="classname">TreeModel</tt>
+row because the tree path of a <tt class="classname">TreeView</tt> row is the
+same as the tree path of the corresponding <tt class="classname">TreeModel</tt>
+row. There are also some problems with tree paths:</p><div class="itemizedlist"><ul type="disc"><li>a tree path can specify a row that doesn't exist in the
+ListStore or TreeStore.</li><li>a tree path can point to a different data row after
+inserting or deleting a row in the <tt class="classname">ListStore</tt> or
+<tt class="classname">TreeStore</tt>.</li></ul></div><p>PyGTK uses the tuple representation when returning tree paths
+but will accept any of the three forms for a tree path representation. You
+should use the tuple representation for a tree path for consistency.</p><p>A tree path can be retrieved from a
+<tt class="classname">TreeIter</tt> using the
+<tt class="methodname">get_path</tt>() method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ path = store.get_path(<b class="parameter"><tt>iter</tt></b>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>iter</tt></i> is a
+<tt class="classname">TreeIter</tt> pointing at a row in store and
+<i class="parameter"><tt>path</tt></i> is the row's tree path as a tuple.</p></div><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="sec-TreeIters"></a>14.2.3.2. TreeIters</h4></div></div><div></div></div><p>A <tt class="classname">TreeIter</tt> is an object that provides a
+transient reference to a <tt class="classname">ListStore</tt> or
+<tt class="classname">TreeStore</tt> row. If the contents of the store change
+(usually because a row is added or deleted) the
+<tt class="classname">TreeIter</tt>s can become invalid. A
+<tt class="classname">TreeModel</tt> that supports persistent TreeIters should
+set the <tt class="literal">gtk.TREE_MODEL_ITERS_PERSIST</tt> flag. An application
+can check for this flag using the <tt class="methodname">get_flags</tt>()
+method.</p><p>A <tt class="classname">TreeIter</tt> is created by one of the
+<tt class="classname">TreeModel</tt> methods that are applicable to both
+<tt class="classname">TreeStore</tt> and <tt class="classname">ListStore</tt>
+objects:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treeiter = store.get_iter(<b class="parameter"><tt>path</tt></b>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>treeiter</tt></i> points at the row at the
+tree path <i class="parameter"><tt>path</tt></i>. The ValueError exception is raised if
+the tree path is invalid.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treeiter = store.get_iter_first()
+</pre></td></tr></table><p>where <i class="parameter"><tt>treeiter</tt></i> is a TreeIter pointing
+at the row at tree path (0,). <i class="parameter"><tt>treeiter</tt></i> will be
+<tt class="literal">None</tt> if the store is empty.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treeiter = store.iter_next(<b class="parameter"><tt>iter</tt></b>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>treeiter</tt></i> is a
+<tt class="classname">TreeIter</tt> that points at the next row at the same
+level as the <tt class="classname">TreeIter</tt> specified by
+<i class="parameter"><tt>iter</tt></i>. <i class="parameter"><tt>treeiter</tt></i> will be
+<tt class="literal">None</tt> if there is no next row (<i class="parameter"><tt>iter</tt></i>
+is also invalidated).</p><p>The following methods are useful only for retrieving a
+<tt class="classname">TreeIter</tt> from a
+<tt class="classname">TreeStore</tt>:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treeiter = treestore.iter_children(<b class="parameter"><tt>parent</tt></b>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>treeiter</tt></i> is a
+<tt class="classname">TreeIter</tt> pointing at the first child row of the row
+specified by the <tt class="classname">TreeIter</tt>
+<i class="parameter"><tt>parent</tt></i>. <i class="parameter"><tt>treeiter</tt></i> will be
+<tt class="literal">None</tt> if there is no child.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treeiter = treestore.iter_nth_child(<b class="parameter"><tt>parent</tt></b>, <b class="parameter"><tt>n</tt></b>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>treeiter</tt></i> is a
+<tt class="classname">TreeIter</tt> pointing at the child row (with the index
+<i class="parameter"><tt>n</tt></i>) of the row specified by the
+<tt class="classname">TreeIter</tt>
+<i class="parameter"><tt>parent</tt></i>. <i class="parameter"><tt>parent</tt></i> may be
+<tt class="literal">None</tt> to retrieve a top level
+row. <i class="parameter"><tt>treeiter</tt></i> will be <tt class="literal">None</tt> if
+there is no child.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treeiter = treestore.iter_parent(<b class="parameter"><tt>child</tt></b>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>treeiter</tt></i> is a
+<tt class="classname">TreeIter</tt> pointing at the parent row of the row
+specified by the <tt class="classname">TreeIter</tt>
+<i class="parameter"><tt>child</tt></i>. treeiter will be <tt class="literal">None</tt> if
+there is no child.</p><p>A tree path can be retrieved from a
+<tt class="classname">TreeIter</tt> using the
+<tt class="methodname">get_path</tt>() method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ path = store.get_path(<b class="parameter"><tt>iter</tt></b>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>iter</tt></i> is a
+<tt class="classname">Treeiter</tt> pointing at a row in store and
+<i class="parameter"><tt>path</tt></i> is the row's tree path as a tuple.</p></div><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="sec-TreeRowReferences"></a>14.2.3.3. TreeRowReferences</h4></div></div><div></div></div><p>A <tt class="classname">TreeRowReference</tt> is a persistent
+reference to a row of data in a store. While the tree path (i.e. the
+location) of the row might change as rows are added to or deleted from the
+store, the <tt class="classname">TreeRowReference</tt> will point at the same
+data row as long as it exists.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p><tt class="classname">TreeRowReference</tt>s are only available in
+PyGTK 2.4 and above.</p></div><p>You can create a <tt class="classname">TreeRowReference</tt> using
+its constructor:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treerowref = TreeRowReference(<b class="parameter"><tt>model</tt></b>, <b class="parameter"><tt>path</tt></b>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>model</tt></i> is the
+<tt class="classname">TreeModel</tt> containing the row and
+<i class="parameter"><tt>path</tt></i> is the tree path of the row to track. If
+<i class="parameter"><tt>path</tt></i> isn't a valid tree path for
+<i class="parameter"><tt>model</tt></i>, <tt class="literal">None</tt> is returned.</p></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-AddingStoreRows"></a>14.2.4. Adding Rows</h3></div></div><div></div></div><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="sec-AddingListStoreRows"></a>14.2.4.1. Adding Rows to a ListStore</h4></div></div><div></div></div><p>Once you have a <tt class="classname">ListStore</tt> you'll need to
+add data rows using one of the following methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ iter = append(<b class="parameter"><tt>row</tt></b>=None)
+ iter = prepend(<b class="parameter"><tt>row</tt></b>=None)
+ iter = insert(<b class="parameter"><tt>position</tt></b>, <b class="parameter"><tt>row</tt></b>=None)
+ iter = insert_before(<b class="parameter"><tt>sibling</tt></b>, <b class="parameter"><tt>row</tt></b>=None)
+ iter = insert_after(<b class="parameter"><tt>sibling</tt></b>, <b class="parameter"><tt>row</tt></b>=None)
+</pre></td></tr></table><p>Each of these methods inserts a row at an implied or specified
+position in the <tt class="classname">ListStore</tt>. The
+<tt class="methodname">append</tt>() and <tt class="methodname">prepend</tt>()
+methods use implied positions: after the last row and before the first row,
+respectively. The <tt class="methodname">insert</tt>() method takes an integer
+(the parameter <i class="parameter"><tt>position</tt></i>) that specifies the location
+where the row will be inserted. The other two methods take a
+<tt class="classname">TreeIter</tt> (<i class="parameter"><tt>sibling</tt></i>) that
+references a row in the <tt class="classname">ListStore</tt> to insert the row
+before or after.</p><p>The <i class="parameter"><tt>row</tt></i> parameter specifies the data that
+should be inserted in the row after it is created. If
+<i class="parameter"><tt>row</tt></i> is <tt class="literal">None</tt> or not specified, an
+empty row will be created. If <i class="parameter"><tt>row</tt></i> is specified it
+must be a tuple or list containing as many items as the number of columns in
+the <tt class="classname">ListStore</tt>. The items must also match the data
+type of their respective <tt class="classname">ListStore</tt> columns.</p><p>All methods return a <tt class="classname">TreeIter</tt> that points
+at the newly inserted row. The following code fragment illustrates the
+creation of a <tt class="classname">ListStore</tt> and the addition of data rows
+to it:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ ...
+ liststore = gtk.ListStore(int, str, gtk.gdk.Color)
+ liststore.append([0,'red',colormap.alloc_color('red')])
+ liststore.append([1,'green',colormap.alloc_color('green')])
+ iter = liststore.insert(1, (2,'blue',colormap.alloc_color('blue')) )
+ iter = liststore.insert_after(iter, [3,'yellow',colormap.alloc_color('blue')])
+ ...
+</pre></td></tr></table></div><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="sec-AddingTreeStoreRows"></a>14.2.4.2. Adding Rows to a TreeStore</h4></div></div><div></div></div><p>Adding a row to a <tt class="classname">TreeStore</tt> is similar to
+adding a row to a <tt class="classname">ListStore</tt> except that you also have
+to specify a parent row (using a <tt class="classname">TreeIter</tt>) to add the
+new row to. The <tt class="classname">TreeStore</tt> methods are:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ iter = append(<b class="parameter"><tt>parent</tt></b>, <b class="parameter"><tt>row</tt></b>=None)
+ iter = prepend(<b class="parameter"><tt>parent</tt></b>, <b class="parameter"><tt>row</tt></b>=None)
+ iter = insert(<b class="parameter"><tt>parent</tt></b>, <b class="parameter"><tt>position</tt></b>, <b class="parameter"><tt>row</tt></b>=None)
+ iter = insert_before(<b class="parameter"><tt>parent</tt></b>, <b class="parameter"><tt>sibling</tt></b>, <b class="parameter"><tt>row</tt></b>=None)
+ iter = insert_after(<b class="parameter"><tt>parent</tt></b>, <b class="parameter"><tt>sibling</tt></b>, <b class="parameter"><tt>row</tt></b>=None)
+</pre></td></tr></table><p>If <i class="parameter"><tt>parent</tt></i> is <tt class="literal">None</tt>, the
+row will be added to the top level rows.</p><p>Each of these methods inserts a row at an implied or specified
+position in the <tt class="classname">TreeStore</tt>. The
+<tt class="methodname">append</tt>() and <tt class="methodname">prepend</tt>()
+methods use implied positions: after the last child row and before the first
+child row, respectively. The <tt class="methodname">insert</tt>() method takes
+an integer (the parameter <i class="parameter"><tt>position</tt></i>) that specifies
+the location where the child row will be inserted. The other two methods
+take a <tt class="classname">TreeIter</tt> (<i class="parameter"><tt>sibling</tt></i>) that
+references a child row in the <tt class="classname">TreeStore</tt> to insert the
+row before or after.</p><p>The <i class="parameter"><tt>row</tt></i> parameter specifies the data that
+should be inserted in the row after it is created. If
+<i class="parameter"><tt>row</tt></i> is <tt class="literal">None</tt> or not specified, an
+empty row will be created. If <i class="parameter"><tt>row</tt></i> is specified it
+must be a tuple or list containing as many items as the number of columns in
+the <tt class="classname">TreeStore</tt>. The items must also match the data
+type of their respective <tt class="classname">TreeStore</tt> columns.</p><p>All methods return a <tt class="classname">TreeIter</tt> that points
+at the newly inserted row. The following code fragment illustrates the
+creation of a <tt class="classname">TreeStore</tt> and the addition of data rows
+to it:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ ...
+ folderpb = gtk.gdk.pixbuf_from_file('folder.xpm')
+ filepb = gtk.gdk.pixbuf_from_file('file.xpm')
+ treestore = gtk.TreeStore(int, str, gtk.gdk.Pixbuf)
+ iter0 = treestore.append(None, [1,'(0,)',folderpb] )
+ treestore.insert(iter0, 0, [11,'(0,0)',filepb])
+ treestore.append(iter0, [12,'(0,1)',filepb])
+ iter1 = treestore.insert_after(None, iter0, [2,'(1,)',folderpb])
+ treestore.insert(iter1, 0, [22,'(1,1)',filepb])
+ treestore.prepend(iter1, [21,'(1,0)',filepb])
+ ...
+</pre></td></tr></table></div><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="sec-LargeDataStores"></a>14.2.4.3. Large Data Stores</h4></div></div><div></div></div><p>When a <tt class="classname">ListStore</tt> or
+<tt class="classname">TreeStore</tt> contains a large number of data rows,
+adding new rows can become very slow. There are a few things that you can do
+to mitigate this problem:</p><div class="itemizedlist"><ul type="disc"><li>If adding a large number of rows disconnect the
+<tt class="classname">TreeModel</tt> from its <tt class="classname">TreeView</tt>
+(using the <tt class="methodname">set_model</tt>() method with the
+<i class="parameter"><tt>model</tt></i> parameter set to <tt class="literal">None</tt>) to
+avoid <tt class="classname">TreeView</tt> updates for each row
+entered.</li><li>Likewise, disable sorting (using the
+<tt class="methodname">set_default_sort_func</tt>() method with the
+<i class="parameter"><tt>sort_func</tt></i> set to <tt class="literal">None</tt>) while
+adding a large number of rows.</li><li>Limit the number of
+<tt class="classname">TreeRowReference</tt>s in use since they update their path
+with each addition or removal.</li><li>Set the <tt class="classname">TreeView</tt>
+"fixed-height-mode" property to <tt class="literal">TRUE</tt> making all rows have
+the same height and avoiding the individual calculation of the height of
+each row. Only available in PyGTK 2.4 and above.</li></ul></div></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-RemovingStoreRows"></a>14.2.5. Removing Rows</h3></div></div><div></div></div><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="sec-RemovingListStoreRows"></a>14.2.5.1. Removing Rows From a ListStore</h4></div></div><div></div></div><p>You can remove a data row from a
+<tt class="classname">ListStore</tt> by using the
+<tt class="methodname">remove</tt>() method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treeiter = liststore.remove(<b class="parameter"><tt>iter</tt></b>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>iter</tt></i> is a
+<tt class="classname">TreeIter</tt> pointing at the row to remove. The returned
+<tt class="classname">TreeIter</tt> (<i class="parameter"><tt>treeiter</tt></i>) points at
+the next row or is invalid if <i class="parameter"><tt>iter</tt></i> was pointing at
+the last row.</p><p>The <tt class="methodname">clear</tt>() method removes all rows
+from the <tt class="classname">ListStore</tt>:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ liststore.clear()
+</pre></td></tr></table></div><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="sec-RemovingTreeStoreRows"></a>14.2.5.2. Removing Rows From a TreeStore</h4></div></div><div></div></div><p>The methods for removing data rows from a
+<tt class="classname">TreeStore</tt> are similar to the
+<tt class="classname">ListStore</tt> methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ result = treestore.remove(<b class="parameter"><tt>iter</tt></b>)
+ treestore.clear()
+</pre></td></tr></table><p>where <i class="parameter"><tt>result</tt></i> is <tt class="literal">TRUE</tt>
+if the row was removed and <i class="parameter"><tt>iter</tt></i> points at the next
+valid row. Otherwise, <i class="parameter"><tt>result</tt></i> is
+<tt class="literal">FALSE</tt> and <i class="parameter"><tt>iter</tt></i> is
+invalidated.</p></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-ManagingRowData"></a>14.2.6. Managing Row Data</h3></div></div><div></div></div><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="sec-AccessingDataValues"></a>14.2.6.1. Setting and Retrieving Data Values</h4></div></div><div></div></div><p>The methods for accessing the data values in a
+<tt class="classname">ListStore</tt> and <tt class="classname">TreeStore</tt> have
+the same format. All store data manipulations use a
+<tt class="classname">TreeIter</tt> to specify the row that you are working
+with. Once you have a <tt class="classname">TreeIter</tt> it can be used to
+retrieve the values of a row column using the
+<tt class="methodname">get_value</tt>() method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ value = store.get_value(<b class="parameter"><tt>iter</tt></b>, <b class="parameter"><tt>column</tt></b>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>iter</tt></i> is a
+<tt class="classname">TreeIter</tt> pointing at a row,
+<i class="parameter"><tt>column</tt></i> is a column number in
+<i class="parameter"><tt>store</tt></i>, and, <i class="parameter"><tt>value</tt></i> is the value
+stored at the row-column location.</p><p>If you want to retrieve the values from multiple columns in
+one call use the <tt class="methodname">get</tt>() method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ values = store.get(iter, column, ...)
+</pre></td></tr></table><p>where <i class="parameter"><tt>iter</tt></i> is a
+<tt class="classname">TreeIter</tt> pointing at a row,
+<i class="parameter"><tt>column</tt></i> is a column number in
+<i class="parameter"><tt>store</tt></i>, and, <i class="parameter"><tt>...</tt></i> represents
+zero or more additional column numbers and <i class="parameter"><tt>values</tt></i> is
+a tuple containing the retrieved data values. For example to retrieve the
+values in columns 0 and 2:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ val0, val2 = store.get(iter, 0, 2)
+</pre></td></tr></table><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>The <tt class="methodname">get</tt>() method is only available
+in PyGTK 2.4 and above.</p></div><p>Setting a single column value is effected using the
+<tt class="methodname">set_value</tt>() method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ store.set_value(<b class="parameter"><tt>iter</tt></b>, <b class="parameter"><tt>column</tt></b>, <b class="parameter"><tt>value</tt></b>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>iter</tt></i> (a
+<tt class="classname">TreeIter</tt>) and <i class="parameter"><tt>column</tt></i> (an int)
+specify the row-column location in <i class="parameter"><tt>store</tt></i> and
+<i class="parameter"><tt>column</tt></i> is the column number where
+<i class="parameter"><tt>value</tt></i> is to be set. <i class="parameter"><tt>value</tt></i> must
+be the same data type as the <i class="parameter"><tt>store</tt></i> column.</p><p>If you wish to set the value of more than one column in a row
+at a time, use the <tt class="methodname">set</tt>() method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ store.set(<i class="parameter"><tt>iter</tt></i>, <i class="parameter"><tt>...</tt></i>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>iter</tt></i> specifies the store row and
+<i class="parameter"><tt>...</tt></i> is one or more column number - value pairs
+indicating the column and and value to set. For example, the following
+call:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ store.set(iter, 0, 'Foo', 5, 'Bar', 1, 123)
+</pre></td></tr></table><p>sets the first column to 'Foo', the sixth column to 'Bar' and
+the second column to 123 in the <i class="parameter"><tt>store</tt></i> row specified
+by <i class="parameter"><tt>iter</tt></i>.</p></div><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="sec-RearrangingListStoreRows"></a>14.2.6.2. Rearranging ListStore Rows</h4></div></div><div></div></div><p>Individual <tt class="classname">ListStore</tt> rows can be moved
+using one of the following methods that are available in PyGTK 2.2 and
+above:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ liststore.swap(<b class="parameter"><tt>a</tt></b>, <b class="parameter"><tt>b</tt></b>)
+ liststore.move_after(<b class="parameter"><tt>iter</tt></b>, <b class="parameter"><tt>position</tt></b>)
+ liststore.move_before(<b class="parameter"><tt>iter</tt></b>, <b class="parameter"><tt>position</tt></b>)
+</pre></td></tr></table><p><tt class="methodname">swap</tt>() swaps the locations of the rows
+referenced by the <tt class="classname">TreeIter</tt>s <i class="parameter"><tt>a</tt></i>
+and <i class="parameter"><tt>b</tt></i>. <tt class="methodname">move_after</tt>() and
+<tt class="methodname">move_before</tt>() move the row referenced by the
+<tt class="classname">TreeIter</tt> <i class="parameter"><tt>iter</tt></i> after or before
+the row referenced by the <tt class="classname">TreeIter</tt>
+<i class="parameter"><tt>position</tt></i>. If <i class="parameter"><tt>position</tt></i> is
+<tt class="literal">None</tt>, <tt class="methodname">move_after</tt>() will place
+the row at the beginning of the store while
+<tt class="methodname">move_before</tt>(), at the end of the store.</p><p>If you want to completely rearrange the
+<tt class="classname">ListStore</tt> data rows, use the following method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ liststore.reorder(<i class="parameter"><tt>new_order</tt></i>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>new_order</tt></i> is a list of integers
+that specify the new row order as:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ <i class="parameter"><tt>new_order</tt></i>[newpos] = oldpos
+</pre></td></tr></table><p>For example, if <i class="parameter"><tt>liststore</tt></i> contained
+four rows:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 'one'
+ 'two'
+ 'three'
+ 'four'
+</pre></td></tr></table><p>The method call:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ liststore.reorder([2, 1, 3, 0])
+</pre></td></tr></table><p>would produce the resulting order:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 'three'
+ 'two'
+ 'four'
+ 'one'
+</pre></td></tr></table><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>These methods will only rearrange unsorted
+<tt class="classname">ListStore</tt>s.</p></div><p>If you want to rearrange rows in PyGTK 2.0 you have to remove
+and insert rows using the methods described in <a href="sec-TreeModelInterface.html#sec-AddingStoreRows" title="14.2.4. Adding Rows">Section 14.2.4, “Adding Rowsâ€</a> and <a href="sec-TreeModelInterface.html#sec-RemovingStoreRows" title="14.2.5. Removing Rows">Section 14.2.5, “Removing Rowsâ€</a>.</p></div><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="sec-RearrangingTreeStoreRows"></a>14.2.6.3. Rearranging TreeStore Rows</h4></div></div><div></div></div><p>The methods used to rearrange <tt class="classname">TreeStore</tt>
+rows are similar to the <tt class="classname">ListStore</tt> methods except they
+only affect the child rows of an implied parent row - it is not possible to,
+say, swap rows with different parent rows.:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treestore.swap(<b class="parameter"><tt>a</tt></b>, <b class="parameter"><tt>b</tt></b>)
+ treestore.move_after(<b class="parameter"><tt>iter</tt></b>, <b class="parameter"><tt>position</tt></b>)
+ treestore.move_before(<b class="parameter"><tt>iter</tt></b>, <b class="parameter"><tt>position</tt></b>)
+</pre></td></tr></table><p><tt class="methodname">swap</tt>() swaps the locations of the child
+rows referenced by the TreeIters <i class="parameter"><tt>a</tt></i> and
+<i class="parameter"><tt>b</tt></i>. <i class="parameter"><tt>a</tt></i> and
+<i class="parameter"><tt>b</tt></i> must both have the same parent
+row. <tt class="methodname">move_after</tt>() and
+<tt class="methodname">move_before</tt>() move the row referenced by the
+<tt class="classname">TreeIter</tt> <i class="parameter"><tt>iter</tt></i> after or before
+the row referenced by the <tt class="classname">TreeIter</tt>
+<i class="parameter"><tt>position</tt></i>. <i class="parameter"><tt>iter</tt></i> and
+<i class="parameter"><tt>position</tt></i> must both have the same parent row. If
+<i class="parameter"><tt>position</tt></i> is <tt class="literal">None</tt>,
+<tt class="methodname">move_after</tt>() will place the row at the beginning of
+the store while <tt class="methodname">move_before</tt>(), at the end of the
+store.</p><p>The <tt class="methodname">reorder</tt>() method requires an
+additional parameter specifying the parent row whose child rows will be
+reordered:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treestore.reorder(<b class="parameter"><tt>parent</tt></b>, <b class="parameter"><tt>new_order</tt></b>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>new_order</tt></i> is a list of integers
+that specify the new child row order of the parent row specified by the
+<tt class="classname">TreeIter</tt> <i class="parameter"><tt>parent</tt></i> as:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ <i class="parameter"><tt>new_order</tt></i>[newpos] = oldpos
+</pre></td></tr></table><p>For example, if <i class="parameter"><tt>treestore</tt></i> contained
+four rows:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 'parent'
+ 'one'
+ 'two'
+ 'three'
+ 'four'
+</pre></td></tr></table><p>The method call:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treestore.reorder(parent, [2, 1, 3, 0])
+</pre></td></tr></table><p>would produce the resulting order:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 'parent'
+ 'three'
+ 'two'
+ 'four'
+ 'one'
+</pre></td></tr></table><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>These methods will only rearrange unsorted
+<tt class="classname">TreeStore</tt>s.</p></div></div><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="sec-ManagingMultipleRows"></a>14.2.6.4. Managing Multiple Rows</h4></div></div><div></div></div><p>One of the trickier aspects of dealing with
+<tt class="classname">ListStore</tt>s and <tt class="classname">TreeStore</tt>s is
+the operation on multiple rows, e.g. moving multiple rows, say, from one
+parent row to another or removing rows based on certain criteria. The
+difficulty arises from the need to use a <tt class="classname">TreeIter</tt>
+that may become invalid as the result of the operation. For
+<tt class="classname">ListStore</tt>s and <tt class="classname">TreeStore</tt>s the
+TreeIters are persistent as can be checked by using the
+<tt class="methodname">get_flags</tt>() method and testing for the
+<tt class="literal">gtk.TREE_MODEL_ITERS_PERSIST</tt> flag. However the stackable
+<tt class="classname">TreeModelFilter</tt> and
+<tt class="classname">TreeModelSort</tt> classes do not have persistent
+<tt class="classname">TreeIter</tt>s.</p><p>Assuming that <tt class="classname">TreeIter</tt>s don't persist how
+do we move all the child rows from one parent row to another? We have
+to:</p><div class="itemizedlist"><ul type="disc"><li>iterate over the parent's children</li><li>retrieve each row's data</li><li>remove each child row</li><li>insert a new row with the old row data in the new
+parent's list</li></ul></div><p>We can't rely on the <tt class="methodname">remove</tt>() method to
+return a valid <tt class="classname">TreeIter</tt> so we'll just ask for the
+first child iter until it returns <tt class="literal">None</tt>. A possible
+function to move child rows is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def move_child_rows(treestore, from_parent, to_parent):
+ n_columns = treestore.get_n_columns()
+ iter = treestore.iter_children(from_parent)
+ while iter:
+ values = treestore.get(iter, *range(n_columns))
+ treestore.remove(iter)
+ treestore.append(to_parent, values)
+ iter = treestore.iter_children(from_parent)
+ return
+</pre></td></tr></table><p>The above function covers the simple case of moving all child
+rows of a single parent row but what if you want to remove all rows in the
+<tt class="classname">TreeStore</tt> based on some match criteria, say the first
+column value? Here you might think that you could use the
+<tt class="methodname">foreach</tt>() method to iterate over all the rows and
+remove the matching ones:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ store.foreach(<i class="parameter"><tt>func</tt></i>, <i class="parameter"><tt>user_data</tt></i>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>func</tt></i> is a function that is
+invoked for each store row and has the signature:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def func(<i class="parameter"><tt>model</tt></i>, <i class="parameter"><tt>path</tt></i>, <i class="parameter"><tt>iter</tt></i>, <i class="parameter"><tt>user_data</tt></i>):
+</pre></td></tr></table><p>where <i class="parameter"><tt>model</tt></i> is the
+<tt class="classname">TreeModel</tt> data store, <i class="parameter"><tt>path</tt></i> is
+the tree path of a row in <i class="parameter"><tt>model</tt></i>,
+<i class="parameter"><tt>iter</tt></i> is a <tt class="classname">TreeIter</tt> pointing at
+<i class="parameter"><tt>path</tt></i> and <i class="parameter"><tt>user_data</tt></i> is the
+passed in data. if <i class="parameter"><tt>func</tt></i> returns
+<tt class="literal">TRUE</tt> the <tt class="methodname">foreach</tt>() method will
+cease iterating and return.</p><p>The problem with that is that changing the contents of the store
+while the <tt class="methodname">foreach</tt>() method is iterating over it may
+have unpredictable results. Using the <tt class="methodname">foreach</tt>()
+method to create and save TreeRowReferences to the rows to be removed and
+then removing them after the <tt class="methodname">foreach</tt>() method
+completes would be a good strategy except that it doesn't work for PyGTK 2.0
+and 2.2 where <tt class="classname">TreeRowReference</tt>s are not
+available.</p><p>A reliable strategy that covers all the PyGTK variants is to
+use the <tt class="methodname">foreach</tt>() method to gather the tree paths
+of rows to be removed and then remove them in reverse order to preserve the
+validity of the tree paths. An example code fragment utilizing this
+strategy is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ ...
+ # match if the value in the first column is &gt;= the passed in value
+ # data is a tuple containing the match value and a list to save paths
+ def match_value_cb(model, path, iter, data):
+ if model.get_value(iter, 0) &gt;= data[0]:
+ data[1].append(path)
+ return False # keep the foreach going
+
+ pathlist = []
+ treestore.foreach(match_value_cb, (10, pathlist))
+
+ # foreach works in a depth first fashion
+ pathlist.reverse()
+ for path in pathlist:
+ treestore.remove(treestore.get_iter(path))
+ ...
+</pre></td></tr></table><p>If you want to search a <tt class="classname">TreeStore</tt> for the
+first row that matches some criteria, you probably want to do the iteration
+yourself using something like:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treestore = TreeStore(str)
+ ...
+ def match_func(model, iter, data):
+ column, key = data # data is a tuple containing column number, key
+ value = model.get_value(iter, column)
+ return value == key
+ def search(model, iter, func, data):
+ while iter:
+ if func(model, iter, data):
+ return iter
+ result = search(model, model.iter_children(iter), func, data)
+ if result: return result
+ iter = model.iter_next(iter)
+ return None
+ ...
+ match_iter = search(treestore, treestore.iter_children(None),
+ match_func, (0, 'foo'))
+</pre></td></tr></table><p>The <tt class="function">search</tt>() function iterates recursively
+over the row (specified by <i class="parameter"><tt>iter</tt></i>) and its siblings and
+their child rows in a depth first fashion looking for a row that has a
+column matching the given key string. The search terminates when a row is
+found.</p></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-PythonProtocolSupport"></a>14.2.7. Python Protocol Support</h3></div></div><div></div></div><p>The classes that implement the <tt class="classname">TreeModel</tt>
+interface (<tt class="classname">TreeStore</tt> and
+<tt class="classname">ListStore</tt> and in PyGTK 2.4, also the
+<tt class="classname">TreeModelSort</tt> and
+<tt class="classname">TreeModelFilter</tt>) support the Python mapping and
+iterator protocols. The iterator protocol allows you to use the Python
+<tt class="function">iter</tt>() function on a <tt class="classname">TreeModel</tt>
+to create an iterator to be used to iterate over the top level rows in the
+<tt class="classname">TreeModel</tt>. A more useful capability is to iterate
+using the <tt class="literal">for</tt> statement or a list comprehension. For
+example:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ ...
+ liststore = gtk.ListStore(str, str)
+ ...
+ # add some rows to liststore
+ ...
+ # for looping
+ for row in liststore:
+ # do individual row processing
+ ...
+ # list comprehension returning a list of values in the first column
+ values = [ r[0] for r in liststore ]
+ ...
+</pre></td></tr></table><p>Other parts of the mapping protocols that are supported are using
+<tt class="literal">del</tt> to delete a row in the model and extracting a PyGTK
+<tt class="classname">TreeModelRow</tt> from the model using a key value that is
+a tree path or <tt class="classname">TreeIter</tt>. For example, the following
+statements all return the first row in a <tt class="classname">TreeModel</tt>
+and the final statement deletes the first child row of the first row:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ row = model[0]
+ row = model['0']
+ row = model["0"]
+ row = model[(0,)]
+ i = model.get_iter(0)
+ row = model[i]
+ del model[(0,0)]
+</pre></td></tr></table><p>In addition, you can set the values in an existing row similar
+to the following:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ ...
+ liststore = gtk.ListStore(str, int, object)
+ ...
+ liststore[0] = ['Button', 23, gtk.Button('Label')]
+</pre></td></tr></table><p>A PyGTK <tt class="classname">TreeModelRow</tt> object supports the
+Python sequence and iterator protocols. You can get an iterator to iterate
+over the column values in the row or use the for statement or list
+comprehension as well. A <tt class="classname">TreeModelRow</tt> uses the column
+number as the index to extract a value. For example:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ ...
+ liststore = gtk.ListStore(str, int)
+ liststore.append(['Random string', 514])
+ ...
+ row = liststore[0]
+ value1 = row[1]
+ value0 = liststore['0'][0]
+ for value in row:
+ print value
+ val0, val1 = row
+ ...
+</pre></td></tr></table><p>Using the example from the previous section to iterate over a
+<tt class="classname">TreeStore</tt> to locate a row containing a particular
+value, the code becomes:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treestore = TreeStore(str)
+ ...
+ def match_func(row, data):
+ column, key = data # data is a tuple containing column number, key
+ return row[column] == key
+ ...
+ def search(rows, func, data):
+ if not rows: return None
+ for row in rows:
+ if func(row, data):
+ return row
+ result = search(row.iterchildren(), func, data)
+ if result: return result
+ return None
+ ...
+ match_row = search(treestore, match_func, (0, 'foo'))
+</pre></td></tr></table><p>You can also set a value in an existing column using:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treestore[(1,0,1)][1] = 'abc'
+</pre></td></tr></table><p>The <tt class="classname">TreeModelRow</tt> also supports the
+<tt class="literal">del</tt> statement and conversion to lists and tuples using
+the Python <tt class="function">list</tt>() and <tt class="function">tuple</tt>()
+functions. As illustrated in the above example the
+<tt class="classname">TreeModelRow</tt> has the
+<tt class="methodname">iterchildren</tt>() method that returns an iterator for
+iterating over the child rows of the
+<tt class="classname">TreeModelRow</tt>.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-TreeModelSignals"></a>14.2.8. TreeModel Signals</h3></div></div><div></div></div><p>Your application can track changes in a
+<tt class="classname">TreeModel</tt> by connecting to the signals that are
+emitted by the <tt class="classname">TreeModel</tt>: "row-changed",
+"row-deleted", "row-inserted", "row-has-child-toggled" and
+"rows-reordered". These signals are used by a
+<tt class="classname">TreeView</tt> to track changes in its
+<tt class="classname">TreeModel</tt>.</p><p>If you connect to these signals in your application, you may see
+clusters of signals when some methods are called. For example the call to
+add the first child row to a parent row:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treestore.append(parent, ['qwe', 'asd', 123])
+</pre></td></tr></table><p>will cause the following signal emissions:</p><div class="itemizedlist"><ul type="disc"><li>"row-inserted" where the inserted row will be
+empty.</li><li>"row-has-child-toggled" since
+<i class="parameter"><tt>parent</tt></i> didn't previously have any child
+rows.</li><li>"row-changed" for the inserted row when setting the value
+'qwe' in the first column.</li><li>"row-changed" for the inserted row when setting the value
+'asd in the second column.</li><li>"row-changed" for the inserted row when setting the value
+123 in the third column.</li></ul></div><p>Note that you can't retrieve the row order in the
+"rows-reordered" callback since the new row order is passed as an opaque
+pointer to an array of integers.</p><p>See the <a href="http://www.pygtk.org/pygtk2reference/class-gtktreemodel.html" target="_top">PyGTK
+Reference Manual</a> for more information on the
+<tt class="classname">TreeModel</tt> signals.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-SortingTreeModelRows"></a>14.2.9. Sorting TreeModel Rows</h3></div></div><div></div></div><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="sec-TreeSortable"></a>14.2.9.1. The TreeSortable Interface</h4></div></div><div></div></div><p>The <tt class="classname">ListStore</tt> and
+<tt class="classname">TreeStore</tt> objects implement the
+<tt class="classname">TreeSortable</tt> interface that provides methods for
+controlling the sorting of <tt class="classname">TreeModel</tt> rows. The key
+element of the interface is a "sort column ID" which is an arbitrary integer
+value referring to a sort comparison function and associated user data. A
+sort column ID must be greater than or equal to zero. A sort column ID is
+created by using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treesortable.set_sort_func(<i class="parameter"><tt>sort_column_id</tt></i>, <i class="parameter"><tt>sort_func</tt></i>, <i class="parameter"><tt>user_data</tt></i>=<tt class="literal">None</tt>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>sort_column_id</tt></i> is a programmer
+assigned integer value, <i class="parameter"><tt>sort_func</tt></i> is a function or
+method used to compare rows and <i class="parameter"><tt>user_data</tt></i> is context
+data. <i class="parameter"><tt>sort_func</tt></i> has the signature:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def sort_func_function(model, iter1, iter2, data)
+ def sort_func_method(self, model, iter1, iter2, data)
+</pre></td></tr></table><p>where <i class="parameter"><tt>model</tt></i> is the
+<tt class="classname">TreeModel</tt> containing the rows pointed to by the
+<tt class="classname">TreeIter</tt>s <i class="parameter"><tt>iter1</tt></i> and
+<i class="parameter"><tt>iter2</tt></i> and <i class="parameter"><tt>data</tt></i> is
+<i class="parameter"><tt>user_data</tt></i>. <i class="parameter"><tt>sort_func</tt></i> should
+return: -1 if the <i class="parameter"><tt>iter1</tt></i> row should precede the
+<i class="parameter"><tt>iter2</tt></i> row; 0, if the rows are equal; and, 1 if the
+<i class="parameter"><tt>iter2</tt></i> row should precede the
+<i class="parameter"><tt>iter1</tt></i> row. The sort comparison function should always
+assume that the sort order is <tt class="literal">gtk.SORT_ASCENDING</tt> as the
+sort order will be taken into account by the
+<tt class="classname">TreeSortable</tt> implementations.</p><p>The same sort comparison function can be used for multiple sort
+column IDs by varying the user_data to provide context information. For
+example, the <i class="parameter"><tt>user_data</tt></i> specified in the
+<tt class="methodname">set_sort_func</tt>() method could be the index of the
+column to extract the sort data from.</p><p>Once a sort column ID is created a store can use it for sorting
+by calling the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treesortable.set_sort_column_id(<b class="parameter"><tt>sort_column_id</tt></b>, <b class="parameter"><tt>order</tt></b>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>order</tt></i> is the sort order either
+<tt class="literal">gtk.SORT_ASCENDING</tt> or
+<tt class="literal">gtk.SORT_DESCENDING</tt>.</p><p>The sort column ID of -1 means that the store should use the
+default sort function that is set using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treesortable.set_default_sort_func(<i class="parameter"><tt>sort_func</tt></i>, <i class="parameter"><tt>user_data</tt></i>=<tt class="literal">None</tt>)
+</pre></td></tr></table><p>You can check if a store has a default sort function using the
+method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ result = treesortable.has_default_sort_func()
+</pre></td></tr></table><p>which returns <tt class="literal">TRUE</tt> if a default sort function
+has been set.</p><p>Once a sort column ID has been set on a
+<tt class="classname">TreeModel</tt> implementing the
+<tt class="classname">TreeSortable</tt> interface it cannot be returned to the
+original unsorted state. You can change the sort function or use a default
+sort function but you cannot set the <tt class="classname">TreeModel</tt> to
+have no sort function.</p></div><div class="sect3" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="sec-SortingStores"></a>14.2.9.2. Sorting in ListStores and TreeStores</h4></div></div><div></div></div><p>When a <tt class="classname">ListStore</tt> or
+<tt class="classname">TreeStore</tt> object is created it automatically sets up
+sort column IDs corresponding to the columns in the store using the column
+index number. For example, a <tt class="classname">ListStore</tt> with three
+columns would have three sort column IDs (0, 1, 2) setup
+automatically. These sort column IDs are associated with an internal sort
+comparison function that handles the fundamental types:</p><div class="itemizedlist"><ul type="disc"><li>'gboolean'</li><li>str</li><li>int</li><li>long</li><li>float</li></ul></div><p>Initially a <tt class="classname">ListStore</tt> or
+<tt class="classname">TreeStore</tt> is set with a sort column ID of -2 that
+indicates that no sort function is being used and that the store is
+unsorted. Once you set a sort column ID on a
+<tt class="classname">ListStore</tt> or <tt class="classname">TreeStore</tt> you
+cannot set it back to -2.</p><p>If you want to maintain the default sort column IDs you can set up
+a sort column ID well out of the range of the number of columns such as 1000
+and up. Then you can switch between the default sort function and your
+application sort functions as needed.</p></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch-TreeViewWidget.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-TreeViewWidget.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-TreeViews.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 14. Tree View Widget </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 14.3. TreeViews</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-TreeModelSortAndTreeModelFilter.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-TreeModelSortAndTreeModelFilter.html
new file mode 100644
index 0000000..46b1364
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-TreeModelSortAndTreeModelFilter.html
@@ -0,0 +1,185 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>14.10. TreeModelSort and TreeModelFilter</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-TreeViewWidget.html" title="Chapter 14. Tree View Widget"><link rel="previous" href="sec-TreeViewDragAndDrop.html" title="14.9. TreeView Drag and Drop"><link rel="next" href="sec-GenericTreeModel.html" title="14.11. The Generic TreeModel"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">14.10. TreeModelSort and TreeModelFilter</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-TreeViewDragAndDrop.html">Prev</a> </td><th width="60%" align="center">Chapter 14. Tree View Widget</th><td width="20%" align="right"> <a accesskey="n" href="sec-GenericTreeModel.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-TreeModelSortAndTreeModelFilter"></a>14.10. TreeModelSort and TreeModelFilter</h2></div></div><div></div></div><p>The <tt class="classname">TreeModelSort</tt> and
+<tt class="classname">TreeModelFilter</tt> objects are tree models that
+interpose between the base <tt class="classname">TreeModel</tt> (either a
+<tt class="classname">TreeStore</tt> or a <tt class="classname">ListStore</tt>) and
+the <tt class="classname">TreeView</tt> to provide a modified model while still
+retaining the original structure of the base model. These interposing models
+implement the <tt class="classname">TreeModel</tt> and
+<tt class="classname">TreeSortable</tt> interfaces but do not provide any
+methods for inserting or removing rows in the model; you have to insert or
+remove rows from the underlying store. The
+<tt class="classname">TreeModelSort</tt> provides a model where the rows are
+always sorted while the <tt class="classname">TreeModelFilter</tt> provides a
+model containing a subset of the rows of the base model.</p><p>These models can be chained to an arbitrary length if desired; i.e
+a <tt class="classname">TreeModelFilter</tt> could have a child
+<tt class="classname">TreeModelSort</tt> that could have a child
+<tt class="classname">TreeModelFilter</tt>, and so on. As long as there is a
+<tt class="classname">TreeStore</tt> or <tt class="classname">ListStore</tt> as the
+anchor of the chain it should just work. In PyGTK 2.0 and 2.2 the
+<tt class="classname">TreeModelSort</tt> and
+<tt class="classname">TreeModelFilter</tt> objects do not support the
+<tt class="classname">TreeModel</tt> Python mapping protocol.</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-TreeModelSort"></a>14.10.1. TreeModelSort</h3></div></div><div></div></div><p>The <tt class="classname">TreeModelSort</tt> maintains a sorted
+model of the child model specified in its constructor. The main use of a
+<tt class="classname">TreeModelSort</tt> is to provide multiple views of a model
+that can be sorted differently. If you have multiple views of the same model
+then any sorting activity is reflected in all the views. By using the
+<tt class="classname">TreeModelSort</tt> the base store is left in its original
+unsorted state and the sort models absorb all the sorting activity. To
+create a <tt class="classname">TreeModelSort</tt> use the constructor:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treemodelsort = gtk.TreeModelSort(<b class="parameter"><tt>child_model</tt></b>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>child_model</tt></i> is a
+<tt class="classname">TreeModel</tt>. Most of the methods of a
+<tt class="classname">TreeModelSort</tt> deal with converting tree paths and
+<tt class="classname">TreeIter</tt>s from the child model to the sorted model
+and back:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ sorted_path = treemodelsort.convert_child_path_to_path(<b class="parameter"><tt>child_path</tt></b>)
+ child_path = treemodelsort.convert_path_to_child_path(<b class="parameter"><tt>sorted_path</tt></b>)
+</pre></td></tr></table><p>These path conversion methods return <tt class="literal">None</tt> if
+the given path cannot be converted to a path in the sorted model or the
+child model respectively. The <tt class="classname">TreeIter</tt> conversion
+methods are:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ sorted_iter = treemodelsort.convert_child_iter_to_iter(<b class="parameter"><tt>sorted_iter</tt></b>, <b class="parameter"><tt>child_iter</tt></b>)
+ child_iter = treemodelsort.convert_iter_to_child_iter(<b class="parameter"><tt>child_iter</tt></b>, <b class="parameter"><tt>sorted_iter</tt></b>)
+</pre></td></tr></table><p>The <tt class="classname">TreeIter</tt> conversion methods duplicate
+the converted argument (its both the return value and the first argument)
+due to backward compatibility issues; you should set the first arguments to
+<tt class="literal">None</tt> and just use the return value. For example:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ sorted_iter = treemodelsort.convert_child_iter_to_iter(None, child_iter)
+ child_iter = treemodelsort.convert_iter_to_child_iter(None, sorted_iter)
+</pre></td></tr></table><p>Like the path conversion methods, these methods return
+<tt class="literal">None</tt> if the given <tt class="classname">TreeIter</tt> cannot
+be converted.</p><p>You can retrieve the child <tt class="classname">TreeModel</tt>
+using the <tt class="methodname">get_model</tt>() method.</p><p>A simple example program using
+<tt class="classname">TreeModelSort</tt> objects is <a href="examples/treemodelsort.py" target="_top">treemodelsort.py</a>. <a href="sec-TreeModelSortAndTreeModelFilter.html#treemodelsortfig" title="Figure 14.9. TreeModelSort Example">Figure 14.9, “TreeModelSort Exampleâ€</a> illustrates the result of running the program
+and adding six rows:</p><div class="figure"><a name="treemodelsortfig"></a><p class="title"><b>Figure 14.9. TreeModelSort Example</b></p><div class="mediaobject" align="center"><img src="figures/treemodelsort.png" align="middle" alt="TreeModelSort Example"></div></div><p>Each of the columns in the windows can be clicked to change the
+sort order independent of the other windows. When the "<span class="guibutton">Add a
+Row</span>" button is clicked a new row is added to the base
+<tt class="classname">ListStore</tt> and the new row is displayed in each
+<tt class="classname">TreeView</tt> as the selected row.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-TreeModelFilter"></a>14.10.2. TreeModelFilter</h3></div></div><div></div></div><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>The <tt class="classname">TreeModelFilter</tt> is available in
+PyGTK 2.4 and above.</p></div><p>A <tt class="classname">TreeModelFilter</tt> object provides several
+ways of modifying the view of the base <tt class="classname">TreeModel</tt>
+including:</p><div class="itemizedlist"><ul type="disc"><li>displaying a subset of the rows in the child model either
+based on boolean data in a "visible column", or based on the boolean return
+value of a "visible function" that takes the child model, a
+<tt class="classname">TreeIter</tt> pointing at a row in the child model and
+user data. In both cases if the boolean value is <tt class="literal">TRUE</tt> the
+row will be displayed; otherwise, the row will be hidden.</li><li>using a virtual root node to provide a view of a subtree
+of the children of a row in the child model. This only makes sense if the
+underlying store is a <tt class="classname">TreeStore</tt>.</li><li>synthesizing the columns and data of a model based on the
+data in the child model. For example, you can provide a column where the
+data is calculated from data in several child model columns.</li></ul></div><p>A <tt class="classname">TreeModelFilter</tt> object is created using
+the <tt class="classname">TreeModel</tt> method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treemodelfilter = treemodel.filter_new(<b class="parameter"><tt>root</tt></b>=None)
+</pre></td></tr></table><p>where <i class="parameter"><tt>root</tt></i> is a tree path in
+<i class="parameter"><tt>treemodel</tt></i> specifying the virtual root for the model
+or <tt class="literal">None</tt> if the root node of
+<i class="parameter"><tt>treemodel</tt></i> is to be used.</p><p>By setting a "virtual root" when creating the
+<tt class="classname">TreeModelFilter</tt>, you can limit the model view to the
+child rows of "root" row in the child model hierarchy. This, of course is
+only useful when the child model is based on a
+<tt class="classname">TreeStore</tt>. For example, you might want to provide a
+view of the parts list that makes up a CDROM drive separate from the full
+parts list of a computer.</p><p>The visibility modes are mutually exclusive and can only be set
+once i.e. once a visibility function or column is set it cannot be changed
+and the alternative mode cannot be set. The simplest visibility mode
+extracts a boolean value from a column in the child model to determine if
+the row should be displayed. The visibility columns is set using:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treemodelfilter.set_visible_column(<b class="parameter"><tt>column</tt></b>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>column</tt></i> is the number of the column
+in the child <tt class="classname">TreeModel</tt> to extract the boolean values
+from. For example, the following code fragment uses the values in the third
+column to set the visibility of the rows:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ ...
+ treestore = gtk.TreeStore(str, str, "gboolean")
+ ...
+ modelfilter = treestore.filter_new()
+ modelfilter.set_visible_column(2)
+ ...
+</pre></td></tr></table><p>Thus any rows in <i class="parameter"><tt>treestore</tt></i> that have a
+value of <tt class="literal">TRUE</tt> in the third column will be
+displayed.</p><p>If you have more complicated visibility criteria setting a
+visibility function should provide sufficient power:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treemodelfilter.set_visible_func(<b class="parameter"><tt>func</tt></b>, <b class="parameter"><tt>data</tt></b>=None)
+</pre></td></tr></table><p>where <i class="parameter"><tt>func</tt></i> is the function called for
+each child model row to determine if it should be displayed and
+<i class="parameter"><tt>data</tt></i> is user data passed to
+<i class="parameter"><tt>func</tt></i>. <i class="parameter"><tt>func</tt></i> should return
+<tt class="literal">TRUE</tt> if the row should be displayed. The signature of
+<i class="parameter"><tt>func</tt></i> is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def func(<i class="parameter"><tt>model</tt></i>, <i class="parameter"><tt>iter</tt></i>, <i class="parameter"><tt>user_data</tt></i>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>model</tt></i> is the child
+<tt class="classname">TreeModel</tt>, <i class="parameter"><tt>iter</tt></i> is a
+<tt class="classname">TreeIter</tt> pointing at a row in
+<i class="parameter"><tt>model</tt></i> and <i class="parameter"><tt>user_data</tt></i> is the
+passed in <i class="parameter"><tt>data</tt></i>.</p><p>If you make a change to the visibility criteria you should
+call:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treemodelfilter.refilter()
+</pre></td></tr></table><p>to force a refiltering of the child model rows.</p><p>For example, the following code fragment illustrates a
+<tt class="classname">TreeModelFilter</tt> that displays rows based on a
+comparison between the value in the third column and the contents of the
+user data:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ ...
+ def match_type(model, iter, udata):
+ value = model.get_value(iter, 2)
+ return value in udata
+ ...
+ show_vals = ['OPEN', 'NEW', 'RESO']
+ liststore = gtk.ListStore(str, str, str)
+ ...
+ modelfilter = liststore.filter_new()
+ modelfilter.set_visible_func(match_type, show_vals)
+ ...
+</pre></td></tr></table><p>The program <a href="examples/treemodelfilter.py" target="_top">treemodelfilter.py</a> illustrates the
+use of the <tt class="methodname">set_visible_func</tt>() method. <a href="sec-TreeModelSortAndTreeModelFilter.html#treemodelfilterfig" title="Figure 14.10. TreeModelFilter Visibility Example">Figure 14.10, “TreeModelFilter Visibility Exampleâ€</a> shows the result of running the
+program.</p><div class="figure"><a name="treemodelfilterfig"></a><p class="title"><b>Figure 14.10. TreeModelFilter Visibility Example</b></p><div class="mediaobject" align="center"><img src="figures/treemodelfilter.png" align="middle" alt="TreeModelFilter Visibility Example"></div></div><p>By toggling the buttons at the bottom the contents of the
+<tt class="classname">TreeView</tt> are changed to display only the rows that
+match one of the active buttons.</p><p>A modify function gives you another level of control over the
+<tt class="classname">TreeView</tt> display to the point where you can
+synthesize one or more (or even all) columns that are represented by the
+<tt class="classname">TreeModelFilter</tt>. You still have to use a base child
+model that is a <tt class="classname">TreeStore</tt> or
+<tt class="classname">ListStore</tt> to determine the number of rows and the
+hierarchy but the columns can be anything you specify in the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treemodelfilter.set_modify_func(<b class="parameter"><tt>types</tt></b>, <b class="parameter"><tt>func</tt></b>, <b class="parameter"><tt>data</tt></b>=None)
+</pre></td></tr></table><p>where <i class="parameter"><tt>types</tt></i> is a sequence (list or tuple)
+specifying the column types being represented, <i class="parameter"><tt>func</tt></i>
+is a function called to return the value for a row and column and
+<i class="parameter"><tt>data</tt></i> is an argument to be passed to
+<i class="parameter"><tt>func</tt></i>. The signature of <i class="parameter"><tt>func</tt></i>
+is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def func(<i class="parameter"><tt>model</tt></i>, <i class="parameter"><tt>iter</tt></i>, <i class="parameter"><tt>column</tt></i>, <i class="parameter"><tt>user_data</tt></i>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>model</tt></i> is the
+<tt class="classname">TreeModelFilter</tt>, <i class="parameter"><tt>iter</tt></i> is a
+<tt class="classname">TreeIter</tt> that points to a row in model,
+<i class="parameter"><tt>column</tt></i> is the number of the column that a value is
+needed for and <i class="parameter"><tt>user_data</tt></i> is the parameter
+<i class="parameter"><tt>data</tt></i>. <i class="parameter"><tt>func</tt></i> must return a value
+matching the type for <i class="parameter"><tt>column</tt></i>.</p><p>A modify function is useful where you want to provide a column
+of data that needs to be generated using the data in the child model
+columns. For example if you had a column containing birth dates and wanted
+to provide a column displaying ages, a modify function could generate the
+age information using the birth date and the current date. Another example
+would be to decide what image to display based on some analysis of the data
+(say, a filename) in a column. This effect can also be achieved using the
+<tt class="classname">TreeViewColumn</tt>
+<tt class="methodname">set_cell_data_func</tt>() method.</p><p>Usually within the modify function, you will have to convert the
+<tt class="classname">TreeModelFilter</tt> <tt class="classname">TreeIter</tt> to a
+<tt class="classname">TreeIter</tt> in the child model using:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ child_iter = treemodelfilter.convert_iter_to_child_iter(<b class="parameter"><tt>filter_iter</tt></b>)
+</pre></td></tr></table><p>Of course, you'll also need to retrieve the child model
+using:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ child_model = treemodelfilter.get_model()
+</pre></td></tr></table><p>These give you access to the child model row and its values for
+generating the value for the specified
+<tt class="classname">TreeModelFilter</tt> row and column. There's also a method
+to convert a child <tt class="classname">TreeIter</tt> to a filter model
+<tt class="classname">TreeIter</tt> and methods to convert filter model paths to
+and from child tree paths:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ filter_iter = treemodelfilter.convert_child_iter_to_iter(<b class="parameter"><tt>child_iter</tt></b>)
+
+ child_path = treemodelfilter.convert_path_to_child_path(<b class="parameter"><tt>filter_path</tt></b>)
+ filter_path = treemodelfilter.convert_child_path_to_path(<b class="parameter"><tt>child_path</tt></b>)
+</pre></td></tr></table><p>Of course, you can combine the visibility modes and the modify
+function to both filter rows and synthesize columns. To get even more
+control over the view you would have to use a custom
+<tt class="classname">TreeModel</tt>.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-TreeViewDragAndDrop.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-TreeViewWidget.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-GenericTreeModel.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">14.9. TreeView Drag and Drop </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 14.11. The Generic TreeModel</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-TreeSelections.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-TreeSelections.html
new file mode 100644
index 0000000..0138906
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-TreeSelections.html
@@ -0,0 +1,133 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>14.8. TreeSelections</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-TreeViewWidget.html" title="Chapter 14. Tree View Widget"><link rel="previous" href="sec-TreeViewSignals.html" title="14.7. TreeView Signals"><link rel="next" href="sec-TreeViewDragAndDrop.html" title="14.9. TreeView Drag and Drop"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">14.8. TreeSelections</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-TreeViewSignals.html">Prev</a> </td><th width="60%" align="center">Chapter 14. Tree View Widget</th><td width="20%" align="right"> <a accesskey="n" href="sec-TreeViewDragAndDrop.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-TreeSelections"></a>14.8. TreeSelections</h2></div></div><div></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-GettingTheTreeSelection"></a>14.8.1. Getting the TreeSelection</h3></div></div><div></div></div><p><tt class="classname">TreeSelection</tt>s are objects that manage
+selections in a <tt class="classname">TreeView</tt>. When a
+<tt class="classname">TreeView</tt> is created a
+<tt class="classname">TreeSelection</tt> is automatically created as well. The
+<tt class="classname">TreeSelection</tt> can be retrieved from the <tt class="classname">TreeView</tt>
+using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treeselection = treeview.get_selection()
+</pre></td></tr></table><p>You can retrieve the <tt class="classname">TreeView</tt> associated
+with a <tt class="classname">TreeSelection</tt> by calling the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treeview = treeselection.get_treeview()
+</pre></td></tr></table></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-TreeSelectionMode"></a>14.8.2. TreeSelection Modes</h3></div></div><div></div></div><p>The <tt class="classname">TreeSelection</tt> supports the following
+selection modes:</p><table border="0" width="100%" bgcolor="#FFECCE"><col align="left" valign="top" width="0*"><tbody><tr><td><span class="term"><tt class="literal">gtk.SELECTION_NONE</tt></span></td><td>No selection is allowed.</td></tr><tr><td><span class="term"><tt class="literal">gtk.SELECTION_SINGLE</tt></span></td><td>A single selection is allowed by clicking.</td></tr><tr><td><span class="term"><tt class="literal">gtk.SELECTION_BROWSE</tt></span></td><td>A single selection allowed by browsing with the pointer.</td></tr><tr><td><span class="term"><tt class="literal">gtk.SELECTION_MULTIPLE</tt></span></td><td>Multiple items can be selected at once.</td></tr></tbody></table><p>You can retrieve the current selection mode by calling the
+method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ mode = treeselection.get_mode()
+</pre></td></tr></table><p>The mode can be set using:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treeselection.set_mode(<b class="parameter"><tt>mode</tt></b>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>mode</tt></i> is one of the above selection
+modes.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-RetrievingTheTreeSelection"></a>14.8.3. Retrieving the Selection</h3></div></div><div></div></div><p>The method to use to retrieve the selection depends on the
+current selection mode. If the selection mode is
+<tt class="literal">gtk.SELECTION_SINGLE</tt> or
+<tt class="literal">gtk.SELECTION_BROWSE</tt>, you should use the following
+method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ (model, iter) = treeselection.get_selected()
+</pre></td></tr></table><p>that returns a 2-tuple containing <i class="parameter"><tt>model</tt></i>,
+the <tt class="classname">TreeModel</tt> used by the
+<tt class="classname">TreeView</tt> associated with
+<i class="parameter"><tt>treeselection</tt></i> and <i class="parameter"><tt>iter</tt></i>, a
+<tt class="classname">TreeIter</tt> pointing at the selected row. If no row is
+selected then <i class="parameter"><tt>iter</tt></i> is <tt class="literal">None</tt>. If the
+selection mode is <tt class="literal">gtk.SELECTION_MULTIPLE</tt> a TypeError
+exception is raised.</p><p>If you have a <tt class="classname">TreeView</tt> using the
+<tt class="literal">gtk.SELECTION_MULTIPLE</tt> selection mode then you should use
+the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ (model, pathlist) = treeselection.get_selected_rows()
+</pre></td></tr></table><p>that returns a 2-tuple containing the tree model and a list of
+the tree paths of the selected rows. This method is not available in PyGTK
+2.0 so you'll have to use a helper function to retrieve the list by
+using:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treeselection.selected_foreach(<i class="parameter"><tt>func</tt></i>, <i class="parameter"><tt>data</tt></i>=None)
+</pre></td></tr></table><p>where <i class="parameter"><tt>func</tt></i> is a function that is called
+on each selected row with <i class="parameter"><tt>data</tt></i>. The signature of
+<i class="parameter"><tt>func</tt></i> is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def func(<i class="parameter"><tt>model</tt></i>, <i class="parameter"><tt>path</tt></i>, <i class="parameter"><tt>iter</tt></i>, <i class="parameter"><tt>data</tt></i>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>model</tt></i> is the
+<tt class="classname">TreeModel</tt>, <i class="parameter"><tt>path</tt></i> is the tree
+path of the selected row and <i class="parameter"><tt>iter</tt></i> is a
+<tt class="classname">TreeIter</tt> pointing at the selected row.</p><p>This method can be used to simulate the
+<tt class="methodname">get_selected_row</tt>() method as follows:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ ...
+ def foreach_cb(model, path, iter, pathlist):
+ list.append(path)
+ ...
+ def my_get_selected_rows(treeselection):
+ pathlist = []
+ treeselection.selected_foreach(foreach_cb, pathlist)
+ model = sel.get_treeview().get_model()
+ return (model, pathlist)
+ ...
+</pre></td></tr></table><p>The <tt class="methodname">selected_foreach</tt>() method cannot be
+used to modify the tree model or the selection though you can change the
+data in the rows.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-TreeSelectionFunction"></a>14.8.4. Using a TreeSelection Function</h3></div></div><div></div></div><p>If you want ultimate control over row selection you can set a
+function to be called before a row is selected or unselected by using the
+method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treeselection.set_select_function(<i class="parameter"><tt>func</tt></i>, <i class="parameter"><tt>data</tt></i>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>func</tt></i> is a callback function and
+<i class="parameter"><tt>data</tt></i> is user data to be passed to
+<i class="parameter"><tt>func</tt></i> when it is called. <i class="parameter"><tt>func</tt></i>
+has the signature:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def func(<i class="parameter"><tt>selection</tt></i>, <i class="parameter"><tt>model</tt></i>, <i class="parameter"><tt>path</tt></i>, <i class="parameter"><tt>is_selected</tt></i>, <i class="parameter"><tt>user_data</tt></i>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>selection</tt></i> is the
+<tt class="classname">TreeSelection</tt>, <i class="parameter"><tt>model</tt></i> is the
+<tt class="classname">TreeModel</tt> used with the
+<tt class="classname">TreeView</tt> associated with
+<i class="parameter"><tt>selection</tt></i>, <i class="parameter"><tt>path</tt></i> is the tree
+path of the selected row, <i class="parameter"><tt>is_selected</tt></i> is
+<tt class="literal">TRUE</tt> if the row is currently selected and
+<i class="parameter"><tt>user_data</tt></i> is
+<i class="parameter"><tt>data</tt></i>. <i class="parameter"><tt>func</tt></i> should return
+<tt class="literal">TRUE</tt> if the row's selection status should be
+toggled.</p><p>Setting a select function is useful if:</p><div class="itemizedlist"><ul type="disc"><li>you want to control the selection or unselection of a row
+based on some additional context information. You will need to indicate in
+some way that the selection change can't be made and perhaps why. For
+example, you can visually differentiate the row or pop up a
+<tt class="classname">MessageDialog</tt>.</li><li>you need to maintain your own list of selected or
+unselected rows though this can also be done by connecting to the "changed"
+signal but with more effort.</li><li>you want to do some additional processing before a row is
+selected or unselected. For example change the look of the row or modify the
+row data.</li></ul></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-SelectingAndUnselectingRows"></a>14.8.5. Selecting and Unselecting Rows</h3></div></div><div></div></div><p>You can change the selection programmatically using the
+following methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treeselection.select_path(<b class="parameter"><tt>path</tt></b>)
+ treeselection.unselect_path(<b class="parameter"><tt>path</tt></b>)
+
+ treeselection.select_iter(<b class="parameter"><tt>iter</tt></b>)
+ treeselection.unselect_iter(<b class="parameter"><tt>iter</tt></b>)
+</pre></td></tr></table><p>These methods select or unselect a single row that is specified
+by either <i class="parameter"><tt>path</tt></i>, a tree path or
+<i class="parameter"><tt>iter</tt></i>, a <tt class="classname">TreeIter</tt> pointing at
+the row. The following methods select or unselect several rows at
+once:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treeselection.select_all()
+ treeselection.unselect_all()
+
+ treeselection.select_range(<b class="parameter"><tt>start_path</tt></b>, <b class="parameter"><tt>end_path</tt></b>)
+ treeselection.unselect_range(<b class="parameter"><tt>start_path</tt></b>, <b class="parameter"><tt>end_path</tt></b>)
+</pre></td></tr></table><p>The <tt class="methodname">select_all</tt>() method requires that
+the selection mode be <tt class="literal">gtk.SELECTION_MULTIPLE</tt> as does the
+<tt class="methodname">select_range</tt>() method. The
+<tt class="methodname">unselect_all</tt>() and
+<tt class="methodname">unselect_range</tt>() methods will function with any
+selection mode. Note that the <tt class="methodname">unselect_all</tt>() method
+is not available in PyGTK 2.0</p><p>You can check if a row is selected by using one of the
+methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ result = treeselection.path_is_selected(path)
+ result = treeselection.iter_is_selected(iter)
+</pre></td></tr></table><p>that return <tt class="literal">TRUE</tt> if the row specified by
+<i class="parameter"><tt>path</tt></i> or <i class="parameter"><tt>iter</tt></i> is currently
+selected. You can retrieve a count of the number of selected rows using the
+method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ count = treeselection.count_selected_rows()
+</pre></td></tr></table><p>This method is not available in PyGTK 2.0 so you'll have to
+simulate it using the <tt class="methodname">selected_foreach</tt>() method
+similar to the simulation of the
+<tt class="methodname">get_selected_rows</tt>() method in <a href="sec-RetrievingTheSelection.html" title="21.2. Retrieving the Selection">Section 21.2, “Retrieving the Selectionâ€</a>. For example:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ ...
+ def foreach_cb(model, path, iter, counter):
+ counter[0] += 1
+ ...
+ def my_count_selected_rows(treeselection):
+ counter = [0]
+ treeselection.selected_foreach(foreach_cb, counter)
+ return counter[0]
+ ...
+</pre></td></tr></table></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-TreeViewSignals.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-TreeViewWidget.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-TreeViewDragAndDrop.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">14.7. TreeView Signals </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 14.9. TreeView Drag and Drop</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-TreeViewColumns.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-TreeViewColumns.html
new file mode 100644
index 0000000..751351b
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-TreeViewColumns.html
@@ -0,0 +1,60 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>14.5. TreeViewColumns</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-TreeViewWidget.html" title="Chapter 14. Tree View Widget"><link rel="previous" href="sec-CellRenderers.html" title="14.4. CellRenderers"><link rel="next" href="sec-ManipulatingTreeViews.html" title="14.6. Manipulating TreeViews"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">14.5. TreeViewColumns</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-CellRenderers.html">Prev</a> </td><th width="60%" align="center">Chapter 14. Tree View Widget</th><td width="20%" align="right"> <a accesskey="n" href="sec-ManipulatingTreeViews.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-TreeViewColumns"></a>14.5. TreeViewColumns</h2></div></div><div></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-CreatingTreeViewColumns"></a>14.5.1. Creating TreeViewColumns</h3></div></div><div></div></div><p>A <tt class="classname">TreeViewColumn</tt> is created using the
+constructor:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treeviewcolumn = gtk.TreeViewColumn(<i class="parameter"><tt>title</tt></i>=None, <i class="parameter"><tt>cell_renderer=None</tt></i>, <i class="parameter"><tt>...</tt></i>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>title</tt></i> is the string to be used as
+the column header label, and <i class="parameter"><tt>cell_renderer</tt></i> is the
+first <tt class="classname">CellRenderer</tt> to pack in the column. Additional
+arguments that are passed to the constructor are keyword values (in the
+format attribute=column) that set attributes on
+<i class="parameter"><tt>cell_renderer</tt></i>. For example:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treeviewcolumn = gtk.TreeViewColumn('States', cell, text=0, foreground=1)
+</pre></td></tr></table><p>creates a <tt class="classname">TreeViewColumn</tt> with the
+<tt class="classname">CellRendererText</tt> cell retrieving its text from the
+first column of the tree model and the text color from the second
+column.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-ManagingCellRenderers"></a>14.5.2. Managing CellRenderers</h3></div></div><div></div></div><p>A <tt class="classname">CellRenderer</tt> can be added to a
+<tt class="classname">TreeViewColumn</tt> using one of the methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treeviewcolumn.pack_start(<b class="parameter"><tt>cell</tt></b>, <b class="parameter"><tt>expand</tt></b>)
+ treeviewcolumn.pack_end(<b class="parameter"><tt>cell</tt></b>, <b class="parameter"><tt>expand</tt></b>)
+</pre></td></tr></table><p><tt class="methodname">pack_start</tt>() and
+<tt class="methodname">pack_end</tt>() add <i class="parameter"><tt>cell</tt></i> to the
+start or end, respectively, of the <tt class="classname">TreeViewColumn</tt>. If
+<i class="parameter"><tt>expand</tt></i> is <tt class="literal">TRUE</tt>,
+<i class="parameter"><tt>cell</tt></i> will share in any available extra space
+allocated by the <tt class="classname">TreeViewColumn</tt>.</p><p>The <tt class="methodname">get_cell_renderers</tt>() method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ cell_list = treeviewcolumn.get_cell_renderers()
+</pre></td></tr></table><p>returns a list of all the <tt class="classname">CellRenderer</tt>s
+in the column.</p><p>The <tt class="methodname">clear</tt>() method removes all the
+<tt class="classname">CellRenderer</tt> attributes from the
+<tt class="classname">TreeViewColumn</tt>:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treeviewcolumn.clear()
+</pre></td></tr></table><p>There are a large number of other methods available for a
+<tt class="classname">TreeViewColumn</tt> - mostly dealing with setting and
+getting properties. See the <a href="http://www.pygtk.org/pygtk2reference/index.html" target="_top">PyGTK Reference
+Manual</a> for more information on the
+<tt class="classname">TreeViewColumn</tt> properties. The capability of using
+the built-in sorting facility is set using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treeviewcolumn.set_sort_column_id(<b class="parameter"><tt>sort_column_id</tt></b>)
+</pre></td></tr></table><p>sets <i class="parameter"><tt>sort_column_id</tt></i> as the tree model
+sort column ID to use when sorting the <tt class="classname">TreeView</tt>
+display. This method also sets the "clickable" property of the column that
+allows the user to click on the column header to activate the sorting. When
+the user clicks on the column header, the
+<tt class="classname">TreeViewColumn</tt> sort column ID is set as the
+<tt class="classname">TreeModel</tt> sort column ID and the
+<tt class="classname">TreeModel</tt> rows are resorted using the associated sort
+comparison function. The automatic sorting facility also toggles the sort
+order of the column and manages the display of the sort indicator. See <a href="sec-TreeModelInterface.html#sec-SortingTreeModelRows" title="14.2.9. Sorting TreeModel Rows">Section 14.2.9, “Sorting TreeModel Rowsâ€</a> for more information on sort
+column IDs and sort comparison functions. Typically when using a
+<tt class="classname">ListStore</tt> or <tt class="classname">TreeStore</tt> the
+default sort column ID (i.e. the column index) of the
+<tt class="classname">TreeModel</tt> column associated with the
+<tt class="classname">TreeViewColumn</tt> is set as the
+<tt class="classname">TreeViewColumn</tt> sort column ID.</p><p>If you use the <tt class="classname">TreeViewColumn</tt> headers for
+sorting by using the <tt class="methodname">set_sort_column_id</tt>() method,
+you don't need to use the <tt class="classname">TreeSortable</tt>
+<tt class="methodname">set_sort_column_id</tt>() method.</p><p>You can track the sorting operations or use a header click for
+your own purposes by connecting to the "clicked" signal of the
+<tt class="classname">TreeView</tt> column. The callback function should be
+defined as:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def callback(treeviewcolumn, user_data, ...)
+</pre></td></tr></table></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-CellRenderers.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-TreeViewWidget.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-ManipulatingTreeViews.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">14.4. CellRenderers </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 14.6. Manipulating TreeViews</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-TreeViewDragAndDrop.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-TreeViewDragAndDrop.html
new file mode 100644
index 0000000..70e60b7
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-TreeViewDragAndDrop.html
@@ -0,0 +1,250 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>14.9. TreeView Drag and Drop</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-TreeViewWidget.html" title="Chapter 14. Tree View Widget"><link rel="previous" href="sec-TreeSelections.html" title="14.8. TreeSelections"><link rel="next" href="sec-TreeModelSortAndTreeModelFilter.html" title="14.10. TreeModelSort and TreeModelFilter"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">14.9. TreeView Drag and Drop</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-TreeSelections.html">Prev</a> </td><th width="60%" align="center">Chapter 14. Tree View Widget</th><td width="20%" align="right"> <a accesskey="n" href="sec-TreeModelSortAndTreeModelFilter.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-TreeViewDragAndDrop"></a>14.9. TreeView Drag and Drop</h2></div></div><div></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="DragDropReordering"></a>14.9.1. Drag and Drop Reordering</h3></div></div><div></div></div><p>Reordering of the <tt class="classname">TreeView</tt> rows (and the
+underlying tree model rows is enabled by using the
+<tt class="methodname">set_reorderable</tt>() method mentioned above. The
+<i class="parameter"><tt>set_reorderable</tt></i>() method sets the "reorderable"
+property to the specified value and enables or disables the internal drag
+and drop of <tt class="classname">TreeView</tt> rows. When the "reorderable"
+property is <tt class="literal">TRUE</tt> a user can drag
+<tt class="classname">TreeView</tt> rows and drop them at a new location. This
+action causes the underlying <tt class="classname">TreeModel</tt> rows to be
+rearranged to match. Drag and drop reordering of rows only works with
+unsorted stores.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-ExternalDragDrop"></a>14.9.2. External Drag and Drop</h3></div></div><div></div></div><p>If you want to control the drag and drop or deal
+with drag and drop from external sources, you'll have to enable and control
+the drag and drop using the following methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treeview.enable_model_drag_source(<b class="parameter"><tt>start_button_mask</tt></b>, <b class="parameter"><tt>targets</tt></b>, <b class="parameter"><tt>actions</tt></b>)
+ treeview.enable_model_drag_dest(<b class="parameter"><tt>targets</tt></b>, <b class="parameter"><tt>actions</tt></b>)
+</pre></td></tr></table><p>These methods enable using rows as a drag source and a drop site
+respectively. <i class="parameter"><tt>start_button_mask</tt></i> is a modifier mask
+(see the <a href="http://www.pygtk.org/pygtk2reference/gdk-constants.html#gdk-modifier-constants" target="_top">gtk.gtk
+Constants reference</a> in the <a href="http://www.pygtk.org/pygtk2reference/index.html" target="_top">PyGTK Reference
+Manual</a>) that specifies the buttons or keys that must be pressed to
+start the drag operation. <i class="parameter"><tt>targets</tt></i> is a list of
+3-tuples that describe the target information that can be given or
+received. For a drag and drop to succeed at least one of the targets must
+match in the drag source and drag destination (e.g. the "STRING"
+target). Each target 3-tuple contains the target name, flags (a combination
+of <tt class="literal">gtk.TARGET_SAME_APP</tt> and
+<tt class="literal">gtk.TARGET_SAME_WIDGET</tt> or neither) and a unique int
+identifier. <i class="parameter"><tt>actions</tt></i> describes what the result of the
+operation should be:</p><table border="0" width="100%" bgcolor="#FFECCE"><col align="left" valign="top" width="0*"><tbody><tr><td><span class="term"><tt class="literal">gtk.gdk.ACTION_DEFAULT</tt>, </span><span class="term"><tt class="literal">gtk.gdk.ACTION_COPY</tt>, </span></td><td>Copy the data.</td></tr><tr><td><span class="term"><tt class="literal">gtk.gdk.ACTION_MOVE</tt></span></td><td>Move the data, i.e. first copy it, then delete it from
+the source using the <tt class="literal">DELETE</tt> target of the X selection
+protocol.</td></tr><tr><td><span class="term"><tt class="literal">gtk.gdk.ACTION_LINK</tt></span></td><td>Add a link to the data. Note that this is only useful
+if source and destination agree on what it means.</td></tr><tr><td><span class="term"><tt class="literal">gtk.gdk.ACTION_PRIVATE</tt></span></td><td>Special action which tells the source that the
+destination will do something that the source doesn't understand.</td></tr><tr><td><span class="term"><tt class="literal">gtk.gdk.ACTION_ASK</tt></span></td><td>Ask the user what to do with the data.</td></tr></tbody></table><p>For example to set up a drag drop destination:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treeview.enable_model_drag_dest([('text/plain', 0, 0)],
+ gtk.gdk.ACTION_DEFAULT | gtk.gdk.ACTION_MOVE)
+</pre></td></tr></table><p>Then you'll have to handle the <tt class="classname">Widget</tt>
+"drag-data-received" signal to receive that dropped data - perhaps replacing
+the data in the row it was dropped on. The signature for the callback for
+the "drag-data-received" signal is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def callback(<i class="parameter"><tt>widget</tt></i>, <i class="parameter"><tt>drag_context</tt></i>, <i class="parameter"><tt>x</tt></i>, <i class="parameter"><tt>y</tt></i>, <i class="parameter"><tt>selection_data</tt></i>, <i class="parameter"><tt>info</tt></i>, <i class="parameter"><tt>timestamp</tt></i>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>widget</tt></i> is the
+<tt class="classname">TreeView</tt>, <i class="parameter"><tt>drag_context</tt></i> is a
+<tt class="classname">DragContext</tt> containing the context of the selection,
+<i class="parameter"><tt>x</tt></i> and <i class="parameter"><tt>y</tt></i> are the position where
+the drop occurred, <i class="parameter"><tt>selection_data</tt></i> is the
+<tt class="classname">SelectionData</tt> containing the data,
+<i class="parameter"><tt>info</tt></i> is the ID integer of the type,
+<i class="parameter"><tt>timestamp</tt></i> is the time when the drop occurred. The row
+can be identified by calling the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ drop_info = treeview.get_dest_row_at_pos(<b class="parameter"><tt>x</tt></b>, <b class="parameter"><tt>y</tt></b>)
+</pre></td></tr></table><p>where (<i class="parameter"><tt>x</tt></i>,
+<i class="parameter"><tt>y</tt></i>) is the position passed to the callback
+function and <i class="parameter"><tt>drop_info</tt></i> is a 2-tuple containing the
+path of a row and a position constant indicating where the drop is with
+respect to the row: <tt class="literal">gtk.TREE_VIEW_DROP_BEFORE</tt>,
+<tt class="literal">gtk.TREE_VIEW_DROP_AFTER</tt>,
+<tt class="literal">gtk.TREE_VIEW_DROP_INTO_OR_BEFORE</tt> or
+<tt class="literal">gtk.TREE_VIEW_DROP_INTO_OR_AFTER</tt>. The callback function
+could be something like:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treeview.enable_model_drag_dest([('text/plain', 0, 0)],
+ gtk.gdk.ACTION_DEFAULT | gtk.gdk.ACTION_MOVE)
+ treeview.connect("drag-data-received", drag_data_received_cb)
+ ...
+ ...
+ def drag_data_received_cb(treeview, context, x, y, selection, info, timestamp):
+ drop_info = treeview.get_dest_row_at_pos(x, y)
+ if drop_info:
+ model = treeview.get_model()
+ path, position = drop_info
+ data = selection.data
+ # do something with the data and the model
+ ...
+ return
+ ...
+</pre></td></tr></table><p>If a row is being used as a drag source it must handle the
+<tt class="classname">Widget</tt> "drag-data-get" signal that populates a
+selection with the data to be passed back to the drag drop destination with
+a callback function with the signature:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def callback(<i class="parameter"><tt>widget</tt></i>, <i class="parameter"><tt>drag_context</tt></i>, <i class="parameter"><tt>selection_data</tt></i>, <i class="parameter"><tt>info</tt></i>, <i class="parameter"><tt>timestamp</tt></i>)
+</pre></td></tr></table><p>The parameters to <i class="parameter"><tt>callback</tt></i> are similar to
+those of the "drag-data-received" callback function. Since the callback is
+not passed a tree path or any easy way of retrieving information about the
+row being dragged, we assume that the row being dragged is selected and the
+selection mode is <tt class="literal">gtk.SELECTION_SINGLE</tt> or
+<tt class="literal">gtk.SELECTION_BROWSE</tt> so we can retrieve the row by
+getting the <tt class="classname">TreeSelection</tt> and retrieving the tree
+model and <tt class="classname">TreeIter</tt> pointing at the row. For example,
+text from a row could be passed in the drag drop by:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ ...
+ treestore = gtk.TreeStore(str, str)
+ ...
+ treeview.enable_model_drag_source(gtk.gdk.BUTTON1_MASK,
+ [('text/plain', 0, 0)],
+ gtk.gdk.ACTION_DEFAULT | gtk.gdk.ACTION_MOVE)
+ treeview.connect("drag-data-get", drag_data_get_cb)
+ ...
+ ...
+ def drag_data_get_cb(treeview, context, selection, info, timestamp):
+ treeselection = treeview.get_selection()
+ model, iter = treeselection.get_selected()
+ text = model.get_value(iter, 1)
+ selection.set('text/plain', 8, text)
+ return
+ ...
+</pre></td></tr></table><p>The <tt class="classname">TreeView</tt> can be disabled as a drag
+source and drop destination by using the methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treeview.unset_rows_drag_source()
+ treeview.unset_rows_drag_dest()
+</pre></td></tr></table></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-TreeViewDnDExample"></a>14.9.3. TreeView Drag and Drop Example</h3></div></div><div></div></div><p>A simple example program is needed to pull together the pieces
+of code described above. This example (<a href="examples/treeviewdnd.py" target="_top">treeviewdnd.py</a>) is a list that URLs
+can be dragged from and dropped on. Also the URLs in the list can be
+reordered by dragging and dropping within the
+<tt class="classname">TreeView</tt>. A couple of buttons are provided to clear
+the list and to clear a selected item.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 1 #!/usr/bin/env python
+ 2
+ 3 # example treeviewdnd.py
+ 4
+ 5 import pygtk
+ 6 pygtk.require('2.0')
+ 7 import gtk
+ 8
+ 9 class TreeViewDnDExample:
+ 10
+ 11 TARGETS = [
+ 12 ('MY_TREE_MODEL_ROW', gtk.TARGET_SAME_WIDGET, 0),
+ 13 ('text/plain', 0, 1),
+ 14 ('TEXT', 0, 2),
+ 15 ('STRING', 0, 3),
+ 16 ]
+ 17 # close the window and quit
+ 18 def delete_event(self, widget, event, data=None):
+ 19 gtk.main_quit()
+ 20 return False
+ 21
+ 22 def clear_selected(self, button):
+ 23 selection = self.treeview.get_selection()
+ 24 model, iter = selection.get_selected()
+ 25 if iter:
+ 26 model.remove(iter)
+ 27 return
+ 28
+ 29 def __init__(self):
+ 30 # Create a new window
+ 31 self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ 32
+ 33 self.window.set_title("URL Cache")
+ 34
+ 35 self.window.set_size_request(200, 200)
+ 36
+ 37 self.window.connect("delete_event", self.delete_event)
+ 38
+ 39 self.scrolledwindow = gtk.ScrolledWindow()
+ 40 self.vbox = gtk.VBox()
+ 41 self.hbox = gtk.HButtonBox()
+ 42 self.vbox.pack_start(self.scrolledwindow, True)
+ 43 self.vbox.pack_start(self.hbox, False)
+ 44 self.b0 = gtk.Button('Clear All')
+ 45 self.b1 = gtk.Button('Clear Selected')
+ 46 self.hbox.pack_start(self.b0)
+ 47 self.hbox.pack_start(self.b1)
+ 48
+ 49 # create a liststore with one string column to use as the model
+ 50 self.liststore = gtk.ListStore(str)
+ 51
+ 52 # create the TreeView using liststore
+ 53 self.treeview = gtk.TreeView(self.liststore)
+ 54
+ 55 # create a CellRenderer to render the data
+ 56 self.cell = gtk.CellRendererText()
+ 57
+ 58 # create the TreeViewColumns to display the data
+ 59 self.tvcolumn = gtk.TreeViewColumn('URL', self.cell, text=0)
+ 60
+ 61 # add columns to treeview
+ 62 self.treeview.append_column(self.tvcolumn)
+ 63 self.b0.connect_object('clicked', gtk.ListStore.clear, self.liststore)
+ 64 self.b1.connect('clicked', self.clear_selected)
+ 65 # make treeview searchable
+ 66 self.treeview.set_search_column(0)
+ 67
+ 68 # Allow sorting on the column
+ 69 self.tvcolumn.set_sort_column_id(0)
+ 70
+ 71 # Allow enable drag and drop of rows including row move
+ 72 self.treeview.enable_model_drag_source( gtk.gdk.BUTTON1_MASK,
+ 73 self.TARGETS,
+ 74 gtk.gdk.ACTION_DEFAULT|
+ 75 gtk.gdk.ACTION_MOVE)
+ 76 self.treeview.enable_model_drag_dest(self.TARGETS,
+ 77 gtk.gdk.ACTION_DEFAULT)
+ 78
+ 79 self.treeview.connect("drag_data_get", self.drag_data_get_data)
+ 80 self.treeview.connect("drag_data_received",
+ 81 self.drag_data_received_data)
+ 82
+ 83 self.scrolledwindow.add(self.treeview)
+ 84 self.window.add(self.vbox)
+ 85 self.window.show_all()
+ 86
+ 87 def drag_data_get_data(self, treeview, context, selection, target_id,
+ 88 etime):
+ 89 treeselection = treeview.get_selection()
+ 90 model, iter = treeselection.get_selected()
+ 91 data = model.get_value(iter, 0)
+ 92 selection.set(selection.target, 8, data)
+ 93
+ 94 def drag_data_received_data(self, treeview, context, x, y, selection,
+ 95 info, etime):
+ 96 model = treeview.get_model()
+ 97 data = selection.data
+ 98 drop_info = treeview.get_dest_row_at_pos(x, y)
+ 99 if drop_info:
+ 100 path, position = drop_info
+ 101 iter = model.get_iter(path)
+ 102 if (position == gtk.TREE_VIEW_DROP_BEFORE
+ 103 or position == gtk.TREE_VIEW_DROP_INTO_OR_BEFORE):
+ 104 model.insert_before(iter, [data])
+ 105 else:
+ 106 model.insert_after(iter, [data])
+ 107 else:
+ 108 model.append([data])
+ 109 if context.action == gtk.gdk.ACTION_MOVE:
+ 110 context.finish(True, True, etime)
+ 111 return
+ 112
+ 113 def main():
+ 114 gtk.main()
+ 115
+ 116 if __name__ == "__main__":
+ 117 treeviewdndex = TreeViewDnDExample()
+ 118 main()
+</pre></td></tr></table><p>The result of running the example program <a href="examples/treeviewdnd.py" target="_top">treeviewdnd.py</a> is illustrated in
+<a href="sec-TreeViewDragAndDrop.html#treeviewdndfig" title="Figure 14.8. TreeView Drag and Drop Example">Figure 14.8, “TreeView Drag and Drop Exampleâ€</a>:</p><div class="figure"><a name="treeviewdndfig"></a><p class="title"><b>Figure 14.8. TreeView Drag and Drop Example</b></p><div class="mediaobject" align="center"><img src="figures/treeviewdnd.png" align="middle" alt="TreeView Drag and Drop Example"></div></div><p>The key to allowing both external drag and drop and internal row
+reordering is the organization of the targets (the
+<tt class="literal">TARGETS</tt> attribute - line 11). An application specific
+target (<tt class="literal">MY_TREE_MODEL_ROW</tt>) is created and used to
+indicate a drag and drop within the <tt class="classname">TreeView</tt> by
+setting the <tt class="literal">gtk.TARGET_SAME_WIDGET</tt> flag. By setting this
+as the first target the drag destination will attempt to match it first with
+the drag source targets. Next the source drag actions must include
+<tt class="literal">gtk.gdk.ACTION_MOVE</tt> and
+<tt class="literal">gtk.gdk.ACTION_DEFAULT</tt> (see lines 72-75). When the
+destination is receiving the data from the source, if the
+<tt class="classname">DragContext</tt> action is
+<tt class="literal">gtk.gdk.ACTION_MOVE</tt> the source is told to delete the data
+(in this case the row) by calling the <tt class="classname">DragContext</tt>
+method <tt class="methodname">finish</tt>() (see lines 109-110). The
+<tt class="classname">TreeView</tt> provides a number of internal functions that
+we are leveraging to drag, drop and delete the data.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-TreeSelections.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-TreeViewWidget.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-TreeModelSortAndTreeModelFilter.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">14.8. TreeSelections </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 14.10. TreeModelSort and TreeModelFilter</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-TreeViewSignals.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-TreeViewSignals.html
new file mode 100644
index 0000000..f1c98d5
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-TreeViewSignals.html
@@ -0,0 +1,26 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>14.7. TreeView Signals</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-TreeViewWidget.html" title="Chapter 14. Tree View Widget"><link rel="previous" href="sec-ManipulatingTreeViews.html" title="14.6. Manipulating TreeViews"><link rel="next" href="sec-TreeSelections.html" title="14.8. TreeSelections"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">14.7. TreeView Signals</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-ManipulatingTreeViews.html">Prev</a> </td><th width="60%" align="center">Chapter 14. Tree View Widget</th><td width="20%" align="right"> <a accesskey="n" href="sec-TreeSelections.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-TreeViewSignals"></a>14.7. TreeView Signals</h2></div></div><div></div></div><p><tt class="classname">TreeView</tt>s emit a large number of signals
+that you can use to track changes in the view of the model. The signals
+generally fall into the following categories:</p><div class="itemizedlist"><ul type="disc"><li>expanding and collapsing rows: "row-collapsed",
+"row-expanded", "test-collapse-row", "test-expand-row" and
+"expand-collapse-cursor-row"</li><li>the cursor: "cursor-changed", "expand-collapse-cursor-row",
+"move-cursor", "select-cursor-parent", "select-cursor-row" and
+"toggle-cursor-row"</li><li>selection: "select-all", "select-cursor-parent",
+"select-cursor-row" and "unselect-all".</li><li>miscellaneous: "columns-changed", "row-activated",
+"set-scroll-adjustments" and "start-interactive-search".</li></ul></div><p>The "test-collapse-row" and "test-expand-row" signals are emitted
+before a row is collapsed or expanded. The return value from your callback
+can cancel or allow the operation - <tt class="literal">TRUE</tt> to allow and
+<tt class="literal">FALSE</tt> to cancel.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def callback(treeview, iter, path, user_data)
+</pre></td></tr></table><p>where <i class="parameter"><tt>iter</tt></i> is a
+<tt class="classname">TreeIter</tt> and <i class="parameter"><tt>path</tt></i> is a tree
+path pointing at the row and <i class="parameter"><tt>user_data</tt></i> is the data
+specified in the <tt class="methodname">connect</tt>() method.</p><p>The "row-activated" signal is emitted when a double click occurs
+on a row or a non-editable row is selected and one of the keys:
+<span><b class="keycap">Space</b></span>, <span><b class="keycap">Shift</b></span>+<span><b class="keycap">Space</b></span>,
+<span><b class="keycap">Return</b></span> or <span><b class="keycap">Enter</b></span> is pressed.</p><p>The rest of the signals are emitted after the
+<tt class="classname">TreeView</tt> has changed. The cursor is the row outlined
+by a box. In most cases moving the cursor also moves the selection. The
+cursor can be moved independently by <span><b class="keycap">Control</b></span>+<span><b class="keycap">Down</b></span> or
+<span><b class="keycap">Control</b></span>+<span><b class="keycap">Up</b></span> and various other key combinations.</p><p>See the <a href="http://www.pygtk.org/pygtk2reference/class-gtktreeview.html" target="_top">PyGTK
+Reference Manual</a> for more information on the
+<tt class="classname">TreeView</tt> signals.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-ManipulatingTreeViews.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-TreeViewWidget.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-TreeSelections.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">14.6. Manipulating TreeViews </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 14.8. TreeSelections</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-TreeViews.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-TreeViews.html
new file mode 100644
index 0000000..838e2a5
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-TreeViews.html
@@ -0,0 +1,88 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>14.3. TreeViews</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-TreeViewWidget.html" title="Chapter 14. Tree View Widget"><link rel="previous" href="sec-TreeModelInterface.html" title="14.2. The TreeModel Interface and Data Stores"><link rel="next" href="sec-CellRenderers.html" title="14.4. CellRenderers"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">14.3. TreeViews</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-TreeModelInterface.html">Prev</a> </td><th width="60%" align="center">Chapter 14. Tree View Widget</th><td width="20%" align="right"> <a accesskey="n" href="sec-CellRenderers.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-TreeViews"></a>14.3. TreeViews</h2></div></div><div></div></div><p>A <tt class="classname">TreeView</tt> is basically a container for the
+<tt class="classname">TreeViewColumn</tt> and
+<tt class="classname">CellRenderer</tt> objects that do the actual display of
+the data store data. It also provides an interface to the displayed data
+rows and to the characteristics that control the data display.</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-CreatingTreeView"></a>14.3.1. Creating a TreeView</h3></div></div><div></div></div><p>A <tt class="classname">TreeView</tt> is created using its
+constructor:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treeview = gtk.TreeView(<b class="parameter"><tt>model</tt></b>=None)
+</pre></td></tr></table><p>where <i class="parameter"><tt>model</tt></i> is an object implementing the
+<tt class="classname">TreeModel</tt> interface (usually a
+<tt class="classname">ListStore</tt> or <tt class="classname">TreeStore</tt>). If
+<i class="parameter"><tt>model</tt></i> is <tt class="literal">None</tt> or not specified the
+<tt class="classname">TreeView</tt> will not be associated with a data
+store.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-TreeViewModelAccess"></a>14.3.2. Getting and Setting the TreeView Model</h3></div></div><div></div></div><p>The tree model providing the data store for a
+<tt class="classname">TreeView</tt> can be retrieved using the
+<tt class="methodname">get_model</tt>() method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ model = treeview.get_model()
+</pre></td></tr></table><p>A <tt class="classname">TreeModel</tt> may be simultaneously
+associated with more than one <tt class="classname">TreeView</tt> which
+automatically changes its display when the <tt class="classname">TreeModel</tt>
+data changes. While a <tt class="classname">TreeView</tt> always displays all of
+the rows of its tree model, it may display only some of the tree model
+columns. This means that two <tt class="classname">TreeView</tt>s associated
+with the same <tt class="classname">TreeModel</tt> may provide completely
+different views of the same data.</p><p>It's also important to realize that there is no preset relation
+between the columns in a <tt class="classname">TreeView</tt> and the columns of
+its <tt class="classname">TreeModel</tt>. That is, the fifth column of data in a
+<tt class="classname">TreeModel</tt> may be displayed in the first column of one
+<tt class="classname">TreeView</tt> and in the third column in another.</p><p>A <tt class="classname">TreeView</tt> can change its tree model
+using the <tt class="methodname">set_model</tt>() method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ treeview.set_model(<b class="parameter"><tt>model</tt></b>=None)
+</pre></td></tr></table><p>where <i class="parameter"><tt>model</tt></i> is an object implementing the
+<tt class="classname">TreeModel</tt> interface
+(e.g. <tt class="classname">ListStore</tt> and
+<tt class="classname">TreeStore</tt>). If <i class="parameter"><tt>model</tt></i> is
+<tt class="literal">None</tt>, the current model is discarded.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-TreeViewProperties"></a>14.3.3. Setting TreeView Properties</h3></div></div><div></div></div><p>The <tt class="classname">TreeView</tt> has a number of properties
+that can be managed using its methods:</p><div class="informaltable"><table cellpadding="5" width="100%" border="0"><colgroup><col><col><col></colgroup><tbody><tr valign="top"><td valign="top">"enable-search"</td><td valign="top">Read-Write</td><td valign="top">If <tt class="literal">TRUE</tt>, the user can search through
+columns interactively. Default is <tt class="literal">TRUE</tt></td></tr><tr valign="top"><td valign="top">"expander-column"</td><td valign="top">Read-Write</td><td valign="top">The column for the expander. Default is 0</td></tr><tr valign="top"><td valign="top">"fixed-height-mode"</td><td valign="top">Read-Write</td><td valign="top">If <tt class="literal">TRUE</tt>, assume all rows have the
+same height thereby speeding up display. Available in GTK+ 2.4 and
+above. Default is <tt class="literal">FALSE</tt></td></tr><tr valign="top"><td valign="top">"hadjustment"</td><td valign="top">Read-Write</td><td valign="top">The horizontal <tt class="classname">Adjustment</tt> for
+the widget. New one created by default.</td></tr><tr valign="top"><td valign="top">"headers-clickable"</td><td valign="top">Write</td><td valign="top">If <tt class="literal">TRUE</tt>, the column headers respond
+to click events. Default is <tt class="literal">FALSE</tt></td></tr><tr valign="top"><td valign="top">"headers-visible"</td><td valign="top">Read-Write</td><td valign="top">If <tt class="literal">TRUE</tt>, show the column header
+buttons. Default is <tt class="literal">TRUE</tt></td></tr><tr valign="top"><td valign="top">"model"</td><td valign="top">Read-Write</td><td valign="top">The model for the tree view. Default is
+<tt class="literal">None</tt></td></tr><tr valign="top"><td valign="top">"reorderable"</td><td valign="top">Read-Write</td><td valign="top">If <tt class="literal">TRUE</tt>, the view is
+reorderable. Default is <tt class="literal">FALSE</tt></td></tr><tr valign="top"><td valign="top">"rules-hint"</td><td valign="top">Read-Write</td><td valign="top">If <tt class="literal">TRUE</tt>, hint to the theme engine to
+draw rows in alternating colors. Default is <tt class="literal">FALSE</tt></td></tr><tr valign="top"><td valign="top">"search-column"</td><td valign="top">Read-Write</td><td valign="top">The model column to search when searching through
+code. Default is -1.</td></tr><tr valign="top"><td valign="top">"vadjustment"</td><td valign="top">Read-Write</td><td valign="top">The vertical <tt class="classname">Adjustment</tt> for the
+widget. New one created by default.</td></tr></tbody></table></div><p>The corresponding methods are:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ enable_search = treeview.get_enable_search()
+ treeview.set_enable_search(<b class="parameter"><tt>enable_search</tt></b>)
+
+ column = treeview.get_expander_column()
+ treeview.set_expander_column(<b class="parameter"><tt>column</tt></b>)
+
+ hadjustment = treeview.get_hadjustment()
+ treeview.set_hadjustment(<b class="parameter"><tt>adjustment</tt></b>)
+
+ treeview.set_headers_clickable(<b class="parameter"><tt>active</tt></b>)
+
+ headers_visible = treeview.get_headers_visible()
+ treeview.set_headers_visible(<b class="parameter"><tt>headers_visible</tt></b>)
+
+ reorderable = treeview.get_reorderable()
+ treeview.set_reorderable(<b class="parameter"><tt>reorderable</tt></b>)
+
+ riles_hint = treeview.get_rules_hint()
+ treeview.set_rules_hint(<b class="parameter"><tt>setting</tt></b>)
+
+ column = treeview.get_search_column()
+ treeview.set_search_column(<b class="parameter"><tt>column</tt></b>)
+
+ vadjustment = treeview.get_vadjustment()
+ treeview.set_vadjustment(<b class="parameter"><tt>adjustment</tt></b>)
+</pre></td></tr></table><p>Most of these are obvious from the description. However, the
+"enable-search" property requires the "search-column" property to be set to
+the number of a valid column in the tree model. Then when the user presses
+<span><b class="keycap">Control</b></span>+<span><b class="keycap">f</b></span> a
+search dialog is popped up that the user can type in. The first matching row
+will be automatically selected as the user types.</p><p>Likewise, the "headers-clickable" property really just sets the
+"clickable" property of the underlying
+<tt class="classname">TreeViewColumn</tt>s. A
+<tt class="classname">TreeViewColumn</tt> will not be sortable unless the tree
+model implements the <tt class="classname">TreeSortable</tt> interface and the
+<tt class="classname">TreeViewColumn</tt>
+<tt class="methodname">set_sort_column_id</tt>() method has been called with a
+valid column number.</p><p>The "reorderable" property enables the user to reorder the
+<tt class="classname">TreeView</tt> model by dragging and dropping the
+<tt class="classname">TreeView</tt> rows displayed.</p><p>The "rules-hint" property should only be set if you have lots of
+columns and think that alternating colors may help the user.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-TreeModelInterface.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-TreeViewWidget.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-CellRenderers.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">14.2. The TreeModel Interface and Data Stores </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 14.4. CellRenderers</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-UIManager.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-UIManager.html
new file mode 100644
index 0000000..eb7859e
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-UIManager.html
@@ -0,0 +1,413 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>16.7. The UIManager</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-NewInPyGTK2.4.html" title="Chapter 16. New Widgets in PyGTK 2.4"><link rel="previous" href="sec-FileChoosers.html" title="16.6. File Selections using FileChooser-based Widgets"><link rel="next" href="ch-UndocumentedWidgets.html" title="Chapter 17. Undocumented Widgets"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">16.7. The UIManager</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-FileChoosers.html">Prev</a> </td><th width="60%" align="center">Chapter 16. New Widgets in PyGTK 2.4</th><td width="20%" align="right"> <a accesskey="n" href="ch-UndocumentedWidgets.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-UIManager"></a>16.7. The UIManager</h2></div></div><div></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-UIManagerOverview"></a>16.7.1. Overview</h3></div></div><div></div></div><p>The <tt class="classname">UIManager</tt> provides a way to create
+menus and toolbars from an XML-like description. The
+<tt class="classname">UIManager</tt> uses <tt class="classname">ActionGroup</tt>
+objects to manage the <tt class="classname">Action</tt> objects providing the
+common substructure for the menu and toolbar items.</p><p>Using the <tt class="classname">UIManager</tt> you can dynamically
+merge and demerge multiple UI descriptions and actions. This allows you to
+modify the menus and toolbars when the mode changes in the application (for
+example, changing from text editing to image editing), or when new plug-in
+features are added or removed from your application.</p><p>A <tt class="classname">UIManager</tt> can be used to create the menus
+and toolbars for an application user interface as follows:</p><div class="itemizedlist"><ul type="disc"><li>Create a <tt class="classname">UIManager</tt> instance</li><li>Extract the <tt class="classname">AccelGroup</tt> from the
+<tt class="classname">UIManager</tt> and add it to the top level
+<tt class="classname">Window</tt></li><li>Create the <tt class="classname">ActionGroup</tt> instances and
+populate them with the appropriate <tt class="classname">Action</tt>
+instances.</li><li>Add the <tt class="classname">ActionGroup</tt> instances to the
+<tt class="classname">UIManager</tt> in the order that the
+<tt class="classname">Action</tt> instances should be found.</li><li>Add the UI XML descriptions to the
+<tt class="classname">UIManager</tt>. Make sure that all
+<tt class="classname">Actions</tt> referenced by the descriptions are available
+in the <tt class="classname">UIManager</tt> <tt class="classname">ActionGroup</tt>
+instances.</li><li>Extract references to the menubar, menu and toolbar widgets
+by name for use in building the user interface.</li><li>Dynamically modify the user interface by adding and
+removing UI descriptions and by adding, rearranging and removing the
+associated <tt class="classname">ActionGroup</tt> instances.</li></ul></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-CreatingUIManager"></a>16.7.2. Creating a UIManager</h3></div></div><div></div></div><p>A <tt class="classname">UIManager</tt> instance is created by the
+constructor:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ uimamager = gtk.UIManager()
+</pre></td></tr></table><p>A new <tt class="classname">UIManager</tt> is created with an
+associated <tt class="classname">AccelGroup</tt> that can be retrieved using the
+method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ accelgroup = uimanager.get_accel_group()
+</pre></td></tr></table><p>The <tt class="classname">AccelGroup</tt> should be added to the top
+level window of the application so that the <tt class="classname">Action</tt>
+accelerators can be used by your users. For example:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ window = gtk.Window()
+ ...
+ uimanager = gtk.UIManager()
+ accelgroup = uimanager.get_accel_group()
+ window.add_accel_group(accelgroup)
+</pre></td></tr></table></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-AddRemoveActionGroups"></a>16.7.3. Adding and Removing ActionGroups</h3></div></div><div></div></div><p>As described in <a href="ch-NewInPyGTK2.4.html#sec-ActionGroups" title="16.1.2. ActionGroups">Section 16.1.2, “ActionGroupsâ€</a>,
+<tt class="classname">ActionGroups</tt> can be populated with
+<tt class="classname">Actions</tt> by using the
+<tt class="methodname">add_actions</tt>(),
+<tt class="methodname">add_toggle_actions</tt>() and
+<tt class="methodname">add_radio_actions</tt>() convenience methods. An
+<tt class="classname">ActionGroup</tt> can be used by a
+<tt class="classname">UIManager</tt> after it has been added to its
+<tt class="classname">ActionGroup</tt> list by using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ uimanager.insert_action_group(<b class="parameter"><tt>action_group</tt></b>, <b class="parameter"><tt>pos</tt></b>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>pos</tt></i> is the index of the position
+where <i class="parameter"><tt>action_group</tt></i> should be inserted. A
+<tt class="classname">UIManager</tt> may contain several
+<tt class="classname">ActionGroups</tt> with duplicate
+<tt class="classname">Action</tt> names. The order of the
+<tt class="classname">ActionGroup</tt> objects is important because the lookup
+of an <tt class="classname">Action</tt> stops when the first
+<tt class="classname">Action</tt> with the given name is encountered. This means
+that actions in earlier <tt class="classname">ActionGroup</tt> objects mask
+those in later <tt class="classname">ActionGroup</tt> objects.</p><p>The actions referenced in a UI XML description must be added to a
+<tt class="classname">UIManager</tt> before the description can be added to the
+<tt class="classname">UIManager</tt>.</p><p>An <tt class="classname">ActionGroup</tt> can be removed from a
+<tt class="classname">UIManager</tt> by using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ uimanager.remove_action_group(<b class="parameter"><tt>action_group</tt></b>)
+</pre></td></tr></table><p>A list of the <tt class="classname">ActionGroup</tt> objects
+associated with a <tt class="classname">UIManager</tt> can be retrieved using
+the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ actiongrouplist = uimanager.get_action_groups()
+</pre></td></tr></table></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-UIDescriptions"></a>16.7.4. UI Descriptions</h3></div></div><div></div></div><p>The UI descriptions accepted by <tt class="classname">UIManager</tt>
+are simple XML definitions with the following elements:</p><table border="0" width="100%" bgcolor="#FFECCE"><col align="left" valign="top" width="0*"><tbody><tr><td><span class="term"><span class="bold"><b>ui</b></span></span></td><td>The root element of a UI description. It can be
+omitted. Can contain <span class="bold"><b>menubar</b></span>, <span class="bold"><b>popup</b></span>, <span class="bold"><b>toolbar</b></span> and
+<span class="bold"><b>accelerator</b></span> elements.</td></tr><tr><td><span class="term"><span class="bold"><b>menubar</b></span></span></td><td>A top level element describing a
+<tt class="classname">MenuBar</tt> structure that can contain <span class="bold"><b>MenuItem</b></span>, <span class="bold"><b>separator</b></span>,
+<span class="bold"><b>placeholder</b></span> and <span class="bold"><b>menu</b></span> elements. It has an optional
+<span class="emphasis"><em>name</em></span> attribute. If <span class="emphasis"><em>name</em></span> is not
+specified, "menubar" is used as the name.</td></tr><tr><td><span class="term"><span class="bold"><b>popup</b></span></span></td><td>A top level element describing a popup
+<tt class="classname">Menu</tt> structure that can contain <span class="bold"><b>menuitem</b></span>, <span class="bold"><b>separator</b></span>,
+<span class="bold"><b>placeholder</b></span>, and <span class="bold"><b>menu</b></span> elements. It has an optional
+<span class="emphasis"><em>name</em></span> attribute. If <span class="emphasis"><em>name</em></span> is not
+specified, "popup" is used as the name.</td></tr><tr><td><span class="term"><span class="bold"><b>toolbar</b></span></span></td><td>A top level element describing a
+<tt class="classname">Toolbar</tt> structure that can contain <span class="bold"><b>toolitem</b></span>, <span class="bold"><b>separator</b></span>
+and <span class="bold"><b>placeholder</b></span> elements. It has an
+optional <span class="emphasis"><em>name</em></span> attribute. If <span class="emphasis"><em>name</em></span>
+is not specified, "toolbar" is used as the name.</td></tr><tr><td><span class="term"><span class="bold"><b>placeholder</b></span></span></td><td>An element identifying a position in a <span class="bold"><b>menubar</b></span>, <span class="bold"><b>toolbar</b></span>,
+<span class="bold"><b>popup</b></span> or <span class="bold"><b>menu</b></span>. A placeholder can contain <span class="bold"><b>menuitem</b></span>, <span class="bold"><b>separator</b></span>,
+<span class="bold"><b>placeholder</b></span>, and <span class="bold"><b>menu</b></span> elements. <span class="bold"><b>Placeholder</b></span> elements are used when merging UI
+descriptions to allow, for example, a menu to be built up from UI
+descriptions using common <span class="bold"><b>placeholder</b></span>
+names. It has an optional <span class="emphasis"><em>name</em></span> attribute. If
+<span class="emphasis"><em>name</em></span> is not specified, "placeholder" is used as the
+name.</td></tr><tr><td><span class="term"><span class="bold"><b>menu</b></span></span></td><td>An element describing a <tt class="classname">Menu</tt>
+structure that can contain <span class="bold"><b>menuitem</b></span>,
+<span class="bold"><b>separator</b></span>, <span class="bold"><b>placeholder</b></span>, and <span class="bold"><b>menu</b></span> elements. A <span class="bold"><b>menu</b></span> element has a required attribute
+<span class="emphasis"><em>action</em></span> that names an <tt class="classname">Action</tt>
+object to be used to create the <tt class="classname">Menu</tt>. It also has
+optional <span class="emphasis"><em>name</em></span> and <span class="emphasis"><em>position</em></span>
+attributes. If <span class="emphasis"><em>name</em></span> is not specified, the
+<span class="emphasis"><em>action</em></span> name is used as the name. The
+<span class="emphasis"><em>position</em></span> attribute can have either the value "top" or
+"bottom" with "bottom" the default if <span class="emphasis"><em>position</em></span> is not
+specified.</td></tr><tr><td><span class="term"><span class="bold"><b>menuitem</b></span></span></td><td>An element describing a
+<tt class="classname">MenuItem</tt>. A <span class="bold"><b>menuitem</b></span>
+element has a required attribute <span class="emphasis"><em>action</em></span> that names an
+<tt class="classname">Action</tt> object to be used to create the
+<tt class="classname">MenuItem</tt>. It also has optional
+<span class="emphasis"><em>name</em></span> and <span class="emphasis"><em>position</em></span> attributes. If
+<span class="emphasis"><em>name</em></span> is not specified, the <span class="emphasis"><em>action</em></span>
+name is used as the name. The <span class="emphasis"><em>position</em></span> attribute can
+have either the value "top" or "bottom" with "bottom" the default if
+<span class="emphasis"><em>position</em></span> is not specified.</td></tr><tr><td><span class="term"><span class="bold"><b>toolitem</b></span></span></td><td>An element describing a toolbar
+<tt class="classname">ToolItem</tt>. A <span class="bold"><b>toolitem</b></span>
+element has a required attribute <span class="emphasis"><em>action</em></span> that names an
+<tt class="classname">Action</tt> object to be used to create the
+<tt class="classname">Toolbar</tt>. It also has optional
+<span class="emphasis"><em>name</em></span> and <span class="emphasis"><em>position</em></span> attributes. If
+<span class="emphasis"><em>name</em></span> is not specified, the <span class="emphasis"><em>action</em></span>
+name is used as the name. The <span class="emphasis"><em>position</em></span> attribute can
+have either the value "top" or "bottom" with "bottom" the default if
+<span class="emphasis"><em>position</em></span> is not specified.</td></tr><tr><td><span class="term"><span class="bold"><b>separator</b></span></span></td><td>An element describing a
+<tt class="classname">SeparatorMenuItem</tt> or a
+<tt class="classname">SeparatorToolItem</tt> as appropriate.</td></tr><tr><td><span class="term"><span class="bold"><b>accelerator</b></span></span></td><td>An element describing a keyboard accelerator. An
+<span class="bold"><b>accelerator</b></span> element has a required
+attribute <span class="emphasis"><em>action</em></span> that names an
+<tt class="classname">Action</tt> object that defines the accelerator key
+combination and is activated by the accelerator. It also has an optional
+<span class="emphasis"><em>name</em></span> attribute. If <span class="emphasis"><em>name</em></span> is not
+specified, the <span class="emphasis"><em>action</em></span> name is used as the
+name.</td></tr></tbody></table><p>For example, a UI description that could be used to create an
+interface similar that in <a href="ch-NewInPyGTK2.4.html#actiongroupfig" title="Figure 16.4. ActionGroup Example">Figure 16.4, “ActionGroup Exampleâ€</a> is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ &lt;ui&gt;
+ &lt;menubar name="MenuBar"&gt;
+ &lt;menu action="File"&gt;
+ &lt;menuitem action="Quit"/&gt;
+ &lt;/menu&gt;
+ &lt;menu action="Sound"&gt;
+ &lt;menuitem action="Mute"/&gt;
+ &lt;/menu&gt;
+ &lt;menu action="RadioBand"&gt;
+ &lt;menuitem action="AM"/&gt;
+ &lt;menuitem action="FM"/&gt;
+ &lt;menuitem action="SSB"/&gt;
+ &lt;/menu&gt;
+ &lt;/menubar&gt;
+ &lt;toolbar name="Toolbar"&gt;
+ &lt;toolitem action="Quit"/&gt;
+ &lt;separator/&gt;
+ &lt;toolitem action="Mute"/&gt;
+ &lt;separator name="sep1"/&gt;
+ &lt;placeholder name="RadioBandItems"&gt;
+ &lt;toolitem action="AM"/&gt;
+ &lt;toolitem action="FM"/&gt;
+ &lt;toolitem action="SSB"/&gt;
+ &lt;/placeholder&gt;
+ &lt;/toolbar&gt;
+ &lt;/ui&gt;
+</pre></td></tr></table><p>Note that this description just uses the <span class="bold"><b>action</b></span> attribute names for the names of most elements
+rather than specifying <span class="emphasis"><em>name</em></span> attributes. Also I would
+recommend not specifying the <span class="bold"><b>ui</b></span> element as
+it appears to be unnecessary.</p><p>The widget hierarchy created using a UI description is very
+similar to the XML element hierarchy except that <span class="bold"><b>placeholder</b></span> elements are merged into their
+parents.</p><p>A widget in the hierarchy created by a UI description can be
+accessed using its path which is composed of the name of the widget element
+and its ancestor elements joined by slash ("/") characters. For example
+using the above description the following are valid widget paths:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ /MenuBar
+ /MenuBar/File/Quit
+ /MenuBar/RadioBand/SSB
+ /Toolbar/Mute
+ /Toolbar/RadioBandItems/FM
+</pre></td></tr></table><p>Note that the <span class="bold"><b>placeholder</b></span> name
+must be included in the path. Usually you just access the top level widgets
+(for example, "/MenuBar" and "/Toolbar") but you may need to access a lower
+level widget to, for example, change a property.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-AddRemoveUIDescriptions"></a>16.7.5. Adding and Removing UI Descriptions</h3></div></div><div></div></div><p>Once a <tt class="classname">UIManager</tt> is set up with an
+<tt class="classname">ActionGroup</tt> a UI description can be added and merged
+with the existing UI by using one of the following methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ merge_id = uimanager.add_ui_from_string(<b class="parameter"><tt>buffer</tt></b>)
+
+ merge_id = uimanager.add_ui_from_file(<b class="parameter"><tt>filename</tt></b>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>buffer</tt></i> is a string containing a UI
+description and <i class="parameter"><tt>filename</tt></i> is the file containing a UI
+description. Both methods return a <i class="parameter"><tt>merge_id</tt></i> which is
+a unique integer value. If the method fails, the <tt class="literal">GError</tt>
+exception is raised. The <i class="parameter"><tt>merge_id</tt></i> can be used to
+remove the UI description from the <tt class="classname">UIManager</tt> by using
+the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ uimanager.remove_ui(<b class="parameter"><tt>merge_id</tt></b>)
+</pre></td></tr></table><p>The same methods can be used more than once to add additional UI
+descriptions that will be merged to provide a combined XML UI
+description. Merged UIs will be discussed in more detail in <a href="sec-UIManager.html#sec-MergingUIDescriptions" title="16.7.8. Merging UI Descriptions">Section 16.7.8, “Merging UI Descriptionsâ€</a> section.</p><p>A single UI element can be added to the current UI description by
+using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ uimanager.add_ui(<b class="parameter"><tt>merge_id</tt></b>, <b class="parameter"><tt>path</tt></b>, <b class="parameter"><tt>name</tt></b>, <b class="parameter"><tt>action</tt></b>, <b class="parameter"><tt>type</tt></b>, <b class="parameter"><tt>top</tt></b>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>merge_id</tt></i> is a unique integer value,
+<i class="parameter"><tt>path</tt></i> is the path where the new element should be
+added, <i class="parameter"><tt>action</tt></i> is the name of an
+<tt class="classname">Action</tt> or <tt class="literal">None</tt> to add a <span class="bold"><b>separator</b></span>, <i class="parameter"><tt>type</tt></i> is the element
+type to be added and <i class="parameter"><tt>top</tt></i> is a boolean value. If
+<i class="parameter"><tt>top</tt></i> is <tt class="literal">TRUE</tt> the element will be
+added before its siblings, otherwise it is added after.</p><p><i class="parameter"><tt>merge_id</tt></i> should be obtained from the
+method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ merge_id = uimanager.new_merge_id()
+</pre></td></tr></table><p>The integer values returned from the
+<tt class="methodname">new_merge_id</tt>() method are monotonically
+increasing.</p><p><i class="parameter"><tt>path</tt></i> is a string composed of the name of
+the element and the names of its ancestor elements separated by slash ("/")
+characters but not including the optional root node "/ui". For example,
+"/MenuBar/RadioBand" is the path of the <span class="bold"><b>menu</b></span> element named "RadioBand" in the following UI
+description:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ &lt;menubar name="MenuBar"&gt;
+ &lt;menu action="RadioBand"&gt;
+ &lt;/menu&gt;
+ &lt;/menubar&gt;
+</pre></td></tr></table><p>The value of <i class="parameter"><tt>type</tt></i> must be one of:</p><table border="0" width="100%" bgcolor="#FFECCE"><col align="left" valign="top" width="0*"><tbody><tr><td><span class="term"><tt class="literal">gtk.UI_MANAGER_AUTO</tt></span></td><td>The type of the UI element (menuitem, toolitem or
+separator) is set according to the context.</td></tr><tr><td><span class="term"><tt class="literal">gtk.UI_MANAGER_MENUBAR</tt></span></td><td>A menubar. </td></tr><tr><td><span class="term"><tt class="literal">gtk.UI_MANAGER_MENU</tt></span></td><td>A menu.</td></tr><tr><td><span class="term"><tt class="literal">gtk.UI_MANAGER_TOOLBAR</tt></span></td><td>A toolbar.</td></tr><tr><td><span class="term"><tt class="literal">gtk.UI_MANAGER_PLACEHOLDER</tt></span></td><td>A placeholder.</td></tr><tr><td><span class="term"><tt class="literal">gtk.UI_MANAGER_POPUP</tt></span></td><td>A popup menu.</td></tr><tr><td><span class="term"><tt class="literal">gtk.UI_MANAGER_MENUITEM</tt></span></td><td>A menuitem.</td></tr><tr><td><span class="term"><tt class="literal">gtk.UI_MANAGER_TOOLITEM</tt></span></td><td>A toolitem.</td></tr><tr><td><span class="term"><tt class="literal">gtk.UI_MANAGER_SEPARATOR</tt></span></td><td>A separator.</td></tr><tr><td><span class="term"><tt class="literal">gtk.UI_MANAGER_ACCELERATOR</tt></span></td><td>An accelerator.</td></tr></tbody></table><p><tt class="methodname">add_ui</tt>() fails silently if the element is
+not added. Using <tt class="methodname">add_ui</tt>() is so low level that you
+should always try to use the convenience methods
+<tt class="methodname">add_ui_from_string</tt>() and
+<tt class="methodname">add_ui_from_file</tt>() instead.</p><p>Adding a UI description or element causes the widget hierarchy to
+be updated in an idle function. You can make sure that the widget hierarchy
+has been updated before accessing it by calling the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ uimanager.ensure_update()
+</pre></td></tr></table></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-AccessingUIWidgets"></a>16.7.6. Accessing UI Widgets</h3></div></div><div></div></div><p>You access a widget in the UI widget hierarchy by using the
+method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ widget = uimanager.get_widget(<b class="parameter"><tt>path</tt></b>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>path</tt></i> is a string containing the name
+of the widget element and it's ancestors as described in <a href="sec-UIManager.html#sec-UIDescriptions" title="16.7.4. UI Descriptions">Section 16.7.4, “UI Descriptionsâ€</a>.</p><p>For example, given the following UI description:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ &lt;menubar name="MenuBar"&gt;
+ &lt;menu action="File"&gt;
+ &lt;menuitem action="Quit"/&gt;
+ &lt;/menu&gt;
+ &lt;menu action="Sound"&gt;
+ &lt;menuitem action="Mute"/&gt;
+ &lt;/menu&gt;
+ &lt;menu action="RadioBand"&gt;
+ &lt;menuitem action="AM"/&gt;
+ &lt;menuitem action="FM"/&gt;
+ &lt;menuitem action="SSB"/&gt;
+ &lt;/menu&gt;
+ &lt;/menubar&gt;
+ &lt;toolbar name="Toolbar"&gt;
+ &lt;toolitem action="Quit"/&gt;
+ &lt;separator/&gt;
+ &lt;toolitem action="Mute"/&gt;
+ &lt;separator name="sep1"/&gt;
+ &lt;placeholder name="RadioBandItems"&gt;
+ &lt;toolitem action="AM"/&gt;
+ &lt;toolitem action="FM"/&gt;
+ &lt;toolitem action="SSB"/&gt;
+ &lt;/placeholder&gt;
+ &lt;/toolbar&gt;
+</pre></td></tr></table><p>added to the <tt class="classname">UIManager</tt>
+<i class="parameter"><tt>uimanager</tt></i>, you can access the
+<tt class="classname">MenuBar</tt> and <tt class="classname">Toolbar</tt> for use in
+an application <tt class="classname">Window</tt> by using the following code
+fragment:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ window = gtk.Window()
+ vbox = gtk.VBox()
+ menubar = uimanager.get_widget('/MenuBar')
+ toolbar = uimanager.get_widget('/Toolbar')
+ vbox.pack_start(meunbar, False)
+ vbox.pack_start(toolbar, False)
+</pre></td></tr></table><p>Likewise the lower level widgets in the hierarchy are accessed by
+using their paths. For example the <tt class="classname">RadioToolButton</tt>
+named "SSB" is accessed as follows:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ ssb = uimanager.get_widget('/Toolbar/RadioBandItems/SSB')
+</pre></td></tr></table><p>As a convenience all the top level widgets of a type can be
+retrieved using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ toplevels = uimanager.get_toplevels(<i class="parameter"><tt>type</tt></i>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>type</tt></i> specifies the type of widgets to
+return using a combination of the flags:
+<tt class="literal">gtk.UI_MANAGER_MENUBAR</tt>,
+<tt class="literal">gtk.UI_MANAGER_TOOLBAR</tt> and
+<tt class="literal">gtk.UI_MANAGER_POPUP</tt>. You can use the
+<tt class="methodname">gtk.Widget.get_name</tt>() method to determine which top
+level widget you have.</p><p>You can retrieve the <tt class="classname">Action</tt> that is used by
+the proxy widget associated with a UI element by using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ action = uimanager_get_action(<i class="parameter"><tt>path</tt></i>)
+</pre></td></tr></table><p>where <i class="parameter"><tt>path</tt></i> is a string containing the path
+to a UI element in <i class="parameter"><tt>uimanager</tt></i>. If the element has no
+associated <tt class="classname">Action</tt>, <tt class="literal">None</tt> is
+returned.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-SimpleUIManagerExample"></a>16.7.7. A Simple UIManager Example</h3></div></div><div></div></div><p>A simple example program illustrating the use of
+<tt class="classname">UIManager</tt> is <a href="examples/uimanager.py" target="_top">uimanager.py</a>. <a href="sec-UIManager.html#uimanagerfig" title="Figure 16.13. Simple UIManager Example">Figure 16.13, “Simple UIManager Exampleâ€</a> illustrates the program in operation.</p><div class="figure"><a name="uimanagerfig"></a><p class="title"><b>Figure 16.13. Simple UIManager Example</b></p><div class="mediaobject" align="center"><img src="figures/uimanager.png" align="middle" alt="Simple UIManager Example"></div></div><p>The <a href="examples/uimanager.py" target="_top">uimanager.py</a>
+example program uses the XML description of <a href="sec-UIManager.html#sec-AccessingUIWidgets" title="16.7.6. Accessing UI Widgets">Section 16.7.6, “Accessing UI Widgetsâ€</a>. The text of the two labels are
+changed in response to the activation of the "Mute"
+<tt class="classname">ToggleAction</tt> and "AM", "FM" and "SSB"
+<tt class="classname">RadioAction</tt>s. All the actions are contained in a
+single <tt class="classname">ActionGroup</tt> allowing the sensitivity and
+visibility of all the action proxy widgets to be toggled on and off by using
+the "Sensitive" and "Visible" toggle buttons. The use of the <span class="bold"><b>placeholder</b></span> element will be described in <a href="sec-UIManager.html#sec-MergingUIDescriptions" title="16.7.8. Merging UI Descriptions">Section 16.7.8, “Merging UI Descriptionsâ€</a>.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-MergingUIDescriptions"></a>16.7.8. Merging UI Descriptions</h3></div></div><div></div></div><p>The merging of UI descriptions is done based on the name of the
+XML elements. As noted above the individual elements in the hierarchy can be
+accessed using a pathname consisting of the element name and the names of
+its ancestors. For example, using the UI description in <a href="sec-UIManager.html#sec-UIDescriptions" title="16.7.4. UI Descriptions">Section 16.7.4, “UI Descriptionsâ€</a> the "AM" <span class="bold"><b>toolitem</b></span> element has the pathname
+"/Toolbar/RadioBandItems/AM" while the "FM" <span class="bold"><b>menuitem</b></span> element has the pathname
+"/MenuBar/RadioBand/FM".</p><p>If a UI description is merged with that UI description the
+elements are added as siblings to the existing elements. For example, if
+the UI description:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ &lt;menubar name="MenuBar"&gt;
+ &lt;menu action="File"&gt;
+ &lt;menuitem action="Save" position="top"/&gt;
+ &lt;menuitem action="New" position="top"/&gt;
+ &lt;/menu&gt;
+ &lt;menu action="Sound"&gt;
+ &lt;menuitem action="Loudness"/&gt;
+ &lt;/menu&gt;
+ &lt;menu action="RadioBand"&gt;
+ &lt;menuitem action="CB"/&gt;
+ &lt;menuitem action="Shortwave"/&gt;
+ &lt;/menu&gt;
+ &lt;/menubar&gt;
+ &lt;toolbar name="Toolbar"&gt;
+ &lt;toolitem action="Save" position="top"/&gt;
+ &lt;toolitem action="New" position="top"/&gt;
+ &lt;separator/&gt;
+ &lt;toolitem action="Loudness"/&gt;
+ &lt;separator/&gt;
+ &lt;placeholder name="RadioBandItems"&gt;
+ &lt;toolitem action="CB"/&gt;
+ &lt;toolitem action="Shortwave"/&gt;
+ &lt;/placeholder&gt;
+ &lt;/toolbar&gt;
+</pre></td></tr></table><p>is added to our example UI description:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ &lt;menubar name="MenuBar"&gt;
+ &lt;menu action="File"&gt;
+ &lt;menuitem action="Quit"/&gt;
+ &lt;/menu&gt;
+ &lt;menu action="Sound"&gt;
+ &lt;menuitem action="Mute"/&gt;
+ &lt;/menu&gt;
+ &lt;menu action="RadioBand"&gt;
+ &lt;menuitem action="AM"/&gt;
+ &lt;menuitem action="FM"/&gt;
+ &lt;menuitem action="SSB"/&gt;
+ &lt;/menu&gt;
+ &lt;/menubar&gt;
+ &lt;toolbar name="Toolbar"&gt;
+ &lt;toolitem action="Quit"/&gt;
+ &lt;separator/&gt;
+ &lt;toolitem action="Mute"/&gt;
+ &lt;separator name="sep1"/&gt;
+ &lt;placeholder name="RadioBandItems"&gt;
+ &lt;toolitem action="AM"/&gt;
+ &lt;toolitem action="FM"/&gt;
+ &lt;toolitem action="SSB"/&gt;
+ &lt;/placeholder&gt;
+ &lt;/toolbar&gt;
+</pre></td></tr></table><p>the following merged UI description will be created:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ &lt;menubar name="MenuBar"&gt;
+ &lt;menu name="File" action="File"&gt;
+ &lt;menuitem name="New" action="New"/&gt;
+ &lt;menuitem name="Save" action="Save"/&gt;
+ &lt;menuitem name="Quit" action="Quit"/&gt;
+ &lt;/menu&gt;
+ &lt;menu name="Sound" action="Sound"&gt;
+ &lt;menuitem name="Mute" action="Mute"/&gt;
+ &lt;menuitem name="Loudness" action="Loudness"/&gt;
+ &lt;/menu&gt;
+ &lt;menu name="RadioBand" action="RadioBand"&gt;
+ &lt;menuitem name="AM" action="AM"/&gt;
+ &lt;menuitem name="FM" action="FM"/&gt;
+ &lt;menuitem name="SSB" action="SSB"/&gt;
+ &lt;menuitem name="CB" action="CB"/&gt;
+ &lt;menuitem name="Shortwave" action="Shortwave"/&gt;
+ &lt;/menu&gt;
+ &lt;/menubar&gt;
+ &lt;toolbar name="Toolbar"&gt;
+ &lt;toolitem name="New" action="New"/&gt;
+ &lt;toolitem name="Save" action="Save"/&gt;
+ &lt;toolitem name="Quit" action="Quit"/&gt;
+ &lt;separator/&gt;
+ &lt;toolitem name="Mute" action="Mute"/&gt;
+ &lt;separator name="sep1"/&gt;
+ &lt;placeholder name="RadioBandItems"&gt;
+ &lt;toolitem name="AM" action="AM"/&gt;
+ &lt;toolitem name="FM" action="FM"/&gt;
+ &lt;toolitem name="SSB" action="SSB"/&gt;
+ &lt;toolitem name="CB" action="CB"/&gt;
+ &lt;toolitem name="Shortwave" action="Shortwave"/&gt;
+ &lt;/placeholder&gt;
+ &lt;separator/&gt;
+ &lt;toolitem name="Loudness" action="Loudness"/&gt;
+ &lt;separator/&gt;
+ &lt;/toolbar&gt;
+</pre></td></tr></table><p>Examining the merged XML you can see that the "New" and "Save"
+<span class="bold"><b>menuitem</b></span> elements have been merged before
+the "Quit" element as a result of the "position" attribute being set to
+"top" which means the element should be prepended. Likewise, the "New" and
+"Save" <span class="bold"><b>toolitem</b></span> elements have been
+prepended to "Toolbar". Note that the "New" and "Save" elements are reversed
+by the merging process.</p><p>The "Loudness" <span class="bold"><b>toolitem</b></span> element
+is appended to the "Toolbar" elements and appears last in the merged UI
+description even though it's not last in its UI description. The
+"RadioBandItems" <span class="bold"><b>placeholder</b></span> element in
+both UI descriptions combines the "CB" and "Shortwave" <span class="bold"><b>toolitem</b></span> elements with the "AM", "FM", and "SSB"
+elements. If the "RadioBandItems" <span class="bold"><b>placeholder</b></span> element was not used the "CB" and
+"Shortwave" elements would have been placed after the "Loudness"
+element.</p><p>A representation of the UI description used by a
+<tt class="classname">UIManager</tt> can be retrieved using the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ uidesc = uimanager.get_ui()
+</pre></td></tr></table><p>The <a href="examples/uimerge.py" target="_top">uimerge.py</a> example
+program demonstrates the merging of the above UI descriptions. <a href="sec-UIManager.html#uimergefig" title="Figure 16.14. UIMerge Example">Figure 16.14, “UIMerge Exampleâ€</a> illustrates the unmerged and merged UIs:</p><div class="figure"><a name="uimergefig"></a><p class="title"><b>Figure 16.14. UIMerge Example</b></p><div class="mediaobject" align="center"><img src="figures/uimerge.png" align="middle" alt="UIMerge Example"></div></div><p>The example program uses three <tt class="classname">ActionGroup</tt>
+objects:</p><div class="itemizedlist"><ul type="disc"><li><tt class="classname">Action</tt> objects for the "File",
+"Sound" and "Radio Band" menus</li><li><tt class="classname">Action</tt> objects for the "Quit",
+"Mute", "AM", "FM", "SSB" and "Radio Band" menus</li><li><tt class="classname">Action</tt> objects for the "Loudness",
+"CB" and "Shortwave" elements</li></ul></div><p>The "Sensitive" and Visible" <tt class="classname">ToggleButton</tt>
+widgets control the sensitivity and visibility of only the second
+<tt class="classname">ActionGroup</tt>.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="sec-UIManagerSignals"></a>16.7.9. UIManager Signals</h3></div></div><div></div></div><p>The <tt class="classname">UIManager</tt> has a couple of interesting
+signals that your application can connect to. The "actions-changed" signal
+is emitted when an <tt class="classname">ActionGroup</tt> is added or
+removed from a <tt class="classname">UIManager</tt>. The signature of the
+callback is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def callback(<i class="parameter"><tt>uimanager</tt></i>, ...)
+</pre></td></tr></table><p>The "add-widget" signal is emitted when a proxy
+<tt class="classname">MenuBar</tt> or <tt class="classname">Toolbar</tt> widget is
+created. The callback signature is:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ def callback(<i class="parameter"><tt>uimanager</tt></i>, <i class="parameter"><tt>widget</tt></i>, ...)
+</pre></td></tr></table><p>where <i class="parameter"><tt>widget</tt></i> is the newly created
+widget.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-FileChoosers.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-NewInPyGTK2.4.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch-UndocumentedWidgets.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">16.6. File Selections using FileChooser-based Widgets </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 17. Undocumented Widgets</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-UpgradedHelloWorld.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-UpgradedHelloWorld.html
new file mode 100644
index 0000000..f8a6d1a
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-UpgradedHelloWorld.html
@@ -0,0 +1,101 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>3.2. An Upgraded Hello World</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-MovingOn.html" title="Chapter 3. Moving On"><link rel="previous" href="ch-MovingOn.html" title="Chapter 3. Moving On"><link rel="next" href="ch-PackingWidgets.html" title="Chapter 4. Packing Widgets"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">3.2. An Upgraded Hello World</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch-MovingOn.html">Prev</a> </td><th width="60%" align="center">Chapter 3. Moving On</th><td width="20%" align="right"> <a accesskey="n" href="ch-PackingWidgets.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-UpgradedHelloWorld"></a>3.2. An Upgraded Hello World</h2></div></div><div></div></div><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ 1 #!/usr/bin/env python
+ 2
+ 3 # example helloworld2.py
+ 4
+ 5 import pygtk
+ 6 pygtk.require('2.0')
+ 7 import gtk
+ 8
+ 9 class HelloWorld2:
+ 10
+ 11 # Our new improved callback. The data passed to this method
+ 12 # is printed to stdout.
+ 13 def callback(self, widget, data):
+ 14 print "Hello again - %s was pressed" % data
+ 15
+ 16 # another callback
+ 17 def delete_event(self, widget, event, data=None):
+ 18 gtk.main_quit()
+ 19 return False
+ 20
+ 21 def __init__(self):
+ 22 # Create a new window
+ 23 self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ 24
+ 25 # This is a new call, which just sets the title of our
+ 26 # new window to "Hello Buttons!"
+ 27 self.window.set_title("Hello Buttons!")
+ 28
+ 29 # Here we just set a handler for delete_event that immediately
+ 30 # exits GTK.
+ 31 self.window.connect("delete_event", self.delete_event)
+ 32
+ 33 # Sets the border width of the window.
+ 34 self.window.set_border_width(10)
+ 35
+ 36 # We create a box to pack widgets into. This is described in detail
+ 37 # in the "packing" section. The box is not really visible, it
+ 38 # is just used as a tool to arrange widgets.
+ 39 self.box1 = gtk.HBox(False, 0)
+ 40
+ 41 # Put the box into the main window.
+ 42 self.window.add(self.box1)
+ 43
+ 44 # Creates a new button with the label "Button 1".
+ 45 self.button1 = gtk.Button("Button 1")
+ 46
+ 47 # Now when the button is clicked, we call the "callback" method
+ 48 # with a pointer to "button 1" as its argument
+ 49 self.button1.connect("clicked", self.callback, "button 1")
+ 50
+ 51 # Instead of add(), we pack this button into the invisible
+ 52 # box, which has been packed into the window.
+ 53 self.box1.pack_start(self.button1, True, True, 0)
+ 54
+ 55 # Always remember this step, this tells GTK that our preparation for
+ 56 # this button is complete, and it can now be displayed.
+ 57 self.button1.show()
+ 58
+ 59 # Do these same steps again to create a second button
+ 60 self.button2 = gtk.Button("Button 2")
+ 61
+ 62 # Call the same callback method with a different argument,
+ 63 # passing a pointer to "button 2" instead.
+ 64 self.button2.connect("clicked", self.callback, "button 2")
+ 65
+ 66 self.box1.pack_start(self.button2, True, True, 0)
+ 67
+ 68 # The order in which we show the buttons is not really important, but I
+ 69 # recommend showing the window last, so it all pops up at once.
+ 70 self.button2.show()
+ 71 self.box1.show()
+ 72 self.window.show()
+ 73
+ 74 def main():
+ 75 gtk.main()
+ 76
+ 77 if __name__ == "__main__":
+ 78 hello = HelloWorld2()
+ 79 main()
+</pre></td></tr></table><p>Running <a href="examples/helloworld2.py" target="_top"><span><b class="command">helloworld2.py</b></span></a>
+produces the window illustrated in <a href="sec-UpgradedHelloWorld.html#helloworld2fig" title="Figure 3.1. Upgraded Hello World Example">Figure 3.1, “Upgraded Hello World Exampleâ€</a>.</p><div class="figure"><a name="helloworld2fig"></a><p class="title"><b>Figure 3.1. Upgraded Hello World Example</b></p><div class="mediaobject" align="center"><img src="figures/helloworld2.png" align="middle" alt="Upgraded Hello World Example"></div></div><p>You'll notice this time there is no easy way to exit the
+program, you have to use your window manager or command line to kill it. A
+good exercise for the reader would be to insert a third "Quit" button that
+will exit the program. You may also wish to play with the options to
+<tt class="methodname">pack_start</tt>() while reading the next section. Try
+resizing the window, and observe the behavior.</p><p>A short commentary on the code differences from the first
+helloworld program is in order.</p><p>As noted above there is no "destroy" event handler in the
+upgraded helloworld.</p><p>Lines 13-14 define a callback method which is similar to the
+<tt class="methodname">hello</tt>() callback in the first helloworld. The
+difference is that the callback prints a message including data passed
+in.</p><p>Line 27 sets a title string to be used on the titlebar of the
+window (see <a href="sec-UpgradedHelloWorld.html#helloworld2fig" title="Figure 3.1. Upgraded Hello World Example">Figure 3.1, “Upgraded Hello World Exampleâ€</a>).</p><p>Line 39 creates a horizontal box
+(<tt class="classname">gtk.HBox</tt>) to hold the two buttons that are created
+in lines 45 and 60. Line 42 adds the horizontal box to the window
+container.</p><p>Lines 49 and 64 connect the <tt class="methodname">callback</tt>()
+method to the "clicked" signal of the buttons. Each button sets up a
+different string to be passed to the <tt class="methodname">callback</tt>()
+method when invoked.</p><p>Lines 53 and 66 pack the buttons into the horizontal box. Lines
+57 and 70 ask GTK to display the buttons.</p><p>Lines 71-72 ask GTK to display the box and the window
+respectively.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch-MovingOn.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-MovingOn.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch-PackingWidgets.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 3. Moving On </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 4. Packing Widgets</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-UsingAdjustmentsTheEasyWay.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-UsingAdjustmentsTheEasyWay.html
new file mode 100644
index 0000000..0aa534b
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-UsingAdjustmentsTheEasyWay.html
@@ -0,0 +1,29 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>7.2. Using Adjustments the Easy Way</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-Adjustments.html" title="Chapter 7. Adjustments"><link rel="previous" href="ch-Adjustments.html" title="Chapter 7. Adjustments"><link rel="next" href="sec-AdjustmentInternals.html" title="7.3. Adjustment Internals"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">7.2. Using Adjustments the Easy Way</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch-Adjustments.html">Prev</a> </td><th width="60%" align="center">Chapter 7. Adjustments</th><td width="20%" align="right"> <a accesskey="n" href="sec-AdjustmentInternals.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-UsingAdjustmentsTheEasyWay"></a>7.2. Using Adjustments the Easy Way</h2></div></div><div></div></div><p>The adjustable widgets can be roughly divided into those which
+use and require specific units for these values, and those which treat them
+as arbitrary numbers. The group which treats the values as arbitrary numbers
+includes the range widgets (scrollbars and scales, the progress bar widget,
+and the spin button widget). These widgets are all the widgets which are
+typically "adjusted" directly by the user with the mouse or keyboard. They
+will treat the lower and upper values of an adjustment as a range within
+which the user can manipulate the adjustment's value. By default, they will
+only modify the value of an adjustment.</p><p>The other group includes the text widget, the viewport widget,
+the compound list widget, and the scrolled window widget. All of these
+widgets use pixel values for their adjustments. These are also all widgets
+which are typically "adjusted" indirectly using scrollbars. While all
+widgets which use adjustments can either create their own adjustments or use
+ones you supply, you'll generally want to let this particular category of
+widgets create its own adjustments. Usually, they will eventually override
+all the values except the value itself in whatever adjustments you give
+them, but the results are, in general, undefined (meaning, you'll have to
+read the source code to find out, and it may be different from widget to
+widget).</p><p>Now, you're probably thinking, since text widgets and viewports
+insist on setting everything except the value of their adjustments, while
+scrollbars will only touch the adjustment's value, if you share an
+adjustment object between a scrollbar and a text widget, manipulating the
+scrollbar will automagically adjust the text widget? Of course it will! Just
+like this:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ # creates its own adjustments
+ viewport = gtk.Viewport()
+ # uses the newly-created adjustment for the scrollbar as well
+ vscrollbar = gtk.VScrollbar(viewport.get_vadjustment())
+</pre></td></tr></table></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch-Adjustments.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-Adjustments.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-AdjustmentInternals.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 7. Adjustments </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 7.3. Adjustment Internals</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-UsingItemFactory.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-UsingItemFactory.html
new file mode 100644
index 0000000..cd4a24a
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-UsingItemFactory.html
@@ -0,0 +1,2 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>11.3. Using ItemFactory</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-MenuWidget.html" title="Chapter 11. Menu Widget"><link rel="previous" href="sec-ManualMenuExample.html" title="11.2. Manual Menu Example"><link rel="next" href="sec-ItemFactoryExample.html" title="11.4. Item Factory Example"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">11.3. Using ItemFactory</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-ManualMenuExample.html">Prev</a> </td><th width="60%" align="center">Chapter 11. Menu Widget</th><td width="20%" align="right"> <a accesskey="n" href="sec-ItemFactoryExample.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-UsingItemFactory"></a>11.3. Using ItemFactory</h2></div></div><div></div></div><p>Now that we've shown you the hard way, here's how you do it
+using the <tt class="classname">gtk.ItemFactory</tt> calls.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-ManualMenuExample.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-MenuWidget.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-ItemFactoryExample.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">11.2. Manual Menu Example </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 11.4. Item Factory Example</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-Viewports.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-Viewports.html
new file mode 100644
index 0000000..43d8082
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-Viewports.html
@@ -0,0 +1,33 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>10.8. Viewports</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-ContainerWidgets.html" title="Chapter 10. Container Widgets"><link rel="previous" href="sec-PanedWindowWidgets.html" title="10.7. Paned Window Widgets"><link rel="next" href="sec-ScrolledWindows.html" title="10.9. Scrolled Windows"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">10.8. Viewports</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-PanedWindowWidgets.html">Prev</a> </td><th width="60%" align="center">Chapter 10. Container Widgets</th><td width="20%" align="right"> <a accesskey="n" href="sec-ScrolledWindows.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-Viewports"></a>10.8. Viewports</h2></div></div><div></div></div><p>It is unlikely that you will ever need to use the
+<tt class="classname">Viewport</tt> widget directly. You are much more likely to
+use the <tt class="classname">ScrolledWindow</tt> widget *see <a href="sec-ScrolledWindows.html" title="10.9. Scrolled Windows">Section 10.9, “Scrolled Windowsâ€</a>) which in turn uses the
+<tt class="classname">Viewport</tt>.</p><p>A viewport widget allows you to place a larger widget within it
+such that you can view a part of it at a time. It uses
+<tt class="classname">Adjustment</tt> object (see <a href="ch-Adjustments.html" title="Chapter 7. Adjustments">Chapter 7, <i>Adjustments</i></a>) to define the area that is currently in
+view.</p><p>A <tt class="classname">Viewport</tt> is created with the
+function:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ viewport = gtk.Viewport(<b class="parameter"><tt>hadjustment</tt></b>=None, <b class="parameter"><tt>vadjustment</tt></b>=None)
+</pre></td></tr></table><p>As you can see you can specify the horizontal and vertical
+<tt class="classname">Adjustment</tt> objects that the widget is to use when you
+create the widget. It will create its own if you pass
+<tt class="literal">None</tt> as the value of the arguments or pass no
+arguments.</p><p>You can get and set the adjustments after the widget has been
+created using the following four methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ viewport.get_hadjustment()
+
+ viewport.get_vadjustment()
+
+ viewport.set_hadjustment(<b class="parameter"><tt>adjustment</tt></b>)
+
+ viewport.set_vadjustment(<b class="parameter"><tt>adjustment</tt></b>)
+</pre></td></tr></table><p>The only other viewport method is used to alter its
+appearance:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ viewport.set_shadow_type(<b class="parameter"><tt>type</tt></b>)
+</pre></td></tr></table><p>Possible values for the <i class="parameter"><tt>type</tt></i> parameter
+are:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ SHADOW_NONE
+ SHADOW_IN
+ SHADOW_OUT
+ SHADOW_ETCHED_IN
+ SHADOW_ETCHED_OUT
+</pre></td></tr></table></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-PanedWindowWidgets.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-ContainerWidgets.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-ScrolledWindows.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">10.7. Paned Window Widgets </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 10.9. Scrolled Windows</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-WidgetAccelerators.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-WidgetAccelerators.html
new file mode 100644
index 0000000..54e0c6a
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-WidgetAccelerators.html
@@ -0,0 +1,39 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>18.3. Widget Accelerators</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-SettingWidgetAttributes.html" title="Chapter 18. Setting Widget Attributes"><link rel="previous" href="sec-WidgetDisplayMethods.html" title="18.2. Widget Display Methods"><link rel="next" href="sec-WidgetNameMethods.html" title="18.4. Widget Name Methods"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">18.3. Widget Accelerators</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-WidgetDisplayMethods.html">Prev</a> </td><th width="60%" align="center">Chapter 18. Setting Widget Attributes</th><td width="20%" align="right"> <a accesskey="n" href="sec-WidgetNameMethods.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-WidgetAccelerators"></a>18.3. Widget Accelerators</h2></div></div><div></div></div><p>The following methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ widget.add_accelerator(<b class="parameter"><tt>accel_signal</tt></b>, <b class="parameter"><tt>accel_group</tt></b>, <b class="parameter"><tt>accel_key</tt></b>, <b class="parameter"><tt>accel_mods</tt></b>, <b class="parameter"><tt>accel_flags</tt></b>)
+
+ widget.remove_accelerator(<b class="parameter"><tt>accel_group</tt></b>, <b class="parameter"><tt>accel_key</tt></b>, <b class="parameter"><tt>accel_mods</tt></b>)
+</pre></td></tr></table><p>add and remove accelerators from a
+<tt class="classname">gtk.AcceleratorGroup</tt> that must be attached to the top
+level widget to handle the accelerators.</p><p>The <i class="parameter"><tt>accel_signal</tt></i> is a signal that is valid
+for the <i class="parameter"><tt>widget</tt></i> to emit.</p><p>The <i class="parameter"><tt>accel_key</tt></i> is a keyboard key to use as the
+accelerator.</p><p>The <i class="parameter"><tt>accel_mods</tt></i> are modifiers to add to the
+<i class="parameter"><tt>accel_key</tt></i> (e.g. <span><b class="keycap">Shift</b></span>,
+<span><b class="keycap">Control</b></span>, etc.):</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ SHIFT_MASK
+ LOCK_MASK
+ CONTROL_MASK
+ MOD1_MASK
+ MOD2_MASK
+ MOD3_MASK
+ MOD4_MASK
+ MOD5_MASK
+ BUTTON1_MASK
+ BUTTON2_MASK
+ BUTTON3_MASK
+ BUTTON4_MASK
+ BUTTON5_MASK
+ RELEASE_MASK
+</pre></td></tr></table><p>The <i class="parameter"><tt>accel_flags</tt></i> set options about how the
+accelerator information is displayed. Valid values are:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ ACCEL_VISIBLE # display the accelerator key in the widget display
+
+ ACCEL_LOCKED # do not allow the accelerator display to change
+</pre></td></tr></table><p>An accelerator group is created by the function:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ accel_group = gtk.AccelGroup()
+</pre></td></tr></table><p>The <i class="parameter"><tt>accel_group</tt></i> is attached to a top level
+widget with the following method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ window.add_accel_group(<b class="parameter"><tt>accel_group</tt></b>)
+</pre></td></tr></table><p>An example of adding an accelerator:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ menu_item.add_accelerator("activate", accel_group,
+ ord('Q'), gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE)
+</pre></td></tr></table></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-WidgetDisplayMethods.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-SettingWidgetAttributes.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-WidgetNameMethods.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">18.2. Widget Display Methods </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 18.4. Widget Name Methods</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-WidgetDisplayMethods.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-WidgetDisplayMethods.html
new file mode 100644
index 0000000..e461b7e
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-WidgetDisplayMethods.html
@@ -0,0 +1,30 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>18.2. Widget Display Methods</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-SettingWidgetAttributes.html" title="Chapter 18. Setting Widget Attributes"><link rel="previous" href="ch-SettingWidgetAttributes.html" title="Chapter 18. Setting Widget Attributes"><link rel="next" href="sec-WidgetAccelerators.html" title="18.3. Widget Accelerators"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">18.2. Widget Display Methods</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch-SettingWidgetAttributes.html">Prev</a> </td><th width="60%" align="center">Chapter 18. Setting Widget Attributes</th><td width="20%" align="right"> <a accesskey="n" href="sec-WidgetAccelerators.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-WidgetDisplayMethods"></a>18.2. Widget Display Methods</h2></div></div><div></div></div><p>The methods:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ widget.show()
+
+ widget.show_all()
+
+ widget.hide()
+
+ widget.hide_all()
+
+ widget.realize()
+
+ widget.unrealize()
+
+ widget.map()
+
+ widget.unmap()
+</pre></td></tr></table><p>manage the display of the <i class="parameter"><tt>widget</tt></i>.</p><p>The <tt class="methodname">show</tt>() method arranges to display the
+widget by using the <tt class="methodname">realize</tt>() and
+<tt class="methodname">map</tt>() methods.</p><p>The <tt class="methodname">hide</tt>() method arranges to remove the
+widget from the display and also unmaps it using the
+<tt class="methodname">unmap</tt>() method if necessary.</p><p>The <tt class="methodname">show_all</tt>() and
+<tt class="methodname">hide_all</tt>() methods arrange to show or hide the
+widget and all its children.</p><p>The <tt class="methodname">realize</tt>() method arranges to allocate
+resources to the widget including its window.</p><p>The <tt class="methodname">unrealize</tt>() method releases the
+widget window and other resources. Unrealizing a widget will also hide and
+unmap it.</p><p>The <tt class="methodname">map</tt>() method arranges to allocate
+space on the display for the widget; this only applies to widgets that need
+to be handled by the window manager. Mapping a widget will also cause it to
+be realized if necessary.</p><p>The <tt class="methodname">unmap</tt>() method removes a widget from
+the display and will also hide it if necessary.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch-SettingWidgetAttributes.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-SettingWidgetAttributes.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-WidgetAccelerators.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 18. Setting Widget Attributes </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 18.3. Widget Accelerators</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-WidgetNameMethods.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-WidgetNameMethods.html
new file mode 100644
index 0000000..121757e
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-WidgetNameMethods.html
@@ -0,0 +1,11 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>18.4. Widget Name Methods</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-SettingWidgetAttributes.html" title="Chapter 18. Setting Widget Attributes"><link rel="previous" href="sec-WidgetAccelerators.html" title="18.3. Widget Accelerators"><link rel="next" href="sec-WidgetStyles.html" title="18.5. Widget Styles"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">18.4. Widget Name Methods</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-WidgetAccelerators.html">Prev</a> </td><th width="60%" align="center">Chapter 18. Setting Widget Attributes</th><td width="20%" align="right"> <a accesskey="n" href="sec-WidgetStyles.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-WidgetNameMethods"></a>18.4. Widget Name Methods</h2></div></div><div></div></div><p>The following widget methods set and get the name of a
+widget:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ widget.set_name(<b class="parameter"><tt>name</tt></b>)
+
+ name = widget.get_name()
+</pre></td></tr></table><p><i class="parameter"><tt>name</tt></i> is the string that will be associated
+with the <i class="parameter"><tt>widget</tt></i>. This is useful for specifying styles
+to be used with specific widgets within an application. The name of the
+widget can be used to narrow the application of the style as opposed to
+using the widget's class. See <a href="ch-GtkRcFiles.html" title="Chapter 23. GTK's rc Files">Chapter 23, <i>GTK's rc Files</i></a> for more
+details.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-WidgetAccelerators.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-SettingWidgetAttributes.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="sec-WidgetStyles.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">18.3. Widget Accelerators </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 18.5. Widget Styles</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-WidgetStyles.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-WidgetStyles.html
new file mode 100644
index 0000000..8863261
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-WidgetStyles.html
@@ -0,0 +1,74 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>18.5. Widget Styles</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-SettingWidgetAttributes.html" title="Chapter 18. Setting Widget Attributes"><link rel="previous" href="sec-WidgetNameMethods.html" title="18.4. Widget Name Methods"><link rel="next" href="ch-TimeoutsIOAndIdleFunctions.html" title="Chapter 19. Timeouts, IO and Idle Functions"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">18.5. Widget Styles</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sec-WidgetNameMethods.html">Prev</a> </td><th width="60%" align="center">Chapter 18. Setting Widget Attributes</th><td width="20%" align="right"> <a accesskey="n" href="ch-TimeoutsIOAndIdleFunctions.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-WidgetStyles"></a>18.5. Widget Styles</h2></div></div><div></div></div><p>The following methods get and set the style associated with a
+widget:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ widget.set_style(<b class="parameter"><tt>style</tt></b>)
+
+ style = widget.get_style()
+</pre></td></tr></table><p>The following function:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ style = get_default_style()
+</pre></td></tr></table><p>gets the default style.</p><p>A style contains the graphics information needed by a widget to
+draw itself in its various states:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ STATE_NORMAL # The state during normal operation.
+ STATE_ACTIVE # The widget is currently active, such as a button pushed
+ STATE_PRELIGHT # The mouse pointer is over the widget.
+ STATE_SELECTED # The widget is selected
+ STATE_INSENSITIVE # The widget is disabled
+</pre></td></tr></table><p>A style contains the following attributes:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ fg # a list of 5 foreground colors - one for each state
+ bg # a list of 5 background colors
+ light # a list of 5 colors - created during set_style() method
+ dark # a list of 5 colors - created during set_style() method
+ mid # a list of 5 colors - created during set_style() method
+ text # a list of 5 colors
+ base # a list of 5 colors
+ text_aa # a list of 5 colors halfway between text/base
+
+ black # the black color
+ white # the white color
+ font_desc # the default pango font description
+
+ xthickness #
+ ythickness #
+
+ fg_gc # a list of 5 graphics contexts - created during set_style() method
+ bg_gc # a list of 5 graphics contexts - created during set_style() method
+ light_gc # a list of 5 graphics contexts - created during set_style() method
+ dark_gc # a list of 5 graphics contexts - created during set_style() method
+ mid_gc # a list of 5 graphics contexts - created during set_style() method
+ text_gc # a list of 5 graphics contexts - created during set_style() method
+ base_gc # a list of 5 graphics contexts - created during set_style() method
+ black_gc # a list of 5 graphics contexts - created during set_style() method
+ white_gc # a list of 5 graphics contexts - created during set_style() method
+
+ bg_pixmap # a list of 5 GdkPixmaps
+</pre></td></tr></table><p>Each attribute can be accessed directly similar to
+<i class="parameter"><tt>style.black</tt></i> and
+<i class="parameter"><tt>style.fg_gc[gtk.STATE_NORMAL]</tt></i>. All attributes are
+read-only except for <i class="parameter"><tt>style.black</tt></i>,
+<i class="parameter"><tt>style.white</tt></i>, <i class="parameter"><tt>style.black_gc</tt></i> and
+<i class="parameter"><tt>style.white_gc</tt></i>.</p><p>An existing style can be copied for later modification by using
+the method:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ new_style = style.copy()
+</pre></td></tr></table><p>which copies the <i class="parameter"><tt>style</tt></i> attributes except
+for the graphics context lists and the light, dark and mid color
+lists.</p><p>The current style of a widget can be retrieved with:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ style = widget.get_style()
+</pre></td></tr></table><p>To change the style of a widget (e.g. to change the widget
+foreground color), the following widget methods should be used:</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ widget.modify_fg(state, color)
+ widget.modify_bg(state, color)
+ widget.modify_text(state, color)
+ widget.modify_base(state, color)
+ widget.modify_font(font_desc)
+ widget.set_style(style)
+</pre></td></tr></table><p>Setting the <i class="parameter"><tt>style</tt></i> will allocate the style
+colors and create the graphics contexts. Most widgets will automatically
+redraw themselves after the style is changed. If
+<i class="parameter"><tt>style</tt></i> is <tt class="literal">None</tt> then the widget
+style will revert to the default style.</p><p>Not all style changes will affect the widget. For example,
+changing the <tt class="classname">Label</tt> (see <a href="ch-MiscellaneousWidgets.html#sec-Labels" title="9.1. Labels">Section 9.1, “Labelsâ€</a>) widget background color will not change the
+label background color because the <tt class="classname">Label</tt> widget does
+not have its own <tt class="classname">gtk.gdk.Window</tt>. The background of
+the label is dependent on the background color of the label's parent. The
+use of an <tt class="classname">EventBox</tt> to hold a Label will allow the
+Label background color to be set. See <a href="ch-ContainerWidgets.html#sec-EventBox" title="10.1. The EventBox">Section 10.1, “The EventBoxâ€</a> for an
+example.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sec-WidgetNameMethods.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-SettingWidgetAttributes.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch-TimeoutsIOAndIdleFunctions.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">18.4. Widget Name Methods </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 19. Timeouts, IO and Idle Functions</td></tr></table></div></body></html>
diff --git a/help/Pygtk2Tutorial/pygtk2tutorial/sec-WidgetsWithoutWindows.html b/help/Pygtk2Tutorial/pygtk2tutorial/sec-WidgetsWithoutWindows.html
new file mode 100644
index 0000000..1952862
--- /dev/null
+++ b/help/Pygtk2Tutorial/pygtk2tutorial/sec-WidgetsWithoutWindows.html
@@ -0,0 +1,30 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>5.2. Widgets Without Windows</title><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="PyGTK 2.0 Tutorial"><link rel="up" href="ch-WidgetOverview.html" title="Chapter 5. Widget Overview"><link rel="previous" href="ch-WidgetOverview.html" title="Chapter 5. Widget Overview"><link rel="next" href="ch-ButtonWidget.html" title="Chapter 6. The Button Widget"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">5.2. Widgets Without Windows</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch-WidgetOverview.html">Prev</a> </td><th width="60%" align="center">Chapter 5. Widget Overview</th><td width="20%" align="right"> <a accesskey="n" href="ch-ButtonWidget.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sec-WidgetsWithoutWindows"></a>5.2. Widgets Without Windows</h2></div></div><div></div></div><p>The following widgets do not have an associated window. If you
+want to capture events, you'll have to use the
+<tt class="classname">EventBox</tt>. See the section on the
+<tt class="classname">EventBox</tt> widget.</p><table border="0" bgcolor="#E0E0E0" width="100%"><tr><td><pre class="programlisting">
+ gtk.Alignment
+ gtk.Arrow
+ gtk.Bin
+ gtk.Box
+ gtk.Button
+ gtk.CheckButton
+ gtk.Fixed
+ gtk.Image
+ gtk.Label
+ gtk.MenuItem
+ gtk.Notebook
+ gtk.Paned
+ gtk.RadioButton
+ gtk.Range
+ gtk.ScrolledWindow
+ gtk.Separator
+ gtk.Table
+ gtk.Toolbar
+ gtk.AspectFrame
+ gtk.Frame
+ gtk.VBox
+ gtk.HBox
+ gtk.VSeparator
+ gtk.HSeparator
+</pre></td></tr></table><p>We'll further our exploration of PyGTK by examining each widget
+in turn, creating a few simple example programs to display them.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch-WidgetOverview.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch-WidgetOverview.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch-ButtonWidget.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 5. Widget Overview </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 6. The Button Widget</td></tr></table></div></body></html>
diff --git a/help/PythonExamples/index.html b/help/PythonExamples/index.html
new file mode 100644
index 0000000..6472fee
--- /dev/null
+++ b/help/PythonExamples/index.html
@@ -0,0 +1,451 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<head>
+ <title>PLEAC - Programming Language Examples Alike Cookbook</title>
+ <link rev="made" href="mailto:gc@mandranokespamsoft.com" />
+ <meta name="keywords" content="programming, cookbook, perl, ruby, GNU, Linux, Guillaume Cottenceau, Free Software, FDL" />
+ <meta name="description" content="Homepage of the PLEAC Project." />
+ <link rel="stylesheet" type="text/css" href="pleac.css" media="screen" />
+</head>
+
+<body bgcolor="#FFFFFF" text="#000000" link="#0000ee" vlink="#551a8b">
+
+ <h1 align="center">PLEAC - Programming Language Examples Alike Cookbook</h1>
+
+<a href="http://sourceforge.net">
+<img src="http://sourceforge.net/sflogo.php?group_id=27880" width="88"
+height="31" border="0" alt="SourceForge Logo"></img></a>
+
+
+<h2>Summary</h2>
+
+<p>
+Following the great <a href="http://www.oreilly.com/catalog/cookbook">Perl
+Cookbook</a> (by Tom Christiansen &amp; Nathan Torkington, published by
+O'Reilly; you can freely browse an excerpt of the book
+<a href="http://safari.oreilly.com/0596003137">here</a>) which
+presents a suite of common programming problems solved in the
+Perl language, this project aims to implement the solutions in
+other programming languages.
+</p>
+
+<p>
+If successful, this project may become a primary resource for quick, handy
+and free reference to solve most common programming problems using
+various programming languages, and for comparison on ease-of-use and
+power/efficiency of these languages.
+</p>
+
+<p>
+The material, considered as some Documentation, is wholly released under
+the Gnu <a href="http://www.gnu.org/copyleft/fdl.html">Free Documentation
+License</a>, except the Perl part, which is copyrighted by O'Reilly &amp;
+Associates yet <a href="http://examples.oreilly.com/cookbook/">freely
+available</a>.
+</p>
+
+<p>
+Please <a
+href="http://lists.sourceforge.net/lists/listinfo/pleac-discuss">subscribe</a>
+to the discussion mailing-list if interested in the project.
+</p>
+
+<p>
+The FAQ is <a href="pleac-faq.html">here</a>. You may also see <a
+href="pleac-refer.html">who talked</a> about Pleac.
+</p>
+
+
+<h2>Status</h2>
+
+<p>
+The latest status is accessible from here (the Perl part
+is the Solutions from the Perl Cookbook, the rest is PLEAC contents):
+</p>
+<ul>
+<li>
+
+<a href="pleac_perl/index.html">perl</a>, 100.00% done
+(<a href="pleac_perl.data">raw source</a>, <a href="pleac_perl.html">colorized source</a>)
+</li>
+<li>
+
+<a href="pleac_groovy/index.html">groovy</a>, 100.00% done
+(<a href="pleac_groovy.data">raw source</a>, <a href="pleac_groovy.html">colorized source</a>)
+</li>
+<li>
+
+<a href="pleac_ocaml/index.html">ocaml</a>, 100.00% done
+(<a href="pleac_ocaml.data">raw source</a>, <a href="pleac_ocaml.html">colorized source</a>)
+</li>
+<li>
+
+<a href="pleac_python/index.html">python</a>, 85.43% done
+(<a href="pleac_python.data">raw source</a>, <a href="pleac_python.html">colorized source</a>)
+</li>
+<li>
+
+<a href="pleac_ruby/index.html">ruby</a>, 65.57% done
+(<a href="pleac_ruby.data">raw source</a>, <a href="pleac_ruby.html">colorized source</a>)
+</li>
+<li>
+
+<a href="pleac_guile/index.html">guile</a>, 47.29% done
+(<a href="pleac_guile.data">raw source</a>, <a href="pleac_guile.html">colorized source</a>)
+</li>
+<li>
+
+<a href="pleac_commonlisp/index.html">commonlisp</a>, 40.86% done
+(<a href="pleac_commonlisp.data">raw source</a>, <a href="pleac_commonlisp.html">colorized source</a>)
+</li>
+<li>
+
+<a href="pleac_rexx/index.html">rexx</a>, 40.00% done
+(<a href="pleac_rexx.data">raw source</a>, <a href="pleac_rexx.html">colorized source</a>)
+</li>
+<li>
+
+<a href="pleac_tcl/index.html">tcl</a>, 39.86% done
+(<a href="pleac_tcl.data">raw source</a>, <a href="pleac_tcl.html">colorized source</a>)
+</li>
+<li>
+
+<a href="pleac_php/index.html">php</a>, 36.57% done
+(<a href="pleac_php.data">raw source</a>, <a href="pleac_php.html">colorized source</a>)
+</li>
+<li>
+
+<a href="pleac_pike/index.html">pike</a>, 33.86% done
+(<a href="pleac_pike.data">raw source</a>, <a href="pleac_pike.html">colorized source</a>)
+</li>
+<li>
+
+<a href="pleac_merd/index.html">merd</a>, 28.86% done
+(<a href="pleac_merd.data">raw source</a>, <a href="pleac_merd.html">colorized source</a>)
+</li>
+<li>
+
+<a href="pleac_haskell/index.html">haskell</a>, 28.29% done
+(<a href="pleac_haskell.data">raw source</a>, <a href="pleac_haskell.html">colorized source</a>)
+</li>
+<li>
+
+<a href="pleac_ada/index.html">ada</a>, 26.00% done
+(<a href="pleac_ada.data">raw source</a>, <a href="pleac_ada.html">colorized source</a>)
+</li>
+<li>
+
+<a href="pleac_haskell-on-steroids/index.html">haskell-on-steroids</a>, 20.86% done
+(<a href="pleac_haskell-on-steroids.data">raw source</a>, <a href="pleac_haskell-on-steroids.html">colorized source</a>)
+</li>
+<li>
+
+<a href="pleac_java/index.html">java</a>, 20.86% done
+(<a href="pleac_java.data">raw source</a>, <a href="pleac_java.html">colorized source</a>)
+</li>
+<li>
+
+<a href="pleac_cposix/index.html">cposix</a>, 12.14% done
+(<a href="pleac_cposix.data">raw source</a>, <a href="pleac_cposix.html">colorized source</a>)
+</li>
+<li>
+
+<a href="pleac_pliant/index.html">pliant</a>, 9.43% done
+(<a href="pleac_pliant.data">raw source</a>, <a href="pleac_pliant.html">colorized source</a>)
+</li>
+<li>
+
+<a href="pleac_c++/index.html">c++</a>, 8.00% done
+(<a href="pleac_c++.data">raw source</a>, <a href="pleac_c++.html">colorized source</a>)
+</li>
+<li>
+
+<a href="pleac_factor/index.html">factor</a>, 2.86% done
+(<a href="pleac_factor.data">raw source</a>, <a href="pleac_factor.html">colorized source</a>)
+</li>
+<li>
+
+<a href="pleac_smalltalk/index.html">smalltalk</a>, 2.29% done
+(<a href="pleac_smalltalk.data">raw source</a>, <a href="pleac_smalltalk.html">colorized source</a>)
+</li>
+<li>
+
+<a href="pleac_forth/index.html">forth</a>, 2.00% done
+(<a href="pleac_forth.data">raw source</a>, <a href="pleac_forth.html">colorized source</a>)
+</li>
+<li>
+
+<a href="pleac_erlang/index.html">erlang</a>, 1.86% done
+(<a href="pleac_erlang.data">raw source</a>, <a href="pleac_erlang.html">colorized source</a>)
+</li>
+<li>
+
+<a href="pleac_R/index.html">R</a>, 1.43% done
+(<a href="pleac_R.data">raw source</a>, <a href="pleac_R.html">colorized source</a>)
+</li>
+<li>
+
+<a href="pleac_masd/index.html">masd</a>, 0.57% done
+(<a href="pleac_masd.data">raw source</a>, <a href="pleac_masd.html">colorized source</a>)
+</li>
+<li>
+
+<a href="pleac_nasm/index.html">nasm</a>, 0.29% done
+(<a href="pleac_nasm.data">raw source</a>, <a href="pleac_nasm.html">colorized source</a>)
+</li>
+</ul>
+<p>
+Your favourite language hasn't yet got any implementation? <a
+href="http://lists.sourceforge.net/lists/listinfo/pleac-discuss">Contribute!</a>.
+</p>
+<p>
+If you like statistics, you may have a look at <a
+href="pleac_evolving.png">pleac evolving over time</a>. It shows
+the evolution of completeness percentage since the beginning of
+the project, for the top implementations.
+</p>
+<p>
+Here is the <a href="AUTHORS">name of the authors</a> so far,
+and <a href="AUTHORS.currently-working">authors currently busy</a> on the
+different languages.
+</p>
+
+
+
+<h2>Compare sections</h2>
+
+<p>
+You can quickly and easily compare a section of Pleac between
+different languages with <a
+href="http://sparcs.kaist.ac.kr/~tinuviel/pleac/pleac.cgi">this
+nice script by Seo Sanghyeon</a>.
+</p>
+
+
+
+<h2>Milestones</h2>
+
+<p><b>200704.</b> The project has been making rapid progress of
+late. Significant additions have been made to both OCaml and
+Guile with both languages now over 40% complete, as they have
+been made to Tcl, PHP, Pike and REXX, where these languages are
+now well over 30% complete. Haskell is undergoing a
+reimplementation so as to better conform to standards, and code
+has been added to each of C, C++, and Common LISP, with each of
+these languages now near 10% complete. Special mention should be
+made of Python, a language which has made slow, but steady,
+progress to now be about 85% complete, as it should be made of
+Groovy, which is the latest PLEAC language addition, one which
+has made remarkably rapid progress, having achieved 100%
+completion in a matter of months. The top 5 are now Groovy
+(100%), Python (85%), Ruby (63%), Guile (43%) and OCaml
+(41%). According to Sourceforge statistics, we have 2,000 page
+views a day.
+
+<p><b>200501.</b> The project is evolving well. Python and Ruby
+contributions have been coming in steadily (both now over 60%),
+sizable contributions have been made to Tcl (25%), Ocaml (24%),
+Ada (26%) and Pliant (9%). Pike has also picked up as of late
+(14%). R has been added. To simplify using and creating example
+scripts, an include system has been implemented, allowing scripts
+and data to live in seperate files, which makes them easier to be
+accessed and used. Standalone scripts are also accessible as
+links from the web presentation. And if you're curious of
+statistics, you can have a look at the graphics showing evolution
+over time (available upper in the Status section).
+
+<p><b>200307.</b> The project is slowing down a bit, but still
+alive: there are contributed additions, some languages get
+beginning of implementations (forth, common lisp, pike). This
+main-page sees an average of 50 visitors per day.
+
+<p><b>200110.</b> The project is in good shape: we now have
+decent versions in Python (43%), Merd (30%), Guile (27%), Ruby (25%),
+Haskell (21%), Tcl (17%), and Java (14%). It can already be used to make
+basic comparisons between languages, and begins to be referred in some
+programming language mailing lists. We also have starting implementations
+in languages which are not part of the industry standards, but still very
+important for a programmers' culture, namely OCaml (7.29%), Erlang (1.86%)
+and Pliant (1.71%).
+</p>
+
+<p><b>200108.</b> Project registered in <a
+href="http://freshmeat.net/releases/54133/">Freshmeat</a>.
+Versions status are: Merd 30%, Ruby 25%, Haskell and Python around 10%.
+</p>
+
+<p><b>200105 (project founding).</b> The project has been accepted by
+SourceForge. Great! Time to work on the generic sourcecode-colorized web
+pages, and to begin implementations in Ruby and Merd.
+</p>
+
+
+
+<h2>Contribute</h2>
+
+<p>
+To contribute to this projet, you may implement the Solutions shown in the
+Perl Cookbook in your language of choice, writing them in a simple
+description language made of <tt>@@PLEAC@@_KEYWORD</tt> sections:
+<ul>
+<li>If you're adding a new part for an existing programming language
+(already some done in PLEAC for that language, for example Ruby), follow what's in
+this <a href="simple_sample.data">simple sample</a>.
+</li>
+<li>If you're adding a new programming language (nothing done in
+PLEAC for that language), follow what's in
+this <a href="sample.data">sample</a>.</li>
+</ul>
+You may also follow the &quot;code&quot; links upper.
+</p>
+
+<p>
+In all cases,
+please <a href="http://lists.sourceforge.net/lists/listinfo/pleac-discuss">subscribe</a>
+to the discussion mailing-list and post your submission there, so
+we can discuss and include your work.
+</p>
+
+<p>
+You may pay particular attention to the results produced by your code.
+Given merits and drawbacks of the Perl language, main aim of the project
+is to solve exactly the same problems in other languages; indeed, when a
+resembling keyword of another language doesn't behave the same way, be
+sure to underline this within comments in your source, and provide us with
+the solution in order to solve exactly the same problem, and produce
+exactly the same output.
+</p>
+
+<p>
+Each time new contents is uploaded to this web site, all description
+language sources are copied under the &quot;code&quot; links in the Status
+section upper, and compiled into &quot;html output&quot;.
+</p>
+
+<p>
+There is a mailing-list logging the CVS commits (see <a
+href="http://sourceforge.net/docman/display_doc.php?docid=772&group_id=1">SourceForge
+documentation</a> on this topic), you can <a
+href="http://lists.sourceforge.net/lists/listinfo/pleac-commits">subscribe</a>
+in order to be informed and discuss the commits.
+</p>
+
+
+<h2>Building the project</h2>
+
+<p>
+To generate the sgml and build the html outputs off the source from <a
+href="http://cvs.sourceforge.net/cvstarballs/pleac-cvsroot.tar.bz2">nightly
+tarball</a> or directly via an anoymous CVS <a
+href="http://sourceforge.net/cvs/?group_id=27880">checkout</a>, you'll
+need the relevant building software. Here are the typically
+needed packages:
+</p>
+
+<pre class="screen">
+make
+ruby
+sgml-common
+sgml-tools
+openjade
+docbook-style-dsssl
+docbook-dtd31-sgml
+emacs
+emacs-X11
+</pre>
+
+<p>
+Additionally, find <tt>`htmlize.el'</tt> and put it in your
+<tt>~/etc/emacs</tt>. All right, you'll probably suffer to successfully
+compile the stuff ;p.
+
+</p>
+
+
+<h2>Related links</h2>
+
+<p>
+These are interesting projects on the same topic (thanks to Pixel):
+</p>
+<ul>
+<li><a href="http://shootout.alioth.debian.org/great/index.php">The Great Computer Language Shootout
+</a></li>
+<li><a href="http://ucsub.colorado.edu/~kominek/rot13/">rot13</a> in
+different languages (string manipulation)</li>
+<li><a href="http://www.nyx.net/~gthompso/quine.htm">Quine</a>
+(self-reproducing code)</li>
+<li>The <a href="http://www.latech.edu/~acm/HelloWorld.shtml">&quot;Hello,
+World&quot;</a> Page</li>
+<li>The <a href="http://www.99-bottles-of-beer.net/">99 Bottles
+of Beer</a> problem</li>
+<li><a href="http://onestepback.org/articles/poly/">OO example
+code</a></li>
+<li><a href="http://www.angelfire.com/tx4/cus/shapes/index.html">OO shape
+examples</a></li>
+<li><a href="http://www.zenspider.com/Languages/Ruby/Cookbook/index.html">
+Ryan Davis's Ruby Cookbook</a>, a strangely named &quot;collaborative
+work&quot; since main author is holding the copyright and all rights are
+reserved</li>
+<li>ActiveState and O'Reilly's <a
+href="http://aspn.activestate.com/ASPN/Cookbook/Python">Python
+Cookbook</a></li>
+<li>ActiveState's <a
+href="http://aspn.activestate.com/ASPN/Cookbook/Tcl">Tcl Cookbook</a></li>
+<li>Michael Neumann's <a
+href="http://www.ntecs.de/old-hp/uu9r/lang/html/lang.en.html">examples
+of programming languages</a></li>
+<li>Pixel's <a
+href="http://merd.net/pixel/language-study/syntax-across-languages.html">Syntax
+Across Languages</a></li>
+<li>Pixel's <a href="http://merd.sourceforge.net/pixel/language-study/scripting-language/">scriptometer</a></li>
+<li><a href="http://cl-cookbook.sourceforge.net/">The Common Lisp Cookbook</a></li>
+<li>A sort of <a href="http://www.htus.org/">Scheme Cookbook</a></li>
+<li>A sort of <a href="http://www.kochandreas.com/home/language/lang.htm">Andreas' practical language comparison</a></li>
+<li>The <a href="http://llama.med.harvard.edu/~fgibbons/PerlPythonPhrasebook.html">Perl/Python Phrase-Book</a></li>
+</ul>
+</p>
+
+
+
+<h2>Administrative</h2>
+
+<p><a href="http://sourceforge.net">SourceForge</a> is kind enough to <a
+href="http://sourceforge.net/projects/pleac">host</a> this project.
+</p>
+
+<p>As the legal parts of any project is primarily important, O'Reilly, who
+is the publisher of the Perl Cookbook, was asked for a confirmation that
+this project would not infringe patents or harm copyright and intellectual
+property. Linda Mui from O'Reilly was kind enough to answer back and
+confirm that this project would not harm in any way their business with
+the Perl Cookbook. Many thanks to Linda.
+</p>
+<p><a href="http://zarb.org/~gc/resource/gc_mail.png">Guillaume
+Cottenceau</a> is project maintainer.
+</p>
+
+
+
+<!--
+<a href="http://www.estat.com/getstats?serial=285085103803"><img
+src="http://perso.estat.com/cgi-bin/perso/285085103803?page=pleac_main"
+border="0" alt="Estat"></img></a>
+
+<p></p>
+-->
+
+<font size="-1">Last update: Mon Mar 30 22:49:37 CEST 2009</font>
+
+<!--
+<address>
+ <a href="http://validator.w3.org/check/referer">
+ <img src="images/v3c_validated.png" height="31" width="88" align="right"
+ border="0" alt="Valid XHTML 1.0!" />
+ </a>
+</address>
+-->
+
+</body>
+
+</html>
diff --git a/help/PythonExamples/library/library.info b/help/PythonExamples/library/library.info
new file mode 100644
index 0000000..ef5bab6
--- /dev/null
+++ b/help/PythonExamples/library/library.info
@@ -0,0 +1,9 @@
+[Library]
+name = PythonExamples
+global_name = PythonExamples
+long_name = PythonExamples
+category = media
+library_version = 1
+host_version = 1
+l10n = false
+locale = en
diff --git a/help/PythonExamples/pleac.css b/help/PythonExamples/pleac.css
new file mode 100644
index 0000000..21007a9
--- /dev/null
+++ b/help/PythonExamples/pleac.css
@@ -0,0 +1,17 @@
+body {
+ padding: 1em 2em;
+}
+
+h1 {
+ background-color: #eee;
+ padding: 0.5em 0.3em;
+ text-align: left;
+ margin: 0 0 0.5em;
+}
+
+h2 {
+ background-color: #eee;
+ padding: 0.3em;
+ margin: 1em 0 0.5em;
+}
+
diff --git a/help/PythonExamples/pleac_python/a1102.html b/help/PythonExamples/pleac_python/a1102.html
new file mode 100644
index 0000000..f2cc853
--- /dev/null
+++ b/help/PythonExamples/pleac_python/a1102.html
@@ -0,0 +1,172 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML
+><HEAD
+><TITLE
+>Helpers</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
+REL="HOME"
+TITLE="PLEAC-Python
+"
+HREF="index.html"><LINK
+REL="PREVIOUS"
+TITLE="Web Automation"
+HREF="webautomation.html"><style type="text/css"> <!--
+ .comment {
+ /* font-lock-comment-face */
+ color: #bebebe;
+ }
+ .comment-delimiter {
+ }
+ .function-name {
+ /* font-lock-function-name-face */
+ color: #b2dfee;
+ }
+ .keyword {
+ /* font-lock-keyword-face */
+ color: #ffa500;
+ }
+ .py-builtins {
+ /* py-builtins-face */
+ color: #ffa500;
+ }
+ .py-pseudo-keyword {
+ /* py-pseudo-keyword-face */
+ color: #ffa500;
+ }
+ .string {
+ /* font-lock-string-face */
+ color: #00cd00;
+ }
+ .type {
+ /* font-lock-type-face */
+ color: #98fb98;
+ }
+ -->
+ </style></head
+><BODY TEXT="#cecece" BGCOLOR="#4f6f6f" LINK="#f5deb3" VLINK="#d5ae83"
+CLASS="APPENDIX"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><DIV
+CLASS="NAVHEADER"
+><TABLE
+SUMMARY="Header navigation table"
+WIDTH="100%"
+BORDER="0"
+CELLPADDING="0"
+CELLSPACING="0"
+><TR
+><TH
+COLSPAN="3"
+ALIGN="center"
+>PLEAC-Python
+</TH
+></TR
+><TR
+><TD
+WIDTH="10%"
+ALIGN="left"
+VALIGN="bottom"
+><A
+HREF="webautomation.html"
+ACCESSKEY="P"
+>Prev</A
+></TD
+><TD
+WIDTH="80%"
+ALIGN="center"
+VALIGN="bottom"
+></TD
+><TD
+WIDTH="10%"
+ALIGN="right"
+VALIGN="bottom"
+>&nbsp;</TD
+></TR
+></TABLE
+><HR
+ALIGN="LEFT"
+WIDTH="100%"></DIV
+><DIV
+CLASS="APPENDIX"
+><H1
+CLASS="APPENDIX"
+><A
+NAME="AEN1102"
+>A. Helpers</A
+></H1
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="NAVFOOTER"
+><HR
+ALIGN="LEFT"
+WIDTH="100%"><TABLE
+SUMMARY="Footer navigation table"
+WIDTH="100%"
+BORDER="0"
+CELLPADDING="0"
+CELLSPACING="0"
+><TR
+><TD
+WIDTH="33%"
+ALIGN="left"
+VALIGN="top"
+><A
+HREF="webautomation.html"
+ACCESSKEY="P"
+>Prev</A
+></TD
+><TD
+WIDTH="34%"
+ALIGN="center"
+VALIGN="top"
+><A
+HREF="index.html"
+ACCESSKEY="H"
+>Home</A
+></TD
+><TD
+WIDTH="33%"
+ALIGN="right"
+VALIGN="top"
+>&nbsp;</TD
+></TR
+><TR
+><TD
+WIDTH="33%"
+ALIGN="left"
+VALIGN="top"
+>Web Automation</TD
+><TD
+WIDTH="34%"
+ALIGN="center"
+VALIGN="top"
+>&nbsp;</TD
+><TD
+WIDTH="33%"
+ALIGN="right"
+VALIGN="top"
+>&nbsp;</TD
+></TR
+></TABLE
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/help/PythonExamples/pleac_python/arrays.html b/help/PythonExamples/pleac_python/arrays.html
new file mode 100644
index 0000000..362550a
--- /dev/null
+++ b/help/PythonExamples/pleac_python/arrays.html
@@ -0,0 +1,1495 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML
+><HEAD
+><TITLE
+>Arrays</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
+REL="HOME"
+TITLE="PLEAC-Python
+"
+HREF="index.html"><LINK
+REL="PREVIOUS"
+TITLE="Dates and Times"
+HREF="datesandtimes.html"><LINK
+REL="NEXT"
+TITLE="Hashes"
+HREF="hashes.html"><style type="text/css"> <!--
+ .comment {
+ /* font-lock-comment-face */
+ color: #bebebe;
+ }
+ .comment-delimiter {
+ }
+ .function-name {
+ /* font-lock-function-name-face */
+ color: #b2dfee;
+ }
+ .keyword {
+ /* font-lock-keyword-face */
+ color: #ffa500;
+ }
+ .py-builtins {
+ /* py-builtins-face */
+ color: #ffa500;
+ }
+ .py-pseudo-keyword {
+ /* py-pseudo-keyword-face */
+ color: #ffa500;
+ }
+ .string {
+ /* font-lock-string-face */
+ color: #00cd00;
+ }
+ .type {
+ /* font-lock-type-face */
+ color: #98fb98;
+ }
+ -->
+ </style></head
+><BODY TEXT="#cecece" BGCOLOR="#4f6f6f" LINK="#f5deb3" VLINK="#d5ae83"
+CLASS="SECT1"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><DIV
+CLASS="NAVHEADER"
+><TABLE
+SUMMARY="Header navigation table"
+WIDTH="100%"
+BORDER="0"
+CELLPADDING="0"
+CELLSPACING="0"
+><TR
+><TH
+COLSPAN="3"
+ALIGN="center"
+>PLEAC-Python
+</TH
+></TR
+><TR
+><TD
+WIDTH="10%"
+ALIGN="left"
+VALIGN="bottom"
+><A
+HREF="datesandtimes.html"
+ACCESSKEY="P"
+>Prev</A
+></TD
+><TD
+WIDTH="80%"
+ALIGN="center"
+VALIGN="bottom"
+></TD
+><TD
+WIDTH="10%"
+ALIGN="right"
+VALIGN="bottom"
+><A
+HREF="hashes.html"
+ACCESSKEY="N"
+>Next</A
+></TD
+></TR
+></TABLE
+><HR
+ALIGN="LEFT"
+WIDTH="100%"></DIV
+><DIV
+CLASS="SECT1"
+><H1
+CLASS="SECT1"
+><A
+NAME="ARRAYS"
+>4. Arrays</A
+></H1
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN170"
+>Introduction</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Python does not automatically flatten lists, in other words
+</span><span class="comment-delimiter"># </span><span class="comment">in the following, non-nested contains four elements and
+</span><span class="comment-delimiter"># </span><span class="comment">nested contains three elements, the third element of which
+</span><span class="comment-delimiter"># </span><span class="comment">is itself a list containing two elements:
+</span>non_nested = [<span class="string">"this"</span>, <span class="string">"that"</span>, <span class="string">"the"</span>, <span class="string">"other"</span>]
+nested = [<span class="string">"this"</span>, <span class="string">"that"</span>, [<span class="string">"the"</span>, <span class="string">"other"</span>]]
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>tune = [<span class="string">"The"</span>, <span class="string">"Star-Spangled"</span>, <span class="string">"Banner"</span>]
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN173"
+>Specifying a List In Your Program</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>a = [<span class="string">"quick"</span>, <span class="string">"brown"</span>, <span class="string">"fox"</span>]
+a = <span class="string">"Why are you teasing me?"</span>.split()
+
+text = <span class="string">"""
+ The boy stood on the burning deck,
+ It was as hot as glass.
+"""</span>
+lines = [line.lstrip() <span class="keyword">for</span> line <span class="keyword">in</span> text.strip().split(<span class="string">"\n"</span>)]
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>biglist = [line.rstrip() <span class="keyword">for</span> line <span class="keyword">in</span> <span class="py-builtins">open</span>(<span class="string">"mydatafile"</span>)]
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>banner = <span class="string">"The Mines of Moria"</span>
+banner = <span class="string">'The Mines of Moria'</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>name = <span class="string">"Gandalf"</span>
+banner = <span class="string">"Speak, "</span> + name + <span class="string">", and enter!"</span>
+banner = <span class="string">"Speak, %s, and welcome!"</span> % name
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>his_host = <span class="string">"www.python.org"</span>
+<span class="keyword">import</span> os
+host_info = os.popen(<span class="string">"nslookup "</span> + his_host).read()
+
+<span class="comment-delimiter"># </span><span class="comment">NOTE: not really relevant to Python (no magic '$$' variable)
+</span>python_info = os.popen(<span class="string">"ps %d"</span> % os.getpid()).read()
+shell_info = os.popen(<span class="string">"ps $$"</span>).read()
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">NOTE: not really relevant to Python (no automatic interpolation)
+</span>banner = [<span class="string">"Costs"</span>, <span class="string">"only"</span>, <span class="string">"$4.95"</span>]
+banner = <span class="string">"Costs only $4.95"</span>.split()
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>brax = <span class="string">""" ' "</span> ( ) &lt; &gt; { } [ ] <span class="string">""".split() #"""</span>
+brax = <span class="py-builtins">list</span>(<span class="string">"""'"</span>()&lt;&gt;{}[]<span class="string">""") #"""</span>
+rings = <span class="string">'''They'</span>re <span class="string">"Nenya Narya Vilya"'''.split() #'''</span>
+tags = <span class="string">'LI TABLE TR TD A IMG H1 P'</span>.split()
+sample = r<span class="string">'The backslash (\) is often used in regular expressions.'</span>.split()
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>banner = <span class="string">"The backslash (\\) is often used in regular expressions."</span>.split()
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>ships = u<span class="string">"Ni&#241;a Pinta Santa Mar&#237;a"</span>.split() <span class="comment-delimiter"># </span><span class="comment">WRONG (only three ships)
+</span>ships = [u<span class="string">"Ni&#241;a"</span>, u<span class="string">"Pinta"</span>, u<span class="string">"Santa Mar&#237;a"</span>] <span class="comment-delimiter"># </span><span class="comment">right
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN176"
+>Printing a List with Commas</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">def</span> <span class="function-name">commify_series</span>(args):
+ n = <span class="py-builtins">len</span>(args)
+ <span class="keyword">if</span> n == 0:
+ <span class="keyword">return</span> <span class="string">""</span>
+ <span class="keyword">elif</span> n == 1:
+ <span class="keyword">return</span> args[0]
+ <span class="keyword">elif</span> n == 2:
+ <span class="keyword">return</span> args[0] + <span class="string">" and "</span> + args[1]
+ <span class="keyword">return</span> <span class="string">", "</span>.join(args[:-1]) + <span class="string">", and "</span> + args[-1]
+
+commify_series([])
+commify_series([<span class="string">"red"</span>])
+commify_series([<span class="string">"red"</span>, <span class="string">"yellow"</span>])
+commify_series([<span class="string">"red"</span>, <span class="string">"yellow"</span>, <span class="string">"green"</span>])
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>mylist = [<span class="string">"red"</span>, <span class="string">"yellow"</span>, <span class="string">"green"</span>]
+<span class="keyword">print</span> <span class="string">"I have"</span>, mylist, <span class="string">"marbles."</span>
+<span class="keyword">print</span> <span class="string">"I have"</span>, <span class="string">" "</span>.join(mylist), <span class="string">"marbles."</span>
+<span class="comment-delimiter">#</span><span class="comment">=&gt; I have ['red', 'yellow', 'green'] marbles.
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt; I have red yellow green marbles.
+</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment">!/usr/bin/env python
+</span><span class="comment-delimiter"># </span><span class="comment">commify_series - show proper comma insertion in list output
+</span>data = (
+ ( <span class="string">'just one thing'</span>, ),
+ ( <span class="string">'Mutt Jeff'</span>.split() ),
+ ( <span class="string">'Peter Paul Mary'</span>.split() ),
+ ( <span class="string">'To our parents'</span>, <span class="string">'Mother Theresa'</span>, <span class="string">'God'</span> ),
+ ( <span class="string">'pastrami'</span>, <span class="string">'ham and cheese'</span>, <span class="string">'peanut butter and jelly'</span>, <span class="string">'tuna'</span> ),
+ ( <span class="string">'recycle tired, old phrases'</span>, <span class="string">'ponder big, happy thoughts'</span> ),
+ ( <span class="string">'recycle tired, old phrases'</span>,
+ <span class="string">'ponder big, happy thoughts'</span>,
+ <span class="string">'sleep and dream peacefully'</span> ),
+ )
+
+<span class="keyword">def</span> <span class="function-name">commify_series</span>(terms):
+ <span class="keyword">for</span> term <span class="keyword">in</span> terms:
+ <span class="keyword">if</span> <span class="string">","</span> <span class="keyword">in</span> term:
+ sepchar = <span class="string">"; "</span>
+ <span class="keyword">break</span>
+ <span class="keyword">else:</span>
+ sepchar = <span class="string">", "</span>
+
+ n = <span class="py-builtins">len</span>(terms)
+ <span class="keyword">if</span> n == 0:
+ <span class="keyword">return</span> <span class="string">""</span>
+ <span class="keyword">elif</span> n == 1:
+ <span class="keyword">return</span> terms[0]
+ <span class="keyword">elif</span> n == 2:
+ <span class="keyword">return</span> <span class="string">" and "</span>.join(terms)
+ <span class="keyword">return</span> <span class="string">"%s%sand %s"</span> % (sepchar.join(terms[:-1]), sepchar, terms[-1])
+
+<span class="keyword">for</span> item <span class="keyword">in</span> data:
+ <span class="keyword">print</span> <span class="string">"The list is: %s."</span> % commify_series(item)
+
+<span class="comment-delimiter">#</span><span class="comment">=&gt; The list is: just one thing.
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt; The list is: Mutt and Jeff.
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt; The list is: Peter, Paul, and Mary.
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt; The list is: To our parents, Mother Theresa, and God.
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt; The list is: pastrami, ham and cheese, peanut butter and jelly, and tuna.
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt; The list is: recycle tired, old phrases and ponder big, happy thoughts.
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt; The list is: recycle tired, old phrases; ponder big, happy thoughts; and
+</span><span class="comment-delimiter"># </span><span class="comment">sleep and dream peacefully.
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN179"
+>Changing Array Size</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Python allocates more space than is necessary every time a list needs to
+</span><span class="comment-delimiter"># </span><span class="comment">grow and only shrinks lists when more than half the available space is
+</span><span class="comment-delimiter"># </span><span class="comment">unused. This means that adding or removing an element will in most cases
+</span><span class="comment-delimiter"># </span><span class="comment">not force a reallocation.
+</span>
+<span class="keyword">del</span> mylist[size:] <span class="comment-delimiter"># </span><span class="comment">shrink mylist
+</span>mylist += [<span class="py-pseudo-keyword">None</span>] * size <span class="comment-delimiter"># </span><span class="comment">grow mylist by appending 'size' None elements
+</span>
+<span class="comment-delimiter"># </span><span class="comment">To add an element to the end of a list, use the append method:
+</span>mylist.append(4)
+
+<span class="comment-delimiter"># </span><span class="comment">To insert an element, use the insert method:
+</span>mylist.insert(0, 10) <span class="comment-delimiter"># </span><span class="comment">Insert 10 at the beginning of the list
+</span>
+<span class="comment-delimiter"># </span><span class="comment">To extend one list with the contents of another, use the extend method:
+</span>list2 = [1,2,3]
+mylist.extend(list2)
+
+<span class="comment-delimiter"># </span><span class="comment">To insert the contents of one list into another, overwriting zero or
+</span><span class="comment-delimiter"># </span><span class="comment">more elements, specify a slice:
+</span>mylist[1:1] = list2 <span class="comment-delimiter"># </span><span class="comment">Don't overwrite anything; grow mylist if needed
+</span>mylist[2:3] = list2 <span class="comment-delimiter"># </span><span class="comment">Overwrite mylist[2] and grow mylist if needed
+</span>
+<span class="comment-delimiter"># </span><span class="comment">To remove one element from the middle of a list:
+</span><span class="comment-delimiter"># </span><span class="comment">To remove elements from the middle of a list:
+</span><span class="keyword">del</span> mylist[idx1:idx2] <span class="comment-delimiter"># </span><span class="comment">0 or more
+</span>x = mylist.pop(idx) <span class="comment-delimiter"># </span><span class="comment">remove mylist[idx] and assign it to x
+</span>
+<span class="comment-delimiter"># </span><span class="comment">You cannot assign to or get a non-existent element:
+</span><span class="comment-delimiter"># </span><span class="comment">&gt;&gt;&gt; x = []
+</span><span class="comment-delimiter"># </span><span class="comment">&gt;&gt;&gt; x[4] = 5
+</span><span class="comment-delimiter">#</span><span class="comment">
+</span><span class="comment-delimiter"># </span><span class="comment">Traceback (most recent call last):
+</span><span class="comment-delimiter"># </span><span class="comment">File "&lt;pyshell#1&gt;", line 1, in -toplevel-
+</span><span class="comment-delimiter"># </span><span class="comment">x[4] = 5
+</span><span class="comment-delimiter"># </span><span class="comment">IndexError: list assignment index out of range
+</span><span class="comment-delimiter">#</span><span class="comment">
+</span><span class="comment-delimiter"># </span><span class="comment">&gt;&gt;&gt; print x[1000]
+</span><span class="comment-delimiter">#</span><span class="comment">
+</span><span class="comment-delimiter"># </span><span class="comment">Traceback (most recent call last):
+</span><span class="comment-delimiter"># </span><span class="comment">File "&lt;pyshell#16&gt;", line 1, in -toplevel-
+</span><span class="comment-delimiter"># </span><span class="comment">print x[1000]
+</span><span class="comment-delimiter"># </span><span class="comment">IndexError: list index out of range
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">def</span> <span class="function-name">what_about_that_list</span>(terms):
+ <span class="keyword">print</span> <span class="string">"The list now has"</span>, <span class="py-builtins">len</span>(terms), <span class="string">"elements."</span>
+ <span class="keyword">print</span> <span class="string">"The index of the last element is"</span>, <span class="py-builtins">len</span>(terms)-1, <span class="string">"(or -1)."</span>
+ <span class="keyword">print</span> <span class="string">"Element #3 is %s."</span> % terms[3]
+
+people = <span class="string">"Crosby Stills Nash Young"</span>.split()
+what_about_that_list(people)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt; The list now has 4 elements.
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt; The index of the last element is 3 (or -1).
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt; Element #3 is Young.
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>people.pop()
+what_about_that_list(people)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>people += [<span class="py-pseudo-keyword">None</span>] * (10000 - <span class="py-builtins">len</span>(people))
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment">&gt;&gt;&gt; people += [None] * (10000 - len(people))
+</span><span class="comment-delimiter">#</span><span class="comment">&gt;&gt;&gt; what_about_that_list(people)
+</span><span class="comment-delimiter">#</span><span class="comment">The list now has 10000 elements.
+</span><span class="comment-delimiter">#</span><span class="comment">The index of the last element is 9999 (or -1).
+</span><span class="comment-delimiter">#</span><span class="comment">Element #3 is None.
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN182"
+>Doing Something with Every Element in a List</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">for</span> item <span class="keyword">in</span> mylist:
+ <span class="keyword">pass</span> <span class="comment-delimiter"># </span><span class="comment">do something with item
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">for</span> user <span class="keyword">in</span> bad_users:
+ complain(user)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> os
+<span class="keyword">for</span> (key, val) <span class="keyword">in</span> sorted(os.environ.items()):
+ <span class="keyword">print</span> <span class="string">"%s=%s"</span> % (key, val)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">for</span> user <span class="keyword">in</span> all_users:
+ disk_space = get_usage(user) <span class="comment-delimiter"># </span><span class="comment">find out how much disk space in use
+</span> <span class="keyword">if</span> disk_space &gt; MAX_QUOTA: <span class="comment-delimiter"># </span><span class="comment">if it's more than we want ...
+</span> complain(user) <span class="comment-delimiter"># </span><span class="comment">... then object vociferously
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> os
+<span class="keyword">for</span> line <span class="keyword">in</span> os.popen(<span class="string">"who"</span>):
+ <span class="keyword">if</span> <span class="string">"dalke"</span> <span class="keyword">in</span> line:
+ <span class="keyword">print</span> line, <span class="comment-delimiter"># </span><span class="comment">or print line[:-1]
+</span>
+<span class="comment-delimiter"># </span><span class="comment">or:
+</span><span class="keyword">print</span> <span class="string">""</span>.join([line <span class="keyword">for</span> line <span class="keyword">in</span> os.popen(<span class="string">"who"</span>)
+ <span class="keyword">if</span> <span class="string">"dalke"</span> <span class="keyword">in</span> line]),
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">for</span> line <span class="keyword">in</span> myfile:
+ <span class="keyword">for</span> word <span class="keyword">in</span> line.split(): <span class="comment-delimiter"># </span><span class="comment">Split on whitespace
+</span> <span class="keyword">print</span> word[::-1], <span class="comment-delimiter"># </span><span class="comment">reverse word
+</span> <span class="keyword">print</span>
+
+<span class="comment-delimiter"># </span><span class="comment">pre 2.3:
+</span><span class="keyword">for</span> line <span class="keyword">in</span> myfile:
+ <span class="keyword">for</span> word <span class="keyword">in</span> line.split(): <span class="comment-delimiter"># </span><span class="comment">Split on whitespace
+</span> chars = <span class="py-builtins">list</span>(word) <span class="comment-delimiter"># </span><span class="comment">Turn the string into a list of characters
+</span> chars.reverse()
+ <span class="keyword">print</span> <span class="string">""</span>.join(chars),
+ <span class="keyword">print</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">for</span> item <span class="keyword">in</span> mylist:
+ <span class="keyword">print</span> <span class="string">"i ="</span>, item
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">NOTE: you can't modify in place the way Perl does:
+</span><span class="comment-delimiter"># </span><span class="comment">data = [1, 2, 3]
+</span><span class="comment-delimiter"># </span><span class="comment">for elem in data:
+</span><span class="comment-delimiter"># </span><span class="comment">elem -= 1
+</span><span class="comment-delimiter">#</span><span class="comment">print data
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt;[1, 2, 3]
+</span>
+data = [1, 2, 3]
+data = [i-1 <span class="keyword">for</span> i <span class="keyword">in</span> data]
+<span class="keyword">print</span> data
+<span class="comment-delimiter">#</span><span class="comment">=&gt;[0, 1, 2]
+</span>
+<span class="comment-delimiter"># </span><span class="comment">or
+</span><span class="keyword">for</span> i, elem <span class="keyword">in</span> <span class="py-builtins">enumerate</span>(data):
+ data[i] = elem - 1
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">NOTE: strings are immutable in Python so this doesn't translate well.
+</span>s = s.strip()
+data = [s.strip() <span class="keyword">for</span> s <span class="keyword">in</span> data]
+<span class="keyword">for</span> k, v <span class="keyword">in</span> mydict.items():
+ mydict[k] = v.strip()
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN185"
+>Iterating Over an Array by Reference</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>fruits = [<span class="string">"Apple"</span>, <span class="string">"Blackberry"</span>]
+<span class="keyword">for</span> fruit <span class="keyword">in</span> fruits:
+ <span class="keyword">print</span> fruit, <span class="string">"tastes good in a pie."</span>
+<span class="comment-delimiter">#</span><span class="comment">=&gt; Apple tastes good in a pie.
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt; Blackberry tastes good in a pie.
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS:
+</span><span class="keyword">for</span> i <span class="keyword">in</span> <span class="py-builtins">range</span>(len(fruits)):
+ <span class="keyword">print</span> fruits[i], <span class="string">"tastes good in a pie."</span>
+
+<span class="comment-delimiter"># </span><span class="comment">If you must explicitly index, use enumerate():
+</span><span class="keyword">for</span> i, fruit <span class="keyword">in</span> <span class="py-builtins">enumerate</span>(fruits):
+ <span class="keyword">print</span> <span class="string">"%s) %s tastes good in a pie."</span>%(i+1, fruit)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>rogue_cats = [<span class="string">"Morris"</span>, <span class="string">"Felix"</span>]
+namedict = { <span class="string">"felines"</span>: rogue_cats }
+<span class="keyword">for</span> cat <span class="keyword">in</span> namedict[<span class="string">"felines"</span>]:
+ <span class="keyword">print</span> cat, <span class="string">"purrs hypnotically."</span>
+<span class="keyword">print</span> <span class="string">"--More--\nYou are controlled."</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">As noted before, if you need an index, use enumerate() and not this:
+</span><span class="keyword">for</span> i <span class="keyword">in</span> <span class="py-builtins">range</span>(len(namedict[<span class="string">"felines"</span>])):
+ <span class="keyword">print</span> namedict[<span class="string">"felines"</span>][i], <span class="string">"purrs hypnotically."</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN188"
+>Extracting Unique Elements from a List</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>uniq = <span class="py-builtins">list</span>(set(mylist))
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">See http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/259174
+</span><span class="comment-delimiter"># </span><span class="comment">for a more heavyweight version of a bag
+</span>seen = {}
+<span class="keyword">for</span> item <span class="keyword">in</span> mylist:
+ seen[item] = seen.get(item, 0) + 1
+
+uniq = seen.keys()
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>seen = {}
+uniq = []
+<span class="keyword">for</span> item <span class="keyword">in</span> mylist:
+ count = seen.get(item, 0)
+ <span class="keyword">if</span> count == 0:
+ uniq.append(item)
+ seen[item] = count + 1
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">generate a list of users logged in, removing duplicates
+</span><span class="keyword">import</span> os
+usernames = [line.split()[0] <span class="keyword">for</span> line <span class="keyword">in</span> os.popen(<span class="string">"who"</span>)]
+uniq = sorted(set(usernames))
+<span class="keyword">print</span> <span class="string">"users logged in:"</span>, <span class="string">" "</span>.join(uniq)
+
+<span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS:
+</span><span class="keyword">import</span> os
+ucnt = {}
+<span class="keyword">for</span> line <span class="keyword">in</span> os.popen(<span class="string">"who"</span>):
+ username = line.split()[0] <span class="comment-delimiter"># </span><span class="comment">Get the first word
+</span> ucnt[username] = ucnt.get(username, 0) + 1 <span class="comment-delimiter"># </span><span class="comment">record the users' presence
+</span>
+<span class="comment-delimiter"># </span><span class="comment">extract and print unique keys
+</span>users = ucnt.keys()
+users.sort()
+<span class="keyword">print</span> <span class="string">"users logged in:"</span>, <span class="string">" "</span>.join(users)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN191"
+>Finding Elements in One Array but Not Another</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">assume a_list and b_list are already loaded
+</span>aonly = [item <span class="keyword">for</span> item <span class="keyword">in</span> a_list <span class="keyword">if</span> item <span class="keyword">not</span> <span class="keyword">in</span> b_list]
+
+<span class="comment-delimiter"># </span><span class="comment">A slightly more complex Pythonic version using sets - if you had a few
+</span><span class="comment-delimiter"># </span><span class="comment">lists, subtracting sets would be clearer than the listcomp version above
+</span>a_set = set(a_list)
+b_set = set(b_list)
+aonly = <span class="py-builtins">list</span>(a_set - b_set) <span class="comment-delimiter"># </span><span class="comment">Elements in a_set but not in b_set
+</span>
+<span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS.
+</span>seen = {} <span class="comment-delimiter"># </span><span class="comment">lookup table to test membership of B
+</span>aonly = [] <span class="comment-delimiter"># </span><span class="comment">answer
+</span>
+<span class="comment-delimiter"># </span><span class="comment">build lookup table
+</span><span class="keyword">for</span> item <span class="keyword">in</span> b_list:
+ seen[item] = 1
+
+<span class="comment-delimiter"># </span><span class="comment">find only elements in a_list and not in b_list
+</span><span class="keyword">for</span> item <span class="keyword">in</span> a_list:
+ <span class="keyword">if</span> <span class="keyword">not</span> item <span class="keyword">not</span> <span class="keyword">in</span> seen:
+ <span class="comment-delimiter"># </span><span class="comment">it's not in 'seen', so add to 'aonly'
+</span> aonly.append(item)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS. There's lots of ways not to do it.
+</span>seen = {} <span class="comment-delimiter"># </span><span class="comment">lookup table
+</span>aonly = [] <span class="comment-delimiter"># </span><span class="comment">answer
+</span>
+<span class="comment-delimiter"># </span><span class="comment">build lookup table - unnecessary and poor Python style
+</span>[seen.update({x: 1}) <span class="keyword">for</span> x <span class="keyword">in</span> b_list]
+
+aonly = [item <span class="keyword">for</span> item <span class="keyword">in</span> a_list <span class="keyword">if</span> item <span class="keyword">not</span> <span class="keyword">in</span> seen]
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>aonly = <span class="py-builtins">list</span>(set(a_list))
+
+<span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS.
+</span>seen = {}
+aonly = []
+<span class="keyword">for</span> item <span class="keyword">in</span> a_list:
+ <span class="keyword">if</span> item <span class="keyword">not</span> <span class="keyword">in</span> seen:
+ aonly.append(item)
+ seen[item] = 1 <span class="comment-delimiter"># </span><span class="comment">mark as seen
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>mydict[<span class="string">"key1"</span>] = 1
+mydict[<span class="string">"key2"</span>] = 2
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>mydict[(<span class="string">"key1"</span>, <span class="string">"key2"</span>)] = (1,2)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS:
+</span>seen = dict.fromkeys(B.keys())
+
+<span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS pre-2.3:
+</span>seen = {}
+<span class="keyword">for</span> term <span class="keyword">in</span> B:
+ seen[term] = <span class="py-pseudo-keyword">None</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS:
+</span>seen = {}
+<span class="keyword">for</span> k, v <span class="keyword">in</span> B:
+ seen[k] = 1
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN194"
+>Computing Union, Intersection, or Difference of Unique Lists</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>a = (1, 3, 5, 6, 7, 8)
+b = (2, 3, 5, 7, 9)
+
+a_set = set(a)
+b_set = set(b)
+
+union = a_set | b_set <span class="comment-delimiter"># </span><span class="comment">or a_set.union(b_set)
+</span>isect = a_set &amp; b_set <span class="comment-delimiter"># </span><span class="comment">or a_set.intersection(b_set)
+</span>diff = a_set ^ b_set <span class="comment-delimiter"># </span><span class="comment">or a_set.symmetric_difference(b_set)
+</span>
+
+<span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS:
+</span>union_list = []; isect_list = []; diff = []
+union_dict = {}; isect_dict = {}
+count = {}
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS:
+</span><span class="keyword">for</span> e <span class="keyword">in</span> a:
+ union_dict[e] = 1
+
+<span class="keyword">for</span> e <span class="keyword">in</span> b:
+ <span class="keyword">if</span> union_dict.has_key(e):
+ isect_dict[e] = 1
+ union_dict[e] = 1
+
+union_list = union_dict.keys()
+isect_list = isect_dict.keys()
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS:
+</span><span class="keyword">for</span> e <span class="keyword">in</span> a + b:
+ <span class="keyword">if</span> union.get(e, 0) == 0:
+ isect[e] = 1
+ union[e] = 1
+
+union = union.keys()
+isect = isect.keys()
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS:
+</span>count = {}
+<span class="keyword">for</span> e <span class="keyword">in</span> a + b:
+ count[e] = count.get(e, 0) + 1
+
+union = []; isect = []; diff = []
+
+<span class="keyword">for</span> e <span class="keyword">in</span> count.keys():
+ union.append(e)
+ <span class="keyword">if</span> count[e] == 2:
+ isect.append(e)
+ <span class="keyword">else:</span>
+ diff.append(e)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS:
+</span>isect = []; diff = []; union = []
+count = {}
+<span class="keyword">for</span> e <span class="keyword">in</span> a + b:
+ count[e] = count.get(e, 0) + 1
+
+<span class="keyword">for</span> e, num <span class="keyword">in</span> count.items():
+ union.append(e)
+ [<span class="py-pseudo-keyword">None</span>, diff, isect][num].append(e)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN197"
+>Appending One Array to Another</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">"append" for a single term and
+</span><span class="comment-delimiter"># </span><span class="comment">"extend" for many terms
+</span>mylist1.extend(mylist2)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>mylist1 = mylist1 + mylist2
+mylist1 += mylist2
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>members = [<span class="string">"Time"</span>, <span class="string">"Flies"</span>]
+initiates = [<span class="string">"An"</span>, <span class="string">"Arrow"</span>]
+members.extend(initiates)
+<span class="comment-delimiter"># </span><span class="comment">members is now ["Time", "Flies", "An", "Arrow"]
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>members[2:] = [<span class="string">"Like"</span>] + initiates
+<span class="keyword">print</span> <span class="string">" "</span>.join(members)
+members[:1] = [<span class="string">"Fruit"</span>] <span class="comment-delimiter"># </span><span class="comment">or members[1] = "Fruit"
+</span>members[-2:] = [<span class="string">"A"</span>, <span class="string">"Banana"</span>]
+<span class="keyword">print</span> <span class="string">" "</span>.join(members)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt; Time Flies Like An Arrow
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt; Fruit Flies Like A Banana
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN200"
+>Reversing an Array</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">reverse mylist into revlist
+</span>
+revlist = mylist[::-1]
+
+<span class="comment-delimiter"># </span><span class="comment">or
+</span>revlist = <span class="py-builtins">list</span>(reversed(mylist))
+
+<span class="comment-delimiter"># </span><span class="comment">or pre-2.3
+</span>revlist = mylist[:] <span class="comment-delimiter"># </span><span class="comment">shallow copy
+</span>revlist.reverse()
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">for</span> elem <span class="keyword">in</span> reversed(mylist):
+ <span class="keyword">pass</span> <span class="comment-delimiter"># </span><span class="comment">do something with elem
+</span>
+<span class="comment-delimiter"># </span><span class="comment">or
+</span><span class="keyword">for</span> elem <span class="keyword">in</span> mylist[::-1]:
+ <span class="keyword">pass</span> <span class="comment-delimiter"># </span><span class="comment">do something with elem
+</span>
+<span class="comment-delimiter"># </span><span class="comment">if you need the index and the list won't take too much memory:
+</span><span class="keyword">for</span> i, elem <span class="keyword">in</span> reversed(<span class="py-builtins">list</span>(enumerate(mylist))):
+ <span class="keyword">pass</span>
+
+<span class="comment-delimiter"># </span><span class="comment">If you absolutely must explicitly index:
+</span><span class="keyword">for</span> i <span class="keyword">in</span> <span class="py-builtins">range</span>(len(mylist)-1, -1, -1):
+ <span class="keyword">pass</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>descending = sorted(users, reverse=<span class="py-pseudo-keyword">True</span>)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN203"
+>Processing Multiple Elements of an Array</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">remove n elements from the front of mylist
+</span>mylist[:n] = [] <span class="comment-delimiter"># </span><span class="comment">or del mylist[:n]
+</span>
+<span class="comment-delimiter"># </span><span class="comment">remove n elements from front of mylist, saving them into front
+</span>front, mylist[:n] = mylist[:n], []
+
+<span class="comment-delimiter"># </span><span class="comment">remove 1 element from the front of mylist, saving it in front:
+</span>front = mylist.pop(0)
+
+<span class="comment-delimiter"># </span><span class="comment">remove n elements from the end of mylist
+</span>mylist[-n:] = [] <span class="comment-delimiter"># </span><span class="comment">or del mylist[-n:]
+</span>
+<span class="comment-delimiter"># </span><span class="comment">remove n elements from the end of mylist, saving them in end
+</span>end, mylist[-n:] = mylist[-n:], []
+
+<span class="comment-delimiter"># </span><span class="comment">remove 1 element from the end of mylist, saving it in end:
+</span>end = mylist.pop()
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">def</span> <span class="function-name">shift2</span>(terms):
+ front = terms[:2]
+ terms[:2] = []
+ <span class="keyword">return</span> front
+
+<span class="keyword">def</span> <span class="function-name">pop2</span>(terms):
+ back = terms[-2:]
+ terms[-2:] = []
+ <span class="keyword">return</span> back
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>friends = <span class="string">"Peter Paul Mary Jim Tim"</span>.split()
+this, that = shift2(friends)
+<span class="comment-delimiter"># </span><span class="comment">'this' contains Peter, 'that' has Paul, and
+</span><span class="comment-delimiter"># </span><span class="comment">'friends' has Mary, Jim, and Tim
+</span>
+beverages = <span class="string">"Dew Jolt Cola Sprite Fresca"</span>.split()
+pair = pop2(beverages)
+<span class="comment-delimiter"># </span><span class="comment">pair[0] contains Sprite, pair[1] has Fresca,
+</span><span class="comment-delimiter"># </span><span class="comment">and 'beverages' has (Dew, Jolt, Cola)
+</span>
+<span class="comment-delimiter"># </span><span class="comment">In general you probably shouldn't do things that way because it's
+</span><span class="comment-delimiter"># </span><span class="comment">not clear from these calls that the lists are modified.
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN206"
+>Finding the First List Element That Passes a Test</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="keyword">for</span> item <span class="keyword">in</span> mylist:
+ <span class="keyword">if</span> criterion:
+ <span class="keyword">pass</span> <span class="comment-delimiter"># </span><span class="comment">do something with matched item
+</span> <span class="keyword">break</span>
+<span class="keyword">else:</span>
+ <span class="keyword">pass</span> <span class="comment-delimiter"># </span><span class="comment">unfound
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">for</span> idx, elem <span class="keyword">in</span> <span class="py-builtins">enumerate</span>(mylist):
+ <span class="keyword">if</span> criterion:
+ <span class="keyword">pass</span> <span class="comment-delimiter"># </span><span class="comment">do something with elem found at mylist[idx]
+</span> <span class="keyword">break</span>
+<span class="keyword">else:</span>
+ <span class="keyword">pass</span> <span class="comment-delimiter">#</span><span class="comment"># unfound
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Assuming employees are sorted high-&gt;low by wage.
+</span><span class="keyword">for</span> employee <span class="keyword">in</span> employees:
+ <span class="keyword">if</span> employee.category == <span class="string">'engineer'</span>:
+ highest_engineer = employee
+ <span class="keyword">break</span>
+
+<span class="keyword">print</span> <span class="string">"Highest paid engineer is:"</span>, highest_engineer.name
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">If you need the index, use enumerate:
+</span><span class="keyword">for</span> i, employee <span class="keyword">in</span> <span class="py-builtins">enumerate</span>(employees):
+ <span class="keyword">if</span> employee.category == <span class="string">'engineer'</span>:
+ highest_engineer = employee
+ <span class="keyword">break</span>
+<span class="keyword">print</span> <span class="string">"Highest paid engineer is: #%s - %s"</span> % (i, highest_engineer.name)
+
+
+<span class="comment-delimiter"># </span><span class="comment">The following is rarely appropriate:
+</span><span class="keyword">for</span> i <span class="keyword">in</span> <span class="py-builtins">range</span>(len(mylist)):
+ <span class="keyword">if</span> criterion:
+ <span class="keyword">pass</span> <span class="comment-delimiter"># </span><span class="comment">do something
+</span> <span class="keyword">break</span>
+<span class="keyword">else:</span>
+ <span class="keyword">pass</span> <span class="comment-delimiter">#</span><span class="comment"># not found
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN209"
+>Finding All Elements in an Array Matching Certain Criteria</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span>matching = [term <span class="keyword">for</span> term <span class="keyword">in</span> mylist <span class="keyword">if</span> test(term)]
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>matching = []
+<span class="keyword">for</span> term <span class="keyword">in</span> mylist:
+ <span class="keyword">if</span> test(term):
+ matching.append(term)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>bigs = [num <span class="keyword">for</span> num <span class="keyword">in</span> nums <span class="keyword">if</span> num &gt; 1000000]
+pigs = [user <span class="keyword">for</span> (user, val) <span class="keyword">in</span> users.items() <span class="keyword">if</span> val &gt; 1e7]
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> os
+matching = [line <span class="keyword">for</span> line <span class="keyword">in</span> os.popen(<span class="string">"who"</span>)
+ <span class="keyword">if</span> line.startswith(<span class="string">"gnat "</span>)]
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>engineers = [employee <span class="keyword">for</span> employee <span class="keyword">in</span> employees
+ <span class="keyword">if</span> employee.position == <span class="string">"Engineer"</span>]
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>secondary_assistance = [applicant <span class="keyword">for</span> applicant <span class="keyword">in</span> applicants
+ <span class="keyword">if</span> 26000 &lt;= applicant.income &lt; 30000]
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN212"
+>Sorting an Array Numerically</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span>sorted_list = sorted(unsorted_list)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">pids is an unsorted list of process IDs
+</span><span class="keyword">import</span> os, signal, time
+<span class="keyword">for</span> pid <span class="keyword">in</span> sorted(pids):
+ <span class="keyword">print</span> pid
+
+pid = <span class="py-builtins">raw_input</span>(<span class="string">"Select a process ID to kill: "</span>)
+<span class="keyword">try:</span>
+ pid = <span class="py-builtins">int</span>(pid)
+<span class="keyword">except</span> <span class="py-builtins">ValueError</span>:
+ <span class="keyword">raise</span> <span class="py-builtins">SystemExit</span>(<span class="string">"Exiting ... "</span>)
+os.kill(pid, signal.SIGTERM)
+time.sleep(2)
+<span class="keyword">try:</span>
+ os.kill(pid, signal.SIGKILL)
+<span class="keyword">except</span> <span class="py-builtins">OSError</span>, err:
+ <span class="keyword">if</span> err.errno != 3: <span class="comment-delimiter"># </span><span class="comment">was it already killed?
+</span> <span class="keyword">raise</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>descending = sorted(unsorted_list, reverse=<span class="py-pseudo-keyword">True</span>)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>allnums = [4, 19, 8, 3]
+allnums.sort(reverse=<span class="py-pseudo-keyword">True</span>) <span class="comment-delimiter"># </span><span class="comment">inplace
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">pre 2.3
+</span>allnums.sort() <span class="comment-delimiter"># </span><span class="comment">inplace
+</span>allnums.reverse() <span class="comment-delimiter"># </span><span class="comment">inplace
+</span><span class="comment-delimiter">#</span><span class="comment">or
+</span>allnums = sorted(allnums, reverse=<span class="py-pseudo-keyword">True</span>) <span class="comment-delimiter"># </span><span class="comment">reallocating
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN215"
+>Sorting a List by Computable Field</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span>ordered = sorted(unordered, cmp=compare)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>ordered = sorted(unordered, key=compute)
+
+<span class="comment-delimiter"># </span><span class="comment">...which is somewhat equivalent to:
+</span>precomputed = [(compute(x), x) <span class="keyword">for</span> x <span class="keyword">in</span> unordered]
+precomputed.sort(<span class="keyword">lambda</span> a, b: <span class="py-builtins">cmp</span>(a[0], b[0]))
+ordered = [v <span class="keyword">for</span> k,v <span class="keyword">in</span> precomputed.items()]
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS.
+</span><span class="keyword">def</span> <span class="function-name">functional_sort</span>(mylist, function):
+ mylist.sort(function)
+ <span class="keyword">return</span> mylist
+
+ordered = [v <span class="keyword">for</span> k,v <span class="keyword">in</span> functional_sort([(compute(x), x) <span class="keyword">for</span> x <span class="keyword">in</span> unordered],
+ <span class="keyword">lambda</span> a, b: <span class="py-builtins">cmp</span>(a[0], b[0]))]
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>ordered = sorted(employees, key=<span class="keyword">lambda</span> x: x.name)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">for</span> employee <span class="keyword">in</span> sorted(employees, key=<span class="keyword">lambda</span> x: x.name):
+ <span class="keyword">print</span> <span class="string">"%s earns $%s"</span> % (employee.name, employee.salary)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>sorted_employees = sorted(employees, key=<span class="keyword">lambda</span> x: x.name):
+<span class="keyword">for</span> employee <span class="keyword">in</span> sorted_employees:
+ <span class="keyword">print</span> <span class="string">"%s earns $%s"</span> % (employee.name, employee.salary)
+
+<span class="comment-delimiter"># </span><span class="comment">load bonus
+</span><span class="keyword">for</span> employee <span class="keyword">in</span> sorted_employees:
+ <span class="keyword">if</span> bonus(employee.ssn):
+ <span class="keyword">print</span> employee.name, <span class="string">"got a bonus!"</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>sorted_employees = sorted(employees, key=<span class="keyword">lambda</span> x: (x.name, x.age)):
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">NOTE: Python should allow access to the pwd fields by name
+</span><span class="comment-delimiter"># </span><span class="comment">as well as by position.
+</span><span class="keyword">import</span> pwd
+<span class="comment-delimiter"># </span><span class="comment">fetch all users
+</span>users = pwd.getpwall()
+<span class="keyword">for</span> user <span class="keyword">in</span> sorted(users, key=<span class="keyword">lambda</span> x: x[0]):
+ <span class="keyword">print</span> user[0]
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>sorted_list = sorted(names, key=<span class="keyword">lambda</span> x: x[:1])
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>sorted_list = sorted(strings, key=len)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS.
+</span>temp = [(<span class="py-builtins">len</span>(s), s) <span class="keyword">for</span> s <span class="keyword">in</span> strings]
+temp.sort(<span class="keyword">lambda</span> a, b: <span class="py-builtins">cmp</span>(a[0], b[0]))
+sorted_list = [x[1] <span class="keyword">for</span> x <span class="keyword">in</span> temp]
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS.
+</span><span class="keyword">def</span> <span class="function-name">functional_sort</span>(mylist, function):
+ mylist.sort(function)
+ <span class="keyword">return</span> mylist
+
+sorted_fields = [v <span class="keyword">for</span> k,v <span class="keyword">in</span> functional_sort(
+ [(<span class="py-builtins">int</span>(re.search(r<span class="string">"(\d+)"</span>, x).group(1)), x) <span class="keyword">for</span> x <span class="keyword">in</span> fields],
+ <span class="keyword">lambda</span> a, b: <span class="py-builtins">cmp</span>(a[0], b[0]))]
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>entries = [line[:-1].split() <span class="keyword">for</span> line <span class="keyword">in</span> <span class="py-builtins">open</span>(<span class="string">"/etc/passwd"</span>)]
+
+<span class="keyword">for</span> entry <span class="keyword">in</span> sorted(entries, key=<span class="keyword">lambda</span> x: (x[3], x[2], x[0])):
+ <span class="keyword">print</span> entry
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN218"
+>Implementing a Circular List</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> itertools
+<span class="keyword">for</span> process <span class="keyword">in</span> itertools.cycle([1, 2, 3, 4, 5]):
+ <span class="keyword">print</span> <span class="string">"Handling process"</span>, process
+ time.sleep(1)
+
+<span class="comment-delimiter"># </span><span class="comment">pre 2.3:
+</span><span class="keyword">import</span> time
+<span class="keyword">class</span> <span class="type">Circular</span>(object):
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>, data):
+ <span class="keyword">assert</span> <span class="py-builtins">len</span>(data) &gt;= 1, <span class="string">"Cannot use an empty list"</span>
+ <span class="py-pseudo-keyword">self</span>.data = data
+
+ <span class="keyword">def</span> <span class="function-name">__iter__</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="keyword">while</span> <span class="py-pseudo-keyword">True</span>:
+ <span class="keyword">for</span> elem <span class="keyword">in</span> <span class="py-pseudo-keyword">self</span>.data:
+ <span class="keyword">yield</span> elem
+
+circular = Circular([1, 2, 3, 4, 5])
+
+<span class="keyword">for</span> process <span class="keyword">in</span> circular:
+ <span class="keyword">print</span> <span class="string">"Handling process"</span>, process
+ time.sleep(1)
+
+<span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS. All those pops and appends mean that the list needs to be
+</span><span class="comment-delimiter"># </span><span class="comment">constantly reallocated. This is rather bad if your list is large:
+</span><span class="keyword">import</span> time
+<span class="keyword">class</span> <span class="type">Circular</span>(object):
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>, data):
+ <span class="keyword">assert</span> <span class="py-builtins">len</span>(data) &gt;= 1, <span class="string">"Cannot use an empty list"</span>
+ <span class="py-pseudo-keyword">self</span>.data = data
+
+ <span class="keyword">def</span> <span class="function-name">next</span>(<span class="py-pseudo-keyword">self</span>):
+ head = <span class="py-pseudo-keyword">self</span>.data.pop(0)
+ <span class="py-pseudo-keyword">self</span>.data.append(head)
+ <span class="keyword">return</span> head
+
+circular = Circular([1, 2, 3, 4, 5])
+<span class="keyword">while</span> <span class="py-pseudo-keyword">True</span>:
+ process = circular.next()
+ <span class="keyword">print</span> <span class="string">"Handling process"</span>, process
+ time.sleep(1)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN221"
+>Randomizing an Array</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">generate a random permutation of mylist in place
+</span><span class="keyword">import</span> random
+random.shuffle(mylist)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN224"
+>Program: words</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> sys
+
+<span class="keyword">def</span> <span class="function-name">make_columns</span>(mylist, screen_width=78):
+ <span class="keyword">if</span> mylist:
+ maxlen = <span class="py-builtins">max</span>([<span class="py-builtins">len</span>(elem) <span class="keyword">for</span> elem <span class="keyword">in</span> mylist])
+ maxlen += 1 <span class="comment-delimiter"># </span><span class="comment">to make extra space
+</span>
+ cols = <span class="py-builtins">max</span>(1, screen_width/maxlen)
+ rows = 1 + <span class="py-builtins">len</span>(mylist)/cols
+
+ <span class="comment-delimiter"># </span><span class="comment">pre-create mask for faster computation
+</span> mask = <span class="string">"%%-%ds "</span> % (maxlen-1)
+
+ <span class="keyword">for</span> n <span class="keyword">in</span> <span class="py-builtins">range</span>(rows):
+ row = [mask%elem
+ <span class="keyword">for</span> elem <span class="keyword">in</span> mylist[n::rows]]
+ <span class="keyword">yield</span> <span class="string">""</span>.join(row).rstrip()
+
+<span class="keyword">for</span> row <span class="keyword">in</span> make_columns(sys.stdin.readlines(), screen_width=50):
+ <span class="keyword">print</span> row
+
+
+<span class="comment-delimiter"># </span><span class="comment">A more literal translation
+</span><span class="keyword">import</span> sys
+
+<span class="comment-delimiter"># </span><span class="comment">subroutine to check whether at last item on line
+</span><span class="keyword">def</span> <span class="function-name">EOL</span>(item):
+ <span class="keyword">return</span> (item+1) % cols == 0
+
+<span class="comment-delimiter"># </span><span class="comment">Might not be portable to non-linux systems
+</span><span class="keyword">def</span> <span class="function-name">getwinsize</span>():
+ <span class="comment-delimiter"># </span><span class="comment">Use the curses module if installed
+</span> <span class="keyword">try:</span>
+ <span class="keyword">import</span> curses
+ stdscr = curses.initscr()
+ rows, cols = stdscr.getmaxyx()
+ <span class="keyword">return</span> cols
+ <span class="keyword">except</span> <span class="py-builtins">ImportError</span>:
+ <span class="keyword">pass</span>
+
+ <span class="comment-delimiter"># </span><span class="comment">Nope, so deal with ioctl directly. What value for TIOCGWINSZ?
+</span> <span class="keyword">try:</span>
+ <span class="keyword">import</span> termios
+ TIOCGWINSZ = termios.TIOCGWINSZ
+ <span class="keyword">except</span> <span class="py-builtins">ImportError</span>:
+ TIOCGWINSZ = 0x40087468 <span class="comment-delimiter"># </span><span class="comment">This is Linux specific
+</span>
+ <span class="keyword">import</span> struct, fcntl
+ s = struct.pack(<span class="string">"HHHH"</span>, 0, 0, 0, 0)
+ <span class="keyword">try:</span>
+ x = fcntl.ioctl(sys.stdout.fileno(), TIOCGWINSZ, s)
+ <span class="keyword">except</span> <span class="py-builtins">IOError</span>:
+ <span class="keyword">return</span> 80
+ rows, cols = struct.unpack(<span class="string">"HHHH"</span>, x)[:2]
+ <span class="keyword">return</span> cols
+
+cols = getwinsize()
+
+data = [s.rstrip() <span class="keyword">for</span> s <span class="keyword">in</span> sys.stdin.readlines()]
+<span class="keyword">if</span> <span class="keyword">not</span> data:
+ maxlen = 1
+<span class="keyword">else:</span>
+ maxlen = <span class="py-builtins">max</span>(map(len, data))
+
+maxlen += 1 <span class="comment-delimiter"># </span><span class="comment">to make extra space
+</span>
+<span class="comment-delimiter"># </span><span class="comment">determine boundaries of screen
+</span>cols = (cols / maxlen) <span class="keyword">or</span> 1
+rows = (<span class="py-builtins">len</span>(data)+cols) / cols
+
+<span class="comment-delimiter"># </span><span class="comment">pre-create mask for faster computation
+</span>mask = <span class="string">"%%-%ds "</span> % (maxlen-1)
+
+<span class="comment-delimiter"># </span><span class="comment">now process each item, picking out proper piece for this position
+</span><span class="keyword">for</span> item <span class="keyword">in</span> <span class="py-builtins">range</span>(rows * cols):
+ target = (item % cols) * rows + (item/cols)
+ <span class="keyword">if</span> target &lt; <span class="py-builtins">len</span>(data):
+ piece = mask % data[target]
+ <span class="keyword">else:</span>
+ piece = mask % <span class="string">""</span>
+ <span class="keyword">if</span> EOL(item):
+ piece = piece.rstrip() <span class="comment-delimiter"># </span><span class="comment">don't blank-pad to EOL
+</span> sys.stdout.write(piece)
+ <span class="keyword">if</span> EOL(item):
+ sys.stdout.write(<span class="string">"\n"</span>)
+
+<span class="keyword">if</span> EOL(item):
+ sys.stdout.write(<span class="string">"\n"</span>)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN227"
+>Program: permute</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">def</span> <span class="function-name">factorial</span>(n):
+ s = 1
+ <span class="keyword">while</span> n:
+ s *= n
+ n -= 1
+ <span class="keyword">return</span> s
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">def</span> <span class="function-name">permute</span>(alist, blist=[]):
+ <span class="keyword">if</span> <span class="keyword">not</span> alist:
+ <span class="keyword">yield</span> blist
+ <span class="keyword">for</span> i, elem <span class="keyword">in</span> <span class="py-builtins">enumerate</span>(alist):
+ <span class="keyword">for</span> elem <span class="keyword">in</span> permute(alist[:i] + alist[i+1:], blist + [elem]):
+ <span class="keyword">yield</span> elem
+
+<span class="keyword">for</span> permutation <span class="keyword">in</span> permute(<span class="py-builtins">range</span>(4)):
+ <span class="keyword">print</span> permutation
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS
+</span><span class="keyword">import</span> fileinput
+
+<span class="comment-delimiter"># </span><span class="comment">Slightly modified from
+</span><span class="comment-delimiter"># </span><span class="comment">http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66463
+</span><span class="keyword">def</span> <span class="function-name">print_list</span>(alist, blist=[]):
+ <span class="keyword">if</span> <span class="keyword">not</span> alist:
+ <span class="keyword">print</span> <span class="string">' '</span>.join(blist)
+ <span class="keyword">for</span> i <span class="keyword">in</span> <span class="py-builtins">range</span>(len(alist)):
+ blist.append(alist.pop(i))
+ print_list(alist, blist)
+ alist.insert(i, blist.pop())
+
+<span class="keyword">for</span> line <span class="keyword">in</span> fileinput.input():
+ words = line.split()
+ print_list(words)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">class</span> <span class="type">FactorialMemo</span>(list):
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="py-pseudo-keyword">self</span>.append(1)
+
+ <span class="keyword">def</span> <span class="function-name">__call__</span>(<span class="py-pseudo-keyword">self</span>, n):
+ <span class="keyword">try:</span>
+ <span class="keyword">return</span> <span class="py-pseudo-keyword">self</span>[n]
+ <span class="keyword">except</span> <span class="py-builtins">IndexError</span>:
+ ret = n * <span class="py-pseudo-keyword">self</span>(n-1)
+ <span class="py-pseudo-keyword">self</span>.append(ret)
+ <span class="keyword">return</span> ret
+
+factorial = FactorialMemo()
+
+<span class="keyword">import</span> sys
+<span class="keyword">import</span> time
+sys.setrecursionlimit(10000)
+
+start = time.time()
+factorial(2000)
+f1 = time.time() - start
+factorial(2100) <span class="comment-delimiter"># </span><span class="comment">First 2000 values are cached already
+</span>f2 = time.time() - f1 - start
+<span class="keyword">print</span> <span class="string">"Slow first time:"</span>, f1
+<span class="keyword">print</span> <span class="string">"Quicker the second time:"</span>, f2
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>
+<span class="keyword">class</span> <span class="type">MemoizedPermutations</span>(list):
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>, alist):
+ <span class="py-pseudo-keyword">self</span>.permute(alist, [])
+
+ <span class="keyword">def</span> <span class="function-name">permute</span>(<span class="py-pseudo-keyword">self</span>, alist, blist):
+ <span class="keyword">if</span> <span class="keyword">not</span> alist:
+ <span class="py-pseudo-keyword">self</span>.append(blist)
+ <span class="keyword">for</span> i, elem <span class="keyword">in</span> <span class="py-builtins">enumerate</span>(alist):
+ <span class="py-pseudo-keyword">self</span>.permute(alist[:i] + alist[i+1:], blist + [elem])
+
+ <span class="keyword">def</span> <span class="function-name">__call__</span>(<span class="py-pseudo-keyword">self</span>, seq, idx):
+ <span class="keyword">return</span> [seq[n] <span class="keyword">for</span> n <span class="keyword">in</span> <span class="py-pseudo-keyword">self</span>[idx]]
+
+
+p5 = MemoizedPermutations(<span class="py-builtins">range</span>(5))
+
+words = <span class="string">"This sentence has five words"</span>.split()
+<span class="keyword">print</span> p5(words, 17)
+<span class="keyword">print</span> p5(words, 81)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+></DIV
+><DIV
+CLASS="NAVFOOTER"
+><HR
+ALIGN="LEFT"
+WIDTH="100%"><TABLE
+SUMMARY="Footer navigation table"
+WIDTH="100%"
+BORDER="0"
+CELLPADDING="0"
+CELLSPACING="0"
+><TR
+><TD
+WIDTH="33%"
+ALIGN="left"
+VALIGN="top"
+><A
+HREF="datesandtimes.html"
+ACCESSKEY="P"
+>Prev</A
+></TD
+><TD
+WIDTH="34%"
+ALIGN="center"
+VALIGN="top"
+><A
+HREF="index.html"
+ACCESSKEY="H"
+>Home</A
+></TD
+><TD
+WIDTH="33%"
+ALIGN="right"
+VALIGN="top"
+><A
+HREF="hashes.html"
+ACCESSKEY="N"
+>Next</A
+></TD
+></TR
+><TR
+><TD
+WIDTH="33%"
+ALIGN="left"
+VALIGN="top"
+>Dates and Times</TD
+><TD
+WIDTH="34%"
+ALIGN="center"
+VALIGN="top"
+>&nbsp;</TD
+><TD
+WIDTH="33%"
+ALIGN="right"
+VALIGN="top"
+>Hashes</TD
+></TR
+></TABLE
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/help/PythonExamples/pleac_python/cgiprogramming.html b/help/PythonExamples/pleac_python/cgiprogramming.html
new file mode 100644
index 0000000..1b3653a
--- /dev/null
+++ b/help/PythonExamples/pleac_python/cgiprogramming.html
@@ -0,0 +1,980 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML
+><HEAD
+><TITLE
+>CGI Programming</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
+REL="HOME"
+TITLE="PLEAC-Python
+"
+HREF="index.html"><LINK
+REL="PREVIOUS"
+TITLE="Internet Services"
+HREF="internetservices.html"><LINK
+REL="NEXT"
+TITLE="Web Automation"
+HREF="webautomation.html"><style type="text/css"> <!--
+ .comment {
+ /* font-lock-comment-face */
+ color: #bebebe;
+ }
+ .comment-delimiter {
+ }
+ .function-name {
+ /* font-lock-function-name-face */
+ color: #b2dfee;
+ }
+ .keyword {
+ /* font-lock-keyword-face */
+ color: #ffa500;
+ }
+ .py-builtins {
+ /* py-builtins-face */
+ color: #ffa500;
+ }
+ .py-pseudo-keyword {
+ /* py-pseudo-keyword-face */
+ color: #ffa500;
+ }
+ .string {
+ /* font-lock-string-face */
+ color: #00cd00;
+ }
+ .type {
+ /* font-lock-type-face */
+ color: #98fb98;
+ }
+ -->
+ </style></head
+><BODY TEXT="#cecece" BGCOLOR="#4f6f6f" LINK="#f5deb3" VLINK="#d5ae83"
+CLASS="SECT1"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><DIV
+CLASS="NAVHEADER"
+><TABLE
+SUMMARY="Header navigation table"
+WIDTH="100%"
+BORDER="0"
+CELLPADDING="0"
+CELLSPACING="0"
+><TR
+><TH
+COLSPAN="3"
+ALIGN="center"
+>PLEAC-Python
+</TH
+></TR
+><TR
+><TD
+WIDTH="10%"
+ALIGN="left"
+VALIGN="bottom"
+><A
+HREF="internetservices.html"
+ACCESSKEY="P"
+>Prev</A
+></TD
+><TD
+WIDTH="80%"
+ALIGN="center"
+VALIGN="bottom"
+></TD
+><TD
+WIDTH="10%"
+ALIGN="right"
+VALIGN="bottom"
+><A
+HREF="webautomation.html"
+ACCESSKEY="N"
+>Next</A
+></TD
+></TR
+></TABLE
+><HR
+ALIGN="LEFT"
+WIDTH="100%"></DIV
+><DIV
+CLASS="SECT1"
+><H1
+CLASS="SECT1"
+><A
+NAME="CGIPROGRAMMING"
+>19. CGI Programming</A
+></H1
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN1007"
+>Introduction</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">Introduction
+</span><span class="comment-delimiter">#</span><span class="comment">
+</span><span class="comment-delimiter"># </span><span class="comment">There is no standard cgi/web framework in python,
+</span><span class="comment-delimiter"># </span><span class="comment">this is reason for ranting now and then.
+</span><span class="comment-delimiter">#</span><span class="comment">
+</span><span class="comment-delimiter"># </span><span class="comment">See `PyWebOff &lt;<a href="http://pyre.third-bit.com/pyweb/index.html">http://pyre.third-bit.com/pyweb/index.html</a>&gt;`__
+</span><span class="comment-delimiter"># </span><span class="comment">which compares CherryPy, Quixote, Twisted, WebWare and Zope
+</span><span class="comment-delimiter"># </span><span class="comment">Karrigell and print stantements.
+</span><span class="comment-delimiter">#</span><span class="comment">
+</span><span class="comment-delimiter"># </span><span class="comment">Then there is Nevow and Standalone ZPT.
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN1010"
+>Writing a CGI Script</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">Partial implementation of PLEAC Python section 19.1
+</span><span class="comment-delimiter"># </span><span class="comment">Written by Seo Sanghyeon
+</span>
+<span class="comment-delimiter"># </span><span class="comment">Standard CGI module is where PERL shines. Python
+</span><span class="comment-delimiter"># </span><span class="comment">module, cgi, is nothing but a form parser. So it is
+</span><span class="comment-delimiter"># </span><span class="comment">not really fair to compare these two. But I hesitate
+</span><span class="comment-delimiter"># </span><span class="comment">to introduce any non-standard module. After all,
+</span><span class="comment-delimiter"># </span><span class="comment">which one should I choose?
+</span>
+<span class="comment-delimiter"># </span><span class="comment">I would stick to simple print statements. I believe
+</span><span class="comment-delimiter"># </span><span class="comment">the following is close to how these tasks are usually
+</span><span class="comment-delimiter"># </span><span class="comment">done in Python.
+</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment">!/usr/bin/env python
+</span><span class="comment-delimiter"># </span><span class="comment">hiweb - using FieldStorage class to get at form data
+</span>
+<span class="keyword">import</span> cgi
+form = cgi.FieldStorage()
+
+<span class="comment-delimiter"># </span><span class="comment">get a value from the form
+</span>value = form.getvalue(<span class="string">"PARAM_NAME"</span>)
+
+<span class="comment-delimiter"># </span><span class="comment">print a standard header
+</span><span class="keyword">print</span> <span class="string">"Content-Type: text/html"</span>
+<span class="keyword">print</span>
+
+<span class="comment-delimiter"># </span><span class="comment">print a document
+</span><span class="keyword">print</span> <span class="string">"&lt;P&gt;You typed: &lt;TT&gt;%s&lt;/TT&gt;&lt;/P&gt;"</span> % (
+ cgi.escape(value),
+ )
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> cgi
+form = cgi.FieldStorage()
+
+who = form.getvalue(<span class="string">"Name"</span>)
+phone = form.getvalue(<span class="string">"Number"</span>)
+picks = form.getvalue(<span class="string">"Choices"</span>)
+
+<span class="comment-delimiter"># </span><span class="comment">if you want to assure `picks' to be a list
+</span>picks = form.getlist(<span class="string">"Choices"</span>)
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Not Implemented
+</span>
+<span class="comment-delimiter"># </span><span class="comment">To implement -EXPIRES =&gt; '+3d', I need to study about
+</span><span class="keyword">import</span> cgi
+<span class="keyword">import</span> datetime
+
+time_format = <span class="string">"%a, %d %b %Y %H:%M:%S %Z"</span>
+<span class="keyword">print</span> <span class="string">"Expires: %s"</span> % (
+ (datetime.datetime.now()
+ + datetime.timedelta(+3)).strftime(time_format)
+ )
+<span class="keyword">print</span> <span class="string">"Date: %s"</span> % (datetime.datetime.now().strftime(time_format))
+<span class="keyword">print</span> <span class="string">"Content-Type: text/plain; charset=ISO-8859-1"</span>
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">NOTES
+</span>
+<span class="comment-delimiter"># </span><span class="comment">CGI::param() is a multi-purpose function. Here I want to
+</span><span class="comment-delimiter"># </span><span class="comment">note which Python functions correspond to it.
+</span>
+<span class="comment-delimiter"># </span><span class="comment">PERL version 5.6.1, CGI.pm version 2.80.
+</span><span class="comment-delimiter"># </span><span class="comment">Python version 2.2.3. cgi.py CVS revision 1.68.
+</span>
+<span class="comment-delimiter"># </span><span class="comment">Assume that `form' is the FieldStorage instance.
+</span>
+<span class="comment-delimiter"># </span><span class="comment">param() with zero argument returns parameter names as
+</span><span class="comment-delimiter"># </span><span class="comment">a list. It is `form.keys()' in Python, following Python's
+</span><span class="comment-delimiter"># </span><span class="comment">usual mapping interface.
+</span>
+<span class="comment-delimiter"># </span><span class="comment">param() with one argument returns the value of the named
+</span><span class="comment-delimiter"># </span><span class="comment">parameter. It is `form.getvalue()', but there are some
+</span><span class="comment-delimiter"># </span><span class="comment">twists:
+</span>
+<span class="comment-delimiter"># </span><span class="comment">1) A single value is passed.
+</span><span class="comment-delimiter"># </span><span class="comment">No problem.
+</span>
+<span class="comment-delimiter"># </span><span class="comment">2) Multiple values are passed.
+</span><span class="comment-delimiter"># </span><span class="comment">PERL: in LIST context, you get a list. in SCALAR context,
+</span><span class="comment-delimiter"># </span><span class="comment">you get the first value from the list.
+</span><span class="comment-delimiter"># </span><span class="comment">Python: `form.getvalue()' returns a list if multiple
+</span><span class="comment-delimiter"># </span><span class="comment">values are passed, a raw value if a single value
+</span><span class="comment-delimiter"># </span><span class="comment">is passed. With `form.getlist()', you always
+</span><span class="comment-delimiter"># </span><span class="comment">get a list. (When a single value is passed, you
+</span><span class="comment-delimiter"># </span><span class="comment">get a list with one element.) With `form.getfirst()',
+</span><span class="comment-delimiter"># </span><span class="comment">you always get a value. (When multiple values are
+</span><span class="comment-delimiter"># </span><span class="comment">passed, you get the first one.)
+</span>
+<span class="comment-delimiter"># </span><span class="comment">3) Parameter name is given, but no value is passed.
+</span><span class="comment-delimiter"># </span><span class="comment">PERL: returns an empty string, not undef. POD says this
+</span><span class="comment-delimiter"># </span><span class="comment">feature is new in 2.63, and was introduced to avoid
+</span><span class="comment-delimiter"># </span><span class="comment">"undefined value" warnings when running with the
+</span><span class="comment-delimiter"># </span><span class="comment">-w switch.
+</span><span class="comment-delimiter"># </span><span class="comment">Python: tricky. If you want black values to be retained,
+</span><span class="comment-delimiter"># </span><span class="comment">you should pass a nonzero `keep_blank_values' keyword
+</span><span class="comment-delimiter"># </span><span class="comment">argument. Default is not to retain blanks. In case
+</span><span class="comment-delimiter"># </span><span class="comment">values are not retained, see below.
+</span>
+<span class="comment-delimiter"># </span><span class="comment">4) Even parameter name is never mentioned.
+</span><span class="comment-delimiter"># </span><span class="comment">PERL: returns undef.
+</span><span class="comment-delimiter"># </span><span class="comment">Python: returns None, or whatever you passed as the second
+</span><span class="comment-delimiter"># </span><span class="comment">argument, or `default` keyword argument. This is
+</span><span class="comment-delimiter"># </span><span class="comment">consistent with `get()' method of the Python mapping
+</span><span class="comment-delimiter"># </span><span class="comment">interface.
+</span>
+<span class="comment-delimiter"># </span><span class="comment">param() with more than one argument modifies the already
+</span><span class="comment-delimiter"># </span><span class="comment">set form data. This functionality is not available in Python
+</span><span class="comment-delimiter"># </span><span class="comment">cgi module.
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN1013"
+>Redirecting Error Messages</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">enable() from 'cgitb' module, by default, redirects traceback
+</span><span class="comment-delimiter"># </span><span class="comment">to the browser. It is defined as 'enable(display=True, logdir=None,
+</span><span class="comment-delimiter"># </span><span class="comment">context=5)'.
+</span>
+<span class="comment-delimiter"># </span><span class="comment">equivalent to importing CGI::Carp::fatalsToBrowser.
+</span><span class="keyword">import</span> cgitb
+cgitb.enable()
+
+<span class="comment-delimiter"># </span><span class="comment">to suppress browser output, you should explicitly say so.
+</span><span class="keyword">import</span> cgitb
+cgitb.enable(display=<span class="py-pseudo-keyword">False</span>)
+
+<span class="comment-delimiter"># </span><span class="comment">equivalent to call CGI::Carp::carpout with temporary files.
+</span><span class="keyword">import</span> cgitb
+cgitb.enable(logdir=<span class="string">"/var/local/cgi-logs/"</span>)
+
+<span class="comment-delimiter"># </span><span class="comment">Python exception, traceback facilities are much richer than PERL's
+</span><span class="comment-delimiter"># </span><span class="comment">die and its friends. You can use your custom exception formatter
+</span><span class="comment-delimiter"># </span><span class="comment">by replacing sys.excepthook. (equivalent to CGI::Carp::set_message.)
+</span><span class="comment-delimiter"># </span><span class="comment">Default formatter is available as traceback.print_exc() in pure
+</span><span class="comment-delimiter"># </span><span class="comment">Python. In fact, what cgitb.enable() does is replacing excepthook
+</span><span class="comment-delimiter"># </span><span class="comment">to cgitb.handler(), which knows how to format exceptions to HTML.
+</span>
+<span class="comment-delimiter"># </span><span class="comment">If this is not enough, (usually this is enough!) Python 2.3 comes
+</span><span class="comment-delimiter"># </span><span class="comment">with a new standard module called 'logging', which is complex, but
+</span><span class="comment-delimiter"># </span><span class="comment">very flexible and entirely customizable.
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN1016"
+>Fixing a 500 Server Error</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">
+</span><span class="comment-delimiter"># </span><span class="comment"><font size="-1"><a href="http://pleac.sourceforge.net/include/python/ch19/webwhoami">download the following standalone program</a></font>
+</span><span class="comment-delimiter">#</span><span class="comment">!/usr/bin/python
+</span><span class="comment-delimiter"># </span><span class="comment">webwhoami - show web users id
+</span><span class="keyword">import</span> getpass
+<span class="keyword">print</span> <span class="string">"Content-Type: text/plain\n"</span>
+<span class="keyword">print</span> <span class="string">"Running as %s\n"</span> % getpass.getuser()
+
+
+
+<span class="comment-delimiter"># </span><span class="comment">STDOUT/ERR flushing
+</span><span class="comment-delimiter">#</span><span class="comment">
+</span><span class="comment-delimiter"># </span><span class="comment">In contrast to what the perl cookbook says, modpython.org tells
+</span><span class="comment-delimiter"># </span><span class="comment">STDERR is buffered too.
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN1019"
+>Writing a Safe CGI Program</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN1022"
+>Making CGI Scripts Efficient</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span>
+<span class="comment-delimiter"># </span><span class="comment">use mod_python in the Apache web server.
+</span>
+<span class="comment-delimiter"># </span><span class="comment">Load the module in httpd.conf or apache.conf
+</span>
+LoadModule python_module libexec/mod_python.so
+
+&lt;Directory /some/directory/htdocs/test&gt;
+ AddHandler mod_python .py
+ PythonHandler mptest
+ PythonDebug On
+&lt;/Directory&gt;
+
+<span class="comment-delimiter"># </span><span class="comment">test.py file in /some/directory/htdocs/test
+</span><span class="keyword">from</span> mod_python <span class="keyword">import</span> apache
+
+<span class="keyword">def</span> <span class="function-name">handler</span>(req):
+ req.write(<span class="string">"Hello World!"</span>)
+ <span class="keyword">return</span> apache.OK</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN1025"
+>Executing Commands Without Shell Escapes</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span>
+<span class="keyword">import</span> os
+os.system(<span class="string">"command %s %s"</span> % (input, <span class="string">" "</span>.join(files))) <span class="comment-delimiter"># </span><span class="comment">UNSAFE
+</span>
+<span class="comment-delimiter"># </span><span class="comment">python doc lib cgi-security it says
+</span><span class="comment-delimiter">#</span><span class="comment">
+</span><span class="comment-delimiter"># </span><span class="comment">To be on the safe side, if you must pass a string gotten from a form to a shell
+</span><span class="comment-delimiter"># </span><span class="comment">command, you should make sure the string contains only alphanumeric characters, dashes,
+</span><span class="comment-delimiter"># </span><span class="comment">underscores, and periods.
+</span><span class="keyword">import</span> re
+cmd = <span class="string">"command %s %s"</span> % (input, <span class="string">" "</span>.join(files))
+<span class="keyword">if</span> re.search(r<span class="string">"[^a-zA-Z0-9._\-]"</span>, cmd):
+ <span class="keyword">print</span> <span class="string">"rejected"</span>
+ sys.exit(1)
+os.system(cmd)
+trans = string.maketrans(string.ascii_letters+string.digits+<span class="string">"-_."</span>,
+
+<span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN1028"
+>Formatting Lists and Tables with HTML Shortcuts</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">This uses nevow's (http://nevow.com) stan; there's no standard
+</span><span class="comment-delimiter"># </span><span class="comment">way to generate HTML, though there are many implementations of
+</span><span class="comment-delimiter"># </span><span class="comment">this basic idea.
+</span><span class="keyword">from</span> nevow <span class="keyword">import</span> tags <span class="keyword">as</span> T
+<span class="keyword">print</span> T.ol[T.li[<span class="string">'red'</span>], T.li[<span class="string">'blue'</span>], T.li[<span class="string">'green'</span>]]
+<span class="comment-delimiter"># </span><span class="comment">&lt;ol&gt;&lt;li&gt;red&lt;/li&gt;&lt;li&gt;blue&lt;/li&gt;&lt;li&gt;green&lt;/li&gt;&lt;/ol&gt;
+</span>
+names = <span class="string">'Larry Moe Curly'</span>.split()
+<span class="keyword">print</span> T.ul[ [T.li(type=<span class="string">"disc"</span>)[name] <span class="keyword">for</span> name <span class="keyword">in</span> names] ]
+<span class="comment-delimiter"># </span><span class="comment">&lt;ul&gt;&lt;li type="disc"&gt;Larry&lt;/li&gt;&lt;li type="disc"&gt;Moe&lt;/li&gt;
+</span><span class="comment-delimiter"># </span><span class="comment">&lt;li type="disc"&gt;Curly&lt;/li&gt;&lt;/ul&gt;
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">print</span> T.li[<span class="string">"alpha"</span>]
+<span class="comment-delimiter"># </span><span class="comment">&lt;li&gt;alpha&lt;/li&gt;
+</span>
+<span class="keyword">print</span> T.li[<span class="string">'alpha'</span>], T.li[<span class="string">'omega'</span>]
+<span class="comment-delimiter"># </span><span class="comment">&lt;li&gt;alpha&lt;/li&gt; &lt;li&gt;omega&lt;/li&gt;
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>states = {
+ <span class="string">"Wisconsin"</span>: [ <span class="string">"Superior"</span>, <span class="string">"Lake Geneva"</span>, <span class="string">"Madison"</span> ],
+ <span class="string">"Colorado"</span>: [ <span class="string">"Denver"</span>, <span class="string">"Fort Collins"</span>, <span class="string">"Boulder"</span> ],
+ <span class="string">"Texas"</span>: [ <span class="string">"Plano"</span>, <span class="string">"Austin"</span>, <span class="string">"Fort Stockton"</span> ],
+ <span class="string">"California"</span>: [ <span class="string">"Sebastopol"</span>, <span class="string">"Santa Rosa"</span>, <span class="string">"Berkeley"</span> ],
+}
+
+<span class="keyword">print</span> <span class="string">"&lt;TABLE&gt; &lt;CAPTION&gt;Cities I Have Known&lt;/CAPTION&gt;"</span>;
+<span class="keyword">print</span> T.tr[T.th(<span class="string">'State'</span>), T.th(<span class="string">'Cities'</span>)]
+<span class="keyword">for</span> k <span class="keyword">in</span> sorted(states.keys()):
+ <span class="keyword">print</span> T.tr[ [T.th(k)] + [T.td(city) <span class="keyword">for</span> city <span class="keyword">in</span> sorted(states[k])] ]
+<span class="keyword">print</span> <span class="string">"&lt;/TABLE&gt;"</span>;
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">&lt;TABLE&gt; &lt;CAPTION&gt;Cities I Have Known&lt;/CAPTION&gt;
+</span><span class="comment-delimiter">#</span><span class="comment">
+</span><span class="comment-delimiter"># </span><span class="comment">&lt;TR&gt;&lt;TH&gt;State&lt;/TH&gt; &lt;TH&gt;Cities&lt;/TH&gt;&lt;/TR&gt;
+</span><span class="comment-delimiter">#</span><span class="comment">
+</span><span class="comment-delimiter"># </span><span class="comment">&lt;TR&gt;&lt;TH&gt;California&lt;/TH&gt; &lt;TD&gt;Berkeley&lt;/TD&gt; &lt;TD&gt;Santa Rosa&lt;/TD&gt;
+</span><span class="comment-delimiter">#</span><span class="comment">
+</span><span class="comment-delimiter"># </span><span class="comment">&lt;TD&gt;Sebastopol&lt;/TD&gt; &lt;/TR&gt;
+</span><span class="comment-delimiter">#</span><span class="comment">
+</span><span class="comment-delimiter"># </span><span class="comment">&lt;TR&gt;&lt;TH&gt;Colorado&lt;/TH&gt; &lt;TD&gt;Boulder&lt;/TD&gt; &lt;TD&gt;Denver&lt;/TD&gt;
+</span><span class="comment-delimiter">#</span><span class="comment">
+</span><span class="comment-delimiter"># </span><span class="comment">&lt;TD&gt;Fort Collins&lt;/TD&gt; &lt;/TR&gt;
+</span><span class="comment-delimiter">#</span><span class="comment">
+</span><span class="comment-delimiter"># </span><span class="comment">&lt;TR&gt;&lt;TH&gt;Texas&lt;/TH&gt; &lt;TD&gt;Austin&lt;/TD&gt; &lt;TD&gt;Fort Stockton&lt;/TD&gt;
+</span><span class="comment-delimiter">#</span><span class="comment">
+</span><span class="comment-delimiter"># </span><span class="comment">&lt;TD&gt;Plano&lt;/TD&gt;&lt;/TR&gt;
+</span><span class="comment-delimiter">#</span><span class="comment">
+</span><span class="comment-delimiter"># </span><span class="comment">&lt;TR&gt;&lt;TH&gt;Wisconsin&lt;/TH&gt; &lt;TD&gt;Lake Geneva&lt;/TD&gt; &lt;TD&gt;Madison&lt;/TD&gt;
+</span><span class="comment-delimiter">#</span><span class="comment">
+</span><span class="comment-delimiter"># </span><span class="comment">&lt;TD&gt;Superior&lt;/TD&gt;&lt;/TR&gt;
+</span><span class="comment-delimiter">#</span><span class="comment">
+</span><span class="comment-delimiter"># </span><span class="comment">&lt;/TABLE&gt;
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">print</span> T.table[
+ [T.caption[<span class="string">'Cities I have Known'</span>],
+ T.tr[T.th[<span class="string">'State'</span>], T.th[<span class="string">'Cities'</span>]] ] +
+ [T.tr[ [T.th(k)] + [T.td(city) <span class="keyword">for</span> city <span class="keyword">in</span> sorted(states[k])]]
+ <span class="keyword">for</span> k <span class="keyword">in</span> sorted(states.keys())]]
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">salcheck - check for salaries
+</span><span class="keyword">import</span> MySQLdb
+<span class="keyword">import</span> cgi
+
+form = cgi.FieldStorage()
+
+<span class="keyword">if</span> <span class="string">'limit'</span> <span class="keyword">in</span> form:
+ limit = <span class="py-builtins">int</span>(form[<span class="string">'limit'</span>].value)
+<span class="keyword">else:</span>
+ limit = <span class="string">''</span>
+
+<span class="comment-delimiter"># </span><span class="comment">There's not a good way to start an HTML/XML construct with stan
+</span><span class="comment-delimiter"># </span><span class="comment">without completing it.
+</span><span class="keyword">print</span> <span class="string">'&lt;html&gt;&lt;head&gt;&lt;title&gt;Salary Query&lt;/title&gt;&lt;/head&gt;&lt;body&gt;'</span>
+<span class="keyword">print</span> T.h1[<span class="string">'Search'</span>]
+<span class="keyword">print</span> <span class="string">'&lt;form&gt;'</span>
+<span class="keyword">print</span> T.p[<span class="string">'Enter minimum salary'</span>,
+ T.input(type=<span class="string">"text"</span>, name=<span class="string">"limit"</span>, value=limit)]
+<span class="keyword">print</span> T.input(type=<span class="string">"submit"</span>)
+<span class="keyword">print</span> <span class="string">'&lt;/form&gt;'</span>
+
+<span class="keyword">if</span> limit:
+ dbconn = MySQLdb.connect(db=<span class="string">'somedb'</span>, host=<span class="string">'server.host.dom'</span>,
+ port=3306, user=<span class="string">'username'</span>,
+ passwd=<span class="string">'password'</span>)
+ cursor = dbconn.cursor()
+ cursor.execute(<span class="string">"""
+ SELECT name, salary FROM employees
+ WHERE salary &gt; %s"""</span>, (limit,))
+
+ <span class="keyword">print</span> T.h1[<span class="string">"Results"</span>]
+ <span class="keyword">print</span> <span class="string">"&lt;TABLE BORDER=1&gt;"</span>
+
+ <span class="keyword">for</span> row <span class="keyword">in</span> cursor.fetchall():
+ <span class="keyword">print</span> T.tr[ [T.td(cell) <span class="keyword">for</span> cell <span class="keyword">in</span> row] ]
+
+ <span class="keyword">print</span> <span class="string">"&lt;/TABLE&gt;\n"</span>;
+ cursor.close()
+ dbconn.close()
+
+<span class="keyword">print</span> <span class="string">'&lt;/body&gt;&lt;/html&gt;'</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN1031"
+>Redirecting to a Different Location</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>url = <span class="string">"http://python.org/pypi"</span>
+<span class="keyword">print</span> <span class="string">"Location: %s\n"</span> % url
+<span class="keyword">raise</span> <span class="py-builtins">SystemExit</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">oreobounce - set a cookie and redirect the browser
+</span><span class="keyword">import</span> Cookie
+<span class="keyword">import</span> time
+
+c = Cookie.SimpleCookie()
+c[<span class="string">'filling'</span>] = <span class="string">'vanilla cr?me'</span>
+now = time.time()
+future = now + 3*(60*60*24*30) <span class="comment-delimiter"># </span><span class="comment">3 months
+</span>expire_date = time.strftime(<span class="string">'%a %d %b %Y %H:%M:%S GMT'</span>, future)
+c[<span class="string">'filling'</span>][<span class="string">'expires'</span>] = expire_date
+c[<span class="string">'filling'</span>][<span class="string">'domain'</span>] = <span class="string">'.python.org'</span>
+
+whither = <span class="string">"http://somewhere.python.org/nonesuch.html"</span>
+
+<span class="comment-delimiter"># </span><span class="comment">Prints the cookie header
+</span><span class="keyword">print</span> <span class="string">'Status: 302 Moved Temporarily'</span>
+<span class="keyword">print</span> c
+<span class="keyword">print</span> <span class="string">'Location:'</span>, whither
+<span class="keyword">print</span>
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment">Status: 302 Moved Temporarily
+</span><span class="comment-delimiter">#</span><span class="comment">Set-Cookie: filling=vanilla%20cr%E4me; domain=.perl.com;
+</span><span class="comment-delimiter"># </span><span class="comment">expires=Tue, 21-Jul-1998 11:58:55 GMT
+</span><span class="comment-delimiter">#</span><span class="comment">Location: http://somewhere.perl.com/nonesuch.html
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">os_snipe - redirect to a Jargon File entry about current OS
+</span><span class="keyword">import</span> os, re
+<span class="py-builtins">dir</span> = <span class="string">'http://www.wins.uva.nl/%7Emes/jargon'</span>
+matches = [
+ (r<span class="string">'Mac'</span>, <span class="string">'m/Macintrash.html'</span>),
+ (r<span class="string">'Win(dows )?NT'</span>, <span class="string">'e/evilandrude.html'</span>),
+ (r<span class="string">'Win|MSIE|WebTV'</span>, <span class="string">'m/MicroslothWindows.html'</span>),
+ (r<span class="string">'Linux'</span>, <span class="string">'l/Linux.html'</span>),
+ (r<span class="string">'HP-UX'</span>, <span class="string">'h/HP-SUX.html'</span>),
+ (r<span class="string">'SunOS'</span>, <span class="string">'s/ScumOS.html'</span>),
+ (<span class="py-pseudo-keyword">None</span>, <span class="string">'a/AppendixB.html'</span>),
+ ]
+
+<span class="keyword">for</span> regex, page <span class="keyword">in</span> matches:
+ <span class="keyword">if</span> <span class="keyword">not</span> regex: <span class="comment-delimiter"># </span><span class="comment">default
+</span> <span class="keyword">break</span>
+ <span class="keyword">if</span> re.search(regex, os.environ[<span class="string">'HTTP_USER_AGENT'</span>]):
+ <span class="keyword">break</span>
+<span class="keyword">print</span> <span class="string">'Location: %s/%s\n'</span> % (dir, page)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">There's no special way to print headers
+</span><span class="keyword">print</span> <span class="string">'Status: 204 No response'</span>
+<span class="keyword">print</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment">Status: 204 No response
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN1034"
+>Debugging the Raw HTTP Exchange</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment"><font size="-1"><a href="http://pleac.sourceforge.net/include/python/ch19/dummyhttpd">download the following standalone program</a></font>
+</span><span class="comment-delimiter">#</span><span class="comment">!/usr/bin/python
+</span><span class="comment-delimiter"># </span><span class="comment">dummyhttpd - start a HTTP daemon and print what the client sends
+</span>
+<span class="keyword">import</span> SocketServer
+<span class="comment-delimiter"># </span><span class="comment">or use BaseHTTPServer, SimpleHTTPServer, CGIHTTPServer
+</span>
+<span class="keyword">def</span> <span class="function-name">adr_str</span>(adr):
+ <span class="keyword">return</span> <span class="string">"%s:%d"</span> % adr
+
+<span class="keyword">class</span> <span class="type">RequestHandler</span>(SocketServer.BaseRequestHandler):
+ <span class="keyword">def</span> <span class="function-name">handle</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="keyword">print</span> <span class="string">"client access from %s"</span> % adr_str(<span class="py-pseudo-keyword">self</span>.client_address)
+ <span class="keyword">print</span> <span class="py-pseudo-keyword">self</span>.request.recv(10000)
+ <span class="py-pseudo-keyword">self</span>.request.send(<span class="string">"Content-Type: text/plain\n"</span>
+ <span class="string">"Server: dymmyhttpd/1.0.0\n"</span>
+ <span class="string">"\n...\n"</span>)
+ <span class="py-pseudo-keyword">self</span>.request.close()
+
+
+adr = (<span class="string">'127.0.0.1'</span>, 8001)
+<span class="keyword">print</span> <span class="string">"Please contact me at &lt;<a href="http://%s">http://%s</a>&gt;"</span> % adr_str(adr)
+server = SocketServer.TCPServer(adr, RequestHandler)
+server.serve_forever()
+server.server_close()</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN1037"
+>Managing Cookies</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span>
+<span class="keyword">import</span> Cookie
+cookies = Cookie.SimpleCookie()
+<span class="comment-delimiter"># </span><span class="comment">SimpleCookie is more secure, but does not support all characters.
+</span>cookies[<span class="string">"preference-name"</span>] = <span class="string">"whatever you'd like"</span>
+<span class="keyword">print</span> cookies
+
+<span class="comment-delimiter"># </span><span class="comment"><font size="-1"><a href="http://pleac.sourceforge.net/include/python/ch19/ic_cookies">download the following standalone program</a></font>
+</span><span class="comment-delimiter">#</span><span class="comment">!/usr/bin/python
+</span><span class="comment-delimiter"># </span><span class="comment">ic_cookies - sample CGI script that uses a cookie
+</span>
+<span class="keyword">import</span> cgi
+<span class="keyword">import</span> os
+<span class="keyword">import</span> Cookie
+<span class="keyword">import</span> datetime
+
+cookname = <span class="string">"favorite-ice-cream"</span> <span class="comment-delimiter"># </span><span class="comment">SimpleCookie does not support blanks
+</span>fieldname = <span class="string">"flavor"</span>
+
+cookies = Cookie.SimpleCookie(os.environ.get(<span class="string">"HTTP_COOKIE"</span>,<span class="string">""</span>))
+<span class="keyword">if</span> cookies.has_key(cookname):
+ favorite = cookies[cookname].value
+<span class="keyword">else:</span>
+ favorite = <span class="string">"mint"</span>
+
+form = cgi.FieldStorage()
+<span class="keyword">if</span> <span class="keyword">not</span> form.has_key(fieldname):
+ <span class="keyword">print</span> <span class="string">"Content-Type: text/html"</span>
+ <span class="keyword">print</span> <span class="string">"\n"</span>
+ <span class="keyword">print</span> <span class="string">"&lt;html&gt;&lt;body&gt;"</span>
+ <span class="keyword">print</span> <span class="string">"&lt;h1&gt;Hello Ice Cream&lt;/h1&gt;"</span>
+ <span class="keyword">print</span> <span class="string">"&lt;form&gt;"</span>
+ <span class="keyword">print</span> <span class="string">'Please select a flavor: &lt;input type="text" name="%s" value="%s" /&gt;'</span> % (
+ fieldname, favorite )
+ <span class="keyword">print</span> <span class="string">"&lt;/form&gt;"</span>
+ <span class="keyword">print</span> <span class="string">"&lt;hr /&gt;"</span>
+ <span class="keyword">print</span> <span class="string">"&lt;/body&gt;&lt;/html&gt;"</span>
+<span class="keyword">else:</span>
+ favorite = form[fieldname].value
+ cookies[cookname] = favorite
+ expire = datetime.datetime.now() + datetime.timedelta(730)
+ cookies[cookname][<span class="string">"expires"</span>] = expire.strftime(<span class="string">"%a, %d %b %Y %H:00:00 GMT"</span>)
+ cookies[cookname][<span class="string">"path"</span>] = <span class="string">"/"</span>
+ <span class="keyword">print</span> <span class="string">"Content-Type: text/html"</span>
+ <span class="keyword">print</span> cookies
+ <span class="keyword">print</span> <span class="string">"\n"</span>
+ <span class="keyword">print</span> <span class="string">"&lt;html&gt;&lt;body&gt;"</span>
+ <span class="keyword">print</span> <span class="string">"&lt;h1&gt;Hello Ice Cream&lt;/h1&gt;"</span>
+ <span class="keyword">print</span> <span class="string">"&lt;p&gt;You chose as your favorite flavor \"%s\"&lt;/p&gt;"</span> % favorite
+ <span class="keyword">print</span> <span class="string">"&lt;/body&gt;&lt;/html&gt;"</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN1040"
+>Creating Sticky Widgets</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN1043"
+>Writing a Multiscreen CGI Script</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN1046"
+>Saving a Form to a File or Mail Pipe</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">first open and exclusively lock the file
+</span><span class="keyword">import</span> os, cgi, fcntl, cPickle
+fh = <span class="py-builtins">open</span>(<span class="string">'/tmp/formlog'</span>, <span class="string">'ab'</span>)
+fcntl.flock(fh.fileno(), fcntl.LOCK_EX)
+
+form = cgi.FieldStorage()
+<span class="comment-delimiter"># </span><span class="comment">This doesn't produce a readable file; we copy the environment so
+</span><span class="comment-delimiter"># </span><span class="comment">that we save a plain dictionary (os.environ is a dictionary-like
+</span><span class="comment-delimiter"># </span><span class="comment">object).
+</span>cPickle.dump((form, os.environ.copy()) fh)
+fh.close()
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> cgi, smtplib, sys
+
+form = cgi.FieldStorage()
+email = <span class="string">"""\
+From: %S
+To: hisname@hishost.com
+Subject: mailed form submission
+
+"""</span> % sys.argv[0]
+
+<span class="keyword">for</span> key <span class="keyword">in</span> form:
+ values = form[key]
+ <span class="keyword">if</span> <span class="keyword">not</span> <span class="py-builtins">isinstance</span>(values, list):
+ value = [values.value]
+ <span class="keyword">else:</span>
+ value = [v.value <span class="keyword">for</span> v <span class="keyword">in</span> values]
+ <span class="keyword">for</span> item <span class="keyword">in</span> values:
+ email += <span class="string">'\n%s: %s'</span> % (key, value)
+
+server = smtplib.SMTP(<span class="string">'localhost'</span>)
+server.sendmail(sys.argv[0], [<span class="string">'hisname@hishost.com'</span>], email)
+server.quit()
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@ I don't get the point of these:
+</span><span class="comment-delimiter"># </span><span class="comment">param("_timestamp", scalar localtime);
+</span><span class="comment-delimiter"># </span><span class="comment">param("_environs", %ENV);
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> fcntl, cPickle
+fh = <span class="py-builtins">open</span>(<span class="string">'/tmp/formlog'</span>, <span class="string">'rb'</span>)
+fcntl.flock(fh.fileno(), fcntl.LOCK_SH)
+
+count = 0
+<span class="keyword">while</span> <span class="py-pseudo-keyword">True</span>:
+ <span class="keyword">try:</span>
+ form, environ = cPickle.load(fh)
+ <span class="keyword">except</span> <span class="py-builtins">EOFError</span>:
+ <span class="keyword">break</span>
+ <span class="keyword">if</span> environ.get(<span class="string">'REMOTE_HOST'</span>).endswith(<span class="string">'perl.com'</span>):
+ <span class="keyword">continue</span>
+ <span class="keyword">if</span> <span class="string">'items requested'</span> <span class="keyword">in</span> form:
+ count += <span class="py-builtins">int</span>(form[<span class="string">'items requested'</span>].value)
+<span class="keyword">print</span> <span class="string">'Total orders:'</span>, count
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN1049"
+>Program: chemiserie</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+></DIV
+><DIV
+CLASS="NAVFOOTER"
+><HR
+ALIGN="LEFT"
+WIDTH="100%"><TABLE
+SUMMARY="Footer navigation table"
+WIDTH="100%"
+BORDER="0"
+CELLPADDING="0"
+CELLSPACING="0"
+><TR
+><TD
+WIDTH="33%"
+ALIGN="left"
+VALIGN="top"
+><A
+HREF="internetservices.html"
+ACCESSKEY="P"
+>Prev</A
+></TD
+><TD
+WIDTH="34%"
+ALIGN="center"
+VALIGN="top"
+><A
+HREF="index.html"
+ACCESSKEY="H"
+>Home</A
+></TD
+><TD
+WIDTH="33%"
+ALIGN="right"
+VALIGN="top"
+><A
+HREF="webautomation.html"
+ACCESSKEY="N"
+>Next</A
+></TD
+></TR
+><TR
+><TD
+WIDTH="33%"
+ALIGN="left"
+VALIGN="top"
+>Internet Services</TD
+><TD
+WIDTH="34%"
+ALIGN="center"
+VALIGN="top"
+>&nbsp;</TD
+><TD
+WIDTH="33%"
+ALIGN="right"
+VALIGN="top"
+>Web Automation</TD
+></TR
+></TABLE
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/help/PythonExamples/pleac_python/classesetc.html b/help/PythonExamples/pleac_python/classesetc.html
new file mode 100644
index 0000000..7e81ee7
--- /dev/null
+++ b/help/PythonExamples/pleac_python/classesetc.html
@@ -0,0 +1,1423 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML
+><HEAD
+><TITLE
+>Classes, Objects, and Ties</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
+REL="HOME"
+TITLE="PLEAC-Python
+"
+HREF="index.html"><LINK
+REL="PREVIOUS"
+TITLE="Packages, Libraries, and Modules"
+HREF="packagesetc.html"><LINK
+REL="NEXT"
+TITLE="Database Access"
+HREF="dbaccess.html"><style type="text/css"> <!--
+ .comment {
+ /* font-lock-comment-face */
+ color: #bebebe;
+ }
+ .comment-delimiter {
+ }
+ .function-name {
+ /* font-lock-function-name-face */
+ color: #b2dfee;
+ }
+ .keyword {
+ /* font-lock-keyword-face */
+ color: #ffa500;
+ }
+ .py-builtins {
+ /* py-builtins-face */
+ color: #ffa500;
+ }
+ .py-pseudo-keyword {
+ /* py-pseudo-keyword-face */
+ color: #ffa500;
+ }
+ .string {
+ /* font-lock-string-face */
+ color: #00cd00;
+ }
+ .type {
+ /* font-lock-type-face */
+ color: #98fb98;
+ }
+ -->
+ </style></head
+><BODY TEXT="#cecece" BGCOLOR="#4f6f6f" LINK="#f5deb3" VLINK="#d5ae83"
+CLASS="SECT1"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><DIV
+CLASS="NAVHEADER"
+><TABLE
+SUMMARY="Header navigation table"
+WIDTH="100%"
+BORDER="0"
+CELLPADDING="0"
+CELLSPACING="0"
+><TR
+><TH
+COLSPAN="3"
+ALIGN="center"
+>PLEAC-Python
+</TH
+></TR
+><TR
+><TD
+WIDTH="10%"
+ALIGN="left"
+VALIGN="bottom"
+><A
+HREF="packagesetc.html"
+ACCESSKEY="P"
+>Prev</A
+></TD
+><TD
+WIDTH="80%"
+ALIGN="center"
+VALIGN="bottom"
+></TD
+><TD
+WIDTH="10%"
+ALIGN="right"
+VALIGN="bottom"
+><A
+HREF="dbaccess.html"
+ACCESSKEY="N"
+>Next</A
+></TD
+></TR
+></TABLE
+><HR
+ALIGN="LEFT"
+WIDTH="100%"></DIV
+><DIV
+CLASS="SECT1"
+><H1
+CLASS="SECT1"
+><A
+NAME="CLASSESETC"
+>13. Classes, Objects, and Ties</A
+></H1
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN704"
+>Introduction</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Inside a module named 'Data' / file named 'Data.py'
+</span><span class="keyword">class</span> <span class="type">Encoder</span>(object):
+ <span class="keyword">pass</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>obj = [3, 5]
+<span class="keyword">print</span> <span class="py-builtins">type</span>(obj), <span class="py-builtins">id</span>(obj), ob[1]
+
+<span class="comment-delimiter">#</span><span class="comment"># Changing the class of builtin types is not supported
+</span><span class="comment-delimiter">#</span><span class="comment"># in Python.
+</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>obj.Stomach = <span class="string">"Empty"</span> <span class="comment-delimiter"># </span><span class="comment">directly accessing an object's contents
+</span>obj.NAME = <span class="string">"Thag"</span> <span class="comment-delimiter"># </span><span class="comment">uppercase field name to make it stand out
+</span>(optional)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>encoded = object.encode(<span class="string">"data"</span>)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>encoded = Data.Encoder.encode(<span class="string">"data"</span>)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">class</span> <span class="type">Class</span>(object):
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="keyword">pass</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="py-builtins">object</span> = Class()
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">class</span> <span class="type">Class</span>(object):
+ <span class="keyword">def</span> <span class="function-name">class_only_method</span>():
+ <span class="keyword">pass</span> <span class="comment-delimiter"># </span><span class="comment">more code here
+</span> class_only_method = <span class="py-builtins">staticmethod</span>(class_only_method)
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">class</span> <span class="type">Class</span>(object):
+ <span class="keyword">def</span> <span class="function-name">instance_only_method</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="keyword">pass</span> <span class="comment-delimiter"># </span><span class="comment">more code here
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>lector = Human.Cannibal()
+lector.feed(<span class="string">"Zak"</span>)
+lector.move(<span class="string">"New York"</span>)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">NOTE: it is rare to use these forms except inside of
+</span><span class="comment-delimiter"># </span><span class="comment">methods to call specific methods from a parent class
+</span>lector = Human.Cannibal()
+Human.Cannibal.feed(lector, <span class="string">"Zak"</span>)
+Human.Cannibal.move(lector, <span class="string">"New York"</span>)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>print&gt;&gt;sys.stderr, <span class="string">"stuff here\n"</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN707"
+>Constructing an Object</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">class</span> <span class="type">Class</span>(object):
+ <span class="keyword">pass</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> time
+<span class="keyword">class</span> <span class="type">Class</span>(object):
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="py-pseudo-keyword">self</span>.start = time.time() <span class="comment-delimiter"># </span><span class="comment">init data fields
+</span> <span class="py-pseudo-keyword">self</span>.age = 0
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> time
+<span class="keyword">class</span> <span class="type">Class</span>(object):
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>, **kwargs):
+ <span class="comment-delimiter"># </span><span class="comment">Sets self.start to the current time, and self.age to 0. If called
+</span> <span class="comment-delimiter"># </span><span class="comment">with arguments, interpret them as key+value pairs to
+</span> <span class="comment-delimiter"># </span><span class="comment">initialize the object with
+</span> <span class="py-pseudo-keyword">self</span>.age = 0
+ <span class="py-pseudo-keyword">self</span>.__dict__.update(kwargs)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN710"
+>Destroying an Object</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> time
+<span class="keyword">class</span> <span class="type">Class</span>(object):
+ <span class="keyword">def</span> <span class="function-name">__del__</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="keyword">print</span> <span class="py-pseudo-keyword">self</span>, <span class="string">"dying at"</span>, time.ctime()
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment"># Why is the perl code introducing a cycle? I guess it's an
+</span><span class="comment-delimiter">#</span><span class="comment"># example of how to keep from calling the finalizer
+</span><span class="py-pseudo-keyword">self</span>.WHATEVER = <span class="py-pseudo-keyword">self</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN713"
+>Managing Instance Data</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">It is standard practice to access attributes directly:
+</span><span class="keyword">class</span> <span class="type">MyClass</span>(object)
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="py-pseudo-keyword">self</span>.name = <span class="string">"default"</span>
+ <span class="py-pseudo-keyword">self</span>.age = 0
+obj = MyClass()
+obj.name = <span class="string">"bob"</span>
+<span class="keyword">print</span> obj.name
+obj.age += 1
+
+<span class="comment-delimiter"># </span><span class="comment">If you later find that you need to compute an attribute, you can always
+</span><span class="comment-delimiter"># </span><span class="comment">retrofit a property(), leaving user code untouched:
+</span><span class="keyword">class</span> <span class="type">MyClass</span>(object):
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="py-pseudo-keyword">self</span>._name = <span class="string">"default"</span>
+ <span class="py-pseudo-keyword">self</span>._age = 0
+
+ <span class="keyword">def</span> <span class="function-name">get_name</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="keyword">return</span> <span class="py-pseudo-keyword">self</span>._name
+ <span class="keyword">def</span> <span class="function-name">set_name</span>(<span class="py-pseudo-keyword">self</span>, name):
+ <span class="py-pseudo-keyword">self</span>._name = name.title()
+ name = <span class="py-builtins">property</span>(get_name, set_name)
+
+ <span class="keyword">def</span> <span class="function-name">get_age</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="keyword">return</span> <span class="py-pseudo-keyword">self</span>._age
+ <span class="keyword">def</span> <span class="function-name">set_age</span>(<span class="py-pseudo-keyword">self</span>, val):
+ <span class="keyword">if</span> val &lt; 0:
+ <span class="keyword">raise</span> <span class="py-builtins">ValueError</span>(<span class="string">"Invalid age: %s"</span> % val)
+ <span class="py-pseudo-keyword">self</span>._age = val
+ age = <span class="py-builtins">property</span>(get_age, set_age)
+obj = MyClass()
+obj.name = <span class="string">"bob"</span>
+<span class="keyword">print</span> obj.name
+obj.age += 1
+
+<span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS - explicit getters and setters should not be used:
+</span><span class="keyword">class</span> <span class="type">MyClass</span>(object):
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="py-pseudo-keyword">self</span>.name = <span class="string">"default"</span>
+ <span class="keyword">def</span> <span class="function-name">get_name</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="keyword">return</span> <span class="py-pseudo-keyword">self</span>.name
+ <span class="keyword">def</span> <span class="function-name">set_name</span>(<span class="py-pseudo-keyword">self</span>, name):
+ <span class="py-pseudo-keyword">self</span>.name = name.title()
+obj = MyClass()
+obj.set_name(<span class="string">"bob"</span>)
+<span class="keyword">print</span> obj.get_name()
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment"># DON'T DO THIS (It's complex, ugly, and unnecessary):
+</span><span class="keyword">class</span> <span class="type">MyClass</span>(object):
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="py-pseudo-keyword">self</span>.age = 0
+ <span class="keyword">def</span> <span class="function-name">name</span>(<span class="py-pseudo-keyword">self</span>, *args):
+ <span class="keyword">if</span> <span class="py-builtins">len</span>(args) == 0:
+ <span class="keyword">return</span> <span class="py-pseudo-keyword">self</span>.name
+ <span class="keyword">elif</span> <span class="py-builtins">len</span>(args) == 1:
+ <span class="py-pseudo-keyword">self</span>.name = args[0]
+ <span class="keyword">else:</span>
+ <span class="keyword">raise</span> <span class="py-builtins">TypeError</span>(<span class="string">"name only takes 0 or 1 arguments"</span>)
+ <span class="keyword">def</span> <span class="function-name">age</span>(<span class="py-pseudo-keyword">self</span>, *args):
+ prev = <span class="py-pseudo-keyword">self</span>.age
+ <span class="keyword">if</span> args:
+ <span class="py-pseudo-keyword">self</span>.age = args[0]
+ <span class="keyword">return</span> prev
+
+<span class="comment-delimiter"># </span><span class="comment">sample call of get and set: happy birthday!
+</span>obj.age(1 + obj.age())
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>him = Person()
+him.NAME = <span class="string">"Sylvester"</span>
+him.AGE = 23
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Here's another way to implement the 'obj.method()' is a getter
+</span><span class="comment-delimiter"># </span><span class="comment">and 'obj.method(value)' is a settor. Again, this is not a
+</span><span class="comment-delimiter"># </span><span class="comment">common Python idiom and should not be used. See below for a
+</span><span class="comment-delimiter"># </span><span class="comment">more common way to do parameter checking of attribute assignment.
+</span>
+<span class="keyword">import</span> re, sys
+
+<span class="keyword">def</span> <span class="function-name">carp</span>(s):
+ sys.stderr.write(<span class="string">"WARNING: "</span> + s + <span class="string">"\n"</span>)
+
+<span class="keyword">class</span> <span class="type">Class</span>:
+ no_name = []
+
+ <span class="keyword">def</span> <span class="function-name">name</span>(<span class="py-pseudo-keyword">self</span>, value = no_name):
+ <span class="keyword">if</span> value <span class="keyword">is</span> Class.no_name:
+ <span class="keyword">return</span> <span class="py-pseudo-keyword">self</span>.NAME
+ value = <span class="py-pseudo-keyword">self</span>._enforce_name_value(value)
+ <span class="py-pseudo-keyword">self</span>.NAME = value
+
+ <span class="keyword">def</span> <span class="function-name">_enforce_name_value</span>(<span class="py-pseudo-keyword">self</span>, value):
+ <span class="keyword">if</span> re.search(r<span class="string">"[^\s\w'-]"</span>, value):
+ carp(<span class="string">"funny characters in name"</span>)
+ <span class="keyword">if</span> re.search(r<span class="string">"\d"</span>, value):
+ carp(<span class="string">"numbers in name"</span>)
+ <span class="keyword">if</span> <span class="keyword">not</span> re.search(r<span class="string">"\S+(\s+\S+)+"</span>, value):
+ carp(<span class="string">"prefer multiword name"</span>)
+ <span class="keyword">if</span> <span class="keyword">not</span> re.search(r<span class="string">"\S"</span>, value):
+ carp(<span class="string">"name is blank"</span>)
+ <span class="keyword">return</span> value.upper() <span class="comment-delimiter"># </span><span class="comment">enforce capitalization
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">A more typical way to enforce restrictions on a value
+</span><span class="comment-delimiter"># </span><span class="comment">to set
+</span><span class="keyword">class</span> <span class="type">Class</span>:
+ <span class="keyword">def</span> <span class="function-name">__setattr__</span>(<span class="py-pseudo-keyword">self</span>, name, value):
+ <span class="keyword">if</span> name == <span class="string">"name"</span>:
+ value = <span class="py-pseudo-keyword">self</span>._enforce_name_value(value) <span class="comment-delimiter"># </span><span class="comment">Do any conversions
+</span> <span class="py-pseudo-keyword">self</span>.__dict__[name] = value <span class="comment-delimiter"># </span><span class="comment">Do the default __setattr__ action
+</span>
+ <span class="keyword">def</span> <span class="function-name">_enforce_name_value</span>(<span class="py-pseudo-keyword">self</span>, value):
+ <span class="keyword">if</span> re.search(r<span class="string">"[^\s\w'-]"</span>, value):
+ carp(<span class="string">"funny characters in name"</span>)
+ <span class="keyword">if</span> re.search(r<span class="string">"\d"</span>, value):
+ carp(<span class="string">"numbers in name"</span>)
+ <span class="keyword">if</span> <span class="keyword">not</span> re.search(r<span class="string">"\S+(\s+\S+)+"</span>, value):
+ carp(<span class="string">"prefer multiword name"</span>)
+ <span class="keyword">if</span> <span class="keyword">not</span> re.search(r<span class="string">"\S"</span>, value):
+ carp(<span class="string">"name is blank"</span>)
+ <span class="keyword">return</span> value.upper() <span class="comment-delimiter"># </span><span class="comment">enforce capitalization
+</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">class</span> <span class="type">Person</span>:
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>, name = <span class="py-pseudo-keyword">None</span>, age = <span class="py-pseudo-keyword">None</span>, peers = <span class="py-pseudo-keyword">None</span>):
+ <span class="keyword">if</span> peers <span class="keyword">is</span> <span class="py-pseudo-keyword">None</span>: peers = [] <span class="comment-delimiter"># </span><span class="comment">See Python FAQ 6.25
+</span> <span class="py-pseudo-keyword">self</span>.name = name
+ <span class="py-pseudo-keyword">self</span>.age = age
+ <span class="py-pseudo-keyword">self</span>.peers = peers
+
+ <span class="keyword">def</span> <span class="function-name">exclaim</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="keyword">return</span> <span class="string">"Hi, I'm %s, age %d, working with %s"</span> % \
+ (<span class="py-pseudo-keyword">self</span>.name, <span class="py-pseudo-keyword">self</span>.age, <span class="string">", "</span>.join(<span class="py-pseudo-keyword">self</span>.peers))
+
+ <span class="keyword">def</span> <span class="function-name">happy_birthday</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="py-pseudo-keyword">self</span>.age += 1
+ <span class="keyword">return</span> <span class="py-pseudo-keyword">self</span>.age
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN716"
+>Managing Class Data</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment"># In the module named 'Person' ...
+</span><span class="keyword">def</span> <span class="function-name">population</span>():
+ <span class="keyword">return</span> Person.body_count[0]
+
+<span class="keyword">class</span> <span class="type">Person</span>(object):
+ body_count = [0] <span class="comment-delimiter"># </span><span class="comment">class variable - shared across all instances
+</span>
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="py-pseudo-keyword">self</span>.body_count[0] += 1
+
+ <span class="keyword">def</span> <span class="function-name">__del__</span>(<span class="py-pseudo-keyword">self</span>): <span class="comment-delimiter"># </span><span class="comment">Beware - may be non-deterministic (Jython)!
+</span> <span class="py-pseudo-keyword">self</span>.body_count[0] -= 1
+
+<span class="comment-delimiter"># </span><span class="comment">later, the user can say this:
+</span><span class="keyword">import</span> Person
+people = []
+<span class="keyword">for</span> i <span class="keyword">in</span> <span class="py-builtins">range</span>(10):
+ people.append(Person.Person())
+<span class="keyword">print</span> <span class="string">"There are"</span>, Person.population(), <span class="string">"people alive."</span>
+
+<span class="comment-delimiter">#</span><span class="comment">=&gt; There are 10 people alive.
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>him = Person()
+him.gender = <span class="string">"male"</span>
+
+her = Person()
+her.gender = <span class="string">"female"</span>
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>FixedArray.max_bounds = 100 <span class="comment-delimiter"># </span><span class="comment">set for whole class
+</span>alpha = FixedArray.FixedArray()
+<span class="keyword">print</span> <span class="string">"Bound on alpha is"</span>, alpha.max_bounds
+<span class="comment-delimiter">#</span><span class="comment">=&gt;100
+</span>
+beta = FixedArray.FixedArray()
+beta.max_bounds = 50 <span class="comment-delimiter"># </span><span class="comment">still sets for whole class
+</span><span class="keyword">print</span> <span class="string">"Bound on alpha is"</span>, alpha.max_bounds
+<span class="comment-delimiter">#</span><span class="comment">=&gt;50
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">In the module named 'FixedArray'
+</span>
+<span class="keyword">class</span> <span class="type">FixedArray</span>(object):
+ _max_bounds = [7] <span class="comment-delimiter"># </span><span class="comment">Shared across whole class
+</span>
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>, bounds=<span class="py-pseudo-keyword">None</span>):
+ <span class="keyword">if</span> bounds <span class="keyword">is</span> <span class="keyword">not</span> <span class="py-pseudo-keyword">None</span>:
+ <span class="py-pseudo-keyword">self</span>.max_bounds = bounds
+
+ <span class="keyword">def</span> <span class="function-name">get_max_bounds</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="keyword">return</span> <span class="py-pseudo-keyword">self</span>._max_bounds[0]
+ <span class="keyword">def</span> <span class="function-name">set_max_bounds</span>(<span class="py-pseudo-keyword">self</span>, val):
+ <span class="py-pseudo-keyword">self</span>._max_bounds[0] = val
+ max_bounds = <span class="py-builtins">property</span>(get_max_bounds, set_max_bounds)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN719"
+>Using Classes as Structs</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">There isn't the severe separation between scalar, arrays and hashs
+</span><span class="comment-delimiter"># </span><span class="comment">in Python, so there isn't a direct equivalent to the Perl code.
+</span><span class="keyword">class</span> <span class="type">Person</span>:
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>, name=<span class="py-pseudo-keyword">None</span>, age=<span class="py-pseudo-keyword">None</span>, peers=<span class="py-pseudo-keyword">None</span>):
+ <span class="keyword">if</span> peers <span class="keyword">is</span> <span class="py-pseudo-keyword">None</span>:
+ peers = []
+ <span class="py-pseudo-keyword">self</span>.name = name
+ <span class="py-pseudo-keyword">self</span>.age = age
+ <span class="py-pseudo-keyword">self</span>.peers = peers
+
+p = Person(<span class="string">"Jason Smythe"</span>, 13, [<span class="string">"Wilbur"</span>, <span class="string">"Ralph"</span>, <span class="string">"Fred"</span>])
+
+<span class="comment-delimiter"># </span><span class="comment">or this way. (This is not the prefered style as objects should
+</span><span class="comment-delimiter"># </span><span class="comment">be constructed with all the appropriate data, if possible.)
+</span>
+p = Person() <span class="comment-delimiter"># </span><span class="comment">allocate an empty Person
+</span>p.name = <span class="string">"Jason Smythe"</span> <span class="comment-delimiter"># </span><span class="comment">set its name field
+</span>p.age = 13 <span class="comment-delimiter"># </span><span class="comment">set its age field
+</span>p.peers.extend( [<span class="string">"Wilbur"</span>, <span class="string">"Ralph"</span>, <span class="string">"Fred"</span> ] ) <span class="comment-delimiter"># </span><span class="comment">set its peers field
+</span>
+p.peers = [<span class="string">"Wilbur"</span>, <span class="string">"Ralph"</span>, <span class="string">"Fred"</span>]
+
+p.peers[:]= [<span class="string">"Wilbur"</span>, <span class="string">"Ralph"</span>, <span class="string">"Fred"</span>]
+
+<span class="comment-delimiter"># </span><span class="comment">fetch various values, including the zeroth friend
+</span><span class="keyword">print</span> <span class="string">"At age %d, %s's first friend is %s."</span> % \
+ (p.age, p.name, p.peers[0])
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">This isn't very Pythonic - should create objects with the
+</span><span class="comment-delimiter"># </span><span class="comment">needed data, and not depend on defaults and modifing the object.
+</span><span class="keyword">import</span> sys
+<span class="keyword">def</span> <span class="function-name">carp</span>(s):
+ sys.stderr.write(<span class="string">"WARNING: "</span> + s + <span class="string">"\n"</span>)
+
+<span class="keyword">class</span> <span class="type">Person</span>:
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>, name = <span class="string">""</span>, age = 0):
+ <span class="py-pseudo-keyword">self</span>.name = name
+ <span class="py-pseudo-keyword">self</span>.age = age
+ <span class="keyword">def</span> <span class="function-name">__setattr__</span>(<span class="py-pseudo-keyword">self</span>, name, value):
+ <span class="keyword">if</span> name == <span class="string">"age"</span>:
+ <span class="comment-delimiter"># </span><span class="comment">This is very unpythonic
+</span> <span class="keyword">if</span> <span class="keyword">not</span> <span class="py-builtins">isinstance</span>(value, <span class="py-builtins">type</span>(0)):
+ carp(<span class="string">"age '%s' isn't numeric"</span> % (value,))
+ <span class="keyword">if</span> value &gt; 150: carp(<span class="string">"age '%s' is unreasonable"</span> % (value,))
+ <span class="py-pseudo-keyword">self</span>.__dict__[name] = value
+
+<span class="keyword">class</span> <span class="type">Family</span>:
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>, head = <span class="py-pseudo-keyword">None</span>, address = <span class="string">""</span>, members = <span class="py-pseudo-keyword">None</span>):
+ <span class="keyword">if</span> members <span class="keyword">is</span> <span class="py-pseudo-keyword">None</span>: members = []
+ <span class="py-pseudo-keyword">self</span>.head = head <span class="keyword">or</span> Person()
+ <span class="py-pseudo-keyword">self</span>.address = address
+ <span class="py-pseudo-keyword">self</span>.members = members
+
+folks = Family()
+
+dad = folks.head
+dad.name = <span class="string">"John"</span>
+dad.age = 34
+
+<span class="keyword">print</span> <span class="string">"%s's age is %d"</span> % (folks.head.name, folks.head.age)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">class</span> <span class="type">Card</span>:
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>, name=<span class="py-pseudo-keyword">None</span>, color=<span class="py-pseudo-keyword">None</span>, cost=<span class="py-pseudo-keyword">None</span>,
+ type=<span class="py-pseudo-keyword">None</span>, release=<span class="py-pseudo-keyword">None</span>, text=<span class="py-pseudo-keyword">None</span>):
+ <span class="py-pseudo-keyword">self</span>.name = name
+ <span class="py-pseudo-keyword">self</span>.color = color
+ <span class="py-pseudo-keyword">self</span>.cost = cost
+ <span class="py-pseudo-keyword">self</span>.type = <span class="py-builtins">type</span>
+ <span class="py-pseudo-keyword">self</span>.release = release
+ <span class="py-pseudo-keyword">self</span>.type = <span class="py-builtins">type</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">For positional args
+</span><span class="keyword">class</span> <span class="type">Card</span>:
+ _names = (<span class="string">"name"</span>, <span class="string">"color"</span>, <span class="string">"cost"</span>, <span class="string">"type"</span>, <span class="string">"release"</span>, <span class="string">"type"</span>)
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>, *args):
+ <span class="keyword">assert</span> <span class="py-builtins">len</span>(args) &lt;= <span class="py-builtins">len</span>(<span class="py-pseudo-keyword">self</span>._names)
+ <span class="keyword">for</span> k, v <span class="keyword">in</span> <span class="py-builtins">zip</span>(<span class="py-pseudo-keyword">self</span>._names, args):
+ <span class="py-builtins">setattr</span>(<span class="py-pseudo-keyword">self</span>, k, <span class="py-pseudo-keyword">None</span>)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">For keyword args
+</span><span class="keyword">class</span> <span class="type">Card</span>:
+ _names = (<span class="string">"name"</span>, <span class="string">"color"</span>, <span class="string">"cost"</span>, <span class="string">"type"</span>, <span class="string">"release"</span>, <span class="string">"type"</span>)
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>, **kwargs):
+ <span class="keyword">for</span> k <span class="keyword">in</span> <span class="py-pseudo-keyword">self</span>._names: <span class="comment-delimiter"># </span><span class="comment">Set the defaults
+</span> <span class="py-builtins">setattr</span>(<span class="py-pseudo-keyword">self</span>, k, <span class="py-pseudo-keyword">None</span>)
+ <span class="keyword">for</span> k, v <span class="keyword">in</span> kwargs.items(): <span class="comment-delimiter"># </span><span class="comment">add in the kwargs
+</span> <span class="keyword">assert</span> k <span class="keyword">in</span> <span class="py-pseudo-keyword">self</span>._names, <span class="string">"Unexpected kwarg: "</span> + k
+ <span class="py-builtins">setattr</span>(<span class="py-pseudo-keyword">self</span>, k, v)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">class</span> <span class="type">hostent</span>:
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>, addr_list = <span class="py-pseudo-keyword">None</span>, length = <span class="py-pseudo-keyword">None</span>,
+ addrtype = <span class="py-pseudo-keyword">None</span>, aliases = <span class="py-pseudo-keyword">None</span>, name = <span class="py-pseudo-keyword">None</span>):
+ <span class="py-pseudo-keyword">self</span>.addr_list = addr_list <span class="keyword">or</span> []
+ <span class="py-pseudo-keyword">self</span>.length = length <span class="keyword">or</span> 0
+ <span class="py-pseudo-keyword">self</span>.addrtype = addrtype <span class="keyword">or</span> <span class="string">""</span>
+ <span class="py-pseudo-keyword">self</span>.aliases = aliases <span class="keyword">or</span> []
+ <span class="py-pseudo-keyword">self</span>.name = name <span class="keyword">or</span> <span class="string">""</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment"># XXX What do I do with these?
+</span><span class="comment-delimiter">#</span><span class="comment">define h_type h_addrtype
+</span><span class="comment-delimiter">#</span><span class="comment">define h_addr h_addr_list[0]
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">make (hostent object)-&gt;type() same as (hostent object)-&gt;addrtype()
+</span><span class="comment-delimiter">#</span><span class="comment">
+</span><span class="comment-delimiter"># </span><span class="comment">*hostent::type = \&amp;hostent::addrtype;
+</span><span class="comment-delimiter">#</span><span class="comment">
+</span><span class="comment-delimiter"># </span><span class="comment"># make (hostenv object)-&gt;
+</span><span class="comment-delimiter"># </span><span class="comment">addr()
+</span><span class="comment-delimiter"># </span><span class="comment">same as (hostenv object)-&gt;addr_list(0)
+</span><span class="comment-delimiter">#</span><span class="comment">sub hostent::addr { shift-&gt;addr_list(0,@_) }
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">No equivalent to Net::hostent (Python uses an unnamed tuple)
+</span><span class="comment-delimiter">#</span><span class="comment">package Extra::hostent;
+</span><span class="comment-delimiter">#</span><span class="comment">use Net::hostent;
+</span><span class="comment-delimiter">#</span><span class="comment">@ISA = qw(hostent);
+</span><span class="comment-delimiter">#</span><span class="comment">sub addr { shift-&gt;addr_list(0,@_) }
+</span><span class="comment-delimiter">#</span><span class="comment">1;
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN722"
+>Cloning Objects</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">class</span> <span class="type">Class</span>(Parent):
+ <span class="keyword">pass</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment"># Note: this is unusual in Python code
+</span>ob1 = SomeClass()
+<span class="comment-delimiter"># </span><span class="comment">later on
+</span>ob2 = ob1.__class__()
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment"># Note: this is unusual in Python code
+</span>ob1 = Widget()
+ob2 = ob1.__class__()
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">XXX I do not know the intent of the original Perl code
+</span><span class="comment-delimiter"># </span><span class="comment">Do not use this style of programming in Python.
+</span><span class="keyword">import</span> time
+<span class="keyword">class</span> <span class="type">Person</span>(possible,base,classes):
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>, *args, **kwargs):
+ <span class="comment-delimiter"># </span><span class="comment">Call the parents' constructors, if there are any
+</span> <span class="keyword">for</span> baseclass <span class="keyword">in</span> <span class="py-pseudo-keyword">self</span>.__class__.__bases__:
+ init = <span class="py-builtins">getattr</span>(baseclass, <span class="string">"__init__"</span>)
+ <span class="keyword">if</span> init <span class="keyword">is</span> <span class="keyword">not</span> <span class="py-pseudo-keyword">None</span>:
+ init(<span class="py-pseudo-keyword">self</span>, *args, **kwargs)
+ <span class="py-pseudo-keyword">self</span>.PARENT = parent <span class="comment-delimiter"># </span><span class="comment">init data fields
+</span> <span class="py-pseudo-keyword">self</span>.START = time.time()
+ <span class="py-pseudo-keyword">self</span>.AGE = 0
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN725"
+>Calling Methods Indirectly</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>methname = <span class="string">"flicker"</span>
+<span class="py-builtins">getattr</span>(obj, methname)(10) <span class="comment-delimiter"># </span><span class="comment">calls obj-&gt;flicker(10);
+</span>
+<span class="comment-delimiter"># </span><span class="comment">call three methods on the object, by name
+</span><span class="keyword">for</span> m <span class="keyword">in</span> (<span class="string">"start"</span>, <span class="string">"run"</span>, <span class="string">"stop"</span>):
+ <span class="py-builtins">getattr</span>(obj, m)()
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>methods = (<span class="string">"name"</span>, <span class="string">"rank"</span>, <span class="string">"serno"</span>)
+his_info = {}
+<span class="keyword">for</span> m <span class="keyword">in</span> methods:
+ his_info[m] = <span class="py-builtins">getattr</span>(ob, m)()
+
+<span class="comment-delimiter"># </span><span class="comment">same as this:
+</span>
+his_info = {
+ <span class="string">'name'</span>: ob.name(),
+ <span class="string">'rank'</span>: ob.rank(),
+ <span class="string">'serno'</span>: ob.serno(),
+}
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>fnref = ob.method
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>fnref(10, <span class="string">"fred"</span>)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>obj.method(10, <span class="string">"fred"</span>)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">XXX Not sure if this is the correct translation.
+</span><span class="comment-delimiter"># </span><span class="comment">XXX Is 'can' special?
+</span><span class="keyword">if</span> <span class="py-builtins">isinstance</span>(obj_target, obj.__class__):
+ obj.can(<span class="string">'method_name'</span>)(obj_target, *arguments)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN728"
+>Determining Subclass Membership</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="py-builtins">isinstance</span>(obj, mimetools.Message)
+<span class="py-builtins">issubclass</span>(obj.__class__, mimetools.Message)
+
+<span class="keyword">if</span> <span class="py-builtins">hasattr</span>(obj, <span class="string">"method_name"</span>): <span class="comment-delimiter"># </span><span class="comment">check method validity
+</span> <span class="keyword">pass</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment"># Explicit type checking is needed fewer times than you think.
+</span>his_print_method = <span class="py-builtins">getattr</span>(obj, <span class="string">"as_string"</span>, <span class="py-pseudo-keyword">None</span>)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>__version__ = (3, 0)
+Some_Module.__version__
+
+<span class="comment-delimiter"># </span><span class="comment">Almost never used, and doesn't work for builtin types, which don't
+</span><span class="comment-delimiter"># </span><span class="comment">have a __module__.
+</span>
+his_vers = obj.__module__.__version__
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">if</span> Some_Module.__version__ &lt; (3, 0):
+ <span class="keyword">raise</span> <span class="py-builtins">ImportError</span>(<span class="string">"Some_Module version %s is too old, expected (3, 0)"</span> %
+ (Some_Module.__version__,))
+<span class="comment-delimiter"># </span><span class="comment">or more simply
+</span><span class="keyword">assert</span> Some_Module.__version__ &gt;= (3, 0), <span class="string">"version too old"</span>
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>__VERSION__ = <span class="string">'1.01'</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN731"
+>Writing an Inheritable Class</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Note: This uses the standard Python idiom of accessing the
+</span><span class="comment-delimiter"># </span><span class="comment">attributes directly rather than going through a method call.
+</span><span class="comment-delimiter"># </span><span class="comment">See earlier in this chapter for examples of how this does
+</span><span class="comment-delimiter"># </span><span class="comment">not break encapsulation.
+</span><span class="keyword">class</span> <span class="type">Person</span>:
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>, name = <span class="string">""</span>, age = 0):
+ <span class="py-pseudo-keyword">self</span>.name = name
+ <span class="py-pseudo-keyword">self</span>.age = age
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Prefered: dude = Person("Jason", 23)
+</span>dude = Person()
+dude.name = <span class="string">"Jason"</span>
+dude.age = 23
+<span class="keyword">print</span> <span class="string">"%s is age %d."</span> % (dude.name, dude.age)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">class</span> <span class="type">Employee</span>(Person):
+ <span class="keyword">pass</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Prefered: empl = Employee("Jason", 23)
+</span>emp = Employee()
+empl.name = <span class="string">"Jason"</span>
+empl.age = 23
+<span class="keyword">print</span> <span class="string">"%s is age %d."</span> % (empl.name, empl.age)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN734"
+>Accessing Overridden Methods</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">This doesn't need to be done since if 'method' doesn't
+</span><span class="comment-delimiter"># </span><span class="comment">exist in the Class it will be looked for in its BaseClass(es)
+</span><span class="keyword">class</span> <span class="type">Class</span>(BaseClass):
+ <span class="keyword">def</span> <span class="function-name">method</span>(<span class="py-pseudo-keyword">self</span>, *args, **kwargs):
+ BaseClass.method(<span class="py-pseudo-keyword">self</span>, *args, **kwargs)
+
+<span class="comment-delimiter"># </span><span class="comment">This lets you pick the specific method in one of the base classes
+</span><span class="keyword">class</span> <span class="type">Class</span>(BaseClass1, BaseClass2):
+ <span class="keyword">def</span> <span class="function-name">method</span>(<span class="py-pseudo-keyword">self</span>, *args, **kwargs):
+ BaseClass2.method(<span class="py-pseudo-keyword">self</span>, *args, **kwargs)
+
+<span class="comment-delimiter"># </span><span class="comment">This looks for the first method in the base class(es) without
+</span><span class="comment-delimiter"># </span><span class="comment">specifically knowing which base class. This reimplements
+</span><span class="comment-delimiter"># </span><span class="comment">the default action so isn't really needed.
+</span><span class="keyword">class</span> <span class="type">Class</span>(BaseClass1, BaseClass2, BaseClass3):
+ <span class="keyword">def</span> <span class="function-name">method</span>(<span class="py-pseudo-keyword">self</span>, *args, **kwargs):
+ <span class="keyword">for</span> baseclass <span class="keyword">in</span> <span class="py-pseudo-keyword">self</span>.__class__.__bases__:
+ f = <span class="py-builtins">getattr</span>(baseclass, <span class="string">"method"</span>)
+ <span class="keyword">if</span> f <span class="keyword">is</span> <span class="keyword">not</span> <span class="py-pseudo-keyword">None</span>:
+ <span class="keyword">return</span> f(*args, **kwargs)
+ <span class="keyword">raise</span> <span class="py-builtins">NotImplementedError</span>(<span class="string">"method"</span>)
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="py-pseudo-keyword">self</span>.meth() <span class="comment-delimiter"># </span><span class="comment">Call wherever first meth is found
+</span>
+Where.meth(<span class="py-pseudo-keyword">self</span>) <span class="comment-delimiter"># </span><span class="comment">Call in the base class "Where"
+</span>
+<span class="comment-delimiter"># </span><span class="comment">XXX Does Perl only have single inheritence? Or does
+</span><span class="comment-delimiter"># </span><span class="comment">it check all base classes? No directly equivalent way
+</span><span class="comment-delimiter"># </span><span class="comment">to do this in Python, but see above.
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> time
+
+<span class="comment-delimiter"># </span><span class="comment">The Perl code calls a private '_init' function, but in
+</span><span class="comment-delimiter"># </span><span class="comment">Python there's need for the complexity of 'new' mechanism
+</span><span class="comment-delimiter"># </span><span class="comment">so it's best just to put the '_init' code in '__init__'.
+</span><span class="keyword">class</span> <span class="type">Class</span>:
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>, *args):
+ <span class="comment-delimiter"># </span><span class="comment">init data fields
+</span> <span class="py-pseudo-keyword">self</span>.START = time.time()
+ <span class="py-pseudo-keyword">self</span>.AGE = 0
+ <span class="py-pseudo-keyword">self</span>.EXTRA = args <span class="comment-delimiter"># </span><span class="comment">anything extra
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>obj = Widget(haircolor = <span class="string">"red"</span>, freckles = 121)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">class</span> <span class="type">Class</span>(Base1, Base2, Base3):
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>, *args, **kwargs):
+ <span class="keyword">for</span> base <span class="keyword">in</span> <span class="py-pseudo-keyword">self</span>.__class__.__bases__:
+ f = <span class="py-builtins">getattr</span>(base, <span class="string">"__init__"</span>)
+ <span class="keyword">if</span> f <span class="keyword">is</span> <span class="keyword">not</span> <span class="py-pseudo-keyword">None</span>:
+ f(<span class="py-pseudo-keyword">self</span>, *args, **kwargs)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN737"
+>Generating Attribute Methods Using AUTOLOAD</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">NOTE: Python prefers direct attribute lookup rather than
+</span><span class="comment-delimiter"># </span><span class="comment">method calls. Python 2.2 will introduce a 'get_set' which
+</span><span class="comment-delimiter"># </span><span class="comment">*may* be equivalent, but I don't know enough about it. So
+</span><span class="comment-delimiter"># </span><span class="comment">instead I'll describe a class that lets you restrict access
+</span><span class="comment-delimiter"># </span><span class="comment">to only specific attributes.
+</span>
+<span class="keyword">class</span> <span class="type">Private</span>:
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>, names):
+ <span class="py-pseudo-keyword">self</span>.__names = names
+ <span class="py-pseudo-keyword">self</span>.__data = {}
+ <span class="keyword">def</span> <span class="function-name">__getattr__</span>(<span class="py-pseudo-keyword">self</span>, name):
+ <span class="keyword">if</span> name <span class="keyword">in</span> <span class="py-pseudo-keyword">self</span>.__names:
+ <span class="keyword">return</span> <span class="py-pseudo-keyword">self</span>.__data[name]
+ <span class="keyword">raise</span> <span class="py-builtins">AttributeError</span>(name)
+ <span class="keyword">def</span> <span class="function-name">__setattr__</span>(<span class="py-pseudo-keyword">self</span>, name, value):
+ <span class="keyword">if</span> name.startswith(<span class="string">"_Private"</span>):
+ <span class="py-pseudo-keyword">self</span>.__dict__[name] = value
+ <span class="keyword">return</span>
+ <span class="keyword">if</span> name <span class="keyword">in</span> <span class="py-pseudo-keyword">self</span>.__names:
+ <span class="py-pseudo-keyword">self</span>.__data[name] = value
+ <span class="keyword">return</span>
+ <span class="keyword">raise</span> <span class="py-builtins">TypeError</span>(<span class="string">"cannot set the attribute %r"</span> % (name,))
+
+<span class="keyword">class</span> <span class="type">Person</span>(Private):
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>, parent = <span class="py-pseudo-keyword">None</span>):
+ Private.__init__(<span class="py-pseudo-keyword">self</span>, [<span class="string">"name"</span>, <span class="string">"age"</span>, <span class="string">"peers"</span>, <span class="string">"parent"</span>])
+ <span class="py-pseudo-keyword">self</span>.parent = parent
+ <span class="keyword">def</span> <span class="function-name">new_child</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="keyword">return</span> Person(<span class="py-pseudo-keyword">self</span>)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>dad = Person()
+dad.name = <span class="string">"Jason"</span>
+dad.age = 23
+kid = dad.new_child()
+kid.name = <span class="string">"Rachel"</span>
+kid.age = 2
+<span class="keyword">print</span> <span class="string">"Kid's parent is"</span>, kid.parent.name
+<span class="comment-delimiter">#</span><span class="comment">=&gt;Kid's parent is Jason
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN740"
+>Solving the Data Inheritance Problem</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment"># XXX No clue on what this does. For that matter, what's
+</span><span class="comment-delimiter">#</span><span class="comment"># "The Data Inheritance Problem"?
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN743"
+>Coping with Circular Data Structures</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>node.NEXT = node
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">This is not a faithful copy of the Perl code, but it does
+</span><span class="comment-delimiter"># </span><span class="comment">show how to have the container's __del__ remove cycles in
+</span><span class="comment-delimiter"># </span><span class="comment">its contents. Note that Python 2.0 includes a garbage
+</span><span class="comment-delimiter"># </span><span class="comment">collector that is able to remove these sorts of cycles, but
+</span><span class="comment-delimiter"># </span><span class="comment">it's still best to prevent cycles in your code.
+</span><span class="keyword">class</span> <span class="type">Node</span>:
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>, value = <span class="py-pseudo-keyword">None</span>):
+ <span class="py-pseudo-keyword">self</span>.next = <span class="py-pseudo-keyword">self</span>
+ <span class="py-pseudo-keyword">self</span>.prev = <span class="py-pseudo-keyword">self</span>
+ <span class="py-pseudo-keyword">self</span>.value = value
+
+<span class="keyword">class</span> <span class="type">Ring</span>:
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="py-pseudo-keyword">self</span>.ring = <span class="py-pseudo-keyword">None</span>
+ <span class="py-pseudo-keyword">self</span>.count = 0
+
+ <span class="keyword">def</span> <span class="function-name">__str__</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="comment-delimiter"># </span><span class="comment">Helpful when debugging, to print the contents of the ring
+</span> s = <span class="string">"#%d: "</span> % <span class="py-pseudo-keyword">self</span>.count
+ x = <span class="py-pseudo-keyword">self</span>.ring
+ <span class="keyword">if</span> x <span class="keyword">is</span> <span class="py-pseudo-keyword">None</span>:
+ <span class="keyword">return</span> s
+ values = []
+ <span class="keyword">while</span> <span class="py-pseudo-keyword">True</span>:
+ values.append(x.value)
+ x = x.next
+ <span class="keyword">if</span> x <span class="keyword">is</span> <span class="py-pseudo-keyword">self</span>.ring:
+ <span class="keyword">break</span>
+ <span class="keyword">return</span> s + <span class="string">" -&gt; "</span>.join(<span class="py-builtins">map</span>(str, values)) + <span class="string">" -&gt;"</span>
+
+ <span class="keyword">def</span> <span class="function-name">search</span>(<span class="py-pseudo-keyword">self</span>, value):
+ node = <span class="py-pseudo-keyword">self</span>.ring
+ <span class="keyword">while</span> <span class="py-pseudo-keyword">True</span>:
+ <span class="keyword">if</span> node.value == value:
+ <span class="keyword">return</span> node
+ node = node.next
+ <span class="keyword">if</span> node <span class="keyword">is</span> <span class="py-pseudo-keyword">self</span>.ring:
+ <span class="keyword">break</span>
+
+ <span class="keyword">def</span> <span class="function-name">insert_value</span>(<span class="py-pseudo-keyword">self</span>, value):
+ node = Node(value)
+ <span class="keyword">if</span> <span class="py-pseudo-keyword">self</span>.ring <span class="keyword">is</span> <span class="keyword">not</span> <span class="py-pseudo-keyword">None</span>:
+ node.prev, node.next = <span class="py-pseudo-keyword">self</span>.ring.prev, <span class="py-pseudo-keyword">self</span>.ring
+ <span class="py-pseudo-keyword">self</span>.ring.prev.next = <span class="py-pseudo-keyword">self</span>.ring.prev = node
+ <span class="py-pseudo-keyword">self</span>.ring = node
+ <span class="py-pseudo-keyword">self</span>.count += 1
+
+ <span class="keyword">def</span> <span class="function-name">delete_value</span>(<span class="py-pseudo-keyword">self</span>, value):
+ node = <span class="py-pseudo-keyword">self</span>.search(value)
+ <span class="keyword">if</span> node <span class="keyword">is</span> <span class="keyword">not</span> <span class="py-pseudo-keyword">None</span>:
+ <span class="py-pseudo-keyword">self</span>.delete_node(node)
+
+ <span class="keyword">def</span> <span class="function-name">delete_node</span>(<span class="py-pseudo-keyword">self</span>, node):
+ <span class="keyword">if</span> node <span class="keyword">is</span> node.next:
+ node.next = node.prev = <span class="py-pseudo-keyword">None</span>
+ <span class="py-pseudo-keyword">self</span>.ring = <span class="py-pseudo-keyword">None</span>
+ <span class="keyword">else:</span>
+ node.prev.next, node.next.prev = node.next, node.prev
+ <span class="keyword">if</span> node <span class="keyword">is</span> <span class="py-pseudo-keyword">self</span>.ring:
+ <span class="py-pseudo-keyword">self</span>.ring = node.next
+ <span class="py-pseudo-keyword">self</span>.count -= 1
+
+ <span class="keyword">def</span> <span class="function-name">__del__</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="keyword">while</span> <span class="py-pseudo-keyword">self</span>.ring <span class="keyword">is</span> <span class="keyword">not</span> <span class="py-pseudo-keyword">None</span>:
+ <span class="py-pseudo-keyword">self</span>.delete_node(<span class="py-pseudo-keyword">self</span>.ring)
+
+COUNT = 1000
+<span class="keyword">for</span> rep <span class="keyword">in</span> <span class="py-builtins">range</span>(20):
+ r = Ring()
+ <span class="keyword">for</span> i <span class="keyword">in</span> <span class="py-builtins">range</span>(COUNT):
+ r.insert_value(i)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN746"
+>Overloading Operators</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> UserString
+<span class="keyword">class</span> <span class="type">MyString</span>(UserString.UserString):
+ <span class="keyword">def</span> <span class="function-name">__cmp__</span>(<span class="py-pseudo-keyword">self</span>, other):
+ <span class="keyword">return</span> <span class="py-builtins">cmp</span>(<span class="py-pseudo-keyword">self</span>.data.upper(), other.upper())
+
+<span class="keyword">class</span> <span class="type">Person</span>:
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>, name, idnum):
+ <span class="py-pseudo-keyword">self</span>.name = name
+ <span class="py-pseudo-keyword">self</span>.idnum = idnum
+ <span class="keyword">def</span> <span class="function-name">__str__</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="keyword">return</span> <span class="string">"%s (%05d)"</span> % (<span class="py-pseudo-keyword">self</span>.name.lower().capitalize(), <span class="py-pseudo-keyword">self</span>.idnum)
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">class</span> <span class="type">TimeNumber</span>:
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>, hours, minutes, seconds):
+ <span class="keyword">assert</span> minutes &lt; 60 <span class="keyword">and</span> seconds &lt; 60
+ <span class="py-pseudo-keyword">self</span>.hours = hours
+ <span class="py-pseudo-keyword">self</span>.minutes = minutes
+ <span class="py-pseudo-keyword">self</span>.seconds = seconds
+ <span class="keyword">def</span> <span class="function-name">__str__</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="keyword">return</span> <span class="string">"%d:%02d:%02d"</span> % (<span class="py-pseudo-keyword">self</span>.hours, <span class="py-pseudo-keyword">self</span>.minutes, <span class="py-pseudo-keyword">self</span>.seconds)
+ <span class="keyword">def</span> <span class="function-name">__add__</span>(<span class="py-pseudo-keyword">self</span>, other):
+ seconds = <span class="py-pseudo-keyword">self</span>.seconds + other.seconds
+ minutes = <span class="py-pseudo-keyword">self</span>.minutes + other.minutes
+ hours = <span class="py-pseudo-keyword">self</span>.hours + other.hours
+ <span class="keyword">if</span> seconds &gt;= 60:
+ seconds %= 60
+ minutes += 1
+ <span class="keyword">if</span> minutes &gt;= 60:
+ minutes %= 60
+ hours += 1
+ <span class="keyword">return</span> TimeNumber(hours, minutes, seconds)
+
+ <span class="keyword">def</span> <span class="function-name">__sub__</span>(<span class="py-pseudo-keyword">self</span>, other):
+ <span class="keyword">raise</span> <span class="py-builtins">NotImplementedError</span>
+
+ <span class="keyword">def</span> <span class="function-name">__mul__</span>(<span class="py-pseudo-keyword">self</span>, other):
+ <span class="keyword">raise</span> <span class="py-builtins">NotImplementedError</span>
+
+ <span class="keyword">def</span> <span class="function-name">__div__</span>(<span class="py-pseudo-keyword">self</span>, other):
+ <span class="keyword">raise</span> <span class="py-builtins">NotImplementedError</span>
+
+t1 = TimeNumber(0, 58, 59)
+sec = TimeNumber(0, 0, 1)
+<span class="py-builtins">min</span> = TimeNumber(0, 1, 0)
+<span class="keyword">print</span> t1 + sec + <span class="py-builtins">min</span> + <span class="py-builtins">min</span>
+<span class="comment-delimiter"># </span><span class="comment">1:01:00
+</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">For demo purposes only - the StrNum class is superfluous in this
+</span><span class="comment-delimiter"># </span><span class="comment">case as plain strings would give the same result.
+</span><span class="keyword">class</span> <span class="type">StrNum</span>:
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>, value):
+ <span class="py-pseudo-keyword">self</span>.value = value
+
+ <span class="keyword">def</span> <span class="function-name">__cmp__</span>(<span class="py-pseudo-keyword">self</span>, other): <span class="comment-delimiter"># </span><span class="comment">both &lt;=&gt; and cmp
+</span> <span class="comment-delimiter"># </span><span class="comment">providing &lt;=&gt; gives us &lt;, ==, etc. for free.
+</span> <span class="comment-delimiter"># </span><span class="comment">__lt__, __eq__, and __gt__ can also be individually specified
+</span> <span class="keyword">return</span> <span class="py-builtins">cmp</span>(<span class="py-pseudo-keyword">self</span>.value, other.value)
+
+ <span class="keyword">def</span> <span class="function-name">__str__</span>(<span class="py-pseudo-keyword">self</span>): <span class="comment-delimiter"># </span><span class="comment">""
+</span> <span class="keyword">return</span> <span class="py-pseudo-keyword">self</span>.value
+
+ <span class="keyword">def</span> <span class="function-name">__nonzero__</span>(<span class="py-pseudo-keyword">self</span>, other): <span class="comment-delimiter"># </span><span class="comment">bool
+</span> <span class="keyword">return</span> <span class="py-builtins">bool</span>(<span class="py-pseudo-keyword">self</span>.value)
+
+ <span class="keyword">def</span> <span class="function-name">__int__</span>(<span class="py-pseudo-keyword">self</span>, other): <span class="comment-delimiter"># </span><span class="comment">0+
+</span> <span class="keyword">return</span> <span class="py-builtins">int</span>(<span class="py-pseudo-keyword">self</span>.value)
+
+ <span class="keyword">def</span> <span class="function-name">__add__</span>(<span class="py-pseudo-keyword">self</span>, other): <span class="comment-delimiter"># </span><span class="comment">+
+</span> <span class="keyword">return</span> StrNum(<span class="py-pseudo-keyword">self</span>.value + other.value)
+
+ <span class="keyword">def</span> <span class="function-name">__radd__</span>(<span class="py-pseudo-keyword">self</span>, other): <span class="comment-delimiter"># </span><span class="comment">+, inverted
+</span> <span class="keyword">return</span> StrNum(other.value + <span class="py-pseudo-keyword">self</span>.value)
+
+ <span class="keyword">def</span> <span class="function-name">__mul__</span>(<span class="py-pseudo-keyword">self</span>, other): <span class="comment-delimiter"># </span><span class="comment">*
+</span> <span class="keyword">return</span> StrNum(<span class="py-pseudo-keyword">self</span>.value * other)
+
+ <span class="keyword">def</span> <span class="function-name">__rmul__</span>(<span class="py-pseudo-keyword">self</span>, other): <span class="comment-delimiter"># </span><span class="comment">*, inverted
+</span> <span class="keyword">return</span> StrNum(<span class="py-pseudo-keyword">self</span>.value * other)
+
+
+<span class="keyword">def</span> <span class="function-name">demo</span>():
+ <span class="comment-delimiter"># </span><span class="comment">show_strnum - demo operator overloading
+</span> x = StrNum(<span class="string">"Red"</span>)
+ y = StrNum(<span class="string">"Black"</span>)
+ z = x + y
+ r = z * 3
+ <span class="keyword">print</span> <span class="string">"values are %s, %s, %s, and %s"</span> % (x, y, z, r)
+ <span class="keyword">if</span> x &lt; y:
+ s = <span class="string">"LT"</span>
+ <span class="keyword">else:</span>
+ s = <span class="string">"GE"</span>
+ <span class="keyword">print</span> x, <span class="string">"is"</span>, s, y
+
+<span class="keyword">if</span> <span class="py-builtins">__name__</span> == <span class="string">"__main__"</span>:
+ demo()
+<span class="comment-delimiter"># </span><span class="comment">values are Red, Black, RedBlack, and RedBlackRedBlackRedBlack
+</span><span class="comment-delimiter"># </span><span class="comment">Red is GE Black
+</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment">!/usr/bin/env python
+</span><span class="comment-delimiter"># </span><span class="comment">demo_fixnum - show operator overloading
+</span>
+<span class="comment-delimiter"># </span><span class="comment">sum of STRFixNum: 40 and STRFixNum: 12 is STRFixNum: 52
+</span><span class="comment-delimiter"># </span><span class="comment">product of STRFixNum: 40 and STRFixNum: 12 is STRFixNum: 480
+</span><span class="comment-delimiter"># </span><span class="comment">STRFixNum: 3 has 0 places
+</span><span class="comment-delimiter"># </span><span class="comment">div of STRFixNum: 40 by STRFixNum: 12 is STRFixNum: 3.33
+</span><span class="comment-delimiter"># </span><span class="comment">square of that is STRFixNum: 11.11
+</span>
+<span class="comment-delimiter"># </span><span class="comment">This isn't excatly the same as the original Perl code since
+</span><span class="comment-delimiter"># </span><span class="comment">I couldn't figure out why the PLACES variable was used.
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> re
+_places_re = re.compile(r<span class="string">"\.(\d+)"</span>)
+
+default_places = 0
+
+<span class="keyword">class</span> <span class="type">FixNum</span>:
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>, value, places = <span class="py-pseudo-keyword">None</span>):
+ <span class="py-pseudo-keyword">self</span>.value = value
+ <span class="keyword">if</span> places <span class="keyword">is</span> <span class="py-pseudo-keyword">None</span>:
+ <span class="comment-delimiter"># </span><span class="comment">get from the value
+</span> m = _places_re.search(<span class="py-builtins">str</span>(value))
+ <span class="keyword">if</span> m:
+ places = <span class="py-builtins">int</span>(m.group(1))
+ <span class="keyword">else:</span>
+ places = default_places
+ <span class="py-pseudo-keyword">self</span>.places = places
+
+ <span class="keyword">def</span> <span class="function-name">__add__</span>(<span class="py-pseudo-keyword">self</span>, other):
+ <span class="keyword">return</span> FixNum(<span class="py-pseudo-keyword">self</span>.value + other.value,
+ <span class="py-builtins">max</span>(<span class="py-pseudo-keyword">self</span>.places, other.places))
+
+ <span class="keyword">def</span> <span class="function-name">__mul__</span>(<span class="py-pseudo-keyword">self</span>, other):
+ <span class="keyword">return</span> FixNum(<span class="py-pseudo-keyword">self</span>.value * other.value,
+ <span class="py-builtins">max</span>(<span class="py-pseudo-keyword">self</span>.places, other.places))
+
+ <span class="keyword">def</span> <span class="function-name">__div__</span>(<span class="py-pseudo-keyword">self</span>, other):
+ <span class="comment-delimiter"># </span><span class="comment">Force to use floating point, since 2/3 in Python is 0
+</span> <span class="comment-delimiter"># </span><span class="comment">Don't use float() since that will convert strings
+</span> <span class="keyword">return</span> FixNum((<span class="py-pseudo-keyword">self</span>.value+0.0) / other.value,
+ <span class="py-builtins">max</span>(<span class="py-pseudo-keyword">self</span>.places, other.places))
+
+ <span class="keyword">def</span> <span class="function-name">__str__</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="keyword">return</span> <span class="string">"STR%s: %.*f"</span> % (<span class="py-pseudo-keyword">self</span>.__class__.__name__,
+ <span class="py-pseudo-keyword">self</span>.places, <span class="py-pseudo-keyword">self</span>.value)
+ <span class="keyword">def</span> <span class="function-name">__int__</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="keyword">return</span> <span class="py-builtins">int</span>(<span class="py-pseudo-keyword">self</span>.value)
+
+ <span class="keyword">def</span> <span class="function-name">__float__</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="keyword">return</span> <span class="py-pseudo-keyword">self</span>.value
+
+<span class="keyword">def</span> <span class="function-name">demo</span>():
+ x = FixNum(40)
+ y = FixNum(12, 0)
+
+ <span class="keyword">print</span> <span class="string">"sum of"</span>, x, <span class="string">"and"</span>, y, <span class="string">"is"</span>, x+y
+ <span class="keyword">print</span> <span class="string">"product of"</span>, x, <span class="string">"and"</span>, y, <span class="string">"is"</span>, x*y
+
+ z = x/y
+ <span class="keyword">print</span> <span class="string">"%s has %d places"</span> % (z, z.places)
+ <span class="keyword">if</span> <span class="keyword">not</span> z.places:
+ z.places = 2
+
+ <span class="keyword">print</span> <span class="string">"div of"</span>, x, <span class="string">"by"</span>, y, <span class="string">"is"</span>, z
+ <span class="keyword">print</span> <span class="string">"square of that is "</span>, z*z
+
+<span class="keyword">if</span> <span class="py-builtins">__name__</span> == <span class="string">"__main__"</span>:
+ demo()</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN749"
+>Creating Magic Variables with tie</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">You can't tie a variable, but you can use properties.
+</span><span class="keyword">import</span> itertools
+<span class="keyword">class</span> <span class="type">ValueRing</span>(object):
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>, colours):
+ <span class="py-pseudo-keyword">self</span>.colourcycle = itertools.cycle(colours)
+
+ <span class="keyword">def</span> <span class="function-name">next_colour</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="keyword">return</span> <span class="py-pseudo-keyword">self</span>.colourcycle.next()
+ colour = <span class="py-builtins">property</span>(next_colour)
+vr = ValueRing([<span class="string">"red"</span>, <span class="string">"blue"</span>])
+<span class="keyword">for</span> i <span class="keyword">in</span> <span class="py-builtins">range</span>(6):
+ <span class="keyword">print</span> vr.colour,
+<span class="keyword">print</span>
+
+<span class="comment-delimiter"># </span><span class="comment">Note that you MUST refer directly to the property
+</span>x = vr.colour
+<span class="keyword">print</span> x, x, x
+<span class="comment-delimiter">#</span><span class="comment">-------------------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Ties are generally unnecessary in Python because of its strong OO support -
+</span><span class="comment-delimiter"># </span><span class="comment">The resulting code is MUCH shorter:
+</span><span class="keyword">class</span> <span class="type">AppendDict</span>(dict):
+ <span class="keyword">def</span> <span class="function-name">__setitem__</span>(<span class="py-pseudo-keyword">self</span>, key, val):
+ <span class="keyword">if</span> key <span class="keyword">in</span> <span class="py-pseudo-keyword">self</span>:
+ <span class="py-pseudo-keyword">self</span>[key].append(val)
+ <span class="keyword">else:</span>
+ <span class="py-builtins">super</span>(AppendDict, <span class="py-pseudo-keyword">self</span>).__setitem__(key, [val])
+tab = AppendDict()
+tab[<span class="string">"beer"</span>] = <span class="string">"guinness"</span>
+tab[<span class="string">"food"</span>] = <span class="string">"potatoes"</span>
+tab[<span class="string">"food"</span>] = <span class="string">"peas"</span>
+
+<span class="keyword">for</span> key, val <span class="keyword">in</span> tab.items():
+ <span class="keyword">print</span> key, <span class="string">"=&gt;"</span>, val
+<span class="comment-delimiter">#</span><span class="comment">-------------------------------------
+</span><span class="keyword">class</span> <span class="type">CaselessDict</span>(dict):
+ <span class="keyword">def</span> <span class="function-name">__setitem__</span>(<span class="py-pseudo-keyword">self</span>, key, val):
+ <span class="py-builtins">super</span>(CaselessDict, <span class="py-pseudo-keyword">self</span>).__setitem__(key.lower(), val)
+ <span class="keyword">def</span> <span class="function-name">__getitem__</span>(<span class="py-pseudo-keyword">self</span>, key):
+ <span class="keyword">return</span> <span class="py-builtins">super</span>(CaselessDict, <span class="py-pseudo-keyword">self</span>).__getitem__(key.lower())
+
+tab = CaselessDict()
+tab[<span class="string">"VILLAIN"</span>] = <span class="string">"big "</span>
+tab[<span class="string">"herOine"</span>] = <span class="string">"red riding hood"</span>
+tab[<span class="string">"villain"</span>] = <span class="string">"bad wolf"</span>
+
+<span class="keyword">for</span> key, val <span class="keyword">in</span> tab.items():
+ <span class="keyword">print</span> key, <span class="string">"is"</span>, val
+<span class="comment-delimiter">#</span><span class="comment">=&gt;villain is bad wolf
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt;heroine is red riding hood
+</span><span class="comment-delimiter">#</span><span class="comment">-------------------------------------
+</span><span class="keyword">class</span> <span class="type">RevDict</span>(dict):
+ <span class="keyword">def</span> <span class="function-name">__setitem__</span>(<span class="py-pseudo-keyword">self</span>, key, val):
+ <span class="py-builtins">super</span>(RevDict, <span class="py-pseudo-keyword">self</span>).__setitem__(key, val)
+ <span class="py-builtins">super</span>(RevDict, <span class="py-pseudo-keyword">self</span>).__setitem__(val, key)
+
+tab = RevDict()
+tab[<span class="string">"red"</span>] = <span class="string">"rojo"</span>
+tab[<span class="string">"blue"</span>] = <span class="string">"azul"</span>
+tab[<span class="string">"green"</span>] = <span class="string">"verde"</span>
+tab[<span class="string">"evil"</span>] = (<span class="string">"No Way!"</span>, <span class="string">"Way!"</span>)
+
+<span class="keyword">for</span> key, val <span class="keyword">in</span> tab.items():
+ <span class="keyword">print</span> key, <span class="string">"is"</span>, val
+<span class="comment-delimiter">#</span><span class="comment">=&gt;blue is azul
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt;('No Way!', 'Way!') is evil
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt;rojo is red
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt;evil is ('No Way!', 'Way!')
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt;azul is blue
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt;verde is green
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt;green is verde
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt;red is rojo
+</span><span class="comment-delimiter">#</span><span class="comment">-------------------------------------
+</span><span class="keyword">import</span> itertools
+<span class="keyword">for</span> elem <span class="keyword">in</span> itertools.count():
+ <span class="keyword">print</span> <span class="string">"Got"</span>, elem
+<span class="comment-delimiter">#</span><span class="comment">-------------------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">You could use FileDispatcher from section 7.18
+</span>tee = FileDispatcher(sys.stderr, sys.stdout)
+<span class="comment-delimiter">#</span><span class="comment">-------------------------------------</PRE
+></TD
+></TR
+></TABLE
+></DIV
+></DIV
+><DIV
+CLASS="NAVFOOTER"
+><HR
+ALIGN="LEFT"
+WIDTH="100%"><TABLE
+SUMMARY="Footer navigation table"
+WIDTH="100%"
+BORDER="0"
+CELLPADDING="0"
+CELLSPACING="0"
+><TR
+><TD
+WIDTH="33%"
+ALIGN="left"
+VALIGN="top"
+><A
+HREF="packagesetc.html"
+ACCESSKEY="P"
+>Prev</A
+></TD
+><TD
+WIDTH="34%"
+ALIGN="center"
+VALIGN="top"
+><A
+HREF="index.html"
+ACCESSKEY="H"
+>Home</A
+></TD
+><TD
+WIDTH="33%"
+ALIGN="right"
+VALIGN="top"
+><A
+HREF="dbaccess.html"
+ACCESSKEY="N"
+>Next</A
+></TD
+></TR
+><TR
+><TD
+WIDTH="33%"
+ALIGN="left"
+VALIGN="top"
+>Packages, Libraries, and Modules</TD
+><TD
+WIDTH="34%"
+ALIGN="center"
+VALIGN="top"
+>&nbsp;</TD
+><TD
+WIDTH="33%"
+ALIGN="right"
+VALIGN="top"
+>Database Access</TD
+></TR
+></TABLE
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/help/PythonExamples/pleac_python/datesandtimes.html b/help/PythonExamples/pleac_python/datesandtimes.html
new file mode 100644
index 0000000..1501e9b
--- /dev/null
+++ b/help/PythonExamples/pleac_python/datesandtimes.html
@@ -0,0 +1,694 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML
+><HEAD
+><TITLE
+>Dates and Times</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
+REL="HOME"
+TITLE="PLEAC-Python
+"
+HREF="index.html"><LINK
+REL="PREVIOUS"
+TITLE="Numbers"
+HREF="numbers.html"><LINK
+REL="NEXT"
+TITLE="Arrays"
+HREF="arrays.html"><style type="text/css"> <!--
+ .comment {
+ /* font-lock-comment-face */
+ color: #bebebe;
+ }
+ .comment-delimiter {
+ }
+ .function-name {
+ /* font-lock-function-name-face */
+ color: #b2dfee;
+ }
+ .keyword {
+ /* font-lock-keyword-face */
+ color: #ffa500;
+ }
+ .py-builtins {
+ /* py-builtins-face */
+ color: #ffa500;
+ }
+ .py-pseudo-keyword {
+ /* py-pseudo-keyword-face */
+ color: #ffa500;
+ }
+ .string {
+ /* font-lock-string-face */
+ color: #00cd00;
+ }
+ .type {
+ /* font-lock-type-face */
+ color: #98fb98;
+ }
+ -->
+ </style></head
+><BODY TEXT="#cecece" BGCOLOR="#4f6f6f" LINK="#f5deb3" VLINK="#d5ae83"
+CLASS="SECT1"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><DIV
+CLASS="NAVHEADER"
+><TABLE
+SUMMARY="Header navigation table"
+WIDTH="100%"
+BORDER="0"
+CELLPADDING="0"
+CELLSPACING="0"
+><TR
+><TH
+COLSPAN="3"
+ALIGN="center"
+>PLEAC-Python
+</TH
+></TR
+><TR
+><TD
+WIDTH="10%"
+ALIGN="left"
+VALIGN="bottom"
+><A
+HREF="numbers.html"
+ACCESSKEY="P"
+>Prev</A
+></TD
+><TD
+WIDTH="80%"
+ALIGN="center"
+VALIGN="bottom"
+></TD
+><TD
+WIDTH="10%"
+ALIGN="right"
+VALIGN="bottom"
+><A
+HREF="arrays.html"
+ACCESSKEY="N"
+>Next</A
+></TD
+></TR
+></TABLE
+><HR
+ALIGN="LEFT"
+WIDTH="100%"></DIV
+><DIV
+CLASS="SECT1"
+><H1
+CLASS="SECT1"
+><A
+NAME="DATESANDTIMES"
+>3. Dates and Times</A
+></H1
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN132"
+>Introduction</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment">introduction
+</span><span class="comment-delimiter"># </span><span class="comment">There are three common ways of manipulating dates in Python
+</span><span class="comment-delimiter"># </span><span class="comment">mxDateTime - a popular third-party module (not discussed here)
+</span><span class="comment-delimiter"># </span><span class="comment">time - a fairly low-level standard library module
+</span><span class="comment-delimiter"># </span><span class="comment">datetime - a new library module for Python 2.3 and used for most of these samples
+</span><span class="comment-delimiter"># </span><span class="comment">(I will use full names to show which module they are in, but you can also use
+</span><span class="comment-delimiter"># </span><span class="comment">from datetime import datetime, timedelta and so on for convenience)
+</span>
+<span class="keyword">import</span> time
+<span class="keyword">import</span> datetime
+
+<span class="keyword">print</span> <span class="string">"Today is day"</span>, time.localtime()[7], <span class="string">"of the current year"</span>
+<span class="comment-delimiter"># </span><span class="comment">Today is day 218 of the current year
+</span>
+today = datetime.date.today()
+<span class="keyword">print</span> <span class="string">"Today is day"</span>, today.timetuple()[7], <span class="string">"of "</span>, today.year
+<span class="comment-delimiter"># </span><span class="comment">Today is day 218 of 2003
+</span>
+<span class="keyword">print</span> <span class="string">"Today is day"</span>, today.strftime(<span class="string">"%j"</span>), <span class="string">"of the current year"</span>
+<span class="comment-delimiter"># </span><span class="comment">Today is day 218 of the current year
+</span> </PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN135"
+>Finding Today's Date</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Finding todays date
+</span>
+today = datetime.date.today()
+<span class="keyword">print</span> <span class="string">"The date is"</span>, today
+<span class="comment-delimiter">#</span><span class="comment">=&gt; The date is 2003-08-06
+</span>
+<span class="comment-delimiter"># </span><span class="comment">the function strftime() (string-format time) produces nice formatting
+</span><span class="comment-delimiter"># </span><span class="comment">All codes are detailed at http://www.python.org/doc/current/lib/module-time.html
+</span><span class="keyword">print</span> t.strftime(<span class="string">"four-digit year: %Y, two-digit year: %y, month: %m, day: %d"</span>)
+<span class="comment-delimiter">#</span><span class="comment">=&gt; four-digit year: 2003, two-digit year: 03, month: 08, day: 06
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN138"
+>Converting DMYHMS to Epoch Seconds</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Converting DMYHMS to Epoch Seconds
+</span><span class="comment-delimiter"># </span><span class="comment">To work with Epoch Seconds, you need to use the time module
+</span>
+<span class="comment-delimiter"># </span><span class="comment">For the local timezone
+</span>t = datetime.datetime.now()
+<span class="keyword">print</span> <span class="string">"Epoch Seconds:"</span>, time.mktime(t.timetuple())
+<span class="comment-delimiter">#</span><span class="comment">=&gt; Epoch Seconds: 1060199000.0
+</span>
+<span class="comment-delimiter"># </span><span class="comment">For UTC
+</span>t = datetime.datetime.utcnow()
+<span class="keyword">print</span> <span class="string">"Epoch Seconds:"</span>, time.mktime(t.timetuple())
+<span class="comment-delimiter">#</span><span class="comment">=&gt; Epoch Seconds: 1060195503.0
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN141"
+>Converting Epoch Seconds to DMYHMS</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Converting Epoch Seconds to DMYHMS
+</span>
+now = datetime.datetime.fromtimestamp(EpochSeconds)
+<span class="comment-delimiter">#</span><span class="comment">or use datetime.datetime.utcfromtimestamp()
+</span><span class="keyword">print</span> now
+<span class="comment-delimiter">#</span><span class="comment">=&gt; datetime.datetime(2003, 8, 6, 20, 43, 20)
+</span><span class="keyword">print</span> now.ctime()
+<span class="comment-delimiter">#</span><span class="comment">=&gt; Wed Aug 6 20:43:20 2003
+</span>
+<span class="comment-delimiter"># </span><span class="comment">or with the time module
+</span>oldtimetuple = time.localtime(EpochSeconds)
+<span class="comment-delimiter"># </span><span class="comment">oldtimetuple contains (year, month, day, hour, minute, second, weekday, yearday, daylightSavingAdjustment)
+</span><span class="keyword">print</span> oldtimetuple
+<span class="comment-delimiter">#</span><span class="comment">=&gt; (2003, 8, 6, 20, 43, 20, 2, 218, 1)
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN144"
+>Adding to or Subtracting from a Date</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Adding to or Subtracting from a Date
+</span><span class="comment-delimiter"># </span><span class="comment">Use the rather nice datetime.timedelta objects
+</span>
+now = datetime.date(2003, 8, 6)
+difference1 = datetime.timedelta(days=1)
+difference2 = datetime.timedelta(weeks=-2)
+
+<span class="keyword">print</span> <span class="string">"One day in the future is:"</span>, now + difference1
+<span class="comment-delimiter">#</span><span class="comment">=&gt; One day in the future is: 2003-08-07
+</span>
+<span class="keyword">print</span> <span class="string">"Two weeks in the past is:"</span>, now + difference2
+<span class="comment-delimiter">#</span><span class="comment">=&gt; Two weeks in the past is: 2003-07-23
+</span>
+<span class="keyword">print</span> datetime.date(2003, 8, 6) - datetime.date(2000, 8, 6)
+<span class="comment-delimiter">#</span><span class="comment">=&gt; 1095 days, 0:00:00
+</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>birthtime = datetime.datetime(1973, 01, 18, 3, 45, 50) <span class="comment-delimiter"># </span><span class="comment">1973-01-18 03:45:50
+</span>
+interval = datetime.timedelta(seconds=5, minutes=17, hours=2, days=55)
+then = birthtime + interval
+
+<span class="keyword">print</span> <span class="string">"Then is"</span>, then.ctime()
+<span class="comment-delimiter">#</span><span class="comment">=&gt; Then is Wed Mar 14 06:02:55 1973
+</span>
+<span class="keyword">print</span> <span class="string">"Then is"</span>, then.strftime(<span class="string">"%A %B %d %I:%M:%S %p %Y"</span>)
+<span class="comment-delimiter">#</span><span class="comment">=&gt; Then is Wednesday March 14 06:02:55 AM 1973
+</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>when = datetime.datetime(1973, 1, 18) + datetime.timedelta(days=55)
+<span class="keyword">print</span> <span class="string">"Nat was 55 days old on:"</span>, when.strftime(<span class="string">"%m/%d/%Y"</span>).lstrip(<span class="string">"0"</span>)
+<span class="comment-delimiter">#</span><span class="comment">=&gt; Nat was 55 days old on: 3/14/1973
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN147"
+>Difference of Two Dates</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Dates produce timedeltas when subtracted.
+</span>
+diff = date2 - date1
+diff = datetime.date(year1, month1, day1) - datetime.date(year2, month2, day2)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>
+bree = datetime.datetime(1981, 6, 16, 4, 35, 25)
+nat = datetime.datetime(1973, 1, 18, 3, 45, 50)
+
+difference = bree - nat
+<span class="keyword">print</span> <span class="string">"There were"</span>, difference, <span class="string">"minutes between Nat and Bree"</span>
+<span class="comment-delimiter">#</span><span class="comment">=&gt; There were 3071 days, 0:49:35 between Nat and Bree
+</span>
+weeks, days = <span class="py-builtins">divmod</span>(difference.days, 7)
+
+minutes, seconds = <span class="py-builtins">divmod</span>(difference.seconds, 60)
+hours, minutes = <span class="py-builtins">divmod</span>(minutes, 60)
+
+<span class="keyword">print</span> <span class="string">"%d weeks, %d days, %d:%d:%d"</span> % (weeks, days, hours, minutes, seconds)
+<span class="comment-delimiter">#</span><span class="comment">=&gt; 438 weeks, 5 days, 0:49:35
+</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">print</span> <span class="string">"There were"</span>, difference.days, <span class="string">"days between Bree and Nat."</span>
+<span class="comment-delimiter">#</span><span class="comment">=&gt; There were 3071 days between bree and nat
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN150"
+>Day in a Week/Month/Year or Week Number</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Day in a Week/Month/Year or Week Number
+</span>
+when = datetime.date(1981, 6, 16)
+
+<span class="keyword">print</span> <span class="string">"16/6/1981 was:"</span>
+<span class="keyword">print</span> when.strftime(<span class="string">"Day %w of the week (a %A). Day %d of the month (%B)."</span>)
+<span class="keyword">print</span> when.strftime(<span class="string">"Day %j of the year (%Y), in week %W of the year."</span>)
+
+<span class="comment-delimiter">#</span><span class="comment">=&gt; 16/6/1981 was:
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt; Day 2 of the week (a Tuesday). Day 16 of the month (June).
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt; Day 167 of the year (1981), in week 24 of the year.
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN153"
+>Parsing Dates and Times from Strings</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Parsing Dates and Times from Strings
+</span>
+time.strptime(<span class="string">"Tue Jun 16 20:18:03 1981"</span>)
+<span class="comment-delimiter"># </span><span class="comment">(1981, 6, 16, 20, 18, 3, 1, 167, -1)
+</span>
+time.strptime(<span class="string">"16/6/1981"</span>, <span class="string">"%d/%m/%Y"</span>)
+<span class="comment-delimiter"># </span><span class="comment">(1981, 6, 16, 0, 0, 0, 1, 167, -1)
+</span><span class="comment-delimiter"># </span><span class="comment">strptime() can use any of the formatting codes from time.strftime()
+</span>
+<span class="comment-delimiter"># </span><span class="comment">The easiest way to convert this to a datetime seems to be;
+</span>now = datetime.datetime(*time.strptime(<span class="string">"16/6/1981"</span>, <span class="string">"%d/%m/%Y"</span>)[0:5])
+<span class="comment-delimiter"># </span><span class="comment">the '*' operator unpacks the tuple, producing the argument list.
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN156"
+>Printing a Date</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Printing a Date
+</span><span class="comment-delimiter"># </span><span class="comment">Use datetime.strftime() - see helpfiles in distro or at python.org
+</span>
+<span class="keyword">print</span> datetime.datetime.now().strftime(<span class="string">"The date is %A (%a) %d/%m/%Y"</span>)
+<span class="comment-delimiter">#</span><span class="comment">=&gt; The date is Friday (Fri) 08/08/2003
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN159"
+>High-Resolution Timers</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">High Resolution Timers
+</span>
+t1 = time.clock()
+<span class="comment-delimiter"># </span><span class="comment">Do Stuff Here
+</span>t2 = time.clock()
+<span class="keyword">print</span> t2 - t1
+
+<span class="comment-delimiter"># </span><span class="comment">2.27236813618
+</span><span class="comment-delimiter"># </span><span class="comment">Accuracy will depend on platform and OS,
+</span><span class="comment-delimiter"># </span><span class="comment">but time.clock() uses the most accurate timer it can
+</span>
+time.clock(); time.clock()
+<span class="comment-delimiter"># </span><span class="comment">174485.51365466841
+</span><span class="comment-delimiter"># </span><span class="comment">174485.55702610247
+</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Also useful;
+</span><span class="keyword">import</span> timeit
+code = <span class="string">'[x for x in range(10) if x % 2 == 0]'</span>
+<span class="py-builtins">eval</span>(code)
+<span class="comment-delimiter"># </span><span class="comment">[0, 2, 4, 6, 8]
+</span>
+t = timeit.Timer(code)
+<span class="keyword">print</span> <span class="string">"10,000 repeats of that code takes:"</span>, t.timeit(10000), <span class="string">"seconds"</span>
+<span class="keyword">print</span> <span class="string">"1,000,000 repeats of that code takes:"</span>, t.timeit(), <span class="string">"seconds"</span>
+
+<span class="comment-delimiter"># </span><span class="comment">10,000 repeats of that code takes: 0.128238644856 seconds
+</span><span class="comment-delimiter"># </span><span class="comment">1,000,000 repeats of that code takes: 12.5396490336 seconds
+</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> timeit
+code = <span class="string">'import random; l = random.sample(xrange(10000000), 1000); l.sort()'</span>
+t = timeit.Timer(code)
+
+<span class="keyword">print</span> <span class="string">"Create a list of a thousand random numbers. Sort the list. Repeated a thousand times."</span>
+<span class="keyword">print</span> <span class="string">"Average Time:"</span>, t.timeit(1000) / 1000
+<span class="comment-delimiter"># </span><span class="comment">Time taken: 5.24391507859
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN162"
+>Short Sleeps</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Short Sleeps
+</span>
+seconds = 3.1
+time.sleep(seconds)
+<span class="keyword">print</span> <span class="string">"boo"</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN165"
+>Program: hopdelta</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Program HopDelta
+</span><span class="comment-delimiter"># </span><span class="comment">Save a raw email to disk and run "python hopdelta.py FILE"
+</span><span class="comment-delimiter"># </span><span class="comment">and it will process the headers and show the time taken
+</span><span class="comment-delimiter"># </span><span class="comment">for each server hop (nb: if server times are wrong, negative dates
+</span><span class="comment-delimiter"># </span><span class="comment">might appear in the output).
+</span>
+<span class="keyword">import</span> datetime, email, email.Utils
+<span class="keyword">import</span> os, sys, time
+
+<span class="keyword">def</span> <span class="function-name">extract_date</span>(hop):
+ <span class="comment-delimiter"># </span><span class="comment">According to RFC822, the date will be prefixed with
+</span> <span class="comment-delimiter"># </span><span class="comment">a semi-colon, and is the last part of a received
+</span> <span class="comment-delimiter"># </span><span class="comment">header.
+</span> date_string = hop[hop.find(<span class="string">';'</span>)+2:]
+ date_string = date_string.strip()
+ time_tuple = email.Utils.parsedate(date_string)
+
+ <span class="comment-delimiter"># </span><span class="comment">convert time_tuple to datetime
+</span> EpochSeconds = time.mktime(time_tuple)
+ dt = datetime.datetime.fromtimestamp(EpochSeconds)
+ <span class="keyword">return</span> dt
+
+<span class="keyword">def</span> <span class="function-name">process</span>(filename):
+ <span class="comment-delimiter"># </span><span class="comment">Main email file processing
+</span> <span class="comment-delimiter"># </span><span class="comment">read the headers and process them
+</span> f = <span class="py-builtins">file</span>(filename, <span class="string">'rb'</span>)
+ msg = email.message_from_file(f)
+
+ hops = msg.get_all(<span class="string">'received'</span>)
+
+ <span class="comment-delimiter"># </span><span class="comment">in reverse order, get the server(s) and date/time involved
+</span> hops.reverse()
+ results = []
+ <span class="keyword">for</span> hop <span class="keyword">in</span> hops:
+ hop = hop.lower()
+
+ <span class="keyword">if</span> hop.startswith(<span class="string">'by'</span>): <span class="comment-delimiter"># </span><span class="comment">'Received: by' line
+</span> sender = <span class="string">"start"</span>
+ receiver = hop[3:hop.find(<span class="string">' '</span>,3)]
+ date = extract_date(hop)
+
+ <span class="keyword">else:</span> <span class="comment-delimiter"># </span><span class="comment">'Received: from' line
+</span> sender = hop[5:hop.find(<span class="string">' '</span>,5)]
+ by = hop.find(<span class="string">'by '</span>)+3
+ receiver = hop[by:hop.find(<span class="string">' '</span>, by)]
+ date = extract_date(hop)
+
+ results.append((sender, receiver, date))
+ output(results)
+
+<span class="keyword">def</span> <span class="function-name">output</span>(results):
+ <span class="keyword">print</span> <span class="string">"Sender, Recipient, Time, Delta"</span>
+ <span class="keyword">print</span>
+ previous_dt = delta = 0
+ <span class="keyword">for</span> (sender, receiver, date) <span class="keyword">in</span> results:
+ <span class="keyword">if</span> previous_dt:
+ delta = date - previous_dt
+
+ <span class="keyword">print</span> <span class="string">"%s, %s, %s, %s"</span> % (sender,
+ receiver,
+ date.strftime(<span class="string">"%Y/%d/%m %H:%M:%S"</span>),
+ delta)
+ <span class="keyword">print</span>
+ previous_dt = date
+
+<span class="keyword">def</span> <span class="function-name">main</span>():
+ <span class="comment-delimiter"># </span><span class="comment">Perform some basic argument checking
+</span> <span class="keyword">if</span> <span class="py-builtins">len</span>(sys.argv) != 2:
+ <span class="keyword">print</span> <span class="string">"Usage: mailhop.py FILENAME"</span>
+
+ <span class="keyword">else:</span>
+ filename = sys.argv[1]
+ <span class="keyword">if</span> os.path.isfile(filename):
+ process(filename)
+ <span class="keyword">else:</span>
+ <span class="keyword">print</span> filename, <span class="string">"doesn't seem to be a valid file."</span>
+
+<span class="keyword">if</span> <span class="py-builtins">__name__</span> == <span class="string">'__main__'</span>:
+ main()</PRE
+></TD
+></TR
+></TABLE
+></DIV
+></DIV
+><DIV
+CLASS="NAVFOOTER"
+><HR
+ALIGN="LEFT"
+WIDTH="100%"><TABLE
+SUMMARY="Footer navigation table"
+WIDTH="100%"
+BORDER="0"
+CELLPADDING="0"
+CELLSPACING="0"
+><TR
+><TD
+WIDTH="33%"
+ALIGN="left"
+VALIGN="top"
+><A
+HREF="numbers.html"
+ACCESSKEY="P"
+>Prev</A
+></TD
+><TD
+WIDTH="34%"
+ALIGN="center"
+VALIGN="top"
+><A
+HREF="index.html"
+ACCESSKEY="H"
+>Home</A
+></TD
+><TD
+WIDTH="33%"
+ALIGN="right"
+VALIGN="top"
+><A
+HREF="arrays.html"
+ACCESSKEY="N"
+>Next</A
+></TD
+></TR
+><TR
+><TD
+WIDTH="33%"
+ALIGN="left"
+VALIGN="top"
+>Numbers</TD
+><TD
+WIDTH="34%"
+ALIGN="center"
+VALIGN="top"
+>&nbsp;</TD
+><TD
+WIDTH="33%"
+ALIGN="right"
+VALIGN="top"
+>Arrays</TD
+></TR
+></TABLE
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/help/PythonExamples/pleac_python/dbaccess.html b/help/PythonExamples/pleac_python/dbaccess.html
new file mode 100644
index 0000000..9bc8667
--- /dev/null
+++ b/help/PythonExamples/pleac_python/dbaccess.html
@@ -0,0 +1,679 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML
+><HEAD
+><TITLE
+>Database Access</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
+REL="HOME"
+TITLE="PLEAC-Python
+"
+HREF="index.html"><LINK
+REL="PREVIOUS"
+TITLE="Classes, Objects, and Ties"
+HREF="classesetc.html"><LINK
+REL="NEXT"
+TITLE="User Interfaces"
+HREF="userinterfaces.html"><style type="text/css"> <!--
+ .comment {
+ /* font-lock-comment-face */
+ color: #bebebe;
+ }
+ .comment-delimiter {
+ }
+ .function-name {
+ /* font-lock-function-name-face */
+ color: #b2dfee;
+ }
+ .keyword {
+ /* font-lock-keyword-face */
+ color: #ffa500;
+ }
+ .py-builtins {
+ /* py-builtins-face */
+ color: #ffa500;
+ }
+ .py-pseudo-keyword {
+ /* py-pseudo-keyword-face */
+ color: #ffa500;
+ }
+ .string {
+ /* font-lock-string-face */
+ color: #00cd00;
+ }
+ .type {
+ /* font-lock-type-face */
+ color: #98fb98;
+ }
+ -->
+ </style></head
+><BODY TEXT="#cecece" BGCOLOR="#4f6f6f" LINK="#f5deb3" VLINK="#d5ae83"
+CLASS="SECT1"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><DIV
+CLASS="NAVHEADER"
+><TABLE
+SUMMARY="Header navigation table"
+WIDTH="100%"
+BORDER="0"
+CELLPADDING="0"
+CELLSPACING="0"
+><TR
+><TH
+COLSPAN="3"
+ALIGN="center"
+>PLEAC-Python
+</TH
+></TR
+><TR
+><TD
+WIDTH="10%"
+ALIGN="left"
+VALIGN="bottom"
+><A
+HREF="classesetc.html"
+ACCESSKEY="P"
+>Prev</A
+></TD
+><TD
+WIDTH="80%"
+ALIGN="center"
+VALIGN="bottom"
+></TD
+><TD
+WIDTH="10%"
+ALIGN="right"
+VALIGN="bottom"
+><A
+HREF="userinterfaces.html"
+ACCESSKEY="N"
+>Next</A
+></TD
+></TR
+></TABLE
+><HR
+ALIGN="LEFT"
+WIDTH="100%"></DIV
+><DIV
+CLASS="SECT1"
+><H1
+CLASS="SECT1"
+><A
+NAME="DBACCESS"
+>14. Database Access</A
+></H1
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN754"
+>Introduction</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"></span><span class="comment-delimiter"></span><span class="comment"></span>
+<span class="comment-delimiter"># </span><span class="comment">See http://www.python.org/doc/topics/database/ for Database Interfaces details.
+</span><span class="comment-delimiter"># </span><span class="comment">currently listed on http://www.python.org/doc/topics/database/modules/
+</span><span class="comment-delimiter">#</span><span class="comment">
+</span><span class="comment-delimiter"># </span><span class="comment">DB/2, Informix, Interbase, Ingres, JDBC, MySQL, pyodbc, mxODBC, ODBC Interface,
+</span><span class="comment-delimiter"># </span><span class="comment">DCOracle, DCOracle2, PyGresQL, psycopg, PySQLite, sapdbapi, Sybase, ThinkSQL.
+</span><span class="comment-delimiter">#</span><span class="comment">
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN757"
+>Making and Using a DBM File</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-------------------------------------
+</span><span class="keyword">import</span> anydbm
+filename = <span class="string">"test.db"</span>
+<span class="keyword">try:</span>
+ db = anydbm.open(filename)
+<span class="keyword">except</span> anydbm, err:
+ <span class="keyword">print</span> <span class="string">"Can't open %s: %s!"</span> % (filename, err)
+
+db[<span class="string">"key"</span>] = <span class="string">"value"</span> <span class="comment-delimiter"># </span><span class="comment">put value into database
+</span><span class="keyword">if</span> <span class="string">"key"</span> <span class="keyword">in</span> db: <span class="comment-delimiter"># </span><span class="comment">check whether in database
+</span> val = db.pop(<span class="string">"key"</span>) <span class="comment-delimiter"># </span><span class="comment">retrieve and remove from database
+</span>db.close() <span class="comment-delimiter"># </span><span class="comment">close the database
+</span><span class="comment-delimiter">#</span><span class="comment">-------------------------------------
+</span><span class="comment-delimiter"># </span><span class="comment"><font size="-1"><a href="http://pleac.sourceforge.net/include/python/ch14/userstats">download the following standalone program</a></font>
+</span><span class="comment-delimiter">#</span><span class="comment">!/usr/bin/python
+</span><span class="comment-delimiter"># </span><span class="comment">userstats - generates statistics on who logged in.
+</span><span class="comment-delimiter"># </span><span class="comment">call with an argument to display totals
+</span>
+<span class="keyword">import</span> sys, os, anydbm, re
+
+db_file = <span class="string">'/tmp/userstats.db'</span> <span class="comment-delimiter"># </span><span class="comment">where data is kept between runs
+</span>
+<span class="keyword">try:</span>
+ db = anydbm.open(db_file,<span class="string">'c'</span>) <span class="comment-delimiter"># </span><span class="comment">open, create if it does not exist
+</span><span class="keyword">except:</span>
+ <span class="keyword">print</span> <span class="string">"Can't open db %s: %s!"</span> % (db_file, sys.exc_info()[1])
+ sys.exit(1)
+
+<span class="keyword">if</span> <span class="py-builtins">len</span>(sys.argv) &gt; 1:
+ <span class="keyword">if</span> sys.argv[1] == <span class="string">'ALL'</span>:
+ userlist = db.keys()
+ <span class="keyword">else:</span>
+ userlist = sys.argv[1:]
+ userlist.sort()
+ <span class="keyword">for</span> user <span class="keyword">in</span> userlist:
+ <span class="keyword">if</span> db.has_key(user):
+ <span class="keyword">print</span> <span class="string">"%s\t%s"</span> % (user, db[user])
+ <span class="keyword">else:</span>
+ <span class="keyword">print</span> <span class="string">"%s\t%s"</span> % (user, 0)
+<span class="keyword">else:</span>
+ who = os.popen(<span class="string">'who'</span>).readlines() <span class="comment-delimiter"># </span><span class="comment">run who(1)
+</span> <span class="keyword">if</span> <span class="py-builtins">len</span>(who)&lt;1:
+ <span class="keyword">print</span> <span class="string">"error running who"</span> <span class="comment-delimiter"># </span><span class="comment">exit
+</span> sys.exit(1)
+ <span class="comment-delimiter"># </span><span class="comment">extract username (first thin on the line) and update
+</span> user_re = re.compile(<span class="string">"^(\S+)"</span>)
+ <span class="keyword">for</span> line <span class="keyword">in</span> who:
+ fnd = user_re.search(line)
+ <span class="keyword">if</span> <span class="keyword">not</span> fnd:
+ <span class="keyword">print</span> <span class="string">"Bad line from who: %s"</span> % line
+ sys.exit(1)
+ user = fnd.groups()[0]
+ <span class="keyword">if</span> <span class="keyword">not</span> db.has_key(user):
+ db[user] = <span class="string">"0"</span>
+ db[user] = <span class="py-builtins">str</span>(int(db[user])+1) <span class="comment-delimiter"># </span><span class="comment">only strings are allowed
+</span>db.close()
+ </PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN760"
+>Emptying a DBM File</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">Emptying a DBM File
+</span>
+<span class="keyword">import</span> anydbm
+
+<span class="keyword">try:</span>
+ db = anydbm.open(FILENAME,<span class="string">'w'</span>) <span class="comment-delimiter"># </span><span class="comment">open, for writing
+</span><span class="keyword">except</span> anydbm.error, err:
+ <span class="keyword">print</span> <span class="string">"Can't open db %s: %s!"</span> % (filename, err)
+ <span class="keyword">raise</span> <span class="py-builtins">SystemExit</span>(1)
+
+db.clear()
+db.close()
+<span class="comment-delimiter"># </span><span class="comment">-------------------------------
+</span><span class="keyword">try:</span>
+ db = anydbm.open(filename,<span class="string">'n'</span>) <span class="comment-delimiter"># </span><span class="comment">open, always create a new empty db
+</span><span class="keyword">except</span> anydbm.error, err:
+ <span class="keyword">print</span> <span class="string">"Can't open db %s: %s!"</span> % (filename, err)
+ <span class="keyword">raise</span> <span class="py-builtins">SystemExit</span>(1)
+
+db.close()
+<span class="comment-delimiter"># </span><span class="comment">-------------------------------
+</span><span class="keyword">import</span> os
+<span class="keyword">try:</span>
+ os.remove(FILENAME)
+<span class="keyword">except</span> <span class="py-builtins">OSError</span>, err:
+ <span class="keyword">print</span> <span class="string">"Couldn't remove %s to empty the database: %s!"</span> % (FILENAME,
+ err)
+ <span class="keyword">raise</span> <span class="py-builtins">SystemExit</span>
+
+<span class="keyword">try:</span>
+ db = anydbm.open(FILENAME,<span class="string">'n'</span>) <span class="comment-delimiter"># </span><span class="comment">open, flways create a new empty db
+</span><span class="keyword">except</span> anydbm.error, err:
+ <span class="keyword">print</span> <span class="string">"Couldn't create %s database: %s!"</span> % (FILENAME, err)
+ <span class="keyword">raise</span> <span class="py-builtins">SystemExit</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN763"
+>Converting Between DBM Files</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">Converting Between DBM Files
+</span>
+<span class="comment-delimiter"># </span><span class="comment"><font size="-1"><a href="http://pleac.sourceforge.net/include/python/ch14/db2gdbm">download the following standalone program</a></font>
+</span><span class="comment-delimiter">#</span><span class="comment">!/usr/bin/python
+</span><span class="comment-delimiter"># </span><span class="comment">db2gdbm: converts DB to GDBM
+</span>
+<span class="keyword">import</span> sys
+<span class="keyword">import</span> dbm, gdbm
+
+<span class="keyword">if</span> <span class="py-builtins">len</span>(sys.argv)&lt;3:
+ <span class="keyword">print</span> <span class="string">"usage: db2gdbm infile outfile"</span>
+ sys.exit(1)
+
+(infile, outfile) = sys.argv[1:]
+
+<span class="comment-delimiter"># </span><span class="comment">open the files
+</span><span class="keyword">try:</span>
+ db_in = dbm.open(infile)
+<span class="keyword">except:</span>
+ <span class="keyword">print</span> <span class="string">"Can't open infile %s: %s!"</span> % (infile, sys.exc_info()[1])
+ sys.exit(1)
+<span class="keyword">try:</span>
+ db_out = dbm.open(outfile,<span class="string">"n"</span>)
+<span class="keyword">except:</span>
+ <span class="keyword">print</span> <span class="string">"Can't open outfile %s: %s!"</span> % (outfile, sys.exc_info()[1])
+ sys.exit(1)
+
+<span class="comment-delimiter"># </span><span class="comment">copy (don't use db_out = db_in because it's slow on big databases)
+</span><span class="comment-delimiter"># </span><span class="comment">is this also so for python ?
+</span><span class="keyword">for</span> k <span class="keyword">in</span> db_in.keys():
+ db_out[k] = db_in[k]
+
+<span class="comment-delimiter"># </span><span class="comment">these close happen automatically at program exit
+</span>db_out.close()
+db_in.close()</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN766"
+>Merging DBM Files</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span>
+OUTPUT.update(INPUT1)
+OUTPUT.update(INPUT2)
+
+OUTPUT = anydbm.open(<span class="string">"OUT"</span>,<span class="string">"n"</span>)
+<span class="keyword">for</span> INPUT <span class="keyword">in</span> (INPUT1, INPUT2, INPUT1):
+ <span class="keyword">for</span> key, value <span class="keyword">in</span> INPUT.iteritems():
+ <span class="keyword">if</span> OUTPUT.has_key(key):
+ <span class="comment-delimiter"># </span><span class="comment">decide which value to use and set OUTPUT[key] if necessary
+</span> <span class="keyword">print</span> <span class="string">"key %s already present: %s, new: %s"</span> % (
+ key, OUTPUT[key], value )
+ <span class="keyword">else:</span>
+ OUTPUT[key] = value</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN769"
+>Locking DBM Files</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">On systems where the Berkeley DB supports it, dbhash takes an
+</span><span class="comment-delimiter"># </span><span class="comment">"l" flag:
+</span><span class="keyword">import</span> dbhash
+dbhash.open(<span class="string">"mydb.db"</span>, <span class="string">"cl"</span>) <span class="comment-delimiter"># </span><span class="comment">'c': create if doesn't exist
+</span>
+<span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN772"
+>Sorting Large DBM Files</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN775"
+>Treating a Text File as a Database Array</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN778"
+>Storing Complex Data in a DBM File</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">shelve uses anydbm to access and chooses between DBMs.
+</span><span class="comment-delimiter"># </span><span class="comment">anydbm detect file formats automatically.
+</span><span class="keyword">import</span> shelve
+db = shelve.open(<span class="string">"celebrities.db"</span>)
+
+name1 = <span class="string">"Greg Stein"</span>
+name2 = <span class="string">"Greg Ward"</span>
+
+<span class="comment-delimiter"># </span><span class="comment">shelve uses pickle to convert objects into strings and back.
+</span><span class="comment-delimiter"># </span><span class="comment">This is automatic.
+</span>db[name1] = [<span class="string">"of ViewCVS fame"</span>, <span class="string">"gstein@lyra.org"</span>]
+db[name2] = [<span class="string">"of Distutils fame"</span>, <span class="string">"gward@python.net"</span>]
+
+greg1 = db[name1]
+greg2 = db[name2]
+
+<span class="keyword">print</span> <span class="string">"Two Gregs: %x %x"</span> % (<span class="py-builtins">id</span>(greg1), <span class="py-builtins">id</span>(greg2))
+
+<span class="keyword">if</span> greg1 == greg2:
+ <span class="keyword">print</span> <span class="string">"You're having runtime fun with one Greg made two."</span>
+<span class="keyword">else:</span>
+ <span class="keyword">print</span> <span class="string">"No two Gregs are ever alike."</span>
+
+<span class="comment-delimiter"># </span><span class="comment">Changes to mutable entries are not written back by default.
+</span><span class="comment-delimiter"># </span><span class="comment">You can get the copy, change it, and put it back.
+</span>entry = db[name1]
+entry[0] = <span class="string">"of Subversion fame"</span>
+db[name1] = entry
+
+<span class="comment-delimiter"># </span><span class="comment">Or you can open shelve with writeback option. Then you can
+</span><span class="comment-delimiter"># </span><span class="comment">change mutable entries directly. (New in 2.3)
+</span>db = shelve.open(<span class="string">"celebrities.db"</span>, writeback=<span class="py-pseudo-keyword">True</span>)
+db[name2][0] = <span class="string">"of Optik fame"</span>
+
+<span class="comment-delimiter"># </span><span class="comment">However, writeback option can consume vast amounts of memory
+</span><span class="comment-delimiter"># </span><span class="comment">to do its magic. You can clear cache with sync().
+</span>db.sync()
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN781"
+>Persistent Data</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS.
+</span><span class="keyword">import</span> os as _os, shelve <span class="keyword">as</span> _shelve
+
+_fname = <span class="string">"persist.db"</span>
+<span class="keyword">if</span> <span class="keyword">not</span> _os.path.exists(_fname):
+ var1 = <span class="string">"foo"</span>
+ var2 = <span class="string">"bar"</span>
+_d = _shelve.open(<span class="string">"persist.db"</span>)
+<span class="py-builtins">globals</span>().update(_d)
+
+<span class="keyword">print</span> <span class="string">"var1 is %s; var2 is %s"</span>%(var1, var2)
+var1 = <span class="py-builtins">raw_input</span>(<span class="string">"New var1: "</span>)
+var2 = <span class="py-builtins">raw_input</span>(<span class="string">"New var2: "</span>)
+
+<span class="keyword">for</span> key, val <span class="keyword">in</span> <span class="py-builtins">globals</span>().items():
+ <span class="keyword">if</span> <span class="keyword">not</span> key.startswith(<span class="string">"_"</span>):
+ _d[key] = val
+<span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN784"
+>Executing an SQL Command Using DBI and DBD</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> dbmodule
+
+dbconn = dbmodule.connect(arguments...)
+
+cursor = dbconn.cursor()
+cursor.execute(sql)
+
+<span class="keyword">while</span> <span class="py-pseudo-keyword">True</span>:
+ row = cursor.fetchone()
+ <span class="keyword">if</span> row <span class="keyword">is</span> <span class="py-pseudo-keyword">None</span>:
+ <span class="keyword">break</span>
+ ...
+
+cursor.close()
+dbconn.close()
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> MySQLdb
+<span class="keyword">import</span> pwd
+
+dbconn = MySQLdb.connect(db=<span class="string">'dbname'</span>, host=<span class="string">'mysqlserver.domain.com'</span>,
+ port=3306, user=<span class="string">'user'</span>, passwd=<span class="string">'password'</span>)
+
+cursor = dbconn.cursor()
+cursor.execute(<span class="string">"CREATE TABLE users (uid INT, login CHAR(8))"</span>)
+
+<span class="comment-delimiter"># </span><span class="comment">Note: some databases use %s for parameters, some use ? or other
+</span><span class="comment-delimiter"># </span><span class="comment">formats
+</span>sql_fmt = <span class="string">"INSERT INTO users VALUES( %s, %s )"</span>
+
+<span class="keyword">for</span> userent <span class="keyword">in</span> pwd.getpwall():
+ <span class="comment-delimiter"># </span><span class="comment">the second argument contains a list of parameters which will
+</span> <span class="comment-delimiter"># </span><span class="comment">be quoted before being put in the query
+</span> cursor.execute(sql_fmt, (userent.pw_uid, userent.pw_name))
+
+cursor.execute(<span class="string">"SELECT * FROM users WHERE uid &lt; 50"</span>)
+
+<span class="keyword">for</span> row <span class="keyword">in</span> cursor.fetchall():
+ <span class="comment-delimiter"># </span><span class="comment">NULL will be displayed as None
+</span> <span class="keyword">print</span> <span class="string">", "</span>.join(<span class="py-builtins">map</span>(str, row))
+
+cursor.execute(<span class="string">"DROP TABLE users"</span>)
+cursor.close()
+dbconn.close()
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN787"
+>Program: ggh - Grep Netscape Global History</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+></DIV
+><DIV
+CLASS="NAVFOOTER"
+><HR
+ALIGN="LEFT"
+WIDTH="100%"><TABLE
+SUMMARY="Footer navigation table"
+WIDTH="100%"
+BORDER="0"
+CELLPADDING="0"
+CELLSPACING="0"
+><TR
+><TD
+WIDTH="33%"
+ALIGN="left"
+VALIGN="top"
+><A
+HREF="classesetc.html"
+ACCESSKEY="P"
+>Prev</A
+></TD
+><TD
+WIDTH="34%"
+ALIGN="center"
+VALIGN="top"
+><A
+HREF="index.html"
+ACCESSKEY="H"
+>Home</A
+></TD
+><TD
+WIDTH="33%"
+ALIGN="right"
+VALIGN="top"
+><A
+HREF="userinterfaces.html"
+ACCESSKEY="N"
+>Next</A
+></TD
+></TR
+><TR
+><TD
+WIDTH="33%"
+ALIGN="left"
+VALIGN="top"
+>Classes, Objects, and Ties</TD
+><TD
+WIDTH="34%"
+ALIGN="center"
+VALIGN="top"
+>&nbsp;</TD
+><TD
+WIDTH="33%"
+ALIGN="right"
+VALIGN="top"
+>User Interfaces</TD
+></TR
+></TABLE
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/help/PythonExamples/pleac_python/directories.html b/help/PythonExamples/pleac_python/directories.html
new file mode 100644
index 0000000..c5263db
--- /dev/null
+++ b/help/PythonExamples/pleac_python/directories.html
@@ -0,0 +1,838 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML
+><HEAD
+><TITLE
+>Directories</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
+REL="HOME"
+TITLE="PLEAC-Python
+"
+HREF="index.html"><LINK
+REL="PREVIOUS"
+TITLE="File Contents"
+HREF="filecontents.html"><LINK
+REL="NEXT"
+TITLE="Subroutines"
+HREF="subroutines.html"><style type="text/css"> <!--
+ .comment {
+ /* font-lock-comment-face */
+ color: #bebebe;
+ }
+ .comment-delimiter {
+ }
+ .function-name {
+ /* font-lock-function-name-face */
+ color: #b2dfee;
+ }
+ .keyword {
+ /* font-lock-keyword-face */
+ color: #ffa500;
+ }
+ .py-builtins {
+ /* py-builtins-face */
+ color: #ffa500;
+ }
+ .py-pseudo-keyword {
+ /* py-pseudo-keyword-face */
+ color: #ffa500;
+ }
+ .string {
+ /* font-lock-string-face */
+ color: #00cd00;
+ }
+ .type {
+ /* font-lock-type-face */
+ color: #98fb98;
+ }
+ -->
+ </style></head
+><BODY TEXT="#cecece" BGCOLOR="#4f6f6f" LINK="#f5deb3" VLINK="#d5ae83"
+CLASS="SECT1"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><DIV
+CLASS="NAVHEADER"
+><TABLE
+SUMMARY="Header navigation table"
+WIDTH="100%"
+BORDER="0"
+CELLPADDING="0"
+CELLSPACING="0"
+><TR
+><TH
+COLSPAN="3"
+ALIGN="center"
+>PLEAC-Python
+</TH
+></TR
+><TR
+><TD
+WIDTH="10%"
+ALIGN="left"
+VALIGN="bottom"
+><A
+HREF="filecontents.html"
+ACCESSKEY="P"
+>Prev</A
+></TD
+><TD
+WIDTH="80%"
+ALIGN="center"
+VALIGN="bottom"
+></TD
+><TD
+WIDTH="10%"
+ALIGN="right"
+VALIGN="bottom"
+><A
+HREF="subroutines.html"
+ACCESSKEY="N"
+>Next</A
+></TD
+></TR
+></TABLE
+><HR
+ALIGN="LEFT"
+WIDTH="100%"></DIV
+><DIV
+CLASS="SECT1"
+><H1
+CLASS="SECT1"
+><A
+NAME="DIRECTORIES"
+>9. Directories</A
+></H1
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN495"
+>Introduction</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>entry = os.stat(<span class="string">"/usr/bin/vi"</span>)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>entry = os.stat(<span class="string">"/usr/bin"</span>)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>entry = os.stat(INFILE.name)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>entry = os.stat(<span class="string">"/usr/bin/vi"</span>)
+ctime = entry.st_ino
+size = entry.st_size
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>f = <span class="py-builtins">open</span>(filename)
+
+f.seek(0, 2)
+<span class="keyword">if</span> <span class="keyword">not</span> f.tell():
+ <span class="keyword">raise</span> <span class="py-builtins">SystemExit</span>(<span class="string">"%s doesn't have text in it."</span>%filename)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>
+<span class="keyword">for</span> filename <span class="keyword">in</span> os.listdir(<span class="string">"/usr/bin"</span>):
+ <span class="keyword">print</span> <span class="string">"Inside /usr/bin is something called"</span>, filename
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN498"
+>Getting and Setting Timestamps</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>fstat = os.stat(filename)
+readtime = fstat.st_atime
+writetime = fstat.st_mtime
+
+os.utime(filename, (newreadtime, newwritetime))
+
+<span class="comment-delimiter">#</span><span class="comment">DON'T DO THIS:
+</span>readtime, writetime = os.stat(filename)[7:9]
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>SECONDS_PER_DAY = 60 * 60 * 24
+fstat = os.stat(filename)
+atime = fstat.st_atime - 7 * SECONDS_PER_DAY
+mtime = fstat.st_mtime - 7 * SECONDS_PER_DAY
+
+os.utime(filename, (atime, mtime))
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>mtime = os.stat(filename).st_mtime
+utime(filename, (time.time(), mtime))
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment">!/usr/bin/perl -w
+</span><span class="comment-delimiter"># </span><span class="comment">uvi - vi a file without changing its access times
+</span>
+<span class="keyword">import</span> sys, os
+<span class="keyword">if</span> <span class="py-builtins">len</span>(sys.argv) != 2:
+ <span class="keyword">raise</span> <span class="py-builtins">SystemExit</span>(<span class="string">"usage: uvi filename"</span>)
+filename = argv[1]
+fstat = os.stat(filename)
+<span class="comment-delimiter"># </span><span class="comment">WARNING: potential security risk
+</span>os.system( (os.environ.get(<span class="string">"EDITOR"</span>) <span class="keyword">or</span> <span class="string">"vi"</span>) + <span class="string">" "</span> + filename)
+os.utime(filename, (fstat.st_atime, fstat.st_mtime))
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN501"
+>Deleting a File</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>os.remove(filename)
+
+err_flg = 0
+<span class="keyword">for</span> filename <span class="keyword">in</span> filenames:
+ <span class="keyword">try:</span>
+ os.remove(filename)
+ <span class="keyword">except</span> <span class="py-builtins">OSError</span>, err:
+ err_flg = 1
+<span class="keyword">if</span> err_flg:
+ <span class="keyword">raise</span> <span class="py-builtins">OSError</span>(<span class="string">"Couldn't remove all of %s: %s"</span> % (filenames, err))
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>os.remove(filename)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>success = 0
+<span class="keyword">for</span> filename <span class="keyword">in</span> filenames:
+ <span class="keyword">try:</span>
+ os.remove(filename)
+ success += 1
+ <span class="keyword">except</span> <span class="py-builtins">OSError</span>, err:
+ <span class="keyword">pass</span>
+<span class="keyword">if</span> success != <span class="py-builtins">len</span>(filenames):
+ sys.stderr.write(<span class="string">"could only delete %d of %d files"</span> % \
+ (success, <span class="py-builtins">len</span>(filenames)))
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN504"
+>Copying or Moving a File</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> shutil
+shutil.copy(oldfile, newfile)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment"># NOTE: this doesn't do the same thing as the Perl code,
+</span><span class="comment-delimiter">#</span><span class="comment"># eg, handling of partial writes.
+</span>infile = <span class="py-builtins">open</span>(oldfile)
+outfile = <span class="py-builtins">open</span>(newfile, <span class="string">"w"</span>)
+
+blksize = 16384 <span class="comment-delimiter"># </span><span class="comment">preferred block size?
+</span>
+<span class="keyword">while</span> <span class="py-pseudo-keyword">True</span>:
+ buf = infile.read(blksize)
+ <span class="keyword">if</span> <span class="keyword">not</span> buf:
+ <span class="keyword">break</span>
+ outfile.write(buf)
+
+infile.close()
+outfile.close()
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">WARNING: these are insecure - do not use in hostile environments
+</span>os.system(<span class="string">"cp %s %s"</span> % (oldfile, newfile)) <span class="comment-delimiter"># </span><span class="comment">unix
+</span>os.system(<span class="string">"copy %s %s"</span> % (oldfile, newfile)) <span class="comment-delimiter"># </span><span class="comment">dos, vms
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> shutil
+
+shutil.copy(<span class="string">"datafile.dat"</span>, <span class="string">"datafile.bak"</span>)
+
+shutil.copy(<span class="string">"datafile.new"</span>, <span class="string">"datafile.dat"</span>)
+os.remove(<span class="string">"datafile.new"</span>)
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN507"
+>Recognizing Two Names for the Same File</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> os
+seen = {}
+
+<span class="keyword">def</span> <span class="function-name">do_my_thing</span>(filename):
+ fstat = os.stat(filename)
+ key = (fstat.st_ino, fstat.st_dev)
+ <span class="keyword">if</span> <span class="keyword">not</span> seen.get(key):
+ <span class="comment-delimiter"># </span><span class="comment">do something with filename because we haven't
+</span> <span class="comment-delimiter"># </span><span class="comment">seen it before
+</span> <span class="keyword">pass</span>
+ seen[key] = seen.get(key, 0 ) + 1
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">for</span> filename <span class="keyword">in</span> files:
+ fstat = os.stat(filename)
+ key = (fstat.st_ino, fstat.st_dev)
+ seen.setdefault(key, []).append(filename)
+
+keys = seen.keys()
+keys.sort()
+<span class="keyword">for</span> inodev <span class="keyword">in</span> keys:
+ ino, dev = inodev
+ filenames = seen[inodev]
+ <span class="keyword">if</span> <span class="py-builtins">len</span>(filenames) &gt; 1:
+ <span class="comment-delimiter"># </span><span class="comment">'filenames' is a list of filenames for the same file
+</span> <span class="keyword">pass</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN510"
+>Processing All Files in a Directory</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">for</span> filename <span class="keyword">in</span> os.listdir(dirname):
+ <span class="comment-delimiter"># </span><span class="comment">do something with "$dirname/$file"
+</span> <span class="keyword">pass</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">XXX No -T equivalent in Python
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">'readir' always skipes '.' and '..' on OSes where those are
+</span><span class="comment-delimiter"># </span><span class="comment">standard directory names
+</span><span class="keyword">for</span> filename <span class="keyword">in</span> os.listdir(dirname):
+ <span class="keyword">pass</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">XX Not Implemented -- need to know what DirHandle does
+</span><span class="comment-delimiter"># </span><span class="comment">use DirHandle;
+</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN513"
+>Globbing, or Getting a List of Filenames Matching a Pattern</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> glob
+filenames = glob.glob(<span class="string">"*.c"</span>)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>filenames = [filename <span class="keyword">for</span> filename <span class="keyword">in</span> os.listdir(path) <span class="keyword">if</span> filename.endswith(<span class="string">".c"</span>)]
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> re
+allowed_name = re.compile(r<span class="string">"\.[ch]$"</span>, re.I).search
+filenames = [f <span class="keyword">for</span> f <span class="keyword">in</span> os.listdir(path) <span class="keyword">if</span> allowed_name(f)]
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> re, os
+allowed_name = re.compile(r<span class="string">"\.[ch]$"</span>, re.I).search
+
+fnames = [os.path.join(dirname, fname)
+ <span class="keyword">for</span> fname <span class="keyword">in</span> os.listdir(dirname)
+ <span class="keyword">if</span> allowed_name(fname)]
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>dirs = [os.path.join(path, f)
+ <span class="keyword">for</span> f <span class="keyword">in</span> os.listdir(path) <span class="keyword">if</span> f.isdigit()]
+dirs = [d <span class="keyword">for</span> d <span class="keyword">in</span> dirs <span class="keyword">if</span> os.path.isdir(d)]
+dirs = sorted(dirs, key=int) <span class="comment-delimiter"># </span><span class="comment">Sort by numeric value - "9" before "11"
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN516"
+>Processing All Files in a Directory Recursively</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">Processing All Files in a Directory Recursively
+</span>
+<span class="comment-delimiter"># </span><span class="comment">os.walk is new in 2.3.
+</span>
+<span class="comment-delimiter"># </span><span class="comment">For pre-2.3 code, there is os.path.walk, which is
+</span><span class="comment-delimiter"># </span><span class="comment">little harder to use.
+</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> os
+<span class="keyword">for</span> root, dirs, files <span class="keyword">in</span> os.walk(top):
+ <span class="keyword">pass</span> <span class="comment-delimiter"># </span><span class="comment">do whatever
+</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> os, os.path
+<span class="keyword">for</span> root, dirs, files <span class="keyword">in</span> os.walk(top):
+ <span class="keyword">for</span> name <span class="keyword">in</span> dirs:
+ <span class="keyword">print</span> os.path.join(root, name) + <span class="string">'/'</span>
+ <span class="keyword">for</span> name <span class="keyword">in</span> files:
+ <span class="keyword">print</span> os.path.join(root, name)
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> os, os.path
+numbytes = 0
+<span class="keyword">for</span> root, dirs, files <span class="keyword">in</span> os.walk(top):
+ <span class="keyword">for</span> name <span class="keyword">in</span> files:
+ path = os.path.join(root, name)
+ numbytes += os.path.getsize(path)
+<span class="keyword">print</span> <span class="string">"%s contains %s bytes"</span> % (top, numbytes)
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> os, os.path
+saved_size, saved_name = -1, <span class="string">''</span>
+<span class="keyword">for</span> root, dirs, files <span class="keyword">in</span> os.walk(top):
+ <span class="keyword">for</span> name <span class="keyword">in</span> files:
+ path = os.path.join(root, name)
+ size = os.path.getsize(path)
+ <span class="keyword">if</span> size &gt; saved_size:
+ saved_size = size
+ saved_name = path
+<span class="keyword">print</span> <span class="string">"Biggest file %s in %s is %s bytes long"</span> % (
+ saved_name, top, saved_size)
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> os, os.path, time
+saved_age, saved_name = <span class="py-pseudo-keyword">None</span>, <span class="string">''</span>
+<span class="keyword">for</span> root, dirs, files <span class="keyword">in</span> os.walk(top):
+ <span class="keyword">for</span> name <span class="keyword">in</span> files:
+ path = os.path.join(root, name)
+ age = os.path.getmtime(path)
+ <span class="keyword">if</span> saved_age <span class="keyword">is</span> <span class="py-pseudo-keyword">None</span> <span class="keyword">or</span> age &gt; saved_age:
+ saved_age = age
+ saved_name = path
+<span class="keyword">print</span> <span class="string">"%s %s"</span> % (saved_name, time.ctime(saved_age))
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment">!/usr/bin/env python
+</span><span class="comment-delimiter"># </span><span class="comment">fdirs - find all directories
+</span><span class="keyword">import</span> sys, os, os.path
+argv = sys.argv[1:] <span class="keyword">or</span> [<span class="string">'.'</span>]
+<span class="keyword">for</span> top <span class="keyword">in</span> argv:
+ <span class="keyword">for</span> root, dirs, files <span class="keyword">in</span> os.walk(top):
+ <span class="keyword">for</span> name <span class="keyword">in</span> dirs:
+ path = os.path.join(root, name)
+ <span class="keyword">print</span> path</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN519"
+>Removing a Directory and Its Contents</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">DeleteDir - remove whole directory trees like rm -r
+</span><span class="keyword">import</span> shutil
+shutil.rmtree(path)
+
+<span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS:
+</span><span class="keyword">import</span> os, sys
+<span class="keyword">def</span> <span class="function-name">DeleteDir</span>(dir):
+ <span class="keyword">for</span> name <span class="keyword">in</span> os.listdir(dir):
+ <span class="py-builtins">file</span> = os.path.join(dir, name)
+ <span class="keyword">if</span> <span class="keyword">not</span> os.path.islink(file) <span class="keyword">and</span> os.path.isdir(file):
+ DeleteDir(file)
+ <span class="keyword">else:</span>
+ os.remove(file)
+ os.rmdir(dir)</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN522"
+>Renaming Files</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">Renaming Files
+</span>
+<span class="comment-delimiter"># </span><span class="comment">code sample one to one from my perlcookbook
+</span><span class="comment-delimiter"># </span><span class="comment">looks strange to me.
+</span><span class="keyword">import</span> os
+<span class="keyword">for</span> fname <span class="keyword">in</span> fnames:
+ newname = fname
+ <span class="comment-delimiter"># </span><span class="comment">change the file's name
+</span> <span class="keyword">try:</span>
+ os.rename(fname, newname)
+ <span class="keyword">except</span> <span class="py-builtins">OSError</span>, err:
+ <span class="keyword">print</span> <span class="string">"Couldn't rename %s to %s: %s!"</span> % \
+ (fname, newfile, err)
+
+<span class="comment-delimiter"># </span><span class="comment">use os.renames if newname needs directory creation.
+</span>
+<span class="comment-delimiter">#</span><span class="comment">A vaguely Pythonic solution is:
+</span><span class="keyword">import</span> glob
+<span class="keyword">def</span> <span class="function-name">rename</span>(files, transfunc)
+ <span class="keyword">for</span> fname <span class="keyword">in</span> fnames:
+ newname = transfunc(fname)
+ <span class="keyword">try:</span>
+ os.rename(fname, newname)
+ <span class="keyword">except</span> <span class="py-builtins">OSError</span>, err:
+ <span class="keyword">print</span> <span class="string">"Couldn't rename %s to %s: %s!"</span> % \
+ (fname, newfile, err)
+
+<span class="keyword">def</span> <span class="function-name">transfunc</span>(fname):
+ <span class="keyword">return</span> fname[:-5]
+rename(glob.glob(<span class="string">"*.orig"</span>), transfunc)
+
+<span class="keyword">def</span> <span class="function-name">transfunc</span>(fname):
+ <span class="keyword">return</span> fname.lower()
+rename([f <span class="keyword">for</span> f <span class="keyword">in</span> glob.glob(<span class="string">"*"</span>) <span class="keyword">if</span> <span class="keyword">not</span> f.startswith(<span class="string">"Make)], transfunc)
+
+def transfunc(fname):
+ return fname + "</span>.bad<span class="string">"
+rename(glob.glob("</span>*.f<span class="string">"), transfunc)
+
+def transfunc(fname):
+ answer = raw_input(fname + "</span>: <span class="string">")
+ if answer.upper().startswith("</span>Y<span class="string">"):
+ return fname.replace("</span>foo<span class="string">", "</span>bar<span class="string">")
+rename(glob.glob("</span>*<span class="string">"), transfunc)
+
+def transfunc(fname):
+ return "</span>.<span class="comment-delimiter">#</span><span class="comment">" + fname[:-1]
+</span>rename(glob.glob(<span class="string">"/tmp/*~"</span>), transfunc)
+
+<span class="comment-delimiter"># </span><span class="comment">This _could_ be made to eval code taken directly from the command line,
+</span><span class="comment-delimiter"># </span><span class="comment">but it would be fragile
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN525"
+>Splitting a Filename into Its Component Parts</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> os
+
+base = os.path.basename(path)
+dirname = os.path.dirname(path)
+dirname, filename = os.path.split(path)
+base, ext = os.path.splitext(filename)
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>path = <span class="string">'/usr/lib/libc.a'</span>
+filename = os.path.basename(path)
+dirname = os.path.dirname(path)
+
+<span class="keyword">print</span> <span class="string">"dir is %s, file is %s"</span> % (dirname, filename)
+<span class="comment-delimiter"># </span><span class="comment">dir is /usr/lib, file is libc.a
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>path = <span class="string">'/usr/lib/libc.a'</span>
+dirname, filename = os.path.split(path)
+name, ext = os.path.splitext(filename)
+
+<span class="keyword">print</span> <span class="string">"dir is %s, name is %s, extension is %s"</span> % (dirname, name, ext)
+<span class="comment-delimiter"># </span><span class="comment">NOTE: The Python code prints
+</span><span class="comment-delimiter"># </span><span class="comment">dir is /usr/lib, name is libc, extension is .a
+</span><span class="comment-delimiter"># </span><span class="comment">while the Perl code prints a '/' after the directory name
+</span><span class="comment-delimiter"># </span><span class="comment">dir is /usr/lib/, name is libc, extension is .a
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> macpath
+path = <span class="string">"Hard%20Drive:System%20Folder:README.txt"</span>
+dirname, base = macpath.split(path)
+name, ext = macpath.splitext(base)
+
+<span class="keyword">print</span> <span class="string">"dir is %s, name is %s, extension is %s"</span> % (dirname, name, ext)
+<span class="comment-delimiter"># </span><span class="comment">dir is Hard%20Drive:System%20Folder, name is README, extension is .txt
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS - it's not portable.
+</span><span class="keyword">def</span> <span class="function-name">extension</span>(path):
+ pos = path.find(<span class="string">"."</span>)
+ <span class="keyword">if</span> pos == -1:
+ <span class="keyword">return</span> <span class="string">""</span>
+ ext = path[pos+1:]
+ <span class="keyword">if</span> <span class="string">"/"</span> <span class="keyword">in</span> ext:
+ <span class="comment-delimiter"># </span><span class="comment">wasn't passed a basename -- this is of the form 'x.y/z'
+</span> <span class="keyword">return</span> <span class="string">""</span>
+ <span class="keyword">return</span> ext
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN528"
+>Program: symirror</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span>
+<span class="comment-delimiter">#</span><span class="comment">!/usr/bin/python
+</span><span class="comment-delimiter"># </span><span class="comment">sysmirror - build spectral forest of symlinks
+</span><span class="keyword">import</span> sys, os, os.path
+
+pgmname = sys.argv[0]
+<span class="keyword">if</span> <span class="py-builtins">len</span>(sys.argv)!=3:
+ <span class="keyword">print</span> <span class="string">"usage: %s realdir mirrordir"</span> % pgmname
+ <span class="keyword">raise</span> <span class="py-builtins">SystemExit</span>
+
+(srcdir, dstdir) = sys.argv[1:3]
+<span class="keyword">if</span> <span class="keyword">not</span> os.path.isdir(srcdir):
+ <span class="keyword">print</span> <span class="string">"%s: %s is not a directory"</span> % (pgmname,srcdir)
+ <span class="keyword">raise</span> <span class="py-builtins">SystemExit</span>
+<span class="keyword">if</span> <span class="keyword">not</span> os.path.isdir(dstdir):
+ <span class="keyword">try:</span>
+ os.mkdir(dstdir)
+ <span class="keyword">except</span> <span class="py-builtins">OSError</span>:
+ <span class="keyword">print</span> <span class="string">"%s: can't make directory %s"</span> % (pgmname,dstdir)
+ <span class="keyword">raise</span> <span class="py-builtins">SystemExit</span>
+
+<span class="comment-delimiter"># </span><span class="comment">fix relative paths
+</span>srcdir = os.path.abspath(srcdir)
+dstdir = os.path.abspath(dstdir)
+
+<span class="keyword">def</span> <span class="function-name">wanted</span>(arg, dirname, names):
+ <span class="keyword">for</span> direntry <span class="keyword">in</span> names:
+ relname = <span class="string">"%s/%s"</span> % (dirname, direntry)
+ <span class="keyword">if</span> os.path.isdir(relname):
+ mode = os.stat(relname).st_mode
+ <span class="keyword">try:</span>
+ os.mkdir(<span class="string">"%s/%s"</span> % (dstdir,relname), mode)
+ <span class="keyword">except:</span>
+ <span class="keyword">print</span> <span class="string">"can't mkdir %s/%s"</span> % (dstdir,relname)
+ <span class="keyword">raise</span> <span class="py-builtins">SystemExit</span>
+ <span class="keyword">else:</span>
+ <span class="keyword">if</span> relname[:2] == <span class="string">"./"</span>:
+ relname = relname[2:]
+ os.symlink(<span class="string">"%s/%s"</span> % (srcdir, relname), <span class="string">"%s/%s"</span> % (dstdir,relname))
+
+os.chdir(srcdir)
+os.path.walk(<span class="string">"."</span>,wanted,<span class="py-pseudo-keyword">None</span>)</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN531"
+>Program: lst</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+></DIV
+><DIV
+CLASS="NAVFOOTER"
+><HR
+ALIGN="LEFT"
+WIDTH="100%"><TABLE
+SUMMARY="Footer navigation table"
+WIDTH="100%"
+BORDER="0"
+CELLPADDING="0"
+CELLSPACING="0"
+><TR
+><TD
+WIDTH="33%"
+ALIGN="left"
+VALIGN="top"
+><A
+HREF="filecontents.html"
+ACCESSKEY="P"
+>Prev</A
+></TD
+><TD
+WIDTH="34%"
+ALIGN="center"
+VALIGN="top"
+><A
+HREF="index.html"
+ACCESSKEY="H"
+>Home</A
+></TD
+><TD
+WIDTH="33%"
+ALIGN="right"
+VALIGN="top"
+><A
+HREF="subroutines.html"
+ACCESSKEY="N"
+>Next</A
+></TD
+></TR
+><TR
+><TD
+WIDTH="33%"
+ALIGN="left"
+VALIGN="top"
+>File Contents</TD
+><TD
+WIDTH="34%"
+ALIGN="center"
+VALIGN="top"
+>&nbsp;</TD
+><TD
+WIDTH="33%"
+ALIGN="right"
+VALIGN="top"
+>Subroutines</TD
+></TR
+></TABLE
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/help/PythonExamples/pleac_python/fileaccess.html b/help/PythonExamples/pleac_python/fileaccess.html
new file mode 100644
index 0000000..0050cb2
--- /dev/null
+++ b/help/PythonExamples/pleac_python/fileaccess.html
@@ -0,0 +1,1107 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML
+><HEAD
+><TITLE
+>File Access</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
+REL="HOME"
+TITLE="PLEAC-Python
+"
+HREF="index.html"><LINK
+REL="PREVIOUS"
+TITLE="Pattern Matching"
+HREF="patternmatching.html"><LINK
+REL="NEXT"
+TITLE="File Contents"
+HREF="filecontents.html"><style type="text/css"> <!--
+ .comment {
+ /* font-lock-comment-face */
+ color: #bebebe;
+ }
+ .comment-delimiter {
+ }
+ .function-name {
+ /* font-lock-function-name-face */
+ color: #b2dfee;
+ }
+ .keyword {
+ /* font-lock-keyword-face */
+ color: #ffa500;
+ }
+ .py-builtins {
+ /* py-builtins-face */
+ color: #ffa500;
+ }
+ .py-pseudo-keyword {
+ /* py-pseudo-keyword-face */
+ color: #ffa500;
+ }
+ .string {
+ /* font-lock-string-face */
+ color: #00cd00;
+ }
+ .type {
+ /* font-lock-type-face */
+ color: #98fb98;
+ }
+ -->
+ </style></head
+><BODY TEXT="#cecece" BGCOLOR="#4f6f6f" LINK="#f5deb3" VLINK="#d5ae83"
+CLASS="SECT1"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><DIV
+CLASS="NAVHEADER"
+><TABLE
+SUMMARY="Header navigation table"
+WIDTH="100%"
+BORDER="0"
+CELLPADDING="0"
+CELLSPACING="0"
+><TR
+><TH
+COLSPAN="3"
+ALIGN="center"
+>PLEAC-Python
+</TH
+></TR
+><TR
+><TD
+WIDTH="10%"
+ALIGN="left"
+VALIGN="bottom"
+><A
+HREF="patternmatching.html"
+ACCESSKEY="P"
+>Prev</A
+></TD
+><TD
+WIDTH="80%"
+ALIGN="center"
+VALIGN="bottom"
+></TD
+><TD
+WIDTH="10%"
+ALIGN="right"
+VALIGN="bottom"
+><A
+HREF="filecontents.html"
+ACCESSKEY="N"
+>Next</A
+></TD
+></TR
+></TABLE
+><HR
+ALIGN="LEFT"
+WIDTH="100%"></DIV
+><DIV
+CLASS="SECT1"
+><H1
+CLASS="SECT1"
+><A
+NAME="FILEACCESS"
+>7. File Access</A
+></H1
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN359"
+>Introduction</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="keyword">for</span> line <span class="keyword">in</span> <span class="py-builtins">open</span>(<span class="string">"/usr/local/widgets/data"</span>):
+ <span class="keyword">if</span> blue <span class="keyword">in</span> line:
+ <span class="keyword">print</span> line[:-1]
+<span class="comment-delimiter">#</span><span class="comment">---------
+</span><span class="keyword">import</span> sys, re
+pattern = re.compile(r<span class="string">"\d"</span>)
+<span class="keyword">for</span> line <span class="keyword">in</span> sys.stdin:
+ <span class="keyword">if</span> <span class="keyword">not</span> pattern.search(line):
+ sys.stderr.write(<span class="string">"No digit found.\n"</span>)
+ sys.stdout.write(<span class="string">"Read: "</span> + line)
+sys.stdout.close()
+<span class="comment-delimiter">#</span><span class="comment">---------
+</span>logfile = <span class="py-builtins">open</span>(<span class="string">"/tmp/log"</span>, <span class="string">"w"</span>)
+<span class="comment-delimiter">#</span><span class="comment">---------
+</span>logfile.close()
+<span class="comment-delimiter">#</span><span class="comment">---------
+</span>print&gt;&gt;logfile, <span class="string">"Countdown initiated ..."</span>
+<span class="keyword">print</span> <span class="string">"You have 30 seconds to reach minimum safety distance."</span>
+
+<span class="comment-delimiter"># </span><span class="comment">DONT DO THIS
+</span><span class="keyword">import</span> sys
+old_output, sys.stdout = sys.stdout, logfile
+<span class="keyword">print</span> <span class="string">"Countdown initiated ..."</span>
+sys.stdout = old_output
+<span class="keyword">print</span> <span class="string">"You have 30 seconds to reach minimum safety distance."</span>
+<span class="comment-delimiter">#</span><span class="comment">---------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN362"
+>Opening a File</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">Python's open() function somewhat covers both perl's open() and
+</span><span class="comment-delimiter"># </span><span class="comment">sysopen() as it has optional arguments for mode and buffering.
+</span>source = <span class="py-builtins">open</span>(path)
+sink = <span class="py-builtins">open</span>(path, <span class="string">"w"</span>)
+<span class="comment-delimiter">#</span><span class="comment">---------
+</span><span class="comment-delimiter"># </span><span class="comment">NOTE: almost no one uses the low-level os.open and os.fdopen
+</span><span class="comment-delimiter"># </span><span class="comment">commands, so their inclusion here is just silly. If
+</span><span class="comment-delimiter"># </span><span class="comment">os.fdopen(os.open(...)) were needed often, it would be turned
+</span><span class="comment-delimiter"># </span><span class="comment">into its own function. Instead, I'll use 'fd' to hint that
+</span><span class="comment-delimiter"># </span><span class="comment">os.open returns a file descriptor
+</span><span class="keyword">import</span> os
+source_fd = os.open(path, os.O_RDONLY)
+source = os.fdopen(fd)
+sink_fd = os.open(path, os.O_WRONLY)
+sink = os.fdopen(sink_fd)
+<span class="comment-delimiter">#</span><span class="comment">---------
+</span>myfile = <span class="py-builtins">open</span>(filename, <span class="string">"w"</span>)
+fd = os.open(filename, os.O_WRONLY | os.O_CREAT)
+myfile = <span class="py-builtins">open</span>(filename, <span class="string">"r+"</span>)
+<span class="comment-delimiter">#</span><span class="comment">---------
+</span>fd = os.open(name, flags)
+fd = os.open(name, flags, mode)
+<span class="comment-delimiter">#</span><span class="comment">---------
+</span>myfile = <span class="py-builtins">open</span>(path)
+fd = os.open(path, os.O_RDONLY)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>myfile = <span class="py-builtins">open</span>(path, <span class="string">"w"</span>)
+fd = os.open(path, os.O_WRONLY|os.O_TRUNC|os.O_CREAT)
+fd = os.open(path, os.O_WRONLY|os.O_TRUNC|os.O_CREAT, 0600)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>fd = os.open(path, os.O_WRONLY|os.O_EXCL|os.O_CREAT)
+fd = os.open(path, os.O_WRONLY|os.O_EXCL|os.O_CREAT, 0600)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>myfile = <span class="py-builtins">open</span>(path, <span class="string">"a"</span>)
+fd = os.open(path, os.O_WRONLY|os.O_APPEND|os.O_CREAT)
+fd = os.open(path, os.O_WRONLY|os.O_APPEND|s.O_CREAT, 0600)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>fd = os.open(path, os.O_WRONLY|os.O_APPEND)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>myfile = <span class="py-builtins">open</span>(path, <span class="string">"rw"</span>)
+fd = os.open(path, os.O_RDWR)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>fd = os.open(path, os.O_RDWR|os.O_CREAT)
+fd = os.open(path, os.O_RDWR|os.O_CREAT, 0600)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>fd = os.open(path, os.O_RDWR|os.O_EXCL|os.O_CREAT)
+fd = os.open(path, os.O_RDWR|os.O_EXCL|os.O_CREAT, 0600)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN365"
+>Opening Files with Unusual Filenames</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">Nothing different needs to be done with Python
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN368"
+>Expanding Tildes in Filenames</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="keyword">import</span> os
+filename = os.path.expanduser(filename)</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN371"
+>Making Perl Report Filenames in Errors</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span>myfile = <span class="py-builtins">open</span>(filename) <span class="comment-delimiter"># </span><span class="comment">raise an exception on error
+</span>
+<span class="keyword">try:</span>
+ myfile = <span class="py-builtins">open</span>(filename)
+<span class="keyword">except</span> <span class="py-builtins">IOError</span>, err:
+ <span class="keyword">raise</span> <span class="py-builtins">AssertionError</span>(<span class="string">"Couldn't open %s for reading : %s"</span> %
+ (filename, err.strerror))</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN374"
+>Creating Temporary Files</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="keyword">import</span> tempfile
+
+myfile = tempfile.TemporaryFile()
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">NOTE: The TemporaryFile() call is much more appropriate
+</span><span class="comment-delimiter"># </span><span class="comment">I would not suggest using this code for real work.
+</span><span class="keyword">import</span> os, tempfile
+
+<span class="keyword">while</span> <span class="py-pseudo-keyword">True</span>:
+ name = os.tmpnam()
+ <span class="keyword">try:</span>
+ fd = os.open(name, os.O_RDWR|os.O_CREAT|os.O_EXCL)
+ <span class="keyword">break</span>
+ <span class="keyword">except</span> os.error:
+ <span class="keyword">pass</span>
+myfile = tempfile.TemporaryFileWrapper(os.fdopen(fd), name)
+
+<span class="comment-delimiter"># </span><span class="comment">now go on to use the file ...
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> os
+<span class="keyword">while</span> <span class="py-pseudo-keyword">True</span>:
+ tmpname = os.tmpnam()
+ fd = os.open(tmpnam, os.O_RDWR | os.O_CREAT | os.O_EXCL)
+ <span class="keyword">if</span> fd:
+ tmpfile = os.fdopen(fd)
+ <span class="keyword">break</span>
+
+os.remove(tmpnam)
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> tempfile
+
+myfile = tempfile.TemporaryFile(bufsize = 0)
+<span class="keyword">for</span> i <span class="keyword">in</span> <span class="py-builtins">range</span>(10):
+ print&gt;&gt;myfile, i
+myfile.seek(0)
+<span class="keyword">print</span> <span class="string">"Tmp file has:"</span>, myfile.read()
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN377"
+>Storing Files Inside Your Program Text</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span>DATA = <span class="string">"""\
+your data goes here
+"""</span>
+<span class="keyword">for</span> line <span class="keyword">in</span> DATA.split(<span class="string">"\n"</span>):
+ <span class="keyword">pass</span> <span class="comment-delimiter"># </span><span class="comment">process the line
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN380"
+>Writing a Filter</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span>
+<span class="keyword">for</span> line <span class="keyword">in</span> sys.stdin:
+ <span class="keyword">pass</span> <span class="comment-delimiter"># </span><span class="comment">do something with the line
+</span>
+<span class="comment-delimiter"># </span><span class="comment">processing a list of files from commandline
+</span><span class="keyword">import</span> fileinput
+<span class="keyword">for</span> line <span class="keyword">in</span> fileinput.input():
+ do something with the line
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> sys
+
+<span class="keyword">def</span> <span class="function-name">do_with</span>(myfile):
+ <span class="keyword">for</span> line <span class="keyword">in</span> myfile:
+ <span class="keyword">print</span> line[:-1]
+
+filenames = sys.argv[1:]
+<span class="keyword">if</span> filenames:
+ <span class="keyword">for</span> filename <span class="keyword">in</span> filenames:
+ <span class="keyword">try:</span>
+ do_with(<span class="py-builtins">open</span>(filename))
+ <span class="keyword">except</span> <span class="py-builtins">IOError</span>, err:
+ sys.stderr.write(<span class="string">"Can't open %s: %s\n"</span> % (filename, err.strerror))
+ <span class="keyword">continue</span>
+<span class="keyword">else:</span>
+ do_with(sys.stdin)
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> sys, glob
+ARGV = sys.argv[1:] <span class="keyword">or</span> glob.glob(<span class="string">"*.[Cch]"</span>)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">NOTE: the getopt module is the prefered mechanism for reading
+</span><span class="comment-delimiter"># </span><span class="comment">command line arguments
+</span><span class="keyword">import</span> sys
+args = sys.argv[1:]
+chop_first = 0
+
+<span class="keyword">if</span> args <span class="keyword">and</span> args[0] == <span class="string">"-c"</span>:
+ chop_first += 1
+ args = args[1:]
+
+<span class="comment-delimiter"># </span><span class="comment">arg demo 2: Process optional -NUMBER flag
+</span>
+<span class="comment-delimiter"># </span><span class="comment">NOTE: You just wouldn't process things this way for Python,
+</span><span class="comment-delimiter"># </span><span class="comment">but I'm trying to preserve the same semantics.
+</span>
+<span class="keyword">import</span> sys, re
+digit_pattern = re.compile(r<span class="string">"-(\d+)$"</span>)
+
+args = sys.argv[1:]
+<span class="keyword">if</span> args:
+ match = digit_pattern.match(args[0])
+ <span class="keyword">if</span> match:
+ columns = <span class="py-builtins">int</span>(match.group(1))
+ args = args[1:]
+
+<span class="comment-delimiter"># </span><span class="comment">NOTE: here's the more idiomatic way, which also checks
+</span><span class="comment-delimiter"># </span><span class="comment">for the "--" or a non "-" argument to stop processing
+</span>
+args = sys.argv[1:]
+<span class="keyword">for</span> i <span class="keyword">in</span> <span class="py-builtins">range</span>(len(args)):
+ arg = args[i]
+ <span class="keyword">if</span> arg == <span class="string">"--"</span> <span class="keyword">or</span> <span class="keyword">not</span> arg.startwith(<span class="string">"-"</span>):
+ <span class="keyword">break</span>
+ <span class="keyword">if</span> arg[1:].isdigit():
+ columns = <span class="py-builtins">int</span>(arg[1:])
+ <span class="keyword">continue</span>
+
+
+
+<span class="comment-delimiter"># </span><span class="comment">arg demo 3: Process clustering -a, -i, -n, or -u flags
+</span><span class="keyword">import</span> sys, getopt
+<span class="keyword">try:</span>
+ args, filenames = getopt.getopt(sys.argv[1:], <span class="string">"ainu"</span>)
+<span class="keyword">except</span> getopt.error:
+ <span class="keyword">raise</span> <span class="py-builtins">SystemExit</span>(<span class="string">"usage: %s [-ainu] [filenames] ..."</span> % sys.argv[0])
+
+append = ignore_ints = nostdout = unbuffer = 0
+<span class="keyword">for</span> k, v <span class="keyword">in</span> args:
+ <span class="keyword">if</span> k == <span class="string">"-a"</span>: append += 1
+ <span class="keyword">elif</span> k == <span class="string">"-i"</span>: ignore_ints += 1
+ <span class="keyword">elif</span> k == <span class="string">"-n"</span>: nostdout += 1
+ <span class="keyword">elif</span> k == <span class="string">"-u"</span>: unbuffer += 1
+ <span class="keyword">else:</span>
+ <span class="keyword">raise</span> <span class="py-builtins">AssertionError</span>(<span class="string">"Unexpected argument: %s"</span> % k)
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Note: Idiomatic Perl get translated to idiomatic Python
+</span><span class="keyword">import</span> fileinput
+<span class="keyword">for</span> line <span class="keyword">in</span> fileinput.input():
+ sys.stdout.write(<span class="string">"%s:%s:%s"</span> %
+ (fileinput.filename(), fileinput.filelineno(), line))
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment">!/usr/bin/env python
+</span><span class="comment-delimiter"># </span><span class="comment">findlogin1 - print all lines containing the string "login"
+</span><span class="keyword">for</span> line <span class="keyword">in</span> fileinput.input(): <span class="comment-delimiter"># </span><span class="comment">loop over files on command line
+</span> <span class="keyword">if</span> line.find(<span class="string">"login"</span>) != -1:
+ sys.stdout.write(line)
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment">!/usr/bin/env python
+</span><span class="comment-delimiter"># </span><span class="comment">lowercase - turn all lines into lowercase
+</span><span class="comment-delimiter">#</span><span class="comment">## NOTE: I don't know how to do locales in Python
+</span><span class="keyword">for</span> line <span class="keyword">in</span> fileinput.input(): <span class="comment-delimiter"># </span><span class="comment">loop over files on command line
+</span> sys.stdout.write(line.lower())
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment">!/usr/bin/env python
+</span><span class="comment-delimiter"># </span><span class="comment">NOTE: The Perl code appears buggy, in that "Q__END__W" is considered
+</span><span class="comment-delimiter"># </span><span class="comment">to be a __END__ and words after the __END__ on the same line
+</span><span class="comment-delimiter"># </span><span class="comment">are included in the count!!!
+</span><span class="comment-delimiter"># </span><span class="comment">countchunks - count how many words are used.
+</span><span class="comment-delimiter"># </span><span class="comment">skip comments, and bail on file if __END__
+</span><span class="comment-delimiter"># </span><span class="comment">or __DATA__ seen.
+</span>chunks = 0
+<span class="keyword">for</span> line <span class="keyword">in</span> fileinput.input():
+ <span class="keyword">for</span> word <span class="keyword">in</span> line.split():
+ <span class="keyword">if</span> word.startswith(<span class="string">"#"</span>):
+ <span class="keyword">continue</span>
+ <span class="keyword">if</span> word <span class="keyword">in</span> (<span class="string">"__DATA__"</span>, <span class="string">"__END__"</span>):
+ fileinput.close()
+ <span class="keyword">break</span>
+ chunks += 1
+<span class="keyword">print</span> <span class="string">"Found"</span>, chunks, <span class="string">"chunks"</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN383"
+>Modifying a File in Place with Temporary File</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="keyword">import</span> shutil
+
+old = <span class="py-builtins">open</span>(<span class="string">"old"</span>)
+new = <span class="py-builtins">open</span>(<span class="string">"new"</span>,<span class="string">"w"</span>)
+
+<span class="keyword">for</span> line <span class="keyword">in</span> old:
+ new.writeline(line)
+new.close()
+old.close()
+
+shutil.copyfile(<span class="string">"old"</span>, <span class="string">"old.orig"</span>)
+shutil.copyfile(<span class="string">"new"</span>, <span class="string">"old"</span>)
+
+<span class="comment-delimiter"># </span><span class="comment">insert lines at line 20:
+</span><span class="keyword">for</span> i, line <span class="keyword">in</span> <span class="py-builtins">enumerate</span>(old):
+ <span class="keyword">if</span> i == 20:
+ print&gt;&gt;new, <span class="string">"Extra line 1\n"</span>
+ print&gt;&gt;new, <span class="string">"Extra line 2\n"</span>
+ print&gt;&gt;new, line
+
+
+<span class="comment-delimiter"># </span><span class="comment">or delete lines 20 through 30:
+</span><span class="keyword">for</span> i, line <span class="keyword">in</span> <span class="py-builtins">enumerate</span>(old):
+ <span class="keyword">if</span> 20 &lt;= i &lt;= 30:
+ <span class="keyword">continue</span>
+ print&gt;&gt;new, line</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN386"
+>Modifying a File in Place with -i Switch</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">modifying with "-i" commandline switch is a perl feature
+</span><span class="comment-delimiter"># </span><span class="comment">python has fileinput
+</span><span class="keyword">import</span> fileinput, sys, time
+today = time.strftime(<span class="string">"%Y-%m-%d"</span>,time.localtime())
+<span class="keyword">for</span> line <span class="keyword">in</span> fileinput.input(inplace=1, backup=<span class="string">".orig"</span>):
+ sys.stdout.write(line.replace(<span class="string">"DATE"</span>,today))
+
+<span class="comment-delimiter"># </span><span class="comment">set up to iterate over the *.c files in the current directory,
+</span><span class="comment-delimiter"># </span><span class="comment">editing in place and saving the old file with a .orig extension.
+</span><span class="keyword">import</span> glob, re
+match = re.compile(<span class="string">"(?&lt;=[pP])earl"</span>)
+files = fileinput.FileInput(glob.glob(<span class="string">"*.c"</span>), inplace=1, backup=<span class="string">".orig"</span>)
+<span class="keyword">while</span> <span class="py-pseudo-keyword">True</span>:
+ line = files.readline()
+ sys.stderr.write(line)
+ <span class="keyword">if</span> <span class="keyword">not</span> line:
+ <span class="keyword">break</span>
+ <span class="keyword">if</span> files.isfirstline():
+ sys.stdout.write(<span class="string">"This line should appear at the top of each file\n"</span>)
+ sys.stdout.write(match.sub(<span class="string">"erl"</span>,line))</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN389"
+>Modifying a File in Place Without a Temporary File</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>myfile = <span class="py-builtins">open</span>(filename, <span class="string">"r+"</span>)
+data = myfile.read()
+<span class="comment-delimiter"># </span><span class="comment">change data here
+</span>myfile.seek(0, 0)
+myfile.write(data)
+myfile.truncate(myfile.tell())
+myfile.close()
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>myfile = <span class="py-builtins">open</span>(filename, <span class="string">"r+"</span>)
+data = [process(line) <span class="keyword">for</span> line <span class="keyword">in</span> myfile]
+myfile.seek(0, 0)
+myfile.writelines(data)
+myfile.truncate(myfile.tell())
+myfile.close()
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN392"
+>Locking a File</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span>
+<span class="keyword">import</span> fcntl
+myfile = <span class="py-builtins">open</span>(somepath, <span class="string">'r+'</span>)
+fcntl.flock(myfile, fcntl.LOCK_EX)
+<span class="comment-delimiter"># </span><span class="comment">update file, then...
+</span>myfile.close()
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>fcntl.LOCK_SH
+fcntl.LOCK_EX
+fcntl.LOCK_NB
+fcntl.LOCK_UN
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> warnings
+<span class="keyword">try:</span>
+ fcntl.flock(myfile, fcntl.LOCK_EX|fcntl.LOCK_NB)
+<span class="keyword">except</span> <span class="py-builtins">IOError</span>:
+ warnings.warn(<span class="string">"can't immediately write-lock the file ($!), blocking ..."</span>)
+ fcntl.flock(myfile, fcntl.LOCK_EX)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>fcntl.flock(myfile, fcntl.LOCK_UN)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">option "r+" instead "w+" stops python from truncating the file on opening
+</span><span class="comment-delimiter"># </span><span class="comment">when another process might well hold an advisory exclusive lock on it.
+</span>myfile = <span class="py-builtins">open</span>(somepath, <span class="string">"r+"</span>)
+fcntl.flock(myfile, fcntl.LOCK_EX)
+myfile.seek(0, 0)
+myfile.truncate(0)
+print&gt;&gt;myfile, <span class="string">"\n"</span> <span class="comment-delimiter"># </span><span class="comment">or myfile.write("\n")
+</span>myfile.close()
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN395"
+>Flushing Output</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">Python doesn't have command buffering. Files can have buffering set,
+</span><span class="comment-delimiter"># </span><span class="comment">when opened:
+</span>myfile = <span class="py-builtins">open</span>(filename, <span class="string">"r"</span>, buffering=0) <span class="comment-delimiter">#</span><span class="comment">Unbuffered
+</span>myfile = <span class="py-builtins">open</span>(filename, <span class="string">"r"</span>, buffering=1) <span class="comment-delimiter">#</span><span class="comment">Line buffered
+</span>myfile = <span class="py-builtins">open</span>(filename, <span class="string">"r"</span>, buffering=100) <span class="comment-delimiter">#</span><span class="comment">Use buffer of (approx) 100 bytes
+</span>myfile = <span class="py-builtins">open</span>(filename, <span class="string">"r"</span>, buffering=-1) <span class="comment-delimiter">#</span><span class="comment">Use system default
+</span>
+myfile.flush() <span class="comment-delimiter"># </span><span class="comment">Flush the I/O buffer
+</span>
+<span class="comment-delimiter"># </span><span class="comment">stdout is treated as a file. If you ever need to flush it, do so:
+</span><span class="keyword">import</span> sys
+sys.stdout.flush()
+
+<span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS. Use urllib, etc.
+</span><span class="keyword">import</span> socket
+mysock = socket.socket()
+mysock.connect((<span class="string">'www.perl.com'</span>, 80))
+<span class="comment-delimiter"># </span><span class="comment">mysock.setblocking(True)
+</span>mysock.send(<span class="string">"GET /index.html http/1.1\n\n"</span>)
+f = mysock.makefile()
+<span class="keyword">print</span> <span class="string">"Doc is:"</span>
+<span class="keyword">for</span> line <span class="keyword">in</span> f:
+ <span class="keyword">print</span> line[:-1]</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN398"
+>Reading from Many Filehandles Without Blocking</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="keyword">import</span> select
+<span class="keyword">while</span> <span class="py-pseudo-keyword">True</span>:
+ rlist, wlist, xlist = select.select([file1, file2, file3], [], [], 0)
+ <span class="keyword">for</span> r <span class="keyword">in</span> rlist:
+ <span class="keyword">pass</span> <span class="comment-delimiter"># </span><span class="comment">Do something with the file handle
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN401"
+>Doing Non-Blocking I/O</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+>Use select.poll() on Unix systems.
+</span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN404"
+>Determining the Number of Bytes to Read</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN407"
+>Storing Filehandles in Variables</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">NOTE: this is all much easier in Python
+</span><span class="keyword">def</span> <span class="function-name">subroutine</span>(myfile):
+ print&gt;&gt;myfile, <span class="string">"Hello, file"</span>
+
+variable = myfile
+subroutine(variable)</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN410"
+>Caching Open Output Filehandles</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN413"
+>Printing to Many Filehandles Simultaneously</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="keyword">for</span> myfile <span class="keyword">in</span> files:
+ print&gt;&gt;myfile, stuff_to_print
+
+<span class="comment-delimiter"># </span><span class="comment">NOTE: This is unix specific
+</span><span class="keyword">import</span> os
+<span class="py-builtins">file</span> = os.popen(<span class="string">"tee file1 file2 file3 &gt;/dev/null"</span>, <span class="string">"w"</span>)
+print&gt;&gt;myfile, <span class="string">"whatever"</span>
+
+<span class="comment-delimiter"># </span><span class="comment">NOTE: the "make STDOUT go to three files" is bad programming style
+</span><span class="keyword">import</span> os, sys
+sys.stdout.file = os.popen(<span class="string">"tee file1 file2 file3"</span>, <span class="string">"w"</span>)
+<span class="keyword">print</span> <span class="string">"whatever"</span>
+sys.stdout.close()
+
+<span class="comment-delimiter"># </span><span class="comment">You could use a utility object to redirect writes:
+</span><span class="keyword">class</span> <span class="type">FileDispatcher</span>(object):
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>, *files):
+ <span class="py-pseudo-keyword">self</span>.files = files
+
+ <span class="keyword">def</span> <span class="function-name">write</span>(<span class="py-pseudo-keyword">self</span>, msg):
+ <span class="keyword">for</span> f <span class="keyword">in</span> <span class="py-pseudo-keyword">self</span>.files:
+ f.write(msg)
+
+ <span class="keyword">def</span> <span class="function-name">close</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="keyword">for</span> f <span class="keyword">in</span> <span class="py-pseudo-keyword">self</span>.files:
+ f.close()
+
+x = <span class="py-builtins">open</span>(<span class="string">"C:/test1.txt"</span>, <span class="string">"w"</span>)
+y = <span class="py-builtins">open</span>(<span class="string">"C:/test2.txt"</span>, <span class="string">"w"</span>)
+z = <span class="py-builtins">open</span>(<span class="string">"C:/test3.txt"</span>, <span class="string">"w"</span>)
+
+fd = FileDispatcher(x, y, z)
+print&gt;&gt;fd, <span class="string">"Foo"</span> <span class="comment-delimiter"># </span><span class="comment">equiv to fd.write("Foo"); fd.write("\n")
+</span>print&gt;&gt;fd, <span class="string">"Testing"</span>
+fd.close()</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN416"
+>Opening and Closing File Descriptors by Number</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="keyword">import</span> os
+myfile = os.fdopen(fdnum) <span class="comment-delimiter"># </span><span class="comment">open the descriptor itself
+</span>myfile = os.fdopen(os.dup(fdnum)) <span class="comment-delimiter"># </span><span class="comment">open to a copy of the descriptor
+</span>
+<span class="comment-delimiter">#</span><span class="comment">##
+</span>outcopy = os.fdopen(os.dup(sys.stdin.fileno()), <span class="string">"w"</span>)
+incopy = os.fdopen(os.dup(sys.stdin.fileno()), <span class="string">"r"</span>)</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN419"
+>Copying Filehandles</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span>original = <span class="py-builtins">open</span>(<span class="string">"C:/test.txt"</span>)
+alias = original
+alias.close()
+<span class="keyword">print</span> original.closed
+<span class="comment-delimiter">#</span><span class="comment">=&gt;True
+</span>
+<span class="keyword">import</span> copy
+
+original = <span class="py-builtins">open</span>(<span class="string">"C:/test.txt"</span>)
+dupe = copy.copy(original)
+dupe.close()
+<span class="keyword">print</span> original.closed
+<span class="comment-delimiter">#</span><span class="comment">=&gt;False
+</span>
+<span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS.
+</span><span class="keyword">import</span> sys
+oldstderr = sys.stderr
+oldstdout = sys.stdout
+
+sys.stderr = <span class="py-builtins">open</span>(<span class="string">"C:/stderrfile.txt"</span>)
+sys.stdout = <span class="py-builtins">open</span>(<span class="string">"C:/stdoutfile.txt"</span>)
+
+<span class="keyword">print</span> <span class="string">"Blah"</span> <span class="comment-delimiter"># </span><span class="comment">Will be written to C:/stdoutfile.txt
+</span>sys.stdout.close()
+
+sys.stdout = oldstdout
+sys.stderr = oldstderr</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN422"
+>Program: netlock</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN425"
+>Program: lockarea</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">On Windows:
+</span><span class="keyword">import</span> msvcrt
+myfile.seek(5, 0)
+msvcrt.locking(myfile.fileno(), msvcrt.LK_NBLCK, 3)
+
+<span class="comment-delimiter"># </span><span class="comment">On Unix:
+</span><span class="keyword">import</span> fcntl
+fcntl.lockf(myfile.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB, 3, 5)</PRE
+></TD
+></TR
+></TABLE
+></DIV
+></DIV
+><DIV
+CLASS="NAVFOOTER"
+><HR
+ALIGN="LEFT"
+WIDTH="100%"><TABLE
+SUMMARY="Footer navigation table"
+WIDTH="100%"
+BORDER="0"
+CELLPADDING="0"
+CELLSPACING="0"
+><TR
+><TD
+WIDTH="33%"
+ALIGN="left"
+VALIGN="top"
+><A
+HREF="patternmatching.html"
+ACCESSKEY="P"
+>Prev</A
+></TD
+><TD
+WIDTH="34%"
+ALIGN="center"
+VALIGN="top"
+><A
+HREF="index.html"
+ACCESSKEY="H"
+>Home</A
+></TD
+><TD
+WIDTH="33%"
+ALIGN="right"
+VALIGN="top"
+><A
+HREF="filecontents.html"
+ACCESSKEY="N"
+>Next</A
+></TD
+></TR
+><TR
+><TD
+WIDTH="33%"
+ALIGN="left"
+VALIGN="top"
+>Pattern Matching</TD
+><TD
+WIDTH="34%"
+ALIGN="center"
+VALIGN="top"
+>&nbsp;</TD
+><TD
+WIDTH="33%"
+ALIGN="right"
+VALIGN="top"
+>File Contents</TD
+></TR
+></TABLE
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/help/PythonExamples/pleac_python/filecontents.html b/help/PythonExamples/pleac_python/filecontents.html
new file mode 100644
index 0000000..fa26ebc
--- /dev/null
+++ b/help/PythonExamples/pleac_python/filecontents.html
@@ -0,0 +1,1191 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML
+><HEAD
+><TITLE
+>File Contents</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
+REL="HOME"
+TITLE="PLEAC-Python
+"
+HREF="index.html"><LINK
+REL="PREVIOUS"
+TITLE="File Access"
+HREF="fileaccess.html"><LINK
+REL="NEXT"
+TITLE="Directories"
+HREF="directories.html"><style type="text/css"> <!--
+ .comment {
+ /* font-lock-comment-face */
+ color: #bebebe;
+ }
+ .comment-delimiter {
+ }
+ .function-name {
+ /* font-lock-function-name-face */
+ color: #b2dfee;
+ }
+ .keyword {
+ /* font-lock-keyword-face */
+ color: #ffa500;
+ }
+ .py-builtins {
+ /* py-builtins-face */
+ color: #ffa500;
+ }
+ .py-pseudo-keyword {
+ /* py-pseudo-keyword-face */
+ color: #ffa500;
+ }
+ .string {
+ /* font-lock-string-face */
+ color: #00cd00;
+ }
+ .type {
+ /* font-lock-type-face */
+ color: #98fb98;
+ }
+ -->
+ </style></head
+><BODY TEXT="#cecece" BGCOLOR="#4f6f6f" LINK="#f5deb3" VLINK="#d5ae83"
+CLASS="SECT1"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><DIV
+CLASS="NAVHEADER"
+><TABLE
+SUMMARY="Header navigation table"
+WIDTH="100%"
+BORDER="0"
+CELLPADDING="0"
+CELLSPACING="0"
+><TR
+><TH
+COLSPAN="3"
+ALIGN="center"
+>PLEAC-Python
+</TH
+></TR
+><TR
+><TD
+WIDTH="10%"
+ALIGN="left"
+VALIGN="bottom"
+><A
+HREF="fileaccess.html"
+ACCESSKEY="P"
+>Prev</A
+></TD
+><TD
+WIDTH="80%"
+ALIGN="center"
+VALIGN="bottom"
+></TD
+><TD
+WIDTH="10%"
+ALIGN="right"
+VALIGN="bottom"
+><A
+HREF="directories.html"
+ACCESSKEY="N"
+>Next</A
+></TD
+></TR
+></TABLE
+><HR
+ALIGN="LEFT"
+WIDTH="100%"></DIV
+><DIV
+CLASS="SECT1"
+><H1
+CLASS="SECT1"
+><A
+NAME="FILECONTENTS"
+>8. File Contents</A
+></H1
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN430"
+>Introduction</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">for</span> line <span class="keyword">in</span> DATAFILE:
+ line = line.rstrip()
+ size = <span class="py-builtins">len</span>(line)
+ <span class="keyword">print</span> size <span class="comment-delimiter"># </span><span class="comment">output size of line
+</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">for</span> line <span class="keyword">in</span> datafile:
+ <span class="keyword">print</span> length(line.rstrip()) <span class="comment-delimiter"># </span><span class="comment">output size of line
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>lines = datafile.readlines()
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>whole_file = myfile.read()
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment"># No direct equivalent in Python
+</span><span class="comment-delimiter">#</span><span class="comment">% perl -040 -e '$word = &lt;&gt;; print "First word is $word\n";'
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment"># No direct equivalent in Python
+</span><span class="comment-delimiter">#</span><span class="comment">% perl -ne 'BEGIN { $/="%%\n" } chomp; print if /Unix/i' fortune.dat
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>print&gt;&gt;myfile, <span class="string">"One"</span>, <span class="string">"two"</span>, <span class="string">"three"</span> <span class="comment-delimiter"># </span><span class="comment">"One two three"
+</span><span class="keyword">print</span> <span class="string">"Baa baa black sheep."</span> <span class="comment-delimiter"># </span><span class="comment">Sent to default output file
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="py-builtins">buffer</span> = myfile.read(4096)
+rv = <span class="py-builtins">len</span>(buffer)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>myfile.truncate(length)
+<span class="py-builtins">open</span>(<span class="string">"/tmp/%d.pid"</span> % os.getpid(), <span class="string">"a"</span>).truncate(length)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>pos = myfile.tell()
+<span class="keyword">print</span> <span class="string">"I'm"</span>, pos, <span class="string">"bytes from the start of DATAFILE."</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>logfile.seek(0, 2) <span class="comment-delimiter"># </span><span class="comment">Seek to the end
+</span>datafile.seek(pos) <span class="comment-delimiter"># </span><span class="comment">Seek to a given byte
+</span>outfile.seek(-20, 1) <span class="comment-delimiter"># </span><span class="comment">Seek back 20 bytes
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>written = os.write(datafile.fileno(), mystr)
+<span class="keyword">if</span> written != <span class="py-builtins">len</span>(mystr):
+ warnings.warn(<span class="string">"only read %s bytes, not %s"</span> % (written, <span class="py-builtins">len</span>(mystr)))
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>pos = os.lseek(myfile.fileno(), 0, 1) <span class="comment-delimiter"># </span><span class="comment">don't change position
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>
+ </PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN433"
+>Reading Lines with Continuation Characters</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="keyword">def</span> <span class="function-name">ContReader</span>(infile):
+ lines = []
+ <span class="keyword">for</span> line <span class="keyword">in</span> infile:
+ line = line.rstrip()
+ <span class="keyword">if</span> line.endswith(<span class="string">"\\"</span>):
+ lines.append(line[:-1])
+ <span class="keyword">continue</span>
+ lines.append(line)
+ <span class="keyword">yield</span> <span class="string">""</span>.join(lines)
+ lines = []
+ <span class="keyword">if</span> lines:
+ <span class="keyword">yield</span> <span class="string">""</span>.join(lines)
+
+<span class="keyword">for</span> line <span class="keyword">in</span> ContReader(datafile):
+ <span class="keyword">pass</span> <span class="comment-delimiter"># </span><span class="comment">process full record in 'line' here
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN436"
+>Counting Lines (or Paragraphs or Records) in a File</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="keyword">import</span> os
+count = <span class="py-builtins">int</span>(os.popen(<span class="string">"wc -l &lt; "</span> + filename).read())
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">for</span> count, line <span class="keyword">in</span> <span class="py-builtins">enumerate</span>(open(filename)):
+ <span class="keyword">pass</span>
+count += 1 <span class="comment-delimiter"># </span><span class="comment">indexing is zero based
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>myfile = <span class="py-builtins">open</span>(filename)
+count = 0
+<span class="keyword">for</span> line <span class="keyword">in</span> myfile:
+ count += 1
+<span class="comment-delimiter"># </span><span class="comment">'count' now holds the number of lines read
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>myfile = <span class="py-builtins">open</span>(filename)
+count = 0
+<span class="keyword">while</span> <span class="py-pseudo-keyword">True</span>:
+ line = myfile.readline()
+ <span class="keyword">if</span> <span class="keyword">not</span> line:
+ <span class="keyword">break</span>
+ count += 1
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>count = 0
+<span class="keyword">while</span> <span class="py-pseudo-keyword">True</span>:
+ s = myfile.read(2**16)
+ count += s.count(<span class="string">"\n"</span>)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">for</span> line, count <span class="keyword">in</span> <span class="py-builtins">zip</span>(open(filename), <span class="py-builtins">xrange</span>(1, sys.maxint)):
+ <span class="keyword">pass</span>
+<span class="comment-delimiter"># </span><span class="comment">'count' now holds the number of lines read
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> fileinput
+fi = fileinput.FileInput(filename)
+<span class="keyword">while</span> fi.readline(): <span class="keyword">pass</span>
+
+count = fi.lineno()
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">def</span> <span class="function-name">SepReader</span>(infile, sep = <span class="string">"\n\n"</span>):
+ text = infile.read(10000)
+ <span class="keyword">if</span> <span class="keyword">not</span> text:
+ <span class="keyword">return</span>
+ <span class="keyword">while</span> <span class="py-pseudo-keyword">True</span>:
+ fields = text.split(sep)
+ <span class="keyword">for</span> field <span class="keyword">in</span> fields[:-1]:
+ <span class="keyword">yield</span> field
+ text = fields[-1]
+ new_text = infile.read(10000)
+ <span class="keyword">if</span> <span class="keyword">not</span> new_text:
+ <span class="keyword">yield</span> text
+ <span class="keyword">break</span>
+ text += new_text
+
+para_count = 0
+<span class="keyword">for</span> para <span class="keyword">in</span> SepReader(<span class="py-builtins">open</span>(filename)):
+ para_count += 1
+<span class="comment-delimiter"># </span><span class="comment">FIXME: For my test case (Python-pre2.2 README from CVS) this
+</span><span class="comment-delimiter"># </span><span class="comment">returns 175 paragraphs while Perl returns 174.
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>
+ </PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN439"
+>Processing Every Word in a File</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="keyword">for</span> line <span class="keyword">in</span> sys.stdin:
+ <span class="keyword">for</span> word <span class="keyword">in</span> line.split():
+ <span class="keyword">pass</span> <span class="comment-delimiter"># </span><span class="comment">do something with 'chunk'
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>pat = re.compile(r<span class="string">"(\w[\w'-]*)"</span>)
+<span class="keyword">for</span> line <span class="keyword">in</span> sys.stdin:
+ pos = 0
+ <span class="keyword">while</span> <span class="py-pseudo-keyword">True</span>:
+ match = pat.search(line, pos)
+ <span class="keyword">if</span> <span class="keyword">not</span> match:
+ <span class="keyword">break</span>
+ pos = match.end(1)
+ <span class="comment-delimiter"># </span><span class="comment">do something with match.group(1)
+</span>
+<span class="comment-delimiter"># </span><span class="comment">EXPERIMENTAL in the sre implementation but
+</span><span class="comment-delimiter"># </span><span class="comment">likely to be included in future (post-2.2) releases.
+</span>pat = re.compile(r<span class="string">"(\w[\w'-]*)"</span>)
+<span class="keyword">for</span> line <span class="keyword">in</span> sys.stdin:
+ scanner = pat.scanner(line)
+ <span class="keyword">while</span> <span class="py-pseudo-keyword">True</span>:
+ match = scanner.search()
+ <span class="keyword">if</span> <span class="keyword">not</span> match:
+ <span class="keyword">break</span>
+ <span class="comment-delimiter"># </span><span class="comment">do something with match.group(1)
+</span>
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Make a word frequency count
+</span><span class="keyword">import</span> fileinput, re
+pat = re.compile(r<span class="string">"(\w[\w'-]*)"</span>)
+seen = {}
+<span class="keyword">for</span> line <span class="keyword">in</span> fileinput.input():
+ pos = 0
+ <span class="keyword">while</span> <span class="py-pseudo-keyword">True</span>:
+ match = pat.search(line, pos)
+ <span class="keyword">if</span> <span class="keyword">not</span> match:
+ <span class="keyword">break</span>
+ pos = match.end(1)
+ text = match.group(1).lower()
+ seen[text] = seen.get(text, 0) + 1
+
+<span class="comment-delimiter"># </span><span class="comment">output dict in a descending numeric sort of its values
+</span><span class="keyword">for</span> text, count <span class="keyword">in</span> sorted(seen.items, key=<span class="keyword">lambda</span> item: item[1]):
+ <span class="keyword">print</span> <span class="string">"%5d %s"</span> % (count, text)
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Line frequency count
+</span><span class="keyword">import</span> fileinput, sys
+seen = {}
+<span class="keyword">for</span> line <span class="keyword">in</span> fileinput.input():
+ text = line.lower()
+ seen[text] = seen.get(text, 0) + 1
+
+<span class="keyword">for</span> text, count <span class="keyword">in</span> sorted(seen.items, key=<span class="keyword">lambda</span> item: item[1]):
+ sys.stdout.write(<span class="string">"%5d %s"</span> % (count, text))
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>
+ </PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN442"
+>Reading a File Backwards by Line or Paragraph</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span>lines = myfile.readlines()
+<span class="keyword">while</span> lines:
+ line = lines.pop()
+ <span class="comment-delimiter"># </span><span class="comment">do something with 'line'
+</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">for</span> line <span class="keyword">in</span> reversed(myfile):
+ <span class="keyword">pass</span> <span class="comment-delimiter"># </span><span class="comment">do something with line
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">for</span> i <span class="keyword">in</span> <span class="py-builtins">range</span>(len(lines)):
+ line = lines[-i]
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">for</span> paragraph <span class="keyword">in</span> sorted(SepReader(infile)):
+ <span class="keyword">pass</span> <span class="comment-delimiter"># </span><span class="comment">do something
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>
+ </PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN445"
+>Trailing a Growing File</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="keyword">import</span> time
+<span class="keyword">while</span> <span class="py-pseudo-keyword">True</span>:
+ <span class="keyword">for</span> line <span class="keyword">in</span> infile:
+ <span class="keyword">pass</span> <span class="comment-delimiter"># </span><span class="comment">do something with the line
+</span> time.sleep(SOMETIME)
+ infile.seek(0, 1)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> time
+naptime = 1
+
+logfile = <span class="py-builtins">open</span>(<span class="string">"/tmp/logfile"</span>)
+<span class="keyword">while</span> <span class="py-pseudo-keyword">True</span>:
+ <span class="keyword">for</span> line <span class="keyword">in</span> logfile:
+ <span class="keyword">print</span> line.rstrip()
+ time.sleep(naptime)
+ infile.seek(0, 1)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">while</span> <span class="py-pseudo-keyword">True</span>:
+ curpos = logfile.tell()
+ <span class="keyword">while</span> <span class="py-pseudo-keyword">True</span>:
+ line = logfile.readline()
+ <span class="keyword">if</span> <span class="keyword">not</span> line:
+ <span class="keyword">break</span>
+ curpos = logfile.tell()
+ sleep(naptime)
+ logfile.seek(curpos, 0) <span class="comment-delimiter"># </span><span class="comment">seek to where we had been
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> os
+<span class="keyword">if</span> os.stat(LOGFILENAME).st_nlink == 0:
+ <span class="keyword">raise</span> <span class="py-builtins">SystemExit</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>
+ </PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN448"
+>Picking a Random Line from a File</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="keyword">import</span> random, fileinput
+text = <span class="py-pseudo-keyword">None</span>
+<span class="keyword">for</span> line <span class="keyword">in</span> fileinput.input():
+ <span class="keyword">if</span> random.randrange(fileinput.lineno()) == 0:
+ text = line
+<span class="comment-delimiter"># </span><span class="comment">'text' is the random line
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">XXX is the perl code correct? Where is the fortunes file opened?
+</span><span class="keyword">import</span> sys
+adage = <span class="py-pseudo-keyword">None</span>
+<span class="keyword">for</span> i, rec <span class="keyword">in</span> <span class="py-builtins">enumerate</span>(SepReader(<span class="py-builtins">open</span>(<span class="string">"/usr/share/games/fortunes"</span>), <span class="string">"%\n"</span>)):
+ <span class="keyword">if</span> random.randrange(i+1) == 0:
+ adage = rec
+<span class="keyword">print</span> adage
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>
+ </PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN451"
+>Randomizing All Lines</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="keyword">import</span> random
+lines = data.readlines()
+random.shuffle(lines)
+<span class="keyword">for</span> line <span class="keyword">in</span> lines:
+ <span class="keyword">print</span> line.rstrip()
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>
+ </PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN454"
+>Reading a Particular Line in a File</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">using efficient caching system
+</span><span class="keyword">import</span> linecache
+linecache.getline(filename, DESIRED_LINE_NUMBER)
+
+<span class="comment-delimiter"># </span><span class="comment">or doing it more oldskool
+</span>lineno = 0
+<span class="keyword">while</span> <span class="py-pseudo-keyword">True</span>:
+ line = infile.readline()
+ <span class="keyword">if</span> <span class="keyword">not</span> line <span class="keyword">or</span> lineno == DESIRED_LINE_NUMBER:
+ <span class="keyword">break</span>
+ lineno += 1
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>lines = infile.readlines()
+line = lines[DESIRED_LINE_NUMBER]
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">for</span> i <span class="keyword">in</span> <span class="py-builtins">range</span>(DESIRED_LINE_NUMBER):
+ line = infile.readline()
+ <span class="keyword">if</span> <span class="keyword">not</span> line:
+ <span class="keyword">break</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>
+<span class="comment-delimiter">#</span><span class="comment"># Not sure what this thing is doing. Allow fast access to a given
+</span><span class="comment-delimiter">#</span><span class="comment"># line number?
+</span>
+<span class="comment-delimiter"># </span><span class="comment">usage: build_index(*DATA_HANDLE, *INDEX_HANDLE)
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN457"
+>Processing Variable-Length Text Fields</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">given $RECORD with field separated by PATTERN,
+</span><span class="comment-delimiter"># </span><span class="comment">extract @FIELDS.
+</span>fields = re.split(pattern_string, text)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>pat = re.compile(pattern_string)
+fields = pat.split(text)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>re.split(r<span class="string">"([+-])"</span>, <span class="string">"3+5-2"</span>)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>[3, <span class="string">'+'</span>, 5, <span class="string">'-'</span>, 2]
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>fields = record.split(<span class="string">":"</span>)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>fields = re.split(r<span class="string">":"</span>, record)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>fields = re.split(r<span class="string">"\s+"</span>, record)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>fields = record.split(<span class="string">" "</span>)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>
+ </PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN460"
+>Removing the Last Line of a File</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span>myfile = <span class="py-builtins">open</span>(filename, <span class="string">"r"</span>)
+prev_pos = pos = 0
+<span class="keyword">while</span> <span class="py-pseudo-keyword">True</span>:
+ line = myfile.readline()
+ <span class="keyword">if</span> <span class="keyword">not</span> line:
+ <span class="keyword">break</span>
+ prev_pos = pos
+ pos = myfile.tell()
+myfile = <span class="py-builtins">open</span>(filename, <span class="string">"a"</span>)
+myfile.truncate(prev_pos)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>
+ </PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN463"
+>Processing Binary Files</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="py-builtins">open</span>(filename, <span class="string">"rb"</span>)
+<span class="py-builtins">open</span>(filename, <span class="string">"wb"</span>)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>gifname = <span class="string">"picture.gif"</span>
+gif_file = <span class="py-builtins">open</span>(gifname, <span class="string">"rb"</span>)
+
+<span class="comment-delimiter"># </span><span class="comment">Don't think there's an equivalent for these in Python
+</span><span class="comment-delimiter">#</span><span class="comment">binmode(GIF); # now DOS won't mangle binary input from GIF
+</span><span class="comment-delimiter">#</span><span class="comment">binmode(STDOUT); # now DOS won't mangle binary output to STDOUT
+</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">while</span> <span class="py-pseudo-keyword">True</span>:
+ buff = gif.read(8 * 2**10)
+ <span class="keyword">if</span> <span class="keyword">not</span> buff:
+ <span class="keyword">break</span>
+ sys.stdout.write(buff)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>
+ </PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN466"
+>Using Random-Access I/O</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span>address = recsize * recno
+myfile.seek(address, 0)
+<span class="py-builtins">buffer</span> = myfile.read(recsize)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>address = recsize * (recno-1)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>
+ </PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN469"
+>Updating a Random-Access File</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="keyword">import</span> posixfile
+address = recsize * recno
+myfile.seek(address)
+<span class="py-builtins">buffer</span> = myfile.read(recsize)
+<span class="comment-delimiter"># </span><span class="comment">... work with the buffer, then turn it back into a string and ...
+</span>myfile.seek(-recsize, posixfile.SEEK_CUR)
+myfile.write(buffer)
+myfile.close()
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment"># Not yet implemented
+</span><span class="comment-delimiter"># </span><span class="comment">weekearly -- set someone's login date back a week
+</span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN472"
+>Reading a String from a Binary File</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment"># Note: this isn't optimal -- the 's+=c' may go O(N**2) so don't
+</span><span class="comment-delimiter">#</span><span class="comment"># use for large strings.
+</span>myfile.seek(addr)
+s = <span class="string">""</span>
+<span class="keyword">while</span> <span class="py-pseudo-keyword">True</span>:
+ c = myfile.read(1)
+ <span class="keyword">if</span> <span class="keyword">not</span> c <span class="keyword">or</span> c == <span class="string">"\0"</span>:
+ <span class="keyword">break</span>
+ s += c
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>myfile.seek(addr)
+offset = 0
+<span class="keyword">while</span> <span class="py-pseudo-keyword">True</span>:
+ s = myfile.read(1000)
+ x = s.find(<span class="string">"\0"</span>)
+ <span class="keyword">if</span> x != -1:
+ offset += x
+ <span class="keyword">break</span>
+ offset += <span class="py-builtins">len</span>(s)
+ <span class="keyword">if</span> <span class="py-builtins">len</span>(s) != 1000: <span class="comment-delimiter"># </span><span class="comment">EOF
+</span> <span class="keyword">break</span>
+myfile.seek(addr)
+s = myfile.read(offset - 1)
+myfile.read(1)
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment"># Not Implemented
+</span><span class="comment-delimiter"># </span><span class="comment">bgets - get a string from an address in a binary file
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment">!/usr/bin/perl
+</span><span class="comment-delimiter"># </span><span class="comment">strings - pull strings out of a binary file
+</span><span class="keyword">import</span> re, sys
+
+<span class="comment-delimiter">#</span><span class="comment"># Assumes SepReader from above
+</span>
+pat = re.compile(r<span class="string">"([\040-\176\s]{4,})"</span>)
+<span class="keyword">for</span> block <span class="keyword">in</span> SepReader(sys.stdin, <span class="string">"\0"</span>):
+ pos = 0
+ <span class="keyword">while</span> <span class="py-pseudo-keyword">True</span>:
+ match = pat.search(block, pos)
+ <span class="keyword">if</span> <span class="keyword">not</span> match:
+ <span class="keyword">break</span>
+ <span class="keyword">print</span> match.group(1)
+ pos = match.end(1)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span> </PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN475"
+>Reading Fixed-Length Records</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span>
+<span class="comment-delimiter"># </span><span class="comment">RECORDSIZE is the length of a record, in bytes.
+</span><span class="comment-delimiter"># </span><span class="comment">TEMPLATE is the unpack template for the record
+</span><span class="comment-delimiter"># </span><span class="comment">FILE is the file to read from
+</span><span class="comment-delimiter"># </span><span class="comment">FIELDS is a tuple, one element per field
+</span><span class="keyword">import</span> struct
+RECORDSIZE= struct.calcsize(TEMPLATE)
+<span class="keyword">while</span> <span class="py-pseudo-keyword">True</span>:
+ record = FILE.read(RECORDSIZE):
+ <span class="keyword">if</span> <span class="py-builtins">len</span>(record)!=RECORDSIZE:
+ <span class="keyword">raise</span> <span class="string">"short read"</span>
+ FIELDS = struct.unpack(TEMPLATE, record)
+<span class="comment-delimiter"># </span><span class="comment">----
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN478"
+>Reading Configuration Files</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">NOTE: to parse INI file, see the stanard ConfigParser module.
+</span><span class="keyword">import</span> re
+pat = re.compile(r<span class="string">"\s*=\s*"</span>)
+<span class="keyword">for</span> line <span class="keyword">in</span> config_file:
+ <span class="keyword">if</span> <span class="string">"#"</span> <span class="keyword">in</span> line: <span class="comment-delimiter"># </span><span class="comment">no comments
+</span> line = line[:line.index(<span class="string">"#"</span>)]
+ line = line.strip() <span class="comment-delimiter"># </span><span class="comment">no leading or trailing white
+</span> <span class="keyword">if</span> <span class="keyword">not</span> line: <span class="comment-delimiter"># </span><span class="comment">anything left?
+</span> <span class="keyword">continue</span>
+ m = pat.search(line)
+ var = line[:m.start()]
+ value = line[m.end():]
+ User_Preferences[var] = value</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN481"
+>Testing a File for Trustworthiness</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="keyword">import</span> os
+
+mode, ino, dev, nlink, uid, gid, size, \
+atime, mtime, ctime = os.stat(filename)
+
+mode &amp;= 07777 <span class="comment-delimiter"># </span><span class="comment">discard file type info
+</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>info = os.stat(filename)
+<span class="keyword">if</span> info.st_uid == 0:
+ <span class="keyword">print</span> <span class="string">"Superuser owns"</span>, filename
+<span class="keyword">if</span> info.st_atime &gt; info.st_mtime:
+ <span class="keyword">print</span> filename, <span class="string">"has been read since it was written."</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> os
+<span class="keyword">def</span> <span class="function-name">is_safe</span>(path):
+ info = os.stat(path)
+
+ <span class="comment-delimiter"># </span><span class="comment">owner neither superuser nor me
+</span> <span class="comment-delimiter"># </span><span class="comment">the real uid is in stored in the $&lt; variable
+</span> <span class="keyword">if</span> info.st_uid <span class="keyword">not</span> <span class="keyword">in</span> (0, os.getuid()):
+ <span class="keyword">return</span> <span class="py-pseudo-keyword">False</span>
+
+ <span class="comment-delimiter"># </span><span class="comment">check whether group or other can write file.
+</span> <span class="comment-delimiter"># </span><span class="comment">use 066 to detect either reading or writing
+</span> <span class="keyword">if</span> info.st_mode &amp; 022: <span class="comment-delimiter"># </span><span class="comment">someone else can write this
+</span> <span class="keyword">if</span> <span class="keyword">not</span> os.path.isdir(path): <span class="comment-delimiter"># </span><span class="comment">non-directories aren't safe
+</span> <span class="keyword">return</span> <span class="py-pseudo-keyword">False</span>
+ <span class="comment-delimiter"># </span><span class="comment">but directories with the sticky bit (01000) are
+</span> <span class="keyword">if</span> <span class="keyword">not</span> (info.st_mode &amp; 01000):
+ <span class="keyword">return</span> <span class="py-pseudo-keyword">False</span>
+ <span class="keyword">return</span> <span class="py-pseudo-keyword">True</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment"># XXX What is '_PC_CHOWN_RESTRICTED'?
+</span>
+<span class="keyword">def</span> <span class="function-name">is_verysafe</span>(path):
+ terms = []
+ <span class="keyword">while</span> <span class="py-pseudo-keyword">True</span>:
+ path, ending = os.path.split(path)
+ <span class="keyword">if</span> <span class="keyword">not</span> ending:
+ <span class="keyword">break</span>
+ terms.insert(0, ending)
+ <span class="keyword">for</span> term <span class="keyword">in</span> terms:
+ path = os.path.join(path, term)
+ <span class="keyword">if</span> <span class="keyword">not</span> is_safe(path):
+ <span class="keyword">return</span> <span class="py-pseudo-keyword">False</span>
+ <span class="keyword">return</span> <span class="py-pseudo-keyword">True</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>
+<span class="comment-delimiter"># </span><span class="comment">Program: tctee
+</span><span class="comment-delimiter"># </span><span class="comment">Not Implemented (requires reimplementing Perl's builtin '&gt;&gt;', '|',
+</span><span class="comment-delimiter"># </span><span class="comment">etc. semantics)
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN484"
+>Program: tailwtmp</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">!/usr/bin/python
+</span><span class="comment-delimiter"># </span><span class="comment">tailwtmp - watch for logins and logouts;
+</span><span class="comment-delimiter"># </span><span class="comment">uses linux utmp structure, from /usr/include/bits/utmp.h
+</span>
+<span class="comment-delimiter"># </span><span class="comment">/* The structure describing an entry in the user accounting database. */
+</span><span class="comment-delimiter"># </span><span class="comment">struct utmp
+</span><span class="comment-delimiter"># </span><span class="comment">{
+</span><span class="comment-delimiter"># </span><span class="comment">short int ut_type; /* Type of login. */
+</span><span class="comment-delimiter"># </span><span class="comment">pid_t ut_pid; /* Process ID of login process. */
+</span><span class="comment-delimiter"># </span><span class="comment">char ut_line[UT_LINESIZE]; /* Devicename. */
+</span><span class="comment-delimiter"># </span><span class="comment">char ut_id[4]; /* Inittab ID. */
+</span><span class="comment-delimiter"># </span><span class="comment">char ut_user[UT_NAMESIZE]; /* Username. */
+</span><span class="comment-delimiter"># </span><span class="comment">char ut_host[UT_HOSTSIZE]; /* Hostname for remote login. */
+</span><span class="comment-delimiter"># </span><span class="comment">struct exit_status ut_exit; /* Exit status of a process marked
+</span><span class="comment-delimiter"># </span><span class="comment">as DEAD_PROCESS. */
+</span><span class="comment-delimiter"># </span><span class="comment">long int ut_session; /* Session ID, used for windowing. */
+</span><span class="comment-delimiter"># </span><span class="comment">struct timeval ut_tv; /* Time entry was made. */
+</span><span class="comment-delimiter"># </span><span class="comment">int32_t ut_addr_v6[4]; /* Internet address of remote host. */
+</span><span class="comment-delimiter"># </span><span class="comment">char __unused[20]; /* Reserved for future use. */
+</span><span class="comment-delimiter"># </span><span class="comment">};
+</span>
+<span class="comment-delimiter"># </span><span class="comment">/* Values for the `ut_type' field of a `struct utmp'. */
+</span><span class="comment-delimiter"># </span><span class="comment">#define EMPTY 0 /* No valid user accounting information. */
+</span><span class="comment-delimiter"># </span><span class="comment">
+</span><span class="comment-delimiter"># </span><span class="comment">#define RUN_LVL 1 /* The system's runlevel. */
+</span><span class="comment-delimiter"># </span><span class="comment">#define BOOT_TIME 2 /* Time of system boot. */
+</span><span class="comment-delimiter"># </span><span class="comment">#define NEW_TIME 3 /* Time after system clock changed. */
+</span><span class="comment-delimiter"># </span><span class="comment">#define OLD_TIME 4 /* Time when system clock changed. */
+</span><span class="comment-delimiter"># </span><span class="comment">
+</span><span class="comment-delimiter"># </span><span class="comment">#define INIT_PROCESS 5 /* Process spawned by the init process. */
+</span><span class="comment-delimiter"># </span><span class="comment">#define LOGIN_PROCESS 6 /* Session leader of a logged in user. */
+</span><span class="comment-delimiter"># </span><span class="comment">#define USER_PROCESS 7 /* Normal process. */
+</span><span class="comment-delimiter"># </span><span class="comment">#define DEAD_PROCESS 8 /* Terminated process. */
+</span><span class="comment-delimiter"># </span><span class="comment">
+</span><span class="comment-delimiter"># </span><span class="comment">#define ACCOUNTING 9
+</span>
+<span class="keyword">import</span> time
+<span class="keyword">import</span> struct
+<span class="keyword">import</span> os
+
+<span class="keyword">class</span> <span class="type">WTmpRecord</span>:
+ fmt = <span class="string">"hI32s4s32s256siili4l20s"</span>;
+ _fieldnames = [<span class="string">"type"</span>,<span class="string">"PID"</span>,<span class="string">"Line"</span>,<span class="string">"inittab"</span>,<span class="string">"User"</span>,<span class="string">"Hostname"</span>,
+ <span class="string">"exit_status"</span>, <span class="string">"session"</span>, <span class="string">"time"</span>, <span class="string">"addr"</span> ]
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="py-pseudo-keyword">self</span>._rec_size = struct.calcsize(<span class="py-pseudo-keyword">self</span>.fmt)
+ <span class="keyword">def</span> <span class="function-name">size</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="keyword">return</span> <span class="py-pseudo-keyword">self</span>._rec_size
+ <span class="keyword">def</span> <span class="function-name">unpack</span>(<span class="py-pseudo-keyword">self</span>, bin_data):
+ rec = struct.unpack(<span class="py-pseudo-keyword">self</span>.fmt, bin_data)
+ <span class="py-pseudo-keyword">self</span>._rec = []
+ <span class="keyword">for</span> i <span class="keyword">in</span> <span class="py-builtins">range</span>(len(rec)):
+ <span class="keyword">if</span> i <span class="keyword">in</span> (2,3,4,5):
+ <span class="comment-delimiter"># </span><span class="comment">remove character zeros from strings
+</span> <span class="py-pseudo-keyword">self</span>._rec.append( rec[i].split(<span class="string">"\0"</span>)[0] )
+ <span class="keyword">else:</span>
+ <span class="py-pseudo-keyword">self</span>._rec.append(rec[i])
+ <span class="keyword">return</span> <span class="py-pseudo-keyword">self</span>._rec
+ <span class="keyword">def</span> <span class="function-name">fieldnames</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="keyword">return</span> <span class="py-pseudo-keyword">self</span>._fieldnames
+ <span class="keyword">def</span> <span class="function-name">__getattr__</span>(<span class="py-pseudo-keyword">self</span>,name):
+ <span class="keyword">return</span> <span class="py-pseudo-keyword">self</span>._rec[<span class="py-pseudo-keyword">self</span>._fieldnames.index(name)]
+
+rec = WTmpRecord()
+f = <span class="py-builtins">open</span>(<span class="string">"/var/log/wtmp"</span>,<span class="string">"rb"</span>)
+f.seek(0,2)
+<span class="keyword">while</span> <span class="py-pseudo-keyword">True</span>:
+ <span class="keyword">while</span> <span class="py-pseudo-keyword">True</span>:
+ bin = f.read(rec.size())
+ <span class="keyword">if</span> <span class="py-builtins">len</span>(bin) != rec.size():
+ <span class="keyword">break</span>
+ rec.unpack(bin)
+ <span class="keyword">if</span> rec.type != 0:
+ <span class="keyword">print</span> <span class="string">" %1d %-8s %-12s %-24s %-20s %5d %08x"</span> % \
+ (rec.type, rec.User, rec.Line,
+ time.strftime(<span class="string">"%a %Y-%m-%d %H:%M:%S"</span>,time.localtime(rec.time)),
+ rec.Hostname, rec.PID, rec.addr)
+ time.sleep(1)
+f.close()</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN487"
+>Program: tctee</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN490"
+>Program: laston</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">!/usr/bin/python
+</span><span class="comment-delimiter"># </span><span class="comment">laston - find out when given user last logged on
+</span><span class="keyword">import</span> sys
+<span class="keyword">import</span> struct
+<span class="keyword">import</span> pwd
+<span class="keyword">import</span> time
+<span class="keyword">import</span> re
+
+f = <span class="py-builtins">open</span>(<span class="string">"/var/log/lastlog"</span>,<span class="string">"rb"</span>)
+
+fmt = <span class="string">"L32s256s"</span>
+rec_size = struct.calcsize(fmt)
+
+<span class="keyword">for</span> user <span class="keyword">in</span> sys.argv[1:]:
+ <span class="keyword">if</span> re.match(r<span class="string">"^\d+$"</span>, user):
+ user_id = <span class="py-builtins">int</span>(user)
+ <span class="keyword">else:</span>
+ <span class="keyword">try:</span>
+ user_id = pwd.getpwnam(user)[2]
+ <span class="keyword">except:</span>
+ <span class="keyword">print</span> <span class="string">"no such uid %s"</span> % (user)
+ <span class="keyword">continue</span>
+ f.seek(rec_size * user_id)
+ bin = f.read(rec_size)
+ <span class="keyword">if</span> <span class="py-builtins">len</span>(bin) == rec_size:
+ data = struct.unpack(fmt, bin)
+ <span class="keyword">if</span> data[0]:
+ logged_in = <span class="string">"at %s"</span> % (time.strftime(<span class="string">"%a %H:%M:%S %Y-%m-%d"</span>,
+ time.localtime(data[0])))
+ line = <span class="string">" on %s"</span> % (data[1])
+ host = <span class="string">" from %s"</span> % (data[2])
+ <span class="keyword">else:</span>
+ logged_in = <span class="string">"never logged in"</span>
+ line = <span class="string">""</span>
+ host = <span class="string">""</span>
+ <span class="keyword">print</span> <span class="string">"%-8s UID %5d %s%s%s"</span> % (user, user_id, logged_in, line, host)
+ <span class="keyword">else:</span>
+ <span class="keyword">print</span> <span class="string">"Read failed."</span>
+f.close()</PRE
+></TD
+></TR
+></TABLE
+></DIV
+></DIV
+><DIV
+CLASS="NAVFOOTER"
+><HR
+ALIGN="LEFT"
+WIDTH="100%"><TABLE
+SUMMARY="Footer navigation table"
+WIDTH="100%"
+BORDER="0"
+CELLPADDING="0"
+CELLSPACING="0"
+><TR
+><TD
+WIDTH="33%"
+ALIGN="left"
+VALIGN="top"
+><A
+HREF="fileaccess.html"
+ACCESSKEY="P"
+>Prev</A
+></TD
+><TD
+WIDTH="34%"
+ALIGN="center"
+VALIGN="top"
+><A
+HREF="index.html"
+ACCESSKEY="H"
+>Home</A
+></TD
+><TD
+WIDTH="33%"
+ALIGN="right"
+VALIGN="top"
+><A
+HREF="directories.html"
+ACCESSKEY="N"
+>Next</A
+></TD
+></TR
+><TR
+><TD
+WIDTH="33%"
+ALIGN="left"
+VALIGN="top"
+>File Access</TD
+><TD
+WIDTH="34%"
+ALIGN="center"
+VALIGN="top"
+>&nbsp;</TD
+><TD
+WIDTH="33%"
+ALIGN="right"
+VALIGN="top"
+>Directories</TD
+></TR
+></TABLE
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/help/PythonExamples/pleac_python/hashes.html b/help/PythonExamples/pleac_python/hashes.html
new file mode 100644
index 0000000..a841e41
--- /dev/null
+++ b/help/PythonExamples/pleac_python/hashes.html
@@ -0,0 +1,1111 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML
+><HEAD
+><TITLE
+>Hashes</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
+REL="HOME"
+TITLE="PLEAC-Python
+"
+HREF="index.html"><LINK
+REL="PREVIOUS"
+TITLE="Arrays"
+HREF="arrays.html"><LINK
+REL="NEXT"
+TITLE="Pattern Matching"
+HREF="patternmatching.html"><style type="text/css"> <!--
+ .comment {
+ /* font-lock-comment-face */
+ color: #bebebe;
+ }
+ .comment-delimiter {
+ }
+ .function-name {
+ /* font-lock-function-name-face */
+ color: #b2dfee;
+ }
+ .keyword {
+ /* font-lock-keyword-face */
+ color: #ffa500;
+ }
+ .py-builtins {
+ /* py-builtins-face */
+ color: #ffa500;
+ }
+ .py-pseudo-keyword {
+ /* py-pseudo-keyword-face */
+ color: #ffa500;
+ }
+ .string {
+ /* font-lock-string-face */
+ color: #00cd00;
+ }
+ .type {
+ /* font-lock-type-face */
+ color: #98fb98;
+ }
+ -->
+ </style></head
+><BODY TEXT="#cecece" BGCOLOR="#4f6f6f" LINK="#f5deb3" VLINK="#d5ae83"
+CLASS="SECT1"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><DIV
+CLASS="NAVHEADER"
+><TABLE
+SUMMARY="Header navigation table"
+WIDTH="100%"
+BORDER="0"
+CELLPADDING="0"
+CELLSPACING="0"
+><TR
+><TH
+COLSPAN="3"
+ALIGN="center"
+>PLEAC-Python
+</TH
+></TR
+><TR
+><TD
+WIDTH="10%"
+ALIGN="left"
+VALIGN="bottom"
+><A
+HREF="arrays.html"
+ACCESSKEY="P"
+>Prev</A
+></TD
+><TD
+WIDTH="80%"
+ALIGN="center"
+VALIGN="bottom"
+></TD
+><TD
+WIDTH="10%"
+ALIGN="right"
+VALIGN="bottom"
+><A
+HREF="patternmatching.html"
+ACCESSKEY="N"
+>Next</A
+></TD
+></TR
+></TABLE
+><HR
+ALIGN="LEFT"
+WIDTH="100%"></DIV
+><DIV
+CLASS="SECT1"
+><H1
+CLASS="SECT1"
+><A
+NAME="HASHES"
+>5. Hashes</A
+></H1
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN232"
+>Introduction</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">dictionaries
+</span>age = {<span class="string">"Nat"</span>: 24,
+ <span class="string">"Jules"</span>: 24,
+ <span class="string">"Josh"</span>: 17}
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>age = {}
+age[<span class="string">"Nat"</span>] = 24
+age[<span class="string">"Jules"</span>] = 25
+age[<span class="string">"Josh"</span>] = 17
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>food_color = {<span class="string">"Apple"</span>: <span class="string">"red"</span>,
+ <span class="string">"Banana"</span>: <span class="string">"yellow"</span>,
+ <span class="string">"Lemon"</span>: <span class="string">"yellow"</span>,
+ <span class="string">"Carrot"</span>: <span class="string">"orange"</span>
+ }
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">NOTE: keys must be quoted in Python
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN235"
+>Adding an Element to a Hash</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span>mydict[key] = value
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">food_color defined per the introduction
+</span>food_color[<span class="string">"Raspberry"</span>] = <span class="string">"pink"</span>
+<span class="keyword">print</span> <span class="string">"Known foods:"</span>
+<span class="keyword">for</span> food <span class="keyword">in</span> food_color:
+ <span class="keyword">print</span> food
+
+<span class="comment-delimiter">#</span><span class="comment">=&gt; Known foods:
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt; Raspberry
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt; Carrot
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt; Lemon
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt; Apple
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt; Banana
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN238"
+>Testing for the Presence of a Key in a Hash</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">does mydict have a value for key?
+</span><span class="keyword">if</span> key <span class="keyword">in</span> mydict:
+ <span class="keyword">pass</span> <span class="comment-delimiter"># </span><span class="comment">it exists
+</span><span class="keyword">else:</span>
+ <span class="keyword">pass</span> <span class="comment-delimiter"># </span><span class="comment">it doesn't
+</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">food_color per the introduction
+</span><span class="keyword">for</span> name <span class="keyword">in</span> (<span class="string">"Banana"</span>, <span class="string">"Martini"</span>):
+ <span class="keyword">if</span> name <span class="keyword">in</span> food_color:
+ <span class="keyword">print</span> name, <span class="string">"is a food."</span>
+ <span class="keyword">else:</span>
+ <span class="keyword">print</span> name, <span class="string">"is a drink."</span>
+
+<span class="comment-delimiter">#</span><span class="comment">=&gt; Banana is a food.
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt; Martini is a drink.
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>age = {}
+age[<span class="string">"Toddler"</span>] = 3
+age[<span class="string">"Unborn"</span>] = 0
+age[<span class="string">"Phantasm"</span>] = <span class="py-pseudo-keyword">None</span>
+
+<span class="keyword">for</span> thing <span class="keyword">in</span> (<span class="string">"Toddler"</span>, <span class="string">"Unborn"</span>, <span class="string">"Phantasm"</span>, <span class="string">"Relic"</span>):
+ <span class="keyword">print</span> (<span class="string">"%s:"</span>%thing),
+ <span class="keyword">if</span> thing <span class="keyword">in</span> age:
+ <span class="keyword">print</span> <span class="string">"Exists"</span>,
+ <span class="keyword">if</span> age[thing] <span class="keyword">is</span> <span class="keyword">not</span> <span class="py-pseudo-keyword">None</span>:
+ <span class="keyword">print</span> <span class="string">"Defined"</span>,
+ <span class="keyword">if</span> age[thing]:
+ <span class="keyword">print</span> <span class="string">"True"</span>,
+ <span class="keyword">print</span>
+<span class="comment-delimiter">#</span><span class="comment">=&gt; Toddler: Exists Defined True
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt; Unborn: Exists Defined
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt; Phantasm: Exists
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt; Relic:
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Get file sizes for the requested filenames
+</span><span class="keyword">import</span> fileinput, os
+size = {}
+<span class="keyword">for</span> line <span class="keyword">in</span> fileinput.input():
+ filename = line.rstrip()
+ <span class="keyword">if</span> filename <span class="keyword">in</span> size:
+ <span class="keyword">continue</span>
+ size[filename] = os.path.getsize(filename)</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN241"
+>Deleting from a Hash</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">remove key and its value from mydict
+</span><span class="keyword">del</span> mydict[key]
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">food_color as per Introduction
+</span><span class="keyword">def</span> <span class="function-name">print_foods</span>():
+ foods = food_color.keys()
+
+ <span class="keyword">print</span> <span class="string">"Keys:"</span>, <span class="string">" "</span>.join(foods)
+ <span class="keyword">print</span> <span class="string">"Values:"</span>,
+
+ <span class="keyword">for</span> food <span class="keyword">in</span> foods:
+ color = food_color[food]
+ <span class="keyword">if</span> color <span class="keyword">is</span> <span class="keyword">not</span> <span class="py-pseudo-keyword">None</span>:
+ <span class="keyword">print</span> color,
+ <span class="keyword">else:</span>
+ <span class="keyword">print</span> <span class="string">"(undef)"</span>,
+ <span class="keyword">print</span>
+
+<span class="keyword">print</span> <span class="string">"Initially:"</span>
+print_foods()
+
+<span class="keyword">print</span> <span class="string">"\nWith Banana set to None"</span>
+food_color[<span class="string">"Banana"</span>] = <span class="py-pseudo-keyword">None</span>
+print_foods()
+
+<span class="keyword">print</span> <span class="string">"\nWith Banana deleted"</span>
+<span class="keyword">del</span> food_color[<span class="string">"Banana"</span>]
+print_foods()
+
+<span class="comment-delimiter">#</span><span class="comment">=&gt; Initially:
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt; Keys: Carrot Lemon Apple Banana
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt; Values: orange yellow red yellow
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt;
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt; With Banana set to None
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt; Keys: Carrot Lemon Apple Banana
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt; Values: orange yellow red (undef)
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt;
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt; With Banana deleted
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt; Keys: Carrot Lemon Apple
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt; Values: orange yellow red
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">for</span> key <span class="keyword">in</span> [<span class="string">"Banana"</span>, <span class="string">"Apple"</span>, <span class="string">"Cabbage"</span>]:
+ <span class="keyword">del</span> food_color[key]
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN244"
+>Traversing a Hash</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">for</span> key, value <span class="keyword">in</span> mydict.items():
+ <span class="keyword">pass</span> <span class="comment-delimiter"># </span><span class="comment">do something with key and value
+</span>
+<span class="comment-delimiter"># </span><span class="comment">If mydict is large, use iteritems() instead
+</span><span class="keyword">for</span> key, value <span class="keyword">in</span> mydict.iteritems():
+ <span class="keyword">pass</span> <span class="comment-delimiter"># </span><span class="comment">do something with key and value
+</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS:
+</span><span class="keyword">for</span> key <span class="keyword">in</span> mydict.keys():
+ value = mydict[key]
+ <span class="comment-delimiter"># </span><span class="comment">do something with key and value
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">food_color per the introduction
+</span><span class="keyword">for</span> food, color <span class="keyword">in</span> food_color.items():
+ <span class="keyword">print</span> <span class="string">"%s is %s."</span> % (food, color)
+
+<span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS:
+</span><span class="keyword">for</span> food <span class="keyword">in</span> food_color:
+ color = food_color[food]
+ <span class="keyword">print</span> <span class="string">"%s is %s."</span> % (food, color)
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">print</span> <span class="string">"""%(food)s
+
+is
+
+%(color)s.
+"""</span> % <span class="py-builtins">vars</span>()
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">for</span> food, color <span class="keyword">in</span> sorted(food_color.items()):
+ <span class="keyword">print</span> <span class="string">"%s is %s."</span> % (food, color)
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment">!/usr/bin/env python
+</span><span class="comment-delimiter"># </span><span class="comment">countfrom - count number of messages from each sender
+</span>
+<span class="keyword">import</span> sys
+<span class="keyword">if</span> <span class="py-builtins">len</span>(sys.argv) &gt; 1:
+ infile = <span class="py-builtins">open</span>(sys.argv[1])
+<span class="keyword">else:</span>
+ infile = sys.stdin
+
+counts = {}
+<span class="keyword">for</span> line <span class="keyword">in</span> infile:
+ <span class="keyword">if</span> line.startswith(<span class="string">"From: "</span>):
+ name = line[6:-1]
+ counts[name] = counts.get(name, 0) + 1
+
+<span class="keyword">for</span> (name, count) <span class="keyword">in</span> sorted(counts.items()):
+ <span class="keyword">print</span> <span class="string">"%s: %s"</span> % (name, count)
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN247"
+>Printing a Hash</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="keyword">for</span> key, val <span class="keyword">in</span> mydict.items():
+ <span class="keyword">print</span> key, <span class="string">"=&gt;"</span>, val
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">print</span> <span class="string">"\n"</span>.join([(<span class="string">"%s =&gt; %s"</span> % item) <span class="keyword">for</span> item <span class="keyword">in</span> mydict.items()])
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">print</span> mydict
+<span class="comment-delimiter">#</span><span class="comment">=&gt; {'firstname': 'Andrew', 'login': 'dalke', 'state': 'New Mexico', 'lastname': 'Dalke'}
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> pprint
+pprint.pprint(dict)
+<span class="comment-delimiter">#</span><span class="comment">=&gt; {'firstname': 'Andrew',
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt; 'lastname': 'Dalke',
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt; 'login': 'dalke',
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt; 'state': 'New Mexico'}
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN250"
+>Retrieving from a Hash in Insertion Order</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">class</span> <span class="type">SequenceDict</span>(dict):
+ <span class="string">"""
+ Dictionary that remembers the insertion order.
+ The lists returned by keys(), values() and items() are
+ in the insertion order.
+ """</span>
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>, *args):
+ <span class="py-pseudo-keyword">self</span>._keys={} <span class="comment-delimiter"># </span><span class="comment">key --&gt; id
+</span> <span class="py-pseudo-keyword">self</span>._ids={} <span class="comment-delimiter"># </span><span class="comment">id --&gt; key
+</span> <span class="py-pseudo-keyword">self</span>._next_id=0
+
+ <span class="keyword">def</span> <span class="function-name">__setitem__</span>(<span class="py-pseudo-keyword">self</span>, key, value):
+ <span class="py-pseudo-keyword">self</span>._keys[key]=<span class="py-pseudo-keyword">self</span>._next_id
+ <span class="py-pseudo-keyword">self</span>._ids[<span class="py-pseudo-keyword">self</span>._next_id]=key
+ <span class="py-pseudo-keyword">self</span>._next_id+=1
+ <span class="keyword">return</span> dict.__setitem__(<span class="py-pseudo-keyword">self</span>, key, value)
+
+ <span class="keyword">def</span> <span class="function-name">__delitem__</span>(<span class="py-pseudo-keyword">self</span>, key):
+ id=<span class="py-pseudo-keyword">self</span>._keys[key]
+ <span class="keyword">del</span>(<span class="py-pseudo-keyword">self</span>._keys[key])
+ <span class="keyword">del</span>(<span class="py-pseudo-keyword">self</span>._ids[id])
+ <span class="keyword">return</span> dict.__delitem__(<span class="py-pseudo-keyword">self</span>, key)
+
+ <span class="keyword">def</span> <span class="function-name">values</span>(<span class="py-pseudo-keyword">self</span>):
+ values=[]
+ ids=<span class="py-builtins">list</span>(<span class="py-pseudo-keyword">self</span>._ids.items())
+ ids.sort()
+ <span class="keyword">for</span> id, key <span class="keyword">in</span> ids:
+ values.append(<span class="py-pseudo-keyword">self</span>[key])
+ <span class="keyword">return</span> values
+
+ <span class="keyword">def</span> <span class="function-name">items</span>(<span class="py-pseudo-keyword">self</span>):
+ items=[]
+ ids=<span class="py-builtins">list</span>(<span class="py-pseudo-keyword">self</span>._ids.items())
+ ids.sort()
+ <span class="keyword">for</span> id, key <span class="keyword">in</span> ids:
+ items.append((key, <span class="py-pseudo-keyword">self</span>[key]))
+ <span class="keyword">return</span> items
+
+ <span class="keyword">def</span> <span class="function-name">keys</span>(<span class="py-pseudo-keyword">self</span>):
+ ids=<span class="py-builtins">list</span>(<span class="py-pseudo-keyword">self</span>._ids.items())
+ ids.sort()
+ keys=[]
+ <span class="keyword">for</span> id, key <span class="keyword">in</span> ids:
+ keys.append(key)
+ <span class="keyword">return</span> keys
+
+ <span class="keyword">def</span> <span class="function-name">update</span>(<span class="py-pseudo-keyword">self</span>, d):
+ <span class="keyword">for</span> key, value <span class="keyword">in</span> d.items():
+ <span class="py-pseudo-keyword">self</span>[key]=value
+
+ <span class="keyword">def</span> <span class="function-name">clear</span>(<span class="py-pseudo-keyword">self</span>):
+ dict.clear(<span class="py-pseudo-keyword">self</span>)
+ <span class="py-pseudo-keyword">self</span>._keys={}
+ <span class="py-pseudo-keyword">self</span>._ids={}
+ <span class="py-pseudo-keyword">self</span>._next_id=0
+
+<span class="keyword">def</span> <span class="function-name">testSequenceDict</span>():
+ sd=SequenceDict()
+
+ <span class="comment-delimiter"># </span><span class="comment">First Test
+</span> sd[3]=<span class="string">"first"</span>
+ sd[2]=<span class="string">"second"</span>
+ sd[1]=<span class="string">"third"</span>
+ <span class="keyword">print</span> sd.keys()
+ <span class="keyword">print</span> sd.items()
+ <span class="keyword">print</span> sd.values()
+
+ <span class="keyword">del</span>(sd[1])
+ <span class="keyword">del</span>(sd[2])
+ <span class="keyword">del</span>(sd[3])
+
+ <span class="keyword">print</span> sd.keys(), sd.items(), sd.values()
+ <span class="keyword">print</span> sd._ids, sd._keys
+
+ <span class="keyword">print</span> <span class="string">"---------------"</span>
+ <span class="comment-delimiter"># </span><span class="comment">Second Test
+</span> sd[<span class="string">"b"</span>]=<span class="string">"first"</span>
+ sd[<span class="string">"a"</span>]=<span class="string">"second"</span>
+ sd.update({<span class="string">"c"</span>: <span class="string">"third"</span>})
+ <span class="keyword">print</span> sd.keys()
+ <span class="keyword">print</span> sd.items()
+ <span class="keyword">print</span> sd.values()
+
+ <span class="keyword">del</span>(sd[<span class="string">"b"</span>])
+ <span class="keyword">del</span>(sd[<span class="string">"a"</span>])
+ <span class="keyword">del</span>(sd[<span class="string">"c"</span>])
+
+ <span class="keyword">print</span> sd.keys(), sd.items(), sd.values()
+ <span class="keyword">print</span> sd._ids, sd._keys
+
+<span class="keyword">def</span> <span class="function-name">likePerlCookbook</span>():
+ food_color=SequenceDict()
+ food_color[<span class="string">"Banana"</span>]=<span class="string">"Yellow"</span>;
+ food_color[<span class="string">"Apple"</span>]=<span class="string">"Green"</span>;
+ food_color[<span class="string">"Lemon"</span>]=<span class="string">"Yellow"</span>
+ <span class="keyword">print</span> <span class="string">"In insertion order, the foods' color are:"</span>
+ <span class="keyword">for</span> food, color <span class="keyword">in</span> food_color.items():
+ <span class="keyword">print</span> <span class="string">"%s is colored %s"</span> % (food, color)
+
+<span class="keyword">if</span> __name__==<span class="string">"__main__"</span>:
+ <span class="comment-delimiter">#</span><span class="comment">testSequenceDict()
+</span> likePerlCookbook()
+ </PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN253"
+>Hashes with Multiple Values Per Key</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="keyword">import</span> os
+ttys = {}
+
+who = os.popen(<span class="string">"who"</span>)
+
+<span class="keyword">for</span> line <span class="keyword">in</span> who:
+ user, tty = line.split()[:2]
+ ttys.setdefault(user, []).append(tty)
+
+<span class="keyword">for</span> (user, tty_list) <span class="keyword">in</span> sorted(ttys.items()):
+ <span class="keyword">print</span> user + <span class="string">": "</span> + <span class="string">" "</span>.join(tty_list)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> pwd
+<span class="keyword">for</span> (user, tty_list) <span class="keyword">in</span> ttys.items():
+ <span class="keyword">print</span> user + <span class="string">":"</span>, <span class="py-builtins">len</span>(tty_list), <span class="string">"ttys."</span>
+ <span class="keyword">for</span> tty <span class="keyword">in</span> sorted(tty_list):
+ <span class="keyword">try:</span>
+ uid = os.stat(<span class="string">"/dev/"</span> + tty).st_uid
+ user = pwd.getpwuid(uid)[0]
+ <span class="keyword">except</span> os.error:
+ user = <span class="string">"(not available)"</span>
+ <span class="keyword">print</span> <span class="string">"\t%s (owned by %s)"</span> % (tty, user)</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN256"
+>Inverting a Hash</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">lookup_dict maps keys to values
+</span>reverse = <span class="py-builtins">dict</span>([(val, key) <span class="keyword">for</span> (key, val) <span class="keyword">in</span> lookup_dict.items()])
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>surname = {<span class="string">"Mickey"</span>: <span class="string">"Mantle"</span>, <span class="string">"Babe"</span>: <span class="string">"Ruth"</span>}
+first_name = <span class="py-builtins">dict</span>([(last, first) <span class="keyword">for</span> (first, last) <span class="keyword">in</span> surname.items()])
+
+<span class="keyword">print</span> first_name[<span class="string">"Mantle"</span>]
+<span class="comment-delimiter">#</span><span class="comment">=&gt; Mickey
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment">!/usr/bin/perl -w
+</span><span class="comment-delimiter"># </span><span class="comment">foodfind - find match for food or color
+</span>
+<span class="keyword">import</span> sys
+<span class="keyword">if</span> <span class="keyword">not</span> sys.argv[1:]:
+ <span class="keyword">raise</span> <span class="py-builtins">SystemExit</span>(<span class="string">"usage: foodfind food_or_color"</span>)
+given = sys.argv[1]
+
+color_dict = {<span class="string">"Apple"</span>: <span class="string">"red"</span>,
+ <span class="string">"Banana"</span>: <span class="string">"yellow"</span>,
+ <span class="string">"Lemon"</span>: <span class="string">"yellow"</span>,
+ <span class="string">"Carrot"</span>: <span class="string">"orange"</span>,
+ }
+food_dict = <span class="py-builtins">dict</span>([(color, food) <span class="keyword">for</span> (food, color) <span class="keyword">in</span> color_dict.items()])
+
+<span class="keyword">if</span> given <span class="keyword">in</span> color_dict:
+ <span class="keyword">print</span> given, <span class="string">"is a food with color"</span>, color_dict[given]
+<span class="keyword">elif</span> given <span class="keyword">in</span> food_dict:
+ <span class="keyword">print</span> food_dict[given], <span class="string">"is a food with color"</span>, given
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">food_color as per the introduction
+</span>foods_with_color = {}
+<span class="keyword">for</span> food, color <span class="keyword">in</span> food_color.items():
+ foods_with_color.setdefault(color, []).append(food)
+
+<span class="keyword">print</span> <span class="string">" "</span>.join(foods_with_color[<span class="string">"yellow"</span>]), <span class="string">"were yellow foods."</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN259"
+>Sorting a Hash</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">mydict is the hash to sort
+</span><span class="keyword">for</span> key, value <span class="keyword">in</span> sorted(mydict.items()):
+ <span class="comment-delimiter"># </span><span class="comment">do something with key, value
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">food_color as per section 5.8
+</span><span class="keyword">for</span> food, color <span class="keyword">in</span> sorted(food_color.items()):
+ <span class="keyword">print</span> <span class="string">"%s is %s."</span> % (food, color)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">NOTE: alternative version
+</span><span class="keyword">for</span> item <span class="keyword">in</span> sorted(food_color.items()):
+ <span class="keyword">print</span> <span class="string">"%s is %s."</span> % item
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">NOTE: alternative version showing a user-defined function
+</span><span class="keyword">def</span> <span class="function-name">food_cmp</span>(x, y):
+ <span class="keyword">return</span> <span class="py-builtins">cmp</span>(x, y)
+
+<span class="keyword">for</span> food, color <span class="keyword">in</span> sorted(food_color, cmp=food_cmp):
+ <span class="keyword">print</span> <span class="string">"%s is %s."</span> % (food, color)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">def</span> <span class="function-name">food_len_cmp</span>(x, y):
+ <span class="keyword">return</span> <span class="py-builtins">cmp</span>(len(x), <span class="py-builtins">len</span>(y))
+
+<span class="keyword">for</span> food <span class="keyword">in</span> sorted(food_color, cmp=food_len_cmp):
+ <span class="keyword">print</span> <span class="string">"%s is %s."</span> % (food, food_color[food])
+
+<span class="comment-delimiter"># </span><span class="comment">In this instance, however, the following is both simpler and faster:
+</span><span class="keyword">for</span> food <span class="keyword">in</span> sorted(food_color, key=len):
+ <span class="keyword">print</span> <span class="string">"%s is %s."</span> % (food, food_color[food])
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN262"
+>Merging Hashes</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>merged = {}
+merged.update(a_dict)
+merged.update(b_dict)
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">NOTE: alternative version
+</span>merged = a_dict.copy()
+merged.update(b_dict)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS:
+</span>
+merged = {}
+<span class="keyword">for</span> k, v <span class="keyword">in</span> a_dict.items():
+ merged[k] = v
+<span class="keyword">for</span> k, v <span class="keyword">in</span> b_dict.items():
+ merged[k] = v
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">food_color as per section 5.8
+</span>drink_color = {<span class="string">"Galliano"</span>: <span class="string">"yellow"</span>,
+ <span class="string">"Mai Tai"</span>: <span class="string">"blue"</span>}
+
+ingested_color = drink_color.copy()
+ingested_color.update(food_color)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS:
+</span>drink_color = {<span class="string">"Galliano"</span>: <span class="string">"yellow"</span>,
+ <span class="string">"Mai Tai"</span>: <span class="string">"blue"</span>}
+
+substance_color = {}
+<span class="keyword">for</span> k, v <span class="keyword">in</span> food_color.items():
+ substance_color[k] = v
+<span class="keyword">for</span> k, v <span class="keyword">in</span> drink_color.items():
+ substance_color[k] = v
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS:
+</span>substance_color = {}
+<span class="keyword">for</span> mydict <span class="keyword">in</span> (food_color, drink_color):
+ <span class="keyword">for</span> k, v <span class="keyword">in</span> mydict:
+ substance_color[k] = v
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS:
+</span>substance_color = {}
+<span class="keyword">for</span> item <span class="keyword">in</span> food_color.items() + drink_color.items():
+ <span class="keyword">for</span> k, v <span class="keyword">in</span> mydict:
+ substance_color[k] = v
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>substance_color = {}
+<span class="keyword">for</span> mydict <span class="keyword">in</span> (food_color, drink_color):
+ <span class="keyword">for</span> k, v <span class="keyword">in</span> mydict.items():
+ <span class="keyword">if</span> substance_color.has_key(k):
+ <span class="keyword">print</span> <span class="string">"Warning:"</span>, k, <span class="string">"seen twice. Using the first definition."</span>
+ <span class="keyword">continue</span>
+ substance_color[k] = v
+
+<span class="comment-delimiter"># </span><span class="comment">I think it's a copy, in which case
+</span>all_colors = new_colors.copy()</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN265"
+>Finding Common or Different Keys in Two Hashes</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span>common = [k <span class="keyword">for</span> k <span class="keyword">in</span> dict1 <span class="keyword">if</span> k <span class="keyword">in</span> dict2]
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>this_not_that = [k <span class="keyword">for</span> k <span class="keyword">in</span> dict1 <span class="keyword">if</span> k <span class="keyword">not</span> <span class="keyword">in</span> dict2]
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">citrus_color is a dict mapping citrus food name to its color.
+</span>citrus_color = {<span class="string">"Lemon"</span>: <span class="string">"yellow"</span>,
+ <span class="string">"Orange"</span>: <span class="string">"orange"</span>,
+ <span class="string">"Lime"</span>: <span class="string">"green"</span>}
+
+<span class="comment-delimiter"># </span><span class="comment">build up a list of non-citrus foods
+</span>non_citrus = [k <span class="keyword">for</span> k <span class="keyword">in</span> food_color <span class="keyword">if</span> k <span class="keyword">not</span> <span class="keyword">in</span> citruscolor]
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN268"
+>Hashing References</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">references as keys of dictionaries is no pb in python
+</span>
+name = {}
+<span class="keyword">for</span> filename <span class="keyword">in</span> (<span class="string">"/etc/termcap"</span>, <span class="string">"/vmunix"</span>, <span class="string">"/bin/cat"</span>):
+ <span class="keyword">try:</span>
+ myfile = <span class="py-builtins">open</span>(filename)
+ <span class="keyword">except</span> <span class="py-builtins">IOError</span>:
+ <span class="keyword">pass</span>
+ <span class="keyword">else:</span>
+ names[myfile] = filename
+
+<span class="keyword">print</span> <span class="string">"open files:"</span>, <span class="string">", "</span>.join(name.values())
+<span class="keyword">for</span> f, fname <span class="keyword">in</span> name.items():
+ f.seek(0, 2) <span class="comment-delimiter"># </span><span class="comment">seek to the end
+</span> <span class="keyword">print</span> <span class="string">"%s is %d bytes long."</span> % (fname, f.tell())
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN271"
+>Presizing a Hash</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">Python doesn't allow presizing of dicts, but hashing is efficient -
+</span><span class="comment-delimiter"># </span><span class="comment">it only re-sizes at intervals, not every time an item is added.
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN274"
+>Finding the Most Common Anything</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span>count = {}
+<span class="keyword">for</span> element <span class="keyword">in</span> mylist:
+ count[element] = count.get(element, 0) + 1</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN277"
+>Representing Relationships Between Data</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> fileinput
+
+father = {<span class="string">'Cain'</span>: <span class="string">'Adam'</span>,
+ <span class="string">'Abel'</span>: <span class="string">'Adam'</span>,
+ <span class="string">'Seth'</span>: <span class="string">'Adam'</span>,
+ <span class="string">'Enoch'</span>: <span class="string">'Cain'</span>,
+ <span class="string">'Irad'</span>: <span class="string">'Enoch'</span>,
+ <span class="string">'Mehujael'</span>: <span class="string">'Irad'</span>,
+ <span class="string">'Methusael'</span>: <span class="string">'Mehujael'</span>,
+ <span class="string">'Lamech'</span>: <span class="string">'Methusael'</span>,
+ <span class="string">'Jabal'</span>: <span class="string">'Lamech'</span>,
+ <span class="string">'Tubalcain'</span>: <span class="string">'Lamech'</span>,
+ <span class="string">'Enos'</span>: <span class="string">'Seth'</span>,
+ }
+
+<span class="keyword">for</span> line <span class="keyword">in</span> fileinput.input():
+ person = line.rstrip()
+ <span class="keyword">while</span> person: <span class="comment-delimiter"># </span><span class="comment">as long as we have people,
+</span> <span class="keyword">print</span> person, <span class="comment-delimiter"># </span><span class="comment">print the current name
+</span> person = father.get(person) <span class="comment-delimiter"># </span><span class="comment">set the person to the person's father
+</span> <span class="keyword">print</span>
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> fileinput
+
+children = {}
+<span class="keyword">for</span> k, v <span class="keyword">in</span> father.items():
+ children.setdefault(v, []).append(k)
+
+<span class="keyword">for</span> line <span class="keyword">in</span> fileinput.input():
+ person = line.rstrip()
+ kids = children.get(person, [<span class="string">"nobody"</span>])
+ <span class="keyword">print</span> person, <span class="string">"begat"</span>, <span class="string">", "</span>.join(kids)
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> sys, re
+pattern = re.compile(r<span class="string">'^\s*#\s*include\s*&lt;([^&gt;]+)'</span>)
+includes = {}
+<span class="keyword">for</span> filename <span class="keyword">in</span> filenames:
+ <span class="keyword">try:</span>
+ infile = <span class="py-builtins">open</span>(filename)
+ <span class="keyword">except</span> <span class="py-builtins">IOError</span>, err:
+ print&gt;&gt;sys.stderr, err
+ <span class="keyword">continue</span>
+ <span class="keyword">for</span> line <span class="keyword">in</span> infile:
+ match = pattern.match(line)
+ <span class="keyword">if</span> match:
+ includes.setdefault(match.group(1), []).append(filename)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">list of files that don't include others
+</span>mydict = {}
+<span class="keyword">for</span> e <span class="keyword">in</span> <span class="py-builtins">reduce</span>(<span class="keyword">lambda</span> a,b: a + b, includes.values()):
+ <span class="keyword">if</span> <span class="keyword">not</span> includes.has_key(e):
+ mydict[e] = 1
+include_free = mydict.keys()
+include_free.sort()</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN280"
+>Program: dutree</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment">!/usr/bin/env python -w
+</span><span class="comment-delimiter"># </span><span class="comment">dutree - print sorted indented rendition of du output
+</span><span class="keyword">import</span> os, sys
+
+<span class="keyword">def</span> <span class="function-name">get_input</span>(args):
+ <span class="comment-delimiter"># </span><span class="comment">NOTE: This is insecure - use only from trusted code!
+</span> cmd = <span class="string">"du "</span> + <span class="string">" "</span>.join(args)
+ infile = os.popen(cmd)
+
+ dirsize = {}
+ kids = {}
+ <span class="keyword">for</span> line <span class="keyword">in</span> infile:
+ size, name = line[:-1].split(<span class="string">"\t"</span>, 1)
+ dirsize[name] = <span class="py-builtins">int</span>(size)
+ parent = os.path.dirname(name)
+ kids.setdefault(parent, []).append(name)
+ <span class="comment-delimiter"># </span><span class="comment">Remove the last field added, which is the root
+</span> kids[parent].pop()
+ <span class="keyword">if</span> <span class="keyword">not</span> kids[parent]:
+ <span class="keyword">del</span> kids[parent]
+
+ <span class="keyword">return</span> name, dirsize, kids
+
+<span class="keyword">def</span> <span class="function-name">getdots</span>(root, dirsize, kids):
+ size = cursize = dirsize[root]
+ <span class="keyword">if</span> kids.has_key(root):
+ <span class="keyword">for</span> kid <span class="keyword">in</span> kids[root]:
+ cursize -= dirsize[kid]
+ getdots(kid, dirsize, kids)
+ <span class="keyword">if</span> size != cursize:
+ dot = root + <span class="string">"/."</span>
+ dirsize[dot] = cursize
+ kids[root].append(dot)
+
+<span class="keyword">def</span> <span class="function-name">output</span>(root, dirsize, kids, prefix = <span class="string">""</span>, width = 0):
+ path = os.path.basename(root)
+ size = dirsize[root]
+ fmt = <span class="string">"%"</span> + <span class="py-builtins">str</span>(width) + <span class="string">"d %s"</span>
+ line = fmt % (size, path)
+ <span class="keyword">print</span> prefix + line
+
+ prefix += (<span class="string">" "</span> * (width-1)) + <span class="string">"| "</span> + (<span class="string">" "</span> * <span class="py-builtins">len</span>(path))
+
+ <span class="keyword">if</span> kids.has_key(root):
+ kid_list = kids[root]
+ kid_list.sort(<span class="keyword">lambda</span> x, y, dirsize=dirsize:
+ <span class="py-builtins">cmp</span>(dirsize[x], dirsize[y]))
+ width = <span class="py-builtins">len</span>(str(dirsize[kid_list[-1]]))
+ <span class="keyword">for</span> kid <span class="keyword">in</span> kid_list:
+ output(kid, dirsize, kids, prefix, width)
+
+<span class="keyword">def</span> <span class="function-name">main</span>():
+ root, dirsize, kids = get_input(sys.argv[1:])
+ getdots(root, dirsize, kids)
+ output(root, dirsize, kids)
+
+<span class="keyword">if</span> <span class="py-builtins">__name__</span> == <span class="string">"__main__"</span>:
+ main()</PRE
+></TD
+></TR
+></TABLE
+></DIV
+></DIV
+><DIV
+CLASS="NAVFOOTER"
+><HR
+ALIGN="LEFT"
+WIDTH="100%"><TABLE
+SUMMARY="Footer navigation table"
+WIDTH="100%"
+BORDER="0"
+CELLPADDING="0"
+CELLSPACING="0"
+><TR
+><TD
+WIDTH="33%"
+ALIGN="left"
+VALIGN="top"
+><A
+HREF="arrays.html"
+ACCESSKEY="P"
+>Prev</A
+></TD
+><TD
+WIDTH="34%"
+ALIGN="center"
+VALIGN="top"
+><A
+HREF="index.html"
+ACCESSKEY="H"
+>Home</A
+></TD
+><TD
+WIDTH="33%"
+ALIGN="right"
+VALIGN="top"
+><A
+HREF="patternmatching.html"
+ACCESSKEY="N"
+>Next</A
+></TD
+></TR
+><TR
+><TD
+WIDTH="33%"
+ALIGN="left"
+VALIGN="top"
+>Arrays</TD
+><TD
+WIDTH="34%"
+ALIGN="center"
+VALIGN="top"
+>&nbsp;</TD
+><TD
+WIDTH="33%"
+ALIGN="right"
+VALIGN="top"
+>Pattern Matching</TD
+></TR
+></TABLE
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/help/PythonExamples/pleac_python/index.html b/help/PythonExamples/pleac_python/index.html
new file mode 100644
index 0000000..525e94e
--- /dev/null
+++ b/help/PythonExamples/pleac_python/index.html
@@ -0,0 +1,284 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML
+><HEAD
+><TITLE
+>PLEAC-Python
+</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
+REL="NEXT"
+TITLE="Strings"
+HREF="strings.html"><style type="text/css"> <!--
+ .comment {
+ /* font-lock-comment-face */
+ color: #bebebe;
+ }
+ .comment-delimiter {
+ }
+ .function-name {
+ /* font-lock-function-name-face */
+ color: #b2dfee;
+ }
+ .keyword {
+ /* font-lock-keyword-face */
+ color: #ffa500;
+ }
+ .py-builtins {
+ /* py-builtins-face */
+ color: #ffa500;
+ }
+ .py-pseudo-keyword {
+ /* py-pseudo-keyword-face */
+ color: #ffa500;
+ }
+ .string {
+ /* font-lock-string-face */
+ color: #00cd00;
+ }
+ .type {
+ /* font-lock-type-face */
+ color: #98fb98;
+ }
+ -->
+ </style></head
+><BODY TEXT="#cecece" BGCOLOR="#4f6f6f" LINK="#f5deb3" VLINK="#d5ae83"
+CLASS="ARTICLE"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><DIV
+CLASS="ARTICLE"
+><DIV
+CLASS="TITLEPAGE"
+><H1
+CLASS="TITLE"
+><A
+NAME="AEN2"
+>PLEAC-Python
+</A
+></H1
+><HR></DIV
+><DIV
+CLASS="TOC"
+><DL
+><DT
+><B
+>Table of Contents</B
+></DT
+><DT
+><A
+HREF="index.html#AEN4"
+>Foreword</A
+></DT
+><DT
+>1. <A
+HREF="strings.html"
+>Strings</a> (100.0%)</br
+></DT
+><DT
+>2. <A
+HREF="numbers.html"
+>Numbers</a> (100.0%)</br
+></DT
+><DT
+>3. <A
+HREF="datesandtimes.html"
+>Dates and Times</a> (100.0%)</br
+></DT
+><DT
+>4. <A
+HREF="arrays.html"
+>Arrays</a> (100.0%)</br
+></DT
+><DT
+>5. <A
+HREF="hashes.html"
+>Hashes</a> (100.0%)</br
+></DT
+><DT
+>6. <A
+HREF="patternmatching.html"
+>Pattern Matching</a> (91.7%)</br
+></DT
+><DT
+>7. <A
+HREF="fileaccess.html"
+>File Access</a> (82.6%)</br
+></DT
+><DT
+>8. <A
+HREF="filecontents.html"
+>File Contents</a> (92.9%)</br
+></DT
+><DT
+>9. <A
+HREF="directories.html"
+>Directories</a> (92.3%)</br
+></DT
+><DT
+>10. <A
+HREF="subroutines.html"
+>Subroutines</a> (100.0%)</br
+></DT
+><DT
+>11. <A
+HREF="referencesandrecords.html"
+>References and Records</a> (96.9%)</br
+></DT
+><DT
+>12. <A
+HREF="packagesetc.html"
+>Packages, Libraries, and Modules</a> (92.5%)</br
+></DT
+><DT
+>13. <A
+HREF="classesetc.html"
+>Classes, Objects, and Ties</a> (100.0%)</br
+></DT
+><DT
+>14. <A
+HREF="dbaccess.html"
+>Database Access</a> (66.7%)</br
+></DT
+><DT
+>15. <A
+HREF="userinterfaces.html"
+>User Interfaces</a> (60.5%)</br
+></DT
+><DT
+>16. <A
+HREF="processmanagementetc.html"
+>Process Management and Communication</a> (68.2%)</br
+></DT
+><DT
+>17. <A
+HREF="sockets.html"
+>Sockets</a> (63.2%)</br
+></DT
+><DT
+>18. <A
+HREF="internetservices.html"
+>Internet Services</a> (66.7%)</br
+></DT
+><DT
+>19. <A
+HREF="cgiprogramming.html"
+>CGI Programming</a> (63.3%)</br
+></DT
+><DT
+>20. <A
+HREF="webautomation.html"
+>Web Automation</a> (59.4%)</br
+></DT
+><DT
+>A. <A
+HREF="a1102.html"
+>Helpers</A
+></DT
+></DL
+></DIV
+><DIV
+CLASS="SECT1"
+><H1
+CLASS="SECT1"
+><A
+NAME="AEN4"
+>Foreword</A
+></H1
+><P
+>Following the <A
+HREF="http://www.oreilly.com/catalog/cookbook"
+TARGET="_top"
+>Perl
+Cookbook</A
+> (by Tom Christiansen and Nathan Torkington, published by
+O'Reilly) spirit, the <A
+HREF="http://pleac.sourceforge.net"
+TARGET="_top"
+>PLEAC
+Project</A
+> aims to gather fans of programming, in order to implement
+the solutions in other programming languages.</P
+><P
+>In this document, you'll find an implementation of the Solutions of the
+Perl Cookbook in the <A
+HREF="http://www.python.org
+"
+TARGET="_top"
+>Python
+</A
+> language.</P
+><P
+>The latest version of Python is 2.4 but users of 2.3 and 2.2 (and
+in some cases earlier versions) can use the code herein.
+Users of 2.2 and 2.3 should install or copy code from utils.py
+(http://aima.cs.berkeley.edu/python/utils.py)
+[the first section provides compatability code with 2.4]
+Users of 2.2 should install optik (http://optik.sourceforge.com)
+[for optparse and textwrap]
+Where a 2.3 or 2.4 feature is unable to be replicated, an effort
+has been made to provide a backward-compatible version in addition
+to one using modern idioms.
+Examples which translate the original Perl closely but which are
+unPythonic are prefixed with a comment stating "DON'T DO THIS".
+In some cases, it may be useful to know the techniques in these,
+though it's a bad solution for the specific problem.
+</span></P
+></DIV
+></DIV
+><DIV
+CLASS="NAVFOOTER"
+><HR
+ALIGN="LEFT"
+WIDTH="100%"><TABLE
+SUMMARY="Footer navigation table"
+WIDTH="100%"
+BORDER="0"
+CELLPADDING="0"
+CELLSPACING="0"
+><TR
+><TD
+WIDTH="33%"
+ALIGN="left"
+VALIGN="top"
+>&nbsp;</TD
+><TD
+WIDTH="34%"
+ALIGN="center"
+VALIGN="top"
+>&nbsp;</TD
+><TD
+WIDTH="33%"
+ALIGN="right"
+VALIGN="top"
+><A
+HREF="strings.html"
+ACCESSKEY="N"
+>Next</A
+></TD
+></TR
+><TR
+><TD
+WIDTH="33%"
+ALIGN="left"
+VALIGN="top"
+>&nbsp;</TD
+><TD
+WIDTH="34%"
+ALIGN="center"
+VALIGN="top"
+>&nbsp;</TD
+><TD
+WIDTH="33%"
+ALIGN="right"
+VALIGN="top"
+>Strings</TD
+></TR
+></TABLE
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/help/PythonExamples/pleac_python/internetservices.html b/help/PythonExamples/pleac_python/internetservices.html
new file mode 100644
index 0000000..ab5db76
--- /dev/null
+++ b/help/PythonExamples/pleac_python/internetservices.html
@@ -0,0 +1,502 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML
+><HEAD
+><TITLE
+>Internet Services</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
+REL="HOME"
+TITLE="PLEAC-Python
+"
+HREF="index.html"><LINK
+REL="PREVIOUS"
+TITLE="Sockets"
+HREF="sockets.html"><LINK
+REL="NEXT"
+TITLE="CGI Programming"
+HREF="cgiprogramming.html"><style type="text/css"> <!--
+ .comment {
+ /* font-lock-comment-face */
+ color: #bebebe;
+ }
+ .comment-delimiter {
+ }
+ .function-name {
+ /* font-lock-function-name-face */
+ color: #b2dfee;
+ }
+ .keyword {
+ /* font-lock-keyword-face */
+ color: #ffa500;
+ }
+ .py-builtins {
+ /* py-builtins-face */
+ color: #ffa500;
+ }
+ .py-pseudo-keyword {
+ /* py-pseudo-keyword-face */
+ color: #ffa500;
+ }
+ .string {
+ /* font-lock-string-face */
+ color: #00cd00;
+ }
+ .type {
+ /* font-lock-type-face */
+ color: #98fb98;
+ }
+ -->
+ </style></head
+><BODY TEXT="#cecece" BGCOLOR="#4f6f6f" LINK="#f5deb3" VLINK="#d5ae83"
+CLASS="SECT1"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><DIV
+CLASS="NAVHEADER"
+><TABLE
+SUMMARY="Header navigation table"
+WIDTH="100%"
+BORDER="0"
+CELLPADDING="0"
+CELLSPACING="0"
+><TR
+><TH
+COLSPAN="3"
+ALIGN="center"
+>PLEAC-Python
+</TH
+></TR
+><TR
+><TD
+WIDTH="10%"
+ALIGN="left"
+VALIGN="bottom"
+><A
+HREF="sockets.html"
+ACCESSKEY="P"
+>Prev</A
+></TD
+><TD
+WIDTH="80%"
+ALIGN="center"
+VALIGN="bottom"
+></TD
+><TD
+WIDTH="10%"
+ALIGN="right"
+VALIGN="bottom"
+><A
+HREF="cgiprogramming.html"
+ACCESSKEY="N"
+>Next</A
+></TD
+></TR
+></TABLE
+><HR
+ALIGN="LEFT"
+WIDTH="100%"></DIV
+><DIV
+CLASS="SECT1"
+><H1
+CLASS="SECT1"
+><A
+NAME="INTERNETSERVICES"
+>18. Internet Services</A
+></H1
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN978"
+>Simple DNS Lookups</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span>
+<span class="keyword">import</span> socket
+<span class="keyword">try:</span>
+ host_info = socket.gethostbyname_ex(name)
+ <span class="comment-delimiter"># </span><span class="comment">(hostname, aliaslist, ipaddrlist)
+</span><span class="keyword">except</span> socket.gaierror, err:
+ <span class="keyword">print</span> <span class="string">"Can't resolve hostname %s: %s"</span> % (name, err[1])
+
+<span class="comment-delimiter"># </span><span class="comment">if you only need the first one
+</span><span class="keyword">import</span> socket
+<span class="keyword">try:</span>
+ address = socket.gethostbyname(name)
+<span class="keyword">except</span> socket.gaierror, err:
+ <span class="keyword">print</span> <span class="string">"Can't resolve hostname %s: %s"</span> % (name, err[1])
+
+<span class="comment-delimiter"># </span><span class="comment">if you have an ip address
+</span><span class="keyword">try:</span>
+ host_info = socket.gethostbyaddr(address)
+ <span class="comment-delimiter"># </span><span class="comment">(hostname, aliaslist, ipaddrlist)
+</span><span class="keyword">except</span> socket.gaierror, err:
+ <span class="keyword">print</span> <span class="string">"Can't resolve address %s: %s"</span> % (address, err[1])
+
+<span class="comment-delimiter"># </span><span class="comment">checking back
+</span><span class="keyword">import</span> socket
+<span class="keyword">try:</span>
+ host_info = socket.gethostbyaddr(address)
+<span class="keyword">except</span> socket.gaierror, err:
+ <span class="keyword">print</span> <span class="string">"Can't look up %s: %s"</span> % (address, err[1])
+ <span class="keyword">raise</span> <span class="py-builtins">SystemExit</span>(1)
+<span class="keyword">try:</span>
+ host_info = socket.gethostbyname_ex(name)
+<span class="keyword">except:</span>
+ <span class="keyword">print</span> <span class="string">"Can't look up %s: %s"</span> % (name, err[1])
+ <span class="keyword">raise</span> <span class="py-builtins">SystemExit</span>(1)
+
+found = address <span class="keyword">in</span> host_info[2]
+
+<span class="comment-delimiter"># </span><span class="comment">use dnspython for more complex jobs.
+</span><span class="comment-delimiter"># </span><span class="comment"><font size="-1"><a href="http://pleac.sourceforge.net/include/python/ch18/mxhost">download the following standalone program</a></font>
+</span><span class="comment-delimiter">#</span><span class="comment">!/usr/bin/python
+</span><span class="comment-delimiter"># </span><span class="comment">mxhost - find mx exchangers for a host
+</span>
+<span class="keyword">import</span> sys
+
+<span class="keyword">import</span> dns
+<span class="keyword">import</span> dns.resolver
+
+answers = dns.resolver.query(sys.argv[1], <span class="string">'MX'</span>)
+<span class="keyword">for</span> rdata <span class="keyword">in</span> answers:
+ <span class="keyword">print</span> rdata.preference, rdata.exchange
+
+
+
+<span class="comment-delimiter"># </span><span class="comment"><font size="-1"><a href="http://pleac.sourceforge.net/include/python/ch18/hostaddrs">download the following standalone program</a></font>
+</span><span class="comment-delimiter">#</span><span class="comment">!/usr/bin/python
+</span><span class="comment-delimiter"># </span><span class="comment">hostaddrs - canonize name and show addresses
+</span>
+<span class="keyword">import</span> sys
+<span class="keyword">import</span> socket
+name = sys.argv[1]
+hent = socket.gethostbyname_ex(name)
+<span class="keyword">print</span> <span class="string">"%s aliases: %s =&gt; %s"</span> % (
+ hent[0],
+ <span class="py-builtins">len</span>(hent[1])==0 <span class="keyword">and</span> <span class="string">"None"</span> <span class="keyword">or</span> <span class="string">","</span>.join(hent[1]),
+ <span class="string">","</span>.join(hent[2]) )</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN981"
+>Being an FTP Client</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="keyword">import</span> ftplib
+ftp = ftplib.FTP(<span class="string">"ftp.host.com"</span>)
+ftp.login(username, password)
+ftp.cwd(directory)
+
+<span class="comment-delimiter"># </span><span class="comment">get file
+</span>outfile = <span class="py-builtins">open</span>(filename, <span class="string">"wb"</span>)
+ftp.retrbinary(<span class="string">"RETR %s"</span> % filename, outfile.write)
+outfile.close()
+
+<span class="comment-delimiter"># </span><span class="comment">upload file
+</span>upfile = <span class="py-builtins">open</span>(upfilename, <span class="string">"rb"</span>)
+ftp.storbinary(<span class="string">"STOR %s"</span> % upfilename, upfile)
+upfile.close()
+
+ftp.quit()</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN984"
+>Sending Mail</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="keyword">import</span> smtplib
+<span class="keyword">from</span> email.MIMEText <span class="keyword">import</span> MIMEText
+
+msg = MIMEText(body)
+msg[<span class="string">'From'</span>] = from_address
+msg[<span class="string">'To'</span>] = to_address
+msg[<span class="string">'Subject'</span>] = subject
+
+mailer = smtplib.SMTP()
+mailer.connect()
+mailer.sendmail(from_address, [to_address], msg.as_string())</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN987"
+>Reading and Posting Usenet News Messages</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="keyword">import</span> nntplib
+
+<span class="comment-delimiter"># </span><span class="comment">You can except nntplib.NNTPError to process errors
+</span><span class="comment-delimiter"># </span><span class="comment">instead of displaying traceback.
+</span>
+server = nntplib.NNTP(<span class="string">"news.example.com"</span>)
+response, count, first, last, name = server.group(<span class="string">"misc.test"</span>)
+headers = server.head(first)
+bodytext = server.body(first)
+article = server.article(first)
+
+f = <span class="py-builtins">file</span>(<span class="string">"article.txt"</span>)
+server.post(f)
+
+response, grouplist = server.list()
+<span class="keyword">for</span> group <span class="keyword">in</span> grouplist:
+ name, last, first, flag = group
+ <span class="keyword">if</span> flag == <span class="string">'y'</span>:
+ <span class="keyword">pass</span> <span class="comment-delimiter"># </span><span class="comment">I can post to group
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN990"
+>Reading Mail with POP3</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="keyword">import</span> poplib
+
+pop = poplib.POP3(<span class="string">"mail.example.com"</span>)
+pop.user(username)
+pop.pass_(password)
+count, size = pop.stat()
+<span class="keyword">for</span> i <span class="keyword">in</span> <span class="py-builtins">range</span>(1, count+1):
+ reponse, message, octets = pop.retr(i)
+ <span class="comment-delimiter"># </span><span class="comment">message is a list of lines
+</span> pop.dele(i)
+
+<span class="comment-delimiter"># </span><span class="comment">You must quit, otherwise mailbox remains locked.
+</span>pop.quit()</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN993"
+>Simulating Telnet from a Program</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span>
+<span class="keyword">import</span> telnetlib
+
+tn = telnetlib.Telnet(hostname)
+
+tn.read_until(<span class="string">"login: "</span>)
+tn.write(user + <span class="string">"\n"</span>)
+tn.read_until(<span class="string">"Password: "</span>)
+tn.write(password + <span class="string">"\n"</span>)
+<span class="comment-delimiter"># </span><span class="comment">read the logon message up to the prompt
+</span>d = tn.expect([prompt,], 10)
+tn.write(<span class="string">"ls\n"</span>)
+files = d[2].split()
+<span class="keyword">print</span> <span class="py-builtins">len</span>(files), <span class="string">"files"</span>
+tn.write(<span class="string">"exit\n"</span>)
+<span class="keyword">print</span> tn.read_all() <span class="comment-delimiter"># </span><span class="comment">blocks till eof
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN996"
+>Pinging a Machine</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN999"
+>Using Whois to Retrieve Information from the InterNIC</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN1002"
+>Program: expn and vrfy</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+></DIV
+><DIV
+CLASS="NAVFOOTER"
+><HR
+ALIGN="LEFT"
+WIDTH="100%"><TABLE
+SUMMARY="Footer navigation table"
+WIDTH="100%"
+BORDER="0"
+CELLPADDING="0"
+CELLSPACING="0"
+><TR
+><TD
+WIDTH="33%"
+ALIGN="left"
+VALIGN="top"
+><A
+HREF="sockets.html"
+ACCESSKEY="P"
+>Prev</A
+></TD
+><TD
+WIDTH="34%"
+ALIGN="center"
+VALIGN="top"
+><A
+HREF="index.html"
+ACCESSKEY="H"
+>Home</A
+></TD
+><TD
+WIDTH="33%"
+ALIGN="right"
+VALIGN="top"
+><A
+HREF="cgiprogramming.html"
+ACCESSKEY="N"
+>Next</A
+></TD
+></TR
+><TR
+><TD
+WIDTH="33%"
+ALIGN="left"
+VALIGN="top"
+>Sockets</TD
+><TD
+WIDTH="34%"
+ALIGN="center"
+VALIGN="top"
+>&nbsp;</TD
+><TD
+WIDTH="33%"
+ALIGN="right"
+VALIGN="top"
+>CGI Programming</TD
+></TR
+></TABLE
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/help/PythonExamples/pleac_python/numbers.html b/help/PythonExamples/pleac_python/numbers.html
new file mode 100644
index 0000000..1ca5921
--- /dev/null
+++ b/help/PythonExamples/pleac_python/numbers.html
@@ -0,0 +1,963 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML
+><HEAD
+><TITLE
+>Numbers</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
+REL="HOME"
+TITLE="PLEAC-Python
+"
+HREF="index.html"><LINK
+REL="PREVIOUS"
+TITLE="Strings"
+HREF="strings.html"><LINK
+REL="NEXT"
+TITLE="Dates and Times"
+HREF="datesandtimes.html"><style type="text/css"> <!--
+ .comment {
+ /* font-lock-comment-face */
+ color: #bebebe;
+ }
+ .comment-delimiter {
+ }
+ .function-name {
+ /* font-lock-function-name-face */
+ color: #b2dfee;
+ }
+ .keyword {
+ /* font-lock-keyword-face */
+ color: #ffa500;
+ }
+ .py-builtins {
+ /* py-builtins-face */
+ color: #ffa500;
+ }
+ .py-pseudo-keyword {
+ /* py-pseudo-keyword-face */
+ color: #ffa500;
+ }
+ .string {
+ /* font-lock-string-face */
+ color: #00cd00;
+ }
+ .type {
+ /* font-lock-type-face */
+ color: #98fb98;
+ }
+ -->
+ </style></head
+><BODY TEXT="#cecece" BGCOLOR="#4f6f6f" LINK="#f5deb3" VLINK="#d5ae83"
+CLASS="SECT1"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><DIV
+CLASS="NAVHEADER"
+><TABLE
+SUMMARY="Header navigation table"
+WIDTH="100%"
+BORDER="0"
+CELLPADDING="0"
+CELLSPACING="0"
+><TR
+><TH
+COLSPAN="3"
+ALIGN="center"
+>PLEAC-Python
+</TH
+></TR
+><TR
+><TD
+WIDTH="10%"
+ALIGN="left"
+VALIGN="bottom"
+><A
+HREF="strings.html"
+ACCESSKEY="P"
+>Prev</A
+></TD
+><TD
+WIDTH="80%"
+ALIGN="center"
+VALIGN="bottom"
+></TD
+><TD
+WIDTH="10%"
+ALIGN="right"
+VALIGN="bottom"
+><A
+HREF="datesandtimes.html"
+ACCESSKEY="N"
+>Next</A
+></TD
+></TR
+></TABLE
+><HR
+ALIGN="LEFT"
+WIDTH="100%"></DIV
+><DIV
+CLASS="SECT1"
+><H1
+CLASS="SECT1"
+><A
+NAME="NUMBERS"
+>2. Numbers</A
+></H1
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN73"
+>Checking Whether a String Is a Valid Number</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">The standard way of validating numbers is to convert them and catch
+</span><span class="comment-delimiter"># </span><span class="comment">an exception on failure
+</span>
+<span class="keyword">try:</span>
+ myfloat = <span class="py-builtins">float</span>(mystr)
+ <span class="keyword">print</span> <span class="string">"is a decimal number"</span>
+<span class="keyword">except</span> <span class="py-builtins">TypeError</span>:
+ <span class="keyword">print</span> <span class="string">"is not a decimal number"</span>
+
+<span class="keyword">try:</span>
+ myint = <span class="py-builtins">int</span>(mystr)
+ <span class="keyword">print</span> <span class="string">"is an integer"</span>
+<span class="keyword">except</span> <span class="py-builtins">TypeError</span>:
+ <span class="keyword">print</span> <span class="string">"is not an integer"</span>
+
+<span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS. Explicit checking is prone to errors:
+</span><span class="keyword">if</span> mystr.isdigit(): <span class="comment-delimiter"># </span><span class="comment">Fails on "+4"
+</span> <span class="keyword">print</span> <span class="string">'is a positive integer'</span>
+<span class="keyword">else:</span>
+ <span class="keyword">print</span> <span class="string">'is not'</span>
+
+<span class="keyword">if</span> re.match(<span class="string">"[+-]?\d+$"</span>, mystr): <span class="comment-delimiter"># </span><span class="comment">Fails on "- 1"
+</span> <span class="keyword">print</span> <span class="string">'is an integer'</span>
+<span class="keyword">else:</span>
+ <span class="keyword">print</span> <span class="string">'is not'</span>
+
+<span class="keyword">if</span> re.match(<span class="string">"-?(?:\d+(?:\.\d*)?|\.\d+)$"</span>, mystr): <span class="comment-delimiter"># </span><span class="comment">Opaque, and fails on "- 1"
+</span> <span class="keyword">print</span> <span class="string">'is a decimal number'</span>
+<span class="keyword">else:</span>
+ <span class="keyword">print</span> <span class="string">'is not'</span>
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN76"
+>Comparing Floating-Point Numbers</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">equal(num1, num2, accuracy) : returns true if num1 and num2 are
+</span><span class="comment-delimiter"># </span><span class="comment">equal to accuracy number of decimal places
+</span>
+<span class="keyword">def</span> <span class="function-name">equal</span>(num1, num2, accuracy):
+ <span class="keyword">return</span> <span class="py-builtins">abs</span>(num1 - num2) &lt; 10**(-accuracy)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">from</span> __future__ <span class="keyword">import</span> division <span class="comment-delimiter"># </span><span class="comment">use / for float div and // for int div
+</span>
+wage = 536 <span class="comment-delimiter"># </span><span class="comment">$5.36/hour
+</span>week = 40 * wage <span class="comment-delimiter"># </span><span class="comment">$214.40
+</span><span class="keyword">print</span> <span class="string">"One week's wage is: $%.2f"</span> % (week/100)
+<span class="comment-delimiter">#</span><span class="comment">=&gt; One week's wage is: $214.40
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN79"
+>Rounding Floating-Point Numbers</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>rounded = <span class="py-builtins">round</span>(num) <span class="comment-delimiter"># </span><span class="comment">rounds to integer
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>a = 0.255
+b = <span class="string">"%.2f"</span> % a
+<span class="keyword">print</span> <span class="string">"Unrounded: %f\nRounded: %s"</span> % (a, b)
+<span class="keyword">print</span> <span class="string">"Unrounded: %f\nRounded: %.2f"</span> % (a, a)
+<span class="comment-delimiter">#</span><span class="comment">=&gt; Unrounded: 0.255000
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt; Rounded: 0.26
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt; Unrounded: 0.255000
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt; Rounded: 0.26
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">from</span> math <span class="keyword">import</span> floor, ceil
+
+<span class="keyword">print</span> <span class="string">"number\tint\tfloor\tceil"</span>
+a = [3.3, 3.5, 3.7, -3.3]
+<span class="keyword">for</span> n <span class="keyword">in</span> a:
+ <span class="keyword">print</span> <span class="string">"% .1f\t% .1f\t% .1f\t% .1f"</span> % (n, <span class="py-builtins">int</span>(n), floor(n), ceil(n))
+<span class="comment-delimiter">#</span><span class="comment">=&gt; number int floor ceil
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt; 3.3 3.0 3.0 4.0
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt; 3.5 3.0 3.0 4.0
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt; 3.7 3.0 3.0 4.0
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt; -3.3 -3.0 -4.0 -3.0
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN82"
+>Converting Between Binary and Decimal</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">To convert a string in any base up to base 36, use the optional arg to int():
+</span>num = <span class="py-builtins">int</span>(<span class="string">'0110110'</span>, 2) <span class="comment-delimiter"># </span><span class="comment">num is 54
+</span>
+<span class="comment-delimiter"># </span><span class="comment">To convert an int to an string representation in another base, you could use
+</span><span class="comment-delimiter"># </span><span class="comment">&lt;<a href="http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/111286">http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/111286</a>&gt;:
+</span><span class="keyword">import</span> baseconvert
+<span class="keyword">def</span> <span class="function-name">dec2bin</span>(i):
+ <span class="keyword">return</span> baseconvert.baseconvert(i, baseconvert.BASE10, baseconvert.BASE2)
+
+binstr = dec2bin(54) <span class="comment-delimiter"># </span><span class="comment">binstr is 110110
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN85"
+>Operating on a Series of Integers</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">for</span> i <span class="keyword">in</span> <span class="py-builtins">range</span>(x,y):
+ <span class="keyword">pass</span> <span class="comment-delimiter"># </span><span class="comment">i is set to every integer from x to y, excluding y
+</span>
+<span class="keyword">for</span> i <span class="keyword">in</span> <span class="py-builtins">range</span>(x, y, 7):
+ <span class="keyword">pass</span> <span class="comment-delimiter"># </span><span class="comment">i is set to every integer from x to y, stepsize = 7
+</span>
+<span class="keyword">print</span> <span class="string">"Infancy is:"</span>,
+<span class="keyword">for</span> i <span class="keyword">in</span> <span class="py-builtins">range</span>(0,3):
+ <span class="keyword">print</span> i,
+<span class="keyword">print</span>
+
+<span class="keyword">print</span> <span class="string">"Toddling is:"</span>,
+<span class="keyword">for</span> i <span class="keyword">in</span> <span class="py-builtins">range</span>(3,5):
+ <span class="keyword">print</span> i,
+<span class="keyword">print</span>
+
+<span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS:
+</span><span class="keyword">print</span> <span class="string">"Childhood is:"</span>,
+i = 5
+<span class="keyword">while</span> i &lt;= 12:
+ <span class="keyword">print</span> i
+ i += 1
+
+<span class="comment-delimiter">#</span><span class="comment">=&gt; Infancy is: 0 1 2
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt; Toddling is: 3 4
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt; Childhood is: 5 6 7 8 9 10 11 12
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN88"
+>Working with Roman Numerals</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">See http://www.faqts.com/knowledge_base/view.phtml/aid/4442
+</span><span class="comment-delimiter"># </span><span class="comment">for a module that does this
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN91"
+>Generating Random Numbers</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> random <span class="comment-delimiter"># </span><span class="comment">use help(random) to see the (large) list of funcs
+</span>
+rand = random.randint(x, y)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>rand = random.randint(25, 76)
+<span class="keyword">print</span> rand
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>elt = random.choice(mylist)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> string
+chars = string.letters + string.digits + <span class="string">"!@$%^&amp;*"</span>
+password = <span class="string">""</span>.join([random.choice(chars) <span class="keyword">for</span> i <span class="keyword">in</span> <span class="py-builtins">range</span>(8)])
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN94"
+>Generating Different Random Numbers</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Changes the default RNG
+</span>random.seed()
+
+<span class="comment-delimiter"># </span><span class="comment">Or you can create independent RNGs
+</span>gen1 = random.Random(6)
+gen2 = random.Random(6)
+gen3 = random.Random(10)
+a1, b1 = gen1.random(), gen1.random()
+a2, b2 = gen2.random(), gen2.random()
+a3, b3 = gen3.random(), gen3.random()
+<span class="comment-delimiter"># </span><span class="comment">a1 == a2 and b1 == b2
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN97"
+>Making Numbers Even More Random</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">see http://www.sbc.su.se/~per/crng/ or http://www.frohne.westhost.com/rv11reference.htm
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN100"
+>Generating Biased Random Numbers</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> random
+mean = 25
+sdev = 2
+salary = random.gauss(mean, sdev)
+<span class="keyword">print</span> <span class="string">"You have been hired at %.2f"</span> % salary
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN103"
+>Doing Trigonometry in Degrees, not Radians</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>radians = math.radians(degrees)
+degrees = math.degrees(radians)
+
+<span class="comment-delimiter"># </span><span class="comment">pre-2.3:
+</span><span class="keyword">from</span> __future__ <span class="keyword">import</span> division
+<span class="keyword">import</span> math
+<span class="keyword">def</span> <span class="function-name">deg2rad</span>(degrees):
+ <span class="keyword">return</span> (degrees / 180) * math.pi
+<span class="keyword">def</span> <span class="function-name">rad2deg</span>(radians):
+ <span class="keyword">return</span> (radians / math.pi) * 180
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Use deg2rad instead of math.radians if you have pre-2.3 Python.
+</span><span class="keyword">import</span> math
+<span class="keyword">def</span> <span class="function-name">degree_sine</span>(degrees):
+ radians = math.radians(degrees)
+ <span class="keyword">return</span> math.sin(radians)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN106"
+>Calculating More Trigonometric Functions</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> math
+
+<span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS. Use math.tan() instead.
+</span><span class="keyword">def</span> <span class="function-name">tan</span>(theta):
+ <span class="keyword">return</span> math.sin(theta) / math.cos(theta)
+<span class="comment-delimiter">#</span><span class="comment">----------------
+</span><span class="comment-delimiter"># </span><span class="comment">NOTE: this sets y to 16331239353195370.0
+</span><span class="keyword">try:</span>
+ y = math.tan(math.pi/2)
+<span class="keyword">except</span> <span class="py-builtins">ValueError</span>:
+ y = <span class="py-pseudo-keyword">None</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN109"
+>Taking Logarithms</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> math
+log_e = math.log(VALUE)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>log_10 = math.log10(VALUE)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">def</span> <span class="function-name">log_base</span>(base, value):
+ <span class="keyword">return</span> math.log(value) / math.log(base)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">log_base defined as above
+</span>answer = log_base(10, 10000)
+<span class="keyword">print</span> <span class="string">"log10(10,000) ="</span>, answer
+<span class="comment-delimiter">#</span><span class="comment">=&gt; log10(10,000) = 4.0
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN112"
+>Multiplying Matrices</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">NOTE: must have NumPy installed. See
+</span><span class="comment-delimiter"># </span><span class="comment">http://www.pfdubois.com/numpy/
+</span>
+<span class="keyword">import</span> Numeric
+a = Numeric.array( ((3, 2, 3),
+ (5, 9, 8) ), <span class="string">"d"</span>)
+b = Numeric.array( ((4, 7),
+ (9, 3),
+ (8, 1) ), <span class="string">"d"</span>)
+c = Numeric.matrixmultiply(a, b)
+
+<span class="keyword">print</span> c
+<span class="comment-delimiter">#</span><span class="comment">=&gt; [[ 54. 30.]
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt; [ 165. 70.]]
+</span>
+<span class="keyword">print</span> a.shape, b.shape, c.shape
+<span class="comment-delimiter">#</span><span class="comment">=&gt; (2, 3) (3, 2) (2, 2)
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN115"
+>Using Complex Numbers</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>a = 3+5j
+b = 2-2j
+c = a * b
+<span class="keyword">print</span> <span class="string">"c ="</span>, c
+<span class="comment-delimiter">#</span><span class="comment">=&gt; c = (16+4j)
+</span>
+<span class="keyword">print</span> c.real, c.imag, c.conjugate()
+<span class="comment-delimiter">#</span><span class="comment">=&gt; 16.0 4.0 (16-4j)
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> cmath
+<span class="keyword">print</span> cmath.sqrt(3+4j)
+<span class="comment-delimiter">#</span><span class="comment">=&gt; (2+1j)
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN118"
+>Converting Between Octal and Hexadecimal</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>number = <span class="py-builtins">int</span>(hexadecimal, 16)
+number = <span class="py-builtins">int</span>(octal, 8)
+s = <span class="py-builtins">hex</span>(number)
+s = <span class="py-builtins">oct</span>(number)
+
+num = <span class="py-builtins">raw_input</span>(<span class="string">"Gimme a number in decimal, octal, or hex: "</span>).rstrip()
+<span class="keyword">if</span> num.startswith(<span class="string">"0x"</span>):
+ num = <span class="py-builtins">int</span>(num[2:], 16)
+<span class="keyword">elif</span> num.startswith(<span class="string">"0"</span>):
+ num = <span class="py-builtins">int</span>(num[1:], 8)
+<span class="keyword">else:</span>
+ num = <span class="py-builtins">int</span>(num)
+<span class="keyword">print</span> <span class="string">"%(num)d %(num)x %(num)o\n"</span> % { <span class="string">"num"</span>: num }
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN121"
+>Putting Commas in Numbers</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">def</span> <span class="function-name">commify</span>(amount):
+ amount = <span class="py-builtins">str</span>(amount)
+ firstcomma = <span class="py-builtins">len</span>(amount)%3 <span class="keyword">or</span> 3 <span class="comment-delimiter"># </span><span class="comment">set to 3 if would make a leading comma
+</span> first, rest = amount[:firstcomma], amount[firstcomma:]
+ segments = [first] + [rest[i:i+3] <span class="keyword">for</span> i <span class="keyword">in</span> <span class="py-builtins">range</span>(0, <span class="py-builtins">len</span>(rest), 3)]
+ <span class="keyword">return</span> <span class="string">","</span>.join(segments)
+
+<span class="keyword">print</span> commify(12345678)
+<span class="comment-delimiter">#</span><span class="comment">=&gt; 12,345,678
+</span>
+<span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS. It works on 2.3+ only and is slower and less straightforward
+</span><span class="comment-delimiter"># </span><span class="comment">than the non-regex version above.
+</span><span class="keyword">import</span> re
+<span class="keyword">def</span> <span class="function-name">commify</span>(amount):
+ amount = <span class="py-builtins">str</span>(amount)
+ amount = amount[::-1]
+ amount = re.sub(r<span class="string">"(\d\d\d)(?=\d)(?!\d*\.)"</span>, r<span class="string">"\1,"</span>, amount)
+ <span class="keyword">return</span> amount[::-1]</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN124"
+>Printing Correct Plurals</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">Printing Correct Plurals
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">def</span> <span class="function-name">pluralise</span>(value, root, singular=<span class="string">""</span>, plural=<span class="string">"s"</span>):
+ <span class="keyword">if</span> value == 1:
+ <span class="keyword">return</span> root + singular
+ <span class="keyword">else:</span>
+ <span class="keyword">return</span> root + plural
+
+<span class="keyword">print</span> <span class="string">"It took"</span>, duration, pluralise(duration, <span class="string">'hour'</span>)
+
+<span class="keyword">print</span> <span class="string">"%d %s %s enough."</span> % (duration,
+ pluralise(duration, <span class="string">'hour'</span>),
+ pluralise(duration, <span class="string">''</span>, <span class="string">'is'</span>, <span class="string">'are'</span>))
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> re
+<span class="keyword">def</span> <span class="function-name">noun_plural</span>(word):
+ endings = [(<span class="string">"ss"</span>, <span class="string">"sses"</span>),
+ (<span class="string">"([psc]h)"</span>, r<span class="string">"\1es"</span>),
+ (<span class="string">"z"</span>, <span class="string">"zes"</span>),
+ (<span class="string">"ff"</span>, <span class="string">"ffs"</span>),
+ (<span class="string">"f"</span>, <span class="string">"ves"</span>),
+ (<span class="string">"ey"</span>, <span class="string">"eys"</span>),
+ (<span class="string">"y"</span>, <span class="string">"ies"</span>),
+ (<span class="string">"ix"</span>, <span class="string">"ices"</span>),
+ (<span class="string">"([sx])"</span>, r<span class="string">"\1es"</span>),
+ (<span class="string">""</span>, <span class="string">"s"</span>)]
+ <span class="keyword">for</span> singular, plural <span class="keyword">in</span> endings:
+ ret, found = re.subn(<span class="string">"%s$"</span>%singular, plural, word)
+ <span class="keyword">if</span> found:
+ <span class="keyword">return</span> ret
+
+verb_singular = noun_plural; <span class="comment-delimiter"># </span><span class="comment">make function alias
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN127"
+>Program: Calculating Prime Factors</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">Program: Calculating Prime Factors
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment">% bigfact 8 9 96 2178
+</span><span class="comment-delimiter">#</span><span class="comment">8 2**3
+</span><span class="comment-delimiter">#</span><span class="comment">
+</span><span class="comment-delimiter">#</span><span class="comment">9 3**2
+</span><span class="comment-delimiter">#</span><span class="comment">
+</span><span class="comment-delimiter">#</span><span class="comment">96 2**5 3
+</span><span class="comment-delimiter">#</span><span class="comment">
+</span><span class="comment-delimiter">#</span><span class="comment">2178 2 3**2 11**2
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment">% bigfact 239322000000000000000000
+</span><span class="comment-delimiter">#</span><span class="comment">239322000000000000000000 2**19 3 5**18 39887
+</span><span class="comment-delimiter">#</span><span class="comment">
+</span><span class="comment-delimiter">#</span><span class="comment">
+</span><span class="comment-delimiter">#</span><span class="comment">% bigfact 25000000000000000000000000
+</span><span class="comment-delimiter">#</span><span class="comment">25000000000000000000000000 2**24 5**26
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> sys
+
+<span class="keyword">def</span> <span class="function-name">factorise</span>(num):
+ factors = {}
+ orig = num
+ <span class="keyword">print</span> num, <span class="string">'\t'</span>,
+
+ <span class="comment-delimiter"># </span><span class="comment">we take advantage of the fact that (i +1)**2 = i**2 + 2*i +1
+</span> i, sqi = 2, 4
+ <span class="keyword">while</span> sqi &lt;= num:
+ <span class="keyword">while</span> <span class="keyword">not</span> num%i:
+ num /= i
+ factors[i] = factors.get(i, 0) + 1
+
+ sqi += 2*i + 1
+ i += 1
+
+ <span class="keyword">if</span> num != 1 <span class="keyword">and</span> num != orig:
+ factors[num] = factors.get(num, 0) + 1
+
+ <span class="keyword">if</span> <span class="keyword">not</span> factors:
+ <span class="keyword">print</span> <span class="string">"PRIME"</span>
+
+ <span class="keyword">for</span> factor <span class="keyword">in</span> sorted(factors):
+ <span class="keyword">if</span> factor:
+ tmp = <span class="py-builtins">str</span>(factor)
+ <span class="keyword">if</span> factors[factor]&gt;1: tmp += <span class="string">"**"</span> + <span class="py-builtins">str</span>(factors[factor])
+ <span class="keyword">print</span> tmp,
+ <span class="keyword">print</span>
+
+<span class="comment-delimiter">#</span><span class="comment">--------
+</span><span class="keyword">if</span> <span class="py-builtins">__name__</span> == <span class="string">'__main__'</span>:
+ <span class="keyword">if</span> <span class="py-builtins">len</span>(sys.argv) == 1:
+ <span class="keyword">print</span> <span class="string">"Usage:"</span>, sys.argv[0], <span class="string">" number [number, ]"</span>
+ <span class="keyword">else:</span>
+ <span class="keyword">for</span> strnum <span class="keyword">in</span> sys.argv[1:]:
+ <span class="keyword">try:</span>
+ num = <span class="py-builtins">int</span>(strnum)
+ factorise(num)
+ <span class="keyword">except</span> <span class="py-builtins">ValueError</span>:
+ <span class="keyword">print</span> strnum, <span class="string">"is not an integer"</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">A more Pythonic variant (which separates calculation from printing):
+</span><span class="keyword">def</span> <span class="function-name">format_factor</span>(base, exponent):
+ <span class="keyword">if</span> exponent &gt; 1:
+ <span class="keyword">return</span> <span class="string">"%s**%s"</span>%(base, exponent)
+ <span class="keyword">return</span> <span class="py-builtins">str</span>(base)
+
+<span class="keyword">def</span> <span class="function-name">factorise</span>(num):
+ factors = {}
+ orig = num
+
+ <span class="comment-delimiter"># </span><span class="comment">we take advantage of the fact that (i+1)**2 = i**2 + 2*i +1
+</span> i, sqi = 2, 4
+ <span class="keyword">while</span> sqi &lt;= num:
+ <span class="keyword">while</span> <span class="keyword">not</span> num%i:
+ num /= i
+ factors[i] = factors.get(i, 0) + 1
+ sqi += 2*i + 1
+ i += 1
+
+ <span class="keyword">if</span> num <span class="keyword">not</span> <span class="keyword">in</span> (1, orig):
+ factors[num] = factors.get(num, 0) + 1
+
+ <span class="keyword">if</span> <span class="keyword">not</span> factors:
+ <span class="keyword">return</span> [<span class="string">"PRIME"</span>]
+
+ out = [format_factor(base, exponent)
+ <span class="keyword">for</span> base, exponent <span class="keyword">in</span> sorted(factors.items())]
+ <span class="keyword">return</span> out
+
+<span class="keyword">def</span> <span class="function-name">print_factors</span>(value):
+ <span class="keyword">try:</span>
+ num = <span class="py-builtins">int</span>(value)
+ <span class="keyword">if</span> num != <span class="py-builtins">float</span>(value):
+ <span class="keyword">raise</span> <span class="py-builtins">ValueError</span>
+ <span class="keyword">except</span> (<span class="py-builtins">ValueError</span>, TypeError):
+ <span class="keyword">raise</span> <span class="py-builtins">ValueError</span>(<span class="string">"Can only factorise an integer"</span>)
+ factors = factorise(num)
+ <span class="keyword">print</span> num, <span class="string">"\t"</span>, <span class="string">" "</span>.join(factors)</PRE
+></TD
+></TR
+></TABLE
+></DIV
+></DIV
+><DIV
+CLASS="NAVFOOTER"
+><HR
+ALIGN="LEFT"
+WIDTH="100%"><TABLE
+SUMMARY="Footer navigation table"
+WIDTH="100%"
+BORDER="0"
+CELLPADDING="0"
+CELLSPACING="0"
+><TR
+><TD
+WIDTH="33%"
+ALIGN="left"
+VALIGN="top"
+><A
+HREF="strings.html"
+ACCESSKEY="P"
+>Prev</A
+></TD
+><TD
+WIDTH="34%"
+ALIGN="center"
+VALIGN="top"
+><A
+HREF="index.html"
+ACCESSKEY="H"
+>Home</A
+></TD
+><TD
+WIDTH="33%"
+ALIGN="right"
+VALIGN="top"
+><A
+HREF="datesandtimes.html"
+ACCESSKEY="N"
+>Next</A
+></TD
+></TR
+><TR
+><TD
+WIDTH="33%"
+ALIGN="left"
+VALIGN="top"
+>Strings</TD
+><TD
+WIDTH="34%"
+ALIGN="center"
+VALIGN="top"
+>&nbsp;</TD
+><TD
+WIDTH="33%"
+ALIGN="right"
+VALIGN="top"
+>Dates and Times</TD
+></TR
+></TABLE
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/help/PythonExamples/pleac_python/packagesetc.html b/help/PythonExamples/pleac_python/packagesetc.html
new file mode 100644
index 0000000..d0ac146
--- /dev/null
+++ b/help/PythonExamples/pleac_python/packagesetc.html
@@ -0,0 +1,1089 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML
+><HEAD
+><TITLE
+>Packages, Libraries, and Modules</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
+REL="HOME"
+TITLE="PLEAC-Python
+"
+HREF="index.html"><LINK
+REL="PREVIOUS"
+TITLE="References and Records"
+HREF="referencesandrecords.html"><LINK
+REL="NEXT"
+TITLE="Classes, Objects, and Ties"
+HREF="classesetc.html"><style type="text/css"> <!--
+ .comment {
+ /* font-lock-comment-face */
+ color: #bebebe;
+ }
+ .comment-delimiter {
+ }
+ .function-name {
+ /* font-lock-function-name-face */
+ color: #b2dfee;
+ }
+ .keyword {
+ /* font-lock-keyword-face */
+ color: #ffa500;
+ }
+ .py-builtins {
+ /* py-builtins-face */
+ color: #ffa500;
+ }
+ .py-pseudo-keyword {
+ /* py-pseudo-keyword-face */
+ color: #ffa500;
+ }
+ .string {
+ /* font-lock-string-face */
+ color: #00cd00;
+ }
+ .type {
+ /* font-lock-type-face */
+ color: #98fb98;
+ }
+ -->
+ </style></head
+><BODY TEXT="#cecece" BGCOLOR="#4f6f6f" LINK="#f5deb3" VLINK="#d5ae83"
+CLASS="SECT1"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><DIV
+CLASS="NAVHEADER"
+><TABLE
+SUMMARY="Header navigation table"
+WIDTH="100%"
+BORDER="0"
+CELLPADDING="0"
+CELLSPACING="0"
+><TR
+><TH
+COLSPAN="3"
+ALIGN="center"
+>PLEAC-Python
+</TH
+></TR
+><TR
+><TD
+WIDTH="10%"
+ALIGN="left"
+VALIGN="bottom"
+><A
+HREF="referencesandrecords.html"
+ACCESSKEY="P"
+>Prev</A
+></TD
+><TD
+WIDTH="80%"
+ALIGN="center"
+VALIGN="bottom"
+></TD
+><TD
+WIDTH="10%"
+ALIGN="right"
+VALIGN="bottom"
+><A
+HREF="classesetc.html"
+ACCESSKEY="N"
+>Next</A
+></TD
+></TR
+></TABLE
+><HR
+ALIGN="LEFT"
+WIDTH="100%"></DIV
+><DIV
+CLASS="SECT1"
+><H1
+CLASS="SECT1"
+><A
+NAME="PACKAGESETC"
+>12. Packages, Libraries, and Modules</A
+></H1
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN642"
+>Introduction</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment"># Python's "module" is the closest equivalent to Perl's "package"
+</span>
+
+<span class="comment-delimiter">#</span><span class="comment">=== In the file "Alpha.py"
+</span>name = <span class="string">"first"</span>
+
+<span class="comment-delimiter">#</span><span class="comment">=== End of file
+</span>
+<span class="comment-delimiter">#</span><span class="comment">=== In the file "Omega.py"
+</span>
+name = <span class="string">"last"</span>
+<span class="comment-delimiter">#</span><span class="comment">=== End of file
+</span>
+<span class="keyword">import</span> Alpha, Omega
+<span class="keyword">print</span> <span class="string">"Alpha is %s, Omega is %s."</span> % (Alpha.name, Omega.name)
+<span class="comment-delimiter">#</span><span class="comment">&gt; Alpha is first, Omega is last.
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Python does not have an equivalent to "compile-time load"
+</span><span class="keyword">import</span> sys
+
+<span class="comment-delimiter"># </span><span class="comment">Depending on the implementation, this could use a builtin
+</span><span class="comment-delimiter"># </span><span class="comment">module or load a file with the extension .py, .pyc, pyo, .pyd,
+</span><span class="comment-delimiter"># </span><span class="comment">.so, .dll, or (with imputils) load from other files.
+</span><span class="keyword">import</span> Cards.Poker
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment">=== In the file Cards/Poker.py
+</span>__all__ = [<span class="string">"card_deck"</span>, <span class="string">"shuffle"</span>] <span class="comment-delimiter"># </span><span class="comment">not usually needed
+</span>card_deck = []
+<span class="keyword">def</span> <span class="function-name">shuffle</span>():
+ <span class="keyword">pass</span>
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN645"
+>Defining a Module's Interface</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment">== In the file "YourModule.py"
+</span>
+__version__ = (1, 0) <span class="comment-delimiter"># </span><span class="comment">Or higher
+</span>__all__ = [<span class="string">"..."</span>, <span class="string">"..."</span>] <span class="comment-delimiter"># </span><span class="comment">Override names included in "... import *"
+</span> <span class="comment-delimiter"># </span><span class="comment">Note: 'import *' is considered poor style
+</span> <span class="comment-delimiter"># </span><span class="comment">and it is rare to use this variable.
+</span><span class="comment-delimiter">#</span><span class="comment">#######################
+</span><span class="comment-delimiter"># </span><span class="comment">your code goes here
+</span><span class="comment-delimiter">#</span><span class="comment">#######################
+</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> YourModule <span class="comment-delimiter"># </span><span class="comment">Import the module into my package
+</span> <span class="comment-delimiter"># </span><span class="comment">(does not import any of its symbols)
+</span>
+<span class="keyword">import</span> YourModule <span class="keyword">as</span> Module <span class="comment-delimiter"># </span><span class="comment">Use a different name for the module
+</span>
+<span class="keyword">from</span> YourModule <span class="keyword">import</span> * <span class="comment-delimiter"># </span><span class="comment">Import all module symbols not starting
+</span> <span class="comment-delimiter"># </span><span class="comment">with an underscore (default); if __all__
+</span> <span class="comment-delimiter"># </span><span class="comment">is defined, only imports those symbols.
+</span> <span class="comment-delimiter"># </span><span class="comment">Using this is discouraged unless the
+</span> <span class="comment-delimiter"># </span><span class="comment">module is specifically designed for it.
+</span>
+<span class="keyword">from</span> YourModule <span class="keyword">import</span> name1, name2, xxx
+ <span class="comment-delimiter"># </span><span class="comment">Import the named symbols from the module
+</span>
+<span class="keyword">from</span> YourModule <span class="keyword">import</span> name1 <span class="keyword">as</span> name2
+ <span class="comment-delimiter"># </span><span class="comment">Import the named object, but use a
+</span> <span class="comment-delimiter"># </span><span class="comment">different name to access it locally.
+</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>__all__ = [<span class="string">"F1"</span>, <span class="string">"F2"</span>, <span class="string">"List"</span>]
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>__all__ = [<span class="string">"Op_Func"</span>, <span class="string">"Table"</span>]
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">from</span> YourModule <span class="keyword">import</span> Op_Func, Table, F1
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">from</span> YourModule <span class="keyword">import</span> Functions, Table
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN648"
+>Trapping Errors in require or use</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">no import
+</span>mod = <span class="string">"module"</span>
+<span class="keyword">try:</span>
+ <span class="py-builtins">__import__</span>(mod)
+<span class="keyword">except</span> <span class="py-builtins">ImportError</span>, err:
+ <span class="keyword">raise</span> <span class="py-builtins">ImportError</span>(<span class="string">"couldn't load %s: %s"</span> % (mod, err))
+
+<span class="comment-delimiter"># </span><span class="comment">imports into current package
+</span><span class="keyword">try:</span>
+ <span class="keyword">import</span> module
+<span class="keyword">except</span> <span class="py-builtins">ImportError</span>, err:
+ <span class="keyword">raise</span> <span class="py-builtins">ImportError</span>(<span class="string">"couldn't load 'module': %s"</span> % (err, ))
+
+<span class="comment-delimiter"># </span><span class="comment">imports into current package, if the name is known
+</span><span class="keyword">try:</span>
+ <span class="keyword">import</span> module
+<span class="keyword">except</span> <span class="py-builtins">ImportError</span>, err:
+ <span class="keyword">raise</span> <span class="py-builtins">ImportError</span>(<span class="string">"couldn't load 'module': %s"</span> % (err, ))
+
+<span class="comment-delimiter"># </span><span class="comment">Use a fixed local name for a named module
+</span>mod = <span class="string">"module"</span>
+<span class="keyword">try:</span>
+ local_name = <span class="py-builtins">__import__</span>(mod)
+<span class="keyword">except</span> <span class="py-builtins">ImportError</span>, err:
+ <span class="keyword">raise</span> <span class="py-builtins">ImportError</span>(<span class="string">"couldn't load %s: %s"</span> % (mod, err))
+
+<span class="comment-delimiter"># </span><span class="comment">Use the given name for the named module.
+</span><span class="comment-delimiter"># </span><span class="comment">(You probably don't need to do this.)
+</span>mod = <span class="string">"module"</span>
+<span class="keyword">try:</span>
+ <span class="py-builtins">globals</span>()[mod] = <span class="py-builtins">__import__</span>(mod)
+<span class="keyword">except</span> <span class="py-builtins">ImportError</span>, err:
+ <span class="keyword">raise</span> <span class="py-builtins">ImportError</span>(<span class="string">"couldn't load %s: %s"</span> % (mod, err))
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>DBs = <span class="string">"Giant.Eenie Giant.Meanie Mouse.Mynie Moe"</span>.split()
+<span class="keyword">for</span> mod <span class="keyword">in</span> DBs.split():
+ <span class="keyword">try:</span>
+ loaded_module = <span class="py-builtins">__import__</span>(mod)
+ <span class="keyword">except</span> <span class="py-builtins">ImportError</span>:
+ <span class="keyword">continue</span>
+ <span class="comment-delimiter"># </span><span class="comment">__import__ returns a reference to the top-most module
+</span> <span class="comment-delimiter"># </span><span class="comment">Need to get the actual submodule requested.
+</span> <span class="keyword">for</span> term <span class="keyword">in</span> mod.split(<span class="string">"."</span>)[:-1]:
+ loaded_module = <span class="py-builtins">getattr</span>(loaded_module, term)
+ <span class="keyword">break</span>
+<span class="keyword">else:</span>
+ <span class="keyword">raise</span> <span class="py-builtins">ImportError</span>(<span class="string">"None of %s loaded"</span> % DBs)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN651"
+>Delaying use Until Run Time</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> sys
+<span class="keyword">if</span> <span class="py-builtins">__name__</span> == <span class="string">"__main__"</span>:
+ <span class="keyword">if</span> <span class="py-builtins">len</span>(sys.argv) != 3 <span class="keyword">or</span> <span class="keyword">not</span> sys.argv[1].isdigit() \
+ <span class="keyword">or</span> <span class="keyword">not</span> sys.argv[2].isdigit():
+ <span class="keyword">raise</span> <span class="py-builtins">SystemExit</span>(<span class="string">"usage: %s num1 num2"</span> % sys.argv[0])
+
+<span class="keyword">import</span> Some.Module
+<span class="keyword">import</span> More.Modules
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">if</span> opt_b:
+ <span class="keyword">import</span> math
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">from</span> os <span class="keyword">import</span> O_EXCL, O_CREAT, O_RDWR
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> os
+O_EXCL = os.O_EXCL
+O_CREAT = os.O_CREAT
+O_RDWR = os.O_RDWR
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> os
+O_EXCL, O_CREAT, O_RDWR = os.O_EXCL, os.O_CREAT, os.O_RDWR
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>load_module(<span class="string">'os'</span>, <span class="string">"O_EXCL O_CREAT O_RDWR"</span>.split())
+
+<span class="keyword">def</span> <span class="function-name">load_module</span>(module_name, symbols):
+ module = <span class="py-builtins">__import__</span>(module_name)
+ <span class="keyword">for</span> symbol <span class="keyword">in</span> symbols:
+ <span class="py-builtins">globals</span>()[symbol] = <span class="py-builtins">getattr</span>(module, symbol)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN654"
+>Making Variables Private to a Module</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Python doesn't have Perl-style packages
+</span>
+<span class="comment-delimiter"># </span><span class="comment">Flipper.py
+</span>__version__ = (1, 0)
+
+__all__ = [<span class="string">"flip_boundary"</span>, <span class="string">"flip_words"</span>]
+
+Separatrix = <span class="string">' '</span> <span class="comment-delimiter"># </span><span class="comment">default to blank
+</span>
+<span class="keyword">def</span> <span class="function-name">flip_boundary</span>(sep = <span class="py-pseudo-keyword">None</span>):
+ prev_sep = Separatrix
+ <span class="keyword">if</span> sep <span class="keyword">is</span> <span class="keyword">not</span> <span class="py-pseudo-keyword">None</span>:
+ <span class="keyword">global</span> Separatrix
+ Separatrix = sep
+ <span class="keyword">return</span> prev_sep
+
+<span class="keyword">def</span> <span class="function-name">flip_words</span>(line):
+ words = line.split(Separatrix)
+ words.reverse()
+ <span class="keyword">return</span> Separatrix.join(words)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN657"
+>Determining the Caller's Package</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>this_pack = <span class="py-builtins">__name__</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>that_pack = sys._getframe(1).f_globals.get(<span class="string">"__name__"</span>, <span class="string">"&lt;string&gt;"</span>)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">print</span> <span class="string">"I am in package"</span>, <span class="py-builtins">__name__</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">def</span> <span class="function-name">nreadline</span>(count, myfile):
+ <span class="keyword">if</span> count &lt;= 0:
+ <span class="keyword">raise</span> <span class="py-builtins">ValueError</span>(<span class="string">"Count must be &gt; 0"</span>)
+ <span class="keyword">return</span> [myfile.readline() <span class="keyword">for</span> i <span class="keyword">in</span> <span class="py-builtins">range</span>(count)]
+
+<span class="keyword">def</span> <span class="function-name">main</span>():
+ myfile = <span class="py-builtins">open</span>(<span class="string">"/etc/termcap"</span>)
+ a, b, c = nreadline(3, myfile)
+ myfile.close()
+
+<span class="keyword">if</span> <span class="py-builtins">__name__</span> == <span class="string">"__main__"</span>:
+ main()
+
+<span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS:
+</span><span class="keyword">import</span> sys
+
+<span class="keyword">def</span> <span class="function-name">nreadline</span>(count, handle_name):
+ <span class="keyword">assert</span> count &gt; 0, <span class="string">"count must be &gt; 0"</span>
+ <span class="py-builtins">locals</span> = sys._getframe(1).f_locals
+ <span class="keyword">if</span> <span class="keyword">not</span> locals.has_key(handle_name):
+ <span class="keyword">raise</span> <span class="py-builtins">AssertionError</span>(<span class="string">"need open filehandle"</span>)
+ infile = locals[handle_name]
+ retlist = []
+ <span class="keyword">for</span> line <span class="keyword">in</span> infile:
+ retlist.append(line)
+ count -= 1
+ <span class="keyword">if</span> count == 0:
+ <span class="keyword">break</span>
+ <span class="keyword">return</span> retlist
+
+<span class="keyword">def</span> <span class="function-name">main</span>():
+ FH = <span class="py-builtins">open</span>(<span class="string">"/etc/termcap"</span>)
+ a, b, c = nreadline(3, <span class="string">"FH"</span>)
+
+<span class="keyword">if</span> <span class="py-builtins">__name__</span> == <span class="string">"__main__"</span>:
+ main()
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN660"
+>Automating Module Clean-Up</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment"># There is no direct equivalent in Python to an END block
+</span><span class="keyword">import</span> time, os, sys
+
+<span class="comment-delimiter"># </span><span class="comment">Tricks to ensure the needed functions exist during module cleanup
+</span><span class="keyword">def</span> <span class="function-name">_getgmtime</span>(asctime=time.asctime, gmtime=time.gmtime,
+ t=time.time):
+ <span class="keyword">return</span> asctime(gmtime(t()))
+
+<span class="keyword">class</span> <span class="type">Logfile</span>:
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>, file):
+ <span class="py-pseudo-keyword">self</span>.file = <span class="py-builtins">file</span>
+
+ <span class="keyword">def</span> <span class="function-name">_logmsg</span>(<span class="py-pseudo-keyword">self</span>, msg, argv0=sys.argv[0], pid=os.getpid(),
+ _getgmtime=_getgmtime):
+ <span class="comment-delimiter"># </span><span class="comment">more tricks to keep all needed references
+</span> now = _getgmtime()
+ print&gt;&gt;<span class="py-pseudo-keyword">self</span>.file, argv0, pid, now + <span class="string">":"</span>, msg
+
+ <span class="keyword">def</span> <span class="function-name">logmsg</span>(<span class="py-pseudo-keyword">self</span>, msg):
+ <span class="py-pseudo-keyword">self</span>._logmsg(<span class="py-pseudo-keyword">self</span>.file, msg)
+
+ <span class="keyword">def</span> <span class="function-name">__del__</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="py-pseudo-keyword">self</span>._logmsg(<span class="string">"shutdown"</span>)
+ <span class="py-pseudo-keyword">self</span>.file.close()
+
+ <span class="keyword">def</span> <span class="function-name">__getattr__</span>(<span class="py-pseudo-keyword">self</span>, attr):
+ <span class="comment-delimiter"># </span><span class="comment">forward everything else to the file handle
+</span> <span class="keyword">return</span> <span class="py-builtins">getattr</span>(<span class="py-pseudo-keyword">self</span>.file, attr)
+
+<span class="comment-delimiter"># </span><span class="comment">0 means unbuffered
+</span>LF = Logfile(<span class="py-builtins">open</span>(<span class="string">"/tmp/mylog"</span>, <span class="string">"a+"</span>, 0))
+logmsg = LF.logmsg
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment"># It is more appropriate to use try/finally around the
+</span><span class="comment-delimiter">#</span><span class="comment"># main code, so the order of initialization and finalization
+</span><span class="comment-delimiter">#</span><span class="comment"># can be specified.
+</span><span class="keyword">if</span> <span class="py-builtins">__name__</span> == <span class="string">"__main__"</span>:
+ <span class="keyword">import</span> logger
+ logger.init(<span class="string">"/tmp/mylog"</span>)
+ <span class="keyword">try:</span>
+ main()
+ <span class="keyword">finally:</span>
+ logger.close()
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN663"
+>Keeping Your Own Module Directory</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment">% python -c 'import sys\
+</span><span class="keyword">for</span> i, name <span class="keyword">in</span> <span class="py-builtins">zip</span>(xrange(sys.maxint), sys.path):\
+ <span class="keyword">print</span> i, <span class="py-builtins">repr</span>(name)
+<span class="comment-delimiter">#</span><span class="comment">&gt; 0 ''
+</span><span class="comment-delimiter">#</span><span class="comment">&gt; 1 '/usr/lib/python2.2'
+</span><span class="comment-delimiter">#</span><span class="comment">&gt; 2 '/usr/lib/python2.2/plat-linux2'
+</span><span class="comment-delimiter">#</span><span class="comment">&gt; 3 '/usr/lib/python2.2/lib-tk'
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">syntax for sh, bash, ksh, or zsh
+</span><span class="comment-delimiter">#</span><span class="comment">$ export PYTHONPATH=$HOME/pythonlib
+</span>
+<span class="comment-delimiter"># </span><span class="comment">syntax for csh or tcsh
+</span><span class="comment-delimiter">#</span><span class="comment">% setenv PYTHONPATH ~/pythonlib
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> sys
+sys.path.insert(0, <span class="string">"/projects/spectre/lib"</span>)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> FindBin
+sys.path.insert(0, FindBin.Bin)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> FindBin
+Bin = <span class="string">"Name"</span>
+bin = <span class="py-builtins">getattr</span>(FindBin, Bin)
+sys.path.insert(0, bin + <span class="string">"/../lib"</span>)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN666"
+>Preparing a Module for Distribution</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment">% h2xs -XA -n Planets
+</span><span class="comment-delimiter">#</span><span class="comment">% h2xs -XA -n Astronomy::Orbits
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span><span class="comment-delimiter"># </span><span class="comment">Need a distutils example
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN669"
+>Speeding Module Loading with SelfLoader</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Python compiles a file to bytecode the first time it is imported and
+</span><span class="comment-delimiter"># </span><span class="comment">stores this compiled form in a .pyc file. There is thus less need for
+</span><span class="comment-delimiter"># </span><span class="comment">incremental compilation as once there is a .pyc file, the sourcecode
+</span><span class="comment-delimiter"># </span><span class="comment">is only recompiled if it is modified.
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN672"
+>Speeding Up Module Loading with Autoloader</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">See previous section
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN675"
+>Overriding Built-In Functions</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment"># Any definition in a Python module overrides the builtin
+</span><span class="comment-delimiter">#</span><span class="comment"># for that module
+</span>
+<span class="comment-delimiter">#</span><span class="comment">=== In MyModule
+</span><span class="keyword">def</span> <span class="py-builtins">open</span>():
+ <span class="keyword">pass</span> <span class="comment-delimiter"># </span><span class="comment">TBA
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">from</span> MyModule <span class="keyword">import</span> <span class="py-builtins">open</span>
+<span class="py-builtins">file</span> = <span class="py-builtins">open</span>()
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN678"
+>Reporting Errors and Warnings Like Built-Ins</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">def</span> <span class="function-name">even_only</span>(n):
+ <span class="keyword">if</span> n &amp; 1: <span class="comment-delimiter"># </span><span class="comment">one way to test
+</span> <span class="keyword">raise</span> <span class="py-builtins">AssertionError</span>(<span class="string">"%s is not even"</span> % (n,))
+ <span class="comment-delimiter">#</span><span class="comment">....
+</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">def</span> <span class="function-name">even_only</span>(n):
+ <span class="keyword">if</span> n % 2: <span class="comment-delimiter"># </span><span class="comment">here's another
+</span> <span class="comment-delimiter"># </span><span class="comment">choice of exception depends on the problem
+</span> <span class="keyword">raise</span> <span class="py-builtins">TypeError</span>(<span class="string">"%s is not even"</span> % (n,))
+ <span class="comment-delimiter">#</span><span class="comment">....
+</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> warnings
+<span class="keyword">def</span> <span class="function-name">even_only</span>(n):
+ <span class="keyword">if</span> n &amp; 1: <span class="comment-delimiter"># </span><span class="comment">test whether odd number
+</span> warnings.warn(<span class="string">"%s is not even, continuing"</span> % (n))
+ n += 1
+ <span class="comment-delimiter">#</span><span class="comment">....
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>warnings.filterwarnings(<span class="string">"ignore"</span>)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN681"
+>Referring to Packages Indirectly</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>val = <span class="py-builtins">getattr</span>(__import__(packname), varname)
+vals = <span class="py-builtins">getattr</span>(__import__(packname), aryname)
+<span class="py-builtins">getattr</span>(__import__(packname), funcname)(<span class="string">"args"</span>)
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS [Use math.log(val, base) instead]
+</span><span class="keyword">import</span> math
+<span class="keyword">def</span> <span class="function-name">make_log</span>(n):
+ <span class="keyword">def</span> <span class="function-name">logn</span>(val):
+ <span class="keyword">return</span> math.log(val, n)
+ <span class="keyword">return</span> logn
+
+<span class="comment-delimiter"># </span><span class="comment">Modifying the global dictionary - this could also be done
+</span><span class="comment-delimiter"># </span><span class="comment">using locals(), or someobject.__dict__
+</span>globaldict = <span class="py-builtins">globals</span>()
+<span class="keyword">for</span> i <span class="keyword">in</span> <span class="py-builtins">range</span>(2, 1000):
+ globaldict[<span class="string">"log%s"</span>%i] = make_log(i)
+
+<span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS
+</span><span class="keyword">for</span> i <span class="keyword">in</span> <span class="py-builtins">range</span>(2,1000):
+ <span class="keyword">exec</span> <span class="string">"log%s = make_log(i)"</span>%i <span class="keyword">in</span> <span class="py-builtins">globals</span>()
+
+<span class="keyword">print</span> log20(400)
+<span class="comment-delimiter">#</span><span class="comment">=&gt;2.0
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>blue = colours.blue
+someobject.blue = colours.azure <span class="comment-delimiter"># </span><span class="comment">someobject could be a module...
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN684"
+>Using h2ph to Translate C #include Files</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Python extension modules can be imported and used just like
+</span><span class="comment-delimiter"># </span><span class="comment">a pure python module.
+</span><span class="comment-delimiter">#</span><span class="comment">
+</span><span class="comment-delimiter"># </span><span class="comment">See http://www.cosc.canterbury.ac.nz/~greg/python/Pyrex/ for
+</span><span class="comment-delimiter"># </span><span class="comment">information on how to create extension modules in Pyrex [a
+</span><span class="comment-delimiter"># </span><span class="comment">language that's basically Python with type definitions which
+</span><span class="comment-delimiter"># </span><span class="comment">converts to compiled C code]
+</span><span class="comment-delimiter">#</span><span class="comment">
+</span><span class="comment-delimiter"># </span><span class="comment">See http://www.boost.org/libs/python/doc/ for information on how
+</span><span class="comment-delimiter"># </span><span class="comment">to create extension modules in C++.
+</span><span class="comment-delimiter">#</span><span class="comment">
+</span><span class="comment-delimiter"># </span><span class="comment">See http://www.swig.org/Doc1.3/Python.html for information on how
+</span><span class="comment-delimiter"># </span><span class="comment">to create extension modules in C/C++
+</span><span class="comment-delimiter">#</span><span class="comment">
+</span><span class="comment-delimiter"># </span><span class="comment">See http://docs.python.org/ext/ext.html for information on how to
+</span><span class="comment-delimiter"># </span><span class="comment">create extension modules in C/C++ (manual reference count management).
+</span><span class="comment-delimiter">#</span><span class="comment">
+</span><span class="comment-delimiter"># </span><span class="comment">See http://cens.ioc.ee/projects/f2py2e/ for information on how to
+</span><span class="comment-delimiter"># </span><span class="comment">create extension modules in Fortran
+</span><span class="comment-delimiter">#</span><span class="comment">
+</span><span class="comment-delimiter"># </span><span class="comment">See http://www.scipy.org/Weave for information on how to
+</span><span class="comment-delimiter"># </span><span class="comment">include inline C code in Python code.
+</span><span class="comment-delimiter">#</span><span class="comment">
+</span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@ Need examples of FineTime extensions using the different methods...
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN687"
+>Using h2xs to Make a Module with C Code</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">See previous section
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN690"
+>Documenting Your Module with Pod</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">To document code, use docstrings. A docstring is a bare string that
+</span><span class="comment-delimiter"># </span><span class="comment">is placed at the beginning of a module or immediately after the
+</span><span class="comment-delimiter"># </span><span class="comment">definition line of a class, method, or function. Normally, the
+</span><span class="comment-delimiter"># </span><span class="comment">first line is a brief description of the object; if a longer
+</span><span class="comment-delimiter"># </span><span class="comment">description is needed, it commences on the third line (the second
+</span><span class="comment-delimiter"># </span><span class="comment">line being left blank). Multiline comments should use triple
+</span><span class="comment-delimiter"># </span><span class="comment">quoted strings.
+</span><span class="comment-delimiter"># </span><span class="comment">
+</span><span class="comment-delimiter"># </span><span class="comment">Docstrings are automagically assigned to an object's __doc__ property.
+</span><span class="comment-delimiter">#</span><span class="comment">
+</span><span class="comment-delimiter"># </span><span class="comment">In other words these three classes are identical:
+</span><span class="keyword">class</span> <span class="type">Foo</span>(object):
+ <span class="string">"A class demonstrating docstrings."</span>
+
+<span class="keyword">class</span> <span class="type">Foo</span>(object):
+ __doc__ = <span class="string">"A class demonstrating docstrings."</span>
+
+<span class="keyword">class</span> <span class="type">Foo</span>(object):
+ <span class="keyword">pass</span>
+Foo.__doc__ = <span class="string">"A class demonstrating docstrings."</span>
+
+<span class="comment-delimiter"># </span><span class="comment">as are these two functions:
+</span><span class="keyword">def</span> <span class="function-name">foo</span>():
+ <span class="string">"A function demonstrating docstrings."</span>
+
+<span class="keyword">def</span> <span class="function-name">foo</span>():
+ <span class="keyword">pass</span>
+foo.__doc__ = <span class="string">"A function demonstrating docstrings."</span>
+
+<span class="comment-delimiter"># </span><span class="comment">the pydoc module is used to display a range of information about
+</span><span class="comment-delimiter"># </span><span class="comment">an object including its docstrings:
+</span><span class="keyword">import</span> pydoc
+<span class="keyword">print</span> pydoc.getdoc(int)
+pydoc.help(int)
+
+<span class="comment-delimiter"># </span><span class="comment">In the interactive interpreter, objects' documentation can be
+</span><span class="comment-delimiter"># </span><span class="comment">using the help function:
+</span>help(int)
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN693"
+>Building and Installing a CPAN Module</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Recent Python distributions are built and installed with disutils.
+</span><span class="comment-delimiter"># </span><span class="comment">
+</span><span class="comment-delimiter"># </span><span class="comment">To build and install under unix
+</span><span class="comment-delimiter"># </span><span class="comment">
+</span><span class="comment-delimiter"># </span><span class="comment">% python setup.py install
+</span><span class="comment-delimiter"># </span><span class="comment">
+</span><span class="comment-delimiter"># </span><span class="comment">If you want to build under one login and install under another
+</span><span class="comment-delimiter"># </span><span class="comment">
+</span><span class="comment-delimiter"># </span><span class="comment">% python setup.py build
+</span><span class="comment-delimiter"># </span><span class="comment">$ python setup.py install
+</span><span class="comment-delimiter"># </span><span class="comment">
+</span><span class="comment-delimiter"># </span><span class="comment">A package may also be available prebuilt, eg, as an RPM or Windows
+</span><span class="comment-delimiter"># </span><span class="comment">installer. Details will be specific to the operating system.
+</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">% python setup.py --prefix ~/python-lib
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN696"
+>Example: Module Template</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment">== File Some/Module.py
+</span>
+<span class="comment-delimiter"># </span><span class="comment">There are so many differences between Python and Perl that
+</span><span class="comment-delimiter"># </span><span class="comment">it isn't worthwhile trying to come up with an equivalent to
+</span><span class="comment-delimiter"># </span><span class="comment">this Perl code. The Python code is much smaller, and there's
+</span><span class="comment-delimiter"># </span><span class="comment">no need to have a template.
+</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN699"
+>Program: Finding Versions and Descriptions of Installed Modules</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment">% pmdesc
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> sys, pydoc
+
+<span class="keyword">def</span> <span class="function-name">print_module_info</span>(path, modname, desc):
+ <span class="comment-delimiter"># </span><span class="comment">Skip files starting with "test_"
+</span> <span class="keyword">if</span> modname.split(<span class="string">"."</span>)[-1].startswith(<span class="string">"test_"</span>):
+ <span class="keyword">return</span>
+ <span class="keyword">try:</span>
+ <span class="comment-delimiter"># </span><span class="comment">This assumes the modules are safe for importing,
+</span> <span class="comment-delimiter"># </span><span class="comment">in that they don't have side effects. Could also
+</span> <span class="comment-delimiter"># </span><span class="comment">grep the file for the __version__ line.
+</span> mod = pydoc.safeimport(modname)
+ <span class="keyword">except</span> pydoc.ErrorDuringImport:
+ <span class="keyword">return</span>
+ version = <span class="py-builtins">getattr</span>(mod, <span class="string">"__version__"</span>, <span class="string">"unknown"</span>)
+ <span class="keyword">if</span> <span class="py-builtins">isinstance</span>(version, <span class="py-builtins">type</span>(<span class="string">""</span>)):
+ <span class="comment-delimiter"># </span><span class="comment">Use the string if it's given
+</span> <span class="keyword">pass</span>
+ <span class="keyword">else:</span>
+ <span class="comment-delimiter"># </span><span class="comment">Assume it's a list of version numbers, from major to minor
+</span> <span class="string">"."</span>.join(<span class="py-builtins">map</span>(str, version))
+ synopsis, text = pydoc.splitdoc(desc)
+ <span class="keyword">print</span> <span class="string">"%s (%s) - %s"</span> % (modname, version, synopsis)
+
+scanner = pydoc.ModuleScanner()
+scanner.run(print_module_info)
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+></DIV
+><DIV
+CLASS="NAVFOOTER"
+><HR
+ALIGN="LEFT"
+WIDTH="100%"><TABLE
+SUMMARY="Footer navigation table"
+WIDTH="100%"
+BORDER="0"
+CELLPADDING="0"
+CELLSPACING="0"
+><TR
+><TD
+WIDTH="33%"
+ALIGN="left"
+VALIGN="top"
+><A
+HREF="referencesandrecords.html"
+ACCESSKEY="P"
+>Prev</A
+></TD
+><TD
+WIDTH="34%"
+ALIGN="center"
+VALIGN="top"
+><A
+HREF="index.html"
+ACCESSKEY="H"
+>Home</A
+></TD
+><TD
+WIDTH="33%"
+ALIGN="right"
+VALIGN="top"
+><A
+HREF="classesetc.html"
+ACCESSKEY="N"
+>Next</A
+></TD
+></TR
+><TR
+><TD
+WIDTH="33%"
+ALIGN="left"
+VALIGN="top"
+>References and Records</TD
+><TD
+WIDTH="34%"
+ALIGN="center"
+VALIGN="top"
+>&nbsp;</TD
+><TD
+WIDTH="33%"
+ALIGN="right"
+VALIGN="top"
+>Classes, Objects, and Ties</TD
+></TR
+></TABLE
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/help/PythonExamples/pleac_python/patternmatching.html b/help/PythonExamples/pleac_python/patternmatching.html
new file mode 100644
index 0000000..2c5b5b5
--- /dev/null
+++ b/help/PythonExamples/pleac_python/patternmatching.html
@@ -0,0 +1,1726 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML
+><HEAD
+><TITLE
+>Pattern Matching</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
+REL="HOME"
+TITLE="PLEAC-Python
+"
+HREF="index.html"><LINK
+REL="PREVIOUS"
+TITLE="Hashes"
+HREF="hashes.html"><LINK
+REL="NEXT"
+TITLE="File Access"
+HREF="fileaccess.html"><style type="text/css"> <!--
+ .comment {
+ /* font-lock-comment-face */
+ color: #bebebe;
+ }
+ .comment-delimiter {
+ }
+ .function-name {
+ /* font-lock-function-name-face */
+ color: #b2dfee;
+ }
+ .keyword {
+ /* font-lock-keyword-face */
+ color: #ffa500;
+ }
+ .py-builtins {
+ /* py-builtins-face */
+ color: #ffa500;
+ }
+ .py-pseudo-keyword {
+ /* py-pseudo-keyword-face */
+ color: #ffa500;
+ }
+ .string {
+ /* font-lock-string-face */
+ color: #00cd00;
+ }
+ .type {
+ /* font-lock-type-face */
+ color: #98fb98;
+ }
+ -->
+ </style></head
+><BODY TEXT="#cecece" BGCOLOR="#4f6f6f" LINK="#f5deb3" VLINK="#d5ae83"
+CLASS="SECT1"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><DIV
+CLASS="NAVHEADER"
+><TABLE
+SUMMARY="Header navigation table"
+WIDTH="100%"
+BORDER="0"
+CELLPADDING="0"
+CELLSPACING="0"
+><TR
+><TH
+COLSPAN="3"
+ALIGN="center"
+>PLEAC-Python
+</TH
+></TR
+><TR
+><TD
+WIDTH="10%"
+ALIGN="left"
+VALIGN="bottom"
+><A
+HREF="hashes.html"
+ACCESSKEY="P"
+>Prev</A
+></TD
+><TD
+WIDTH="80%"
+ALIGN="center"
+VALIGN="bottom"
+></TD
+><TD
+WIDTH="10%"
+ALIGN="right"
+VALIGN="bottom"
+><A
+HREF="fileaccess.html"
+ACCESSKEY="N"
+>Next</A
+></TD
+></TR
+></TABLE
+><HR
+ALIGN="LEFT"
+WIDTH="100%"></DIV
+><DIV
+CLASS="SECT1"
+><H1
+CLASS="SECT1"
+><A
+NAME="PATTERNMATCHING"
+>6. Pattern Matching</A
+></H1
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN285"
+>Introduction</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">Note: regexes are used less often in Python than in Perl as tasks are often
+</span><span class="comment-delimiter"># </span><span class="comment">covered by string methods, or specialised objects, modules, or packages.
+</span>
+<span class="keyword">import</span> re <span class="comment-delimiter"># </span><span class="comment">"re" is the regular expression module.
+</span>re.search(<span class="string">"sheep"</span>,meadow) <span class="comment-delimiter"># </span><span class="comment">returns a MatchObject is meadow contains "sheep".
+</span><span class="keyword">if</span> <span class="keyword">not</span> re.search(<span class="string">"sheep"</span>,meadow):
+ <span class="keyword">print</span> <span class="string">"no sheep on this meadow only a fat python."</span>
+<span class="comment-delimiter"># </span><span class="comment">replacing strings is not done by "re"gular expressions.
+</span>meadow = meadow.replace(<span class="string">"old"</span>,<span class="string">"new"</span>) <span class="comment-delimiter"># </span><span class="comment">replace "old" with "new" and assign result.
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>re.search(<span class="string">"ovine"</span>,meadow)
+
+meadow = <span class="string">"""Fine bovines demand fine toreadors.
+Muskoxen are polar ovibovine species.
+Grooviness went out of fashion decades ago."""</span>
+
+meadow = <span class="string">"Ovines are found typically in ovaries."</span>
+
+<span class="keyword">if</span> re.search(r<span class="string">"\bovines\b"</span>,meadow,re.I) : <span class="keyword">print</span> <span class="string">"Here be sheep!"</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">The tricky bit
+</span>mystr = <span class="string">"good food"</span>
+re.sub(<span class="string">"o*"</span>,<span class="string">"e"</span>,mystr,1) <span class="comment-delimiter"># </span><span class="comment">gives 'egood food'
+</span>
+echo ababacaca | python -c <span class="string">"import sys,re; print re.search('(a|ba|b)+(a|ac)+',sys.stdin.read()).group()"</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">pattern matching modifiers
+</span><span class="comment-delimiter"># </span><span class="comment">assume perl code iterates over some file
+</span><span class="keyword">import</span> re, fileinput
+<span class="keyword">for</span> ln = fileinput.input():
+ fnd = re.findall(<span class="string">"(\d+)"</span>,ln)
+ <span class="keyword">if</span> <span class="py-builtins">len</span>(fnd) &gt; 0:
+ <span class="keyword">print</span> <span class="string">"Found number %s"</span> % (fnd[0])
+<span class="comment-delimiter"># </span><span class="comment">----------------------------
+</span>digits = <span class="string">"123456789"</span>
+nonlap = re.findall(<span class="string">"(\d\d\d)"</span>, digits)
+yeslap = [<span class="string">"not yet"</span>]
+<span class="keyword">print</span> <span class="string">"Non-overlapping:"</span>,<span class="string">","</span>.join(nonlap)
+<span class="keyword">print</span> <span class="string">"Overlapping :"</span>,<span class="string">","</span>.join(yeslap)
+<span class="comment-delimiter"># </span><span class="comment">----------------------------
+</span>mystr = <span class="string">"And little lambs eat ivy"</span>
+fnd = re.search(<span class="string">"(l[^s]*s)"</span>, mystr)
+<span class="keyword">print</span> <span class="string">"(%s) (%s) (%s)"</span> % (mystr[:fnd.start()], fnd.group(), mystr[fnd.end():])
+<span class="comment-delimiter"># </span><span class="comment">(And ) (little lambs) ( eat ivy)
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN288"
+>Copying and Substituting Simultaneously</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="keyword">import</span> re
+dst = re.sub(<span class="string">"this"</span>,<span class="string">"that"</span>,src)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">strip to basename
+</span>basename = re.sub(<span class="string">".*/(?=[^/]+)"</span>,<span class="string">""</span>,progname)
+
+<span class="comment-delimiter"># </span><span class="comment">Make All Words Title-Cased
+</span><span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS - use str.title() instead
+</span><span class="keyword">def</span> <span class="function-name">cap</span>(mo): <span class="keyword">return</span> mo.group().capitalize()
+re.sub(<span class="string">"(?P&lt;n&gt;\w+)"</span>,cap,<span class="string">"make all words title-cased"</span>)
+
+<span class="comment-delimiter"># </span><span class="comment">/usr/man/man3/foo.1 changes to /usr/man/cat3/foo.1
+</span>manpage = <span class="string">"/usr/man/man3/foo.1"</span>
+catpage = re.sub(<span class="string">"man(?=\d)"</span>,<span class="string">"cat"</span>,manpage)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>bindirs = <span class="string">"/usr/bin /bin /usr/local/bin"</span>.split()
+libdirs = [d.replace(<span class="string">"bin"</span>, <span class="string">"lib"</span>) <span class="keyword">for</span> d <span class="keyword">in</span> bindirs]
+
+<span class="keyword">print</span> <span class="string">" "</span>.join(libdirs)
+<span class="comment-delimiter">#</span><span class="comment">=&gt; /usr/lib /lib /usr/local/lib
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">strings are never modified in place.
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN291"
+>Matching Letters</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">#---------------------------
+</span>
+<span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS. use line[:-1].isalpha() [this probably goes for the
+</span><span class="comment-delimiter"># </span><span class="comment">remainder of this section too!]
+</span><span class="keyword">import</span> re
+<span class="keyword">if</span> re.match(<span class="string">"^[A-Za-z]+$"</span>,line):
+ <span class="keyword">print</span> <span class="string">"pure alphabetic"</span>
+<span class="comment-delimiter">#</span><span class="comment">#---------------------------
+</span><span class="keyword">if</span> re.match(r<span class="string">"^[^\W\d_]+$"</span>, line, re.LOCALE):
+ <span class="keyword">print</span> <span class="string">"pure alphabetic"</span>
+<span class="comment-delimiter">#</span><span class="comment">#---------------------------
+</span><span class="keyword">import</span> re
+<span class="keyword">import</span> locale
+
+<span class="keyword">try:</span>
+ locale.setlocale(locale.LC_ALL, <span class="string">'fr_CA.ISO8859-1'</span>)
+<span class="keyword">except:</span>
+ <span class="keyword">print</span> <span class="string">"couldn't set locale to French Cnadian"</span>
+ <span class="keyword">raise</span> <span class="py-builtins">SystemExit</span>
+
+DATA=<span class="string">"""
+silly
+fa&#231;ade
+co&#246;perate
+ni&#241;o
+Ren&#233;e
+Moli&#232;re
+h&#230;moglobin
+na&#239;ve
+tsch&#252;&#223;
+random!stuff#here
+"""</span>
+
+<span class="keyword">for</span> ln <span class="keyword">in</span> DATA.split():
+ ln = ln.rstrip()
+ <span class="keyword">if</span> re.match(r<span class="string">"^[^\W\d_]+$"</span>,ln,re.LOCALE):
+ <span class="keyword">print</span> <span class="string">"%s: alphabetic"</span> % (ln)
+ <span class="keyword">else:</span>
+ <span class="keyword">print</span> <span class="string">"%s: line noise"</span> % (ln)
+<span class="comment-delimiter"># </span><span class="comment">although i dont think "co&#246;perate" should be in canadian
+</span><span class="comment-delimiter">#</span><span class="comment">#---------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN294"
+>Matching Words</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">Matching Words
+</span><span class="string">"\S+"</span> <span class="comment-delimiter"># </span><span class="comment">as many non-whitespace bytes as possible
+</span><span class="string">"[A-Za-z'-]+"</span> <span class="comment-delimiter"># </span><span class="comment">as many letters, apostrophes, and hyphens
+</span>
+<span class="comment-delimiter"># </span><span class="comment">string split is similar to splitting on "\s+"
+</span><span class="string">"A text with some\tseparator"</span>.split()
+
+<span class="string">"\b*([A-Za-z]+)\b*"</span> <span class="comment-delimiter"># </span><span class="comment">word boundaries
+</span><span class="string">"\s*([A-Za-z]+)\s*"</span> <span class="comment-delimiter"># </span><span class="comment">might work too as on letters are allowed.
+</span>
+re.search(<span class="string">"\Bis\B"</span>,<span class="string">"this thistle"</span>) <span class="comment-delimiter"># </span><span class="comment">matches on thistle not on this
+</span>re.search(<span class="string">"\Bis\B"</span>,<span class="string">"vis-a-vis"</span>) <span class="comment-delimiter"># </span><span class="comment">does not match
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN297"
+>Commenting Regular Expressions</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment">!/usr/bin/python
+</span><span class="comment-delimiter"># </span><span class="comment">resname - change all "foo.bar.com" style names in the input stream
+</span><span class="comment-delimiter"># </span><span class="comment">into "foo.bar.com [204.148.40.9]" (or whatever) instead
+</span>
+<span class="keyword">import</span> socket <span class="comment-delimiter"># </span><span class="comment">load inet_addr
+</span><span class="keyword">import</span> fileinput
+<span class="keyword">import</span> re
+
+match = re.compile(<span class="string">"""(?P&lt;hostname&gt; # capture hostname
+ (?: # these parens for grouping only
+ [\w-]+ # hostname component
+ \. # ant the domain dot
+ ) + # now repeat that whole thing a bunch of times
+ [A-Za-z] # next must be a letter
+ [\w-] + # now trailing domain part
+ ) # end of hostname capture
+ """</span>,re.VERBOSE) <span class="comment-delimiter"># </span><span class="comment">for nice formatting
+</span>
+<span class="keyword">def</span> <span class="function-name">repl</span>(match_obj):
+ orig_hostname = match_obj.group(<span class="string">"hostname"</span>)
+ <span class="keyword">try:</span>
+ addr = socket.gethostbyname(orig_hostname)
+ <span class="keyword">except</span> socket.gaierror:
+ addr = <span class="string">"???"</span>
+ <span class="keyword">return</span> <span class="string">"%s [%s]"</span> % (orig_hostname, addr)
+
+<span class="keyword">for</span> ln <span class="keyword">in</span> fileinput.input():
+ <span class="keyword">print</span> match.sub(repl, ln)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>re.sub(<span class="string">"""(?x) # nicer formatting
+ \# # a pound sign
+ (\w+) # the variable name
+ \# # another pound sign
+ """</span>,
+ <span class="keyword">lambda</span> m: <span class="py-builtins">eval</span>(m.group(1)), <span class="comment-delimiter"># </span><span class="comment">replace with the value of the global variable
+</span> line
+ )
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span>re.sub(<span class="string">"""(?x) # nicer formatting
+ \# # a pound sign
+ (\w+) # the variable name
+ \# # another pound sign
+ """</span>,
+ <span class="keyword">lambda</span> m: <span class="py-builtins">eval</span>(eval(m.group(1))), <span class="comment-delimiter"># </span><span class="comment">replace with the value of *any* variable
+</span> line
+ )
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN300"
+>Finding the Nth Occurrence of a Match</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="keyword">import</span> re
+pond = <span class="string">"one fish two fish red fish blue fish"</span>
+fishes = re.findall(r<span class="string">"(?i)(\w+)\s+fish\b"</span>,pond)
+<span class="keyword">if</span> <span class="py-builtins">len</span>(fishes)&gt;2:
+ <span class="keyword">print</span> <span class="string">"The third fish is a %s one."</span> % (fishes[2])
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span>re.findall(r<span class="string">"(?i)(?:\w+\s+fish\s+){2}(\w+)\s+fish"</span>,pond)
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span>count = 0
+<span class="keyword">for</span> match_object <span class="keyword">in</span> re.finditer(r<span class="string">"PAT"</span>, mystr):
+ count += 1 <span class="comment-delimiter"># </span><span class="comment">or whatever you want to do here
+</span>
+<span class="comment-delimiter"># </span><span class="comment">"progressive" matching might be better if one wants match 5 from 50.
+</span><span class="comment-delimiter"># </span><span class="comment">to count use
+</span>count = <span class="py-builtins">len</span>(re.findall(r<span class="string">"PAT"</span>,mystr))
+count = <span class="py-builtins">len</span>(re.findall(r<span class="string">"aba"</span>,<span class="string">"abaababa"</span>))
+
+<span class="comment-delimiter"># </span><span class="comment">"count" overlapping matches
+</span>count = <span class="py-builtins">len</span>(re.findall(r<span class="string">"(?=aba)"</span>,<span class="string">"abaababa"</span>))
+
+<span class="comment-delimiter"># </span><span class="comment">FASTEST non-overlapping might be str.count
+</span><span class="string">"abaababa"</span>.count(<span class="string">"aba"</span>)
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span>pond = <span class="string">"one fish two fish red fish blue fish"</span>
+colors = re.findall(r<span class="string">"(?i)(\w+)\s+fish\b"</span>,pond) <span class="comment-delimiter"># </span><span class="comment">get all matches
+</span>color = colors[2] <span class="comment-delimiter"># </span><span class="comment">then the one we want
+</span>
+<span class="comment-delimiter"># </span><span class="comment">or without a temporary list
+</span>color = re.findall(r<span class="string">"(?i)(\w+)\s+fish\b"</span>,pond)[2] <span class="comment-delimiter"># </span><span class="comment">just grab element 3
+</span>
+<span class="keyword">print</span> <span class="string">"The third fish in the pond is %s."</span> % (color)
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span><span class="keyword">import</span> re
+
+pond = <span class="string">"one fish two fish red fish blue fish"</span>
+matches = re.findall(r<span class="string">"(\w+)\s+fish\b"</span>,pond)
+evens = [fish <span class="keyword">for</span> (i, fish) <span class="keyword">in</span> <span class="py-builtins">enumerate</span>(matches) <span class="keyword">if</span> i%2]
+<span class="keyword">print</span> <span class="string">"Even numbered fish are %s."</span> % (<span class="string">" "</span>.join(evens))
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span>count = 0
+<span class="keyword">def</span> <span class="function-name">four_is_sushi</span>(match_obj):
+ <span class="keyword">global</span> count
+ count += 1
+ <span class="keyword">if</span> count==4:
+ <span class="keyword">return</span> <span class="string">"sushi%s"</span> % (match_obj.group(2))
+ <span class="keyword">return</span> <span class="string">""</span>.join(match_obj.groups())
+
+re.sub(r<span class="string">"""(?x) # VERBOSE
+ \b # makes next \w more efficient
+ ( \w+ ) # this is what we'll be changing
+ (
+ \s+ fish \b
+ )"""</span>,
+ four_is_sushi,
+ pond)
+<span class="comment-delimiter"># </span><span class="comment">one fish two fish red fish sushi fish
+</span><span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">greedily
+</span>last_fish = re.findall(r<span class="string">"(?i).*\b(\w+)\s+fish\b"</span>,pond)
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span>pond = <span class="string">"One fish two fish red fish blue fish swim here"</span>
+color = re.findall(r<span class="string">"(?i)\b(\w+)\s+fish\b"</span>,pond)[-1]
+<span class="keyword">print</span> <span class="string">"Last fish is "</span>+color+<span class="string">"."</span>
+<span class="comment-delimiter"># </span><span class="comment">FASTER using string.
+</span>lastfish = pond.rfind(<span class="string">"fish"</span>)
+color = pond[:lastfish].split()[-1]
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span>r<span class="string">"""(?x)
+ A # find some pattern A
+ (?! # mustn't be able to find
+ .* # something
+ A # and A
+ )
+ $ # through the end of string
+ """</span>
+
+pond = <span class="string">"One fish two fish red fish blue fish swim here"</span>
+fnd = re.findall(r<span class="string">"""(?xis) # VERBOSE, CASEINSENSITIVE, DOTALL
+ \b ( \w+ ) \s+ fish \b
+ (?! .* \b fish \b )"""</span>,
+ pond)
+<span class="keyword">if</span> <span class="py-builtins">len</span>(fnd):
+ <span class="keyword">print</span> <span class="string">"Last fish is %s."</span> % (fnd[0])
+<span class="keyword">else:</span>
+ <span class="keyword">print</span> <span class="string">"Failed!"</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN303"
+>Matching Multiple Lines</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">Matching Multiple Lines
+</span><span class="comment-delimiter">#</span><span class="comment">
+</span><span class="comment-delimiter">#</span><span class="comment">!/usr/bin/python
+</span><span class="comment-delimiter"># </span><span class="comment">killtags - very bad html tag killer
+</span><span class="keyword">import</span> re
+<span class="keyword">import</span> sys
+
+text = <span class="py-builtins">open</span>(sys.argv[1]).read() <span class="comment-delimiter"># </span><span class="comment">read the whole file
+</span>text = re.sub(<span class="string">"(?ms)&lt;.*?&gt;"</span>,<span class="string">""</span>,text) <span class="comment-delimiter"># </span><span class="comment">strip tags (terrible
+</span><span class="keyword">print</span> text
+<span class="comment-delimiter">#</span><span class="comment"># ----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment">!/usr/bin/python
+</span><span class="comment-delimiter"># </span><span class="comment">headerfy: change certain chapter headers to html
+</span><span class="keyword">import</span> sys, re
+
+match = re.compile(r<span class="string">"""(?xms) # re.VERBOSE, re.MULTILINE, and re.DOTALL
+ \A # start of the string
+ (?P&lt;chapter&gt; # capture in g&lt;chapter&gt;
+ Chapter # literal string
+ \s+ # mandatory whitespace
+ \d+ # decimal number
+ \s* # optional whitespace
+ : # a real colon
+ . * # anything not a newline till end of line
+ )
+ """</span>)
+text = <span class="py-builtins">open</span>(sys.argv[1]).read() <span class="comment-delimiter"># </span><span class="comment">read the whole file
+</span><span class="keyword">for</span> paragraph <span class="keyword">in</span> text.split(<span class="string">"\n"</span>): <span class="comment-delimiter"># </span><span class="comment">split on unix end of lines
+</span> p = match.sub(<span class="string">"&lt;h1&gt;\g&lt;chapter&gt;&lt;/h1&gt;"</span>,paragraph)
+ <span class="keyword">print</span> p
+<span class="comment-delimiter">#</span><span class="comment"># ----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">the one liner does not run.
+</span><span class="comment-delimiter"># </span><span class="comment">python -c 'import sys,re; for p in open(sys.argv[1]).read().split("\n\n"): print re.sub(r"(?ms)\A(Chapter\s+\d+\s*:.*)","&lt;h1&gt;\g0&lt;/h1&gt;",p)'
+</span><span class="comment-delimiter">#</span><span class="comment"># ----------------------------
+</span>match = re.compile(r<span class="string">"(?ms)^START(.*?)^END"</span>)
+ <span class="comment-delimiter"># </span><span class="comment">s makes . span line boundaries
+</span> <span class="comment-delimiter"># </span><span class="comment">m makes ^ match at the beginning of the string and at the beginning of each line
+</span>
+chunk = 0
+<span class="keyword">for</span> paragraph <span class="keyword">in</span> <span class="py-builtins">open</span>(sys.argv[1]).read().split(<span class="string">"\n\n"</span>):
+ chunk += 1
+ fnd = match.findall(paragraph)
+ <span class="keyword">if</span> fnd:
+ <span class="keyword">print</span> <span class="string">"chunk %d in %s has &lt;&lt;%s&gt;&gt;"</span> % (chunk,sys.argv[1],<span class="string">"&gt;&gt;,&lt;&lt;"</span>.join(fnd))
+<span class="comment-delimiter">#</span><span class="comment"># ----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN306"
+>Reading Records with a Pattern Separator</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="keyword">import</span> sys
+<span class="comment-delimiter"># </span><span class="comment">Read the whole file and split
+</span>chunks = <span class="py-builtins">open</span>(sys.argv[1]).read().split() <span class="comment-delimiter"># </span><span class="comment">on whitespace
+</span>chunks = <span class="py-builtins">open</span>(sys.argv[1]).read().split(<span class="string">"\n"</span>) <span class="comment-delimiter"># </span><span class="comment">on line ends
+</span>
+<span class="comment-delimiter"># </span><span class="comment">splitting on pattern
+</span><span class="keyword">import</span> re
+pattern = r<span class="string">"x"</span>
+chunks = re.split(pattern, <span class="py-builtins">open</span>(sys.argv[1]).read())
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span>chunks = re.split(r<span class="string">"(?m)^\.(Ch|Se|Ss)$"</span>,<span class="py-builtins">open</span>(sys.argv[1]).read())
+<span class="keyword">print</span> <span class="string">"I read %d chunks."</span> % (<span class="py-builtins">len</span>(chunks))
+<span class="comment-delimiter"># </span><span class="comment">without delimiters
+</span>chunks = re.split(r<span class="string">"(?m)^\.(?:Ch|Se|Ss)$"</span>,<span class="py-builtins">open</span>(sys.argv[1]).read())
+
+<span class="comment-delimiter"># </span><span class="comment">with delimiters
+</span>chunks = re.split(r<span class="string">"(?m)^(\.(?:Ch|Se|Ss))$"</span>,<span class="py-builtins">open</span>(sys.argv[1]).read())
+
+<span class="comment-delimiter"># </span><span class="comment">with delimiters at chunkstart
+</span>chunks = re.findall(r<span class="string">"""(?xms) # multiline, dot matches lineend, allow comments
+ ((?:^\.)? # consume the separator if present
+ .*?) # match everything but not greedy
+ (?= # end the match on this but dont consume it
+ (?: # dont put into group [1]
+ ^\.(?:Ch|Se|Ss)$ # either end on one of the roff commands
+ |\Z # or end of text
+ )
+ )"""</span>,
+ <span class="py-builtins">open</span>(sys.argv[1]).read())
+<span class="comment-delimiter"># </span><span class="comment">[1] if "?:" is removed the result holds tuples: ('.Ch\nchapter x','.Ch')
+</span><span class="comment-delimiter"># </span><span class="comment">which might be more usefull.
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN309"
+>Extracting a Range of Lines</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Python doesn't have perl's range operators
+</span><span class="comment-delimiter"># </span><span class="comment">If you want to only use a selected line range, use enumerate
+</span><span class="comment-delimiter"># </span><span class="comment">(though note that indexing starts at zero:
+</span><span class="keyword">for</span> i, line <span class="keyword">in</span> <span class="py-builtins">enumerate</span>(myfile):
+ <span class="keyword">if</span> firstlinenum &lt;= i &lt; lastlinenum:
+ dosomethingwith(line)
+
+<span class="comment-delimiter"># </span><span class="comment">Using patterned ranges is slightly trickier -
+</span><span class="comment-delimiter"># </span><span class="comment">You need to search for the first pattern then
+</span><span class="comment-delimiter"># </span><span class="comment">search for the next pattern:
+</span><span class="keyword">import</span> re
+<span class="keyword">for</span> line <span class="keyword">in</span> myfile:
+ <span class="keyword">if</span> re.match(pat1, line):
+ <span class="keyword">break</span>
+
+dosomethingwith(line) <span class="comment-delimiter"># </span><span class="comment">Only if pat1 can be on same line as pat2
+</span>
+<span class="keyword">for</span> line <span class="keyword">in</span> myfile:
+ <span class="keyword">if</span> re.match(pat2, line):
+ <span class="keyword">break</span>
+ dosomethingwith(line)
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">If you need to extract ranges a lot, the following generator funcs
+</span><span class="comment-delimiter"># </span><span class="comment">may be useful:
+</span><span class="keyword">def</span> <span class="function-name">extract_range</span>(myfile, start, finish):
+ <span class="keyword">for</span> i, line <span class="keyword">in</span> <span class="py-builtins">enumerate</span>(myfile):
+ <span class="keyword">if</span> start &lt;= i &lt; finish:
+ <span class="keyword">yield</span> line
+ <span class="keyword">elif</span> i == finish:
+ <span class="keyword">break</span>
+
+<span class="keyword">for</span> line <span class="keyword">in</span> extract_range(<span class="py-builtins">open</span>(<span class="string">"/etc/passwd"</span>), 3, 5):
+ <span class="keyword">print</span> line
+
+<span class="keyword">def</span> <span class="function-name">patterned_range</span>(myfile, startpat, endpat=<span class="py-pseudo-keyword">None</span>):
+ startpat = re.compile(startpat)
+ <span class="keyword">if</span> endpat <span class="keyword">is</span> <span class="keyword">not</span> <span class="py-pseudo-keyword">None</span>:
+ endpat = re.compile(endpat)
+ in_range = <span class="py-pseudo-keyword">False</span>
+ <span class="keyword">for</span> line <span class="keyword">in</span> myfile:
+ <span class="keyword">if</span> re.match(startpat, line):
+ in_range = <span class="py-pseudo-keyword">True</span>
+ <span class="keyword">if</span> in_range:
+ <span class="keyword">yield</span> line
+ <span class="keyword">if</span> endpat <span class="keyword">is</span> <span class="keyword">not</span> <span class="py-pseudo-keyword">None</span> <span class="keyword">and</span> re.match(endpat, line):
+ <span class="keyword">break</span>
+
+<span class="comment-delimiter"># </span><span class="comment">DO NOT DO THIS. Use the email module instead
+</span><span class="keyword">for</span> line <span class="keyword">in</span> patterned_range(msg, <span class="string">"^From:?"</span>, <span class="string">"^$"</span>):
+ <span class="keyword">pass</span> <span class="comment-delimiter">#</span><span class="comment">...
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN312"
+>Matching Shell Globs as Regular Expressions</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span>tests = ((<span class="string">"list.?"</span>,r<span class="string">"^list\..$"</span>),
+ (<span class="string">"project.*"</span>,r<span class="string">"^project\..*$"</span>),
+ (<span class="string">"*old"</span>,r<span class="string">"^.*old$"</span>),
+ (<span class="string">"type*.[ch]"</span>,r<span class="string">"^type.*\.[ch]$"</span>),
+ (<span class="string">"*.*"</span>,r<span class="string">"^.*\..*$"</span>),
+ (<span class="string">"*"</span>,r<span class="string">"^.*$"</span>),
+ )
+
+<span class="comment-delimiter"># </span><span class="comment">The book says convert "*","?","[","]" all other characters will be quoted.
+</span><span class="comment-delimiter"># </span><span class="comment">The book uses "\Q" which escapes any characters that would otherwise be
+</span><span class="comment-delimiter"># </span><span class="comment">treated as regular expression.
+</span><span class="comment-delimiter"># </span><span class="comment">Escaping every char fails as "\s" is not "s" in a regex.
+</span>
+<span class="keyword">def</span> <span class="function-name">glob2pat</span>(globstr):
+ pat = globstr.replace(<span class="string">"\\"</span>,r<span class="string">"\\"</span>)
+ pat = pat.replace(<span class="string">"."</span>,r<span class="string">"\."</span>).replace(<span class="string">"?"</span>,r<span class="string">"."</span>).replace(<span class="string">"*"</span>,r<span class="string">".*"</span>)
+
+ <span class="keyword">return</span> <span class="string">"^"</span>+pat+<span class="string">"$"</span>
+
+<span class="keyword">for</span> globstr, patstr <span class="keyword">in</span> tests:
+ g2p = glob2pat(globstr)
+ <span class="keyword">if</span> g2p != patstr:
+ <span class="keyword">print</span> globstr, <span class="string">"failed! Should be"</span>, patstr, <span class="string">"but was"</span>, g2p</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN315"
+>Speeding Up Interpolated Matches</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span>
+<span class="comment-delimiter"># </span><span class="comment"><font size="-1"><a href="http://pleac.sourceforge.net/include/python/ch06/popgrep1">download the following standalone program</a></font>
+</span><span class="comment-delimiter">#</span><span class="comment">!/usr/bin/python
+</span><span class="comment-delimiter"># </span><span class="comment">popgrep1 - grep for abbreviations of places that say "pop"
+</span><span class="comment-delimiter"># </span><span class="comment">version 1: slow but obvious way
+</span><span class="keyword">import</span> fileinput
+<span class="keyword">import</span> re
+popstates = [<span class="string">"CO"</span>,<span class="string">"ON"</span>,<span class="string">"MI"</span>,<span class="string">"WI"</span>,<span class="string">"MN"</span>]
+<span class="keyword">for</span> line <span class="keyword">in</span> fileinput.input():
+ <span class="keyword">for</span> state <span class="keyword">in</span> popstates:
+ <span class="keyword">if</span> re.search(r<span class="string">"\b"</span>+state+r<span class="string">"\b"</span>,line):
+ <span class="keyword">print</span> line
+
+
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment"><font size="-1"><a href="http://pleac.sourceforge.net/include/python/ch06/popgrep2">download the following standalone program</a></font>
+</span><span class="comment-delimiter">#</span><span class="comment">!/usr/bin/python
+</span><span class="comment-delimiter"># </span><span class="comment">popgrep2 - grep for abbreviations of places that say "pop"
+</span><span class="comment-delimiter"># </span><span class="comment">version 2: compile the patterns
+</span><span class="keyword">import</span> fileinput
+<span class="keyword">import</span> re
+popstates = [<span class="string">"CO"</span>,<span class="string">"ON"</span>,<span class="string">"MI"</span>,<span class="string">"WI"</span>,<span class="string">"MN"</span>]
+state_re = []
+<span class="keyword">for</span> state <span class="keyword">in</span> popstates:
+ state_re.append(re.compile(r<span class="string">"\b"</span>+state+r<span class="string">"\b"</span>))
+<span class="keyword">for</span> line <span class="keyword">in</span> fileinput.input():
+ <span class="keyword">for</span> state <span class="keyword">in</span> state_re:
+ <span class="keyword">if</span> state.search(line):
+ <span class="keyword">print</span> line
+
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment"><font size="-1"><a href="http://pleac.sourceforge.net/include/python/ch06/popgrep3">download the following standalone program</a></font>
+</span><span class="comment-delimiter">#</span><span class="comment">!/usr/bin/python
+</span><span class="comment-delimiter"># </span><span class="comment">popgrep3 - grep for abbreviations of places that say "pop"
+</span><span class="comment-delimiter"># </span><span class="comment">version 3: compile a single pattern
+</span><span class="keyword">import</span> fileinput
+<span class="keyword">import</span> re
+popstates = [<span class="string">"CO"</span>,<span class="string">"ON"</span>,<span class="string">"MI"</span>,<span class="string">"WI"</span>,<span class="string">"MN"</span>]
+state_re = re.compile(r<span class="string">"\b(?:"</span>+<span class="string">"|"</span>.join(popstates)+r<span class="string">")\b"</span>)
+<span class="keyword">for</span> line <span class="keyword">in</span> fileinput.input():
+ <span class="keyword">if</span> state_re.search(line):
+ <span class="keyword">print</span> line
+
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment"><font size="-1"><a href="http://pleac.sourceforge.net/include/python/ch06/grepauth">download the following standalone program</a></font>
+</span><span class="comment-delimiter">#</span><span class="comment">!/usr/bin/python
+</span><span class="comment-delimiter"># </span><span class="comment">grepauth - print lines that mention both Tom and Nat
+</span><span class="keyword">import</span> fileinput
+<span class="keyword">import</span> re
+
+<span class="keyword">def</span> <span class="function-name">build_match_any</span>(words):
+ <span class="keyword">return</span> re.compile(<span class="string">"|"</span>.join(words))
+<span class="keyword">def</span> <span class="function-name">uniq</span>(arr):
+ seen = {}
+ <span class="keyword">for</span> item <span class="keyword">in</span> arr:
+ seen[item] = seen.get(item, 0) + 1
+ <span class="keyword">return</span> seen.keys()
+<span class="keyword">def</span> <span class="function-name">build_match_all</span>(words):
+ r = re.compile(<span class="string">"|"</span>.join(words))
+ c = <span class="keyword">lambda</span> line: <span class="py-builtins">len</span>(uniq(r.findall(line)))&gt;=<span class="py-builtins">len</span>(words)
+ <span class="keyword">return</span> c
+
+any = build_match_any((<span class="string">"Tom"</span>,<span class="string">"Nat"</span>))
+all = build_match_all((<span class="string">"Tom"</span>,<span class="string">"Nat"</span>))
+<span class="keyword">for</span> line <span class="keyword">in</span> fileinput.input():
+ <span class="keyword">if</span> any.search(line):
+ <span class="keyword">print</span> <span class="string">"any:"</span>, line
+ <span class="keyword">if</span> all(line):
+ <span class="keyword">print</span> <span class="string">"all:"</span>, line
+
+
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN318"
+>Testing for a Valid Pattern</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">Testing for a Valid Pattern
+</span>
+<span class="keyword">import</span> re
+<span class="keyword">while</span> <span class="py-pseudo-keyword">True</span>:
+ pat = <span class="py-builtins">raw_input</span>(<span class="string">"Pattern? "</span>)
+ <span class="keyword">try:</span>
+ re.compile(pat)
+ <span class="keyword">except</span> re.error, err:
+ <span class="keyword">print</span> <span class="string">"INVALID PATTERN"</span>, err
+ <span class="keyword">continue</span>
+ <span class="keyword">break</span>
+
+<span class="comment-delimiter"># </span><span class="comment">----
+</span><span class="keyword">def</span> <span class="function-name">is_valid_pattern</span>(pat):
+ <span class="keyword">try:</span>
+ re.compile(pat)
+ <span class="keyword">except</span> re.error:
+ <span class="keyword">return</span> <span class="py-pseudo-keyword">False</span>
+ <span class="keyword">return</span> <span class="py-pseudo-keyword">True</span>
+
+<span class="comment-delimiter"># </span><span class="comment">----
+</span>
+<span class="comment-delimiter"># </span><span class="comment"><font size="-1"><a href="http://pleac.sourceforge.net/include/python/ch06/paragrep">download the following standalone program</a></font>
+</span><span class="comment-delimiter">#</span><span class="comment">!/usr/bin/python
+</span><span class="comment-delimiter"># </span><span class="comment">paragrep - trivial paragraph grepper
+</span><span class="comment-delimiter">#</span><span class="comment">
+</span><span class="comment-delimiter"># </span><span class="comment">differs from perl version in parano.
+</span><span class="comment-delimiter"># </span><span class="comment">python version displays paragraph in current file.
+</span>
+<span class="keyword">import</span> sys, os.path, re
+<span class="keyword">if</span> <span class="py-builtins">len</span>(sys.argv)&lt;=1:
+ <span class="keyword">print</span> <span class="string">"usage: %s pat [files]\n"</span> % sys.argv[0]
+ sys.exit(1)
+
+pat = sys.argv[1]
+<span class="keyword">try:</span>
+ pat_re = re.compile(pat)
+<span class="keyword">except:</span>
+ <span class="keyword">print</span> <span class="string">"%s: bad pattern %s: %s"</span> % (sys.argv[1], pat, sys.exc_info()[1])
+ sys.exit(1)
+<span class="keyword">for</span> filename <span class="keyword">in</span> <span class="py-builtins">filter</span>(os.path.isfile,sys.argv[2:]):
+ parano = 0
+ <span class="keyword">for</span> para <span class="keyword">in</span> <span class="py-builtins">open</span>(filename).read().split(<span class="string">"\n\n"</span>):
+ parano += 1
+ <span class="keyword">if</span> pat_re.search(para):
+ <span class="keyword">print</span> filename, parano, para, <span class="string">"\n"</span>
+
+
+
+<span class="comment-delimiter"># </span><span class="comment">----
+</span>
+<span class="comment-delimiter"># </span><span class="comment">as we dont evaluate patterns the attack ::
+</span><span class="comment-delimiter">#</span><span class="comment">
+</span><span class="comment-delimiter"># </span><span class="comment">$pat = "You lose @{[ system('rm -rf *']} big here";
+</span><span class="comment-delimiter">#</span><span class="comment">
+</span><span class="comment-delimiter"># </span><span class="comment">does not work.
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN321"
+>Honoring Locale Settings in Regular Expressions</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span>
+<span class="comment-delimiter"># </span><span class="comment"><font size="-1"><a href="http://pleac.sourceforge.net/include/python/ch06/localeg">download the following standalone program</a></font>
+</span><span class="comment-delimiter">#</span><span class="comment">!/usr/bin/python
+</span><span class="comment-delimiter"># </span><span class="comment">localeg - demonstrates locale effects
+</span><span class="comment-delimiter">#</span><span class="comment">
+</span><span class="comment-delimiter"># </span><span class="comment">re must be told to respect locale either in the regexp
+</span><span class="comment-delimiter"># </span><span class="comment">"(?L)" or as flag to the call (python 2.4) "re.LOCALE".
+</span>
+<span class="keyword">import</span> sys
+<span class="keyword">import</span> re, string
+<span class="keyword">from</span> locale <span class="keyword">import</span> LC_CTYPE, setlocale, getlocale
+
+name = <span class="string">"andreas k\xF6nig"</span>
+locale = {<span class="string">"German"</span> : <span class="string">"de_DE.ISO_8859-1"</span>, <span class="string">"English"</span> : <span class="string">"en_US"</span>}
+<span class="comment-delimiter"># </span><span class="comment">us-ascii is not supported on linux py23
+</span><span class="comment-delimiter"># </span><span class="comment">none works in activestate py24
+</span>
+<span class="keyword">try:</span>
+ setlocale(LC_CTYPE, locale[<span class="string">"English"</span>])
+<span class="keyword">except:</span>
+ <span class="keyword">print</span> <span class="string">"Invalid locale %s"</span> % locale[<span class="string">"English"</span>]
+ sys.exit(1)
+english_names = []
+<span class="keyword">for</span> n <span class="keyword">in</span> re.findall(r<span class="string">"(?L)\b(\w+)\b"</span>,name):
+ english_names.append(n.capitalize())
+
+<span class="keyword">try:</span>
+ setlocale(LC_CTYPE, locale[<span class="string">"German"</span>])
+<span class="keyword">except:</span>
+ <span class="keyword">print</span> <span class="string">"Invalid locale %s"</span> % locale[<span class="string">"German"</span>]
+ sys.exit(1)
+german_names = <span class="py-builtins">map</span>(string.capitalize, re.findall(r<span class="string">"(?L)\b(\w+)\b"</span>,name))
+
+<span class="keyword">print</span> <span class="string">"English names: %s"</span> % <span class="string">" "</span>.join(english_names)
+<span class="keyword">print</span> <span class="string">"German names: %s"</span> % <span class="string">" "</span>.join(german_names)</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN324"
+>Approximate Matching</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span><span class="keyword">import</span> difflib
+matchlist = [<span class="string">"ape"</span>, <span class="string">"apple"</span>, <span class="string">"lapel"</span>, <span class="string">"peach"</span>, <span class="string">"puppy"</span>]
+<span class="keyword">print</span> difflib.get_close_matches(<span class="string">"appel"</span>, matchlist)
+<span class="comment-delimiter">#</span><span class="comment">=&gt; ['lapel', 'apple', 'ape']
+</span><span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Also see:
+</span><span class="comment-delimiter"># </span><span class="comment">http://www.personal.psu.edu/staff/i/u/iua1/python/apse/
+</span><span class="comment-delimiter"># </span><span class="comment">http://www.bio.cam.ac.uk/~mw263/pyagrep.html
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN327"
+>Matching from Where the Last Pattern Left Off</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">To search (potentially) repeatedly for a pattern, use re.finditer():
+</span>
+<span class="comment-delimiter"># </span><span class="comment">DO NOT DO THIS. Split on commas and convert elems using int()
+</span>mystr = <span class="string">"3,4,5,9,120"</span>
+<span class="keyword">for</span> match <span class="keyword">in</span> re.finditer(<span class="string">"(\d+)"</span>, mystr):
+ n = match.group(0)
+ <span class="keyword">if</span> n == <span class="string">"9"</span>:
+ <span class="keyword">break</span> <span class="comment-delimiter"># </span><span class="comment">'120' will never be matched
+</span> <span class="keyword">print</span> <span class="string">"Found number"</span>, n
+
+<span class="comment-delimiter"># </span><span class="comment">matches know their end position
+</span>mystr = <span class="string">"The year 1752 lost 10 days on the 3rd of September"</span>
+x = re.finditer(<span class="string">"(\d+)"</span>, mystr)
+<span class="keyword">for</span> match <span class="keyword">in</span> x:
+ n = match.group(0)
+ <span class="keyword">print</span> <span class="string">"Found number"</span>, n
+
+tail = re.match(<span class="string">"(\S+)"</span>, mystr[match.end():])
+<span class="keyword">if</span> tail:
+ <span class="keyword">print</span> <span class="string">"Found %s after the last number."</span>%tail.group(0)</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN330"
+>Greedy and Non-Greedy Matches</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">Python's regexes are based on Perl's, so it has the non-greedy
+</span><span class="comment-delimiter"># </span><span class="comment">'*?', '+?', and '??' versions of '*', '+', and '?'.
+</span><span class="comment-delimiter"># </span><span class="comment">DO NOT DO THIS. import htmllib, formatter, etc, instead
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">greedy pattern
+</span>txt = re.sub(<span class="string">"&lt;.*&gt;"</span>, <span class="string">""</span>, txt) <span class="comment-delimiter"># </span><span class="comment">try to remove tags, very badly
+</span>
+<span class="comment-delimiter"># </span><span class="comment">non-greedy pattern
+</span>txt = re.sub(<span class="string">"&lt;.*?&gt;"</span>, <span class="string">""</span>, txt) <span class="comment-delimiter"># </span><span class="comment">try to remove tags, still rather badly
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>txt = <span class="string">"&lt;b&gt;&lt;i&gt;this&lt;/i&gt; and &lt;i&gt;that&lt;/i&gt; are important&lt;/b&gt; Oh, &lt;b&gt;&lt;i&gt;me too!&lt;/i&gt;&lt;/b&gt;"</span>
+
+<span class="keyword">print</span> re.findall(<span class="string">"&lt;b&gt;&lt;i&gt;(.*?)&lt;/i&gt;&lt;/b&gt;"</span>, txt
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span><span class="keyword">print</span> re.findall(<span class="string">"/BEGIN((?:(?!BEGIN).)*)END/"</span>, txt)
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span><span class="keyword">print</span> re.findall(<span class="string">"&lt;b&gt;&lt;i&gt;((?:(?!&lt;b&gt;|&lt;i&gt;).)*)&lt;/i&gt;&lt;/b&gt;"</span>, txt)
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span><span class="keyword">print</span> re.findall(<span class="string">"&lt;b&gt;&lt;i&gt;((?:(?!&lt;[ib]&gt;).)*)&lt;/i&gt;&lt;/b&gt;"</span>, txt)
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span><span class="keyword">print</span> re.findall(<span class="string">"""
+ &lt;b&gt;&lt;i&gt;
+ [^&lt;]* # stuff not possibly bad, and not possibly the end.
+ (?: # at this point, we can have '&lt;' if not part of something bad
+ (?! &lt;/?[ib]&gt; ) # what we can't have
+ &lt; # okay, so match the '&lt;'
+ [^&lt;]* # and continue with more safe stuff
+ ) *
+ &lt;/i&gt;&lt;/b&gt;
+ """</span>, re.VERBOSE, txt)
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN333"
+>Detecting Duplicate Words</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span>text = <span class="string">"""
+This is a test
+test of the duplicate word finder.
+"""</span>
+words = text.split()
+<span class="keyword">for</span> curr, next <span class="keyword">in</span> <span class="py-builtins">zip</span>(words[:-1], words[1:]):
+ <span class="keyword">if</span> curr.upper() == next.upper():
+ <span class="keyword">print</span> <span class="string">"Duplicate word '%s' found."</span> % curr
+
+<span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS
+</span><span class="keyword">import</span> re
+pat = r<span class="string">"""
+ \b # start at a word boundary (begin letters)
+ (\S+) # find chunk of non-whitespace
+ \b # until another word boundary (end letters)
+ (
+ \s+ # separated by some whitespace
+ \1 # and that very same chunk again
+ \b # until another word boundary
+ ) + # one or more sets of those
+ """</span>
+<span class="keyword">for</span> match <span class="keyword">in</span> re.finditer(pat, text, flags=re.VERBOSE|re.IGNORECASE):
+ <span class="keyword">print</span> <span class="string">"Duplicate word '%s' found."</span> % match.group(1)
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span>a = <span class="string">'nobody'</span>;
+b = <span class="string">'bodysnatcher'</span>;
+
+text = a+<span class="string">" "</span>+b
+pat = r<span class="string">"^(\w+)(\w+) \2(\w+)$"</span>
+<span class="keyword">for</span> match <span class="keyword">in</span> re.finditer(pat, text):
+ m1, m2, m3 = match.groups()
+ <span class="keyword">print</span> m2, <span class="string">"overlaps in %s-%s-%s"</span>%(m1, m2, m3)
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span>pat = r<span class="string">"^(\w+?)(\w+) \2(\w+)$"</span>
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span><span class="keyword">try:</span>
+ <span class="keyword">while</span> <span class="py-pseudo-keyword">True</span>:
+ factor = re.match(r<span class="string">"^(oo+?)\1+$"</span>, n).group(1)
+ n = re.sub(factor, <span class="string">"o"</span>, n)
+ <span class="keyword">print</span> <span class="py-builtins">len</span>(factor)
+<span class="keyword">except</span> <span class="py-builtins">AttributeError</span>:
+ <span class="keyword">print</span> <span class="py-builtins">len</span>(n)
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span><span class="keyword">def</span> <span class="function-name">diaphantine</span>(n, x, y, z):
+ pat = r<span class="string">"^(o*)\1{%s}(o*)\2{%s}(o*)\3{%s}$"</span>%(x-1, y-1, z-1)
+ text = <span class="string">"o"</span>*n
+ <span class="keyword">try:</span>
+ vals = [<span class="py-builtins">len</span>(v) <span class="keyword">for</span> v <span class="keyword">in</span> re.match(pat, text).groups()]
+ <span class="keyword">except</span> <span class="py-builtins">ValueError</span>:
+ <span class="keyword">print</span> <span class="string">"No solutions."</span>
+ <span class="keyword">else:</span>
+ <span class="keyword">print</span> <span class="string">"One solution is: x=%s, y=%s, z=%s."</span>%<span class="py-builtins">tuple</span>(vals)
+
+diaphantine(n=281, x=12, y=15, z=16)</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN336"
+>Expressing AND, OR, and NOT in a Single Pattern</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Pass any of the following patterns to re.match(), etc
+</span>pat = <span class="string">"ALPHA|BETA"</span>
+pat = <span class="string">"^(?=.*ALPHA)(?=.*BETA)"</span>
+pat = <span class="string">"ALPHA.*BETA|BETA.*ALPHA"</span>
+pat = <span class="string">"^(?:(?!PAT).)*$"</span>
+pat = <span class="string">"(?=^(?:(?!BAD).)*$)GOOD"</span>
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span><span class="keyword">if</span> <span class="keyword">not</span> re.match(pattern, text):
+ something()
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span><span class="keyword">if</span> re.match(pat1, text) <span class="keyword">and</span> re.match(pat2, text):
+ something()
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span><span class="keyword">if</span> re.match(pat1, text) <span class="keyword">or</span> re.match(pat2, text):
+ something()
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS.
+</span><span class="string">"""minigrep - trivial grep"""</span>
+<span class="keyword">import</span> sys, re
+
+pat = sys.argv[1]
+<span class="keyword">for</span> line <span class="keyword">in</span> sys.stdin:
+ <span class="keyword">if</span> re.match(pat, line):
+ <span class="keyword">print</span> line[:-1]
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span><span class="keyword">if</span> re.match(r<span class="string">"^(?=.*bell)(?=.*lab)"</span>, <span class="string">"labelled"</span>):
+ something()
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span><span class="keyword">if</span> re.search(<span class="string">"bell"</span>, s) <span class="keyword">and</span> re.search(<span class="string">"lab"</span>, s):
+ something()
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span><span class="keyword">if</span> re.match(<span class="string">"""
+ ^ # start of string
+ (?= # zero-width lookahead
+ .* # any amount of intervening stuff
+ bell # the desired bell string
+ ) # rewind, since we were only looking
+ (?= # and do the same thing
+ .* # any amount of intervening stuff
+ lab # and the lab part
+ )
+ """</span>,
+ murray_hill,
+ re.DOTALL | re.VERBOSE):
+ <span class="keyword">print</span> <span class="string">"Looks like Bell Labs might be in Murray Hill!"</span>
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span><span class="keyword">if</span> re.match(r<span class="string">"(?:^.*bell.*lab)|(?:^.*lab.*bell)"</span>, <span class="string">"labelled"</span>):
+ something()
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span>brand = <span class="string">"labelled"</span>
+<span class="keyword">if</span> re.match(<span class="string">"""
+ (?: # non-capturing grouper
+ ^ .*? # any amount of stuff at the front
+ bell # look for a bell
+ .*? # followed by any amount of anything
+ lab # look for a lab
+ ) # end grouper
+ | # otherwise, try the other direction
+ (?: # non-capturing grouper
+ ^ .*? # any amount of stuff at the front
+ lab # look for a lab
+ .*? # followed by any amount of anything
+ bell # followed by a bell
+ ) # end grouper
+ """</span>,
+ brand,
+ re.DOTALL | re.VERBOSE):
+ <span class="keyword">print</span> <span class="string">"Our brand has bell and lab separate."</span>
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span>x = <span class="string">"odlaw"</span>
+<span class="keyword">if</span> re.match(<span class="string">"^(?:(?!waldo).)*$"</span>, x):
+ <span class="keyword">print</span> <span class="string">"There's no waldo here!"</span>
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span><span class="keyword">if</span> re.match(<span class="string">"""
+ ^ # start of string
+ (?: # non-capturing grouper
+ (?! # look ahead negation
+ waldo # is he ahead of us now?
+ ) # is so, the negation failed
+ . # any character (cuzza /s)
+ ) * # repeat that grouping 0 or more
+ $ # through the end of the string
+ """</span>,
+ x,
+ re.VERBOSE | re.DOTALL):
+ <span class="keyword">print</span> <span class="string">"There's no waldo here!\n"</span>;
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN339"
+>Matching Multiple-Byte Characters</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN342"
+>Matching a Valid Mail Address</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span><span class="keyword">from</span> email._parseaddr <span class="keyword">import</span> AddressList
+
+<span class="keyword">print</span> AddressList(<span class="string">"fred&amp;barney@stonehenge.com"</span>).addresslist[0]
+
+<span class="keyword">print</span> AddressList(<span class="string">"fred&amp;barney@stonehenge.com (Hanna Barbara)"</span>).addresslist[0]
+
+name, address = AddressList(<span class="string">"Mr Fooby Blah &lt;<a href="mailto:me&#64;nowhere.com">me&#64;nowhere.com</a>&gt;"</span>).addresslist[0]
+<span class="keyword">print</span> <span class="string">"%s's address is '%s'"</span>%(name, address)</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN345"
+>Matching Abbreviations</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Assuming the strings all start with different letters, or you don't
+</span><span class="comment-delimiter"># </span><span class="comment">mind there being precedence, use the startswith string method:
+</span>
+<span class="keyword">def</span> <span class="function-name">get_action</span>(answer):
+ answer = answer.lower()
+ actions = [<span class="string">"send"</span>, <span class="string">"stop"</span>, <span class="string">"abort"</span>, <span class="string">"list"</span>, <span class="string">"end"</span>]
+ <span class="keyword">for</span> action <span class="keyword">in</span> actions:
+ <span class="keyword">if</span> action.startswith(answer):
+ <span class="keyword">return</span> action
+
+<span class="keyword">print</span> <span class="string">"Action is %s."</span>%get_action(<span class="string">"L"</span>)
+<span class="comment-delimiter">#</span><span class="comment">=&gt; Action is list.
+</span><span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment">DON'T DO THIS:
+</span><span class="keyword">import</span> re
+answer = <span class="string">"ab"</span>
+answer = re.escape(answer.strip())
+<span class="keyword">for</span> action <span class="keyword">in</span> (<span class="string">"SEND"</span>, <span class="string">"STOP"</span>, <span class="string">"ABORT"</span>, <span class="string">"LIST"</span>, <span class="string">"EDIT"</span>):
+ <span class="keyword">if</span> re.match(answer, action, flags=re.IGNORECASE):
+ <span class="keyword">print</span> <span class="string">"Action is %s."</span>%action.lower()
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span><span class="keyword">import</span> re, sys
+<span class="keyword">def</span> <span class="function-name">handle_cmd</span>(cmd):
+ cmd = re.escape(cmd.strip())
+ <span class="keyword">for</span> name, action <span class="keyword">in</span> {<span class="string">"edit"</span>: invoke_editor,
+ <span class="string">"send"</span>: deliver_message,
+ <span class="string">"list"</span>: lambda: system(pager, myfile),
+ <span class="string">"abort"</span>: sys.exit,
+ }
+ <span class="keyword">if</span> re.match(cmd, name, flags=re.IGNORECASE):
+ action()
+ <span class="keyword">break</span>
+ <span class="keyword">else:</span>
+ <span class="keyword">print</span> <span class="string">"Unknown command:"</span>, cmd
+handle_cmd(<span class="string">"ab"</span>)</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN348"
+>Program: urlify</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">urlify - wrap HTML links around URL-like constructs
+</span><span class="keyword">import</span> re, sys, fileinput
+
+<span class="keyword">def</span> <span class="function-name">urlify_string</span>(s):
+ urls = r<span class="string">'(http|telnet|gopher|file|wais|ftp)'</span>
+
+ ltrs = r<span class="string">'\w'</span>;
+ gunk = r<span class="string">'/#~:.?+=&amp;%@!\-'</span>
+ punc = r<span class="string">'.:?\-'</span>
+ any = ltrs + gunk + punc
+
+ pat = re.compile(r<span class="string">"""
+ \b # start at word boundary
+ ( # begin \1 {
+ %(urls)s : # need resource and a colon
+ [%(any)s] +? # followed by one or more
+ # of any valid character, but
+ # be conservative and take only
+ # what you need to....
+ ) # end \1 }
+ (?= # look-ahead non-consumptive assertion
+ [%(punc)s]* # either 0 or more punctuation
+ [^%(any)s] # followed by a non-url char
+ | # or else
+ $ # then end of the string
+ )
+ """</span>%<span class="py-builtins">locals</span>(), re.VERBOSE | re.IGNORECASE)
+ <span class="keyword">return</span> re.sub(pat, r<span class="string">"&lt;A HREF=\1&gt;\1&lt;/A&gt;"</span>, s)
+
+<span class="keyword">if</span> <span class="py-builtins">__name__</span> == <span class="string">"__main__"</span>:
+ <span class="keyword">for</span> line <span class="keyword">in</span> fileinput.input():
+ <span class="keyword">print</span> urlify_string(line)</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN351"
+>Program: tcgrep</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN354"
+>Regular Expression Grabbag</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">The majority of regexes in this section are either partially
+</span><span class="comment-delimiter"># </span><span class="comment">or completely The Wrong Thing to Do.
+</span><span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS. Use a Roman Numeral module, etc. (since
+</span><span class="comment-delimiter"># </span><span class="comment">you need one anyway to calculate values)
+</span>pat = r<span class="string">"^m*(d?c{0,3}|c[dm])(l?x{0,3}|x[lc])(v?i{0,3}|i[vx])$"</span>
+re.match(pat, <span class="string">"mcmlxcvii"</span>)
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span>txt = <span class="string">"one two three four five"</span>
+
+<span class="comment-delimiter"># </span><span class="comment">If the words are cleanly delimited just split and rejoin:
+</span>word1, word2, rest = txt.split(<span class="string">" "</span>, 2)
+<span class="keyword">print</span> <span class="string">" "</span>.join([word2, word1, rest])
+
+<span class="comment-delimiter"># </span><span class="comment">Otherwise:
+</span>frompat = r<span class="string">"(\S+)(\s+)(\S+)"</span>
+topat = r<span class="string">"\3\2\1"</span>
+<span class="keyword">print</span> re.sub(frompat, topat, txt)
+
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span><span class="keyword">print</span> str.split(<span class="string">"="</span>)
+
+<span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS
+</span>pat = r<span class="string">"(\w+)\s*=\s*(.*)\s*$"</span>
+<span class="keyword">print</span> re.match(pat, <span class="string">"key=val"</span>).groups()
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span>line = <span class="string">"such a very very very very very very very very very very very very very long line"</span>
+<span class="keyword">if</span> <span class="py-builtins">len</span>(line) &gt; 80:
+ process(line)
+
+<span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS
+</span>pat = <span class="string">".{80,}"</span>
+<span class="keyword">if</span> re.match(pat, line):
+ process(line)
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span>dt = time.strptime(<span class="string">"12/11/05 12:34:56"</span>, <span class="string">"%d/%m/%y %H:%M:%S"</span>)
+
+<span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS
+</span>pat = r<span class="string">"(\d+)/(\d+)/(\d+) (\d+):(\d+):(\d+)"</span>
+dt = re.match(pat, <span class="string">"12/11/05 12:34:56"</span>).groups()
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span>txt = <span class="string">"/usr/bin/python"</span>
+<span class="keyword">print</span> txt.replace(<span class="string">"/usr/bin"</span>, <span class="string">"/usr/local/bin"</span>)
+<span class="comment-delimiter"># </span><span class="comment">Alternatively for file operations use os.path, shutil, etc.
+</span>
+<span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS
+</span><span class="keyword">print</span> re.sub(<span class="string">"/usr/bin"</span>, <span class="string">"/usr/local/bin"</span>, txt)
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span><span class="keyword">import</span> re
+
+<span class="keyword">def</span> <span class="function-name">unescape_hex</span>(matchobj):
+ <span class="keyword">return</span> <span class="py-builtins">chr</span>(int(matchobj.groups(0)[0], 16))
+txt = re.sub(r<span class="string">"%([0-9A-Fa-f][0-9A-Fa-f])"</span>, unescape_hex, txt)
+
+<span class="comment-delimiter"># </span><span class="comment">Assuming that the hex escaping is well-behaved, an alternative is:
+</span><span class="keyword">def</span> <span class="function-name">unescape_hex</span>(seg):
+ <span class="keyword">return</span> <span class="py-builtins">chr</span>(int(seg[:2], 16)) + seg[2:]
+
+segs = txt.split(<span class="string">"%"</span>)
+txt = segs[0] + <span class="string">""</span>.join(unescape_hex(seg) <span class="keyword">for</span> seg <span class="keyword">in</span> segs[1:])
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span>txt = re.sub(r<span class="string">"""
+ /\* # Match the opening delimiter
+ .*? # Match a minimal number of characters
+ \*/ # Match the closing delimiter
+ """</span>, <span class="string">""</span>, txt, re.VERBOSE)
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span>txt.strip()
+
+<span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS
+</span>txt = re.sub(r<span class="string">"^\s+"</span>, <span class="string">""</span>, txt)
+txt = re.sub(r<span class="string">"\s+$"</span>, <span class="string">""</span>, txt)
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span>txt.replace(<span class="string">"\\n"</span>, <span class="string">"\n"</span>)
+
+<span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS
+</span>txt = re.sub(<span class="string">"\\n"</span>, <span class="string">"\n"</span>, txt)
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span>txt = re.sub(<span class="string">"^.*::"</span>, <span class="string">""</span>)
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span><span class="keyword">import</span> socket
+socket.inet_aton(txt) <span class="comment-delimiter"># </span><span class="comment">Will raise an error if incorrect
+</span>
+<span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS.
+</span>octseg =r<span class="string">"([01]?\d\d|2[0-4]\d|25[0-5])"</span>
+dot = r<span class="string">"\."</span>
+pat = <span class="string">"^"</span> + octseg + dot + octseg + dot + octseg + dot + octseg + <span class="string">"$"</span>
+
+<span class="keyword">if</span> <span class="keyword">not</span> re.match(pat, txt, re.VERBOSE)
+ <span class="keyword">raise</span> <span class="py-builtins">ValueError</span>
+
+<span class="comment-delimiter"># </span><span class="comment">Defitely DON'T DO THIS.
+</span>pat = r<span class="string">"""^([01]?\d\d|2[0-4]\d|25[0-5])\.([01]?\d\d|2[0-4]\d|25[0-5])\.
+ ([01]?\d\d|2[0-4]\d|25[0-5])\.([01]?\d\d|2[0-4]\d|25[0-5])$"""</span>
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span>fname = os.path.basename(path)
+
+<span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS.
+</span>fname = re.sub(<span class="string">"^.*/"</span>, <span class="string">""</span>, path)
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span><span class="keyword">import</span> os
+<span class="keyword">try:</span>
+ tc = os.environ[<span class="string">"TERMCAP"</span>]
+<span class="keyword">except</span> <span class="py-builtins">KeyError</span>:
+ cols = 80
+<span class="keyword">else:</span>
+ cols = re.match(<span class="string">":co#(\d+):"</span>).groups(1)
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">(not quite equivalent to the Perl version)
+</span>name = os.path.basename(sys.argv[0])
+
+<span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS.
+</span>name = re.sub(<span class="string">"^.*/"</span>, <span class="string">""</span>, sys.argv[0])
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span><span class="keyword">if</span> sys.platform != <span class="string">"linux"</span>:
+ <span class="keyword">raise</span> <span class="py-builtins">SystemExit</span>(<span class="string">"This isn't Linux"</span>)
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span>txt = re.sub(r<span class="string">"\n\s+"</span>, <span class="string">" "</span>, txt)
+
+<span class="comment-delimiter"># </span><span class="comment">In many cases you could just use:
+</span>txt = txt.replace(<span class="string">"\n"</span>, <span class="string">" "</span>)
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span>nums = re.findall(r<span class="string">"\d+\.?\d*|\.\d+"</span>, txt)
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">If the words are clearly delimited just use:
+</span>capwords = [word <span class="keyword">for</span> word <span class="keyword">in</span> txt.split() <span class="keyword">if</span> word.isupper()]
+
+<span class="comment-delimiter"># </span><span class="comment">Otherwise
+</span>capwords = [word <span class="keyword">for</span> word <span class="keyword">in</span> re.findall(r<span class="string">"\b(\S+)\b"</span>, txt) <span class="keyword">if</span> word.isupper()]
+
+<span class="comment-delimiter"># </span><span class="comment">(probably) DON'T DO THIS.
+</span>capwords = re.findall(r<span class="string">"(\b[^\Wa-z0-9_]+\b)"</span>, txt)
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">If the words are clearly delimited just use:
+</span>lowords = [word <span class="keyword">for</span> word <span class="keyword">in</span> txt.split() <span class="keyword">if</span> word.islower()]
+
+<span class="comment-delimiter"># </span><span class="comment">Otherwise
+</span>lowords = [word <span class="keyword">for</span> word <span class="keyword">in</span> re.findall(r<span class="string">"\b(\S+)\b"</span>, txt) <span class="keyword">if</span> word.islower()]
+
+<span class="comment-delimiter"># </span><span class="comment">(probably) DON'T DO THIS.
+</span>lowords = re.findall(r<span class="string">"(\b[^\WA-Z0-9_]+\b)"</span>, txt)
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">If the words are clearly delimited just use:
+</span>icwords = [word <span class="keyword">for</span> word <span class="keyword">in</span> txt.split() <span class="keyword">if</span> word.istitle()]
+
+<span class="comment-delimiter"># </span><span class="comment">Otherwise
+</span>icwords = [word <span class="keyword">for</span> word <span class="keyword">in</span> re.finditer(r<span class="string">"\b(\S+)\b"</span>) <span class="keyword">if</span> word.istitle()]
+
+<span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS.
+</span>icwords = re.findall(r<span class="string">"(\b[^\Wa-z0-9_][^\WA-Z0-9_]*\b)"</span>, txt)
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS - use HTMLParser, etc.
+</span>links = re.findall(r<span class="string">"""&lt;A[^&gt;]+?HREF\s*=\s*["']?([^'" &gt;]+?)[ '"</span>]?&gt;<span class="string">""", txt)
+##-----------------------------
+names = txt.split()
+if len(names) == 3:
+ initial = names[1][0]
+else:
+ initial = ""
+
+# DON'T DO THIS.
+pat = "</span>^\S+\s+(\S)\S*\s+\S<span class="string">"
+try:
+ initial = re.match(pat, txt).group(1)
+except AttributeError:
+ initial = ""
+##-----------------------------
+txt = re.sub('"</span>([^<span class="string">"]*)"', "``\1''", txt)
+##-----------------------------
+sentences = [elem[0] for elem in re.findall(r"(.*?[!?.])( |\Z)", s)]
+##-----------------------------
+import time
+dt = time.strptime(txt, "%Y-%m-%d")
+
+# DON'</span>T DO THIS.
+year, month, day = re.match(r<span class="string">"(\d{4})-(\d\d)-(\d\d)"</span>, txt).groups()
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span>pat = r<span class="string">"""
+ ^
+ (?:
+ 1 \s (?: \d\d\d \s)? # 1, or 1 and area code
+ | # ... or ...
+ \(\d\d\d\) \s # area code with parens
+ | # ... or ...
+ (?: \+\d\d?\d? \s)? # optional +country code
+ \d\d\d ([\s\-]) # and area code
+ )
+ \d\d\d (\s|\1) # prefix (and area code separator)
+ \d\d\d\d # exchange
+ $
+ """</span>
+re.match(pat, txt, re.VERBOSE)
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span>re.match(r<span class="string">"\boh\s+my\s+gh?o(d(dess(es)?|s?)|odness|sh)\b"</span>, txt, re.IGNORECASE)
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span><span class="keyword">for</span> line <span class="keyword">in</span> <span class="py-builtins">file</span>(fname, <span class="string">"Ur"</span>): <span class="comment-delimiter">#</span><span class="comment">Universal newlines
+</span> process(line)
+
+<span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS
+</span>lines = [re.sub(r<span class="string">"^([^\012\015]*)(\012\015?|\015\012?)"</span>, <span class="string">""</span>, line)
+ <span class="keyword">for</span> line <span class="keyword">in</span> <span class="py-builtins">file</span>(fname)]
+<span class="comment-delimiter">#</span><span class="comment">#-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+></DIV
+><DIV
+CLASS="NAVFOOTER"
+><HR
+ALIGN="LEFT"
+WIDTH="100%"><TABLE
+SUMMARY="Footer navigation table"
+WIDTH="100%"
+BORDER="0"
+CELLPADDING="0"
+CELLSPACING="0"
+><TR
+><TD
+WIDTH="33%"
+ALIGN="left"
+VALIGN="top"
+><A
+HREF="hashes.html"
+ACCESSKEY="P"
+>Prev</A
+></TD
+><TD
+WIDTH="34%"
+ALIGN="center"
+VALIGN="top"
+><A
+HREF="index.html"
+ACCESSKEY="H"
+>Home</A
+></TD
+><TD
+WIDTH="33%"
+ALIGN="right"
+VALIGN="top"
+><A
+HREF="fileaccess.html"
+ACCESSKEY="N"
+>Next</A
+></TD
+></TR
+><TR
+><TD
+WIDTH="33%"
+ALIGN="left"
+VALIGN="top"
+>Hashes</TD
+><TD
+WIDTH="34%"
+ALIGN="center"
+VALIGN="top"
+>&nbsp;</TD
+><TD
+WIDTH="33%"
+ALIGN="right"
+VALIGN="top"
+>File Access</TD
+></TR
+></TABLE
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/help/PythonExamples/pleac_python/processmanagementetc.html b/help/PythonExamples/pleac_python/processmanagementetc.html
new file mode 100644
index 0000000..3810192
--- /dev/null
+++ b/help/PythonExamples/pleac_python/processmanagementetc.html
@@ -0,0 +1,887 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML
+><HEAD
+><TITLE
+>Process Management and Communication</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
+REL="HOME"
+TITLE="PLEAC-Python
+"
+HREF="index.html"><LINK
+REL="PREVIOUS"
+TITLE="User Interfaces"
+HREF="userinterfaces.html"><LINK
+REL="NEXT"
+TITLE="Sockets"
+HREF="sockets.html"><style type="text/css"> <!--
+ .comment {
+ /* font-lock-comment-face */
+ color: #bebebe;
+ }
+ .comment-delimiter {
+ }
+ .function-name {
+ /* font-lock-function-name-face */
+ color: #b2dfee;
+ }
+ .keyword {
+ /* font-lock-keyword-face */
+ color: #ffa500;
+ }
+ .py-builtins {
+ /* py-builtins-face */
+ color: #ffa500;
+ }
+ .py-pseudo-keyword {
+ /* py-pseudo-keyword-face */
+ color: #ffa500;
+ }
+ .string {
+ /* font-lock-string-face */
+ color: #00cd00;
+ }
+ .type {
+ /* font-lock-type-face */
+ color: #98fb98;
+ }
+ -->
+ </style></head
+><BODY TEXT="#cecece" BGCOLOR="#4f6f6f" LINK="#f5deb3" VLINK="#d5ae83"
+CLASS="SECT1"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><DIV
+CLASS="NAVHEADER"
+><TABLE
+SUMMARY="Header navigation table"
+WIDTH="100%"
+BORDER="0"
+CELLPADDING="0"
+CELLSPACING="0"
+><TR
+><TH
+COLSPAN="3"
+ALIGN="center"
+>PLEAC-Python
+</TH
+></TR
+><TR
+><TD
+WIDTH="10%"
+ALIGN="left"
+VALIGN="bottom"
+><A
+HREF="userinterfaces.html"
+ACCESSKEY="P"
+>Prev</A
+></TD
+><TD
+WIDTH="80%"
+ALIGN="center"
+VALIGN="bottom"
+></TD
+><TD
+WIDTH="10%"
+ALIGN="right"
+VALIGN="bottom"
+><A
+HREF="sockets.html"
+ACCESSKEY="N"
+>Next</A
+></TD
+></TR
+></TABLE
+><HR
+ALIGN="LEFT"
+WIDTH="100%"></DIV
+><DIV
+CLASS="SECT1"
+><H1
+CLASS="SECT1"
+><A
+NAME="PROCESSMANAGEMENTETC"
+>16. Process Management and Communication</A
+></H1
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN851"
+>Gathering Output from a Program</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="keyword">import</span> popen2
+
+<span class="comment-delimiter"># </span><span class="comment">other popen methods than popen4 can lead to deadlocks
+</span><span class="comment-delimiter"># </span><span class="comment">if there is much data on stdout and stderr
+</span>
+(err_out, stdin) = popen2.popen4(<span class="string">"program args"</span>)
+lines = err_out.read() <span class="comment-delimiter"># </span><span class="comment">collect output into one multiline string
+</span>
+(err_out, stdin) = popen2.popen4(<span class="string">"program args"</span>)
+lines = err_out.readlines() <span class="comment-delimiter"># </span><span class="comment">collect output into a list, one line per element
+</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>
+(err_out, stdin) = popen2.popen4(<span class="string">"program args"</span>)
+output = []
+<span class="keyword">while</span> <span class="py-pseudo-keyword">True</span>:
+ line = err_out.readline()
+ <span class="keyword">if</span> <span class="keyword">not</span> line:
+ <span class="keyword">break</span>
+ output.appen(line)
+output = <span class="string">''</span>.join(output)</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN854"
+>Running Another Program</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="keyword">import</span> os
+myfile = <span class="string">"foo.txt"</span>
+status = os.system(<span class="string">"vi %s"</span> % myfile)
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> os
+os.system(<span class="string">"cmd1 args | cmd2 | cmd3 &gt;outfile"</span>)
+os.system(<span class="string">"cmd args &lt;infile &gt;outfile 2&gt;errfile"</span>)
+
+status = os.system(<span class="string">"%s %s %s"</span> % (program, arg1, arg2))
+<span class="keyword">if</span> status != 0:
+ <span class="keyword">print</span> <span class="string">"%s exited funny: %s"</span> % (program, status)
+ <span class="keyword">raise</span> <span class="py-builtins">SystemExit</span>
+ </PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN857"
+>Replacing the Current Program with a Different One</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> os
+<span class="keyword">import</span> sys
+<span class="keyword">import</span> glob
+
+args = glob.glob(<span class="string">"*.data"</span>)
+<span class="keyword">try:</span>
+ os.execvp(<span class="string">"archive"</span>, args)
+<span class="keyword">except</span> <span class="py-builtins">OSError</span>, e:
+ <span class="keyword">print</span> <span class="string">"Couldn't replace myself with archive: %s"</span> % err
+ <span class="keyword">raise</span> <span class="py-builtins">SystemExit</span>
+
+<span class="comment-delimiter"># </span><span class="comment">The error message does not contain the line number like the "die" in
+</span><span class="comment-delimiter"># </span><span class="comment">perl. But if you want to show more information for debugging, you can
+</span><span class="comment-delimiter"># </span><span class="comment">delete the try...except and you get a nice traceback which shows all
+</span><span class="comment-delimiter"># </span><span class="comment">line numbers and filenames.
+</span>
+<span class="comment-delimiter"># </span><span class="comment">-----------------------------
+</span>os.execvp(<span class="string">"archive"</span>, [<span class="string">"accounting.data"</span>])</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN860"
+>Reading or Writing to Another Program</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">-------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Read from a child process
+</span>
+<span class="keyword">import</span> sys
+<span class="keyword">import</span> popen2
+pipe = popen2.Popen4(<span class="string">"program arguments"</span>)
+pid = pipe.pid
+<span class="keyword">for</span> line <span class="keyword">in</span> pipe.fromchild.readlines():
+ sys.stdout.write(line)
+
+<span class="comment-delimiter"># </span><span class="comment">Popen4 provides stdout and stderr.
+</span><span class="comment-delimiter"># </span><span class="comment">This avoids deadlocks if you get data
+</span><span class="comment-delimiter"># </span><span class="comment">from both streams.
+</span><span class="comment-delimiter">#</span><span class="comment">
+</span><span class="comment-delimiter"># </span><span class="comment">If you don't need the pid, you
+</span><span class="comment-delimiter"># </span><span class="comment">can use popen2.popen4(...)
+</span>
+<span class="comment-delimiter"># </span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Write to a child process
+</span>
+<span class="keyword">import</span> popen2
+
+pipe = popen2.Popen4(<span class="string">"gzip &gt; foo.gz"</span>)
+pid = pipe.pid
+pipe.tochild.write(<span class="string">"Hello zipped world!\n"</span>)
+pipe.tochild.close() <span class="comment-delimiter"># </span><span class="comment">programm will get EOF on STDIN
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN863"
+>Filtering Your Own Output</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="keyword">class</span> <span class="type">OutputFilter</span>(object):
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>, target, *args, **kwds):
+ <span class="py-pseudo-keyword">self</span>.target = target
+ <span class="py-pseudo-keyword">self</span>.setup(*args, **kwds)
+ <span class="py-pseudo-keyword">self</span>.textbuffer = <span class="string">""</span>
+
+ <span class="keyword">def</span> <span class="function-name">setup</span>(<span class="py-pseudo-keyword">self</span>, *args, **kwds):
+ <span class="keyword">pass</span>
+
+ <span class="keyword">def</span> <span class="function-name">write</span>(<span class="py-pseudo-keyword">self</span>, data):
+ <span class="keyword">if</span> data.endswith(<span class="string">"\n"</span>):
+ data = <span class="py-pseudo-keyword">self</span>.process(<span class="py-pseudo-keyword">self</span>.textbuffer + data)
+ <span class="py-pseudo-keyword">self</span>.textbuffer = <span class="string">""</span>
+ <span class="keyword">if</span> data <span class="keyword">is</span> <span class="keyword">not</span> <span class="py-pseudo-keyword">None</span>:
+ <span class="py-pseudo-keyword">self</span>.target.write(data)
+ <span class="keyword">else:</span>
+ <span class="py-pseudo-keyword">self</span>.textbuffer += data
+
+ <span class="keyword">def</span> <span class="function-name">process</span>(<span class="py-pseudo-keyword">self</span>, data):
+ <span class="keyword">return</span> data
+
+<span class="keyword">class</span> <span class="type">HeadFilter</span>(OutputFilter):
+ <span class="keyword">def</span> <span class="function-name">setup</span>(<span class="py-pseudo-keyword">self</span>, maxcount):
+ <span class="py-pseudo-keyword">self</span>.count = 0
+ <span class="py-pseudo-keyword">self</span>.maxcount = maxcount
+
+ <span class="keyword">def</span> <span class="function-name">process</span>(<span class="py-pseudo-keyword">self</span>, data):
+ <span class="keyword">if</span> <span class="py-pseudo-keyword">self</span>.count &lt; <span class="py-pseudo-keyword">self</span>.maxcount:
+ <span class="py-pseudo-keyword">self</span>.count += 1
+ <span class="keyword">return</span> data
+
+<span class="keyword">class</span> <span class="type">NumberFilter</span>(OutputFilter):
+ <span class="keyword">def</span> <span class="function-name">setup</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="py-pseudo-keyword">self</span>.count=0
+
+ <span class="keyword">def</span> <span class="function-name">process</span>(<span class="py-pseudo-keyword">self</span>, data):
+ <span class="py-pseudo-keyword">self</span>.count += 1
+ <span class="keyword">return</span> <span class="string">"%s: %s"</span>%(<span class="py-pseudo-keyword">self</span>.count, data)
+
+<span class="keyword">class</span> <span class="type">QuoteFilter</span>(OutputFilter):
+ <span class="keyword">def</span> <span class="function-name">process</span>(<span class="py-pseudo-keyword">self</span>, data):
+ <span class="keyword">return</span> <span class="string">"&gt; "</span> + data
+
+<span class="keyword">import</span> sys
+f = HeadFilter(sys.stdout, 100)
+<span class="keyword">for</span> i <span class="keyword">in</span> <span class="py-builtins">range</span>(130):
+ print&gt;&gt;f, i
+
+<span class="keyword">print</span>
+
+txt = <span class="string">"""Welcome to Linux, version 2.0.33 on a i686
+
+"</span>The software required `Windows 95 <span class="keyword">or</span> better<span class="string">',
+so I installed Linux." """
+f1 = NumberFilter(sys.stdout)
+f2 = QuoteFilter(f1)
+for line in txt.split("\n"):
+ print&gt;&gt;f2, line
+print
+f1 = QuoteFilter(sys.stdout)
+f2 = NumberFilter(f1)
+for line in txt.split("\n"):
+ print&gt;&gt;f2, line</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN866"
+>Preprocessing Input</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"># This script accepts several filenames
+# as argument. If the file is zipped, unzip
+# it first. Then read each line if the file
+import os
+import sys
+import popen2
+
+for file in sys.argv[1:]:
+ if file.endswith(".gz") or file.endswith(".Z"):
+ (stdout, stdin) = popen2.popen2("gzip -dc '</span>%s<span class="string">'" % file)
+ fd = stdout
+ else:
+ fd = open(file)
+ for line in fd:
+ # ....
+ sys.stdout.write(line)
+ fd.close()
+#-----------------------------
+
+#-----------------------------
+# Ask for filename and open it
+import sys
+print "File, please?"
+line = sys.stdin.readline()
+file = line.strip() # chomp
+open(file)</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN869"
+>Reading STDERR from a Program</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"># Execute foo_command and read the output
+
+import popen2
+(stdout_err, stdin) = popen2.popen4("foo_command")
+for line in stdout_err.readlines():
+ # ....</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN872"
+>Controlling Input and Output of Another Program</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"># Open command in a pipe
+# which reads from stdin and writes to stdout
+
+import popen2
+pipe = popen2.Popen4("wc -l") # Unix command
+pipe.tochild.write("line 1\nline 2\nline 3\n")
+pipe.tochild.close()
+output = pipe.fromchild.read()</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN875"
+>Controlling the Input, Output, and Error of Another Program</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1">
+# popen3: get stdout and stderr of new process
+# Attetion: This can lead to deadlock,
+# since the buffer of stderr or stdout might get filled.
+# You need to use select if you want to avoid this.
+
+import popen2
+(child_stdout, child_stdin, child_stderr) = popen2.popen3(...)</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN878"
+>Communicating Between Related Processes</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"># @@INCOMPLETE@@
+# @@INCOMPLETE@@</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN881"
+>Making a Process Look Like a File with Named Pipes</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"># @@INCOMPLETE@@
+# @@INCOMPLETE@@</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN884"
+>Sharing Variables in Different Processes</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"># @@INCOMPLETE@@
+# @@INCOMPLETE@@</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN887"
+>Listing Available Signals</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1">#
+# Print available signals and their value
+# See "man signal" "man kill" on unix.
+
+import signal
+for name in dir(signal):
+ if name.startswith("SIG"):
+ value = getattr(signal, name)
+ print "%s=%s" % (name, value)</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN890"
+>Sending a Signal</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"># You can send signals to processes
+# with os.kill(pid, signal)</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN893"
+>Installing a Signal Handler</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1">import signal
+
+def get_sig_quit(signum, frame):
+ ....
+
+signal.signal(signal.SIGQUIT, get_sig_quit) # Install handler
+
+signal.signal(signal.SIGINT, signal.SIG_IGN) # Ignore this signal
+signal.signal(signal.SIGSTOP, signal.SIG_DFL) # Restore to default handling</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN896"
+>Temporarily Overriding a Signal Handler</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"># Example of handler: User must Enter Name ctrl-c does not help
+
+import sys
+import signal
+
+def ding(signum, frame):
+ print "\aEnter your name!"
+ return
+
+signal.signal(signal.SIGINT, ding)
+print "Please enter your name:"
+
+name = ""
+while not name:
+ try:
+ name = sys.stdin.readline().strip()
+ except:
+ pass
+
+print "Hello: %s" % name</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN899"
+>Writing a Signal Handler</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"># @@INCOMPLETE@@
+# @@INCOMPLETE@@</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN902"
+>Catching Ctrl-C</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1">import signal
+
+# ignore signal INT
+signal.signal(signal.SIGINT, signal.SIG_IGN)
+
+# Install signal handler
+def tsktsk(signum, frame):
+ print "..."
+
+signal.signal(signal.SIGINT, tsktsk)</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN905"
+>Avoiding Zombie Processes</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"># @@INCOMPLETE@@
+# @@INCOMPLETE@@</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN908"
+>Blocking Signals</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"># @@INCOMPLETE@@
+# @@INCOMPLETE@@</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN911"
+>Timing Out an Operation</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1">import signal
+
+def handler(signum, frame):
+ raise "timeout"
+
+signal.signal(signal.SIGALRM, handler)
+
+try:
+ signal.alarm(5) # signal.alarm(3600)
+
+ # long-time operation
+ while True:
+ print "foo"
+
+ signal.alarm(0)
+except:
+ signal.alarm(0)
+ print "timed out"
+else:
+ print "no time out"</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN914"
+>Program: sigrand</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"># @@INCOMPLETE@@
+# @@INCOMPLETE@@</PRE
+></TD
+></TR
+></TABLE
+></DIV
+></DIV
+><DIV
+CLASS="NAVFOOTER"
+><HR
+ALIGN="LEFT"
+WIDTH="100%"><TABLE
+SUMMARY="Footer navigation table"
+WIDTH="100%"
+BORDER="0"
+CELLPADDING="0"
+CELLSPACING="0"
+><TR
+><TD
+WIDTH="33%"
+ALIGN="left"
+VALIGN="top"
+><A
+HREF="userinterfaces.html"
+ACCESSKEY="P"
+>Prev</A
+></TD
+><TD
+WIDTH="34%"
+ALIGN="center"
+VALIGN="top"
+><A
+HREF="index.html"
+ACCESSKEY="H"
+>Home</A
+></TD
+><TD
+WIDTH="33%"
+ALIGN="right"
+VALIGN="top"
+><A
+HREF="sockets.html"
+ACCESSKEY="N"
+>Next</A
+></TD
+></TR
+><TR
+><TD
+WIDTH="33%"
+ALIGN="left"
+VALIGN="top"
+>User Interfaces</TD
+><TD
+WIDTH="34%"
+ALIGN="center"
+VALIGN="top"
+>&nbsp;</TD
+><TD
+WIDTH="33%"
+ALIGN="right"
+VALIGN="top"
+>Sockets</TD
+></TR
+></TABLE
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/help/PythonExamples/pleac_python/referencesandrecords.html b/help/PythonExamples/pleac_python/referencesandrecords.html
new file mode 100644
index 0000000..e478e1e
--- /dev/null
+++ b/help/PythonExamples/pleac_python/referencesandrecords.html
@@ -0,0 +1,1019 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML
+><HEAD
+><TITLE
+>References and Records</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
+REL="HOME"
+TITLE="PLEAC-Python
+"
+HREF="index.html"><LINK
+REL="PREVIOUS"
+TITLE="Subroutines"
+HREF="subroutines.html"><LINK
+REL="NEXT"
+TITLE="Packages, Libraries, and Modules"
+HREF="packagesetc.html"><style type="text/css"> <!--
+ .comment {
+ /* font-lock-comment-face */
+ color: #bebebe;
+ }
+ .comment-delimiter {
+ }
+ .function-name {
+ /* font-lock-function-name-face */
+ color: #b2dfee;
+ }
+ .keyword {
+ /* font-lock-keyword-face */
+ color: #ffa500;
+ }
+ .py-builtins {
+ /* py-builtins-face */
+ color: #ffa500;
+ }
+ .py-pseudo-keyword {
+ /* py-pseudo-keyword-face */
+ color: #ffa500;
+ }
+ .string {
+ /* font-lock-string-face */
+ color: #00cd00;
+ }
+ .type {
+ /* font-lock-type-face */
+ color: #98fb98;
+ }
+ -->
+ </style></head
+><BODY TEXT="#cecece" BGCOLOR="#4f6f6f" LINK="#f5deb3" VLINK="#d5ae83"
+CLASS="SECT1"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><DIV
+CLASS="NAVHEADER"
+><TABLE
+SUMMARY="Header navigation table"
+WIDTH="100%"
+BORDER="0"
+CELLPADDING="0"
+CELLSPACING="0"
+><TR
+><TH
+COLSPAN="3"
+ALIGN="center"
+>PLEAC-Python
+</TH
+></TR
+><TR
+><TD
+WIDTH="10%"
+ALIGN="left"
+VALIGN="bottom"
+><A
+HREF="subroutines.html"
+ACCESSKEY="P"
+>Prev</A
+></TD
+><TD
+WIDTH="80%"
+ALIGN="center"
+VALIGN="bottom"
+></TD
+><TD
+WIDTH="10%"
+ALIGN="right"
+VALIGN="bottom"
+><A
+HREF="packagesetc.html"
+ACCESSKEY="N"
+>Next</A
+></TD
+></TR
+></TABLE
+><HR
+ALIGN="LEFT"
+WIDTH="100%"></DIV
+><DIV
+CLASS="SECT1"
+><H1
+CLASS="SECT1"
+><A
+NAME="REFERENCESANDRECORDS"
+>11. References and Records</A
+></H1
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN592"
+>Introduction</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">Introduction.
+</span><span class="comment-delimiter"># </span><span class="comment">In Python, all names are references.
+</span><span class="comment-delimiter"># </span><span class="comment">All objects are inherently anonymous, they don't know what names refer to them.
+</span><span class="keyword">print</span> ref <span class="comment-delimiter"># </span><span class="comment">prints the value that the name ref refers to.
+</span>ref = 3 <span class="comment-delimiter"># </span><span class="comment">assigns the name ref to the value 3.
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>aref = mylist
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>aref = [3, 4, 5] <span class="comment-delimiter"># </span><span class="comment">aref is a name for this list
+</span>href = {<span class="string">"How"</span>: <span class="string">"Now"</span>, <span class="string">"Brown"</span>: <span class="string">"Cow"</span>} <span class="comment-delimiter"># </span><span class="comment">href is a name for this dictionary
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Python doesn't have autovivification as (for simple types) there is no difference between a name and a reference.
+</span><span class="comment-delimiter"># </span><span class="comment">If we try the equivalent of the Perl code we get the list, not a reference to the list.
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">To handle multidimensional arrays, you should use an extension to Python,
+</span><span class="comment-delimiter"># </span><span class="comment">such as numarray (http://www.stsci.edu/resources/software_hardware/numarray)
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">In Python, assignment doesn't return anything.
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>Nat = { <span class="string">"Name"</span>: <span class="string">"Leonhard Euler"</span>,
+ <span class="string">"Address"</span>: <span class="string">"1729 Ramanujan Lane\nMathworld, PI 31416"</span>,
+ <span class="string">"Birthday"</span>: 0x5bb5580
+}
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN595"
+>Taking References to Arrays</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span>aref = mylist
+anon_list = [1, 3, 5, 7, 9]
+anon_copy = anon_list
+implicit_creation = [2, 4, 6, 8, 10]
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>anon_list.append(11)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>two = implicit_creation[0]
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">To get the last index of a list, you can use len()
+</span><span class="comment-delimiter"># </span><span class="comment">[or list.__len__() - but don't] directly
+</span>last_idx = <span class="py-builtins">len</span>(aref) - 1
+
+<span class="comment-delimiter"># </span><span class="comment">Normally, though, you'd use an index of -1 for the last
+</span><span class="comment-delimiter"># </span><span class="comment">element, -2 for the second last, etc.
+</span><span class="keyword">print</span> implicit_creation[-1]
+<span class="comment-delimiter">#</span><span class="comment">=&gt; 10
+</span>
+num_items = <span class="py-builtins">len</span>(aref)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>last_idx = aref.__len__() - 1
+num_items = aref.__len__()
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">if</span> <span class="keyword">not</span> <span class="py-builtins">isinstance</span>(someVar, <span class="py-builtins">type</span>([])):
+ <span class="keyword">print</span> <span class="string">"Expected a list"</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">print</span> list_ref
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">sort is in place.
+</span>list_ref.sort()
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>list_ref.append(item)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">def</span> <span class="function-name">list_ref</span>():
+ <span class="keyword">return</span> []
+
+aref1 = list_ref()
+aref2 = list_ref()
+<span class="comment-delimiter"># </span><span class="comment">aref1 and aref2 point to different lists.
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>list_ref[N] <span class="comment-delimiter"># </span><span class="comment">refers to the Nth item in the list_ref list.
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">The following two statements are equivalent and return up to 3 elements
+</span><span class="comment-delimiter"># </span><span class="comment">at indices 3, 4, and 5 (if they exist).
+</span>pie[3:6]
+pie[3:6:1]
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">This will insert 3 elements, overwriting elements at indices 3,4, or 5 - if they exist.
+</span>pie[3:6] = [<span class="string">"blackberry"</span>, <span class="string">"blueberry"</span>, <span class="string">"pumpkin"</span>]
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">for</span> item <span class="keyword">in</span> pie:
+ <span class="keyword">print</span> item
+
+<span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS (this type of indexing should be done with enumerate)
+</span><span class="comment-delimiter"># </span><span class="comment">xrange does not create a list 0..len(pie) - 1, it creates an object
+</span><span class="comment-delimiter"># </span><span class="comment">that returns one index at a time.
+</span><span class="keyword">for</span> idx <span class="keyword">in</span> <span class="py-builtins">xrange</span>(len(pie)):
+ <span class="keyword">print</span> pie[idx]</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN598"
+>Making Hashes of Arrays</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">Making Hashes of Arrays
+</span>
+hash[<span class="string">"KEYNAME"</span>].append(<span class="string">"new value"</span>)
+
+<span class="keyword">for</span> mystr <span class="keyword">in</span> hash.keys():
+ <span class="keyword">print</span> <span class="string">"%s: %s"</span> % (mystr, hash[mystr])
+
+hash[<span class="string">"a key"</span>] = [3, 4, 5]
+
+values = hash[<span class="string">"a key"</span>]
+
+hash[<span class="string">"a key"</span>].append(value)
+
+<span class="comment-delimiter"># </span><span class="comment">autovivification also does not work in python.
+</span>residents = phone2name[number]
+<span class="comment-delimiter"># </span><span class="comment">do this instead
+</span>residents = phone2name.get(number, [])</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN601"
+>Taking References to Hashes</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">Taking References to Hashes
+</span>
+href = <span class="py-builtins">hash</span>
+anon_hash = { <span class="string">"key1"</span>:<span class="string">"value1"</span>, <span class="string">"key2"</span> : <span class="string">"value2 ..."</span> }
+anon_hash_copy = anon_hash.copy()
+
+<span class="py-builtins">hash</span> = href
+value = href[key]
+<span class="py-builtins">slice</span> = [href[k] <span class="keyword">for</span> k <span class="keyword">in</span> (key1, key2, key3)]
+keys = hash.keys()
+
+<span class="keyword">import</span> types
+<span class="keyword">if</span> <span class="py-builtins">type</span>(someref) != types.DictType:
+ <span class="keyword">raise</span> <span class="string">"Expected a dictionary, not %s"</span> % <span class="py-builtins">type</span>(someref)
+<span class="keyword">if</span> <span class="py-builtins">isinstance</span>(someref,dict):
+ <span class="keyword">raise</span> <span class="string">"Expected a dictionary, not %s"</span> % <span class="py-builtins">type</span>(someref)
+
+<span class="keyword">for</span> href <span class="keyword">in</span> ( ENV, INC ):
+ <span class="keyword">for</span> key <span class="keyword">in</span> href.keys():
+ <span class="keyword">print</span> <span class="string">"%s =&gt; %s"</span> % (key, href[key])
+
+values = [hash_ref[k] <span class="keyword">for</span> k <span class="keyword">in</span> (key1, key2, key3)]
+
+<span class="keyword">for</span> key <span class="keyword">in</span> (<span class="string">"key1"</span>, <span class="string">"key2"</span>, <span class="string">"key3"</span>):
+ hash_ref[k] += 7 <span class="comment-delimiter"># </span><span class="comment">not like in perl but the same result.
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN604"
+>Taking References to Functions</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>cref = func
+cref = <span class="keyword">lambda</span> a, b: ...
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>returned = cref(arguments)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>funcname = <span class="string">"thefunc"</span>
+<span class="py-builtins">locals</span>()[funcname]();
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>commands = {
+ <span class="string">'happy'</span>: joy,
+ <span class="string">'sad'</span>: sullen,
+ <span class="string">'done'</span>: (<span class="keyword">lambda</span> : sys.exit()), <span class="comment-delimiter"># </span><span class="comment">In this case "done: sys.exit" would suffice
+</span> <span class="string">'mad'</span>: angry,
+ }
+
+<span class="keyword">print</span> <span class="string">"How are you?"</span>,
+cmd = <span class="py-builtins">raw_input</span>()
+<span class="keyword">if</span> cmd <span class="keyword">in</span> commands:
+ commands[cmd]()
+<span class="keyword">else:</span>
+ <span class="keyword">print</span> <span class="string">"No such command: %s"</span> % cmd
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">def</span> <span class="function-name">counter_maker</span>():
+ start = [0]
+ <span class="keyword">def</span> <span class="function-name">counter_function</span>():
+ <span class="comment-delimiter"># </span><span class="comment">start refers to the variable defined in counter_maker, but
+</span> <span class="comment-delimiter"># </span><span class="comment">we can't reassign or increment variables in parent scopes.
+</span> <span class="comment-delimiter"># </span><span class="comment">By using a one-element list we can modify the list without
+</span> <span class="comment-delimiter"># </span><span class="comment">reassigning the variable. This way of using a list is very
+</span> <span class="comment-delimiter"># </span><span class="comment">like a reference.
+</span> start[0] += 1
+ <span class="keyword">return</span> start[0]-1
+ <span class="keyword">return</span> counter_function
+
+counter = counter_maker()
+<span class="keyword">for</span> i <span class="keyword">in</span> <span class="py-builtins">range</span>(5):
+ <span class="keyword">print</span> counter()
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>counter1 = counter_maker()
+counter2 = counter_maker()
+
+<span class="keyword">for</span> i <span class="keyword">in</span> <span class="py-builtins">range</span>(5):
+ <span class="keyword">print</span> counter1()
+<span class="keyword">print</span> counter1(), counter2()
+<span class="comment-delimiter">#</span><span class="comment">=&gt; 0
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt; 1
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt; 2
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt; 3
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt; 4
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt; 5 0
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> time
+<span class="keyword">def</span> <span class="function-name">timestamp</span>():
+ start_time = time.time()
+ <span class="keyword">def</span> <span class="function-name">elapsed</span>():
+ <span class="keyword">return</span> time.time() - start_time
+ <span class="keyword">return</span> elapsed
+early = timestamp()
+time.sleep(20)
+later = timestamp()
+time.sleep(10)
+<span class="keyword">print</span> <span class="string">"It's been %d seconds since early"</span> % early()
+<span class="keyword">print</span> <span class="string">"It's been %d seconds since later"</span> % later()
+<span class="comment-delimiter">#</span><span class="comment">=&gt; It's been 30 seconds since early.
+</span><span class="comment-delimiter">#</span><span class="comment">=&gt; It's been 10 seconds since later.
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN607"
+>Taking References to Scalars</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">A name is a reference to an object and an object can be referred to
+</span><span class="comment-delimiter"># </span><span class="comment">by any number of names. There is no way to manipulate pointers or
+</span><span class="comment-delimiter"># </span><span class="comment">an object's id. This section is thus inapplicable.
+</span>x = 1
+y = x
+<span class="keyword">print</span> x, <span class="py-builtins">id</span>(x), y, <span class="py-builtins">id</span>(y)
+x += 1 <span class="comment-delimiter"># </span><span class="comment">"x" now refers to a different object than y
+</span><span class="keyword">print</span> x, <span class="py-builtins">id</span>(x), y, <span class="py-builtins">id</span>(y)
+y = 4 <span class="comment-delimiter"># </span><span class="comment">"y" now refers to a different object than it did before
+</span><span class="keyword">print</span> x, <span class="py-builtins">id</span>(x), y, <span class="py-builtins">id</span>(y)
+
+<span class="comment-delimiter"># </span><span class="comment">Some objects (including ints and strings) are immutable, however, which
+</span><span class="comment-delimiter"># </span><span class="comment">can give the illusion of a by-value/by-reference distinction:
+</span>a = x = [1]
+b = y = 1
+c = z = <span class="string">"s"</span>
+<span class="keyword">print</span> a, b, c
+<span class="comment-delimiter">#</span><span class="comment">=&gt; [1] 1 s
+</span>
+x += x <span class="comment-delimiter"># </span><span class="comment">calls list.__iadd__ which is inplace.
+</span>y += y <span class="comment-delimiter"># </span><span class="comment">can't find int.__iadd__ so calls int.__add__ which isn't inplace
+</span>z += z <span class="comment-delimiter"># </span><span class="comment">can't find str.__iadd__ so calls str.__add__ which isn't inplace
+</span><span class="keyword">print</span> a, b, c
+<span class="comment-delimiter">#</span><span class="comment">=&gt; [1, 1] 1 s
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN610"
+>Creating Arrays of Scalar References</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">As indicated by the previous section, everything is referenced, so
+</span><span class="comment-delimiter"># </span><span class="comment">just create a list as normal, and beware that augmented assignment
+</span><span class="comment-delimiter"># </span><span class="comment">works differently with immutable objects to mutable ones:
+</span>mylist = [1, <span class="string">"s"</span>, [1]]
+<span class="keyword">print</span> mylist
+<span class="comment-delimiter">#</span><span class="comment">=&gt; [1, s, [1]]
+</span>
+<span class="keyword">for</span> elem <span class="keyword">in</span> mylist:
+ elem *= 2
+<span class="keyword">print</span> mylist
+<span class="comment-delimiter">#</span><span class="comment">=&gt; [1, s, [1, 1]]
+</span>
+mylist[0] *= 2
+mylist[-1] *= 2
+<span class="keyword">print</span> mylist
+<span class="comment-delimiter">#</span><span class="comment">=&gt; [1, s, [1, 1, 1, 1]]
+</span>
+<span class="comment-delimiter"># </span><span class="comment">If you need to modify every value in a list, you should use a list comprehension
+</span><span class="comment-delimiter"># </span><span class="comment">which does NOT modify inplace:
+</span><span class="keyword">import</span> math
+mylist = [(val**3 * 4/3*math.pi) <span class="keyword">for</span> val <span class="keyword">in</span> mylist]</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN613"
+>Using Closures Instead of Objects</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>c1 = mkcounter(20)
+c2 = mkcounter(77)
+
+<span class="keyword">print</span> <span class="string">"next c1: %d"</span> % c1[<span class="string">'next'</span>]() <span class="comment-delimiter"># </span><span class="comment">21
+</span><span class="keyword">print</span> <span class="string">"next c2: %d"</span> % c2[<span class="string">'next'</span>]() <span class="comment-delimiter"># </span><span class="comment">78
+</span><span class="keyword">print</span> <span class="string">"next c1: %d"</span> % c1[<span class="string">'next'</span>]() <span class="comment-delimiter"># </span><span class="comment">22
+</span><span class="keyword">print</span> <span class="string">"last c1: %d"</span> % c1[<span class="string">'prev'</span>]() <span class="comment-delimiter"># </span><span class="comment">21
+</span><span class="keyword">print</span> <span class="string">"old c2: %d"</span> % c2[<span class="string">'reset'</span>]() <span class="comment-delimiter"># </span><span class="comment">77
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS. Use an object instead
+</span><span class="keyword">def</span> <span class="function-name">mkcounter</span>(start):
+ count = [start]
+ <span class="keyword">def</span> <span class="function-name">next</span>():
+ count[0] += 1
+ <span class="keyword">return</span> count[0]
+ <span class="keyword">def</span> <span class="function-name">prev</span>():
+ count[0] -= 1
+ <span class="keyword">return</span> count[0]
+ <span class="keyword">def</span> <span class="function-name">get</span>():
+ <span class="keyword">return</span> count[0]
+ <span class="keyword">def</span> <span class="function-name">set</span>(value):
+ count[0] = value
+ <span class="keyword">return</span> count[0]
+ <span class="keyword">def</span> <span class="function-name">bump</span>(incr):
+ count[0] += incr
+ <span class="keyword">return</span> count[0]
+ <span class="keyword">def</span> <span class="function-name">reset</span>():
+ count[0] = start
+ <span class="keyword">return</span> count[0]
+ <span class="keyword">return</span> {
+ <span class="string">'next'</span>: next, <span class="string">'prev'</span>: prev, <span class="string">'get'</span>: get, <span class="string">'set'</span>: set,
+ <span class="string">'bump'</span>: bump, <span class="string">'reset'</span>: reset, <span class="string">'last'</span>: prev}
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN616"
+>Creating References to Methods</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>mref = obj.meth
+<span class="comment-delimiter"># </span><span class="comment">later...
+</span>mref(<span class="string">"args"</span>, <span class="string">"go"</span>, <span class="string">"here"</span>)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN619"
+>Constructing Records</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>record = {
+ <span class="string">"name"</span>: <span class="string">"Jason"</span>,
+ <span class="string">"empno"</span>: 132,
+ <span class="string">"title"</span>: <span class="string">"deputy peon"</span>,
+ <span class="string">"age"</span>: 23,
+ <span class="string">"salary"</span>: 37000,
+ <span class="string">"pals"</span>: [<span class="string">"Norbert"</span>, <span class="string">"Rhys"</span>, <span class="string">"Phineas"</span>],
+}
+<span class="keyword">print</span> <span class="string">"I am %s, and my pals are %s."</span> % (record[<span class="string">"name"</span>],
+ <span class="string">", "</span>.join(record[<span class="string">"pals"</span>]))
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>byname = {}
+byname[record[<span class="string">"name"</span>]] = record
+
+rp = byname.get(<span class="string">"Aron"</span>)
+<span class="keyword">if</span> rp:
+ <span class="keyword">print</span> <span class="string">"Aron is employee %d."</span>% rp[<span class="string">"empno"</span>]
+
+byname[<span class="string">"Jason"</span>][<span class="string">"pals"</span>].append(<span class="string">"Theodore"</span>)
+<span class="keyword">print</span> <span class="string">"Jason now has %d pals."</span> % <span class="py-builtins">len</span>(byname[<span class="string">"Jason"</span>][<span class="string">"pals"</span>])
+
+<span class="keyword">for</span> name, record <span class="keyword">in</span> byname.items():
+ <span class="keyword">print</span> <span class="string">"%s is employee number %d."</span> % (name, record[<span class="string">"empno"</span>])
+
+employees = {}
+employees[record[<span class="string">"empno"</span>]] = record;
+
+<span class="comment-delimiter"># </span><span class="comment">lookup by id
+</span>rp = employees.get(132)
+<span class="keyword">if</span> (rp):
+ <span class="keyword">print</span> <span class="string">"Employee number 132 is %s."</span> % rp[<span class="string">"name"</span>]
+
+byname[<span class="string">"Jason"</span>][<span class="string">"salary"</span>] *= 1.035
+
+peons = [r <span class="keyword">for</span> r <span class="keyword">in</span> employees.values() <span class="keyword">if</span> r[<span class="string">"title"</span>] == <span class="string">"peon"</span>]
+tsevens = [r <span class="keyword">for</span> r <span class="keyword">in</span> employees.values() <span class="keyword">if</span> r[<span class="string">"age"</span>] == 27]
+
+<span class="comment-delimiter"># </span><span class="comment">Go through all records
+</span><span class="keyword">print</span> employees.values()
+
+<span class="keyword">for</span> rp <span class="keyword">in</span> sorted(employees.values(), key=<span class="keyword">lambda</span> x:x[<span class="string">"age"</span>]):
+ <span class="keyword">print</span> <span class="string">"%s is age %d."</span>%(rp[<span class="string">"name"</span>], rp[<span class="string">"age"</span>])
+
+<span class="comment-delimiter"># </span><span class="comment">use @byage, an array of arrays of records
+</span>byage = {}
+byage[record[<span class="string">"age"</span>]] = byage.get(record[<span class="string">"age"</span>], []) + [record]
+
+<span class="keyword">for</span> age, records <span class="keyword">in</span> byage.items():
+ <span class="keyword">print</span> records
+ <span class="keyword">print</span> <span class="string">"Age %s:"</span>%age,
+ <span class="keyword">for</span> rp <span class="keyword">in</span> records:
+ <span class="keyword">print</span> rp[<span class="string">"name"</span>],
+ <span class="keyword">print</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN622"
+>Reading and Writing Hash Records to Text Files</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>FieldName: Value
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">for</span> record <span class="keyword">in</span> list_of_records:
+ <span class="comment-delimiter"># </span><span class="comment">Note: sorted added in Python 2.4
+</span> <span class="keyword">for</span> key <span class="keyword">in</span> sorted(record.keys()):
+ <span class="keyword">print</span> <span class="string">"%s: %s"</span> % (key, record[key])
+ <span class="keyword">print</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> re
+list_of_records = [{}]
+<span class="keyword">while</span> <span class="py-pseudo-keyword">True</span>:
+ line = sys.stdin.readline()
+ <span class="keyword">if</span> <span class="keyword">not</span> line:
+ <span class="comment-delimiter"># </span><span class="comment">EOF
+</span> <span class="keyword">break</span>
+ <span class="comment-delimiter"># </span><span class="comment">Remove trailing \n:
+</span> line = line[:1]
+ <span class="keyword">if</span> <span class="keyword">not</span> line.strip():
+ <span class="comment-delimiter"># </span><span class="comment">New record
+</span> list_of_records.append({})
+ <span class="keyword">continue</span>
+ key, value = re.split(r<span class="string">':\s*'</span>, line, 1)
+ <span class="comment-delimiter"># </span><span class="comment">Assign the key/value to the last item in the list_of_records:
+</span> list_of_records[-1][key] = value
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN625"
+>Printing Data Structures</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"></span><span class="comment-delimiter"></span><span class="comment"></span><span class="keyword">import</span> pprint
+
+mylist = [[1,2,3], [4, [5,6,7], 8,9, [0,3,5]], 7, 8]
+mydict = {<span class="string">"abc"</span>: <span class="string">"def"</span>, <span class="string">"ghi"</span>:[1,2,3]}
+pprint.pprint(mylist, width=1)
+
+fmtdict = pprint.pformat(mydict, width=1)
+<span class="keyword">print</span> fmtdict
+<span class="comment-delimiter"># </span><span class="comment">"import pprint; help(pprint)" for more details
+</span>
+<span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span><span class="comment-delimiter"># </span><span class="comment">Note that pprint does not currently handle user objects
+</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN628"
+>Copying Data Structures</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"></span><span class="comment-delimiter"></span><span class="comment"></span>newlist = <span class="py-builtins">list</span>(mylist) <span class="comment-delimiter"># </span><span class="comment">shallow copy
+</span>newdict = <span class="py-builtins">dict</span>(mydict) <span class="comment-delimiter"># </span><span class="comment">shallow copy
+</span>
+<span class="comment-delimiter"># </span><span class="comment">Pre 2.3:
+</span><span class="keyword">import</span> copy
+newlist = copy.copy(mylist) <span class="comment-delimiter"># </span><span class="comment">shallow copy
+</span>newdict = copy.copy(mydict) <span class="comment-delimiter"># </span><span class="comment">shallow copy
+</span>
+<span class="comment-delimiter"># </span><span class="comment">shallow copies copy a data structure, but don't copy the items in those
+</span><span class="comment-delimiter"># </span><span class="comment">data structures so if there are nested data structures, both copy and
+</span><span class="comment-delimiter"># </span><span class="comment">original will refer to the same object
+</span>mylist = [<span class="string">"1"</span>, <span class="string">"2"</span>, <span class="string">"3"</span>]
+newlist = <span class="py-builtins">list</span>(mylist)
+mylist[0] = <span class="string">"0"</span>
+<span class="keyword">print</span> mylist, newlist
+<span class="comment-delimiter">#</span><span class="comment">=&gt; ['0', '2', '3'] ['1', '2', '3']
+</span>
+mylist = [[<span class="string">"1"</span>, <span class="string">"2"</span>, <span class="string">"3"</span>], 4]
+newlist = <span class="py-builtins">list</span>(mylist)
+mylist[0][0] = <span class="string">"0"</span>
+<span class="keyword">print</span> mylist, newlist
+<span class="comment-delimiter">#</span><span class="comment">=&gt; [['0', '2', '3'], 4] [['0', '2', '3'], 4]
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> copy
+newlist = copy.deepcopy(mylist) <span class="comment-delimiter"># </span><span class="comment">deep copy
+</span>newdict = copy.deepcopy(mydict) <span class="comment-delimiter"># </span><span class="comment">deep copy
+</span>
+<span class="comment-delimiter"># </span><span class="comment">deep copies copy a data structure recursively:
+</span><span class="keyword">import</span> copy
+
+mylist = [[<span class="string">"1"</span>, <span class="string">"2"</span>, <span class="string">"3"</span>], 4]
+newlist = copy.deepcopy(mylist)
+mylist[0][0] = <span class="string">"0"</span>
+<span class="keyword">print</span> mylist, newlist
+<span class="comment-delimiter">#</span><span class="comment">=&gt; [['0', '2', '3'], 4] [['1', '2', '3'], 4]
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN631"
+>Storing Data Structures to Disk</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"></span><span class="comment-delimiter"></span><span class="comment"></span><span class="keyword">import</span> pickle
+<span class="keyword">class</span> <span class="type">Foo</span>(object):
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="py-pseudo-keyword">self</span>.val = 1
+
+x = Foo()
+x.val = 3
+p_x = pickle.dumps(x) <span class="comment-delimiter"># </span><span class="comment">Also pickle.dump(x, myfile) which writes to myfile
+</span><span class="keyword">del</span> x
+x = pickle.loads(p_x) <span class="comment-delimiter"># </span><span class="comment">Also x = pickle.load(myfile) which loads from myfile
+</span><span class="keyword">print</span> x.val
+<span class="comment-delimiter">#</span><span class="comment">=&gt; 3
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN634"
+>Transparently Persistent Data Structures</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"></span><span class="comment-delimiter"></span><span class="comment"></span><span class="keyword">import</span> os, shelve
+fname = <span class="string">"testfile.db"</span>
+<span class="keyword">if</span> <span class="keyword">not</span> os.path.exists(fname):
+ d = shelve.open(<span class="string">"testfile.db"</span>)
+ <span class="keyword">for</span> i <span class="keyword">in</span> <span class="py-builtins">range</span>(100000):
+ d[<span class="py-builtins">str</span>(i)] = i
+ d.close()
+
+d = shelve.open(<span class="string">"testfile.db"</span>)
+<span class="keyword">print</span> d[<span class="string">"100"</span>]
+<span class="keyword">print</span> d[<span class="string">"1212010201"</span>] <span class="comment-delimiter"># </span><span class="comment">KeyError
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN637"
+>Program: Binary Trees</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">bintree - binary tree demo program
+</span><span class="comment-delimiter"># </span><span class="comment">Use the heapq module instead?
+</span><span class="keyword">import</span> random
+<span class="keyword">import</span> warnings
+
+<span class="keyword">class</span> <span class="type">BTree</span>(object):
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="py-pseudo-keyword">self</span>.value = <span class="py-pseudo-keyword">None</span>
+
+ <span class="comment-delimiter">#</span><span class="comment">## insert given value into proper point of
+</span> <span class="comment-delimiter">#</span><span class="comment">## the tree, extending this node if necessary.
+</span> <span class="keyword">def</span> <span class="function-name">insert</span>(<span class="py-pseudo-keyword">self</span>, value):
+ <span class="keyword">if</span> <span class="py-pseudo-keyword">self</span>.value <span class="keyword">is</span> <span class="py-pseudo-keyword">None</span>:
+ <span class="py-pseudo-keyword">self</span>.left = BTree()
+ <span class="py-pseudo-keyword">self</span>.right = BTree()
+ <span class="py-pseudo-keyword">self</span>.value = value
+ <span class="keyword">elif</span> <span class="py-pseudo-keyword">self</span>.value &gt; value:
+ <span class="py-pseudo-keyword">self</span>.left.insert(value)
+ <span class="keyword">elif</span> <span class="py-pseudo-keyword">self</span>.value &lt; value:
+ <span class="py-pseudo-keyword">self</span>.right.insert(value)
+ <span class="keyword">else:</span>
+ warnings.warn(<span class="string">"Duplicate insertion of %s."</span>%value)
+
+ <span class="comment-delimiter"># </span><span class="comment">recurse on left child,
+</span> <span class="comment-delimiter"># </span><span class="comment">then show current value,
+</span> <span class="comment-delimiter"># </span><span class="comment">then recurse on right child.
+</span> <span class="keyword">def</span> <span class="function-name">in_order</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="keyword">if</span> <span class="py-pseudo-keyword">self</span>.value <span class="keyword">is</span> <span class="keyword">not</span> <span class="py-pseudo-keyword">None</span>:
+ <span class="py-pseudo-keyword">self</span>.left.in_order()
+ <span class="keyword">print</span> <span class="py-pseudo-keyword">self</span>.value,
+ <span class="py-pseudo-keyword">self</span>.right.in_order()
+
+ <span class="comment-delimiter"># </span><span class="comment">show current value,
+</span> <span class="comment-delimiter"># </span><span class="comment">then recurse on left child,
+</span> <span class="comment-delimiter"># </span><span class="comment">then recurse on right child.
+</span> <span class="keyword">def</span> <span class="function-name">pre_order</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="keyword">if</span> <span class="py-pseudo-keyword">self</span>.value <span class="keyword">is</span> <span class="keyword">not</span> <span class="py-pseudo-keyword">None</span>:
+ <span class="keyword">print</span> <span class="py-pseudo-keyword">self</span>.value,
+ <span class="py-pseudo-keyword">self</span>.left.pre_order()
+ <span class="py-pseudo-keyword">self</span>.right.pre_order()
+
+ <span class="comment-delimiter"># </span><span class="comment">recurse on left child,
+</span> <span class="comment-delimiter"># </span><span class="comment">then recurse on right child,
+</span> <span class="comment-delimiter"># </span><span class="comment">then show current value.
+</span> <span class="keyword">def</span> <span class="function-name">post_order</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="keyword">if</span> <span class="py-pseudo-keyword">self</span>.value <span class="keyword">is</span> <span class="keyword">not</span> <span class="py-pseudo-keyword">None</span>:
+ <span class="py-pseudo-keyword">self</span>.left.post_order()
+ <span class="py-pseudo-keyword">self</span>.right.post_order()
+ <span class="keyword">print</span> <span class="py-pseudo-keyword">self</span>.value,
+
+ <span class="comment-delimiter"># </span><span class="comment">find out whether provided value is in the tree.
+</span> <span class="comment-delimiter"># </span><span class="comment">if so, return the node at which the value was found.
+</span> <span class="comment-delimiter"># </span><span class="comment">cut down search time by only looking in the correct
+</span> <span class="comment-delimiter"># </span><span class="comment">branch, based on current value.
+</span> <span class="keyword">def</span> <span class="function-name">search</span>(<span class="py-pseudo-keyword">self</span>, value):
+ <span class="keyword">if</span> <span class="py-pseudo-keyword">self</span>.value <span class="keyword">is</span> <span class="keyword">not</span> <span class="py-pseudo-keyword">None</span>:
+ <span class="keyword">if</span> <span class="py-pseudo-keyword">self</span>.value == value:
+ <span class="keyword">return</span> <span class="py-pseudo-keyword">self</span>
+ <span class="keyword">if</span> value &lt; <span class="py-pseudo-keyword">self</span>.value:
+ <span class="keyword">return</span> <span class="py-pseudo-keyword">self</span>.left.search(value)
+ <span class="keyword">else:</span>
+ <span class="keyword">return</span> <span class="py-pseudo-keyword">self</span>.right.search(value)
+
+<span class="keyword">def</span> <span class="function-name">test</span>():
+ root = BTree()
+
+ <span class="keyword">for</span> i <span class="keyword">in</span> <span class="py-builtins">range</span>(20):
+ root.insert(random.randint(1, 1000))
+
+ <span class="comment-delimiter"># </span><span class="comment">now dump out the tree all three ways
+</span> <span class="keyword">print</span> <span class="string">"Pre order: "</span>, root.pre_order()
+ <span class="keyword">print</span> <span class="string">"In order: "</span>, root.in_order()
+ <span class="keyword">print</span> <span class="string">"Post order:"</span>, root.post_order()
+
+ <span class="comment-delimiter">#</span><span class="comment">## prompt until empty line
+</span> <span class="keyword">while</span> <span class="py-pseudo-keyword">True</span>:
+ val = <span class="py-builtins">raw_input</span>(<span class="string">"Search? "</span>).strip()
+ <span class="keyword">if</span> <span class="keyword">not</span> val:
+ <span class="keyword">break</span>
+ val = <span class="py-builtins">int</span>(val)
+ found = root.search(val)
+ <span class="keyword">if</span> found:
+ <span class="keyword">print</span> <span class="string">"Found %s at %s, %s"</span>%(val, found, found.value)
+ <span class="keyword">else:</span>
+ <span class="keyword">print</span> <span class="string">"No %s in tree"</span> % val
+
+<span class="keyword">if</span> <span class="py-builtins">__name__</span> == <span class="string">"__main__"</span>:
+ test()</PRE
+></TD
+></TR
+></TABLE
+></DIV
+></DIV
+><DIV
+CLASS="NAVFOOTER"
+><HR
+ALIGN="LEFT"
+WIDTH="100%"><TABLE
+SUMMARY="Footer navigation table"
+WIDTH="100%"
+BORDER="0"
+CELLPADDING="0"
+CELLSPACING="0"
+><TR
+><TD
+WIDTH="33%"
+ALIGN="left"
+VALIGN="top"
+><A
+HREF="subroutines.html"
+ACCESSKEY="P"
+>Prev</A
+></TD
+><TD
+WIDTH="34%"
+ALIGN="center"
+VALIGN="top"
+><A
+HREF="index.html"
+ACCESSKEY="H"
+>Home</A
+></TD
+><TD
+WIDTH="33%"
+ALIGN="right"
+VALIGN="top"
+><A
+HREF="packagesetc.html"
+ACCESSKEY="N"
+>Next</A
+></TD
+></TR
+><TR
+><TD
+WIDTH="33%"
+ALIGN="left"
+VALIGN="top"
+>Subroutines</TD
+><TD
+WIDTH="34%"
+ALIGN="center"
+VALIGN="top"
+>&nbsp;</TD
+><TD
+WIDTH="33%"
+ALIGN="right"
+VALIGN="top"
+>Packages, Libraries, and Modules</TD
+></TR
+></TABLE
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/help/PythonExamples/pleac_python/sockets.html b/help/PythonExamples/pleac_python/sockets.html
new file mode 100644
index 0000000..5984f7a
--- /dev/null
+++ b/help/PythonExamples/pleac_python/sockets.html
@@ -0,0 +1,917 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML
+><HEAD
+><TITLE
+>Sockets</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
+REL="HOME"
+TITLE="PLEAC-Python
+"
+HREF="index.html"><LINK
+REL="PREVIOUS"
+TITLE="Process Management and Communication"
+HREF="processmanagementetc.html"><LINK
+REL="NEXT"
+TITLE="Internet Services"
+HREF="internetservices.html"><style type="text/css"> <!--
+ .comment {
+ /* font-lock-comment-face */
+ color: #bebebe;
+ }
+ .comment-delimiter {
+ }
+ .function-name {
+ /* font-lock-function-name-face */
+ color: #b2dfee;
+ }
+ .keyword {
+ /* font-lock-keyword-face */
+ color: #ffa500;
+ }
+ .py-builtins {
+ /* py-builtins-face */
+ color: #ffa500;
+ }
+ .py-pseudo-keyword {
+ /* py-pseudo-keyword-face */
+ color: #ffa500;
+ }
+ .string {
+ /* font-lock-string-face */
+ color: #00cd00;
+ }
+ .type {
+ /* font-lock-type-face */
+ color: #98fb98;
+ }
+ -->
+ </style></head
+><BODY TEXT="#cecece" BGCOLOR="#4f6f6f" LINK="#f5deb3" VLINK="#d5ae83"
+CLASS="SECT1"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><DIV
+CLASS="NAVHEADER"
+><TABLE
+SUMMARY="Header navigation table"
+WIDTH="100%"
+BORDER="0"
+CELLPADDING="0"
+CELLSPACING="0"
+><TR
+><TH
+COLSPAN="3"
+ALIGN="center"
+>PLEAC-Python
+</TH
+></TR
+><TR
+><TD
+WIDTH="10%"
+ALIGN="left"
+VALIGN="bottom"
+><A
+HREF="processmanagementetc.html"
+ACCESSKEY="P"
+>Prev</A
+></TD
+><TD
+WIDTH="80%"
+ALIGN="center"
+VALIGN="bottom"
+></TD
+><TD
+WIDTH="10%"
+ALIGN="right"
+VALIGN="bottom"
+><A
+HREF="internetservices.html"
+ACCESSKEY="N"
+>Next</A
+></TD
+></TR
+></TABLE
+><HR
+ALIGN="LEFT"
+WIDTH="100%"></DIV
+><DIV
+CLASS="SECT1"
+><H1
+CLASS="SECT1"
+><A
+NAME="SOCKETS"
+>17. Sockets</A
+></H1
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN919"
+>Introduction</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"># Socket Programming (tcp/ip and udp/ip)
+
+import socket
+
+# Convert human readable form to 32 bit value
+packed_ip = socket.inet_aton("208.146.240.1")
+packed_ip = socket.inet_aton("www.oreilly.com")
+
+# Convert 32 bit value to ip adress
+ip_adress = socket.inet_ntoa(packed_ip)
+
+# Create socket object
+socketobj = socket(family, type) # Example socket.AF_INT, socket.SOCK_STREAM
+
+# Get socketname
+socketobj.getsockname() # Example, get port adress of client</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN922"
+>Writing a TCP Client</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1">
+# Example: Connect to a server (tcp)
+# Connect to a smtp server at localhost and send an email.
+# For real applications you should use smtplib.
+
+import socket
+s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+s.connect(("localhost", 25)) # SMTP
+print s.recv(1024)
+s.send("mail from: &lt;<a href="mailto:pleac&#64;localhost">pleac&#64;localhost</a>&gt;\n")
+print s.recv(1024)
+s.send("rcpt to: &lt;<a href="mailto:guettli&#64;localhost">guettli&#64;localhost</a>&gt;\n")
+print s.recv(1024)
+s.send("data\n")
+print s.recv(1024)
+s.send("From: Python Lover\nSubject: Python is better then perl\n\nYES!\n.\n")
+print s.recv(1024)
+s.close()</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN925"
+>Writing a TCP Server</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1">
+# Create a Server, calling handler for every client
+# You can test it with "telnet localhost 1029"
+
+from SocketServer import TCPServer
+from SocketServer import BaseRequestHandler
+
+class MyHandler(BaseRequestHandler):
+ def handle(self):
+ print "I got an request"
+
+server = TCPServer(("127.0.0.1", 1029), MyHandler)
+server.serve_forever()</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN928"
+>Communicating over TCP</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"># This is the continuation of 17.2
+
+import time
+from SocketServer import TCPServer
+from SocketServer import BaseRequestHandler
+
+class MyHandler(BaseRequestHandler):
+ def handle(self):
+ # self.request is the socket object
+ print "%s I got an request from ip=%s port=%s" % (
+ time.strftime("%Y-%m-%d %H:%M:%S"),
+ self.client_address[0],
+ self.client_address[1]
+ )
+ self.request.send("What is your name?\n")
+ bufsize=1024
+ response=self.request.recv(bufsize).strip() # or recv(bufsize, flags)
+ data_to_send="Welcome %s!\n" % response
+ self.request.send(data_to_send) # or send(data, flags)
+ print "%s connection finnished" % self.client_address[0]
+
+server = TCPServer(("127.0.0.1", 1028), MyHandler)
+server.serve_forever()
+
+# -----------------
+# Using select
+
+import select
+import socket
+
+in_list = []
+in_list.append(mysocket)
+in_list.append(myfile)
+# ...
+
+out_list = []
+out_list.append(...)
+
+except_list = []
+except_list.append(...)
+
+(in_, out_, exc_) = select.select(in_list, out_list, except_list, timeout)
+
+for fd in in_:
+ print "Can read", fd
+for fd in out_:
+ print "Can write", fd
+for fd in exc_:
+ print "Exception on", fd
+
+# Missing: setting TCP_NODELAY</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN931"
+>Setting Up a UDP Client</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1">
+import socket
+# Set up a UDP socket
+s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+# send
+MSG = '</span>Hello<span class="string">'
+HOSTNAME = '</span>127.0.0.1<span class="string">'
+PORTNO = 10000
+s.connect((HOSTNAME, PORTNO))
+if len(MSG) != s.send(MSG):
+ # where to get error message "$!".
+ print "cannot send to %s(%d):" % (HOSTNAME,PORTNO)
+ raise SystemExit(1)
+MAXLEN = 1024
+(data,addr) = s.recvfrom(MAXLEN)
+s.close()
+print '</span>%s(%d) said <span class="string">"%s"' % (addr[0],addr[1], data)
+
+# <font size="-1"><a href="http://pleac.sourceforge.net/include/python/ch17/clockdrift">download the following standalone program</a></font>
+#!/usr/bin/python
+# clockdrift - compare another system'</span>s clock with this one
+
+<span class="keyword">import</span> socket
+<span class="keyword">import</span> struct
+<span class="keyword">import</span> sys
+<span class="keyword">import</span> time
+
+<span class="keyword">if</span> <span class="py-builtins">len</span>(sys.argv)&gt;1:
+ him = sys.argv[1]
+<span class="keyword">else:</span>
+ him = <span class="string">'127.1'</span>
+
+SECS_of_70_YEARS = 2208988800
+
+s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+s.connect((him,socket.getservbyname(<span class="string">'time'</span>,<span class="string">'udp'</span>)))
+s.send(<span class="string">''</span>)
+(ptime, src) = s.recvfrom(4)
+host = socket.gethostbyaddr(src[0])
+delta = struct.unpack(<span class="string">"!L"</span>, ptime)[0] - SECS_of_70_YEARS - time.time()
+<span class="keyword">print</span> <span class="string">"Clock on %s is %d seconds ahead of this one."</span> % (host[0], delta)</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN934"
+>Setting Up a UDP Server</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span>
+<span class="keyword">import</span> socket
+<span class="keyword">import</span> sys
+
+s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+<span class="keyword">try:</span>
+ s.bind((<span class="string">''</span>, server_port))
+<span class="keyword">except</span> socket.error, err:
+ <span class="keyword">print</span> <span class="string">"Couldn't be a udp server on port %d : %s"</span> % (
+ server_port, err)
+ <span class="keyword">raise</span> <span class="py-builtins">SystemExit</span>
+
+<span class="keyword">while</span> <span class="py-pseudo-keyword">True</span>:
+ datagram = s.recv(MAX_TO_READ)
+ <span class="keyword">if</span> <span class="keyword">not</span> datagram:
+ <span class="keyword">break</span>
+ <span class="comment-delimiter"># </span><span class="comment">do something
+</span>s.close()
+
+<span class="comment-delimiter"># </span><span class="comment">or
+</span><span class="keyword">import</span> SocketServer
+
+<span class="keyword">class</span> <span class="type">handler</span>(SocketServer.DatagramRequestHandler):
+ <span class="keyword">def</span> <span class="function-name">handle</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="comment-delimiter"># </span><span class="comment">do something (with self.request[0])
+</span>
+s = SocketServer.UDPServer((<span class="string">''</span>,10000), handler)
+s.serve_forever()
+
+<span class="comment-delimiter"># </span><span class="comment"><font size="-1"><a href="http://pleac.sourceforge.net/include/python/ch17/udpqotd">download the following standalone program</a></font>
+</span><span class="comment-delimiter">#</span><span class="comment">!/usr/bin/python
+</span><span class="comment-delimiter"># </span><span class="comment">udpqotd - UDP message server
+</span>
+<span class="keyword">import</span> SocketServer
+
+PORTNO = 5151
+
+<span class="keyword">class</span> <span class="type">handler</span>(SocketServer.DatagramRequestHandler):
+ <span class="keyword">def</span> <span class="function-name">handle</span>(<span class="py-pseudo-keyword">self</span>):
+ newmsg = <span class="py-pseudo-keyword">self</span>.rfile.readline().rstrip()
+ <span class="keyword">print</span> <span class="string">"Client %s said ``%s''"</span> % (<span class="py-pseudo-keyword">self</span>.client_address[0], newmsg)
+ <span class="py-pseudo-keyword">self</span>.wfile.write(<span class="py-pseudo-keyword">self</span>.server.oldmsg)
+ <span class="py-pseudo-keyword">self</span>.server.oldmsg = newmsg
+
+s = SocketServer.UDPServer((<span class="string">''</span>,PORTNO), handler)
+<span class="keyword">print</span> <span class="string">"Awaiting UDP messages on port %d"</span> % PORTNO
+s.oldmsg = <span class="string">"This is the starting message."</span>
+s.serve_forever()
+
+
+<span class="comment-delimiter"># </span><span class="comment"><font size="-1"><a href="http://pleac.sourceforge.net/include/python/ch17/udpmsg">download the following standalone program</a></font>
+</span><span class="comment-delimiter">#</span><span class="comment">!/usr/bin/python
+</span><span class="comment-delimiter"># </span><span class="comment">udpmsg - send a message to the udpquotd server
+</span>
+<span class="keyword">import</span> socket
+<span class="keyword">import</span> sys
+
+MAXLEN = 1024
+PORTNO = 5151
+TIMEOUT = 5
+
+server_host = sys.argv[1]
+msg = <span class="string">" "</span>.join(sys.argv[2:])
+
+sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+sock.settimeout(TIMEOUT)
+sock.connect((server_host, PORTNO))
+sock.send(msg)
+<span class="keyword">try:</span>
+ msg = sock.recv(MAXLEN)
+ ipaddr, port = sock.getpeername()
+ hishost = socket.gethostbyaddr(ipaddr)
+ <span class="keyword">print</span> <span class="string">"Server %s responded ``%s''"</span> % ( hishost[0], msg)
+<span class="keyword">except:</span>
+ <span class="keyword">print</span> <span class="string">"recv from %s failed (timeout or no server running)."</span> % (
+ server_host )
+sock.close()</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN937"
+>Using UNIX Domain Sockets</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span>
+<span class="keyword">import</span> socket
+<span class="keyword">import</span> os, os.path
+
+<span class="keyword">if</span> os.path.exists(<span class="string">"/tmp/mysock"</span>):
+ os.remove(<span class="string">"/tmp/mysock"</span>)
+
+server = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
+server.bind(<span class="string">"/tmp/mysock"</span>)
+
+client = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
+client.connect(<span class="string">"/tmp/mysock"</span>)
+ </PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN940"
+>Identifying the Other End of a Socket</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span>
+ipaddr, port = s.getpeername()
+hostname, aliaslist, ipaddrlist = socket.gethostbyaddr(ipaddr)
+ipaddr = socket.gethostbyname(<span class="string">'www.python.org'</span>)
+<span class="comment-delimiter"># </span><span class="comment">'194.109.137.226'
+</span>hostname, aliaslist, ipaddrlist = socket.gethostbyname_ex(<span class="string">'www.python.org'</span>)
+<span class="comment-delimiter"># </span><span class="comment">('fang.python.org', ['www.python.org'], ['194.109.137.226'])
+</span>socket.gethostbyname_ex(<span class="string">'www.google.org'</span>)
+<span class="comment-delimiter"># </span><span class="comment">('www.l.google.com', ['www.google.org', 'www.google.com'],
+</span><span class="comment-delimiter"># </span><span class="comment">['64.233.161.147','64.233.161.104', '64.233.161.99'])
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN943"
+>Finding Your Own Name and Address</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span>
+<span class="keyword">import</span> os
+
+kernel, hostname, release, version, hardware = os.uname()
+
+<span class="keyword">import</span> socket
+
+address = socket.gethostbyname(hostname)
+hostname = socket.gethostbyaddr(address)
+hostname, aliaslist, ipaddrlist = socket.gethostbyname_ex(hostname)
+<span class="comment-delimiter"># </span><span class="comment">e.g. ('lx3.local', ['lx3', 'b70'], ['192.168.0.13', '192.168.0.70'])
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN946"
+>Closing a Socket After Forking</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span>
+socket.shutdown(0) <span class="comment-delimiter"># </span><span class="comment">Further receives are disallowed
+</span>socket.shutdown(1) <span class="comment-delimiter"># </span><span class="comment">Further sends are disallowed.
+</span>socket.shutdown(2) <span class="comment-delimiter"># </span><span class="comment">Further sends and receives are disallowed.
+</span>
+<span class="comment-delimiter">#</span><span class="comment">
+</span>
+server.send(<span class="string">"my request\n"</span>) <span class="comment-delimiter"># </span><span class="comment">send some data
+</span>server.shutdown(1) <span class="comment-delimiter"># </span><span class="comment">send eof; no more writing
+</span>answer = server.recv(1000) <span class="comment-delimiter"># </span><span class="comment">but you can still read
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN949"
+>Writing Bidirectional Clients</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN952"
+>Forking Servers</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN955"
+>Pre-Forking Servers</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN958"
+>Non-Forking Servers</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN961"
+>Writing a Multi-Homed Server</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN964"
+>Making a Daemon Server</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN967"
+>Restarting a Server on Demand</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">------------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Restart programm on signal SIGHUP
+</span><span class="comment-delimiter"># </span><span class="comment">Script must be executable: chmod a+x foo.py
+</span>
+<span class="comment-delimiter">#</span><span class="comment">!/usr/bin/env python
+</span><span class="keyword">import</span> os
+<span class="keyword">import</span> sys
+<span class="keyword">import</span> time
+<span class="keyword">import</span> signal
+
+<span class="keyword">def</span> <span class="function-name">phoenix</span>(signum, frame):
+ <span class="keyword">print</span> <span class="string">"Restarting myself: %s %s"</span> % (<span class="py-pseudo-keyword">self</span>, args)
+ os.execv(<span class="py-pseudo-keyword">self</span>, args)
+
+<span class="py-pseudo-keyword">self</span> = os.path.abspath(sys.argv[0])
+args = sys.argv[:]
+signal.signal(signal.SIGHUP, phoenix)
+
+<span class="keyword">while</span> <span class="py-pseudo-keyword">True</span>:
+ <span class="keyword">print</span> <span class="string">"work"</span>
+ time.sleep(1)
+
+<span class="comment-delimiter">#</span><span class="comment">--------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Read config file on SIGHUP
+</span><span class="keyword">import</span> signal
+
+config_file = <span class="string">"/usr/local/etc/myprog/server_conf.py"</span>
+
+<span class="keyword">def</span> <span class="function-name">read_config</span>():
+ <span class="py-builtins">execfile</span>(config_file)
+
+signal.signal(signal.SIGHUP, read_config)</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN970"
+>Program: backsniff</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span>
+<span class="comment-delimiter"># </span><span class="comment">chroot
+</span>
+<span class="keyword">import</span> os
+
+<span class="keyword">try:</span>
+ os.chroot(<span class="string">"/var/daemon"</span>)
+<span class="keyword">except</span> <span class="py-builtins">Exception</span>:
+ <span class="keyword">print</span> <span class="string">"Could not chroot"</span>
+ <span class="keyword">raise</span> <span class="py-builtins">SystemExit</span>(1)
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">fork (Unix): Create a new process
+</span><span class="comment-delimiter"># </span><span class="comment">if pid == 0 --&gt; parent process
+</span><span class="comment-delimiter"># </span><span class="comment">else child process
+</span>
+<span class="keyword">import</span> os
+
+pid = os.fork()
+<span class="keyword">if</span> pid:
+ <span class="keyword">print</span> <span class="string">"I am the new child %s"</span> % pid
+ <span class="keyword">raise</span> <span class="py-builtins">SystemExit</span>
+<span class="keyword">else:</span>
+ <span class="keyword">print</span> <span class="string">"I am still the parent"</span>
+
+
+<span class="comment-delimiter"># </span><span class="comment">----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">setsid (Unix): Create a new session
+</span><span class="keyword">import</span> os
+id=os.setsid()
+
+<span class="comment-delimiter"># </span><span class="comment">----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Work until INT TERM or HUP signal is received
+</span><span class="keyword">import</span> time
+<span class="keyword">import</span> signal
+
+time_to_die = 0
+
+<span class="keyword">def</span> <span class="function-name">sighandler</span>(signum, frame):
+ <span class="keyword">print</span> <span class="string">"time to die"</span>
+ <span class="keyword">global</span> time_to_die
+ time_to_die = 1
+
+signal.signal(signal.SIGINT, sighandler)
+signal.signal(signal.SIGTERM, sighandler)
+signal.signal(signal.SIGHUP, sighandler)
+
+<span class="keyword">while</span> <span class="keyword">not</span> time_to_die:
+ <span class="keyword">print</span> <span class="string">"work"</span>
+ time.sleep(1)</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN973"
+>Program: fwdport</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+></DIV
+><DIV
+CLASS="NAVFOOTER"
+><HR
+ALIGN="LEFT"
+WIDTH="100%"><TABLE
+SUMMARY="Footer navigation table"
+WIDTH="100%"
+BORDER="0"
+CELLPADDING="0"
+CELLSPACING="0"
+><TR
+><TD
+WIDTH="33%"
+ALIGN="left"
+VALIGN="top"
+><A
+HREF="processmanagementetc.html"
+ACCESSKEY="P"
+>Prev</A
+></TD
+><TD
+WIDTH="34%"
+ALIGN="center"
+VALIGN="top"
+><A
+HREF="index.html"
+ACCESSKEY="H"
+>Home</A
+></TD
+><TD
+WIDTH="33%"
+ALIGN="right"
+VALIGN="top"
+><A
+HREF="internetservices.html"
+ACCESSKEY="N"
+>Next</A
+></TD
+></TR
+><TR
+><TD
+WIDTH="33%"
+ALIGN="left"
+VALIGN="top"
+>Process Management and Communication</TD
+><TD
+WIDTH="34%"
+ALIGN="center"
+VALIGN="top"
+>&nbsp;</TD
+><TD
+WIDTH="33%"
+ALIGN="right"
+VALIGN="top"
+>Internet Services</TD
+></TR
+></TABLE
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/help/PythonExamples/pleac_python/strings.html b/help/PythonExamples/pleac_python/strings.html
new file mode 100644
index 0000000..1e0fb9b
--- /dev/null
+++ b/help/PythonExamples/pleac_python/strings.html
@@ -0,0 +1,1277 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML
+><HEAD
+><TITLE
+>Strings</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
+REL="HOME"
+TITLE="PLEAC-Python
+"
+HREF="index.html"><LINK
+REL="PREVIOUS"
+TITLE="PLEAC-Python
+"
+HREF="index.html"><LINK
+REL="NEXT"
+TITLE="Numbers"
+HREF="numbers.html"><style type="text/css"> <!--
+ .comment {
+ /* font-lock-comment-face */
+ color: #bebebe;
+ }
+ .comment-delimiter {
+ }
+ .function-name {
+ /* font-lock-function-name-face */
+ color: #b2dfee;
+ }
+ .keyword {
+ /* font-lock-keyword-face */
+ color: #ffa500;
+ }
+ .py-builtins {
+ /* py-builtins-face */
+ color: #ffa500;
+ }
+ .py-pseudo-keyword {
+ /* py-pseudo-keyword-face */
+ color: #ffa500;
+ }
+ .string {
+ /* font-lock-string-face */
+ color: #00cd00;
+ }
+ .type {
+ /* font-lock-type-face */
+ color: #98fb98;
+ }
+ -->
+ </style></head
+><BODY TEXT="#cecece" BGCOLOR="#4f6f6f" LINK="#f5deb3" VLINK="#d5ae83"
+CLASS="SECT1"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><DIV
+CLASS="NAVHEADER"
+><TABLE
+SUMMARY="Header navigation table"
+WIDTH="100%"
+BORDER="0"
+CELLPADDING="0"
+CELLSPACING="0"
+><TR
+><TH
+COLSPAN="3"
+ALIGN="center"
+>PLEAC-Python
+</TH
+></TR
+><TR
+><TD
+WIDTH="10%"
+ALIGN="left"
+VALIGN="bottom"
+><A
+HREF="index.html"
+ACCESSKEY="P"
+>Prev</A
+></TD
+><TD
+WIDTH="80%"
+ALIGN="center"
+VALIGN="bottom"
+></TD
+><TD
+WIDTH="10%"
+ALIGN="right"
+VALIGN="bottom"
+><A
+HREF="numbers.html"
+ACCESSKEY="N"
+>Next</A
+></TD
+></TR
+></TABLE
+><HR
+ALIGN="LEFT"
+WIDTH="100%"></DIV
+><DIV
+CLASS="SECT1"
+><H1
+CLASS="SECT1"
+><A
+NAME="STRINGS"
+>1. Strings</A
+></H1
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN14"
+>Introduction</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>mystr = <span class="string">"\n"</span> <span class="comment-delimiter"># </span><span class="comment">a newline character
+</span>mystr = r<span class="string">"\n"</span> <span class="comment-delimiter"># </span><span class="comment">two characters, \ and n
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>mystr = <span class="string">"Jon 'Maddog' Orwant"</span> <span class="comment-delimiter"># </span><span class="comment">literal single quote inside double quotes
+</span>mystr = <span class="string">'Jon "Maddog" Orwant'</span> <span class="comment-delimiter"># </span><span class="comment">literal double quote inside single quotes
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>mystr = <span class="string">'Jon \'Maddog\' Orwant'</span> <span class="comment-delimiter"># </span><span class="comment">escaped single quote
+</span>mystr = <span class="string">"Jon \"Maddog\" Orwant"</span> <span class="comment-delimiter"># </span><span class="comment">escaped double quote
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>mystr = <span class="string">"""
+This is a multiline string literal
+enclosed in triple double quotes.
+"""</span>
+mystr = <span class="string">'''
+And this is a multiline string literal
+enclosed in triple single quotes.
+'''</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN17"
+>Accessing Substrings</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>
+<span class="comment-delimiter"># </span><span class="comment">get a 5-char string, skip 3, then grab 2 8-char strings, then the rest
+</span><span class="comment-delimiter"># </span><span class="comment">Note that struct.unpack cannot use * for an unknown length.
+</span><span class="comment-delimiter"># </span><span class="comment">See http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/65224
+</span><span class="keyword">import</span> struct
+(lead, s1, s2), tail = struct.unpack(<span class="string">"5s 3x 8s 8s"</span>, data[:24]), data[24:]
+
+<span class="comment-delimiter"># </span><span class="comment">split at five-char boundaries
+</span>fivers = struct.unpack(<span class="string">"5s"</span> * (<span class="py-builtins">len</span>(data)//5), data)
+fivers = <span class="keyword">print</span> [x[i*5:i*5+5] <span class="keyword">for</span> i <span class="keyword">in</span> <span class="py-builtins">range</span>(len(x)/5)]
+
+<span class="comment-delimiter"># </span><span class="comment">chop string into individual characters
+</span>chars = <span class="py-builtins">list</span>(data)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>mystr = <span class="string">"This is what you have"</span>
+<span class="comment-delimiter"># </span><span class="comment">+012345678901234567890 Indexing forwards (left to right)
+</span><span class="comment-delimiter"># </span><span class="comment">109876543210987654321- Indexing backwards (right to left)
+</span><span class="comment-delimiter"># </span><span class="comment">note that 0 means 10 or 20, etc. above
+</span>
+first = mystr[0] <span class="comment-delimiter"># </span><span class="comment">"T"
+</span>start = mystr[5:7] <span class="comment-delimiter"># </span><span class="comment">"is"
+</span>rest = mystr[13:] <span class="comment-delimiter"># </span><span class="comment">"you have"
+</span>last = mystr[-1] <span class="comment-delimiter"># </span><span class="comment">"e"
+</span>end = mystr[-4:] <span class="comment-delimiter"># </span><span class="comment">"have"
+</span>piece = mystr[-8:-5] <span class="comment-delimiter"># </span><span class="comment">"you"
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Python strings are immutable.
+</span><span class="comment-delimiter"># </span><span class="comment">In general, you should just do piecemeal reallocation:
+</span>mystr = <span class="string">"This is what you have"</span>
+mystr = mystr[:5] + <span class="string">"wasn't"</span> + mystr[7:]
+
+<span class="comment-delimiter"># </span><span class="comment">Or replace and reallocate
+</span>mystr = <span class="string">"This is what you have"</span>
+mystr = mystr.replace(<span class="string">" is "</span>, <span class="string">" wasn't "</span>)
+
+<span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS: In-place modification could be done using character arrays
+</span><span class="keyword">import</span> array
+mystr = array.array(<span class="string">"c"</span>, <span class="string">"This is what you have"</span>)
+mystr[5:7] = array.array(<span class="string">"c"</span>, <span class="string">"wasn't"</span>)
+<span class="comment-delimiter"># </span><span class="comment">mystr is now array('c', "This wasn't what you have")
+</span>
+<span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS: It could also be done using MutableString
+</span><span class="keyword">from</span> UserString <span class="keyword">import</span> MutableString
+mystr = MutableString(<span class="string">"This is what you have"</span>)
+mystr[-12:] = <span class="string">"ondrous"</span>
+<span class="comment-delimiter"># </span><span class="comment">mystr is now "This is wondrous"
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">you can test simple substrings with "in" (for regex matching see ch.6):
+</span><span class="keyword">if</span> txt <span class="keyword">in</span> mystr[-10:]:
+ <span class="keyword">print</span> <span class="string">"'%s' found in last 10 characters"</span>%txt
+
+<span class="comment-delimiter"># </span><span class="comment">Or use the startswith() and endswith() string methods:
+</span><span class="keyword">if</span> mystr.startswith(txt):
+ <span class="keyword">print</span> <span class="string">"%s starts with %s."</span>%(mystr, txt)
+<span class="keyword">if</span> mystr.endswith(txt):
+ <span class="keyword">print</span> <span class="string">"%s ends with %s."</span>%(mystr, txt)
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN20"
+>Establishing a Default Value</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Introductory Note: quite a bit of this section is not terribly Pythonic
+</span><span class="comment-delimiter"># </span><span class="comment">as names must be set before being used. For instance, unless myvar has
+</span><span class="comment-delimiter"># </span><span class="comment">been previously defined, these next lines will all raise NameError:
+</span>myvar = myvar <span class="keyword">or</span> some_default
+myvar2 = myvar <span class="keyword">or</span> some_default
+myvar |= some_default <span class="comment-delimiter"># </span><span class="comment">bitwise-or, not logical-or - for demo
+</span>
+<span class="comment-delimiter"># </span><span class="comment">The standard way of setting a default is often:
+</span>myvar = default_value
+<span class="keyword">if</span> some_condition:
+ <span class="keyword">pass</span> <span class="comment-delimiter"># </span><span class="comment">code which may set myvar to something else
+</span>
+<span class="comment-delimiter"># </span><span class="comment">if myvar is returned from a function and may be empty/None, then use:
+</span>myvar = somefunc()
+<span class="keyword">if</span> <span class="keyword">not</span> myvar:
+ myvar = default_value
+
+<span class="comment-delimiter"># </span><span class="comment">If you want a default value that can be overridden by the person calling
+</span><span class="comment-delimiter"># </span><span class="comment">your code, you can often wrap it in a function with a named parameter:
+</span><span class="keyword">def</span> <span class="function-name">myfunc</span>(myvar=<span class="string">"a"</span>):
+ <span class="keyword">return</span> myvar + <span class="string">"b"</span>
+<span class="keyword">print</span> myfunc(), myfunc(<span class="string">"c"</span>)
+<span class="comment-delimiter">#</span><span class="comment">=&gt; ab cb
+</span>
+<span class="comment-delimiter"># </span><span class="comment">Note, though, that this won't work for mutable objects such as lists or
+</span><span class="comment-delimiter"># </span><span class="comment">dicts that are mutated in the function as the object is only created once
+</span><span class="comment-delimiter"># </span><span class="comment">and repeated calls to the same function will return the same object. This
+</span><span class="comment-delimiter"># </span><span class="comment">can be desired behaviour however - see section 10.3, for instance.
+</span><span class="keyword">def</span> <span class="function-name">myfunc</span>(myvar=[]):
+ myvar.append(<span class="string">"x"</span>)
+ <span class="keyword">return</span> myvar
+<span class="keyword">print</span> myfunc(), myfunc()
+<span class="comment-delimiter">#</span><span class="comment">=&gt; ['x'] ['x', 'x']
+</span>
+<span class="comment-delimiter"># </span><span class="comment">You need to do:
+</span><span class="keyword">def</span> <span class="function-name">myfunc</span>(myvar=<span class="py-pseudo-keyword">None</span>):
+ <span class="keyword">if</span> myvar <span class="keyword">is</span> <span class="py-pseudo-keyword">None</span>:
+ myvar = []
+ myvar.append(<span class="string">"x"</span>)
+ <span class="keyword">return</span> myvar
+<span class="keyword">print</span> myfunc(), myfunc()
+<span class="comment-delimiter">#</span><span class="comment">=&gt; ['x'] ['x']
+</span>
+<span class="comment-delimiter">#</span><span class="comment">=== Perl Equivalencies start here
+</span><span class="comment-delimiter"># </span><span class="comment">use b if b is true, otherwise use c
+</span>a = b <span class="keyword">or</span> c
+
+<span class="comment-delimiter"># </span><span class="comment">as that is a little tricksy, the following may be preferred:
+</span><span class="keyword">if</span> b:
+ a = b
+<span class="keyword">else:</span>
+ a = c
+
+<span class="comment-delimiter"># </span><span class="comment">set x to y unless x is already true
+</span><span class="keyword">if</span> <span class="keyword">not</span> x:
+ x = y
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">use b if b is defined, else c
+</span><span class="keyword">try:</span>
+ a = b
+<span class="keyword">except</span> <span class="py-builtins">NameError</span>:
+ a = c
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>foo = bar <span class="keyword">or</span> <span class="string">"DEFAULT VALUE"</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">To get a user (for both UNIX and Windows), use:
+</span><span class="keyword">import</span> getpass
+user = getpass.getuser()
+
+<span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS: find the user name on Unix systems
+</span><span class="keyword">import</span> os
+user = os.environ.get(<span class="string">"USER"</span>)
+<span class="keyword">if</span> user <span class="keyword">is</span> <span class="py-pseudo-keyword">None</span>:
+ user = os.environ.get(<span class="string">"LOGNAME"</span>)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">if</span> <span class="keyword">not</span> starting_point:
+ starting_point = <span class="string">"Greenwich"</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">if</span> <span class="keyword">not</span> a: <span class="comment-delimiter"># </span><span class="comment">copy only if empty
+</span> a = b
+
+<span class="keyword">if</span> b: <span class="comment-delimiter"># </span><span class="comment">assign b if nonempty, else c
+</span> a = b
+<span class="keyword">else:</span>
+ a = c
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN23"
+>Exchanging Values Without Using Temporary Variables</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>v1, v2 = v2, v1
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS:
+</span>temp = a
+a = b
+b = temp
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>a = <span class="string">"alpha"</span>
+b = <span class="string">"omega"</span>
+a, b = b, a <span class="comment-delimiter"># </span><span class="comment">the first shall be last -- and versa vice
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>alpha, beta, production = <span class="string">"January March August"</span>.split()
+alpha, beta, production = beta, production, alpha
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN26"
+>Converting Between ASCII Characters and Values</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>num = <span class="py-builtins">ord</span>(char)
+char = <span class="py-builtins">chr</span>(num)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>char = <span class="string">"%c"</span> % num
+<span class="keyword">print</span> <span class="string">"Number %d is character %c"</span> % (num, num)
+<span class="keyword">print</span> <span class="string">"Number %(n)d is character %(n)c"</span> % {<span class="string">"n"</span>: num}
+<span class="keyword">print</span> <span class="string">"Number %(num)d is character %(num)c"</span> % <span class="py-builtins">locals</span>()
+<span class="comment-delimiter">#</span><span class="comment">=&gt; Number 101 is character e
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>ascii_character_numbers = [<span class="py-builtins">ord</span>(c) <span class="keyword">for</span> c <span class="keyword">in</span> <span class="string">"sample"</span>]
+<span class="keyword">print</span> ascii_character_numbers
+<span class="comment-delimiter">#</span><span class="comment">=&gt; [115, 97, 109, 112, 108, 101]
+</span>
+word = <span class="string">""</span>.join([<span class="py-builtins">chr</span>(n) <span class="keyword">for</span> n <span class="keyword">in</span> ascii_character_numbers])
+word = <span class="string">""</span>.join([<span class="py-builtins">chr</span>(n) <span class="keyword">for</span> n <span class="keyword">in</span> [115, 97, 109, 112, 108, 101]])
+<span class="keyword">print</span> word
+<span class="comment-delimiter">#</span><span class="comment">=&gt; sample
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>hal = <span class="string">"HAL"</span>
+ibm = <span class="string">""</span>.join([<span class="py-builtins">chr</span>(ord(c)+1) <span class="keyword">for</span> c <span class="keyword">in</span> hal]) <span class="comment-delimiter"># </span><span class="comment">add one to each ASCII value
+</span><span class="keyword">print</span> ibm
+<span class="comment-delimiter">#</span><span class="comment">=&gt; IBM
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN29"
+>Processing a String One Character at a Time</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>mylist = <span class="py-builtins">list</span>(mystr)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">for</span> char <span class="keyword">in</span> mystr:
+ <span class="keyword">pass</span> <span class="comment-delimiter"># </span><span class="comment">do something with char
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>mystr = <span class="string">"an apple a day"</span>
+uniq = sorted(set(mystr))
+<span class="keyword">print</span> <span class="string">"unique chars are: '%s'"</span> % <span class="string">""</span>.join(uniq)
+<span class="comment-delimiter">#</span><span class="comment">=&gt; unique chars are: ' adelnpy'
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>ascvals = [<span class="py-builtins">ord</span>(c) <span class="keyword">for</span> c <span class="keyword">in</span> mystr]
+<span class="keyword">print</span> <span class="string">"total is %s for '%s'."</span>%(<span class="py-builtins">sum</span>(ascvals), mystr)
+<span class="comment-delimiter">#</span><span class="comment">=&gt; total is 1248 for 'an apple a day'.
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">sysv checksum
+</span><span class="keyword">def</span> <span class="function-name">checksum</span>(myfile):
+ values = [<span class="py-builtins">ord</span>(c) <span class="keyword">for</span> line <span class="keyword">in</span> myfile <span class="keyword">for</span> c <span class="keyword">in</span> line]
+ <span class="keyword">return</span> <span class="py-builtins">sum</span>(values)%(2**16) - 1
+
+<span class="keyword">import</span> fileinput
+<span class="keyword">print</span> checksum(fileinput.input()) <span class="comment-delimiter"># </span><span class="comment">data from sys.stdin
+</span>
+<span class="comment-delimiter"># </span><span class="comment">Using a function means any iterable can be checksummed:
+</span><span class="keyword">print</span> checksum(<span class="py-builtins">open</span>(<span class="string">"C:/test.txt"</span>) <span class="comment-delimiter"># </span><span class="comment">data from file
+</span><span class="keyword">print</span> checksum(<span class="string">"sometext"</span>) <span class="comment-delimiter"># </span><span class="comment">data from string
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment">!/usr/bin/python
+</span><span class="comment-delimiter"># </span><span class="comment">slowcat - emulate a s l o w line printer
+</span><span class="comment-delimiter"># </span><span class="comment">usage: slowcat [- DELAY] [files ...]
+</span><span class="keyword">import</span> sys, select
+<span class="keyword">import</span> re
+DELAY = 1
+<span class="keyword">if</span> re.match(<span class="string">"^-\d+$"</span>,sys.argv[1]):
+ DELAY=-<span class="py-builtins">int</span>(sys.argv[1])
+ <span class="keyword">del</span> sys.argv[1]
+<span class="keyword">for</span> ln <span class="keyword">in</span> fileinput.input():
+ <span class="keyword">for</span> c <span class="keyword">in</span> ln:
+ sys.stdout.write(c)
+ sys.stdout.flush()
+ select.select([],[],[], 0.005 * DELAY)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN32"
+>Reversing a String by Word or Character</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">2.3+ only
+</span>revchars = mystr[::-1] <span class="comment-delimiter"># </span><span class="comment">extended slice - step is -1
+</span>revwords = <span class="string">" "</span>.join(mystr.split(<span class="string">" "</span>)[::-1])
+
+<span class="comment-delimiter"># </span><span class="comment">pre 2.3 version:
+</span>mylist = <span class="py-builtins">list</span>(mystr)
+mylist.reverse()
+revbytes = <span class="string">""</span>.join(mylist)
+
+mylist = mystr.split()
+mylist.reverse()
+revwords = <span class="string">' '</span>.join(mylist)
+
+<span class="comment-delimiter"># </span><span class="comment">Alternative version using reversed():
+</span>revchars = <span class="string">""</span>.join(reversed(mystr))
+revwords = <span class="string">" "</span>.join(reversed(mystr.split(<span class="string">" "</span>)))
+
+<span class="comment-delimiter"># </span><span class="comment">reversed() makes an iterator, which means that the reversal
+</span><span class="comment-delimiter"># </span><span class="comment">happens as it is consumed. This means that "print reversed(mystr)" is not
+</span><span class="comment-delimiter"># </span><span class="comment">the same as mystr[::-1]. Standard usage is:
+</span><span class="keyword">for</span> char <span class="keyword">in</span> reversed(mystr):
+ <span class="keyword">pass</span> <span class="comment-delimiter"># </span><span class="comment">... do something
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">2.3+ only
+</span>word = <span class="string">"reviver"</span>
+is_palindrome = (word == word[::-1])
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Generator version
+</span><span class="keyword">def</span> <span class="function-name">get_palindromes</span>(fname):
+ <span class="keyword">for</span> line <span class="keyword">in</span> <span class="py-builtins">open</span>(fname):
+ word = line.rstrip()
+ <span class="keyword">if</span> <span class="py-builtins">len</span>(word) &gt; 5 <span class="keyword">and</span> word == word[::-1]:
+ <span class="keyword">yield</span> word
+long_palindromes = <span class="py-builtins">list</span>(get_palindromes(<span class="string">"/usr/share/dict/words"</span>))
+
+<span class="comment-delimiter"># </span><span class="comment">Simpler old-style version using 2.2 string reversal
+</span><span class="keyword">def</span> <span class="function-name">rev_string</span>(mystr):
+ mylist = <span class="py-builtins">list</span>(mystr)
+ mylist.reverse()
+ <span class="keyword">return</span> <span class="string">""</span>.join(mylist)
+
+long_palindromes=[]
+<span class="keyword">for</span> line <span class="keyword">in</span> <span class="py-builtins">open</span>(<span class="string">"/usr/share/dict/words"</span>):
+ word = line.rstrip()
+ <span class="keyword">if</span> <span class="py-builtins">len</span>(word) &gt; 5 <span class="keyword">and</span> word == rev_string(word):
+ long_palindromes.append(word)
+<span class="keyword">print</span> long_palindromes
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN35"
+>Expanding and Compressing Tabs</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>mystr.expandtabs()
+mystr.expandtabs(4)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN38"
+>Expanding Variables in User Input</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>text = <span class="string">"I am %(rows)s high and %(cols)s long"</span>%{<span class="string">"rows"</span>:24, <span class="string">"cols"</span>:80)
+<span class="keyword">print</span> text
+<span class="comment-delimiter">#</span><span class="comment">=&gt; I am 24 high and 80 long
+</span>
+rows, cols = 24, 80
+text = <span class="string">"I am %(rows)s high and %(cols)s long"</span>%<span class="py-builtins">locals</span>()
+<span class="keyword">print</span> text
+<span class="comment-delimiter">#</span><span class="comment">=&gt; I am 24 high and 80 long
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> re
+<span class="keyword">print</span> re.sub(<span class="string">"\d+"</span>, <span class="keyword">lambda</span> i: <span class="py-builtins">str</span>(2 * <span class="py-builtins">int</span>(i.group(0))), <span class="string">"I am 17 years old"</span>)
+<span class="comment-delimiter">#</span><span class="comment">=&gt; I am 34 years old
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">expand variables in text, but put an error message in
+</span><span class="comment-delimiter"># </span><span class="comment">if the variable isn't defined
+</span><span class="keyword">class</span> <span class="type">SafeDict</span>(dict):
+ <span class="keyword">def</span> <span class="function-name">__getitem__</span>(<span class="py-pseudo-keyword">self</span>, key):
+ <span class="keyword">return</span> <span class="py-pseudo-keyword">self</span>.get(key, <span class="string">"[No Variable: %s]"</span>%key)
+
+hi = <span class="string">"Hello"</span>
+text = <span class="string">"%(hi)s and %(bye)s!"</span>%SafeDict(<span class="py-builtins">locals</span>())
+<span class="keyword">print</span> text
+<span class="comment-delimiter">#</span><span class="comment">=&gt; Hello and [No Variable: bye]!
+</span>
+<span class="comment-delimiter">#</span><span class="comment">If you don't need a particular error message, just use the Template class:
+</span><span class="keyword">from</span> string <span class="keyword">import</span> Template
+x = Template(<span class="string">"$hi and $bye!"</span>)
+hi = <span class="string">"Hello"</span>
+<span class="keyword">print</span> x.safe_substitute(<span class="py-builtins">locals</span>())
+<span class="comment-delimiter">#</span><span class="comment">=&gt; Hello and $bye!
+</span><span class="keyword">print</span> x.substitute(<span class="py-builtins">locals</span>()) <span class="comment-delimiter"># </span><span class="comment">will throw a KeyError
+</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN41"
+>Controlling Case</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>mystr = <span class="string">"bo peep"</span>.upper() <span class="comment-delimiter"># </span><span class="comment">BO PEEP
+</span>mystr = mystr.lower() <span class="comment-delimiter"># </span><span class="comment">bo peep
+</span>mystr = mystr.capitalize() <span class="comment-delimiter"># </span><span class="comment">Bo peep
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>beast = <span class="string">"python"</span>
+caprest = beast.capitalize().swapcase() <span class="comment-delimiter"># </span><span class="comment">pYTHON
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">print</span> <span class="string">"thIS is a loNG liNE"</span>.title()
+<span class="comment-delimiter">#</span><span class="comment">=&gt; This Is A Long Line
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">if</span> a.upper() == b.upper():
+ <span class="keyword">print</span> <span class="string">"a and b are the same"</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> random
+<span class="keyword">def</span> <span class="function-name">randcase_one</span>(letter):
+ <span class="keyword">if</span> random.randint(0,5): <span class="comment-delimiter"># </span><span class="comment">True on 1, 2, 3, 4
+</span> <span class="keyword">return</span> letter.lower()
+ <span class="keyword">else:</span>
+ <span class="keyword">return</span> letter.upper()
+
+<span class="keyword">def</span> <span class="function-name">randcase</span>(myfile):
+ <span class="keyword">for</span> line <span class="keyword">in</span> myfile:
+ <span class="keyword">yield</span> <span class="string">""</span>.join(randcase_one(letter) <span class="keyword">for</span> letter <span class="keyword">in</span> line[:-1])
+
+<span class="keyword">for</span> line <span class="keyword">in</span> randcase(myfile):
+ <span class="keyword">print</span> line
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN44"
+>Interpolating Functions and Expressions Within Strings</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="string">"I have %d guanacos."</span> % (n + 1)
+<span class="keyword">print</span> <span class="string">"I have"</span>, n+1, <span class="string">"guanacos."</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment">Python templates disallow in-string calculations (see PEP 292)
+</span><span class="keyword">from</span> string <span class="keyword">import</span> Template
+
+email_template = Template(<span class="string">"""\
+To: $address
+From: Your Bank
+CC: $cc_number
+Date: $date
+
+Dear $name,
+
+Today you bounced check number $checknum to us.
+Your account is now closed.
+
+Sincerely,
+the management
+"""</span>)
+
+<span class="keyword">import</span> random
+<span class="keyword">import</span> datetime
+
+person = {<span class="string">"address"</span>:<span class="string">"Joe@somewhere.com"</span>,
+ <span class="string">"name"</span>: <span class="string">"Joe"</span>,
+ <span class="string">"cc_number"</span> : 1234567890,
+ <span class="string">"checknum"</span> : 500+random.randint(0,99)}
+
+<span class="keyword">print</span> email_template.substitute(person, date=datetime.date.today())
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN47"
+>Indenting Here Documents</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">indenting here documents
+</span><span class="comment-delimiter">#</span><span class="comment">
+</span><span class="comment-delimiter"># </span><span class="comment">in python multiline strings can be used as here documents
+</span>var = <span class="string">"""
+ your text
+ goes here
+ """</span>
+
+<span class="comment-delimiter"># </span><span class="comment">using regular expressions
+</span><span class="keyword">import</span> re
+re_leading_blanks = re.compile(<span class="string">"^\s+"</span>,re.MULTILINE)
+var1 = re_leading_blanks.sub(<span class="string">""</span>,var)[:-1]
+
+<span class="comment-delimiter"># </span><span class="comment">using string methods
+</span><span class="comment-delimiter"># </span><span class="comment">split into lines, use every line except first and last, left strip and rejoin.
+</span>var2 = <span class="string">"\n"</span>.join([line.lstrip() <span class="keyword">for</span> line <span class="keyword">in</span> var.split(<span class="string">"\n"</span>)[1:-1]])
+
+poem = <span class="string">"""
+ Here's your poem:
+ Now far ahead the Road has gone,
+ And I must follow, if I can,
+ Pursuing it with eager feet,
+ Until it joins some larger way
+ Where many paths and errand meet.
+ And whither then? I cannot say.
+ --Bilbo in /usr/src/perl/pp_ctl.c
+ """</span>
+
+<span class="keyword">import</span> textwrap
+<span class="keyword">print</span> textwrap.dedent(poem)[1:-1]
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span> </PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN50"
+>Reformatting Paragraphs</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">from</span> textwrap <span class="keyword">import</span> wrap
+output = wrap(para,
+ initial_indent=leadtab
+ subsequent_indent=nexttab)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment">!/usr/bin/env python
+</span><span class="comment-delimiter"># </span><span class="comment">wrapdemo - show how textwrap works
+</span>
+txt = <span class="string">"""\
+Folding and splicing is the work of an editor,
+not a mere collection of silicon
+and
+mobile electrons!
+"""</span>
+
+<span class="keyword">from</span> textwrap <span class="keyword">import</span> TextWrapper
+
+wrapper = TextWrapper(width=20,
+ initial_indent=<span class="string">" "</span>*4,
+ subsequent_indent=<span class="string">" "</span>*2)
+
+<span class="keyword">print</span> <span class="string">"0123456789"</span> * 2
+<span class="keyword">print</span> wrapper.fill(txt)
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="string">"""Expected result:
+
+01234567890123456789
+ Folding and
+ splicing is the
+ work of an editor,
+ not a mere
+ collection of
+ silicon and mobile
+ electrons!
+"""</span>
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">merge multiple lines into one, then wrap one long line
+</span>
+<span class="keyword">from</span> textwrap <span class="keyword">import</span> fill
+<span class="keyword">import</span> fileinput
+
+<span class="keyword">print</span> fill(<span class="string">""</span>.join(fileinput.input()))
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Term::ReadKey::GetTerminalSize() isn't in the Perl standard library.
+</span><span class="comment-delimiter"># </span><span class="comment">It isn't in the Python standard library either. Michael Hudson's
+</span><span class="comment-delimiter"># </span><span class="comment">recipe from python-list #530228 is shown here.
+</span><span class="comment-delimiter"># </span><span class="comment">(http://aspn.activestate.com/ASPN/Mail/Message/python-list/530228)
+</span><span class="comment-delimiter"># </span><span class="comment">Be aware that this will work on Unix but not on Windows.
+</span>
+<span class="keyword">from</span> termwrap <span class="keyword">import</span> wrap
+<span class="keyword">import</span> struct, fcntl
+<span class="keyword">def</span> <span class="function-name">getheightwidth</span>():
+ height, width = struct.unpack(
+ <span class="string">"hhhh"</span>, fcntl.ioctl(0, TERMIOS.TIOCGWINSZ ,<span class="string">"\000"</span>*8))[0:2]
+ <span class="keyword">return</span> height, width
+
+<span class="comment-delimiter"># </span><span class="comment">PERL &lt;&gt;, $/, $\ emulation
+</span><span class="keyword">import</span> fileinput
+<span class="keyword">import</span> re
+
+_, width = getheightwidth()
+<span class="keyword">for</span> para <span class="keyword">in</span> re.split(r<span class="string">"\n{2,}"</span>, <span class="string">""</span>.join(fileinput.input())):
+ <span class="keyword">print</span> fill(para, width)</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN53"
+>Escaping Characters</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>mystr = <span class="string">'''Mom said, "Don'</span>t do that.<span class="string">"''' #"</span>
+re.sub(<span class="string">"['\"]"</span>, <span class="keyword">lambda</span> i: <span class="string">"\\"</span> + i.group(0), mystr)
+re.sub(<span class="string">"[A-Z]"</span>, <span class="keyword">lambda</span> i: <span class="string">"\\"</span> + i.group(0), mystr)
+re.sub(<span class="string">"\W"</span>, <span class="keyword">lambda</span> i: <span class="string">"\\"</span> + i.group(0), <span class="string">"is a test!"</span>) <span class="comment-delimiter"># </span><span class="comment">no function like quotemeta?
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN56"
+>Trimming Blanks from the Ends of a String</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>mystr = mystr.lstrip() <span class="comment-delimiter"># </span><span class="comment">left
+</span>mystr = mystr.rstrip() <span class="comment-delimiter"># </span><span class="comment">right
+</span>mystr = mystr.strip() <span class="comment-delimiter"># </span><span class="comment">both ends
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN59"
+>Parsing Comma-Separated Data</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> csv
+<span class="keyword">def</span> <span class="function-name">parse_csv</span>(line):
+ reader = csv.reader([line], escapechar=<span class="string">'\\'</span>)
+ <span class="keyword">return</span> reader.next()
+
+line = <span class="string">'''XYZZY,"","O'</span>Reilly, Inc<span class="string">","</span>Wall, Larry<span class="string">","</span>a \\<span class="string">"glug\\"</span> bit,<span class="string">",5,"</span>Error, Core Dumped,<span class="string">",''' #"</span>
+
+fields = parse_csv(line)
+
+<span class="keyword">for</span> i, field <span class="keyword">in</span> <span class="py-builtins">enumerate</span>(fields):
+ <span class="keyword">print</span> <span class="string">"%d : %s"</span> % (i, field)
+
+<span class="comment-delimiter"># </span><span class="comment">pre-2.3 version of parse_csv
+</span><span class="keyword">import</span> re
+<span class="keyword">def</span> <span class="function-name">parse_csv</span>(text):
+ pattern = re.compile(<span class="string">'''"([^"\\\]*(?:\\\.[^"\\\]*)*)",?|([^,]+),?|,'''</span>)
+ mylist = [<span class="string">""</span>.join(elem)
+ <span class="keyword">for</span> elem <span class="keyword">in</span> re.findall(pattern, text)]
+ <span class="keyword">if</span> text[-1] == <span class="string">","</span>:
+ mylist += [<span class="string">''</span>]
+ <span class="keyword">return</span> mylist
+
+<span class="comment-delimiter"># </span><span class="comment">cvs.reader is meant to work for many lines, something like:
+</span><span class="comment-delimiter"># </span><span class="comment">(NB: in Python default, quotechar is *not* escaped by backslash,
+</span><span class="comment-delimiter"># </span><span class="comment">but doubled instead. That's what Excel does.)
+</span><span class="keyword">for</span> fields <span class="keyword">in</span> cvs.reader(lines, dialect=<span class="string">"some"</span>):
+ <span class="keyword">for</span> num, field <span class="keyword">in</span> <span class="py-builtins">enumerate</span>(fields):
+ <span class="keyword">print</span> num, <span class="string">":"</span>, field
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN62"
+>Soundex Matching</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">def</span> <span class="function-name">soundex</span>(name, len=4):
+ <span class="string">""" soundex module conforming to Knuth's algorithm
+ implementation 2000-12-24 by Gregory Jorgensen
+ public domain
+ """</span>
+
+ <span class="comment-delimiter"># </span><span class="comment">digits holds the soundex values for the alphabet
+</span> digits = <span class="string">'01230120022455012623010202'</span>
+ sndx = <span class="string">''</span>
+ fc = <span class="string">''</span>
+
+ <span class="comment-delimiter"># </span><span class="comment">translate alpha chars in name to soundex digits
+</span> <span class="keyword">for</span> c <span class="keyword">in</span> name.upper():
+ <span class="keyword">if</span> c.isalpha():
+ <span class="keyword">if</span> <span class="keyword">not</span> fc:
+ fc = c <span class="comment-delimiter"># </span><span class="comment">remember first letter
+</span> d = digits[<span class="py-builtins">ord</span>(c)-<span class="py-builtins">ord</span>(<span class="string">'A'</span>)]
+ <span class="comment-delimiter"># </span><span class="comment">duplicate consecutive soundex digits are skipped
+</span> <span class="keyword">if</span> <span class="keyword">not</span> sndx <span class="keyword">or</span> (d != sndx[-1]):
+ sndx += d
+
+ <span class="comment-delimiter"># </span><span class="comment">replace first digit with first alpha character
+</span> sndx = fc + sndx[1:]
+
+ <span class="comment-delimiter"># </span><span class="comment">remove all 0s from the soundex code
+</span> sndx = sndx.replace(<span class="string">'0'</span>,<span class="string">''</span>)
+
+ <span class="comment-delimiter"># </span><span class="comment">return soundex code padded to len characters
+</span> <span class="keyword">return</span> (sndx + (<span class="py-builtins">len</span> * <span class="string">'0'</span>))[:len]
+
+user = <span class="py-builtins">raw_input</span>(<span class="string">"Lookup user: "</span>)
+<span class="keyword">if</span> user == <span class="string">""</span>:
+ <span class="keyword">raise</span> <span class="py-builtins">SystemExit</span>
+
+name_code = soundex(user)
+<span class="keyword">for</span> line <span class="keyword">in</span> <span class="py-builtins">open</span>(<span class="string">"/etc/passwd"</span>):
+ line = line.split(<span class="string">":"</span>)
+ <span class="keyword">for</span> piece <span class="keyword">in</span> line[4].split():
+ <span class="keyword">if</span> name_code == soundex(piece):
+ <span class="keyword">print</span> <span class="string">"%s: %s\n"</span> % line[0], line[4])
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN65"
+>Program: fixstyle</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> sys, fileinput, re
+
+data = <span class="string">"""\
+analysed =&gt; analyzed
+built-in =&gt; builtin
+chastized =&gt; chastised
+commandline =&gt; command-line
+de-allocate =&gt; deallocate
+dropin =&gt; drop-in
+hardcode =&gt; hard-code
+meta-data =&gt; metadata
+multicharacter =&gt; multi-character
+multiway =&gt; multi-way
+non-empty =&gt; nonempty
+non-profit =&gt; nonprofit
+non-trappable =&gt; nontrappable
+pre-define =&gt; predefine
+preextend =&gt; pre-extend
+re-compiling =&gt; recompiling
+reenter =&gt; re-enter
+turnkey =&gt; turn-key
+"""</span>
+mydict = {}
+<span class="keyword">for</span> line <span class="keyword">in</span> data.split(<span class="string">"\n"</span>):
+ <span class="keyword">if</span> <span class="keyword">not</span> line.strip():
+ <span class="keyword">continue</span>
+ k, v = [word.strip() <span class="keyword">for</span> word <span class="keyword">in</span> line.split(<span class="string">"=&gt;"</span>)]
+ mydict[k] = v
+pattern_text = <span class="string">"("</span> + <span class="string">"|"</span>.join([re.escape(word) <span class="keyword">for</span> word <span class="keyword">in</span> mydict.keys()]) + <span class="string">")"</span>
+pattern = re.compile(pattern_text)
+
+args = sys.argv[1:]
+verbose = 0
+<span class="keyword">if</span> args <span class="keyword">and</span> args[0] == <span class="string">"-v"</span>:
+ verbose = 1
+ args = args[1:]
+
+<span class="keyword">if</span> <span class="keyword">not</span> args:
+ sys.stderr.write(<span class="string">"%s: Reading from stdin\n"</span> % sys.argv[0])
+
+<span class="keyword">for</span> line <span class="keyword">in</span> fileinput.input(args, inplace=1, backup=<span class="string">".orig"</span>):
+ output = <span class="string">""</span>
+ pos = 0
+ <span class="keyword">while</span> <span class="py-pseudo-keyword">True</span>:
+ match = pattern.search(line, pos)
+ <span class="keyword">if</span> <span class="keyword">not</span> match:
+ output += line[pos:]
+ <span class="keyword">break</span>
+ output += line[pos:match.start(0)] + mydict[match.group(1)]
+ pos = match.end(0)
+ sys.stdout.write(output)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN68"
+>Program: psgrep</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment">!/usr/bin/python
+</span><span class="comment-delimiter"># </span><span class="comment">psgrep - print selected lines of ps output by
+</span><span class="comment-delimiter"># </span><span class="comment">compiling user queries into code.
+</span><span class="comment-delimiter">#</span><span class="comment">
+</span><span class="comment-delimiter"># </span><span class="comment">examples :
+</span><span class="comment-delimiter"># </span><span class="comment">psgrep "uid&lt;10"
+</span><span class="keyword">import</span> sys, os, re
+
+<span class="keyword">class</span> <span class="type">PsLineMatch</span>:
+ <span class="comment-delimiter"># </span><span class="comment">each field from the PS header
+</span> fieldnames = (<span class="string">"flags"</span>,<span class="string">"uid"</span>,<span class="string">"pid"</span>,<span class="string">"ppid"</span>,<span class="string">"pri"</span>,<span class="string">"nice"</span>,<span class="string">"size"</span>, \
+ <span class="string">"rss"</span>,<span class="string">"wchan"</span>,<span class="string">"stat"</span>,<span class="string">"tty"</span>,<span class="string">"time"</span>,<span class="string">"command"</span>)
+ numeric_fields = (<span class="string">"flags"</span>,<span class="string">"uid"</span>,<span class="string">"pid"</span>,<span class="string">"ppid"</span>,<span class="string">"pri"</span>,<span class="string">"nice"</span>,<span class="string">"size"</span>,<span class="string">"rss"</span>)
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="py-pseudo-keyword">self</span>._fields = {}
+
+ <span class="keyword">def</span> <span class="function-name">new_line</span>(<span class="py-pseudo-keyword">self</span>, ln):
+ <span class="py-pseudo-keyword">self</span>._ln = ln.rstrip()
+ <span class="comment-delimiter"># </span><span class="comment">ps header for option "wwaxl" (different than in the perl code)
+</span> <span class="string">"""
+ F UID PID PPID PRI NI VSZ RSS WCHAN STAT TTY TIME COMMAND"</span>
+ 004 0 1 0 15 0 448 236 schedu S ? 0:07 init<span class="string">"
+ . . . . . . . . . . . . .
+ """</span>
+ <span class="comment-delimiter"># </span><span class="comment">because only the last entry might contain blanks, splitting
+</span> <span class="comment-delimiter"># </span><span class="comment">is safe
+</span> data = <span class="py-pseudo-keyword">self</span>._ln.split(<span class="py-pseudo-keyword">None</span>,12)
+ <span class="keyword">for</span> fn, elem <span class="keyword">in</span> <span class="py-builtins">zip</span>(<span class="py-pseudo-keyword">self</span>.fieldnames, data):
+ <span class="keyword">if</span> fn <span class="keyword">in</span> <span class="py-pseudo-keyword">self</span>.numeric_fields: <span class="comment-delimiter"># </span><span class="comment">make numbers integer
+</span> <span class="py-pseudo-keyword">self</span>._fields[fn] = <span class="py-builtins">int</span>(elem)
+ <span class="keyword">else:</span>
+ <span class="py-pseudo-keyword">self</span>._fields[fn] = elem
+
+ <span class="keyword">def</span> <span class="function-name">set_query</span>(<span class="py-pseudo-keyword">self</span>, args):
+ <span class="comment-delimiter"># </span><span class="comment">assume args: "uid==500", "command ~ ^wm"
+</span> conds=[]
+ m = re.compile(<span class="string">"(\w+)([=&lt;&gt;]+)(.+)"</span>)
+ <span class="keyword">for</span> a <span class="keyword">in</span> args:
+ <span class="keyword">try:</span>
+ (field,op,val) = m.match(a).groups()
+ <span class="keyword">except:</span>
+ <span class="keyword">print</span> <span class="string">"can't understand query \"%s\""</span> % (a)
+ <span class="keyword">raise</span> <span class="py-builtins">SystemExit</span>
+ <span class="keyword">if</span> field <span class="keyword">in</span> <span class="py-pseudo-keyword">self</span>.numeric_fields:
+ conds.append(a)
+ <span class="keyword">else:</span>
+ conds.append(<span class="string">"%s%s'%s'"</span>,(field,op,val))
+ <span class="py-pseudo-keyword">self</span>._desirable = <span class="py-builtins">compile</span>(<span class="string">"(("</span>+<span class="string">")and("</span>.join(conds)+<span class="string">"))"</span>, <span class="string">"&lt;string&gt;"</span>,<span class="string">"eval"</span>)
+
+ <span class="keyword">def</span> <span class="function-name">is_desirable</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="keyword">return</span> <span class="py-builtins">eval</span>(<span class="py-pseudo-keyword">self</span>._desirable, {}, <span class="py-pseudo-keyword">self</span>._fields)
+
+ <span class="keyword">def</span> <span class="function-name">__str__</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="comment-delimiter"># </span><span class="comment">to allow "print".
+</span> <span class="keyword">return</span> <span class="py-pseudo-keyword">self</span>._ln
+
+<span class="keyword">if</span> <span class="py-builtins">len</span>(sys.argv)&lt;=1:
+ <span class="keyword">print</span> <span class="string">"""usage: %s criterion ...
+ Each criterion is a Perl expression involving:
+ %s
+ All criteria must be met for a line to be printed."""</span> \
+ % (sys.argv[0], <span class="string">" "</span>.join(PsLineMatch().fieldnames))
+ <span class="keyword">raise</span> <span class="py-builtins">SystemExit</span>
+
+psln = PsLineMatch()
+psln.set_query(sys.argv[1:])
+p = os.popen(<span class="string">"ps wwaxl"</span>)
+<span class="keyword">print</span> p.readline()[:-1] <span class="comment-delimiter"># </span><span class="comment">emit header line
+</span><span class="keyword">for</span> ln <span class="keyword">in</span> p.readlines():
+ psln.new_line(ln)
+ <span class="keyword">if</span> psln.is_desirable():
+ <span class="keyword">print</span> psln
+p.close()
+
+<span class="comment-delimiter"># </span><span class="comment">alternatively one could consider every argument being a string and
+</span><span class="comment-delimiter"># </span><span class="comment">support wildcards: "uid==500" "command~^wm" by means of re, but this
+</span><span class="comment-delimiter"># </span><span class="comment">does not show dynamic python code generation, although re.compile
+</span><span class="comment-delimiter"># </span><span class="comment">also precompiles.
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+></DIV
+><DIV
+CLASS="NAVFOOTER"
+><HR
+ALIGN="LEFT"
+WIDTH="100%"><TABLE
+SUMMARY="Footer navigation table"
+WIDTH="100%"
+BORDER="0"
+CELLPADDING="0"
+CELLSPACING="0"
+><TR
+><TD
+WIDTH="33%"
+ALIGN="left"
+VALIGN="top"
+><A
+HREF="index.html"
+ACCESSKEY="P"
+>Prev</A
+></TD
+><TD
+WIDTH="34%"
+ALIGN="center"
+VALIGN="top"
+><A
+HREF="index.html"
+ACCESSKEY="H"
+>Home</A
+></TD
+><TD
+WIDTH="33%"
+ALIGN="right"
+VALIGN="top"
+><A
+HREF="numbers.html"
+ACCESSKEY="N"
+>Next</A
+></TD
+></TR
+><TR
+><TD
+WIDTH="33%"
+ALIGN="left"
+VALIGN="top"
+>PLEAC-Python
+</TD
+><TD
+WIDTH="34%"
+ALIGN="center"
+VALIGN="top"
+>&nbsp;</TD
+><TD
+WIDTH="33%"
+ALIGN="right"
+VALIGN="top"
+>Numbers</TD
+></TR
+></TABLE
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/help/PythonExamples/pleac_python/subroutines.html b/help/PythonExamples/pleac_python/subroutines.html
new file mode 100644
index 0000000..b4497c4
--- /dev/null
+++ b/help/PythonExamples/pleac_python/subroutines.html
@@ -0,0 +1,1071 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML
+><HEAD
+><TITLE
+>Subroutines</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
+REL="HOME"
+TITLE="PLEAC-Python
+"
+HREF="index.html"><LINK
+REL="PREVIOUS"
+TITLE="Directories"
+HREF="directories.html"><LINK
+REL="NEXT"
+TITLE="References and Records"
+HREF="referencesandrecords.html"><style type="text/css"> <!--
+ .comment {
+ /* font-lock-comment-face */
+ color: #bebebe;
+ }
+ .comment-delimiter {
+ }
+ .function-name {
+ /* font-lock-function-name-face */
+ color: #b2dfee;
+ }
+ .keyword {
+ /* font-lock-keyword-face */
+ color: #ffa500;
+ }
+ .py-builtins {
+ /* py-builtins-face */
+ color: #ffa500;
+ }
+ .py-pseudo-keyword {
+ /* py-pseudo-keyword-face */
+ color: #ffa500;
+ }
+ .string {
+ /* font-lock-string-face */
+ color: #00cd00;
+ }
+ .type {
+ /* font-lock-type-face */
+ color: #98fb98;
+ }
+ -->
+ </style></head
+><BODY TEXT="#cecece" BGCOLOR="#4f6f6f" LINK="#f5deb3" VLINK="#d5ae83"
+CLASS="SECT1"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><DIV
+CLASS="NAVHEADER"
+><TABLE
+SUMMARY="Header navigation table"
+WIDTH="100%"
+BORDER="0"
+CELLPADDING="0"
+CELLSPACING="0"
+><TR
+><TH
+COLSPAN="3"
+ALIGN="center"
+>PLEAC-Python
+</TH
+></TR
+><TR
+><TD
+WIDTH="10%"
+ALIGN="left"
+VALIGN="bottom"
+><A
+HREF="directories.html"
+ACCESSKEY="P"
+>Prev</A
+></TD
+><TD
+WIDTH="80%"
+ALIGN="center"
+VALIGN="bottom"
+></TD
+><TD
+WIDTH="10%"
+ALIGN="right"
+VALIGN="bottom"
+><A
+HREF="referencesandrecords.html"
+ACCESSKEY="N"
+>Next</A
+></TD
+></TR
+></TABLE
+><HR
+ALIGN="LEFT"
+WIDTH="100%"></DIV
+><DIV
+CLASS="SECT1"
+><H1
+CLASS="SECT1"
+><A
+NAME="SUBROUTINES"
+>10. Subroutines</A
+></H1
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN536"
+>Introduction</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">DO NOT DO THIS...
+</span>greeted = 0
+<span class="keyword">def</span> <span class="function-name">hello</span>():
+ <span class="keyword">global</span> greeted
+ greeted += 1
+ <span class="keyword">print</span> <span class="string">"hi there"</span>
+
+<span class="comment-delimiter">#</span><span class="comment">... as using a callable object to save state is cleaner
+</span><span class="comment-delimiter"># </span><span class="comment">class hello
+</span><span class="comment-delimiter"># </span><span class="comment">def __init__(self):
+</span><span class="comment-delimiter"># </span><span class="comment">self.greeted = 0
+</span><span class="comment-delimiter"># </span><span class="comment">def __call__(self):
+</span><span class="comment-delimiter"># </span><span class="comment">self.greeted += 1
+</span><span class="comment-delimiter"># </span><span class="comment">print "hi there"
+</span><span class="comment-delimiter"># </span><span class="comment">hello = hello()
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>hello() <span class="comment-delimiter"># </span><span class="comment">call subroutine hello with no arguments/parameters
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN539"
+>Accessing Subroutine Arguments</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> math
+<span class="comment-delimiter"># </span><span class="comment">Provided for demonstration purposes only. Use math.hypot() instead.
+</span><span class="keyword">def</span> <span class="function-name">hypotenuse</span>(side1, side2):
+ <span class="keyword">return</span> math.sqrt(side1**2 + side2**2)
+
+diag = hypotenuse(3, 4) <span class="comment-delimiter"># </span><span class="comment">diag is 5.0
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">print</span> hypotenuse(3, 4) <span class="comment-delimiter"># </span><span class="comment">prints 5.0
+</span>
+a = (3, 4)
+<span class="keyword">print</span> hypotenuse(*a) <span class="comment-delimiter"># </span><span class="comment">prints 5.0
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>both = men + women
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>nums = [1.4, 3.5, 6.7]
+<span class="comment-delimiter"># </span><span class="comment">Provided for demonstration purposes only. Use:
+</span><span class="comment-delimiter"># </span><span class="comment">ints = [int(num) for num in nums]
+</span><span class="keyword">def</span> <span class="function-name">int_all</span>(nums):
+ retlist = [] <span class="comment-delimiter"># </span><span class="comment">make new list for return
+</span> <span class="keyword">for</span> n <span class="keyword">in</span> nums:
+ retlist.append(<span class="py-builtins">int</span>(n))
+ <span class="keyword">return</span> retlist
+ints = int_all(nums) <span class="comment-delimiter"># </span><span class="comment">nums unchanged
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>nums = [1.4, 3.5, 6.7]
+
+<span class="keyword">def</span> <span class="function-name">trunc_em</span>(nums):
+ <span class="keyword">for</span> i,elem <span class="keyword">in</span> <span class="py-builtins">enumerate</span>(nums):
+ nums[i] = <span class="py-builtins">int</span>(elem)
+trunc_em(nums) <span class="comment-delimiter"># </span><span class="comment">nums now [1,3,6]
+</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">By convention, if a method (or function) modifies an object
+</span><span class="comment-delimiter"># </span><span class="comment">in-place, it returns None rather than the modified object.
+</span><span class="comment-delimiter"># </span><span class="comment">None of Python's built-in functions modify in-place; methods
+</span><span class="comment-delimiter"># </span><span class="comment">such as list.sort() are somewhat more common.
+</span>mylist = [3,2,1]
+mylist = mylist.sort() <span class="comment-delimiter"># </span><span class="comment">incorrect - returns None
+</span>mylist = sorted(mylist) <span class="comment-delimiter"># </span><span class="comment">correct - returns sorted copy
+</span>mylist.sort() <span class="comment-delimiter"># </span><span class="comment">correct - sorts in-place
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN542"
+>Making Variables Private to a Function</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Using global variables is discouraged - by default variables
+</span><span class="comment-delimiter"># </span><span class="comment">are visible only at and below the scope at which they are declared.
+</span><span class="comment-delimiter"># </span><span class="comment">Global variables modified by a function or method must be declared
+</span><span class="comment-delimiter"># </span><span class="comment">using the "global" keyword if they are modified
+</span><span class="keyword">def</span> <span class="function-name">somefunc</span>():
+ variable = something <span class="comment-delimiter"># </span><span class="comment">variable is invisible outside of somefunc
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> sys
+name, age = sys.args[1:] <span class="comment-delimiter"># </span><span class="comment">assumes two and only two command line parameters
+</span>start = fetch_time()
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>a, b = pair
+c = fetch_time()
+
+<span class="keyword">def</span> <span class="function-name">check_x</span>(x):
+ y = <span class="string">"whatever"</span>
+ run_check()
+ <span class="keyword">if</span> condition:
+ <span class="keyword">print</span> <span class="string">"got"</span>, x
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">def</span> <span class="function-name">save_list</span>(*args):
+ Global_List.extend(args)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN545"
+>Creating Persistent Private Variables</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment"># Python allows static nesting of scopes for reading but not writing,
+</span><span class="comment-delimiter">#</span><span class="comment"># preferring to use objects. The closest equivalent to:
+</span><span class="comment-delimiter">#</span><span class="comment">{
+</span><span class="comment-delimiter"># </span><span class="comment">my $counter;
+</span><span class="comment-delimiter"># </span><span class="comment">sub next_counter { return ++$counter }
+</span><span class="comment-delimiter">#</span><span class="comment">}
+</span><span class="comment-delimiter">#</span><span class="comment"># is:
+</span><span class="keyword">def</span> <span class="function-name">next_counter</span>(counter=[0]): <span class="comment-delimiter"># </span><span class="comment">default lists are created once only.
+</span> counter[0] += 1
+ <span class="keyword">return</span> counter[0]
+
+<span class="comment-delimiter"># </span><span class="comment">As that's a little tricksy (and can't make more than one counter),
+</span><span class="comment-delimiter"># </span><span class="comment">many Pythonistas would prefer either:
+</span><span class="keyword">def</span> <span class="function-name">make_counter</span>():
+ counter = 0
+ <span class="keyword">while</span> <span class="py-pseudo-keyword">True</span>:
+ counter += 1
+ <span class="keyword">yield</span> counter
+next_counter = make_counter().next
+
+<span class="comment-delimiter"># </span><span class="comment">Or:
+</span><span class="keyword">class</span> <span class="type">Counter</span>:
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="py-pseudo-keyword">self</span>.counter = 0
+ <span class="keyword">def</span> <span class="function-name">__call__</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="py-pseudo-keyword">self</span>.counter += 1
+ <span class="keyword">return</span> <span class="py-pseudo-keyword">self</span>.counter
+next_counter = Counter()
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment"># A close equivalent of
+</span><span class="comment-delimiter">#</span><span class="comment">BEGIN {
+</span><span class="comment-delimiter"># </span><span class="comment">my $counter = 42;
+</span><span class="comment-delimiter"># </span><span class="comment">sub next_counter { return ++$counter }
+</span><span class="comment-delimiter"># </span><span class="comment">sub prev_counter { return --$counter }
+</span><span class="comment-delimiter">#</span><span class="comment">}
+</span><span class="comment-delimiter">#</span><span class="comment"># is to use a list (to save the counter) and closured functions:
+</span><span class="keyword">def</span> <span class="function-name">make_counter</span>(start=0):
+ counter = [start]
+ <span class="keyword">def</span> <span class="function-name">next_counter</span>():
+ counter[0] += 1
+ <span class="keyword">return</span> counter[0]
+ <span class="keyword">def</span> <span class="function-name">prev_counter</span>():
+ counter[0] -= 1
+ <span class="keyword">return</span> counter[0]
+ <span class="keyword">return</span> next_counter, prev_counter
+next_counter, prev_counter = make_counter()
+
+<span class="comment-delimiter">#</span><span class="comment"># A clearer way uses a class:
+</span><span class="keyword">class</span> <span class="type">Counter</span>:
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>, start=0):
+ <span class="py-pseudo-keyword">self</span>.value = start
+ <span class="keyword">def</span> <span class="function-name">next</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="py-pseudo-keyword">self</span>.value += 1
+ <span class="keyword">return</span> <span class="py-pseudo-keyword">self</span>.value
+ <span class="keyword">def</span> <span class="function-name">prev</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="py-pseudo-keyword">self</span>.value -= 1
+ <span class="keyword">return</span> <span class="py-pseudo-keyword">self</span>.value
+ <span class="keyword">def</span> <span class="function-name">__int__</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="keyword">return</span> <span class="py-pseudo-keyword">self</span>.value
+
+counter = Counter(42)
+next_counter = counter.next
+prev_counter = counter.prev
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN548"
+>Determining Current Function Name</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment"># This sort of code inspection is liable to change as
+</span><span class="comment-delimiter">#</span><span class="comment"># Python evolves. There may be cleaner ways to do this.
+</span><span class="comment-delimiter">#</span><span class="comment"># This also may not work for code called from functions
+</span><span class="comment-delimiter">#</span><span class="comment"># written in C.
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> sys
+this_function = sys._getframe(0).f_code.co_name
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>i = 0 <span class="comment-delimiter"># </span><span class="comment">how far up the call stack to look
+</span>module = sys._getframe(i).f_globals[<span class="string">"__name__"</span>]
+filename = sys._getframe(i).f_code.co_filename
+line = sys._getframe(i).f_lineno
+subr = sys._getframe(i).f_code.co_name
+has_args = <span class="py-builtins">bool</span>(sys._getframe(i+1).f_code.co_argcount)
+
+<span class="comment-delimiter"># </span><span class="comment">'wantarray' is Perl specific
+</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>me = whoami()
+him = whowasi()
+
+<span class="keyword">def</span> <span class="function-name">whoami</span>():
+ sys._getframe(1).f_code.co_name
+<span class="keyword">def</span> <span class="function-name">whowasi</span>():
+ sys._getframe(2).f_code.co_name
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN551"
+>Passing Arrays and Hashes by Reference</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Every variable name is a reference to an object, thus nothing special
+</span><span class="comment-delimiter"># </span><span class="comment">needs to be done to pass a list or a dict as a parameter.
+</span>list_diff(list1, list2)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Note: if one parameter to zip() is longer it will be truncated
+</span><span class="keyword">def</span> <span class="function-name">add_vecpair</span>(x, y):
+ <span class="keyword">return</span> [x1+y1 <span class="keyword">for</span> x1, y1 <span class="keyword">in</span> <span class="py-builtins">zip</span>(x, y)]
+
+a = [1, 2]
+b = [5, 8]
+<span class="keyword">print</span> <span class="string">" "</span>.join([<span class="py-builtins">str</span>(n) <span class="keyword">for</span> n <span class="keyword">in</span> add_vecpair(a, b)])
+<span class="comment-delimiter">#</span><span class="comment">=&gt; 6 10
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">DO NOT DO THIS:
+</span><span class="keyword">assert</span> <span class="py-builtins">isinstance</span>(x, <span class="py-builtins">type</span>([])) <span class="keyword">and</span> <span class="py-builtins">isinstance</span>(y, <span class="py-builtins">type</span>([])), \
+ <span class="string">"usage: add_vecpair(list1, list2)"</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN554"
+>Detecting Return Context</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">perl return context is not something standard in python...
+</span><span class="comment-delimiter"># </span><span class="comment">but still you can achieve something alike if you really need it
+</span><span class="comment-delimiter"># </span><span class="comment">(but you must really need it badly since you should never use this!!)
+</span><span class="comment-delimiter">#</span><span class="comment">
+</span><span class="comment-delimiter"># </span><span class="comment">see http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/284742 for more
+</span><span class="comment-delimiter">#</span><span class="comment">
+</span><span class="comment-delimiter"># </span><span class="comment">NB: it has been tested under Python 2.3.x and no guarantees can be given
+</span><span class="comment-delimiter"># </span><span class="comment">that it works under any future Python version.
+</span><span class="keyword">import</span> inspect,dis
+
+<span class="keyword">def</span> <span class="function-name">expecting</span>():
+ <span class="string">"""Return how many values the caller is expecting"""</span>
+ f = inspect.currentframe().f_back.f_back
+ bytecode = f.f_code.co_code
+ i = f.f_lasti
+ instruction = <span class="py-builtins">ord</span>(bytecode[i+3])
+ <span class="keyword">if</span> instruction == dis.opmap[<span class="string">'UNPACK_SEQUENCE'</span>]:
+ howmany = <span class="py-builtins">ord</span>(bytecode[i+4])
+ <span class="keyword">return</span> howmany
+ <span class="keyword">elif</span> instruction == dis.opmap[<span class="string">'POP_TOP'</span>]:
+ <span class="keyword">return</span> 0
+ <span class="keyword">return</span> 1
+
+<span class="keyword">def</span> <span class="function-name">cleverfunc</span>():
+ howmany = expecting()
+ <span class="keyword">if</span> howmany == 0:
+ <span class="keyword">print</span> <span class="string">"return value discarded"</span>
+ <span class="keyword">if</span> howmany == 2:
+ <span class="keyword">return</span> 1,2
+ <span class="keyword">elif</span> howmany == 3:
+ <span class="keyword">return</span> 1,2,3
+ <span class="keyword">return</span> 1
+
+cleverfunc()
+x = cleverfunc()
+<span class="keyword">print</span> x
+x,y = cleverfunc()
+<span class="keyword">print</span> x,y
+x,y,z = cleverfunc()
+<span class="keyword">print</span> x,y,z</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN557"
+>Passing by Named Parameter</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>thefunc(increment= <span class="string">"20s"</span>, start=<span class="string">"+5m"</span>, finish=<span class="string">"+30m"</span>)
+thefunc(start= <span class="string">"+5m"</span>,finish=<span class="string">"+30m"</span>)
+thefunc(finish= <span class="string">"+30m"</span>)
+thefunc(start=<span class="string">"+5m"</span>, increment=<span class="string">"15s"</span>)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">def</span> <span class="function-name">thefunc</span>(increment=<span class="string">'10s'</span>,
+ finish=<span class="string">'0'</span>,
+ start=<span class="string">'0'</span>):
+ <span class="keyword">if</span> increment.endswith(<span class="string">"m"</span>):
+ <span class="keyword">pass</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN560"
+>Skipping Selected Return Values</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>a, _, c = func() <span class="comment-delimiter"># </span><span class="comment">Use _ as a placeholder...
+</span>a, ignore, c = func() <span class="comment-delimiter"># </span><span class="comment">...or assign to an otherwise unused variable
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN563"
+>Returning More Than One Array or Hash</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">def</span> <span class="function-name">somefunc</span>():
+ mylist = []
+ mydict = {}
+ <span class="comment-delimiter"># </span><span class="comment">...
+</span> <span class="keyword">return</span> mylist, mydict
+
+mylist, mydict = somefunc()
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">def</span> <span class="function-name">fn</span>():
+ <span class="keyword">return</span> a, b, c
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>h0, h1, h2 = fn()
+tuple_of_dicts = fn() <span class="comment-delimiter"># </span><span class="comment">eg: tuple_of_dicts[2]["keystring"]
+</span>r0, r1, r2 = fn() <span class="comment-delimiter"># </span><span class="comment">eg: r2["keystring"]
+</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN566"
+>Returning Failure</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Note: Exceptions are almost always preferred to error values
+</span><span class="keyword">return</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">def</span> <span class="function-name">empty_retval</span>():
+ <span class="keyword">return</span> <span class="py-pseudo-keyword">None</span>
+
+<span class="keyword">def</span> <span class="function-name">empty_retval</span>():
+ <span class="keyword">return</span> <span class="comment-delimiter"># </span><span class="comment">identical to return None
+</span>
+<span class="keyword">def</span> <span class="function-name">empty_retval</span>():
+ <span class="keyword">pass</span> <span class="comment-delimiter"># </span><span class="comment">None returned by default (empty func needs pass)
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>a = yourfunc()
+<span class="keyword">if</span> a:
+ <span class="keyword">pass</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>a = sfunc()
+<span class="keyword">if</span> <span class="keyword">not</span> a:
+ <span class="keyword">raise</span> <span class="py-builtins">AssertionError</span>(<span class="string">"sfunc failed"</span>)
+
+<span class="keyword">assert</span> sfunc(), <span class="string">"sfunc failed"</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN569"
+>Prototyping Functions</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">Prototypes are inapplicable to Python as Python disallows calling
+</span><span class="comment-delimiter"># </span><span class="comment">functions without using brackets, and user functions are able to
+</span><span class="comment-delimiter"># </span><span class="comment">mimic built-in functions with no special actions required as they
+</span><span class="comment-delimiter"># </span><span class="comment">only flatten lists (and convert dicts to named arguments) if
+</span><span class="comment-delimiter"># </span><span class="comment">explicitly told to do so. Python functions use named parameters
+</span><span class="comment-delimiter"># </span><span class="comment">rather than shifting arguments:
+</span>
+<span class="keyword">def</span> <span class="function-name">myfunc</span>(a, b, c=4):
+ <span class="keyword">print</span> a, b, c
+
+mylist = [1,2]
+
+mydict1 = {<span class="string">"b"</span>: 2, <span class="string">"c"</span>: 3}
+mydict2 = {<span class="string">"b"</span>: 2}
+
+myfunc(1,2,3)
+<span class="comment-delimiter">#</span><span class="comment">=&gt; 1 2 3
+</span>
+myfunc(1,2)
+<span class="comment-delimiter">#</span><span class="comment">=&gt; 1 2 4
+</span>
+myfunc(*mylist)
+<span class="comment-delimiter">#</span><span class="comment">=&gt; 1 2 4
+</span>
+myfunc(5, *mylist)
+<span class="comment-delimiter">#</span><span class="comment">=&gt; 5, 1, 2
+</span>
+myfunc(5, **mydict1)
+<span class="comment-delimiter">#</span><span class="comment">=&gt; 5, 2, 3
+</span>
+myfunc(5, **mydict2)
+<span class="comment-delimiter">#</span><span class="comment">=&gt; 5, 2, 4
+</span>
+myfunc(c=3, b=2, a=1)
+<span class="comment-delimiter">#</span><span class="comment">=&gt; 1, 2, 3
+</span>
+myfunc(b=2, a=1)
+<span class="comment-delimiter">#</span><span class="comment">=&gt; 1, 2, 4
+</span>
+myfunc(mylist, mydict1)
+<span class="comment-delimiter">#</span><span class="comment">=&gt; [1, 2] {'c': 3, 'b': 2} 4
+</span>
+<span class="comment-delimiter"># </span><span class="comment">For demonstration purposes only - don't do this
+</span><span class="keyword">def</span> <span class="function-name">mypush</span>(mylist, *vals):
+ mylist.extend(vals)
+
+mylist = []
+mypush(mylist, 1, 2, 3, 4, 5)
+<span class="keyword">print</span> mylist
+<span class="comment-delimiter">#</span><span class="comment">=&gt; [1, 2, 3, 4, 5]
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN572"
+>Handling Exceptions</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">raise</span> <span class="py-builtins">ValueError</span>(<span class="string">"some message"</span>) <span class="comment-delimiter"># </span><span class="comment">specific exception class
+</span><span class="keyword">raise</span> <span class="py-builtins">Exception</span>(<span class="string">"use me rarely"</span>) <span class="comment-delimiter"># </span><span class="comment">general exception
+</span><span class="keyword">raise</span> <span class="string">"don't use me"</span> <span class="comment-delimiter"># </span><span class="comment">string exception (deprecated)
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Note that bare excepts are considered bad style. Normally you should
+</span><span class="comment-delimiter"># </span><span class="comment">trap specific exceptions. For instance these bare excepts will
+</span><span class="comment-delimiter"># </span><span class="comment">catch KeyboardInterrupt, SystemExit, and MemoryError as well as
+</span><span class="comment-delimiter"># </span><span class="comment">more common errors. In addition they force you to import sys to
+</span><span class="comment-delimiter"># </span><span class="comment">get the error message.
+</span><span class="keyword">import</span> warnings, sys
+<span class="keyword">try:</span>
+ func()
+<span class="keyword">except:</span>
+ warnings.warn(<span class="string">"func raised an exception: "</span> + <span class="py-builtins">str</span>(sys.exc_info()[1]))
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">try:</span>
+ func()
+<span class="keyword">except:</span>
+ warnings.warn(<span class="string">"func blew up: "</span> + <span class="py-builtins">str</span>(sys.exc_info()[1]))
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">class</span> <span class="type">MoonPhaseError</span>(Exception):
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>, phase):
+ <span class="py-pseudo-keyword">self</span>.phase = phase
+<span class="keyword">class</span> <span class="type">FullMoonError</span>(MoonPhaseError):
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>):
+ MoonPhaseError.__init__(<span class="string">"full moon"</span>)
+
+<span class="keyword">def</span> <span class="function-name">func</span>():
+ <span class="keyword">raise</span> FullMoonError()
+
+<span class="comment-delimiter"># </span><span class="comment">Ignore only FullMoonError exceptions
+</span><span class="keyword">try:</span>
+ func()
+<span class="keyword">except</span> FullMoonError:
+ <span class="keyword">pass</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Ignore only MoonPhaseError for a full moon
+</span><span class="keyword">try:</span>
+ func()
+<span class="keyword">except</span> MoonPhaseError, err:
+ <span class="keyword">if</span> err.phase != <span class="string">"full moon"</span>:
+ <span class="keyword">raise</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN575"
+>Saving Global Values</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">There is no direct equivalent to 'local' in Python, and
+</span><span class="comment-delimiter"># </span><span class="comment">it's impossible to write your own. But then again, even in
+</span><span class="comment-delimiter"># </span><span class="comment">Perl it's considered poor style.
+</span>
+<span class="comment-delimiter"># </span><span class="comment">DON'T DO THIS (You probably shouldn't use global variables anyway):
+</span><span class="keyword">class</span> <span class="type">Local</span>(object):
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>, globalname, val):
+ <span class="py-pseudo-keyword">self</span>.globalname = globalname
+ <span class="py-pseudo-keyword">self</span>.globalval = <span class="py-builtins">globals</span>()[globalname]
+ <span class="py-builtins">globals</span>()[globalname] = val
+
+ <span class="keyword">def</span> <span class="function-name">__del__</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="py-builtins">globals</span>()[<span class="py-pseudo-keyword">self</span>.globalname] = <span class="py-pseudo-keyword">self</span>.globalval
+
+foo = 4
+
+<span class="keyword">def</span> <span class="function-name">blah</span>():
+ <span class="keyword">print</span> foo
+
+<span class="keyword">def</span> <span class="function-name">blech</span>():
+ temp = Local(<span class="string">"foo"</span>, 6)
+ blah()
+
+blah()
+blech()
+blah()
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN578"
+>Redefining a Function</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>grow = expand
+grow() <span class="comment-delimiter"># </span><span class="comment">calls expand()
+</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>one.var = two.table <span class="comment-delimiter"># </span><span class="comment">make one.var the same as two.table
+</span>one.big = two.small <span class="comment-delimiter"># </span><span class="comment">make one.big the same as two.small
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>fred = barney <span class="comment-delimiter"># </span><span class="comment">alias fred to barney
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span>s = red(<span class="string">"careful here"</span>)
+<span class="keyword">print</span> s
+<span class="comment-delimiter">#</span><span class="comment">&gt; &lt;FONT COLOR='red'&gt;careful here&lt;/FONT&gt;
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Note: the 'text' should be HTML escaped if it can contain
+</span><span class="comment-delimiter"># </span><span class="comment">any of the characters '&lt;', '&gt;' or '&amp;'
+</span><span class="keyword">def</span> <span class="function-name">red</span>(text):
+ <span class="keyword">return</span> <span class="string">"&lt;FONT COLOR='red'&gt;"</span> + text + <span class="string">"&lt;/FONT&gt;"</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">def</span> <span class="function-name">color_font</span>(color, text):
+ <span class="keyword">return</span> <span class="string">"&lt;FONT COLOR='%s'&gt;%s&lt;/FONT&gt;"</span> % (color, text)
+
+<span class="keyword">def</span> <span class="function-name">red</span>(text): <span class="keyword">return</span> color_font(<span class="string">"red"</span>, text)
+<span class="keyword">def</span> <span class="function-name">green</span>(text): <span class="keyword">return</span> color_font(<span class="string">"green"</span>, text)
+<span class="keyword">def</span> <span class="function-name">blue</span>(text): <span class="keyword">return</span> color_font(<span class="string">"blue"</span>, text)
+<span class="keyword">def</span> <span class="function-name">purple</span>(text): <span class="keyword">return</span> color_font(<span class="string">"purple"</span>, text)
+<span class="comment-delimiter"># </span><span class="comment">etc
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">This is done in Python by making an object, instead of
+</span><span class="comment-delimiter"># </span><span class="comment">saving state in a local anonymous context.
+</span><span class="keyword">class</span> <span class="type">ColorFont</span>:
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>, color):
+ <span class="py-pseudo-keyword">self</span>.color = color
+ <span class="keyword">def</span> <span class="function-name">__call__</span>(<span class="py-pseudo-keyword">self</span>, text):
+ <span class="keyword">return</span> <span class="string">"&lt;FONT COLOR='%s'&gt;%s&lt;/FONT&gt;"</span> % (<span class="py-pseudo-keyword">self</span>.color, text)
+
+colors = <span class="string">"red blue green yellow orange purple violet"</span>.split(<span class="string">" "</span>)
+<span class="keyword">for</span> name <span class="keyword">in</span> colors:
+ <span class="py-builtins">globals</span>()[name] = ColorFont(name)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">If you really don't want to make a new class, you can
+</span><span class="comment-delimiter"># </span><span class="comment">fake it somewhat by passing in default args.
+</span>colors = <span class="string">"red blue green yellow orange purple violet"</span>.split(<span class="string">" "</span>)
+<span class="keyword">for</span> name <span class="keyword">in</span> colors:
+ <span class="keyword">def</span> <span class="function-name">temp</span>(text, color = name):
+ <span class="keyword">return</span> <span class="string">"&lt;FONT COLOR='%s'&gt;%s&lt;/FONT&gt;"</span> % (color, text)
+ <span class="py-builtins">globals</span>()[name] = temp
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN581"
+>Trapping Undefined Function Calls with AUTOLOAD</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span>
+<span class="comment-delimiter"># </span><span class="comment">Python has the ability to derive from ModuleType and add
+</span><span class="comment-delimiter"># </span><span class="comment">new __getattr__ and __setattr__ methods. I don't know the
+</span><span class="comment-delimiter"># </span><span class="comment">expected way to use them to emulate Perl's AUTOLOAD. Instead,
+</span><span class="comment-delimiter"># </span><span class="comment">here's how something similar would be done in Python. This
+</span><span class="comment-delimiter"># </span><span class="comment">uses the ColorFont defined above.
+</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">class</span> <span class="type">AnyColor</span>:
+ <span class="keyword">def</span> <span class="function-name">__getattr__</span>(<span class="py-pseudo-keyword">self</span>, name):
+ <span class="keyword">return</span> ColorFont(name)
+
+colors = AnyColor()
+
+<span class="keyword">print</span> colors.chartreuse(<span class="string">"stuff"</span>)
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter">#</span><span class="comment"># Skipping this translation because 'local' is too Perl
+</span><span class="comment-delimiter">#</span><span class="comment"># specific, and there isn't enough context to figure out
+</span><span class="comment-delimiter">#</span><span class="comment"># what this is supposed to do.
+</span><span class="comment-delimiter">#</span><span class="comment">{
+</span><span class="comment-delimiter"># </span><span class="comment">local *yellow = \&amp;violet;
+</span><span class="comment-delimiter"># </span><span class="comment">local (*red, *green) = (\&amp;green, \&amp;red);
+</span><span class="comment-delimiter"># </span><span class="comment">print_stuff();
+</span><span class="comment-delimiter">#</span><span class="comment">}
+</span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN584"
+>Nesting Subroutines</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">def</span> <span class="function-name">outer</span>(arg1):
+ x = arg1 + 35
+ <span class="keyword">def</span> <span class="function-name">inner</span>():
+ <span class="keyword">return</span> x * 19
+ <span class="keyword">return</span> x + inner()
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN587"
+>Program: Sorting Your Mail</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> mailbox, sys
+mbox = mailbox.PortableUnixMailbox(sys.stdin)
+
+<span class="keyword">def</span> <span class="function-name">extract_data</span>(msg, idx):
+ subject = msg.getheader(<span class="string">"Subject"</span>, <span class="string">""</span>).strip()
+ <span class="keyword">if</span> subject[:3].lower() == <span class="string">"re:"</span>:
+ subject = subject[3:].lstrip()
+ text = msg.fp.read()
+ <span class="keyword">return</span> subject, idx, msg, text
+messages = [extract_data(idx, msg) <span class="keyword">for</span> idx, msg <span class="keyword">in</span> <span class="py-builtins">enumerate</span>(mbox)]
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Sorts by subject then by original position in the list
+</span><span class="keyword">for</span> subject, pos, msg, text <span class="keyword">in</span> sorted(messages):
+ <span class="keyword">print</span> <span class="string">"%s\n%s"</span>%(msg, text)
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Sorts by subject then date then original position
+</span><span class="keyword">def</span> <span class="function-name">subject_date_position</span>(elem):
+ <span class="keyword">return</span> (elem[0], elem[2].getdate(<span class="string">"Date"</span>), elem[1])
+messages.sort(key=subject_date_position)
+
+<span class="comment-delimiter"># </span><span class="comment">Pre 2.4:
+</span>messages = sorted(messages, key=subject_date_position)
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+></DIV
+><DIV
+CLASS="NAVFOOTER"
+><HR
+ALIGN="LEFT"
+WIDTH="100%"><TABLE
+SUMMARY="Footer navigation table"
+WIDTH="100%"
+BORDER="0"
+CELLPADDING="0"
+CELLSPACING="0"
+><TR
+><TD
+WIDTH="33%"
+ALIGN="left"
+VALIGN="top"
+><A
+HREF="directories.html"
+ACCESSKEY="P"
+>Prev</A
+></TD
+><TD
+WIDTH="34%"
+ALIGN="center"
+VALIGN="top"
+><A
+HREF="index.html"
+ACCESSKEY="H"
+>Home</A
+></TD
+><TD
+WIDTH="33%"
+ALIGN="right"
+VALIGN="top"
+><A
+HREF="referencesandrecords.html"
+ACCESSKEY="N"
+>Next</A
+></TD
+></TR
+><TR
+><TD
+WIDTH="33%"
+ALIGN="left"
+VALIGN="top"
+>Directories</TD
+><TD
+WIDTH="34%"
+ALIGN="center"
+VALIGN="top"
+>&nbsp;</TD
+><TD
+WIDTH="33%"
+ALIGN="right"
+VALIGN="top"
+>References and Records</TD
+></TR
+></TABLE
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/help/PythonExamples/pleac_python/userinterfaces.html b/help/PythonExamples/pleac_python/userinterfaces.html
new file mode 100644
index 0000000..7f711e0
--- /dev/null
+++ b/help/PythonExamples/pleac_python/userinterfaces.html
@@ -0,0 +1,1050 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML
+><HEAD
+><TITLE
+>User Interfaces</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
+REL="HOME"
+TITLE="PLEAC-Python
+"
+HREF="index.html"><LINK
+REL="PREVIOUS"
+TITLE="Database Access"
+HREF="dbaccess.html"><LINK
+REL="NEXT"
+TITLE="Process Management and Communication"
+HREF="processmanagementetc.html"><style type="text/css"> <!--
+ .comment {
+ /* font-lock-comment-face */
+ color: #bebebe;
+ }
+ .comment-delimiter {
+ }
+ .function-name {
+ /* font-lock-function-name-face */
+ color: #b2dfee;
+ }
+ .keyword {
+ /* font-lock-keyword-face */
+ color: #ffa500;
+ }
+ .py-builtins {
+ /* py-builtins-face */
+ color: #ffa500;
+ }
+ .py-pseudo-keyword {
+ /* py-pseudo-keyword-face */
+ color: #ffa500;
+ }
+ .string {
+ /* font-lock-string-face */
+ color: #00cd00;
+ }
+ .type {
+ /* font-lock-type-face */
+ color: #98fb98;
+ }
+ -->
+ </style></head
+><BODY TEXT="#cecece" BGCOLOR="#4f6f6f" LINK="#f5deb3" VLINK="#d5ae83"
+CLASS="SECT1"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><DIV
+CLASS="NAVHEADER"
+><TABLE
+SUMMARY="Header navigation table"
+WIDTH="100%"
+BORDER="0"
+CELLPADDING="0"
+CELLSPACING="0"
+><TR
+><TH
+COLSPAN="3"
+ALIGN="center"
+>PLEAC-Python
+</TH
+></TR
+><TR
+><TD
+WIDTH="10%"
+ALIGN="left"
+VALIGN="bottom"
+><A
+HREF="dbaccess.html"
+ACCESSKEY="P"
+>Prev</A
+></TD
+><TD
+WIDTH="80%"
+ALIGN="center"
+VALIGN="bottom"
+></TD
+><TD
+WIDTH="10%"
+ALIGN="right"
+VALIGN="bottom"
+><A
+HREF="processmanagementetc.html"
+ACCESSKEY="N"
+>Next</A
+></TD
+></TR
+></TABLE
+><HR
+ALIGN="LEFT"
+WIDTH="100%"></DIV
+><DIV
+CLASS="SECT1"
+><H1
+CLASS="SECT1"
+><A
+NAME="USERINTERFACES"
+>15. User Interfaces</A
+></H1
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN792"
+>Parsing Program Arguments</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Parsing program arguments
+</span><span class="comment-delimiter"># </span><span class="comment">-- getopt way (All Python versions)
+</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Preamble
+</span>
+<span class="keyword">import</span> sys
+<span class="keyword">import</span> getopt
+
+<span class="comment-delimiter"># </span><span class="comment">getopt() explicitly receives arguments for it to process.
+</span><span class="comment-delimiter"># </span><span class="comment">No magic. Explicit is better than implicit.
+</span>
+<span class="comment-delimiter"># </span><span class="comment">PERL: @ARGV
+</span>argv = sys.argv[1:]
+
+<span class="comment-delimiter"># </span><span class="comment">Note that sys.argv[0] is the script name, and need to be
+</span><span class="comment-delimiter"># </span><span class="comment">stripped.
+</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Short options
+</span>
+<span class="comment-delimiter"># </span><span class="comment">PERL: getopt("vDo");
+</span><span class="comment-delimiter"># </span><span class="comment">Polluting the caller's namespace is evil. Don't do that.
+</span>
+<span class="comment-delimiter"># </span><span class="comment">PERL: getopt("vDo:", \%opts);
+</span>opts, rest = getopt.getopt(argv, <span class="string">"vDo:"</span>)
+
+<span class="comment-delimiter"># </span><span class="comment">If you want switches to take arguments, you must say so.
+</span><span class="comment-delimiter"># </span><span class="comment">Unlike PERL, which silently performs its magic, switches
+</span><span class="comment-delimiter"># </span><span class="comment">specified without trailing colons are considered boolean
+</span><span class="comment-delimiter"># </span><span class="comment">flags by default.
+</span>
+<span class="comment-delimiter"># </span><span class="comment">PERL: getopt("vDo", \%opts);
+</span>opts, rest = getopt.getopt(argv, <span class="string">"v:D:o:"</span>)
+
+<span class="comment-delimiter"># </span><span class="comment">PERL: getopts("vDo:", \%opts);
+</span><span class="comment-delimiter"># </span><span class="comment">getopt/getopts distinction is not present in Python 'getopt'
+</span><span class="comment-delimiter"># </span><span class="comment">module.
+</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">getopt() return values, compared to PERL
+</span>
+<span class="comment-delimiter"># </span><span class="comment">getopt() returns two values. The first is a list of
+</span><span class="comment-delimiter"># </span><span class="comment">(option, value) pair. (Not a dictionary, i.e. Python hash.)
+</span><span class="comment-delimiter"># </span><span class="comment">The second is the list of arguments left unprocessed.
+</span>
+<span class="comment-delimiter"># </span><span class="comment">Example
+</span><span class="comment-delimiter"># </span><span class="comment">&gt;&gt;&gt; argv = "-v ARG1 -D ARG2 -o ARG3".split()
+</span><span class="comment-delimiter"># </span><span class="comment">&gt;&gt;&gt; opts, rest = getopt.getopt(argv, "v:D:o:")
+</span><span class="comment-delimiter"># </span><span class="comment">&gt;&gt;&gt; print opts
+</span><span class="comment-delimiter"># </span><span class="comment">[('-v', 'ARG1'), ('-D', 'ARG2'), ('-o', 'ARG3')]
+</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Long options
+</span>
+<span class="comment-delimiter"># </span><span class="comment">getopt() handles long options too. Pass a list of option
+</span><span class="comment-delimiter"># </span><span class="comment">names as the third argument. If an option takes an argument,
+</span><span class="comment-delimiter"># </span><span class="comment">append an equal sign.
+</span>
+opts, rest = getopt.getopt(argv, <span class="string">""</span>, [
+ <span class="string">"verbose"</span>, <span class="string">"Debug"</span>, <span class="string">"output="</span>])
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">Switch clustering
+</span>
+<span class="comment-delimiter"># </span><span class="comment">getopt() does switch clustering just fine.
+</span>
+<span class="comment-delimiter"># </span><span class="comment">Example
+</span><span class="comment-delimiter"># </span><span class="comment">&gt;&gt;&gt; argv1 = '-r -f /tmp/testdir'.split()
+</span><span class="comment-delimiter"># </span><span class="comment">&gt;&gt;&gt; argv2 = '-rf /tmp/testdir'.split()
+</span><span class="comment-delimiter"># </span><span class="comment">&gt;&gt;&gt; print getopt.getopt(argv1, 'rf')
+</span><span class="comment-delimiter"># </span><span class="comment">([('-r', ''), ('-f', '')], ['/tmp/testdir'])
+</span><span class="comment-delimiter"># </span><span class="comment">&gt;&gt;&gt; print getopt.getopt(argv2, 'rf')
+</span><span class="comment-delimiter"># </span><span class="comment">([('-r', ''), ('-f', '')], ['/tmp/testdir'])
+</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span>
+<span class="comment-delimiter"># </span><span class="comment">TODO: Complete this section using 'getopt'. Show how to
+</span><span class="comment-delimiter"># </span><span class="comment">use the parsed result.
+</span>
+<span class="comment-delimiter"># </span><span class="comment">http://www.python.org/doc/current/lib/module-getopt.html
+</span><span class="comment-delimiter"># </span><span class="comment">Python library reference has a "typical usage" demo.
+</span>
+<span class="comment-delimiter"># </span><span class="comment">TODO: Introduce 'optparse', a very powerful command line
+</span><span class="comment-delimiter"># </span><span class="comment">option parsing module. New in 2.3.
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN795"
+>Testing Whether a Program Is Running Interactively</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">#------------------
+</span><span class="keyword">import</span> sys
+
+<span class="keyword">def</span> <span class="function-name">is_interactive_python</span>():
+ <span class="keyword">try:</span>
+ ps = sys.ps1
+ <span class="keyword">except:</span>
+ <span class="keyword">return</span> <span class="py-pseudo-keyword">False</span>
+ <span class="keyword">return</span> <span class="py-pseudo-keyword">True</span>
+<span class="comment-delimiter">#</span><span class="comment">#------------------
+</span><span class="keyword">import</span> sys
+<span class="keyword">def</span> <span class="function-name">is_interactive</span>():
+ <span class="comment-delimiter"># </span><span class="comment">only False if stdin is redirected like "-t" in perl.
+</span> <span class="keyword">return</span> sys.stdin.isatty()
+
+<span class="comment-delimiter"># </span><span class="comment">Or take advantage of Python's Higher Order Functions:
+</span>is_interactive = sys.stdin.isatty
+<span class="comment-delimiter">#</span><span class="comment">#------------------
+</span><span class="keyword">import</span> posix
+<span class="keyword">def</span> <span class="function-name">is_interactive_posix</span>():
+ tty = <span class="py-builtins">open</span>(<span class="string">"/dev/tty"</span>)
+ tpgrp = posix.tcgetpgrp(tty.fileno())
+ pgrp = posix.getpgrp()
+ tty.close()
+ <span class="keyword">return</span> (tpgrp == pgrp)
+
+<span class="comment-delimiter"># </span><span class="comment">test with:
+</span><span class="comment-delimiter"># </span><span class="comment">python 15.2.py
+</span><span class="comment-delimiter"># </span><span class="comment">echo "dummy" | python 15.2.py | cat
+</span><span class="keyword">print</span> <span class="string">"is python shell:"</span>, is_interactive_python()
+<span class="keyword">print</span> <span class="string">"is a tty:"</span>, is_interactive()
+<span class="keyword">print</span> <span class="string">"has no tty:"</span>, is_interactive_posix()
+
+<span class="keyword">if</span> is_interactive():
+ <span class="keyword">while</span> <span class="py-pseudo-keyword">True</span>:
+ <span class="keyword">try:</span>
+ ln = <span class="py-builtins">raw_input</span>(<span class="string">"Prompt:"</span>)
+ <span class="keyword">except:</span>
+ <span class="keyword">break</span>
+ <span class="keyword">print</span> <span class="string">"you typed:"</span>, ln</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN798"
+>Clearing the Screen</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span>
+<span class="comment-delimiter"># </span><span class="comment">Python has no Term::Cap module.
+</span><span class="comment-delimiter"># </span><span class="comment">One could use the curses, but this was not ported to windows,
+</span><span class="comment-delimiter"># </span><span class="comment">use console.
+</span>
+<span class="comment-delimiter"># </span><span class="comment">just run clear
+</span><span class="keyword">import</span> os
+os.system(<span class="string">"clear"</span>)
+<span class="comment-delimiter"># </span><span class="comment">cache output
+</span>clear = os.popen(<span class="string">"clear"</span>).read()
+<span class="keyword">print</span> clear
+<span class="comment-delimiter"># </span><span class="comment">or to avoid print's newline
+</span>sys.stdout.write(clear)</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN801"
+>Determining Terminal or Window Size</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">Determining Terminal or Window Size
+</span>
+<span class="comment-delimiter"># </span><span class="comment">eiter use ioctl
+</span><span class="keyword">import</span> struct, fcntl, termios, sys
+
+s = struct.pack(<span class="string">"HHHH"</span>, 0, 0, 0, 0)
+hchar, wchar = struct.unpack(<span class="string">"HHHH"</span>, fcntl.ioctl(sys.stdout.fileno(),
+ termios.TIOCGWINSZ, s))[:2]
+<span class="comment-delimiter"># </span><span class="comment">or curses
+</span><span class="keyword">import</span> curses
+(hchar,wchar) = curses.getmaxyx()
+
+<span class="comment-delimiter"># </span><span class="comment">graph contents of values
+</span><span class="keyword">import</span> struct, fcntl, termios, sys
+width = struct.unpack(<span class="string">"HHHH"</span>, fcntl.ioctl(sys.stdout.fileno(),
+ termios.TIOCGWINSZ,
+ struct.pack(<span class="string">"HHHH"</span>, 0, 0, 0, 0)))[1]
+<span class="keyword">if</span> width&lt;10:
+ <span class="keyword">print</span> <span class="string">"You must have at least 10 characters"</span>
+ <span class="keyword">raise</span> <span class="py-builtins">SystemExit</span>
+
+max_value = 0
+<span class="keyword">for</span> v <span class="keyword">in</span> values:
+ max_value = <span class="py-builtins">max</span>(max_value,v)
+
+ratio = (width-10)/max_value <span class="comment-delimiter"># </span><span class="comment">chars per unit
+</span><span class="keyword">for</span> v <span class="keyword">in</span> values:
+ <span class="keyword">print</span> <span class="string">"%8.1f %s"</span> % (v, <span class="string">"*"</span>*(v*ratio))</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN804"
+>Changing Text Color</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span>
+<span class="comment-delimiter"># </span><span class="comment">there seems to be no standard ansi module
+</span><span class="comment-delimiter"># </span><span class="comment">and BLINK does not blink here.
+</span>RED = <span class="string">'\033[31m'</span>
+RESET = <span class="string">'\033[0;0m'</span>
+BLINK = <span class="string">'\033[05m'</span>
+NOBLINK = <span class="string">'\033[25m'</span>
+
+<span class="keyword">print</span> RED+<span class="string">"DANGER, Will Robinson!"</span>+RESET
+<span class="keyword">print</span> <span class="string">"This is just normal text"</span>
+<span class="keyword">print</span> <span class="string">"Will ``"</span>+BLINK+<span class="string">"Do you hurt yet?"</span>+NOBLINK+<span class="string">"'' and back"</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN807"
+>Reading from the Keyboard</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span>
+<span class="comment-delimiter"># </span><span class="comment">Show ASCII values for keypresses
+</span>
+<span class="comment-delimiter"># </span><span class="comment">_Getch is from http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/134892
+</span><span class="keyword">class</span> <span class="type">_Getch</span>:
+ <span class="string">"""Gets a single character from standard input. Doesn't echo to screen."""</span>
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="keyword">try:</span>
+ <span class="py-pseudo-keyword">self</span>.impl = _GetchWindows()
+ <span class="keyword">except</span> <span class="py-builtins">ImportError</span>:
+ <span class="py-pseudo-keyword">self</span>.impl = _GetchUnix()
+
+ <span class="keyword">def</span> <span class="function-name">__call__</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="keyword">return</span> <span class="py-pseudo-keyword">self</span>.impl()
+
+
+<span class="keyword">class</span> <span class="type">_GetchUnix</span>:
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="keyword">import</span> tty, sys
+
+ <span class="keyword">def</span> <span class="function-name">__call__</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="keyword">import</span> sys, tty, termios
+ fd = sys.stdin.fileno()
+ old_settings = termios.tcgetattr(fd)
+ <span class="keyword">try:</span>
+ tty.setraw(sys.stdin.fileno())
+ ch = sys.stdin.read(1)
+ <span class="keyword">finally:</span>
+ termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
+ <span class="keyword">return</span> ch
+
+
+<span class="keyword">class</span> <span class="type">_GetchWindows</span>:
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="keyword">import</span> msvcrt
+
+ <span class="keyword">def</span> <span class="function-name">__call__</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="keyword">import</span> msvcrt
+ <span class="keyword">return</span> msvcrt.getch()
+
+
+getch = _Getch()
+
+<span class="keyword">print</span> <span class="string">"Press keys to see their ASCII values. Use Ctrl-C to quit.\n"</span>
+<span class="keyword">try:</span>
+ <span class="keyword">while</span> <span class="py-pseudo-keyword">True</span>:
+ char = <span class="py-builtins">ord</span>(getch())
+ <span class="keyword">if</span> char == 3:
+ <span class="keyword">break</span>
+ <span class="keyword">print</span> <span class="string">" Decimal: %3d Octal: %3o Hex: x%02x"</span> % (char, char, char)
+<span class="keyword">except</span> KeyboardError:
+ <span class="keyword">pass</span>
+<span class="comment-delimiter">#</span><span class="comment">----------------------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN810"
+>Ringing the Terminal Bell</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="keyword">print</span> <span class="string">"\aWake up!\n"</span>;
+<span class="comment-delimiter">#</span><span class="comment">----------------------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN813"
+>Using POSIX termios</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN816"
+>Checking for Waiting Input</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">On Windows
+</span><span class="keyword">import</span> msvcrt
+<span class="keyword">if</span> msvcrt.kbhit():
+ c = msvcrt.getch
+
+<span class="comment-delimiter"># </span><span class="comment">See http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/134892
+</span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN819"
+>Reading Passwords</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">----------------------------------------
+</span><span class="keyword">import</span> getpass
+<span class="keyword">import</span> pwd
+<span class="keyword">import</span> crypt
+password = getpass.getpass(<span class="string">'Enter your password: '</span>)
+username = getpass.getuser()
+encrypted = pwd.getpwnam(username).pw_passwd
+<span class="keyword">if</span> <span class="keyword">not</span> encrypted <span class="keyword">or</span> encrypted == <span class="string">'x'</span>:
+ <span class="comment-delimiter"># </span><span class="comment">If using shadow passwords, this will be empty or 'x'
+</span> <span class="keyword">print</span> <span class="string">"Cannot verify password"</span>
+<span class="keyword">elif</span> crypt.crypt(password, encrypted) != encrypted:
+ <span class="keyword">print</span> <span class="string">"You are not"</span>, username
+<span class="keyword">else:</span>
+ <span class="keyword">print</span> <span class="string">"Welcome,"</span>, username
+<span class="comment-delimiter">#</span><span class="comment">----------------------------------------
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN822"
+>Editing Input</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span>
+<span class="comment-delimiter"># </span><span class="comment">simply importing readline gives line edit capabilities to raw_
+</span><span class="keyword">import</span> readline
+readline.add_history(<span class="string">"fake line"</span>)
+line = <span class="py-builtins">raw_input</span>()
+
+<span class="comment-delimiter"># </span><span class="comment"><font size="-1"><a href="http://pleac.sourceforge.net/include/python/ch15/vbsh">download the following standalone program</a></font>
+</span><span class="comment-delimiter">#</span><span class="comment">!/usr/bin/python
+</span><span class="comment-delimiter"># </span><span class="comment">vbsh - very bad shell
+</span>
+<span class="keyword">import</span> os
+<span class="keyword">import</span> readline
+
+<span class="keyword">while</span> <span class="py-pseudo-keyword">True</span>:
+ <span class="keyword">try:</span>
+ cmd = <span class="py-builtins">raw_input</span>(<span class="string">'$ '</span>)
+ <span class="keyword">except</span> <span class="py-builtins">EOFError</span>:
+ <span class="keyword">break</span>
+ status = os.system(cmd)
+ exit_value = status &gt;&gt; 8
+ signal_num = status &amp; 127
+ dumped_core = status &amp; 128 <span class="keyword">and</span> <span class="string">"(core dumped)"</span> <span class="keyword">or</span> <span class="string">""</span>
+ <span class="keyword">print</span> <span class="string">"Program terminated with status %d from signal %d%s\n"</span> % (
+ exit_value, signal_num, dumped_core)
+
+
+
+readline.add_history(<span class="string">"some line!"</span>)
+readline.remove_history_item(position)
+line = readline.get_history_item(index)
+
+<span class="comment-delimiter"># </span><span class="comment">an interactive python shell would be
+</span><span class="keyword">import</span> code, readline
+code.InteractiveConsole().interact(<span class="string">"code.InteractiveConsole"</span>)</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN825"
+>Managing the Screen</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN828"
+>Controlling Another Program with Expect</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">----------------------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">This entry uses pexpect, a pure Python Expect-like module.
+</span><span class="comment-delimiter"># </span><span class="comment">http://pexpect.sourceforge.net/
+</span>
+<span class="comment-delimiter"># </span><span class="comment">for more information, check pexpect's documentation and example.
+</span>
+<span class="keyword">import</span> pexpect
+
+<span class="comment-delimiter">#</span><span class="comment">----------------------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">spawn program
+</span><span class="keyword">try:</span>
+ command = pexpect.spawn(<span class="string">"program to run"</span>)
+<span class="keyword">except</span> pexpect.ExceptionPexpect:
+ <span class="comment-delimiter"># </span><span class="comment">couldn't spawn program
+</span> <span class="keyword">pass</span>
+
+<span class="comment-delimiter">#</span><span class="comment">----------------------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">you can pass any filelike object to setlog
+</span><span class="comment-delimiter"># </span><span class="comment">passing None will stop logging
+</span>
+<span class="comment-delimiter"># </span><span class="comment">stop logging
+</span>command.setlog(<span class="py-pseudo-keyword">None</span>)
+
+<span class="comment-delimiter"># </span><span class="comment">log to stdout
+</span><span class="keyword">import</span> sys
+command.setlog(sys.stdout)
+
+<span class="comment-delimiter"># </span><span class="comment">log to specific file
+</span>fp = <span class="py-builtins">file</span>(<span class="string">"pexpect.log"</span>, <span class="string">"w"</span>)
+command.setlog(fp)
+
+<span class="comment-delimiter">#</span><span class="comment">----------------------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">expecting simple string
+</span>command.expect(<span class="string">"ftp&gt;"</span>)
+
+<span class="comment-delimiter"># </span><span class="comment">expecting regular expression
+</span><span class="comment-delimiter"># </span><span class="comment">actually, string is always treated as regular expression
+</span>
+<span class="comment-delimiter"># </span><span class="comment">so it's the same thing
+</span>command.expect(<span class="string">"Name.*:"</span>)
+
+<span class="comment-delimiter"># </span><span class="comment">you can do it this way, too
+</span><span class="keyword">import</span> re
+regex = re.compile(<span class="string">"Name.*:"</span>)
+command.expect(regex)
+
+<span class="comment-delimiter">#</span><span class="comment">----------------------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">expecting with timeout
+</span><span class="keyword">try:</span>
+ command.expect(<span class="string">"Password:"</span>, 10)
+<span class="keyword">except</span> pexpect.TIMEOUT:
+ <span class="comment-delimiter"># </span><span class="comment">timed out
+</span> <span class="keyword">pass</span>
+
+<span class="comment-delimiter"># </span><span class="comment">setting default timeout
+</span>command.timeout = 10
+
+<span class="comment-delimiter"># </span><span class="comment">since we set default timeout, following does same as above
+</span><span class="keyword">try:</span>
+ command.expect(<span class="string">"Password:"</span>)
+<span class="keyword">except</span> pexpect.TIMEOUT:
+ <span class="comment-delimiter"># </span><span class="comment">timed out
+</span> <span class="keyword">pass</span>
+
+<span class="comment-delimiter">#</span><span class="comment">----------------------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">what? do you *really* want to wait forever?
+</span>
+<span class="comment-delimiter">#</span><span class="comment">----------------------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">sending line: normal way
+</span>command.sendline(<span class="string">"get spam_and_ham"</span>)
+
+<span class="comment-delimiter"># </span><span class="comment">you can also treat it as file
+</span>print&gt;&gt;command, <span class="string">"get spam_and_ham"</span>
+
+<span class="comment-delimiter">#</span><span class="comment">----------------------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">finalization
+</span>
+<span class="comment-delimiter"># </span><span class="comment">close connection with child process
+</span><span class="comment-delimiter"># </span><span class="comment">(that is, freeing file descriptor)
+</span>command.close()
+
+<span class="comment-delimiter"># </span><span class="comment">kill child process
+</span><span class="keyword">import</span> signal
+command.kill(signal.SIGKILL)
+
+<span class="comment-delimiter">#</span><span class="comment">----------------------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">expecting multiple choices
+</span>which = command.expect([<span class="string">"invalid"</span>, <span class="string">"success"</span>, <span class="string">"error"</span>, <span class="string">"boom"</span>])
+
+<span class="comment-delimiter"># </span><span class="comment">return value is index of matched choice
+</span><span class="comment-delimiter"># </span><span class="comment">0: invalid
+</span><span class="comment-delimiter"># </span><span class="comment">1: success
+</span><span class="comment-delimiter"># </span><span class="comment">2: error
+</span><span class="comment-delimiter"># </span><span class="comment">3: boom
+</span>
+<span class="comment-delimiter">#</span><span class="comment">----------------------------------------
+</span><span class="comment-delimiter"># </span><span class="comment">avoiding exception handling
+</span>choices = [<span class="string">"invalid"</span>, <span class="string">"success"</span>, <span class="string">"error"</span>, <span class="string">"boom"</span>]
+choices.append(pexpect.TIMEOUT)
+choices.append(pexpect.EOF)
+
+which = command.expect(choices)
+
+<span class="comment-delimiter"># </span><span class="comment">if TIMEOUT or EOF occurs, appropriate index is returned
+</span><span class="comment-delimiter"># </span><span class="comment">(instead of raising exception)
+</span><span class="comment-delimiter"># </span><span class="comment">4: TIMEOUT
+</span><span class="comment-delimiter"># </span><span class="comment">5: EOF
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN831"
+>Creating Menus with Tk</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="keyword">from</span> Tkinter <span class="keyword">import</span> *
+
+<span class="keyword">def</span> <span class="function-name">print_callback</span>():
+ <span class="keyword">print</span> <span class="string">"print_callback"</span>
+
+main = Tk()
+
+menubar = Menu(main)
+main.config(menu=menubar)
+
+file_menu = Menu(menubar)
+menubar.add_cascade(label=<span class="string">"File"</span>, underline=1, menu=file_menu)
+file_menu.add_command(label=<span class="string">"Print"</span>, command=print_callback)
+
+main.mainloop()
+
+<span class="comment-delimiter"># </span><span class="comment">using a class
+</span><span class="keyword">from</span> Tkinter <span class="keyword">import</span> *
+
+<span class="keyword">class</span> <span class="type">Application</span>(Tk):
+ <span class="keyword">def</span> <span class="function-name">print_callback</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="keyword">print</span> <span class="string">"print_callback"</span>
+ <span class="keyword">def</span> <span class="function-name">debug_callback</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="keyword">print</span> <span class="string">"debug:"</span>, <span class="py-pseudo-keyword">self</span>.debug.get()
+ <span class="keyword">print</span> <span class="string">"debug level:"</span>, <span class="py-pseudo-keyword">self</span>.debug_level.get()
+
+ <span class="keyword">def</span> <span class="function-name">createWidgets</span>(<span class="py-pseudo-keyword">self</span>):
+ menubar = Menu(<span class="py-pseudo-keyword">self</span>)
+ <span class="py-pseudo-keyword">self</span>.config(menu=menubar)
+ file_menu = Menu(menubar)
+ menubar.add_cascade(label=<span class="string">"File"</span>,
+ underline=1, menu=file_menu)
+ file_menu.add_command(label=<span class="string">"Print"</span>,
+ command=<span class="py-pseudo-keyword">self</span>.print_callback)
+ file_menu.add_command(label=<span class="string">"Quit Immediately"</span>,
+ command=sys.exit)
+ <span class="comment-delimiter"># </span><span class="comment">
+</span> options_menu = Menu(menubar)
+ menubar.add_cascade(label=<span class="string">"Options"</span>,
+ underline=0, menu=options_menu)
+ options_menu.add_checkbutton(
+ label=<span class="string">"Create Debugging File"</span>,
+ variable=<span class="py-pseudo-keyword">self</span>.debug,
+ command=<span class="py-pseudo-keyword">self</span>.debug_callback,
+ onvalue=1, offvalue=0)
+ options_menu.add_separator()
+ options_menu.add_radiobutton(
+ label = <span class="string">"Level 1"</span>,
+ variable = <span class="py-pseudo-keyword">self</span>.debug_level,
+ value = 1
+ )
+ options_menu.add_radiobutton(
+ label = <span class="string">"Level 2"</span>,
+ variable = <span class="py-pseudo-keyword">self</span>.debug_level,
+ value = 2
+ )
+ options_menu.add_radiobutton(
+ label = <span class="string">"Level 3"</span>,
+ variable = <span class="py-pseudo-keyword">self</span>.debug_level,
+ value = 3
+ )
+
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>, master=<span class="py-pseudo-keyword">None</span>):
+ Tk.__init__(<span class="py-pseudo-keyword">self</span>, master)
+ <span class="comment-delimiter"># </span><span class="comment">bound variables must be IntVar, StrVar, ...
+</span> <span class="py-pseudo-keyword">self</span>.debug = IntVar()
+ <span class="py-pseudo-keyword">self</span>.debug.set(0)
+ <span class="py-pseudo-keyword">self</span>.debug_level = IntVar()
+ <span class="py-pseudo-keyword">self</span>.debug_level.set(1)
+ <span class="py-pseudo-keyword">self</span>.createWidgets()
+
+app = Application()
+app.mainloop()</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN834"
+>Creating Dialog Boxes with Tk</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN837"
+>Responding to Tk Resize Events</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN840"
+>Removing the DOS Shell Window with Windows Perl/Tk</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">Start Python scripts without the annoying DOS window on win32
+</span><span class="comment-delimiter"># </span><span class="comment">Use extension ".pyw" on files - eg: "foo.pyw" instead of "foo.py"
+</span><span class="comment-delimiter"># </span><span class="comment">Or run programs using "pythonw.exe" rather than "python.exe"
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN843"
+>Program: Small termcap program</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN846"
+>Program: tkshufflepod</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+></DIV
+><DIV
+CLASS="NAVFOOTER"
+><HR
+ALIGN="LEFT"
+WIDTH="100%"><TABLE
+SUMMARY="Footer navigation table"
+WIDTH="100%"
+BORDER="0"
+CELLPADDING="0"
+CELLSPACING="0"
+><TR
+><TD
+WIDTH="33%"
+ALIGN="left"
+VALIGN="top"
+><A
+HREF="dbaccess.html"
+ACCESSKEY="P"
+>Prev</A
+></TD
+><TD
+WIDTH="34%"
+ALIGN="center"
+VALIGN="top"
+><A
+HREF="index.html"
+ACCESSKEY="H"
+>Home</A
+></TD
+><TD
+WIDTH="33%"
+ALIGN="right"
+VALIGN="top"
+><A
+HREF="processmanagementetc.html"
+ACCESSKEY="N"
+>Next</A
+></TD
+></TR
+><TR
+><TD
+WIDTH="33%"
+ALIGN="left"
+VALIGN="top"
+>Database Access</TD
+><TD
+WIDTH="34%"
+ALIGN="center"
+VALIGN="top"
+>&nbsp;</TD
+><TD
+WIDTH="33%"
+ALIGN="right"
+VALIGN="top"
+>Process Management and Communication</TD
+></TR
+></TABLE
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/help/PythonExamples/pleac_python/webautomation.html b/help/PythonExamples/pleac_python/webautomation.html
new file mode 100644
index 0000000..a10d377
--- /dev/null
+++ b/help/PythonExamples/pleac_python/webautomation.html
@@ -0,0 +1,975 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<HTML
+><HEAD
+><TITLE
+>Web Automation</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
+REL="HOME"
+TITLE="PLEAC-Python
+"
+HREF="index.html"><LINK
+REL="PREVIOUS"
+TITLE="CGI Programming"
+HREF="cgiprogramming.html"><LINK
+REL="NEXT"
+TITLE="Helpers"
+HREF="a1102.html"><style type="text/css"> <!--
+ .comment {
+ /* font-lock-comment-face */
+ color: #bebebe;
+ }
+ .comment-delimiter {
+ }
+ .function-name {
+ /* font-lock-function-name-face */
+ color: #b2dfee;
+ }
+ .keyword {
+ /* font-lock-keyword-face */
+ color: #ffa500;
+ }
+ .py-builtins {
+ /* py-builtins-face */
+ color: #ffa500;
+ }
+ .py-pseudo-keyword {
+ /* py-pseudo-keyword-face */
+ color: #ffa500;
+ }
+ .string {
+ /* font-lock-string-face */
+ color: #00cd00;
+ }
+ .type {
+ /* font-lock-type-face */
+ color: #98fb98;
+ }
+ -->
+ </style></head
+><BODY TEXT="#cecece" BGCOLOR="#4f6f6f" LINK="#f5deb3" VLINK="#d5ae83"
+CLASS="SECT1"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><DIV
+CLASS="NAVHEADER"
+><TABLE
+SUMMARY="Header navigation table"
+WIDTH="100%"
+BORDER="0"
+CELLPADDING="0"
+CELLSPACING="0"
+><TR
+><TH
+COLSPAN="3"
+ALIGN="center"
+>PLEAC-Python
+</TH
+></TR
+><TR
+><TD
+WIDTH="10%"
+ALIGN="left"
+VALIGN="bottom"
+><A
+HREF="cgiprogramming.html"
+ACCESSKEY="P"
+>Prev</A
+></TD
+><TD
+WIDTH="80%"
+ALIGN="center"
+VALIGN="bottom"
+></TD
+><TD
+WIDTH="10%"
+ALIGN="right"
+VALIGN="bottom"
+><A
+HREF="a1102.html"
+ACCESSKEY="N"
+>Next</A
+></TD
+></TR
+></TABLE
+><HR
+ALIGN="LEFT"
+WIDTH="100%"></DIV
+><DIV
+CLASS="SECT1"
+><H1
+CLASS="SECT1"
+><A
+NAME="WEBAUTOMATION"
+>20. Web Automation</A
+></H1
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN1054"
+>Introduction</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN1057"
+>Fetching a URL from a Perl Script</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> urllib
+content = urllib.urlopen(url).read()
+
+<span class="keyword">try:</span>
+ <span class="keyword">import</span> urllib
+ content = urllib.urlopen(url).read()
+<span class="keyword">except</span> <span class="py-builtins">IOError</span>:
+ <span class="keyword">print</span> <span class="string">"could not get %s"</span> % url
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="comment-delimiter"># </span><span class="comment"><font size="-1"><a href="http://pleac.sourceforge.net/include/python/ch20/titlebytes">download the following standalone program</a></font>
+</span><span class="comment-delimiter">#</span><span class="comment">!/usr/bin/python
+</span><span class="comment-delimiter"># </span><span class="comment">titlebytes - find the title and size of documents
+</span><span class="comment-delimiter">#</span><span class="comment">
+</span><span class="comment-delimiter"># </span><span class="comment">differences to perl
+</span><span class="comment-delimiter"># </span><span class="comment">
+</span><span class="comment-delimiter"># </span><span class="comment">* no URI::Heuristics
+</span><span class="comment-delimiter"># </span><span class="comment">* perl LWP supports fetching files from local system
+</span><span class="comment-delimiter"># </span><span class="comment">* fetching a title from ftp or file doesnt work in perl either.
+</span>
+<span class="keyword">import</span> sys, urllib2, HTMLParser
+<span class="keyword">if</span> <span class="py-builtins">len</span>(sys.argv)&lt;=1:
+ <span class="keyword">print</span> <span class="string">"usage: %s url"</span> % sys.argv[0]
+ sys.exit(1)
+raw_url = sys.argv[1]
+
+<span class="comment-delimiter"># </span><span class="comment">python has no equivalent to pearls URI::Heuristics, which
+</span><span class="comment-delimiter"># </span><span class="comment">would do some guessing like :
+</span><span class="comment-delimiter">#</span><span class="comment">
+</span><span class="comment-delimiter"># </span><span class="comment">perl -&gt; http://www.perl.com
+</span><span class="comment-delimiter"># </span><span class="comment">www.oreilly.com -&gt; http://www.oreilly.com
+</span><span class="comment-delimiter"># </span><span class="comment">ftp.funet.fi -&gt; ftp://ftp.funet.fi
+</span><span class="comment-delimiter"># </span><span class="comment">/etc/passwd -&gt; file:/etc/passwd
+</span>
+<span class="comment-delimiter"># </span><span class="comment">simple but pedantic html parser: tpj.com breaks it.
+</span><span class="keyword">class</span> <span class="type">html</span>(HTMLParser.HTMLParser):
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>):
+ HTMLParser.HTMLParser.__init__(<span class="py-pseudo-keyword">self</span>)
+ <span class="py-pseudo-keyword">self</span>._data = {}
+ <span class="py-pseudo-keyword">self</span>._open_tags = []
+ <span class="keyword">def</span> <span class="function-name">handle_starttag</span>(<span class="py-pseudo-keyword">self</span>, tag, attrs):
+ <span class="py-pseudo-keyword">self</span>._open_tags.append(tag)
+ <span class="keyword">def</span> <span class="function-name">handle_endtag</span>(<span class="py-pseudo-keyword">self</span>, tag):
+ <span class="keyword">if</span> <span class="py-builtins">len</span>(<span class="py-pseudo-keyword">self</span>._open_tags)&gt;0:
+ <span class="py-pseudo-keyword">self</span>._open_tags.pop()
+ <span class="keyword">def</span> <span class="function-name">handle_data</span>(<span class="py-pseudo-keyword">self</span>, data):
+ <span class="keyword">if</span> <span class="py-builtins">len</span>(<span class="py-pseudo-keyword">self</span>._open_tags)&gt;0:
+ <span class="py-pseudo-keyword">self</span>._data[<span class="py-pseudo-keyword">self</span>._open_tags[-1]] = data
+ <span class="keyword">def</span> <span class="function-name">__getattr__</span>(<span class="py-pseudo-keyword">self</span>,attr):
+ <span class="keyword">if</span> <span class="keyword">not</span> <span class="py-pseudo-keyword">self</span>._data.has_key(attr):
+ <span class="keyword">return</span> <span class="string">""</span>
+ <span class="keyword">return</span> <span class="py-pseudo-keyword">self</span>._data[attr]
+
+url = raw_url
+<span class="keyword">print</span> <span class="string">"%s =&gt;\n\t"</span> % url,
+<span class="comment-delimiter"># </span><span class="comment">TODO fake user agent "Schmozilla/v9.17 Platinum"
+</span><span class="comment-delimiter"># </span><span class="comment">TODO referer "http://wizard.yellowbrick.oz"
+</span><span class="comment-delimiter"># </span><span class="comment">as we only do http httplib would do also
+</span><span class="keyword">try:</span>
+ response = urllib2.urlopen(url)
+<span class="keyword">except:</span>
+ <span class="keyword">print</span> <span class="string">" %s"</span> % sys.exc_info()[1].reason[1]
+ sys.exit(1)
+<span class="comment-delimiter"># </span><span class="comment">title is not in response
+</span>data = response.read()
+parser = html()
+parser.feed(data)
+parser.close() <span class="comment-delimiter"># </span><span class="comment">force processing all data
+</span>count = <span class="py-builtins">len</span>(data.split(<span class="string">"\n"</span>))
+bytes = <span class="py-builtins">len</span>(data)
+<span class="keyword">print</span> <span class="string">"%s (%d lines, %d bytes)"</span> % (parser.title,
+ count,
+ bytes)
+
+<span class="comment-delimiter"># </span><span class="comment">omly bytes is in response.info()
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN1060"
+>Automating Form Submission</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span>
+<span class="comment-delimiter"># </span><span class="comment">GET method
+</span><span class="keyword">import</span> httplib
+conn = httplib.HTTPConnection(<span class="string">'www.perl.com'</span>)
+conn.request(<span class="string">'GET'</span>,<span class="string">'/cgi-bin/cpan_mod?module=DB_File&amp;readme=1'</span>)
+r1 = conn.getresponse()
+content = r1.read()
+
+<span class="comment-delimiter"># </span><span class="comment">POST method
+</span><span class="keyword">import</span> urllib
+params = urllib.urlencode({<span class="string">'module'</span>: <span class="string">'DB_File'</span>, <span class="string">'readme'</span>: 1})
+content = urllib.urlopen(<span class="string">'http://www.perl.com'</span>, params).read()
+
+<span class="comment-delimiter"># </span><span class="comment">fields must be properly escaped
+</span><span class="comment-delimiter"># </span><span class="comment">script.cgi?field1?arg=%22this%20isn%27t%20%3CEASY%3E%22
+</span>
+<span class="comment-delimiter"># </span><span class="comment">proxies can be taken from environment, or specified
+</span><span class="comment-delimiter"># </span><span class="comment">as the optional thrid parameter to urlopen.
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN1063"
+>Extracting URLs</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment"><font size="-1"><a href="http://pleac.sourceforge.net/include/python/ch20/xurl">download the following standalone program</a></font>
+</span><span class="comment-delimiter">#</span><span class="comment">!/usr/bin/python
+</span><span class="comment-delimiter"># </span><span class="comment">xurl - extract unique, sorted list of links from URL
+</span>
+<span class="keyword">from</span> HTMLParser <span class="keyword">import</span> HTMLParser
+<span class="keyword">import</span> urllib
+<span class="keyword">from</span> sets <span class="keyword">import</span> Set <span class="keyword">as</span> set <span class="comment-delimiter"># </span><span class="comment">not needed in 2.4
+</span><span class="keyword">class</span> <span class="type">myParser</span>(HTMLParser):
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>, url):
+ <span class="py-pseudo-keyword">self</span>.baseUrl = url[:url.rfind(<span class="string">'/'</span>)]
+ HTMLParser.__init__(<span class="py-pseudo-keyword">self</span>)
+ <span class="keyword">def</span> <span class="function-name">reset</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="py-pseudo-keyword">self</span>.urls = set()
+ HTMLParser.reset(<span class="py-pseudo-keyword">self</span>)
+ <span class="keyword">def</span> <span class="function-name">handle_starttag</span>(<span class="py-pseudo-keyword">self</span>, tag, attrs):
+ <span class="keyword">if</span> tag == <span class="string">'a'</span>:
+ <span class="keyword">if</span> attrs[0][0] == <span class="string">'href'</span>:
+ <span class="keyword">if</span> attrs[0][1].find(<span class="string">':'</span>) == -1:
+ <span class="comment-delimiter"># </span><span class="comment">we need to add the base URL.
+</span> <span class="py-pseudo-keyword">self</span>.urls.add(<span class="py-pseudo-keyword">self</span>.baseUrl + <span class="string">'/'</span> + attrs[0][1])
+ <span class="keyword">else:</span>
+ <span class="py-pseudo-keyword">self</span>.urls.add(attrs[0][1])
+url = <span class="string">'http://www.perl.com/CPAN'</span>
+p = myParser(url)
+s = urllib.urlopen(url)
+data = s.read()
+p.feed(data)
+urllist = p.urls._data.keys()
+urllist.sort()
+<span class="keyword">print</span> <span class="string">'\n'</span>.join(urllist)</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN1066"
+>Converting ASCII to HTML</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">Converting ASCII to HTML
+</span>
+<span class="comment-delimiter"># </span><span class="comment"><font size="-1"><a href="http://pleac.sourceforge.net/include/python/ch20/text2html">download the following standalone program</a></font>
+</span><span class="comment-delimiter">#</span><span class="comment">!/usr/bin/python
+</span><span class="comment-delimiter"># </span><span class="comment">text2html - trivial html encoding of normal text
+</span>
+<span class="keyword">import</span> sys
+<span class="keyword">import</span> re
+
+<span class="comment-delimiter"># </span><span class="comment">precompile regular expressions
+</span>re_quoted = re.compile(r<span class="string">"(?m)^(&gt;.*?)$"</span>)
+re_url = re.compile(r<span class="string">"&lt;URL:(.*)&gt;"</span>)
+re_http = re.compile(r<span class="string">"(http:\S+)"</span>)
+re_strong = re.compile(r<span class="string">"\*(\S+)\*"</span>)
+re_em = re.compile(r<span class="string">"\b_(\S+)_\b"</span>)
+
+<span class="comment-delimiter"># </span><span class="comment">split paragraphs
+</span><span class="keyword">for</span> para <span class="keyword">in</span> <span class="py-builtins">open</span>(sys.argv[1]).read().split(<span class="string">"\n\n"</span>):
+ <span class="comment-delimiter"># </span><span class="comment">TODO encode entities: dont encode "&lt;&gt;" but do "&amp;"
+</span> <span class="keyword">if</span> para.startswith(<span class="string">" "</span>):
+ <span class="keyword">print</span> <span class="string">"&lt;pre&gt;\n%s\n&lt;/pre&gt;"</span> % para
+ <span class="keyword">else:</span>
+ para = re_quoted.sub(r<span class="string">"\1&lt;br /&gt;"</span>, para) <span class="comment-delimiter"># </span><span class="comment">quoted text
+</span> para = re_url.sub(r<span class="string">'&lt;a href="\1"&gt;\1&lt;/a&gt;'</span>, para) <span class="comment-delimiter"># </span><span class="comment">embedded URL
+</span> para = re_http.sub(r<span class="string">'&lt;a href="\1"&gt;\1&lt;/a&gt;'</span>, para) <span class="comment-delimiter"># </span><span class="comment">guessed URL
+</span> para = re_strong.sub(r<span class="string">"&lt;strong&gt;\1&lt;/strong&gt;"</span>,para) <span class="comment-delimiter"># </span><span class="comment">this is *bold* here
+</span> para = re_em.sub(r<span class="string">"&lt;em&gt;\1&lt;/em&gt;"</span>,para) <span class="comment-delimiter"># </span><span class="comment">this is _italic_ here
+</span> <span class="keyword">print</span> <span class="string">"&lt;p&gt;\n%s\n&lt;/p&gt;"</span> % para <span class="comment-delimiter"># </span><span class="comment">add paragraph tags
+</span>
+
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> sys, re
+<span class="keyword">import</span> htmlentitydefs
+
+<span class="keyword">def</span> <span class="function-name">encode_entities</span>(s):
+ <span class="keyword">for</span> k,v <span class="keyword">in</span> htmlentitydefs.codepoint2name.items():
+ <span class="keyword">if</span> k&lt;256: <span class="comment-delimiter"># </span><span class="comment">no unicodes
+</span> s = s.replace(<span class="py-builtins">chr</span>(k),<span class="string">"&amp;%s;"</span>%v)
+ <span class="keyword">return</span> s
+
+<span class="keyword">print</span> <span class="string">"&lt;table&gt;"</span>
+text = sys.stdin.read()
+text = encode_entities(text)
+text = re.sub(r<span class="string">"(\n[ \t]+)"</span>,<span class="string">" . "</span>,text) <span class="comment-delimiter"># </span><span class="comment">continuation lines
+</span>text = re.sub(r<span class="string">"(?m)^(\S+?:)\s*(.*?)$"</span>,
+ r<span class="string">'&lt;tr&gt;&lt;th align="left"&gt;\1&lt;/th&gt;&lt;td&gt;\2&lt;/td&gt;&lt;/tr&gt;'</span>,
+ text);
+<span class="keyword">print</span> text
+<span class="keyword">print</span> <span class="string">"&lt;/table&gt;"</span>
+ </PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN1069"
+>Converting HTML to ASCII</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">Converting HTML to ASCII
+</span>
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> os
+ascii = os.popen(<span class="string">"lynx -dump "</span> + filename).read()
+
+<span class="comment-delimiter">#</span><span class="comment">-----------------------------
+</span><span class="keyword">import</span> formatter
+<span class="keyword">import</span> htmllib
+
+w = formatter.DumbWriter()
+f = formatter.AbstractFormatter(w)
+p = htmllib.HTMLParser(f)
+p.feed(html)
+p.close()
+
+<span class="comment-delimiter"># </span><span class="comment">Above is a bare minimum to use writer/formatter/parser
+</span><span class="comment-delimiter"># </span><span class="comment">framework of Python.
+</span>
+<span class="comment-delimiter"># </span><span class="comment">Search Python Cookbook for more details, like writing
+</span><span class="comment-delimiter"># </span><span class="comment">your own writers or formatters.
+</span>
+<span class="comment-delimiter"># </span><span class="comment">Recipe #52297 has TtyFormatter, formatting underline
+</span><span class="comment-delimiter"># </span><span class="comment">and bold in Terminal. Recipe #135005 has a writer
+</span><span class="comment-delimiter"># </span><span class="comment">accumulating text instead of printing.
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN1072"
+>Extracting or Removing HTML Tags</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span>
+<span class="keyword">import</span> re
+
+plain_text = re.sub(r<span class="string">"&lt;[^&gt;]*&gt;"</span>,<span class="string">""</span>,html_text) <span class="comment-delimiter">#</span><span class="comment">WRONG
+</span>
+<span class="comment-delimiter"># </span><span class="comment">using HTMLParser
+</span><span class="keyword">import</span> sys, HTMLParser
+
+<span class="keyword">class</span> <span class="type">html</span>(HTMLParser.HTMLParser):
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>):
+ HTMLParser.HTMLParser.__init__(<span class="py-pseudo-keyword">self</span>)
+ <span class="py-pseudo-keyword">self</span>._plaintext = <span class="string">""</span>
+ <span class="py-pseudo-keyword">self</span>._ignore = <span class="py-pseudo-keyword">False</span>
+ <span class="keyword">def</span> <span class="function-name">handle_starttag</span>(<span class="py-pseudo-keyword">self</span>, tag, attrs):
+ <span class="keyword">if</span> tag == <span class="string">"script"</span>:
+ <span class="py-pseudo-keyword">self</span>._ignore = <span class="py-pseudo-keyword">True</span>
+ <span class="keyword">def</span> <span class="function-name">handle_endtag</span>(<span class="py-pseudo-keyword">self</span>, tag):
+ <span class="keyword">if</span> tag == <span class="string">"script"</span>:
+ <span class="py-pseudo-keyword">self</span>._ignore = <span class="py-pseudo-keyword">False</span>
+ <span class="keyword">def</span> <span class="function-name">handle_data</span>(<span class="py-pseudo-keyword">self</span>, data):
+ <span class="keyword">if</span> <span class="py-builtins">len</span>(data)&gt;0 <span class="keyword">and</span> <span class="keyword">not</span> <span class="py-pseudo-keyword">self</span>._ignore:
+ <span class="py-pseudo-keyword">self</span>._plaintext += data
+ <span class="keyword">def</span> <span class="function-name">get_plaintext</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="keyword">return</span> <span class="py-pseudo-keyword">self</span>._plaintext
+ <span class="keyword">def</span> <span class="function-name">error</span>(<span class="py-pseudo-keyword">self</span>,msg):
+ <span class="comment-delimiter"># </span><span class="comment">ignore all errors
+</span> <span class="keyword">pass</span>
+
+html_text = <span class="py-builtins">open</span>(sys.argv[1]).read()
+
+parser = html()
+parser.feed(html_text)
+parser.close() <span class="comment-delimiter"># </span><span class="comment">force processing all data
+</span><span class="keyword">print</span> parser.get_plaintext()
+
+title_s = re.search(r<span class="string">"(?i)&lt;title&gt;\s*(.*?)\s*&lt;/title&gt;"</span>, text)
+title = title_s <span class="keyword">and</span> title_s.groups()[0] <span class="keyword">or</span> <span class="string">"NO TITLE"</span>
+
+<span class="comment-delimiter"># </span><span class="comment"><font size="-1"><a href="http://pleac.sourceforge.net/include/python/ch20/htitle">download the following standalone program</a></font>
+</span><span class="comment-delimiter">#</span><span class="comment">!/usr/bin/python
+</span><span class="comment-delimiter"># </span><span class="comment">htitlebytes - get html title from URL
+</span><span class="comment-delimiter">#</span><span class="comment">
+</span>
+<span class="keyword">import</span> sys, urllib2, HTMLParser
+<span class="keyword">if</span> <span class="py-builtins">len</span>(sys.argv)&lt;=1:
+ <span class="keyword">print</span> <span class="string">"usage: %s url ..."</span> % sys.argv[0]
+ sys.exit(1)
+
+<span class="comment-delimiter"># </span><span class="comment">simple but pedantic html parser: tpj.com breaks it.
+</span><span class="keyword">class</span> <span class="type">html</span>(HTMLParser.HTMLParser):
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>):
+ HTMLParser.HTMLParser.__init__(<span class="py-pseudo-keyword">self</span>)
+ <span class="py-pseudo-keyword">self</span>._data = {}
+ <span class="py-pseudo-keyword">self</span>._open_tags = []
+ <span class="keyword">def</span> <span class="function-name">handle_starttag</span>(<span class="py-pseudo-keyword">self</span>, tag, attrs):
+ <span class="py-pseudo-keyword">self</span>._open_tags.append(tag)
+ <span class="keyword">def</span> <span class="function-name">handle_endtag</span>(<span class="py-pseudo-keyword">self</span>, tag):
+ <span class="keyword">if</span> <span class="py-builtins">len</span>(<span class="py-pseudo-keyword">self</span>._open_tags)&gt;0:
+ <span class="py-pseudo-keyword">self</span>._open_tags.pop()
+ <span class="keyword">def</span> <span class="function-name">handle_data</span>(<span class="py-pseudo-keyword">self</span>, data):
+ <span class="keyword">if</span> <span class="py-builtins">len</span>(<span class="py-pseudo-keyword">self</span>._open_tags)&gt;0:
+ <span class="py-pseudo-keyword">self</span>._data[<span class="py-pseudo-keyword">self</span>._open_tags[-1]] = data
+ <span class="keyword">def</span> <span class="function-name">__getattr__</span>(<span class="py-pseudo-keyword">self</span>,attr):
+ <span class="keyword">if</span> <span class="keyword">not</span> <span class="py-pseudo-keyword">self</span>._data.has_key(attr):
+ <span class="keyword">return</span> <span class="string">""</span>
+ <span class="keyword">return</span> <span class="py-pseudo-keyword">self</span>._data[attr]
+ <span class="keyword">def</span> <span class="function-name">error</span>(<span class="py-pseudo-keyword">self</span>,msg):
+ <span class="comment-delimiter"># </span><span class="comment">ignore all errors
+</span> <span class="keyword">pass</span>
+
+<span class="keyword">for</span> url <span class="keyword">in</span> sys.argv[1:]:
+ <span class="keyword">print</span> <span class="string">"%s: "</span> % url,
+ <span class="comment-delimiter"># </span><span class="comment">TODO fake user agent "Schmozilla/v9.17 Platinum"
+</span> <span class="comment-delimiter"># </span><span class="comment">TODO referer "http://wizard.yellowbrick.oz"
+</span> <span class="comment-delimiter"># </span><span class="comment">as we only do http httplib would do also
+</span> <span class="keyword">try:</span>
+ response = urllib2.urlopen(url)
+ <span class="keyword">except:</span>
+ <span class="keyword">print</span> <span class="string">" %s"</span> % sys.exc_info()[1]
+ sys.exit(1)
+ <span class="comment-delimiter"># </span><span class="comment">title is not in response
+</span> parser = html()
+ parser.feed(response.read())
+ parser.close() <span class="comment-delimiter"># </span><span class="comment">force processing all data
+</span> <span class="keyword">print</span> parser.title </PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN1075"
+>Finding Stale Links</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment"><font size="-1"><a href="http://pleac.sourceforge.net/include/python/ch20/churl">download the following standalone program</a></font>
+</span><span class="comment-delimiter">#</span><span class="comment">!/usr/bin/python
+</span><span class="comment-delimiter"># </span><span class="comment">churl - check urls
+</span>
+<span class="keyword">import</span> sys
+
+<span class="comment-delimiter"># </span><span class="comment">head request
+</span><span class="keyword">import</span> urllib
+<span class="keyword">def</span> <span class="function-name">valid</span>(url):
+ <span class="keyword">try:</span>
+ conn = urllib.urlopen(url)
+ <span class="keyword">return</span> 1
+ <span class="keyword">except:</span>
+ <span class="keyword">return</span> 0
+
+<span class="comment-delimiter"># </span><span class="comment">parser class as in xurl
+</span><span class="keyword">from</span> HTMLParser <span class="keyword">import</span> HTMLParser
+<span class="keyword">from</span> sets <span class="keyword">import</span> Set <span class="keyword">as</span> set <span class="comment-delimiter"># </span><span class="comment">not needed in 2.4
+</span><span class="keyword">class</span> <span class="type">myParser</span>(HTMLParser):
+ <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>, url):
+ <span class="py-pseudo-keyword">self</span>.baseUrl = url[:url.rfind(<span class="string">'/'</span>)]
+ HTMLParser.__init__(<span class="py-pseudo-keyword">self</span>)
+ <span class="keyword">def</span> <span class="function-name">reset</span>(<span class="py-pseudo-keyword">self</span>):
+ <span class="py-pseudo-keyword">self</span>.urls = set()
+ HTMLParser.reset(<span class="py-pseudo-keyword">self</span>)
+ <span class="keyword">def</span> <span class="function-name">handle_starttag</span>(<span class="py-pseudo-keyword">self</span>, tag, attrs):
+ <span class="keyword">if</span> tag == <span class="string">'a'</span>:
+ <span class="keyword">if</span> attrs[0][0] == <span class="string">'href'</span>:
+ <span class="keyword">if</span> attrs[0][1].find(<span class="string">':'</span>) == -1:
+ <span class="comment-delimiter"># </span><span class="comment">we need to add the base URL.
+</span> <span class="py-pseudo-keyword">self</span>.urls.add(<span class="py-pseudo-keyword">self</span>.baseUrl + <span class="string">'/'</span> + attrs[0][1])
+ <span class="keyword">else:</span>
+ <span class="py-pseudo-keyword">self</span>.urls.add(attrs[0][1])
+
+<span class="keyword">if</span> <span class="py-builtins">len</span>(sys.argv)&lt;=1:
+ <span class="keyword">print</span> <span class="string">"usage: %s &lt;start_url&gt;"</span> % (sys.argv[0])
+ sys.exit(1)
+
+base_url = sys.argv[1]
+<span class="keyword">print</span> base_url+<span class="string">":"</span>
+p = myParser(base_url)
+s = urllib.urlopen(base_url)
+data = s.read()
+p.feed(data)
+<span class="keyword">for</span> link <span class="keyword">in</span> p.urls._data.keys():
+ state = <span class="string">"UNKNOWN URL"</span>
+ <span class="keyword">if</span> link.startswith(<span class="string">"http:"</span>):
+ state = <span class="string">"BAD"</span>
+ <span class="keyword">if</span> valid(link):
+ state = <span class="string">"OK"</span>
+ <span class="keyword">print</span> <span class="string">" %s: %s"</span> % (link, state)</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN1078"
+>Finding Fresh Links</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment"><font size="-1"><a href="http://pleac.sourceforge.net/include/python/ch20/surl">download the following standalone program</a></font>
+</span><span class="comment-delimiter">#</span><span class="comment">!/usr/bin/python
+</span><span class="comment-delimiter"># </span><span class="comment">surl - sort URLs by their last modification date
+</span>
+<span class="keyword">import</span> urllib
+<span class="keyword">import</span> time
+<span class="keyword">import</span> sys
+
+Date = {}
+<span class="keyword">while</span> 1:
+ <span class="comment-delimiter"># </span><span class="comment">we only read from stdin not from argv.
+</span> ln = sys.stdin.readline()
+ <span class="keyword">if</span> <span class="keyword">not</span> ln:
+ <span class="keyword">break</span>
+ ln = ln.strip()
+ <span class="keyword">try:</span>
+ u = urllib.urlopen(ln)
+ date = time.mktime(u.info().getdate(<span class="string">"date"</span>))
+ <span class="keyword">if</span> <span class="keyword">not</span> Date.has_key(date):
+ Date[date] = []
+ Date[date].append(ln)
+ <span class="keyword">except:</span>
+ sys.stderr.write(<span class="string">"%s: %s!\n"</span> % (ln, sys.exc_info()[1]))
+
+dates = Date.keys()
+dates.sort() <span class="comment-delimiter"># </span><span class="comment">python 2.4 would have sorted
+</span><span class="keyword">for</span> d <span class="keyword">in</span> dates:
+ <span class="keyword">print</span> <span class="string">"%s %s"</span> % (time.strftime(<span class="string">"%Y-%m-%d %H:%M:%S"</span>, time.localtime(d)),
+ <span class="string">", "</span>.join(Date[d]))</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN1081"
+>Creating HTML Templates</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="keyword">import</span> re
+
+<span class="keyword">def</span> <span class="function-name">template</span>(filename, fillings):
+ text = <span class="py-builtins">open</span>(filename).read()
+ <span class="keyword">def</span> <span class="function-name">repl</span>(matchobj):
+ <span class="keyword">if</span> fillings.has_key(matchobj.group(1)):
+ <span class="keyword">return</span> <span class="py-builtins">str</span>(fillings[matchobj.group(1)])
+ <span class="keyword">return</span> <span class="string">""</span>
+ <span class="comment-delimiter"># </span><span class="comment">replace quoted words with value from fillings dictionary
+</span> text = re.sub(<span class="string">"%%(.+?)%%"</span>, repl, text)
+ <span class="keyword">return</span> text
+
+fields = { <span class="string">"username"</span>:<span class="string">"peter"</span>, <span class="string">"count"</span>:<span class="string">"23"</span>, <span class="string">"total"</span>: <span class="string">"1234"</span>}
+<span class="keyword">print</span> template(<span class="string">"/home/httpd/templates/simple.template"</span>, fields)
+
+<span class="comment-delimiter"># </span><span class="comment"><font size="-1"><a href="http://pleac.sourceforge.net/include/python/ch20/userrep1">download the following standalone program</a></font>
+</span><span class="comment-delimiter">#</span><span class="comment">!/usr/bin/python
+</span><span class="comment-delimiter"># </span><span class="comment">userrep1 - report duration of user logins using SQL database
+</span>
+<span class="keyword">import</span> MySQLdb
+<span class="keyword">import</span> cgi
+<span class="keyword">import</span> re
+<span class="keyword">import</span> sys
+
+<span class="keyword">def</span> <span class="function-name">template</span>(filename, fillings):
+ text = <span class="py-builtins">open</span>(filename).read()
+ <span class="keyword">def</span> <span class="function-name">repl</span>(matchobj):
+ <span class="keyword">if</span> fillings.has_key(matchobj.group(1)):
+ <span class="keyword">return</span> <span class="py-builtins">str</span>(fillings[matchobj.group(1)])
+ <span class="keyword">return</span> <span class="string">""</span>
+ <span class="comment-delimiter"># </span><span class="comment">replace quoted words with value from fillings dictionary
+</span> text = re.sub(<span class="string">"%%(.+?)%%"</span>, repl, text)
+ <span class="keyword">return</span> text
+
+fields = cgi.FieldStorage()
+<span class="keyword">if</span> <span class="keyword">not</span> fields.has_key(<span class="string">"user"</span>):
+ <span class="keyword">print</span> <span class="string">"Content-Type: text/plain\n"</span>
+ <span class="keyword">print</span> <span class="string">"No username"</span>
+ sys.exit(1)
+
+<span class="keyword">def</span> <span class="function-name">get_userdata</span>(username):
+ db = MySQLdb.connect(passwd=<span class="string">""</span>,db=<span class="string">"connections"</span>, user=<span class="string">"bert"</span>)
+ db.query(<span class="string">"select count(duration) as count,"</span>
+ +<span class="string">" sum(duration) as total from logins"</span>
+ +<span class="string">" where username='%s'"</span> % username)
+ res = db.store_result().fetch_row(maxrows=1,how=1)
+ res[0][<span class="string">"username"</span>] = username
+ db.close()
+ <span class="keyword">return</span> res[0]
+
+<span class="keyword">print</span> <span class="string">"Content-Type: text/html\n"</span>
+
+<span class="keyword">print</span> template(<span class="string">"report.tpl"</span>, get_userdata(fields[<span class="string">"user"</span>].value))
+
+<span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN1084"
+>Mirroring Web Pages</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN1087"
+>Creating a Robot</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN1090"
+>Parsing a Web Server Log File</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span>
+<span class="comment-delimiter"># </span><span class="comment">sample data, use ``LOGFILE = open(sys.argv[1])`` in real life
+</span>LOGFILE = [
+ <span class="string">'127.0.0.1 - - [04/Sep/2005:20:50:31 +0200] "GET /bus HTTP/1.1" 301 303\n'</span>,
+ <span class="string">'127.0.0.1 - - [04/Sep/2005:20:50:31 +0200] "GET /bus HTTP/1.1" 301 303 "-" "Opera/8.02 (X11; Linux i686; U; en)"\n'</span>,
+ <span class="string">'192.168.0.1 - - [04/Sep/2005:20:50:36 +0200] "GET /bus/libjs/layersmenu-library.js HTTP/1.1" 200 6228\n'</span>,
+ <span class="string">'192.168.0.1 - - [04/Sep/2005:20:50:36 +0200] "GET /bus/libjs/layersmenu-library.js HTTP/1.1" 200 6228 "http://localhost/bus/" "Opera/8.02 (X11; Linux i686; U; en)"\n'</span>,
+ ]
+
+<span class="keyword">import</span> re
+
+<span class="comment-delimiter"># </span><span class="comment">similar too perl version.
+</span>web_server_log_re = re.compile(r<span class="string">'^(\S+) (\S+) (\S+) \[([^:]+):(\d+:\d+:\d+) ([^\]]+)\] "(\S+) (.*?) (\S+)" (\S+) (\S+)$'</span>)
+
+<span class="comment-delimiter"># </span><span class="comment">with group naming.
+</span>split_re = re.compile(r<span class="string">'''(?x) # allow nicer formatting (but requires escaping blanks)
+ ^(?P&lt;client&gt;\S+)\s
+ (?P&lt;identuser&gt;\S+)\s
+ (?P&lt;authuser&gt;\S+)\s
+ \[
+ (?P&lt;date&gt;[^:]+):
+ (?P&lt;time&gt;[\d:]+)\s
+ (?P&lt;tz&gt;[^\]]+)
+ \]\s
+ "
+ (?P&lt;method&gt;\S+)\s
+ (?P&lt;url&gt;.*?)\s
+ (?P&lt;protocol&gt;\S+)
+ "\s
+ (?P&lt;status&gt;\S+)\s
+ (?P&lt;bytes&gt;\S+)
+ (?:
+ \s
+ "
+ (?P&lt;referrer&gt;[^"]+)
+ "\s
+ "
+ (?P&lt;agent&gt;[^"]+)
+ "
+ )?'''</span>)
+<span class="keyword">for</span> line <span class="keyword">in</span> LOGFILE:
+ f = split_re.match(line)
+ <span class="keyword">if</span> f:
+ <span class="keyword">print</span> <span class="string">"agent = %s"</span> % f.groupdict()[<span class="string">'agent'</span>]</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN1093"
+>Processing Server Logs</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN1096"
+>Program: htmlsub</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+><font color="#f5deb3" size="+1"><span class="comment-delimiter"></span><span class="comment"></span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span><span class="comment-delimiter"># </span><span class="comment">@@INCOMPLETE@@
+</span></pre>
+ </body>
+</html></PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT2"
+><H2
+CLASS="SECT2"
+><A
+NAME="AEN1099"
+>Program: hrefsub</A
+></H2
+><TABLE
+BORDER="0"
+BGCOLOR="#2F4F4F"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+></PRE
+></TD
+></TR
+></TABLE
+></DIV
+></DIV
+><DIV
+CLASS="NAVFOOTER"
+><HR
+ALIGN="LEFT"
+WIDTH="100%"><TABLE
+SUMMARY="Footer navigation table"
+WIDTH="100%"
+BORDER="0"
+CELLPADDING="0"
+CELLSPACING="0"
+><TR
+><TD
+WIDTH="33%"
+ALIGN="left"
+VALIGN="top"
+><A
+HREF="cgiprogramming.html"
+ACCESSKEY="P"
+>Prev</A
+></TD
+><TD
+WIDTH="34%"
+ALIGN="center"
+VALIGN="top"
+><A
+HREF="index.html"
+ACCESSKEY="H"
+>Home</A
+></TD
+><TD
+WIDTH="33%"
+ALIGN="right"
+VALIGN="top"
+><A
+HREF="a1102.html"
+ACCESSKEY="N"
+>Next</A
+></TD
+></TR
+><TR
+><TD
+WIDTH="33%"
+ALIGN="left"
+VALIGN="top"
+>CGI Programming</TD
+><TD
+WIDTH="34%"
+ALIGN="center"
+VALIGN="top"
+>&nbsp;</TD
+><TD
+WIDTH="33%"
+ALIGN="right"
+VALIGN="top"
+>Helpers</TD
+></TR
+></TABLE
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/help/PythonTutorial/_sources/tutorial/index.txt b/help/PythonTutorial/_sources/tutorial/index.txt
new file mode 100644
index 0000000..8a1a8fb
--- /dev/null
+++ b/help/PythonTutorial/_sources/tutorial/index.txt
@@ -0,0 +1,62 @@
+.. _tutorial-index:
+
+######################
+ The Python Tutorial
+######################
+
+:Release: |version|
+:Date: |today|
+
+Python is an easy to learn, powerful programming language. It has efficient
+high-level data structures and a simple but effective approach to
+object-oriented programming. Python's elegant syntax and dynamic typing,
+together with its interpreted nature, make it an ideal language for scripting
+and rapid application development in many areas on most platforms.
+
+The Python interpreter and the extensive standard library are freely available
+in source or binary form for all major platforms from the Python Web site,
+http://www.python.org/, and may be freely distributed. The same site also
+contains distributions of and pointers to many free third party Python modules,
+programs and tools, and additional documentation.
+
+The Python interpreter is easily extended with new functions and data types
+implemented in C or C++ (or other languages callable from C). Python is also
+suitable as an extension language for customizable applications.
+
+This tutorial introduces the reader informally to the basic concepts and
+features of the Python language and system. It helps to have a Python
+interpreter handy for hands-on experience, but all examples are self-contained,
+so the tutorial can be read off-line as well.
+
+For a description of standard objects and modules, see the Python Library
+Reference document. The Python Reference Manual gives a more formal definition
+of the language. To write extensions in C or C++, read Extending and Embedding
+the Python Interpreter and Python/C API Reference. There are also several books
+covering Python in depth.
+
+This tutorial does not attempt to be comprehensive and cover every single
+feature, or even every commonly used feature. Instead, it introduces many of
+Python's most noteworthy features, and will give you a good idea of the
+language's flavor and style. After reading it, you will be able to read and
+write Python modules and programs, and you will be ready to learn more about the
+various Python library modules described in the Python Library Reference.
+
+The :ref:`glossary` is also worth going through.
+
+.. toctree::
+ :numbered:
+
+ appetite.rst
+ interpreter.rst
+ introduction.rst
+ controlflow.rst
+ datastructures.rst
+ modules.rst
+ inputoutput.rst
+ errors.rst
+ classes.rst
+ stdlib.rst
+ stdlib2.rst
+ whatnow.rst
+ interactive.rst
+ floatingpoint.rst
diff --git a/help/PythonTutorial/_static/default.css b/help/PythonTutorial/_static/default.css
new file mode 100644
index 0000000..c999f67
--- /dev/null
+++ b/help/PythonTutorial/_static/default.css
@@ -0,0 +1,210 @@
+/**
+ * Sphinx stylesheet -- default theme
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+@import url("basic.css");
+
+/* -- page layout ----------------------------------------------------------- */
+
+body {
+ font-family: sans-serif;
+ font-size: 100%;
+ background-color: #11303d;
+ color: #000;
+ margin: 0;
+ padding: 0;
+}
+
+div.document {
+ background-color: #1c4e63;
+}
+
+div.documentwrapper {
+ float: left;
+ width: 100%;
+}
+
+div.bodywrapper {
+ margin: 0 0 0 230px;
+}
+
+div.body {
+ background-color: #ffffff;
+ color: #000000;
+ padding: 0 20px 30px 20px;
+}
+
+div.footer {
+ color: #ffffff;
+ width: 100%;
+ padding: 9px 0 9px 0;
+ text-align: center;
+ font-size: 75%;
+}
+
+div.footer a {
+ color: #ffffff;
+ text-decoration: underline;
+}
+
+div.related {
+ background-color: #133f52;
+ line-height: 30px;
+ color: #ffffff;
+}
+
+div.related a {
+ color: #ffffff;
+}
+
+div.sphinxsidebar {
+}
+
+div.sphinxsidebar h3 {
+ font-family: 'Trebuchet MS', sans-serif;
+ color: #ffffff;
+ font-size: 1.4em;
+ font-weight: normal;
+ margin: 0;
+ padding: 0;
+}
+
+div.sphinxsidebar h3 a {
+ color: #ffffff;
+}
+
+div.sphinxsidebar h4 {
+ font-family: 'Trebuchet MS', sans-serif;
+ color: #ffffff;
+ font-size: 1.3em;
+ font-weight: normal;
+ margin: 5px 0 0 0;
+ padding: 0;
+}
+
+div.sphinxsidebar p {
+ color: #ffffff;
+}
+
+div.sphinxsidebar p.topless {
+ margin: 5px 10px 10px 10px;
+}
+
+div.sphinxsidebar ul {
+ margin: 10px;
+ padding: 0;
+ color: #ffffff;
+}
+
+div.sphinxsidebar a {
+ color: #98dbcc;
+}
+
+div.sphinxsidebar input {
+ border: 1px solid #98dbcc;
+ font-family: sans-serif;
+ font-size: 1em;
+}
+
+/* -- body styles ----------------------------------------------------------- */
+
+a {
+ color: #355f7c;
+ text-decoration: none;
+}
+
+a:hover {
+ text-decoration: underline;
+}
+
+div.body p, div.body dd, div.body li {
+ text-align: justify;
+ line-height: 130%;
+}
+
+div.body h1,
+div.body h2,
+div.body h3,
+div.body h4,
+div.body h5,
+div.body h6 {
+ font-family: 'Trebuchet MS', sans-serif;
+ background-color: #f2f2f2;
+ font-weight: normal;
+ color: #20435c;
+ border-bottom: 1px solid #ccc;
+ margin: 20px -20px 10px -20px;
+ padding: 3px 0 3px 10px;
+}
+
+div.body h1 { margin-top: 0; font-size: 200%; }
+div.body h2 { font-size: 160%; }
+div.body h3 { font-size: 140%; }
+div.body h4 { font-size: 120%; }
+div.body h5 { font-size: 110%; }
+div.body h6 { font-size: 100%; }
+
+a.headerlink {
+ color: #c60f0f;
+ font-size: 0.8em;
+ padding: 0 4px 0 4px;
+ text-decoration: none;
+}
+
+a.headerlink:hover {
+ background-color: #c60f0f;
+ color: white;
+}
+
+div.body p, div.body dd, div.body li {
+ text-align: justify;
+ line-height: 130%;
+}
+
+div.admonition p.admonition-title + p {
+ display: inline;
+}
+
+div.note {
+ background-color: #eee;
+ border: 1px solid #ccc;
+}
+
+div.seealso {
+ background-color: #ffc;
+ border: 1px solid #ff6;
+}
+
+div.topic {
+ background-color: #eee;
+}
+
+div.warning {
+ background-color: #ffe4e4;
+ border: 1px solid #f66;
+}
+
+p.admonition-title {
+ display: inline;
+}
+
+p.admonition-title:after {
+ content: ":";
+}
+
+pre {
+ padding: 5px;
+ background-color: #eeffcc;
+ color: #333333;
+ line-height: 120%;
+ border: 1px solid #ac9;
+ border-left: none;
+ border-right: none;
+}
+
+tt {
+ background-color: #ecf0f3;
+ padding: 0 1px 0 1px;
+ font-size: 0.95em;
+} \ No newline at end of file
diff --git a/help/PythonTutorial/_static/doctools.js b/help/PythonTutorial/_static/doctools.js
new file mode 100644
index 0000000..9447678
--- /dev/null
+++ b/help/PythonTutorial/_static/doctools.js
@@ -0,0 +1,232 @@
+/// XXX: make it cross browser
+
+/**
+ * make the code below compatible with browsers without
+ * an installed firebug like debugger
+ */
+if (!window.console || !console.firebug) {
+ var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml",
+ "group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"];
+ window.console = {};
+ for (var i = 0; i < names.length; ++i)
+ window.console[names[i]] = function() {}
+}
+
+/**
+ * small helper function to urldecode strings
+ */
+jQuery.urldecode = function(x) {
+ return decodeURIComponent(x).replace(/\+/g, ' ');
+}
+
+/**
+ * small helper function to urlencode strings
+ */
+jQuery.urlencode = encodeURIComponent;
+
+/**
+ * This function returns the parsed url parameters of the
+ * current request. Multiple values per key are supported,
+ * it will always return arrays of strings for the value parts.
+ */
+jQuery.getQueryParameters = function(s) {
+ if (typeof s == 'undefined')
+ s = document.location.search;
+ var parts = s.substr(s.indexOf('?') + 1).split('&');
+ var result = {};
+ for (var i = 0; i < parts.length; i++) {
+ var tmp = parts[i].split('=', 2);
+ var key = jQuery.urldecode(tmp[0]);
+ var value = jQuery.urldecode(tmp[1]);
+ if (key in result)
+ result[key].push(value);
+ else
+ result[key] = [value];
+ }
+ return result;
+}
+
+/**
+ * small function to check if an array contains
+ * a given item.
+ */
+jQuery.contains = function(arr, item) {
+ for (var i = 0; i < arr.length; i++) {
+ if (arr[i] == item)
+ return true;
+ }
+ return false;
+}
+
+/**
+ * highlight a given string on a jquery object by wrapping it in
+ * span elements with the given class name.
+ */
+jQuery.fn.highlightText = function(text, className) {
+ function highlight(node) {
+ if (node.nodeType == 3) {
+ var val = node.nodeValue;
+ var pos = val.toLowerCase().indexOf(text);
+ if (pos >= 0 && !jQuery.className.has(node.parentNode, className)) {
+ var span = document.createElement("span");
+ span.className = className;
+ span.appendChild(document.createTextNode(val.substr(pos, text.length)));
+ node.parentNode.insertBefore(span, node.parentNode.insertBefore(
+ document.createTextNode(val.substr(pos + text.length)),
+ node.nextSibling));
+ node.nodeValue = val.substr(0, pos);
+ }
+ }
+ else if (!jQuery(node).is("button, select, textarea")) {
+ jQuery.each(node.childNodes, function() {
+ highlight(this)
+ });
+ }
+ }
+ return this.each(function() {
+ highlight(this);
+ });
+}
+
+/**
+ * Small JavaScript module for the documentation.
+ */
+var Documentation = {
+
+ init : function() {
+ this.fixFirefoxAnchorBug();
+ this.highlightSearchWords();
+ this.initModIndex();
+ },
+
+ /**
+ * i18n support
+ */
+ TRANSLATIONS : {},
+ PLURAL_EXPR : function(n) { return n == 1 ? 0 : 1; },
+ LOCALE : 'unknown',
+
+ // gettext and ngettext don't access this so that the functions
+ // can savely bound to a different name (_ = Documentation.gettext)
+ gettext : function(string) {
+ var translated = Documentation.TRANSLATIONS[string];
+ if (typeof translated == 'undefined')
+ return string;
+ return (typeof translated == 'string') ? translated : translated[0];
+ },
+
+ ngettext : function(singular, plural, n) {
+ var translated = Documentation.TRANSLATIONS[singular];
+ if (typeof translated == 'undefined')
+ return (n == 1) ? singular : plural;
+ return translated[Documentation.PLURALEXPR(n)];
+ },
+
+ addTranslations : function(catalog) {
+ for (var key in catalog.messages)
+ this.TRANSLATIONS[key] = catalog.messages[key];
+ this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')');
+ this.LOCALE = catalog.locale;
+ },
+
+ /**
+ * add context elements like header anchor links
+ */
+ addContextElements : function() {
+ $('div[id] > :header:first').each(function() {
+ $('<a class="headerlink">\u00B6</a>').
+ attr('href', '#' + this.id).
+ attr('title', _('Permalink to this headline')).
+ appendTo(this);
+ });
+ $('dt[id]').each(function() {
+ $('<a class="headerlink">\u00B6</a>').
+ attr('href', '#' + this.id).
+ attr('title', _('Permalink to this definition')).
+ appendTo(this);
+ });
+ },
+
+ /**
+ * workaround a firefox stupidity
+ */
+ fixFirefoxAnchorBug : function() {
+ if (document.location.hash && $.browser.mozilla)
+ window.setTimeout(function() {
+ document.location.href += '';
+ }, 10);
+ },
+
+ /**
+ * highlight the search words provided in the url in the text
+ */
+ highlightSearchWords : function() {
+ var params = $.getQueryParameters();
+ var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : [];
+ if (terms.length) {
+ var body = $('div.body');
+ window.setTimeout(function() {
+ $.each(terms, function() {
+ body.highlightText(this.toLowerCase(), 'highlight');
+ });
+ }, 10);
+ $('<li class="highlight-link"><a href="javascript:Documentation.' +
+ 'hideSearchWords()">' + _('Hide Search Matches') + '</a></li>')
+ .appendTo($('.sidebar .this-page-menu'));
+ }
+ },
+
+ /**
+ * init the modindex toggle buttons
+ */
+ initModIndex : function() {
+ var togglers = $('img.toggler').click(function() {
+ var src = $(this).attr('src');
+ var idnum = $(this).attr('id').substr(7);
+ console.log($('tr.cg-' + idnum).toggle());
+ if (src.substr(-9) == 'minus.png')
+ $(this).attr('src', src.substr(0, src.length-9) + 'plus.png');
+ else
+ $(this).attr('src', src.substr(0, src.length-8) + 'minus.png');
+ }).css('display', '');
+ if (DOCUMENTATION_OPTIONS.COLLAPSE_MODINDEX) {
+ togglers.click();
+ }
+ },
+
+ /**
+ * helper function to hide the search marks again
+ */
+ hideSearchWords : function() {
+ $('.sidebar .this-page-menu li.highlight-link').fadeOut(300);
+ $('span.highlight').removeClass('highlight');
+ },
+
+ /**
+ * make the url absolute
+ */
+ makeURL : function(relativeURL) {
+ return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL;
+ },
+
+ /**
+ * get the current relative url
+ */
+ getCurrentURL : function() {
+ var path = document.location.pathname;
+ var parts = path.split(/\//);
+ $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() {
+ if (this == '..')
+ parts.pop();
+ });
+ var url = parts.join('/');
+ return path.substring(url.lastIndexOf('/') + 1, path.length - 1);
+ }
+};
+
+// quick alias for translations
+_ = Documentation.gettext;
+
+$(document).ready(function() {
+ Documentation.init();
+});
diff --git a/help/PythonTutorial/_static/jquery.js b/help/PythonTutorial/_static/jquery.js
new file mode 100644
index 0000000..82b98e1
--- /dev/null
+++ b/help/PythonTutorial/_static/jquery.js
@@ -0,0 +1,32 @@
+/*
+ * jQuery 1.2.6 - New Wave Javascript
+ *
+ * Copyright (c) 2008 John Resig (jquery.com)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * $Date: 2008-05-24 14:22:17 -0400 (Sat, 24 May 2008) $
+ * $Rev: 5685 $
+ */
+(function(){var _jQuery=window.jQuery,_$=window.$;var jQuery=window.jQuery=window.$=function(selector,context){return new jQuery.fn.init(selector,context);};var quickExpr=/^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/,isSimple=/^.[^:#\[\.]*$/,undefined;jQuery.fn=jQuery.prototype={init:function(selector,context){selector=selector||document;if(selector.nodeType){this[0]=selector;this.length=1;return this;}if(typeof selector=="string"){var match=quickExpr.exec(selector);if(match&&(match[1]||!context)){if(match[1])selector=jQuery.clean([match[1]],context);else{var elem=document.getElementById(match[3]);if(elem){if(elem.id!=match[3])return jQuery().find(selector);return jQuery(elem);}selector=[];}}else
+return jQuery(context).find(selector);}else if(jQuery.isFunction(selector))return jQuery(document)[jQuery.fn.ready?"ready":"load"](selector);return this.setArray(jQuery.makeArray(selector));},jquery:"1.2.6",size:function(){return this.length;},length:0,get:function(num){return num==undefined?jQuery.makeArray(this):this[num];},pushStack:function(elems){var ret=jQuery(elems);ret.prevObject=this;return ret;},setArray:function(elems){this.length=0;Array.prototype.push.apply(this,elems);return this;},each:function(callback,args){return jQuery.each(this,callback,args);},index:function(elem){var ret=-1;return jQuery.inArray(elem&&elem.jquery?elem[0]:elem,this);},attr:function(name,value,type){var options=name;if(name.constructor==String)if(value===undefined)return this[0]&&jQuery[type||"attr"](this[0],name);else{options={};options[name]=value;}return this.each(function(i){for(name in options)jQuery.attr(type?this.style:this,name,jQuery.prop(this,options[name],type,i,name));});},css:function(key,value){if((key=='width'||key=='height')&&parseFloat(value)<0)value=undefined;return this.attr(key,value,"curCSS");},text:function(text){if(typeof text!="object"&&text!=null)return this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(text));var ret="";jQuery.each(text||this,function(){jQuery.each(this.childNodes,function(){if(this.nodeType!=8)ret+=this.nodeType!=1?this.nodeValue:jQuery.fn.text([this]);});});return ret;},wrapAll:function(html){if(this[0])jQuery(html,this[0].ownerDocument).clone().insertBefore(this[0]).map(function(){var elem=this;while(elem.firstChild)elem=elem.firstChild;return elem;}).append(this);return this;},wrapInner:function(html){return this.each(function(){jQuery(this).contents().wrapAll(html);});},wrap:function(html){return this.each(function(){jQuery(this).wrapAll(html);});},append:function(){return this.domManip(arguments,true,false,function(elem){if(this.nodeType==1)this.appendChild(elem);});},prepend:function(){return this.domManip(arguments,true,true,function(elem){if(this.nodeType==1)this.insertBefore(elem,this.firstChild);});},before:function(){return this.domManip(arguments,false,false,function(elem){this.parentNode.insertBefore(elem,this);});},after:function(){return this.domManip(arguments,false,true,function(elem){this.parentNode.insertBefore(elem,this.nextSibling);});},end:function(){return this.prevObject||jQuery([]);},find:function(selector){var elems=jQuery.map(this,function(elem){return jQuery.find(selector,elem);});return this.pushStack(/[^+>] [^+>]/.test(selector)||selector.indexOf("..")>-1?jQuery.unique(elems):elems);},clone:function(events){var ret=this.map(function(){if(jQuery.browser.msie&&!jQuery.isXMLDoc(this)){var clone=this.cloneNode(true),container=document.createElement("div");container.appendChild(clone);return jQuery.clean([container.innerHTML])[0];}else
+return this.cloneNode(true);});var clone=ret.find("*").andSelf().each(function(){if(this[expando]!=undefined)this[expando]=null;});if(events===true)this.find("*").andSelf().each(function(i){if(this.nodeType==3)return;var events=jQuery.data(this,"events");for(var type in events)for(var handler in events[type])jQuery.event.add(clone[i],type,events[type][handler],events[type][handler].data);});return ret;},filter:function(selector){return this.pushStack(jQuery.isFunction(selector)&&jQuery.grep(this,function(elem,i){return selector.call(elem,i);})||jQuery.multiFilter(selector,this));},not:function(selector){if(selector.constructor==String)if(isSimple.test(selector))return this.pushStack(jQuery.multiFilter(selector,this,true));else
+selector=jQuery.multiFilter(selector,this);var isArrayLike=selector.length&&selector[selector.length-1]!==undefined&&!selector.nodeType;return this.filter(function(){return isArrayLike?jQuery.inArray(this,selector)<0:this!=selector;});},add:function(selector){return this.pushStack(jQuery.unique(jQuery.merge(this.get(),typeof selector=='string'?jQuery(selector):jQuery.makeArray(selector))));},is:function(selector){return!!selector&&jQuery.multiFilter(selector,this).length>0;},hasClass:function(selector){return this.is("."+selector);},val:function(value){if(value==undefined){if(this.length){var elem=this[0];if(jQuery.nodeName(elem,"select")){var index=elem.selectedIndex,values=[],options=elem.options,one=elem.type=="select-one";if(index<0)return null;for(var i=one?index:0,max=one?index+1:options.length;i<max;i++){var option=options[i];if(option.selected){value=jQuery.browser.msie&&!option.attributes.value.specified?option.text:option.value;if(one)return value;values.push(value);}}return values;}else
+return(this[0].value||"").replace(/\r/g,"");}return undefined;}if(value.constructor==Number)value+='';return this.each(function(){if(this.nodeType!=1)return;if(value.constructor==Array&&/radio|checkbox/.test(this.type))this.checked=(jQuery.inArray(this.value,value)>=0||jQuery.inArray(this.name,value)>=0);else if(jQuery.nodeName(this,"select")){var values=jQuery.makeArray(value);jQuery("option",this).each(function(){this.selected=(jQuery.inArray(this.value,values)>=0||jQuery.inArray(this.text,values)>=0);});if(!values.length)this.selectedIndex=-1;}else
+this.value=value;});},html:function(value){return value==undefined?(this[0]?this[0].innerHTML:null):this.empty().append(value);},replaceWith:function(value){return this.after(value).remove();},eq:function(i){return this.slice(i,i+1);},slice:function(){return this.pushStack(Array.prototype.slice.apply(this,arguments));},map:function(callback){return this.pushStack(jQuery.map(this,function(elem,i){return callback.call(elem,i,elem);}));},andSelf:function(){return this.add(this.prevObject);},data:function(key,value){var parts=key.split(".");parts[1]=parts[1]?"."+parts[1]:"";if(value===undefined){var data=this.triggerHandler("getData"+parts[1]+"!",[parts[0]]);if(data===undefined&&this.length)data=jQuery.data(this[0],key);return data===undefined&&parts[1]?this.data(parts[0]):data;}else
+return this.trigger("setData"+parts[1]+"!",[parts[0],value]).each(function(){jQuery.data(this,key,value);});},removeData:function(key){return this.each(function(){jQuery.removeData(this,key);});},domManip:function(args,table,reverse,callback){var clone=this.length>1,elems;return this.each(function(){if(!elems){elems=jQuery.clean(args,this.ownerDocument);if(reverse)elems.reverse();}var obj=this;if(table&&jQuery.nodeName(this,"table")&&jQuery.nodeName(elems[0],"tr"))obj=this.getElementsByTagName("tbody")[0]||this.appendChild(this.ownerDocument.createElement("tbody"));var scripts=jQuery([]);jQuery.each(elems,function(){var elem=clone?jQuery(this).clone(true)[0]:this;if(jQuery.nodeName(elem,"script"))scripts=scripts.add(elem);else{if(elem.nodeType==1)scripts=scripts.add(jQuery("script",elem).remove());callback.call(obj,elem);}});scripts.each(evalScript);});}};jQuery.fn.init.prototype=jQuery.fn;function evalScript(i,elem){if(elem.src)jQuery.ajax({url:elem.src,async:false,dataType:"script"});else
+jQuery.globalEval(elem.text||elem.textContent||elem.innerHTML||"");if(elem.parentNode)elem.parentNode.removeChild(elem);}function now(){return+new Date;}jQuery.extend=jQuery.fn.extend=function(){var target=arguments[0]||{},i=1,length=arguments.length,deep=false,options;if(target.constructor==Boolean){deep=target;target=arguments[1]||{};i=2;}if(typeof target!="object"&&typeof target!="function")target={};if(length==i){target=this;--i;}for(;i<length;i++)if((options=arguments[i])!=null)for(var name in options){var src=target[name],copy=options[name];if(target===copy)continue;if(deep&&copy&&typeof copy=="object"&&!copy.nodeType)target[name]=jQuery.extend(deep,src||(copy.length!=null?[]:{}),copy);else if(copy!==undefined)target[name]=copy;}return target;};var expando="jQuery"+now(),uuid=0,windowData={},exclude=/z-?index|font-?weight|opacity|zoom|line-?height/i,defaultView=document.defaultView||{};jQuery.extend({noConflict:function(deep){window.$=_$;if(deep)window.jQuery=_jQuery;return jQuery;},isFunction:function(fn){return!!fn&&typeof fn!="string"&&!fn.nodeName&&fn.constructor!=Array&&/^[\s[]?function/.test(fn+"");},isXMLDoc:function(elem){return elem.documentElement&&!elem.body||elem.tagName&&elem.ownerDocument&&!elem.ownerDocument.body;},globalEval:function(data){data=jQuery.trim(data);if(data){var head=document.getElementsByTagName("head")[0]||document.documentElement,script=document.createElement("script");script.type="text/javascript";if(jQuery.browser.msie)script.text=data;else
+script.appendChild(document.createTextNode(data));head.insertBefore(script,head.firstChild);head.removeChild(script);}},nodeName:function(elem,name){return elem.nodeName&&elem.nodeName.toUpperCase()==name.toUpperCase();},cache:{},data:function(elem,name,data){elem=elem==window?windowData:elem;var id=elem[expando];if(!id)id=elem[expando]=++uuid;if(name&&!jQuery.cache[id])jQuery.cache[id]={};if(data!==undefined)jQuery.cache[id][name]=data;return name?jQuery.cache[id][name]:id;},removeData:function(elem,name){elem=elem==window?windowData:elem;var id=elem[expando];if(name){if(jQuery.cache[id]){delete jQuery.cache[id][name];name="";for(name in jQuery.cache[id])break;if(!name)jQuery.removeData(elem);}}else{try{delete elem[expando];}catch(e){if(elem.removeAttribute)elem.removeAttribute(expando);}delete jQuery.cache[id];}},each:function(object,callback,args){var name,i=0,length=object.length;if(args){if(length==undefined){for(name in object)if(callback.apply(object[name],args)===false)break;}else
+for(;i<length;)if(callback.apply(object[i++],args)===false)break;}else{if(length==undefined){for(name in object)if(callback.call(object[name],name,object[name])===false)break;}else
+for(var value=object[0];i<length&&callback.call(value,i,value)!==false;value=object[++i]){}}return object;},prop:function(elem,value,type,i,name){if(jQuery.isFunction(value))value=value.call(elem,i);return value&&value.constructor==Number&&type=="curCSS"&&!exclude.test(name)?value+"px":value;},className:{add:function(elem,classNames){jQuery.each((classNames||"").split(/\s+/),function(i,className){if(elem.nodeType==1&&!jQuery.className.has(elem.className,className))elem.className+=(elem.className?" ":"")+className;});},remove:function(elem,classNames){if(elem.nodeType==1)elem.className=classNames!=undefined?jQuery.grep(elem.className.split(/\s+/),function(className){return!jQuery.className.has(classNames,className);}).join(" "):"";},has:function(elem,className){return jQuery.inArray(className,(elem.className||elem).toString().split(/\s+/))>-1;}},swap:function(elem,options,callback){var old={};for(var name in options){old[name]=elem.style[name];elem.style[name]=options[name];}callback.call(elem);for(var name in options)elem.style[name]=old[name];},css:function(elem,name,force){if(name=="width"||name=="height"){var val,props={position:"absolute",visibility:"hidden",display:"block"},which=name=="width"?["Left","Right"]:["Top","Bottom"];function getWH(){val=name=="width"?elem.offsetWidth:elem.offsetHeight;var padding=0,border=0;jQuery.each(which,function(){padding+=parseFloat(jQuery.curCSS(elem,"padding"+this,true))||0;border+=parseFloat(jQuery.curCSS(elem,"border"+this+"Width",true))||0;});val-=Math.round(padding+border);}if(jQuery(elem).is(":visible"))getWH();else
+jQuery.swap(elem,props,getWH);return Math.max(0,val);}return jQuery.curCSS(elem,name,force);},curCSS:function(elem,name,force){var ret,style=elem.style;function color(elem){if(!jQuery.browser.safari)return false;var ret=defaultView.getComputedStyle(elem,null);return!ret||ret.getPropertyValue("color")=="";}if(name=="opacity"&&jQuery.browser.msie){ret=jQuery.attr(style,"opacity");return ret==""?"1":ret;}if(jQuery.browser.opera&&name=="display"){var save=style.outline;style.outline="0 solid black";style.outline=save;}if(name.match(/float/i))name=styleFloat;if(!force&&style&&style[name])ret=style[name];else if(defaultView.getComputedStyle){if(name.match(/float/i))name="float";name=name.replace(/([A-Z])/g,"-$1").toLowerCase();var computedStyle=defaultView.getComputedStyle(elem,null);if(computedStyle&&!color(elem))ret=computedStyle.getPropertyValue(name);else{var swap=[],stack=[],a=elem,i=0;for(;a&&color(a);a=a.parentNode)stack.unshift(a);for(;i<stack.length;i++)if(color(stack[i])){swap[i]=stack[i].style.display;stack[i].style.display="block";}ret=name=="display"&&swap[stack.length-1]!=null?"none":(computedStyle&&computedStyle.getPropertyValue(name))||"";for(i=0;i<swap.length;i++)if(swap[i]!=null)stack[i].style.display=swap[i];}if(name=="opacity"&&ret=="")ret="1";}else if(elem.currentStyle){var camelCase=name.replace(/\-(\w)/g,function(all,letter){return letter.toUpperCase();});ret=elem.currentStyle[name]||elem.currentStyle[camelCase];if(!/^\d+(px)?$/i.test(ret)&&/^\d/.test(ret)){var left=style.left,rsLeft=elem.runtimeStyle.left;elem.runtimeStyle.left=elem.currentStyle.left;style.left=ret||0;ret=style.pixelLeft+"px";style.left=left;elem.runtimeStyle.left=rsLeft;}}return ret;},clean:function(elems,context){var ret=[];context=context||document;if(typeof context.createElement=='undefined')context=context.ownerDocument||context[0]&&context[0].ownerDocument||document;jQuery.each(elems,function(i,elem){if(!elem)return;if(elem.constructor==Number)elem+='';if(typeof elem=="string"){elem=elem.replace(/(<(\w+)[^>]*?)\/>/g,function(all,front,tag){return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?all:front+"></"+tag+">";});var tags=jQuery.trim(elem).toLowerCase(),div=context.createElement("div");var wrap=!tags.indexOf("<opt")&&[1,"<select multiple='multiple'>","</select>"]||!tags.indexOf("<leg")&&[1,"<fieldset>","</fieldset>"]||tags.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1,"<table>","</table>"]||!tags.indexOf("<tr")&&[2,"<table><tbody>","</tbody></table>"]||(!tags.indexOf("<td")||!tags.indexOf("<th"))&&[3,"<table><tbody><tr>","</tr></tbody></table>"]||!tags.indexOf("<col")&&[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"]||jQuery.browser.msie&&[1,"div<div>","</div>"]||[0,"",""];div.innerHTML=wrap[1]+elem+wrap[2];while(wrap[0]--)div=div.lastChild;if(jQuery.browser.msie){var tbody=!tags.indexOf("<table")&&tags.indexOf("<tbody")<0?div.firstChild&&div.firstChild.childNodes:wrap[1]=="<table>"&&tags.indexOf("<tbody")<0?div.childNodes:[];for(var j=tbody.length-1;j>=0;--j)if(jQuery.nodeName(tbody[j],"tbody")&&!tbody[j].childNodes.length)tbody[j].parentNode.removeChild(tbody[j]);if(/^\s/.test(elem))div.insertBefore(context.createTextNode(elem.match(/^\s*/)[0]),div.firstChild);}elem=jQuery.makeArray(div.childNodes);}if(elem.length===0&&(!jQuery.nodeName(elem,"form")&&!jQuery.nodeName(elem,"select")))return;if(elem[0]==undefined||jQuery.nodeName(elem,"form")||elem.options)ret.push(elem);else
+ret=jQuery.merge(ret,elem);});return ret;},attr:function(elem,name,value){if(!elem||elem.nodeType==3||elem.nodeType==8)return undefined;var notxml=!jQuery.isXMLDoc(elem),set=value!==undefined,msie=jQuery.browser.msie;name=notxml&&jQuery.props[name]||name;if(elem.tagName){var special=/href|src|style/.test(name);if(name=="selected"&&jQuery.browser.safari)elem.parentNode.selectedIndex;if(name in elem&&notxml&&!special){if(set){if(name=="type"&&jQuery.nodeName(elem,"input")&&elem.parentNode)throw"type property can't be changed";elem[name]=value;}if(jQuery.nodeName(elem,"form")&&elem.getAttributeNode(name))return elem.getAttributeNode(name).nodeValue;return elem[name];}if(msie&&notxml&&name=="style")return jQuery.attr(elem.style,"cssText",value);if(set)elem.setAttribute(name,""+value);var attr=msie&&notxml&&special?elem.getAttribute(name,2):elem.getAttribute(name);return attr===null?undefined:attr;}if(msie&&name=="opacity"){if(set){elem.zoom=1;elem.filter=(elem.filter||"").replace(/alpha\([^)]*\)/,"")+(parseInt(value)+''=="NaN"?"":"alpha(opacity="+value*100+")");}return elem.filter&&elem.filter.indexOf("opacity=")>=0?(parseFloat(elem.filter.match(/opacity=([^)]*)/)[1])/100)+'':"";}name=name.replace(/-([a-z])/ig,function(all,letter){return letter.toUpperCase();});if(set)elem[name]=value;return elem[name];},trim:function(text){return(text||"").replace(/^\s+|\s+$/g,"");},makeArray:function(array){var ret=[];if(array!=null){var i=array.length;if(i==null||array.split||array.setInterval||array.call)ret[0]=array;else
+while(i)ret[--i]=array[i];}return ret;},inArray:function(elem,array){for(var i=0,length=array.length;i<length;i++)if(array[i]===elem)return i;return-1;},merge:function(first,second){var i=0,elem,pos=first.length;if(jQuery.browser.msie){while(elem=second[i++])if(elem.nodeType!=8)first[pos++]=elem;}else
+while(elem=second[i++])first[pos++]=elem;return first;},unique:function(array){var ret=[],done={};try{for(var i=0,length=array.length;i<length;i++){var id=jQuery.data(array[i]);if(!done[id]){done[id]=true;ret.push(array[i]);}}}catch(e){ret=array;}return ret;},grep:function(elems,callback,inv){var ret=[];for(var i=0,length=elems.length;i<length;i++)if(!inv!=!callback(elems[i],i))ret.push(elems[i]);return ret;},map:function(elems,callback){var ret=[];for(var i=0,length=elems.length;i<length;i++){var value=callback(elems[i],i);if(value!=null)ret[ret.length]=value;}return ret.concat.apply([],ret);}});var userAgent=navigator.userAgent.toLowerCase();jQuery.browser={version:(userAgent.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/)||[])[1],safari:/webkit/.test(userAgent),opera:/opera/.test(userAgent),msie:/msie/.test(userAgent)&&!/opera/.test(userAgent),mozilla:/mozilla/.test(userAgent)&&!/(compatible|webkit)/.test(userAgent)};var styleFloat=jQuery.browser.msie?"styleFloat":"cssFloat";jQuery.extend({boxModel:!jQuery.browser.msie||document.compatMode=="CSS1Compat",props:{"for":"htmlFor","class":"className","float":styleFloat,cssFloat:styleFloat,styleFloat:styleFloat,readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing"}});jQuery.each({parent:function(elem){return elem.parentNode;},parents:function(elem){return jQuery.dir(elem,"parentNode");},next:function(elem){return jQuery.nth(elem,2,"nextSibling");},prev:function(elem){return jQuery.nth(elem,2,"previousSibling");},nextAll:function(elem){return jQuery.dir(elem,"nextSibling");},prevAll:function(elem){return jQuery.dir(elem,"previousSibling");},siblings:function(elem){return jQuery.sibling(elem.parentNode.firstChild,elem);},children:function(elem){return jQuery.sibling(elem.firstChild);},contents:function(elem){return jQuery.nodeName(elem,"iframe")?elem.contentDocument||elem.contentWindow.document:jQuery.makeArray(elem.childNodes);}},function(name,fn){jQuery.fn[name]=function(selector){var ret=jQuery.map(this,fn);if(selector&&typeof selector=="string")ret=jQuery.multiFilter(selector,ret);return this.pushStack(jQuery.unique(ret));};});jQuery.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(name,original){jQuery.fn[name]=function(){var args=arguments;return this.each(function(){for(var i=0,length=args.length;i<length;i++)jQuery(args[i])[original](this);});};});jQuery.each({removeAttr:function(name){jQuery.attr(this,name,"");if(this.nodeType==1)this.removeAttribute(name);},addClass:function(classNames){jQuery.className.add(this,classNames);},removeClass:function(classNames){jQuery.className.remove(this,classNames);},toggleClass:function(classNames){jQuery.className[jQuery.className.has(this,classNames)?"remove":"add"](this,classNames);},remove:function(selector){if(!selector||jQuery.filter(selector,[this]).r.length){jQuery("*",this).add(this).each(function(){jQuery.event.remove(this);jQuery.removeData(this);});if(this.parentNode)this.parentNode.removeChild(this);}},empty:function(){jQuery(">*",this).remove();while(this.firstChild)this.removeChild(this.firstChild);}},function(name,fn){jQuery.fn[name]=function(){return this.each(fn,arguments);};});jQuery.each(["Height","Width"],function(i,name){var type=name.toLowerCase();jQuery.fn[type]=function(size){return this[0]==window?jQuery.browser.opera&&document.body["client"+name]||jQuery.browser.safari&&window["inner"+name]||document.compatMode=="CSS1Compat"&&document.documentElement["client"+name]||document.body["client"+name]:this[0]==document?Math.max(Math.max(document.body["scroll"+name],document.documentElement["scroll"+name]),Math.max(document.body["offset"+name],document.documentElement["offset"+name])):size==undefined?(this.length?jQuery.css(this[0],type):null):this.css(type,size.constructor==String?size:size+"px");};});function num(elem,prop){return elem[0]&&parseInt(jQuery.curCSS(elem[0],prop,true),10)||0;}var chars=jQuery.browser.safari&&parseInt(jQuery.browser.version)<417?"(?:[\\w*_-]|\\\\.)":"(?:[\\w\u0128-\uFFFF*_-]|\\\\.)",quickChild=new RegExp("^>\\s*("+chars+"+)"),quickID=new RegExp("^("+chars+"+)(#)("+chars+"+)"),quickClass=new RegExp("^([#.]?)("+chars+"*)");jQuery.extend({expr:{"":function(a,i,m){return m[2]=="*"||jQuery.nodeName(a,m[2]);},"#":function(a,i,m){return a.getAttribute("id")==m[2];},":":{lt:function(a,i,m){return i<m[3]-0;},gt:function(a,i,m){return i>m[3]-0;},nth:function(a,i,m){return m[3]-0==i;},eq:function(a,i,m){return m[3]-0==i;},first:function(a,i){return i==0;},last:function(a,i,m,r){return i==r.length-1;},even:function(a,i){return i%2==0;},odd:function(a,i){return i%2;},"first-child":function(a){return a.parentNode.getElementsByTagName("*")[0]==a;},"last-child":function(a){return jQuery.nth(a.parentNode.lastChild,1,"previousSibling")==a;},"only-child":function(a){return!jQuery.nth(a.parentNode.lastChild,2,"previousSibling");},parent:function(a){return a.firstChild;},empty:function(a){return!a.firstChild;},contains:function(a,i,m){return(a.textContent||a.innerText||jQuery(a).text()||"").indexOf(m[3])>=0;},visible:function(a){return"hidden"!=a.type&&jQuery.css(a,"display")!="none"&&jQuery.css(a,"visibility")!="hidden";},hidden:function(a){return"hidden"==a.type||jQuery.css(a,"display")=="none"||jQuery.css(a,"visibility")=="hidden";},enabled:function(a){return!a.disabled;},disabled:function(a){return a.disabled;},checked:function(a){return a.checked;},selected:function(a){return a.selected||jQuery.attr(a,"selected");},text:function(a){return"text"==a.type;},radio:function(a){return"radio"==a.type;},checkbox:function(a){return"checkbox"==a.type;},file:function(a){return"file"==a.type;},password:function(a){return"password"==a.type;},submit:function(a){return"submit"==a.type;},image:function(a){return"image"==a.type;},reset:function(a){return"reset"==a.type;},button:function(a){return"button"==a.type||jQuery.nodeName(a,"button");},input:function(a){return/input|select|textarea|button/i.test(a.nodeName);},has:function(a,i,m){return jQuery.find(m[3],a).length;},header:function(a){return/h\d/i.test(a.nodeName);},animated:function(a){return jQuery.grep(jQuery.timers,function(fn){return a==fn.elem;}).length;}}},parse:[/^(\[) *@?([\w-]+) *([!*$^~=]*) *('?"?)(.*?)\4 *\]/,/^(:)([\w-]+)\("?'?(.*?(\(.*?\))?[^(]*?)"?'?\)/,new RegExp("^([:.#]*)("+chars+"+)")],multiFilter:function(expr,elems,not){var old,cur=[];while(expr&&expr!=old){old=expr;var f=jQuery.filter(expr,elems,not);expr=f.t.replace(/^\s*,\s*/,"");cur=not?elems=f.r:jQuery.merge(cur,f.r);}return cur;},find:function(t,context){if(typeof t!="string")return[t];if(context&&context.nodeType!=1&&context.nodeType!=9)return[];context=context||document;var ret=[context],done=[],last,nodeName;while(t&&last!=t){var r=[];last=t;t=jQuery.trim(t);var foundToken=false,re=quickChild,m=re.exec(t);if(m){nodeName=m[1].toUpperCase();for(var i=0;ret[i];i++)for(var c=ret[i].firstChild;c;c=c.nextSibling)if(c.nodeType==1&&(nodeName=="*"||c.nodeName.toUpperCase()==nodeName))r.push(c);ret=r;t=t.replace(re,"");if(t.indexOf(" ")==0)continue;foundToken=true;}else{re=/^([>+~])\s*(\w*)/i;if((m=re.exec(t))!=null){r=[];var merge={};nodeName=m[2].toUpperCase();m=m[1];for(var j=0,rl=ret.length;j<rl;j++){var n=m=="~"||m=="+"?ret[j].nextSibling:ret[j].firstChild;for(;n;n=n.nextSibling)if(n.nodeType==1){var id=jQuery.data(n);if(m=="~"&&merge[id])break;if(!nodeName||n.nodeName.toUpperCase()==nodeName){if(m=="~")merge[id]=true;r.push(n);}if(m=="+")break;}}ret=r;t=jQuery.trim(t.replace(re,""));foundToken=true;}}if(t&&!foundToken){if(!t.indexOf(",")){if(context==ret[0])ret.shift();done=jQuery.merge(done,ret);r=ret=[context];t=" "+t.substr(1,t.length);}else{var re2=quickID;var m=re2.exec(t);if(m){m=[0,m[2],m[3],m[1]];}else{re2=quickClass;m=re2.exec(t);}m[2]=m[2].replace(/\\/g,"");var elem=ret[ret.length-1];if(m[1]=="#"&&elem&&elem.getElementById&&!jQuery.isXMLDoc(elem)){var oid=elem.getElementById(m[2]);if((jQuery.browser.msie||jQuery.browser.opera)&&oid&&typeof oid.id=="string"&&oid.id!=m[2])oid=jQuery('[@id="'+m[2]+'"]',elem)[0];ret=r=oid&&(!m[3]||jQuery.nodeName(oid,m[3]))?[oid]:[];}else{for(var i=0;ret[i];i++){var tag=m[1]=="#"&&m[3]?m[3]:m[1]!=""||m[0]==""?"*":m[2];if(tag=="*"&&ret[i].nodeName.toLowerCase()=="object")tag="param";r=jQuery.merge(r,ret[i].getElementsByTagName(tag));}if(m[1]==".")r=jQuery.classFilter(r,m[2]);if(m[1]=="#"){var tmp=[];for(var i=0;r[i];i++)if(r[i].getAttribute("id")==m[2]){tmp=[r[i]];break;}r=tmp;}ret=r;}t=t.replace(re2,"");}}if(t){var val=jQuery.filter(t,r);ret=r=val.r;t=jQuery.trim(val.t);}}if(t)ret=[];if(ret&&context==ret[0])ret.shift();done=jQuery.merge(done,ret);return done;},classFilter:function(r,m,not){m=" "+m+" ";var tmp=[];for(var i=0;r[i];i++){var pass=(" "+r[i].className+" ").indexOf(m)>=0;if(!not&&pass||not&&!pass)tmp.push(r[i]);}return tmp;},filter:function(t,r,not){var last;while(t&&t!=last){last=t;var p=jQuery.parse,m;for(var i=0;p[i];i++){m=p[i].exec(t);if(m){t=t.substring(m[0].length);m[2]=m[2].replace(/\\/g,"");break;}}if(!m)break;if(m[1]==":"&&m[2]=="not")r=isSimple.test(m[3])?jQuery.filter(m[3],r,true).r:jQuery(r).not(m[3]);else if(m[1]==".")r=jQuery.classFilter(r,m[2],not);else if(m[1]=="["){var tmp=[],type=m[3];for(var i=0,rl=r.length;i<rl;i++){var a=r[i],z=a[jQuery.props[m[2]]||m[2]];if(z==null||/href|src|selected/.test(m[2]))z=jQuery.attr(a,m[2])||'';if((type==""&&!!z||type=="="&&z==m[5]||type=="!="&&z!=m[5]||type=="^="&&z&&!z.indexOf(m[5])||type=="$="&&z.substr(z.length-m[5].length)==m[5]||(type=="*="||type=="~=")&&z.indexOf(m[5])>=0)^not)tmp.push(a);}r=tmp;}else if(m[1]==":"&&m[2]=="nth-child"){var merge={},tmp=[],test=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(m[3]=="even"&&"2n"||m[3]=="odd"&&"2n+1"||!/\D/.test(m[3])&&"0n+"+m[3]||m[3]),first=(test[1]+(test[2]||1))-0,last=test[3]-0;for(var i=0,rl=r.length;i<rl;i++){var node=r[i],parentNode=node.parentNode,id=jQuery.data(parentNode);if(!merge[id]){var c=1;for(var n=parentNode.firstChild;n;n=n.nextSibling)if(n.nodeType==1)n.nodeIndex=c++;merge[id]=true;}var add=false;if(first==0){if(node.nodeIndex==last)add=true;}else if((node.nodeIndex-last)%first==0&&(node.nodeIndex-last)/first>=0)add=true;if(add^not)tmp.push(node);}r=tmp;}else{var fn=jQuery.expr[m[1]];if(typeof fn=="object")fn=fn[m[2]];if(typeof fn=="string")fn=eval("false||function(a,i){return "+fn+";}");r=jQuery.grep(r,function(elem,i){return fn(elem,i,m,r);},not);}}return{r:r,t:t};},dir:function(elem,dir){var matched=[],cur=elem[dir];while(cur&&cur!=document){if(cur.nodeType==1)matched.push(cur);cur=cur[dir];}return matched;},nth:function(cur,result,dir,elem){result=result||1;var num=0;for(;cur;cur=cur[dir])if(cur.nodeType==1&&++num==result)break;return cur;},sibling:function(n,elem){var r=[];for(;n;n=n.nextSibling){if(n.nodeType==1&&n!=elem)r.push(n);}return r;}});jQuery.event={add:function(elem,types,handler,data){if(elem.nodeType==3||elem.nodeType==8)return;if(jQuery.browser.msie&&elem.setInterval)elem=window;if(!handler.guid)handler.guid=this.guid++;if(data!=undefined){var fn=handler;handler=this.proxy(fn,function(){return fn.apply(this,arguments);});handler.data=data;}var events=jQuery.data(elem,"events")||jQuery.data(elem,"events",{}),handle=jQuery.data(elem,"handle")||jQuery.data(elem,"handle",function(){if(typeof jQuery!="undefined"&&!jQuery.event.triggered)return jQuery.event.handle.apply(arguments.callee.elem,arguments);});handle.elem=elem;jQuery.each(types.split(/\s+/),function(index,type){var parts=type.split(".");type=parts[0];handler.type=parts[1];var handlers=events[type];if(!handlers){handlers=events[type]={};if(!jQuery.event.special[type]||jQuery.event.special[type].setup.call(elem)===false){if(elem.addEventListener)elem.addEventListener(type,handle,false);else if(elem.attachEvent)elem.attachEvent("on"+type,handle);}}handlers[handler.guid]=handler;jQuery.event.global[type]=true;});elem=null;},guid:1,global:{},remove:function(elem,types,handler){if(elem.nodeType==3||elem.nodeType==8)return;var events=jQuery.data(elem,"events"),ret,index;if(events){if(types==undefined||(typeof types=="string"&&types.charAt(0)=="."))for(var type in events)this.remove(elem,type+(types||""));else{if(types.type){handler=types.handler;types=types.type;}jQuery.each(types.split(/\s+/),function(index,type){var parts=type.split(".");type=parts[0];if(events[type]){if(handler)delete events[type][handler.guid];else
+for(handler in events[type])if(!parts[1]||events[type][handler].type==parts[1])delete events[type][handler];for(ret in events[type])break;if(!ret){if(!jQuery.event.special[type]||jQuery.event.special[type].teardown.call(elem)===false){if(elem.removeEventListener)elem.removeEventListener(type,jQuery.data(elem,"handle"),false);else if(elem.detachEvent)elem.detachEvent("on"+type,jQuery.data(elem,"handle"));}ret=null;delete events[type];}}});}for(ret in events)break;if(!ret){var handle=jQuery.data(elem,"handle");if(handle)handle.elem=null;jQuery.removeData(elem,"events");jQuery.removeData(elem,"handle");}}},trigger:function(type,data,elem,donative,extra){data=jQuery.makeArray(data);if(type.indexOf("!")>=0){type=type.slice(0,-1);var exclusive=true;}if(!elem){if(this.global[type])jQuery("*").add([window,document]).trigger(type,data);}else{if(elem.nodeType==3||elem.nodeType==8)return undefined;var val,ret,fn=jQuery.isFunction(elem[type]||null),event=!data[0]||!data[0].preventDefault;if(event){data.unshift({type:type,target:elem,preventDefault:function(){},stopPropagation:function(){},timeStamp:now()});data[0][expando]=true;}data[0].type=type;if(exclusive)data[0].exclusive=true;var handle=jQuery.data(elem,"handle");if(handle)val=handle.apply(elem,data);if((!fn||(jQuery.nodeName(elem,'a')&&type=="click"))&&elem["on"+type]&&elem["on"+type].apply(elem,data)===false)val=false;if(event)data.shift();if(extra&&jQuery.isFunction(extra)){ret=extra.apply(elem,val==null?data:data.concat(val));if(ret!==undefined)val=ret;}if(fn&&donative!==false&&val!==false&&!(jQuery.nodeName(elem,'a')&&type=="click")){this.triggered=true;try{elem[type]();}catch(e){}}this.triggered=false;}return val;},handle:function(event){var val,ret,namespace,all,handlers;event=arguments[0]=jQuery.event.fix(event||window.event);namespace=event.type.split(".");event.type=namespace[0];namespace=namespace[1];all=!namespace&&!event.exclusive;handlers=(jQuery.data(this,"events")||{})[event.type];for(var j in handlers){var handler=handlers[j];if(all||handler.type==namespace){event.handler=handler;event.data=handler.data;ret=handler.apply(this,arguments);if(val!==false)val=ret;if(ret===false){event.preventDefault();event.stopPropagation();}}}return val;},fix:function(event){if(event[expando]==true)return event;var originalEvent=event;event={originalEvent:originalEvent};var props="altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target timeStamp toElement type view wheelDelta which".split(" ");for(var i=props.length;i;i--)event[props[i]]=originalEvent[props[i]];event[expando]=true;event.preventDefault=function(){if(originalEvent.preventDefault)originalEvent.preventDefault();originalEvent.returnValue=false;};event.stopPropagation=function(){if(originalEvent.stopPropagation)originalEvent.stopPropagation();originalEvent.cancelBubble=true;};event.timeStamp=event.timeStamp||now();if(!event.target)event.target=event.srcElement||document;if(event.target.nodeType==3)event.target=event.target.parentNode;if(!event.relatedTarget&&event.fromElement)event.relatedTarget=event.fromElement==event.target?event.toElement:event.fromElement;if(event.pageX==null&&event.clientX!=null){var doc=document.documentElement,body=document.body;event.pageX=event.clientX+(doc&&doc.scrollLeft||body&&body.scrollLeft||0)-(doc.clientLeft||0);event.pageY=event.clientY+(doc&&doc.scrollTop||body&&body.scrollTop||0)-(doc.clientTop||0);}if(!event.which&&((event.charCode||event.charCode===0)?event.charCode:event.keyCode))event.which=event.charCode||event.keyCode;if(!event.metaKey&&event.ctrlKey)event.metaKey=event.ctrlKey;if(!event.which&&event.button)event.which=(event.button&1?1:(event.button&2?3:(event.button&4?2:0)));return event;},proxy:function(fn,proxy){proxy.guid=fn.guid=fn.guid||proxy.guid||this.guid++;return proxy;},special:{ready:{setup:function(){bindReady();return;},teardown:function(){return;}},mouseenter:{setup:function(){if(jQuery.browser.msie)return false;jQuery(this).bind("mouseover",jQuery.event.special.mouseenter.handler);return true;},teardown:function(){if(jQuery.browser.msie)return false;jQuery(this).unbind("mouseover",jQuery.event.special.mouseenter.handler);return true;},handler:function(event){if(withinElement(event,this))return true;event.type="mouseenter";return jQuery.event.handle.apply(this,arguments);}},mouseleave:{setup:function(){if(jQuery.browser.msie)return false;jQuery(this).bind("mouseout",jQuery.event.special.mouseleave.handler);return true;},teardown:function(){if(jQuery.browser.msie)return false;jQuery(this).unbind("mouseout",jQuery.event.special.mouseleave.handler);return true;},handler:function(event){if(withinElement(event,this))return true;event.type="mouseleave";return jQuery.event.handle.apply(this,arguments);}}}};jQuery.fn.extend({bind:function(type,data,fn){return type=="unload"?this.one(type,data,fn):this.each(function(){jQuery.event.add(this,type,fn||data,fn&&data);});},one:function(type,data,fn){var one=jQuery.event.proxy(fn||data,function(event){jQuery(this).unbind(event,one);return(fn||data).apply(this,arguments);});return this.each(function(){jQuery.event.add(this,type,one,fn&&data);});},unbind:function(type,fn){return this.each(function(){jQuery.event.remove(this,type,fn);});},trigger:function(type,data,fn){return this.each(function(){jQuery.event.trigger(type,data,this,true,fn);});},triggerHandler:function(type,data,fn){return this[0]&&jQuery.event.trigger(type,data,this[0],false,fn);},toggle:function(fn){var args=arguments,i=1;while(i<args.length)jQuery.event.proxy(fn,args[i++]);return this.click(jQuery.event.proxy(fn,function(event){this.lastToggle=(this.lastToggle||0)%i;event.preventDefault();return args[this.lastToggle++].apply(this,arguments)||false;}));},hover:function(fnOver,fnOut){return this.bind('mouseenter',fnOver).bind('mouseleave',fnOut);},ready:function(fn){bindReady();if(jQuery.isReady)fn.call(document,jQuery);else
+jQuery.readyList.push(function(){return fn.call(this,jQuery);});return this;}});jQuery.extend({isReady:false,readyList:[],ready:function(){if(!jQuery.isReady){jQuery.isReady=true;if(jQuery.readyList){jQuery.each(jQuery.readyList,function(){this.call(document);});jQuery.readyList=null;}jQuery(document).triggerHandler("ready");}}});var readyBound=false;function bindReady(){if(readyBound)return;readyBound=true;if(document.addEventListener&&!jQuery.browser.opera)document.addEventListener("DOMContentLoaded",jQuery.ready,false);if(jQuery.browser.msie&&window==top)(function(){if(jQuery.isReady)return;try{document.documentElement.doScroll("left");}catch(error){setTimeout(arguments.callee,0);return;}jQuery.ready();})();if(jQuery.browser.opera)document.addEventListener("DOMContentLoaded",function(){if(jQuery.isReady)return;for(var i=0;i<document.styleSheets.length;i++)if(document.styleSheets[i].disabled){setTimeout(arguments.callee,0);return;}jQuery.ready();},false);if(jQuery.browser.safari){var numStyles;(function(){if(jQuery.isReady)return;if(document.readyState!="loaded"&&document.readyState!="complete"){setTimeout(arguments.callee,0);return;}if(numStyles===undefined)numStyles=jQuery("style, link[rel=stylesheet]").length;if(document.styleSheets.length!=numStyles){setTimeout(arguments.callee,0);return;}jQuery.ready();})();}jQuery.event.add(window,"load",jQuery.ready);}jQuery.each(("blur,focus,load,resize,scroll,unload,click,dblclick,"+"mousedown,mouseup,mousemove,mouseover,mouseout,change,select,"+"submit,keydown,keypress,keyup,error").split(","),function(i,name){jQuery.fn[name]=function(fn){return fn?this.bind(name,fn):this.trigger(name);};});var withinElement=function(event,elem){var parent=event.relatedTarget;while(parent&&parent!=elem)try{parent=parent.parentNode;}catch(error){parent=elem;}return parent==elem;};jQuery(window).bind("unload",function(){jQuery("*").add(document).unbind();});jQuery.fn.extend({_load:jQuery.fn.load,load:function(url,params,callback){if(typeof url!='string')return this._load(url);var off=url.indexOf(" ");if(off>=0){var selector=url.slice(off,url.length);url=url.slice(0,off);}callback=callback||function(){};var type="GET";if(params)if(jQuery.isFunction(params)){callback=params;params=null;}else{params=jQuery.param(params);type="POST";}var self=this;jQuery.ajax({url:url,type:type,dataType:"html",data:params,complete:function(res,status){if(status=="success"||status=="notmodified")self.html(selector?jQuery("<div/>").append(res.responseText.replace(/<script(.|\s)*?\/script>/g,"")).find(selector):res.responseText);self.each(callback,[res.responseText,status,res]);}});return this;},serialize:function(){return jQuery.param(this.serializeArray());},serializeArray:function(){return this.map(function(){return jQuery.nodeName(this,"form")?jQuery.makeArray(this.elements):this;}).filter(function(){return this.name&&!this.disabled&&(this.checked||/select|textarea/i.test(this.nodeName)||/text|hidden|password/i.test(this.type));}).map(function(i,elem){var val=jQuery(this).val();return val==null?null:val.constructor==Array?jQuery.map(val,function(val,i){return{name:elem.name,value:val};}):{name:elem.name,value:val};}).get();}});jQuery.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","),function(i,o){jQuery.fn[o]=function(f){return this.bind(o,f);};});var jsc=now();jQuery.extend({get:function(url,data,callback,type){if(jQuery.isFunction(data)){callback=data;data=null;}return jQuery.ajax({type:"GET",url:url,data:data,success:callback,dataType:type});},getScript:function(url,callback){return jQuery.get(url,null,callback,"script");},getJSON:function(url,data,callback){return jQuery.get(url,data,callback,"json");},post:function(url,data,callback,type){if(jQuery.isFunction(data)){callback=data;data={};}return jQuery.ajax({type:"POST",url:url,data:data,success:callback,dataType:type});},ajaxSetup:function(settings){jQuery.extend(jQuery.ajaxSettings,settings);},ajaxSettings:{url:location.href,global:true,type:"GET",timeout:0,contentType:"application/x-www-form-urlencoded",processData:true,async:true,data:null,username:null,password:null,accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},ajax:function(s){s=jQuery.extend(true,s,jQuery.extend(true,{},jQuery.ajaxSettings,s));var jsonp,jsre=/=\?(&|$)/g,status,data,type=s.type.toUpperCase();if(s.data&&s.processData&&typeof s.data!="string")s.data=jQuery.param(s.data);if(s.dataType=="jsonp"){if(type=="GET"){if(!s.url.match(jsre))s.url+=(s.url.match(/\?/)?"&":"?")+(s.jsonp||"callback")+"=?";}else if(!s.data||!s.data.match(jsre))s.data=(s.data?s.data+"&":"")+(s.jsonp||"callback")+"=?";s.dataType="json";}if(s.dataType=="json"&&(s.data&&s.data.match(jsre)||s.url.match(jsre))){jsonp="jsonp"+jsc++;if(s.data)s.data=(s.data+"").replace(jsre,"="+jsonp+"$1");s.url=s.url.replace(jsre,"="+jsonp+"$1");s.dataType="script";window[jsonp]=function(tmp){data=tmp;success();complete();window[jsonp]=undefined;try{delete window[jsonp];}catch(e){}if(head)head.removeChild(script);};}if(s.dataType=="script"&&s.cache==null)s.cache=false;if(s.cache===false&&type=="GET"){var ts=now();var ret=s.url.replace(/(\?|&)_=.*?(&|$)/,"$1_="+ts+"$2");s.url=ret+((ret==s.url)?(s.url.match(/\?/)?"&":"?")+"_="+ts:"");}if(s.data&&type=="GET"){s.url+=(s.url.match(/\?/)?"&":"?")+s.data;s.data=null;}if(s.global&&!jQuery.active++)jQuery.event.trigger("ajaxStart");var remote=/^(?:\w+:)?\/\/([^\/?#]+)/;if(s.dataType=="script"&&type=="GET"&&remote.test(s.url)&&remote.exec(s.url)[1]!=location.host){var head=document.getElementsByTagName("head")[0];var script=document.createElement("script");script.src=s.url;if(s.scriptCharset)script.charset=s.scriptCharset;if(!jsonp){var done=false;script.onload=script.onreadystatechange=function(){if(!done&&(!this.readyState||this.readyState=="loaded"||this.readyState=="complete")){done=true;success();complete();head.removeChild(script);}};}head.appendChild(script);return undefined;}var requestDone=false;var xhr=window.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest();if(s.username)xhr.open(type,s.url,s.async,s.username,s.password);else
+xhr.open(type,s.url,s.async);try{if(s.data)xhr.setRequestHeader("Content-Type",s.contentType);if(s.ifModified)xhr.setRequestHeader("If-Modified-Since",jQuery.lastModified[s.url]||"Thu, 01 Jan 1970 00:00:00 GMT");xhr.setRequestHeader("X-Requested-With","XMLHttpRequest");xhr.setRequestHeader("Accept",s.dataType&&s.accepts[s.dataType]?s.accepts[s.dataType]+", */*":s.accepts._default);}catch(e){}if(s.beforeSend&&s.beforeSend(xhr,s)===false){s.global&&jQuery.active--;xhr.abort();return false;}if(s.global)jQuery.event.trigger("ajaxSend",[xhr,s]);var onreadystatechange=function(isTimeout){if(!requestDone&&xhr&&(xhr.readyState==4||isTimeout=="timeout")){requestDone=true;if(ival){clearInterval(ival);ival=null;}status=isTimeout=="timeout"&&"timeout"||!jQuery.httpSuccess(xhr)&&"error"||s.ifModified&&jQuery.httpNotModified(xhr,s.url)&&"notmodified"||"success";if(status=="success"){try{data=jQuery.httpData(xhr,s.dataType,s.dataFilter);}catch(e){status="parsererror";}}if(status=="success"){var modRes;try{modRes=xhr.getResponseHeader("Last-Modified");}catch(e){}if(s.ifModified&&modRes)jQuery.lastModified[s.url]=modRes;if(!jsonp)success();}else
+jQuery.handleError(s,xhr,status);complete();if(s.async)xhr=null;}};if(s.async){var ival=setInterval(onreadystatechange,13);if(s.timeout>0)setTimeout(function(){if(xhr){xhr.abort();if(!requestDone)onreadystatechange("timeout");}},s.timeout);}try{xhr.send(s.data);}catch(e){jQuery.handleError(s,xhr,null,e);}if(!s.async)onreadystatechange();function success(){if(s.success)s.success(data,status);if(s.global)jQuery.event.trigger("ajaxSuccess",[xhr,s]);}function complete(){if(s.complete)s.complete(xhr,status);if(s.global)jQuery.event.trigger("ajaxComplete",[xhr,s]);if(s.global&&!--jQuery.active)jQuery.event.trigger("ajaxStop");}return xhr;},handleError:function(s,xhr,status,e){if(s.error)s.error(xhr,status,e);if(s.global)jQuery.event.trigger("ajaxError",[xhr,s,e]);},active:0,httpSuccess:function(xhr){try{return!xhr.status&&location.protocol=="file:"||(xhr.status>=200&&xhr.status<300)||xhr.status==304||xhr.status==1223||jQuery.browser.safari&&xhr.status==undefined;}catch(e){}return false;},httpNotModified:function(xhr,url){try{var xhrRes=xhr.getResponseHeader("Last-Modified");return xhr.status==304||xhrRes==jQuery.lastModified[url]||jQuery.browser.safari&&xhr.status==undefined;}catch(e){}return false;},httpData:function(xhr,type,filter){var ct=xhr.getResponseHeader("content-type"),xml=type=="xml"||!type&&ct&&ct.indexOf("xml")>=0,data=xml?xhr.responseXML:xhr.responseText;if(xml&&data.documentElement.tagName=="parsererror")throw"parsererror";if(filter)data=filter(data,type);if(type=="script")jQuery.globalEval(data);if(type=="json")data=eval("("+data+")");return data;},param:function(a){var s=[];if(a.constructor==Array||a.jquery)jQuery.each(a,function(){s.push(encodeURIComponent(this.name)+"="+encodeURIComponent(this.value));});else
+for(var j in a)if(a[j]&&a[j].constructor==Array)jQuery.each(a[j],function(){s.push(encodeURIComponent(j)+"="+encodeURIComponent(this));});else
+s.push(encodeURIComponent(j)+"="+encodeURIComponent(jQuery.isFunction(a[j])?a[j]():a[j]));return s.join("&").replace(/%20/g,"+");}});jQuery.fn.extend({show:function(speed,callback){return speed?this.animate({height:"show",width:"show",opacity:"show"},speed,callback):this.filter(":hidden").each(function(){this.style.display=this.oldblock||"";if(jQuery.css(this,"display")=="none"){var elem=jQuery("<"+this.tagName+" />").appendTo("body");this.style.display=elem.css("display");if(this.style.display=="none")this.style.display="block";elem.remove();}}).end();},hide:function(speed,callback){return speed?this.animate({height:"hide",width:"hide",opacity:"hide"},speed,callback):this.filter(":visible").each(function(){this.oldblock=this.oldblock||jQuery.css(this,"display");this.style.display="none";}).end();},_toggle:jQuery.fn.toggle,toggle:function(fn,fn2){return jQuery.isFunction(fn)&&jQuery.isFunction(fn2)?this._toggle.apply(this,arguments):fn?this.animate({height:"toggle",width:"toggle",opacity:"toggle"},fn,fn2):this.each(function(){jQuery(this)[jQuery(this).is(":hidden")?"show":"hide"]();});},slideDown:function(speed,callback){return this.animate({height:"show"},speed,callback);},slideUp:function(speed,callback){return this.animate({height:"hide"},speed,callback);},slideToggle:function(speed,callback){return this.animate({height:"toggle"},speed,callback);},fadeIn:function(speed,callback){return this.animate({opacity:"show"},speed,callback);},fadeOut:function(speed,callback){return this.animate({opacity:"hide"},speed,callback);},fadeTo:function(speed,to,callback){return this.animate({opacity:to},speed,callback);},animate:function(prop,speed,easing,callback){var optall=jQuery.speed(speed,easing,callback);return this[optall.queue===false?"each":"queue"](function(){if(this.nodeType!=1)return false;var opt=jQuery.extend({},optall),p,hidden=jQuery(this).is(":hidden"),self=this;for(p in prop){if(prop[p]=="hide"&&hidden||prop[p]=="show"&&!hidden)return opt.complete.call(this);if(p=="height"||p=="width"){opt.display=jQuery.css(this,"display");opt.overflow=this.style.overflow;}}if(opt.overflow!=null)this.style.overflow="hidden";opt.curAnim=jQuery.extend({},prop);jQuery.each(prop,function(name,val){var e=new jQuery.fx(self,opt,name);if(/toggle|show|hide/.test(val))e[val=="toggle"?hidden?"show":"hide":val](prop);else{var parts=val.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),start=e.cur(true)||0;if(parts){var end=parseFloat(parts[2]),unit=parts[3]||"px";if(unit!="px"){self.style[name]=(end||1)+unit;start=((end||1)/e.cur(true))*start;self.style[name]=start+unit;}if(parts[1])end=((parts[1]=="-="?-1:1)*end)+start;e.custom(start,end,unit);}else
+e.custom(start,val,"");}});return true;});},queue:function(type,fn){if(jQuery.isFunction(type)||(type&&type.constructor==Array)){fn=type;type="fx";}if(!type||(typeof type=="string"&&!fn))return queue(this[0],type);return this.each(function(){if(fn.constructor==Array)queue(this,type,fn);else{queue(this,type).push(fn);if(queue(this,type).length==1)fn.call(this);}});},stop:function(clearQueue,gotoEnd){var timers=jQuery.timers;if(clearQueue)this.queue([]);this.each(function(){for(var i=timers.length-1;i>=0;i--)if(timers[i].elem==this){if(gotoEnd)timers[i](true);timers.splice(i,1);}});if(!gotoEnd)this.dequeue();return this;}});var queue=function(elem,type,array){if(elem){type=type||"fx";var q=jQuery.data(elem,type+"queue");if(!q||array)q=jQuery.data(elem,type+"queue",jQuery.makeArray(array));}return q;};jQuery.fn.dequeue=function(type){type=type||"fx";return this.each(function(){var q=queue(this,type);q.shift();if(q.length)q[0].call(this);});};jQuery.extend({speed:function(speed,easing,fn){var opt=speed&&speed.constructor==Object?speed:{complete:fn||!fn&&easing||jQuery.isFunction(speed)&&speed,duration:speed,easing:fn&&easing||easing&&easing.constructor!=Function&&easing};opt.duration=(opt.duration&&opt.duration.constructor==Number?opt.duration:jQuery.fx.speeds[opt.duration])||jQuery.fx.speeds.def;opt.old=opt.complete;opt.complete=function(){if(opt.queue!==false)jQuery(this).dequeue();if(jQuery.isFunction(opt.old))opt.old.call(this);};return opt;},easing:{linear:function(p,n,firstNum,diff){return firstNum+diff*p;},swing:function(p,n,firstNum,diff){return((-Math.cos(p*Math.PI)/2)+0.5)*diff+firstNum;}},timers:[],timerId:null,fx:function(elem,options,prop){this.options=options;this.elem=elem;this.prop=prop;if(!options.orig)options.orig={};}});jQuery.fx.prototype={update:function(){if(this.options.step)this.options.step.call(this.elem,this.now,this);(jQuery.fx.step[this.prop]||jQuery.fx.step._default)(this);if(this.prop=="height"||this.prop=="width")this.elem.style.display="block";},cur:function(force){if(this.elem[this.prop]!=null&&this.elem.style[this.prop]==null)return this.elem[this.prop];var r=parseFloat(jQuery.css(this.elem,this.prop,force));return r&&r>-10000?r:parseFloat(jQuery.curCSS(this.elem,this.prop))||0;},custom:function(from,to,unit){this.startTime=now();this.start=from;this.end=to;this.unit=unit||this.unit||"px";this.now=this.start;this.pos=this.state=0;this.update();var self=this;function t(gotoEnd){return self.step(gotoEnd);}t.elem=this.elem;jQuery.timers.push(t);if(jQuery.timerId==null){jQuery.timerId=setInterval(function(){var timers=jQuery.timers;for(var i=0;i<timers.length;i++)if(!timers[i]())timers.splice(i--,1);if(!timers.length){clearInterval(jQuery.timerId);jQuery.timerId=null;}},13);}},show:function(){this.options.orig[this.prop]=jQuery.attr(this.elem.style,this.prop);this.options.show=true;this.custom(0,this.cur());if(this.prop=="width"||this.prop=="height")this.elem.style[this.prop]="1px";jQuery(this.elem).show();},hide:function(){this.options.orig[this.prop]=jQuery.attr(this.elem.style,this.prop);this.options.hide=true;this.custom(this.cur(),0);},step:function(gotoEnd){var t=now();if(gotoEnd||t>this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;var done=true;for(var i in this.options.curAnim)if(this.options.curAnim[i]!==true)done=false;if(done){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;this.elem.style.display=this.options.display;if(jQuery.css(this.elem,"display")=="none")this.elem.style.display="block";}if(this.options.hide)this.elem.style.display="none";if(this.options.hide||this.options.show)for(var p in this.options.curAnim)jQuery.attr(this.elem.style,p,this.options.orig[p]);}if(done)this.options.complete.call(this.elem);return false;}else{var n=t-this.startTime;this.state=n/this.options.duration;this.pos=jQuery.easing[this.options.easing||(jQuery.easing.swing?"swing":"linear")](this.state,n,0,1,this.options.duration);this.now=this.start+((this.end-this.start)*this.pos);this.update();}return true;}};jQuery.extend(jQuery.fx,{speeds:{slow:600,fast:200,def:400},step:{scrollLeft:function(fx){fx.elem.scrollLeft=fx.now;},scrollTop:function(fx){fx.elem.scrollTop=fx.now;},opacity:function(fx){jQuery.attr(fx.elem.style,"opacity",fx.now);},_default:function(fx){fx.elem.style[fx.prop]=fx.now+fx.unit;}}});jQuery.fn.offset=function(){var left=0,top=0,elem=this[0],results;if(elem)with(jQuery.browser){var parent=elem.parentNode,offsetChild=elem,offsetParent=elem.offsetParent,doc=elem.ownerDocument,safari2=safari&&parseInt(version)<522&&!/adobeair/i.test(userAgent),css=jQuery.curCSS,fixed=css(elem,"position")=="fixed";if(elem.getBoundingClientRect){var box=elem.getBoundingClientRect();add(box.left+Math.max(doc.documentElement.scrollLeft,doc.body.scrollLeft),box.top+Math.max(doc.documentElement.scrollTop,doc.body.scrollTop));add(-doc.documentElement.clientLeft,-doc.documentElement.clientTop);}else{add(elem.offsetLeft,elem.offsetTop);while(offsetParent){add(offsetParent.offsetLeft,offsetParent.offsetTop);if(mozilla&&!/^t(able|d|h)$/i.test(offsetParent.tagName)||safari&&!safari2)border(offsetParent);if(!fixed&&css(offsetParent,"position")=="fixed")fixed=true;offsetChild=/^body$/i.test(offsetParent.tagName)?offsetChild:offsetParent;offsetParent=offsetParent.offsetParent;}while(parent&&parent.tagName&&!/^body|html$/i.test(parent.tagName)){if(!/^inline|table.*$/i.test(css(parent,"display")))add(-parent.scrollLeft,-parent.scrollTop);if(mozilla&&css(parent,"overflow")!="visible")border(parent);parent=parent.parentNode;}if((safari2&&(fixed||css(offsetChild,"position")=="absolute"))||(mozilla&&css(offsetChild,"position")!="absolute"))add(-doc.body.offsetLeft,-doc.body.offsetTop);if(fixed)add(Math.max(doc.documentElement.scrollLeft,doc.body.scrollLeft),Math.max(doc.documentElement.scrollTop,doc.body.scrollTop));}results={top:top,left:left};}function border(elem){add(jQuery.curCSS(elem,"borderLeftWidth",true),jQuery.curCSS(elem,"borderTopWidth",true));}function add(l,t){left+=parseInt(l,10)||0;top+=parseInt(t,10)||0;}return results;};jQuery.fn.extend({position:function(){var left=0,top=0,results;if(this[0]){var offsetParent=this.offsetParent(),offset=this.offset(),parentOffset=/^body|html$/i.test(offsetParent[0].tagName)?{top:0,left:0}:offsetParent.offset();offset.top-=num(this,'marginTop');offset.left-=num(this,'marginLeft');parentOffset.top+=num(offsetParent,'borderTopWidth');parentOffset.left+=num(offsetParent,'borderLeftWidth');results={top:offset.top-parentOffset.top,left:offset.left-parentOffset.left};}return results;},offsetParent:function(){var offsetParent=this[0].offsetParent;while(offsetParent&&(!/^body|html$/i.test(offsetParent.tagName)&&jQuery.css(offsetParent,'position')=='static'))offsetParent=offsetParent.offsetParent;return jQuery(offsetParent);}});jQuery.each(['Left','Top'],function(i,name){var method='scroll'+name;jQuery.fn[method]=function(val){if(!this[0])return;return val!=undefined?this.each(function(){this==window||this==document?window.scrollTo(!i?val:jQuery(window).scrollLeft(),i?val:jQuery(window).scrollTop()):this[method]=val;}):this[0]==window||this[0]==document?self[i?'pageYOffset':'pageXOffset']||jQuery.boxModel&&document.documentElement[method]||document.body[method]:this[0][method];};});jQuery.each(["Height","Width"],function(i,name){var tl=i?"Left":"Top",br=i?"Right":"Bottom";jQuery.fn["inner"+name]=function(){return this[name.toLowerCase()]()+num(this,"padding"+tl)+num(this,"padding"+br);};jQuery.fn["outer"+name]=function(margin){return this["inner"+name]()+num(this,"border"+tl+"Width")+num(this,"border"+br+"Width")+(margin?num(this,"margin"+tl)+num(this,"margin"+br):0);};});})(); \ No newline at end of file
diff --git a/help/PythonTutorial/_static/minus.png b/help/PythonTutorial/_static/minus.png
new file mode 100644
index 0000000..da1c562
--- /dev/null
+++ b/help/PythonTutorial/_static/minus.png
Binary files differ
diff --git a/help/PythonTutorial/_static/opensearch.xml b/help/PythonTutorial/_static/opensearch.xml
new file mode 100644
index 0000000..1b6a851
--- /dev/null
+++ b/help/PythonTutorial/_static/opensearch.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/">
+ <ShortName>Python</ShortName>
+ <Description>Search Python v2.6.4c2 documentation</Description>
+ <InputEncoding>utf-8</InputEncoding>
+ <Url type="text/html" method="get"
+ template="http://docs.python.org/dev/search.html?q={searchTerms}&amp;check_keywords=yes&amp;area=default"/>
+ <LongName>Python v2.6.4c2 documentation</LongName>
+<Image height="16" width="16" type="image/x-icon">http://www.python.org/images/favicon16x16.ico</Image>
+</OpenSearchDescription> \ No newline at end of file
diff --git a/help/PythonTutorial/_static/py.png b/help/PythonTutorial/_static/py.png
new file mode 100644
index 0000000..93e4a02
--- /dev/null
+++ b/help/PythonTutorial/_static/py.png
Binary files differ
diff --git a/help/PythonTutorial/_static/pygments.css b/help/PythonTutorial/_static/pygments.css
new file mode 100644
index 0000000..1f2d2b6
--- /dev/null
+++ b/help/PythonTutorial/_static/pygments.css
@@ -0,0 +1,61 @@
+.hll { background-color: #ffffcc }
+.c { color: #408090; font-style: italic } /* Comment */
+.err { border: 1px solid #FF0000 } /* Error */
+.k { color: #007020; font-weight: bold } /* Keyword */
+.o { color: #666666 } /* Operator */
+.cm { color: #408090; font-style: italic } /* Comment.Multiline */
+.cp { color: #007020 } /* Comment.Preproc */
+.c1 { color: #408090; font-style: italic } /* Comment.Single */
+.cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */
+.gd { color: #A00000 } /* Generic.Deleted */
+.ge { font-style: italic } /* Generic.Emph */
+.gr { color: #FF0000 } /* Generic.Error */
+.gh { color: #000080; font-weight: bold } /* Generic.Heading */
+.gi { color: #00A000 } /* Generic.Inserted */
+.go { color: #303030 } /* Generic.Output */
+.gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */
+.gs { font-weight: bold } /* Generic.Strong */
+.gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+.gt { color: #0040D0 } /* Generic.Traceback */
+.kc { color: #007020; font-weight: bold } /* Keyword.Constant */
+.kd { color: #007020; font-weight: bold } /* Keyword.Declaration */
+.kn { color: #007020; font-weight: bold } /* Keyword.Namespace */
+.kp { color: #007020 } /* Keyword.Pseudo */
+.kr { color: #007020; font-weight: bold } /* Keyword.Reserved */
+.kt { color: #902000 } /* Keyword.Type */
+.m { color: #208050 } /* Literal.Number */
+.s { color: #4070a0 } /* Literal.String */
+.na { color: #4070a0 } /* Name.Attribute */
+.nb { color: #007020 } /* Name.Builtin */
+.nc { color: #0e84b5; font-weight: bold } /* Name.Class */
+.no { color: #60add5 } /* Name.Constant */
+.nd { color: #555555; font-weight: bold } /* Name.Decorator */
+.ni { color: #d55537; font-weight: bold } /* Name.Entity */
+.ne { color: #007020 } /* Name.Exception */
+.nf { color: #06287e } /* Name.Function */
+.nl { color: #002070; font-weight: bold } /* Name.Label */
+.nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */
+.nt { color: #062873; font-weight: bold } /* Name.Tag */
+.nv { color: #bb60d5 } /* Name.Variable */
+.ow { color: #007020; font-weight: bold } /* Operator.Word */
+.w { color: #bbbbbb } /* Text.Whitespace */
+.mf { color: #208050 } /* Literal.Number.Float */
+.mh { color: #208050 } /* Literal.Number.Hex */
+.mi { color: #208050 } /* Literal.Number.Integer */
+.mo { color: #208050 } /* Literal.Number.Oct */
+.sb { color: #4070a0 } /* Literal.String.Backtick */
+.sc { color: #4070a0 } /* Literal.String.Char */
+.sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */
+.s2 { color: #4070a0 } /* Literal.String.Double */
+.se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */
+.sh { color: #4070a0 } /* Literal.String.Heredoc */
+.si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */
+.sx { color: #c65d09 } /* Literal.String.Other */
+.sr { color: #235388 } /* Literal.String.Regex */
+.s1 { color: #4070a0 } /* Literal.String.Single */
+.ss { color: #517918 } /* Literal.String.Symbol */
+.bp { color: #007020 } /* Name.Builtin.Pseudo */
+.vc { color: #bb60d5 } /* Name.Variable.Class */
+.vg { color: #bb60d5 } /* Name.Variable.Global */
+.vi { color: #bb60d5 } /* Name.Variable.Instance */
+.il { color: #208050 } /* Literal.Number.Integer.Long */ \ No newline at end of file
diff --git a/help/PythonTutorial/about.html b/help/PythonTutorial/about.html
new file mode 100644
index 0000000..b046d27
--- /dev/null
+++ b/help/PythonTutorial/about.html
@@ -0,0 +1,374 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+ <title>About these documents &mdash; Python v2.6.4c2 documentation</title>
+ <link rel="stylesheet" href="_static/default.css" type="text/css" />
+ <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+ <script type="text/javascript">
+ var DOCUMENTATION_OPTIONS = {
+ URL_ROOT: '',
+ VERSION: '2.6.4c2',
+ COLLAPSE_MODINDEX: false,
+ FILE_SUFFIX: '.html',
+ HAS_SOURCE: true
+ };
+ </script>
+ <script type="text/javascript" src="_static/jquery.js"></script>
+ <script type="text/javascript" src="_static/doctools.js"></script>
+ <link rel="search" type="application/opensearchdescription+xml"
+ title="Search within Python v2.6.4c2 documentation"
+ href="_static/opensearch.xml"/>
+ <link rel="author" title="About these documents" href="" />
+ <link rel="copyright" title="Copyright" href="copyright.html" />
+ <link rel="top" title="Python v2.6.4c2 documentation" href="index.html" />
+ <link rel="next" title="Reporting Bugs in Python" href="bugs.html" />
+ <link rel="prev" title="Glossary" href="glossary.html" />
+ <link rel="shortcut icon" type="image/png" href="_static/py.png" />
+
+
+ </head>
+ <body>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="modindex.html" title="Global Module Index"
+ accesskey="M">modules</a> |</li>
+ <li class="right" >
+ <a href="bugs.html" title="Reporting Bugs in Python"
+ accesskey="N">next</a> |</li>
+ <li class="right" >
+ <a href="glossary.html" title="Glossary"
+ accesskey="P">previous</a> |</li>
+ <li><img src="_static/py.png" alt=""
+ style="vertical-align: middle; margin-top: -1px"/></li>
+ <li><a href="index.html">Python v2.6.4c2 documentation</a> &raquo;</li>
+
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body">
+
+ <div class="section" id="about-these-documents">
+<h1>About these documents<a class="headerlink" href="#about-these-documents" title="Permalink to this headline">¶</a></h1>
+<p>These documents are generated from <a class="reference external" href="http://docutils.sf.net/rst.html">reStructuredText</a> sources by <em>Sphinx</em>, a document processor
+specifically written for the Python documentation.</p>
+<p>Development of the documentation and its toolchain takes place on the
+<a class="reference external" href="mailto:docs&#37;&#52;&#48;python&#46;org">docs<span>&#64;</span>python<span>&#46;</span>org</a> mailing list. We&#8217;re always looking for volunteers wanting
+to help with the docs, so feel free to send a mail there!</p>
+<p>Many thanks go to:</p>
+<ul class="simple">
+<li>Fred L. Drake, Jr., the creator of the original Python documentation toolset
+and writer of much of the content;</li>
+<li>the <a class="reference external" href="http://docutils.sf.net/">Docutils</a> project for creating
+reStructuredText and the Docutils suite;</li>
+<li>Fredrik Lundh for his <a class="reference external" href="http://effbot.org/zone/pyref.htm">Alternative Python Reference</a> project from which Sphinx got many good
+ideas.</li>
+</ul>
+<p>See <a class="reference external" href="bugs.html#reporting-bugs"><em>Reporting Bugs in Python</em></a> for information how to report bugs in this
+documentation, or Python itself.</p>
+<div class="section" id="contributors-to-the-python-documentation">
+<h2>Contributors to the Python Documentation<a class="headerlink" href="#contributors-to-the-python-documentation" title="Permalink to this headline">¶</a></h2>
+<p>This section lists people who have contributed in some way to the Python
+documentation. It is probably not complete &#8211; if you feel that you or
+anyone else should be on this list, please let us know (send email to
+<a class="reference external" href="mailto:docs&#37;&#52;&#48;python&#46;org">docs<span>&#64;</span>python<span>&#46;</span>org</a>), and we&#8217;ll be glad to correct the problem.</p>
+<ul class="simple">
+<li>Aahz</li>
+<li>Michael Abbott</li>
+<li>Steve Alexander</li>
+<li>Jim Ahlstrom</li>
+<li>Fred Allen</li>
+<li>A. Amoroso</li>
+<li>Pehr Anderson</li>
+<li>Oliver Andrich</li>
+<li>Heidi Annexstad</li>
+<li>Jesús Cea Avión</li>
+<li>Daniel Barclay</li>
+<li>Chris Barker</li>
+<li>Don Bashford</li>
+<li>Anthony Baxter</li>
+<li>Alexander Belopolsky</li>
+<li>Bennett Benson</li>
+<li>Jonathan Black</li>
+<li>Robin Boerdijk</li>
+<li>Michal Bozon</li>
+<li>Aaron Brancotti</li>
+<li>Georg Brandl</li>
+<li>Keith Briggs</li>
+<li>Ian Bruntlett</li>
+<li>Lee Busby</li>
+<li>Lorenzo M. Catucci</li>
+<li>Carl Cerecke</li>
+<li>Mauro Cicognini</li>
+<li>Gilles Civario</li>
+<li>Mike Clarkson</li>
+<li>Steve Clift</li>
+<li>Dave Cole</li>
+<li>Matthew Cowles</li>
+<li>Jeremy Craven</li>
+<li>Andrew Dalke</li>
+<li>Ben Darnell</li>
+<li>L. Peter Deutsch</li>
+<li>Robert Donohue</li>
+<li>Fred L. Drake, Jr.</li>
+<li>Josip Dzolonga</li>
+<li>Jeff Epler</li>
+<li>Michael Ernst</li>
+<li>Blame Andy Eskilsson</li>
+<li>Carey Evans</li>
+<li>Martijn Faassen</li>
+<li>Carl Feynman</li>
+<li>Dan Finnie</li>
+<li>Hernán Martínez Foffani</li>
+<li>Stefan Franke</li>
+<li>Jim Fulton</li>
+<li>Peter Funk</li>
+<li>Lele Gaifax</li>
+<li>Matthew Gallagher</li>
+<li>Gabriel Genellina</li>
+<li>Ben Gertzfield</li>
+<li>Nadim Ghaznavi</li>
+<li>Jonathan Giddy</li>
+<li>Shelley Gooch</li>
+<li>Nathaniel Gray</li>
+<li>Grant Griffin</li>
+<li>Thomas Guettler</li>
+<li>Anders Hammarquist</li>
+<li>Mark Hammond</li>
+<li>Harald Hanche-Olsen</li>
+<li>Manus Hand</li>
+<li>Gerhard Häring</li>
+<li>Travis B. Hartwell</li>
+<li>Tim Hatch</li>
+<li>Janko Hauser</li>
+<li>Thomas Heller</li>
+<li>Bernhard Herzog</li>
+<li>Magnus L. Hetland</li>
+<li>Konrad Hinsen</li>
+<li>Stefan Hoffmeister</li>
+<li>Albert Hofkamp</li>
+<li>Gregor Hoffleit</li>
+<li>Steve Holden</li>
+<li>Thomas Holenstein</li>
+<li>Gerrit Holl</li>
+<li>Rob Hooft</li>
+<li>Brian Hooper</li>
+<li>Randall Hopper</li>
+<li>Michael Hudson</li>
+<li>Eric Huss</li>
+<li>Jeremy Hylton</li>
+<li>Roger Irwin</li>
+<li>Jack Jansen</li>
+<li>Philip H. Jensen</li>
+<li>Pedro Diaz Jimenez</li>
+<li>Kent Johnson</li>
+<li>Lucas de Jonge</li>
+<li>Andreas Jung</li>
+<li>Robert Kern</li>
+<li>Jim Kerr</li>
+<li>Jan Kim</li>
+<li>Greg Kochanski</li>
+<li>Guido Kollerie</li>
+<li>Peter A. Koren</li>
+<li>Daniel Kozan</li>
+<li>Andrew M. Kuchling</li>
+<li>Dave Kuhlman</li>
+<li>Erno Kuusela</li>
+<li>Thomas Lamb</li>
+<li>Detlef Lannert</li>
+<li>Piers Lauder</li>
+<li>Glyph Lefkowitz</li>
+<li>Robert Lehmann</li>
+<li>Marc-André Lemburg</li>
+<li>Ross Light</li>
+<li>Ulf A. Lindgren</li>
+<li>Everett Lipman</li>
+<li>Mirko Liss</li>
+<li>Martin von Löwis</li>
+<li>Fredrik Lundh</li>
+<li>Jeff MacDonald</li>
+<li>John Machin</li>
+<li>Andrew MacIntyre</li>
+<li>Vladimir Marangozov</li>
+<li>Vincent Marchetti</li>
+<li>Laura Matson</li>
+<li>Daniel May</li>
+<li>Rebecca McCreary</li>
+<li>Doug Mennella</li>
+<li>Paolo Milani</li>
+<li>Skip Montanaro</li>
+<li>Paul Moore</li>
+<li>Ross Moore</li>
+<li>Sjoerd Mullender</li>
+<li>Dale Nagata</li>
+<li>Ng Pheng Siong</li>
+<li>Koray Oner</li>
+<li>Tomas Oppelstrup</li>
+<li>Denis S. Otkidach</li>
+<li>Zooko O&#8217;Whielacronx</li>
+<li>Shriphani Palakodety</li>
+<li>William Park</li>
+<li>Joonas Paalasmaa</li>
+<li>Harri Pasanen</li>
+<li>Bo Peng</li>
+<li>Tim Peters</li>
+<li>Benjamin Peterson</li>
+<li>Christopher Petrilli</li>
+<li>Justin D. Pettit</li>
+<li>Chris Phoenix</li>
+<li>François Pinard</li>
+<li>Paul Prescod</li>
+<li>Eric S. Raymond</li>
+<li>Edward K. Ream</li>
+<li>Sean Reifschneider</li>
+<li>Bernhard Reiter</li>
+<li>Armin Rigo</li>
+<li>Wes Rishel</li>
+<li>Armin Ronacher</li>
+<li>Jim Roskind</li>
+<li>Guido van Rossum</li>
+<li>Donald Wallace Rouse II</li>
+<li>Mark Russell</li>
+<li>Nick Russo</li>
+<li>Chris Ryland</li>
+<li>Constantina S.</li>
+<li>Hugh Sasse</li>
+<li>Bob Savage</li>
+<li>Scott Schram</li>
+<li>Neil Schemenauer</li>
+<li>Barry Scott</li>
+<li>Joakim Sernbrant</li>
+<li>Justin Sheehy</li>
+<li>Charlie Shepherd</li>
+<li>Michael Simcich</li>
+<li>Ionel Simionescu</li>
+<li>Michael Sloan</li>
+<li>Gregory P. Smith</li>
+<li>Roy Smith</li>
+<li>Clay Spence</li>
+<li>Nicholas Spies</li>
+<li>Tage Stabell-Kulo</li>
+<li>Frank Stajano</li>
+<li>Anthony Starks</li>
+<li>Greg Stein</li>
+<li>Peter Stoehr</li>
+<li>Mark Summerfield</li>
+<li>Reuben Sumner</li>
+<li>Kalle Svensson</li>
+<li>Jim Tittsler</li>
+<li>David Turner</li>
+<li>Ville Vainio</li>
+<li>Martijn Vries</li>
+<li>Charles G. Waldman</li>
+<li>Greg Ward</li>
+<li>Barry Warsaw</li>
+<li>Corran Webster</li>
+<li>Glyn Webster</li>
+<li>Bob Weiner</li>
+<li>Eddy Welbourne</li>
+<li>Jeff Wheeler</li>
+<li>Mats Wichmann</li>
+<li>Gerry Wiener</li>
+<li>Timothy Wild</li>
+<li>Collin Winter</li>
+<li>Blake Winton</li>
+<li>Dan Wolfe</li>
+<li>Steven Work</li>
+<li>Thomas Wouters</li>
+<li>Ka-Ping Yee</li>
+<li>Rory Yorke</li>
+<li>Moshe Zadka</li>
+<li>Milan Zamazal</li>
+<li>Cheng Zhang</li>
+</ul>
+<p>It is only with the input and contributions of the Python community
+that Python has such wonderful documentation &#8211; Thank You!</p>
+</div>
+</div>
+
+
+ </div>
+ </div>
+ </div>
+ <div class="sphinxsidebar">
+ <div class="sphinxsidebarwrapper">
+ <h3><a href="contents.html">Table Of Contents</a></h3>
+ <ul>
+<li><a class="reference external" href="">About these documents</a><ul>
+<li><a class="reference external" href="#contributors-to-the-python-documentation">Contributors to the Python Documentation</a></li>
+</ul>
+</li>
+</ul>
+
+ <h4>Previous topic</h4>
+ <p class="topless"><a href="glossary.html"
+ title="previous chapter">Glossary</a></p>
+ <h4>Next topic</h4>
+ <p class="topless"><a href="bugs.html"
+ title="next chapter">Reporting Bugs in Python</a></p>
+ <h3>This Page</h3>
+ <ul class="this-page-menu">
+ <li><a href="_sources/about.txt"
+ rel="nofollow">Show Source</a></li>
+ </ul>
+ <div id="searchbox" style="display: none">
+ <h3>Quick search</h3>
+ <form class="search" action="search.html" method="get">
+ <input type="text" name="q" size="18" />
+ <input type="submit" value="Go" />
+ <input type="hidden" name="check_keywords" value="yes" />
+ <input type="hidden" name="area" value="default" />
+ </form>
+ <p class="searchtip" style="font-size: 90%">
+ Enter search terms or a module, class or function name.
+ </p>
+ </div>
+ <script type="text/javascript">$('#searchbox').show(0);</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="genindex.html" title="General Index"
+ >index</a></li>
+ <li class="right" >
+ <a href="modindex.html" title="Global Module Index"
+ >modules</a> |</li>
+ <li class="right" >
+ <a href="bugs.html" title="Reporting Bugs in Python"
+ >next</a> |</li>
+ <li class="right" >
+ <a href="glossary.html" title="Glossary"
+ >previous</a> |</li>
+ <li><img src="_static/py.png" alt=""
+ style="vertical-align: middle; margin-top: -1px"/></li>
+ <li><a href="index.html">Python v2.6.4c2 documentation</a> &raquo;</li>
+
+ </ul>
+ </div>
+ <div class="footer">
+ &copy; <a href="copyright.html">Copyright</a> 1990-2009, Python Software Foundation.
+ <br />
+ The Python Software Foundation is a non-profit corporation.
+ <a href="http://www.python.org/psf/donations/">Please donate.</a>
+ <br />
+ Last updated on Oct 19, 2009.
+ Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 0.6.2.
+ </div>
+
+ </body>
+</html> \ No newline at end of file
diff --git a/help/PythonTutorial/copyright.html b/help/PythonTutorial/copyright.html
new file mode 100644
index 0000000..388023e
--- /dev/null
+++ b/help/PythonTutorial/copyright.html
@@ -0,0 +1,140 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+ <title>Copyright &mdash; Python v2.6.4c2 documentation</title>
+ <link rel="stylesheet" href="_static/default.css" type="text/css" />
+ <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+ <script type="text/javascript">
+ var DOCUMENTATION_OPTIONS = {
+ URL_ROOT: '',
+ VERSION: '2.6.4c2',
+ COLLAPSE_MODINDEX: false,
+ FILE_SUFFIX: '.html',
+ HAS_SOURCE: true
+ };
+ </script>
+ <script type="text/javascript" src="_static/jquery.js"></script>
+ <script type="text/javascript" src="_static/doctools.js"></script>
+ <link rel="search" type="application/opensearchdescription+xml"
+ title="Search within Python v2.6.4c2 documentation"
+ href="_static/opensearch.xml"/>
+ <link rel="author" title="About these documents" href="about.html" />
+ <link rel="copyright" title="Copyright" href="" />
+ <link rel="top" title="Python v2.6.4c2 documentation" href="index.html" />
+ <link rel="next" title="History and License" href="license.html" />
+ <link rel="prev" title="Reporting Bugs in Python" href="bugs.html" />
+ <link rel="shortcut icon" type="image/png" href="_static/py.png" />
+
+
+ </head>
+ <body>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="modindex.html" title="Global Module Index"
+ accesskey="M">modules</a> |</li>
+ <li class="right" >
+ <a href="license.html" title="History and License"
+ accesskey="N">next</a> |</li>
+ <li class="right" >
+ <a href="bugs.html" title="Reporting Bugs in Python"
+ accesskey="P">previous</a> |</li>
+ <li><img src="_static/py.png" alt=""
+ style="vertical-align: middle; margin-top: -1px"/></li>
+ <li><a href="index.html">Python v2.6.4c2 documentation</a> &raquo;</li>
+
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body">
+
+ <div class="section" id="copyright">
+<h1>Copyright<a class="headerlink" href="#copyright" title="Permalink to this headline">¶</a></h1>
+<p>Python and this documentation is:</p>
+<p>Copyright © 2001-2008 Python Software Foundation. All rights reserved.</p>
+<p>Copyright © 2000 BeOpen.com. All rights reserved.</p>
+<p>Copyright © 1995-2000 Corporation for National Research Initiatives. All rights
+reserved.</p>
+<p>Copyright © 1991-1995 Stichting Mathematisch Centrum. All rights reserved.</p>
+<hr class="docutils" />
+<p>See <a class="reference external" href="license.html#history-and-license"><em>History and License</em></a> for complete license and permissions information.</p>
+</div>
+
+
+ </div>
+ </div>
+ </div>
+ <div class="sphinxsidebar">
+ <div class="sphinxsidebarwrapper">
+ <h4>Previous topic</h4>
+ <p class="topless"><a href="bugs.html"
+ title="previous chapter">Reporting Bugs in Python</a></p>
+ <h4>Next topic</h4>
+ <p class="topless"><a href="license.html"
+ title="next chapter">History and License</a></p>
+ <h3>This Page</h3>
+ <ul class="this-page-menu">
+ <li><a href="_sources/copyright.txt"
+ rel="nofollow">Show Source</a></li>
+ </ul>
+ <div id="searchbox" style="display: none">
+ <h3>Quick search</h3>
+ <form class="search" action="search.html" method="get">
+ <input type="text" name="q" size="18" />
+ <input type="submit" value="Go" />
+ <input type="hidden" name="check_keywords" value="yes" />
+ <input type="hidden" name="area" value="default" />
+ </form>
+ <p class="searchtip" style="font-size: 90%">
+ Enter search terms or a module, class or function name.
+ </p>
+ </div>
+ <script type="text/javascript">$('#searchbox').show(0);</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="genindex.html" title="General Index"
+ >index</a></li>
+ <li class="right" >
+ <a href="modindex.html" title="Global Module Index"
+ >modules</a> |</li>
+ <li class="right" >
+ <a href="license.html" title="History and License"
+ >next</a> |</li>
+ <li class="right" >
+ <a href="bugs.html" title="Reporting Bugs in Python"
+ >previous</a> |</li>
+ <li><img src="_static/py.png" alt=""
+ style="vertical-align: middle; margin-top: -1px"/></li>
+ <li><a href="index.html">Python v2.6.4c2 documentation</a> &raquo;</li>
+
+ </ul>
+ </div>
+ <div class="footer">
+ &copy; <a href="">Copyright</a> 1990-2009, Python Software Foundation.
+ <br />
+ The Python Software Foundation is a non-profit corporation.
+ <a href="http://www.python.org/psf/donations/">Please donate.</a>
+ <br />
+ Last updated on Oct 19, 2009.
+ Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 0.6.2.
+ </div>
+
+ </body>
+</html> \ No newline at end of file
diff --git a/help/PythonTutorial/genindex.html b/help/PythonTutorial/genindex.html
new file mode 100644
index 0000000..ae350a4
--- /dev/null
+++ b/help/PythonTutorial/genindex.html
@@ -0,0 +1,177 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+ <title>Index &mdash; Python v2.6.4c2 documentation</title>
+ <link rel="stylesheet" href="_static/default.css" type="text/css" />
+ <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+ <script type="text/javascript">
+ var DOCUMENTATION_OPTIONS = {
+ URL_ROOT: '',
+ VERSION: '2.6.4c2',
+ COLLAPSE_MODINDEX: false,
+ FILE_SUFFIX: '.html',
+ HAS_SOURCE: true
+ };
+ </script>
+ <script type="text/javascript" src="_static/jquery.js"></script>
+ <script type="text/javascript" src="_static/doctools.js"></script>
+ <link rel="search" type="application/opensearchdescription+xml"
+ title="Search within Python v2.6.4c2 documentation"
+ href="_static/opensearch.xml"/>
+ <link rel="author" title="About these documents" href="about.html" />
+ <link rel="copyright" title="Copyright" href="copyright.html" />
+ <link rel="top" title="Python v2.6.4c2 documentation" href="index.html" />
+ <link rel="shortcut icon" type="image/png" href="_static/py.png" />
+
+
+ </head>
+ <body>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="modindex.html" title="Global Module Index"
+ accesskey="M">modules</a> |</li>
+ <li><img src="_static/py.png" alt=""
+ style="vertical-align: middle; margin-top: -1px"/></li>
+ <li><a href="index.html">Python v2.6.4c2 documentation</a> &raquo;</li>
+
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body">
+
+
+ <h1 id="index">Index</h1>
+
+ <p>Index pages by letter:</p>
+
+ <p><a href="genindex-Symbols.html"><strong>Symbols</strong></a>
+ | <a href="genindex-_.html"><strong>_</strong></a>
+ | <a href="genindex-A.html"><strong>A</strong></a>
+ | <a href="genindex-B.html"><strong>B</strong></a>
+ | <a href="genindex-C.html"><strong>C</strong></a>
+ | <a href="genindex-D.html"><strong>D</strong></a>
+ | <a href="genindex-E.html"><strong>E</strong></a>
+ | <a href="genindex-F.html"><strong>F</strong></a>
+ | <a href="genindex-G.html"><strong>G</strong></a>
+ | <a href="genindex-H.html"><strong>H</strong></a>
+ | <a href="genindex-I.html"><strong>I</strong></a>
+ | <a href="genindex-J.html"><strong>J</strong></a>
+ | <a href="genindex-K.html"><strong>K</strong></a>
+ | <a href="genindex-L.html"><strong>L</strong></a>
+ | <a href="genindex-M.html"><strong>M</strong></a>
+ | <a href="genindex-N.html"><strong>N</strong></a>
+ | <a href="genindex-O.html"><strong>O</strong></a>
+ | <a href="genindex-P.html"><strong>P</strong></a>
+ | <a href="genindex-Q.html"><strong>Q</strong></a>
+ | <a href="genindex-R.html"><strong>R</strong></a>
+ | <a href="genindex-S.html"><strong>S</strong></a>
+ | <a href="genindex-T.html"><strong>T</strong></a>
+ | <a href="genindex-U.html"><strong>U</strong></a>
+ | <a href="genindex-V.html"><strong>V</strong></a>
+ | <a href="genindex-W.html"><strong>W</strong></a>
+ | <a href="genindex-X.html"><strong>X</strong></a>
+ | <a href="genindex-Y.html"><strong>Y</strong></a>
+ | <a href="genindex-Z.html"><strong>Z</strong></a>
+ </p>
+
+ <p><a href="genindex-all.html"><strong>Full index on one page</strong>
+ (can be huge)</a></p>
+
+
+ </div>
+ </div>
+ </div>
+ <div class="sphinxsidebar">
+ <div class="sphinxsidebarwrapper">
+
+ <h4>Index</h4>
+ <p><a href="genindex-Symbols.html"><strong>Symbols</strong></a>
+ | <a href="genindex-_.html"><strong>_</strong></a>
+ | <a href="genindex-A.html"><strong>A</strong></a>
+ | <a href="genindex-B.html"><strong>B</strong></a>
+ | <a href="genindex-C.html"><strong>C</strong></a>
+ | <a href="genindex-D.html"><strong>D</strong></a>
+ | <a href="genindex-E.html"><strong>E</strong></a>
+ | <a href="genindex-F.html"><strong>F</strong></a>
+ | <a href="genindex-G.html"><strong>G</strong></a>
+ | <a href="genindex-H.html"><strong>H</strong></a>
+ | <a href="genindex-I.html"><strong>I</strong></a>
+ | <a href="genindex-J.html"><strong>J</strong></a>
+ | <a href="genindex-K.html"><strong>K</strong></a>
+ | <a href="genindex-L.html"><strong>L</strong></a>
+ | <a href="genindex-M.html"><strong>M</strong></a>
+ | <a href="genindex-N.html"><strong>N</strong></a>
+ | <a href="genindex-O.html"><strong>O</strong></a>
+ | <a href="genindex-P.html"><strong>P</strong></a>
+ | <a href="genindex-Q.html"><strong>Q</strong></a>
+ | <a href="genindex-R.html"><strong>R</strong></a>
+ | <a href="genindex-S.html"><strong>S</strong></a>
+ | <a href="genindex-T.html"><strong>T</strong></a>
+ | <a href="genindex-U.html"><strong>U</strong></a>
+ | <a href="genindex-V.html"><strong>V</strong></a>
+ | <a href="genindex-W.html"><strong>W</strong></a>
+ | <a href="genindex-X.html"><strong>X</strong></a>
+ | <a href="genindex-Y.html"><strong>Y</strong></a>
+ | <a href="genindex-Z.html"><strong>Z</strong></a>
+ </p>
+
+ <p><a href="genindex-all.html"><strong>Full index on one page</strong></a></p>
+
+
+
+ <div id="searchbox" style="display: none">
+ <h3>Quick search</h3>
+ <form class="search" action="search.html" method="get">
+ <input type="text" name="q" size="18" />
+ <input type="submit" value="Go" />
+ <input type="hidden" name="check_keywords" value="yes" />
+ <input type="hidden" name="area" value="default" />
+ </form>
+ <p class="searchtip" style="font-size: 90%">
+ Enter search terms or a module, class or function name.
+ </p>
+ </div>
+ <script type="text/javascript">$('#searchbox').show(0);</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="" title="General Index"
+ >index</a></li>
+ <li class="right" >
+ <a href="modindex.html" title="Global Module Index"
+ >modules</a> |</li>
+ <li><img src="_static/py.png" alt=""
+ style="vertical-align: middle; margin-top: -1px"/></li>
+ <li><a href="index.html">Python v2.6.4c2 documentation</a> &raquo;</li>
+
+ </ul>
+ </div>
+ <div class="footer">
+ &copy; <a href="copyright.html">Copyright</a> 1990-2009, Python Software Foundation.
+ <br />
+ The Python Software Foundation is a non-profit corporation.
+ <a href="http://www.python.org/psf/donations/">Please donate.</a>
+ <br />
+ Last updated on Oct 19, 2009.
+ Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 0.6.2.
+ </div>
+
+ </body>
+</html> \ No newline at end of file
diff --git a/help/PythonTutorial/glossary.html b/help/PythonTutorial/glossary.html
new file mode 100644
index 0000000..0946bcb
--- /dev/null
+++ b/help/PythonTutorial/glossary.html
@@ -0,0 +1,610 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+ <title>Glossary &mdash; Python v2.6.4c2 documentation</title>
+ <link rel="stylesheet" href="_static/default.css" type="text/css" />
+ <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+ <script type="text/javascript">
+ var DOCUMENTATION_OPTIONS = {
+ URL_ROOT: '',
+ VERSION: '2.6.4c2',
+ COLLAPSE_MODINDEX: false,
+ FILE_SUFFIX: '.html',
+ HAS_SOURCE: true
+ };
+ </script>
+ <script type="text/javascript" src="_static/jquery.js"></script>
+ <script type="text/javascript" src="_static/doctools.js"></script>
+ <link rel="search" type="application/opensearchdescription+xml"
+ title="Search within Python v2.6.4c2 documentation"
+ href="_static/opensearch.xml"/>
+ <link rel="author" title="About these documents" href="about.html" />
+ <link rel="copyright" title="Copyright" href="copyright.html" />
+ <link rel="top" title="Python v2.6.4c2 documentation" href="index.html" />
+ <link rel="next" title="About these documents" href="about.html" />
+ <link rel="prev" title="HOWTO Use Python in the web" href="howto/webservers.html" />
+ <link rel="shortcut icon" type="image/png" href="_static/py.png" />
+
+
+ </head>
+ <body>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="modindex.html" title="Global Module Index"
+ accesskey="M">modules</a> |</li>
+ <li class="right" >
+ <a href="about.html" title="About these documents"
+ accesskey="N">next</a> |</li>
+ <li class="right" >
+ <a href="howto/webservers.html" title="HOWTO Use Python in the web"
+ accesskey="P">previous</a> |</li>
+ <li><img src="_static/py.png" alt=""
+ style="vertical-align: middle; margin-top: -1px"/></li>
+ <li><a href="index.html">Python v2.6.4c2 documentation</a> &raquo;</li>
+
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body">
+
+ <div class="section" id="glossary">
+<span id="id1"></span><h1>Glossary<a class="headerlink" href="#glossary" title="Permalink to this headline">¶</a></h1>
+<dl class="glossary docutils">
+<dt id="term-"><tt class="docutils literal"><span class="pre">&gt;&gt;&gt;</span></tt></dt>
+<dd>The default Python prompt of the interactive shell. Often seen for code
+examples which can be executed interactively in the interpreter.</dd>
+<dt id="term-1"><tt class="docutils literal"><span class="pre">...</span></tt></dt>
+<dd>The default Python prompt of the interactive shell when entering code for
+an indented code block or within a pair of matching left and right
+delimiters (parentheses, square brackets or curly braces).</dd>
+<dt id="term-to3">2to3</dt>
+<dd><p class="first">A tool that tries to convert Python 2.x code to Python 3.x code by
+handling most of the incompatibilites which can be detected by parsing the
+source and traversing the parse tree.</p>
+<p class="last">2to3 is available in the standard library as <a title="the 2to3 library" class="reference external" href="library/2to3.html#module-lib2to3"><tt class="xref docutils literal"><span class="pre">lib2to3</span></tt></a>; a standalone
+entry point is provided as <tt class="docutils literal"><span class="pre">Tools/scripts/2to3</span></tt>. See
+<a class="reference external" href="library/2to3.html#to3-reference"><em>2to3 - Automated Python 2 to 3 code translation</em></a>.</p>
+</dd>
+<dt id="term-abstract-base-class">abstract base class</dt>
+<dd>Abstract Base Classes (abbreviated ABCs) complement <a class="reference internal" href="#term-duck-typing"><em class="xref">duck-typing</em></a> by
+providing a way to define interfaces when other techniques like <a title="hasattr" class="reference external" href="library/functions.html#hasattr"><tt class="xref docutils literal"><span class="pre">hasattr()</span></tt></a>
+would be clumsy. Python comes with many builtin ABCs for data structures
+(in the <a title="High-performance datatypes" class="reference external" href="library/collections.html#module-collections"><tt class="xref docutils literal"><span class="pre">collections</span></tt></a> module), numbers (in the <a title="Numeric abstract base classes (Complex, Real, Integral, etc.)." class="reference external" href="library/numbers.html#module-numbers"><tt class="xref docutils literal"><span class="pre">numbers</span></tt></a>
+module), and streams (in the <a title="Core tools for working with streams." class="reference external" href="library/io.html#module-io"><tt class="xref docutils literal"><span class="pre">io</span></tt></a> module). You can create your own
+ABC with the <a title="Abstract base classes according to PEP 3119." class="reference external" href="library/abc.html#module-abc"><tt class="xref docutils literal"><span class="pre">abc</span></tt></a> module.</dd>
+<dt id="term-argument">argument</dt>
+<dd><p class="first">A value passed to a function or method, assigned to a named local
+variable in the function body. A function or method may have both
+positional arguments and keyword arguments in its definition.
+Positional and keyword arguments may be variable-length: <tt class="docutils literal"><span class="pre">*</span></tt> accepts
+or passes (if in the function definition or call) several positional
+arguments in a list, while <tt class="docutils literal"><span class="pre">**</span></tt> does the same for keyword arguments
+in a dictionary.</p>
+<p class="last">Any expression may be used within the argument list, and the evaluated
+value is passed to the local variable.</p>
+</dd>
+<dt id="term-attribute">attribute</dt>
+<dd>A value associated with an object which is referenced by name using
+dotted expressions. For example, if an object <em>o</em> has an attribute
+<em>a</em> it would be referenced as <em>o.a</em>.</dd>
+<dt id="term-bdfl">BDFL</dt>
+<dd>Benevolent Dictator For Life, a.k.a. <a class="reference external" href="http://www.python.org/~guido/">Guido van Rossum</a>, Python&#8217;s creator.</dd>
+<dt id="term-bytecode">bytecode</dt>
+<dd>Python source code is compiled into bytecode, the internal representation
+of a Python program in the interpreter. The bytecode is also cached in
+<tt class="docutils literal"><span class="pre">.pyc</span></tt> and <tt class="docutils literal"><span class="pre">.pyo</span></tt> files so that executing the same file is faster the
+second time (recompilation from source to bytecode can be avoided). This
+&#8220;intermediate language&#8221; is said to run on a <a class="reference internal" href="#term-virtual-machine"><em class="xref">virtual machine</em></a>
+that executes the machine code corresponding to each bytecode.</dd>
+<dt id="term-class">class</dt>
+<dd>A template for creating user-defined objects. Class definitions
+normally contain method definitions which operate on instances of the
+class.</dd>
+<dt id="term-classic-class">classic class</dt>
+<dd>Any class which does not inherit from <a title="object" class="reference external" href="library/functions.html#object"><tt class="xref docutils literal"><span class="pre">object</span></tt></a>. See
+<a class="reference internal" href="#term-new-style-class"><em class="xref">new-style class</em></a>. Classic classes will be removed in Python 3.0.</dd>
+<dt id="term-coercion">coercion</dt>
+<dd>The implicit conversion of an instance of one type to another during an
+operation which involves two arguments of the same type. For example,
+<tt class="docutils literal"><span class="pre">int(3.15)</span></tt> converts the floating point number to the integer <tt class="docutils literal"><span class="pre">3</span></tt>, but
+in <tt class="docutils literal"><span class="pre">3+4.5</span></tt>, each argument is of a different type (one int, one float),
+and both must be converted to the same type before they can be added or it
+will raise a <tt class="docutils literal"><span class="pre">TypeError</span></tt>. Coercion between two operands can be
+performed with the <tt class="docutils literal"><span class="pre">coerce</span></tt> builtin function; thus, <tt class="docutils literal"><span class="pre">3+4.5</span></tt> is
+equivalent to calling <tt class="docutils literal"><span class="pre">operator.add(*coerce(3,</span> <span class="pre">4.5))</span></tt> and results in
+<tt class="docutils literal"><span class="pre">operator.add(3.0,</span> <span class="pre">4.5)</span></tt>. Without coercion, all arguments of even
+compatible types would have to be normalized to the same value by the
+programmer, e.g., <tt class="docutils literal"><span class="pre">float(3)+4.5</span></tt> rather than just <tt class="docutils literal"><span class="pre">3+4.5</span></tt>.</dd>
+<dt id="term-complex-number">complex number</dt>
+<dd>An extension of the familiar real number system in which all numbers are
+expressed as a sum of a real part and an imaginary part. Imaginary
+numbers are real multiples of the imaginary unit (the square root of
+<tt class="docutils literal"><span class="pre">-1</span></tt>), often written <tt class="docutils literal"><span class="pre">i</span></tt> in mathematics or <tt class="docutils literal"><span class="pre">j</span></tt> in
+engineering. Python has builtin support for complex numbers, which are
+written with this latter notation; the imaginary part is written with a
+<tt class="docutils literal"><span class="pre">j</span></tt> suffix, e.g., <tt class="docutils literal"><span class="pre">3+1j</span></tt>. To get access to complex equivalents of the
+<a title="Mathematical functions (sin() etc.)." class="reference external" href="library/math.html#module-math"><tt class="xref docutils literal"><span class="pre">math</span></tt></a> module, use <a title="Mathematical functions for complex numbers." class="reference external" href="library/cmath.html#module-cmath"><tt class="xref docutils literal"><span class="pre">cmath</span></tt></a>. Use of complex numbers is a fairly
+advanced mathematical feature. If you&#8217;re not aware of a need for them,
+it&#8217;s almost certain you can safely ignore them.</dd>
+<dt id="term-context-manager">context manager</dt>
+<dd>An object which controls the environment seen in a <a class="reference external" href="reference/compound_stmts.html#with"><tt class="xref docutils literal"><span class="pre">with</span></tt></a>
+statement by defining <a title="object.__enter__" class="reference external" href="reference/datamodel.html#object.__enter__"><tt class="xref docutils literal"><span class="pre">__enter__()</span></tt></a> and <a title="object.__exit__" class="reference external" href="reference/datamodel.html#object.__exit__"><tt class="xref docutils literal"><span class="pre">__exit__()</span></tt></a> methods.
+See <span class="target" id="index-175"></span><a class="reference external" href="http://www.python.org/dev/peps/pep-0343"><strong>PEP 343</strong></a>.</dd>
+<dt id="term-cpython">CPython</dt>
+<dd>The canonical implementation of the Python programming language. The
+term &#8220;CPython&#8221; is used in contexts when necessary to distinguish this
+implementation from others such as Jython or IronPython.</dd>
+<dt id="term-decorator">decorator</dt>
+<dd><p class="first">A function returning another function, usually applied as a function
+transformation using the <tt class="docutils literal"><span class="pre">&#64;wrapper</span></tt> syntax. Common examples for
+decorators are <a title="classmethod" class="reference external" href="library/functions.html#classmethod"><tt class="xref docutils literal"><span class="pre">classmethod()</span></tt></a> and <a title="staticmethod" class="reference external" href="library/functions.html#staticmethod"><tt class="xref docutils literal"><span class="pre">staticmethod()</span></tt></a>.</p>
+<p>The decorator syntax is merely syntactic sugar, the following two
+function definitions are semantically equivalent:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">f</span><span class="p">(</span><span class="o">...</span><span class="p">):</span>
+ <span class="o">...</span>
+<span class="n">f</span> <span class="o">=</span> <span class="nb">staticmethod</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
+
+<span class="nd">@staticmethod</span>
+<span class="k">def</span> <span class="nf">f</span><span class="p">(</span><span class="o">...</span><span class="p">):</span>
+ <span class="o">...</span>
+</pre></div>
+</div>
+<p class="last">See <a class="reference external" href="reference/compound_stmts.html#function"><em>the documentation for function definition</em></a> for more
+about decorators.</p>
+</dd>
+<dt id="term-descriptor">descriptor</dt>
+<dd><p class="first">Any <em>new-style</em> object which defines the methods <a title="object.__get__" class="reference external" href="reference/datamodel.html#object.__get__"><tt class="xref docutils literal"><span class="pre">__get__()</span></tt></a>,
+<a title="object.__set__" class="reference external" href="reference/datamodel.html#object.__set__"><tt class="xref docutils literal"><span class="pre">__set__()</span></tt></a>, or <a title="object.__delete__" class="reference external" href="reference/datamodel.html#object.__delete__"><tt class="xref docutils literal"><span class="pre">__delete__()</span></tt></a>. When a class attribute is a
+descriptor, its special binding behavior is triggered upon attribute
+lookup. Normally, using <em>a.b</em> to get, set or delete an attribute looks up
+the object named <em>b</em> in the class dictionary for <em>a</em>, but if <em>b</em> is a
+descriptor, the respective descriptor method gets called. Understanding
+descriptors is a key to a deep understanding of Python because they are
+the basis for many features including functions, methods, properties,
+class methods, static methods, and reference to super classes.</p>
+<p class="last">For more information about descriptors&#8217; methods, see <a class="reference external" href="reference/datamodel.html#descriptors"><em>Implementing Descriptors</em></a>.</p>
+</dd>
+<dt id="term-dictionary">dictionary</dt>
+<dd>An associative array, where arbitrary keys are mapped to values. The use
+of <a title="dict" class="reference external" href="library/stdtypes.html#dict"><tt class="xref docutils literal"><span class="pre">dict</span></tt></a> closely resembles that for <a title="list" class="reference external" href="library/functions.html#list"><tt class="xref docutils literal"><span class="pre">list</span></tt></a>, but the keys can
+be any object with a <a title="object.__hash__" class="reference external" href="reference/datamodel.html#object.__hash__"><tt class="xref docutils literal"><span class="pre">__hash__()</span></tt></a> function, not just integers.
+Called a hash in Perl.</dd>
+<dt id="term-docstring">docstring</dt>
+<dd>A string literal which appears as the first expression in a class,
+function or module. While ignored when the suite is executed, it is
+recognized by the compiler and put into the <tt class="xref docutils literal"><span class="pre">__doc__</span></tt> attribute
+of the enclosing class, function or module. Since it is available via
+introspection, it is the canonical place for documentation of the
+object.</dd>
+<dt id="term-duck-typing">duck-typing</dt>
+<dd>A pythonic programming style which determines an object&#8217;s type by inspection
+of its method or attribute signature rather than by explicit relationship
+to some type object (&#8220;If it looks like a duck and quacks like a duck, it
+must be a duck.&#8221;) By emphasizing interfaces rather than specific types,
+well-designed code improves its flexibility by allowing polymorphic
+substitution. Duck-typing avoids tests using <a title="type" class="reference external" href="library/functions.html#type"><tt class="xref docutils literal"><span class="pre">type()</span></tt></a> or
+<a title="isinstance" class="reference external" href="library/functions.html#isinstance"><tt class="xref docutils literal"><span class="pre">isinstance()</span></tt></a>. (Note, however, that duck-typing can be complemented
+with abstract base classes.) Instead, it typically employs <a title="hasattr" class="reference external" href="library/functions.html#hasattr"><tt class="xref docutils literal"><span class="pre">hasattr()</span></tt></a>
+tests or <a class="reference internal" href="#term-eafp"><em class="xref">EAFP</em></a> programming.</dd>
+<dt id="term-eafp">EAFP</dt>
+<dd>Easier to ask for forgiveness than permission. This common Python coding
+style assumes the existence of valid keys or attributes and catches
+exceptions if the assumption proves false. This clean and fast style is
+characterized by the presence of many <a class="reference external" href="reference/compound_stmts.html#try"><tt class="xref docutils literal"><span class="pre">try</span></tt></a> and <a class="reference external" href="reference/compound_stmts.html#except"><tt class="xref docutils literal"><span class="pre">except</span></tt></a>
+statements. The technique contrasts with the <a class="reference internal" href="#term-lbyl"><em class="xref">LBYL</em></a> style
+common to many other languages such as C.</dd>
+<dt id="term-expression">expression</dt>
+<dd>A piece of syntax which can be evaluated to some value. In other words,
+an expression is an accumulation of expression elements like literals, names,
+attribute access, operators or function calls which all return a value.
+In contrast to many other languages, not all language constructs are expressions.
+There are also <a class="reference internal" href="#term-statement"><em class="xref">statement</em></a>s which cannot be used as expressions,
+such as <a class="reference external" href="reference/simple_stmts.html#print"><tt class="xref docutils literal"><span class="pre">print</span></tt></a> or <a class="reference external" href="reference/compound_stmts.html#if"><tt class="xref docutils literal"><span class="pre">if</span></tt></a>. Assignments are also statements,
+not expressions.</dd>
+<dt id="term-extension-module">extension module</dt>
+<dd>A module written in C or C++, using Python&#8217;s C API to interact with the core and
+with user code.</dd>
+<dt id="term-finder">finder</dt>
+<dd>An object that tries to find the <a class="reference internal" href="#term-loader"><em class="xref">loader</em></a> for a module. It must
+implement a method named <tt class="xref docutils literal"><span class="pre">find_module()</span></tt>. See <span class="target" id="index-176"></span><a class="reference external" href="http://www.python.org/dev/peps/pep-0302"><strong>PEP 302</strong></a> for
+details.</dd>
+<dt id="term-function">function</dt>
+<dd>A series of statements which returns some value to a caller. It can also
+be passed zero or more arguments which may be used in the execution of
+the body. See also <a class="reference internal" href="#term-argument"><em class="xref">argument</em></a> and <a class="reference internal" href="#term-method"><em class="xref">method</em></a>.</dd>
+<dt id="term-future">__future__</dt>
+<dd><p class="first">A pseudo module which programmers can use to enable new language features
+which are not compatible with the current interpreter. For example, the
+expression <tt class="docutils literal"><span class="pre">11/4</span></tt> currently evaluates to <tt class="docutils literal"><span class="pre">2</span></tt>. If the module in which
+it is executed had enabled <em>true division</em> by executing:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">__future__</span> <span class="kn">import</span> <span class="n">division</span>
+</pre></div>
+</div>
+<p>the expression <tt class="docutils literal"><span class="pre">11/4</span></tt> would evaluate to <tt class="docutils literal"><span class="pre">2.75</span></tt>. By importing the
+<a title="Future statement definitions" class="reference external" href="library/__future__.html#module-__future__"><tt class="xref docutils literal"><span class="pre">__future__</span></tt></a> module and evaluating its variables, you can see when a
+new feature was first added to the language and when it will become the
+default:</p>
+<div class="last highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">__future__</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">__future__</span><span class="o">.</span><span class="n">division</span>
+<span class="go">_Feature((2, 2, 0, &#39;alpha&#39;, 2), (3, 0, 0, &#39;alpha&#39;, 0), 8192)</span>
+</pre></div>
+</div>
+</dd>
+<dt id="term-garbage-collection">garbage collection</dt>
+<dd>The process of freeing memory when it is not used anymore. Python
+performs garbage collection via reference counting and a cyclic garbage
+collector that is able to detect and break reference cycles.</dd>
+<dt id="term-generator">generator</dt>
+<dd>A function which returns an iterator. It looks like a normal function
+except that values are returned to the caller using a <a class="reference external" href="reference/simple_stmts.html#yield"><tt class="xref docutils literal"><span class="pre">yield</span></tt></a>
+statement instead of a <a class="reference external" href="reference/simple_stmts.html#return"><tt class="xref docutils literal"><span class="pre">return</span></tt></a> statement. Generator functions
+often contain one or more <a class="reference external" href="reference/compound_stmts.html#for"><tt class="xref docutils literal"><span class="pre">for</span></tt></a> or <a class="reference external" href="reference/compound_stmts.html#while"><tt class="xref docutils literal"><span class="pre">while</span></tt></a> loops which
+<a class="reference external" href="reference/simple_stmts.html#yield"><tt class="xref docutils literal"><span class="pre">yield</span></tt></a> elements back to the caller. The function execution is
+stopped at the <a class="reference external" href="reference/simple_stmts.html#yield"><tt class="xref docutils literal"><span class="pre">yield</span></tt></a> keyword (returning the result) and is
+resumed there when the next element is requested by calling the
+<a title="next" class="reference external" href="library/functions.html#next"><tt class="xref docutils literal"><span class="pre">next()</span></tt></a> method of the returned iterator.</dd>
+<dt id="term-generator-expression">generator expression</dt>
+<dd><p class="first">An expression that returns a generator. It looks like a normal expression
+followed by a <a class="reference external" href="reference/compound_stmts.html#for"><tt class="xref docutils literal"><span class="pre">for</span></tt></a> expression defining a loop variable, range,
+and an optional <a class="reference external" href="reference/compound_stmts.html#if"><tt class="xref docutils literal"><span class="pre">if</span></tt></a> expression. The combined expression
+generates values for an enclosing function:</p>
+<div class="last highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="nb">sum</span><span class="p">(</span><span class="n">i</span><span class="o">*</span><span class="n">i</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mf">10</span><span class="p">))</span> <span class="c"># sum of squares 0, 1, 4, ... 81</span>
+<span class="go">285</span>
+</pre></div>
+</div>
+</dd>
+<dt id="term-gil">GIL</dt>
+<dd>See <a class="reference internal" href="#term-global-interpreter-lock"><em class="xref">global interpreter lock</em></a>.</dd>
+<dt id="term-global-interpreter-lock">global interpreter lock</dt>
+<dd>The lock used by Python threads to assure that only one thread
+executes in the <a class="reference internal" href="#term-cpython"><em class="xref">CPython</em></a> <a class="reference internal" href="#term-virtual-machine"><em class="xref">virtual machine</em></a> at a time.
+This simplifies the CPython implementation by assuring that no two
+processes can access the same memory at the same time. Locking the
+entire interpreter makes it easier for the interpreter to be
+multi-threaded, at the expense of much of the parallelism afforded by
+multi-processor machines. Efforts have been made in the past to
+create a &#8220;free-threaded&#8221; interpreter (one which locks shared data at a
+much finer granularity), but so far none have been successful because
+performance suffered in the common single-processor case.</dd>
+<dt id="term-hashable">hashable</dt>
+<dd><p class="first">An object is <em>hashable</em> if it has a hash value which never changes during
+its lifetime (it needs a <a title="object.__hash__" class="reference external" href="reference/datamodel.html#object.__hash__"><tt class="xref docutils literal"><span class="pre">__hash__()</span></tt></a> method), and can be compared to
+other objects (it needs an <a title="object.__eq__" class="reference external" href="reference/datamodel.html#object.__eq__"><tt class="xref docutils literal"><span class="pre">__eq__()</span></tt></a> or <a title="object.__cmp__" class="reference external" href="reference/datamodel.html#object.__cmp__"><tt class="xref docutils literal"><span class="pre">__cmp__()</span></tt></a> method).
+Hashable objects which compare equal must have the same hash value.</p>
+<p>Hashability makes an object usable as a dictionary key and a set member,
+because these data structures use the hash value internally.</p>
+<p class="last">All of Python&#8217;s immutable built-in objects are hashable, while no mutable
+containers (such as lists or dictionaries) are. Objects which are
+instances of user-defined classes are hashable by default; they all
+compare unequal, and their hash value is their <a title="id" class="reference external" href="library/functions.html#id"><tt class="xref docutils literal"><span class="pre">id()</span></tt></a>.</p>
+</dd>
+<dt id="term-idle">IDLE</dt>
+<dd>An Integrated Development Environment for Python. IDLE is a basic editor
+and interpreter environment which ships with the standard distribution of
+Python. Good for beginners, it also serves as clear example code for
+those wanting to implement a moderately sophisticated, multi-platform GUI
+application.</dd>
+<dt id="term-immutable">immutable</dt>
+<dd>An object with a fixed value. Immutable objects include numbers, strings and
+tuples. Such an object cannot be altered. A new object has to
+be created if a different value has to be stored. They play an important
+role in places where a constant hash value is needed, for example as a key
+in a dictionary.</dd>
+<dt id="term-integer-division">integer division</dt>
+<dd>Mathematical division discarding any remainder. For example, the
+expression <tt class="docutils literal"><span class="pre">11/4</span></tt> currently evaluates to <tt class="docutils literal"><span class="pre">2</span></tt> in contrast to the
+<tt class="docutils literal"><span class="pre">2.75</span></tt> returned by float division. Also called <em>floor division</em>.
+When dividing two integers the outcome will always be another integer
+(having the floor function applied to it). However, if one of the operands
+is another numeric type (such as a <a title="float" class="reference external" href="library/functions.html#float"><tt class="xref docutils literal"><span class="pre">float</span></tt></a>), the result will be
+coerced (see <a class="reference internal" href="#term-coercion"><em class="xref">coercion</em></a>) to a common type. For example, an integer
+divided by a float will result in a float value, possibly with a decimal
+fraction. Integer division can be forced by using the <tt class="docutils literal"><span class="pre">//</span></tt> operator
+instead of the <tt class="docutils literal"><span class="pre">/</span></tt> operator. See also <a class="reference internal" href="#term-future"><em class="xref">__future__</em></a>.</dd>
+<dt id="term-importer">importer</dt>
+<dd>An object that both finds and loads a module; both a
+<a class="reference internal" href="#term-finder"><em class="xref">finder</em></a> and <a class="reference internal" href="#term-loader"><em class="xref">loader</em></a> object.</dd>
+<dt id="term-interactive">interactive</dt>
+<dd>Python has an interactive interpreter which means you can enter
+statements and expressions at the interpreter prompt, immediately
+execute them and see their results. Just launch <tt class="docutils literal"><span class="pre">python</span></tt> with no
+arguments (possibly by selecting it from your computer&#8217;s main
+menu). It is a very powerful way to test out new ideas or inspect
+modules and packages (remember <tt class="docutils literal"><span class="pre">help(x)</span></tt>).</dd>
+<dt id="term-interpreted">interpreted</dt>
+<dd>Python is an interpreted language, as opposed to a compiled one,
+though the distinction can be blurry because of the presence of the
+bytecode compiler. This means that source files can be run directly
+without explicitly creating an executable which is then run.
+Interpreted languages typically have a shorter development/debug cycle
+than compiled ones, though their programs generally also run more
+slowly. See also <a class="reference internal" href="#term-interactive"><em class="xref">interactive</em></a>.</dd>
+<dt id="term-iterable">iterable</dt>
+<dd>A container object capable of returning its members one at a
+time. Examples of iterables include all sequence types (such as
+<a title="list" class="reference external" href="library/functions.html#list"><tt class="xref docutils literal"><span class="pre">list</span></tt></a>, <a title="str" class="reference external" href="library/functions.html#str"><tt class="xref docutils literal"><span class="pre">str</span></tt></a>, and <a title="tuple" class="reference external" href="library/functions.html#tuple"><tt class="xref docutils literal"><span class="pre">tuple</span></tt></a>) and some non-sequence
+types like <a title="dict" class="reference external" href="library/stdtypes.html#dict"><tt class="xref docutils literal"><span class="pre">dict</span></tt></a> and <a title="file" class="reference external" href="library/functions.html#file"><tt class="xref docutils literal"><span class="pre">file</span></tt></a> and objects of any classes you
+define with an <a title="object.__iter__" class="reference external" href="reference/datamodel.html#object.__iter__"><tt class="xref docutils literal"><span class="pre">__iter__()</span></tt></a> or <a title="object.__getitem__" class="reference external" href="reference/datamodel.html#object.__getitem__"><tt class="xref docutils literal"><span class="pre">__getitem__()</span></tt></a> method. Iterables
+can be used in a <a class="reference external" href="reference/compound_stmts.html#for"><tt class="xref docutils literal"><span class="pre">for</span></tt></a> loop and in many other places where a
+sequence is needed (<a title="zip" class="reference external" href="library/functions.html#zip"><tt class="xref docutils literal"><span class="pre">zip()</span></tt></a>, <a title="map" class="reference external" href="library/functions.html#map"><tt class="xref docutils literal"><span class="pre">map()</span></tt></a>, ...). When an iterable
+object is passed as an argument to the builtin function <a title="iter" class="reference external" href="library/functions.html#iter"><tt class="xref docutils literal"><span class="pre">iter()</span></tt></a>, it
+returns an iterator for the object. This iterator is good for one pass
+over the set of values. When using iterables, it is usually not necessary
+to call <a title="iter" class="reference external" href="library/functions.html#iter"><tt class="xref docutils literal"><span class="pre">iter()</span></tt></a> or deal with iterator objects yourself. The <tt class="docutils literal"><span class="pre">for</span></tt>
+statement does that automatically for you, creating a temporary unnamed
+variable to hold the iterator for the duration of the loop. See also
+<a class="reference internal" href="#term-iterator"><em class="xref">iterator</em></a>, <a class="reference internal" href="#term-sequence"><em class="xref">sequence</em></a>, and <a class="reference internal" href="#term-generator"><em class="xref">generator</em></a>.</dd>
+<dt id="term-iterator">iterator</dt>
+<dd><p class="first">An object representing a stream of data. Repeated calls to the iterator&#8217;s
+<a title="next" class="reference external" href="library/functions.html#next"><tt class="xref docutils literal"><span class="pre">next()</span></tt></a> method return successive items in the stream. When no more
+data are available a <a title="exceptions.StopIteration" class="reference external" href="library/exceptions.html#exceptions.StopIteration"><tt class="xref docutils literal"><span class="pre">StopIteration</span></tt></a> exception is raised instead. At
+this point, the iterator object is exhausted and any further calls to its
+<a title="next" class="reference external" href="library/functions.html#next"><tt class="xref docutils literal"><span class="pre">next()</span></tt></a> method just raise <a title="exceptions.StopIteration" class="reference external" href="library/exceptions.html#exceptions.StopIteration"><tt class="xref docutils literal"><span class="pre">StopIteration</span></tt></a> again. Iterators are
+required to have an <a title="object.__iter__" class="reference external" href="reference/datamodel.html#object.__iter__"><tt class="xref docutils literal"><span class="pre">__iter__()</span></tt></a> method that returns the iterator
+object itself so every iterator is also iterable and may be used in most
+places where other iterables are accepted. One notable exception is code
+which attempts multiple iteration passes. A container object (such as a
+<a title="list" class="reference external" href="library/functions.html#list"><tt class="xref docutils literal"><span class="pre">list</span></tt></a>) produces a fresh new iterator each time you pass it to the
+<a title="iter" class="reference external" href="library/functions.html#iter"><tt class="xref docutils literal"><span class="pre">iter()</span></tt></a> function or use it in a <a class="reference external" href="reference/compound_stmts.html#for"><tt class="xref docutils literal"><span class="pre">for</span></tt></a> loop. Attempting this
+with an iterator will just return the same exhausted iterator object used
+in the previous iteration pass, making it appear like an empty container.</p>
+<p class="last">More information can be found in <a class="reference external" href="library/stdtypes.html#typeiter"><em>Iterator Types</em></a>.</p>
+</dd>
+<dt id="term-keyword-argument">keyword argument</dt>
+<dd>Arguments which are preceded with a <tt class="docutils literal"><span class="pre">variable_name=</span></tt> in the call.
+The variable name designates the local name in the function to which the
+value is assigned. <tt class="docutils literal"><span class="pre">**</span></tt> is used to accept or pass a dictionary of
+keyword arguments. See <a class="reference internal" href="#term-argument"><em class="xref">argument</em></a>.</dd>
+<dt id="term-lambda">lambda</dt>
+<dd>An anonymous inline function consisting of a single <a class="reference internal" href="#term-expression"><em class="xref">expression</em></a>
+which is evaluated when the function is called. The syntax to create
+a lambda function is <tt class="docutils literal"><span class="pre">lambda</span> <span class="pre">[arguments]:</span> <span class="pre">expression</span></tt></dd>
+<dt id="term-lbyl">LBYL</dt>
+<dd>Look before you leap. This coding style explicitly tests for
+pre-conditions before making calls or lookups. This style contrasts with
+the <a class="reference internal" href="#term-eafp"><em class="xref">EAFP</em></a> approach and is characterized by the presence of many
+<a class="reference external" href="reference/compound_stmts.html#if"><tt class="xref docutils literal"><span class="pre">if</span></tt></a> statements.</dd>
+<dt id="term-list">list</dt>
+<dd>A built-in Python <a class="reference internal" href="#term-sequence"><em class="xref">sequence</em></a>. Despite its name it is more akin
+to an array in other languages than to a linked list since access to
+elements are O(1).</dd>
+<dt id="term-list-comprehension">list comprehension</dt>
+<dd>A compact way to process all or part of the elements in a sequence and
+return a list with the results. <tt class="docutils literal"><span class="pre">result</span> <span class="pre">=</span> <span class="pre">[&quot;0x%02x&quot;</span> <span class="pre">%</span> <span class="pre">x</span> <span class="pre">for</span> <span class="pre">x</span> <span class="pre">in</span>
+<span class="pre">range(256)</span> <span class="pre">if</span> <span class="pre">x</span> <span class="pre">%</span> <span class="pre">2</span> <span class="pre">==</span> <span class="pre">0]</span></tt> generates a list of strings containing
+even hex numbers (0x..) in the range from 0 to 255. The <a class="reference external" href="reference/compound_stmts.html#if"><tt class="xref docutils literal"><span class="pre">if</span></tt></a>
+clause is optional. If omitted, all elements in <tt class="docutils literal"><span class="pre">range(256)</span></tt> are
+processed.</dd>
+<dt id="term-loader">loader</dt>
+<dd>An object that loads a module. It must define a method named
+<tt class="xref docutils literal"><span class="pre">load_module()</span></tt>. A loader is typically returned by a
+<a class="reference internal" href="#term-finder"><em class="xref">finder</em></a>. See <span class="target" id="index-178"></span><a class="reference external" href="http://www.python.org/dev/peps/pep-0302"><strong>PEP 302</strong></a> for details.</dd>
+<dt id="term-mapping">mapping</dt>
+<dd>A container object (such as <a title="dict" class="reference external" href="library/stdtypes.html#dict"><tt class="xref docutils literal"><span class="pre">dict</span></tt></a>) which supports arbitrary key
+lookups using the special method <a title="object.__getitem__" class="reference external" href="reference/datamodel.html#object.__getitem__"><tt class="xref docutils literal"><span class="pre">__getitem__()</span></tt></a>.</dd>
+<dt id="term-metaclass">metaclass</dt>
+<dd><p class="first">The class of a class. Class definitions create a class name, a class
+dictionary, and a list of base classes. The metaclass is responsible for
+taking those three arguments and creating the class. Most object oriented
+programming languages provide a default implementation. What makes Python
+special is that it is possible to create custom metaclasses. Most users
+never need this tool, but when the need arises, metaclasses can provide
+powerful, elegant solutions. They have been used for logging attribute
+access, adding thread-safety, tracking object creation, implementing
+singletons, and many other tasks.</p>
+<p class="last">More information can be found in <a class="reference external" href="reference/datamodel.html#metaclasses"><em>Customizing class creation</em></a>.</p>
+</dd>
+<dt id="term-method">method</dt>
+<dd>A function which is defined inside a class body. If called as an attribute
+of an instance of that class, the method will get the instance object as
+its first <a class="reference internal" href="#term-argument"><em class="xref">argument</em></a> (which is usually called <tt class="docutils literal"><span class="pre">self</span></tt>).
+See <a class="reference internal" href="#term-function"><em class="xref">function</em></a> and <a class="reference internal" href="#term-nested-scope"><em class="xref">nested scope</em></a>.</dd>
+<dt id="term-mutable">mutable</dt>
+<dd>Mutable objects can change their value but keep their <a title="id" class="reference external" href="library/functions.html#id"><tt class="xref docutils literal"><span class="pre">id()</span></tt></a>. See
+also <a class="reference internal" href="#term-immutable"><em class="xref">immutable</em></a>.</dd>
+<dt id="term-named-tuple">named tuple</dt>
+<dd><p class="first">Any tuple-like class whose indexable elements are also accessible using
+named attributes (for example, <a title="time.localtime" class="reference external" href="library/time.html#time.localtime"><tt class="xref docutils literal"><span class="pre">time.localtime()</span></tt></a> returns a
+tuple-like object where the <em>year</em> is accessible either with an
+index such as <tt class="docutils literal"><span class="pre">t[0]</span></tt> or with a named attribute like <tt class="docutils literal"><span class="pre">t.tm_year</span></tt>).</p>
+<p class="last">A named tuple can be a built-in type such as <a title="time.struct_time" class="reference external" href="library/time.html#time.struct_time"><tt class="xref docutils literal"><span class="pre">time.struct_time</span></tt></a>,
+or it can be created with a regular class definition. A full featured
+named tuple can also be created with the factory function
+<a title="collections.namedtuple" class="reference external" href="library/collections.html#collections.namedtuple"><tt class="xref docutils literal"><span class="pre">collections.namedtuple()</span></tt></a>. The latter approach automatically
+provides extra features such as a self-documenting representation like
+<tt class="docutils literal"><span class="pre">Employee(name='jones',</span> <span class="pre">title='programmer')</span></tt>.</p>
+</dd>
+<dt id="term-namespace">namespace</dt>
+<dd>The place where a variable is stored. Namespaces are implemented as
+dictionaries. There are the local, global and builtin namespaces as well
+as nested namespaces in objects (in methods). Namespaces support
+modularity by preventing naming conflicts. For instance, the functions
+<tt class="xref docutils literal"><span class="pre">__builtin__.open()</span></tt> and <a title="os.open" class="reference external" href="library/os.html#os.open"><tt class="xref docutils literal"><span class="pre">os.open()</span></tt></a> are distinguished by their
+namespaces. Namespaces also aid readability and maintainability by making
+it clear which module implements a function. For instance, writing
+<a title="random.seed" class="reference external" href="library/random.html#random.seed"><tt class="xref docutils literal"><span class="pre">random.seed()</span></tt></a> or <a title="itertools.izip" class="reference external" href="library/itertools.html#itertools.izip"><tt class="xref docutils literal"><span class="pre">itertools.izip()</span></tt></a> makes it clear that those
+functions are implemented by the <a title="Generate pseudo-random numbers with various common distributions." class="reference external" href="library/random.html#module-random"><tt class="xref docutils literal"><span class="pre">random</span></tt></a> and <a title="Functions creating iterators for efficient looping." class="reference external" href="library/itertools.html#module-itertools"><tt class="xref docutils literal"><span class="pre">itertools</span></tt></a>
+modules, respectively.</dd>
+<dt id="term-nested-scope">nested scope</dt>
+<dd>The ability to refer to a variable in an enclosing definition. For
+instance, a function defined inside another function can refer to
+variables in the outer function. Note that nested scopes work only for
+reference and not for assignment which will always write to the innermost
+scope. In contrast, local variables both read and write in the innermost
+scope. Likewise, global variables read and write to the global namespace.</dd>
+<dt id="term-new-style-class">new-style class</dt>
+<dd><p class="first">Any class which inherits from <a title="object" class="reference external" href="library/functions.html#object"><tt class="xref docutils literal"><span class="pre">object</span></tt></a>. This includes all built-in
+types like <a title="list" class="reference external" href="library/functions.html#list"><tt class="xref docutils literal"><span class="pre">list</span></tt></a> and <a title="dict" class="reference external" href="library/stdtypes.html#dict"><tt class="xref docutils literal"><span class="pre">dict</span></tt></a>. Only new-style classes can
+use Python&#8217;s newer, versatile features like <a title="__slots__" class="reference external" href="reference/datamodel.html#__slots__"><tt class="xref docutils literal"><span class="pre">__slots__</span></tt></a>,
+descriptors, properties, and <a title="object.__getattribute__" class="reference external" href="reference/datamodel.html#object.__getattribute__"><tt class="xref docutils literal"><span class="pre">__getattribute__()</span></tt></a>.</p>
+<p class="last">More information can be found in <a class="reference external" href="reference/datamodel.html#newstyle"><em>New-style and classic classes</em></a>.</p>
+</dd>
+<dt id="term-object">object</dt>
+<dd>Any data with state (attributes or value) and defined behavior
+(methods). Also the ultimate base class of any <a class="reference internal" href="#term-new-style-class"><em class="xref">new-style
+class</em></a>.</dd>
+<dt id="term-positional-argument">positional argument</dt>
+<dd>The arguments assigned to local names inside a function or method,
+determined by the order in which they were given in the call. <tt class="docutils literal"><span class="pre">*</span></tt> is
+used to either accept multiple positional arguments (when in the
+definition), or pass several arguments as a list to a function. See
+<a class="reference internal" href="#term-argument"><em class="xref">argument</em></a>.</dd>
+<dt id="term-python-3000">Python 3000</dt>
+<dd>Nickname for the next major Python version, 3.0 (coined long ago
+when the release of version 3 was something in the distant future.) This
+is also abbreviated &#8220;Py3k&#8221;.</dd>
+<dt id="term-pythonic">Pythonic</dt>
+<dd><p class="first">An idea or piece of code which closely follows the most common idioms
+of the Python language, rather than implementing code using concepts
+common to other languages. For example, a common idiom in Python is
+to loop over all elements of an iterable using a <a class="reference external" href="reference/compound_stmts.html#for"><tt class="xref docutils literal"><span class="pre">for</span></tt></a>
+statement. Many other languages don&#8217;t have this type of construct, so
+people unfamiliar with Python sometimes use a numerical counter instead:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">food</span><span class="p">)):</span>
+ <span class="k">print</span> <span class="n">food</span><span class="p">[</span><span class="n">i</span><span class="p">]</span>
+</pre></div>
+</div>
+<p>As opposed to the cleaner, Pythonic method:</p>
+<div class="last highlight-python"><div class="highlight"><pre><span class="k">for</span> <span class="n">piece</span> <span class="ow">in</span> <span class="n">food</span><span class="p">:</span>
+ <span class="k">print</span> <span class="n">piece</span>
+</pre></div>
+</div>
+</dd>
+<dt id="term-reference-count">reference count</dt>
+<dd>The number of references to an object. When the reference count of an
+object drops to zero, it is deallocated. Reference counting is
+generally not visible to Python code, but it is a key element of the
+<a class="reference internal" href="#term-cpython"><em class="xref">CPython</em></a> implementation. The <a title="Access system-specific parameters and functions." class="reference external" href="library/sys.html#module-sys"><tt class="xref docutils literal"><span class="pre">sys</span></tt></a> module defines a
+<tt class="xref docutils literal"><span class="pre">getrefcount()</span></tt> function that programmers can call to return the
+reference count for a particular object.</dd>
+<dt id="term-slots">__slots__</dt>
+<dd>A declaration inside a <a class="reference internal" href="#term-new-style-class"><em class="xref">new-style class</em></a> that saves memory by
+pre-declaring space for instance attributes and eliminating instance
+dictionaries. Though popular, the technique is somewhat tricky to get
+right and is best reserved for rare cases where there are large numbers of
+instances in a memory-critical application.</dd>
+<dt id="term-sequence">sequence</dt>
+<dd>An <a class="reference internal" href="#term-iterable"><em class="xref">iterable</em></a> which supports efficient element access using integer
+indices via the <a title="object.__getitem__" class="reference external" href="reference/datamodel.html#object.__getitem__"><tt class="xref docutils literal"><span class="pre">__getitem__()</span></tt></a> special method and defines a
+<a title="len" class="reference external" href="library/functions.html#len"><tt class="xref docutils literal"><span class="pre">len()</span></tt></a> method that returns the length of the sequence.
+Some built-in sequence types are <a title="list" class="reference external" href="library/functions.html#list"><tt class="xref docutils literal"><span class="pre">list</span></tt></a>, <a title="str" class="reference external" href="library/functions.html#str"><tt class="xref docutils literal"><span class="pre">str</span></tt></a>,
+<a title="tuple" class="reference external" href="library/functions.html#tuple"><tt class="xref docutils literal"><span class="pre">tuple</span></tt></a>, and <a title="unicode" class="reference external" href="library/functions.html#unicode"><tt class="xref docutils literal"><span class="pre">unicode</span></tt></a>. Note that <a title="dict" class="reference external" href="library/stdtypes.html#dict"><tt class="xref docutils literal"><span class="pre">dict</span></tt></a> also
+supports <a title="object.__getitem__" class="reference external" href="reference/datamodel.html#object.__getitem__"><tt class="xref docutils literal"><span class="pre">__getitem__()</span></tt></a> and <a title="object.__len__" class="reference external" href="reference/datamodel.html#object.__len__"><tt class="xref docutils literal"><span class="pre">__len__()</span></tt></a>, but is considered a
+mapping rather than a sequence because the lookups use arbitrary
+<a class="reference internal" href="#term-immutable"><em class="xref">immutable</em></a> keys rather than integers.</dd>
+<dt id="term-slice">slice</dt>
+<dd>An object usually containing a portion of a <a class="reference internal" href="#term-sequence"><em class="xref">sequence</em></a>. A slice is
+created using the subscript notation, <tt class="docutils literal"><span class="pre">[]</span></tt> with colons between numbers
+when several are given, such as in <tt class="docutils literal"><span class="pre">variable_name[1:3:5]</span></tt>. The bracket
+(subscript) notation uses <a title="slice" class="reference external" href="library/functions.html#slice"><tt class="xref docutils literal"><span class="pre">slice</span></tt></a> objects internally (or in older
+versions, <a title="object.__getslice__" class="reference external" href="reference/datamodel.html#object.__getslice__"><tt class="xref docutils literal"><span class="pre">__getslice__()</span></tt></a> and <a title="object.__setslice__" class="reference external" href="reference/datamodel.html#object.__setslice__"><tt class="xref docutils literal"><span class="pre">__setslice__()</span></tt></a>).</dd>
+<dt id="term-special-method">special method</dt>
+<dd>A method that is called implicitly by Python to execute a certain
+operation on a type, such as addition. Such methods have names starting
+and ending with double underscores. Special methods are documented in
+<a class="reference external" href="reference/datamodel.html#specialnames"><em>Special method names</em></a>.</dd>
+<dt id="term-statement">statement</dt>
+<dd>A statement is part of a suite (a &#8220;block&#8221; of code). A statement is either
+an <a class="reference internal" href="#term-expression"><em class="xref">expression</em></a> or a one of several constructs with a keyword, such
+as <a class="reference external" href="reference/compound_stmts.html#if"><tt class="xref docutils literal"><span class="pre">if</span></tt></a>, <a class="reference external" href="reference/compound_stmts.html#while"><tt class="xref docutils literal"><span class="pre">while</span></tt></a> or <a class="reference external" href="reference/simple_stmts.html#print"><tt class="xref docutils literal"><span class="pre">print</span></tt></a>.</dd>
+<dt id="term-triple-quoted-string">triple-quoted string</dt>
+<dd>A string which is bound by three instances of either a quotation mark
+(&#8220;) or an apostrophe (&#8216;). While they don&#8217;t provide any functionality
+not available with single-quoted strings, they are useful for a number
+of reasons. They allow you to include unescaped single and double
+quotes within a string and they can span multiple lines without the
+use of the continuation character, making them especially useful when
+writing docstrings.</dd>
+<dt id="term-type">type</dt>
+<dd>The type of a Python object determines what kind of object it is; every
+object has a type. An object&#8217;s type is accessible as its
+<tt class="xref docutils literal"><span class="pre">__class__</span></tt> attribute or can be retrieved with <tt class="docutils literal"><span class="pre">type(obj)</span></tt>.</dd>
+<dt id="term-virtual-machine">virtual machine</dt>
+<dd>A computer defined entirely in software. Python&#8217;s virtual machine
+executes the <a class="reference internal" href="#term-bytecode"><em class="xref">bytecode</em></a> emitted by the bytecode compiler.</dd>
+<dt id="term-zen-of-python">Zen of Python</dt>
+<dd>Listing of Python design principles and philosophies that are helpful in
+understanding and using the language. The listing can be found by typing
+&#8220;<tt class="docutils literal"><span class="pre">import</span> <span class="pre">this</span></tt>&#8221; at the interactive prompt.</dd>
+</dl>
+</div>
+
+
+ </div>
+ </div>
+ </div>
+ <div class="sphinxsidebar">
+ <div class="sphinxsidebarwrapper">
+ <h4>Previous topic</h4>
+ <p class="topless"><a href="howto/webservers.html"
+ title="previous chapter">HOWTO Use Python in the web</a></p>
+ <h4>Next topic</h4>
+ <p class="topless"><a href="about.html"
+ title="next chapter">About these documents</a></p>
+ <h3>This Page</h3>
+ <ul class="this-page-menu">
+ <li><a href="_sources/glossary.txt"
+ rel="nofollow">Show Source</a></li>
+ </ul>
+ <div id="searchbox" style="display: none">
+ <h3>Quick search</h3>
+ <form class="search" action="search.html" method="get">
+ <input type="text" name="q" size="18" />
+ <input type="submit" value="Go" />
+ <input type="hidden" name="check_keywords" value="yes" />
+ <input type="hidden" name="area" value="default" />
+ </form>
+ <p class="searchtip" style="font-size: 90%">
+ Enter search terms or a module, class or function name.
+ </p>
+ </div>
+ <script type="text/javascript">$('#searchbox').show(0);</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="genindex.html" title="General Index"
+ >index</a></li>
+ <li class="right" >
+ <a href="modindex.html" title="Global Module Index"
+ >modules</a> |</li>
+ <li class="right" >
+ <a href="about.html" title="About these documents"
+ >next</a> |</li>
+ <li class="right" >
+ <a href="howto/webservers.html" title="HOWTO Use Python in the web"
+ >previous</a> |</li>
+ <li><img src="_static/py.png" alt=""
+ style="vertical-align: middle; margin-top: -1px"/></li>
+ <li><a href="index.html">Python v2.6.4c2 documentation</a> &raquo;</li>
+
+ </ul>
+ </div>
+ <div class="footer">
+ &copy; <a href="copyright.html">Copyright</a> 1990-2009, Python Software Foundation.
+ <br />
+ The Python Software Foundation is a non-profit corporation.
+ <a href="http://www.python.org/psf/donations/">Please donate.</a>
+ <br />
+ Last updated on Oct 19, 2009.
+ Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 0.6.2.
+ </div>
+
+ </body>
+</html> \ No newline at end of file
diff --git a/help/PythonTutorial/index.html b/help/PythonTutorial/index.html
new file mode 100644
index 0000000..aca95c2
--- /dev/null
+++ b/help/PythonTutorial/index.html
@@ -0,0 +1,189 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+ <title>Overview &mdash; Python v2.6.4c2 documentation</title>
+ <link rel="stylesheet" href="_static/default.css" type="text/css" />
+ <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+ <script type="text/javascript">
+ var DOCUMENTATION_OPTIONS = {
+ URL_ROOT: '',
+ VERSION: '2.6.4c2',
+ COLLAPSE_MODINDEX: false,
+ FILE_SUFFIX: '.html',
+ HAS_SOURCE: true
+ };
+ </script>
+ <script type="text/javascript" src="_static/jquery.js"></script>
+ <script type="text/javascript" src="_static/doctools.js"></script>
+ <link rel="search" type="application/opensearchdescription+xml"
+ title="Search within Python v2.6.4c2 documentation"
+ href="_static/opensearch.xml"/>
+ <link rel="author" title="About these documents" href="about.html" />
+ <link rel="copyright" title="Copyright" href="copyright.html" />
+ <link rel="top" title="Python v2.6.4c2 documentation" href="" />
+ <link rel="shortcut icon" type="image/png" href="_static/py.png" />
+
+
+ </head>
+ <body>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="modindex.html" title="Global Module Index"
+ accesskey="M">modules</a> |</li>
+ <li><img src="_static/py.png" alt=""
+ style="vertical-align: middle; margin-top: -1px"/></li>
+ <li><a href="">Python v2.6.4c2 documentation</a> &raquo;</li>
+
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body">
+
+ <h1>Python v2.6.4c2 documentation</h1>
+ <p>
+ Welcome! This is
+ the documentation for Python
+ 2.6.4c2, last updated Oct 19, 2009.
+ </p>
+
+ <p><strong>Parts of the documentation:</strong></p>
+ <table class="contentstable" align="center"><tr>
+ <td width="50%">
+ <p class="biglink"><a class="biglink" href="whatsnew/2.6.html">What's new in Python 2.6?</a><br/>
+ <span class="linkdescr">or <a href="whatsnew/index.html">all "What's new" documents</a> since 2.0</span></p>
+ <p class="biglink"><a class="biglink" href="tutorial/index.html">Tutorial</a><br/>
+ <span class="linkdescr">start here</span></p>
+ <p class="biglink"><a class="biglink" href="using/index.html">Using Python</a><br/>
+ <span class="linkdescr">how to use Python on different platforms</span></p>
+ <p class="biglink"><a class="biglink" href="library/index.html">Library Reference</a><br/>
+ <span class="linkdescr">keep this under your pillow</span></p>
+ <p class="biglink"><a class="biglink" href="reference/index.html">Language Reference</a><br/>
+ <span class="linkdescr">describes syntax and language elements</span></p>
+ <p class="biglink"><a class="biglink" href="howto/index.html">Python HOWTOs</a><br/>
+ <span class="linkdescr">in-depth documents on specific topics</span></p>
+ </td><td width="50%">
+ <p class="biglink"><a class="biglink" href="extending/index.html">Extending and Embedding</a><br/>
+ <span class="linkdescr">tutorial for C/C++ programmers</span></p>
+ <p class="biglink"><a class="biglink" href="c-api/index.html">Python/C API</a><br/>
+ <span class="linkdescr">reference for C/C++ programmers</span></p>
+ <p class="biglink"><a class="biglink" href="install/index.html">Installing Python Modules</a><br/>
+ <span class="linkdescr">information for installers &amp; sys-admins</span></p>
+ <p class="biglink"><a class="biglink" href="distutils/index.html">Distributing Python Modules</a><br/>
+ <span class="linkdescr">sharing modules with others</span></p>
+ <p class="biglink"><a class="biglink" href="documenting/index.html">Documenting Python</a><br/>
+ <span class="linkdescr">guide for documentation authors</span></p>
+ </td></tr>
+ </table>
+
+ <p><strong>Indices and tables:</strong></p>
+ <table class="contentstable" align="center"><tr>
+ <td width="50%">
+ <p class="biglink"><a class="biglink" href="modindex.html">Global Module Index</a><br/>
+ <span class="linkdescr">quick access to all modules</span></p>
+ <p class="biglink"><a class="biglink" href="genindex.html">General Index</a><br/>
+ <span class="linkdescr">all functions, classes, terms</span></p>
+ <p class="biglink"><a class="biglink" href="glossary.html">Glossary</a><br/>
+ <span class="linkdescr">the most important terms explained</span></p>
+ </td><td width="50%">
+ <p class="biglink"><a class="biglink" href="search.html">Search page</a><br/>
+ <span class="linkdescr">search this documentation</span></p>
+ <p class="biglink"><a class="biglink" href="contents.html">Complete Table of Contents</a><br/>
+ <span class="linkdescr">lists all sections and subsections</span></p>
+ </td></tr>
+ </table>
+
+ <p><strong>Meta information:</strong></p>
+ <table class="contentstable" align="center"><tr>
+ <td width="50%">
+ <p class="biglink"><a class="biglink" href="bugs.html">Reporting bugs</a></p>
+ <p class="biglink"><a class="biglink" href="about.html">About the documentation</a></p>
+ </td><td width="50%">
+ <p class="biglink"><a class="biglink" href="license.html">History and License of Python</a></p>
+ <p class="biglink"><a class="biglink" href="copyright.html">Copyright</a></p>
+ </td></tr>
+ </table>
+
+
+ </div>
+ </div>
+ </div>
+ <div class="sphinxsidebar">
+ <div class="sphinxsidebarwrapper">
+ <h3>Download</h3>
+ <p><a href="download.html">Download these documents</a></p>
+ <h3>Docs for other versions</h3>
+ <ul>
+ <li><a href="http://docs.python.org/2.7/">Python 2.7 (in development)</a></li>
+ <li><a href="http://docs.python.org/3.1/">Python 3.1 (stable)</a></li>
+ <li><a href="http://docs.python.org/dev/py3k/">Python 3.2 (in development)</a></li>
+ <li><a href="http://www.python.org/doc/versions/">Old versions</a></li>
+ </ul>
+
+ <h3>Other resources</h3>
+ <ul>
+
+ <li><a href="http://www.python.org/doc/faq/">FAQs</a></li>
+ <li><a href="http://www.python.org/doc/essays/">Guido's Essays</a></li>
+ <li><a href="http://www.python.org/doc/newstyle/">New-style Classes</a></li>
+ <li><a href="http://www.python.org/dev/peps/">PEP Index</a></li>
+ <li><a href="http://wiki.python.org/moin/BeginnersGuide">Beginner's Guide</a></li>
+ <li><a href="http://wiki.python.org/moin/PythonBooks">Book List</a></li>
+ <li><a href="http://www.python.org/doc/av/">Audio/Visual Talks</a></li>
+ <li><a href="http://www.python.org/doc/other/">Other Doc Collections</a></li>
+ </ul>
+ <div id="searchbox" style="display: none">
+ <h3>Quick search</h3>
+ <form class="search" action="search.html" method="get">
+ <input type="text" name="q" size="18" />
+ <input type="submit" value="Go" />
+ <input type="hidden" name="check_keywords" value="yes" />
+ <input type="hidden" name="area" value="default" />
+ </form>
+ <p class="searchtip" style="font-size: 90%">
+ Enter search terms or a module, class or function name.
+ </p>
+ </div>
+ <script type="text/javascript">$('#searchbox').show(0);</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="genindex.html" title="General Index"
+ >index</a></li>
+ <li class="right" >
+ <a href="modindex.html" title="Global Module Index"
+ >modules</a> |</li>
+ <li><img src="_static/py.png" alt=""
+ style="vertical-align: middle; margin-top: -1px"/></li>
+ <li><a href="">Python v2.6.4c2 documentation</a> &raquo;</li>
+
+ </ul>
+ </div>
+ <div class="footer">
+ &copy; <a href="copyright.html">Copyright</a> 1990-2009, Python Software Foundation.
+ <br />
+ The Python Software Foundation is a non-profit corporation.
+ <a href="http://www.python.org/psf/donations/">Please donate.</a>
+ <br />
+ Last updated on Oct 19, 2009.
+ Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 0.6.2.
+ </div>
+
+ </body>
+</html> \ No newline at end of file
diff --git a/help/PythonTutorial/library/library.info b/help/PythonTutorial/library/library.info
new file mode 100644
index 0000000..c62e346
--- /dev/null
+++ b/help/PythonTutorial/library/library.info
@@ -0,0 +1,9 @@
+[Library]
+name = PythonTutorial
+global_name = PythonTutorial
+long_name = PythonTutorial
+category = media
+library_version = 1
+host_version = 1
+l10n = false
+locale = en
diff --git a/help/PythonTutorial/modindex.html b/help/PythonTutorial/modindex.html
new file mode 100644
index 0000000..855bd5c
--- /dev/null
+++ b/help/PythonTutorial/modindex.html
@@ -0,0 +1,1905 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+ <title>Global Module Index &mdash; Python v2.6.4c2 documentation</title>
+ <link rel="stylesheet" href="_static/default.css" type="text/css" />
+ <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+ <script type="text/javascript">
+ var DOCUMENTATION_OPTIONS = {
+ URL_ROOT: '',
+ VERSION: '2.6.4c2',
+ COLLAPSE_MODINDEX: false,
+ FILE_SUFFIX: '.html',
+ HAS_SOURCE: true
+ };
+ </script>
+ <script type="text/javascript" src="_static/jquery.js"></script>
+ <script type="text/javascript" src="_static/doctools.js"></script>
+ <link rel="search" type="application/opensearchdescription+xml"
+ title="Search within Python v2.6.4c2 documentation"
+ href="_static/opensearch.xml"/>
+ <link rel="author" title="About these documents" href="about.html" />
+ <link rel="copyright" title="Copyright" href="copyright.html" />
+ <link rel="top" title="Python v2.6.4c2 documentation" href="index.html" />
+
+ <link rel="shortcut icon" type="image/png" href="_static/py.png" />
+
+
+
+ <script type="text/javascript">
+ DOCUMENTATION_OPTIONS.COLLAPSE_MODINDEX = true;
+ </script>
+
+
+ </head>
+ <body>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="" title="Global Module Index"
+ accesskey="M">modules</a> |</li>
+ <li><img src="_static/py.png" alt=""
+ style="vertical-align: middle; margin-top: -1px"/></li>
+ <li><a href="index.html">Python v2.6.4c2 documentation</a> &raquo;</li>
+
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body">
+
+
+ <h1 id="global-module-index">Global Module Index</h1>
+ <a href="#cap-A"><strong>A</strong></a> |
+ <a href="#cap-B"><strong>B</strong></a> |
+ <a href="#cap-C"><strong>C</strong></a> |
+ <a href="#cap-D"><strong>D</strong></a> |
+ <a href="#cap-E"><strong>E</strong></a> |
+ <a href="#cap-F"><strong>F</strong></a> |
+ <a href="#cap-G"><strong>G</strong></a> |
+ <a href="#cap-H"><strong>H</strong></a> |
+ <a href="#cap-I"><strong>I</strong></a> |
+ <a href="#cap-J"><strong>J</strong></a> |
+ <a href="#cap-K"><strong>K</strong></a> |
+ <a href="#cap-L"><strong>L</strong></a> |
+ <a href="#cap-M"><strong>M</strong></a> |
+ <a href="#cap-N"><strong>N</strong></a> |
+ <a href="#cap-O"><strong>O</strong></a> |
+ <a href="#cap-P"><strong>P</strong></a> |
+ <a href="#cap-Q"><strong>Q</strong></a> |
+ <a href="#cap-R"><strong>R</strong></a> |
+ <a href="#cap-S"><strong>S</strong></a> |
+ <a href="#cap-T"><strong>T</strong></a> |
+ <a href="#cap-U"><strong>U</strong></a> |
+ <a href="#cap-V"><strong>V</strong></a> |
+ <a href="#cap-W"><strong>W</strong></a> |
+ <a href="#cap-X"><strong>X</strong></a> |
+ <a href="#cap-Z"><strong>Z</strong></a>
+ <hr/>
+
+ <table width="100%" class="indextable" cellspacing="0" cellpadding="2"><tr>
+ <td></td>
+ <td>
+ <a href="library/__builtin__.html#module-__builtin__"><tt class="xref">__builtin__</tt></a></td><td>
+ <em>The module that provides the built-in namespace.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/__future__.html#module-__future__"><tt class="xref">__future__</tt></a></td><td>
+ <em>Future statement definitions</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/__main__.html#module-__main__"><tt class="xref">__main__</tt></a></td><td>
+ <em>The environment where the top-level script is run.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/_winreg.html#module-_winreg"><tt class="xref">_winreg</tt></a> <em>(Windows)</em></td><td>
+ <em>Routines and objects for manipulating the Windows registry.</em></td></tr><tr class="pcap"><td></td><td>&nbsp;</td><td></td></tr>
+ <tr class="cap"><td></td><td><a name="cap-A"><strong>A</strong></a></td><td></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/abc.html#module-abc"><tt class="xref">abc</tt></a></td><td>
+ <em>Abstract base classes according to PEP 3119.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/aepack.html#module-aepack"><tt class="xref">aepack</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Conversion between Python variables and AppleEvent data containers.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/aetools.html#module-aetools"><tt class="xref">aetools</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Basic support for sending Apple Events</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/aetypes.html#module-aetypes"><tt class="xref">aetypes</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Python representation of the Apple Event Object Model.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/aifc.html#module-aifc"><tt class="xref">aifc</tt></a></td><td>
+ <em>Read and write audio files in AIFF or AIFC format.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/al.html#module-al"><tt class="xref">al</tt></a> <em>(IRIX)</em></td><td><strong>Deprecated:</strong>
+ <em>Audio functions on the SGI.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/al.html#module-AL"><tt class="xref">AL</tt></a> <em>(IRIX)</em></td><td><strong>Deprecated:</strong>
+ <em>Constants used with the al module.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/anydbm.html#module-anydbm"><tt class="xref">anydbm</tt></a></td><td>
+ <em>Generic interface to DBM-style database modules.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/undoc.html#module-applesingle"><tt class="xref">applesingle</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Rudimentary decoder for AppleSingle format files.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/array.html#module-array"><tt class="xref">array</tt></a></td><td>
+ <em>Space efficient arrays of uniformly typed numeric values.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/ast.html#module-ast"><tt class="xref">ast</tt></a></td><td>
+ <em>Abstract Syntax Tree classes and manipulation.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/asynchat.html#module-asynchat"><tt class="xref">asynchat</tt></a></td><td>
+ <em>Support for asynchronous command/response protocols.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/asyncore.html#module-asyncore"><tt class="xref">asyncore</tt></a></td><td>
+ <em>A base class for developing asynchronous socket handling
+services.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/atexit.html#module-atexit"><tt class="xref">atexit</tt></a></td><td>
+ <em>Register and execute cleanup functions.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/audioop.html#module-audioop"><tt class="xref">audioop</tt></a></td><td>
+ <em>Manipulate raw audio data.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/autogil.html#module-autoGIL"><tt class="xref">autoGIL</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Global Interpreter Lock handling in event loops.</em></td></tr><tr class="pcap"><td></td><td>&nbsp;</td><td></td></tr>
+ <tr class="cap"><td></td><td><a name="cap-B"><strong>B</strong></a></td><td></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/base64.html#module-base64"><tt class="xref">base64</tt></a></td><td>
+ <em>RFC 3548: Base16, Base32, Base64 Data Encodings</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/basehttpserver.html#module-BaseHTTPServer"><tt class="xref">BaseHTTPServer</tt></a></td><td>
+ <em>Basic HTTP server (base class for SimpleHTTPServer and CGIHTTPServer).</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/bastion.html#module-Bastion"><tt class="xref">Bastion</tt></a></td><td><strong>Deprecated:</strong>
+ <em>Providing restricted access to objects.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/bdb.html#module-bdb"><tt class="xref">bdb</tt></a></td><td>
+ <em>Debugger framework.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/binascii.html#module-binascii"><tt class="xref">binascii</tt></a></td><td>
+ <em>Tools for converting between binary and various ASCII-encoded binary
+representations.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/binhex.html#module-binhex"><tt class="xref">binhex</tt></a></td><td>
+ <em>Encode and decode files in binhex4 format.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/bisect.html#module-bisect"><tt class="xref">bisect</tt></a></td><td>
+ <em>Array bisection algorithms for binary searching.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/bsddb.html#module-bsddb"><tt class="xref">bsddb</tt></a></td><td>
+ <em>Interface to Berkeley DB database library</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/undoc.html#module-buildtools"><tt class="xref">buildtools</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Helper module for BuildApplet, BuildApplication and macfreeze.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/bz2.html#module-bz2"><tt class="xref">bz2</tt></a></td><td>
+ <em>Interface to compression and decompression routines compatible with bzip2.</em></td></tr><tr class="pcap"><td></td><td>&nbsp;</td><td></td></tr>
+ <tr class="cap"><td></td><td><a name="cap-C"><strong>C</strong></a></td><td></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/calendar.html#module-calendar"><tt class="xref">calendar</tt></a></td><td>
+ <em>Functions for working with calendars, including some emulation of the Unix cal
+program.</em></td></tr><tr>
+ <td><img src="_static/minus.png" id="toggle-32"
+ class="toggler" style="display: none" alt="-" /></td>
+ <td>
+ <tt class="xref">Carbon</tt></td><td>
+ <em></em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.AE"><tt class="xref">Carbon.AE</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Interface to the Apple Events toolbox.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.AH"><tt class="xref">Carbon.AH</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Interface to the Apple Help manager.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.App"><tt class="xref">Carbon.App</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Interface to the Appearance Manager.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.Appearance"><tt class="xref">Carbon.Appearance</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Constant definitions for the interface to the Appearance Manager.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.CarbonEvents"><tt class="xref">Carbon.CarbonEvents</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Constants for the interface to the Carbon Event Manager.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.CarbonEvt"><tt class="xref">Carbon.CarbonEvt</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Interface to the Carbon Event Manager.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.CF"><tt class="xref">Carbon.CF</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Interface to the Core Foundation.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.CG"><tt class="xref">Carbon.CG</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Interface to Core Graphics.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.Cm"><tt class="xref">Carbon.Cm</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Interface to the Component Manager.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.Components"><tt class="xref">Carbon.Components</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Constants for the interface to the Component Manager.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.ControlAccessor"><tt class="xref">Carbon.ControlAccessor</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Accessor functions for the interface to the Control Manager.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.Controls"><tt class="xref">Carbon.Controls</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Constants for the interface to the Control Manager.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.CoreFounation"><tt class="xref">Carbon.CoreFounation</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Constants for the interface to CoreFoundation.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.CoreGraphics"><tt class="xref">Carbon.CoreGraphics</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Constants for the interface to CoreGraphics.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.Ctl"><tt class="xref">Carbon.Ctl</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Interface to the Control Manager.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.Dialogs"><tt class="xref">Carbon.Dialogs</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Constants for the interface to the Dialog Manager.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.Dlg"><tt class="xref">Carbon.Dlg</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Interface to the Dialog Manager.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.Drag"><tt class="xref">Carbon.Drag</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Interface to the Drag and Drop Manager.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.Dragconst"><tt class="xref">Carbon.Dragconst</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Constants for the interface to the Drag and Drop Manager.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.Events"><tt class="xref">Carbon.Events</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Constants for the interface to the classic Event Manager.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.Evt"><tt class="xref">Carbon.Evt</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Interface to the classic Event Manager.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.File"><tt class="xref">Carbon.File</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Interface to the File Manager.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.Files"><tt class="xref">Carbon.Files</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Constants for the interface to the File Manager.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.Fm"><tt class="xref">Carbon.Fm</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Interface to the Font Manager.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.Folder"><tt class="xref">Carbon.Folder</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Interface to the Folder Manager.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.Folders"><tt class="xref">Carbon.Folders</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Constants for the interface to the Folder Manager.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.Fonts"><tt class="xref">Carbon.Fonts</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Constants for the interface to the Font Manager.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.Help"><tt class="xref">Carbon.Help</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Interface to the Carbon Help Manager.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.IBCarbon"><tt class="xref">Carbon.IBCarbon</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Interface to the Carbon InterfaceBuilder support libraries.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.IBCarbonRuntime"><tt class="xref">Carbon.IBCarbonRuntime</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Constants for the interface to the Carbon InterfaceBuilder support libraries.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.Icns"><tt class="xref">Carbon.Icns</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Interface to the Carbon Icon Manager</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.Icons"><tt class="xref">Carbon.Icons</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Constants for the interface to the Carbon Icon Manager</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.Launch"><tt class="xref">Carbon.Launch</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Interface to the Carbon Launch Services.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.LaunchServices"><tt class="xref">Carbon.LaunchServices</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Constants for the interface to the Carbon Launch Services.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.List"><tt class="xref">Carbon.List</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Interface to the List Manager.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.Lists"><tt class="xref">Carbon.Lists</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Constants for the interface to the List Manager.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.MacHelp"><tt class="xref">Carbon.MacHelp</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Constants for the interface to the Carbon Help Manager.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.MediaDescr"><tt class="xref">Carbon.MediaDescr</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Parsers and generators for Quicktime Media descriptors</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.Menu"><tt class="xref">Carbon.Menu</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Interface to the Menu Manager.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.Menus"><tt class="xref">Carbon.Menus</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Constants for the interface to the Menu Manager.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.Mlte"><tt class="xref">Carbon.Mlte</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Interface to the MultiLingual Text Editor.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.OSA"><tt class="xref">Carbon.OSA</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Interface to the Carbon OSA Library.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.OSAconst"><tt class="xref">Carbon.OSAconst</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Constants for the interface to the Carbon OSA Library.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.Qd"><tt class="xref">Carbon.Qd</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Interface to the QuickDraw toolbox.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.Qdoffs"><tt class="xref">Carbon.Qdoffs</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Interface to the QuickDraw Offscreen APIs.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.QDOffscreen"><tt class="xref">Carbon.QDOffscreen</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Constants for the interface to the QuickDraw Offscreen APIs.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.Qt"><tt class="xref">Carbon.Qt</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Interface to the QuickTime toolbox.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.QuickDraw"><tt class="xref">Carbon.QuickDraw</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Constants for the interface to the QuickDraw toolbox.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.QuickTime"><tt class="xref">Carbon.QuickTime</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Constants for the interface to the QuickTime toolbox.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.Res"><tt class="xref">Carbon.Res</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Interface to the Resource Manager and Handles.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.Resources"><tt class="xref">Carbon.Resources</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Constants for the interface to the Resource Manager and Handles.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.Scrap"><tt class="xref">Carbon.Scrap</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>The Scrap Manager provides basic services for implementing cut &amp; paste and
+clipboard operations.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.Snd"><tt class="xref">Carbon.Snd</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Interface to the Sound Manager.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.Sound"><tt class="xref">Carbon.Sound</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Constants for the interface to the Sound Manager.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.TE"><tt class="xref">Carbon.TE</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Interface to TextEdit.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.TextEdit"><tt class="xref">Carbon.TextEdit</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Constants for the interface to TextEdit.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.Win"><tt class="xref">Carbon.Win</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Interface to the Window Manager.</em></td></tr><tr class="cg-32">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/carbon.html#module-Carbon.Windows"><tt class="xref">Carbon.Windows</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Constants for the interface to the Window Manager.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/cd.html#module-cd"><tt class="xref">cd</tt></a> <em>(IRIX)</em></td><td><strong>Deprecated:</strong>
+ <em>Interface to the CD-ROM on Silicon Graphics systems.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/undoc.html#module-cfmfile"><tt class="xref">cfmfile</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Code Fragment Resource module.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/cgi.html#module-cgi"><tt class="xref">cgi</tt></a></td><td>
+ <em>Helpers for running Python scripts via the Common Gateway Interface.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/cgihttpserver.html#module-CGIHTTPServer"><tt class="xref">CGIHTTPServer</tt></a></td><td>
+ <em>This module provides a request handler for HTTP servers which can run CGI
+scripts.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/cgitb.html#module-cgitb"><tt class="xref">cgitb</tt></a></td><td>
+ <em>Configurable traceback handler for CGI scripts.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/chunk.html#module-chunk"><tt class="xref">chunk</tt></a></td><td>
+ <em>Module to read IFF chunks.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/cmath.html#module-cmath"><tt class="xref">cmath</tt></a></td><td>
+ <em>Mathematical functions for complex numbers.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/cmd.html#module-cmd"><tt class="xref">cmd</tt></a></td><td>
+ <em>Build line-oriented command interpreters.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/code.html#module-code"><tt class="xref">code</tt></a></td><td>
+ <em>Facilities to implement read-eval-print loops.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/codecs.html#module-codecs"><tt class="xref">codecs</tt></a></td><td>
+ <em>Encode and decode data and streams.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/codeop.html#module-codeop"><tt class="xref">codeop</tt></a></td><td>
+ <em>Compile (possibly incomplete) Python code.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/collections.html#module-collections"><tt class="xref">collections</tt></a></td><td>
+ <em>High-performance datatypes</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/colorpicker.html#module-ColorPicker"><tt class="xref">ColorPicker</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Interface to the standard color selection dialog.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/colorsys.html#module-colorsys"><tt class="xref">colorsys</tt></a></td><td>
+ <em>Conversion functions between RGB and other color systems.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/commands.html#module-commands"><tt class="xref">commands</tt></a> <em>(Unix)</em></td><td>
+ <em>Utility functions for running external commands.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/compileall.html#module-compileall"><tt class="xref">compileall</tt></a></td><td>
+ <em>Tools for byte-compiling all Python source files in a directory tree.</em></td></tr><tr>
+ <td><img src="_static/minus.png" id="toggle-49"
+ class="toggler" style="display: none" alt="-" /></td>
+ <td>
+ <a href="library/compiler.html#module-compiler"><tt class="xref">compiler</tt></a></td><td><strong>Deprecated:</strong>
+ <em>Python code compiler written in Python.</em></td></tr><tr class="cg-49">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/compiler.html#module-compiler.ast"><tt class="xref">compiler.ast</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-49">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/compiler.html#module-compiler.visitor"><tt class="xref">compiler.visitor</tt></a></td><td>
+ <em></em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/configparser.html#module-ConfigParser"><tt class="xref">ConfigParser</tt></a></td><td>
+ <em>Configuration file parser.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/contextlib.html#module-contextlib"><tt class="xref">contextlib</tt></a></td><td>
+ <em>Utilities for with-statement contexts.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/cookie.html#module-Cookie"><tt class="xref">Cookie</tt></a></td><td>
+ <em>Support for HTTP state management (cookies).</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/cookielib.html#module-cookielib"><tt class="xref">cookielib</tt></a></td><td>
+ <em>Classes for automatic handling of HTTP cookies.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/copy.html#module-copy"><tt class="xref">copy</tt></a></td><td>
+ <em>Shallow and deep copy operations.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/copy_reg.html#module-copy_reg"><tt class="xref">copy_reg</tt></a></td><td>
+ <em>Register pickle support functions.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/pickle.html#module-cPickle"><tt class="xref">cPickle</tt></a></td><td>
+ <em>Faster version of pickle, but not subclassable.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/profile.html#module-cProfile"><tt class="xref">cProfile</tt></a></td><td>
+ <em>Python profiler</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/crypt.html#module-crypt"><tt class="xref">crypt</tt></a> <em>(Unix)</em></td><td>
+ <em>The crypt() function used to check Unix passwords.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/stringio.html#module-cStringIO"><tt class="xref">cStringIO</tt></a></td><td>
+ <em>Faster version of StringIO, but not subclassable.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/csv.html#module-csv"><tt class="xref">csv</tt></a></td><td>
+ <em>Write and read tabular data to and from delimited files.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/ctypes.html#module-ctypes"><tt class="xref">ctypes</tt></a></td><td>
+ <em>A foreign function library for Python.</em></td></tr><tr>
+ <td><img src="_static/minus.png" id="toggle-62"
+ class="toggler" style="display: none" alt="-" /></td>
+ <td>
+ <a href="library/curses.html#module-curses"><tt class="xref">curses</tt></a></td><td>
+ <em>An interface to the curses library, providing portable terminal handling.</em></td></tr><tr class="cg-62">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/curses.ascii.html#module-curses.ascii"><tt class="xref">curses.ascii</tt></a></td><td>
+ <em>Constants and set-membership functions for ASCII characters.</em></td></tr><tr class="cg-62">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/curses.panel.html#module-curses.panel"><tt class="xref">curses.panel</tt></a></td><td>
+ <em>A panel stack extension that adds depth to curses windows.</em></td></tr><tr class="cg-62">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/curses.html#module-curses.textpad"><tt class="xref">curses.textpad</tt></a></td><td>
+ <em>Emacs-like input editing in a curses window.</em></td></tr><tr class="cg-62">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/curses.html#module-curses.wrapper"><tt class="xref">curses.wrapper</tt></a></td><td>
+ <em>Terminal configuration wrapper for curses programs.</em></td></tr><tr class="pcap"><td></td><td>&nbsp;</td><td></td></tr>
+ <tr class="cap"><td></td><td><a name="cap-D"><strong>D</strong></a></td><td></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/datetime.html#module-datetime"><tt class="xref">datetime</tt></a></td><td>
+ <em>Basic date and time types.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/dbhash.html#module-dbhash"><tt class="xref">dbhash</tt></a></td><td>
+ <em>DBM-style interface to the BSD database library.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/dbm.html#module-dbm"><tt class="xref">dbm</tt></a> <em>(Unix)</em></td><td>
+ <em>The standard &#34;database&#34; interface, based on ndbm.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/decimal.html#module-decimal"><tt class="xref">decimal</tt></a></td><td>
+ <em>Implementation of the General Decimal Arithmetic Specification.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/gl.html#module-DEVICE"><tt class="xref">DEVICE</tt></a> <em>(IRIX)</em></td><td><strong>Deprecated:</strong>
+ <em>Constants used with the gl module.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/difflib.html#module-difflib"><tt class="xref">difflib</tt></a></td><td>
+ <em>Helpers for computing differences between objects.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/dircache.html#module-dircache"><tt class="xref">dircache</tt></a></td><td><strong>Deprecated:</strong>
+ <em>Return directory listing, with cache mechanism.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/dis.html#module-dis"><tt class="xref">dis</tt></a></td><td>
+ <em>Disassembler for Python bytecode.</em></td></tr><tr>
+ <td><img src="_static/minus.png" id="toggle-71"
+ class="toggler" style="display: none" alt="-" /></td>
+ <td>
+ <a href="library/distutils.html#module-distutils"><tt class="xref">distutils</tt></a></td><td>
+ <em>Support for building and installing Python modules into an existing Python
+installation.</em></td></tr><tr class="cg-71">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="distutils/apiref.html#module-distutils.archive_util"><tt class="xref">distutils.archive_util</tt></a></td><td>
+ <em>Utility functions for creating archive files (tarballs, zip files, ...)</em></td></tr><tr class="cg-71">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="distutils/apiref.html#module-distutils.bcppcompiler"><tt class="xref">distutils.bcppcompiler</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-71">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="distutils/apiref.html#module-distutils.ccompiler"><tt class="xref">distutils.ccompiler</tt></a></td><td>
+ <em>Abstract CCompiler class</em></td></tr><tr class="cg-71">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="distutils/apiref.html#module-distutils.cmd"><tt class="xref">distutils.cmd</tt></a></td><td>
+ <em>This module provides the abstract base class Command. This class is subclassed
+by the modules in the distutils.command subpackage.</em></td></tr><tr class="cg-71">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="distutils/apiref.html#module-distutils.command"><tt class="xref">distutils.command</tt></a></td><td>
+ <em>This subpackage contains one module for each standard Distutils command.</em></td></tr><tr class="cg-71">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="distutils/apiref.html#module-distutils.command.bdist"><tt class="xref">distutils.command.bdist</tt></a></td><td>
+ <em>Build a binary installer for a package</em></td></tr><tr class="cg-71">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="distutils/apiref.html#module-distutils.command.bdist_dumb"><tt class="xref">distutils.command.bdist_dumb</tt></a></td><td>
+ <em>Build a &#34;dumb&#34; installer - a simple archive of files</em></td></tr><tr class="cg-71">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="distutils/apiref.html#module-distutils.command.bdist_msi"><tt class="xref">distutils.command.bdist_msi</tt></a></td><td>
+ <em>Build a binary distribution as a Windows MSI file</em></td></tr><tr class="cg-71">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="distutils/apiref.html#module-distutils.command.bdist_packager"><tt class="xref">distutils.command.bdist_packager</tt></a></td><td>
+ <em>Abstract base class for packagers</em></td></tr><tr class="cg-71">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="distutils/apiref.html#module-distutils.command.bdist_rpm"><tt class="xref">distutils.command.bdist_rpm</tt></a></td><td>
+ <em>Build a binary distribution as a Redhat RPM and SRPM</em></td></tr><tr class="cg-71">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="distutils/apiref.html#module-distutils.command.bdist_wininst"><tt class="xref">distutils.command.bdist_wininst</tt></a></td><td>
+ <em>Build a Windows installer</em></td></tr><tr class="cg-71">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="distutils/apiref.html#module-distutils.command.build"><tt class="xref">distutils.command.build</tt></a></td><td>
+ <em>Build all files of a package</em></td></tr><tr class="cg-71">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="distutils/apiref.html#module-distutils.command.build_clib"><tt class="xref">distutils.command.build_clib</tt></a></td><td>
+ <em>Build any C libraries in a package</em></td></tr><tr class="cg-71">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="distutils/apiref.html#module-distutils.command.build_ext"><tt class="xref">distutils.command.build_ext</tt></a></td><td>
+ <em>Build any extensions in a package</em></td></tr><tr class="cg-71">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="distutils/apiref.html#module-distutils.command.build_py"><tt class="xref">distutils.command.build_py</tt></a></td><td>
+ <em>Build the .py/.pyc files of a package</em></td></tr><tr class="cg-71">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="distutils/apiref.html#module-distutils.command.build_scripts"><tt class="xref">distutils.command.build_scripts</tt></a></td><td>
+ <em>Build the scripts of a package</em></td></tr><tr class="cg-71">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="distutils/apiref.html#module-distutils.command.clean"><tt class="xref">distutils.command.clean</tt></a></td><td>
+ <em>Clean a package build area</em></td></tr><tr class="cg-71">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="distutils/apiref.html#module-distutils.command.config"><tt class="xref">distutils.command.config</tt></a></td><td>
+ <em>Perform package configuration</em></td></tr><tr class="cg-71">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="distutils/apiref.html#module-distutils.command.install"><tt class="xref">distutils.command.install</tt></a></td><td>
+ <em>Install a package</em></td></tr><tr class="cg-71">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="distutils/apiref.html#module-distutils.command.install_data"><tt class="xref">distutils.command.install_data</tt></a></td><td>
+ <em>Install data files from a package</em></td></tr><tr class="cg-71">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="distutils/apiref.html#module-distutils.command.install_headers"><tt class="xref">distutils.command.install_headers</tt></a></td><td>
+ <em>Install C/C++ header files from a package</em></td></tr><tr class="cg-71">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="distutils/apiref.html#module-distutils.command.install_lib"><tt class="xref">distutils.command.install_lib</tt></a></td><td>
+ <em>Install library files from a package</em></td></tr><tr class="cg-71">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="distutils/apiref.html#module-distutils.command.install_scripts"><tt class="xref">distutils.command.install_scripts</tt></a></td><td>
+ <em>Install script files from a package</em></td></tr><tr class="cg-71">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="distutils/apiref.html#module-distutils.command.register"><tt class="xref">distutils.command.register</tt></a></td><td>
+ <em>Register a module with the Python Package Index</em></td></tr><tr class="cg-71">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="distutils/apiref.html#module-distutils.command.sdist"><tt class="xref">distutils.command.sdist</tt></a></td><td>
+ <em>Build a source distribution</em></td></tr><tr class="cg-71">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="distutils/apiref.html#module-distutils.core"><tt class="xref">distutils.core</tt></a></td><td>
+ <em>The core Distutils functionality</em></td></tr><tr class="cg-71">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="distutils/apiref.html#module-distutils.cygwinccompiler"><tt class="xref">distutils.cygwinccompiler</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-71">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="distutils/apiref.html#module-distutils.debug"><tt class="xref">distutils.debug</tt></a></td><td>
+ <em>Provides the debug flag for distutils</em></td></tr><tr class="cg-71">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="distutils/apiref.html#module-distutils.dep_util"><tt class="xref">distutils.dep_util</tt></a></td><td>
+ <em>Utility functions for simple dependency checking</em></td></tr><tr class="cg-71">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="distutils/apiref.html#module-distutils.dir_util"><tt class="xref">distutils.dir_util</tt></a></td><td>
+ <em>Utility functions for operating on directories and directory trees</em></td></tr><tr class="cg-71">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="distutils/apiref.html#module-distutils.dist"><tt class="xref">distutils.dist</tt></a></td><td>
+ <em>Provides the Distribution class, which represents the module distribution being
+built/installed/distributed</em></td></tr><tr class="cg-71">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="distutils/apiref.html#module-distutils.emxccompiler"><tt class="xref">distutils.emxccompiler</tt></a></td><td>
+ <em>OS/2 EMX Compiler support</em></td></tr><tr class="cg-71">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="distutils/apiref.html#module-distutils.errors"><tt class="xref">distutils.errors</tt></a></td><td>
+ <em>Provides standard distutils exceptions</em></td></tr><tr class="cg-71">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="distutils/apiref.html#module-distutils.extension"><tt class="xref">distutils.extension</tt></a></td><td>
+ <em>Provides the Extension class, used to describe C/C++ extension modules in setup
+scripts</em></td></tr><tr class="cg-71">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="distutils/apiref.html#module-distutils.fancy_getopt"><tt class="xref">distutils.fancy_getopt</tt></a></td><td>
+ <em>Additional getopt functionality</em></td></tr><tr class="cg-71">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="distutils/apiref.html#module-distutils.file_util"><tt class="xref">distutils.file_util</tt></a></td><td>
+ <em>Utility functions for operating on single files</em></td></tr><tr class="cg-71">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="distutils/apiref.html#module-distutils.filelist"><tt class="xref">distutils.filelist</tt></a></td><td>
+ <em>The FileList class, used for poking about the file system and
+building lists of files.</em></td></tr><tr class="cg-71">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="distutils/apiref.html#module-distutils.log"><tt class="xref">distutils.log</tt></a></td><td>
+ <em>A simple logging mechanism, 282-style</em></td></tr><tr class="cg-71">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="distutils/apiref.html#module-distutils.msvccompiler"><tt class="xref">distutils.msvccompiler</tt></a></td><td>
+ <em>Microsoft Compiler</em></td></tr><tr class="cg-71">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="distutils/apiref.html#module-distutils.mwerkscompiler"><tt class="xref">distutils.mwerkscompiler</tt></a></td><td>
+ <em>Metrowerks CodeWarrior support</em></td></tr><tr class="cg-71">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="distutils/apiref.html#module-distutils.spawn"><tt class="xref">distutils.spawn</tt></a></td><td>
+ <em>Provides the spawn() function</em></td></tr><tr class="cg-71">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="distutils/apiref.html#module-distutils.sysconfig"><tt class="xref">distutils.sysconfig</tt></a></td><td>
+ <em>Low-level access to configuration information of the Python interpreter.</em></td></tr><tr class="cg-71">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="distutils/apiref.html#module-distutils.text_file"><tt class="xref">distutils.text_file</tt></a></td><td>
+ <em>provides the TextFile class, a simple interface to text files</em></td></tr><tr class="cg-71">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="distutils/apiref.html#module-distutils.unixccompiler"><tt class="xref">distutils.unixccompiler</tt></a></td><td>
+ <em>UNIX C Compiler</em></td></tr><tr class="cg-71">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="distutils/apiref.html#module-distutils.util"><tt class="xref">distutils.util</tt></a></td><td>
+ <em>Miscellaneous other utility functions</em></td></tr><tr class="cg-71">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="distutils/apiref.html#module-distutils.version"><tt class="xref">distutils.version</tt></a></td><td>
+ <em>implements classes that represent module version numbers.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/dl.html#module-dl"><tt class="xref">dl</tt></a> <em>(Unix)</em></td><td><strong>Deprecated:</strong>
+ <em>Call C functions in shared objects.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/doctest.html#module-doctest"><tt class="xref">doctest</tt></a></td><td>
+ <em>Test pieces of code within docstrings.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/docxmlrpcserver.html#module-DocXMLRPCServer"><tt class="xref">DocXMLRPCServer</tt></a></td><td>
+ <em>Self-documenting XML-RPC server implementation.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/dumbdbm.html#module-dumbdbm"><tt class="xref">dumbdbm</tt></a></td><td>
+ <em>Portable implementation of the simple DBM interface.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/dummy_thread.html#module-dummy_thread"><tt class="xref">dummy_thread</tt></a></td><td>
+ <em>Drop-in replacement for the thread module.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/dummy_threading.html#module-dummy_threading"><tt class="xref">dummy_threading</tt></a></td><td>
+ <em>Drop-in replacement for the threading module.</em></td></tr><tr class="pcap"><td></td><td>&nbsp;</td><td></td></tr>
+ <tr class="cap"><td></td><td><a name="cap-E"><strong>E</strong></a></td><td></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/easydialogs.html#module-EasyDialogs"><tt class="xref">EasyDialogs</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Basic Macintosh dialogs.</em></td></tr><tr>
+ <td><img src="_static/minus.png" id="toggle-79"
+ class="toggler" style="display: none" alt="-" /></td>
+ <td>
+ <a href="library/email.html#module-email"><tt class="xref">email</tt></a></td><td>
+ <em>Package supporting the parsing, manipulating, and generating email messages,
+including MIME documents.</em></td></tr><tr class="cg-79">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/email.charset.html#module-email.charset"><tt class="xref">email.charset</tt></a></td><td>
+ <em>Character Sets</em></td></tr><tr class="cg-79">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/email.encoders.html#module-email.encoders"><tt class="xref">email.encoders</tt></a></td><td>
+ <em>Encoders for email message payloads.</em></td></tr><tr class="cg-79">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/email.errors.html#module-email.errors"><tt class="xref">email.errors</tt></a></td><td>
+ <em>The exception classes used by the email package.</em></td></tr><tr class="cg-79">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/email.generator.html#module-email.generator"><tt class="xref">email.generator</tt></a></td><td>
+ <em>Generate flat text email messages from a message structure.</em></td></tr><tr class="cg-79">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/email.header.html#module-email.header"><tt class="xref">email.header</tt></a></td><td>
+ <em>Representing non-ASCII headers</em></td></tr><tr class="cg-79">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/email.iterators.html#module-email.iterators"><tt class="xref">email.iterators</tt></a></td><td>
+ <em>Iterate over a message object tree.</em></td></tr><tr class="cg-79">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/email.message.html#module-email.message"><tt class="xref">email.message</tt></a></td><td>
+ <em>The base class representing email messages.</em></td></tr><tr class="cg-79">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/email.mime.html#module-email.mime"><tt class="xref">email.mime</tt></a></td><td>
+ <em>Build MIME messages.</em></td></tr><tr class="cg-79">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/email.parser.html#module-email.parser"><tt class="xref">email.parser</tt></a></td><td>
+ <em>Parse flat text email messages to produce a message object structure.</em></td></tr><tr class="cg-79">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/email.util.html#module-email.utils"><tt class="xref">email.utils</tt></a></td><td>
+ <em>Miscellaneous email package utilities.</em></td></tr><tr>
+ <td><img src="_static/minus.png" id="toggle-80"
+ class="toggler" style="display: none" alt="-" /></td>
+ <td>
+ <tt class="xref">encodings</tt></td><td>
+ <em></em></td></tr><tr class="cg-80">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/codecs.html#module-encodings.idna"><tt class="xref">encodings.idna</tt></a></td><td>
+ <em>Internationalized Domain Names implementation</em></td></tr><tr class="cg-80">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/codecs.html#module-encodings.utf_8_sig"><tt class="xref">encodings.utf_8_sig</tt></a></td><td>
+ <em>UTF-8 codec with BOM signature</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/errno.html#module-errno"><tt class="xref">errno</tt></a></td><td>
+ <em>Standard errno system symbols.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/exceptions.html#module-exceptions"><tt class="xref">exceptions</tt></a></td><td>
+ <em>Standard exception classes.</em></td></tr><tr class="pcap"><td></td><td>&nbsp;</td><td></td></tr>
+ <tr class="cap"><td></td><td><a name="cap-F"><strong>F</strong></a></td><td></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/fcntl.html#module-fcntl"><tt class="xref">fcntl</tt></a> <em>(Unix)</em></td><td>
+ <em>The fcntl() and ioctl() system calls.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/filecmp.html#module-filecmp"><tt class="xref">filecmp</tt></a></td><td>
+ <em>Compare files efficiently.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/fileinput.html#module-fileinput"><tt class="xref">fileinput</tt></a></td><td>
+ <em>Loop over standard input or a list of files.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/macostools.html#module-findertools"><tt class="xref">findertools</tt></a> <em>(Mac)</em></td><td>
+ <em>Wrappers around the finder&#39;s Apple Events interface.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/fl.html#module-FL"><tt class="xref">FL</tt></a> <em>(IRIX)</em></td><td><strong>Deprecated:</strong>
+ <em>Constants used with the fl module.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/fl.html#module-fl"><tt class="xref">fl</tt></a> <em>(IRIX)</em></td><td><strong>Deprecated:</strong>
+ <em>FORMS library for applications with graphical user interfaces.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/fl.html#module-flp"><tt class="xref">flp</tt></a> <em>(IRIX)</em></td><td><strong>Deprecated:</strong>
+ <em>Functions for loading stored FORMS designs.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/fm.html#module-fm"><tt class="xref">fm</tt></a> <em>(IRIX)</em></td><td><strong>Deprecated:</strong>
+ <em>Font Manager interface for SGI workstations.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/fnmatch.html#module-fnmatch"><tt class="xref">fnmatch</tt></a></td><td>
+ <em>Unix shell style filename pattern matching.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/formatter.html#module-formatter"><tt class="xref">formatter</tt></a></td><td>
+ <em>Generic output formatter and device interface.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/fpectl.html#module-fpectl"><tt class="xref">fpectl</tt></a> <em>(Unix)</em></td><td>
+ <em>Provide control for floating point exception handling.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/fpformat.html#module-fpformat"><tt class="xref">fpformat</tt></a></td><td><strong>Deprecated:</strong>
+ <em>General floating point formatting functions.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/fractions.html#module-fractions"><tt class="xref">fractions</tt></a></td><td>
+ <em>Rational numbers.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/framework.html#module-FrameWork"><tt class="xref">FrameWork</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Interactive application framework.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/ftplib.html#module-ftplib"><tt class="xref">ftplib</tt></a></td><td>
+ <em>FTP protocol client (requires sockets).</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/functools.html#module-functools"><tt class="xref">functools</tt></a></td><td>
+ <em>Higher order functions and operations on callable objects.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/future_builtins.html#module-future_builtins"><tt class="xref">future_builtins</tt></a></td><td>
+ <em></em></td></tr><tr class="pcap"><td></td><td>&nbsp;</td><td></td></tr>
+ <tr class="cap"><td></td><td><a name="cap-G"><strong>G</strong></a></td><td></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/gc.html#module-gc"><tt class="xref">gc</tt></a></td><td>
+ <em>Interface to the cycle-detecting garbage collector.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/gdbm.html#module-gdbm"><tt class="xref">gdbm</tt></a> <em>(Unix)</em></td><td>
+ <em>GNU&#39;s reinterpretation of dbm.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/gensuitemodule.html#module-gensuitemodule"><tt class="xref">gensuitemodule</tt></a> <em>(Mac)</em></td><td>
+ <em>Create a stub package from an OSA dictionary</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/getopt.html#module-getopt"><tt class="xref">getopt</tt></a></td><td>
+ <em>Portable parser for command line options; support both short and long option
+names.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/getpass.html#module-getpass"><tt class="xref">getpass</tt></a></td><td>
+ <em>Portable reading of passwords and retrieval of the userid.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/gettext.html#module-gettext"><tt class="xref">gettext</tt></a></td><td>
+ <em>Multilingual internationalization services.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/gl.html#module-gl"><tt class="xref">gl</tt></a> <em>(IRIX)</em></td><td><strong>Deprecated:</strong>
+ <em>Functions from the Silicon Graphics Graphics Library.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/gl.html#module-GL"><tt class="xref">GL</tt></a> <em>(IRIX)</em></td><td><strong>Deprecated:</strong>
+ <em>Constants used with the gl module.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/glob.html#module-glob"><tt class="xref">glob</tt></a></td><td>
+ <em>Unix shell style pathname pattern expansion.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/grp.html#module-grp"><tt class="xref">grp</tt></a> <em>(Unix)</em></td><td>
+ <em>The group database (getgrnam() and friends).</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/gzip.html#module-gzip"><tt class="xref">gzip</tt></a></td><td>
+ <em>Interfaces for gzip compression and decompression using file objects.</em></td></tr><tr class="pcap"><td></td><td>&nbsp;</td><td></td></tr>
+ <tr class="cap"><td></td><td><a name="cap-H"><strong>H</strong></a></td><td></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/hashlib.html#module-hashlib"><tt class="xref">hashlib</tt></a></td><td>
+ <em>Secure hash and message digest algorithms.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/heapq.html#module-heapq"><tt class="xref">heapq</tt></a></td><td>
+ <em>Heap queue algorithm (a.k.a. priority queue).</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/hmac.html#module-hmac"><tt class="xref">hmac</tt></a></td><td>
+ <em>Keyed-Hashing for Message Authentication (HMAC) implementation for Python.</em></td></tr><tr>
+ <td><img src="_static/minus.png" id="toggle-114"
+ class="toggler" style="display: none" alt="-" /></td>
+ <td>
+ <a href="library/hotshot.html#module-hotshot"><tt class="xref">hotshot</tt></a></td><td>
+ <em>High performance logging profiler, mostly written in C.</em></td></tr><tr class="cg-114">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/hotshot.html#module-hotshot.stats"><tt class="xref">hotshot.stats</tt></a></td><td>
+ <em>Statistical analysis for Hotshot</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/htmllib.html#module-htmlentitydefs"><tt class="xref">htmlentitydefs</tt></a></td><td>
+ <em>Definitions of HTML general entities.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/htmllib.html#module-htmllib"><tt class="xref">htmllib</tt></a></td><td><strong>Deprecated:</strong>
+ <em>A parser for HTML documents.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/htmlparser.html#module-HTMLParser"><tt class="xref">HTMLParser</tt></a></td><td>
+ <em>A simple parser that can handle HTML and XHTML.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/httplib.html#module-httplib"><tt class="xref">httplib</tt></a></td><td>
+ <em>HTTP and HTTPS protocol client (requires sockets).</em></td></tr><tr class="pcap"><td></td><td>&nbsp;</td><td></td></tr>
+ <tr class="cap"><td></td><td><a name="cap-I"><strong>I</strong></a></td><td></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/ic.html#module-ic"><tt class="xref">ic</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Access to the Mac OS X Internet Config.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/undoc.html#module-icopen"><tt class="xref">icopen</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Internet Config replacement for open().</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/imageop.html#module-imageop"><tt class="xref">imageop</tt></a></td><td><strong>Deprecated:</strong>
+ <em>Manipulate raw image data.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/imaplib.html#module-imaplib"><tt class="xref">imaplib</tt></a></td><td>
+ <em>IMAP4 protocol client (requires sockets).</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/imgfile.html#module-imgfile"><tt class="xref">imgfile</tt></a> <em>(IRIX)</em></td><td><strong>Deprecated:</strong>
+ <em>Support for SGI imglib files.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/imghdr.html#module-imghdr"><tt class="xref">imghdr</tt></a></td><td>
+ <em>Determine the type of image contained in a file or byte stream.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/imp.html#module-imp"><tt class="xref">imp</tt></a></td><td>
+ <em>Access the implementation of the import statement.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/imputil.html#module-imputil"><tt class="xref">imputil</tt></a></td><td><strong>Deprecated:</strong>
+ <em>Manage and augment the import process.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/inspect.html#module-inspect"><tt class="xref">inspect</tt></a></td><td>
+ <em>Extract information and source code from live objects.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/io.html#module-io"><tt class="xref">io</tt></a></td><td>
+ <em>Core tools for working with streams.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/itertools.html#module-itertools"><tt class="xref">itertools</tt></a></td><td>
+ <em>Functions creating iterators for efficient looping.</em></td></tr><tr class="pcap"><td></td><td>&nbsp;</td><td></td></tr>
+ <tr class="cap"><td></td><td><a name="cap-J"><strong>J</strong></a></td><td></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/jpeg.html#module-jpeg"><tt class="xref">jpeg</tt></a> <em>(IRIX)</em></td><td><strong>Deprecated:</strong>
+ <em>Read and write image files in compressed JPEG format.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/json.html#module-json"><tt class="xref">json</tt></a></td><td>
+ <em>Encode and decode the JSON format.</em></td></tr><tr class="pcap"><td></td><td>&nbsp;</td><td></td></tr>
+ <tr class="cap"><td></td><td><a name="cap-K"><strong>K</strong></a></td><td></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/keyword.html#module-keyword"><tt class="xref">keyword</tt></a></td><td>
+ <em>Test whether a string is a keyword in Python.</em></td></tr><tr class="pcap"><td></td><td>&nbsp;</td><td></td></tr>
+ <tr class="cap"><td></td><td><a name="cap-L"><strong>L</strong></a></td><td></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/2to3.html#module-lib2to3"><tt class="xref">lib2to3</tt></a></td><td>
+ <em>the 2to3 library</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/linecache.html#module-linecache"><tt class="xref">linecache</tt></a></td><td>
+ <em>This module provides random access to individual lines from text files.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/locale.html#module-locale"><tt class="xref">locale</tt></a></td><td>
+ <em>Internationalization services.</em></td></tr><tr>
+ <td><img src="_static/minus.png" id="toggle-136"
+ class="toggler" style="display: none" alt="-" /></td>
+ <td>
+ <a href="library/logging.html#module-logging"><tt class="xref">logging</tt></a></td><td>
+ <em>Flexible error logging system for applications.</em></td></tr><tr class="cg-136">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/logging.html#module-logging.handlers"><tt class="xref">logging.handlers</tt></a></td><td>
+ <em></em></td></tr><tr class="pcap"><td></td><td>&nbsp;</td><td></td></tr>
+ <tr class="cap"><td></td><td><a name="cap-M"><strong>M</strong></a></td><td></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/undoc.html#module-macerrors"><tt class="xref">macerrors</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Constant definitions for many Mac OS error codes.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/macos.html#module-MacOS"><tt class="xref">MacOS</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Access to Mac OS-specific interpreter features.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/macostools.html#module-macostools"><tt class="xref">macostools</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Convenience routines for file manipulation.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/macpath.html#module-macpath"><tt class="xref">macpath</tt></a></td><td>
+ <em>Mac OS 9 path manipulation functions.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/undoc.html#module-macresource"><tt class="xref">macresource</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Locate script resources.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/mailbox.html#module-mailbox"><tt class="xref">mailbox</tt></a></td><td>
+ <em>Manipulate mailboxes in various formats</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/mailcap.html#module-mailcap"><tt class="xref">mailcap</tt></a></td><td>
+ <em>Mailcap file handling.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/marshal.html#module-marshal"><tt class="xref">marshal</tt></a></td><td>
+ <em>Convert Python objects to streams of bytes and back (with different
+constraints).</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/math.html#module-math"><tt class="xref">math</tt></a></td><td>
+ <em>Mathematical functions (sin() etc.).</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/md5.html#module-md5"><tt class="xref">md5</tt></a></td><td><strong>Deprecated:</strong>
+ <em>RSA&#39;s MD5 message digest algorithm.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/mhlib.html#module-mhlib"><tt class="xref">mhlib</tt></a></td><td><strong>Deprecated:</strong>
+ <em>Manipulate MH mailboxes from Python.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/mimetools.html#module-mimetools"><tt class="xref">mimetools</tt></a></td><td><strong>Deprecated:</strong>
+ <em>Tools for parsing MIME-style message bodies.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/mimetypes.html#module-mimetypes"><tt class="xref">mimetypes</tt></a></td><td>
+ <em>Mapping of filename extensions to MIME types.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/mimewriter.html#module-MimeWriter"><tt class="xref">MimeWriter</tt></a></td><td><strong>Deprecated:</strong>
+ <em>Write MIME format files.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/mimify.html#module-mimify"><tt class="xref">mimify</tt></a></td><td><strong>Deprecated:</strong>
+ <em>Mimification and unmimification of mail messages.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/miniaeframe.html#module-MiniAEFrame"><tt class="xref">MiniAEFrame</tt></a> <em>(Mac)</em></td><td>
+ <em>Support to act as an Open Scripting Architecture (OSA) server (&#34;Apple Events&#34;).</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/mmap.html#module-mmap"><tt class="xref">mmap</tt></a></td><td>
+ <em>Interface to memory-mapped files for Unix and Windows.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/modulefinder.html#module-modulefinder"><tt class="xref">modulefinder</tt></a></td><td>
+ <em>Find modules used by a script.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/msilib.html#module-msilib"><tt class="xref">msilib</tt></a> <em>(Windows)</em></td><td>
+ <em>Creation of Microsoft Installer files, and CAB files.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/msvcrt.html#module-msvcrt"><tt class="xref">msvcrt</tt></a> <em>(Windows)</em></td><td>
+ <em>Miscellaneous useful routines from the MS VC++ runtime.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/multifile.html#module-multifile"><tt class="xref">multifile</tt></a></td><td><strong>Deprecated:</strong>
+ <em>Support for reading files which contain distinct parts, such as some MIME data.</em></td></tr><tr>
+ <td><img src="_static/minus.png" id="toggle-158"
+ class="toggler" style="display: none" alt="-" /></td>
+ <td>
+ <a href="library/multiprocessing.html#module-multiprocessing"><tt class="xref">multiprocessing</tt></a></td><td>
+ <em>Process-based &#34;threading&#34; interface.</em></td></tr><tr class="cg-158">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/multiprocessing.html#module-multiprocessing.connection"><tt class="xref">multiprocessing.connection</tt></a></td><td>
+ <em>API for dealing with sockets.</em></td></tr><tr class="cg-158">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/multiprocessing.html#module-multiprocessing.dummy"><tt class="xref">multiprocessing.dummy</tt></a></td><td>
+ <em>Dumb wrapper around threading.</em></td></tr><tr class="cg-158">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/multiprocessing.html#module-multiprocessing.managers"><tt class="xref">multiprocessing.managers</tt></a></td><td>
+ <em>Share data between process with shared objects.</em></td></tr><tr class="cg-158">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/multiprocessing.html#module-multiprocessing.pool"><tt class="xref">multiprocessing.pool</tt></a></td><td>
+ <em>Create pools of processes.</em></td></tr><tr class="cg-158">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/multiprocessing.html#module-multiprocessing.sharedctypes"><tt class="xref">multiprocessing.sharedctypes</tt></a></td><td>
+ <em>Allocate ctypes objects from shared memory.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/mutex.html#module-mutex"><tt class="xref">mutex</tt></a></td><td><strong>Deprecated:</strong>
+ <em>Lock and queue for mutual exclusion.</em></td></tr><tr class="pcap"><td></td><td>&nbsp;</td><td></td></tr>
+ <tr class="cap"><td></td><td><a name="cap-N"><strong>N</strong></a></td><td></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/undoc.html#module-Nav"><tt class="xref">Nav</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Interface to Navigation Services.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/netrc.html#module-netrc"><tt class="xref">netrc</tt></a></td><td>
+ <em>Loading of .netrc files.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/new.html#module-new"><tt class="xref">new</tt></a></td><td><strong>Deprecated:</strong>
+ <em>Interface to the creation of runtime implementation objects.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/nis.html#module-nis"><tt class="xref">nis</tt></a> <em>(Unix)</em></td><td>
+ <em>Interface to Sun&#39;s NIS (Yellow Pages) library.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/nntplib.html#module-nntplib"><tt class="xref">nntplib</tt></a></td><td>
+ <em>NNTP protocol client (requires sockets).</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/numbers.html#module-numbers"><tt class="xref">numbers</tt></a></td><td>
+ <em>Numeric abstract base classes (Complex, Real, Integral, etc.).</em></td></tr><tr class="pcap"><td></td><td>&nbsp;</td><td></td></tr>
+ <tr class="cap"><td></td><td><a name="cap-O"><strong>O</strong></a></td><td></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/operator.html#module-operator"><tt class="xref">operator</tt></a></td><td>
+ <em>Functions corresponding to the standard operators.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/optparse.html#module-optparse"><tt class="xref">optparse</tt></a></td><td>
+ <em>More convenient, flexible, and powerful command-line parsing library.</em></td></tr><tr>
+ <td><img src="_static/minus.png" id="toggle-168"
+ class="toggler" style="display: none" alt="-" /></td>
+ <td>
+ <a href="library/os.html#module-os"><tt class="xref">os</tt></a></td><td>
+ <em>Miscellaneous operating system interfaces.</em></td></tr><tr class="cg-168">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/os.path.html#module-os.path"><tt class="xref">os.path</tt></a></td><td>
+ <em>Operations on pathnames.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/ossaudiodev.html#module-ossaudiodev"><tt class="xref">ossaudiodev</tt></a> <em>(Linux, FreeBSD)</em></td><td>
+ <em>Access to OSS-compatible audio devices.</em></td></tr><tr class="pcap"><td></td><td>&nbsp;</td><td></td></tr>
+ <tr class="cap"><td></td><td><a name="cap-P"><strong>P</strong></a></td><td></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/parser.html#module-parser"><tt class="xref">parser</tt></a></td><td>
+ <em>Access parse trees for Python source code.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/pdb.html#module-pdb"><tt class="xref">pdb</tt></a></td><td>
+ <em>The Python debugger for interactive interpreters.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/pickle.html#module-pickle"><tt class="xref">pickle</tt></a></td><td>
+ <em>Convert Python objects to streams of bytes and back.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/pickletools.html#module-pickletools"><tt class="xref">pickletools</tt></a></td><td>
+ <em>Contains extensive comments about the pickle protocols and pickle-machine
+opcodes, as well as some useful functions.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/pipes.html#module-pipes"><tt class="xref">pipes</tt></a> <em>(Unix)</em></td><td>
+ <em>A Python interface to Unix shell pipelines.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/undoc.html#module-PixMapWrapper"><tt class="xref">PixMapWrapper</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Wrapper for PixMap objects.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/pkgutil.html#module-pkgutil"><tt class="xref">pkgutil</tt></a></td><td>
+ <em>Utilities to support extension of packages.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/platform.html#module-platform"><tt class="xref">platform</tt></a></td><td>
+ <em>Retrieves as much platform identifying data as possible.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/plistlib.html#module-plistlib"><tt class="xref">plistlib</tt></a></td><td>
+ <em>Generate and parse Mac OS X plist files.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/popen2.html#module-popen2"><tt class="xref">popen2</tt></a></td><td><strong>Deprecated:</strong>
+ <em>Subprocesses with accessible standard I/O streams.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/poplib.html#module-poplib"><tt class="xref">poplib</tt></a></td><td>
+ <em>POP3 protocol client (requires sockets).</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/posix.html#module-posix"><tt class="xref">posix</tt></a> <em>(Unix)</em></td><td>
+ <em>The most common POSIX system calls (normally used via module os).</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/posixfile.html#module-posixfile"><tt class="xref">posixfile</tt></a> <em>(Unix)</em></td><td><strong>Deprecated:</strong>
+ <em>A file-like object with support for locking.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/pprint.html#module-pprint"><tt class="xref">pprint</tt></a></td><td>
+ <em>Data pretty printer.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/profile.html#module-pstats"><tt class="xref">pstats</tt></a></td><td>
+ <em>Statistics object for use with the profiler.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/pty.html#module-pty"><tt class="xref">pty</tt></a> <em>(IRIX, Linux)</em></td><td>
+ <em>Pseudo-Terminal Handling for SGI and Linux.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/pwd.html#module-pwd"><tt class="xref">pwd</tt></a> <em>(Unix)</em></td><td>
+ <em>The password database (getpwnam() and friends).</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/py_compile.html#module-py_compile"><tt class="xref">py_compile</tt></a></td><td>
+ <em>Generate byte-code files from Python source files.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/pyclbr.html#module-pyclbr"><tt class="xref">pyclbr</tt></a></td><td>
+ <em>Supports information extraction for a Python class browser.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/pydoc.html#module-pydoc"><tt class="xref">pydoc</tt></a></td><td>
+ <em>Documentation generator and online help system.</em></td></tr><tr class="pcap"><td></td><td>&nbsp;</td><td></td></tr>
+ <tr class="cap"><td></td><td><a name="cap-Q"><strong>Q</strong></a></td><td></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/queue.html#module-Queue"><tt class="xref">Queue</tt></a></td><td>
+ <em>A synchronized queue class.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/quopri.html#module-quopri"><tt class="xref">quopri</tt></a></td><td>
+ <em>Encode and decode files using the MIME quoted-printable encoding.</em></td></tr><tr class="pcap"><td></td><td>&nbsp;</td><td></td></tr>
+ <tr class="cap"><td></td><td><a name="cap-R"><strong>R</strong></a></td><td></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/random.html#module-random"><tt class="xref">random</tt></a></td><td>
+ <em>Generate pseudo-random numbers with various common distributions.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/re.html#module-re"><tt class="xref">re</tt></a></td><td>
+ <em>Regular expression operations.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/readline.html#module-readline"><tt class="xref">readline</tt></a> <em>(Unix)</em></td><td>
+ <em>GNU readline support for Python.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/repr.html#module-repr"><tt class="xref">repr</tt></a></td><td>
+ <em>Alternate repr() implementation with size limits.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/resource.html#module-resource"><tt class="xref">resource</tt></a> <em>(Unix)</em></td><td>
+ <em>An interface to provide resource usage information on the current process.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/rexec.html#module-rexec"><tt class="xref">rexec</tt></a></td><td><strong>Deprecated:</strong>
+ <em>Basic restricted execution framework.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/rfc822.html#module-rfc822"><tt class="xref">rfc822</tt></a></td><td><strong>Deprecated:</strong>
+ <em>Parse 2822 style mail messages.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/rlcompleter.html#module-rlcompleter"><tt class="xref">rlcompleter</tt></a></td><td>
+ <em>Python identifier completion, suitable for the GNU readline library.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/robotparser.html#module-robotparser"><tt class="xref">robotparser</tt></a></td><td>
+ <em>Loads a robots.txt file and answers questions about
+fetchability of other URLs.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/runpy.html#module-runpy"><tt class="xref">runpy</tt></a></td><td>
+ <em>Locate and run Python modules without importing them first.</em></td></tr><tr class="pcap"><td></td><td>&nbsp;</td><td></td></tr>
+ <tr class="cap"><td></td><td><a name="cap-S"><strong>S</strong></a></td><td></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/sched.html#module-sched"><tt class="xref">sched</tt></a></td><td>
+ <em>General purpose event scheduler.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/scrolledtext.html#module-ScrolledText"><tt class="xref">ScrolledText</tt></a> <em>(Tk)</em></td><td>
+ <em>Text widget with a vertical scroll bar.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/select.html#module-select"><tt class="xref">select</tt></a></td><td>
+ <em>Wait for I/O completion on multiple streams.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/sets.html#module-sets"><tt class="xref">sets</tt></a></td><td><strong>Deprecated:</strong>
+ <em>Implementation of sets of unique elements.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/sgmllib.html#module-sgmllib"><tt class="xref">sgmllib</tt></a></td><td><strong>Deprecated:</strong>
+ <em>Only as much of an SGML parser as needed to parse HTML.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/sha.html#module-sha"><tt class="xref">sha</tt></a></td><td><strong>Deprecated:</strong>
+ <em>NIST&#39;s secure hash algorithm, SHA.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/shelve.html#module-shelve"><tt class="xref">shelve</tt></a></td><td>
+ <em>Python object persistence.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/shlex.html#module-shlex"><tt class="xref">shlex</tt></a></td><td>
+ <em>Simple lexical analysis for Unix shell-like languages.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/shutil.html#module-shutil"><tt class="xref">shutil</tt></a></td><td>
+ <em>High-level file operations, including copying.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/signal.html#module-signal"><tt class="xref">signal</tt></a></td><td>
+ <em>Set handlers for asynchronous events.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/simplehttpserver.html#module-SimpleHTTPServer"><tt class="xref">SimpleHTTPServer</tt></a></td><td>
+ <em>This module provides a basic request handler for HTTP servers.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/simplexmlrpcserver.html#module-SimpleXMLRPCServer"><tt class="xref">SimpleXMLRPCServer</tt></a></td><td>
+ <em>Basic XML-RPC server implementation.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/site.html#module-site"><tt class="xref">site</tt></a></td><td>
+ <em>A standard way to reference site-specific modules.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/smtpd.html#module-smtpd"><tt class="xref">smtpd</tt></a></td><td>
+ <em>A SMTP server implementation in Python.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/smtplib.html#module-smtplib"><tt class="xref">smtplib</tt></a></td><td>
+ <em>SMTP protocol client (requires sockets).</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/sndhdr.html#module-sndhdr"><tt class="xref">sndhdr</tt></a></td><td>
+ <em>Determine type of a sound file.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/socket.html#module-socket"><tt class="xref">socket</tt></a></td><td>
+ <em>Low-level networking interface.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/socketserver.html#module-SocketServer"><tt class="xref">SocketServer</tt></a></td><td>
+ <em>A framework for network servers.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/spwd.html#module-spwd"><tt class="xref">spwd</tt></a> <em>(Unix)</em></td><td>
+ <em>The shadow password database (getspnam() and friends).</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/sqlite3.html#module-sqlite3"><tt class="xref">sqlite3</tt></a></td><td>
+ <em>A DB-API 2.0 implementation using SQLite 3.x.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/ssl.html#module-ssl"><tt class="xref">ssl</tt></a></td><td>
+ <em>SSL wrapper for socket objects</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/stat.html#module-stat"><tt class="xref">stat</tt></a></td><td>
+ <em>Utilities for interpreting the results of os.stat(), os.lstat() and os.fstat().</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/statvfs.html#module-statvfs"><tt class="xref">statvfs</tt></a></td><td><strong>Deprecated:</strong>
+ <em>Constants for interpreting the result of os.statvfs().</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/string.html#module-string"><tt class="xref">string</tt></a></td><td>
+ <em>Common string operations.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/stringio.html#module-StringIO"><tt class="xref">StringIO</tt></a></td><td>
+ <em>Read and write strings as if they were files.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/stringprep.html#module-stringprep"><tt class="xref">stringprep</tt></a></td><td><strong>Deprecated:</strong>
+ <em>String preparation, as per RFC 3453</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/struct.html#module-struct"><tt class="xref">struct</tt></a></td><td>
+ <em>Interpret strings as packed binary data.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/subprocess.html#module-subprocess"><tt class="xref">subprocess</tt></a></td><td>
+ <em>Subprocess management.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/sunau.html#module-sunau"><tt class="xref">sunau</tt></a></td><td>
+ <em>Provide an interface to the Sun AU sound format.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/sunaudio.html#module-sunaudiodev"><tt class="xref">sunaudiodev</tt></a> <em>(SunOS)</em></td><td><strong>Deprecated:</strong>
+ <em>Access to Sun audio hardware.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/sunaudio.html#module-SUNAUDIODEV"><tt class="xref">SUNAUDIODEV</tt></a> <em>(SunOS)</em></td><td><strong>Deprecated:</strong>
+ <em>Constants for use with sunaudiodev.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/symbol.html#module-symbol"><tt class="xref">symbol</tt></a></td><td>
+ <em>Constants representing internal nodes of the parse tree.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/symtable.html#module-symtable"><tt class="xref">symtable</tt></a></td><td>
+ <em>Interface to the compiler&#39;s internal symbol tables.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/sys.html#module-sys"><tt class="xref">sys</tt></a></td><td>
+ <em>Access system-specific parameters and functions.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/syslog.html#module-syslog"><tt class="xref">syslog</tt></a> <em>(Unix)</em></td><td>
+ <em>An interface to the Unix syslog library routines.</em></td></tr><tr class="pcap"><td></td><td>&nbsp;</td><td></td></tr>
+ <tr class="cap"><td></td><td><a name="cap-T"><strong>T</strong></a></td><td></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/tabnanny.html#module-tabnanny"><tt class="xref">tabnanny</tt></a></td><td>
+ <em>Tool for detecting white space related problems in Python source files in a
+directory tree.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/tarfile.html#module-tarfile"><tt class="xref">tarfile</tt></a></td><td>
+ <em>Read and write tar-format archive files.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/telnetlib.html#module-telnetlib"><tt class="xref">telnetlib</tt></a></td><td>
+ <em>Telnet client class.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/tempfile.html#module-tempfile"><tt class="xref">tempfile</tt></a></td><td>
+ <em>Generate temporary files and directories.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/termios.html#module-termios"><tt class="xref">termios</tt></a> <em>(Unix)</em></td><td>
+ <em>POSIX style tty control.</em></td></tr><tr>
+ <td><img src="_static/minus.png" id="toggle-242"
+ class="toggler" style="display: none" alt="-" /></td>
+ <td>
+ <a href="library/test.html#module-test"><tt class="xref">test</tt></a></td><td>
+ <em>Regression tests package containing the testing suite for Python.</em></td></tr><tr class="cg-242">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/test.html#module-test.test_support"><tt class="xref">test.test_support</tt></a></td><td>
+ <em>Support for Python regression tests.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/textwrap.html#module-textwrap"><tt class="xref">textwrap</tt></a></td><td>
+ <em>Text wrapping and filling</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/thread.html#module-thread"><tt class="xref">thread</tt></a></td><td>
+ <em>Create multiple threads of control within one interpreter.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/threading.html#module-threading"><tt class="xref">threading</tt></a></td><td>
+ <em>Higher-level threading interface.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/time.html#module-time"><tt class="xref">time</tt></a></td><td>
+ <em>Time access and conversions.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/timeit.html#module-timeit"><tt class="xref">timeit</tt></a></td><td>
+ <em>Measure the execution time of small code snippets.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/tix.html#module-Tix"><tt class="xref">Tix</tt></a></td><td>
+ <em>Tk Extension Widgets for Tkinter</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/tkinter.html#module-Tkinter"><tt class="xref">Tkinter</tt></a></td><td>
+ <em>Interface to Tcl/Tk for graphical user interfaces</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/token.html#module-token"><tt class="xref">token</tt></a></td><td>
+ <em>Constants representing terminal nodes of the parse tree.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/tokenize.html#module-tokenize"><tt class="xref">tokenize</tt></a></td><td>
+ <em>Lexical scanner for Python source code.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/trace.html#module-trace"><tt class="xref">trace</tt></a></td><td>
+ <em>Trace or track Python statement execution.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/traceback.html#module-traceback"><tt class="xref">traceback</tt></a></td><td>
+ <em>Print or retrieve a stack traceback.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/tty.html#module-tty"><tt class="xref">tty</tt></a> <em>(Unix)</em></td><td>
+ <em>Utility functions that perform common terminal control operations.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/turtle.html#module-turtle"><tt class="xref">turtle</tt></a></td><td>
+ <em>Turtle graphics for Tk</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/types.html#module-types"><tt class="xref">types</tt></a></td><td>
+ <em>Names for built-in types.</em></td></tr><tr class="pcap"><td></td><td>&nbsp;</td><td></td></tr>
+ <tr class="cap"><td></td><td><a name="cap-U"><strong>U</strong></a></td><td></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/unicodedata.html#module-unicodedata"><tt class="xref">unicodedata</tt></a></td><td>
+ <em>Access the Unicode Database.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/unittest.html#module-unittest"><tt class="xref">unittest</tt></a></td><td>
+ <em>Unit testing framework for Python.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/urllib.html#module-urllib"><tt class="xref">urllib</tt></a></td><td>
+ <em>Open an arbitrary network resource by URL (requires sockets).</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/urllib2.html#module-urllib2"><tt class="xref">urllib2</tt></a></td><td>
+ <em>Next generation URL opening library.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/urlparse.html#module-urlparse"><tt class="xref">urlparse</tt></a></td><td>
+ <em>Parse URLs into or assemble them from components.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/user.html#module-user"><tt class="xref">user</tt></a></td><td><strong>Deprecated:</strong>
+ <em>A standard way to reference user-specific modules.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/userdict.html#module-UserDict"><tt class="xref">UserDict</tt></a></td><td>
+ <em>Class wrapper for dictionary objects.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/userdict.html#module-UserList"><tt class="xref">UserList</tt></a></td><td>
+ <em>Class wrapper for list objects.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/userdict.html#module-UserString"><tt class="xref">UserString</tt></a></td><td>
+ <em>Class wrapper for string objects.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/uu.html#module-uu"><tt class="xref">uu</tt></a></td><td>
+ <em>Encode and decode files in uuencode format.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/uuid.html#module-uuid"><tt class="xref">uuid</tt></a></td><td>
+ <em>UUID objects (universally unique identifiers) according to RFC 4122</em></td></tr><tr class="pcap"><td></td><td>&nbsp;</td><td></td></tr>
+ <tr class="cap"><td></td><td><a name="cap-V"><strong>V</strong></a></td><td></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/undoc.html#module-videoreader"><tt class="xref">videoreader</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Read QuickTime movies frame by frame for further processing.</em></td></tr><tr class="pcap"><td></td><td>&nbsp;</td><td></td></tr>
+ <tr class="cap"><td></td><td><a name="cap-W"><strong>W</strong></a></td><td></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/undoc.html#module-W"><tt class="xref">W</tt></a> <em>(Mac)</em></td><td><strong>Deprecated:</strong>
+ <em>Widgets for the Mac, built on top of FrameWork.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/warnings.html#module-warnings"><tt class="xref">warnings</tt></a></td><td>
+ <em>Issue warning messages and control their disposition.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/wave.html#module-wave"><tt class="xref">wave</tt></a></td><td>
+ <em>Provide an interface to the WAV sound format.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/weakref.html#module-weakref"><tt class="xref">weakref</tt></a></td><td>
+ <em>Support for weak references and weak dictionaries.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/webbrowser.html#module-webbrowser"><tt class="xref">webbrowser</tt></a></td><td>
+ <em>Easy-to-use controller for Web browsers.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/whichdb.html#module-whichdb"><tt class="xref">whichdb</tt></a></td><td>
+ <em>Guess which DBM-style module created a given database.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/winsound.html#module-winsound"><tt class="xref">winsound</tt></a> <em>(Windows)</em></td><td>
+ <em>Access to the sound-playing machinery for Windows.</em></td></tr><tr>
+ <td><img src="_static/minus.png" id="toggle-276"
+ class="toggler" style="display: none" alt="-" /></td>
+ <td>
+ <a href="library/wsgiref.html#module-wsgiref"><tt class="xref">wsgiref</tt></a></td><td>
+ <em>WSGI Utilities and Reference Implementation.</em></td></tr><tr class="cg-276">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/wsgiref.html#module-wsgiref.handlers"><tt class="xref">wsgiref.handlers</tt></a></td><td>
+ <em>WSGI server/gateway base classes.</em></td></tr><tr class="cg-276">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/wsgiref.html#module-wsgiref.headers"><tt class="xref">wsgiref.headers</tt></a></td><td>
+ <em>WSGI response header tools.</em></td></tr><tr class="cg-276">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/wsgiref.html#module-wsgiref.simple_server"><tt class="xref">wsgiref.simple_server</tt></a></td><td>
+ <em>A simple WSGI HTTP server.</em></td></tr><tr class="cg-276">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/wsgiref.html#module-wsgiref.util"><tt class="xref">wsgiref.util</tt></a></td><td>
+ <em>WSGI environment utilities.</em></td></tr><tr class="cg-276">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/wsgiref.html#module-wsgiref.validate"><tt class="xref">wsgiref.validate</tt></a></td><td>
+ <em>WSGI conformance checker.</em></td></tr><tr class="pcap"><td></td><td>&nbsp;</td><td></td></tr>
+ <tr class="cap"><td></td><td><a name="cap-X"><strong>X</strong></a></td><td></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/xdrlib.html#module-xdrlib"><tt class="xref">xdrlib</tt></a></td><td>
+ <em>Encoders and decoders for the External Data Representation (XDR).</em></td></tr><tr>
+ <td><img src="_static/minus.png" id="toggle-278"
+ class="toggler" style="display: none" alt="-" /></td>
+ <td>
+ <tt class="xref">xml</tt></td><td>
+ <em></em></td></tr><tr class="cg-278">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/xml.dom.html#module-xml.dom"><tt class="xref">xml.dom</tt></a></td><td>
+ <em>Document Object Model API for Python.</em></td></tr><tr class="cg-278">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/xml.dom.minidom.html#module-xml.dom.minidom"><tt class="xref">xml.dom.minidom</tt></a></td><td>
+ <em>Lightweight Document Object Model (DOM) implementation.</em></td></tr><tr class="cg-278">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/xml.dom.pulldom.html#module-xml.dom.pulldom"><tt class="xref">xml.dom.pulldom</tt></a></td><td>
+ <em>Support for building partial DOM trees from SAX events.</em></td></tr><tr class="cg-278">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/xml.etree.elementtree.html#module-xml.etree.ElementTree"><tt class="xref">xml.etree.ElementTree</tt></a></td><td>
+ <em>Implementation of the ElementTree API.</em></td></tr><tr class="cg-278">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/pyexpat.html#module-xml.parsers.expat"><tt class="xref">xml.parsers.expat</tt></a></td><td>
+ <em>An interface to the Expat non-validating XML parser.</em></td></tr><tr class="cg-278">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/xml.sax.html#module-xml.sax"><tt class="xref">xml.sax</tt></a></td><td>
+ <em>Package containing SAX2 base classes and convenience functions.</em></td></tr><tr class="cg-278">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/xml.sax.handler.html#module-xml.sax.handler"><tt class="xref">xml.sax.handler</tt></a></td><td>
+ <em>Base classes for SAX event handlers.</em></td></tr><tr class="cg-278">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/xml.sax.utils.html#module-xml.sax.saxutils"><tt class="xref">xml.sax.saxutils</tt></a></td><td>
+ <em>Convenience functions and classes for use with SAX.</em></td></tr><tr class="cg-278">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="library/xml.sax.reader.html#module-xml.sax.xmlreader"><tt class="xref">xml.sax.xmlreader</tt></a></td><td>
+ <em>Interface which SAX-compliant XML parsers must implement.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/xmlrpclib.html#module-xmlrpclib"><tt class="xref">xmlrpclib</tt></a></td><td>
+ <em>XML-RPC client access.</em></td></tr><tr class="pcap"><td></td><td>&nbsp;</td><td></td></tr>
+ <tr class="cap"><td></td><td><a name="cap-Z"><strong>Z</strong></a></td><td></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/zipfile.html#module-zipfile"><tt class="xref">zipfile</tt></a></td><td>
+ <em>Read and write ZIP-format archive files.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/zipimport.html#module-zipimport"><tt class="xref">zipimport</tt></a></td><td>
+ <em>support for importing Python modules from ZIP archives.</em></td></tr><tr>
+ <td></td>
+ <td>
+ <a href="library/zlib.html#module-zlib"><tt class="xref">zlib</tt></a></td><td>
+ <em>Low-level interface to compression and decompression routines compatible with
+gzip.</em></td></tr>
+ </table>
+
+
+ </div>
+ </div>
+ </div>
+ <div class="sphinxsidebar">
+ <div class="sphinxsidebarwrapper">
+ <div id="searchbox" style="display: none">
+ <h3>Quick search</h3>
+ <form class="search" action="search.html" method="get">
+ <input type="text" name="q" size="18" />
+ <input type="submit" value="Go" />
+ <input type="hidden" name="check_keywords" value="yes" />
+ <input type="hidden" name="area" value="default" />
+ </form>
+ <p class="searchtip" style="font-size: 90%">
+ Enter search terms or a module, class or function name.
+ </p>
+ </div>
+ <script type="text/javascript">$('#searchbox').show(0);</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="genindex.html" title="General Index"
+ >index</a></li>
+ <li class="right" >
+ <a href="" title="Global Module Index"
+ >modules</a> |</li>
+ <li><img src="_static/py.png" alt=""
+ style="vertical-align: middle; margin-top: -1px"/></li>
+ <li><a href="index.html">Python v2.6.4c2 documentation</a> &raquo;</li>
+
+ </ul>
+ </div>
+ <div class="footer">
+ &copy; <a href="copyright.html">Copyright</a> 1990-2009, Python Software Foundation.
+ <br />
+ The Python Software Foundation is a non-profit corporation.
+ <a href="http://www.python.org/psf/donations/">Please donate.</a>
+ <br />
+ Last updated on Oct 19, 2009.
+ Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 0.6.2.
+ </div>
+
+ </body>
+</html> \ No newline at end of file
diff --git a/help/PythonTutorial/tutorial/appetite.html b/help/PythonTutorial/tutorial/appetite.html
new file mode 100644
index 0000000..9f7e947
--- /dev/null
+++ b/help/PythonTutorial/tutorial/appetite.html
@@ -0,0 +1,201 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+ <title>1. Whetting Your Appetite &mdash; Python v2.6.4c2 documentation</title>
+ <link rel="stylesheet" href="../_static/default.css" type="text/css" />
+ <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
+ <script type="text/javascript">
+ var DOCUMENTATION_OPTIONS = {
+ URL_ROOT: '../',
+ VERSION: '2.6.4c2',
+ COLLAPSE_MODINDEX: false,
+ FILE_SUFFIX: '.html',
+ HAS_SOURCE: true
+ };
+ </script>
+ <script type="text/javascript" src="../_static/jquery.js"></script>
+ <script type="text/javascript" src="../_static/doctools.js"></script>
+ <link rel="search" type="application/opensearchdescription+xml"
+ title="Search within Python v2.6.4c2 documentation"
+ href="../_static/opensearch.xml"/>
+ <link rel="author" title="About these documents" href="../about.html" />
+ <link rel="copyright" title="Copyright" href="../copyright.html" />
+ <link rel="top" title="Python v2.6.4c2 documentation" href="../index.html" />
+ <link rel="up" title="The Python Tutorial" href="index.html" />
+ <link rel="next" title="2. Using the Python Interpreter" href="interpreter.html" />
+ <link rel="prev" title="The Python Tutorial" href="index.html" />
+ <link rel="shortcut icon" type="image/png" href="../_static/py.png" />
+
+
+ </head>
+ <body>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../modindex.html" title="Global Module Index"
+ accesskey="M">modules</a> |</li>
+ <li class="right" >
+ <a href="interpreter.html" title="2. Using the Python Interpreter"
+ accesskey="N">next</a> |</li>
+ <li class="right" >
+ <a href="index.html" title="The Python Tutorial"
+ accesskey="P">previous</a> |</li>
+ <li><img src="../_static/py.png" alt=""
+ style="vertical-align: middle; margin-top: -1px"/></li>
+ <li><a href="../index.html">Python v2.6.4c2 documentation</a> &raquo;</li>
+
+ <li><a href="index.html" accesskey="U">The Python Tutorial</a> &raquo;</li>
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body">
+
+ <div class="section" id="whetting-your-appetite">
+<span id="tut-intro"></span><h1>1. Whetting Your Appetite<a class="headerlink" href="#whetting-your-appetite" title="Permalink to this headline">¶</a></h1>
+<p>If you do much work on computers, eventually you find that there&#8217;s some task
+you&#8217;d like to automate. For example, you may wish to perform a
+search-and-replace over a large number of text files, or rename and rearrange a
+bunch of photo files in a complicated way. Perhaps you&#8217;d like to write a small
+custom database, or a specialized GUI application, or a simple game.</p>
+<p>If you&#8217;re a professional software developer, you may have to work with several
+C/C++/Java libraries but find the usual write/compile/test/re-compile cycle is
+too slow. Perhaps you&#8217;re writing a test suite for such a library and find
+writing the testing code a tedious task. Or maybe you&#8217;ve written a program that
+could use an extension language, and you don&#8217;t want to design and implement a
+whole new language for your application.</p>
+<p>Python is just the language for you.</p>
+<p>You could write a Unix shell script or Windows batch files for some of these
+tasks, but shell scripts are best at moving around files and changing text data,
+not well-suited for GUI applications or games. You could write a C/C++/Java
+program, but it can take a lot of development time to get even a first-draft
+program. Python is simpler to use, available on Windows, Mac OS X, and Unix
+operating systems, and will help you get the job done more quickly.</p>
+<p>Python is simple to use, but it is a real programming language, offering much
+more structure and support for large programs than shell scripts or batch files
+can offer. On the other hand, Python also offers much more error checking than
+C, and, being a <em>very-high-level language</em>, it has high-level data types built
+in, such as flexible arrays and dictionaries. Because of its more general data
+types Python is applicable to a much larger problem domain than Awk or even
+Perl, yet many things are at least as easy in Python as in those languages.</p>
+<p>Python allows you to split your program into modules that can be reused in other
+Python programs. It comes with a large collection of standard modules that you
+can use as the basis of your programs &#8212; or as examples to start learning to
+program in Python. Some of these modules provide things like file I/O, system
+calls, sockets, and even interfaces to graphical user interface toolkits like
+Tk.</p>
+<p>Python is an interpreted language, which can save you considerable time during
+program development because no compilation and linking is necessary. The
+interpreter can be used interactively, which makes it easy to experiment with
+features of the language, to write throw-away programs, or to test functions
+during bottom-up program development. It is also a handy desk calculator.</p>
+<p>Python enables programs to be written compactly and readably. Programs written
+in Python are typically much shorter than equivalent C, C++, or Java programs,
+for several reasons:</p>
+<ul class="simple">
+<li>the high-level data types allow you to express complex operations in a single
+statement;</li>
+<li>statement grouping is done by indentation instead of beginning and ending
+brackets;</li>
+<li>no variable or argument declarations are necessary.</li>
+</ul>
+<p>Python is <em>extensible</em>: if you know how to program in C it is easy to add a new
+built-in function or module to the interpreter, either to perform critical
+operations at maximum speed, or to link Python programs to libraries that may
+only be available in binary form (such as a vendor-specific graphics library).
+Once you are really hooked, you can link the Python interpreter into an
+application written in C and use it as an extension or command language for that
+application.</p>
+<p>By the way, the language is named after the BBC show &#8220;Monty Python&#8217;s Flying
+Circus&#8221; and has nothing to do with reptiles. Making references to Monty
+Python skits in documentation is not only allowed, it is encouraged!</p>
+<p>Now that you are all excited about Python, you&#8217;ll want to examine it in some
+more detail. Since the best way to learn a language is to use it, the tutorial
+invites you to play with the Python interpreter as you read.</p>
+<p>In the next chapter, the mechanics of using the interpreter are explained. This
+is rather mundane information, but essential for trying out the examples shown
+later.</p>
+<p>The rest of the tutorial introduces various features of the Python language and
+system through examples, beginning with simple expressions, statements and data
+types, through functions and modules, and finally touching upon advanced
+concepts like exceptions and user-defined classes.</p>
+</div>
+
+
+ </div>
+ </div>
+ </div>
+ <div class="sphinxsidebar">
+ <div class="sphinxsidebarwrapper">
+ <h4>Previous topic</h4>
+ <p class="topless"><a href="index.html"
+ title="previous chapter">The Python Tutorial</a></p>
+ <h4>Next topic</h4>
+ <p class="topless"><a href="interpreter.html"
+ title="next chapter">2. Using the Python Interpreter</a></p>
+ <h3>This Page</h3>
+ <ul class="this-page-menu">
+ <li><a href="../_sources/tutorial/appetite.txt"
+ rel="nofollow">Show Source</a></li>
+ </ul>
+ <div id="searchbox" style="display: none">
+ <h3>Quick search</h3>
+ <form class="search" action="../search.html" method="get">
+ <input type="text" name="q" size="18" />
+ <input type="submit" value="Go" />
+ <input type="hidden" name="check_keywords" value="yes" />
+ <input type="hidden" name="area" value="default" />
+ </form>
+ <p class="searchtip" style="font-size: 90%">
+ Enter search terms or a module, class or function name.
+ </p>
+ </div>
+ <script type="text/javascript">$('#searchbox').show(0);</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../genindex.html" title="General Index"
+ >index</a></li>
+ <li class="right" >
+ <a href="../modindex.html" title="Global Module Index"
+ >modules</a> |</li>
+ <li class="right" >
+ <a href="interpreter.html" title="2. Using the Python Interpreter"
+ >next</a> |</li>
+ <li class="right" >
+ <a href="index.html" title="The Python Tutorial"
+ >previous</a> |</li>
+ <li><img src="../_static/py.png" alt=""
+ style="vertical-align: middle; margin-top: -1px"/></li>
+ <li><a href="../index.html">Python v2.6.4c2 documentation</a> &raquo;</li>
+
+ <li><a href="index.html" >The Python Tutorial</a> &raquo;</li>
+ </ul>
+ </div>
+ <div class="footer">
+ &copy; <a href="../copyright.html">Copyright</a> 1990-2009, Python Software Foundation.
+ <br />
+ The Python Software Foundation is a non-profit corporation.
+ <a href="http://www.python.org/psf/donations/">Please donate.</a>
+ <br />
+ Last updated on Oct 19, 2009.
+ Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 0.6.2.
+ </div>
+
+ </body>
+</html> \ No newline at end of file
diff --git a/help/PythonTutorial/tutorial/classes.html b/help/PythonTutorial/tutorial/classes.html
new file mode 100644
index 0000000..b4b8ff1
--- /dev/null
+++ b/help/PythonTutorial/tutorial/classes.html
@@ -0,0 +1,838 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+ <title>9. Classes &mdash; Python v2.6.4c2 documentation</title>
+ <link rel="stylesheet" href="../_static/default.css" type="text/css" />
+ <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
+ <script type="text/javascript">
+ var DOCUMENTATION_OPTIONS = {
+ URL_ROOT: '../',
+ VERSION: '2.6.4c2',
+ COLLAPSE_MODINDEX: false,
+ FILE_SUFFIX: '.html',
+ HAS_SOURCE: true
+ };
+ </script>
+ <script type="text/javascript" src="../_static/jquery.js"></script>
+ <script type="text/javascript" src="../_static/doctools.js"></script>
+ <link rel="search" type="application/opensearchdescription+xml"
+ title="Search within Python v2.6.4c2 documentation"
+ href="../_static/opensearch.xml"/>
+ <link rel="author" title="About these documents" href="../about.html" />
+ <link rel="copyright" title="Copyright" href="../copyright.html" />
+ <link rel="top" title="Python v2.6.4c2 documentation" href="../index.html" />
+ <link rel="up" title="The Python Tutorial" href="index.html" />
+ <link rel="next" title="10. Brief Tour of the Standard Library" href="stdlib.html" />
+ <link rel="prev" title="8. Errors and Exceptions" href="errors.html" />
+ <link rel="shortcut icon" type="image/png" href="../_static/py.png" />
+
+
+ </head>
+ <body>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../modindex.html" title="Global Module Index"
+ accesskey="M">modules</a> |</li>
+ <li class="right" >
+ <a href="stdlib.html" title="10. Brief Tour of the Standard Library"
+ accesskey="N">next</a> |</li>
+ <li class="right" >
+ <a href="errors.html" title="8. Errors and Exceptions"
+ accesskey="P">previous</a> |</li>
+ <li><img src="../_static/py.png" alt=""
+ style="vertical-align: middle; margin-top: -1px"/></li>
+ <li><a href="../index.html">Python v2.6.4c2 documentation</a> &raquo;</li>
+
+ <li><a href="index.html" accesskey="U">The Python Tutorial</a> &raquo;</li>
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body">
+
+ <div class="section" id="classes">
+<span id="tut-classes"></span><h1>9. Classes<a class="headerlink" href="#classes" title="Permalink to this headline">¶</a></h1>
+<p>Python&#8217;s class mechanism adds classes to the language with a minimum of new
+syntax and semantics. It is a mixture of the class mechanisms found in C++ and
+Modula-3. As is true for modules, classes in Python do not put an absolute
+barrier between definition and user, but rather rely on the politeness of the
+user not to &#8220;break into the definition.&#8221; The most important features of classes
+are retained with full power, however: the class inheritance mechanism allows
+multiple base classes, a derived class can override any methods of its base
+class or classes, and a method can call the method of a base class with the same
+name. Objects can contain an arbitrary amount of private data.</p>
+<p>In C++ terminology, all class members (including the data members) are <em>public</em>,
+and all member functions are <em>virtual</em>. There are no special constructors or
+destructors. As in Modula-3, there are no shorthands for referencing the
+object&#8217;s members from its methods: the method function is declared with an
+explicit first argument representing the object, which is provided implicitly by
+the call. As in Smalltalk, classes themselves are objects, albeit in the wider
+sense of the word: in Python, all data types are objects. This provides
+semantics for importing and renaming. Unlike C++ and Modula-3, built-in types
+can be used as base classes for extension by the user. Also, like in C++ but
+unlike in Modula-3, most built-in operators with special syntax (arithmetic
+operators, subscripting etc.) can be redefined for class instances.</p>
+<div class="section" id="a-word-about-terminology">
+<span id="tut-terminology"></span><h2>9.1. A Word About Terminology<a class="headerlink" href="#a-word-about-terminology" title="Permalink to this headline">¶</a></h2>
+<p>Lacking universally accepted terminology to talk about classes, I will make
+occasional use of Smalltalk and C++ terms. (I would use Modula-3 terms, since
+its object-oriented semantics are closer to those of Python than C++, but I
+expect that few readers have heard of it.)</p>
+<p>Objects have individuality, and multiple names (in multiple scopes) can be bound
+to the same object. This is known as aliasing in other languages. This is
+usually not appreciated on a first glance at Python, and can be safely ignored
+when dealing with immutable basic types (numbers, strings, tuples). However,
+aliasing has an (intended!) effect on the semantics of Python code involving
+mutable objects such as lists, dictionaries, and most types representing
+entities outside the program (files, windows, etc.). This is usually used to
+the benefit of the program, since aliases behave like pointers in some respects.
+For example, passing an object is cheap since only a pointer is passed by the
+implementation; and if a function modifies an object passed as an argument, the
+caller will see the change &#8212; this eliminates the need for two different
+argument passing mechanisms as in Pascal.</p>
+</div>
+<div class="section" id="python-scopes-and-name-spaces">
+<span id="tut-scopes"></span><h2>9.2. Python Scopes and Name Spaces<a class="headerlink" href="#python-scopes-and-name-spaces" title="Permalink to this headline">¶</a></h2>
+<p>Before introducing classes, I first have to tell you something about Python&#8217;s
+scope rules. Class definitions play some neat tricks with namespaces, and you
+need to know how scopes and namespaces work to fully understand what&#8217;s going on.
+Incidentally, knowledge about this subject is useful for any advanced Python
+programmer.</p>
+<p>Let&#8217;s begin with some definitions.</p>
+<p>A <em>namespace</em> is a mapping from names to objects. Most namespaces are currently
+implemented as Python dictionaries, but that&#8217;s normally not noticeable in any
+way (except for performance), and it may change in the future. Examples of
+namespaces are: the set of built-in names (functions such as <a title="abs" class="reference external" href="../library/functions.html#abs"><tt class="xref docutils literal"><span class="pre">abs()</span></tt></a>, and
+built-in exception names); the global names in a module; and the local names in
+a function invocation. In a sense the set of attributes of an object also form
+a namespace. The important thing to know about namespaces is that there is
+absolutely no relation between names in different namespaces; for instance, two
+different modules may both define a function &#8220;maximize&#8221; without confusion &#8212;
+users of the modules must prefix it with the module name.</p>
+<p>By the way, I use the word <em>attribute</em> for any name following a dot &#8212; for
+example, in the expression <tt class="docutils literal"><span class="pre">z.real</span></tt>, <tt class="docutils literal"><span class="pre">real</span></tt> is an attribute of the object
+<tt class="docutils literal"><span class="pre">z</span></tt>. Strictly speaking, references to names in modules are attribute
+references: in the expression <tt class="docutils literal"><span class="pre">modname.funcname</span></tt>, <tt class="docutils literal"><span class="pre">modname</span></tt> is a module
+object and <tt class="docutils literal"><span class="pre">funcname</span></tt> is an attribute of it. In this case there happens to be
+a straightforward mapping between the module&#8217;s attributes and the global names
+defined in the module: they share the same namespace! <a class="footnote-reference" href="#id2" id="id1">[1]</a></p>
+<p>Attributes may be read-only or writable. In the latter case, assignment to
+attributes is possible. Module attributes are writable: you can write
+<tt class="docutils literal"><span class="pre">modname.the_answer</span> <span class="pre">=</span> <span class="pre">42</span></tt>. Writable attributes may also be deleted with the
+<a class="reference external" href="../reference/simple_stmts.html#del"><tt class="xref docutils literal"><span class="pre">del</span></tt></a> statement. For example, <tt class="docutils literal"><span class="pre">del</span> <span class="pre">modname.the_answer</span></tt> will remove
+the attribute <tt class="xref docutils literal"><span class="pre">the_answer</span></tt> from the object named by <tt class="docutils literal"><span class="pre">modname</span></tt>.</p>
+<p>Name spaces are created at different moments and have different lifetimes. The
+namespace containing the built-in names is created when the Python interpreter
+starts up, and is never deleted. The global namespace for a module is created
+when the module definition is read in; normally, module namespaces also last
+until the interpreter quits. The statements executed by the top-level
+invocation of the interpreter, either read from a script file or interactively,
+are considered part of a module called <a title="The environment where the top-level script is run." class="reference external" href="../library/__main__.html#module-__main__"><tt class="xref docutils literal"><span class="pre">__main__</span></tt></a>, so they have their own
+global namespace. (The built-in names actually also live in a module; this is
+called <a title="The module that provides the built-in namespace." class="reference external" href="../library/__builtin__.html#module-__builtin__"><tt class="xref docutils literal"><span class="pre">__builtin__</span></tt></a>.)</p>
+<p>The local namespace for a function is created when the function is called, and
+deleted when the function returns or raises an exception that is not handled
+within the function. (Actually, forgetting would be a better way to describe
+what actually happens.) Of course, recursive invocations each have their own
+local namespace.</p>
+<p>A <em>scope</em> is a textual region of a Python program where a namespace is directly
+accessible. &#8220;Directly accessible&#8221; here means that an unqualified reference to a
+name attempts to find the name in the namespace.</p>
+<p>Although scopes are determined statically, they are used dynamically. At any
+time during execution, there are at least three nested scopes whose namespaces
+are directly accessible: the innermost scope, which is searched first, contains
+the local names; the namespaces of any enclosing functions, which are searched
+starting with the nearest enclosing scope; the middle scope, searched next,
+contains the current module&#8217;s global names; and the outermost scope (searched
+last) is the namespace containing built-in names.</p>
+<p>If a name is declared global, then all references and assignments go directly to
+the middle scope containing the module&#8217;s global names. Otherwise, all variables
+found outside of the innermost scope are read-only (an attempt to write to such
+a variable will simply create a <em>new</em> local variable in the innermost scope,
+leaving the identically named outer variable unchanged).</p>
+<p>Usually, the local scope references the local names of the (textually) current
+function. Outside functions, the local scope references the same namespace as
+the global scope: the module&#8217;s namespace. Class definitions place yet another
+namespace in the local scope.</p>
+<p>It is important to realize that scopes are determined textually: the global
+scope of a function defined in a module is that module&#8217;s namespace, no matter
+from where or by what alias the function is called. On the other hand, the
+actual search for names is done dynamically, at run time &#8212; however, the
+language definition is evolving towards static name resolution, at &#8220;compile&#8221;
+time, so don&#8217;t rely on dynamic name resolution! (In fact, local variables are
+already determined statically.)</p>
+<p>A special quirk of Python is that &#8211; if no <a class="reference external" href="../reference/simple_stmts.html#global"><tt class="xref docutils literal"><span class="pre">global</span></tt></a>
+statement is in effect &#8211; assignments to names always go
+into the innermost scope. Assignments do not copy data &#8212; they just bind names
+to objects. The same is true for deletions: the statement <tt class="docutils literal"><span class="pre">del</span> <span class="pre">x</span></tt> removes the
+binding of <tt class="docutils literal"><span class="pre">x</span></tt> from the namespace referenced by the local scope. In fact, all
+operations that introduce new names use the local scope: in particular, import
+statements and function definitions bind the module or function name in the
+local scope. (The <a class="reference external" href="../reference/simple_stmts.html#global"><tt class="xref docutils literal"><span class="pre">global</span></tt></a> statement can be used to indicate that
+particular variables live in the global scope.)</p>
+</div>
+<div class="section" id="a-first-look-at-classes">
+<span id="tut-firstclasses"></span><h2>9.3. A First Look at Classes<a class="headerlink" href="#a-first-look-at-classes" title="Permalink to this headline">¶</a></h2>
+<p>Classes introduce a little bit of new syntax, three new object types, and some
+new semantics.</p>
+<div class="section" id="class-definition-syntax">
+<span id="tut-classdefinition"></span><h3>9.3.1. Class Definition Syntax<a class="headerlink" href="#class-definition-syntax" title="Permalink to this headline">¶</a></h3>
+<p>The simplest form of class definition looks like this:</p>
+<div class="highlight-python"><pre>class ClassName:
+ &lt;statement-1&gt;
+ .
+ .
+ .
+ &lt;statement-N&gt;</pre>
+</div>
+<p>Class definitions, like function definitions (<a class="reference external" href="../reference/compound_stmts.html#def"><tt class="xref docutils literal"><span class="pre">def</span></tt></a> statements) must be
+executed before they have any effect. (You could conceivably place a class
+definition in a branch of an <a class="reference external" href="../reference/compound_stmts.html#if"><tt class="xref docutils literal"><span class="pre">if</span></tt></a> statement, or inside a function.)</p>
+<p>In practice, the statements inside a class definition will usually be function
+definitions, but other statements are allowed, and sometimes useful &#8212; we&#8217;ll
+come back to this later. The function definitions inside a class normally have
+a peculiar form of argument list, dictated by the calling conventions for
+methods &#8212; again, this is explained later.</p>
+<p>When a class definition is entered, a new namespace is created, and used as the
+local scope &#8212; thus, all assignments to local variables go into this new
+namespace. In particular, function definitions bind the name of the new
+function here.</p>
+<p>When a class definition is left normally (via the end), a <em>class object</em> is
+created. This is basically a wrapper around the contents of the namespace
+created by the class definition; we&#8217;ll learn more about class objects in the
+next section. The original local scope (the one in effect just before the class
+definition was entered) is reinstated, and the class object is bound here to the
+class name given in the class definition header (<tt class="xref docutils literal"><span class="pre">ClassName</span></tt> in the
+example).</p>
+</div>
+<div class="section" id="class-objects">
+<span id="tut-classobjects"></span><h3>9.3.2. Class Objects<a class="headerlink" href="#class-objects" title="Permalink to this headline">¶</a></h3>
+<p>Class objects support two kinds of operations: attribute references and
+instantiation.</p>
+<p><em>Attribute references</em> use the standard syntax used for all attribute references
+in Python: <tt class="docutils literal"><span class="pre">obj.name</span></tt>. Valid attribute names are all the names that were in
+the class&#8217;s namespace when the class object was created. So, if the class
+definition looked like this:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="k">class</span> <span class="nc">MyClass</span><span class="p">:</span>
+ <span class="sd">&quot;&quot;&quot;A simple example class&quot;&quot;&quot;</span>
+ <span class="n">i</span> <span class="o">=</span> <span class="mf">12345</span>
+ <span class="k">def</span> <span class="nf">f</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+ <span class="k">return</span> <span class="s">&#39;hello world&#39;</span>
+</pre></div>
+</div>
+<p>then <tt class="docutils literal"><span class="pre">MyClass.i</span></tt> and <tt class="docutils literal"><span class="pre">MyClass.f</span></tt> are valid attribute references, returning
+an integer and a function object, respectively. Class attributes can also be
+assigned to, so you can change the value of <tt class="docutils literal"><span class="pre">MyClass.i</span></tt> by assignment.
+<tt class="xref docutils literal"><span class="pre">__doc__</span></tt> is also a valid attribute, returning the docstring belonging to
+the class: <tt class="docutils literal"><span class="pre">&quot;A</span> <span class="pre">simple</span> <span class="pre">example</span> <span class="pre">class&quot;</span></tt>.</p>
+<p>Class <em>instantiation</em> uses function notation. Just pretend that the class
+object is a parameterless function that returns a new instance of the class.
+For example (assuming the above class):</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="n">x</span> <span class="o">=</span> <span class="n">MyClass</span><span class="p">()</span>
+</pre></div>
+</div>
+<p>creates a new <em>instance</em> of the class and assigns this object to the local
+variable <tt class="docutils literal"><span class="pre">x</span></tt>.</p>
+<p>The instantiation operation (&#8220;calling&#8221; a class object) creates an empty object.
+Many classes like to create objects with instances customized to a specific
+initial state. Therefore a class may define a special method named
+<a title="object.__init__" class="reference external" href="../reference/datamodel.html#object.__init__"><tt class="xref docutils literal"><span class="pre">__init__()</span></tt></a>, like this:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+ <span class="bp">self</span><span class="o">.</span><span class="n">data</span> <span class="o">=</span> <span class="p">[]</span>
+</pre></div>
+</div>
+<p>When a class defines an <a title="object.__init__" class="reference external" href="../reference/datamodel.html#object.__init__"><tt class="xref docutils literal"><span class="pre">__init__()</span></tt></a> method, class instantiation
+automatically invokes <a title="object.__init__" class="reference external" href="../reference/datamodel.html#object.__init__"><tt class="xref docutils literal"><span class="pre">__init__()</span></tt></a> for the newly-created class instance. So
+in this example, a new, initialized instance can be obtained by:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="n">x</span> <span class="o">=</span> <span class="n">MyClass</span><span class="p">()</span>
+</pre></div>
+</div>
+<p>Of course, the <a title="object.__init__" class="reference external" href="../reference/datamodel.html#object.__init__"><tt class="xref docutils literal"><span class="pre">__init__()</span></tt></a> method may have arguments for greater
+flexibility. In that case, arguments given to the class instantiation operator
+are passed on to <a title="object.__init__" class="reference external" href="../reference/datamodel.html#object.__init__"><tt class="xref docutils literal"><span class="pre">__init__()</span></tt></a>. For example,</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">class</span> <span class="nc">Complex</span><span class="p">:</span>
+<span class="gp">... </span> <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">realpart</span><span class="p">,</span> <span class="n">imagpart</span><span class="p">):</span>
+<span class="gp">... </span> <span class="bp">self</span><span class="o">.</span><span class="n">r</span> <span class="o">=</span> <span class="n">realpart</span>
+<span class="gp">... </span> <span class="bp">self</span><span class="o">.</span><span class="n">i</span> <span class="o">=</span> <span class="n">imagpart</span>
+<span class="gp">...</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">x</span> <span class="o">=</span> <span class="n">Complex</span><span class="p">(</span><span class="mf">3.0</span><span class="p">,</span> <span class="o">-</span><span class="mf">4.5</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">x</span><span class="o">.</span><span class="n">r</span><span class="p">,</span> <span class="n">x</span><span class="o">.</span><span class="n">i</span>
+<span class="go">(3.0, -4.5)</span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="instance-objects">
+<span id="tut-instanceobjects"></span><h3>9.3.3. Instance Objects<a class="headerlink" href="#instance-objects" title="Permalink to this headline">¶</a></h3>
+<p>Now what can we do with instance objects? The only operations understood by
+instance objects are attribute references. There are two kinds of valid
+attribute names, data attributes and methods.</p>
+<p><em>data attributes</em> correspond to &#8220;instance variables&#8221; in Smalltalk, and to &#8220;data
+members&#8221; in C++. Data attributes need not be declared; like local variables,
+they spring into existence when they are first assigned to. For example, if
+<tt class="docutils literal"><span class="pre">x</span></tt> is the instance of <tt class="xref docutils literal"><span class="pre">MyClass</span></tt> created above, the following piece of
+code will print the value <tt class="docutils literal"><span class="pre">16</span></tt>, without leaving a trace:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="n">x</span><span class="o">.</span><span class="n">counter</span> <span class="o">=</span> <span class="mf">1</span>
+<span class="k">while</span> <span class="n">x</span><span class="o">.</span><span class="n">counter</span> <span class="o">&lt;</span> <span class="mf">10</span><span class="p">:</span>
+ <span class="n">x</span><span class="o">.</span><span class="n">counter</span> <span class="o">=</span> <span class="n">x</span><span class="o">.</span><span class="n">counter</span> <span class="o">*</span> <span class="mf">2</span>
+<span class="k">print</span> <span class="n">x</span><span class="o">.</span><span class="n">counter</span>
+<span class="k">del</span> <span class="n">x</span><span class="o">.</span><span class="n">counter</span>
+</pre></div>
+</div>
+<p>The other kind of instance attribute reference is a <em>method</em>. A method is a
+function that &#8220;belongs to&#8221; an object. (In Python, the term method is not unique
+to class instances: other object types can have methods as well. For example,
+list objects have methods called append, insert, remove, sort, and so on.
+However, in the following discussion, we&#8217;ll use the term method exclusively to
+mean methods of class instance objects, unless explicitly stated otherwise.)</p>
+<p id="index-1057">Valid method names of an instance object depend on its class. By definition,
+all attributes of a class that are function objects define corresponding
+methods of its instances. So in our example, <tt class="docutils literal"><span class="pre">x.f</span></tt> is a valid method
+reference, since <tt class="docutils literal"><span class="pre">MyClass.f</span></tt> is a function, but <tt class="docutils literal"><span class="pre">x.i</span></tt> is not, since
+<tt class="docutils literal"><span class="pre">MyClass.i</span></tt> is not. But <tt class="docutils literal"><span class="pre">x.f</span></tt> is not the same thing as <tt class="docutils literal"><span class="pre">MyClass.f</span></tt> &#8212; it
+is a <em>method object</em>, not a function object.</p>
+</div>
+<div class="section" id="method-objects">
+<span id="tut-methodobjects"></span><h3>9.3.4. Method Objects<a class="headerlink" href="#method-objects" title="Permalink to this headline">¶</a></h3>
+<p>Usually, a method is called right after it is bound:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="n">x</span><span class="o">.</span><span class="n">f</span><span class="p">()</span>
+</pre></div>
+</div>
+<p>In the <tt class="xref docutils literal"><span class="pre">MyClass</span></tt> example, this will return the string <tt class="docutils literal"><span class="pre">'hello</span> <span class="pre">world'</span></tt>.
+However, it is not necessary to call a method right away: <tt class="docutils literal"><span class="pre">x.f</span></tt> is a method
+object, and can be stored away and called at a later time. For example:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="n">xf</span> <span class="o">=</span> <span class="n">x</span><span class="o">.</span><span class="n">f</span>
+<span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
+ <span class="k">print</span> <span class="n">xf</span><span class="p">()</span>
+</pre></div>
+</div>
+<p>will continue to print <tt class="docutils literal"><span class="pre">hello</span> <span class="pre">world</span></tt> until the end of time.</p>
+<p>What exactly happens when a method is called? You may have noticed that
+<tt class="docutils literal"><span class="pre">x.f()</span></tt> was called without an argument above, even though the function
+definition for <tt class="xref docutils literal"><span class="pre">f()</span></tt> specified an argument. What happened to the argument?
+Surely Python raises an exception when a function that requires an argument is
+called without any &#8212; even if the argument isn&#8217;t actually used...</p>
+<p>Actually, you may have guessed the answer: the special thing about methods is
+that the object is passed as the first argument of the function. In our
+example, the call <tt class="docutils literal"><span class="pre">x.f()</span></tt> is exactly equivalent to <tt class="docutils literal"><span class="pre">MyClass.f(x)</span></tt>. In
+general, calling a method with a list of <em>n</em> arguments is equivalent to calling
+the corresponding function with an argument list that is created by inserting
+the method&#8217;s object before the first argument.</p>
+<p>If you still don&#8217;t understand how methods work, a look at the implementation can
+perhaps clarify matters. When an instance attribute is referenced that isn&#8217;t a
+data attribute, its class is searched. If the name denotes a valid class
+attribute that is a function object, a method object is created by packing
+(pointers to) the instance object and the function object just found together in
+an abstract object: this is the method object. When the method object is called
+with an argument list, it is unpacked again, a new argument list is constructed
+from the instance object and the original argument list, and the function object
+is called with this new argument list.</p>
+</div>
+</div>
+<div class="section" id="random-remarks">
+<span id="tut-remarks"></span><h2>9.4. Random Remarks<a class="headerlink" href="#random-remarks" title="Permalink to this headline">¶</a></h2>
+<p>Data attributes override method attributes with the same name; to avoid
+accidental name conflicts, which may cause hard-to-find bugs in large programs,
+it is wise to use some kind of convention that minimizes the chance of
+conflicts. Possible conventions include capitalizing method names, prefixing
+data attribute names with a small unique string (perhaps just an underscore), or
+using verbs for methods and nouns for data attributes.</p>
+<p>Data attributes may be referenced by methods as well as by ordinary users
+(&#8220;clients&#8221;) of an object. In other words, classes are not usable to implement
+pure abstract data types. In fact, nothing in Python makes it possible to
+enforce data hiding &#8212; it is all based upon convention. (On the other hand,
+the Python implementation, written in C, can completely hide implementation
+details and control access to an object if necessary; this can be used by
+extensions to Python written in C.)</p>
+<p>Clients should use data attributes with care &#8212; clients may mess up invariants
+maintained by the methods by stamping on their data attributes. Note that
+clients may add data attributes of their own to an instance object without
+affecting the validity of the methods, as long as name conflicts are avoided &#8212;
+again, a naming convention can save a lot of headaches here.</p>
+<p>There is no shorthand for referencing data attributes (or other methods!) from
+within methods. I find that this actually increases the readability of methods:
+there is no chance of confusing local variables and instance variables when
+glancing through a method.</p>
+<p>Often, the first argument of a method is called <tt class="docutils literal"><span class="pre">self</span></tt>. This is nothing more
+than a convention: the name <tt class="docutils literal"><span class="pre">self</span></tt> has absolutely no special meaning to
+Python. (Note, however, that by not following the convention your code may be
+less readable to other Python programmers, and it is also conceivable that a
+<em>class browser</em> program might be written that relies upon such a convention.)</p>
+<p>Any function object that is a class attribute defines a method for instances of
+that class. It is not necessary that the function definition is textually
+enclosed in the class definition: assigning a function object to a local
+variable in the class is also ok. For example:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="c"># Function defined outside the class</span>
+<span class="k">def</span> <span class="nf">f1</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">):</span>
+ <span class="k">return</span> <span class="nb">min</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">x</span><span class="o">+</span><span class="n">y</span><span class="p">)</span>
+
+<span class="k">class</span> <span class="nc">C</span><span class="p">:</span>
+ <span class="n">f</span> <span class="o">=</span> <span class="n">f1</span>
+ <span class="k">def</span> <span class="nf">g</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+ <span class="k">return</span> <span class="s">&#39;hello world&#39;</span>
+ <span class="n">h</span> <span class="o">=</span> <span class="n">g</span>
+</pre></div>
+</div>
+<p>Now <tt class="docutils literal"><span class="pre">f</span></tt>, <tt class="docutils literal"><span class="pre">g</span></tt> and <tt class="docutils literal"><span class="pre">h</span></tt> are all attributes of class <tt class="xref docutils literal"><span class="pre">C</span></tt> that refer to
+function objects, and consequently they are all methods of instances of
+<tt class="xref docutils literal"><span class="pre">C</span></tt> &#8212; <tt class="docutils literal"><span class="pre">h</span></tt> being exactly equivalent to <tt class="docutils literal"><span class="pre">g</span></tt>. Note that this practice
+usually only serves to confuse the reader of a program.</p>
+<p>Methods may call other methods by using method attributes of the <tt class="docutils literal"><span class="pre">self</span></tt>
+argument:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="k">class</span> <span class="nc">Bag</span><span class="p">:</span>
+ <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+ <span class="bp">self</span><span class="o">.</span><span class="n">data</span> <span class="o">=</span> <span class="p">[]</span>
+ <span class="k">def</span> <span class="nf">add</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x</span><span class="p">):</span>
+ <span class="bp">self</span><span class="o">.</span><span class="n">data</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
+ <span class="k">def</span> <span class="nf">addtwice</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x</span><span class="p">):</span>
+ <span class="bp">self</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
+ <span class="bp">self</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
+</pre></div>
+</div>
+<p>Methods may reference global names in the same way as ordinary functions. The
+global scope associated with a method is the module containing the class
+definition. (The class itself is never used as a global scope!) While one
+rarely encounters a good reason for using global data in a method, there are
+many legitimate uses of the global scope: for one thing, functions and modules
+imported into the global scope can be used by methods, as well as functions and
+classes defined in it. Usually, the class containing the method is itself
+defined in this global scope, and in the next section we&#8217;ll find some good
+reasons why a method would want to reference its own class!</p>
+<p>Each value is an object, and therefore has a <em>class</em> (also called its <em>type</em>).
+It is stored as <tt class="docutils literal"><span class="pre">object.__class__</span></tt>.</p>
+</div>
+<div class="section" id="inheritance">
+<span id="tut-inheritance"></span><h2>9.5. Inheritance<a class="headerlink" href="#inheritance" title="Permalink to this headline">¶</a></h2>
+<p>Of course, a language feature would not be worthy of the name &#8220;class&#8221; without
+supporting inheritance. The syntax for a derived class definition looks like
+this:</p>
+<div class="highlight-python"><pre>class DerivedClassName(BaseClassName):
+ &lt;statement-1&gt;
+ .
+ .
+ .
+ &lt;statement-N&gt;</pre>
+</div>
+<p>The name <tt class="xref docutils literal"><span class="pre">BaseClassName</span></tt> must be defined in a scope containing the
+derived class definition. In place of a base class name, other arbitrary
+expressions are also allowed. This can be useful, for example, when the base
+class is defined in another module:</p>
+<div class="highlight-python"><pre>class DerivedClassName(modname.BaseClassName):</pre>
+</div>
+<p>Execution of a derived class definition proceeds the same as for a base class.
+When the class object is constructed, the base class is remembered. This is
+used for resolving attribute references: if a requested attribute is not found
+in the class, the search proceeds to look in the base class. This rule is
+applied recursively if the base class itself is derived from some other class.</p>
+<p>There&#8217;s nothing special about instantiation of derived classes:
+<tt class="docutils literal"><span class="pre">DerivedClassName()</span></tt> creates a new instance of the class. Method references
+are resolved as follows: the corresponding class attribute is searched,
+descending down the chain of base classes if necessary, and the method reference
+is valid if this yields a function object.</p>
+<p>Derived classes may override methods of their base classes. Because methods
+have no special privileges when calling other methods of the same object, a
+method of a base class that calls another method defined in the same base class
+may end up calling a method of a derived class that overrides it. (For C++
+programmers: all methods in Python are effectively <tt class="docutils literal"><span class="pre">virtual</span></tt>.)</p>
+<p>An overriding method in a derived class may in fact want to extend rather than
+simply replace the base class method of the same name. There is a simple way to
+call the base class method directly: just call <tt class="docutils literal"><span class="pre">BaseClassName.methodname(self,</span>
+<span class="pre">arguments)</span></tt>. This is occasionally useful to clients as well. (Note that this
+only works if the base class is defined or imported directly in the global
+scope.)</p>
+<p>Python has two built-in functions that work with inheritance:</p>
+<ul class="simple">
+<li>Use <a title="isinstance" class="reference external" href="../library/functions.html#isinstance"><tt class="xref docutils literal"><span class="pre">isinstance()</span></tt></a> to check an object&#8217;s type: <tt class="docutils literal"><span class="pre">isinstance(obj,</span> <span class="pre">int)</span></tt>
+will be <tt class="xref docutils literal"><span class="pre">True</span></tt> only if <tt class="docutils literal"><span class="pre">obj.__class__</span></tt> is <a title="int" class="reference external" href="../library/functions.html#int"><tt class="xref docutils literal"><span class="pre">int</span></tt></a> or some class
+derived from <a title="int" class="reference external" href="../library/functions.html#int"><tt class="xref docutils literal"><span class="pre">int</span></tt></a>.</li>
+<li>Use <a title="issubclass" class="reference external" href="../library/functions.html#issubclass"><tt class="xref docutils literal"><span class="pre">issubclass()</span></tt></a> to check class inheritance: <tt class="docutils literal"><span class="pre">issubclass(bool,</span> <span class="pre">int)</span></tt>
+is <tt class="xref docutils literal"><span class="pre">True</span></tt> since <a title="bool" class="reference external" href="../library/functions.html#bool"><tt class="xref docutils literal"><span class="pre">bool</span></tt></a> is a subclass of <a title="int" class="reference external" href="../library/functions.html#int"><tt class="xref docutils literal"><span class="pre">int</span></tt></a>. However,
+<tt class="docutils literal"><span class="pre">issubclass(unicode,</span> <span class="pre">str)</span></tt> is <tt class="xref docutils literal"><span class="pre">False</span></tt> since <a title="unicode" class="reference external" href="../library/functions.html#unicode"><tt class="xref docutils literal"><span class="pre">unicode</span></tt></a> is not a
+subclass of <a title="str" class="reference external" href="../library/functions.html#str"><tt class="xref docutils literal"><span class="pre">str</span></tt></a> (they only share a common ancestor,
+<a title="basestring" class="reference external" href="../library/functions.html#basestring"><tt class="xref docutils literal"><span class="pre">basestring</span></tt></a>).</li>
+</ul>
+<div class="section" id="multiple-inheritance">
+<span id="tut-multiple"></span><h3>9.5.1. Multiple Inheritance<a class="headerlink" href="#multiple-inheritance" title="Permalink to this headline">¶</a></h3>
+<p>Python supports a limited form of multiple inheritance as well. A class
+definition with multiple base classes looks like this:</p>
+<div class="highlight-python"><pre>class DerivedClassName(Base1, Base2, Base3):
+ &lt;statement-1&gt;
+ .
+ .
+ .
+ &lt;statement-N&gt;</pre>
+</div>
+<p>For old-style classes, the only rule is depth-first, left-to-right. Thus, if an
+attribute is not found in <tt class="xref docutils literal"><span class="pre">DerivedClassName</span></tt>, it is searched in
+<tt class="xref docutils literal"><span class="pre">Base1</span></tt>, then (recursively) in the base classes of <tt class="xref docutils literal"><span class="pre">Base1</span></tt>, and
+only if it is not found there, it is searched in <tt class="xref docutils literal"><span class="pre">Base2</span></tt>, and so on.</p>
+<p>(To some people breadth first &#8212; searching <tt class="xref docutils literal"><span class="pre">Base2</span></tt> and <tt class="xref docutils literal"><span class="pre">Base3</span></tt>
+before the base classes of <tt class="xref docutils literal"><span class="pre">Base1</span></tt> &#8212; looks more natural. However, this
+would require you to know whether a particular attribute of <tt class="xref docutils literal"><span class="pre">Base1</span></tt> is
+actually defined in <tt class="xref docutils literal"><span class="pre">Base1</span></tt> or in one of its base classes before you can
+figure out the consequences of a name conflict with an attribute of
+<tt class="xref docutils literal"><span class="pre">Base2</span></tt>. The depth-first rule makes no differences between direct and
+inherited attributes of <tt class="xref docutils literal"><span class="pre">Base1</span></tt>.)</p>
+<p>For <a class="reference external" href="../glossary.html#term-new-style-class"><em class="xref">new-style class</em></a>es, the method resolution order changes dynamically
+to support cooperative calls to <a title="super" class="reference external" href="../library/functions.html#super"><tt class="xref docutils literal"><span class="pre">super()</span></tt></a>. This approach is known in some
+other multiple-inheritance languages as call-next-method and is more powerful
+than the super call found in single-inheritance languages.</p>
+<p>With new-style classes, dynamic ordering is necessary because all cases of
+multiple inheritance exhibit one or more diamond relationships (where one at
+least one of the parent classes can be accessed through multiple paths from the
+bottommost class). For example, all new-style classes inherit from
+<a title="object" class="reference external" href="../library/functions.html#object"><tt class="xref docutils literal"><span class="pre">object</span></tt></a>, so any case of multiple inheritance provides more than one path
+to reach <a title="object" class="reference external" href="../library/functions.html#object"><tt class="xref docutils literal"><span class="pre">object</span></tt></a>. To keep the base classes from being accessed more
+than once, the dynamic algorithm linearizes the search order in a way that
+preserves the left-to-right ordering specified in each class, that calls each
+parent only once, and that is monotonic (meaning that a class can be subclassed
+without affecting the precedence order of its parents). Taken together, these
+properties make it possible to design reliable and extensible classes with
+multiple inheritance. For more detail, see
+<a class="reference external" href="http://www.python.org/download/releases/2.3/mro/">http://www.python.org/download/releases/2.3/mro/</a>.</p>
+</div>
+</div>
+<div class="section" id="private-variables">
+<span id="tut-private"></span><h2>9.6. Private Variables<a class="headerlink" href="#private-variables" title="Permalink to this headline">¶</a></h2>
+<p>There is limited support for class-private identifiers. Any identifier of the
+form <tt class="docutils literal"><span class="pre">__spam</span></tt> (at least two leading underscores, at most one trailing
+underscore) is textually replaced with <tt class="docutils literal"><span class="pre">_classname__spam</span></tt>, where <tt class="docutils literal"><span class="pre">classname</span></tt>
+is the current class name with leading underscore(s) stripped. This mangling is
+done without regard to the syntactic position of the identifier, so it can be
+used to define class-private instance and class variables, methods, variables
+stored in globals, and even variables stored in instances. private to this class
+on instances of <em>other</em> classes. Truncation may occur when the mangled name
+would be longer than 255 characters. Outside classes, or when the class name
+consists of only underscores, no mangling occurs.</p>
+<p>Name mangling is intended to give classes an easy way to define &#8220;private&#8221;
+instance variables and methods, without having to worry about instance variables
+defined by derived classes, or mucking with instance variables by code outside
+the class. Note that the mangling rules are designed mostly to avoid accidents;
+it still is possible for a determined soul to access or modify a variable that
+is considered private. This can even be useful in special circumstances, such
+as in the debugger, and that&#8217;s one reason why this loophole is not closed.
+(Buglet: derivation of a class with the same name as the base class makes use of
+private variables of the base class possible.)</p>
+<p>Notice that code passed to <tt class="docutils literal"><span class="pre">exec</span></tt>, <tt class="docutils literal"><span class="pre">eval()</span></tt> or <tt class="docutils literal"><span class="pre">execfile()</span></tt> does not
+consider the classname of the invoking class to be the current class; this is
+similar to the effect of the <tt class="docutils literal"><span class="pre">global</span></tt> statement, the effect of which is
+likewise restricted to code that is byte-compiled together. The same
+restriction applies to <tt class="docutils literal"><span class="pre">getattr()</span></tt>, <tt class="docutils literal"><span class="pre">setattr()</span></tt> and <tt class="docutils literal"><span class="pre">delattr()</span></tt>, as well
+as when referencing <tt class="docutils literal"><span class="pre">__dict__</span></tt> directly.</p>
+</div>
+<div class="section" id="odds-and-ends">
+<span id="tut-odds"></span><h2>9.7. Odds and Ends<a class="headerlink" href="#odds-and-ends" title="Permalink to this headline">¶</a></h2>
+<p>Sometimes it is useful to have a data type similar to the Pascal &#8220;record&#8221; or C
+&#8220;struct&#8221;, bundling together a few named data items. An empty class definition
+will do nicely:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="k">class</span> <span class="nc">Employee</span><span class="p">:</span>
+ <span class="k">pass</span>
+
+<span class="n">john</span> <span class="o">=</span> <span class="n">Employee</span><span class="p">()</span> <span class="c"># Create an empty employee record</span>
+
+<span class="c"># Fill the fields of the record</span>
+<span class="n">john</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="s">&#39;John Doe&#39;</span>
+<span class="n">john</span><span class="o">.</span><span class="n">dept</span> <span class="o">=</span> <span class="s">&#39;computer lab&#39;</span>
+<span class="n">john</span><span class="o">.</span><span class="n">salary</span> <span class="o">=</span> <span class="mf">1000</span>
+</pre></div>
+</div>
+<p>A piece of Python code that expects a particular abstract data type can often be
+passed a class that emulates the methods of that data type instead. For
+instance, if you have a function that formats some data from a file object, you
+can define a class with methods <tt class="xref docutils literal"><span class="pre">read()</span></tt> and <tt class="xref docutils literal"><span class="pre">readline()</span></tt> that get the
+data from a string buffer instead, and pass it as an argument.</p>
+<p>Instance method objects have attributes, too: <tt class="docutils literal"><span class="pre">m.im_self</span></tt> is the instance
+object with the method <tt class="xref docutils literal"><span class="pre">m()</span></tt>, and <tt class="docutils literal"><span class="pre">m.im_func</span></tt> is the function object
+corresponding to the method.</p>
+</div>
+<div class="section" id="exceptions-are-classes-too">
+<span id="tut-exceptionclasses"></span><h2>9.8. Exceptions Are Classes Too<a class="headerlink" href="#exceptions-are-classes-too" title="Permalink to this headline">¶</a></h2>
+<p>User-defined exceptions are identified by classes as well. Using this mechanism
+it is possible to create extensible hierarchies of exceptions.</p>
+<p>There are two new valid (semantic) forms for the raise statement:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="k">raise</span> <span class="n">Class</span><span class="p">,</span> <span class="n">instance</span>
+
+<span class="k">raise</span> <span class="n">instance</span>
+</pre></div>
+</div>
+<p>In the first form, <tt class="docutils literal"><span class="pre">instance</span></tt> must be an instance of <tt class="xref docutils literal"><span class="pre">Class</span></tt> or of a
+class derived from it. The second form is a shorthand for:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="k">raise</span> <span class="n">instance</span><span class="o">.</span><span class="n">__class__</span><span class="p">,</span> <span class="n">instance</span>
+</pre></div>
+</div>
+<p>A class in an except clause is compatible with an exception if it is the same
+class or a base class thereof (but not the other way around &#8212; an except clause
+listing a derived class is not compatible with a base class). For example, the
+following code will print B, C, D in that order:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="k">class</span> <span class="nc">B</span><span class="p">:</span>
+ <span class="k">pass</span>
+<span class="k">class</span> <span class="nc">C</span><span class="p">(</span><span class="n">B</span><span class="p">):</span>
+ <span class="k">pass</span>
+<span class="k">class</span> <span class="nc">D</span><span class="p">(</span><span class="n">C</span><span class="p">):</span>
+ <span class="k">pass</span>
+
+<span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="p">[</span><span class="n">B</span><span class="p">,</span> <span class="n">C</span><span class="p">,</span> <span class="n">D</span><span class="p">]:</span>
+ <span class="k">try</span><span class="p">:</span>
+ <span class="k">raise</span> <span class="n">c</span><span class="p">()</span>
+ <span class="k">except</span> <span class="n">D</span><span class="p">:</span>
+ <span class="k">print</span> <span class="s">&quot;D&quot;</span>
+ <span class="k">except</span> <span class="n">C</span><span class="p">:</span>
+ <span class="k">print</span> <span class="s">&quot;C&quot;</span>
+ <span class="k">except</span> <span class="n">B</span><span class="p">:</span>
+ <span class="k">print</span> <span class="s">&quot;B&quot;</span>
+</pre></div>
+</div>
+<p>Note that if the except clauses were reversed (with <tt class="docutils literal"><span class="pre">except</span> <span class="pre">B</span></tt> first), it
+would have printed B, B, B &#8212; the first matching except clause is triggered.</p>
+<p>When an error message is printed for an unhandled exception, the exception&#8217;s
+class name is printed, then a colon and a space, and finally the instance
+converted to a string using the built-in function <a title="str" class="reference external" href="../library/functions.html#str"><tt class="xref docutils literal"><span class="pre">str()</span></tt></a>.</p>
+</div>
+<div class="section" id="iterators">
+<span id="tut-iterators"></span><h2>9.9. Iterators<a class="headerlink" href="#iterators" title="Permalink to this headline">¶</a></h2>
+<p>By now you have probably noticed that most container objects can be looped over
+using a <a class="reference external" href="../reference/compound_stmts.html#for"><tt class="xref docutils literal"><span class="pre">for</span></tt></a> statement:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="k">for</span> <span class="n">element</span> <span class="ow">in</span> <span class="p">[</span><span class="mf">1</span><span class="p">,</span> <span class="mf">2</span><span class="p">,</span> <span class="mf">3</span><span class="p">]:</span>
+ <span class="k">print</span> <span class="n">element</span>
+<span class="k">for</span> <span class="n">element</span> <span class="ow">in</span> <span class="p">(</span><span class="mf">1</span><span class="p">,</span> <span class="mf">2</span><span class="p">,</span> <span class="mf">3</span><span class="p">):</span>
+ <span class="k">print</span> <span class="n">element</span>
+<span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="p">{</span><span class="s">&#39;one&#39;</span><span class="p">:</span><span class="mf">1</span><span class="p">,</span> <span class="s">&#39;two&#39;</span><span class="p">:</span><span class="mf">2</span><span class="p">}:</span>
+ <span class="k">print</span> <span class="n">key</span>
+<span class="k">for</span> <span class="n">char</span> <span class="ow">in</span> <span class="s">&quot;123&quot;</span><span class="p">:</span>
+ <span class="k">print</span> <span class="n">char</span>
+<span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="nb">open</span><span class="p">(</span><span class="s">&quot;myfile.txt&quot;</span><span class="p">):</span>
+ <span class="k">print</span> <span class="n">line</span>
+</pre></div>
+</div>
+<p>This style of access is clear, concise, and convenient. The use of iterators
+pervades and unifies Python. Behind the scenes, the <a class="reference external" href="../reference/compound_stmts.html#for"><tt class="xref docutils literal"><span class="pre">for</span></tt></a> statement
+calls <a title="iter" class="reference external" href="../library/functions.html#iter"><tt class="xref docutils literal"><span class="pre">iter()</span></tt></a> on the container object. The function returns an iterator
+object that defines the method <a title="next" class="reference external" href="../library/functions.html#next"><tt class="xref docutils literal"><span class="pre">next()</span></tt></a> which accesses elements in the
+container one at a time. When there are no more elements, <a title="next" class="reference external" href="../library/functions.html#next"><tt class="xref docutils literal"><span class="pre">next()</span></tt></a> raises a
+<a title="exceptions.StopIteration" class="reference external" href="../library/exceptions.html#exceptions.StopIteration"><tt class="xref docutils literal"><span class="pre">StopIteration</span></tt></a> exception which tells the <a class="reference external" href="../reference/compound_stmts.html#for"><tt class="xref docutils literal"><span class="pre">for</span></tt></a> loop to terminate.
+This example shows how it all works:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">s</span> <span class="o">=</span> <span class="s">&#39;abc&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">it</span> <span class="o">=</span> <span class="nb">iter</span><span class="p">(</span><span class="n">s</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">it</span>
+<span class="go">&lt;iterator object at 0x00A1DB50&gt;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">it</span><span class="o">.</span><span class="n">next</span><span class="p">()</span>
+<span class="go">&#39;a&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">it</span><span class="o">.</span><span class="n">next</span><span class="p">()</span>
+<span class="go">&#39;b&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">it</span><span class="o">.</span><span class="n">next</span><span class="p">()</span>
+<span class="go">&#39;c&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">it</span><span class="o">.</span><span class="n">next</span><span class="p">()</span>
+
+<span class="gt">Traceback (most recent call last):</span>
+ File <span class="nb">&quot;&lt;stdin&gt;&quot;</span>, line <span class="m">1</span>, in <span class="n-Identifier">?</span>
+ <span class="n">it</span><span class="o">.</span><span class="n">next</span><span class="p">()</span>
+<span class="nc">StopIteration</span>
+</pre></div>
+</div>
+<p>Having seen the mechanics behind the iterator protocol, it is easy to add
+iterator behavior to your classes. Define a <a title="object.__iter__" class="reference external" href="../reference/datamodel.html#object.__iter__"><tt class="xref docutils literal"><span class="pre">__iter__()</span></tt></a> method which
+returns an object with a <a title="next" class="reference external" href="../library/functions.html#next"><tt class="xref docutils literal"><span class="pre">next()</span></tt></a> method. If the class defines
+<a title="next" class="reference external" href="../library/functions.html#next"><tt class="xref docutils literal"><span class="pre">next()</span></tt></a>, then <a title="object.__iter__" class="reference external" href="../reference/datamodel.html#object.__iter__"><tt class="xref docutils literal"><span class="pre">__iter__()</span></tt></a> can just return <tt class="docutils literal"><span class="pre">self</span></tt>:</p>
+<div class="highlight-python"><pre>class Reverse:
+ "Iterator for looping over a sequence backwards"
+ def __init__(self, data):
+ self.data = data
+ self.index = len(data)
+ def __iter__(self):
+ return self
+ def next(self):
+ if self.index == 0:
+ raise StopIteration
+ self.index = self.index - 1
+ return self.data[self.index]
+
+&gt;&gt;&gt; for char in Reverse('spam'):
+... print char
+...
+m
+a
+p
+s</pre>
+</div>
+</div>
+<div class="section" id="generators">
+<span id="tut-generators"></span><h2>9.10. Generators<a class="headerlink" href="#generators" title="Permalink to this headline">¶</a></h2>
+<p><a class="reference external" href="../glossary.html#term-generator"><em class="xref">Generator</em></a>s are a simple and powerful tool for creating iterators. They
+are written like regular functions but use the <a class="reference external" href="../reference/simple_stmts.html#yield"><tt class="xref docutils literal"><span class="pre">yield</span></tt></a> statement
+whenever they want to return data. Each time <a title="next" class="reference external" href="../library/functions.html#next"><tt class="xref docutils literal"><span class="pre">next()</span></tt></a> is called, the
+generator resumes where it left-off (it remembers all the data values and which
+statement was last executed). An example shows that generators can be trivially
+easy to create:</p>
+<div class="highlight-python"><pre>def reverse(data):
+ for index in range(len(data)-1, -1, -1):
+ yield data[index]
+
+&gt;&gt;&gt; for char in reverse('golf'):
+... print char
+...
+f
+l
+o
+g</pre>
+</div>
+<p>Anything that can be done with generators can also be done with class based
+iterators as described in the previous section. What makes generators so
+compact is that the <a title="object.__iter__" class="reference external" href="../reference/datamodel.html#object.__iter__"><tt class="xref docutils literal"><span class="pre">__iter__()</span></tt></a> and <a title="next" class="reference external" href="../library/functions.html#next"><tt class="xref docutils literal"><span class="pre">next()</span></tt></a> methods are created
+automatically.</p>
+<p>Another key feature is that the local variables and execution state are
+automatically saved between calls. This made the function easier to write and
+much more clear than an approach using instance variables like <tt class="docutils literal"><span class="pre">self.index</span></tt>
+and <tt class="docutils literal"><span class="pre">self.data</span></tt>.</p>
+<p>In addition to automatic method creation and saving program state, when
+generators terminate, they automatically raise <a title="exceptions.StopIteration" class="reference external" href="../library/exceptions.html#exceptions.StopIteration"><tt class="xref docutils literal"><span class="pre">StopIteration</span></tt></a>. In
+combination, these features make it easy to create iterators with no more effort
+than writing a regular function.</p>
+</div>
+<div class="section" id="generator-expressions">
+<span id="tut-genexps"></span><h2>9.11. Generator Expressions<a class="headerlink" href="#generator-expressions" title="Permalink to this headline">¶</a></h2>
+<p>Some simple generators can be coded succinctly as expressions using a syntax
+similar to list comprehensions but with parentheses instead of brackets. These
+expressions are designed for situations where the generator is used right away
+by an enclosing function. Generator expressions are more compact but less
+versatile than full generator definitions and tend to be more memory friendly
+than equivalent list comprehensions.</p>
+<p>Examples:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="nb">sum</span><span class="p">(</span><span class="n">i</span><span class="o">*</span><span class="n">i</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mf">10</span><span class="p">))</span> <span class="c"># sum of squares</span>
+<span class="go">285</span>
+
+<span class="gp">&gt;&gt;&gt; </span><span class="n">xvec</span> <span class="o">=</span> <span class="p">[</span><span class="mf">10</span><span class="p">,</span> <span class="mf">20</span><span class="p">,</span> <span class="mf">30</span><span class="p">]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">yvec</span> <span class="o">=</span> <span class="p">[</span><span class="mf">7</span><span class="p">,</span> <span class="mf">5</span><span class="p">,</span> <span class="mf">3</span><span class="p">]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">sum</span><span class="p">(</span><span class="n">x</span><span class="o">*</span><span class="n">y</span> <span class="k">for</span> <span class="n">x</span><span class="p">,</span><span class="n">y</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">xvec</span><span class="p">,</span> <span class="n">yvec</span><span class="p">))</span> <span class="c"># dot product</span>
+<span class="go">260</span>
+
+<span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">math</span> <span class="kn">import</span> <span class="n">pi</span><span class="p">,</span> <span class="n">sin</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">sine_table</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">((</span><span class="n">x</span><span class="p">,</span> <span class="n">sin</span><span class="p">(</span><span class="n">x</span><span class="o">*</span><span class="n">pi</span><span class="o">/</span><span class="mf">180</span><span class="p">))</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mf">0</span><span class="p">,</span> <span class="mf">91</span><span class="p">))</span>
+
+<span class="gp">&gt;&gt;&gt; </span><span class="n">unique_words</span> <span class="o">=</span> <span class="n">set</span><span class="p">(</span><span class="n">word</span> <span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">page</span> <span class="k">for</span> <span class="n">word</span> <span class="ow">in</span> <span class="n">line</span><span class="o">.</span><span class="n">split</span><span class="p">())</span>
+
+<span class="gp">&gt;&gt;&gt; </span><span class="n">valedictorian</span> <span class="o">=</span> <span class="nb">max</span><span class="p">((</span><span class="n">student</span><span class="o">.</span><span class="n">gpa</span><span class="p">,</span> <span class="n">student</span><span class="o">.</span><span class="n">name</span><span class="p">)</span> <span class="k">for</span> <span class="n">student</span> <span class="ow">in</span> <span class="n">graduates</span><span class="p">)</span>
+
+<span class="gp">&gt;&gt;&gt; </span><span class="n">data</span> <span class="o">=</span> <span class="s">&#39;golf&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">list</span><span class="p">(</span><span class="n">data</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">data</span><span class="p">)</span><span class="o">-</span><span class="mf">1</span><span class="p">,</span><span class="o">-</span><span class="mf">1</span><span class="p">,</span><span class="o">-</span><span class="mf">1</span><span class="p">))</span>
+<span class="go">[&#39;f&#39;, &#39;l&#39;, &#39;o&#39;, &#39;g&#39;]</span>
+</pre></div>
+</div>
+<p class="rubric">Footnotes</p>
+<table class="docutils footnote" frame="void" id="id2" rules="none">
+<colgroup><col class="label" /><col /></colgroup>
+<tbody valign="top">
+<tr><td class="label"><a class="fn-backref" href="#id1">[1]</a></td><td>Except for one thing. Module objects have a secret read-only attribute called
+<tt class="xref docutils literal"><span class="pre">__dict__</span></tt> which returns the dictionary used to implement the module&#8217;s
+namespace; the name <tt class="xref docutils literal"><span class="pre">__dict__</span></tt> is an attribute but not a global name.
+Obviously, using this violates the abstraction of namespace implementation, and
+should be restricted to things like post-mortem debuggers.</td></tr>
+</tbody>
+</table>
+</div>
+</div>
+
+
+ </div>
+ </div>
+ </div>
+ <div class="sphinxsidebar">
+ <div class="sphinxsidebarwrapper">
+ <h3><a href="../contents.html">Table Of Contents</a></h3>
+ <ul>
+<li><a class="reference external" href="">9. Classes</a><ul>
+<li><a class="reference external" href="#a-word-about-terminology">9.1. A Word About Terminology</a></li>
+<li><a class="reference external" href="#python-scopes-and-name-spaces">9.2. Python Scopes and Name Spaces</a></li>
+<li><a class="reference external" href="#a-first-look-at-classes">9.3. A First Look at Classes</a><ul>
+<li><a class="reference external" href="#class-definition-syntax">9.3.1. Class Definition Syntax</a></li>
+<li><a class="reference external" href="#class-objects">9.3.2. Class Objects</a></li>
+<li><a class="reference external" href="#instance-objects">9.3.3. Instance Objects</a></li>
+<li><a class="reference external" href="#method-objects">9.3.4. Method Objects</a></li>
+</ul>
+</li>
+<li><a class="reference external" href="#random-remarks">9.4. Random Remarks</a></li>
+<li><a class="reference external" href="#inheritance">9.5. Inheritance</a><ul>
+<li><a class="reference external" href="#multiple-inheritance">9.5.1. Multiple Inheritance</a></li>
+</ul>
+</li>
+<li><a class="reference external" href="#private-variables">9.6. Private Variables</a></li>
+<li><a class="reference external" href="#odds-and-ends">9.7. Odds and Ends</a></li>
+<li><a class="reference external" href="#exceptions-are-classes-too">9.8. Exceptions Are Classes Too</a></li>
+<li><a class="reference external" href="#iterators">9.9. Iterators</a></li>
+<li><a class="reference external" href="#generators">9.10. Generators</a></li>
+<li><a class="reference external" href="#generator-expressions">9.11. Generator Expressions</a></li>
+</ul>
+</li>
+</ul>
+
+ <h4>Previous topic</h4>
+ <p class="topless"><a href="errors.html"
+ title="previous chapter">8. Errors and Exceptions</a></p>
+ <h4>Next topic</h4>
+ <p class="topless"><a href="stdlib.html"
+ title="next chapter">10. Brief Tour of the Standard Library</a></p>
+ <h3>This Page</h3>
+ <ul class="this-page-menu">
+ <li><a href="../_sources/tutorial/classes.txt"
+ rel="nofollow">Show Source</a></li>
+ </ul>
+ <div id="searchbox" style="display: none">
+ <h3>Quick search</h3>
+ <form class="search" action="../search.html" method="get">
+ <input type="text" name="q" size="18" />
+ <input type="submit" value="Go" />
+ <input type="hidden" name="check_keywords" value="yes" />
+ <input type="hidden" name="area" value="default" />
+ </form>
+ <p class="searchtip" style="font-size: 90%">
+ Enter search terms or a module, class or function name.
+ </p>
+ </div>
+ <script type="text/javascript">$('#searchbox').show(0);</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../genindex.html" title="General Index"
+ >index</a></li>
+ <li class="right" >
+ <a href="../modindex.html" title="Global Module Index"
+ >modules</a> |</li>
+ <li class="right" >
+ <a href="stdlib.html" title="10. Brief Tour of the Standard Library"
+ >next</a> |</li>
+ <li class="right" >
+ <a href="errors.html" title="8. Errors and Exceptions"
+ >previous</a> |</li>
+ <li><img src="../_static/py.png" alt=""
+ style="vertical-align: middle; margin-top: -1px"/></li>
+ <li><a href="../index.html">Python v2.6.4c2 documentation</a> &raquo;</li>
+
+ <li><a href="index.html" >The Python Tutorial</a> &raquo;</li>
+ </ul>
+ </div>
+ <div class="footer">
+ &copy; <a href="../copyright.html">Copyright</a> 1990-2009, Python Software Foundation.
+ <br />
+ The Python Software Foundation is a non-profit corporation.
+ <a href="http://www.python.org/psf/donations/">Please donate.</a>
+ <br />
+ Last updated on Oct 19, 2009.
+ Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 0.6.2.
+ </div>
+
+ </body>
+</html> \ No newline at end of file
diff --git a/help/PythonTutorial/tutorial/controlflow.html b/help/PythonTutorial/tutorial/controlflow.html
new file mode 100644
index 0000000..1ece9b8
--- /dev/null
+++ b/help/PythonTutorial/tutorial/controlflow.html
@@ -0,0 +1,695 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+ <title>4. More Control Flow Tools &mdash; Python v2.6.4c2 documentation</title>
+ <link rel="stylesheet" href="../_static/default.css" type="text/css" />
+ <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
+ <script type="text/javascript">
+ var DOCUMENTATION_OPTIONS = {
+ URL_ROOT: '../',
+ VERSION: '2.6.4c2',
+ COLLAPSE_MODINDEX: false,
+ FILE_SUFFIX: '.html',
+ HAS_SOURCE: true
+ };
+ </script>
+ <script type="text/javascript" src="../_static/jquery.js"></script>
+ <script type="text/javascript" src="../_static/doctools.js"></script>
+ <link rel="search" type="application/opensearchdescription+xml"
+ title="Search within Python v2.6.4c2 documentation"
+ href="../_static/opensearch.xml"/>
+ <link rel="author" title="About these documents" href="../about.html" />
+ <link rel="copyright" title="Copyright" href="../copyright.html" />
+ <link rel="top" title="Python v2.6.4c2 documentation" href="../index.html" />
+ <link rel="up" title="The Python Tutorial" href="index.html" />
+ <link rel="next" title="5. Data Structures" href="datastructures.html" />
+ <link rel="prev" title="3. An Informal Introduction to Python" href="introduction.html" />
+ <link rel="shortcut icon" type="image/png" href="../_static/py.png" />
+
+
+ </head>
+ <body>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../modindex.html" title="Global Module Index"
+ accesskey="M">modules</a> |</li>
+ <li class="right" >
+ <a href="datastructures.html" title="5. Data Structures"
+ accesskey="N">next</a> |</li>
+ <li class="right" >
+ <a href="introduction.html" title="3. An Informal Introduction to Python"
+ accesskey="P">previous</a> |</li>
+ <li><img src="../_static/py.png" alt=""
+ style="vertical-align: middle; margin-top: -1px"/></li>
+ <li><a href="../index.html">Python v2.6.4c2 documentation</a> &raquo;</li>
+
+ <li><a href="index.html" accesskey="U">The Python Tutorial</a> &raquo;</li>
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body">
+
+ <div class="section" id="more-control-flow-tools">
+<span id="tut-morecontrol"></span><h1>4. More Control Flow Tools<a class="headerlink" href="#more-control-flow-tools" title="Permalink to this headline">¶</a></h1>
+<p>Besides the <a class="reference external" href="../reference/compound_stmts.html#while"><tt class="xref docutils literal"><span class="pre">while</span></tt></a> statement just introduced, Python knows the usual
+control flow statements known from other languages, with some twists.</p>
+<div class="section" id="if-statements">
+<span id="tut-if"></span><h2>4.1. <a class="reference external" href="../reference/compound_stmts.html#if"><tt class="xref docutils literal"><span class="pre">if</span></tt></a> Statements<a class="headerlink" href="#if-statements" title="Permalink to this headline">¶</a></h2>
+<p>Perhaps the most well-known statement type is the <a class="reference external" href="../reference/compound_stmts.html#if"><tt class="xref docutils literal"><span class="pre">if</span></tt></a> statement. For
+example:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">x</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="nb">raw_input</span><span class="p">(</span><span class="s">&quot;Please enter an integer: &quot;</span><span class="p">))</span>
+<span class="go">Please enter an integer: 42</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">if</span> <span class="n">x</span> <span class="o">&lt;</span> <span class="mf">0</span><span class="p">:</span>
+<span class="gp">... </span> <span class="n">x</span> <span class="o">=</span> <span class="mf">0</span>
+<span class="gp">... </span> <span class="k">print</span> <span class="s">&#39;Negative changed to zero&#39;</span>
+<span class="gp">... </span><span class="k">elif</span> <span class="n">x</span> <span class="o">==</span> <span class="mf">0</span><span class="p">:</span>
+<span class="gp">... </span> <span class="k">print</span> <span class="s">&#39;Zero&#39;</span>
+<span class="gp">... </span><span class="k">elif</span> <span class="n">x</span> <span class="o">==</span> <span class="mf">1</span><span class="p">:</span>
+<span class="gp">... </span> <span class="k">print</span> <span class="s">&#39;Single&#39;</span>
+<span class="gp">... </span><span class="k">else</span><span class="p">:</span>
+<span class="gp">... </span> <span class="k">print</span> <span class="s">&#39;More&#39;</span>
+<span class="gp">...</span>
+<span class="go">More</span>
+</pre></div>
+</div>
+<p>There can be zero or more <a class="reference external" href="../reference/compound_stmts.html#elif"><tt class="xref docutils literal"><span class="pre">elif</span></tt></a> parts, and the <a class="reference external" href="../reference/compound_stmts.html#else"><tt class="xref docutils literal"><span class="pre">else</span></tt></a> part is
+optional. The keyword &#8216;<a class="reference external" href="../reference/compound_stmts.html#elif"><tt class="xref docutils literal"><span class="pre">elif</span></tt></a>&#8216; is short for &#8216;else if&#8217;, and is useful
+to avoid excessive indentation. An <a class="reference external" href="../reference/compound_stmts.html#if"><tt class="xref docutils literal"><span class="pre">if</span></tt></a> ... <a class="reference external" href="../reference/compound_stmts.html#elif"><tt class="xref docutils literal"><span class="pre">elif</span></tt></a> ...
+<a class="reference external" href="../reference/compound_stmts.html#elif"><tt class="xref docutils literal"><span class="pre">elif</span></tt></a> ... sequence is a substitute for the <tt class="docutils literal"><span class="pre">switch</span></tt> or
+<tt class="docutils literal"><span class="pre">case</span></tt> statements found in other languages.</p>
+</div>
+<div class="section" id="for-statements">
+<span id="tut-for"></span><h2>4.2. <a class="reference external" href="../reference/compound_stmts.html#for"><tt class="xref docutils literal"><span class="pre">for</span></tt></a> Statements<a class="headerlink" href="#for-statements" title="Permalink to this headline">¶</a></h2>
+<p id="index-1058">The <a class="reference external" href="../reference/compound_stmts.html#for"><tt class="xref docutils literal"><span class="pre">for</span></tt></a> statement in Python differs a bit from what you may be used
+to in C or Pascal. Rather than always iterating over an arithmetic progression
+of numbers (like in Pascal), or giving the user the ability to define both the
+iteration step and halting condition (as C), Python&#8217;s <a class="reference external" href="../reference/compound_stmts.html#for"><tt class="xref docutils literal"><span class="pre">for</span></tt></a> statement
+iterates over the items of any sequence (a list or a string), in the order that
+they appear in the sequence. For example (no pun intended):</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="c"># Measure some strings:</span>
+<span class="gp">... </span><span class="n">a</span> <span class="o">=</span> <span class="p">[</span><span class="s">&#39;cat&#39;</span><span class="p">,</span> <span class="s">&#39;window&#39;</span><span class="p">,</span> <span class="s">&#39;defenestrate&#39;</span><span class="p">]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">a</span><span class="p">:</span>
+<span class="gp">... </span> <span class="k">print</span> <span class="n">x</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
+<span class="gp">...</span>
+<span class="go">cat 3</span>
+<span class="go">window 6</span>
+<span class="go">defenestrate 12</span>
+</pre></div>
+</div>
+<p>It is not safe to modify the sequence being iterated over in the loop (this can
+only happen for mutable sequence types, such as lists). If you need to modify
+the list you are iterating over (for example, to duplicate selected items) you
+must iterate over a copy. The slice notation makes this particularly
+convenient:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">a</span><span class="p">[:]:</span> <span class="c"># make a slice copy of the entire list</span>
+<span class="gp">... </span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mf">6</span><span class="p">:</span> <span class="n">a</span><span class="o">.</span><span class="n">insert</span><span class="p">(</span><span class="mf">0</span><span class="p">,</span> <span class="n">x</span><span class="p">)</span>
+<span class="gp">...</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">a</span>
+<span class="go">[&#39;defenestrate&#39;, &#39;cat&#39;, &#39;window&#39;, &#39;defenestrate&#39;]</span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="the-range-function">
+<span id="tut-range"></span><h2>4.3. The <a title="range" class="reference external" href="../library/functions.html#range"><tt class="xref docutils literal"><span class="pre">range()</span></tt></a> Function<a class="headerlink" href="#the-range-function" title="Permalink to this headline">¶</a></h2>
+<p>If you do need to iterate over a sequence of numbers, the built-in function
+<a title="range" class="reference external" href="../library/functions.html#range"><tt class="xref docutils literal"><span class="pre">range()</span></tt></a> comes in handy. It generates lists containing arithmetic
+progressions:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="nb">range</span><span class="p">(</span><span class="mf">10</span><span class="p">)</span>
+<span class="go">[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]</span>
+</pre></div>
+</div>
+<p>The given end point is never part of the generated list; <tt class="docutils literal"><span class="pre">range(10)</span></tt> generates
+a list of 10 values, the legal indices for items of a sequence of length 10. It
+is possible to let the range start at another number, or to specify a different
+increment (even negative; sometimes this is called the &#8216;step&#8217;):</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="nb">range</span><span class="p">(</span><span class="mf">5</span><span class="p">,</span> <span class="mf">10</span><span class="p">)</span>
+<span class="go">[5, 6, 7, 8, 9]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">range</span><span class="p">(</span><span class="mf">0</span><span class="p">,</span> <span class="mf">10</span><span class="p">,</span> <span class="mf">3</span><span class="p">)</span>
+<span class="go">[0, 3, 6, 9]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">range</span><span class="p">(</span><span class="o">-</span><span class="mf">10</span><span class="p">,</span> <span class="o">-</span><span class="mf">100</span><span class="p">,</span> <span class="o">-</span><span class="mf">30</span><span class="p">)</span>
+<span class="go">[-10, -40, -70]</span>
+</pre></div>
+</div>
+<p>To iterate over the indices of a sequence, you can combine <a title="range" class="reference external" href="../library/functions.html#range"><tt class="xref docutils literal"><span class="pre">range()</span></tt></a> and
+<a title="len" class="reference external" href="../library/functions.html#len"><tt class="xref docutils literal"><span class="pre">len()</span></tt></a> as follows:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">a</span> <span class="o">=</span> <span class="p">[</span><span class="s">&#39;Mary&#39;</span><span class="p">,</span> <span class="s">&#39;had&#39;</span><span class="p">,</span> <span class="s">&#39;a&#39;</span><span class="p">,</span> <span class="s">&#39;little&#39;</span><span class="p">,</span> <span class="s">&#39;lamb&#39;</span><span class="p">]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">a</span><span class="p">)):</span>
+<span class="gp">... </span> <span class="k">print</span> <span class="n">i</span><span class="p">,</span> <span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">]</span>
+<span class="gp">...</span>
+<span class="go">0 Mary</span>
+<span class="go">1 had</span>
+<span class="go">2 a</span>
+<span class="go">3 little</span>
+<span class="go">4 lamb</span>
+</pre></div>
+</div>
+<p>In most such cases, however, it is convenient to use the <a title="enumerate" class="reference external" href="../library/functions.html#enumerate"><tt class="xref docutils literal"><span class="pre">enumerate()</span></tt></a>
+function, see <a class="reference external" href="datastructures.html#tut-loopidioms"><em>Looping Techniques</em></a>.</p>
+</div>
+<div class="section" id="break-and-continue-statements-and-else-clauses-on-loops">
+<span id="tut-break"></span><h2>4.4. <a class="reference external" href="../reference/simple_stmts.html#break"><tt class="xref docutils literal"><span class="pre">break</span></tt></a> and <a class="reference external" href="../reference/simple_stmts.html#continue"><tt class="xref docutils literal"><span class="pre">continue</span></tt></a> Statements, and <a class="reference external" href="../reference/compound_stmts.html#else"><tt class="xref docutils literal"><span class="pre">else</span></tt></a> Clauses on Loops<a class="headerlink" href="#break-and-continue-statements-and-else-clauses-on-loops" title="Permalink to this headline">¶</a></h2>
+<p>The <a class="reference external" href="../reference/simple_stmts.html#break"><tt class="xref docutils literal"><span class="pre">break</span></tt></a> statement, like in C, breaks out of the smallest enclosing
+<a class="reference external" href="../reference/compound_stmts.html#for"><tt class="xref docutils literal"><span class="pre">for</span></tt></a> or <a class="reference external" href="../reference/compound_stmts.html#while"><tt class="xref docutils literal"><span class="pre">while</span></tt></a> loop.</p>
+<p>The <a class="reference external" href="../reference/simple_stmts.html#continue"><tt class="xref docutils literal"><span class="pre">continue</span></tt></a> statement, also borrowed from C, continues with the next
+iteration of the loop.</p>
+<p>Loop statements may have an <tt class="docutils literal"><span class="pre">else</span></tt> clause; it is executed when the loop
+terminates through exhaustion of the list (with <a class="reference external" href="../reference/compound_stmts.html#for"><tt class="xref docutils literal"><span class="pre">for</span></tt></a>) or when the
+condition becomes false (with <a class="reference external" href="../reference/compound_stmts.html#while"><tt class="xref docutils literal"><span class="pre">while</span></tt></a>), but not when the loop is
+terminated by a <a class="reference external" href="../reference/simple_stmts.html#break"><tt class="xref docutils literal"><span class="pre">break</span></tt></a> statement. This is exemplified by the
+following loop, which searches for prime numbers:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mf">2</span><span class="p">,</span> <span class="mf">10</span><span class="p">):</span>
+<span class="gp">... </span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mf">2</span><span class="p">,</span> <span class="n">n</span><span class="p">):</span>
+<span class="gp">... </span> <span class="k">if</span> <span class="n">n</span> <span class="o">%</span> <span class="n">x</span> <span class="o">==</span> <span class="mf">0</span><span class="p">:</span>
+<span class="gp">... </span> <span class="k">print</span> <span class="n">n</span><span class="p">,</span> <span class="s">&#39;equals&#39;</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="s">&#39;*&#39;</span><span class="p">,</span> <span class="n">n</span><span class="o">/</span><span class="n">x</span>
+<span class="gp">... </span> <span class="k">break</span>
+<span class="gp">... </span> <span class="k">else</span><span class="p">:</span>
+<span class="gp">... </span> <span class="c"># loop fell through without finding a factor</span>
+<span class="gp">... </span> <span class="k">print</span> <span class="n">n</span><span class="p">,</span> <span class="s">&#39;is a prime number&#39;</span>
+<span class="gp">...</span>
+<span class="go">2 is a prime number</span>
+<span class="go">3 is a prime number</span>
+<span class="go">4 equals 2 * 2</span>
+<span class="go">5 is a prime number</span>
+<span class="go">6 equals 2 * 3</span>
+<span class="go">7 is a prime number</span>
+<span class="go">8 equals 2 * 4</span>
+<span class="go">9 equals 3 * 3</span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="pass-statements">
+<span id="tut-pass"></span><h2>4.5. <a class="reference external" href="../reference/simple_stmts.html#pass"><tt class="xref docutils literal"><span class="pre">pass</span></tt></a> Statements<a class="headerlink" href="#pass-statements" title="Permalink to this headline">¶</a></h2>
+<p>The <a class="reference external" href="../reference/simple_stmts.html#pass"><tt class="xref docutils literal"><span class="pre">pass</span></tt></a> statement does nothing. It can be used when a statement is
+required syntactically but the program requires no action. For example:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
+<span class="gp">... </span> <span class="k">pass</span> <span class="c"># Busy-wait for keyboard interrupt (Ctrl+C)</span>
+<span class="gp">...</span>
+</pre></div>
+</div>
+<p>This is commonly used for creating minimal classes:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">class</span> <span class="nc">MyEmptyClass</span><span class="p">:</span>
+<span class="gp">... </span> <span class="k">pass</span>
+<span class="gp">...</span>
+</pre></div>
+</div>
+<p>Another place <a class="reference external" href="../reference/simple_stmts.html#pass"><tt class="xref docutils literal"><span class="pre">pass</span></tt></a> can be used is as a place-holder for a function or
+conditional body when you are working on new code, allowing you to keep thinking
+at a more abstract level. The <a class="reference external" href="../reference/simple_stmts.html#pass"><tt class="xref docutils literal"><span class="pre">pass</span></tt></a> is silently ignored:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">def</span> <span class="nf">initlog</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">):</span>
+<span class="gp">... </span> <span class="k">pass</span> <span class="c"># Remember to implement this!</span>
+<span class="gp">...</span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="defining-functions">
+<span id="tut-functions"></span><h2>4.6. Defining Functions<a class="headerlink" href="#defining-functions" title="Permalink to this headline">¶</a></h2>
+<p>We can create a function that writes the Fibonacci series to an arbitrary
+boundary:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">def</span> <span class="nf">fib</span><span class="p">(</span><span class="n">n</span><span class="p">):</span> <span class="c"># write Fibonacci series up to n</span>
+<span class="gp">... </span> <span class="sd">&quot;&quot;&quot;Print a Fibonacci series up to n.&quot;&quot;&quot;</span>
+<span class="gp">... </span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span> <span class="o">=</span> <span class="mf">0</span><span class="p">,</span> <span class="mf">1</span>
+<span class="gp">... </span> <span class="k">while</span> <span class="n">b</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">:</span>
+<span class="gp">... </span> <span class="k">print</span> <span class="n">b</span><span class="p">,</span>
+<span class="gp">... </span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span> <span class="o">=</span> <span class="n">b</span><span class="p">,</span> <span class="n">a</span><span class="o">+</span><span class="n">b</span>
+<span class="gp">...</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="c"># Now call the function we just defined:</span>
+<span class="gp">... </span><span class="n">fib</span><span class="p">(</span><span class="mf">2000</span><span class="p">)</span>
+<span class="go">1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597</span>
+</pre></div>
+</div>
+<p id="index-1059">The keyword <a class="reference external" href="../reference/compound_stmts.html#def"><tt class="xref docutils literal"><span class="pre">def</span></tt></a> introduces a function <em>definition</em>. It must be
+followed by the function name and the parenthesized list of formal parameters.
+The statements that form the body of the function start at the next line, and
+must be indented.</p>
+<p>The first statement of the function body can optionally be a string literal;
+this string literal is the function&#8217;s documentation string, or <em>docstring</em>.
+(More about docstrings can be found in the section <a class="reference internal" href="#tut-docstrings"><em>Documentation Strings</em></a>.)
+There are tools which use docstrings to automatically produce online or printed
+documentation, or to let the user interactively browse through code; it&#8217;s good
+practice to include docstrings in code that you write, so make a habit of it.</p>
+<p>The <em>execution</em> of a function introduces a new symbol table used for the local
+variables of the function. More precisely, all variable assignments in a
+function store the value in the local symbol table; whereas variable references
+first look in the local symbol table, then in the local symbol tables of
+enclosing functions, then in the global symbol table, and finally in the table
+of built-in names. Thus, global variables cannot be directly assigned a value
+within a function (unless named in a <a class="reference external" href="../reference/simple_stmts.html#global"><tt class="xref docutils literal"><span class="pre">global</span></tt></a> statement), although they
+may be referenced.</p>
+<p>The actual parameters (arguments) to a function call are introduced in the local
+symbol table of the called function when it is called; thus, arguments are
+passed using <em>call by value</em> (where the <em>value</em> is always an object <em>reference</em>,
+not the value of the object). <a class="footnote-reference" href="#id2" id="id1">[1]</a> When a function calls another function, a new
+local symbol table is created for that call.</p>
+<p>A function definition introduces the function name in the current symbol table.
+The value of the function name has a type that is recognized by the interpreter
+as a user-defined function. This value can be assigned to another name which
+can then also be used as a function. This serves as a general renaming
+mechanism:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">fib</span>
+<span class="go">&lt;function fib at 10042ed0&gt;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">f</span> <span class="o">=</span> <span class="n">fib</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">f</span><span class="p">(</span><span class="mf">100</span><span class="p">)</span>
+<span class="go">1 1 2 3 5 8 13 21 34 55 89</span>
+</pre></div>
+</div>
+<p>Coming from other languages, you might object that <tt class="docutils literal"><span class="pre">fib</span></tt> is not a function but
+a procedure since it doesn&#8217;t return a value. In fact, even functions without a
+<a class="reference external" href="../reference/simple_stmts.html#return"><tt class="xref docutils literal"><span class="pre">return</span></tt></a> statement do return a value, albeit a rather boring one. This
+value is called <tt class="xref docutils literal"><span class="pre">None</span></tt> (it&#8217;s a built-in name). Writing the value <tt class="xref docutils literal"><span class="pre">None</span></tt> is
+normally suppressed by the interpreter if it would be the only value written.
+You can see it if you really want to using <a class="reference external" href="../reference/simple_stmts.html#print"><tt class="xref docutils literal"><span class="pre">print</span></tt></a>:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">fib</span><span class="p">(</span><span class="mf">0</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">print</span> <span class="n">fib</span><span class="p">(</span><span class="mf">0</span><span class="p">)</span>
+<span class="go">None</span>
+</pre></div>
+</div>
+<p>It is simple to write a function that returns a list of the numbers of the
+Fibonacci series, instead of printing it:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">def</span> <span class="nf">fib2</span><span class="p">(</span><span class="n">n</span><span class="p">):</span> <span class="c"># return Fibonacci series up to n</span>
+<span class="gp">... </span> <span class="sd">&quot;&quot;&quot;Return a list containing the Fibonacci series up to n.&quot;&quot;&quot;</span>
+<span class="gp">... </span> <span class="n">result</span> <span class="o">=</span> <span class="p">[]</span>
+<span class="gp">... </span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span> <span class="o">=</span> <span class="mf">0</span><span class="p">,</span> <span class="mf">1</span>
+<span class="gp">... </span> <span class="k">while</span> <span class="n">b</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">:</span>
+<span class="gp">... </span> <span class="n">result</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">b</span><span class="p">)</span> <span class="c"># see below</span>
+<span class="gp">... </span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span> <span class="o">=</span> <span class="n">b</span><span class="p">,</span> <span class="n">a</span><span class="o">+</span><span class="n">b</span>
+<span class="gp">... </span> <span class="k">return</span> <span class="n">result</span>
+<span class="gp">...</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">f100</span> <span class="o">=</span> <span class="n">fib2</span><span class="p">(</span><span class="mf">100</span><span class="p">)</span> <span class="c"># call it</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">f100</span> <span class="c"># write the result</span>
+<span class="go">[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]</span>
+</pre></div>
+</div>
+<p>This example, as usual, demonstrates some new Python features:</p>
+<ul class="simple">
+<li>The <a class="reference external" href="../reference/simple_stmts.html#return"><tt class="xref docutils literal"><span class="pre">return</span></tt></a> statement returns with a value from a function.
+<a class="reference external" href="../reference/simple_stmts.html#return"><tt class="xref docutils literal"><span class="pre">return</span></tt></a> without an expression argument returns <tt class="xref docutils literal"><span class="pre">None</span></tt>. Falling off
+the end of a function also returns <tt class="xref docutils literal"><span class="pre">None</span></tt>.</li>
+<li>The statement <tt class="docutils literal"><span class="pre">result.append(b)</span></tt> calls a <em>method</em> of the list object
+<tt class="docutils literal"><span class="pre">result</span></tt>. A method is a function that &#8216;belongs&#8217; to an object and is named
+<tt class="docutils literal"><span class="pre">obj.methodname</span></tt>, where <tt class="docutils literal"><span class="pre">obj</span></tt> is some object (this may be an expression),
+and <tt class="docutils literal"><span class="pre">methodname</span></tt> is the name of a method that is defined by the object&#8217;s type.
+Different types define different methods. Methods of different types may have
+the same name without causing ambiguity. (It is possible to define your own
+object types and methods, using <em>classes</em>, as discussed later in this tutorial.)
+The method <tt class="xref docutils literal"><span class="pre">append()</span></tt> shown in the example is defined for list objects; it
+adds a new element at the end of the list. In this example it is equivalent to
+<tt class="docutils literal"><span class="pre">result</span> <span class="pre">=</span> <span class="pre">result</span> <span class="pre">+</span> <span class="pre">[b]</span></tt>, but more efficient.</li>
+</ul>
+</div>
+<div class="section" id="more-on-defining-functions">
+<span id="tut-defining"></span><h2>4.7. More on Defining Functions<a class="headerlink" href="#more-on-defining-functions" title="Permalink to this headline">¶</a></h2>
+<p>It is also possible to define functions with a variable number of arguments.
+There are three forms, which can be combined.</p>
+<div class="section" id="default-argument-values">
+<span id="tut-defaultargs"></span><h3>4.7.1. Default Argument Values<a class="headerlink" href="#default-argument-values" title="Permalink to this headline">¶</a></h3>
+<p>The most useful form is to specify a default value for one or more arguments.
+This creates a function that can be called with fewer arguments than it is
+defined to allow. For example:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">ask_ok</span><span class="p">(</span><span class="n">prompt</span><span class="p">,</span> <span class="n">retries</span><span class="o">=</span><span class="mf">4</span><span class="p">,</span> <span class="n">complaint</span><span class="o">=</span><span class="s">&#39;Yes or no, please!&#39;</span><span class="p">):</span>
+ <span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
+ <span class="n">ok</span> <span class="o">=</span> <span class="nb">raw_input</span><span class="p">(</span><span class="n">prompt</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">ok</span> <span class="ow">in</span> <span class="p">(</span><span class="s">&#39;y&#39;</span><span class="p">,</span> <span class="s">&#39;ye&#39;</span><span class="p">,</span> <span class="s">&#39;yes&#39;</span><span class="p">):</span> <span class="k">return</span> <span class="bp">True</span>
+ <span class="k">if</span> <span class="n">ok</span> <span class="ow">in</span> <span class="p">(</span><span class="s">&#39;n&#39;</span><span class="p">,</span> <span class="s">&#39;no&#39;</span><span class="p">,</span> <span class="s">&#39;nop&#39;</span><span class="p">,</span> <span class="s">&#39;nope&#39;</span><span class="p">):</span> <span class="k">return</span> <span class="bp">False</span>
+ <span class="n">retries</span> <span class="o">=</span> <span class="n">retries</span> <span class="o">-</span> <span class="mf">1</span>
+ <span class="k">if</span> <span class="n">retries</span> <span class="o">&lt;</span> <span class="mf">0</span><span class="p">:</span> <span class="k">raise</span> <span class="ne">IOError</span><span class="p">,</span> <span class="s">&#39;refusenik user&#39;</span>
+ <span class="k">print</span> <span class="n">complaint</span>
+</pre></div>
+</div>
+<p>This function can be called either like this: <tt class="docutils literal"><span class="pre">ask_ok('Do</span> <span class="pre">you</span> <span class="pre">really</span> <span class="pre">want</span> <span class="pre">to</span>
+<span class="pre">quit?')</span></tt> or like this: <tt class="docutils literal"><span class="pre">ask_ok('OK</span> <span class="pre">to</span> <span class="pre">overwrite</span> <span class="pre">the</span> <span class="pre">file?',</span> <span class="pre">2)</span></tt>.</p>
+<p>This example also introduces the <a class="reference external" href="../reference/expressions.html#in"><tt class="xref docutils literal"><span class="pre">in</span></tt></a> keyword. This tests whether or
+not a sequence contains a certain value.</p>
+<p>The default values are evaluated at the point of function definition in the
+<em>defining</em> scope, so that</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="n">i</span> <span class="o">=</span> <span class="mf">5</span>
+
+<span class="k">def</span> <span class="nf">f</span><span class="p">(</span><span class="n">arg</span><span class="o">=</span><span class="n">i</span><span class="p">):</span>
+ <span class="k">print</span> <span class="n">arg</span>
+
+<span class="n">i</span> <span class="o">=</span> <span class="mf">6</span>
+<span class="n">f</span><span class="p">()</span>
+</pre></div>
+</div>
+<p>will print <tt class="docutils literal"><span class="pre">5</span></tt>.</p>
+<p><strong>Important warning:</strong> The default value is evaluated only once. This makes a
+difference when the default is a mutable object such as a list, dictionary, or
+instances of most classes. For example, the following function accumulates the
+arguments passed to it on subsequent calls:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">f</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">L</span><span class="o">=</span><span class="p">[]):</span>
+ <span class="n">L</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
+ <span class="k">return</span> <span class="n">L</span>
+
+<span class="k">print</span> <span class="n">f</span><span class="p">(</span><span class="mf">1</span><span class="p">)</span>
+<span class="k">print</span> <span class="n">f</span><span class="p">(</span><span class="mf">2</span><span class="p">)</span>
+<span class="k">print</span> <span class="n">f</span><span class="p">(</span><span class="mf">3</span><span class="p">)</span>
+</pre></div>
+</div>
+<p>This will print</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="p">[</span><span class="mf">1</span><span class="p">]</span>
+<span class="p">[</span><span class="mf">1</span><span class="p">,</span> <span class="mf">2</span><span class="p">]</span>
+<span class="p">[</span><span class="mf">1</span><span class="p">,</span> <span class="mf">2</span><span class="p">,</span> <span class="mf">3</span><span class="p">]</span>
+</pre></div>
+</div>
+<p>If you don&#8217;t want the default to be shared between subsequent calls, you can
+write the function like this instead:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">f</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">L</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
+ <span class="k">if</span> <span class="n">L</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span>
+ <span class="n">L</span> <span class="o">=</span> <span class="p">[]</span>
+ <span class="n">L</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
+ <span class="k">return</span> <span class="n">L</span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="keyword-arguments">
+<span id="tut-keywordargs"></span><h3>4.7.2. Keyword Arguments<a class="headerlink" href="#keyword-arguments" title="Permalink to this headline">¶</a></h3>
+<p>Functions can also be called using keyword arguments of the form <tt class="docutils literal"><span class="pre">keyword</span> <span class="pre">=</span>
+<span class="pre">value</span></tt>. For instance, the following function:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">parrot</span><span class="p">(</span><span class="n">voltage</span><span class="p">,</span> <span class="n">state</span><span class="o">=</span><span class="s">&#39;a stiff&#39;</span><span class="p">,</span> <span class="n">action</span><span class="o">=</span><span class="s">&#39;voom&#39;</span><span class="p">,</span> <span class="nb">type</span><span class="o">=</span><span class="s">&#39;Norwegian Blue&#39;</span><span class="p">):</span>
+ <span class="k">print</span> <span class="s">&quot;-- This parrot wouldn&#39;t&quot;</span><span class="p">,</span> <span class="n">action</span><span class="p">,</span>
+ <span class="k">print</span> <span class="s">&quot;if you put&quot;</span><span class="p">,</span> <span class="n">voltage</span><span class="p">,</span> <span class="s">&quot;volts through it.&quot;</span>
+ <span class="k">print</span> <span class="s">&quot;-- Lovely plumage, the&quot;</span><span class="p">,</span> <span class="nb">type</span>
+ <span class="k">print</span> <span class="s">&quot;-- It&#39;s&quot;</span><span class="p">,</span> <span class="n">state</span><span class="p">,</span> <span class="s">&quot;!&quot;</span>
+</pre></div>
+</div>
+<p>could be called in any of the following ways:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="n">parrot</span><span class="p">(</span><span class="mf">1000</span><span class="p">)</span>
+<span class="n">parrot</span><span class="p">(</span><span class="n">action</span> <span class="o">=</span> <span class="s">&#39;VOOOOOM&#39;</span><span class="p">,</span> <span class="n">voltage</span> <span class="o">=</span> <span class="mf">1000000</span><span class="p">)</span>
+<span class="n">parrot</span><span class="p">(</span><span class="s">&#39;a thousand&#39;</span><span class="p">,</span> <span class="n">state</span> <span class="o">=</span> <span class="s">&#39;pushing up the daisies&#39;</span><span class="p">)</span>
+<span class="n">parrot</span><span class="p">(</span><span class="s">&#39;a million&#39;</span><span class="p">,</span> <span class="s">&#39;bereft of life&#39;</span><span class="p">,</span> <span class="s">&#39;jump&#39;</span><span class="p">)</span>
+</pre></div>
+</div>
+<p>but the following calls would all be invalid:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="n">parrot</span><span class="p">()</span> <span class="c"># required argument missing</span>
+<span class="n">parrot</span><span class="p">(</span><span class="n">voltage</span><span class="o">=</span><span class="mf">5.0</span><span class="p">,</span> <span class="s">&#39;dead&#39;</span><span class="p">)</span> <span class="c"># non-keyword argument following keyword</span>
+<span class="n">parrot</span><span class="p">(</span><span class="mf">110</span><span class="p">,</span> <span class="n">voltage</span><span class="o">=</span><span class="mf">220</span><span class="p">)</span> <span class="c"># duplicate value for argument</span>
+<span class="n">parrot</span><span class="p">(</span><span class="n">actor</span><span class="o">=</span><span class="s">&#39;John Cleese&#39;</span><span class="p">)</span> <span class="c"># unknown keyword</span>
+</pre></div>
+</div>
+<p>In general, an argument list must have any positional arguments followed by any
+keyword arguments, where the keywords must be chosen from the formal parameter
+names. It&#8217;s not important whether a formal parameter has a default value or
+not. No argument may receive a value more than once &#8212; formal parameter names
+corresponding to positional arguments cannot be used as keywords in the same
+calls. Here&#8217;s an example that fails due to this restriction:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">def</span> <span class="nf">function</span><span class="p">(</span><span class="n">a</span><span class="p">):</span>
+<span class="gp">... </span> <span class="k">pass</span>
+<span class="gp">...</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">function</span><span class="p">(</span><span class="mf">0</span><span class="p">,</span> <span class="n">a</span><span class="o">=</span><span class="mf">0</span><span class="p">)</span>
+<span class="gt">Traceback (most recent call last):</span>
+ File <span class="nb">&quot;&lt;stdin&gt;&quot;</span>, line <span class="m">1</span>, in <span class="n-Identifier">?</span>
+<span class="nc">TypeError</span>: <span class="n-Identifier">function() got multiple values for keyword argument &#39;a&#39;</span>
+</pre></div>
+</div>
+<p>When a final formal parameter of the form <tt class="docutils literal"><span class="pre">**name</span></tt> is present, it receives a
+dictionary (see <a class="reference external" href="../library/stdtypes.html#typesmapping"><em>Mapping Types &#8212; dict</em></a>) containing all keyword arguments except for
+those corresponding to a formal parameter. This may be combined with a formal
+parameter of the form <tt class="docutils literal"><span class="pre">*name</span></tt> (described in the next subsection) which
+receives a tuple containing the positional arguments beyond the formal parameter
+list. (<tt class="docutils literal"><span class="pre">*name</span></tt> must occur before <tt class="docutils literal"><span class="pre">**name</span></tt>.) For example, if we define a
+function like this:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">cheeseshop</span><span class="p">(</span><span class="n">kind</span><span class="p">,</span> <span class="o">*</span><span class="n">arguments</span><span class="p">,</span> <span class="o">**</span><span class="n">keywords</span><span class="p">):</span>
+ <span class="k">print</span> <span class="s">&quot;-- Do you have any&quot;</span><span class="p">,</span> <span class="n">kind</span><span class="p">,</span> <span class="s">&quot;?&quot;</span>
+ <span class="k">print</span> <span class="s">&quot;-- I&#39;m sorry, we&#39;re all out of&quot;</span><span class="p">,</span> <span class="n">kind</span>
+ <span class="k">for</span> <span class="n">arg</span> <span class="ow">in</span> <span class="n">arguments</span><span class="p">:</span> <span class="k">print</span> <span class="n">arg</span>
+ <span class="k">print</span> <span class="s">&quot;-&quot;</span> <span class="o">*</span> <span class="mf">40</span>
+ <span class="n">keys</span> <span class="o">=</span> <span class="n">keywords</span><span class="o">.</span><span class="n">keys</span><span class="p">()</span>
+ <span class="n">keys</span><span class="o">.</span><span class="n">sort</span><span class="p">()</span>
+ <span class="k">for</span> <span class="n">kw</span> <span class="ow">in</span> <span class="n">keys</span><span class="p">:</span> <span class="k">print</span> <span class="n">kw</span><span class="p">,</span> <span class="s">&quot;:&quot;</span><span class="p">,</span> <span class="n">keywords</span><span class="p">[</span><span class="n">kw</span><span class="p">]</span>
+</pre></div>
+</div>
+<p>It could be called like this:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="n">cheeseshop</span><span class="p">(</span><span class="s">&quot;Limburger&quot;</span><span class="p">,</span> <span class="s">&quot;It&#39;s very runny, sir.&quot;</span><span class="p">,</span>
+ <span class="s">&quot;It&#39;s really very, VERY runny, sir.&quot;</span><span class="p">,</span>
+ <span class="n">shopkeeper</span><span class="o">=</span><span class="s">&#39;Michael Palin&#39;</span><span class="p">,</span>
+ <span class="n">client</span><span class="o">=</span><span class="s">&quot;John Cleese&quot;</span><span class="p">,</span>
+ <span class="n">sketch</span><span class="o">=</span><span class="s">&quot;Cheese Shop Sketch&quot;</span><span class="p">)</span>
+</pre></div>
+</div>
+<p>and of course it would print:</p>
+<div class="highlight-python"><pre>-- Do you have any Limburger ?
+-- I'm sorry, we're all out of Limburger
+It's very runny, sir.
+It's really very, VERY runny, sir.
+----------------------------------------
+client : John Cleese
+shopkeeper : Michael Palin
+sketch : Cheese Shop Sketch</pre>
+</div>
+<p>Note that the <tt class="xref docutils literal"><span class="pre">sort()</span></tt> method of the list of keyword argument names is
+called before printing the contents of the <tt class="docutils literal"><span class="pre">keywords</span></tt> dictionary; if this is
+not done, the order in which the arguments are printed is undefined.</p>
+</div>
+<div class="section" id="arbitrary-argument-lists">
+<span id="tut-arbitraryargs"></span><h3>4.7.3. Arbitrary Argument Lists<a class="headerlink" href="#arbitrary-argument-lists" title="Permalink to this headline">¶</a></h3>
+<p id="index-1060">Finally, the least frequently used option is to specify that a function can be
+called with an arbitrary number of arguments. These arguments will be wrapped
+up in a tuple (see <a class="reference external" href="datastructures.html#tut-tuples"><em>Tuples and Sequences</em></a>). Before the variable number of arguments,
+zero or more normal arguments may occur.</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">write_multiple_items</span><span class="p">(</span><span class="nb">file</span><span class="p">,</span> <span class="n">separator</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">):</span>
+ <span class="nb">file</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">separator</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">args</span><span class="p">))</span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="unpacking-argument-lists">
+<span id="tut-unpacking-arguments"></span><h3>4.7.4. Unpacking Argument Lists<a class="headerlink" href="#unpacking-argument-lists" title="Permalink to this headline">¶</a></h3>
+<p>The reverse situation occurs when the arguments are already in a list or tuple
+but need to be unpacked for a function call requiring separate positional
+arguments. For instance, the built-in <a title="range" class="reference external" href="../library/functions.html#range"><tt class="xref docutils literal"><span class="pre">range()</span></tt></a> function expects separate
+<em>start</em> and <em>stop</em> arguments. If they are not available separately, write the
+function call with the <tt class="docutils literal"><span class="pre">*</span></tt>-operator to unpack the arguments out of a list
+or tuple:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="nb">range</span><span class="p">(</span><span class="mf">3</span><span class="p">,</span> <span class="mf">6</span><span class="p">)</span> <span class="c"># normal call with separate arguments</span>
+<span class="go">[3, 4, 5]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">args</span> <span class="o">=</span> <span class="p">[</span><span class="mf">3</span><span class="p">,</span> <span class="mf">6</span><span class="p">]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">range</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">)</span> <span class="c"># call with arguments unpacked from a list</span>
+<span class="go">[3, 4, 5]</span>
+</pre></div>
+</div>
+<p id="index-1061">In the same fashion, dictionaries can deliver keyword arguments with the <tt class="docutils literal"><span class="pre">**</span></tt>-operator:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">def</span> <span class="nf">parrot</span><span class="p">(</span><span class="n">voltage</span><span class="p">,</span> <span class="n">state</span><span class="o">=</span><span class="s">&#39;a stiff&#39;</span><span class="p">,</span> <span class="n">action</span><span class="o">=</span><span class="s">&#39;voom&#39;</span><span class="p">):</span>
+<span class="gp">... </span> <span class="k">print</span> <span class="s">&quot;-- This parrot wouldn&#39;t&quot;</span><span class="p">,</span> <span class="n">action</span><span class="p">,</span>
+<span class="gp">... </span> <span class="k">print</span> <span class="s">&quot;if you put&quot;</span><span class="p">,</span> <span class="n">voltage</span><span class="p">,</span> <span class="s">&quot;volts through it.&quot;</span><span class="p">,</span>
+<span class="gp">... </span> <span class="k">print</span> <span class="s">&quot;E&#39;s&quot;</span><span class="p">,</span> <span class="n">state</span><span class="p">,</span> <span class="s">&quot;!&quot;</span>
+<span class="gp">...</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">d</span> <span class="o">=</span> <span class="p">{</span><span class="s">&quot;voltage&quot;</span><span class="p">:</span> <span class="s">&quot;four million&quot;</span><span class="p">,</span> <span class="s">&quot;state&quot;</span><span class="p">:</span> <span class="s">&quot;bleedin&#39; demised&quot;</span><span class="p">,</span> <span class="s">&quot;action&quot;</span><span class="p">:</span> <span class="s">&quot;VOOM&quot;</span><span class="p">}</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">parrot</span><span class="p">(</span><span class="o">**</span><span class="n">d</span><span class="p">)</span>
+<span class="go">-- This parrot wouldn&#39;t VOOM if you put four million volts through it. E&#39;s bleedin&#39; demised !</span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="lambda-forms">
+<span id="tut-lambda"></span><h3>4.7.5. Lambda Forms<a class="headerlink" href="#lambda-forms" title="Permalink to this headline">¶</a></h3>
+<p>By popular demand, a few features commonly found in functional programming
+languages like Lisp have been added to Python. With the <a class="reference external" href="../reference/expressions.html#lambda"><tt class="xref docutils literal"><span class="pre">lambda</span></tt></a>
+keyword, small anonymous functions can be created. Here&#8217;s a function that
+returns the sum of its two arguments: <tt class="docutils literal"><span class="pre">lambda</span> <span class="pre">a,</span> <span class="pre">b:</span> <span class="pre">a+b</span></tt>. Lambda forms can be
+used wherever function objects are required. They are syntactically restricted
+to a single expression. Semantically, they are just syntactic sugar for a
+normal function definition. Like nested function definitions, lambda forms can
+reference variables from the containing scope:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">def</span> <span class="nf">make_incrementor</span><span class="p">(</span><span class="n">n</span><span class="p">):</span>
+<span class="gp">... </span> <span class="k">return</span> <span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span> <span class="o">+</span> <span class="n">n</span>
+<span class="gp">...</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">f</span> <span class="o">=</span> <span class="n">make_incrementor</span><span class="p">(</span><span class="mf">42</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">f</span><span class="p">(</span><span class="mf">0</span><span class="p">)</span>
+<span class="go">42</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">f</span><span class="p">(</span><span class="mf">1</span><span class="p">)</span>
+<span class="go">43</span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="documentation-strings">
+<span id="tut-docstrings"></span><h3>4.7.6. Documentation Strings<a class="headerlink" href="#documentation-strings" title="Permalink to this headline">¶</a></h3>
+<p id="index-1062">There are emerging conventions about the content and formatting of documentation
+strings.</p>
+<p>The first line should always be a short, concise summary of the object&#8217;s
+purpose. For brevity, it should not explicitly state the object&#8217;s name or type,
+since these are available by other means (except if the name happens to be a
+verb describing a function&#8217;s operation). This line should begin with a capital
+letter and end with a period.</p>
+<p>If there are more lines in the documentation string, the second line should be
+blank, visually separating the summary from the rest of the description. The
+following lines should be one or more paragraphs describing the object&#8217;s calling
+conventions, its side effects, etc.</p>
+<p>The Python parser does not strip indentation from multi-line string literals in
+Python, so tools that process documentation have to strip indentation if
+desired. This is done using the following convention. The first non-blank line
+<em>after</em> the first line of the string determines the amount of indentation for
+the entire documentation string. (We can&#8217;t use the first line since it is
+generally adjacent to the string&#8217;s opening quotes so its indentation is not
+apparent in the string literal.) Whitespace &#8220;equivalent&#8221; to this indentation is
+then stripped from the start of all lines of the string. Lines that are
+indented less should not occur, but if they occur all their leading whitespace
+should be stripped. Equivalence of whitespace should be tested after expansion
+of tabs (to 8 spaces, normally).</p>
+<p>Here is an example of a multi-line docstring:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">def</span> <span class="nf">my_function</span><span class="p">():</span>
+<span class="gp">... </span> <span class="sd">&quot;&quot;&quot;Do nothing, but document it.</span>
+<span class="gp">...</span><span class="sd"></span>
+<span class="gp">... </span><span class="sd"> No, really, it doesn&#39;t do anything.</span>
+<span class="gp">... </span><span class="sd"> &quot;&quot;&quot;</span>
+<span class="gp">... </span> <span class="k">pass</span>
+<span class="gp">...</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">print</span> <span class="n">my_function</span><span class="o">.</span><span class="n">__doc__</span>
+<span class="go">Do nothing, but document it.</span>
+
+<span class="go"> No, really, it doesn&#39;t do anything.</span>
+</pre></div>
+</div>
+</div>
+</div>
+<div class="section" id="intermezzo-coding-style">
+<span id="tut-codingstyle"></span><h2>4.8. Intermezzo: Coding Style<a class="headerlink" href="#intermezzo-coding-style" title="Permalink to this headline">¶</a></h2>
+<p id="index-1063">Now that you are about to write longer, more complex pieces of Python, it is a
+good time to talk about <em>coding style</em>. Most languages can be written (or more
+concise, <em>formatted</em>) in different styles; some are more readable than others.
+Making it easy for others to read your code is always a good idea, and adopting
+a nice coding style helps tremendously for that.</p>
+<p>For Python, <span class="target" id="index-1064"></span><a class="reference external" href="http://www.python.org/dev/peps/pep-0008"><strong>PEP 8</strong></a> has emerged as the style guide that most projects adhere to;
+it promotes a very readable and eye-pleasing coding style. Every Python
+developer should read it at some point; here are the most important points
+extracted for you:</p>
+<ul>
+<li><p class="first">Use 4-space indentation, and no tabs.</p>
+<p>4 spaces are a good compromise between small indentation (allows greater
+nesting depth) and large indentation (easier to read). Tabs introduce
+confusion, and are best left out.</p>
+</li>
+<li><p class="first">Wrap lines so that they don&#8217;t exceed 79 characters.</p>
+<p>This helps users with small displays and makes it possible to have several
+code files side-by-side on larger displays.</p>
+</li>
+<li><p class="first">Use blank lines to separate functions and classes, and larger blocks of
+code inside functions.</p>
+</li>
+<li><p class="first">When possible, put comments on a line of their own.</p>
+</li>
+<li><p class="first">Use docstrings.</p>
+</li>
+<li><p class="first">Use spaces around operators and after commas, but not directly inside
+bracketing constructs: <tt class="docutils literal"><span class="pre">a</span> <span class="pre">=</span> <span class="pre">f(1,</span> <span class="pre">2)</span> <span class="pre">+</span> <span class="pre">g(3,</span> <span class="pre">4)</span></tt>.</p>
+</li>
+<li><p class="first">Name your classes and functions consistently; the convention is to use
+<tt class="docutils literal"><span class="pre">CamelCase</span></tt> for classes and <tt class="docutils literal"><span class="pre">lower_case_with_underscores</span></tt> for functions
+and methods. Always use <tt class="docutils literal"><span class="pre">self</span></tt> as the name for the first method argument
+(see <a class="reference external" href="classes.html#tut-firstclasses"><em>A First Look at Classes</em></a> for more on classes and methods).</p>
+</li>
+<li><p class="first">Don&#8217;t use fancy encodings if your code is meant to be used in international
+environments. Plain ASCII works best in any case.</p>
+</li>
+</ul>
+<p class="rubric">Footnotes</p>
+<table class="docutils footnote" frame="void" id="id2" rules="none">
+<colgroup><col class="label" /><col /></colgroup>
+<tbody valign="top">
+<tr><td class="label"><a class="fn-backref" href="#id1">[1]</a></td><td>Actually, <em>call by object reference</em> would be a better description,
+since if a mutable object is passed, the caller will see any changes the
+callee makes to it (items inserted into a list).</td></tr>
+</tbody>
+</table>
+</div>
+</div>
+
+
+ </div>
+ </div>
+ </div>
+ <div class="sphinxsidebar">
+ <div class="sphinxsidebarwrapper">
+ <h3><a href="../contents.html">Table Of Contents</a></h3>
+ <ul>
+<li><a class="reference external" href="">4. More Control Flow Tools</a><ul>
+<li><a class="reference external" href="#if-statements">4.1. <tt class="docutils literal"><span class="pre">if</span></tt> Statements</a></li>
+<li><a class="reference external" href="#for-statements">4.2. <tt class="docutils literal"><span class="pre">for</span></tt> Statements</a></li>
+<li><a class="reference external" href="#the-range-function">4.3. The <tt class="docutils literal"><span class="pre">range()</span></tt> Function</a></li>
+<li><a class="reference external" href="#break-and-continue-statements-and-else-clauses-on-loops">4.4. <tt class="docutils literal"><span class="pre">break</span></tt> and <tt class="docutils literal"><span class="pre">continue</span></tt> Statements, and <tt class="docutils literal"><span class="pre">else</span></tt> Clauses on Loops</a></li>
+<li><a class="reference external" href="#pass-statements">4.5. <tt class="docutils literal"><span class="pre">pass</span></tt> Statements</a></li>
+<li><a class="reference external" href="#defining-functions">4.6. Defining Functions</a></li>
+<li><a class="reference external" href="#more-on-defining-functions">4.7. More on Defining Functions</a><ul>
+<li><a class="reference external" href="#default-argument-values">4.7.1. Default Argument Values</a></li>
+<li><a class="reference external" href="#keyword-arguments">4.7.2. Keyword Arguments</a></li>
+<li><a class="reference external" href="#arbitrary-argument-lists">4.7.3. Arbitrary Argument Lists</a></li>
+<li><a class="reference external" href="#unpacking-argument-lists">4.7.4. Unpacking Argument Lists</a></li>
+<li><a class="reference external" href="#lambda-forms">4.7.5. Lambda Forms</a></li>
+<li><a class="reference external" href="#documentation-strings">4.7.6. Documentation Strings</a></li>
+</ul>
+</li>
+<li><a class="reference external" href="#intermezzo-coding-style">4.8. Intermezzo: Coding Style</a></li>
+</ul>
+</li>
+</ul>
+
+ <h4>Previous topic</h4>
+ <p class="topless"><a href="introduction.html"
+ title="previous chapter">3. An Informal Introduction to Python</a></p>
+ <h4>Next topic</h4>
+ <p class="topless"><a href="datastructures.html"
+ title="next chapter">5. Data Structures</a></p>
+ <h3>This Page</h3>
+ <ul class="this-page-menu">
+ <li><a href="../_sources/tutorial/controlflow.txt"
+ rel="nofollow">Show Source</a></li>
+ </ul>
+ <div id="searchbox" style="display: none">
+ <h3>Quick search</h3>
+ <form class="search" action="../search.html" method="get">
+ <input type="text" name="q" size="18" />
+ <input type="submit" value="Go" />
+ <input type="hidden" name="check_keywords" value="yes" />
+ <input type="hidden" name="area" value="default" />
+ </form>
+ <p class="searchtip" style="font-size: 90%">
+ Enter search terms or a module, class or function name.
+ </p>
+ </div>
+ <script type="text/javascript">$('#searchbox').show(0);</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../genindex.html" title="General Index"
+ >index</a></li>
+ <li class="right" >
+ <a href="../modindex.html" title="Global Module Index"
+ >modules</a> |</li>
+ <li class="right" >
+ <a href="datastructures.html" title="5. Data Structures"
+ >next</a> |</li>
+ <li class="right" >
+ <a href="introduction.html" title="3. An Informal Introduction to Python"
+ >previous</a> |</li>
+ <li><img src="../_static/py.png" alt=""
+ style="vertical-align: middle; margin-top: -1px"/></li>
+ <li><a href="../index.html">Python v2.6.4c2 documentation</a> &raquo;</li>
+
+ <li><a href="index.html" >The Python Tutorial</a> &raquo;</li>
+ </ul>
+ </div>
+ <div class="footer">
+ &copy; <a href="../copyright.html">Copyright</a> 1990-2009, Python Software Foundation.
+ <br />
+ The Python Software Foundation is a non-profit corporation.
+ <a href="http://www.python.org/psf/donations/">Please donate.</a>
+ <br />
+ Last updated on Oct 19, 2009.
+ Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 0.6.2.
+ </div>
+
+ </body>
+</html> \ No newline at end of file
diff --git a/help/PythonTutorial/tutorial/datastructures.html b/help/PythonTutorial/tutorial/datastructures.html
new file mode 100644
index 0000000..2ad57b0
--- /dev/null
+++ b/help/PythonTutorial/tutorial/datastructures.html
@@ -0,0 +1,739 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+ <title>5. Data Structures &mdash; Python v2.6.4c2 documentation</title>
+ <link rel="stylesheet" href="../_static/default.css" type="text/css" />
+ <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
+ <script type="text/javascript">
+ var DOCUMENTATION_OPTIONS = {
+ URL_ROOT: '../',
+ VERSION: '2.6.4c2',
+ COLLAPSE_MODINDEX: false,
+ FILE_SUFFIX: '.html',
+ HAS_SOURCE: true
+ };
+ </script>
+ <script type="text/javascript" src="../_static/jquery.js"></script>
+ <script type="text/javascript" src="../_static/doctools.js"></script>
+ <link rel="search" type="application/opensearchdescription+xml"
+ title="Search within Python v2.6.4c2 documentation"
+ href="../_static/opensearch.xml"/>
+ <link rel="author" title="About these documents" href="../about.html" />
+ <link rel="copyright" title="Copyright" href="../copyright.html" />
+ <link rel="top" title="Python v2.6.4c2 documentation" href="../index.html" />
+ <link rel="up" title="The Python Tutorial" href="index.html" />
+ <link rel="next" title="6. Modules" href="modules.html" />
+ <link rel="prev" title="4. More Control Flow Tools" href="controlflow.html" />
+ <link rel="shortcut icon" type="image/png" href="../_static/py.png" />
+
+
+ </head>
+ <body>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../modindex.html" title="Global Module Index"
+ accesskey="M">modules</a> |</li>
+ <li class="right" >
+ <a href="modules.html" title="6. Modules"
+ accesskey="N">next</a> |</li>
+ <li class="right" >
+ <a href="controlflow.html" title="4. More Control Flow Tools"
+ accesskey="P">previous</a> |</li>
+ <li><img src="../_static/py.png" alt=""
+ style="vertical-align: middle; margin-top: -1px"/></li>
+ <li><a href="../index.html">Python v2.6.4c2 documentation</a> &raquo;</li>
+
+ <li><a href="index.html" accesskey="U">The Python Tutorial</a> &raquo;</li>
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body">
+
+ <div class="section" id="data-structures">
+<span id="tut-structures"></span><h1>5. Data Structures<a class="headerlink" href="#data-structures" title="Permalink to this headline">¶</a></h1>
+<p>This chapter describes some things you&#8217;ve learned about already in more detail,
+and adds some new things as well.</p>
+<div class="section" id="more-on-lists">
+<span id="tut-morelists"></span><h2>5.1. More on Lists<a class="headerlink" href="#more-on-lists" title="Permalink to this headline">¶</a></h2>
+<p>The list data type has some more methods. Here are all of the methods of list
+objects:</p>
+<dl class="method">
+<dt>
+<tt class="descclassname">list.</tt><tt class="descname">append</tt><big>(</big><em>x</em><big>)</big></dt>
+<dd>Add an item to the end of the list; equivalent to <tt class="docutils literal"><span class="pre">a[len(a):]</span> <span class="pre">=</span> <span class="pre">[x]</span></tt>.</dd></dl>
+
+<dl class="method">
+<dt>
+<tt class="descclassname">list.</tt><tt class="descname">extend</tt><big>(</big><em>L</em><big>)</big></dt>
+<dd>Extend the list by appending all the items in the given list; equivalent to
+<tt class="docutils literal"><span class="pre">a[len(a):]</span> <span class="pre">=</span> <span class="pre">L</span></tt>.</dd></dl>
+
+<dl class="method">
+<dt>
+<tt class="descclassname">list.</tt><tt class="descname">insert</tt><big>(</big><em>i</em>, <em>x</em><big>)</big></dt>
+<dd>Insert an item at a given position. The first argument is the index of the
+element before which to insert, so <tt class="docutils literal"><span class="pre">a.insert(0,</span> <span class="pre">x)</span></tt> inserts at the front of
+the list, and <tt class="docutils literal"><span class="pre">a.insert(len(a),</span> <span class="pre">x)</span></tt> is equivalent to <tt class="docutils literal"><span class="pre">a.append(x)</span></tt>.</dd></dl>
+
+<dl class="method">
+<dt>
+<tt class="descclassname">list.</tt><tt class="descname">remove</tt><big>(</big><em>x</em><big>)</big></dt>
+<dd>Remove the first item from the list whose value is <em>x</em>. It is an error if there
+is no such item.</dd></dl>
+
+<dl class="method">
+<dt>
+<tt class="descclassname">list.</tt><tt class="descname">pop</tt><big>(</big><span class="optional">[</span><em>i</em><span class="optional">]</span><big>)</big></dt>
+<dd>Remove the item at the given position in the list, and return it. If no index
+is specified, <tt class="docutils literal"><span class="pre">a.pop()</span></tt> removes and returns the last item in the list. (The
+square brackets around the <em>i</em> in the method signature denote that the parameter
+is optional, not that you should type square brackets at that position. You
+will see this notation frequently in the Python Library Reference.)</dd></dl>
+
+<dl class="method">
+<dt>
+<tt class="descclassname">list.</tt><tt class="descname">index</tt><big>(</big><em>x</em><big>)</big></dt>
+<dd>Return the index in the list of the first item whose value is <em>x</em>. It is an
+error if there is no such item.</dd></dl>
+
+<dl class="method">
+<dt>
+<tt class="descclassname">list.</tt><tt class="descname">count</tt><big>(</big><em>x</em><big>)</big></dt>
+<dd>Return the number of times <em>x</em> appears in the list.</dd></dl>
+
+<dl class="method">
+<dt>
+<tt class="descclassname">list.</tt><tt class="descname">sort</tt><big>(</big><big>)</big></dt>
+<dd>Sort the items of the list, in place.</dd></dl>
+
+<dl class="method">
+<dt>
+<tt class="descclassname">list.</tt><tt class="descname">reverse</tt><big>(</big><big>)</big></dt>
+<dd>Reverse the elements of the list, in place.</dd></dl>
+
+<p>An example that uses most of the list methods:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">a</span> <span class="o">=</span> <span class="p">[</span><span class="mf">66.25</span><span class="p">,</span> <span class="mf">333</span><span class="p">,</span> <span class="mf">333</span><span class="p">,</span> <span class="mf">1</span><span class="p">,</span> <span class="mf">1234.5</span><span class="p">]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">print</span> <span class="n">a</span><span class="o">.</span><span class="n">count</span><span class="p">(</span><span class="mf">333</span><span class="p">),</span> <span class="n">a</span><span class="o">.</span><span class="n">count</span><span class="p">(</span><span class="mf">66.25</span><span class="p">),</span> <span class="n">a</span><span class="o">.</span><span class="n">count</span><span class="p">(</span><span class="s">&#39;x&#39;</span><span class="p">)</span>
+<span class="go">2 1 0</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">a</span><span class="o">.</span><span class="n">insert</span><span class="p">(</span><span class="mf">2</span><span class="p">,</span> <span class="o">-</span><span class="mf">1</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">a</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="mf">333</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">a</span>
+<span class="go">[66.25, 333, -1, 333, 1, 1234.5, 333]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">a</span><span class="o">.</span><span class="n">index</span><span class="p">(</span><span class="mf">333</span><span class="p">)</span>
+<span class="go">1</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">a</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="mf">333</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">a</span>
+<span class="go">[66.25, -1, 333, 1, 1234.5, 333]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">a</span><span class="o">.</span><span class="n">reverse</span><span class="p">()</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">a</span>
+<span class="go">[333, 1234.5, 1, 333, -1, 66.25]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">a</span><span class="o">.</span><span class="n">sort</span><span class="p">()</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">a</span>
+<span class="go">[-1, 1, 66.25, 333, 333, 1234.5]</span>
+</pre></div>
+</div>
+<div class="section" id="using-lists-as-stacks">
+<span id="tut-lists-as-stacks"></span><h3>5.1.1. Using Lists as Stacks<a class="headerlink" href="#using-lists-as-stacks" title="Permalink to this headline">¶</a></h3>
+<p>The list methods make it very easy to use a list as a stack, where the last
+element added is the first element retrieved (&#8220;last-in, first-out&#8221;). To add an
+item to the top of the stack, use <tt class="xref docutils literal"><span class="pre">append()</span></tt>. To retrieve an item from the
+top of the stack, use <tt class="xref docutils literal"><span class="pre">pop()</span></tt> without an explicit index. For example:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">stack</span> <span class="o">=</span> <span class="p">[</span><span class="mf">3</span><span class="p">,</span> <span class="mf">4</span><span class="p">,</span> <span class="mf">5</span><span class="p">]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">stack</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="mf">6</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">stack</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="mf">7</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">stack</span>
+<span class="go">[3, 4, 5, 6, 7]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">stack</span><span class="o">.</span><span class="n">pop</span><span class="p">()</span>
+<span class="go">7</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">stack</span>
+<span class="go">[3, 4, 5, 6]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">stack</span><span class="o">.</span><span class="n">pop</span><span class="p">()</span>
+<span class="go">6</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">stack</span><span class="o">.</span><span class="n">pop</span><span class="p">()</span>
+<span class="go">5</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">stack</span>
+<span class="go">[3, 4]</span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="using-lists-as-queues">
+<span id="tut-lists-as-queues"></span><h3>5.1.2. Using Lists as Queues<a class="headerlink" href="#using-lists-as-queues" title="Permalink to this headline">¶</a></h3>
+<p>You can also use a list conveniently as a queue, where the first element added
+is the first element retrieved (&#8220;first-in, first-out&#8221;). To add an item to the
+back of the queue, use <tt class="xref docutils literal"><span class="pre">append()</span></tt>. To retrieve an item from the front of
+the queue, use <tt class="xref docutils literal"><span class="pre">pop()</span></tt> with <tt class="docutils literal"><span class="pre">0</span></tt> as the index. For example:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">queue</span> <span class="o">=</span> <span class="p">[</span><span class="s">&quot;Eric&quot;</span><span class="p">,</span> <span class="s">&quot;John&quot;</span><span class="p">,</span> <span class="s">&quot;Michael&quot;</span><span class="p">]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">queue</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s">&quot;Terry&quot;</span><span class="p">)</span> <span class="c"># Terry arrives</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">queue</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s">&quot;Graham&quot;</span><span class="p">)</span> <span class="c"># Graham arrives</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">queue</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="mf">0</span><span class="p">)</span>
+<span class="go">&#39;Eric&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">queue</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="mf">0</span><span class="p">)</span>
+<span class="go">&#39;John&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">queue</span>
+<span class="go">[&#39;Michael&#39;, &#39;Terry&#39;, &#39;Graham&#39;]</span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="functional-programming-tools">
+<span id="tut-functional"></span><h3>5.1.3. Functional Programming Tools<a class="headerlink" href="#functional-programming-tools" title="Permalink to this headline">¶</a></h3>
+<p>There are three built-in functions that are very useful when used with lists:
+<a title="filter" class="reference external" href="../library/functions.html#filter"><tt class="xref docutils literal"><span class="pre">filter()</span></tt></a>, <a title="map" class="reference external" href="../library/functions.html#map"><tt class="xref docutils literal"><span class="pre">map()</span></tt></a>, and <a title="reduce" class="reference external" href="../library/functions.html#reduce"><tt class="xref docutils literal"><span class="pre">reduce()</span></tt></a>.</p>
+<p><tt class="docutils literal"><span class="pre">filter(function,</span> <span class="pre">sequence)</span></tt> returns a sequence consisting of those items from
+the sequence for which <tt class="docutils literal"><span class="pre">function(item)</span></tt> is true. If <em>sequence</em> is a
+<tt class="xref docutils literal"><span class="pre">string</span></tt> or <a title="tuple" class="reference external" href="../library/functions.html#tuple"><tt class="xref docutils literal"><span class="pre">tuple</span></tt></a>, the result will be of the same type;
+otherwise, it is always a <a title="list" class="reference external" href="../library/functions.html#list"><tt class="xref docutils literal"><span class="pre">list</span></tt></a>. For example, to compute some primes:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">def</span> <span class="nf">f</span><span class="p">(</span><span class="n">x</span><span class="p">):</span> <span class="k">return</span> <span class="n">x</span> <span class="o">%</span> <span class="mf">2</span> <span class="o">!=</span> <span class="mf">0</span> <span class="ow">and</span> <span class="n">x</span> <span class="o">%</span> <span class="mf">3</span> <span class="o">!=</span> <span class="mf">0</span>
+<span class="gp">...</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">filter</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="nb">range</span><span class="p">(</span><span class="mf">2</span><span class="p">,</span> <span class="mf">25</span><span class="p">))</span>
+<span class="go">[5, 7, 11, 13, 17, 19, 23]</span>
+</pre></div>
+</div>
+<p><tt class="docutils literal"><span class="pre">map(function,</span> <span class="pre">sequence)</span></tt> calls <tt class="docutils literal"><span class="pre">function(item)</span></tt> for each of the sequence&#8217;s
+items and returns a list of the return values. For example, to compute some
+cubes:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">def</span> <span class="nf">cube</span><span class="p">(</span><span class="n">x</span><span class="p">):</span> <span class="k">return</span> <span class="n">x</span><span class="o">*</span><span class="n">x</span><span class="o">*</span><span class="n">x</span>
+<span class="gp">...</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">map</span><span class="p">(</span><span class="n">cube</span><span class="p">,</span> <span class="nb">range</span><span class="p">(</span><span class="mf">1</span><span class="p">,</span> <span class="mf">11</span><span class="p">))</span>
+<span class="go">[1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]</span>
+</pre></div>
+</div>
+<p>More than one sequence may be passed; the function must then have as many
+arguments as there are sequences and is called with the corresponding item from
+each sequence (or <tt class="xref docutils literal"><span class="pre">None</span></tt> if some sequence is shorter than another). For
+example:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">seq</span> <span class="o">=</span> <span class="nb">range</span><span class="p">(</span><span class="mf">8</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">def</span> <span class="nf">add</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">):</span> <span class="k">return</span> <span class="n">x</span><span class="o">+</span><span class="n">y</span>
+<span class="gp">...</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">map</span><span class="p">(</span><span class="n">add</span><span class="p">,</span> <span class="n">seq</span><span class="p">,</span> <span class="n">seq</span><span class="p">)</span>
+<span class="go">[0, 2, 4, 6, 8, 10, 12, 14]</span>
+</pre></div>
+</div>
+<p><tt class="docutils literal"><span class="pre">reduce(function,</span> <span class="pre">sequence)</span></tt> returns a single value constructed by calling the
+binary function <em>function</em> on the first two items of the sequence, then on the
+result and the next item, and so on. For example, to compute the sum of the
+numbers 1 through 10:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">def</span> <span class="nf">add</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">):</span> <span class="k">return</span> <span class="n">x</span><span class="o">+</span><span class="n">y</span>
+<span class="gp">...</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">reduce</span><span class="p">(</span><span class="n">add</span><span class="p">,</span> <span class="nb">range</span><span class="p">(</span><span class="mf">1</span><span class="p">,</span> <span class="mf">11</span><span class="p">))</span>
+<span class="go">55</span>
+</pre></div>
+</div>
+<p>If there&#8217;s only one item in the sequence, its value is returned; if the sequence
+is empty, an exception is raised.</p>
+<p>A third argument can be passed to indicate the starting value. In this case the
+starting value is returned for an empty sequence, and the function is first
+applied to the starting value and the first sequence item, then to the result
+and the next item, and so on. For example,</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">def</span> <span class="nf">sum</span><span class="p">(</span><span class="n">seq</span><span class="p">):</span>
+<span class="gp">... </span> <span class="k">def</span> <span class="nf">add</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">):</span> <span class="k">return</span> <span class="n">x</span><span class="o">+</span><span class="n">y</span>
+<span class="gp">... </span> <span class="k">return</span> <span class="nb">reduce</span><span class="p">(</span><span class="n">add</span><span class="p">,</span> <span class="n">seq</span><span class="p">,</span> <span class="mf">0</span><span class="p">)</span>
+<span class="gp">...</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">sum</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="mf">1</span><span class="p">,</span> <span class="mf">11</span><span class="p">))</span>
+<span class="go">55</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">sum</span><span class="p">([])</span>
+<span class="go">0</span>
+</pre></div>
+</div>
+<p>Don&#8217;t use this example&#8217;s definition of <a title="sum" class="reference external" href="../library/functions.html#sum"><tt class="xref docutils literal"><span class="pre">sum()</span></tt></a>: since summing numbers is
+such a common need, a built-in function <tt class="docutils literal"><span class="pre">sum(sequence)</span></tt> is already provided,
+and works exactly like this.</p>
+<p>
+<span class="versionmodified">New in version 2.3.</span></p>
+</div>
+<div class="section" id="list-comprehensions">
+<h3>5.1.4. List Comprehensions<a class="headerlink" href="#list-comprehensions" title="Permalink to this headline">¶</a></h3>
+<p>List comprehensions provide a concise way to create lists without resorting to
+use of <a title="map" class="reference external" href="../library/functions.html#map"><tt class="xref docutils literal"><span class="pre">map()</span></tt></a>, <a title="filter" class="reference external" href="../library/functions.html#filter"><tt class="xref docutils literal"><span class="pre">filter()</span></tt></a> and/or <a class="reference external" href="../reference/expressions.html#lambda"><tt class="xref docutils literal"><span class="pre">lambda</span></tt></a>. The resulting list
+definition tends often to be clearer than lists built using those constructs.
+Each list comprehension consists of an expression followed by a <a class="reference external" href="../reference/compound_stmts.html#for"><tt class="xref docutils literal"><span class="pre">for</span></tt></a>
+clause, then zero or more <a class="reference external" href="../reference/compound_stmts.html#for"><tt class="xref docutils literal"><span class="pre">for</span></tt></a> or <a class="reference external" href="../reference/compound_stmts.html#if"><tt class="xref docutils literal"><span class="pre">if</span></tt></a> clauses. The result
+will be a list resulting from evaluating the expression in the context of the
+<a class="reference external" href="../reference/compound_stmts.html#for"><tt class="xref docutils literal"><span class="pre">for</span></tt></a> and <a class="reference external" href="../reference/compound_stmts.html#if"><tt class="xref docutils literal"><span class="pre">if</span></tt></a> clauses which follow it. If the expression
+would evaluate to a tuple, it must be parenthesized.</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">freshfruit</span> <span class="o">=</span> <span class="p">[</span><span class="s">&#39; banana&#39;</span><span class="p">,</span> <span class="s">&#39; loganberry &#39;</span><span class="p">,</span> <span class="s">&#39;passion fruit &#39;</span><span class="p">]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="p">[</span><span class="n">weapon</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span> <span class="k">for</span> <span class="n">weapon</span> <span class="ow">in</span> <span class="n">freshfruit</span><span class="p">]</span>
+<span class="go">[&#39;banana&#39;, &#39;loganberry&#39;, &#39;passion fruit&#39;]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">vec</span> <span class="o">=</span> <span class="p">[</span><span class="mf">2</span><span class="p">,</span> <span class="mf">4</span><span class="p">,</span> <span class="mf">6</span><span class="p">]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="p">[</span><span class="mf">3</span><span class="o">*</span><span class="n">x</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">vec</span><span class="p">]</span>
+<span class="go">[6, 12, 18]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="p">[</span><span class="mf">3</span><span class="o">*</span><span class="n">x</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">vec</span> <span class="k">if</span> <span class="n">x</span> <span class="o">&gt;</span> <span class="mf">3</span><span class="p">]</span>
+<span class="go">[12, 18]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="p">[</span><span class="mf">3</span><span class="o">*</span><span class="n">x</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">vec</span> <span class="k">if</span> <span class="n">x</span> <span class="o">&lt;</span> <span class="mf">2</span><span class="p">]</span>
+<span class="go">[]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="p">[[</span><span class="n">x</span><span class="p">,</span><span class="n">x</span><span class="o">**</span><span class="mf">2</span><span class="p">]</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">vec</span><span class="p">]</span>
+<span class="go">[[2, 4], [4, 16], [6, 36]]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="p">[</span><span class="n">x</span><span class="p">,</span> <span class="n">x</span><span class="o">**</span><span class="mf">2</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">vec</span><span class="p">]</span> <span class="c"># error - parens required for tuples</span>
+<span class="go"> File &quot;&lt;stdin&gt;&quot;, line 1, in ?</span>
+<span class="go"> [x, x**2 for x in vec]</span>
+<span class="go"> ^</span>
+<span class="go">SyntaxError: invalid syntax</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="p">[(</span><span class="n">x</span><span class="p">,</span> <span class="n">x</span><span class="o">**</span><span class="mf">2</span><span class="p">)</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">vec</span><span class="p">]</span>
+<span class="go">[(2, 4), (4, 16), (6, 36)]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">vec1</span> <span class="o">=</span> <span class="p">[</span><span class="mf">2</span><span class="p">,</span> <span class="mf">4</span><span class="p">,</span> <span class="mf">6</span><span class="p">]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">vec2</span> <span class="o">=</span> <span class="p">[</span><span class="mf">4</span><span class="p">,</span> <span class="mf">3</span><span class="p">,</span> <span class="o">-</span><span class="mf">9</span><span class="p">]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="p">[</span><span class="n">x</span><span class="o">*</span><span class="n">y</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">vec1</span> <span class="k">for</span> <span class="n">y</span> <span class="ow">in</span> <span class="n">vec2</span><span class="p">]</span>
+<span class="go">[8, 6, -18, 16, 12, -36, 24, 18, -54]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="p">[</span><span class="n">x</span><span class="o">+</span><span class="n">y</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">vec1</span> <span class="k">for</span> <span class="n">y</span> <span class="ow">in</span> <span class="n">vec2</span><span class="p">]</span>
+<span class="go">[6, 5, -7, 8, 7, -5, 10, 9, -3]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="p">[</span><span class="n">vec1</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">*</span><span class="n">vec2</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">vec1</span><span class="p">))]</span>
+<span class="go">[8, 12, -54]</span>
+</pre></div>
+</div>
+<p>List comprehensions are much more flexible than <a title="map" class="reference external" href="../library/functions.html#map"><tt class="xref docutils literal"><span class="pre">map()</span></tt></a> and can be applied
+to complex expressions and nested functions:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="p">[</span><span class="nb">str</span><span class="p">(</span><span class="nb">round</span><span class="p">(</span><span class="mf">355</span><span class="o">/</span><span class="mf">113.0</span><span class="p">,</span> <span class="n">i</span><span class="p">))</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mf">1</span><span class="p">,</span><span class="mf">6</span><span class="p">)]</span>
+<span class="go">[&#39;3.1&#39;, &#39;3.14&#39;, &#39;3.142&#39;, &#39;3.1416&#39;, &#39;3.14159&#39;]</span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="nested-list-comprehensions">
+<h3>5.1.5. Nested List Comprehensions<a class="headerlink" href="#nested-list-comprehensions" title="Permalink to this headline">¶</a></h3>
+<p>If you&#8217;ve got the stomach for it, list comprehensions can be nested. They are a
+powerful tool but &#8211; like all powerful tools &#8211; they need to be used carefully,
+if at all.</p>
+<p>Consider the following example of a 3x3 matrix held as a list containing three
+lists, one list per row:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">mat</span> <span class="o">=</span> <span class="p">[</span>
+<span class="gp">... </span> <span class="p">[</span><span class="mf">1</span><span class="p">,</span> <span class="mf">2</span><span class="p">,</span> <span class="mf">3</span><span class="p">],</span>
+<span class="gp">... </span> <span class="p">[</span><span class="mf">4</span><span class="p">,</span> <span class="mf">5</span><span class="p">,</span> <span class="mf">6</span><span class="p">],</span>
+<span class="gp">... </span> <span class="p">[</span><span class="mf">7</span><span class="p">,</span> <span class="mf">8</span><span class="p">,</span> <span class="mf">9</span><span class="p">],</span>
+<span class="gp">... </span> <span class="p">]</span>
+</pre></div>
+</div>
+<p>Now, if you wanted to swap rows and columns, you could use a list
+comprehension:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">print</span> <span class="p">[[</span><span class="n">row</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">mat</span><span class="p">]</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="p">[</span><span class="mf">0</span><span class="p">,</span> <span class="mf">1</span><span class="p">,</span> <span class="mf">2</span><span class="p">]]</span>
+<span class="go">[[1, 4, 7], [2, 5, 8], [3, 6, 9]]</span>
+</pre></div>
+</div>
+<p>Special care has to be taken for the <em>nested</em> list comprehension:</p>
+<blockquote>
+To avoid apprehension when nesting list comprehensions, read from right to
+left.</blockquote>
+<p>A more verbose version of this snippet shows the flow explicitly:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="p">[</span><span class="mf">0</span><span class="p">,</span> <span class="mf">1</span><span class="p">,</span> <span class="mf">2</span><span class="p">]:</span>
+ <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">mat</span><span class="p">:</span>
+ <span class="k">print</span> <span class="n">row</span><span class="p">[</span><span class="n">i</span><span class="p">],</span>
+ <span class="k">print</span>
+</pre></div>
+</div>
+<p>In real world, you should prefer built-in functions to complex flow statements.
+The <a title="zip" class="reference external" href="../library/functions.html#zip"><tt class="xref docutils literal"><span class="pre">zip()</span></tt></a> function would do a great job for this use case:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="nb">zip</span><span class="p">(</span><span class="o">*</span><span class="n">mat</span><span class="p">)</span>
+<span class="go">[(1, 4, 7), (2, 5, 8), (3, 6, 9)]</span>
+</pre></div>
+</div>
+<p>See <a class="reference external" href="controlflow.html#tut-unpacking-arguments"><em>Unpacking Argument Lists</em></a> for details on the asterisk in this line.</p>
+</div>
+</div>
+<div class="section" id="the-del-statement">
+<span id="tut-del"></span><h2>5.2. The <a class="reference external" href="../reference/simple_stmts.html#del"><tt class="xref docutils literal"><span class="pre">del</span></tt></a> statement<a class="headerlink" href="#the-del-statement" title="Permalink to this headline">¶</a></h2>
+<p>There is a way to remove an item from a list given its index instead of its
+value: the <a class="reference external" href="../reference/simple_stmts.html#del"><tt class="xref docutils literal"><span class="pre">del</span></tt></a> statement. This differs from the <tt class="xref docutils literal"><span class="pre">pop()</span></tt> method
+which returns a value. The <a class="reference external" href="../reference/simple_stmts.html#del"><tt class="xref docutils literal"><span class="pre">del</span></tt></a> statement can also be used to remove
+slices from a list or clear the entire list (which we did earlier by assignment
+of an empty list to the slice). For example:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">a</span> <span class="o">=</span> <span class="p">[</span><span class="o">-</span><span class="mf">1</span><span class="p">,</span> <span class="mf">1</span><span class="p">,</span> <span class="mf">66.25</span><span class="p">,</span> <span class="mf">333</span><span class="p">,</span> <span class="mf">333</span><span class="p">,</span> <span class="mf">1234.5</span><span class="p">]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">del</span> <span class="n">a</span><span class="p">[</span><span class="mf">0</span><span class="p">]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">a</span>
+<span class="go">[1, 66.25, 333, 333, 1234.5]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">del</span> <span class="n">a</span><span class="p">[</span><span class="mf">2</span><span class="p">:</span><span class="mf">4</span><span class="p">]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">a</span>
+<span class="go">[1, 66.25, 1234.5]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">del</span> <span class="n">a</span><span class="p">[:]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">a</span>
+<span class="go">[]</span>
+</pre></div>
+</div>
+<p><a class="reference external" href="../reference/simple_stmts.html#del"><tt class="xref docutils literal"><span class="pre">del</span></tt></a> can also be used to delete entire variables:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">del</span> <span class="n">a</span>
+</pre></div>
+</div>
+<p>Referencing the name <tt class="docutils literal"><span class="pre">a</span></tt> hereafter is an error (at least until another value
+is assigned to it). We&#8217;ll find other uses for <a class="reference external" href="../reference/simple_stmts.html#del"><tt class="xref docutils literal"><span class="pre">del</span></tt></a> later.</p>
+</div>
+<div class="section" id="tuples-and-sequences">
+<span id="tut-tuples"></span><h2>5.3. Tuples and Sequences<a class="headerlink" href="#tuples-and-sequences" title="Permalink to this headline">¶</a></h2>
+<p>We saw that lists and strings have many common properties, such as indexing and
+slicing operations. They are two examples of <em>sequence</em> data types (see
+<a class="reference external" href="../library/stdtypes.html#typesseq"><em>Sequence Types &#8212; str, unicode, list, tuple, buffer, xrange</em></a>). Since Python is an evolving language, other sequence data
+types may be added. There is also another standard sequence data type: the
+<em>tuple</em>.</p>
+<p>A tuple consists of a number of values separated by commas, for instance:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">t</span> <span class="o">=</span> <span class="mf">12345</span><span class="p">,</span> <span class="mf">54321</span><span class="p">,</span> <span class="s">&#39;hello!&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">t</span><span class="p">[</span><span class="mf">0</span><span class="p">]</span>
+<span class="go">12345</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">t</span>
+<span class="go">(12345, 54321, &#39;hello!&#39;)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="c"># Tuples may be nested:</span>
+<span class="gp">... </span><span class="n">u</span> <span class="o">=</span> <span class="n">t</span><span class="p">,</span> <span class="p">(</span><span class="mf">1</span><span class="p">,</span> <span class="mf">2</span><span class="p">,</span> <span class="mf">3</span><span class="p">,</span> <span class="mf">4</span><span class="p">,</span> <span class="mf">5</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">u</span>
+<span class="go">((12345, 54321, &#39;hello!&#39;), (1, 2, 3, 4, 5))</span>
+</pre></div>
+</div>
+<p>As you see, on output tuples are always enclosed in parentheses, so that nested
+tuples are interpreted correctly; they may be input with or without surrounding
+parentheses, although often parentheses are necessary anyway (if the tuple is
+part of a larger expression).</p>
+<p>Tuples have many uses. For example: (x, y) coordinate pairs, employee records
+from a database, etc. Tuples, like strings, are immutable: it is not possible
+to assign to the individual items of a tuple (you can simulate much of the same
+effect with slicing and concatenation, though). It is also possible to create
+tuples which contain mutable objects, such as lists.</p>
+<p>A special problem is the construction of tuples containing 0 or 1 items: the
+syntax has some extra quirks to accommodate these. Empty tuples are constructed
+by an empty pair of parentheses; a tuple with one item is constructed by
+following a value with a comma (it is not sufficient to enclose a single value
+in parentheses). Ugly, but effective. For example:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">empty</span> <span class="o">=</span> <span class="p">()</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">singleton</span> <span class="o">=</span> <span class="s">&#39;hello&#39;</span><span class="p">,</span> <span class="c"># &lt;-- note trailing comma</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">len</span><span class="p">(</span><span class="n">empty</span><span class="p">)</span>
+<span class="go">0</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">len</span><span class="p">(</span><span class="n">singleton</span><span class="p">)</span>
+<span class="go">1</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">singleton</span>
+<span class="go">(&#39;hello&#39;,)</span>
+</pre></div>
+</div>
+<p>The statement <tt class="docutils literal"><span class="pre">t</span> <span class="pre">=</span> <span class="pre">12345,</span> <span class="pre">54321,</span> <span class="pre">'hello!'</span></tt> is an example of <em>tuple packing</em>:
+the values <tt class="docutils literal"><span class="pre">12345</span></tt>, <tt class="docutils literal"><span class="pre">54321</span></tt> and <tt class="docutils literal"><span class="pre">'hello!'</span></tt> are packed together in a tuple.
+The reverse operation is also possible:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">z</span> <span class="o">=</span> <span class="n">t</span>
+</pre></div>
+</div>
+<p>This is called, appropriately enough, <em>sequence unpacking</em> and works for any
+sequence on the right-hand side. Sequence unpacking requires the list of
+variables on the left to have the same number of elements as the length of the
+sequence. Note that multiple assignment is really just a combination of tuple
+packing and sequence unpacking.</p>
+</div>
+<div class="section" id="sets">
+<span id="tut-sets"></span><h2>5.4. Sets<a class="headerlink" href="#sets" title="Permalink to this headline">¶</a></h2>
+<p>Python also includes a data type for <em>sets</em>. A set is an unordered collection
+with no duplicate elements. Basic uses include membership testing and
+eliminating duplicate entries. Set objects also support mathematical operations
+like union, intersection, difference, and symmetric difference.</p>
+<p>Here is a brief demonstration:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">basket</span> <span class="o">=</span> <span class="p">[</span><span class="s">&#39;apple&#39;</span><span class="p">,</span> <span class="s">&#39;orange&#39;</span><span class="p">,</span> <span class="s">&#39;apple&#39;</span><span class="p">,</span> <span class="s">&#39;pear&#39;</span><span class="p">,</span> <span class="s">&#39;orange&#39;</span><span class="p">,</span> <span class="s">&#39;banana&#39;</span><span class="p">]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">fruit</span> <span class="o">=</span> <span class="n">set</span><span class="p">(</span><span class="n">basket</span><span class="p">)</span> <span class="c"># create a set without duplicates</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">fruit</span>
+<span class="go">set([&#39;orange&#39;, &#39;pear&#39;, &#39;apple&#39;, &#39;banana&#39;])</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="s">&#39;orange&#39;</span> <span class="ow">in</span> <span class="n">fruit</span> <span class="c"># fast membership testing</span>
+<span class="go">True</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="s">&#39;crabgrass&#39;</span> <span class="ow">in</span> <span class="n">fruit</span>
+<span class="go">False</span>
+
+<span class="gp">&gt;&gt;&gt; </span><span class="c"># Demonstrate set operations on unique letters from two words</span>
+<span class="gp">...</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">a</span> <span class="o">=</span> <span class="n">set</span><span class="p">(</span><span class="s">&#39;abracadabra&#39;</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">b</span> <span class="o">=</span> <span class="n">set</span><span class="p">(</span><span class="s">&#39;alacazam&#39;</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">a</span> <span class="c"># unique letters in a</span>
+<span class="go">set([&#39;a&#39;, &#39;r&#39;, &#39;b&#39;, &#39;c&#39;, &#39;d&#39;])</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">a</span> <span class="o">-</span> <span class="n">b</span> <span class="c"># letters in a but not in b</span>
+<span class="go">set([&#39;r&#39;, &#39;d&#39;, &#39;b&#39;])</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">a</span> <span class="o">|</span> <span class="n">b</span> <span class="c"># letters in either a or b</span>
+<span class="go">set([&#39;a&#39;, &#39;c&#39;, &#39;r&#39;, &#39;d&#39;, &#39;b&#39;, &#39;m&#39;, &#39;z&#39;, &#39;l&#39;])</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">a</span> <span class="o">&amp;</span> <span class="n">b</span> <span class="c"># letters in both a and b</span>
+<span class="go">set([&#39;a&#39;, &#39;c&#39;])</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">a</span> <span class="o">^</span> <span class="n">b</span> <span class="c"># letters in a or b but not both</span>
+<span class="go">set([&#39;r&#39;, &#39;d&#39;, &#39;b&#39;, &#39;m&#39;, &#39;z&#39;, &#39;l&#39;])</span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="dictionaries">
+<span id="tut-dictionaries"></span><h2>5.5. Dictionaries<a class="headerlink" href="#dictionaries" title="Permalink to this headline">¶</a></h2>
+<p>Another useful data type built into Python is the <em>dictionary</em> (see
+<a class="reference external" href="../library/stdtypes.html#typesmapping"><em>Mapping Types &#8212; dict</em></a>). Dictionaries are sometimes found in other languages as
+&#8220;associative memories&#8221; or &#8220;associative arrays&#8221;. Unlike sequences, which are
+indexed by a range of numbers, dictionaries are indexed by <em>keys</em>, which can be
+any immutable type; strings and numbers can always be keys. Tuples can be used
+as keys if they contain only strings, numbers, or tuples; if a tuple contains
+any mutable object either directly or indirectly, it cannot be used as a key.
+You can&#8217;t use lists as keys, since lists can be modified in place using index
+assignments, slice assignments, or methods like <tt class="xref docutils literal"><span class="pre">append()</span></tt> and
+<tt class="xref docutils literal"><span class="pre">extend()</span></tt>.</p>
+<p>It is best to think of a dictionary as an unordered set of <em>key: value</em> pairs,
+with the requirement that the keys are unique (within one dictionary). A pair of
+braces creates an empty dictionary: <tt class="docutils literal"><span class="pre">{}</span></tt>. Placing a comma-separated list of
+key:value pairs within the braces adds initial key:value pairs to the
+dictionary; this is also the way dictionaries are written on output.</p>
+<p>The main operations on a dictionary are storing a value with some key and
+extracting the value given the key. It is also possible to delete a key:value
+pair with <tt class="docutils literal"><span class="pre">del</span></tt>. If you store using a key that is already in use, the old
+value associated with that key is forgotten. It is an error to extract a value
+using a non-existent key.</p>
+<p>The <tt class="xref docutils literal"><span class="pre">keys()</span></tt> method of a dictionary object returns a list of all the keys
+used in the dictionary, in arbitrary order (if you want it sorted, just apply
+the <tt class="xref docutils literal"><span class="pre">sort()</span></tt> method to the list of keys). To check whether a single key is
+in the dictionary, use the <a class="reference external" href="../reference/expressions.html#in"><tt class="xref docutils literal"><span class="pre">in</span></tt></a> keyword.</p>
+<p>Here is a small example using a dictionary:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">tel</span> <span class="o">=</span> <span class="p">{</span><span class="s">&#39;jack&#39;</span><span class="p">:</span> <span class="mf">4098</span><span class="p">,</span> <span class="s">&#39;sape&#39;</span><span class="p">:</span> <span class="mf">4139</span><span class="p">}</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">tel</span><span class="p">[</span><span class="s">&#39;guido&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="mf">4127</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">tel</span>
+<span class="go">{&#39;sape&#39;: 4139, &#39;guido&#39;: 4127, &#39;jack&#39;: 4098}</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">tel</span><span class="p">[</span><span class="s">&#39;jack&#39;</span><span class="p">]</span>
+<span class="go">4098</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">del</span> <span class="n">tel</span><span class="p">[</span><span class="s">&#39;sape&#39;</span><span class="p">]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">tel</span><span class="p">[</span><span class="s">&#39;irv&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="mf">4127</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">tel</span>
+<span class="go">{&#39;guido&#39;: 4127, &#39;irv&#39;: 4127, &#39;jack&#39;: 4098}</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">tel</span><span class="o">.</span><span class="n">keys</span><span class="p">()</span>
+<span class="go">[&#39;guido&#39;, &#39;irv&#39;, &#39;jack&#39;]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="s">&#39;guido&#39;</span> <span class="ow">in</span> <span class="n">tel</span>
+<span class="go">True</span>
+</pre></div>
+</div>
+<p>The <a title="dict" class="reference external" href="../library/stdtypes.html#dict"><tt class="xref docutils literal"><span class="pre">dict()</span></tt></a> constructor builds dictionaries directly from lists of
+key-value pairs stored as tuples. When the pairs form a pattern, list
+comprehensions can compactly specify the key-value list.</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="nb">dict</span><span class="p">([(</span><span class="s">&#39;sape&#39;</span><span class="p">,</span> <span class="mf">4139</span><span class="p">),</span> <span class="p">(</span><span class="s">&#39;guido&#39;</span><span class="p">,</span> <span class="mf">4127</span><span class="p">),</span> <span class="p">(</span><span class="s">&#39;jack&#39;</span><span class="p">,</span> <span class="mf">4098</span><span class="p">)])</span>
+<span class="go">{&#39;sape&#39;: 4139, &#39;jack&#39;: 4098, &#39;guido&#39;: 4127}</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">dict</span><span class="p">([(</span><span class="n">x</span><span class="p">,</span> <span class="n">x</span><span class="o">**</span><span class="mf">2</span><span class="p">)</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="p">(</span><span class="mf">2</span><span class="p">,</span> <span class="mf">4</span><span class="p">,</span> <span class="mf">6</span><span class="p">)])</span> <span class="c"># use a list comprehension</span>
+<span class="go">{2: 4, 4: 16, 6: 36}</span>
+</pre></div>
+</div>
+<p>Later in the tutorial, we will learn about Generator Expressions which are even
+better suited for the task of supplying key-values pairs to the <a title="dict" class="reference external" href="../library/stdtypes.html#dict"><tt class="xref docutils literal"><span class="pre">dict()</span></tt></a>
+constructor.</p>
+<p>When the keys are simple strings, it is sometimes easier to specify pairs using
+keyword arguments:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="nb">dict</span><span class="p">(</span><span class="n">sape</span><span class="o">=</span><span class="mf">4139</span><span class="p">,</span> <span class="n">guido</span><span class="o">=</span><span class="mf">4127</span><span class="p">,</span> <span class="n">jack</span><span class="o">=</span><span class="mf">4098</span><span class="p">)</span>
+<span class="go">{&#39;sape&#39;: 4139, &#39;jack&#39;: 4098, &#39;guido&#39;: 4127}</span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="looping-techniques">
+<span id="tut-loopidioms"></span><h2>5.6. Looping Techniques<a class="headerlink" href="#looping-techniques" title="Permalink to this headline">¶</a></h2>
+<p>When looping through dictionaries, the key and corresponding value can be
+retrieved at the same time using the <tt class="xref docutils literal"><span class="pre">iteritems()</span></tt> method.</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">knights</span> <span class="o">=</span> <span class="p">{</span><span class="s">&#39;gallahad&#39;</span><span class="p">:</span> <span class="s">&#39;the pure&#39;</span><span class="p">,</span> <span class="s">&#39;robin&#39;</span><span class="p">:</span> <span class="s">&#39;the brave&#39;</span><span class="p">}</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">knights</span><span class="o">.</span><span class="n">iteritems</span><span class="p">():</span>
+<span class="gp">... </span> <span class="k">print</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span>
+<span class="gp">...</span>
+<span class="go">gallahad the pure</span>
+<span class="go">robin the brave</span>
+</pre></div>
+</div>
+<p>When looping through a sequence, the position index and corresponding value can
+be retrieved at the same time using the <a title="enumerate" class="reference external" href="../library/functions.html#enumerate"><tt class="xref docutils literal"><span class="pre">enumerate()</span></tt></a> function.</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">([</span><span class="s">&#39;tic&#39;</span><span class="p">,</span> <span class="s">&#39;tac&#39;</span><span class="p">,</span> <span class="s">&#39;toe&#39;</span><span class="p">]):</span>
+<span class="gp">... </span> <span class="k">print</span> <span class="n">i</span><span class="p">,</span> <span class="n">v</span>
+<span class="gp">...</span>
+<span class="go">0 tic</span>
+<span class="go">1 tac</span>
+<span class="go">2 toe</span>
+</pre></div>
+</div>
+<p>To loop over two or more sequences at the same time, the entries can be paired
+with the <a title="zip" class="reference external" href="../library/functions.html#zip"><tt class="xref docutils literal"><span class="pre">zip()</span></tt></a> function.</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">questions</span> <span class="o">=</span> <span class="p">[</span><span class="s">&#39;name&#39;</span><span class="p">,</span> <span class="s">&#39;quest&#39;</span><span class="p">,</span> <span class="s">&#39;favorite color&#39;</span><span class="p">]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">answers</span> <span class="o">=</span> <span class="p">[</span><span class="s">&#39;lancelot&#39;</span><span class="p">,</span> <span class="s">&#39;the holy grail&#39;</span><span class="p">,</span> <span class="s">&#39;blue&#39;</span><span class="p">]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">for</span> <span class="n">q</span><span class="p">,</span> <span class="n">a</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">questions</span><span class="p">,</span> <span class="n">answers</span><span class="p">):</span>
+<span class="gp">... </span> <span class="k">print</span> <span class="s">&#39;What is your {0}? It is {1}.&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">q</span><span class="p">,</span> <span class="n">a</span><span class="p">)</span>
+<span class="gp">...</span>
+<span class="go">What is your name? It is lancelot.</span>
+<span class="go">What is your quest? It is the holy grail.</span>
+<span class="go">What is your favorite color? It is blue.</span>
+</pre></div>
+</div>
+<p>To loop over a sequence in reverse, first specify the sequence in a forward
+direction and then call the <a title="reversed" class="reference external" href="../library/functions.html#reversed"><tt class="xref docutils literal"><span class="pre">reversed()</span></tt></a> function.</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">reversed</span><span class="p">(</span><span class="nb">xrange</span><span class="p">(</span><span class="mf">1</span><span class="p">,</span><span class="mf">10</span><span class="p">,</span><span class="mf">2</span><span class="p">)):</span>
+<span class="gp">... </span> <span class="k">print</span> <span class="n">i</span>
+<span class="gp">...</span>
+<span class="go">9</span>
+<span class="go">7</span>
+<span class="go">5</span>
+<span class="go">3</span>
+<span class="go">1</span>
+</pre></div>
+</div>
+<p>To loop over a sequence in sorted order, use the <a title="sorted" class="reference external" href="../library/functions.html#sorted"><tt class="xref docutils literal"><span class="pre">sorted()</span></tt></a> function which
+returns a new sorted list while leaving the source unaltered.</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">basket</span> <span class="o">=</span> <span class="p">[</span><span class="s">&#39;apple&#39;</span><span class="p">,</span> <span class="s">&#39;orange&#39;</span><span class="p">,</span> <span class="s">&#39;apple&#39;</span><span class="p">,</span> <span class="s">&#39;pear&#39;</span><span class="p">,</span> <span class="s">&#39;orange&#39;</span><span class="p">,</span> <span class="s">&#39;banana&#39;</span><span class="p">]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">for</span> <span class="n">f</span> <span class="ow">in</span> <span class="n">sorted</span><span class="p">(</span><span class="n">set</span><span class="p">(</span><span class="n">basket</span><span class="p">)):</span>
+<span class="gp">... </span> <span class="k">print</span> <span class="n">f</span>
+<span class="gp">...</span>
+<span class="go">apple</span>
+<span class="go">banana</span>
+<span class="go">orange</span>
+<span class="go">pear</span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="more-on-conditions">
+<span id="tut-conditions"></span><h2>5.7. More on Conditions<a class="headerlink" href="#more-on-conditions" title="Permalink to this headline">¶</a></h2>
+<p>The conditions used in <tt class="docutils literal"><span class="pre">while</span></tt> and <tt class="docutils literal"><span class="pre">if</span></tt> statements can contain any
+operators, not just comparisons.</p>
+<p>The comparison operators <tt class="docutils literal"><span class="pre">in</span></tt> and <tt class="docutils literal"><span class="pre">not</span> <span class="pre">in</span></tt> check whether a value occurs
+(does not occur) in a sequence. The operators <tt class="docutils literal"><span class="pre">is</span></tt> and <tt class="docutils literal"><span class="pre">is</span> <span class="pre">not</span></tt> compare
+whether two objects are really the same object; this only matters for mutable
+objects like lists. All comparison operators have the same priority, which is
+lower than that of all numerical operators.</p>
+<p>Comparisons can be chained. For example, <tt class="docutils literal"><span class="pre">a</span> <span class="pre">&lt;</span> <span class="pre">b</span> <span class="pre">==</span> <span class="pre">c</span></tt> tests whether <tt class="docutils literal"><span class="pre">a</span></tt> is
+less than <tt class="docutils literal"><span class="pre">b</span></tt> and moreover <tt class="docutils literal"><span class="pre">b</span></tt> equals <tt class="docutils literal"><span class="pre">c</span></tt>.</p>
+<p>Comparisons may be combined using the Boolean operators <tt class="docutils literal"><span class="pre">and</span></tt> and <tt class="docutils literal"><span class="pre">or</span></tt>, and
+the outcome of a comparison (or of any other Boolean expression) may be negated
+with <tt class="docutils literal"><span class="pre">not</span></tt>. These have lower priorities than comparison operators; between
+them, <tt class="docutils literal"><span class="pre">not</span></tt> has the highest priority and <tt class="docutils literal"><span class="pre">or</span></tt> the lowest, so that <tt class="docutils literal"><span class="pre">A</span> <span class="pre">and</span>
+<span class="pre">not</span> <span class="pre">B</span> <span class="pre">or</span> <span class="pre">C</span></tt> is equivalent to <tt class="docutils literal"><span class="pre">(A</span> <span class="pre">and</span> <span class="pre">(not</span> <span class="pre">B))</span> <span class="pre">or</span> <span class="pre">C</span></tt>. As always, parentheses
+can be used to express the desired composition.</p>
+<p>The Boolean operators <tt class="docutils literal"><span class="pre">and</span></tt> and <tt class="docutils literal"><span class="pre">or</span></tt> are so-called <em>short-circuit</em>
+operators: their arguments are evaluated from left to right, and evaluation
+stops as soon as the outcome is determined. For example, if <tt class="docutils literal"><span class="pre">A</span></tt> and <tt class="docutils literal"><span class="pre">C</span></tt> are
+true but <tt class="docutils literal"><span class="pre">B</span></tt> is false, <tt class="docutils literal"><span class="pre">A</span> <span class="pre">and</span> <span class="pre">B</span> <span class="pre">and</span> <span class="pre">C</span></tt> does not evaluate the expression
+<tt class="docutils literal"><span class="pre">C</span></tt>. When used as a general value and not as a Boolean, the return value of a
+short-circuit operator is the last evaluated argument.</p>
+<p>It is possible to assign the result of a comparison or other Boolean expression
+to a variable. For example,</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">string1</span><span class="p">,</span> <span class="n">string2</span><span class="p">,</span> <span class="n">string3</span> <span class="o">=</span> <span class="s">&#39;&#39;</span><span class="p">,</span> <span class="s">&#39;Trondheim&#39;</span><span class="p">,</span> <span class="s">&#39;Hammer Dance&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">non_null</span> <span class="o">=</span> <span class="n">string1</span> <span class="ow">or</span> <span class="n">string2</span> <span class="ow">or</span> <span class="n">string3</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">non_null</span>
+<span class="go">&#39;Trondheim&#39;</span>
+</pre></div>
+</div>
+<p>Note that in Python, unlike C, assignment cannot occur inside expressions. C
+programmers may grumble about this, but it avoids a common class of problems
+encountered in C programs: typing <tt class="docutils literal"><span class="pre">=</span></tt> in an expression when <tt class="docutils literal"><span class="pre">==</span></tt> was
+intended.</p>
+</div>
+<div class="section" id="comparing-sequences-and-other-types">
+<span id="tut-comparing"></span><h2>5.8. Comparing Sequences and Other Types<a class="headerlink" href="#comparing-sequences-and-other-types" title="Permalink to this headline">¶</a></h2>
+<p>Sequence objects may be compared to other objects with the same sequence type.
+The comparison uses <em>lexicographical</em> ordering: first the first two items are
+compared, and if they differ this determines the outcome of the comparison; if
+they are equal, the next two items are compared, and so on, until either
+sequence is exhausted. If two items to be compared are themselves sequences of
+the same type, the lexicographical comparison is carried out recursively. If
+all items of two sequences compare equal, the sequences are considered equal.
+If one sequence is an initial sub-sequence of the other, the shorter sequence is
+the smaller (lesser) one. Lexicographical ordering for strings uses the ASCII
+ordering for individual characters. Some examples of comparisons between
+sequences of the same type:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="p">(</span><span class="mf">1</span><span class="p">,</span> <span class="mf">2</span><span class="p">,</span> <span class="mf">3</span><span class="p">)</span> <span class="o">&lt;</span> <span class="p">(</span><span class="mf">1</span><span class="p">,</span> <span class="mf">2</span><span class="p">,</span> <span class="mf">4</span><span class="p">)</span>
+<span class="p">[</span><span class="mf">1</span><span class="p">,</span> <span class="mf">2</span><span class="p">,</span> <span class="mf">3</span><span class="p">]</span> <span class="o">&lt;</span> <span class="p">[</span><span class="mf">1</span><span class="p">,</span> <span class="mf">2</span><span class="p">,</span> <span class="mf">4</span><span class="p">]</span>
+<span class="s">&#39;ABC&#39;</span> <span class="o">&lt;</span> <span class="s">&#39;C&#39;</span> <span class="o">&lt;</span> <span class="s">&#39;Pascal&#39;</span> <span class="o">&lt;</span> <span class="s">&#39;Python&#39;</span>
+<span class="p">(</span><span class="mf">1</span><span class="p">,</span> <span class="mf">2</span><span class="p">,</span> <span class="mf">3</span><span class="p">,</span> <span class="mf">4</span><span class="p">)</span> <span class="o">&lt;</span> <span class="p">(</span><span class="mf">1</span><span class="p">,</span> <span class="mf">2</span><span class="p">,</span> <span class="mf">4</span><span class="p">)</span>
+<span class="p">(</span><span class="mf">1</span><span class="p">,</span> <span class="mf">2</span><span class="p">)</span> <span class="o">&lt;</span> <span class="p">(</span><span class="mf">1</span><span class="p">,</span> <span class="mf">2</span><span class="p">,</span> <span class="o">-</span><span class="mf">1</span><span class="p">)</span>
+<span class="p">(</span><span class="mf">1</span><span class="p">,</span> <span class="mf">2</span><span class="p">,</span> <span class="mf">3</span><span class="p">)</span> <span class="o">==</span> <span class="p">(</span><span class="mf">1.0</span><span class="p">,</span> <span class="mf">2.0</span><span class="p">,</span> <span class="mf">3.0</span><span class="p">)</span>
+<span class="p">(</span><span class="mf">1</span><span class="p">,</span> <span class="mf">2</span><span class="p">,</span> <span class="p">(</span><span class="s">&#39;aa&#39;</span><span class="p">,</span> <span class="s">&#39;ab&#39;</span><span class="p">))</span> <span class="o">&lt;</span> <span class="p">(</span><span class="mf">1</span><span class="p">,</span> <span class="mf">2</span><span class="p">,</span> <span class="p">(</span><span class="s">&#39;abc&#39;</span><span class="p">,</span> <span class="s">&#39;a&#39;</span><span class="p">),</span> <span class="mf">4</span><span class="p">)</span>
+</pre></div>
+</div>
+<p>Note that comparing objects of different types is legal. The outcome is
+deterministic but arbitrary: the types are ordered by their name. Thus, a list
+is always smaller than a string, a string is always smaller than a tuple, etc.
+<a class="footnote-reference" href="#id2" id="id1">[1]</a> Mixed numeric types are compared according to their numeric value, so 0
+equals 0.0, etc.</p>
+<p class="rubric">Footnotes</p>
+<table class="docutils footnote" frame="void" id="id2" rules="none">
+<colgroup><col class="label" /><col /></colgroup>
+<tbody valign="top">
+<tr><td class="label"><a class="fn-backref" href="#id1">[1]</a></td><td>The rules for comparing objects of different types should not be relied upon;
+they may change in a future version of the language.</td></tr>
+</tbody>
+</table>
+</div>
+</div>
+
+
+ </div>
+ </div>
+ </div>
+ <div class="sphinxsidebar">
+ <div class="sphinxsidebarwrapper">
+ <h3><a href="../contents.html">Table Of Contents</a></h3>
+ <ul>
+<li><a class="reference external" href="">5. Data Structures</a><ul>
+<li><a class="reference external" href="#more-on-lists">5.1. More on Lists</a><ul>
+<li><a class="reference external" href="#using-lists-as-stacks">5.1.1. Using Lists as Stacks</a></li>
+<li><a class="reference external" href="#using-lists-as-queues">5.1.2. Using Lists as Queues</a></li>
+<li><a class="reference external" href="#functional-programming-tools">5.1.3. Functional Programming Tools</a></li>
+<li><a class="reference external" href="#list-comprehensions">5.1.4. List Comprehensions</a></li>
+<li><a class="reference external" href="#nested-list-comprehensions">5.1.5. Nested List Comprehensions</a></li>
+</ul>
+</li>
+<li><a class="reference external" href="#the-del-statement">5.2. The <tt class="docutils literal"><span class="pre">del</span></tt> statement</a></li>
+<li><a class="reference external" href="#tuples-and-sequences">5.3. Tuples and Sequences</a></li>
+<li><a class="reference external" href="#sets">5.4. Sets</a></li>
+<li><a class="reference external" href="#dictionaries">5.5. Dictionaries</a></li>
+<li><a class="reference external" href="#looping-techniques">5.6. Looping Techniques</a></li>
+<li><a class="reference external" href="#more-on-conditions">5.7. More on Conditions</a></li>
+<li><a class="reference external" href="#comparing-sequences-and-other-types">5.8. Comparing Sequences and Other Types</a></li>
+</ul>
+</li>
+</ul>
+
+ <h4>Previous topic</h4>
+ <p class="topless"><a href="controlflow.html"
+ title="previous chapter">4. More Control Flow Tools</a></p>
+ <h4>Next topic</h4>
+ <p class="topless"><a href="modules.html"
+ title="next chapter">6. Modules</a></p>
+ <h3>This Page</h3>
+ <ul class="this-page-menu">
+ <li><a href="../_sources/tutorial/datastructures.txt"
+ rel="nofollow">Show Source</a></li>
+ </ul>
+ <div id="searchbox" style="display: none">
+ <h3>Quick search</h3>
+ <form class="search" action="../search.html" method="get">
+ <input type="text" name="q" size="18" />
+ <input type="submit" value="Go" />
+ <input type="hidden" name="check_keywords" value="yes" />
+ <input type="hidden" name="area" value="default" />
+ </form>
+ <p class="searchtip" style="font-size: 90%">
+ Enter search terms or a module, class or function name.
+ </p>
+ </div>
+ <script type="text/javascript">$('#searchbox').show(0);</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../genindex.html" title="General Index"
+ >index</a></li>
+ <li class="right" >
+ <a href="../modindex.html" title="Global Module Index"
+ >modules</a> |</li>
+ <li class="right" >
+ <a href="modules.html" title="6. Modules"
+ >next</a> |</li>
+ <li class="right" >
+ <a href="controlflow.html" title="4. More Control Flow Tools"
+ >previous</a> |</li>
+ <li><img src="../_static/py.png" alt=""
+ style="vertical-align: middle; margin-top: -1px"/></li>
+ <li><a href="../index.html">Python v2.6.4c2 documentation</a> &raquo;</li>
+
+ <li><a href="index.html" >The Python Tutorial</a> &raquo;</li>
+ </ul>
+ </div>
+ <div class="footer">
+ &copy; <a href="../copyright.html">Copyright</a> 1990-2009, Python Software Foundation.
+ <br />
+ The Python Software Foundation is a non-profit corporation.
+ <a href="http://www.python.org/psf/donations/">Please donate.</a>
+ <br />
+ Last updated on Oct 19, 2009.
+ Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 0.6.2.
+ </div>
+
+ </body>
+</html> \ No newline at end of file
diff --git a/help/PythonTutorial/tutorial/errors.html b/help/PythonTutorial/tutorial/errors.html
new file mode 100644
index 0000000..63f3991
--- /dev/null
+++ b/help/PythonTutorial/tutorial/errors.html
@@ -0,0 +1,510 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+ <title>8. Errors and Exceptions &mdash; Python v2.6.4c2 documentation</title>
+ <link rel="stylesheet" href="../_static/default.css" type="text/css" />
+ <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
+ <script type="text/javascript">
+ var DOCUMENTATION_OPTIONS = {
+ URL_ROOT: '../',
+ VERSION: '2.6.4c2',
+ COLLAPSE_MODINDEX: false,
+ FILE_SUFFIX: '.html',
+ HAS_SOURCE: true
+ };
+ </script>
+ <script type="text/javascript" src="../_static/jquery.js"></script>
+ <script type="text/javascript" src="../_static/doctools.js"></script>
+ <link rel="search" type="application/opensearchdescription+xml"
+ title="Search within Python v2.6.4c2 documentation"
+ href="../_static/opensearch.xml"/>
+ <link rel="author" title="About these documents" href="../about.html" />
+ <link rel="copyright" title="Copyright" href="../copyright.html" />
+ <link rel="top" title="Python v2.6.4c2 documentation" href="../index.html" />
+ <link rel="up" title="The Python Tutorial" href="index.html" />
+ <link rel="next" title="9. Classes" href="classes.html" />
+ <link rel="prev" title="7. Input and Output" href="inputoutput.html" />
+ <link rel="shortcut icon" type="image/png" href="../_static/py.png" />
+
+
+ </head>
+ <body>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../modindex.html" title="Global Module Index"
+ accesskey="M">modules</a> |</li>
+ <li class="right" >
+ <a href="classes.html" title="9. Classes"
+ accesskey="N">next</a> |</li>
+ <li class="right" >
+ <a href="inputoutput.html" title="7. Input and Output"
+ accesskey="P">previous</a> |</li>
+ <li><img src="../_static/py.png" alt=""
+ style="vertical-align: middle; margin-top: -1px"/></li>
+ <li><a href="../index.html">Python v2.6.4c2 documentation</a> &raquo;</li>
+
+ <li><a href="index.html" accesskey="U">The Python Tutorial</a> &raquo;</li>
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body">
+
+ <div class="section" id="errors-and-exceptions">
+<span id="tut-errors"></span><h1>8. Errors and Exceptions<a class="headerlink" href="#errors-and-exceptions" title="Permalink to this headline">¶</a></h1>
+<p>Until now error messages haven&#8217;t been more than mentioned, but if you have tried
+out the examples you have probably seen some. There are (at least) two
+distinguishable kinds of errors: <em>syntax errors</em> and <em>exceptions</em>.</p>
+<div class="section" id="syntax-errors">
+<span id="tut-syntaxerrors"></span><h2>8.1. Syntax Errors<a class="headerlink" href="#syntax-errors" title="Permalink to this headline">¶</a></h2>
+<p>Syntax errors, also known as parsing errors, are perhaps the most common kind of
+complaint you get while you are still learning Python:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">while</span> <span class="bp">True</span> <span class="k">print</span> <span class="s">&#39;Hello world&#39;</span>
+<span class="go"> File &quot;&lt;stdin&gt;&quot;, line 1, in ?</span>
+<span class="go"> while True print &#39;Hello world&#39;</span>
+<span class="go"> ^</span>
+<span class="go">SyntaxError: invalid syntax</span>
+</pre></div>
+</div>
+<p>The parser repeats the offending line and displays a little &#8216;arrow&#8217; pointing at
+the earliest point in the line where the error was detected. The error is
+caused by (or at least detected at) the token <em>preceding</em> the arrow: in the
+example, the error is detected at the keyword <a class="reference external" href="../reference/simple_stmts.html#print"><tt class="xref docutils literal"><span class="pre">print</span></tt></a>, since a colon
+(<tt class="docutils literal"><span class="pre">':'</span></tt>) is missing before it. File name and line number are printed so you
+know where to look in case the input came from a script.</p>
+</div>
+<div class="section" id="exceptions">
+<span id="tut-exceptions"></span><h2>8.2. Exceptions<a class="headerlink" href="#exceptions" title="Permalink to this headline">¶</a></h2>
+<p>Even if a statement or expression is syntactically correct, it may cause an
+error when an attempt is made to execute it. Errors detected during execution
+are called <em>exceptions</em> and are not unconditionally fatal: you will soon learn
+how to handle them in Python programs. Most exceptions are not handled by
+programs, however, and result in error messages as shown here:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="mf">10</span> <span class="o">*</span> <span class="p">(</span><span class="mf">1</span><span class="o">/</span><span class="mf">0</span><span class="p">)</span>
+<span class="gt">Traceback (most recent call last):</span>
+ File <span class="nb">&quot;&lt;stdin&gt;&quot;</span>, line <span class="m">1</span>, in <span class="n-Identifier">?</span>
+<span class="nc">ZeroDivisionError</span>: <span class="n-Identifier">integer division or modulo by zero</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="mf">4</span> <span class="o">+</span> <span class="n">spam</span><span class="o">*</span><span class="mf">3</span>
+<span class="gt">Traceback (most recent call last):</span>
+ File <span class="nb">&quot;&lt;stdin&gt;&quot;</span>, line <span class="m">1</span>, in <span class="n-Identifier">?</span>
+<span class="nc">NameError</span>: <span class="n-Identifier">name &#39;spam&#39; is not defined</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="s">&#39;2&#39;</span> <span class="o">+</span> <span class="mf">2</span>
+<span class="gt">Traceback (most recent call last):</span>
+ File <span class="nb">&quot;&lt;stdin&gt;&quot;</span>, line <span class="m">1</span>, in <span class="n-Identifier">?</span>
+<span class="nc">TypeError</span>: <span class="n-Identifier">cannot concatenate &#39;str&#39; and &#39;int&#39; objects</span>
+</pre></div>
+</div>
+<p>The last line of the error message indicates what happened. Exceptions come in
+different types, and the type is printed as part of the message: the types in
+the example are <a title="exceptions.ZeroDivisionError" class="reference external" href="../library/exceptions.html#exceptions.ZeroDivisionError"><tt class="xref docutils literal"><span class="pre">ZeroDivisionError</span></tt></a>, <a title="exceptions.NameError" class="reference external" href="../library/exceptions.html#exceptions.NameError"><tt class="xref docutils literal"><span class="pre">NameError</span></tt></a> and <a title="exceptions.TypeError" class="reference external" href="../library/exceptions.html#exceptions.TypeError"><tt class="xref docutils literal"><span class="pre">TypeError</span></tt></a>.
+The string printed as the exception type is the name of the built-in exception
+that occurred. This is true for all built-in exceptions, but need not be true
+for user-defined exceptions (although it is a useful convention). Standard
+exception names are built-in identifiers (not reserved keywords).</p>
+<p>The rest of the line provides detail based on the type of exception and what
+caused it.</p>
+<p>The preceding part of the error message shows the context where the exception
+happened, in the form of a stack traceback. In general it contains a stack
+traceback listing source lines; however, it will not display lines read from
+standard input.</p>
+<p><a class="reference external" href="../library/exceptions.html#bltin-exceptions"><em>Built-in Exceptions</em></a> lists the built-in exceptions and their meanings.</p>
+</div>
+<div class="section" id="handling-exceptions">
+<span id="tut-handling"></span><h2>8.3. Handling Exceptions<a class="headerlink" href="#handling-exceptions" title="Permalink to this headline">¶</a></h2>
+<p>It is possible to write programs that handle selected exceptions. Look at the
+following example, which asks the user for input until a valid integer has been
+entered, but allows the user to interrupt the program (using <tt class="docutils literal"><span class="pre">Control-C</span></tt> or
+whatever the operating system supports); note that a user-generated interruption
+is signalled by raising the <a title="exceptions.KeyboardInterrupt" class="reference external" href="../library/exceptions.html#exceptions.KeyboardInterrupt"><tt class="xref docutils literal"><span class="pre">KeyboardInterrupt</span></tt></a> exception.</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
+<span class="gp">... </span> <span class="k">try</span><span class="p">:</span>
+<span class="gp">... </span> <span class="n">x</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="nb">raw_input</span><span class="p">(</span><span class="s">&quot;Please enter a number: &quot;</span><span class="p">))</span>
+<span class="gp">... </span> <span class="k">break</span>
+<span class="gp">... </span> <span class="k">except</span> <span class="ne">ValueError</span><span class="p">:</span>
+<span class="gp">... </span> <span class="k">print</span> <span class="s">&quot;Oops! That was no valid number. Try again...&quot;</span>
+<span class="gp">...</span>
+</pre></div>
+</div>
+<p>The <a class="reference external" href="../reference/compound_stmts.html#try"><tt class="xref docutils literal"><span class="pre">try</span></tt></a> statement works as follows.</p>
+<ul class="simple">
+<li>First, the <em>try clause</em> (the statement(s) between the <a class="reference external" href="../reference/compound_stmts.html#try"><tt class="xref docutils literal"><span class="pre">try</span></tt></a> and
+<a class="reference external" href="../reference/compound_stmts.html#except"><tt class="xref docutils literal"><span class="pre">except</span></tt></a> keywords) is executed.</li>
+<li>If no exception occurs, the <em>except clause</em> is skipped and execution of the
+<a class="reference external" href="../reference/compound_stmts.html#try"><tt class="xref docutils literal"><span class="pre">try</span></tt></a> statement is finished.</li>
+<li>If an exception occurs during execution of the try clause, the rest of the
+clause is skipped. Then if its type matches the exception named after the
+<a class="reference external" href="../reference/compound_stmts.html#except"><tt class="xref docutils literal"><span class="pre">except</span></tt></a> keyword, the except clause is executed, and then execution
+continues after the <a class="reference external" href="../reference/compound_stmts.html#try"><tt class="xref docutils literal"><span class="pre">try</span></tt></a> statement.</li>
+<li>If an exception occurs which does not match the exception named in the except
+clause, it is passed on to outer <a class="reference external" href="../reference/compound_stmts.html#try"><tt class="xref docutils literal"><span class="pre">try</span></tt></a> statements; if no handler is
+found, it is an <em>unhandled exception</em> and execution stops with a message as
+shown above.</li>
+</ul>
+<p>A <a class="reference external" href="../reference/compound_stmts.html#try"><tt class="xref docutils literal"><span class="pre">try</span></tt></a> statement may have more than one except clause, to specify
+handlers for different exceptions. At most one handler will be executed.
+Handlers only handle exceptions that occur in the corresponding try clause, not
+in other handlers of the same <a class="reference external" href="../reference/compound_stmts.html#try"><tt class="xref docutils literal"><span class="pre">try</span></tt></a> statement. An except clause may
+name multiple exceptions as a parenthesized tuple, for example:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="o">...</span> <span class="k">except</span> <span class="p">(</span><span class="ne">RuntimeError</span><span class="p">,</span> <span class="ne">TypeError</span><span class="p">,</span> <span class="ne">NameError</span><span class="p">):</span>
+<span class="o">...</span> <span class="k">pass</span>
+</pre></div>
+</div>
+<p>The last except clause may omit the exception name(s), to serve as a wildcard.
+Use this with extreme caution, since it is easy to mask a real programming error
+in this way! It can also be used to print an error message and then re-raise
+the exception (allowing a caller to handle the exception as well):</p>
+<div class="highlight-python"><pre>import sys
+
+try:
+ f = open('myfile.txt')
+ s = f.readline()
+ i = int(s.strip())
+except IOError as (errno, strerror):
+ print "I/O error({0}): {1}".format(errno, strerror)
+except ValueError:
+ print "Could not convert data to an integer."
+except:
+ print "Unexpected error:", sys.exc_info()[0]
+ raise</pre>
+</div>
+<p>The <a class="reference external" href="../reference/compound_stmts.html#try"><tt class="xref docutils literal"><span class="pre">try</span></tt></a> ... <a class="reference external" href="../reference/compound_stmts.html#except"><tt class="xref docutils literal"><span class="pre">except</span></tt></a> statement has an optional <em>else
+clause</em>, which, when present, must follow all except clauses. It is useful for
+code that must be executed if the try clause does not raise an exception. For
+example:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="k">for</span> <span class="n">arg</span> <span class="ow">in</span> <span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mf">1</span><span class="p">:]:</span>
+ <span class="k">try</span><span class="p">:</span>
+ <span class="n">f</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="n">arg</span><span class="p">,</span> <span class="s">&#39;r&#39;</span><span class="p">)</span>
+ <span class="k">except</span> <span class="ne">IOError</span><span class="p">:</span>
+ <span class="k">print</span> <span class="s">&#39;cannot open&#39;</span><span class="p">,</span> <span class="n">arg</span>
+ <span class="k">else</span><span class="p">:</span>
+ <span class="k">print</span> <span class="n">arg</span><span class="p">,</span> <span class="s">&#39;has&#39;</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">f</span><span class="o">.</span><span class="n">readlines</span><span class="p">()),</span> <span class="s">&#39;lines&#39;</span>
+ <span class="n">f</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
+</pre></div>
+</div>
+<p>The use of the <a class="reference external" href="../reference/compound_stmts.html#else"><tt class="xref docutils literal"><span class="pre">else</span></tt></a> clause is better than adding additional code to
+the <a class="reference external" href="../reference/compound_stmts.html#try"><tt class="xref docutils literal"><span class="pre">try</span></tt></a> clause because it avoids accidentally catching an exception
+that wasn&#8217;t raised by the code being protected by the <a class="reference external" href="../reference/compound_stmts.html#try"><tt class="xref docutils literal"><span class="pre">try</span></tt></a> ...
+<a class="reference external" href="../reference/compound_stmts.html#except"><tt class="xref docutils literal"><span class="pre">except</span></tt></a> statement.</p>
+<p>When an exception occurs, it may have an associated value, also known as the
+exception&#8217;s <em>argument</em>. The presence and type of the argument depend on the
+exception type.</p>
+<p>The except clause may specify a variable after the exception name (or tuple).
+The variable is bound to an exception instance with the arguments stored in
+<tt class="docutils literal"><span class="pre">instance.args</span></tt>. For convenience, the exception instance defines
+<a title="object.__getitem__" class="reference external" href="../reference/datamodel.html#object.__getitem__"><tt class="xref docutils literal"><span class="pre">__getitem__()</span></tt></a> and <a title="object.__str__" class="reference external" href="../reference/datamodel.html#object.__str__"><tt class="xref docutils literal"><span class="pre">__str__()</span></tt></a> so the arguments can be accessed or
+printed directly without having to reference <tt class="docutils literal"><span class="pre">.args</span></tt>.</p>
+<p>But use of <tt class="docutils literal"><span class="pre">.args</span></tt> is discouraged. Instead, the preferred use is to pass a
+single argument to an exception (which can be a tuple if multiple arguments are
+needed) and have it bound to the <tt class="docutils literal"><span class="pre">message</span></tt> attribute. One may also
+instantiate an exception first before raising it and add any attributes to it as
+desired.</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">try</span><span class="p">:</span>
+<span class="gp">... </span> <span class="k">raise</span> <span class="ne">Exception</span><span class="p">(</span><span class="s">&#39;spam&#39;</span><span class="p">,</span> <span class="s">&#39;eggs&#39;</span><span class="p">)</span>
+<span class="gp">... </span><span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">inst</span><span class="p">:</span>
+<span class="gp">... </span> <span class="k">print</span> <span class="nb">type</span><span class="p">(</span><span class="n">inst</span><span class="p">)</span> <span class="c"># the exception instance</span>
+<span class="gp">... </span> <span class="k">print</span> <span class="n">inst</span><span class="o">.</span><span class="n">args</span> <span class="c"># arguments stored in .args</span>
+<span class="gp">... </span> <span class="k">print</span> <span class="n">inst</span> <span class="c"># __str__ allows args to printed directly</span>
+<span class="gp">... </span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="o">=</span> <span class="n">inst</span> <span class="c"># __getitem__ allows args to be unpacked directly</span>
+<span class="gp">... </span> <span class="k">print</span> <span class="s">&#39;x =&#39;</span><span class="p">,</span> <span class="n">x</span>
+<span class="gp">... </span> <span class="k">print</span> <span class="s">&#39;y =&#39;</span><span class="p">,</span> <span class="n">y</span>
+<span class="gp">...</span>
+<span class="go">&lt;type &#39;exceptions.Exception&#39;&gt;</span>
+<span class="go">(&#39;spam&#39;, &#39;eggs&#39;)</span>
+<span class="go">(&#39;spam&#39;, &#39;eggs&#39;)</span>
+<span class="go">x = spam</span>
+<span class="go">y = eggs</span>
+</pre></div>
+</div>
+<p>If an exception has an argument, it is printed as the last part (&#8216;detail&#8217;) of
+the message for unhandled exceptions.</p>
+<p>Exception handlers don&#8217;t just handle exceptions if they occur immediately in the
+try clause, but also if they occur inside functions that are called (even
+indirectly) in the try clause. For example:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">def</span> <span class="nf">this_fails</span><span class="p">():</span>
+<span class="gp">... </span> <span class="n">x</span> <span class="o">=</span> <span class="mf">1</span><span class="o">/</span><span class="mf">0</span>
+<span class="gp">...</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">try</span><span class="p">:</span>
+<span class="gp">... </span> <span class="n">this_fails</span><span class="p">()</span>
+<span class="gp">... </span><span class="k">except</span> <span class="ne">ZeroDivisionError</span> <span class="k">as</span> <span class="n">detail</span><span class="p">:</span>
+<span class="gp">... </span> <span class="k">print</span> <span class="s">&#39;Handling run-time error:&#39;</span><span class="p">,</span> <span class="n">detail</span>
+<span class="gp">...</span>
+<span class="go">Handling run-time error: integer division or modulo by zero</span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="raising-exceptions">
+<span id="tut-raising"></span><h2>8.4. Raising Exceptions<a class="headerlink" href="#raising-exceptions" title="Permalink to this headline">¶</a></h2>
+<p>The <a class="reference external" href="../reference/simple_stmts.html#raise"><tt class="xref docutils literal"><span class="pre">raise</span></tt></a> statement allows the programmer to force a specified
+exception to occur. For example:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">raise</span> <span class="ne">NameError</span><span class="p">(</span><span class="s">&#39;HiThere&#39;</span><span class="p">)</span>
+<span class="gt">Traceback (most recent call last):</span>
+ File <span class="nb">&quot;&lt;stdin&gt;&quot;</span>, line <span class="m">1</span>, in <span class="n-Identifier">?</span>
+<span class="nc">NameError</span>: <span class="n-Identifier">HiThere</span>
+</pre></div>
+</div>
+<p>The sole argument to <a class="reference external" href="../reference/simple_stmts.html#raise"><tt class="xref docutils literal"><span class="pre">raise</span></tt></a> indicates the exception to be raised.
+This must be either an exception instance or an exception class (a class that
+derives from <tt class="xref docutils literal"><span class="pre">Exception</span></tt>).</p>
+<p>If you need to determine whether an exception was raised but don&#8217;t intend to
+handle it, a simpler form of the <a class="reference external" href="../reference/simple_stmts.html#raise"><tt class="xref docutils literal"><span class="pre">raise</span></tt></a> statement allows you to
+re-raise the exception:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">try</span><span class="p">:</span>
+<span class="gp">... </span> <span class="k">raise</span> <span class="ne">NameError</span><span class="p">(</span><span class="s">&#39;HiThere&#39;</span><span class="p">)</span>
+<span class="gp">... </span><span class="k">except</span> <span class="ne">NameError</span><span class="p">:</span>
+<span class="gp">... </span> <span class="k">print</span> <span class="s">&#39;An exception flew by!&#39;</span>
+<span class="gp">... </span> <span class="k">raise</span>
+<span class="gp">...</span>
+<span class="go">An exception flew by!</span>
+<span class="gt">Traceback (most recent call last):</span>
+ File <span class="nb">&quot;&lt;stdin&gt;&quot;</span>, line <span class="m">2</span>, in <span class="n-Identifier">?</span>
+<span class="nc">NameError</span>: <span class="n-Identifier">HiThere</span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="user-defined-exceptions">
+<span id="tut-userexceptions"></span><h2>8.5. User-defined Exceptions<a class="headerlink" href="#user-defined-exceptions" title="Permalink to this headline">¶</a></h2>
+<p>Programs may name their own exceptions by creating a new exception class.
+Exceptions should typically be derived from the <a title="exceptions.Exception" class="reference external" href="../library/exceptions.html#exceptions.Exception"><tt class="xref docutils literal"><span class="pre">Exception</span></tt></a> class, either
+directly or indirectly. For example:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">class</span> <span class="nc">MyError</span><span class="p">(</span><span class="ne">Exception</span><span class="p">):</span>
+<span class="gp">... </span> <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
+<span class="gp">... </span> <span class="bp">self</span><span class="o">.</span><span class="n">value</span> <span class="o">=</span> <span class="n">value</span>
+<span class="gp">... </span> <span class="k">def</span> <span class="nf">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+<span class="gp">... </span> <span class="k">return</span> <span class="nb">repr</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">value</span><span class="p">)</span>
+<span class="gp">...</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">try</span><span class="p">:</span>
+<span class="gp">... </span> <span class="k">raise</span> <span class="n">MyError</span><span class="p">(</span><span class="mf">2</span><span class="o">*</span><span class="mf">2</span><span class="p">)</span>
+<span class="gp">... </span><span class="k">except</span> <span class="n">MyError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
+<span class="gp">... </span> <span class="k">print</span> <span class="s">&#39;My exception occurred, value:&#39;</span><span class="p">,</span> <span class="n">e</span><span class="o">.</span><span class="n">value</span>
+<span class="gp">...</span>
+<span class="go">My exception occurred, value: 4</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">raise</span> <span class="n">MyError</span><span class="p">(</span><span class="s">&#39;oops!&#39;</span><span class="p">)</span>
+<span class="gt">Traceback (most recent call last):</span>
+ File <span class="nb">&quot;&lt;stdin&gt;&quot;</span>, line <span class="m">1</span>, in <span class="n-Identifier">?</span>
+<span class="nc">__main__.MyError</span>: <span class="n-Identifier">&#39;oops!&#39;</span>
+</pre></div>
+</div>
+<p>In this example, the default <a title="object.__init__" class="reference external" href="../reference/datamodel.html#object.__init__"><tt class="xref docutils literal"><span class="pre">__init__()</span></tt></a> of <tt class="xref docutils literal"><span class="pre">Exception</span></tt> has been
+overridden. The new behavior simply creates the <em>value</em> attribute. This
+replaces the default behavior of creating the <em>args</em> attribute.</p>
+<p>Exception classes can be defined which do anything any other class can do, but
+are usually kept simple, often only offering a number of attributes that allow
+information about the error to be extracted by handlers for the exception. When
+creating a module that can raise several distinct errors, a common practice is
+to create a base class for exceptions defined by that module, and subclass that
+to create specific exception classes for different error conditions:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="k">class</span> <span class="nc">Error</span><span class="p">(</span><span class="ne">Exception</span><span class="p">):</span>
+ <span class="sd">&quot;&quot;&quot;Base class for exceptions in this module.&quot;&quot;&quot;</span>
+ <span class="k">pass</span>
+
+<span class="k">class</span> <span class="nc">InputError</span><span class="p">(</span><span class="n">Error</span><span class="p">):</span>
+ <span class="sd">&quot;&quot;&quot;Exception raised for errors in the input.</span>
+
+<span class="sd"> Attributes:</span>
+<span class="sd"> expression -- input expression in which the error occurred</span>
+<span class="sd"> message -- explanation of the error</span>
+<span class="sd"> &quot;&quot;&quot;</span>
+
+ <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">expression</span><span class="p">,</span> <span class="n">message</span><span class="p">):</span>
+ <span class="bp">self</span><span class="o">.</span><span class="n">expression</span> <span class="o">=</span> <span class="n">expression</span>
+ <span class="bp">self</span><span class="o">.</span><span class="n">message</span> <span class="o">=</span> <span class="n">message</span>
+
+<span class="k">class</span> <span class="nc">TransitionError</span><span class="p">(</span><span class="n">Error</span><span class="p">):</span>
+ <span class="sd">&quot;&quot;&quot;Raised when an operation attempts a state transition that&#39;s not</span>
+<span class="sd"> allowed.</span>
+
+<span class="sd"> Attributes:</span>
+<span class="sd"> previous -- state at beginning of transition</span>
+<span class="sd"> next -- attempted new state</span>
+<span class="sd"> message -- explanation of why the specific transition is not allowed</span>
+<span class="sd"> &quot;&quot;&quot;</span>
+
+ <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">previous</span><span class="p">,</span> <span class="n">next</span><span class="p">,</span> <span class="n">message</span><span class="p">):</span>
+ <span class="bp">self</span><span class="o">.</span><span class="n">previous</span> <span class="o">=</span> <span class="n">previous</span>
+ <span class="bp">self</span><span class="o">.</span><span class="n">next</span> <span class="o">=</span> <span class="n">next</span>
+ <span class="bp">self</span><span class="o">.</span><span class="n">message</span> <span class="o">=</span> <span class="n">message</span>
+</pre></div>
+</div>
+<p>Most exceptions are defined with names that end in &#8220;Error,&#8221; similar to the
+naming of the standard exceptions.</p>
+<p>Many standard modules define their own exceptions to report errors that may
+occur in functions they define. More information on classes is presented in
+chapter <a class="reference external" href="classes.html#tut-classes"><em>Classes</em></a>.</p>
+</div>
+<div class="section" id="defining-clean-up-actions">
+<span id="tut-cleanup"></span><h2>8.6. Defining Clean-up Actions<a class="headerlink" href="#defining-clean-up-actions" title="Permalink to this headline">¶</a></h2>
+<p>The <a class="reference external" href="../reference/compound_stmts.html#try"><tt class="xref docutils literal"><span class="pre">try</span></tt></a> statement has another optional clause which is intended to
+define clean-up actions that must be executed under all circumstances. For
+example:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">try</span><span class="p">:</span>
+<span class="gp">... </span> <span class="k">raise</span> <span class="ne">KeyboardInterrupt</span>
+<span class="gp">... </span><span class="k">finally</span><span class="p">:</span>
+<span class="gp">... </span> <span class="k">print</span> <span class="s">&#39;Goodbye, world!&#39;</span>
+<span class="gp">...</span>
+<span class="go">Goodbye, world!</span>
+<span class="gt">Traceback (most recent call last):</span>
+ File <span class="nb">&quot;&lt;stdin&gt;&quot;</span>, line <span class="m">2</span>, in <span class="n-Identifier">?</span>
+<span class="nc">KeyboardInterrupt</span>
+</pre></div>
+</div>
+<p>A <em>finally clause</em> is always executed before leaving the <a class="reference external" href="../reference/compound_stmts.html#try"><tt class="xref docutils literal"><span class="pre">try</span></tt></a>
+statement, whether an exception has occurred or not. When an exception has
+occurred in the <a class="reference external" href="../reference/compound_stmts.html#try"><tt class="xref docutils literal"><span class="pre">try</span></tt></a> clause and has not been handled by an
+<a class="reference external" href="../reference/compound_stmts.html#except"><tt class="xref docutils literal"><span class="pre">except</span></tt></a> clause (or it has occurred in a <a class="reference external" href="../reference/compound_stmts.html#except"><tt class="xref docutils literal"><span class="pre">except</span></tt></a> or
+<a class="reference external" href="../reference/compound_stmts.html#else"><tt class="xref docutils literal"><span class="pre">else</span></tt></a> clause), it is re-raised after the <a class="reference external" href="../reference/compound_stmts.html#finally"><tt class="xref docutils literal"><span class="pre">finally</span></tt></a> clause has
+been executed. The <a class="reference external" href="../reference/compound_stmts.html#finally"><tt class="xref docutils literal"><span class="pre">finally</span></tt></a> clause is also executed &#8220;on the way out&#8221;
+when any other clause of the <a class="reference external" href="../reference/compound_stmts.html#try"><tt class="xref docutils literal"><span class="pre">try</span></tt></a> statement is left via a
+<a class="reference external" href="../reference/simple_stmts.html#break"><tt class="xref docutils literal"><span class="pre">break</span></tt></a>, <a class="reference external" href="../reference/simple_stmts.html#continue"><tt class="xref docutils literal"><span class="pre">continue</span></tt></a> or <a class="reference external" href="../reference/simple_stmts.html#return"><tt class="xref docutils literal"><span class="pre">return</span></tt></a> statement. A more
+complicated example (having <a class="reference external" href="../reference/compound_stmts.html#except"><tt class="xref docutils literal"><span class="pre">except</span></tt></a> and <a class="reference external" href="../reference/compound_stmts.html#finally"><tt class="xref docutils literal"><span class="pre">finally</span></tt></a> clauses in
+the same <a class="reference external" href="../reference/compound_stmts.html#try"><tt class="xref docutils literal"><span class="pre">try</span></tt></a> statement works as of Python 2.5):</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">def</span> <span class="nf">divide</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">):</span>
+<span class="gp">... </span> <span class="k">try</span><span class="p">:</span>
+<span class="gp">... </span> <span class="n">result</span> <span class="o">=</span> <span class="n">x</span> <span class="o">/</span> <span class="n">y</span>
+<span class="gp">... </span> <span class="k">except</span> <span class="ne">ZeroDivisionError</span><span class="p">:</span>
+<span class="gp">... </span> <span class="k">print</span> <span class="s">&quot;division by zero!&quot;</span>
+<span class="gp">... </span> <span class="k">else</span><span class="p">:</span>
+<span class="gp">... </span> <span class="k">print</span> <span class="s">&quot;result is&quot;</span><span class="p">,</span> <span class="n">result</span>
+<span class="gp">... </span> <span class="k">finally</span><span class="p">:</span>
+<span class="gp">... </span> <span class="k">print</span> <span class="s">&quot;executing finally clause&quot;</span>
+<span class="gp">...</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">divide</span><span class="p">(</span><span class="mf">2</span><span class="p">,</span> <span class="mf">1</span><span class="p">)</span>
+<span class="go">result is 2</span>
+<span class="go">executing finally clause</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">divide</span><span class="p">(</span><span class="mf">2</span><span class="p">,</span> <span class="mf">0</span><span class="p">)</span>
+<span class="go">division by zero!</span>
+<span class="go">executing finally clause</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">divide</span><span class="p">(</span><span class="s">&quot;2&quot;</span><span class="p">,</span> <span class="s">&quot;1&quot;</span><span class="p">)</span>
+<span class="go">executing finally clause</span>
+<span class="gt">Traceback (most recent call last):</span>
+ File <span class="nb">&quot;&lt;stdin&gt;&quot;</span>, line <span class="m">1</span>, in <span class="n-Identifier">?</span>
+ File <span class="nb">&quot;&lt;stdin&gt;&quot;</span>, line <span class="m">3</span>, in <span class="n-Identifier">divide</span>
+<span class="nc">TypeError: unsupported operand type(s) for /</span>: <span class="n-Identifier">&#39;str&#39; and &#39;str&#39;</span>
+</pre></div>
+</div>
+<p>As you can see, the <a class="reference external" href="../reference/compound_stmts.html#finally"><tt class="xref docutils literal"><span class="pre">finally</span></tt></a> clause is executed in any event. The
+<a title="exceptions.TypeError" class="reference external" href="../library/exceptions.html#exceptions.TypeError"><tt class="xref docutils literal"><span class="pre">TypeError</span></tt></a> raised by dividing two strings is not handled by the
+<a class="reference external" href="../reference/compound_stmts.html#except"><tt class="xref docutils literal"><span class="pre">except</span></tt></a> clause and therefore re-raised after the <a class="reference external" href="../reference/compound_stmts.html#finally"><tt class="xref docutils literal"><span class="pre">finally</span></tt></a>
+clause has been executed.</p>
+<p>In real world applications, the <a class="reference external" href="../reference/compound_stmts.html#finally"><tt class="xref docutils literal"><span class="pre">finally</span></tt></a> clause is useful for
+releasing external resources (such as files or network connections), regardless
+of whether the use of the resource was successful.</p>
+</div>
+<div class="section" id="predefined-clean-up-actions">
+<span id="tut-cleanup-with"></span><h2>8.7. Predefined Clean-up Actions<a class="headerlink" href="#predefined-clean-up-actions" title="Permalink to this headline">¶</a></h2>
+<p>Some objects define standard clean-up actions to be undertaken when the object
+is no longer needed, regardless of whether or not the operation using the object
+succeeded or failed. Look at the following example, which tries to open a file
+and print its contents to the screen.</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="nb">open</span><span class="p">(</span><span class="s">&quot;myfile.txt&quot;</span><span class="p">):</span>
+ <span class="k">print</span> <span class="n">line</span>
+</pre></div>
+</div>
+<p>The problem with this code is that it leaves the file open for an indeterminate
+amount of time after the code has finished executing. This is not an issue in
+simple scripts, but can be a problem for larger applications. The
+<a class="reference external" href="../reference/compound_stmts.html#with"><tt class="xref docutils literal"><span class="pre">with</span></tt></a> statement allows objects like files to be used in a way that
+ensures they are always cleaned up promptly and correctly.</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s">&quot;myfile.txt&quot;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
+ <span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">f</span><span class="p">:</span>
+ <span class="k">print</span> <span class="n">line</span>
+</pre></div>
+</div>
+<p>After the statement is executed, the file <em>f</em> is always closed, even if a
+problem was encountered while processing the lines. Other objects which provide
+predefined clean-up actions will indicate this in their documentation.</p>
+</div>
+</div>
+
+
+ </div>
+ </div>
+ </div>
+ <div class="sphinxsidebar">
+ <div class="sphinxsidebarwrapper">
+ <h3><a href="../contents.html">Table Of Contents</a></h3>
+ <ul>
+<li><a class="reference external" href="">8. Errors and Exceptions</a><ul>
+<li><a class="reference external" href="#syntax-errors">8.1. Syntax Errors</a></li>
+<li><a class="reference external" href="#exceptions">8.2. Exceptions</a></li>
+<li><a class="reference external" href="#handling-exceptions">8.3. Handling Exceptions</a></li>
+<li><a class="reference external" href="#raising-exceptions">8.4. Raising Exceptions</a></li>
+<li><a class="reference external" href="#user-defined-exceptions">8.5. User-defined Exceptions</a></li>
+<li><a class="reference external" href="#defining-clean-up-actions">8.6. Defining Clean-up Actions</a></li>
+<li><a class="reference external" href="#predefined-clean-up-actions">8.7. Predefined Clean-up Actions</a></li>
+</ul>
+</li>
+</ul>
+
+ <h4>Previous topic</h4>
+ <p class="topless"><a href="inputoutput.html"
+ title="previous chapter">7. Input and Output</a></p>
+ <h4>Next topic</h4>
+ <p class="topless"><a href="classes.html"
+ title="next chapter">9. Classes</a></p>
+ <h3>This Page</h3>
+ <ul class="this-page-menu">
+ <li><a href="../_sources/tutorial/errors.txt"
+ rel="nofollow">Show Source</a></li>
+ </ul>
+ <div id="searchbox" style="display: none">
+ <h3>Quick search</h3>
+ <form class="search" action="../search.html" method="get">
+ <input type="text" name="q" size="18" />
+ <input type="submit" value="Go" />
+ <input type="hidden" name="check_keywords" value="yes" />
+ <input type="hidden" name="area" value="default" />
+ </form>
+ <p class="searchtip" style="font-size: 90%">
+ Enter search terms or a module, class or function name.
+ </p>
+ </div>
+ <script type="text/javascript">$('#searchbox').show(0);</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../genindex.html" title="General Index"
+ >index</a></li>
+ <li class="right" >
+ <a href="../modindex.html" title="Global Module Index"
+ >modules</a> |</li>
+ <li class="right" >
+ <a href="classes.html" title="9. Classes"
+ >next</a> |</li>
+ <li class="right" >
+ <a href="inputoutput.html" title="7. Input and Output"
+ >previous</a> |</li>
+ <li><img src="../_static/py.png" alt=""
+ style="vertical-align: middle; margin-top: -1px"/></li>
+ <li><a href="../index.html">Python v2.6.4c2 documentation</a> &raquo;</li>
+
+ <li><a href="index.html" >The Python Tutorial</a> &raquo;</li>
+ </ul>
+ </div>
+ <div class="footer">
+ &copy; <a href="../copyright.html">Copyright</a> 1990-2009, Python Software Foundation.
+ <br />
+ The Python Software Foundation is a non-profit corporation.
+ <a href="http://www.python.org/psf/donations/">Please donate.</a>
+ <br />
+ Last updated on Oct 19, 2009.
+ Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 0.6.2.
+ </div>
+
+ </body>
+</html> \ No newline at end of file
diff --git a/help/PythonTutorial/tutorial/floatingpoint.html b/help/PythonTutorial/tutorial/floatingpoint.html
new file mode 100644
index 0000000..8338268
--- /dev/null
+++ b/help/PythonTutorial/tutorial/floatingpoint.html
@@ -0,0 +1,333 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+ <title>14. Floating Point Arithmetic: Issues and Limitations &mdash; Python v2.6.4c2 documentation</title>
+ <link rel="stylesheet" href="../_static/default.css" type="text/css" />
+ <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
+ <script type="text/javascript">
+ var DOCUMENTATION_OPTIONS = {
+ URL_ROOT: '../',
+ VERSION: '2.6.4c2',
+ COLLAPSE_MODINDEX: false,
+ FILE_SUFFIX: '.html',
+ HAS_SOURCE: true
+ };
+ </script>
+ <script type="text/javascript" src="../_static/jquery.js"></script>
+ <script type="text/javascript" src="../_static/doctools.js"></script>
+ <link rel="search" type="application/opensearchdescription+xml"
+ title="Search within Python v2.6.4c2 documentation"
+ href="../_static/opensearch.xml"/>
+ <link rel="author" title="About these documents" href="../about.html" />
+ <link rel="copyright" title="Copyright" href="../copyright.html" />
+ <link rel="top" title="Python v2.6.4c2 documentation" href="../index.html" />
+ <link rel="up" title="The Python Tutorial" href="index.html" />
+ <link rel="next" title="Using Python" href="../using/index.html" />
+ <link rel="prev" title="13. Interactive Input Editing and History Substitution" href="interactive.html" />
+ <link rel="shortcut icon" type="image/png" href="../_static/py.png" />
+
+
+ </head>
+ <body>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../modindex.html" title="Global Module Index"
+ accesskey="M">modules</a> |</li>
+ <li class="right" >
+ <a href="../using/index.html" title="Using Python"
+ accesskey="N">next</a> |</li>
+ <li class="right" >
+ <a href="interactive.html" title="13. Interactive Input Editing and History Substitution"
+ accesskey="P">previous</a> |</li>
+ <li><img src="../_static/py.png" alt=""
+ style="vertical-align: middle; margin-top: -1px"/></li>
+ <li><a href="../index.html">Python v2.6.4c2 documentation</a> &raquo;</li>
+
+ <li><a href="index.html" accesskey="U">The Python Tutorial</a> &raquo;</li>
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body">
+
+ <div class="section" id="floating-point-arithmetic-issues-and-limitations">
+<span id="tut-fp-issues"></span><h1>14. Floating Point Arithmetic: Issues and Limitations<a class="headerlink" href="#floating-point-arithmetic-issues-and-limitations" title="Permalink to this headline">¶</a></h1>
+<p>Floating-point numbers are represented in computer hardware as base 2 (binary)
+fractions. For example, the decimal fraction</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="mf">0.125</span>
+</pre></div>
+</div>
+<p>has value 1/10 + 2/100 + 5/1000, and in the same way the binary fraction</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="mf">0.001</span>
+</pre></div>
+</div>
+<p>has value 0/2 + 0/4 + 1/8. These two fractions have identical values, the only
+real difference being that the first is written in base 10 fractional notation,
+and the second in base 2.</p>
+<p>Unfortunately, most decimal fractions cannot be represented exactly as binary
+fractions. A consequence is that, in general, the decimal floating-point
+numbers you enter are only approximated by the binary floating-point numbers
+actually stored in the machine.</p>
+<p>The problem is easier to understand at first in base 10. Consider the fraction
+1/3. You can approximate that as a base 10 fraction:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="mf">0.3</span>
+</pre></div>
+</div>
+<p>or, better,</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="mf">0.33</span>
+</pre></div>
+</div>
+<p>or, better,</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="mf">0.333</span>
+</pre></div>
+</div>
+<p>and so on. No matter how many digits you&#8217;re willing to write down, the result
+will never be exactly 1/3, but will be an increasingly better approximation of
+1/3.</p>
+<p>In the same way, no matter how many base 2 digits you&#8217;re willing to use, the
+decimal value 0.1 cannot be represented exactly as a base 2 fraction. In base
+2, 1/10 is the infinitely repeating fraction</p>
+<div class="highlight-python"><pre>0.0001100110011001100110011001100110011001100110011...</pre>
+</div>
+<p>Stop at any finite number of bits, and you get an approximation. This is why
+you see things like:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="mf">0.1</span>
+<span class="go">0.10000000000000001</span>
+</pre></div>
+</div>
+<p>On most machines today, that is what you&#8217;ll see if you enter 0.1 at a Python
+prompt. You may not, though, because the number of bits used by the hardware to
+store floating-point values can vary across machines, and Python only prints a
+decimal approximation to the true decimal value of the binary approximation
+stored by the machine. On most machines, if Python were to print the true
+decimal value of the binary approximation stored for 0.1, it would have to
+display</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="mf">0.1</span>
+<span class="go">0.1000000000000000055511151231257827021181583404541015625</span>
+</pre></div>
+</div>
+<p>instead! The Python prompt uses the built-in <a title="repr" class="reference external" href="../library/functions.html#repr"><tt class="xref docutils literal"><span class="pre">repr()</span></tt></a> function to obtain a
+string version of everything it displays. For floats, <tt class="docutils literal"><span class="pre">repr(float)</span></tt> rounds
+the true decimal value to 17 significant digits, giving</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="mf">0.10000000000000001</span>
+</pre></div>
+</div>
+<p><tt class="docutils literal"><span class="pre">repr(float)</span></tt> produces 17 significant digits because it turns out that&#8217;s
+enough (on most machines) so that <tt class="docutils literal"><span class="pre">eval(repr(x))</span> <span class="pre">==</span> <span class="pre">x</span></tt> exactly for all finite
+floats <em>x</em>, but rounding to 16 digits is not enough to make that true.</p>
+<p>Note that this is in the very nature of binary floating-point: this is not a bug
+in Python, and it is not a bug in your code either. You&#8217;ll see the same kind of
+thing in all languages that support your hardware&#8217;s floating-point arithmetic
+(although some languages may not <em>display</em> the difference by default, or in all
+output modes).</p>
+<p>Python&#8217;s built-in <a title="str" class="reference external" href="../library/functions.html#str"><tt class="xref docutils literal"><span class="pre">str()</span></tt></a> function produces only 12 significant digits, and
+you may wish to use that instead. It&#8217;s unusual for <tt class="docutils literal"><span class="pre">eval(str(x))</span></tt> to
+reproduce <em>x</em>, but the output may be more pleasant to look at:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">print</span> <span class="nb">str</span><span class="p">(</span><span class="mf">0.1</span><span class="p">)</span>
+<span class="go">0.1</span>
+</pre></div>
+</div>
+<p>It&#8217;s important to realize that this is, in a real sense, an illusion: the value
+in the machine is not exactly 1/10, you&#8217;re simply rounding the <em>display</em> of the
+true machine value.</p>
+<p>Other surprises follow from this one. For example, after seeing</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="mf">0.1</span>
+<span class="go">0.10000000000000001</span>
+</pre></div>
+</div>
+<p>you may be tempted to use the <a title="round" class="reference external" href="../library/functions.html#round"><tt class="xref docutils literal"><span class="pre">round()</span></tt></a> function to chop it back to the
+single digit you expect. But that makes no difference:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="nb">round</span><span class="p">(</span><span class="mf">0.1</span><span class="p">,</span> <span class="mf">1</span><span class="p">)</span>
+<span class="go">0.10000000000000001</span>
+</pre></div>
+</div>
+<p>The problem is that the binary floating-point value stored for &#8220;0.1&#8221; was already
+the best possible binary approximation to 1/10, so trying to round it again
+can&#8217;t make it better: it was already as good as it gets.</p>
+<p>Another consequence is that since 0.1 is not exactly 1/10, summing ten values of
+0.1 may not yield exactly 1.0, either:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="nb">sum</span> <span class="o">=</span> <span class="mf">0.0</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mf">10</span><span class="p">):</span>
+<span class="gp">... </span> <span class="nb">sum</span> <span class="o">+=</span> <span class="mf">0.1</span>
+<span class="gp">...</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">sum</span>
+<span class="go">0.99999999999999989</span>
+</pre></div>
+</div>
+<p>Binary floating-point arithmetic holds many surprises like this. The problem
+with &#8220;0.1&#8221; is explained in precise detail below, in the &#8220;Representation Error&#8221;
+section. See <a class="reference external" href="http://www.lahey.com/float.htm">The Perils of Floating Point</a>
+for a more complete account of other common surprises.</p>
+<p>As that says near the end, &#8220;there are no easy answers.&#8221; Still, don&#8217;t be unduly
+wary of floating-point! The errors in Python float operations are inherited
+from the floating-point hardware, and on most machines are on the order of no
+more than 1 part in 2**53 per operation. That&#8217;s more than adequate for most
+tasks, but you do need to keep in mind that it&#8217;s not decimal arithmetic, and
+that every float operation can suffer a new rounding error.</p>
+<p>While pathological cases do exist, for most casual use of floating-point
+arithmetic you&#8217;ll see the result you expect in the end if you simply round the
+display of your final results to the number of decimal digits you expect.
+<a title="str" class="reference external" href="../library/functions.html#str"><tt class="xref docutils literal"><span class="pre">str()</span></tt></a> usually suffices, and for finer control see the <a title="str.format" class="reference external" href="../library/stdtypes.html#str.format"><tt class="xref docutils literal"><span class="pre">str.format()</span></tt></a>
+method&#8217;s format specifiers in <a class="reference external" href="../library/string.html#formatstrings"><em>Format String Syntax</em></a>.</p>
+<div class="section" id="representation-error">
+<span id="tut-fp-error"></span><h2>14.1. Representation Error<a class="headerlink" href="#representation-error" title="Permalink to this headline">¶</a></h2>
+<p>This section explains the &#8220;0.1&#8221; example in detail, and shows how you can perform
+an exact analysis of cases like this yourself. Basic familiarity with binary
+floating-point representation is assumed.</p>
+<p><em>Representation error</em> refers to the fact that some (most, actually)
+decimal fractions cannot be represented exactly as binary (base 2) fractions.
+This is the chief reason why Python (or Perl, C, C++, Java, Fortran, and many
+others) often won&#8217;t display the exact decimal number you expect:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="mf">0.1</span>
+<span class="go">0.10000000000000001</span>
+</pre></div>
+</div>
+<p>Why is that? 1/10 is not exactly representable as a binary fraction. Almost all
+machines today (November 2000) use IEEE-754 floating point arithmetic, and
+almost all platforms map Python floats to IEEE-754 &#8220;double precision&#8221;. 754
+doubles contain 53 bits of precision, so on input the computer strives to
+convert 0.1 to the closest fraction it can of the form <em>J</em>/2***N* where <em>J</em> is
+an integer containing exactly 53 bits. Rewriting</p>
+<div class="highlight-python"><pre>1 / 10 ~= J / (2**N)</pre>
+</div>
+<p>as</p>
+<div class="highlight-python"><pre>J ~= 2**N / 10</pre>
+</div>
+<p>and recalling that <em>J</em> has exactly 53 bits (is <tt class="docutils literal"><span class="pre">&gt;=</span> <span class="pre">2**52</span></tt> but <tt class="docutils literal"><span class="pre">&lt;</span> <span class="pre">2**53</span></tt>),
+the best value for <em>N</em> is 56:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="mf">2</span><span class="o">**</span><span class="mf">52</span>
+<span class="go">4503599627370496L</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="mf">2</span><span class="o">**</span><span class="mf">53</span>
+<span class="go">9007199254740992L</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="mf">2</span><span class="o">**</span><span class="mf">56</span><span class="o">/</span><span class="mf">10</span>
+<span class="go">7205759403792793L</span>
+</pre></div>
+</div>
+<p>That is, 56 is the only value for <em>N</em> that leaves <em>J</em> with exactly 53 bits. The
+best possible value for <em>J</em> is then that quotient rounded:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">q</span><span class="p">,</span> <span class="n">r</span> <span class="o">=</span> <span class="nb">divmod</span><span class="p">(</span><span class="mf">2</span><span class="o">**</span><span class="mf">56</span><span class="p">,</span> <span class="mf">10</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">r</span>
+<span class="go">6L</span>
+</pre></div>
+</div>
+<p>Since the remainder is more than half of 10, the best approximation is obtained
+by rounding up:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">q</span><span class="o">+</span><span class="mf">1</span>
+<span class="go">7205759403792794L</span>
+</pre></div>
+</div>
+<p>Therefore the best possible approximation to 1/10 in 754 double precision is
+that over 2**56, or</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="mf">7205759403792794</span> <span class="o">/</span> <span class="mf">72057594037927936</span>
+</pre></div>
+</div>
+<p>Note that since we rounded up, this is actually a little bit larger than 1/10;
+if we had not rounded up, the quotient would have been a little bit smaller than
+1/10. But in no case can it be <em>exactly</em> 1/10!</p>
+<p>So the computer never &#8220;sees&#8221; 1/10: what it sees is the exact fraction given
+above, the best 754 double approximation it can get:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="o">.</span><span class="mf">1</span> <span class="o">*</span> <span class="mf">2</span><span class="o">**</span><span class="mf">56</span>
+<span class="go">7205759403792794.0</span>
+</pre></div>
+</div>
+<p>If we multiply that fraction by 10**30, we can see the (truncated) value of
+its 30 most significant decimal digits:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="mf">7205759403792794</span> <span class="o">*</span> <span class="mf">10</span><span class="o">**</span><span class="mf">30</span> <span class="o">/</span> <span class="mf">2</span><span class="o">**</span><span class="mf">56</span>
+<span class="go">100000000000000005551115123125L</span>
+</pre></div>
+</div>
+<p>meaning that the exact number stored in the computer is approximately equal to
+the decimal value 0.100000000000000005551115123125. Rounding that to 17
+significant digits gives the 0.10000000000000001 that Python displays (well,
+will display on any 754-conforming platform that does best-possible input and
+output conversions in its C library &#8212; yours may not!).</p>
+</div>
+</div>
+
+
+ </div>
+ </div>
+ </div>
+ <div class="sphinxsidebar">
+ <div class="sphinxsidebarwrapper">
+ <h3><a href="../contents.html">Table Of Contents</a></h3>
+ <ul>
+<li><a class="reference external" href="">14. Floating Point Arithmetic: Issues and Limitations</a><ul>
+<li><a class="reference external" href="#representation-error">14.1. Representation Error</a></li>
+</ul>
+</li>
+</ul>
+
+ <h4>Previous topic</h4>
+ <p class="topless"><a href="interactive.html"
+ title="previous chapter">13. Interactive Input Editing and History Substitution</a></p>
+ <h4>Next topic</h4>
+ <p class="topless"><a href="../using/index.html"
+ title="next chapter">Using Python</a></p>
+ <h3>This Page</h3>
+ <ul class="this-page-menu">
+ <li><a href="../_sources/tutorial/floatingpoint.txt"
+ rel="nofollow">Show Source</a></li>
+ </ul>
+ <div id="searchbox" style="display: none">
+ <h3>Quick search</h3>
+ <form class="search" action="../search.html" method="get">
+ <input type="text" name="q" size="18" />
+ <input type="submit" value="Go" />
+ <input type="hidden" name="check_keywords" value="yes" />
+ <input type="hidden" name="area" value="default" />
+ </form>
+ <p class="searchtip" style="font-size: 90%">
+ Enter search terms or a module, class or function name.
+ </p>
+ </div>
+ <script type="text/javascript">$('#searchbox').show(0);</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../genindex.html" title="General Index"
+ >index</a></li>
+ <li class="right" >
+ <a href="../modindex.html" title="Global Module Index"
+ >modules</a> |</li>
+ <li class="right" >
+ <a href="../using/index.html" title="Using Python"
+ >next</a> |</li>
+ <li class="right" >
+ <a href="interactive.html" title="13. Interactive Input Editing and History Substitution"
+ >previous</a> |</li>
+ <li><img src="../_static/py.png" alt=""
+ style="vertical-align: middle; margin-top: -1px"/></li>
+ <li><a href="../index.html">Python v2.6.4c2 documentation</a> &raquo;</li>
+
+ <li><a href="index.html" >The Python Tutorial</a> &raquo;</li>
+ </ul>
+ </div>
+ <div class="footer">
+ &copy; <a href="../copyright.html">Copyright</a> 1990-2009, Python Software Foundation.
+ <br />
+ The Python Software Foundation is a non-profit corporation.
+ <a href="http://www.python.org/psf/donations/">Please donate.</a>
+ <br />
+ Last updated on Oct 19, 2009.
+ Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 0.6.2.
+ </div>
+
+ </body>
+</html> \ No newline at end of file
diff --git a/help/PythonTutorial/tutorial/index.html b/help/PythonTutorial/tutorial/index.html
new file mode 100644
index 0000000..c70fbde
--- /dev/null
+++ b/help/PythonTutorial/tutorial/index.html
@@ -0,0 +1,337 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+ <title>The Python Tutorial &mdash; Python v2.6.4c2 documentation</title>
+ <link rel="stylesheet" href="../_static/default.css" type="text/css" />
+ <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
+ <script type="text/javascript">
+ var DOCUMENTATION_OPTIONS = {
+ URL_ROOT: '../',
+ VERSION: '2.6.4c2',
+ COLLAPSE_MODINDEX: false,
+ FILE_SUFFIX: '.html',
+ HAS_SOURCE: true
+ };
+ </script>
+ <script type="text/javascript" src="../_static/jquery.js"></script>
+ <script type="text/javascript" src="../_static/doctools.js"></script>
+ <link rel="search" type="application/opensearchdescription+xml"
+ title="Search within Python v2.6.4c2 documentation"
+ href="../_static/opensearch.xml"/>
+ <link rel="author" title="About these documents" href="../about.html" />
+ <link rel="copyright" title="Copyright" href="../copyright.html" />
+ <link rel="top" title="Python v2.6.4c2 documentation" href="../index.html" />
+ <link rel="next" title="1. Whetting Your Appetite" href="appetite.html" />
+ <link rel="prev" title="What’s New in Python 2.0" href="../whatsnew/2.0.html" />
+ <link rel="shortcut icon" type="image/png" href="../_static/py.png" />
+
+
+ </head>
+ <body>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../modindex.html" title="Global Module Index"
+ accesskey="M">modules</a> |</li>
+ <li class="right" >
+ <a href="appetite.html" title="1. Whetting Your Appetite"
+ accesskey="N">next</a> |</li>
+ <li class="right" >
+ <a href="../whatsnew/2.0.html" title="What’s New in Python 2.0"
+ accesskey="P">previous</a> |</li>
+ <li><img src="../_static/py.png" alt=""
+ style="vertical-align: middle; margin-top: -1px"/></li>
+ <li><a href="../index.html">Python v2.6.4c2 documentation</a> &raquo;</li>
+
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body">
+
+ <div class="section" id="the-python-tutorial">
+<span id="tutorial-index"></span><h1>The Python Tutorial<a class="headerlink" href="#the-python-tutorial" title="Permalink to this headline">¶</a></h1>
+<table class="docutils field-list" frame="void" rules="none">
+<col class="field-name" />
+<col class="field-body" />
+<tbody valign="top">
+<tr class="field"><th class="field-name">Release:</th><td class="field-body">2.6</td>
+</tr>
+<tr class="field"><th class="field-name">Date:</th><td class="field-body">October 19, 2009</td>
+</tr>
+</tbody>
+</table>
+<p>Python is an easy to learn, powerful programming language. It has efficient
+high-level data structures and a simple but effective approach to
+object-oriented programming. Python&#8217;s elegant syntax and dynamic typing,
+together with its interpreted nature, make it an ideal language for scripting
+and rapid application development in many areas on most platforms.</p>
+<p>The Python interpreter and the extensive standard library are freely available
+in source or binary form for all major platforms from the Python Web site,
+<a class="reference external" href="http://www.python.org/">http://www.python.org/</a>, and may be freely distributed. The same site also
+contains distributions of and pointers to many free third party Python modules,
+programs and tools, and additional documentation.</p>
+<p>The Python interpreter is easily extended with new functions and data types
+implemented in C or C++ (or other languages callable from C). Python is also
+suitable as an extension language for customizable applications.</p>
+<p>This tutorial introduces the reader informally to the basic concepts and
+features of the Python language and system. It helps to have a Python
+interpreter handy for hands-on experience, but all examples are self-contained,
+so the tutorial can be read off-line as well.</p>
+<p>For a description of standard objects and modules, see the Python Library
+Reference document. The Python Reference Manual gives a more formal definition
+of the language. To write extensions in C or C++, read Extending and Embedding
+the Python Interpreter and Python/C API Reference. There are also several books
+covering Python in depth.</p>
+<p>This tutorial does not attempt to be comprehensive and cover every single
+feature, or even every commonly used feature. Instead, it introduces many of
+Python&#8217;s most noteworthy features, and will give you a good idea of the
+language&#8217;s flavor and style. After reading it, you will be able to read and
+write Python modules and programs, and you will be ready to learn more about the
+various Python library modules described in the Python Library Reference.</p>
+<p>The <a class="reference external" href="../glossary.html#glossary"><em>Glossary</em></a> is also worth going through.</p>
+<ul>
+<li class="toctree-l1"><a class="reference external" href="appetite.html">1. Whetting Your Appetite</a></li>
+<li class="toctree-l1"><a class="reference external" href="interpreter.html">2. Using the Python Interpreter</a><ul>
+<li class="toctree-l2"><a class="reference external" href="interpreter.html#invoking-the-interpreter">2.1. Invoking the Interpreter</a><ul>
+<li class="toctree-l3"><a class="reference external" href="interpreter.html#argument-passing">2.1.1. Argument Passing</a></li>
+<li class="toctree-l3"><a class="reference external" href="interpreter.html#interactive-mode">2.1.2. Interactive Mode</a></li>
+</ul>
+</li>
+<li class="toctree-l2"><a class="reference external" href="interpreter.html#the-interpreter-and-its-environment">2.2. The Interpreter and Its Environment</a><ul>
+<li class="toctree-l3"><a class="reference external" href="interpreter.html#error-handling">2.2.1. Error Handling</a></li>
+<li class="toctree-l3"><a class="reference external" href="interpreter.html#executable-python-scripts">2.2.2. Executable Python Scripts</a></li>
+<li class="toctree-l3"><a class="reference external" href="interpreter.html#source-code-encoding">2.2.3. Source Code Encoding</a></li>
+<li class="toctree-l3"><a class="reference external" href="interpreter.html#the-interactive-startup-file">2.2.4. The Interactive Startup File</a></li>
+</ul>
+</li>
+</ul>
+</li>
+<li class="toctree-l1"><a class="reference external" href="introduction.html">3. An Informal Introduction to Python</a><ul>
+<li class="toctree-l2"><a class="reference external" href="introduction.html#using-python-as-a-calculator">3.1. Using Python as a Calculator</a><ul>
+<li class="toctree-l3"><a class="reference external" href="introduction.html#numbers">3.1.1. Numbers</a></li>
+<li class="toctree-l3"><a class="reference external" href="introduction.html#strings">3.1.2. Strings</a></li>
+<li class="toctree-l3"><a class="reference external" href="introduction.html#unicode-strings">3.1.3. Unicode Strings</a></li>
+<li class="toctree-l3"><a class="reference external" href="introduction.html#lists">3.1.4. Lists</a></li>
+</ul>
+</li>
+<li class="toctree-l2"><a class="reference external" href="introduction.html#first-steps-towards-programming">3.2. First Steps Towards Programming</a></li>
+</ul>
+</li>
+<li class="toctree-l1"><a class="reference external" href="controlflow.html">4. More Control Flow Tools</a><ul>
+<li class="toctree-l2"><a class="reference external" href="controlflow.html#if-statements">4.1. <tt class="docutils literal"><span class="pre">if</span></tt> Statements</a></li>
+<li class="toctree-l2"><a class="reference external" href="controlflow.html#for-statements">4.2. <tt class="docutils literal"><span class="pre">for</span></tt> Statements</a></li>
+<li class="toctree-l2"><a class="reference external" href="controlflow.html#the-range-function">4.3. The <tt class="docutils literal"><span class="pre">range()</span></tt> Function</a></li>
+<li class="toctree-l2"><a class="reference external" href="controlflow.html#break-and-continue-statements-and-else-clauses-on-loops">4.4. <tt class="docutils literal"><span class="pre">break</span></tt> and <tt class="docutils literal"><span class="pre">continue</span></tt> Statements, and <tt class="docutils literal"><span class="pre">else</span></tt> Clauses on Loops</a></li>
+<li class="toctree-l2"><a class="reference external" href="controlflow.html#pass-statements">4.5. <tt class="docutils literal"><span class="pre">pass</span></tt> Statements</a></li>
+<li class="toctree-l2"><a class="reference external" href="controlflow.html#defining-functions">4.6. Defining Functions</a></li>
+<li class="toctree-l2"><a class="reference external" href="controlflow.html#more-on-defining-functions">4.7. More on Defining Functions</a><ul>
+<li class="toctree-l3"><a class="reference external" href="controlflow.html#default-argument-values">4.7.1. Default Argument Values</a></li>
+<li class="toctree-l3"><a class="reference external" href="controlflow.html#keyword-arguments">4.7.2. Keyword Arguments</a></li>
+<li class="toctree-l3"><a class="reference external" href="controlflow.html#arbitrary-argument-lists">4.7.3. Arbitrary Argument Lists</a></li>
+<li class="toctree-l3"><a class="reference external" href="controlflow.html#unpacking-argument-lists">4.7.4. Unpacking Argument Lists</a></li>
+<li class="toctree-l3"><a class="reference external" href="controlflow.html#lambda-forms">4.7.5. Lambda Forms</a></li>
+<li class="toctree-l3"><a class="reference external" href="controlflow.html#documentation-strings">4.7.6. Documentation Strings</a></li>
+</ul>
+</li>
+<li class="toctree-l2"><a class="reference external" href="controlflow.html#intermezzo-coding-style">4.8. Intermezzo: Coding Style</a></li>
+</ul>
+</li>
+<li class="toctree-l1"><a class="reference external" href="datastructures.html">5. Data Structures</a><ul>
+<li class="toctree-l2"><a class="reference external" href="datastructures.html#more-on-lists">5.1. More on Lists</a><ul>
+<li class="toctree-l3"><a class="reference external" href="datastructures.html#using-lists-as-stacks">5.1.1. Using Lists as Stacks</a></li>
+<li class="toctree-l3"><a class="reference external" href="datastructures.html#using-lists-as-queues">5.1.2. Using Lists as Queues</a></li>
+<li class="toctree-l3"><a class="reference external" href="datastructures.html#functional-programming-tools">5.1.3. Functional Programming Tools</a></li>
+<li class="toctree-l3"><a class="reference external" href="datastructures.html#list-comprehensions">5.1.4. List Comprehensions</a></li>
+<li class="toctree-l3"><a class="reference external" href="datastructures.html#nested-list-comprehensions">5.1.5. Nested List Comprehensions</a></li>
+</ul>
+</li>
+<li class="toctree-l2"><a class="reference external" href="datastructures.html#the-del-statement">5.2. The <tt class="docutils literal"><span class="pre">del</span></tt> statement</a></li>
+<li class="toctree-l2"><a class="reference external" href="datastructures.html#tuples-and-sequences">5.3. Tuples and Sequences</a></li>
+<li class="toctree-l2"><a class="reference external" href="datastructures.html#sets">5.4. Sets</a></li>
+<li class="toctree-l2"><a class="reference external" href="datastructures.html#dictionaries">5.5. Dictionaries</a></li>
+<li class="toctree-l2"><a class="reference external" href="datastructures.html#looping-techniques">5.6. Looping Techniques</a></li>
+<li class="toctree-l2"><a class="reference external" href="datastructures.html#more-on-conditions">5.7. More on Conditions</a></li>
+<li class="toctree-l2"><a class="reference external" href="datastructures.html#comparing-sequences-and-other-types">5.8. Comparing Sequences and Other Types</a></li>
+</ul>
+</li>
+<li class="toctree-l1"><a class="reference external" href="modules.html">6. Modules</a><ul>
+<li class="toctree-l2"><a class="reference external" href="modules.html#more-on-modules">6.1. More on Modules</a><ul>
+<li class="toctree-l3"><a class="reference external" href="modules.html#executing-modules-as-scripts">6.1.1. Executing modules as scripts</a></li>
+<li class="toctree-l3"><a class="reference external" href="modules.html#the-module-search-path">6.1.2. The Module Search Path</a></li>
+<li class="toctree-l3"><a class="reference external" href="modules.html#compiled-python-files">6.1.3. &#8220;Compiled&#8221; Python files</a></li>
+</ul>
+</li>
+<li class="toctree-l2"><a class="reference external" href="modules.html#standard-modules">6.2. Standard Modules</a></li>
+<li class="toctree-l2"><a class="reference external" href="modules.html#the-dir-function">6.3. The <tt class="docutils literal"><span class="pre">dir()</span></tt> Function</a></li>
+<li class="toctree-l2"><a class="reference external" href="modules.html#packages">6.4. Packages</a><ul>
+<li class="toctree-l3"><a class="reference external" href="modules.html#importing-from-a-package">6.4.1. Importing * From a Package</a></li>
+<li class="toctree-l3"><a class="reference external" href="modules.html#intra-package-references">6.4.2. Intra-package References</a></li>
+<li class="toctree-l3"><a class="reference external" href="modules.html#packages-in-multiple-directories">6.4.3. Packages in Multiple Directories</a></li>
+</ul>
+</li>
+</ul>
+</li>
+<li class="toctree-l1"><a class="reference external" href="inputoutput.html">7. Input and Output</a><ul>
+<li class="toctree-l2"><a class="reference external" href="inputoutput.html#fancier-output-formatting">7.1. Fancier Output Formatting</a><ul>
+<li class="toctree-l3"><a class="reference external" href="inputoutput.html#old-string-formatting">7.1.1. Old string formatting</a></li>
+</ul>
+</li>
+<li class="toctree-l2"><a class="reference external" href="inputoutput.html#reading-and-writing-files">7.2. Reading and Writing Files</a><ul>
+<li class="toctree-l3"><a class="reference external" href="inputoutput.html#methods-of-file-objects">7.2.1. Methods of File Objects</a></li>
+<li class="toctree-l3"><a class="reference external" href="inputoutput.html#the-pickle-module">7.2.2. The <tt class="docutils literal"><span class="pre">pickle</span></tt> Module</a></li>
+</ul>
+</li>
+</ul>
+</li>
+<li class="toctree-l1"><a class="reference external" href="errors.html">8. Errors and Exceptions</a><ul>
+<li class="toctree-l2"><a class="reference external" href="errors.html#syntax-errors">8.1. Syntax Errors</a></li>
+<li class="toctree-l2"><a class="reference external" href="errors.html#exceptions">8.2. Exceptions</a></li>
+<li class="toctree-l2"><a class="reference external" href="errors.html#handling-exceptions">8.3. Handling Exceptions</a></li>
+<li class="toctree-l2"><a class="reference external" href="errors.html#raising-exceptions">8.4. Raising Exceptions</a></li>
+<li class="toctree-l2"><a class="reference external" href="errors.html#user-defined-exceptions">8.5. User-defined Exceptions</a></li>
+<li class="toctree-l2"><a class="reference external" href="errors.html#defining-clean-up-actions">8.6. Defining Clean-up Actions</a></li>
+<li class="toctree-l2"><a class="reference external" href="errors.html#predefined-clean-up-actions">8.7. Predefined Clean-up Actions</a></li>
+</ul>
+</li>
+<li class="toctree-l1"><a class="reference external" href="classes.html">9. Classes</a><ul>
+<li class="toctree-l2"><a class="reference external" href="classes.html#a-word-about-terminology">9.1. A Word About Terminology</a></li>
+<li class="toctree-l2"><a class="reference external" href="classes.html#python-scopes-and-name-spaces">9.2. Python Scopes and Name Spaces</a></li>
+<li class="toctree-l2"><a class="reference external" href="classes.html#a-first-look-at-classes">9.3. A First Look at Classes</a><ul>
+<li class="toctree-l3"><a class="reference external" href="classes.html#class-definition-syntax">9.3.1. Class Definition Syntax</a></li>
+<li class="toctree-l3"><a class="reference external" href="classes.html#class-objects">9.3.2. Class Objects</a></li>
+<li class="toctree-l3"><a class="reference external" href="classes.html#instance-objects">9.3.3. Instance Objects</a></li>
+<li class="toctree-l3"><a class="reference external" href="classes.html#method-objects">9.3.4. Method Objects</a></li>
+</ul>
+</li>
+<li class="toctree-l2"><a class="reference external" href="classes.html#random-remarks">9.4. Random Remarks</a></li>
+<li class="toctree-l2"><a class="reference external" href="classes.html#inheritance">9.5. Inheritance</a><ul>
+<li class="toctree-l3"><a class="reference external" href="classes.html#multiple-inheritance">9.5.1. Multiple Inheritance</a></li>
+</ul>
+</li>
+<li class="toctree-l2"><a class="reference external" href="classes.html#private-variables">9.6. Private Variables</a></li>
+<li class="toctree-l2"><a class="reference external" href="classes.html#odds-and-ends">9.7. Odds and Ends</a></li>
+<li class="toctree-l2"><a class="reference external" href="classes.html#exceptions-are-classes-too">9.8. Exceptions Are Classes Too</a></li>
+<li class="toctree-l2"><a class="reference external" href="classes.html#iterators">9.9. Iterators</a></li>
+<li class="toctree-l2"><a class="reference external" href="classes.html#generators">9.10. Generators</a></li>
+<li class="toctree-l2"><a class="reference external" href="classes.html#generator-expressions">9.11. Generator Expressions</a></li>
+</ul>
+</li>
+<li class="toctree-l1"><a class="reference external" href="stdlib.html">10. Brief Tour of the Standard Library</a><ul>
+<li class="toctree-l2"><a class="reference external" href="stdlib.html#operating-system-interface">10.1. Operating System Interface</a></li>
+<li class="toctree-l2"><a class="reference external" href="stdlib.html#file-wildcards">10.2. File Wildcards</a></li>
+<li class="toctree-l2"><a class="reference external" href="stdlib.html#command-line-arguments">10.3. Command Line Arguments</a></li>
+<li class="toctree-l2"><a class="reference external" href="stdlib.html#error-output-redirection-and-program-termination">10.4. Error Output Redirection and Program Termination</a></li>
+<li class="toctree-l2"><a class="reference external" href="stdlib.html#string-pattern-matching">10.5. String Pattern Matching</a></li>
+<li class="toctree-l2"><a class="reference external" href="stdlib.html#mathematics">10.6. Mathematics</a></li>
+<li class="toctree-l2"><a class="reference external" href="stdlib.html#internet-access">10.7. Internet Access</a></li>
+<li class="toctree-l2"><a class="reference external" href="stdlib.html#dates-and-times">10.8. Dates and Times</a></li>
+<li class="toctree-l2"><a class="reference external" href="stdlib.html#data-compression">10.9. Data Compression</a></li>
+<li class="toctree-l2"><a class="reference external" href="stdlib.html#performance-measurement">10.10. Performance Measurement</a></li>
+<li class="toctree-l2"><a class="reference external" href="stdlib.html#quality-control">10.11. Quality Control</a></li>
+<li class="toctree-l2"><a class="reference external" href="stdlib.html#batteries-included">10.12. Batteries Included</a></li>
+</ul>
+</li>
+<li class="toctree-l1"><a class="reference external" href="stdlib2.html">11. Brief Tour of the Standard Library &#8211; Part II</a><ul>
+<li class="toctree-l2"><a class="reference external" href="stdlib2.html#output-formatting">11.1. Output Formatting</a></li>
+<li class="toctree-l2"><a class="reference external" href="stdlib2.html#templating">11.2. Templating</a></li>
+<li class="toctree-l2"><a class="reference external" href="stdlib2.html#working-with-binary-data-record-layouts">11.3. Working with Binary Data Record Layouts</a></li>
+<li class="toctree-l2"><a class="reference external" href="stdlib2.html#multi-threading">11.4. Multi-threading</a></li>
+<li class="toctree-l2"><a class="reference external" href="stdlib2.html#logging">11.5. Logging</a></li>
+<li class="toctree-l2"><a class="reference external" href="stdlib2.html#weak-references">11.6. Weak References</a></li>
+<li class="toctree-l2"><a class="reference external" href="stdlib2.html#tools-for-working-with-lists">11.7. Tools for Working with Lists</a></li>
+<li class="toctree-l2"><a class="reference external" href="stdlib2.html#decimal-floating-point-arithmetic">11.8. Decimal Floating Point Arithmetic</a></li>
+</ul>
+</li>
+<li class="toctree-l1"><a class="reference external" href="whatnow.html">12. What Now?</a></li>
+<li class="toctree-l1"><a class="reference external" href="interactive.html">13. Interactive Input Editing and History Substitution</a><ul>
+<li class="toctree-l2"><a class="reference external" href="interactive.html#line-editing">13.1. Line Editing</a></li>
+<li class="toctree-l2"><a class="reference external" href="interactive.html#history-substitution">13.2. History Substitution</a></li>
+<li class="toctree-l2"><a class="reference external" href="interactive.html#key-bindings">13.3. Key Bindings</a></li>
+<li class="toctree-l2"><a class="reference external" href="interactive.html#commentary">13.4. Commentary</a></li>
+</ul>
+</li>
+<li class="toctree-l1"><a class="reference external" href="floatingpoint.html">14. Floating Point Arithmetic: Issues and Limitations</a><ul>
+<li class="toctree-l2"><a class="reference external" href="floatingpoint.html#representation-error">14.1. Representation Error</a></li>
+</ul>
+</li>
+</ul>
+</div>
+
+
+ </div>
+ </div>
+ </div>
+ <div class="sphinxsidebar">
+ <div class="sphinxsidebarwrapper">
+ <h4>Previous topic</h4>
+ <p class="topless"><a href="../whatsnew/2.0.html"
+ title="previous chapter">What&#8217;s New in Python 2.0</a></p>
+ <h4>Next topic</h4>
+ <p class="topless"><a href="appetite.html"
+ title="next chapter">1. Whetting Your Appetite</a></p>
+ <h3>This Page</h3>
+ <ul class="this-page-menu">
+ <li><a href="../_sources/tutorial/index.txt"
+ rel="nofollow">Show Source</a></li>
+ </ul>
+ <div id="searchbox" style="display: none">
+ <h3>Quick search</h3>
+ <form class="search" action="../search.html" method="get">
+ <input type="text" name="q" size="18" />
+ <input type="submit" value="Go" />
+ <input type="hidden" name="check_keywords" value="yes" />
+ <input type="hidden" name="area" value="default" />
+ </form>
+ <p class="searchtip" style="font-size: 90%">
+ Enter search terms or a module, class or function name.
+ </p>
+ </div>
+ <script type="text/javascript">$('#searchbox').show(0);</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../genindex.html" title="General Index"
+ >index</a></li>
+ <li class="right" >
+ <a href="../modindex.html" title="Global Module Index"
+ >modules</a> |</li>
+ <li class="right" >
+ <a href="appetite.html" title="1. Whetting Your Appetite"
+ >next</a> |</li>
+ <li class="right" >
+ <a href="../whatsnew/2.0.html" title="What’s New in Python 2.0"
+ >previous</a> |</li>
+ <li><img src="../_static/py.png" alt=""
+ style="vertical-align: middle; margin-top: -1px"/></li>
+ <li><a href="../index.html">Python v2.6.4c2 documentation</a> &raquo;</li>
+
+ </ul>
+ </div>
+ <div class="footer">
+ &copy; <a href="../copyright.html">Copyright</a> 1990-2009, Python Software Foundation.
+ <br />
+ The Python Software Foundation is a non-profit corporation.
+ <a href="http://www.python.org/psf/donations/">Please donate.</a>
+ <br />
+ Last updated on Oct 19, 2009.
+ Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 0.6.2.
+ </div>
+
+ </body>
+</html> \ No newline at end of file
diff --git a/help/PythonTutorial/tutorial/inputoutput.html b/help/PythonTutorial/tutorial/inputoutput.html
new file mode 100644
index 0000000..1aa8347
--- /dev/null
+++ b/help/PythonTutorial/tutorial/inputoutput.html
@@ -0,0 +1,506 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+ <title>7. Input and Output &mdash; Python v2.6.4c2 documentation</title>
+ <link rel="stylesheet" href="../_static/default.css" type="text/css" />
+ <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
+ <script type="text/javascript">
+ var DOCUMENTATION_OPTIONS = {
+ URL_ROOT: '../',
+ VERSION: '2.6.4c2',
+ COLLAPSE_MODINDEX: false,
+ FILE_SUFFIX: '.html',
+ HAS_SOURCE: true
+ };
+ </script>
+ <script type="text/javascript" src="../_static/jquery.js"></script>
+ <script type="text/javascript" src="../_static/doctools.js"></script>
+ <link rel="search" type="application/opensearchdescription+xml"
+ title="Search within Python v2.6.4c2 documentation"
+ href="../_static/opensearch.xml"/>
+ <link rel="author" title="About these documents" href="../about.html" />
+ <link rel="copyright" title="Copyright" href="../copyright.html" />
+ <link rel="top" title="Python v2.6.4c2 documentation" href="../index.html" />
+ <link rel="up" title="The Python Tutorial" href="index.html" />
+ <link rel="next" title="8. Errors and Exceptions" href="errors.html" />
+ <link rel="prev" title="6. Modules" href="modules.html" />
+ <link rel="shortcut icon" type="image/png" href="../_static/py.png" />
+
+
+ </head>
+ <body>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../modindex.html" title="Global Module Index"
+ accesskey="M">modules</a> |</li>
+ <li class="right" >
+ <a href="errors.html" title="8. Errors and Exceptions"
+ accesskey="N">next</a> |</li>
+ <li class="right" >
+ <a href="modules.html" title="6. Modules"
+ accesskey="P">previous</a> |</li>
+ <li><img src="../_static/py.png" alt=""
+ style="vertical-align: middle; margin-top: -1px"/></li>
+ <li><a href="../index.html">Python v2.6.4c2 documentation</a> &raquo;</li>
+
+ <li><a href="index.html" accesskey="U">The Python Tutorial</a> &raquo;</li>
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body">
+
+ <div class="section" id="input-and-output">
+<span id="tut-io"></span><h1>7. Input and Output<a class="headerlink" href="#input-and-output" title="Permalink to this headline">¶</a></h1>
+<p>There are several ways to present the output of a program; data can be printed
+in a human-readable form, or written to a file for future use. This chapter will
+discuss some of the possibilities.</p>
+<div class="section" id="fancier-output-formatting">
+<span id="tut-formatting"></span><h2>7.1. Fancier Output Formatting<a class="headerlink" href="#fancier-output-formatting" title="Permalink to this headline">¶</a></h2>
+<p>So far we&#8217;ve encountered two ways of writing values: <em>expression statements</em> and
+the <a class="reference external" href="../reference/simple_stmts.html#print"><tt class="xref docutils literal"><span class="pre">print</span></tt></a> statement. (A third way is using the <tt class="xref docutils literal"><span class="pre">write()</span></tt> method
+of file objects; the standard output file can be referenced as <tt class="docutils literal"><span class="pre">sys.stdout</span></tt>.
+See the Library Reference for more information on this.)</p>
+<p id="index-1065">Often you&#8217;ll want more control over the formatting of your output than simply
+printing space-separated values. There are two ways to format your output; the
+first way is to do all the string handling yourself; using string slicing and
+concatenation operations you can create any layout you can imagine. The
+standard module <a title="Common string operations." class="reference external" href="../library/string.html#module-string"><tt class="xref docutils literal"><span class="pre">string</span></tt></a> contains some useful operations for padding
+strings to a given column width; these will be discussed shortly. The second
+way is to use the <a title="str.format" class="reference external" href="../library/stdtypes.html#str.format"><tt class="xref docutils literal"><span class="pre">str.format()</span></tt></a> method.</p>
+<p>One question remains, of course: how do you convert values to strings? Luckily,
+Python has ways to convert any value to a string: pass it to the <a title="repr" class="reference external" href="../library/functions.html#repr"><tt class="xref docutils literal"><span class="pre">repr()</span></tt></a>
+or <a title="str" class="reference external" href="../library/functions.html#str"><tt class="xref docutils literal"><span class="pre">str()</span></tt></a> functions.</p>
+<p>The <a title="str" class="reference external" href="../library/functions.html#str"><tt class="xref docutils literal"><span class="pre">str()</span></tt></a> function is meant to return representations of values which are
+fairly human-readable, while <a title="repr" class="reference external" href="../library/functions.html#repr"><tt class="xref docutils literal"><span class="pre">repr()</span></tt></a> is meant to generate representations
+which can be read by the interpreter (or will force a <a title="exceptions.SyntaxError" class="reference external" href="../library/exceptions.html#exceptions.SyntaxError"><tt class="xref docutils literal"><span class="pre">SyntaxError</span></tt></a> if
+there is not equivalent syntax). For objects which don&#8217;t have a particular
+representation for human consumption, <a title="str" class="reference external" href="../library/functions.html#str"><tt class="xref docutils literal"><span class="pre">str()</span></tt></a> will return the same value as
+<a title="repr" class="reference external" href="../library/functions.html#repr"><tt class="xref docutils literal"><span class="pre">repr()</span></tt></a>. Many values, such as numbers or structures like lists and
+dictionaries, have the same representation using either function. Strings and
+floating point numbers, in particular, have two distinct representations.</p>
+<p>Some examples:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">s</span> <span class="o">=</span> <span class="s">&#39;Hello, world.&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">str</span><span class="p">(</span><span class="n">s</span><span class="p">)</span>
+<span class="go">&#39;Hello, world.&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">repr</span><span class="p">(</span><span class="n">s</span><span class="p">)</span>
+<span class="go">&quot;&#39;Hello, world.&#39;&quot;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">str</span><span class="p">(</span><span class="mf">0.1</span><span class="p">)</span>
+<span class="go">&#39;0.1&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">repr</span><span class="p">(</span><span class="mf">0.1</span><span class="p">)</span>
+<span class="go">&#39;0.10000000000000001&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">x</span> <span class="o">=</span> <span class="mf">10</span> <span class="o">*</span> <span class="mf">3.25</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">y</span> <span class="o">=</span> <span class="mf">200</span> <span class="o">*</span> <span class="mf">200</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">s</span> <span class="o">=</span> <span class="s">&#39;The value of x is &#39;</span> <span class="o">+</span> <span class="nb">repr</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="o">+</span> <span class="s">&#39;, and y is &#39;</span> <span class="o">+</span> <span class="nb">repr</span><span class="p">(</span><span class="n">y</span><span class="p">)</span> <span class="o">+</span> <span class="s">&#39;...&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">print</span> <span class="n">s</span>
+<span class="go">The value of x is 32.5, and y is 40000...</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="c"># The repr() of a string adds string quotes and backslashes:</span>
+<span class="gp">... </span><span class="n">hello</span> <span class="o">=</span> <span class="s">&#39;hello, world</span><span class="se">\n</span><span class="s">&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">hellos</span> <span class="o">=</span> <span class="nb">repr</span><span class="p">(</span><span class="n">hello</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">print</span> <span class="n">hellos</span>
+<span class="go">&#39;hello, world\n&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="c"># The argument to repr() may be any Python object:</span>
+<span class="gp">... </span><span class="nb">repr</span><span class="p">((</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="p">(</span><span class="s">&#39;spam&#39;</span><span class="p">,</span> <span class="s">&#39;eggs&#39;</span><span class="p">)))</span>
+<span class="go">&quot;(32.5, 40000, (&#39;spam&#39;, &#39;eggs&#39;))&quot;</span>
+</pre></div>
+</div>
+<p>Here are two ways to write a table of squares and cubes:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mf">1</span><span class="p">,</span> <span class="mf">11</span><span class="p">):</span>
+<span class="gp">... </span> <span class="k">print</span> <span class="nb">repr</span><span class="p">(</span><span class="n">x</span><span class="p">)</span><span class="o">.</span><span class="n">rjust</span><span class="p">(</span><span class="mf">2</span><span class="p">),</span> <span class="nb">repr</span><span class="p">(</span><span class="n">x</span><span class="o">*</span><span class="n">x</span><span class="p">)</span><span class="o">.</span><span class="n">rjust</span><span class="p">(</span><span class="mf">3</span><span class="p">),</span>
+<span class="gp">... </span> <span class="c"># Note trailing comma on previous line</span>
+<span class="gp">... </span> <span class="k">print</span> <span class="nb">repr</span><span class="p">(</span><span class="n">x</span><span class="o">*</span><span class="n">x</span><span class="o">*</span><span class="n">x</span><span class="p">)</span><span class="o">.</span><span class="n">rjust</span><span class="p">(</span><span class="mf">4</span><span class="p">)</span>
+<span class="gp">...</span>
+<span class="go"> 1 1 1</span>
+<span class="go"> 2 4 8</span>
+<span class="go"> 3 9 27</span>
+<span class="go"> 4 16 64</span>
+<span class="go"> 5 25 125</span>
+<span class="go"> 6 36 216</span>
+<span class="go"> 7 49 343</span>
+<span class="go"> 8 64 512</span>
+<span class="go"> 9 81 729</span>
+<span class="go">10 100 1000</span>
+
+<span class="gp">&gt;&gt;&gt; </span><span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mf">1</span><span class="p">,</span><span class="mf">11</span><span class="p">):</span>
+<span class="gp">... </span> <span class="k">print</span> <span class="s">&#39;{0:2d} {1:3d} {2:4d}&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">x</span><span class="o">*</span><span class="n">x</span><span class="p">,</span> <span class="n">x</span><span class="o">*</span><span class="n">x</span><span class="o">*</span><span class="n">x</span><span class="p">)</span>
+<span class="gp">...</span>
+<span class="go"> 1 1 1</span>
+<span class="go"> 2 4 8</span>
+<span class="go"> 3 9 27</span>
+<span class="go"> 4 16 64</span>
+<span class="go"> 5 25 125</span>
+<span class="go"> 6 36 216</span>
+<span class="go"> 7 49 343</span>
+<span class="go"> 8 64 512</span>
+<span class="go"> 9 81 729</span>
+<span class="go">10 100 1000</span>
+</pre></div>
+</div>
+<p>(Note that in the first example, one space between each column was added by the
+way <a class="reference external" href="../reference/simple_stmts.html#print"><tt class="xref docutils literal"><span class="pre">print</span></tt></a> works: it always adds spaces between its arguments.)</p>
+<p>This example demonstrates the <tt class="xref docutils literal"><span class="pre">rjust()</span></tt> method of string objects, which
+right-justifies a string in a field of a given width by padding it with spaces
+on the left. There are similar methods <tt class="xref docutils literal"><span class="pre">ljust()</span></tt> and <tt class="xref docutils literal"><span class="pre">center()</span></tt>. These
+methods do not write anything, they just return a new string. If the input
+string is too long, they don&#8217;t truncate it, but return it unchanged; this will
+mess up your column lay-out but that&#8217;s usually better than the alternative,
+which would be lying about a value. (If you really want truncation you can
+always add a slice operation, as in <tt class="docutils literal"><span class="pre">x.ljust(n)[:n]</span></tt>.)</p>
+<p>There is another method, <tt class="xref docutils literal"><span class="pre">zfill()</span></tt>, which pads a numeric string on the left
+with zeros. It understands about plus and minus signs:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="s">&#39;12&#39;</span><span class="o">.</span><span class="n">zfill</span><span class="p">(</span><span class="mf">5</span><span class="p">)</span>
+<span class="go">&#39;00012&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="s">&#39;-3.14&#39;</span><span class="o">.</span><span class="n">zfill</span><span class="p">(</span><span class="mf">7</span><span class="p">)</span>
+<span class="go">&#39;-003.14&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="s">&#39;3.14159265359&#39;</span><span class="o">.</span><span class="n">zfill</span><span class="p">(</span><span class="mf">5</span><span class="p">)</span>
+<span class="go">&#39;3.14159265359&#39;</span>
+</pre></div>
+</div>
+<p>Basic usage of the <a title="str.format" class="reference external" href="../library/stdtypes.html#str.format"><tt class="xref docutils literal"><span class="pre">str.format()</span></tt></a> method looks like this:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">print</span> <span class="s">&#39;We are the {0} who say &quot;{1}!&quot;&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="s">&#39;knights&#39;</span><span class="p">,</span> <span class="s">&#39;Ni&#39;</span><span class="p">)</span>
+<span class="go">We are the knights who say &quot;Ni!&quot;</span>
+</pre></div>
+</div>
+<p>The brackets and characters within them (called format fields) are replaced with
+the objects passed into the format method. The number in the brackets refers to
+the position of the object passed into the format method.</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">print</span> <span class="s">&#39;{0} and {1}&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="s">&#39;spam&#39;</span><span class="p">,</span> <span class="s">&#39;eggs&#39;</span><span class="p">)</span>
+<span class="go">spam and eggs</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">print</span> <span class="s">&#39;{1} and {0}&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="s">&#39;spam&#39;</span><span class="p">,</span> <span class="s">&#39;eggs&#39;</span><span class="p">)</span>
+<span class="go">eggs and spam</span>
+</pre></div>
+</div>
+<p>If keyword arguments are used in the format method, their values are referred to
+by using the name of the argument.</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">print</span> <span class="s">&#39;This {food} is {adjective}.&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span>
+<span class="gp">... </span> <span class="n">food</span><span class="o">=</span><span class="s">&#39;spam&#39;</span><span class="p">,</span> <span class="n">adjective</span><span class="o">=</span><span class="s">&#39;absolutely horrible&#39;</span><span class="p">)</span>
+<span class="go">This spam is absolutely horrible.</span>
+</pre></div>
+</div>
+<p>Positional and keyword arguments can be arbitrarily combined:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">print</span> <span class="s">&#39;The story of {0}, {1}, and {other}.&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="s">&#39;Bill&#39;</span><span class="p">,</span> <span class="s">&#39;Manfred&#39;</span><span class="p">,</span>
+<span class="gp">... </span> <span class="n">other</span><span class="o">=</span><span class="s">&#39;Georg&#39;</span><span class="p">)</span>
+<span class="go">The story of Bill, Manfred, and Georg.</span>
+</pre></div>
+</div>
+<p>An optional <tt class="docutils literal"><span class="pre">':'</span></tt> and format specifier can follow the field name. This also
+greater control over how the value is formatted. The following example
+truncates the Pi to three places after the decimal.</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">math</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">print</span> <span class="s">&#39;The value of PI is approximately {0:.3f}.&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">math</span><span class="o">.</span><span class="n">pi</span><span class="p">)</span>
+<span class="go">The value of PI is approximately 3.142.</span>
+</pre></div>
+</div>
+<p>Passing an integer after the <tt class="docutils literal"><span class="pre">':'</span></tt> will cause that field to be a minimum
+number of characters wide. This is useful for making tables pretty.:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">table</span> <span class="o">=</span> <span class="p">{</span><span class="s">&#39;Sjoerd&#39;</span><span class="p">:</span> <span class="mf">4127</span><span class="p">,</span> <span class="s">&#39;Jack&#39;</span><span class="p">:</span> <span class="mf">4098</span><span class="p">,</span> <span class="s">&#39;Dcab&#39;</span><span class="p">:</span> <span class="mf">7678</span><span class="p">}</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">for</span> <span class="n">name</span><span class="p">,</span> <span class="n">phone</span> <span class="ow">in</span> <span class="n">table</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
+<span class="gp">... </span> <span class="k">print</span> <span class="s">&#39;{0:10} ==&gt; {1:10d}&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">phone</span><span class="p">)</span>
+<span class="gp">...</span>
+<span class="go">Jack ==&gt; 4098</span>
+<span class="go">Dcab ==&gt; 7678</span>
+<span class="go">Sjoerd ==&gt; 4127</span>
+</pre></div>
+</div>
+<p>If you have a really long format string that you don&#8217;t want to split up, it
+would be nice if you could reference the variables to be formatted by name
+instead of by position. This can be done by simply passing the dict and using
+square brackets <tt class="docutils literal"><span class="pre">'[]'</span></tt> to access the keys</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">table</span> <span class="o">=</span> <span class="p">{</span><span class="s">&#39;Sjoerd&#39;</span><span class="p">:</span> <span class="mf">4127</span><span class="p">,</span> <span class="s">&#39;Jack&#39;</span><span class="p">:</span> <span class="mf">4098</span><span class="p">,</span> <span class="s">&#39;Dcab&#39;</span><span class="p">:</span> <span class="mf">8637678</span><span class="p">}</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">print</span> <span class="p">(</span><span class="s">&#39;Jack: {0[Jack]:d}; Sjoerd: {0[Sjoerd]:d}; &#39;</span>
+<span class="gp">... </span> <span class="s">&#39;Dcab: {0[Dcab]:d}&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">table</span><span class="p">))</span>
+<span class="go">Jack: 4098; Sjoerd: 4127; Dcab: 8637678</span>
+</pre></div>
+</div>
+<p>This could also be done by passing the table as keyword arguments with the &#8216;**&#8217;
+notation.:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">table</span> <span class="o">=</span> <span class="p">{</span><span class="s">&#39;Sjoerd&#39;</span><span class="p">:</span> <span class="mf">4127</span><span class="p">,</span> <span class="s">&#39;Jack&#39;</span><span class="p">:</span> <span class="mf">4098</span><span class="p">,</span> <span class="s">&#39;Dcab&#39;</span><span class="p">:</span> <span class="mf">8637678</span><span class="p">}</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">print</span> <span class="s">&#39;Jack: {Jack:d}; Sjoerd: {Sjoerd:d}; Dcab: {Dcab:d}&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="o">**</span><span class="n">table</span><span class="p">)</span>
+<span class="go">Jack: 4098; Sjoerd: 4127; Dcab: 8637678</span>
+</pre></div>
+</div>
+<p>This is particularly useful in combination with the new built-in <a title="vars" class="reference external" href="../library/functions.html#vars"><tt class="xref docutils literal"><span class="pre">vars()</span></tt></a>
+function, which returns a dictionary containing all local variables.</p>
+<p>For a complete overview of string formatting with <a title="str.format" class="reference external" href="../library/stdtypes.html#str.format"><tt class="xref docutils literal"><span class="pre">str.format()</span></tt></a>, see
+<a class="reference external" href="../library/string.html#formatstrings"><em>Format String Syntax</em></a>.</p>
+<div class="section" id="old-string-formatting">
+<h3>7.1.1. Old string formatting<a class="headerlink" href="#old-string-formatting" title="Permalink to this headline">¶</a></h3>
+<p>The <tt class="docutils literal"><span class="pre">%</span></tt> operator can also be used for string formatting. It interprets the
+left argument much like a <tt class="xref docutils literal"><span class="pre">sprintf()</span></tt>-style format string to be applied
+to the right argument, and returns the string resulting from this formatting
+operation. For example:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">math</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">print</span> <span class="s">&#39;The value of PI is approximately </span><span class="si">%5.3f</span><span class="s">.&#39;</span> <span class="o">%</span> <span class="n">math</span><span class="o">.</span><span class="n">pi</span>
+<span class="go">The value of PI is approximately 3.142.</span>
+</pre></div>
+</div>
+<p>Since <a title="str.format" class="reference external" href="../library/stdtypes.html#str.format"><tt class="xref docutils literal"><span class="pre">str.format()</span></tt></a> is quite new, a lot of Python code still uses the <tt class="docutils literal"><span class="pre">%</span></tt>
+operator. However, because this old style of formatting will eventually removed
+from the language <a title="str.format" class="reference external" href="../library/stdtypes.html#str.format"><tt class="xref docutils literal"><span class="pre">str.format()</span></tt></a> should generally be used.</p>
+<p>More information can be found in the <a class="reference external" href="../library/stdtypes.html#string-formatting"><em>String Formatting Operations</em></a> section.</p>
+</div>
+</div>
+<div class="section" id="reading-and-writing-files">
+<span id="tut-files"></span><h2>7.2. Reading and Writing Files<a class="headerlink" href="#reading-and-writing-files" title="Permalink to this headline">¶</a></h2>
+<p id="index-1066"><a title="open" class="reference external" href="../library/functions.html#open"><tt class="xref docutils literal"><span class="pre">open()</span></tt></a> returns a file object, and is most commonly used with two
+arguments: <tt class="docutils literal"><span class="pre">open(filename,</span> <span class="pre">mode)</span></tt>.</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">f</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="s">&#39;/tmp/workfile&#39;</span><span class="p">,</span> <span class="s">&#39;w&#39;</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">print</span> <span class="n">f</span>
+<span class="go">&lt;open file &#39;/tmp/workfile&#39;, mode &#39;w&#39; at 80a0960&gt;</span>
+</pre></div>
+</div>
+<p>The first argument is a string containing the filename. The second argument is
+another string containing a few characters describing the way in which the file
+will be used. <em>mode</em> can be <tt class="docutils literal"><span class="pre">'r'</span></tt> when the file will only be read, <tt class="docutils literal"><span class="pre">'w'</span></tt>
+for only writing (an existing file with the same name will be erased), and
+<tt class="docutils literal"><span class="pre">'a'</span></tt> opens the file for appending; any data written to the file is
+automatically added to the end. <tt class="docutils literal"><span class="pre">'r+'</span></tt> opens the file for both reading and
+writing. The <em>mode</em> argument is optional; <tt class="docutils literal"><span class="pre">'r'</span></tt> will be assumed if it&#8217;s
+omitted.</p>
+<p>On Windows, <tt class="docutils literal"><span class="pre">'b'</span></tt> appended to the mode opens the file in binary mode, so there
+are also modes like <tt class="docutils literal"><span class="pre">'rb'</span></tt>, <tt class="docutils literal"><span class="pre">'wb'</span></tt>, and <tt class="docutils literal"><span class="pre">'r+b'</span></tt>. Windows makes a
+distinction between text and binary files; the end-of-line characters in text
+files are automatically altered slightly when data is read or written. This
+behind-the-scenes modification to file data is fine for ASCII text files, but
+it&#8217;ll corrupt binary data like that in <tt class="docutils literal"><span class="pre">JPEG</span></tt> or <tt class="docutils literal"><span class="pre">EXE</span></tt> files. Be
+very careful to use binary mode when reading and writing such files. On Unix,
+it doesn&#8217;t hurt to append a <tt class="docutils literal"><span class="pre">'b'</span></tt> to the mode, so you can use it
+platform-independently for all binary files.</p>
+<div class="section" id="methods-of-file-objects">
+<span id="tut-filemethods"></span><h3>7.2.1. Methods of File Objects<a class="headerlink" href="#methods-of-file-objects" title="Permalink to this headline">¶</a></h3>
+<p>The rest of the examples in this section will assume that a file object called
+<tt class="docutils literal"><span class="pre">f</span></tt> has already been created.</p>
+<p>To read a file&#8217;s contents, call <tt class="docutils literal"><span class="pre">f.read(size)</span></tt>, which reads some quantity of
+data and returns it as a string. <em>size</em> is an optional numeric argument. When
+<em>size</em> is omitted or negative, the entire contents of the file will be read and
+returned; it&#8217;s your problem if the file is twice as large as your machine&#8217;s
+memory. Otherwise, at most <em>size</em> bytes are read and returned. If the end of
+the file has been reached, <tt class="docutils literal"><span class="pre">f.read()</span></tt> will return an empty string (<tt class="docutils literal"><span class="pre">&quot;&quot;</span></tt>).</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">f</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
+<span class="go">&#39;This is the entire file.\n&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">f</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
+<span class="go">&#39;&#39;</span>
+</pre></div>
+</div>
+<p><tt class="docutils literal"><span class="pre">f.readline()</span></tt> reads a single line from the file; a newline character (<tt class="docutils literal"><span class="pre">\n</span></tt>)
+is left at the end of the string, and is only omitted on the last line of the
+file if the file doesn&#8217;t end in a newline. This makes the return value
+unambiguous; if <tt class="docutils literal"><span class="pre">f.readline()</span></tt> returns an empty string, the end of the file
+has been reached, while a blank line is represented by <tt class="docutils literal"><span class="pre">'\n'</span></tt>, a string
+containing only a single newline.</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">f</span><span class="o">.</span><span class="n">readline</span><span class="p">()</span>
+<span class="go">&#39;This is the first line of the file.\n&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">f</span><span class="o">.</span><span class="n">readline</span><span class="p">()</span>
+<span class="go">&#39;Second line of the file\n&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">f</span><span class="o">.</span><span class="n">readline</span><span class="p">()</span>
+<span class="go">&#39;&#39;</span>
+</pre></div>
+</div>
+<p><tt class="docutils literal"><span class="pre">f.readlines()</span></tt> returns a list containing all the lines of data in the file.
+If given an optional parameter <em>sizehint</em>, it reads that many bytes from the
+file and enough more to complete a line, and returns the lines from that. This
+is often used to allow efficient reading of a large file by lines, but without
+having to load the entire file in memory. Only complete lines will be returned.</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">f</span><span class="o">.</span><span class="n">readlines</span><span class="p">()</span>
+<span class="go">[&#39;This is the first line of the file.\n&#39;, &#39;Second line of the file\n&#39;]</span>
+</pre></div>
+</div>
+<p>An alternative approach to reading lines is to loop over the file object. This is
+memory efficient, fast, and leads to simpler code:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">f</span><span class="p">:</span>
+<span class="go"> print line,</span>
+
+<span class="go">This is the first line of the file.</span>
+<span class="go">Second line of the file</span>
+</pre></div>
+</div>
+<p>The alternative approach is simpler but does not provide as fine-grained
+control. Since the two approaches manage line buffering differently, they
+should not be mixed.</p>
+<p><tt class="docutils literal"><span class="pre">f.write(string)</span></tt> writes the contents of <em>string</em> to the file, returning
+<tt class="xref docutils literal"><span class="pre">None</span></tt>.</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">f</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s">&#39;This is a test</span><span class="se">\n</span><span class="s">&#39;</span><span class="p">)</span>
+</pre></div>
+</div>
+<p>To write something other than a string, it needs to be converted to a string
+first:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">value</span> <span class="o">=</span> <span class="p">(</span><span class="s">&#39;the answer&#39;</span><span class="p">,</span> <span class="mf">42</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">s</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">f</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">s</span><span class="p">)</span>
+</pre></div>
+</div>
+<p><tt class="docutils literal"><span class="pre">f.tell()</span></tt> returns an integer giving the file object&#8217;s current position in the
+file, measured in bytes from the beginning of the file. To change the file
+object&#8217;s position, use <tt class="docutils literal"><span class="pre">f.seek(offset,</span> <span class="pre">from_what)</span></tt>. The position is computed
+from adding <em>offset</em> to a reference point; the reference point is selected by
+the <em>from_what</em> argument. A <em>from_what</em> value of 0 measures from the beginning
+of the file, 1 uses the current file position, and 2 uses the end of the file as
+the reference point. <em>from_what</em> can be omitted and defaults to 0, using the
+beginning of the file as the reference point.</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">f</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="s">&#39;/tmp/workfile&#39;</span><span class="p">,</span> <span class="s">&#39;r+&#39;</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">f</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s">&#39;0123456789abcdef&#39;</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">f</span><span class="o">.</span><span class="n">seek</span><span class="p">(</span><span class="mf">5</span><span class="p">)</span> <span class="c"># Go to the 6th byte in the file</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">f</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="mf">1</span><span class="p">)</span>
+<span class="go">&#39;5&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">f</span><span class="o">.</span><span class="n">seek</span><span class="p">(</span><span class="o">-</span><span class="mf">3</span><span class="p">,</span> <span class="mf">2</span><span class="p">)</span> <span class="c"># Go to the 3rd byte before the end</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">f</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="mf">1</span><span class="p">)</span>
+<span class="go">&#39;d&#39;</span>
+</pre></div>
+</div>
+<p>When you&#8217;re done with a file, call <tt class="docutils literal"><span class="pre">f.close()</span></tt> to close it and free up any
+system resources taken up by the open file. After calling <tt class="docutils literal"><span class="pre">f.close()</span></tt>,
+attempts to use the file object will automatically fail.</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">f</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">f</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
+<span class="gt">Traceback (most recent call last):</span>
+ File <span class="nb">&quot;&lt;stdin&gt;&quot;</span>, line <span class="m">1</span>, in <span class="n-Identifier">?</span>
+<span class="nc">ValueError</span>: <span class="n-Identifier">I/O operation on closed file</span>
+</pre></div>
+</div>
+<p>It is good practice to use the <a class="reference external" href="../reference/compound_stmts.html#with"><tt class="xref docutils literal"><span class="pre">with</span></tt></a> keyword when dealing with file
+objects. This has the advantage that the file is properly closed after its
+suite finishes, even if an exception is raised on the way. It is also much
+shorter than writing equivalent <a class="reference external" href="../reference/compound_stmts.html#try"><tt class="xref docutils literal"><span class="pre">try</span></tt></a>-<a class="reference external" href="../reference/compound_stmts.html#finally"><tt class="xref docutils literal"><span class="pre">finally</span></tt></a> blocks:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s">&#39;/tmp/workfile&#39;</span><span class="p">,</span> <span class="s">&#39;r&#39;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
+<span class="gp">... </span> <span class="n">read_data</span> <span class="o">=</span> <span class="n">f</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">f</span><span class="o">.</span><span class="n">closed</span>
+<span class="go">True</span>
+</pre></div>
+</div>
+<p>File objects have some additional methods, such as <tt class="xref docutils literal"><span class="pre">isatty()</span></tt> and
+<tt class="xref docutils literal"><span class="pre">truncate()</span></tt> which are less frequently used; consult the Library Reference
+for a complete guide to file objects.</p>
+</div>
+<div class="section" id="the-pickle-module">
+<span id="tut-pickle"></span><h3>7.2.2. The <a title="Convert Python objects to streams of bytes and back." class="reference external" href="../library/pickle.html#module-pickle"><tt class="xref docutils literal"><span class="pre">pickle</span></tt></a> Module<a class="headerlink" href="#the-pickle-module" title="Permalink to this headline">¶</a></h3>
+<p id="index-1067">Strings can easily be written to and read from a file. Numbers take a bit more
+effort, since the <tt class="xref docutils literal"><span class="pre">read()</span></tt> method only returns strings, which will have to
+be passed to a function like <a title="int" class="reference external" href="../library/functions.html#int"><tt class="xref docutils literal"><span class="pre">int()</span></tt></a>, which takes a string like <tt class="docutils literal"><span class="pre">'123'</span></tt>
+and returns its numeric value 123. However, when you want to save more complex
+data types like lists, dictionaries, or class instances, things get a lot more
+complicated.</p>
+<p>Rather than have users be constantly writing and debugging code to save
+complicated data types, Python provides a standard module called <a title="Convert Python objects to streams of bytes and back." class="reference external" href="../library/pickle.html#module-pickle"><tt class="xref docutils literal"><span class="pre">pickle</span></tt></a>.
+This is an amazing module that can take almost any Python object (even some
+forms of Python code!), and convert it to a string representation; this process
+is called <em>pickling</em>. Reconstructing the object from the string
+representation is called <em>unpickling</em>. Between pickling and unpickling,
+the string representing the object may have been stored in a file or data, or
+sent over a network connection to some distant machine.</p>
+<p>If you have an object <tt class="docutils literal"><span class="pre">x</span></tt>, and a file object <tt class="docutils literal"><span class="pre">f</span></tt> that&#8217;s been opened for
+writing, the simplest way to pickle the object takes only one line of code:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="n">pickle</span><span class="o">.</span><span class="n">dump</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">f</span><span class="p">)</span>
+</pre></div>
+</div>
+<p>To unpickle the object again, if <tt class="docutils literal"><span class="pre">f</span></tt> is a file object which has been opened
+for reading:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="n">x</span> <span class="o">=</span> <span class="n">pickle</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
+</pre></div>
+</div>
+<p>(There are other variants of this, used when pickling many objects or when you
+don&#8217;t want to write the pickled data to a file; consult the complete
+documentation for <a title="Convert Python objects to streams of bytes and back." class="reference external" href="../library/pickle.html#module-pickle"><tt class="xref docutils literal"><span class="pre">pickle</span></tt></a> in the Python Library Reference.)</p>
+<p><a title="Convert Python objects to streams of bytes and back." class="reference external" href="../library/pickle.html#module-pickle"><tt class="xref docutils literal"><span class="pre">pickle</span></tt></a> is the standard way to make Python objects which can be stored and
+reused by other programs or by a future invocation of the same program; the
+technical term for this is a <em>persistent</em> object. Because <a title="Convert Python objects to streams of bytes and back." class="reference external" href="../library/pickle.html#module-pickle"><tt class="xref docutils literal"><span class="pre">pickle</span></tt></a> is
+so widely used, many authors who write Python extensions take care to ensure
+that new data types such as matrices can be properly pickled and unpickled.</p>
+</div>
+</div>
+</div>
+
+
+ </div>
+ </div>
+ </div>
+ <div class="sphinxsidebar">
+ <div class="sphinxsidebarwrapper">
+ <h3><a href="../contents.html">Table Of Contents</a></h3>
+ <ul>
+<li><a class="reference external" href="">7. Input and Output</a><ul>
+<li><a class="reference external" href="#fancier-output-formatting">7.1. Fancier Output Formatting</a><ul>
+<li><a class="reference external" href="#old-string-formatting">7.1.1. Old string formatting</a></li>
+</ul>
+</li>
+<li><a class="reference external" href="#reading-and-writing-files">7.2. Reading and Writing Files</a><ul>
+<li><a class="reference external" href="#methods-of-file-objects">7.2.1. Methods of File Objects</a></li>
+<li><a class="reference external" href="#the-pickle-module">7.2.2. The <tt class="docutils literal"><span class="pre">pickle</span></tt> Module</a></li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+
+ <h4>Previous topic</h4>
+ <p class="topless"><a href="modules.html"
+ title="previous chapter">6. Modules</a></p>
+ <h4>Next topic</h4>
+ <p class="topless"><a href="errors.html"
+ title="next chapter">8. Errors and Exceptions</a></p>
+ <h3>This Page</h3>
+ <ul class="this-page-menu">
+ <li><a href="../_sources/tutorial/inputoutput.txt"
+ rel="nofollow">Show Source</a></li>
+ </ul>
+ <div id="searchbox" style="display: none">
+ <h3>Quick search</h3>
+ <form class="search" action="../search.html" method="get">
+ <input type="text" name="q" size="18" />
+ <input type="submit" value="Go" />
+ <input type="hidden" name="check_keywords" value="yes" />
+ <input type="hidden" name="area" value="default" />
+ </form>
+ <p class="searchtip" style="font-size: 90%">
+ Enter search terms or a module, class or function name.
+ </p>
+ </div>
+ <script type="text/javascript">$('#searchbox').show(0);</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../genindex.html" title="General Index"
+ >index</a></li>
+ <li class="right" >
+ <a href="../modindex.html" title="Global Module Index"
+ >modules</a> |</li>
+ <li class="right" >
+ <a href="errors.html" title="8. Errors and Exceptions"
+ >next</a> |</li>
+ <li class="right" >
+ <a href="modules.html" title="6. Modules"
+ >previous</a> |</li>
+ <li><img src="../_static/py.png" alt=""
+ style="vertical-align: middle; margin-top: -1px"/></li>
+ <li><a href="../index.html">Python v2.6.4c2 documentation</a> &raquo;</li>
+
+ <li><a href="index.html" >The Python Tutorial</a> &raquo;</li>
+ </ul>
+ </div>
+ <div class="footer">
+ &copy; <a href="../copyright.html">Copyright</a> 1990-2009, Python Software Foundation.
+ <br />
+ The Python Software Foundation is a non-profit corporation.
+ <a href="http://www.python.org/psf/donations/">Please donate.</a>
+ <br />
+ Last updated on Oct 19, 2009.
+ Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 0.6.2.
+ </div>
+
+ </body>
+</html> \ No newline at end of file
diff --git a/help/PythonTutorial/tutorial/interactive.html b/help/PythonTutorial/tutorial/interactive.html
new file mode 100644
index 0000000..bee44c6
--- /dev/null
+++ b/help/PythonTutorial/tutorial/interactive.html
@@ -0,0 +1,281 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+ <title>13. Interactive Input Editing and History Substitution &mdash; Python v2.6.4c2 documentation</title>
+ <link rel="stylesheet" href="../_static/default.css" type="text/css" />
+ <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
+ <script type="text/javascript">
+ var DOCUMENTATION_OPTIONS = {
+ URL_ROOT: '../',
+ VERSION: '2.6.4c2',
+ COLLAPSE_MODINDEX: false,
+ FILE_SUFFIX: '.html',
+ HAS_SOURCE: true
+ };
+ </script>
+ <script type="text/javascript" src="../_static/jquery.js"></script>
+ <script type="text/javascript" src="../_static/doctools.js"></script>
+ <link rel="search" type="application/opensearchdescription+xml"
+ title="Search within Python v2.6.4c2 documentation"
+ href="../_static/opensearch.xml"/>
+ <link rel="author" title="About these documents" href="../about.html" />
+ <link rel="copyright" title="Copyright" href="../copyright.html" />
+ <link rel="top" title="Python v2.6.4c2 documentation" href="../index.html" />
+ <link rel="up" title="The Python Tutorial" href="index.html" />
+ <link rel="next" title="14. Floating Point Arithmetic: Issues and Limitations" href="floatingpoint.html" />
+ <link rel="prev" title="12. What Now?" href="whatnow.html" />
+ <link rel="shortcut icon" type="image/png" href="../_static/py.png" />
+
+
+ </head>
+ <body>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../modindex.html" title="Global Module Index"
+ accesskey="M">modules</a> |</li>
+ <li class="right" >
+ <a href="floatingpoint.html" title="14. Floating Point Arithmetic: Issues and Limitations"
+ accesskey="N">next</a> |</li>
+ <li class="right" >
+ <a href="whatnow.html" title="12. What Now?"
+ accesskey="P">previous</a> |</li>
+ <li><img src="../_static/py.png" alt=""
+ style="vertical-align: middle; margin-top: -1px"/></li>
+ <li><a href="../index.html">Python v2.6.4c2 documentation</a> &raquo;</li>
+
+ <li><a href="index.html" accesskey="U">The Python Tutorial</a> &raquo;</li>
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body">
+
+ <div class="section" id="interactive-input-editing-and-history-substitution">
+<span id="tut-interacting"></span><h1>13. Interactive Input Editing and History Substitution<a class="headerlink" href="#interactive-input-editing-and-history-substitution" title="Permalink to this headline">¶</a></h1>
+<p>Some versions of the Python interpreter support editing of the current input
+line and history substitution, similar to facilities found in the Korn shell and
+the GNU Bash shell. This is implemented using the <em>GNU Readline</em> library, which
+supports Emacs-style and vi-style editing. This library has its own
+documentation which I won&#8217;t duplicate here; however, the basics are easily
+explained. The interactive editing and history described here are optionally
+available in the Unix and Cygwin versions of the interpreter.</p>
+<p>This chapter does <em>not</em> document the editing facilities of Mark Hammond&#8217;s
+PythonWin package or the Tk-based environment, IDLE, distributed with Python.
+The command line history recall which operates within DOS boxes on NT and some
+other DOS and Windows flavors is yet another beast.</p>
+<div class="section" id="line-editing">
+<span id="tut-lineediting"></span><h2>13.1. Line Editing<a class="headerlink" href="#line-editing" title="Permalink to this headline">¶</a></h2>
+<p>If supported, input line editing is active whenever the interpreter prints a
+primary or secondary prompt. The current line can be edited using the
+conventional Emacs control characters. The most important of these are:
+<tt class="docutils literal"><span class="pre">C-A</span></tt> (Control-A) moves the cursor to the beginning of the line, <tt class="docutils literal"><span class="pre">C-E</span></tt>
+to the end, <tt class="docutils literal"><span class="pre">C-B</span></tt> moves it one position to the left, <tt class="docutils literal"><span class="pre">C-F</span></tt> to the
+right. Backspace erases the character to the left of the cursor, <tt class="docutils literal"><span class="pre">C-D</span></tt> the
+character to its right. <tt class="docutils literal"><span class="pre">C-K</span></tt> kills (erases) the rest of the line to the
+right of the cursor, <tt class="docutils literal"><span class="pre">C-Y</span></tt> yanks back the last killed string.
+<tt class="docutils literal"><span class="pre">C-underscore</span></tt> undoes the last change you made; it can be repeated for
+cumulative effect.</p>
+</div>
+<div class="section" id="history-substitution">
+<span id="tut-history"></span><h2>13.2. History Substitution<a class="headerlink" href="#history-substitution" title="Permalink to this headline">¶</a></h2>
+<p>History substitution works as follows. All non-empty input lines issued are
+saved in a history buffer, and when a new prompt is given you are positioned on
+a new line at the bottom of this buffer. <tt class="docutils literal"><span class="pre">C-P</span></tt> moves one line up (back) in
+the history buffer, <tt class="docutils literal"><span class="pre">C-N</span></tt> moves one down. Any line in the history buffer
+can be edited; an asterisk appears in front of the prompt to mark a line as
+modified. Pressing the <tt class="docutils literal"><span class="pre">Return</span></tt> key passes the current line to the
+interpreter. <tt class="docutils literal"><span class="pre">C-R</span></tt> starts an incremental reverse search; <tt class="docutils literal"><span class="pre">C-S</span></tt> starts
+a forward search.</p>
+</div>
+<div class="section" id="key-bindings">
+<span id="tut-keybindings"></span><h2>13.3. Key Bindings<a class="headerlink" href="#key-bindings" title="Permalink to this headline">¶</a></h2>
+<p>The key bindings and some other parameters of the Readline library can be
+customized by placing commands in an initialization file called
+<tt class="docutils literal"><span class="pre">~/.inputrc</span></tt>. Key bindings have the form</p>
+<div class="highlight-python"><pre>key-name: function-name</pre>
+</div>
+<p>or</p>
+<div class="highlight-python"><pre>"string": function-name</pre>
+</div>
+<p>and options can be set with</p>
+<div class="highlight-python"><pre>set option-name value</pre>
+</div>
+<p>For example:</p>
+<div class="highlight-python"><pre># I prefer vi-style editing:
+set editing-mode vi
+
+# Edit using a single line:
+set horizontal-scroll-mode On
+
+# Rebind some keys:
+Meta-h: backward-kill-word
+"\C-u": universal-argument
+"\C-x\C-r": re-read-init-file</pre>
+</div>
+<p>Note that the default binding for <tt class="docutils literal"><span class="pre">Tab</span></tt> in Python is to insert a <tt class="docutils literal"><span class="pre">Tab</span></tt>
+character instead of Readline&#8217;s default filename completion function. If you
+insist, you can override this by putting</p>
+<div class="highlight-python"><pre>Tab: complete</pre>
+</div>
+<p>in your <tt class="docutils literal"><span class="pre">~/.inputrc</span></tt>. (Of course, this makes it harder to type indented
+continuation lines if you&#8217;re accustomed to using <tt class="docutils literal"><span class="pre">Tab</span></tt> for that purpose.)</p>
+<p id="index-1068">Automatic completion of variable and module names is optionally available. To
+enable it in the interpreter&#8217;s interactive mode, add the following to your
+startup file: <a class="footnote-reference" href="#id2" id="id1">[1]</a></p>
+<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">rlcompleter</span><span class="o">,</span> <span class="nn">readline</span>
+<span class="n">readline</span><span class="o">.</span><span class="n">parse_and_bind</span><span class="p">(</span><span class="s">&#39;tab: complete&#39;</span><span class="p">)</span>
+</pre></div>
+</div>
+<p>This binds the <tt class="docutils literal"><span class="pre">Tab</span></tt> key to the completion function, so hitting the
+<tt class="docutils literal"><span class="pre">Tab</span></tt> key twice suggests completions; it looks at Python statement names,
+the current local variables, and the available module names. For dotted
+expressions such as <tt class="docutils literal"><span class="pre">string.a</span></tt>, it will evaluate the expression up to the
+final <tt class="docutils literal"><span class="pre">'.'</span></tt> and then suggest completions from the attributes of the resulting
+object. Note that this may execute application-defined code if an object with a
+<a title="object.__getattr__" class="reference external" href="../reference/datamodel.html#object.__getattr__"><tt class="xref docutils literal"><span class="pre">__getattr__()</span></tt></a> method is part of the expression.</p>
+<p>A more capable startup file might look like this example. Note that this
+deletes the names it creates once they are no longer needed; this is done since
+the startup file is executed in the same namespace as the interactive commands,
+and removing the names avoids creating side effects in the interactive
+environment. You may find it convenient to keep some of the imported modules,
+such as <a title="Miscellaneous operating system interfaces." class="reference external" href="../library/os.html#module-os"><tt class="xref docutils literal"><span class="pre">os</span></tt></a>, which turn out to be needed in most sessions with the
+interpreter.</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="c"># Add auto-completion and a stored history file of commands to your Python</span>
+<span class="c"># interactive interpreter. Requires Python 2.0+, readline. Autocomplete is</span>
+<span class="c"># bound to the Esc key by default (you can change it - see readline docs).</span>
+<span class="c">#</span>
+<span class="c"># Store the file in ~/.pystartup, and set an environment variable to point</span>
+<span class="c"># to it: &quot;export PYTHONSTARTUP=/home/user/.pystartup&quot; in bash.</span>
+<span class="c">#</span>
+<span class="c"># Note that PYTHONSTARTUP does *not* expand &quot;~&quot;, so you have to put in the</span>
+<span class="c"># full path to your home directory.</span>
+
+<span class="kn">import</span> <span class="nn">atexit</span>
+<span class="kn">import</span> <span class="nn">os</span>
+<span class="kn">import</span> <span class="nn">readline</span>
+<span class="kn">import</span> <span class="nn">rlcompleter</span>
+
+<span class="n">historyPath</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">expanduser</span><span class="p">(</span><span class="s">&quot;~/.pyhistory&quot;</span><span class="p">)</span>
+
+<span class="k">def</span> <span class="nf">save_history</span><span class="p">(</span><span class="n">historyPath</span><span class="o">=</span><span class="n">historyPath</span><span class="p">):</span>
+ <span class="kn">import</span> <span class="nn">readline</span>
+ <span class="n">readline</span><span class="o">.</span><span class="n">write_history_file</span><span class="p">(</span><span class="n">historyPath</span><span class="p">)</span>
+
+<span class="k">if</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">historyPath</span><span class="p">):</span>
+ <span class="n">readline</span><span class="o">.</span><span class="n">read_history_file</span><span class="p">(</span><span class="n">historyPath</span><span class="p">)</span>
+
+<span class="n">atexit</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="n">save_history</span><span class="p">)</span>
+<span class="k">del</span> <span class="n">os</span><span class="p">,</span> <span class="n">atexit</span><span class="p">,</span> <span class="n">readline</span><span class="p">,</span> <span class="n">rlcompleter</span><span class="p">,</span> <span class="n">save_history</span><span class="p">,</span> <span class="n">historyPath</span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="commentary">
+<span id="tut-commentary"></span><h2>13.4. Commentary<a class="headerlink" href="#commentary" title="Permalink to this headline">¶</a></h2>
+<p>This facility is an enormous step forward compared to earlier versions of the
+interpreter; however, some wishes are left: It would be nice if the proper
+indentation were suggested on continuation lines (the parser knows if an indent
+token is required next). The completion mechanism might use the interpreter&#8217;s
+symbol table. A command to check (or even suggest) matching parentheses,
+quotes, etc., would also be useful.</p>
+<p class="rubric">Footnotes</p>
+<table class="docutils footnote" frame="void" id="id2" rules="none">
+<colgroup><col class="label" /><col /></colgroup>
+<tbody valign="top">
+<tr><td class="label"><a class="fn-backref" href="#id1">[1]</a></td><td>Python will execute the contents of a file identified by the
+<span class="target" id="index-1069"></span><a class="reference external" href="../using/cmdline.html#envvar-PYTHONSTARTUP"><strong class="xref">PYTHONSTARTUP</strong></a> environment variable when you start an interactive
+interpreter.</td></tr>
+</tbody>
+</table>
+</div>
+</div>
+
+
+ </div>
+ </div>
+ </div>
+ <div class="sphinxsidebar">
+ <div class="sphinxsidebarwrapper">
+ <h3><a href="../contents.html">Table Of Contents</a></h3>
+ <ul>
+<li><a class="reference external" href="">13. Interactive Input Editing and History Substitution</a><ul>
+<li><a class="reference external" href="#line-editing">13.1. Line Editing</a></li>
+<li><a class="reference external" href="#history-substitution">13.2. History Substitution</a></li>
+<li><a class="reference external" href="#key-bindings">13.3. Key Bindings</a></li>
+<li><a class="reference external" href="#commentary">13.4. Commentary</a></li>
+</ul>
+</li>
+</ul>
+
+ <h4>Previous topic</h4>
+ <p class="topless"><a href="whatnow.html"
+ title="previous chapter">12. What Now?</a></p>
+ <h4>Next topic</h4>
+ <p class="topless"><a href="floatingpoint.html"
+ title="next chapter">14. Floating Point Arithmetic: Issues and Limitations</a></p>
+ <h3>This Page</h3>
+ <ul class="this-page-menu">
+ <li><a href="../_sources/tutorial/interactive.txt"
+ rel="nofollow">Show Source</a></li>
+ </ul>
+ <div id="searchbox" style="display: none">
+ <h3>Quick search</h3>
+ <form class="search" action="../search.html" method="get">
+ <input type="text" name="q" size="18" />
+ <input type="submit" value="Go" />
+ <input type="hidden" name="check_keywords" value="yes" />
+ <input type="hidden" name="area" value="default" />
+ </form>
+ <p class="searchtip" style="font-size: 90%">
+ Enter search terms or a module, class or function name.
+ </p>
+ </div>
+ <script type="text/javascript">$('#searchbox').show(0);</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../genindex.html" title="General Index"
+ >index</a></li>
+ <li class="right" >
+ <a href="../modindex.html" title="Global Module Index"
+ >modules</a> |</li>
+ <li class="right" >
+ <a href="floatingpoint.html" title="14. Floating Point Arithmetic: Issues and Limitations"
+ >next</a> |</li>
+ <li class="right" >
+ <a href="whatnow.html" title="12. What Now?"
+ >previous</a> |</li>
+ <li><img src="../_static/py.png" alt=""
+ style="vertical-align: middle; margin-top: -1px"/></li>
+ <li><a href="../index.html">Python v2.6.4c2 documentation</a> &raquo;</li>
+
+ <li><a href="index.html" >The Python Tutorial</a> &raquo;</li>
+ </ul>
+ </div>
+ <div class="footer">
+ &copy; <a href="../copyright.html">Copyright</a> 1990-2009, Python Software Foundation.
+ <br />
+ The Python Software Foundation is a non-profit corporation.
+ <a href="http://www.python.org/psf/donations/">Please donate.</a>
+ <br />
+ Last updated on Oct 19, 2009.
+ Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 0.6.2.
+ </div>
+
+ </body>
+</html> \ No newline at end of file
diff --git a/help/PythonTutorial/tutorial/interpreter.html b/help/PythonTutorial/tutorial/interpreter.html
new file mode 100644
index 0000000..39d6426
--- /dev/null
+++ b/help/PythonTutorial/tutorial/interpreter.html
@@ -0,0 +1,356 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+ <title>2. Using the Python Interpreter &mdash; Python v2.6.4c2 documentation</title>
+ <link rel="stylesheet" href="../_static/default.css" type="text/css" />
+ <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
+ <script type="text/javascript">
+ var DOCUMENTATION_OPTIONS = {
+ URL_ROOT: '../',
+ VERSION: '2.6.4c2',
+ COLLAPSE_MODINDEX: false,
+ FILE_SUFFIX: '.html',
+ HAS_SOURCE: true
+ };
+ </script>
+ <script type="text/javascript" src="../_static/jquery.js"></script>
+ <script type="text/javascript" src="../_static/doctools.js"></script>
+ <link rel="search" type="application/opensearchdescription+xml"
+ title="Search within Python v2.6.4c2 documentation"
+ href="../_static/opensearch.xml"/>
+ <link rel="author" title="About these documents" href="../about.html" />
+ <link rel="copyright" title="Copyright" href="../copyright.html" />
+ <link rel="top" title="Python v2.6.4c2 documentation" href="../index.html" />
+ <link rel="up" title="The Python Tutorial" href="index.html" />
+ <link rel="next" title="3. An Informal Introduction to Python" href="introduction.html" />
+ <link rel="prev" title="1. Whetting Your Appetite" href="appetite.html" />
+ <link rel="shortcut icon" type="image/png" href="../_static/py.png" />
+
+
+ </head>
+ <body>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../modindex.html" title="Global Module Index"
+ accesskey="M">modules</a> |</li>
+ <li class="right" >
+ <a href="introduction.html" title="3. An Informal Introduction to Python"
+ accesskey="N">next</a> |</li>
+ <li class="right" >
+ <a href="appetite.html" title="1. Whetting Your Appetite"
+ accesskey="P">previous</a> |</li>
+ <li><img src="../_static/py.png" alt=""
+ style="vertical-align: middle; margin-top: -1px"/></li>
+ <li><a href="../index.html">Python v2.6.4c2 documentation</a> &raquo;</li>
+
+ <li><a href="index.html" accesskey="U">The Python Tutorial</a> &raquo;</li>
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body">
+
+ <div class="section" id="using-the-python-interpreter">
+<span id="tut-using"></span><h1>2. Using the Python Interpreter<a class="headerlink" href="#using-the-python-interpreter" title="Permalink to this headline">¶</a></h1>
+<div class="section" id="invoking-the-interpreter">
+<span id="tut-invoking"></span><h2>2.1. Invoking the Interpreter<a class="headerlink" href="#invoking-the-interpreter" title="Permalink to this headline">¶</a></h2>
+<p>The Python interpreter is usually installed as <tt class="docutils literal"><span class="pre">/usr/local/bin/python</span></tt> on
+those machines where it is available; putting <tt class="docutils literal"><span class="pre">/usr/local/bin</span></tt> in your
+Unix shell&#8217;s search path makes it possible to start it by typing the command</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="n">python</span>
+</pre></div>
+</div>
+<p>to the shell. Since the choice of the directory where the interpreter lives is
+an installation option, other places are possible; check with your local Python
+guru or system administrator. (E.g., <tt class="docutils literal"><span class="pre">/usr/local/python</span></tt> is a popular
+alternative location.)</p>
+<p>On Windows machines, the Python installation is usually placed in
+<tt class="docutils literal"><span class="pre">C:\Python26</span></tt>, though you can change this when you&#8217;re running the
+installer. To add this directory to your path, you can type the following
+command into the command prompt in a DOS box:</p>
+<div class="highlight-python"><pre>set path=%path%;C:\python26</pre>
+</div>
+<p>Typing an end-of-file character (<tt class="docutils literal"><span class="pre">Control-D</span></tt> on Unix, <tt class="docutils literal"><span class="pre">Control-Z</span></tt> on
+Windows) at the primary prompt causes the interpreter to exit with a zero exit
+status. If that doesn&#8217;t work, you can exit the interpreter by typing the
+following commands: <tt class="docutils literal"><span class="pre">import</span> <span class="pre">sys;</span> <span class="pre">sys.exit()</span></tt>.</p>
+<p>The interpreter&#8217;s line-editing features usually aren&#8217;t very sophisticated. On
+Unix, whoever installed the interpreter may have enabled support for the GNU
+readline library, which adds more elaborate interactive editing and history
+features. Perhaps the quickest check to see whether command line editing is
+supported is typing Control-P to the first Python prompt you get. If it beeps,
+you have command line editing; see Appendix <a class="reference external" href="interactive.html#tut-interacting"><em>Interactive Input Editing and History Substitution</em></a> for an
+introduction to the keys. If nothing appears to happen, or if <tt class="docutils literal"><span class="pre">^P</span></tt> is echoed,
+command line editing isn&#8217;t available; you&#8217;ll only be able to use backspace to
+remove characters from the current line.</p>
+<p>The interpreter operates somewhat like the Unix shell: when called with standard
+input connected to a tty device, it reads and executes commands interactively;
+when called with a file name argument or with a file as standard input, it reads
+and executes a <em>script</em> from that file.</p>
+<p>A second way of starting the interpreter is <tt class="docutils literal"><span class="pre">python</span> <span class="pre">-c</span> <span class="pre">command</span> <span class="pre">[arg]</span> <span class="pre">...</span></tt>,
+which executes the statement(s) in <em>command</em>, analogous to the shell&#8217;s
+<a class="reference external" href="../using/cmdline.html#cmdoption-c"><em class="xref">-c</em></a> option. Since Python statements often contain spaces or other
+characters that are special to the shell, it is usually advised to quote
+<em>command</em> in its entirety with single quotes.</p>
+<p>Some Python modules are also useful as scripts. These can be invoked using
+<tt class="docutils literal"><span class="pre">python</span> <span class="pre">-m</span> <span class="pre">module</span> <span class="pre">[arg]</span> <span class="pre">...</span></tt>, which executes the source file for <em>module</em> as
+if you had spelled out its full name on the command line.</p>
+<p>Note that there is a difference between <tt class="docutils literal"><span class="pre">python</span> <span class="pre">file</span></tt> and <tt class="docutils literal"><span class="pre">python</span> <span class="pre">&lt;file</span></tt>.
+In the latter case, input requests from the program, such as calls to
+<a title="input" class="reference external" href="../library/functions.html#input"><tt class="xref docutils literal"><span class="pre">input()</span></tt></a> and <a title="raw_input" class="reference external" href="../library/functions.html#raw_input"><tt class="xref docutils literal"><span class="pre">raw_input()</span></tt></a>, are satisfied from <em>file</em>. Since this file
+has already been read until the end by the parser before the program starts
+executing, the program will encounter end-of-file immediately. In the former
+case (which is usually what you want) they are satisfied from whatever file or
+device is connected to standard input of the Python interpreter.</p>
+<p>When a script file is used, it is sometimes useful to be able to run the script
+and enter interactive mode afterwards. This can be done by passing <a class="reference external" href="../using/cmdline.html#cmdoption-i"><em class="xref">-i</em></a>
+before the script. (This does not work if the script is read from standard
+input, for the same reason as explained in the previous paragraph.)</p>
+<div class="section" id="argument-passing">
+<span id="tut-argpassing"></span><h3>2.1.1. Argument Passing<a class="headerlink" href="#argument-passing" title="Permalink to this headline">¶</a></h3>
+<p>When known to the interpreter, the script name and additional arguments
+thereafter are passed to the script in the variable <tt class="docutils literal"><span class="pre">sys.argv</span></tt>, which is a
+list of strings. Its length is at least one; when no script and no arguments
+are given, <tt class="docutils literal"><span class="pre">sys.argv[0]</span></tt> is an empty string. When the script name is given as
+<tt class="docutils literal"><span class="pre">'-'</span></tt> (meaning standard input), <tt class="docutils literal"><span class="pre">sys.argv[0]</span></tt> is set to <tt class="docutils literal"><span class="pre">'-'</span></tt>. When
+<a class="reference external" href="../using/cmdline.html#cmdoption-c"><em class="xref">-c</em></a> <em>command</em> is used, <tt class="docutils literal"><span class="pre">sys.argv[0]</span></tt> is set to <tt class="docutils literal"><span class="pre">'-c'</span></tt>. When
+<a class="reference external" href="../using/cmdline.html#cmdoption-m"><em class="xref">-m</em></a> <em>module</em> is used, <tt class="docutils literal"><span class="pre">sys.argv[0]</span></tt> is set to the full name of the
+located module. Options found after <a class="reference external" href="../using/cmdline.html#cmdoption-c"><em class="xref">-c</em></a> <em>command</em> or <a class="reference external" href="../using/cmdline.html#cmdoption-m"><em class="xref">-m</em></a>
+<em>module</em> are not consumed by the Python interpreter&#8217;s option processing but
+left in <tt class="docutils literal"><span class="pre">sys.argv</span></tt> for the command or module to handle.</p>
+</div>
+<div class="section" id="interactive-mode">
+<span id="tut-interactive"></span><h3>2.1.2. Interactive Mode<a class="headerlink" href="#interactive-mode" title="Permalink to this headline">¶</a></h3>
+<p>When commands are read from a tty, the interpreter is said to be in <em>interactive
+mode</em>. In this mode it prompts for the next command with the <em>primary prompt</em>,
+usually three greater-than signs (<tt class="docutils literal"><span class="pre">&gt;&gt;&gt;</span></tt>); for continuation lines it prompts
+with the <em>secondary prompt</em>, by default three dots (<tt class="docutils literal"><span class="pre">...</span></tt>). The interpreter
+prints a welcome message stating its version number and a copyright notice
+before printing the first prompt:</p>
+<div class="highlight-python"><pre>python
+Python 2.6 (#1, Feb 28 2007, 00:02:06)
+Type "help", "copyright", "credits" or "license" for more information.
+&gt;&gt;&gt;</pre>
+</div>
+<p>Continuation lines are needed when entering a multi-line construct. As an
+example, take a look at this <a class="reference external" href="../reference/compound_stmts.html#if"><tt class="xref docutils literal"><span class="pre">if</span></tt></a> statement:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">the_world_is_flat</span> <span class="o">=</span> <span class="mf">1</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">if</span> <span class="n">the_world_is_flat</span><span class="p">:</span>
+<span class="gp">... </span> <span class="k">print</span> <span class="s">&quot;Be careful not to fall off!&quot;</span>
+<span class="gp">...</span>
+<span class="go">Be careful not to fall off!</span>
+</pre></div>
+</div>
+</div>
+</div>
+<div class="section" id="the-interpreter-and-its-environment">
+<span id="tut-interp"></span><h2>2.2. The Interpreter and Its Environment<a class="headerlink" href="#the-interpreter-and-its-environment" title="Permalink to this headline">¶</a></h2>
+<div class="section" id="error-handling">
+<span id="tut-error"></span><h3>2.2.1. Error Handling<a class="headerlink" href="#error-handling" title="Permalink to this headline">¶</a></h3>
+<p>When an error occurs, the interpreter prints an error message and a stack trace.
+In interactive mode, it then returns to the primary prompt; when input came from
+a file, it exits with a nonzero exit status after printing the stack trace.
+(Exceptions handled by an <a class="reference external" href="../reference/compound_stmts.html#except"><tt class="xref docutils literal"><span class="pre">except</span></tt></a> clause in a <a class="reference external" href="../reference/compound_stmts.html#try"><tt class="xref docutils literal"><span class="pre">try</span></tt></a> statement
+are not errors in this context.) Some errors are unconditionally fatal and
+cause an exit with a nonzero exit; this applies to internal inconsistencies and
+some cases of running out of memory. All error messages are written to the
+standard error stream; normal output from executed commands is written to
+standard output.</p>
+<p>Typing the interrupt character (usually Control-C or DEL) to the primary or
+secondary prompt cancels the input and returns to the primary prompt. <a class="footnote-reference" href="#id2" id="id1">[1]</a>
+Typing an interrupt while a command is executing raises the
+<a title="exceptions.KeyboardInterrupt" class="reference external" href="../library/exceptions.html#exceptions.KeyboardInterrupt"><tt class="xref docutils literal"><span class="pre">KeyboardInterrupt</span></tt></a> exception, which may be handled by a <a class="reference external" href="../reference/compound_stmts.html#try"><tt class="xref docutils literal"><span class="pre">try</span></tt></a>
+statement.</p>
+</div>
+<div class="section" id="executable-python-scripts">
+<span id="tut-scripts"></span><h3>2.2.2. Executable Python Scripts<a class="headerlink" href="#executable-python-scripts" title="Permalink to this headline">¶</a></h3>
+<p>On BSD&#8217;ish Unix systems, Python scripts can be made directly executable, like
+shell scripts, by putting the line</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="c">#! /usr/bin/env python</span>
+</pre></div>
+</div>
+<p>(assuming that the interpreter is on the user&#8217;s <span class="target" id="index-1070"></span><strong class="xref">PATH</strong>) at the beginning
+of the script and giving the file an executable mode. The <tt class="docutils literal"><span class="pre">#!</span></tt> must be the
+first two characters of the file. On some platforms, this first line must end
+with a Unix-style line ending (<tt class="docutils literal"><span class="pre">'\n'</span></tt>), not a Windows (<tt class="docutils literal"><span class="pre">'\r\n'</span></tt>) line
+ending. Note that the hash, or pound, character, <tt class="docutils literal"><span class="pre">'#'</span></tt>, is used to start a
+comment in Python.</p>
+<p>The script can be given an executable mode, or permission, using the
+<strong>chmod</strong> command:</p>
+<div class="highlight-python"><pre>$ chmod +x myscript.py</pre>
+</div>
+<p>On Windows systems, there is no notion of an &#8220;executable mode&#8221;. The Python
+installer automatically associates <tt class="docutils literal"><span class="pre">.py</span></tt> files with <tt class="docutils literal"><span class="pre">python.exe</span></tt> so that
+a double-click on a Python file will run it as a script. The extension can
+also be <tt class="docutils literal"><span class="pre">.pyw</span></tt>, in that case, the console window that normally appears is
+suppressed.</p>
+</div>
+<div class="section" id="source-code-encoding">
+<h3>2.2.3. Source Code Encoding<a class="headerlink" href="#source-code-encoding" title="Permalink to this headline">¶</a></h3>
+<p>It is possible to use encodings different than ASCII in Python source files. The
+best way to do it is to put one more special comment line right after the <tt class="docutils literal"><span class="pre">#!</span></tt>
+line to define the source file encoding:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="c"># -*- coding: encoding -*-</span>
+</pre></div>
+</div>
+<p>With that declaration, all characters in the source file will be treated as
+having the encoding <em>encoding</em>, and it will be possible to directly write
+Unicode string literals in the selected encoding. The list of possible
+encodings can be found in the Python Library Reference, in the section on
+<a title="Encode and decode data and streams." class="reference external" href="../library/codecs.html#module-codecs"><tt class="xref docutils literal"><span class="pre">codecs</span></tt></a>.</p>
+<p>For example, to write Unicode literals including the Euro currency symbol, the
+ISO-8859-15 encoding can be used, with the Euro symbol having the ordinal value
+164. This script will print the value 8364 (the Unicode codepoint corresponding
+to the Euro symbol) and then exit:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="c"># -*- coding: iso-8859-15 -*-</span>
+
+<span class="n">currency</span> <span class="o">=</span> <span class="s">u&quot;€&quot;</span>
+<span class="k">print</span> <span class="nb">ord</span><span class="p">(</span><span class="n">currency</span><span class="p">)</span>
+</pre></div>
+</div>
+<p>If your editor supports saving files as <tt class="docutils literal"><span class="pre">UTF-8</span></tt> with a UTF-8 <em>byte order mark</em>
+(aka BOM), you can use that instead of an encoding declaration. IDLE supports
+this capability if <tt class="docutils literal"><span class="pre">Options/General/Default</span> <span class="pre">Source</span> <span class="pre">Encoding/UTF-8</span></tt> is set.
+Notice that this signature is not understood in older Python releases (2.2 and
+earlier), and also not understood by the operating system for script files with
+<tt class="docutils literal"><span class="pre">#!</span></tt> lines (only used on Unix systems).</p>
+<p>By using UTF-8 (either through the signature or an encoding declaration),
+characters of most languages in the world can be used simultaneously in string
+literals and comments. Using non-ASCII characters in identifiers is not
+supported. To display all these characters properly, your editor must recognize
+that the file is UTF-8, and it must use a font that supports all the characters
+in the file.</p>
+</div>
+<div class="section" id="the-interactive-startup-file">
+<span id="tut-startup"></span><h3>2.2.4. The Interactive Startup File<a class="headerlink" href="#the-interactive-startup-file" title="Permalink to this headline">¶</a></h3>
+<p>When you use Python interactively, it is frequently handy to have some standard
+commands executed every time the interpreter is started. You can do this by
+setting an environment variable named <span class="target" id="index-1071"></span><a class="reference external" href="../using/cmdline.html#envvar-PYTHONSTARTUP"><strong class="xref">PYTHONSTARTUP</strong></a> to the name of a
+file containing your start-up commands. This is similar to the <tt class="docutils literal"><span class="pre">.profile</span></tt>
+feature of the Unix shells.</p>
+<p>This file is only read in interactive sessions, not when Python reads commands
+from a script, and not when <tt class="docutils literal"><span class="pre">/dev/tty</span></tt> is given as the explicit source of
+commands (which otherwise behaves like an interactive session). It is executed
+in the same namespace where interactive commands are executed, so that objects
+that it defines or imports can be used without qualification in the interactive
+session. You can also change the prompts <tt class="docutils literal"><span class="pre">sys.ps1</span></tt> and <tt class="docutils literal"><span class="pre">sys.ps2</span></tt> in this
+file.</p>
+<p>If you want to read an additional start-up file from the current directory, you
+can program this in the global start-up file using code like <tt class="docutils literal"><span class="pre">if</span>
+<span class="pre">os.path.isfile('.pythonrc.py'):</span> <span class="pre">execfile('.pythonrc.py')</span></tt>. If you want to use
+the startup file in a script, you must do this explicitly in the script:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">os</span>
+<span class="n">filename</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">&#39;PYTHONSTARTUP&#39;</span><span class="p">)</span>
+<span class="k">if</span> <span class="n">filename</span> <span class="ow">and</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">isfile</span><span class="p">(</span><span class="n">filename</span><span class="p">):</span>
+ <span class="nb">execfile</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>
+</pre></div>
+</div>
+<p class="rubric">Footnotes</p>
+<table class="docutils footnote" frame="void" id="id2" rules="none">
+<colgroup><col class="label" /><col /></colgroup>
+<tbody valign="top">
+<tr><td class="label"><a class="fn-backref" href="#id1">[1]</a></td><td>A problem with the GNU Readline package may prevent this.</td></tr>
+</tbody>
+</table>
+</div>
+</div>
+</div>
+
+
+ </div>
+ </div>
+ </div>
+ <div class="sphinxsidebar">
+ <div class="sphinxsidebarwrapper">
+ <h3><a href="../contents.html">Table Of Contents</a></h3>
+ <ul>
+<li><a class="reference external" href="">2. Using the Python Interpreter</a><ul>
+<li><a class="reference external" href="#invoking-the-interpreter">2.1. Invoking the Interpreter</a><ul>
+<li><a class="reference external" href="#argument-passing">2.1.1. Argument Passing</a></li>
+<li><a class="reference external" href="#interactive-mode">2.1.2. Interactive Mode</a></li>
+</ul>
+</li>
+<li><a class="reference external" href="#the-interpreter-and-its-environment">2.2. The Interpreter and Its Environment</a><ul>
+<li><a class="reference external" href="#error-handling">2.2.1. Error Handling</a></li>
+<li><a class="reference external" href="#executable-python-scripts">2.2.2. Executable Python Scripts</a></li>
+<li><a class="reference external" href="#source-code-encoding">2.2.3. Source Code Encoding</a></li>
+<li><a class="reference external" href="#the-interactive-startup-file">2.2.4. The Interactive Startup File</a></li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+
+ <h4>Previous topic</h4>
+ <p class="topless"><a href="appetite.html"
+ title="previous chapter">1. Whetting Your Appetite</a></p>
+ <h4>Next topic</h4>
+ <p class="topless"><a href="introduction.html"
+ title="next chapter">3. An Informal Introduction to Python</a></p>
+ <h3>This Page</h3>
+ <ul class="this-page-menu">
+ <li><a href="../_sources/tutorial/interpreter.txt"
+ rel="nofollow">Show Source</a></li>
+ </ul>
+ <div id="searchbox" style="display: none">
+ <h3>Quick search</h3>
+ <form class="search" action="../search.html" method="get">
+ <input type="text" name="q" size="18" />
+ <input type="submit" value="Go" />
+ <input type="hidden" name="check_keywords" value="yes" />
+ <input type="hidden" name="area" value="default" />
+ </form>
+ <p class="searchtip" style="font-size: 90%">
+ Enter search terms or a module, class or function name.
+ </p>
+ </div>
+ <script type="text/javascript">$('#searchbox').show(0);</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../genindex.html" title="General Index"
+ >index</a></li>
+ <li class="right" >
+ <a href="../modindex.html" title="Global Module Index"
+ >modules</a> |</li>
+ <li class="right" >
+ <a href="introduction.html" title="3. An Informal Introduction to Python"
+ >next</a> |</li>
+ <li class="right" >
+ <a href="appetite.html" title="1. Whetting Your Appetite"
+ >previous</a> |</li>
+ <li><img src="../_static/py.png" alt=""
+ style="vertical-align: middle; margin-top: -1px"/></li>
+ <li><a href="../index.html">Python v2.6.4c2 documentation</a> &raquo;</li>
+
+ <li><a href="index.html" >The Python Tutorial</a> &raquo;</li>
+ </ul>
+ </div>
+ <div class="footer">
+ &copy; <a href="../copyright.html">Copyright</a> 1990-2009, Python Software Foundation.
+ <br />
+ The Python Software Foundation is a non-profit corporation.
+ <a href="http://www.python.org/psf/donations/">Please donate.</a>
+ <br />
+ Last updated on Oct 19, 2009.
+ Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 0.6.2.
+ </div>
+
+ </body>
+</html> \ No newline at end of file
diff --git a/help/PythonTutorial/tutorial/introduction.html b/help/PythonTutorial/tutorial/introduction.html
new file mode 100644
index 0000000..9a35514
--- /dev/null
+++ b/help/PythonTutorial/tutorial/introduction.html
@@ -0,0 +1,751 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+ <title>3. An Informal Introduction to Python &mdash; Python v2.6.4c2 documentation</title>
+ <link rel="stylesheet" href="../_static/default.css" type="text/css" />
+ <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
+ <script type="text/javascript">
+ var DOCUMENTATION_OPTIONS = {
+ URL_ROOT: '../',
+ VERSION: '2.6.4c2',
+ COLLAPSE_MODINDEX: false,
+ FILE_SUFFIX: '.html',
+ HAS_SOURCE: true
+ };
+ </script>
+ <script type="text/javascript" src="../_static/jquery.js"></script>
+ <script type="text/javascript" src="../_static/doctools.js"></script>
+ <link rel="search" type="application/opensearchdescription+xml"
+ title="Search within Python v2.6.4c2 documentation"
+ href="../_static/opensearch.xml"/>
+ <link rel="author" title="About these documents" href="../about.html" />
+ <link rel="copyright" title="Copyright" href="../copyright.html" />
+ <link rel="top" title="Python v2.6.4c2 documentation" href="../index.html" />
+ <link rel="up" title="The Python Tutorial" href="index.html" />
+ <link rel="next" title="4. More Control Flow Tools" href="controlflow.html" />
+ <link rel="prev" title="2. Using the Python Interpreter" href="interpreter.html" />
+ <link rel="shortcut icon" type="image/png" href="../_static/py.png" />
+
+
+ </head>
+ <body>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../modindex.html" title="Global Module Index"
+ accesskey="M">modules</a> |</li>
+ <li class="right" >
+ <a href="controlflow.html" title="4. More Control Flow Tools"
+ accesskey="N">next</a> |</li>
+ <li class="right" >
+ <a href="interpreter.html" title="2. Using the Python Interpreter"
+ accesskey="P">previous</a> |</li>
+ <li><img src="../_static/py.png" alt=""
+ style="vertical-align: middle; margin-top: -1px"/></li>
+ <li><a href="../index.html">Python v2.6.4c2 documentation</a> &raquo;</li>
+
+ <li><a href="index.html" accesskey="U">The Python Tutorial</a> &raquo;</li>
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body">
+
+ <div class="section" id="an-informal-introduction-to-python">
+<span id="tut-informal"></span><h1>3. An Informal Introduction to Python<a class="headerlink" href="#an-informal-introduction-to-python" title="Permalink to this headline">¶</a></h1>
+<p>In the following examples, input and output are distinguished by the presence or
+absence of prompts (<tt class="docutils literal"><span class="pre">&gt;&gt;&gt;</span></tt> and <tt class="docutils literal"><span class="pre">...</span></tt>): to repeat the example, you must type
+everything after the prompt, when the prompt appears; lines that do not begin
+with a prompt are output from the interpreter. Note that a secondary prompt on a
+line by itself in an example means you must type a blank line; this is used to
+end a multi-line command.</p>
+<p>Many of the examples in this manual, even those entered at the interactive
+prompt, include comments. Comments in Python start with the hash character,
+<tt class="docutils literal"><span class="pre">#</span></tt>, and extend to the end of the physical line. A comment may appear at the
+start of a line or following whitespace or code, but not within a string
+literal. A hash character within a string literal is just a hash character.
+Since comments are to clarify code and are not interpreted by Python, they may
+be omitted when typing in examples.</p>
+<p>Some examples:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="c"># this is the first comment</span>
+<span class="n">SPAM</span> <span class="o">=</span> <span class="mf">1</span> <span class="c"># and this is the second comment</span>
+ <span class="c"># ... and now a third!</span>
+<span class="n">STRING</span> <span class="o">=</span> <span class="s">&quot;# This is not a comment.&quot;</span>
+</pre></div>
+</div>
+<div class="section" id="using-python-as-a-calculator">
+<span id="tut-calculator"></span><h2>3.1. Using Python as a Calculator<a class="headerlink" href="#using-python-as-a-calculator" title="Permalink to this headline">¶</a></h2>
+<p>Let&#8217;s try some simple Python commands. Start the interpreter and wait for the
+primary prompt, <tt class="docutils literal"><span class="pre">&gt;&gt;&gt;</span></tt>. (It shouldn&#8217;t take long.)</p>
+<div class="section" id="numbers">
+<span id="tut-numbers"></span><h3>3.1.1. Numbers<a class="headerlink" href="#numbers" title="Permalink to this headline">¶</a></h3>
+<p>The interpreter acts as a simple calculator: you can type an expression at it
+and it will write the value. Expression syntax is straightforward: the
+operators <tt class="docutils literal"><span class="pre">+</span></tt>, <tt class="docutils literal"><span class="pre">-</span></tt>, <tt class="docutils literal"><span class="pre">*</span></tt> and <tt class="docutils literal"><span class="pre">/</span></tt> work just like in most other languages
+(for example, Pascal or C); parentheses can be used for grouping. For example:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="mf">2</span><span class="o">+</span><span class="mf">2</span>
+<span class="go">4</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="c"># This is a comment</span>
+<span class="gp">... </span><span class="mf">2</span><span class="o">+</span><span class="mf">2</span>
+<span class="go">4</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="mf">2</span><span class="o">+</span><span class="mf">2</span> <span class="c"># and a comment on the same line as code</span>
+<span class="go">4</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="p">(</span><span class="mf">50</span><span class="o">-</span><span class="mf">5</span><span class="o">*</span><span class="mf">6</span><span class="p">)</span><span class="o">/</span><span class="mf">4</span>
+<span class="go">5</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="c"># Integer division returns the floor:</span>
+<span class="gp">... </span><span class="mf">7</span><span class="o">/</span><span class="mf">3</span>
+<span class="go">2</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="mf">7</span><span class="o">/-</span><span class="mf">3</span>
+<span class="go">-3</span>
+</pre></div>
+</div>
+<p>The equal sign (<tt class="docutils literal"><span class="pre">'='</span></tt>) is used to assign a value to a variable. Afterwards, no
+result is displayed before the next interactive prompt:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">width</span> <span class="o">=</span> <span class="mf">20</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">height</span> <span class="o">=</span> <span class="mf">5</span><span class="o">*</span><span class="mf">9</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">width</span> <span class="o">*</span> <span class="n">height</span>
+<span class="go">900</span>
+</pre></div>
+</div>
+<p>A value can be assigned to several variables simultaneously:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">x</span> <span class="o">=</span> <span class="n">y</span> <span class="o">=</span> <span class="n">z</span> <span class="o">=</span> <span class="mf">0</span> <span class="c"># Zero x, y and z</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">x</span>
+<span class="go">0</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">y</span>
+<span class="go">0</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">z</span>
+<span class="go">0</span>
+</pre></div>
+</div>
+<p>Variables must be &#8220;defined&#8221; (assigned a value) before they can be used, or an
+error will occur:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="c"># try to access an undefined variable</span>
+<span class="gp">... </span><span class="n">n</span>
+<span class="gt">Traceback (most recent call last):</span>
+ File <span class="nb">&quot;&lt;stdin&gt;&quot;</span>, line <span class="m">1</span>, in <span class="n-Identifier">&lt;module&gt;</span>
+<span class="nc">NameError</span>: <span class="n-Identifier">name &#39;n&#39; is not defined</span>
+</pre></div>
+</div>
+<p>There is full support for floating point; operators with mixed type operands
+convert the integer operand to floating point:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="mf">3</span> <span class="o">*</span> <span class="mf">3.75</span> <span class="o">/</span> <span class="mf">1.5</span>
+<span class="go">7.5</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="mf">7.0</span> <span class="o">/</span> <span class="mf">2</span>
+<span class="go">3.5</span>
+</pre></div>
+</div>
+<p>Complex numbers are also supported; imaginary numbers are written with a suffix
+of <tt class="docutils literal"><span class="pre">j</span></tt> or <tt class="docutils literal"><span class="pre">J</span></tt>. Complex numbers with a nonzero real component are written as
+<tt class="docutils literal"><span class="pre">(real+imagj)</span></tt>, or can be created with the <tt class="docutils literal"><span class="pre">complex(real,</span> <span class="pre">imag)</span></tt> function.</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="mf">1</span><span class="n">j</span> <span class="o">*</span> <span class="mf">1</span><span class="n">J</span>
+<span class="go">(-1+0j)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="mf">1</span><span class="n">j</span> <span class="o">*</span> <span class="nb">complex</span><span class="p">(</span><span class="mf">0</span><span class="p">,</span><span class="mf">1</span><span class="p">)</span>
+<span class="go">(-1+0j)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="mf">3</span><span class="o">+</span><span class="mf">1</span><span class="n">j</span><span class="o">*</span><span class="mf">3</span>
+<span class="go">(3+3j)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="p">(</span><span class="mf">3</span><span class="o">+</span><span class="mf">1</span><span class="n">j</span><span class="p">)</span><span class="o">*</span><span class="mf">3</span>
+<span class="go">(9+3j)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="p">(</span><span class="mf">1</span><span class="o">+</span><span class="mf">2</span><span class="n">j</span><span class="p">)</span><span class="o">/</span><span class="p">(</span><span class="mf">1</span><span class="o">+</span><span class="mf">1</span><span class="n">j</span><span class="p">)</span>
+<span class="go">(1.5+0.5j)</span>
+</pre></div>
+</div>
+<p>Complex numbers are always represented as two floating point numbers, the real
+and imaginary part. To extract these parts from a complex number <em>z</em>, use
+<tt class="docutils literal"><span class="pre">z.real</span></tt> and <tt class="docutils literal"><span class="pre">z.imag</span></tt>.</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">a</span><span class="o">=</span><span class="mf">1.5</span><span class="o">+</span><span class="mf">0.5</span><span class="n">j</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">a</span><span class="o">.</span><span class="n">real</span>
+<span class="go">1.5</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">a</span><span class="o">.</span><span class="n">imag</span>
+<span class="go">0.5</span>
+</pre></div>
+</div>
+<p>The conversion functions to floating point and integer (<a title="float" class="reference external" href="../library/functions.html#float"><tt class="xref docutils literal"><span class="pre">float()</span></tt></a>,
+<a title="int" class="reference external" href="../library/functions.html#int"><tt class="xref docutils literal"><span class="pre">int()</span></tt></a> and <a title="long" class="reference external" href="../library/functions.html#long"><tt class="xref docutils literal"><span class="pre">long()</span></tt></a>) don&#8217;t work for complex numbers &#8212; there is no one
+correct way to convert a complex number to a real number. Use <tt class="docutils literal"><span class="pre">abs(z)</span></tt> to get
+its magnitude (as a float) or <tt class="docutils literal"><span class="pre">z.real</span></tt> to get its real part.</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">a</span><span class="o">=</span><span class="mf">3.0</span><span class="o">+</span><span class="mf">4.0</span><span class="n">j</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">float</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
+<span class="gt">Traceback (most recent call last):</span>
+ File <span class="nb">&quot;&lt;stdin&gt;&quot;</span>, line <span class="m">1</span>, in <span class="n-Identifier">?</span>
+<span class="nc">TypeError</span>: <span class="n-Identifier">can&#39;t convert complex to float; use abs(z)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">a</span><span class="o">.</span><span class="n">real</span>
+<span class="go">3.0</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">a</span><span class="o">.</span><span class="n">imag</span>
+<span class="go">4.0</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">abs</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> <span class="c"># sqrt(a.real**2 + a.imag**2)</span>
+<span class="go">5.0</span>
+<span class="go">&gt;&gt;&gt;</span>
+</pre></div>
+</div>
+<p>In interactive mode, the last printed expression is assigned to the variable
+<tt class="docutils literal"><span class="pre">_</span></tt>. This means that when you are using Python as a desk calculator, it is
+somewhat easier to continue calculations, for example:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">tax</span> <span class="o">=</span> <span class="mf">12.5</span> <span class="o">/</span> <span class="mf">100</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">price</span> <span class="o">=</span> <span class="mf">100.50</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">price</span> <span class="o">*</span> <span class="n">tax</span>
+<span class="go">12.5625</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">price</span> <span class="o">+</span> <span class="n">_</span>
+<span class="go">113.0625</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">round</span><span class="p">(</span><span class="n">_</span><span class="p">,</span> <span class="mf">2</span><span class="p">)</span>
+<span class="go">113.06</span>
+<span class="go">&gt;&gt;&gt;</span>
+</pre></div>
+</div>
+<p>This variable should be treated as read-only by the user. Don&#8217;t explicitly
+assign a value to it &#8212; you would create an independent local variable with the
+same name masking the built-in variable with its magic behavior.</p>
+</div>
+<div class="section" id="strings">
+<span id="tut-strings"></span><h3>3.1.2. Strings<a class="headerlink" href="#strings" title="Permalink to this headline">¶</a></h3>
+<p>Besides numbers, Python can also manipulate strings, which can be expressed in
+several ways. They can be enclosed in single quotes or double quotes:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="s">&#39;spam eggs&#39;</span>
+<span class="go">&#39;spam eggs&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="s">&#39;doesn</span><span class="se">\&#39;</span><span class="s">t&#39;</span>
+<span class="go">&quot;doesn&#39;t&quot;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="s">&quot;doesn&#39;t&quot;</span>
+<span class="go">&quot;doesn&#39;t&quot;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="s">&#39;&quot;Yes,&quot; he said.&#39;</span>
+<span class="go">&#39;&quot;Yes,&quot; he said.&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="s">&quot;</span><span class="se">\&quot;</span><span class="s">Yes,</span><span class="se">\&quot;</span><span class="s"> he said.&quot;</span>
+<span class="go">&#39;&quot;Yes,&quot; he said.&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="s">&#39;&quot;Isn</span><span class="se">\&#39;</span><span class="s">t,&quot; she said.&#39;</span>
+<span class="go">&#39;&quot;Isn\&#39;t,&quot; she said.&#39;</span>
+</pre></div>
+</div>
+<p>String literals can span multiple lines in several ways. Continuation lines can
+be used, with a backslash as the last character on the line indicating that the
+next line is a logical continuation of the line:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="n">hello</span> <span class="o">=</span> <span class="s">&quot;This is a rather long string containing</span><span class="se">\n\</span>
+<span class="s">several lines of text just as you would do in C.</span><span class="se">\n\</span>
+<span class="s"> Note that whitespace at the beginning of the line is</span><span class="se">\</span>
+<span class="s"> significant.&quot;</span>
+
+<span class="k">print</span> <span class="n">hello</span>
+</pre></div>
+</div>
+<p>Note that newlines still need to be embedded in the string using <tt class="docutils literal"><span class="pre">\n</span></tt>; the
+newline following the trailing backslash is discarded. This example would print
+the following:</p>
+<div class="highlight-python"><pre>This is a rather long string containing
+several lines of text just as you would do in C.
+ Note that whitespace at the beginning of the line is significant.</pre>
+</div>
+<p>Or, strings can be surrounded in a pair of matching triple-quotes: <tt class="docutils literal"><span class="pre">&quot;&quot;&quot;</span></tt> or
+<tt class="docutils literal"><span class="pre">'''</span></tt>. End of lines do not need to be escaped when using triple-quotes, but
+they will be included in the string.</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="k">print</span> <span class="s">&quot;&quot;&quot;</span>
+<span class="s">Usage: thingy [OPTIONS]</span>
+<span class="s"> -h Display this usage message</span>
+<span class="s"> -H hostname Hostname to connect to</span>
+<span class="s">&quot;&quot;&quot;</span>
+</pre></div>
+</div>
+<p>produces the following output:</p>
+<div class="highlight-python"><pre>Usage: thingy [OPTIONS]
+ -h Display this usage message
+ -H hostname Hostname to connect to</pre>
+</div>
+<p>If we make the string literal a &#8220;raw&#8221; string, <tt class="docutils literal"><span class="pre">\n</span></tt> sequences are not converted
+to newlines, but the backslash at the end of the line, and the newline character
+in the source, are both included in the string as data. Thus, the example:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="n">hello</span> <span class="o">=</span> <span class="s">r&quot;This is a rather long string containing\n</span><span class="se">\</span>
+<span class="s">several lines of text much as you would do in C.&quot;</span>
+
+<span class="k">print</span> <span class="n">hello</span>
+</pre></div>
+</div>
+<p>would print:</p>
+<div class="highlight-python"><pre>This is a rather long string containing\n\
+several lines of text much as you would do in C.</pre>
+</div>
+<p>The interpreter prints the result of string operations in the same way as they
+are typed for input: inside quotes, and with quotes and other funny characters
+escaped by backslashes, to show the precise value. The string is enclosed in
+double quotes if the string contains a single quote and no double quotes, else
+it&#8217;s enclosed in single quotes. (The <a class="reference external" href="../reference/simple_stmts.html#print"><tt class="xref docutils literal"><span class="pre">print</span></tt></a> statement, described
+later, can be used to write strings without quotes or escapes.)</p>
+<p>Strings can be concatenated (glued together) with the <tt class="docutils literal"><span class="pre">+</span></tt> operator, and
+repeated with <tt class="docutils literal"><span class="pre">*</span></tt>:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">word</span> <span class="o">=</span> <span class="s">&#39;Help&#39;</span> <span class="o">+</span> <span class="s">&#39;A&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">word</span>
+<span class="go">&#39;HelpA&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="s">&#39;&lt;&#39;</span> <span class="o">+</span> <span class="n">word</span><span class="o">*</span><span class="mf">5</span> <span class="o">+</span> <span class="s">&#39;&gt;&#39;</span>
+<span class="go">&#39;&lt;HelpAHelpAHelpAHelpAHelpA&gt;&#39;</span>
+</pre></div>
+</div>
+<p>Two string literals next to each other are automatically concatenated; the first
+line above could also have been written <tt class="docutils literal"><span class="pre">word</span> <span class="pre">=</span> <span class="pre">'Help'</span> <span class="pre">'A'</span></tt>; this only works
+with two literals, not with arbitrary string expressions:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="s">&#39;str&#39;</span> <span class="s">&#39;ing&#39;</span> <span class="c"># &lt;- This is ok</span>
+<span class="go">&#39;string&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="s">&#39;str&#39;</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span> <span class="o">+</span> <span class="s">&#39;ing&#39;</span> <span class="c"># &lt;- This is ok</span>
+<span class="go">&#39;string&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="s">&#39;str&#39;</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span> <span class="s">&#39;ing&#39;</span> <span class="c"># &lt;- This is invalid</span>
+<span class="go"> File &quot;&lt;stdin&gt;&quot;, line 1, in ?</span>
+<span class="go"> &#39;str&#39;.strip() &#39;ing&#39;</span>
+<span class="go"> ^</span>
+<span class="go">SyntaxError: invalid syntax</span>
+</pre></div>
+</div>
+<p>Strings can be subscripted (indexed); like in C, the first character of a string
+has subscript (index) 0. There is no separate character type; a character is
+simply a string of size one. Like in Icon, substrings can be specified with the
+<em>slice notation</em>: two indices separated by a colon.</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">word</span><span class="p">[</span><span class="mf">4</span><span class="p">]</span>
+<span class="go">&#39;A&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">word</span><span class="p">[</span><span class="mf">0</span><span class="p">:</span><span class="mf">2</span><span class="p">]</span>
+<span class="go">&#39;He&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">word</span><span class="p">[</span><span class="mf">2</span><span class="p">:</span><span class="mf">4</span><span class="p">]</span>
+<span class="go">&#39;lp&#39;</span>
+</pre></div>
+</div>
+<p>Slice indices have useful defaults; an omitted first index defaults to zero, an
+omitted second index defaults to the size of the string being sliced.</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">word</span><span class="p">[:</span><span class="mf">2</span><span class="p">]</span> <span class="c"># The first two characters</span>
+<span class="go">&#39;He&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">word</span><span class="p">[</span><span class="mf">2</span><span class="p">:]</span> <span class="c"># Everything except the first two characters</span>
+<span class="go">&#39;lpA&#39;</span>
+</pre></div>
+</div>
+<p>Unlike a C string, Python strings cannot be changed. Assigning to an indexed
+position in the string results in an error:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">word</span><span class="p">[</span><span class="mf">0</span><span class="p">]</span> <span class="o">=</span> <span class="s">&#39;x&#39;</span>
+<span class="gt">Traceback (most recent call last):</span>
+ File <span class="nb">&quot;&lt;stdin&gt;&quot;</span>, line <span class="m">1</span>, in <span class="n-Identifier">?</span>
+<span class="nc">TypeError</span>: <span class="n-Identifier">object does not support item assignment</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">word</span><span class="p">[:</span><span class="mf">1</span><span class="p">]</span> <span class="o">=</span> <span class="s">&#39;Splat&#39;</span>
+<span class="gt">Traceback (most recent call last):</span>
+ File <span class="nb">&quot;&lt;stdin&gt;&quot;</span>, line <span class="m">1</span>, in <span class="n-Identifier">?</span>
+<span class="nc">TypeError</span>: <span class="n-Identifier">object does not support slice assignment</span>
+</pre></div>
+</div>
+<p>However, creating a new string with the combined content is easy and efficient:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="s">&#39;x&#39;</span> <span class="o">+</span> <span class="n">word</span><span class="p">[</span><span class="mf">1</span><span class="p">:]</span>
+<span class="go">&#39;xelpA&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="s">&#39;Splat&#39;</span> <span class="o">+</span> <span class="n">word</span><span class="p">[</span><span class="mf">4</span><span class="p">]</span>
+<span class="go">&#39;SplatA&#39;</span>
+</pre></div>
+</div>
+<p>Here&#8217;s a useful invariant of slice operations: <tt class="docutils literal"><span class="pre">s[:i]</span> <span class="pre">+</span> <span class="pre">s[i:]</span></tt> equals <tt class="docutils literal"><span class="pre">s</span></tt>.</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">word</span><span class="p">[:</span><span class="mf">2</span><span class="p">]</span> <span class="o">+</span> <span class="n">word</span><span class="p">[</span><span class="mf">2</span><span class="p">:]</span>
+<span class="go">&#39;HelpA&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">word</span><span class="p">[:</span><span class="mf">3</span><span class="p">]</span> <span class="o">+</span> <span class="n">word</span><span class="p">[</span><span class="mf">3</span><span class="p">:]</span>
+<span class="go">&#39;HelpA&#39;</span>
+</pre></div>
+</div>
+<p>Degenerate slice indices are handled gracefully: an index that is too large is
+replaced by the string size, an upper bound smaller than the lower bound returns
+an empty string.</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">word</span><span class="p">[</span><span class="mf">1</span><span class="p">:</span><span class="mf">100</span><span class="p">]</span>
+<span class="go">&#39;elpA&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">word</span><span class="p">[</span><span class="mf">10</span><span class="p">:]</span>
+<span class="go">&#39;&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">word</span><span class="p">[</span><span class="mf">2</span><span class="p">:</span><span class="mf">1</span><span class="p">]</span>
+<span class="go">&#39;&#39;</span>
+</pre></div>
+</div>
+<p>Indices may be negative numbers, to start counting from the right. For example:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">word</span><span class="p">[</span><span class="o">-</span><span class="mf">1</span><span class="p">]</span> <span class="c"># The last character</span>
+<span class="go">&#39;A&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">word</span><span class="p">[</span><span class="o">-</span><span class="mf">2</span><span class="p">]</span> <span class="c"># The last-but-one character</span>
+<span class="go">&#39;p&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">word</span><span class="p">[</span><span class="o">-</span><span class="mf">2</span><span class="p">:]</span> <span class="c"># The last two characters</span>
+<span class="go">&#39;pA&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">word</span><span class="p">[:</span><span class="o">-</span><span class="mf">2</span><span class="p">]</span> <span class="c"># Everything except the last two characters</span>
+<span class="go">&#39;Hel&#39;</span>
+</pre></div>
+</div>
+<p>But note that -0 is really the same as 0, so it does not count from the right!</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">word</span><span class="p">[</span><span class="o">-</span><span class="mf">0</span><span class="p">]</span> <span class="c"># (since -0 equals 0)</span>
+<span class="go">&#39;H&#39;</span>
+</pre></div>
+</div>
+<p>Out-of-range negative slice indices are truncated, but don&#8217;t try this for
+single-element (non-slice) indices:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">word</span><span class="p">[</span><span class="o">-</span><span class="mf">100</span><span class="p">:]</span>
+<span class="go">&#39;HelpA&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">word</span><span class="p">[</span><span class="o">-</span><span class="mf">10</span><span class="p">]</span> <span class="c"># error</span>
+<span class="gt">Traceback (most recent call last):</span>
+ File <span class="nb">&quot;&lt;stdin&gt;&quot;</span>, line <span class="m">1</span>, in <span class="n-Identifier">?</span>
+<span class="nc">IndexError</span>: <span class="n-Identifier">string index out of range</span>
+</pre></div>
+</div>
+<p>One way to remember how slices work is to think of the indices as pointing
+<em>between</em> characters, with the left edge of the first character numbered 0.
+Then the right edge of the last character of a string of <em>n</em> characters has
+index <em>n</em>, for example:</p>
+<div class="highlight-python"><pre> +---+---+---+---+---+
+ | H | e | l | p | A |
+ +---+---+---+---+---+
+ 0 1 2 3 4 5
+-5 -4 -3 -2 -1</pre>
+</div>
+<p>The first row of numbers gives the position of the indices 0...5 in the string;
+the second row gives the corresponding negative indices. The slice from <em>i</em> to
+<em>j</em> consists of all characters between the edges labeled <em>i</em> and <em>j</em>,
+respectively.</p>
+<p>For non-negative indices, the length of a slice is the difference of the
+indices, if both are within bounds. For example, the length of <tt class="docutils literal"><span class="pre">word[1:3]</span></tt> is
+2.</p>
+<p>The built-in function <a title="len" class="reference external" href="../library/functions.html#len"><tt class="xref docutils literal"><span class="pre">len()</span></tt></a> returns the length of a string:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">s</span> <span class="o">=</span> <span class="s">&#39;supercalifragilisticexpialidocious&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">len</span><span class="p">(</span><span class="n">s</span><span class="p">)</span>
+<span class="go">34</span>
+</pre></div>
+</div>
+<div class="admonition-see-also admonition seealso">
+<p class="first admonition-title">See also</p>
+<dl class="last docutils">
+<dt><a class="reference external" href="../library/stdtypes.html#typesseq"><em>Sequence Types &#8212; str, unicode, list, tuple, buffer, xrange</em></a></dt>
+<dd>Strings, and the Unicode strings described in the next section, are
+examples of <em>sequence types</em>, and support the common operations supported
+by such types.</dd>
+<dt><a class="reference external" href="../library/stdtypes.html#string-methods"><em>String Methods</em></a></dt>
+<dd>Both strings and Unicode strings support a large number of methods for
+basic transformations and searching.</dd>
+<dt><a class="reference external" href="../library/string.html#new-string-formatting"><em>String Formatting</em></a></dt>
+<dd>Information about string formatting with <a title="str.format" class="reference external" href="../library/stdtypes.html#str.format"><tt class="xref docutils literal"><span class="pre">str.format()</span></tt></a> is described
+here.</dd>
+<dt><a class="reference external" href="../library/stdtypes.html#string-formatting"><em>String Formatting Operations</em></a></dt>
+<dd>The old formatting operations invoked when strings and Unicode strings are
+the left operand of the <tt class="docutils literal"><span class="pre">%</span></tt> operator are described in more detail here.</dd>
+</dl>
+</div>
+</div>
+<div class="section" id="unicode-strings">
+<span id="tut-unicodestrings"></span><h3>3.1.3. Unicode Strings<a class="headerlink" href="#unicode-strings" title="Permalink to this headline">¶</a></h3>
+<p>Starting with Python 2.0 a new data type for storing text data is available to
+the programmer: the Unicode object. It can be used to store and manipulate
+Unicode data (see <a class="reference external" href="http://www.unicode.org/">http://www.unicode.org/</a>) and integrates well with the existing
+string objects, providing auto-conversions where necessary.</p>
+<p>Unicode has the advantage of providing one ordinal for every character in every
+script used in modern and ancient texts. Previously, there were only 256
+possible ordinals for script characters. Texts were typically bound to a code
+page which mapped the ordinals to script characters. This lead to very much
+confusion especially with respect to internationalization (usually written as
+<tt class="docutils literal"><span class="pre">i18n</span></tt> &#8212; <tt class="docutils literal"><span class="pre">'i'</span></tt> + 18 characters + <tt class="docutils literal"><span class="pre">'n'</span></tt>) of software. Unicode solves
+these problems by defining one code page for all scripts.</p>
+<p>Creating Unicode strings in Python is just as simple as creating normal
+strings:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="s">u&#39;Hello World !&#39;</span>
+<span class="go">u&#39;Hello World !&#39;</span>
+</pre></div>
+</div>
+<p>The small <tt class="docutils literal"><span class="pre">'u'</span></tt> in front of the quote indicates that a Unicode string is
+supposed to be created. If you want to include special characters in the string,
+you can do so by using the Python <em>Unicode-Escape</em> encoding. The following
+example shows how:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="s">u&#39;Hello</span><span class="se">\u0020</span><span class="s">World !&#39;</span>
+<span class="go">u&#39;Hello World !&#39;</span>
+</pre></div>
+</div>
+<p>The escape sequence <tt class="docutils literal"><span class="pre">\u0020</span></tt> indicates to insert the Unicode character with
+the ordinal value 0x0020 (the space character) at the given position.</p>
+<p>Other characters are interpreted by using their respective ordinal values
+directly as Unicode ordinals. If you have literal strings in the standard
+Latin-1 encoding that is used in many Western countries, you will find it
+convenient that the lower 256 characters of Unicode are the same as the 256
+characters of Latin-1.</p>
+<p>For experts, there is also a raw mode just like the one for normal strings. You
+have to prefix the opening quote with &#8216;ur&#8217; to have Python use the
+<em>Raw-Unicode-Escape</em> encoding. It will only apply the above <tt class="docutils literal"><span class="pre">\uXXXX</span></tt>
+conversion if there is an uneven number of backslashes in front of the small
+&#8216;u&#8217;.</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="s">ur&#39;Hello\u0020World !&#39;</span>
+<span class="go">u&#39;Hello World !&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="s">ur&#39;Hello</span><span class="se">\\</span><span class="s">u0020World !&#39;</span>
+<span class="go">u&#39;Hello\\\\u0020World !&#39;</span>
+</pre></div>
+</div>
+<p>The raw mode is most useful when you have to enter lots of backslashes, as can
+be necessary in regular expressions.</p>
+<p>Apart from these standard encodings, Python provides a whole set of other ways
+of creating Unicode strings on the basis of a known encoding.</p>
+<p id="index-1072">The built-in function <a title="unicode" class="reference external" href="../library/functions.html#unicode"><tt class="xref docutils literal"><span class="pre">unicode()</span></tt></a> provides access to all registered Unicode
+codecs (COders and DECoders). Some of the more well known encodings which these
+codecs can convert are <em>Latin-1</em>, <em>ASCII</em>, <em>UTF-8</em>, and <em>UTF-16</em>. The latter two
+are variable-length encodings that store each Unicode character in one or more
+bytes. The default encoding is normally set to ASCII, which passes through
+characters in the range 0 to 127 and rejects any other characters with an error.
+When a Unicode string is printed, written to a file, or converted with
+<a title="str" class="reference external" href="../library/functions.html#str"><tt class="xref docutils literal"><span class="pre">str()</span></tt></a>, conversion takes place using this default encoding.</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="s">u&quot;abc&quot;</span>
+<span class="go">u&#39;abc&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">str</span><span class="p">(</span><span class="s">u&quot;abc&quot;</span><span class="p">)</span>
+<span class="go">&#39;abc&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="s">u&quot;äöü&quot;</span>
+<span class="go">u&#39;\xe4\xf6\xfc&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">str</span><span class="p">(</span><span class="s">u&quot;äöü&quot;</span><span class="p">)</span>
+<span class="gt">Traceback (most recent call last):</span>
+ File <span class="nb">&quot;&lt;stdin&gt;&quot;</span>, line <span class="m">1</span>, in <span class="n-Identifier">?</span>
+<span class="nc">UnicodeEncodeError: &#39;ascii&#39; codec can&#39;t encode characters in position 0-2</span>: <span class="n-Identifier">ordinal not in range(128)</span>
+</pre></div>
+</div>
+<p>To convert a Unicode string into an 8-bit string using a specific encoding,
+Unicode objects provide an <tt class="xref docutils literal"><span class="pre">encode()</span></tt> method that takes one argument, the
+name of the encoding. Lowercase names for encodings are preferred.</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="s">u&quot;äöü&quot;</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s">&#39;utf-8&#39;</span><span class="p">)</span>
+<span class="go">&#39;\xc3\xa4\xc3\xb6\xc3\xbc&#39;</span>
+</pre></div>
+</div>
+<p>If you have data in a specific encoding and want to produce a corresponding
+Unicode string from it, you can use the <a title="unicode" class="reference external" href="../library/functions.html#unicode"><tt class="xref docutils literal"><span class="pre">unicode()</span></tt></a> function with the
+encoding name as the second argument.</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="nb">unicode</span><span class="p">(</span><span class="s">&#39;</span><span class="se">\xc3\xa4\xc3\xb6\xc3\xbc</span><span class="s">&#39;</span><span class="p">,</span> <span class="s">&#39;utf-8&#39;</span><span class="p">)</span>
+<span class="go">u&#39;\xe4\xf6\xfc&#39;</span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="lists">
+<span id="tut-lists"></span><h3>3.1.4. Lists<a class="headerlink" href="#lists" title="Permalink to this headline">¶</a></h3>
+<p>Python knows a number of <em>compound</em> data types, used to group together other
+values. The most versatile is the <em>list</em>, which can be written as a list of
+comma-separated values (items) between square brackets. List items need not all
+have the same type.</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">a</span> <span class="o">=</span> <span class="p">[</span><span class="s">&#39;spam&#39;</span><span class="p">,</span> <span class="s">&#39;eggs&#39;</span><span class="p">,</span> <span class="mf">100</span><span class="p">,</span> <span class="mf">1234</span><span class="p">]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">a</span>
+<span class="go">[&#39;spam&#39;, &#39;eggs&#39;, 100, 1234]</span>
+</pre></div>
+</div>
+<p>Like string indices, list indices start at 0, and lists can be sliced,
+concatenated and so on:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">a</span><span class="p">[</span><span class="mf">0</span><span class="p">]</span>
+<span class="go">&#39;spam&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">a</span><span class="p">[</span><span class="mf">3</span><span class="p">]</span>
+<span class="go">1234</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">a</span><span class="p">[</span><span class="o">-</span><span class="mf">2</span><span class="p">]</span>
+<span class="go">100</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">a</span><span class="p">[</span><span class="mf">1</span><span class="p">:</span><span class="o">-</span><span class="mf">1</span><span class="p">]</span>
+<span class="go">[&#39;eggs&#39;, 100]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">a</span><span class="p">[:</span><span class="mf">2</span><span class="p">]</span> <span class="o">+</span> <span class="p">[</span><span class="s">&#39;bacon&#39;</span><span class="p">,</span> <span class="mf">2</span><span class="o">*</span><span class="mf">2</span><span class="p">]</span>
+<span class="go">[&#39;spam&#39;, &#39;eggs&#39;, &#39;bacon&#39;, 4]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="mf">3</span><span class="o">*</span><span class="n">a</span><span class="p">[:</span><span class="mf">3</span><span class="p">]</span> <span class="o">+</span> <span class="p">[</span><span class="s">&#39;Boo!&#39;</span><span class="p">]</span>
+<span class="go">[&#39;spam&#39;, &#39;eggs&#39;, 100, &#39;spam&#39;, &#39;eggs&#39;, 100, &#39;spam&#39;, &#39;eggs&#39;, 100, &#39;Boo!&#39;]</span>
+</pre></div>
+</div>
+<p>Unlike strings, which are <em>immutable</em>, it is possible to change individual
+elements of a list:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">a</span>
+<span class="go">[&#39;spam&#39;, &#39;eggs&#39;, 100, 1234]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">a</span><span class="p">[</span><span class="mf">2</span><span class="p">]</span> <span class="o">=</span> <span class="n">a</span><span class="p">[</span><span class="mf">2</span><span class="p">]</span> <span class="o">+</span> <span class="mf">23</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">a</span>
+<span class="go">[&#39;spam&#39;, &#39;eggs&#39;, 123, 1234]</span>
+</pre></div>
+</div>
+<p>Assignment to slices is also possible, and this can even change the size of the
+list or clear it entirely:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="c"># Replace some items:</span>
+<span class="gp">... </span><span class="n">a</span><span class="p">[</span><span class="mf">0</span><span class="p">:</span><span class="mf">2</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="mf">1</span><span class="p">,</span> <span class="mf">12</span><span class="p">]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">a</span>
+<span class="go">[1, 12, 123, 1234]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="c"># Remove some:</span>
+<span class="gp">... </span><span class="n">a</span><span class="p">[</span><span class="mf">0</span><span class="p">:</span><span class="mf">2</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">a</span>
+<span class="go">[123, 1234]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="c"># Insert some:</span>
+<span class="gp">... </span><span class="n">a</span><span class="p">[</span><span class="mf">1</span><span class="p">:</span><span class="mf">1</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="s">&#39;bletch&#39;</span><span class="p">,</span> <span class="s">&#39;xyzzy&#39;</span><span class="p">]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">a</span>
+<span class="go">[123, &#39;bletch&#39;, &#39;xyzzy&#39;, 1234]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="c"># Insert (a copy of) itself at the beginning</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">a</span><span class="p">[:</span><span class="mf">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">a</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">a</span>
+<span class="go">[123, &#39;bletch&#39;, &#39;xyzzy&#39;, 1234, 123, &#39;bletch&#39;, &#39;xyzzy&#39;, 1234]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="c"># Clear the list: replace all items with an empty list</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">a</span><span class="p">[:]</span> <span class="o">=</span> <span class="p">[]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">a</span>
+<span class="go">[]</span>
+</pre></div>
+</div>
+<p>The built-in function <a title="len" class="reference external" href="../library/functions.html#len"><tt class="xref docutils literal"><span class="pre">len()</span></tt></a> also applies to lists:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">a</span> <span class="o">=</span> <span class="p">[</span><span class="s">&#39;a&#39;</span><span class="p">,</span> <span class="s">&#39;b&#39;</span><span class="p">,</span> <span class="s">&#39;c&#39;</span><span class="p">,</span> <span class="s">&#39;d&#39;</span><span class="p">]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">len</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
+<span class="go">4</span>
+</pre></div>
+</div>
+<p>It is possible to nest lists (create lists containing other lists), for
+example:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">q</span> <span class="o">=</span> <span class="p">[</span><span class="mf">2</span><span class="p">,</span> <span class="mf">3</span><span class="p">]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">p</span> <span class="o">=</span> <span class="p">[</span><span class="mf">1</span><span class="p">,</span> <span class="n">q</span><span class="p">,</span> <span class="mf">4</span><span class="p">]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">len</span><span class="p">(</span><span class="n">p</span><span class="p">)</span>
+<span class="go">3</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">p</span><span class="p">[</span><span class="mf">1</span><span class="p">]</span>
+<span class="go">[2, 3]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">p</span><span class="p">[</span><span class="mf">1</span><span class="p">][</span><span class="mf">0</span><span class="p">]</span>
+<span class="go">2</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">p</span><span class="p">[</span><span class="mf">1</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s">&#39;xtra&#39;</span><span class="p">)</span> <span class="c"># See section 5.1</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">p</span>
+<span class="go">[1, [2, 3, &#39;xtra&#39;], 4]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">q</span>
+<span class="go">[2, 3, &#39;xtra&#39;]</span>
+</pre></div>
+</div>
+<p>Note that in the last example, <tt class="docutils literal"><span class="pre">p[1]</span></tt> and <tt class="docutils literal"><span class="pre">q</span></tt> really refer to the same
+object! We&#8217;ll come back to <em>object semantics</em> later.</p>
+</div>
+</div>
+<div class="section" id="first-steps-towards-programming">
+<span id="tut-firststeps"></span><h2>3.2. First Steps Towards Programming<a class="headerlink" href="#first-steps-towards-programming" title="Permalink to this headline">¶</a></h2>
+<p>Of course, we can use Python for more complicated tasks than adding two and two
+together. For instance, we can write an initial sub-sequence of the <em>Fibonacci</em>
+series as follows:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="c"># Fibonacci series:</span>
+<span class="gp">... </span><span class="c"># the sum of two elements defines the next</span>
+<span class="gp">... </span><span class="n">a</span><span class="p">,</span> <span class="n">b</span> <span class="o">=</span> <span class="mf">0</span><span class="p">,</span> <span class="mf">1</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">while</span> <span class="n">b</span> <span class="o">&lt;</span> <span class="mf">10</span><span class="p">:</span>
+<span class="gp">... </span> <span class="k">print</span> <span class="n">b</span>
+<span class="gp">... </span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span> <span class="o">=</span> <span class="n">b</span><span class="p">,</span> <span class="n">a</span><span class="o">+</span><span class="n">b</span>
+<span class="gp">...</span>
+<span class="go">1</span>
+<span class="go">1</span>
+<span class="go">2</span>
+<span class="go">3</span>
+<span class="go">5</span>
+<span class="go">8</span>
+</pre></div>
+</div>
+<p>This example introduces several new features.</p>
+<ul>
+<li><p class="first">The first line contains a <em>multiple assignment</em>: the variables <tt class="docutils literal"><span class="pre">a</span></tt> and <tt class="docutils literal"><span class="pre">b</span></tt>
+simultaneously get the new values 0 and 1. On the last line this is used again,
+demonstrating that the expressions on the right-hand side are all evaluated
+first before any of the assignments take place. The right-hand side expressions
+are evaluated from the left to the right.</p>
+</li>
+<li><p class="first">The <a class="reference external" href="../reference/compound_stmts.html#while"><tt class="xref docutils literal"><span class="pre">while</span></tt></a> loop executes as long as the condition (here: <tt class="docutils literal"><span class="pre">b</span> <span class="pre">&lt;</span> <span class="pre">10</span></tt>)
+remains true. In Python, like in C, any non-zero integer value is true; zero is
+false. The condition may also be a string or list value, in fact any sequence;
+anything with a non-zero length is true, empty sequences are false. The test
+used in the example is a simple comparison. The standard comparison operators
+are written the same as in C: <tt class="docutils literal"><span class="pre">&lt;</span></tt> (less than), <tt class="docutils literal"><span class="pre">&gt;</span></tt> (greater than), <tt class="docutils literal"><span class="pre">==</span></tt>
+(equal to), <tt class="docutils literal"><span class="pre">&lt;=</span></tt> (less than or equal to), <tt class="docutils literal"><span class="pre">&gt;=</span></tt> (greater than or equal to)
+and <tt class="docutils literal"><span class="pre">!=</span></tt> (not equal to).</p>
+</li>
+<li><p class="first">The <em>body</em> of the loop is <em>indented</em>: indentation is Python&#8217;s way of grouping
+statements. Python does not (yet!) provide an intelligent input line editing
+facility, so you have to type a tab or space(s) for each indented line. In
+practice you will prepare more complicated input for Python with a text editor;
+most text editors have an auto-indent facility. When a compound statement is
+entered interactively, it must be followed by a blank line to indicate
+completion (since the parser cannot guess when you have typed the last line).
+Note that each line within a basic block must be indented by the same amount.</p>
+</li>
+<li><p class="first">The <a class="reference external" href="../reference/simple_stmts.html#print"><tt class="xref docutils literal"><span class="pre">print</span></tt></a> statement writes the value of the expression(s) it is
+given. It differs from just writing the expression you want to write (as we did
+earlier in the calculator examples) in the way it handles multiple expressions
+and strings. Strings are printed without quotes, and a space is inserted
+between items, so you can format things nicely, like this:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">i</span> <span class="o">=</span> <span class="mf">256</span><span class="o">*</span><span class="mf">256</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">print</span> <span class="s">&#39;The value of i is&#39;</span><span class="p">,</span> <span class="n">i</span>
+<span class="go">The value of i is 65536</span>
+</pre></div>
+</div>
+<p>A trailing comma avoids the newline after the output:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">a</span><span class="p">,</span> <span class="n">b</span> <span class="o">=</span> <span class="mf">0</span><span class="p">,</span> <span class="mf">1</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">while</span> <span class="n">b</span> <span class="o">&lt;</span> <span class="mf">1000</span><span class="p">:</span>
+<span class="gp">... </span> <span class="k">print</span> <span class="n">b</span><span class="p">,</span>
+<span class="gp">... </span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span> <span class="o">=</span> <span class="n">b</span><span class="p">,</span> <span class="n">a</span><span class="o">+</span><span class="n">b</span>
+<span class="gp">...</span>
+<span class="go">1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987</span>
+</pre></div>
+</div>
+<p>Note that the interpreter inserts a newline before it prints the next prompt if
+the last line was not completed.</p>
+</li>
+</ul>
+</div>
+</div>
+
+
+ </div>
+ </div>
+ </div>
+ <div class="sphinxsidebar">
+ <div class="sphinxsidebarwrapper">
+ <h3><a href="../contents.html">Table Of Contents</a></h3>
+ <ul>
+<li><a class="reference external" href="">3. An Informal Introduction to Python</a><ul>
+<li><a class="reference external" href="#using-python-as-a-calculator">3.1. Using Python as a Calculator</a><ul>
+<li><a class="reference external" href="#numbers">3.1.1. Numbers</a></li>
+<li><a class="reference external" href="#strings">3.1.2. Strings</a></li>
+<li><a class="reference external" href="#unicode-strings">3.1.3. Unicode Strings</a></li>
+<li><a class="reference external" href="#lists">3.1.4. Lists</a></li>
+</ul>
+</li>
+<li><a class="reference external" href="#first-steps-towards-programming">3.2. First Steps Towards Programming</a></li>
+</ul>
+</li>
+</ul>
+
+ <h4>Previous topic</h4>
+ <p class="topless"><a href="interpreter.html"
+ title="previous chapter">2. Using the Python Interpreter</a></p>
+ <h4>Next topic</h4>
+ <p class="topless"><a href="controlflow.html"
+ title="next chapter">4. More Control Flow Tools</a></p>
+ <h3>This Page</h3>
+ <ul class="this-page-menu">
+ <li><a href="../_sources/tutorial/introduction.txt"
+ rel="nofollow">Show Source</a></li>
+ </ul>
+ <div id="searchbox" style="display: none">
+ <h3>Quick search</h3>
+ <form class="search" action="../search.html" method="get">
+ <input type="text" name="q" size="18" />
+ <input type="submit" value="Go" />
+ <input type="hidden" name="check_keywords" value="yes" />
+ <input type="hidden" name="area" value="default" />
+ </form>
+ <p class="searchtip" style="font-size: 90%">
+ Enter search terms or a module, class or function name.
+ </p>
+ </div>
+ <script type="text/javascript">$('#searchbox').show(0);</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../genindex.html" title="General Index"
+ >index</a></li>
+ <li class="right" >
+ <a href="../modindex.html" title="Global Module Index"
+ >modules</a> |</li>
+ <li class="right" >
+ <a href="controlflow.html" title="4. More Control Flow Tools"
+ >next</a> |</li>
+ <li class="right" >
+ <a href="interpreter.html" title="2. Using the Python Interpreter"
+ >previous</a> |</li>
+ <li><img src="../_static/py.png" alt=""
+ style="vertical-align: middle; margin-top: -1px"/></li>
+ <li><a href="../index.html">Python v2.6.4c2 documentation</a> &raquo;</li>
+
+ <li><a href="index.html" >The Python Tutorial</a> &raquo;</li>
+ </ul>
+ </div>
+ <div class="footer">
+ &copy; <a href="../copyright.html">Copyright</a> 1990-2009, Python Software Foundation.
+ <br />
+ The Python Software Foundation is a non-profit corporation.
+ <a href="http://www.python.org/psf/donations/">Please donate.</a>
+ <br />
+ Last updated on Oct 19, 2009.
+ Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 0.6.2.
+ </div>
+
+ </body>
+</html> \ No newline at end of file
diff --git a/help/PythonTutorial/tutorial/modules.html b/help/PythonTutorial/tutorial/modules.html
new file mode 100644
index 0000000..a32a8ef
--- /dev/null
+++ b/help/PythonTutorial/tutorial/modules.html
@@ -0,0 +1,636 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+ <title>6. Modules &mdash; Python v2.6.4c2 documentation</title>
+ <link rel="stylesheet" href="../_static/default.css" type="text/css" />
+ <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
+ <script type="text/javascript">
+ var DOCUMENTATION_OPTIONS = {
+ URL_ROOT: '../',
+ VERSION: '2.6.4c2',
+ COLLAPSE_MODINDEX: false,
+ FILE_SUFFIX: '.html',
+ HAS_SOURCE: true
+ };
+ </script>
+ <script type="text/javascript" src="../_static/jquery.js"></script>
+ <script type="text/javascript" src="../_static/doctools.js"></script>
+ <link rel="search" type="application/opensearchdescription+xml"
+ title="Search within Python v2.6.4c2 documentation"
+ href="../_static/opensearch.xml"/>
+ <link rel="author" title="About these documents" href="../about.html" />
+ <link rel="copyright" title="Copyright" href="../copyright.html" />
+ <link rel="top" title="Python v2.6.4c2 documentation" href="../index.html" />
+ <link rel="up" title="The Python Tutorial" href="index.html" />
+ <link rel="next" title="7. Input and Output" href="inputoutput.html" />
+ <link rel="prev" title="5. Data Structures" href="datastructures.html" />
+ <link rel="shortcut icon" type="image/png" href="../_static/py.png" />
+
+
+ </head>
+ <body>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../modindex.html" title="Global Module Index"
+ accesskey="M">modules</a> |</li>
+ <li class="right" >
+ <a href="inputoutput.html" title="7. Input and Output"
+ accesskey="N">next</a> |</li>
+ <li class="right" >
+ <a href="datastructures.html" title="5. Data Structures"
+ accesskey="P">previous</a> |</li>
+ <li><img src="../_static/py.png" alt=""
+ style="vertical-align: middle; margin-top: -1px"/></li>
+ <li><a href="../index.html">Python v2.6.4c2 documentation</a> &raquo;</li>
+
+ <li><a href="index.html" accesskey="U">The Python Tutorial</a> &raquo;</li>
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body">
+
+ <div class="section" id="modules">
+<span id="tut-modules"></span><h1>6. Modules<a class="headerlink" href="#modules" title="Permalink to this headline">¶</a></h1>
+<p>If you quit from the Python interpreter and enter it again, the definitions you
+have made (functions and variables) are lost. Therefore, if you want to write a
+somewhat longer program, you are better off using a text editor to prepare the
+input for the interpreter and running it with that file as input instead. This
+is known as creating a <em>script</em>. As your program gets longer, you may want to
+split it into several files for easier maintenance. You may also want to use a
+handy function that you&#8217;ve written in several programs without copying its
+definition into each program.</p>
+<p>To support this, Python has a way to put definitions in a file and use them in a
+script or in an interactive instance of the interpreter. Such a file is called a
+<em>module</em>; definitions from a module can be <em>imported</em> into other modules or into
+the <em>main</em> module (the collection of variables that you have access to in a
+script executed at the top level and in calculator mode).</p>
+<p>A module is a file containing Python definitions and statements. The file name
+is the module name with the suffix <tt class="docutils literal"><span class="pre">.py</span></tt> appended. Within a module, the
+module&#8217;s name (as a string) is available as the value of the global variable
+<tt class="docutils literal"><span class="pre">__name__</span></tt>. For instance, use your favorite text editor to create a file
+called <tt class="docutils literal"><span class="pre">fibo.py</span></tt> in the current directory with the following contents:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="c"># Fibonacci numbers module</span>
+
+<span class="k">def</span> <span class="nf">fib</span><span class="p">(</span><span class="n">n</span><span class="p">):</span> <span class="c"># write Fibonacci series up to n</span>
+ <span class="n">a</span><span class="p">,</span> <span class="n">b</span> <span class="o">=</span> <span class="mf">0</span><span class="p">,</span> <span class="mf">1</span>
+ <span class="k">while</span> <span class="n">b</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">:</span>
+ <span class="k">print</span> <span class="n">b</span><span class="p">,</span>
+ <span class="n">a</span><span class="p">,</span> <span class="n">b</span> <span class="o">=</span> <span class="n">b</span><span class="p">,</span> <span class="n">a</span><span class="o">+</span><span class="n">b</span>
+
+<span class="k">def</span> <span class="nf">fib2</span><span class="p">(</span><span class="n">n</span><span class="p">):</span> <span class="c"># return Fibonacci series up to n</span>
+ <span class="n">result</span> <span class="o">=</span> <span class="p">[]</span>
+ <span class="n">a</span><span class="p">,</span> <span class="n">b</span> <span class="o">=</span> <span class="mf">0</span><span class="p">,</span> <span class="mf">1</span>
+ <span class="k">while</span> <span class="n">b</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">:</span>
+ <span class="n">result</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">b</span><span class="p">)</span>
+ <span class="n">a</span><span class="p">,</span> <span class="n">b</span> <span class="o">=</span> <span class="n">b</span><span class="p">,</span> <span class="n">a</span><span class="o">+</span><span class="n">b</span>
+ <span class="k">return</span> <span class="n">result</span>
+</pre></div>
+</div>
+<p>Now enter the Python interpreter and import this module with the following
+command:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">fibo</span>
+</pre></div>
+</div>
+<p>This does not enter the names of the functions defined in <tt class="docutils literal"><span class="pre">fibo</span></tt> directly in
+the current symbol table; it only enters the module name <tt class="docutils literal"><span class="pre">fibo</span></tt> there. Using
+the module name you can access the functions:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">fibo</span><span class="o">.</span><span class="n">fib</span><span class="p">(</span><span class="mf">1000</span><span class="p">)</span>
+<span class="go">1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">fibo</span><span class="o">.</span><span class="n">fib2</span><span class="p">(</span><span class="mf">100</span><span class="p">)</span>
+<span class="go">[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">fibo</span><span class="o">.</span><span class="n">__name__</span>
+<span class="go">&#39;fibo&#39;</span>
+</pre></div>
+</div>
+<p>If you intend to use a function often you can assign it to a local name:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">fib</span> <span class="o">=</span> <span class="n">fibo</span><span class="o">.</span><span class="n">fib</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">fib</span><span class="p">(</span><span class="mf">500</span><span class="p">)</span>
+<span class="go">1 1 2 3 5 8 13 21 34 55 89 144 233 377</span>
+</pre></div>
+</div>
+<div class="section" id="more-on-modules">
+<span id="tut-moremodules"></span><h2>6.1. More on Modules<a class="headerlink" href="#more-on-modules" title="Permalink to this headline">¶</a></h2>
+<p>A module can contain executable statements as well as function definitions.
+These statements are intended to initialize the module. They are executed only
+the <em>first</em> time the module is imported somewhere. <a class="footnote-reference" href="#id2" id="id1">[1]</a></p>
+<p>Each module has its own private symbol table, which is used as the global symbol
+table by all functions defined in the module. Thus, the author of a module can
+use global variables in the module without worrying about accidental clashes
+with a user&#8217;s global variables. On the other hand, if you know what you are
+doing you can touch a module&#8217;s global variables with the same notation used to
+refer to its functions, <tt class="docutils literal"><span class="pre">modname.itemname</span></tt>.</p>
+<p>Modules can import other modules. It is customary but not required to place all
+<a class="reference external" href="../reference/simple_stmts.html#import"><tt class="xref docutils literal"><span class="pre">import</span></tt></a> statements at the beginning of a module (or script, for that
+matter). The imported module names are placed in the importing module&#8217;s global
+symbol table.</p>
+<p>There is a variant of the <a class="reference external" href="../reference/simple_stmts.html#import"><tt class="xref docutils literal"><span class="pre">import</span></tt></a> statement that imports names from a
+module directly into the importing module&#8217;s symbol table. For example:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">fibo</span> <span class="kn">import</span> <span class="n">fib</span><span class="p">,</span> <span class="n">fib2</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">fib</span><span class="p">(</span><span class="mf">500</span><span class="p">)</span>
+<span class="go">1 1 2 3 5 8 13 21 34 55 89 144 233 377</span>
+</pre></div>
+</div>
+<p>This does not introduce the module name from which the imports are taken in the
+local symbol table (so in the example, <tt class="docutils literal"><span class="pre">fibo</span></tt> is not defined).</p>
+<p>There is even a variant to import all names that a module defines:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">fibo</span> <span class="kn">import</span> <span class="o">*</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">fib</span><span class="p">(</span><span class="mf">500</span><span class="p">)</span>
+<span class="go">1 1 2 3 5 8 13 21 34 55 89 144 233 377</span>
+</pre></div>
+</div>
+<p>This imports all names except those beginning with an underscore (<tt class="docutils literal"><span class="pre">_</span></tt>).</p>
+<div class="admonition note">
+<p class="first admonition-title">Note</p>
+<p class="last">For efficiency reasons, each module is only imported once per interpreter
+session. Therefore, if you change your modules, you must restart the
+interpreter &#8211; or, if it&#8217;s just one module you want to test interactively,
+use <a title="reload" class="reference external" href="../library/functions.html#reload"><tt class="xref docutils literal"><span class="pre">reload()</span></tt></a>, e.g. <tt class="docutils literal"><span class="pre">reload(modulename)</span></tt>.</p>
+</div>
+<div class="section" id="executing-modules-as-scripts">
+<span id="tut-modulesasscripts"></span><h3>6.1.1. Executing modules as scripts<a class="headerlink" href="#executing-modules-as-scripts" title="Permalink to this headline">¶</a></h3>
+<p>When you run a Python module with</p>
+<div class="highlight-python"><pre>python fibo.py &lt;arguments&gt;</pre>
+</div>
+<p>the code in the module will be executed, just as if you imported it, but with
+the <tt class="docutils literal"><span class="pre">__name__</span></tt> set to <tt class="docutils literal"><span class="pre">&quot;__main__&quot;</span></tt>. That means that by adding this code at
+the end of your module:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">&quot;__main__&quot;</span><span class="p">:</span>
+ <span class="kn">import</span> <span class="nn">sys</span>
+ <span class="n">fib</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mf">1</span><span class="p">]))</span>
+</pre></div>
+</div>
+<p>you can make the file usable as a script as well as an importable module,
+because the code that parses the command line only runs if the module is
+executed as the &#8220;main&#8221; file:</p>
+<div class="highlight-python"><pre>$ python fibo.py 50
+1 1 2 3 5 8 13 21 34</pre>
+</div>
+<p>If the module is imported, the code is not run:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">fibo</span>
+<span class="go">&gt;&gt;&gt;</span>
+</pre></div>
+</div>
+<p>This is often used either to provide a convenient user interface to a module, or
+for testing purposes (running the module as a script executes a test suite).</p>
+</div>
+<div class="section" id="the-module-search-path">
+<span id="tut-searchpath"></span><h3>6.1.2. The Module Search Path<a class="headerlink" href="#the-module-search-path" title="Permalink to this headline">¶</a></h3>
+<p id="index-1073">When a module named <tt class="xref docutils literal"><span class="pre">spam</span></tt> is imported, the interpreter searches for a file
+named <tt class="docutils literal"><span class="pre">spam.py</span></tt> in the current directory, and then in the list of
+directories specified by the environment variable <span class="target" id="index-1074"></span><a class="reference external" href="../using/cmdline.html#envvar-PYTHONPATH"><strong class="xref">PYTHONPATH</strong></a>. This
+has the same syntax as the shell variable <span class="target" id="index-1075"></span><strong class="xref">PATH</strong>, that is, a list of
+directory names. When <span class="target" id="index-1076"></span><a class="reference external" href="../using/cmdline.html#envvar-PYTHONPATH"><strong class="xref">PYTHONPATH</strong></a> is not set, or when the file is not
+found there, the search continues in an installation-dependent default path; on
+Unix, this is usually <tt class="docutils literal"><span class="pre">.:/usr/local/lib/python</span></tt>.</p>
+<p>Actually, modules are searched in the list of directories given by the variable
+<tt class="docutils literal"><span class="pre">sys.path</span></tt> which is initialized from the directory containing the input script
+(or the current directory), <span class="target" id="index-1077"></span><a class="reference external" href="../using/cmdline.html#envvar-PYTHONPATH"><strong class="xref">PYTHONPATH</strong></a> and the installation- dependent
+default. This allows Python programs that know what they&#8217;re doing to modify or
+replace the module search path. Note that because the directory containing the
+script being run is on the search path, it is important that the script not have
+the same name as a standard module, or Python will attempt to load the script as
+a module when that module is imported. This will generally be an error. See
+section <a class="reference internal" href="#tut-standardmodules"><em>Standard Modules</em></a> for more information.</p>
+</div>
+<div class="section" id="compiled-python-files">
+<h3>6.1.3. &#8220;Compiled&#8221; Python files<a class="headerlink" href="#compiled-python-files" title="Permalink to this headline">¶</a></h3>
+<p>As an important speed-up of the start-up time for short programs that use a lot
+of standard modules, if a file called <tt class="docutils literal"><span class="pre">spam.pyc</span></tt> exists in the directory
+where <tt class="docutils literal"><span class="pre">spam.py</span></tt> is found, this is assumed to contain an
+already-&#8220;byte-compiled&#8221; version of the module <tt class="xref docutils literal"><span class="pre">spam</span></tt>. The modification time
+of the version of <tt class="docutils literal"><span class="pre">spam.py</span></tt> used to create <tt class="docutils literal"><span class="pre">spam.pyc</span></tt> is recorded in
+<tt class="docutils literal"><span class="pre">spam.pyc</span></tt>, and the <tt class="docutils literal"><span class="pre">.pyc</span></tt> file is ignored if these don&#8217;t match.</p>
+<p>Normally, you don&#8217;t need to do anything to create the <tt class="docutils literal"><span class="pre">spam.pyc</span></tt> file.
+Whenever <tt class="docutils literal"><span class="pre">spam.py</span></tt> is successfully compiled, an attempt is made to write
+the compiled version to <tt class="docutils literal"><span class="pre">spam.pyc</span></tt>. It is not an error if this attempt
+fails; if for any reason the file is not written completely, the resulting
+<tt class="docutils literal"><span class="pre">spam.pyc</span></tt> file will be recognized as invalid and thus ignored later. The
+contents of the <tt class="docutils literal"><span class="pre">spam.pyc</span></tt> file are platform independent, so a Python
+module directory can be shared by machines of different architectures.</p>
+<p>Some tips for experts:</p>
+<ul>
+<li><p class="first">When the Python interpreter is invoked with the <a class="reference external" href="../using/cmdline.html#cmdoption-O"><em class="xref">-O</em></a> flag, optimized
+code is generated and stored in <tt class="docutils literal"><span class="pre">.pyo</span></tt> files. The optimizer currently
+doesn&#8217;t help much; it only removes <a class="reference external" href="../reference/simple_stmts.html#assert"><tt class="xref docutils literal"><span class="pre">assert</span></tt></a> statements. When
+<a class="reference external" href="../using/cmdline.html#cmdoption-O"><em class="xref">-O</em></a> is used, <em>all</em> <a class="reference external" href="../glossary.html#term-bytecode"><em class="xref">bytecode</em></a> is optimized; <tt class="docutils literal"><span class="pre">.pyc</span></tt> files are
+ignored and <tt class="docutils literal"><span class="pre">.py</span></tt> files are compiled to optimized bytecode.</p>
+</li>
+<li><p class="first">Passing two <a class="reference external" href="../using/cmdline.html#cmdoption-O"><em class="xref">-O</em></a> flags to the Python interpreter (<a class="reference external" href="../using/cmdline.html#cmdoption-OO"><em class="xref">-OO</em></a>) will
+cause the bytecode compiler to perform optimizations that could in some rare
+cases result in malfunctioning programs. Currently only <tt class="docutils literal"><span class="pre">__doc__</span></tt> strings are
+removed from the bytecode, resulting in more compact <tt class="docutils literal"><span class="pre">.pyo</span></tt> files. Since
+some programs may rely on having these available, you should only use this
+option if you know what you&#8217;re doing.</p>
+</li>
+<li><p class="first">A program doesn&#8217;t run any faster when it is read from a <tt class="docutils literal"><span class="pre">.pyc</span></tt> or
+<tt class="docutils literal"><span class="pre">.pyo</span></tt> file than when it is read from a <tt class="docutils literal"><span class="pre">.py</span></tt> file; the only thing
+that&#8217;s faster about <tt class="docutils literal"><span class="pre">.pyc</span></tt> or <tt class="docutils literal"><span class="pre">.pyo</span></tt> files is the speed with which
+they are loaded.</p>
+</li>
+<li><p class="first">When a script is run by giving its name on the command line, the bytecode for
+the script is never written to a <tt class="docutils literal"><span class="pre">.pyc</span></tt> or <tt class="docutils literal"><span class="pre">.pyo</span></tt> file. Thus, the
+startup time of a script may be reduced by moving most of its code to a module
+and having a small bootstrap script that imports that module. It is also
+possible to name a <tt class="docutils literal"><span class="pre">.pyc</span></tt> or <tt class="docutils literal"><span class="pre">.pyo</span></tt> file directly on the command
+line.</p>
+</li>
+<li><p class="first">It is possible to have a file called <tt class="docutils literal"><span class="pre">spam.pyc</span></tt> (or <tt class="docutils literal"><span class="pre">spam.pyo</span></tt>
+when <a class="reference external" href="../using/cmdline.html#cmdoption-O"><em class="xref">-O</em></a> is used) without a file <tt class="docutils literal"><span class="pre">spam.py</span></tt> for the same module.
+This can be used to distribute a library of Python code in a form that is
+moderately hard to reverse engineer.</p>
+</li>
+<li id="index-1078"><p class="first">The module <a title="Tools for byte-compiling all Python source files in a directory tree." class="reference external" href="../library/compileall.html#module-compileall"><tt class="xref docutils literal"><span class="pre">compileall</span></tt></a> can create <tt class="docutils literal"><span class="pre">.pyc</span></tt> files (or <tt class="docutils literal"><span class="pre">.pyo</span></tt>
+files when <a class="reference external" href="../using/cmdline.html#cmdoption-O"><em class="xref">-O</em></a> is used) for all modules in a directory.</p>
+</li>
+</ul>
+</div>
+</div>
+<div class="section" id="standard-modules">
+<span id="tut-standardmodules"></span><h2>6.2. Standard Modules<a class="headerlink" href="#standard-modules" title="Permalink to this headline">¶</a></h2>
+<p id="index-1079">Python comes with a library of standard modules, described in a separate
+document, the Python Library Reference (&#8220;Library Reference&#8221; hereafter). Some
+modules are built into the interpreter; these provide access to operations that
+are not part of the core of the language but are nevertheless built in, either
+for efficiency or to provide access to operating system primitives such as
+system calls. The set of such modules is a configuration option which also
+depends on the underlying platform For example, the <tt class="xref docutils literal"><span class="pre">winreg</span></tt> module is only
+provided on Windows systems. One particular module deserves some attention:
+<a title="Access system-specific parameters and functions." class="reference external" href="../library/sys.html#module-sys"><tt class="xref docutils literal"><span class="pre">sys</span></tt></a>, which is built into every Python interpreter. The variables
+<tt class="docutils literal"><span class="pre">sys.ps1</span></tt> and <tt class="docutils literal"><span class="pre">sys.ps2</span></tt> define the strings used as primary and secondary
+prompts:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">sys</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">sys</span><span class="o">.</span><span class="n">ps1</span>
+<span class="go">&#39;&gt;&gt;&gt; &#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">sys</span><span class="o">.</span><span class="n">ps2</span>
+<span class="go">&#39;... &#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">sys</span><span class="o">.</span><span class="n">ps1</span> <span class="o">=</span> <span class="s">&#39;C&gt; &#39;</span>
+<span class="go">C&gt; print &#39;Yuck!&#39;</span>
+<span class="go">Yuck!</span>
+<span class="go">C&gt;</span>
+</pre></div>
+</div>
+<p>These two variables are only defined if the interpreter is in interactive mode.</p>
+<p>The variable <tt class="docutils literal"><span class="pre">sys.path</span></tt> is a list of strings that determines the interpreter&#8217;s
+search path for modules. It is initialized to a default path taken from the
+environment variable <span class="target" id="index-1080"></span><a class="reference external" href="../using/cmdline.html#envvar-PYTHONPATH"><strong class="xref">PYTHONPATH</strong></a>, or from a built-in default if
+<span class="target" id="index-1081"></span><a class="reference external" href="../using/cmdline.html#envvar-PYTHONPATH"><strong class="xref">PYTHONPATH</strong></a> is not set. You can modify it using standard list
+operations:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">sys</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">sys</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s">&#39;/ufs/guido/lib/python&#39;</span><span class="p">)</span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="the-dir-function">
+<span id="tut-dir"></span><h2>6.3. The <a title="dir" class="reference external" href="../library/functions.html#dir"><tt class="xref docutils literal"><span class="pre">dir()</span></tt></a> Function<a class="headerlink" href="#the-dir-function" title="Permalink to this headline">¶</a></h2>
+<p>The built-in function <a title="dir" class="reference external" href="../library/functions.html#dir"><tt class="xref docutils literal"><span class="pre">dir()</span></tt></a> is used to find out which names a module
+defines. It returns a sorted list of strings:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">fibo</span><span class="o">,</span> <span class="nn">sys</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">dir</span><span class="p">(</span><span class="n">fibo</span><span class="p">)</span>
+<span class="go">[&#39;__name__&#39;, &#39;fib&#39;, &#39;fib2&#39;]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">dir</span><span class="p">(</span><span class="n">sys</span><span class="p">)</span>
+<span class="go">[&#39;__displayhook__&#39;, &#39;__doc__&#39;, &#39;__excepthook__&#39;, &#39;__name__&#39;, &#39;__stderr__&#39;,</span>
+<span class="go"> &#39;__stdin__&#39;, &#39;__stdout__&#39;, &#39;_getframe&#39;, &#39;api_version&#39;, &#39;argv&#39;,</span>
+<span class="go"> &#39;builtin_module_names&#39;, &#39;byteorder&#39;, &#39;callstats&#39;, &#39;copyright&#39;,</span>
+<span class="go"> &#39;displayhook&#39;, &#39;exc_clear&#39;, &#39;exc_info&#39;, &#39;exc_type&#39;, &#39;excepthook&#39;,</span>
+<span class="go"> &#39;exec_prefix&#39;, &#39;executable&#39;, &#39;exit&#39;, &#39;getdefaultencoding&#39;, &#39;getdlopenflags&#39;,</span>
+<span class="go"> &#39;getrecursionlimit&#39;, &#39;getrefcount&#39;, &#39;hexversion&#39;, &#39;maxint&#39;, &#39;maxunicode&#39;,</span>
+<span class="go"> &#39;meta_path&#39;, &#39;modules&#39;, &#39;path&#39;, &#39;path_hooks&#39;, &#39;path_importer_cache&#39;,</span>
+<span class="go"> &#39;platform&#39;, &#39;prefix&#39;, &#39;ps1&#39;, &#39;ps2&#39;, &#39;setcheckinterval&#39;, &#39;setdlopenflags&#39;,</span>
+<span class="go"> &#39;setprofile&#39;, &#39;setrecursionlimit&#39;, &#39;settrace&#39;, &#39;stderr&#39;, &#39;stdin&#39;, &#39;stdout&#39;,</span>
+<span class="go"> &#39;version&#39;, &#39;version_info&#39;, &#39;warnoptions&#39;]</span>
+</pre></div>
+</div>
+<p>Without arguments, <a title="dir" class="reference external" href="../library/functions.html#dir"><tt class="xref docutils literal"><span class="pre">dir()</span></tt></a> lists the names you have defined currently:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">a</span> <span class="o">=</span> <span class="p">[</span><span class="mf">1</span><span class="p">,</span> <span class="mf">2</span><span class="p">,</span> <span class="mf">3</span><span class="p">,</span> <span class="mf">4</span><span class="p">,</span> <span class="mf">5</span><span class="p">]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">fibo</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">fib</span> <span class="o">=</span> <span class="n">fibo</span><span class="o">.</span><span class="n">fib</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">dir</span><span class="p">()</span>
+<span class="go">[&#39;__builtins__&#39;, &#39;__doc__&#39;, &#39;__file__&#39;, &#39;__name__&#39;, &#39;a&#39;, &#39;fib&#39;, &#39;fibo&#39;, &#39;sys&#39;]</span>
+</pre></div>
+</div>
+<p>Note that it lists all types of names: variables, modules, functions, etc.</p>
+<p id="index-1082"><a title="dir" class="reference external" href="../library/functions.html#dir"><tt class="xref docutils literal"><span class="pre">dir()</span></tt></a> does not list the names of built-in functions and variables. If you
+want a list of those, they are defined in the standard module
+<a title="The module that provides the built-in namespace." class="reference external" href="../library/__builtin__.html#module-__builtin__"><tt class="xref docutils literal"><span class="pre">__builtin__</span></tt></a>:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">__builtin__</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">dir</span><span class="p">(</span><span class="n">__builtin__</span><span class="p">)</span>
+<span class="go">[&#39;ArithmeticError&#39;, &#39;AssertionError&#39;, &#39;AttributeError&#39;, &#39;DeprecationWarning&#39;,</span>
+<span class="go"> &#39;EOFError&#39;, &#39;Ellipsis&#39;, &#39;EnvironmentError&#39;, &#39;Exception&#39;, &#39;False&#39;,</span>
+<span class="go"> &#39;FloatingPointError&#39;, &#39;FutureWarning&#39;, &#39;IOError&#39;, &#39;ImportError&#39;,</span>
+<span class="go"> &#39;IndentationError&#39;, &#39;IndexError&#39;, &#39;KeyError&#39;, &#39;KeyboardInterrupt&#39;,</span>
+<span class="go"> &#39;LookupError&#39;, &#39;MemoryError&#39;, &#39;NameError&#39;, &#39;None&#39;, &#39;NotImplemented&#39;,</span>
+<span class="go"> &#39;NotImplementedError&#39;, &#39;OSError&#39;, &#39;OverflowError&#39;,</span>
+<span class="go"> &#39;PendingDeprecationWarning&#39;, &#39;ReferenceError&#39;, &#39;RuntimeError&#39;,</span>
+<span class="go"> &#39;RuntimeWarning&#39;, &#39;StandardError&#39;, &#39;StopIteration&#39;, &#39;SyntaxError&#39;,</span>
+<span class="go"> &#39;SyntaxWarning&#39;, &#39;SystemError&#39;, &#39;SystemExit&#39;, &#39;TabError&#39;, &#39;True&#39;,</span>
+<span class="go"> &#39;TypeError&#39;, &#39;UnboundLocalError&#39;, &#39;UnicodeDecodeError&#39;,</span>
+<span class="go"> &#39;UnicodeEncodeError&#39;, &#39;UnicodeError&#39;, &#39;UnicodeTranslateError&#39;,</span>
+<span class="go"> &#39;UserWarning&#39;, &#39;ValueError&#39;, &#39;Warning&#39;, &#39;WindowsError&#39;,</span>
+<span class="go"> &#39;ZeroDivisionError&#39;, &#39;_&#39;, &#39;__debug__&#39;, &#39;__doc__&#39;, &#39;__import__&#39;,</span>
+<span class="go"> &#39;__name__&#39;, &#39;abs&#39;, &#39;apply&#39;, &#39;basestring&#39;, &#39;bool&#39;, &#39;buffer&#39;,</span>
+<span class="go"> &#39;callable&#39;, &#39;chr&#39;, &#39;classmethod&#39;, &#39;cmp&#39;, &#39;coerce&#39;, &#39;compile&#39;,</span>
+<span class="go"> &#39;complex&#39;, &#39;copyright&#39;, &#39;credits&#39;, &#39;delattr&#39;, &#39;dict&#39;, &#39;dir&#39;, &#39;divmod&#39;,</span>
+<span class="go"> &#39;enumerate&#39;, &#39;eval&#39;, &#39;execfile&#39;, &#39;exit&#39;, &#39;file&#39;, &#39;filter&#39;, &#39;float&#39;,</span>
+<span class="go"> &#39;frozenset&#39;, &#39;getattr&#39;, &#39;globals&#39;, &#39;hasattr&#39;, &#39;hash&#39;, &#39;help&#39;, &#39;hex&#39;,</span>
+<span class="go"> &#39;id&#39;, &#39;input&#39;, &#39;int&#39;, &#39;intern&#39;, &#39;isinstance&#39;, &#39;issubclass&#39;, &#39;iter&#39;,</span>
+<span class="go"> &#39;len&#39;, &#39;license&#39;, &#39;list&#39;, &#39;locals&#39;, &#39;long&#39;, &#39;map&#39;, &#39;max&#39;, &#39;min&#39;,</span>
+<span class="go"> &#39;object&#39;, &#39;oct&#39;, &#39;open&#39;, &#39;ord&#39;, &#39;pow&#39;, &#39;property&#39;, &#39;quit&#39;, &#39;range&#39;,</span>
+<span class="go"> &#39;raw_input&#39;, &#39;reduce&#39;, &#39;reload&#39;, &#39;repr&#39;, &#39;reversed&#39;, &#39;round&#39;, &#39;set&#39;,</span>
+<span class="go"> &#39;setattr&#39;, &#39;slice&#39;, &#39;sorted&#39;, &#39;staticmethod&#39;, &#39;str&#39;, &#39;sum&#39;, &#39;super&#39;,</span>
+<span class="go"> &#39;tuple&#39;, &#39;type&#39;, &#39;unichr&#39;, &#39;unicode&#39;, &#39;vars&#39;, &#39;xrange&#39;, &#39;zip&#39;]</span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="packages">
+<span id="tut-packages"></span><h2>6.4. Packages<a class="headerlink" href="#packages" title="Permalink to this headline">¶</a></h2>
+<p>Packages are a way of structuring Python&#8217;s module namespace by using &#8220;dotted
+module names&#8221;. For example, the module name <tt class="xref docutils literal"><span class="pre">A.B</span></tt> designates a submodule
+named <tt class="docutils literal"><span class="pre">B</span></tt> in a package named <tt class="docutils literal"><span class="pre">A</span></tt>. Just like the use of modules saves the
+authors of different modules from having to worry about each other&#8217;s global
+variable names, the use of dotted module names saves the authors of multi-module
+packages like NumPy or the Python Imaging Library from having to worry about
+each other&#8217;s module names.</p>
+<p>Suppose you want to design a collection of modules (a &#8220;package&#8221;) for the uniform
+handling of sound files and sound data. There are many different sound file
+formats (usually recognized by their extension, for example: <tt class="docutils literal"><span class="pre">.wav</span></tt>,
+<tt class="docutils literal"><span class="pre">.aiff</span></tt>, <tt class="docutils literal"><span class="pre">.au</span></tt>), so you may need to create and maintain a growing
+collection of modules for the conversion between the various file formats.
+There are also many different operations you might want to perform on sound data
+(such as mixing, adding echo, applying an equalizer function, creating an
+artificial stereo effect), so in addition you will be writing a never-ending
+stream of modules to perform these operations. Here&#8217;s a possible structure for
+your package (expressed in terms of a hierarchical filesystem):</p>
+<div class="highlight-python"><pre>sound/ Top-level package
+ __init__.py Initialize the sound package
+ formats/ Subpackage for file format conversions
+ __init__.py
+ wavread.py
+ wavwrite.py
+ aiffread.py
+ aiffwrite.py
+ auread.py
+ auwrite.py
+ ...
+ effects/ Subpackage for sound effects
+ __init__.py
+ echo.py
+ surround.py
+ reverse.py
+ ...
+ filters/ Subpackage for filters
+ __init__.py
+ equalizer.py
+ vocoder.py
+ karaoke.py
+ ...</pre>
+</div>
+<p>When importing the package, Python searches through the directories on
+<tt class="docutils literal"><span class="pre">sys.path</span></tt> looking for the package subdirectory.</p>
+<p>The <tt class="docutils literal"><span class="pre">__init__.py</span></tt> files are required to make Python treat the directories
+as containing packages; this is done to prevent directories with a common name,
+such as <tt class="docutils literal"><span class="pre">string</span></tt>, from unintentionally hiding valid modules that occur later
+on the module search path. In the simplest case, <tt class="docutils literal"><span class="pre">__init__.py</span></tt> can just be
+an empty file, but it can also execute initialization code for the package or
+set the <tt class="docutils literal"><span class="pre">__all__</span></tt> variable, described later.</p>
+<p>Users of the package can import individual modules from the package, for
+example:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">sound.effects.echo</span>
+</pre></div>
+</div>
+<p>This loads the submodule <tt class="xref docutils literal"><span class="pre">sound.effects.echo</span></tt>. It must be referenced with
+its full name.</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="n">sound</span><span class="o">.</span><span class="n">effects</span><span class="o">.</span><span class="n">echo</span><span class="o">.</span><span class="n">echofilter</span><span class="p">(</span><span class="nb">input</span><span class="p">,</span> <span class="n">output</span><span class="p">,</span> <span class="n">delay</span><span class="o">=</span><span class="mf">0.7</span><span class="p">,</span> <span class="n">atten</span><span class="o">=</span><span class="mf">4</span><span class="p">)</span>
+</pre></div>
+</div>
+<p>An alternative way of importing the submodule is:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">sound.effects</span> <span class="kn">import</span> <span class="n">echo</span>
+</pre></div>
+</div>
+<p>This also loads the submodule <tt class="xref docutils literal"><span class="pre">echo</span></tt>, and makes it available without its
+package prefix, so it can be used as follows:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="n">echo</span><span class="o">.</span><span class="n">echofilter</span><span class="p">(</span><span class="nb">input</span><span class="p">,</span> <span class="n">output</span><span class="p">,</span> <span class="n">delay</span><span class="o">=</span><span class="mf">0.7</span><span class="p">,</span> <span class="n">atten</span><span class="o">=</span><span class="mf">4</span><span class="p">)</span>
+</pre></div>
+</div>
+<p>Yet another variation is to import the desired function or variable directly:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">sound.effects.echo</span> <span class="kn">import</span> <span class="n">echofilter</span>
+</pre></div>
+</div>
+<p>Again, this loads the submodule <tt class="xref docutils literal"><span class="pre">echo</span></tt>, but this makes its function
+<tt class="xref docutils literal"><span class="pre">echofilter()</span></tt> directly available:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="n">echofilter</span><span class="p">(</span><span class="nb">input</span><span class="p">,</span> <span class="n">output</span><span class="p">,</span> <span class="n">delay</span><span class="o">=</span><span class="mf">0.7</span><span class="p">,</span> <span class="n">atten</span><span class="o">=</span><span class="mf">4</span><span class="p">)</span>
+</pre></div>
+</div>
+<p>Note that when using <tt class="docutils literal"><span class="pre">from</span> <span class="pre">package</span> <span class="pre">import</span> <span class="pre">item</span></tt>, the item can be either a
+submodule (or subpackage) of the package, or some other name defined in the
+package, like a function, class or variable. The <tt class="docutils literal"><span class="pre">import</span></tt> statement first
+tests whether the item is defined in the package; if not, it assumes it is a
+module and attempts to load it. If it fails to find it, an <a title="exceptions.ImportError" class="reference external" href="../library/exceptions.html#exceptions.ImportError"><tt class="xref docutils literal"><span class="pre">ImportError</span></tt></a>
+exception is raised.</p>
+<p>Contrarily, when using syntax like <tt class="docutils literal"><span class="pre">import</span> <span class="pre">item.subitem.subsubitem</span></tt>, each item
+except for the last must be a package; the last item can be a module or a
+package but can&#8217;t be a class or function or variable defined in the previous
+item.</p>
+<div class="section" id="importing-from-a-package">
+<span id="tut-pkg-import-star"></span><h3>6.4.1. Importing * From a Package<a class="headerlink" href="#importing-from-a-package" title="Permalink to this headline">¶</a></h3>
+<p id="index-1083">Now what happens when the user writes <tt class="docutils literal"><span class="pre">from</span> <span class="pre">sound.effects</span> <span class="pre">import</span> <span class="pre">*</span></tt>? Ideally,
+one would hope that this somehow goes out to the filesystem, finds which
+submodules are present in the package, and imports them all. Unfortunately,
+this operation does not work very well on Windows platforms, where the
+filesystem does not always have accurate information about the case of a
+filename! On these platforms, there is no guaranteed way to know whether a file
+<tt class="docutils literal"><span class="pre">ECHO.PY</span></tt> should be imported as a module <tt class="xref docutils literal"><span class="pre">echo</span></tt>, <tt class="xref docutils literal"><span class="pre">Echo</span></tt> or
+<tt class="xref docutils literal"><span class="pre">ECHO</span></tt>. (For example, Windows 95 has the annoying practice of showing all
+file names with a capitalized first letter.) The DOS 8+3 filename restriction
+adds another interesting problem for long module names.</p>
+<p>The only solution is for the package author to provide an explicit index of the
+package. The import statement uses the following convention: if a package&#8217;s
+<tt class="docutils literal"><span class="pre">__init__.py</span></tt> code defines a list named <tt class="docutils literal"><span class="pre">__all__</span></tt>, it is taken to be the
+list of module names that should be imported when <tt class="docutils literal"><span class="pre">from</span> <span class="pre">package</span> <span class="pre">import</span> <span class="pre">*</span></tt> is
+encountered. It is up to the package author to keep this list up-to-date when a
+new version of the package is released. Package authors may also decide not to
+support it, if they don&#8217;t see a use for importing * from their package. For
+example, the file <tt class="docutils literal"><span class="pre">sounds/effects/__init__.py</span></tt> could contain the following
+code:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="n">__all__</span> <span class="o">=</span> <span class="p">[</span><span class="s">&quot;echo&quot;</span><span class="p">,</span> <span class="s">&quot;surround&quot;</span><span class="p">,</span> <span class="s">&quot;reverse&quot;</span><span class="p">]</span>
+</pre></div>
+</div>
+<p>This would mean that <tt class="docutils literal"><span class="pre">from</span> <span class="pre">sound.effects</span> <span class="pre">import</span> <span class="pre">*</span></tt> would import the three
+named submodules of the <tt class="xref docutils literal"><span class="pre">sound</span></tt> package.</p>
+<p>If <tt class="docutils literal"><span class="pre">__all__</span></tt> is not defined, the statement <tt class="docutils literal"><span class="pre">from</span> <span class="pre">sound.effects</span> <span class="pre">import</span> <span class="pre">*</span></tt>
+does <em>not</em> import all submodules from the package <tt class="xref docutils literal"><span class="pre">sound.effects</span></tt> into the
+current namespace; it only ensures that the package <tt class="xref docutils literal"><span class="pre">sound.effects</span></tt> has
+been imported (possibly running any initialization code in <tt class="docutils literal"><span class="pre">__init__.py</span></tt>)
+and then imports whatever names are defined in the package. This includes any
+names defined (and submodules explicitly loaded) by <tt class="docutils literal"><span class="pre">__init__.py</span></tt>. It
+also includes any submodules of the package that were explicitly loaded by
+previous import statements. Consider this code:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">sound.effects.echo</span>
+<span class="kn">import</span> <span class="nn">sound.effects.surround</span>
+<span class="kn">from</span> <span class="nn">sound.effects</span> <span class="kn">import</span> <span class="o">*</span>
+</pre></div>
+</div>
+<p>In this example, the echo and surround modules are imported in the current
+namespace because they are defined in the <tt class="xref docutils literal"><span class="pre">sound.effects</span></tt> package when the
+<tt class="docutils literal"><span class="pre">from...import</span></tt> statement is executed. (This also works when <tt class="docutils literal"><span class="pre">__all__</span></tt> is
+defined.)</p>
+<p>Note that in general the practice of importing <tt class="docutils literal"><span class="pre">*</span></tt> from a module or package is
+frowned upon, since it often causes poorly readable code. However, it is okay to
+use it to save typing in interactive sessions, and certain modules are designed
+to export only names that follow certain patterns.</p>
+<p>Remember, there is nothing wrong with using <tt class="docutils literal"><span class="pre">from</span> <span class="pre">Package</span> <span class="pre">import</span>
+<span class="pre">specific_submodule</span></tt>! In fact, this is the recommended notation unless the
+importing module needs to use submodules with the same name from different
+packages.</p>
+</div>
+<div class="section" id="intra-package-references">
+<h3>6.4.2. Intra-package References<a class="headerlink" href="#intra-package-references" title="Permalink to this headline">¶</a></h3>
+<p>The submodules often need to refer to each other. For example, the
+<tt class="xref docutils literal"><span class="pre">surround</span></tt> module might use the <tt class="xref docutils literal"><span class="pre">echo</span></tt> module. In fact, such
+references are so common that the <a class="reference external" href="../reference/simple_stmts.html#import"><tt class="xref docutils literal"><span class="pre">import</span></tt></a> statement first looks in the
+containing package before looking in the standard module search path. Thus, the
+<tt class="xref docutils literal"><span class="pre">surround</span></tt> module can simply use <tt class="docutils literal"><span class="pre">import</span> <span class="pre">echo</span></tt> or <tt class="docutils literal"><span class="pre">from</span> <span class="pre">echo</span> <span class="pre">import</span>
+<span class="pre">echofilter</span></tt>. If the imported module is not found in the current package (the
+package of which the current module is a submodule), the <a class="reference external" href="../reference/simple_stmts.html#import"><tt class="xref docutils literal"><span class="pre">import</span></tt></a>
+statement looks for a top-level module with the given name.</p>
+<p>When packages are structured into subpackages (as with the <tt class="xref docutils literal"><span class="pre">sound</span></tt> package
+in the example), you can use absolute imports to refer to submodules of siblings
+packages. For example, if the module <tt class="xref docutils literal"><span class="pre">sound.filters.vocoder</span></tt> needs to use
+the <tt class="xref docutils literal"><span class="pre">echo</span></tt> module in the <tt class="xref docutils literal"><span class="pre">sound.effects</span></tt> package, it can use <tt class="docutils literal"><span class="pre">from</span>
+<span class="pre">sound.effects</span> <span class="pre">import</span> <span class="pre">echo</span></tt>.</p>
+<p>Starting with Python 2.5, in addition to the implicit relative imports described
+above, you can write explicit relative imports with the <tt class="docutils literal"><span class="pre">from</span> <span class="pre">module</span> <span class="pre">import</span>
+<span class="pre">name</span></tt> form of import statement. These explicit relative imports use leading
+dots to indicate the current and parent packages involved in the relative
+import. From the <tt class="xref docutils literal"><span class="pre">surround</span></tt> module for example, you might use:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">.</span> <span class="kn">import</span> <span class="n">echo</span>
+<span class="kn">from</span> <span class="nn">..</span> <span class="kn">import</span> <span class="n">formats</span>
+<span class="kn">from</span> <span class="nn">..filters</span> <span class="kn">import</span> <span class="n">equalizer</span>
+</pre></div>
+</div>
+<p>Note that both explicit and implicit relative imports are based on the name of
+the current module. Since the name of the main module is always <tt class="docutils literal"><span class="pre">&quot;__main__&quot;</span></tt>,
+modules intended for use as the main module of a Python application should
+always use absolute imports.</p>
+</div>
+<div class="section" id="packages-in-multiple-directories">
+<h3>6.4.3. Packages in Multiple Directories<a class="headerlink" href="#packages-in-multiple-directories" title="Permalink to this headline">¶</a></h3>
+<p>Packages support one more special attribute, <tt class="xref docutils literal"><span class="pre">__path__</span></tt>. This is
+initialized to be a list containing the name of the directory holding the
+package&#8217;s <tt class="docutils literal"><span class="pre">__init__.py</span></tt> before the code in that file is executed. This
+variable can be modified; doing so affects future searches for modules and
+subpackages contained in the package.</p>
+<p>While this feature is not often needed, it can be used to extend the set of
+modules found in a package.</p>
+<p class="rubric">Footnotes</p>
+<table class="docutils footnote" frame="void" id="id2" rules="none">
+<colgroup><col class="label" /><col /></colgroup>
+<tbody valign="top">
+<tr><td class="label"><a class="fn-backref" href="#id1">[1]</a></td><td>In fact function definitions are also &#8216;statements&#8217; that are &#8216;executed&#8217;; the
+execution enters the function name in the module&#8217;s global symbol table.</td></tr>
+</tbody>
+</table>
+</div>
+</div>
+</div>
+
+
+ </div>
+ </div>
+ </div>
+ <div class="sphinxsidebar">
+ <div class="sphinxsidebarwrapper">
+ <h3><a href="../contents.html">Table Of Contents</a></h3>
+ <ul>
+<li><a class="reference external" href="">6. Modules</a><ul>
+<li><a class="reference external" href="#more-on-modules">6.1. More on Modules</a><ul>
+<li><a class="reference external" href="#executing-modules-as-scripts">6.1.1. Executing modules as scripts</a></li>
+<li><a class="reference external" href="#the-module-search-path">6.1.2. The Module Search Path</a></li>
+<li><a class="reference external" href="#compiled-python-files">6.1.3. &#8220;Compiled&#8221; Python files</a></li>
+</ul>
+</li>
+<li><a class="reference external" href="#standard-modules">6.2. Standard Modules</a></li>
+<li><a class="reference external" href="#the-dir-function">6.3. The <tt class="docutils literal"><span class="pre">dir()</span></tt> Function</a></li>
+<li><a class="reference external" href="#packages">6.4. Packages</a><ul>
+<li><a class="reference external" href="#importing-from-a-package">6.4.1. Importing * From a Package</a></li>
+<li><a class="reference external" href="#intra-package-references">6.4.2. Intra-package References</a></li>
+<li><a class="reference external" href="#packages-in-multiple-directories">6.4.3. Packages in Multiple Directories</a></li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+
+ <h4>Previous topic</h4>
+ <p class="topless"><a href="datastructures.html"
+ title="previous chapter">5. Data Structures</a></p>
+ <h4>Next topic</h4>
+ <p class="topless"><a href="inputoutput.html"
+ title="next chapter">7. Input and Output</a></p>
+ <h3>This Page</h3>
+ <ul class="this-page-menu">
+ <li><a href="../_sources/tutorial/modules.txt"
+ rel="nofollow">Show Source</a></li>
+ </ul>
+ <div id="searchbox" style="display: none">
+ <h3>Quick search</h3>
+ <form class="search" action="../search.html" method="get">
+ <input type="text" name="q" size="18" />
+ <input type="submit" value="Go" />
+ <input type="hidden" name="check_keywords" value="yes" />
+ <input type="hidden" name="area" value="default" />
+ </form>
+ <p class="searchtip" style="font-size: 90%">
+ Enter search terms or a module, class or function name.
+ </p>
+ </div>
+ <script type="text/javascript">$('#searchbox').show(0);</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../genindex.html" title="General Index"
+ >index</a></li>
+ <li class="right" >
+ <a href="../modindex.html" title="Global Module Index"
+ >modules</a> |</li>
+ <li class="right" >
+ <a href="inputoutput.html" title="7. Input and Output"
+ >next</a> |</li>
+ <li class="right" >
+ <a href="datastructures.html" title="5. Data Structures"
+ >previous</a> |</li>
+ <li><img src="../_static/py.png" alt=""
+ style="vertical-align: middle; margin-top: -1px"/></li>
+ <li><a href="../index.html">Python v2.6.4c2 documentation</a> &raquo;</li>
+
+ <li><a href="index.html" >The Python Tutorial</a> &raquo;</li>
+ </ul>
+ </div>
+ <div class="footer">
+ &copy; <a href="../copyright.html">Copyright</a> 1990-2009, Python Software Foundation.
+ <br />
+ The Python Software Foundation is a non-profit corporation.
+ <a href="http://www.python.org/psf/donations/">Please donate.</a>
+ <br />
+ Last updated on Oct 19, 2009.
+ Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 0.6.2.
+ </div>
+
+ </body>
+</html> \ No newline at end of file
diff --git a/help/PythonTutorial/tutorial/stdlib.html b/help/PythonTutorial/tutorial/stdlib.html
new file mode 100644
index 0000000..7d13ddb
--- /dev/null
+++ b/help/PythonTutorial/tutorial/stdlib.html
@@ -0,0 +1,413 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+ <title>10. Brief Tour of the Standard Library &mdash; Python v2.6.4c2 documentation</title>
+ <link rel="stylesheet" href="../_static/default.css" type="text/css" />
+ <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
+ <script type="text/javascript">
+ var DOCUMENTATION_OPTIONS = {
+ URL_ROOT: '../',
+ VERSION: '2.6.4c2',
+ COLLAPSE_MODINDEX: false,
+ FILE_SUFFIX: '.html',
+ HAS_SOURCE: true
+ };
+ </script>
+ <script type="text/javascript" src="../_static/jquery.js"></script>
+ <script type="text/javascript" src="../_static/doctools.js"></script>
+ <link rel="search" type="application/opensearchdescription+xml"
+ title="Search within Python v2.6.4c2 documentation"
+ href="../_static/opensearch.xml"/>
+ <link rel="author" title="About these documents" href="../about.html" />
+ <link rel="copyright" title="Copyright" href="../copyright.html" />
+ <link rel="top" title="Python v2.6.4c2 documentation" href="../index.html" />
+ <link rel="up" title="The Python Tutorial" href="index.html" />
+ <link rel="next" title="11. Brief Tour of the Standard Library – Part II" href="stdlib2.html" />
+ <link rel="prev" title="9. Classes" href="classes.html" />
+ <link rel="shortcut icon" type="image/png" href="../_static/py.png" />
+
+
+ </head>
+ <body>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../modindex.html" title="Global Module Index"
+ accesskey="M">modules</a> |</li>
+ <li class="right" >
+ <a href="stdlib2.html" title="11. Brief Tour of the Standard Library – Part II"
+ accesskey="N">next</a> |</li>
+ <li class="right" >
+ <a href="classes.html" title="9. Classes"
+ accesskey="P">previous</a> |</li>
+ <li><img src="../_static/py.png" alt=""
+ style="vertical-align: middle; margin-top: -1px"/></li>
+ <li><a href="../index.html">Python v2.6.4c2 documentation</a> &raquo;</li>
+
+ <li><a href="index.html" accesskey="U">The Python Tutorial</a> &raquo;</li>
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body">
+
+ <div class="section" id="brief-tour-of-the-standard-library">
+<span id="tut-brieftour"></span><h1>10. Brief Tour of the Standard Library<a class="headerlink" href="#brief-tour-of-the-standard-library" title="Permalink to this headline">¶</a></h1>
+<div class="section" id="operating-system-interface">
+<span id="tut-os-interface"></span><h2>10.1. Operating System Interface<a class="headerlink" href="#operating-system-interface" title="Permalink to this headline">¶</a></h2>
+<p>The <a title="Miscellaneous operating system interfaces." class="reference external" href="../library/os.html#module-os"><tt class="xref docutils literal"><span class="pre">os</span></tt></a> module provides dozens of functions for interacting with the
+operating system:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">os</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">os</span><span class="o">.</span><span class="n">system</span><span class="p">(</span><span class="s">&#39;time 0:02&#39;</span><span class="p">)</span>
+<span class="go">0</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">os</span><span class="o">.</span><span class="n">getcwd</span><span class="p">()</span> <span class="c"># Return the current working directory</span>
+<span class="go">&#39;C:\\Python26&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">os</span><span class="o">.</span><span class="n">chdir</span><span class="p">(</span><span class="s">&#39;/server/accesslogs&#39;</span><span class="p">)</span>
+</pre></div>
+</div>
+<p>Be sure to use the <tt class="docutils literal"><span class="pre">import</span> <span class="pre">os</span></tt> style instead of <tt class="docutils literal"><span class="pre">from</span> <span class="pre">os</span> <span class="pre">import</span> <span class="pre">*</span></tt>. This
+will keep <a title="os.open" class="reference external" href="../library/os.html#os.open"><tt class="xref docutils literal"><span class="pre">os.open()</span></tt></a> from shadowing the built-in <a title="open" class="reference external" href="../library/functions.html#open"><tt class="xref docutils literal"><span class="pre">open()</span></tt></a> function which
+operates much differently.</p>
+<p id="index-1084">The built-in <a title="dir" class="reference external" href="../library/functions.html#dir"><tt class="xref docutils literal"><span class="pre">dir()</span></tt></a> and <a title="help" class="reference external" href="../library/functions.html#help"><tt class="xref docutils literal"><span class="pre">help()</span></tt></a> functions are useful as interactive
+aids for working with large modules like <a title="Miscellaneous operating system interfaces." class="reference external" href="../library/os.html#module-os"><tt class="xref docutils literal"><span class="pre">os</span></tt></a>:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">os</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">dir</span><span class="p">(</span><span class="n">os</span><span class="p">)</span>
+<span class="go">&lt;returns a list of all module functions&gt;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">help</span><span class="p">(</span><span class="n">os</span><span class="p">)</span>
+<span class="go">&lt;returns an extensive manual page created from the module&#39;s docstrings&gt;</span>
+</pre></div>
+</div>
+<p>For daily file and directory management tasks, the <a title="High-level file operations, including copying." class="reference external" href="../library/shutil.html#module-shutil"><tt class="xref docutils literal"><span class="pre">shutil</span></tt></a> module provides
+a higher level interface that is easier to use:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">shutil</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">shutil</span><span class="o">.</span><span class="n">copyfile</span><span class="p">(</span><span class="s">&#39;data.db&#39;</span><span class="p">,</span> <span class="s">&#39;archive.db&#39;</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">shutil</span><span class="o">.</span><span class="n">move</span><span class="p">(</span><span class="s">&#39;/build/executables&#39;</span><span class="p">,</span> <span class="s">&#39;installdir&#39;</span><span class="p">)</span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="file-wildcards">
+<span id="tut-file-wildcards"></span><h2>10.2. File Wildcards<a class="headerlink" href="#file-wildcards" title="Permalink to this headline">¶</a></h2>
+<p>The <a title="Unix shell style pathname pattern expansion." class="reference external" href="../library/glob.html#module-glob"><tt class="xref docutils literal"><span class="pre">glob</span></tt></a> module provides a function for making file lists from directory
+wildcard searches:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">glob</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">glob</span><span class="o">.</span><span class="n">glob</span><span class="p">(</span><span class="s">&#39;*.py&#39;</span><span class="p">)</span>
+<span class="go">[&#39;primes.py&#39;, &#39;random.py&#39;, &#39;quote.py&#39;]</span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="command-line-arguments">
+<span id="tut-command-line-arguments"></span><h2>10.3. Command Line Arguments<a class="headerlink" href="#command-line-arguments" title="Permalink to this headline">¶</a></h2>
+<p>Common utility scripts often need to process command line arguments. These
+arguments are stored in the <a title="Access system-specific parameters and functions." class="reference external" href="../library/sys.html#module-sys"><tt class="xref docutils literal"><span class="pre">sys</span></tt></a> module&#8217;s <em>argv</em> attribute as a list. For
+instance the following output results from running <tt class="docutils literal"><span class="pre">python</span> <span class="pre">demo.py</span> <span class="pre">one</span> <span class="pre">two</span>
+<span class="pre">three</span></tt> at the command line:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">sys</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">print</span> <span class="n">sys</span><span class="o">.</span><span class="n">argv</span>
+<span class="go">[&#39;demo.py&#39;, &#39;one&#39;, &#39;two&#39;, &#39;three&#39;]</span>
+</pre></div>
+</div>
+<p>The <a title="Portable parser for command line options; support both short and long option names." class="reference external" href="../library/getopt.html#module-getopt"><tt class="xref docutils literal"><span class="pre">getopt</span></tt></a> module processes <em>sys.argv</em> using the conventions of the Unix
+<tt class="xref docutils literal"><span class="pre">getopt()</span></tt> function. More powerful and flexible command line processing is
+provided by the <a title="More convenient, flexible, and powerful command-line parsing library." class="reference external" href="../library/optparse.html#module-optparse"><tt class="xref docutils literal"><span class="pre">optparse</span></tt></a> module.</p>
+</div>
+<div class="section" id="error-output-redirection-and-program-termination">
+<span id="tut-stderr"></span><h2>10.4. Error Output Redirection and Program Termination<a class="headerlink" href="#error-output-redirection-and-program-termination" title="Permalink to this headline">¶</a></h2>
+<p>The <a title="Access system-specific parameters and functions." class="reference external" href="../library/sys.html#module-sys"><tt class="xref docutils literal"><span class="pre">sys</span></tt></a> module also has attributes for <em>stdin</em>, <em>stdout</em>, and <em>stderr</em>.
+The latter is useful for emitting warnings and error messages to make them
+visible even when <em>stdout</em> has been redirected:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">sys</span><span class="o">.</span><span class="n">stderr</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s">&#39;Warning, log file not found starting a new one</span><span class="se">\n</span><span class="s">&#39;</span><span class="p">)</span>
+<span class="go">Warning, log file not found starting a new one</span>
+</pre></div>
+</div>
+<p>The most direct way to terminate a script is to use <tt class="docutils literal"><span class="pre">sys.exit()</span></tt>.</p>
+</div>
+<div class="section" id="string-pattern-matching">
+<span id="tut-string-pattern-matching"></span><h2>10.5. String Pattern Matching<a class="headerlink" href="#string-pattern-matching" title="Permalink to this headline">¶</a></h2>
+<p>The <a title="Regular expression operations." class="reference external" href="../library/re.html#module-re"><tt class="xref docutils literal"><span class="pre">re</span></tt></a> module provides regular expression tools for advanced string
+processing. For complex matching and manipulation, regular expressions offer
+succinct, optimized solutions:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">re</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">re</span><span class="o">.</span><span class="n">findall</span><span class="p">(</span><span class="s">r&#39;\bf[a-z]*&#39;</span><span class="p">,</span> <span class="s">&#39;which foot or hand fell fastest&#39;</span><span class="p">)</span>
+<span class="go">[&#39;foot&#39;, &#39;fell&#39;, &#39;fastest&#39;]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">re</span><span class="o">.</span><span class="n">sub</span><span class="p">(</span><span class="s">r&#39;(\b[a-z]+) \1&#39;</span><span class="p">,</span> <span class="s">r&#39;\1&#39;</span><span class="p">,</span> <span class="s">&#39;cat in the the hat&#39;</span><span class="p">)</span>
+<span class="go">&#39;cat in the hat&#39;</span>
+</pre></div>
+</div>
+<p>When only simple capabilities are needed, string methods are preferred because
+they are easier to read and debug:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="s">&#39;tea for too&#39;</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s">&#39;too&#39;</span><span class="p">,</span> <span class="s">&#39;two&#39;</span><span class="p">)</span>
+<span class="go">&#39;tea for two&#39;</span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="mathematics">
+<span id="tut-mathematics"></span><h2>10.6. Mathematics<a class="headerlink" href="#mathematics" title="Permalink to this headline">¶</a></h2>
+<p>The <a title="Mathematical functions (sin() etc.)." class="reference external" href="../library/math.html#module-math"><tt class="xref docutils literal"><span class="pre">math</span></tt></a> module gives access to the underlying C library functions for
+floating point math:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">math</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">math</span><span class="o">.</span><span class="n">cos</span><span class="p">(</span><span class="n">math</span><span class="o">.</span><span class="n">pi</span> <span class="o">/</span> <span class="mf">4.0</span><span class="p">)</span>
+<span class="go">0.70710678118654757</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">math</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="mf">1024</span><span class="p">,</span> <span class="mf">2</span><span class="p">)</span>
+<span class="go">10.0</span>
+</pre></div>
+</div>
+<p>The <a title="Generate pseudo-random numbers with various common distributions." class="reference external" href="../library/random.html#module-random"><tt class="xref docutils literal"><span class="pre">random</span></tt></a> module provides tools for making random selections:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">random</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">random</span><span class="o">.</span><span class="n">choice</span><span class="p">([</span><span class="s">&#39;apple&#39;</span><span class="p">,</span> <span class="s">&#39;pear&#39;</span><span class="p">,</span> <span class="s">&#39;banana&#39;</span><span class="p">])</span>
+<span class="go">&#39;apple&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">random</span><span class="o">.</span><span class="n">sample</span><span class="p">(</span><span class="nb">xrange</span><span class="p">(</span><span class="mf">100</span><span class="p">),</span> <span class="mf">10</span><span class="p">)</span> <span class="c"># sampling without replacement</span>
+<span class="go">[30, 83, 16, 4, 8, 81, 41, 50, 18, 33]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">random</span><span class="o">.</span><span class="n">random</span><span class="p">()</span> <span class="c"># random float</span>
+<span class="go">0.17970987693706186</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">random</span><span class="o">.</span><span class="n">randrange</span><span class="p">(</span><span class="mf">6</span><span class="p">)</span> <span class="c"># random integer chosen from range(6)</span>
+<span class="go">4</span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="internet-access">
+<span id="tut-internet-access"></span><h2>10.7. Internet Access<a class="headerlink" href="#internet-access" title="Permalink to this headline">¶</a></h2>
+<p>There are a number of modules for accessing the internet and processing internet
+protocols. Two of the simplest are <a title="Next generation URL opening library." class="reference external" href="../library/urllib2.html#module-urllib2"><tt class="xref docutils literal"><span class="pre">urllib2</span></tt></a> for retrieving data from urls
+and <a title="SMTP protocol client (requires sockets)." class="reference external" href="../library/smtplib.html#module-smtplib"><tt class="xref docutils literal"><span class="pre">smtplib</span></tt></a> for sending mail:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">urllib2</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">urllib2</span><span class="o">.</span><span class="n">urlopen</span><span class="p">(</span><span class="s">&#39;http://tycho.usno.navy.mil/cgi-bin/timer.pl&#39;</span><span class="p">):</span>
+<span class="gp">... </span> <span class="k">if</span> <span class="s">&#39;EST&#39;</span> <span class="ow">in</span> <span class="n">line</span> <span class="ow">or</span> <span class="s">&#39;EDT&#39;</span> <span class="ow">in</span> <span class="n">line</span><span class="p">:</span> <span class="c"># look for Eastern Time</span>
+<span class="gp">... </span> <span class="k">print</span> <span class="n">line</span>
+
+<span class="go">&lt;BR&gt;Nov. 25, 09:43:32 PM EST</span>
+
+<span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">smtplib</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">server</span> <span class="o">=</span> <span class="n">smtplib</span><span class="o">.</span><span class="n">SMTP</span><span class="p">(</span><span class="s">&#39;localhost&#39;</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">server</span><span class="o">.</span><span class="n">sendmail</span><span class="p">(</span><span class="s">&#39;soothsayer@example.org&#39;</span><span class="p">,</span> <span class="s">&#39;jcaesar@example.org&#39;</span><span class="p">,</span>
+<span class="gp">... </span><span class="sd">&quot;&quot;&quot;To: jcaesar@example.org</span>
+<span class="gp">... </span><span class="sd">From: soothsayer@example.org</span>
+<span class="gp">...</span><span class="sd"></span>
+<span class="gp">... </span><span class="sd">Beware the Ides of March.</span>
+<span class="gp">... </span><span class="sd">&quot;&quot;&quot;</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">server</span><span class="o">.</span><span class="n">quit</span><span class="p">()</span>
+</pre></div>
+</div>
+<p>(Note that the second example needs a mailserver running on localhost.)</p>
+</div>
+<div class="section" id="dates-and-times">
+<span id="tut-dates-and-times"></span><h2>10.8. Dates and Times<a class="headerlink" href="#dates-and-times" title="Permalink to this headline">¶</a></h2>
+<p>The <a title="Basic date and time types." class="reference external" href="../library/datetime.html#module-datetime"><tt class="xref docutils literal"><span class="pre">datetime</span></tt></a> module supplies classes for manipulating dates and times in
+both simple and complex ways. While date and time arithmetic is supported, the
+focus of the implementation is on efficient member extraction for output
+formatting and manipulation. The module also supports objects that are timezone
+aware.</p>
+<div class="highlight-python"><pre># dates are easily constructed and formatted
+&gt;&gt;&gt; from datetime import date
+&gt;&gt;&gt; now = date.today()
+&gt;&gt;&gt; now
+datetime.date(2003, 12, 2)
+&gt;&gt;&gt; now.strftime("%m-%d-%y. %d %b %Y is a %A on the %d day of %B.")
+'12-02-03. 02 Dec 2003 is a Tuesday on the 02 day of December.'
+
+# dates support calendar arithmetic
+&gt;&gt;&gt; birthday = date(1964, 7, 31)
+&gt;&gt;&gt; age = now - birthday
+&gt;&gt;&gt; age.days
+14368</pre>
+</div>
+</div>
+<div class="section" id="data-compression">
+<span id="tut-data-compression"></span><h2>10.9. Data Compression<a class="headerlink" href="#data-compression" title="Permalink to this headline">¶</a></h2>
+<p>Common data archiving and compression formats are directly supported by modules
+including: <a title="Low-level interface to compression and decompression routines compatible with gzip." class="reference external" href="../library/zlib.html#module-zlib"><tt class="xref docutils literal"><span class="pre">zlib</span></tt></a>, <a title="Interfaces for gzip compression and decompression using file objects." class="reference external" href="../library/gzip.html#module-gzip"><tt class="xref docutils literal"><span class="pre">gzip</span></tt></a>, <a title="Interface to compression and decompression routines compatible with bzip2." class="reference external" href="../library/bz2.html#module-bz2"><tt class="xref docutils literal"><span class="pre">bz2</span></tt></a>, <a title="Read and write ZIP-format archive files." class="reference external" href="../library/zipfile.html#module-zipfile"><tt class="xref docutils literal"><span class="pre">zipfile</span></tt></a> and
+<a title="Read and write tar-format archive files." class="reference external" href="../library/tarfile.html#module-tarfile"><tt class="xref docutils literal"><span class="pre">tarfile</span></tt></a>.</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">zlib</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">s</span> <span class="o">=</span> <span class="s">&#39;witch which has which witches wrist watch&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">len</span><span class="p">(</span><span class="n">s</span><span class="p">)</span>
+<span class="go">41</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">t</span> <span class="o">=</span> <span class="n">zlib</span><span class="o">.</span><span class="n">compress</span><span class="p">(</span><span class="n">s</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">len</span><span class="p">(</span><span class="n">t</span><span class="p">)</span>
+<span class="go">37</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">zlib</span><span class="o">.</span><span class="n">decompress</span><span class="p">(</span><span class="n">t</span><span class="p">)</span>
+<span class="go">&#39;witch which has which witches wrist watch&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">zlib</span><span class="o">.</span><span class="n">crc32</span><span class="p">(</span><span class="n">s</span><span class="p">)</span>
+<span class="go">226805979</span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="performance-measurement">
+<span id="tut-performance-measurement"></span><h2>10.10. Performance Measurement<a class="headerlink" href="#performance-measurement" title="Permalink to this headline">¶</a></h2>
+<p>Some Python users develop a deep interest in knowing the relative performance of
+different approaches to the same problem. Python provides a measurement tool
+that answers those questions immediately.</p>
+<p>For example, it may be tempting to use the tuple packing and unpacking feature
+instead of the traditional approach to swapping arguments. The <a title="Measure the execution time of small code snippets." class="reference external" href="../library/timeit.html#module-timeit"><tt class="xref docutils literal"><span class="pre">timeit</span></tt></a>
+module quickly demonstrates a modest performance advantage:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">timeit</span> <span class="kn">import</span> <span class="n">Timer</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">Timer</span><span class="p">(</span><span class="s">&#39;t=a; a=b; b=t&#39;</span><span class="p">,</span> <span class="s">&#39;a=1; b=2&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">timeit</span><span class="p">()</span>
+<span class="go">0.57535828626024577</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">Timer</span><span class="p">(</span><span class="s">&#39;a,b = b,a&#39;</span><span class="p">,</span> <span class="s">&#39;a=1; b=2&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">timeit</span><span class="p">()</span>
+<span class="go">0.54962537085770791</span>
+</pre></div>
+</div>
+<p>In contrast to <a title="Measure the execution time of small code snippets." class="reference external" href="../library/timeit.html#module-timeit"><tt class="xref docutils literal"><span class="pre">timeit</span></tt></a>&#8216;s fine level of granularity, the <tt class="xref docutils literal"><span class="pre">profile</span></tt> and
+<a title="Statistics object for use with the profiler." class="reference external" href="../library/profile.html#module-pstats"><tt class="xref docutils literal"><span class="pre">pstats</span></tt></a> modules provide tools for identifying time critical sections in
+larger blocks of code.</p>
+</div>
+<div class="section" id="quality-control">
+<span id="tut-quality-control"></span><h2>10.11. Quality Control<a class="headerlink" href="#quality-control" title="Permalink to this headline">¶</a></h2>
+<p>One approach for developing high quality software is to write tests for each
+function as it is developed and to run those tests frequently during the
+development process.</p>
+<p>The <a title="Test pieces of code within docstrings." class="reference external" href="../library/doctest.html#module-doctest"><tt class="xref docutils literal"><span class="pre">doctest</span></tt></a> module provides a tool for scanning a module and validating
+tests embedded in a program&#8217;s docstrings. Test construction is as simple as
+cutting-and-pasting a typical call along with its results into the docstring.
+This improves the documentation by providing the user with an example and it
+allows the doctest module to make sure the code remains true to the
+documentation:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">average</span><span class="p">(</span><span class="n">values</span><span class="p">):</span>
+ <span class="sd">&quot;&quot;&quot;Computes the arithmetic mean of a list of numbers.</span>
+
+<span class="sd"> &gt;&gt;&gt; print average([20, 30, 70])</span>
+<span class="sd"> 40.0</span>
+<span class="sd"> &quot;&quot;&quot;</span>
+ <span class="k">return</span> <span class="nb">sum</span><span class="p">(</span><span class="n">values</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">)</span> <span class="o">/</span> <span class="nb">len</span><span class="p">(</span><span class="n">values</span><span class="p">)</span>
+
+<span class="kn">import</span> <span class="nn">doctest</span>
+<span class="n">doctest</span><span class="o">.</span><span class="n">testmod</span><span class="p">()</span> <span class="c"># automatically validate the embedded tests</span>
+</pre></div>
+</div>
+<p>The <a title="Unit testing framework for Python." class="reference external" href="../library/unittest.html#module-unittest"><tt class="xref docutils literal"><span class="pre">unittest</span></tt></a> module is not as effortless as the <a title="Test pieces of code within docstrings." class="reference external" href="../library/doctest.html#module-doctest"><tt class="xref docutils literal"><span class="pre">doctest</span></tt></a> module,
+but it allows a more comprehensive set of tests to be maintained in a separate
+file:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">unittest</span>
+
+<span class="k">class</span> <span class="nc">TestStatisticalFunctions</span><span class="p">(</span><span class="n">unittest</span><span class="o">.</span><span class="n">TestCase</span><span class="p">):</span>
+
+ <span class="k">def</span> <span class="nf">test_average</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+ <span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="n">average</span><span class="p">([</span><span class="mf">20</span><span class="p">,</span> <span class="mf">30</span><span class="p">,</span> <span class="mf">70</span><span class="p">]),</span> <span class="mf">40.0</span><span class="p">)</span>
+ <span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="nb">round</span><span class="p">(</span><span class="n">average</span><span class="p">([</span><span class="mf">1</span><span class="p">,</span> <span class="mf">5</span><span class="p">,</span> <span class="mf">7</span><span class="p">]),</span> <span class="mf">1</span><span class="p">),</span> <span class="mf">4.3</span><span class="p">)</span>
+ <span class="bp">self</span><span class="o">.</span><span class="n">assertRaises</span><span class="p">(</span><span class="ne">ZeroDivisionError</span><span class="p">,</span> <span class="n">average</span><span class="p">,</span> <span class="p">[])</span>
+ <span class="bp">self</span><span class="o">.</span><span class="n">assertRaises</span><span class="p">(</span><span class="ne">TypeError</span><span class="p">,</span> <span class="n">average</span><span class="p">,</span> <span class="mf">20</span><span class="p">,</span> <span class="mf">30</span><span class="p">,</span> <span class="mf">70</span><span class="p">)</span>
+
+<span class="n">unittest</span><span class="o">.</span><span class="n">main</span><span class="p">()</span> <span class="c"># Calling from the command line invokes all tests</span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="batteries-included">
+<span id="tut-batteries-included"></span><h2>10.12. Batteries Included<a class="headerlink" href="#batteries-included" title="Permalink to this headline">¶</a></h2>
+<p>Python has a &#8220;batteries included&#8221; philosophy. This is best seen through the
+sophisticated and robust capabilities of its larger packages. For example:</p>
+<ul class="simple">
+<li>The <a title="XML-RPC client access." class="reference external" href="../library/xmlrpclib.html#module-xmlrpclib"><tt class="xref docutils literal"><span class="pre">xmlrpclib</span></tt></a> and <a title="Basic XML-RPC server implementation." class="reference external" href="../library/simplexmlrpcserver.html#module-SimpleXMLRPCServer"><tt class="xref docutils literal"><span class="pre">SimpleXMLRPCServer</span></tt></a> modules make implementing
+remote procedure calls into an almost trivial task. Despite the modules
+names, no direct knowledge or handling of XML is needed.</li>
+<li>The <a title="Package supporting the parsing, manipulating, and generating email messages, including MIME documents." class="reference external" href="../library/email.html#module-email"><tt class="xref docutils literal"><span class="pre">email</span></tt></a> package is a library for managing email messages, including
+MIME and other RFC 2822-based message documents. Unlike <a title="SMTP protocol client (requires sockets)." class="reference external" href="../library/smtplib.html#module-smtplib"><tt class="xref docutils literal"><span class="pre">smtplib</span></tt></a> and
+<a title="POP3 protocol client (requires sockets)." class="reference external" href="../library/poplib.html#module-poplib"><tt class="xref docutils literal"><span class="pre">poplib</span></tt></a> which actually send and receive messages, the email package has
+a complete toolset for building or decoding complex message structures
+(including attachments) and for implementing internet encoding and header
+protocols.</li>
+<li>The <a title="Document Object Model API for Python." class="reference external" href="../library/xml.dom.html#module-xml.dom"><tt class="xref docutils literal"><span class="pre">xml.dom</span></tt></a> and <a title="Package containing SAX2 base classes and convenience functions." class="reference external" href="../library/xml.sax.html#module-xml.sax"><tt class="xref docutils literal"><span class="pre">xml.sax</span></tt></a> packages provide robust support for
+parsing this popular data interchange format. Likewise, the <a title="Write and read tabular data to and from delimited files." class="reference external" href="../library/csv.html#module-csv"><tt class="xref docutils literal"><span class="pre">csv</span></tt></a> module
+supports direct reads and writes in a common database format. Together, these
+modules and packages greatly simplify data interchange between python
+applications and other tools.</li>
+<li>Internationalization is supported by a number of modules including
+<a title="Multilingual internationalization services." class="reference external" href="../library/gettext.html#module-gettext"><tt class="xref docutils literal"><span class="pre">gettext</span></tt></a>, <a title="Internationalization services." class="reference external" href="../library/locale.html#module-locale"><tt class="xref docutils literal"><span class="pre">locale</span></tt></a>, and the <a title="Encode and decode data and streams." class="reference external" href="../library/codecs.html#module-codecs"><tt class="xref docutils literal"><span class="pre">codecs</span></tt></a> package.</li>
+</ul>
+</div>
+</div>
+
+
+ </div>
+ </div>
+ </div>
+ <div class="sphinxsidebar">
+ <div class="sphinxsidebarwrapper">
+ <h3><a href="../contents.html">Table Of Contents</a></h3>
+ <ul>
+<li><a class="reference external" href="">10. Brief Tour of the Standard Library</a><ul>
+<li><a class="reference external" href="#operating-system-interface">10.1. Operating System Interface</a></li>
+<li><a class="reference external" href="#file-wildcards">10.2. File Wildcards</a></li>
+<li><a class="reference external" href="#command-line-arguments">10.3. Command Line Arguments</a></li>
+<li><a class="reference external" href="#error-output-redirection-and-program-termination">10.4. Error Output Redirection and Program Termination</a></li>
+<li><a class="reference external" href="#string-pattern-matching">10.5. String Pattern Matching</a></li>
+<li><a class="reference external" href="#mathematics">10.6. Mathematics</a></li>
+<li><a class="reference external" href="#internet-access">10.7. Internet Access</a></li>
+<li><a class="reference external" href="#dates-and-times">10.8. Dates and Times</a></li>
+<li><a class="reference external" href="#data-compression">10.9. Data Compression</a></li>
+<li><a class="reference external" href="#performance-measurement">10.10. Performance Measurement</a></li>
+<li><a class="reference external" href="#quality-control">10.11. Quality Control</a></li>
+<li><a class="reference external" href="#batteries-included">10.12. Batteries Included</a></li>
+</ul>
+</li>
+</ul>
+
+ <h4>Previous topic</h4>
+ <p class="topless"><a href="classes.html"
+ title="previous chapter">9. Classes</a></p>
+ <h4>Next topic</h4>
+ <p class="topless"><a href="stdlib2.html"
+ title="next chapter">11. Brief Tour of the Standard Library &#8211; Part II</a></p>
+ <h3>This Page</h3>
+ <ul class="this-page-menu">
+ <li><a href="../_sources/tutorial/stdlib.txt"
+ rel="nofollow">Show Source</a></li>
+ </ul>
+ <div id="searchbox" style="display: none">
+ <h3>Quick search</h3>
+ <form class="search" action="../search.html" method="get">
+ <input type="text" name="q" size="18" />
+ <input type="submit" value="Go" />
+ <input type="hidden" name="check_keywords" value="yes" />
+ <input type="hidden" name="area" value="default" />
+ </form>
+ <p class="searchtip" style="font-size: 90%">
+ Enter search terms or a module, class or function name.
+ </p>
+ </div>
+ <script type="text/javascript">$('#searchbox').show(0);</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../genindex.html" title="General Index"
+ >index</a></li>
+ <li class="right" >
+ <a href="../modindex.html" title="Global Module Index"
+ >modules</a> |</li>
+ <li class="right" >
+ <a href="stdlib2.html" title="11. Brief Tour of the Standard Library – Part II"
+ >next</a> |</li>
+ <li class="right" >
+ <a href="classes.html" title="9. Classes"
+ >previous</a> |</li>
+ <li><img src="../_static/py.png" alt=""
+ style="vertical-align: middle; margin-top: -1px"/></li>
+ <li><a href="../index.html">Python v2.6.4c2 documentation</a> &raquo;</li>
+
+ <li><a href="index.html" >The Python Tutorial</a> &raquo;</li>
+ </ul>
+ </div>
+ <div class="footer">
+ &copy; <a href="../copyright.html">Copyright</a> 1990-2009, Python Software Foundation.
+ <br />
+ The Python Software Foundation is a non-profit corporation.
+ <a href="http://www.python.org/psf/donations/">Please donate.</a>
+ <br />
+ Last updated on Oct 19, 2009.
+ Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 0.6.2.
+ </div>
+
+ </body>
+</html> \ No newline at end of file
diff --git a/help/PythonTutorial/tutorial/stdlib2.html b/help/PythonTutorial/tutorial/stdlib2.html
new file mode 100644
index 0000000..18eb604
--- /dev/null
+++ b/help/PythonTutorial/tutorial/stdlib2.html
@@ -0,0 +1,496 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+ <title>11. Brief Tour of the Standard Library – Part II &mdash; Python v2.6.4c2 documentation</title>
+ <link rel="stylesheet" href="../_static/default.css" type="text/css" />
+ <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
+ <script type="text/javascript">
+ var DOCUMENTATION_OPTIONS = {
+ URL_ROOT: '../',
+ VERSION: '2.6.4c2',
+ COLLAPSE_MODINDEX: false,
+ FILE_SUFFIX: '.html',
+ HAS_SOURCE: true
+ };
+ </script>
+ <script type="text/javascript" src="../_static/jquery.js"></script>
+ <script type="text/javascript" src="../_static/doctools.js"></script>
+ <link rel="search" type="application/opensearchdescription+xml"
+ title="Search within Python v2.6.4c2 documentation"
+ href="../_static/opensearch.xml"/>
+ <link rel="author" title="About these documents" href="../about.html" />
+ <link rel="copyright" title="Copyright" href="../copyright.html" />
+ <link rel="top" title="Python v2.6.4c2 documentation" href="../index.html" />
+ <link rel="up" title="The Python Tutorial" href="index.html" />
+ <link rel="next" title="12. What Now?" href="whatnow.html" />
+ <link rel="prev" title="10. Brief Tour of the Standard Library" href="stdlib.html" />
+ <link rel="shortcut icon" type="image/png" href="../_static/py.png" />
+
+
+ </head>
+ <body>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../modindex.html" title="Global Module Index"
+ accesskey="M">modules</a> |</li>
+ <li class="right" >
+ <a href="whatnow.html" title="12. What Now?"
+ accesskey="N">next</a> |</li>
+ <li class="right" >
+ <a href="stdlib.html" title="10. Brief Tour of the Standard Library"
+ accesskey="P">previous</a> |</li>
+ <li><img src="../_static/py.png" alt=""
+ style="vertical-align: middle; margin-top: -1px"/></li>
+ <li><a href="../index.html">Python v2.6.4c2 documentation</a> &raquo;</li>
+
+ <li><a href="index.html" accesskey="U">The Python Tutorial</a> &raquo;</li>
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body">
+
+ <div class="section" id="brief-tour-of-the-standard-library-part-ii">
+<span id="tut-brieftourtwo"></span><h1>11. Brief Tour of the Standard Library &#8211; Part II<a class="headerlink" href="#brief-tour-of-the-standard-library-part-ii" title="Permalink to this headline">¶</a></h1>
+<p>This second tour covers more advanced modules that support professional
+programming needs. These modules rarely occur in small scripts.</p>
+<div class="section" id="output-formatting">
+<span id="tut-output-formatting"></span><h2>11.1. Output Formatting<a class="headerlink" href="#output-formatting" title="Permalink to this headline">¶</a></h2>
+<p>The <a title="Alternate repr() implementation with size limits." class="reference external" href="../library/repr.html#module-repr"><tt class="xref docutils literal"><span class="pre">repr</span></tt></a> module provides a version of <a title="repr" class="reference external" href="../library/functions.html#repr"><tt class="xref docutils literal"><span class="pre">repr()</span></tt></a> customized for
+abbreviated displays of large or deeply nested containers:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">repr</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">repr</span><span class="o">.</span><span class="n">repr</span><span class="p">(</span><span class="n">set</span><span class="p">(</span><span class="s">&#39;supercalifragilisticexpialidocious&#39;</span><span class="p">))</span>
+<span class="go">&quot;set([&#39;a&#39;, &#39;c&#39;, &#39;d&#39;, &#39;e&#39;, &#39;f&#39;, &#39;g&#39;, ...])&quot;</span>
+</pre></div>
+</div>
+<p>The <a title="Data pretty printer." class="reference external" href="../library/pprint.html#module-pprint"><tt class="xref docutils literal"><span class="pre">pprint</span></tt></a> module offers more sophisticated control over printing both
+built-in and user defined objects in a way that is readable by the interpreter.
+When the result is longer than one line, the &#8220;pretty printer&#8221; adds line breaks
+and indentation to more clearly reveal data structure:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">pprint</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">t</span> <span class="o">=</span> <span class="p">[[[[</span><span class="s">&#39;black&#39;</span><span class="p">,</span> <span class="s">&#39;cyan&#39;</span><span class="p">],</span> <span class="s">&#39;white&#39;</span><span class="p">,</span> <span class="p">[</span><span class="s">&#39;green&#39;</span><span class="p">,</span> <span class="s">&#39;red&#39;</span><span class="p">]],</span> <span class="p">[[</span><span class="s">&#39;magenta&#39;</span><span class="p">,</span>
+<span class="gp">... </span> <span class="s">&#39;yellow&#39;</span><span class="p">],</span> <span class="s">&#39;blue&#39;</span><span class="p">]]]</span>
+<span class="gp">...</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">pprint</span><span class="o">.</span><span class="n">pprint</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">width</span><span class="o">=</span><span class="mf">30</span><span class="p">)</span>
+<span class="go">[[[[&#39;black&#39;, &#39;cyan&#39;],</span>
+<span class="go"> &#39;white&#39;,</span>
+<span class="go"> [&#39;green&#39;, &#39;red&#39;]],</span>
+<span class="go"> [[&#39;magenta&#39;, &#39;yellow&#39;],</span>
+<span class="go"> &#39;blue&#39;]]]</span>
+</pre></div>
+</div>
+<p>The <a title="Text wrapping and filling" class="reference external" href="../library/textwrap.html#module-textwrap"><tt class="xref docutils literal"><span class="pre">textwrap</span></tt></a> module formats paragraphs of text to fit a given screen
+width:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">textwrap</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">doc</span> <span class="o">=</span> <span class="s">&quot;&quot;&quot;The wrap() method is just like fill() except that it returns</span>
+<span class="gp">... </span><span class="s">a list of strings instead of one big string with newlines to separate</span>
+<span class="gp">... </span><span class="s">the wrapped lines.&quot;&quot;&quot;</span>
+<span class="gp">...</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">print</span> <span class="n">textwrap</span><span class="o">.</span><span class="n">fill</span><span class="p">(</span><span class="n">doc</span><span class="p">,</span> <span class="n">width</span><span class="o">=</span><span class="mf">40</span><span class="p">)</span>
+<span class="go">The wrap() method is just like fill()</span>
+<span class="go">except that it returns a list of strings</span>
+<span class="go">instead of one big string with newlines</span>
+<span class="go">to separate the wrapped lines.</span>
+</pre></div>
+</div>
+<p>The <a title="Internationalization services." class="reference external" href="../library/locale.html#module-locale"><tt class="xref docutils literal"><span class="pre">locale</span></tt></a> module accesses a database of culture specific data formats.
+The grouping attribute of locale&#8217;s format function provides a direct way of
+formatting numbers with group separators:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">locale</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">locale</span><span class="o">.</span><span class="n">setlocale</span><span class="p">(</span><span class="n">locale</span><span class="o">.</span><span class="n">LC_ALL</span><span class="p">,</span> <span class="s">&#39;English_United States.1252&#39;</span><span class="p">)</span>
+<span class="go">&#39;English_United States.1252&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">conv</span> <span class="o">=</span> <span class="n">locale</span><span class="o">.</span><span class="n">localeconv</span><span class="p">()</span> <span class="c"># get a mapping of conventions</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">x</span> <span class="o">=</span> <span class="mf">1234567.8</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">locale</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="s">&quot;</span><span class="si">%d</span><span class="s">&quot;</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="n">grouping</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
+<span class="go">&#39;1,234,567&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">locale</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="s">&quot;</span><span class="si">%s%.*f</span><span class="s">&quot;</span><span class="p">,</span> <span class="p">(</span><span class="n">conv</span><span class="p">[</span><span class="s">&#39;currency_symbol&#39;</span><span class="p">],</span>
+<span class="gp">... </span> <span class="n">conv</span><span class="p">[</span><span class="s">&#39;frac_digits&#39;</span><span class="p">],</span> <span class="n">x</span><span class="p">),</span> <span class="n">grouping</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
+<span class="go">&#39;$1,234,567.80&#39;</span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="templating">
+<span id="tut-templating"></span><h2>11.2. Templating<a class="headerlink" href="#templating" title="Permalink to this headline">¶</a></h2>
+<p>The <a title="Common string operations." class="reference external" href="../library/string.html#module-string"><tt class="xref docutils literal"><span class="pre">string</span></tt></a> module includes a versatile <tt class="xref docutils literal"><span class="pre">Template</span></tt> class with a
+simplified syntax suitable for editing by end-users. This allows users to
+customize their applications without having to alter the application.</p>
+<p>The format uses placeholder names formed by <tt class="docutils literal"><span class="pre">$</span></tt> with valid Python identifiers
+(alphanumeric characters and underscores). Surrounding the placeholder with
+braces allows it to be followed by more alphanumeric letters with no intervening
+spaces. Writing <tt class="docutils literal"><span class="pre">$$</span></tt> creates a single escaped <tt class="docutils literal"><span class="pre">$</span></tt>:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">string</span> <span class="kn">import</span> <span class="n">Template</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">t</span> <span class="o">=</span> <span class="n">Template</span><span class="p">(</span><span class="s">&#39;${village}folk send $$10 to $cause.&#39;</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">t</span><span class="o">.</span><span class="n">substitute</span><span class="p">(</span><span class="n">village</span><span class="o">=</span><span class="s">&#39;Nottingham&#39;</span><span class="p">,</span> <span class="n">cause</span><span class="o">=</span><span class="s">&#39;the ditch fund&#39;</span><span class="p">)</span>
+<span class="go">&#39;Nottinghamfolk send $10 to the ditch fund.&#39;</span>
+</pre></div>
+</div>
+<p>The <tt class="xref docutils literal"><span class="pre">substitute()</span></tt> method raises a <a title="exceptions.KeyError" class="reference external" href="../library/exceptions.html#exceptions.KeyError"><tt class="xref docutils literal"><span class="pre">KeyError</span></tt></a> when a placeholder is not
+supplied in a dictionary or a keyword argument. For mail-merge style
+applications, user supplied data may be incomplete and the
+<tt class="xref docutils literal"><span class="pre">safe_substitute()</span></tt> method may be more appropriate &#8212; it will leave
+placeholders unchanged if data is missing:</p>
+<div class="highlight-python"><pre>&gt;&gt;&gt; t = Template('Return the $item to $owner.')
+&gt;&gt;&gt; d = dict(item='unladen swallow')
+&gt;&gt;&gt; t.substitute(d)
+Traceback (most recent call last):
+ . . .
+KeyError: 'owner'
+&gt;&gt;&gt; t.safe_substitute(d)
+'Return the unladen swallow to $owner.'</pre>
+</div>
+<p>Template subclasses can specify a custom delimiter. For example, a batch
+renaming utility for a photo browser may elect to use percent signs for
+placeholders such as the current date, image sequence number, or file format:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">time</span><span class="o">,</span> <span class="nn">os.path</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">photofiles</span> <span class="o">=</span> <span class="p">[</span><span class="s">&#39;img_1074.jpg&#39;</span><span class="p">,</span> <span class="s">&#39;img_1076.jpg&#39;</span><span class="p">,</span> <span class="s">&#39;img_1077.jpg&#39;</span><span class="p">]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">class</span> <span class="nc">BatchRename</span><span class="p">(</span><span class="n">Template</span><span class="p">):</span>
+<span class="gp">... </span> <span class="n">delimiter</span> <span class="o">=</span> <span class="s">&#39;%&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">fmt</span> <span class="o">=</span> <span class="nb">raw_input</span><span class="p">(</span><span class="s">&#39;Enter rename style (</span><span class="si">%d</span><span class="s">-date %n-seqnum </span><span class="si">%f</span><span class="s">-format): &#39;</span><span class="p">)</span>
+<span class="go">Enter rename style (%d-date %n-seqnum %f-format): Ashley_%n%f</span>
+
+<span class="gp">&gt;&gt;&gt; </span><span class="n">t</span> <span class="o">=</span> <span class="n">BatchRename</span><span class="p">(</span><span class="n">fmt</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">date</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s">&#39;</span><span class="si">%d</span><span class="s">%b%y&#39;</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">filename</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">photofiles</span><span class="p">):</span>
+<span class="gp">... </span> <span class="n">base</span><span class="p">,</span> <span class="n">ext</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">splitext</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>
+<span class="gp">... </span> <span class="n">newname</span> <span class="o">=</span> <span class="n">t</span><span class="o">.</span><span class="n">substitute</span><span class="p">(</span><span class="n">d</span><span class="o">=</span><span class="n">date</span><span class="p">,</span> <span class="n">n</span><span class="o">=</span><span class="n">i</span><span class="p">,</span> <span class="n">f</span><span class="o">=</span><span class="n">ext</span><span class="p">)</span>
+<span class="gp">... </span> <span class="k">print</span> <span class="s">&#39;{0} --&gt; {1}&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="n">newname</span><span class="p">)</span>
+
+<span class="go">img_1074.jpg --&gt; Ashley_0.jpg</span>
+<span class="go">img_1076.jpg --&gt; Ashley_1.jpg</span>
+<span class="go">img_1077.jpg --&gt; Ashley_2.jpg</span>
+</pre></div>
+</div>
+<p>Another application for templating is separating program logic from the details
+of multiple output formats. This makes it possible to substitute custom
+templates for XML files, plain text reports, and HTML web reports.</p>
+</div>
+<div class="section" id="working-with-binary-data-record-layouts">
+<span id="tut-binary-formats"></span><h2>11.3. Working with Binary Data Record Layouts<a class="headerlink" href="#working-with-binary-data-record-layouts" title="Permalink to this headline">¶</a></h2>
+<p>The <a title="Interpret strings as packed binary data." class="reference external" href="../library/struct.html#module-struct"><tt class="xref docutils literal"><span class="pre">struct</span></tt></a> module provides <tt class="xref docutils literal"><span class="pre">pack()</span></tt> and <tt class="xref docutils literal"><span class="pre">unpack()</span></tt> functions for
+working with variable length binary record formats. The following example shows
+how to loop through header information in a ZIP file without using the
+<a title="Read and write ZIP-format archive files." class="reference external" href="../library/zipfile.html#module-zipfile"><tt class="xref docutils literal"><span class="pre">zipfile</span></tt></a> module. Pack codes <tt class="docutils literal"><span class="pre">&quot;H&quot;</span></tt> and <tt class="docutils literal"><span class="pre">&quot;I&quot;</span></tt> represent two and four
+byte unsigned numbers respectively. The <tt class="docutils literal"><span class="pre">&quot;&lt;&quot;</span></tt> indicates that they are
+standard size and in little-endian byte order:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">struct</span>
+
+<span class="n">data</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="s">&#39;myfile.zip&#39;</span><span class="p">,</span> <span class="s">&#39;rb&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
+<span class="n">start</span> <span class="o">=</span> <span class="mf">0</span>
+<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mf">3</span><span class="p">):</span> <span class="c"># show the first 3 file headers</span>
+ <span class="n">start</span> <span class="o">+=</span> <span class="mf">14</span>
+ <span class="n">fields</span> <span class="o">=</span> <span class="n">struct</span><span class="o">.</span><span class="n">unpack</span><span class="p">(</span><span class="s">&#39;&lt;IIIHH&#39;</span><span class="p">,</span> <span class="n">data</span><span class="p">[</span><span class="n">start</span><span class="p">:</span><span class="n">start</span><span class="o">+</span><span class="mf">16</span><span class="p">])</span>
+ <span class="n">crc32</span><span class="p">,</span> <span class="n">comp_size</span><span class="p">,</span> <span class="n">uncomp_size</span><span class="p">,</span> <span class="n">filenamesize</span><span class="p">,</span> <span class="n">extra_size</span> <span class="o">=</span> <span class="n">fields</span>
+
+ <span class="n">start</span> <span class="o">+=</span> <span class="mf">16</span>
+ <span class="n">filename</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="n">start</span><span class="p">:</span><span class="n">start</span><span class="o">+</span><span class="n">filenamesize</span><span class="p">]</span>
+ <span class="n">start</span> <span class="o">+=</span> <span class="n">filenamesize</span>
+ <span class="n">extra</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="n">start</span><span class="p">:</span><span class="n">start</span><span class="o">+</span><span class="n">extra_size</span><span class="p">]</span>
+ <span class="k">print</span> <span class="n">filename</span><span class="p">,</span> <span class="nb">hex</span><span class="p">(</span><span class="n">crc32</span><span class="p">),</span> <span class="n">comp_size</span><span class="p">,</span> <span class="n">uncomp_size</span>
+
+ <span class="n">start</span> <span class="o">+=</span> <span class="n">extra_size</span> <span class="o">+</span> <span class="n">comp_size</span> <span class="c"># skip to the next header</span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="multi-threading">
+<span id="tut-multi-threading"></span><h2>11.4. Multi-threading<a class="headerlink" href="#multi-threading" title="Permalink to this headline">¶</a></h2>
+<p>Threading is a technique for decoupling tasks which are not sequentially
+dependent. Threads can be used to improve the responsiveness of applications
+that accept user input while other tasks run in the background. A related use
+case is running I/O in parallel with computations in another thread.</p>
+<p>The following code shows how the high level <a title="Higher-level threading interface." class="reference external" href="../library/threading.html#module-threading"><tt class="xref docutils literal"><span class="pre">threading</span></tt></a> module can run
+tasks in background while the main program continues to run:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">threading</span><span class="o">,</span> <span class="nn">zipfile</span>
+
+<span class="k">class</span> <span class="nc">AsyncZip</span><span class="p">(</span><span class="n">threading</span><span class="o">.</span><span class="n">Thread</span><span class="p">):</span>
+ <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">infile</span><span class="p">,</span> <span class="n">outfile</span><span class="p">):</span>
+ <span class="n">threading</span><span class="o">.</span><span class="n">Thread</span><span class="o">.</span><span class="n">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
+ <span class="bp">self</span><span class="o">.</span><span class="n">infile</span> <span class="o">=</span> <span class="n">infile</span>
+ <span class="bp">self</span><span class="o">.</span><span class="n">outfile</span> <span class="o">=</span> <span class="n">outfile</span>
+ <span class="k">def</span> <span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+ <span class="n">f</span> <span class="o">=</span> <span class="n">zipfile</span><span class="o">.</span><span class="n">ZipFile</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">outfile</span><span class="p">,</span> <span class="s">&#39;w&#39;</span><span class="p">,</span> <span class="n">zipfile</span><span class="o">.</span><span class="n">ZIP_DEFLATED</span><span class="p">)</span>
+ <span class="n">f</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">infile</span><span class="p">)</span>
+ <span class="n">f</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
+ <span class="k">print</span> <span class="s">&#39;Finished background zip of: &#39;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">infile</span>
+
+<span class="n">background</span> <span class="o">=</span> <span class="n">AsyncZip</span><span class="p">(</span><span class="s">&#39;mydata.txt&#39;</span><span class="p">,</span> <span class="s">&#39;myarchive.zip&#39;</span><span class="p">)</span>
+<span class="n">background</span><span class="o">.</span><span class="n">start</span><span class="p">()</span>
+<span class="k">print</span> <span class="s">&#39;The main program continues to run in foreground.&#39;</span>
+
+<span class="n">background</span><span class="o">.</span><span class="n">join</span><span class="p">()</span> <span class="c"># Wait for the background task to finish</span>
+<span class="k">print</span> <span class="s">&#39;Main program waited until background was done.&#39;</span>
+</pre></div>
+</div>
+<p>The principal challenge of multi-threaded applications is coordinating threads
+that share data or other resources. To that end, the threading module provides
+a number of synchronization primitives including locks, events, condition
+variables, and semaphores.</p>
+<p>While those tools are powerful, minor design errors can result in problems that
+are difficult to reproduce. So, the preferred approach to task coordination is
+to concentrate all access to a resource in a single thread and then use the
+<a title="A synchronized queue class." class="reference external" href="../library/queue.html#module-Queue"><tt class="xref docutils literal"><span class="pre">Queue</span></tt></a> module to feed that thread with requests from other threads.
+Applications using <a title="Queue.Queue" class="reference external" href="../library/queue.html#Queue.Queue"><tt class="xref docutils literal"><span class="pre">Queue.Queue</span></tt></a> objects for inter-thread communication
+and coordination are easier to design, more readable, and more reliable.</p>
+</div>
+<div class="section" id="logging">
+<span id="tut-logging"></span><h2>11.5. Logging<a class="headerlink" href="#logging" title="Permalink to this headline">¶</a></h2>
+<p>The <a title="Flexible error logging system for applications." class="reference external" href="../library/logging.html#module-logging"><tt class="xref docutils literal"><span class="pre">logging</span></tt></a> module offers a full featured and flexible logging system.
+At its simplest, log messages are sent to a file or to <tt class="docutils literal"><span class="pre">sys.stderr</span></tt>:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">logging</span>
+<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s">&#39;Debugging information&#39;</span><span class="p">)</span>
+<span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s">&#39;Informational message&#39;</span><span class="p">)</span>
+<span class="n">logging</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="s">&#39;Warning:config file </span><span class="si">%s</span><span class="s"> not found&#39;</span><span class="p">,</span> <span class="s">&#39;server.conf&#39;</span><span class="p">)</span>
+<span class="n">logging</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="s">&#39;Error occurred&#39;</span><span class="p">)</span>
+<span class="n">logging</span><span class="o">.</span><span class="n">critical</span><span class="p">(</span><span class="s">&#39;Critical error -- shutting down&#39;</span><span class="p">)</span>
+</pre></div>
+</div>
+<p>This produces the following output:</p>
+<div class="highlight-python"><pre>WARNING:root:Warning:config file server.conf not found
+ERROR:root:Error occurred
+CRITICAL:root:Critical error -- shutting down</pre>
+</div>
+<p>By default, informational and debugging messages are suppressed and the output
+is sent to standard error. Other output options include routing messages
+through email, datagrams, sockets, or to an HTTP Server. New filters can select
+different routing based on message priority: <tt class="xref docutils literal"><span class="pre">DEBUG</span></tt>, <tt class="xref docutils literal"><span class="pre">INFO</span></tt>,
+<tt class="xref docutils literal"><span class="pre">WARNING</span></tt>, <tt class="xref docutils literal"><span class="pre">ERROR</span></tt>, and <tt class="xref docutils literal"><span class="pre">CRITICAL</span></tt>.</p>
+<p>The logging system can be configured directly from Python or can be loaded from
+a user editable configuration file for customized logging without altering the
+application.</p>
+</div>
+<div class="section" id="weak-references">
+<span id="tut-weak-references"></span><h2>11.6. Weak References<a class="headerlink" href="#weak-references" title="Permalink to this headline">¶</a></h2>
+<p>Python does automatic memory management (reference counting for most objects and
+<a class="reference external" href="../glossary.html#term-garbage-collection"><em class="xref">garbage collection</em></a> to eliminate cycles). The memory is freed shortly
+after the last reference to it has been eliminated.</p>
+<p>This approach works fine for most applications but occasionally there is a need
+to track objects only as long as they are being used by something else.
+Unfortunately, just tracking them creates a reference that makes them permanent.
+The <a title="Support for weak references and weak dictionaries." class="reference external" href="../library/weakref.html#module-weakref"><tt class="xref docutils literal"><span class="pre">weakref</span></tt></a> module provides tools for tracking objects without creating a
+reference. When the object is no longer needed, it is automatically removed
+from a weakref table and a callback is triggered for weakref objects. Typical
+applications include caching objects that are expensive to create:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">weakref</span><span class="o">,</span> <span class="nn">gc</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">class</span> <span class="nc">A</span><span class="p">:</span>
+<span class="gp">... </span> <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
+<span class="gp">... </span> <span class="bp">self</span><span class="o">.</span><span class="n">value</span> <span class="o">=</span> <span class="n">value</span>
+<span class="gp">... </span> <span class="k">def</span> <span class="nf">__repr__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+<span class="gp">... </span> <span class="k">return</span> <span class="nb">str</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">value</span><span class="p">)</span>
+<span class="gp">...</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">a</span> <span class="o">=</span> <span class="n">A</span><span class="p">(</span><span class="mf">10</span><span class="p">)</span> <span class="c"># create a reference</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">d</span> <span class="o">=</span> <span class="n">weakref</span><span class="o">.</span><span class="n">WeakValueDictionary</span><span class="p">()</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">d</span><span class="p">[</span><span class="s">&#39;primary&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">a</span> <span class="c"># does not create a reference</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">d</span><span class="p">[</span><span class="s">&#39;primary&#39;</span><span class="p">]</span> <span class="c"># fetch the object if it is still alive</span>
+<span class="go">10</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">del</span> <span class="n">a</span> <span class="c"># remove the one reference</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">gc</span><span class="o">.</span><span class="n">collect</span><span class="p">()</span> <span class="c"># run garbage collection right away</span>
+<span class="go">0</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">d</span><span class="p">[</span><span class="s">&#39;primary&#39;</span><span class="p">]</span> <span class="c"># entry was automatically removed</span>
+<span class="gt">Traceback (most recent call last):</span>
+ File <span class="nb">&quot;&lt;stdin&gt;&quot;</span>, line <span class="m">1</span>, in <span class="n-Identifier">&lt;module&gt;</span>
+ <span class="n">d</span><span class="p">[</span><span class="s">&#39;primary&#39;</span><span class="p">]</span> <span class="c"># entry was automatically removed</span>
+ File <span class="nb">&quot;C:/python26/lib/weakref.py&quot;</span>, line <span class="m">46</span>, in <span class="n-Identifier">__getitem__</span>
+ <span class="n">o</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">data</span><span class="p">[</span><span class="n">key</span><span class="p">]()</span>
+<span class="nc">KeyError</span>: <span class="n-Identifier">&#39;primary&#39;</span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="tools-for-working-with-lists">
+<span id="tut-list-tools"></span><h2>11.7. Tools for Working with Lists<a class="headerlink" href="#tools-for-working-with-lists" title="Permalink to this headline">¶</a></h2>
+<p>Many data structure needs can be met with the built-in list type. However,
+sometimes there is a need for alternative implementations with different
+performance trade-offs.</p>
+<p>The <a title="Space efficient arrays of uniformly typed numeric values." class="reference external" href="../library/array.html#module-array"><tt class="xref docutils literal"><span class="pre">array</span></tt></a> module provides an <tt class="xref docutils literal"><span class="pre">array()</span></tt> object that is like a list
+that stores only homogeneous data and stores it more compactly. The following
+example shows an array of numbers stored as two byte unsigned binary numbers
+(typecode <tt class="docutils literal"><span class="pre">&quot;H&quot;</span></tt>) rather than the usual 16 bytes per entry for regular lists of
+python int objects:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">array</span> <span class="kn">import</span> <span class="n">array</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">a</span> <span class="o">=</span> <span class="n">array</span><span class="p">(</span><span class="s">&#39;H&#39;</span><span class="p">,</span> <span class="p">[</span><span class="mf">4000</span><span class="p">,</span> <span class="mf">10</span><span class="p">,</span> <span class="mf">700</span><span class="p">,</span> <span class="mf">22222</span><span class="p">])</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">sum</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
+<span class="go">26932</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">a</span><span class="p">[</span><span class="mf">1</span><span class="p">:</span><span class="mf">3</span><span class="p">]</span>
+<span class="go">array(&#39;H&#39;, [10, 700])</span>
+</pre></div>
+</div>
+<p>The <a title="High-performance datatypes" class="reference external" href="../library/collections.html#module-collections"><tt class="xref docutils literal"><span class="pre">collections</span></tt></a> module provides a <tt class="xref docutils literal"><span class="pre">deque()</span></tt> object that is like a
+list with faster appends and pops from the left side but slower lookups in the
+middle. These objects are well suited for implementing queues and breadth first
+tree searches:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">collections</span> <span class="kn">import</span> <span class="n">deque</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">d</span> <span class="o">=</span> <span class="n">deque</span><span class="p">([</span><span class="s">&quot;task1&quot;</span><span class="p">,</span> <span class="s">&quot;task2&quot;</span><span class="p">,</span> <span class="s">&quot;task3&quot;</span><span class="p">])</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">d</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s">&quot;task4&quot;</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="k">print</span> <span class="s">&quot;Handling&quot;</span><span class="p">,</span> <span class="n">d</span><span class="o">.</span><span class="n">popleft</span><span class="p">()</span>
+<span class="go">Handling task1</span>
+
+<span class="go">unsearched = deque([starting_node])</span>
+<span class="go">def breadth_first_search(unsearched):</span>
+<span class="go"> node = unsearched.popleft()</span>
+<span class="go"> for m in gen_moves(node):</span>
+<span class="go"> if is_goal(m):</span>
+<span class="go"> return m</span>
+<span class="go"> unsearched.append(m)</span>
+</pre></div>
+</div>
+<p>In addition to alternative list implementations, the library also offers other
+tools such as the <a title="Array bisection algorithms for binary searching." class="reference external" href="../library/bisect.html#module-bisect"><tt class="xref docutils literal"><span class="pre">bisect</span></tt></a> module with functions for manipulating sorted
+lists:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">bisect</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">scores</span> <span class="o">=</span> <span class="p">[(</span><span class="mf">100</span><span class="p">,</span> <span class="s">&#39;perl&#39;</span><span class="p">),</span> <span class="p">(</span><span class="mf">200</span><span class="p">,</span> <span class="s">&#39;tcl&#39;</span><span class="p">),</span> <span class="p">(</span><span class="mf">400</span><span class="p">,</span> <span class="s">&#39;lua&#39;</span><span class="p">),</span> <span class="p">(</span><span class="mf">500</span><span class="p">,</span> <span class="s">&#39;python&#39;</span><span class="p">)]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">bisect</span><span class="o">.</span><span class="n">insort</span><span class="p">(</span><span class="n">scores</span><span class="p">,</span> <span class="p">(</span><span class="mf">300</span><span class="p">,</span> <span class="s">&#39;ruby&#39;</span><span class="p">))</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">scores</span>
+<span class="go">[(100, &#39;perl&#39;), (200, &#39;tcl&#39;), (300, &#39;ruby&#39;), (400, &#39;lua&#39;), (500, &#39;python&#39;)]</span>
+</pre></div>
+</div>
+<p>The <a title="Heap queue algorithm (a.k.a. priority queue)." class="reference external" href="../library/heapq.html#module-heapq"><tt class="xref docutils literal"><span class="pre">heapq</span></tt></a> module provides functions for implementing heaps based on
+regular lists. The lowest valued entry is always kept at position zero. This
+is useful for applications which repeatedly access the smallest element but do
+not want to run a full list sort:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">heapq</span> <span class="kn">import</span> <span class="n">heapify</span><span class="p">,</span> <span class="n">heappop</span><span class="p">,</span> <span class="n">heappush</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">data</span> <span class="o">=</span> <span class="p">[</span><span class="mf">1</span><span class="p">,</span> <span class="mf">3</span><span class="p">,</span> <span class="mf">5</span><span class="p">,</span> <span class="mf">7</span><span class="p">,</span> <span class="mf">9</span><span class="p">,</span> <span class="mf">2</span><span class="p">,</span> <span class="mf">4</span><span class="p">,</span> <span class="mf">6</span><span class="p">,</span> <span class="mf">8</span><span class="p">,</span> <span class="mf">0</span><span class="p">]</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">heapify</span><span class="p">(</span><span class="n">data</span><span class="p">)</span> <span class="c"># rearrange the list into heap order</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">heappush</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="o">-</span><span class="mf">5</span><span class="p">)</span> <span class="c"># add a new entry</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="p">[</span><span class="n">heappop</span><span class="p">(</span><span class="n">data</span><span class="p">)</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mf">3</span><span class="p">)]</span> <span class="c"># fetch the three smallest entries</span>
+<span class="go">[-5, 0, 1]</span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="decimal-floating-point-arithmetic">
+<span id="tut-decimal-fp"></span><h2>11.8. Decimal Floating Point Arithmetic<a class="headerlink" href="#decimal-floating-point-arithmetic" title="Permalink to this headline">¶</a></h2>
+<p>The <a title="Implementation of the General Decimal Arithmetic Specification." class="reference external" href="../library/decimal.html#module-decimal"><tt class="xref docutils literal"><span class="pre">decimal</span></tt></a> module offers a <tt class="xref docutils literal"><span class="pre">Decimal</span></tt> datatype for decimal
+floating point arithmetic. Compared to the built-in <a title="float" class="reference external" href="../library/functions.html#float"><tt class="xref docutils literal"><span class="pre">float</span></tt></a>
+implementation of binary floating point, the new class is especially helpful for
+financial applications and other uses which require exact decimal
+representation, control over precision, control over rounding to meet legal or
+regulatory requirements, tracking of significant decimal places, or for
+applications where the user expects the results to match calculations done by
+hand.</p>
+<p>For example, calculating a 5% tax on a 70 cent phone charge gives different
+results in decimal floating point and binary floating point. The difference
+becomes significant if the results are rounded to the nearest cent:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">decimal</span> <span class="kn">import</span> <span class="o">*</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">Decimal</span><span class="p">(</span><span class="s">&#39;0.70&#39;</span><span class="p">)</span> <span class="o">*</span> <span class="n">Decimal</span><span class="p">(</span><span class="s">&#39;1.05&#39;</span><span class="p">)</span>
+<span class="go">Decimal(&#39;0.7350&#39;)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="o">.</span><span class="mf">70</span> <span class="o">*</span> <span class="mf">1.05</span>
+<span class="go">0.73499999999999999</span>
+</pre></div>
+</div>
+<p>The <tt class="xref docutils literal"><span class="pre">Decimal</span></tt> result keeps a trailing zero, automatically inferring four
+place significance from multiplicands with two place significance. Decimal
+reproduces mathematics as done by hand and avoids issues that can arise when
+binary floating point cannot exactly represent decimal quantities.</p>
+<p>Exact representation enables the <tt class="xref docutils literal"><span class="pre">Decimal</span></tt> class to perform modulo
+calculations and equality tests that are unsuitable for binary floating point:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">Decimal</span><span class="p">(</span><span class="s">&#39;1.00&#39;</span><span class="p">)</span> <span class="o">%</span> <span class="n">Decimal</span><span class="p">(</span><span class="s">&#39;.10&#39;</span><span class="p">)</span>
+<span class="go">Decimal(&#39;0.00&#39;)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="mf">1.00</span> <span class="o">%</span> <span class="mf">0.10</span>
+<span class="go">0.09999999999999995</span>
+
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">sum</span><span class="p">([</span><span class="n">Decimal</span><span class="p">(</span><span class="s">&#39;0.1&#39;</span><span class="p">)]</span><span class="o">*</span><span class="mf">10</span><span class="p">)</span> <span class="o">==</span> <span class="n">Decimal</span><span class="p">(</span><span class="s">&#39;1.0&#39;</span><span class="p">)</span>
+<span class="go">True</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="nb">sum</span><span class="p">([</span><span class="mf">0.1</span><span class="p">]</span><span class="o">*</span><span class="mf">10</span><span class="p">)</span> <span class="o">==</span> <span class="mf">1.0</span>
+<span class="go">False</span>
+</pre></div>
+</div>
+<p>The <a title="Implementation of the General Decimal Arithmetic Specification." class="reference external" href="../library/decimal.html#module-decimal"><tt class="xref docutils literal"><span class="pre">decimal</span></tt></a> module provides arithmetic with as much precision as needed:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">getcontext</span><span class="p">()</span><span class="o">.</span><span class="n">prec</span> <span class="o">=</span> <span class="mf">36</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">Decimal</span><span class="p">(</span><span class="mf">1</span><span class="p">)</span> <span class="o">/</span> <span class="n">Decimal</span><span class="p">(</span><span class="mf">7</span><span class="p">)</span>
+<span class="go">Decimal(&#39;0.142857142857142857142857142857142857&#39;)</span>
+</pre></div>
+</div>
+</div>
+</div>
+
+
+ </div>
+ </div>
+ </div>
+ <div class="sphinxsidebar">
+ <div class="sphinxsidebarwrapper">
+ <h3><a href="../contents.html">Table Of Contents</a></h3>
+ <ul>
+<li><a class="reference external" href="">11. Brief Tour of the Standard Library &#8211; Part II</a><ul>
+<li><a class="reference external" href="#output-formatting">11.1. Output Formatting</a></li>
+<li><a class="reference external" href="#templating">11.2. Templating</a></li>
+<li><a class="reference external" href="#working-with-binary-data-record-layouts">11.3. Working with Binary Data Record Layouts</a></li>
+<li><a class="reference external" href="#multi-threading">11.4. Multi-threading</a></li>
+<li><a class="reference external" href="#logging">11.5. Logging</a></li>
+<li><a class="reference external" href="#weak-references">11.6. Weak References</a></li>
+<li><a class="reference external" href="#tools-for-working-with-lists">11.7. Tools for Working with Lists</a></li>
+<li><a class="reference external" href="#decimal-floating-point-arithmetic">11.8. Decimal Floating Point Arithmetic</a></li>
+</ul>
+</li>
+</ul>
+
+ <h4>Previous topic</h4>
+ <p class="topless"><a href="stdlib.html"
+ title="previous chapter">10. Brief Tour of the Standard Library</a></p>
+ <h4>Next topic</h4>
+ <p class="topless"><a href="whatnow.html"
+ title="next chapter">12. What Now?</a></p>
+ <h3>This Page</h3>
+ <ul class="this-page-menu">
+ <li><a href="../_sources/tutorial/stdlib2.txt"
+ rel="nofollow">Show Source</a></li>
+ </ul>
+ <div id="searchbox" style="display: none">
+ <h3>Quick search</h3>
+ <form class="search" action="../search.html" method="get">
+ <input type="text" name="q" size="18" />
+ <input type="submit" value="Go" />
+ <input type="hidden" name="check_keywords" value="yes" />
+ <input type="hidden" name="area" value="default" />
+ </form>
+ <p class="searchtip" style="font-size: 90%">
+ Enter search terms or a module, class or function name.
+ </p>
+ </div>
+ <script type="text/javascript">$('#searchbox').show(0);</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../genindex.html" title="General Index"
+ >index</a></li>
+ <li class="right" >
+ <a href="../modindex.html" title="Global Module Index"
+ >modules</a> |</li>
+ <li class="right" >
+ <a href="whatnow.html" title="12. What Now?"
+ >next</a> |</li>
+ <li class="right" >
+ <a href="stdlib.html" title="10. Brief Tour of the Standard Library"
+ >previous</a> |</li>
+ <li><img src="../_static/py.png" alt=""
+ style="vertical-align: middle; margin-top: -1px"/></li>
+ <li><a href="../index.html">Python v2.6.4c2 documentation</a> &raquo;</li>
+
+ <li><a href="index.html" >The Python Tutorial</a> &raquo;</li>
+ </ul>
+ </div>
+ <div class="footer">
+ &copy; <a href="../copyright.html">Copyright</a> 1990-2009, Python Software Foundation.
+ <br />
+ The Python Software Foundation is a non-profit corporation.
+ <a href="http://www.python.org/psf/donations/">Please donate.</a>
+ <br />
+ Last updated on Oct 19, 2009.
+ Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 0.6.2.
+ </div>
+
+ </body>
+</html> \ No newline at end of file
diff --git a/help/PythonTutorial/tutorial/whatnow.html b/help/PythonTutorial/tutorial/whatnow.html
new file mode 100644
index 0000000..d1986d4
--- /dev/null
+++ b/help/PythonTutorial/tutorial/whatnow.html
@@ -0,0 +1,186 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+ <title>12. What Now? &mdash; Python v2.6.4c2 documentation</title>
+ <link rel="stylesheet" href="../_static/default.css" type="text/css" />
+ <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
+ <script type="text/javascript">
+ var DOCUMENTATION_OPTIONS = {
+ URL_ROOT: '../',
+ VERSION: '2.6.4c2',
+ COLLAPSE_MODINDEX: false,
+ FILE_SUFFIX: '.html',
+ HAS_SOURCE: true
+ };
+ </script>
+ <script type="text/javascript" src="../_static/jquery.js"></script>
+ <script type="text/javascript" src="../_static/doctools.js"></script>
+ <link rel="search" type="application/opensearchdescription+xml"
+ title="Search within Python v2.6.4c2 documentation"
+ href="../_static/opensearch.xml"/>
+ <link rel="author" title="About these documents" href="../about.html" />
+ <link rel="copyright" title="Copyright" href="../copyright.html" />
+ <link rel="top" title="Python v2.6.4c2 documentation" href="../index.html" />
+ <link rel="up" title="The Python Tutorial" href="index.html" />
+ <link rel="next" title="13. Interactive Input Editing and History Substitution" href="interactive.html" />
+ <link rel="prev" title="11. Brief Tour of the Standard Library – Part II" href="stdlib2.html" />
+ <link rel="shortcut icon" type="image/png" href="../_static/py.png" />
+
+
+ </head>
+ <body>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../modindex.html" title="Global Module Index"
+ accesskey="M">modules</a> |</li>
+ <li class="right" >
+ <a href="interactive.html" title="13. Interactive Input Editing and History Substitution"
+ accesskey="N">next</a> |</li>
+ <li class="right" >
+ <a href="stdlib2.html" title="11. Brief Tour of the Standard Library – Part II"
+ accesskey="P">previous</a> |</li>
+ <li><img src="../_static/py.png" alt=""
+ style="vertical-align: middle; margin-top: -1px"/></li>
+ <li><a href="../index.html">Python v2.6.4c2 documentation</a> &raquo;</li>
+
+ <li><a href="index.html" accesskey="U">The Python Tutorial</a> &raquo;</li>
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body">
+
+ <div class="section" id="what-now">
+<span id="tut-whatnow"></span><h1>12. What Now?<a class="headerlink" href="#what-now" title="Permalink to this headline">¶</a></h1>
+<p>Reading this tutorial has probably reinforced your interest in using Python &#8212;
+you should be eager to apply Python to solving your real-world problems. Where
+should you go to learn more?</p>
+<p>This tutorial is part of Python&#8217;s documentation set. Some other documents in
+the set are:</p>
+<ul>
+<li><p class="first"><a class="reference external" href="../library/index.html#library-index"><em>The Python Standard Library</em></a>:</p>
+<p>You should browse through this manual, which gives complete (though terse)
+reference material about types, functions, and the modules in the standard
+library. The standard Python distribution includes a <em>lot</em> of additional code.
+There are modules to read Unix mailboxes, retrieve documents via HTTP, generate
+random numbers, parse command-line options, write CGI programs, compress data,
+and many other tasks. Skimming through the Library Reference will give you an
+idea of what&#8217;s available.</p>
+</li>
+<li><p class="first"><a class="reference external" href="../install/index.html#install-index"><em>Installing Python Modules</em></a> explains how to install external modules written by other
+Python users.</p>
+</li>
+<li><p class="first"><a class="reference external" href="../reference/index.html#reference-index"><em>The Python Language Reference</em></a>: A detailed explanation of Python&#8217;s syntax and
+semantics. It&#8217;s heavy reading, but is useful as a complete guide to the
+language itself.</p>
+</li>
+</ul>
+<p>More Python resources:</p>
+<ul class="simple">
+<li><a class="reference external" href="http://www.python.org">http://www.python.org</a>: The major Python Web site. It contains code,
+documentation, and pointers to Python-related pages around the Web. This Web
+site is mirrored in various places around the world, such as Europe, Japan, and
+Australia; a mirror may be faster than the main site, depending on your
+geographical location.</li>
+<li><a class="reference external" href="http://docs.python.org">http://docs.python.org</a>: Fast access to Python&#8217;s documentation.</li>
+<li><a class="reference external" href="http://pypi.python.org">http://pypi.python.org</a>: The Python Package Index, previously also nicknamed
+the Cheese Shop, is an index of user-created Python modules that are available
+for download. Once you begin releasing code, you can register it here so that
+others can find it.</li>
+<li><a class="reference external" href="http://aspn.activestate.com/ASPN/Python/Cookbook/">http://aspn.activestate.com/ASPN/Python/Cookbook/</a>: The Python Cookbook is a
+sizable collection of code examples, larger modules, and useful scripts.
+Particularly notable contributions are collected in a book also titled Python
+Cookbook (O&#8217;Reilly &amp; Associates, ISBN 0-596-00797-3.)</li>
+</ul>
+<p>For Python-related questions and problem reports, you can post to the newsgroup
+<em>comp.lang.python</em>, or send them to the mailing list at
+<a class="reference external" href="mailto:python-list&#37;&#52;&#48;python&#46;org">python-list<span>&#64;</span>python<span>&#46;</span>org</a>. The newsgroup and mailing list are gatewayed, so
+messages posted to one will automatically be forwarded to the other. There are
+around 120 postings a day (with peaks up to several hundred), asking (and
+answering) questions, suggesting new features, and announcing new modules.
+Before posting, be sure to check the list of <a class="reference external" href="http://www.python.org/doc/faq/">Frequently Asked Questions</a> (also called the FAQ), or look for it in the
+<tt class="docutils literal"><span class="pre">Misc/</span></tt> directory of the Python source distribution. Mailing list
+archives are available at <a class="reference external" href="http://mail.python.org/pipermail/">http://mail.python.org/pipermail/</a>. The FAQ answers
+many of the questions that come up again and again, and may already contain the
+solution for your problem.</p>
+</div>
+
+
+ </div>
+ </div>
+ </div>
+ <div class="sphinxsidebar">
+ <div class="sphinxsidebarwrapper">
+ <h4>Previous topic</h4>
+ <p class="topless"><a href="stdlib2.html"
+ title="previous chapter">11. Brief Tour of the Standard Library &#8211; Part II</a></p>
+ <h4>Next topic</h4>
+ <p class="topless"><a href="interactive.html"
+ title="next chapter">13. Interactive Input Editing and History Substitution</a></p>
+ <h3>This Page</h3>
+ <ul class="this-page-menu">
+ <li><a href="../_sources/tutorial/whatnow.txt"
+ rel="nofollow">Show Source</a></li>
+ </ul>
+ <div id="searchbox" style="display: none">
+ <h3>Quick search</h3>
+ <form class="search" action="../search.html" method="get">
+ <input type="text" name="q" size="18" />
+ <input type="submit" value="Go" />
+ <input type="hidden" name="check_keywords" value="yes" />
+ <input type="hidden" name="area" value="default" />
+ </form>
+ <p class="searchtip" style="font-size: 90%">
+ Enter search terms or a module, class or function name.
+ </p>
+ </div>
+ <script type="text/javascript">$('#searchbox').show(0);</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../genindex.html" title="General Index"
+ >index</a></li>
+ <li class="right" >
+ <a href="../modindex.html" title="Global Module Index"
+ >modules</a> |</li>
+ <li class="right" >
+ <a href="interactive.html" title="13. Interactive Input Editing and History Substitution"
+ >next</a> |</li>
+ <li class="right" >
+ <a href="stdlib2.html" title="11. Brief Tour of the Standard Library – Part II"
+ >previous</a> |</li>
+ <li><img src="../_static/py.png" alt=""
+ style="vertical-align: middle; margin-top: -1px"/></li>
+ <li><a href="../index.html">Python v2.6.4c2 documentation</a> &raquo;</li>
+
+ <li><a href="index.html" >The Python Tutorial</a> &raquo;</li>
+ </ul>
+ </div>
+ <div class="footer">
+ &copy; <a href="../copyright.html">Copyright</a> 1990-2009, Python Software Foundation.
+ <br />
+ The Python Software Foundation is a non-profit corporation.
+ <a href="http://www.python.org/psf/donations/">Please donate.</a>
+ <br />
+ Last updated on Oct 19, 2009.
+ Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 0.6.2.
+ </div>
+
+ </body>
+</html> \ No newline at end of file
diff --git a/help/PythonTutorial/whatsnew/2.0.html b/help/PythonTutorial/whatsnew/2.0.html
new file mode 100644
index 0000000..2238500
--- /dev/null
+++ b/help/PythonTutorial/whatsnew/2.0.html
@@ -0,0 +1,1177 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+ <title>What’s New in Python 2.0 &mdash; Python v2.6.4c2 documentation</title>
+ <link rel="stylesheet" href="../_static/default.css" type="text/css" />
+ <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
+ <script type="text/javascript">
+ var DOCUMENTATION_OPTIONS = {
+ URL_ROOT: '../',
+ VERSION: '2.6.4c2',
+ COLLAPSE_MODINDEX: false,
+ FILE_SUFFIX: '.html',
+ HAS_SOURCE: true
+ };
+ </script>
+ <script type="text/javascript" src="../_static/jquery.js"></script>
+ <script type="text/javascript" src="../_static/doctools.js"></script>
+ <link rel="search" type="application/opensearchdescription+xml"
+ title="Search within Python v2.6.4c2 documentation"
+ href="../_static/opensearch.xml"/>
+ <link rel="author" title="About these documents" href="../about.html" />
+ <link rel="copyright" title="Copyright" href="../copyright.html" />
+ <link rel="top" title="Python v2.6.4c2 documentation" href="../index.html" />
+ <link rel="up" title="What’s New in Python" href="index.html" />
+ <link rel="next" title="The Python Tutorial" href="../tutorial/index.html" />
+ <link rel="prev" title="What’s New in Python 2.1" href="2.1.html" />
+ <link rel="shortcut icon" type="image/png" href="../_static/py.png" />
+
+
+ </head>
+ <body>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../modindex.html" title="Global Module Index"
+ accesskey="M">modules</a> |</li>
+ <li class="right" >
+ <a href="../tutorial/index.html" title="The Python Tutorial"
+ accesskey="N">next</a> |</li>
+ <li class="right" >
+ <a href="2.1.html" title="What’s New in Python 2.1"
+ accesskey="P">previous</a> |</li>
+ <li><img src="../_static/py.png" alt=""
+ style="vertical-align: middle; margin-top: -1px"/></li>
+ <li><a href="../index.html">Python v2.6.4c2 documentation</a> &raquo;</li>
+
+ <li><a href="index.html" accesskey="U">What&#8217;s New in Python</a> &raquo;</li>
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body">
+
+ <div class="section" id="what-s-new-in-python-2-0">
+<h1>What&#8217;s New in Python 2.0<a class="headerlink" href="#what-s-new-in-python-2-0" title="Permalink to this headline">¶</a></h1>
+<table class="docutils field-list" frame="void" rules="none">
+<col class="field-name" />
+<col class="field-body" />
+<tbody valign="top">
+<tr class="field"><th class="field-name">Author:</th><td class="field-body">A.M. Kuchling and Moshe Zadka</td>
+</tr>
+</tbody>
+</table>
+<div class="section" id="introduction">
+<h2>Introduction<a class="headerlink" href="#introduction" title="Permalink to this headline">¶</a></h2>
+<p>A new release of Python, version 2.0, was released on October 16, 2000. This
+article covers the exciting new features in 2.0, highlights some other useful
+changes, and points out a few incompatible changes that may require rewriting
+code.</p>
+<p>Python&#8217;s development never completely stops between releases, and a steady flow
+of bug fixes and improvements are always being submitted. A host of minor fixes,
+a few optimizations, additional docstrings, and better error messages went into
+2.0; to list them all would be impossible, but they&#8217;re certainly significant.
+Consult the publicly-available CVS logs if you want to see the full list. This
+progress is due to the five developers working for PythonLabs are now getting
+paid to spend their days fixing bugs, and also due to the improved communication
+resulting from moving to SourceForge.</p>
+</div>
+<div class="section" id="what-about-python-1-6">
+<h2>What About Python 1.6?<a class="headerlink" href="#what-about-python-1-6" title="Permalink to this headline">¶</a></h2>
+<p>Python 1.6 can be thought of as the Contractual Obligations Python release.
+After the core development team left CNRI in May 2000, CNRI requested that a 1.6
+release be created, containing all the work on Python that had been performed at
+CNRI. Python 1.6 therefore represents the state of the CVS tree as of May 2000,
+with the most significant new feature being Unicode support. Development
+continued after May, of course, so the 1.6 tree received a few fixes to ensure
+that it&#8217;s forward-compatible with Python 2.0. 1.6 is therefore part of Python&#8217;s
+evolution, and not a side branch.</p>
+<p>So, should you take much interest in Python 1.6? Probably not. The 1.6final
+and 2.0beta1 releases were made on the same day (September 5, 2000), the plan
+being to finalize Python 2.0 within a month or so. If you have applications to
+maintain, there seems little point in breaking things by moving to 1.6, fixing
+them, and then having another round of breakage within a month by moving to 2.0;
+you&#8217;re better off just going straight to 2.0. Most of the really interesting
+features described in this document are only in 2.0, because a lot of work was
+done between May and September.</p>
+</div>
+<div class="section" id="new-development-process">
+<h2>New Development Process<a class="headerlink" href="#new-development-process" title="Permalink to this headline">¶</a></h2>
+<p>The most important change in Python 2.0 may not be to the code at all, but to
+how Python is developed: in May 2000 the Python developers began using the tools
+made available by SourceForge for storing source code, tracking bug reports,
+and managing the queue of patch submissions. To report bugs or submit patches
+for Python 2.0, use the bug tracking and patch manager tools available from
+Python&#8217;s project page, located at <a class="reference external" href="http://sourceforge.net/projects/python/">http://sourceforge.net/projects/python/</a>.</p>
+<p>The most important of the services now hosted at SourceForge is the Python CVS
+tree, the version-controlled repository containing the source code for Python.
+Previously, there were roughly 7 or so people who had write access to the CVS
+tree, and all patches had to be inspected and checked in by one of the people on
+this short list. Obviously, this wasn&#8217;t very scalable. By moving the CVS tree
+to SourceForge, it became possible to grant write access to more people; as of
+September 2000 there were 27 people able to check in changes, a fourfold
+increase. This makes possible large-scale changes that wouldn&#8217;t be attempted if
+they&#8217;d have to be filtered through the small group of core developers. For
+example, one day Peter Schneider-Kamp took it into his head to drop K&amp;R C
+compatibility and convert the C source for Python to ANSI C. After getting
+approval on the python-dev mailing list, he launched into a flurry of checkins
+that lasted about a week, other developers joined in to help, and the job was
+done. If there were only 5 people with write access, probably that task would
+have been viewed as &#8220;nice, but not worth the time and effort needed&#8221; and it
+would never have gotten done.</p>
+<p>The shift to using SourceForge&#8217;s services has resulted in a remarkable increase
+in the speed of development. Patches now get submitted, commented on, revised
+by people other than the original submitter, and bounced back and forth between
+people until the patch is deemed worth checking in. Bugs are tracked in one
+central location and can be assigned to a specific person for fixing, and we can
+count the number of open bugs to measure progress. This didn&#8217;t come without a
+cost: developers now have more e-mail to deal with, more mailing lists to
+follow, and special tools had to be written for the new environment. For
+example, SourceForge sends default patch and bug notification e-mail messages
+that are completely unhelpful, so Ka-Ping Yee wrote an HTML screen-scraper that
+sends more useful messages.</p>
+<p>The ease of adding code caused a few initial growing pains, such as code was
+checked in before it was ready or without getting clear agreement from the
+developer group. The approval process that has emerged is somewhat similar to
+that used by the Apache group. Developers can vote +1, +0, -0, or -1 on a patch;
++1 and -1 denote acceptance or rejection, while +0 and -0 mean the developer is
+mostly indifferent to the change, though with a slight positive or negative
+slant. The most significant change from the Apache model is that the voting is
+essentially advisory, letting Guido van Rossum, who has Benevolent Dictator For
+Life status, know what the general opinion is. He can still ignore the result of
+a vote, and approve or reject a change even if the community disagrees with him.</p>
+<p>Producing an actual patch is the last step in adding a new feature, and is
+usually easy compared to the earlier task of coming up with a good design.
+Discussions of new features can often explode into lengthy mailing list threads,
+making the discussion hard to follow, and no one can read every posting to
+python-dev. Therefore, a relatively formal process has been set up to write
+Python Enhancement Proposals (PEPs), modelled on the Internet RFC process. PEPs
+are draft documents that describe a proposed new feature, and are continually
+revised until the community reaches a consensus, either accepting or rejecting
+the proposal. Quoting from the introduction to PEP 1, &#8220;PEP Purpose and
+Guidelines&#8221;:</p>
+<blockquote class="epigraph">
+<p>PEP stands for Python Enhancement Proposal. A PEP is a design document
+providing information to the Python community, or describing a new feature for
+Python. The PEP should provide a concise technical specification of the feature
+and a rationale for the feature.</p>
+<p>We intend PEPs to be the primary mechanisms for proposing new features, for
+collecting community input on an issue, and for documenting the design decisions
+that have gone into Python. The PEP author is responsible for building
+consensus within the community and documenting dissenting opinions.</p>
+</blockquote>
+<p>Read the rest of PEP 1 for the details of the PEP editorial process, style, and
+format. PEPs are kept in the Python CVS tree on SourceForge, though they&#8217;re not
+part of the Python 2.0 distribution, and are also available in HTML form from
+<a class="reference external" href="http://www.python.org/peps/">http://www.python.org/peps/</a>. As of September 2000, there are 25 PEPS, ranging
+from PEP 201, &#8220;Lockstep Iteration&#8221;, to PEP 225, &#8220;Elementwise/Objectwise
+Operators&#8221;.</p>
+</div>
+<div class="section" id="unicode">
+<h2>Unicode<a class="headerlink" href="#unicode" title="Permalink to this headline">¶</a></h2>
+<p>The largest new feature in Python 2.0 is a new fundamental data type: Unicode
+strings. Unicode uses 16-bit numbers to represent characters instead of the
+8-bit number used by ASCII, meaning that 65,536 distinct characters can be
+supported.</p>
+<p>The final interface for Unicode support was arrived at through countless often-
+stormy discussions on the python-dev mailing list, and mostly implemented by
+Marc-André Lemburg, based on a Unicode string type implementation by Fredrik
+Lundh. A detailed explanation of the interface was written up as <span class="target" id="index-1116"></span><a class="reference external" href="http://www.python.org/dev/peps/pep-0100"><strong>PEP 100</strong></a>,
+&#8220;Python Unicode Integration&#8221;. This article will simply cover the most
+significant points about the Unicode interfaces.</p>
+<p>In Python source code, Unicode strings are written as <tt class="docutils literal"><span class="pre">u&quot;string&quot;</span></tt>. Arbitrary
+Unicode characters can be written using a new escape sequence, <tt class="docutils literal"><span class="pre">\uHHHH</span></tt>, where
+<em>HHHH</em> is a 4-digit hexadecimal number from 0000 to FFFF. The existing
+<tt class="docutils literal"><span class="pre">\xHHHH</span></tt> escape sequence can also be used, and octal escapes can be used for
+characters up to U+01FF, which is represented by <tt class="docutils literal"><span class="pre">\777</span></tt>.</p>
+<p>Unicode strings, just like regular strings, are an immutable sequence type.
+They can be indexed and sliced, but not modified in place. Unicode strings have
+an <tt class="docutils literal"><span class="pre">encode(</span> <span class="pre">[encoding]</span> <span class="pre">)</span></tt> method that returns an 8-bit string in the desired
+encoding. Encodings are named by strings, such as <tt class="docutils literal"><span class="pre">'ascii'</span></tt>, <tt class="docutils literal"><span class="pre">'utf-8'</span></tt>,
+<tt class="docutils literal"><span class="pre">'iso-8859-1'</span></tt>, or whatever. A codec API is defined for implementing and
+registering new encodings that are then available throughout a Python program.
+If an encoding isn&#8217;t specified, the default encoding is usually 7-bit ASCII,
+though it can be changed for your Python installation by calling the
+<tt class="xref docutils literal"><span class="pre">sys.setdefaultencoding(encoding)()</span></tt> function in a customised version of
+<tt class="docutils literal"><span class="pre">site.py</span></tt>.</p>
+<p>Combining 8-bit and Unicode strings always coerces to Unicode, using the default
+ASCII encoding; the result of <tt class="docutils literal"><span class="pre">'a'</span> <span class="pre">+</span> <span class="pre">u'bc'</span></tt> is <tt class="docutils literal"><span class="pre">u'abc'</span></tt>.</p>
+<p>New built-in functions have been added, and existing built-ins modified to
+support Unicode:</p>
+<ul class="simple">
+<li><tt class="docutils literal"><span class="pre">unichr(ch)</span></tt> returns a Unicode string 1 character long, containing the
+character <em>ch</em>.</li>
+<li><tt class="docutils literal"><span class="pre">ord(u)</span></tt>, where <em>u</em> is a 1-character regular or Unicode string, returns the
+number of the character as an integer.</li>
+<li><tt class="docutils literal"><span class="pre">unicode(string</span> <span class="pre">[,</span> <span class="pre">encoding]</span>&nbsp; <span class="pre">[,</span> <span class="pre">errors]</span> <span class="pre">)</span></tt> creates a Unicode string
+from an 8-bit string. <tt class="docutils literal"><span class="pre">encoding</span></tt> is a string naming the encoding to use. The
+<tt class="docutils literal"><span class="pre">errors</span></tt> parameter specifies the treatment of characters that are invalid for
+the current encoding; passing <tt class="docutils literal"><span class="pre">'strict'</span></tt> as the value causes an exception to
+be raised on any encoding error, while <tt class="docutils literal"><span class="pre">'ignore'</span></tt> causes errors to be silently
+ignored and <tt class="docutils literal"><span class="pre">'replace'</span></tt> uses U+FFFD, the official replacement character, in
+case of any problems.</li>
+<li>The <a class="reference external" href="../reference/simple_stmts.html#exec"><tt class="xref docutils literal"><span class="pre">exec</span></tt></a> statement, and various built-ins such as <tt class="docutils literal"><span class="pre">eval()</span></tt>,
+<tt class="docutils literal"><span class="pre">getattr()</span></tt>, and <tt class="docutils literal"><span class="pre">setattr()</span></tt> will also accept Unicode strings as well as
+regular strings. (It&#8217;s possible that the process of fixing this missed some
+built-ins; if you find a built-in function that accepts strings but doesn&#8217;t
+accept Unicode strings at all, please report it as a bug.)</li>
+</ul>
+<p>A new module, <a title="Access the Unicode Database." class="reference external" href="../library/unicodedata.html#module-unicodedata"><tt class="xref docutils literal"><span class="pre">unicodedata</span></tt></a>, provides an interface to Unicode character
+properties. For example, <tt class="docutils literal"><span class="pre">unicodedata.category(u'A')</span></tt> returns the 2-character
+string &#8216;Lu&#8217;, the &#8216;L&#8217; denoting it&#8217;s a letter, and &#8216;u&#8217; meaning that it&#8217;s
+uppercase. <tt class="docutils literal"><span class="pre">unicodedata.bidirectional(u'\u0660')</span></tt> returns &#8216;AN&#8217;, meaning that
+U+0660 is an Arabic number.</p>
+<p>The <a title="Encode and decode data and streams." class="reference external" href="../library/codecs.html#module-codecs"><tt class="xref docutils literal"><span class="pre">codecs</span></tt></a> module contains functions to look up existing encodings and
+register new ones. Unless you want to implement a new encoding, you&#8217;ll most
+often use the <tt class="xref docutils literal"><span class="pre">codecs.lookup(encoding)()</span></tt> function, which returns a
+4-element tuple: <tt class="docutils literal"><span class="pre">(encode_func,</span> <span class="pre">decode_func,</span> <span class="pre">stream_reader,</span> <span class="pre">stream_writer)</span></tt>.</p>
+<ul class="simple">
+<li><em>encode_func</em> is a function that takes a Unicode string, and returns a 2-tuple
+<tt class="docutils literal"><span class="pre">(string,</span> <span class="pre">length)</span></tt>. <em>string</em> is an 8-bit string containing a portion (perhaps
+all) of the Unicode string converted into the given encoding, and <em>length</em> tells
+you how much of the Unicode string was converted.</li>
+<li><em>decode_func</em> is the opposite of <em>encode_func</em>, taking an 8-bit string and
+returning a 2-tuple <tt class="docutils literal"><span class="pre">(ustring,</span> <span class="pre">length)</span></tt>, consisting of the resulting Unicode
+string <em>ustring</em> and the integer <em>length</em> telling how much of the 8-bit string
+was consumed.</li>
+<li><em>stream_reader</em> is a class that supports decoding input from a stream.
+<em>stream_reader(file_obj)</em> returns an object that supports the <tt class="xref docutils literal"><span class="pre">read()</span></tt>,
+<tt class="xref docutils literal"><span class="pre">readline()</span></tt>, and <tt class="xref docutils literal"><span class="pre">readlines()</span></tt> methods. These methods will all
+translate from the given encoding and return Unicode strings.</li>
+<li><em>stream_writer</em>, similarly, is a class that supports encoding output to a
+stream. <em>stream_writer(file_obj)</em> returns an object that supports the
+<tt class="xref docutils literal"><span class="pre">write()</span></tt> and <tt class="xref docutils literal"><span class="pre">writelines()</span></tt> methods. These methods expect Unicode
+strings, translating them to the given encoding on output.</li>
+</ul>
+<p>For example, the following code writes a Unicode string into a file, encoding
+it as UTF-8:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">codecs</span>
+
+<span class="n">unistr</span> <span class="o">=</span> <span class="s">u&#39;</span><span class="se">\u0660\u2000</span><span class="s">ab ...&#39;</span>
+
+<span class="p">(</span><span class="n">UTF8_encode</span><span class="p">,</span> <span class="n">UTF8_decode</span><span class="p">,</span>
+ <span class="n">UTF8_streamreader</span><span class="p">,</span> <span class="n">UTF8_streamwriter</span><span class="p">)</span> <span class="o">=</span> <span class="n">codecs</span><span class="o">.</span><span class="n">lookup</span><span class="p">(</span><span class="s">&#39;UTF-8&#39;</span><span class="p">)</span>
+
+<span class="n">output</span> <span class="o">=</span> <span class="n">UTF8_streamwriter</span><span class="p">(</span> <span class="nb">open</span><span class="p">(</span> <span class="s">&#39;/tmp/output&#39;</span><span class="p">,</span> <span class="s">&#39;wb&#39;</span><span class="p">)</span> <span class="p">)</span>
+<span class="n">output</span><span class="o">.</span><span class="n">write</span><span class="p">(</span> <span class="n">unistr</span> <span class="p">)</span>
+<span class="n">output</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
+</pre></div>
+</div>
+<p>The following code would then read UTF-8 input from the file:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="nb">input</span> <span class="o">=</span> <span class="n">UTF8_streamreader</span><span class="p">(</span> <span class="nb">open</span><span class="p">(</span> <span class="s">&#39;/tmp/output&#39;</span><span class="p">,</span> <span class="s">&#39;rb&#39;</span><span class="p">)</span> <span class="p">)</span>
+<span class="k">print</span> <span class="nb">repr</span><span class="p">(</span><span class="nb">input</span><span class="o">.</span><span class="n">read</span><span class="p">())</span>
+<span class="nb">input</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
+</pre></div>
+</div>
+<p>Unicode-aware regular expressions are available through the <a title="Regular expression operations." class="reference external" href="../library/re.html#module-re"><tt class="xref docutils literal"><span class="pre">re</span></tt></a> module,
+which has a new underlying implementation called SRE written by Fredrik Lundh of
+Secret Labs AB.</p>
+<p>A <tt class="docutils literal"><span class="pre">-U</span></tt> command line option was added which causes the Python compiler to
+interpret all string literals as Unicode string literals. This is intended to be
+used in testing and future-proofing your Python code, since some future version
+of Python may drop support for 8-bit strings and provide only Unicode strings.</p>
+</div>
+<div class="section" id="list-comprehensions">
+<h2>List Comprehensions<a class="headerlink" href="#list-comprehensions" title="Permalink to this headline">¶</a></h2>
+<p>Lists are a workhorse data type in Python, and many programs manipulate a list
+at some point. Two common operations on lists are to loop over them, and either
+pick out the elements that meet a certain criterion, or apply some function to
+each element. For example, given a list of strings, you might want to pull out
+all the strings containing a given substring, or strip off trailing whitespace
+from each line.</p>
+<p>The existing <a title="map" class="reference external" href="../library/functions.html#map"><tt class="xref docutils literal"><span class="pre">map()</span></tt></a> and <a title="filter" class="reference external" href="../library/functions.html#filter"><tt class="xref docutils literal"><span class="pre">filter()</span></tt></a> functions can be used for this
+purpose, but they require a function as one of their arguments. This is fine if
+there&#8217;s an existing built-in function that can be passed directly, but if there
+isn&#8217;t, you have to create a little function to do the required work, and
+Python&#8217;s scoping rules make the result ugly if the little function needs
+additional information. Take the first example in the previous paragraph,
+finding all the strings in the list containing a given substring. You could
+write the following to do it:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="c"># Given the list L, make a list of all strings</span>
+<span class="c"># containing the substring S.</span>
+<span class="n">sublist</span> <span class="o">=</span> <span class="nb">filter</span><span class="p">(</span> <span class="k">lambda</span> <span class="n">s</span><span class="p">,</span> <span class="n">substring</span><span class="o">=</span><span class="n">S</span><span class="p">:</span>
+ <span class="n">string</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">substring</span><span class="p">)</span> <span class="o">!=</span> <span class="o">-</span><span class="mf">1</span><span class="p">,</span>
+ <span class="n">L</span><span class="p">)</span>
+</pre></div>
+</div>
+<p>Because of Python&#8217;s scoping rules, a default argument is used so that the
+anonymous function created by the <a class="reference external" href="../reference/expressions.html#lambda"><tt class="xref docutils literal"><span class="pre">lambda</span></tt></a> statement knows what
+substring is being searched for. List comprehensions make this cleaner:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="n">sublist</span> <span class="o">=</span> <span class="p">[</span> <span class="n">s</span> <span class="k">for</span> <span class="n">s</span> <span class="ow">in</span> <span class="n">L</span> <span class="k">if</span> <span class="n">string</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">S</span><span class="p">)</span> <span class="o">!=</span> <span class="o">-</span><span class="mf">1</span> <span class="p">]</span>
+</pre></div>
+</div>
+<p>List comprehensions have the form:</p>
+<div class="highlight-python"><pre>[ expression for expr in sequence1
+ for expr2 in sequence2 ...
+ for exprN in sequenceN
+ if condition ]</pre>
+</div>
+<p>The <a class="reference external" href="../reference/compound_stmts.html#for"><tt class="xref docutils literal"><span class="pre">for</span></tt></a>...<a class="reference external" href="../reference/expressions.html#in"><tt class="xref docutils literal"><span class="pre">in</span></tt></a> clauses contain the sequences to be
+iterated over. The sequences do not have to be the same length, because they
+are <em>not</em> iterated over in parallel, but from left to right; this is explained
+more clearly in the following paragraphs. The elements of the generated list
+will be the successive values of <em>expression</em>. The final <a class="reference external" href="../reference/compound_stmts.html#if"><tt class="xref docutils literal"><span class="pre">if</span></tt></a> clause
+is optional; if present, <em>expression</em> is only evaluated and added to the result
+if <em>condition</em> is true.</p>
+<p>To make the semantics very clear, a list comprehension is equivalent to the
+following Python code:</p>
+<div class="highlight-python"><pre>for expr1 in sequence1:
+ for expr2 in sequence2:
+ ...
+ for exprN in sequenceN:
+ if (condition):
+ # Append the value of
+ # the expression to the
+ # resulting list.</pre>
+</div>
+<p>This means that when there are multiple <a class="reference external" href="../reference/compound_stmts.html#for"><tt class="xref docutils literal"><span class="pre">for</span></tt></a>...<a class="reference external" href="../reference/expressions.html#in"><tt class="xref docutils literal"><span class="pre">in</span></tt></a>
+clauses, the resulting list will be equal to the product of the lengths of all
+the sequences. If you have two lists of length 3, the output list is 9 elements
+long:</p>
+<div class="highlight-python"><pre>seq1 = 'abc'
+seq2 = (1,2,3)
+&gt;&gt;&gt; [ (x,y) for x in seq1 for y in seq2]
+[('a', 1), ('a', 2), ('a', 3), ('b', 1), ('b', 2), ('b', 3), ('c', 1),
+('c', 2), ('c', 3)]</pre>
+</div>
+<p>To avoid introducing an ambiguity into Python&#8217;s grammar, if <em>expression</em> is
+creating a tuple, it must be surrounded with parentheses. The first list
+comprehension below is a syntax error, while the second one is correct:</p>
+<div class="highlight-python"><pre># Syntax error
+[ x,y for x in seq1 for y in seq2]
+# Correct
+[ (x,y) for x in seq1 for y in seq2]</pre>
+</div>
+<p>The idea of list comprehensions originally comes from the functional programming
+language Haskell (<a class="reference external" href="http://www.haskell.org">http://www.haskell.org</a>). Greg Ewing argued most effectively
+for adding them to Python and wrote the initial list comprehension patch, which
+was then discussed for a seemingly endless time on the python-dev mailing list
+and kept up-to-date by Skip Montanaro.</p>
+</div>
+<div class="section" id="augmented-assignment">
+<h2>Augmented Assignment<a class="headerlink" href="#augmented-assignment" title="Permalink to this headline">¶</a></h2>
+<p>Augmented assignment operators, another long-requested feature, have been added
+to Python 2.0. Augmented assignment operators include <tt class="docutils literal"><span class="pre">+=</span></tt>, <tt class="docutils literal"><span class="pre">-=</span></tt>, <tt class="docutils literal"><span class="pre">*=</span></tt>,
+and so forth. For example, the statement <tt class="docutils literal"><span class="pre">a</span> <span class="pre">+=</span> <span class="pre">2</span></tt> increments the value of the
+variable <tt class="docutils literal"><span class="pre">a</span></tt> by 2, equivalent to the slightly lengthier <tt class="docutils literal"><span class="pre">a</span> <span class="pre">=</span> <span class="pre">a</span> <span class="pre">+</span> <span class="pre">2</span></tt>.</p>
+<p>The full list of supported assignment operators is <tt class="docutils literal"><span class="pre">+=</span></tt>, <tt class="docutils literal"><span class="pre">-=</span></tt>, <tt class="docutils literal"><span class="pre">*=</span></tt>,
+<tt class="docutils literal"><span class="pre">/=</span></tt>, <tt class="docutils literal"><span class="pre">%=</span></tt>, <tt class="docutils literal"><span class="pre">**=</span></tt>, <tt class="docutils literal"><span class="pre">&amp;=</span></tt>, <tt class="docutils literal"><span class="pre">|=</span></tt>, <tt class="docutils literal"><span class="pre">^=</span></tt>, <tt class="docutils literal"><span class="pre">&gt;&gt;=</span></tt>, and <tt class="docutils literal"><span class="pre">&lt;&lt;=</span></tt>. Python
+classes can override the augmented assignment operators by defining methods
+named <a title="object.__iadd__" class="reference external" href="../reference/datamodel.html#object.__iadd__"><tt class="xref docutils literal"><span class="pre">__iadd__()</span></tt></a>, <a title="object.__isub__" class="reference external" href="../reference/datamodel.html#object.__isub__"><tt class="xref docutils literal"><span class="pre">__isub__()</span></tt></a>, etc. For example, the following
+<tt class="xref docutils literal"><span class="pre">Number</span></tt> class stores a number and supports using += to create a new
+instance with an incremented value.</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="k">class</span> <span class="nc">Number</span><span class="p">:</span>
+ <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
+ <span class="bp">self</span><span class="o">.</span><span class="n">value</span> <span class="o">=</span> <span class="n">value</span>
+ <span class="k">def</span> <span class="nf">__iadd__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">increment</span><span class="p">):</span>
+ <span class="k">return</span> <span class="n">Number</span><span class="p">(</span> <span class="bp">self</span><span class="o">.</span><span class="n">value</span> <span class="o">+</span> <span class="n">increment</span><span class="p">)</span>
+
+<span class="n">n</span> <span class="o">=</span> <span class="n">Number</span><span class="p">(</span><span class="mf">5</span><span class="p">)</span>
+<span class="n">n</span> <span class="o">+=</span> <span class="mf">3</span>
+<span class="k">print</span> <span class="n">n</span><span class="o">.</span><span class="n">value</span>
+</pre></div>
+</div>
+<p>The <a title="object.__iadd__" class="reference external" href="../reference/datamodel.html#object.__iadd__"><tt class="xref docutils literal"><span class="pre">__iadd__()</span></tt></a> special method is called with the value of the increment,
+and should return a new instance with an appropriately modified value; this
+return value is bound as the new value of the variable on the left-hand side.</p>
+<p>Augmented assignment operators were first introduced in the C programming
+language, and most C-derived languages, such as <strong>awk</strong>, C++, Java, Perl,
+and PHP also support them. The augmented assignment patch was implemented by
+Thomas Wouters.</p>
+</div>
+<div class="section" id="string-methods">
+<h2>String Methods<a class="headerlink" href="#string-methods" title="Permalink to this headline">¶</a></h2>
+<p>Until now string-manipulation functionality was in the <a title="Common string operations." class="reference external" href="../library/string.html#module-string"><tt class="xref docutils literal"><span class="pre">string</span></tt></a> module,
+which was usually a front-end for the <tt class="xref docutils literal"><span class="pre">strop</span></tt> module written in C. The
+addition of Unicode posed a difficulty for the <tt class="xref docutils literal"><span class="pre">strop</span></tt> module, because the
+functions would all need to be rewritten in order to accept either 8-bit or
+Unicode strings. For functions such as <a title="string.replace" class="reference external" href="../library/string.html#string.replace"><tt class="xref docutils literal"><span class="pre">string.replace()</span></tt></a>, which takes 3
+string arguments, that means eight possible permutations, and correspondingly
+complicated code.</p>
+<p>Instead, Python 2.0 pushes the problem onto the string type, making string
+manipulation functionality available through methods on both 8-bit strings and
+Unicode strings.</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="s">&#39;andrew&#39;</span><span class="o">.</span><span class="n">capitalize</span><span class="p">()</span>
+<span class="go">&#39;Andrew&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="s">&#39;hostname&#39;</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s">&#39;os&#39;</span><span class="p">,</span> <span class="s">&#39;linux&#39;</span><span class="p">)</span>
+<span class="go">&#39;hlinuxtname&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="s">&#39;moshe&#39;</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="s">&#39;sh&#39;</span><span class="p">)</span>
+<span class="go">2</span>
+</pre></div>
+</div>
+<p>One thing that hasn&#8217;t changed, a noteworthy April Fools&#8217; joke notwithstanding,
+is that Python strings are immutable. Thus, the string methods return new
+strings, and do not modify the string on which they operate.</p>
+<p>The old <a title="Common string operations." class="reference external" href="../library/string.html#module-string"><tt class="xref docutils literal"><span class="pre">string</span></tt></a> module is still around for backwards compatibility, but it
+mostly acts as a front-end to the new string methods.</p>
+<p>Two methods which have no parallel in pre-2.0 versions, although they did exist
+in JPython for quite some time, are <tt class="xref docutils literal"><span class="pre">startswith()</span></tt> and <tt class="xref docutils literal"><span class="pre">endswith()</span></tt>.
+<tt class="docutils literal"><span class="pre">s.startswith(t)</span></tt> is equivalent to <tt class="docutils literal"><span class="pre">s[:len(t)]</span> <span class="pre">==</span> <span class="pre">t</span></tt>, while
+<tt class="docutils literal"><span class="pre">s.endswith(t)</span></tt> is equivalent to <tt class="docutils literal"><span class="pre">s[-len(t):]</span> <span class="pre">==</span> <span class="pre">t</span></tt>.</p>
+<p>One other method which deserves special mention is <tt class="xref docutils literal"><span class="pre">join()</span></tt>. The
+<tt class="xref docutils literal"><span class="pre">join()</span></tt> method of a string receives one parameter, a sequence of strings,
+and is equivalent to the <a title="string.join" class="reference external" href="../library/string.html#string.join"><tt class="xref docutils literal"><span class="pre">string.join()</span></tt></a> function from the old <a title="Common string operations." class="reference external" href="../library/string.html#module-string"><tt class="xref docutils literal"><span class="pre">string</span></tt></a>
+module, with the arguments reversed. In other words, <tt class="docutils literal"><span class="pre">s.join(seq)</span></tt> is
+equivalent to the old <tt class="docutils literal"><span class="pre">string.join(seq,</span> <span class="pre">s)</span></tt>.</p>
+</div>
+<div class="section" id="garbage-collection-of-cycles">
+<h2>Garbage Collection of Cycles<a class="headerlink" href="#garbage-collection-of-cycles" title="Permalink to this headline">¶</a></h2>
+<p>The C implementation of Python uses reference counting to implement garbage
+collection. Every Python object maintains a count of the number of references
+pointing to itself, and adjusts the count as references are created or
+destroyed. Once the reference count reaches zero, the object is no longer
+accessible, since you need to have a reference to an object to access it, and if
+the count is zero, no references exist any longer.</p>
+<p>Reference counting has some pleasant properties: it&#8217;s easy to understand and
+implement, and the resulting implementation is portable, fairly fast, and reacts
+well with other libraries that implement their own memory handling schemes. The
+major problem with reference counting is that it sometimes doesn&#8217;t realise that
+objects are no longer accessible, resulting in a memory leak. This happens when
+there are cycles of references.</p>
+<p>Consider the simplest possible cycle, a class instance which has a reference to
+itself:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="n">instance</span> <span class="o">=</span> <span class="n">SomeClass</span><span class="p">()</span>
+<span class="n">instance</span><span class="o">.</span><span class="n">myself</span> <span class="o">=</span> <span class="n">instance</span>
+</pre></div>
+</div>
+<p>After the above two lines of code have been executed, the reference count of
+<tt class="docutils literal"><span class="pre">instance</span></tt> is 2; one reference is from the variable named <tt class="docutils literal"><span class="pre">'instance'</span></tt>, and
+the other is from the <tt class="docutils literal"><span class="pre">myself</span></tt> attribute of the instance.</p>
+<p>If the next line of code is <tt class="docutils literal"><span class="pre">del</span> <span class="pre">instance</span></tt>, what happens? The reference count
+of <tt class="docutils literal"><span class="pre">instance</span></tt> is decreased by 1, so it has a reference count of 1; the
+reference in the <tt class="docutils literal"><span class="pre">myself</span></tt> attribute still exists. Yet the instance is no
+longer accessible through Python code, and it could be deleted. Several objects
+can participate in a cycle if they have references to each other, causing all of
+the objects to be leaked.</p>
+<p>Python 2.0 fixes this problem by periodically executing a cycle detection
+algorithm which looks for inaccessible cycles and deletes the objects involved.
+A new <a title="Interface to the cycle-detecting garbage collector." class="reference external" href="../library/gc.html#module-gc"><tt class="xref docutils literal"><span class="pre">gc</span></tt></a> module provides functions to perform a garbage collection,
+obtain debugging statistics, and tuning the collector&#8217;s parameters.</p>
+<p>Running the cycle detection algorithm takes some time, and therefore will result
+in some additional overhead. It is hoped that after we&#8217;ve gotten experience
+with the cycle collection from using 2.0, Python 2.1 will be able to minimize
+the overhead with careful tuning. It&#8217;s not yet obvious how much performance is
+lost, because benchmarking this is tricky and depends crucially on how often the
+program creates and destroys objects. The detection of cycles can be disabled
+when Python is compiled, if you can&#8217;t afford even a tiny speed penalty or
+suspect that the cycle collection is buggy, by specifying the
+<em class="xref">--without-cycle-gc</em> switch when running the <strong>configure</strong>
+script.</p>
+<p>Several people tackled this problem and contributed to a solution. An early
+implementation of the cycle detection approach was written by Toby Kelsey. The
+current algorithm was suggested by Eric Tiedemann during a visit to CNRI, and
+Guido van Rossum and Neil Schemenauer wrote two different implementations, which
+were later integrated by Neil. Lots of other people offered suggestions along
+the way; the March 2000 archives of the python-dev mailing list contain most of
+the relevant discussion, especially in the threads titled &#8220;Reference cycle
+collection for Python&#8221; and &#8220;Finalization again&#8221;.</p>
+</div>
+<div class="section" id="other-core-changes">
+<h2>Other Core Changes<a class="headerlink" href="#other-core-changes" title="Permalink to this headline">¶</a></h2>
+<p>Various minor changes have been made to Python&#8217;s syntax and built-in functions.
+None of the changes are very far-reaching, but they&#8217;re handy conveniences.</p>
+<div class="section" id="minor-language-changes">
+<h3>Minor Language Changes<a class="headerlink" href="#minor-language-changes" title="Permalink to this headline">¶</a></h3>
+<p>A new syntax makes it more convenient to call a given function with a tuple of
+arguments and/or a dictionary of keyword arguments. In Python 1.5 and earlier,
+you&#8217;d use the <a title="apply" class="reference external" href="../library/functions.html#apply"><tt class="xref docutils literal"><span class="pre">apply()</span></tt></a> built-in function: <tt class="docutils literal"><span class="pre">apply(f,</span> <span class="pre">args,</span> <span class="pre">kw)</span></tt> calls the
+function <tt class="xref docutils literal"><span class="pre">f()</span></tt> with the argument tuple <em>args</em> and the keyword arguments in
+the dictionary <em>kw</em>. <a title="apply" class="reference external" href="../library/functions.html#apply"><tt class="xref docutils literal"><span class="pre">apply()</span></tt></a> is the same in 2.0, but thanks to a patch
+from Greg Ewing, <tt class="docutils literal"><span class="pre">f(*args,</span> <span class="pre">**kw)</span></tt> as a shorter and clearer way to achieve the
+same effect. This syntax is symmetrical with the syntax for defining
+functions:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">f</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">):</span>
+ <span class="c"># args is a tuple of positional args,</span>
+ <span class="c"># kw is a dictionary of keyword args</span>
+ <span class="o">...</span>
+</pre></div>
+</div>
+<p>The <a class="reference external" href="../reference/simple_stmts.html#print"><tt class="xref docutils literal"><span class="pre">print</span></tt></a> statement can now have its output directed to a file-like
+object by following the <a class="reference external" href="../reference/simple_stmts.html#print"><tt class="xref docutils literal"><span class="pre">print</span></tt></a> with <tt class="docutils literal"><span class="pre">&gt;&gt;</span> <span class="pre">file</span></tt>, similar to the
+redirection operator in Unix shells. Previously you&#8217;d either have to use the
+<tt class="xref docutils literal"><span class="pre">write()</span></tt> method of the file-like object, which lacks the convenience and
+simplicity of <a class="reference external" href="../reference/simple_stmts.html#print"><tt class="xref docutils literal"><span class="pre">print</span></tt></a>, or you could assign a new value to
+<tt class="docutils literal"><span class="pre">sys.stdout</span></tt> and then restore the old value. For sending output to standard
+error, it&#8217;s much easier to write this:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="k">print</span> <span class="o">&gt;&gt;</span> <span class="n">sys</span><span class="o">.</span><span class="n">stderr</span><span class="p">,</span> <span class="s">&quot;Warning: action field not supplied&quot;</span>
+</pre></div>
+</div>
+<p>Modules can now be renamed on importing them, using the syntax <tt class="docutils literal"><span class="pre">import</span> <span class="pre">module</span>
+<span class="pre">as</span> <span class="pre">name</span></tt> or <tt class="docutils literal"><span class="pre">from</span> <span class="pre">module</span> <span class="pre">import</span> <span class="pre">name</span> <span class="pre">as</span> <span class="pre">othername</span></tt>. The patch was submitted
+by Thomas Wouters.</p>
+<p>A new format style is available when using the <tt class="docutils literal"><span class="pre">%</span></tt> operator; &#8216;%r&#8217; will insert
+the <a title="repr" class="reference external" href="../library/functions.html#repr"><tt class="xref docutils literal"><span class="pre">repr()</span></tt></a> of its argument. This was also added from symmetry
+considerations, this time for symmetry with the existing &#8216;%s&#8217; format style,
+which inserts the <a title="str" class="reference external" href="../library/functions.html#str"><tt class="xref docutils literal"><span class="pre">str()</span></tt></a> of its argument. For example, <tt class="docutils literal"><span class="pre">'%r</span> <span class="pre">%s'</span> <span class="pre">%</span> <span class="pre">('abc',</span>
+<span class="pre">'abc')</span></tt> returns a string containing <tt class="docutils literal"><span class="pre">'abc'</span> <span class="pre">abc</span></tt>.</p>
+<p>Previously there was no way to implement a class that overrode Python&#8217;s built-in
+<a class="reference external" href="../reference/expressions.html#in"><tt class="xref docutils literal"><span class="pre">in</span></tt></a> operator and implemented a custom version. <tt class="docutils literal"><span class="pre">obj</span> <span class="pre">in</span> <span class="pre">seq</span></tt> returns
+true if <em>obj</em> is present in the sequence <em>seq</em>; Python computes this by simply
+trying every index of the sequence until either <em>obj</em> is found or an
+<a title="exceptions.IndexError" class="reference external" href="../library/exceptions.html#exceptions.IndexError"><tt class="xref docutils literal"><span class="pre">IndexError</span></tt></a> is encountered. Moshe Zadka contributed a patch which adds a
+<a title="object.__contains__" class="reference external" href="../reference/datamodel.html#object.__contains__"><tt class="xref docutils literal"><span class="pre">__contains__()</span></tt></a> magic method for providing a custom implementation for
+<a class="reference external" href="../reference/expressions.html#in"><tt class="xref docutils literal"><span class="pre">in</span></tt></a>. Additionally, new built-in objects written in C can define what
+<a class="reference external" href="../reference/expressions.html#in"><tt class="xref docutils literal"><span class="pre">in</span></tt></a> means for them via a new slot in the sequence protocol.</p>
+<p>Earlier versions of Python used a recursive algorithm for deleting objects.
+Deeply nested data structures could cause the interpreter to fill up the C stack
+and crash; Christian Tismer rewrote the deletion logic to fix this problem. On
+a related note, comparing recursive objects recursed infinitely and crashed;
+Jeremy Hylton rewrote the code to no longer crash, producing a useful result
+instead. For example, after this code:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="n">a</span> <span class="o">=</span> <span class="p">[]</span>
+<span class="n">b</span> <span class="o">=</span> <span class="p">[]</span>
+<span class="n">a</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
+<span class="n">b</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">b</span><span class="p">)</span>
+</pre></div>
+</div>
+<p>The comparison <tt class="docutils literal"><span class="pre">a==b</span></tt> returns true, because the two recursive data structures
+are isomorphic. See the thread &#8220;trashcan and PR#7&#8221; in the April 2000 archives of
+the python-dev mailing list for the discussion leading up to this
+implementation, and some useful relevant links. Note that comparisons can now
+also raise exceptions. In earlier versions of Python, a comparison operation
+such as <tt class="docutils literal"><span class="pre">cmp(a,b)</span></tt> would always produce an answer, even if a user-defined
+<a title="object.__cmp__" class="reference external" href="../reference/datamodel.html#object.__cmp__"><tt class="xref docutils literal"><span class="pre">__cmp__()</span></tt></a> method encountered an error, since the resulting exception would
+simply be silently swallowed.</p>
+<p>Work has been done on porting Python to 64-bit Windows on the Itanium processor,
+mostly by Trent Mick of ActiveState. (Confusingly, <tt class="docutils literal"><span class="pre">sys.platform</span></tt> is still
+<tt class="docutils literal"><span class="pre">'win32'</span></tt> on Win64 because it seems that for ease of porting, MS Visual C++
+treats code as 32 bit on Itanium.) PythonWin also supports Windows CE; see the
+Python CE page at <a class="reference external" href="http://starship.python.net/crew/mhammond/ce/">http://starship.python.net/crew/mhammond/ce/</a> for more
+information.</p>
+<p>Another new platform is Darwin/MacOS X; initial support for it is in Python 2.0.
+Dynamic loading works, if you specify &#8220;configure &#8211;with-dyld &#8211;with-suffix=.x&#8221;.
+Consult the README in the Python source distribution for more instructions.</p>
+<p>An attempt has been made to alleviate one of Python&#8217;s warts, the often-confusing
+<a title="exceptions.NameError" class="reference external" href="../library/exceptions.html#exceptions.NameError"><tt class="xref docutils literal"><span class="pre">NameError</span></tt></a> exception when code refers to a local variable before the
+variable has been assigned a value. For example, the following code raises an
+exception on the <a class="reference external" href="../reference/simple_stmts.html#print"><tt class="xref docutils literal"><span class="pre">print</span></tt></a> statement in both 1.5.2 and 2.0; in 1.5.2 a
+<a title="exceptions.NameError" class="reference external" href="../library/exceptions.html#exceptions.NameError"><tt class="xref docutils literal"><span class="pre">NameError</span></tt></a> exception is raised, while 2.0 raises a new
+<a title="exceptions.UnboundLocalError" class="reference external" href="../library/exceptions.html#exceptions.UnboundLocalError"><tt class="xref docutils literal"><span class="pre">UnboundLocalError</span></tt></a> exception. <a title="exceptions.UnboundLocalError" class="reference external" href="../library/exceptions.html#exceptions.UnboundLocalError"><tt class="xref docutils literal"><span class="pre">UnboundLocalError</span></tt></a> is a subclass of
+<a title="exceptions.NameError" class="reference external" href="../library/exceptions.html#exceptions.NameError"><tt class="xref docutils literal"><span class="pre">NameError</span></tt></a>, so any existing code that expects <a title="exceptions.NameError" class="reference external" href="../library/exceptions.html#exceptions.NameError"><tt class="xref docutils literal"><span class="pre">NameError</span></tt></a> to be
+raised should still work.</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">f</span><span class="p">():</span>
+ <span class="k">print</span> <span class="s">&quot;i=&quot;</span><span class="p">,</span><span class="n">i</span>
+ <span class="n">i</span> <span class="o">=</span> <span class="n">i</span> <span class="o">+</span> <span class="mf">1</span>
+<span class="n">f</span><span class="p">()</span>
+</pre></div>
+</div>
+<p>Two new exceptions, <tt class="xref docutils literal"><span class="pre">TabError</span></tt> and <tt class="xref docutils literal"><span class="pre">IndentationError</span></tt>, have been
+introduced. They&#8217;re both subclasses of <a title="exceptions.SyntaxError" class="reference external" href="../library/exceptions.html#exceptions.SyntaxError"><tt class="xref docutils literal"><span class="pre">SyntaxError</span></tt></a>, and are raised when
+Python code is found to be improperly indented.</p>
+</div>
+<div class="section" id="changes-to-built-in-functions">
+<h3>Changes to Built-in Functions<a class="headerlink" href="#changes-to-built-in-functions" title="Permalink to this headline">¶</a></h3>
+<p>A new built-in, <tt class="xref docutils literal"><span class="pre">zip(seq1,</span> <span class="pre">seq2,</span> <span class="pre">...)()</span></tt>, has been added. <a title="zip" class="reference external" href="../library/functions.html#zip"><tt class="xref docutils literal"><span class="pre">zip()</span></tt></a>
+returns a list of tuples where each tuple contains the i-th element from each of
+the argument sequences. The difference between <a title="zip" class="reference external" href="../library/functions.html#zip"><tt class="xref docutils literal"><span class="pre">zip()</span></tt></a> and <tt class="docutils literal"><span class="pre">map(None,</span>
+<span class="pre">seq1,</span> <span class="pre">seq2)</span></tt> is that <a title="map" class="reference external" href="../library/functions.html#map"><tt class="xref docutils literal"><span class="pre">map()</span></tt></a> pads the sequences with <tt class="xref docutils literal"><span class="pre">None</span></tt> if the
+sequences aren&#8217;t all of the same length, while <a title="zip" class="reference external" href="../library/functions.html#zip"><tt class="xref docutils literal"><span class="pre">zip()</span></tt></a> truncates the
+returned list to the length of the shortest argument sequence.</p>
+<p>The <a title="int" class="reference external" href="../library/functions.html#int"><tt class="xref docutils literal"><span class="pre">int()</span></tt></a> and <a title="long" class="reference external" href="../library/functions.html#long"><tt class="xref docutils literal"><span class="pre">long()</span></tt></a> functions now accept an optional &#8220;base&#8221;
+parameter when the first argument is a string. <tt class="docutils literal"><span class="pre">int('123',</span> <span class="pre">10)</span></tt> returns 123,
+while <tt class="docutils literal"><span class="pre">int('123',</span> <span class="pre">16)</span></tt> returns 291. <tt class="docutils literal"><span class="pre">int(123,</span> <span class="pre">16)</span></tt> raises a
+<a title="exceptions.TypeError" class="reference external" href="../library/exceptions.html#exceptions.TypeError"><tt class="xref docutils literal"><span class="pre">TypeError</span></tt></a> exception with the message &#8220;can&#8217;t convert non-string with
+explicit base&#8221;.</p>
+<p>A new variable holding more detailed version information has been added to the
+<a title="Access system-specific parameters and functions." class="reference external" href="../library/sys.html#module-sys"><tt class="xref docutils literal"><span class="pre">sys</span></tt></a> module. <tt class="docutils literal"><span class="pre">sys.version_info</span></tt> is a tuple <tt class="docutils literal"><span class="pre">(major,</span> <span class="pre">minor,</span> <span class="pre">micro,</span>
+<span class="pre">level,</span> <span class="pre">serial)</span></tt> For example, in a hypothetical 2.0.1beta1, <tt class="docutils literal"><span class="pre">sys.version_info</span></tt>
+would be <tt class="docutils literal"><span class="pre">(2,</span> <span class="pre">0,</span> <span class="pre">1,</span> <span class="pre">'beta',</span> <span class="pre">1)</span></tt>. <em>level</em> is a string such as <tt class="docutils literal"><span class="pre">&quot;alpha&quot;</span></tt>,
+<tt class="docutils literal"><span class="pre">&quot;beta&quot;</span></tt>, or <tt class="docutils literal"><span class="pre">&quot;final&quot;</span></tt> for a final release.</p>
+<p>Dictionaries have an odd new method, <tt class="xref docutils literal"><span class="pre">setdefault(key,</span> <span class="pre">default)()</span></tt>, which
+behaves similarly to the existing <tt class="xref docutils literal"><span class="pre">get()</span></tt> method. However, if the key is
+missing, <tt class="xref docutils literal"><span class="pre">setdefault()</span></tt> both returns the value of <em>default</em> as <tt class="xref docutils literal"><span class="pre">get()</span></tt>
+would do, and also inserts it into the dictionary as the value for <em>key</em>. Thus,
+the following lines of code:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="k">if</span> <span class="nb">dict</span><span class="o">.</span><span class="n">has_key</span><span class="p">(</span> <span class="n">key</span> <span class="p">):</span> <span class="k">return</span> <span class="nb">dict</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
+<span class="k">else</span><span class="p">:</span>
+ <span class="nb">dict</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
+ <span class="k">return</span> <span class="nb">dict</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
+</pre></div>
+</div>
+<p>can be reduced to a single <tt class="docutils literal"><span class="pre">return</span> <span class="pre">dict.setdefault(key,</span> <span class="pre">[])</span></tt> statement.</p>
+<p>The interpreter sets a maximum recursion depth in order to catch runaway
+recursion before filling the C stack and causing a core dump or GPF..
+Previously this limit was fixed when you compiled Python, but in 2.0 the maximum
+recursion depth can be read and modified using <a title="sys.getrecursionlimit" class="reference external" href="../library/sys.html#sys.getrecursionlimit"><tt class="xref docutils literal"><span class="pre">sys.getrecursionlimit()</span></tt></a> and
+<a title="sys.setrecursionlimit" class="reference external" href="../library/sys.html#sys.setrecursionlimit"><tt class="xref docutils literal"><span class="pre">sys.setrecursionlimit()</span></tt></a>. The default value is 1000, and a rough maximum
+value for a given platform can be found by running a new script,
+<tt class="docutils literal"><span class="pre">Misc/find_recursionlimit.py</span></tt>.</p>
+</div>
+</div>
+<div class="section" id="porting-to-2-0">
+<h2>Porting to 2.0<a class="headerlink" href="#porting-to-2-0" title="Permalink to this headline">¶</a></h2>
+<p>New Python releases try hard to be compatible with previous releases, and the
+record has been pretty good. However, some changes are considered useful
+enough, usually because they fix initial design decisions that turned out to be
+actively mistaken, that breaking backward compatibility can&#8217;t always be avoided.
+This section lists the changes in Python 2.0 that may cause old Python code to
+break.</p>
+<p>The change which will probably break the most code is tightening up the
+arguments accepted by some methods. Some methods would take multiple arguments
+and treat them as a tuple, particularly various list methods such as
+<tt class="xref docutils literal"><span class="pre">append()</span></tt> and <tt class="xref docutils literal"><span class="pre">insert()</span></tt>. In earlier versions of Python, if <tt class="docutils literal"><span class="pre">L</span></tt> is
+a list, <tt class="docutils literal"><span class="pre">L.append(</span> <span class="pre">1,2</span> <span class="pre">)</span></tt> appends the tuple <tt class="docutils literal"><span class="pre">(1,2)</span></tt> to the list. In Python
+2.0 this causes a <a title="exceptions.TypeError" class="reference external" href="../library/exceptions.html#exceptions.TypeError"><tt class="xref docutils literal"><span class="pre">TypeError</span></tt></a> exception to be raised, with the message:
+&#8216;append requires exactly 1 argument; 2 given&#8217;. The fix is to simply add an
+extra set of parentheses to pass both values as a tuple: <tt class="docutils literal"><span class="pre">L.append(</span> <span class="pre">(1,2)</span> <span class="pre">)</span></tt>.</p>
+<p>The earlier versions of these methods were more forgiving because they used an
+old function in Python&#8217;s C interface to parse their arguments; 2.0 modernizes
+them to use <a title="PyArg_ParseTuple" class="reference external" href="../c-api/arg.html#PyArg_ParseTuple"><tt class="xref docutils literal"><span class="pre">PyArg_ParseTuple()</span></tt></a>, the current argument parsing function,
+which provides more helpful error messages and treats multi-argument calls as
+errors. If you absolutely must use 2.0 but can&#8217;t fix your code, you can edit
+<tt class="docutils literal"><span class="pre">Objects/listobject.c</span></tt> and define the preprocessor symbol
+<tt class="docutils literal"><span class="pre">NO_STRICT_LIST_APPEND</span></tt> to preserve the old behaviour; this isn&#8217;t recommended.</p>
+<p>Some of the functions in the <a title="Low-level networking interface." class="reference external" href="../library/socket.html#module-socket"><tt class="xref docutils literal"><span class="pre">socket</span></tt></a> module are still forgiving in this
+way. For example, <tt class="xref docutils literal"><span class="pre">socket.connect(</span> <span class="pre">('hostname',</span> <span class="pre">25)</span> <span class="pre">)()</span></tt> is the correct
+form, passing a tuple representing an IP address, but <tt class="xref docutils literal"><span class="pre">socket.connect(</span>
+<span class="pre">'hostname',</span> <span class="pre">25</span> <span class="pre">)()</span></tt> also works. <tt class="xref docutils literal"><span class="pre">socket.connect_ex()</span></tt> and <tt class="xref docutils literal"><span class="pre">socket.bind()</span></tt>
+are similarly easy-going. 2.0alpha1 tightened these functions up, but because
+the documentation actually used the erroneous multiple argument form, many
+people wrote code which would break with the stricter checking. GvR backed out
+the changes in the face of public reaction, so for the <a title="Low-level networking interface." class="reference external" href="../library/socket.html#module-socket"><tt class="xref docutils literal"><span class="pre">socket</span></tt></a> module, the
+documentation was fixed and the multiple argument form is simply marked as
+deprecated; it <em>will</em> be tightened up again in a future Python version.</p>
+<p>The <tt class="docutils literal"><span class="pre">\x</span></tt> escape in string literals now takes exactly 2 hex digits. Previously
+it would consume all the hex digits following the &#8216;x&#8217; and take the lowest 8 bits
+of the result, so <tt class="docutils literal"><span class="pre">\x123456</span></tt> was equivalent to <tt class="docutils literal"><span class="pre">\x56</span></tt>.</p>
+<p>The <a title="exceptions.AttributeError" class="reference external" href="../library/exceptions.html#exceptions.AttributeError"><tt class="xref docutils literal"><span class="pre">AttributeError</span></tt></a> and <a title="exceptions.NameError" class="reference external" href="../library/exceptions.html#exceptions.NameError"><tt class="xref docutils literal"><span class="pre">NameError</span></tt></a> exceptions have a more friendly
+error message, whose text will be something like <tt class="docutils literal"><span class="pre">'Spam'</span> <span class="pre">instance</span> <span class="pre">has</span> <span class="pre">no</span>
+<span class="pre">attribute</span> <span class="pre">'eggs'</span></tt> or <tt class="docutils literal"><span class="pre">name</span> <span class="pre">'eggs'</span> <span class="pre">is</span> <span class="pre">not</span> <span class="pre">defined</span></tt>. Previously the error
+message was just the missing attribute name <tt class="docutils literal"><span class="pre">eggs</span></tt>, and code written to take
+advantage of this fact will break in 2.0.</p>
+<p>Some work has been done to make integers and long integers a bit more
+interchangeable. In 1.5.2, large-file support was added for Solaris, to allow
+reading files larger than 2 GiB; this made the <tt class="xref docutils literal"><span class="pre">tell()</span></tt> method of file
+objects return a long integer instead of a regular integer. Some code would
+subtract two file offsets and attempt to use the result to multiply a sequence
+or slice a string, but this raised a <a title="exceptions.TypeError" class="reference external" href="../library/exceptions.html#exceptions.TypeError"><tt class="xref docutils literal"><span class="pre">TypeError</span></tt></a>. In 2.0, long integers
+can be used to multiply or slice a sequence, and it&#8217;ll behave as you&#8217;d
+intuitively expect it to; <tt class="docutils literal"><span class="pre">3L</span> <span class="pre">*</span> <span class="pre">'abc'</span></tt> produces &#8216;abcabcabc&#8217;, and
+<tt class="docutils literal"><span class="pre">(0,1,2,3)[2L:4L]</span></tt> produces (2,3). Long integers can also be used in various
+contexts where previously only integers were accepted, such as in the
+<tt class="xref docutils literal"><span class="pre">seek()</span></tt> method of file objects, and in the formats supported by the <tt class="docutils literal"><span class="pre">%</span></tt>
+operator (<tt class="docutils literal"><span class="pre">%d</span></tt>, <tt class="docutils literal"><span class="pre">%i</span></tt>, <tt class="docutils literal"><span class="pre">%x</span></tt>, etc.). For example, <tt class="docutils literal"><span class="pre">&quot;%d&quot;</span> <span class="pre">%</span> <span class="pre">2L**64</span></tt> will
+produce the string <tt class="docutils literal"><span class="pre">18446744073709551616</span></tt>.</p>
+<p>The subtlest long integer change of all is that the <a title="str" class="reference external" href="../library/functions.html#str"><tt class="xref docutils literal"><span class="pre">str()</span></tt></a> of a long
+integer no longer has a trailing &#8216;L&#8217; character, though <a title="repr" class="reference external" href="../library/functions.html#repr"><tt class="xref docutils literal"><span class="pre">repr()</span></tt></a> still
+includes it. The &#8216;L&#8217; annoyed many people who wanted to print long integers that
+looked just like regular integers, since they had to go out of their way to chop
+off the character. This is no longer a problem in 2.0, but code which does
+<tt class="docutils literal"><span class="pre">str(longval)[:-1]</span></tt> and assumes the &#8216;L&#8217; is there, will now lose the final
+digit.</p>
+<p>Taking the <a title="repr" class="reference external" href="../library/functions.html#repr"><tt class="xref docutils literal"><span class="pre">repr()</span></tt></a> of a float now uses a different formatting precision
+than <a title="str" class="reference external" href="../library/functions.html#str"><tt class="xref docutils literal"><span class="pre">str()</span></tt></a>. <a title="repr" class="reference external" href="../library/functions.html#repr"><tt class="xref docutils literal"><span class="pre">repr()</span></tt></a> uses <tt class="docutils literal"><span class="pre">%.17g</span></tt> format string for C&#8217;s
+<tt class="xref docutils literal"><span class="pre">sprintf()</span></tt>, while <a title="str" class="reference external" href="../library/functions.html#str"><tt class="xref docutils literal"><span class="pre">str()</span></tt></a> uses <tt class="docutils literal"><span class="pre">%.12g</span></tt> as before. The effect is that
+<a title="repr" class="reference external" href="../library/functions.html#repr"><tt class="xref docutils literal"><span class="pre">repr()</span></tt></a> may occasionally show more decimal places than <a title="str" class="reference external" href="../library/functions.html#str"><tt class="xref docutils literal"><span class="pre">str()</span></tt></a>, for
+certain numbers. For example, the number 8.1 can&#8217;t be represented exactly in
+binary, so <tt class="docutils literal"><span class="pre">repr(8.1)</span></tt> is <tt class="docutils literal"><span class="pre">'8.0999999999999996'</span></tt>, while str(8.1) is
+<tt class="docutils literal"><span class="pre">'8.1'</span></tt>.</p>
+<p>The <tt class="docutils literal"><span class="pre">-X</span></tt> command-line option, which turned all standard exceptions into
+strings instead of classes, has been removed; the standard exceptions will now
+always be classes. The <a title="Standard exception classes." class="reference external" href="../library/exceptions.html#module-exceptions"><tt class="xref docutils literal"><span class="pre">exceptions</span></tt></a> module containing the standard
+exceptions was translated from Python to a built-in C module, written by Barry
+Warsaw and Fredrik Lundh.</p>
+</div>
+<div class="section" id="extending-embedding-changes">
+<h2>Extending/Embedding Changes<a class="headerlink" href="#extending-embedding-changes" title="Permalink to this headline">¶</a></h2>
+<p>Some of the changes are under the covers, and will only be apparent to people
+writing C extension modules or embedding a Python interpreter in a larger
+application. If you aren&#8217;t dealing with Python&#8217;s C API, you can safely skip
+this section.</p>
+<p>The version number of the Python C API was incremented, so C extensions compiled
+for 1.5.2 must be recompiled in order to work with 2.0. On Windows, it&#8217;s not
+possible for Python 2.0 to import a third party extension built for Python 1.5.x
+due to how Windows DLLs work, so Python will raise an exception and the import
+will fail.</p>
+<p>Users of Jim Fulton&#8217;s ExtensionClass module will be pleased to find out that
+hooks have been added so that ExtensionClasses are now supported by
+<a title="isinstance" class="reference external" href="../library/functions.html#isinstance"><tt class="xref docutils literal"><span class="pre">isinstance()</span></tt></a> and <a title="issubclass" class="reference external" href="../library/functions.html#issubclass"><tt class="xref docutils literal"><span class="pre">issubclass()</span></tt></a>. This means you no longer have to
+remember to write code such as <tt class="docutils literal"><span class="pre">if</span> <span class="pre">type(obj)</span> <span class="pre">==</span> <span class="pre">myExtensionClass</span></tt>, but can use
+the more natural <tt class="docutils literal"><span class="pre">if</span> <span class="pre">isinstance(obj,</span> <span class="pre">myExtensionClass)</span></tt>.</p>
+<p>The <tt class="docutils literal"><span class="pre">Python/importdl.c</span></tt> file, which was a mass of #ifdefs to support
+dynamic loading on many different platforms, was cleaned up and reorganised by
+Greg Stein. <tt class="docutils literal"><span class="pre">importdl.c</span></tt> is now quite small, and platform-specific code
+has been moved into a bunch of <tt class="docutils literal"><span class="pre">Python/dynload_*.c</span></tt> files. Another
+cleanup: there were also a number of <tt class="docutils literal"><span class="pre">my*.h</span></tt> files in the Include/
+directory that held various portability hacks; they&#8217;ve been merged into a single
+file, <tt class="docutils literal"><span class="pre">Include/pyport.h</span></tt>.</p>
+<p>Vladimir Marangozov&#8217;s long-awaited malloc restructuring was completed, to make
+it easy to have the Python interpreter use a custom allocator instead of C&#8217;s
+standard <tt class="xref docutils literal"><span class="pre">malloc()</span></tt>. For documentation, read the comments in
+<tt class="docutils literal"><span class="pre">Include/pymem.h</span></tt> and <tt class="docutils literal"><span class="pre">Include/objimpl.h</span></tt>. For the lengthy
+discussions during which the interface was hammered out, see the Web archives of
+the &#8216;patches&#8217; and &#8216;python-dev&#8217; lists at python.org.</p>
+<p>Recent versions of the GUSI development environment for MacOS support POSIX
+threads. Therefore, Python&#8217;s POSIX threading support now works on the
+Macintosh. Threading support using the user-space GNU <tt class="docutils literal"><span class="pre">pth</span></tt> library was also
+contributed.</p>
+<p>Threading support on Windows was enhanced, too. Windows supports thread locks
+that use kernel objects only in case of contention; in the common case when
+there&#8217;s no contention, they use simpler functions which are an order of
+magnitude faster. A threaded version of Python 1.5.2 on NT is twice as slow as
+an unthreaded version; with the 2.0 changes, the difference is only 10%. These
+improvements were contributed by Yakov Markovitch.</p>
+<p>Python 2.0&#8217;s source now uses only ANSI C prototypes, so compiling Python now
+requires an ANSI C compiler, and can no longer be done using a compiler that
+only supports K&amp;R C.</p>
+<p>Previously the Python virtual machine used 16-bit numbers in its bytecode,
+limiting the size of source files. In particular, this affected the maximum
+size of literal lists and dictionaries in Python source; occasionally people who
+are generating Python code would run into this limit. A patch by Charles G.
+Waldman raises the limit from <tt class="docutils literal"><span class="pre">2^16</span></tt> to <tt class="docutils literal"><span class="pre">2^{32}</span></tt>.</p>
+<p>Three new convenience functions intended for adding constants to a module&#8217;s
+dictionary at module initialization time were added: <a title="PyModule_AddObject" class="reference external" href="../c-api/module.html#PyModule_AddObject"><tt class="xref docutils literal"><span class="pre">PyModule_AddObject()</span></tt></a>,
+<a title="PyModule_AddIntConstant" class="reference external" href="../c-api/module.html#PyModule_AddIntConstant"><tt class="xref docutils literal"><span class="pre">PyModule_AddIntConstant()</span></tt></a>, and <a title="PyModule_AddStringConstant" class="reference external" href="../c-api/module.html#PyModule_AddStringConstant"><tt class="xref docutils literal"><span class="pre">PyModule_AddStringConstant()</span></tt></a>. Each
+of these functions takes a module object, a null-terminated C string containing
+the name to be added, and a third argument for the value to be assigned to the
+name. This third argument is, respectively, a Python object, a C long, or a C
+string.</p>
+<p>A wrapper API was added for Unix-style signal handlers. <a title="PyOS_getsig" class="reference external" href="../c-api/sys.html#PyOS_getsig"><tt class="xref docutils literal"><span class="pre">PyOS_getsig()</span></tt></a> gets
+a signal handler and <a title="PyOS_setsig" class="reference external" href="../c-api/sys.html#PyOS_setsig"><tt class="xref docutils literal"><span class="pre">PyOS_setsig()</span></tt></a> will set a new handler.</p>
+</div>
+<div class="section" id="distutils-making-modules-easy-to-install">
+<h2>Distutils: Making Modules Easy to Install<a class="headerlink" href="#distutils-making-modules-easy-to-install" title="Permalink to this headline">¶</a></h2>
+<p>Before Python 2.0, installing modules was a tedious affair &#8211; there was no way
+to figure out automatically where Python is installed, or what compiler options
+to use for extension modules. Software authors had to go through an arduous
+ritual of editing Makefiles and configuration files, which only really work on
+Unix and leave Windows and MacOS unsupported. Python users faced wildly
+differing installation instructions which varied between different extension
+packages, which made administering a Python installation something of a chore.</p>
+<p>The SIG for distribution utilities, shepherded by Greg Ward, has created the
+Distutils, a system to make package installation much easier. They form the
+<a title="Support for building and installing Python modules into an existing Python installation." class="reference external" href="../library/distutils.html#module-distutils"><tt class="xref docutils literal"><span class="pre">distutils</span></tt></a> package, a new part of Python&#8217;s standard library. In the best
+case, installing a Python module from source will require the same steps: first
+you simply mean unpack the tarball or zip archive, and the run &#8220;<tt class="docutils literal"><span class="pre">python</span>
+<span class="pre">setup.py</span> <span class="pre">install</span></tt>&#8220;. The platform will be automatically detected, the compiler
+will be recognized, C extension modules will be compiled, and the distribution
+installed into the proper directory. Optional command-line arguments provide
+more control over the installation process, the distutils package offers many
+places to override defaults &#8211; separating the build from the install, building
+or installing in non-default directories, and more.</p>
+<p>In order to use the Distutils, you need to write a <tt class="docutils literal"><span class="pre">setup.py</span></tt> script. For
+the simple case, when the software contains only .py files, a minimal
+<tt class="docutils literal"><span class="pre">setup.py</span></tt> can be just a few lines long:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">distutils.core</span> <span class="kn">import</span> <span class="n">setup</span>
+<span class="n">setup</span> <span class="p">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">&quot;foo&quot;</span><span class="p">,</span> <span class="n">version</span> <span class="o">=</span> <span class="s">&quot;1.0&quot;</span><span class="p">,</span>
+ <span class="n">py_modules</span> <span class="o">=</span> <span class="p">[</span><span class="s">&quot;module1&quot;</span><span class="p">,</span> <span class="s">&quot;module2&quot;</span><span class="p">])</span>
+</pre></div>
+</div>
+<p>The <tt class="docutils literal"><span class="pre">setup.py</span></tt> file isn&#8217;t much more complicated if the software consists
+of a few packages:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">distutils.core</span> <span class="kn">import</span> <span class="n">setup</span>
+<span class="n">setup</span> <span class="p">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">&quot;foo&quot;</span><span class="p">,</span> <span class="n">version</span> <span class="o">=</span> <span class="s">&quot;1.0&quot;</span><span class="p">,</span>
+ <span class="n">packages</span> <span class="o">=</span> <span class="p">[</span><span class="s">&quot;package&quot;</span><span class="p">,</span> <span class="s">&quot;package.subpackage&quot;</span><span class="p">])</span>
+</pre></div>
+</div>
+<p>A C extension can be the most complicated case; here&#8217;s an example taken from
+the PyXML package:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">distutils.core</span> <span class="kn">import</span> <span class="n">setup</span><span class="p">,</span> <span class="n">Extension</span>
+
+<span class="n">expat_extension</span> <span class="o">=</span> <span class="n">Extension</span><span class="p">(</span><span class="s">&#39;xml.parsers.pyexpat&#39;</span><span class="p">,</span>
+ <span class="n">define_macros</span> <span class="o">=</span> <span class="p">[(</span><span class="s">&#39;XML_NS&#39;</span><span class="p">,</span> <span class="bp">None</span><span class="p">)],</span>
+ <span class="n">include_dirs</span> <span class="o">=</span> <span class="p">[</span> <span class="s">&#39;extensions/expat/xmltok&#39;</span><span class="p">,</span>
+ <span class="s">&#39;extensions/expat/xmlparse&#39;</span> <span class="p">],</span>
+ <span class="n">sources</span> <span class="o">=</span> <span class="p">[</span> <span class="s">&#39;extensions/pyexpat.c&#39;</span><span class="p">,</span>
+ <span class="s">&#39;extensions/expat/xmltok/xmltok.c&#39;</span><span class="p">,</span>
+ <span class="s">&#39;extensions/expat/xmltok/xmlrole.c&#39;</span><span class="p">,</span> <span class="p">]</span>
+ <span class="p">)</span>
+<span class="n">setup</span> <span class="p">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">&quot;PyXML&quot;</span><span class="p">,</span> <span class="n">version</span> <span class="o">=</span> <span class="s">&quot;0.5.4&quot;</span><span class="p">,</span>
+ <span class="n">ext_modules</span> <span class="o">=</span><span class="p">[</span> <span class="n">expat_extension</span> <span class="p">]</span> <span class="p">)</span>
+</pre></div>
+</div>
+<p>The Distutils can also take care of creating source and binary distributions.
+The &#8220;sdist&#8221; command, run by &#8220;<tt class="docutils literal"><span class="pre">python</span> <span class="pre">setup.py</span> <span class="pre">sdist</span></tt>&#8216;, builds a source
+distribution such as <tt class="docutils literal"><span class="pre">foo-1.0.tar.gz</span></tt>. Adding new commands isn&#8217;t
+difficult, &#8220;bdist_rpm&#8221; and &#8220;bdist_wininst&#8221; commands have already been
+contributed to create an RPM distribution and a Windows installer for the
+software, respectively. Commands to create other distribution formats such as
+Debian packages and Solaris <tt class="docutils literal"><span class="pre">.pkg</span></tt> files are in various stages of
+development.</p>
+<p>All this is documented in a new manual, <em>Distributing Python Modules</em>, that
+joins the basic set of Python documentation.</p>
+</div>
+<div class="section" id="xml-modules">
+<h2>XML Modules<a class="headerlink" href="#xml-modules" title="Permalink to this headline">¶</a></h2>
+<p>Python 1.5.2 included a simple XML parser in the form of the <tt class="xref docutils literal"><span class="pre">xmllib</span></tt>
+module, contributed by Sjoerd Mullender. Since 1.5.2&#8217;s release, two different
+interfaces for processing XML have become common: SAX2 (version 2 of the Simple
+API for XML) provides an event-driven interface with some similarities to
+<tt class="xref docutils literal"><span class="pre">xmllib</span></tt>, and the DOM (Document Object Model) provides a tree-based
+interface, transforming an XML document into a tree of nodes that can be
+traversed and modified. Python 2.0 includes a SAX2 interface and a stripped-
+down DOM interface as part of the <tt class="xref docutils literal"><span class="pre">xml</span></tt> package. Here we will give a brief
+overview of these new interfaces; consult the Python documentation or the source
+code for complete details. The Python XML SIG is also working on improved
+documentation.</p>
+<div class="section" id="sax2-support">
+<h3>SAX2 Support<a class="headerlink" href="#sax2-support" title="Permalink to this headline">¶</a></h3>
+<p>SAX defines an event-driven interface for parsing XML. To use SAX, you must
+write a SAX handler class. Handler classes inherit from various classes
+provided by SAX, and override various methods that will then be called by the
+XML parser. For example, the <tt class="xref docutils literal"><span class="pre">startElement()</span></tt> and <tt class="xref docutils literal"><span class="pre">endElement()</span></tt>
+methods are called for every starting and end tag encountered by the parser, the
+<tt class="xref docutils literal"><span class="pre">characters()</span></tt> method is called for every chunk of character data, and so
+forth.</p>
+<p>The advantage of the event-driven approach is that the whole document doesn&#8217;t
+have to be resident in memory at any one time, which matters if you are
+processing really huge documents. However, writing the SAX handler class can
+get very complicated if you&#8217;re trying to modify the document structure in some
+elaborate way.</p>
+<p>For example, this little example program defines a handler that prints a message
+for every starting and ending tag, and then parses the file <tt class="docutils literal"><span class="pre">hamlet.xml</span></tt>
+using it:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">xml</span> <span class="kn">import</span> <span class="n">sax</span>
+
+<span class="k">class</span> <span class="nc">SimpleHandler</span><span class="p">(</span><span class="n">sax</span><span class="o">.</span><span class="n">ContentHandler</span><span class="p">):</span>
+ <span class="k">def</span> <span class="nf">startElement</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">attrs</span><span class="p">):</span>
+ <span class="k">print</span> <span class="s">&#39;Start of element:&#39;</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">attrs</span><span class="o">.</span><span class="n">keys</span><span class="p">()</span>
+
+ <span class="k">def</span> <span class="nf">endElement</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">):</span>
+ <span class="k">print</span> <span class="s">&#39;End of element:&#39;</span><span class="p">,</span> <span class="n">name</span>
+
+<span class="c"># Create a parser object</span>
+<span class="n">parser</span> <span class="o">=</span> <span class="n">sax</span><span class="o">.</span><span class="n">make_parser</span><span class="p">()</span>
+
+<span class="c"># Tell it what handler to use</span>
+<span class="n">handler</span> <span class="o">=</span> <span class="n">SimpleHandler</span><span class="p">()</span>
+<span class="n">parser</span><span class="o">.</span><span class="n">setContentHandler</span><span class="p">(</span> <span class="n">handler</span> <span class="p">)</span>
+
+<span class="c"># Parse a file!</span>
+<span class="n">parser</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span> <span class="s">&#39;hamlet.xml&#39;</span> <span class="p">)</span>
+</pre></div>
+</div>
+<p>For more information, consult the Python documentation, or the XML HOWTO at
+<a class="reference external" href="http://pyxml.sourceforge.net/topics/howto/xml-howto.html">http://pyxml.sourceforge.net/topics/howto/xml-howto.html</a>.</p>
+</div>
+<div class="section" id="dom-support">
+<h3>DOM Support<a class="headerlink" href="#dom-support" title="Permalink to this headline">¶</a></h3>
+<p>The Document Object Model is a tree-based representation for an XML document. A
+top-level <tt class="xref docutils literal"><span class="pre">Document</span></tt> instance is the root of the tree, and has a single
+child which is the top-level <tt class="xref docutils literal"><span class="pre">Element</span></tt> instance. This <tt class="xref docutils literal"><span class="pre">Element</span></tt>
+has children nodes representing character data and any sub-elements, which may
+have further children of their own, and so forth. Using the DOM you can
+traverse the resulting tree any way you like, access element and attribute
+values, insert and delete nodes, and convert the tree back into XML.</p>
+<p>The DOM is useful for modifying XML documents, because you can create a DOM
+tree, modify it by adding new nodes or rearranging subtrees, and then produce a
+new XML document as output. You can also construct a DOM tree manually and
+convert it to XML, which can be a more flexible way of producing XML output than
+simply writing <tt class="docutils literal"><span class="pre">&lt;tag1&gt;</span></tt>...<tt class="docutils literal"><span class="pre">&lt;/tag1&gt;</span></tt> to a file.</p>
+<p>The DOM implementation included with Python lives in the <a title="Lightweight Document Object Model (DOM) implementation." class="reference external" href="../library/xml.dom.minidom.html#module-xml.dom.minidom"><tt class="xref docutils literal"><span class="pre">xml.dom.minidom</span></tt></a>
+module. It&#8217;s a lightweight implementation of the Level 1 DOM with support for
+XML namespaces. The <tt class="xref docutils literal"><span class="pre">parse()</span></tt> and <tt class="xref docutils literal"><span class="pre">parseString()</span></tt> convenience
+functions are provided for generating a DOM tree:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">xml.dom</span> <span class="kn">import</span> <span class="n">minidom</span>
+<span class="n">doc</span> <span class="o">=</span> <span class="n">minidom</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="s">&#39;hamlet.xml&#39;</span><span class="p">)</span>
+</pre></div>
+</div>
+<p><tt class="docutils literal"><span class="pre">doc</span></tt> is a <tt class="xref docutils literal"><span class="pre">Document</span></tt> instance. <tt class="xref docutils literal"><span class="pre">Document</span></tt>, like all the other
+DOM classes such as <tt class="xref docutils literal"><span class="pre">Element</span></tt> and <tt class="xref docutils literal"><span class="pre">Text</span></tt>, is a subclass of the
+<tt class="xref docutils literal"><span class="pre">Node</span></tt> base class. All the nodes in a DOM tree therefore support certain
+common methods, such as <tt class="xref docutils literal"><span class="pre">toxml()</span></tt> which returns a string containing the XML
+representation of the node and its children. Each class also has special
+methods of its own; for example, <tt class="xref docutils literal"><span class="pre">Element</span></tt> and <tt class="xref docutils literal"><span class="pre">Document</span></tt>
+instances have a method to find all child elements with a given tag name.
+Continuing from the previous 2-line example:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="n">perslist</span> <span class="o">=</span> <span class="n">doc</span><span class="o">.</span><span class="n">getElementsByTagName</span><span class="p">(</span> <span class="s">&#39;PERSONA&#39;</span> <span class="p">)</span>
+<span class="k">print</span> <span class="n">perslist</span><span class="p">[</span><span class="mf">0</span><span class="p">]</span><span class="o">.</span><span class="n">toxml</span><span class="p">()</span>
+<span class="k">print</span> <span class="n">perslist</span><span class="p">[</span><span class="mf">1</span><span class="p">]</span><span class="o">.</span><span class="n">toxml</span><span class="p">()</span>
+</pre></div>
+</div>
+<p>For the <em>Hamlet</em> XML file, the above few lines output:</p>
+<div class="highlight-python"><pre>&lt;PERSONA&gt;CLAUDIUS, king of Denmark. &lt;/PERSONA&gt;
+&lt;PERSONA&gt;HAMLET, son to the late, and nephew to the present king.&lt;/PERSONA&gt;</pre>
+</div>
+<p>The root element of the document is available as <tt class="docutils literal"><span class="pre">doc.documentElement</span></tt>, and
+its children can be easily modified by deleting, adding, or removing nodes:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="n">root</span> <span class="o">=</span> <span class="n">doc</span><span class="o">.</span><span class="n">documentElement</span>
+
+<span class="c"># Remove the first child</span>
+<span class="n">root</span><span class="o">.</span><span class="n">removeChild</span><span class="p">(</span> <span class="n">root</span><span class="o">.</span><span class="n">childNodes</span><span class="p">[</span><span class="mf">0</span><span class="p">]</span> <span class="p">)</span>
+
+<span class="c"># Move the new first child to the end</span>
+<span class="n">root</span><span class="o">.</span><span class="n">appendChild</span><span class="p">(</span> <span class="n">root</span><span class="o">.</span><span class="n">childNodes</span><span class="p">[</span><span class="mf">0</span><span class="p">]</span> <span class="p">)</span>
+
+<span class="c"># Insert the new first child (originally,</span>
+<span class="c"># the third child) before the 20th child.</span>
+<span class="n">root</span><span class="o">.</span><span class="n">insertBefore</span><span class="p">(</span> <span class="n">root</span><span class="o">.</span><span class="n">childNodes</span><span class="p">[</span><span class="mf">0</span><span class="p">],</span> <span class="n">root</span><span class="o">.</span><span class="n">childNodes</span><span class="p">[</span><span class="mf">20</span><span class="p">]</span> <span class="p">)</span>
+</pre></div>
+</div>
+<p>Again, I will refer you to the Python documentation for a complete listing of
+the different <tt class="xref docutils literal"><span class="pre">Node</span></tt> classes and their various methods.</p>
+</div>
+<div class="section" id="relationship-to-pyxml">
+<h3>Relationship to PyXML<a class="headerlink" href="#relationship-to-pyxml" title="Permalink to this headline">¶</a></h3>
+<p>The XML Special Interest Group has been working on XML-related Python code for a
+while. Its code distribution, called PyXML, is available from the SIG&#8217;s Web
+pages at <a class="reference external" href="http://www.python.org/sigs/xml-sig/">http://www.python.org/sigs/xml-sig/</a>. The PyXML distribution also used
+the package name <tt class="docutils literal"><span class="pre">xml</span></tt>. If you&#8217;ve written programs that used PyXML, you&#8217;re
+probably wondering about its compatibility with the 2.0 <tt class="xref docutils literal"><span class="pre">xml</span></tt> package.</p>
+<p>The answer is that Python 2.0&#8217;s <tt class="xref docutils literal"><span class="pre">xml</span></tt> package isn&#8217;t compatible with PyXML,
+but can be made compatible by installing a recent version PyXML. Many
+applications can get by with the XML support that is included with Python 2.0,
+but more complicated applications will require that the full PyXML package will
+be installed. When installed, PyXML versions 0.6.0 or greater will replace the
+<tt class="xref docutils literal"><span class="pre">xml</span></tt> package shipped with Python, and will be a strict superset of the
+standard package, adding a bunch of additional features. Some of the additional
+features in PyXML include:</p>
+<ul class="simple">
+<li>4DOM, a full DOM implementation from FourThought, Inc.</li>
+<li>The xmlproc validating parser, written by Lars Marius Garshol.</li>
+<li>The <tt class="xref docutils literal"><span class="pre">sgmlop</span></tt> parser accelerator module, written by Fredrik Lundh.</li>
+</ul>
+</div>
+</div>
+<div class="section" id="module-changes">
+<h2>Module changes<a class="headerlink" href="#module-changes" title="Permalink to this headline">¶</a></h2>
+<p>Lots of improvements and bugfixes were made to Python&#8217;s extensive standard
+library; some of the affected modules include <a title="(Unix) GNU readline support for Python." class="reference external" href="../library/readline.html#module-readline"><tt class="xref docutils literal"><span class="pre">readline</span></tt></a>,
+<a title="Configuration file parser." class="reference external" href="../library/configparser.html#module-ConfigParser"><tt class="xref docutils literal"><span class="pre">ConfigParser</span></tt></a>, <a title="Helpers for running Python scripts via the Common Gateway Interface." class="reference external" href="../library/cgi.html#module-cgi"><tt class="xref docutils literal"><span class="pre">cgi</span></tt></a>, <a title="Functions for working with calendars, including some emulation of the Unix cal program." class="reference external" href="../library/calendar.html#module-calendar"><tt class="xref docutils literal"><span class="pre">calendar</span></tt></a>, <a title="(Unix) The most common POSIX system calls (normally used via module os)." class="reference external" href="../library/posix.html#module-posix"><tt class="xref docutils literal"><span class="pre">posix</span></tt></a>, <a title="(Unix) GNU readline support for Python." class="reference external" href="../library/readline.html#module-readline"><tt class="xref docutils literal"><span class="pre">readline</span></tt></a>,
+<tt class="xref docutils literal"><span class="pre">xmllib</span></tt>, <a title="Read and write audio files in AIFF or AIFC format." class="reference external" href="../library/aifc.html#module-aifc"><tt class="xref docutils literal"><span class="pre">aifc</span></tt></a>, <tt class="xref docutils literal"><span class="pre">chunk,</span> <span class="pre">wave</span></tt>, <a title="Generate pseudo-random numbers with various common distributions." class="reference external" href="../library/random.html#module-random"><tt class="xref docutils literal"><span class="pre">random</span></tt></a>, <a title="Python object persistence." class="reference external" href="../library/shelve.html#module-shelve"><tt class="xref docutils literal"><span class="pre">shelve</span></tt></a>,
+and <a title="NNTP protocol client (requires sockets)." class="reference external" href="../library/nntplib.html#module-nntplib"><tt class="xref docutils literal"><span class="pre">nntplib</span></tt></a>. Consult the CVS logs for the exact patch-by-patch details.</p>
+<p>Brian Gallew contributed OpenSSL support for the <a title="Low-level networking interface." class="reference external" href="../library/socket.html#module-socket"><tt class="xref docutils literal"><span class="pre">socket</span></tt></a> module. OpenSSL
+is an implementation of the Secure Socket Layer, which encrypts the data being
+sent over a socket. When compiling Python, you can edit <tt class="docutils literal"><span class="pre">Modules/Setup</span></tt>
+to include SSL support, which adds an additional function to the <a title="Low-level networking interface." class="reference external" href="../library/socket.html#module-socket"><tt class="xref docutils literal"><span class="pre">socket</span></tt></a>
+module: <tt class="xref docutils literal"><span class="pre">socket.ssl(socket,</span> <span class="pre">keyfile,</span> <span class="pre">certfile)()</span></tt>, which takes a socket
+object and returns an SSL socket. The <a title="HTTP and HTTPS protocol client (requires sockets)." class="reference external" href="../library/httplib.html#module-httplib"><tt class="xref docutils literal"><span class="pre">httplib</span></tt></a> and <a title="Open an arbitrary network resource by URL (requires sockets)." class="reference external" href="../library/urllib.html#module-urllib"><tt class="xref docutils literal"><span class="pre">urllib</span></tt></a> modules
+were also changed to support &#8220;<a class="reference external" href="https://">https://</a>&#8221; URLs, though no one has implemented FTP
+or SMTP over SSL.</p>
+<p>The <a title="HTTP and HTTPS protocol client (requires sockets)." class="reference external" href="../library/httplib.html#module-httplib"><tt class="xref docutils literal"><span class="pre">httplib</span></tt></a> module has been rewritten by Greg Stein to support HTTP/1.1.
+Backward compatibility with the 1.5 version of <a title="HTTP and HTTPS protocol client (requires sockets)." class="reference external" href="../library/httplib.html#module-httplib"><tt class="xref docutils literal"><span class="pre">httplib</span></tt></a> is provided,
+though using HTTP/1.1 features such as pipelining will require rewriting code to
+use a different set of interfaces.</p>
+<p>The <a title="Interface to Tcl/Tk for graphical user interfaces" class="reference external" href="../library/tkinter.html#module-Tkinter"><tt class="xref docutils literal"><span class="pre">Tkinter</span></tt></a> module now supports Tcl/Tk version 8.1, 8.2, or 8.3, and
+support for the older 7.x versions has been dropped. The Tkinter module now
+supports displaying Unicode strings in Tk widgets. Also, Fredrik Lundh
+contributed an optimization which makes operations like <tt class="docutils literal"><span class="pre">create_line</span></tt> and
+<tt class="docutils literal"><span class="pre">create_polygon</span></tt> much faster, especially when using lots of coordinates.</p>
+<p>The <a title="An interface to the curses library, providing portable terminal handling." class="reference external" href="../library/curses.html#module-curses"><tt class="xref docutils literal"><span class="pre">curses</span></tt></a> module has been greatly extended, starting from Oliver
+Andrich&#8217;s enhanced version, to provide many additional functions from ncurses
+and SYSV curses, such as colour, alternative character set support, pads, and
+mouse support. This means the module is no longer compatible with operating
+systems that only have BSD curses, but there don&#8217;t seem to be any currently
+maintained OSes that fall into this category.</p>
+<p>As mentioned in the earlier discussion of 2.0&#8217;s Unicode support, the underlying
+implementation of the regular expressions provided by the <a title="Regular expression operations." class="reference external" href="../library/re.html#module-re"><tt class="xref docutils literal"><span class="pre">re</span></tt></a> module has
+been changed. SRE, a new regular expression engine written by Fredrik Lundh and
+partially funded by Hewlett Packard, supports matching against both 8-bit
+strings and Unicode strings.</p>
+</div>
+<div class="section" id="new-modules">
+<h2>New modules<a class="headerlink" href="#new-modules" title="Permalink to this headline">¶</a></h2>
+<p>A number of new modules were added. We&#8217;ll simply list them with brief
+descriptions; consult the 2.0 documentation for the details of a particular
+module.</p>
+<ul class="simple">
+<li><a title="Register and execute cleanup functions." class="reference external" href="../library/atexit.html#module-atexit"><tt class="xref docutils literal"><span class="pre">atexit</span></tt></a>: For registering functions to be called before the Python
+interpreter exits. Code that currently sets <tt class="docutils literal"><span class="pre">sys.exitfunc</span></tt> directly should be
+changed to use the <a title="Register and execute cleanup functions." class="reference external" href="../library/atexit.html#module-atexit"><tt class="xref docutils literal"><span class="pre">atexit</span></tt></a> module instead, importing <a title="Register and execute cleanup functions." class="reference external" href="../library/atexit.html#module-atexit"><tt class="xref docutils literal"><span class="pre">atexit</span></tt></a> and
+calling <a title="atexit.register" class="reference external" href="../library/atexit.html#atexit.register"><tt class="xref docutils literal"><span class="pre">atexit.register()</span></tt></a> with the function to be called on exit.
+(Contributed by Skip Montanaro.)</li>
+<li><a title="Encode and decode data and streams." class="reference external" href="../library/codecs.html#module-codecs"><tt class="xref docutils literal"><span class="pre">codecs</span></tt></a>, <tt class="xref docutils literal"><span class="pre">encodings</span></tt>, <a title="Access the Unicode Database." class="reference external" href="../library/unicodedata.html#module-unicodedata"><tt class="xref docutils literal"><span class="pre">unicodedata</span></tt></a>: Added as part of the new
+Unicode support.</li>
+<li><a title="Compare files efficiently." class="reference external" href="../library/filecmp.html#module-filecmp"><tt class="xref docutils literal"><span class="pre">filecmp</span></tt></a>: Supersedes the old <tt class="xref docutils literal"><span class="pre">cmp</span></tt>, <tt class="xref docutils literal"><span class="pre">cmpcache</span></tt> and
+<tt class="xref docutils literal"><span class="pre">dircmp</span></tt> modules, which have now become deprecated. (Contributed by Gordon
+MacMillan and Moshe Zadka.)</li>
+<li><a title="Multilingual internationalization services." class="reference external" href="../library/gettext.html#module-gettext"><tt class="xref docutils literal"><span class="pre">gettext</span></tt></a>: This module provides internationalization (I18N) and
+localization (L10N) support for Python programs by providing an interface to the
+GNU gettext message catalog library. (Integrated by Barry Warsaw, from separate
+contributions by Martin von Löwis, Peter Funk, and James Henstridge.)</li>
+<li><tt class="xref docutils literal"><span class="pre">linuxaudiodev</span></tt>: Support for the <tt class="docutils literal"><span class="pre">/dev/audio</span></tt> device on Linux, a
+twin to the existing <a title="(SunOS) Access to Sun audio hardware. (deprecated)" class="reference external" href="../library/sunaudio.html#module-sunaudiodev"><tt class="xref docutils literal"><span class="pre">sunaudiodev</span></tt></a> module. (Contributed by Peter Bosch,
+with fixes by Jeremy Hylton.)</li>
+<li><a title="Interface to memory-mapped files for Unix and Windows." class="reference external" href="../library/mmap.html#module-mmap"><tt class="xref docutils literal"><span class="pre">mmap</span></tt></a>: An interface to memory-mapped files on both Windows and Unix. A
+file&#8217;s contents can be mapped directly into memory, at which point it behaves
+like a mutable string, so its contents can be read and modified. They can even
+be passed to functions that expect ordinary strings, such as the <a title="Regular expression operations." class="reference external" href="../library/re.html#module-re"><tt class="xref docutils literal"><span class="pre">re</span></tt></a>
+module. (Contributed by Sam Rushing, with some extensions by A.M. Kuchling.)</li>
+<li><tt class="xref docutils literal"><span class="pre">pyexpat</span></tt>: An interface to the Expat XML parser. (Contributed by Paul
+Prescod.)</li>
+<li><a title="Loads a robots.txt file and answers questions about fetchability of other URLs." class="reference external" href="../library/robotparser.html#module-robotparser"><tt class="xref docutils literal"><span class="pre">robotparser</span></tt></a>: Parse a <tt class="docutils literal"><span class="pre">robots.txt</span></tt> file, which is used for writing
+Web spiders that politely avoid certain areas of a Web site. The parser accepts
+the contents of a <tt class="docutils literal"><span class="pre">robots.txt</span></tt> file, builds a set of rules from it, and
+can then answer questions about the fetchability of a given URL. (Contributed
+by Skip Montanaro.)</li>
+<li><a title="Tool for detecting white space related problems in Python source files in a directory tree." class="reference external" href="../library/tabnanny.html#module-tabnanny"><tt class="xref docutils literal"><span class="pre">tabnanny</span></tt></a>: A module/script to check Python source code for ambiguous
+indentation. (Contributed by Tim Peters.)</li>
+<li><a title="Class wrapper for string objects." class="reference external" href="../library/userdict.html#module-UserString"><tt class="xref docutils literal"><span class="pre">UserString</span></tt></a>: A base class useful for deriving objects that behave like
+strings.</li>
+<li><a title="Easy-to-use controller for Web browsers." class="reference external" href="../library/webbrowser.html#module-webbrowser"><tt class="xref docutils literal"><span class="pre">webbrowser</span></tt></a>: A module that provides a platform independent way to launch
+a web browser on a specific URL. For each platform, various browsers are tried
+in a specific order. The user can alter which browser is launched by setting the
+<em>BROWSER</em> environment variable. (Originally inspired by Eric S. Raymond&#8217;s patch
+to <a title="Open an arbitrary network resource by URL (requires sockets)." class="reference external" href="../library/urllib.html#module-urllib"><tt class="xref docutils literal"><span class="pre">urllib</span></tt></a> which added similar functionality, but the final module comes
+from code originally implemented by Fred Drake as
+<tt class="docutils literal"><span class="pre">Tools/idle/BrowserControl.py</span></tt>, and adapted for the standard library by
+Fred.)</li>
+<li><a title="(Windows) Routines and objects for manipulating the Windows registry." class="reference external" href="../library/_winreg.html#module-_winreg"><tt class="xref docutils literal"><span class="pre">_winreg</span></tt></a>: An interface to the Windows registry. <a title="(Windows) Routines and objects for manipulating the Windows registry." class="reference external" href="../library/_winreg.html#module-_winreg"><tt class="xref docutils literal"><span class="pre">_winreg</span></tt></a> is an
+adaptation of functions that have been part of PythonWin since 1995, but has now
+been added to the core distribution, and enhanced to support Unicode.
+<a title="(Windows) Routines and objects for manipulating the Windows registry." class="reference external" href="../library/_winreg.html#module-_winreg"><tt class="xref docutils literal"><span class="pre">_winreg</span></tt></a> was written by Bill Tutt and Mark Hammond.</li>
+<li><a title="Read and write ZIP-format archive files." class="reference external" href="../library/zipfile.html#module-zipfile"><tt class="xref docutils literal"><span class="pre">zipfile</span></tt></a>: A module for reading and writing ZIP-format archives. These
+are archives produced by <strong>PKZIP</strong> on DOS/Windows or <strong>zip</strong> on
+Unix, not to be confused with <strong>gzip</strong>-format files (which are
+supported by the <a title="Interfaces for gzip compression and decompression using file objects." class="reference external" href="../library/gzip.html#module-gzip"><tt class="xref docutils literal"><span class="pre">gzip</span></tt></a> module) (Contributed by James C. Ahlstrom.)</li>
+<li><a title="Manage and augment the import process. (deprecated)" class="reference external" href="../library/imputil.html#module-imputil"><tt class="xref docutils literal"><span class="pre">imputil</span></tt></a>: A module that provides a simpler way for writing customised
+import hooks, in comparison to the existing <tt class="xref docutils literal"><span class="pre">ihooks</span></tt> module. (Implemented
+by Greg Stein, with much discussion on python-dev along the way.)</li>
+</ul>
+</div>
+<div class="section" id="idle-improvements">
+<h2>IDLE Improvements<a class="headerlink" href="#idle-improvements" title="Permalink to this headline">¶</a></h2>
+<p>IDLE is the official Python cross-platform IDE, written using Tkinter. Python
+2.0 includes IDLE 0.6, which adds a number of new features and improvements. A
+partial list:</p>
+<ul class="simple">
+<li>UI improvements and optimizations, especially in the area of syntax
+highlighting and auto-indentation.</li>
+<li>The class browser now shows more information, such as the top level functions
+in a module.</li>
+<li>Tab width is now a user settable option. When opening an existing Python file,
+IDLE automatically detects the indentation conventions, and adapts.</li>
+<li>There is now support for calling browsers on various platforms, used to open
+the Python documentation in a browser.</li>
+<li>IDLE now has a command line, which is largely similar to the vanilla Python
+interpreter.</li>
+<li>Call tips were added in many places.</li>
+<li>IDLE can now be installed as a package.</li>
+<li>In the editor window, there is now a line/column bar at the bottom.</li>
+<li>Three new keystroke commands: Check module (Alt-F5), Import module (F5) and
+Run script (Ctrl-F5).</li>
+</ul>
+</div>
+<div class="section" id="deleted-and-deprecated-modules">
+<h2>Deleted and Deprecated Modules<a class="headerlink" href="#deleted-and-deprecated-modules" title="Permalink to this headline">¶</a></h2>
+<p>A few modules have been dropped because they&#8217;re obsolete, or because there are
+now better ways to do the same thing. The <tt class="xref docutils literal"><span class="pre">stdwin</span></tt> module is gone; it was
+for a platform-independent windowing toolkit that&#8217;s no longer developed.</p>
+<p>A number of modules have been moved to the <tt class="docutils literal"><span class="pre">lib-old</span></tt> subdirectory:
+<tt class="xref docutils literal"><span class="pre">cmp</span></tt>, <tt class="xref docutils literal"><span class="pre">cmpcache</span></tt>, <tt class="xref docutils literal"><span class="pre">dircmp</span></tt>, <tt class="xref docutils literal"><span class="pre">dump</span></tt>, <tt class="xref docutils literal"><span class="pre">find</span></tt>,
+<tt class="xref docutils literal"><span class="pre">grep</span></tt>, <tt class="xref docutils literal"><span class="pre">packmail</span></tt>, <tt class="xref docutils literal"><span class="pre">poly</span></tt>, <tt class="xref docutils literal"><span class="pre">util</span></tt>, <tt class="xref docutils literal"><span class="pre">whatsound</span></tt>,
+<tt class="xref docutils literal"><span class="pre">zmod</span></tt>. If you have code which relies on a module that&#8217;s been moved to
+<tt class="docutils literal"><span class="pre">lib-old</span></tt>, you can simply add that directory to <tt class="docutils literal"><span class="pre">sys.path</span></tt> to get them
+back, but you&#8217;re encouraged to update any code that uses these modules.</p>
+</div>
+<div class="section" id="acknowledgements">
+<h2>Acknowledgements<a class="headerlink" href="#acknowledgements" title="Permalink to this headline">¶</a></h2>
+<p>The authors would like to thank the following people for offering suggestions on
+various drafts of this article: David Bolen, Mark Hammond, Gregg Hauser, Jeremy
+Hylton, Fredrik Lundh, Detlef Lannert, Aahz Maruch, Skip Montanaro, Vladimir
+Marangozov, Tobias Polzin, Guido van Rossum, Neil Schemenauer, and Russ Schmidt.</p>
+</div>
+</div>
+
+
+ </div>
+ </div>
+ </div>
+ <div class="sphinxsidebar">
+ <div class="sphinxsidebarwrapper">
+ <h3><a href="../contents.html">Table Of Contents</a></h3>
+ <ul>
+<li><a class="reference external" href="">What&#8217;s New in Python 2.0</a><ul>
+<li><a class="reference external" href="#introduction">Introduction</a></li>
+<li><a class="reference external" href="#what-about-python-1-6">What About Python 1.6?</a></li>
+<li><a class="reference external" href="#new-development-process">New Development Process</a></li>
+<li><a class="reference external" href="#unicode">Unicode</a></li>
+<li><a class="reference external" href="#list-comprehensions">List Comprehensions</a></li>
+<li><a class="reference external" href="#augmented-assignment">Augmented Assignment</a></li>
+<li><a class="reference external" href="#string-methods">String Methods</a></li>
+<li><a class="reference external" href="#garbage-collection-of-cycles">Garbage Collection of Cycles</a></li>
+<li><a class="reference external" href="#other-core-changes">Other Core Changes</a><ul>
+<li><a class="reference external" href="#minor-language-changes">Minor Language Changes</a></li>
+<li><a class="reference external" href="#changes-to-built-in-functions">Changes to Built-in Functions</a></li>
+</ul>
+</li>
+<li><a class="reference external" href="#porting-to-2-0">Porting to 2.0</a></li>
+<li><a class="reference external" href="#extending-embedding-changes">Extending/Embedding Changes</a></li>
+<li><a class="reference external" href="#distutils-making-modules-easy-to-install">Distutils: Making Modules Easy to Install</a></li>
+<li><a class="reference external" href="#xml-modules">XML Modules</a><ul>
+<li><a class="reference external" href="#sax2-support">SAX2 Support</a></li>
+<li><a class="reference external" href="#dom-support">DOM Support</a></li>
+<li><a class="reference external" href="#relationship-to-pyxml">Relationship to PyXML</a></li>
+</ul>
+</li>
+<li><a class="reference external" href="#module-changes">Module changes</a></li>
+<li><a class="reference external" href="#new-modules">New modules</a></li>
+<li><a class="reference external" href="#idle-improvements">IDLE Improvements</a></li>
+<li><a class="reference external" href="#deleted-and-deprecated-modules">Deleted and Deprecated Modules</a></li>
+<li><a class="reference external" href="#acknowledgements">Acknowledgements</a></li>
+</ul>
+</li>
+</ul>
+
+ <h4>Previous topic</h4>
+ <p class="topless"><a href="2.1.html"
+ title="previous chapter">What&#8217;s New in Python 2.1</a></p>
+ <h4>Next topic</h4>
+ <p class="topless"><a href="../tutorial/index.html"
+ title="next chapter">The Python Tutorial</a></p>
+ <h3>This Page</h3>
+ <ul class="this-page-menu">
+ <li><a href="../_sources/whatsnew/2.0.txt"
+ rel="nofollow">Show Source</a></li>
+ </ul>
+ <div id="searchbox" style="display: none">
+ <h3>Quick search</h3>
+ <form class="search" action="../search.html" method="get">
+ <input type="text" name="q" size="18" />
+ <input type="submit" value="Go" />
+ <input type="hidden" name="check_keywords" value="yes" />
+ <input type="hidden" name="area" value="default" />
+ </form>
+ <p class="searchtip" style="font-size: 90%">
+ Enter search terms or a module, class or function name.
+ </p>
+ </div>
+ <script type="text/javascript">$('#searchbox').show(0);</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../genindex.html" title="General Index"
+ >index</a></li>
+ <li class="right" >
+ <a href="../modindex.html" title="Global Module Index"
+ >modules</a> |</li>
+ <li class="right" >
+ <a href="../tutorial/index.html" title="The Python Tutorial"
+ >next</a> |</li>
+ <li class="right" >
+ <a href="2.1.html" title="What’s New in Python 2.1"
+ >previous</a> |</li>
+ <li><img src="../_static/py.png" alt=""
+ style="vertical-align: middle; margin-top: -1px"/></li>
+ <li><a href="../index.html">Python v2.6.4c2 documentation</a> &raquo;</li>
+
+ <li><a href="index.html" >What&#8217;s New in Python</a> &raquo;</li>
+ </ul>
+ </div>
+ <div class="footer">
+ &copy; <a href="../copyright.html">Copyright</a> 1990-2009, Python Software Foundation.
+ <br />
+ The Python Software Foundation is a non-profit corporation.
+ <a href="http://www.python.org/psf/donations/">Please donate.</a>
+ <br />
+ Last updated on Oct 19, 2009.
+ Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 0.6.2.
+ </div>
+
+ </body>
+</html> \ No newline at end of file
diff --git a/help/application.html b/help/application.html
new file mode 100644
index 0000000..38ab0bf
--- /dev/null
+++ b/help/application.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<title>Untitled Document</title>
+<link href="CSS/Accessible_Design.css" rel="stylesheet" type="text/css" />
+
+</head>
+
+<body>
+<h1>What is an XO Activity? </h1>
+<p>The software which defines a &quot;Sugar Activity&quot; is totally contained in a directory and it's subdirectories. The name of this root directory describes the activity and ends with the &quot;.activity&quot; suffix (as an example, the command line activity is contained in the &quot;Terminal.activity&quot; subdirectory). Examine the files and folders that are installed on your machine by clicking on the middle box on the left side of the project page. </p>
+<h3>Activity bundles </h3>
+For easy distribution and installation, there is a well defined bundling process which creates a zipped image of the files under the activity root, and names the resulting file in the formaat: &lt;some name&gt;&lt;some version number&gt;&quot;.XO&quot;. The software platform on the XO supports the automatic installation of these bundled (or XO zipped files) into a parent directory that may change from one revision of the operating system to the next. So current location of installed directories is &quot;/home/olpc/Activities&quot;.
+<p>These activity bundles can come from at least three distinct sources:
+
+<li type="circle">Many come loaded along with the operating system itself.
+<li type="circle">The user can browse the web, and download activities from web sites sponsored by OLPC. The browser that downloads the XO zipped file puts it into the Journal. Then it can be &quot;Resumed&quot; from the journal, which actually unzips and installs it. </li>
+<li>If the user collaborates with a buddy who has a new activitiy, the act of joining an activity which is loaded on the buddy's machine, but not on one's own machine, causes that activity to be transfered over and installed on the local machine. </li>
+<p>&nbsp;</p>
+<h1>Project Page -- The basic services of the XO</h1><img class = "right" src="images/project_whole.jpg" width="400" height="300" alt="Project Page" />
+<p>The Project Page is divided vertically into two halves. The left side includes various sources and destinations where your program can reside. The right side shows the contents of the activity.info file and the collection of files that make up your application. The right side of the screen can be thought of as a sand box or playpen where your program can act, misbehave, and show all its &quot;bugs&quot;. As you develop the python programs that make up your activity you may want to save it fairly often just in case one of your ideas turns out to be a blind alley.</p>
+<p>The top box on the left side represents the journal. At any time you can save the current state of your program to the Journal. You do this by clicking on the left arrow between the Journal box and the playpen. The process of creating a bundle is computer intensive and slow, but the end result conserves space on the disk, and bandwidth when the activity is being shared across the network. When you do this it is saved in the bundled format mentioned above.</p>
+<p><img class="left" src="images/journal.jpg" alt="journal" width="400" height="254" /> </p>
+<p>When you click on the right arrow, you are instructing the debugger to load an XO file into the workspace. This will replace any activity that is already occupying the workspace. The checksum of the activity that is about to be overwritten will be checked against the checksum stored away the last time the activity was saved. If there have been changes since the last save, a notification will be presented before any changes are lost. </p>
+<p>The middle box initially labeled /home/olpc/Activities/. This is a list of all the Activities that are loaded on your XO. You can highlight any of these activities and load it into the workarea of the debugger. Then if you click on the edit tab, you will find that up to five python program files are automatically loaded. The /home/olpc/Activities/ directory, is read-only. You do not have sufficient permissions to write to this location. <img src="images/project page_3.png" alt="Activities Directory" width="643" height="303" /></p>
+<p>By clicking the &quot;home&quot; button, the user can switch to a location where storing data is permitted. In Unix computers, this place to store your own files, is sometimes called the &quot;home&quot; directory. When your home directory is displayed, the &quot;left arrow&quot; is visible, and the debugger is able to copy your whole directory tree, in the full unzipped form. Limited only by your total disk space you can keep any number of activity trees in your home directory. The &quot;home&quot; button toggles between the &quot;installed Activity&quot; directory and the &quot;home&quot; directory.</p>
+<p>The Examples box provides a set of templates and features of the XO which are chosen to be helpful toward the objective of developing activities.<img src="images/project page_2.png" alt="Examples" width="636" height="192" /> </p>
+<p>The workspace for the Activity under development is the right side of the screen:<img class= "right" src="images/project page.png" alt="playpen" width="586" height="817" /> </p>
+<p>The project name will be used as the first part of the root directory for your activity. In order to function properly, the second part of the root durectory will be set automatically by the debugger to &quot;.activity&quot;. The version is included in the XO file name, and displayed in the journal. It should be changed whenever you make a significant change to the program. </p>
+<p>The Unique ID must be some string of characters that is that: unique. This will be used by the dbus session manager to identify your activity and service it properly. The OLPC developers suggest that you use a url that you own, or the prefix &quot;org.laptop&quot; plus a name that you place in the OLPC git repository. </p>
+<p>To start up properly, using the standard desktop, the start-up script needs the name of the module, and the class which will start your activity. This will probably be the class you write which sub-classes the &quot;sugar.activity.activity.Activity&quot; which is the starting point for most activitiies. </p>
+<p>Your activity needs a &quot;SVG&quot; icon to represent it on the desktop. This needs to be placed in the &quot;activity.info&quot; sub directory under the root or your Activity. </p>
+<p>The activity size and bundled size give you some indication of the size on disk, and the size for transmission when your activity is being shared with other XO's over the network.</p>
+<p>The hostname and port fields and not useful debugging using a single XO machine. They should only be changed when two XO's are begin used to debug a program. In this case, you should enter the child's ip address into these fields on the parent machine.</p>
+<h1>Editing Python programs</h1>
+<p><img class = "right" src="file:///MacintoshHD/Users/ghunt/Pictures/screenshots_pydebug/Edit Page.jpg" width="400" height="300" alt="Edit Page" />When you load an Activity into the PyDebug workspace, the Editor will automatically load the 5 largest python programs, (those filenames ending with &quot;.py&quot;) from the root Activity directory. Whenever you start running your program, before the first breakpoint is reached, any changes that you have made to your programs will be saved to the disk. If you do not want this automatic saving of changes, you should click on the &quot;X&quot; on the tab of the file that you do not want to save, and answer no to the alert asking whether you want the program to be saved. If you do not have permissions to write a file, perhaps you have cut and pasted from an installed Activity, the debugger will not write any changes, and will not issue any error messages. </p>
+<p>One of the most productive ways to program is to find programs that do approximately what you want your program to do. Then cut and paste that small portion of code into yours, and modify it to do what you want. Often, when you use cut and paste, you will need to change variable names. For this, use the find and replace (magnifier icon). </p>
+
+<h1>Running programs</h1>
+<p><img class="right" src="file:///MacintoshHD/Users/ghunt/Pictures/screenshots_pydebug/Terminal_Ipython Page.jpg" width="400" height="300" alt="termina page" />From the project page, click on the &quot;Run Program&quot; icon. Or if your have already changed to the &quot;Activity&quot; tab, you can type &quot;sugarun&quot; or the shorter alias &quot;sug&quot;. This will start your program as a sugar activity, if possble, and stop it at the first &quot;import&quot; statement. </p>
+<p>At that point you can enter a &quot;c&quot; for &quot;continue&quot;, and the program will continue until it finishes or until it encounters an unhandled exception. Alternatively you can set &quot;b&quot;reakpoints, &quot;s&quot;tep, or make the call and return to the &quot;n&quot;ext statement in the current routine. </p>
+<h3>Switching between the text-mode and graphical screens </h3>
+<p>Use &lt;alt&gt;-&lt;tab&gt; to switch between the graphical output page created by your application, and the text-mode debugging screen of the PyDebug Activity. </p>
+<p>The original plan, at this point not entirely abandoned, was to have your graphical output be visible as the third tab of the main Toolbar. At this point this objective seems less important than other objectives. </p>
+<h1>Getting help </h1>
+<p>The help section of PyDebug is drawn from many web sites and includes useful information and documentation.</p>
+<p>One of the most useful sources of information is the python programs themselves that exist on your XO. The XXX icon on the help page starts up a local html server called pydoc. This will give you summary information and how to interface with all the sugar programs.</p>
+<p>For people who have some knowledge of programming, but are new to python, the &quot;DIVE INTO PYTHON&quot; is a short introduction to the python programming language. </p>
+</body>
+</html>
diff --git a/help/byteofpython/read/about-the-author.html b/help/byteofpython/read/about-the-author.html
new file mode 100644
index 0000000..9108c02
--- /dev/null
+++ b/help/byteofpython/read/about-the-author.html
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>About the Author</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="about.html" title="Appendix B. About" /><link rel="prev" href="about.html" title="Appendix B. About" /><link rel="next" href="revhistory.html" title="Appendix C. Revision History" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">About the Author</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="about.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Appendix B. About</th><td width="20%" align="right"> <a accesskey="n" href="revhistory.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="about-the-author"></a>About the Author</h2></div></div></div><p>
+ Swaroop C H loves his job which is being a software developer at Yahoo! in the
+ Bangalore office in India. His interests on the technological side
+ include FLOSS such as Linux, DotGNU, Qt and MySQL, great languages like Python
+ and C#, writing stuff like this book and any software he can create in his
+ spare time, as well as writing his blog. His other interests include coffee,
+ reading Robert Ludlum novels, trekking and politics.
+ </p><p>
+ If you are still to interested to know more about this guy, check out his
+ blog at <a href="http://www.swaroopch.info" target="_top">www.swaroopch.info</a> .
+ </p></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="about.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="about.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="revhistory.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Appendix B. About </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Appendix C. Revision History</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/about.html b/help/byteofpython/read/about.html
new file mode 100644
index 0000000..1e93ff4
--- /dev/null
+++ b/help/byteofpython/read/about.html
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Appendix B. About</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="index.html" title="A Byte of Python" /><link rel="prev" href="floss.html" title="Appendix A. Free/Libré and Open Source Software (FLOSS)" /><link rel="next" href="about-the-author.html" title="About the Author" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Appendix B. About</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="floss.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="about-the-author.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="appendix" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title"><a id="about"></a>Appendix B. About</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="about.html#colophon">Colophon</a></span></dt><dt><span class="section"><a href="about-the-author.html">About the Author</a></span></dt></dl></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="colophon"></a>Colophon</h2></div></div></div><p>
+ Almost all of the software that I have used in the creation of this
+ book are <span class="emphasis"><em>free and open source software</em></span>. In the
+ first draft of this book, I had used Red Hat 9.0 Linux as the foundation
+ of my setup and now for this sixth draft, I am using Fedora Core 3 Linux
+ as the basis of my setup.
+ </p><p>
+ Initially, I was using KWord to write the book (as explained in the
+ <a href="history-lesson.html" title="History Lesson">History Lesson</a> in the preface). Later,
+ I switched to DocBook XML using Kate but I found it too tedious. So, I
+ switched to OpenOffice which was just excellent with the level of control
+ it provided for formatting as well as the PDF generation, but it produced
+ very sloppy HTML from the document. Finally, I discovered XEmacs and I rewrote
+ the book from scratch in DocBook XML (again) after I decided that this format
+ was the long term solution. In this new sixth draft, I decided to use Quanta+
+ to do all the editing.
+ </p><p>
+ The standard XSL stylesheets that came with Fedora Core 3 Linux are being used.
+ The standard default fonts are used as well. The standard fonts are used as well.
+ However, I have written a CSS document to give color and style to the HTML pages.
+ I have also written a crude lexical analyzer, in Python of course, which
+ automatically provides syntax highlighting to all the program listings.
+ </p></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="floss.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="about-the-author.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Appendix A. Free/Libré and Open Source Software (FLOSS) </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> About the Author</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/assert-statement.html b/help/byteofpython/read/assert-statement.html
new file mode 100644
index 0000000..c0e27d7
--- /dev/null
+++ b/help/byteofpython/read/assert-statement.html
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>The assert statement</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="more-python.html" title="Chapter 15. More Python" /><link rel="prev" href="exec-statement.html" title="The exec and eval statements" /><link rel="next" href="repr-function.html" title="The repr function" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">The assert statement</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="exec-statement.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 15. More Python</th><td width="20%" align="right"> <a accesskey="n" href="repr-function.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="assert-statement"></a>The assert statement</h2></div></div></div><p>
+
+ The <code class="literal">assert</code> statement is used to assert that something is true. For
+ example, if you are very sure that you will have at least one element in a list you are
+ using and want to check this, and raise an error if it is not true, then
+ <code class="literal">assert</code> statement is ideal in this situation. When the assert
+ statement fails, an <code class="classname">AssertionError</code> is raised.
+
+ </p><pre class="screen">
+
+&gt;&gt;&gt; mylist = ['item']
+&gt;&gt;&gt; assert len(mylist) &gt;= 1
+&gt;&gt;&gt; mylist.pop()
+'item'
+&gt;&gt;&gt; assert len(mylist) &gt;= 1
+Traceback (most recent call last):
+ File "&lt;stdin&gt;", line 1, in ?
+AssertionError
+
+ </pre></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="exec-statement.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="more-python.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="repr-function.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">The exec and eval statements </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> The repr function</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/basics-summary.html b/help/byteofpython/read/basics-summary.html
new file mode 100644
index 0000000..5627ba6
--- /dev/null
+++ b/help/byteofpython/read/basics-summary.html
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Summary</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="basics.html" title="Chapter 4. The Basics" /><link rel="prev" href="indentation.html" title="Indentation" /><link rel="next" href="operators-expressions.html" title="Chapter 5. Operators and Expressions" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Summary</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="indentation.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 4. The Basics</th><td width="20%" align="right"> <a accesskey="n" href="operators-expressions.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="basics-summary"></a>Summary</h2></div></div></div><p>
+
+ Now that we have gone through many nitty-gritty details, we can move on to more
+ interesting stuff such as control flow statements. Be sure to become comfortable with
+ what you have read in this chapter.
+
+ </p></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="indentation.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="basics.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="operators-expressions.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Indentation </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Chapter 5. Operators and Expressions</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/basics.html b/help/byteofpython/read/basics.html
new file mode 100644
index 0000000..1148e6e
--- /dev/null
+++ b/help/byteofpython/read/basics.html
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Chapter 4. The Basics</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="index.html" title="A Byte of Python" /><link rel="prev" href="first-steps-summary.html" title="Summary" /><link rel="next" href="numbers.html" title="Numbers" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 4. The Basics</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="first-steps-summary.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="numbers.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="chapter" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title"><a id="basics"></a>Chapter 4. The Basics</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="basics.html#literal-constants">Literal Constants</a></span></dt><dt><span class="section"><a href="numbers.html">Numbers</a></span></dt><dt><span class="section"><a href="strings.html">Strings</a></span></dt><dt><span class="section"><a href="variables.html">Variables</a></span></dt><dt><span class="section"><a href="identifier.html">Identifier Naming</a></span></dt><dt><span class="section"><a href="data-types.html">Data Types</a></span></dt><dt><span class="section"><a href="data-type-object.html">Objects</a></span></dt><dd><dl><dt><span class="section"><a href="data-type-object.html#id3052938">Output</a></span></dt><dt><span class="section"><a href="data-type-object.html#id3052959">How It Works</a></span></dt></dl></dd><dt><span class="section"><a href="logical-and-physical-lines.html">Logical and Physical Lines</a></span></dt><dt><span class="section"><a href="indentation.html">Indentation</a></span></dt><dt><span class="section"><a href="basics-summary.html">Summary</a></span></dt></dl></div><p>
+
+ Just printing 'Hello World' is not enough, is it? You want to do more than that - you
+ want to take some input, manipulate it and get something out of it. We can achieve this
+ in Python using constants and variables.
+
+ </p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="literal-constants"></a>Literal Constants</h2></div></div></div><p>
+
+ An example of a literal constant is a number like <code class="literal">5</code>,
+ <code class="literal">1.23</code>, <code class="literal">9.25e-3</code> or a string like
+ <code class="literal">'This is a string'</code> or <code class="literal">"It's a string!"</code>.
+ It is called a literal because it is <span class="emphasis"><em>literal</em></span> - you use its value
+ literally. The number <code class="literal">2</code> always represents itself and nothing else - it
+ is a constant because its value cannot be changed. Hence, all these are referred to as
+ literal constants.
+
+ </p></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="first-steps-summary.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="numbers.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Summary </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Numbers</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/break-statement.html b/help/byteofpython/read/break-statement.html
new file mode 100644
index 0000000..a2a5087
--- /dev/null
+++ b/help/byteofpython/read/break-statement.html
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>The break statement</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="control-flow.html" title="Chapter 6. Control Flow" /><link rel="prev" href="for-loop.html" title="The for loop" /><link rel="next" href="continue-statement.html" title="The continue statement" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">The break statement</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="for-loop.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 6. Control Flow</th><td width="20%" align="right"> <a accesskey="n" href="continue-statement.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="break-statement"></a>The break statement</h2></div></div></div><p>
+
+ The <code class="literal">break</code> statement is used to <span class="emphasis"><em>break</em></span> out of a
+ loop statement i.e. stop the execution of a looping statement, even if the loop condition
+ has not become <code class="literal">False</code> or the sequence of items has been completely
+ iterated over.
+
+ </p><p>
+
+ An important note is that if you <span class="emphasis"><em>break</em></span> out of a <code class="literal">for</code>
+ or <code class="literal">while</code> loop, any corresponding loop <code class="literal">else</code> block is
+ <span class="bold"><strong>not</strong></span> executed.
+
+ </p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="id3059485"></a>Using the break statement</h3></div></div></div><div class="example"><a id="using-break-statement"></a><p class="title"><b>Example 6.4. Using the break statement</b></p><pre class="programlisting">
+
+<span class="py-comment">#!/usr/bin/python</span>
+<span class="py-comment"># Filename: break.py</span>
+
+<span class="py-statement">while</span> <span class="py-builtin">True</span>:
+ s = <span class="py-builtin">raw_input</span>(<span class="py-string">'Enter something : '</span>)
+ <span class="py-statement">if</span> s == <span class="py-string">'quit'</span>:
+ <span class="py-statement">break</span>
+ <span class="py-statement">print</span> <span class="py-string">'Length of the string is'</span>, <span class="py-builtin">len</span>(s)
+<span class="py-statement">print</span> <span class="py-string">'Done'</span>
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3059507"></a>Output</h4></div></div></div><pre class="screen">
+
+$ python break.py
+Enter something : Programming is fun
+Length of the string is 18
+Enter something : When the work is done
+Length of the string is 21
+Enter something : if you wanna make your work also fun:
+Length of the string is 37
+Enter something : use Python!
+Length of the string is 12
+Enter something : quit
+Done
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3059526"></a>How It Works</h4></div></div></div><p>
+
+ In this program, we repeatedly take the user's input and print the length
+ of each input each time. We are providing a special condition to stop
+ the program by checking if the user input is <code class="literal">'quit'</code>.
+ We stop the program by <span class="emphasis"><em>break</em></span>ing out of the loop
+ and reach the end of the program.
+
+ </p><p>
+
+ The length of the input string can be found out using the built-in
+ <code class="function">len</code> function.
+
+ </p><p>
+
+ Remember that the <code class="literal">break</code> statement can be used with
+ the <code class="literal">for</code> loop as well.
+
+ </p></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3058324"></a>G2's Poetic Python</h4></div></div></div><p>
+
+ The input I have used here is a mini poem I have written called
+ <span class="bold"><strong>G2's Poetic Python</strong></span>:
+
+ </p><pre class="screen">
+Programming is fun
+When the work is done
+if you wanna make your work also fun:
+ use Python!
+ </pre></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="for-loop.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="control-flow.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="continue-statement.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">The for loop </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> The continue statement</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/byte-compiled.html b/help/byteofpython/read/byte-compiled.html
new file mode 100644
index 0000000..89bedb5
--- /dev/null
+++ b/help/byteofpython/read/byte-compiled.html
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Byte-compiled .pyc files</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="modules.html" title="Chapter 8. Modules" /><link rel="prev" href="modules.html" title="Chapter 8. Modules" /><link rel="next" href="from-import.html" title="The from..import statement" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Byte-compiled .pyc files</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="modules.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 8. Modules</th><td width="20%" align="right"> <a accesskey="n" href="from-import.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="byte-compiled"></a>Byte-compiled .pyc files</h2></div></div></div><p>
+
+ Importing a module is a relatively costly affair, so Python does some tricks to make
+ it faster. One way is to create <span class="emphasis"><em>byte-compiled</em></span> files with the extension
+ <code class="filename">.pyc</code> which is related to the intermediate form that Python transforms
+ the program into (remember the <a href="features-of-python.html#python-vm">intro section on how Python
+ works</a> ?). This <code class="filename">.pyc</code> file is useful when you import the module the
+ next time from a different program - it will be much faster since part of the processing
+ required in importing a module is already done. Also, these byte-compiled files are
+ platform-independent. So, now you know what those <code class="filename">.pyc</code> files really are.
+
+ </p></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="modules.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="modules.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="from-import.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 8. Modules </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> The from..import statement</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/byte.css b/help/byteofpython/read/byte.css
new file mode 100644
index 0000000..0302016
--- /dev/null
+++ b/help/byteofpython/read/byte.css
@@ -0,0 +1,121 @@
+/*
+ * Filename : byte.css
+ * Details : CSS document for the book "A Byte of Python"
+ * Website : www.byteofpython.info
+ * Copyright: Swaroop C H (c) 2004
+ * License : Creative Commons License. See book for more details.
+ * Note : Indispensable tools in the creation of this document
+ * include KColorChooser and XEmacs.
+ */
+
+body {
+ font-size:12pt;
+}
+
+div.header {
+ text-align:center;
+}
+
+a.header-link {
+ text-decoration:none;
+ color:#663300;
+ font-family:sans-serif;
+}
+
+a.header-link:hover {
+ text-decoration:underline;
+}
+
+h1.title {
+ font-size:40pt;
+ text-align:center;
+ background-color:#FFFED3;
+ border-left:1px solid #DBDAB5;
+ border-right:1px solid #DBDAB5;
+ border-top:1px solid #DBDAB5;
+ padding:5px;
+ margin-top:10px;
+}
+
+div.author {
+ font-size:16pt;
+ text-align:center;
+ background-color:#FFFED3;
+ border-left:1px solid #DBDAB5;
+ border-right:1px solid #DBDAB5;
+ border-bottom:1px solid #DBDAB5;
+ padding:5px;
+}
+
+p.releaseinfo {
+ font-weight:bold;
+}
+
+h2 {
+ color:#663300;
+}
+
+h1, h2, h3, h4, h5, h6, div.affiliation {
+ margin:0px;
+ font-family:sans-serif;
+}
+
+pre.programlisting {
+ background-color:#FFFFCC;
+ border:1px solid #D8D8AD;
+ padding:5px;
+ margin-left:3%;
+ margin-right:3%;
+}
+
+pre.screen {
+ background-color:#FFEFEF;
+ border:1px solid #D8CACB;
+ padding:5px;
+ margin-left:3%;
+ margin-right:3%;
+}
+
+div.caution, div.important, div.note {
+ background-color:#E6E6FF;
+ border:1px solid #C7C7DD;
+ padding:5px;
+ margin-top:10px;
+ margin-bottom:10px;
+}
+
+span.py-statement {
+ color:red;
+}
+
+span.py-number {
+ color:#6721A8;
+}
+
+span.py-builtin {
+ color:#A80000;
+}
+
+span.py-string {
+ color:#9B30FF; /* purple1 */
+}
+
+span.py-escape-sequence {
+ color:#AA00AA;
+}
+
+span.py-conditional {
+ color:red;
+}
+
+span.py-loop {
+ color:red;
+}
+
+span.py-comment {
+ color:blue;
+}
+
+span.py-identifier {
+ color:#A26811;
+}
diff --git a/help/byteofpython/read/choosing-an-editor.html b/help/byteofpython/read/choosing-an-editor.html
new file mode 100644
index 0000000..82f406d
--- /dev/null
+++ b/help/byteofpython/read/choosing-an-editor.html
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Choosing an Editor</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="first-steps.html" title="Chapter 3. First Steps" /><link rel="prev" href="interpreter-prompt.html" title="Using the interpreter prompt" /><link rel="next" href="source-file.html" title="Using a Source File" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Choosing an Editor</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="interpreter-prompt.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 3. First Steps</th><td width="20%" align="right"> <a accesskey="n" href="source-file.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="choosing-an-editor"></a>Choosing an Editor</h2></div></div></div><p>
+
+ Before we move on to writing Python programs in source files, we need an editor
+ to write the source files. The choice of an editor is crucial indeed. You have
+ to choose an editor as you would choose a car you would buy. A good editor will
+ help you write Python programs easily, making your journey more comfortable and
+ helps you reach your destination (achieve your goal) in a much faster and safer
+ way.
+
+ </p><p>
+
+ One of the very basic requirements is <span class="bold"><strong>syntax
+ highlighting</strong></span> where all the different parts of your Python program are
+ colorized so that you can <span class="emphasis"><em>see</em></span> your program and visualize its
+ running.
+
+ </p><p>
+
+ If you are using Windows, then I suggest that you use IDLE. IDLE does syntax highlighting
+ and a lot more such as allowing you to run your programs within IDLE among other things.
+ A special note: <span class="bold"><strong>don't use Notepad</strong></span> - it is a bad choice
+ because it does not do syntax highlighting and also importantly it does not support
+ indentation of the text which is very important in our case as we will see later. Good
+ editors such as IDLE (and also VIM) will automatically help you do this.
+
+ </p><p>
+
+ If you are using Linux/FreeBSD, then you have a lot of choices for an editor. If you are
+ an experienced programmer, then you must be already using <span class="application">VIM</span>
+ or <span class="application">Emacs</span>. Needless to say, these are two of the most powerful
+ editors and you will be benefitted by using them to write your Python programs. I
+ personally use <span class="application">VIM</span> for most of my programs. If you are a
+ beginner programmer, then you can use <span class="application">Kate</span> which is one of my
+ favorites. In case you are willing to take the time to learn VIM or Emacs, then I highly
+ recommend that you do learn to use either of them as it will be very useful for you in
+ the long run.
+
+ </p><p>
+
+ If you still want to explore other choices of an editor, see the comprehensive
+ <a href="http://www.python.org/cgi-bin/moinmoin/PythonEditors" target="_top">list of Python
+ editors</a> and make your choice. You can also choose an
+ <span class="acronym">IDE</span> (Integrated Development Environment) for Python. See the
+ comprehensive <a href="http://www.python.org/cgi-bin/moinmoin/IntegratedDevelopmentEnvironments" target="_top">list of IDEs that support Python</a> for more details. Once you start writing
+ large Python programs, IDEs can be very useful indeed.
+
+ </p><p>
+
+ I repeat once again, please choose a proper editor - it can make writing Python
+ programs more fun and easy.
+
+ </p></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="interpreter-prompt.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="first-steps.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="source-file.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Using the interpreter prompt </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Using a Source File</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/class-and-object-vars.html b/help/byteofpython/read/class-and-object-vars.html
new file mode 100644
index 0000000..0a481be
--- /dev/null
+++ b/help/byteofpython/read/class-and-object-vars.html
@@ -0,0 +1,186 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Class and Object Variables</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="oops.html" title="Chapter 11. Object-Oriented Programming" /><link rel="prev" href="class-init.html" title="The __init__ method" /><link rel="next" href="inheritance.html" title="Inheritance" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Class and Object Variables</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="class-init.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 11. Object-Oriented Programming</th><td width="20%" align="right"> <a accesskey="n" href="inheritance.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="class-and-object-vars"></a>Class and Object Variables</h2></div></div></div><p>
+
+ We have already discussed the functionality part of classes and objects, now we'll see the
+ data part of it. Actually, they are nothing but ordinary variables which are
+ <span class="emphasis"><em>bound</em></span> to the classes and objects <span class="bold"><strong>namespaces</strong></span>
+ i.e. the names are valid within the context of these classes and objects only.
+
+ </p><p>
+
+ There are two types of <span class="emphasis"><em>fields</em></span> - class variables and object variables
+ which are classified depending on whether the class or the object <span class="emphasis"><em>owns</em></span>
+ the variables respectively.
+
+ </p><p>
+
+ <span class="emphasis"><em>Class variables</em></span> are shared in the sense that they are accessed by all
+ objects (instances) of that class. There is only copy of the class variable and when any one
+ object makes a change to a class variable, the change is reflected in all the other instances
+ as well.
+
+ </p><p>
+
+ <span class="emphasis"><em>Object variables</em></span> are owned by each individual object/instance of the
+ class. In this case, each object has its own copy of the field i.e. they are not shared
+ and are not related in any way to the field by the samen name in a different instance of
+ the same class. An example will make this easy to understand.
+
+ </p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="using-class-and-obj-vars"></a>Using Class and Object Variables</h3></div></div></div><div class="example"><a id="id3072746"></a><p class="title"><b>Example 11.4. Using Class and Object Variables</b></p><pre class="programlisting">
+
+<span class="py-comment">#!/usr/bin/python</span>
+<span class="py-comment"># Filename: objvar.py</span>
+
+<span class="py-statement">class</span> <span class="py-identifier">Person</span>:
+ <span class="py-string">'''Represents a person.'''</span>
+ population = <span class="py-number">0</span>
+
+ <span class="py-statement">def</span> <span class="py-identifier">__init__</span>(<span class="py-builtin">self</span>, name):
+ <span class="py-string">'''Initializes the person's data.'''</span>
+ <span class="py-builtin">self</span>.name = name
+ <span class="py-statement">print</span> <span class="py-string">'(Initializing %s)'</span> % <span class="py-builtin">self</span>.name
+
+ <span class="py-comment"># When this person is created, he/she</span>
+ <span class="py-comment"># adds to the population</span>
+ Person.population += <span class="py-number">1</span>
+
+ <span class="py-statement">def</span> <span class="py-identifier">__del__</span>(<span class="py-builtin">self</span>):
+ <span class="py-string">'''I am dying.'''</span>
+ <span class="py-statement">print</span> <span class="py-string">'%s says bye.'</span> % <span class="py-builtin">self</span>.name
+
+ Person.population -= <span class="py-number">1</span>
+
+ <span class="py-statement">if</span> Person.population == <span class="py-number">0</span>:
+ <span class="py-statement">print</span> <span class="py-string">'I am the last one.'</span>
+ <span class="py-statement">else</span>:
+ <span class="py-statement">print</span> <span class="py-string">'There are still %d people left.'</span> % Person.population
+
+ <span class="py-statement">def</span> <span class="py-identifier">sayHi</span>(<span class="py-builtin">self</span>):
+ <span class="py-string">'''Greeting by the person.
+
+ Really, that's all it does.'''</span>
+ <span class="py-statement">print</span> <span class="py-string">'Hi, my name is %s.'</span> % <span class="py-builtin">self</span>.name
+
+ <span class="py-statement">def</span> <span class="py-identifier">howMany</span>(<span class="py-builtin">self</span>):
+ <span class="py-string">'''Prints the current population.'''</span>
+ <span class="py-statement">if</span> Person.population == <span class="py-number">1</span>:
+ <span class="py-statement">print</span> <span class="py-string">'I am the only person here.'</span>
+ <span class="py-statement">else</span>:
+ <span class="py-statement">print</span> <span class="py-string">'We have %d persons here.'</span> % Person.population
+
+swaroop = Person(<span class="py-string">'Swaroop'</span>)
+swaroop.sayHi()
+swaroop.howMany()
+
+kalam = Person(<span class="py-string">'Abdul Kalam'</span>)
+kalam.sayHi()
+kalam.howMany()
+
+swaroop.sayHi()
+swaroop.howMany()
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3072759"></a>Output</h4></div></div></div><pre class="screen">
+
+$ python objvar.py
+(Initializing Swaroop)
+Hi, my name is Swaroop.
+I am the only person here.
+(Initializing Abdul Kalam)
+Hi, my name is Abdul Kalam.
+We have 2 persons here.
+Hi, my name is Swaroop.
+We have 2 persons here.
+Abdul Kalam says bye.
+There are still 1 people left.
+Swaroop says bye.
+I am the last one.
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3072771"></a>How It Works</h4></div></div></div><p>
+
+ This is a long example but helps demonstrate the nature of class and
+ object variables. Here, <code class="varname">population</code> belongs to the
+ <code class="classname">Person</code> class and hence is a class variable.
+ The <code class="varname">name</code> variable belongs to the object (it is
+ assigned using <code class="literal">self</code>) and hence is an object variable.
+
+ </p><p>
+
+ Thus, we refer to the <code class="varname">population</code> class variable as
+ <code class="varname">Person.population</code> and not as
+ <code class="varname">self.population</code>. Note that an object variable with
+ the same name as a class variable will hide the class variable!
+ We refer to the object variable <code class="varname">name</code> using
+ <code class="varname">self.name</code> notation in the methods of that object.
+ Remember this simple difference between class and object variables.
+
+ </p><p>
+
+ Observe that the <code class="methodname">__init__</code> method is used to
+ initialize the <code class="classname">Person</code> instance with a name.
+ In this method, we increase the <code class="varname">population</code> count by
+ 1 since we have one more person being added. Also observe that the values
+ of <code class="varname">self.name</code> is specific to each object which
+ indicates the nature of object variables.
+
+ </p><p>
+
+ Remember, that you must refer to the variables and methods of the same
+ object using the <code class="varname">self</code> variable
+ <span class="bold"><strong>only</strong></span>. This is called an
+ <span class="emphasis"><em>attribute reference</em></span>.
+
+ </p><p>
+
+ In this program, we also see the use of
+ <span class="bold"><strong>docstrings</strong></span> for classes as well as methods.
+ We can access the class docstring at runtime using
+ <code class="varname">Person.__doc__</code> and the method docstring as
+ <code class="varname">Person.sayHi.__doc__</code>
+
+ </p><p>
+
+ Just like the <code class="methodname">__init__</code> method, there is another
+ special method <code class="methodname">__del__</code> which is called when an
+ object is going to die i.e. it is no longer being used and is being returned
+ to the system for reusing that piece of memory. In this method, we simply
+ decrease the <code class="varname">Person.population</code> count by 1.
+
+ </p><p>
+
+ The <code class="methodname">__del__</code> method is run when the object is no longer
+ in use and there is no guarantee <span class="emphasis"><em>when</em></span> that method will
+ be run. If you want to explicitly do this, you just have to use the
+ <code class="literal">del</code> statement which we have used in previous examples.
+
+ </p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note for C++/Java/C# Programmers</h3><p>
+
+ All class members (including the data members) are
+ <span class="emphasis"><em>public</em></span> and all the methods are
+ <span class="emphasis"><em>virtual</em></span> in Python.
+
+ </p><p>
+
+ One exception: If you use data members with names using the
+ <span class="emphasis"><em>double underscore prefix</em></span> such as
+ <code class="varname">__privatevar</code>, Python uses name-mangling to
+ effectively make it a private variable.
+
+ </p><p>
+
+ Thus, the convention followed is that any variable that is to be
+ used only within the class or object should begin with an
+ underscore and all other names are public and can be used by other
+ classes/objects. Remember that this is only a convention and is not
+ enforced by Python (except for the double underscore prefix).
+
+ </p><p>
+
+ Also, note that the <code class="methodname">__del__</code> method is
+ analogous to the concept of a <span class="emphasis"><em>destructor</em></span>.
+
+ </p></div></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="class-init.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="oops.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="inheritance.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">The __init__ method </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Inheritance</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/class-init.html b/help/byteofpython/read/class-init.html
new file mode 100644
index 0000000..f80dc9b
--- /dev/null
+++ b/help/byteofpython/read/class-init.html
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>The __init__ method</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="oops.html" title="Chapter 11. Object-Oriented Programming" /><link rel="prev" href="object-methods.html" title="object Methods" /><link rel="next" href="class-and-object-vars.html" title="Class and Object Variables" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">The __init__ method</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="object-methods.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 11. Object-Oriented Programming</th><td width="20%" align="right"> <a accesskey="n" href="class-and-object-vars.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="class-init"></a>The __init__ method</h2></div></div></div><p>
+
+ There are many method names which have special significance in Python classes. We will
+ see the significance of the <code class="methodname">__init__</code> method now.
+
+ </p><p>
+
+ The <code class="methodname">__init__</code> method is run as soon as an object of a class is
+ instantiated. The method is useful to do any <span class="emphasis"><em>initialization</em></span> you want
+ to do with your object. Notice the double underscore both in the beginning and at the end
+ in the name.
+
+ </p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="using-class-init"></a>Using the __init__ method</h3></div></div></div><div class="example"><a id="id3072557"></a><p class="title"><b>Example 11.3. Using the __init__ method</b></p><pre class="programlisting">
+
+<span class="py-comment">#!/usr/bin/python</span>
+<span class="py-comment"># Filename: class_init.py</span>
+
+<span class="py-statement">class</span> <span class="py-identifier">Person</span>:
+ <span class="py-statement">def</span> <span class="py-identifier">__init__</span>(<span class="py-builtin">self</span>, name):
+ <span class="py-builtin">self</span>.name = name
+ <span class="py-statement">def</span> <span class="py-identifier">sayHi</span>(<span class="py-builtin">self</span>):
+ <span class="py-statement">print</span> <span class="py-string">'Hello, my name is'</span>, <span class="py-builtin">self</span>.name
+
+p = Person(<span class="py-string">'Swaroop'</span>)
+p.sayHi()
+
+<span class="py-comment"># This short example can also be written as Person('Swaroop').sayHi()</span>
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3072570"></a>Output</h4></div></div></div><pre class="screen">
+
+$ python class_init.py
+Hello, my name is Swaroop
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3072594"></a>How It Works</h4></div></div></div><p>
+
+ Here, we define the <code class="methodname">__init__</code> method as taking a
+ parameter <code class="varname">name</code> (along with the usual <code class="varname">self</code>).
+ Here, we just create a new field also called <code class="literal">name</code>. Notice
+ these are two different variables even though they have the same name. The
+ dotted notation allows us to differentiate between them.
+
+ </p><p>
+
+ Most importantly, notice that we do not explicitly call the
+ <code class="methodname">__init__</code> method but pass the arguments in the
+ parentheses following the class name when creating a new instance of the
+ class. This is the special significance of this method.
+
+ </p><p>
+
+ Now, we are able to use the <code class="varname">self.name</code> field in our
+ methods which is demonstrated in the <code class="methodname">sayHi</code> method.
+
+ </p></div><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note for C++/Java/C# Programmers</h3><p>
+
+ The <code class="methodname">__init__</code> method is analogous to a
+ <span class="emphasis"><em>constructor</em></span> in C++, C# or Java.
+
+ </p></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="object-methods.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="oops.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="class-and-object-vars.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">object Methods </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Class and Object Variables</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/classes.html b/help/byteofpython/read/classes.html
new file mode 100644
index 0000000..6982716
--- /dev/null
+++ b/help/byteofpython/read/classes.html
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Classes</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="oops.html" title="Chapter 11. Object-Oriented Programming" /><link rel="prev" href="self.html" title="The self" /><link rel="next" href="object-methods.html" title="object Methods" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Classes</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="self.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 11. Object-Oriented Programming</th><td width="20%" align="right"> <a accesskey="n" href="object-methods.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="classes"></a>Classes</h2></div></div></div><p>
+
+ The simplest class possible is shown in the following example.
+
+ </p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="creating-class"></a>Creating a Class</h3></div></div></div><div class="example"><a id="id3072324"></a><p class="title"><b>Example 11.1. Creating a Class</b></p><pre class="programlisting">
+
+<span class="py-comment">#!/usr/bin/python</span>
+<span class="py-comment"># Filename: simplestclass.py</span>
+
+<span class="py-statement">class</span> <span class="py-identifier">Person</span>:
+ <span class="py-statement">pass</span> <span class="py-comment"># An empty block</span>
+
+p = Person()
+<span class="py-statement">print</span> p
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3072337"></a>Output</h4></div></div></div><pre class="screen">
+
+$ python simplestclass.py
+&lt;__main__.Person instance at 0xf6fcb18c&gt;
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3072357"></a>How It Works</h4></div></div></div><p>
+
+ We create a new class using the <code class="literal">class</code> statement followed
+ by the name of the class. This follows an indented block of statements
+ which form the body of the class. In this case, we have an empty block
+ which is indicated using the <code class="literal">pass</code> statement.
+
+ </p><p>
+
+ Next, we create an object/instance of this class using the name of the
+ class followed by a pair of parentheses. (We will learn
+ <a href="class-init.html" title="The __init__ method">more about instantiation</a> in the next
+ section). For our verification, we confirm the type of the variable
+ by simply printing it. It tells us that we have an instance of the
+ <code class="classname">Person</code> class in the <code class="literal">__main__</code>
+ module.
+
+ </p><p>
+
+ Notice that the address of the computer memory where your object is stored
+ is also printed. The address will have a different value on your computer
+ since Python can store the object wherever it finds space.
+
+ </p></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="self.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="oops.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="object-methods.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">The self </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> object Methods</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/continue-statement.html b/help/byteofpython/read/continue-statement.html
new file mode 100644
index 0000000..72ee86c
--- /dev/null
+++ b/help/byteofpython/read/continue-statement.html
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>The continue statement</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="control-flow.html" title="Chapter 6. Control Flow" /><link rel="prev" href="break-statement.html" title="The break statement" /><link rel="next" href="control-flow-summary.html" title="Summary" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">The continue statement</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="break-statement.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 6. Control Flow</th><td width="20%" align="right"> <a accesskey="n" href="control-flow-summary.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="continue-statement"></a>The continue statement</h2></div></div></div><p>
+
+ The <code class="literal">continue</code> statement is used to tell Python to skip the rest of the
+ statements in the current loop block and to <span class="emphasis"><em>continue</em></span> to the next
+ iteration of the loop.
+
+ </p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="id3058376"></a>Using the continue statement</h3></div></div></div><div class="example"><a id="using-continue-statement"></a><p class="title"><b>Example 6.5. Using the continue statement</b></p><pre class="programlisting">
+
+<span class="py-comment">#!/usr/bin/python</span>
+<span class="py-comment"># Filename: continue.py</span>
+
+<span class="py-statement">while</span> <span class="py-builtin">True</span>:
+ s = <span class="py-builtin">raw_input</span>(<span class="py-string">'Enter something : '</span>)
+ <span class="py-statement">if</span> s == <span class="py-string">'quit'</span>:
+ <span class="py-statement">break</span>
+ <span class="py-statement">if</span> <span class="py-builtin">len</span>(s) &lt; <span class="py-number">3</span>:
+ <span class="py-statement">continue</span>
+ <span class="py-statement">print</span> <span class="py-string">'Input is of sufficient length'</span>
+ <span class="py-comment"># Do other kinds of processing here...</span>
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3058399"></a>Output</h4></div></div></div><pre class="screen">
+
+$ python continue.py
+Enter something : a
+Enter something : 12
+Enter something : abc
+Input is of sufficient length
+Enter something : quit
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3059822"></a>How It Works</h4></div></div></div><p>
+
+ In this program, we accept input from the user, but we process them only
+ if they are at least 3 characters long. So, we use the built-in
+ <code class="function">len</code> function to get the length and if the length
+ is less than 3, we skip the rest of the statements in the block by using
+ the <code class="literal">continue</code> statement. Otherwise, the rest of the
+ statements in the loop are executed and we can do any kind of processing
+ we want to do here.
+
+ </p><p>
+
+ Note that the <code class="literal">continue</code> statement works with the
+ <code class="literal">for</code> loop as well.
+
+ </p></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="break-statement.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="control-flow.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="control-flow-summary.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">The break statement </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Summary</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/control-flow-summary.html b/help/byteofpython/read/control-flow-summary.html
new file mode 100644
index 0000000..477ba82
--- /dev/null
+++ b/help/byteofpython/read/control-flow-summary.html
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Summary</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="control-flow.html" title="Chapter 6. Control Flow" /><link rel="prev" href="continue-statement.html" title="The continue statement" /><link rel="next" href="functions.html" title="Chapter 7. Functions" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Summary</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="continue-statement.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 6. Control Flow</th><td width="20%" align="right"> <a accesskey="n" href="functions.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="control-flow-summary"></a>Summary</h2></div></div></div><p>
+
+ We have seen how to use the three control flow statements - <code class="literal">if</code>,
+ <code class="literal">while</code> and <code class="literal">for</code> along with their associated
+ <code class="literal">break</code> and <code class="literal">continue</code> statements. These are some of the
+ most often used parts of Python and hence, becoming comfortable with them is essential.
+
+ </p><p>
+
+ Next, we will see how to create and use functions.
+
+ </p></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="continue-statement.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="control-flow.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="functions.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">The continue statement </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Chapter 7. Functions</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/control-flow.html b/help/byteofpython/read/control-flow.html
new file mode 100644
index 0000000..78725e0
--- /dev/null
+++ b/help/byteofpython/read/control-flow.html
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Chapter 6. Control Flow</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="index.html" title="A Byte of Python" /><link rel="prev" href="operators-expressions-summary.html" title="Summary" /><link rel="next" href="if-statement.html" title="The if statement" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 6. Control Flow</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="operators-expressions-summary.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="if-statement.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="chapter" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title"><a id="control-flow"></a>Chapter 6. Control Flow</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="control-flow.html#control-flow-intro">Introduction</a></span></dt><dt><span class="section"><a href="if-statement.html">The if statement</a></span></dt><dd><dl><dt><span class="section"><a href="if-statement.html#id3058469">Using the if statement</a></span></dt><dt><span class="section"><a href="if-statement.html#id3058524">How It Works</a></span></dt></dl></dd><dt><span class="section"><a href="while-statement.html">The while statement</a></span></dt><dd><dl><dt><span class="section"><a href="while-statement.html#id3058859">Using the while statement</a></span></dt></dl></dd><dt><span class="section"><a href="for-loop.html">The for loop</a></span></dt><dd><dl><dt><span class="section"><a href="for-loop.html#id3059152">Using the for statement</a></span></dt></dl></dd><dt><span class="section"><a href="break-statement.html">The break statement</a></span></dt><dd><dl><dt><span class="section"><a href="break-statement.html#id3059485">Using the break statement</a></span></dt></dl></dd><dt><span class="section"><a href="continue-statement.html">The continue statement</a></span></dt><dd><dl><dt><span class="section"><a href="continue-statement.html#id3058376">Using the continue statement</a></span></dt></dl></dd><dt><span class="section"><a href="control-flow-summary.html">Summary</a></span></dt></dl></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="control-flow-intro"></a>Introduction</h2></div></div></div><p>
+
+ In the programs we have seen till now, there has always been a series of statements
+ and Python faithfully executes them in the same order. What if you wanted to change the
+ flow of how it works? For example, you want the program to take some decisions and do
+ different things depending on different situations such as printing 'Good Morning' or
+ 'Good Evening' depending on the time of the day?
+
+ </p><p>
+
+ As you might have guessed, this is achieved using control flow statements. There are three
+ control flow statements in Python - <code class="literal">if</code>, <code class="literal">for</code> and
+ <code class="literal">while</code>.
+
+ </p></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="operators-expressions-summary.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="if-statement.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Summary </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> The if statement</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/data-structures-summary.html b/help/byteofpython/read/data-structures-summary.html
new file mode 100644
index 0000000..96aa800
--- /dev/null
+++ b/help/byteofpython/read/data-structures-summary.html
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Summary</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="data-structures.html" title="Chapter 9. Data Structures" /><link rel="prev" href="more-about-strings.html" title="More about Strings" /><link rel="next" href="problem-solving.html" title="Chapter 10. Problem Solving - Writing a Python Script" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Summary</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="more-about-strings.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 9. Data Structures</th><td width="20%" align="right"> <a accesskey="n" href="problem-solving.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="data-structures-summary"></a>Summary</h2></div></div></div><p>
+
+ We have explored the various built-in data structures of Python in detail. These
+ data structures will be essential for writing programs of reasonable size.
+
+ </p><p>
+
+ Now that we have a lot of the basics of Python in place, we will next see how to
+ design and write a real-world Python program.
+
+ </p></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="more-about-strings.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="data-structures.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="problem-solving.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">More about Strings </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Chapter 10. Problem Solving - Writing a Python Script</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/data-structures.html b/help/byteofpython/read/data-structures.html
new file mode 100644
index 0000000..6b28cbc
--- /dev/null
+++ b/help/byteofpython/read/data-structures.html
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Chapter 9. Data Structures</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="index.html" title="A Byte of Python" /><link rel="prev" href="modules-summary.html" title="Summary" /><link rel="next" href="list.html" title="List" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 9. Data Structures</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="modules-summary.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="list.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="chapter" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title"><a id="data-structures"></a>Chapter 9. Data Structures</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="data-structures.html#data-structures-intro">Introduction</a></span></dt><dt><span class="section"><a href="list.html">List</a></span></dt><dd><dl><dt><span class="section"><a href="list.html#list-objects-classes">Quick introduction to Objects and Classes</a></span></dt><dt><span class="section"><a href="list.html#using-lists">Using Lists</a></span></dt></dl></dd><dt><span class="section"><a href="tuple.html">Tuple</a></span></dt><dd><dl><dt><span class="section"><a href="tuple.html#id3066333">Using Tuples</a></span></dt><dt><span class="section"><a href="tuple.html#tuple-print">Tuples and the print statement</a></span></dt></dl></dd><dt><span class="section"><a href="dictionary.html">Dictionary</a></span></dt><dd><dl><dt><span class="section"><a href="dictionary.html#using-dictionaries">Using Dictionaries</a></span></dt></dl></dd><dt><span class="section"><a href="sequences.html">Sequences</a></span></dt><dd><dl><dt><span class="section"><a href="sequences.html#using-sequences">Using Sequences</a></span></dt></dl></dd><dt><span class="section"><a href="references.html">References</a></span></dt><dd><dl><dt><span class="section"><a href="references.html#objects-and-references">Objects and References</a></span></dt></dl></dd><dt><span class="section"><a href="more-about-strings.html">More about Strings</a></span></dt><dd><dl><dt><span class="section"><a href="more-about-strings.html#string-methods">String Methods</a></span></dt></dl></dd><dt><span class="section"><a href="data-structures-summary.html">Summary</a></span></dt></dl></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="data-structures-intro"></a>Introduction</h2></div></div></div><p>
+
+ Data structures are basically just that - they are <span class="emphasis"><em>structures</em></span> which
+ can hold some <span class="emphasis"><em>data</em></span> together. In other words, they are used to store
+ a collection of related data.
+
+ </p><p>
+
+ There are three built-in data structures in Python - list, tuple and dictionary. We will
+ see how to use each of them and how they make life easier.
+
+ </p></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="modules-summary.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="list.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Summary </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> List</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/data-type-object.html b/help/byteofpython/read/data-type-object.html
new file mode 100644
index 0000000..7cd64b3
--- /dev/null
+++ b/help/byteofpython/read/data-type-object.html
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Objects</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="basics.html" title="Chapter 4. The Basics" /><link rel="prev" href="data-types.html" title="Data Types" /><link rel="next" href="logical-and-physical-lines.html" title="Logical and Physical Lines" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Objects</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="data-types.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 4. The Basics</th><td width="20%" align="right"> <a accesskey="n" href="logical-and-physical-lines.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="data-type-object"></a>Objects</h2></div></div></div><p>
+
+ Remember, Python refers to anything used in a program as an <span class="emphasis"><em>object</em></span>.
+ This is meant in the generic sense. Instead of saying 'the <span class="emphasis"><em>something</em></span>',
+ we say 'the <span class="emphasis"><em>object</em></span>'.
+
+ </p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note for Object Oriented Programming users</h3><p>
+
+ Python is strongly object-oriented in the sense that everything is an object
+ including numbers, strings and even functions.
+
+ </p></div><p>
+
+ We will now see how to use variables along with literal constants. Save the following
+ example and run the program.
+
+ </p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">How to write Python programs</h3><p>
+
+ Henceforth, the standard procedure to save and run a Python program is as follows:
+
+ </p><div class="procedure"><ol type="1"><li><p>
+
+ Open your favorite editor.
+
+ </p></li><li><p>
+
+ Enter the program code given in the example.
+
+ </p></li><li><p>
+
+ Save it as a file with the filename mentioned in the comment.
+ I follow the convention of having all Python programs saved with
+ the extension <code class="literal">.py</code>.
+
+ </p></li><li><p>
+
+ Run the interpreter with the command
+ <span><strong class="command">python <em class="replaceable"><code>program.py</code></em></strong></span> or
+ use IDLE to run the programs. You can also use the
+ <a href="executable-python-programs.html" title="Executable Python programs">executable method</a>
+ as explained earlier.
+
+ </p></li></ol></div></div><div class="example"><a id="id3052925"></a><p class="title"><b>Example 4.1. Using Variables and Literal constants</b></p><pre class="programlisting">
+
+<span class="py-comment"># Filename : var.py</span>
+
+i = <span class="py-number">5</span>
+<span class="py-statement">print</span> i
+i = i + <span class="py-number">1</span>
+<span class="py-statement">print</span> i
+
+s = <span class="py-string">'''This is a multi-line string.
+This is the second line.'''</span>
+<span class="py-statement">print</span> s
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="id3052938"></a>Output</h3></div></div></div><pre class="screen">
+
+$ python var.py
+5
+6
+This is a multi-line string.
+This is the second line.
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="id3052959"></a>How It Works</h3></div></div></div><p>
+
+ Here's how this program works. First, we assign the literal constant value
+ <code class="literal">5</code> to the variable <code class="varname">i</code> using the
+ assignment operator (<code class="literal">=</code>). This line is called a statement
+ because it states that something should be done and in this case, we connect
+ the variable name <code class="literal">i</code> to the value <code class="literal">5</code>.
+ Next, we print the value of <code class="varname">i</code> using the <code class="literal">print</code>
+ statement which, unsurprisingly, just prints the value of the variable to the
+ screen.
+
+ </p><p>
+
+ The we add <code class="literal">1</code> to the value stored in <code class="varname">i</code> and
+ store it back. We then print it and expectedly, we get the value
+ <code class="literal">6</code>.
+
+ </p><p>
+
+ Similarly, we assign the literal string to the variable <code class="varname">s</code>
+ and then print it.
+
+ </p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note for C/C++ Programmers</h3><p>
+
+ Variables are used by just assigning them a value. No declaration or
+ data type definition is needed/used.
+
+ </p></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="data-types.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="basics.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="logical-and-physical-lines.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Data Types </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Logical and Physical Lines</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/data-types.html b/help/byteofpython/read/data-types.html
new file mode 100644
index 0000000..e150595
--- /dev/null
+++ b/help/byteofpython/read/data-types.html
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Data Types</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="basics.html" title="Chapter 4. The Basics" /><link rel="prev" href="identifier.html" title="Identifier Naming" /><link rel="next" href="data-type-object.html" title="Objects" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Data Types</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="identifier.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 4. The Basics</th><td width="20%" align="right"> <a accesskey="n" href="data-type-object.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="data-types"></a>Data Types</h2></div></div></div><p>
+
+ Variables can hold values of different types called <span class="bold"><strong>data
+ types</strong></span>. The basic types are numbers and strings, which we have already
+ discussed. In later chapters, we will see how to create our own types using
+ <a href="oops.html" title="Chapter 11. Object-Oriented Programming">classes</a>.
+
+ </p></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="identifier.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="basics.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="data-type-object.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Identifier Naming </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Objects</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/default-argument-values.html b/help/byteofpython/read/default-argument-values.html
new file mode 100644
index 0000000..6fb884c
--- /dev/null
+++ b/help/byteofpython/read/default-argument-values.html
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Default Argument Values</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="functions.html" title="Chapter 7. Functions" /><link rel="prev" href="local-variables.html" title="Local Variables" /><link rel="next" href="keyword-arguments.html" title="Keyword Arguments" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Default Argument Values</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="local-variables.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 7. Functions</th><td width="20%" align="right"> <a accesskey="n" href="keyword-arguments.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="default-argument-values"></a>Default Argument Values</h2></div></div></div><p>
+
+ For some functions, you may want to make some of its parameters as
+ <span class="emphasis"><em>optional</em></span> and use default values if the user does not want to provide
+ values for such parameters. This is done with the help of default argument values. You
+ can specify default argument values for parameters by following the parameter name in the
+ function definition with the assignment operator (<code class="literal">=</code>) followed by the
+ default value.
+
+ </p><p>
+
+ Note that the default argument value should be a constant. More precisely, the default
+ argument value should be immutable - this is explained in detail in later chapters. For
+ now, just remember this.
+
+ </p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="id3061854"></a>Using Default Argument Values</h3></div></div></div><div class="example"><a id="id3061860"></a><p class="title"><b>Example 7.5. Using Default Argument Values</b></p><pre class="programlisting">
+
+<span class="py-comment">#!/usr/bin/python</span>
+<span class="py-comment"># Filename: func_default.py</span>
+
+<span class="py-statement">def</span> <span class="py-identifier">say</span>(message, times = <span class="py-number">1</span>):
+ <span class="py-statement">print</span> message * times
+
+say(<span class="py-string">'Hello'</span>)
+say(<span class="py-string">'World'</span>, <span class="py-number">5</span>)
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3061872"></a>Output</h4></div></div></div><pre class="screen">
+
+$ python func_default.py
+Hello
+WorldWorldWorldWorldWorld
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3061893"></a>How It Works</h4></div></div></div><p>
+
+ The function named <code class="function">say</code> is used to print a string
+ as many times as want. If we don't supply a value, then by default, the
+ string is printed just once. We achieve this by specifying a default
+ argument value of <code class="literal">1</code> to the parameter
+ <code class="varname">times</code>.
+
+ </p><p>
+
+ In the first usage of <code class="function">say</code>, we supply only the string
+ and it prints the string once. In the second usage of <code class="function">say</code>,
+ we supply both the string and an argument <code class="literal">5</code> stating that
+ we want to <span class="emphasis"><em>say</em></span> the string message 5 times.
+
+ </p><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Important</h3><p>
+
+ Only those parameters which are at the end of the parameter list can
+ be given default argument values i.e. you cannot have a parameter
+ with a default argument value before a parameter without a default
+ argument value in the order of parameters declared in the function
+ parameter list.
+
+ </p><p>
+
+ This is because the values are assigned to the parameters by
+ position. For example, <code class="literal">def func(a, b=5)</code> is valid,
+ but <code class="literal">def func(a=5, b)</code> is <span class="emphasis"><em>not
+ valid</em></span>.
+
+ </p></div></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="local-variables.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="functions.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="keyword-arguments.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Local Variables </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Keyword Arguments</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/dictionary.html b/help/byteofpython/read/dictionary.html
new file mode 100644
index 0000000..e0d18e5
--- /dev/null
+++ b/help/byteofpython/read/dictionary.html
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Dictionary</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="data-structures.html" title="Chapter 9. Data Structures" /><link rel="prev" href="tuple.html" title="Tuple" /><link rel="next" href="sequences.html" title="Sequences" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Dictionary</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="tuple.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 9. Data Structures</th><td width="20%" align="right"> <a accesskey="n" href="sequences.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="dictionary"></a>Dictionary</h2></div></div></div><p>
+
+ A dictionary is like an address-book where you can find the address or contact details
+ of a person by knowing only his/her name i.e. we associate
+ <span class="bold"><strong>keys</strong></span> (name) with <span class="bold"><strong>values</strong></span>
+ (details). Note that the key must be unique just like you cannot find out the correct
+ information if you have two persons with the exact same name.
+
+ </p><p>
+
+ Note that you can use only immutable objects (like strings) for the keys of a dictionary
+ but you can use either immutable or mutable objects for the values of the dictionary.
+ This basically translates to say that you should use only simple objects for keys.
+
+ </p><p>
+
+ Pairs of keys and valus are specified in a dictionary by using the notation
+ <code class="literal">d = {key1 : value1, key2 : value2 }</code>. Notice that they key/value pairs
+ are separated by a colon and the pairs are separated themselves by commas and all this
+ is enclosed in a pair of curly brackets.
+
+ </p><p>
+
+ Remember that key/value pairs in a dictionary are not ordered in any manner. If you want
+ a particular order, then you will have to sort them yourself before using it.
+
+ </p><p>
+
+ The dictionaries that you will be using are instances/objects of the
+ <code class="classname">dict</code> class.
+
+ </p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="using-dictionaries"></a>Using Dictionaries</h3></div></div></div><div class="example"><a id="id3066768"></a><p class="title"><b>Example 9.4. Using dictionaries</b></p><pre class="programlisting">
+
+<span class="py-comment">#!/usr/bin/python</span>
+<span class="py-comment"># Filename: using_dict.py</span>
+
+<span class="py-comment"># 'ab' is short for 'a'ddress'b'ook</span>
+
+ab = { <span class="py-string">'Swaroop'</span> : <span class="py-string">'swaroopch@byteofpython.info'</span>,
+ <span class="py-string">'Larry'</span> : <span class="py-string">'larry@wall.org'</span>,
+ <span class="py-string">'Matsumoto'</span> : <span class="py-string">'matz@ruby-lang.org'</span>,
+ <span class="py-string">'Spammer'</span> : <span class="py-string">'spammer@hotmail.com'</span>
+ }
+
+<span class="py-statement">print</span> <span class="py-string">"Swaroop's address is %s"</span> % ab[<span class="py-string">'Swaroop'</span>]
+
+<span class="py-comment"># Adding a key/value pair</span>
+ab[<span class="py-string">'Guido'</span>] = <span class="py-string">'guido@python.org'</span>
+
+<span class="py-comment"># Deleting a key/value pair</span>
+<span class="py-statement">del</span> ab[<span class="py-string">'Spammer'</span>]
+
+<span class="py-statement">print</span> <span class="py-string">'\nThere are %d contacts in the address-book\n'</span> % <span class="py-builtin">len</span>(ab)
+
+<span class="py-statement">for</span> name, address <span class="py-statement">in</span> ab.items():
+ <span class="py-statement">print</span> <span class="py-string">'Contact %s at %s'</span> % (name, address)
+
+<span class="py-statement">if</span> <span class="py-string">'Guido'</span> <span class="py-statement">in</span> ab: <span class="py-comment"># OR ab.has_key('Guido')</span>
+ <span class="py-statement">print</span> <span class="py-string">"\nGuido's address is %s"</span> % ab[<span class="py-string">'Guido'</span>]
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3066781"></a>Output</h4></div></div></div><pre class="screen">
+
+$ python using_dict.py
+Swaroop's address is swaroopch@byteofpython.info
+
+There are 4 contacts in the address-book
+
+Contact Swaroop at swaroopch@byteofpython.info
+Contact Matsumoto at matz@ruby-lang.org
+Contact Larry at larry@wall.org
+Contact Guido at guido@python.org
+
+Guido's address is guido@python.org
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3065791"></a>How It Works</h4></div></div></div><p>
+
+ We create the dictionary <code class="varname">ab</code> using the notation already
+ discussed. We then access key/value pairs by specifying the key using the
+ indexing operator as discussed in the context of lists and tuples.
+ Observe that the syntax is very simple for dictionaries as well.
+
+ </p><p>
+
+ We can add new key/value pairs by simply using the indexing operator to
+ access a key and assign that value, as we have done for Guido in the
+ above case.
+
+ </p><p>
+
+ We can delete key/value pairs using our old friend - the <code class="literal">del</code>
+ statement. We simply specify the dictionary and the indexing operator for the
+ key to be removed and pass it to the <code class="literal">del</code> statement.
+ There is no need to know the value corresponding to the key for this
+ operation.
+
+ </p><p>
+
+ Next, we access each key/value pair of the dictionary using the
+ <code class="methodname">items</code> method of the dictionary which returns a
+ list of tuples where each tuple contains a pair of items - the key followed
+ by the value. We retrieve this pair and assign it to the variables
+ <code class="varname">name</code> and <code class="varname">address</code> correspondingly
+ for each pair using the <code class="literal">for..in</code> loop and then print
+ these values in the for-block.
+
+ </p><p>
+
+ We can check if a key/value pair exists using the <code class="literal">in</code>
+ operator or even the <code class="methodname">has_key</code> method of the
+ <code class="classname">dict</code> class. You can see the documentation for
+ the complete list of methods of the <code class="classname">dict</code> class
+ using <code class="literal">help(dict)</code>.
+
+ </p><p><b>Keyword Arguments and Dictionaries. </b>
+
+ On a different note, if you have used keyword arguments in your
+ functions, you have already used dictionaries! Just think about it
+ - the key/value pair is specified by you in the parameter list of
+ the function definition and when you access variables within your
+ function, it is just a key access of a dictionary (which is called
+ the <span class="emphasis"><em>symbol table</em></span> in compiler design
+ terminology).
+
+ </p></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="tuple.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="data-structures.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="sequences.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Tuple </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Sequences</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/dir.html b/help/byteofpython/read/dir.html
new file mode 100644
index 0000000..ed7840c
--- /dev/null
+++ b/help/byteofpython/read/dir.html
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>The dir() function</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="modules.html" title="Chapter 8. Modules" /><link rel="prev" href="making-modules.html" title="Making your own Modules" /><link rel="next" href="modules-summary.html" title="Summary" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">The dir() function</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="making-modules.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 8. Modules</th><td width="20%" align="right"> <a accesskey="n" href="modules-summary.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="dir"></a>The dir() function</h2></div></div></div><p>
+
+ You can use the built-in <code class="function">dir</code> function to list the identifiers
+ that a module defines. The identifiers are the functions, classes and variables defined
+ in that module.
+
+ </p><p>
+
+ When you supply a module name to the <code class="function">dir()</code> function, it returns the
+ list of the names defined in that module. When no argument is applied to it, it returns
+ the list of names defined in the current module.
+
+ </p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="using-dir"></a>Using the dir function</h3></div></div></div><div class="example"><a id="id3064758"></a><p class="title"><b>Example 8.4. Using the dir function</b></p><pre class="screen">
+
+$ python
+&gt;&gt;&gt; import sys
+&gt;&gt;&gt; dir(sys) # get list of attributes for sys module
+['__displayhook__', '__doc__', '__excepthook__', '__name__', '__stderr__',
+'__stdin__', '__stdout__', '_getframe', 'api_version', 'argv',
+'builtin_module_names', 'byteorder', 'call_tracing', 'callstats',
+'copyright', 'displayhook', 'exc_clear', 'exc_info', 'exc_type',
+'excepthook', 'exec_prefix', 'executable', 'exit', 'getcheckinterval',
+'getdefaultencoding', 'getdlopenflags', 'getfilesystemencoding',
+'getrecursionlimit', 'getrefcount', 'hexversion', 'maxint', 'maxunicode',
+'meta_path','modules', 'path', 'path_hooks', 'path_importer_cache',
+'platform', 'prefix', 'ps1', 'ps2', 'setcheckinterval', 'setdlopenflags',
+'setprofile', 'setrecursionlimit', 'settrace', 'stderr', 'stdin', 'stdout',
+'version', 'version_info', 'warnoptions']
+&gt;&gt;&gt; dir() # get list of attributes for current module
+['__builtins__', '__doc__', '__name__', 'sys']
+&gt;&gt;&gt;
+&gt;&gt;&gt; a = 5 # create a new variable 'a'
+&gt;&gt;&gt; dir()
+['__builtins__', '__doc__', '__name__', 'a', 'sys']
+&gt;&gt;&gt;
+&gt;&gt;&gt; del a # delete/remove a name
+&gt;&gt;&gt;
+&gt;&gt;&gt; dir()
+['__builtins__', '__doc__', '__name__', 'sys']
+&gt;&gt;&gt;
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3064770"></a>How It Works</h4></div></div></div><p>
+
+ First, we see the usage of <code class="function">dir</code> on the imported
+ <code class="literal">sys</code> module. We can see the huge list of attributes
+ that it contains.
+
+ </p><p>
+
+ Next, we use the <code class="function">dir</code> function without passing
+ parameters to it - by default, it returns the list of attributes for
+ the current module. Notice that the list of imported modules is also
+ part of this list.
+
+ </p><p>
+
+ In order to observe the <code class="function">dir</code> in action, we define
+ a new variable <code class="varname">a</code> and assign it a value and then check
+ <code class="function">dir</code> and we observe that there is an additional
+ value in the list of the same name. We remove the variable/attribute of
+ the current module using the <code class="literal">del</code> statement and the
+ change is reflected again in the output of the <code class="function">dir</code>
+ function.
+
+ </p><p>
+
+ A note on <code class="literal">del</code> - this statement is used to
+ <span class="emphasis"><em>delete</em></span> a variable/name and after the statement has
+ run, in this case <code class="literal">del a</code>, you can no longer access the
+ variable <code class="varname">a</code> - it is as if it never existed before at all.
+
+ </p></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="making-modules.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="modules.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="modules-summary.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Making your own Modules </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Summary</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/docstrings.html b/help/byteofpython/read/docstrings.html
new file mode 100644
index 0000000..256f634
--- /dev/null
+++ b/help/byteofpython/read/docstrings.html
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>DocStrings</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="functions.html" title="Chapter 7. Functions" /><link rel="prev" href="return.html" title="The return statement" /><link rel="next" href="functions-summary.html" title="Summary" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">DocStrings</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="return.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 7. Functions</th><td width="20%" align="right"> <a accesskey="n" href="functions-summary.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="docstrings"></a>DocStrings</h2></div></div></div><p>
+
+ Python has a nifty feature called <span class="emphasis"><em>documentation strings</em></span> which is
+ usually referred to by its shorter name <span class="emphasis"><em>docstrings</em></span>. DocStrings are an
+ important tool that you should make use of since it helps to document the program better
+ and makes it more easy to understand. Amazingly, we can even get back the docstring
+ from, say a function, when the program is actually running!
+
+ </p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="id3062388"></a>Using DocStrings</h3></div></div></div><div class="example"><a id="id3062393"></a><p class="title"><b>Example 7.8. Using DocStrings</b></p><pre class="programlisting">
+
+<span class="py-comment">#!/usr/bin/python</span>
+<span class="py-comment"># Filename: func_doc.py</span>
+
+<span class="py-statement">def</span> <span class="py-identifier">printMax</span>(x, y):
+ <span class="py-string">'''Prints the maximum of two numbers.
+
+ The two values must be integers.'''</span>
+ x = <span class="py-builtin">int</span>(x) <span class="py-comment"># convert to integers, if possible</span>
+ y = <span class="py-builtin">int</span>(y)
+
+ <span class="py-statement">if</span> x &gt; y:
+ <span class="py-statement">print</span> x, <span class="py-string">'is maximum'</span>
+ <span class="py-statement">else</span>:
+ <span class="py-statement">print</span> y, <span class="py-string">'is maximum'</span>
+
+printMax(<span class="py-number">3</span>, <span class="py-number">5</span>)
+<span class="py-statement">print</span> printMax.__doc__
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3062406"></a>Output</h4></div></div></div><pre class="screen">
+
+$ python func_doc.py
+5 is maximum
+Prints the maximum of two numbers.
+
+ The two values must be integers.
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3062429"></a>How It Works</h4></div></div></div><p>
+
+ A string on the first logical line of a function is the
+ <span class="emphasis"><em>docstring</em></span> for that function. Note that DocStrings
+ also apply to <a href="modules.html" title="Chapter 8. Modules">modules</a> and
+ <a href="classes.html" title="Classes">classes</a> which we will learn about in the
+ respective chapters.
+
+ </p><p>
+
+ The convention followed for a docstring is a multi-line string where the
+ first line starts with a capital letter and ends with a dot. Then the
+ second line is blank followed by any detailed explanation starting from
+ the third line. You are <span class="emphasis"><em>strongly advised</em></span> to follow
+ this convention for all your docstrings for all your non-trivial functions.
+
+ </p><p>
+
+ We can access the docstring of the <code class="function">printMax</code> function
+ using the <code class="literal">__doc__</code> (notice the double underscores)
+ attribute (name belonging to) of the function. Just remember that Python treats
+ <span class="emphasis"><em>everything</em></span> as an object and this includes functions.
+ We'll learn more about objects in the chapter on
+ <a href="oops.html" title="Chapter 11. Object-Oriented Programming">classes</a>.
+
+ </p><p>
+
+ If you have used the <code class="literal">help()</code> in Python, then you have
+ already seen the usage of docstrings! What it does is just fetch the
+ <code class="varname">__doc__</code> attribute of that function and displays it in
+ a neat manner for you. You can try it out on the function above - just
+ include <code class="literal">help(printMax)</code> in your program. Remember to
+ press <span><strong class="keycap">q</strong></span> to exit the <code class="literal">help</code>.
+
+ </p><p>
+
+ Automated tools can retrieve the documentation from your program in this
+ manner. Therefore, I <span class="emphasis"><em>strongly recommend</em></span> that you use
+ docstrings for any non-trivial function that you write. The
+ <span><strong class="command">pydoc</strong></span> command that comes with your Python distribution
+ works similarly to <code class="literal">help()</code> using docstrings.
+
+ </p></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="return.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="functions.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="functions-summary.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">The return statement </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Summary</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/exceptions-summary.html b/help/byteofpython/read/exceptions-summary.html
new file mode 100644
index 0000000..d4ee555
--- /dev/null
+++ b/help/byteofpython/read/exceptions-summary.html
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Summary</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="exceptions.html" title="Chapter 13. Exceptions" /><link rel="prev" href="try-finally.html" title="Try..Finally" /><link rel="next" href="stdlib.html" title="Chapter 14. The Python Standard Library" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Summary</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="try-finally.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 13. Exceptions</th><td width="20%" align="right"> <a accesskey="n" href="stdlib.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="exceptions-summary"></a>Summary</h2></div></div></div><p>
+
+ We have discussed the usage of the <code class="literal">try..except</code> and
+ <code class="literal">try..finally</code> statements. We have seen how to create our own exception
+ types and how to raise exceptions as well.
+
+ </p><p>
+
+ Next, we will explore the Python Standard Library.
+
+ </p></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="try-finally.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="exceptions.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="stdlib.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Try..Finally </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Chapter 14. The Python Standard Library</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/exceptions.html b/help/byteofpython/read/exceptions.html
new file mode 100644
index 0000000..40a619b
--- /dev/null
+++ b/help/byteofpython/read/exceptions.html
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Chapter 13. Exceptions</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="index.html" title="A Byte of Python" /><link rel="prev" href="io-summary.html" title="Summary" /><link rel="next" href="try-except.html" title="Try..Except" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 13. Exceptions</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="io-summary.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="try-except.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="chapter" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title"><a id="exceptions"></a>Chapter 13. Exceptions</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="exceptions.html#errors">Errors</a></span></dt><dt><span class="section"><a href="try-except.html">Try..Except</a></span></dt><dd><dl><dt><span class="section"><a href="try-except.html#handling-exceptions">Handling Exceptions</a></span></dt></dl></dd><dt><span class="section"><a href="raising-exceptions.html">Raising Exceptions</a></span></dt><dd><dl><dt><span class="section"><a href="raising-exceptions.html#how-to-raise-exceptions">How To Raise Exceptions</a></span></dt></dl></dd><dt><span class="section"><a href="try-finally.html">Try..Finally</a></span></dt><dd><dl><dt><span class="section"><a href="try-finally.html#using-try-finally">Using Finally</a></span></dt></dl></dd><dt><span class="section"><a href="exceptions-summary.html">Summary</a></span></dt></dl></div><p>
+
+ Exceptions occur when certain <span class="emphasis"><em>exceptional</em></span> situations occur in your program.
+ For example, what if you are going to read a file and the file does not exist? Or what if you
+ accidentally deleted it when the program was running? Such situations are handled using
+ <span class="bold"><strong>exceptions</strong></span>.
+
+ </p><p>
+
+ What if your program had some invalid statements? This is handled by Python which
+ <span class="bold"><strong>raises</strong></span> its hands and tells you there is an
+ <span class="bold"><strong>error</strong></span>.
+
+ </p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="errors"></a>Errors</h2></div></div></div><p>
+
+ Consider a simple <code class="literal">print</code> statement. What if we misspelt
+ <code class="literal">print</code> as <code class="literal">Print</code>? Note the capitalization.
+ In this case, Python <span class="emphasis"><em>raises</em></span> a syntax error.
+
+ </p><pre class="screen">
+
+&gt;&gt;&gt; Print 'Hello World'
+ File "&lt;stdin&gt;", line 1
+ Print 'Hello World'
+ ^
+SyntaxError: invalid syntax
+
+&gt;&gt;&gt; print 'Hello World'
+Hello World
+
+ </pre><p>
+
+ Observe that a <code class="classname">SyntaxError</code> is raised and also the location
+ where the error was detected is printed. This is what an <span class="emphasis"><em>error handler</em></span>
+ for this error does.
+
+ </p></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="io-summary.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="try-except.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Summary </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Try..Except</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/exec-statement.html b/help/byteofpython/read/exec-statement.html
new file mode 100644
index 0000000..8bc8f0b
--- /dev/null
+++ b/help/byteofpython/read/exec-statement.html
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>The exec and eval statements</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="more-python.html" title="Chapter 15. More Python" /><link rel="prev" href="lambda-forms.html" title="Lambda Forms" /><link rel="next" href="assert-statement.html" title="The assert statement" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">The exec and eval statements</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="lambda-forms.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 15. More Python</th><td width="20%" align="right"> <a accesskey="n" href="assert-statement.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="exec-statement"></a>The exec and eval statements</h2></div></div></div><p>
+
+ The <code class="literal">exec</code> statement is used to execute Python statements which are
+ stored in a string or file. For example, we can generate a string containing Python code
+ at runtime and then execute these statements using the <code class="literal">exec</code> statement.
+ A simple example is shown below.
+
+ </p><pre class="screen">
+
+&gt;&gt;&gt; exec 'print "Hello World"'
+Hello World
+
+ </pre><p>
+
+ The <code class="literal">eval</code> statement is used to evaluate valid Python expressions
+ which are stored in a string. A simple example is shown below.
+
+ </p><pre class="screen">
+
+&gt;&gt;&gt; eval('2*3')
+6
+
+ </pre></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="lambda-forms.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="more-python.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="assert-statement.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Lambda Forms </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> The assert statement</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/executable-python-programs.html b/help/byteofpython/read/executable-python-programs.html
new file mode 100644
index 0000000..562ec35
--- /dev/null
+++ b/help/byteofpython/read/executable-python-programs.html
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Executable Python programs</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="first-steps.html" title="Chapter 3. First Steps" /><link rel="prev" href="source-file.html" title="Using a Source File" /><link rel="next" href="getting-help.html" title="Getting Help" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Executable Python programs</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="source-file.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 3. First Steps</th><td width="20%" align="right"> <a accesskey="n" href="getting-help.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="executable-python-programs"></a>Executable Python programs</h2></div></div></div><p>
+
+ This applies only to Linux/Unix users but Windows users might be curious as well
+ about the first line of the program. First, we have to give the program executable
+ permission using the <span><strong class="command">chmod</strong></span> command then <span class="emphasis"><em>run</em></span>
+ the source program.
+
+ </p><pre class="screen">
+
+$ chmod a+x helloworld.py
+$ ./helloworld.py
+Hello World
+
+ </pre><p>
+
+ The chmod command is used here to <span class="emphasis"><em>ch</em></span>ange the
+ <span class="emphasis"><em>mod</em></span>e of the file by giving e<span class="emphasis"><em>x</em></span>ecute
+ permission to <span class="emphasis"><em>a</em></span>ll users of the system. Then, we execute the
+ program directly by specifying the location of the source file. We use the
+ <code class="literal">./</code> to indicate that the program is located in the current
+ directory.
+
+ </p><p>
+
+ To make things more fun, you can rename the file to just <code class="filename">helloworld</code>
+ and run it as <span><strong class="command">./helloworld</strong></span> and it will still work since the system
+ knows that it has to run the program using the interpreter whose location is specified
+ in the first line in the source file.
+
+ </p><p>
+
+ You are now able to run the program as long as you know the exact path of the program
+ - but what if you wanted to be able to run the program from anywhere? You can do this
+ by storing the program in one of the directories listed in the <code class="envar">PATH</code>
+ environment variable. Whenever you run any program, the system looks for that program
+ in each of the directories listed in the <code class="envar">PATH</code> environment variable and
+ then runs that program. We can make this program available everywhere by simply
+ copying this source file to one of the directories listed in <code class="envar">PATH</code>.
+
+ </p><pre class="screen">
+
+$ echo $PATH
+/opt/mono/bin:/usr/local/bin:/usr/bin:/bin:/usr/X11R6/bin:/home/swaroop/bin
+$ cp helloworld.py /home/swaroop/bin/helloworld
+$ helloworld
+Hello World
+
+ </pre><p>
+
+ We can display the <code class="envar">PATH</code> variable using the <span><strong class="command">echo</strong></span>
+ command and prefixing the variable name by <code class="literal">$</code> to indicate to the
+ shell that we need the value of this variable. We see that
+ <code class="filename">/home/swaroop/bin</code> is one of the directories in the PATH variable
+ where <span class="bold"><strong>swaroop</strong></span> is the username I am using in my
+ system. There will usually be a similar directory for your username on your system.
+ Alternatively, you can add a directory of your choice to the <code class="envar">PATH</code>
+ variable - this can be done by running
+ <span><strong class="command">PATH=$PATH:/home/swaroop/mydir</strong></span> where
+ <code class="literal">'/home/swaroop/mydir'</code> is the directory I want to add to the
+ <code class="envar">PATH</code> variable.
+
+ </p><p>
+
+ This method is very useful if you want to write useful scripts that you want to run
+ the program anytime, anywhere. It is like creating your own commands just like
+ <span><strong class="command">cd</strong></span> or any other commands that you use in the Linux terminal or
+ DOS prompt.
+
+ </p><div class="caution" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Caution</h3><p>
+
+ W.r.t. Python, a program or a script or software all mean the same thing.
+
+ </p></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="source-file.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="first-steps.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="getting-help.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Using a Source File </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Getting Help</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/explore-more.html b/help/byteofpython/read/explore-more.html
new file mode 100644
index 0000000..4aa0907
--- /dev/null
+++ b/help/byteofpython/read/explore-more.html
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Explore More</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="what-next.html" title="Chapter 16. What Next?" /><link rel="prev" href="what-next.html" title="Chapter 16. What Next?" /><link rel="next" href="what-next-summary.html" title="Summary" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Explore More</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="what-next.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 16. What Next?</th><td width="20%" align="right"> <a accesskey="n" href="what-next-summary.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="explore-more"></a>Explore More</h2></div></div></div><div class="itemizedlist"><ul type="disc"><li><p>
+
+ The <span class="bold"><strong>Python Standard Library</strong></span> is an
+ extensive library. Most of the time, this library will have what you are
+ looking for. This is referred to as the 'batteries included' philosophy of
+ Python. I highly recommend that you go through the
+ <a href="http://docs.python.org/" target="_top">Python Standard Documentation</a>
+ before you proceed to start writing large Python programs.
+
+ </p></li><li><p>
+
+ <a href="http://www.python.org/" target="_top">Python.org</a> - the official homepage
+ of the Python programming language. You will find the latest versions of the
+ Python language and interpreter here. There are also various mailing lists where
+ active discussions on various aspects of Python take place.
+
+ </p></li><li><p>
+
+ <span class="bold"><strong>comp.lang.python</strong></span> is the usenet newsgroup
+ where discussion about this language takes place. You can post your doubts
+ and queries to this newsgroup. You can access this online using
+ <a href="http://groups.google.com/groups?hl=en&amp;lr=&amp;ie=UTF-8&amp;group=comp.lang.python" target="_top">Google Groups</a> or join the
+ <a href="http://mail.python.org/mailman/listinfo/python-list" target="_top">mailing list</a> which is just a mirror of the newsgroup.
+
+ </p></li><li><p>
+
+ <a href="http://aspn.activestate.com/ASPN/Python/Cookbook/" target="_top">Python
+ Cookbook</a> is an extremely valuable collection of recipes or tips
+ on how to solve certain kinds of problems using Python. This is a
+ must-read for every Python user.
+
+ </p></li><li><p>
+
+ <a href="http://gnosis.cx/publish/tech_index_cp.html" target="_top">Charming
+ Python</a> is an excellent series of Python-related articles by
+ David Mertz.
+
+ </p></li><li><p>
+
+ <a href="http://www.diveintopython.org/" target="_top">Dive Into Python</a>
+ is a very good book for experienced Python programmers. If you have
+ thoroughly read the current book you are reading, then I would highly
+ recommend that you read 'Dive Into Python' next. It covers a range
+ of topics including XML Processing, Unit Testing and Functional
+ Programming.
+
+ </p></li><li><p>
+
+ <a href="http://www.jython.org/" target="_top">Jython</a> is an implementation of
+ the Python interpreter in the Java language. This means that you can write
+ programs in Python and use the Java libraries as well! Jython is a stable
+ and mature software. If you are a Java programmer as well, I highly
+ recommend that you give Jython a try.
+
+ </p></li><li><p>
+
+ <a href="http://www.ironpython.com/" target="_top">IronPython</a> is an implementation
+ of the Python interpreter in C# language and can run on the .NET / Mono / DotGNU
+ platform. This means that you can write programs in Python and use the
+ .NET Libraries and other libraries provided by these 3 platforms as well!
+ IronPython is still pre-alpha software and is suitable only for experimenting
+ as of now. Jim Hugunin, who wrote IronPython has joined Microsoft and will be
+ working towards a full version of IronPython in future.
+
+ </p></li><li><p>
+
+ <a href="http://www.caddr.com/code/lython/" target="_top">Lython</a> is a Lisp
+ frontend to the Python language. It is similar to Common Lisp and compiles
+ directly to Python bytecode which means that it will interoperate with our
+ usual Python code.
+
+ </p></li><li><p>
+
+ There are many many more resources on Python. Interesting ones are
+ <a href="http://www.pythonware.com/daily/" target="_top">Daily Python-URL!</a>
+ which keeps you up to date on the latest Python happenings,
+ <a href="http://www.vex.net/parnassus/" target="_top">Vaults of Parnassus</a>,
+ <a href="http://www.onlamp.com/python/" target="_top">ONLamp.com Python DevCenter</a>,
+ <a href="http://dirtsimple.org/" target="_top">dirtSimple.org</a>,
+ <a href="http://pythonnotes.blogspot.com/" target="_top">Python Notes</a>
+ and many many more.
+
+ </p></li></ul></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="what-next.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="what-next.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="what-next-summary.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 16. What Next? </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Summary</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/expressions.html b/help/byteofpython/read/expressions.html
new file mode 100644
index 0000000..ee847b8
--- /dev/null
+++ b/help/byteofpython/read/expressions.html
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Expressions</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="operators-expressions.html" title="Chapter 5. Operators and Expressions" /><link rel="prev" href="operator-precedence.html" title="Operator Precedence" /><link rel="next" href="operators-expressions-summary.html" title="Summary" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Expressions</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="operator-precedence.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 5. Operators and Expressions</th><td width="20%" align="right"> <a accesskey="n" href="operators-expressions-summary.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="expressions"></a>Expressions</h2></div></div></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="using-expressions"></a>Using Expressions</h3></div></div></div><div class="example"><a id="id3056452"></a><p class="title"><b>Example 5.1. Using Expressions</b></p><pre class="programlisting">
+
+<span class="py-comment">#!/usr/bin/python</span>
+<span class="py-comment"># Filename: expression.py</span>
+
+length = <span class="py-number">5</span>
+breadth = <span class="py-number">2</span>
+
+area = length * breadth
+<span class="py-statement">print</span> <span class="py-string">'Area is'</span>, area
+<span class="py-statement">print</span> <span class="py-string">'Perimeter is'</span>, <span class="py-number">2</span> * (length + breadth)
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3056465"></a>Output</h4></div></div></div><pre class="screen">
+
+$ python expression.py
+Area is 10
+Perimeter is 14
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3056486"></a>How It Works</h4></div></div></div><p>
+
+ The length and breadth of the rectangle are stored in variables by the
+ same name. We use these to calculate the area and perimieter of the
+ rectangle with the help of expressions. We store the result of the
+ expression <code class="literal">length * breadth</code> in the variable
+ <code class="varname">area</code> and then print it using the <code class="literal">print</code>
+ statement. In the second case, we directly use the value of the expression
+ <code class="literal">2 * (length + breadth)</code> in the print statement.
+
+ </p><p>
+
+ Also, notice how Python 'pretty-prints' the output. Even though we have not
+ specified a space between <code class="literal">'Area is'</code> and the variable
+ <code class="varname">area</code>, Python puts it for us so that we get a clean nice
+ output and the program is much more readable this way (since we don't need
+ to worry about spacing in the output). This is an example of how Python
+ makes life easy for the programmer.
+
+ </p></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="operator-precedence.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="operators-expressions.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="operators-expressions-summary.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Operator Precedence </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Summary</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/features-of-python.html b/help/byteofpython/read/features-of-python.html
new file mode 100644
index 0000000..99b84ac
--- /dev/null
+++ b/help/byteofpython/read/features-of-python.html
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Features of Python</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="introduction.html" title="Chapter 1. Introduction" /><link rel="prev" href="introduction.html" title="Chapter 1. Introduction" /><link rel="next" href="why-not-perl.html" title="Why not Perl?" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Features of Python</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="introduction.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 1. Introduction</th><td width="20%" align="right"> <a accesskey="n" href="why-not-perl.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="features-of-python"></a>Features of Python</h2></div></div></div><div class="variablelist"><dl><dt><span class="term">Simple</span></dt><dd><p>
+
+ Python is a simple and minimalistic language. Reading a good
+ Python program feels almost like reading English, although very
+ strict English! This pseudo-code nature of Python is one of its
+ greatest strengths. It allows you to concentrate on the solution
+ to the problem rather than the language itself.
+
+ </p></dd><dt><span class="term">Easy to Learn</span></dt><dd><p>
+
+ As you will see, Python is extremely easy to get started with.
+ Python has an extraordinarily simple syntax, as already mentioned.
+
+ </p></dd><dt><span class="term">Free and Open Source</span></dt><dd><p>
+
+ Python is an example of a <span class="acronym">FLOSS</span>
+ (Free/Libré and Open Source Software). In simple terms,
+ you can freely distribute copies of this software, read it's
+ source code, make changes to it, use pieces of it in new
+ free programs, and that you know you can do these things. FLOSS
+ is based on the concept of a community which shares knowledge.
+ This is one of the reasons why Python is so good - it has been
+ created and is constantly improved by a community who just want
+ to see a better Python.
+
+ </p></dd><dt><span class="term">High-level Language</span></dt><dd><p>
+
+ When you write programs in Python, you never need to bother about
+ the low-level details such as managing the memory used by your
+ program, etc.
+
+ </p></dd><dt><span class="term">Portable</span></dt><dd><p>
+
+ Due to its open-source nature, Python has been ported (i.e. changed
+ to make it work on) to many platforms. All your Python programs can
+ work on any of these platforms without requiring any changes at all
+ if you are careful enough to avoid any system-dependent features.
+
+ </p><p>
+
+ You can use Python on Linux, Windows, FreeBSD, Macintosh, Solaris,
+ OS/2, Amiga, AROS, AS/400, BeOS, OS/390, z/OS, Palm OS, QNX, VMS,
+ Psion, Acorn RISC OS, VxWorks, PlayStation, Sharp Zaurus, Windows CE
+ and even PocketPC !
+
+ </p></dd><dt><span class="term">Interpreted</span></dt><dd><p>
+
+ This requires a bit of explanation.
+
+ </p><p>
+
+ A program written in a compiled language like C or C++ is converted
+ from the source language i.e. C or C++ into a language that is
+ spoken by your computer (binary code i.e. 0s and 1s) using a compiler
+ with various flags and options. When you run the program, the
+ linker/loader software copies the program from hard disk to memory
+ and starts running it.
+
+ </p><p><a id="python-vm"></a>
+
+ Python, on the other hand, does not need compilation to binary.
+ You just <span class="emphasis"><em>run</em></span> the program directly from the source
+ code. Internally, Python converts the source code into an intermediate
+ form called bytecodes and then translates this into the native
+ language of your computer and then runs it. All this, actually, makes
+ using Python much easier since you don't have to worry about
+ compiling the program, making sure that the proper libraries are
+ linked and loaded, etc, etc. This also makes your Python programs
+ much more portable, since you can just copy your Python program onto
+ another computer and it just works!
+ </p></dd><dt><span class="term">Object Oriented</span></dt><dd><p>
+
+ Python supports procedure-oriented programming as well as
+ object-oriented programming. In <span class="emphasis"><em>procedure-oriented</em></span>
+ languages, the program is built around procedures or functions which
+ are nothing but reusable pieces of programs. In
+ <span class="emphasis"><em>object-oriented</em></span> languages, the program is built
+ around objects which combine data and functionality. Python has a very
+ powerful but simplistic way of doing OOP, especially when compared to
+ big languages like C++ or Java.
+
+ </p></dd><dt><span class="term">Extensible</span></dt><dd><p>
+
+ If you need a critical piece of code to run very fast or want to
+ have some piece of algorithm not to be open, you can code that
+ part of your program in C or C++ and then use them from your
+ Python program.
+
+ </p></dd><dt><span class="term">Embeddable</span></dt><dd><p>
+
+ You can embed Python within your C/C++ programs to give 'scripting'
+ capabilities for your program's users.
+
+ </p></dd><dt><span class="term">Extensive Libraries</span></dt><dd><p>
+
+ The Python Standard Library is huge indeed. It can help you do various
+ things involving regular expressions, documentation generation, unit
+ testing, threading, databases, web browsers, CGI, ftp, email, XML,
+ XML-RPC, HTML, WAV files, cryptography, GUI (graphical user interfaces),
+ Tk, and other system-dependent stuff. Remember, all this is always
+ available wherever Python is installed. This is called the 'Batteries
+ Included' philosophy of Python.
+
+ </p><p>
+
+ Besides, the standard library, there are various other high-quality
+ libraries such as <a href="http://www.wxpython.org" target="_top">wxPython</a>,
+ <a href="http://www.twistedmatrix.com/products/twisted" target="_top">Twisted</a>,
+ <a href="http://www.pythonware.com/products/pil/index.htm" target="_top">Python Imaging
+ Library</a> and many more.
+
+ </p></dd></dl></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="introduction-summary"></a>Summary</h3></div></div></div><p>
+
+ Python is indeed an exciting and powerful language. It has the right combination
+ of performance and features that make writing programs in Python both fun and easy.
+
+ </p></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="introduction.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="introduction.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="why-not-perl.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 1. Introduction </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Why not Perl?</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/feedback.html b/help/byteofpython/read/feedback.html
new file mode 100644
index 0000000..a7ed8ff
--- /dev/null
+++ b/help/byteofpython/read/feedback.html
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Feedback</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="preface.html" title="Preface" /><link rel="prev" href="license.html" title="License Terms" /><link rel="next" href="something-to-think-about.html" title="Something To Think About" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Feedback</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="license.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Preface</th><td width="20%" align="right"> <a accesskey="n" href="something-to-think-about.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="feedback"></a>Feedback</h2></div></div></div><p>
+ I have put in a lot of effort to make this book as interesting and as accurate
+ as possible. However, if you find some material to be inconsistent or incorrect,
+ or simply needs improvement, then please do inform me, so that I can make suitable
+ improvements. You can reach me at <code class="email">&lt;<strong>swaroop (at) byteofpython.info</strong>&gt;</code> .
+ </p></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="license.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="preface.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="something-to-think-about.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">License Terms </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Something To Think About</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/first-steps-summary.html b/help/byteofpython/read/first-steps-summary.html
new file mode 100644
index 0000000..ab08e6a
--- /dev/null
+++ b/help/byteofpython/read/first-steps-summary.html
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Summary</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="first-steps.html" title="Chapter 3. First Steps" /><link rel="prev" href="getting-help.html" title="Getting Help" /><link rel="next" href="basics.html" title="Chapter 4. The Basics" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Summary</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="getting-help.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 3. First Steps</th><td width="20%" align="right"> <a accesskey="n" href="basics.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="first-steps-summary"></a>Summary</h2></div></div></div><p>
+
+ You should now be able to write, save and run Python programs at ease. Now that you
+ are a Python user, let's learn some more Python concepts.
+
+ </p></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="getting-help.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="first-steps.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="basics.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Getting Help </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Chapter 4. The Basics</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/first-steps.html b/help/byteofpython/read/first-steps.html
new file mode 100644
index 0000000..8c2b6cc
--- /dev/null
+++ b/help/byteofpython/read/first-steps.html
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Chapter 3. First Steps</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="index.html" title="A Byte of Python" /><link rel="prev" href="installation-summary.html" title="Summary" /><link rel="next" href="interpreter-prompt.html" title="Using the interpreter prompt" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 3. First Steps</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="installation-summary.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="interpreter-prompt.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="chapter" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title"><a id="first-steps"></a>Chapter 3. First Steps</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="first-steps.html#first-steps-intro">Introduction</a></span></dt><dt><span class="section"><a href="interpreter-prompt.html">Using the interpreter prompt</a></span></dt><dt><span class="section"><a href="choosing-an-editor.html">Choosing an Editor</a></span></dt><dt><span class="section"><a href="source-file.html">Using a Source File</a></span></dt><dd><dl><dt><span class="section"><a href="source-file.html#id3050490">Output</a></span></dt><dt><span class="section"><a href="source-file.html#id3050545">How It Works</a></span></dt></dl></dd><dt><span class="section"><a href="executable-python-programs.html">Executable Python programs</a></span></dt><dt><span class="section"><a href="getting-help.html">Getting Help</a></span></dt><dt><span class="section"><a href="first-steps-summary.html">Summary</a></span></dt></dl></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="first-steps-intro"></a>Introduction</h2></div></div></div><p>
+
+ We will now see how to run a traditional 'Hello World' program in Python. This will
+ teach you how to write, save and run Python programs.
+
+ </p><p>
+
+ There are two ways of using Python to run your program - using the interactive
+ interpreter prompt or using a source file. We will now see how to use both the methods.
+
+ </p></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="installation-summary.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="interpreter-prompt.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Summary </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Using the interpreter prompt</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/floss.html b/help/byteofpython/read/floss.html
new file mode 100644
index 0000000..1232684
--- /dev/null
+++ b/help/byteofpython/read/floss.html
@@ -0,0 +1,177 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Appendix A. Free/Libré and Open Source Software (FLOSS)</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="index.html" title="A Byte of Python" /><link rel="prev" href="what-next-summary.html" title="Summary" /><link rel="next" href="about.html" title="Appendix B. About" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Appendix A. Free/Libré and Open Source Software (FLOSS)</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="what-next-summary.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="about.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="appendix" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title"><a id="floss"></a>Appendix A. Free/Libré and Open Source Software (FLOSS)</h2></div></div></div><p>
+
+ <span class="acronym">FLOSS</span> is based on the concept of a community, which itself is
+ based on the concept of sharing, and particularly the sharing of knowledge.
+ FLOSS are free for usage, modification and redistribution.
+
+ </p><p>
+
+ If you have already read this book, then you are familiar with FLOSS as well since
+ you have been using <span class="bold"><strong>Python</strong></span> all along!
+
+ </p><p>
+
+ If you want to know more about FLOSS, you can explore the following list. I have
+ listed some big FLOSS as well as those FLOSS which are cross-platform (i.e. work
+ on Linux, Windows, etc.) so that you can try using these software without the
+ need to switch to Linux immediately <span class="emphasis"><em>although you eventually will
+ ;-)</em></span>
+
+ </p><div class="itemizedlist"><ul type="disc"><li><p><b>Linux. </b>
+
+ This is a FLOSS operating system that the whole world is slowly
+ embracing! It was started by Linus Torvalds as a student. Now, it
+ is giving competition to Microsoft Windows. The latest 2.6 kernel
+ is a major breakthrough w.r.t. speed, stability and scalability.
+ [ <a href="http://www.kernel.org" target="_top">Linux Kernel</a> ]
+
+ </p></li><li><p><b>Knoppix. </b>
+
+ This is a distribution of Linux which runs off just the CD!
+ There is no installation required - you can just reboot your
+ computer, pop the CD in the drive and start using a full-featured
+ Linux distribution! You can use all the various FLOSS that comes
+ with a standard Linux distribution such as running Python programs,
+ compiling C programs, watching movies, etc. Then, reboot your
+ computer again, remove the CD and use your existing OS, as if
+ nothing happened at all.
+ [ <a href="http://www.knopper.net" target="_top">Knoppix</a> ]
+
+ </p></li><li><p><b>Fedora. </b>
+
+ This is a community-driven distribution, sponsored by Red Hat and is one
+ of the most popular Linux distributions. It contains the Linux kernel,
+ the KDE, GNOME and XFCE desktops, and the plethora of FLOSS available
+ and all this in an easy-to-use and easy-to-install manner.
+
+ </p><p>
+
+ If you care a complete beginner to Linux, then I would recommend that
+ you try <span class="bold"><strong>Mandrake Linux</strong></span> . The newly
+ released Mandrake 10.1 is just awesome.
+
+ [ <a href="http://fedora.redhat.com" target="_top">Fedora Linux</a>,
+ <a href="http://www.mandrakelinux.com" target="_top">Mandrake Linux</a> ]
+
+ </p></li><li><p><b>OpenOffice.org. </b>
+
+ This is an excellent office suite based on Sun Microsystems' StarOffice
+ software. OpenOffice has writer, presentation, spreadsheet and drawing
+ components among other things. It can even open and edit MS Word and
+ MS PowerPoint files with ease. It runs on almost all platforms. The
+ upcoming OpenOffice 2.0 has some radical improvements.
+
+ [ <a href="http://www.openoffice.org" target="_top">OpenOffice</a> ]
+
+ </p></li><li><p><b>Mozilla Firefox. </b>
+
+ This is <span class="bold"><strong>the</strong></span> next generation web browser
+ which is predicted to beat Internet Explorer (in terms of market share only
+ ;-) in a few years. It is blazingly fast and has gained critical acclaim
+ for its sensible and impressive features. The extensions concept allows any
+ kind of functionality to be added to it.
+
+ </p><p>
+
+ It's companion product Thunderbird is an excellent email client that makes
+ reading email a snap.
+
+ [ <a href="http://www.mozilla.org/products/firefox" target="_top">Mozilla
+ Firefox</a>, <a href="http://www.mozilla.org/products/thunderbird" target="_top">Mozilla Thunderbird</a> ]
+
+ </p></li><li><p><b>Mono. </b>
+
+ This is an open source implementation of the Microsoft .NET platform.
+ It allows .NET applications to be created and run on Linux, Windows,
+ FreeBSD, Mac OS and many other platforms as well. Mono implements the
+ ECMA standards of the CLI and C# which Microsoft, Intel and HP have
+ submitted for standardization and they have now become open standards.
+ This is a step in the direction of ISO standardization for the same.
+
+ </p><p>
+
+ Currently, there is a complete C# <span><strong class="command">mcs</strong></span> (which itself is written
+ in C#!), a feature-complete ASP.NET implementation, many ADO.NET providers for
+ databases and many many more features that are being improved and added everyday.
+
+ [ <a href="http://www.mono-project.com" target="_top">Mono</a>,
+ <a href="http://www.ecma-international.org" target="_top">ECMA</a>,
+ <a href="http://www.microsoft.com/net" target="_top">Microsoft .NET</a> ]
+
+ </p></li><li><p><b>Apache web server. </b>
+
+ This is the popular open source web server. In fact, it is
+ <span class="bold"><strong>the</strong></span> most popular web server on the
+ planet! It runs nearly 60% of the websites out there. Yes, that's right
+ - Apache handles more websites than all the competition (including
+ Microsoft IIS) combined.
+
+ [ <a href="http://www.apache.org" target="_top">Apache</a> ]
+
+ </p></li><li><p><b>MySQL. </b>
+
+ This is an extremely popular open source database server. It is most famous
+ for it's blazing speed. More features are being added to it's latest versions.
+
+ [ <a href="http://www.mysql.com" target="_top">MySQL</a> ]
+
+ </p></li><li><p><b>MPlayer. </b>
+
+ This is a video player that can play anything from DivX to MP3 to Ogg
+ to VCDs and DVDs to ... who says open source ain't fun? ;-)
+
+ [ <a href="http://www.mplayerhq.hu" target="_top">MPlayer</a> ]
+
+ </p></li><li><p><b>Movix. </b>
+
+ This is a Linux distribution which is based on Knoppix and runs off the
+ CD but is designed to play movies! You can create Movix CDs which are
+ just bootable CDs and when you reboot the computer and pop in the CD,
+ the movie starts playing by itself! You don't even need a hard disk to
+ watch a movie using Movix.
+
+ [ <a href="http://movix.sourceforge.net" target="_top">Movix</a> ]
+
+ </p></li></ul></div><p>
+
+ This list is just intended to give you a brief idea - there are many more excellent FLOSS out
+ there, such as the Perl language, PHP language, Drupal content management system for websites,
+ PostgreSQL database server, TORCS racing game, KDevelop IDE, Anjuta IDE, Xine - the movie player,
+ VIM editor, Quanta+ editor, XMMS audio player, GIMP image editing program, ... this list could
+ go on forever.
+
+ </p><p>
+
+ Visit the following websites for more information on FLOSS:
+
+ </p><div class="itemizedlist"><ul type="disc"><li><p>
+ <a href="http://www.sourceforge.net" target="_top">SourceForge</a>
+ </p></li><li><p>
+ <a href="http://www.freshmeat.net" target="_top">FreshMeat</a>
+ </p></li><li><p>
+ <a href="http://www.kde.org" target="_top">KDE</a>
+ </p></li><li><p>
+ <a href="http://www.gnome.org" target="_top">GNOME</a>
+ </p></li></ul></div><p>
+
+ To get the latest buzz in the FLOSS world, check out the following websites:
+
+ </p><div class="itemizedlist"><ul type="disc"><li><p>
+ <a href="http://www.osnews.com" target="_top">OSNews</a>
+ </p></li><li><p>
+ <a href="http://www.linuxtoday.com" target="_top">LinuxToday</a>
+ </p></li><li><p>
+ <a href="http://www.newsforge.com" target="_top">NewsForge</a>
+ </p></li><li><p>
+ <a href="http://www.swaroopch.info/blog" target="_top">SwaroopCH's blog</a>
+ </p></li></ul></div><p>
+
+ So, go ahead and explore the vast, free and open world of FLOSS!
+
+ </p></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="what-next-summary.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="about.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Summary </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Appendix B. About</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/for-loop.html b/help/byteofpython/read/for-loop.html
new file mode 100644
index 0000000..8b56fca
--- /dev/null
+++ b/help/byteofpython/read/for-loop.html
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>The for loop</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="control-flow.html" title="Chapter 6. Control Flow" /><link rel="prev" href="while-statement.html" title="The while statement" /><link rel="next" href="break-statement.html" title="The break statement" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">The for loop</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="while-statement.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 6. Control Flow</th><td width="20%" align="right"> <a accesskey="n" href="break-statement.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="for-loop"></a>The for loop</h2></div></div></div><p>
+
+ The <code class="literal">for..in</code> statement is another looping statement which
+ <span class="emphasis"><em>iterates</em></span> over a sequence of objects i.e. go through each item
+ in a sequence. We will see more about <a href="sequences.html" title="Sequences">sequences</a> in
+ detail in later chapters. What you need to know right now is that a sequence is just
+ an ordered collection of items.
+
+ </p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="id3059152"></a>Using the for statement</h3></div></div></div><div class="example"><a id="using-for-statement"></a><p class="title"><b>Example 6.3. Using the for statement</b></p><pre class="programlisting">
+
+<span class="py-comment">#!/usr/bin/python</span>
+<span class="py-comment"># Filename: for.py</span>
+
+<span class="py-statement">for</span> i <span class="py-statement">in</span> <span class="py-builtin">range</span>(<span class="py-number">1</span>, <span class="py-number">5</span>):
+ <span class="py-statement">print</span> i
+<span class="py-statement">else</span>:
+ <span class="py-statement">print</span> <span class="py-string">'The for loop is over'</span>
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3059174"></a>Output</h4></div></div></div><pre class="screen">
+
+$ python for.py
+1
+2
+3
+4
+The for loop is over
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3059193"></a>How It Works</h4></div></div></div><p>
+
+ In this program, we are printing a <span class="emphasis"><em>sequence</em></span> of
+ numbers. We generate this sequence of numbers using hte built-in
+ <code class="function">range</code> function.
+
+ </p><p>
+
+ What we do here is supply it two numbers and <code class="function">range</code>
+ returns a sequence of numbers starting from the first number and up to
+ the second number. For example, <code class="literal">range(1,5)</code> gives the
+ sequence <code class="literal">[1, 2, 3, 4]</code>. By default,
+ <code class="function">range</code> takes a step count of 1. If we supply a third
+ number to <code class="function">range</code>, then that becomes the step count.
+ For example, <code class="literal">range(1,5,2)</code> gives
+ <code class="literal">[1,3]</code>. Remember that the range extends
+ <span class="emphasis"><em>up to</em></span> the second number i.e. it does
+ <span class="bold"><strong>not</strong></span> include the second number.
+
+ </p><p>
+
+ The <code class="literal">for</code> loop then iterates over this range -
+ <code class="literal">for i in range(1,5)</code> is equivalent to
+ <code class="literal">for i in [1, 2, 3, 4]</code> which is like assigning each
+ number (or object) in the sequence to i, one at a time, and then
+ executing the block of statements for each value of <code class="varname">i</code>.
+ In this case, we just print the value in the block of statements.
+
+ </p><p>
+
+ Remember that the <code class="literal">else</code> part is optional. When included,
+ it is always executed once after the <code class="literal">for</code> loop is over
+ unless a <a href="break-statement.html" title="The break statement">break</a> statement is encountered.
+
+ </p><p>
+
+ Remember that the <code class="literal">for..in</code> loop works for any sequence.
+ Here, we have a list of numbers generated by the built-in
+ <code class="function">range</code> function, but in general we can use any kind
+ of sequence of any kind of objects! We will explore this idea in detail
+ in later chapters.
+
+ </p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note for C/C++/Java/C# Programmers</h3><p>
+
+ The Python <code class="literal">for</code> loop is radically different from
+ the C/C++ <code class="literal">for</code> loop. C# programmers will note that
+ the <code class="literal">for</code> loop in Python is similar to the
+ <code class="literal">foreach</code> loop in C#. Java programmers will note
+ that the same is similar to <code class="literal">for (int i : IntArray)</code>
+ in Java 1.5 .
+
+ </p><p>
+
+ In C/C++, if you want to write
+ <code class="literal">for (int i = 0; i &lt; 5; i++)</code>, then in
+ Python you write just <code class="literal">for i in range(0,5)</code>. As
+ you can see, the <code class="literal">for</code> loop is simpler, more
+ expressive and less error prone in Python.
+
+ </p></div></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="while-statement.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="control-flow.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="break-statement.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">The while statement </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> The break statement</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/for-windows-users.html b/help/byteofpython/read/for-windows-users.html
new file mode 100644
index 0000000..fc10f94
--- /dev/null
+++ b/help/byteofpython/read/for-windows-users.html
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>For Windows Users</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="installing-python.html" title="Chapter 2. Installing Python" /><link rel="prev" href="installing-python.html" title="Chapter 2. Installing Python" /><link rel="next" href="installation-summary.html" title="Summary" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">For Windows Users</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="installing-python.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 2. Installing Python</th><td width="20%" align="right"> <a accesskey="n" href="installation-summary.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="for-windows-users"></a>For Windows Users</h2></div></div></div><p>
+
+ Visit <a href="http://www.python.org/download/" target="_top">Python.org/download</a> and
+ download the latest version from this website (which was
+ <a href="http://www.python.org/ftp/python/2.3.4/Python-2.3.4.exe" target="_top">2.3.4</a>
+ as of this writing. This is just 9.4 MB which is very compact compared to most other
+ languages. The installation is just like any other Windows-based software.
+
+ </p><div class="caution" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Caution</h3><p>
+
+ When you are given the option of unchecking any <span class="emphasis"><em>optional</em></span>
+ components, don't uncheck any! Some of these components can be useful for you,
+ especially IDLE.
+
+ </p></div><p>
+
+ An interesting fact is that about 70% of Python downloads are by Windows users. Of course,
+ this doesn't give the complete picture since almost all Linux users will have Python
+ installed already on their systems by default.
+
+ </p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Using Python in the Windows command line</h3><p>
+
+ If you want to be able to use Python from the Windows command line, then you
+ need to set the PATH variable appropriately.
+
+ </p><p>
+
+ For Windows 2000, XP, 2003 , click on <span class="guimenu">Control Panel</span> -&gt;
+ <span class="guisubmenu">System</span> -&gt; <span class="guisubmenu">Advanced</span> -&gt;
+ <span class="guimenuitem">Environment Variables</span>. Click on the variable
+ named <span class="bold"><strong>PATH</strong></span> in the 'System Variables'
+ section, then select <span class="guimenuitem">Edit</span> and add
+ <span><strong class="command">;C:\Python23</strong></span> (without the quotes) to the end of
+ what is already there. Of course, use the appropriate directory name.
+
+ </p><p>
+
+ For older versions of Windows, add the following line to the file
+ <code class="filename">C:\AUTOEXEC.BAT</code> : '<span><strong class="command">PATH=%PATH%;C:\Python23</strong></span>'
+ (without the quotes) and restart the system. For Windows NT, use the
+ <code class="filename">AUTOEXEC.NT</code> file.
+
+ </p></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="installing-python.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="installing-python.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="installation-summary.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 2. Installing Python </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Summary</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/from-import.html b/help/byteofpython/read/from-import.html
new file mode 100644
index 0000000..4c8a1b6
--- /dev/null
+++ b/help/byteofpython/read/from-import.html
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>The from..import statement</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="modules.html" title="Chapter 8. Modules" /><link rel="prev" href="byte-compiled.html" title="Byte-compiled .pyc files" /><link rel="next" href="module-name.html" title="A module's __name__" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">The from..import statement</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="byte-compiled.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 8. Modules</th><td width="20%" align="right"> <a accesskey="n" href="module-name.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="from-import"></a>The from..import statement</h2></div></div></div><p>
+
+ If you want to directly import the <code class="varname">argv</code> variable into your program (to
+ avoid typing the <code class="literal">sys.</code> everytime for it), then you can use the
+ <code class="literal">from sys import argv</code> statement. If you want to import all the names
+ used in the <code class="literal">sys</code> module, then you can use the
+ <code class="literal">from sys import *</code> statement. This works for any module. In general,
+ avoid using the <code class="literal">from..import</code> statement and use the
+ <code class="literal">import</code> statement instead since your program will be much more readable
+ and will avoid any name clashes that way.
+
+ </p></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="byte-compiled.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="modules.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="module-name.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Byte-compiled .pyc files </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> A module's __name__</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/function-parameters.html b/help/byteofpython/read/function-parameters.html
new file mode 100644
index 0000000..08c6846
--- /dev/null
+++ b/help/byteofpython/read/function-parameters.html
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Function Parameters</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="functions.html" title="Chapter 7. Functions" /><link rel="prev" href="functions.html" title="Chapter 7. Functions" /><link rel="next" href="local-variables.html" title="Local Variables" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Function Parameters</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="functions.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 7. Functions</th><td width="20%" align="right"> <a accesskey="n" href="local-variables.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="function-parameters"></a>Function Parameters</h2></div></div></div><p>
+
+ A function can take parameters which are just values you supply to the function so
+ that the function can <span class="emphasis"><em>do</em></span> something utilising those values. These
+ parameters are just like variables except that the values of these variables are defined
+ when we call the function and are not assigned values within the function itself.
+
+ </p><p>
+
+ Parameters are specified within the pair of parentheses in the function definition,
+ separated by commas. When we call the function, we supply the values in the same way.
+ Note the terminology used - the names given in the function definition are called
+ <span class="emphasis"><em>parameters</em></span> whereas the values you supply in the function call are
+ called <span class="emphasis"><em>arguments</em></span>.
+
+ </p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="id3061450"></a>Using Function Parameters</h3></div></div></div><div class="example"><a id="id3061456"></a><p class="title"><b>Example 7.2. Using Function Parameters</b></p><pre class="programlisting">
+
+<span class="py-comment">#!/usr/bin/python</span>
+<span class="py-comment"># Filename: func_param.py</span>
+
+<span class="py-statement">def</span> <span class="py-identifier">printMax</span>(a, b):
+ <span class="py-statement">if</span> a &gt; b:
+ <span class="py-statement">print</span> a, <span class="py-string">'is maximum'</span>
+ <span class="py-statement">else</span>:
+ <span class="py-statement">print</span> b, <span class="py-string">'is maximum'</span>
+
+printMax(<span class="py-number">3</span>, <span class="py-number">4</span>) <span class="py-comment"># directly give literal values</span>
+
+x = <span class="py-number">5</span>
+y = <span class="py-number">7</span>
+
+printMax(x, y) <span class="py-comment"># give variables as arguments</span>
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3061469"></a>Output</h4></div></div></div><pre class="screen">
+
+$ python func_param.py
+4 is maximum
+7 is maximum
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3061492"></a>How It Works</h4></div></div></div><p>
+
+ Here, we define a function called <code class="function">printMax</code> where we
+ take two parameters called <code class="varname">a</code> and <code class="varname">b</code>.
+ We find out the greater number using a simple <code class="literal">if..else</code>
+ statement and then print the bigger number.
+
+ </p><p>
+
+ In the first usage of <code class="function">printMax</code>, we directly supply the
+ numbers i.e. arguments. In the second usage, we call the function using
+ variables. <code class="literal">printMax(x, y)</code> causes value of argument
+ <code class="varname">x</code> to be assigned to parameter <code class="varname">a</code> and
+ the value of argument <code class="varname">y</code> assigned to parameter
+ <code class="varname">b</code>. The printMax function works the same in both the cases.
+
+ </p></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="functions.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="functions.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="local-variables.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 7. Functions </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Local Variables</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/functions-summary.html b/help/byteofpython/read/functions-summary.html
new file mode 100644
index 0000000..4a247b8
--- /dev/null
+++ b/help/byteofpython/read/functions-summary.html
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Summary</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="functions.html" title="Chapter 7. Functions" /><link rel="prev" href="docstrings.html" title="DocStrings" /><link rel="next" href="modules.html" title="Chapter 8. Modules" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Summary</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="docstrings.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 7. Functions</th><td width="20%" align="right"> <a accesskey="n" href="modules.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="functions-summary"></a>Summary</h2></div></div></div><p>
+
+ We have seen so many aspects of functions but note that we still haven't covered all
+ aspects of it. However, we have already covered most of what you'll use regarding Python
+ functions on an everyday basis.
+
+ </p><p>
+
+ Next, we will see how to use as well as create Python modules.
+
+ </p></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="docstrings.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="functions.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="modules.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">DocStrings </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Chapter 8. Modules</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/functions.html b/help/byteofpython/read/functions.html
new file mode 100644
index 0000000..2aae41a
--- /dev/null
+++ b/help/byteofpython/read/functions.html
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Chapter 7. Functions</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="index.html" title="A Byte of Python" /><link rel="prev" href="control-flow-summary.html" title="Summary" /><link rel="next" href="function-parameters.html" title="Function Parameters" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 7. Functions</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="control-flow-summary.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="function-parameters.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="chapter" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title"><a id="functions"></a>Chapter 7. Functions</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="functions.html#function-intro">Introduction</a></span></dt><dd><dl><dt><span class="section"><a href="functions.html#def-function">Defining a Function</a></span></dt></dl></dd><dt><span class="section"><a href="function-parameters.html">Function Parameters</a></span></dt><dd><dl><dt><span class="section"><a href="function-parameters.html#id3061450">Using Function Parameters</a></span></dt></dl></dd><dt><span class="section"><a href="local-variables.html">Local Variables</a></span></dt><dd><dl><dt><span class="section"><a href="local-variables.html#id3061586">Using Local Variables</a></span></dt><dt><span class="section"><a href="local-variables.html#global">Using the global statement</a></span></dt></dl></dd><dt><span class="section"><a href="default-argument-values.html">Default Argument Values</a></span></dt><dd><dl><dt><span class="section"><a href="default-argument-values.html#id3061854">Using Default Argument Values</a></span></dt></dl></dd><dt><span class="section"><a href="keyword-arguments.html">Keyword Arguments</a></span></dt><dd><dl><dt><span class="section"><a href="keyword-arguments.html#id3062017">Using Keyword Arguments</a></span></dt></dl></dd><dt><span class="section"><a href="return.html">The return statement</a></span></dt><dd><dl><dt><span class="section"><a href="return.html#id3062208">Using the literal statement</a></span></dt></dl></dd><dt><span class="section"><a href="docstrings.html">DocStrings</a></span></dt><dd><dl><dt><span class="section"><a href="docstrings.html#id3062388">Using DocStrings</a></span></dt></dl></dd><dt><span class="section"><a href="functions-summary.html">Summary</a></span></dt></dl></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="function-intro"></a>Introduction</h2></div></div></div><p>
+
+ Functions are reusable pieces of programs. They allow you to give a name to a block of
+ statements and you can run that block using that name anywhere in your program and any
+ number of times. This is known as <span class="emphasis"><em>calling</em></span> the function. We have
+ already used many built-in functions such as the <code class="function">len</code> and
+ <code class="function">range</code>.
+
+ </p><p>
+
+ Functions are <span class="bold"><strong>def</strong></span>ined using the <code class="literal">def</code>
+ keyword. This is followed by an <span class="emphasis"><em>identifier</em></span> name for the function
+ followed by a pair of parentheses which may enclose some names of variables and the
+ line ends with a colon. Next follows the block of statements that are part of this
+ function. An example will show that this is actually very simple:
+
+ </p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="def-function"></a>Defining a Function</h3></div></div></div><div class="example"><a id="id3061356"></a><p class="title"><b>Example 7.1. Defining a function</b></p><pre class="programlisting">
+
+<span class="py-comment">#!/usr/bin/python</span>
+<span class="py-comment"># Filename: function1.py</span>
+
+<span class="py-statement">def</span> <span class="py-identifier">sayHello</span>():
+ <span class="py-statement">print</span> <span class="py-string">'Hello World!'</span> <span class="py-comment"># block belonging to the function</span>
+<span class="py-comment"># End of function</span>
+
+sayHello() <span class="py-comment"># call the function</span>
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3061369"></a>Output</h4></div></div></div><pre class="screen">
+
+$ python function1.py
+Hello World!
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3061389"></a>How It Works</h4></div></div></div><p>
+
+ We define a function called <code class="literal">sayHello</code> using the syntax
+ as explained above. This function takes no parameters and hence there are
+ no variables declared in the parentheses. Parameters to functions are just
+ input to the function so that we can pass in different values to it and
+ get back corresponding results.
+
+ </p></div></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="control-flow-summary.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="function-parameters.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Summary </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Function Parameters</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/getting-help.html b/help/byteofpython/read/getting-help.html
new file mode 100644
index 0000000..f3ddd53
--- /dev/null
+++ b/help/byteofpython/read/getting-help.html
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Getting Help</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="first-steps.html" title="Chapter 3. First Steps" /><link rel="prev" href="executable-python-programs.html" title="Executable Python programs" /><link rel="next" href="first-steps-summary.html" title="Summary" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Getting Help</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="executable-python-programs.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 3. First Steps</th><td width="20%" align="right"> <a accesskey="n" href="first-steps-summary.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="getting-help"></a>Getting Help</h2></div></div></div><p>
+
+ If you need quick information about any function or statement in Python, then you can
+ use the built-in <code class="literal">help</code> functionality. This is very useful especially
+ when using the interpreter prompt. For example, run <code class="literal">help(str)</code> - this
+ displays the help for the <code class="literal">str</code> class which is used to store all
+ text (strings) that you use in your program. Classes will be explained in detail in
+ the chapter on object-oriented programming.
+
+ </p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>
+
+ Press <span><strong class="keycap">q</strong></span> to exit the help.
+
+ </p></div><p>
+
+ Similarly, you can obtain information about almost anything in Python. Use
+ <code class="literal">help()</code> to learn more about using <code class="literal">help</code> itself!
+
+ </p><p>
+
+ In case you need to get help for operators like <code class="literal">print</code>, then you need
+ to set the <code class="envar">PYTHONDOCS</code> environment variable appropriately. This can be
+ done easily on Linux/Unix using the <span><strong class="command">env</strong></span> command.
+
+ </p><pre class="screen">
+
+$ env PYTHONDOCS=/usr/share/doc/python-docs-2.3.4/html/ python
+Python 2.3.4 (#1, Oct 26 2004, 16:42:40)
+[GCC 3.4.2 20041017 (Red Hat 3.4.2-6.fc3)] on linux2
+Type "help", "copyright", "credits" or "license" for more information.
+&gt;&gt;&gt; help('print')
+
+ </pre><p>
+
+ You will notice that I have used quotes to specify <code class="literal">'print'</code> so that
+ Python can understand that I want to fetch help about 'print' and I am not asking it
+ to print something.
+
+ </p><p>
+
+ Note that the location I have used is the location in Fedora Core 3 Linux - it may be
+ different for different distributions and versions.
+
+
+ </p></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="executable-python-programs.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="first-steps.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="first-steps-summary.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Executable Python programs </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Summary</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/history-lesson.html b/help/byteofpython/read/history-lesson.html
new file mode 100644
index 0000000..df782d6
--- /dev/null
+++ b/help/byteofpython/read/history-lesson.html
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>History Lesson</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="preface.html" title="Preface" /><link rel="prev" href="preface.html" title="Preface" /><link rel="next" href="status.html" title="Status of the book" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">History Lesson</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="preface.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Preface</th><td width="20%" align="right"> <a accesskey="n" href="status.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="history-lesson"></a>History Lesson</h2></div></div></div><p>
+ I first started with Python when I needed to write an installer for my
+ software <a href="http://www.g2swaroop.net/software/" target="_top">Diamond</a>
+ so that I could make the installation easy. I had to choose between
+ Python and Perl bindings for the Qt library. I did some research on the web
+ and I came across an article where Eric S. Raymond, the famous and respected
+ hacker, talked about how Python has become his favorite programming language.
+ I also found out that the PyQt bindings were very good compared to Perl-Qt.
+ So, I decided that Python was the language for me.
+ </p><p>
+ Then, I started searching for a good book on Python. I couldn't find any!
+ I did find some O'Reilly books but they were either too expensive or were more
+ like a reference manual than a guide. So, I settled for the documentation that
+ came with Python. However, it was too brief and small. It did give a good idea
+ about Python but was not complete. I managed with it since I had previous
+ programming experience, but it was unsuitable for newbies.
+ </p><p>
+ About six months after my first brush with Python, I installed the (then) latest
+ Red Hat 9.0 Linux and I was playing around with KWord. I got excited about it and
+ suddenly got the idea of writing some stuff on Python. I started writing a few
+ pages but it quickly became 30 pages long. Then, I became serious about making it
+ more useful in a book form. After a <span class="emphasis"><em>lot</em></span> of rewrites, it has
+ reached a stage where it has become a useful guide to learning the Python language.
+ I consider this book to be my contribution and tribute to the open source community.
+ </p><p>
+ This book started out as my personal notes on Python and I still consider it in the
+ same way, although I've taken a lot of effort to make it more palatable to others :)
+ </p><p>
+ In the true spirit of open source, I have received lots of constructive suggestions,
+ criticisms and <a href="feedback.html" title="Feedback">feedback</a> from enthusiastic readers
+ which has helped me improve this book a lot.
+ </p></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="preface.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="preface.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="status.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Preface </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Status of the book</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/identifier.html b/help/byteofpython/read/identifier.html
new file mode 100644
index 0000000..6a777d0
--- /dev/null
+++ b/help/byteofpython/read/identifier.html
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Identifier Naming</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="basics.html" title="Chapter 4. The Basics" /><link rel="prev" href="variables.html" title="Variables" /><link rel="next" href="data-types.html" title="Data Types" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Identifier Naming</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="variables.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 4. The Basics</th><td width="20%" align="right"> <a accesskey="n" href="data-types.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="identifier"></a>Identifier Naming</h2></div></div></div><p>
+
+ Variables are examples of identifiers. <span class="emphasis"><em>Identifiers</em></span> are names given
+ to identify <span class="emphasis"><em>something</em></span>. There are some rules you have to follow for
+ naming identifiers:
+
+ </p><div class="itemizedlist"><ul type="disc"><li><p>
+
+ The first character of the identifier must be a letter of the alphabet
+ (upper or lowercase) or an underscore ('_').
+
+ </p></li><li><p>
+
+ The rest of the identifier name can consist of letters (upper or lowercase),
+ underscores ('_') or digits (0-9).
+
+ </p></li><li><p>
+
+ Identifier names are case-sensitive. For example, <code class="literal">myname</code>
+ and <code class="literal">myName</code> are <span class="bold"><strong>not</strong></span> the
+ same. Note the lowercase <code class="literal">n</code> in the former and the
+ uppercase <code class="literal">N</code> in te latter.
+
+ </p></li><li><p>
+
+ Examples of <span class="emphasis"><em>valid</em></span> identifier names are
+ <code class="literal">i</code>, <code class="literal">__my_name</code>, <code class="literal">name_23</code>
+ and <code class="literal">a1b2_c3</code>.
+
+ </p></li><li><p>
+
+ Examples of <span class="emphasis"><em>invalid</em></span> identifier names are
+ <code class="literal">2things</code>, <code class="literal">this is spaced out</code>
+ and <code class="literal">my-name</code>.
+
+ </p></li></ul></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="variables.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="basics.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="data-types.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Variables </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Data Types</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/if-statement.html b/help/byteofpython/read/if-statement.html
new file mode 100644
index 0000000..3595c47
--- /dev/null
+++ b/help/byteofpython/read/if-statement.html
@@ -0,0 +1,140 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>The if statement</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="control-flow.html" title="Chapter 6. Control Flow" /><link rel="prev" href="control-flow.html" title="Chapter 6. Control Flow" /><link rel="next" href="while-statement.html" title="The while statement" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">The if statement</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="control-flow.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 6. Control Flow</th><td width="20%" align="right"> <a accesskey="n" href="while-statement.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="if-statement"></a>The if statement</h2></div></div></div><p>
+
+ The <code class="literal">if</code> statement is used to check a condition and <span class="emphasis"><em>if</em></span>
+ the condition is true, we run a block of statements (called the
+ <span class="emphasis"><em>if-block</em></span>), <span class="emphasis"><em>else</em></span> we process another block of
+ statements (called the <span class="emphasis"><em>else-block</em></span>). The <span class="emphasis"><em>else</em></span>
+ clause is optional.
+
+ </p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="id3058469"></a>Using the if statement</h3></div></div></div><div class="example"><a id="using-if-statement"></a><p class="title"><b>Example 6.1. Using the if statement</b></p><pre class="programlisting">
+
+<span class="py-comment">#!/usr/bin/python</span>
+<span class="py-comment"># Filename: if.py</span>
+
+number = <span class="py-number">23</span>
+guess = <span class="py-builtin">int</span>(<span class="py-builtin">raw_input</span>(<span class="py-string">'Enter an integer : '</span>))
+
+<span class="py-statement">if</span> guess == number:
+ <span class="py-statement">print</span> <span class="py-string">'Congratulations, you guessed it.'</span> <span class="py-comment"># New block starts here</span>
+ <span class="py-statement">print</span> <span class="py-string">"(but you do not win any prizes!)"</span> <span class="py-comment"># New block ends here</span>
+<span class="py-statement">elif</span> guess &lt; number:
+ <span class="py-statement">print</span> <span class="py-string">'No, it is a little higher than that'</span> <span class="py-comment"># Another block</span>
+ <span class="py-comment"># You can do whatever you want in a block ...</span>
+<span class="py-statement">else</span>:
+ <span class="py-statement">print</span> <span class="py-string">'No, it is a little lower than that'</span>
+ <span class="py-comment"># you must have guess &gt; number to reach here</span>
+
+<span class="py-statement">print</span> <span class="py-string">'Done'</span>
+<span class="py-comment"># This last statement is always executed, after the if statement is executed</span>
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3058492"></a>Output</h4></div></div></div><pre class="screen">
+
+$ python if.py
+Enter an integer : 50
+No, it is a little lower than that
+Done
+$ python if.py
+Enter an integer : 22
+No, it is a little higher than that
+Done
+$ python if.py
+Enter an integer : 23
+Congratulations, you guessed it.
+(but you do not win any prizes!)
+Done
+
+ </pre></div></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="id3058524"></a>How It Works</h3></div></div></div><p>
+
+ In this program, we take guesses from the user and check if it is the number
+ that we have. We set the variable <code class="varname">number</code> to any integer we
+ want, say <code class="literal">23</code>. Then, we take the user's guess using the
+ <code class="literal">raw_input()</code> function. Functions are just reusable pieces of
+ programs. We'll read more about them in the <a href="functions.html" title="Chapter 7. Functions">next
+ chapter</a>.
+
+ </p><p>
+
+ We supply a string to the built-in <code class="function">raw_input</code> function
+ which prints it to the screen and waits for input from the user. Once we enter
+ something and press <span><strong class="keycap">enter</strong></span>, the function returns the input
+ which in the case of <code class="function">raw_input</code> is a string. We then
+ convert this string to an integer using <code class="literal">int</code> and then store
+ it in the variable <code class="varname">guess</code>. Actually, the <code class="literal">int</code>
+ is a class but all you need to know right now is that you can use it to convert
+ a string to an integer (assuming the string contains a valid integer in the text).
+
+ </p><p>
+
+ Next, we compare the guess of the user with the number we have chosen. If they
+ are equal, we print a success message. Notice that we use indentation levels to
+ tell Python which statements belong to which block. This is why indentation is
+ so important in Python. I hope you are sticking to 'one tab per indentation level'
+ rule. Are you?
+
+ </p><p>
+
+ Notice how the <code class="literal">if</code> statement contains a colon at the end - we
+ are indicating to Python that a block of statements follows.
+
+ </p><p>
+
+ Then, we check if the guess is less than the number, and if so, we inform the user
+ to guess a little higher than that. What we have used here is the
+ <code class="literal">elif</code> clause which actually combines two related
+ <code class="literal">if else-if else</code> statements into one combined
+ <code class="literal">if-elif-else</code> statement. This makes the program easier and
+ reduces the amount of indentation required.
+
+ </p><p>
+
+ The <code class="literal">elif</code> and <code class="literal">else</code> statements must also have
+ a colon at the end of the logical line followed by their corresponding block of
+ statements (with proper indentation, of course)
+
+ </p><p>
+
+ You can have another <code class="literal">if</code> statement inside the if-block of an
+ <code class="literal">if</code> statement and so on - this is called a nested
+ <code class="literal">if</code> statement.
+
+ </p><p>
+
+ Remember that the <code class="literal">elif</code> and <code class="literal">else</code> parts are
+ optional. A minival valid <code class="literal">if</code> statement is
+
+ </p><pre class="programlisting">
+
+<span class="py-statement">if</span> <span class="py-builtin">True</span>:
+ <span class="py-statement">print</span> <span class="py-string">'Yes, it is true'</span>
+
+ </pre><p>
+
+ After Python has finished executing the complete <code class="literal">if</code> statement
+ along with the assocated <code class="literal">elif</code> and <code class="literal">else</code>
+ clauses, it moves on to the next statement in the block containing the
+ <code class="literal">if</code> statement. In this case, it is the main block where
+ execution of the program starts and the next statement is the
+ <code class="literal">print 'Done'</code> statement. After this, Python sees the ends of
+ the program and simply finishes up.
+
+ </p><p>
+
+ Although this is a very simple program, I have been pointing out a lot of things
+ that you should notice even in this simple program. All these are pretty
+ straightforward (and surprisingly simple for those of you from C/C++ backgrounds)
+ and requires you to become aware of all these initially, but after that, you
+ will become comfortable with it and it'll feel 'natural' to you.
+
+ </p></div><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note for C/C++ Programmers</h3><p>
+
+ There is no <code class="literal">switch</code> statement in Python. You can use an
+ <code class="literal">if..elif..else</code> statement to do the same thing (and in some
+ cases, use a <a href="dictionary.html" title="Dictionary">dictionary</a> to do it quickly)
+
+ </p></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="control-flow.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="control-flow.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="while-statement.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 6. Control Flow </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> The while statement</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/images/home.gif b/help/byteofpython/read/images/home.gif
new file mode 100644
index 0000000..6784f5b
--- /dev/null
+++ b/help/byteofpython/read/images/home.gif
Binary files differ
diff --git a/help/byteofpython/read/images/next.gif b/help/byteofpython/read/images/next.gif
new file mode 100644
index 0000000..aa1516e
--- /dev/null
+++ b/help/byteofpython/read/images/next.gif
Binary files differ
diff --git a/help/byteofpython/read/images/prev.gif b/help/byteofpython/read/images/prev.gif
new file mode 100644
index 0000000..64ca8f3
--- /dev/null
+++ b/help/byteofpython/read/images/prev.gif
Binary files differ
diff --git a/help/byteofpython/read/images/up.gif b/help/byteofpython/read/images/up.gif
new file mode 100644
index 0000000..aabc2d0
--- /dev/null
+++ b/help/byteofpython/read/images/up.gif
Binary files differ
diff --git a/help/byteofpython/read/indentation.html b/help/byteofpython/read/indentation.html
new file mode 100644
index 0000000..0770a53
--- /dev/null
+++ b/help/byteofpython/read/indentation.html
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Indentation</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="basics.html" title="Chapter 4. The Basics" /><link rel="prev" href="logical-and-physical-lines.html" title="Logical and Physical Lines" /><link rel="next" href="basics-summary.html" title="Summary" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Indentation</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="logical-and-physical-lines.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 4. The Basics</th><td width="20%" align="right"> <a accesskey="n" href="basics-summary.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="indentation"></a>Indentation</h2></div></div></div><p>
+
+ Whitespace is important in Python. Actually, <span class="bold"><strong>whitespace at the
+ beginning of the line is important</strong></span>. This is called
+ <span class="bold"><strong>indentation</strong></span>. Leading whitespace (spaces and tabs) at
+ the beginning of the logical line is used to determine the indentation level of the
+ logical line, which in turn is used to determine the grouping of statements.
+
+ </p><p>
+
+ This means that statements which go together <span class="bold"><strong>must</strong></span>
+ have the same indentation. Each such set of statements is called a
+ <span class="bold"><strong>block</strong></span>. We will see examples of how blocks are
+ important in later chapters.
+
+ </p><p>
+
+ One thing you should remember is how wrong indentation can give rise to errors.
+ For example:
+
+ </p><pre class="programlisting">
+
+i = <span class="py-number">5</span>
+ <span class="py-statement">print</span> <span class="py-string">'Value is'</span>, i <span class="py-comment"># Error! Notice a single space at the start of the line</span>
+<span class="py-statement">print</span> <span class="py-string">'I repeat, the value is'</span>, i
+
+ </pre><p>
+
+ When you run this, you get the following error:
+
+ </p><pre class="screen">
+
+ File "whitespace.py", line 4
+ print 'Value is', i # Error! Notice a single space at the start of the line
+ ^
+SyntaxError: invalid syntax
+
+ </pre><p>
+
+ Notice that there is a single space at the beginning of the second line. The error
+ indicated by Python tells us that the syntax of the program is invalid i.e. the
+ program was not properly written. What this means to you is that <span class="emphasis"><em>you cannot
+ arbitrarily start new blocks of statements</em></span> (except for the main block which
+ you have been using all along, of course). Cases where you can use new blocks will be
+ detailed in later chapters such as the <a href="control-flow.html" title="Chapter 6. Control Flow">control flow
+ chapter</a>.
+
+ </p><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">How to indent</h3><p>
+
+ Do <span class="bold"><strong>not</strong></span> use a mixture of tabs and spaces for
+ the indentation as it does not work across different platforms properly. I
+ <span class="emphasis"><em>strongly recommend</em></span> that you use a
+ <span class="emphasis"><em>single tab</em></span> or <span class="emphasis"><em>two or four spaces</em></span> for
+ each indentation level.
+
+ </p><p>
+
+ Choose any of these three indentation styles. More importantly, choose one and
+ use it <span class="bold"><strong>consistently</strong></span> i.e. use that indentation
+ style <span class="emphasis"><em>only</em></span>.
+
+ </p></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="logical-and-physical-lines.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="basics.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="basics-summary.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Logical and Physical Lines </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Summary</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/index.html b/help/byteofpython/read/index.html
new file mode 100644
index 0000000..10d1e14
--- /dev/null
+++ b/help/byteofpython/read/index.html
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>A Byte of Python</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><meta name="description" content="Abstract &#10;&#9;&#9;&#9;This book will help you to learn the Python programming language, whether you&#10;&#9;&#9;&#9;are new to computers or are an experienced programmer.&#10;&#9;&#9;" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="next" href="preface.html" title="Preface" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">A Byte of Python</th></tr><tr><td width="20%" align="left"> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="preface.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="book" lang="en" xml:lang="en"><div class="titlepage"><div><div><h1 class="title"><a id="byte-of-python"></a>A Byte of Python</h1></div><div><div class="author"><h3 class="author"><span class="firstname">Swaroop</span> <span class="surname">C H</span></h3><div class="affiliation"><span class="orgname">www.byteofpython.info<br /></span></div></div></div><div><p class="releaseinfo">Version 1.20</p></div><div><p class="copyright">Copyright © 2003-2005 Swaroop C H</p></div><div><div class="legalnotice"><a id="id2980897"></a><p>
+ This book is released under the
+ Creative Commons Attribution-NonCommercial-ShareAlike License 2.0 .
+ </p></div></div><div><div class="abstract"><tr class="title"><b>Abstract</b></p><p>
+ This book will help you to learn the Python programming language, whether you
+ are new to computers or are an experienced programmer.
+ </p></div></<p>To read the latest version of this book, please see <a
+ href="http://www.swaroopch.com/notes/Python">www.swaroopch.com/notes/Python</a>.</p></div></div><hr /></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="preface"><a href="preface.html">Preface</a></span></dt><dd><dl><dt><span class="section"><a href="preface.html#who-this-book-is-for">Who This Book Is For</a></span></dt><dt><span class="section"><a href="history-lesson.html">History Lesson</a></span></dt><dt><span class="section"><a href="status.html">Status of the book</a></span></dt><dt><span class="section"><a href="official-website.html">Official Website</a></span></dt><dt><span class="section"><a href="license.html">License Terms</a></span></dt><dt><span class="section"><a href="feedback.html">Feedback</a></span></dt><dt><span class="section"><a href="something-to-think-about.html">Something To Think About</a></span></dt></dl></dd><dt><span class="chapter"><a href="introduction.html">1. Introduction</a></span></dt><dd><dl><dt><span class="section"><a href="introduction.html#introduction-section">Introduction</a></span></dt><dt><span class="section"><a href="features-of-python.html">Features of Python</a></span></dt><dd><dl><dt><span class="section"><a href="features-of-python.html#introduction-summary">Summary</a></span></dt></dl></dd><dt><span class="section"><a href="why-not-perl.html">Why not Perl?</a></span></dt><dt><span class="section"><a href="what-programmers-say.html">What Programmers Say</a></span></dt></dl></dd><dt><span class="chapter"><a href="installing-python.html">2. Installing Python</a></span></dt><dd><dl><dt><span class="section"><a href="installing-python.html#for-linux-bsd-users">For Linux/BSD users</a></span></dt><dt><span class="section"><a href="for-windows-users.html">For Windows Users</a></span></dt><dt><span class="section"><a href="installation-summary.html">Summary</a></span></dt></dl></dd><dt><span class="chapter"><a href="first-steps.html">3. First Steps</a></span></dt><dd><dl><dt><span class="section"><a href="first-steps.html#first-steps-intro">Introduction</a></span></dt><dt><span class="section"><a href="interpreter-prompt.html">Using the interpreter prompt</a></span></dt><dt><span class="section"><a href="choosing-an-editor.html">Choosing an Editor</a></span></dt><dt><span class="section"><a href="source-file.html">Using a Source File</a></span></dt><dd><dl><dt><span class="section"><a href="source-file.html#id3050490">Output</a></span></dt><dt><span class="section"><a href="source-file.html#id3050545">How It Works</a></span></dt></dl></dd><dt><span class="section"><a href="executable-python-programs.html">Executable Python programs</a></span></dt><dt><span class="section"><a href="getting-help.html">Getting Help</a></span></dt><dt><span class="section"><a href="first-steps-summary.html">Summary</a></span></dt></dl></dd><dt><span class="chapter"><a href="basics.html">4. The Basics</a></span></dt><dd><dl><dt><span class="section"><a href="basics.html#literal-constants">Literal Constants</a></span></dt><dt><span class="section"><a href="numbers.html">Numbers</a></span></dt><dt><span class="section"><a href="strings.html">Strings</a></span></dt><dt><span class="section"><a href="variables.html">Variables</a></span></dt><dt><span class="section"><a href="identifier.html">Identifier Naming</a></span></dt><dt><span class="section"><a href="data-types.html">Data Types</a></span></dt><dt><span class="section"><a href="data-type-object.html">Objects</a></span></dt><dd><dl><dt><span class="section"><a href="data-type-object.html#id3052938">Output</a></span></dt><dt><span class="section"><a href="data-type-object.html#id3052959">How It Works</a></span></dt></dl></dd><dt><span class="section"><a href="logical-and-physical-lines.html">Logical and Physical Lines</a></span></dt><dt><span class="section"><a href="indentation.html">Indentation</a></span></dt><dt><span class="section"><a href="basics-summary.html">Summary</a></span></dt></dl></dd><dt><span class="chapter"><a href="operators-expressions.html">5. Operators and Expressions</a></span></dt><dd><dl><dt><span class="section"><a href="operators-expressions.html#operators-expressions-intro">Introduction</a></span></dt><dt><span class="section"><a href="operators.html">Operators</a></span></dt><dt><span class="section"><a href="operator-precedence.html">Operator Precedence</a></span></dt><dd><dl><dt><span class="section"><a href="operator-precedence.html#order-of-evaluation">Order of Evaluation</a></span></dt><dt><span class="section"><a href="operator-precedence.html#associativity">Associativity</a></span></dt></dl></dd><dt><span class="section"><a href="expressions.html">Expressions</a></span></dt><dd><dl><dt><span class="section"><a href="expressions.html#using-expressions">Using Expressions</a></span></dt></dl></dd><dt><span class="section"><a href="operators-expressions-summary.html">Summary</a></span></dt></dl></dd><dt><span class="chapter"><a href="control-flow.html">6. Control Flow</a></span></dt><dd><dl><dt><span class="section"><a href="control-flow.html#control-flow-intro">Introduction</a></span></dt><dt><span class="section"><a href="if-statement.html">The if statement</a></span></dt><dd><dl><dt><span class="section"><a href="if-statement.html#id3058469">Using the if statement</a></span></dt><dt><span class="section"><a href="if-statement.html#id3058524">How It Works</a></span></dt></dl></dd><dt><span class="section"><a href="while-statement.html">The while statement</a></span></dt><dd><dl><dt><span class="section"><a href="while-statement.html#id3058859">Using the while statement</a></span></dt></dl></dd><dt><span class="section"><a href="for-loop.html">The for loop</a></span></dt><dd><dl><dt><span class="section"><a href="for-loop.html#id3059152">Using the for statement</a></span></dt></dl></dd><dt><span class="section"><a href="break-statement.html">The break statement</a></span></dt><dd><dl><dt><span class="section"><a href="break-statement.html#id3059485">Using the break statement</a></span></dt></dl></dd><dt><span class="section"><a href="continue-statement.html">The continue statement</a></span></dt><dd><dl><dt><span class="section"><a href="continue-statement.html#id3058376">Using the continue statement</a></span></dt></dl></dd><dt><span class="section"><a href="control-flow-summary.html">Summary</a></span></dt></dl></dd><dt><span class="chapter"><a href="functions.html">7. Functions</a></span></dt><dd><dl><dt><span class="section"><a href="functions.html#function-intro">Introduction</a></span></dt><dd><dl><dt><span class="section"><a href="functions.html#def-function">Defining a Function</a></span></dt></dl></dd><dt><span class="section"><a href="function-parameters.html">Function Parameters</a></span></dt><dd><dl><dt><span class="section"><a href="function-parameters.html#id3061450">Using Function Parameters</a></span></dt></dl></dd><dt><span class="section"><a href="local-variables.html">Local Variables</a></span></dt><dd><dl><dt><span class="section"><a href="local-variables.html#id3061586">Using Local Variables</a></span></dt><dt><span class="section"><a href="local-variables.html#global">Using the global statement</a></span></dt></dl></dd><dt><span class="section"><a href="default-argument-values.html">Default Argument Values</a></span></dt><dd><dl><dt><span class="section"><a href="default-argument-values.html#id3061854">Using Default Argument Values</a></span></dt></dl></dd><dt><span class="section"><a href="keyword-arguments.html">Keyword Arguments</a></span></dt><dd><dl><dt><span class="section"><a href="keyword-arguments.html#id3062017">Using Keyword Arguments</a></span></dt></dl></dd><dt><span class="section"><a href="return.html">The return statement</a></span></dt><dd><dl><dt><span class="section"><a href="return.html#id3062208">Using the literal statement</a></span></dt></dl></dd><dt><span class="section"><a href="docstrings.html">DocStrings</a></span></dt><dd><dl><dt><span class="section"><a href="docstrings.html#id3062388">Using DocStrings</a></span></dt></dl></dd><dt><span class="section"><a href="functions-summary.html">Summary</a></span></dt></dl></dd><dt><span class="chapter"><a href="modules.html">8. Modules</a></span></dt><dd><dl><dt><span class="section"><a href="modules.html#modules-intro">Introduction</a></span></dt><dd><dl><dt><span class="section"><a href="modules.html#using-sys-module">Using the sys module</a></span></dt></dl></dd><dt><span class="section"><a href="byte-compiled.html">Byte-compiled .pyc files</a></span></dt><dt><span class="section"><a href="from-import.html">The from..import statement</a></span></dt><dt><span class="section"><a href="module-name.html">A module's __name__</a></span></dt><dd><dl><dt><span class="section"><a href="module-name.html#using-name">Using a module's __name__</a></span></dt></dl></dd><dt><span class="section"><a href="making-modules.html">Making your own Modules</a></span></dt><dd><dl><dt><span class="section"><a href="making-modules.html#creating-modules">Creating your own Modules</a></span></dt><dt><span class="section"><a href="making-modules.html#using-from-import">from..import</a></span></dt></dl></dd><dt><span class="section"><a href="dir.html">The dir() function</a></span></dt><dd><dl><dt><span class="section"><a href="dir.html#using-dir">Using the dir function</a></span></dt></dl></dd><dt><span class="section"><a href="modules-summary.html">Summary</a></span></dt></dl></dd><dt><span class="chapter"><a href="data-structures.html">9. Data Structures</a></span></dt><dd><dl><dt><span class="section"><a href="data-structures.html#data-structures-intro">Introduction</a></span></dt><dt><span class="section"><a href="list.html">List</a></span></dt><dd><dl><dt><span class="section"><a href="list.html#list-objects-classes">Quick introduction to Objects and Classes</a></span></dt><dt><span class="section"><a href="list.html#using-lists">Using Lists</a></span></dt></dl></dd><dt><span class="section"><a href="tuple.html">Tuple</a></span></dt><dd><dl><dt><span class="section"><a href="tuple.html#id3066333">Using Tuples</a></span></dt><dt><span class="section"><a href="tuple.html#tuple-print">Tuples and the print statement</a></span></dt></dl></dd><dt><span class="section"><a href="dictionary.html">Dictionary</a></span></dt><dd><dl><dt><span class="section"><a href="dictionary.html#using-dictionaries">Using Dictionaries</a></span></dt></dl></dd><dt><span class="section"><a href="sequences.html">Sequences</a></span></dt><dd><dl><dt><span class="section"><a href="sequences.html#using-sequences">Using Sequences</a></span></dt></dl></dd><dt><span class="section"><a href="references.html">References</a></span></dt><dd><dl><dt><span class="section"><a href="references.html#objects-and-references">Objects and References</a></span></dt></dl></dd><dt><span class="section"><a href="more-about-strings.html">More about Strings</a></span></dt><dd><dl><dt><span class="section"><a href="more-about-strings.html#string-methods">String Methods</a></span></dt></dl></dd><dt><span class="section"><a href="data-structures-summary.html">Summary</a></span></dt></dl></dd><dt><span class="chapter"><a href="problem-solving.html">10. Problem Solving - Writing a Python Script</a></span></dt><dd><dl><dt><span class="section"><a href="problem-solving.html#the-problem">The Problem</a></span></dt><dt><span class="section"><a href="the-solution.html">The Solution</a></span></dt><dd><dl><dt><span class="section"><a href="the-solution.html#first-version">First Version</a></span></dt><dt><span class="section"><a href="the-solution.html#second-version">Second Version</a></span></dt><dt><span class="section"><a href="the-solution.html#third-version">Third Version</a></span></dt><dt><span class="section"><a href="the-solution.html#fourth-version">Fourth Version</a></span></dt><dt><span class="section"><a href="the-solution.html#more-refinements">More Refinements</a></span></dt></dl></dd><dt><span class="section"><a href="software-development-process.html">The Software Development Process</a></span></dt><dt><span class="section"><a href="problem-solving-summary.html">Summary</a></span></dt></dl></dd><dt><span class="chapter"><a href="oops.html">11. Object-Oriented Programming</a></span></dt><dd><dl><dt><span class="section"><a href="oops.html#oops-intro">Introduction</a></span></dt><dt><span class="section"><a href="self.html">The self</a></span></dt><dt><span class="section"><a href="classes.html">Classes</a></span></dt><dd><dl><dt><span class="section"><a href="classes.html#creating-class">Creating a Class</a></span></dt></dl></dd><dt><span class="section"><a href="object-methods.html">object Methods</a></span></dt><dd><dl><dt><span class="section"><a href="object-methods.html#using-object-methods">Using Object Methds</a></span></dt></dl></dd><dt><span class="section"><a href="class-init.html">The __init__ method</a></span></dt><dd><dl><dt><span class="section"><a href="class-init.html#using-class-init">Using the __init__ method</a></span></dt></dl></dd><dt><span class="section"><a href="class-and-object-vars.html">Class and Object Variables</a></span></dt><dd><dl><dt><span class="section"><a href="class-and-object-vars.html#using-class-and-obj-vars">Using Class and Object Variables</a></span></dt></dl></dd><dt><span class="section"><a href="inheritance.html">Inheritance</a></span></dt><dd><dl><dt><span class="section"><a href="inheritance.html#using-inheritance">Using Inheritance</a></span></dt></dl></dd><dt><span class="section"><a href="oops-summary.html">Summary</a></span></dt></dl></dd><dt><span class="chapter"><a href="io.html">12. Input/Output</a></span></dt><dd><dl><dt><span class="section"><a href="io.html#files">Files</a></span></dt><dd><dl><dt><span class="section"><a href="io.html#using-files">Using file</a></span></dt></dl></dd><dt><span class="section"><a href="pickle.html">Pickle</a></span></dt><dd><dl><dt><span class="section"><a href="pickle.html#pickling-and-unpickling">Pickling and Unpickling</a></span></dt></dl></dd><dt><span class="section"><a href="io-summary.html">Summary</a></span></dt></dl></dd><dt><span class="chapter"><a href="exceptions.html">13. Exceptions</a></span></dt><dd><dl><dt><span class="section"><a href="exceptions.html#errors">Errors</a></span></dt><dt><span class="section"><a href="try-except.html">Try..Except</a></span></dt><dd><dl><dt><span class="section"><a href="try-except.html#handling-exceptions">Handling Exceptions</a></span></dt></dl></dd><dt><span class="section"><a href="raising-exceptions.html">Raising Exceptions</a></span></dt><dd><dl><dt><span class="section"><a href="raising-exceptions.html#how-to-raise-exceptions">How To Raise Exceptions</a></span></dt></dl></dd><dt><span class="section"><a href="try-finally.html">Try..Finally</a></span></dt><dd><dl><dt><span class="section"><a href="try-finally.html#using-try-finally">Using Finally</a></span></dt></dl></dd><dt><span class="section"><a href="exceptions-summary.html">Summary</a></span></dt></dl></dd><dt><span class="chapter"><a href="stdlib.html">14. The Python Standard Library</a></span></dt><dd><dl><dt><span class="section"><a href="stdlib.html#stdlib-intro">Introduction</a></span></dt><dt><span class="section"><a href="sys-module.html">The sys module</a></span></dt><dd><dl><dt><span class="section"><a href="sys-module.html#command-line-arguments">Command Line Arguments</a></span></dt><dt><span class="section"><a href="sys-module.html#more-sys">More sys</a></span></dt></dl></dd><dt><span class="section"><a href="os-module.html">The os module</a></span></dt><dt><span class="section"><a href="stdlib-summary.html">Summary</a></span></dt></dl></dd><dt><span class="chapter"><a href="more-python.html">15. More Python</a></span></dt><dd><dl><dt><span class="section"><a href="more-python.html#special-methods">Special Methods</a></span></dt><dt><span class="section"><a href="single-statement-blocks.html">Single Statement Blocks</a></span></dt><dt><span class="section"><a href="list-comprehension.html">List Comprehension</a></span></dt><dd><dl><dt><span class="section"><a href="list-comprehension.html#using-list-comprehension">Using List Comprehensions</a></span></dt></dl></dd><dt><span class="section"><a href="tuples-lists-functions.html">Receiving Tuples and Lists in Functions</a></span></dt><dt><span class="section"><a href="lambda-forms.html">Lambda Forms</a></span></dt><dd><dl><dt><span class="section"><a href="lambda-forms.html#using-lambda-forms">Using Lambda Forms</a></span></dt></dl></dd><dt><span class="section"><a href="exec-statement.html">The exec and eval statements</a></span></dt><dt><span class="section"><a href="assert-statement.html">The assert statement</a></span></dt><dt><span class="section"><a href="repr-function.html">The repr function</a></span></dt><dt><span class="section"><a href="more-python-summary.html">Summary</a></span></dt></dl></dd><dt><span class="chapter"><a href="what-next.html">16. What Next?</a></span></dt><dd><dl><dt><span class="section"><a href="what-next.html#graphical-software">Graphical Software</a></span></dt><dd><dl><dt><span class="section"><a href="what-next.html#id3080050">Summary of GUI Tools</a></span></dt></dl></dd><dt><span class="section"><a href="explore-more.html">Explore More</a></span></dt><dt><span class="section"><a href="what-next-summary.html">Summary</a></span></dt></dl></dd><dt><span class="appendix"><a href="floss.html">A. Free/Libré and Open Source Software (FLOSS)</a></span></dt><dt><span class="appendix"><a href="about.html">B. About</a></span></dt><dd><dl><dt><span class="section"><a href="about.html#colophon">Colophon</a></span></dt><dt><span class="section"><a href="about-the-author.html">About the Author</a></span></dt></dl></dd><dt><span class="appendix"><a href="revhistory.html">C. Revision History</a></span></dt><dd><dl><dt><span class="section"><a href="revhistory.html#timestamp">Timestamp</a></span></dt></dl></dd></dl></div><div class="list-of-tables"><p><b>List of Tables</b></p><dl><dt>5.1. <a href="operators.html#id3055069">Operators and their usage</a></dt><dt>5.2. <a href="operator-precedence.html#id3056064">Operator Precedence</a></dt><dt>15.1. <a href="more-python.html#id3078372">Some Special Methods</a></dt></dl></div><div class="list-of-examples"><p><b>List of Examples</b></p><dl><dt>3.1. <a href="interpreter-prompt.html#id3050174">Using the python interpreter prompt</a></dt><dt>3.2. <a href="source-file.html#id3050424">Using a Source File</a></dt><dt>4.1. <a href="data-type-object.html#id3052925">Using Variables and Literal constants</a></dt><dt>5.1. <a href="expressions.html#id3056452">Using Expressions</a></dt><dt>6.1. <a href="if-statement.html#using-if-statement">Using the if statement</a></dt><dt>6.2. <a href="while-statement.html#using-while-statement">Using the while statement</a></dt><dt>6.3. <a href="for-loop.html#using-for-statement">Using the for statement</a></dt><dt>6.4. <a href="break-statement.html#using-break-statement">Using the break statement</a></dt><dt>6.5. <a href="continue-statement.html#using-continue-statement">Using the continue statement</a></dt><dt>7.1. <a href="functions.html#id3061356">Defining a function</a></dt><dt>7.2. <a href="function-parameters.html#id3061456">Using Function Parameters</a></dt><dt>7.3. <a href="local-variables.html#id3061592">Using Local Variables</a></dt><dt>7.4. <a href="local-variables.html#id3061735">Using the global statement</a></dt><dt>7.5. <a href="default-argument-values.html#id3061860">Using Default Argument Values</a></dt><dt>7.6. <a href="keyword-arguments.html#id3062023">Using Keyword Arguments</a></dt><dt>7.7. <a href="return.html#id3062214">Using the literal statement</a></dt><dt>7.8. <a href="docstrings.html#id3062393">Using DocStrings</a></dt><dt>8.1. <a href="modules.html#id3064063">Using the sys module</a></dt><dt>8.2. <a href="module-name.html#id3064494">Using a module's __name__</a></dt><dt>8.3. <a href="making-modules.html#id3064587">How to create your own module</a></dt><dt>8.4. <a href="dir.html#id3064758">Using the dir function</a></dt><dt>9.1. <a href="list.html#id3066103">Using lists</a></dt><dt>9.2. <a href="tuple.html#id3066339">Using Tuples</a></dt><dt>9.3. <a href="tuple.html#id3066528">Output using tuples</a></dt><dt>9.4. <a href="dictionary.html#id3066768">Using dictionaries</a></dt><dt>9.5. <a href="sequences.html#id3067126">Using Sequences</a></dt><dt>9.6. <a href="references.html#id3067361">Objects and References</a></dt><dt>9.7. <a href="more-about-strings.html#id3067506">String Methods</a></dt><dt>10.1. <a href="the-solution.html#id3069271">Backup Script - The First Version</a></dt><dt>10.2. <a href="the-solution.html#id3069716">Backup Script - The Second Version</a></dt><dt>10.3. <a href="the-solution.html#id3069869">Backup Script - The Third Version (does not work!)</a></dt><dt>10.4. <a href="the-solution.html#id3070006">Backup Script - The Fourth Version</a></dt><dt>11.1. <a href="classes.html#id3072324">Creating a Class</a></dt><dt>11.2. <a href="object-methods.html#id3072450">Using Object Methods</a></dt><dt>11.3. <a href="class-init.html#id3072557">Using the __init__ method</a></dt><dt>11.4. <a href="class-and-object-vars.html#id3072746">Using Class and Object Variables</a></dt><dt>11.5. <a href="inheritance.html#id3073177">Using Inheritance</a></dt><dt>12.1. <a href="io.html#id3074897">Using files</a></dt><dt>12.2. <a href="pickle.html#id3075130">Pickling and Unpickling</a></dt><dt>13.1. <a href="try-except.html#id3075967">Handling Exceptions</a></dt><dt>13.2. <a href="raising-exceptions.html#id3076145">How to Raise Exceptions</a></dt><dt>13.3. <a href="try-finally.html#id3076307">Using Finally</a></dt><dt>14.1. <a href="sys-module.html#id3077190">Using sys.argv</a></dt><dt>15.1. <a href="list-comprehension.html#id3078606">Using List Comprehensions</a></dt><dt>15.2. <a href="lambda-forms.html#id3078769">Using Lambda Forms</a></dt></dl></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="preface.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top"> </td><td width="20%" align="center"> </td><td width="40%" align="right" valign="top"> Preface</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/inheritance.html b/help/byteofpython/read/inheritance.html
new file mode 100644
index 0000000..79a758b
--- /dev/null
+++ b/help/byteofpython/read/inheritance.html
@@ -0,0 +1,161 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Inheritance</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="oops.html" title="Chapter 11. Object-Oriented Programming" /><link rel="prev" href="class-and-object-vars.html" title="Class and Object Variables" /><link rel="next" href="oops-summary.html" title="Summary" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Inheritance</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="class-and-object-vars.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 11. Object-Oriented Programming</th><td width="20%" align="right"> <a accesskey="n" href="oops-summary.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="inheritance"></a>Inheritance</h2></div></div></div><p>
+
+ One of the major benefits of object oriented programming is
+ <span class="bold"><strong>reuse</strong></span> of code and one of the ways this is achieved is
+ through the <span class="emphasis"><em>inheritance</em></span> mechanism. Inheritance can be best imagined as
+ implementing a <span class="emphasis"><em>type and subtype</em></span> relationship between classes.
+
+ </p><p>
+
+ Suppose you want to write a program which has to keep track of the teachers and students in
+ a college. They have some common characteristics such as name, age and address. They also
+ have specific characteristics such as salary, courses and leaves for teachers and,
+ marks and fees for students.
+
+ </p><p>
+
+ You can create two independent classes for each type and process them but adding a new
+ common characteristic would mean adding to both of these independent classes. This quickly
+ becomes unwieldy.
+
+ </p><p>
+
+ A better way would be to create a common class called <code class="classname">SchoolMember</code>
+ and then have the teacher and student classes <span class="emphasis"><em>inherit</em></span> from this
+ class i.e. they will become sub-types of this type (class) and then we can add specific
+ characteristics to these sub-types.
+
+ </p><p>
+
+ There are many advantages to this approach. If we add/change any functionality in
+ <code class="classname">SchoolMember</code>, this is automatically reflected in the subtypes as
+ well. For example, you can add a new ID card field for both teachers and students by simply
+ adding it to the SchoolMember class. However, changes in the subtypes do not affect other
+ subtypes. Another advantage is that if you can refer to a teacher or student object as a
+ <code class="classname">SchoolMember</code> object which could be useful in some situations such as
+ counting of the number of school members. This is called
+ <span class="bold"><strong>polymorphism</strong></span> where a sub-type can be substituted in any
+ situation where a parent type is expected i.e. the object can be treated as an instance of
+ the parent class.
+
+ </p><p>
+
+ Also observe that we <span class="emphasis"><em>reuse</em></span> the code of the parent class and we do not
+ need to repeat it in the different classes as we would have had to in case we had used
+ independent classes.
+
+ </p><p>
+
+ The <code class="classname">SchoolMember</code> class in this situation is known as the
+ <span class="emphasis"><em>base class</em></span> or the <span class="emphasis"><em>superclass</em></span>. The
+ <code class="classname">Teacher</code> and <code class="classname">Student</code> classes are called the
+ <span class="emphasis"><em>derived classes</em></span> or <span class="emphasis"><em>subclasses</em></span>.
+
+ </p><p>
+
+ We will now see this example as a program.
+
+ </p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="using-inheritance"></a>Using Inheritance</h3></div></div></div><div class="example"><a id="id3073177"></a><p class="title"><b>Example 11.5. Using Inheritance</b></p><pre class="programlisting">
+
+<span class="py-comment">#!/usr/bin/python</span>
+<span class="py-comment"># Filename: inherit.py</span>
+
+<span class="py-statement">class</span> <span class="py-identifier">SchoolMember</span>:
+ <span class="py-string">'''Represents any school member.'''</span>
+ <span class="py-statement">def</span> <span class="py-identifier">__init__</span>(<span class="py-builtin">self</span>, name, age):
+ <span class="py-builtin">self</span>.name = name
+ <span class="py-builtin">self</span>.age = age
+ <span class="py-statement">print</span> <span class="py-string">'(Initialized SchoolMember: %s)'</span> % <span class="py-builtin">self</span>.name
+
+ <span class="py-statement">def</span> <span class="py-identifier">tell</span>(<span class="py-builtin">self</span>):
+ <span class="py-string">'''Tell my details.'''</span>
+ <span class="py-statement">print</span> <span class="py-string">'Name:"%s" Age:"%s"'</span> % (<span class="py-builtin">self</span>.name, <span class="py-builtin">self</span>.age),
+
+<span class="py-statement">class</span> <span class="py-identifier">Teacher</span>(SchoolMember):
+ <span class="py-string">'''Represents a teacher.'''</span>
+ <span class="py-statement">def</span> <span class="py-identifier">__init__</span>(<span class="py-builtin">self</span>, name, age, salary):
+ SchoolMember.__init__(<span class="py-builtin">self</span>, name, age)
+ <span class="py-builtin">self</span>.salary = salary
+ <span class="py-statement">print</span> <span class="py-string">'(Initialized Teacher: %s)'</span> % <span class="py-builtin">self</span>.name
+
+ <span class="py-statement">def</span> <span class="py-identifier">tell</span>(<span class="py-builtin">self</span>):
+ SchoolMember.tell(<span class="py-builtin">self</span>)
+ <span class="py-statement">print</span> <span class="py-string">'Salary: "%d"'</span> % <span class="py-builtin">self</span>.salary
+
+<span class="py-statement">class</span> <span class="py-identifier">Student</span>(SchoolMember):
+ <span class="py-string">'''Represents a student.'''</span>
+ <span class="py-statement">def</span> <span class="py-identifier">__init__</span>(<span class="py-builtin">self</span>, name, age, marks):
+ SchoolMember.__init__(<span class="py-builtin">self</span>, name, age)
+ <span class="py-builtin">self</span>.marks = marks
+ <span class="py-statement">print</span> <span class="py-string">'(Initialized Student: %s)'</span> % <span class="py-builtin">self</span>.name
+
+ <span class="py-statement">def</span> <span class="py-identifier">tell</span>(<span class="py-builtin">self</span>):
+ SchoolMember.tell(<span class="py-builtin">self</span>)
+ <span class="py-statement">print</span> <span class="py-string">'Marks: "%d"'</span> % <span class="py-builtin">self</span>.marks
+
+t = Teacher(<span class="py-string">'Mrs. Shrividya'</span>, <span class="py-number">40</span>, <span class="py-number">30000</span>)
+s = Student(<span class="py-string">'Swaroop'</span>, <span class="py-number">22</span>, <span class="py-number">75</span>)
+
+<span class="py-statement">print</span> <span class="py-comment"># prints a blank line</span>
+
+members = [t, s]
+<span class="py-statement">for</span> member <span class="py-statement">in</span> members:
+ member.tell() <span class="py-comment"># works for both Teachers and Students</span>
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3073189"></a>Output</h4></div></div></div><pre class="screen">
+
+$ python inherit.py
+(Initialized SchoolMember: Mrs. Shrividya)
+(Initialized Teacher: Mrs. Shrividya)
+(Initialized SchoolMember: Swaroop)
+(Initialized Student: Swaroop)
+
+Name:"Mrs. Shrividya" Age:"40" Salary: "30000"
+Name:"Swaroop" Age:"22" Marks: "75"
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3073202"></a>How It Works</h4></div></div></div><p>
+
+ To use inheritance, we specify the base class names in a tuple following
+ the class name in the class definition. Next, we observe that the
+ <code class="methodname">__init__</code> method of the base class is explicitly
+ called using the <code class="varname">self</code> variable so that we can initialize
+ the base class part of the object. This is very important to remember -
+ Python does not automatically call the constructor of the base class, you
+ have to explicitly call it yourself.
+
+ </p><p>
+
+ We also observe that we can call methods of the base class by prefixing
+ the class name to the method call and then pass in the
+ <code class="varname">self</code> variable along with any arguments.
+
+ </p><p>
+
+ Notice that we can treat instances of <code class="classname">Teacher</code> or
+ <code class="classname">Student</code> as just instances of the
+ <code class="classname">SchoolMember</code> when we use the
+ <code class="methodname">tell</code> method of the <code class="classname">SchoolMember</code>
+ class.
+
+ </p><p>
+
+ Also, observe that the <code class="methodname">tell</code> method of the
+ subtype is called and not the <code class="methodname">tell</code> method of the
+ <code class="classname">SchoolMember</code> class. One way to understand this is that
+ Python <span class="emphasis"><em>always</em></span> starts looking for methods in the type, which
+ in this case it does. If it could not find the method, it starts looking at the
+ methods belonging to its base classes one by one in the order they are specified
+ in the tuple in the class definition.
+
+ </p><p>
+
+ A note on terminology - if more than one class is listed in the inheritance
+ tuple, then it is called <span class="emphasis"><em>multiple inheritance</em></span>.
+
+ </p></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="class-and-object-vars.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="oops.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="oops-summary.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Class and Object Variables </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Summary</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/installation-summary.html b/help/byteofpython/read/installation-summary.html
new file mode 100644
index 0000000..aa86fe8
--- /dev/null
+++ b/help/byteofpython/read/installation-summary.html
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Summary</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="installing-python.html" title="Chapter 2. Installing Python" /><link rel="prev" href="for-windows-users.html" title="For Windows Users" /><link rel="next" href="first-steps.html" title="Chapter 3. First Steps" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Summary</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="for-windows-users.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 2. Installing Python</th><td width="20%" align="right"> <a accesskey="n" href="first-steps.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="installation-summary"></a>Summary</h2></div></div></div><p>
+
+ For a Linux system, you most probably already have Python installed on your system.
+ Otherwise, you can install it using the package management software that comes with
+ your distribution. For a Windows system, installing Python is as easy as downloading
+ the installer and double-clicking on it. From now on, we will assume that you have
+ Python installed on your system.
+
+ </p><p>
+
+ Next, we will write our first Python program.
+
+ </p></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="for-windows-users.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="installing-python.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="first-steps.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">For Windows Users </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Chapter 3. First Steps</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/installing-python.html b/help/byteofpython/read/installing-python.html
new file mode 100644
index 0000000..7244c42
--- /dev/null
+++ b/help/byteofpython/read/installing-python.html
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Chapter 2. Installing Python</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="index.html" title="A Byte of Python" /><link rel="prev" href="what-programmers-say.html" title="What Programmers Say" /><link rel="next" href="for-windows-users.html" title="For Windows Users" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 2. Installing Python</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="what-programmers-say.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="for-windows-users.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="chapter" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title"><a id="installing-python"></a>Chapter 2. Installing Python</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="installing-python.html#for-linux-bsd-users">For Linux/BSD users</a></span></dt><dt><span class="section"><a href="for-windows-users.html">For Windows Users</a></span></dt><dt><span class="section"><a href="installation-summary.html">Summary</a></span></dt></dl></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="for-linux-bsd-users"></a>For Linux/BSD users</h2></div></div></div><p>
+
+ If you are using a Linux distribution such as Fedora or Mandrake or
+ {put your choice here}, or a BSD system such as FreeBSD, then you probably already
+ have Python installed on your system.
+
+ </p><p>
+
+ To test if you have Python already installed on your Linux box, open a shell
+ program (like <span class="application">konsole</span> or
+ <span class="application">gnome-terminal</span>) and enter the command
+ <span><strong class="command">python -V</strong></span> as shown below.
+
+ </p><div class="informalexample"><pre class="screen">
+$ python -V
+Python 2.3.4
+ </pre></div><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>
+
+ <code class="prompt">$</code> is the prompt of the shell. It will be different for you
+ depending on the settings of your OS, hence I will indicate the prompt by
+ just the <code class="prompt">$</code> symbol.
+
+ </p></div><p>
+
+ If you see some version information like the one shown above, then you have
+ Python installed already.
+
+ </p><p>
+
+ However, if you get a message like this one:
+
+ </p><pre class="screen">
+$ python -V
+bash: python: command not found
+ </pre><p>
+
+ then, you don't have Python installed. This is highly unlikely but possible.
+
+ </p><p>
+
+ In this case, you have two ways of installing Python on your system.
+
+ </p><div class="itemizedlist"><ul type="disc"><li><p>
+
+ Install the binary packages using the package management software
+ that comes with your OS, such as <span class="application">yum</span> in
+ Fedora Linux, <span class="application">urpmi</span> in Mandrake Linux,
+ <span class="application">apt-get</span> in Debian Linux,
+ <span class="application">pkg_add</span> in FreeBSD, etc. Note that you
+ will need an internet connection to use this method.
+
+ </p><p>
+
+ Alternatively, you can download the binaries from somewhere else and
+ then copy to your PC and install it.
+
+ </p></li><li><p>
+
+ You can compile Python from the <a href="http://www.python.org/download/" target="_top">source code</a> and install it. The compilation instructions are
+ provided at the website.
+
+ </p></li></ul></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="what-programmers-say.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="for-windows-users.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">What Programmers Say </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> For Windows Users</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/interpreter-prompt.html b/help/byteofpython/read/interpreter-prompt.html
new file mode 100644
index 0000000..b377fce
--- /dev/null
+++ b/help/byteofpython/read/interpreter-prompt.html
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Using the interpreter prompt</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="first-steps.html" title="Chapter 3. First Steps" /><link rel="prev" href="first-steps.html" title="Chapter 3. First Steps" /><link rel="next" href="choosing-an-editor.html" title="Choosing an Editor" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Using the interpreter prompt</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="first-steps.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 3. First Steps</th><td width="20%" align="right"> <a accesskey="n" href="choosing-an-editor.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="interpreter-prompt"></a>Using the interpreter prompt</h2></div></div></div><p>
+
+ Start the intepreter on the command line by entering <span><strong class="command">python</strong></span> at the
+ shell prompt. Now enter <code class="literal">print 'Hello World'</code> followed by the
+ <span><strong class="keycap">Enter</strong></span> key. You should see the words
+ <code class="computeroutput">Hello World</code> as output.
+
+ </p><p>
+
+ For Windows users, you can run the interpreter in the command line if you have set
+ the <code class="envar">PATH</code> variable appropriately. Alternatively, you can use the
+ <span class="acronym">IDLE</span> program. IDLE is short for Integrated DeveLopment Environment.
+ Click on <span class="guimenu">Start</span> -&gt; <span class="guisubmenu">Programs</span> -&gt;
+ <span class="guisubmenu">Python 2.3</span> -&gt; <span class="guisubmenu">IDLE (Python GUI)</span>.
+ Linux users can use IDLE too.
+
+ </p><p>
+
+ Note that the &lt;&lt;&lt; signs are the prompt for entering Python statements.
+
+ </p><div class="example"><a id="id3050174"></a><p class="title"><b>Example 3.1. Using the python interpreter prompt</b></p><pre class="screen">
+
+$ python
+Python 2.3.4 (#1, Oct 26 2004, 16:42:40)
+[GCC 3.4.2 20041017 (Red Hat 3.4.2-6.fc3)] on linux2
+Type "help", "copyright", "credits" or "license" for more information.
+&gt;&gt;&gt; print 'hello world'
+hello world
+&gt;&gt;&gt;
+
+ </pre></div><p>
+
+ Notice that Python gives you the output of the line immediately! What you just entered
+ is a single Python <span class="emphasis"><em>statement</em></span>. We use <code class="literal">print</code>
+ to (unsurprisingly) print any value that you supply to it. Here, we are supplying the
+ text <code class="literal">Hello World</code> and this is promptly printed to the screen.
+
+ </p><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">How to quit the Python prompt</h3><p>
+
+ To exit the prompt, press
+ <span><strong class="keycap">Ctrl</strong></span>-<span><strong class="keycap">d</strong></span>
+ if you are using IDLE or are using a Linux/BSD shell. In case of the Windows
+ command prompt, press <span><strong class="keycap">Ctrl</strong></span>-<span><strong class="keycap">z</strong></span>
+ followed by <span><strong class="keycap">Enter</strong></span>.
+
+ </p></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="first-steps.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="first-steps.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="choosing-an-editor.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 3. First Steps </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Choosing an Editor</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/introduction.html b/help/byteofpython/read/introduction.html
new file mode 100644
index 0000000..06c6aa5
--- /dev/null
+++ b/help/byteofpython/read/introduction.html
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Chapter 1. Introduction</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="index.html" title="A Byte of Python" /><link rel="prev" href="something-to-think-about.html" title="Something To Think About" /><link rel="next" href="features-of-python.html" title="Features of Python" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 1. Introduction</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="something-to-think-about.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="features-of-python.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="chapter" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title"><a id="introduction"></a>Chapter 1. Introduction</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="introduction.html#introduction-section">Introduction</a></span></dt><dt><span class="section"><a href="features-of-python.html">Features of Python</a></span></dt><dd><dl><dt><span class="section"><a href="features-of-python.html#introduction-summary">Summary</a></span></dt></dl></dd><dt><span class="section"><a href="why-not-perl.html">Why not Perl?</a></span></dt><dt><span class="section"><a href="what-programmers-say.html">What Programmers Say</a></span></dt></dl></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="introduction-section"></a>Introduction</h2></div></div></div><p>
+
+ Python is one of those rare languages which can claim to be both
+ <span class="bold"><strong>simple</strong></span> and <span class="bold"><strong>powerful</strong></span>.
+ You will find that you will be pleasantly surprised on how easy it is to concentrate
+ on the solution to the problem rather than the syntax and structure of the language
+ you are programming in.
+
+ </p><p>
+
+ The official introduction to Python is
+
+ </p><div class="blockquote"><blockquote class="blockquote"><p>
+
+ Python is an easy to learn, powerful programming language. It has
+ efficient high-level data structures and a simple but effective approach
+ to object-oriented programming. Python's elegant syntax and dynamic typing,
+ together with its interpreted nature, make it an ideal language for
+ scripting and rapid application development in many areas on most platforms.
+
+ </p></blockquote></div><p>
+
+ I will discuss most of these features in more detail in the next section.
+
+ </p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3>
+
+ Guido van Rossum, the creator of the Python language, named the language after the
+ BBC show "Monty Python's Flying Circus ". He doesn't particularly like
+ snakes that kill animals for food by winding their long bodies around them and
+ crushing them.
+
+ </div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="something-to-think-about.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="features-of-python.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Something To Think About </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Features of Python</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/io-summary.html b/help/byteofpython/read/io-summary.html
new file mode 100644
index 0000000..d22516d
--- /dev/null
+++ b/help/byteofpython/read/io-summary.html
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Summary</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="io.html" title="Chapter 12. Input/Output" /><link rel="prev" href="pickle.html" title="Pickle" /><link rel="next" href="exceptions.html" title="Chapter 13. Exceptions" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Summary</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="pickle.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 12. Input/Output</th><td width="20%" align="right"> <a accesskey="n" href="exceptions.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="io-summary"></a>Summary</h2></div></div></div><p>
+
+ We have discussed various types of input/output and also file handling and using the
+ pickle module.
+
+ </p><p>
+
+ Next, we will explore the concept of exceptions.
+
+ </p></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="pickle.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="io.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="exceptions.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Pickle </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Chapter 13. Exceptions</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/io.html b/help/byteofpython/read/io.html
new file mode 100644
index 0000000..e3fe577
--- /dev/null
+++ b/help/byteofpython/read/io.html
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Chapter 12. Input/Output</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="index.html" title="A Byte of Python" /><link rel="prev" href="oops-summary.html" title="Summary" /><link rel="next" href="pickle.html" title="Pickle" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 12. Input/Output</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="oops-summary.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="pickle.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="chapter" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title"><a id="io"></a>Chapter 12. Input/Output</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="io.html#files">Files</a></span></dt><dd><dl><dt><span class="section"><a href="io.html#using-files">Using file</a></span></dt></dl></dd><dt><span class="section"><a href="pickle.html">Pickle</a></span></dt><dd><dl><dt><span class="section"><a href="pickle.html#pickling-and-unpickling">Pickling and Unpickling</a></span></dt></dl></dd><dt><span class="section"><a href="io-summary.html">Summary</a></span></dt></dl></div><p>
+
+ There will be lots of times when you want your program to interact with the user (which could be
+ yourself). You would want to take input from the user and then print some results back. We can
+ achieve this using the <code class="function">raw_input</code> and <code class="literal">print</code> statements
+ respectively. For output, we can also use the various methods of the <code class="classname">str</code>
+ (string) class. For example, you can use the <code class="methodname">rjust</code> method to get a
+ string which is right justified to a specified width. See <code class="literal">help(str)</code> for more
+ details.
+
+ </p><p>
+
+ Another common type of input/output is dealing with files. The ability to create, read and write
+ files is essential to many programs and we will explore this aspect in this chapter.
+
+ </p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="files"></a>Files</h2></div></div></div><p>
+
+ You can open and use files for reading or writing by creating an object of the
+ <code class="classname">file</code> class and using its <code class="methodname">read</code>,
+ <code class="methodname">readline</code> or <code class="methodname">write</code> methods
+ appropriately to read from or write to the file. The ability to read or write to
+ the file depends on the mode you have specified for the file opening. Then finally,
+ when you are finished with the file, you call the <code class="methodname">close</code>
+ method to tell Python that we are done using the file.
+
+ </p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="using-files"></a>Using file</h3></div></div></div><div class="example"><a id="id3074897"></a><p class="title"><b>Example 12.1. Using files</b></p><pre class="programlisting">
+
+<span class="py-comment">#!/usr/bin/python</span>
+<span class="py-comment"># Filename: using_file.py</span>
+
+poem = <span class="py-string">'''\
+Programming is fun
+When the work is done
+if you wanna make your work also fun:
+ use Python!
+'''</span>
+
+f = <span class="py-builtin">file</span>(<span class="py-string">'poem.txt'</span>, <span class="py-string">'w'</span>) <span class="py-comment"># open for 'w'riting</span>
+f.write(poem) <span class="py-comment"># write text to file</span>
+f.close() <span class="py-comment"># close the file</span>
+
+f = <span class="py-builtin">file</span>(<span class="py-string">'poem.txt'</span>) <span class="py-comment"># if no mode is specified, 'r'ead mode is assumed by default</span>
+<span class="py-statement">while</span> <span class="py-builtin">True</span>:
+ line = f.readline()
+ <span class="py-statement">if</span> <span class="py-builtin">len</span>(line) == <span class="py-number">0</span>: <span class="py-comment"># Zero length indicates EOF</span>
+ <span class="py-statement">break</span>
+ <span class="py-statement">print</span> line, <span class="py-comment"># Notice comma to avoid automatic newline added by Python</span>
+f.close() <span class="py-comment"># close the file</span>
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3074910"></a>Output</h4></div></div></div><pre class="screen">
+
+$ python using_file.py
+Programming is fun
+When the work is done
+if you wanna make your work also fun:
+ use Python!
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3074940"></a>How It Works</h4></div></div></div><p>
+
+ First, we create an instance of the <code class="classname">file</code> class
+ by specifying the name of the file and the mode in which we want to open
+ the file. The mode can be a read mode (<code class="literal">'r'</code>), write
+ mode (<code class="literal">'w'</code>) or append mode (<code class="literal">'a'</code>).
+ There are actually many more modes available and <code class="literal">help(file)</code>
+ will give you more details about them.
+
+ </p><p>
+
+ We first open the file in write mode and use the <code class="methodname">write</code>
+ method of the <code class="classname">file</code> class to write to the file and then
+ we finally <code class="methodname">close</code> the file.
+
+ </p><p>
+
+ Next, we open the same file again for reading. If we don't specify a mode,
+ then the read mode is the default one. We read in each line of the file
+ using the <code class="methodname">readline</code> method, in a loop. This method
+ returns a complete line including the newline character at the end of the
+ line. So, when an <span class="emphasis"><em>empty</em></span> string is returned, it
+ indicates that the end of the file has been reached and we stop the loop.
+
+ </p><p>
+
+ Notice that we use a comma with the <code class="literal">print</code> statement to
+ suppress the automatic newline that the <code class="literal">print</code> statement
+ adds because the line that is read from the file already ends with a
+ newline character. Then, we finally <code class="methodname">close</code> the file.
+
+ </p><p>
+
+ Now, see the contents of the <code class="filename">poem.txt</code> file to confirm
+ that the program has indeed worked properly.
+
+ </p></div></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="oops-summary.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="pickle.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Summary </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Pickle</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/keyword-arguments.html b/help/byteofpython/read/keyword-arguments.html
new file mode 100644
index 0000000..802c917
--- /dev/null
+++ b/help/byteofpython/read/keyword-arguments.html
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Keyword Arguments</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="functions.html" title="Chapter 7. Functions" /><link rel="prev" href="default-argument-values.html" title="Default Argument Values" /><link rel="next" href="return.html" title="The return statement" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Keyword Arguments</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="default-argument-values.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 7. Functions</th><td width="20%" align="right"> <a accesskey="n" href="return.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="keyword-arguments"></a>Keyword Arguments</h2></div></div></div><p>
+
+ If you have some functions with many parameters and you want to specify only some of them,
+ then you can give values for such parameters by naming them - this is called
+ <span class="emphasis"><em>keyword arguments</em></span> - we use the name (keyword) instead of the position
+ (which we have been using all along) to specify the arguments to the function.
+
+ </p><p>
+
+ There are two <span class="emphasis"><em>advantages</em></span> - one, using the function is easier since we
+ do not need to worry about the order of the arguments. Two, we can give values to only
+ those parameters which we want, provided that the other parameters have default argument
+ values.
+
+ </p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="id3062017"></a>Using Keyword Arguments</h3></div></div></div><div class="example"><a id="id3062023"></a><p class="title"><b>Example 7.6. Using Keyword Arguments</b></p><pre class="programlisting">
+
+<span class="py-comment">#!/usr/bin/python</span>
+<span class="py-comment"># Filename: func_key.py</span>
+
+<span class="py-statement">def</span> <span class="py-identifier">func</span>(a, b=<span class="py-number">5</span>, c=<span class="py-number">10</span>):
+ <span class="py-statement">print</span> <span class="py-string">'a is'</span>, a, <span class="py-string">'and b is'</span>, b, <span class="py-string">'and c is'</span>, c
+
+func(<span class="py-number">3</span>, <span class="py-number">7</span>)
+func(<span class="py-number">25</span>, c=<span class="py-number">24</span>)
+func(c=<span class="py-number">50</span>, a=<span class="py-number">100</span>)
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3062036"></a>Output</h4></div></div></div><pre class="screen">
+
+$ python func_key.py
+a is 3 and b is 7 and c is 10
+a is 25 and b is 5 and c is 24
+a is 100 and b is 5 and c is 50
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3062054"></a>How It Works</h4></div></div></div><p>
+
+ The function named <code class="function">func</code> has one parameter without
+ default argument values, followed by two parameters with default argument
+ values.
+
+ </p><p>
+
+ In the first usage, <code class="literal">func(3, 7)</code>, the parameter
+ <code class="varname">a</code> gets the value <code class="literal">3</code>, the parameter
+ <code class="varname">b</code> gets the value <code class="literal">5</code> and
+ <code class="varname">c</code> gets the default value of <code class="literal">10</code>.
+
+ </p><p>
+
+ In the second usage <code class="literal">func(25, c=24)</code>, the variable
+ <code class="varname">a</code> gets the value of 25 due to the position of the
+ argument. Then, the parameter <code class="varname">c</code> gets the value of
+ <code class="literal">24</code> due to naming i.e. keyword arguments. The variable
+ <code class="varname">b</code> gets the default value of <code class="literal">5</code>.
+
+ </p><p>
+
+ In the third usage <code class="literal">func(c=50, a=100)</code>, we use keyword
+ arguments completely to specify the values. Notice, that we are specifying
+ value for parameter <code class="varname">c</code> before that for
+ <code class="varname">a</code> even though <code class="varname">a</code> is defined before
+ <code class="varname">c</code> in the function definition.
+
+ </p></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="default-argument-values.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="functions.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="return.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Default Argument Values </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> The return statement</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/lambda-forms.html b/help/byteofpython/read/lambda-forms.html
new file mode 100644
index 0000000..364cb93
--- /dev/null
+++ b/help/byteofpython/read/lambda-forms.html
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Lambda Forms</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="more-python.html" title="Chapter 15. More Python" /><link rel="prev" href="tuples-lists-functions.html" title="Receiving Tuples and Lists in Functions" /><link rel="next" href="exec-statement.html" title="The exec and eval statements" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Lambda Forms</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="tuples-lists-functions.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 15. More Python</th><td width="20%" align="right"> <a accesskey="n" href="exec-statement.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="lambda-forms"></a>Lambda Forms</h2></div></div></div><p>
+
+ A <code class="literal">lambda</code> statement is used to create new function objects and then
+ return them at runtime.
+
+ </p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="using-lambda-forms"></a>Using Lambda Forms</h3></div></div></div><div class="example"><a id="id3078769"></a><p class="title"><b>Example 15.2. Using Lambda Forms</b></p><pre class="programlisting">
+
+<span class="py-comment">#!/usr/bin/python</span>
+<span class="py-comment"># Filename: lambda.py</span>
+
+<span class="py-statement">def</span> <span class="py-identifier">make_repeater</span>(n):
+ <span class="py-statement">return</span> <span class="py-statement">lambda</span> s: s * n
+
+twice = make_repeater(<span class="py-number">2</span>)
+
+<span class="py-statement">print</span> twice(<span class="py-string">'word'</span>)
+<span class="py-statement">print</span> twice(<span class="py-number">5</span>)
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3078781"></a>Output</h4></div></div></div><pre class="screen">
+
+$ python lambda.py
+wordword
+10
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3078801"></a>How It Works</h4></div></div></div><p>
+
+ Here, we use a function <code class="function">make_repeater</code> to create new
+ function objects at runtime and return it. A <code class="literal">lambda</code>
+ statement is used to create the function object. Essentially, the
+ <code class="literal">lambda</code> takes a parameter followed by a single expression
+ only which becomes the body of the function and the value of this
+ expression is returned by the new function. Note that even a
+ <code class="literal">print</code> statement cannot be used inside a lambda form,
+ only expressions.
+
+ </p></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="tuples-lists-functions.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="more-python.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="exec-statement.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Receiving Tuples and Lists in Functions </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> The exec and eval statements</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/license.html b/help/byteofpython/read/license.html
new file mode 100644
index 0000000..c7421cf
--- /dev/null
+++ b/help/byteofpython/read/license.html
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>License Terms</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="preface.html" title="Preface" /><link rel="prev" href="official-website.html" title="Official Website" /><link rel="next" href="feedback.html" title="Feedback" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">License Terms</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="official-website.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Preface</th><td width="20%" align="right"> <a accesskey="n" href="feedback.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="license"></a>License Terms</h2></div></div></div><p>
+ This book is licensed under the <a href="http://creativecommons.org/licenses/by-nc-sa/2.0/" target="_top">Creative Commons
+ Attribution-NonCommercial-ShareAlike License 2.0</a> .
+ </p><p>
+ Basically, you are free to copy, distribute, and display the book, as long
+ as you give credit to me. The restrictions are that you cannot use the book
+ for commercial purposes without my permission. You are free to modify and
+ build upon this work, provided that you clearly mark all changes and release
+ the modified work under the same license as this book.
+ </p><p>
+ Please visit the <a href="http://creativecommons.org/licenses/by-nc-sa/2.0/" target="_top">Creative Commons website</a> for the full and exact text of the license, or
+ for an easy-to-understand version. There is even a comic strip explaining the
+ terms of the license.
+ </p></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="official-website.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="preface.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="feedback.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Official Website </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Feedback</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/list-comprehension.html b/help/byteofpython/read/list-comprehension.html
new file mode 100644
index 0000000..22d6a81
--- /dev/null
+++ b/help/byteofpython/read/list-comprehension.html
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>List Comprehension</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="more-python.html" title="Chapter 15. More Python" /><link rel="prev" href="single-statement-blocks.html" title="Single Statement Blocks" /><link rel="next" href="tuples-lists-functions.html" title="Receiving Tuples and Lists in Functions" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">List Comprehension</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="single-statement-blocks.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 15. More Python</th><td width="20%" align="right"> <a accesskey="n" href="tuples-lists-functions.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="list-comprehension"></a>List Comprehension</h2></div></div></div><p>
+
+ List comprehensions are used to derive a new list from an existing list. For example, you
+ have a list of numbers and you want to get a corresponding list with all the numbers
+ multiplied by 2 but only when the number itself is greater than 2. List comprehensions
+ are ideal for such situations.
+
+ </p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="using-list-comprehension"></a>Using List Comprehensions</h3></div></div></div><div class="example"><a id="id3078606"></a><p class="title"><b>Example 15.1. Using List Comprehensions</b></p><pre class="programlisting">
+
+<span class="py-comment">#!/usr/bin/python</span>
+<span class="py-comment"># Filename: list_comprehension.py</span>
+
+listone = [<span class="py-number">2</span>, <span class="py-number">3</span>, <span class="py-number">4</span>]
+listtwo = [<span class="py-number">2</span>*i <span class="py-statement">for</span> i <span class="py-statement">in</span> listone <span class="py-statement">if</span> i &gt; <span class="py-number">2</span>]
+<span class="py-statement">print</span> listtwo
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3078619"></a>Output</h4></div></div></div><pre class="screen">
+
+$ python list_comprehension.py
+[6, 8]
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3078638"></a>How It Works</h4></div></div></div><p>
+
+ Here, we derive a new list by specifying the manipulation to be done
+ (<code class="literal">2*i</code>) when some condition is satisfied
+ (<code class="literal">if i &gt; 2</code>). Note that the original list
+ remains unmodified. Many a time, we use loops to process each element of
+ a list, the same can be achieved using list comprehensions in a more
+ precise, compact and explicit manner.
+
+ </p></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="single-statement-blocks.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="more-python.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="tuples-lists-functions.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Single Statement Blocks </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Receiving Tuples and Lists in Functions</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/list.html b/help/byteofpython/read/list.html
new file mode 100644
index 0000000..af3be18
--- /dev/null
+++ b/help/byteofpython/read/list.html
@@ -0,0 +1,150 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>List</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="data-structures.html" title="Chapter 9. Data Structures" /><link rel="prev" href="data-structures.html" title="Chapter 9. Data Structures" /><link rel="next" href="tuple.html" title="Tuple" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">List</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="data-structures.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 9. Data Structures</th><td width="20%" align="right"> <a accesskey="n" href="tuple.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="list"></a>List</h2></div></div></div><p>
+
+ A <code class="literal">list</code> is a data structure that holds an ordered collection of items
+ i.e. you can store a <span class="emphasis"><em>sequence</em></span> of items in a list. This is easy to
+ imagine if you can think of a shopping list where you have a list of items to buy,
+ except that you probbly have each item on a separate line in your shopping list whereas
+ in Python you put commas in between them.
+
+ </p><p>
+
+ The list of items should be enclosed in square brackets so that Python understands that
+ you are specifying a list. Once you have created a list, you can add, remove or search
+ for items in the list. Since, we can add and remove items, we say that a list is a
+ <span class="emphasis"><em>mutable</em></span> data type i.e. this type can be altered.
+
+ </p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="list-objects-classes"></a>Quick introduction to Objects and Classes</h3></div></div></div><p>
+
+ Although, I've been generally delaying the discussion of objects and classes
+ till now, a little explanation is needed right now so that you can understand
+ lists better. We will still explore this topic in detail in its own
+ <a href="oops.html" title="Chapter 11. Object-Oriented Programming">chapter</a>.
+
+ </p><p>
+
+ A list is an example of usage of objects and classes. When you use a variable
+ <code class="varname">i</code> and assign a value to it, say integer <code class="literal">5</code>
+ to it, you can think of it as creating an <span class="bold"><strong>object</strong></span>
+ (instance) <code class="varname">i</code> of <span class="bold"><strong>class</strong></span> (type)
+ <code class="classname">int</code>. In fact, you can see <code class="literal">help(int)</code>
+ to understand this better.
+
+ </p><p>
+
+ A class can also have <span class="bold"><strong>methods</strong></span> i.e. functions
+ defined for use with respect to that class only. You can use these pieces of
+ functionality only when you have an object of that class. For example, Python
+ provides an <code class="function">append</code> method for the <code class="classname">list</code>
+ class which allows you to add an item to the end of the list. For example,
+ <code class="literal">mylist.append('an item')</code> will add that string to the list
+ <code class="varname">mylist</code>. Note the use of dotted notation for accessing methods
+ of the objects.
+
+ </p><p>
+
+ A class can also have <span class="bold"><strong>fields</strong></span> which are nothing
+ but variables defined for use with respect to that class only. You can use these
+ variables/names only when you have an object of that class. Fields are also
+ accessed by the dotted notation, for example, <code class="varname">mylist.field</code> .
+
+ </p></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="using-lists"></a>Using Lists</h3></div></div></div><div class="example"><a id="id3066103"></a><p class="title"><b>Example 9.1. Using lists</b></p><pre class="programlisting">
+
+<span class="py-comment">#!/usr/bin/python</span>
+<span class="py-comment"># Filename: using_list.py</span>
+
+<span class="py-comment"># This is my shopping list</span>
+shoplist = [<span class="py-string">'apple'</span>, <span class="py-string">'mango'</span>, <span class="py-string">'carrot'</span>, <span class="py-string">'banana'</span>]
+
+<span class="py-statement">print</span> <span class="py-string">'I have'</span>, <span class="py-builtin">len</span>(shoplist), <span class="py-string">'items to purchase.'</span>
+
+<span class="py-statement">print</span> <span class="py-string">'These items are:'</span>, <span class="py-comment"># Notice the comma at end of the line</span>
+<span class="py-statement">for</span> item <span class="py-statement">in</span> shoplist:
+ <span class="py-statement">print</span> item,
+
+<span class="py-statement">print</span> <span class="py-string">'\nI also have to buy rice.'</span>
+shoplist.append(<span class="py-string">'rice'</span>)
+<span class="py-statement">print</span> <span class="py-string">'My shopping list is now'</span>, shoplist
+
+<span class="py-statement">print</span> <span class="py-string">'I will sort my list now'</span>
+shoplist.sort()
+<span class="py-statement">print</span> <span class="py-string">'Sorted shopping list is'</span>, shoplist
+
+<span class="py-statement">print</span> <span class="py-string">'The first item I will buy is'</span>, shoplist[<span class="py-number">0</span>]
+olditem = shoplist[<span class="py-number">0</span>]
+<span class="py-statement">del</span> shoplist[<span class="py-number">0</span>]
+<span class="py-statement">print</span> <span class="py-string">'I bought the'</span>, olditem
+<span class="py-statement">print</span> <span class="py-string">'My shopping list is now'</span>, shoplist
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3066116"></a>Output</h4></div></div></div><pre class="screen">
+
+$ python using_list.py
+I have 4 items to purchase.
+These items are: apple mango carrot banana
+I also have to buy rice.
+My shopping list is now ['apple', 'mango', 'carrot', 'banana', 'rice']
+I will sort my list now
+Sorted shopping list is ['apple', 'banana', 'carrot', 'mango', 'rice']
+The first item I will buy is apple
+I bought the apple
+My shopping list is now ['banana', 'carrot', 'mango', 'rice']
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3066150"></a>How It Works</h4></div></div></div><p>
+
+ The variable <code class="varname">shoplist</code> is a shopping list for someone
+ who is going to the market. In <code class="varname">shoplist</code>, we only store
+ strings of the names of the items to buy but remember you can add
+ <span class="emphasis"><em>any kind of object</em></span> to a list including numbers and
+ even other lists.
+
+ </p><p>
+
+ We have also used the <code class="literal">for..in</code> loop to iterate through
+ the items of the list. By now, you must have realised that a list is
+ also a sequence. The speciality of sequences will be discussed in a later
+ <a href="sequences.html" title="Sequences">section</a>
+
+ </p><p>
+
+ Notice that we use a <span class="emphasis"><em>comma</em></span> at the end of the
+ <code class="literal">print</code> statement to suppress the automatic printing of
+ a line break after every <code class="literal">print</code> statement. This is a bit
+ of an ugly way of doing it, but it is simple and gets the job done.
+
+ </p><p>
+
+ Next, we add an item to the list using the <code class="methodname">append</code>
+ method of the list object, as already discussed before. Then, we check that
+ the item has been indeed added to the list by printing the contents of the
+ list by simply passing the list to the <code class="literal">print</code> statement
+ which prints it in a neat manner for us.
+
+ </p><p>
+
+ Then, we sort the list by using the <code class="methodname">sort</code> method
+ of the list. Understand that this method affects the list itself and does
+ not return a modified list - this is different from the way strings
+ work. This is what we mean by saying that lists are <span class="emphasis"><em>mutable</em></span>
+ and that strings are <span class="emphasis"><em>immutable</em></span>.
+
+ </p><p>
+
+ Next, when we finish buying an item in the market, we want to remove it
+ from the list. We achieve this by using the <code class="literal">del</code>
+ statement. Here, we mention which item of the list we want to remove and
+ the <code class="literal">del</code> statement removes it fromt he list for us.
+ We specify that we want to remove the first item from the list and hence
+ we use <code class="literal">del shoplist[0]</code> (remember that Python starts
+ counting from 0).
+
+ </p><p>
+
+ If you want to know all the methods defined by the list object, see
+ <code class="literal">help(list)</code> for complete details.
+
+ </p></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="data-structures.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="data-structures.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="tuple.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 9. Data Structures </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Tuple</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/local-variables.html b/help/byteofpython/read/local-variables.html
new file mode 100644
index 0000000..1d32934
--- /dev/null
+++ b/help/byteofpython/read/local-variables.html
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Local Variables</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="functions.html" title="Chapter 7. Functions" /><link rel="prev" href="function-parameters.html" title="Function Parameters" /><link rel="next" href="default-argument-values.html" title="Default Argument Values" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Local Variables</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="function-parameters.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 7. Functions</th><td width="20%" align="right"> <a accesskey="n" href="default-argument-values.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="local-variables"></a>Local Variables</h2></div></div></div><p>
+
+ When you declare variables inside a function definition, they are not related in any way
+ to other variables with the same names used outside the function i.e. variable names are
+ <span class="emphasis"><em>local</em></span> to the function. This is called the <span class="emphasis"><em>scope</em></span>
+ of the variable. All variables have the scope of the block they are declared in starting
+ from the point of definition of the name.
+
+ </p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="id3061586"></a>Using Local Variables</h3></div></div></div><div class="example"><a id="id3061592"></a><p class="title"><b>Example 7.3. Using Local Variables</b></p><pre class="programlisting">
+
+<span class="py-comment">#!/usr/bin/python</span>
+<span class="py-comment"># Filename: func_local.py</span>
+
+<span class="py-statement">def</span> <span class="py-identifier">func</span>(x):
+ <span class="py-statement">print</span> <span class="py-string">'x is'</span>, x
+ x = <span class="py-number">2</span>
+ <span class="py-statement">print</span> <span class="py-string">'Changed local x to'</span>, x
+
+x = <span class="py-number">50</span>
+func(x)
+<span class="py-statement">print</span> <span class="py-string">'x is still'</span>, x
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3061604"></a>Output</h4></div></div></div><pre class="screen">
+
+$ python func_local.py
+x is 50
+Changed local x to 2
+x is still 50
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3061626"></a>How It Works</h4></div></div></div><p>
+
+ In the function, the first time that we use the <span class="emphasis"><em>value</em></span>
+ of the name <code class="varname">x</code>, Python uses the value of the parameter
+ declared in the function.
+
+ </p><p>
+
+ Next, we assign the value <code class="literal">2</code> to <code class="varname">x</code>.
+ The name <code class="varname">x</code> is local to our function.
+ So, when we change the value of <code class="varname">x</code> in the function, the
+ <code class="varname">x</code> defined in the main block remains unaffected.
+
+ </p><p>
+
+ In the last <code class="literal">print</code> statement, we confirm that the value
+ of <code class="varname">x</code> in the main block is actually unaffected.
+
+ </p></div></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="global"></a>Using the global statement</h3></div></div></div><p>
+
+ If you want to assign a value to a name defined outside the function, then you
+ have to tell Python that the name is not local, but it is <span class="emphasis"><em>global</em></span>.
+ We do this using the <code class="literal">global</code> statement. It is impossible to assign
+ a value to a variable defined outside a function without the <code class="literal">global</code>
+ statement.
+
+ </p><p>
+
+ You can use the values of such variables defined outside the function (assuming there
+ is no variable with the same name within the function). However, this is not
+ encouraged and should be avoided since it becomes unclear to the reader of the program
+ as to where that variable's definition is. Using the <code class="literal">global</code>
+ statement makes it amply clear that the variable is defined in an outer block.
+
+ </p><div class="example"><a id="id3061735"></a><p class="title"><b>Example 7.4. Using the global statement</b></p><pre class="programlisting">
+
+<span class="py-comment">#!/usr/bin/python</span>
+<span class="py-comment"># Filename: func_global.py</span>
+
+<span class="py-statement">def</span> <span class="py-identifier">func</span>():
+ <span class="py-statement">global</span> x
+
+ <span class="py-statement">print</span> <span class="py-string">'x is'</span>, x
+ x = <span class="py-number">2</span>
+ <span class="py-statement">print</span> <span class="py-string">'Changed global x to'</span>, x
+
+x = <span class="py-number">50</span>
+func()
+<span class="py-statement">print</span> <span class="py-string">'Value of x is'</span>, x
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3061747"></a>Output</h4></div></div></div><pre class="screen">
+
+$ python func_global.py
+x is 50
+Changed global x to 2
+Value of x is 2
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3061769"></a>How It Works</h4></div></div></div><p>
+
+ The <code class="literal">global</code> statement is used to decare that
+ <code class="varname">x</code> is a global variable - hence, when we assign a value
+ to <code class="varname">x</code> inside the function, that change is reflected
+ when we use the value of <code class="varname">x</code> in the main block.
+
+ </p><p>
+
+ You can specify more than one global variable using the same
+ <code class="literal">global</code> statement. For example,
+ <code class="literal">global x, y, z</code>.
+
+ </p></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="function-parameters.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="functions.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="default-argument-values.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Function Parameters </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Default Argument Values</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/logical-and-physical-lines.html b/help/byteofpython/read/logical-and-physical-lines.html
new file mode 100644
index 0000000..a974b9f
--- /dev/null
+++ b/help/byteofpython/read/logical-and-physical-lines.html
@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Logical and Physical Lines</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="basics.html" title="Chapter 4. The Basics" /><link rel="prev" href="data-type-object.html" title="Objects" /><link rel="next" href="indentation.html" title="Indentation" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Logical and Physical Lines</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="data-type-object.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 4. The Basics</th><td width="20%" align="right"> <a accesskey="n" href="indentation.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="logical-and-physical-lines"></a>Logical and Physical Lines</h2></div></div></div><p>
+
+ A physical line is what you <span class="emphasis"><em>see</em></span> when you write the program. A
+ logical line is what Python <span class="emphasis"><em>sees</em></span> as a single statement. Python
+ implicitly assumes that each <span class="emphasis"><em>physical line</em></span> corresponds to a
+ <span class="emphasis"><em>logical line</em></span>.
+
+ </p><p>
+
+ An example of a logical line is a statement like <code class="literal">print 'Hello World'</code>
+ - if this was on a line by itself (as you see it in an editor), then this also
+ corresponds to a physical line.
+
+ </p><p>
+
+ Implicitly, Python encourages the use of a single statement per line which makes code
+ more readable.
+
+ </p><p>
+
+ If you want to specify more than one logical line on a single physical line, then you have
+ to explicitly specify this using a semicolon (<code class="literal">;</code>) which indicates the
+ end of a logical line/statement. For example,
+
+ </p><pre class="programlisting">
+
+i = <span class="py-number">5</span>
+<span class="py-statement">print</span> i
+
+ </pre><p>
+
+ is effectively same as
+
+ </p><pre class="programlisting">
+
+i = <span class="py-number">5</span>;
+<span class="py-statement">print</span> i;
+
+ </pre><p>
+
+ and the same can be written as
+
+ </p><pre class="programlisting">
+
+i = <span class="py-number">5</span>; <span class="py-statement">print</span> i;
+
+ </pre><p>
+
+ or even
+
+ </p><pre class="programlisting">
+
+i = <span class="py-number">5</span>; <span class="py-statement">print</span> i
+
+ </pre><p>
+
+ However, I <span class="bold"><strong>strongly recommend</strong></span> that you stick to
+ <span class="bold"><strong>writing a single logical line in a single physical line
+ only</strong></span>. Use more than one physical line for a single logical line only
+ if the logical line is really long. The idea is to avoid the semicolon as far as
+ possible since it leads to more readable code. In fact, I have <span class="emphasis"><em>never</em></span>
+ used or even seen a semicolon in a Python program.
+
+ </p><p>
+
+ An example of writing a logical line spanning many physical lines follows. This is
+ referred to as <span class="bold"><strong>explicit line joining</strong></span>.
+
+ </p><pre class="programlisting">
+
+s = <span class="py-string">'This is a string. \
+This continues the string.'</span>
+<span class="py-statement">print</span> s
+
+ </pre><p>
+
+ This gives the output:
+
+ </p><pre class="screen">
+
+This is a string. This continues the string.
+
+ </pre><p>
+
+ Similarly,
+
+ </p><pre class="programlisting">
+
+<span class="py-statement">print</span> \
+i
+
+ </pre><p>
+
+ is the same as
+
+ </p><pre class="programlisting">
+
+<span class="py-statement">print</span> i
+
+ </pre><p>
+
+ Sometimes, there is an implicit assumption where you don't need to use a backslash. This
+ is the case where the logical line uses parentheses, square brackets or curly braces. This
+ is is called <span class="bold"><strong>implicit line joining</strong></span>. You can see this in
+ action when we write programs using <a href="list.html" title="List">lists</a> in later chapters.
+
+ </p></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="data-type-object.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="basics.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="indentation.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Objects </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Indentation</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/making-modules.html b/help/byteofpython/read/making-modules.html
new file mode 100644
index 0000000..124fc35
--- /dev/null
+++ b/help/byteofpython/read/making-modules.html
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Making your own Modules</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="modules.html" title="Chapter 8. Modules" /><link rel="prev" href="module-name.html" title="A module's __name__" /><link rel="next" href="dir.html" title="The dir() function" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Making your own Modules</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="module-name.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 8. Modules</th><td width="20%" align="right"> <a accesskey="n" href="dir.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="making-modules"></a>Making your own Modules</h2></div></div></div><p>
+
+ Creating your own modules is easy, you've been doing it all along! Every Python program
+ is also a module. You just have to make sure it has a <code class="filename">.py</code> extension.
+ The following example should make it clear.
+
+ </p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="creating-modules"></a>Creating your own Modules</h3></div></div></div><div class="example"><a id="id3064587"></a><p class="title"><b>Example 8.3. How to create your own module</b></p><pre class="programlisting">
+
+<span class="py-comment">#!/usr/bin/python</span>
+<span class="py-comment"># Filename: mymodule.py</span>
+
+<span class="py-statement">def</span> <span class="py-identifier">sayhi</span>():
+ <span class="py-statement">print</span> <span class="py-string">'Hi, this is mymodule speaking.'</span>
+
+version = <span class="py-string">'0.1'</span>
+
+<span class="py-comment"># End of mymodule.py</span>
+
+ </pre></div><p>
+
+ The above was a sample <span class="emphasis"><em>module</em></span>. As you can see, there is nothing
+ particularly special about compared to our usual Python program. We will next see
+ how to use this module in our other Python programs.
+
+ </p><p>
+
+ Remember that the module should be placed in the same directory as the program that
+ we import it in, or the module should be in one of the directories listed in
+ <code class="varname">sys.path</code> .
+
+ </p><pre class="programlisting">
+
+<span class="py-comment">#!/usr/bin/python</span>
+<span class="py-comment"># Filename: mymodule_demo.py</span>
+
+<span class="py-statement">import</span> mymodule
+
+mymodule.sayhi()
+<span class="py-statement">print</span> <span class="py-string">'Version'</span>, mymodule.version
+
+ </pre><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3064630"></a>Output</h4></div></div></div><pre class="screen">
+
+$ python mymodule_demo.py
+Hi, this is mymodule speaking.
+Version 0.1
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3064650"></a>How It Works</h4></div></div></div><p>
+
+ Notice that we use the same dotted notation to access members of the
+ module. Python makes good reuse of the same notation to give the
+ distinctive 'Pythonic' feel to it so that we don't have to keep
+ learning new ways to do things.
+
+ </p></div></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="using-from-import"></a>from..import</h3></div></div></div><p>
+
+ Here is a version utilising the <code class="literal">from..import</code> syntax.
+
+ </p><pre class="programlisting">
+
+<span class="py-comment">#!/usr/bin/python</span>
+<span class="py-comment"># Filename: mymodule_demo2.py</span>
+
+<span class="py-statement">from</span> mymodule <span class="py-statement">import</span> sayhi, version
+<span class="py-comment"># Alternative:</span>
+<span class="py-comment"># from mymodule import *</span>
+
+sayhi()
+<span class="py-statement">print</span> <span class="py-string">'Version'</span>, version
+
+ </pre><p>
+
+ The output of <code class="filename">mymodule_demo2.py</code> is same as the output of
+ <code class="filename">mymodule_demo.py</code>.
+
+ </p></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="module-name.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="modules.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="dir.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">A module's __name__ </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> The dir() function</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/module-name.html b/help/byteofpython/read/module-name.html
new file mode 100644
index 0000000..d6504f5
--- /dev/null
+++ b/help/byteofpython/read/module-name.html
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>A module's __name__</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="modules.html" title="Chapter 8. Modules" /><link rel="prev" href="from-import.html" title="The from..import statement" /><link rel="next" href="making-modules.html" title="Making your own Modules" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">A module's __name__</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="from-import.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 8. Modules</th><td width="20%" align="right"> <a accesskey="n" href="making-modules.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="module-name"></a>A module's __name__</h2></div></div></div><p>
+
+ Every module has a name and statements in a module can find out the name of its module.
+ This is especially handy in one particular situation - As mentioned previously, when a
+ module is imported for the first time, the main block in that module is run. What if we
+ want to run the block only if the program was used by itself and not when it was
+ imported from another module? This can be achieved using the <code class="varname">__name__</code>
+ attribute of the module.
+
+ </p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="using-name"></a>Using a module's __name__</h3></div></div></div><div class="example"><a id="id3064494"></a><p class="title"><b>Example 8.2. Using a module's __name__</b></p><pre class="programlisting">
+
+<span class="py-comment">#!/usr/bin/python</span>
+<span class="py-comment"># Filename: using_name.py</span>
+
+<span class="py-statement">if</span> __name__ == <span class="py-string">'__main__'</span>:
+ <span class="py-statement">print</span> <span class="py-string">'This program is being run by itself'</span>
+<span class="py-statement">else</span>:
+ <span class="py-statement">print</span> <span class="py-string">'I am being imported from another module'</span>
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3064506"></a>Output</h4></div></div></div><pre class="screen">
+
+$ python using_name.py
+This program is being run by itself
+
+$ python
+&gt;&gt;&gt; import using_name
+I am being imported from another module
+&gt;&gt;&gt;
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3064525"></a>How It Works</h4></div></div></div><p>
+
+ Every Python module has it's <code class="varname">__name__</code> defined and if this
+ is <code class="literal">'__main__'</code>, it implies that the module is being run
+ standalone by the user and we can do corresponding appropriate actions.
+
+ </p></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="from-import.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="modules.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="making-modules.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">The from..import statement </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Making your own Modules</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/modules-summary.html b/help/byteofpython/read/modules-summary.html
new file mode 100644
index 0000000..75a99ae
--- /dev/null
+++ b/help/byteofpython/read/modules-summary.html
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Summary</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="modules.html" title="Chapter 8. Modules" /><link rel="prev" href="dir.html" title="The dir() function" /><link rel="next" href="data-structures.html" title="Chapter 9. Data Structures" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Summary</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="dir.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 8. Modules</th><td width="20%" align="right"> <a accesskey="n" href="data-structures.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="modules-summary"></a>Summary</h2></div></div></div><p>
+
+ Modules are useful because they provide services and functionality that you can reuse in
+ other programs. The standard library that comes with Python is an example of such a set
+ of modules. We have seen how to use these modules and create our own modules as well.
+
+ </p><p>
+
+ Next, we will learn about some interesting concepts called data structures.
+
+ </p></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="dir.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="modules.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="data-structures.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">The dir() function </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Chapter 9. Data Structures</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/modules.html b/help/byteofpython/read/modules.html
new file mode 100644
index 0000000..d15ef4a
--- /dev/null
+++ b/help/byteofpython/read/modules.html
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Chapter 8. Modules</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="index.html" title="A Byte of Python" /><link rel="prev" href="functions-summary.html" title="Summary" /><link rel="next" href="byte-compiled.html" title="Byte-compiled .pyc files" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 8. Modules</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="functions-summary.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="byte-compiled.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="chapter" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title"><a id="modules"></a>Chapter 8. Modules</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="modules.html#modules-intro">Introduction</a></span></dt><dd><dl><dt><span class="section"><a href="modules.html#using-sys-module">Using the sys module</a></span></dt></dl></dd><dt><span class="section"><a href="byte-compiled.html">Byte-compiled .pyc files</a></span></dt><dt><span class="section"><a href="from-import.html">The from..import statement</a></span></dt><dt><span class="section"><a href="module-name.html">A module's __name__</a></span></dt><dd><dl><dt><span class="section"><a href="module-name.html#using-name">Using a module's __name__</a></span></dt></dl></dd><dt><span class="section"><a href="making-modules.html">Making your own Modules</a></span></dt><dd><dl><dt><span class="section"><a href="making-modules.html#creating-modules">Creating your own Modules</a></span></dt><dt><span class="section"><a href="making-modules.html#using-from-import">from..import</a></span></dt></dl></dd><dt><span class="section"><a href="dir.html">The dir() function</a></span></dt><dd><dl><dt><span class="section"><a href="dir.html#using-dir">Using the dir function</a></span></dt></dl></dd><dt><span class="section"><a href="modules-summary.html">Summary</a></span></dt></dl></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="modules-intro"></a>Introduction</h2></div></div></div><p>
+
+ You have seen how you can reuse code in your program by defining functions once. What
+ if you wanted to reuse a number of functions in other programs that you write? As you
+ might have guessed, the answer is modules. A module is basically a file containing all
+ your functions and variables that you have defined. To reuse the module in other programs,
+ the filename of the module <span class="bold"><strong>must</strong></span> have a
+ <code class="filename">.py</code> extension.
+
+ </p><p>
+
+ A module can be <span class="emphasis"><em>imported</em></span> by another program to make use of its
+ functionality. This is how we can use the Python standard library as well. First,
+ we will see how to use the standard library modules.
+
+ </p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="using-sys-module"></a>Using the sys module</h3></div></div></div><div class="example"><a id="id3064063"></a><p class="title"><b>Example 8.1. Using the sys module</b></p><pre class="programlisting">
+
+<span class="py-comment">#!/usr/bin/python</span>
+<span class="py-comment"># Filename: using_sys.py</span>
+
+<span class="py-statement">import</span> <span class="py-builtin">sys</span>
+
+<span class="py-statement">print</span> <span class="py-string">'The command line arguments are:'</span>
+<span class="py-statement">for</span> i <span class="py-statement">in</span> <span class="py-builtin">sys</span>.argv:
+ <span class="py-statement">print</span> i
+
+<span class="py-statement">print</span> <span class="py-string">'\n\nThe PYTHONPATH is'</span>, <span class="py-builtin">sys</span>.path, <span class="py-string">'\n'</span>
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3064075"></a>Output</h4></div></div></div><pre class="screen">
+
+$ python using_sys.py we are arguments
+The command line arguments are:
+using_sys.py
+we
+are
+arguments
+
+
+The PYTHONPATH is ['/home/swaroop/byte/code', '/usr/lib/python23.zip',
+'/usr/lib/python2.3', '/usr/lib/python2.3/plat-linux2',
+'/usr/lib/python2.3/lib-tk', '/usr/lib/python2.3/lib-dynload',
+'/usr/lib/python2.3/site-packages', '/usr/lib/python2.3/site-packages/gtk-2.0']
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3064094"></a>How It Works</h4></div></div></div><p>
+
+ First, we <span class="emphasis"><em>import</em></span> the <code class="literal">sys</code> module
+ using the <code class="literal">import</code> statement. Basically, this translates
+ to us telling Python that we want to use this module. The
+ <code class="literal">sys</code> module contains functionality related to the Python
+ interpreter and its environment.
+
+ </p><p>
+
+ When Python executes the <code class="literal">import sys</code> statement, it looks for
+ the <code class="filename">sys.py</code> module in one of the directores listed in its
+ <code class="varname">sys.path</code> variable. If the file is found, then the
+ statements in the main block of that module is run and then the module is
+ made <span class="emphasis"><em>available</em></span> for you to use. Note that the
+ initialization is done only the <span class="emphasis"><em>first</em></span> time that we
+ import a module. Also, 'sys' is short for 'system'.
+
+ </p><p>
+
+ The <code class="varname">argv</code> variable in the <code class="literal">sys</code> module is
+ referred to using the dotted notation - <code class="varname">sys.argv</code> - one of
+ the advantages of this approach is that the name does not clash with any
+ <code class="varname">argv</code> variable used in your program. Also, it indicates
+ clearly that this name is part of the <code class="literal">sys</code> module.
+
+ </p><p>
+
+ The <code class="varname">sys.argv</code> variable is a <span class="emphasis"><em>list</em></span> of
+ strings (lists are explained in detail in later
+ <a href="list.html" title="List">sections</a>). Specifically, the
+ <code class="varname">sys.argv</code> contains the list of
+ <span class="emphasis"><em>command line arguments</em></span> i.e. the arguments passed to your
+ program using the command line.
+
+ </p><p>
+
+ If you are using an IDE to write and run these programs, look for a way to
+ specify command line arguments to the program in the menus.
+
+ </p><p>
+
+ Here, when we execute <code class="literal">python using_sys.py we are arguments</code>,
+ we run the module <code class="filename">using_sys.py</code> with the
+ <span><strong class="command">python</strong></span> command and the other things that follow are
+ arguments passed to the program. Python stores it in the
+ <code class="varname">sys.argv</code> variable for us.
+
+ </p><p>
+
+ Remember, the name of the script running is always the first argument in the
+ <code class="varname">sys.argv</code> list. So, in this case we will have
+ <code class="literal">'using_sys.py'</code> as <code class="varname">sys.argv[0]</code>,
+ <code class="literal">'we'</code> as <code class="varname">sys.argv[1]</code>,
+ <code class="literal">'are'</code> as <code class="varname">sys.argv[2]</code> and
+ <code class="literal">'arguments'</code> as <code class="varname">sys.argv[3]</code> . Notice that
+ Python starts counting from 0 and not 1.
+
+ </p><p>
+
+ The <code class="varname">sys.path</code> contains the list of directory names where
+ modules are imported from. Observe that the first string in
+ <code class="varname">sys.path</code> is empty - this empty string indicates that the
+ current directory is also part of the <code class="varname">sys.path</code> which is
+ same as the <code class="envar">PYTHONPATH</code> environment variable. This means
+ that you can directly import modules located in the current directory.
+ Otherwise, you will have to place your module in one of the directories
+ listed in <code class="varname">sys.path</code> .
+
+ </p></div></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="functions-summary.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="byte-compiled.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Summary </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Byte-compiled .pyc files</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/more-about-strings.html b/help/byteofpython/read/more-about-strings.html
new file mode 100644
index 0000000..d4e99cf
--- /dev/null
+++ b/help/byteofpython/read/more-about-strings.html
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>More about Strings</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="data-structures.html" title="Chapter 9. Data Structures" /><link rel="prev" href="references.html" title="References" /><link rel="next" href="data-structures-summary.html" title="Summary" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">More about Strings</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="references.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 9. Data Structures</th><td width="20%" align="right"> <a accesskey="n" href="data-structures-summary.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="more-about-strings"></a>More about Strings</h2></div></div></div><p>
+
+ We have already discussed strings in detail earlier. What more can there be to know?
+ Well, did you know that strings are also objects and have methods which do everything
+ from checking part of a string to stripping spaces!
+
+ </p><p>
+
+ The strings that you use in program are all objects of the class <code class="classname">str</code>.
+ Some useful methods of this class are demonstrated in the next example. For a complete list
+ of such methods, see <code class="literal">help(str)</code>.
+
+ </p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="string-methods"></a>String Methods</h3></div></div></div><div class="example"><a id="id3067506"></a><p class="title"><b>Example 9.7. String Methods</b></p><pre class="programlisting">
+
+<span class="py-comment">#!/usr/bin/python</span>
+<span class="py-comment"># Filename: str_methods.py</span>
+
+name = <span class="py-string">'Swaroop'</span> <span class="py-comment"># This is a string object</span>
+
+<span class="py-statement">if</span> name.startswith(<span class="py-string">'Swa'</span>):
+ <span class="py-statement">print</span> <span class="py-string">'Yes, the string starts with "Swa"'</span>
+
+<span class="py-statement">if</span> <span class="py-string">'a'</span> <span class="py-statement">in</span> name:
+ <span class="py-statement">print</span> <span class="py-string">'Yes, it contains the string "a"'</span>
+
+<span class="py-statement">if</span> name.find(<span class="py-string">'war'</span>) != -<span class="py-number">1</span>:
+ <span class="py-statement">print</span> <span class="py-string">'Yes, it contains the string "war"'</span>
+
+delimiter = <span class="py-string">'_*_'</span>
+mylist = [<span class="py-string">'Brazil'</span>, <span class="py-string">'Russia'</span>, <span class="py-string">'India'</span>, <span class="py-string">'China'</span>]
+<span class="py-statement">print</span> delimiter.join(mylist)
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3067519"></a>Output</h4></div></div></div><pre class="screen">
+
+$ python str_methods.py
+Yes, the string starts with "Swa"
+Yes, it contains the string "a"
+Yes, it contains the string "war"
+Brazil_*_Russia_*_India_*_China
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3067545"></a>How It Works</h4></div></div></div><p>
+
+ Here, we see a lot of the string methods in action. The
+ <code class="methodname">startswith</code> method is used to find out whether the
+ string starts with the given string. The <code class="literal">in</code> operator is
+ used to check if a given string is a part of the string.
+
+ </p><p>
+
+ The <code class="methodname">find</code> method is used to do find the position of
+ the given string in the string or returns -1 if it is not successful to find
+ the substring. The <code class="classname">str</code> class also has a neat method
+ to <code class="methodname">join</code> the items of a sequence with the string
+ acting as a delimiter between each item of the sequence and returns a bigger
+ string generated from this.
+
+ </p></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="references.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="data-structures.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="data-structures-summary.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">References </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Summary</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/more-python-summary.html b/help/byteofpython/read/more-python-summary.html
new file mode 100644
index 0000000..54b63c7
--- /dev/null
+++ b/help/byteofpython/read/more-python-summary.html
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Summary</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="more-python.html" title="Chapter 15. More Python" /><link rel="prev" href="repr-function.html" title="The repr function" /><link rel="next" href="what-next.html" title="Chapter 16. What Next?" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Summary</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="repr-function.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 15. More Python</th><td width="20%" align="right"> <a accesskey="n" href="what-next.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="more-python-summary"></a>Summary</h2></div></div></div><p>
+
+ We have covered some more features of Python in this chapter and yet you can be sure we
+ haven't covered all the features of Python. However, at this stage, we have covered most
+ of what you are ever going to use in practice. This is sufficient for you to get
+ started with whatever programs you are going to create.
+
+ </p><p>
+
+ Next, we will discuss how to explore Python further.
+
+ </p></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="repr-function.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="more-python.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="what-next.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">The repr function </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Chapter 16. What Next?</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/more-python.html b/help/byteofpython/read/more-python.html
new file mode 100644
index 0000000..b6bbd90
--- /dev/null
+++ b/help/byteofpython/read/more-python.html
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Chapter 15. More Python</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="index.html" title="A Byte of Python" /><link rel="prev" href="stdlib-summary.html" title="Summary" /><link rel="next" href="single-statement-blocks.html" title="Single Statement Blocks" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 15. More Python</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="stdlib-summary.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="single-statement-blocks.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="chapter" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title"><a id="more-python"></a>Chapter 15. More Python</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="more-python.html#special-methods">Special Methods</a></span></dt><dt><span class="section"><a href="single-statement-blocks.html">Single Statement Blocks</a></span></dt><dt><span class="section"><a href="list-comprehension.html">List Comprehension</a></span></dt><dd><dl><dt><span class="section"><a href="list-comprehension.html#using-list-comprehension">Using List Comprehensions</a></span></dt></dl></dd><dt><span class="section"><a href="tuples-lists-functions.html">Receiving Tuples and Lists in Functions</a></span></dt><dt><span class="section"><a href="lambda-forms.html">Lambda Forms</a></span></dt><dd><dl><dt><span class="section"><a href="lambda-forms.html#using-lambda-forms">Using Lambda Forms</a></span></dt></dl></dd><dt><span class="section"><a href="exec-statement.html">The exec and eval statements</a></span></dt><dt><span class="section"><a href="assert-statement.html">The assert statement</a></span></dt><dt><span class="section"><a href="repr-function.html">The repr function</a></span></dt><dt><span class="section"><a href="more-python-summary.html">Summary</a></span></dt></dl></div><p>
+
+ Till now, we have covered majority of the various aspects of Python that you will use.
+ In this chapter, we will cover some more aspects that will make our knowledge of Python
+ more <span class="emphasis"><em>complete</em></span>.
+
+ </p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="special-methods"></a>Special Methods</h2></div></div></div><p>
+
+ There are certain special methods which have special significance in classes such as
+ the <code class="methodname">__init__</code> and <code class="methodname">__del__</code> methods
+ whose significance we have already seen.
+
+ </p><p>
+
+ Generally, special methods are used to mimic certain behavior. For example, if you want
+ to use the <code class="literal">x[key]</code> indexing operation for your class (just like you use
+ for lists and tuples) then just implement the <code class="methodname">__getitem__()</code>
+ method and your job is done. If you think about it, this is what Python does for the
+ <code class="classname">list</code> class itself!
+
+ </p><p>
+
+ Some useful special methods are listed in the following table. If you want to know about
+ all the special methods, then a huge list is available in the Python Reference Manual.
+
+ </p><div class="table"><a id="id3078372"></a><p class="title"><b>Table 15.1. Some Special Methods</b></p><table summary="Some Special Methods" border="1"><colgroup><col /><col /></colgroup><thead><tr><th>Name</th><th>Explanation</th></tr></thead><tbody><tr><td>__init__(self, ...)</td><td>
+
+ This method is called just before the newly created object
+ is returned for usage.
+
+ </td></tr><tr><td>__del__(self)</td><td>
+
+ Called just before the object is destroyed
+
+ </td></tr><tr><td>__str__(self)</td><td>
+
+ Called when we use the <code class="literal">print</code> statement
+ with the object or when <code class="classname">str()</code> is
+ used.
+
+ </td></tr><tr><td>__lt__(self, other)</td><td>
+
+ Called when the <span class="emphasis"><em>less than</em></span> operator
+ ( &lt; ) is used. Similarly, there are special
+ methods for all the operators (+, &gt;, etc.)
+
+ </td></tr><tr><td>__getitem__(self, key)</td><td>
+
+ Called when <code class="literal">x[key]</code> indexing operation
+ is used.
+
+ </td></tr><tr><td>__len__(self)</td><td>
+
+ Called when the built-in <code class="function">len()</code> function
+ is used for the sequence object.
+
+ </td></tr></tbody></table></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="stdlib-summary.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="single-statement-blocks.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Summary </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Single Statement Blocks</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/numbers.html b/help/byteofpython/read/numbers.html
new file mode 100644
index 0000000..329d015
--- /dev/null
+++ b/help/byteofpython/read/numbers.html
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Numbers</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="basics.html" title="Chapter 4. The Basics" /><link rel="prev" href="basics.html" title="Chapter 4. The Basics" /><link rel="next" href="strings.html" title="Strings" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Numbers</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="basics.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 4. The Basics</th><td width="20%" align="right"> <a accesskey="n" href="strings.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="numbers"></a>Numbers</h2></div></div></div><p>
+
+ Numbers in Python are of four types - integers, long integers, floating point and complex
+ numbers.
+
+ </p><div class="itemizedlist"><ul type="disc"><li><p>
+
+ Examples of integers are <code class="literal">2</code> which are just whole numbers.
+
+ </p></li><li><p>
+
+ Long integers are just bigger whole numbers.
+
+ </p></li><li><p>
+
+ Examples of floating point numbers (or <span class="emphasis"><em>floats</em></span>
+ for short) are <code class="literal">3.23</code> and <code class="literal">52.3E-4</code>.
+ The <code class="literal">E</code> notation indicates powers of 10. In this case,
+ <code class="literal">52.3E-4</code> means
+ <code class="literal">52.3 * 10<sup>-4</sup></code>.
+
+ </p></li><li><p>
+
+ Examples of complex numbers are <code class="literal">(-5+4j)</code> and
+ <code class="literal">(2.3 - 4.6j)</code>
+
+ </p></li></ul></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="basics.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="basics.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="strings.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 4. The Basics </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Strings</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/object-methods.html b/help/byteofpython/read/object-methods.html
new file mode 100644
index 0000000..58c3269
--- /dev/null
+++ b/help/byteofpython/read/object-methods.html
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>object Methods</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="oops.html" title="Chapter 11. Object-Oriented Programming" /><link rel="prev" href="classes.html" title="Classes" /><link rel="next" href="class-init.html" title="The __init__ method" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">object Methods</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="classes.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 11. Object-Oriented Programming</th><td width="20%" align="right"> <a accesskey="n" href="class-init.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="object-methods"></a>object Methods</h2></div></div></div><p>
+
+ We have already discussed that classes/objects can have methods just like functions except
+ that we have an extra <code class="literal">self</code> variable. We will now see an example.
+
+ </p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="using-object-methods"></a>Using Object Methds</h3></div></div></div><div class="example"><a id="id3072450"></a><p class="title"><b>Example 11.2. Using Object Methods</b></p><pre class="programlisting">
+
+<span class="py-comment">#!/usr/bin/python</span>
+<span class="py-comment"># Filename: method.py</span>
+
+<span class="py-statement">class</span> <span class="py-identifier">Person</span>:
+ <span class="py-statement">def</span> <span class="py-identifier">sayHi</span>(<span class="py-builtin">self</span>):
+ <span class="py-statement">print</span> <span class="py-string">'Hello, how are you?'</span>
+
+p = Person()
+p.sayHi()
+
+<span class="py-comment"># This short example can also be written as Person().sayHi()</span>
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3072462"></a>Output</h4></div></div></div><pre class="screen">
+
+$ python method.py
+Hello, how are you?
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3072483"></a>How It Works</h4></div></div></div><p>
+
+ Here we see the <code class="literal">self</code> in action. Notice that the
+ <code class="function">sayHi</code> method takes no parameters but still has the
+ <code class="literal">self</code> in the function definition.
+
+ </p></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="classes.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="oops.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="class-init.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Classes </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> The __init__ method</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/official-website.html b/help/byteofpython/read/official-website.html
new file mode 100644
index 0000000..a49a286
--- /dev/null
+++ b/help/byteofpython/read/official-website.html
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Official Website</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="preface.html" title="Preface" /><link rel="prev" href="status.html" title="Status of the book" /><link rel="next" href="license.html" title="License Terms" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Official Website</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="status.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Preface</th><td width="20%" align="right"> <a accesskey="n" href="license.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="official-website"></a>Official Website</h2></div></div></div><p>
+ The official website of the book is <a href="http://www.byteofpython.info" target="_top">www.byteofpython.info</a> . From the website, you can read the whole book
+ online or you can download the latest versions of the book, and also send me
+ feedback.
+ </p></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="status.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="preface.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="license.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Status of the book </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> License Terms</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/oops-summary.html b/help/byteofpython/read/oops-summary.html
new file mode 100644
index 0000000..701229e
--- /dev/null
+++ b/help/byteofpython/read/oops-summary.html
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Summary</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="oops.html" title="Chapter 11. Object-Oriented Programming" /><link rel="prev" href="inheritance.html" title="Inheritance" /><link rel="next" href="io.html" title="Chapter 12. Input/Output" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Summary</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="inheritance.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 11. Object-Oriented Programming</th><td width="20%" align="right"> <a accesskey="n" href="io.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="oops-summary"></a>Summary</h2></div></div></div><p>
+
+ We have now explored the various aspects of classes and objects as well as the various
+ terminologies associated with it. We have also seen the benefits and pitfalls of
+ object-oriented programming. Python is highly object-oriented and understanding these
+ concepts carefully will help you a lot in the long run.
+
+ </p><p>
+
+ Next, we will learn how to deal with input/output and how to access files in Python.
+
+ </p></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="inheritance.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="oops.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="io.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Inheritance </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Chapter 12. Input/Output</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/oops.html b/help/byteofpython/read/oops.html
new file mode 100644
index 0000000..55d4f14
--- /dev/null
+++ b/help/byteofpython/read/oops.html
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Chapter 11. Object-Oriented Programming</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="index.html" title="A Byte of Python" /><link rel="prev" href="problem-solving-summary.html" title="Summary" /><link rel="next" href="self.html" title="The self" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 11. Object-Oriented Programming</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="problem-solving-summary.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="self.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="chapter" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title"><a id="oops"></a>Chapter 11. Object-Oriented Programming</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="oops.html#oops-intro">Introduction</a></span></dt><dt><span class="section"><a href="self.html">The self</a></span></dt><dt><span class="section"><a href="classes.html">Classes</a></span></dt><dd><dl><dt><span class="section"><a href="classes.html#creating-class">Creating a Class</a></span></dt></dl></dd><dt><span class="section"><a href="object-methods.html">object Methods</a></span></dt><dd><dl><dt><span class="section"><a href="object-methods.html#using-object-methods">Using Object Methds</a></span></dt></dl></dd><dt><span class="section"><a href="class-init.html">The __init__ method</a></span></dt><dd><dl><dt><span class="section"><a href="class-init.html#using-class-init">Using the __init__ method</a></span></dt></dl></dd><dt><span class="section"><a href="class-and-object-vars.html">Class and Object Variables</a></span></dt><dd><dl><dt><span class="section"><a href="class-and-object-vars.html#using-class-and-obj-vars">Using Class and Object Variables</a></span></dt></dl></dd><dt><span class="section"><a href="inheritance.html">Inheritance</a></span></dt><dd><dl><dt><span class="section"><a href="inheritance.html#using-inheritance">Using Inheritance</a></span></dt></dl></dd><dt><span class="section"><a href="oops-summary.html">Summary</a></span></dt></dl></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="oops-intro"></a>Introduction</h2></div></div></div><p>
+
+ In all our programs till now, we have designed our program around functions or blocks
+ of statements which manipulate data. This is called the <span class="emphasis"><em>procedure-oriented</em></span>
+ way of programming. There is another way of organizing your program which is to combine
+ data and functionality and wrap it inside what is called an object. This is called the
+ <span class="emphasis"><em>object oriented</em></span> programming paradigm. Most of the time you can use
+ procedural programming but sometimes when you want to write large programs or have a solution
+ that is better suited to it, you can use object oriented programming techniques.
+
+ </p><p>
+
+ Classes and objects are the two main aspecs of object oriented programming.
+ A <span class="bold"><strong>class</strong></span> creates a new <span class="emphasis"><em>type</em></span> where
+ <span class="bold"><strong>objects</strong></span> are <span class="emphasis"><em>instances</em></span> of the class.
+ An analogy is that you can have variables of type <code class="classname">int</code> which
+ translates to saying that variables that store integers are variables which are instances
+ (objects) of the <code class="classname">int</code> class.
+
+ </p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note for C/C++/Java/C# Programmers</h3><p>
+
+ Note that even integers are treated as objects (of the <code class="classname">int</code> class).
+ This is unlike C++ and Java (before version 1.5) where integers are primitive native
+ types. See <code class="literal">help(int)</code> for more details on the class.
+
+ </p><p>
+
+ C# and Java 1.5 programmers will be familiar with this concept since it is similar
+ to the <span class="emphasis"><em>boxing and unboxing</em></span> concept.
+
+ </p></div><p>
+
+ Objects can store data using ordinary variables that <span class="emphasis"><em>belong</em></span> to the
+ object. Variables that belong to an object or class are called as
+ <span class="bold"><strong>fields</strong></span>. Objects can also have functionality by using
+ functions that <span class="emphasis"><em>belong</em></span> to a class. Such functions are called
+ <span class="bold"><strong>methods</strong></span> of the class. This terminology is important
+ because it helps us to differentiate between functions and variables which are separate
+ by itself and those which belong to a class or object. Collectively, the fields and
+ methods can be referred to as the <span class="bold"><strong>attributes</strong></span> of that class.
+
+ </p><p>
+
+ Fields are of two types - they can belong to each instance/object of the class or they can
+ belong to the class itself. They are called <span class="bold"><strong>instance variables</strong></span>
+ and <span class="bold"><strong>class variables</strong></span> respectively.
+
+ </p><p>
+
+ A class is created using the <code class="literal">class</code> keyword. The fields and methods of the
+ class are listed in an indented block.
+
+ </p></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="problem-solving-summary.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="self.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Summary </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> The self</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/operator-precedence.html b/help/byteofpython/read/operator-precedence.html
new file mode 100644
index 0000000..11786a1
--- /dev/null
+++ b/help/byteofpython/read/operator-precedence.html
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Operator Precedence</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="operators-expressions.html" title="Chapter 5. Operators and Expressions" /><link rel="prev" href="operators.html" title="Operators" /><link rel="next" href="expressions.html" title="Expressions" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Operator Precedence</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="operators.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 5. Operators and Expressions</th><td width="20%" align="right"> <a accesskey="n" href="expressions.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="operator-precedence"></a>Operator Precedence</h2></div></div></div><p>
+
+ If you had an expression such as <code class="literal">2 + 3 * 4</code>, is the addition done first
+ or the multiplication? Our high school maths tells us that the multiplication should be
+ done first - this means that the multiplication operator has higher precedence than the
+ addition operator.
+
+ </p><p>
+
+ The following table gives the operator precedence table for Python, from the lowest
+ precedence (least binding) to the highest precedence (most binding). This means that
+ in a given expression, Python will first evaluate the operators lower in the table
+ before the operators listed higher in the table.
+
+ </p><p>
+
+ The following table (same as the one in the Python reference manual) is provided for the
+ sake of completeness. However, I advise you to use parentheses for grouping of operators
+ and operands in order to explicitly specify the precedence and to make the program as
+ readable as possible. For example, <code class="literal">2 + (3 * 4)</code> is definitely more clearer
+ than <code class="literal">2 + 3 * 4</code>. As with everything else, the parentheses shold be used
+ sensibly and should not be redundant (as in <code class="literal">2 + (3 + 4)</code>).
+
+ </p><div class="table"><a id="id3056064"></a><p class="title"><b>Table 5.2. Operator Precedence</b></p><table summary="Operator Precedence" border="1"><colgroup><col /><col /></colgroup><thead><tr><th>Operator</th><th>Description</th></tr></thead><tbody><tr><td>lambda</td><td>Lambda Expression</td></tr><tr><td>or</td><td>Boolean OR</td></tr><tr><td>and</td><td>Boolean AND</td></tr><tr><td>not x</td><td>Boolean NOT</td></tr><tr><td>in, not in</td><td>Membership tests</td></tr><tr><td>is, is not</td><td>Identity tests</td></tr><tr><td>&lt;, &lt;=, &gt;, &gt;=, !=, ==</td><td>Comparisons</td></tr><tr><td>|</td><td>Bitwise OR</td></tr><tr><td>^</td><td>Bitwise XOR</td></tr><tr><td>&amp;</td><td>Bitwise AND</td></tr><tr><td>&lt;&lt;, &gt;&gt;</td><td>Shifts</td></tr><tr><td>+, -</td><td>Addition and subtraction</td></tr><tr><td>*, /, %</td><td>Multiplication, Division and Remainder</td></tr><tr><td>+x, -x</td><td>Positive, Negative</td></tr><tr><td>~x</td><td>Bitwise NOT</td></tr><tr><td>**</td><td>Exponentiation</td></tr><tr><td>x.attribute</td><td>Attribute reference</td></tr><tr><td>x[index]</td><td>Subscription</td></tr><tr><td>x[index:index]</td><td>Slicing</td></tr><tr><td>f(arguments ...)</td><td>Function call</td></tr><tr><td>(expressions, ...)</td><td>Binding or tuple display</td></tr><tr><td>[expressions, ...]</td><td>List display</td></tr><tr><td>{key:datum, ...}</td><td>Dictionary display</td></tr><tr><td>`expressions, ...`</td><td>String conversion</td></tr></tbody></table></div><p>
+
+ The operators which we have not already come across will be explained in later chapters.
+
+ </p><p>
+
+ Operators with the same <span class="emphasis"><em>same precedence</em></span> are listed in the same row
+ in the above table. For example, <code class="literal">+</code> and <code class="literal">-</code> have the
+ same precedence.
+
+ </p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="order-of-evaluation"></a>Order of Evaluation</h3></div></div></div><p>
+
+ By default, the operator precedence table decides which operators are evaluated
+ before others. However, if you want to change the orer in which they are
+ evaluated, you can use parentheses. For example, if you want addition to be
+ evaluated before multiplication in an expression, then you can write something
+ like <code class="literal">(2 + 3) * 4</code>.
+
+ </p></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="associativity"></a>Associativity</h3></div></div></div><p>
+
+ Operators are usually associated from left to right i.e. operators with same
+ precedence are evaluated in a left to right manner. For example,
+ <code class="literal">2 + 3 + 4</code> is evaluated as
+ <code class="literal">(2 + 3) + 4</code>. Some operators like assignment operators have
+ right to left associativity i.e. <code class="literal">a = b = c</code> is treated as
+ <code class="literal">a = (b = c)</code>.
+
+ </p></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="operators.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="operators-expressions.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="expressions.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Operators </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Expressions</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/operators-expressions-summary.html b/help/byteofpython/read/operators-expressions-summary.html
new file mode 100644
index 0000000..044acb2
--- /dev/null
+++ b/help/byteofpython/read/operators-expressions-summary.html
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Summary</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="operators-expressions.html" title="Chapter 5. Operators and Expressions" /><link rel="prev" href="expressions.html" title="Expressions" /><link rel="next" href="control-flow.html" title="Chapter 6. Control Flow" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Summary</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="expressions.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 5. Operators and Expressions</th><td width="20%" align="right"> <a accesskey="n" href="control-flow.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="operators-expressions-summary"></a>Summary</h2></div></div></div><p>
+
+ We have seen how to use operators, operands and expressions - these are the basic
+ building blocks of any program. Next, we will see how to make use of these in our
+ programs using statements.
+
+ </p></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="expressions.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="operators-expressions.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="control-flow.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Expressions </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Chapter 6. Control Flow</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/operators-expressions.html b/help/byteofpython/read/operators-expressions.html
new file mode 100644
index 0000000..7b54606
--- /dev/null
+++ b/help/byteofpython/read/operators-expressions.html
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Chapter 5. Operators and Expressions</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="index.html" title="A Byte of Python" /><link rel="prev" href="basics-summary.html" title="Summary" /><link rel="next" href="operators.html" title="Operators" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 5. Operators and Expressions</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="basics-summary.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="operators.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="chapter" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title"><a id="operators-expressions"></a>Chapter 5. Operators and Expressions</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="operators-expressions.html#operators-expressions-intro">Introduction</a></span></dt><dt><span class="section"><a href="operators.html">Operators</a></span></dt><dt><span class="section"><a href="operator-precedence.html">Operator Precedence</a></span></dt><dd><dl><dt><span class="section"><a href="operator-precedence.html#order-of-evaluation">Order of Evaluation</a></span></dt><dt><span class="section"><a href="operator-precedence.html#associativity">Associativity</a></span></dt></dl></dd><dt><span class="section"><a href="expressions.html">Expressions</a></span></dt><dd><dl><dt><span class="section"><a href="expressions.html#using-expressions">Using Expressions</a></span></dt></dl></dd><dt><span class="section"><a href="operators-expressions-summary.html">Summary</a></span></dt></dl></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="operators-expressions-intro"></a>Introduction</h2></div></div></div><p>
+
+ Most statements (logical lines) that you write will contain
+ <span class="bold"><strong>expressions</strong></span>. A simple example of an expression is
+ <code class="literal">2 + 3</code>. An expression can be broken down into operators and operands.
+
+ </p><p>
+
+ <span class="emphasis"><em>Operators</em></span> are functionality that do something and can be
+ represented by symbols such as <code class="literal">+</code> or by special keywords. Operators
+ require some data to operate on and such data are called <span class="emphasis"><em>operands</em></span>.
+ In this case, <code class="literal">2</code> and <code class="literal">3</code> are the operands.
+
+ </p></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="basics-summary.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="operators.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Summary </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Operators</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/operators.html b/help/byteofpython/read/operators.html
new file mode 100644
index 0000000..2c55a73
--- /dev/null
+++ b/help/byteofpython/read/operators.html
@@ -0,0 +1,256 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Operators</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="operators-expressions.html" title="Chapter 5. Operators and Expressions" /><link rel="prev" href="operators-expressions.html" title="Chapter 5. Operators and Expressions" /><link rel="next" href="operator-precedence.html" title="Operator Precedence" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Operators</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="operators-expressions.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 5. Operators and Expressions</th><td width="20%" align="right"> <a accesskey="n" href="operator-precedence.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="operators"></a>Operators</h2></div></div></div><p>
+
+ We will briefly take a look at the operators and their usage:
+
+ </p><div class="tip" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Tip</h3><p>
+
+ You can evaluate the expressions given in the examples using the interpreter
+ interactively. For example, to test the expression <code class="literal">2 + 3</code>, use
+ the interactive Python interpreter prompt:
+
+ </p><pre class="screen">
+
+&gt;&gt;&gt; 2 + 3
+5
+&gt;&gt;&gt; 3 * 5
+15
+&gt;&gt;&gt;
+
+ </pre></div><div class="table"><a id="id3055069"></a><p class="title"><b>Table 5.1. Operators and their usage</b></p><table summary="Operators and their usage" border="1"><colgroup><col /><col /><col /><col /></colgroup><thead><tr><th>Operator</th><th>Name</th><th>Explanation</th><th>Examples</th></tr></thead><tbody><tr><td>+</td><td>Plus</td><td>
+
+ Adds the two objects
+
+ </td><td>
+
+ <code class="literal">3 + 5</code> gives <code class="literal">8</code>.
+ <code class="literal">'a' + 'b'</code> gives <code class="literal">'ab'</code>.
+
+ </td></tr><tr><td>-</td><td>Minus</td><td>
+
+ Either gives a negative number or gives the subtraction of
+ one number from the other
+
+ </td><td>
+
+ <code class="literal">-5.2</code> gives a negative number.
+ <code class="literal">50 - 24</code> gives <code class="literal">26</code>.
+
+ </td></tr><tr><td>*</td><td>Multiply</td><td>
+
+ Gives the multiplication of the two numbers or returns
+ the string repeated that many times.
+
+ </td><td>
+
+ <code class="literal">2 * 3</code> gives <code class="literal">6</code>.
+ <code class="literal">'la' * 3</code> gives <code class="literal">'lalala'</code>.
+
+ </td></tr><tr><td>**</td><td>Power</td><td>
+
+ Returns x to the power of y
+
+ </td><td>
+
+ <code class="literal">3 ** 4</code> gives <code class="literal">81</code>
+ (i.e. <code class="literal">3 * 3 * 3 * 3</code>)
+
+ </td></tr><tr><td>/</td><td>Divide</td><td>
+
+ Divide x by y
+
+ </td><td>
+
+ <code class="literal">4/3</code> gives <code class="literal">1</code> (division
+ of integers gives an integer).
+ <code class="literal">4.0/3</code> or <code class="literal">4/3.0</code> gives
+ <code class="literal">1.3333333333333333</code>
+
+ </td></tr><tr><td>//</td><td>Floor Division</td><td>
+
+ Returns the floor of the quotient
+
+ </td><td>
+
+ <code class="literal">4 // 3.0</code> gives <code class="literal">1.0</code>
+
+ </td></tr><tr><td>%</td><td>Modulo</td><td>
+
+ Returns the remainder of the division
+
+ </td><td>
+
+ <code class="literal">8%3</code> gives <code class="literal">2</code>.
+ <code class="literal">-25.5%2.25</code> gives <code class="literal">1.5</code> .
+
+ </td></tr><tr><td>&lt;&lt;</td><td>Left Shift</td><td>
+
+ Shifts the bits of the number to the left by the number of
+ bits specified. (Each number is represented in memory by
+ bits or binary digits i.e. 0 and 1)
+
+ </td><td>
+
+ <code class="literal">2 &lt;&lt; 2</code> gives
+ <code class="literal">8</code>.
+ - <code class="literal">2</code> is represented by
+ <code class="literal">10</code> in bits. Left shifting by 2 bits
+ gives <code class="literal">1000</code> which represents the
+ decimal <code class="literal">8</code>.
+
+ </td></tr><tr><td>&gt;&gt;</td><td>Right Shift</td><td>
+
+ Shifts the bits of the number to the right by the number
+ of bits specified.
+
+ </td><td>
+
+ <code class="literal">11 &gt;&gt; 1</code> gives
+ <code class="literal">5</code> -
+ <code class="literal">11</code> is represented in bits by
+ <code class="literal">1011</code> which when right shifted by
+ 1 bit gives <code class="literal">101</code> which is nothing
+ but decimal <code class="literal">5</code>.
+
+ </td></tr><tr><td>&amp;</td><td>Bitwise AND</td><td>
+
+ Bitwise AND of the numbers
+
+ </td><td>
+
+ <code class="literal">5 &amp; 3</code> gives
+ <code class="literal">1</code>.
+
+ </td></tr><tr><td>|</td><td>Bit-wise OR</td><td>
+
+ Bitwise OR of the numbers
+
+ </td><td>
+
+ <code class="literal">5 | 3</code> gives <code class="literal">7</code>
+
+ </td></tr><tr><td>^</td><td>Bit-wise XOR</td><td>
+
+ <code class="literal">5 ^ 3</code> gives <code class="literal">6</code>
+
+ </td><td class="auto-generated"> </td></tr><tr><td>~</td><td>Bit-wise invert</td><td>
+
+ The bit-wise inversion of x is -(x+1)
+
+ </td><td>
+
+ <code class="literal">~5</code> gives <code class="literal">-6</code>.
+
+ </td></tr><tr><td>&lt;</td><td>Less Than</td><td>
+
+ Returns whether x is less than y. All comparison operators
+ return 1 for true and 0 for false. This is equivalent to
+ the special variables <code class="literal">True</code> and
+ <code class="literal">False</code> respectively. Note the
+ capitalization of these variables' names.
+
+ </td><td>
+
+ <code class="literal">5 &lt; 3</code> gives
+ <code class="literal">0</code> (i.e. <code class="literal">False</code>) and
+ <code class="literal">3 &lt; 5</code> gives
+ <code class="literal">1</code> (i.e. <code class="literal">True</code>).
+
+ Comparisons can be chained arbitrarily:
+ 3 &lt; 5 &lt; 7 gives <code class="literal">True</code>.
+
+ </td></tr><tr><td>&gt;</td><td>Greater Than</td><td>
+
+ Returns whether x is greater than y
+
+ </td><td>
+
+ <code class="literal">5 &lt; 3</code> returns
+ <code class="literal">True</code>. If both operands are numbers, they
+ are first converted to a common type. Otherwise, it always
+ returns <code class="literal">False</code>.
+
+ </td></tr><tr><td>&lt;=</td><td>Less Than or Equal To</td><td>
+
+ Returns whether x is less than or equal to y
+
+ </td><td>
+
+ <code class="literal">x = 3; y = 6; x &lt;= y</code>
+ returns <code class="literal">True</code>.
+
+ </td></tr><tr><td>&gt;=</td><td>Greater Than or Equal To</td><td>
+
+ Returns whether x is greater than or equal to y
+
+ </td><td>
+
+ x = 4; y = 3; x &gt;= 3 returns
+ <code class="literal">True</code>.
+
+ </td></tr><tr><td>==</td><td>Equal To</td><td>
+
+ Compares if the objects are equal
+
+ </td><td>
+
+ <code class="literal">x = 2; y = 2; x == y</code> returns
+ <code class="literal">True</code>.
+
+ <code class="literal">x = 'str'; y = 'stR'; x == y</code> returns
+ <code class="literal">False</code>.
+
+ <code class="literal">x = 'str'; y = 'str'; x == y</code> returns
+ <code class="literal">True</code>.
+
+ </td></tr><tr><td>!=</td><td>Not Equal To</td><td>
+
+ Compares if the objects are not equal
+
+ </td><td>
+
+ <code class="literal">x = 2; y = 3; x != y</code> returns
+ <code class="literal">True</code>.
+
+ </td></tr><tr><td>not</td><td>Boolean NOT</td><td>
+
+ If x is <code class="literal">True</code>, it returns
+ <code class="literal">False</code>. If x is <code class="literal">False</code>,
+ it returns <code class="literal">True</code>.
+
+ </td><td>
+
+ <code class="literal">x = True; not y</code> returns
+ <code class="literal">False</code>.
+
+ </td></tr><tr><td>and</td><td>Boolean AND</td><td>
+
+ <code class="literal">x and y</code> returns <code class="literal">False</code>
+ if x is <code class="literal">False</code>, else it returns evaluation
+ of y
+
+ </td><td>
+
+ <code class="literal">x = False; y = True; x and y</code> returns
+ <code class="literal">False</code> since x is False. In this case,
+ Python will not evaluate y since it knows that the value of
+ the expression will has to be false (since x is False).
+ This is called short-circuit evaluation.
+
+ </td></tr><tr><td>or</td><td>Boolean OR</td><td>
+
+ If x is <code class="literal">True</code>, it returns True, else it
+ returns evaluation of y
+
+ </td><td>
+
+ <code class="literal">x = True; y = False; x or y</code> returns
+ <code class="literal">True</code>. Short-circuit evaluation applies
+ here as well.
+
+ </td></tr></tbody></table></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="operators-expressions.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="operators-expressions.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="operator-precedence.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 5. Operators and Expressions </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Operator Precedence</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/os-module.html b/help/byteofpython/read/os-module.html
new file mode 100644
index 0000000..9f27f76
--- /dev/null
+++ b/help/byteofpython/read/os-module.html
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>The os module</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="stdlib.html" title="Chapter 14. The Python Standard Library" /><link rel="prev" href="sys-module.html" title="The sys module" /><link rel="next" href="stdlib-summary.html" title="Summary" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">The os module</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sys-module.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 14. The Python Standard Library</th><td width="20%" align="right"> <a accesskey="n" href="stdlib-summary.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="os-module"></a>The os module</h2></div></div></div><p>
+
+ This module represents generic <span class="bold"><strong>o</strong></span>perating
+ <span class="bold"><strong>s</strong></span>ystem functionality. This module is especially important
+ if you want to make your programs platform-independent i.e. it allows the program to be
+ written such that it will run on Linux as well as Windows without any problems and without
+ requiring changes. An example of this is using the <code class="varname">os.sep</code> variable
+ instead of the operation system-specific path separator.
+
+ </p><p>
+
+ Some of the more useful parts of the <code class="literal">os</code> module are listed below
+ Most of them are self-explanatory.
+
+ </p><div class="itemizedlist"><ul type="disc"><li><p>
+
+ The <code class="varname">os.name</code> string specifies which platform you are using,
+ such as <code class="literal">'nt'</code> for Windows and <code class="literal">'posix'</code>
+ for Linux/Unix users.
+
+ </p></li><li><p>
+
+ The <code class="function">os.getcwd()</code> function gets the current working
+ directory i.e. the path of the directory from which the curent Python
+ script is working.
+
+ </p></li><li><p>
+
+ The <code class="function">os.getenv()</code> and <code class="function">os.putenv()</code>
+ functions are used to get and set environment variables respectively.
+
+ </p></li><li><p>
+
+ The <code class="function">os.listdir()</code> function returns the name of all
+ files and directories in the specified directory.
+
+ </p></li><li><p>
+
+ The <code class="function">os.remove()</code> function is used to delete a file.
+
+ </p></li><li><p>
+
+ The <code class="function">os.system()</code> function is used to run a shell
+ command.
+
+ </p></li><li><p>
+
+ The <code class="varname">os.linesep</code> string gives the line terminator used
+ in the current platform. For example, Windows uses <code class="literal">'\r\n'</code>,
+ Linux uses <code class="literal">'\n'</code> and Mac uses <code class="literal">'\r'</code>.
+
+ </p></li><li><p>
+
+ The <code class="function">os.path.split()</code> function returns the directory
+ name and file name of the path.
+
+ </p><pre class="screen">
+
+&gt;&gt;&gt; os.path.split('/home/swaroop/byte/code/poem.txt')
+('/home/swaroop/byte/code', 'poem.txt')
+
+ </pre></li><li><p>
+
+ The <code class="function">os.path.isfile()</code> and the
+ <code class="function">os.path.isdir()</code> functions check if the given path
+ refers to a file or directory respectively. Similarly, the
+ <code class="function">os.path.exists()</code> function is used to check if a
+ given path actually exists.
+
+ </p></li></ul></div><p>
+
+ You can explore the Python Standard Documentation for more details on these functions and
+ variables. You can use <code class="literal">help(sys)</code>, etc. as well.
+
+ </p></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sys-module.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="stdlib.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="stdlib-summary.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">The sys module </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Summary</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/pickle.html b/help/byteofpython/read/pickle.html
new file mode 100644
index 0000000..e976431
--- /dev/null
+++ b/help/byteofpython/read/pickle.html
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Pickle</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="io.html" title="Chapter 12. Input/Output" /><link rel="prev" href="io.html" title="Chapter 12. Input/Output" /><link rel="next" href="io-summary.html" title="Summary" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Pickle</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="io.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 12. Input/Output</th><td width="20%" align="right"> <a accesskey="n" href="io-summary.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="pickle"></a>Pickle</h2></div></div></div><p>
+
+ Python provides a standard module called <code class="literal">pickle</code> using which you can
+ store <span class="bold"><strong>any</strong></span> Python object in a file and then get it back
+ later intact. This is called storing the object <span class="emphasis"><em>persistently</em></span>.
+
+ </p><p>
+
+ There is another module called <code class="literal">cPickle</code> which functions exactly same as
+ the <code class="literal">pickle</code> module except that it is written in the C language and is
+ (upto 1000 times) faster. You can use either of these modules, although we will be using
+ the <code class="literal">cPickle</code> module here. Remember though, that we refer to both these
+ modules as simply the <code class="literal">pickle</code> module.
+
+ </p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="pickling-and-unpickling"></a>Pickling and Unpickling</h3></div></div></div><div class="example"><a id="id3075130"></a><p class="title"><b>Example 12.2. Pickling and Unpickling</b></p><pre class="programlisting">
+
+<span class="py-comment">#!/usr/bin/python</span>
+<span class="py-comment"># Filename: pickling.py</span>
+
+<span class="py-statement">import</span> <span class="py-builtin">cPickle</span> as p
+<span class="py-comment">#import pickle as p</span>
+
+shoplistfile = <span class="py-string">'shoplist.data'</span> <span class="py-comment"># the name of the file where we will store the object</span>
+
+shoplist = [<span class="py-string">'apple'</span>, <span class="py-string">'mango'</span>, <span class="py-string">'carrot'</span>]
+
+<span class="py-comment"># Write to the file</span>
+f = <span class="py-builtin">file</span>(shoplistfile, <span class="py-string">'w'</span>)
+p.dump(shoplist, f) <span class="py-comment"># dump the object to a file</span>
+f.close()
+
+<span class="py-statement">del</span> shoplist <span class="py-comment"># remove the shoplist</span>
+
+<span class="py-comment"># Read back from the storage</span>
+f = <span class="py-builtin">file</span>(shoplistfile)
+storedlist = p.load(f)
+<span class="py-statement">print</span> storedlist
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3075143"></a>Output</h4></div></div></div><pre class="screen">
+
+$ python pickling.py
+['apple', 'mango', 'carrot']
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3075174"></a>How It Works</h4></div></div></div><p>
+
+ First, notice that we use the <code class="literal">import..as</code> syntax. This
+ is handy since we can use a shorter name for a module. In this case, it even
+ allows us to switch to a different module (<code class="literal">cPickle</code>
+ or <code class="literal">pickle</code>) by simply changing one line! In the rest of the
+ program, we simply refer to this module as <code class="varname">p</code>.
+
+ </p><p>
+
+ To store an object in a file, first we open a <code class="classname">file</code>
+ object in write mode and store the object into the open file by calling
+ the <code class="function">dump</code> function of the pickle module. This process
+ is called <span class="emphasis"><em>pickling</em></span>.
+
+ </p><p>
+
+ Next, we retrieve the object using the <code class="function">load</code> function
+ of the <code class="literal">pickle</code> module which returns the object.
+ This process is called <span class="emphasis"><em>unpickling</em></span>.
+
+ </p></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="io.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="io.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="io-summary.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 12. Input/Output </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Summary</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/preface.html b/help/byteofpython/read/preface.html
new file mode 100644
index 0000000..bda1115
--- /dev/null
+++ b/help/byteofpython/read/preface.html
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Preface</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="index.html" title="A Byte of Python" /><link rel="prev" href="index.html" title="A Byte of Python" /><link rel="next" href="history-lesson.html" title="History Lesson" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Preface</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="index.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="history-lesson.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="preface" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title"><a id="preface"></a>Preface</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="preface.html#who-this-book-is-for">Who This Book Is For</a></span></dt><dt><span class="section"><a href="history-lesson.html">History Lesson</a></span></dt><dt><span class="section"><a href="status.html">Status of the book</a></span></dt><dt><span class="section"><a href="official-website.html">Official Website</a></span></dt><dt><span class="section"><a href="license.html">License Terms</a></span></dt><dt><span class="section"><a href="feedback.html">Feedback</a></span></dt><dt><span class="section"><a href="something-to-think-about.html">Something To Think About</a></span></dt></dl></div><p>
+ Python is probably one of the few programming languages which is both
+ simple and powerful. This is good for both and beginners as well as
+ experts, and more importantly, is fun to program with. This book aims
+ to help you learn this wonderful language and show how to get things
+ done quickly and painlessly - in effect 'The Perfect Anti-venom to your
+ programming problems'.
+ </p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="who-this-book-is-for"></a>Who This Book Is For</h2></div></div></div><p>
+ This book serves as a guide or tutorial to the Python programming
+ language. It is mainly targeted at newbies. It is useful for experienced
+ programmers as well.
+ </p><p>
+ The aim is that if all you know about computers is how to save text files,
+ then you can learn Python from this book. If you have previous programming
+ experience, then you can also learn Python from this book.
+ </p><p>
+ If you do have previous programming experience, you will be interested in
+ the differences between Python and your favorite programming language - I
+ have highlighted many such differences. A little warning though, Python is
+ soon going to become your favorite programming language!
+ </p></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="index.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="history-lesson.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">A Byte of Python </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> History Lesson</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/problem-solving-summary.html b/help/byteofpython/read/problem-solving-summary.html
new file mode 100644
index 0000000..b58a307
--- /dev/null
+++ b/help/byteofpython/read/problem-solving-summary.html
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Summary</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="problem-solving.html" title="Chapter 10. Problem Solving - Writing a Python Script" /><link rel="prev" href="software-development-process.html" title="The Software Development Process" /><link rel="next" href="oops.html" title="Chapter 11. Object-Oriented Programming" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Summary</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="software-development-process.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 10. Problem Solving - Writing a Python Script</th><td width="20%" align="right"> <a accesskey="n" href="oops.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="problem-solving-summary"></a>Summary</h2></div></div></div><p>
+
+ We have seen how to create our own Python programs/scripts and the various stages involved
+ in writing such programs. You may find it useful to create your own program just like we
+ did in this chapter so that you become comfortable with Python as well as problem-solving.
+
+ </p><p>
+
+ Next, we will discuss object-oriented programming.
+
+ </p></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="software-development-process.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="problem-solving.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="oops.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">The Software Development Process </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Chapter 11. Object-Oriented Programming</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/problem-solving.html b/help/byteofpython/read/problem-solving.html
new file mode 100644
index 0000000..4bbf93e
--- /dev/null
+++ b/help/byteofpython/read/problem-solving.html
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Chapter 10. Problem Solving - Writing a Python Script</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="index.html" title="A Byte of Python" /><link rel="prev" href="data-structures-summary.html" title="Summary" /><link rel="next" href="the-solution.html" title="The Solution" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 10. Problem Solving - Writing a Python Script</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="data-structures-summary.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="the-solution.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="chapter" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title"><a id="problem-solving"></a>Chapter 10. Problem Solving - Writing a Python Script</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="problem-solving.html#the-problem">The Problem</a></span></dt><dt><span class="section"><a href="the-solution.html">The Solution</a></span></dt><dd><dl><dt><span class="section"><a href="the-solution.html#first-version">First Version</a></span></dt><dt><span class="section"><a href="the-solution.html#second-version">Second Version</a></span></dt><dt><span class="section"><a href="the-solution.html#third-version">Third Version</a></span></dt><dt><span class="section"><a href="the-solution.html#fourth-version">Fourth Version</a></span></dt><dt><span class="section"><a href="the-solution.html#more-refinements">More Refinements</a></span></dt></dl></dd><dt><span class="section"><a href="software-development-process.html">The Software Development Process</a></span></dt><dt><span class="section"><a href="problem-solving-summary.html">Summary</a></span></dt></dl></div><p>
+
+ We have explored various parts of the Python language and now we will take a look at how all
+ these parts fit together, by designing and writing a program which <span class="emphasis"><em>does</em></span>
+ something useful.
+
+ </p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="the-problem"></a>The Problem</h2></div></div></div><p>
+
+ The problem is <span class="emphasis"><em>'I want a program which creates a backup of all my important
+ files'</em></span>.
+
+ </p><p>
+
+ Although, this is a simple problem, there is not enough information for us to get started with
+ the solution. A little more <span class="bold"><strong>analysis</strong></span> is required. For example,
+ how do we specify which files are to be backed up? Where is the backup stored? How are they
+ stored in the backup?
+
+ </p><p>
+
+ After analyzing the problem properly, we <span class="bold"><strong>design</strong></span> our program. We
+ make a list of things about how our program should work. In this case, I have created the
+ following list on how <span class="emphasis"><em>I</em></span> want it to work. If you do the design, you may not
+ come up with the same kind of problem - every person has their own way of doing things, this is
+ ok.
+
+ </p><div class="orderedlist"><ol type="1"><li><p>
+
+ The files and directories to be backed up are specified in a list.
+
+ </p></li><li><p>
+
+ The backup must be stored in a main backup directory.
+
+ </p></li><li><p>
+
+ The files are backed up into a zip file.
+
+ </p></li><li><p>
+
+ The name of the zip archive is the current date and time.
+
+ </p></li><li><p>
+
+ We use the standard <span><strong class="command">zip</strong></span> command available by default in any
+ standard Linux/Unix distribution. Windows users can use the
+ <span class="application">Info-Zip</span> program. Note that you can use any archiving
+ command you want as long as it has a command line interface so that we can pass
+ arguments to it from our script.
+
+ </p></li></ol></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="data-structures-summary.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="the-solution.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Summary </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> The Solution</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/raising-exceptions.html b/help/byteofpython/read/raising-exceptions.html
new file mode 100644
index 0000000..fa6251d
--- /dev/null
+++ b/help/byteofpython/read/raising-exceptions.html
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Raising Exceptions</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="exceptions.html" title="Chapter 13. Exceptions" /><link rel="prev" href="try-except.html" title="Try..Except" /><link rel="next" href="try-finally.html" title="Try..Finally" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Raising Exceptions</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="try-except.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 13. Exceptions</th><td width="20%" align="right"> <a accesskey="n" href="try-finally.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="raising-exceptions"></a>Raising Exceptions</h2></div></div></div><p>
+
+ You can <span class="emphasis"><em>raise</em></span> exceptions using the <code class="literal">raise</code> statement.
+ You also have to specify the name of the error/exception and the exception object that is
+ to be <span class="emphasis"><em>thrown</em></span> along with the exception. The error or exception that you
+ can arise should be class which directly or indirectly is a derived class of the
+ <code class="classname">Error</code> or <code class="classname">Exception</code> class respectively.
+
+ </p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="how-to-raise-exceptions"></a>How To Raise Exceptions</h3></div></div></div><div class="example"><a id="id3076145"></a><p class="title"><b>Example 13.2. How to Raise Exceptions</b></p><pre class="programlisting">
+
+<span class="py-comment">#!/usr/bin/python</span>
+<span class="py-comment"># Filename: raising.py</span>
+
+<span class="py-statement">class</span> <span class="py-identifier">ShortInputException</span>(Exception):
+ <span class="py-string">'''A user-defined exception class.'''</span>
+ <span class="py-statement">def</span> <span class="py-identifier">__init__</span>(<span class="py-builtin">self</span>, length, atleast):
+ Exception.__init__(<span class="py-builtin">self</span>)
+ <span class="py-builtin">self</span>.length = length
+ <span class="py-builtin">self</span>.atleast = atleast
+
+<span class="py-statement">try</span>:
+ s = <span class="py-builtin">raw_input</span>(<span class="py-string">'Enter something --&gt; '</span>)
+ <span class="py-statement">if</span> <span class="py-builtin">len</span>(s) &lt; <span class="py-number">3</span>:
+ raise ShortInputException(<span class="py-builtin">len</span>(s), <span class="py-number">3</span>)
+ <span class="py-comment"># Other work can continue as usual here</span>
+<span class="py-statement">except</span> EOFError:
+ <span class="py-statement">print</span> <span class="py-string">'\nWhy did you do an EOF on me?'</span>
+<span class="py-statement">except</span> ShortInputException, x:
+ <span class="py-statement">print</span> <span class="py-string">'ShortInputException: The input was of length %d, \
+ was expecting at least %d'</span> % (x.length, x.atleast)
+<span class="py-statement">else</span>:
+ <span class="py-statement">print</span> <span class="py-string">'No exception was raised.'</span>
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3076158"></a>Output</h4></div></div></div><pre class="screen">
+
+$ python raising.py
+Enter something --&gt;
+Why did you do an EOF on me?
+
+$ python raising.py
+Enter something --&gt; ab
+ShortInputException: The input was of length 2, was expecting at least 3
+
+$ python raising.py
+Enter something --&gt; abc
+No exception was raised.
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3076191"></a>How It Works</h4></div></div></div><p>
+
+ Here, we are creating our own exception type although we could've used any
+ predefined exception/error for demonstration purposes. This new exception
+ type is the <code class="classname">ShortInputException</code> class. It has two
+ fields - <code class="varname">length</code> which is the length of the given input,
+ and <code class="varname">atleast</code> which is the minimum length that the program
+ was expecting.
+
+ </p><p>
+
+ In the <code class="literal">except</code> clause, we mention the class of error as
+ well as the variable to hold the corresponding error/exception object.
+ This is analogous to parameters and arguments in a function call. Within
+ this particular <code class="literal">except</code> clause, we use the
+ <code class="varname">length</code> and <code class="varname">atleast</code> fields of the
+ exception object to print an appropriate message to the user.
+
+ </p></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="try-except.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="exceptions.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="try-finally.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Try..Except </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Try..Finally</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/references.html b/help/byteofpython/read/references.html
new file mode 100644
index 0000000..cedc2d5
--- /dev/null
+++ b/help/byteofpython/read/references.html
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>References</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="data-structures.html" title="Chapter 9. Data Structures" /><link rel="prev" href="sequences.html" title="Sequences" /><link rel="next" href="more-about-strings.html" title="More about Strings" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">References</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="sequences.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 9. Data Structures</th><td width="20%" align="right"> <a accesskey="n" href="more-about-strings.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="references"></a>References</h2></div></div></div><p>
+
+ When you create an object and assign it to a variable, the variable only
+ <span class="emphasis"><em>refers</em></span> to the object and does not represent the object itself!
+ That is, the variable name points to that part of your computer's memory where the
+ object is stored. This is called as <span class="bold"><strong>binding</strong></span> of the
+ name to the object.
+
+ </p><p>
+
+ Generally, you don't need to be worried about this, but there is a subtle effect due
+ to references which you need to be aware of. This is demonstrated by the following
+ example.
+
+ </p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="objects-and-references"></a>Objects and References</h3></div></div></div><div class="example"><a id="id3067361"></a><p class="title"><b>Example 9.6. Objects and References</b></p><pre class="programlisting">
+
+<span class="py-comment">#!/usr/bin/python</span>
+<span class="py-comment"># Filename: reference.py</span>
+
+<span class="py-statement">print</span> <span class="py-string">'Simple Assignment'</span>
+shoplist = [<span class="py-string">'apple'</span>, <span class="py-string">'mango'</span>, <span class="py-string">'carrot'</span>, <span class="py-string">'banana'</span>]
+mylist = shoplist <span class="py-comment"># mylist is just another name pointing to the same object!</span>
+
+<span class="py-statement">del</span> shoplist[<span class="py-number">0</span>] <span class="py-comment"># I purchased the first item, so I remove it from the list</span>
+
+<span class="py-statement">print</span> <span class="py-string">'shoplist is'</span>, shoplist
+<span class="py-statement">print</span> <span class="py-string">'mylist is'</span>, mylist
+<span class="py-comment"># notice that both shoplist and mylist both print the same list without</span>
+<span class="py-comment"># the 'apple' confirming that they point to the same object</span>
+
+<span class="py-statement">print</span> <span class="py-string">'Copy by making a full slice'</span>
+mylist = shoplist[:] <span class="py-comment"># make a copy by doing a full slice</span>
+<span class="py-statement">del</span> mylist[<span class="py-number">0</span>] <span class="py-comment"># remove first item</span>
+
+<span class="py-statement">print</span> <span class="py-string">'shoplist is'</span>, shoplist
+<span class="py-statement">print</span> <span class="py-string">'mylist is'</span>, mylist
+<span class="py-comment"># notice that now the two lists are different</span>
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3067374"></a>Output</h4></div></div></div><pre class="screen">
+
+$ python reference.py
+Simple Assignment
+shoplist is ['mango', 'carrot', 'banana']
+mylist is ['mango', 'carrot', 'banana']
+Copy by making a full slice
+shoplist is ['mango', 'carrot', 'banana']
+mylist is ['carrot', 'banana']
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3067410"></a>How It Works</h4></div></div></div><p>
+
+ Most of the explanation is available in the comments itself. What you
+ need to remember is that if you want to make a copy of a list or such
+ kinds of sequences or complex objects (not simple <span class="emphasis"><em>objects</em></span>
+ such as integers), then you have to use the slicing operation to make a
+ copy. If you just assign the variable name to another name, both of them
+ will <span class="emphasis"><em>refer</em></span> to the same object and this could lead to
+ all sorts of trouble if you are not careful.
+
+ </p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note for Perl programmers</h3><p>
+
+ Remember that an assignment statement for lists does
+ <span class="bold"><strong>not</strong></span> create a copy. You have to use
+ slicing operation to make a copy of the sequence.
+
+ </p></div></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="sequences.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="data-structures.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="more-about-strings.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Sequences </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> More about Strings</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/repr-function.html b/help/byteofpython/read/repr-function.html
new file mode 100644
index 0000000..330cefb
--- /dev/null
+++ b/help/byteofpython/read/repr-function.html
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>The repr function</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="more-python.html" title="Chapter 15. More Python" /><link rel="prev" href="assert-statement.html" title="The assert statement" /><link rel="next" href="more-python-summary.html" title="Summary" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">The repr function</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="assert-statement.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 15. More Python</th><td width="20%" align="right"> <a accesskey="n" href="more-python-summary.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="repr-function"></a>The repr function</h2></div></div></div><p>
+
+ The <code class="function">reprt</code> function is used to obtain a canonical string
+ representation of the object. Backticks (also called conversion or reverse quotes) do
+ the same thing. Note that you will have <code class="literal">eval(repr(object)) == object</code>
+ most of the time.
+
+ </p><pre class="screen">
+
+&gt;&gt;&gt; i = []
+&gt;&gt;&gt; i.append('item')
+&gt;&gt;&gt; `i`
+"['item']"
+&gt;&gt;&gt; repr(i)
+"['item']"
+
+ </pre><p>
+
+ Basically, the <code class="function">repr</code> function or the backticks are used to obtain
+ a printable representation of the object. you can control what your objects return
+ for the <code class="function">repr</code> function by defining the <code class="methodname">__repr__</code>
+ method in your class.
+
+ </p></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="assert-statement.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="more-python.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="more-python-summary.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">The assert statement </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Summary</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/return.html b/help/byteofpython/read/return.html
new file mode 100644
index 0000000..f4a896a
--- /dev/null
+++ b/help/byteofpython/read/return.html
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>The return statement</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="functions.html" title="Chapter 7. Functions" /><link rel="prev" href="keyword-arguments.html" title="Keyword Arguments" /><link rel="next" href="docstrings.html" title="DocStrings" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">The return statement</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="keyword-arguments.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 7. Functions</th><td width="20%" align="right"> <a accesskey="n" href="docstrings.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="return"></a>The return statement</h2></div></div></div><p>
+
+ The <code class="literal">return</code> statement is used to <span class="emphasis"><em>return</em></span> from a
+ function i.e. break out of the function. We can optionally <span class="emphasis"><em>return a value</em></span>
+ from the function as well.
+
+ </p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="id3062208"></a>Using the literal statement</h3></div></div></div><div class="example"><a id="id3062214"></a><p class="title"><b>Example 7.7. Using the literal statement</b></p><pre class="programlisting">
+
+<span class="py-comment">#!/usr/bin/python</span>
+<span class="py-comment"># Filename: func_return.py</span>
+
+<span class="py-statement">def</span> <span class="py-identifier">maximum</span>(x, y):
+ <span class="py-statement">if</span> x &gt; y:
+ <span class="py-statement">return</span> x
+ <span class="py-statement">else</span>:
+ <span class="py-statement">return</span> y
+
+<span class="py-statement">print</span> maximum(<span class="py-number">2</span>, <span class="py-number">3</span>)
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3062226"></a>Output</h4></div></div></div><pre class="screen">
+
+$ python func_return.py
+3
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3062245"></a>How It Works</h4></div></div></div><p>
+
+ The <code class="function">maximum</code> function returns the maximum of the
+ parameters, in this case the numbers supplied to the function. It uses a
+ simple <code class="literal">if..else</code> statement to find the greater value
+ and then <span class="emphasis"><em>returns</em></span> that value.
+
+ </p><p>
+
+ Note that a <code class="literal">return</code> statement without a value is
+ equivalent to <code class="literal">return None</code>. <code class="literal">None</code> is
+ a special type in Python that represents nothingness. For example, it
+ is used to indicate that a variable has no value if it has a value of
+ <code class="literal">None</code>.
+
+ </p><p>
+
+ Every function implicitly contains a <code class="literal">return None</code>
+ statement at the end unless you have written your own <code class="literal">return</code>
+ statement. You can see this by running <code class="literal">print someFunction()</code>
+ where the function <code class="function">someFunction</code> does not use the
+ <code class="literal">return</code> statement such as:
+
+ </p><pre class="programlisting">
+
+<span class="py-statement">def</span> <span class="py-identifier">someFunction</span>():
+ <span class="py-statement">pass</span>
+
+ </pre><p>
+
+ The <code class="literal">pass</code> statement is used in Python to indicate an
+ empty block of statements.
+
+ </p></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="keyword-arguments.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="functions.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="docstrings.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Keyword Arguments </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> DocStrings</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/revhistory.html b/help/byteofpython/read/revhistory.html
new file mode 100644
index 0000000..65a6e8e
--- /dev/null
+++ b/help/byteofpython/read/revhistory.html
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Appendix C. Revision History</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="index.html" title="A Byte of Python" /><link rel="prev" href="about-the-author.html" title="About the Author" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Appendix C. Revision History</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="about-the-author.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> </td></tr></table><hr /></div><div class="appendix" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title"><a id="revhistory"></a>Appendix C. Revision History</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="revhistory.html#timestamp">Timestamp</a></span></dt></dl></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="timestamp"></a>Timestamp</h2></div></div></div><p>
+ This document was generated on January 13, 2005
+ at 04:02
+ </p></div><div class="revhistory"><table border="0" width="100%" summary="Revision history"><tr><th align="left" valign="top" colspan="3"><b>Revision History</b></th></tr><tr><td align="left">Revision 1.20</td><td align="left">13/01/2005</td><td align="left"> </td></tr><tr><td align="left" colspan="3">
+ Complete rewrite using Quanta+ on FC3 with lot of corrections and updates. Many
+ new examples. Re-wrote my DocBook setup from scratch.
+ </td></tr><tr><td align="left">Revision 1.15</td><td align="left">28/03/2004</td><td align="left"> </td></tr><tr><td align="left" colspan="3">
+ Minor revisions
+ </td></tr><tr><td align="left">Revision 1.12</td><td align="left">16/03/2004</td><td align="left"> </td></tr><tr><td align="left" colspan="3">
+ Additions and corrections.
+ </td></tr><tr><td align="left">Revision 1.10</td><td align="left">09/03/2004</td><td align="left"> </td></tr><tr><td align="left" colspan="3">
+ More typo corrections, thanks to many enthusiastic and helpful readers.
+ </td></tr><tr><td align="left">Revision 1.00</td><td align="left">08/03/2004</td><td align="left"> </td></tr><tr><td align="left" colspan="3">
+ After tremendous feedback and suggestions from readers, I have made
+ significant revisions to the content along with typo corrections.
+ </td></tr><tr><td align="left">Revision 0.99</td><td align="left">22/02/2004</td><td align="left"> </td></tr><tr><td align="left" colspan="3">
+ Added a new chapter on modules. Added details about variable number
+ of arguments in functions.
+ </td></tr><tr><td align="left">Revision 0.98</td><td align="left">16/02/2004</td><td align="left"> </td></tr><tr><td align="left" colspan="3">
+ Wrote a Python script and CSS stylesheet to improve XHTML output,
+ including a crude-yet-functional lexical analyzer for automatic
+ VIM-like syntax highlighting of the program listings.
+ </td></tr><tr><td align="left">Revision 0.97</td><td align="left">13/02/2004</td><td align="left"> </td></tr><tr><td align="left" colspan="3">
+ Another completely rewritten draft, in DocBook XML (again). Book has
+ improved a lot - it is more coherent and readable.
+ </td></tr><tr><td align="left">Revision 0.93</td><td align="left">25/01/2004</td><td align="left"> </td></tr><tr><td align="left" colspan="3">
+ Added IDLE talk and more Windows-specific stuff
+ </td></tr><tr><td align="left">Revision 0.92</td><td align="left">05/01/2004</td><td align="left"> </td></tr><tr><td align="left" colspan="3">
+ Changes to few examples.
+ </td></tr><tr><td align="left">Revision 0.91</td><td align="left">30/12/2003</td><td align="left"> </td></tr><tr><td align="left" colspan="3">
+ Corrected typos. Improvised many topics.
+ </td></tr><tr><td align="left">Revision 0.90</td><td align="left">18/12/2003</td><td align="left"> </td></tr><tr><td align="left" colspan="3">
+ Added 2 more chapters. OpenOffice format with revisions.
+ </td></tr><tr><td align="left">Revision 0.60</td><td align="left">21/11/2003</td><td align="left"> </td></tr><tr><td align="left" colspan="3">
+ Fully rewritten and expanded.
+ </td></tr><tr><td align="left">Revision 0.20</td><td align="left">20/11/2003</td><td align="left"> </td></tr><tr><td align="left" colspan="3">
+ Corrected some typos and errors.
+ </td></tr><tr><td align="left">Revision 0.15</td><td align="left">20/11/2003</td><td align="left"> </td></tr><tr><td align="left" colspan="3">
+ Converted to DocBook XML.
+ </td></tr><tr><td align="left">Revision 0.10</td><td align="left">14/11/2003</td><td align="left"> </td></tr><tr><td align="left" colspan="3">
+ Initial draft using KWord.
+ </td></tr></table></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="about-the-author.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> </td></tr><tr><td width="40%" align="left" valign="top">About the Author </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> </td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/self.html b/help/byteofpython/read/self.html
new file mode 100644
index 0000000..c2bb7d1
--- /dev/null
+++ b/help/byteofpython/read/self.html
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>The self</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="oops.html" title="Chapter 11. Object-Oriented Programming" /><link rel="prev" href="oops.html" title="Chapter 11. Object-Oriented Programming" /><link rel="next" href="classes.html" title="Classes" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">The self</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="oops.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 11. Object-Oriented Programming</th><td width="20%" align="right"> <a accesskey="n" href="classes.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="self"></a>The self</h2></div></div></div><p>
+
+ Class methods have only one specific difference from ordinary functions - they must have
+ an extra first name that has to be added to the beginning of the parameter list, but you
+ do <span class="bold"><strong>do not</strong></span> give a value for this parameter when you call
+ the method, Python will provide it. This particular variable refers to the object itself,
+ and by convention, it is given the name <code class="literal">self</code>.
+
+ </p><p>
+
+ Although, you can give any name for this parameter, it is <span class="emphasis"><em>strongly
+ recommended</em></span> that you use the name <code class="literal">self</code> - any other name is
+ definitely frowned upon. There are many advantages to using a standard name - any reader
+ of your program will immediately recognize it and even specialized <span class="abbrev">IDEs</span>
+ (Integrated Development Environments) can help you if you use <code class="literal">self</code>.
+
+ </p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note for C++/Java/C# Programmers</h3><p>
+
+ The <code class="literal">self</code> in Python is equivalent to the <code class="literal">self</code>
+ pointer in C++ and the <code class="literal">this</code> reference in Java and C#.
+
+ </p></div><p>
+
+ You must be wondering how Python gives the value for <code class="literal">self</code> and why you
+ don't need to give a value for it. An example will make this clear. Say you have a class
+ called <code class="classname">MyClass</code> and an instance of this class called
+ <code class="varname">MyObject</code>. When you call a method of this object as
+ <code class="literal">MyObject.method(arg1, arg2)</code>, this is automatically converted by Python
+ into <code class="literal">MyClass.method(MyObject, arg1, arg2</code> - this is what the special
+ <code class="literal">self</code> is all about.
+
+ </p><p>
+
+ This also means that if you have a method which takes no arguments, then you still have
+ to define the method to have a <code class="literal">self</code> argument.
+
+ </p></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="oops.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="oops.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="classes.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 11. Object-Oriented Programming </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Classes</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/sequences.html b/help/byteofpython/read/sequences.html
new file mode 100644
index 0000000..169aa8d
--- /dev/null
+++ b/help/byteofpython/read/sequences.html
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Sequences</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="data-structures.html" title="Chapter 9. Data Structures" /><link rel="prev" href="dictionary.html" title="Dictionary" /><link rel="next" href="references.html" title="References" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Sequences</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="dictionary.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 9. Data Structures</th><td width="20%" align="right"> <a accesskey="n" href="references.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="sequences"></a>Sequences</h2></div></div></div><p>
+
+ Lists, tuples and strings are examples of sequences, but what are sequences and what is
+ so special about them? Two of the main features of a sequence is the
+ <span class="bold"><strong>indexing</strong></span> operation which allows us to fetch a particular
+ item in the sequence directly and the <span class="bold"><strong>slicing</strong></span> operation
+ which allows us to retrieve a slice of the sequence i.e. a part of the sequence.
+
+ </p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="using-sequences"></a>Using Sequences</h3></div></div></div><div class="example"><a id="id3067126"></a><p class="title"><b>Example 9.5. Using Sequences</b></p><pre class="programlisting">
+
+<span class="py-comment">#!/usr/bin/python</span>
+<span class="py-comment"># Filename: seq.py</span>
+
+shoplist = [<span class="py-string">'apple'</span>, <span class="py-string">'mango'</span>, <span class="py-string">'carrot'</span>, <span class="py-string">'banana'</span>]
+
+<span class="py-comment"># Indexing or 'Subscription' operation</span>
+<span class="py-statement">print</span> <span class="py-string">'Item 0 is'</span>, shoplist[<span class="py-number">0</span>]
+<span class="py-statement">print</span> <span class="py-string">'Item 1 is'</span>, shoplist[<span class="py-number">1</span>]
+<span class="py-statement">print</span> <span class="py-string">'Item 2 is'</span>, shoplist[<span class="py-number">2</span>]
+<span class="py-statement">print</span> <span class="py-string">'Item 3 is'</span>, shoplist[<span class="py-number">3</span>]
+<span class="py-statement">print</span> <span class="py-string">'Item -1 is'</span>, shoplist[-<span class="py-number">1</span>]
+<span class="py-statement">print</span> <span class="py-string">'Item -2 is'</span>, shoplist[-<span class="py-number">2</span>]
+
+<span class="py-comment"># Slicing on a list</span>
+<span class="py-statement">print</span> <span class="py-string">'Item 1 to 3 is'</span>, shoplist[<span class="py-number">1</span>:<span class="py-number">3</span>]
+<span class="py-statement">print</span> <span class="py-string">'Item 2 to end is'</span>, shoplist[<span class="py-number">2</span>:]
+<span class="py-statement">print</span> <span class="py-string">'Item 1 to -1 is'</span>, shoplist[<span class="py-number">1</span>:-<span class="py-number">1</span>]
+<span class="py-statement">print</span> <span class="py-string">'Item start to end is'</span>, shoplist[:]
+
+<span class="py-comment"># Slicing on a string</span>
+name = <span class="py-string">'swaroop'</span>
+<span class="py-statement">print</span> <span class="py-string">'characters 1 to 3 is'</span>, name[<span class="py-number">1</span>:<span class="py-number">3</span>]
+<span class="py-statement">print</span> <span class="py-string">'characters 2 to end is'</span>, name[<span class="py-number">2</span>:]
+<span class="py-statement">print</span> <span class="py-string">'characters 1 to -1 is'</span>, name[<span class="py-number">1</span>:-<span class="py-number">1</span>]
+<span class="py-statement">print</span> <span class="py-string">'characters start to end is'</span>, name[:]
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3067138"></a>Output</h4></div></div></div><pre class="screen">
+
+$ python seq.py
+Item 0 is apple
+Item 1 is mango
+Item 2 is carrot
+Item 3 is banana
+Item -1 is banana
+Item -2 is carrot
+Item 1 to 3 is ['mango', 'carrot']
+Item 2 to end is ['carrot', 'banana']
+Item 1 to -1 is ['mango', 'carrot']
+Item start to end is ['apple', 'mango', 'carrot', 'banana']
+characters 1 to 3 is wa
+characters 2 to end is aroop
+characters 1 to -1 is waroo
+characters start to end is swaroop
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3067175"></a>How It Works</h4></div></div></div><p>
+
+ First, we see how to use indexes to get individual items of a sequence.
+ This is also referred to as the subscription operation. Whenever you
+ specify a number to a sequence within square brackets as shown above,
+ Python will fetch you the item corresponding to that position in the
+ sequence. Remember that Python starts counting numbers from 0. Hence,
+ <code class="literal">shoplist[0]</code> fetches the first item and
+ <code class="literal">shoplist[3]</code> fetches the fourth item in the
+ <code class="varname">shoplist</code> sequence.
+
+ </p><p>
+
+ The index can also be a negative number, in which case, the position is
+ calculated from the end of the sequence. Therefore,
+ <code class="literal">shoplist[-1]</code> refers to the last item in the sequence and
+ <code class="literal">shoplist[-2]</code> fetches the second last item in the
+ sequence.
+
+ </p><p>
+
+ The slicing operation is used by specifying the name of the sequence followed
+ by an optional pair of numbers separated by a colon within square brackets.
+ Note that this is very very similar to the indexing operation you have been
+ using til lnow. Remember the numbers are optional but the colon isn't.
+
+ </p><p>
+
+ The first number (before the colon) in the slicing operation refers to the
+ position from where the slice starts and the second number (after the colon)
+ indicates where the slice will stop at. If the first number is not specified,
+ Python will start at the beginning of the sequence. If the second number is
+ left out, Python will stop at the end of the sequence. Note that the slice
+ returned <span class="emphasis"><em>starts</em></span> at the start position and will end
+ just before the <span class="emphasis"><em>end</em></span> position i.e. the start position is
+ included but the end position is excluded from the sequence slice.
+
+ </p><p>
+
+ Thus, <code class="literal">shoplist[1:3]</code> returns a slice of the sequence
+ starting at position 1, includes position 2 but stops at position 3 and
+ therefore a <span class="emphasis"><em>slice</em></span> of two items is returned.
+ Similarly, <code class="literal">shoplist[:]</code> returns a copy of the whole
+ sequence.
+
+ </p><p>
+
+ You can also do slicing with negative positions. Negative numbers are used
+ for positions from the end of the sequence. For example,
+ <code class="literal">shoplist[:-1]</code> will return a slice of the sequence which
+ excludes the last item of the sequence but contains everything else.
+
+ </p><p>
+
+ Try various combinations of such slice specifications using the Python
+ interpreter interactively i.e. the prompt so that you can see the results
+ immediately. The great thing about sequences is that you can access
+ tuples, lists and strings all in the same way!
+
+ </p></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="dictionary.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="data-structures.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="references.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Dictionary </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> References</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/single-statement-blocks.html b/help/byteofpython/read/single-statement-blocks.html
new file mode 100644
index 0000000..3388e12
--- /dev/null
+++ b/help/byteofpython/read/single-statement-blocks.html
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Single Statement Blocks</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="more-python.html" title="Chapter 15. More Python" /><link rel="prev" href="more-python.html" title="Chapter 15. More Python" /><link rel="next" href="list-comprehension.html" title="List Comprehension" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Single Statement Blocks</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="more-python.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 15. More Python</th><td width="20%" align="right"> <a accesskey="n" href="list-comprehension.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="single-statement-blocks"></a>Single Statement Blocks</h2></div></div></div><p>
+
+ By now, you should have firmly understood that each block of statements is set apart
+ from the rest by its own indentation level. Well, this is true for the most part but
+ it is not 100% accurate. If your block of statements contains only one single statement,
+ then you can specify it on the same line of, say, a conditional statement or looping
+ statement. The following example should make this clear:
+
+ </p><pre class="screen">
+
+&gt;&gt;&gt; flag = True
+&gt;&gt;&gt; if flag: print 'Yes'
+...
+Yes
+
+ </pre><p>
+
+ As we can see, the single statement is used in-place and not as a separate block.
+ Although, you can use this for making your program <span class="emphasis"><em>smaller</em></span>, I
+ <span class="bold"><strong>strongly</strong></span> recommend that you do not use this
+ short-cut method except for error checking, etc. One major reason is that it will
+ be much easier to add an extra statement if you are using proper indentation.
+
+ </p><p>
+
+ Also notice that when the Python interpreter is used in interactive mode, it helps you
+ enter the statements by changing prompts appropriately. In the aboe case, after you entered
+ the keyword <code class="literal">if</code>, it changes the prompt to <code class="literal">...</code> to
+ indicate that the statement is not yet complete. When we do complete the statement in
+ this manner, we press <span><strong class="keycap">enter</strong></span> to confirm that the statement is complete.
+ Then, Python finishes executing the whole statement and returns to the old prompt waiting
+ for the next input.
+
+ </p></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="more-python.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="more-python.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="list-comprehension.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 15. More Python </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> List Comprehension</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/software-development-process.html b/help/byteofpython/read/software-development-process.html
new file mode 100644
index 0000000..2e6165c
--- /dev/null
+++ b/help/byteofpython/read/software-development-process.html
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>The Software Development Process</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="problem-solving.html" title="Chapter 10. Problem Solving - Writing a Python Script" /><link rel="prev" href="the-solution.html" title="The Solution" /><link rel="next" href="problem-solving-summary.html" title="Summary" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">The Software Development Process</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="the-solution.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 10. Problem Solving - Writing a Python Script</th><td width="20%" align="right"> <a accesskey="n" href="problem-solving-summary.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="software-development-process"></a>The Software Development Process</h2></div></div></div><p>
+
+ We have now gone through the various <span class="bold"><strong>phases</strong></span> in the process
+ of writing a software. These phases can be summarised as follows:
+
+ </p><div class="procedure"><ol type="1"><li><p>
+
+ What (Analysis)
+
+ </p></li><li><p>
+
+ How (Design)
+
+ </p></li><li><p>
+
+ Do It (Implementation)
+
+ </p></li><li><p>
+
+ Test (Testing and Debugging)
+
+ </p></li><li><p>
+
+ Use (Operation or Deployment)
+
+ </p></li><li><p>
+
+ Maintain (Refinement)
+
+ </p></li></ol></div><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Important</h3><p>
+
+ A recommended way of writing programs is the procedure we have followed in creating
+ the backup script - Do the analysis and design. Start implementing with a simple
+ version. Test and debug it. Use it to ensure that it works as expected. Now, add any
+ features that you want and continue to repeat the Do It-Test-Use cycle as many times
+ as required. Remember, '<span class="bold"><strong>Software is grown, not built</strong></span>'.
+
+ </p></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="the-solution.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="problem-solving.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="problem-solving-summary.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">The Solution </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Summary</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/something-to-think-about.html b/help/byteofpython/read/something-to-think-about.html
new file mode 100644
index 0000000..f7c34cc
--- /dev/null
+++ b/help/byteofpython/read/something-to-think-about.html
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Something To Think About</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="preface.html" title="Preface" /><link rel="prev" href="feedback.html" title="Feedback" /><link rel="next" href="introduction.html" title="Chapter 1. Introduction" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Something To Think About</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="feedback.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Preface</th><td width="20%" align="right"> <a accesskey="n" href="introduction.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="something-to-think-about"></a>Something To Think About</h2></div></div></div><div class="blockquote"><table border="0" width="100%" cellspacing="0" cellpadding="0" class="blockquote" summary="Block quote"><tr><td width="10%" valign="top"> </td><td width="80%" valign="top"><p>
+ There are two ways of constructing a software design: one way is to
+ make it so simple that there are obviously no deficiencies; the other
+ is to make it so complicated that there are no obvious deficiencies.
+ </p></td><td width="10%" valign="top"> </td></tr><tr><td width="10%" valign="top"> </td><td colspan="2" align="right" valign="top">--<span class="attribution">C. A. R. Hoare</span></td></tr></table></div><div class="blockquote"><table border="0" width="100%" cellspacing="0" cellpadding="0" class="blockquote" summary="Block quote"><tr><td width="10%" valign="top"> </td><td width="80%" valign="top"><p>
+ Success in life is a matter not so much of talent and opportunity as
+ of concentration and perseverance.
+ </p></td><td width="10%" valign="top"> </td></tr><tr><td width="10%" valign="top"> </td><td colspan="2" align="right" valign="top">--<span class="attribution">C. W. Wendte</span></td></tr></table></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="feedback.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="preface.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="introduction.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Feedback </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Chapter 1. Introduction</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/source-file.html b/help/byteofpython/read/source-file.html
new file mode 100644
index 0000000..1b0b944
--- /dev/null
+++ b/help/byteofpython/read/source-file.html
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Using a Source File</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="first-steps.html" title="Chapter 3. First Steps" /><link rel="prev" href="choosing-an-editor.html" title="Choosing an Editor" /><link rel="next" href="executable-python-programs.html" title="Executable Python programs" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Using a Source File</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="choosing-an-editor.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 3. First Steps</th><td width="20%" align="right"> <a accesskey="n" href="executable-python-programs.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="source-file"></a>Using a Source File</h2></div></div></div><p>
+
+ Now let's get back to programming. There is a tradition that whenever you learn a new
+ programming language, the first program that you write and run is the 'Hello World'
+ program - all it does is just say 'Hello World' when you run it. As Simon Cozens
+ <sup>[<a id="id3050402" href="#ftn.id3050402">1</a>]</sup>
+ puts it, it is the 'traditional incantation to the programming gods to help you learn
+ the language better' :) .
+
+ </p><p>
+
+ Start your choice of editor, enter the following program and save it as
+ <code class="filename">helloworld.py</code>
+
+ </p><div class="example"><a id="id3050424"></a><p class="title"><b>Example 3.2. Using a Source File</b></p><pre class="programlisting">
+
+<span class="py-comment">#!/usr/bin/python</span>
+<span class="py-comment"># Filename : helloworld.py</span>
+<span class="py-statement">print</span> <span class="py-string">'Hello World'</span>
+
+ </pre><p>
+ (Source file: <a href="code/helloworld.py" target="_top">code/helloworld.py</a>)
+ </p></div><p>
+
+ Run this program by opening a shell (Linux terminal or DOS prompt) and entering the
+ command <span><strong class="command">python <em class="replaceable"><code>helloworld.py</code></em></strong></span>. If you
+ are using IDLE, use the menu <span class="guimenu">Edit</span> -&gt;
+ <span class="guimenuitem">Run Script</span> or the keyboard shortcut
+ <span><strong class="keycap">Ctrl</strong></span>-<span><strong class="keycap">F5</strong></span>. The output is as shown
+ below.
+
+ </p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="id3050490"></a>Output</h3></div></div></div><pre class="screen">
+
+$ python helloworld.py
+Hello World
+
+ </pre></div><p>
+
+ If you got the output as shown above, congratulations! - you have successfully run your
+ first Python program.
+
+ </p><p>
+
+ In case you got an error, please type the above program <span class="emphasis"><em>exactly</em></span> as
+ shown and above and run the program again. Note that Python is case-sensitive i.e.
+ <code class="literal">print</code> is not the same as <code class="literal">Print</code> - note the
+ lowercase <code class="literal">p</code> in the former and the uppercase <code class="literal">P</code> in
+ the latter. Also, ensure there are no spaces or tabs before the first character in each
+ line - we will see why this is important later.
+
+ </p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="id3050545"></a>How It Works</h3></div></div></div><p>
+
+ Let us consider the first two lines of the program. These are called
+ <span class="emphasis"><em>comments</em></span> - anything to the right of the <code class="literal">#</code>
+ symbol is a comment and is mainly useful as notes for the reader of the program.
+
+ </p><p>
+
+ Python does not use comments except for the special case of the first line here.
+ It is called the <span class="emphasis"><em>shebang line</em></span> - whenever the first two
+ characters of the source file are <code class="literal">#!</code> followed by the location
+ of a program, this tells your Linux/Unix system that this program should be run
+ with this interpreter when you <span class="emphasis"><em>execute</em></span> the program. This is
+ explained in detail in the <a href="executable-python-programs.html" title="Executable Python programs">next section</a>. Note that you can always run the program on any platform by
+ specifying the interpreter directly on the command line such as the command
+ <span><strong class="command">python <em class="replaceable"><code>helloworld.py</code></em></strong></span> .
+
+ </p><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Important</h3><p>
+
+ Use comments sensibly in your program to explain some important details
+ of your program - this is useful for readers of your program so that they
+ can easily understand what the program is doing. Remember, that person
+ can be yourself after six months!
+
+ </p></div><p>
+
+ The comments are followed by a Python <span class="emphasis"><em>statement</em></span> - this just
+ prints the text <code class="literal">'Hello World'</code>. The <code class="literal">print</code>
+ is actually an operator and <code class="literal">'Hello World'</code> is referred to as a
+ string - don't worry, we will explore these terminologies in detail later.
+
+ </p></div><div class="footnotes"><br /><hr width="100" align="left" /><div class="footnote"><p><sup>[<a id="ftn.id3050402" href="#id3050402">1</a>] </sup>
+ one of the leading Perl6/Parrot hackers and the author of the amazing
+ 'Beginning Perl' book
+ </p></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="choosing-an-editor.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="first-steps.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="executable-python-programs.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Choosing an Editor </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Executable Python programs</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/status.html b/help/byteofpython/read/status.html
new file mode 100644
index 0000000..4ab34b4
--- /dev/null
+++ b/help/byteofpython/read/status.html
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Status of the book</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="preface.html" title="Preface" /><link rel="prev" href="history-lesson.html" title="History Lesson" /><link rel="next" href="official-website.html" title="Official Website" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Status of the book</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="history-lesson.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Preface</th><td width="20%" align="right"> <a accesskey="n" href="official-website.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="status"></a>Status of the book</h2></div></div></div><p>
+ This book is a <span class="bold"><strong>work-in-progress</strong></span>. Many chapters
+ are constantly being changed and improved. However, the book has matured a lot.
+ You should be able to learn Python easily from this book. Please do tell me if
+ you find any part of the book to be incorrect or incomprehensible.
+ </p><p>
+ More chapters are planned for the future, such as on wxPython, Twisted and maybe
+ even Boa Constructor.
+ </p></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="history-lesson.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="preface.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="official-website.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">History Lesson </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Official Website</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/stdlib-summary.html b/help/byteofpython/read/stdlib-summary.html
new file mode 100644
index 0000000..dcc5d50
--- /dev/null
+++ b/help/byteofpython/read/stdlib-summary.html
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Summary</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="stdlib.html" title="Chapter 14. The Python Standard Library" /><link rel="prev" href="os-module.html" title="The os module" /><link rel="next" href="more-python.html" title="Chapter 15. More Python" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Summary</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="os-module.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 14. The Python Standard Library</th><td width="20%" align="right"> <a accesskey="n" href="more-python.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="stdlib-summary"></a>Summary</h2></div></div></div><p>
+
+ We have seen some of the functionality of the <code class="literal">sys</code> module and
+ <code class="literal">sys</code> modules in the Python Standard Library. You should explore the
+ Python Standard Documentation to find out more about these and other modules as well.
+
+ </p><p>
+
+ Next, we will cover various aspects of Python that will make our tour of Python more
+ <span class="emphasis"><em>complete</em></span>.
+
+ </p></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="os-module.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="stdlib.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="more-python.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">The os module </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Chapter 15. More Python</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/stdlib.html b/help/byteofpython/read/stdlib.html
new file mode 100644
index 0000000..f6bc89a
--- /dev/null
+++ b/help/byteofpython/read/stdlib.html
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Chapter 14. The Python Standard Library</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="index.html" title="A Byte of Python" /><link rel="prev" href="exceptions-summary.html" title="Summary" /><link rel="next" href="sys-module.html" title="The sys module" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 14. The Python Standard Library</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="exceptions-summary.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="sys-module.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="chapter" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title"><a id="stdlib"></a>Chapter 14. The Python Standard Library</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="stdlib.html#stdlib-intro">Introduction</a></span></dt><dt><span class="section"><a href="sys-module.html">The sys module</a></span></dt><dd><dl><dt><span class="section"><a href="sys-module.html#command-line-arguments">Command Line Arguments</a></span></dt><dt><span class="section"><a href="sys-module.html#more-sys">More sys</a></span></dt></dl></dd><dt><span class="section"><a href="os-module.html">The os module</a></span></dt><dt><span class="section"><a href="stdlib-summary.html">Summary</a></span></dt></dl></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="stdlib-intro"></a>Introduction</h2></div></div></div><p>
+
+ The Python Standard Library is available with every Python installation. It contains a
+ huge number of very useful modules. It is important that you become familiar with the
+ Python Standard Library since most of your problems can be solved more easily and quickly
+ if you are familiar with this library of modules.
+
+ </p><p>
+
+ We will explore some of the commonly used modules in this library. You can find complete
+ details for all of the modules in the Python Standard Library in the 'Library
+ Reference' section in the documentation that comes with your Python installation.
+
+ </p></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="exceptions-summary.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="sys-module.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Summary </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> The sys module</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/strings.html b/help/byteofpython/read/strings.html
new file mode 100644
index 0000000..311d7e3
--- /dev/null
+++ b/help/byteofpython/read/strings.html
@@ -0,0 +1,139 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Strings</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="basics.html" title="Chapter 4. The Basics" /><link rel="prev" href="numbers.html" title="Numbers" /><link rel="next" href="variables.html" title="Variables" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Strings</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="numbers.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 4. The Basics</th><td width="20%" align="right"> <a accesskey="n" href="variables.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="strings"></a>Strings</h2></div></div></div><p>
+
+ A string is a <span class="emphasis"><em>sequence</em></span> of <span class="emphasis"><em>characters</em></span>. Strings
+ are basically just a bunch of words.
+
+ </p><p>
+
+ I can almost guarantee that you will be using strings in almost every Python program that
+ you write, so pay attention to the following part. Here's how you use strings in Python:
+
+ </p><div class="itemizedlist"><ul type="disc"><li><h5><a id="id3052205"></a>Using Single Quotes (<code class="literal">'</code>)</h5><p>
+
+ You can specify strings using single quotes such as
+ <code class="literal">'Quote me on this'</code> . All white space i.e. spaces and
+ tabs are preserved as-is.
+
+ </p></li><li><h5><a id="id3052231"></a>Using Double Quotes (<code class="literal">"</code>)</h5><p>
+
+ Strings in double quotes work exactly the same way as strings in single
+ quotes. An example is
+ <code class="literal">"What's your name?"</code>
+
+ </p></li><li><h5><a id="id3052258"></a>Using Triple Quotes (<code class="literal">'''</code> or <code class="literal">"""</code>)</h5><p>
+
+ You can specify multi-line strings using triple quotes. You can use single
+ quotes and double quotes freely within the triple quotes. An example is
+
+ </p><pre class="programlisting">
+
+<span class="py-string">'''This is a multi-line string. This is the first line.
+This is the second line.
+"What's your name?," I asked.
+He said "Bond, James Bond."
+'''</span>
+
+ </pre></li><li><h5><a id="id3052296"></a>Escape Sequences</h5><p>
+
+ Suppose, you want to have a string which contains a single quote
+ (<code class="literal">'</code>), how will you specify this string? For example,
+ the string is <code class="literal">What's your name?</code>. You cannot specify
+ <code class="literal">'What's your name?'</code> because Python will be confused
+ as to where the string starts and ends. So, you will have to specify
+ that this single quote does not indicate the end of the string. This can
+ be done with the help of what is called an <span class="emphasis"><em>escape
+ sequence</em></span>. You specify the single quote as <code class="literal">\'</code>
+ - notice the backslash. Now, you can specify the string as
+ <code class="literal">'What\'s your name?'</code>.
+
+ </p><p>
+
+ Another way of specifying this specific string would be
+ <code class="literal">"What's your name?"</code> i.e. using double quotes. Similarly,
+ you have to use an escape sequence forusing a double quote itself in a
+ double quoted string. Also, you have to indicate the backslash itself using
+ the escape sequence <code class="literal">\\</code>.
+
+ </p><p>
+
+ What if you wanted to specify a two-line string? One way is to use a
+ triple-quoted string as shown above or you can use an escape sequence for
+ the newline character - <code class="literal">\n</code> to indicate the start of a
+ new line. An example is <code class="literal">This is the first line\nThis is the
+ second line</code> . Another useful escape sequence to know is the tab
+ - <code class="literal">\t</code>. There are many more escape sequences but I have
+ mentioned only the most useful ones here.
+
+ </p><p>
+
+ One thing to note is that in a string, a single backslash at the end of
+ the line indicates that the string is continued in the next line, but
+ no newline is added. For example,
+
+ </p><pre class="programlisting">
+
+<span class="py-string">"This is the first sentence.\
+This is the second sentence."</span>
+
+ </pre><p>
+
+ is equivalent to <code class="literal">"This is the first sentence. This is the second sentence."</code>
+
+ </p></li><li><h5><a id="id3052423"></a>Raw Strings</h5><p>
+
+ If you need to specify some strings where no special processing such as
+ escape sequences are handled, then what you need is to specify a
+ <span class="emphasis"><em>raw</em></span> string by prefixing <code class="literal">r</code> or
+ <code class="literal">R</code> to the string. An example is
+ <code class="literal">r"Newlines are indicated by \n"</code>.
+
+ </p></li><li><h5><a id="id3052460"></a>Unicode Strings</h5><p>
+
+ Unicode is a standard way of writing international text. If you want to
+ write text in your native language such as Hindi or Arabic, then you need
+ to have a Unicode-enabled text editor. Similarly, Python allows you to
+ handle Unicode text - all you need to do is prefix <code class="literal">u</code>
+ or <code class="literal">U</code>. For example,
+ <code class="literal">u"This is a Unicode string."</code>.
+
+ </p><p>
+
+ Remember to use Unicode strings when you are dealing with text files,
+ especially when you know that the file will contain text written in
+ languages other than English.
+
+ </p></li><li><h5><a id="id3052503"></a>Strings are immutable</h5><p>
+
+ This means that once you have created a string, you cannot change it.
+ Although this might seem like a bad thing, it really isn't. We will see
+ why this is not a limitation in the various programs that we see later on.
+
+ </p></li><li><h5><a id="id3052519"></a>String literal concatenation</h5><p>
+
+ If you place two string literals side by side, they are automatically
+ concatenated by Python. For example, <code class="literal">'What\'s' 'your name?'</code>
+ is automatically converted in to <code class="literal">"What's your name?"</code>.
+
+ </p></li></ul></div><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note for C/C++ Programmers</h3><p>
+
+ There is no separate <code class="classname">char</code> data type in Python. There is
+ no real need for it and I am sure you won't miss it.
+
+ </p></div><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note for Perl/PHP Programmers</h3><p>
+
+ Remember that single-quoted strings and double-quoted strings are the same - they
+ do not differ in any way.
+
+ </p></div><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note for Regular Expression Users</h3><p>
+
+ Always use raw strings when dealing with regular expressions. Otherwise, a lot of
+ backwhacking may be required. For example, backreferences can be referred to as
+ <code class="literal">'\\1'</code> or <code class="literal">r'\1'</code>.
+
+ </p></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="numbers.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="basics.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="variables.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Numbers </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Variables</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/sys-module.html b/help/byteofpython/read/sys-module.html
new file mode 100644
index 0000000..db35270
--- /dev/null
+++ b/help/byteofpython/read/sys-module.html
@@ -0,0 +1,137 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>The sys module</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="stdlib.html" title="Chapter 14. The Python Standard Library" /><link rel="prev" href="stdlib.html" title="Chapter 14. The Python Standard Library" /><link rel="next" href="os-module.html" title="The os module" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">The sys module</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="stdlib.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 14. The Python Standard Library</th><td width="20%" align="right"> <a accesskey="n" href="os-module.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="sys-module"></a>The sys module</h2></div></div></div><p>
+
+ The <code class="literal">sys</code> module contains system-specific functionality. we have already
+ seen that the <code class="varname">sys.argv</code> list contains the command-line arguments.
+
+ </p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="command-line-arguments"></a>Command Line Arguments</h3></div></div></div><div class="example"><a id="id3077190"></a><p class="title"><b>Example 14.1. Using sys.argv</b></p><pre class="programlisting">
+
+<span class="py-comment">#!/usr/bin/python</span>
+<span class="py-comment"># Filename: cat.py</span>
+
+<span class="py-statement">import</span> <span class="py-builtin">sys</span>
+
+<span class="py-statement">def</span> <span class="py-identifier">readfile</span>(filename):
+ <span class="py-string">'''Print a file to the standard output.'''</span>
+ f = <span class="py-builtin">file</span>(filename)
+ <span class="py-statement">while</span> <span class="py-builtin">True</span>:
+ line = f.readline()
+ <span class="py-statement">if</span> <span class="py-builtin">len</span>(line) == <span class="py-number">0</span>:
+ <span class="py-statement">break</span>
+ <span class="py-statement">print</span> line, <span class="py-comment"># notice comma</span>
+ f.close()
+
+<span class="py-comment"># Script starts from here</span>
+<span class="py-statement">if</span> <span class="py-builtin">len</span>(<span class="py-builtin">sys</span>.argv) &lt; <span class="py-number">2</span>:
+ <span class="py-statement">print</span> <span class="py-string">'No action specified.'</span>
+ <span class="py-builtin">sys</span>.exit()
+
+<span class="py-statement">if</span> <span class="py-builtin">sys</span>.argv[<span class="py-number">1</span>].startswith(<span class="py-string">'--'</span>):
+ option = <span class="py-builtin">sys</span>.argv[<span class="py-number">1</span>][<span class="py-number">2</span>:]
+ <span class="py-comment"># fetch sys.argv[1] but without the first two characters</span>
+ <span class="py-statement">if</span> option == <span class="py-string">'version'</span>:
+ <span class="py-statement">print</span> <span class="py-string">'Version 1.2'</span>
+ <span class="py-statement">elif</span> option == <span class="py-string">'help'</span>:
+ <span class="py-statement">print</span> <span class="py-string">'''\
+This program prints files to the standard output.
+Any number of files can be specified.
+Options include:
+ --version : Prints the version number
+ --help : Display this help'''</span>
+ <span class="py-statement">else</span>:
+ <span class="py-statement">print</span> <span class="py-string">'Unknown option.'</span>
+ <span class="py-builtin">sys</span>.exit()
+<span class="py-statement">else</span>:
+ <span class="py-statement">for</span> filename <span class="py-statement">in</span> <span class="py-builtin">sys</span>.argv[<span class="py-number">1</span>:]:
+ readfile(filename)
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3077202"></a>Output</h4></div></div></div><pre class="screen">
+
+$ python cat.py
+No action specified.
+
+$ python cat.py --help
+This program prints files to the standard output.
+Any number of files can be specified.
+Options include:
+ --version : Prints the version number
+ --help : Display this help
+
+$ python cat.py --version
+Version 1.2
+
+$ python cat.py --nonsense
+Unknown option.
+
+$ python cat.py poem.txt
+Programming is fun
+When the work is done
+if you wanna make your work also fun:
+ use Python!
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3077215"></a>How It Works</h4></div></div></div><p>
+
+ This program tries to mimic the <span><strong class="command">cat</strong></span> command familiar to
+ Linux/Unix users. You just speicfy the names of some text files and it will
+ print them to the output.
+
+ </p><p>
+
+ When a Python program is run i.e. not an interactive mode, there is always
+ at least one item in the <code class="varname">sys.argv</code> list which is the name
+ of the current program being run and is available as
+ <code class="literal">sys.argv[0]</code> since Python starts counting from 0. Other
+ command line arguments follow this item.
+
+ </p><p>
+
+ To make the program user-friendly we have supplied certain options that the
+ user can specify to learn more about the program. We use the first argument
+ to check if any options have been specified to our program. If the
+ <code class="literal">--version</code> option is used, the version number of the program
+ is printed. Similarly, when the <code class="literal">--help</code> option is specified,
+ we give a bit of explanation about the program. We make use of the
+ <code class="function">sys.exit</code> function to exit the running program. As always,
+ see <code class="literal">help(sys.exit)</code> for more details.
+
+ </p><p>
+
+ When no options are specified and filenames are passed to the program, it
+ simply prints out each line of each file, one after the other in the order
+ specified on the command line.
+
+ </p><p>
+
+ As an aside, the name <span><strong class="command">cat</strong></span> is short for
+ <span class="emphasis"><em>concatenate</em></span> which is basically what this program does
+ - it can print out a file or attach/concatenate two or more files together
+ in the output.
+
+ </p></div></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="more-sys"></a>More sys</h3></div></div></div><p>
+
+ The <code class="varname">sys.version</code> string gives you information about the version
+ of Python that you have installed. The <code class="varname">sys.version_info</code> tuple
+ gives an easier way of enabling Python-version specific parts of your program.
+
+ </p><pre class="screen">
+
+[swaroop@localhost code]$ python
+&gt;&gt;&gt; import sys
+&gt;&gt;&gt; sys.version
+'2.3.4 (#1, Oct 26 2004, 16:42:40) \n[GCC 3.4.2 20041017 (Red Hat 3.4.2-6.fc3)]'
+&gt;&gt;&gt; sys.version_info
+(2, 3, 4, 'final', 0)
+
+ </pre><p>
+
+ For experienced programmers, other items of interest in the <code class="literal">sys</code>
+ module include <code class="varname">sys.stdin</code>, <code class="varname">sys.stdout</code> and
+ <code class="varname">sys.stderr</code> which correspond to the standard input, standard
+ output and standard error streams of your program respectively.
+
+ </p></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="stdlib.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="stdlib.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="os-module.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 14. The Python Standard Library </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> The os module</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/the-solution.html b/help/byteofpython/read/the-solution.html
new file mode 100644
index 0000000..d911c77
--- /dev/null
+++ b/help/byteofpython/read/the-solution.html
@@ -0,0 +1,471 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>The Solution</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="problem-solving.html" title="Chapter 10. Problem Solving - Writing a Python Script" /><link rel="prev" href="problem-solving.html" title="Chapter 10. Problem Solving - Writing a Python Script" /><link rel="next" href="software-development-process.html" title="The Software Development Process" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">The Solution</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="problem-solving.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 10. Problem Solving - Writing a Python Script</th><td width="20%" align="right"> <a accesskey="n" href="software-development-process.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="the-solution"></a>The Solution</h2></div></div></div><p>
+
+ As the design of our program is now stable, we can write the code which is an
+ <span class="bold"><strong>implementation</strong></span> of our solution.
+
+ </p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="first-version"></a>First Version</h3></div></div></div><div class="example"><a id="id3069271"></a><p class="title"><b>Example 10.1. Backup Script - The First Version</b></p><pre class="programlisting">
+
+<span class="py-comment">#!/usr/bin/python</span>
+<span class="py-comment"># Filename: backup_ver1.py</span>
+
+<span class="py-statement">import</span> <span class="py-builtin">os</span>
+<span class="py-statement">import</span> <span class="py-builtin">time</span>
+
+<span class="py-comment"># 1. The files and directories to be backed up are specified in a list.</span>
+source = [<span class="py-string">'/home/swaroop/byte'</span>, <span class="py-string">'/home/swaroop/bin'</span>]
+<span class="py-comment"># If you are using Windows, use source = [r'C:\Documents', r'D:\Work'] or something like that</span>
+
+<span class="py-comment"># 2. The backup must be stored in a main backup directory</span>
+target_dir = <span class="py-string">'/mnt/e/backup/'</span> <span class="py-comment"># Remember to change this to what you will be using</span>
+
+<span class="py-comment"># 3. The files are backed up into a zip file.</span>
+<span class="py-comment"># 4. The name of the zip archive is the current date and time</span>
+target = target_dir + <span class="py-builtin">time</span>.strftime(<span class="py-string">'%Y%m%d%H%M%S'</span>) + <span class="py-string">'.zip'</span>
+
+<span class="py-comment"># 5. We use the zip command (in Unix/Linux) to put the files in a zip archive</span>
+zip_command = <span class="py-string">"zip -qr '%s' %s"</span> % (target, <span class="py-string">' '</span>.join(source))
+
+<span class="py-comment"># Run the backup</span>
+<span class="py-statement">if</span> <span class="py-builtin">os</span>.system(zip_command) == <span class="py-number">0</span>:
+ <span class="py-statement">print</span> <span class="py-string">'Successful backup to'</span>, target
+<span class="py-statement">else</span>:
+ <span class="py-statement">print</span> <span class="py-string">'Backup FAILED'</span>
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3069284"></a>Output</h4></div></div></div><pre class="screen">
+
+$ python backup_ver1.py
+Successful backup to /mnt/e/backup/20041208073244.zip
+
+ </pre><p>
+
+ Now, we are in the <span class="bold"><strong>testing</strong></span> phase where
+ we test that our program works properly. If it doesn't behave as
+ expected, then we have to <span class="bold"><strong>debug</strong></span> our
+ program i.e. remove the <span class="emphasis"><em>bugs</em></span> (errors) from the
+ program.
+
+ </p></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3069350"></a>How It Works</h4></div></div></div><p>
+
+ You will notice how we have converted our <span class="emphasis"><em>design</em></span> into
+ <span class="emphasis"><em>code</em></span> in a step-by-step manner.
+
+ </p><p>
+
+ We make use of the <code class="literal">os</code> and <code class="literal">time</code>
+ modules and so we import them. Then, we specify the files and directories
+ to be backed up in the <code class="varname">source</code> list. The target directory
+ is where store all the backup files and this is specified in the
+ <code class="varname">target_dir</code> variable. The name of the zip archive that
+ we are going to create is the current date and time which we fetch using the
+ <code class="function">time.strftime()</code> function. It will also have the
+ <code class="filename">.zip</code> extension and will be stored in the
+ <code class="varname">target_dir</code> directory.
+
+ </p><p>
+
+ The <code class="function">time.strftime()</code> function takes a specification
+ such as the one we have used in the above program. The <code class="literal">%Y</code>
+ specification will be replaced by the year without the cetury. The
+ <code class="literal">%m</code> specification will be replaced by the month as a
+ decimal number between <code class="literal">01</code> and <code class="literal">12</code> and
+ so on. The complete list of such specifications can be found in the
+ [<span class="citation">Python Reference Manual</span>] that comes with your Python
+ distribution. Notice that this is similar to (but not same as) the
+ specification used in <code class="literal">print</code> statement (using the
+ <code class="literal">%</code> followed by tuple).
+
+ </p><p>
+
+ We create the name of the target zip file using the addition operator
+ which <span class="emphasis"><em>concatenates</em></span> the strings i.e. it joins the
+ two strings together and returns a new one. Then, we create a string
+ <code class="varname">zip_command</code> which contains the command that we are
+ going to execute. You can check if this command works by running it on
+ the shell (Linux terminal or DOS prompt).
+
+ </p><p>
+
+ The <span><strong class="command">zip</strong></span> command that we are using has some options
+ and parameters passed. The <code class="option">-q</code> option is used to indicate
+ that the zip command should work <span class="bold"><strong>q</strong></span>uietly.
+ The <code class="option">-r</code> option specifies that the zip command should work
+ <span class="bold"><strong>r</strong></span>ecursively for directories i.e. it
+ should include subdirectories and files within the subdirectories as well.
+ The two options are combined and specified in a shorter way as
+ <code class="option">-qr</code>. The options are followed by the name of the zip archive
+ to create followed by the list of files and directories to backup. We
+ convert the <code class="varname">source</code> list into a string using the
+ <code class="methodname">join</code> method of strings which we have already seen
+ how to use.
+
+ </p><p>
+
+ Then, we finally <span class="emphasis"><em>run</em></span> the command using the
+ <code class="function">os.system</code> function which runs the command as if it
+ was run from the <span class="emphasis"><em>system</em></span> i.e. in the shell - it returns
+ <code class="literal">0</code> if the command was successfully, else it returns an
+ error number.
+
+ </p><p>
+
+ Depending on the outcome of the command, we print the appropriate message
+ that the backup has failed or succeeded and that's it, we have created a
+ script to take a backup of our important files!
+
+ </p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note to Windows Users</h3><p>
+
+ You can set the <code class="varname">source</code> list and
+ <code class="varname">target</code> directory to any file and directory names
+ but you have to be a little careful in Windows. The problem is that
+ Windows uses the backslash (<code class="literal">\</code>) as the directory
+ separator character but Python uses backslashes to represent
+ escape sequences!
+
+ </p><p>
+
+ So, you have to represent a backslash itself using an escape
+ sequence or you have to use raw strings. For example, use
+ <code class="literal">'C:\\Documents'</code> or <code class="literal">r'C:\Documents'</code>
+ but do <span class="bold"><strong>not</strong></span> use
+ <code class="literal">'C:\Documents'</code> - you are using an unknown
+ escape sequence <code class="literal">\D</code> !
+
+ </p></div><p>
+
+ Now that we have a working backup script, we can use it whenever we want
+ to take a backup of the files. Linux/Unix users are advised to use the
+ <a href="executable-python-programs.html" title="Executable Python programs">executable method</a> as
+ discussed earlier so that they can run the backup script anytime anywhere.
+ This is called the <span class="bold"><strong>operation</strong></span> phase or the
+ <span class="bold"><strong>deployment</strong></span> phase of the software.
+
+ </p><p>
+
+ The above program works properly, but (usually) first programs do not work
+ exactly as you expect. For example, there might be problems if you have not
+ designed the program properly or if you have made a mistake in typing the
+ code, etc. Appropriately, you will have to go back to the design phase or
+ you will have to debug your program.
+
+ </p></div></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="second-version"></a>Second Version</h3></div></div></div><p>
+
+ The first version of our script works. However, we can make some refinements to it
+ so that it can work better on a daily basis. This is called the
+ <span class="bold"><strong>maintenance</strong></span> phase of the software.
+
+ </p><p>
+
+ One of the refinements I felt was useful is a better file-naming mechanism - using
+ the <span class="emphasis"><em>time</em></span> as the name of the file within a directory with the
+ current <span class="emphasis"><em>date</em></span> as a directory within the main backup directory.
+ One advantage is that your backups are stored in a hierarchical manner and therefore
+ it is much easier to manage. Another advantage is that the length of the filenames
+ are much shorter this way. Yet another advantage is that separate directories will
+ help you to easily check if you have taken a backup for each day since the
+ directory would be created only if you have taken a backup for that day.
+
+ </p><div class="example"><a id="id3069716"></a><p class="title"><b>Example 10.2. Backup Script - The Second Version</b></p><pre class="programlisting">
+
+<span class="py-comment">#!/usr/bin/python</span>
+<span class="py-comment"># Filename: backup_ver2.py</span>
+
+<span class="py-statement">import</span> <span class="py-builtin">os</span>
+<span class="py-statement">import</span> <span class="py-builtin">time</span>
+
+<span class="py-comment"># 1. The files and directories to be backed up are specified in a list.</span>
+source = [<span class="py-string">'/home/swaroop/byte'</span>, <span class="py-string">'/home/swaroop/bin'</span>]
+<span class="py-comment"># If you are using Windows, use source = [r'C:\Documents', r'D:\Work'] or something like that</span>
+
+<span class="py-comment"># 2. The backup must be stored in a main backup directory</span>
+target_dir = <span class="py-string">'/mnt/e/backup/'</span> <span class="py-comment"># Remember to change this to what you will be using</span>
+
+<span class="py-comment"># 3. The files are backed up into a zip file.</span>
+<span class="py-comment"># 4. The current day is the name of the subdirectory in the main directory</span>
+today = target_dir + <span class="py-builtin">time</span>.strftime(<span class="py-string">'%Y%m%d'</span>)
+<span class="py-comment"># The current time is the name of the zip archive</span>
+now = <span class="py-builtin">time</span>.strftime(<span class="py-string">'%H%M%S'</span>)
+
+<span class="py-comment"># Create the subdirectory if it isn't already there</span>
+<span class="py-statement">if</span> <span class="py-statement">not</span> <span class="py-builtin">os</span>.path.exists(today):
+ <span class="py-builtin">os</span>.mkdir(today) <span class="py-comment"># make directory</span>
+ <span class="py-statement">print</span> <span class="py-string">'Successfully created directory'</span>, today
+
+<span class="py-comment"># The name of the zip file</span>
+target = today + <span class="py-builtin">os</span>.sep + now + <span class="py-string">'.zip'</span>
+
+<span class="py-comment"># 5. We use the zip command (in Unix/Linux) to put the files in a zip archive</span>
+zip_command = <span class="py-string">"zip -qr '%s' %s"</span> % (target, <span class="py-string">' '</span>.join(source))
+
+<span class="py-comment"># Run the backup</span>
+<span class="py-statement">if</span> <span class="py-builtin">os</span>.system(zip_command) == <span class="py-number">0</span>:
+ <span class="py-statement">print</span> <span class="py-string">'Successful backup to'</span>, target
+<span class="py-statement">else</span>:
+ <span class="py-statement">print</span> <span class="py-string">'Backup FAILED'</span>
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3069729"></a>Output</h4></div></div></div><pre class="screen">
+
+$ python backup_ver2.py
+Successfully created directory /mnt/e/backup/20041208
+Successful backup to /mnt/e/backup/20041208/080020.zip
+
+$ python backup_ver2.py
+Successful backup to /mnt/e/backup/20041208/080428.zip
+
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3069742"></a>How It Works</h4></div></div></div><p>
+
+ Most of the program remains the same. The changes is that we check if there
+ is a directory with the current day as name inside the main backup
+ directory using the <code class="function">os.exists</code> function. If it doesn't
+ exist, we create it using the <code class="function">os.mkdir</code> function.
+
+ </p><p>
+
+ Notice the use of <code class="varname">os.sep</code> variable - this gives the
+ directory separator according to your operating system i.e. it will be
+ <code class="literal">'/'</code> in Linux, Unix, it will be <code class="literal">'\\'</code>
+ in Windows and <code class="literal">':'</code> in Mac OS. Using
+ <code class="varname">os.sep</code> instead of these characters directly will make
+ our program portable and work across these systems.
+
+ </p></div></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="third-version"></a>Third Version</h3></div></div></div><p>
+
+ The second version works fine when I do many backups, but when there are lots of
+ backups, I am finding it hard to differentiate what the backups were for! For
+ example, I might have made some major changes to a program or presentation,
+ then I want to associate what those changes are with the name of the zip archive.
+ This can be easily achieved by attaching a user-supplied comment to the name of
+ the zip archive.
+
+ </p><div class="example"><a id="id3069869"></a><p class="title"><b>Example 10.3. Backup Script - The Third Version (does not work!)</b></p><pre class="programlisting">
+
+<span class="py-comment">#!/usr/bin/python</span>
+<span class="py-comment"># Filename: backup_ver2.py</span>
+
+<span class="py-statement">import</span> <span class="py-builtin">os</span>
+<span class="py-statement">import</span> <span class="py-builtin">time</span>
+
+<span class="py-comment"># 1. The files and directories to be backed up are specified in a list.</span>
+source = [<span class="py-string">'/home/swaroop/byte'</span>, <span class="py-string">'/home/swaroop/bin'</span>]
+<span class="py-comment"># If you are using Windows, use source = [r'C:\Documents', r'D:\Work'] or something like that</span>
+
+<span class="py-comment"># 2. The backup must be stored in a main backup directory</span>
+target_dir = <span class="py-string">'/mnt/e/backup/'</span> <span class="py-comment"># Remember to change this to what you will be using</span>
+
+<span class="py-comment"># 3. The files are backed up into a zip file.</span>
+<span class="py-comment"># 4. The current day is the name of the subdirectory in the main directory</span>
+today = target_dir + <span class="py-builtin">time</span>.strftime(<span class="py-string">'%Y%m%d'</span>)
+<span class="py-comment"># The current time is the name of the zip archive</span>
+now = <span class="py-builtin">time</span>.strftime(<span class="py-string">'%H%M%S'</span>)
+
+<span class="py-comment"># Take a comment from the user to create the name of the zip file</span>
+comment = <span class="py-builtin">raw_input</span>(<span class="py-string">'Enter a comment --&gt; '</span>)
+<span class="py-statement">if</span> <span class="py-builtin">len</span>(comment) == <span class="py-number">0</span>: <span class="py-comment"># check if a comment was entered</span>
+ target = today + <span class="py-builtin">os</span>.sep + now + <span class="py-string">'.zip'</span>
+<span class="py-statement">else</span>:
+ target = today + <span class="py-builtin">os</span>.sep + now + <span class="py-string">'_'</span> +
+ comment.replace(<span class="py-string">' '</span>, <span class="py-string">'_'</span>) + <span class="py-string">'.zip'</span>
+
+<span class="py-comment"># Create the subdirectory if it isn't already there</span>
+<span class="py-statement">if</span> <span class="py-statement">not</span> <span class="py-builtin">os</span>.path.exists(today):
+ <span class="py-builtin">os</span>.mkdir(today) <span class="py-comment"># make directory</span>
+ <span class="py-statement">print</span> <span class="py-string">'Successfully created directory'</span>, today
+
+<span class="py-comment"># 5. We use the zip command (in Unix/Linux) to put the files in a zip archive</span>
+zip_command = <span class="py-string">"zip -qr '%s' %s"</span> % (target, <span class="py-string">' '</span>.join(source))
+
+<span class="py-comment"># Run the backup</span>
+<span class="py-statement">if</span> <span class="py-builtin">os</span>.system(zip_command) == <span class="py-number">0</span>:
+ <span class="py-statement">print</span> <span class="py-string">'Successful backup to'</span>, target
+<span class="py-statement">else</span>:
+ <span class="py-statement">print</span> <span class="py-string">'Backup FAILED'</span>
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3069882"></a>Output</h4></div></div></div><pre class="screen">
+
+$ python backup_ver3.py
+File "backup_ver3.py", line 25
+target = today + os.sep + now + '_' +
+ ^
+SyntaxError: invalid syntax
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3069894"></a>How This (does not) Work</h4></div></div></div><p>
+
+ <span class="bold"><strong>This program does not work!</strong></span>.
+ Python says there is a syntax error which means that the script
+ does not satisfy the structure that Python expects to see.
+ When we observe the error given by Python, it also tells us the
+ place where it detected the error as well. So we start
+ <span class="emphasis"><em>debugging</em></span> our program from that line.
+
+ </p><p>
+
+ On careful observation, we see that the single logical line has
+ been split into two physical lines but we have not specified that
+ these two physical lines belong together. Basically, Python has
+ found the addition operator (<code class="literal">+</code>) without any
+ operand in that logical line and hence it doesn't know how to
+ continue. Remember that we can specify that the logical line continues
+ in the next physical line by the use of a backslash at the end of the
+ physical line. So, we make this correction to our program. This is
+ called <span class="bold"><strong>bug fixing</strong></span>.
+
+ </p></div></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="fourth-version"></a>Fourth Version</h3></div></div></div><div class="example"><a id="id3070006"></a><p class="title"><b>Example 10.4. Backup Script - The Fourth Version</b></p><pre class="programlisting">
+
+<span class="py-comment">#!/usr/bin/python</span>
+<span class="py-comment"># Filename: backup_ver2.py</span>
+
+<span class="py-statement">import</span> <span class="py-builtin">os</span>, <span class="py-builtin">time</span>
+
+<span class="py-comment"># 1. The files and directories to be backed up are specified in a list.</span>
+source = [<span class="py-string">'/home/swaroop/byte'</span>, <span class="py-string">'/home/swaroop/bin'</span>]
+<span class="py-comment"># If you are using Windows, use source = [r'C:\Documents', r'D:\Work'] or something like that</span>
+
+<span class="py-comment"># 2. The backup must be stored in a main backup directory</span>
+target_dir = <span class="py-string">'/mnt/e/backup/'</span> <span class="py-comment"># Remember to change this to what you will be using</span>
+
+<span class="py-comment"># 3. The files are backed up into a zip file.</span>
+<span class="py-comment"># 4. The current day is the name of the subdirectory in the main directory</span>
+today = target_dir + <span class="py-builtin">time</span>.strftime(<span class="py-string">'%Y%m%d'</span>)
+<span class="py-comment"># The current time is the name of the zip archive</span>
+now = <span class="py-builtin">time</span>.strftime(<span class="py-string">'%H%M%S'</span>)
+
+<span class="py-comment"># Take a comment from the user to create the name of the zip file</span>
+comment = <span class="py-builtin">raw_input</span>(<span class="py-string">'Enter a comment --&gt; '</span>)
+<span class="py-statement">if</span> <span class="py-builtin">len</span>(comment) == <span class="py-number">0</span>: <span class="py-comment"># check if a comment was entered</span>
+ target = today + <span class="py-builtin">os</span>.sep + now + <span class="py-string">'.zip'</span>
+<span class="py-statement">else</span>:
+ target = today + <span class="py-builtin">os</span>.sep + now + <span class="py-string">'_'</span> + \
+ comment.replace(<span class="py-string">' '</span>, <span class="py-string">'_'</span>) + <span class="py-string">'.zip'</span>
+ <span class="py-comment"># Notice the backslash!</span>
+
+<span class="py-comment"># Create the subdirectory if it isn't already there</span>
+<span class="py-statement">if</span> <span class="py-statement">not</span> <span class="py-builtin">os</span>.path.exists(today):
+ <span class="py-builtin">os</span>.mkdir(today) <span class="py-comment"># make directory</span>
+ <span class="py-statement">print</span> <span class="py-string">'Successfully created directory'</span>, today
+
+<span class="py-comment"># 5. We use the zip command (in Unix/Linux) to put the files in a zip archive</span>
+zip_command = <span class="py-string">"zip -qr '%s' %s"</span> % (target, <span class="py-string">' '</span>.join(source))
+
+<span class="py-comment"># Run the backup</span>
+<span class="py-statement">if</span> <span class="py-builtin">os</span>.system(zip_command) == <span class="py-number">0</span>:
+ <span class="py-statement">print</span> <span class="py-string">'Successful backup to'</span>, target
+<span class="py-statement">else</span>:
+ <span class="py-statement">print</span> <span class="py-string">'Backup FAILED'</span>
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3070018"></a>Output</h4></div></div></div><pre class="screen">
+
+$ python backup_ver4.py
+Enter a comment --&gt; added new examples
+Successful backup to /mnt/e/backup/20041208/082156_added_new_examples.zip
+
+$ python backup_ver4.py
+Enter a comment --&gt;
+Successful backup to /mnt/e/backup/20041208/082316.zip
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3070031"></a>How It Works</h4></div></div></div><p>
+
+ This program now works! Let us go through the actual enhancements that we
+ had made in version 3. We take in the user's comments using the
+ <code class="function">raw_input</code> function and then check if the user actually
+ entered something by finding out the length of the input using the
+ <code class="function">len</code> function. If the user has just pressed
+ <span><strong class="keycap">enter</strong></span> for some reason (maybe it was just a routine backup
+ or no special changes were made), then we proceed as we have done before.
+
+ </p><p>
+
+ However, if a comment was supplied, then this is attached to the name of
+ the zip archive just before the <code class="filename">.zip</code> extension.
+ Notice that we are replacing spaces in the comment with underscores - this
+ is because managing such filenames are much easier.
+
+ </p></div></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="more-refinements"></a>More Refinements</h3></div></div></div><p>
+
+ The fourth version is a satisfactorily working script for most users, but there is
+ always room for improvement. For example, you can include a
+ <span class="emphasis"><em>verbosity</em></span> level for the program where you can specify a
+ <code class="option">-v</code> option to make your program become more talkative.
+
+ </p><p>
+
+ Another possible enhancement would be to allow extra files and directories to be
+ passed to the script at the command line. We will get these from the
+ <code class="varname">sys.argv</code> list and we can add them to our
+ <code class="varname">source</code> list using the <code class="methodname">extend</code> method
+ provided by the <code class="classname">list</code> class.
+
+ </p><p>
+
+ One refinement I prefer is the use of the <span><strong class="command">tar</strong></span> command instead
+ of the <span><strong class="command">zip</strong></span> command. One advantage is that when you use the
+ <span><strong class="command">tar</strong></span> command along with <span><strong class="command">gzip</strong></span>, the backup is
+ much faster and the backup created is also much smaller. If I need to use this
+ archive in Windows, then <span class="application">WinZip</span> handles such
+ <code class="filename">.tar.gz</code> files easily as well. The <span><strong class="command">tar</strong></span>
+ command is available by default on most Linux/Unix systems. Windows users can
+ <a href="http://gnuwin32.sourceforge.net/packages/tar.htm" target="_top">download</a>
+ and install it as well.
+
+ </p><p>
+
+ The command string will now be:
+
+ </p><pre class="programlisting">
+
+tar = <span class="py-string">'tar -cvzf %s %s -X /home/swaroop/excludes.txt'</span> % (target, <span class="py-string">' '</span>.join(srcdir))
+
+ </pre><p>
+
+ The options are explained below.
+
+ </p><div class="itemizedlist"><ul type="disc"><li><p>
+
+ <code class="option">-c</code> indicates <span class="bold"><strong>c</strong></span>reation
+ of an archive.
+
+ </p></li><li><p>
+
+ <code class="option">-v</code> indicates <span class="bold"><strong>v</strong></span>erbose
+ i.e. the command should be more talkative.
+
+ </p></li><li><p>
+
+ <code class="option">-z</code> indicates the g<span class="bold"><strong>z</strong></span>ip
+ filter should be used.
+
+ </p></li><li><p>
+
+ <code class="option">-f</code> indicates <span class="bold"><strong>f</strong></span>orce
+ in creation of archive i.e. it should replace if there is a file
+ by the same name already.
+
+ </p></li><li><p>
+
+ <code class="option">-X</code> indicates a file which contains a list of filenames
+ which must be e<span class="bold"><strong>x</strong></span>cluded from the backup.
+ For example, you can specify <code class="literal">*~</code> in this file to not
+ include any filenames ending with <code class="literal">~</code> in the backup.
+
+ </p></li></ul></div><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Important</h3><p>
+
+ The most preferred way of creating such kind of archives would be using
+ the <code class="literal">zipfile</code> or <code class="literal">tarfile</code> module
+ respectively. They are part of the Python Standard Library and available
+ for you to use already. Using these libraries also avoids the use of the
+ <code class="function">os.system</code> which is generally not advisable to use
+ because it is very easy to make costly mistakes using it.
+
+ </p><p>
+
+ However, I have been using the <code class="function">os.system</code> way of
+ creating a backup purely for pedagogical purposes, so that the example
+ is simple enough to be understood by everybody but real enough to be
+ useful.
+
+ </p></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="problem-solving.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="problem-solving.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="software-development-process.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 10. Problem Solving - Writing a Python Script </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> The Software Development Process</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/try-except.html b/help/byteofpython/read/try-except.html
new file mode 100644
index 0000000..f1eb173
--- /dev/null
+++ b/help/byteofpython/read/try-except.html
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Try..Except</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="exceptions.html" title="Chapter 13. Exceptions" /><link rel="prev" href="exceptions.html" title="Chapter 13. Exceptions" /><link rel="next" href="raising-exceptions.html" title="Raising Exceptions" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Try..Except</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="exceptions.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 13. Exceptions</th><td width="20%" align="right"> <a accesskey="n" href="raising-exceptions.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="try-except"></a>Try..Except</h2></div></div></div><p>
+
+ We will <span class="bold"><strong>try</strong></span> to read input from the user. Press
+ <span><strong class="keycap">Ctrl</strong></span>-<span><strong class="keycap">d</strong></span> and see what happens.
+
+ </p><pre class="screen">
+
+&gt;&gt;&gt; s = raw_input('Enter something --&gt; ')
+Enter something --&gt; Traceback (most recent call last):
+ File "&lt;stdin&gt;", line 1, in ?
+EOFError
+
+ </pre><p>
+
+ Python raises an error called <code class="classname">EOFError</code> which basically means
+ it found an <span class="emphasis"><em>end of file</em></span> when it did not expect to (which is
+ represented by <span><strong class="keycap">Ctrl</strong></span>-<span><strong class="keycap">d</strong></span>)
+
+ </p><p>
+
+ Next, we will see how to handle such errors.
+
+ </p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="handling-exceptions"></a>Handling Exceptions</h3></div></div></div><p>
+
+ We can handle exceptions using the <code class="literal">try..except</code> statement.
+ We basically put our usual statements within the try-block and put all our
+ error handlers in the except-block.
+
+ </p><div class="example"><a id="id3075967"></a><p class="title"><b>Example 13.1. Handling Exceptions</b></p><pre class="programlisting">
+
+<span class="py-comment">#!/usr/bin/python</span>
+<span class="py-comment"># Filename: try_except.py</span>
+
+<span class="py-statement">import</span> <span class="py-builtin">sys</span>
+
+<span class="py-statement">try</span>:
+ s = <span class="py-builtin">raw_input</span>(<span class="py-string">'Enter something --&gt; '</span>)
+<span class="py-statement">except</span> EOFError:
+ <span class="py-statement">print</span> <span class="py-string">'\nWhy did you do an EOF on me?'</span>
+ <span class="py-builtin">sys</span>.exit() <span class="py-comment"># exit the program</span>
+<span class="py-statement">except</span>:
+ <span class="py-statement">print</span> <span class="py-string">'\nSome error/exception occurred.'</span>
+ <span class="py-comment"># here, we are not exiting the program</span>
+
+<span class="py-statement">print</span> <span class="py-string">'Done'</span>
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3075979"></a>Output</h4></div></div></div><pre class="screen">
+
+$ python try_except.py
+Enter something --&gt;
+Why did you do an EOF on me?
+
+$ python try_except.py
+Enter something --&gt; Python is exceptional!
+Done
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3076002"></a>How It Works</h4></div></div></div><p>
+
+ We put all the statements that might raise an error in the
+ <code class="literal">try</code> block and then handle all the errors and exceptions
+ in the <code class="literal">except</code> clause/block. The <code class="literal">except</code>
+ clause can handle a single specified error or exception, or a parenthesized
+ list of errors/exceptions. If no names of errors or exceptions are
+ supplied, it will handle <span class="emphasis"><em>all</em></span> errors and exceptions.
+ There has to be at least one <code class="literal">except</code> clause associated
+ with every <code class="literal">try</code> clause.
+
+ </p><p>
+
+ If any error or exception is not handled, then the default Python handler
+ is called which just stops the execution of the program and prints a
+ message. We have already seen this in action.
+
+ </p><p>
+
+ You can also have an <code class="literal">else</code> clause associated with a
+ <code class="literal">try..catch</code> block. The <code class="literal">else</code> clause
+ is executed if no exception occurs.
+
+ </p><p>
+
+ We can also get the exception object so that we can retrieve additional
+ information about the exception which has occurred. This is demonstrated
+ in the next example.
+
+ </p></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="exceptions.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="exceptions.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="raising-exceptions.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 13. Exceptions </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Raising Exceptions</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/try-finally.html b/help/byteofpython/read/try-finally.html
new file mode 100644
index 0000000..a578e95
--- /dev/null
+++ b/help/byteofpython/read/try-finally.html
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Try..Finally</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="exceptions.html" title="Chapter 13. Exceptions" /><link rel="prev" href="raising-exceptions.html" title="Raising Exceptions" /><link rel="next" href="exceptions-summary.html" title="Summary" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Try..Finally</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="raising-exceptions.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 13. Exceptions</th><td width="20%" align="right"> <a accesskey="n" href="exceptions-summary.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="try-finally"></a>Try..Finally</h2></div></div></div><p>
+
+ What if you were reading a file and you wanted to close the file whether or not an
+ exception was raised? This can be done using the <code class="literal">finally</code> block.
+ Note that you can use an <code class="literal">except</code> clause along with a
+ <code class="literal">finally</code> block for the same corresponding <code class="literal">try</code>
+ block. You will have to embed one within another if you want to use both.
+
+ </p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="using-try-finally"></a>Using Finally</h3></div></div></div><div class="example"><a id="id3076307"></a><p class="title"><b>Example 13.3. Using Finally</b></p><pre class="programlisting">
+
+<span class="py-comment">#!/usr/bin/python</span>
+<span class="py-comment"># Filename: finally.py</span>
+
+<span class="py-statement">import</span> <span class="py-builtin">time</span>
+
+<span class="py-statement">try</span>:
+ f = <span class="py-builtin">file</span>(<span class="py-string">'poem.txt'</span>)
+ <span class="py-statement">while</span> <span class="py-builtin">True</span>: <span class="py-comment"># our usual file-reading idiom</span>
+ line = f.readline()
+ <span class="py-statement">if</span> <span class="py-builtin">len</span>(line) == <span class="py-number">0</span>:
+ <span class="py-statement">break</span>
+ <span class="py-builtin">time</span>.sleep(<span class="py-number">2</span>)
+ <span class="py-statement">print</span> line,
+<span class="py-statement">finally</span>:
+ f.close()
+ <span class="py-statement">print</span> <span class="py-string">'Cleaning up...closed the file'</span>
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3076320"></a>Output</h4></div></div></div><pre class="screen">
+
+$ python finally.py
+Programming is fun
+When the work is done
+Cleaning up...closed the file
+Traceback (most recent call last):
+ File "finally.py", line 12, in ?
+ time.sleep(2)
+KeyboardInterrupt
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3076341"></a>How It Works</h4></div></div></div><p>
+
+ We do the usual file-reading stuff, but I've arbitrarily introduced a way
+ of sleeping for 2 seconds before printing each line using the
+ <code class="function">time.sleep</code> method. The only reason is so that the
+ program runs slowly (Python is very fast by nature). When the program is
+ still running, press <span><strong class="keycap">Ctrl</strong></span>-<span><strong class="keycap">c</strong></span>
+ to interrupt/cancel the program.
+
+ </p><p>
+
+ Observe that a <code class="classname">KeyboardInterrupt</code> exception is thrown
+ and the program exits, but before the program exits, the finally clause is
+ executed and the file is closed.
+
+ </p></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="raising-exceptions.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="exceptions.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="exceptions-summary.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Raising Exceptions </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Summary</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/tuple.html b/help/byteofpython/read/tuple.html
new file mode 100644
index 0000000..5e5587f
--- /dev/null
+++ b/help/byteofpython/read/tuple.html
@@ -0,0 +1,150 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Tuple</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="data-structures.html" title="Chapter 9. Data Structures" /><link rel="prev" href="list.html" title="List" /><link rel="next" href="dictionary.html" title="Dictionary" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Tuple</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="list.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 9. Data Structures</th><td width="20%" align="right"> <a accesskey="n" href="dictionary.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="tuple"></a>Tuple</h2></div></div></div><p>
+
+ Tuples are just like lists except that they are <span class="bold"><strong>immutable</strong></span>
+ like strings i.e. you cannot modify tuples. Tuples are defined by specifying items
+ separated by commas within a pair of parentheses. Tuples are usually used in cases where
+ a statement or a user-defined function can safely assume that the collection of values
+ i.e. the tuple of values used will not change.
+
+ </p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="id3066333"></a>Using Tuples</h3></div></div></div><div class="example"><a id="id3066339"></a><p class="title"><b>Example 9.2. Using Tuples</b></p><pre class="programlisting">
+
+<span class="py-comment">#!/usr/bin/python</span>
+<span class="py-comment"># Filename: using_tuple.py</span>
+
+zoo = (<span class="py-string">'wolf'</span>, <span class="py-string">'elephant'</span>, <span class="py-string">'penguin'</span>)
+<span class="py-statement">print</span> <span class="py-string">'Number of animals in the zoo is'</span>, <span class="py-builtin">len</span>(zoo)
+
+new_zoo = (<span class="py-string">'monkey'</span>, <span class="py-string">'dolphin'</span>, zoo)
+<span class="py-statement">print</span> <span class="py-string">'Number of animals in the new zoo is'</span>, <span class="py-builtin">len</span>(new_zoo)
+<span class="py-statement">print</span> <span class="py-string">'All animals in new zoo are'</span>, new_zoo
+<span class="py-statement">print</span> <span class="py-string">'Animals brought from old zoo are'</span>, new_zoo[<span class="py-number">2</span>]
+<span class="py-statement">print</span> <span class="py-string">'Last animal brought from old zoo is'</span>, new_zoo[<span class="py-number">2</span>][<span class="py-number">2</span>]
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3066351"></a>Output</h4></div></div></div><pre class="screen">
+
+$ python using_tuple.py
+Number of animals in the zoo is 3
+Number of animals in the new zoo is 3
+All animals in new zoo are ('monkey', 'dolphin', ('wolf', 'elephant', 'penguin'))
+Animals brought from old zoo are ('wolf', 'elephant', 'penguin')
+Last animal brought from old zoo is penguin
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3066377"></a>How It Works</h4></div></div></div><p>
+
+ The variable <code class="varname">zoo</code> refers to a tuple of items. We see
+ that the <code class="function">len</code> function can be used to get the length
+ of the tuple. This also indicates that a tuple is a
+ <a href="sequences.html" title="Sequences">sequence</a> as well.
+
+ </p><p>
+
+ We are now shifting these animals to a new zoo since the old zoo is being
+ closed. Therefore, the <code class="varname">new_zoo</code> tuple contains some
+ animals which are already there along with the animals brought over from
+ the old zoo. Back to reality, note that a tuple within a tuple does not
+ lose its identity.
+
+ </p><p>
+
+ We can access the items in the tuple by specifying the item's position
+ within a pair of square brackets just like we did for lists. This is
+ called the <span class="emphasis"><em>indexing</em></span> operator. We access the third
+ item in <code class="varname">new_zoo</code> by specifying
+ <code class="literal">new_zoo[2]</code> and we access the third item in the third
+ item in the <code class="varname">new_zoo</code> tuple by specifying
+ <code class="literal">new_zoo[2][2]</code>. This is pretty simple once you've
+ understood the idiom.
+
+ </p><p><b>Tuple with 0 or 1 items. </b>
+
+ An empty tuple is constructed by an empty pair of parentheses
+ such as <code class="literal">myempty = ()</code>. However, a tuple with
+ a single item is not so simple. You have to specify it using a
+ comma following the first (and only) item so that Python can
+ differentiate between a tuple and a pair of parentheses surrounding
+ the object in an expression i.e. you have to specify
+ <code class="literal">singleton = (2 , )</code> if you mean you want a tuple
+ containing the item <code class="literal">2</code>.
+
+ </p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note for Perl programmers</h3><p>
+
+ A list within a list does not lose its identity i.e. lists are not
+ flattened as in Perl. The same applies to a tuple within a tuple,
+ or a tuple within a list, or a list within a tuple, etc. As far as
+ Python is concerned, they are just objects stored using another
+ object, that's all.
+
+ </p></div></div></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="tuple-print"></a>Tuples and the print statement</h3></div></div></div><p>
+
+ One of the most common usage of tuples is with the print statement. Here is an
+ example:
+
+ </p><div class="example"><a id="id3066528"></a><p class="title"><b>Example 9.3. Output using tuples</b></p><pre class="programlisting">
+
+<span class="py-comment">#!/usr/bin/python</span>
+<span class="py-comment"># Filename: print_tuple.py</span>
+
+age = <span class="py-number">22</span>
+name = <span class="py-string">'Swaroop'</span>
+
+<span class="py-statement">print</span> <span class="py-string">'%s is %d years old'</span> % (name, age)
+<span class="py-statement">print</span> <span class="py-string">'Why is %s playing with that python?'</span> % name
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3066540"></a>Output</h4></div></div></div><pre class="screen">
+
+$ python print_tuple.py
+Swaroop is 22 years old
+Why is Swaroop playing with that python?
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3066563"></a>How It Works</h4></div></div></div><p>
+
+ The <code class="literal">print</code> statement can take a string using certain
+ specifications followed by the <code class="literal">%</code> symbol followed by
+ a tuple of items matching the specification. The specifications are used
+ to format the output in a certain way. The specification can be like
+ <code class="literal">%s</code> for strings and <code class="literal">%d</code> for integers.
+ The tuple must have items corresponding to these specifications in the same
+ order.
+
+ </p><p>
+
+ Observe the first usage where we use <code class="literal">%s</code> first and this
+ corresponds to the variable <code class="varname">name</code> which is the first
+ item in the tuple and the second specification is <code class="literal">%d</code>
+ corresponding to <code class="varname">age</code> which is the second item in the
+ tuple.
+
+ </p><p>
+
+ What Python does here is that it converts each item in the tuple into a
+ string and substitutes that string value into the place of the
+ specification. Therefore the <code class="literal">%s</code> is replaced by the
+ value of the variable <code class="varname">name</code> and so on.
+
+ </p><p>
+
+ This usage of the <code class="literal">print</code> statement makes writing
+ output extremely easy and avoids lot of string manipulation to achieve
+ the same. It also avoids using commas everywhere as we have done till now.
+
+ </p><p>
+
+ Most of the time, you can just use the <code class="literal">%s</code> specification
+ and let Python take care of the rest for you. This works even for numbers.
+ However, you may want to give the correct specifications since this adds
+ one level of checking that your program is correct.
+
+ </p><p>
+
+ In the second <code class="literal">print</code> statement, we are using a single
+ specification followed by the <code class="literal">%</code> symbol followed by a
+ single item - there are no pair of parentheses. This works only in the case
+ where there is a single specification in the string.
+
+ </p></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="list.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="data-structures.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="dictionary.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">List </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Dictionary</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/tuples-lists-functions.html b/help/byteofpython/read/tuples-lists-functions.html
new file mode 100644
index 0000000..c9fe2eb
--- /dev/null
+++ b/help/byteofpython/read/tuples-lists-functions.html
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Receiving Tuples and Lists in Functions</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="more-python.html" title="Chapter 15. More Python" /><link rel="prev" href="list-comprehension.html" title="List Comprehension" /><link rel="next" href="lambda-forms.html" title="Lambda Forms" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Receiving Tuples and Lists in Functions</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="list-comprehension.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 15. More Python</th><td width="20%" align="right"> <a accesskey="n" href="lambda-forms.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="tuples-lists-functions"></a>Receiving Tuples and Lists in Functions</h2></div></div></div><p>
+
+ There is a special way of receiving parameters to a function as a tuple or a dictionary
+ using the <code class="literal">*</code> or <code class="literal">**</code> prefix respectively. This is
+ useful when taking variable number of arguments in the function.
+
+ </p><pre class="screen">
+
+&gt;&gt;&gt; def powersum(power, *args):
+... '''Return the sum of each argument raised to specified power.'''
+... total = 0
+... for i in args:
+... total += pow(i, power)
+... return total
+...
+&gt;&gt;&gt; powersum(2, 3, 4)
+25
+
+&gt;&gt;&gt; powersum(2, 10)
+100
+
+ </pre><p>
+
+ Due to the <code class="literal">*</code> prefix on the <code class="varname">args</code> variable, all
+ extra arguments passed to the function are stored in <code class="varname">args</code> as a tuple.
+ If a <code class="literal">**</code> prefix had been used instead, the extra parameters would be
+ considered to be key/value pairs of a dictionary.
+
+ </p></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="list-comprehension.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="more-python.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="lambda-forms.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">List Comprehension </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Lambda Forms</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/variables.html b/help/byteofpython/read/variables.html
new file mode 100644
index 0000000..3b1d010
--- /dev/null
+++ b/help/byteofpython/read/variables.html
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Variables</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="basics.html" title="Chapter 4. The Basics" /><link rel="prev" href="strings.html" title="Strings" /><link rel="next" href="identifier.html" title="Identifier Naming" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Variables</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="strings.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 4. The Basics</th><td width="20%" align="right"> <a accesskey="n" href="identifier.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="variables"></a>Variables</h2></div></div></div><p>
+
+ Using just literal constants can soon become boring - we need some way of storing any
+ information and manipulate them as well. This is where <span class="emphasis"><em>variables</em></span>
+ come into the picture. Variables are exactly what they mean - their value can vary i.e.
+ you can store anything using a variable. Variables are just parts of your computer's
+ memory where you store some information. Unlike literal constants, you need some method
+ of accessing these variables and hence you give them names.
+
+ </p></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="strings.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="basics.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="identifier.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Strings </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Identifier Naming</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/what-next-summary.html b/help/byteofpython/read/what-next-summary.html
new file mode 100644
index 0000000..1f65738
--- /dev/null
+++ b/help/byteofpython/read/what-next-summary.html
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Summary</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="what-next.html" title="Chapter 16. What Next?" /><link rel="prev" href="explore-more.html" title="Explore More" /><link rel="next" href="floss.html" title="Appendix A. Free/Libré and Open Source Software (FLOSS)" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Summary</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="explore-more.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 16. What Next?</th><td width="20%" align="right"> <a accesskey="n" href="floss.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="what-next-summary"></a>Summary</h2></div></div></div><p>
+
+ We have now come to the end of this book but, as they say, this is the
+ <span class="emphasis"><em>the beginning of the end</em></span>!. You are now an avid Python user and you
+ are no doubt ready to solve many problems using Python. You can start automating your
+ computer to do all kinds of previously unimaginable things or write your own games
+ and much much more. So, get started!
+
+ </p></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="explore-more.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="what-next.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="floss.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Explore More </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Appendix A. Free/Libré and Open Source Software (FLOSS)</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/what-next.html b/help/byteofpython/read/what-next.html
new file mode 100644
index 0000000..d583b8c
--- /dev/null
+++ b/help/byteofpython/read/what-next.html
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Chapter 16. What Next?</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="index.html" title="A Byte of Python" /><link rel="prev" href="more-python-summary.html" title="Summary" /><link rel="next" href="explore-more.html" title="Explore More" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 16. What Next?</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="more-python-summary.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="explore-more.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="chapter" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title"><a id="what-next"></a>Chapter 16. What Next?</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="what-next.html#graphical-software">Graphical Software</a></span></dt><dd><dl><dt><span class="section"><a href="what-next.html#id3080050">Summary of GUI Tools</a></span></dt></dl></dd><dt><span class="section"><a href="explore-more.html">Explore More</a></span></dt><dt><span class="section"><a href="what-next-summary.html">Summary</a></span></dt></dl></div><p>
+
+ If you have read this book thoroughly till now and practiced writing a lot of programs, then you
+ must have become comfortable and familiar with Python. You have probably created some Python
+ programs to try out stuff and to exercise your Python skills as well. If you have not done it
+ already, you should. The question now is 'What Next?'.
+
+ </p><p>
+
+ I would suggest that you tackle this problem: create your own command-line
+ <span class="emphasis"><em>address-book</em></span> program using which you can add, modify, delete or search for
+ your contacts such as friends, family and colleagues and their information such as email address
+ and/or phone number. Details must be stored for later retrieval.
+
+ </p><p>
+
+ This is fairly easy if you think about it in terms of all the various stuff that we have come
+ across till now. If you still want directions on how to proceed, then here's a hint.
+
+ </p><p><b>Hint. (You shouldn't be reading this). </b>
+
+ Create a class to represent the person's information. Use a dictionary to store person
+ objects with their name as the key. Use the cPickle module to store the objects
+ persistently on your hard disk. Use the dictionary built-in methods to add, delete and
+ modify the persons.
+
+ </p><p>
+
+ Once you are able to do this, you can claim to be a Python programmer. Now, immediately send me
+ a mail thanking me for this great book ;-) . This step is optional but recommended.
+
+ </p><p>
+
+ Here are some ways to continue your journey with Python:
+
+ </p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="graphical-software"></a>Graphical Software</h2></div></div></div><p>
+
+ <span class="bold"><strong>GUI</strong></span> Libraries using Python - you need these to create
+ your own graphical programs using Python. You can create your own IrfanView or
+ Kuickshow or anything like that using the GUI libraries with their Python bindings.
+ Bindings are what allow you to write programs in Python and use the libraries which are
+ themselves written in C or C++ or other languages.
+
+ </p><p>
+
+ There are lots of choices for GUI using Python:
+
+ </p><div class="itemizedlist"><ul type="disc"><li><p><b>PyQt. </b>
+
+ This is the Python binding for the Qt toolkit which is the foundation
+ upon which the KDE is built. Qt is extremely easy to use and very
+ powerful especially due to the Qt Designer and the amazing Qt
+ documentation. You can use it for free on Linux but you will have to
+ pay for it if you want to use it on Windows. PyQt is free if you want
+ to create free (GPL'ed) software on Linux/Unix and paid if you want to
+ create proprietary software. A good resource on PyQt is
+ <a href="http://www.opendocs.org/pyqt/" target="_top">'GUI Programming with
+ Python: Qt Edition'</a>. See the
+ <a href="http://www.riverbankcomputing.co.uk/pyqt/index.php" target="_top">official homepage</a> for more details.
+
+ </p></li><li><p><b>PyGTK. </b>
+
+ This is the Python binding for the GTK+ toolkit which is the
+ foundation upon which GNOME is built. GTK+ has many quirks in usage
+ but once you become comfortable, you can create GUI apps fast. The
+ Glade graphical interface designer is indispensable. The documentation
+ is yet to improve. GTK+ works well on Linux but its port to Windows
+ is incomplete. You can create both free as well as proprietary software
+ using GTK+. See the <a href="http://www.pygtk.org/" target="_top">official
+ homepage</a> for more details.
+
+ </p></li><li><p><b>wxPython. </b>
+
+ This is the Python bindings for the wxWidgets toolkit. wxPython has
+ a learning curve associated with it. However, it is very portable
+ and runs on Linux, Windows, Mac and even embedded platforms. There
+ are many IDEs available for wxPython which include GUI designers as
+ well such as <a href="http://spe.pycs.net/" target="_top">SPE (Stani's Python
+ Editor)</a> and the
+ <a href="http://wxglade.sourceforge.net/" target="_top">wxGlade</a> GUI
+ builder. You can create free as well as proprietary software using
+ wxPython. See the <a href="http://www.wxpython.org/" target="_top">official
+ homepage</a> for more details.
+
+ </p></li><li><p><b>TkInter. </b>
+
+ This is one of the oldest GUI toolkits in existence. If you have used
+ <span class="application">IDLE</span>, you have seen a TkInter program at
+ work. The documentation for TkInter at <a href="http://www.pythonware.com/library/tkinter/introduction/index.htm" target="_top">PythonWare.org</a> is comprehensive. TkInter is portable and works
+ on both Linux/Unix as well as Windows. Importantly, TkInter is part of
+ the standard Python distribution.
+
+ </p></li><li><p>
+
+ For more choices, see the <a href="http://www.python.org/cgi-bin/moinmoin/GuiProgramming" target="_top">GuiProgramming wiki page at Python.org</a>
+
+ </p></li></ul></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="id3080050"></a>Summary of GUI Tools</h3></div></div></div><p>
+
+ Unfortunately, there is no one standard GUI tool for Python. I suggest that you
+ choose one of the above tools depending on your situation. The first factor is
+ whether you are willing to pay to use any of the GUI tools. The second factor
+ is whether you want the program to run on Linux or Windows or both. The third
+ factor is whether you are a KDE or GNOME user on Linux.
+
+ </p><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Future Chapters</h3><p>
+
+ I am contemplating writing 1 or 2 chapters for this book on GUI Programming.
+ I will be probably be choosing wxPython as the choice of toolkit. If you would
+ like to present your views on the subject, please join the
+ <a href="http://lists.ibiblio.org/mailman/listinfo/byte-of-python" target="_top">byte-of-python mailing list</a> where readers discuss with me on what
+ improvements can be made to the book.
+
+ </p></div></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="more-python-summary.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="explore-more.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Summary </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Explore More</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/what-programmers-say.html b/help/byteofpython/read/what-programmers-say.html
new file mode 100644
index 0000000..3aa6667
--- /dev/null
+++ b/help/byteofpython/read/what-programmers-say.html
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>What Programmers Say</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="introduction.html" title="Chapter 1. Introduction" /><link rel="prev" href="why-not-perl.html" title="Why not Perl?" /><link rel="next" href="installing-python.html" title="Chapter 2. Installing Python" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">What Programmers Say</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="why-not-perl.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 1. Introduction</th><td width="20%" align="right"> <a accesskey="n" href="installing-python.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="what-programmers-say"></a>What Programmers Say</h2></div></div></div><p>
+
+ You may find it interesting to read what great hackers like ESR have to say about Python:
+
+ </p><div class="itemizedlist"><ul type="disc"><li><p>
+
+ <span class="bold"><strong>Eric S. Raymond</strong></span> is the author of
+ 'The Cathedral and the Bazaar' and is also the person who coined the term
+ 'Open Source'. He says that <a href="http://www.linuxjournal.com/article.php?sid=3882" target="_top">Python has become
+ his favorite programming language</a>. This article was the real
+ inspiration for my first brush with Python.
+
+ </p></li><li><p>
+
+ <span class="bold"><strong>Bruce Eckel</strong></span> is the author of the
+ famous 'Thinking in Java' and 'Thinking in C++' books. He says that no
+ language has made him more productive than Python. He says that Python
+ is perhaps the only language that focuses on making things easier for
+ the programmer. Read the <a href="http://www.artima.com/intv/aboutme.html" target="_top">complete interview</a>
+ for more details.
+
+ </p></li><li><p>
+
+ <span class="bold"><strong>Peter Norvig</strong></span> is a well-known Lisp
+ author and Director of Search Quality at Google (thanks to Guido van
+ Rossum for pointing that out). He says that Python has always been an
+ integral part of Google. You can actually verify this statement by
+ looking at the <a href="http://www.google.com/jobs/index.html" target="_top">Google Jobs</a> page which lists Python knowledge as a requirement
+ for software engineers.
+
+ </p></li><li><p>
+
+ <span class="bold"><strong>Bruce Perens</strong></span> is a co-founder of
+ OpenSource.org and the UserLinux project. UserLinux aims to create a
+ standardized Linux distribution supported by multiple vendors. Python
+ has beaten contenders like Perl and Ruby to become the main programming
+ language that will be supported by UserLinux.
+
+ </p></li></ul></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="why-not-perl.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="introduction.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="installing-python.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Why not Perl? </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> Chapter 2. Installing Python</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/while-statement.html b/help/byteofpython/read/while-statement.html
new file mode 100644
index 0000000..6249cac
--- /dev/null
+++ b/help/byteofpython/read/while-statement.html
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>The while statement</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="control-flow.html" title="Chapter 6. Control Flow" /><link rel="prev" href="if-statement.html" title="The if statement" /><link rel="next" href="for-loop.html" title="The for loop" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">The while statement</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="if-statement.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 6. Control Flow</th><td width="20%" align="right"> <a accesskey="n" href="for-loop.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="while-statement"></a>The while statement</h2></div></div></div><p>
+
+ The <code class="literal">while</code> statement allows you to repeatedly execute a block of
+ statements as long as a condition is true. A <code class="literal">while</code> statement is an
+ example of what is called a <span class="emphasis"><em>looping</em></span> statement. A
+ <code class="literal">while</code> statement can have an optional <code class="literal">else</code> clause.
+
+ </p><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="id3058859"></a>Using the while statement</h3></div></div></div><div class="example"><a id="using-while-statement"></a><p class="title"><b>Example 6.2. Using the while statement</b></p><pre class="programlisting">
+
+<span class="py-comment">#!/usr/bin/python</span>
+<span class="py-comment"># Filename: while.py</span>
+
+number = <span class="py-number">23</span>
+running = <span class="py-builtin">True</span>
+
+<span class="py-statement">while</span> running:
+ guess = <span class="py-builtin">int</span>(<span class="py-builtin">raw_input</span>(<span class="py-string">'Enter an integer : '</span>))
+
+ <span class="py-statement">if</span> guess == number:
+ <span class="py-statement">print</span> <span class="py-string">'Congratulations, you guessed it.'</span>
+ running = <span class="py-builtin">False</span> <span class="py-comment"># this causes the while loop to stop</span>
+ <span class="py-statement">elif</span> guess &lt; number:
+ <span class="py-statement">print</span> <span class="py-string">'No, it is a little higher than that.'</span>
+ <span class="py-statement">else</span>:
+ <span class="py-statement">print</span> <span class="py-string">'No, it is a little lower than that.'</span>
+<span class="py-statement">else</span>:
+ <span class="py-statement">print</span> <span class="py-string">'The while loop is over.'</span>
+ <span class="py-comment"># Do anything else you want to do here</span>
+
+<span class="py-statement">print</span> <span class="py-string">'Done'</span>
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3058882"></a>Output</h4></div></div></div><pre class="screen">
+
+$ python while.py
+Enter an integer : 50
+No, it is a little lower than that.
+Enter an integer : 22
+No, it is a little higher than that.
+Enter an integer : 23
+Congratulations, you guessed it.
+The while loop is over.
+Done
+
+ </pre></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h4 class="title"><a id="id3058910"></a>How It Works</h4></div></div></div><p>
+
+ In this program, we are still playing the guessing game, but the advantage
+ is that the user is allowed to keep guessing until he guesses correctly -
+ there is no need to repeatedly execute the program for each guess as we
+ have done previously. This aptly demonstrates the use of the
+ <code class="literal">while</code> statement.
+
+ </p><p>
+
+ We move the <code class="literal">raw_input</code> and <code class="literal">if</code>
+ statements to inside the <code class="literal">while</code> loop and set the
+ variable <code class="varname">running</code> to <code class="literal">True</code> before
+ the while loop. First, we check if the variable <code class="varname">running</code>
+ is <code class="literal">True</code> and then proceed to execute the corresponding
+ <span class="emphasis"><em>while-block</em></span>. After this block is executed, the
+ condition is again checked which in this case is the <code class="varname">running</code>
+ variable. If it is true, we execute the while-block again, else we continue
+ to execute the optional else-block and then continue to the next statement.
+
+ </p><p>
+
+ The <code class="literal">else</code> block is executed when the <code class="literal">while</code>
+ loop condition becomes <code class="literal">False</code> - this may even be the first
+ time that the condition is checked. If there is an <code class="literal">else</code>
+ clause for a <code class="literal">while</code> loop, it is always executed unless you
+ have a <code class="literal">while</code> loop which loops forever without ever breaking
+ out!
+
+ </p><p>
+
+ The <code class="literal">True</code> and <code class="literal">False</code> are called Boolean
+ types and you can consider them to be equivalent to the value
+ <code class="literal">1</code> and <code class="literal">0</code> respecitvely. It's important
+ to use these where the condition or checking is important and not the actual
+ value such as <code class="literal">1</code>.
+
+ </p><p>
+
+ The else-block is actually redundant since you can put those statements
+ in the same block (as the <code class="literal">while</code> statement) after the
+ <code class="literal">while</code> statement to get the same effect.
+
+ </p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note for C/C++ Programmers</h3><p>
+
+ Remember that you can have an <code class="literal">else</code> clause for
+ the <code class="literal">while</code> loop.
+
+ </p></div></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="if-statement.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="control-flow.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="for-loop.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">The if statement </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> The for loop</td></tr></table></div></body></html>
diff --git a/help/byteofpython/read/why-not-perl.html b/help/byteofpython/read/why-not-perl.html
new file mode 100644
index 0000000..4a49f73
--- /dev/null
+++ b/help/byteofpython/read/why-not-perl.html
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Why not Perl?</title><link rel="stylesheet" href="byte.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.67.2" /><link rel="start" href="index.html" title="A Byte of Python" /><link rel="up" href="introduction.html" title="Chapter 1. Introduction" /><link rel="prev" href="features-of-python.html" title="Features of Python" /><link rel="next" href="what-programmers-say.html" title="What Programmers Say" /></head><body>
+<div class="header">
+<strong><a href="http://www.byteofpython.info/" class="header-link">A Byte of Python</a></strong>
+</div>
+<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Why not Perl?</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="features-of-python.html"><img src="images/prev.gif" alt="Prev" /></a> </td><th width="60%" align="center">Chapter 1. Introduction</th><td width="20%" align="right"> <a accesskey="n" href="what-programmers-say.html"><img src="images/next.gif" alt="Next" /></a></td></tr></table><hr /></div><div class="section" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="why-not-perl"></a>Why not Perl?</h2></div></div></div><p>
+
+ If you didn't know already, Perl is another extremely popular open source interpreted
+ programming language.
+
+ </p><p>
+
+ If you have ever tried writing a large program in Perl, you would have answered this
+ question yourself! In other words, Perl programs are easy when they are small and it
+ excels at small hacks and scripts to 'get work done'. However, they quickly become
+ unwieldy once you start writing bigger programs and I am speaking this out of
+ experience of writing large Perl programs at Yahoo!
+
+ </p><p>
+
+ When compared to Perl, Python programs are definitely simpler, clearer, easier to
+ write and hence more understandable and maintainable. I do admire Perl and I do use
+ it on a daily basis for various things but whenever I write a program, I always start
+ thinking in terms of Python because it has become so natural for me. Perl has undergone
+ so many hacks and changes, that it feels like it is one big (but one hell of a) hack.
+ Sadly, the upcoming Perl 6 does not seem to be making any improvements regarding this.
+
+ </p><p>
+
+ The only and very significant advantage that I feel Perl has, is its huge
+ <a href="http://cpan.perl.org" target="_top">CPAN</a> library - the Comprehensive Perl Archive
+ Network. As the name suggests, this is a humongous collection of Perl modules and it is
+ simply mind-boggling because of its sheer size and depth - you can do virtually anything
+ you can do with a computer using these modules. One of the reasons that Perl has more
+ libraries than Python is that it has been around for a much longer time than Python.
+ Maybe I should suggest a port-Perl-modules-to-Python hackathon on
+ <a href="http://groups.google.com/groups?q=comp.lang.python" target="_top">comp.lang.python</a> :)
+
+ </p><p>
+
+ Also, the new <a href="http://www.parrotcode.org" target="_top">Parrot virtual machine</a> is
+ designed to run both the completely redesigned Perl 6 as well as Python and other interpreted
+ languages like Ruby, PHP and Tcl. What this means to you is that <span class="emphasis"><em>maybe</em></span>
+ you will be able to use all Perl modules from Python in the future, so that will give you
+ the best of both worlds - the powerful CPAN library combined with the powerful Python
+ language. However, we will have to just wait and see what happens.
+
+ </p></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="features-of-python.html"><img src="images/prev.gif" alt="Prev" /></a> </td><td width="20%" align="center"><a accesskey="u" href="introduction.html"><img src="images/up.gif" alt="Up" /></a></td><td width="40%" align="right"> <a accesskey="n" href="what-programmers-say.html"><img src="images/next.gif" alt="Next" /></a></td></tr><tr><td width="40%" align="left" valign="top">Features of Python </td><td width="20%" align="center"><a accesskey="h" href="index.html"><img src="images/home.gif" alt="Home" /></a></td><td width="40%" align="right" valign="top"> What Programmers Say</td></tr></table></div></body></html>
diff --git a/help/diveintopython-5.4/html/appendix/about.html b/help/diveintopython-5.4/html/appendix/about.html
new file mode 100644
index 0000000..ffbf3c1
--- /dev/null
+++ b/help/diveintopython-5.4/html/appendix/about.html
@@ -0,0 +1,68 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>Appendix&nbsp;F.&nbsp;About the book</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="../toc/index.html" title="Dive Into Python">
+ <link rel="previous" href="history.html" title="Appendix&nbsp;E.&nbsp;Revision history">
+ <link rel="next" href="fdl.html" title="Appendix&nbsp;G.&nbsp;GNU Free Documentation License">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<span class="thispage">About the book</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="history.html" title="Prev: &#8220;Revision history&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="fdl.html" title="Next: &#8220;GNU Free Documentation License&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="appendix" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="about"></a>Appendix&nbsp;F.&nbsp;About the book
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p>This book was written in <a href="http://www.oasis-open.org/docbook/" title="DocBook home page"><span class="application">DocBook</span> <span class="acronym">XML</span></a> using <a href="http://www.gnu.org/software/emacs/" title="The One True Editor"><span class="application">Emacs</span></a>, and converted to <span class="acronym">HTML</span> using <a href="http://saxon.sourceforge.net/" title="SAXON home page">the <span class="application"><span class="acronym">SAXON</span></span> <span class="acronym">XSLT</span> processor from Michael Kay</a> with a customized version of <a href="http://www.nwalsh.com/xsl/" title="DocBook XSL home page">Norman Walsh's <span class="acronym">XSL</span> stylesheets</a>. From there, it was converted to <span class="acronym">PDF</span> using <a href="http://www.easysw.com/htmldoc/" title="HTMLDOC home page"><span class="application">HTMLDoc</span></a>, and to plain text using <a href="http://ei5nazha.yz.yamagata-u.ac.jp/~aito/w3m/eng/" title="w3m home page"><span class="application">w3m</span></a>. Program listings and examples were colorized using an updated version of Just van Rossum's <tt class="filename">pyfontify.py</tt>, which is included in the example scripts.
+ </p>
+ <p>If you're interested in learning more about <span class="application">DocBook</span> for technical writing, you can <a href="http://diveintopython.org/download/diveintopython-xml-5.4.zip" title="Download XML source files">download the <span class="acronym">XML</span> source</a> and the <a href="http://diveintopython.org/download/diveintopython-common-5.4.zip" title="Download build scripts and auxiliary files">build scripts</a>, which include the customized <span class="acronym">XSL</span> stylesheets used to create all the different formats of the book. You should also read the canonical book, <a href="http://www.docbook.org/" title="Read DocBook: TDG online"><i class="citetitle"><span class="application">DocBook</span>: The Definitive Guide</i></a>. If you're going to do any serious writing in <span class="application">DocBook</span>, I would recommend subscribing to the <a href="http://lists.oasis-open.org/archives/" title="Subscribe to DocBook and/or DocBook-Apps"><span class="application">DocBook</span> mailing lists</a>.
+ </p>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="history.html">&lt;&lt;&nbsp;Revision history</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="fdl.html">GNU Free Documentation License&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/appendix/abstracts.html b/help/diveintopython-5.4/html/appendix/abstracts.html
new file mode 100644
index 0000000..886e2da
--- /dev/null
+++ b/help/diveintopython-5.4/html/appendix/abstracts.html
@@ -0,0 +1,1163 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>Appendix&nbsp;B.&nbsp;A 5-minute review</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="../toc/index.html" title="Dive Into Python">
+ <link rel="previous" href="furtherreading.html" title="Appendix&nbsp;A.&nbsp;Further reading">
+ <link rel="next" href="tips.html" title="Appendix&nbsp;C.&nbsp;Tips and tricks">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<span class="thispage">A 5-minute review</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="furtherreading.html" title="Prev: &#8220;Further reading&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="tips.html" title="Next: &#8220;Tips and tricks&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="appendix" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="abstracts"></a>Appendix&nbsp;B.&nbsp;A 5-minute review
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p><a href="../installing_python/index.html">Chapter&nbsp;1.&nbsp;Installing Python</a></p>
+ <ul>
+ <li><a href="../installing_python/index.html#install.choosing">1.1.&nbsp;Which Python is right for you?</a><blockquote>
+ <div class="abstract">
+ <p>The first thing you need to do with <span class="application">Python</span> is install it. Or do you?
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../installing_python/windows.html">1.2.&nbsp;Python on Windows</a><blockquote>
+ <div class="abstract">
+ <p>On Windows, you have a couple choices for installing <span class="application">Python</span>.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../installing_python/macosx.html">1.3.&nbsp;Python on Mac OS X</a><blockquote>
+ <div class="abstract">
+ <p>On <span class="abbrev">Mac</span> <span class="acronym">OS</span> X, you have two choices for installing <span class="application">Python</span>: install it, or don't install it. You probably want to install it.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../installing_python/macos9.html">1.4.&nbsp;Python on Mac OS 9</a><blockquote>
+ <div class="abstract">
+ <p><span class="abbrev">Mac</span> <span class="acronym">OS</span> 9 does not come with any version of <span class="application">Python</span>, but installation is very simple, and there is only one choice.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../installing_python/redhat.html">1.5.&nbsp;Python on RedHat Linux</a><blockquote>
+ <div class="abstract">
+ <p>Download the latest <span class="application">Python</span> <span class="acronym">RPM</span> by going to <a href="http://www.python.org/ftp/python/">http://www.python.org/ftp/python/</a> and selecting the highest version number listed, then selecting the <tt class="filename">rpms/</tt> directory within that. Then download the <span class="acronym">RPM</span> with the highest version number. You can install it with the <span><b class="command">rpm</b></span> command, as shown here:
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../installing_python/debian.html">1.6.&nbsp;Python on Debian GNU/Linux</a><blockquote>
+ <div class="abstract">
+ <p>If you are lucky enough to be running Debian <span class="acronym">GNU</span>/Linux, you install <span class="application">Python</span> through the <span><b class="command">apt</b></span> command.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../installing_python/source.html">1.7.&nbsp;Python Installation from Source</a><blockquote>
+ <div class="abstract">
+ <p>If you prefer to build from source, you can download the <span class="application">Python</span> source code from <a href="http://www.python.org/ftp/python/">http://www.python.org/ftp/python/</a>. Select the highest version number listed, download the <tt class="filename">.tgz</tt> file), and then do the usual <b class="userinput"><tt>configure</tt></b>, <b class="userinput"><tt>make</tt></b>, <b class="userinput"><tt>make install</tt></b> dance.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../installing_python/shell.html">1.8.&nbsp;The Interactive Shell</a><blockquote>
+ <div class="abstract">
+ <p>Now that you have <span class="application">Python</span> installed, what's this interactive shell thing you're running?
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../installing_python/summary.html">1.9.&nbsp;Summary</a><blockquote>
+ <div class="abstract">
+ <p>You should now have a version of <span class="application">Python</span> installed that works for you.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ </ul>
+ <p><a href="../getting_to_know_python/index.html">Chapter&nbsp;2.&nbsp;Your First Python Program</a></p>
+ <ul>
+ <li><a href="../getting_to_know_python/index.html#odbchelper.divein">2.1.&nbsp;Diving in</a><blockquote>
+ <div class="abstract">
+ <p>Here is a complete, working <span class="application">Python</span> program.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../getting_to_know_python/declaring_functions.html">2.2.&nbsp;Declaring Functions</a><blockquote>
+ <div class="abstract">
+ <p><span class="application">Python</span> has functions like most other languages, but it does not have separate header files like <span class="application"><span class="acronym">C++</span></span> or <tt class="literal">interface</tt>/<tt class="literal">implementation</tt> sections like <span class="application">Pascal</span>. When you need a function, just declare it, like this:
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../getting_to_know_python/documenting_functions.html">2.3.&nbsp;Documenting Functions</a><blockquote>
+ <div class="abstract">
+ <p>You can document a <span class="application">Python</span> function by giving it a <tt class="literal">doc string</tt>.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../getting_to_know_python/everything_is_an_object.html">2.4.&nbsp;Everything Is an Object</a><blockquote>
+ <div class="abstract">
+ <p>A function, like everything else in <span class="application">Python</span>, is an object.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../getting_to_know_python/indenting_code.html">2.5.&nbsp;Indenting Code</a><blockquote>
+ <div class="abstract">
+ <p><span class="application">Python</span> functions have no explicit <tt class="literal">begin</tt> or <tt class="literal">end</tt>, and no curly braces to mark where the function code starts and stops. The only delimiter is a colon (<tt class="literal">:</tt>) and the indentation of the code itself.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../getting_to_know_python/testing_modules.html">2.6.&nbsp;Testing Modules</a><blockquote>
+ <div class="abstract">
+ <p><span class="application">Python</span> modules are objects and have several useful attributes. You can use this to easily test your modules as you write them.
+ Here's an example that uses the <tt class="literal">if</tt> <tt class="literal">__name__</tt> trick.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ </ul>
+ <p><a href="../native_data_types/index.html">Chapter&nbsp;3.&nbsp;Native Datatypes</a></p>
+ <ul>
+ <li><a href="../native_data_types/index.html#odbchelper.dict">3.1.&nbsp;Introducing Dictionaries</a><blockquote>
+ <div class="abstract">
+ <p>One of <span class="application">Python</span>'s built-in datatypes is the dictionary, which defines one-to-one relationships between keys and values.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../native_data_types/lists.html">3.2.&nbsp;Introducing Lists</a><blockquote>
+ <div class="abstract">
+ <p>Lists are <span class="application">Python</span>'s workhorse datatype. If your only experience with lists is arrays in <span class="application">Visual Basic</span> or (God forbid) the datastore in <span class="application">Powerbuilder</span>, brace yourself for <span class="application">Python</span> lists.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../native_data_types/tuples.html">3.3.&nbsp;Introducing Tuples</a><blockquote>
+ <div class="abstract">
+ <p>A tuple is an immutable list. A tuple can not be changed in any way once it is created.</p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../native_data_types/declaring_variables.html">3.4.&nbsp;Declaring variables</a><blockquote>
+ <div class="abstract">
+ <p><span class="application">Python</span> has local and global variables like most other languages, but it has no explicit variable declarations. Variables spring
+ into existence by being assigned a value, and they are automatically destroyed when they go out of scope.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../native_data_types/formatting_strings.html">3.5.&nbsp;Formatting Strings</a><blockquote>
+ <div class="abstract">
+ <p><span class="application">Python</span> supports formatting values into strings. Although this can include very complicated expressions, the most basic usage is
+ to insert values into a string with the <tt class="literal">%s</tt> placeholder.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../native_data_types/mapping_lists.html">3.6.&nbsp;Mapping Lists</a><blockquote>
+ <div class="abstract">
+ <p>One of the most powerful features of <span class="application">Python</span> is the list comprehension, which provides a compact way of mapping a list into another list by applying a function to each
+ of the elements of the list.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../native_data_types/joining_lists.html">3.7.&nbsp;Joining Lists and Splitting Strings</a><blockquote>
+ <div class="abstract">
+ <p>You have a list of key-value pairs in the form <tt class="literal"><i class="replaceable">key</i>=<i class="replaceable">value</i></tt>, and you want to join them into a single string. To join any list of strings into a single string, use the <tt class="function">join</tt> method of a string object.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../native_data_types/summary.html">3.8.&nbsp;Summary</a><blockquote>
+ <div class="abstract">
+ <p>The <tt class="filename">odbchelper.py</tt> program and its output should now make perfect sense.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ </ul>
+ <p><a href="../power_of_introspection/index.html">Chapter&nbsp;4.&nbsp;The Power Of Introspection</a></p>
+ <ul>
+ <li><a href="../power_of_introspection/index.html#apihelper.divein">4.1.&nbsp;Diving In</a><blockquote>
+ <div class="abstract">
+ <p>Here is a complete, working <span class="application">Python</span> program. You should understand a good deal about it just by looking at it. The numbered lines illustrate concepts covered
+ in <a href="../getting_to_know_python/index.html" title="Chapter&nbsp;2.&nbsp;Your First Python Program">Chapter&nbsp;2, <i>Your First Python Program</i></a>. Don't worry if the rest of the code looks intimidating; you'll learn all about it throughout this chapter.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../power_of_introspection/optional_arguments.html">4.2.&nbsp;Using Optional and Named Arguments</a><blockquote>
+ <div class="abstract">
+ <p><span class="application">Python</span> allows function arguments to have default values; if the function is called without the argument, the argument gets its default
+ value. Futhermore, arguments can be specified in any order by using named arguments. Stored procedures in <span class="application">SQL Server</span> Transact/<span class="acronym">SQL</span> can do this, so if you're a <span class="application">SQL Server</span> scripting guru, you can skim this part.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../power_of_introspection/built_in_functions.html">4.3.&nbsp;Using type, str, dir, and Other Built-In Functions</a><blockquote>
+ <div class="abstract">
+ <p><span class="application">Python</span> has a small set of extremely useful built-in functions. All other functions are partitioned off into modules. This was
+ actually a conscious design decision, to keep the core language from getting bloated like other scripting languages (cough
+ cough, <span class="application">Visual Basic</span>).
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../power_of_introspection/getattr.html">4.4.&nbsp;Getting Object References With getattr</a><blockquote>
+ <div class="abstract">
+ <p>You already know that <a href="../getting_to_know_python/everything_is_an_object.html" title="2.4.&nbsp;Everything Is an Object"><span class="application">Python</span> functions are objects</a>. What you don't know is that you can get a reference to a function without knowing its name until run-time, by using the
+ <tt class="function">getattr</tt> function.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../power_of_introspection/filtering_lists.html">4.5.&nbsp;Filtering Lists</a><blockquote>
+ <div class="abstract">
+ <p>As you know, <span class="application">Python</span> has powerful capabilities for mapping lists into other lists, via list comprehensions (<a href="../native_data_types/mapping_lists.html" title="3.6.&nbsp;Mapping Lists">Section&nbsp;3.6, &#8220;Mapping Lists&#8221;</a>). This can be combined with a filtering mechanism, where some elements in the list are mapped while others are skipped entirely.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../power_of_introspection/and_or.html">4.6.&nbsp;The Peculiar Nature of and and or</a><blockquote>
+ <div class="abstract">
+ <p>In <span class="application">Python</span>, <tt class="literal">and</tt> and <tt class="literal">or</tt> perform boolean logic as you would expect, but they do not return boolean values; instead, they return one of the actual
+ values they are comparing.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../power_of_introspection/lambda_functions.html">4.7.&nbsp;Using lambda Functions</a><blockquote>
+ <div class="abstract">
+ <p><span class="application">Python</span> supports an interesting syntax that lets you define one-line mini-functions on the fly. Borrowed from <span class="application">Lisp</span>, these so-called <tt class="literal">lambda</tt> functions can be used anywhere a function is required.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../power_of_introspection/all_together.html">4.8.&nbsp;Putting It All Together</a><blockquote>
+ <div class="abstract">
+ <p>The last line of code, the only one you haven't deconstructed yet, is the one that does all the work. But by now the work
+ is easy, because everything you need is already set up just the way you need it. All the dominoes are in place; it's time
+ to knock them down.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../power_of_introspection/summary.html">4.9.&nbsp;Summary</a><blockquote>
+ <div class="abstract">
+ <p>The <tt class="filename">apihelper.py</tt> program and its output should now make perfect sense.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ </ul>
+ <p><a href="../object_oriented_framework/index.html">Chapter&nbsp;5.&nbsp;Objects and Object-Orientation</a></p>
+ <ul>
+ <li><a href="../object_oriented_framework/index.html#fileinfo.divein">5.1.&nbsp;Diving In</a><blockquote>
+ <div class="abstract">
+ <p>Here is a complete, working <span class="application">Python</span> program. Read the <a href="../getting_to_know_python/documenting_functions.html" title="2.3.&nbsp;Documenting Functions"><tt class="literal">doc string</tt>s</a> of the module, the classes, and the functions to get an overview of what this program does and how it works. As usual, don't
+ worry about the stuff you don't understand; that's what the rest of the chapter is for.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../object_oriented_framework/importing_modules.html">5.2.&nbsp;Importing Modules Using from module import</a><blockquote>
+ <div class="abstract">
+ <p><span class="application">Python</span> has two ways of importing modules. Both are useful, and you should know when to use each. One way, <tt class="literal">import <i class="replaceable">module</i></tt>, you've already seen in <a href="../getting_to_know_python/everything_is_an_object.html" title="2.4.&nbsp;Everything Is an Object">Section&nbsp;2.4, &#8220;Everything Is an Object&#8221;</a>. The other way accomplishes the same thing, but it has subtle and important differences.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../object_oriented_framework/defining_classes.html">5.3.&nbsp;Defining Classes</a><blockquote>
+ <div class="abstract">
+ <p><span class="application">Python</span> is fully object-oriented: you can define your own classes, inherit from your own or built-in classes, and instantiate the
+ classes you've defined.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../object_oriented_framework/instantiating_classes.html">5.4.&nbsp;Instantiating Classes</a><blockquote>
+ <div class="abstract">
+ <p>Instantiating classes in <span class="application">Python</span> is straightforward. To instantiate a class, simply call the class as if it were a function, passing the arguments that the
+ <tt class="function">__init__</tt> method defines. The return value will be the newly created object.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../object_oriented_framework/userdict.html">5.5.&nbsp;Exploring UserDict: A Wrapper Class</a><blockquote>
+ <div class="abstract">
+ <p>As you've seen, <tt class="classname">FileInfo</tt> is a class that acts like a dictionary. To explore this further, let's look at the <tt class="classname">UserDict</tt> class in the <tt class="filename">UserDict</tt> module, which is the ancestor of the <tt class="classname">FileInfo</tt> class. This is nothing special; the class is written in <span class="application">Python</span> and stored in a <tt class="literal">.py</tt> file, just like any other <span class="application">Python</span> code. In particular, it's stored in the <tt class="filename">lib</tt> directory in your <span class="application">Python</span> installation.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../object_oriented_framework/special_class_methods.html">5.6.&nbsp;Special Class Methods</a><blockquote>
+ <div class="abstract">
+ <p>In addition to normal class methods, there are a number of special methods that <span class="application">Python</span> classes can define. Instead of being called directly by your code (like normal methods), special methods are called for
+ you by <span class="application">Python</span> in particular circumstances or when specific syntax is used.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../object_oriented_framework/special_class_methods2.html">5.7.&nbsp;Advanced Special Class Methods</a><blockquote>
+ <div class="abstract">
+ <p><span class="application">Python</span> has more special methods than just <tt class="function">__getitem__</tt> and <tt class="function">__setitem__</tt>. Some of them let you emulate functionality that you may not even know about.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../object_oriented_framework/class_attributes.html">5.8.&nbsp;Introducing Class Attributes</a><blockquote>
+ <div class="abstract">
+ <p>You already know about <a href="userdict.html#fileinfo.userdict.init.example" title="Example&nbsp;5.9.&nbsp;Defining the UserDict Class">data attributes</a>, which are variables owned by a specific instance of a class. <span class="application">Python</span> also supports class attributes, which are variables owned by the class itself.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../object_oriented_framework/private_functions.html">5.9.&nbsp;Private Functions</a><blockquote>
+ <div class="abstract">
+ <p>Unlike in most languages, whether a <span class="application">Python</span> function, method, or attribute is private or public is determined entirely by its name.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../object_oriented_framework/summary.html">5.10.&nbsp;Summary</a><blockquote>
+ <div class="abstract">
+ <p>That's it for the hard-core object trickery. You'll see a real-world application of special class methods in <a href="../soap_web_services/index.html">Chapter 12</a>, which uses <tt class="function">getattr</tt> to create a proxy to a remote web service.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ </ul>
+ <p><a href="../file_handling/index.html">Chapter&nbsp;6.&nbsp;Exceptions and File Handling</a></p>
+ <ul>
+ <li><a href="../file_handling/index.html#fileinfo.exception">6.1.&nbsp;Handling Exceptions</a><blockquote>
+ <div class="abstract">
+ <p>Like many other programming languages, <span class="application">Python</span> has exception handling via <tt class="literal">try...except</tt> blocks.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../file_handling/file_objects.html">6.2.&nbsp;Working with File Objects</a><blockquote>
+ <div class="abstract">
+ <p><span class="application">Python</span> has a built-in function, <tt class="function">open</tt>, for opening a file on disk. <tt class="function">open</tt> returns a file object, which has methods and attributes for getting information about and manipulating the opened file.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../file_handling/for_loops.html">6.3.&nbsp;Iterating with for Loops</a><blockquote>
+ <div class="abstract">
+ <p>Like most other languages, <span class="application">Python</span> has <tt class="literal">for</tt> loops. The only reason you haven't seen them until now is that <span class="application">Python</span> is good at so many other things that you don't need them as often.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../file_handling/more_on_modules.html">6.4.&nbsp;Using sys.modules</a><blockquote>
+ <div class="abstract">
+ <p>Modules, like everything else in <span class="application">Python</span>, are objects. Once imported, you can always get a reference to a module through the global dictionary <tt class="literal"><tt class="filename">sys</tt>.modules</tt>.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../file_handling/os_module.html">6.5.&nbsp;Working with Directories</a><blockquote>
+ <div class="abstract">
+ <p>The <tt class="filename">os.path</tt> module has several functions for manipulating files and directories. Here, we're looking at handling pathnames and listing
+ the contents of a directory.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../file_handling/all_together.html">6.6.&nbsp;Putting It All Together</a><blockquote>
+ <div class="abstract">
+ <p>Once again, all the dominoes are in place. You've seen how each line of code works. Now let's step back and see how it all
+ fits together.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../file_handling/summary.html">6.7.&nbsp;Summary</a><blockquote>
+ <div class="abstract">
+ <p>The <tt class="filename">fileinfo.py</tt> program introduced in <a href="../object_oriented_framework/index.html">Chapter 5</a> should now make perfect sense.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ </ul>
+ <p><a href="../regular_expressions/index.html">Chapter&nbsp;7.&nbsp;Regular Expressions</a></p>
+ <ul>
+ <li><a href="../regular_expressions/index.html#re.intro">7.1.&nbsp;Diving In</a><blockquote>
+ <div class="abstract">
+ <p>If what you're trying to do can be accomplished with string functions, you should use them. They're fast and simple and easy
+ to read, and there's a lot to be said for fast, simple, readable code. But if you find yourself using a lot of different
+ string functions with <tt class="literal">if</tt> statements to handle special cases, or if you're combining them with <tt class="function">split</tt> and <tt class="function">join</tt> and list comprehensions in weird unreadable ways, you may need to move up to regular expressions.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../regular_expressions/street_addresses.html">7.2.&nbsp;Case Study: Street Addresses</a><blockquote>
+ <div class="abstract">
+ <p>This series of examples was inspired by a real-life problem I had in my day job several years ago, when I needed to scrub
+ and standardize street addresses exported from a legacy system before importing them into a newer system. (See, I don't just
+ make this stuff up; it's actually useful.) This example shows how I approached the problem.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../regular_expressions/roman_numerals.html">7.3.&nbsp;Case Study: Roman Numerals</a><blockquote>
+ <div class="abstract">
+ <p>You've most likely seen Roman numerals, even if you didn't recognize them. You may have seen them in copyrights of old movies
+ and television shows (&#8220;<span class="quote">Copyright <tt class="literal">MCMXLVI</tt></span>&#8221; instead of &#8220;<span class="quote">Copyright <tt class="literal">1946</tt></span>&#8221;), or on the dedication walls of libraries or universities (&#8220;<span class="quote">established <tt class="literal">MDCCCLXXXVIII</tt></span>&#8221; instead of &#8220;<span class="quote">established <tt class="literal">1888</tt></span>&#8221;). You may also have seen them in outlines and bibliographical references. It's a system of representing numbers that really
+ does date back to the ancient Roman empire (hence the name).
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../regular_expressions/n_m_syntax.html">7.4.&nbsp;Using the {n,m} Syntax</a><blockquote>
+ <div class="abstract">
+ <p>In <a href="roman_numerals.html" title="7.3.&nbsp;Case Study: Roman Numerals">the previous section</a>, you were dealing with a pattern where the same character could be repeated up to three times. There is another way to express
+ this in regular expressions, which some people find more readable. First look at the method we already used in the previous
+ example.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../regular_expressions/verbose.html">7.5.&nbsp;Verbose Regular Expressions</a><blockquote>
+ <div class="abstract">
+ <p>So far you've just been dealing with what I'll call &#8220;<span class="quote">compact</span>&#8221; regular expressions. As you've seen, they are difficult to read, and even if you figure out what one does, that's no guarantee
+ that you'll be able to understand it six months later. What you really need is inline documentation.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../regular_expressions/phone_numbers.html">7.6.&nbsp;Case study: Parsing Phone Numbers</a><blockquote>
+ <div class="abstract">
+ <p>So far you've concentrated on matching whole patterns. Either the pattern matches, or it doesn't. But regular expressions
+ are much more powerful than that. When a regular expression <span class="emphasis"><em>does</em></span> match, you can pick out specific pieces of it. You can find out what matched where.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../regular_expressions/summary.html">7.7.&nbsp;Summary</a><blockquote>
+ <div class="abstract">
+ <p>This is just the tiniest tip of the iceberg of what regular expressions can do. In other words, even though you're completely
+ overwhelmed by them now, believe me, you ain't seen nothing yet.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ </ul>
+ <p><a href="../html_processing/index.html">Chapter&nbsp;8.&nbsp;HTML Processing</a></p>
+ <ul>
+ <li><a href="../html_processing/index.html#dialect.divein">8.1.&nbsp;Diving in</a><blockquote>
+ <div class="abstract">
+ <p>I often see questions on <a href="http://groups.google.com/groups?group=comp.lang.python">comp.lang.python</a> like &#8220;<span class="quote">How can I list all the [headers|images|links] in my <span class="acronym">HTML</span> document?</span>&#8221; &#8220;<span class="quote">How do I parse/translate/munge the text of my <span class="acronym">HTML</span> document but leave the tags alone?</span>&#8221; &#8220;<span class="quote">How can I add/remove/quote attributes of all my <span class="acronym">HTML</span> tags at once?</span>&#8221; This chapter will answer all of these questions.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../html_processing/introducing_sgmllib.html">8.2.&nbsp;Introducing sgmllib.py</a><blockquote>
+ <div class="abstract">
+ <p><span class="acronym">HTML</span> processing is broken into three steps: breaking down the <span class="acronym">HTML</span> into its constituent pieces, fiddling with the pieces, and reconstructing the pieces into <span class="acronym">HTML</span> again. The first step is done by <tt class="filename">sgmllib.py</tt>, a part of the standard <span class="application">Python</span> library.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../html_processing/extracting_data.html">8.3.&nbsp;Extracting data from HTML documents</a><blockquote>
+ <div class="abstract">
+ <p>To extract data from <span class="acronym">HTML</span> documents, subclass the <tt class="classname">SGMLParser</tt> class and define methods for each tag or entity you want to capture.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../html_processing/basehtmlprocessor.html">8.4.&nbsp;Introducing BaseHTMLProcessor.py</a><blockquote>
+ <div class="abstract">
+ <p><tt class="classname">SGMLParser</tt> doesn't produce anything by itself. It parses and parses and parses, and it calls a method for each interesting thing it
+ finds, but the methods don't do anything. <tt class="classname">SGMLParser</tt> is an <span class="acronym">HTML</span> <span class="emphasis"><em>consumer</em></span>: it takes <span class="acronym">HTML</span> and breaks it down into small, structured pieces. As you saw in the <a href="extracting_data.html" title="8.3.&nbsp;Extracting data from HTML documents">previous section</a>, you can subclass <tt class="classname">SGMLParser</tt> to define classes that catch specific tags and produce useful things, like a list of all the links on a web page. Now you'll
+ take this one step further by defining a class that catches everything <tt class="classname">SGMLParser</tt> throws at it and reconstructs the complete <span class="acronym">HTML</span> document. In technical terms, this class will be an <span class="acronym">HTML</span> <span class="emphasis"><em>producer</em></span>.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../html_processing/locals_and_globals.html">8.5.&nbsp;locals and globals</a><blockquote>
+ <div class="abstract">
+ <p>Let's digress from <span class="acronym">HTML</span> processing for a minute and talk about how <span class="application">Python</span> handles variables. <span class="application">Python</span> has two built-in functions, <tt class="function">locals</tt> and <tt class="function">globals</tt>, which provide dictionary-based access to local and global variables.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../html_processing/dictionary_based_string_formatting.html">8.6.&nbsp;Dictionary-based string formatting</a><blockquote>
+ <div class="abstract">
+ <p>There is an alternative form of string formatting that uses dictionaries instead of tuples of values.</p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../html_processing/quoting_attribute_values.html">8.7.&nbsp;Quoting attribute values</a><blockquote>
+ <div class="abstract">
+ <p>A common question on <a href="http://groups.google.com/groups?group=comp.lang.python">comp.lang.python</a> is &#8220;<span class="quote">I have a bunch of <span class="acronym">HTML</span> documents with unquoted attribute values, and I want to properly quote them all. How can I do this?</span>&#8221;<sup>[<a name="d0e21764" href="#ftn.d0e21764">4</a>]</sup> (This is generally precipitated by a project manager who has found the <span class="acronym">HTML</span>-is-a-standard religion joining a large project and proclaiming that all pages must validate against an <span class="acronym">HTML</span> validator. Unquoted attribute values are a common violation of the <span class="acronym">HTML</span> standard.) Whatever the reason, unquoted attribute values are easy to fix by feeding <span class="acronym">HTML</span> through <tt class="classname">BaseHTMLProcessor</tt>.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../html_processing/dialect.html">8.8.&nbsp;Introducing dialect.py</a><blockquote>
+ <div class="abstract">
+ <p><tt class="classname">Dialectizer</tt> is a simple (and silly) descendant of <tt class="classname">BaseHTMLProcessor</tt>. It runs blocks of text through a series of substitutions, but it makes sure that anything within a <tt class="literal"><tt class="sgmltag-element">&lt;pre&gt;</tt>...<tt class="sgmltag-element">&lt;/pre&gt;</tt></tt> block passes through unaltered.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../html_processing/all_together.html">8.9.&nbsp;Putting it all together</a><blockquote>
+ <div class="abstract">
+ <p>It's time to put everything you've learned so far to good use. I hope you were paying attention.</p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../html_processing/summary.html">8.10.&nbsp;Summary</a><blockquote>
+ <div class="abstract">
+ <p><span class="application">Python</span> provides you with a powerful tool, <tt class="filename">sgmllib.py</tt>, to manipulate <span class="acronym">HTML</span> by turning its structure into an object model. You can use this tool in many different ways.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ </ul>
+ <p><a href="../xml_processing/index.html">Chapter&nbsp;9.&nbsp;XML Processing</a></p>
+ <ul>
+ <li><a href="../xml_processing/index.html#kgp.divein">9.1.&nbsp;Diving in</a><blockquote>
+ <div class="abstract">
+ <p>There are two basic ways to work with <span class="acronym">XML</span>. One is called <span class="acronym">SAX</span> (&#8220;<span class="quote">Simple <span class="acronym">API</span> for <span class="acronym">XML</span></span>&#8221;), and it works by reading the <span class="acronym">XML</span> a little bit at a time and calling a method for each element it finds. (If you read <a href="../html_processing/index.html" title="Chapter&nbsp;8.&nbsp;HTML Processing">Chapter&nbsp;8, <i>HTML Processing</i></a>, this should sound familiar, because that's how the <tt class="filename">sgmllib</tt> module works.) The other is called <span class="acronym">DOM</span> (&#8220;<span class="quote">Document Object Model</span>&#8221;), and it works by reading in the entire <span class="acronym">XML</span> document at once and creating an internal representation of it using native <span class="application">Python</span> classes linked in a tree structure. <span class="application">Python</span> has standard modules for both kinds of parsing, but this chapter will only deal with using the <span class="acronym">DOM</span>.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../xml_processing/packages.html">9.2.&nbsp;Packages</a><blockquote>
+ <div class="abstract">
+ <p>Actually parsing an <span class="acronym">XML</span> document is very simple: one line of code. However, before you get to that line of code, you need to take a short detour
+ to talk about packages.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../xml_processing/parsing_xml.html">9.3.&nbsp;Parsing XML</a><blockquote>
+ <div class="abstract">
+ <p>As I was saying, actually parsing an <span class="acronym">XML</span> document is very simple: one line of code. Where you go from there is up to you.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../xml_processing/unicode.html">9.4.&nbsp;Unicode</a><blockquote>
+ <div class="abstract">
+ <p>Unicode is a system to represent characters from all the world's different languages. When <span class="application">Python</span> parses an <span class="acronym">XML</span> document, all data is stored in memory as unicode.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../xml_processing/searching.html">9.5.&nbsp;Searching for elements</a><blockquote>
+ <div class="abstract">
+ <p>Traversing <span class="acronym">XML</span> documents by stepping through each node can be tedious. If you're looking for something in particular, buried deep within
+ your <span class="acronym">XML</span> document, there is a shortcut you can use to find it quickly: <tt class="function">getElementsByTagName</tt>.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../xml_processing/attributes.html">9.6.&nbsp;Accessing element attributes</a><blockquote>
+ <div class="abstract">
+ <p><span class="acronym">XML</span> elements can have one or more attributes, and it is incredibly simple to access them once you have parsed an <span class="acronym">XML</span> document.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../xml_processing/summary.html">9.7.&nbsp;Segue</a><blockquote>
+ <div class="abstract">
+ <p>OK, that's it for the hard-core XML stuff. The next chapter will continue to use these same example programs, but focus on
+ other aspects that make the program more flexible: using streams for input processing, using <tt class="function">getattr</tt> for method dispatching, and using command-line flags to allow users to reconfigure the program without changing the code.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ </ul>
+ <p><a href="../scripts_and_streams/index.html">Chapter&nbsp;10.&nbsp;Scripts and Streams</a></p>
+ <ul>
+ <li><a href="../scripts_and_streams/index.html#kgp.openanything">10.1.&nbsp;Abstracting input sources</a><blockquote>
+ <div class="abstract">
+ <p>One of <span class="application">Python</span>'s greatest strengths is its dynamic binding, and one powerful use of dynamic binding is the <span class="emphasis"><em>file-like object</em></span>.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../scripts_and_streams/stdin_stdout_stderr.html">10.2.&nbsp;Standard input, output, and error</a><blockquote>
+ <div class="abstract">
+ <p><span class="acronym">UNIX</span> users are already familiar with the concept of standard input, standard output, and standard error. This section is for
+ the rest of you.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../scripts_and_streams/caching.html">10.3.&nbsp;Caching node lookups</a><blockquote>
+ <div class="abstract">
+ <p><tt class="filename">kgp.py</tt> employs several tricks which may or may not be useful to you in your <span class="acronym">XML</span> processing. The first one takes advantage of the consistent structure of the input documents to build a cache of nodes.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../scripts_and_streams/child_nodes.html">10.4.&nbsp;Finding direct children of a node</a><blockquote>
+ <div class="abstract">
+ <p>Another useful techique when parsing <span class="acronym">XML</span> documents is finding all the direct child elements of a particular element. For instance, in the grammar files, a <tt class="sgmltag-element">ref</tt> element can have several <tt class="sgmltag-element">p</tt> elements, each of which can contain many things, including other <tt class="sgmltag-element">p</tt> elements. You want to find just the <tt class="sgmltag-element">p</tt> elements that are children of the <tt class="sgmltag-element">ref</tt>, not <tt class="sgmltag-element">p</tt> elements that are children of other <tt class="sgmltag-element">p</tt> elements.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../scripts_and_streams/handlers_by_node_type.html">10.5.&nbsp;Creating separate handlers by node type</a><blockquote>
+ <div class="abstract">
+ <p>The third useful <span class="acronym">XML</span> processing tip involves separating your code into logical functions, based on node types and element names. Parsed <span class="acronym">XML</span> documents are made up of various types of nodes, each represented by a <span class="application">Python</span> object. The root level of the document itself is represented by a <tt class="classname">Document</tt> object. The <tt class="classname">Document</tt> then contains one or more <tt class="classname">Element</tt> objects (for actual <span class="acronym">XML</span> tags), each of which may contain other <tt class="classname">Element</tt> objects, <tt class="classname">Text</tt> objects (for bits of text), or <tt class="classname">Comment</tt> objects (for embedded comments). <span class="application">Python</span> makes it easy to write a dispatcher to separate the logic for each node type.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../scripts_and_streams/command_line_arguments.html">10.6.&nbsp;Handling command-line arguments</a><blockquote>
+ <div class="abstract">
+ <p><span class="application">Python</span> fully supports creating programs that can be run on the command line, complete with command-line arguments and either short-
+ or long-style flags to specify various options. None of this is <span class="acronym">XML</span>-specific, but this script makes good use of command-line processing, so it seemed like a good time to mention it.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../scripts_and_streams/all_together.html">10.7.&nbsp;Putting it all together</a><blockquote>
+ <div class="abstract">
+ <p>You've covered a lot of ground. Let's step back and see how all the pieces fit together.</p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../scripts_and_streams/summary.html">10.8.&nbsp;Summary</a><blockquote>
+ <div class="abstract">
+ <p><span class="application">Python</span> comes with powerful libraries for parsing and manipulating <span class="acronym">XML</span> documents. The <tt class="filename">minidom</tt> takes an <span class="acronym">XML</span> file and parses it into <span class="application">Python</span> objects, providing for random access to arbitrary elements. Furthermore, this chapter shows how <span class="application">Python</span> can be used to create a "real" standalone command-line script, complete with command-line flags, command-line arguments,
+ error handling, even the ability to take input from the piped result of a previous program.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ </ul>
+ <p><a href="../http_web_services/index.html">Chapter&nbsp;11.&nbsp;HTTP Web Services</a></p>
+ <ul>
+ <li><a href="../http_web_services/index.html#oa.divein">11.1.&nbsp;Diving in</a><blockquote>
+ <div class="abstract">
+ <p>You've learned about <a href="../html_processing/index.html" title="Chapter&nbsp;8.&nbsp;HTML Processing">HTML processing</a> and <a href="../xml_processing/index.html" title="Chapter&nbsp;9.&nbsp;XML Processing">XML processing</a>, and along the way you saw <a href="../html_processing/extracting_data.html#dialect.extract.urllib" title="Example&nbsp;8.5.&nbsp;Introducing urllib">how to download a web page</a> and <a href="../scripts_and_streams/index.html#kgp.openanything.urllib" title="Example&nbsp;10.2.&nbsp;Parsing XML from a URL">how to parse XML from a URL</a>, but let's dive into the more general topic of HTTP web services.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../http_web_services/review.html">11.2.&nbsp;How not to fetch data over HTTP</a><blockquote>
+ <div class="abstract">
+ <p>Let's say you want to download a resource over HTTP, such as a syndicated Atom feed. But you don't just want to download
+ it once; you want to download it over and over again, every hour, to get the latest news from the site that's offering the
+ news feed. Let's do it the quick-and-dirty way first, and then see how you can do better.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../http_web_services/http_features.html">11.3.&nbsp;Features of HTTP</a><blockquote>
+ <div class="abstract">
+ <p>There are five important features of HTTP which you should support.</p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../http_web_services/debugging.html">11.4.&nbsp;Debugging HTTP web services</a><blockquote>
+ <div class="abstract">
+ <p>First, let's turn on the debugging features of <span class="application">Python</span>'s HTTP library and see what's being sent over the wire. This will be useful throughout the chapter, as you add more and
+ more features.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../http_web_services/user_agent.html">11.5.&nbsp;Setting the User-Agent</a><blockquote>
+ <div class="abstract">
+ <p>The first step to improving your HTTP web services client is to identify yourself properly with a <tt class="literal">User-Agent</tt>. To do that, you need to move beyond the basic <tt class="filename">urllib</tt> and dive into <tt class="filename">urllib2</tt>.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../http_web_services/etags.html">11.6.&nbsp;Handling Last-Modified and ETag</a><blockquote>
+ <div class="abstract">
+ <p>Now that you know how to add custom HTTP headers to your web service requests, let's look at adding support for <tt class="literal">Last-Modified</tt> and <tt class="literal">ETag</tt> headers.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../http_web_services/redirects.html">11.7.&nbsp;Handling redirects</a><blockquote>
+ <div class="abstract">
+ <p>You can support permanent and temporary redirects using a different kind of custom URL handler.</p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../http_web_services/gzip_compression.html">11.8.&nbsp;Handling compressed data</a><blockquote>
+ <div class="abstract">
+ <p>The last important HTTP feature you want to support is compression. Many web services have the ability to send data compressed,
+ which can cut down the amount of data sent over the wire by 60% or more. This is especially true of XML web services, since
+ XML data compresses very well.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../http_web_services/alltogether.html">11.9.&nbsp;Putting it all together</a><blockquote>
+ <div class="abstract">
+ <p>You've seen all the pieces for building an intelligent HTTP web services client. Now let's see how they all fit together.</p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../http_web_services/summary.html">11.10.&nbsp;Summary</a><blockquote>
+ <div class="abstract">
+ <p>The <tt class="filename">openanything.py</tt> and its functions should now make perfect sense.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ </ul>
+ <p><a href="../soap_web_services/index.html">Chapter&nbsp;12.&nbsp;SOAP Web Services</a></p>
+ <ul>
+ <li><a href="../soap_web_services/index.html#soap.divein">12.1.&nbsp;Diving In</a><blockquote>
+ <div class="abstract">
+ <p>You use Google, right? It's a popular search engine. Have you ever wished you could programmatically access Google search
+ results? Now you can. Here is a program to search Google from <span class="application">Python</span>.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../soap_web_services/install.html">12.2.&nbsp;Installing the SOAP Libraries</a><blockquote>
+ <div class="abstract">
+ <p>Unlike the other code in this book, this chapter relies on libraries that do not come pre-installed with <span class="application">Python</span>.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../soap_web_services/first_steps.html">12.3.&nbsp;First Steps with SOAP</a><blockquote>
+ <div class="abstract">
+ <p>The heart of <span class="acronym">SOAP</span> is the ability to call remote functions. There are a number of public access <span class="acronym">SOAP</span> servers that provide simple functions for demonstration purposes.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../soap_web_services/debugging.html">12.4.&nbsp;Debugging SOAP Web Services</a><blockquote>
+ <div class="abstract">
+ <p>The <span class="acronym">SOAP</span> libraries provide an easy way to see what's going on behind the scenes.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../soap_web_services/wsdl.html">12.5.&nbsp;Introducing WSDL</a><blockquote>
+ <div class="abstract">
+ <p>The <tt class="classname">SOAPProxy</tt> class proxies local method calls and transparently turns then into invocations of remote <span class="acronym">SOAP</span> methods. As you've seen, this is a lot of work, and <tt class="classname">SOAPProxy</tt> does it quickly and transparently. What it doesn't do is provide any means of method introspection.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../soap_web_services/introspection.html">12.6.&nbsp;Introspecting SOAP Web Services with WSDL</a><blockquote>
+ <div class="abstract">
+ <p>Like many things in the web services arena, <span class="acronym">WSDL</span> has a long and checkered history, full of political strife and intrigue. I will skip over this history entirely, since it
+ bores me to tears. There were other standards that tried to do similar things, but <span class="acronym">WSDL</span> won, so let's learn how to use it.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../soap_web_services/google.html">12.7.&nbsp;Searching Google</a><blockquote>
+ <div class="abstract">
+ <p>Let's finally turn to the sample code that you saw that the beginning of this chapter, which does something more useful and
+ exciting than get the current temperature.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../soap_web_services/troubleshooting.html">12.8.&nbsp;Troubleshooting SOAP Web Services</a><blockquote>
+ <div class="abstract">
+ <p>Of course, the world of <span class="acronym">SOAP</span> web services is not all happiness and light. Sometimes things go wrong.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../soap_web_services/summary.html">12.9.&nbsp;Summary</a><blockquote>
+ <div class="abstract">
+ <p><span class="acronym">SOAP</span> web services are very complicated. The specification is very ambitious and tries to cover many different use cases for web
+ services. This chapter has touched on some of the simpler use cases.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ </ul>
+ <p><a href="../unit_testing/index.html">Chapter&nbsp;13.&nbsp;Unit Testing</a></p>
+ <ul>
+ <li><a href="../unit_testing/index.html#roman.intro">13.1.&nbsp;Introduction to Roman numerals</a><blockquote>
+ <div class="abstract">
+ <p>In previous chapters, you &#8220;<span class="quote">dived in</span>&#8221; by immediately looking at code and trying to understand it as quickly as possible. Now that you have some <span class="application">Python</span> under your belt, you're going to step back and look at the steps that happen <span class="emphasis"><em>before</em></span> the code gets written.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../unit_testing/diving_in.html">13.2.&nbsp;Diving in</a><blockquote>
+ <div class="abstract">
+ <p>Now that you've completely defined the behavior you expect from your conversion functions, you're going to do something a
+ little unexpected: you're going to write a test suite that puts these functions through their paces and makes sure that they
+ behave the way you want them to. You read that right: you're going to write code that tests code that you haven't written
+ yet.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../unit_testing/romantest.html">13.3.&nbsp;Introducing romantest.py</a><blockquote>
+ <div class="abstract">
+ <p>This is the complete test suite for your Roman numeral conversion functions, which are yet to be written but will eventually
+ be in <tt class="filename">roman.py</tt>. It is not immediately obvious how it all fits together; none of these classes or methods reference any of the others.
+ There are good reasons for this, as you'll see shortly.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../unit_testing/testing_for_success.html">13.4.&nbsp;Testing for success</a><blockquote>
+ <div class="abstract">
+ <p>The most fundamental part of unit testing is constructing individual test cases. A test case answers a single question about
+ the code it is testing.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../unit_testing/testing_for_failure.html">13.5.&nbsp;Testing for failure</a><blockquote>
+ <div class="abstract">
+ <p>It is not enough to test that functions succeed when given good input; you must also test that they fail when given bad input.
+ And not just any sort of failure; they must fail in the way you expect.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../unit_testing/testing_for_sanity.html">13.6.&nbsp;Testing for sanity</a><blockquote>
+ <div class="abstract">
+ <p>Often, you will find that a unit of code contains a set of reciprocal functions, usually in the form of conversion functions
+ where one converts A to B and the other converts B to A. In these cases, it is useful to create a &#8220;<span class="quote">sanity check</span>&#8221; to make sure that you can convert A to B and back to A without losing precision, incurring rounding errors, or triggering
+ any other sort of bug.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ </ul>
+ <p><a href="../unit_testing/stage_1.html">Chapter&nbsp;14.&nbsp;Test-First Programming</a></p>
+ <ul>
+ <li><a href="../unit_testing/stage_1.html#roman.stage1">14.1.&nbsp;roman.py, stage 1</a><blockquote>
+ <div class="abstract">
+ <p>Now that the unit tests are complete, it's time to start writing the code that the test cases are attempting to test. You're
+ going to do this in stages, so you can see all the unit tests fail, then watch them pass one by one as you fill in the gaps
+ in <tt class="filename">roman.py</tt>.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../unit_testing/stage_2.html">14.2.&nbsp;roman.py, stage 2</a><blockquote>
+ <div class="abstract">
+ <p>Now that you have the framework of the <tt class="filename">roman</tt> module laid out, it's time to start writing code and passing test cases.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../unit_testing/stage_3.html">14.3.&nbsp;roman.py, stage 3</a><blockquote>
+ <div class="abstract">
+ <p>Now that <tt class="function">toRoman</tt> behaves correctly with good input (integers from <tt class="literal">1</tt> to <tt class="literal">3999</tt>), it's time to make it behave correctly with bad input (everything else).
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../unit_testing/stage_4.html">14.4.&nbsp;roman.py, stage 4</a><blockquote>
+ <div class="abstract">
+ <p>Now that <tt class="function">toRoman</tt> is done, it's time to start coding <tt class="function">fromRoman</tt>. Thanks to the rich data structure that maps individual Roman numerals to integer values, this is no more difficult than
+ the <tt class="function">toRoman</tt> function.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../unit_testing/stage_5.html">14.5.&nbsp;roman.py, stage 5</a><blockquote>
+ <div class="abstract">
+ <p>Now that <tt class="function">fromRoman</tt> works properly with good input, it's time to fit in the last piece of the puzzle: making it work properly with bad input.
+ That means finding a way to look at a string and determine if it's a valid Roman numeral. This is inherently more difficult
+ than <a href="stage_3.html" title="14.3.&nbsp;roman.py, stage 3">validating numeric input</a> in <tt class="function">toRoman</tt>, but you have a powerful tool at your disposal: regular expressions.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ </ul>
+ <p><a href="../refactoring/index.html">Chapter&nbsp;15.&nbsp;Refactoring</a></p>
+ <ul>
+ <li><a href="../refactoring/index.html#roman.bugs">15.1.&nbsp;Handling bugs</a><blockquote>
+ <div class="abstract">
+ <p>Despite your best efforts to write comprehensive unit tests, bugs happen. What do I mean by &#8220;<span class="quote">bug</span>&#8221;? A bug is a test case you haven't written yet.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../refactoring/handling_changing_requirements.html">15.2.&nbsp;Handling changing requirements</a><blockquote>
+ <div class="abstract">
+ <p>Despite your best efforts to pin your customers to the ground and extract exact requirements from them on pain of horrible
+ nasty things involving scissors and hot wax, requirements will change. Most customers don't know what they want until they
+ see it, and even if they do, they aren't that good at articulating what they want precisely enough to be useful. And even
+ if they do, they'll want more in the next release anyway. So be prepared to update your test cases as requirements change.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../refactoring/refactoring.html">15.3.&nbsp;Refactoring</a><blockquote>
+ <div class="abstract">
+ <p>The best thing about comprehensive unit testing is not the feeling you get when all your test cases finally pass, or even
+ the feeling you get when someone else blames you for breaking their code and you can actually <span class="emphasis"><em>prove</em></span> that you didn't. The best thing about unit testing is that it gives you the freedom to refactor mercilessly.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../refactoring/postscript.html">15.4.&nbsp;Postscript</a><blockquote>
+ <div class="abstract">
+ <p>A clever reader read the <a href="refactoring.html" title="15.3.&nbsp;Refactoring">previous section</a> and took it to the next level. The biggest headache (and performance drain) in the program as it is currently written is
+ the regular expression, which is required because you have no other way of breaking down a Roman numeral. But there's only
+ 5000 of them; why don't you just build a lookup table once, then simply read that? This idea gets even better when you realize
+ that you don't need to use regular expressions at all. As you build the lookup table for converting integers to Roman numerals,
+ you can build the reverse lookup table to convert Roman numerals to integers.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../refactoring/summary.html">15.5.&nbsp;Summary</a><blockquote>
+ <div class="abstract">
+ <p>Unit testing is a powerful concept which, if properly implemented, can both reduce maintenance costs and increase flexibility
+ in any long-term project. It is also important to understand that unit testing is not a panacea, a Magic Problem Solver,
+ or a silver bullet. Writing good test cases is hard, and keeping them up to date takes discipline (especially when customers
+ are screaming for critical bug fixes). Unit testing is not a replacement for other forms of testing, including functional
+ testing, integration testing, and user acceptance testing. But it is feasible, and it does work, and once you've seen it
+ work, you'll wonder how you ever got along without it.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ </ul>
+ <p><a href="../functional_programming/index.html">Chapter&nbsp;16.&nbsp;Functional Programming</a></p>
+ <ul>
+ <li><a href="../functional_programming/index.html#regression.divein">16.1.&nbsp;Diving in</a><blockquote>
+ <div class="abstract">
+ <p>In <a href="../unit_testing/index.html" title="Chapter&nbsp;13.&nbsp;Unit Testing">Chapter&nbsp;13, <i>Unit Testing</i></a>, you learned about the philosophy of unit testing. In <a href="../unit_testing/stage_1.html" title="Chapter&nbsp;14.&nbsp;Test-First Programming">Chapter&nbsp;14, <i>Test-First Programming</i></a>, you stepped through the implementation of basic unit tests in <span class="application">Python</span>. In <a href="../refactoring/index.html" title="Chapter&nbsp;15.&nbsp;Refactoring">Chapter&nbsp;15, <i>Refactoring</i></a>, you saw how unit testing makes large-scale refactoring easier. This chapter will build on those sample programs, but here
+ we will focus more on advanced <span class="application">Python</span>-specific techniques, rather than on unit testing itself.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../functional_programming/finding_the_path.html">16.2.&nbsp;Finding the path</a><blockquote>
+ <div class="abstract">
+ <p>When running <span class="application">Python</span> scripts from the command line, it is sometimes useful to know where the currently running script is located on disk.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../functional_programming/filtering_lists.html">16.3.&nbsp;Filtering lists revisited</a><blockquote>
+ <div class="abstract">
+ <p>You're already familiar with <a href="../power_of_introspection/filtering_lists.html" title="4.5.&nbsp;Filtering Lists">using list comprehensions to filter lists</a>. There is another way to accomplish this same thing, which some people feel is more expressive.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../functional_programming/mapping_lists.html">16.4.&nbsp;Mapping lists revisited</a><blockquote>
+ <div class="abstract">
+ <p>You're already familiar with using <a href="../native_data_types/mapping_lists.html" title="3.6.&nbsp;Mapping Lists">list comprehensions</a> to map one list into another. There is another way to accomplish the same thing, using the built-in <tt class="function">map</tt> function. It works much the same way as the <a href="filtering_lists.html" title="16.3.&nbsp;Filtering lists revisited"><tt class="function">filter</tt></a> function.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../functional_programming/data_centric.html">16.5.&nbsp;Data-centric programming</a><blockquote>
+ <div class="abstract">
+ <p>By now you're probably scratching your head wondering why this is better than using <tt class="literal">for</tt> loops and straight function calls. And that's a perfectly valid question. Mostly, it's a matter of perspective. Using
+ <tt class="function">map</tt> and <tt class="function">filter</tt> forces you to center your thinking around your data.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../functional_programming/dynamic_import.html">16.6.&nbsp;Dynamically importing modules</a><blockquote>
+ <div class="abstract">
+ <p>OK, enough philosophizing. Let's talk about dynamically importing modules.</p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../functional_programming/all_together.html">16.7.&nbsp;Putting it all together</a><blockquote>
+ <div class="abstract">
+ <p>You've learned enough now to deconstruct the first seven lines of this chapter's code sample: reading a directory and importing
+ selected modules within it.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../functional_programming/summary.html">16.8.&nbsp;Summary</a><blockquote>
+ <div class="abstract">
+ <p>The <tt class="filename">regression.py</tt> program and its output should now make perfect sense.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ </ul>
+ <p><a href="../dynamic_functions/index.html">Chapter&nbsp;17.&nbsp;Dynamic functions</a></p>
+ <ul>
+ <li><a href="../dynamic_functions/index.html#plural.divein">17.1.&nbsp;Diving in</a><blockquote>
+ <div class="abstract">
+ <p>I want to talk about plural nouns. Also, functions that return other functions, advanced regular expressions, and generators.
+ Generators are new in <span class="application">Python</span> 2.3. But first, let's talk about how to make plural nouns.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../dynamic_functions/stage1.html">17.2.&nbsp;plural.py, stage 1</a><blockquote>
+ <div class="abstract">
+ <p>So you're looking at words, which at least in English are strings of characters. And you have rules that say you need to
+ find different combinations of characters, and then do different things to them. This sounds like a job for regular expressions.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../dynamic_functions/stage2.html">17.3.&nbsp;plural.py, stage 2</a><blockquote>
+ <div class="abstract">
+ <p>Now you're going to add a level of abstraction. You started by defining a list of rules: if this, then do that, otherwise
+ go to the next rule. Let's temporarily complicate part of the program so you can simplify another part.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../dynamic_functions/stage3.html">17.4.&nbsp;plural.py, stage 3</a><blockquote>
+ <div class="abstract">
+ <p>Defining separate named functions for each match and apply rule isn't really necessary. You never call them directly; you
+ define them in the <tt class="varname">rules</tt> list and call them through there. Let's streamline the rules definition by anonymizing those functions.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../dynamic_functions/stage4.html">17.5.&nbsp;plural.py, stage 4</a><blockquote>
+ <div class="abstract">
+ <p>Let's factor out the duplication in the code so that defining new rules can be easier.</p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../dynamic_functions/stage5.html">17.6.&nbsp;plural.py, stage 5</a><blockquote>
+ <div class="abstract">
+ <p>You've factored out all the duplicate code and added enough abstractions so that the pluralization rules are defined in a
+ list of strings. The next logical step is to take these strings and put them in a separate file, where they can be maintained
+ separately from the code that uses them.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../dynamic_functions/stage6.html">17.7.&nbsp;plural.py, stage 6</a><blockquote>
+ <div class="abstract">
+ <p>Now you're ready to talk about generators.</p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../dynamic_functions/summary.html">17.8.&nbsp;Summary</a><blockquote>
+ <div class="abstract">
+ <p>You talked about several different advanced techniques in this chapter. Not all of them are appropriate for every situation.</p>
+ </div>
+ </blockquote>
+ </li>
+ </ul>
+ <p><a href="../performance_tuning/index.html">Chapter&nbsp;18.&nbsp;Performance Tuning</a></p>
+ <ul>
+ <li><a href="../performance_tuning/index.html#soundex.divein">18.1.&nbsp;Diving in</a><blockquote>
+ <div class="abstract">
+ <p>There are so many pitfalls involved in optimizing your code, it's hard to know where to start.</p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../performance_tuning/timeit.html">18.2.&nbsp;Using the timeit Module</a><blockquote>
+ <div class="abstract">
+ <p>The most important thing you need to know about optimizing <span class="application">Python</span> code is that you shouldn't write your own timing function.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../performance_tuning/regular_expressions.html">18.3.&nbsp;Optimizing Regular Expressions</a><blockquote>
+ <div class="abstract">
+ <p>The first thing the Soundex function checks is whether the input is a non-empty string of letters. What's the best way to
+ do this?
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../performance_tuning/dictionary_lookups.html">18.4.&nbsp;Optimizing Dictionary Lookups</a><blockquote>
+ <div class="abstract">
+ <p>The second step of the Soundex algorithm is to convert characters to digits in a specific pattern. What's the best way to
+ do this?
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../performance_tuning/list_operations.html">18.5.&nbsp;Optimizing List Operations</a><blockquote>
+ <div class="abstract">
+ <p>The third step in the Soundex algorithm is eliminating consecutive duplicate digits. What's the best way to do this?</p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../performance_tuning/string_manipulation.html">18.6.&nbsp;Optimizing String Manipulation</a><blockquote>
+ <div class="abstract">
+ <p>The final step of the Soundex algorithm is padding short results with zeros, and truncating long results. What is the best
+ way to do this?
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ <li><a href="../performance_tuning/summary.html">18.7.&nbsp;Summary</a><blockquote>
+ <div class="abstract">
+ <p>This chapter has illustrated several important aspects of performance tuning in <span class="application">Python</span>, and performance tuning in general.
+ </p>
+ </div>
+ </blockquote>
+ </li>
+ </ul>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="furtherreading.html">&lt;&lt;&nbsp;Further reading</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="tips.html">Tips and tricks&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/appendix/examples.html b/help/diveintopython-5.4/html/appendix/examples.html
new file mode 100644
index 0000000..ca250aa
--- /dev/null
+++ b/help/diveintopython-5.4/html/appendix/examples.html
@@ -0,0 +1,1110 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>Appendix&nbsp;D.&nbsp;List of examples</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="../toc/index.html" title="Dive Into Python">
+ <link rel="previous" href="tips.html" title="Appendix&nbsp;C.&nbsp;Tips and tricks">
+ <link rel="next" href="history.html" title="Appendix&nbsp;E.&nbsp;Revision history">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<span class="thispage">List of examples</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="tips.html" title="Prev: &#8220;Tips and tricks&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="history.html" title="Next: &#8220;Revision history&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="appendix" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="examples"></a>Appendix&nbsp;D.&nbsp;List of examples
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p><a href="../installing_python/index.html">Chapter&nbsp;1.&nbsp;Installing Python</a></p>
+ <ul>
+ <li><a href="../installing_python/macosx.html">1.3.&nbsp;Python on Mac OS X</a><p></p>
+ <ul>
+ <li><a href="../installing_python/macosx.html#d0e3331">Example&nbsp;1.1.&nbsp;Two versions of Python</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../installing_python/redhat.html">1.5.&nbsp;Python on RedHat Linux</a><p></p>
+ <ul>
+ <li><a href="../installing_python/redhat.html#d0e3510">Example&nbsp;1.2.&nbsp;Installing on RedHat Linux 9</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../installing_python/debian.html">1.6.&nbsp;Python on Debian GNU/Linux</a><p></p>
+ <ul>
+ <li><a href="../installing_python/debian.html#d0e3634">Example&nbsp;1.3.&nbsp;Installing on Debian GNU/Linux</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../installing_python/source.html">1.7.&nbsp;Python Installation from Source</a><p></p>
+ <ul>
+ <li><a href="../installing_python/source.html#d0e3716">Example&nbsp;1.4.&nbsp;Installing from source</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../installing_python/shell.html">1.8.&nbsp;The Interactive Shell</a><p></p>
+ <ul>
+ <li><a href="../installing_python/shell.html#d0e3829">Example&nbsp;1.5.&nbsp;First Steps in the Interactive Shell</a></li>
+ </ul>
+ <p></p>
+ </li>
+ </ul>
+ <p><a href="../getting_to_know_python/index.html">Chapter&nbsp;2.&nbsp;Your First Python Program</a></p>
+ <ul>
+ <li><a href="../getting_to_know_python/index.html#odbchelper.divein">2.1.&nbsp;Diving in</a><p></p>
+ <ul>
+ <li><a href="../getting_to_know_python/index.html#d0e3948">Example&nbsp;2.1.&nbsp;odbchelper.py</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../getting_to_know_python/documenting_functions.html">2.3.&nbsp;Documenting Functions</a><p></p>
+ <ul>
+ <li><a href="../getting_to_know_python/documenting_functions.html#odbchelper.triplequotes">Example&nbsp;2.2.&nbsp;Defining the buildConnectionString Function's doc string</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../getting_to_know_python/everything_is_an_object.html">2.4.&nbsp;Everything Is an Object</a><p></p>
+ <ul>
+ <li><a href="../getting_to_know_python/everything_is_an_object.html#odbchelper.import">Example&nbsp;2.3.&nbsp;Accessing the buildConnectionString Function's doc string</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../getting_to_know_python/everything_is_an_object.html#d0e4550">2.4.1.&nbsp;The Import Search Path</a><p></p>
+ <ul>
+ <li><a href="../getting_to_know_python/everything_is_an_object.html#odbchelper.objects.sys.path">Example&nbsp;2.4.&nbsp;Import Search Path</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../getting_to_know_python/indenting_code.html">2.5.&nbsp;Indenting Code</a><p></p>
+ <ul>
+ <li><a href="../getting_to_know_python/indenting_code.html#d0e4759">Example&nbsp;2.5.&nbsp;Indenting the buildConnectionString Function</a></li>
+ <li><a href="../getting_to_know_python/indenting_code.html#odbchelper.indenting.if">Example&nbsp;2.6.&nbsp;if Statements</a></li>
+ </ul>
+ <p></p>
+ </li>
+ </ul>
+ <p><a href="../native_data_types/index.html">Chapter&nbsp;3.&nbsp;Native Datatypes</a></p>
+ <ul>
+ <li><a href="../native_data_types/index.html#d0e5174">3.1.1.&nbsp;Defining Dictionaries</a><p></p>
+ <ul>
+ <li><a href="../native_data_types/index.html#odbchelper.dict.define">Example&nbsp;3.1.&nbsp;Defining a Dictionary</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../native_data_types/index.html#d0e5269">3.1.2.&nbsp;Modifying Dictionaries</a><p></p>
+ <ul>
+ <li><a href="../native_data_types/index.html#odbchelper.dict.modify">Example&nbsp;3.2.&nbsp;Modifying a Dictionary</a></li>
+ <li><a href="../native_data_types/index.html#odbchelper.dict.case">Example&nbsp;3.3.&nbsp;Dictionary Keys Are Case-Sensitive</a></li>
+ <li><a href="../native_data_types/index.html#odbchelper.dictionarytypes">Example&nbsp;3.4.&nbsp;Mixing Datatypes in a Dictionary</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../native_data_types/index.html#d0e5450">3.1.3.&nbsp;Deleting Items From Dictionaries</a><p></p>
+ <ul>
+ <li><a href="../native_data_types/index.html#odbchelper.dict.del">Example&nbsp;3.5.&nbsp;Deleting Items from a Dictionary</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../native_data_types/lists.html#d0e5623">3.2.1.&nbsp;Defining Lists</a><p></p>
+ <ul>
+ <li><a href="../native_data_types/lists.html#d0e5626">Example&nbsp;3.6.&nbsp;Defining a List</a></li>
+ <li><a href="../native_data_types/lists.html#odbchelper.negative.example">Example&nbsp;3.7.&nbsp;Negative List Indices</a></li>
+ <li><a href="../native_data_types/lists.html#odbchelper.list.slice">Example&nbsp;3.8.&nbsp;Slicing a List</a></li>
+ <li><a href="../native_data_types/lists.html#odbchelper.list.slicing.example">Example&nbsp;3.9.&nbsp;Slicing Shorthand</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../native_data_types/lists.html#d0e5887">3.2.2.&nbsp;Adding Elements to Lists</a><p></p>
+ <ul>
+ <li><a href="../native_data_types/lists.html#d0e5890">Example&nbsp;3.10.&nbsp;Adding Elements to a List</a></li>
+ <li><a href="../native_data_types/lists.html#odbchelper.list.append.vs.extend">Example&nbsp;3.11.&nbsp;The Difference between extend and append</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../native_data_types/lists.html#d0e6115">3.2.3.&nbsp;Searching Lists</a><p></p>
+ <ul>
+ <li><a href="../native_data_types/lists.html#odbchelper.list.search">Example&nbsp;3.12.&nbsp;Searching a List</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../native_data_types/lists.html#d0e6277">3.2.4.&nbsp;Deleting List Elements</a><p></p>
+ <ul>
+ <li><a href="../native_data_types/lists.html#odbchelper.list.removingelements">Example&nbsp;3.13.&nbsp;Removing Elements from a List</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../native_data_types/lists.html#d0e6392">3.2.5.&nbsp;Using List Operators</a><p></p>
+ <ul>
+ <li><a href="../native_data_types/lists.html#odbchelper.list.operators">Example&nbsp;3.14.&nbsp;List Operators</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../native_data_types/tuples.html">3.3.&nbsp;Introducing Tuples</a><p></p>
+ <ul>
+ <li><a href="../native_data_types/tuples.html#d0e6568">Example&nbsp;3.15.&nbsp;Defining a tuple</a></li>
+ <li><a href="../native_data_types/tuples.html#odbchelper.tuplemethods">Example&nbsp;3.16.&nbsp;Tuples Have No Methods</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../native_data_types/declaring_variables.html">3.4.&nbsp;Declaring variables</a><p></p>
+ <ul>
+ <li><a href="../native_data_types/declaring_variables.html#myparamsdef">Example&nbsp;3.17.&nbsp;Defining the myParams Variable</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../native_data_types/declaring_variables.html#d0e6873">3.4.1.&nbsp;Referencing Variables</a><p></p>
+ <ul>
+ <li><a href="../native_data_types/declaring_variables.html#odbchelper.unboundvariable">Example&nbsp;3.18.&nbsp;Referencing an Unbound Variable</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../native_data_types/declaring_variables.html#odbchelper.multiassign">3.4.2.&nbsp;Assigning Multiple Values at Once</a><p></p>
+ <ul>
+ <li><a href="../native_data_types/declaring_variables.html#d0e6913">Example&nbsp;3.19.&nbsp;Assigning multiple values at once</a></li>
+ <li><a href="../native_data_types/declaring_variables.html#odbchelper.multiassign.range">Example&nbsp;3.20.&nbsp;Assigning Consecutive Values</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../native_data_types/formatting_strings.html">3.5.&nbsp;Formatting Strings</a><p></p>
+ <ul>
+ <li><a href="../native_data_types/formatting_strings.html#d0e7165">Example&nbsp;3.21.&nbsp;Introducing String Formatting</a></li>
+ <li><a href="../native_data_types/formatting_strings.html#odbchelper.stringformatting.coerce">Example&nbsp;3.22.&nbsp;String Formatting vs. Concatenating</a></li>
+ <li><a href="../native_data_types/formatting_strings.html#odbchelper.stringformatting.numbers">Example&nbsp;3.23.&nbsp;Formatting Numbers</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../native_data_types/mapping_lists.html">3.6.&nbsp;Mapping Lists</a><p></p>
+ <ul>
+ <li><a href="../native_data_types/mapping_lists.html#d0e7412">Example&nbsp;3.24.&nbsp;Introducing List Comprehensions</a></li>
+ <li><a href="../native_data_types/mapping_lists.html#odbchelper.items">Example&nbsp;3.25.&nbsp;The keys, values, and items Functions</a></li>
+ <li><a href="../native_data_types/mapping_lists.html#d0e7615">Example&nbsp;3.26.&nbsp;List Comprehensions in buildConnectionString, Step by Step</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../native_data_types/joining_lists.html">3.7.&nbsp;Joining Lists and Splitting Strings</a><p></p>
+ <ul>
+ <li><a href="../native_data_types/joining_lists.html#odbchelper.join.example">Example&nbsp;3.27.&nbsp;Output of odbchelper.py</a></li>
+ <li><a href="../native_data_types/joining_lists.html#odbchelper.split.example">Example&nbsp;3.28.&nbsp;Splitting a String</a></li>
+ </ul>
+ <p></p>
+ </li>
+ </ul>
+ <p><a href="../power_of_introspection/index.html">Chapter&nbsp;4.&nbsp;The Power Of Introspection</a></p>
+ <ul>
+ <li><a href="../power_of_introspection/index.html#apihelper.divein">4.1.&nbsp;Diving In</a><p></p>
+ <ul>
+ <li><a href="../power_of_introspection/index.html#d0e8158">Example&nbsp;4.1.&nbsp;apihelper.py</a></li>
+ <li><a href="../power_of_introspection/index.html#d0e8257">Example&nbsp;4.2.&nbsp;Sample Usage of apihelper.py</a></li>
+ <li><a href="../power_of_introspection/index.html#d0e8294">Example&nbsp;4.3.&nbsp;Advanced Usage of apihelper.py</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../power_of_introspection/optional_arguments.html">4.2.&nbsp;Using Optional and Named Arguments</a><p></p>
+ <ul>
+ <li><a href="../power_of_introspection/optional_arguments.html#d0e8401">Example&nbsp;4.4.&nbsp;Valid Calls of info</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../power_of_introspection/built_in_functions.html#d0e8510">4.3.1.&nbsp;The type Function</a><p></p>
+ <ul>
+ <li><a href="../power_of_introspection/built_in_functions.html#apihelper.type.intro">Example&nbsp;4.5.&nbsp;Introducing type</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../power_of_introspection/built_in_functions.html#d0e8609">4.3.2.&nbsp;The str Function</a><p></p>
+ <ul>
+ <li><a href="../power_of_introspection/built_in_functions.html#apihelper.str.intro">Example&nbsp;4.6.&nbsp;Introducing str</a></li>
+ <li><a href="../power_of_introspection/built_in_functions.html#apihelper.dir.intro">Example&nbsp;4.7.&nbsp;Introducing dir</a></li>
+ <li><a href="../power_of_introspection/built_in_functions.html#apihelper.builtin.callable">Example&nbsp;4.8.&nbsp;Introducing callable</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../power_of_introspection/built_in_functions.html#d0e8958">4.3.3.&nbsp;Built-In Functions</a><p></p>
+ <ul>
+ <li><a href="../power_of_introspection/built_in_functions.html#apihelper.builtin.list">Example&nbsp;4.9.&nbsp;Built-in Attributes and Functions</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../power_of_introspection/getattr.html">4.4.&nbsp;Getting Object References With getattr</a><p></p>
+ <ul>
+ <li><a href="../power_of_introspection/getattr.html#apihelper.getattr.intro">Example&nbsp;4.10.&nbsp;Introducing getattr</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../power_of_introspection/getattr.html#d0e9194">4.4.1.&nbsp;getattr with Modules</a><p></p>
+ <ul>
+ <li><a href="../power_of_introspection/getattr.html#apihelper.getattr.example">Example&nbsp;4.11.&nbsp;The getattr Function in apihelper.py</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../power_of_introspection/getattr.html#d0e9362">4.4.2.&nbsp;getattr As a Dispatcher</a><p></p>
+ <ul>
+ <li><a href="../power_of_introspection/getattr.html#apihelper.getattr.dispatch">Example&nbsp;4.12.&nbsp;Creating a Dispatcher with getattr</a></li>
+ <li><a href="../power_of_introspection/getattr.html#apihelper.getattr.default">Example&nbsp;4.13.&nbsp;getattr Default Values</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../power_of_introspection/filtering_lists.html">4.5.&nbsp;Filtering Lists</a><p></p>
+ <ul>
+ <li><a href="../power_of_introspection/filtering_lists.html#d0e9539">Example&nbsp;4.14.&nbsp;Introducing List Filtering</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../power_of_introspection/and_or.html">4.6.&nbsp;The Peculiar Nature of and and or</a><p></p>
+ <ul>
+ <li><a href="../power_of_introspection/and_or.html#apihelper.andor.intro.example">Example&nbsp;4.15.&nbsp;Introducing and</a></li>
+ <li><a href="../power_of_introspection/and_or.html#d0e9812">Example&nbsp;4.16.&nbsp;Introducing or</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../power_of_introspection/and_or.html#d0e9975">4.6.1.&nbsp;Using the and-or Trick</a><p></p>
+ <ul>
+ <li><a href="../power_of_introspection/and_or.html#apihelper.andortrick.intro">Example&nbsp;4.17.&nbsp;Introducing the and-or Trick</a></li>
+ <li><a href="../power_of_introspection/and_or.html#d0e10093">Example&nbsp;4.18.&nbsp;When the and-or Trick Fails</a></li>
+ <li><a href="../power_of_introspection/and_or.html#d0e10205">Example&nbsp;4.19.&nbsp;Using the and-or Trick Safely</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../power_of_introspection/lambda_functions.html">4.7.&nbsp;Using lambda Functions</a><p></p>
+ <ul>
+ <li><a href="../power_of_introspection/lambda_functions.html#d0e10311">Example&nbsp;4.20.&nbsp;Introducing lambda Functions</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../power_of_introspection/lambda_functions.html#d0e10403">4.7.1.&nbsp;Real-World lambda Functions</a><p></p>
+ <ul>
+ <li><a href="../power_of_introspection/lambda_functions.html#d0e10444">Example&nbsp;4.21.&nbsp;split With No Arguments</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../power_of_introspection/all_together.html">4.8.&nbsp;Putting It All Together</a><p></p>
+ <ul>
+ <li><a href="../power_of_introspection/all_together.html#d0e10681">Example&nbsp;4.22.&nbsp;Getting a doc string Dynamically</a></li>
+ <li><a href="../power_of_introspection/all_together.html#d0e10793">Example&nbsp;4.23.&nbsp;Why Use str on a doc string?</a></li>
+ <li><a href="../power_of_introspection/all_together.html#d0e10958">Example&nbsp;4.24.&nbsp;Introducing ljust</a></li>
+ <li><a href="../power_of_introspection/all_together.html#d0e11026">Example&nbsp;4.25.&nbsp;Printing a List</a></li>
+ </ul>
+ <p></p>
+ </li>
+ </ul>
+ <p><a href="../object_oriented_framework/index.html">Chapter&nbsp;5.&nbsp;Objects and Object-Orientation</a></p>
+ <ul>
+ <li><a href="../object_oriented_framework/index.html#fileinfo.divein">5.1.&nbsp;Diving In</a><p></p>
+ <ul>
+ <li><a href="../object_oriented_framework/index.html#d0e11177">Example&nbsp;5.1.&nbsp;fileinfo.py</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../object_oriented_framework/importing_modules.html">5.2.&nbsp;Importing Modules Using from module import</a><p></p>
+ <ul>
+ <li><a href="../object_oriented_framework/importing_modules.html#d0e11355">Example&nbsp;5.2.&nbsp;import module vs. from module import</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../object_oriented_framework/defining_classes.html">5.3.&nbsp;Defining Classes</a><p></p>
+ <ul>
+ <li><a href="../object_oriented_framework/defining_classes.html#fileinfo.class.simplest">Example&nbsp;5.3.&nbsp;The Simplest Python Class</a></li>
+ <li><a href="../object_oriented_framework/defining_classes.html#fileinfo.class.example">Example&nbsp;5.4.&nbsp;Defining the FileInfo Class</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../object_oriented_framework/defining_classes.html#d0e11720">5.3.1.&nbsp;Initializing and Coding Classes</a><p></p>
+ <ul>
+ <li><a href="../object_oriented_framework/defining_classes.html#fileinfo.init.example">Example&nbsp;5.5.&nbsp;Initializing the FileInfo Class</a></li>
+ <li><a href="../object_oriented_framework/defining_classes.html#fileinfo.init.code.example">Example&nbsp;5.6.&nbsp;Coding the FileInfo Class</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../object_oriented_framework/instantiating_classes.html">5.4.&nbsp;Instantiating Classes</a><p></p>
+ <ul>
+ <li><a href="../object_oriented_framework/instantiating_classes.html#d0e12003">Example&nbsp;5.7.&nbsp;Creating a FileInfo Instance</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../object_oriented_framework/instantiating_classes.html#d0e12165">5.4.1.&nbsp;Garbage Collection</a><p></p>
+ <ul>
+ <li><a href="../object_oriented_framework/instantiating_classes.html#fileinfo.scope">Example&nbsp;5.8.&nbsp;Trying to Implement a Memory Leak</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../object_oriented_framework/userdict.html">5.5.&nbsp;Exploring UserDict: A Wrapper Class</a><p></p>
+ <ul>
+ <li><a href="../object_oriented_framework/userdict.html#fileinfo.userdict.init.example">Example&nbsp;5.9.&nbsp;Defining the UserDict Class</a></li>
+ <li><a href="../object_oriented_framework/userdict.html#fileinfo.userdict.normalmethods">Example&nbsp;5.10.&nbsp;UserDict Normal Methods</a></li>
+ <li><a href="../object_oriented_framework/userdict.html#fileinfo.userdict.fromdict">Example&nbsp;5.11.&nbsp;Inheriting Directly from Built-In Datatype dict</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../object_oriented_framework/special_class_methods.html#d0e12822">5.6.1.&nbsp;Getting and Setting Items</a><p></p>
+ <ul>
+ <li><a href="../object_oriented_framework/special_class_methods.html#d0e12825">Example&nbsp;5.12.&nbsp;The __getitem__ Special Method</a></li>
+ <li><a href="../object_oriented_framework/special_class_methods.html#fileinfo.specialmethods.setitem.example">Example&nbsp;5.13.&nbsp;The __setitem__ Special Method</a></li>
+ <li><a href="../object_oriented_framework/special_class_methods.html#d0e13038">Example&nbsp;5.14.&nbsp;Overriding __setitem__ in MP3FileInfo</a></li>
+ <li><a href="../object_oriented_framework/special_class_methods.html#fileinfo.specialmethods.setname">Example&nbsp;5.15.&nbsp;Setting an MP3FileInfo's name</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../object_oriented_framework/special_class_methods2.html">5.7.&nbsp;Advanced Special Class Methods</a><p></p>
+ <ul>
+ <li><a href="../object_oriented_framework/special_class_methods2.html#fileinfo.morespecial.example">Example&nbsp;5.16.&nbsp;More Special Methods in UserDict</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../object_oriented_framework/class_attributes.html">5.8.&nbsp;Introducing Class Attributes</a><p></p>
+ <ul>
+ <li><a href="../object_oriented_framework/class_attributes.html#fileinfo.classattributes.intro">Example&nbsp;5.17.&nbsp;Introducing Class Attributes</a></li>
+ <li><a href="../object_oriented_framework/class_attributes.html#fileinfo.classattributes.writeable.example">Example&nbsp;5.18.&nbsp;Modifying Class Attributes</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../object_oriented_framework/private_functions.html">5.9.&nbsp;Private Functions</a><p></p>
+ <ul>
+ <li><a href="../object_oriented_framework/private_functions.html#d0e13946">Example&nbsp;5.19.&nbsp;Trying to Call a Private Method</a></li>
+ </ul>
+ <p></p>
+ </li>
+ </ul>
+ <p><a href="../file_handling/index.html">Chapter&nbsp;6.&nbsp;Exceptions and File Handling</a></p>
+ <ul>
+ <li><a href="../file_handling/index.html#fileinfo.exception">6.1.&nbsp;Handling Exceptions</a><p></p>
+ <ul>
+ <li><a href="../file_handling/index.html#d0e14243">Example&nbsp;6.1.&nbsp;Opening a Non-Existent File</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../file_handling/index.html#d0e14344">6.1.1.&nbsp;Using Exceptions For Other Purposes</a><p></p>
+ <ul>
+ <li><a href="../file_handling/index.html#crossplatform.example">Example&nbsp;6.2.&nbsp;Supporting Platform-Specific Functionality</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../file_handling/file_objects.html">6.2.&nbsp;Working with File Objects</a><p></p>
+ <ul>
+ <li><a href="../file_handling/file_objects.html#d0e14596">Example&nbsp;6.3.&nbsp;Opening a File</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../file_handling/file_objects.html#d0e14670">6.2.1.&nbsp;Reading Files</a><p></p>
+ <ul>
+ <li><a href="../file_handling/file_objects.html#d0e14675">Example&nbsp;6.4.&nbsp;Reading a File</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../file_handling/file_objects.html#d0e14800">6.2.2.&nbsp;Closing Files</a><p></p>
+ <ul>
+ <li><a href="../file_handling/file_objects.html#d0e14805">Example&nbsp;6.5.&nbsp;Closing a File</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../file_handling/file_objects.html#d0e14928">6.2.3.&nbsp;Handling I/O Errors</a><p></p>
+ <ul>
+ <li><a href="../file_handling/file_objects.html#fileinfo.files.incode">Example&nbsp;6.6.&nbsp;File Objects in MP3FileInfo</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../file_handling/file_objects.html#d0e15055">6.2.4.&nbsp;Writing to Files</a><p></p>
+ <ul>
+ <li><a href="../file_handling/file_objects.html#fileinfo.files.writeandappend">Example&nbsp;6.7.&nbsp;Writing to Files</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../file_handling/for_loops.html">6.3.&nbsp;Iterating with for Loops</a><p></p>
+ <ul>
+ <li><a href="../file_handling/for_loops.html#d0e15255">Example&nbsp;6.8.&nbsp;Introducing the for Loop</a></li>
+ <li><a href="../file_handling/for_loops.html#fileinfo.for.counter">Example&nbsp;6.9.&nbsp;Simple Counters</a></li>
+ <li><a href="../file_handling/for_loops.html#dictionaryiter.example">Example&nbsp;6.10.&nbsp;Iterating Through a Dictionary</a></li>
+ <li><a href="../file_handling/for_loops.html#fileinfo.multiassign.for.example">Example&nbsp;6.11.&nbsp;for Loop in MP3FileInfo</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../file_handling/more_on_modules.html">6.4.&nbsp;Using sys.modules</a><p></p>
+ <ul>
+ <li><a href="../file_handling/more_on_modules.html#d0e15693">Example&nbsp;6.12.&nbsp;Introducing sys.modules</a></li>
+ <li><a href="../file_handling/more_on_modules.html#d0e15784">Example&nbsp;6.13.&nbsp;Using sys.modules</a></li>
+ <li><a href="../file_handling/more_on_modules.html#d0e15859">Example&nbsp;6.14.&nbsp;The __module__ Class Attribute</a></li>
+ <li><a href="../file_handling/more_on_modules.html#d0e15923">Example&nbsp;6.15.&nbsp;sys.modules in fileinfo.py</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../file_handling/os_module.html">6.5.&nbsp;Working with Directories</a><p></p>
+ <ul>
+ <li><a href="../file_handling/os_module.html#fileinfo.os.path.join.example">Example&nbsp;6.16.&nbsp;Constructing Pathnames</a></li>
+ <li><a href="../file_handling/os_module.html#splittingpathnames.example">Example&nbsp;6.17.&nbsp;Splitting Pathnames</a></li>
+ <li><a href="../file_handling/os_module.html#fileinfo.listdir.example">Example&nbsp;6.18.&nbsp;Listing Directories</a></li>
+ <li><a href="../file_handling/os_module.html#d0e16376">Example&nbsp;6.19.&nbsp;Listing Directories in fileinfo.py</a></li>
+ <li><a href="../file_handling/os_module.html#fileinfo.os.glob.example">Example&nbsp;6.20.&nbsp;Listing Directories with glob</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../file_handling/all_together.html">6.6.&nbsp;Putting It All Together</a><p></p>
+ <ul>
+ <li><a href="../file_handling/all_together.html#fileinfo.nested">Example&nbsp;6.21.&nbsp;listDirectory</a></li>
+ </ul>
+ <p></p>
+ </li>
+ </ul>
+ <p><a href="../regular_expressions/index.html">Chapter&nbsp;7.&nbsp;Regular Expressions</a></p>
+ <ul>
+ <li><a href="../regular_expressions/street_addresses.html">7.2.&nbsp;Case Study: Street Addresses</a><p></p>
+ <ul>
+ <li><a href="../regular_expressions/street_addresses.html#d0e16923">Example&nbsp;7.1.&nbsp;Matching at the End of a String</a></li>
+ <li><a href="../regular_expressions/street_addresses.html#d0e17121">Example&nbsp;7.2.&nbsp;Matching Whole Words</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../regular_expressions/roman_numerals.html#d0e17592">7.3.1.&nbsp;Checking for Thousands</a><p></p>
+ <ul>
+ <li><a href="../regular_expressions/roman_numerals.html#d0e17600">Example&nbsp;7.3.&nbsp;Checking for Thousands</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../regular_expressions/roman_numerals.html#d0e17785">7.3.2.&nbsp;Checking for Hundreds</a><p></p>
+ <ul>
+ <li><a href="../regular_expressions/roman_numerals.html#re.roman.hundreds">Example&nbsp;7.4.&nbsp;Checking for Hundreds</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../regular_expressions/n_m_syntax.html">7.4.&nbsp;Using the {n,m} Syntax</a><p></p>
+ <ul>
+ <li><a href="../regular_expressions/n_m_syntax.html#d0e18113">Example&nbsp;7.5.&nbsp;The Old Way: Every Character Optional</a></li>
+ <li><a href="../regular_expressions/n_m_syntax.html#d0e18215">Example&nbsp;7.6.&nbsp;The New Way: From n o m</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../regular_expressions/n_m_syntax.html#d0e18326">7.4.1.&nbsp;Checking for Tens and Ones</a><p></p>
+ <ul>
+ <li><a href="../regular_expressions/n_m_syntax.html#re.tens.example">Example&nbsp;7.7.&nbsp;Checking for Tens</a></li>
+ <li><a href="../regular_expressions/n_m_syntax.html#re.nm.example">Example&nbsp;7.8.&nbsp;Validating Roman Numerals with {n,m}</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../regular_expressions/verbose.html">7.5.&nbsp;Verbose Regular Expressions</a><p></p>
+ <ul>
+ <li><a href="../regular_expressions/verbose.html#d0e18777">Example&nbsp;7.9.&nbsp;Regular Expressions with Inline Comments</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../regular_expressions/phone_numbers.html">7.6.&nbsp;Case study: Parsing Phone Numbers</a><p></p>
+ <ul>
+ <li><a href="../regular_expressions/phone_numbers.html#re.phone.example">Example&nbsp;7.10.&nbsp;Finding Numbers</a></li>
+ <li><a href="../regular_expressions/phone_numbers.html#d0e19043">Example&nbsp;7.11.&nbsp;Finding the Extension</a></li>
+ <li><a href="../regular_expressions/phone_numbers.html#d0e19106">Example&nbsp;7.12.&nbsp;Handling Different Separators</a></li>
+ <li><a href="../regular_expressions/phone_numbers.html#d0e19203">Example&nbsp;7.13.&nbsp;Handling Numbers Without Separators</a></li>
+ <li><a href="../regular_expressions/phone_numbers.html#d0e19318">Example&nbsp;7.14.&nbsp;Handling Leading Characters</a></li>
+ <li><a href="../regular_expressions/phone_numbers.html#d0e19396">Example&nbsp;7.15.&nbsp;Phone Number, Wherever I May Find Ye</a></li>
+ <li><a href="../regular_expressions/phone_numbers.html#d0e19458">Example&nbsp;7.16.&nbsp;Parsing Phone Numbers (Final Version)</a></li>
+ </ul>
+ <p></p>
+ </li>
+ </ul>
+ <p><a href="../html_processing/index.html">Chapter&nbsp;8.&nbsp;HTML Processing</a></p>
+ <ul>
+ <li><a href="../html_processing/index.html#dialect.divein">8.1.&nbsp;Diving in</a><p></p>
+ <ul>
+ <li><a href="../html_processing/index.html#dialect.basehtml.listing">Example&nbsp;8.1.&nbsp;BaseHTMLProcessor.py</a></li>
+ <li><a href="../html_processing/index.html#d0e19707">Example&nbsp;8.2.&nbsp;dialect.py</a></li>
+ <li><a href="../html_processing/index.html#d0e19713">Example&nbsp;8.3.&nbsp;Output of dialect.py</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../html_processing/introducing_sgmllib.html">8.2.&nbsp;Introducing sgmllib.py</a><p></p>
+ <ul>
+ <li><a href="../html_processing/introducing_sgmllib.html#d0e20080">Example&nbsp;8.4.&nbsp;Sample test of sgmllib.py</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../html_processing/extracting_data.html">8.3.&nbsp;Extracting data from HTML documents</a><p></p>
+ <ul>
+ <li><a href="../html_processing/extracting_data.html#dialect.extract.urllib">Example&nbsp;8.5.&nbsp;Introducing urllib</a></li>
+ <li><a href="../html_processing/extracting_data.html#dialect.extract.links">Example&nbsp;8.6.&nbsp;Introducing urllister.py</a></li>
+ <li><a href="../html_processing/extracting_data.html#dialect.feed.example">Example&nbsp;8.7.&nbsp;Using urllister.py</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../html_processing/basehtmlprocessor.html">8.4.&nbsp;Introducing BaseHTMLProcessor.py</a><p></p>
+ <ul>
+ <li><a href="../html_processing/basehtmlprocessor.html#dialect.basehtml.intro">Example&nbsp;8.8.&nbsp;Introducing BaseHTMLProcessor</a></li>
+ <li><a href="../html_processing/basehtmlprocessor.html#dialect.output.example">Example&nbsp;8.9.&nbsp;BaseHTMLProcessor output</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../html_processing/locals_and_globals.html">8.5.&nbsp;locals and globals</a><p></p>
+ <ul>
+ <li><a href="../html_processing/locals_and_globals.html#d0e21119">Example&nbsp;8.10.&nbsp;Introducing locals</a></li>
+ <li><a href="../html_processing/locals_and_globals.html#dialect.globals.example">Example&nbsp;8.11.&nbsp;Introducing globals</a></li>
+ <li><a href="../html_processing/locals_and_globals.html#dialect.locals.readonly.example">Example&nbsp;8.12.&nbsp;locals is read-only, globals is not</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../html_processing/dictionary_based_string_formatting.html">8.6.&nbsp;Dictionary-based string formatting</a><p></p>
+ <ul>
+ <li><a href="../html_processing/dictionary_based_string_formatting.html#d0e21518">Example&nbsp;8.13.&nbsp;Introducing dictionary-based string formatting</a></li>
+ <li><a href="../html_processing/dictionary_based_string_formatting.html#dialect.unknownstarttag">Example&nbsp;8.14.&nbsp;Dictionary-based string formatting in BaseHTMLProcessor.py</a></li>
+ <li><a href="../html_processing/dictionary_based_string_formatting.html#d0e21622">Example&nbsp;8.15.&nbsp;More dictionary-based string formatting</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../html_processing/quoting_attribute_values.html">8.7.&nbsp;Quoting attribute values</a><p></p>
+ <ul>
+ <li><a href="../html_processing/quoting_attribute_values.html#dialect.quoting.example">Example&nbsp;8.16.&nbsp;Quoting attribute values</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../html_processing/dialect.html">8.8.&nbsp;Introducing dialect.py</a><p></p>
+ <ul>
+ <li><a href="../html_processing/dialect.html#dialect.specifictags.example">Example&nbsp;8.17.&nbsp;Handling specific tags</a></li>
+ <li><a href="../html_processing/dialect.html#dialect.dialectizer.example">Example&nbsp;8.18.&nbsp;SGMLParser</a></li>
+ <li><a href="../html_processing/dialect.html#d0e22310">Example&nbsp;8.19.&nbsp;Overriding the handle_data method</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../html_processing/all_together.html">8.9.&nbsp;Putting it all together</a><p></p>
+ <ul>
+ <li><a href="../html_processing/all_together.html#d0e22387">Example&nbsp;8.20.&nbsp;The translate function, part 1</a></li>
+ <li><a href="../html_processing/all_together.html#d0e22433">Example&nbsp;8.21.&nbsp;The translate function, part 2: curiouser and curiouser</a></li>
+ <li><a href="../html_processing/all_together.html#d0e22614">Example&nbsp;8.22.&nbsp;The translate function, part 3</a></li>
+ </ul>
+ <p></p>
+ </li>
+ </ul>
+ <p><a href="../xml_processing/index.html">Chapter&nbsp;9.&nbsp;XML Processing</a></p>
+ <ul>
+ <li><a href="../xml_processing/index.html#kgp.divein">9.1.&nbsp;Diving in</a><p></p>
+ <ul>
+ <li><a href="../xml_processing/index.html#d0e22845">Example&nbsp;9.1.&nbsp;kgp.py</a></li>
+ <li><a href="../xml_processing/index.html#d0e22856">Example&nbsp;9.2.&nbsp;toolbox.py</a></li>
+ <li><a href="../xml_processing/index.html#d0e22873">Example&nbsp;9.3.&nbsp;Sample output of kgp.py</a></li>
+ <li><a href="../xml_processing/index.html#d0e22893">Example&nbsp;9.4.&nbsp;Simpler output from kgp.py</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../xml_processing/packages.html">9.2.&nbsp;Packages</a><p></p>
+ <ul>
+ <li><a href="../xml_processing/packages.html#d0e22925">Example&nbsp;9.5.&nbsp;Loading an XML document (a sneak peek)</a></li>
+ <li><a href="../xml_processing/packages.html#d0e22983">Example&nbsp;9.6.&nbsp;File layout of a package</a></li>
+ <li><a href="../xml_processing/packages.html#d0e23025">Example&nbsp;9.7.&nbsp;Packages are modules, too</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../xml_processing/parsing_xml.html">9.3.&nbsp;Parsing XML</a><p></p>
+ <ul>
+ <li><a href="../xml_processing/parsing_xml.html#d0e23245">Example&nbsp;9.8.&nbsp;Loading an XML document (for real this time)</a></li>
+ <li><a href="../xml_processing/parsing_xml.html#kgp.parse.gettingchildnodes.example">Example&nbsp;9.9.&nbsp;Getting child nodes</a></li>
+ <li><a href="../xml_processing/parsing_xml.html#d0e23458">Example&nbsp;9.10.&nbsp;toxml works on any node</a></li>
+ <li><a href="../xml_processing/parsing_xml.html#kgp.parse.childnodescanbetext.example">Example&nbsp;9.11.&nbsp;Child nodes can be text</a></li>
+ <li><a href="../xml_processing/parsing_xml.html#d0e23628">Example&nbsp;9.12.&nbsp;Drilling down all the way to text</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../xml_processing/unicode.html">9.4.&nbsp;Unicode</a><p></p>
+ <ul>
+ <li><a href="../xml_processing/unicode.html#d0e23841">Example&nbsp;9.13.&nbsp;Introducing unicode</a></li>
+ <li><a href="../xml_processing/unicode.html#d0e23908">Example&nbsp;9.14.&nbsp;Storing non-ASCII characters</a></li>
+ <li><a href="../xml_processing/unicode.html#d0e24009">Example&nbsp;9.15.&nbsp;sitecustomize.py</a></li>
+ <li><a href="../xml_processing/unicode.html#d0e24048">Example&nbsp;9.16.&nbsp;Effects of setting the default encoding</a></li>
+ <li><a href="../xml_processing/unicode.html#d0e24123">Example&nbsp;9.17.&nbsp;Specifying encoding in .py files</a></li>
+ <li><a href="../xml_processing/unicode.html#d0e24153">Example&nbsp;9.18.&nbsp;russiansample.xml</a></li>
+ <li><a href="../xml_processing/unicode.html#d0e24188">Example&nbsp;9.19.&nbsp;Parsing russiansample.xml</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../xml_processing/searching.html">9.5.&nbsp;Searching for elements</a><p></p>
+ <ul>
+ <li><a href="../xml_processing/searching.html#d0e24431">Example&nbsp;9.20.&nbsp;binary.xml</a></li>
+ <li><a href="../xml_processing/searching.html#d0e24464">Example&nbsp;9.21.&nbsp;Introducing getElementsByTagName</a></li>
+ <li><a href="../xml_processing/searching.html#d0e24526">Example&nbsp;9.22.&nbsp;Every element is searchable</a></li>
+ <li><a href="../xml_processing/searching.html#d0e24615">Example&nbsp;9.23.&nbsp;Searching is actually recursive</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../xml_processing/attributes.html">9.6.&nbsp;Accessing element attributes</a><p></p>
+ <ul>
+ <li><a href="../xml_processing/attributes.html#d0e24787">Example&nbsp;9.24.&nbsp;Accessing element attributes</a></li>
+ <li><a href="../xml_processing/attributes.html#d0e24922">Example&nbsp;9.25.&nbsp;Accessing individual attributes</a></li>
+ </ul>
+ <p></p>
+ </li>
+ </ul>
+ <p><a href="../scripts_and_streams/index.html">Chapter&nbsp;10.&nbsp;Scripts and Streams</a></p>
+ <ul>
+ <li><a href="../scripts_and_streams/index.html#kgp.openanything">10.1.&nbsp;Abstracting input sources</a><p></p>
+ <ul>
+ <li><a href="../scripts_and_streams/index.html#d0e25118">Example&nbsp;10.1.&nbsp;Parsing XML from a file</a></li>
+ <li><a href="../scripts_and_streams/index.html#kgp.openanything.urllib">Example&nbsp;10.2.&nbsp;Parsing XML from a URL</a></li>
+ <li><a href="../scripts_and_streams/index.html#d0e25321">Example&nbsp;10.3.&nbsp;Parsing XML from a string (the easy but inflexible way)</a></li>
+ <li><a href="../scripts_and_streams/index.html#kgp.openanything.stringio.example">Example&nbsp;10.4.&nbsp;Introducing StringIO</a></li>
+ <li><a href="../scripts_and_streams/index.html#d0e25526">Example&nbsp;10.5.&nbsp;Parsing XML from a string (the file-like object way)</a></li>
+ <li><a href="../scripts_and_streams/index.html#kgp.openanything.example">Example&nbsp;10.6.&nbsp;openAnything</a></li>
+ <li><a href="../scripts_and_streams/index.html#d0e25723">Example&nbsp;10.7.&nbsp;Using openAnything in kgp.py</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../scripts_and_streams/stdin_stdout_stderr.html">10.2.&nbsp;Standard input, output, and error</a><p></p>
+ <ul>
+ <li><a href="../scripts_and_streams/stdin_stdout_stderr.html#d0e25781">Example&nbsp;10.8.&nbsp;Introducing stdout and stderr</a></li>
+ <li><a href="../scripts_and_streams/stdin_stdout_stderr.html#d0e25905">Example&nbsp;10.9.&nbsp;Redirecting output</a></li>
+ <li><a href="../scripts_and_streams/stdin_stdout_stderr.html#d0e26005">Example&nbsp;10.10.&nbsp;Redirecting error information</a></li>
+ <li><a href="../scripts_and_streams/stdin_stdout_stderr.html#kgp.stdio.print.example">Example&nbsp;10.11.&nbsp;Printing to stderr</a></li>
+ <li><a href="../scripts_and_streams/stdin_stdout_stderr.html#d0e26136">Example&nbsp;10.12.&nbsp;Chaining commands</a></li>
+ <li><a href="../scripts_and_streams/stdin_stdout_stderr.html#d0e26237">Example&nbsp;10.13.&nbsp;Reading from standard input in kgp.py</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../scripts_and_streams/caching.html">10.3.&nbsp;Caching node lookups</a><p></p>
+ <ul>
+ <li><a href="../scripts_and_streams/caching.html#d0e26362">Example&nbsp;10.14.&nbsp;loadGrammar</a></li>
+ <li><a href="../scripts_and_streams/caching.html#d0e26435">Example&nbsp;10.15.&nbsp;Using the ref element cache</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../scripts_and_streams/child_nodes.html">10.4.&nbsp;Finding direct children of a node</a><p></p>
+ <ul>
+ <li><a href="../scripts_and_streams/child_nodes.html#d0e26500">Example&nbsp;10.16.&nbsp;Finding direct child elements</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../scripts_and_streams/handlers_by_node_type.html">10.5.&nbsp;Creating separate handlers by node type</a><p></p>
+ <ul>
+ <li><a href="../scripts_and_streams/handlers_by_node_type.html#d0e26627">Example&nbsp;10.17.&nbsp;Class names of parsed XML objects</a></li>
+ <li><a href="../scripts_and_streams/handlers_by_node_type.html#d0e26733">Example&nbsp;10.18.&nbsp;parse, a generic XML node dispatcher</a></li>
+ <li><a href="../scripts_and_streams/handlers_by_node_type.html#d0e26769">Example&nbsp;10.19.&nbsp;Functions called by the parse dispatcher</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../scripts_and_streams/command_line_arguments.html">10.6.&nbsp;Handling command-line arguments</a><p></p>
+ <ul>
+ <li><a href="../scripts_and_streams/command_line_arguments.html#d0e26871">Example&nbsp;10.20.&nbsp;Introducing sys.argv</a></li>
+ <li><a href="../scripts_and_streams/command_line_arguments.html#d0e26892">Example&nbsp;10.21.&nbsp;The contents of sys.argv</a></li>
+ <li><a href="../scripts_and_streams/command_line_arguments.html#d0e26982">Example&nbsp;10.22.&nbsp;Introducing getopt</a></li>
+ <li><a href="../scripts_and_streams/command_line_arguments.html#d0e27157">Example&nbsp;10.23.&nbsp;Handling command-line arguments in kgp.py</a></li>
+ </ul>
+ <p></p>
+ </li>
+ </ul>
+ <p><a href="../http_web_services/index.html">Chapter&nbsp;11.&nbsp;HTTP Web Services</a></p>
+ <ul>
+ <li><a href="../http_web_services/index.html#oa.divein">11.1.&nbsp;Diving in</a><p></p>
+ <ul>
+ <li><a href="../http_web_services/index.html#d0e27515">Example&nbsp;11.1.&nbsp;openanything.py</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../http_web_services/review.html">11.2.&nbsp;How not to fetch data over HTTP</a><p></p>
+ <ul>
+ <li><a href="../http_web_services/review.html#d0e27543">Example&nbsp;11.2.&nbsp;Downloading a feed the quick-and-dirty way</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../http_web_services/debugging.html">11.4.&nbsp;Debugging HTTP web services</a><p></p>
+ <ul>
+ <li><a href="../http_web_services/debugging.html#d0e27789">Example&nbsp;11.3.&nbsp;Debugging HTTP</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../http_web_services/user_agent.html">11.5.&nbsp;Setting the User-Agent</a><p></p>
+ <ul>
+ <li><a href="../http_web_services/user_agent.html#d0e27984">Example&nbsp;11.4.&nbsp;Introducing urllib2</a></li>
+ <li><a href="../http_web_services/user_agent.html#d0e28108">Example&nbsp;11.5.&nbsp;Adding headers with the Request</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../http_web_services/etags.html">11.6.&nbsp;Handling Last-Modified and ETag</a><p></p>
+ <ul>
+ <li><a href="../http_web_services/etags.html#oa.etags.example.1">Example&nbsp;11.6.&nbsp;Testing Last-Modified</a></li>
+ <li><a href="../http_web_services/etags.html#d0e28385">Example&nbsp;11.7.&nbsp;Defining URL handlers</a></li>
+ <li><a href="../http_web_services/etags.html#d0e28438">Example&nbsp;11.8.&nbsp;Using custom URL handlers</a></li>
+ <li><a href="../http_web_services/etags.html#oa.etags.example">Example&nbsp;11.9.&nbsp;Supporting ETag/If-None-Match</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../http_web_services/redirects.html">11.7.&nbsp;Handling redirects</a><p></p>
+ <ul>
+ <li><a href="../http_web_services/redirects.html#d0e28730">Example&nbsp;11.10.&nbsp;Accessing web services without a redirect handler</a></li>
+ <li><a href="../http_web_services/redirects.html#d0e28866">Example&nbsp;11.11.&nbsp;Defining the redirect handler</a></li>
+ <li><a href="../http_web_services/redirects.html#d0e28932">Example&nbsp;11.12.&nbsp;Using the redirect handler to detect permanent redirects</a></li>
+ <li><a href="../http_web_services/redirects.html#d0e29025">Example&nbsp;11.13.&nbsp;Using the redirect handler to detect temporary redirects</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../http_web_services/gzip_compression.html">11.8.&nbsp;Handling compressed data</a><p></p>
+ <ul>
+ <li><a href="../http_web_services/gzip_compression.html#d0e29136">Example&nbsp;11.14.&nbsp;Telling the server you would like compressed data</a></li>
+ <li><a href="../http_web_services/gzip_compression.html#d0e29222">Example&nbsp;11.15.&nbsp;Decompressing the data</a></li>
+ <li><a href="../http_web_services/gzip_compression.html#d0e29389">Example&nbsp;11.16.&nbsp;Decompressing the data directly from the server</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../http_web_services/alltogether.html">11.9.&nbsp;Putting it all together</a><p></p>
+ <ul>
+ <li><a href="../http_web_services/alltogether.html#d0e29475">Example&nbsp;11.17.&nbsp;The openanything function</a></li>
+ <li><a href="../http_web_services/alltogether.html#d0e29574">Example&nbsp;11.18.&nbsp;The fetch function</a></li>
+ <li><a href="../http_web_services/alltogether.html#d0e29650">Example&nbsp;11.19.&nbsp;Using openanything.py</a></li>
+ </ul>
+ <p></p>
+ </li>
+ </ul>
+ <p><a href="../soap_web_services/index.html">Chapter&nbsp;12.&nbsp;SOAP Web Services</a></p>
+ <ul>
+ <li><a href="../soap_web_services/index.html#soap.divein">12.1.&nbsp;Diving In</a><p></p>
+ <ul>
+ <li><a href="../soap_web_services/index.html#d0e29893">Example&nbsp;12.1.&nbsp;search.py</a></li>
+ <li><a href="../soap_web_services/index.html#d0e29906">Example&nbsp;12.2.&nbsp;Sample Usage of search.py</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../soap_web_services/install.html#d0e29967">12.2.1.&nbsp;Installing PyXML</a><p></p>
+ <ul>
+ <li><a href="../soap_web_services/install.html#d0e30044">Example&nbsp;12.3.&nbsp;Verifying PyXML Installation</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../soap_web_services/install.html#d0e30070">12.2.2.&nbsp;Installing fpconst</a><p></p>
+ <ul>
+ <li><a href="../soap_web_services/install.html#d0e30145">Example&nbsp;12.4.&nbsp;Verifying fpconst Installation</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../soap_web_services/install.html#d0e30171">12.2.3.&nbsp;Installing SOAPpy</a><p></p>
+ <ul>
+ <li><a href="../soap_web_services/install.html#d0e30237">Example&nbsp;12.5.&nbsp;Verifying SOAPpy Installation</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../soap_web_services/first_steps.html">12.3.&nbsp;First Steps with SOAP</a><p></p>
+ <ul>
+ <li><a href="../soap_web_services/first_steps.html#d0e30286">Example&nbsp;12.6.&nbsp;Getting the Current Temperature</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../soap_web_services/debugging.html">12.4.&nbsp;Debugging SOAP Web Services</a><p></p>
+ <ul>
+ <li><a href="../soap_web_services/debugging.html#d0e30423">Example&nbsp;12.7.&nbsp;Debugging SOAP Web Services</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../soap_web_services/introspection.html">12.6.&nbsp;Introspecting SOAP Web Services with WSDL</a><p></p>
+ <ul>
+ <li><a href="../soap_web_services/introspection.html#d0e30755">Example&nbsp;12.8.&nbsp;Discovering The Available Methods</a></li>
+ <li><a href="../soap_web_services/introspection.html#d0e30857">Example&nbsp;12.9.&nbsp;Discovering A Method's Arguments</a></li>
+ <li><a href="../soap_web_services/introspection.html#d0e30967">Example&nbsp;12.10.&nbsp;Discovering A Method's Return Values</a></li>
+ <li><a href="../soap_web_services/introspection.html#d0e31039">Example&nbsp;12.11.&nbsp;Calling A Web Service Through A WSDL Proxy</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../soap_web_services/google.html">12.7.&nbsp;Searching Google</a><p></p>
+ <ul>
+ <li><a href="../soap_web_services/google.html#d0e31206">Example&nbsp;12.12.&nbsp;Introspecting Google Web Services</a></li>
+ <li><a href="../soap_web_services/google.html#d0e31392">Example&nbsp;12.13.&nbsp;Searching Google</a></li>
+ <li><a href="../soap_web_services/google.html#d0e31503">Example&nbsp;12.14.&nbsp;Accessing Secondary Information From Google</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../soap_web_services/troubleshooting.html">12.8.&nbsp;Troubleshooting SOAP Web Services</a><p></p>
+ <ul>
+ <li><a href="../soap_web_services/troubleshooting.html#d0e31615">Example&nbsp;12.15.&nbsp;Calling a Method With an Incorrectly Configured Proxy</a></li>
+ <li><a href="../soap_web_services/troubleshooting.html#d0e31701">Example&nbsp;12.16.&nbsp;Calling a Method With the Wrong Arguments</a></li>
+ <li><a href="../soap_web_services/troubleshooting.html#d0e31779">Example&nbsp;12.17.&nbsp;Calling a Method and Expecting the Wrong Number of Return Values</a></li>
+ <li><a href="../soap_web_services/troubleshooting.html#d0e31834">Example&nbsp;12.18.&nbsp;Calling a Method With An Application-Specific Error</a></li>
+ </ul>
+ <p></p>
+ </li>
+ </ul>
+ <p><a href="../unit_testing/index.html">Chapter&nbsp;13.&nbsp;Unit Testing</a></p>
+ <ul>
+ <li><a href="../unit_testing/romantest.html">13.3.&nbsp;Introducing romantest.py</a><p></p>
+ <ul>
+ <li><a href="../unit_testing/romantest.html#d0e32173">Example&nbsp;13.1.&nbsp;romantest.py</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../unit_testing/testing_for_success.html">13.4.&nbsp;Testing for success</a><p></p>
+ <ul>
+ <li><a href="../unit_testing/testing_for_success.html#roman.testtoromanknownvalues.example">Example&nbsp;13.2.&nbsp;testToRomanKnownValues</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../unit_testing/testing_for_failure.html">13.5.&nbsp;Testing for failure</a><p></p>
+ <ul>
+ <li><a href="../unit_testing/testing_for_failure.html#roman.tobadinput.example">Example&nbsp;13.3.&nbsp;Testing bad input to toRoman</a></li>
+ <li><a href="../unit_testing/testing_for_failure.html#roman.frombadinput.example">Example&nbsp;13.4.&nbsp;Testing bad input to fromRoman</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../unit_testing/testing_for_sanity.html">13.6.&nbsp;Testing for sanity</a><p></p>
+ <ul>
+ <li><a href="../unit_testing/testing_for_sanity.html#roman.sanity.example">Example&nbsp;13.5.&nbsp;Testing toRoman against fromRoman</a></li>
+ <li><a href="../unit_testing/testing_for_sanity.html#d0e32750">Example&nbsp;13.6.&nbsp;Testing for case</a></li>
+ </ul>
+ <p></p>
+ </li>
+ </ul>
+ <p><a href="../unit_testing/stage_1.html">Chapter&nbsp;14.&nbsp;Test-First Programming</a></p>
+ <ul>
+ <li><a href="../unit_testing/stage_1.html#roman.stage1">14.1.&nbsp;roman.py, stage 1</a><p></p>
+ <ul>
+ <li><a href="../unit_testing/stage_1.html#d0e32864">Example&nbsp;14.1.&nbsp;roman1.py</a></li>
+ <li><a href="../unit_testing/stage_1.html#roman.stage1.output">Example&nbsp;14.2.&nbsp;Output of romantest1.py against roman1.py</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../unit_testing/stage_2.html">14.2.&nbsp;roman.py, stage 2</a><p></p>
+ <ul>
+ <li><a href="../unit_testing/stage_2.html#roman.stage2.example">Example&nbsp;14.3.&nbsp;roman2.py</a></li>
+ <li><a href="../unit_testing/stage_2.html#d0e33197">Example&nbsp;14.4.&nbsp;How toRoman works</a></li>
+ <li><a href="../unit_testing/stage_2.html#d0e33236">Example&nbsp;14.5.&nbsp;Output of romantest2.py against roman2.py</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../unit_testing/stage_3.html">14.3.&nbsp;roman.py, stage 3</a><p></p>
+ <ul>
+ <li><a href="../unit_testing/stage_3.html#d0e33364">Example&nbsp;14.6.&nbsp;roman3.py</a></li>
+ <li><a href="../unit_testing/stage_3.html#d0e33410">Example&nbsp;14.7.&nbsp;Watching toRoman handle bad input</a></li>
+ <li><a href="../unit_testing/stage_3.html#d0e33439">Example&nbsp;14.8.&nbsp;Output of romantest3.py against roman3.py</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../unit_testing/stage_4.html">14.4.&nbsp;roman.py, stage 4</a><p></p>
+ <ul>
+ <li><a href="../unit_testing/stage_4.html#d0e33582">Example&nbsp;14.9.&nbsp;roman4.py</a></li>
+ <li><a href="../unit_testing/stage_4.html#d0e33611">Example&nbsp;14.10.&nbsp;How fromRoman works</a></li>
+ <li><a href="../unit_testing/stage_4.html#d0e33644">Example&nbsp;14.11.&nbsp;Output of romantest4.py against roman4.py</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../unit_testing/stage_5.html">14.5.&nbsp;roman.py, stage 5</a><p></p>
+ <ul>
+ <li><a href="../unit_testing/stage_5.html#d0e34010">Example&nbsp;14.12.&nbsp;roman5.py</a></li>
+ <li><a href="../unit_testing/stage_5.html#d0e34080">Example&nbsp;14.13.&nbsp;Output of romantest5.py against roman5.py</a></li>
+ </ul>
+ <p></p>
+ </li>
+ </ul>
+ <p><a href="../refactoring/index.html">Chapter&nbsp;15.&nbsp;Refactoring</a></p>
+ <ul>
+ <li><a href="../refactoring/index.html#roman.bugs">15.1.&nbsp;Handling bugs</a><p></p>
+ <ul>
+ <li><a href="../refactoring/index.html#d0e34158">Example&nbsp;15.1.&nbsp;The bug</a></li>
+ <li><a href="../refactoring/index.html#d0e34188">Example&nbsp;15.2.&nbsp;Testing for the bug (romantest61.py)</a></li>
+ <li><a href="../refactoring/index.html#d0e34210">Example&nbsp;15.3.&nbsp;Output of romantest61.py against roman61.py</a></li>
+ <li><a href="../refactoring/index.html#d0e34229">Example&nbsp;15.4.&nbsp;Fixing the bug (roman62.py)</a></li>
+ <li><a href="../refactoring/index.html#d0e34251">Example&nbsp;15.5.&nbsp;Output of romantest62.py against roman62.py</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../refactoring/handling_changing_requirements.html">15.2.&nbsp;Handling changing requirements</a><p></p>
+ <ul>
+ <li><a href="../refactoring/handling_changing_requirements.html#d0e34307">Example&nbsp;15.6.&nbsp;Modifying test cases for new requirements (romantest71.py)</a></li>
+ <li><a href="../refactoring/handling_changing_requirements.html#d0e34405">Example&nbsp;15.7.&nbsp;Output of romantest71.py against roman71.py</a></li>
+ <li><a href="../refactoring/handling_changing_requirements.html#d0e34511">Example&nbsp;15.8.&nbsp;Coding the new requirements (roman72.py)</a></li>
+ <li><a href="../refactoring/handling_changing_requirements.html#roman.roman72.output">Example&nbsp;15.9.&nbsp;Output of romantest72.py against roman72.py</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../refactoring/refactoring.html">15.3.&nbsp;Refactoring</a><p></p>
+ <ul>
+ <li><a href="../refactoring/refactoring.html#d0e34647">Example&nbsp;15.10.&nbsp;Compiling regular expressions</a></li>
+ <li><a href="../refactoring/refactoring.html#d0e34769">Example&nbsp;15.11.&nbsp;Compiled regular expressions in roman81.py</a></li>
+ <li><a href="../refactoring/refactoring.html#roman.stage8.1.output">Example&nbsp;15.12.&nbsp;Output of romantest81.py against roman81.py</a></li>
+ <li><a href="../refactoring/refactoring.html#d0e34895">Example&nbsp;15.13.&nbsp;roman82.py</a></li>
+ <li><a href="../refactoring/refactoring.html#d0e34949">Example&nbsp;15.14.&nbsp;Output of romantest82.py against roman82.py</a></li>
+ <li><a href="../refactoring/refactoring.html#d0e35003">Example&nbsp;15.15.&nbsp;roman83.py</a></li>
+ <li><a href="../refactoring/refactoring.html#d0e35043">Example&nbsp;15.16.&nbsp;Output of romantest83.py against roman83.py</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../refactoring/postscript.html">15.4.&nbsp;Postscript</a><p></p>
+ <ul>
+ <li><a href="../refactoring/postscript.html#d0e35088">Example&nbsp;15.17.&nbsp;roman9.py</a></li>
+ <li><a href="../refactoring/postscript.html#d0e35106">Example&nbsp;15.18.&nbsp;Output of romantest9.py against roman9.py</a></li>
+ </ul>
+ <p></p>
+ </li>
+ </ul>
+ <p><a href="../functional_programming/index.html">Chapter&nbsp;16.&nbsp;Functional Programming</a></p>
+ <ul>
+ <li><a href="../functional_programming/index.html#regression.divein">16.1.&nbsp;Diving in</a><p></p>
+ <ul>
+ <li><a href="../functional_programming/index.html#d0e35275">Example&nbsp;16.1.&nbsp;regression.py</a></li>
+ <li><a href="../functional_programming/index.html#d0e35293">Example&nbsp;16.2.&nbsp;Sample output of regression.py</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../functional_programming/finding_the_path.html">16.2.&nbsp;Finding the path</a><p></p>
+ <ul>
+ <li><a href="../functional_programming/finding_the_path.html#d0e35359">Example&nbsp;16.3.&nbsp;fullpath.py</a></li>
+ <li><a href="../functional_programming/finding_the_path.html#d0e35399">Example&nbsp;16.4.&nbsp;Further explanation of os.path.abspath</a></li>
+ <li><a href="../functional_programming/finding_the_path.html#d0e35527">Example&nbsp;16.5.&nbsp;Sample output from fullpath.py</a></li>
+ <li><a href="../functional_programming/finding_the_path.html#regression.path.cwd.example">Example&nbsp;16.6.&nbsp;Running scripts in the current directory</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../functional_programming/filtering_lists.html">16.3.&nbsp;Filtering lists revisited</a><p></p>
+ <ul>
+ <li><a href="../functional_programming/filtering_lists.html#d0e35724">Example&nbsp;16.7.&nbsp;Introducing filter</a></li>
+ <li><a href="../functional_programming/filtering_lists.html#d0e35864">Example&nbsp;16.8.&nbsp;filter in regression.py</a></li>
+ <li><a href="../functional_programming/filtering_lists.html#d0e35972">Example&nbsp;16.9.&nbsp;Filtering using list comprehensions instead</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../functional_programming/mapping_lists.html">16.4.&nbsp;Mapping lists revisited</a><p></p>
+ <ul>
+ <li><a href="../functional_programming/mapping_lists.html#d0e36003">Example&nbsp;16.10.&nbsp;Introducing map</a></li>
+ <li><a href="../functional_programming/mapping_lists.html#d0e36107">Example&nbsp;16.11.&nbsp;map with lists of mixed datatypes</a></li>
+ <li><a href="../functional_programming/mapping_lists.html#d0e36143">Example&nbsp;16.12.&nbsp;map in regression.py</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../functional_programming/dynamic_import.html">16.6.&nbsp;Dynamically importing modules</a><p></p>
+ <ul>
+ <li><a href="../functional_programming/dynamic_import.html#d0e36316">Example&nbsp;16.13.&nbsp;Importing multiple modules at once</a></li>
+ <li><a href="../functional_programming/dynamic_import.html#d0e36341">Example&nbsp;16.14.&nbsp;Importing modules dynamically</a></li>
+ <li><a href="../functional_programming/dynamic_import.html#d0e36423">Example&nbsp;16.15.&nbsp;Importing a list of modules dynamically</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../functional_programming/all_together.html">16.7.&nbsp;Putting it all together</a><p></p>
+ <ul>
+ <li><a href="../functional_programming/all_together.html#d0e36538">Example&nbsp;16.16.&nbsp;The regressionTest function</a></li>
+ <li><a href="../functional_programming/all_together.html#d0e36556">Example&nbsp;16.17.&nbsp;Step 1: Get all the files</a></li>
+ <li><a href="../functional_programming/all_together.html#d0e36595">Example&nbsp;16.18.&nbsp;Step 2: Filter to find the files you care about</a></li>
+ <li><a href="../functional_programming/all_together.html#d0e36643">Example&nbsp;16.19.&nbsp;Step 3: Map filenames to module names</a></li>
+ <li><a href="../functional_programming/all_together.html#d0e36727">Example&nbsp;16.20.&nbsp;Step 4: Mapping module names to modules</a></li>
+ <li><a href="../functional_programming/all_together.html#d0e36788">Example&nbsp;16.21.&nbsp;Step 5: Loading the modules into a test suite</a></li>
+ <li><a href="../functional_programming/all_together.html#d0e36869">Example&nbsp;16.22.&nbsp;Step 6: Telling unittest to use your test suite</a></li>
+ </ul>
+ <p></p>
+ </li>
+ </ul>
+ <p><a href="../dynamic_functions/index.html">Chapter&nbsp;17.&nbsp;Dynamic functions</a></p>
+ <ul>
+ <li><a href="../dynamic_functions/stage1.html">17.2.&nbsp;plural.py, stage 1</a><p></p>
+ <ul>
+ <li><a href="../dynamic_functions/stage1.html#d0e37108">Example&nbsp;17.1.&nbsp;plural1.py</a></li>
+ <li><a href="../dynamic_functions/stage1.html#d0e37161">Example&nbsp;17.2.&nbsp;Introducing re.sub</a></li>
+ <li><a href="../dynamic_functions/stage1.html#d0e37292">Example&nbsp;17.3.&nbsp;Back to plural1.py</a></li>
+ <li><a href="../dynamic_functions/stage1.html#d0e37404">Example&nbsp;17.4.&nbsp;More on negation regular expressions</a></li>
+ <li><a href="../dynamic_functions/stage1.html#d0e37507">Example&nbsp;17.5.&nbsp;More on re.sub</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../dynamic_functions/stage2.html">17.3.&nbsp;plural.py, stage 2</a><p></p>
+ <ul>
+ <li><a href="../dynamic_functions/stage2.html#d0e37629">Example&nbsp;17.6.&nbsp;plural2.py</a></li>
+ <li><a href="../dynamic_functions/stage2.html#d0e37727">Example&nbsp;17.7.&nbsp;Unrolling the plural function</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../dynamic_functions/stage3.html">17.4.&nbsp;plural.py, stage 3</a><p></p>
+ <ul>
+ <li><a href="../dynamic_functions/stage3.html#d0e37775">Example&nbsp;17.8.&nbsp;plural3.py</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../dynamic_functions/stage4.html">17.5.&nbsp;plural.py, stage 4</a><p></p>
+ <ul>
+ <li><a href="../dynamic_functions/stage4.html#plural.stage4.example.1">Example&nbsp;17.9.&nbsp;plural4.py</a></li>
+ <li><a href="../dynamic_functions/stage4.html#d0e37935">Example&nbsp;17.10.&nbsp;plural4.py continued</a></li>
+ <li><a href="../dynamic_functions/stage4.html#d0e37982">Example&nbsp;17.11.&nbsp;Unrolling the rules definition</a></li>
+ <li><a href="../dynamic_functions/stage4.html#plural.finishing.up">Example&nbsp;17.12.&nbsp;plural4.py, finishing up</a></li>
+ <li><a href="../dynamic_functions/stage4.html#d0e38026">Example&nbsp;17.13.&nbsp;Another look at buildMatchAndApplyFunctions</a></li>
+ <li><a href="../dynamic_functions/stage4.html#d0e38048">Example&nbsp;17.14.&nbsp;Expanding tuples when calling functions</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../dynamic_functions/stage5.html">17.6.&nbsp;plural.py, stage 5</a><p></p>
+ <ul>
+ <li><a href="../dynamic_functions/stage5.html#d0e38148">Example&nbsp;17.15.&nbsp;rules.en</a></li>
+ <li><a href="../dynamic_functions/stage5.html#d0e38156">Example&nbsp;17.16.&nbsp;plural5.py</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../dynamic_functions/stage6.html">17.7.&nbsp;plural.py, stage 6</a><p></p>
+ <ul>
+ <li><a href="../dynamic_functions/stage6.html#d0e38279">Example&nbsp;17.17.&nbsp;plural6.py</a></li>
+ <li><a href="../dynamic_functions/stage6.html#plural.introducing.generators">Example&nbsp;17.18.&nbsp;Introducing generators</a></li>
+ <li><a href="../dynamic_functions/stage6.html#plural.fib.example">Example&nbsp;17.19.&nbsp;Using generators instead of recursion</a></li>
+ <li><a href="../dynamic_functions/stage6.html#d0e38564">Example&nbsp;17.20.&nbsp;Generators in for loops</a></li>
+ <li><a href="../dynamic_functions/stage6.html#d0e38646">Example&nbsp;17.21.&nbsp;Generators that generate dynamic functions</a></li>
+ </ul>
+ <p></p>
+ </li>
+ </ul>
+ <p><a href="../performance_tuning/index.html">Chapter&nbsp;18.&nbsp;Performance Tuning</a></p>
+ <ul>
+ <li><a href="../performance_tuning/index.html#soundex.divein">18.1.&nbsp;Diving in</a><p></p>
+ <ul>
+ <li><a href="../performance_tuning/index.html#d0e38889">Example&nbsp;18.1.&nbsp;soundex/stage1/soundex1a.py</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../performance_tuning/timeit.html">18.2.&nbsp;Using the timeit Module</a><p></p>
+ <ul>
+ <li><a href="../performance_tuning/timeit.html#d0e38948">Example&nbsp;18.2.&nbsp;Introducing timeit</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../performance_tuning/regular_expressions.html">18.3.&nbsp;Optimizing Regular Expressions</a><p></p>
+ <ul>
+ <li><a href="../performance_tuning/regular_expressions.html#d0e39318">Example&nbsp;18.3.&nbsp;Best Result So Far: soundex/stage1/soundex1e.py</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../performance_tuning/dictionary_lookups.html">18.4.&nbsp;Optimizing Dictionary Lookups</a><p></p>
+ <ul>
+ <li><a href="../performance_tuning/dictionary_lookups.html#d0e39507">Example&nbsp;18.4.&nbsp;Best Result So Far: soundex/stage2/soundex2c.py</a></li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../performance_tuning/list_operations.html">18.5.&nbsp;Optimizing List Operations</a><p></p>
+ <ul>
+ <li><a href="../performance_tuning/list_operations.html#d0e39674">Example&nbsp;18.5.&nbsp;Best Result So Far: soundex/stage2/soundex2c.py</a></li>
+ </ul>
+ <p></p>
+ </li>
+ </ul>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="tips.html">&lt;&lt;&nbsp;Tips and tricks</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="history.html">Revision history&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/appendix/fdl.html b/help/diveintopython-5.4/html/appendix/fdl.html
new file mode 100644
index 0000000..3497f91
--- /dev/null
+++ b/help/diveintopython-5.4/html/appendix/fdl.html
@@ -0,0 +1,124 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>Appendix&nbsp;G.&nbsp;GNU Free Documentation License</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="../toc/index.html" title="Dive Into Python">
+ <link rel="previous" href="about.html" title="Appendix&nbsp;F.&nbsp;About the book">
+ <link rel="next" href="fdl_applicability.html" title="G.1.&nbsp;Applicability and definitions">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<span class="thispage">GNU Free Documentation License</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="about.html" title="Prev: &#8220;About the book&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="fdl_applicability.html" title="Next: &#8220;Applicability and definitions&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="appendix" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="gfdl"></a>Appendix&nbsp;G.&nbsp;<span class="acronym">GNU</span> Free Documentation License
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="toc">
+ <ul>
+ <li><span class="section"><a href="fdl.html#d0e40006">G.0. Preamble</a></span></li>
+ <li><span class="section"><a href="fdl_applicability.html">G.1. Applicability and definitions</a></span></li>
+ <li><span class="section"><a href="fdl_copying.html">G.2. Verbatim copying</a></span></li>
+ <li><span class="section"><a href="fdl_copyinginquantity.html">G.3. Copying in quantity</a></span></li>
+ <li><span class="section"><a href="fdl_modifications.html">G.4. Modifications</a></span></li>
+ <li><span class="section"><a href="fdl_combining.html">G.5. Combining documents</a></span></li>
+ <li><span class="section"><a href="fdl_collections.html">G.6. Collections of documents</a></span></li>
+ <li><span class="section"><a href="fdl_aggregation.html">G.7. Aggregation with independent works</a></span></li>
+ <li><span class="section"><a href="fdl_translation.html">G.8. Translation</a></span></li>
+ <li><span class="section"><a href="fdl_termination.html">G.9. Termination</a></span></li>
+ <li><span class="section"><a href="fdl_future.html">G.10. Future revisions of this license</a></span></li>
+ <li><span class="section"><a href="fdl_howto.html">G.11. How to use this License for your documents</a></span></li>
+ </ul>
+ </div>
+ <p>Version 1.1, March 2000</p>
+ <div class="blockquote">
+ <blockquote class="blockquote">
+ <p>Copyright (C) 2000 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+ </p>
+ </blockquote>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="d0e40006"></a>G.0.&nbsp;Preamble
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p>The purpose of this License is to make a manual, textbook,
+ or other written document "free" in the sense of freedom: to
+ assure everyone the effective freedom to copy and redistribute it,
+ with or without modifying it, either commercially or
+ noncommercially. Secondarily, this License preserves for the
+ author and publisher a way to get credit for their work, while not
+ being considered responsible for modifications made by
+ others.
+ </p>
+ <p>This License is a kind of "copyleft", which means that
+ derivative works of the document must themselves be free in the
+ same sense. It complements the GNU General Public License, which
+ is a copyleft license designed for free software.
+ </p>
+ <p>We have designed this License in order to use it for manuals
+ for free software, because free software needs free documentation:
+ a free program should come with manuals providing the same
+ freedoms that the software does. But this License is not limited
+ to software manuals; it can be used for any textual work,
+ regardless of subject matter or whether it is published as a
+ printed book. We recommend this License principally for works
+ whose purpose is instruction or reference.
+ </p>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="about.html">&lt;&lt;&nbsp;About the book</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<span class="thispage">1</span> <span class="divider">|</span> <a href="fdl_applicability.html" title="G.1.&nbsp;Applicability and definitions">2</a> <span class="divider">|</span> <a href="fdl_copying.html" title="G.2.&nbsp;Verbatim copying">3</a> <span class="divider">|</span> <a href="fdl_copyinginquantity.html" title="G.3.&nbsp;Copying in quantity">4</a> <span class="divider">|</span> <a href="fdl_modifications.html" title="G.4.&nbsp;Modifications">5</a> <span class="divider">|</span> <a href="fdl_combining.html" title="G.5.&nbsp;Combining documents">6</a> <span class="divider">|</span> <a href="fdl_collections.html" title="G.6.&nbsp;Collections of documents">7</a> <span class="divider">|</span> <a href="fdl_aggregation.html" title="G.7.&nbsp;Aggregation with independent works">8</a> <span class="divider">|</span> <a href="fdl_translation.html" title="G.8.&nbsp;Translation">9</a> <span class="divider">|</span> <a href="fdl_termination.html" title="G.9.&nbsp;Termination">10</a> <span class="divider">|</span> <a href="fdl_future.html" title="G.10.&nbsp;Future revisions of this license">11</a> <span class="divider">|</span> <a href="fdl_howto.html" title="G.11.&nbsp;How to use this License for your documents">12</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="fdl_applicability.html">Applicability and definitions&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/appendix/fdl_aggregation.html b/help/diveintopython-5.4/html/appendix/fdl_aggregation.html
new file mode 100644
index 0000000..cb14676
--- /dev/null
+++ b/help/diveintopython-5.4/html/appendix/fdl_aggregation.html
@@ -0,0 +1,81 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>G.7.&nbsp;Aggregation with independent works</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="fdl.html" title="Appendix&nbsp;G.&nbsp;GNU Free Documentation License">
+ <link rel="previous" href="fdl_collections.html" title="G.6.&nbsp;Collections of documents">
+ <link rel="next" href="fdl_translation.html" title="G.8.&nbsp;Translation">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="fdl.html">GNU Free Documentation License</a>&nbsp;&gt;&nbsp;<span class="thispage">Aggregation with independent works</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="fdl_collections.html" title="Prev: &#8220;Collections of documents&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="fdl_translation.html" title="Next: &#8220;Translation&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="d0e40130"></a>G.7.&nbsp;Aggregation with independent works
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p>A compilation of the Document or its derivatives with other
+ separate and independent documents or works, in or on a volume of
+ a storage or distribution medium, does not as a whole count as a
+ Modified Version of the Document, provided no compilation
+ copyright is claimed for the compilation. Such a compilation is
+ called an "aggregate", and this License does not apply to the
+ other self-contained works thus compiled with the Document, on
+ account of their being thus compiled, if they are not themselves
+ derivative works of the Document.
+ </p>
+ <p>If the Cover Text requirement of section 3 is applicable to
+ these copies of the Document, then if the Document is less than
+ one quarter of the entire aggregate, the Document's Cover Texts
+ may be placed on covers that surround only the Document within the
+ aggregate. Otherwise they must appear on covers around the whole
+ aggregate.
+ </p>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="fdl_collections.html">&lt;&lt;&nbsp;Collections of documents</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="fdl.html#d0e40006" title="G.0.&nbsp;Preamble">1</a> <span class="divider">|</span> <a href="fdl_applicability.html" title="G.1.&nbsp;Applicability and definitions">2</a> <span class="divider">|</span> <a href="fdl_copying.html" title="G.2.&nbsp;Verbatim copying">3</a> <span class="divider">|</span> <a href="fdl_copyinginquantity.html" title="G.3.&nbsp;Copying in quantity">4</a> <span class="divider">|</span> <a href="fdl_modifications.html" title="G.4.&nbsp;Modifications">5</a> <span class="divider">|</span> <a href="fdl_combining.html" title="G.5.&nbsp;Combining documents">6</a> <span class="divider">|</span> <a href="fdl_collections.html" title="G.6.&nbsp;Collections of documents">7</a> <span class="divider">|</span> <span class="thispage">8</span> <span class="divider">|</span> <a href="fdl_translation.html" title="G.8.&nbsp;Translation">9</a> <span class="divider">|</span> <a href="fdl_termination.html" title="G.9.&nbsp;Termination">10</a> <span class="divider">|</span> <a href="fdl_future.html" title="G.10.&nbsp;Future revisions of this license">11</a> <span class="divider">|</span> <a href="fdl_howto.html" title="G.11.&nbsp;How to use this License for your documents">12</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="fdl_translation.html">Translation&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/appendix/fdl_applicability.html b/help/diveintopython-5.4/html/appendix/fdl_applicability.html
new file mode 100644
index 0000000..347dc28
--- /dev/null
+++ b/help/diveintopython-5.4/html/appendix/fdl_applicability.html
@@ -0,0 +1,128 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>G.1.&nbsp;Applicability and definitions</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="fdl.html" title="Appendix&nbsp;G.&nbsp;GNU Free Documentation License">
+ <link rel="previous" href="fdl.html" title="Appendix&nbsp;G.&nbsp;GNU Free Documentation License">
+ <link rel="next" href="fdl_copying.html" title="G.2.&nbsp;Verbatim copying">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="fdl.html">GNU Free Documentation License</a>&nbsp;&gt;&nbsp;<span class="thispage">Applicability and definitions</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="fdl.html" title="Prev: &#8220;GNU Free Documentation License&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="fdl_copying.html" title="Next: &#8220;Verbatim copying&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="d0e40015"></a>G.1.&nbsp;Applicability and definitions
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p>This License applies to any manual or other work that
+ contains a notice placed by the copyright holder saying it can be
+ distributed under the terms of this License. The "Document",
+ below, refers to any such manual or work. Any member of the
+ public is a licensee, and is addressed as "you".
+ </p>
+ <p>A "Modified Version" of the Document means any work
+ containing the Document or a portion of it, either copied
+ verbatim, or with modifications and/or translated into another
+ language.
+ </p>
+ <p>A "Secondary Section" is a named appendix or a front-matter
+ section of the Document that deals exclusively with the
+ relationship of the publishers or authors of the Document to the
+ Document's overall subject (or to related matters) and contains
+ nothing that could fall directly within that overall subject.
+ (For example, if the Document is in part a textbook of
+ mathematics, a Secondary Section may not explain any mathematics.)
+ The relationship could be a matter of historical connection with
+ the subject or with related matters, or of legal, commercial,
+ philosophical, ethical or political position regarding
+ them.
+ </p>
+ <p>The "Invariant Sections" are certain Secondary Sections
+ whose titles are designated, as being those of Invariant Sections,
+ in the notice that says that the Document is released under this
+ License.
+ </p>
+ <p>The "Cover Texts" are certain short passages of text that
+ are listed, as Front-Cover Texts or Back-Cover Texts, in the
+ notice that says that the Document is released under this
+ License.
+ </p>
+ <p>A "Transparent" copy of the Document means a
+ machine-readable copy, represented in a format whose specification
+ is available to the general public, whose contents can be viewed
+ and edited directly and straightforwardly with generic text
+ editors or (for images composed of pixels) generic paint programs
+ or (for drawings) some widely available drawing editor, and that
+ is suitable for input to text formatters or for automatic
+ translation to a variety of formats suitable for input to text
+ formatters. A copy made in an otherwise Transparent file format
+ whose markup has been designed to thwart or discourage subsequent
+ modification by readers is not Transparent. A copy that is not
+ "Transparent" is called "Opaque".
+ </p>
+ <p>Examples of suitable formats for Transparent copies include
+ plain ASCII without markup, Texinfo input format, LaTeX input
+ format, SGML or XML using a publicly available DTD, and
+ standard-conforming simple HTML designed for human modification.
+ Opaque formats include PostScript, PDF, proprietary formats that
+ can be read and edited only by proprietary word processors, SGML
+ or XML for which the DTD and/or processing tools are not generally
+ available, and the machine-generated HTML produced by some word
+ processors for output purposes only.
+ </p>
+ <p>The "Title Page" means, for a printed book, the title page
+ itself, plus such following pages as are needed to hold, legibly,
+ the material this License requires to appear in the title page.
+ For works in formats which do not have any title page as such,
+ "Title Page" means the text near the most prominent appearance of
+ the work's title, preceding the beginning of the body of the
+ text.
+ </p>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="fdl.html">&lt;&lt;&nbsp;GNU Free Documentation License</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="fdl.html#d0e40006" title="G.0.&nbsp;Preamble">1</a> <span class="divider">|</span> <span class="thispage">2</span> <span class="divider">|</span> <a href="fdl_copying.html" title="G.2.&nbsp;Verbatim copying">3</a> <span class="divider">|</span> <a href="fdl_copyinginquantity.html" title="G.3.&nbsp;Copying in quantity">4</a> <span class="divider">|</span> <a href="fdl_modifications.html" title="G.4.&nbsp;Modifications">5</a> <span class="divider">|</span> <a href="fdl_combining.html" title="G.5.&nbsp;Combining documents">6</a> <span class="divider">|</span> <a href="fdl_collections.html" title="G.6.&nbsp;Collections of documents">7</a> <span class="divider">|</span> <a href="fdl_aggregation.html" title="G.7.&nbsp;Aggregation with independent works">8</a> <span class="divider">|</span> <a href="fdl_translation.html" title="G.8.&nbsp;Translation">9</a> <span class="divider">|</span> <a href="fdl_termination.html" title="G.9.&nbsp;Termination">10</a> <span class="divider">|</span> <a href="fdl_future.html" title="G.10.&nbsp;Future revisions of this license">11</a> <span class="divider">|</span> <a href="fdl_howto.html" title="G.11.&nbsp;How to use this License for your documents">12</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="fdl_copying.html">Verbatim copying&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/appendix/fdl_collections.html b/help/diveintopython-5.4/html/appendix/fdl_collections.html
new file mode 100644
index 0000000..7e73323
--- /dev/null
+++ b/help/diveintopython-5.4/html/appendix/fdl_collections.html
@@ -0,0 +1,77 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>G.6.&nbsp;Collections of documents</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="fdl.html" title="Appendix&nbsp;G.&nbsp;GNU Free Documentation License">
+ <link rel="previous" href="fdl_combining.html" title="G.5.&nbsp;Combining documents">
+ <link rel="next" href="fdl_aggregation.html" title="G.7.&nbsp;Aggregation with independent works">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="fdl.html">GNU Free Documentation License</a>&nbsp;&gt;&nbsp;<span class="thispage">Collections of documents</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="fdl_combining.html" title="Prev: &#8220;Combining documents&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="fdl_aggregation.html" title="Next: &#8220;Aggregation with independent works&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="d0e40122"></a>G.6.&nbsp;Collections of documents
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p>You may make a collection consisting of the Document and
+ other documents released under this License, and replace the
+ individual copies of this License in the various documents with a
+ single copy that is included in the collection, provided that you
+ follow the rules of this License for verbatim copying of each of
+ the documents in all other respects.
+ </p>
+ <p>You may extract a single document from such a collection,
+ and distribute it individually under this License, provided you
+ insert a copy of this License into the extracted document, and
+ follow this License in all other respects regarding verbatim
+ copying of that document.
+ </p>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="fdl_combining.html">&lt;&lt;&nbsp;Combining documents</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="fdl.html#d0e40006" title="G.0.&nbsp;Preamble">1</a> <span class="divider">|</span> <a href="fdl_applicability.html" title="G.1.&nbsp;Applicability and definitions">2</a> <span class="divider">|</span> <a href="fdl_copying.html" title="G.2.&nbsp;Verbatim copying">3</a> <span class="divider">|</span> <a href="fdl_copyinginquantity.html" title="G.3.&nbsp;Copying in quantity">4</a> <span class="divider">|</span> <a href="fdl_modifications.html" title="G.4.&nbsp;Modifications">5</a> <span class="divider">|</span> <a href="fdl_combining.html" title="G.5.&nbsp;Combining documents">6</a> <span class="divider">|</span> <span class="thispage">7</span> <span class="divider">|</span> <a href="fdl_aggregation.html" title="G.7.&nbsp;Aggregation with independent works">8</a> <span class="divider">|</span> <a href="fdl_translation.html" title="G.8.&nbsp;Translation">9</a> <span class="divider">|</span> <a href="fdl_termination.html" title="G.9.&nbsp;Termination">10</a> <span class="divider">|</span> <a href="fdl_future.html" title="G.10.&nbsp;Future revisions of this license">11</a> <span class="divider">|</span> <a href="fdl_howto.html" title="G.11.&nbsp;How to use this License for your documents">12</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="fdl_aggregation.html">Aggregation with independent works&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/appendix/fdl_combining.html b/help/diveintopython-5.4/html/appendix/fdl_combining.html
new file mode 100644
index 0000000..cf51d1f
--- /dev/null
+++ b/help/diveintopython-5.4/html/appendix/fdl_combining.html
@@ -0,0 +1,87 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>G.5.&nbsp;Combining documents</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="fdl.html" title="Appendix&nbsp;G.&nbsp;GNU Free Documentation License">
+ <link rel="previous" href="fdl_modifications.html" title="G.4.&nbsp;Modifications">
+ <link rel="next" href="fdl_collections.html" title="G.6.&nbsp;Collections of documents">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="fdl.html">GNU Free Documentation License</a>&nbsp;&gt;&nbsp;<span class="thispage">Combining documents</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="fdl_modifications.html" title="Prev: &#8220;Modifications&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="fdl_collections.html" title="Next: &#8220;Collections of documents&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="d0e40112"></a>G.5.&nbsp;Combining documents
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p>You may combine the Document with other documents released
+ under this License, under the terms defined in section 4 above for
+ modified versions, provided that you include in the combination
+ all of the Invariant Sections of all of the original documents,
+ unmodified, and list them all as Invariant Sections of your
+ combined work in its license notice.
+ </p>
+ <p>The combined work need only contain one copy of this
+ License, and multiple identical Invariant Sections may be replaced
+ with a single copy. If there are multiple Invariant Sections with
+ the same name but different contents, make the title of each such
+ section unique by adding at the end of it, in parentheses, the
+ name of the original author or publisher of that section if known,
+ or else a unique number. Make the same adjustment to the section
+ titles in the list of Invariant Sections in the license notice of
+ the combined work.
+ </p>
+ <p>In the combination, you must combine any sections entitled
+ "History" in the various original documents, forming one section
+ entitled "History"; likewise combine any sections entitled
+ "Acknowledgements", and any sections entitled "Dedications". You
+ must delete all sections entitled "Endorsements."
+ </p>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="fdl_modifications.html">&lt;&lt;&nbsp;Modifications</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="fdl.html#d0e40006" title="G.0.&nbsp;Preamble">1</a> <span class="divider">|</span> <a href="fdl_applicability.html" title="G.1.&nbsp;Applicability and definitions">2</a> <span class="divider">|</span> <a href="fdl_copying.html" title="G.2.&nbsp;Verbatim copying">3</a> <span class="divider">|</span> <a href="fdl_copyinginquantity.html" title="G.3.&nbsp;Copying in quantity">4</a> <span class="divider">|</span> <a href="fdl_modifications.html" title="G.4.&nbsp;Modifications">5</a> <span class="divider">|</span> <span class="thispage">6</span> <span class="divider">|</span> <a href="fdl_collections.html" title="G.6.&nbsp;Collections of documents">7</a> <span class="divider">|</span> <a href="fdl_aggregation.html" title="G.7.&nbsp;Aggregation with independent works">8</a> <span class="divider">|</span> <a href="fdl_translation.html" title="G.8.&nbsp;Translation">9</a> <span class="divider">|</span> <a href="fdl_termination.html" title="G.9.&nbsp;Termination">10</a> <span class="divider">|</span> <a href="fdl_future.html" title="G.10.&nbsp;Future revisions of this license">11</a> <span class="divider">|</span> <a href="fdl_howto.html" title="G.11.&nbsp;How to use this License for your documents">12</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="fdl_collections.html">Collections of documents&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/appendix/fdl_copying.html b/help/diveintopython-5.4/html/appendix/fdl_copying.html
new file mode 100644
index 0000000..dafce3f
--- /dev/null
+++ b/help/diveintopython-5.4/html/appendix/fdl_copying.html
@@ -0,0 +1,78 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>G.2.&nbsp;Verbatim copying</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="fdl.html" title="Appendix&nbsp;G.&nbsp;GNU Free Documentation License">
+ <link rel="previous" href="fdl_applicability.html" title="G.1.&nbsp;Applicability and definitions">
+ <link rel="next" href="fdl_copyinginquantity.html" title="G.3.&nbsp;Copying in quantity">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="fdl.html">GNU Free Documentation License</a>&nbsp;&gt;&nbsp;<span class="thispage">Verbatim copying</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="fdl_applicability.html" title="Prev: &#8220;Applicability and definitions&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="fdl_copyinginquantity.html" title="Next: &#8220;Copying in quantity&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="d0e40035"></a>G.2.&nbsp;Verbatim copying
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p>You may copy and distribute the Document in any medium,
+ either commercially or noncommercially, provided that this
+ License, the copyright notices, and the license notice saying this
+ License applies to the Document are reproduced in all copies, and
+ that you add no other conditions whatsoever to those of this
+ License. You may not use technical measures to obstruct or
+ control the reading or further copying of the copies you make or
+ distribute. However, you may accept compensation in exchange for
+ copies. If you distribute a large enough number of copies you
+ must also follow the conditions in section 3.
+ </p>
+ <p>You may also lend copies, under the same conditions stated
+ above, and you may publicly display copies.
+ </p>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="fdl_applicability.html">&lt;&lt;&nbsp;Applicability and definitions</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="fdl.html#d0e40006" title="G.0.&nbsp;Preamble">1</a> <span class="divider">|</span> <a href="fdl_applicability.html" title="G.1.&nbsp;Applicability and definitions">2</a> <span class="divider">|</span> <span class="thispage">3</span> <span class="divider">|</span> <a href="fdl_copyinginquantity.html" title="G.3.&nbsp;Copying in quantity">4</a> <span class="divider">|</span> <a href="fdl_modifications.html" title="G.4.&nbsp;Modifications">5</a> <span class="divider">|</span> <a href="fdl_combining.html" title="G.5.&nbsp;Combining documents">6</a> <span class="divider">|</span> <a href="fdl_collections.html" title="G.6.&nbsp;Collections of documents">7</a> <span class="divider">|</span> <a href="fdl_aggregation.html" title="G.7.&nbsp;Aggregation with independent works">8</a> <span class="divider">|</span> <a href="fdl_translation.html" title="G.8.&nbsp;Translation">9</a> <span class="divider">|</span> <a href="fdl_termination.html" title="G.9.&nbsp;Termination">10</a> <span class="divider">|</span> <a href="fdl_future.html" title="G.10.&nbsp;Future revisions of this license">11</a> <span class="divider">|</span> <a href="fdl_howto.html" title="G.11.&nbsp;How to use this License for your documents">12</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="fdl_copyinginquantity.html">Copying in quantity&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/appendix/fdl_copyinginquantity.html b/help/diveintopython-5.4/html/appendix/fdl_copyinginquantity.html
new file mode 100644
index 0000000..43a337c
--- /dev/null
+++ b/help/diveintopython-5.4/html/appendix/fdl_copyinginquantity.html
@@ -0,0 +1,102 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>G.3.&nbsp;Copying in quantity</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="fdl.html" title="Appendix&nbsp;G.&nbsp;GNU Free Documentation License">
+ <link rel="previous" href="fdl_copying.html" title="G.2.&nbsp;Verbatim copying">
+ <link rel="next" href="fdl_modifications.html" title="G.4.&nbsp;Modifications">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="fdl.html">GNU Free Documentation License</a>&nbsp;&gt;&nbsp;<span class="thispage">Copying in quantity</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="fdl_copying.html" title="Prev: &#8220;Verbatim copying&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="fdl_modifications.html" title="Next: &#8220;Modifications&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="d0e40043"></a>G.3.&nbsp;Copying in quantity
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p>If you publish printed copies of the Document numbering more
+ than 100, and the Document's license notice requires Cover Texts,
+ you must enclose the copies in covers that carry, clearly and
+ legibly, all these Cover Texts: Front-Cover Texts on the front
+ cover, and Back-Cover Texts on the back cover. Both covers must
+ also clearly and legibly identify you as the publisher of these
+ copies. The front cover must present the full title with all
+ words of the title equally prominent and visible. You may add
+ other material on the covers in addition. Copying with changes
+ limited to the covers, as long as they preserve the title of the
+ Document and satisfy these conditions, can be treated as verbatim
+ copying in other respects.
+ </p>
+ <p>If the required texts for either cover are too voluminous to
+ fit legibly, you should put the first ones listed (as many as fit
+ reasonably) on the actual cover, and continue the rest onto
+ adjacent pages.
+ </p>
+ <p>If you publish or distribute Opaque copies of the Document
+ numbering more than 100, you must either include a
+ machine-readable Transparent copy along with each Opaque copy, or
+ state in or with each Opaque copy a publicly-accessible
+ computer-network location containing a complete Transparent copy
+ of the Document, free of added material, which the general
+ network-using public has access to download anonymously at no
+ charge using public-standard network protocols. If you use the
+ latter option, you must take reasonably prudent steps, when you
+ begin distribution of Opaque copies in quantity, to ensure that
+ this Transparent copy will remain thus accessible at the stated
+ location until at least one year after the last time you
+ distribute an Opaque copy (directly or through your agents or
+ retailers) of that edition to the public.
+ </p>
+ <p>It is requested, but not required, that you contact the
+ authors of the Document well before redistributing any large
+ number of copies, to give them a chance to provide you with an
+ updated version of the Document.
+ </p>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="fdl_copying.html">&lt;&lt;&nbsp;Verbatim copying</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="fdl.html#d0e40006" title="G.0.&nbsp;Preamble">1</a> <span class="divider">|</span> <a href="fdl_applicability.html" title="G.1.&nbsp;Applicability and definitions">2</a> <span class="divider">|</span> <a href="fdl_copying.html" title="G.2.&nbsp;Verbatim copying">3</a> <span class="divider">|</span> <span class="thispage">4</span> <span class="divider">|</span> <a href="fdl_modifications.html" title="G.4.&nbsp;Modifications">5</a> <span class="divider">|</span> <a href="fdl_combining.html" title="G.5.&nbsp;Combining documents">6</a> <span class="divider">|</span> <a href="fdl_collections.html" title="G.6.&nbsp;Collections of documents">7</a> <span class="divider">|</span> <a href="fdl_aggregation.html" title="G.7.&nbsp;Aggregation with independent works">8</a> <span class="divider">|</span> <a href="fdl_translation.html" title="G.8.&nbsp;Translation">9</a> <span class="divider">|</span> <a href="fdl_termination.html" title="G.9.&nbsp;Termination">10</a> <span class="divider">|</span> <a href="fdl_future.html" title="G.10.&nbsp;Future revisions of this license">11</a> <span class="divider">|</span> <a href="fdl_howto.html" title="G.11.&nbsp;How to use this License for your documents">12</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="fdl_modifications.html">Modifications&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/appendix/fdl_future.html b/help/diveintopython-5.4/html/appendix/fdl_future.html
new file mode 100644
index 0000000..db4e9d9
--- /dev/null
+++ b/help/diveintopython-5.4/html/appendix/fdl_future.html
@@ -0,0 +1,80 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>G.10.&nbsp;Future revisions of this license</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="fdl.html" title="Appendix&nbsp;G.&nbsp;GNU Free Documentation License">
+ <link rel="previous" href="fdl_termination.html" title="G.9.&nbsp;Termination">
+ <link rel="next" href="fdl_howto.html" title="G.11.&nbsp;How to use this License for your documents">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="fdl.html">GNU Free Documentation License</a>&nbsp;&gt;&nbsp;<span class="thispage">Future revisions of this license</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="fdl_termination.html" title="Prev: &#8220;Termination&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="fdl_howto.html" title="Next: &#8220;How to use this License for your documents&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="d0e40150"></a>G.10.&nbsp;Future revisions of this license
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p>The Free Software Foundation may publish new, revised
+ versions of the GNU Free Documentation License from time to time.
+ Such new versions will be similar in spirit to the present
+ version, but may differ in detail to address new problems or
+ concerns. See <a href="http://www.gnu.org/copyleft/">http://www.gnu.org/copyleft/</a>.
+ </p>
+ <p>Each version of the License is given a distinguishing
+ version number. If the Document specifies that a particular
+ numbered version of this License "or any later version" applies to
+ it, you have the option of following the terms and conditions
+ either of that specified version or of any later version that has
+ been published (not as a draft) by the Free Software Foundation.
+ If the Document does not specify a version number of this License,
+ you may choose any version ever published (not as a draft) by the
+ Free Software Foundation.
+ </p>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="fdl_termination.html">&lt;&lt;&nbsp;Termination</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="fdl.html#d0e40006" title="G.0.&nbsp;Preamble">1</a> <span class="divider">|</span> <a href="fdl_applicability.html" title="G.1.&nbsp;Applicability and definitions">2</a> <span class="divider">|</span> <a href="fdl_copying.html" title="G.2.&nbsp;Verbatim copying">3</a> <span class="divider">|</span> <a href="fdl_copyinginquantity.html" title="G.3.&nbsp;Copying in quantity">4</a> <span class="divider">|</span> <a href="fdl_modifications.html" title="G.4.&nbsp;Modifications">5</a> <span class="divider">|</span> <a href="fdl_combining.html" title="G.5.&nbsp;Combining documents">6</a> <span class="divider">|</span> <a href="fdl_collections.html" title="G.6.&nbsp;Collections of documents">7</a> <span class="divider">|</span> <a href="fdl_aggregation.html" title="G.7.&nbsp;Aggregation with independent works">8</a> <span class="divider">|</span> <a href="fdl_translation.html" title="G.8.&nbsp;Translation">9</a> <span class="divider">|</span> <a href="fdl_termination.html" title="G.9.&nbsp;Termination">10</a> <span class="divider">|</span> <span class="thispage">11</span> <span class="divider">|</span> <a href="fdl_howto.html" title="G.11.&nbsp;How to use this License for your documents">12</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="fdl_howto.html">How to use this License for your documents&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/appendix/fdl_howto.html b/help/diveintopython-5.4/html/appendix/fdl_howto.html
new file mode 100644
index 0000000..9821779
--- /dev/null
+++ b/help/diveintopython-5.4/html/appendix/fdl_howto.html
@@ -0,0 +1,94 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>G.11.&nbsp;How to use this License for your documents</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="fdl.html" title="Appendix&nbsp;G.&nbsp;GNU Free Documentation License">
+ <link rel="previous" href="fdl_future.html" title="G.10.&nbsp;Future revisions of this license">
+ <link rel="next" href="license.html" title="Appendix&nbsp;H.&nbsp;Python license">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="fdl.html">GNU Free Documentation License</a>&nbsp;&gt;&nbsp;<span class="thispage">How to use this License for your documents</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="fdl_future.html" title="Prev: &#8220;Future revisions of this license&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="license.html" title="Next: &#8220;Python license&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="d0e40161"></a>G.11.&nbsp;How to use this License for your documents
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p>To use this License in a document you have written, include
+ a copy of the License in the document and put the following
+ copyright and license notices just after the title page:
+ </p>
+ <div class="blockquote">
+ <blockquote class="blockquote">
+ <p>
+ Copyright (c) YEAR YOUR NAME.
+ Permission is granted to copy, distribute and/or modify this document
+ under the terms of the GNU Free Documentation License, Version 1.1
+ or any later version published by the Free Software Foundation;
+ with the Invariant Sections being LIST THEIR TITLES, with the
+ Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST.
+ A copy of the license is included in the section entitled "GNU
+ Free Documentation License".
+
+ </p>
+ </blockquote>
+ </div>
+ <p>If you have no Invariant Sections, write "with no Invariant
+ Sections" instead of saying which ones are invariant. If you have
+ no Front-Cover Texts, write "no Front-Cover Texts" instead of
+ "Front-Cover Texts being LIST"; likewise for Back-Cover
+ Texts.
+ </p>
+ <p>If your document contains nontrivial examples of program
+ code, we recommend releasing these examples in parallel under your
+ choice of free software license, such as the GNU General Public
+ License, to permit their use in free software.
+ </p>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="fdl_future.html">&lt;&lt;&nbsp;Future revisions of this license</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="fdl.html#d0e40006" title="G.0.&nbsp;Preamble">1</a> <span class="divider">|</span> <a href="fdl_applicability.html" title="G.1.&nbsp;Applicability and definitions">2</a> <span class="divider">|</span> <a href="fdl_copying.html" title="G.2.&nbsp;Verbatim copying">3</a> <span class="divider">|</span> <a href="fdl_copyinginquantity.html" title="G.3.&nbsp;Copying in quantity">4</a> <span class="divider">|</span> <a href="fdl_modifications.html" title="G.4.&nbsp;Modifications">5</a> <span class="divider">|</span> <a href="fdl_combining.html" title="G.5.&nbsp;Combining documents">6</a> <span class="divider">|</span> <a href="fdl_collections.html" title="G.6.&nbsp;Collections of documents">7</a> <span class="divider">|</span> <a href="fdl_aggregation.html" title="G.7.&nbsp;Aggregation with independent works">8</a> <span class="divider">|</span> <a href="fdl_translation.html" title="G.8.&nbsp;Translation">9</a> <span class="divider">|</span> <a href="fdl_termination.html" title="G.9.&nbsp;Termination">10</a> <span class="divider">|</span> <a href="fdl_future.html" title="G.10.&nbsp;Future revisions of this license">11</a> <span class="divider">|</span> <span class="thispage">12</span>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="license.html">Python license&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/appendix/fdl_modifications.html b/help/diveintopython-5.4/html/appendix/fdl_modifications.html
new file mode 100644
index 0000000..d26c4b4
--- /dev/null
+++ b/help/diveintopython-5.4/html/appendix/fdl_modifications.html
@@ -0,0 +1,179 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>G.4.&nbsp;Modifications</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="fdl.html" title="Appendix&nbsp;G.&nbsp;GNU Free Documentation License">
+ <link rel="previous" href="fdl_copyinginquantity.html" title="G.3.&nbsp;Copying in quantity">
+ <link rel="next" href="fdl_combining.html" title="G.5.&nbsp;Combining documents">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="fdl.html">GNU Free Documentation License</a>&nbsp;&gt;&nbsp;<span class="thispage">Modifications</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="fdl_copyinginquantity.html" title="Prev: &#8220;Copying in quantity&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="fdl_combining.html" title="Next: &#8220;Combining documents&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="d0e40055"></a>G.4.&nbsp;Modifications
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p>You may copy and distribute a Modified Version of the
+ Document under the conditions of sections 2 and 3 above, provided
+ that you release the Modified Version under precisely this
+ License, with the Modified Version filling the role of the
+ Document, thus licensing distribution and modification of the
+ Modified Version to whoever possesses a copy of it. In addition,
+ you must do these things in the Modified Version:
+ </p>
+ <div class="orderedlist">
+ <ol type="A">
+ <li>Use in the Title Page
+ (and on the covers, if any) a title distinct from that of the
+ Document, and from those of previous versions (which should, if
+ there were any, be listed in the History section of the
+ Document). You may use the same title as a previous version if
+ the original publisher of that version gives permission.
+ </li>
+ <li>List on the Title Page,
+ as authors, one or more persons or entities responsible for
+ authorship of the modifications in the Modified Version,
+ together with at least five of the principal authors of the
+ Document (all of its principal authors, if it has less than
+ five).
+ </li>
+ <li>State on the Title page
+ the name of the publisher of the Modified Version, as the
+ publisher.
+ </li>
+ <li>Preserve all the
+ copyright notices of the Document.
+ </li>
+ <li>Add an appropriate
+ copyright notice for your modifications adjacent to the other
+ copyright notices.
+ </li>
+ <li>Include, immediately
+ after the copyright notices, a license notice giving the public
+ permission to use the Modified Version under the terms of this
+ License, in the form shown in the Addendum below.
+ </li>
+ <li>Preserve in that license
+ notice the full lists of Invariant Sections and required Cover
+ Texts given in the Document's license notice.
+ </li>
+ <li>Include an unaltered
+ copy of this License.
+ </li>
+ <li>Preserve the section
+ entitled "History", and its title, and add to it an item stating
+ at least the title, year, new authors, and publisher of the
+ Modified Version as given on the Title Page. If there is no
+ section entitled "History" in the Document, create one stating
+ the title, year, authors, and publisher of the Document as given
+ on its Title Page, then add an item describing the Modified
+ Version as stated in the previous sentence.
+ </li>
+ <li>Preserve the network
+ location, if any, given in the Document for public access to a
+ Transparent copy of the Document, and likewise the network
+ locations given in the Document for previous versions it was
+ based on. These may be placed in the "History" section. You
+ may omit a network location for a work that was published at
+ least four years before the Document itself, or if the original
+ publisher of the version it refers to gives permission.
+ </li>
+ <li>In any section entitled
+ "Acknowledgements" or "Dedications", preserve the section's
+ title, and preserve in the section all the substance and tone of
+ each of the contributor acknowledgements and/or dedications
+ given therein.
+ </li>
+ <li>Preserve all the
+ Invariant Sections of the Document, unaltered in their text and
+ in their titles. Section numbers or the equivalent are not
+ considered part of the section titles.
+ </li>
+ <li>Delete any section
+ entitled "Endorsements". Such a section may not be included in
+ the Modified Version.
+ </li>
+ <li>Do not retitle any
+ existing section as "Endorsements" or to conflict in title with
+ any Invariant Section.
+ </li>
+ </ol>
+ </div>
+ <p>If the Modified Version includes new front-matter sections
+ or appendices that qualify as Secondary Sections and contain no
+ material copied from the Document, you may at your option
+ designate some or all of these sections as invariant. To do this,
+ add their titles to the list of Invariant Sections in the Modified
+ Version's license notice. These titles must be distinct from any
+ other section titles.
+ </p>
+ <p>You may add a section entitled "Endorsements", provided it
+ contains nothing but endorsements of your Modified Version by
+ various parties--for example, statements of peer review or that
+ the text has been approved by an organization as the authoritative
+ definition of a standard.
+ </p>
+ <p>You may add a passage of up to five words as a Front-Cover
+ Text, and a passage of up to 25 words as a Back-Cover Text, to the
+ end of the list of Cover Texts in the Modified Version. Only one
+ passage of Front-Cover Text and one of Back-Cover Text may be
+ added by (or through arrangements made by) any one entity. If the
+ Document already includes a cover text for the same cover,
+ previously added by you or by arrangement made by the same entity
+ you are acting on behalf of, you may not add another; but you may
+ replace the old one, on explicit permission from the previous
+ publisher that added the old one.
+ </p>
+ <p>The author(s) and publisher(s) of the Document do not by
+ this License give permission to use their names for publicity for
+ or to assert or imply endorsement of any Modified Version.
+ </p>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="fdl_copyinginquantity.html">&lt;&lt;&nbsp;Copying in quantity</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="fdl.html#d0e40006" title="G.0.&nbsp;Preamble">1</a> <span class="divider">|</span> <a href="fdl_applicability.html" title="G.1.&nbsp;Applicability and definitions">2</a> <span class="divider">|</span> <a href="fdl_copying.html" title="G.2.&nbsp;Verbatim copying">3</a> <span class="divider">|</span> <a href="fdl_copyinginquantity.html" title="G.3.&nbsp;Copying in quantity">4</a> <span class="divider">|</span> <span class="thispage">5</span> <span class="divider">|</span> <a href="fdl_combining.html" title="G.5.&nbsp;Combining documents">6</a> <span class="divider">|</span> <a href="fdl_collections.html" title="G.6.&nbsp;Collections of documents">7</a> <span class="divider">|</span> <a href="fdl_aggregation.html" title="G.7.&nbsp;Aggregation with independent works">8</a> <span class="divider">|</span> <a href="fdl_translation.html" title="G.8.&nbsp;Translation">9</a> <span class="divider">|</span> <a href="fdl_termination.html" title="G.9.&nbsp;Termination">10</a> <span class="divider">|</span> <a href="fdl_future.html" title="G.10.&nbsp;Future revisions of this license">11</a> <span class="divider">|</span> <a href="fdl_howto.html" title="G.11.&nbsp;How to use this License for your documents">12</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="fdl_combining.html">Combining documents&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/appendix/fdl_termination.html b/help/diveintopython-5.4/html/appendix/fdl_termination.html
new file mode 100644
index 0000000..847628d
--- /dev/null
+++ b/help/diveintopython-5.4/html/appendix/fdl_termination.html
@@ -0,0 +1,73 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>G.9.&nbsp;Termination</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="fdl.html" title="Appendix&nbsp;G.&nbsp;GNU Free Documentation License">
+ <link rel="previous" href="fdl_translation.html" title="G.8.&nbsp;Translation">
+ <link rel="next" href="fdl_future.html" title="G.10.&nbsp;Future revisions of this license">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="fdl.html">GNU Free Documentation License</a>&nbsp;&gt;&nbsp;<span class="thispage">Termination</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="fdl_translation.html" title="Prev: &#8220;Translation&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="fdl_future.html" title="Next: &#8220;Future revisions of this license&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="d0e40144"></a>G.9.&nbsp;Termination
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p>You may not copy, modify, sublicense, or distribute the
+ Document except as expressly provided for under this License. Any
+ other attempt to copy, modify, sublicense or distribute the
+ Document is void, and will automatically terminate your rights
+ under this License. However, parties who have received copies, or
+ rights, from you under this License will not have their licenses
+ terminated so long as such parties remain in full
+ compliance.
+ </p>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="fdl_translation.html">&lt;&lt;&nbsp;Translation</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="fdl.html#d0e40006" title="G.0.&nbsp;Preamble">1</a> <span class="divider">|</span> <a href="fdl_applicability.html" title="G.1.&nbsp;Applicability and definitions">2</a> <span class="divider">|</span> <a href="fdl_copying.html" title="G.2.&nbsp;Verbatim copying">3</a> <span class="divider">|</span> <a href="fdl_copyinginquantity.html" title="G.3.&nbsp;Copying in quantity">4</a> <span class="divider">|</span> <a href="fdl_modifications.html" title="G.4.&nbsp;Modifications">5</a> <span class="divider">|</span> <a href="fdl_combining.html" title="G.5.&nbsp;Combining documents">6</a> <span class="divider">|</span> <a href="fdl_collections.html" title="G.6.&nbsp;Collections of documents">7</a> <span class="divider">|</span> <a href="fdl_aggregation.html" title="G.7.&nbsp;Aggregation with independent works">8</a> <span class="divider">|</span> <a href="fdl_translation.html" title="G.8.&nbsp;Translation">9</a> <span class="divider">|</span> <span class="thispage">10</span> <span class="divider">|</span> <a href="fdl_future.html" title="G.10.&nbsp;Future revisions of this license">11</a> <span class="divider">|</span> <a href="fdl_howto.html" title="G.11.&nbsp;How to use this License for your documents">12</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="fdl_future.html">Future revisions of this license&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/appendix/fdl_translation.html b/help/diveintopython-5.4/html/appendix/fdl_translation.html
new file mode 100644
index 0000000..c298259
--- /dev/null
+++ b/help/diveintopython-5.4/html/appendix/fdl_translation.html
@@ -0,0 +1,76 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>G.8.&nbsp;Translation</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="fdl.html" title="Appendix&nbsp;G.&nbsp;GNU Free Documentation License">
+ <link rel="previous" href="fdl_aggregation.html" title="G.7.&nbsp;Aggregation with independent works">
+ <link rel="next" href="fdl_termination.html" title="G.9.&nbsp;Termination">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="fdl.html">GNU Free Documentation License</a>&nbsp;&gt;&nbsp;<span class="thispage">Translation</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="fdl_aggregation.html" title="Prev: &#8220;Aggregation with independent works&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="fdl_termination.html" title="Next: &#8220;Termination&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="d0e40138"></a>G.8.&nbsp;Translation
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p>Translation is considered a kind of modification, so you may
+ distribute translations of the Document under the terms of section
+ 4. Replacing Invariant Sections with translations requires
+ special permission from their copyright holders, but you may
+ include translations of some or all Invariant Sections in addition
+ to the original versions of these Invariant Sections. You may
+ include a translation of this License provided that you also
+ include the original English version of this License. In case of
+ a disagreement between the translation and the original English
+ version of this License, the original English version will
+ prevail.
+ </p>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="fdl_aggregation.html">&lt;&lt;&nbsp;Aggregation with independent works</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="fdl.html#d0e40006" title="G.0.&nbsp;Preamble">1</a> <span class="divider">|</span> <a href="fdl_applicability.html" title="G.1.&nbsp;Applicability and definitions">2</a> <span class="divider">|</span> <a href="fdl_copying.html" title="G.2.&nbsp;Verbatim copying">3</a> <span class="divider">|</span> <a href="fdl_copyinginquantity.html" title="G.3.&nbsp;Copying in quantity">4</a> <span class="divider">|</span> <a href="fdl_modifications.html" title="G.4.&nbsp;Modifications">5</a> <span class="divider">|</span> <a href="fdl_combining.html" title="G.5.&nbsp;Combining documents">6</a> <span class="divider">|</span> <a href="fdl_collections.html" title="G.6.&nbsp;Collections of documents">7</a> <span class="divider">|</span> <a href="fdl_aggregation.html" title="G.7.&nbsp;Aggregation with independent works">8</a> <span class="divider">|</span> <span class="thispage">9</span> <span class="divider">|</span> <a href="fdl_termination.html" title="G.9.&nbsp;Termination">10</a> <span class="divider">|</span> <a href="fdl_future.html" title="G.10.&nbsp;Future revisions of this license">11</a> <span class="divider">|</span> <a href="fdl_howto.html" title="G.11.&nbsp;How to use this License for your documents">12</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="fdl_termination.html">Termination&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/appendix/furtherreading.html b/help/diveintopython-5.4/html/appendix/furtherreading.html
new file mode 100644
index 0000000..f5f72f4
--- /dev/null
+++ b/help/diveintopython-5.4/html/appendix/furtherreading.html
@@ -0,0 +1,468 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>Appendix&nbsp;A.&nbsp;Further reading</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="../toc/index.html" title="Dive Into Python">
+ <link rel="previous" href="../performance_tuning/summary.html" title="18.7.&nbsp;Summary">
+ <link rel="next" href="abstracts.html" title="Appendix&nbsp;B.&nbsp;A 5-minute review">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<span class="thispage">Further reading</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="../performance_tuning/summary.html" title="Prev: &#8220;Summary&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="abstracts.html" title="Next: &#8220;A 5-minute review&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="appendix" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="furtherreading"></a>Appendix&nbsp;A.&nbsp;Further reading
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p><a href="../installing_python/index.html">Chapter&nbsp;1.&nbsp;Installing Python</a></p>
+ <ul></ul>
+ <p><a href="../getting_to_know_python/index.html">Chapter&nbsp;2.&nbsp;Your First Python Program</a></p>
+ <ul>
+ <li><a href="../getting_to_know_python/documenting_functions.html">2.3.&nbsp;Documenting Functions</a><p></p>
+ <ul>
+ <li><a href="http://www.python.org/peps/pep-0257.html">PEP 257</a> defines <tt class="literal">doc string</tt> conventions.
+ </li>
+ <li><a href="http://www.python.org/doc/essays/styleguide.html"><i class="citetitle"><span class="application">Python</span> Style Guide</i></a> discusses how to write a good <tt class="literal">doc string</tt>.
+ </li>
+ <li><a href="http://www.python.org/doc/current/tut/tut.html"><i class="citetitle"><span class="application">Python</span> Tutorial</i></a> discusses conventions for <a href="http://www.python.org/doc/current/tut/node6.html#SECTION006750000000000000000">spacing in <tt class="literal">doc string</tt>s</a>.
+ </li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../getting_to_know_python/everything_is_an_object.html#d0e4665">2.4.2.&nbsp;What's an Object?</a><p></p>
+ <ul>
+ <li><a href="http://www.python.org/doc/current/ref/"><i class="citetitle"><span class="application">Python</span> Reference Manual</i></a> explains exactly what it means to say that <a href="http://www.python.org/doc/current/ref/objects.html">everything in <span class="application">Python</span> is an object</a>, because some people are pedantic and like to discuss this sort of thing at great length.
+ </li>
+ <li><a href="http://www.effbot.org/guides/">eff-bot</a> summarizes <a href="http://www.effbot.org/guides/python-objects.htm"><span class="application">Python</span> objects</a>.
+ </li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../getting_to_know_python/indenting_code.html">2.5.&nbsp;Indenting Code</a><p></p>
+ <ul>
+ <li><a href="http://www.python.org/doc/current/ref/"><i class="citetitle"><span class="application">Python</span> Reference Manual</i></a> discusses cross-platform indentation issues and <a href="http://www.python.org/doc/current/ref/indentation.html">shows various indentation errors</a>.
+ </li>
+ <li><a href="http://www.python.org/doc/essays/styleguide.html"><i class="citetitle"><span class="application">Python</span> Style Guide</i></a> discusses good indentation style.
+ </li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../getting_to_know_python/testing_modules.html">2.6.&nbsp;Testing Modules</a><p></p>
+ <ul>
+ <li><a href="http://www.python.org/doc/current/ref/"><i class="citetitle"><span class="application">Python</span> Reference Manual</i></a> discusses the low-level details of <a href="http://www.python.org/doc/current/ref/import.html">importing modules</a>.
+ </li>
+ </ul>
+ <p></p>
+ </li>
+ </ul>
+ <p><a href="../native_data_types/index.html">Chapter&nbsp;3.&nbsp;Native Datatypes</a></p>
+ <ul>
+ <li><a href="../native_data_types/index.html#d0e5450">3.1.3.&nbsp;Deleting Items From Dictionaries</a><p></p>
+ <ul>
+ <li><a href="http://www.ibiblio.org/obp/thinkCSpy/" title="Python book for computer science majors"><i class="citetitle">How to Think Like a Computer Scientist</i></a> teaches about dictionaries and shows how to <a href="http://www.ibiblio.org/obp/thinkCSpy/chap10.htm">use dictionaries to model sparse matrices</a>.
+ </li>
+ <li><a href="http://www.faqts.com/knowledge-base/index.phtml/fid/199/"><span class="application">Python</span> Knowledge Base</a> has a lot of <a href="http://www.faqts.com/knowledge-base/index.phtml/fid/541">example code using dictionaries</a>.
+ </li>
+ <li><a href="http://www.activestate.com/ASPN/Python/Cookbook/" title="growing archive of annotated code samples"><span class="application">Python</span> Cookbook</a> discusses <a href="http://www.activestate.com/ASPN/Python/Cookbook/Recipe/52306">how to sort the values of a dictionary by key</a>.
+ </li>
+ <li><a href="http://www.python.org/doc/current/lib/"><i class="citetitle"><span class="application">Python</span> Library Reference</i></a> summarizes <a href="http://www.python.org/doc/current/lib/typesmapping.html">all the dictionary methods</a>.
+ </li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../native_data_types/lists.html#d0e6392">3.2.5.&nbsp;Using List Operators</a><p></p>
+ <ul>
+ <li><a href="http://www.ibiblio.org/obp/thinkCSpy/" title="Python book for computer science majors"><i class="citetitle">How to Think Like a Computer Scientist</i></a> teaches about lists and makes an important point about <a href="http://www.ibiblio.org/obp/thinkCSpy/chap08.htm">passing lists as function arguments</a>.
+ </li>
+ <li><a href="http://www.python.org/doc/current/tut/tut.html"><i class="citetitle"><span class="application">Python</span> Tutorial</i></a> shows how to <a href="http://www.python.org/doc/current/tut/node7.html#SECTION007110000000000000000">use lists as stacks and queues</a>.
+ </li>
+ <li><a href="http://www.faqts.com/knowledge-base/index.phtml/fid/199/"><span class="application">Python</span> Knowledge Base</a> answers <a href="http://www.faqts.com/knowledge-base/index.phtml/fid/534">common questions about lists</a> and has a lot of <a href="http://www.faqts.com/knowledge-base/index.phtml/fid/540">example code using lists</a>.
+ </li>
+ <li><a href="http://www.python.org/doc/current/lib/"><i class="citetitle"><span class="application">Python</span> Library Reference</i></a> summarizes <a href="http://www.python.org/doc/current/lib/typesseq-mutable.html">all the list methods</a>.
+ </li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../native_data_types/tuples.html">3.3.&nbsp;Introducing Tuples</a><p></p>
+ <ul>
+ <li><a href="http://www.ibiblio.org/obp/thinkCSpy/" title="Python book for computer science majors"><i class="citetitle">How to Think Like a Computer Scientist</i></a> teaches about tuples and shows how to <a href="http://www.ibiblio.org/obp/thinkCSpy/chap10.htm">concatenate tuples</a>.
+ </li>
+ <li><a href="http://www.faqts.com/knowledge-base/index.phtml/fid/199/"><span class="application">Python</span> Knowledge Base</a> shows how to <a href="http://www.faqts.com/knowledge-base/view.phtml/aid/4553/fid/587">sort a tuple</a>.
+ </li>
+ <li><a href="http://www.python.org/doc/current/tut/tut.html"><i class="citetitle"><span class="application">Python</span> Tutorial</i></a> shows how to <a href="http://www.python.org/doc/current/tut/node7.html#SECTION007300000000000000000">define a tuple with one element</a>.
+ </li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../native_data_types/declaring_variables.html#odbchelper.multiassign">3.4.2.&nbsp;Assigning Multiple Values at Once</a><p></p>
+ <ul>
+ <li><a href="http://www.python.org/doc/current/ref/"><i class="citetitle"><span class="application">Python</span> Reference Manual</i></a> shows examples of <a href="http://www.python.org/doc/current/ref/implicit-joining.html">when you can skip the line continuation character</a> and <a href="http://www.python.org/doc/current/ref/explicit-joining.html">when you need to use it</a>.
+ </li>
+ <li><a href="http://www.ibiblio.org/obp/thinkCSpy/" title="Python book for computer science majors"><i class="citetitle">How to Think Like a Computer Scientist</i></a> shows how to use multi-variable assignment to <a href="http://www.ibiblio.org/obp/thinkCSpy/chap09.htm">swap the values of two variables</a>.
+ </li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../native_data_types/formatting_strings.html">3.5.&nbsp;Formatting Strings</a><p></p>
+ <ul>
+ <li><a href="http://www.python.org/doc/current/lib/"><i class="citetitle"><span class="application">Python</span> Library Reference</i></a> summarizes <a href="http://www.python.org/doc/current/lib/typesseq-strings.html">all the string formatting format characters</a>.
+ </li>
+ <li><a href="http://www-gnats.gnu.org:8080/cgi-bin/info2www?(gawk)Top"><i class="citetitle">Effective <span class="acronym">AWK</span> Programming</i></a> discusses <a href="http://www-gnats.gnu.org:8080/cgi-bin/info2www?(gawk)Control+Letters">all the format characters</a> and advanced string formatting techniques like <a href="http://www-gnats.gnu.org:8080/cgi-bin/info2www?(gawk)Format+Modifiers">specifying width, precision, and zero-padding</a>.
+ </li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../native_data_types/mapping_lists.html">3.6.&nbsp;Mapping Lists</a><p></p>
+ <ul>
+ <li><a href="http://www.python.org/doc/current/tut/tut.html"><i class="citetitle"><span class="application">Python</span> Tutorial</i></a> discusses another way to map lists <a href="http://www.python.org/doc/current/tut/node7.html#SECTION007130000000000000000">using the built-in <tt class="function">map</tt> function</a>.
+ </li>
+ <li><a href="http://www.python.org/doc/current/tut/tut.html"><i class="citetitle"><span class="application">Python</span> Tutorial</i></a> shows how to <a href="http://www.python.org/doc/current/tut/node7.html#SECTION007140000000000000000">do nested list comprehensions</a>.
+ </li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../native_data_types/joining_lists.html">3.7.&nbsp;Joining Lists and Splitting Strings</a><p></p>
+ <ul>
+ <li><a href="http://www.faqts.com/knowledge-base/index.phtml/fid/199/"><span class="application">Python</span> Knowledge Base</a> answers <a href="http://www.faqts.com/knowledge-base/index.phtml/fid/480">common questions about strings</a> and has a lot of <a href="http://www.faqts.com/knowledge-base/index.phtml/fid/539">example code using strings</a>.
+ </li>
+ <li><a href="http://www.python.org/doc/current/lib/"><i class="citetitle"><span class="application">Python</span> Library Reference</i></a> summarizes <a href="http://www.python.org/doc/current/lib/string-methods.html">all the string methods</a>.
+ </li>
+ <li><a href="http://www.python.org/doc/current/lib/"><i class="citetitle"><span class="application">Python</span> Library Reference</i></a> documents the <a href="http://www.python.org/doc/current/lib/module-string.html"><tt class="filename">string</tt> module</a>.
+ </li>
+ <li><a href="http://www.python.org/doc/FAQ.html"><i class="citetitle">The Whole <span class="application">Python</span> <span class="acronym">FAQ</span></i></a> explains <a href="http://www.python.org/cgi-bin/faqw.py?query=4.96&amp;querytype=simple&amp;casefold=yes&amp;req=search">why <tt class="function">join</tt> is a string method</a> instead of a list method.
+ </li>
+ </ul>
+ <p></p>
+ </li>
+ </ul>
+ <p><a href="../power_of_introspection/index.html">Chapter&nbsp;4.&nbsp;The Power Of Introspection</a></p>
+ <ul>
+ <li><a href="../power_of_introspection/optional_arguments.html">4.2.&nbsp;Using Optional and Named Arguments</a><p></p>
+ <ul>
+ <li><a href="http://www.python.org/doc/current/tut/tut.html"><i class="citetitle"><span class="application">Python</span> Tutorial</i></a> discusses exactly <a href="http://www.python.org/doc/current/tut/node6.html#SECTION006710000000000000000">when and how default arguments are evaluated</a>, which matters when the default value is a list or an expression with side effects.
+ </li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../power_of_introspection/built_in_functions.html#d0e8958">4.3.3.&nbsp;Built-In Functions</a><p></p>
+ <ul>
+ <li><a href="http://www.python.org/doc/current/lib/"><i class="citetitle"><span class="application">Python</span> Library Reference</i></a> documents <a href="http://www.python.org/doc/current/lib/built-in-funcs.html">all the built-in functions</a> and <a href="http://www.python.org/doc/current/lib/module-exceptions.html">all the built-in exceptions</a>.
+ </li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../power_of_introspection/filtering_lists.html">4.5.&nbsp;Filtering Lists</a><p></p>
+ <ul>
+ <li><a href="http://www.python.org/doc/current/tut/tut.html"><i class="citetitle"><span class="application">Python</span> Tutorial</i></a> discusses another way to filter lists <a href="http://www.python.org/doc/current/tut/node7.html#SECTION007130000000000000000">using the built-in <tt class="function">filter</tt> function</a>.
+ </li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../power_of_introspection/and_or.html#d0e9975">4.6.1.&nbsp;Using the and-or Trick</a><p></p>
+ <ul>
+ <li><a href="http://www.activestate.com/ASPN/Python/Cookbook/" title="growing archive of annotated code samples"><span class="application">Python</span> Cookbook</a> discusses <a href="http://www.activestate.com/ASPN/Python/Cookbook/Recipe/52310">alternatives to the <tt class="literal">and-or</tt> trick</a>.
+ </li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../power_of_introspection/lambda_functions.html#d0e10403">4.7.1.&nbsp;Real-World lambda Functions</a><p></p>
+ <ul>
+ <li><a href="http://www.faqts.com/knowledge-base/index.phtml/fid/199/"><span class="application">Python</span> Knowledge Base</a> discusses using <tt class="literal">lambda</tt> to <a href="http://www.faqts.com/knowledge-base/view.phtml/aid/6081/fid/241">call functions indirectly</a>.
+ </li>
+ <li><a href="http://www.python.org/doc/current/tut/tut.html"><i class="citetitle"><span class="application">Python</span> Tutorial</i></a> shows how to <a href="http://www.python.org/doc/current/tut/node6.html#SECTION006740000000000000000">access outside variables from inside a <tt class="literal">lambda</tt> function</a>. (<a href="http://python.sourceforge.net/peps/pep-0227.html"><span class="acronym">PEP</span> 227</a> explains how this will change in future versions of <span class="application">Python</span>.)
+ </li>
+ <li><a href="http://www.python.org/doc/FAQ.html"><i class="citetitle">The Whole <span class="application">Python</span> <span class="acronym">FAQ</span></i></a> has examples of <a href="http://www.python.org/cgi-bin/faqw.py?query=4.15&amp;querytype=simple&amp;casefold=yes&amp;req=search">obfuscated one-liners using <tt class="literal">lambda</tt></a>.
+ </li>
+ </ul>
+ <p></p>
+ </li>
+ </ul>
+ <p><a href="../object_oriented_framework/index.html">Chapter&nbsp;5.&nbsp;Objects and Object-Orientation</a></p>
+ <ul>
+ <li><a href="../object_oriented_framework/importing_modules.html">5.2.&nbsp;Importing Modules Using from module import</a><p></p>
+ <ul>
+ <li><a href="http://www.effbot.org/guides/">eff-bot</a> has more to say on <a href="http://www.effbot.org/guides/import-confusion.htm"><tt class="literal">import <i class="replaceable">module</i></tt> <span class="foreignphrase"><i class="foreignphrase"><span class="acronym">vs.</span></i></span> <tt class="literal">from <i class="replaceable">module</i> import</tt></a>.
+ </li>
+ <li><a href="http://www.python.org/doc/current/tut/tut.html"><i class="citetitle"><span class="application">Python</span> Tutorial</i></a> discusses advanced import techniques, including <a href="http://www.python.org/doc/current/tut/node8.html#SECTION008410000000000000000"><tt class="literal">from <i class="replaceable">module</i> import *</tt></a>.
+ </li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../object_oriented_framework/defining_classes.html#d0e11896">5.3.2.&nbsp;Knowing When to Use self and __init__</a><p></p>
+ <ul>
+ <li><a href="http://www.freenetpages.co.uk/hp/alan.gauld/" title="Python book for first-time programmers"><i class="citetitle">Learning to Program</i></a> has a gentler <a href="http://www.freenetpages.co.uk/hp/alan.gauld/tutclass.htm">introduction to classes</a>.
+ </li>
+ <li><a href="http://www.ibiblio.org/obp/thinkCSpy/" title="Python book for computer science majors"><i class="citetitle">How to Think Like a Computer Scientist</i></a> shows how to <a href="http://www.ibiblio.org/obp/thinkCSpy/chap12.htm">use classes to model compound datatypes</a>.
+ </li>
+ <li><a href="http://www.python.org/doc/current/tut/tut.html"><i class="citetitle"><span class="application">Python</span> Tutorial</i></a> has an in-depth look at <a href="http://www.python.org/doc/current/tut/node11.html">classes, namespaces, and inheritance</a>.
+ </li>
+ <li><a href="http://www.faqts.com/knowledge-base/index.phtml/fid/199/"><span class="application">Python</span> Knowledge Base</a> answers <a href="http://www.faqts.com/knowledge-base/index.phtml/fid/242">common questions about classes</a>.
+ </li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../object_oriented_framework/instantiating_classes.html#d0e12165">5.4.1.&nbsp;Garbage Collection</a><p></p>
+ <ul>
+ <li><a href="http://www.python.org/doc/current/lib/"><i class="citetitle"><span class="application">Python</span> Library Reference</i></a> summarizes <a href="http://www.python.org/doc/current/lib/specialattrs.html">built-in attributes like <tt class="literal">__class__</tt></a>.
+ </li>
+ <li><a href="http://www.python.org/doc/current/lib/"><i class="citetitle"><span class="application">Python</span> Library Reference</i></a> documents the <a href="http://www.python.org/doc/current/lib/module-gc.html"><tt class="filename">gc</tt> module</a>, which gives you low-level control over <span class="application">Python</span>'s garbage collection.
+ </li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../object_oriented_framework/userdict.html">5.5.&nbsp;Exploring UserDict: A Wrapper Class</a><p></p>
+ <ul>
+ <li><a href="http://www.python.org/doc/current/lib/"><i class="citetitle"><span class="application">Python</span> Library Reference</i></a> documents the <a href="http://www.python.org/doc/current/lib/module-UserDict.html"><tt class="filename">UserDict</tt> module</a> and the <a href="http://www.python.org/doc/current/lib/module-copy.html"><tt class="filename">copy</tt> module</a>.
+ </li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../object_oriented_framework/special_class_methods2.html">5.7.&nbsp;Advanced Special Class Methods</a><p></p>
+ <ul>
+ <li><a href="http://www.python.org/doc/current/ref/"><i class="citetitle"><span class="application">Python</span> Reference Manual</i></a> documents <a href="http://www.python.org/doc/current/ref/specialnames.html">all the special class methods</a>.
+ </li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../object_oriented_framework/private_functions.html">5.9.&nbsp;Private Functions</a><p></p>
+ <ul>
+ <li><a href="http://www.python.org/doc/current/tut/tut.html"><i class="citetitle"><span class="application">Python</span> Tutorial</i></a> discusses the inner workings of <a href="http://www.python.org/doc/current/tut/node11.html#SECTION0011600000000000000000">private variables</a>.
+ </li>
+ </ul>
+ <p></p>
+ </li>
+ </ul>
+ <p><a href="../file_handling/index.html">Chapter&nbsp;6.&nbsp;Exceptions and File Handling</a></p>
+ <ul>
+ <li><a href="../file_handling/index.html#d0e14344">6.1.1.&nbsp;Using Exceptions For Other Purposes</a><p></p>
+ <ul>
+ <li><a href="http://www.python.org/doc/current/tut/tut.html"><i class="citetitle"><span class="application">Python</span> Tutorial</i></a> discusses <a href="http://www.python.org/doc/current/tut/node10.html#SECTION0010400000000000000000">defining and raising your own exceptions, and handling multiple exceptions at once</a>.
+ </li>
+ <li><a href="http://www.python.org/doc/current/lib/"><i class="citetitle"><span class="application">Python</span> Library Reference</i></a> summarizes <a href="http://www.python.org/doc/current/lib/module-exceptions.html">all the built-in exceptions</a>.
+ </li>
+ <li><a href="http://www.python.org/doc/current/lib/"><i class="citetitle"><span class="application">Python</span> Library Reference</i></a> documents the <a href="http://www.python.org/doc/current/lib/module-getpass.html">getpass</a> module.
+ </li>
+ <li><a href="http://www.python.org/doc/current/lib/"><i class="citetitle"><span class="application">Python</span> Library Reference</i></a> documents the <a href="http://www.python.org/doc/current/lib/module-traceback.html"><tt class="filename">traceback</tt> module</a>, which provides low-level access to exception attributes after an exception is raised.
+ </li>
+ <li><a href="http://www.python.org/doc/current/ref/"><i class="citetitle"><span class="application">Python</span> Reference Manual</i></a> discusses the inner workings of the <a href="http://www.python.org/doc/current/ref/try.html"><tt class="literal">try...except</tt> block</a>.
+ </li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../file_handling/file_objects.html#d0e15055">6.2.4.&nbsp;Writing to Files</a><p></p>
+ <ul>
+ <li><a href="http://www.python.org/doc/current/tut/tut.html"><i class="citetitle"><span class="application">Python</span> Tutorial</i></a> discusses reading and writing files, including how to <a href="http://www.python.org/doc/current/tut/node9.html#SECTION009210000000000000000">read a file one line at a time into a list</a>.
+ </li>
+ <li><a href="http://www.effbot.org/guides/">eff-bot</a> discusses efficiency and performance of <a href="http://www.effbot.org/guides/readline-performance.htm">various ways of reading a file</a>.
+ </li>
+ <li><a href="http://www.faqts.com/knowledge-base/index.phtml/fid/199/"><span class="application">Python</span> Knowledge Base</a> answers <a href="http://www.faqts.com/knowledge-base/index.phtml/fid/552">common questions about files</a>.
+ </li>
+ <li><a href="http://www.python.org/doc/current/lib/"><i class="citetitle"><span class="application">Python</span> Library Reference</i></a> summarizes <a href="http://www.python.org/doc/current/lib/bltin-file-objects.html">all the file object methods</a>.
+ </li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../file_handling/more_on_modules.html">6.4.&nbsp;Using sys.modules</a><p></p>
+ <ul>
+ <li><a href="http://www.python.org/doc/current/tut/tut.html"><i class="citetitle"><span class="application">Python</span> Tutorial</i></a> discusses exactly <a href="http://www.python.org/doc/current/tut/node6.html#SECTION006710000000000000000">when and how default arguments are evaluated</a>.
+ </li>
+ <li><a href="http://www.python.org/doc/current/lib/"><i class="citetitle"><span class="application">Python</span> Library Reference</i></a> documents the <a href="http://www.python.org/doc/current/lib/module-sys.html"><tt class="filename">sys</tt></a> module.
+ </li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../file_handling/os_module.html">6.5.&nbsp;Working with Directories</a><p></p>
+ <ul>
+ <li><a href="http://www.faqts.com/knowledge-base/index.phtml/fid/199/"><span class="application">Python</span> Knowledge Base</a> answers <a href="http://www.faqts.com/knowledge-base/index.phtml/fid/240">questions about the <tt class="filename">os</tt> module</a>.
+ </li>
+ <li><a href="http://www.python.org/doc/current/lib/"><i class="citetitle"><span class="application">Python</span> Library Reference</i></a> documents the <a href="http://www.python.org/doc/current/lib/module-os.html"><tt class="filename">os</tt></a> module and the <a href="http://www.python.org/doc/current/lib/module-os.path.html"><tt class="filename">os.path</tt></a> module.
+ </li>
+ </ul>
+ <p></p>
+ </li>
+ </ul>
+ <p><a href="../regular_expressions/index.html">Chapter&nbsp;7.&nbsp;Regular Expressions</a></p>
+ <ul>
+ <li><a href="../regular_expressions/phone_numbers.html">7.6.&nbsp;Case study: Parsing Phone Numbers</a><p></p>
+ <ul>
+ <li><a href="http://py-howto.sourceforge.net/regex/regex.html">Regular Expression HOWTO</a> teaches about regular expressions and how to use them in <span class="application">Python</span>.
+ </li>
+ <li><a href="http://www.python.org/doc/current/lib/"><i class="citetitle"><span class="application">Python</span> Library Reference</i></a> summarizes the <a href="http://www.python.org/doc/current/lib/module-re.html"><tt class="filename">re</tt> module</a>.
+ </li>
+ </ul>
+ <p></p>
+ </li>
+ </ul>
+ <p><a href="../html_processing/index.html">Chapter&nbsp;8.&nbsp;HTML Processing</a></p>
+ <ul>
+ <li><a href="../html_processing/basehtmlprocessor.html">8.4.&nbsp;Introducing BaseHTMLProcessor.py</a><p></p>
+ <ul>
+ <li><a href="http://www.w3.org/">W3C</a> discusses <a href="http://www.w3.org/TR/REC-html40/charset.html#entities">character and entity references</a>.
+ </li>
+ <li><a href="http://www.python.org/doc/current/lib/"><i class="citetitle"><span class="application">Python</span> Library Reference</i></a> confirms your suspicions that <a href="http://www.python.org/doc/current/lib/module-htmlentitydefs.html">the <tt class="filename">htmlentitydefs</tt> module</a> is exactly what it sounds like.
+ </li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../html_processing/all_together.html">8.9.&nbsp;Putting it all together</a><p></p>
+ <ul>
+ <li>You thought I was kidding about the server-side scripting idea. So did I, until I found <a href="http://rinkworks.com/dialect/">this web-based dialectizer</a>. Unfortunately, source code does not appear to be available.
+ </li>
+ </ul>
+ <p></p>
+ </li>
+ </ul>
+ <p><a href="../xml_processing/index.html">Chapter&nbsp;9.&nbsp;XML Processing</a></p>
+ <ul>
+ <li><a href="../xml_processing/unicode.html">9.4.&nbsp;Unicode</a><p></p>
+ <ul>
+ <li><a href="http://www.unicode.org/">Unicode.org</a> is the home page of the unicode standard, including a brief <a href="http://www.unicode.org/standard/principles.html">technical introduction</a>.
+ </li>
+ <li><a href="http://www.reportlab.com/i18n/python_unicode_tutorial.html">Unicode Tutorial</a> has some more examples of how to use <span class="application">Python</span>'s unicode functions, including how to force <span class="application">Python</span> to coerce unicode into <span class="acronym">ASCII</span> even when it doesn't really want to.
+ </li>
+ <li><a href="http://www.python.org/peps/pep-0263.html">PEP 263</a> goes into more detail about how and when to define a character encoding in your <tt class="filename">.py</tt> files.
+ </li>
+ </ul>
+ <p></p>
+ </li>
+ </ul>
+ <p><a href="../scripts_and_streams/index.html">Chapter&nbsp;10.&nbsp;Scripts and Streams</a></p>
+ <ul></ul>
+ <p><a href="../http_web_services/index.html">Chapter&nbsp;11.&nbsp;HTTP Web Services</a></p>
+ <ul>
+ <li><a href="../http_web_services/index.html#oa.divein">11.1.&nbsp;Diving in</a><p></p>
+ <ul>
+ <li>Paul Prescod believes that <a href="http://webservices.xml.com/pub/a/ws/2002/02/06/rest.html">pure HTTP web services are the future of the Internet</a>.
+ </li>
+ </ul>
+ <p></p>
+ </li>
+ </ul>
+ <p><a href="../soap_web_services/index.html">Chapter&nbsp;12.&nbsp;SOAP Web Services</a></p>
+ <ul>
+ <li><a href="../soap_web_services/index.html#soap.divein">12.1.&nbsp;Diving In</a><p></p>
+ <ul>
+ <li><a href="http://www.xmethods.net/">http://www.xmethods.net/</a> is a repository of public access <span class="acronym">SOAP</span> web services.
+ </li>
+ <li>The <a href="http://www.w3.org/TR/soap/"><span class="acronym">SOAP</span> specification</a> is surprisingly readable, if you like that sort of thing.
+ </li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../soap_web_services/troubleshooting.html">12.8.&nbsp;Troubleshooting SOAP Web Services</a><p></p>
+ <ul>
+ <li><a href="http://www-106.ibm.com/developerworks/webservices/library/ws-pyth17.html">New developments for <span class="application">SOAPpy</span></a> steps through trying to connect to another <span class="acronym">SOAP</span> service that doesn't quite work as advertised.
+ </li>
+ </ul>
+ <p></p>
+ </li>
+ </ul>
+ <p><a href="../unit_testing/index.html">Chapter&nbsp;13.&nbsp;Unit Testing</a></p>
+ <ul>
+ <li><a href="../unit_testing/index.html#roman.intro">13.1.&nbsp;Introduction to Roman numerals</a><p></p>
+ <ul>
+ <li><a href="http://www.wilkiecollins.demon.co.uk/roman/front.htm">This site</a> has more on Roman numerals, including a fascinating <a href="http://www.wilkiecollins.demon.co.uk/roman/intro.htm">history</a> of how Romans and other civilizations really used them (short answer: haphazardly and inconsistently).
+ </li>
+ </ul>
+ <p></p>
+ </li>
+ <li><a href="../unit_testing/romantest.html">13.3.&nbsp;Introducing romantest.py</a><p></p>
+ <ul>
+ <li><a href="http://pyunit.sourceforge.net/">The <span class="application">PyUnit</span> home page</a> has an in-depth discussion of <a href="http://pyunit.sourceforge.net/pyunit.html">using the <tt class="filename">unittest</tt> framework</a>, including advanced features not covered in this chapter.
+ </li>
+ <li><a href="http://pyunit.sourceforge.net/pyunit.html">The <span class="application">PyUnit</span> <span class="acronym">FAQ</span></a> explains <a href="http://pyunit.sourceforge.net/pyunit.html#WHERE">why test cases are stored separately</a> from the code they test.
+ </li>
+ <li><a href="http://www.python.org/doc/current/lib/"><i class="citetitle"><span class="application">Python</span> Library Reference</i></a> summarizes the <a href="http://www.python.org/doc/current/lib/module-unittest.html"><tt class="filename">unittest</tt></a> module.
+ </li>
+ <li><a href="http://www.extremeprogramming.org/">ExtremeProgramming.org</a> discusses <a href="http://www.extremeprogramming.org/rules/unittests.html">why you should write unit tests</a>.
+ </li>
+ <li><a href="http://www.c2.com/cgi/wiki">The Portland Pattern Repository</a> has an ongoing discussion of <a href="http://www.c2.com/cgi/wiki?UnitTests">unit tests</a>, including a <a href="http://www.c2.com/cgi/wiki?StandardDefinitionOfUnitTest">standard definition</a>, why you should <a href="http://www.c2.com/cgi/wiki?CodeUnitTestFirst">code unit tests first</a>, and several in-depth <a href="http://www.c2.com/cgi/wiki?UnitTestTrial">case studies</a>.
+ </li>
+ </ul>
+ <p></p>
+ </li>
+ </ul>
+ <p><a href="../unit_testing/stage_1.html">Chapter&nbsp;14.&nbsp;Test-First Programming</a></p>
+ <ul></ul>
+ <p><a href="../refactoring/index.html">Chapter&nbsp;15.&nbsp;Refactoring</a></p>
+ <ul>
+ <li><a href="../refactoring/summary.html">15.5.&nbsp;Summary</a><p></p>
+ <ul>
+ <li><a href="http://www.xprogramming.com/">XProgramming.com</a> has links to <a href="http://www.xprogramming.com/software.htm">download unit testing frameworks</a> for many different languages.
+ </li>
+ </ul>
+ <p></p>
+ </li>
+ </ul>
+ <p><a href="../functional_programming/index.html">Chapter&nbsp;16.&nbsp;Functional Programming</a></p>
+ <ul></ul>
+ <p><a href="../dynamic_functions/index.html">Chapter&nbsp;17.&nbsp;Dynamic functions</a></p>
+ <ul>
+ <li><a href="../dynamic_functions/stage6.html">17.7.&nbsp;plural.py, stage 6</a><p></p>
+ <ul>
+ <li><a href="http://www.python.org/peps/pep-0255.html">PEP 255</a> defines generators.
+ </li>
+ <li><a href="http://www.activestate.com/ASPN/Python/Cookbook/" title="growing archive of annotated code samples"><span class="application">Python</span> Cookbook</a> has <a href="http://www.google.com/search?q=generators+cookbook+site:aspn.activestate.com">many more examples of generators</a>.
+ </li>
+ </ul>
+ <p></p>
+ </li>
+ </ul>
+ <p><a href="../performance_tuning/index.html">Chapter&nbsp;18.&nbsp;Performance Tuning</a></p>
+ <ul>
+ <li><a href="../performance_tuning/index.html#soundex.divein">18.1.&nbsp;Diving in</a><p></p>
+ <ul>
+ <li><a href="http://www.avotaynu.com/soundex.html">Soundexing and Genealogy</a> gives a chronology of the evolution of the Soundex and its regional variations.
+ </li>
+ </ul>
+ <p></p>
+ </li>
+ </ul>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="../performance_tuning/summary.html">&lt;&lt;&nbsp;Summary</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="abstracts.html">A 5-minute review&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/appendix/history.html b/help/diveintopython-5.4/html/appendix/history.html
new file mode 100644
index 0000000..ec5bf4d
--- /dev/null
+++ b/help/diveintopython-5.4/html/appendix/history.html
@@ -0,0 +1,1068 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>Appendix&nbsp;E.&nbsp;Revision history</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="../toc/index.html" title="Dive Into Python">
+ <link rel="previous" href="examples.html" title="Appendix&nbsp;D.&nbsp;List of examples">
+ <link rel="next" href="about.html" title="Appendix&nbsp;F.&nbsp;About the book">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<span class="thispage">Revision history</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="examples.html" title="Prev: &#8220;List of examples&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="about.html" title="Next: &#8220;About the book&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="appendix" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="revhistory"></a>Appendix&nbsp;E.&nbsp;Revision history
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="revhistory"><a name="5.4"></a><h3 class="revdate">2004-05-20 (5.4)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>Added <a href="../soap_web_services/index.html#soap.divein" title="12.1.&nbsp;Diving In">Section&nbsp;12.1, &#8220;Diving In&#8221;</a>.
+ </li>
+ <li>Added <a href="../soap_web_services/install.html" title="12.2.&nbsp;Installing the SOAP Libraries">Section&nbsp;12.2, &#8220;Installing the SOAP Libraries&#8221;</a>.
+ </li>
+ <li>Added <a href="../soap_web_services/first_steps.html" title="12.3.&nbsp;First Steps with SOAP">Section&nbsp;12.3, &#8220;First Steps with SOAP&#8221;</a>.
+ </li>
+ <li>Added <a href="../soap_web_services/debugging.html" title="12.4.&nbsp;Debugging SOAP Web Services">Section&nbsp;12.4, &#8220;Debugging SOAP Web Services&#8221;</a>.
+ </li>
+ <li>Added <a href="../soap_web_services/wsdl.html" title="12.5.&nbsp;Introducing WSDL">Section&nbsp;12.5, &#8220;Introducing WSDL&#8221;</a>.
+ </li>
+ <li>Added <a href="../soap_web_services/introspection.html" title="12.6.&nbsp;Introspecting SOAP Web Services with WSDL">Section&nbsp;12.6, &#8220;Introspecting SOAP Web Services with WSDL&#8221;</a>.
+ </li>
+ <li>Added <a href="../soap_web_services/google.html" title="12.7.&nbsp;Searching Google">Section&nbsp;12.7, &#8220;Searching Google&#8221;</a>.
+ </li>
+ <li>Added <a href="../soap_web_services/troubleshooting.html" title="12.8.&nbsp;Troubleshooting SOAP Web Services">Section&nbsp;12.8, &#8220;Troubleshooting SOAP Web Services&#8221;</a>.
+ </li>
+ <li>Added <a href="../soap_web_services/summary.html" title="12.9.&nbsp;Summary">Section&nbsp;12.9, &#8220;Summary&#8221;</a>.
+ </li>
+ <li>Incorporated technical reviewer revisions in <a href="../functional_programming/index.html" title="Chapter&nbsp;16.&nbsp;Functional Programming">Chapter&nbsp;16, <i>Functional Programming</i></a> and <a href="../performance_tuning/index.html" title="Chapter&nbsp;18.&nbsp;Performance Tuning">Chapter&nbsp;18, <i>Performance Tuning</i></a>.
+ </li>
+ </ul>
+ </div>
+ <a name="5.3"></a><h3 class="revdate">2004-05-12 (5.3)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>Added <tt class="methodname">isalpha()</tt> example to <a href="../performance_tuning/regular_expressions.html" title="18.3.&nbsp;Optimizing Regular Expressions">Section&nbsp;18.3, &#8220;Optimizing Regular Expressions&#8221;</a>. Thanks, Paul.
+ </li>
+ <li>Incorporated copyediting revisions into <a href="../object_oriented_framework/index.html" title="Chapter&nbsp;5.&nbsp;Objects and Object-Orientation">Chapter&nbsp;5, <i>Objects and Object-Orientation</i></a> and <a href="../file_handling/index.html" title="Chapter&nbsp;6.&nbsp;Exceptions and File Handling">Chapter&nbsp;6, <i>Exceptions and File Handling</i></a>.
+ </li>
+ <li>Fixed URL of <a href="../xml_processing/summary.html" title="9.7.&nbsp;Segue">Section&nbsp;9.7, &#8220;Segue&#8221;</a>.
+ </li>
+ </ul>
+ </div>
+ <a name="5.2"></a><h3 class="revdate">2004-05-09 (5.2)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>Fixed URL of <a href="../unit_testing/stage_1.html#roman.stage1" title="14.1.&nbsp;roman.py, stage 1">Section&nbsp;14.1, &#8220;roman.py, stage 1&#8221;</a>.
+ </li>
+ <li>Added <a href="../performance_tuning/index.html#soundex.divein" title="18.1.&nbsp;Diving in">Section&nbsp;18.1, &#8220;Diving in&#8221;</a>.
+ </li>
+ <li>Added <a href="../performance_tuning/timeit.html" title="18.2.&nbsp;Using the timeit Module">Section&nbsp;18.2, &#8220;Using the timeit Module&#8221;</a>.
+ </li>
+ <li>Added <a href="../performance_tuning/regular_expressions.html" title="18.3.&nbsp;Optimizing Regular Expressions">Section&nbsp;18.3, &#8220;Optimizing Regular Expressions&#8221;</a>.
+ </li>
+ <li>Added <a href="../performance_tuning/dictionary_lookups.html" title="18.4.&nbsp;Optimizing Dictionary Lookups">Section&nbsp;18.4, &#8220;Optimizing Dictionary Lookups&#8221;</a>.
+ </li>
+ <li>Added <a href="../performance_tuning/list_operations.html" title="18.5.&nbsp;Optimizing List Operations">Section&nbsp;18.5, &#8220;Optimizing List Operations&#8221;</a>.
+ </li>
+ <li>Added <a href="../performance_tuning/string_manipulation.html" title="18.6.&nbsp;Optimizing String Manipulation">Section&nbsp;18.6, &#8220;Optimizing String Manipulation&#8221;</a>.
+ </li>
+ <li>Added <a href="../performance_tuning/summary.html" title="18.7.&nbsp;Summary">Section&nbsp;18.7, &#8220;Summary&#8221;</a>.
+ </li>
+ </ul>
+ </div>
+ <a name="5.1"></a><h3 class="revdate">2004-05-05 (5.1)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>Clarified <a href="../regular_expressions/n_m_syntax.html#re.tens.example" title="Example&nbsp;7.7.&nbsp;Checking for Tens">Example&nbsp;7.7, &#8220;Checking for Tens&#8221;</a> and <a href="../regular_expressions/n_m_syntax.html#re.nm.example" title="Example&nbsp;7.8.&nbsp;Validating Roman Numerals with {n,m}">Example&nbsp;7.8, &#8220;Validating Roman Numerals with {n,m}&#8221;</a>.
+ </li>
+ <li>Clarified <a href="../regular_expressions/phone_numbers.html#re.phone.example" title="Example&nbsp;7.10.&nbsp;Finding Numbers">Example&nbsp;7.10, &#8220;Finding Numbers&#8221;</a>.
+ </li>
+ <li>Fixed typo in <a href="../http_web_services/etags.html#oa.etags.example.1" title="Example&nbsp;11.6.&nbsp;Testing Last-Modified">Example&nbsp;11.6, &#8220;Testing Last-Modified&#8221;</a>. Thanks, Jesir.
+ </li>
+ <li>Fixed typo in <a href="../native_data_types/lists.html#odbchelper.list.append.vs.extend" title="Example&nbsp;3.11.&nbsp;The Difference between extend and append">Example&nbsp;3.11, &#8220;The Difference between extend and append&#8221;</a>. Thanks, Daniel.
+ </li>
+ <li>Incorporated technical reviewer revisions.</li>
+ <li>Incorporated copy editor revisions in <a href="../installing_python/index.html" title="Chapter&nbsp;1.&nbsp;Installing Python">Chapter&nbsp;1, <i>Installing Python</i></a>, <a href="../getting_to_know_python/index.html" title="Chapter&nbsp;2.&nbsp;Your First Python Program">Chapter&nbsp;2, <i>Your First Python Program</i></a>, <a href="../native_data_types/index.html" title="Chapter&nbsp;3.&nbsp;Native Datatypes">Chapter&nbsp;3, <i>Native Datatypes</i></a>, and <a href="../power_of_introspection/index.html" title="Chapter&nbsp;4.&nbsp;The Power Of Introspection">Chapter&nbsp;4, <i>The Power Of Introspection</i></a>.
+ </li>
+ </ul>
+ </div>
+ <a name="5.0"></a><h3 class="revdate">2004-04-16 (5.0)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>Added <a href="../http_web_services/index.html#oa.divein" title="11.1.&nbsp;Diving in">Section&nbsp;11.1, &#8220;Diving in&#8221;</a>.
+ </li>
+ <li>Added <a href="../http_web_services/review.html" title="11.2.&nbsp;How not to fetch data over HTTP">Section&nbsp;11.2, &#8220;How not to fetch data over HTTP&#8221;</a>.
+ </li>
+ <li>Added <a href="../http_web_services/http_features.html" title="11.3.&nbsp;Features of HTTP">Section&nbsp;11.3, &#8220;Features of HTTP&#8221;</a>.
+ </li>
+ <li>Added <a href="../http_web_services/debugging.html" title="11.4.&nbsp;Debugging HTTP web services">Section&nbsp;11.4, &#8220;Debugging HTTP web services&#8221;</a>.
+ </li>
+ <li>Added <a href="../http_web_services/user_agent.html" title="11.5.&nbsp;Setting the User-Agent">Section&nbsp;11.5, &#8220;Setting the User-Agent&#8221;</a>.
+ </li>
+ <li>Added <a href="../http_web_services/etags.html" title="11.6.&nbsp;Handling Last-Modified and ETag">Section&nbsp;11.6, &#8220;Handling Last-Modified and ETag&#8221;</a>.
+ </li>
+ <li>Added <a href="../http_web_services/redirects.html" title="11.7.&nbsp;Handling redirects">Section&nbsp;11.7, &#8220;Handling redirects&#8221;</a>.
+ </li>
+ <li>Added <a href="../http_web_services/gzip_compression.html" title="11.8.&nbsp;Handling compressed data">Section&nbsp;11.8, &#8220;Handling compressed data&#8221;</a>.
+ </li>
+ <li>Added <a href="../http_web_services/alltogether.html" title="11.9.&nbsp;Putting it all together">Section&nbsp;11.9, &#8220;Putting it all together&#8221;</a>.
+ </li>
+ <li>Added <a href="../http_web_services/summary.html" title="11.10.&nbsp;Summary">Section&nbsp;11.10, &#8220;Summary&#8221;</a>.
+ </li>
+ <li>Added <a href="../native_data_types/lists.html#odbchelper.list.append.vs.extend" title="Example&nbsp;3.11.&nbsp;The Difference between extend and append">Example&nbsp;3.11, &#8220;The Difference between extend and append&#8221;</a>.
+ </li>
+ <li>Changed descriptions of how to download <span class="application">Python</span> throughout <a href="../installing_python/index.html" title="Chapter&nbsp;1.&nbsp;Installing Python">Chapter&nbsp;1, <i>Installing Python</i></a> to be more generic and less version-specific.
+ </li>
+ <li>Changed references of &#8220;<span class="quote">module</span>&#8221; to &#8220;<span class="quote">program</span>&#8221; in <a href="../getting_to_know_python/index.html#odbchelper.divein" title="2.1.&nbsp;Diving in">Section&nbsp;2.1, &#8220;Diving in&#8221;</a> and <a href="../getting_to_know_python/everything_is_an_object.html" title="2.4.&nbsp;Everything Is an Object">Section&nbsp;2.4, &#8220;Everything Is an Object&#8221;</a> since we haven't explained modules yet.
+ </li>
+ <li>Added explicit instructions in <a href="../getting_to_know_python/everything_is_an_object.html" title="2.4.&nbsp;Everything Is an Object">Section&nbsp;2.4, &#8220;Everything Is an Object&#8221;</a> for the reader to open their <span class="application">Python</span> <span class="acronym">IDE</span> and follow along with the examples.
+ </li>
+ <li>Changed all examples and descriptions that referred to truth values <tt class="constant">1</tt> and <tt class="constant">0</tt> to refer to <tt class="constant">True</tt> and <tt class="constant">False</tt>.
+ </li>
+ <li>Updated <a href="../native_data_types/formatting_strings.html#odbchelper.stringformatting.coerce" title="Example&nbsp;3.22.&nbsp;String Formatting vs. Concatenating">Example&nbsp;3.22, &#8220;String Formatting vs. Concatenating&#8221;</a> to show new <span class="application">Python</span> 2.3 <tt class="literal">TypeError</tt> message.
+ </li>
+ <li>Fixed typo in <a href="../dynamic_functions/stage6.html#plural.fib.example" title="Example&nbsp;17.19.&nbsp;Using generators instead of recursion">Example&nbsp;17.19, &#8220;Using generators instead of recursion&#8221;</a>.
+ </li>
+ <li>Fixed typo in <a href="../regular_expressions/summary.html" title="7.7.&nbsp;Summary">Section&nbsp;7.7, &#8220;Summary&#8221;</a>.
+ </li>
+ <li>Fixed typo in <a href="../dynamic_functions/stage4.html#plural.stage4.example.1" title="Example&nbsp;17.9.&nbsp;plural4.py">Example&nbsp;17.9, &#8220;plural4.py&#8221;</a>.
+ </li>
+ </ul>
+ </div>
+ <a name="4.9"></a><h3 class="revdate">2004-03-25 (4.9)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>Finished <a href="../functional_programming/all_together.html" title="16.7.&nbsp;Putting it all together">Section&nbsp;16.7, &#8220;Putting it all together&#8221;</a>.
+ </li>
+ <li>Added <a href="../functional_programming/summary.html" title="16.8.&nbsp;Summary">Section&nbsp;16.8, &#8220;Summary&#8221;</a>.
+ </li>
+ <li>Split unit testing introduction into two chapters, <a href="../unit_testing/index.html" title="Chapter&nbsp;13.&nbsp;Unit Testing">Chapter&nbsp;13, <i>Unit Testing</i></a> and <a href="../unit_testing/stage_1.html" title="Chapter&nbsp;14.&nbsp;Test-First Programming">Chapter&nbsp;14, <i>Test-First Programming</i></a>.
+ </li>
+ <li>Fixed typo in <a href="../dynamic_functions/stage4.html#plural.finishing.up" title="Example&nbsp;17.12.&nbsp;plural4.py, finishing up">Example&nbsp;17.12, &#8220;plural4.py, finishing up&#8221;</a>.
+ </li>
+ <li>Fixed typo in <a href="../dynamic_functions/stage6.html#plural.introducing.generators" title="Example&nbsp;17.18.&nbsp;Introducing generators">Example&nbsp;17.18, &#8220;Introducing generators&#8221;</a>.
+ </li>
+ </ul>
+ </div>
+ <a name="4.8"></a><h3 class="revdate">2004-03-25 (4.8)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>Finished <a href="../dynamic_functions/stage6.html" title="17.7.&nbsp;plural.py, stage 6">Section&nbsp;17.7, &#8220;plural.py, stage 6&#8221;</a>.
+ </li>
+ <li>Finished <a href="../dynamic_functions/summary.html" title="17.8.&nbsp;Summary">Section&nbsp;17.8, &#8220;Summary&#8221;</a>.
+ </li>
+ <li>Fixed broken links in <a href="../appendix/furtherreading.html" title="Appendix&nbsp;A.&nbsp;Further reading">Appendix&nbsp;A, <i>Further reading</i></a>, <a href="../appendix/abstracts.html" title="Appendix&nbsp;B.&nbsp;A 5-minute review">Appendix&nbsp;B, <i>A 5-minute review</i></a>, <a href="../appendix/tips.html" title="Appendix&nbsp;C.&nbsp;Tips and tricks">Appendix&nbsp;C, <i>Tips and tricks</i></a>, <a href="../appendix/examples.html" title="Appendix&nbsp;D.&nbsp;List of examples">Appendix&nbsp;D, <i>List of examples</i></a>.
+ </li>
+ </ul>
+ </div>
+ <a name="4.7"></a><h3 class="revdate">2004-03-21 (4.7)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>Added <a href="../dynamic_functions/index.html#plural.divein" title="17.1.&nbsp;Diving in">Section&nbsp;17.1, &#8220;Diving in&#8221;</a>.
+ </li>
+ <li>Added <a href="../dynamic_functions/stage1.html" title="17.2.&nbsp;plural.py, stage 1">Section&nbsp;17.2, &#8220;plural.py, stage 1&#8221;</a>.
+ </li>
+ <li>Added <a href="../dynamic_functions/stage2.html" title="17.3.&nbsp;plural.py, stage 2">Section&nbsp;17.3, &#8220;plural.py, stage 2&#8221;</a>.
+ </li>
+ <li>Added <a href="../dynamic_functions/stage3.html" title="17.4.&nbsp;plural.py, stage 3">Section&nbsp;17.4, &#8220;plural.py, stage 3&#8221;</a>.
+ </li>
+ <li>Added <a href="../dynamic_functions/stage4.html" title="17.5.&nbsp;plural.py, stage 4">Section&nbsp;17.5, &#8220;plural.py, stage 4&#8221;</a>.
+ </li>
+ <li>Added <a href="../dynamic_functions/stage5.html" title="17.6.&nbsp;plural.py, stage 5">Section&nbsp;17.6, &#8220;plural.py, stage 5&#8221;</a>.
+ </li>
+ <li>Added <a href="../dynamic_functions/stage6.html" title="17.7.&nbsp;plural.py, stage 6">Section&nbsp;17.7, &#8220;plural.py, stage 6&#8221;</a> (unfinished).
+ </li>
+ <li>Added <a href="../dynamic_functions/summary.html" title="17.8.&nbsp;Summary">Section&nbsp;17.8, &#8220;Summary&#8221;</a> (unfinished).
+ </li>
+ </ul>
+ </div>
+ <a name="4.6"></a><h3 class="revdate">2004-03-14 (4.6)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>Finished <a href="../regular_expressions/n_m_syntax.html" title="7.4.&nbsp;Using the {n,m} Syntax">Section&nbsp;7.4, &#8220;Using the {n,m} Syntax&#8221;</a>.
+ </li>
+ <li>Finished <a href="../regular_expressions/verbose.html" title="7.5.&nbsp;Verbose Regular Expressions">Section&nbsp;7.5, &#8220;Verbose Regular Expressions&#8221;</a>.
+ </li>
+ <li>Finished <a href="../regular_expressions/phone_numbers.html" title="7.6.&nbsp;Case study: Parsing Phone Numbers">Section&nbsp;7.6, &#8220;Case study: Parsing Phone Numbers&#8221;</a>.
+ </li>
+ <li>Expanded <a href="../regular_expressions/summary.html" title="7.7.&nbsp;Summary">Section&nbsp;7.7, &#8220;Summary&#8221;</a>.
+ </li>
+ </ul>
+ </div>
+ <a name="4.5"></a><h3 class="revdate">2004-03-07 (4.5)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>Added <a href="../regular_expressions/index.html#re.intro" title="7.1.&nbsp;Diving In">Section&nbsp;7.1, &#8220;Diving In&#8221;</a>.
+ </li>
+ <li>Added <a href="../regular_expressions/n_m_syntax.html" title="7.4.&nbsp;Using the {n,m} Syntax">Section&nbsp;7.4, &#8220;Using the {n,m} Syntax&#8221;</a> (incomplete).
+ </li>
+ <li>Added <a href="../regular_expressions/verbose.html" title="7.5.&nbsp;Verbose Regular Expressions">Section&nbsp;7.5, &#8220;Verbose Regular Expressions&#8221;</a> (incomplete).
+ </li>
+ <li>Added <a href="../regular_expressions/phone_numbers.html" title="7.6.&nbsp;Case study: Parsing Phone Numbers">Section&nbsp;7.6, &#8220;Case study: Parsing Phone Numbers&#8221;</a> (incomplete).
+ </li>
+ <li>Added <a href="../regular_expressions/summary.html" title="7.7.&nbsp;Summary">Section&nbsp;7.7, &#8220;Summary&#8221;</a>.
+ </li>
+ <li>Moved <a href="../regular_expressions/street_addresses.html" title="7.2.&nbsp;Case Study: Street Addresses">Section&nbsp;7.2, &#8220;Case Study: Street Addresses&#8221;</a> and <a href="../regular_expressions/roman_numerals.html" title="7.3.&nbsp;Case Study: Roman Numerals">Section&nbsp;7.3, &#8220;Case Study: Roman Numerals&#8221;</a> to regular expressions chapter.
+ </li>
+ <li>Added <a href="../file_handling/os_module.html#fileinfo.os.glob.example" title="Example&nbsp;6.20.&nbsp;Listing Directories with glob">Example&nbsp;6.20, &#8220;Listing Directories with glob&#8221;</a>.
+ </li>
+ <li>Added <a href="../file_handling/file_objects.html#fileinfo.files.writeandappend" title="Example&nbsp;6.7.&nbsp;Writing to Files">Example&nbsp;6.7, &#8220;Writing to Files&#8221;</a>.
+ </li>
+ <li>Added <a href="../object_oriented_framework/userdict.html#fileinfo.userdict.fromdict" title="Example&nbsp;5.11.&nbsp;Inheriting Directly from Built-In Datatype dict">Example&nbsp;5.11, &#8220;Inheriting Directly from Built-In Datatype dict&#8221;</a>.
+ </li>
+ <li>Added <a href="../scripts_and_streams/stdin_stdout_stderr.html#kgp.stdio.print.example" title="Example&nbsp;10.11.&nbsp;Printing to stderr">Example&nbsp;10.11, &#8220;Printing to stderr&#8221;</a>.
+ </li>
+ <li>Added <a href="../power_of_introspection/getattr.html#apihelper.getattr.dispatch" title="Example&nbsp;4.12.&nbsp;Creating a Dispatcher with getattr">Example&nbsp;4.12, &#8220;Creating a Dispatcher with getattr&#8221;</a> and <a href="../power_of_introspection/getattr.html#apihelper.getattr.default" title="Example&nbsp;4.13.&nbsp;getattr Default Values">Example&nbsp;4.13, &#8220;getattr Default Values&#8221;</a>.
+ </li>
+ <li>Added <a href="../getting_to_know_python/indenting_code.html#odbchelper.indenting.if" title="Example&nbsp;2.6.&nbsp;if Statements">Example&nbsp;2.6, &#8220;if Statements&#8221;</a>.
+ </li>
+ <li>Added <a href="../native_data_types/formatting_strings.html#odbchelper.stringformatting.numbers" title="Example&nbsp;3.23.&nbsp;Formatting Numbers">Example&nbsp;3.23, &#8220;Formatting Numbers&#8221;</a>.
+ </li>
+ <li>Split <a href="../object_oriented_framework/index.html" title="Chapter&nbsp;5.&nbsp;Objects and Object-Orientation">Chapter&nbsp;5, <i>Objects and Object-Orientation</i></a> into 2 chapters: <a href="../object_oriented_framework/index.html" title="Chapter&nbsp;5.&nbsp;Objects and Object-Orientation">Chapter&nbsp;5, <i>Objects and Object-Orientation</i></a> and <a href="../file_handling/index.html" title="Chapter&nbsp;6.&nbsp;Exceptions and File Handling">Chapter&nbsp;6, <i>Exceptions and File Handling</i></a>.
+ </li>
+ <li>Split <a href="../xml_processing/index.html" title="Chapter&nbsp;9.&nbsp;XML Processing">Chapter&nbsp;9, <i>XML Processing</i></a> into 2 chapters: <a href="../xml_processing/index.html" title="Chapter&nbsp;9.&nbsp;XML Processing">Chapter&nbsp;9, <i>XML Processing</i></a> and <a href="../scripts_and_streams/index.html" title="Chapter&nbsp;10.&nbsp;Scripts and Streams">Chapter&nbsp;10, <i>Scripts and Streams</i></a>.
+ </li>
+ <li>Split <a href="../unit_testing/index.html" title="Chapter&nbsp;13.&nbsp;Unit Testing">Chapter&nbsp;13, <i>Unit Testing</i></a> into 2 chapters: <a href="../unit_testing/index.html" title="Chapter&nbsp;13.&nbsp;Unit Testing">Chapter&nbsp;13, <i>Unit Testing</i></a> and <a href="../refactoring/index.html" title="Chapter&nbsp;15.&nbsp;Refactoring">Chapter&nbsp;15, <i>Refactoring</i></a>.
+ </li>
+ <li>Renamed <tt class="function">help</tt> to <tt class="function">info</tt> in <a href="../power_of_introspection/index.html" title="Chapter&nbsp;4.&nbsp;The Power Of Introspection">Chapter&nbsp;4, <i>The Power Of Introspection</i></a>.
+ </li>
+ <li>Fixed incorrect back-reference in <a href="../html_processing/locals_and_globals.html" title="8.5.&nbsp;locals and globals">Section&nbsp;8.5, &#8220;locals and globals&#8221;</a>.
+ </li>
+ <li>Fixed broken example links in <a href="../html_processing/index.html#dialect.divein" title="8.1.&nbsp;Diving in">Section&nbsp;8.1, &#8220;Diving in&#8221;</a>.
+ </li>
+ <li>Fixed missing line in example in <a href="../xml_processing/index.html#kgp.divein" title="9.1.&nbsp;Diving in">Section&nbsp;9.1, &#8220;Diving in&#8221;</a>.
+ </li>
+ <li>Fixed typo in <a href="../html_processing/introducing_sgmllib.html" title="8.2.&nbsp;Introducing sgmllib.py">Section&nbsp;8.2, &#8220;Introducing sgmllib.py&#8221;</a>.
+ </li>
+ </ul>
+ </div>
+ <a name="4.4"></a><h3 class="revdate">2003-10-08 (4.4)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>Added <a href="../installing_python/index.html#install.choosing" title="1.1.&nbsp;Which Python is right for you?">Section&nbsp;1.1, &#8220;Which Python is right for you?&#8221;</a>.
+ </li>
+ <li>Added <a href="../installing_python/windows.html" title="1.2.&nbsp;Python on Windows">Section&nbsp;1.2, &#8220;Python on Windows&#8221;</a>.
+ </li>
+ <li>Added <a href="../installing_python/macosx.html" title="1.3.&nbsp;Python on Mac OS X">Section&nbsp;1.3, &#8220;Python on Mac OS X&#8221;</a>.
+ </li>
+ <li>Added <a href="../installing_python/macos9.html" title="1.4.&nbsp;Python on Mac OS 9">Section&nbsp;1.4, &#8220;Python on Mac OS 9&#8221;</a>.
+ </li>
+ <li>Added <a href="../installing_python/redhat.html" title="1.5.&nbsp;Python on RedHat Linux">Section&nbsp;1.5, &#8220;Python on RedHat Linux&#8221;</a>.
+ </li>
+ <li>Added <a href="../installing_python/debian.html" title="1.6.&nbsp;Python on Debian GNU/Linux">Section&nbsp;1.6, &#8220;Python on Debian GNU/Linux&#8221;</a>.
+ </li>
+ <li>Added <a href="../installing_python/source.html" title="1.7.&nbsp;Python Installation from Source">Section&nbsp;1.7, &#8220;Python Installation from Source&#8221;</a>.
+ </li>
+ <li>Added <a href="../installing_python/summary.html" title="1.9.&nbsp;Summary">Section&nbsp;1.9, &#8220;Summary&#8221;</a>.
+ </li>
+ <li>Removed preface.</li>
+ <li>Fixed typo in <a href="../native_data_types/joining_lists.html#odbchelper.join.example" title="Example&nbsp;3.27.&nbsp;Output of odbchelper.py">Example&nbsp;3.27, &#8220;Output of odbchelper.py&#8221;</a>.
+ </li>
+ <li>Added link to PEP 257 in <a href="../getting_to_know_python/documenting_functions.html" title="2.3.&nbsp;Documenting Functions">Section&nbsp;2.3, &#8220;Documenting Functions&#8221;</a>.
+ </li>
+ <li>Fixed link to <a href="http://www.ibiblio.org/obp/thinkCSpy/" title="Python book for computer science majors"><i class="citetitle">How to Think Like a Computer Scientist</i></a> in <a href="../native_data_types/declaring_variables.html#odbchelper.multiassign" title="3.4.2.&nbsp;Assigning Multiple Values at Once">Section&nbsp;3.4.2, &#8220;Assigning Multiple Values at Once&#8221;</a>.
+ </li>
+ <li>Added note about implied assert in <a href="../native_data_types/tuples.html" title="3.3.&nbsp;Introducing Tuples">Section&nbsp;3.3, &#8220;Introducing Tuples&#8221;</a>.
+ </li>
+ </ul>
+ </div>
+ <a name="4.3"></a><h3 class="revdate">2003-09-28 (4.3)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>Added <a href="../functional_programming/dynamic_import.html" title="16.6.&nbsp;Dynamically importing modules">Section&nbsp;16.6, &#8220;Dynamically importing modules&#8221;</a>.
+ </li>
+ <li>Added <a href="../functional_programming/all_together.html" title="16.7.&nbsp;Putting it all together">Section&nbsp;16.7, &#8220;Putting it all together&#8221;</a> (incomplete).
+ </li>
+ <li>Fixed links in <a href="../appendix/about.html" title="Appendix&nbsp;F.&nbsp;About the book">Appendix&nbsp;F, <i>About the book</i></a>.
+ </li>
+ </ul>
+ </div>
+ <a name="4.2.1"></a><h3 class="revdate">2003-09-17 (4.2.1)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>Fixed links on index page.</li>
+ <li>Fixed syntax highlighting.</li>
+ </ul>
+ </div>
+ <a name="4.2"></a><h3 class="revdate">2003-09-12 (4.2)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>Fixed typos in <a href="../functional_programming/mapping_lists.html" title="16.4.&nbsp;Mapping lists revisited">Section&nbsp;16.4, &#8220;Mapping lists revisited&#8221;</a>, <a href="../functional_programming/filtering_lists.html" title="16.3.&nbsp;Filtering lists revisited">Section&nbsp;16.3, &#8220;Filtering lists revisited&#8221;</a>, <a href="../regular_expressions/street_addresses.html" title="7.2.&nbsp;Case Study: Street Addresses">Section&nbsp;7.2, &#8220;Case Study: Street Addresses&#8221;</a>, and <a href="../scripts_and_streams/command_line_arguments.html" title="10.6.&nbsp;Handling command-line arguments">Section&nbsp;10.6, &#8220;Handling command-line arguments&#8221;</a>. Thanks, Doug.
+ </li>
+ <li>Fixed external link in <a href="../object_oriented_framework/defining_classes.html" title="5.3.&nbsp;Defining Classes">Section&nbsp;5.3, &#8220;Defining Classes&#8221;</a>. Thanks, Harry.
+ </li>
+ <li>Changed wording at the end of <a href="../power_of_introspection/filtering_lists.html" title="4.5.&nbsp;Filtering Lists">Section&nbsp;4.5, &#8220;Filtering Lists&#8221;</a>. Thanks, Paul.
+ </li>
+ <li>Added sentence in <a href="../unit_testing/testing_for_failure.html" title="13.5.&nbsp;Testing for failure">Section&nbsp;13.5, &#8220;Testing for failure&#8221;</a> to make it clearer that we're passing a function to <tt class="function">assertRaises</tt>, not a function name as a string. Thanks, Stephen.
+ </li>
+ <li>Fixed typo in <a href="../html_processing/dialect.html" title="8.8.&nbsp;Introducing dialect.py">Section&nbsp;8.8, &#8220;Introducing dialect.py&#8221;</a>. Thanks, Wellie.
+ </li>
+ <li>Fixed links to dialectized examples.</li>
+ <li>Fixed external link to the history of Roman numerals. Thanks to many concerned Roman numeral fans around the world.</li>
+ </ul>
+ </div>
+ <a name="4.1"></a><h3 class="revdate">2002-07-28 (4.1)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>Added <a href="../scripts_and_streams/caching.html" title="10.3.&nbsp;Caching node lookups">Section&nbsp;10.3, &#8220;Caching node lookups&#8221;</a>.
+ </li>
+ <li>Added <a href="../scripts_and_streams/child_nodes.html" title="10.4.&nbsp;Finding direct children of a node">Section&nbsp;10.4, &#8220;Finding direct children of a node&#8221;</a>.
+ </li>
+ <li>Added <a href="../scripts_and_streams/handlers_by_node_type.html" title="10.5.&nbsp;Creating separate handlers by node type">Section&nbsp;10.5, &#8220;Creating separate handlers by node type&#8221;</a>.
+ </li>
+ <li>Added <a href="../scripts_and_streams/command_line_arguments.html" title="10.6.&nbsp;Handling command-line arguments">Section&nbsp;10.6, &#8220;Handling command-line arguments&#8221;</a>.
+ </li>
+ <li>Added <a href="../scripts_and_streams/all_together.html" title="10.7.&nbsp;Putting it all together">Section&nbsp;10.7, &#8220;Putting it all together&#8221;</a>.
+ </li>
+ <li>Added <a href="../scripts_and_streams/summary.html" title="10.8.&nbsp;Summary">Section&nbsp;10.8, &#8220;Summary&#8221;</a>.
+ </li>
+ <li>Fixed typo in <a href="../file_handling/os_module.html" title="6.5.&nbsp;Working with Directories">Section&nbsp;6.5, &#8220;Working with Directories&#8221;</a>. It's <tt class="function">os.getcwd()</tt>, not <tt class="function">os.path.getcwd()</tt>. Thanks, Abhishek.
+ </li>
+ <li>Fixed typo in <a href="../native_data_types/joining_lists.html" title="3.7.&nbsp;Joining Lists and Splitting Strings">Section&nbsp;3.7, &#8220;Joining Lists and Splitting Strings&#8221;</a>. When evaluated (instead of printed), the <span class="application">Python</span> <span class="acronym">IDE</span> will display single quotes around the output.
+ </li>
+ <li>Changed <tt class="function">str</tt> example in <a href="../power_of_introspection/all_together.html" title="4.8.&nbsp;Putting It All Together">Section&nbsp;4.8, &#8220;Putting It All Together&#8221;</a> to use a user-defined function, since <span class="application">Python</span> 2.2 obsoleted the old example by defining a <tt class="literal">doc string</tt> for the built-in dictionary methods. Thanks Eric.
+ </li>
+ <li>Fixed typo in <a href="../xml_processing/unicode.html" title="9.4.&nbsp;Unicode">Section&nbsp;9.4, &#8220;Unicode&#8221;</a>, "anyway" to "anywhere". Thanks Frank.
+ </li>
+ <li>Fixed typo in <a href="../unit_testing/testing_for_sanity.html" title="13.6.&nbsp;Testing for sanity">Section&nbsp;13.6, &#8220;Testing for sanity&#8221;</a>, doubled word "accept". Thanks Ralph.
+ </li>
+ <li>Fixed typo in <a href="../refactoring/refactoring.html" title="15.3.&nbsp;Refactoring">Section&nbsp;15.3, &#8220;Refactoring&#8221;</a>, <tt class="literal">C?C?C?</tt> matches 0 to 3 <tt class="literal">C</tt> characters, not 4. Thanks Ralph.
+ </li>
+ <li>Clarified and expanded explanation of implied slice indices in <a href="../native_data_types/lists.html#odbchelper.list.slicing.example" title="Example&nbsp;3.9.&nbsp;Slicing Shorthand">Example&nbsp;3.9, &#8220;Slicing Shorthand&#8221;</a>. Thanks Petr.
+ </li>
+ <li>Added historical note in <a href="../object_oriented_framework/userdict.html" title="5.5.&nbsp;Exploring UserDict: A Wrapper Class">Section&nbsp;5.5, &#8220;Exploring UserDict: A Wrapper Class&#8221;</a> now that <span class="application">Python</span> 2.2 supports subclassing built-in datatypes directly.
+ </li>
+ <li>Added explanation of <tt class="function">update</tt> dictionary method in <a href="../object_oriented_framework/userdict.html#fileinfo.userdict.init.example" title="Example&nbsp;5.9.&nbsp;Defining the UserDict Class">Example&nbsp;5.9, &#8220;Defining the UserDict Class&#8221;</a>. Thanks Petr.
+ </li>
+ <li>Clarified <span class="application">Python</span>'s lack of overloading in <a href="../object_oriented_framework/userdict.html" title="5.5.&nbsp;Exploring UserDict: A Wrapper Class">Section&nbsp;5.5, &#8220;Exploring UserDict: A Wrapper Class&#8221;</a>. Thanks Petr.
+ </li>
+ <li>Fixed typo in <a href="../html_processing/basehtmlprocessor.html#dialect.basehtml.intro" title="Example&nbsp;8.8.&nbsp;Introducing BaseHTMLProcessor">Example&nbsp;8.8, &#8220;Introducing BaseHTMLProcessor&#8221;</a>. <span class="acronym">HTML</span> comments end with two dashes and a bracket, not one. Thanks Petr.
+ </li>
+ <li>Changed tense of note about nested scopes in <a href="../html_processing/locals_and_globals.html" title="8.5.&nbsp;locals and globals">Section&nbsp;8.5, &#8220;locals and globals&#8221;</a> now that <span class="application">Python</span> 2.2 is out. Thanks Petr.
+ </li>
+ <li>Fixed typo in <a href="../html_processing/dictionary_based_string_formatting.html#dialect.unknownstarttag" title="Example&nbsp;8.14.&nbsp;Dictionary-based string formatting in BaseHTMLProcessor.py">Example&nbsp;8.14, &#8220;Dictionary-based string formatting in BaseHTMLProcessor.py&#8221;</a>; a space should have been a non-breaking space. Thanks Petr.
+ </li>
+ <li>Added title to note on derived classes in <a href="../object_oriented_framework/userdict.html" title="5.5.&nbsp;Exploring UserDict: A Wrapper Class">Section&nbsp;5.5, &#8220;Exploring UserDict: A Wrapper Class&#8221;</a>. Thanks Petr.
+ </li>
+ <li>Added title to note on downloading <tt class="filename">unittest</tt> in <a href="../refactoring/refactoring.html" title="15.3.&nbsp;Refactoring">Section&nbsp;15.3, &#8220;Refactoring&#8221;</a>. Thanks Petr.
+ </li>
+ <li>Fixed typesetting problem in <a href="../functional_programming/finding_the_path.html#regression.path.cwd.example" title="Example&nbsp;16.6.&nbsp;Running scripts in the current directory">Example&nbsp;16.6, &#8220;Running scripts in the current directory&#8221;</a>; tabs should have been spaces, and the line numbers were misaligned. Thanks Petr.
+ </li>
+ <li>Fixed capitalization typo in the tip on truth values in <a href="../native_data_types/lists.html" title="3.2.&nbsp;Introducing Lists">Section&nbsp;3.2, &#8220;Introducing Lists&#8221;</a>. It's <tt class="literal">True</tt> and <tt class="literal">False</tt>, not <tt class="literal">true</tt> and <tt class="literal">false</tt>. Thanks to everyone who pointed this out.
+ </li>
+ <li>Changed section titles of <a href="../native_data_types/index.html#odbchelper.dict" title="3.1.&nbsp;Introducing Dictionaries">Section&nbsp;3.1, &#8220;Introducing Dictionaries&#8221;</a>, <a href="../native_data_types/lists.html" title="3.2.&nbsp;Introducing Lists">Section&nbsp;3.2, &#8220;Introducing Lists&#8221;</a>, and <a href="../native_data_types/tuples.html" title="3.3.&nbsp;Introducing Tuples">Section&nbsp;3.3, &#8220;Introducing Tuples&#8221;</a>. "Dictionaries 101" was a cute way of saying that this section was an beginner's introduction to dictionaries. American
+ colleges tend to use this numbering scheme to indicate introductory courses with no prerequisites, but apparently this is
+ a distinctly American tradition, and it was unnecessarily confusing my international readers. In my defense, when I initially
+ wrote these sections a year and a half ago, it never occurred to me that I would have international readers.
+ </li>
+ <li>Upgraded to version 1.52 of the <span class="application">DocBook</span> <span class="acronym">XSL</span> stylesheets.
+ </li>
+ <li>Upgraded to version 6.52 of the <span class="application"><span class="acronym">SAXON</span></span> <span class="acronym">XSLT</span> processor from Michael Kay.
+ </li>
+ <li>Various accessibility-related stylesheet tweaks.</li>
+ <li>Somewhere between this revision and the last one, she said yes. The wedding will be next spring.</li>
+ </ul>
+ </div>
+ <a name="4.0-2"></a><h3 class="revdate">2002-04-26 (4.0-2)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>Fixed typo in <a href="../power_of_introspection/and_or.html#apihelper.andor.intro.example" title="Example&nbsp;4.15.&nbsp;Introducing and">Example&nbsp;4.15, &#8220;Introducing and&#8221;</a>.
+ </li>
+ <li>Fixed typo in <a href="../getting_to_know_python/everything_is_an_object.html#odbchelper.objects.sys.path" title="Example&nbsp;2.4.&nbsp;Import Search Path">Example&nbsp;2.4, &#8220;Import Search Path&#8221;</a>.
+ </li>
+ <li>Fixed Windows help file (missing table of contents due to base stylesheet changes).</li>
+ </ul>
+ </div>
+ <a name="4.0"></a><h3 class="revdate">2002-04-19 (4.0)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>Expanded <a href="../getting_to_know_python/everything_is_an_object.html" title="2.4.&nbsp;Everything Is an Object">Section&nbsp;2.4, &#8220;Everything Is an Object&#8221;</a> to include more about import search paths.
+ </li>
+ <li>Fixed typo in <a href="../native_data_types/lists.html#odbchelper.negative.example" title="Example&nbsp;3.7.&nbsp;Negative List Indices">Example&nbsp;3.7, &#8220;Negative List Indices&#8221;</a>. Thanks to Brian for the correction.
+ </li>
+ <li>Rewrote the tip on truth values in <a href="../native_data_types/lists.html" title="3.2.&nbsp;Introducing Lists">Section&nbsp;3.2, &#8220;Introducing Lists&#8221;</a>, now that <span class="application">Python</span> has a separate boolean datatype.
+ </li>
+ <li>Fixed typo in <a href="../object_oriented_framework/importing_modules.html" title="5.2.&nbsp;Importing Modules Using from module import">Section&nbsp;5.2, &#8220;Importing Modules Using from module import&#8221;</a> when comparing syntax to <span class="application">Java</span>. Thanks to Rick for the correction.
+ </li>
+ <li>Added note in <a href="../object_oriented_framework/userdict.html" title="5.5.&nbsp;Exploring UserDict: A Wrapper Class">Section&nbsp;5.5, &#8220;Exploring UserDict: A Wrapper Class&#8221;</a> about derived classes always overriding ancestor classes.
+ </li>
+ <li>Fixed typo in <a href="../object_oriented_framework/class_attributes.html#fileinfo.classattributes.writeable.example" title="Example&nbsp;5.18.&nbsp;Modifying Class Attributes">Example&nbsp;5.18, &#8220;Modifying Class Attributes&#8221;</a>. Thanks to Kevin for the correction.
+ </li>
+ <li>Added note in <a href="../file_handling/index.html#fileinfo.exception" title="6.1.&nbsp;Handling Exceptions">Section&nbsp;6.1, &#8220;Handling Exceptions&#8221;</a> that you can define and raise your own exceptions. Thanks to Rony for the suggestion.
+ </li>
+ <li>Fixed typo in <a href="../html_processing/dialect.html#dialect.specifictags.example" title="Example&nbsp;8.17.&nbsp;Handling specific tags">Example&nbsp;8.17, &#8220;Handling specific tags&#8221;</a>. Thanks for Rick for the correction.
+ </li>
+ <li>Added note in <a href="../html_processing/dialect.html#dialect.dialectizer.example" title="Example&nbsp;8.18.&nbsp;SGMLParser">Example&nbsp;8.18, &#8220;SGMLParser&#8221;</a> about what the return codes mean. Thanks to Howard for the suggestion.
+ </li>
+ <li>Added <tt class="function">str</tt> function when creating <tt class="classname">StringIO</tt> instance in <a href="../scripts_and_streams/index.html#kgp.openanything.example" title="Example&nbsp;10.6.&nbsp;openAnything">Example&nbsp;10.6, &#8220;openAnything&#8221;</a>. Thanks to Ganesan for the idea.
+ </li>
+ <li>Added link in <a href="../unit_testing/romantest.html" title="13.3.&nbsp;Introducing romantest.py">Section&nbsp;13.3, &#8220;Introducing romantest.py&#8221;</a> to explanation of why test cases belong in a separate file.
+ </li>
+ <li>Changed <a href="../functional_programming/finding_the_path.html" title="16.2.&nbsp;Finding the path">Section&nbsp;16.2, &#8220;Finding the path&#8221;</a> to use <tt class="function">os.path.dirname</tt> instead of <tt class="literal">os.path.split</tt>. Thanks to Marc for the idea.
+ </li>
+ <li>Added code samples (<tt class="filename">piglatin.py</tt>, <tt class="filename">parsephone.py</tt>, and <tt class="filename">plural.py</tt>) for the upcoming regular expressions chapter.
+ </li>
+ <li>Updated and expanded list of Python distributions on home page.</li>
+ </ul>
+ </div>
+ <a name="3.9"></a><h3 class="revdate">2002-01-01 (3.9)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>Added <a href="../xml_processing/unicode.html" title="9.4.&nbsp;Unicode">Section&nbsp;9.4, &#8220;Unicode&#8221;</a>.
+ </li>
+ <li>Added <a href="../xml_processing/searching.html" title="9.5.&nbsp;Searching for elements">Section&nbsp;9.5, &#8220;Searching for elements&#8221;</a>.
+ </li>
+ <li>Added <a href="../xml_processing/attributes.html" title="9.6.&nbsp;Accessing element attributes">Section&nbsp;9.6, &#8220;Accessing element attributes&#8221;</a>.
+ </li>
+ <li>Added <a href="../scripts_and_streams/index.html#kgp.openanything" title="10.1.&nbsp;Abstracting input sources">Section&nbsp;10.1, &#8220;Abstracting input sources&#8221;</a>.
+ </li>
+ <li>Added <a href="../scripts_and_streams/stdin_stdout_stderr.html" title="10.2.&nbsp;Standard input, output, and error">Section&nbsp;10.2, &#8220;Standard input, output, and error&#8221;</a>.
+ </li>
+ <li>Added simple counter <tt class="literal">for</tt> loop examples (good usage and bad usage) in <a href="../file_handling/for_loops.html" title="6.3.&nbsp;Iterating with for Loops">Section&nbsp;6.3, &#8220;Iterating with for Loops&#8221;</a>. Thanks to Kevin for the idea.
+ </li>
+ <li>Fixed typo in <a href="../native_data_types/mapping_lists.html#odbchelper.items" title="Example&nbsp;3.25.&nbsp;The keys, values, and items Functions">Example&nbsp;3.25, &#8220;The keys, values, and items Functions&#8221;</a> (two elements of <tt class="literal">params.values()</tt> were reversed).
+ </li>
+ <li>Fixed mistake in <a href="../power_of_introspection/built_in_functions.html" title="4.3.&nbsp;Using type, str, dir, and Other Built-In Functions">Section&nbsp;4.3, &#8220;Using type, str, dir, and Other Built-In Functions&#8221;</a> with regards to the name of the <tt class="filename">__builtin__</tt> module. Thanks to Denis for the correction.
+ </li>
+ <li>Added additional example in <a href="../functional_programming/finding_the_path.html" title="16.2.&nbsp;Finding the path">Section&nbsp;16.2, &#8220;Finding the path&#8221;</a> to show how to run unit tests in the current working directory, instead of the directory where <tt class="filename">regression.py</tt> is located.
+ </li>
+ <li>Modified explanation of how to derive a negative list index from a positive list index in <a href="../native_data_types/lists.html#odbchelper.negative.example" title="Example&nbsp;3.7.&nbsp;Negative List Indices">Example&nbsp;3.7, &#8220;Negative List Indices&#8221;</a>. Thanks to Renauld for the suggestion.
+ </li>
+ <li>Updated links on home page for downloading latest version of <span class="application">Python</span>.
+ </li>
+ <li>Added link on home page to Bruce Eckel's preliminary draft of <a href="http://www.mindview.net/Books/TIPython" title="advanced book on design patterns in Python"><i class="citetitle">Thinking in Python</i></a>, a marvelous (and advanced) book on design patterns and how to implement them in <span class="application">Python</span>.
+ </li>
+ </ul>
+ </div>
+ <a name="3.8"></a><h3 class="revdate">2001-11-18 (3.8)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>Added <a href="../functional_programming/finding_the_path.html" title="16.2.&nbsp;Finding the path">Section&nbsp;16.2, &#8220;Finding the path&#8221;</a>.
+ </li>
+ <li>Added <a href="../functional_programming/filtering_lists.html" title="16.3.&nbsp;Filtering lists revisited">Section&nbsp;16.3, &#8220;Filtering lists revisited&#8221;</a>.
+ </li>
+ <li>Added <a href="../functional_programming/mapping_lists.html" title="16.4.&nbsp;Mapping lists revisited">Section&nbsp;16.4, &#8220;Mapping lists revisited&#8221;</a>.
+ </li>
+ <li>Added <a href="../functional_programming/data_centric.html" title="16.5.&nbsp;Data-centric programming">Section&nbsp;16.5, &#8220;Data-centric programming&#8221;</a>.
+ </li>
+ <li>Expanded sample output in <a href="../functional_programming/index.html#regression.divein" title="16.1.&nbsp;Diving in">Section&nbsp;16.1, &#8220;Diving in&#8221;</a>.
+ </li>
+ <li>Finished <a href="../xml_processing/parsing_xml.html" title="9.3.&nbsp;Parsing XML">Section&nbsp;9.3, &#8220;Parsing XML&#8221;</a>.
+ </li>
+ </ul>
+ </div>
+ <a name="3.7"></a><h3 class="revdate">2001-09-30 (3.7)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>Added <a href="../xml_processing/packages.html" title="9.2.&nbsp;Packages">Section&nbsp;9.2, &#8220;Packages&#8221;</a>.
+ </li>
+ <li>Added <a href="../xml_processing/parsing_xml.html" title="9.3.&nbsp;Parsing XML">Section&nbsp;9.3, &#8220;Parsing XML&#8221;</a>.
+ </li>
+ <li>Cleaned up introductory paragraph in <a href="../xml_processing/index.html#kgp.divein" title="9.1.&nbsp;Diving in">Section&nbsp;9.1, &#8220;Diving in&#8221;</a>. Thanks to Matt for this suggestion.
+ </li>
+ <li>Added <span class="application">Java</span> tip in <a href="../object_oriented_framework/importing_modules.html" title="5.2.&nbsp;Importing Modules Using from module import">Section&nbsp;5.2, &#8220;Importing Modules Using from module import&#8221;</a>. Thanks to Ori for this suggestion.
+ </li>
+ <li>Fixed mistake in <a href="../power_of_introspection/all_together.html" title="4.8.&nbsp;Putting It All Together">Section&nbsp;4.8, &#8220;Putting It All Together&#8221;</a> where I implied that you could not use <tt class="literal">is None</tt> to compare to a null value in <span class="application">Python</span>. In fact, you can, and it's faster than <tt class="literal">== None</tt>. Thanks to Ori pointing this out.
+ </li>
+ <li>Clarified in <a href="../native_data_types/lists.html" title="3.2.&nbsp;Introducing Lists">Section&nbsp;3.2, &#8220;Introducing Lists&#8221;</a> where I said that <tt class="literal">li = li + other</tt> was equivalent to <tt class="literal">li.extend(other)</tt>. The result is the same, but <tt class="function">extend</tt> is faster because it doesn't create a new list. Thanks to Denis pointing this out.
+ </li>
+ <li>Fixed mistake in <a href="../native_data_types/lists.html" title="3.2.&nbsp;Introducing Lists">Section&nbsp;3.2, &#8220;Introducing Lists&#8221;</a> where I said that <tt class="literal">li += other</tt> was equivalent to <tt class="literal">li = li + other</tt>. In fact, it's equivalent to <tt class="literal">li.extend(other)</tt>, since it doesn't create a new list. Thanks to Denis pointing this out.
+ </li>
+ <li>Fixed typographical laziness in <a href="../getting_to_know_python/index.html" title="Chapter&nbsp;2.&nbsp;Your First Python Program">Chapter&nbsp;2, <i>Your First Python Program</i></a>; when I was writing it, I had not yet standardized on putting string literals in single quotes within the text. They were
+ set off by typography, but this is lost in some renditions of the book (like plain text), making it difficult to read. Thanks
+ to Denis for this suggestion.
+ </li>
+ <li>Fixed mistake in <a href="../getting_to_know_python/declaring_functions.html" title="2.2.&nbsp;Declaring Functions">Section&nbsp;2.2, &#8220;Declaring Functions&#8221;</a> where I said that statically typed languages always use explicit variable + datatype declarations to enforce static typing.
+ Most do, but there are some statically typed languages where the compiler figures out what type the variable is based on
+ usage within the code. Thanks to Tony for pointing this out.
+ </li>
+ <li>Added link to <a href="http://es.diveintopython.org/">Spanish translation</a>.
+ </li>
+ </ul>
+ </div>
+ <a name="3.6.4"></a><h3 class="revdate">2001-09-06 (3.6.4)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>Added code in <tt class="classname">BaseHTMLProcessor</tt> to handle non-<span class="acronym">HTML</span> entity references, and added a note about it in <a href="../html_processing/basehtmlprocessor.html" title="8.4.&nbsp;Introducing BaseHTMLProcessor.py">Section&nbsp;8.4, &#8220;Introducing BaseHTMLProcessor.py&#8221;</a>.
+ </li>
+ <li>Modified <a href="../html_processing/locals_and_globals.html#dialect.globals.example" title="Example&nbsp;8.11.&nbsp;Introducing globals">Example&nbsp;8.11, &#8220;Introducing globals&#8221;</a> to include <tt class="filename">htmlentitydefs</tt> in the output.
+ </li>
+ </ul>
+ </div>
+ <a name="3.6.3"></a><h3 class="revdate">2001-09-04 (3.6.3)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>Fixed typo in <a href="../xml_processing/index.html#kgp.divein" title="9.1.&nbsp;Diving in">Section&nbsp;9.1, &#8220;Diving in&#8221;</a>.
+ </li>
+ <li>Added link to <a href="http://kr.diveintopython.org/html/index.htm">Korean translation</a>.
+ </li>
+ </ul>
+ </div>
+ <a name="3.6.2"></a><h3 class="revdate">2001-08-31 (3.6.2)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>Fixed typo in <a href="../unit_testing/testing_for_sanity.html" title="13.6.&nbsp;Testing for sanity">Section&nbsp;13.6, &#8220;Testing for sanity&#8221;</a> (the last requirement was listed twice).
+ </li>
+ </ul>
+ </div>
+ <a name="3.6"></a><h3 class="revdate">2001-08-31 (3.6)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>Finished <a href="../html_processing/index.html" title="Chapter&nbsp;8.&nbsp;HTML Processing">Chapter&nbsp;8, <i>HTML Processing</i></a> with <a href="../html_processing/all_together.html" title="8.9.&nbsp;Putting it all together">Section&nbsp;8.9, &#8220;Putting it all together&#8221;</a> and <a href="../html_processing/summary.html" title="8.10.&nbsp;Summary">Section&nbsp;8.10, &#8220;Summary&#8221;</a>.
+ </li>
+ <li>Added <a href="../refactoring/postscript.html" title="15.4.&nbsp;Postscript">Section&nbsp;15.4, &#8220;Postscript&#8221;</a>.
+ </li>
+ <li>Started <a href="../xml_processing/index.html" title="Chapter&nbsp;9.&nbsp;XML Processing">Chapter&nbsp;9, <i>XML Processing</i></a> with <a href="../xml_processing/index.html#kgp.divein" title="9.1.&nbsp;Diving in">Section&nbsp;9.1, &#8220;Diving in&#8221;</a>.
+ </li>
+ <li>Started <a href="../functional_programming/index.html" title="Chapter&nbsp;16.&nbsp;Functional Programming">Chapter&nbsp;16, <i>Functional Programming</i></a> with <a href="../functional_programming/index.html#regression.divein" title="16.1.&nbsp;Diving in">Section&nbsp;16.1, &#8220;Diving in&#8221;</a>.
+ </li>
+ <li>Fixed long-standing bug in colorizing script that improperly colorized the examples in <a href="../html_processing/index.html" title="Chapter&nbsp;8.&nbsp;HTML Processing">Chapter&nbsp;8, <i>HTML Processing</i></a>.
+ </li>
+ <li>Added link to <a href="http://fr.diveintopython.org/toc.html">French translation</a>. They did the right thing and translated the source <span class="acronym">XML</span>, so they can re-use all my build scripts and make their work available in six different formats.
+ </li>
+ <li>Upgraded to version 1.43 of the <span class="application">DocBook</span> <span class="acronym">XSL</span> stylesheets.
+ </li>
+ <li>Upgraded to version 6.43 of the <span class="application"><span class="acronym">SAXON</span></span> <span class="acronym">XSLT</span> processor from Michael Kay.
+ </li>
+ <li>Massive stylesheet changes, moving away from a table-based layout and towards more appropriate use of cascading style sheets.
+ Unfortunately, <span class="acronym">CSS</span> has as many compatibility problems as anything else, so there are still some tables used in the header and footer. The resulting
+ <span class="acronym">HTML</span> version looks worse in <span class="application">Netscape</span> 4, but better in modern browsers, including <span class="application">Netscape</span> 6, <span class="application">Mozilla</span>, <span class="application">Internet Explorer</span> 5, <span class="application">Opera</span> 5, <span class="application">Konqueror</span>, and <span class="application">iCab</span>. And it's still completely readable in Lynx. I love Lynx. It was my first web browser. You never forget your first.
+ </li>
+ <li>Moved to <a href="http://jakarta.apache.org/ant/"><span class="application">Ant</span></a> to have better control over the build process, which is especially important now that I'm juggling six output formats and
+ two languages.
+ </li>
+ <li>Consolidated the available downloadable archives; previously, I had different files for each platform, because the .zip files
+ that <span class="application">Python</span>'s <tt class="filename">zipfile</tt> module creates are non-standard and can't be opened by <span class="application">Aladdin Expander</span> on <span class="abbrev">Mac</span> <span class="acronym">OS</span>. But the .zip files that <span class="application">Ant</span> creates are completely standard and cross-platform. Go <span class="application">Ant</span>!
+ </li>
+ <li>Now hosting the complete <span class="acronym">XML</span> source, <span class="acronym">XSL</span> stylesheets, and associated scripts and libraries on SourceForge. There's also <span class="acronym">CVS</span> access for the really adventurous.
+ </li>
+ <li>Re-licensed the example code under the new-and-improved <span class="acronym">GPL</span>-compatible <a href="http://www.python.org/2.1.1/license.html">Python 2.1.1 license</a>. Thanks, Guido; people really do care, and it really does matter.
+ </li>
+ </ul>
+ </div>
+ <a name="3.5"></a><h3 class="revdate">2001-06-26 (3.5)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>Added explanation of strong/weak/static/dynamic datatypes in <a href="../getting_to_know_python/declaring_functions.html" title="2.2.&nbsp;Declaring Functions">Section&nbsp;2.2, &#8220;Declaring Functions&#8221;</a>.
+ </li>
+ <li>Added case-sensitivity example in <a href="../native_data_types/index.html#odbchelper.dict" title="3.1.&nbsp;Introducing Dictionaries">Section&nbsp;3.1, &#8220;Introducing Dictionaries&#8221;</a>.
+ </li>
+ <li>Use <tt class="function">os.path.normcase</tt> in <a href="../object_oriented_framework/index.html" title="Chapter&nbsp;5.&nbsp;Objects and Object-Orientation">Chapter&nbsp;5, <i>Objects and Object-Orientation</i></a> to compensate for inferior operating systems whose files aren't case-sensitive.
+ </li>
+ <li>Fixed indentation problems in code samples in <span class="acronym">PDF</span> version.
+ </li>
+ </ul>
+ </div>
+ <a name="3.4"></a><h3 class="revdate">2001-05-31 (3.4)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>Added <a href="../unit_testing/stage_5.html" title="14.5.&nbsp;roman.py, stage 5">Section&nbsp;14.5, &#8220;roman.py, stage 5&#8221;</a>.
+ </li>
+ <li>Added <a href="../refactoring/index.html#roman.bugs" title="15.1.&nbsp;Handling bugs">Section&nbsp;15.1, &#8220;Handling bugs&#8221;</a>.
+ </li>
+ <li>Added <a href="../refactoring/handling_changing_requirements.html" title="15.2.&nbsp;Handling changing requirements">Section&nbsp;15.2, &#8220;Handling changing requirements&#8221;</a>.
+ </li>
+ <li>Added <a href="../refactoring/refactoring.html" title="15.3.&nbsp;Refactoring">Section&nbsp;15.3, &#8220;Refactoring&#8221;</a>.
+ </li>
+ <li>Added <a href="../refactoring/summary.html" title="15.5.&nbsp;Summary">Section&nbsp;15.5, &#8220;Summary&#8221;</a>.
+ </li>
+ <li>Fixed yet another stylesheet bug that was dropping nested <tt class="sgmltag-element">&lt;/span&gt;</tt> tags.
+ </li>
+ </ul>
+ </div>
+ <a name="3.3"></a><h3 class="revdate">2001-05-24 (3.3)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>Added <a href="../unit_testing/diving_in.html" title="13.2.&nbsp;Diving in">Section&nbsp;13.2, &#8220;Diving in&#8221;</a>.
+ </li>
+ <li>Added <a href="../unit_testing/romantest.html" title="13.3.&nbsp;Introducing romantest.py">Section&nbsp;13.3, &#8220;Introducing romantest.py&#8221;</a>.
+ </li>
+ <li>Added <a href="../unit_testing/testing_for_success.html" title="13.4.&nbsp;Testing for success">Section&nbsp;13.4, &#8220;Testing for success&#8221;</a>.
+ </li>
+ <li>Added <a href="../unit_testing/testing_for_failure.html" title="13.5.&nbsp;Testing for failure">Section&nbsp;13.5, &#8220;Testing for failure&#8221;</a>.
+ </li>
+ <li>Added <a href="../unit_testing/testing_for_sanity.html" title="13.6.&nbsp;Testing for sanity">Section&nbsp;13.6, &#8220;Testing for sanity&#8221;</a>.
+ </li>
+ <li>Added <a href="../unit_testing/stage_1.html#roman.stage1" title="14.1.&nbsp;roman.py, stage 1">Section&nbsp;14.1, &#8220;roman.py, stage 1&#8221;</a>.
+ </li>
+ <li>Added <a href="../unit_testing/stage_2.html" title="14.2.&nbsp;roman.py, stage 2">Section&nbsp;14.2, &#8220;roman.py, stage 2&#8221;</a>.
+ </li>
+ <li>Added <a href="../unit_testing/stage_3.html" title="14.3.&nbsp;roman.py, stage 3">Section&nbsp;14.3, &#8220;roman.py, stage 3&#8221;</a>.
+ </li>
+ <li>Added <a href="../unit_testing/stage_4.html" title="14.4.&nbsp;roman.py, stage 4">Section&nbsp;14.4, &#8220;roman.py, stage 4&#8221;</a>.
+ </li>
+ <li>Tweaked stylesheets in an endless quest for complete <span class="application">Netscape</span>/<span class="application">Mozilla</span> compatibility.
+ </li>
+ </ul>
+ </div>
+ <a name="3.2"></a><h3 class="revdate">2001-05-03 (3.2)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>Added <a href="../html_processing/dialect.html" title="8.8.&nbsp;Introducing dialect.py">Section&nbsp;8.8, &#8220;Introducing dialect.py&#8221;</a>.
+ </li>
+ <li>Added <a href="../regular_expressions/street_addresses.html" title="7.2.&nbsp;Case Study: Street Addresses">Section&nbsp;7.2, &#8220;Case Study: Street Addresses&#8221;</a>.
+ </li>
+ <li>Fixed bug in <tt class="function">handle_decl</tt> method that would produce incorrect declarations (adding a space where it couldn't be).
+ </li>
+ <li>Fixed bug in <span class="acronym">CSS</span> (introduced in 2.9) where body background color was missing.
+ </li>
+ </ul>
+ </div>
+ <a name="3.1"></a><h3 class="revdate">2001-04-18 (3.1)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>Added code in <a href="../html_processing/index.html#dialect.divein" title="8.1.&nbsp;Diving in"><tt class="filename">BaseHTMLProcessor.py</tt></a> to handle declarations, now that <span class="application">Python</span> 2.1 supports them.
+ </li>
+ <li>Added note about nested scopes in <a href="../html_processing/locals_and_globals.html" title="8.5.&nbsp;locals and globals">Section&nbsp;8.5, &#8220;locals and globals&#8221;</a>.
+ </li>
+ <li>Fixed obscure bug in <a href="../html_processing/index.html#dialect.basehtml.listing" title="Example&nbsp;8.1.&nbsp;BaseHTMLProcessor.py">Example&nbsp;8.1, &#8220;BaseHTMLProcessor.py&#8221;</a> where attribute values with character entities would not be properly escaped.
+ </li>
+ <li>Now recommending (but not requiring) <span class="application">Python</span> 2.1, due to its support of declarations in <tt class="filename">sgmllib.py</tt>.
+ </li>
+ <li>Updated download links on the <a href="http://diveintopython.org/">home page</a> to point to <span class="application">Python</span> 2.1, where available.
+ </li>
+ <li>Moved to versioned filenames, to help people who redistribute the book.</li>
+ </ul>
+ </div>
+ <a name="3.0"></a><h3 class="revdate">2001-04-16 (3.0)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>Fixed minor bug in code listing in <a href="../html_processing/index.html" title="Chapter&nbsp;8.&nbsp;HTML Processing">Chapter&nbsp;8, <i>HTML Processing</i></a>.
+ </li>
+ <li>Added link to Chinese translation on <a href="http://diveintopython.org/">home page</a>.
+ </li>
+ </ul>
+ </div>
+ <a name="2.9"></a><h3 class="revdate">2001-04-13 (2.9)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>Added <a href="../html_processing/locals_and_globals.html" title="8.5.&nbsp;locals and globals">Section&nbsp;8.5, &#8220;locals and globals&#8221;</a>.
+ </li>
+ <li>Added <a href="../html_processing/dictionary_based_string_formatting.html" title="8.6.&nbsp;Dictionary-based string formatting">Section&nbsp;8.6, &#8220;Dictionary-based string formatting&#8221;</a>.
+ </li>
+ <li>Tightened code in <a href="../html_processing/index.html" title="Chapter&nbsp;8.&nbsp;HTML Processing">Chapter&nbsp;8, <i>HTML Processing</i></a>, specifically <tt class="classname">ChefDialectizer</tt>, to use fewer and simpler regular expressions.
+ </li>
+ <li>Fixed a stylesheet bug that was inserting blank pages between chapters in the <span class="acronym">PDF</span> version.
+ </li>
+ <li>Fixed a script bug that was stripping the <tt class="literal">DOCTYPE</tt> from the <a href="http://diveintopython.org/">home page</a>.
+ </li>
+ <li>Added link to <a href="http://www.activestate.com/ASPN/Python/Cookbook/" title="growing archive of annotated code samples"><span class="application">Python</span> Cookbook</a>, and added a few links to individual recipes in <a href="../appendix/furtherreading.html" title="Appendix&nbsp;A.&nbsp;Further reading">Appendix&nbsp;A, <i>Further reading</i></a>.
+ </li>
+ <li>Switched to <a href="http://www.google.com/services/free.html">Google</a> for searching on <tt class="systemitem">http://diveintopython.org/</tt>.
+ </li>
+ <li>Upgraded to version 1.36 of the <span class="application">DocBook</span> <span class="acronym">XSL</span> stylesheets, which was much more difficult than it sounds. There may still be lingering bugs.
+ </li>
+ </ul>
+ </div>
+ <a name="2.8"></a><h3 class="revdate">2001-03-26 (2.8)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>Added <a href="../html_processing/extracting_data.html" title="8.3.&nbsp;Extracting data from HTML documents">Section&nbsp;8.3, &#8220;Extracting data from HTML documents&#8221;</a>.
+ </li>
+ <li>Added <a href="../html_processing/basehtmlprocessor.html" title="8.4.&nbsp;Introducing BaseHTMLProcessor.py">Section&nbsp;8.4, &#8220;Introducing BaseHTMLProcessor.py&#8221;</a>.
+ </li>
+ <li>Added <a href="../html_processing/quoting_attribute_values.html" title="8.7.&nbsp;Quoting attribute values">Section&nbsp;8.7, &#8220;Quoting attribute values&#8221;</a>.
+ </li>
+ <li>Tightened up code in <a href="../power_of_introspection/index.html" title="Chapter&nbsp;4.&nbsp;The Power Of Introspection">Chapter&nbsp;4, <i>The Power Of Introspection</i></a>, using the built-in function <tt class="function">callable</tt> instead of manually checking types.
+ </li>
+ <li>Moved <a href="../object_oriented_framework/importing_modules.html" title="5.2.&nbsp;Importing Modules Using from module import">Section&nbsp;5.2, &#8220;Importing Modules Using from module import&#8221;</a> from <a href="../power_of_introspection/index.html" title="Chapter&nbsp;4.&nbsp;The Power Of Introspection">Chapter&nbsp;4, <i>The Power Of Introspection</i></a> to <a href="../object_oriented_framework/index.html" title="Chapter&nbsp;5.&nbsp;Objects and Object-Orientation">Chapter&nbsp;5, <i>Objects and Object-Orientation</i></a>.
+ </li>
+ <li>Fixed typo in code example in <a href="../object_oriented_framework/index.html#fileinfo.divein" title="5.1.&nbsp;Diving In">Section&nbsp;5.1, &#8220;Diving In&#8221;</a> (added colon).
+ </li>
+ <li>Added several additional downloadable example scripts.</li>
+ <li>Added Windows Help output format.</li>
+ </ul>
+ </div>
+ <a name="2.7"></a><h3 class="revdate">2001-03-16 (2.7)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>Added <a href="../html_processing/introducing_sgmllib.html" title="8.2.&nbsp;Introducing sgmllib.py">Section&nbsp;8.2, &#8220;Introducing sgmllib.py&#8221;</a>.
+ </li>
+ <li>Tightened up code in <a href="../html_processing/index.html" title="Chapter&nbsp;8.&nbsp;HTML Processing">Chapter&nbsp;8, <i>HTML Processing</i></a>.
+ </li>
+ <li>Changed code in <a href="../getting_to_know_python/index.html" title="Chapter&nbsp;2.&nbsp;Your First Python Program">Chapter&nbsp;2, <i>Your First Python Program</i></a> to use <tt class="function">items</tt> method instead of <tt class="function">keys</tt>.
+ </li>
+ <li>Moved <a href="../native_data_types/declaring_variables.html#odbchelper.multiassign" title="3.4.2.&nbsp;Assigning Multiple Values at Once">Section&nbsp;3.4.2, &#8220;Assigning Multiple Values at Once&#8221;</a> section to <a href="../getting_to_know_python/index.html" title="Chapter&nbsp;2.&nbsp;Your First Python Program">Chapter&nbsp;2, <i>Your First Python Program</i></a>.
+ </li>
+ <li>Edited note about <tt class="function">join</tt> string method, and provided a link to the new entry in <a href="http://www.python.org/doc/FAQ.html"><i class="citetitle">The Whole <span class="application">Python</span> <span class="acronym">FAQ</span></i></a> that explains <a href="http://www.python.org/cgi-bin/faqw.py?query=4.96&amp;querytype=simple&amp;casefold=yes&amp;req=search">why <tt class="function">join</tt> is a string method</a> instead of a list method.
+ </li>
+ <li>Rewrote <a href="../power_of_introspection/and_or.html" title="4.6.&nbsp;The Peculiar Nature of and and or">Section&nbsp;4.6, &#8220;The Peculiar Nature of and and or&#8221;</a> to emphasize the fundamental nature of <tt class="literal">and</tt> and <tt class="literal">or</tt> and de-emphasize the <tt class="literal">and-or</tt> trick.
+ </li>
+ <li>Reorganized language comparisons into <tt class="sgmltag-element">note</tt>s.
+ </li>
+ </ul>
+ </div>
+ <a name="2.6"></a><h3 class="revdate">2001-02-28 (2.6)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>The <span class="acronym">PDF</span> and <span class="application">Word</span> versions now have colorized examples, an improved table of contents, and properly indented <tt class="sgmltag-element">tip</tt>s and <tt class="sgmltag-element">note</tt>s.
+ </li>
+ <li>The <span class="application">Word</span> version is now in native <span class="application">Word</span> format, compatible with <span class="application">Word 97</span>.
+ </li>
+ <li>The <span class="acronym">PDF</span> and text versions now have fewer problems with improperly converted special characters (like trademark symbols and curly
+ quotes).
+ </li>
+ <li>Added link to download <span class="application">Word</span> version for <span class="acronym">UNIX</span>, in case some twisted soul wants to import it into <span class="application">StarOffice</span> or something.
+ </li>
+ <li>Fixed several <tt class="sgmltag-element">note</tt>s which were missing titles.
+ </li>
+ <li>Fixed stylesheets to work around bug in <span class="application">Internet Explorer</span> 5 for <span class="abbrev">Mac</span> <span class="acronym">OS</span> which caused colorized words in the examples to be displayed in the wrong font. (Hello?!? Microsoft? Which part of <tt class="sgmltag-element">&lt;pre&gt;</tt> don't you understand?)
+ </li>
+ <li>Fixed archive corruption in <span class="abbrev">Mac</span> <span class="acronym">OS</span> downloads.
+ </li>
+ <li>In first section of each chapter, added link to download examples. (My access logs show that people skim or skip the two
+ pages where they could have downloaded them (the <a href="http://diveintopython.org/" title="Dive Into Python home page">home page</a> and preface), then scramble to find a download link once they actually start reading.)
+ </li>
+ <li>Tightened the <a href="http://diveintopython.org/" title="Dive Into Python home page">home page</a> and preface even more, in the hopes that someday someone will read them.
+ </li>
+ <li>Soon I hope to get back to actually writing this book instead of debugging it.</li>
+ </ul>
+ </div>
+ <a name="2.5"></a><h3 class="revdate">2001-02-23 (2.5)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>Added <a href="../file_handling/more_on_modules.html" title="6.4.&nbsp;Using sys.modules">Section&nbsp;6.4, &#8220;Using sys.modules&#8221;</a>.
+ </li>
+ <li>Added <a href="../file_handling/os_module.html" title="6.5.&nbsp;Working with Directories">Section&nbsp;6.5, &#8220;Working with Directories&#8221;</a>.
+ </li>
+ <li>Moved <a href="../file_handling/os_module.html#splittingpathnames.example" title="Example&nbsp;6.17.&nbsp;Splitting Pathnames">Example&nbsp;6.17, &#8220;Splitting Pathnames&#8221;</a> from <a href="../native_data_types/declaring_variables.html#odbchelper.multiassign" title="3.4.2.&nbsp;Assigning Multiple Values at Once">Section&nbsp;3.4.2, &#8220;Assigning Multiple Values at Once&#8221;</a> to <a href="../file_handling/os_module.html" title="6.5.&nbsp;Working with Directories">Section&nbsp;6.5, &#8220;Working with Directories&#8221;</a>.
+ </li>
+ <li>Added <a href="../file_handling/all_together.html" title="6.6.&nbsp;Putting It All Together">Section&nbsp;6.6, &#8220;Putting It All Together&#8221;</a>.
+ </li>
+ <li>Added <a href="../object_oriented_framework/summary.html" title="5.10.&nbsp;Summary">Section&nbsp;5.10, &#8220;Summary&#8221;</a>.
+ </li>
+ <li>Added <a href="../html_processing/index.html#dialect.divein" title="8.1.&nbsp;Diving in">Section&nbsp;8.1, &#8220;Diving in&#8221;</a>.
+ </li>
+ <li>Fixed program listing in <a href="../file_handling/for_loops.html#dictionaryiter.example" title="Example&nbsp;6.10.&nbsp;Iterating Through a Dictionary">Example&nbsp;6.10, &#8220;Iterating Through a Dictionary&#8221;</a> which was missing a colon.
+ </li>
+ </ul>
+ </div>
+ <a name="2.4.1"></a><h3 class="revdate">2001-02-12 (2.4.1)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>Changed newsgroup links to use &#8220;<span class="quote">news:</span>&#8221; protocol, now that <tt class="systemitem">deja.com</tt> is defunct.
+ </li>
+ <li>Added file sizes to download links.</li>
+ </ul>
+ </div>
+ <a name="2.4"></a><h3 class="revdate">2001-02-12 (2.4)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>Added &#8220;<span class="quote">further reading</span>&#8221; links in most sections, and collated them in <a href="../appendix/furtherreading.html" title="Appendix&nbsp;A.&nbsp;Further reading">Appendix&nbsp;A, <i>Further reading</i></a>.
+ </li>
+ <li>Added <span class="acronym">URL</span>s in parentheses next to external links in text version.
+ </li>
+ </ul>
+ </div>
+ <a name="2.3"></a><h3 class="revdate">2001-02-09 (2.3)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>Rewrote some of the code in <a href="../object_oriented_framework/index.html" title="Chapter&nbsp;5.&nbsp;Objects and Object-Orientation">Chapter&nbsp;5, <i>Objects and Object-Orientation</i></a> to use class attributes and a better example of multi-variable assignment.
+ </li>
+ <li>Reorganized <a href="../object_oriented_framework/index.html" title="Chapter&nbsp;5.&nbsp;Objects and Object-Orientation">Chapter&nbsp;5, <i>Objects and Object-Orientation</i></a> to put the class sections first.
+ </li>
+ <li>Added <a href="../object_oriented_framework/class_attributes.html" title="5.8.&nbsp;Introducing Class Attributes">Section&nbsp;5.8, &#8220;Introducing Class Attributes&#8221;</a>.
+ </li>
+ <li>Added <a href="../file_handling/index.html#fileinfo.exception" title="6.1.&nbsp;Handling Exceptions">Section&nbsp;6.1, &#8220;Handling Exceptions&#8221;</a>.
+ </li>
+ <li>Added <a href="../file_handling/file_objects.html" title="6.2.&nbsp;Working with File Objects">Section&nbsp;6.2, &#8220;Working with File Objects&#8221;</a>.
+ </li>
+ <li>Merged the &#8220;<span class="quote">review</span>&#8221; section in <a href="../object_oriented_framework/index.html" title="Chapter&nbsp;5.&nbsp;Objects and Object-Orientation">Chapter&nbsp;5, <i>Objects and Object-Orientation</i></a> into <a href="../object_oriented_framework/index.html#fileinfo.divein" title="5.1.&nbsp;Diving In">Section&nbsp;5.1, &#8220;Diving In&#8221;</a>.
+ </li>
+ <li>Colorized all program listings and examples.</li>
+ <li>Fixed important error in <a href="../getting_to_know_python/declaring_functions.html" title="2.2.&nbsp;Declaring Functions">Section&nbsp;2.2, &#8220;Declaring Functions&#8221;</a>: functions that do not explicitly return a value return <tt class="literal">None</tt>, so you <span class="emphasis"><em>can</em></span> assign the return value of such a function to a variable without raising an exception.
+ </li>
+ <li>Added minor clarifications to <a href="../getting_to_know_python/documenting_functions.html" title="2.3.&nbsp;Documenting Functions">Section&nbsp;2.3, &#8220;Documenting Functions&#8221;</a>, <a href="../getting_to_know_python/everything_is_an_object.html" title="2.4.&nbsp;Everything Is an Object">Section&nbsp;2.4, &#8220;Everything Is an Object&#8221;</a>, and <a href="../native_data_types/declaring_variables.html" title="3.4.&nbsp;Declaring variables">Section&nbsp;3.4, &#8220;Declaring variables&#8221;</a>.
+ </li>
+ </ul>
+ </div>
+ <a name="2.2"></a><h3 class="revdate">2001-02-02 (2.2)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>Edited <a href="../power_of_introspection/getattr.html" title="4.4.&nbsp;Getting Object References With getattr">Section&nbsp;4.4, &#8220;Getting Object References With getattr&#8221;</a>.
+ </li>
+ <li>Added titles to <tt class="sgmltag-element">xref</tt> tags, so they can have their cute little tooltips too.
+ </li>
+ <li>Changed the look of the revision history page.</li>
+ <li>Fixed problem I introduced yesterday in my <span class="acronym">HTML</span> post-processing script that was causing invalid <span class="acronym">HTML</span> character references and breaking some browsers.
+ </li>
+ <li>Upgraded to version 1.29 of the <span class="application">DocBook</span> <span class="acronym">XSL</span> stylesheets.
+ </li>
+ </ul>
+ </div>
+ <a name="2.1"></a><h3 class="revdate">2001-02-01 (2.1)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>Rewrote the example code of <a href="../power_of_introspection/index.html" title="Chapter&nbsp;4.&nbsp;The Power Of Introspection">Chapter&nbsp;4, <i>The Power Of Introspection</i></a> to use <tt class="function">getattr</tt> instead of <tt class="function">exec</tt> and <tt class="function">eval</tt>, and rewrote explanatory text to match.
+ </li>
+ <li>Added example of list operators in <a href="../native_data_types/lists.html" title="3.2.&nbsp;Introducing Lists">Section&nbsp;3.2, &#8220;Introducing Lists&#8221;</a>.
+ </li>
+ <li>Added links to relevant sections in the summary lists at the end of each chapter (<a href="../native_data_types/summary.html" title="3.8.&nbsp;Summary">Section&nbsp;3.8, &#8220;Summary&#8221;</a> and <a href="../power_of_introspection/summary.html" title="4.9.&nbsp;Summary">Section&nbsp;4.9, &#8220;Summary&#8221;</a>).
+ </li>
+ </ul>
+ </div>
+ <a name="2.0"></a><h3 class="revdate">2001-01-31 (2.0)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>Split <a href="../object_oriented_framework/special_class_methods.html" title="5.6.&nbsp;Special Class Methods">Section&nbsp;5.6, &#8220;Special Class Methods&#8221;</a> into three sections, <a href="../object_oriented_framework/userdict.html" title="5.5.&nbsp;Exploring UserDict: A Wrapper Class">Section&nbsp;5.5, &#8220;Exploring UserDict: A Wrapper Class&#8221;</a>, <a href="../object_oriented_framework/special_class_methods.html" title="5.6.&nbsp;Special Class Methods">Section&nbsp;5.6, &#8220;Special Class Methods&#8221;</a>, and <a href="../object_oriented_framework/special_class_methods2.html" title="5.7.&nbsp;Advanced Special Class Methods">Section&nbsp;5.7, &#8220;Advanced Special Class Methods&#8221;</a>.
+ </li>
+ <li>Changed notes on <a href="../object_oriented_framework/instantiating_classes.html" title="5.4.&nbsp;Instantiating Classes">garbage collection</a> to point out that <span class="application">Python</span> 2.0 and later can handle circular references without additional coding.
+ </li>
+ <li>Fixed <span class="acronym">UNIX</span> downloads to include all relevant files.
+ </li>
+ </ul>
+ </div>
+ <a name="1.9"></a><h3 class="revdate">2001-01-15 (1.9)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>Removed introduction to <a href="../getting_to_know_python/index.html" title="Chapter&nbsp;2.&nbsp;Your First Python Program">Chapter&nbsp;2, <i>Your First Python Program</i></a>.
+ </li>
+ <li>Removed introduction to <a href="../power_of_introspection/index.html" title="Chapter&nbsp;4.&nbsp;The Power Of Introspection">Chapter&nbsp;4, <i>The Power Of Introspection</i></a>.
+ </li>
+ <li>Removed introduction to <a href="../object_oriented_framework/index.html" title="Chapter&nbsp;5.&nbsp;Objects and Object-Orientation">Chapter&nbsp;5, <i>Objects and Object-Orientation</i></a>.
+ </li>
+ <li>Edited text ruthlessly. I tend to ramble.</li>
+ </ul>
+ </div>
+ <a name="1.8"></a><h3 class="revdate">2001-01-12 (1.8)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>Added more examples to <a href="../native_data_types/declaring_variables.html#odbchelper.multiassign" title="3.4.2.&nbsp;Assigning Multiple Values at Once">Section&nbsp;3.4.2, &#8220;Assigning Multiple Values at Once&#8221;</a>.
+ </li>
+ <li>Added <a href="../object_oriented_framework/defining_classes.html" title="5.3.&nbsp;Defining Classes">Section&nbsp;5.3, &#8220;Defining Classes&#8221;</a>.
+ </li>
+ <li>Added <a href="../object_oriented_framework/instantiating_classes.html" title="5.4.&nbsp;Instantiating Classes">Section&nbsp;5.4, &#8220;Instantiating Classes&#8221;</a>.
+ </li>
+ <li>Added <a href="../object_oriented_framework/special_class_methods.html" title="5.6.&nbsp;Special Class Methods">Section&nbsp;5.6, &#8220;Special Class Methods&#8221;</a>.
+ </li>
+ <li>More minor stylesheet tweaks, including adding titles to <tt class="sgmltag-element">link</tt> tags, which, if your browser is cool enough, will display a description of the link target in a cute little tooltip.
+ </li>
+ </ul>
+ </div>
+ <a name="1.71"></a><h3 class="revdate">2001-01-03 (1.71)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>Made several modifications to stylesheets to improve browser compatibility.</li>
+ </ul>
+ </div>
+ <a name="1.7"></a><h3 class="revdate">2001-01-02 (1.7)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>Added introduction to <a href="../getting_to_know_python/index.html" title="Chapter&nbsp;2.&nbsp;Your First Python Program">Chapter&nbsp;2, <i>Your First Python Program</i></a>.
+ </li>
+ <li>Added introduction to <a href="../power_of_introspection/index.html" title="Chapter&nbsp;4.&nbsp;The Power Of Introspection">Chapter&nbsp;4, <i>The Power Of Introspection</i></a>.
+ </li>
+ <li>Added review section to <a href="../object_oriented_framework/index.html" title="Chapter&nbsp;5.&nbsp;Objects and Object-Orientation">Chapter&nbsp;5, <i>Objects and Object-Orientation</i></a> [later removed]
+ </li>
+ <li>Added <a href="../object_oriented_framework/private_functions.html" title="5.9.&nbsp;Private Functions">Section&nbsp;5.9, &#8220;Private Functions&#8221;</a>.
+ </li>
+ <li>Added <a href="../file_handling/for_loops.html" title="6.3.&nbsp;Iterating with for Loops">Section&nbsp;6.3, &#8220;Iterating with for Loops&#8221;</a>.
+ </li>
+ <li>Added <a href="../native_data_types/declaring_variables.html#odbchelper.multiassign" title="3.4.2.&nbsp;Assigning Multiple Values at Once">Section&nbsp;3.4.2, &#8220;Assigning Multiple Values at Once&#8221;</a>.
+ </li>
+ <li>Wrote scripts to convert book to new output formats: one single <span class="acronym">HTML</span> file, <span class="acronym">PDF</span>, <span class="application">Microsoft Word 97</span>, and plain text.
+ </li>
+ <li>Registered the <tt class="systemitem">diveintopython.org</tt> domain and moved the book there, along with links to download the book in all available output formats for offline reading.
+ </li>
+ <li>Modified the <span class="acronym">XSL</span> stylesheets to change the header and footer navigation that displays on each page. The top of each page is branded with
+ the domain name and book version, followed by a breadcrumb trail to jump back to the chapter table of contents, the main table
+ of contents, or the site home page.
+ </li>
+ </ul>
+ </div>
+ <a name="1.6"></a><h3 class="revdate">2000-12-11 (1.6)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>Added <a href="../power_of_introspection/all_together.html" title="4.8.&nbsp;Putting It All Together">Section&nbsp;4.8, &#8220;Putting It All Together&#8221;</a>.
+ </li>
+ <li>Finished <a href="../power_of_introspection/index.html" title="Chapter&nbsp;4.&nbsp;The Power Of Introspection">Chapter&nbsp;4, <i>The Power Of Introspection</i></a> with <a href="../power_of_introspection/summary.html" title="4.9.&nbsp;Summary">Section&nbsp;4.9, &#8220;Summary&#8221;</a>.
+ </li>
+ <li>Started <a href="../object_oriented_framework/index.html" title="Chapter&nbsp;5.&nbsp;Objects and Object-Orientation">Chapter&nbsp;5, <i>Objects and Object-Orientation</i></a> with <a href="../object_oriented_framework/index.html#fileinfo.divein" title="5.1.&nbsp;Diving In">Section&nbsp;5.1, &#8220;Diving In&#8221;</a>.
+ </li>
+ </ul>
+ </div>
+ <a name="1.5"></a><h3 class="revdate">2000-11-22 (1.5)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>Added <a href="../power_of_introspection/and_or.html" title="4.6.&nbsp;The Peculiar Nature of and and or">Section&nbsp;4.6, &#8220;The Peculiar Nature of and and or&#8221;</a>.
+ </li>
+ <li>Added <a href="../power_of_introspection/lambda_functions.html" title="4.7.&nbsp;Using lambda Functions">Section&nbsp;4.7, &#8220;Using lambda Functions&#8221;</a>.
+ </li>
+ <li>Added <a href="../appendix/abstracts.html" title="Appendix&nbsp;B.&nbsp;A 5-minute review">appendix that lists section abstracts</a>.
+ </li>
+ <li>Added <a href="../appendix/tips.html" title="Appendix&nbsp;C.&nbsp;Tips and tricks">appendix that lists tips</a>.
+ </li>
+ <li>Added <a href="../appendix/examples.html" title="Appendix&nbsp;D.&nbsp;List of examples">appendix that lists examples</a>.
+ </li>
+ <li>Added <a href="../appendix/history.html" title="Appendix&nbsp;E.&nbsp;Revision history">appendix that lists revision history</a>.
+ </li>
+ <li>Expanded example of mapping lists in <a href="../native_data_types/mapping_lists.html" title="3.6.&nbsp;Mapping Lists">Section&nbsp;3.6, &#8220;Mapping Lists&#8221;</a>.
+ </li>
+ <li>Encapsulated several more common phrases into entities.</li>
+ <li>Upgraded to version 1.25 of the <span class="application">DocBook</span> <span class="acronym">XSL</span> stylesheets.
+ </li>
+ </ul>
+ </div>
+ <a name="1.4"></a><h3 class="revdate">2000-11-14 (1.4)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>Added <a href="../power_of_introspection/filtering_lists.html" title="4.5.&nbsp;Filtering Lists">Section&nbsp;4.5, &#8220;Filtering Lists&#8221;</a>.
+ </li>
+ <li>Added <tt class="function">dir</tt> documentation to <a href="../power_of_introspection/built_in_functions.html" title="4.3.&nbsp;Using type, str, dir, and Other Built-In Functions">Section&nbsp;4.3, &#8220;Using type, str, dir, and Other Built-In Functions&#8221;</a>.
+ </li>
+ <li>Added <tt class="function">in</tt> example in <a href="../native_data_types/tuples.html" title="3.3.&nbsp;Introducing Tuples">Section&nbsp;3.3, &#8220;Introducing Tuples&#8221;</a>.
+ </li>
+ <li>Added additional note about <tt class="literal">if</tt> <tt class="literal">__name__</tt> trick under <span class="application">MacPython</span>.
+ </li>
+ <li>Switched to the <span class="application"><span class="acronym">SAXON</span></span> <span class="acronym">XSLT</span> processor from Michael Kay.
+ </li>
+ <li>Upgraded to version 1.24 of the <span class="application">DocBook</span> <span class="acronym">XSL</span> stylesheets.
+ </li>
+ <li>Added db-html processing instructions with explicit filenames of each chapter and section, to allow deep links to content
+ even if I add or re-arrange sections later.
+ </li>
+ <li>Made several common phrases into entities for easier reuse.</li>
+ <li>Changed several <tt class="sgmltag-element">literal</tt> tags to <tt class="sgmltag-element">constant</tt>.
+ </li>
+ </ul>
+ </div>
+ <a name="1.3"></a><h3 class="revdate">2000-11-09 (1.3)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>Added section on dynamic code execution.</li>
+ <li>Added links to relevant section/example wherever I refer to previously covered concepts.</li>
+ <li>Expanded <a href="../power_of_introspection/index.html#apihelper.divein" title="4.1.&nbsp;Diving In">introduction of chapter 2</a> to explain what the function actually does.
+ </li>
+ <li>Explicitly placed example code under the <span class="acronym">GNU</span> General Public License and added appendix to display license. [Note 8/16/2001: code has been re-licensed under <span class="acronym">GPL</span>-compatible <span class="application">Python</span> license]
+ </li>
+ <li>Changed links to licenses to use <tt class="sgmltag-element">xref</tt> tags, now that I know how to use them.
+ </li>
+ </ul>
+ </div>
+ <a name="1.2"></a><h3 class="revdate">2000-11-06 (1.2)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>Added first four sections of chapter 2.</li>
+ <li>Tightened up preface even more, and added link to <span class="abbrev">Mac</span> <span class="acronym">OS</span> version of <span class="application">Python</span>.
+ </li>
+ <li>Filled out examples in "Mapping lists" and "Joining strings" to show logical progression.</li>
+ <li>Added output in chapter 1 summary.</li>
+ </ul>
+ </div>
+ <a name="1.1"></a><h3 class="revdate">2000-10-31 (1.1)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>Finished chapter 1 with sections on mapping and joining, and a chapter summary.</li>
+ <li>Toned down the preface, added links to introductions for non-programmers.</li>
+ <li>Fixed several typos.</li>
+ </ul>
+ </div>
+ <a name="1.0"></a><h3 class="revdate">2000-10-30 (1.0)</h3>
+
+ <div class="itemizedlist">
+ <ul>
+ <li>Initial publication</li>
+ </ul>
+ </div>
+
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="examples.html">&lt;&lt;&nbsp;List of examples</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="about.html">About the book&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/appendix/license.html b/help/diveintopython-5.4/html/appendix/license.html
new file mode 100644
index 0000000..f081df0
--- /dev/null
+++ b/help/diveintopython-5.4/html/appendix/license.html
@@ -0,0 +1,120 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>Appendix&nbsp;H.&nbsp;Python license</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="../toc/index.html" title="Dive Into Python">
+ <link rel="previous" href="fdl_howto.html" title="G.11.&nbsp;How to use this License for your documents">
+ <link rel="next" href="license_terms.html" title="H.B.&nbsp;Terms and conditions for accessing or otherwise using Python">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<span class="thispage">Python license</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="fdl_howto.html" title="Prev: &#8220;How to use this License for your documents&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="license_terms.html" title="Next: &#8220;Terms and conditions for accessing or otherwise using Python&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="appendix" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="license"></a>Appendix&nbsp;H.&nbsp;<span class="application">Python</span> license
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="toc">
+ <ul>
+ <li><span class="section"><a href="license.html#d0e40180">H.A. History of the software</a></span></li>
+ <li><span class="section"><a href="license_terms.html">H.B. Terms and conditions for accessing or otherwise using Python</a></span><ul>
+ <li><span class="section"><a href="license_terms.html#d0e40195">H.B.1. PSF license agreement</a></span></li>
+ <li><span class="section"><a href="license_terms.html#d0e40223">H.B.2. BeOpen Python open source license agreement version 1</a></span></li>
+ <li><span class="section"><a href="license_terms.html#d0e40248">H.B.3. CNRI open source GPL-compatible license agreement</a></span></li>
+ <li><span class="section"><a href="license_terms.html#d0e40276">H.B.4. CWI permissions statement and disclaimer</a></span></li>
+ </ul>
+ </li>
+ </ul>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="d0e40180"></a>H.A.&nbsp;History of the software
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p>Python was created in the early 1990s by Guido van Rossum at Stichting
+ Mathematisch Centrum (CWI) in the Netherlands as a successor of a
+ language called ABC. Guido is Python's principal author, although it
+ includes many contributions from others. The last version released
+ from CWI was Python 1.2. In 1995, Guido continued his work on Python
+ at the Corporation for National Research Initiatives (CNRI) in Reston,
+ Virginia where he released several versions of the software. Python
+ 1.6 was the last of the versions released by CNRI. In 2000, Guido and
+ the Python core development team moved to BeOpen.com to form the
+ BeOpen PythonLabs team. Python 2.0 was the first and only release
+ from BeOpen.com.
+ </p>
+ <p>Following the release of Python 1.6, and after Guido van Rossum left
+ CNRI to work with commercial software developers, it became clear that
+ the ability to use Python with software available under the GNU Public
+ License (GPL) was very desirable. CNRI and the Free Software
+ Foundation (FSF) interacted to develop enabling wording changes to the
+ Python license. Python 1.6.1 is essentially the same as Python 1.6,
+ with a few minor bug fixes, and with a different license that enables
+ later versions to be GPL-compatible. Python 2.1 is a derivative work
+ of Python 1.6.1, as well as of Python 2.0.
+ </p>
+ <p>After Python 2.0 was released by BeOpen.com, Guido van Rossum and the
+ other PythonLabs developers joined Digital Creations. All
+ intellectual property added from this point on, starting with Python
+ 2.1 and its alpha and beta releases, is owned by the Python Software
+ Foundation (PSF), a non-profit modeled after the Apache Software
+ Foundation. See http://www.python.org/psf/ for more information about
+ the PSF.
+ </p>
+ <p>Thanks to the many outside volunteers who have worked under Guido's
+ direction to make these releases possible.
+ </p>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="fdl_howto.html">&lt;&lt;&nbsp;How to use this License for your documents</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<span class="thispage">1</span> <span class="divider">|</span> <a href="license_terms.html" title="H.B.&nbsp;Terms and conditions for accessing or otherwise using Python">2</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="license_terms.html">Terms and conditions for accessing or otherwise using Python&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/appendix/license_terms.html b/help/diveintopython-5.4/html/appendix/license_terms.html
new file mode 100644
index 0000000..ebe62b1
--- /dev/null
+++ b/help/diveintopython-5.4/html/appendix/license_terms.html
@@ -0,0 +1,305 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>H.B.&nbsp;Terms and conditions for accessing or otherwise using Python</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="license.html" title="Appendix&nbsp;H.&nbsp;Python license">
+ <link rel="previous" href="license.html" title="Appendix&nbsp;H.&nbsp;Python license">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="license.html">Python license</a>&nbsp;&gt;&nbsp;<span class="thispage">Terms and conditions for accessing or otherwise using Python</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="license.html" title="Prev: &#8220;Python license&#8221;">&lt;&lt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="d0e40191"></a>H.B.&nbsp;Terms and conditions for accessing or otherwise using Python
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="toc">
+ <ul>
+ <li><span class="section"><a href="license_terms.html#d0e40195">H.B.1. PSF license agreement</a></span></li>
+ <li><span class="section"><a href="license_terms.html#d0e40223">H.B.2. BeOpen Python open source license agreement version 1</a></span></li>
+ <li><span class="section"><a href="license_terms.html#d0e40248">H.B.3. CNRI open source GPL-compatible license agreement</a></span></li>
+ <li><span class="section"><a href="license_terms.html#d0e40276">H.B.4. CWI permissions statement and disclaimer</a></span></li>
+ </ul>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e40195"></a>H.B.1.&nbsp;PSF license agreement
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="orderedlist">
+ <ol type="1">
+ <li>This LICENSE AGREEMENT is between the Python Software Foundation
+ ("PSF"), and the Individual or Organization ("Licensee") accessing and
+ otherwise using Python 2.1.1 software in source or binary form and its
+ associated documentation.
+ </li>
+ <li>Subject to the terms and conditions of this License Agreement, PSF
+ hereby grants Licensee a nonexclusive, royalty-free, world-wide
+ license to reproduce, analyze, test, perform and/or display publicly,
+ prepare derivative works, distribute, and otherwise use Python 2.1.1
+ alone or in any derivative version, provided, however, that PSF's
+ License Agreement and PSF's notice of copyright, i.e., "Copyright (c)
+ 2001 Python Software Foundation; All Rights Reserved" are retained in
+ Python 2.1.1 alone or in any derivative version prepared by Licensee.
+ </li>
+ <li>In the event Licensee prepares a derivative work that is based on
+ or incorporates Python 2.1.1 or any part thereof, and wants to make
+ the derivative work available to others as provided herein, then
+ Licensee hereby agrees to include in any such work a brief summary of
+ the changes made to Python 2.1.1.
+ </li>
+ <li>PSF is making Python 2.1.1 available to Licensee on an "AS IS"
+ basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+ IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
+ DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
+ FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 2.1.1 WILL NOT
+ INFRINGE ANY THIRD PARTY RIGHTS.
+ </li>
+ <li>PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
+ 2.1.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
+ A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 2.1.1,
+ OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+ </li>
+ <li>This License Agreement will automatically terminate upon a material
+ breach of its terms and conditions.
+ </li>
+ <li>Nothing in this License Agreement shall be deemed to create any
+ relationship of agency, partnership, or joint venture between PSF and
+ Licensee. This License Agreement does not grant permission to use PSF
+ trademarks or trade name in a trademark sense to endorse or promote
+ products or services of Licensee, or any third party.
+ </li>
+ <li>By copying, installing or otherwise using Python 2.1.1, Licensee
+ agrees to be bound by the terms and conditions of this License
+ Agreement.
+ </li>
+ </ol>
+ </div>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e40223"></a>H.B.2.&nbsp;BeOpen Python open source license agreement version 1
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="orderedlist">
+ <ol type="1">
+ <li>This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an
+ office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the
+ Individual or Organization ("Licensee") accessing and otherwise using
+ this software in source or binary form and its associated
+ documentation ("the Software").
+ </li>
+ <li>Subject to the terms and conditions of this BeOpen Python License
+ Agreement, BeOpen hereby grants Licensee a non-exclusive,
+ royalty-free, world-wide license to reproduce, analyze, test, perform
+ and/or display publicly, prepare derivative works, distribute, and
+ otherwise use the Software alone or in any derivative version,
+ provided, however, that the BeOpen Python License is retained in the
+ Software, alone or in any derivative version prepared by Licensee.
+ </li>
+ <li>BeOpen is making the Software available to Licensee on an "AS IS"
+ basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+ IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND
+ DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
+ FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT
+ INFRINGE ANY THIRD PARTY RIGHTS.
+ </li>
+ <li>BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE
+ SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS
+ AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY
+ DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+ </li>
+ <li>This License Agreement will automatically terminate upon a material
+ breach of its terms and conditions.
+ </li>
+ <li>This License Agreement shall be governed by and interpreted in all
+ respects by the law of the State of California, excluding conflict of
+ law provisions. Nothing in this License Agreement shall be deemed to
+ create any relationship of agency, partnership, or joint venture
+ between BeOpen and Licensee. This License Agreement does not grant
+ permission to use BeOpen trademarks or trade names in a trademark
+ sense to endorse or promote products or services of Licensee, or any
+ third party. As an exception, the "BeOpen Python" logos available at
+ http://www.pythonlabs.com/logos.html may be used according to the
+ permissions granted on that web page.
+ </li>
+ <li>By copying, installing or otherwise using the software, Licensee
+ agrees to be bound by the terms and conditions of this License
+ Agreement.
+ </li>
+ </ol>
+ </div>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e40248"></a>H.B.3.&nbsp;CNRI open source GPL-compatible license agreement
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="orderedlist">
+ <ol type="1">
+ <li>This LICENSE AGREEMENT is between the Corporation for National
+ Research Initiatives, having an office at 1895 Preston White Drive,
+ Reston, VA 20191 ("CNRI"), and the Individual or Organization
+ ("Licensee") accessing and otherwise using Python 1.6.1 software in
+ source or binary form and its associated documentation.
+ </li>
+ <li>Subject to the terms and conditions of this License Agreement, CNRI
+ hereby grants Licensee a nonexclusive, royalty-free, world-wide
+ license to reproduce, analyze, test, perform and/or display publicly,
+ prepare derivative works, distribute, and otherwise use Python 1.6.1
+ alone or in any derivative version, provided, however, that CNRI's
+ License Agreement and CNRI's notice of copyright, i.e., "Copyright (c)
+ 1995-2001 Corporation for National Research Initiatives; All Rights
+ Reserved" are retained in Python 1.6.1 alone or in any derivative
+ version prepared by Licensee. Alternately, in lieu of CNRI's License
+ Agreement, Licensee may substitute the following text (omitting the
+ quotes): "Python 1.6.1 is made available subject to the terms and
+ conditions in CNRI's License Agreement. This Agreement together with
+ Python 1.6.1 may be located on the Internet using the following
+ unique, persistent identifier (known as a handle): 1895.22/1013. This
+ Agreement may also be obtained from a proxy server on the Internet
+ using the following URL: http://hdl.handle.net/1895.22/1013".
+ </li>
+ <li>In the event Licensee prepares a derivative work that is based on
+ or incorporates Python 1.6.1 or any part thereof, and wants to make
+ the derivative work available to others as provided herein, then
+ Licensee hereby agrees to include in any such work a brief summary of
+ the changes made to Python 1.6.1.
+ </li>
+ <li>CNRI is making Python 1.6.1 available to Licensee on an "AS IS"
+ basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+ IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND
+ DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
+ FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT
+ INFRINGE ANY THIRD PARTY RIGHTS.
+ </li>
+ <li>CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
+ 1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
+ A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1,
+ OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+ </li>
+ <li>This License Agreement will automatically terminate upon a material
+ breach of its terms and conditions.
+ </li>
+ <li>This License Agreement shall be governed by the federal
+ intellectual property law of the United States, including without
+ limitation the federal copyright law, and, to the extent such
+ U.S. federal law does not apply, by the law of the Commonwealth of
+ Virginia, excluding Virginia's conflict of law provisions.
+ Notwithstanding the foregoing, with regard to derivative works based
+ on Python 1.6.1 that incorporate non-separable material that was
+ previously distributed under the GNU General Public License (GPL), the
+ law of the Commonwealth of Virginia shall govern this License
+ Agreement only as to issues arising under or with respect to
+ Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this
+ License Agreement shall be deemed to create any relationship of
+ agency, partnership, or joint venture between CNRI and Licensee. This
+ License Agreement does not grant permission to use CNRI trademarks or
+ trade name in a trademark sense to endorse or promote products or
+ services of Licensee, or any third party.
+ </li>
+ <li>By clicking on the "ACCEPT" button where indicated, or by copying,
+ installing or otherwise using Python 1.6.1, Licensee agrees to be
+ bound by the terms and conditions of this License Agreement.
+ </li>
+ </ol>
+ </div>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e40276"></a>H.B.4.&nbsp;CWI permissions statement and disclaimer
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="blockquote">
+ <blockquote class="blockquote">
+ <p>Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam,
+ The Netherlands. All rights reserved.
+ </p>
+ </blockquote>
+ </div>
+ <p>Permission to use, copy, modify, and distribute this software and its
+ documentation for any purpose and without fee is hereby granted,
+ provided that the above copyright notice appear in all copies and that
+ both that copyright notice and this permission notice appear in
+ supporting documentation, and that the name of Stichting Mathematisch
+ Centrum or CWI not be used in advertising or publicity pertaining to
+ distribution of the software without specific, written prior
+ permission.
+ </p>
+ <p>STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
+ FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ </p>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="license.html">&lt;&lt;&nbsp;Python license</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="license.html#d0e40180" title="H.A.&nbsp;History of the software">1</a> <span class="divider">|</span> <span class="thispage">2</span>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/appendix/tips.html b/help/diveintopython-5.4/html/appendix/tips.html
new file mode 100644
index 0000000..fd8a552
--- /dev/null
+++ b/help/diveintopython-5.4/html/appendix/tips.html
@@ -0,0 +1,839 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>Appendix&nbsp;C.&nbsp;Tips and tricks</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="../toc/index.html" title="Dive Into Python">
+ <link rel="previous" href="abstracts.html" title="Appendix&nbsp;B.&nbsp;A 5-minute review">
+ <link rel="next" href="examples.html" title="Appendix&nbsp;D.&nbsp;List of examples">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<span class="thispage">Tips and tricks</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="abstracts.html" title="Prev: &#8220;A 5-minute review&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="examples.html" title="Next: &#8220;List of examples&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="appendix" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="tips"></a>Appendix&nbsp;C.&nbsp;Tips and tricks
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p><a href="../installing_python/index.html">Chapter&nbsp;1.&nbsp;Installing Python</a></p>
+ <ul></ul>
+ <p><a href="../getting_to_know_python/index.html">Chapter&nbsp;2.&nbsp;Your First Python Program</a></p>
+ <ul>
+ <li><a href="../getting_to_know_python/index.html#odbchelper.divein">2.1.&nbsp;Diving in</a><a name="tip.run.windows"></a><table class="tip" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/tip.png" alt="Tip" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">In the <span class="application">ActivePython</span> <span class="acronym">IDE</span> on Windows, you can run the <span class="application">Python</span> program you're editing by choosing
+ <span class="guimenu">File</span>-&gt;<span class="guimenuitem"><span class="accel">R</span>un...</span> (<span><b class="shortcut"><span><b class="keycap">Ctrl</b></span>-<span class="keysym">R</span></b></span>). Output is displayed in the interactive window.
+ </td>
+ </tr>
+ </table><a name="tip.run.mac"></a><table class="tip" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/tip.png" alt="Tip" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">In the <span class="application">Python</span> <span class="acronym">IDE</span> on <span class="abbrev">Mac</span> <span class="acronym">OS</span>, you can run a <span class="application">Python</span> program with
+ <span class="guimenu">Python</span>-&gt;<span class="guimenuitem">Run window...</span> (<span><b class="shortcut"><span><b class="keycap">Cmd</b></span>-<span class="keysym">R</span></b></span>), but there is an important option you must set first. Open the <tt class="filename">.py</tt> file in the <span class="acronym">IDE</span>, pop up the options menu by clicking the black triangle in the upper-right corner of the window, and make sure the <span class="guimenuitem">Run as __main__</span> option is checked. This is a per-file setting, but you'll only need to do it once per file.
+ </td>
+ </tr>
+ </table><a name="tip.run.unix"></a><table class="tip" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/tip.png" alt="Tip" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">On <span class="acronym">UNIX</span>-compatible systems (including <span class="abbrev">Mac</span> <span class="acronym">OS</span> X), you can run a <span class="application">Python</span> program from the command line: <b class="userinput"><tt>python <tt class="filename">odbchelper.py</tt></tt></b></td>
+ </tr>
+ </table>
+ <p></p>
+ </li>
+ <li><a href="../getting_to_know_python/declaring_functions.html">2.2.&nbsp;Declaring Functions</a><a name="compare.funcdef.vb"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">In <span class="application">Visual Basic</span>, functions (that return a value) start with <tt class="literal">function</tt>, and subroutines (that do not return a value) start with <tt class="literal">sub</tt>. There are no subroutines in <span class="application">Python</span>. Everything is a function, all functions return a value (even if it's <tt class="literal">None</tt>), and all functions start with <tt class="literal">def</tt>.
+ </td>
+ </tr>
+ </table><a name="compare.funcdef.java"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">In <span class="application">Java</span>, <span class="application"><span class="acronym">C++</span></span>, and other statically-typed languages, you must specify the datatype of the function return value and each function argument.
+ In <span class="application">Python</span>, you never explicitly specify the datatype of anything. Based on what value you assign, <span class="application">Python</span> keeps track of the datatype internally.
+ </td>
+ </tr>
+ </table>
+ <p></p>
+ </li>
+ <li><a href="../getting_to_know_python/documenting_functions.html">2.3.&nbsp;Documenting Functions</a><a name="compare.quoting.perl"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">Triple quotes are also an easy way to define a string with both single and double quotes, like <tt class="literal">qq/.../</tt> in <span class="application">Perl</span>.
+ </td>
+ </tr>
+ </table><a name="tip.docstring"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">Many <span class="application">Python</span> <span class="acronym">IDE</span>s use the <tt class="literal">doc string</tt> to provide context-sensitive documentation, so that when you type a function name, its <tt class="literal">doc string</tt> appears as a tooltip. This can be incredibly helpful, but it's only as good as the <tt class="literal">doc string</tt>s you write.
+ </td>
+ </tr>
+ </table>
+ <p></p>
+ </li>
+ <li><a href="../getting_to_know_python/everything_is_an_object.html">2.4.&nbsp;Everything Is an Object</a><a name="compare.import.perl"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%"><tt class="literal">import</tt> in <span class="application">Python</span> is like <tt class="literal">require</tt> in <span class="application">Perl</span>. Once you <tt class="literal">import</tt> a <span class="application">Python</span> module, you access its functions with <tt class="literal"><i class="replaceable">module</i>.<i class="replaceable">function</i></tt>; once you <tt class="literal">require</tt> a <span class="application">Perl</span> module, you access its functions with <tt class="literal"><i class="replaceable">module</i>::<i class="replaceable">function</i></tt>.
+ </td>
+ </tr>
+ </table>
+ <p></p>
+ </li>
+ <li><a href="../getting_to_know_python/indenting_code.html">2.5.&nbsp;Indenting Code</a><a name="compare.lineend.java"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%"><span class="application">Python</span> uses carriage returns to separate statements and a colon and indentation to separate code blocks. <span class="application"><span class="acronym">C++</span></span> and <span class="application">Java</span> use semicolons to separate statements and curly braces to separate code blocks.
+ </td>
+ </tr>
+ </table>
+ <p></p>
+ </li>
+ <li><a href="../getting_to_know_python/testing_modules.html">2.6.&nbsp;Testing Modules</a><a name="compare.equals.c"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">Like <span class="application"><span class="acronym">C</span></span>, <span class="application">Python</span> uses <tt class="literal">==</tt> for comparison and <tt class="literal">=</tt> for assignment. Unlike <span class="application"><span class="acronym">C</span></span>, <span class="application">Python</span> does not support in-line assignment, so there's no chance of accidentally assigning the value you thought you were comparing.
+ </td>
+ </tr>
+ </table><a name="tip.mac.runasmain"></a><table class="tip" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/tip.png" alt="Tip" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">On <span class="application">MacPython</span>, there is an additional step to make the <tt class="literal">if</tt> <tt class="literal">__name__</tt> trick work. Pop up the module's options menu by clicking the black triangle in the upper-right corner of the window, and
+ make sure <span class="guimenuitem">Run as __main__</span> is checked.
+ </td>
+ </tr>
+ </table>
+ <p></p>
+ </li>
+ </ul>
+ <p><a href="../native_data_types/index.html">Chapter&nbsp;3.&nbsp;Native Datatypes</a></p>
+ <ul>
+ <li><a href="../native_data_types/index.html#odbchelper.dict">3.1.&nbsp;Introducing Dictionaries</a><a name="compare.dict.perl"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">A dictionary in <span class="application">Python</span> is like a hash in <span class="application">Perl</span>. In <span class="application">Perl</span>, variables that store hashes always start with a <tt class="literal">%</tt> character. In <span class="application">Python</span>, variables can be named anything, and <span class="application">Python</span> keeps track of the datatype internally.
+ </td>
+ </tr>
+ </table><a name="compare.dict.java"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">A dictionary in <span class="application">Python</span> is like an instance of the <tt class="classname">Hashtable</tt> class in <span class="application">Java</span>.
+ </td>
+ </tr>
+ </table><a name="compare.dict.vb"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">A dictionary in <span class="application">Python</span> is like an instance of the <tt class="classname">Scripting.Dictionary</tt> object in <span class="application">Visual Basic</span>.
+ </td>
+ </tr>
+ </table>
+ <p></p>
+ </li>
+ <li><a href="../native_data_types/index.html#d0e5269">3.1.2.&nbsp;Modifying Dictionaries</a><a name="tip.dictorder"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">Dictionaries have no concept of order among elements. It is incorrect to say that the elements are &#8220;<span class="quote">out of order</span>&#8221;; they are simply unordered. This is an important distinction that will annoy you when you want to access the elements of
+ a dictionary in a specific, repeatable order (like alphabetical order by key). There are ways of doing this, but they're
+ not built into the dictionary.
+ </td>
+ </tr>
+ </table>
+ <p></p>
+ </li>
+ <li><a href="../native_data_types/lists.html">3.2.&nbsp;Introducing Lists</a><a name="compare.list.perl"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">A list in <span class="application">Python</span> is like an array in <span class="application">Perl</span>. In <span class="application">Perl</span>, variables that store arrays always start with the <tt class="literal">@</tt> character; in <span class="application">Python</span>, variables can be named anything, and <span class="application">Python</span> keeps track of the datatype internally.
+ </td>
+ </tr>
+ </table><a name="compare.list.java"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">A list in <span class="application">Python</span> is much more than an array in <span class="application">Java</span> (although it can be used as one if that's really all you want out of life). A better analogy would be to the <tt class="classname">ArrayList</tt> class, which can hold arbitrary objects and can expand dynamically as new items are added.
+ </td>
+ </tr>
+ </table>
+ <p></p>
+ </li>
+ <li><a href="../native_data_types/lists.html#d0e6115">3.2.3.&nbsp;Searching Lists</a><a name="tip.boolean"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">Before version 2.2.1, <span class="application">Python</span> had no separate boolean datatype. To compensate for this, <span class="application">Python</span> accepted almost anything in a boolean context (like an <tt class="literal">if</tt> statement), according to the following rules:
+ <div class="itemizedlist">
+ <ul>
+ <li><tt class="constant">0</tt> is false; all other numbers are true.
+ </li>
+ <li>An empty string (<tt class="literal">""</tt>) is false, all other strings are true.
+ </li>
+ <li>An empty list (<tt class="literal">[]</tt>) is false; all other lists are true.
+ </li>
+ <li>An empty tuple (<tt class="literal">()</tt>) is false; all other tuples are true.
+ </li>
+ <li>An empty dictionary (<tt class="literal">{}</tt>) is false; all other dictionaries are true.
+ </li>
+ </ul>
+ </div>These rules still apply in <span class="application">Python</span> 2.2.1 and beyond, but now you can also use an actual boolean, which has a value of <tt class="literal">True</tt> or <tt class="literal">False</tt>. Note the capitalization; these values, like everything else in <span class="application">Python</span>, are case-sensitive.
+ </td>
+ </tr>
+ </table>
+ <p></p>
+ </li>
+ <li><a href="../native_data_types/tuples.html">3.3.&nbsp;Introducing Tuples</a><a name="tip.tuple"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">Tuples can be converted into lists, and vice-versa. The built-in <tt class="function">tuple</tt> function takes a list and returns a tuple with the same elements, and the <tt class="function">list</tt> function takes a tuple and returns a list. In effect, <tt class="function">tuple</tt> freezes a list, and <tt class="function">list</tt> thaws a tuple.
+ </td>
+ </tr>
+ </table>
+ <p></p>
+ </li>
+ <li><a href="../native_data_types/declaring_variables.html">3.4.&nbsp;Declaring variables</a><a name="tip.multiline"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">When a command is split among several lines with the line-continuation marker (&#8220;<span class="quote"><tt class="literal">\</tt></span>&#8221;), the continued lines can be indented in any manner; <span class="application">Python</span>'s normally stringent indentation rules do not apply. If your <span class="application">Python</span> <span class="acronym">IDE</span> auto-indents the continued line, you should probably accept its default unless you have a burning reason not to.
+ </td>
+ </tr>
+ </table>
+ <p></p>
+ </li>
+ <li><a href="../native_data_types/formatting_strings.html">3.5.&nbsp;Formatting Strings</a><a name="compare.stringformatting.c"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">String formatting in <span class="application">Python</span> uses the same syntax as the <tt class="function">sprintf</tt> function in <span class="application"><span class="acronym">C</span></span>.
+ </td>
+ </tr>
+ </table>
+ <p></p>
+ </li>
+ <li><a href="../native_data_types/joining_lists.html">3.7.&nbsp;Joining Lists and Splitting Strings</a><a name="tip.join"></a><table class="caution" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/caution.png" alt="Caution" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%"><tt class="function">join</tt> works only on lists of strings; it does not do any type coercion. Joining a list that has one or more non-string elements
+ will raise an exception.
+ </td>
+ </tr>
+ </table><a name="tip.split"></a><table class="tip" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/tip.png" alt="Tip" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%"><tt class="literal"><i class="replaceable">anystring</i>.<tt class="function">split</tt>(<i class="replaceable">delimiter</i>, 1)</tt> is a useful technique when you want to search a string for a substring and then work with everything before the substring
+ (which ends up in the first element of the returned list) and everything after it (which ends up in the second element).
+ </td>
+ </tr>
+ </table>
+ <p></p>
+ </li>
+ </ul>
+ <p><a href="../power_of_introspection/index.html">Chapter&nbsp;4.&nbsp;The Power Of Introspection</a></p>
+ <ul>
+ <li><a href="../power_of_introspection/optional_arguments.html">4.2.&nbsp;Using Optional and Named Arguments</a><a name="tip.arguments"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">The only thing you need to do to call a function is specify a value (somehow) for each required argument; the manner and order
+ in which you do that is up to you.
+ </td>
+ </tr>
+ </table>
+ <p></p>
+ </li>
+ <li><a href="../power_of_introspection/built_in_functions.html#d0e8958">4.3.3.&nbsp;Built-In Functions</a><a name="tip.manuals"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%"><span class="application">Python</span> comes with excellent reference manuals, which you should peruse thoroughly to learn all the modules <span class="application">Python</span> has to offer. But unlike most languages, where you would find yourself referring back to the manuals or man pages to remind
+ yourself how to use these modules, <span class="application">Python</span> is largely self-documenting.
+ </td>
+ </tr>
+ </table>
+ <p></p>
+ </li>
+ <li><a href="../power_of_introspection/lambda_functions.html">4.7.&nbsp;Using lambda Functions</a><a name="tip.lambda"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%"><tt class="literal">lambda</tt> functions are a matter of style. Using them is never required; anywhere you could use them, you could define a separate
+ normal function and use that instead. I use them in places where I want to encapsulate specific, non-reusable code without
+ littering my code with a lot of little one-line functions.
+ </td>
+ </tr>
+ </table>
+ <p></p>
+ </li>
+ <li><a href="../power_of_introspection/all_together.html">4.8.&nbsp;Putting It All Together</a><a name="compare.isnull.sql"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">In <span class="acronym">SQL</span>, you must use <tt class="literal">IS NULL</tt> instead of <tt class="literal">= NULL</tt> to compare a null value. In <span class="application">Python</span>, you can use either <tt class="literal">== None</tt> or <tt class="literal">is None</tt>, but <tt class="literal">is None</tt> is faster.
+ </td>
+ </tr>
+ </table>
+ <p></p>
+ </li>
+ </ul>
+ <p><a href="../object_oriented_framework/index.html">Chapter&nbsp;5.&nbsp;Objects and Object-Orientation</a></p>
+ <ul>
+ <li><a href="../object_oriented_framework/importing_modules.html">5.2.&nbsp;Importing Modules Using from module import</a><a name="compare.fromimport.perl"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%"><tt class="literal">from <i class="replaceable">module</i> import *</tt> in <span class="application">Python</span> is like <tt class="literal">use <i class="replaceable">module</i></tt> in <span class="application">Perl</span>; <tt class="literal">import <i class="replaceable">module</i></tt> in <span class="application">Python</span> is like <tt class="literal">require <i class="replaceable">module</i></tt> in <span class="application">Perl</span>.
+ </td>
+ </tr>
+ </table><a name="compare.fromimport.java"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%"><tt class="literal">from <i class="replaceable">module</i> import *</tt> in <span class="application">Python</span> is like <tt class="literal">import <i class="replaceable">module</i>.*</tt> in <span class="application">Java</span>; <tt class="literal">import <i class="replaceable">module</i></tt> in <span class="application">Python</span> is like <tt class="literal">import <i class="replaceable">module</i></tt> in <span class="application">Java</span>.
+ </td>
+ </tr>
+ </table><a name="d0e11495"></a><table class="caution" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/caution.png" alt="Caution" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">Use <tt class="literal">from module import *</tt> sparingly, because it makes it difficult to determine where a particular function or attribute came from, and that makes
+ debugging and refactoring more difficult.
+ </td>
+ </tr>
+ </table>
+ <p></p>
+ </li>
+ <li><a href="../object_oriented_framework/defining_classes.html">5.3.&nbsp;Defining Classes</a><a name="compare.pass.java"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">The <tt class="literal">pass</tt> statement in <span class="application">Python</span> is like an empty set of braces (<tt class="literal">{}</tt>) in <span class="application">Java</span> or <span class="application"><span class="acronym">C</span></span>.
+ </td>
+ </tr>
+ </table><a name="compare.extends.java"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">In <span class="application">Python</span>, the ancestor of a class is simply listed in parentheses immediately after the class name. There is no special keyword like
+ <tt class="literal">extends</tt> in <span class="application">Java</span>.
+ </td>
+ </tr>
+ </table>
+ <p></p>
+ </li>
+ <li><a href="../object_oriented_framework/defining_classes.html#d0e11720">5.3.1.&nbsp;Initializing and Coding Classes</a><a name="compare.self.java"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">By convention, the first argument of any <span class="application">Python</span> class method (the reference to the current instance) is called <tt class="literal">self</tt>. This argument fills the role of the reserved word <tt class="literal">this</tt> in <span class="application"><span class="acronym">C++</span></span> or <span class="application">Java</span>, but <tt class="literal">self</tt> is not a reserved word in <span class="application">Python</span>, merely a naming convention. Nonetheless, please don't call it anything but <tt class="literal">self</tt>; this is a very strong convention.
+ </td>
+ </tr>
+ </table>
+ <p></p>
+ </li>
+ <li><a href="../object_oriented_framework/defining_classes.html#d0e11896">5.3.2.&nbsp;Knowing When to Use self and __init__</a><a name="tip.initoptional"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%"><tt class="function">__init__</tt> methods are optional, but when you define one, you must remember to explicitly call the ancestor's <tt class="function">__init__</tt> method (if it defines one). This is more generally true: whenever a descendant wants to extend the behavior of the ancestor,
+ the descendant method must explicitly call the ancestor method at the proper time, with the proper arguments.
+ </td>
+ </tr>
+ </table>
+ <p></p>
+ </li>
+ <li><a href="../object_oriented_framework/instantiating_classes.html">5.4.&nbsp;Instantiating Classes</a><a name="compare.new.java"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">In <span class="application">Python</span>, simply call a class as if it were a function to create a new instance of the class. There is no explicit <tt class="literal">new</tt> operator like <span class="application"><span class="acronym">C++</span></span> or <span class="application">Java</span>.
+ </td>
+ </tr>
+ </table>
+ <p></p>
+ </li>
+ <li><a href="../object_oriented_framework/userdict.html">5.5.&nbsp;Exploring UserDict: A Wrapper Class</a><a name="tip.locate"></a><table class="tip" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/tip.png" alt="Tip" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">In the <span class="application">ActivePython</span> <span class="acronym">IDE</span> on Windows, you can quickly open any module in your library path by selecting
+ <span class="guimenu">File</span>-&gt;<span class="guimenuitem"><span class="accel">L</span>ocate...</span> (<span><b class="shortcut"><span><b class="keycap">Ctrl</b></span>-<span class="keysym">L</span></b></span>).
+ </td>
+ </tr>
+ </table><a name="compare.overloading"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%"><span class="application">Java</span> and <span class="application">Powerbuilder</span> support function overloading by argument list, <span class="foreignphrase"><i class="foreignphrase"><span class="acronym">i.e.</span></i></span> one class can have multiple methods with the same name but a different number of arguments, or arguments of different types.
+ Other languages (most notably <span class="acronym">PL/SQL</span>) even support function overloading by argument name; <span class="foreignphrase"><i class="foreignphrase"><span class="acronym">i.e.</span></i></span> one class can have multiple methods with the same name and the same number of arguments of the same type but different argument
+ names. <span class="application">Python</span> supports neither of these; it has no form of function overloading whatsoever. Methods are defined solely by their name,
+ and there can be only one method per class with a given name. So if a descendant class has an <tt class="function">__init__</tt> method, it <span class="emphasis"><em>always</em></span> overrides the ancestor <tt class="function">__init__</tt> method, even if the descendant defines it with a different argument list. And the same rule applies to any other method.
+ </td>
+ </tr>
+ </table><a name="fileinfo.derivedclasses"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">Guido, the original author of <span class="application">Python</span>, explains method overriding this way: "Derived classes may override methods of their base classes. Because methods have no
+ special privileges when calling other methods of the same object, a method of a base class that calls another method defined
+ in the same base class, may in fact end up calling a method of a derived class that overrides it. (For <span class="application"><span class="acronym">C++</span></span> programmers: all methods in <span class="application">Python</span> are effectively virtual.)" If that doesn't make sense to you (it confuses the hell out of me), feel free to ignore it.
+ I just thought I'd pass it along.
+ </td>
+ </tr>
+ </table><a name="note.dataattributes"></a><table class="caution" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/caution.png" alt="Caution" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">Always assign an initial value to all of an instance's data attributes in the <tt class="function">__init__</tt> method. It will save you hours of debugging later, tracking down <tt class="classname">AttributeError</tt> exceptions because you're referencing uninitialized (and therefore non-existent) attributes.
+ </td>
+ </tr>
+ </table><a name="d0e12692"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">In versions of <span class="application">Python</span> prior to 2.2, you could not directly subclass built-in datatypes like strings, lists, and dictionaries. To compensate for
+ this, <span class="application">Python</span> comes with wrapper classes that mimic the behavior of these built-in datatypes: <tt class="classname">UserString</tt>, <tt class="classname">UserList</tt>, and <tt class="classname">UserDict</tt>. Using a combination of normal and special methods, the <tt class="classname">UserDict</tt> class does an excellent imitation of a dictionary. In <span class="application">Python</span> 2.2 and later, you can inherit classes directly from built-in datatypes like <tt class="classname">dict</tt>. An example of this is given in the examples that come with this book, in <tt class="filename">fileinfo_fromdict.py</tt>.
+ </td>
+ </tr>
+ </table>
+ <p></p>
+ </li>
+ <li><a href="../object_oriented_framework/special_class_methods.html#d0e12822">5.6.1.&nbsp;Getting and Setting Items</a><a name="tip.self.call"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">When accessing data attributes within a class, you need to qualify the attribute name: <tt class="literal">self.<i class="replaceable">attribute</i></tt>. When calling other methods within a class, you need to qualify the method name: <tt class="literal">self.<i class="replaceable">method</i></tt>.
+ </td>
+ </tr>
+ </table>
+ <p></p>
+ </li>
+ <li><a href="../object_oriented_framework/special_class_methods2.html">5.7.&nbsp;Advanced Special Class Methods</a><a name="compare.strequals.java"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">In <span class="application">Java</span>, you determine whether two string variables reference the same physical memory location by using <tt class="literal">str1 == str2</tt>. This is called <span class="emphasis"><em>object identity</em></span>, and it is written in <span class="application">Python</span> as <tt class="literal">str1 is str2</tt>. To compare string values in <span class="application">Java</span>, you would use <tt class="literal">str1.equals(str2)</tt>; in <span class="application">Python</span>, you would use <tt class="literal">str1 == str2</tt>. <span class="application">Java</span> programmers who have been taught to believe that the world is a better place because <tt class="literal">==</tt> in <span class="application">Java</span> compares by identity instead of by value may have a difficult time adjusting to <span class="application">Python</span>'s lack of such &#8220;<span class="quote">gotchas</span>&#8221;.
+ </td>
+ </tr>
+ </table><a name="note.physical.v.logical"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">While other object-oriented languages only let you define the physical model of an object (&#8220;<span class="quote">this object has a <tt class="function">GetLength</tt> method</span>&#8221;), <span class="application">Python</span>'s special class methods like <tt class="function">__len__</tt> allow you to define the logical model of an object (&#8220;<span class="quote">this object has a length</span>&#8221;).
+ </td>
+ </tr>
+ </table>
+ <p></p>
+ </li>
+ <li><a href="../object_oriented_framework/class_attributes.html">5.8.&nbsp;Introducing Class Attributes</a><a name="compare.classattr.java"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">In <span class="application">Java</span>, both static variables (called class attributes in <span class="application">Python</span>) and instance variables (called data attributes in <span class="application">Python</span>) are defined immediately after the class definition (one with the <tt class="literal">static</tt> keyword, one without). In <span class="application">Python</span>, only class attributes can be defined here; data attributes are defined in the <tt class="function">__init__</tt> method.
+ </td>
+ </tr>
+ </table><a name="d0e13711"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">There are no constants in <span class="application">Python</span>. Everything can be changed if you try hard enough. This fits with one of the core principles of <span class="application">Python</span>: bad behavior should be discouraged but not banned. If you really want to change the value of <tt class="literal">None</tt>, you can do it, but don't come running to me when your code is impossible to debug.
+ </td>
+ </tr>
+ </table>
+ <p></p>
+ </li>
+ <li><a href="../object_oriented_framework/private_functions.html">5.9.&nbsp;Private Functions</a><a name="tip.specialmethodnames"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">In <span class="application">Python</span>, all special methods (like <a href="special_class_methods.html#fileinfo.specialmethods.setitem.example" title="Example&nbsp;5.13.&nbsp;The __setitem__ Special Method"><tt class="function">__setitem__</tt></a>) and built-in attributes (like <a href="../getting_to_know_python/everything_is_an_object.html#odbchelper.import" title="Example&nbsp;2.3.&nbsp;Accessing the buildConnectionString Function's doc string"><tt class="literal">__doc__</tt></a>) follow a standard naming convention: they both start with and end with two underscores. Don't name your own methods and
+ attributes this way, because it will only confuse you (and others) later.
+ </td>
+ </tr>
+ </table>
+ <p></p>
+ </li>
+ </ul>
+ <p><a href="../file_handling/index.html">Chapter&nbsp;6.&nbsp;Exceptions and File Handling</a></p>
+ <ul>
+ <li><a href="../file_handling/index.html#fileinfo.exception">6.1.&nbsp;Handling Exceptions</a><a name="compare.exceptions.java"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%"><span class="application">Python</span> uses <tt class="literal">try...except</tt> to handle exceptions and <tt class="literal">raise</tt> to generate them. <span class="application">Java</span> and <span class="application"><span class="acronym">C++</span></span> use <tt class="literal">try...catch</tt> to handle exceptions, and <tt class="literal">throw</tt> to generate them.
+ </td>
+ </tr>
+ </table>
+ <p></p>
+ </li>
+ <li><a href="../file_handling/os_module.html">6.5.&nbsp;Working with Directories</a><a name="tip.os"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">Whenever possible, you should use the functions in <tt class="filename">os</tt> and <tt class="filename">os.path</tt> for file, directory, and path manipulations. These modules are wrappers for platform-specific modules, so functions like
+ <tt class="function">os.path.split</tt> work on <span class="acronym">UNIX</span>, Windows, <span class="abbrev">Mac</span> <span class="acronym">OS</span>, and any other platform supported by <span class="application">Python</span>.
+ </td>
+ </tr>
+ </table>
+ <p></p>
+ </li>
+ </ul>
+ <p><a href="../regular_expressions/index.html">Chapter&nbsp;7.&nbsp;Regular Expressions</a></p>
+ <ul>
+ <li><a href="../regular_expressions/n_m_syntax.html">7.4.&nbsp;Using the {n,m} Syntax</a><a name="d0e18321"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">There is no way to programmatically determine that two regular expressions are equivalent. The best you can do is write a
+ lot of test cases to make sure they behave the same way on all relevant inputs. You'll talk more about writing test cases
+ later in this book.
+ </td>
+ </tr>
+ </table>
+ <p></p>
+ </li>
+ </ul>
+ <p><a href="../html_processing/index.html">Chapter&nbsp;8.&nbsp;HTML Processing</a></p>
+ <ul>
+ <li><a href="../html_processing/introducing_sgmllib.html">8.2.&nbsp;Introducing sgmllib.py</a><a name="d0e20023"></a><table class="important" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/important.png" alt="Important" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%"><span class="application">Python</span> 2.0 had a bug where <tt class="classname">SGMLParser</tt> would not recognize declarations at all (<tt class="function">handle_decl</tt> would never be called), which meant that <tt class="sgmltag-element">DOCTYPE</tt>s were silently ignored. This is fixed in <span class="application">Python</span> 2.1.
+ </td>
+ </tr>
+ </table><a name="tip.commandline.windows"></a><table class="tip" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/tip.png" alt="Tip" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">In the <span class="application">ActivePython</span> <span class="acronym">IDE</span> on Windows, you can specify command line arguments in the &#8220;<span class="quote">Run script</span>&#8221; dialog. Separate multiple arguments with spaces.
+ </td>
+ </tr>
+ </table>
+ <p></p>
+ </li>
+ <li><a href="../html_processing/basehtmlprocessor.html">8.4.&nbsp;Introducing BaseHTMLProcessor.py</a><a name="d0e20845"></a><table class="important" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/important.png" alt="Important" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">The <span class="acronym">HTML</span> specification requires that all non-<span class="acronym">HTML</span> (like client-side <span class="application">JavaScript</span>) must be enclosed in <span class="acronym">HTML</span> comments, but not all web pages do this properly (and all modern web browsers are forgiving if they don't). <tt class="classname">BaseHTMLProcessor</tt> is not forgiving; if script is improperly embedded, it will be parsed as if it were <span class="acronym">HTML</span>. For instance, if the script contains less-than and equals signs, <tt class="classname">SGMLParser</tt> may incorrectly think that it has found tags and attributes. <tt class="classname">SGMLParser</tt> always converts tags and attribute names to lowercase, which may break the script, and <tt class="classname">BaseHTMLProcessor</tt> always encloses attribute values in double quotes (even if the original <span class="acronym">HTML</span> document used single quotes or no quotes), which will certainly break the script. Always protect your client-side script
+ within <span class="acronym">HTML</span> comments.
+ </td>
+ </tr>
+ </table>
+ <p></p>
+ </li>
+ <li><a href="../html_processing/locals_and_globals.html">8.5.&nbsp;locals and globals</a><a name="d0e21061"></a><table class="important" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/important.png" alt="Important" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%"><span class="application">Python</span> 2.2 introduced a subtle but important change that affects the namespace search order: nested scopes. In versions of <span class="application">Python</span> prior to 2.2, when you reference a variable within a <a href="../file_handling/all_together.html#fileinfo.nested" title="Example&nbsp;6.21.&nbsp;listDirectory">nested function</a> or <a href="../power_of_introspection/lambda_functions.html" title="4.7.&nbsp;Using lambda Functions"><tt class="literal">lambda</tt> function</a>, <span class="application">Python</span> will search for that variable in the current (nested or <tt class="literal">lambda</tt>) function's namespace, then in the module's namespace. <span class="application">Python</span> 2.2 will search for the variable in the current (nested or <tt class="literal">lambda</tt>) function's namespace, <span class="emphasis"><em>then in the parent function's namespace</em></span>, then in the module's namespace. <span class="application">Python</span> 2.1 can work either way; by default, it works like <span class="application">Python</span> 2.0, but you can add the following line of code at the top of your module to make your module work like <span class="application">Python</span> 2.2:<pre class="programlisting"><span class='pykeyword'>
+from</span> __future__ <span class='pykeyword'>import</span> nested_scopes</pre></td>
+ </tr>
+ </table><a name="tip.localsbyname"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">Using the <tt class="function">locals</tt> and <tt class="function">globals</tt> functions, you can get the value of arbitrary variables dynamically, providing the variable name as a string. This mirrors
+ the functionality of the <a href="../power_of_introspection/getattr.html" title="4.4.&nbsp;Getting Object References With getattr"><tt class="function">getattr</tt></a> function, which allows you to access arbitrary functions dynamically by providing the function name as a string.
+ </td>
+ </tr>
+ </table>
+ <p></p>
+ </li>
+ <li><a href="../html_processing/dictionary_based_string_formatting.html">8.6.&nbsp;Dictionary-based string formatting</a><a name="d0e21731"></a><table class="important" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/important.png" alt="Important" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">Using dictionary-based string formatting with <tt class="function">locals</tt> is a convenient way of making complex string formatting expressions more readable, but it comes with a price. There is a
+ slight performance hit in making the call to <tt class="function">locals</tt>, since <a href="locals_and_globals.html#dialect.locals.readonly.example" title="Example&nbsp;8.12.&nbsp;locals is read-only, globals is not"><tt class="function">locals</tt> builds a copy</a> of the local namespace.
+ </td>
+ </tr>
+ </table>
+ <p></p>
+ </li>
+ </ul>
+ <p><a href="../xml_processing/index.html">Chapter&nbsp;9.&nbsp;XML Processing</a></p>
+ <ul>
+ <li><a href="../xml_processing/packages.html">9.2.&nbsp;Packages</a><a name="d0e23185"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">A package is a directory with the special <tt class="filename">__init__.py</tt> file in it. The <tt class="filename">__init__.py</tt> file defines the attributes and methods of the package. It doesn't need to define anything; it can just be an empty file,
+ but it has to exist. But if <tt class="filename">__init__.py</tt> doesn't exist, the directory is just a directory, not a package, and it can't be imported or contain modules or nested packages.
+ </td>
+ </tr>
+ </table>
+ <p></p>
+ </li>
+ <li><a href="../xml_processing/attributes.html">9.6.&nbsp;Accessing element attributes</a><a name="d0e24744"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">This section may be a little confusing, because of some overlapping terminology. Elements in an <span class="acronym">XML</span> document have attributes, and <span class="application">Python</span> objects also have attributes. When you parse an <span class="acronym">XML</span> document, you get a bunch of <span class="application">Python</span> objects that represent all the pieces of the <span class="acronym">XML</span> document, and some of these <span class="application">Python</span> objects represent attributes of the <span class="acronym">XML</span> elements. But the (<span class="application">Python</span>) objects that represent the (<span class="acronym">XML</span>) attributes also have (<span class="application">Python</span>) attributes, which are used to access various parts of the (<span class="acronym">XML</span>) attribute that the object represents. I told you it was confusing. I am open to suggestions on how to distinguish these
+ more clearly.
+ </td>
+ </tr>
+ </table><a name="d0e24990"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">Like a dictionary, attributes of an <span class="acronym">XML</span> element have no ordering. Attributes may <span class="emphasis"><em>happen to be</em></span> listed in a certain order in the original <span class="acronym">XML</span> document, and the <tt class="classname">Attr</tt> objects may <span class="emphasis"><em>happen to be</em></span> listed in a certain order when the <span class="acronym">XML</span> document is parsed into <span class="application">Python</span> objects, but these orders are arbitrary and should carry no special meaning. You should always access individual attributes
+ by name, like the keys of a dictionary.
+ </td>
+ </tr>
+ </table>
+ <p></p>
+ </li>
+ </ul>
+ <p><a href="../scripts_and_streams/index.html">Chapter&nbsp;10.&nbsp;Scripts and Streams</a></p>
+ <ul></ul>
+ <p><a href="../http_web_services/index.html">Chapter&nbsp;11.&nbsp;HTTP Web Services</a></p>
+ <ul>
+ <li><a href="../http_web_services/etags.html">11.6.&nbsp;Handling Last-Modified and ETag</a><a name="tip.etag.vs.lastmodified"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">In these examples, the HTTP server has supported both <tt class="literal">Last-Modified</tt> and <tt class="literal">ETag</tt> headers, but not all servers do. As a web services client, you should be prepared to support both, but you must code defensively
+ in case a server only supports one or the other, or neither.
+ </td>
+ </tr>
+ </table>
+ <p></p>
+ </li>
+ </ul>
+ <p><a href="../soap_web_services/index.html">Chapter&nbsp;12.&nbsp;SOAP Web Services</a></p>
+ <ul></ul>
+ <p><a href="../unit_testing/index.html">Chapter&nbsp;13.&nbsp;Unit Testing</a></p>
+ <ul>
+ <li><a href="../unit_testing/diving_in.html">13.2.&nbsp;Diving in</a><a name="note.unittest"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%"><tt class="filename">unittest</tt> is included with <span class="application">Python</span> 2.1 and later. <span class="application">Python</span> 2.0 users can download it from <a href="http://pyunit.sourceforge.net/"><tt class="systemitem">pyunit.sourceforge.net</tt></a>.
+ </td>
+ </tr>
+ </table>
+ <p></p>
+ </li>
+ </ul>
+ <p><a href="../unit_testing/stage_1.html">Chapter&nbsp;14.&nbsp;Test-First Programming</a></p>
+ <ul>
+ <li><a href="../unit_testing/stage_3.html">14.3.&nbsp;roman.py, stage 3</a><a name="d0e33558"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">The most important thing that comprehensive unit testing can tell you is when to stop coding. When all the unit tests for
+ a function pass, stop coding the function. When all the unit tests for an entire module pass, stop coding the module.
+ </td>
+ </tr>
+ </table>
+ <p></p>
+ </li>
+ <li><a href="../unit_testing/stage_5.html">14.5.&nbsp;roman.py, stage 5</a><a name="d0e34136"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">When all of your tests pass, stop coding.</td>
+ </tr>
+ </table>
+ <p></p>
+ </li>
+ </ul>
+ <p><a href="../refactoring/index.html">Chapter&nbsp;15.&nbsp;Refactoring</a></p>
+ <ul>
+ <li><a href="../refactoring/refactoring.html">15.3.&nbsp;Refactoring</a><a name="d0e34764"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">Whenever you are going to use a regular expression more than once, you should compile it to get a pattern object, then call
+ the methods on the pattern object directly.
+ </td>
+ </tr>
+ </table>
+ <p></p>
+ </li>
+ </ul>
+ <p><a href="../functional_programming/index.html">Chapter&nbsp;16.&nbsp;Functional Programming</a></p>
+ <ul>
+ <li><a href="../functional_programming/finding_the_path.html">16.2.&nbsp;Finding the path</a><a name="os.path.abspath.exist.note"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">The pathnames and filenames you pass to <tt class="function">os.path.abspath</tt> do not need to exist.
+ </td>
+ </tr>
+ </table><a name="os.path.normpath.note"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%"><tt class="function">os.path.abspath</tt> not only constructs full path names, it also normalizes them. That means that if you are in the <tt class="filename">/usr/</tt> directory, <tt class="literal">os.path.abspath('bin/../local/bin')</tt> will return <tt class="filename">/usr/local/bin</tt>. It normalizes the path by making it as simple as possible. If you just want to normalize a pathname like this without
+ turning it into a full pathname, use <tt class="function">os.path.normpath</tt> instead.
+ </td>
+ </tr>
+ </table><a name="os.path.abspath.crossplatform.note"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">Like the other functions in the <tt class="filename">os</tt> and <tt class="filename">os.path</tt> modules, <tt class="function">os.path.abspath</tt> is cross-platform. Your results will look slightly different than my examples if you're running on Windows (which uses backslash
+ as a path separator) or <span class="abbrev">Mac</span> <span class="acronym">OS</span> (which uses colons), but they'll still work. That's the whole point of the <tt class="filename">os</tt> module.
+ </td>
+ </tr>
+ </table>
+ <p></p>
+ </li>
+ </ul>
+ <p><a href="../dynamic_functions/index.html">Chapter&nbsp;17.&nbsp;Dynamic functions</a></p>
+ <ul></ul>
+ <p><a href="../performance_tuning/index.html">Chapter&nbsp;18.&nbsp;Performance Tuning</a></p>
+ <ul>
+ <li><a href="../performance_tuning/timeit.html">18.2.&nbsp;Using the timeit Module</a><a name="d0e39049"></a><table class="tip" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/tip.png" alt="Tip" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">You can use the <tt class="filename">timeit</tt> module on the command line to test an existing <span class="application">Python</span> program, without modifying the code. See <a href="http://docs.python.org/lib/node396.html">http://docs.python.org/lib/node396.html</a> for documentation on the command-line flags.
+ </td>
+ </tr>
+ </table><a name="d0e39097"></a><table class="tip" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/tip.png" alt="Tip" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">The <tt class="filename">timeit</tt> module only works if you already know what piece of code you need to optimize. If you have a larger <span class="application">Python</span> program and don't know where your performance problems are, check out <a href="http://docs.python.org/lib/module-hotshot.html">the <tt class="filename">hotshot</tt> module.</a></td>
+ </tr>
+ </table>
+ <p></p>
+ </li>
+ </ul>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="abstracts.html">&lt;&lt;&nbsp;A 5-minute review</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="examples.html">List of examples&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/diveintopython.css b/help/diveintopython-5.4/html/diveintopython.css
new file mode 100644
index 0000000..0162921
--- /dev/null
+++ b/help/diveintopython-5.4/html/diveintopython.css
@@ -0,0 +1,187 @@
+body {
+ background-color: white;
+ color: #222;
+ font-family: "Book Antiqua", Georgia, Palatino, Times, "Times New Roman", serif;
+ line-height: 145%;
+}
+
+h1, h2, h3, h4, h5, h6, p#tagline, #menu, .Footer, #breadcrumb {
+ margin: 0;
+ padding: 0;
+ font-family: "Lucida Grande", Tahoma, "Trebuchet MS", Verdana, Lucida, Geneva, Helvetica, sans-serif;
+}
+
+.titlepage h1 {
+ margin-top: 1em;
+}
+
+h1 {
+ font-size: 180%;
+ background-color: white;
+ color: maroon;
+ text-shadow: 2px 2px 2px #990000;
+}
+
+h1 a {
+ background-color: white;
+ color: maroon;
+ text-decoration: none;
+}
+
+h2 {
+ margin-top: 1em;
+ font-size: 140%;
+ text-shadow: 2px 2px 2px #999999;
+}
+
+h3 {
+ margin-top: 1em;
+ font-size: 100%;
+}
+
+label, .divider {
+ display: none;
+}
+
+#Header {
+ border-bottom: 1px solid maroon;
+}
+
+p#tagline {
+ margin: 3px 0 6px 2px;
+ font-size: 90%;
+ font-weight: bold;
+ background-color: white;
+ color: maroon;
+}
+
+#breadcrumb {
+ font-size: 90%;
+}
+
+#navigation {
+ font-size: 90%;
+}
+
+.thispage {
+ font-weight: bold;
+}
+
+.Footer {
+ font-size: 90%;
+ border-top: 1px solid maroon;
+ background-color: white;
+ color: maroon;
+ width: 85%;
+}
+
+table.Footer {
+ margin-top: 1em;
+}
+
+#breadcrumb {
+ padding: 0 0 1em 2px;
+}
+
+.tip, .note, .warning, .caution, .important, .footnote {
+ margin: 1em 2em 1em 2em;
+}
+
+.furtherreading {
+ margin-top: 1em;
+}
+
+.screen, .programlisting, .example table {
+ margin: 1em 1em 0 1em;
+ padding: 0;
+}
+
+.example table {
+ margin-bottom: 1em;
+}
+
+.toc li {
+ list-style: none;
+}
+
+/* ----- Python code syntax coloring ----- */
+.computeroutput, .traceback, .pykeyword, .pystring, .pycomment, .pyfunction, .pyclass {
+ background-color: white;
+}
+
+.pykeyword, .pyfunction, .pyclass {
+ font-weight: bold;
+}
+
+.computeroutput {
+ color: teal;
+}
+
+.traceback {
+ color: red;
+}
+
+.pykeyword {
+ color: navy;
+}
+
+.pystring {
+ color: olive;
+}
+
+.pycomment {
+ color: green;
+ font-style: italic;
+}
+
+.pyfunction {
+ color: teal;
+}
+
+.pyclass {
+ color: blue;
+}
+
+/* ----- home page ----- */
+#wrapper {
+ float: left;
+ width: 66%;
+ border: 0;
+ background-color: white;
+ color: #222;
+ margin: 1em 2em 0 0;
+}
+
+#menu {
+ font-size: 90%;
+ margin-top: 1.5em;
+}
+
+#menu h2 {
+ background-color: white;
+ color: maroon;
+}
+
+#menu ul {
+ list-style: none;
+}
+
+.selfad {
+ padding: 5px;
+ background-color: #ccc;
+ color: #222;
+ border: 1px solid #222;
+}
+
+.selfad p {
+ font-family: Tahoma, sans-serif;
+ font-size: 90%;
+ margin: 10px;
+ line-height: 140%;
+}
+
+#sponsoredlinks {
+ float: right;
+ margin-top: 20px;
+ margin-left: 20px;
+}
diff --git a/help/diveintopython-5.4/html/dynamic_functions/index.html b/help/diveintopython-5.4/html/dynamic_functions/index.html
new file mode 100644
index 0000000..c776852
--- /dev/null
+++ b/help/diveintopython-5.4/html/dynamic_functions/index.html
@@ -0,0 +1,121 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>Chapter&nbsp;17.&nbsp;Dynamic functions</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="../toc/index.html" title="Dive Into Python">
+ <link rel="previous" href="../functional_programming/summary.html" title="16.8.&nbsp;Summary">
+ <link rel="next" href="stage1.html" title="17.2.&nbsp;plural.py, stage 1">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<span class="thispage">Dynamic functions</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="../functional_programming/summary.html" title="Prev: &#8220;Summary&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="stage1.html" title="Next: &#8220;plural.py, stage 1&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="chapter" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="plural"></a>Chapter&nbsp;17.&nbsp;Dynamic functions
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="toc">
+ <ul>
+ <li><span class="section"><a href="index.html#plural.divein">17.1. Diving in</a></span></li>
+ <li><span class="section"><a href="stage1.html">17.2. plural.py, stage 1</a></span></li>
+ <li><span class="section"><a href="stage2.html">17.3. plural.py, stage 2</a></span></li>
+ <li><span class="section"><a href="stage3.html">17.4. plural.py, stage 3</a></span></li>
+ <li><span class="section"><a href="stage4.html">17.5. plural.py, stage 4</a></span></li>
+ <li><span class="section"><a href="stage5.html">17.6. plural.py, stage 5</a></span></li>
+ <li><span class="section"><a href="stage6.html">17.7. plural.py, stage 6</a></span></li>
+ <li><span class="section"><a href="summary.html">17.8. Summary</a></span></li>
+ </ul>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="plural.divein"></a>17.1.&nbsp;Diving in
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>I want to talk about plural nouns. Also, functions that return other functions, advanced regular expressions, and generators.
+ Generators are new in <span class="application">Python</span> 2.3. But first, let's talk about how to make plural nouns.
+ </p>
+ </div>
+ <p>If you haven't read <a href="../regular_expressions/index.html" title="Chapter&nbsp;7.&nbsp;Regular Expressions">Chapter&nbsp;7, <i>Regular Expressions</i></a>, now would be a good time. This chapter assumes you understand the basics of regular expressions, and quickly descends into
+ more advanced uses.
+ </p>
+ <p>English is a schizophrenic language that borrows from a lot of other languages, and the rules for making singular nouns into
+ plural nouns are varied and complex. There are rules, and then there are exceptions to those rules, and then there are exceptions
+ to the exceptions.
+ </p>
+ <p>If you grew up in an English-speaking country or learned English in a formal school setting, you're probably familiar with
+ the basic rules:
+ </p>
+ <div class="orderedlist">
+ <ol type="1">
+ <li>If a word ends in S, X, or Z, add ES. &#8220;<span class="quote">Bass</span>&#8221; becomes &#8220;<span class="quote">basses</span>&#8221;, &#8220;<span class="quote">fax</span>&#8221; becomes &#8220;<span class="quote">faxes</span>&#8221;, and &#8220;<span class="quote">waltz</span>&#8221; becomes &#8220;<span class="quote">waltzes</span>&#8221;.
+ </li>
+ <li>If a word ends in a noisy H, add ES; if it ends in a silent H, just add S. What's a noisy H? One that gets combined with
+ other letters to make a sound that you can hear. So &#8220;<span class="quote">coach</span>&#8221; becomes &#8220;<span class="quote">coaches</span>&#8221; and &#8220;<span class="quote">rash</span>&#8221; becomes &#8220;<span class="quote">rashes</span>&#8221;, because you can hear the CH and SH sounds when you say them. But &#8220;<span class="quote">cheetah</span>&#8221; becomes &#8220;<span class="quote">cheetahs</span>&#8221;, because the H is silent.
+ </li>
+ <li>If a word ends in Y that sounds like I, change the Y to IES; if the Y is combined with a vowel to sound like something else,
+ just add S. So &#8220;<span class="quote">vacancy</span>&#8221; becomes &#8220;<span class="quote">vacancies</span>&#8221;, but &#8220;<span class="quote">day</span>&#8221; becomes &#8220;<span class="quote">days</span>&#8221;.
+ </li>
+ <li>If all else fails, just add S and hope for the best.</li>
+ </ol>
+ </div>
+ <p>(I know, there are a lot of exceptions. &#8220;<span class="quote">Man</span>&#8221; becomes &#8220;<span class="quote">men</span>&#8221; and &#8220;<span class="quote">woman</span>&#8221; becomes &#8220;<span class="quote">women</span>&#8221;, but &#8220;<span class="quote">human</span>&#8221; becomes &#8220;<span class="quote">humans</span>&#8221;. &#8220;<span class="quote">Mouse</span>&#8221; becomes &#8220;<span class="quote">mice</span>&#8221; and &#8220;<span class="quote">louse</span>&#8221; becomes &#8220;<span class="quote">lice</span>&#8221;, but &#8220;<span class="quote">house</span>&#8221; becomes &#8220;<span class="quote">houses</span>&#8221;. &#8220;<span class="quote">Knife</span>&#8221; becomes &#8220;<span class="quote">knives</span>&#8221; and &#8220;<span class="quote">wife</span>&#8221; becomes &#8220;<span class="quote">wives</span>&#8221;, but &#8220;<span class="quote">lowlife</span>&#8221; becomes &#8220;<span class="quote">lowlifes</span>&#8221;. And don't even get me started on words that are their own plural, like &#8220;<span class="quote">sheep</span>&#8221;, &#8220;<span class="quote">deer</span>&#8221;, and &#8220;<span class="quote">haiku</span>&#8221;.)
+ </p>
+ <p>Other languages are, of course, completely different.</p>
+ <p>Let's design a module that pluralizes nouns. Start with just English nouns, and just these four rules, but keep in mind that
+ you'll inevitably need to add more rules, and you may eventually need to add more languages.
+ </p>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="../functional_programming/summary.html">&lt;&lt;&nbsp;Summary</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<span class="thispage">1</span> <span class="divider">|</span> <a href="stage1.html" title="17.2.&nbsp;plural.py, stage 1">2</a> <span class="divider">|</span> <a href="stage2.html" title="17.3.&nbsp;plural.py, stage 2">3</a> <span class="divider">|</span> <a href="stage3.html" title="17.4.&nbsp;plural.py, stage 3">4</a> <span class="divider">|</span> <a href="stage4.html" title="17.5.&nbsp;plural.py, stage 4">5</a> <span class="divider">|</span> <a href="stage5.html" title="17.6.&nbsp;plural.py, stage 5">6</a> <span class="divider">|</span> <a href="stage6.html" title="17.7.&nbsp;plural.py, stage 6">7</a> <span class="divider">|</span> <a href="summary.html" title="17.8.&nbsp;Summary">8</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="stage1.html">plural.py, stage 1&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/dynamic_functions/stage1.html b/help/diveintopython-5.4/html/dynamic_functions/stage1.html
new file mode 100644
index 0000000..ec9de92
--- /dev/null
+++ b/help/diveintopython-5.4/html/dynamic_functions/stage1.html
@@ -0,0 +1,235 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>17.2.&nbsp;plural.py, stage 1</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;17.&nbsp;Dynamic functions">
+ <link rel="previous" href="index.html" title="Chapter&nbsp;17.&nbsp;Dynamic functions">
+ <link rel="next" href="stage2.html" title="17.3.&nbsp;plural.py, stage 2">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Dynamic functions</a>&nbsp;&gt;&nbsp;<span class="thispage">plural.py, stage 1</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="index.html" title="Prev: &#8220;Dynamic functions&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="stage2.html" title="Next: &#8220;plural.py, stage 2&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="plural.stage1"></a>17.2.&nbsp;<tt class="filename">plural.py</tt>, stage 1
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>So you're looking at words, which at least in English are strings of characters. And you have rules that say you need to
+ find different combinations of characters, and then do different things to them. This sounds like a job for regular expressions.
+ </p>
+ </div>
+ <div class="example"><a name="d0e37108"></a><h3 class="title">Example&nbsp;17.1.&nbsp;<tt class="filename">plural1.py</tt></h3><pre class="programlisting"><span class='pykeyword'>
+import</span> re
+
+<span class='pykeyword'>def</span><span class='pyclass'> plural</span>(noun):
+ <span class='pykeyword'>if</span> re.search(<span class='pystring'>'[sxz]$'</span>, noun): <a name="plural.stage1.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ <span class='pykeyword'>return</span> re.sub(<span class='pystring'>'$'</span>, <span class='pystring'>'es'</span>, noun) <a name="plural.stage1.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+ <span class='pykeyword'>elif</span> re.search(<span class='pystring'>'[^aeioudgkprt]h$'</span>, noun):
+ <span class='pykeyword'>return</span> re.sub(<span class='pystring'>'$'</span>, <span class='pystring'>'es'</span>, noun)
+ <span class='pykeyword'>elif</span> re.search(<span class='pystring'>'[^aeiou]y$'</span>, noun):
+ <span class='pykeyword'>return</span> re.sub(<span class='pystring'>'y$'</span>, <span class='pystring'>'ies'</span>, noun)
+ <span class='pykeyword'>else</span>:
+ <span class='pykeyword'>return</span> noun + <span class='pystring'>'s'</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#plural.stage1.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">OK, this is a regular expression, but it uses a syntax you didn't see in <a href="../regular_expressions/index.html" title="Chapter&nbsp;7.&nbsp;Regular Expressions">Chapter&nbsp;7, <i>Regular Expressions</i></a>. The square brackets mean &#8220;<span class="quote">match exactly one of these characters</span>&#8221;. So <tt class="literal">[sxz]</tt> means &#8220;<span class="quote"><tt class="literal">s</tt>, or <tt class="literal">x</tt>, or <tt class="literal">z</tt></span>&#8221;, but only one of them. The <tt class="literal">$</tt> should be familiar; it matches the end of string. So you're checking to see if <tt class="varname">noun</tt> ends with <tt class="literal">s</tt>, <tt class="literal">x</tt>, or <tt class="literal">z</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#plural.stage1.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This <tt class="function">re.sub</tt> function performs regular expression-based string substitutions. Let's look at it in more detail.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="d0e37161"></a><h3 class="title">Example&nbsp;17.2.&nbsp;Introducing <tt class="function">re.sub</tt></h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> re</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">re.search(<span class='pystring'>'[abc]'</span>, <span class='pystring'>'Mark'</span>)</span> <a name="plural.stage1.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">&lt;_sre.SRE_Match object at 0x001C1FA8&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">re.sub(<span class='pystring'>'[abc]'</span>, <span class='pystring'>'o'</span>, <span class='pystring'>'Mark'</span>)</span> <a name="plural.stage1.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">'Mork'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">re.sub(<span class='pystring'>'[abc]'</span>, <span class='pystring'>'o'</span>, <span class='pystring'>'rock'</span>)</span> <a name="plural.stage1.2.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">'rook'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">re.sub(<span class='pystring'>'[abc]'</span>, <span class='pystring'>'o'</span>, <span class='pystring'>'caps'</span>)</span> <a name="plural.stage1.2.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">'oops'</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#plural.stage1.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Does the string <tt class="literal">Mark</tt> contain <tt class="literal">a</tt>, <tt class="literal">b</tt>, or <tt class="literal">c</tt>? Yes, it contains <tt class="literal">a</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#plural.stage1.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">OK, now find <tt class="literal">a</tt>, <tt class="literal">b</tt>, or <tt class="literal">c</tt>, and replace it with <tt class="literal">o</tt>. <tt class="literal">Mark</tt> becomes <tt class="literal">Mork</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#plural.stage1.2.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The same function turns <tt class="literal">rock</tt> into <tt class="literal">rook</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#plural.stage1.2.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You might think this would turn <tt class="literal">caps</tt> into <tt class="literal">oaps</tt>, but it doesn't. <tt class="literal">re.sub</tt> replaces <span class="emphasis"><em>all</em></span> of the matches, not just the first one. So this regular expression turns <tt class="literal">caps</tt> into <tt class="literal">oops</tt>, because both the <tt class="literal">c</tt> and the <tt class="literal">a</tt> get turned into <tt class="literal">o</tt>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="d0e37292"></a><h3 class="title">Example&nbsp;17.3.&nbsp;Back to <tt class="filename">plural1.py</tt></h3><pre class="programlisting"><span class='pykeyword'>
+import</span> re
+
+<span class='pykeyword'>def</span><span class='pyclass'> plural</span>(noun):
+ <span class='pykeyword'>if</span> re.search(<span class='pystring'>'[sxz]$'</span>, noun):
+ <span class='pykeyword'>return</span> re.sub(<span class='pystring'>'$'</span>, <span class='pystring'>'es'</span>, noun) <a name="plural.stage1.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ <span class='pykeyword'>elif</span> re.search(<span class='pystring'>'[^aeioudgkprt]h$'</span>, noun): <a name="plural.stage1.3.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+ <span class='pykeyword'>return</span> re.sub(<span class='pystring'>'$'</span>, <span class='pystring'>'es'</span>, noun) <a name="plural.stage1.3.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+ <span class='pykeyword'>elif</span> re.search(<span class='pystring'>'[^aeiou]y$'</span>, noun):
+ <span class='pykeyword'>return</span> re.sub(<span class='pystring'>'y$'</span>, <span class='pystring'>'ies'</span>, noun)
+ <span class='pykeyword'>else</span>:
+ <span class='pykeyword'>return</span> noun + <span class='pystring'>'s'</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#plural.stage1.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Back to the <tt class="function">plural</tt> function. What are you doing? You're replacing the end of string with <tt class="literal">es</tt>. In other words, adding <tt class="literal">es</tt> to the string. You could accomplish the same thing with string concatenation, for example <tt class="literal">noun + 'es'</tt>, but I'm using regular expressions for everything, for consistency, for reasons that will become clear later in the chapter.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#plural.stage1.3.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Look closely, this is another new variation. The <tt class="literal">^</tt> as the first character inside the square brackets means something special: negation. <tt class="literal">[^abc]</tt> means &#8220;<span class="quote">any single character <span class="emphasis"><em>except</em></span> <tt class="literal">a</tt>, <tt class="literal">b</tt>, or <tt class="literal">c</tt></span>&#8221;. So <tt class="literal">[^aeioudgkprt]</tt> means any character except <tt class="literal">a</tt>, <tt class="literal">e</tt>, <tt class="literal">i</tt>, <tt class="literal">o</tt>, <tt class="literal">u</tt>, <tt class="literal">d</tt>, <tt class="literal">g</tt>, <tt class="literal">k</tt>, <tt class="literal">p</tt>, <tt class="literal">r</tt>, or <tt class="literal">t</tt>. Then that character needs to be followed by <tt class="literal">h</tt>, followed by end of string. You're looking for words that end in H where the H can be heard.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#plural.stage1.3.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Same pattern here: match words that end in Y, where the character before the Y is <span class="emphasis"><em>not</em></span> <tt class="literal">a</tt>, <tt class="literal">e</tt>, <tt class="literal">i</tt>, <tt class="literal">o</tt>, or <tt class="literal">u</tt>. You're looking for words that end in Y that sounds like I.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="d0e37404"></a><h3 class="title">Example&nbsp;17.4.&nbsp;More on negation regular expressions</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> re</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">re.search(<span class='pystring'>'[^aeiou]y$'</span>, <span class='pystring'>'vacancy'</span>)</span> <a name="plural.stage1.4.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">&lt;_sre.SRE_Match object at 0x001C1FA8&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">re.search(<span class='pystring'>'[^aeiou]y$'</span>, <span class='pystring'>'boy'</span>)</span> <a name="plural.stage1.4.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">re.search(<span class='pystring'>'[^aeiou]y$'</span>, <span class='pystring'>'day'</span>)</span>
+<tt class="prompt">&gt;&gt;&gt; </tt>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">re.search(<span class='pystring'>'[^aeiou]y$'</span>, <span class='pystring'>'pita'</span>)</span> <a name="plural.stage1.4.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#plural.stage1.4.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="literal">vacancy</tt> matches this regular expression, because it ends in <tt class="literal">cy</tt>, and <tt class="literal">c</tt> is not <tt class="literal">a</tt>, <tt class="literal">e</tt>, <tt class="literal">i</tt>, <tt class="literal">o</tt>, or <tt class="literal">u</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#plural.stage1.4.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="literal">boy</tt> does not match, because it ends in <tt class="literal">oy</tt>, and you specifically said that the character before the <tt class="literal">y</tt> could not be <tt class="literal">o</tt>. <tt class="literal">day</tt> does not match, because it ends in <tt class="literal">ay</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#plural.stage1.4.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="literal">pita</tt> does not match, because it does not end in <tt class="literal">y</tt>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="d0e37507"></a><h3 class="title">Example&nbsp;17.5.&nbsp;More on <tt class="function">re.sub</tt></h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">re.sub(<span class='pystring'>'y$'</span>, <span class='pystring'>'ies'</span>, <span class='pystring'>'vacancy'</span>)</span> <a name="plural.stage1.5.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">'vacancies'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">re.sub(<span class='pystring'>'y$'</span>, <span class='pystring'>'ies'</span>, <span class='pystring'>'agency'</span>)</span>
+<span class="computeroutput">'agencies'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">re.sub(<span class='pystring'>'([^aeiou])y$'</span>, r<span class='pystring'>'\1ies'</span>, <span class='pystring'>'vacancy'</span>)</span> <a name="plural.stage1.5.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">'vacancies'</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#plural.stage1.5.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This regular expression turns <tt class="literal">vacancy</tt> into <tt class="literal">vacancies</tt> and <tt class="literal">agency</tt> into <tt class="literal">agencies</tt>, which is what you wanted. Note that it would also turn <tt class="literal">boy</tt> into <tt class="literal">boies</tt>, but that will never happen in the function because you did that <tt class="function">re.search</tt> first to find out whether you should do this <tt class="function">re.sub</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#plural.stage1.5.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Just in passing, I want to point out that it is possible to combine these two regular expressions (one to find out if the
+ rule applies, and another to actually apply it) into a single regular expression. Here's what that would look like. Most
+ of it should look familiar: you're using a remembered group, which you learned in <a href="../regular_expressions/phone_numbers.html" title="7.6.&nbsp;Case study: Parsing Phone Numbers">Section&nbsp;7.6, &#8220;Case study: Parsing Phone Numbers&#8221;</a>, to remember the character before the <tt class="literal">y</tt>. Then in the substitution string, you use a new syntax, <tt class="literal">\1</tt>, which means &#8220;<span class="quote">hey, that first group you remembered? put it here</span>&#8221;. In this case, you remember the <tt class="literal">c</tt> before the <tt class="literal">y</tt>, and then when you do the substitution, you substitute <tt class="literal">c</tt> in place of <tt class="literal">c</tt>, and <tt class="literal">ies</tt> in place of <tt class="literal">y</tt>. (If you have more than one remembered group, you can use <tt class="literal">\2</tt> and <tt class="literal">\3</tt> and so on.)
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>Regular expression substitutions are extremely powerful, and the <tt class="literal">\1</tt> syntax makes them even more powerful. But combining the entire operation into one regular expression is also much harder
+ to read, and it doesn't directly map to the way you first described the pluralizing rules. You originally laid out rules
+ like &#8220;<span class="quote">if the word ends in S, X, or Z, then add ES</span>&#8221;. And if you look at this function, you have two lines of code that say &#8220;<span class="quote">if the word ends in S, X, or Z, then add ES</span>&#8221;. It doesn't get much more direct than that.
+ </p>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="index.html">&lt;&lt;&nbsp;Dynamic functions</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#plural.divein" title="17.1.&nbsp;Diving in">1</a> <span class="divider">|</span> <span class="thispage">2</span> <span class="divider">|</span> <a href="stage2.html" title="17.3.&nbsp;plural.py, stage 2">3</a> <span class="divider">|</span> <a href="stage3.html" title="17.4.&nbsp;plural.py, stage 3">4</a> <span class="divider">|</span> <a href="stage4.html" title="17.5.&nbsp;plural.py, stage 4">5</a> <span class="divider">|</span> <a href="stage5.html" title="17.6.&nbsp;plural.py, stage 5">6</a> <span class="divider">|</span> <a href="stage6.html" title="17.7.&nbsp;plural.py, stage 6">7</a> <span class="divider">|</span> <a href="summary.html" title="17.8.&nbsp;Summary">8</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="stage2.html">plural.py, stage 2&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/dynamic_functions/stage2.html b/help/diveintopython-5.4/html/dynamic_functions/stage2.html
new file mode 100644
index 0000000..3eac124
--- /dev/null
+++ b/help/diveintopython-5.4/html/dynamic_functions/stage2.html
@@ -0,0 +1,158 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>17.3.&nbsp;plural.py, stage 2</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;17.&nbsp;Dynamic functions">
+ <link rel="previous" href="stage1.html" title="17.2.&nbsp;plural.py, stage 1">
+ <link rel="next" href="stage3.html" title="17.4.&nbsp;plural.py, stage 3">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Dynamic functions</a>&nbsp;&gt;&nbsp;<span class="thispage">plural.py, stage 2</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="stage1.html" title="Prev: &#8220;plural.py, stage 1&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="stage3.html" title="Next: &#8220;plural.py, stage 3&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="plural.stage2"></a>17.3.&nbsp;<tt class="filename">plural.py</tt>, stage 2
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>Now you're going to add a level of abstraction. You started by defining a list of rules: if this, then do that, otherwise
+ go to the next rule. Let's temporarily complicate part of the program so you can simplify another part.
+ </p>
+ </div>
+ <div class="example"><a name="d0e37629"></a><h3 class="title">Example&nbsp;17.6.&nbsp;<tt class="filename">plural2.py</tt></h3><pre class="programlisting"><span class='pykeyword'>
+import</span> re
+
+<span class='pykeyword'>def</span><span class='pyclass'> match_sxz</span>(noun):
+ <span class='pykeyword'>return</span> re.search(<span class='pystring'>'[sxz]$'</span>, noun)
+
+<span class='pykeyword'>def</span><span class='pyclass'> apply_sxz</span>(noun):
+ <span class='pykeyword'>return</span> re.sub(<span class='pystring'>'$'</span>, <span class='pystring'>'es'</span>, noun)
+
+<span class='pykeyword'>def</span><span class='pyclass'> match_h</span>(noun):
+ <span class='pykeyword'>return</span> re.search(<span class='pystring'>'[^aeioudgkprt]h$'</span>, noun)
+
+<span class='pykeyword'>def</span><span class='pyclass'> apply_h</span>(noun):
+ <span class='pykeyword'>return</span> re.sub(<span class='pystring'>'$'</span>, <span class='pystring'>'es'</span>, noun)
+
+<span class='pykeyword'>def</span><span class='pyclass'> match_y</span>(noun):
+ <span class='pykeyword'>return</span> re.search(<span class='pystring'>'[^aeiou]y$'</span>, noun)
+
+<span class='pykeyword'>def</span><span class='pyclass'> apply_y</span>(noun):
+ <span class='pykeyword'>return</span> re.sub(<span class='pystring'>'y$'</span>, <span class='pystring'>'ies'</span>, noun)
+
+<span class='pykeyword'>def</span><span class='pyclass'> match_default</span>(noun):
+ <span class='pykeyword'>return</span> 1
+
+<span class='pykeyword'>def</span><span class='pyclass'> apply_default</span>(noun):
+ <span class='pykeyword'>return</span> noun + <span class='pystring'>'s'</span>
+
+rules = ((match_sxz, apply_sxz),
+ (match_h, apply_h),
+ (match_y, apply_y),
+ (match_default, apply_default)
+ ) <a name="plural.stage2.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+
+<span class='pykeyword'>def</span><span class='pyclass'> plural</span>(noun):
+ <span class='pykeyword'>for</span> matchesRule, applyRule <span class='pykeyword'>in</span> rules: <a name="plural.stage2.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+ <span class='pykeyword'>if</span> matchesRule(noun): <a name="plural.stage2.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+ <span class='pykeyword'>return</span> applyRule(noun) <a name="plural.stage2.1.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#plural.stage2.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This version looks more complicated (it's certainly longer), but it does exactly the same thing: try to match four different
+ rules, in order, and apply the appropriate regular expression when a match is found. The difference is that each individual
+ match and apply rule is defined in its own function, and the functions are then listed in this <tt class="varname">rules</tt> variable, which is a tuple of tuples.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#plural.stage2.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Using a <tt class="literal">for</tt> loop, you can pull out the match and apply rules two at a time (one match, one apply) from the <tt class="varname">rules</tt> tuple. On the first iteration of the <tt class="literal">for</tt> loop, <tt class="varname">matchesRule</tt> will get <tt class="function">match_sxz</tt>, and <tt class="varname">applyRule</tt> will get <tt class="function">apply_sxz</tt>. On the second iteration (assuming you get that far), <tt class="varname">matchesRule</tt> will be assigned <tt class="function">match_h</tt>, and <tt class="varname">applyRule</tt> will be assigned <tt class="function">apply_h</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#plural.stage2.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Remember that <a href="../getting_to_know_python/everything_is_an_object.html" title="2.4.&nbsp;Everything Is an Object">everything in <span class="application">Python</span> is an object</a>, including functions. <tt class="varname">rules</tt> contains actual functions; not names of functions, but actual functions. When they get assigned in the <tt class="literal">for</tt> loop, then <tt class="varname">matchesRule</tt> and <tt class="varname">applyRule</tt> are actual functions that you can call. So on the first iteration of the <tt class="literal">for</tt> loop, this is equivalent to calling <tt class="function">matches_sxz(noun)</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#plural.stage2.1.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">On the first iteration of the <tt class="literal">for</tt> loop, this is equivalent to calling <tt class="function">apply_sxz(noun)</tt>, and so forth.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>If this additional level of abstraction is confusing, try unrolling the function to see the equivalence. This <tt class="literal">for</tt> loop is equivalent to the following:
+ </p>
+ <div class="example"><a name="d0e37727"></a><h3 class="title">Example&nbsp;17.7.&nbsp;Unrolling the <tt class="function">plural</tt> function
+ </h3><pre class="programlisting"><span class='pykeyword'>
+def</span> plural(noun):
+ <span class='pykeyword'>if</span> match_sxz(noun):
+ <span class='pykeyword'>return</span> apply_sxz(noun)
+ <span class='pykeyword'>if</span> match_h(noun):
+ <span class='pykeyword'>return</span> apply_h(noun)
+ <span class='pykeyword'>if</span> match_y(noun):
+ <span class='pykeyword'>return</span> apply_y(noun)
+ <span class='pykeyword'>if</span> match_default(noun):
+ <span class='pykeyword'>return</span> apply_default(noun)
+</pre></div>
+ <p>The benefit here is that that <tt class="function">plural</tt> function is now simplified. It takes a list of rules, defined elsewhere, and iterates through them in a generic fashion.
+ Get a match rule; does it match? Then call the apply rule. The rules could be defined anywhere, in any way. The <tt class="function">plural</tt> function doesn't care.
+ </p>
+ <p>Now, was adding this level of abstraction worth it? Well, not yet. Let's consider what it would take to add a new rule to
+ the function. Well, in the previous example, it would require adding an <tt class="literal">if</tt> statement to the <tt class="function">plural</tt> function. In this example, it would require adding two functions, <tt class="function">match_foo</tt> and <tt class="function">apply_foo</tt>, and then updating the <tt class="varname">rules</tt> list to specify where in the order the new match and apply functions should be called relative to the other rules.
+ </p>
+ <p>This is really just a stepping stone to the next section. Let's move on.</p>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="stage1.html">&lt;&lt;&nbsp;plural.py, stage 1</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#plural.divein" title="17.1.&nbsp;Diving in">1</a> <span class="divider">|</span> <a href="stage1.html" title="17.2.&nbsp;plural.py, stage 1">2</a> <span class="divider">|</span> <span class="thispage">3</span> <span class="divider">|</span> <a href="stage3.html" title="17.4.&nbsp;plural.py, stage 3">4</a> <span class="divider">|</span> <a href="stage4.html" title="17.5.&nbsp;plural.py, stage 4">5</a> <span class="divider">|</span> <a href="stage5.html" title="17.6.&nbsp;plural.py, stage 5">6</a> <span class="divider">|</span> <a href="stage6.html" title="17.7.&nbsp;plural.py, stage 6">7</a> <span class="divider">|</span> <a href="summary.html" title="17.8.&nbsp;Summary">8</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="stage3.html">plural.py, stage 3&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/dynamic_functions/stage3.html b/help/diveintopython-5.4/html/dynamic_functions/stage3.html
new file mode 100644
index 0000000..5586bd5
--- /dev/null
+++ b/help/diveintopython-5.4/html/dynamic_functions/stage3.html
@@ -0,0 +1,120 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>17.4.&nbsp;plural.py, stage 3</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;17.&nbsp;Dynamic functions">
+ <link rel="previous" href="stage2.html" title="17.3.&nbsp;plural.py, stage 2">
+ <link rel="next" href="stage4.html" title="17.5.&nbsp;plural.py, stage 4">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Dynamic functions</a>&nbsp;&gt;&nbsp;<span class="thispage">plural.py, stage 3</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="stage2.html" title="Prev: &#8220;plural.py, stage 2&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="stage4.html" title="Next: &#8220;plural.py, stage 4&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="plural.stage3"></a>17.4.&nbsp;<tt class="filename">plural.py</tt>, stage 3
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>Defining separate named functions for each match and apply rule isn't really necessary. You never call them directly; you
+ define them in the <tt class="varname">rules</tt> list and call them through there. Let's streamline the rules definition by anonymizing those functions.
+ </p>
+ </div>
+ <div class="example"><a name="d0e37775"></a><h3 class="title">Example&nbsp;17.8.&nbsp;<tt class="filename">plural3.py</tt></h3><pre class="programlisting"><span class='pykeyword'>
+import</span> re
+
+rules = \
+ (
+ (
+ <span class='pykeyword'>lambda</span> word: re.search(<span class='pystring'>'[sxz]$'</span>, word),
+ <span class='pykeyword'>lambda</span> word: re.sub(<span class='pystring'>'$'</span>, <span class='pystring'>'es'</span>, word)
+ ),
+ (
+ <span class='pykeyword'>lambda</span> word: re.search(<span class='pystring'>'[^aeioudgkprt]h$'</span>, word),
+ <span class='pykeyword'>lambda</span> word: re.sub(<span class='pystring'>'$'</span>, <span class='pystring'>'es'</span>, word)
+ ),
+ (
+ <span class='pykeyword'>lambda</span> word: re.search(<span class='pystring'>'[^aeiou]y$'</span>, word),
+ <span class='pykeyword'>lambda</span> word: re.sub(<span class='pystring'>'y$'</span>, <span class='pystring'>'ies'</span>, word)
+ ),
+ (
+ <span class='pykeyword'>lambda</span> word: re.search(<span class='pystring'>'$'</span>, word),
+ <span class='pykeyword'>lambda</span> word: re.sub(<span class='pystring'>'$'</span>, <span class='pystring'>'s'</span>, word)
+ )
+ ) <a name="plural.stage3.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+
+<span class='pykeyword'>def</span><span class='pyclass'> plural</span>(noun):
+ <span class='pykeyword'>for</span> matchesRule, applyRule <span class='pykeyword'>in</span> rules: <a name="plural.stage3.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+ <span class='pykeyword'>if</span> matchesRule(noun):
+ <span class='pykeyword'>return</span> applyRule(noun)
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#plural.stage3.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This is the same set of rules as you defined in stage 2. The only difference is that instead of defining named functions
+ like <tt class="function">match_sxz</tt> and <tt class="function">apply_sxz</tt>, you have &#8220;<span class="quote">inlined</span>&#8221; those function definitions directly into the <tt class="varname">rules</tt> list itself, using <a href="../power_of_introspection/lambda_functions.html" title="4.7.&nbsp;Using lambda Functions">lambda functions</a>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#plural.stage3.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Note that the <tt class="function">plural</tt> function hasn't changed at all. It iterates through a set of rule functions, checks the first rule, and if it returns a
+ true value, calls the second rule and returns the value. Same as above, word for word. The only difference is that the rule
+ functions were defined inline, anonymously, using lambda functions. But the <tt class="function">plural</tt> function doesn't care how they were defined; it just gets a list of rules and blindly works through them.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>Now to add a new rule, all you need to do is define the functions directly in the <tt class="varname">rules</tt> list itself: one match rule, and one apply rule. But defining the rule functions inline like this makes it very clear that
+ you have some unnecessary duplication here. You have four pairs of functions, and they all follow the same pattern. The
+ match function is a single call to <tt class="function">re.search</tt>, and the apply function is a single call to <tt class="function">re.sub</tt>. Let's factor out these similarities.
+ </p>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="stage2.html">&lt;&lt;&nbsp;plural.py, stage 2</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#plural.divein" title="17.1.&nbsp;Diving in">1</a> <span class="divider">|</span> <a href="stage1.html" title="17.2.&nbsp;plural.py, stage 1">2</a> <span class="divider">|</span> <a href="stage2.html" title="17.3.&nbsp;plural.py, stage 2">3</a> <span class="divider">|</span> <span class="thispage">4</span> <span class="divider">|</span> <a href="stage4.html" title="17.5.&nbsp;plural.py, stage 4">5</a> <span class="divider">|</span> <a href="stage5.html" title="17.6.&nbsp;plural.py, stage 5">6</a> <span class="divider">|</span> <a href="stage6.html" title="17.7.&nbsp;plural.py, stage 6">7</a> <span class="divider">|</span> <a href="summary.html" title="17.8.&nbsp;Summary">8</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="stage4.html">plural.py, stage 4&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/dynamic_functions/stage4.html b/help/diveintopython-5.4/html/dynamic_functions/stage4.html
new file mode 100644
index 0000000..12dca7e
--- /dev/null
+++ b/help/diveintopython-5.4/html/dynamic_functions/stage4.html
@@ -0,0 +1,212 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>17.5.&nbsp;plural.py, stage 4</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;17.&nbsp;Dynamic functions">
+ <link rel="previous" href="stage3.html" title="17.4.&nbsp;plural.py, stage 3">
+ <link rel="next" href="stage5.html" title="17.6.&nbsp;plural.py, stage 5">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Dynamic functions</a>&nbsp;&gt;&nbsp;<span class="thispage">plural.py, stage 4</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="stage3.html" title="Prev: &#8220;plural.py, stage 3&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="stage5.html" title="Next: &#8220;plural.py, stage 5&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="plural.stage4"></a>17.5.&nbsp;<tt class="filename">plural.py</tt>, stage 4
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>Let's factor out the duplication in the code so that defining new rules can be easier.</p>
+ </div>
+ <div class="example"><a name="plural.stage4.example.1"></a><h3 class="title">Example&nbsp;17.9.&nbsp;<tt class="filename">plural4.py</tt></h3><pre class="programlisting"><span class='pykeyword'>
+import</span> re
+
+<span class='pykeyword'>def</span><span class='pyclass'> buildMatchAndApplyFunctions</span>((pattern, search, replace)):
+ matchFunction = <span class='pykeyword'>lambda</span> word: re.search(pattern, word) <a name="plural.stage4.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ applyFunction = <span class='pykeyword'>lambda</span> word: re.sub(search, replace, word) <a name="plural.stage4.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+ <span class='pykeyword'>return</span> (matchFunction, applyFunction) <a name="plural.stage4.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#plural.stage4.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">buildMatchAndApplyFunctions</tt> is a function that builds other functions dynamically. It takes <tt class="varname">pattern</tt>, <tt class="varname">search</tt> and <tt class="varname">replace</tt> (actually it takes a tuple, but more on that in a minute), and you can build the match function using the <tt class="literal">lambda</tt> syntax to be a function that takes one parameter (<tt class="varname">word</tt>) and calls <tt class="function">re.search</tt> with the <tt class="varname">pattern</tt> that was passed to the <tt class="function">buildMatchAndApplyFunctions</tt> function, and the <tt class="varname">word</tt> that was passed to the match function you're building. Whoa.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#plural.stage4.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Building the apply function works the same way. The apply function is a function that takes one parameter, and calls <tt class="function">re.sub</tt> with the <tt class="varname">search</tt> and <tt class="varname">replace</tt> parameters that were passed to the <tt class="function">buildMatchAndApplyFunctions</tt> function, and the <tt class="varname">word</tt> that was passed to the apply function you're building. This technique of using the values of outside parameters within a
+ dynamic function is called <span class="emphasis"><em>closures</em></span>. You're essentially defining constants within the apply function you're building: it takes one parameter (<tt class="varname">word</tt>), but it then acts on that plus two other values (<tt class="varname">search</tt> and <tt class="varname">replace</tt>) which were set when you defined the apply function.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#plural.stage4.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Finally, the <tt class="function">buildMatchAndApplyFunctions</tt> function returns a tuple of two values: the two functions you just created. The constants you defined within those functions
+ (<tt class="varname">pattern</tt> within <tt class="varname">matchFunction</tt>, and <tt class="varname">search</tt> and <tt class="varname">replace</tt> within <tt class="varname">applyFunction</tt>) stay with those functions, even after you return from <tt class="function">buildMatchAndApplyFunctions</tt>. That's insanely cool.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>If this is incredibly confusing (and it should be, this is weird stuff), it may become clearer when you see how to use it.</p>
+ <div class="example"><a name="d0e37935"></a><h3 class="title">Example&nbsp;17.10.&nbsp;<tt class="filename">plural4.py</tt> continued
+ </h3><pre class="programlisting">
+patterns = \
+ (
+ (<span class='pystring'>'[sxz]$'</span>, <span class='pystring'>'$'</span>, <span class='pystring'>'es'</span>),
+ (<span class='pystring'>'[^aeioudgkprt]h$'</span>, <span class='pystring'>'$'</span>, <span class='pystring'>'es'</span>),
+ (<span class='pystring'>'(qu|[^aeiou])y$'</span>, <span class='pystring'>'y$'</span>, <span class='pystring'>'ies'</span>),
+ (<span class='pystring'>'$'</span>, <span class='pystring'>'$'</span>, <span class='pystring'>'s'</span>)
+ ) <a name="plural.stage4.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+rules = map(buildMatchAndApplyFunctions, patterns) <a name="plural.stage4.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#plural.stage4.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Our pluralization rules are now defined as a series of strings (not functions). The first string is the regular expression
+ that you would use in <tt class="function">re.search</tt> to see if this rule matches; the second and third are the search and replace expressions you would use in <tt class="function">re.sub</tt> to actually apply the rule to turn a noun into its plural.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#plural.stage4.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This line is magic. It takes the list of strings in <tt class="varname">patterns</tt> and turns them into a list of functions. How? By mapping the strings to the <tt class="function">buildMatchAndApplyFunctions</tt> function, which just happens to take three strings as parameters and return a tuple of two functions. This means that <tt class="varname">rules</tt> ends up being exactly the same as the previous example: a list of tuples, where each tuple is a pair of functions, where
+ the first function is the match function that calls <tt class="function">re.search</tt>, and the second function is the apply function that calls <tt class="function">re.sub</tt>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>I swear I am not making this up: <tt class="varname">rules</tt> ends up with exactly the same list of functions as the previous example. Unroll the <tt class="varname">rules</tt> definition, and you'll get this:
+ </p>
+ <div class="example"><a name="d0e37982"></a><h3 class="title">Example&nbsp;17.11.&nbsp;Unrolling the rules definition</h3><pre class="programlisting">
+rules = \
+ (
+ (
+ <span class='pykeyword'>lambda</span> word: re.search(<span class='pystring'>'[sxz]$'</span>, word),
+ <span class='pykeyword'>lambda</span> word: re.sub(<span class='pystring'>'$'</span>, <span class='pystring'>'es'</span>, word)
+ ),
+ (
+ <span class='pykeyword'>lambda</span> word: re.search(<span class='pystring'>'[^aeioudgkprt]h$'</span>, word),
+ <span class='pykeyword'>lambda</span> word: re.sub(<span class='pystring'>'$'</span>, <span class='pystring'>'es'</span>, word)
+ ),
+ (
+ <span class='pykeyword'>lambda</span> word: re.search(<span class='pystring'>'[^aeiou]y$'</span>, word),
+ <span class='pykeyword'>lambda</span> word: re.sub(<span class='pystring'>'y$'</span>, <span class='pystring'>'ies'</span>, word)
+ ),
+ (
+ <span class='pykeyword'>lambda</span> word: re.search(<span class='pystring'>'$'</span>, word),
+ <span class='pykeyword'>lambda</span> word: re.sub(<span class='pystring'>'$'</span>, <span class='pystring'>'s'</span>, word)
+ )
+ )
+</pre></div>
+ <div class="example"><a name="plural.finishing.up"></a><h3 class="title">Example&nbsp;17.12.&nbsp;<tt class="filename">plural4.py</tt>, finishing up
+ </h3><pre class="programlisting"><span class='pykeyword'>
+def</span> plural(noun):
+ <span class='pykeyword'>for</span> matchesRule, applyRule <span class='pykeyword'>in</span> rules: <a name="plural.stage4.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ <span class='pykeyword'>if</span> matchesRule(noun):
+ <span class='pykeyword'>return</span> applyRule(noun)
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#plural.stage4.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Since the <tt class="varname">rules</tt> list is the same as the previous example, it should come as no surprise that the <tt class="function">plural</tt> function hasn't changed. Remember, it's completely generic; it takes a list of rule functions and calls them in order.
+ It doesn't care how the rules are defined. In <a href="stage2.html" title="17.3.&nbsp;plural.py, stage 2">stage 2</a>, they were defined as seperate named functions. In <a href="stage3.html" title="17.4.&nbsp;plural.py, stage 3">stage 3</a>, they were defined as anonymous <tt class="literal">lambda</tt> functions. Now in stage 4, they are built dynamically by mapping the <tt class="function">buildMatchAndApplyFunctions</tt> function onto a list of raw strings. Doesn't matter; the <tt class="function">plural</tt> function still works the same way.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>Just in case that wasn't mind-blowing enough, I must confess that there was a subtlety in the definition of <tt class="function">buildMatchAndApplyFunctions</tt> that I skipped over. Let's go back and take another look.
+ </p>
+ <div class="example"><a name="d0e38026"></a><h3 class="title">Example&nbsp;17.13.&nbsp;Another look at <tt class="function">buildMatchAndApplyFunctions</tt></h3><pre class="programlisting"><span class='pykeyword'>
+def</span> buildMatchAndApplyFunctions((pattern, search, replace)): <a name="plural.stage4.4.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#plural.stage4.4.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Notice the double parentheses? This function doesn't actually take three parameters; it actually takes one parameter, a tuple
+ of three elements. But the tuple is expanded when the function is called, and the three elements of the tuple are each assigned
+ to different variables: <tt class="varname">pattern</tt>, <tt class="varname">search</tt>, and <tt class="varname">replace</tt>. Confused yet? Let's see it in action.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="d0e38048"></a><h3 class="title">Example&nbsp;17.14.&nbsp;Expanding tuples when calling functions</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>def</span><span class='pyclass'> foo</span>((a, b, c)):</span>
+<tt class="prompt">... </tt><span class="userinput"><span class='pykeyword'>print</span> c</span>
+<tt class="prompt">... </tt><span class="userinput"><span class='pykeyword'>print</span> b</span>
+<tt class="prompt">... </tt><span class="userinput"><span class='pykeyword'>print</span> a</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">parameters = (<span class='pystring'>'apple'</span>, <span class='pystring'>'bear'</span>, <span class='pystring'>'catnap'</span>)</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">foo(parameters)</span> <a name="plural.stage4.5.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">catnap</span>
+<span class="computeroutput">bear</span>
+<span class="computeroutput">apple</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#plural.stage4.5.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The proper way to call the function <tt class="function">foo</tt> is with a tuple of three elements. When the function is called, the elements are assigned to different local variables within
+ <tt class="function">foo</tt>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ <p>Now let's go back and see why this auto-tuple-expansion trick was necessary. <tt class="varname">patterns</tt> was a list of tuples, and each tuple had three elements. When you called <tt class="literal">map(buildMatchAndApplyFunctions, patterns)</tt>, that means that <tt class="function">buildMatchAndApplyFunctions</tt> is <span class="emphasis"><em>not</em></span> getting called with three parameters. Using <tt class="function">map</tt> to map a single list onto a function always calls the function with a single parameter: each element of the list. In the
+ case of <tt class="varname">patterns</tt>, each element of the list is a tuple, so <tt class="function">buildMatchAndApplyFunctions</tt> always gets called with the tuple, and you use the auto-tuple-expansion trick in the definition of <tt class="function">buildMatchAndApplyFunctions</tt> to assign the elements of that tuple to named variables that you can work with.
+ </p>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="stage3.html">&lt;&lt;&nbsp;plural.py, stage 3</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#plural.divein" title="17.1.&nbsp;Diving in">1</a> <span class="divider">|</span> <a href="stage1.html" title="17.2.&nbsp;plural.py, stage 1">2</a> <span class="divider">|</span> <a href="stage2.html" title="17.3.&nbsp;plural.py, stage 2">3</a> <span class="divider">|</span> <a href="stage3.html" title="17.4.&nbsp;plural.py, stage 3">4</a> <span class="divider">|</span> <span class="thispage">5</span> <span class="divider">|</span> <a href="stage5.html" title="17.6.&nbsp;plural.py, stage 5">6</a> <span class="divider">|</span> <a href="stage6.html" title="17.7.&nbsp;plural.py, stage 6">7</a> <span class="divider">|</span> <a href="summary.html" title="17.8.&nbsp;Summary">8</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="stage5.html">plural.py, stage 5&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/dynamic_functions/stage5.html b/help/diveintopython-5.4/html/dynamic_functions/stage5.html
new file mode 100644
index 0000000..f0f7c06
--- /dev/null
+++ b/help/diveintopython-5.4/html/dynamic_functions/stage5.html
@@ -0,0 +1,148 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>17.6.&nbsp;plural.py, stage 5</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;17.&nbsp;Dynamic functions">
+ <link rel="previous" href="stage4.html" title="17.5.&nbsp;plural.py, stage 4">
+ <link rel="next" href="stage6.html" title="17.7.&nbsp;plural.py, stage 6">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Dynamic functions</a>&nbsp;&gt;&nbsp;<span class="thispage">plural.py, stage 5</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="stage4.html" title="Prev: &#8220;plural.py, stage 4&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="stage6.html" title="Next: &#8220;plural.py, stage 6&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="plural.stage5"></a>17.6.&nbsp;<tt class="filename">plural.py</tt>, stage 5
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>You've factored out all the duplicate code and added enough abstractions so that the pluralization rules are defined in a
+ list of strings. The next logical step is to take these strings and put them in a separate file, where they can be maintained
+ separately from the code that uses them.
+ </p>
+ </div>
+ <p>First, let's create a text file that contains the rules you want. No fancy data structures, just space- (or tab-)delimited
+ strings in three columns. You'll call it <tt class="filename">rules.en</tt>; &#8220;<span class="quote">en</span>&#8221; stands for English. These are the rules for pluralizing English nouns. You could add other rule files for other languages
+ later.
+ </p>
+ <div class="example"><a name="d0e38148"></a><h3 class="title">Example&nbsp;17.15.&nbsp;<tt class="filename">rules.en</tt></h3><pre class="programlisting">
+[sxz]$ $ es
+[^aeioudgkprt]h$ $ es
+[^aeiou]y$ y$ ies
+$ $ s
+</pre></div>
+ <p>Now let's see how you can use this rules file.</p>
+ <div class="example"><a name="d0e38156"></a><h3 class="title">Example&nbsp;17.16.&nbsp;<tt class="filename">plural5.py</tt></h3><pre class="programlisting"><span class='pykeyword'>
+import</span> re
+<span class='pykeyword'>import</span> string
+
+<span class='pykeyword'>def</span><span class='pyclass'> buildRule</span>((pattern, search, replace)):
+ <span class='pykeyword'>return</span> <span class='pykeyword'>lambda</span> word: re.search(pattern, word) <span class='pykeyword'>and</span> re.sub(search, replace, word) <a name="plural.stage5.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+
+<span class='pykeyword'>def</span><span class='pyclass'> plural</span>(noun, language=<span class='pystring'>'en'</span>): <a name="plural.stage5.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+ lines = file(<span class='pystring'>'rules.%s'</span> % language).readlines() <a name="plural.stage5.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+ patterns = map(string.split, lines) <a name="plural.stage5.1.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+ rules = map(buildRule, patterns) <a name="plural.stage5.1.5"></a><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12">
+ <span class='pykeyword'>for</span> rule <span class='pykeyword'>in</span> rules:
+ result = rule(noun) <a name="plural.stage5.1.6"></a><img src="../images/callouts/6.png" alt="6" border="0" width="12" height="12">
+ <span class='pykeyword'>if</span> result: <span class='pykeyword'>return</span> result
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#plural.stage5.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You're still using the closures technique here (building a function dynamically that uses variables defined outside the function),
+ but now you've combined the separate match and apply functions into one. (The reason for this change will become clear in
+ the next section.) This will let you accomplish the same thing as having two functions, but you'll need to call it differently,
+ as you'll see in a minute.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#plural.stage5.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Our <tt class="function">plural</tt> function now takes an optional second parameter, <tt class="varname">language</tt>, which defaults to <tt class="literal">en</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#plural.stage5.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You use the <tt class="varname">language</tt> parameter to construct a filename, then open the file and read the contents into a list. If <tt class="varname">language</tt> is <tt class="literal">en</tt>, then you'll open the <tt class="filename">rules.en</tt> file, read the entire thing, break it up by carriage returns, and return a list. Each line of the file will be one element
+ in the list.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#plural.stage5.1.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">As you saw, each line in the file really has three values, but they're separated by whitespace (tabs or spaces, it makes no
+ difference). Mapping the <tt class="function">string.split</tt> function onto this list will create a new list where each element is a tuple of three strings. So a line like <tt class="literal">[sxz]$ $ es</tt> will be broken up into the tuple <tt class="literal">('[sxz]$', '$', 'es')</tt>. This means that <tt class="varname">patterns</tt> will end up as a list of tuples, just like you hard-coded it in <a href="stage4.html" title="17.5.&nbsp;plural.py, stage 4">stage 4</a>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#plural.stage5.1.5"><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">If <tt class="varname">patterns</tt> is a list of tuples, then <tt class="varname">rules</tt> will be a list of the functions created dynamically by each call to <tt class="function">buildRule</tt>. Calling <tt class="function">buildRule(('[sxz]$', '$', 'es'))</tt> returns a function that takes a single parameter, <tt class="varname">word</tt>. When this returned function is called, it will execute <tt class="literal">re.search('[sxz]$', word) and re.sub('$', 'es', word)</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#plural.stage5.1.6"><img src="../images/callouts/6.png" alt="6" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Because you're now building a combined match-and-apply function, you need to call it differently. Just call the function,
+ and if it returns something, then that's the plural; if it returns nothing (<tt class="literal">None</tt>), then the rule didn't match and you need to try another rule.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>So the improvement here is that you've completely separated the pluralization rules into an external file. Not only can the
+ file be maintained separately from the code, but you've set up a naming scheme where the same <tt class="function">plural</tt> function can use different rule files, based on the <tt class="varname">language</tt> parameter.
+ </p>
+ <p>The downside here is that you're reading that file every time you call the <tt class="function">plural</tt> function. I thought I could get through this entire book without using the phrase &#8220;<span class="quote">left as an exercise for the reader</span>&#8221;, but here you go: building a caching mechanism for the language-specific rule files that auto-refreshes itself if the rule
+ files change between calls <span class="emphasis"><em>is left as an exercise for the reader</em></span>. Have fun.
+ </p>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="stage4.html">&lt;&lt;&nbsp;plural.py, stage 4</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#plural.divein" title="17.1.&nbsp;Diving in">1</a> <span class="divider">|</span> <a href="stage1.html" title="17.2.&nbsp;plural.py, stage 1">2</a> <span class="divider">|</span> <a href="stage2.html" title="17.3.&nbsp;plural.py, stage 2">3</a> <span class="divider">|</span> <a href="stage3.html" title="17.4.&nbsp;plural.py, stage 3">4</a> <span class="divider">|</span> <a href="stage4.html" title="17.5.&nbsp;plural.py, stage 4">5</a> <span class="divider">|</span> <span class="thispage">6</span> <span class="divider">|</span> <a href="stage6.html" title="17.7.&nbsp;plural.py, stage 6">7</a> <span class="divider">|</span> <a href="summary.html" title="17.8.&nbsp;Summary">8</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="stage6.html">plural.py, stage 6&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/dynamic_functions/stage6.html b/help/diveintopython-5.4/html/dynamic_functions/stage6.html
new file mode 100644
index 0000000..871b160
--- /dev/null
+++ b/help/diveintopython-5.4/html/dynamic_functions/stage6.html
@@ -0,0 +1,256 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>17.7.&nbsp;plural.py, stage 6</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;17.&nbsp;Dynamic functions">
+ <link rel="previous" href="stage5.html" title="17.6.&nbsp;plural.py, stage 5">
+ <link rel="next" href="summary.html" title="17.8.&nbsp;Summary">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Dynamic functions</a>&nbsp;&gt;&nbsp;<span class="thispage">plural.py, stage 6</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="stage5.html" title="Prev: &#8220;plural.py, stage 5&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="summary.html" title="Next: &#8220;Summary&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="plural.stage6"></a>17.7.&nbsp;<tt class="filename">plural.py</tt>, stage 6
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>Now you're ready to talk about generators.</p>
+ </div>
+ <div class="example"><a name="d0e38279"></a><h3 class="title">Example&nbsp;17.17.&nbsp;<tt class="filename">plural6.py</tt></h3><pre class="programlisting"><span class='pykeyword'>
+import</span> re
+
+<span class='pykeyword'>def</span><span class='pyclass'> rules</span>(language):
+ <span class='pykeyword'>for</span> line <span class='pykeyword'>in</span> file(<span class='pystring'>'rules.%s'</span> % language):
+ pattern, search, replace = line.split()
+ <span class='pykeyword'>yield</span> <span class='pykeyword'>lambda</span> word: re.search(pattern, word) <span class='pykeyword'>and</span> re.sub(search, replace, word)
+
+<span class='pykeyword'>def</span><span class='pyclass'> plural</span>(noun, language=<span class='pystring'>'en'</span>):
+ <span class='pykeyword'>for</span> applyRule <span class='pykeyword'>in</span> rules(language):
+ result = applyRule(noun)
+ <span class='pykeyword'>if</span> result: <span class='pykeyword'>return</span> result
+</pre></div>
+ <p>This uses a technique called generators, which I'm not even going to try to explain until you look at a simpler example first.</p>
+ <div class="example"><a name="plural.introducing.generators"></a><h3 class="title">Example&nbsp;17.18.&nbsp;Introducing generators</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>def</span><span class='pyclass'> make_counter</span>(x):</span>
+<tt class="prompt">... </tt><span class="userinput"><span class='pykeyword'>print</span> <span class='pystring'>'entering make_counter'</span></span>
+<tt class="prompt">... </tt><span class="userinput"><span class='pykeyword'>while</span> 1:</span>
+<tt class="prompt">... </tt><span class="userinput"> <span class='pykeyword'>yield</span> x</span> <a name="plural.stage6.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">... </tt><span class="userinput"> <span class='pykeyword'>print</span> <span class='pystring'>'incrementing x'</span></span>
+<tt class="prompt">... </tt><span class="userinput"> x = x + 1</span>
+<tt class="prompt">... </tt>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">counter = make_counter(2)</span> <a name="plural.stage6.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">counter</span> <a name="plural.stage6.2.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">&lt;generator object at 0x001C9C10&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">counter.next()</span> <a name="plural.stage6.2.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">entering make_counter
+2</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">counter.next()</span> <a name="plural.stage6.2.5"></a><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12">
+<span class="computeroutput">incrementing x
+3</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">counter.next()</span> <a name="plural.stage6.2.6"></a><img src="../images/callouts/6.png" alt="6" border="0" width="12" height="12">
+<span class="computeroutput">incrementing x
+4</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#plural.stage6.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The presence of the <tt class="literal">yield</tt> keyword in <tt class="function">make_counter</tt> means that this is not a normal function. It is a special kind of function which generates values one at a time. You can
+ think of it as a resumable function. Calling it will return a generator that can be used to generate successive values of
+ <tt class="varname">x</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#plural.stage6.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">To create an instance of the <tt class="function">make_counter</tt> generator, just call it like any other function. Note that this does not actually execute the function code. You can tell
+ this because the first line of <tt class="function">make_counter</tt> is a <tt class="function">print</tt> statement, but nothing has been printed yet.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#plural.stage6.2.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="function">make_counter</tt> function returns a generator object.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#plural.stage6.2.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The first time you call the <tt class="function">next()</tt> method on the generator object, it executes the code in <tt class="function">make_counter</tt> up to the first <tt class="literal">yield</tt> statement, and then returns the value that was yielded. In this case, that will be <tt class="literal">2</tt>, because you originally created the generator by calling <tt class="function">make_counter(2)</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#plural.stage6.2.5"><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Repeatedly calling <tt class="function">next()</tt> on the generator object <span class="emphasis"><em>resumes where you left off</em></span> and continues until you hit the next <tt class="literal">yield</tt> statement. The next line of code waiting to be executed is the <tt class="function">print</tt> statement that prints <tt class="literal">incrementing x</tt>, and then after that the <tt class="literal">x = x + 1</tt> statement that actually increments it. Then you loop through the <tt class="literal">while</tt> loop again, and the first thing you do is <tt class="literal">yield x</tt>, which returns the current value of <tt class="varname">x</tt> (now 3).
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#plural.stage6.2.6"><img src="../images/callouts/6.png" alt="6" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The second time you call <tt class="function">counter.next()</tt>, you do all the same things again, but this time <tt class="varname">x</tt> is now <tt class="literal">4</tt>. And so forth. Since <tt class="function">make_counter</tt> sets up an infinite loop, you could theoretically do this forever, and it would just keep incrementing <tt class="varname">x</tt> and spitting out values. But let's look at more productive uses of generators instead.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="plural.fib.example"></a><h3 class="title">Example&nbsp;17.19.&nbsp;Using generators instead of recursion</h3><pre class="programlisting"><span class='pykeyword'>
+def</span> fibonacci(max):
+ a, b = 0, 1 <a name="plural.stage6.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ <span class='pykeyword'>while</span> a &lt; max:
+ <span class='pykeyword'>yield</span> a <a name="plural.stage6.3.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+ a, b = b, a+b <a name="plural.stage6.3.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#plural.stage6.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The Fibonacci sequence is a sequence of numbers where each number is the sum of the two numbers before it. It starts with
+ <tt class="constant">0</tt> and <tt class="constant">1</tt>, goes up slowly at first, then more and more rapidly. To start the sequence, you need two variables: <tt class="varname">a</tt> starts at <tt class="constant">0</tt>, and <tt class="varname">b</tt> starts at <tt class="constant">1</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#plural.stage6.3.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="varname">a</tt> is the current number in the sequence, so yield it.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#plural.stage6.3.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="varname">b</tt> is the next number in the sequence, so assign that to <tt class="varname">a</tt>, but also calculate the next value (<tt class="literal">a+b</tt>) and assign that to <tt class="varname">b</tt> for later use. Note that this happens in parallel; if <tt class="varname">a</tt> is <tt class="literal">3</tt> and <tt class="varname">b</tt> is <tt class="literal">5</tt>, then <tt class="literal">a, b = b, a+b</tt> will set <tt class="varname">a</tt> to <tt class="literal">5</tt> (the previous value of <tt class="varname">b</tt>) and <tt class="varname">b</tt> to <tt class="literal">8</tt> (the sum of the previous values of <tt class="varname">a</tt> and <tt class="varname">b</tt>).
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>So you have a function that spits out successive Fibonacci numbers. Sure, you could do that with recursion, but this way
+ is easier to read. Also, it works well with <tt class="literal">for</tt> loops.
+ </p>
+ <div class="example"><a name="d0e38564"></a><h3 class="title">Example&nbsp;17.20.&nbsp;Generators in <tt class="literal">for</tt> loops
+ </h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>for</span> n <span class='pykeyword'>in</span> fibonacci(1000):</span> <a name="plural.stage6.4.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">... </tt><span class="userinput"><span class='pykeyword'>print</span> n,</span> <a name="plural.stage6.4.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#plural.stage6.4.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You can use a generator like <tt class="function">fibonacci</tt> in a <tt class="literal">for</tt> loop directly. The <tt class="literal">for</tt> loop will create the generator object and successively call the <tt class="function">next()</tt> method to get values to assign to the <tt class="literal">for</tt> loop index variable (<tt class="varname">n</tt>).
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#plural.stage6.4.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Each time through the <tt class="literal">for</tt> loop, <tt class="varname">n</tt> gets a new value from the <tt class="literal">yield</tt> statement in <tt class="function">fibonacci</tt>, and all you do is print it out. Once <tt class="function">fibonacci</tt> runs out of numbers (<tt class="varname">a</tt> gets bigger than <tt class="varname">max</tt>, which in this case is <tt class="literal">1000</tt>), then the <tt class="literal">for</tt> loop exits gracefully.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>OK, let's go back to the <tt class="function">plural</tt> function and see how you're using this.
+ </p>
+ <div class="example"><a name="d0e38646"></a><h3 class="title">Example&nbsp;17.21.&nbsp;Generators that generate dynamic functions</h3><pre class="programlisting"><span class='pykeyword'>
+def</span> rules(language):
+ <span class='pykeyword'>for</span> line <span class='pykeyword'>in</span> file(<span class='pystring'>'rules.%s'</span> % language): <a name="plural.stage6.5.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ pattern, search, replace = line.split() <a name="plural.stage6.5.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+ <span class='pykeyword'>yield</span> <span class='pykeyword'>lambda</span> word: re.search(pattern, word) <span class='pykeyword'>and</span> re.sub(search, replace, word) <a name="plural.stage6.5.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+
+<span class='pykeyword'>def</span><span class='pyclass'> plural</span>(noun, language=<span class='pystring'>'en'</span>):
+ <span class='pykeyword'>for</span> applyRule <span class='pykeyword'>in</span> rules(language): <a name="plural.stage6.5.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+ result = applyRule(noun)
+ <span class='pykeyword'>if</span> result: <span class='pykeyword'>return</span> result
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#plural.stage6.5.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="literal">for line in file(...)</tt> is a common idiom for reading lines from a file, one line at a time. It works because <span class="emphasis"><em><tt class="function">file</tt> actually returns a generator</em></span> whose <tt class="function">next()</tt> method returns the next line of the file. That is so insanely cool, I wet myself just thinking about it.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#plural.stage6.5.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">No magic here. Remember that the lines of the rules file have three values separated by whitespace, so <tt class="literal">line.split()</tt> returns a tuple of 3 values, and you assign those values to 3 local variables.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#plural.stage6.5.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><span class="emphasis"><em>And then you yield.</em></span> What do you yield? A function, built dynamically with <tt class="literal">lambda</tt>, that is actually a closure (it uses the local variables <tt class="varname">pattern</tt>, <tt class="varname">search</tt>, and <tt class="varname">replace</tt> as constants). In other words, <tt class="function">rules</tt> is a generator that spits out rule functions.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#plural.stage6.5.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Since <tt class="function">rules</tt> is a generator, you can use it directly in a <tt class="literal">for</tt> loop. The first time through the <tt class="literal">for</tt> loop, you will call the <tt class="function">rules</tt> function, which will open the rules file, read the first line out of it, dynamically build a function that matches and applies
+ the first rule defined in the rules file, and yields the dynamically built function. The second time through the <tt class="literal">for</tt> loop, you will pick up where you left off in <tt class="function">rules</tt> (which was in the middle of the <tt class="literal">for line in file(...)</tt> loop), read the second line of the rules file, dynamically build another function that matches and applies the second rule
+ defined in the rules file, and yields it. And so forth.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>What have you gained over <a href="stage5.html" title="17.6.&nbsp;plural.py, stage 5">stage 5</a>? In stage 5, you read the entire rules file and built a list of all the possible rules before you even tried the first one.
+ Now with generators, you can do everything lazily: you open the first and read the first rule and create a function to try
+ it, but if that works you don't ever read the rest of the file or create any other functions.
+ </p>
+ <div class="furtherreading">
+ <h3>Further reading</h3>
+ <ul>
+ <li><a href="http://www.python.org/peps/pep-0255.html">PEP 255</a> defines generators.
+ </li>
+ <li><a href="http://www.activestate.com/ASPN/Python/Cookbook/" title="growing archive of annotated code samples"><span class="application">Python</span> Cookbook</a> has <a href="http://www.google.com/search?q=generators+cookbook+site:aspn.activestate.com">many more examples of generators</a>.
+ </li>
+ </ul>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="stage5.html">&lt;&lt;&nbsp;plural.py, stage 5</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#plural.divein" title="17.1.&nbsp;Diving in">1</a> <span class="divider">|</span> <a href="stage1.html" title="17.2.&nbsp;plural.py, stage 1">2</a> <span class="divider">|</span> <a href="stage2.html" title="17.3.&nbsp;plural.py, stage 2">3</a> <span class="divider">|</span> <a href="stage3.html" title="17.4.&nbsp;plural.py, stage 3">4</a> <span class="divider">|</span> <a href="stage4.html" title="17.5.&nbsp;plural.py, stage 4">5</a> <span class="divider">|</span> <a href="stage5.html" title="17.6.&nbsp;plural.py, stage 5">6</a> <span class="divider">|</span> <span class="thispage">7</span> <span class="divider">|</span> <a href="summary.html" title="17.8.&nbsp;Summary">8</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="summary.html">Summary&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/dynamic_functions/summary.html b/help/diveintopython-5.4/html/dynamic_functions/summary.html
new file mode 100644
index 0000000..9dcf7cb
--- /dev/null
+++ b/help/diveintopython-5.4/html/dynamic_functions/summary.html
@@ -0,0 +1,86 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>17.8.&nbsp;Summary</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;17.&nbsp;Dynamic functions">
+ <link rel="previous" href="stage6.html" title="17.7.&nbsp;plural.py, stage 6">
+ <link rel="next" href="../performance_tuning/index.html" title="Chapter&nbsp;18.&nbsp;Performance Tuning">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Dynamic functions</a>&nbsp;&gt;&nbsp;<span class="thispage">Summary</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="stage6.html" title="Prev: &#8220;plural.py, stage 6&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="../performance_tuning/index.html" title="Next: &#8220;Performance Tuning&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="plural.summary"></a>17.8.&nbsp;Summary
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>You talked about several different advanced techniques in this chapter. Not all of them are appropriate for every situation.</p>
+ </div>
+ <p>You should now be comfortable with all of these techniques:</p>
+ <div class="itemizedlist">
+ <ul>
+ <li>Performing <a href="stage1.html" title="17.2.&nbsp;plural.py, stage 1">string substitution with regular expressions</a>.
+ </li>
+ <li>Treating <a href="stage2.html" title="17.3.&nbsp;plural.py, stage 2">functions as objects</a>, storing them in lists, assigning them to variables, and calling them through those variables.
+ </li>
+ <li>Building <a href="stage3.html" title="17.4.&nbsp;plural.py, stage 3">dynamic functions with <tt class="literal">lambda</tt></a>.
+ </li>
+ <li>Building <a href="stage4.html" title="17.5.&nbsp;plural.py, stage 4">closures</a>, dynamic functions that contain surrounding variables as constants.
+ </li>
+ <li>Building <a href="stage6.html" title="17.7.&nbsp;plural.py, stage 6">generators</a>, resumable functions that perform incremental logic and return different values each time you call them.
+ </li>
+ </ul>
+ </div>
+ <p>Adding abstractions, building functions dynamically, building closures, and using generators can all make your code simpler,
+ more readable, and more flexible. But they can also end up making it more difficult to debug later. It's up to you to find
+ the right balance between simplicity and power.
+ </p>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="stage6.html">&lt;&lt;&nbsp;plural.py, stage 6</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#plural.divein" title="17.1.&nbsp;Diving in">1</a> <span class="divider">|</span> <a href="stage1.html" title="17.2.&nbsp;plural.py, stage 1">2</a> <span class="divider">|</span> <a href="stage2.html" title="17.3.&nbsp;plural.py, stage 2">3</a> <span class="divider">|</span> <a href="stage3.html" title="17.4.&nbsp;plural.py, stage 3">4</a> <span class="divider">|</span> <a href="stage4.html" title="17.5.&nbsp;plural.py, stage 4">5</a> <span class="divider">|</span> <a href="stage5.html" title="17.6.&nbsp;plural.py, stage 5">6</a> <span class="divider">|</span> <a href="stage6.html" title="17.7.&nbsp;plural.py, stage 6">7</a> <span class="divider">|</span> <span class="thispage">8</span>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="../performance_tuning/index.html">Performance Tuning&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/file_handling/all_together.html b/help/diveintopython-5.4/html/file_handling/all_together.html
new file mode 100644
index 0000000..9f86f16
--- /dev/null
+++ b/help/diveintopython-5.4/html/file_handling/all_together.html
@@ -0,0 +1,132 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>6.6.&nbsp;Putting It All Together</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;6.&nbsp;Exceptions and File Handling">
+ <link rel="previous" href="os_module.html" title="6.5.&nbsp;Working with Directories">
+ <link rel="next" href="summary.html" title="6.7.&nbsp;Summary">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Exceptions and File Handling</a>&nbsp;&gt;&nbsp;<span class="thispage">Putting It All Together</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="os_module.html" title="Prev: &#8220;Working with Directories&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="summary.html" title="Next: &#8220;Summary&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="fileinfo.alltogether"></a>6.6.&nbsp;Putting It All Together
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>Once again, all the dominoes are in place. You've seen how each line of code works. Now let's step back and see how it all
+ fits together.
+ </p>
+ </div>
+ <div class="example"><a name="fileinfo.nested"></a><h3 class="title">Example&nbsp;6.21.&nbsp;<tt class="function">listDirectory</tt></h3><pre class="programlisting"><span class='pykeyword'>
+def</span> listDirectory(directory, fileExtList): <a name="fileinfo.alltogether.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ <span class='pystring'>"get list of file info objects for files of particular extensions"</span>
+ fileList = [os.path.normcase(f)
+ <span class='pykeyword'>for</span> f <span class='pykeyword'>in</span> os.listdir(directory)]
+ fileList = [os.path.join(directory, f)
+ <span class='pykeyword'>for</span> f <span class='pykeyword'>in</span> fileList
+ <span class='pykeyword'>if</span> os.path.splitext(f)[1] <span class='pykeyword'>in</span> fileExtList] <a name="fileinfo.alltogether.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+ <span class='pykeyword'>def</span><span class='pyclass'> getFileInfoClass</span>(filename, module=sys.modules[FileInfo.__module__]): <a name="fileinfo.alltogether.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+ <span class='pystring'>"get file info class from filename extension"</span>
+ subclass = <span class='pystring'>"%sFileInfo"</span> % os.path.splitext(filename)[1].upper()[1:] <a name="fileinfo.alltogether.1.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+ <span class='pykeyword'>return</span> hasattr(module, subclass) <span class='pykeyword'>and</span> getattr(module, subclass) <span class='pykeyword'>or</span> FileInfo <a name="fileinfo.alltogether.1.5"></a><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12">
+ <span class='pykeyword'>return</span> [getFileInfoClass(f)(f) <span class='pykeyword'>for</span> f <span class='pykeyword'>in</span> fileList] <a name="fileinfo.alltogether.1.6"></a><img src="../images/callouts/6.png" alt="6" border="0" width="12" height="12"></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.alltogether.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">listDirectory</tt> is the main attraction of this entire module. It takes a directory (like <tt class="filename">c:\music\_singles\</tt> in my case) and a list of interesting file extensions (like <tt class="literal">['.mp3']</tt>), and it returns a list of class instances that act like dictionaries that contain metadata about each interesting file in
+ that directory. And it does it in just a few straightforward lines of code.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.alltogether.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">As you saw in the <a href="os_module.html" title="6.5.&nbsp;Working with Directories">previous section</a>, this line of code gets a list of the full pathnames of all the files in <tt class="varname">directory</tt> that have an interesting file extension (as specified by <tt class="varname">fileExtList</tt>).
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.alltogether.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Old-school <span class="application">Pascal</span> programmers may be familiar with them, but most people give me a blank stare when I tell them that <span class="application">Python</span> supports <span class="emphasis"><em>nested functions</em></span> -- literally, a function within a function. The nested function <tt class="function">getFileInfoClass</tt> can be called only from the function in which it is defined, <tt class="function">listDirectory</tt>. As with any other function, you don't need an interface declaration or anything fancy; just define the function and code
+ it.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.alltogether.1.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Now that you've seen the <a href="os_module.html" title="6.5.&nbsp;Working with Directories"><tt class="filename">os</tt></a> module, this line should make more sense. It gets the extension of the file (<tt class="literal">os.path.splitext(filename)[1]</tt>), forces it to uppercase (<tt class="literal">.upper()</tt>), slices off the dot (<tt class="literal">[1:]</tt>), and constructs a class name out of it with string formatting. So <tt class="filename">c:\music\ap\mahadeva.mp3</tt> becomes <tt class="literal">.mp3</tt> becomes <tt class="literal">.MP3</tt> becomes <tt class="literal">MP3</tt> becomes <tt class="literal">MP3FileInfo</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.alltogether.1.5"><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Having constructed the name of the handler class that would handle this file, you check to see if that handler class actually
+ exists in this module. If it does, you return the class, otherwise you return the base class <tt class="classname">FileInfo</tt>. This is a very important point: <span class="emphasis"><em>this function returns a class</em></span>. Not an instance of a class, but the class itself.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.alltogether.1.6"><img src="../images/callouts/6.png" alt="6" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">For each file in the &#8220;<span class="quote">interesting files</span>&#8221; list (<tt class="varname">fileList</tt>), you call <tt class="function">getFileInfoClass</tt> with the filename (<tt class="varname">f</tt>). Calling <tt class="literal">getFileInfoClass(f)</tt> returns a class; you don't know exactly which class, but you don't care. You then create an instance of this class (whatever
+ it is) and pass the filename (<tt class="varname">f</tt> again), to the <tt class="function">__init__</tt> method. As you saw <a href="../object_oriented_framework/special_class_methods.html#fileinfo.specialmethods.setname" title="Example&nbsp;5.15.&nbsp;Setting an MP3FileInfo's name">earlier in this chapter</a>, the <tt class="function">__init__</tt> method of <tt class="classname">FileInfo</tt> sets <tt class="literal">self["name"]</tt>, which triggers <tt class="function">__setitem__</tt>, which is overridden in the descendant (<tt class="classname">MP3FileInfo</tt>) to parse the file appropriately to pull out the file's metadata. You do all that for each interesting file and return a
+ list of the resulting instances.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>Note that <tt class="function">listDirectory</tt> is completely generic. It doesn't know ahead of time which types of files it will be getting, or which classes are defined
+ that could potentially handle those files. It inspects the directory for the files to process, and then introspects its own
+ module to see what special handler classes (like <tt class="classname">MP3FileInfo</tt>) are defined. You can extend this program to handle other types of files simply by defining an appropriately-named class:
+ <tt class="classname">HTMLFileInfo</tt> for <span class="acronym">HTML</span> files, <tt class="classname">DOCFileInfo</tt> for <span class="application">Word</span> <tt class="literal">.doc</tt> files, and so forth. <tt class="function">listDirectory</tt> will handle them all, without modification, by handing off the real work to the appropriate classes and collating the results.
+ </p>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="os_module.html">&lt;&lt;&nbsp;Working with Directories</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#fileinfo.exception" title="6.1.&nbsp;Handling Exceptions">1</a> <span class="divider">|</span> <a href="file_objects.html" title="6.2.&nbsp;Working with File Objects">2</a> <span class="divider">|</span> <a href="for_loops.html" title="6.3.&nbsp;Iterating with for Loops">3</a> <span class="divider">|</span> <a href="more_on_modules.html" title="6.4.&nbsp;Using sys.modules">4</a> <span class="divider">|</span> <a href="os_module.html" title="6.5.&nbsp;Working with Directories">5</a> <span class="divider">|</span> <span class="thispage">6</span> <span class="divider">|</span> <a href="summary.html" title="6.7.&nbsp;Summary">7</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="summary.html">Summary&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/file_handling/file_objects.html b/help/diveintopython-5.4/html/file_handling/file_objects.html
new file mode 100644
index 0000000..b75d626
--- /dev/null
+++ b/help/diveintopython-5.4/html/file_handling/file_objects.html
@@ -0,0 +1,403 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>6.2.&nbsp;Working with File Objects</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;6.&nbsp;Exceptions and File Handling">
+ <link rel="previous" href="index.html" title="Chapter&nbsp;6.&nbsp;Exceptions and File Handling">
+ <link rel="next" href="for_loops.html" title="6.3.&nbsp;Iterating with for Loops">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Exceptions and File Handling</a>&nbsp;&gt;&nbsp;<span class="thispage">Working with File Objects</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="index.html" title="Prev: &#8220;Exceptions and File Handling&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="for_loops.html" title="Next: &#8220;Iterating with for Loops&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="fileinfo.files"></a>6.2.&nbsp;Working with File Objects
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="toc">
+ <ul>
+ <li><span class="section"><a href="file_objects.html#d0e14670">6.2.1. Reading Files</a></span></li>
+ <li><span class="section"><a href="file_objects.html#d0e14800">6.2.2. Closing Files</a></span></li>
+ <li><span class="section"><a href="file_objects.html#d0e14928">6.2.3. Handling I/O Errors</a></span></li>
+ <li><span class="section"><a href="file_objects.html#d0e15055">6.2.4. Writing to Files</a></span></li>
+ </ul>
+ </div>
+ <div class="abstract">
+ <p><span class="application">Python</span> has a built-in function, <tt class="function">open</tt>, for opening a file on disk. <tt class="function">open</tt> returns a file object, which has methods and attributes for getting information about and manipulating the opened file.
+ </p>
+ </div>
+ <div class="example"><a name="d0e14596"></a><h3 class="title">Example&nbsp;6.3.&nbsp;Opening a File</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">f = open(<span class='pystring'>"/music/_singles/kairo.mp3"</span>, <span class='pystring'>"rb"</span>)</span> <a name="fileinfo.files.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">f</span> <a name="fileinfo.files.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">&lt;open file '/music/_singles/kairo.mp3', mode 'rb' at 010E3988&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">f.mode</span> <a name="fileinfo.files.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">'rb'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">f.name</span> <a name="fileinfo.files.1.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">'/music/_singles/kairo.mp3'</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.files.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="function">open</tt> method can take up to three parameters: a filename, a mode, and a buffering parameter. Only the first one, the filename,
+ is required; the other two are <a href="../power_of_introspection/optional_arguments.html" title="4.2.&nbsp;Using Optional and Named Arguments">optional</a>. If not specified, the file is opened for reading in text mode. Here you are opening the file for reading in binary mode.
+ (<tt class="literal">print open.__doc__</tt> displays a great explanation of all the possible modes.)
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.files.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="function">open</tt> function returns an object (by now, <a href="../getting_to_know_python/everything_is_an_object.html" title="2.4.&nbsp;Everything Is an Object">this should not surprise you</a>). A file object has several useful attributes.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.files.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="varname">mode</tt> attribute of a file object tells you in which mode the file was opened.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.files.1.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="varname">name</tt> attribute of a file object tells you the name of the file that the file object has open.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e14670"></a>6.2.1.&nbsp;Reading Files
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p>After you open a file, the first thing you'll want to do is read from it, as shown in the next example.</p>
+ <div class="example"><a name="d0e14675"></a><h3 class="title">Example&nbsp;6.4.&nbsp;Reading a File</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">f</span>
+<span class="computeroutput">&lt;open file '/music/_singles/kairo.mp3', mode 'rb' at 010E3988&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">f.tell()</span> <a name="fileinfo.files.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">0</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">f.seek(-128, 2)</span> <a name="fileinfo.files.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">f.tell()</span> <a name="fileinfo.files.2.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">7542909</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">tagData = f.read(128)</span> <a name="fileinfo.files.2.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">tagData</span>
+<span class="computeroutput">'TAGKAIRO****THE BEST GOA ***DJ MARY-JANE***
+Rave Mix 2000http://mp3.com/DJMARYJANE \037'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">f.tell()</span> <a name="fileinfo.files.2.5"></a><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12">
+<span class="computeroutput">7543037</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.files.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">A file object maintains state about the file it has open. The <tt class="function">tell</tt> method of a file object tells you your current position in the open file. Since you haven't done anything with this file
+ yet, the current position is <tt class="constant">0</tt>, which is the beginning of the file.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.files.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="function">seek</tt> method of a file object moves to another position in the open file. The second parameter specifies what the first one means;
+ <tt class="constant">0</tt> means move to an absolute position (counting from the start of the file), <tt class="constant">1</tt> means move to a relative position (counting from the current position), and <tt class="literal">2</tt> means move to a position relative to the end of the file. Since the <span class="abbrev">MP3</span> tags you're looking for are stored at the end of the file, you use <tt class="literal">2</tt> and tell the file object to move to a position <tt class="literal">128</tt> bytes from the end of the file.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.files.2.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="function">tell</tt> method confirms that the current file position has moved.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.files.2.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="function">read</tt> method reads a specified number of bytes from the open file and returns a string with the data that was read. The optional
+ parameter specifies the maximum number of bytes to read. If no parameter is specified, <tt class="function">read</tt> will read until the end of the file. (You could have simply said <tt class="literal">read()</tt> here, since you know exactly where you are in the file and you are, in fact, reading the last 128 bytes.) The read data
+ is assigned to the <tt class="varname">tagData</tt> variable, and the current position is updated based on how many bytes were read.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.files.2.5"><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="function">tell</tt> method confirms that the current position has moved. If you do the math, you'll see that after reading 128 bytes, the position
+ has been incremented by 128.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e14800"></a>6.2.2.&nbsp;Closing Files
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p>Open files consume system resources, and depending on the file mode, other programs may not be able to access them. It's
+ important to close files as soon as you're finished with them.
+ </p>
+ <div class="example"><a name="d0e14805"></a><h3 class="title">Example&nbsp;6.5.&nbsp;Closing a File</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">f</span>
+<span class="computeroutput">&lt;open file '/music/_singles/kairo.mp3', mode 'rb' at 010E3988&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">f.closed</span> <a name="fileinfo.files.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">False</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">f.close()</span> <a name="fileinfo.files.3.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">f</span>
+<span class="computeroutput">&lt;closed file '/music/_singles/kairo.mp3', mode 'rb' at 010E3988&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">f.closed</span> <a name="fileinfo.files.3.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">True</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">f.seek(0)</span> <a name="fileinfo.files.3.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="traceback">Traceback (innermost last):
+ File "&lt;interactive input&gt;", line 1, in ?
+ValueError: I/O operation on closed file</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">f.tell()</span>
+<span class="traceback">Traceback (innermost last):
+ File "&lt;interactive input&gt;", line 1, in ?
+ValueError: I/O operation on closed file</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">f.read()</span>
+<span class="traceback">Traceback (innermost last):
+ File "&lt;interactive input&gt;", line 1, in ?
+ValueError: I/O operation on closed file</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">f.close()</span> <a name="fileinfo.files.3.5"></a><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12"></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.files.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="varname">closed</tt> attribute of a file object indicates whether the object has a file open or not. In this case, the file is still open (<tt class="varname">closed</tt> is <tt class="constant">False</tt>).
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.files.3.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">To close a file, call the <tt class="function">close</tt> method of the file object. This frees the lock (if any) that you were holding on the file, flushes buffered writes (if any)
+ that the system hadn't gotten around to actually writing yet, and releases the system resources.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.files.3.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="varname">closed</tt> attribute confirms that the file is closed.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.files.3.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Just because a file is closed doesn't mean that the file object ceases to exist. The variable <tt class="varname">f</tt> will continue to exist until it <a href="../object_oriented_framework/instantiating_classes.html#fileinfo.scope" title="Example&nbsp;5.8.&nbsp;Trying to Implement a Memory Leak">goes out of scope</a> or gets manually deleted. However, none of the methods that manipulate an open file will work once the file has been closed;
+ they all raise an exception.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.files.3.5"><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Calling <tt class="function">close</tt> on a file object whose file is already closed does <span class="emphasis"><em>not</em></span> raise an exception; it fails silently.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e14928"></a>6.2.3.&nbsp;Handling <span class="acronym">I/O</span> Errors
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p>Now you've seen enough to understand the file handling code in the <tt class="filename">fileinfo.py</tt> sample code from teh previous chapter. This example shows how to safely open and read from a file and gracefully handle
+ errors.
+ </p>
+ <div class="example"><a name="fileinfo.files.incode"></a><h3 class="title">Example&nbsp;6.6.&nbsp;File Objects in <tt class="classname">MP3FileInfo</tt></h3><pre class="programlisting">
+ <span class='pykeyword'>try</span>: <a name="fileinfo.files.4.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ fsock = open(filename, <span class='pystring'>"rb"</span>, 0) <a name="fileinfo.files.4.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+ <span class='pykeyword'>try</span>:
+ fsock.seek(-128, 2) <a name="fileinfo.files.4.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+ tagdata = fsock.read(128) <a name="fileinfo.files.4.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+ <span class='pykeyword'>finally</span>: <a name="fileinfo.files.4.5"></a><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12">
+ fsock.close()
+ .
+ .
+ .
+ <span class='pykeyword'>except</span> IOError: <a name="fileinfo.files.4.6"></a><img src="../images/callouts/6.png" alt="6" border="0" width="12" height="12">
+ <span class='pykeyword'>pass</span> </pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.files.4.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Because opening and reading files is risky and may raise an exception, all of this code is wrapped in a <tt class="literal">try...except</tt> block. (Hey, isn't <a href="../getting_to_know_python/indenting_code.html" title="2.5.&nbsp;Indenting Code">standardized indentation</a> great? This is where you start to appreciate it.)
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.files.4.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="function">open</tt> function may raise an <tt class="errorcode">IOError</tt>. (Maybe the file doesn't exist.)
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.files.4.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="function">seek</tt> method may raise an <tt class="errorcode">IOError</tt>. (Maybe the file is smaller than 128 bytes.)
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.files.4.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="function">read</tt> method may raise an <tt class="errorcode">IOError</tt>. (Maybe the disk has a bad sector, or it's on a network drive and the network just went down.)
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.files.4.5"><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This is new: a <tt class="literal">try...finally</tt> block. Once the file has been opened successfully by the <tt class="function">open</tt> function, you want to make absolutely sure that you close it, even if an exception is raised by the <tt class="function">seek</tt> or <tt class="function">read</tt> methods. That's what a <tt class="literal">try...finally</tt> block is for: code in the <tt class="literal">finally</tt> block will <span class="emphasis"><em>always</em></span> be executed, even if something in the <tt class="literal">try</tt> block raises an exception. Think of it as code that gets executed on the way out, regardless of what happened before.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.files.4.6"><img src="../images/callouts/6.png" alt="6" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">At last, you handle your <tt class="errorcode">IOError</tt> exception. This could be the <tt class="errorcode">IOError</tt> exception raised by the call to <tt class="function">open</tt>, <tt class="function">seek</tt>, or <tt class="function">read</tt>. Here, you really don't care, because all you're going to do is ignore it silently and continue. (Remember, <tt class="literal">pass</tt> is a <span class="application">Python</span> statement that <a href="../object_oriented_framework/defining_classes.html#fileinfo.class.simplest" title="Example&nbsp;5.3.&nbsp;The Simplest Python Class">does nothing</a>.) That's perfectly legal; &#8220;<span class="quote">handling</span>&#8221; an exception can mean explicitly doing nothing. It still counts as handled, and processing will continue normally on the
+ next line of code after the <tt class="literal">try...except</tt> block.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e15055"></a>6.2.4.&nbsp;Writing to Files
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p>As you would expect, you can also write to files in much the same way that you read from them. There are two basic file modes:</p>
+ <div class="itemizedlist">
+ <ul>
+ <li>"Append" mode will add data to the end of the file.</li>
+ <li>"write" mode will overwrite the file.</li>
+ </ul>
+ </div>
+ <p>Either mode will create the file automatically if it doesn't already exist, so there's never a need for any sort of fiddly
+ "if the log file doesn't exist yet, create a new empty file just so you can open it for the first time" logic. Just open
+ it and start writing.
+ </p>
+ <div class="example"><a name="fileinfo.files.writeandappend"></a><h3 class="title">Example&nbsp;6.7.&nbsp;Writing to Files</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">logfile = open(<span class='pystring'>'test.log'</span>, <span class='pystring'>'w'</span>)</span> <a name="fileinfo.files.5.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">logfile.write(<span class='pystring'>'test succeeded'</span>)</span> <a name="fileinfo.files.5.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">logfile.close()</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> file(<span class='pystring'>'test.log'</span>).read()</span> <a name="fileinfo.files.5.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">test succeeded</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">logfile = open(<span class='pystring'>'test.log'</span>, <span class='pystring'>'a'</span>)</span> <a name="fileinfo.files.5.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">logfile.write(<span class='pystring'>'line 2'</span>)</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">logfile.close()</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> file(<span class='pystring'>'test.log'</span>).read()</span> <a name="fileinfo.files.5.5"></a><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12">
+<span class="computeroutput">test succeededline 2</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.files.5.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You start boldly by creating either the new file <tt class="filename">test.log</tt> or overwrites the existing file, and opening the file for writing. (The second parameter <tt class="literal">"w"</tt> means open the file for writing.) Yes, that's all as dangerous as it sounds. I hope you didn't care about the previous
+ contents of that file, because it's gone now.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.files.5.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You can add data to the newly opened file with the <tt class="function">write</tt> method of the file object returned by <tt class="function">open</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.files.5.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">file</tt> is a synonym for <tt class="function">open</tt>. This one-liner opens the file, reads its contents, and prints them.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.files.5.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You happen to know that <tt class="filename">test.log</tt> exists (since you just finished writing to it), so you can open it and append to it. (The <tt class="literal">"a"</tt> parameter means open the file for appending.) Actually you could do this even if the file didn't exist, because opening
+ the file for appending will create the file if necessary. But appending will <span class="emphasis"><em>never</em></span> harm the existing contents of the file.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.files.5.5"><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">As you can see, both the original line you wrote and the second line you appended are now in <tt class="filename">test.log</tt>. Also note that carriage returns are not included. Since you didn't write them explicitly to the file either time, the
+ file doesn't include them. You can write a carriage return with the <tt class="literal">"\n"</tt> character. Since you didn't do this, everything you wrote to the file ended up smooshed together on the same line.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="furtherreading">
+ <h3>Further Reading on File Handling</h3>
+ <ul>
+ <li><a href="http://www.python.org/doc/current/tut/tut.html"><i class="citetitle"><span class="application">Python</span> Tutorial</i></a> discusses reading and writing files, including how to <a href="http://www.python.org/doc/current/tut/node9.html#SECTION009210000000000000000">read a file one line at a time into a list</a>.
+ </li>
+ <li><a href="http://www.effbot.org/guides/">eff-bot</a> discusses efficiency and performance of <a href="http://www.effbot.org/guides/readline-performance.htm">various ways of reading a file</a>.
+ </li>
+ <li><a href="http://www.faqts.com/knowledge-base/index.phtml/fid/199/"><span class="application">Python</span> Knowledge Base</a> answers <a href="http://www.faqts.com/knowledge-base/index.phtml/fid/552">common questions about files</a>.
+ </li>
+ <li><a href="http://www.python.org/doc/current/lib/"><i class="citetitle"><span class="application">Python</span> Library Reference</i></a> summarizes <a href="http://www.python.org/doc/current/lib/bltin-file-objects.html">all the file object methods</a>.
+ </li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="index.html">&lt;&lt;&nbsp;Exceptions and File Handling</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#fileinfo.exception" title="6.1.&nbsp;Handling Exceptions">1</a> <span class="divider">|</span> <span class="thispage">2</span> <span class="divider">|</span> <a href="for_loops.html" title="6.3.&nbsp;Iterating with for Loops">3</a> <span class="divider">|</span> <a href="more_on_modules.html" title="6.4.&nbsp;Using sys.modules">4</a> <span class="divider">|</span> <a href="os_module.html" title="6.5.&nbsp;Working with Directories">5</a> <span class="divider">|</span> <a href="all_together.html" title="6.6.&nbsp;Putting It All Together">6</a> <span class="divider">|</span> <a href="summary.html" title="6.7.&nbsp;Summary">7</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="for_loops.html">Iterating with for Loops&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/file_handling/for_loops.html b/help/diveintopython-5.4/html/file_handling/for_loops.html
new file mode 100644
index 0000000..2b37b3d
--- /dev/null
+++ b/help/diveintopython-5.4/html/file_handling/for_loops.html
@@ -0,0 +1,224 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>6.3.&nbsp;Iterating with for Loops</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;6.&nbsp;Exceptions and File Handling">
+ <link rel="previous" href="file_objects.html" title="6.2.&nbsp;Working with File Objects">
+ <link rel="next" href="more_on_modules.html" title="6.4.&nbsp;Using sys.modules">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Exceptions and File Handling</a>&nbsp;&gt;&nbsp;<span class="thispage">Iterating with for Loops</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="file_objects.html" title="Prev: &#8220;Working with File Objects&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="more_on_modules.html" title="Next: &#8220;Using sys.modules&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="fileinfo.for"></a>6.3.&nbsp;Iterating with <tt class="literal">for</tt> Loops
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>Like most other languages, <span class="application">Python</span> has <tt class="literal">for</tt> loops. The only reason you haven't seen them until now is that <span class="application">Python</span> is good at so many other things that you don't need them as often.
+ </p>
+ </div>
+ <p>Most other languages don't have a powerful list datatype like <span class="application">Python</span>, so you end up doing a lot of manual work, specifying a start, end, and step to define a range of integers or characters
+ or other iteratable entities. But in <span class="application">Python</span>, a <tt class="literal">for</tt> loop simply iterates over a list, the same way <a href="../native_data_types/mapping_lists.html" title="3.6.&nbsp;Mapping Lists">list comprehensions</a> work.
+ </p>
+ <div class="example"><a name="d0e15255"></a><h3 class="title">Example&nbsp;6.8.&nbsp;Introducing the <tt class="literal">for</tt> Loop
+ </h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li = [<span class='pystring'>'a'</span>, <span class='pystring'>'b'</span>, <span class='pystring'>'e'</span>]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>for</span> s <span class='pykeyword'>in</span> li:</span> <a name="fileinfo.for.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">... </tt><span class="userinput"><span class='pykeyword'>print</span> s</span> <a name="fileinfo.for.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">a
+b
+e</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> <span class='pystring'>"\n"</span>.join(li)</span> <a name="fileinfo.for.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">a
+b
+e</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.for.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The syntax for a <tt class="literal">for</tt> loop is similar to <a href="../native_data_types/mapping_lists.html" title="3.6.&nbsp;Mapping Lists">list comprehensions</a>. <tt class="varname">li</tt> is a list, and <tt class="varname">s</tt> will take the value of each element in turn, starting from the first element.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.for.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Like an <tt class="literal">if</tt> statement or any other <a href="../getting_to_know_python/indenting_code.html" title="2.5.&nbsp;Indenting Code">indented block</a>, a <tt class="literal">for</tt> loop can have any number of lines of code in it.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.for.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This is the reason you haven't seen the <tt class="literal">for</tt> loop yet: you haven't needed it yet. It's amazing how often you use <tt class="literal">for</tt> loops in other languages when all you really want is a <tt class="function">join</tt> or a list comprehension.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>Doing a &#8220;<span class="quote">normal</span>&#8221; (by <span class="application">Visual Basic</span> standards) counter <tt class="literal">for</tt> loop is also simple.
+ </p>
+ <div class="example"><a name="fileinfo.for.counter"></a><h3 class="title">Example&nbsp;6.9.&nbsp;Simple Counters</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>for</span> i <span class='pykeyword'>in</span> range(5):</span> <a name="fileinfo.for.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">... </tt><span class="userinput"><span class='pykeyword'>print</span> i</span>
+<span class="computeroutput">0
+1
+2
+3
+4</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li = [<span class='pystring'>'a'</span>, <span class='pystring'>'b'</span>, <span class='pystring'>'c'</span>, <span class='pystring'>'d'</span>, <span class='pystring'>'e'</span>]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>for</span> i <span class='pykeyword'>in</span> range(len(li)):</span> <a name="fileinfo.for.3.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<tt class="prompt">... </tt><span class="userinput"><span class='pykeyword'>print</span> li[i]</span>
+<span class="computeroutput">a
+b
+c
+d
+e</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.for.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">As you saw in <a href="../native_data_types/declaring_variables.html#odbchelper.multiassign.range" title="Example&nbsp;3.20.&nbsp;Assigning Consecutive Values">Example&nbsp;3.20, &#8220;Assigning Consecutive Values&#8221;</a>, <tt class="function">range</tt> produces a list of integers, which you then loop through. I know it looks a bit odd, but it is occasionally (and I stress
+ <span class="emphasis"><em>occasionally</em></span>) useful to have a counter loop.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.for.3.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Don't ever do this. This is <span class="application">Visual Basic</span>-style thinking. Break out of it. Just iterate through the list, as shown in the previous example.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p><tt class="literal">for</tt> loops are not just for simple counters. They can iterate through all kinds of things. Here is an example of using a <tt class="literal">for</tt> loop to iterate through a dictionary.
+ </p>
+ <div class="example"><a name="dictionaryiter.example"></a><h3 class="title">Example&nbsp;6.10.&nbsp;Iterating Through a Dictionary</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> os</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>for</span> k, v <span class='pykeyword'>in</span> os.environ.items():</span> <a name="fileinfo.for.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"> <a name="fileinfo.for.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<tt class="prompt">... </tt><span class="userinput"><span class='pykeyword'>print</span> <span class='pystring'>"%s=%s"</span> % (k, v)</span>
+<span class="computeroutput">USERPROFILE=C:\Documents and Settings\mpilgrim
+OS=Windows_NT
+COMPUTERNAME=MPILGRIM
+USERNAME=mpilgrim
+
+[...snip...]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> <span class='pystring'>"\n"</span>.join([<span class='pystring'>"%s=%s"</span> % (k, v)</span>
+<tt class="prompt">... </tt><span class="userinput"><span class='pykeyword'>for</span> k, v <span class='pykeyword'>in</span> os.environ.items()])</span> <a name="fileinfo.for.2.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">USERPROFILE=C:\Documents and Settings\mpilgrim
+OS=Windows_NT
+COMPUTERNAME=MPILGRIM
+USERNAME=mpilgrim
+
+[...snip...]</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.for.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="varname">os.environ</tt> is a dictionary of the environment variables defined on your system. In Windows, these are your user and system variables
+ accessible from <span class="acronym">MS-DOS</span>. In <span class="acronym">UNIX</span>, they are the variables exported in your shell's startup scripts. In <span class="abbrev">Mac</span> <span class="acronym">OS</span>, there is no concept of environment variables, so this dictionary is empty.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.for.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="literal">os.environ.items()</tt> returns a list of tuples: <tt class="literal">[(<i class="replaceable">key1</i>, <i class="replaceable">value1</i>), (<i class="replaceable">key2</i>, <i class="replaceable">value2</i>), ...]</tt>. The <tt class="literal">for</tt> loop iterates through this list. The first round, it assigns <tt class="literal"><i class="replaceable">key1</i></tt> to <tt class="varname">k</tt> and <tt class="literal"><i class="replaceable">value1</i></tt> to <tt class="varname">v</tt>, so <tt class="varname">k</tt> = <tt class="literal">USERPROFILE</tt> and <tt class="varname">v</tt> = <tt class="literal">C:\Documents and Settings\mpilgrim</tt>. In the second round, <tt class="varname">k</tt> gets the second key, <tt class="literal">OS</tt>, and <tt class="varname">v</tt> gets the corresponding value, <tt class="literal">Windows_NT</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.for.2.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">With <a href="../native_data_types/declaring_variables.html#odbchelper.multiassign" title="3.4.2.&nbsp;Assigning Multiple Values at Once">multi-variable assignment</a> and <a href="../native_data_types/mapping_lists.html" title="3.6.&nbsp;Mapping Lists">list comprehensions</a>, you can replace the entire <tt class="literal">for</tt> loop with a single statement. Whether you actually do this in real code is a matter of personal coding style. I like it
+ because it makes it clear that what I'm doing is mapping a dictionary into a list, then joining the list into a single string.
+ Other programmers prefer to write this out as a <tt class="literal">for</tt> loop. The output is the same in either case, although this version is slightly faster, because there is only one <tt class="function">print</tt> statement instead of many.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>Now we can look at the <tt class="literal">for</tt> loop in <tt class="classname">MP3FileInfo</tt>, from the sample <tt class="filename">fileinfo.py</tt> program introduced in <a href="../object_oriented_framework/index.html">Chapter 5</a>.
+ </p>
+ <div class="example"><a name="fileinfo.multiassign.for.example"></a><h3 class="title">Example&nbsp;6.11.&nbsp;<tt class="literal">for</tt> Loop in <tt class="classname">MP3FileInfo</tt></h3><pre class="programlisting">
+ tagDataMap = {<span class='pystring'>"title"</span> : ( 3, 33, stripnulls),
+ <span class='pystring'>"artist"</span> : ( 33, 63, stripnulls),
+ <span class='pystring'>"album"</span> : ( 63, 93, stripnulls),
+ <span class='pystring'>"year"</span> : ( 93, 97, stripnulls),
+ <span class='pystring'>"comment"</span> : ( 97, 126, stripnulls),
+ <span class='pystring'>"genre"</span> : (127, 128, ord)} <a name="fileinfo.multiassign.5.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ .
+ .
+ .
+ <span class='pykeyword'>if</span> tagdata[:3] == <span class='pystring'>"TAG"</span>:
+ <span class='pykeyword'>for</span> tag, (start, end, parseFunc) <span class='pykeyword'>in</span> self.tagDataMap.items(): <a name="fileinfo.multiassign.5.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+ self[tag] = parseFunc(tagdata[start:end]) <a name="fileinfo.multiassign.5.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.multiassign.5.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="varname">tagDataMap</tt> is a <a href="../object_oriented_framework/class_attributes.html" title="5.8.&nbsp;Introducing Class Attributes">class attribute</a> that defines the tags you're looking for in an <span class="abbrev">MP3</span> file. Tags are stored in fixed-length fields. Once you read the last 128 bytes of the file, bytes 3 through 32 of those
+ are always the song title, 33 through 62 are always the artist name, 63 through 92 are the album name, and so forth. Note
+ that <tt class="varname">tagDataMap</tt> is a dictionary of tuples, and each tuple contains two integers and a function reference.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.multiassign.5.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This looks complicated, but it's not. The structure of the <tt class="literal">for</tt> variables matches the structure of the elements of the list returned by <tt class="function">items</tt>. Remember that <tt class="function">items</tt> returns a list of tuples of the form <tt class="literal">(<i class="replaceable">key</i>, <i class="replaceable">value</i>)</tt>. The first element of that list is <tt class="literal">("title", (3, 33, &lt;function stripnulls&gt;))</tt>, so the first time around the loop, <tt class="varname">tag</tt> gets <tt class="literal">"title"</tt>, <tt class="varname">start</tt> gets <tt class="literal">3</tt>, <tt class="varname">end</tt> gets <tt class="literal">33</tt>, and <tt class="varname">parseFunc</tt> gets the function <tt class="function">stripnulls</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.multiassign.5.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Now that you've extracted all the parameters for a single <span class="abbrev">MP3</span> tag, saving the tag data is easy. You <a href="../native_data_types/lists.html#odbchelper.list.slice" title="Example&nbsp;3.8.&nbsp;Slicing a List">slice</a> <tt class="varname">tagdata</tt> from <tt class="varname">start</tt> to <tt class="varname">end</tt> to get the actual data for this tag, call <tt class="varname">parseFunc</tt> to post-process the data, and assign this as the value for the key <tt class="varname">tag</tt> in the pseudo-dictionary <tt class="varname">self</tt>. After iterating through all the elements in <tt class="varname">tagDataMap</tt>, <tt class="varname">self</tt> has the values for all the tags, and <a href="../object_oriented_framework/special_class_methods.html#fileinfo.specialmethods.setname" title="Example&nbsp;5.15.&nbsp;Setting an MP3FileInfo's name">you know what that looks like</a>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="file_objects.html">&lt;&lt;&nbsp;Working with File Objects</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#fileinfo.exception" title="6.1.&nbsp;Handling Exceptions">1</a> <span class="divider">|</span> <a href="file_objects.html" title="6.2.&nbsp;Working with File Objects">2</a> <span class="divider">|</span> <span class="thispage">3</span> <span class="divider">|</span> <a href="more_on_modules.html" title="6.4.&nbsp;Using sys.modules">4</a> <span class="divider">|</span> <a href="os_module.html" title="6.5.&nbsp;Working with Directories">5</a> <span class="divider">|</span> <a href="all_together.html" title="6.6.&nbsp;Putting It All Together">6</a> <span class="divider">|</span> <a href="summary.html" title="6.7.&nbsp;Summary">7</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="more_on_modules.html">Using sys.modules&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/file_handling/index.html b/help/diveintopython-5.4/html/file_handling/index.html
new file mode 100644
index 0000000..3d4a3b4
--- /dev/null
+++ b/help/diveintopython-5.4/html/file_handling/index.html
@@ -0,0 +1,276 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>Chapter&nbsp;6.&nbsp;Exceptions and File Handling</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="../toc/index.html" title="Dive Into Python">
+ <link rel="previous" href="../object_oriented_framework/summary.html" title="5.10.&nbsp;Summary">
+ <link rel="next" href="file_objects.html" title="6.2.&nbsp;Working with File Objects">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<span class="thispage">Exceptions and File Handling</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="../object_oriented_framework/summary.html" title="Prev: &#8220;Summary&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="file_objects.html" title="Next: &#8220;Working with File Objects&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="chapter" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="filehandling"></a>Chapter&nbsp;6.&nbsp;Exceptions and File Handling
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="toc">
+ <ul>
+ <li><span class="section"><a href="index.html#fileinfo.exception">6.1. Handling Exceptions</a></span><ul>
+ <li><span class="section"><a href="index.html#d0e14344">6.1.1. Using Exceptions For Other Purposes</a></span></li>
+ </ul>
+ </li>
+ <li><span class="section"><a href="file_objects.html">6.2. Working with File Objects</a></span><ul>
+ <li><span class="section"><a href="file_objects.html#d0e14670">6.2.1. Reading Files</a></span></li>
+ <li><span class="section"><a href="file_objects.html#d0e14800">6.2.2. Closing Files</a></span></li>
+ <li><span class="section"><a href="file_objects.html#d0e14928">6.2.3. Handling I/O Errors</a></span></li>
+ <li><span class="section"><a href="file_objects.html#d0e15055">6.2.4. Writing to Files</a></span></li>
+ </ul>
+ </li>
+ <li><span class="section"><a href="for_loops.html">6.3. Iterating with for Loops</a></span></li>
+ <li><span class="section"><a href="more_on_modules.html">6.4. Using sys.modules</a></span></li>
+ <li><span class="section"><a href="os_module.html">6.5. Working with Directories</a></span></li>
+ <li><span class="section"><a href="all_together.html">6.6. Putting It All Together</a></span></li>
+ <li><span class="section"><a href="summary.html">6.7. Summary</a></span></li>
+ </ul>
+ </div>
+ <div class="abstract">
+ <p>In this chapter, you will dive into exceptions, file objects, <tt class="literal">for</tt> loops, and the <tt class="filename">os</tt> and <tt class="filename">sys</tt> modules. If you've used exceptions in another programming language, you can skim the first section to get a sense of <span class="application">Python</span>'s syntax. Be sure to tune in again for file handling.
+ </p>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="fileinfo.exception"></a>6.1.&nbsp;Handling Exceptions
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="toc">
+ <ul>
+ <li><span class="section"><a href="index.html#d0e14344">6.1.1. Using Exceptions For Other Purposes</a></span></li>
+ </ul>
+ </div>
+ <div class="abstract">
+ <p>Like many other programming languages, <span class="application">Python</span> has exception handling via <tt class="literal">try...except</tt> blocks.
+ </p>
+ </div><a name="compare.exceptions.java"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%"><span class="application">Python</span> uses <tt class="literal">try...except</tt> to handle exceptions and <tt class="literal">raise</tt> to generate them. <span class="application">Java</span> and <span class="application"><span class="acronym">C++</span></span> use <tt class="literal">try...catch</tt> to handle exceptions, and <tt class="literal">throw</tt> to generate them.
+ </td>
+ </tr>
+ </table>
+ <p>Exceptions are everywhere in <span class="application">Python</span>. Virtually every module in the standard <span class="application">Python</span> library uses them, and <span class="application">Python</span> itself will raise them in a lot of different circumstances. You've already seen them repeatedly throughout this book.
+ </p>
+ <div class="itemizedlist">
+ <ul>
+ <li><a href="../native_data_types/index.html#odbchelper.dict.define" title="Example&nbsp;3.1.&nbsp;Defining a Dictionary">Accessing a non-existent dictionary key</a> will raise a <tt class="errorcode">KeyError</tt> exception.
+ </li>
+ <li><a href="../native_data_types/lists.html#odbchelper.list.search" title="Example&nbsp;3.12.&nbsp;Searching a List">Searching a list for a non-existent value</a> will raise a <tt class="errorcode">ValueError</tt> exception.
+ </li>
+ <li><a href="../native_data_types/tuples.html#odbchelper.tuplemethods" title="Example&nbsp;3.16.&nbsp;Tuples Have No Methods">Calling a non-existent method</a> will raise an <tt class="errorcode">AttributeError</tt> exception.
+ </li>
+ <li><a href="../native_data_types/declaring_variables.html#odbchelper.unboundvariable" title="Example&nbsp;3.18.&nbsp;Referencing an Unbound Variable">Referencing a non-existent variable</a> will raise a <tt class="errorcode">NameError</tt> exception.
+ </li>
+ <li><a href="../native_data_types/formatting_strings.html#odbchelper.stringformatting.coerce" title="Example&nbsp;3.22.&nbsp;String Formatting vs. Concatenating">Mixing datatypes without coercion</a> will raise a <tt class="errorcode">TypeError</tt> exception.
+ </li>
+ </ul>
+ </div>
+ <p>In each of these cases, you were simply playing around in the <span class="application">Python</span> <span class="acronym">IDE</span>: an error occurred, the exception was printed (depending on your <span class="acronym">IDE</span>, perhaps in an intentionally jarring shade of red), and that was that. This is called an <span class="emphasis"><em>unhandled</em></span> exception. When the exception was raised, there was no code to explicitly notice it and deal with it, so it bubbled its
+ way back to the default behavior built in to <span class="application">Python</span>, which is to spit out some debugging information and give up. In the <span class="acronym">IDE</span>, that's no big deal, but if that happened while your actual <span class="application">Python</span> program was running, the entire program would come to a screeching halt.
+ </p>
+ <p>An exception doesn't need result in a complete program crash, though. Exceptions, when raised, can be <span class="emphasis"><em>handled</em></span>. Sometimes an exception is really because you have a bug in your code (like accessing a variable that doesn't exist), but
+ many times, an exception is something you can anticipate. If you're opening a file, it might not exist. If you're connecting
+ to a database, it might be unavailable, or you might not have the correct security credentials to access it. If you know
+ a line of code may raise an exception, you should handle the exception using a <tt class="literal">try...except</tt> block.
+ </p>
+ <div class="example"><a name="d0e14243"></a><h3 class="title">Example&nbsp;6.1.&nbsp;Opening a Non-Existent File</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">fsock = open(<span class='pystring'>"/notthere"</span>, <span class='pystring'>"r"</span>)</span> <a name="fileinfo.exceptions.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="traceback">Traceback (innermost last):
+ File "&lt;interactive input&gt;", line 1, in ?
+IOError: [Errno 2] No such file or directory: '/notthere'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>try</span>:</span>
+<tt class="prompt">... </tt><span class="userinput">fsock = open(<span class='pystring'>"/notthere"</span>)</span> <a name="fileinfo.exceptions.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<tt class="prompt">... </tt><span class="userinput"><span class='pykeyword'>except</span> IOError:</span> <a name="fileinfo.exceptions.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<tt class="prompt">... </tt><span class="userinput"><span class='pykeyword'>print</span> <span class='pystring'>"The file does not exist, exiting gracefully"</span></span>
+<tt class="prompt">... </tt><span class="userinput"><span class='pykeyword'>print</span> <span class='pystring'>"This line will always print"</span></span> <a name="fileinfo.exceptions.1.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">The file does not exist, exiting gracefully
+This line will always print</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.exceptions.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Using the built-in <tt class="function">open</tt> function, you can try to open a file for reading (more on <tt class="function">open</tt> in the next section). But the file doesn't exist, so this raises the <tt class="errorcode">IOError</tt> exception. Since you haven't provided any explicit check for an <tt class="errorcode">IOError</tt> exception, <span class="application">Python</span> just prints out some debugging information about what happened and then gives up.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.exceptions.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You're trying to open the same non-existent file, but this time you're doing it within a <tt class="literal">try...except</tt> block.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.exceptions.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">When the <tt class="function">open</tt> method raises an <tt class="errorcode">IOError</tt> exception, you're ready for it. The <tt class="literal">except IOError:</tt> line catches the exception and executes your own block of code, which in this case just prints a more pleasant error message.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.exceptions.1.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Once an exception has been handled, processing continues normally on the first line after the <tt class="literal">try...except</tt> block. Note that this line will always print, whether or not an exception occurs. If you really did have a file called
+ <tt class="filename">notthere</tt> in your root directory, the call to <tt class="function">open</tt> would succeed, the <tt class="literal">except</tt> clause would be ignored, and this line would still be executed.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>Exceptions may seem unfriendly (after all, if you don't catch the exception, your entire program will crash), but consider
+ the alternative. Would you rather get back an unusable file object to a non-existent file? You'd need to check its validity
+ somehow anyway, and if you forgot, somewhere down the line, your program would give you strange errors somewhere down the
+ line that you would need to trace back to the source. I'm sure you've experienced this, and you know it's not fun. With
+ exceptions, errors occur immediately, and you can handle them in a standard way at the source of the problem.
+ </p>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e14344"></a>6.1.1.&nbsp;Using Exceptions For Other Purposes
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p>There are a lot of other uses for exceptions besides handling actual error conditions. A common use in the standard <span class="application">Python</span> library is to try to import a module, and then check whether it worked. Importing a module that does not exist will raise
+ an <tt class="errorcode">ImportError</tt> exception. You can use this to define multiple levels of functionality based on which modules are available at run-time,
+ or to support multiple platforms (where platform-specific code is separated into different modules).
+ </p>
+ <p>You can also define your own exceptions by creating a class that inherits from the built-in <tt class="classname">Exception</tt> class, and then raise your exceptions with the <tt class="function">raise</tt> command. See the further reading section if you're interested in doing this.
+ </p>
+ <p>The next example demonstrates how to use an exception to support platform-specific functionality. This code comes from the
+ <tt class="filename">getpass</tt> module, a wrapper module for getting a password from the user. Getting a password is accomplished differently on <span class="acronym">UNIX</span>, Windows, and <span class="abbrev">Mac</span> <span class="acronym">OS</span> platforms, but this code encapsulates all of those differences.
+ </p>
+ <div class="example"><a name="crossplatform.example"></a><h3 class="title">Example&nbsp;6.2.&nbsp;Supporting Platform-Specific Functionality</h3><pre class="programlisting">
+ <span class='pycomment'># Bind the name getpass to the appropriate function</span>
+ <span class='pykeyword'>try</span>:
+ <span class='pykeyword'>import</span> termios, TERMIOS <a name="fileinfo.exceptions.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ <span class='pykeyword'>except</span> ImportError:
+ <span class='pykeyword'>try</span>:
+ <span class='pykeyword'>import</span> msvcrt <a name="fileinfo.exceptions.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+ <span class='pykeyword'>except</span> ImportError:
+ <span class='pykeyword'>try</span>:
+ <span class='pykeyword'>from</span> EasyDialogs <span class='pykeyword'>import</span> AskPassword <a name="fileinfo.exceptions.2.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+ <span class='pykeyword'>except</span> ImportError:
+ getpass = default_getpass <a name="fileinfo.exceptions.2.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+ <span class='pykeyword'>else</span>: <a name="fileinfo.exceptions.2.5"></a><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12">
+ getpass = AskPassword
+ <span class='pykeyword'>else</span>:
+ getpass = win_getpass
+ <span class='pykeyword'>else</span>:
+ getpass = unix_getpass</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.exceptions.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="filename">termios</tt> is a <span class="acronym">UNIX</span>-specific module that provides low-level control over the input terminal. If this module is not available (because it's not
+ on your system, or your system doesn't support it), the import fails and <span class="application">Python</span> raises an <tt class="errorcode">ImportError</tt>, which you catch.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.exceptions.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">OK, you didn't have <tt class="filename">termios</tt>, so let's try <tt class="filename">msvcrt</tt>, which is a Windows-specific module that provides an <span class="acronym">API</span> to many useful functions in the Microsoft <span class="application">Visual C++</span> runtime services. If this import fails, <span class="application">Python</span> will raise an <tt class="errorcode">ImportError</tt>, which you catch.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.exceptions.2.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">If the first two didn't work, you try to import a function from <tt class="filename">EasyDialogs</tt>, which is a <span class="abbrev">Mac</span> <span class="acronym">OS</span>-specific module that provides functions to pop up dialog boxes of various types. Once again, if this import fails, <span class="application">Python</span> will raise an <tt class="errorcode">ImportError</tt>, which you catch.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.exceptions.2.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">None of these platform-specific modules is available (which is possible, since <span class="application">Python</span> has been ported to a lot of different platforms), so you need to fall back on a default password input function (which is
+ defined elsewhere in the <tt class="filename">getpass</tt> module). Notice what you're doing here: assigning the function <tt class="function">default_getpass</tt> to the variable <tt class="varname">getpass</tt>. If you read the official <tt class="filename">getpass</tt> documentation, it tells you that the <tt class="filename">getpass</tt> module defines a <tt class="function">getpass</tt> function. It does this by binding <tt class="varname">getpass</tt> to the correct function for your platform. Then when you call the <tt class="function">getpass</tt> function, you're really calling a platform-specific function that this code has set up for you. You don't need to know or
+ care which platform your code is running on -- just call <tt class="function">getpass</tt>, and it will always do the right thing.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.exceptions.2.5"><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">A <tt class="literal">try...except</tt> block can have an <tt class="literal">else</tt> clause, like an <tt class="literal">if</tt> statement. If no exception is raised during the <tt class="literal">try</tt> block, the <tt class="literal">else</tt> clause is executed afterwards. In this case, that means that the <tt class="literal">from EasyDialogs import AskPassword</tt> import worked, so you should bind <tt class="varname">getpass</tt> to the <tt class="function">AskPassword</tt> function. Each of the other <tt class="literal">try...except</tt> blocks has similar <tt class="literal">else</tt> clauses to bind <tt class="varname">getpass</tt> to the appropriate function when you find an <tt class="literal">import</tt> that works.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="furtherreading">
+ <h3>Further Reading on Exception Handling</h3>
+ <ul>
+ <li><a href="http://www.python.org/doc/current/tut/tut.html"><i class="citetitle"><span class="application">Python</span> Tutorial</i></a> discusses <a href="http://www.python.org/doc/current/tut/node10.html#SECTION0010400000000000000000">defining and raising your own exceptions, and handling multiple exceptions at once</a>.
+ </li>
+ <li><a href="http://www.python.org/doc/current/lib/"><i class="citetitle"><span class="application">Python</span> Library Reference</i></a> summarizes <a href="http://www.python.org/doc/current/lib/module-exceptions.html">all the built-in exceptions</a>.
+ </li>
+ <li><a href="http://www.python.org/doc/current/lib/"><i class="citetitle"><span class="application">Python</span> Library Reference</i></a> documents the <a href="http://www.python.org/doc/current/lib/module-getpass.html">getpass</a> module.
+ </li>
+ <li><a href="http://www.python.org/doc/current/lib/"><i class="citetitle"><span class="application">Python</span> Library Reference</i></a> documents the <a href="http://www.python.org/doc/current/lib/module-traceback.html"><tt class="filename">traceback</tt> module</a>, which provides low-level access to exception attributes after an exception is raised.
+ </li>
+ <li><a href="http://www.python.org/doc/current/ref/"><i class="citetitle"><span class="application">Python</span> Reference Manual</i></a> discusses the inner workings of the <a href="http://www.python.org/doc/current/ref/try.html"><tt class="literal">try...except</tt> block</a>.
+ </li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="../object_oriented_framework/summary.html">&lt;&lt;&nbsp;Summary</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<span class="thispage">1</span> <span class="divider">|</span> <a href="file_objects.html" title="6.2.&nbsp;Working with File Objects">2</a> <span class="divider">|</span> <a href="for_loops.html" title="6.3.&nbsp;Iterating with for Loops">3</a> <span class="divider">|</span> <a href="more_on_modules.html" title="6.4.&nbsp;Using sys.modules">4</a> <span class="divider">|</span> <a href="os_module.html" title="6.5.&nbsp;Working with Directories">5</a> <span class="divider">|</span> <a href="all_together.html" title="6.6.&nbsp;Putting It All Together">6</a> <span class="divider">|</span> <a href="summary.html" title="6.7.&nbsp;Summary">7</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="file_objects.html">Working with File Objects&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/file_handling/more_on_modules.html b/help/diveintopython-5.4/html/file_handling/more_on_modules.html
new file mode 100644
index 0000000..0d781aa
--- /dev/null
+++ b/help/diveintopython-5.4/html/file_handling/more_on_modules.html
@@ -0,0 +1,200 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>6.4.&nbsp;Using sys.modules</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;6.&nbsp;Exceptions and File Handling">
+ <link rel="previous" href="for_loops.html" title="6.3.&nbsp;Iterating with for Loops">
+ <link rel="next" href="os_module.html" title="6.5.&nbsp;Working with Directories">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Exceptions and File Handling</a>&nbsp;&gt;&nbsp;<span class="thispage">Using sys.modules</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="for_loops.html" title="Prev: &#8220;Iterating with for Loops&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="os_module.html" title="Next: &#8220;Working with Directories&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="fileinfo.modules"></a>6.4.&nbsp;Using <tt class="literal"><tt class="filename">sys</tt>.modules</tt></h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>Modules, like everything else in <span class="application">Python</span>, are objects. Once imported, you can always get a reference to a module through the global dictionary <tt class="literal"><tt class="filename">sys</tt>.modules</tt>.
+ </p>
+ </div>
+ <div class="example"><a name="d0e15693"></a><h3 class="title">Example&nbsp;6.12.&nbsp;Introducing <tt class="literal"><tt class="filename">sys</tt>.modules</tt></h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> sys</span> <a name="fileinfo.modules.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> <span class='pystring'>'\n'</span>.join(sys.modules.keys())</span> <a name="fileinfo.modules.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">win32api
+os.path
+os
+exceptions
+__main__
+ntpath
+nt
+sys
+__builtin__
+site
+signal
+UserDict
+stat</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.modules.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="filename">sys</tt> module contains system-level information, such as the version of <span class="application">Python</span> you're running (<tt class="literal"><tt class="filename">sys</tt>.version</tt> or <tt class="literal"><tt class="filename">sys</tt>.version_info</tt>), and system-level options such as the maximum allowed recursion depth (<tt class="literal"><tt class="filename">sys</tt>.getrecursionlimit()</tt> and <tt class="literal"><tt class="filename">sys</tt>.setrecursionlimit()</tt>).
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.modules.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="literal"><tt class="filename">sys</tt>.modules</tt> is a dictionary containing all the modules that have ever been imported since <span class="application">Python</span> was started; the key is the module name, the value is the module object. Note that this is more than just the modules <span class="emphasis"><em>your</em></span> program has imported. <span class="application">Python</span> preloads some modules on startup, and if you're using a <span class="application">Python</span> <span class="acronym">IDE</span>, <tt class="literal"><tt class="filename">sys</tt>.modules</tt> contains all the modules imported by all the programs you've run within the <span class="acronym">IDE</span>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>This example demonstrates how to use <tt class="literal"><tt class="filename">sys</tt>.modules</tt>.
+ </p>
+ <div class="example"><a name="d0e15784"></a><h3 class="title">Example&nbsp;6.13.&nbsp;Using <tt class="literal"><tt class="filename">sys</tt>.modules</tt></h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> fileinfo</span> <a name="fileinfo.modules.1.3"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> <span class='pystring'>'\n'</span>.join(sys.modules.keys())</span>
+<span class="computeroutput">win32api
+os.path
+os
+fileinfo
+exceptions
+__main__
+ntpath
+nt
+sys
+__builtin__
+site
+signal
+UserDict
+stat</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">fileinfo</span>
+<span class="computeroutput">&lt;module 'fileinfo' from 'fileinfo.pyc'&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">sys.modules[<span class='pystring'>"fileinfo"</span>]</span> <a name="fileinfo.modules.1.4"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">&lt;module 'fileinfo' from 'fileinfo.pyc'&gt;</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.modules.1.3"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">As new modules are imported, they are added to <tt class="literal"><tt class="filename">sys</tt>.modules</tt>. This explains why importing the same module twice is very fast: <span class="application">Python</span> has already loaded and cached the module in <tt class="literal"><tt class="filename">sys</tt>.modules</tt>, so importing the second time is simply a dictionary lookup.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.modules.1.4"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Given the name (as a string) of any previously-imported module, you can get a reference to the module itself through the <tt class="literal"><tt class="filename">sys</tt>.modules</tt> dictionary.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>The next example shows how to use the <tt class="literal">__module__</tt> class attribute with the <tt class="literal"><tt class="filename">sys</tt>.modules</tt> dictionary to get a reference to the module in which a class is defined.
+ </p>
+ <div class="example"><a name="d0e15859"></a><h3 class="title">Example&nbsp;6.14.&nbsp;The <tt class="literal">__module__</tt> Class Attribute
+ </h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>from</span> fileinfo <span class='pykeyword'>import</span> MP3FileInfo</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">MP3FileInfo.__module__</span> <a name="fileinfo.modules.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">'fileinfo'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">sys.modules[MP3FileInfo.__module__]</span> <a name="fileinfo.modules.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">&lt;module 'fileinfo' from 'fileinfo.pyc'&gt;</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.modules.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Every <span class="application">Python</span> class has a built-in <a href="../object_oriented_framework/class_attributes.html" title="5.8.&nbsp;Introducing Class Attributes">class attribute</a> <tt class="literal">__module__</tt>, which is the name of the module in which the class is defined.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.modules.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Combining this with the <tt class="literal"><tt class="filename">sys</tt>.modules</tt> dictionary, you can get a reference to the module in which a class is defined.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>Now you're ready to see how <tt class="literal"><tt class="filename">sys</tt>.modules</tt> is used in <tt class="filename">fileinfo.py</tt>, the sample program introduced in <a href="../object_oriented_framework/index.html">Chapter 5</a>. This example shows that portion of the code.
+ </p>
+ <div class="example"><a name="d0e15923"></a><h3 class="title">Example&nbsp;6.15.&nbsp;<tt class="literal"><tt class="filename">sys</tt>.modules</tt> in <tt class="filename">fileinfo.py</tt></h3><pre class="programlisting">
+ <span class='pykeyword'>def</span><span class='pyclass'> getFileInfoClass</span>(filename, module=sys.modules[FileInfo.__module__]): <a name="fileinfo.modules.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ <span class='pystring'>"get file info class from filename extension"</span>
+ subclass = <span class='pystring'>"%sFileInfo"</span> % os.path.splitext(filename)[1].upper()[1:] <a name="fileinfo.modules.3.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+ <span class='pykeyword'>return</span> hasattr(module, subclass) <span class='pykeyword'>and</span> getattr(module, subclass) <span class='pykeyword'>or</span> FileInfo <a name="fileinfo.modules.3.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.modules.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This is a function with two arguments; <tt class="varname">filename</tt> is required, but <tt class="varname">module</tt> is <a href="../power_of_introspection/optional_arguments.html" title="4.2.&nbsp;Using Optional and Named Arguments">optional</a> and defaults to the module that contains the <tt class="classname">FileInfo</tt> class. This looks inefficient, because you might expect <span class="application">Python</span> to evaluate the <tt class="literal"><tt class="filename">sys</tt>.modules</tt> expression every time the function is called. In fact, <span class="application">Python</span> evaluates default expressions only once, the first time the module is imported. As you'll see later, you never call this
+ function with a <tt class="varname">module</tt> argument, so <tt class="varname">module</tt> serves as a function-level constant.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.modules.3.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You'll plow through this line later, after you dive into the <tt class="filename">os</tt> module. For now, take it on faith that <tt class="varname">subclass</tt> ends up as the name of a class, like <tt class="classname">MP3FileInfo</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.modules.3.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You already know about <a href="../power_of_introspection/getattr.html" title="4.4.&nbsp;Getting Object References With getattr"><tt class="function">getattr</tt></a>, which gets a reference to an object by name. <tt class="function">hasattr</tt> is a complementary function that checks whether an object has a particular attribute; in this case, whether a module has
+ a particular class (although it works for any object and any attribute, just like <tt class="function">getattr</tt>). In English, this line of code says, &#8220;<span class="quote">If this module has the class named by <tt class="varname">subclass</tt> then return it, otherwise return the base class <tt class="classname">FileInfo</tt>.</span>&#8221;
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="furtherreading">
+ <h3>Further Reading on Modules</h3>
+ <ul>
+ <li><a href="http://www.python.org/doc/current/tut/tut.html"><i class="citetitle"><span class="application">Python</span> Tutorial</i></a> discusses exactly <a href="http://www.python.org/doc/current/tut/node6.html#SECTION006710000000000000000">when and how default arguments are evaluated</a>.
+ </li>
+ <li><a href="http://www.python.org/doc/current/lib/"><i class="citetitle"><span class="application">Python</span> Library Reference</i></a> documents the <a href="http://www.python.org/doc/current/lib/module-sys.html"><tt class="filename">sys</tt></a> module.
+ </li>
+ </ul>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="for_loops.html">&lt;&lt;&nbsp;Iterating with for Loops</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#fileinfo.exception" title="6.1.&nbsp;Handling Exceptions">1</a> <span class="divider">|</span> <a href="file_objects.html" title="6.2.&nbsp;Working with File Objects">2</a> <span class="divider">|</span> <a href="for_loops.html" title="6.3.&nbsp;Iterating with for Loops">3</a> <span class="divider">|</span> <span class="thispage">4</span> <span class="divider">|</span> <a href="os_module.html" title="6.5.&nbsp;Working with Directories">5</a> <span class="divider">|</span> <a href="all_together.html" title="6.6.&nbsp;Putting It All Together">6</a> <span class="divider">|</span> <a href="summary.html" title="6.7.&nbsp;Summary">7</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="os_module.html">Working with Directories&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/file_handling/os_module.html b/help/diveintopython-5.4/html/file_handling/os_module.html
new file mode 100644
index 0000000..06e14d1
--- /dev/null
+++ b/help/diveintopython-5.4/html/file_handling/os_module.html
@@ -0,0 +1,322 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>6.5.&nbsp;Working with Directories</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;6.&nbsp;Exceptions and File Handling">
+ <link rel="previous" href="more_on_modules.html" title="6.4.&nbsp;Using sys.modules">
+ <link rel="next" href="all_together.html" title="6.6.&nbsp;Putting It All Together">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Exceptions and File Handling</a>&nbsp;&gt;&nbsp;<span class="thispage">Working with Directories</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="more_on_modules.html" title="Prev: &#8220;Using sys.modules&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="all_together.html" title="Next: &#8220;Putting It All Together&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="fileinfo.os"></a>6.5.&nbsp;Working with Directories
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>The <tt class="filename">os.path</tt> module has several functions for manipulating files and directories. Here, we're looking at handling pathnames and listing
+ the contents of a directory.
+ </p>
+ </div>
+ <div class="example"><a name="fileinfo.os.path.join.example"></a><h3 class="title">Example&nbsp;6.16.&nbsp;Constructing Pathnames</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> os</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">os.path.join(<span class='pystring'>"c:\\music\\ap\\"</span>, <span class='pystring'>"mahadeva.mp3"</span>)</span> <a name="fileinfo.os.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"> <a name="fileinfo.os.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">'c:\\music\\ap\\mahadeva.mp3'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">os.path.join(<span class='pystring'>"c:\\music\\ap"</span>, <span class='pystring'>"mahadeva.mp3"</span>)</span> <a name="fileinfo.os.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">'c:\\music\\ap\\mahadeva.mp3'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">os.path.expanduser(<span class='pystring'>"~"</span>)</span> <a name="fileinfo.os.1.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">'c:\\Documents and Settings\\mpilgrim\\My Documents'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">os.path.join(os.path.expanduser(<span class='pystring'>"~"</span>), <span class='pystring'>"Python"</span>)</span> <a name="fileinfo.os.1.5"></a><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12">
+<span class="computeroutput">'c:\\Documents and Settings\\mpilgrim\\My Documents\\Python'</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.os.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="filename">os.path</tt> is a reference to a module -- which module depends on your platform. Just as <a href="index.html#crossplatform.example" title="Example&nbsp;6.2.&nbsp;Supporting Platform-Specific Functionality"><tt class="filename">getpass</tt></a> encapsulates differences between platforms by setting <tt class="varname">getpass</tt> to a platform-specific function, <tt class="filename">os</tt> encapsulates differences between platforms by setting <tt class="varname">path</tt> to a platform-specific module.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.os.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="function">join</tt> function of <tt class="filename">os.path</tt> constructs a pathname out of one or more partial pathnames. In this case, it simply concatenates strings. (Note that dealing
+ with pathnames on Windows is annoying because the backslash character must be escaped.)
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.os.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">In this slightly less trivial case, <tt class="function">join</tt> will add an extra backslash to the pathname before joining it to the filename. I was overjoyed when I discovered this, since
+ <tt class="function">addSlashIfNecessary</tt> is one of the stupid little functions I always need to write when building up my toolbox in a new language. <span class="emphasis"><em>Do not</em></span> write this stupid little function in <span class="application">Python</span>; smart people have already taken care of it for you.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.os.1.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">expanduser</tt> will expand a pathname that uses <tt class="literal">~</tt> to represent the current user's home directory. This works on any platform where users have a home directory, like Windows,
+ <span class="acronym">UNIX</span>, and <span class="abbrev">Mac</span> <span class="acronym">OS</span> X; it has no effect on <span class="abbrev">Mac</span> <span class="acronym">OS</span>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.os.1.5"><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Combining these techniques, you can easily construct pathnames for directories and files under the user's home directory.</td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="splittingpathnames.example"></a><h3 class="title">Example&nbsp;6.17.&nbsp;Splitting Pathnames</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">os.path.split(<span class='pystring'>"c:\\music\\ap\\mahadeva.mp3"</span>)</span> <a name="fileinfo.os.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">('c:\\music\\ap', 'mahadeva.mp3')</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">(filepath, filename) = os.path.split(<span class='pystring'>"c:\\music\\ap\\mahadeva.mp3"</span>)</span> <a name="fileinfo.os.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">filepath</span> <a name="fileinfo.os.2.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">'c:\\music\\ap'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">filename</span> <a name="fileinfo.os.2.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">'mahadeva.mp3'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">(shortname, extension) = os.path.splitext(filename)</span> <a name="fileinfo.os.2.5"></a><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">shortname</span>
+<span class="computeroutput">'mahadeva'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">extension</span>
+<span class="computeroutput">'.mp3'</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.os.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="function">split</tt> function splits a full pathname and returns a tuple containing the path and filename. Remember when I said you could use
+ <a href="../native_data_types/declaring_variables.html#odbchelper.multiassign" title="3.4.2.&nbsp;Assigning Multiple Values at Once">multi-variable assignment</a> to return multiple values from a function? Well, <tt class="function">split</tt> is such a function.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.os.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You assign the return value of the <tt class="function">split</tt> function into a tuple of two variables. Each variable receives the value of the corresponding element of the returned tuple.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.os.2.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The first variable, <tt class="varname">filepath</tt>, receives the value of the first element of the tuple returned from <tt class="function">split</tt>, the file path.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.os.2.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The second variable, <tt class="varname">filename</tt>, receives the value of the second element of the tuple returned from <tt class="function">split</tt>, the filename.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.os.2.5"><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="filename">os.path</tt> also contains a function <tt class="function">splitext</tt>, which splits a filename and returns a tuple containing the filename and the file extension. You use the same technique
+ to assign each of them to separate variables.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="fileinfo.listdir.example"></a><h3 class="title">Example&nbsp;6.18.&nbsp;Listing Directories</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">os.listdir(<span class='pystring'>"c:\\music\\_singles\\"</span>)</span> <a name="fileinfo.os.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">['a_time_long_forgotten_con.mp3', 'hellraiser.mp3',
+'kairo.mp3', 'long_way_home1.mp3', 'sidewinder.mp3',
+'spinning.mp3']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">dirname = <span class='pystring'>"c:\\"</span></span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">os.listdir(dirname)</span> <a name="fileinfo.os.3.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">['AUTOEXEC.BAT', 'boot.ini', 'CONFIG.SYS', 'cygwin',
+'docbook', 'Documents and Settings', 'Incoming', 'Inetpub', 'IO.SYS',
+'MSDOS.SYS', 'Music', 'NTDETECT.COM', 'ntldr', 'pagefile.sys',
+'Program Files', 'Python20', 'RECYCLER',
+'System Volume Information', 'TEMP', 'WINNT']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">[f <span class='pykeyword'>for</span> f <span class='pykeyword'>in</span> os.listdir(dirname)</span>
+<tt class="prompt">... </tt><span class="userinput"><span class='pykeyword'>if</span> os.path.isfile(os.path.join(dirname, f))]</span> <a name="fileinfo.os.3.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">['AUTOEXEC.BAT', 'boot.ini', 'CONFIG.SYS', 'IO.SYS', 'MSDOS.SYS',
+'NTDETECT.COM', 'ntldr', 'pagefile.sys']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">[f <span class='pykeyword'>for</span> f <span class='pykeyword'>in</span> os.listdir(dirname)</span>
+<tt class="prompt">... </tt><span class="userinput"><span class='pykeyword'>if</span> os.path.isdir(os.path.join(dirname, f))]</span> <a name="fileinfo.os.3.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">['cygwin', 'docbook', 'Documents and Settings', 'Incoming',
+'Inetpub', 'Music', 'Program Files', 'Python20', 'RECYCLER',
+'System Volume Information', 'TEMP', 'WINNT']</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.os.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="function">listdir</tt> function takes a pathname and returns a list of the contents of the directory.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.os.3.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">listdir</tt> returns both files and folders, with no indication of which is which.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.os.3.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You can use <a href="../power_of_introspection/filtering_lists.html" title="4.5.&nbsp;Filtering Lists">list filtering</a> and the <tt class="function">isfile</tt> function of the <tt class="filename">os.path</tt> module to separate the files from the folders. <tt class="function">isfile</tt> takes a pathname and returns 1 if the path represents a file, and 0 otherwise. Here you're using <tt class="literal"><tt class="filename">os.path</tt>.<tt class="function">join</tt></tt> to ensure a full pathname, but <tt class="function">isfile</tt> also works with a partial path, relative to the current working directory. You can use <tt class="literal">os.getcwd()</tt> to get the current working directory.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.os.3.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="filename">os.path</tt> also has a <tt class="function">isdir</tt> function which returns 1 if the path represents a directory, and 0 otherwise. You can use this to get a list of the subdirectories
+ within a directory.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="d0e16376"></a><h3 class="title">Example&nbsp;6.19.&nbsp;Listing Directories in <tt class="filename">fileinfo.py</tt></h3><pre class="programlisting"><span class='pykeyword'>
+def</span> listDirectory(directory, fileExtList):
+ <span class='pystring'>"get list of file info objects for files of particular extensions"</span>
+ fileList = [os.path.normcase(f)
+ <span class='pykeyword'>for</span> f <span class='pykeyword'>in</span> os.listdir(directory)] <a name="fileinfo.os.3a.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"> <a name="fileinfo.os.3a.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+ fileList = [os.path.join(directory, f)
+ <span class='pykeyword'>for</span> f <span class='pykeyword'>in</span> fileList
+ <span class='pykeyword'>if</span> os.path.splitext(f)[1] <span class='pykeyword'>in</span> fileExtList] <a name="fileinfo.os.3a.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"> <a name="fileinfo.os.3a.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"> <a name="fileinfo.os.3a.5"></a><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12"></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.os.3a.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="literal">os.listdir(directory)</tt> returns a list of all the files and folders in <tt class="varname">directory</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.os.3a.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Iterating through the list with <tt class="varname">f</tt>, you use <tt class="literal">os.path.normcase(f)</tt> to normalize the case according to operating system defaults. <tt class="function">normcase</tt> is a useful little function that compensates for case-insensitive operating systems that think that <tt class="filename">mahadeva.mp3</tt> and <tt class="filename">mahadeva.MP3</tt> are the same file. For instance, on Windows and <span class="abbrev">Mac</span> <span class="acronym">OS</span>, <tt class="function">normcase</tt> will convert the entire filename to lowercase; on <span class="acronym">UNIX</span>-compatible systems, it will return the filename unchanged.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.os.3a.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Iterating through the normalized list with <tt class="varname">f</tt> again, you use <tt class="literal">os.path.splitext(f)</tt> to split each filename into name and extension.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.os.3a.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">For each file, you see if the extension is in the list of file extensions you care about (<tt class="varname">fileExtList</tt>, which was passed to the <tt class="function">listDirectory</tt> function).
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.os.3a.5"><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">For each file you care about, you use <tt class="literal">os.path.join(directory, f)</tt> to construct the full pathname of the file, and return a list of the full pathnames.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div><a name="tip.os"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">Whenever possible, you should use the functions in <tt class="filename">os</tt> and <tt class="filename">os.path</tt> for file, directory, and path manipulations. These modules are wrappers for platform-specific modules, so functions like
+ <tt class="function">os.path.split</tt> work on <span class="acronym">UNIX</span>, Windows, <span class="abbrev">Mac</span> <span class="acronym">OS</span>, and any other platform supported by <span class="application">Python</span>.
+ </td>
+ </tr>
+ </table>
+ <p>There is one other way to get the contents of a directory. It's very powerful, and it uses the sort of wildcards that you
+ may already be familiar with from working on the command line.
+ </p>
+ <div class="example"><a name="fileinfo.os.glob.example"></a><h3 class="title">Example&nbsp;6.20.&nbsp;Listing Directories with <tt class="filename">glob</tt></h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">os.listdir(<span class='pystring'>"c:\\music\\_singles\\"</span>)</span> <a name="fileinfo.os.4.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">['a_time_long_forgotten_con.mp3', 'hellraiser.mp3',
+'kairo.mp3', 'long_way_home1.mp3', 'sidewinder.mp3',
+'spinning.mp3']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> glob</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">glob.glob(<span class='pystring'>'c:\\music\\_singles\\*.mp3'</span>)</span> <a name="fileinfo.os.4.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">['c:\\music\\_singles\\a_time_long_forgotten_con.mp3',
+'c:\\music\\_singles\\hellraiser.mp3',
+'c:\\music\\_singles\\kairo.mp3',
+'c:\\music\\_singles\\long_way_home1.mp3',
+'c:\\music\\_singles\\sidewinder.mp3',
+'c:\\music\\_singles\\spinning.mp3']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">glob.glob(<span class='pystring'>'c:\\music\\_singles\\s*.mp3'</span>)</span> <a name="fileinfo.os.4.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">['c:\\music\\_singles\\sidewinder.mp3',
+'c:\\music\\_singles\\spinning.mp3']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">glob.glob(<span class='pystring'>'c:\\music\\*\\*.mp3'</span>)</span> <a name="fileinfo.os.4.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.os.4.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">As you saw earlier, <tt class="function">os.listdir</tt> simply takes a directory path and lists all files and directories in that directory.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.os.4.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="filename">glob</tt> module, on the other hand, takes a wildcard and returns the full path of all files and directories matching the wildcard.
+ Here the wildcard is a directory path plus "*.mp3", which will match all <tt class="filename">.mp3</tt> files. Note that each element of the returned list already includes the full path of the file.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.os.4.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">If you want to find all the files in a specific directory that start with "s" and end with ".mp3", you can do that too.</td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.os.4.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Now consider this scenario: you have a <tt class="filename">music</tt> directory, with several subdirectories within it, with <tt class="filename">.mp3</tt> files within each subdirectory. You can get a list of all of those with a single call to <tt class="filename">glob</tt>, by using two wildcards at once. One wildcard is the <tt class="literal">"*.mp3"</tt> (to match <tt class="filename">.mp3</tt> files), and one wildcard is <span class="emphasis"><em>within the directory path itself</em></span>, to match any subdirectory within <tt class="filename">c:\music</tt>. That's a crazy amount of power packed into one deceptively simple-looking function!
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="furtherreading">
+ <h3>Further Reading on the <tt class="filename">os</tt> Module
+ </h3>
+ <ul>
+ <li><a href="http://www.faqts.com/knowledge-base/index.phtml/fid/199/"><span class="application">Python</span> Knowledge Base</a> answers <a href="http://www.faqts.com/knowledge-base/index.phtml/fid/240">questions about the <tt class="filename">os</tt> module</a>.
+ </li>
+ <li><a href="http://www.python.org/doc/current/lib/"><i class="citetitle"><span class="application">Python</span> Library Reference</i></a> documents the <a href="http://www.python.org/doc/current/lib/module-os.html"><tt class="filename">os</tt></a> module and the <a href="http://www.python.org/doc/current/lib/module-os.path.html"><tt class="filename">os.path</tt></a> module.
+ </li>
+ </ul>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="more_on_modules.html">&lt;&lt;&nbsp;Using sys.modules</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#fileinfo.exception" title="6.1.&nbsp;Handling Exceptions">1</a> <span class="divider">|</span> <a href="file_objects.html" title="6.2.&nbsp;Working with File Objects">2</a> <span class="divider">|</span> <a href="for_loops.html" title="6.3.&nbsp;Iterating with for Loops">3</a> <span class="divider">|</span> <a href="more_on_modules.html" title="6.4.&nbsp;Using sys.modules">4</a> <span class="divider">|</span> <span class="thispage">5</span> <span class="divider">|</span> <a href="all_together.html" title="6.6.&nbsp;Putting It All Together">6</a> <span class="divider">|</span> <a href="summary.html" title="6.7.&nbsp;Summary">7</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="all_together.html">Putting It All Together&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/file_handling/summary.html b/help/diveintopython-5.4/html/file_handling/summary.html
new file mode 100644
index 0000000..ed70dff
--- /dev/null
+++ b/help/diveintopython-5.4/html/file_handling/summary.html
@@ -0,0 +1,161 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>6.7.&nbsp;Summary</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;6.&nbsp;Exceptions and File Handling">
+ <link rel="previous" href="all_together.html" title="6.6.&nbsp;Putting It All Together">
+ <link rel="next" href="../regular_expressions/index.html" title="Chapter&nbsp;7.&nbsp;Regular Expressions">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Exceptions and File Handling</a>&nbsp;&gt;&nbsp;<span class="thispage">Summary</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="all_together.html" title="Prev: &#8220;Putting It All Together&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="../regular_expressions/index.html" title="Next: &#8220;Regular Expressions&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="fileinfo.summary2"></a>6.7.&nbsp;Summary
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>The <tt class="filename">fileinfo.py</tt> program introduced in <a href="../object_oriented_framework/index.html">Chapter 5</a> should now make perfect sense.
+ </p>
+ </div>
+ <div class="informalexample"><pre class="programlisting">
+<span class='pystring'>"""Framework for getting filetype-specific metadata.
+
+Instantiate appropriate class with filename. Returned object acts like a
+dictionary, with key-value pairs for each piece of metadata.
+ import fileinfo
+ info = fileinfo.MP3FileInfo("/music/ap/mahadeva.mp3")
+ print "\\n".join(["%s=%s" % (k, v) for k, v in info.items()])
+
+Or use listDirectory function to get info on all files in a directory.
+ for info in fileinfo.listDirectory("/music/ap/", [".mp3"]):
+ ...
+
+Framework can be extended by adding classes for particular file types, e.g.
+HTMLFileInfo, MPGFileInfo, DOCFileInfo. Each class is completely responsible for
+parsing its files appropriately; see MP3FileInfo for example.
+"""</span>
+<span class='pykeyword'>import</span> os
+<span class='pykeyword'>import</span> sys
+<span class='pykeyword'>from</span> UserDict <span class='pykeyword'>import</span> UserDict
+
+<span class='pykeyword'>def</span><span class='pyclass'> stripnulls</span>(data):
+ <span class='pystring'>"strip whitespace and nulls"</span>
+ <span class='pykeyword'>return</span> data.replace(<span class='pystring'>"\00"</span>, <span class='pystring'>""</span>).strip()
+
+<span class='pykeyword'>class</span><span class='pyclass'> FileInfo</span>(UserDict):
+ <span class='pystring'>"store file metadata"</span>
+ <span class='pykeyword'>def</span><span class='pyclass'> __init__</span>(self, filename=None):
+ UserDict.__init__(self)
+ self[<span class='pystring'>"name"</span>] = filename
+
+<span class='pykeyword'>class</span><span class='pyclass'> MP3FileInfo</span>(FileInfo):
+ <span class='pystring'>"store ID3v1.0 MP3 tags"</span>
+ tagDataMap = {<span class='pystring'>"title"</span> : ( 3, 33, stripnulls),
+ <span class='pystring'>"artist"</span> : ( 33, 63, stripnulls),
+ <span class='pystring'>"album"</span> : ( 63, 93, stripnulls),
+ <span class='pystring'>"year"</span> : ( 93, 97, stripnulls),
+ <span class='pystring'>"comment"</span> : ( 97, 126, stripnulls),
+ <span class='pystring'>"genre"</span> : (127, 128, ord)}
+
+ <span class='pykeyword'>def</span><span class='pyclass'> __parse</span>(self, filename):
+ <span class='pystring'>"parse ID3v1.0 tags from MP3 file"</span>
+ self.clear()
+ <span class='pykeyword'>try</span>:
+ fsock = open(filename, <span class='pystring'>"rb"</span>, 0)
+ <span class='pykeyword'>try</span>:
+ fsock.seek(-128, 2)
+ tagdata = fsock.read(128)
+ <span class='pykeyword'>finally</span>:
+ fsock.close()
+ <span class='pykeyword'>if</span> tagdata[:3] == <span class='pystring'>"TAG"</span>:
+ <span class='pykeyword'>for</span> tag, (start, end, parseFunc) <span class='pykeyword'>in</span> self.tagDataMap.items():
+ self[tag] = parseFunc(tagdata[start:end])
+ <span class='pykeyword'>except</span> IOError:
+ <span class='pykeyword'>pass</span>
+
+ <span class='pykeyword'>def</span><span class='pyclass'> __setitem__</span>(self, key, item):
+ <span class='pykeyword'>if</span> key == <span class='pystring'>"name"</span> <span class='pykeyword'>and</span> item:
+ self.__parse(item)
+ FileInfo.__setitem__(self, key, item)
+
+<span class='pykeyword'>def</span><span class='pyclass'> listDirectory</span>(directory, fileExtList):
+ <span class='pystring'>"get list of file info objects for files of particular extensions"</span>
+ fileList = [os.path.normcase(f)
+ <span class='pykeyword'>for</span> f <span class='pykeyword'>in</span> os.listdir(directory)]
+ fileList = [os.path.join(directory, f)
+ <span class='pykeyword'>for</span> f <span class='pykeyword'>in</span> fileList
+ <span class='pykeyword'>if</span> os.path.splitext(f)[1] <span class='pykeyword'>in</span> fileExtList]
+ <span class='pykeyword'>def</span><span class='pyclass'> getFileInfoClass</span>(filename, module=sys.modules[FileInfo.__module__]):
+ <span class='pystring'>"get file info class from filename extension"</span>
+ subclass = <span class='pystring'>"%sFileInfo"</span> % os.path.splitext(filename)[1].upper()[1:]
+ <span class='pykeyword'>return</span> hasattr(module, subclass) <span class='pykeyword'>and</span> getattr(module, subclass) <span class='pykeyword'>or</span> FileInfo
+ <span class='pykeyword'>return</span> [getFileInfoClass(f)(f) <span class='pykeyword'>for</span> f <span class='pykeyword'>in</span> fileList]
+
+<span class='pykeyword'>if</span> __name__ == <span class='pystring'>"__main__"</span>:
+ <span class='pykeyword'>for</span> info <span class='pykeyword'>in</span> listDirectory(<span class='pystring'>"/music/_singles/"</span>, [<span class='pystring'>".mp3"</span>]):
+ <span class='pykeyword'>print</span> <span class='pystring'>"\n"</span>.join([<span class='pystring'>"%s=%s"</span> % (k, v) <span class='pykeyword'>for</span> k, v <span class='pykeyword'>in</span> info.items()])
+ print</pre></div>
+ <div class="highlights">
+ <p>Before diving into the next chapter, make sure you're comfortable doing the following things:</p>
+ <div class="itemizedlist">
+ <ul>
+ <li>Catching exceptions with <a href="index.html#fileinfo.exception" title="6.1.&nbsp;Handling Exceptions"><tt class="literal">try...except</tt></a></li>
+ <li>Protecting external resources with <a href="file_objects.html#fileinfo.files.incode" title="Example&nbsp;6.6.&nbsp;File Objects in MP3FileInfo"><tt class="literal">try...finally</tt></a></li>
+ <li>Reading from <a href="file_objects.html" title="6.2.&nbsp;Working with File Objects">files</a></li>
+ <li>Assigning multiple values at once in a <a href="for_loops.html#fileinfo.multiassign.for.example" title="Example&nbsp;6.11.&nbsp;for Loop in MP3FileInfo"><tt class="literal">for</tt> loop</a></li>
+ <li>Using the <a href="os_module.html" title="6.5.&nbsp;Working with Directories"><tt class="filename">os</tt></a> module for all your cross-platform file manipulation needs
+ </li>
+ <li>Dynamically <a href="all_together.html" title="6.6.&nbsp;Putting It All Together">instantiating classes of unknown type</a> by treating classes as objects and passing them around
+ </li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="all_together.html">&lt;&lt;&nbsp;Putting It All Together</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#fileinfo.exception" title="6.1.&nbsp;Handling Exceptions">1</a> <span class="divider">|</span> <a href="file_objects.html" title="6.2.&nbsp;Working with File Objects">2</a> <span class="divider">|</span> <a href="for_loops.html" title="6.3.&nbsp;Iterating with for Loops">3</a> <span class="divider">|</span> <a href="more_on_modules.html" title="6.4.&nbsp;Using sys.modules">4</a> <span class="divider">|</span> <a href="os_module.html" title="6.5.&nbsp;Working with Directories">5</a> <span class="divider">|</span> <a href="all_together.html" title="6.6.&nbsp;Putting It All Together">6</a> <span class="divider">|</span> <span class="thispage">7</span>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="../regular_expressions/index.html">Regular Expressions&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/functional_programming/all_together.html b/help/diveintopython-5.4/html/functional_programming/all_together.html
new file mode 100644
index 0000000..53ca4a5
--- /dev/null
+++ b/help/diveintopython-5.4/html/functional_programming/all_together.html
@@ -0,0 +1,261 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>16.7.&nbsp;Putting it all together</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;16.&nbsp;Functional Programming">
+ <link rel="previous" href="dynamic_import.html" title="16.6.&nbsp;Dynamically importing modules">
+ <link rel="next" href="summary.html" title="16.8.&nbsp;Summary">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Functional Programming</a>&nbsp;&gt;&nbsp;<span class="thispage">Putting it all together</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="dynamic_import.html" title="Prev: &#8220;Dynamically importing modules&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="summary.html" title="Next: &#8220;Summary&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="regression.alltogether"></a>16.7.&nbsp;Putting it all together
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>You've learned enough now to deconstruct the first seven lines of this chapter's code sample: reading a directory and importing
+ selected modules within it.
+ </p>
+ </div>
+ <div class="example"><a name="d0e36538"></a><h3 class="title">Example&nbsp;16.16.&nbsp;The <tt class="function">regressionTest</tt> function
+ </h3><pre class="programlisting"><span class='pykeyword'>
+def</span> regressionTest():
+ path = os.path.abspath(os.path.dirname(sys.argv[0]))
+ files = os.listdir(path)
+ test = re.compile(<span class='pystring'>"test\.py$"</span>, re.IGNORECASE)
+ files = filter(test.search, files)
+ filenameToModuleName = <span class='pykeyword'>lambda</span> f: os.path.splitext(f)[0]
+ moduleNames = map(filenameToModuleName, files)
+ modules = map(__import__, moduleNames)
+load = unittest.defaultTestLoader.loadTestsFromModule
+<span class='pykeyword'>return</span> unittest.TestSuite(map(load, modules))
+</pre></div>
+ <p>Let's look at it line by line, interactively. Assume that the current directory is <tt class="filename">c:\diveintopython\py</tt>, which contains the examples that come with this book, including this chapter's script. As you saw in <a href="finding_the_path.html" title="16.2.&nbsp;Finding the path">Section&nbsp;16.2, &#8220;Finding the path&#8221;</a>, the script directory will end up in the <tt class="varname">path</tt> variable, so let's start hard-code that and go from there.
+ </p>
+ <div class="example"><a name="d0e36556"></a><h3 class="title">Example&nbsp;16.17.&nbsp;Step 1: Get all the files</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> sys, os, re, unittest</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">path = r<span class='pystring'>'c:\diveintopython\py'</span></span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">files = os.listdir(path) </span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">files</span> <a name="regression.alltogether.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">['BaseHTMLProcessor.py', 'LICENSE.txt', 'apihelper.py', 'apihelpertest.py',
+'argecho.py', 'autosize.py', 'builddialectexamples.py', 'dialect.py',
+'fileinfo.py', 'fullpath.py', 'kgptest.py', 'makerealworddoc.py',
+'odbchelper.py', 'odbchelpertest.py', 'parsephone.py', 'piglatin.py',
+'plural.py', 'pluraltest.py', 'pyfontify.py', 'regression.py', 'roman.py', 'romantest.py',
+'uncurly.py', 'unicode2koi8r.py', 'urllister.py', 'kgp', 'plural', 'roman',
+'colorize.py']</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.alltogether.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="varname">files</tt> is a list of all the files and directories in the script's directory. (If you've been running some of the examples already,
+ you may also see some <tt class="filename">.pyc</tt> files in there as well.)
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="d0e36595"></a><h3 class="title">Example&nbsp;16.18.&nbsp;Step 2: Filter to find the files you care about</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">test = re.compile(<span class='pystring'>"test\.py$"</span>, re.IGNORECASE) </span> <a name="regression.alltogether.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">files = filter(test.search, files) </span> <a name="regression.alltogether.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">files</span> <a name="regression.alltogether.2.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">['apihelpertest.py', 'kgptest.py', 'odbchelpertest.py', 'pluraltest.py', 'romantest.py']</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.alltogether.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This regular expression will match any string that ends with <tt class="literal">test.py</tt>. Note that you need to escape the period, since a period in a regular expression usually means &#8220;<span class="quote">match any single character</span>&#8221;, but you actually want to match a literal period instead.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.alltogether.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The compiled regular expression acts like a function, so you can use it to filter the large list of files and directories,
+ to find the ones that match the regular expression.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.alltogether.2.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">And you're left with the list of unit testing scripts, because they were the only ones named <tt class="filename">SOMETHINGtest.py</tt>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="d0e36643"></a><h3 class="title">Example&nbsp;16.19.&nbsp;Step 3: Map filenames to module names</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">filenameToModuleName = <span class='pykeyword'>lambda</span> f: os.path.splitext(f)[0]</span> <a name="regression.alltogether.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">filenameToModuleName(<span class='pystring'>'romantest.py'</span>)</span> <a name="regression.alltogether.3.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">'romantest'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">filenameToModuleName(<span class='pystring'>'odchelpertest.py'</span>)</span>
+<span class="computeroutput">'odbchelpertest'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">moduleNames = map(filenameToModuleName, files) </span> <a name="regression.alltogether.3.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">moduleNames</span> <a name="regression.alltogether.3.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">['apihelpertest', 'kgptest', 'odbchelpertest', 'pluraltest', 'romantest']</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.alltogether.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">As you saw in <a href="../power_of_introspection/lambda_functions.html" title="4.7.&nbsp;Using lambda Functions">Section&nbsp;4.7, &#8220;Using lambda Functions&#8221;</a>, <tt class="literal">lambda</tt> is a quick-and-dirty way of creating an inline, one-line function. This one takes a filename with an extension and returns
+ just the filename part, using the standard library function <tt class="function">os.path.splitext</tt> that you saw in <a href="../file_handling/os_module.html#splittingpathnames.example" title="Example&nbsp;6.17.&nbsp;Splitting Pathnames">Example&nbsp;6.17, &#8220;Splitting Pathnames&#8221;</a>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.alltogether.3.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="varname">filenameToModuleName</tt> is a function. There's nothing magic about <tt class="literal">lambda</tt> functions as opposed to regular functions that you define with a <tt class="literal">def</tt> statement. You can call the <tt class="varname">filenameToModuleName</tt> function like any other, and it does just what you wanted it to do: strips the file extension off of its argument.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.alltogether.3.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Now you can apply this function to each file in the list of unit test files, using <tt class="function">map</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.alltogether.3.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">And the result is just what you wanted: a list of modules, as strings.</td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="d0e36727"></a><h3 class="title">Example&nbsp;16.20.&nbsp;Step 4: Mapping module names to modules</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">modules = map(__import__, moduleNames) </span> <a name="regression.alltogether.4.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">modules</span> <a name="regression.alltogether.4.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">[&lt;module 'apihelpertest' from 'apihelpertest.py'&gt;,
+&lt;module 'kgptest' from 'kgptest.py'&gt;,
+&lt;module 'odbchelpertest' from 'odbchelpertest.py'&gt;,
+&lt;module 'pluraltest' from 'pluraltest.py'&gt;,
+&lt;module 'romantest' from 'romantest.py'&gt;]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">modules[-1]</span> <a name="regression.alltogether.4.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">&lt;module 'romantest' from 'romantest.py'&gt;</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.alltogether.4.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">As you saw in <a href="dynamic_import.html" title="16.6.&nbsp;Dynamically importing modules">Section&nbsp;16.6, &#8220;Dynamically importing modules&#8221;</a>, you can use a combination of <tt class="function">map</tt> and <tt class="function">__import__</tt> to map a list of module names (as strings) into actual modules (which you can call or access like any other module).
+
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.alltogether.4.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="varname">modules</tt> is now a list of modules, fully accessible like any other module.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.alltogether.4.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The last module in the list <span class="emphasis"><em>is</em></span> the <tt class="filename">romantest</tt> module, just as if you had said <tt class="literal">import romantest</tt>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="d0e36788"></a><h3 class="title">Example&nbsp;16.21.&nbsp;Step 5: Loading the modules into a test suite</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">load = unittest.defaultTestLoader.loadTestsFromModule </span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">map(load, modules)</span> <a name="regression.alltogether.5.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">[&lt;unittest.TestSuite tests=[
+ &lt;unittest.TestSuite tests=[&lt;apihelpertest.BadInput testMethod=testNoObject&gt;]&gt;,
+ &lt;unittest.TestSuite tests=[&lt;apihelpertest.KnownValues testMethod=testApiHelper&gt;]&gt;,
+ &lt;unittest.TestSuite tests=[
+ &lt;apihelpertest.ParamChecks testMethod=testCollapse&gt;,
+ &lt;apihelpertest.ParamChecks testMethod=testSpacing&gt;]&gt;,
+ ...
+ ]
+]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">unittest.TestSuite(map(load, modules))</span> <a name="regression.alltogether.5.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.alltogether.5.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">These are real module objects. Not only can you access them like any other module, instantiate classes and call functions,
+ you can also introspect into the module to figure out which classes and functions it has in the first place. That's what
+ the <tt class="function">loadTestsFromModule</tt> method does: it introspects into each module and returns a <tt class="literal">unittest.TestSuite</tt> object for each module. Each <tt class="literal">TestSuite</tt> object actually contains a list of <tt class="literal">TestSuite</tt> objects, one for each <tt class="literal">TestCase</tt> class in your module, and each of those <tt class="literal">TestSuite</tt> objects contains a list of tests, one for each test method in your module.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.alltogether.5.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Finally, you wrap the list of <tt class="literal">TestSuite</tt> objects into one big test suite. The <tt class="filename">unittest</tt> module has no problem traversing this tree of nested test suites within test suites; eventually it gets down to an individual
+ test method and executes it, verifies that it passes or fails, and moves on to the next one.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>This introspection process is what the <tt class="filename">unittest</tt> module usually does for us. Remember that magic-looking <tt class="literal">unittest.main()</tt> function that our individual test modules called to kick the whole thing off? <tt class="function">unittest.main()</tt> actually creates an instance of <tt class="literal">unittest.TestProgram</tt>, which in turn creates an instance of a <tt class="literal">unittest.defaultTestLoader</tt> and loads it up with the module that called it. (How does it get a reference to the module that called it if you don't give
+ it one? By using the equally-magic <tt class="literal">__import__('__main__')</tt> command, which dynamically imports the currently-running module. I could write a book on all the tricks and techniques used
+ in the <tt class="filename">unittest</tt> module, but then I'd never finish this one.)
+ </p>
+ <div class="example"><a name="d0e36869"></a><h3 class="title">Example&nbsp;16.22.&nbsp;Step 6: Telling <tt class="filename">unittest</tt> to use your test suite
+ </h3><pre class="programlisting"><span class='pykeyword'>
+if</span> __name__ == <span class='pystring'>"__main__"</span>:
+ unittest.main(defaultTest=<span class='pystring'>"regressionTest"</span>) <a name="regression.alltogether.6.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+</pre></div>
+ <div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.alltogether.6.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Instead of letting the <tt class="filename">unittest</tt> module do all its magic for us, you've done most of it yourself. You've created a function (<tt class="function">regressionTest</tt>) that imports the modules yourself, calls <tt class="literal">unittest.defaultTestLoader</tt> yourself, and wraps it all up in a test suite. Now all you need to do is tell <tt class="filename">unittest</tt> that, instead of looking for tests and building a test suite in the usual way, it should just call the <tt class="function">regressionTest</tt> function, which returns a ready-to-use <tt class="literal">TestSuite</tt>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="dynamic_import.html">&lt;&lt;&nbsp;Dynamically importing modules</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#regression.divein" title="16.1.&nbsp;Diving in">1</a> <span class="divider">|</span> <a href="finding_the_path.html" title="16.2.&nbsp;Finding the path">2</a> <span class="divider">|</span> <a href="filtering_lists.html" title="16.3.&nbsp;Filtering lists revisited">3</a> <span class="divider">|</span> <a href="mapping_lists.html" title="16.4.&nbsp;Mapping lists revisited">4</a> <span class="divider">|</span> <a href="data_centric.html" title="16.5.&nbsp;Data-centric programming">5</a> <span class="divider">|</span> <a href="dynamic_import.html" title="16.6.&nbsp;Dynamically importing modules">6</a> <span class="divider">|</span> <span class="thispage">7</span> <span class="divider">|</span> <a href="summary.html" title="16.8.&nbsp;Summary">8</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="summary.html">Summary&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/functional_programming/data_centric.html b/help/diveintopython-5.4/html/functional_programming/data_centric.html
new file mode 100644
index 0000000..817c3fd
--- /dev/null
+++ b/help/diveintopython-5.4/html/functional_programming/data_centric.html
@@ -0,0 +1,96 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>16.5.&nbsp;Data-centric programming</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;16.&nbsp;Functional Programming">
+ <link rel="previous" href="mapping_lists.html" title="16.4.&nbsp;Mapping lists revisited">
+ <link rel="next" href="dynamic_import.html" title="16.6.&nbsp;Dynamically importing modules">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Functional Programming</a>&nbsp;&gt;&nbsp;<span class="thispage">Data-centric programming</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="mapping_lists.html" title="Prev: &#8220;Mapping lists revisited&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="dynamic_import.html" title="Next: &#8220;Dynamically importing modules&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="regression.datacentric"></a>16.5.&nbsp;Data-centric programming
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>By now you're probably scratching your head wondering why this is better than using <tt class="literal">for</tt> loops and straight function calls. And that's a perfectly valid question. Mostly, it's a matter of perspective. Using
+ <tt class="function">map</tt> and <tt class="function">filter</tt> forces you to center your thinking around your data.
+ </p>
+ </div>
+ <p>In this case, you started with no data at all; the first thing you did was <a href="finding_the_path.html" title="16.2.&nbsp;Finding the path">get the directory path</a> of the current script, and got a list of files in that directory. That was the bootstrap, and it gave you real data to work
+ with: a list of filenames.
+ </p>
+ <p>However, you knew you didn't care about all of those files, only the ones that were actually test suites. You had <span class="emphasis"><em>too much data</em></span>, so you needed to <tt class="function">filter</tt> it. How did you know which data to keep? You needed a test to decide, so you defined one and passed it to the <tt class="function">filter</tt> function. In this case you used a regular expression to decide, but the concept would be the same regardless of how you
+ constructed the test.
+ </p>
+ <p>Now you had the filenames of each of the test suites (and only the test suites, since everything else had been filtered out),
+ but you really wanted module names instead. You had the right amount of data, but it was <span class="emphasis"><em>in the wrong format</em></span>. So you defined a function that would transform a single filename into a module name, and you mapped that function onto
+ the entire list. From one filename, you can get a module name; from a list of filenames, you can get a list of module names.
+ </p>
+ <p>Instead of <tt class="function">filter</tt>, you could have used a <tt class="literal">for</tt> loop with an <tt class="literal">if</tt> statement. Instead of <tt class="function">map</tt>, you could have used a <tt class="literal">for</tt> loop with a function call. But using <tt class="literal">for</tt> loops like that is busywork. At best, it simply wastes time; at worst, it introduces obscure bugs. For instance, you need
+ to figure out how to test for the condition &#8220;<span class="quote">is this file a test suite?</span>&#8221; anyway; that's the application-specific logic, and no language can write that for us. But once you've figured that out,
+ do you really want go to all the trouble of defining a new empty list and writing a <tt class="literal">for</tt> loop and an <tt class="literal">if</tt> statement and manually calling <tt class="function">append</tt> to add each element to the new list if it passes the condition and then keeping track of which variable holds the new filtered
+ data and which one holds the old unfiltered data? Why not just define the test condition, then let <span class="application">Python</span> do the rest of that work for us?
+ </p>
+ <p>Oh sure, you could try to be fancy and delete elements in place without creating a new list. But you've been burned by that
+ before. Trying to modify a data structure that you're looping through can be tricky. You delete an element, then loop to
+ the next element, and suddenly you've skipped one. Is <span class="application">Python</span> one of the languages that works that way? How long would it take you to figure it out? Would you remember for certain whether
+ it was safe the next time you tried? Programmers spend so much time and make so many mistakes dealing with purely technical
+ issues like this, and it's all pointless. It doesn't advance your program at all; it's just busywork.
+ </p>
+ <p>I resisted list comprehensions when I first learned <span class="application">Python</span>, and I resisted <tt class="function">filter</tt> and <tt class="function">map</tt> even longer. I insisted on making my life more difficult, sticking to the familiar way of <tt class="literal">for</tt> loops and <tt class="literal">if</tt> statements and step-by-step code-centric programming. And my <span class="application">Python</span> programs looked a lot like <span class="application">Visual Basic</span> programs, detailing every step of every operation in every function. And they had all the same types of little problems
+ and obscure bugs. And it was all pointless.
+ </p>
+ <p>Let it all go. Busywork code is not important. Data is important. And data is not difficult. It's only data. If you have
+ too much, filter it. If it's not what you want, map it. Focus on the data; leave the busywork behind.
+ </p>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="mapping_lists.html">&lt;&lt;&nbsp;Mapping lists revisited</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#regression.divein" title="16.1.&nbsp;Diving in">1</a> <span class="divider">|</span> <a href="finding_the_path.html" title="16.2.&nbsp;Finding the path">2</a> <span class="divider">|</span> <a href="filtering_lists.html" title="16.3.&nbsp;Filtering lists revisited">3</a> <span class="divider">|</span> <a href="mapping_lists.html" title="16.4.&nbsp;Mapping lists revisited">4</a> <span class="divider">|</span> <span class="thispage">5</span> <span class="divider">|</span> <a href="dynamic_import.html" title="16.6.&nbsp;Dynamically importing modules">6</a> <span class="divider">|</span> <a href="all_together.html" title="16.7.&nbsp;Putting it all together">7</a> <span class="divider">|</span> <a href="summary.html" title="16.8.&nbsp;Summary">8</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="dynamic_import.html">Dynamically importing modules&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/functional_programming/dynamic_import.html b/help/diveintopython-5.4/html/functional_programming/dynamic_import.html
new file mode 100644
index 0000000..d883d74
--- /dev/null
+++ b/help/diveintopython-5.4/html/functional_programming/dynamic_import.html
@@ -0,0 +1,161 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>16.6.&nbsp;Dynamically importing modules</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;16.&nbsp;Functional Programming">
+ <link rel="previous" href="data_centric.html" title="16.5.&nbsp;Data-centric programming">
+ <link rel="next" href="all_together.html" title="16.7.&nbsp;Putting it all together">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Functional Programming</a>&nbsp;&gt;&nbsp;<span class="thispage">Dynamically importing modules</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="data_centric.html" title="Prev: &#8220;Data-centric programming&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="all_together.html" title="Next: &#8220;Putting it all together&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="regression.import"></a>16.6.&nbsp;Dynamically importing modules
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>OK, enough philosophizing. Let's talk about dynamically importing modules.</p>
+ </div>
+ <p>First, let's look at how you normally import modules. The <tt class="literal">import <i class="replaceable">module</i></tt> syntax looks in the search path for the named module and imports it by name. You can even import multiple modules at once
+ this way, with a comma-separated list. You did this on the very first line of this chapter's script.
+ </p>
+ <div class="example"><a name="d0e36316"></a><h3 class="title">Example&nbsp;16.13.&nbsp;Importing multiple modules at once</h3><pre class="programlisting"><span class='pykeyword'>
+import</span> sys, os, re, unittest <a name="regression.import.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.import.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This imports four modules at once: <tt class="filename">sys</tt> (for system functions and access to the command line parameters), <tt class="filename">os</tt> (for operating system functions like directory listings), <tt class="filename">re</tt> (for regular expressions), and <tt class="filename">unittest</tt> (for unit testing).
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>Now let's do the same thing, but with dynamic imports.</p>
+ <div class="example"><a name="d0e36341"></a><h3 class="title">Example&nbsp;16.14.&nbsp;Importing modules dynamically</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">sys = __import__(<span class='pystring'>'sys'</span>)</span> <a name="regression.import.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">os = __import__(<span class='pystring'>'os'</span>)</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">re = __import__(<span class='pystring'>'re'</span>)</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">unittest = __import__(<span class='pystring'>'unittest'</span>)</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">sys</span> <a name="regression.import.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="computeroutput">&lt;module 'sys' (built-in)&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">os</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="computeroutput">&lt;module 'os' from '/usr/local/lib/python2.2/os.pyc'&gt;</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.import.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The built-in <tt class="function">__import__</tt> function accomplishes the same goal as using the <tt class="literal">import</tt> statement, but it's an actual function, and it takes a string as an argument.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.import.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The variable <tt class="varname">sys</tt> is now the <tt class="filename">sys</tt> module, just as if you had said <tt class="literal">import sys</tt>. The variable <tt class="varname">os</tt> is now the <tt class="filename">os</tt> module, and so forth.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>So <tt class="function">__import__</tt> imports a module, but takes a string argument to do it. In this case the module you imported was just a hard-coded string,
+ but it could just as easily be a variable, or the result of a function call. And the variable that you assign the module
+ to doesn't need to match the module name, either. You could import a series of modules and assign them to a list.
+ </p>
+ <div class="example"><a name="d0e36423"></a><h3 class="title">Example&nbsp;16.15.&nbsp;Importing a list of modules dynamically</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">moduleNames = [<span class='pystring'>'sys'</span>, <span class='pystring'>'os'</span>, <span class='pystring'>'re'</span>, <span class='pystring'>'unittest'</span>]</span> <a name="regression.import.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">moduleNames</span>
+<span class="computeroutput">['sys', 'os', 're', 'unittest']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">modules = map(__import__, moduleNames)</span> <a name="regression.import.3.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">modules</span> <a name="regression.import.3.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">[&lt;module 'sys' (built-in)&gt;,
+&lt;module 'os' from 'c:\Python22\lib\os.pyc'&gt;,
+&lt;module 're' from 'c:\Python22\lib\re.pyc'&gt;,
+&lt;module 'unittest' from 'c:\Python22\lib\unittest.pyc'&gt;]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">modules[0].version</span> <a name="regression.import.3.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">'2.2.2 (#37, Nov 26 2002, 10:24:37) [MSC 32 bit (Intel)]'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> sys</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">sys.version</span>
+<span class="computeroutput">'2.2.2 (#37, Nov 26 2002, 10:24:37) [MSC 32 bit (Intel)]'</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.import.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="varname">moduleNames</tt> is just a list of strings. Nothing fancy, except that the strings happen to be names of modules that you could import, if
+ you wanted to.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.import.3.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Surprise, you wanted to import them, and you did, by mapping the <tt class="function">__import__</tt> function onto the list. Remember, this takes each element of the list (<tt class="varname">moduleNames</tt>) and calls the function (<tt class="function">__import__</tt>) over and over, once with each element of the list, builds a list of the return values, and returns the result.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.import.3.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">So now from a list of strings, you've created a list of actual modules. (Your paths may be different, depending on your operating
+ system, where you installed Python, the phase of the moon, etc.)
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.import.3.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">To drive home the point that these are real modules, let's look at some module attributes. Remember, <tt class="varname">modules[0]</tt> <span class="emphasis"><em>is</em></span> the <tt class="filename">sys</tt> module, so <tt class="varname">modules[0].version</tt> <span class="emphasis"><em>is</em></span> <tt class="varname">sys.version</tt>. All the other attributes and methods of these modules are also available. There's nothing magic about the <tt class="literal">import</tt> statement, and there's nothing magic about modules. Modules are objects. Everything is an object.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>Now you should be able to put this all together and figure out what most of this chapter's code sample is doing.</p>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="data_centric.html">&lt;&lt;&nbsp;Data-centric programming</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#regression.divein" title="16.1.&nbsp;Diving in">1</a> <span class="divider">|</span> <a href="finding_the_path.html" title="16.2.&nbsp;Finding the path">2</a> <span class="divider">|</span> <a href="filtering_lists.html" title="16.3.&nbsp;Filtering lists revisited">3</a> <span class="divider">|</span> <a href="mapping_lists.html" title="16.4.&nbsp;Mapping lists revisited">4</a> <span class="divider">|</span> <a href="data_centric.html" title="16.5.&nbsp;Data-centric programming">5</a> <span class="divider">|</span> <span class="thispage">6</span> <span class="divider">|</span> <a href="all_together.html" title="16.7.&nbsp;Putting it all together">7</a> <span class="divider">|</span> <a href="summary.html" title="16.8.&nbsp;Summary">8</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="all_together.html">Putting it all together&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/functional_programming/filtering_lists.html b/help/diveintopython-5.4/html/functional_programming/filtering_lists.html
new file mode 100644
index 0000000..0270c54
--- /dev/null
+++ b/help/diveintopython-5.4/html/functional_programming/filtering_lists.html
@@ -0,0 +1,169 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>16.3.&nbsp;Filtering lists revisited</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;16.&nbsp;Functional Programming">
+ <link rel="previous" href="finding_the_path.html" title="16.2.&nbsp;Finding the path">
+ <link rel="next" href="mapping_lists.html" title="16.4.&nbsp;Mapping lists revisited">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Functional Programming</a>&nbsp;&gt;&nbsp;<span class="thispage">Filtering lists revisited</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="finding_the_path.html" title="Prev: &#8220;Finding the path&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="mapping_lists.html" title="Next: &#8220;Mapping lists revisited&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="regression.filter"></a>16.3.&nbsp;Filtering lists revisited
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>You're already familiar with <a href="../power_of_introspection/filtering_lists.html" title="4.5.&nbsp;Filtering Lists">using list comprehensions to filter lists</a>. There is another way to accomplish this same thing, which some people feel is more expressive.
+ </p>
+ </div>
+ <p><span class="application">Python</span> has a built-in <tt class="function">filter</tt> function which takes two arguments, a function and a list, and returns a list.<sup>[<a name="d0e35697" href="#ftn.d0e35697">7</a>]</sup> The function passed as the first argument to <tt class="function">filter</tt> must itself take one argument, and the list that <tt class="function">filter</tt> returns will contain all the elements from the list passed to <tt class="function">filter</tt> for which the function passed to <tt class="function">filter</tt> returns true.
+ </p>
+ <p>Got all that? It's not as difficult as it sounds.</p>
+ <div class="example"><a name="d0e35724"></a><h3 class="title">Example&nbsp;16.7.&nbsp;Introducing <tt class="function">filter</tt></h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>def</span><span class='pyclass'> odd</span>(n):</span> <a name="regression.filter.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">... </tt><span class="userinput"><span class='pykeyword'>return</span> n % 2</span>
+<tt class="prompt">... </tt>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li = [1, 2, 3, 5, 9, 10, 256, -3]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">filter(odd, li)</span> <a name="regression.filter.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">[1, 3, 5, 9, -3]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">[e <span class='pykeyword'>for</span> e <span class='pykeyword'>in</span> li <span class='pykeyword'>if</span> odd(e)]</span> <a name="regression.filter.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">filteredList = []</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>for</span> n <span class='pykeyword'>in</span> li:</span> <a name="regression.filter.1.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<tt class="prompt">... </tt><span class="userinput"><span class='pykeyword'>if</span> odd(n):</span>
+<tt class="prompt">... </tt><span class="userinput"> filteredList.append(n)</span>
+<tt class="prompt">... </tt>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">filteredList</span>
+<span class="computeroutput">[1, 3, 5, 9, -3]</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.filter.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">odd</tt> uses the built-in mod function &#8220;<span class="quote"><tt class="literal">%</tt></span>&#8221; to return <tt class="constant">True</tt> if <tt class="varname">n</tt> is odd and <tt class="constant">False</tt> if <tt class="varname">n</tt> is even.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.filter.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">filter</tt> takes two arguments, a function (<tt class="function">odd</tt>) and a list (<tt class="varname">li</tt>). It loops through the list and calls <tt class="function">odd</tt> with each element. If <tt class="function">odd</tt> returns a true value (remember, any non-zero value is true in <span class="application">Python</span>), then the element is included in the returned list, otherwise it is filtered out. The result is a list of only the odd
+ numbers from the original list, in the same order as they appeared in the original.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.filter.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You could accomplish the same thing using list comprehensions, as you saw in <a href="../power_of_introspection/filtering_lists.html" title="4.5.&nbsp;Filtering Lists">Section&nbsp;4.5, &#8220;Filtering Lists&#8221;</a>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.filter.1.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You could also accomplish the same thing with a <tt class="literal">for</tt> loop. Depending on your programming background, this may seem more &#8220;<span class="quote">straightforward</span>&#8221;, but functions like <tt class="function">filter</tt> are much more expressive. Not only is it easier to write, it's easier to read, too. Reading the <tt class="literal">for</tt> loop is like standing too close to a painting; you see all the details, but it may take a few seconds to be able to step
+ back and see the bigger picture: &#8220;<span class="quote">Oh, you're just filtering the list!</span>&#8221;
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="d0e35864"></a><h3 class="title">Example&nbsp;16.8.&nbsp;<tt class="function">filter</tt> in <tt class="filename">regression.py</tt></h3><pre class="programlisting">
+ files = os.listdir(path) <a name="regression.filter.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ test = re.compile(<span class='pystring'>"test\.py$"</span>, re.IGNORECASE) <a name="regression.filter.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+ files = filter(test.search, files) <a name="regression.filter.2.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.filter.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">As you saw in <a href="finding_the_path.html" title="16.2.&nbsp;Finding the path">Section&nbsp;16.2, &#8220;Finding the path&#8221;</a>, <tt class="varname">path</tt> may contain the full or partial pathname of the directory of the currently running script, or it may contain an empty string
+ if the script is being run from the current directory. Either way, <tt class="varname">files</tt> will end up with the names of the files in the same directory as this script you're running.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.filter.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This is a compiled regular expression. As you saw in <a href="../refactoring/refactoring.html" title="15.3.&nbsp;Refactoring">Section&nbsp;15.3, &#8220;Refactoring&#8221;</a>, if you're going to use the same regular expression over and over, you should compile it for faster performance. The compiled
+ object has a <tt class="function">search</tt> method which takes a single argument, the string to search. If the regular expression matches the string, the <tt class="function">search</tt> method returns a <tt class="classname">Match</tt> object containing information about the regular expression match; otherwise it returns <tt class="literal">None</tt>, the <span class="application">Python</span> null value.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.filter.2.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">For each element in the <tt class="varname">files</tt> list, you're going to call the <tt class="function">search</tt> method of the compiled regular expression object, <tt class="varname">test</tt>. If the regular expression matches, the method will return a <tt class="classname">Match</tt> object, which <span class="application">Python</span> considers to be true, so the element will be included in the list returned by <tt class="function">filter</tt>. If the regular expression does not match, the <tt class="function">search</tt> method will return <tt class="literal">None</tt>, which <span class="application">Python</span> considers to be false, so the element will not be included.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p><b>Historical note.&nbsp;</b>Versions of <span class="application">Python</span> prior to 2.0 did not have <a href="../native_data_types/mapping_lists.html" title="3.6.&nbsp;Mapping Lists">list comprehensions</a>, so you couldn't <a href="../power_of_introspection/filtering_lists.html" title="4.5.&nbsp;Filtering Lists">filter using list comprehensions</a>; the <tt class="function">filter</tt> function was the only game in town. Even with the introduction of list comprehensions in 2.0, some people still prefer the
+ old-style <tt class="function">filter</tt> (and its companion function, <tt class="function">map</tt>, which you'll see later in this chapter). Both techniques work at the moment, so which one you use is a matter of style.
+ There is discussion that <tt class="function">map</tt> and <tt class="function">filter</tt> might be deprecated in a future version of <span class="application">Python</span>, but no decision has been made.
+ </p>
+ <div class="example"><a name="d0e35972"></a><h3 class="title">Example&nbsp;16.9.&nbsp;Filtering using list comprehensions instead</h3><pre class="programlisting">
+ files = os.listdir(path)
+ test = re.compile(<span class='pystring'>"test\.py$"</span>, re.IGNORECASE)
+ files = [f <span class='pykeyword'>for</span> f <span class='pykeyword'>in</span> files <span class='pykeyword'>if</span> test.search(f)] <a name="regression.filter.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.filter.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This will accomplish exactly the same result as using the <tt class="function">filter</tt> function. Which way is more expressive? That's up to you.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="footnotes">
+ <h3 class="footnotetitle">Footnotes</h3>
+ <div class="footnote">
+ <p><sup>[<a name="ftn.d0e35697" href="#d0e35697">7</a>] </sup>Technically, the second argument to <tt class="function">filter</tt> can be any sequence, including lists, tuples, and custom classes that act like lists by defining the <tt class="function">__getitem__</tt> special method. If possible, <tt class="function">filter</tt> will return the same datatype as you give it, so filtering a list returns a list, but filtering a tuple returns a tuple.
+ </p>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="finding_the_path.html">&lt;&lt;&nbsp;Finding the path</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#regression.divein" title="16.1.&nbsp;Diving in">1</a> <span class="divider">|</span> <a href="finding_the_path.html" title="16.2.&nbsp;Finding the path">2</a> <span class="divider">|</span> <span class="thispage">3</span> <span class="divider">|</span> <a href="mapping_lists.html" title="16.4.&nbsp;Mapping lists revisited">4</a> <span class="divider">|</span> <a href="data_centric.html" title="16.5.&nbsp;Data-centric programming">5</a> <span class="divider">|</span> <a href="dynamic_import.html" title="16.6.&nbsp;Dynamically importing modules">6</a> <span class="divider">|</span> <a href="all_together.html" title="16.7.&nbsp;Putting it all together">7</a> <span class="divider">|</span> <a href="summary.html" title="16.8.&nbsp;Summary">8</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="mapping_lists.html">Mapping lists revisited&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/functional_programming/finding_the_path.html b/help/diveintopython-5.4/html/functional_programming/finding_the_path.html
new file mode 100644
index 0000000..7e4c633
--- /dev/null
+++ b/help/diveintopython-5.4/html/functional_programming/finding_the_path.html
@@ -0,0 +1,251 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>16.2.&nbsp;Finding the path</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;16.&nbsp;Functional Programming">
+ <link rel="previous" href="index.html" title="Chapter&nbsp;16.&nbsp;Functional Programming">
+ <link rel="next" href="filtering_lists.html" title="16.3.&nbsp;Filtering lists revisited">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Functional Programming</a>&nbsp;&gt;&nbsp;<span class="thispage">Finding the path</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="index.html" title="Prev: &#8220;Functional Programming&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="filtering_lists.html" title="Next: &#8220;Filtering lists revisited&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="regression.path"></a>16.2.&nbsp;Finding the path
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>When running <span class="application">Python</span> scripts from the command line, it is sometimes useful to know where the currently running script is located on disk.
+ </p>
+ </div>
+ <p>This is one of those obscure little tricks that is virtually impossible to figure out on your own, but simple to remember
+ once you see it. The key to it is <tt class="literal">sys.argv</tt>. As you saw in <a href="../xml_processing/index.html" title="Chapter&nbsp;9.&nbsp;XML Processing">Chapter&nbsp;9, <i>XML Processing</i></a>, this is a list that holds the list of command-line arguments. However, it also holds the name of the running script, exactly
+ as it was called from the command line, and this is enough information to determine its location.
+ </p>
+ <div class="example"><a name="d0e35359"></a><h3 class="title">Example&nbsp;16.3.&nbsp;<tt class="filename">fullpath.py</tt></h3>
+ <p>If you have not already done so, you can <a href="http://diveintopython.org/download/diveintopython-examples-5.4.zip" title="Download example scripts">download this and other examples</a> used in this book.
+ </p><pre class="programlisting"><span class='pykeyword'>
+import</span> sys, os
+
+<span class='pykeyword'>print</span> <span class='pystring'>'sys.argv[0] ='</span>, sys.argv[0] <a name="regression.path.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+pathname = os.path.dirname(sys.argv[0]) <a name="regression.path.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"><span class='pykeyword'>
+print</span> <span class='pystring'>'path ='</span>, pathname
+<span class='pykeyword'>print</span> <span class='pystring'>'full path ='</span>, os.path.abspath(pathname) <a name="regression.path.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.path.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Regardless of how you run a script, <tt class="literal">sys.argv[0]</tt> will always contain the name of the script, exactly as it appears on the command line. This may or may not include any path
+ information, as you'll see shortly.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.path.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">os.path.dirname</tt> takes a filename as a string and returns the directory path portion. If the given filename does not include any path information,
+ <tt class="function">os.path.dirname</tt> returns an empty string.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.path.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">os.path.abspath</tt> is the key here. It takes a pathname, which can be partial or even blank, and returns a fully qualified pathname.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p><tt class="function">os.path.abspath</tt> deserves further explanation. It is very flexible; it can take any kind of pathname.
+ </p>
+ <div class="example"><a name="d0e35399"></a><h3 class="title">Example&nbsp;16.4.&nbsp;Further explanation of <tt class="function">os.path.abspath</tt></h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> os</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">os.getcwd()</span> <a name="regression.path.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">/home/you</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">os.path.abspath(<span class='pystring'>''</span>)</span> <a name="regression.path.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">/home/you</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">os.path.abspath(<span class='pystring'>'.ssh'</span>)</span> <a name="regression.path.2.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">/home/you/.ssh</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">os.path.abspath(<span class='pystring'>'/home/you/.ssh'</span>)</span> <a name="regression.path.2.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">/home/you/.ssh</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">os.path.abspath(<span class='pystring'>'.ssh/../foo/'</span>)</span> <a name="regression.path.2.5"></a><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12">
+<span class="computeroutput">/home/you/foo</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.path.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">os.getcwd()</tt> returns the current working directory.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.path.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Calling <tt class="function">os.path.abspath</tt> with an empty string returns the current working directory, same as <tt class="function">os.getcwd()</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.path.2.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Calling <tt class="function">os.path.abspath</tt> with a partial pathname constructs a fully qualified pathname out of it, based on the current working directory.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.path.2.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Calling <tt class="function">os.path.abspath</tt> with a full pathname simply returns it.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.path.2.5"><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">os.path.abspath</tt> also <span class="emphasis"><em>normalizes</em></span> the pathname it returns. Note that this example worked even though I don't actually have a 'foo' directory. <tt class="function">os.path.abspath</tt> never checks your actual disk; this is all just string manipulation.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div><a name="os.path.abspath.exist.note"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">The pathnames and filenames you pass to <tt class="function">os.path.abspath</tt> do not need to exist.
+ </td>
+ </tr>
+ </table><a name="os.path.normpath.note"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%"><tt class="function">os.path.abspath</tt> not only constructs full path names, it also normalizes them. That means that if you are in the <tt class="filename">/usr/</tt> directory, <tt class="literal">os.path.abspath('bin/../local/bin')</tt> will return <tt class="filename">/usr/local/bin</tt>. It normalizes the path by making it as simple as possible. If you just want to normalize a pathname like this without
+ turning it into a full pathname, use <tt class="function">os.path.normpath</tt> instead.
+ </td>
+ </tr>
+ </table>
+ <div class="example"><a name="d0e35527"></a><h3 class="title">Example&nbsp;16.5.&nbsp;Sample output from <tt class="filename">fullpath.py</tt></h3><pre class="screen">
+<tt class="prompt">[you@localhost py]$ </tt><span class="userinput">python /home/you/diveintopython/common/py/fullpath.py</span> <a name="regression.path.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">sys.argv[0] = /home/you/diveintopython/common/py/fullpath.py
+path = /home/you/diveintopython/common/py
+full path = /home/you/diveintopython/common/py</span>
+<tt class="prompt">[you@localhost diveintopython]$ </tt><span class="userinput">python common/py/fullpath.py</span> <a name="regression.path.3.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">sys.argv[0] = common/py/fullpath.py
+path = common/py
+full path = /home/you/diveintopython/common/py</span>
+<tt class="prompt">[you@localhost diveintopython]$ </tt><span class="userinput">cd common/py</span>
+<tt class="prompt">[you@localhost py]$ </tt><span class="userinput">python fullpath.py</span> <a name="regression.path.3.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">sys.argv[0] = fullpath.py
+path =
+full path = /home/you/diveintopython/common/py</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.path.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">In the first case, <tt class="literal">sys.argv[0]</tt> includes the full path of the script. You can then use the <tt class="function">os.path.dirname</tt> function to strip off the script name and return the full directory name, and <tt class="function">os.path.abspath</tt> simply returns what you give it.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.path.3.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">If the script is run by using a partial pathname, <tt class="literal">sys.argv[0]</tt> will still contain exactly what appears on the command line. <tt class="function">os.path.dirname</tt> will then give you a partial pathname (relative to the current directory), and <tt class="function">os.path.abspath</tt> will construct a full pathname from the partial pathname.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.path.3.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">If the script is run from the current directory without giving any path, <tt class="function">os.path.dirname</tt> will simply return an empty string. Given an empty string, <tt class="function">os.path.abspath</tt> returns the current directory, which is what you want, since the script was run from the current directory.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div><a name="os.path.abspath.crossplatform.note"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">Like the other functions in the <tt class="filename">os</tt> and <tt class="filename">os.path</tt> modules, <tt class="function">os.path.abspath</tt> is cross-platform. Your results will look slightly different than my examples if you're running on Windows (which uses backslash
+ as a path separator) or <span class="abbrev">Mac</span> <span class="acronym">OS</span> (which uses colons), but they'll still work. That's the whole point of the <tt class="filename">os</tt> module.
+ </td>
+ </tr>
+ </table>
+ <p><b>Addendum.&nbsp;</b>One reader was dissatisfied with this solution, and wanted to be able to run all the unit tests in the current directory,
+ not the directory where <tt class="filename">regression.py</tt> is located. He suggests this approach instead:
+ </p>
+ <div class="example"><a name="regression.path.cwd.example"></a><h3 class="title">Example&nbsp;16.6.&nbsp;Running scripts in the current directory</h3><pre class="programlisting"><span class='pykeyword'>import</span> sys, os, re, unittest
+
+<span class='pykeyword'>def</span><span class='pyclass'> regressionTest</span>():
+ path = os.getcwd() <a name="regression.path.4.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ sys.path.append(path) <a name="regression.path.4.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+ files = os.listdir(path) <a name="regression.path.4.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.path.4.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Instead of setting <tt class="varname">path</tt> to the directory where the currently running script is located, you set it to the current working directory instead. This
+ will be whatever directory you were in before you ran the script, which is not necessarily the same as the directory the script
+ is in. (Read that sentence a few times until you get it.)
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.path.4.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Append this directory to the <span class="application">Python</span> library search path, so that when you dynamically import the unit test modules later, <span class="application">Python</span> can find them. You didn't need to do this when <tt class="varname">path</tt> was the directory of the currently running script, because <span class="application">Python</span> always looks in that directory.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.path.4.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The rest of the function is the same.</td>
+ </tr>
+ </table>
+ </div>
+ <p>This technique will allow you to re-use this <tt class="filename">regression.py</tt> script on multiple projects. Just put the script in a common directory, then change to the project's directory before running
+ it. All of that project's unit tests will be found and tested, instead of the unit tests in the common directory where <tt class="filename">regression.py</tt> is located.
+ </p>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="index.html">&lt;&lt;&nbsp;Functional Programming</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#regression.divein" title="16.1.&nbsp;Diving in">1</a> <span class="divider">|</span> <span class="thispage">2</span> <span class="divider">|</span> <a href="filtering_lists.html" title="16.3.&nbsp;Filtering lists revisited">3</a> <span class="divider">|</span> <a href="mapping_lists.html" title="16.4.&nbsp;Mapping lists revisited">4</a> <span class="divider">|</span> <a href="data_centric.html" title="16.5.&nbsp;Data-centric programming">5</a> <span class="divider">|</span> <a href="dynamic_import.html" title="16.6.&nbsp;Dynamically importing modules">6</a> <span class="divider">|</span> <a href="all_together.html" title="16.7.&nbsp;Putting it all together">7</a> <span class="divider">|</span> <a href="summary.html" title="16.8.&nbsp;Summary">8</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="filtering_lists.html">Filtering lists revisited&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/functional_programming/index.html b/help/diveintopython-5.4/html/functional_programming/index.html
new file mode 100644
index 0000000..de4e062
--- /dev/null
+++ b/help/diveintopython-5.4/html/functional_programming/index.html
@@ -0,0 +1,187 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>Chapter&nbsp;16.&nbsp;Functional Programming</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="../toc/index.html" title="Dive Into Python">
+ <link rel="previous" href="../refactoring/summary.html" title="15.5.&nbsp;Summary">
+ <link rel="next" href="finding_the_path.html" title="16.2.&nbsp;Finding the path">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<span class="thispage">Functional Programming</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="../refactoring/summary.html" title="Prev: &#8220;Summary&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="finding_the_path.html" title="Next: &#8220;Finding the path&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="chapter" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="regression"></a>Chapter&nbsp;16.&nbsp;Functional Programming
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="toc">
+ <ul>
+ <li><span class="section"><a href="index.html#regression.divein">16.1. Diving in</a></span></li>
+ <li><span class="section"><a href="finding_the_path.html">16.2. Finding the path</a></span></li>
+ <li><span class="section"><a href="filtering_lists.html">16.3. Filtering lists revisited</a></span></li>
+ <li><span class="section"><a href="mapping_lists.html">16.4. Mapping lists revisited</a></span></li>
+ <li><span class="section"><a href="data_centric.html">16.5. Data-centric programming</a></span></li>
+ <li><span class="section"><a href="dynamic_import.html">16.6. Dynamically importing modules</a></span></li>
+ <li><span class="section"><a href="all_together.html">16.7. Putting it all together</a></span></li>
+ <li><span class="section"><a href="summary.html">16.8. Summary</a></span></li>
+ </ul>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="regression.divein"></a>16.1.&nbsp;Diving in
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>In <a href="../unit_testing/index.html" title="Chapter&nbsp;13.&nbsp;Unit Testing">Chapter&nbsp;13, <i>Unit Testing</i></a>, you learned about the philosophy of unit testing. In <a href="../unit_testing/stage_1.html" title="Chapter&nbsp;14.&nbsp;Test-First Programming">Chapter&nbsp;14, <i>Test-First Programming</i></a>, you stepped through the implementation of basic unit tests in <span class="application">Python</span>. In <a href="../refactoring/index.html" title="Chapter&nbsp;15.&nbsp;Refactoring">Chapter&nbsp;15, <i>Refactoring</i></a>, you saw how unit testing makes large-scale refactoring easier. This chapter will build on those sample programs, but here
+ we will focus more on advanced <span class="application">Python</span>-specific techniques, rather than on unit testing itself.
+ </p>
+ </div>
+ <p>The following is a complete <span class="application">Python</span> program that acts as a cheap and simple regression testing framework. It takes unit tests that you've written for individual
+ modules, collects them all into one big test suite, and runs them all at once. I actually use this script as part of the
+ build process for this book; I have unit tests for several of the example programs (not just the <tt class="filename">roman.py</tt> module featured in <a href="../unit_testing/index.html" title="Chapter&nbsp;13.&nbsp;Unit Testing">Chapter&nbsp;13, <i>Unit Testing</i></a>), and the first thing my automated build script does is run this program to make sure all my examples still work. If this
+ regression test fails, the build immediately stops. I don't want to release non-working examples any more than you want to
+ download them and sit around scratching your head and yelling at your monitor and wondering why they don't work.
+ </p>
+ <div class="example"><a name="d0e35275"></a><h3 class="title">Example&nbsp;16.1.&nbsp;<tt class="filename">regression.py</tt></h3>
+ <p>If you have not already done so, you can <a href="http://diveintopython.org/download/diveintopython-examples-5.4.zip" title="Download example scripts">download this and other examples</a> used in this book.
+ </p><pre class="programlisting">
+<span class='pystring'>"""Regression testing framework
+
+This module will search for scripts in the same directory named
+XYZtest.py. Each such script should be a test suite that tests a
+module through PyUnit. (As of Python 2.1, PyUnit is included in
+the standard library as "unittest".) This script will aggregate all
+found test suites into one big test suite and run them all at once.
+"""</span>
+
+<span class='pykeyword'>import</span> sys, os, re, unittest
+
+<span class='pykeyword'>def</span><span class='pyclass'> regressionTest</span>():
+ path = os.path.abspath(os.path.dirname(sys.argv[0]))
+ files = os.listdir(path)
+ test = re.compile(<span class='pystring'>"test\.py$"</span>, re.IGNORECASE)
+ files = filter(test.search, files)
+ filenameToModuleName = <span class='pykeyword'>lambda</span> f: os.path.splitext(f)[0]
+ moduleNames = map(filenameToModuleName, files)
+ modules = map(__import__, moduleNames)
+ load = unittest.defaultTestLoader.loadTestsFromModule
+ <span class='pykeyword'>return</span> unittest.TestSuite(map(load, modules))
+
+<span class='pykeyword'>if</span> __name__ == <span class='pystring'>"__main__"</span>:
+ unittest.main(defaultTest=<span class='pystring'>"regressionTest"</span>)
+</pre></div>
+ <p>Running this script in the same directory as the rest of the example scripts that come with this book will find all the unit
+ tests, named <tt class="filename"><i class="replaceable"><tt>module</tt></i>test.py</tt>, run them as a single test, and pass or fail them all at once.
+ </p>
+ <div class="example"><a name="d0e35293"></a><h3 class="title">Example&nbsp;16.2.&nbsp;Sample output of <tt class="filename">regression.py</tt></h3><pre class="screen">
+<tt class="prompt">[you@localhost py]$ </tt><span class="userinput">python regression.py -v</span>
+<span class="computeroutput">help should fail with no object ... ok </span><a name="regression.divein.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"><span class="computeroutput">
+help should return known result for apihelper ... ok
+help should honor collapse argument ... ok
+help should honor spacing argument ... ok
+buildConnectionString should fail with list input ... ok </span><a name="regression.divein.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"><span class="computeroutput">
+buildConnectionString should fail with string input ... ok
+buildConnectionString should fail with tuple input ... ok
+buildConnectionString handles empty dictionary ... ok
+buildConnectionString returns known result with known input ... ok
+fromRoman should only accept uppercase input ... ok </span><a name="regression.divein.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"><span class="computeroutput">
+toRoman should always return uppercase ... ok
+fromRoman should fail with blank string ... ok
+fromRoman should fail with malformed antecedents ... ok
+fromRoman should fail with repeated pairs of numerals ... ok
+fromRoman should fail with too many repeated numerals ... ok
+fromRoman should give known result with known input ... ok
+toRoman should give known result with known input ... ok
+fromRoman(toRoman(n))==n for all n ... ok
+toRoman should fail with non-integer input ... ok
+toRoman should fail with negative input ... ok
+toRoman should fail with large input ... ok
+toRoman should fail with 0 input ... ok
+kgp a ref test ... ok
+kgp b ref test ... ok
+kgp c ref test ... ok
+kgp d ref test ... ok
+kgp e ref test ... ok
+kgp f ref test ... ok
+kgp g ref test ... ok
+
+----------------------------------------------------------------------
+Ran 29 tests in 2.799s
+
+OK</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.divein.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The first 5 tests are from <tt class="filename">apihelpertest.py</tt>, which tests the example script from <a href="../power_of_introspection/index.html" title="Chapter&nbsp;4.&nbsp;The Power Of Introspection">Chapter&nbsp;4, <i>The Power Of Introspection</i></a>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.divein.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The next 5 tests are from <tt class="filename">odbchelpertest.py</tt>, which tests the example script from <a href="../getting_to_know_python/index.html" title="Chapter&nbsp;2.&nbsp;Your First Python Program">Chapter&nbsp;2, <i>Your First Python Program</i></a>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.divein.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The rest are from <tt class="filename">romantest.py</tt>, which you studied in depth in <a href="../unit_testing/index.html" title="Chapter&nbsp;13.&nbsp;Unit Testing">Chapter&nbsp;13, <i>Unit Testing</i></a>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="../refactoring/summary.html">&lt;&lt;&nbsp;Summary</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<span class="thispage">1</span> <span class="divider">|</span> <a href="finding_the_path.html" title="16.2.&nbsp;Finding the path">2</a> <span class="divider">|</span> <a href="filtering_lists.html" title="16.3.&nbsp;Filtering lists revisited">3</a> <span class="divider">|</span> <a href="mapping_lists.html" title="16.4.&nbsp;Mapping lists revisited">4</a> <span class="divider">|</span> <a href="data_centric.html" title="16.5.&nbsp;Data-centric programming">5</a> <span class="divider">|</span> <a href="dynamic_import.html" title="16.6.&nbsp;Dynamically importing modules">6</a> <span class="divider">|</span> <a href="all_together.html" title="16.7.&nbsp;Putting it all together">7</a> <span class="divider">|</span> <a href="summary.html" title="16.8.&nbsp;Summary">8</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="finding_the_path.html">Finding the path&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/functional_programming/mapping_lists.html b/help/diveintopython-5.4/html/functional_programming/mapping_lists.html
new file mode 100644
index 0000000..035f43a
--- /dev/null
+++ b/help/diveintopython-5.4/html/functional_programming/mapping_lists.html
@@ -0,0 +1,155 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>16.4.&nbsp;Mapping lists revisited</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;16.&nbsp;Functional Programming">
+ <link rel="previous" href="filtering_lists.html" title="16.3.&nbsp;Filtering lists revisited">
+ <link rel="next" href="data_centric.html" title="16.5.&nbsp;Data-centric programming">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Functional Programming</a>&nbsp;&gt;&nbsp;<span class="thispage">Mapping lists revisited</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="filtering_lists.html" title="Prev: &#8220;Filtering lists revisited&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="data_centric.html" title="Next: &#8220;Data-centric programming&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="regression.map"></a>16.4.&nbsp;Mapping lists revisited
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>You're already familiar with using <a href="../native_data_types/mapping_lists.html" title="3.6.&nbsp;Mapping Lists">list comprehensions</a> to map one list into another. There is another way to accomplish the same thing, using the built-in <tt class="function">map</tt> function. It works much the same way as the <a href="filtering_lists.html" title="16.3.&nbsp;Filtering lists revisited"><tt class="function">filter</tt></a> function.
+ </p>
+ </div>
+ <div class="example"><a name="d0e36003"></a><h3 class="title">Example&nbsp;16.10.&nbsp;Introducing <tt class="function">map</tt></h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>def</span><span class='pyclass'> double</span>(n):</span>
+<tt class="prompt">... </tt>return n*2
+<tt class="prompt">... </tt>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li = [1, 2, 3, 5, 9, 10, 256, -3]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">map(double, li)</span> <a name="regression.map.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">[2, 4, 6, 10, 18, 20, 512, -6]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">[double(n) <span class='pykeyword'>for</span> n <span class='pykeyword'>in</span> li]</span> <a name="regression.map.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">[2, 4, 6, 10, 18, 20, 512, -6]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">newlist = []</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>for</span> n <span class='pykeyword'>in</span> li:</span> <a name="regression.map.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<tt class="prompt">... </tt><span class="userinput">newlist.append(double(n))</span>
+<tt class="prompt">... </tt>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">newlist</span>
+<span class="computeroutput">[2, 4, 6, 10, 18, 20, 512, -6]</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.map.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">map</tt> takes a function and a list<sup>[<a name="d0e36079" href="#ftn.d0e36079">8</a>]</sup> and returns a new list by calling the function with each element of the list in order. In this case, the function simply
+ multiplies each element by 2.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.map.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You could accomplish the same thing with a list comprehension. List comprehensions were first introduced in <span class="application">Python</span> 2.0; <tt class="function">map</tt> has been around forever.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.map.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You could, if you insist on thinking like a <span class="application">Visual Basic</span> programmer, use a <tt class="literal">for</tt> loop to accomplish the same thing.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="d0e36107"></a><h3 class="title">Example&nbsp;16.11.&nbsp;<tt class="function">map</tt> with lists of mixed datatypes
+ </h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li = [5, <span class='pystring'>'a'</span>, (2, <span class='pystring'>'b'</span>)]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">map(double, li)</span> <a name="regression.map.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">[10, 'aa', (2, 'b', 2, 'b')]</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.map.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">As a side note, I'd like to point out that <tt class="function">map</tt> works just as well with lists of mixed datatypes, as long as the function you're using correctly handles each type. In this
+ case, the <tt class="function">double</tt> function simply multiplies the given argument by 2, and <span class="application">Python</span> Does The Right Thing depending on the datatype of the argument. For integers, this means actually multiplying it by 2; for
+ strings, it means concatenating the string with itself; for tuples, it means making a new tuple that has all of the elements
+ of the original, then all of the elements of the original again.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>All right, enough play time. Let's look at some real code.</p>
+ <div class="example"><a name="d0e36143"></a><h3 class="title">Example&nbsp;16.12.&nbsp;<tt class="function">map</tt> in <tt class="filename">regression.py</tt></h3><pre class="programlisting">
+ filenameToModuleName = <span class='pykeyword'>lambda</span> f: os.path.splitext(f)[0] <a name="regression.map.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ moduleNames = map(filenameToModuleName, files) <a name="regression.map.3.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.map.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">As you saw in <a href="../power_of_introspection/lambda_functions.html" title="4.7.&nbsp;Using lambda Functions">Section&nbsp;4.7, &#8220;Using lambda Functions&#8221;</a>, <tt class="literal">lambda</tt> defines an inline function. And as you saw in <a href="../file_handling/os_module.html#splittingpathnames.example" title="Example&nbsp;6.17.&nbsp;Splitting Pathnames">Example&nbsp;6.17, &#8220;Splitting Pathnames&#8221;</a>, <tt class="function">os.path.splitext</tt> takes a filename and returns a tuple <tt class="literal">(<i class="replaceable">name</i>, <i class="replaceable">extension</i>)</tt>. So <tt class="function">filenameToModuleName</tt> is a function which will take a filename and strip off the file extension, and return just the name.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#regression.map.3.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Calling <tt class="function">map</tt> takes each filename listed in <tt class="varname">files</tt>, passes it to the function <tt class="function">filenameToModuleName</tt>, and returns a list of the return values of each of those function calls. In other words, you strip the file extension off
+ of each filename, and store the list of all those stripped filenames in <tt class="varname">moduleNames</tt>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>As you'll see in the rest of the chapter, you can extend this type of data-centric thinking all the way to the final goal,
+ which is to define and execute a single test suite that contains the tests from all of those individual test suites.
+ </p>
+ <div class="footnotes">
+ <h3 class="footnotetitle">Footnotes</h3>
+ <div class="footnote">
+ <p><sup>[<a name="ftn.d0e36079" href="#d0e36079">8</a>] </sup>Again, I should point out that <tt class="function">map</tt> can take a list, a tuple, or any object that acts like a sequence. See previous footnote about <tt class="function">filter</tt>.
+ </p>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="filtering_lists.html">&lt;&lt;&nbsp;Filtering lists revisited</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#regression.divein" title="16.1.&nbsp;Diving in">1</a> <span class="divider">|</span> <a href="finding_the_path.html" title="16.2.&nbsp;Finding the path">2</a> <span class="divider">|</span> <a href="filtering_lists.html" title="16.3.&nbsp;Filtering lists revisited">3</a> <span class="divider">|</span> <span class="thispage">4</span> <span class="divider">|</span> <a href="data_centric.html" title="16.5.&nbsp;Data-centric programming">5</a> <span class="divider">|</span> <a href="dynamic_import.html" title="16.6.&nbsp;Dynamically importing modules">6</a> <span class="divider">|</span> <a href="all_together.html" title="16.7.&nbsp;Putting it all together">7</a> <span class="divider">|</span> <a href="summary.html" title="16.8.&nbsp;Summary">8</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="data_centric.html">Data-centric programming&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/functional_programming/summary.html b/help/diveintopython-5.4/html/functional_programming/summary.html
new file mode 100644
index 0000000..673ecab
--- /dev/null
+++ b/help/diveintopython-5.4/html/functional_programming/summary.html
@@ -0,0 +1,81 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>16.8.&nbsp;Summary</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;16.&nbsp;Functional Programming">
+ <link rel="previous" href="all_together.html" title="16.7.&nbsp;Putting it all together">
+ <link rel="next" href="../dynamic_functions/index.html" title="Chapter&nbsp;17.&nbsp;Dynamic functions">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Functional Programming</a>&nbsp;&gt;&nbsp;<span class="thispage">Summary</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="all_together.html" title="Prev: &#8220;Putting it all together&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="../dynamic_functions/index.html" title="Next: &#8220;Dynamic functions&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="regression.summary"></a>16.8.&nbsp;Summary
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>The <tt class="filename">regression.py</tt> program and its output should now make perfect sense.
+ </p>
+ </div>
+ <p>You should now feel comfortable doing all of these things:</p>
+ <div class="itemizedlist">
+ <ul>
+ <li>Manipulating <a href="finding_the_path.html" title="16.2.&nbsp;Finding the path">path information</a> from the command line.
+ </li>
+ <li>Filtering lists <a href="filtering_lists.html" title="16.3.&nbsp;Filtering lists revisited">using <tt class="function">filter</tt></a> instead of list comprehensions.
+ </li>
+ <li>Mapping lists <a href="mapping_lists.html" title="16.4.&nbsp;Mapping lists revisited">using <tt class="function">map</tt></a> instead of list comprehensions.
+ </li>
+ <li>Dynamically <a href="dynamic_import.html" title="16.6.&nbsp;Dynamically importing modules">importing modules</a>.
+ </li>
+ </ul>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="all_together.html">&lt;&lt;&nbsp;Putting it all together</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#regression.divein" title="16.1.&nbsp;Diving in">1</a> <span class="divider">|</span> <a href="finding_the_path.html" title="16.2.&nbsp;Finding the path">2</a> <span class="divider">|</span> <a href="filtering_lists.html" title="16.3.&nbsp;Filtering lists revisited">3</a> <span class="divider">|</span> <a href="mapping_lists.html" title="16.4.&nbsp;Mapping lists revisited">4</a> <span class="divider">|</span> <a href="data_centric.html" title="16.5.&nbsp;Data-centric programming">5</a> <span class="divider">|</span> <a href="dynamic_import.html" title="16.6.&nbsp;Dynamically importing modules">6</a> <span class="divider">|</span> <a href="all_together.html" title="16.7.&nbsp;Putting it all together">7</a> <span class="divider">|</span> <span class="thispage">8</span>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="../dynamic_functions/index.html">Dynamic functions&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/getting_to_know_python/declaring_functions.html b/help/diveintopython-5.4/html/getting_to_know_python/declaring_functions.html
new file mode 100644
index 0000000..605ff16
--- /dev/null
+++ b/help/diveintopython-5.4/html/getting_to_know_python/declaring_functions.html
@@ -0,0 +1,132 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>2.2.&nbsp;Declaring Functions</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;2.&nbsp;Your First Python Program">
+ <link rel="previous" href="index.html" title="Chapter&nbsp;2.&nbsp;Your First Python Program">
+ <link rel="next" href="documenting_functions.html" title="2.3.&nbsp;Documenting Functions">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Your First Python Program</a>&nbsp;&gt;&nbsp;<span class="thispage">Declaring Functions</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="index.html" title="Prev: &#8220;Your First Python Program&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="documenting_functions.html" title="Next: &#8220;Documenting Functions&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="odbchelper.funcdef"></a>2.2.&nbsp;Declaring Functions
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="toc">
+ <ul>
+ <li><span class="section"><a href="declaring_functions.html#d0e4188">2.2.1. How Python's Datatypes Compare to Other Programming Languages</a></span></li>
+ </ul>
+ </div>
+ <div class="abstract">
+ <p><span class="application">Python</span> has functions like most other languages, but it does not have separate header files like <span class="application"><span class="acronym">C++</span></span> or <tt class="literal">interface</tt>/<tt class="literal">implementation</tt> sections like <span class="application">Pascal</span>. When you need a function, just declare it, like this:
+ </p>
+ </div>
+ <div class="informalexample"><pre class="programlisting"><span class='pykeyword'>
+def</span> buildConnectionString(params):</pre></div>
+ <p>Note that the keyword <tt class="literal">def</tt> starts the function declaration, followed by the function name, followed by the arguments in parentheses. Multiple arguments
+ (not shown here) are separated with commas.
+ </p>
+ <p>Also note that the function doesn't define a return datatype. <span class="application">Python</span> functions do not specify the datatype of their return value; they don't even specify whether or not they return a value.
+ In fact, every <span class="application">Python</span> function returns a value; if the function ever executes a <tt class="literal">return</tt> statement, it will return that value, otherwise it will return <tt class="literal">None</tt>, the <span class="application">Python</span> null value.
+ </p><a name="compare.funcdef.vb"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">In <span class="application">Visual Basic</span>, functions (that return a value) start with <tt class="literal">function</tt>, and subroutines (that do not return a value) start with <tt class="literal">sub</tt>. There are no subroutines in <span class="application">Python</span>. Everything is a function, all functions return a value (even if it's <tt class="literal">None</tt>), and all functions start with <tt class="literal">def</tt>.
+ </td>
+ </tr>
+ </table>
+ <p>The argument, <tt class="literal">params</tt>, doesn't specify a datatype. In <span class="application">Python</span>, variables are never explicitly typed. <span class="application">Python</span> figures out what type a variable is and keeps track of it internally.
+ </p><a name="compare.funcdef.java"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">In <span class="application">Java</span>, <span class="application"><span class="acronym">C++</span></span>, and other statically-typed languages, you must specify the datatype of the function return value and each function argument.
+ In <span class="application">Python</span>, you never explicitly specify the datatype of anything. Based on what value you assign, <span class="application">Python</span> keeps track of the datatype internally.
+ </td>
+ </tr>
+ </table>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e4188"></a>2.2.1.&nbsp;How <span class="application">Python</span>'s Datatypes Compare to Other Programming Languages
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p>An erudite reader sent me this explanation of how <span class="application">Python</span> compares to other programming languages:
+ </p>
+ <div class="variablelist">
+ <dl>
+ <dt><span class="term">statically typed language</span></dt>
+ <dd>A language in which types are fixed at compile time. Most statically typed languages enforce this by requiring you to declare
+ all variables with their datatypes before using them. <span class="application">Java</span> and <span class="application"><span class="acronym">C</span></span> are statically typed languages.
+ </dd>
+ <dt><span class="term">dynamically typed language</span></dt>
+ <dd>A language in which types are discovered at execution time; the opposite of statically typed. <span class="application">VBScript</span> and <span class="application">Python</span> are dynamically typed, because they figure out what type a variable is when you first assign it a value.
+ </dd>
+ <dt><span class="term">strongly typed language</span></dt>
+ <dd>A language in which types are always enforced. <span class="application">Java</span> and <span class="application">Python</span> are strongly typed. If you have an integer, you can't treat it like a string without explicitly converting it.
+ </dd>
+ <dt><span class="term">weakly typed language</span></dt>
+ <dd>A language in which types may be ignored; the opposite of strongly typed. <span class="application">VBScript</span> is weakly typed. In <span class="application">VBScript</span>, you can concatenate the string <tt class="literal">'12'</tt> and the integer <tt class="literal">3</tt> to get the string <tt class="literal">'123'</tt>, then treat that as the integer <tt class="literal">123</tt>, all without any explicit conversion.
+ </dd>
+ </dl>
+ </div>
+ <p>So <span class="application">Python</span> is both <span class="emphasis"><em>dynamically typed</em></span> (because it doesn't use explicit datatype declarations) and <span class="emphasis"><em>strongly typed</em></span> (because once a variable has a datatype, it actually matters).
+ </p>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="index.html">&lt;&lt;&nbsp;Your First Python Program</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#odbchelper.divein" title="2.1.&nbsp;Diving in">1</a> <span class="divider">|</span> <span class="thispage">2</span> <span class="divider">|</span> <a href="documenting_functions.html" title="2.3.&nbsp;Documenting Functions">3</a> <span class="divider">|</span> <a href="everything_is_an_object.html" title="2.4.&nbsp;Everything Is an Object">4</a> <span class="divider">|</span> <a href="indenting_code.html" title="2.5.&nbsp;Indenting Code">5</a> <span class="divider">|</span> <a href="testing_modules.html" title="2.6.&nbsp;Testing Modules">6</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="documenting_functions.html">Documenting Functions&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/getting_to_know_python/documenting_functions.html b/help/diveintopython-5.4/html/getting_to_know_python/documenting_functions.html
new file mode 100644
index 0000000..1ffc66b
--- /dev/null
+++ b/help/diveintopython-5.4/html/getting_to_know_python/documenting_functions.html
@@ -0,0 +1,107 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>2.3.&nbsp;Documenting Functions</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;2.&nbsp;Your First Python Program">
+ <link rel="previous" href="declaring_functions.html" title="2.2.&nbsp;Declaring Functions">
+ <link rel="next" href="everything_is_an_object.html" title="2.4.&nbsp;Everything Is an Object">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Your First Python Program</a>&nbsp;&gt;&nbsp;<span class="thispage">Documenting Functions</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="declaring_functions.html" title="Prev: &#8220;Declaring Functions&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="everything_is_an_object.html" title="Next: &#8220;Everything Is an Object&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="odbchelper.docstring"></a>2.3.&nbsp;Documenting Functions
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>You can document a <span class="application">Python</span> function by giving it a <tt class="literal">doc string</tt>.
+ </p>
+ </div>
+ <div class="example"><a name="odbchelper.triplequotes"></a><h3 class="title">Example&nbsp;2.2.&nbsp;Defining the <tt class="function">buildConnectionString</tt> Function's <tt class="literal">doc string</tt></h3><pre class="programlisting"><span class='pykeyword'>
+def</span> buildConnectionString(params):
+ <span class='pystring'>"""Build a connection string from a dictionary of parameters.
+
+ Returns string."""</span></pre><p>Triple quotes signify a multi-line string. Everything between the start and end quotes is part of a single string, including
+ carriage returns and other quote characters. You can use them anywhere, but you'll see them most often used when defining
+ a <tt class="literal">doc string</tt>.
+ </p>
+ </div><a name="compare.quoting.perl"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">Triple quotes are also an easy way to define a string with both single and double quotes, like <tt class="literal">qq/.../</tt> in <span class="application">Perl</span>.
+ </td>
+ </tr>
+ </table>
+ <p>Everything between the triple quotes is the function's <tt class="literal">doc string</tt>, which documents what the function does. A <tt class="literal">doc string</tt>, if it exists, must be the first thing defined in a function (that is, the first thing after the colon). You don't technically
+ need to give your function a <tt class="literal">doc string</tt>, but you always should. I know you've heard this in every programming class you've ever taken, but <span class="application">Python</span> gives you an added incentive: the <tt class="literal">doc string</tt> is available at runtime as an attribute of the function.
+ </p><a name="tip.docstring"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">Many <span class="application">Python</span> <span class="acronym">IDE</span>s use the <tt class="literal">doc string</tt> to provide context-sensitive documentation, so that when you type a function name, its <tt class="literal">doc string</tt> appears as a tooltip. This can be incredibly helpful, but it's only as good as the <tt class="literal">doc string</tt>s you write.
+ </td>
+ </tr>
+ </table>
+ <div class="furtherreading">
+ <h3>Further Reading on Documenting Functions</h3>
+ <ul>
+ <li><a href="http://www.python.org/peps/pep-0257.html">PEP 257</a> defines <tt class="literal">doc string</tt> conventions.
+ </li>
+ <li><a href="http://www.python.org/doc/essays/styleguide.html"><i class="citetitle"><span class="application">Python</span> Style Guide</i></a> discusses how to write a good <tt class="literal">doc string</tt>.
+ </li>
+ <li><a href="http://www.python.org/doc/current/tut/tut.html"><i class="citetitle"><span class="application">Python</span> Tutorial</i></a> discusses conventions for <a href="http://www.python.org/doc/current/tut/node6.html#SECTION006750000000000000000">spacing in <tt class="literal">doc string</tt>s</a>.
+ </li>
+ </ul>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="declaring_functions.html">&lt;&lt;&nbsp;Declaring Functions</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#odbchelper.divein" title="2.1.&nbsp;Diving in">1</a> <span class="divider">|</span> <a href="declaring_functions.html" title="2.2.&nbsp;Declaring Functions">2</a> <span class="divider">|</span> <span class="thispage">3</span> <span class="divider">|</span> <a href="everything_is_an_object.html" title="2.4.&nbsp;Everything Is an Object">4</a> <span class="divider">|</span> <a href="indenting_code.html" title="2.5.&nbsp;Indenting Code">5</a> <span class="divider">|</span> <a href="testing_modules.html" title="2.6.&nbsp;Testing Modules">6</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="everything_is_an_object.html">Everything Is an Object&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/getting_to_know_python/everything_is_an_object.html b/help/diveintopython-5.4/html/getting_to_know_python/everything_is_an_object.html
new file mode 100644
index 0000000..7e9bcc3
--- /dev/null
+++ b/help/diveintopython-5.4/html/getting_to_know_python/everything_is_an_object.html
@@ -0,0 +1,196 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>2.4.&nbsp;Everything Is an Object</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;2.&nbsp;Your First Python Program">
+ <link rel="previous" href="documenting_functions.html" title="2.3.&nbsp;Documenting Functions">
+ <link rel="next" href="indenting_code.html" title="2.5.&nbsp;Indenting Code">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Your First Python Program</a>&nbsp;&gt;&nbsp;<span class="thispage">Everything Is an Object</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="documenting_functions.html" title="Prev: &#8220;Documenting Functions&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="indenting_code.html" title="Next: &#8220;Indenting Code&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="odbchelper.objects"></a>2.4.&nbsp;Everything Is an Object
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="toc">
+ <ul>
+ <li><span class="section"><a href="everything_is_an_object.html#d0e4550">2.4.1. The Import Search Path</a></span></li>
+ <li><span class="section"><a href="everything_is_an_object.html#d0e4665">2.4.2. What's an Object?</a></span></li>
+ </ul>
+ </div>
+ <p>In case you missed it, I just said that <span class="application">Python</span> functions have attributes, and that those attributes are available at runtime.
+ </p>
+ <div class="abstract">
+ <p>A function, like everything else in <span class="application">Python</span>, is an object.
+ </p>
+ </div>
+ <p>Open your favorite <span class="application">Python</span> <span class="acronym">IDE</span> and follow along:
+ </p>
+ <div class="example"><a name="odbchelper.import"></a><h3 class="title">Example&nbsp;2.3.&nbsp;Accessing the <tt class="function">buildConnectionString</tt> Function's <tt class="literal">doc string</tt></h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> odbchelper</span> <a name="odbchelper.objects.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">params = {<span class='pystring'>"server"</span>:<span class='pystring'>"mpilgrim"</span>, <span class='pystring'>"database"</span>:<span class='pystring'>"master"</span>, <span class='pystring'>"uid"</span>:<span class='pystring'>"sa"</span>, <span class='pystring'>"pwd"</span>:<span class='pystring'>"secret"</span>}</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> odbchelper.buildConnectionString(params)</span> <a name="odbchelper.objects.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">server=mpilgrim;uid=sa;database=master;pwd=secret</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> odbchelper.buildConnectionString.__doc__</span> <a name="odbchelper.objects.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">Build a connection string from a dictionary
+
+Returns string.</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.objects.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The first line imports the <tt class="filename">odbchelper</tt> program as a module -- a chunk of code that you can use interactively, or from a larger <span class="application">Python</span> program. (You'll see examples of multi-module <span class="application">Python</span> programs in <a href="../power_of_introspection/index.html">Chapter 4</a>.) Once you import a module, you can reference any of its public functions, classes, or attributes. Modules can do this
+ to access functionality in other modules, and you can do it in the <span class="acronym">IDE</span> too. This is an important concept, and you'll talk more about it later.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.objects.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">When you want to use functions defined in imported modules, you need to include the module name. So you can't just say <tt class="function">buildConnectionString</tt>; it must be <tt class="function">odbchelper.buildConnectionString</tt>. If you've used classes in <span class="application">Java</span>, this should feel vaguely familiar.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.objects.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Instead of calling the function as you would expect to, you asked for one of the function's attributes, <tt class="literal">__doc__</tt>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div><a name="compare.import.perl"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%"><tt class="literal">import</tt> in <span class="application">Python</span> is like <tt class="literal">require</tt> in <span class="application">Perl</span>. Once you <tt class="literal">import</tt> a <span class="application">Python</span> module, you access its functions with <tt class="literal"><i class="replaceable">module</i>.<i class="replaceable">function</i></tt>; once you <tt class="literal">require</tt> a <span class="application">Perl</span> module, you access its functions with <tt class="literal"><i class="replaceable">module</i>::<i class="replaceable">function</i></tt>.
+ </td>
+ </tr>
+ </table>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e4550"></a>2.4.1.&nbsp;The Import Search Path
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p>Before you go any further, I want to briefly mention the library search path. <span class="application">Python</span> looks in several places when you try to import a module. Specifically, it looks in all the directories defined in <tt class="varname">sys.path</tt>. This is just a list, and you can easily view it or modify it with standard list methods. (You'll learn more about lists
+ later in this chapter.)
+ </p>
+ <div class="example"><a name="odbchelper.objects.sys.path"></a><h3 class="title">Example&nbsp;2.4.&nbsp;Import Search Path</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> sys</span> <a name="odbchelper.objects.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">sys.path</span> <a name="odbchelper.objects.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">['', '/usr/local/lib/python2.2', '/usr/local/lib/python2.2/plat-linux2',
+'/usr/local/lib/python2.2/lib-dynload', '/usr/local/lib/python2.2/site-packages',
+'/usr/local/lib/python2.2/site-packages/PIL', '/usr/local/lib/python2.2/site-packages/piddle']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">sys</span> <a name="odbchelper.objects.2.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">&lt;module 'sys' (built-in)&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">sys.path.append(<span class='pystring'>'/my/new/path'</span>)</span> <a name="odbchelper.objects.2.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.objects.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Importing the <tt class="filename">sys</tt> module makes all of its functions and attributes available.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.objects.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="varname">sys.path</tt> is a list of directory names that constitute the current search path. (Yours will look different, depending on your operating
+ system, what version of <span class="application">Python</span> you're running, and where it was originally installed.) <span class="application">Python</span> will look through these directories (in this order) for a <tt class="literal">.py</tt> file matching the module name you're trying to import.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.objects.2.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Actually, I lied; the truth is more complicated than that, because not all modules are stored as <tt class="literal">.py</tt> files. Some, like the <tt class="filename">sys</tt> module, are "built-in modules"; they are actually baked right into <span class="application">Python</span> itself. Built-in modules behave just like regular modules, but their <span class="application">Python</span> source code is not available, because they are not written in <span class="application">Python</span>! (The <tt class="filename">sys</tt> module is written in <span class="application"><span class="acronym">C</span></span>.)
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.objects.2.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You can add a new directory to <span class="application">Python</span>'s search path at runtime by appending the directory name to <tt class="varname">sys.path</tt>, and then <span class="application">Python</span> will look in that directory as well, whenever you try to import a module. The effect lasts as long as <span class="application">Python</span> is running. (You'll talk more about <tt class="function">append</tt> and other list methods in <a href="../native_data_types/index.html">Chapter 3</a>.)
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e4665"></a>2.4.2.&nbsp;What's an Object?
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p>Everything in <span class="application">Python</span> is an object, and almost everything has attributes and methods. All functions have a built-in attribute <tt class="literal">__doc__</tt>, which returns the <tt class="literal">doc string</tt> defined in the function's source code. The <tt class="filename">sys</tt> module is an object which has (among other things) an attribute called <tt class="varname">path</tt>. And so forth.
+ </p>
+ <p>Still, this begs the question. What is an object? Different programming languages define &#8220;<span class="quote">object</span>&#8221; in different ways. In some, it means that <span class="emphasis"><em>all</em></span> objects <span class="emphasis"><em>must</em></span> have attributes and methods; in others, it means that all objects are subclassable. In <span class="application">Python</span>, the definition is looser; some objects have neither attributes nor methods (more on this in <a href="../native_data_types/index.html">Chapter 3</a>), and not all objects are subclassable (more on this in <a href="../object_oriented_framework/index.html">Chapter 5</a>). But everything is an object in the sense that it can be assigned to a variable or passed as an argument to a function
+ (more in this in <a href="../power_of_introspection/index.html">Chapter 4</a>).
+ </p>
+ <p>This is so important that I'm going to repeat it in case you missed it the first few times: <span class="emphasis"><em>everything in <span class="application">Python</span> is an object</em></span>. Strings are objects. Lists are objects. Functions are objects. Even modules are objects.
+ </p>
+ <div class="furtherreading">
+ <h3>Further Reading on Objects</h3>
+ <ul>
+ <li><a href="http://www.python.org/doc/current/ref/"><i class="citetitle"><span class="application">Python</span> Reference Manual</i></a> explains exactly what it means to say that <a href="http://www.python.org/doc/current/ref/objects.html">everything in <span class="application">Python</span> is an object</a>, because some people are pedantic and like to discuss this sort of thing at great length.
+ </li>
+ <li><a href="http://www.effbot.org/guides/">eff-bot</a> summarizes <a href="http://www.effbot.org/guides/python-objects.htm"><span class="application">Python</span> objects</a>.
+ </li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="documenting_functions.html">&lt;&lt;&nbsp;Documenting Functions</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#odbchelper.divein" title="2.1.&nbsp;Diving in">1</a> <span class="divider">|</span> <a href="declaring_functions.html" title="2.2.&nbsp;Declaring Functions">2</a> <span class="divider">|</span> <a href="documenting_functions.html" title="2.3.&nbsp;Documenting Functions">3</a> <span class="divider">|</span> <span class="thispage">4</span> <span class="divider">|</span> <a href="indenting_code.html" title="2.5.&nbsp;Indenting Code">5</a> <span class="divider">|</span> <a href="testing_modules.html" title="2.6.&nbsp;Testing Modules">6</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="indenting_code.html">Indenting Code&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/getting_to_know_python/indenting_code.html b/help/diveintopython-5.4/html/getting_to_know_python/indenting_code.html
new file mode 100644
index 0000000..54de53d
--- /dev/null
+++ b/help/diveintopython-5.4/html/getting_to_know_python/indenting_code.html
@@ -0,0 +1,142 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>2.5.&nbsp;Indenting Code</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;2.&nbsp;Your First Python Program">
+ <link rel="previous" href="everything_is_an_object.html" title="2.4.&nbsp;Everything Is an Object">
+ <link rel="next" href="testing_modules.html" title="2.6.&nbsp;Testing Modules">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Your First Python Program</a>&nbsp;&gt;&nbsp;<span class="thispage">Indenting Code</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="everything_is_an_object.html" title="Prev: &#8220;Everything Is an Object&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="testing_modules.html" title="Next: &#8220;Testing Modules&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="odbchelper.indenting"></a>2.5.&nbsp;Indenting Code
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p><span class="application">Python</span> functions have no explicit <tt class="literal">begin</tt> or <tt class="literal">end</tt>, and no curly braces to mark where the function code starts and stops. The only delimiter is a colon (<tt class="literal">:</tt>) and the indentation of the code itself.
+ </p>
+ </div>
+ <div class="example"><a name="d0e4759"></a><h3 class="title">Example&nbsp;2.5.&nbsp;Indenting the <tt class="function">buildConnectionString</tt> Function
+ </h3><pre class="programlisting"><span class='pykeyword'>
+def</span> buildConnectionString(params):
+ <span class='pystring'>"""Build a connection string from a dictionary of parameters.
+
+ Returns string."""</span>
+ <span class='pykeyword'>return</span> <span class='pystring'>";"</span>.join([<span class='pystring'>"%s=%s"</span> % (k, v) <span class='pykeyword'>for</span> k, v <span class='pykeyword'>in</span> params.items()])</pre></div>
+ <p>Code blocks are defined by their indentation. By "code block", I mean functions, <tt class="literal">if</tt> statements, <tt class="literal">for</tt> loops, <tt class="literal">while</tt> loops, and so forth. Indenting starts a block and unindenting ends it. There are no explicit braces, brackets, or keywords.
+ This means that whitespace is significant, and must be consistent. In this example, the function code (including the <tt class="literal">doc string</tt>) is indented four spaces. It doesn't need to be four spaces, it just needs to be consistent. The first line that is not
+ indented is outside the function.
+ </p>
+ <p><a href="indenting_code.html#odbchelper.indenting.if" title="Example&nbsp;2.6.&nbsp;if Statements">Example&nbsp;2.6, &#8220;if Statements&#8221;</a> shows an example of code indentation with <tt class="literal">if</tt> statements.
+ </p>
+ <div class="example"><a name="odbchelper.indenting.if"></a><h3 class="title">Example&nbsp;2.6.&nbsp;<tt class="literal">if</tt> Statements
+ </h3><pre class="programlisting"><span class='pykeyword'>
+def</span> fib(n): <a name="odbchelper.indenting.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ <span class='pykeyword'>print</span> <span class='pystring'>'n ='</span>, n <a name="odbchelper.indenting.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+ <span class='pykeyword'>if</span> n &gt; 1: <a name="odbchelper.indenting.2.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+ <span class='pykeyword'>return</span> n * fib(n - 1)
+ <span class='pykeyword'>else</span>: <a name="odbchelper.indenting.2.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+ <span class='pykeyword'>print</span> <span class='pystring'>'end of the line'</span>
+ <span class='pykeyword'>return</span> 1
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.indenting.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This is a function named <tt class="function">fib</tt> that takes one argument, <tt class="varname">n</tt>. All the code within the function is indented.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.indenting.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Printing to the screen is very easy in <span class="application">Python</span>, just use <tt class="function">print</tt>. <tt class="function">print</tt> statements can take any data type, including strings, integers, and other native types like dictionaries and lists that you'll
+ learn about in the next chapter. You can even mix and match to print several things on one line by using a comma-separated
+ list of values. Each value is printed on the same line, separated by spaces (the commas don't print). So when <tt class="function">fib</tt> is called with <tt class="literal">5</tt>, this will print "n = 5".
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.indenting.2.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="literal">if</tt> statements are a type of code block. If the <tt class="literal">if</tt> expression evaluates to true, the indented block is executed, otherwise it falls to the <tt class="literal">else</tt> block.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.indenting.2.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Of course <tt class="literal">if</tt> and <tt class="literal">else</tt> blocks can contain multiple lines, as long as they are all indented the same amount. This <tt class="literal">else</tt> block has two lines of code in it. There is no other special syntax for multi-line code blocks. Just indent and get on
+ with your life.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>After some initial protests and several snide analogies to <span class="application">Fortran</span>, you will make peace with this and start seeing its benefits. One major benefit is that all <span class="application">Python</span> programs look similar, since indentation is a language requirement and not a matter of style. This makes it easier to read
+ and understand other people's <span class="application">Python</span> code.
+ </p><a name="compare.lineend.java"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%"><span class="application">Python</span> uses carriage returns to separate statements and a colon and indentation to separate code blocks. <span class="application"><span class="acronym">C++</span></span> and <span class="application">Java</span> use semicolons to separate statements and curly braces to separate code blocks.
+ </td>
+ </tr>
+ </table>
+ <div class="furtherreading">
+ <h3>Further Reading on Code Indentation</h3>
+ <ul>
+ <li><a href="http://www.python.org/doc/current/ref/"><i class="citetitle"><span class="application">Python</span> Reference Manual</i></a> discusses cross-platform indentation issues and <a href="http://www.python.org/doc/current/ref/indentation.html">shows various indentation errors</a>.
+ </li>
+ <li><a href="http://www.python.org/doc/essays/styleguide.html"><i class="citetitle"><span class="application">Python</span> Style Guide</i></a> discusses good indentation style.
+ </li>
+ </ul>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="everything_is_an_object.html">&lt;&lt;&nbsp;Everything Is an Object</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#odbchelper.divein" title="2.1.&nbsp;Diving in">1</a> <span class="divider">|</span> <a href="declaring_functions.html" title="2.2.&nbsp;Declaring Functions">2</a> <span class="divider">|</span> <a href="documenting_functions.html" title="2.3.&nbsp;Documenting Functions">3</a> <span class="divider">|</span> <a href="everything_is_an_object.html" title="2.4.&nbsp;Everything Is an Object">4</a> <span class="divider">|</span> <span class="thispage">5</span> <span class="divider">|</span> <a href="testing_modules.html" title="2.6.&nbsp;Testing Modules">6</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="testing_modules.html">Testing Modules&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/getting_to_know_python/index.html b/help/diveintopython-5.4/html/getting_to_know_python/index.html
new file mode 100644
index 0000000..1b27929
--- /dev/null
+++ b/help/diveintopython-5.4/html/getting_to_know_python/index.html
@@ -0,0 +1,148 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>Chapter&nbsp;2.&nbsp;Your First Python Program</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="../toc/index.html" title="Dive Into Python">
+ <link rel="previous" href="../installing_python/summary.html" title="1.9.&nbsp;Summary">
+ <link rel="next" href="declaring_functions.html" title="2.2.&nbsp;Declaring Functions">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<span class="thispage">Your First Python Program</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="../installing_python/summary.html" title="Prev: &#8220;Summary&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="declaring_functions.html" title="Next: &#8220;Declaring Functions&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="chapter" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="odbchelper"></a>Chapter&nbsp;2.&nbsp;Your First <span class="application">Python</span> Program
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="toc">
+ <ul>
+ <li><span class="section"><a href="index.html#odbchelper.divein">2.1. Diving in</a></span></li>
+ <li><span class="section"><a href="declaring_functions.html">2.2. Declaring Functions</a></span><ul>
+ <li><span class="section"><a href="declaring_functions.html#d0e4188">2.2.1. How Python's Datatypes Compare to Other Programming Languages</a></span></li>
+ </ul>
+ </li>
+ <li><span class="section"><a href="documenting_functions.html">2.3. Documenting Functions</a></span></li>
+ <li><span class="section"><a href="everything_is_an_object.html">2.4. Everything Is an Object</a></span><ul>
+ <li><span class="section"><a href="everything_is_an_object.html#d0e4550">2.4.1. The Import Search Path</a></span></li>
+ <li><span class="section"><a href="everything_is_an_object.html#d0e4665">2.4.2. What's an Object?</a></span></li>
+ </ul>
+ </li>
+ <li><span class="section"><a href="indenting_code.html">2.5. Indenting Code</a></span></li>
+ <li><span class="section"><a href="testing_modules.html">2.6. Testing Modules</a></span></li>
+ </ul>
+ </div>
+ <div class="abstract">
+ <p>You know how other books go on and on about programming fundamentals and finally work up to building a complete, working program?
+ Let's skip all that.
+ </p>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="odbchelper.divein"></a>2.1.&nbsp;Diving in
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>Here is a complete, working <span class="application">Python</span> program.
+ </p>
+ </div>
+ <p>It probably makes absolutely no sense to you. Don't worry about that, because you're going to dissect it line by line. But
+ read through it first and see what, if anything, you can make of it.
+ </p>
+ <div class="example"><a name="d0e3948"></a><h3 class="title">Example&nbsp;2.1.&nbsp;<tt class="filename">odbchelper.py</tt></h3>
+ <p>If you have not already done so, you can <a href="http://diveintopython.org/download/diveintopython-examples-5.4.zip" title="Download example scripts">download this and other examples</a> used in this book.
+ </p><pre class="programlisting"><span class='pykeyword'>
+def</span> buildConnectionString(params):
+ <span class='pystring'>"""Build a connection string from a dictionary of parameters.
+
+ Returns string."""</span>
+ <span class='pykeyword'>return</span> <span class='pystring'>";"</span>.join([<span class='pystring'>"%s=%s"</span> % (k, v) <span class='pykeyword'>for</span> k, v <span class='pykeyword'>in</span> params.items()])
+
+<span class='pykeyword'>if</span> __name__ == <span class='pystring'>"__main__"</span>:
+ myParams = {<span class='pystring'>"server"</span>:<span class='pystring'>"mpilgrim"</span>, \
+ <span class='pystring'>"database"</span>:<span class='pystring'>"master"</span>, \
+ <span class='pystring'>"uid"</span>:<span class='pystring'>"sa"</span>, \
+ <span class='pystring'>"pwd"</span>:<span class='pystring'>"secret"</span> \
+ }
+ <span class='pykeyword'>print</span> buildConnectionString(myParams)</pre></div>
+ <p>Now run this program and see what happens.</p><a name="tip.run.windows"></a><table class="tip" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/tip.png" alt="Tip" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">In the <span class="application">ActivePython</span> <span class="acronym">IDE</span> on Windows, you can run the <span class="application">Python</span> program you're editing by choosing
+ <span class="guimenu">File</span>-&gt;<span class="guimenuitem"><span class="accel">R</span>un...</span> (<span><b class="shortcut"><span><b class="keycap">Ctrl</b></span>-<span class="keysym">R</span></b></span>). Output is displayed in the interactive window.
+ </td>
+ </tr>
+ </table><a name="tip.run.mac"></a><table class="tip" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/tip.png" alt="Tip" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">In the <span class="application">Python</span> <span class="acronym">IDE</span> on <span class="abbrev">Mac</span> <span class="acronym">OS</span>, you can run a <span class="application">Python</span> program with
+ <span class="guimenu">Python</span>-&gt;<span class="guimenuitem">Run window...</span> (<span><b class="shortcut"><span><b class="keycap">Cmd</b></span>-<span class="keysym">R</span></b></span>), but there is an important option you must set first. Open the <tt class="filename">.py</tt> file in the <span class="acronym">IDE</span>, pop up the options menu by clicking the black triangle in the upper-right corner of the window, and make sure the <span class="guimenuitem">Run as __main__</span> option is checked. This is a per-file setting, but you'll only need to do it once per file.
+ </td>
+ </tr>
+ </table><a name="tip.run.unix"></a><table class="tip" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/tip.png" alt="Tip" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">On <span class="acronym">UNIX</span>-compatible systems (including <span class="abbrev">Mac</span> <span class="acronym">OS</span> X), you can run a <span class="application">Python</span> program from the command line: <b class="userinput"><tt>python <tt class="filename">odbchelper.py</tt></tt></b></td>
+ </tr>
+ </table>
+ <div class="informalexample"><a name="odbchelper.output"></a><p>The output of <tt class="filename">odbchelper.py</tt> will look like this:
+ </p><pre class="screen"><span class="computeroutput">server=mpilgrim;uid=sa;database=master;pwd=secret</span></pre></div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="../installing_python/summary.html">&lt;&lt;&nbsp;Summary</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<span class="thispage">1</span> <span class="divider">|</span> <a href="declaring_functions.html" title="2.2.&nbsp;Declaring Functions">2</a> <span class="divider">|</span> <a href="documenting_functions.html" title="2.3.&nbsp;Documenting Functions">3</a> <span class="divider">|</span> <a href="everything_is_an_object.html" title="2.4.&nbsp;Everything Is an Object">4</a> <span class="divider">|</span> <a href="indenting_code.html" title="2.5.&nbsp;Indenting Code">5</a> <span class="divider">|</span> <a href="testing_modules.html" title="2.6.&nbsp;Testing Modules">6</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="declaring_functions.html">Declaring Functions&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/getting_to_know_python/testing_modules.html b/help/diveintopython-5.4/html/getting_to_know_python/testing_modules.html
new file mode 100644
index 0000000..40d3ad8
--- /dev/null
+++ b/help/diveintopython-5.4/html/getting_to_know_python/testing_modules.html
@@ -0,0 +1,106 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>2.6.&nbsp;Testing Modules</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;2.&nbsp;Your First Python Program">
+ <link rel="previous" href="indenting_code.html" title="2.5.&nbsp;Indenting Code">
+ <link rel="next" href="../native_data_types/index.html" title="Chapter&nbsp;3.&nbsp;Native Datatypes">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Your First Python Program</a>&nbsp;&gt;&nbsp;<span class="thispage">Testing Modules</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="indenting_code.html" title="Prev: &#8220;Indenting Code&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="../native_data_types/index.html" title="Next: &#8220;Native Datatypes&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="odbchelper.testing"></a>2.6.&nbsp;Testing Modules
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p><span class="application">Python</span> modules are objects and have several useful attributes. You can use this to easily test your modules as you write them.
+ Here's an example that uses the <tt class="literal">if</tt> <tt class="literal">__name__</tt> trick.
+ </p>
+ </div>
+ <div class="informalexample"><a name="odbchelper.ifnametrick"></a><pre class="programlisting"><span class='pykeyword'>
+if</span> __name__ == <span class='pystring'>"__main__"</span>:</pre></div>
+ <p>Some quick observations before you get to the good stuff. First, parentheses are not required around the <tt class="literal">if</tt> expression. Second, the <tt class="literal">if</tt> statement ends with a colon, and is followed by <a href="indenting_code.html" title="2.5.&nbsp;Indenting Code">indented code</a>.
+ </p><a name="compare.equals.c"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">Like <span class="application"><span class="acronym">C</span></span>, <span class="application">Python</span> uses <tt class="literal">==</tt> for comparison and <tt class="literal">=</tt> for assignment. Unlike <span class="application"><span class="acronym">C</span></span>, <span class="application">Python</span> does not support in-line assignment, so there's no chance of accidentally assigning the value you thought you were comparing.
+ </td>
+ </tr>
+ </table>
+ <p>So why is this particular <tt class="literal">if</tt> statement a trick? Modules are objects, and all modules have a built-in attribute <tt class="literal">__name__</tt>. A module's <tt class="literal">__name__</tt> depends on how you're using the module. If you <tt class="literal">import</tt> the module, then <tt class="literal">__name__</tt> is the module's filename, without a directory path or file extension. But you can also run the module directly as a standalone
+ program, in which case <tt class="literal">__name__</tt> will be a special default value, <tt class="literal">__main__</tt>.
+ </p>
+ <div class="informalexample"><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> odbchelper</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">odbchelper.<tt class="literal">__name__</tt></span>
+<span class="computeroutput">'odbchelper'</span></pre></div>
+ <p>Knowing this, you can design a test suite for your module within the module itself by putting it in this <tt class="literal">if</tt> statement. When you run the module directly, <tt class="literal">__name__</tt> is <tt class="literal">__main__</tt>, so the test suite executes. When you import the module, <tt class="literal">__name__</tt> is something else, so the test suite is ignored. This makes it easier to develop and debug new modules before integrating
+ them into a larger program.
+ </p><a name="tip.mac.runasmain"></a><table class="tip" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/tip.png" alt="Tip" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">On <span class="application">MacPython</span>, there is an additional step to make the <tt class="literal">if</tt> <tt class="literal">__name__</tt> trick work. Pop up the module's options menu by clicking the black triangle in the upper-right corner of the window, and
+ make sure <span class="guimenuitem">Run as __main__</span> is checked.
+ </td>
+ </tr>
+ </table>
+ <div class="furtherreading">
+ <h3>Further Reading on Importing Modules</h3>
+ <ul>
+ <li><a href="http://www.python.org/doc/current/ref/"><i class="citetitle"><span class="application">Python</span> Reference Manual</i></a> discusses the low-level details of <a href="http://www.python.org/doc/current/ref/import.html">importing modules</a>.
+ </li>
+ </ul>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="indenting_code.html">&lt;&lt;&nbsp;Indenting Code</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#odbchelper.divein" title="2.1.&nbsp;Diving in">1</a> <span class="divider">|</span> <a href="declaring_functions.html" title="2.2.&nbsp;Declaring Functions">2</a> <span class="divider">|</span> <a href="documenting_functions.html" title="2.3.&nbsp;Documenting Functions">3</a> <span class="divider">|</span> <a href="everything_is_an_object.html" title="2.4.&nbsp;Everything Is an Object">4</a> <span class="divider">|</span> <a href="indenting_code.html" title="2.5.&nbsp;Indenting Code">5</a> <span class="divider">|</span> <span class="thispage">6</span>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="../native_data_types/index.html">Native Datatypes&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/history.xml b/help/diveintopython-5.4/html/history.xml
new file mode 100644
index 0000000..0a3d1f7
--- /dev/null
+++ b/help/diveintopython-5.4/html/history.xml
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="utf-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"><channel><title>Dive Into Python</title><link>http://diveintopython.org/</link><description>Python from novice to pro</description><language>en</language><item><title>Revision 5.4</title><link>http://diveintopython.org/appendix/history.html#5.4</link><dc:date>2004-05-20</dc:date></item><item><title>Revision 5.3</title><link>http://diveintopython.org/appendix/history.html#5.3</link><dc:date>2004-05-12</dc:date></item><item><title>Revision 5.2</title><link>http://diveintopython.org/appendix/history.html#5.2</link><dc:date>2004-05-09</dc:date></item><item><title>Revision 5.1</title><link>http://diveintopython.org/appendix/history.html#5.1</link><dc:date>2004-05-05</dc:date></item><item><title>Revision 5.0</title><link>http://diveintopython.org/appendix/history.html#5.0</link><dc:date>2004-04-16</dc:date></item><item><title>Revision 4.9</title><link>http://diveintopython.org/appendix/history.html#4.9</link><dc:date>2004-03-25</dc:date></item><item><title>Revision 4.8</title><link>http://diveintopython.org/appendix/history.html#4.8</link><dc:date>2004-03-25</dc:date></item><item><title>Revision 4.7</title><link>http://diveintopython.org/appendix/history.html#4.7</link><dc:date>2004-03-21</dc:date></item><item><title>Revision 4.6</title><link>http://diveintopython.org/appendix/history.html#4.6</link><dc:date>2004-03-14</dc:date></item><item><title>Revision 4.5</title><link>http://diveintopython.org/appendix/history.html#4.5</link><dc:date>2004-03-07</dc:date></item><item><title>Revision 4.4</title><link>http://diveintopython.org/appendix/history.html#4.4</link><dc:date>2003-10-08</dc:date></item><item><title>Revision 4.3</title><link>http://diveintopython.org/appendix/history.html#4.3</link><dc:date>2003-09-28</dc:date></item><item><title>Revision 4.2.1</title><link>http://diveintopython.org/appendix/history.html#4.2.1</link><dc:date>2003-09-17</dc:date></item><item><title>Revision 4.2</title><link>http://diveintopython.org/appendix/history.html#4.2</link><dc:date>2003-09-12</dc:date></item></channel></rss> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/html_processing/all_together.html b/help/diveintopython-5.4/html/html_processing/all_together.html
new file mode 100644
index 0000000..05b38a4
--- /dev/null
+++ b/help/diveintopython-5.4/html/html_processing/all_together.html
@@ -0,0 +1,181 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>8.9.&nbsp;Putting it all together</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;8.&nbsp;HTML Processing">
+ <link rel="previous" href="dialect.html" title="8.8.&nbsp;Introducing dialect.py">
+ <link rel="next" href="summary.html" title="8.10.&nbsp;Summary">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">HTML Processing</a>&nbsp;&gt;&nbsp;<span class="thispage">Putting it all together</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="dialect.html" title="Prev: &#8220;Introducing dialect.py&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="summary.html" title="Next: &#8220;Summary&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="dialect.alltogether"></a>8.9.&nbsp;Putting it all together
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>It's time to put everything you've learned so far to good use. I hope you were paying attention.</p>
+ </div>
+ <div class="example"><a name="d0e22387"></a><h3 class="title">Example&nbsp;8.20.&nbsp;The <tt class="function">translate</tt> function, part 1
+ </h3><pre class="programlisting"><span class='pykeyword'>
+def</span> translate(url, dialectName=<span class='pystring'>"chef"</span>): <a name="dialect.alltogether.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ <span class='pykeyword'>import</span> urllib <a name="dialect.alltogether.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+ sock = urllib.urlopen(url) <a name="dialect.alltogether.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+ htmlSource = sock.read()
+ sock.close()
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.alltogether.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="function">translate</tt> function has an <a href="../power_of_introspection/optional_arguments.html" title="4.2.&nbsp;Using Optional and Named Arguments">optional argument</a> <tt class="varname">dialectName</tt>, which is a string that specifies the dialect you'll be using. You'll see how this is used in a minute.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.alltogether.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Hey, wait a minute, there's an <a href="../getting_to_know_python/everything_is_an_object.html#odbchelper.import" title="Example&nbsp;2.3.&nbsp;Accessing the buildConnectionString Function's doc string"><tt class="literal">import</tt></a> statement in this function! That's perfectly legal in <span class="application">Python</span>. You're used to seeing <tt class="literal">import</tt> statements at the top of a program, which means that the imported module is available anywhere in the program. But you can
+ also import modules within a function, which means that the imported module is only available within the function. If you
+ have a module that is only ever used in one function, this is an easy way to make your code more modular. (When you find
+ that your weekend hack has turned into an 800-line work of art and decide to split it up into a dozen reusable modules, you'll
+ appreciate this.)
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.alltogether.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Now you <a href="extracting_data.html#dialect.extract.urllib" title="Example&nbsp;8.5.&nbsp;Introducing urllib">get the source of the given URL</a>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="d0e22433"></a><h3 class="title">Example&nbsp;8.21.&nbsp;The <tt class="function">translate</tt> function, part 2: curiouser and curiouser
+ </h3><pre class="programlisting">
+ parserName = <span class='pystring'>"%sDialectizer"</span> % dialectName.capitalize() <a name="dialect.alltogether.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ parserClass = globals()[parserName] <a name="dialect.alltogether.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+ parser = parserClass() <a name="dialect.alltogether.2.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.alltogether.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">capitalize</tt> is a string method you haven't seen before; it simply capitalizes the first letter of a string and forces everything else
+ to lowercase. Combined with some <a href="../native_data_types/formatting_strings.html" title="3.5.&nbsp;Formatting Strings">string formatting</a>, you've taken the name of a dialect and transformed it into the name of the corresponding Dialectizer class. If <tt class="varname">dialectName</tt> is the string <tt class="literal">'chef'</tt>, <tt class="varname">parserName</tt> will be the string <tt class="literal">'ChefDialectizer'</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.alltogether.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You have the name of a class as a string (<tt class="varname">parserName</tt>), and you have the global namespace as a dictionary (<tt class="function">globals</tt>()). Combined, you can get a reference to the class which the string names. (Remember, <a href="../object_oriented_framework/class_attributes.html" title="5.8.&nbsp;Introducing Class Attributes">classes are objects</a>, and they can be assigned to variables just like any other object.) If <tt class="varname">parserName</tt> is the string <tt class="literal">'ChefDialectizer'</tt>, <tt class="varname">parserClass</tt> will be the class <tt class="literal">ChefDialectizer</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.alltogether.2.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Finally, you have a class object (<tt class="varname">parserClass</tt>), and you want an instance of the class. Well, you already know how to do that: <a href="../object_oriented_framework/instantiating_classes.html" title="5.4.&nbsp;Instantiating Classes">call the class like a function</a>. The fact that the class is being stored in a local variable makes absolutely no difference; you just call the local variable
+ like a function, and out pops an instance of the class. If <tt class="varname">parserClass</tt> is the class <tt class="literal">ChefDialectizer</tt>, <tt class="varname">parser</tt> will be an instance of the class <tt class="literal">ChefDialectizer</tt>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>Why bother? After all, there are only 3 <tt class="classname">Dialectizer</tt> classes; why not just use a <tt class="function">case</tt> statement? (Well, there's no <tt class="function">case</tt> statement in <span class="application">Python</span>, but why not just use a series of <tt class="literal">if</tt> statements?) One reason: extensibility. The <tt class="function">translate</tt> function has absolutely no idea how many Dialectizer classes you've defined. Imagine if you defined a new <tt class="classname">FooDialectizer</tt> tomorrow; <tt class="function">translate</tt> would work by passing <tt class="literal">'foo'</tt> as the <tt class="varname">dialectName</tt>.
+ </p>
+ <p>Even better, imagine putting <tt class="classname">FooDialectizer</tt> in a separate module, and importing it with <tt class="literal">from <i class="replaceable">module</i> import</tt>. You've already seen that this <a href="locals_and_globals.html#dialect.globals.example" title="Example&nbsp;8.11.&nbsp;Introducing globals">includes it in <tt class="function">globals</tt>()</a>, so <tt class="function">translate</tt> would still work without modification, even though <tt class="classname">FooDialectizer</tt> was in a separate file.
+ </p>
+ <p>Now imagine that the name of the dialect is coming from somewhere outside the program, maybe from a database or from a user-inputted
+ value on a form. You can use any number of server-side <span class="application">Python</span> scripting architectures to dynamically generate web pages; this function could take a <span class="acronym">URL</span> and a dialect name (both strings) in the query string of a web page request, and output the &#8220;<span class="quote">translated</span>&#8221; web page.
+ </p>
+ <p>Finally, imagine a <tt class="classname">Dialectizer</tt> framework with a plug-in architecture. You could put each <tt class="classname">Dialectizer</tt> class in a separate file, leaving only the <tt class="function">translate</tt> function in <tt class="filename">dialect.py</tt>. Assuming a consistent naming scheme, the <tt class="function">translate</tt> function could dynamic import the appropiate class from the appropriate file, given nothing but the dialect name. (You haven't
+ seen dynamic importing yet, but I promise to cover it in a later chapter.) To add a new dialect, you would simply add an
+ appropriately-named file in the plug-ins directory (like <tt class="filename">foodialect.py</tt> which contains the <tt class="classname">FooDialectizer</tt> class). Calling the <tt class="function">translate</tt> function with the dialect name <tt class="literal">'foo'</tt> would find the module <tt class="filename">foodialect.py</tt>, import the class <tt class="classname">FooDialectizer</tt>, and away you go.
+ </p>
+ <div class="example"><a name="d0e22614"></a><h3 class="title">Example&nbsp;8.22.&nbsp;The <tt class="function">translate</tt> function, part 3
+ </h3><pre class="programlisting">
+ parser.feed(htmlSource) <a name="dialect.alltogether.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ parser.close() <a name="dialect.alltogether.3.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+ <span class='pykeyword'>return</span> parser.output() <a name="dialect.alltogether.3.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.alltogether.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">After all that imagining, this is going to seem pretty boring, but the <tt class="function">feed</tt> function is what <a href="extracting_data.html#dialect.feed.example" title="Example&nbsp;8.7.&nbsp;Using urllister.py">does the entire transformation</a>. You had the entire <span class="acronym">HTML</span> source in a single string, so you only had to call <tt class="function">feed</tt> once. However, you can call <tt class="function">feed</tt> as often as you want, and the parser will just keep parsing. So if you were worried about memory usage (or you knew you
+ were going to be dealing with very large <span class="acronym">HTML</span> pages), you could set this up in a loop, where you read a few bytes of <span class="acronym">HTML</span> and fed it to the parser. The result would be the same.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.alltogether.3.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Because <tt class="function">feed</tt> maintains an internal buffer, you should always call the parser's <tt class="function">close</tt> method when you're done (even if you fed it all at once, like you did). Otherwise you may find that your output is missing
+ the last few bytes.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.alltogether.3.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Remember, <tt class="function">output</tt> is the function you defined on <tt class="classname">BaseHTMLProcessor</tt> that <a href="basehtmlprocessor.html#dialect.output.example" title="Example&nbsp;8.9.&nbsp;BaseHTMLProcessor output">joins all the pieces of output you've buffered</a> and returns them in a single string.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>And just like that, you've &#8220;<span class="quote">translated</span>&#8221; a web page, given nothing but a <span class="acronym">URL</span> and the name of a dialect.
+ </p>
+ <div class="furtherreading">
+ <h3>Further reading</h3>
+ <ul>
+ <li>You thought I was kidding about the server-side scripting idea. So did I, until I found <a href="http://rinkworks.com/dialect/">this web-based dialectizer</a>. Unfortunately, source code does not appear to be available.
+ </li>
+ </ul>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="dialect.html">&lt;&lt;&nbsp;Introducing dialect.py</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#dialect.divein" title="8.1.&nbsp;Diving in">1</a> <span class="divider">|</span> <a href="introducing_sgmllib.html" title="8.2.&nbsp;Introducing sgmllib.py">2</a> <span class="divider">|</span> <a href="extracting_data.html" title="8.3.&nbsp;Extracting data from HTML documents">3</a> <span class="divider">|</span> <a href="basehtmlprocessor.html" title="8.4.&nbsp;Introducing BaseHTMLProcessor.py">4</a> <span class="divider">|</span> <a href="locals_and_globals.html" title="8.5.&nbsp;locals and globals">5</a> <span class="divider">|</span> <a href="dictionary_based_string_formatting.html" title="8.6.&nbsp;Dictionary-based string formatting">6</a> <span class="divider">|</span> <a href="quoting_attribute_values.html" title="8.7.&nbsp;Quoting attribute values">7</a> <span class="divider">|</span> <a href="dialect.html" title="8.8.&nbsp;Introducing dialect.py">8</a> <span class="divider">|</span> <span class="thispage">9</span> <span class="divider">|</span> <a href="summary.html" title="8.10.&nbsp;Summary">10</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="summary.html">Summary&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/html_processing/basehtmlprocessor.html b/help/diveintopython-5.4/html/html_processing/basehtmlprocessor.html
new file mode 100644
index 0000000..1037dd8
--- /dev/null
+++ b/help/diveintopython-5.4/html/html_processing/basehtmlprocessor.html
@@ -0,0 +1,205 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>8.4.&nbsp;Introducing BaseHTMLProcessor.py</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;8.&nbsp;HTML Processing">
+ <link rel="previous" href="extracting_data.html" title="8.3.&nbsp;Extracting data from HTML documents">
+ <link rel="next" href="locals_and_globals.html" title="8.5.&nbsp;locals and globals">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">HTML Processing</a>&nbsp;&gt;&nbsp;<span class="thispage">Introducing BaseHTMLProcessor.py</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="extracting_data.html" title="Prev: &#8220;Extracting data from HTML documents&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="locals_and_globals.html" title="Next: &#8220;locals and globals&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="dialect.basehtml"></a>8.4.&nbsp;Introducing <tt class="filename">BaseHTMLProcessor.py</tt></h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p><tt class="classname">SGMLParser</tt> doesn't produce anything by itself. It parses and parses and parses, and it calls a method for each interesting thing it
+ finds, but the methods don't do anything. <tt class="classname">SGMLParser</tt> is an <span class="acronym">HTML</span> <span class="emphasis"><em>consumer</em></span>: it takes <span class="acronym">HTML</span> and breaks it down into small, structured pieces. As you saw in the <a href="extracting_data.html" title="8.3.&nbsp;Extracting data from HTML documents">previous section</a>, you can subclass <tt class="classname">SGMLParser</tt> to define classes that catch specific tags and produce useful things, like a list of all the links on a web page. Now you'll
+ take this one step further by defining a class that catches everything <tt class="classname">SGMLParser</tt> throws at it and reconstructs the complete <span class="acronym">HTML</span> document. In technical terms, this class will be an <span class="acronym">HTML</span> <span class="emphasis"><em>producer</em></span>.
+ </p>
+ </div>
+ <p><tt class="classname">BaseHTMLProcessor</tt> subclasses <tt class="classname">SGMLParser</tt> and provides all 8 essential handler methods: <tt class="function">unknown_starttag</tt>, <tt class="function">unknown_endtag</tt>, <tt class="function">handle_charref</tt>, <tt class="function">handle_entityref</tt>, <tt class="function">handle_comment</tt>, <tt class="function">handle_pi</tt>, <tt class="function">handle_decl</tt>, and <tt class="function">handle_data</tt>.
+ </p>
+ <div class="example"><a name="dialect.basehtml.intro"></a><h3 class="title">Example&nbsp;8.8.&nbsp;Introducing <tt class="classname">BaseHTMLProcessor</tt></h3><pre class="programlisting"><span class='pykeyword'>
+class</span> BaseHTMLProcessor(SGMLParser):
+ <span class='pykeyword'>def</span><span class='pyclass'> reset</span>(self): <a name="dialect.basehtml.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ self.pieces = []
+ SGMLParser.reset(self)
+
+ <span class='pykeyword'>def</span><span class='pyclass'> unknown_starttag</span>(self, tag, attrs): <a name="dialect.basehtml.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+ strattrs = <span class='pystring'>""</span>.join([<span class='pystring'>' %s="%s"'</span> % (key, value) <span class='pykeyword'>for</span> key, value <span class='pykeyword'>in</span> attrs])
+ self.pieces.append(<span class='pystring'>"&lt;%(tag)s%(strattrs)s&gt;"</span> % locals())
+
+ <span class='pykeyword'>def</span><span class='pyclass'> unknown_endtag</span>(self, tag): <a name="dialect.basehtml.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+ self.pieces.append(<span class='pystring'>"&lt;/%(tag)s&gt;"</span> % locals())
+
+ <span class='pykeyword'>def</span><span class='pyclass'> handle_charref</span>(self, ref): <a name="dialect.basehtml.1.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+ self.pieces.append(<span class='pystring'>"&amp;#%(ref)s;"</span> % locals())
+
+ <span class='pykeyword'>def</span><span class='pyclass'> handle_entityref</span>(self, ref): <a name="dialect.basehtml.1.5"></a><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12">
+ self.pieces.append(<span class='pystring'>"&amp;%(ref)s"</span> % locals())
+ <span class='pykeyword'>if</span> htmlentitydefs.entitydefs.has_key(ref):
+ self.pieces.append(<span class='pystring'>";"</span>)
+
+ <span class='pykeyword'>def</span><span class='pyclass'> handle_data</span>(self, text): <a name="dialect.basehtml.1.6"></a><img src="../images/callouts/6.png" alt="6" border="0" width="12" height="12">
+ self.pieces.append(text)
+
+ <span class='pykeyword'>def</span><span class='pyclass'> handle_comment</span>(self, text): <a name="dialect.basehtml.1.7"></a><img src="../images/callouts/7.png" alt="7" border="0" width="12" height="12">
+ self.pieces.append(<span class='pystring'>"&lt;!--%(text)s--&gt;"</span> % locals())
+
+ <span class='pykeyword'>def</span><span class='pyclass'> handle_pi</span>(self, text): <a name="dialect.basehtml.1.8"></a><img src="../images/callouts/8.png" alt="8" border="0" width="12" height="12">
+ self.pieces.append(<span class='pystring'>"&lt;?%(text)s&gt;"</span> % locals())
+
+ <span class='pykeyword'>def</span><span class='pyclass'> handle_decl</span>(self, text):
+ self.pieces.append(<span class='pystring'>"&lt;!%(text)s&gt;"</span> % locals())</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.basehtml.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">reset</tt>, called by <tt class="function">SGMLParser.__init__</tt>, initializes <tt class="varname">self.pieces</tt> as an empty list before <a href="../object_oriented_framework/defining_classes.html#fileinfo.init.code.example" title="Example&nbsp;5.6.&nbsp;Coding the FileInfo Class">calling the ancestor method</a>. <tt class="varname">self.pieces</tt> is a <a href="../object_oriented_framework/userdict.html#fileinfo.userdict.init.example" title="Example&nbsp;5.9.&nbsp;Defining the UserDict Class">data attribute</a> which will hold the pieces of the <span class="acronym">HTML</span> document you're constructing. Each handler method will reconstruct the <span class="acronym">HTML</span> that <tt class="classname">SGMLParser</tt> parsed, and each method will append that string to <tt class="varname">self.pieces</tt>. Note that <tt class="varname">self.pieces</tt> is a list. You might be tempted to define it as a string and just keep appending each piece to it. That would work, but
+ <span class="application">Python</span> is much more efficient at dealing with lists.<sup>[<a name="d0e20702" href="#ftn.d0e20702">2</a>]</sup></td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.basehtml.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Since <tt class="classname">BaseHTMLProcessor</tt> does not define any methods for specific tags (like the <tt class="function">start_a</tt> method in <a href="extracting_data.html#dialect.extract.links" title="Example&nbsp;8.6.&nbsp;Introducing urllister.py"><tt class="classname">URLLister</tt></a>), <tt class="classname">SGMLParser</tt> will call <tt class="function">unknown_starttag</tt> for every start tag. This method takes the tag (<tt class="varname">tag</tt>) and the list of attribute name/value pairs (<tt class="varname">attrs</tt>), reconstructs the original <span class="acronym">HTML</span>, and appends it to <tt class="varname">self.pieces</tt>. The <a href="../native_data_types/formatting_strings.html" title="3.5.&nbsp;Formatting Strings">string formatting</a> here is a little strange; you'll untangle that (and also the odd-looking <tt class="function">locals</tt> function) later in this chapter.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.basehtml.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Reconstructing end tags is much simpler; just take the tag name and wrap it in the <tt class="literal">&lt;/...&gt;</tt> brackets.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.basehtml.1.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">When <tt class="classname">SGMLParser</tt> finds a character reference, it calls <tt class="function">handle_charref</tt> with the bare reference. If the <span class="acronym">HTML</span> document contains the reference <tt class="literal">&amp;#160;</tt>, <tt class="varname">ref</tt> will be <tt class="literal">160</tt>. Reconstructing the original complete character reference just involves wrapping <tt class="varname">ref</tt> in <tt class="literal">&amp;#...;</tt> characters.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.basehtml.1.5"><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Entity references are similar to character references, but without the hash mark. Reconstructing the original entity reference
+ requires wrapping <tt class="varname">ref</tt> in <tt class="literal">&amp;...;</tt> characters. (Actually, as an erudite reader pointed out to me, it's slightly more complicated than this. Only certain standard
+ <span class="acronym">HTML</span> entites end in a semicolon; other similar-looking entities do not. Luckily for us, the set of standard <span class="acronym">HTML</span> entities is defined in a dictionary in a <span class="application">Python</span> module called <tt class="filename">htmlentitydefs</tt>. Hence the extra <tt class="literal">if</tt> statement.)
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.basehtml.1.6"><img src="../images/callouts/6.png" alt="6" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Blocks of text are simply appended to <tt class="varname">self.pieces</tt> unaltered.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.basehtml.1.7"><img src="../images/callouts/7.png" alt="7" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><span class="acronym">HTML</span> comments are wrapped in <tt class="literal">&lt;!--...--&gt;</tt> characters.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.basehtml.1.8"><img src="../images/callouts/8.png" alt="8" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Processing instructions are wrapped in <tt class="literal">&lt;?...&gt;</tt> characters.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div><a name="d0e20845"></a><table class="important" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/important.png" alt="Important" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">The <span class="acronym">HTML</span> specification requires that all non-<span class="acronym">HTML</span> (like client-side <span class="application">JavaScript</span>) must be enclosed in <span class="acronym">HTML</span> comments, but not all web pages do this properly (and all modern web browsers are forgiving if they don't). <tt class="classname">BaseHTMLProcessor</tt> is not forgiving; if script is improperly embedded, it will be parsed as if it were <span class="acronym">HTML</span>. For instance, if the script contains less-than and equals signs, <tt class="classname">SGMLParser</tt> may incorrectly think that it has found tags and attributes. <tt class="classname">SGMLParser</tt> always converts tags and attribute names to lowercase, which may break the script, and <tt class="classname">BaseHTMLProcessor</tt> always encloses attribute values in double quotes (even if the original <span class="acronym">HTML</span> document used single quotes or no quotes), which will certainly break the script. Always protect your client-side script
+ within <span class="acronym">HTML</span> comments.
+ </td>
+ </tr>
+ </table>
+ <div class="example"><a name="dialect.output.example"></a><h3 class="title">Example&nbsp;8.9.&nbsp;<tt class="classname">BaseHTMLProcessor</tt> output
+ </h3><pre class="programlisting">
+ <span class='pykeyword'>def</span><span class='pyclass'> output</span>(self): <a name="dialect.basehtml.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ <span class='pystring'>"""Return processed HTML as a single string"""</span>
+ <span class='pykeyword'>return</span> <span class='pystring'>""</span>.join(self.pieces) <a name="dialect.basehtml.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.basehtml.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This is the one method in <tt class="classname">BaseHTMLProcessor</tt> that is never called by the ancestor <tt class="classname">SGMLParser</tt>. Since the other handler methods store their reconstructed <span class="acronym">HTML</span> in <tt class="varname">self.pieces</tt>, this function is needed to join all those pieces into one string. As noted before, <span class="application">Python</span> is great at lists and mediocre at strings, so you only create the complete string when somebody explicitly asks for it.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.basehtml.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">If you prefer, you could use the <tt class="function">join</tt> method of the <tt class="filename">string</tt> module instead: <tt class="literal">string.join(self.pieces, "")</tt></td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="furtherreading">
+ <h3>Further reading</h3>
+ <ul>
+ <li><a href="http://www.w3.org/">W3C</a> discusses <a href="http://www.w3.org/TR/REC-html40/charset.html#entities">character and entity references</a>.
+ </li>
+ <li><a href="http://www.python.org/doc/current/lib/"><i class="citetitle"><span class="application">Python</span> Library Reference</i></a> confirms your suspicions that <a href="http://www.python.org/doc/current/lib/module-htmlentitydefs.html">the <tt class="filename">htmlentitydefs</tt> module</a> is exactly what it sounds like.
+ </li>
+ </ul>
+ </div>
+ <div class="footnotes">
+ <h3 class="footnotetitle">Footnotes</h3>
+ <div class="footnote">
+ <p><sup>[<a name="ftn.d0e20702" href="#d0e20702">2</a>] </sup>The reason <span class="application">Python</span> is better at lists than strings is that lists are mutable but strings are immutable. This means that appending to a list
+ just adds the element and updates the index. Since strings can not be changed after they are created, code like <tt class="literal">s = s + newpiece</tt> will create an entirely new string out of the concatenation of the original and the new piece, then throw away the original
+ string. This involves a lot of expensive memory management, and the amount of effort involved increases as the string gets
+ longer, so doing <tt class="literal">s = s + newpiece</tt> in a loop is deadly. In technical terms, appending <tt class="varname">n</tt> items to a list is <tt class="literal">O(n)</tt>, while appending <tt class="varname">n</tt> items to a string is <tt class="literal">O(n<sup>2</sup>)</tt>.
+ </p>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="extracting_data.html">&lt;&lt;&nbsp;Extracting data from HTML documents</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#dialect.divein" title="8.1.&nbsp;Diving in">1</a> <span class="divider">|</span> <a href="introducing_sgmllib.html" title="8.2.&nbsp;Introducing sgmllib.py">2</a> <span class="divider">|</span> <a href="extracting_data.html" title="8.3.&nbsp;Extracting data from HTML documents">3</a> <span class="divider">|</span> <span class="thispage">4</span> <span class="divider">|</span> <a href="locals_and_globals.html" title="8.5.&nbsp;locals and globals">5</a> <span class="divider">|</span> <a href="dictionary_based_string_formatting.html" title="8.6.&nbsp;Dictionary-based string formatting">6</a> <span class="divider">|</span> <a href="quoting_attribute_values.html" title="8.7.&nbsp;Quoting attribute values">7</a> <span class="divider">|</span> <a href="dialect.html" title="8.8.&nbsp;Introducing dialect.py">8</a> <span class="divider">|</span> <a href="all_together.html" title="8.9.&nbsp;Putting it all together">9</a> <span class="divider">|</span> <a href="summary.html" title="8.10.&nbsp;Summary">10</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="locals_and_globals.html">locals and globals&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/html_processing/dialect.html b/help/diveintopython-5.4/html/html_processing/dialect.html
new file mode 100644
index 0000000..969526e
--- /dev/null
+++ b/help/diveintopython-5.4/html/html_processing/dialect.html
@@ -0,0 +1,227 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>8.8.&nbsp;Introducing dialect.py</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;8.&nbsp;HTML Processing">
+ <link rel="previous" href="quoting_attribute_values.html" title="8.7.&nbsp;Quoting attribute values">
+ <link rel="next" href="all_together.html" title="8.9.&nbsp;Putting it all together">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">HTML Processing</a>&nbsp;&gt;&nbsp;<span class="thispage">Introducing dialect.py</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="quoting_attribute_values.html" title="Prev: &#8220;Quoting attribute values&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="all_together.html" title="Next: &#8220;Putting it all together&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="dialect.dialectizer"></a>8.8.&nbsp;Introducing <tt class="filename">dialect.py</tt></h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p><tt class="classname">Dialectizer</tt> is a simple (and silly) descendant of <tt class="classname">BaseHTMLProcessor</tt>. It runs blocks of text through a series of substitutions, but it makes sure that anything within a <tt class="literal"><tt class="sgmltag-element">&lt;pre&gt;</tt>...<tt class="sgmltag-element">&lt;/pre&gt;</tt></tt> block passes through unaltered.
+ </p>
+ </div>
+ <p>To handle the <tt class="sgmltag-element">&lt;pre&gt;</tt> blocks, you define two methods in <tt class="classname">Dialectizer</tt>: <tt class="function">start_pre</tt> and <tt class="function">end_pre</tt>.
+ </p>
+ <div class="example"><a name="dialect.specifictags.example"></a><h3 class="title">Example&nbsp;8.17.&nbsp;Handling specific tags</h3><pre class="programlisting">
+ <span class='pykeyword'>def</span><span class='pyclass'> start_pre</span>(self, attrs): <a name="dialect.dialectizer.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ self.verbatim += 1 <a name="dialect.dialectizer.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+ self.unknown_starttag(<span class='pystring'>"pre"</span>, attrs) <a name="dialect.dialectizer.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+
+ <span class='pykeyword'>def</span><span class='pyclass'> end_pre</span>(self): <a name="dialect.dialectizer.1.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+ self.unknown_endtag(<span class='pystring'>"pre"</span>) <a name="dialect.dialectizer.1.5"></a><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12">
+ self.verbatim -= 1 <a name="dialect.dialectizer.1.6"></a><img src="../images/callouts/6.png" alt="6" border="0" width="12" height="12"></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.dialectizer.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">start_pre</tt> is called every time <tt class="classname">SGMLParser</tt> finds a <tt class="sgmltag-element">&lt;pre&gt;</tt> tag in the <span class="acronym">HTML</span> source. (In a minute, you'll see exactly how this happens.) The method takes a single parameter, <tt class="varname">attrs</tt>, which contains the attributes of the tag (if any). <tt class="varname">attrs</tt> is a list of key/value tuples, just like <a href="dictionary_based_string_formatting.html#dialect.unknownstarttag" title="Example&nbsp;8.14.&nbsp;Dictionary-based string formatting in BaseHTMLProcessor.py"><tt class="function">unknown_starttag</tt></a> takes.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.dialectizer.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">In the <tt class="function">reset</tt> method, you initialize a data attribute that serves as a counter for <tt class="sgmltag-element">&lt;pre&gt;</tt> tags. Every time you hit a <tt class="sgmltag-element">&lt;pre&gt;</tt> tag, you increment the counter; every time you hit a <tt class="sgmltag-element">&lt;/pre&gt;</tt> tag, you'll decrement the counter. (You could just use this as a flag and set it to <tt class="constant">1</tt> and reset it to <tt class="constant">0</tt>, but it's just as easy to do it this way, and this handles the odd (but possible) case of nested <tt class="sgmltag-element">&lt;pre&gt;</tt> tags.) In a minute, you'll see how this counter is put to good use.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.dialectizer.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">That's it, that's the only special processing you do for <tt class="sgmltag-element">&lt;pre&gt;</tt> tags. Now you pass the list of attributes along to <tt class="function">unknown_starttag</tt> so it can do the default processing.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.dialectizer.1.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">end_pre</tt> is called every time <tt class="classname">SGMLParser</tt> finds a <tt class="sgmltag-element">&lt;/pre&gt;</tt> tag. Since end tags can not contain attributes, the method takes no parameters.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.dialectizer.1.5"><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">First, you want to do the default processing, just like any other end tag.</td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.dialectizer.1.6"><img src="../images/callouts/6.png" alt="6" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Second, you decrement your counter to signal that this <tt class="sgmltag-element">&lt;pre&gt;</tt> block has been closed.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>At this point, it's worth digging a little further into <tt class="classname">SGMLParser</tt>. I've claimed repeatedly (and you've taken it on faith so far) that <tt class="classname">SGMLParser</tt> looks for and calls specific methods for each tag, if they exist. For instance, you just saw the definition of <tt class="function">start_pre</tt> and <tt class="function">end_pre</tt> to handle <tt class="sgmltag-element">&lt;pre&gt;</tt> and <tt class="sgmltag-element">&lt;/pre&gt;</tt>. But how does this happen? Well, it's not magic, it's just good <span class="application">Python</span> coding.
+ </p>
+ <div class="example"><a name="dialect.dialectizer.example"></a><h3 class="title">Example&nbsp;8.18.&nbsp;<tt class="classname">SGMLParser</tt></h3><pre class="programlisting">
+ <span class='pykeyword'>def</span><span class='pyclass'> finish_starttag</span>(self, tag, attrs): <a name="dialect.dialectizer.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ <span class='pykeyword'>try</span>:
+ method = getattr(self, <span class='pystring'>'start_'</span> + tag) <a name="dialect.dialectizer.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+ <span class='pykeyword'>except</span> AttributeError: <a name="dialect.dialectizer.2.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+ <span class='pykeyword'>try</span>:
+ method = getattr(self, <span class='pystring'>'do_'</span> + tag) <a name="dialect.dialectizer.2.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+ <span class='pykeyword'>except</span> AttributeError:
+ self.unknown_starttag(tag, attrs) <a name="dialect.dialectizer.2.5"></a><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12">
+ <span class='pykeyword'>return</span> -1
+ <span class='pykeyword'>else</span>:
+ self.handle_starttag(tag, method, attrs) <a name="dialect.dialectizer.2.6"></a><img src="../images/callouts/6.png" alt="6" border="0" width="12" height="12">
+ <span class='pykeyword'>return</span> 0
+ <span class='pykeyword'>else</span>:
+ self.stack.append(tag)
+ self.handle_starttag(tag, method, attrs)
+ <span class='pykeyword'>return</span> 1 <a name="dialect.dialectizer.2.7"></a><img src="../images/callouts/7.png" alt="7" border="0" width="12" height="12">
+
+ <span class='pykeyword'>def</span><span class='pyclass'> handle_starttag</span>(self, tag, method, attrs):
+ method(attrs) <a name="dialect.dialectizer.2.8"></a><img src="../images/callouts/8.png" alt="8" border="0" width="12" height="12"></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.dialectizer.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">At this point, <tt class="classname">SGMLParser</tt> has already found a start tag and parsed the attribute list. The only thing left to do is figure out whether there is a
+ specific handler method for this tag, or whether you should fall back on the default method (<tt class="function">unknown_starttag</tt>).
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.dialectizer.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The &#8220;<span class="quote">magic</span>&#8221; of <tt class="classname">SGMLParser</tt> is nothing more than your old friend, <a href="../power_of_introspection/getattr.html" title="4.4.&nbsp;Getting Object References With getattr"><tt class="function">getattr</tt></a>. What you may not have realized before is that <tt class="function">getattr</tt> will find methods defined in descendants of an object as well as the object itself. Here the object is <tt class="literal">self</tt>, the current instance. So if <tt class="varname">tag</tt> is <tt class="literal">'pre'</tt>, this call to <tt class="function">getattr</tt> will look for a <tt class="function">start_pre</tt> method on the current instance, which is an instance of the <tt class="classname">Dialectizer</tt> class.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.dialectizer.2.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">getattr</tt> raises an <tt class="errorcode">AttributeError</tt> if the method it's looking for doesn't exist in the object (or any of its descendants), but that's okay, because you wrapped
+ the call to <tt class="function">getattr</tt> inside a <a href="../file_handling/index.html#fileinfo.exception" title="6.1.&nbsp;Handling Exceptions"><tt class="literal">try...except</tt></a> block and explicitly caught the <tt class="errorcode">AttributeError</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.dialectizer.2.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Since you didn't find a <tt class="function">start_xxx</tt> method, you'll also look for a <tt class="function">do_xxx</tt> method before giving up. This alternate naming scheme is generally used for standalone tags, like <tt class="sgmltag-element">&lt;br&gt;</tt>, which have no corresponding end tag. But you can use either naming scheme; as you can see, <tt class="classname">SGMLParser</tt> tries both for every tag. (You shouldn't define both a <tt class="function">start_xxx</tt> and <tt class="function">do_xxx</tt> handler method for the same tag, though; only the <tt class="function">start_xxx</tt> method will get called.)
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.dialectizer.2.5"><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Another <tt class="errorcode">AttributeError</tt>, which means that the call to <tt class="function">getattr</tt> failed with <tt class="function">do_xxx</tt>. Since you found neither a <tt class="function">start_xxx</tt> nor a <tt class="function">do_xxx</tt> method for this tag, you catch the exception and fall back on the default method, <tt class="function">unknown_starttag</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.dialectizer.2.6"><img src="../images/callouts/6.png" alt="6" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Remember, <tt class="literal">try...except</tt> blocks can have an <tt class="literal">else</tt> clause, which is called if <a href="../file_handling/index.html#crossplatform.example" title="Example&nbsp;6.2.&nbsp;Supporting Platform-Specific Functionality">no exception is raised</a> during the <tt class="literal">try...except</tt> block. Logically, that means that you <span class="emphasis"><em>did</em></span> find a <tt class="function">do_xxx</tt> method for this tag, so you're going to call it.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.dialectizer.2.7"><img src="../images/callouts/7.png" alt="7" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">By the way, don't worry about these different return values; in theory they mean something, but they're never actually used.
+ Don't worry about the <tt class="literal">self.stack.append(tag)</tt> either; <tt class="classname">SGMLParser</tt> keeps track internally of whether your start tags are balanced by appropriate end tags, but it doesn't do anything with this
+ information either. In theory, you could use this module to validate that your tags were fully balanced, but it's probably
+ not worth it, and it's beyond the scope of this chapter. You have better things to worry about right now.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.dialectizer.2.8"><img src="../images/callouts/8.png" alt="8" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">start_xxx</tt> and <tt class="function">do_xxx</tt> methods are not called directly; the tag, method, and attributes are passed to this function, <tt class="function">handle_starttag</tt>, so that descendants can override it and change the way <span class="emphasis"><em>all</em></span> start tags are dispatched. You don't need that level of control, so you just let this method do its thing, which is to call
+ the method (<tt class="function">start_xxx</tt> or <tt class="function">do_xxx</tt>) with the list of attributes. Remember, <tt class="varname">method</tt> is a function, returned from <tt class="function">getattr</tt>, and functions are objects. (I know you're getting tired of hearing it, and I promise I'll stop saying it as soon as I run
+ out of ways to use it to my advantage.) Here, the function object is passed into this dispatch method as an argument, and
+ this method turns around and calls the function. At this point, you don't need to know what the function is, what it's named,
+ or where it's defined; the only thing you need to know about the function is that it is called with one argument, <tt class="varname">attrs</tt>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>Now back to our regularly scheduled program: <tt class="classname">Dialectizer</tt>. When you left, you were in the process of defining specific handler methods for <tt class="sgmltag-element">&lt;pre&gt;</tt> and <tt class="sgmltag-element">&lt;/pre&gt;</tt> tags. There's only one thing left to do, and that is to process text blocks with the pre-defined substitutions. For that,
+ you need to override the <tt class="function">handle_data</tt> method.
+ </p>
+ <div class="example"><a name="d0e22310"></a><h3 class="title">Example&nbsp;8.19.&nbsp;Overriding the <tt class="function">handle_data</tt> method
+ </h3><pre class="programlisting">
+ <span class='pykeyword'>def</span><span class='pyclass'> handle_data</span>(self, text): <a name="dialect.dialectizer.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ self.pieces.append(self.verbatim <span class='pykeyword'>and</span> text <span class='pykeyword'>or</span> self.process(text)) <a name="dialect.dialectizer.3.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.dialectizer.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">handle_data</tt> is called with only one argument, the text to process.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.dialectizer.3.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">In the ancestor <a href="basehtmlprocessor.html#dialect.basehtml.intro" title="Example&nbsp;8.8.&nbsp;Introducing BaseHTMLProcessor"><tt class="classname">BaseHTMLProcessor</tt></a>, the <tt class="function">handle_data</tt> method simply appended the text to the output buffer, <tt class="varname">self.pieces</tt>. Here the logic is only slightly more complicated. If you're in the middle of a <tt class="literal"><tt class="sgmltag-element">&lt;pre&gt;</tt>...<tt class="sgmltag-element">&lt;/pre&gt;</tt></tt> block, <tt class="varname">self.verbatim</tt> will be some value greater than <tt class="constant">0</tt>, and you want to put the text in the output buffer unaltered. Otherwise, you will call a separate method to process the
+ substitutions, then put the result of that into the output buffer. In <span class="application">Python</span>, this is a one-liner, using <a href="../power_of_introspection/and_or.html#apihelper.andortrick.intro" title="Example&nbsp;4.17.&nbsp;Introducing the and-or Trick">the <tt class="literal">and-or</tt> trick</a>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>You're close to completely understanding <tt class="classname">Dialectizer</tt>. The only missing link is the nature of the text substitutions themselves. If you know any <span class="application">Perl</span>, you know that when complex text substitutions are required, the only real solution is regular expressions. The classes
+ later in <tt class="filename">dialect.py</tt> define a series of regular expressions that operate on the text between the <span class="acronym">HTML</span> tags. But you just had <a href="../regular_expressions/index.html" title="Chapter&nbsp;7.&nbsp;Regular Expressions">a whole chapter on regular expressions</a>. You don't really want to slog through regular expressions again, do you? God knows I don't. I think you've learned enough
+ for one chapter.
+ </p>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="quoting_attribute_values.html">&lt;&lt;&nbsp;Quoting attribute values</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#dialect.divein" title="8.1.&nbsp;Diving in">1</a> <span class="divider">|</span> <a href="introducing_sgmllib.html" title="8.2.&nbsp;Introducing sgmllib.py">2</a> <span class="divider">|</span> <a href="extracting_data.html" title="8.3.&nbsp;Extracting data from HTML documents">3</a> <span class="divider">|</span> <a href="basehtmlprocessor.html" title="8.4.&nbsp;Introducing BaseHTMLProcessor.py">4</a> <span class="divider">|</span> <a href="locals_and_globals.html" title="8.5.&nbsp;locals and globals">5</a> <span class="divider">|</span> <a href="dictionary_based_string_formatting.html" title="8.6.&nbsp;Dictionary-based string formatting">6</a> <span class="divider">|</span> <a href="quoting_attribute_values.html" title="8.7.&nbsp;Quoting attribute values">7</a> <span class="divider">|</span> <span class="thispage">8</span> <span class="divider">|</span> <a href="all_together.html" title="8.9.&nbsp;Putting it all together">9</a> <span class="divider">|</span> <a href="summary.html" title="8.10.&nbsp;Summary">10</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="all_together.html">Putting it all together&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/html_processing/dictionary_based_string_formatting.html b/help/diveintopython-5.4/html/html_processing/dictionary_based_string_formatting.html
new file mode 100644
index 0000000..7a52602
--- /dev/null
+++ b/help/diveintopython-5.4/html/html_processing/dictionary_based_string_formatting.html
@@ -0,0 +1,167 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>8.6.&nbsp;Dictionary-based string formatting</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;8.&nbsp;HTML Processing">
+ <link rel="previous" href="locals_and_globals.html" title="8.5.&nbsp;locals and globals">
+ <link rel="next" href="quoting_attribute_values.html" title="8.7.&nbsp;Quoting attribute values">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">HTML Processing</a>&nbsp;&gt;&nbsp;<span class="thispage">Dictionary-based string formatting</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="locals_and_globals.html" title="Prev: &#8220;locals and globals&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="quoting_attribute_values.html" title="Next: &#8220;Quoting attribute values&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="dialect.dictsub"></a>8.6.&nbsp;Dictionary-based string formatting
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p>Why did you learn about <tt class="function">locals</tt> and <tt class="function">globals</tt>? So you can learn about dictionary-based string formatting. As you recall, <a href="../native_data_types/formatting_strings.html" title="3.5.&nbsp;Formatting Strings">regular string formatting</a> provides an easy way to insert values into strings. Values are listed in a tuple and inserted in order into the string in
+ place of each formatting marker. While this is efficient, it is not always the easiest code to read, especially when multiple
+ values are being inserted. You can't simply scan through the string in one pass and understand what the result will be; you're
+ constantly switching between reading the string and reading the tuple of values.
+ </p>
+ <div class="abstract">
+ <p>There is an alternative form of string formatting that uses dictionaries instead of tuples of values.</p>
+ </div>
+ <div class="example"><a name="d0e21518"></a><h3 class="title">Example&nbsp;8.13.&nbsp;Introducing dictionary-based string formatting</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">params = {<span class='pystring'>"server"</span>:<span class='pystring'>"mpilgrim"</span>, <span class='pystring'>"database"</span>:<span class='pystring'>"master"</span>, <span class='pystring'>"uid"</span>:<span class='pystring'>"sa"</span>, <span class='pystring'>"pwd"</span>:<span class='pystring'>"secret"</span>}</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pystring'>"%(pwd)s"</span> % params</span> <a name="dialect.dictsub.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">'secret'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pystring'>"%(pwd)s is not a good password for %(uid)s"</span> % params</span> <a name="dialect.dictsub.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">'secret is not a good password for sa'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pystring'>"%(database)s of mind, %(database)s of body"</span> % params</span> <a name="dialect.dictsub.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">'master of mind, master of body'</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.dictsub.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Instead of a tuple of explicit values, this form of string formatting uses a dictionary, <tt class="varname">params</tt>. And instead of a simple <tt class="literal">%s</tt> marker in the string, the marker contains a name in parentheses. This name is used as a key in the <tt class="varname">params</tt> dictionary and subsitutes the corresponding value, <tt class="literal">secret</tt>, in place of the <tt class="literal">%(pwd)s</tt> marker.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.dictsub.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Dictionary-based string formatting works with any number of named keys. Each key must exist in the given dictionary, or the
+ formatting will fail with a <tt class="errorcode">KeyError</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.dictsub.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You can even specify the same key twice; each occurrence will be replaced with the same value.</td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>So why would you use dictionary-based string formatting? Well, it does seem like overkill to set up a dictionary of keys
+ and values simply to do string formatting in the next line; it's really most useful when you happen to have a dictionary of
+ meaningful keys and values already. Like <a href="locals_and_globals.html" title="8.5.&nbsp;locals and globals"><tt class="function">locals</tt></a>.
+ </p>
+ <div class="example"><a name="dialect.unknownstarttag"></a><h3 class="title">Example&nbsp;8.14.&nbsp;Dictionary-based string formatting in <tt class="filename">BaseHTMLProcessor.py</tt></h3><pre class="programlisting">
+ <span class='pykeyword'>def</span><span class='pyclass'> handle_comment</span>(self, text):
+ self.pieces.append(<span class='pystring'>"&lt;!--%(text)s--&gt;"</span> % locals()) <a name="dialect.dictsub.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.dictsub.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Using the built-in <tt class="function">locals</tt> function is the most common use of dictionary-based string formatting. It means that you can use the names of local variables
+ within your string (in this case, <tt class="varname">text</tt>, which was passed to the class method as an argument) and each named variable will be replaced by its value. If <tt class="varname">text</tt> is <tt class="literal">'Begin page footer'</tt>, the string formatting <tt class="literal">"&lt;!--%(text)s--&gt;" % locals()</tt> will resolve to the string <tt class="literal">'&lt;!--Begin page footer--&gt;'</tt>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="d0e21622"></a><h3 class="title">Example&nbsp;8.15.&nbsp;More dictionary-based string formatting</h3><pre class="programlisting">
+ <span class='pykeyword'>def</span><span class='pyclass'> unknown_starttag</span>(self, tag, attrs):
+ strattrs = <span class='pystring'>""</span>.join([<span class='pystring'>' %s="%s"'</span> % (key, value) <span class='pykeyword'>for</span> key, value <span class='pykeyword'>in</span> attrs]) <a name="dialect.dictsub.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ self.pieces.append(<span class='pystring'>"&lt;%(tag)s%(strattrs)s&gt;"</span> % locals()) <a name="dialect.dictsub.3.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.dictsub.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">When this method is called, <tt class="varname">attrs</tt> is a list of key/value tuples, just like the <a href="../native_data_types/mapping_lists.html#odbchelper.items" title="Example&nbsp;3.25.&nbsp;The keys, values, and items Functions"><tt class="function">items</tt> of a dictionary</a>, which means you can use <a href="../native_data_types/declaring_variables.html#odbchelper.multiassign" title="3.4.2.&nbsp;Assigning Multiple Values at Once">multi-variable assignment</a> to iterate through it. This should be a familiar pattern by now, but there's a lot going on here, so let's break it down:
+ <div class="orderedlist">
+ <ol type="a">
+ <li>Suppose <tt class="varname">attrs</tt> is <tt class="literal">[('href', 'index.html'), ('title', 'Go to home page')]</tt>.
+ </li>
+ <li>In the first round of the list comprehension, <tt class="varname">key</tt> will get <tt class="literal">'href'</tt>, and <tt class="varname">value</tt> will get <tt class="literal">'index.html'</tt>.
+ </li>
+ <li>The string formatting <tt class="literal">'&nbsp;%s="%s"' % (key, value)</tt> will resolve to <tt class="literal">'&nbsp;href="index.html"'</tt>. This string becomes the first element of the list comprehension's return value.
+ </li>
+ <li>In the second round, <tt class="varname">key</tt> will get <tt class="literal">'title'</tt>, and <tt class="varname">value</tt> will get <tt class="literal">'Go to home page'</tt>.
+ </li>
+ <li>The string formatting will resolve to <tt class="literal">' title="Go to home page"'</tt>.
+ </li>
+ <li>The list comprehension returns a list of these two resolved strings, and <tt class="varname">strattrs</tt> will join both elements of this list together to form <tt class="literal">'&nbsp;href="index.html" title="Go to home page"'</tt>.
+ </li>
+ </ol>
+ </div>
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.dictsub.3.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Now, using dictionary-based string formatting, you insert the value of <tt class="varname">tag</tt> and <tt class="varname">strattrs</tt> into a string. So if <tt class="varname">tag</tt> is <tt class="literal">'a'</tt>, the final result would be <tt class="literal">'&lt;a href="index.html" title="Go to home page"&gt;'</tt>, and that is what gets appended to <tt class="varname">self.pieces</tt>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div><a name="d0e21731"></a><table class="important" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/important.png" alt="Important" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">Using dictionary-based string formatting with <tt class="function">locals</tt> is a convenient way of making complex string formatting expressions more readable, but it comes with a price. There is a
+ slight performance hit in making the call to <tt class="function">locals</tt>, since <a href="locals_and_globals.html#dialect.locals.readonly.example" title="Example&nbsp;8.12.&nbsp;locals is read-only, globals is not"><tt class="function">locals</tt> builds a copy</a> of the local namespace.
+ </td>
+ </tr>
+ </table>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="locals_and_globals.html">&lt;&lt;&nbsp;locals and globals</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#dialect.divein" title="8.1.&nbsp;Diving in">1</a> <span class="divider">|</span> <a href="introducing_sgmllib.html" title="8.2.&nbsp;Introducing sgmllib.py">2</a> <span class="divider">|</span> <a href="extracting_data.html" title="8.3.&nbsp;Extracting data from HTML documents">3</a> <span class="divider">|</span> <a href="basehtmlprocessor.html" title="8.4.&nbsp;Introducing BaseHTMLProcessor.py">4</a> <span class="divider">|</span> <a href="locals_and_globals.html" title="8.5.&nbsp;locals and globals">5</a> <span class="divider">|</span> <span class="thispage">6</span> <span class="divider">|</span> <a href="quoting_attribute_values.html" title="8.7.&nbsp;Quoting attribute values">7</a> <span class="divider">|</span> <a href="dialect.html" title="8.8.&nbsp;Introducing dialect.py">8</a> <span class="divider">|</span> <a href="all_together.html" title="8.9.&nbsp;Putting it all together">9</a> <span class="divider">|</span> <a href="summary.html" title="8.10.&nbsp;Summary">10</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="quoting_attribute_values.html">Quoting attribute values&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/html_processing/extracting_data.html b/help/diveintopython-5.4/html/html_processing/extracting_data.html
new file mode 100644
index 0000000..8ce5a68
--- /dev/null
+++ b/help/diveintopython-5.4/html/html_processing/extracting_data.html
@@ -0,0 +1,229 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>8.3.&nbsp;Extracting data from HTML documents</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;8.&nbsp;HTML Processing">
+ <link rel="previous" href="introducing_sgmllib.html" title="8.2.&nbsp;Introducing sgmllib.py">
+ <link rel="next" href="basehtmlprocessor.html" title="8.4.&nbsp;Introducing BaseHTMLProcessor.py">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">HTML Processing</a>&nbsp;&gt;&nbsp;<span class="thispage">Extracting data from HTML documents</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="introducing_sgmllib.html" title="Prev: &#8220;Introducing sgmllib.py&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="basehtmlprocessor.html" title="Next: &#8220;Introducing BaseHTMLProcessor.py&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="dialect.extract"></a>8.3.&nbsp;Extracting data from <span class="acronym">HTML</span> documents
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>To extract data from <span class="acronym">HTML</span> documents, subclass the <tt class="classname">SGMLParser</tt> class and define methods for each tag or entity you want to capture.
+ </p>
+ </div>
+ <p>The first step to extracting data from an <span class="acronym">HTML</span> document is getting some <span class="acronym">HTML</span>. If you have some <span class="acronym">HTML</span> lying around on your hard drive, you can use <a href="../file_handling/file_objects.html" title="6.2.&nbsp;Working with File Objects">file functions</a> to read it, but the real fun begins when you get <span class="acronym">HTML</span> from live web pages.
+ </p>
+ <div class="example"><a name="dialect.extract.urllib"></a><h3 class="title">Example&nbsp;8.5.&nbsp;Introducing <tt class="filename">urllib</tt></h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> urllib</span> <a name="dialect.extract.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">sock = urllib.urlopen(<span class='pystring'>"http://diveintopython.org/"</span>)</span> <a name="dialect.extract.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">htmlSource = sock.read()</span> <a name="dialect.extract.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">sock.close()</span> <a name="dialect.extract.1.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> htmlSource</span> <a name="dialect.extract.1.5"></a><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12">
+<span class="computeroutput">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"&gt;&lt;html&gt;&lt;head&gt;
+ &lt;meta http-equiv='Content-Type' content='text/html; charset=ISO-8859-1'&gt;
+ &lt;title&gt;Dive Into Python&lt;/title&gt;
+&lt;link rel='stylesheet' href='diveintopython.css' type='text/css'&gt;
+&lt;link rev='made' href='mailto:mark@diveintopython.org'&gt;
+&lt;meta name='keywords' content='Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free'&gt;
+&lt;meta name='description' content='a free Python tutorial for experienced programmers'&gt;
+&lt;/head&gt;
+&lt;body bgcolor='white' text='black' link='#0000FF' vlink='#840084' alink='#0000FF'&gt;
+&lt;table cellpadding='0' cellspacing='0' border='0' width='100%'&gt;
+&lt;tr&gt;&lt;td class='header' width='1%' valign='top'&gt;diveintopython.org&lt;/td&gt;
+&lt;td width='99%' align='right'&gt;&lt;hr size='1' noshade&gt;&lt;/td&gt;&lt;/tr&gt;
+&lt;tr&gt;&lt;td class='tagline' colspan='2'&gt;Python&amp;nbsp;for&amp;nbsp;experienced&amp;nbsp;programmers&lt;/td&gt;&lt;/tr&gt;</span>
+
+[...snip...]</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.extract.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="filename">urllib</tt> module is part of the standard <span class="application">Python</span> library. It contains functions for getting information about and actually retrieving data from Internet-based <span class="acronym">URL</span>s (mainly web pages).
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.extract.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The simplest use of <tt class="filename">urllib</tt> is to retrieve the entire text of a web page using the <tt class="function">urlopen</tt> function. Opening a <span class="acronym">URL</span> is similar to <a href="../file_handling/file_objects.html" title="6.2.&nbsp;Working with File Objects">opening a file</a>. The return value of <tt class="function">urlopen</tt> is a file-like object, which has some of the same methods as a file object.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.extract.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The simplest thing to do with the file-like object returned by <tt class="function">urlopen</tt> is <tt class="function">read</tt>, which reads the entire <span class="acronym">HTML</span> of the web page into a single string. The object also supports <tt class="function">readlines</tt>, which reads the text line by line into a list.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.extract.1.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">When you're done with the object, make sure to <tt class="function">close</tt> it, just like a normal file object.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.extract.1.5"><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You now have the complete <span class="acronym">HTML</span> of the home page of <tt class="systemitem">http://diveintopython.org/</tt> in a string, and you're ready to parse it.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="dialect.extract.links"></a><h3 class="title">Example&nbsp;8.6.&nbsp;Introducing <tt class="filename">urllister.py</tt></h3>
+ <p>If you have not already done so, you can <a href="http://diveintopython.org/download/diveintopython-examples-5.4.zip" title="Download example scripts">download this and other examples</a> used in this book.
+ </p><pre class="programlisting"><span class='pykeyword'>
+from</span> sgmllib <span class='pykeyword'>import</span> SGMLParser
+
+<span class='pykeyword'>class</span><span class='pyclass'> URLLister</span>(SGMLParser):
+ <span class='pykeyword'>def</span><span class='pyclass'> reset</span>(self): <a name="dialect.extract.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ SGMLParser.reset(self)
+ self.urls = []
+
+ <span class='pykeyword'>def</span><span class='pyclass'> start_a</span>(self, attrs): <a name="dialect.extract.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+ href = [v <span class='pykeyword'>for</span> k, v <span class='pykeyword'>in</span> attrs <span class='pykeyword'>if</span> k==<span class='pystring'>'href'</span>] <a name="dialect.extract.2.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"> <a name="dialect.extract.2.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+ <span class='pykeyword'>if</span> href:
+ self.urls.extend(href)</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.extract.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">reset</tt> is called by the <tt class="function">__init__</tt> method of <tt class="classname">SGMLParser</tt>, and it can also be called manually once an instance of the parser has been created. So if you need to do any initialization,
+ do it in <tt class="function">reset</tt>, not in <tt class="function">__init__</tt>, so that it will be re-initialized properly when someone re-uses a parser instance.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.extract.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">start_a</tt> is called by <tt class="classname">SGMLParser</tt> whenever it finds an <tt class="sgmltag-element">&lt;a&gt;</tt> tag. The tag may contain an <tt class="literal">href</tt> attribute, and/or other attributes, like <tt class="literal">name</tt> or <tt class="literal">title</tt>. The <tt class="varname">attrs</tt> parameter is a list of tuples, <tt class="literal">[(<i class="replaceable">attribute</i>, <i class="replaceable">value</i>), (<i class="replaceable">attribute</i>, <i class="replaceable">value</i>), ...]</tt>. Or it may be just an <tt class="sgmltag-element">&lt;a&gt;</tt>, a valid (if useless) <span class="acronym">HTML</span> tag, in which case <tt class="varname">attrs</tt> would be an empty list.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.extract.2.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You can find out whether this <tt class="sgmltag-element">&lt;a&gt;</tt> tag has an <tt class="literal">href</tt> attribute with a simple <a href="../native_data_types/declaring_variables.html#odbchelper.multiassign" title="3.4.2.&nbsp;Assigning Multiple Values at Once">multi-variable</a> <a href="../native_data_types/mapping_lists.html" title="3.6.&nbsp;Mapping Lists">list comprehension</a>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.extract.2.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">String comparisons like <tt class="literal">k=='href'</tt> are always case-sensitive, but that's safe in this case, because <tt class="classname">SGMLParser</tt> converts attribute names to lowercase while building <tt class="varname">attrs</tt>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="dialect.feed.example"></a><h3 class="title">Example&nbsp;8.7.&nbsp;Using <tt class="filename">urllister.py</tt></h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> urllib, urllister</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">usock = urllib.urlopen(<span class='pystring'>"http://diveintopython.org/"</span>)</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">parser = urllister.URLLister()</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">parser.feed(usock.read())</span> <a name="dialect.extract.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">usock.close()</span> <a name="dialect.extract.3.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">parser.close()</span> <a name="dialect.extract.3.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>for</span> url <span class='pykeyword'>in</span> parser.urls: <span class='pykeyword'>print</span> url</span> <a name="dialect.extract.3.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">toc/index.html
+#download
+#languages
+toc/index.html
+appendix/history.html
+download/diveintopython-html-5.0.zip
+download/diveintopython-pdf-5.0.zip
+download/diveintopython-word-5.0.zip
+download/diveintopython-text-5.0.zip
+download/diveintopython-html-flat-5.0.zip
+download/diveintopython-xml-5.0.zip
+download/diveintopython-common-5.0.zip
+</span>
+
+... rest of output omitted for brevity ...</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.extract.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Call the <tt class="function">feed</tt> method, defined in <tt class="classname">SGMLParser</tt>, to get <span class="acronym">HTML</span> into the parser.<sup>[<a name="d0e20503" href="#ftn.d0e20503">1</a>]</sup> It takes a string, which is what <tt class="function">usock.read()</tt> returns.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.extract.3.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Like files, you should <tt class="function">close</tt> your <span class="acronym">URL</span> objects as soon as you're done with them.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.extract.3.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You should <tt class="function">close</tt> your parser object, too, but for a different reason. You've read all the data and fed it to the parser, but the <tt class="function">feed</tt> method isn't guaranteed to have actually processed all the <span class="acronym">HTML</span> you give it; it may buffer it, waiting for more. Be sure to call <tt class="function">close</tt> to flush the buffer and force everything to be fully parsed.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.extract.3.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Once the parser is <tt class="function">close</tt>d, the parsing is complete, and <tt class="varname">parser.urls</tt> contains a list of all the linked <span class="acronym">URL</span>s in the <span class="acronym">HTML</span> document. (Your output may look different, if the download links have been updated by the time you read this.)
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="footnotes">
+ <h3 class="footnotetitle">Footnotes</h3>
+ <div class="footnote">
+ <p><sup>[<a name="ftn.d0e20503" href="#d0e20503">1</a>] </sup>The technical term for a parser like <tt class="classname">SGMLParser</tt> is a <span class="emphasis"><em>consumer</em></span>: it consumes <span class="acronym">HTML</span> and breaks it down. Presumably, the name <tt class="function">feed</tt> was chosen to fit into the whole &#8220;<span class="quote">consumer</span>&#8221; motif. Personally, it makes me think of an exhibit in the zoo where there's just a dark cage with no trees or plants or
+ evidence of life of any kind, but if you stand perfectly still and look really closely you can make out two beady eyes staring
+ back at you from the far left corner, but you convince yourself that that's just your mind playing tricks on you, and the
+ only way you can tell that the whole thing isn't just an empty cage is a small innocuous sign on the railing that reads, &#8220;<span class="quote">Do not feed the parser.</span>&#8221; But maybe that's just me. In any event, it's an interesting mental image.
+ </p>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="introducing_sgmllib.html">&lt;&lt;&nbsp;Introducing sgmllib.py</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#dialect.divein" title="8.1.&nbsp;Diving in">1</a> <span class="divider">|</span> <a href="introducing_sgmllib.html" title="8.2.&nbsp;Introducing sgmllib.py">2</a> <span class="divider">|</span> <span class="thispage">3</span> <span class="divider">|</span> <a href="basehtmlprocessor.html" title="8.4.&nbsp;Introducing BaseHTMLProcessor.py">4</a> <span class="divider">|</span> <a href="locals_and_globals.html" title="8.5.&nbsp;locals and globals">5</a> <span class="divider">|</span> <a href="dictionary_based_string_formatting.html" title="8.6.&nbsp;Dictionary-based string formatting">6</a> <span class="divider">|</span> <a href="quoting_attribute_values.html" title="8.7.&nbsp;Quoting attribute values">7</a> <span class="divider">|</span> <a href="dialect.html" title="8.8.&nbsp;Introducing dialect.py">8</a> <span class="divider">|</span> <a href="all_together.html" title="8.9.&nbsp;Putting it all together">9</a> <span class="divider">|</span> <a href="summary.html" title="8.10.&nbsp;Summary">10</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="basehtmlprocessor.html">Introducing BaseHTMLProcessor.py&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/html_processing/index.html b/help/diveintopython-5.4/html/html_processing/index.html
new file mode 100644
index 0000000..f4ef76a
--- /dev/null
+++ b/help/diveintopython-5.4/html/html_processing/index.html
@@ -0,0 +1,336 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>Chapter&nbsp;8.&nbsp;HTML Processing</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="../toc/index.html" title="Dive Into Python">
+ <link rel="previous" href="../regular_expressions/summary.html" title="7.7.&nbsp;Summary">
+ <link rel="next" href="introducing_sgmllib.html" title="8.2.&nbsp;Introducing sgmllib.py">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<span class="thispage">HTML Processing</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="../regular_expressions/summary.html" title="Prev: &#8220;Summary&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="introducing_sgmllib.html" title="Next: &#8220;Introducing sgmllib.py&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="chapter" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="dialect"></a>Chapter&nbsp;8.&nbsp;<span class="acronym">HTML</span> Processing
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="toc">
+ <ul>
+ <li><span class="section"><a href="index.html#dialect.divein">8.1. Diving in</a></span></li>
+ <li><span class="section"><a href="introducing_sgmllib.html">8.2. Introducing sgmllib.py</a></span></li>
+ <li><span class="section"><a href="extracting_data.html">8.3. Extracting data from HTML documents</a></span></li>
+ <li><span class="section"><a href="basehtmlprocessor.html">8.4. Introducing BaseHTMLProcessor.py</a></span></li>
+ <li><span class="section"><a href="locals_and_globals.html">8.5. locals and globals</a></span></li>
+ <li><span class="section"><a href="dictionary_based_string_formatting.html">8.6. Dictionary-based string formatting</a></span></li>
+ <li><span class="section"><a href="quoting_attribute_values.html">8.7. Quoting attribute values</a></span></li>
+ <li><span class="section"><a href="dialect.html">8.8. Introducing dialect.py</a></span></li>
+ <li><span class="section"><a href="all_together.html">8.9. Putting it all together</a></span></li>
+ <li><span class="section"><a href="summary.html">8.10. Summary</a></span></li>
+ </ul>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="dialect.divein"></a>8.1.&nbsp;Diving in
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>I often see questions on <a href="http://groups.google.com/groups?group=comp.lang.python">comp.lang.python</a> like &#8220;<span class="quote">How can I list all the [headers|images|links] in my <span class="acronym">HTML</span> document?</span>&#8221; &#8220;<span class="quote">How do I parse/translate/munge the text of my <span class="acronym">HTML</span> document but leave the tags alone?</span>&#8221; &#8220;<span class="quote">How can I add/remove/quote attributes of all my <span class="acronym">HTML</span> tags at once?</span>&#8221; This chapter will answer all of these questions.
+ </p>
+ </div>
+ <p>Here is a complete, working <span class="application">Python</span> program in two parts. The first part, <tt class="filename">BaseHTMLProcessor.py</tt>, is a generic tool to help you process <span class="acronym">HTML</span> files by walking through the tags and text blocks. The second part, <tt class="filename">dialect.py</tt>, is an example of how to use <tt class="filename">BaseHTMLProcessor.py</tt> to translate the text of an <span class="acronym">HTML</span> document but leave the tags alone. Read the <tt class="literal">doc string</tt>s and comments to get an overview of what's going on. Most of it will seem like black magic, because it's not obvious how
+ any of these class methods ever get called. Don't worry, all will be revealed in due time.
+ </p>
+ <div class="example"><a name="dialect.basehtml.listing"></a><h3 class="title">Example&nbsp;8.1.&nbsp;<tt class="filename">BaseHTMLProcessor.py</tt></h3>
+ <p>If you have not already done so, you can <a href="http://diveintopython.org/download/diveintopython-examples-5.4.zip" title="Download example scripts">download this and other examples</a> used in this book.
+ </p><pre class="programlisting"><span class='pykeyword'>
+from</span> sgmllib <span class='pykeyword'>import</span> SGMLParser
+<span class='pykeyword'>import</span> htmlentitydefs
+
+<span class='pykeyword'>class</span><span class='pyclass'> BaseHTMLProcessor</span>(SGMLParser):
+ <span class='pykeyword'>def</span><span class='pyclass'> reset</span>(self):
+ <span class='pycomment'># extend (called by SGMLParser.__init__)</span>
+ self.pieces = []
+ SGMLParser.reset(self)
+
+ <span class='pykeyword'>def</span><span class='pyclass'> unknown_starttag</span>(self, tag, attrs):
+ <span class='pycomment'># called for each start tag</span>
+ <span class='pycomment'># attrs is a list of (attr, value) tuples</span>
+ <span class='pycomment'># e.g. for &lt;pre class="screen"&gt;, tag="pre", attrs=[("class", "screen")]</span>
+ <span class='pycomment'># Ideally we would like to reconstruct original tag and attributes, but</span>
+ <span class='pycomment'># we may end up quoting attribute values that weren't quoted in the source</span>
+ <span class='pycomment'># document, or we may change the type of quotes around the attribute value</span>
+ <span class='pycomment'># (single to double quotes).</span>
+ <span class='pycomment'># Note that improperly embedded non-HTML code (like client-side Javascript)</span>
+ <span class='pycomment'># may be parsed incorrectly by the ancestor, causing runtime script errors.</span>
+ <span class='pycomment'># All non-HTML code must be enclosed in HTML comment tags (&lt;!-- code --&gt;)</span>
+ <span class='pycomment'># to ensure that it will pass through this parser unaltered (in handle_comment).</span>
+ strattrs = <span class='pystring'>""</span>.join([<span class='pystring'>' %s="%s"'</span> % (key, value) <span class='pykeyword'>for</span> key, value <span class='pykeyword'>in</span> attrs])
+ self.pieces.append(<span class='pystring'>"&lt;%(tag)s%(strattrs)s&gt;"</span> % locals())
+
+ <span class='pykeyword'>def</span><span class='pyclass'> unknown_endtag</span>(self, tag):
+ <span class='pycomment'># called for each end tag, e.g. for &lt;/pre&gt;, tag will be "pre"</span>
+ <span class='pycomment'># Reconstruct the original end tag.</span>
+ self.pieces.append(<span class='pystring'>"&lt;/%(tag)s&gt;"</span> % locals())
+
+ <span class='pykeyword'>def</span><span class='pyclass'> handle_charref</span>(self, ref):
+ <span class='pycomment'># called for each character reference, e.g. for "&amp;#160;", ref will be "160"</span>
+ <span class='pycomment'># Reconstruct the original character reference.</span>
+ self.pieces.append(<span class='pystring'>"&amp;#%(ref)s;"</span> % locals())
+
+ <span class='pykeyword'>def</span><span class='pyclass'> handle_entityref</span>(self, ref):
+ <span class='pycomment'># called for each entity reference, e.g. for "&amp;copy;", ref will be "copy"</span>
+ <span class='pycomment'># Reconstruct the original entity reference.</span>
+ self.pieces.append(<span class='pystring'>"&amp;%(ref)s"</span> % locals())
+ <span class='pycomment'># standard HTML entities are closed with a semicolon; other entities are not</span>
+ <span class='pykeyword'>if</span> htmlentitydefs.entitydefs.has_key(ref):
+ self.pieces.append(<span class='pystring'>";"</span>)
+
+ <span class='pykeyword'>def</span><span class='pyclass'> handle_data</span>(self, text):
+ <span class='pycomment'># called for each block of plain text, i.e. outside of any tag and</span>
+ <span class='pycomment'># not containing any character or entity references</span>
+ <span class='pycomment'># Store the original text verbatim.</span>
+ self.pieces.append(text)
+
+ <span class='pykeyword'>def</span><span class='pyclass'> handle_comment</span>(self, text):
+ <span class='pycomment'># called for each HTML comment, e.g. &lt;!-- insert Javascript code here --&gt;</span>
+ <span class='pycomment'># Reconstruct the original comment.</span>
+ <span class='pycomment'># It is especially important that the source document enclose client-side</span>
+ <span class='pycomment'># code (like Javascript) within comments so it can pass through this</span>
+ <span class='pycomment'># processor undisturbed; see comments in unknown_starttag for details.</span>
+ self.pieces.append(<span class='pystring'>"&lt;!--%(text)s--&gt;"</span> % locals())
+
+ <span class='pykeyword'>def</span><span class='pyclass'> handle_pi</span>(self, text):
+ <span class='pycomment'># called for each processing instruction, e.g. &lt;?instruction&gt;</span>
+ <span class='pycomment'># Reconstruct original processing instruction.</span>
+ self.pieces.append(<span class='pystring'>"&lt;?%(text)s&gt;"</span> % locals())
+
+ <span class='pykeyword'>def</span><span class='pyclass'> handle_decl</span>(self, text):
+ <span class='pycomment'># called for the DOCTYPE, if present, e.g.</span>
+ <span class='pycomment'># &lt;!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"</span>
+ <span class='pycomment'># "http://www.w3.org/TR/html4/loose.dtd"&gt;</span>
+ <span class='pycomment'># Reconstruct original DOCTYPE</span>
+ self.pieces.append(<span class='pystring'>"&lt;!%(text)s&gt;"</span> % locals())
+
+ <span class='pykeyword'>def</span><span class='pyclass'> output</span>(self):
+ <span class='pystring'>"""Return processed HTML as a single string"""</span>
+ <span class='pykeyword'>return</span> <span class='pystring'>""</span>.join(self.pieces)</pre></div>
+ <div class="example"><a name="d0e19707"></a><h3 class="title">Example&nbsp;8.2.&nbsp;<tt class="filename">dialect.py</tt></h3><pre class="programlisting"><span class='pykeyword'>
+import</span> re
+<span class='pykeyword'>from</span> BaseHTMLProcessor <span class='pykeyword'>import</span> BaseHTMLProcessor
+
+<span class='pykeyword'>class</span><span class='pyclass'> Dialectizer</span>(BaseHTMLProcessor):
+ subs = ()
+
+ <span class='pykeyword'>def</span><span class='pyclass'> reset</span>(self):
+ <span class='pycomment'># extend (called from __init__ in ancestor)</span>
+ <span class='pycomment'># Reset all data attributes</span>
+ self.verbatim = 0
+ BaseHTMLProcessor.reset(self)
+
+ <span class='pykeyword'>def</span><span class='pyclass'> start_pre</span>(self, attrs):
+ <span class='pycomment'># called for every &lt;pre&gt; tag in HTML source</span>
+ <span class='pycomment'># Increment verbatim mode count, then handle tag like normal</span>
+ self.verbatim += 1
+ self.unknown_starttag(<span class='pystring'>"pre"</span>, attrs)
+
+ <span class='pykeyword'>def</span><span class='pyclass'> end_pre</span>(self):
+ <span class='pycomment'># called for every &lt;/pre&gt; tag in HTML source</span>
+ <span class='pycomment'># Decrement verbatim mode count</span>
+ self.unknown_endtag(<span class='pystring'>"pre"</span>)
+ self.verbatim -= 1
+
+ <span class='pykeyword'>def</span><span class='pyclass'> handle_data</span>(self, text):
+ <span class='pycomment'># override</span>
+ <span class='pycomment'># called for every block of text in HTML source</span>
+ <span class='pycomment'># If in verbatim mode, save text unaltered;</span>
+ <span class='pycomment'># otherwise process the text with a series of substitutions</span>
+ self.pieces.append(self.verbatim <span class='pykeyword'>and</span> text <span class='pykeyword'>or</span> self.process(text))
+
+ <span class='pykeyword'>def</span><span class='pyclass'> process</span>(self, text):
+ <span class='pycomment'># called from handle_data</span>
+ <span class='pycomment'># Process text block by performing series of regular expression</span>
+ <span class='pycomment'># substitutions (actual substitions are defined in descendant)</span>
+ <span class='pykeyword'>for</span> fromPattern, toPattern <span class='pykeyword'>in</span> self.subs:
+ text = re.sub(fromPattern, toPattern, text)
+ <span class='pykeyword'>return</span> text
+
+<span class='pykeyword'>class</span><span class='pyclass'> ChefDialectizer</span>(Dialectizer):
+ <span class='pystring'>"""convert HTML to Swedish Chef-speak
+
+ based on the classic chef.x, copyright (c) 1992, 1993 John Hagerman
+ """</span>
+ subs = ((r<span class='pystring'>'a([nu])'</span>, r<span class='pystring'>'u\1'</span>),
+ (r<span class='pystring'>'A([nu])'</span>, r<span class='pystring'>'U\1'</span>),
+ (r<span class='pystring'>'a\B'</span>, r<span class='pystring'>'e'</span>),
+ (r<span class='pystring'>'A\B'</span>, r<span class='pystring'>'E'</span>),
+ (r<span class='pystring'>'en\b'</span>, r<span class='pystring'>'ee'</span>),
+ (r<span class='pystring'>'\Bew'</span>, r<span class='pystring'>'oo'</span>),
+ (r<span class='pystring'>'\Be\b'</span>, r<span class='pystring'>'e-a'</span>),
+ (r<span class='pystring'>'\be'</span>, r<span class='pystring'>'i'</span>),
+ (r<span class='pystring'>'\bE'</span>, r<span class='pystring'>'I'</span>),
+ (r<span class='pystring'>'\Bf'</span>, r<span class='pystring'>'ff'</span>),
+ (r<span class='pystring'>'\Bir'</span>, r<span class='pystring'>'ur'</span>),
+ (r<span class='pystring'>'(\w*?)i(\w*?)$'</span>, r<span class='pystring'>'\1ee\2'</span>),
+ (r<span class='pystring'>'\bow'</span>, r<span class='pystring'>'oo'</span>),
+ (r<span class='pystring'>'\bo'</span>, r<span class='pystring'>'oo'</span>),
+ (r<span class='pystring'>'\bO'</span>, r<span class='pystring'>'Oo'</span>),
+ (r<span class='pystring'>'the'</span>, r<span class='pystring'>'zee'</span>),
+ (r<span class='pystring'>'The'</span>, r<span class='pystring'>'Zee'</span>),
+ (r<span class='pystring'>'th\b'</span>, r<span class='pystring'>'t'</span>),
+ (r<span class='pystring'>'\Btion'</span>, r<span class='pystring'>'shun'</span>),
+ (r<span class='pystring'>'\Bu'</span>, r<span class='pystring'>'oo'</span>),
+ (r<span class='pystring'>'\BU'</span>, r<span class='pystring'>'Oo'</span>),
+ (r<span class='pystring'>'v'</span>, r<span class='pystring'>'f'</span>),
+ (r<span class='pystring'>'V'</span>, r<span class='pystring'>'F'</span>),
+ (r<span class='pystring'>'w'</span>, r<span class='pystring'>'w'</span>),
+ (r<span class='pystring'>'W'</span>, r<span class='pystring'>'W'</span>),
+ (r<span class='pystring'>'([a-z])[.]'</span>, r<span class='pystring'>'\1. Bork Bork Bork!'</span>))
+
+<span class='pykeyword'>class</span><span class='pyclass'> FuddDialectizer</span>(Dialectizer):
+ <span class='pystring'>"""convert HTML to Elmer Fudd-speak"""</span>
+ subs = ((r<span class='pystring'>'[rl]'</span>, r<span class='pystring'>'w'</span>),
+ (r<span class='pystring'>'qu'</span>, r<span class='pystring'>'qw'</span>),
+ (r<span class='pystring'>'th\b'</span>, r<span class='pystring'>'f'</span>),
+ (r<span class='pystring'>'th'</span>, r<span class='pystring'>'d'</span>),
+ (r<span class='pystring'>'n[.]'</span>, r<span class='pystring'>'n, uh-hah-hah-hah.'</span>))
+
+<span class='pykeyword'>class</span><span class='pyclass'> OldeDialectizer</span>(Dialectizer):
+ <span class='pystring'>"""convert HTML to mock Middle English"""</span>
+ subs = ((r<span class='pystring'>'i([bcdfghjklmnpqrstvwxyz])e\b'</span>, r<span class='pystring'>'y\1'</span>),
+ (r<span class='pystring'>'i([bcdfghjklmnpqrstvwxyz])e'</span>, r<span class='pystring'>'y\1\1e'</span>),
+ (r<span class='pystring'>'ick\b'</span>, r<span class='pystring'>'yk'</span>),
+ (r<span class='pystring'>'ia([bcdfghjklmnpqrstvwxyz])'</span>, r<span class='pystring'>'e\1e'</span>),
+ (r<span class='pystring'>'e[ea]([bcdfghjklmnpqrstvwxyz])'</span>, r<span class='pystring'>'e\1e'</span>),
+ (r<span class='pystring'>'([bcdfghjklmnpqrstvwxyz])y'</span>, r<span class='pystring'>'\1ee'</span>),
+ (r<span class='pystring'>'([bcdfghjklmnpqrstvwxyz])er'</span>, r<span class='pystring'>'\1re'</span>),
+ (r<span class='pystring'>'([aeiou])re\b'</span>, r<span class='pystring'>'\1r'</span>),
+ (r<span class='pystring'>'ia([bcdfghjklmnpqrstvwxyz])'</span>, r<span class='pystring'>'i\1e'</span>),
+ (r<span class='pystring'>'tion\b'</span>, r<span class='pystring'>'cioun'</span>),
+ (r<span class='pystring'>'ion\b'</span>, r<span class='pystring'>'ioun'</span>),
+ (r<span class='pystring'>'aid'</span>, r<span class='pystring'>'ayde'</span>),
+ (r<span class='pystring'>'ai'</span>, r<span class='pystring'>'ey'</span>),
+ (r<span class='pystring'>'ay\b'</span>, r<span class='pystring'>'y'</span>),
+ (r<span class='pystring'>'ay'</span>, r<span class='pystring'>'ey'</span>),
+ (r<span class='pystring'>'ant'</span>, r<span class='pystring'>'aunt'</span>),
+ (r<span class='pystring'>'ea'</span>, r<span class='pystring'>'ee'</span>),
+ (r<span class='pystring'>'oa'</span>, r<span class='pystring'>'oo'</span>),
+ (r<span class='pystring'>'ue'</span>, r<span class='pystring'>'e'</span>),
+ (r<span class='pystring'>'oe'</span>, r<span class='pystring'>'o'</span>),
+ (r<span class='pystring'>'ou'</span>, r<span class='pystring'>'ow'</span>),
+ (r<span class='pystring'>'ow'</span>, r<span class='pystring'>'ou'</span>),
+ (r<span class='pystring'>'\bhe'</span>, r<span class='pystring'>'hi'</span>),
+ (r<span class='pystring'>'ve\b'</span>, r<span class='pystring'>'veth'</span>),
+ (r<span class='pystring'>'se\b'</span>, r<span class='pystring'>'e'</span>),
+ (r<span class='pystring'>"'s\b"</span>, r<span class='pystring'>'es'</span>),
+ (r<span class='pystring'>'ic\b'</span>, r<span class='pystring'>'ick'</span>),
+ (r<span class='pystring'>'ics\b'</span>, r<span class='pystring'>'icc'</span>),
+ (r<span class='pystring'>'ical\b'</span>, r<span class='pystring'>'ick'</span>),
+ (r<span class='pystring'>'tle\b'</span>, r<span class='pystring'>'til'</span>),
+ (r<span class='pystring'>'ll\b'</span>, r<span class='pystring'>'l'</span>),
+ (r<span class='pystring'>'ould\b'</span>, r<span class='pystring'>'olde'</span>),
+ (r<span class='pystring'>'own\b'</span>, r<span class='pystring'>'oune'</span>),
+ (r<span class='pystring'>'un\b'</span>, r<span class='pystring'>'onne'</span>),
+ (r<span class='pystring'>'rry\b'</span>, r<span class='pystring'>'rye'</span>),
+ (r<span class='pystring'>'est\b'</span>, r<span class='pystring'>'este'</span>),
+ (r<span class='pystring'>'pt\b'</span>, r<span class='pystring'>'pte'</span>),
+ (r<span class='pystring'>'th\b'</span>, r<span class='pystring'>'the'</span>),
+ (r<span class='pystring'>'ch\b'</span>, r<span class='pystring'>'che'</span>),
+ (r<span class='pystring'>'ss\b'</span>, r<span class='pystring'>'sse'</span>),
+ (r<span class='pystring'>'([wybdp])\b'</span>, r<span class='pystring'>'\1e'</span>),
+ (r<span class='pystring'>'([rnt])\b'</span>, r<span class='pystring'>'\1\1e'</span>),
+ (r<span class='pystring'>'from'</span>, r<span class='pystring'>'fro'</span>),
+ (r<span class='pystring'>'when'</span>, r<span class='pystring'>'whan'</span>))
+
+<span class='pykeyword'>def</span><span class='pyclass'> translate</span>(url, dialectName=<span class='pystring'>"chef"</span>):
+ <span class='pystring'>"""fetch URL and translate using dialect
+
+ dialect in ("chef", "fudd", "olde")"""</span>
+ <span class='pykeyword'>import</span> urllib
+ sock = urllib.urlopen(url)
+ htmlSource = sock.read()
+ sock.close()
+ parserName = <span class='pystring'>"%sDialectizer"</span> % dialectName.capitalize()
+ parserClass = globals()[parserName]
+ parser = parserClass()
+ parser.feed(htmlSource)
+ parser.close()
+ <span class='pykeyword'>return</span> parser.output()
+
+<span class='pykeyword'>def</span><span class='pyclass'> test</span>(url):
+ <span class='pystring'>"""test all dialects against URL"""</span>
+ <span class='pykeyword'>for</span> dialect <span class='pykeyword'>in</span> (<span class='pystring'>"chef"</span>, <span class='pystring'>"fudd"</span>, <span class='pystring'>"olde"</span>):
+ outfile = <span class='pystring'>"%s.html"</span> % dialect
+ fsock = open(outfile, <span class='pystring'>"wb"</span>)
+ fsock.write(translate(url, dialect))
+ fsock.close()
+ <span class='pykeyword'>import</span> webbrowser
+ webbrowser.open_new(outfile)
+
+<span class='pykeyword'>if</span> __name__ == <span class='pystring'>"__main__"</span>:
+ test(<span class='pystring'>"http://diveintopython.org/odbchelper_list.html"</span>)</pre></div>
+ <div class="example"><a name="d0e19713"></a><h3 class="title">Example&nbsp;8.3.&nbsp;Output of <tt class="filename">dialect.py</tt></h3>
+ <p>Running this script will translate <a href="../native_data_types/lists.html" title="3.2.&nbsp;Introducing Lists">Section&nbsp;3.2, &#8220;Introducing Lists&#8221;</a> into <a href="../native_data_types/chef.html">mock Swedish Chef-speak</a> (from The Muppets), <a href="../native_data_types/fudd.html">mock Elmer Fudd-speak</a> (from Bugs Bunny cartoons), and <a href="../native_data_types/olde.html">mock Middle English</a> (loosely based on Chaucer's <i class="citetitle">The Canterbury Tales</i>). If you look at the <span class="acronym">HTML</span> source of the output pages, you'll see that all the <span class="acronym">HTML</span> tags and attributes are untouched, but the text between the tags has been &#8220;<span class="quote">translated</span>&#8221; into the mock language. If you look closer, you'll see that, in fact, only the titles and paragraphs were translated; the
+ code listings and screen examples were left untouched.
+ </p><pre class="programlisting">
+&lt;div <span class='pykeyword'>class</span>="<span class='pyclass'>abstract</span>"&gt;
+&lt;p&gt;Lists awe &lt;span <span class='pykeyword'>class</span>="<span class='pyclass'>application</span>"&gt;Pydon&lt;/span&gt;'s wowkhowse datatype.
+If youw onwy expewience wif wists <span class='pykeyword'>is</span> awways <span class='pykeyword'>in</span>
+&lt;span <span class='pykeyword'>class</span>="<span class='pyclass'>application</span>"&gt;Visuaw Basic&lt;/span&gt; ow (God fowbid) de datastowe
+<span class='pykeyword'>in</span> &lt;span <span class='pykeyword'>class</span>="<span class='pyclass'>application</span>"&gt;Powewbuiwdew&lt;/span&gt;, bwace youwsewf fow
+&lt;span <span class='pykeyword'>class</span>="<span class='pyclass'>application</span>"&gt;Pydon&lt;/span&gt; wists.&lt;/p&gt;
+&lt;/div&gt;
+</pre></div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="../regular_expressions/summary.html">&lt;&lt;&nbsp;Summary</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<span class="thispage">1</span> <span class="divider">|</span> <a href="introducing_sgmllib.html" title="8.2.&nbsp;Introducing sgmllib.py">2</a> <span class="divider">|</span> <a href="extracting_data.html" title="8.3.&nbsp;Extracting data from HTML documents">3</a> <span class="divider">|</span> <a href="basehtmlprocessor.html" title="8.4.&nbsp;Introducing BaseHTMLProcessor.py">4</a> <span class="divider">|</span> <a href="locals_and_globals.html" title="8.5.&nbsp;locals and globals">5</a> <span class="divider">|</span> <a href="dictionary_based_string_formatting.html" title="8.6.&nbsp;Dictionary-based string formatting">6</a> <span class="divider">|</span> <a href="quoting_attribute_values.html" title="8.7.&nbsp;Quoting attribute values">7</a> <span class="divider">|</span> <a href="dialect.html" title="8.8.&nbsp;Introducing dialect.py">8</a> <span class="divider">|</span> <a href="all_together.html" title="8.9.&nbsp;Putting it all together">9</a> <span class="divider">|</span> <a href="summary.html" title="8.10.&nbsp;Summary">10</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="introducing_sgmllib.html">Introducing sgmllib.py&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/html_processing/introducing_sgmllib.html b/help/diveintopython-5.4/html/html_processing/introducing_sgmllib.html
new file mode 100644
index 0000000..5627231
--- /dev/null
+++ b/help/diveintopython-5.4/html/html_processing/introducing_sgmllib.html
@@ -0,0 +1,173 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>8.2.&nbsp;Introducing sgmllib.py</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;8.&nbsp;HTML Processing">
+ <link rel="previous" href="index.html" title="Chapter&nbsp;8.&nbsp;HTML Processing">
+ <link rel="next" href="extracting_data.html" title="8.3.&nbsp;Extracting data from HTML documents">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">HTML Processing</a>&nbsp;&gt;&nbsp;<span class="thispage">Introducing sgmllib.py</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="index.html" title="Prev: &#8220;HTML Processing&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="extracting_data.html" title="Next: &#8220;Extracting data from HTML documents&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="dialect.sgmllib"></a>8.2.&nbsp;Introducing <tt class="filename">sgmllib.py</tt></h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p><span class="acronym">HTML</span> processing is broken into three steps: breaking down the <span class="acronym">HTML</span> into its constituent pieces, fiddling with the pieces, and reconstructing the pieces into <span class="acronym">HTML</span> again. The first step is done by <tt class="filename">sgmllib.py</tt>, a part of the standard <span class="application">Python</span> library.
+ </p>
+ </div>
+ <p>The key to understanding this chapter is to realize that <span class="acronym">HTML</span> is not just text, it is structured text. The structure is derived from the more-or-less-hierarchical sequence of start tags
+ and end tags. Usually you don't work with <span class="acronym">HTML</span> this way; you work with it <span class="emphasis"><em>textually</em></span> in a text editor, or <span class="emphasis"><em>visually</em></span> in a web browser or web authoring tool. <tt class="filename">sgmllib.py</tt> presents <span class="acronym">HTML</span> <span class="emphasis"><em>structurally</em></span>.
+ </p>
+ <p><tt class="filename">sgmllib.py</tt> contains one important class: <tt class="classname">SGMLParser</tt>. <tt class="classname">SGMLParser</tt> parses <span class="acronym">HTML</span> into useful pieces, like start tags and end tags. As soon as it succeeds in breaking down some data into a useful piece,
+ it calls a method on itself based on what it found. In order to use the parser, you subclass the <tt class="classname">SGMLParser</tt> class and override these methods. This is what I meant when I said that it presents <span class="acronym">HTML</span> <span class="emphasis"><em>structurally</em></span>: the structure of the <span class="acronym">HTML</span> determines the sequence of method calls and the arguments passed to each method.
+ </p>
+ <p><tt class="classname">SGMLParser</tt> parses <span class="acronym">HTML</span> into 8 kinds of data, and calls a separate method for each of them:
+ </p>
+ <div class="variablelist">
+ <dl>
+ <dt><span class="term">Start tag</span></dt>
+ <dd>An <span class="acronym">HTML</span> tag that starts a block, like <tt class="sgmltag-element">&lt;html&gt;</tt>, <tt class="sgmltag-element">&lt;head&gt;</tt>, <tt class="sgmltag-element">&lt;body&gt;</tt>, or <tt class="sgmltag-element">&lt;pre&gt;</tt>, or a standalone tag like <tt class="sgmltag-element">&lt;br&gt;</tt> or <tt class="sgmltag-element">&lt;img&gt;</tt>. When it finds a start tag <i class="replaceable"><tt>tagname</tt></i>, <tt class="classname">SGMLParser</tt> will look for a method called <tt class="function">start_<i class="replaceable"><tt>tagname</tt></i></tt> or <tt class="function">do_<i class="replaceable"><tt>tagname</tt></i></tt>. For instance, when it finds a <tt class="sgmltag-element">&lt;pre&gt;</tt> tag, it will look for a <tt class="function">start_pre</tt> or <tt class="function">do_pre</tt> method. If found, <tt class="classname">SGMLParser</tt> calls this method with a list of the tag's attributes; otherwise, it calls <tt class="function">unknown_starttag</tt> with the tag name and list of attributes.
+ </dd>
+ <dt><span class="term">End tag</span></dt>
+ <dd>An <span class="acronym">HTML</span> tag that ends a block, like <tt class="sgmltag-element">&lt;/html&gt;</tt>, <tt class="sgmltag-element">&lt;/head&gt;</tt>, <tt class="sgmltag-element">&lt;/body&gt;</tt>, or <tt class="sgmltag-element">&lt;/pre&gt;</tt>. When it finds an end tag, <tt class="classname">SGMLParser</tt> will look for a method called <tt class="function">end_<i class="replaceable"><tt>tagname</tt></i></tt>. If found, <tt class="classname">SGMLParser</tt> calls this method, otherwise it calls <tt class="function">unknown_endtag</tt> with the tag name.
+ </dd>
+ <dt><span class="term">Character reference</span></dt>
+ <dd>An escaped character referenced by its decimal or hexadecimal equivalent, like <tt class="literal">&amp;#160;</tt>. When found, <tt class="classname">SGMLParser</tt> calls <tt class="function">handle_charref</tt> with the text of the decimal or hexadecimal character equivalent.
+ </dd>
+ <dt><span class="term">Entity reference</span></dt>
+ <dd>An <span class="acronym">HTML</span> entity, like <tt class="literal">&amp;copy;</tt>. When found, <tt class="classname">SGMLParser</tt> calls <tt class="function">handle_entityref</tt> with the name of the <span class="acronym">HTML</span> entity.
+ </dd>
+ <dt><span class="term">Comment</span></dt>
+ <dd>An <span class="acronym">HTML</span> comment, enclosed in <tt class="literal">&lt;!-- ... --&gt;</tt>. When found, <tt class="classname">SGMLParser</tt> calls <tt class="function">handle_comment</tt> with the body of the comment.
+ </dd>
+ <dt><span class="term">Processing instruction</span></dt>
+ <dd>An <span class="acronym">HTML</span> processing instruction, enclosed in <tt class="literal">&lt;? ... &gt;</tt>. When found, <tt class="classname">SGMLParser</tt> calls <tt class="function">handle_pi</tt> with the body of the processing instruction.
+ </dd>
+ <dt><span class="term">Declaration</span></dt>
+ <dd>An <span class="acronym">HTML</span> declaration, such as a <tt class="sgmltag-element">DOCTYPE</tt>, enclosed in <tt class="literal">&lt;! ... &gt;</tt>. When found, <tt class="classname">SGMLParser</tt> calls <tt class="function">handle_decl</tt> with the body of the declaration.
+ </dd>
+ <dt><span class="term">Text data</span></dt>
+ <dd>A block of text. Anything that doesn't fit into the other 7 categories. When found, <tt class="classname">SGMLParser</tt> calls <tt class="function">handle_data</tt> with the text.
+ </dd>
+ </dl>
+ </div><a name="d0e20023"></a><table class="important" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/important.png" alt="Important" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%"><span class="application">Python</span> 2.0 had a bug where <tt class="classname">SGMLParser</tt> would not recognize declarations at all (<tt class="function">handle_decl</tt> would never be called), which meant that <tt class="sgmltag-element">DOCTYPE</tt>s were silently ignored. This is fixed in <span class="application">Python</span> 2.1.
+ </td>
+ </tr>
+ </table>
+ <p><tt class="filename">sgmllib.py</tt> comes with a test suite to illustrate this. You can run <tt class="filename">sgmllib.py</tt>, passing the name of an <span class="acronym">HTML</span> file on the command line, and it will print out the tags and other elements as it parses them. It does this by subclassing
+ the <tt class="classname">SGMLParser</tt> class and defining <tt class="function">unknown_starttag</tt>, <tt class="function">unknown_endtag</tt>, <tt class="function">handle_data</tt> and other methods which simply print their arguments.
+ </p><a name="tip.commandline.windows"></a><table class="tip" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/tip.png" alt="Tip" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">In the <span class="application">ActivePython</span> <span class="acronym">IDE</span> on Windows, you can specify command line arguments in the &#8220;<span class="quote">Run script</span>&#8221; dialog. Separate multiple arguments with spaces.
+ </td>
+ </tr>
+ </table>
+ <div class="example"><a name="d0e20080"></a><h3 class="title">Example&nbsp;8.4.&nbsp;Sample test of <tt class="filename">sgmllib.py</tt></h3>
+ <p>Here is a snippet from the table of contents of the <span class="acronym">HTML</span> version of this book. Of course your paths may vary. (If you haven't downloaded the <span class="acronym">HTML</span> version of the book, you can do so at <a href="http://diveintopython.org/">http://diveintopython.org/</a>.
+ </p><pre class="screen">
+<tt class="prompt">c:\python23\lib&gt;</tt> <span class="userinput">type <span class='pystring'>"c:\downloads\diveintopython\html\toc\index.html"</span></span>
+<tt class="literal">
+&lt;!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"&gt;
+&lt;html lang="en"&gt;
+ &lt;head&gt;
+ &lt;meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"&gt;
+
+ &lt;title&gt;Dive Into Python&lt;/title&gt;
+ &lt;link rel="stylesheet" href="diveintopython.css" type="text/css"&gt;
+
+... rest of file omitted for brevity ...
+</tt></pre><p>Running this through the test suite of <tt class="filename">sgmllib.py</tt> yields this output:
+ </p><pre class="screen">
+<tt class="prompt">c:\python23\lib&gt;</tt> <span class="userinput">python sgmllib.py <span class='pystring'>"c:\downloads\diveintopython\html\toc\index.html"</span></span>
+<span class="computeroutput">data: '\n\n'
+start tag: &lt;html lang="en" &gt;
+data: '\n '
+start tag: &lt;head&gt;
+data: '\n '
+start tag: &lt;meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" &gt;
+data: '\n \n '
+start tag: &lt;title&gt;
+data: 'Dive Into Python'
+end tag: &lt;/title&gt;
+data: '\n '
+start tag: &lt;link rel="stylesheet" href="diveintopython.css" type="text/css" &gt;
+data: '\n '
+
+... rest of output omitted for brevity ...
+</span></pre></div>
+ <p>Here's the roadmap for the rest of the chapter:</p>
+ <div class="itemizedlist">
+ <ul>
+ <li>Subclass <tt class="classname">SGMLParser</tt> to create classes that extract interesting data out of <span class="acronym">HTML</span> documents.
+ </li>
+ <li>Subclass <tt class="classname">SGMLParser</tt> to create <tt class="classname">BaseHTMLProcessor</tt>, which overrides all 8 handler methods and uses them to reconstruct the original <span class="acronym">HTML</span> from the pieces.
+ </li>
+ <li>Subclass <tt class="classname">BaseHTMLProcessor</tt> to create <tt class="classname">Dialectizer</tt>, which adds some methods to process specific <span class="acronym">HTML</span> tags specially, and overrides the <tt class="function">handle_data</tt> method to provide a framework for processing the text blocks between the <span class="acronym">HTML</span> tags.
+ </li>
+ <li>Subclass <tt class="classname">Dialectizer</tt> to create classes that define text processing rules used by <tt class="function">Dialectizer.handle_data</tt>.
+ </li>
+ <li>Write a test suite that grabs a real web page from <tt class="systemitem">http://diveintopython.org/</tt> and processes it.
+ </li>
+ </ul>
+ </div>
+ <p>Along the way, you'll also learn about <tt class="function">locals</tt>, <tt class="function">globals</tt>, and dictionary-based string formatting.
+ </p>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="index.html">&lt;&lt;&nbsp;HTML Processing</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#dialect.divein" title="8.1.&nbsp;Diving in">1</a> <span class="divider">|</span> <span class="thispage">2</span> <span class="divider">|</span> <a href="extracting_data.html" title="8.3.&nbsp;Extracting data from HTML documents">3</a> <span class="divider">|</span> <a href="basehtmlprocessor.html" title="8.4.&nbsp;Introducing BaseHTMLProcessor.py">4</a> <span class="divider">|</span> <a href="locals_and_globals.html" title="8.5.&nbsp;locals and globals">5</a> <span class="divider">|</span> <a href="dictionary_based_string_formatting.html" title="8.6.&nbsp;Dictionary-based string formatting">6</a> <span class="divider">|</span> <a href="quoting_attribute_values.html" title="8.7.&nbsp;Quoting attribute values">7</a> <span class="divider">|</span> <a href="dialect.html" title="8.8.&nbsp;Introducing dialect.py">8</a> <span class="divider">|</span> <a href="all_together.html" title="8.9.&nbsp;Putting it all together">9</a> <span class="divider">|</span> <a href="summary.html" title="8.10.&nbsp;Summary">10</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="extracting_data.html">Extracting data from HTML documents&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/html_processing/locals_and_globals.html b/help/diveintopython-5.4/html/html_processing/locals_and_globals.html
new file mode 100644
index 0000000..28ad609
--- /dev/null
+++ b/help/diveintopython-5.4/html/html_processing/locals_and_globals.html
@@ -0,0 +1,267 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>8.5.&nbsp;locals and globals</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;8.&nbsp;HTML Processing">
+ <link rel="previous" href="basehtmlprocessor.html" title="8.4.&nbsp;Introducing BaseHTMLProcessor.py">
+ <link rel="next" href="dictionary_based_string_formatting.html" title="8.6.&nbsp;Dictionary-based string formatting">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">HTML Processing</a>&nbsp;&gt;&nbsp;<span class="thispage">locals and globals</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="basehtmlprocessor.html" title="Prev: &#8220;Introducing BaseHTMLProcessor.py&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="dictionary_based_string_formatting.html" title="Next: &#8220;Dictionary-based string formatting&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="dialect.locals"></a>8.5.&nbsp;<tt class="function">locals</tt> and <tt class="function">globals</tt></h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>Let's digress from <span class="acronym">HTML</span> processing for a minute and talk about how <span class="application">Python</span> handles variables. <span class="application">Python</span> has two built-in functions, <tt class="function">locals</tt> and <tt class="function">globals</tt>, which provide dictionary-based access to local and global variables.
+ </p>
+ </div>
+ <p>Remember <tt class="function">locals</tt>? You first saw it here:
+ </p>
+ <div class="informalexample"><pre class="programlisting">
+ <span class='pykeyword'>def</span><span class='pyclass'> unknown_starttag</span>(self, tag, attrs):
+ strattrs = <span class='pystring'>""</span>.join([<span class='pystring'>' %s="%s"'</span> % (key, value) <span class='pykeyword'>for</span> key, value <span class='pykeyword'>in</span> attrs])
+ self.pieces.append(<span class='pystring'>"&lt;%(tag)s%(strattrs)s&gt;"</span> % locals())
+</pre></div>
+ <p>No, wait, you can't learn about <tt class="function">locals</tt> yet. First, you need to learn about namespaces. This is dry stuff, but it's important, so pay attention.
+ </p>
+ <p><span class="application">Python</span> uses what are called namespaces to keep track of variables. A namespace is just like a dictionary where the keys are names
+ of variables and the dictionary values are the values of those variables. In fact, you can access a namespace as a <span class="application">Python</span> dictionary, as you'll see in a minute.
+ </p>
+ <p>At any particular point in a <span class="application">Python</span> program, there are several namespaces available. Each function has its own namespace, called the local namespace, which
+ keeps track of the function's variables, including function arguments and locally defined variables. Each module has its
+ own namespace, called the global namespace, which keeps track of the module's variables, including functions, classes, any
+ other imported modules, and module-level variables and constants. And there is the built-in namespace, accessible from any
+ module, which holds built-in functions and exceptions.
+ </p>
+ <p>When a line of code asks for the value of a variable <tt class="varname">x</tt>, <span class="application">Python</span> will search for that variable in all the available namespaces, in order:
+ </p>
+ <div class="orderedlist">
+ <ol type="1">
+ <li>local namespace - specific to the current function or class method. If the function defines a local variable <tt class="varname">x</tt>, or has an argument <tt class="varname">x</tt>, <span class="application">Python</span> will use this and stop searching.
+ </li>
+ <li>global namespace - specific to the current module. If the module has defined a variable, function, or class called <tt class="varname">x</tt>, <span class="application">Python</span> will use that and stop searching.
+ </li>
+ <li>built-in namespace - global to all modules. As a last resort, <span class="application">Python</span> will assume that <tt class="varname">x</tt> is the name of built-in function or variable.
+ </li>
+ </ol>
+ </div>
+ <p>If <span class="application">Python</span> doesn't find <tt class="varname">x</tt> in any of these namespaces, it gives up and raises a <tt class="errorcode">NameError</tt> with the message <tt class="errorname">There is no variable named 'x'</tt>, which you saw back in <a href="../native_data_types/declaring_variables.html#odbchelper.unboundvariable" title="Example&nbsp;3.18.&nbsp;Referencing an Unbound Variable">Example&nbsp;3.18, &#8220;Referencing an Unbound Variable&#8221;</a>, but you didn't appreciate how much work <span class="application">Python</span> was doing before giving you that error.
+ </p><a name="d0e21061"></a><table class="important" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/important.png" alt="Important" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%"><span class="application">Python</span> 2.2 introduced a subtle but important change that affects the namespace search order: nested scopes. In versions of <span class="application">Python</span> prior to 2.2, when you reference a variable within a <a href="../file_handling/all_together.html#fileinfo.nested" title="Example&nbsp;6.21.&nbsp;listDirectory">nested function</a> or <a href="../power_of_introspection/lambda_functions.html" title="4.7.&nbsp;Using lambda Functions"><tt class="literal">lambda</tt> function</a>, <span class="application">Python</span> will search for that variable in the current (nested or <tt class="literal">lambda</tt>) function's namespace, then in the module's namespace. <span class="application">Python</span> 2.2 will search for the variable in the current (nested or <tt class="literal">lambda</tt>) function's namespace, <span class="emphasis"><em>then in the parent function's namespace</em></span>, then in the module's namespace. <span class="application">Python</span> 2.1 can work either way; by default, it works like <span class="application">Python</span> 2.0, but you can add the following line of code at the top of your module to make your module work like <span class="application">Python</span> 2.2:<pre class="programlisting"><span class='pykeyword'>
+from</span> __future__ <span class='pykeyword'>import</span> nested_scopes</pre></td>
+ </tr>
+ </table>
+ <p>Are you confused yet? Don't despair! This is really cool, I promise. Like many things in <span class="application">Python</span>, namespaces are <span class="emphasis"><em>directly accessible at run-time</em></span>. How? Well, the local namespace is accessible via the built-in <tt class="function">locals</tt> function, and the global (module level) namespace is accessible via the built-in <tt class="function">globals</tt> function.
+ </p>
+ <div class="example"><a name="d0e21119"></a><h3 class="title">Example&nbsp;8.10.&nbsp;Introducing <tt class="function">locals</tt></h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>def</span><span class='pyclass'> foo</span>(arg):</span> <a name="dialect.locals.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">... </tt><span class="userinput">x = 1</span>
+<tt class="prompt">... </tt><span class="userinput"><span class='pykeyword'>print</span> locals()</span>
+<tt class="prompt">... </tt>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">foo(7)</span> <a name="dialect.locals.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">{'arg': 7, 'x': 1}</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">foo(<span class='pystring'>'bar'</span>)</span> <a name="dialect.locals.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">{'arg': 'bar', 'x': 1}</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.locals.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The function <tt class="function">foo</tt> has two variables in its local namespace: <tt class="varname">arg</tt>, whose value is passed in to the function, and <tt class="varname">x</tt>, which is defined within the function.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.locals.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">locals</tt> returns a dictionary of name/value pairs. The keys of this dictionary are the names of the variables as strings; the values
+ of the dictionary are the actual values of the variables. So calling <tt class="function">foo</tt> with <tt class="literal">7</tt> prints the dictionary containing the function's two local variables: <tt class="varname">arg</tt> (<tt class="literal">7</tt>) and <tt class="varname">x</tt> (<tt class="constant">1</tt>).
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.locals.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Remember, <span class="application">Python</span> has dynamic typing, so you could just as easily pass a string in for <tt class="varname">arg</tt>; the function (and the call to <tt class="function">locals</tt>) would still work just as well. <tt class="function">locals</tt> works with all variables of all datatypes.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>What <tt class="function">locals</tt> does for the local (function) namespace, <tt class="function">globals</tt> does for the global (module) namespace. <tt class="function">globals</tt> is more exciting, though, because a module's namespace is more exciting.<sup>[<a name="d0e21226" href="#ftn.d0e21226">3</a>]</sup> Not only does the module's namespace include module-level variables and constants, it includes all the functions and classes
+ defined in the module. Plus, it includes anything that was imported into the module.
+ </p>
+ <p>Remember the difference between <a href="../object_oriented_framework/importing_modules.html" title="5.2.&nbsp;Importing Modules Using from module import"><tt class="literal">from <i class="replaceable">module</i> import</tt></a> and <a href="../getting_to_know_python/everything_is_an_object.html#odbchelper.import" title="Example&nbsp;2.3.&nbsp;Accessing the buildConnectionString Function's doc string"><tt class="literal">import <i class="replaceable">module</i></tt></a>? With <tt class="literal">import <i class="replaceable">module</i></tt>, the module itself is imported, but it retains its own namespace, which is why you need to use the module name to access
+ any of its functions or attributes: <tt class="literal"><i class="replaceable">module</i>.<i class="replaceable">function</i></tt>. But with <tt class="literal">from <i class="replaceable">module</i> import</tt>, you're actually importing specific functions and attributes from another module into your own namespace, which is why you
+ access them directly without referencing the original module they came from. With the <tt class="function">globals</tt> function, you can actually see this happen.
+ </p>
+ <div class="example"><a name="dialect.globals.example"></a><h3 class="title">Example&nbsp;8.11.&nbsp;Introducing <tt class="function">globals</tt></h3>
+ <p>Look at the following block of code at the bottom of <tt class="filename">BaseHTMLProcessor.py</tt>:
+ </p><pre class="programlisting"><span class='pykeyword'>
+if</span> __name__ == <span class='pystring'>"__main__"</span>:
+ <span class='pykeyword'>for</span> k, v <span class='pykeyword'>in</span> globals().items(): <a name="dialect.locals.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ <span class='pykeyword'>print</span> k, <span class='pystring'>"="</span>, v</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.locals.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Just so you don't get intimidated, remember that you've seen all this before. The <tt class="function">globals</tt> function returns a dictionary, and you're <a href="../file_handling/for_loops.html#dictionaryiter.example" title="Example&nbsp;6.10.&nbsp;Iterating Through a Dictionary">iterating through the dictionary</a> using the <tt class="function">items</tt> method and <a href="../native_data_types/declaring_variables.html#odbchelper.multiassign" title="3.4.2.&nbsp;Assigning Multiple Values at Once">multi-variable assignment</a>. The only thing new here is the <tt class="function">globals</tt> function.
+ </td>
+ </tr>
+ </table>
+ </div>
+ <p>Now running the script from the command line gives this output (note that your output may be slightly different, depending
+ on your platform and where you installed <span class="application">Python</span>):
+ </p><pre class="screen"><tt class="prompt">c:\docbook\dip\py&gt;</tt> <span class="userinput">python BaseHTMLProcessor.py</span></pre><pre class="programlisting">
+SGMLParser = sgmllib.SGMLParser <a name="dialect.locals.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+htmlentitydefs = &lt;module <span class='pystring'>'htmlentitydefs'</span> <span class='pykeyword'>from</span> <span class='pystring'>'C:\Python23\lib\htmlentitydefs.py'</span>&gt; <a name="dialect.locals.3.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+BaseHTMLProcessor = __main__.BaseHTMLProcessor <a name="dialect.locals.3.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+__name__ = __main__ <a name="dialect.locals.3.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+... rest of output omitted <span class='pykeyword'>for</span> brevity...</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.locals.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="classname">SGMLParser</tt> was imported from <tt class="filename">sgmllib</tt>, using <tt class="literal">from <i class="replaceable">module</i> import</tt>. That means that it was imported directly into the module's namespace, and here it is.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.locals.3.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Contrast this with <tt class="filename">htmlentitydefs</tt>, which was imported using <tt class="literal">import</tt>. That means that the <tt class="filename">htmlentitydefs</tt> module itself is in the namespace, but the <tt class="varname">entitydefs</tt> variable defined within <tt class="filename">htmlentitydefs</tt> is not.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.locals.3.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This module only defines one class, <tt class="classname">BaseHTMLProcessor</tt>, and here it is. Note that the value here is <a href="../object_oriented_framework/class_attributes.html#fileinfo.classattributes.intro" title="Example&nbsp;5.17.&nbsp;Introducing Class Attributes">the class itself</a>, not a specific instance of the class.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.locals.3.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Remember the <a href="../getting_to_know_python/testing_modules.html#odbchelper.ifnametrick"><tt class="literal">if <span class="literal">__name__</span></tt> trick</a>? When running a module (as opposed to importing it from another module), the built-in <tt class="literal">__name__</tt> attribute is a special value, <tt class="literal">__main__</tt>. Since you ran this module as a script from the command line, <tt class="literal">__name__</tt> is <tt class="literal">__main__</tt>, which is why the little test code to print the <tt class="function">globals</tt> got executed.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div><a name="tip.localsbyname"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">Using the <tt class="function">locals</tt> and <tt class="function">globals</tt> functions, you can get the value of arbitrary variables dynamically, providing the variable name as a string. This mirrors
+ the functionality of the <a href="../power_of_introspection/getattr.html" title="4.4.&nbsp;Getting Object References With getattr"><tt class="function">getattr</tt></a> function, which allows you to access arbitrary functions dynamically by providing the function name as a string.
+ </td>
+ </tr>
+ </table>
+ <p>There is one other important difference between the <tt class="function">locals</tt> and <tt class="function">globals</tt> functions, which you should learn now before it bites you. It will bite you anyway, but at least then you'll remember learning
+ it.
+ </p>
+ <div class="example"><a name="dialect.locals.readonly.example"></a><h3 class="title">Example&nbsp;8.12.&nbsp;<tt class="function">locals</tt> is read-only, <tt class="function">globals</tt> is not
+ </h3><pre class="programlisting"><span class='pykeyword'>
+def</span> foo(arg):
+ x = 1
+ <span class='pykeyword'>print</span> locals() <a name="dialect.locals.4.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ locals()[<span class='pystring'>"x"</span>] = 2 <a name="dialect.locals.4.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+ <span class='pykeyword'>print</span> <span class='pystring'>"x="</span>,x <a name="dialect.locals.4.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+
+z = 7
+<span class='pykeyword'>print</span> <span class='pystring'>"z="</span>,z
+foo(3)
+globals()[<span class='pystring'>"z"</span>] = 8 <a name="dialect.locals.4.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"><span class='pykeyword'>
+print</span> <span class='pystring'>"z="</span>,z <a name="dialect.locals.4.5"></a><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12">
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.locals.4.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Since <tt class="function">foo</tt> is called with <tt class="literal">3</tt>, this will print <tt class="literal">{'arg': 3, 'x': 1}</tt>. This should not be a surprise.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.locals.4.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">locals</tt> is a function that returns a dictionary, and here you are setting a value in that dictionary. You might think that this
+ would change the value of the local variable <tt class="varname">x</tt> to <tt class="literal">2</tt>, but it doesn't. <tt class="function">locals</tt> does not actually return the local namespace, it returns a copy. So changing it does nothing to the value of the variables
+ in the local namespace.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.locals.4.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This prints <tt class="literal">x= 1</tt>, not <tt class="literal">x= 2</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.locals.4.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">After being burned by <tt class="function">locals</tt>, you might think that this <span class="emphasis"><em>wouldn't</em></span> change the value of <tt class="varname">z</tt>, but it does. Due to internal differences in how <span class="application">Python</span> is implemented (which I'd rather not go into, since I don't fully understand them myself), <tt class="function">globals</tt> returns the actual global namespace, not a copy: the exact opposite behavior of <tt class="function">locals</tt>. So any changes to the dictionary returned by <tt class="function">globals</tt> directly affect your global variables.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.locals.4.5"><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This prints <tt class="literal">z= 8</tt>, not <tt class="literal">z= 7</tt>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="footnotes">
+ <h3 class="footnotetitle">Footnotes</h3>
+ <div class="footnote">
+ <p><sup>[<a name="ftn.d0e21226" href="#d0e21226">3</a>] </sup>I don't get out much.
+ </p>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="basehtmlprocessor.html">&lt;&lt;&nbsp;Introducing BaseHTMLProcessor.py</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#dialect.divein" title="8.1.&nbsp;Diving in">1</a> <span class="divider">|</span> <a href="introducing_sgmllib.html" title="8.2.&nbsp;Introducing sgmllib.py">2</a> <span class="divider">|</span> <a href="extracting_data.html" title="8.3.&nbsp;Extracting data from HTML documents">3</a> <span class="divider">|</span> <a href="basehtmlprocessor.html" title="8.4.&nbsp;Introducing BaseHTMLProcessor.py">4</a> <span class="divider">|</span> <span class="thispage">5</span> <span class="divider">|</span> <a href="dictionary_based_string_formatting.html" title="8.6.&nbsp;Dictionary-based string formatting">6</a> <span class="divider">|</span> <a href="quoting_attribute_values.html" title="8.7.&nbsp;Quoting attribute values">7</a> <span class="divider">|</span> <a href="dialect.html" title="8.8.&nbsp;Introducing dialect.py">8</a> <span class="divider">|</span> <a href="all_together.html" title="8.9.&nbsp;Putting it all together">9</a> <span class="divider">|</span> <a href="summary.html" title="8.10.&nbsp;Summary">10</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="dictionary_based_string_formatting.html">Dictionary-based string formatting&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/html_processing/quoting_attribute_values.html b/help/diveintopython-5.4/html/html_processing/quoting_attribute_values.html
new file mode 100644
index 0000000..7b25cdd
--- /dev/null
+++ b/help/diveintopython-5.4/html/html_processing/quoting_attribute_values.html
@@ -0,0 +1,130 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>8.7.&nbsp;Quoting attribute values</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;8.&nbsp;HTML Processing">
+ <link rel="previous" href="dictionary_based_string_formatting.html" title="8.6.&nbsp;Dictionary-based string formatting">
+ <link rel="next" href="dialect.html" title="8.8.&nbsp;Introducing dialect.py">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">HTML Processing</a>&nbsp;&gt;&nbsp;<span class="thispage">Quoting attribute values</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="dictionary_based_string_formatting.html" title="Prev: &#8220;Dictionary-based string formatting&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="dialect.html" title="Next: &#8220;Introducing dialect.py&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="dialect.quoting"></a>8.7.&nbsp;Quoting attribute values
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>A common question on <a href="http://groups.google.com/groups?group=comp.lang.python">comp.lang.python</a> is &#8220;<span class="quote">I have a bunch of <span class="acronym">HTML</span> documents with unquoted attribute values, and I want to properly quote them all. How can I do this?</span>&#8221;<sup>[<a name="d0e21764" href="#ftn.d0e21764">4</a>]</sup> (This is generally precipitated by a project manager who has found the <span class="acronym">HTML</span>-is-a-standard religion joining a large project and proclaiming that all pages must validate against an <span class="acronym">HTML</span> validator. Unquoted attribute values are a common violation of the <span class="acronym">HTML</span> standard.) Whatever the reason, unquoted attribute values are easy to fix by feeding <span class="acronym">HTML</span> through <tt class="classname">BaseHTMLProcessor</tt>.
+ </p>
+ </div>
+ <p><tt class="classname">BaseHTMLProcessor</tt> consumes <span class="acronym">HTML</span> (since it's descended from <tt class="classname">SGMLParser</tt>) and produces equivalent <span class="acronym">HTML</span>, but the <span class="acronym">HTML</span> output is not identical to the input. Tags and attribute names will end up in lowercase, even if they started in uppercase
+ or mixed case, and attribute values will be enclosed in double quotes, even if they started in single quotes or with no quotes
+ at all. It is this last side effect that you can take advantage of.
+ </p>
+ <div class="example"><a name="dialect.quoting.example"></a><h3 class="title">Example&nbsp;8.16.&nbsp;Quoting attribute values</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">htmlSource = <span class='pystring'>""</span>"</span> <a name="dialect.basehtml.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">... </tt>&lt;html&gt;
+<tt class="prompt">... </tt>&lt;head&gt;
+<tt class="prompt">... </tt>&lt;title&gt;Test page&lt;/title&gt;
+<tt class="prompt">... </tt>&lt;/head&gt;
+<tt class="prompt">... </tt>&lt;body&gt;
+<tt class="prompt">... </tt>&lt;ul&gt;
+<tt class="prompt">... </tt>&lt;li&gt;&lt;a href=index.html&gt;Home&lt;/a&gt;&lt;/li&gt;
+<tt class="prompt">... </tt>&lt;li&gt;&lt;a href=toc.html&gt;Table of contents&lt;/a&gt;&lt;/li&gt;
+<tt class="prompt">... </tt>&lt;li&gt;&lt;a href=history.html&gt;Revision history&lt;/a&gt;&lt;/li&gt;
+<tt class="prompt">... </tt>&lt;/body&gt;
+<tt class="prompt">... </tt>&lt;/html&gt;
+<tt class="prompt">... </tt><span class="userinput"><span class='pystring'>""</span>"</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>from</span> BaseHTMLProcessor <span class='pykeyword'>import</span> BaseHTMLProcessor</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">parser = BaseHTMLProcessor()</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">parser.feed(htmlSource)</span> <a name="dialect.basehtml.3.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> parser.output()</span> <a name="dialect.basehtml.3.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">&lt;html&gt;
+&lt;head&gt;
+&lt;title&gt;Test page&lt;/title&gt;
+&lt;/head&gt;
+&lt;body&gt;
+&lt;ul&gt;
+&lt;li&gt;&lt;a href="index.html"&gt;Home&lt;/a&gt;&lt;/li&gt;
+&lt;li&gt;&lt;a href="toc.html"&gt;Table of contents&lt;/a&gt;&lt;/li&gt;
+&lt;li&gt;&lt;a href="history.html"&gt;Revision history&lt;/a&gt;&lt;/li&gt;
+&lt;/body&gt;
+&lt;/html&gt;</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.basehtml.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Note that the attribute values of the <tt class="literal">href</tt> attributes in the <tt class="sgmltag-element">&lt;a&gt;</tt> tags are not properly quoted. (Also note that you're using <a href="../getting_to_know_python/documenting_functions.html#odbchelper.triplequotes" title="Example&nbsp;2.2.&nbsp;Defining the buildConnectionString Function's doc string">triple quotes</a> for something other than a <tt class="literal">doc string</tt>. And directly in the <span class="acronym">IDE</span>, no less. They're very useful.)
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.basehtml.3.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Feed the parser.</td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#dialect.basehtml.3.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Using the <tt class="function">output</tt> function defined in <tt class="classname">BaseHTMLProcessor</tt>, you get the output as a single string, complete with quoted attribute values. While this may seem anti-climactic, think
+ about how much has actually happened here: <tt class="classname">SGMLParser</tt> parsed the entire <span class="acronym">HTML</span> document, breaking it down into tags, refs, data, and so forth; <tt class="classname">BaseHTMLProcessor</tt> used those elements to reconstruct pieces of <span class="acronym">HTML</span> (which are still stored in <tt class="varname">parser.pieces</tt>, if you want to see them); finally, you called <tt class="function">parser.output</tt>, which joined all the pieces of <span class="acronym">HTML</span> into one string.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="footnotes">
+ <h3 class="footnotetitle">Footnotes</h3>
+ <div class="footnote">
+ <p><sup>[<a name="ftn.d0e21764" href="#d0e21764">4</a>] </sup>All right, it's not that common a question. It's not up there with &#8220;<span class="quote">What editor should I use to write <span class="application">Python</span> code?</span>&#8221; (answer: <span class="application">Emacs</span>) or &#8220;<span class="quote">Is <span class="application">Python</span> better or worse than <span class="application">Perl</span>?</span>&#8221; (answer: &#8220;<span class="quote"><span class="application">Perl</span> is worse than <span class="application">Python</span> because people wanted it worse.</span>&#8221; -Larry Wall, 10/14/1998) But questions about <span class="acronym">HTML</span> processing pop up in one form or another about once a month, and among those questions, this is a popular one.
+ </p>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="dictionary_based_string_formatting.html">&lt;&lt;&nbsp;Dictionary-based string formatting</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#dialect.divein" title="8.1.&nbsp;Diving in">1</a> <span class="divider">|</span> <a href="introducing_sgmllib.html" title="8.2.&nbsp;Introducing sgmllib.py">2</a> <span class="divider">|</span> <a href="extracting_data.html" title="8.3.&nbsp;Extracting data from HTML documents">3</a> <span class="divider">|</span> <a href="basehtmlprocessor.html" title="8.4.&nbsp;Introducing BaseHTMLProcessor.py">4</a> <span class="divider">|</span> <a href="locals_and_globals.html" title="8.5.&nbsp;locals and globals">5</a> <span class="divider">|</span> <a href="dictionary_based_string_formatting.html" title="8.6.&nbsp;Dictionary-based string formatting">6</a> <span class="divider">|</span> <span class="thispage">7</span> <span class="divider">|</span> <a href="dialect.html" title="8.8.&nbsp;Introducing dialect.py">8</a> <span class="divider">|</span> <a href="all_together.html" title="8.9.&nbsp;Putting it all together">9</a> <span class="divider">|</span> <a href="summary.html" title="8.10.&nbsp;Summary">10</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="dialect.html">Introducing dialect.py&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/html_processing/summary.html b/help/diveintopython-5.4/html/html_processing/summary.html
new file mode 100644
index 0000000..e8f43d5
--- /dev/null
+++ b/help/diveintopython-5.4/html/html_processing/summary.html
@@ -0,0 +1,86 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>8.10.&nbsp;Summary</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;8.&nbsp;HTML Processing">
+ <link rel="previous" href="all_together.html" title="8.9.&nbsp;Putting it all together">
+ <link rel="next" href="../xml_processing/index.html" title="Chapter&nbsp;9.&nbsp;XML Processing">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">HTML Processing</a>&nbsp;&gt;&nbsp;<span class="thispage">Summary</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="all_together.html" title="Prev: &#8220;Putting it all together&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="../xml_processing/index.html" title="Next: &#8220;XML Processing&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="dialect.summary"></a>8.10.&nbsp;Summary
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p><span class="application">Python</span> provides you with a powerful tool, <tt class="filename">sgmllib.py</tt>, to manipulate <span class="acronym">HTML</span> by turning its structure into an object model. You can use this tool in many different ways.
+ </p>
+ </div>
+ <div class="itemizedlist">
+ <ul>
+ <li>parsing the <span class="acronym">HTML</span> looking for something specific
+ </li>
+ <li>aggregating the results, like the <a href="extracting_data.html#dialect.extract.links" title="Example&nbsp;8.6.&nbsp;Introducing urllister.py"><span class="acronym">URL</span> lister</a></li>
+ <li>altering the structure along the way, like the <a href="quoting_attribute_values.html#dialect.quoting.example" title="Example&nbsp;8.16.&nbsp;Quoting attribute values">attribute quoter</a></li>
+ <li>transforming the <span class="acronym">HTML</span> into something else by manipulating the text while leaving the tags alone, like the <a href="dialect.html" title="8.8.&nbsp;Introducing dialect.py"><tt class="classname">Dialectizer</tt></a></li>
+ </ul>
+ </div>
+ <p>Along with these examples, you should be comfortable doing all of the following things:</p>
+ <div class="itemizedlist">
+ <ul>
+ <li>Using <a href="locals_and_globals.html" title="8.5.&nbsp;locals and globals"><tt class="function">locals</tt>() and <tt class="function">globals</tt>()</a> to access namespaces
+ </li>
+ <li><a href="dictionary_based_string_formatting.html" title="8.6.&nbsp;Dictionary-based string formatting">Formatting strings</a> using dictionary-based substitutions
+ </li>
+ </ul>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="all_together.html">&lt;&lt;&nbsp;Putting it all together</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#dialect.divein" title="8.1.&nbsp;Diving in">1</a> <span class="divider">|</span> <a href="introducing_sgmllib.html" title="8.2.&nbsp;Introducing sgmllib.py">2</a> <span class="divider">|</span> <a href="extracting_data.html" title="8.3.&nbsp;Extracting data from HTML documents">3</a> <span class="divider">|</span> <a href="basehtmlprocessor.html" title="8.4.&nbsp;Introducing BaseHTMLProcessor.py">4</a> <span class="divider">|</span> <a href="locals_and_globals.html" title="8.5.&nbsp;locals and globals">5</a> <span class="divider">|</span> <a href="dictionary_based_string_formatting.html" title="8.6.&nbsp;Dictionary-based string formatting">6</a> <span class="divider">|</span> <a href="quoting_attribute_values.html" title="8.7.&nbsp;Quoting attribute values">7</a> <span class="divider">|</span> <a href="dialect.html" title="8.8.&nbsp;Introducing dialect.py">8</a> <span class="divider">|</span> <a href="all_together.html" title="8.9.&nbsp;Putting it all together">9</a> <span class="divider">|</span> <span class="thispage">10</span>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="../xml_processing/index.html">XML Processing&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/http_web_services/alltogether.html b/help/diveintopython-5.4/html/http_web_services/alltogether.html
new file mode 100644
index 0000000..8694a04
--- /dev/null
+++ b/help/diveintopython-5.4/html/http_web_services/alltogether.html
@@ -0,0 +1,258 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>11.9.&nbsp;Putting it all together</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;11.&nbsp;HTTP Web Services">
+ <link rel="previous" href="gzip_compression.html" title="11.8.&nbsp;Handling compressed data">
+ <link rel="next" href="summary.html" title="11.10.&nbsp;Summary">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">HTTP Web Services</a>&nbsp;&gt;&nbsp;<span class="thispage">Putting it all together</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="gzip_compression.html" title="Prev: &#8220;Handling compressed data&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="summary.html" title="Next: &#8220;Summary&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="oa.alltogether"></a>11.9.&nbsp;Putting it all together
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>You've seen all the pieces for building an intelligent HTTP web services client. Now let's see how they all fit together.</p>
+ </div>
+ <div class="example"><a name="d0e29475"></a><h3 class="title">Example&nbsp;11.17.&nbsp;The <tt class="function">openanything</tt> function
+ </h3>
+ <p>This function is defined in <tt class="filename">openanything.py</tt>.
+ </p><pre class="programlisting"><span class='pykeyword'>
+def</span> openAnything(source, etag=None, lastmodified=None, agent=USER_AGENT):
+ <span class='pycomment'># non-HTTP code omitted for brevity</span>
+ <span class='pykeyword'>if</span> urlparse.urlparse(source)[0] == <span class='pystring'>'http'</span>: <a name="oa.alltogether.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ <span class='pycomment'># open URL with urllib2 </span>
+ request = urllib2.Request(source)
+ request.add_header(<span class='pystring'>'User-Agent'</span>, agent) <a name="oa.alltogether.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+ <span class='pykeyword'>if</span> etag:
+ request.add_header(<span class='pystring'>'If-None-Match'</span>, etag) <a name="oa.alltogether.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+ <span class='pykeyword'>if</span> lastmodified:
+ request.add_header(<span class='pystring'>'If-Modified-Since'</span>, lastmodified) <a name="oa.alltogether.1.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+ request.add_header(<span class='pystring'>'Accept-encoding'</span>, <span class='pystring'>'gzip'</span>) <a name="oa.alltogether.1.5"></a><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12">
+ opener = urllib2.build_opener(SmartRedirectHandler(), DefaultErrorHandler()) <a name="oa.alltogether.1.6"></a><img src="../images/callouts/6.png" alt="6" border="0" width="12" height="12">
+ <span class='pykeyword'>return</span> opener.open(request) <a name="oa.alltogether.1.7"></a><img src="../images/callouts/7.png" alt="7" border="0" width="12" height="12">
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.alltogether.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="filename">urlparse</tt> is a handy utility module for, you guessed it, parsing URLs. It's primary function, also called <tt class="function">urlparse</tt>, takes a URL and splits it into a tuple of (scheme, domain, path, params, query string parameters, and fragment identifier).
+ Of these, the only thing you care about is the scheme, to make sure that you're dealing with an HTTP URL (which <tt class="filename">urllib2</tt> can handle).
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.alltogether.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You identify yourself to the HTTP server with the <tt class="literal">User-Agent</tt> passed in by the calling function. If no <tt class="literal">User-Agent</tt> was specified, you use a default one defined earlier in the <tt class="filename">openanything.py</tt> module. You never use the default one defined by <tt class="filename">urllib2</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.alltogether.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">If an <tt class="literal">ETag</tt> hash was given, send it in the <tt class="literal">If-None-Match</tt> header.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.alltogether.1.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">If a last-modified date was given, send it in the <tt class="literal">If-Modified-Since</tt> header.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.alltogether.1.5"><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Tell the server you would like compressed data if possible.</td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.alltogether.1.6"><img src="../images/callouts/6.png" alt="6" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Build a URL opener that uses <span class="emphasis"><em>both</em></span> of the custom URL handlers: <tt class="classname">SmartRedirectHandler</tt> for handling <tt class="literal">301</tt> and <tt class="literal">302</tt> redirects, and <tt class="classname">DefaultErrorHandler</tt> for handling <tt class="literal">304</tt>, <tt class="literal">404</tt>, and other error conditions gracefully.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.alltogether.1.7"><img src="../images/callouts/7.png" alt="7" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">That's it! Open the URL and return a file-like object to the caller.</td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="d0e29574"></a><h3 class="title">Example&nbsp;11.18.&nbsp;The <tt class="function">fetch</tt> function
+ </h3>
+ <p>This function is defined in <tt class="filename">openanything.py</tt>.
+ </p><pre class="programlisting"><span class='pykeyword'>
+def</span> fetch(source, etag=None, last_modified=None, agent=USER_AGENT):
+ <span class='pystring'>'''Fetch data and metadata from a URL, file, stream, or string'''</span>
+ result = {}
+ f = openAnything(source, etag, last_modified, agent) <a name="oa.alltogether.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ result[<span class='pystring'>'data'</span>] = f.read() <a name="oa.alltogether.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+ <span class='pykeyword'>if</span> hasattr(f, <span class='pystring'>'headers'</span>):
+ <span class='pycomment'># save ETag, if the server sent one </span>
+ result[<span class='pystring'>'etag'</span>] = f.headers.get(<span class='pystring'>'ETag'</span>) <a name="oa.alltogether.2.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+ <span class='pycomment'># save Last-Modified header, if the server sent one </span>
+ result[<span class='pystring'>'lastmodified'</span>] = f.headers.get(<span class='pystring'>'Last-Modified'</span>) <a name="oa.alltogether.2.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+ <span class='pykeyword'>if</span> f.headers.get(<span class='pystring'>'content-encoding'</span>, <span class='pystring'>''</span>) == <span class='pystring'>'gzip'</span>: <a name="oa.alltogether.2.5"></a><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12">
+ <span class='pycomment'># data came back gzip-compressed, decompress it </span>
+ result[<span class='pystring'>'data'</span>] = gzip.GzipFile(fileobj=StringIO(result[<span class='pystring'>'data'</span>]])).read()
+ <span class='pykeyword'>if</span> hasattr(f, <span class='pystring'>'url'</span>): <a name="oa.alltogether.2.6"></a><img src="../images/callouts/6.png" alt="6" border="0" width="12" height="12">
+ result[<span class='pystring'>'url'</span>] = f.url
+ result[<span class='pystring'>'status'</span>] = 200
+ <span class='pykeyword'>if</span> hasattr(f, <span class='pystring'>'status'</span>): <a name="oa.alltogether.2.7"></a><img src="../images/callouts/7.png" alt="7" border="0" width="12" height="12">
+ result[<span class='pystring'>'status'</span>] = f.status
+ f.close()
+ <span class='pykeyword'>return</span> result
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.alltogether.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">First, you call the <tt class="function">openAnything</tt> function with a URL, <tt class="literal">ETag</tt> hash, <tt class="literal">Last-Modified</tt> date, and <tt class="literal">User-Agent</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.alltogether.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Read the actual data returned from the server. This may be compressed; if so, you'll decompress it later.</td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.alltogether.2.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Save the <tt class="literal">ETag</tt> hash returned from the server, so the calling application can pass it back to you next time, and you can pass it on to <tt class="function">openAnything</tt>, which can stick it in the <tt class="literal">If-None-Match</tt> header and send it to the remote server.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.alltogether.2.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Save the <tt class="literal">Last-Modified</tt> date too.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.alltogether.2.5"><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">If the server says that it sent compressed data, decompress it.</td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.alltogether.2.6"><img src="../images/callouts/6.png" alt="6" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">If you got a URL back from the server, save it, and assume that the status code is <tt class="literal">200</tt> until you find out otherwise.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.alltogether.2.7"><img src="../images/callouts/7.png" alt="7" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">If one of the custom URL handlers captured a status code, then save that too.</td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="d0e29650"></a><h3 class="title">Example&nbsp;11.19.&nbsp;Using <tt class="filename">openanything.py</tt></h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> openanything</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">useragent = <span class='pystring'>'MyHTTPWebServicesApp/1.0'</span></span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">url = <span class='pystring'>'http://diveintopython.org/redir/example301.xml'</span></span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">params = openanything.fetch(url, agent=useragent)</span> <a name="oa.alltogether.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">params</span> <a name="oa.alltogether.3.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">{'url': 'http://diveintomark.org/xml/atom.xml',
+'lastmodified': 'Thu, 15 Apr 2004 19:45:21 GMT',
+'etag': '"e842a-3e53-55d97640"',
+'status': 301,
+'data': '&lt;?xml version="1.0" encoding="iso-8859-1"?&gt;
+&lt;feed version="0.3"
+&lt;-- rest of data omitted for brevity --&gt;'}</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>if</span> params[<span class='pystring'>'status'</span>] == 301:</span> <a name="oa.alltogether.3.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<tt class="prompt">... </tt><span class="userinput">url = params[<span class='pystring'>'url'</span>]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">newparams = openanything.fetch(</span>
+<tt class="prompt">... </tt><span class="userinput">url, params[<span class='pystring'>'etag'</span>], params[<span class='pystring'>'lastmodified'</span>], useragent)</span> <a name="oa.alltogether.3.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">newparams</span>
+<span class="computeroutput">{'url': 'http://diveintomark.org/xml/atom.xml',
+'lastmodified': None,
+'etag': '"e842a-3e53-55d97640"',
+'status': 304,
+'data': ''}</span> <a name="oa.alltogether.3.5"></a><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12">
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.alltogether.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The very first time you fetch a resource, you don't have an <tt class="literal">ETag</tt> hash or <tt class="literal">Last-Modified</tt> date, so you'll leave those out. (They're <a href="../power_of_introspection/optional_arguments.html" title="4.2.&nbsp;Using Optional and Named Arguments">optional parameters</a>.)
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.alltogether.3.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">What you get back is a dictionary of several useful headers, the HTTP status code, and the actual data returned from the server.
+ <tt class="filename">openanything</tt> handles the gzip compression internally; you don't care about that at this level.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.alltogether.3.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">If you ever get a <tt class="literal">301</tt> status code, that's a permanent redirect, and you need to update your URL to the new address.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.alltogether.3.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The second time you fetch the same resource, you have all sorts of information to pass back: a (possibly updated) URL, the
+ <tt class="literal">ETag</tt> from the last time, the <tt class="literal">Last-Modified</tt> date from the last time, and of course your <tt class="literal">User-Agent</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.alltogether.3.5"><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">What you get back is again a dictionary, but the data hasn't changed, so all you got was a <tt class="literal">304</tt> status code and no data.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="gzip_compression.html">&lt;&lt;&nbsp;Handling compressed data</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#oa.divein" title="11.1.&nbsp;Diving in">1</a> <span class="divider">|</span> <a href="review.html" title="11.2.&nbsp;How not to fetch data over HTTP">2</a> <span class="divider">|</span> <a href="http_features.html" title="11.3.&nbsp;Features of HTTP">3</a> <span class="divider">|</span> <a href="debugging.html" title="11.4.&nbsp;Debugging HTTP web services">4</a> <span class="divider">|</span> <a href="user_agent.html" title="11.5.&nbsp;Setting the User-Agent">5</a> <span class="divider">|</span> <a href="etags.html" title="11.6.&nbsp;Handling Last-Modified and ETag">6</a> <span class="divider">|</span> <a href="redirects.html" title="11.7.&nbsp;Handling redirects">7</a> <span class="divider">|</span> <a href="gzip_compression.html" title="11.8.&nbsp;Handling compressed data">8</a> <span class="divider">|</span> <span class="thispage">9</span> <span class="divider">|</span> <a href="summary.html" title="11.10.&nbsp;Summary">10</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="summary.html">Summary&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/http_web_services/debugging.html b/help/diveintopython-5.4/html/http_web_services/debugging.html
new file mode 100644
index 0000000..d58a5ab
--- /dev/null
+++ b/help/diveintopython-5.4/html/http_web_services/debugging.html
@@ -0,0 +1,150 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>11.4.&nbsp;Debugging HTTP web services</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;11.&nbsp;HTTP Web Services">
+ <link rel="previous" href="http_features.html" title="11.3.&nbsp;Features of HTTP">
+ <link rel="next" href="user_agent.html" title="11.5.&nbsp;Setting the User-Agent">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">HTTP Web Services</a>&nbsp;&gt;&nbsp;<span class="thispage">Debugging HTTP web services</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="http_features.html" title="Prev: &#8220;Features of HTTP&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="user_agent.html" title="Next: &#8220;Setting the User-Agent&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="oa.debug"></a>11.4.&nbsp;Debugging HTTP web services
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>First, let's turn on the debugging features of <span class="application">Python</span>'s HTTP library and see what's being sent over the wire. This will be useful throughout the chapter, as you add more and
+ more features.
+ </p>
+ </div>
+ <div class="example"><a name="d0e27789"></a><h3 class="title">Example&nbsp;11.3.&nbsp;Debugging HTTP</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> httplib</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">httplib.HTTPConnection.debuglevel = 1</span> <a name="oa.debug.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> urllib</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">feeddata = urllib.urlopen(<span class='pystring'>'http://diveintomark.org/xml/atom.xml'</span>).read()</span>
+<span class="computeroutput">connect: (diveintomark.org, 80)</span> <a name="oa.debug.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">send: '</span>
+<span class="computeroutput">GET /xml/atom.xml HTTP/1.0</span> <a name="oa.debug.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">Host: diveintomark.org</span> <a name="oa.debug.1.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">User-agent: Python-urllib/1.15</span> <a name="oa.debug.1.5"></a><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12">
+<span class="computeroutput">'</span>
+<span class="computeroutput">reply: 'HTTP/1.1 200 OK\r\n'</span> <a name="oa.debug.1.6"></a><img src="../images/callouts/6.png" alt="6" border="0" width="12" height="12">
+<span class="computeroutput">header: Date: Wed, 14 Apr 2004 22:27:30 GMT</span>
+<span class="computeroutput">header: Server: Apache/2.0.49 (Debian GNU/Linux)</span>
+<span class="computeroutput">header: Content-Type: application/atom+xml</span>
+<span class="computeroutput">header: Last-Modified: Wed, 14 Apr 2004 22:14:38 GMT</span> <a name="oa.debug.1.7"></a><img src="../images/callouts/7.png" alt="7" border="0" width="12" height="12">
+<span class="computeroutput">header: ETag: "e8284-68e0-4de30f80"</span> <a name="oa.debug.1.8"></a><img src="../images/callouts/8.png" alt="8" border="0" width="12" height="12">
+<span class="computeroutput">header: Accept-Ranges: bytes</span>
+<span class="computeroutput">header: Content-Length: 26848</span>
+<span class="computeroutput">header: Connection: close</span>
+</pre></div>
+ <div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.debug.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="filename">urllib</tt> relies on another standard <span class="application">Python</span> library, <tt class="filename">httplib</tt>. Normally you don't need to <tt class="literal">import httplib</tt> directly (<tt class="filename">urllib</tt> does that automatically), but you will here so you can set the debugging flag on the <tt class="classname">HTTPConnection</tt> class that <tt class="filename">urllib</tt> uses internally to connect to the HTTP server. This is an incredibly useful technique. Some other <span class="application">Python</span> libraries have similar debug flags, but there's no particular standard for naming them or turning them on; you need to read
+ the documentation of each library to see if such a feature is available.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.debug.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Now that the debugging flag is set, information on the the HTTP request and response is printed out in real time. The first
+ thing it tells you is that you're connecting to the server <tt class="literal">diveintomark.org</tt> on port 80, which is the standard port for HTTP.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.debug.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">When you request the Atom feed, <tt class="filename">urllib</tt> sends three lines to the server. The first line specifies the HTTP verb you're using, and the path of the resource (minus
+ the domain name). All the requests in this chapter will use <tt class="literal">GET</tt>, but in the next chapter on <span class="acronym">SOAP</span>, you'll see that it uses <tt class="literal">POST</tt> for everything. The basic syntax is the same, regardless of the verb.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.debug.1.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The second line is the <tt class="literal">Host</tt> header, which specifies the domain name of the service you're accessing. This is important, because a single HTTP server
+ can host multiple separate domains. My server currently hosts 12 domains; other servers can host hundreds or even thousands.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.debug.1.5"><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The third line is the <tt class="literal">User-Agent</tt> header. What you see here is the generic <tt class="literal">User-Agent</tt> that the <tt class="filename">urllib</tt> library adds by default. In the next section, you'll see how to customize this to be more specific.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.debug.1.6"><img src="../images/callouts/6.png" alt="6" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The server replies with a status code and a bunch of headers (and possibly some data, which got stored in the <tt class="varname">feeddata</tt> variable). The status code here is <tt class="literal">200</tt>, meaning &#8220;<span class="quote">everything's normal, here's the data you requested</span>&#8221;. The server also tells you the date it responded to your request, some information about the server itself, and the content
+ type of the data it's giving you. Depending on your application, this might be useful, or not. It's certainly reassuring
+ that you thought you were asking for an Atom feed, and lo and behold, you're getting an Atom feed (<tt class="literal">application/atom+xml</tt>, which is the registered content type for Atom feeds).
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.debug.1.7"><img src="../images/callouts/7.png" alt="7" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The server tells you when this Atom feed was last modified (in this case, about 13 minutes ago). You can send this date back
+ to the server the next time you request the same feed, and the server can do last-modified checking.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.debug.1.8"><img src="../images/callouts/8.png" alt="8" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The server also tells you that this Atom feed has an ETag hash of <tt class="literal">"e8284-68e0-4de30f80"</tt>. The hash doesn't mean anything by itself; there's nothing you can do with it, except send it back to the server the next
+ time you request this same feed. Then the server can use it to tell you if the data has changed or not.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="http_features.html">&lt;&lt;&nbsp;Features of HTTP</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#oa.divein" title="11.1.&nbsp;Diving in">1</a> <span class="divider">|</span> <a href="review.html" title="11.2.&nbsp;How not to fetch data over HTTP">2</a> <span class="divider">|</span> <a href="http_features.html" title="11.3.&nbsp;Features of HTTP">3</a> <span class="divider">|</span> <span class="thispage">4</span> <span class="divider">|</span> <a href="user_agent.html" title="11.5.&nbsp;Setting the User-Agent">5</a> <span class="divider">|</span> <a href="etags.html" title="11.6.&nbsp;Handling Last-Modified and ETag">6</a> <span class="divider">|</span> <a href="redirects.html" title="11.7.&nbsp;Handling redirects">7</a> <span class="divider">|</span> <a href="gzip_compression.html" title="11.8.&nbsp;Handling compressed data">8</a> <span class="divider">|</span> <a href="alltogether.html" title="11.9.&nbsp;Putting it all together">9</a> <span class="divider">|</span> <a href="summary.html" title="11.10.&nbsp;Summary">10</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="user_agent.html">Setting the User-Agent&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/http_web_services/etags.html b/help/diveintopython-5.4/html/http_web_services/etags.html
new file mode 100644
index 0000000..109e560
--- /dev/null
+++ b/help/diveintopython-5.4/html/http_web_services/etags.html
@@ -0,0 +1,279 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>11.6.&nbsp;Handling Last-Modified and ETag</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;11.&nbsp;HTTP Web Services">
+ <link rel="previous" href="user_agent.html" title="11.5.&nbsp;Setting the User-Agent">
+ <link rel="next" href="redirects.html" title="11.7.&nbsp;Handling redirects">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">HTTP Web Services</a>&nbsp;&gt;&nbsp;<span class="thispage">Handling Last-Modified and ETag</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="user_agent.html" title="Prev: &#8220;Setting the User-Agent&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="redirects.html" title="Next: &#8220;Handling redirects&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="oa.etags"></a>11.6.&nbsp;Handling <tt class="literal">Last-Modified</tt> and <tt class="literal">ETag</tt></h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>Now that you know how to add custom HTTP headers to your web service requests, let's look at adding support for <tt class="literal">Last-Modified</tt> and <tt class="literal">ETag</tt> headers.
+ </p>
+ </div>
+ <p>These examples show the output with debugging turned off. If you still have it turned on from the previous section, you can
+ turn it off by setting <tt class="literal">httplib.HTTPConnection.debuglevel = 0</tt>. Or you can just leave debugging on, if that helps you.
+ </p>
+ <div class="example"><a name="oa.etags.example.1"></a><h3 class="title">Example&nbsp;11.6.&nbsp;Testing <tt class="literal">Last-Modified</tt></h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> urllib2</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">request = urllib2.Request(<span class='pystring'>'http://diveintomark.org/xml/atom.xml'</span>)</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">opener = urllib2.build_opener()</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">firstdatastream = opener.open(request)</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">firstdatastream.headers.dict</span> <a name="oa.etags.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">{'date': 'Thu, 15 Apr 2004 20:42:41 GMT',
+ 'server': 'Apache/2.0.49 (Debian GNU/Linux)',
+ 'content-type': 'application/atom+xml',
+ 'last-modified': 'Thu, 15 Apr 2004 19:45:21 GMT',
+ 'etag': '"e842a-3e53-55d97640"',
+ 'content-length': '15955',
+ 'accept-ranges': 'bytes',
+ 'connection': 'close'}</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">request.add_header(<span class='pystring'>'If-Modified-Since'</span>,</span>
+<tt class="prompt">... </tt><span class="userinput">firstdatastream.headers.get(<span class='pystring'>'Last-Modified'</span>))</span> <a name="oa.etags.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">seconddatastream = opener.open(request)</span> <a name="oa.etags.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="traceback">Traceback (most recent call last):
+ File "&lt;stdin&gt;", line 1, in ?
+ File "c:\python23\lib\urllib2.py", line 326, in open
+ '_open', req)
+ File "c:\python23\lib\urllib2.py", line 306, in _call_chain
+ result = func(*args)
+ File "c:\python23\lib\urllib2.py", line 901, in http_open
+ return self.do_open(httplib.HTTP, req)
+ File "c:\python23\lib\urllib2.py", line 895, in do_open
+ return self.parent.error('http', req, fp, code, msg, hdrs)
+ File "c:\python23\lib\urllib2.py", line 352, in error
+ return self._call_chain(*args)
+ File "c:\python23\lib\urllib2.py", line 306, in _call_chain
+ result = func(*args)
+ File "c:\python23\lib\urllib2.py", line 412, in http_error_default
+ raise HTTPError(req.get_full_url(), code, msg, hdrs, fp)
+urllib2.HTTPError: HTTP Error 304: Not Modified</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.etags.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Remember all those HTTP headers you saw printed out when you turned on debugging? This is how you can get access to them
+ programmatically: <tt class="varname">firstdatastream.headers</tt> is <a href="../object_oriented_framework/userdict.html" title="5.5.&nbsp;Exploring UserDict: A Wrapper Class">an object that acts like a dictionary</a> and allows you to get any of the individual headers returned from the HTTP server.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.etags.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">On the second request, you add the <tt class="literal">If-Modified-Since</tt> header with the last-modified date from the first request. If the data hasn't changed, the server should return a <tt class="literal">304</tt> status code.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.etags.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Sure enough, the data hasn't changed. You can see from the traceback that <tt class="filename">urllib2</tt> throws a special exception, <tt class="classname">HTTPError</tt>, in response to the <tt class="literal">304</tt> status code. This is a little unusual, and not entirely helpful. After all, it's not an error; you specifically asked the
+ server not to send you any data if it hadn't changed, and the data didn't change, so the server told you it wasn't sending
+ you any data. That's not an error; that's exactly what you were hoping for.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p><tt class="filename">urllib2</tt> also raises an <tt class="classname">HTTPError</tt> exception for conditions that you would think of as errors, such as <tt class="literal">404</tt> (page not found). In fact, it will raise <tt class="classname">HTTPError</tt> for <span class="emphasis"><em>any</em></span> status code other than <tt class="literal">200</tt> (OK), <tt class="literal">301</tt> (permanent redirect), or <tt class="literal">302</tt> (temporary redirect). It would be more helpful for your purposes to capture the status code and simply return it, without
+ throwing an exception. To do that, you'll need to define a custom URL handler.
+ </p>
+ <div class="example"><a name="d0e28385"></a><h3 class="title">Example&nbsp;11.7.&nbsp;Defining URL handlers</h3>
+ <p>This custom URL handler is part of <tt class="filename">openanything.py</tt>.
+ </p><pre class="programlisting"><span class='pykeyword'>
+class</span> DefaultErrorHandler(urllib2.HTTPDefaultErrorHandler): <a name="oa.etags.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ <span class='pykeyword'>def</span><span class='pyclass'> http_error_default</span>(self, req, fp, code, msg, headers): <a name="oa.etags.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+ result = urllib2.HTTPError(
+ req.get_full_url(), code, msg, headers, fp)
+ result.status = code <a name="oa.etags.2.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+ <span class='pykeyword'>return</span> result
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.etags.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="filename">urllib2</tt> is designed around URL handlers. Each handler is just a class that can define any number of methods. When something happens
+ -- like an HTTP error, or even a <tt class="literal">304</tt> code -- <tt class="filename">urllib2</tt> introspects into the list of defined handlers for a method that can handle it. You used a similar introspection in <a href="../xml_processing/index.html" title="Chapter&nbsp;9.&nbsp;XML Processing">Chapter&nbsp;9, <i>XML Processing</i></a> to define handlers for different node types, but <tt class="filename">urllib2</tt> is more flexible, and introspects over as many handlers as are defined for the current request.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.etags.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="filename">urllib2</tt> searches through the defined handlers and calls the <tt class="methodname">http_error_default</tt> method when it encounters a <tt class="literal">304</tt> status code from the server. By defining a custom error handler, you can prevent <tt class="filename">urllib2</tt> from raising an exception. Instead, you create the <tt class="classname">HTTPError</tt> object, but return it instead of raising it.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.etags.2.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This is the key part: before returning, you save the status code returned by the HTTP server. This will allow you easy access
+ to it from the calling program.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="d0e28438"></a><h3 class="title">Example&nbsp;11.8.&nbsp;Using custom URL handlers</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">request.headers</span> <a name="oa.etags.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">{'If-modified-since': 'Thu, 15 Apr 2004 19:45:21 GMT'}</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> openanything</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">opener = urllib2.build_opener(</span>
+<tt class="prompt">... </tt><span class="userinput">openanything.DefaultErrorHandler())</span> <a name="oa.etags.3.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">seconddatastream = opener.open(request)</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">seconddatastream.status</span> <a name="oa.etags.3.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">304</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">seconddatastream.read()</span> <a name="oa.etags.3.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">''</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.etags.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You're continuing the previous example, so the <tt class="classname">Request</tt> object is already set up, and you've already added the <tt class="literal">If-Modified-Since</tt> header.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.etags.3.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This is the key: now that you've defined your custom URL handler, you need to tell <tt class="filename">urllib2</tt> to use it. Remember how I said that <tt class="filename">urllib2</tt> broke up the process of accessing an HTTP resource into three steps, and for good reason? This is why building the URL opener
+ is its own step, because you can build it with your own custom URL handlers that override <tt class="filename">urllib2</tt>'s default behavior.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.etags.3.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Now you can quietly open the resource, and what you get back is an object that, along with the usual headers (use <tt class="varname">seconddatastream.headers.dict</tt> to acess them), also contains the HTTP status code. In this case, as you expected, the status is <tt class="literal">304</tt>, meaning this data hasn't changed since the last time you asked for it.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.etags.3.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Note that when the server sends back a <tt class="literal">304</tt> status code, it doesn't re-send the data. That's the whole point: to save bandwidth by not re-downloading data that hasn't
+ changed. So if you actually want that data, you'll need to cache it locally the first time you get it.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>Handling <tt class="literal">ETag</tt> works much the same way, but instead of checking for <tt class="literal">Last-Modified</tt> and sending <tt class="literal">If-Modified-Since</tt>, you check for <tt class="literal">ETag</tt> and send <tt class="literal">If-None-Match</tt>. Let's start with a fresh <span class="acronym">IDE</span> session.
+ </p>
+ <div class="example"><a name="oa.etags.example"></a><h3 class="title">Example&nbsp;11.9.&nbsp;Supporting <tt class="literal">ETag</tt>/<tt class="literal">If-None-Match</tt></h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> urllib2, openanything</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">request = urllib2.Request(<span class='pystring'>'http://diveintomark.org/xml/atom.xml'</span>)</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">opener = urllib2.build_opener(</span>
+<tt class="prompt">... </tt><span class="userinput">openanything.DefaultErrorHandler())</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">firstdatastream = opener.open(request)</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">firstdatastream.headers.get(<span class='pystring'>'ETag'</span>)</span> <a name="oa.etags.4.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">'"e842a-3e53-55d97640"'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">firstdata = firstdatastream.read()</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> firstdata</span> <a name="oa.etags.4.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">&lt;?xml version="1.0" encoding="iso-8859-1"?&gt;
+&lt;feed version="0.3"
+ xmlns="http://purl.org/atom/ns#"
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xml:lang="en"&gt;
+ &lt;title mode="escaped"&gt;dive into mark&lt;/title&gt;
+ &lt;link rel="alternate" type="text/html" href="http://diveintomark.org/"/&gt;
+ &lt;-- rest of feed omitted for brevity --&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">request.add_header(<span class='pystring'>'If-None-Match'</span>,</span>
+<tt class="prompt">... </tt><span class="userinput">firstdatastream.headers.get(<span class='pystring'>'ETag'</span>))</span> <a name="oa.etags.4.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">seconddatastream = opener.open(request)</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">seconddatastream.status</span> <a name="oa.etags.4.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">304</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">seconddatastream.read()</span> <a name="oa.etags.4.5"></a><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12">
+<span class="computeroutput">''</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.etags.4.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Using the <tt class="varname">firstdatastream.headers</tt> pseudo-dictionary, you can get the <tt class="literal">ETag</tt> returned from the server. (What happens if the server didn't send back an <tt class="literal">ETag</tt>? Then this line would return <tt class="literal">None</tt>.)
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.etags.4.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">OK, you got the data.</td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.etags.4.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Now set up the second call by setting the <tt class="literal">If-None-Match</tt> header to the <tt class="literal">ETag</tt> you got from the first call.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.etags.4.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The second call succeeds quietly (without throwing an exception), and once again you see that the server has sent back a <tt class="literal">304</tt> status code. Based on the <tt class="literal">ETag</tt> you sent the second time, it knows that the data hasn't changed.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.etags.4.5"><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Regardless of whether the <tt class="literal">304</tt> is triggered by <tt class="literal">Last-Modified</tt> date checking or <tt class="literal">ETag</tt> hash matching, you'll never get the data along with the <tt class="literal">304</tt>. That's the whole point.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div><a name="tip.etag.vs.lastmodified"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">In these examples, the HTTP server has supported both <tt class="literal">Last-Modified</tt> and <tt class="literal">ETag</tt> headers, but not all servers do. As a web services client, you should be prepared to support both, but you must code defensively
+ in case a server only supports one or the other, or neither.
+ </td>
+ </tr>
+ </table>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="user_agent.html">&lt;&lt;&nbsp;Setting the User-Agent</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#oa.divein" title="11.1.&nbsp;Diving in">1</a> <span class="divider">|</span> <a href="review.html" title="11.2.&nbsp;How not to fetch data over HTTP">2</a> <span class="divider">|</span> <a href="http_features.html" title="11.3.&nbsp;Features of HTTP">3</a> <span class="divider">|</span> <a href="debugging.html" title="11.4.&nbsp;Debugging HTTP web services">4</a> <span class="divider">|</span> <a href="user_agent.html" title="11.5.&nbsp;Setting the User-Agent">5</a> <span class="divider">|</span> <span class="thispage">6</span> <span class="divider">|</span> <a href="redirects.html" title="11.7.&nbsp;Handling redirects">7</a> <span class="divider">|</span> <a href="gzip_compression.html" title="11.8.&nbsp;Handling compressed data">8</a> <span class="divider">|</span> <a href="alltogether.html" title="11.9.&nbsp;Putting it all together">9</a> <span class="divider">|</span> <a href="summary.html" title="11.10.&nbsp;Summary">10</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="redirects.html">Handling redirects&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/http_web_services/gzip_compression.html b/help/diveintopython-5.4/html/http_web_services/gzip_compression.html
new file mode 100644
index 0000000..4f7b448
--- /dev/null
+++ b/help/diveintopython-5.4/html/http_web_services/gzip_compression.html
@@ -0,0 +1,223 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>11.8.&nbsp;Handling compressed data</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;11.&nbsp;HTTP Web Services">
+ <link rel="previous" href="redirects.html" title="11.7.&nbsp;Handling redirects">
+ <link rel="next" href="alltogether.html" title="11.9.&nbsp;Putting it all together">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">HTTP Web Services</a>&nbsp;&gt;&nbsp;<span class="thispage">Handling compressed data</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="redirects.html" title="Prev: &#8220;Handling redirects&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="alltogether.html" title="Next: &#8220;Putting it all together&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="oa.gzip"></a>11.8.&nbsp;Handling compressed data
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>The last important HTTP feature you want to support is compression. Many web services have the ability to send data compressed,
+ which can cut down the amount of data sent over the wire by 60% or more. This is especially true of XML web services, since
+ XML data compresses very well.
+ </p>
+ </div>
+ <p>Servers won't give you compressed data unless you tell them you can handle it.</p>
+ <div class="example"><a name="d0e29136"></a><h3 class="title">Example&nbsp;11.14.&nbsp;Telling the server you would like compressed data</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> urllib2, httplib</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">httplib.HTTPConnection.debuglevel = 1</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">request = urllib2.Request(<span class='pystring'>'http://diveintomark.org/xml/atom.xml'</span>)</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">request.add_header(<span class='pystring'>'Accept-encoding'</span>, <span class='pystring'>'gzip'</span>)</span> <a name="oa.gzip.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">opener = urllib2.build_opener()</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">f = opener.open(request)</span>
+<span class="computeroutput">connect: (diveintomark.org, 80)
+send: '
+GET /xml/atom.xml HTTP/1.0
+Host: diveintomark.org
+User-agent: Python-urllib/2.1
+Accept-encoding: gzip</span> <a name="oa.gzip.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">'
+reply: 'HTTP/1.1 200 OK\r\n'
+header: Date: Thu, 15 Apr 2004 22:24:39 GMT
+header: Server: Apache/2.0.49 (Debian GNU/Linux)
+header: Last-Modified: Thu, 15 Apr 2004 19:45:21 GMT
+header: ETag: "e842a-3e53-55d97640"
+header: Accept-Ranges: bytes
+header: Vary: Accept-Encoding
+header: Content-Encoding: gzip</span> <a name="oa.gzip.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">header: Content-Length: 6289</span> <a name="oa.gzip.1.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">header: Connection: close
+header: Content-Type: application/atom+xml</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.gzip.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This is the key: once you've created your <tt class="classname">Request</tt> object, add an <tt class="literal">Accept-encoding</tt> header to tell the server you can accept gzip-encoded data. <tt class="literal">gzip</tt> is the name of the compression algorithm you're using. In theory there could be other compression algorithms, but <tt class="literal">gzip</tt> is the compression algorithm used by 99% of web servers.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.gzip.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">There's your header going across the wire.</td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.gzip.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">And here's what the server sends back: the <tt class="literal">Content-Encoding: gzip</tt> header means that the data you're about to receive has been gzip-compressed.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.gzip.1.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="literal">Content-Length</tt> header is the length of the compressed data, not the uncompressed data. As you'll see in a minute, the actual length of
+ the uncompressed data was 15955, so gzip compression cut your bandwidth by over 60%!
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="d0e29222"></a><h3 class="title">Example&nbsp;11.15.&nbsp;Decompressing the data</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">compresseddata = f.read()</span> <a name="oa.gzip.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">len(compresseddata)</span>
+<span class="computeroutput">6289</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> StringIO</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">compressedstream = StringIO.StringIO(compresseddata)</span> <a name="oa.gzip.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> gzip</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">gzipper = gzip.GzipFile(fileobj=compressedstream)</span> <a name="oa.gzip.2.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">data = gzipper.read()</span> <a name="oa.gzip.2.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> data</span> <a name="oa.gzip.2.5"></a><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12">
+<span class="computeroutput">&lt;?xml version="1.0" encoding="iso-8859-1"?&gt;
+&lt;feed version="0.3"
+ xmlns="http://purl.org/atom/ns#"
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xml:lang="en"&gt;
+ &lt;title mode="escaped"&gt;dive into mark&lt;/title&gt;
+ &lt;link rel="alternate" type="text/html" href="http://diveintomark.org/"/&gt;
+ &lt;-- rest of feed omitted for brevity --&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">len(data)</span>
+<span class="computeroutput">15955</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.gzip.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Continuing from the previous example, <tt class="varname">f</tt> is the file-like object returned from the URL opener. Using its <tt class="methodname">read()</tt> method would ordinarily get you the uncompressed data, but since this data has been gzip-compressed, this is just the first
+ step towards getting the data you really want.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.gzip.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">OK, this step is a little bit of messy workaround. <span class="application">Python</span> has a <tt class="filename">gzip</tt> module, which reads (and actually writes) gzip-compressed files on disk. But you don't have a file on disk, you have a gzip-compressed
+ buffer in memory, and you don't want to write out a temporary file just so you can uncompress it. So what you're going to
+ do is create a file-like object out of the in-memory data (<tt class="varname">compresseddata</tt>), using the <tt class="filename">StringIO</tt> module. You first saw the <tt class="filename">StringIO</tt> module in <a href="../scripts_and_streams/index.html#kgp.openanything.stringio.example" title="Example&nbsp;10.4.&nbsp;Introducing StringIO">the previous chapter</a>, but now you've found another use for it.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.gzip.2.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Now you can create an instance of <tt class="classname">GzipFile</tt>, and tell it that its &#8220;<span class="quote">file</span>&#8221; is the file-like object <tt class="varname">compressedstream</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.gzip.2.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This is the line that does all the actual work: &#8220;<span class="quote">reading</span>&#8221; from <tt class="classname">GzipFile</tt> will decompress the data. Strange? Yes, but it makes sense in a twisted kind of way. <tt class="varname">gzipper</tt> is a file-like object which represents a gzip-compressed file. That &#8220;<span class="quote">file</span>&#8221; is not a real file on disk, though; <tt class="varname">gzipper</tt> is really just &#8220;<span class="quote">reading</span>&#8221; from the file-like object you created with <tt class="filename">StringIO</tt> to wrap the compressed data, which is only in memory in the variable <tt class="varname">compresseddata</tt>. And where did that compressed data come from? You originally downloaded it from a remote HTTP server by &#8220;<span class="quote">reading</span>&#8221; from the file-like object you built with <tt class="function">urllib2.build_opener</tt>. And amazingly, this all just works. Every step in the chain has no idea that the previous step is faking it.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.gzip.2.5"><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Look ma, real data. (15955 bytes of it, in fact.)</td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>&#8220;<span class="quote">But wait!</span>&#8221; I hear you cry. &#8220;<span class="quote">This could be even easier!</span>&#8221; I know what you're thinking. You're thinking that <tt class="varname">opener.open</tt> returns a file-like object, so why not cut out the <tt class="filename">StringIO</tt> middleman and just pass <tt class="varname">f</tt> directly to <tt class="methodname">GzipFile</tt>? OK, maybe you weren't thinking that, but don't worry about it, because it doesn't work.
+ </p>
+ <div class="example"><a name="d0e29389"></a><h3 class="title">Example&nbsp;11.16.&nbsp;Decompressing the data directly from the server</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">f = opener.open(request)</span> <a name="oa.gzip.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">f.headers.get(<span class='pystring'>'Content-Encoding'</span>)</span> <a name="oa.gzip.3.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">'gzip'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">data = gzip.GzipFile(fileobj=f).read()</span> <a name="oa.gzip.3.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="traceback">Traceback (most recent call last):
+ File "&lt;stdin&gt;", line 1, in ?
+ File "c:\python23\lib\gzip.py", line 217, in read
+ self._read(readsize)
+ File "c:\python23\lib\gzip.py", line 252, in _read
+ pos = self.fileobj.tell() # Save current position
+AttributeError: addinfourl instance has no attribute 'tell'</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.gzip.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Continuing from the previous example, you already have a <tt class="classname">Request</tt> object set up with an <tt class="literal">Accept-encoding: gzip</tt> header.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.gzip.3.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Simply opening the request will get you the headers (though not download any data yet). As you can see from the returned
+ <tt class="literal">Content-Encoding</tt> header, this data has been sent gzip-compressed.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.gzip.3.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Since <tt class="methodname">opener.open</tt> returns a file-like object, and you know from the headers that when you read it, you're going to get gzip-compressed data,
+ why not simply pass that file-like object directly to <tt class="classname">GzipFile</tt>? As you &#8220;<span class="quote">read</span>&#8221; from the <tt class="classname">GzipFile</tt> instance, it will &#8220;<span class="quote">read</span>&#8221; compressed data from the remote HTTP server and decompress it on the fly. It's a good idea, but unfortunately it doesn't
+ work. Because of the way gzip compression works, <tt class="classname">GzipFile</tt> needs to save its position and move forwards and backwards through the compressed file. This doesn't work when the &#8220;<span class="quote">file</span>&#8221; is a stream of bytes coming from a remote server; all you can do with it is retrieve bytes one at a time, not move back
+ and forth through the data stream. So the inelegant hack of using <tt class="filename">StringIO</tt> is the best solution: download the compressed data, create a file-like object out of it with <tt class="filename">StringIO</tt>, and then decompress the data from that.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="redirects.html">&lt;&lt;&nbsp;Handling redirects</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#oa.divein" title="11.1.&nbsp;Diving in">1</a> <span class="divider">|</span> <a href="review.html" title="11.2.&nbsp;How not to fetch data over HTTP">2</a> <span class="divider">|</span> <a href="http_features.html" title="11.3.&nbsp;Features of HTTP">3</a> <span class="divider">|</span> <a href="debugging.html" title="11.4.&nbsp;Debugging HTTP web services">4</a> <span class="divider">|</span> <a href="user_agent.html" title="11.5.&nbsp;Setting the User-Agent">5</a> <span class="divider">|</span> <a href="etags.html" title="11.6.&nbsp;Handling Last-Modified and ETag">6</a> <span class="divider">|</span> <a href="redirects.html" title="11.7.&nbsp;Handling redirects">7</a> <span class="divider">|</span> <span class="thispage">8</span> <span class="divider">|</span> <a href="alltogether.html" title="11.9.&nbsp;Putting it all together">9</a> <span class="divider">|</span> <a href="summary.html" title="11.10.&nbsp;Summary">10</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="alltogether.html">Putting it all together&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/http_web_services/http_features.html b/help/diveintopython-5.4/html/http_web_services/http_features.html
new file mode 100644
index 0000000..5b98687
--- /dev/null
+++ b/help/diveintopython-5.4/html/http_web_services/http_features.html
@@ -0,0 +1,186 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>11.3.&nbsp;Features of HTTP</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;11.&nbsp;HTTP Web Services">
+ <link rel="previous" href="review.html" title="11.2.&nbsp;How not to fetch data over HTTP">
+ <link rel="next" href="debugging.html" title="11.4.&nbsp;Debugging HTTP web services">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">HTTP Web Services</a>&nbsp;&gt;&nbsp;<span class="thispage">Features of HTTP</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="review.html" title="Prev: &#8220;How not to fetch data over HTTP&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="debugging.html" title="Next: &#8220;Debugging HTTP web services&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="oa.features"></a>11.3.&nbsp;Features of HTTP
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="toc">
+ <ul>
+ <li><span class="section"><a href="http_features.html#d0e27596">11.3.1. User-Agent</a></span></li>
+ <li><span class="section"><a href="http_features.html#d0e27616">11.3.2. Redirects</a></span></li>
+ <li><span class="section"><a href="http_features.html#d0e27689">11.3.3. Last-Modified/If-Modified-Since</a></span></li>
+ <li><span class="section"><a href="http_features.html#d0e27724">11.3.4. ETag/If-None-Match</a></span></li>
+ <li><span class="section"><a href="http_features.html#d0e27752">11.3.5. Compression</a></span></li>
+ </ul>
+ </div>
+ <div class="abstract">
+ <p>There are five important features of HTTP which you should support.</p>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e27596"></a>11.3.1.&nbsp;<tt class="literal">User-Agent</tt></h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p>The <tt class="literal">User-Agent</tt> is simply a way for a client to tell a server who it is when it requests a web page, a syndicated feed, or any sort of web
+ service over HTTP. When the client requests a resource, it should always announce who it is, as specifically as possible.
+ This allows the server-side administrator to get in touch with the client-side developer if anything is going fantastically
+ wrong.
+ </p>
+ <p>By default, <span class="application">Python</span> sends a generic <tt class="literal">User-Agent</tt>: <tt class="literal">Python-urllib/1.15</tt>. In the next section, you'll see how to change this to something more specific.
+ </p>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e27616"></a>11.3.2.&nbsp;Redirects
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p>Sometimes resources move around. Web sites get reorganized, pages move to new addresses. Even web services can reorganize.
+ A syndicated feed at <tt class="literal">http://example.com/index.xml</tt> might be moved to <tt class="literal">http://example.com/xml/atom.xml</tt>. Or an entire domain might move, as an organization expands and reorganizes; for instance, <tt class="literal">http://www.example.com/index.xml</tt> might be redirected to <tt class="literal">http://server-farm-1.example.com/index.xml</tt>.
+ </p>
+ <p>Every time you request any kind of resource from an HTTP server, the server includes a status code in its response. Status
+ code <tt class="literal">200</tt> means &#8220;<span class="quote">everything's normal, here's the page you asked for</span>&#8221;. Status code <tt class="literal">404</tt> means &#8220;<span class="quote">page not found</span>&#8221;. (You've probably seen 404 errors while browsing the web.)
+ </p>
+ <p>HTTP has two different ways of signifying that a resource has moved. Status code <tt class="literal">302</tt> is a <span class="emphasis"><em>temporary redirect</em></span>; it means &#8220;<span class="quote">oops, that got moved over here temporarily</span>&#8221; (and then gives the temporary address in a <tt class="literal">Location:</tt> header). Status code <tt class="literal">301</tt> is a <span class="emphasis"><em>permanent redirect</em></span>; it means &#8220;<span class="quote">oops, that got moved permanently</span>&#8221; (and then gives the new address in a <tt class="literal">Location:</tt> header). If you get a <tt class="literal">302</tt> status code and a new address, the HTTP specification says you should use the new address to get what you asked for, but
+ the next time you want to access the same resource, you should retry the old address. But if you get a <tt class="literal">301</tt> status code and a new address, you're supposed to use the new address from then on.
+ </p>
+ <p><tt class="function">urllib.urlopen</tt> will automatically &#8220;<span class="quote">follow</span>&#8221; redirects when it receives the appropriate status code from the HTTP server, but unfortunately, it doesn't tell you when
+ it does so. You'll end up getting data you asked for, but you'll never know that the underlying library &#8220;<span class="quote">helpfully</span>&#8221; followed a redirect for you. So you'll continue pounding away at the old address, and each time you'll get redirected to
+ the new address. That's two round trips instead of one: not very efficient! Later in this chapter, you'll see how to work
+ around this so you can deal with permanent redirects properly and efficiently.
+ </p>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e27689"></a>11.3.3.&nbsp;<tt class="literal">Last-Modified</tt>/<tt class="literal">If-Modified-Since</tt></h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p>Some data changes all the time. The home page of CNN.com is constantly updating every few minutes. On the other hand, the
+ home page of Google.com only changes once every few weeks (when they put up a special holiday logo, or advertise a new service).
+ Web services are no different; usually the server knows when the data you requested last changed, and HTTP provides a way
+ for the server to include this last-modified date along with the data you requested.
+ </p>
+ <p>If you ask for the same data a second time (or third, or fourth), you can tell the server the last-modified date that you
+ got last time: you send an <tt class="literal">If-Modified-Since</tt> header with your request, with the date you got back from the server last time. If the data hasn't changed since then, the
+ server sends back a special HTTP status code <tt class="literal">304</tt>, which means &#8220;<span class="quote">this data hasn't changed since the last time you asked for it</span>&#8221;. Why is this an improvement? Because when the server sends a <tt class="literal">304</tt>, <span class="emphasis"><em>it doesn't re-send the data</em></span>. All you get is the status code. So you don't need to download the same data over and over again if it hasn't changed;
+ the server assumes you have the data cached locally.
+ </p>
+ <p>All modern web browsers support last-modified date checking. If you've ever visited a page, re-visited the same page a day
+ later and found that it hadn't changed, and wondered why it loaded so quickly the second time -- this could be why. Your
+ web browser cached the contents of the page locally the first time, and when you visited the second time, your browser automatically
+ sent the last-modified date it got from the server the first time. The server simply says <tt class="literal">304: Not Modified</tt>, so your browser knows to load the page from its cache. Web services can be this smart too.
+ </p>
+ <p><span class="application">Python</span>'s URL library has no built-in support for last-modified date checking, but since you can add arbitrary headers to each request
+ and read arbitrary headers in each response, you can add support for it yourself.
+ </p>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e27724"></a>11.3.4.&nbsp;<tt class="literal">ETag</tt>/<tt class="literal">If-None-Match</tt></h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p>ETags are an alternate way to accomplish the same thing as the last-modified date checking: don't re-download data that hasn't
+ changed. The way it works is, the server sends some sort of hash of the data (in an <tt class="literal">ETag</tt> header) along with the data you requested. Exactly how this hash is determined is entirely up to the server. The second
+ time you request the same data, you include the ETag hash in an <tt class="literal">If-None-Match:</tt> header, and if the data hasn't changed, the server will send you back a <tt class="literal">304</tt> status code. As with the last-modified date checking, the server <span class="emphasis"><em>just</em></span> sends the <tt class="literal">304</tt>; it doesn't send you the same data a second time. By including the ETag hash in your second request, you're telling the
+ server that there's no need to re-send the same data if it still matches this hash, since you still have the data from the
+ last time.
+ </p>
+ <p><span class="application">Python</span>'s URL library has no built-in support for ETags, but you'll see how to add it later in this chapter.
+ </p>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e27752"></a>11.3.5.&nbsp;Compression
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p>The last important HTTP feature is gzip compression. When you talk about HTTP web services, you're almost always talking
+ about moving XML back and forth over the wire. XML is text, and quite verbose text at that, and text generally compresses
+ well. When you request a resource over HTTP, you can ask the server that, if it has any new data to send you, to please send
+ it in compressed format. You include the <tt class="literal">Accept-encoding: gzip</tt> header in your request, and if the server supports compression, it will send you back gzip-compressed data and mark it with
+ a <tt class="literal">Content-encoding: gzip</tt> header.
+ </p>
+ <p><span class="application">Python</span>'s URL library has no built-in support for gzip compression per se, but you can add arbitrary headers to the request. And
+ <span class="application">Python</span> comes with a separate <tt class="filename">gzip</tt> module, which has functions you can use to decompress the data yourself.
+ </p>
+ <p>Note that <a href="review.html" title="11.2.&nbsp;How not to fetch data over HTTP">our little one-line script</a> to download a syndicated feed did not support any of these HTTP features. Let's see how you can improve it.
+ </p>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="review.html">&lt;&lt;&nbsp;How not to fetch data over HTTP</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#oa.divein" title="11.1.&nbsp;Diving in">1</a> <span class="divider">|</span> <a href="review.html" title="11.2.&nbsp;How not to fetch data over HTTP">2</a> <span class="divider">|</span> <span class="thispage">3</span> <span class="divider">|</span> <a href="debugging.html" title="11.4.&nbsp;Debugging HTTP web services">4</a> <span class="divider">|</span> <a href="user_agent.html" title="11.5.&nbsp;Setting the User-Agent">5</a> <span class="divider">|</span> <a href="etags.html" title="11.6.&nbsp;Handling Last-Modified and ETag">6</a> <span class="divider">|</span> <a href="redirects.html" title="11.7.&nbsp;Handling redirects">7</a> <span class="divider">|</span> <a href="gzip_compression.html" title="11.8.&nbsp;Handling compressed data">8</a> <span class="divider">|</span> <a href="alltogether.html" title="11.9.&nbsp;Putting it all together">9</a> <span class="divider">|</span> <a href="summary.html" title="11.10.&nbsp;Summary">10</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="debugging.html">Debugging HTTP web services&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/http_web_services/index.html b/help/diveintopython-5.4/html/http_web_services/index.html
new file mode 100644
index 0000000..0c7a19d
--- /dev/null
+++ b/help/diveintopython-5.4/html/http_web_services/index.html
@@ -0,0 +1,236 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>Chapter&nbsp;11.&nbsp;HTTP Web Services</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="../toc/index.html" title="Dive Into Python">
+ <link rel="previous" href="../scripts_and_streams/summary.html" title="10.8.&nbsp;Summary">
+ <link rel="next" href="review.html" title="11.2.&nbsp;How not to fetch data over HTTP">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<span class="thispage">HTTP Web Services</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="../scripts_and_streams/summary.html" title="Prev: &#8220;Summary&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="review.html" title="Next: &#8220;How not to fetch data over HTTP&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="chapter" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="oa"></a>Chapter&nbsp;11.&nbsp;HTTP Web Services
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="toc">
+ <ul>
+ <li><span class="section"><a href="index.html#oa.divein">11.1. Diving in</a></span></li>
+ <li><span class="section"><a href="review.html">11.2. How not to fetch data over HTTP</a></span></li>
+ <li><span class="section"><a href="http_features.html">11.3. Features of HTTP</a></span><ul>
+ <li><span class="section"><a href="http_features.html#d0e27596">11.3.1. User-Agent</a></span></li>
+ <li><span class="section"><a href="http_features.html#d0e27616">11.3.2. Redirects</a></span></li>
+ <li><span class="section"><a href="http_features.html#d0e27689">11.3.3. Last-Modified/If-Modified-Since</a></span></li>
+ <li><span class="section"><a href="http_features.html#d0e27724">11.3.4. ETag/If-None-Match</a></span></li>
+ <li><span class="section"><a href="http_features.html#d0e27752">11.3.5. Compression</a></span></li>
+ </ul>
+ </li>
+ <li><span class="section"><a href="debugging.html">11.4. Debugging HTTP web services</a></span></li>
+ <li><span class="section"><a href="user_agent.html">11.5. Setting the User-Agent</a></span></li>
+ <li><span class="section"><a href="etags.html">11.6. Handling Last-Modified and ETag</a></span></li>
+ <li><span class="section"><a href="redirects.html">11.7. Handling redirects</a></span></li>
+ <li><span class="section"><a href="gzip_compression.html">11.8. Handling compressed data</a></span></li>
+ <li><span class="section"><a href="alltogether.html">11.9. Putting it all together</a></span></li>
+ <li><span class="section"><a href="summary.html">11.10. Summary</a></span></li>
+ </ul>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="oa.divein"></a>11.1.&nbsp;Diving in
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>You've learned about <a href="../html_processing/index.html" title="Chapter&nbsp;8.&nbsp;HTML Processing">HTML processing</a> and <a href="../xml_processing/index.html" title="Chapter&nbsp;9.&nbsp;XML Processing">XML processing</a>, and along the way you saw <a href="../html_processing/extracting_data.html#dialect.extract.urllib" title="Example&nbsp;8.5.&nbsp;Introducing urllib">how to download a web page</a> and <a href="../scripts_and_streams/index.html#kgp.openanything.urllib" title="Example&nbsp;10.2.&nbsp;Parsing XML from a URL">how to parse XML from a URL</a>, but let's dive into the more general topic of HTTP web services.
+ </p>
+ </div>
+ <p>Simply stated, HTTP web services are programmatic ways of sending and receiving data from remote servers using the operations
+ of HTTP directly. If you want to get data from the server, use a straight HTTP GET; if you want to send new data to the server,
+ use HTTP POST. (Some more advanced HTTP web service APIs also define ways of modifying existing data and deleting data, using
+ HTTP PUT and HTTP DELETE.) In other words, the &#8220;<span class="quote">verbs</span>&#8221; built into the HTTP protocol (GET, POST, PUT, and DELETE) map directly to application-level operations for receiving, sending,
+ modifying, and deleting data.
+ </p>
+ <p>The main advantage of this approach is simplicity, and its simplicity has proven popular with a lot of different sites. Data
+ -- usually XML data -- can be built and stored statically, or generated dynamically by a server-side script, and all major
+ languages include an HTTP library for downloading it. Debugging is also easier, because you can load up the web service in
+ any web browser and see the raw data. Modern browsers will even nicely format and pretty-print XML data for you, to allow
+ you to quickly navigate through it.
+ </p>
+ <p>Examples of pure XML-over-HTTP web services:</p>
+ <div class="itemizedlist">
+ <ul>
+ <li><a href="http://www.amazon.com/webservices">Amazon API</a> allows you to retrieve product information from the Amazon.com online store.
+ </li>
+ <li><a href="http://www.nws.noaa.gov/alerts/">National Weather Service</a> (United States) and <a href="http://demo.xml.weather.gov.hk/">Hong Kong Observatory</a> (Hong Kong) offer weather alerts as a web service.
+ </li>
+ <li><a href="http://atomenabled.org/">Atom API</a> for managing web-based content.
+ </li>
+ <li><a href="http://syndic8.com/">Syndicated feeds</a> from weblogs and news sites bring you up-to-the-minute news from a variety of sites.
+ </li>
+ </ul>
+ </div>
+ <p>In later chapters, you'll explore APIs which use HTTP as a transport for sending and receiving data, but don't map application
+ semantics to the underlying HTTP semantics. (They tunnel everything over HTTP POST.) But this chapter will concentrate on
+ using HTTP GET to get data from a remote server, and you'll explore several HTTP features you can use to get the maximum benefit
+ out of pure HTTP web services.
+ </p>
+ <p>Here is a more advanced version of the <tt class="filename">openanything</tt> module that you saw in <a href="../scripts_and_streams/index.html" title="Chapter&nbsp;10.&nbsp;Scripts and Streams">the previous chapter</a>:
+ </p>
+ <div class="example"><a name="d0e27515"></a><h3 class="title">Example&nbsp;11.1.&nbsp;<tt class="filename">openanything.py</tt></h3>
+ <p>If you have not already done so, you can <a href="http://diveintopython.org/download/diveintopython-examples-5.4.zip" title="Download example scripts">download this and other examples</a> used in this book.
+ </p><pre class="programlisting"><span class='pykeyword'>
+import</span> urllib2, urlparse, gzip
+<span class='pykeyword'>from</span> StringIO <span class='pykeyword'>import</span> StringIO
+
+USER_AGENT = <span class='pystring'>'OpenAnything/1.0 +http://diveintopython.org/http_web_services/'</span>
+
+<span class='pykeyword'>class</span><span class='pyclass'> SmartRedirectHandler</span>(urllib2.HTTPRedirectHandler):
+ <span class='pykeyword'>def</span><span class='pyclass'> http_error_301</span>(self, req, fp, code, msg, headers):
+ result = urllib2.HTTPRedirectHandler.http_error_301(
+ self, req, fp, code, msg, headers)
+ result.status = code
+ <span class='pykeyword'>return</span> result
+
+ <span class='pykeyword'>def</span><span class='pyclass'> http_error_302</span>(self, req, fp, code, msg, headers):
+ result = urllib2.HTTPRedirectHandler.http_error_302(
+ self, req, fp, code, msg, headers)
+ result.status = code
+ <span class='pykeyword'>return</span> result
+
+<span class='pykeyword'>class</span><span class='pyclass'> DefaultErrorHandler</span>(urllib2.HTTPDefaultErrorHandler):
+ <span class='pykeyword'>def</span><span class='pyclass'> http_error_default</span>(self, req, fp, code, msg, headers):
+ result = urllib2.HTTPError(
+ req.get_full_url(), code, msg, headers, fp)
+ result.status = code
+ <span class='pykeyword'>return</span> result
+
+<span class='pykeyword'>def</span><span class='pyclass'> openAnything</span>(source, etag=None, lastmodified=None, agent=USER_AGENT):
+ <span class='pystring'>'''URL, filename, or string --&gt; stream
+
+ This function lets you define parsers that take any input source
+ (URL, pathname to local or network file, or actual data as a string)
+ and deal with it in a uniform manner. Returned object is guaranteed
+ to have all the basic stdio read methods (read, readline, readlines).
+ Just .close() the object when you're done with it.
+
+ If the etag argument is supplied, it will be used as the value of an
+ If-None-Match request header.
+
+ If the lastmodified argument is supplied, it must be a formatted
+ date/time string in GMT (as returned in the Last-Modified header of
+ a previous request). The formatted date/time will be used
+ as the value of an If-Modified-Since request header.
+
+ If the agent argument is supplied, it will be used as the value of a
+ User-Agent request header.
+ '''</span>
+
+ <span class='pykeyword'>if</span> hasattr(source, <span class='pystring'>'read'</span>):
+ <span class='pykeyword'>return</span> source
+
+ <span class='pykeyword'>if</span> source == <span class='pystring'>'-'</span>:
+ <span class='pykeyword'>return</span> sys.stdin
+
+ <span class='pykeyword'>if</span> urlparse.urlparse(source)[0] == <span class='pystring'>'http'</span>:
+ <span class='pycomment'># open URL with urllib2 </span>
+ request = urllib2.Request(source)
+ request.add_header(<span class='pystring'>'User-Agent'</span>, agent)
+ <span class='pykeyword'>if</span> etag:
+ request.add_header(<span class='pystring'>'If-None-Match'</span>, etag)
+ <span class='pykeyword'>if</span> lastmodified:
+ request.add_header(<span class='pystring'>'If-Modified-Since'</span>, lastmodified)
+ request.add_header(<span class='pystring'>'Accept-encoding'</span>, <span class='pystring'>'gzip'</span>)
+ opener = urllib2.build_opener(SmartRedirectHandler(), DefaultErrorHandler())
+ <span class='pykeyword'>return</span> opener.open(request)
+
+ <span class='pycomment'># try to open with native open function (if source is a filename)</span>
+ <span class='pykeyword'>try</span>:
+ <span class='pykeyword'>return</span> open(source)
+ <span class='pykeyword'>except</span> (IOError, OSError):
+ <span class='pykeyword'>pass</span>
+
+ <span class='pycomment'># treat source as string</span>
+ <span class='pykeyword'>return</span> StringIO(str(source))
+
+<span class='pykeyword'>def</span><span class='pyclass'> fetch</span>(source, etag=None, last_modified=None, agent=USER_AGENT):
+ <span class='pystring'>'''Fetch data and metadata from a URL, file, stream, or string'''</span>
+ result = {}
+ f = openAnything(source, etag, last_modified, agent)
+ result[<span class='pystring'>'data'</span>] = f.read()
+ <span class='pykeyword'>if</span> hasattr(f, <span class='pystring'>'headers'</span>):
+ <span class='pycomment'># save ETag, if the server sent one </span>
+ result[<span class='pystring'>'etag'</span>] = f.headers.get(<span class='pystring'>'ETag'</span>)
+ <span class='pycomment'># save Last-Modified header, if the server sent one </span>
+ result[<span class='pystring'>'lastmodified'</span>] = f.headers.get(<span class='pystring'>'Last-Modified'</span>)
+ <span class='pykeyword'>if</span> f.headers.get(<span class='pystring'>'content-encoding'</span>, <span class='pystring'>''</span>) == <span class='pystring'>'gzip'</span>:
+ <span class='pycomment'># data came back gzip-compressed, decompress it </span>
+ result[<span class='pystring'>'data'</span>] = gzip.GzipFile(fileobj=StringIO(result[<span class='pystring'>'data'</span>]])).read()
+ <span class='pykeyword'>if</span> hasattr(f, <span class='pystring'>'url'</span>):
+ result[<span class='pystring'>'url'</span>] = f.url
+ result[<span class='pystring'>'status'</span>] = 200
+ <span class='pykeyword'>if</span> hasattr(f, <span class='pystring'>'status'</span>):
+ result[<span class='pystring'>'status'</span>] = f.status
+ f.close()
+ <span class='pykeyword'>return</span> result
+</pre></div>
+ <div class="furtherreading">
+ <h3>Further reading</h3>
+ <ul>
+ <li>Paul Prescod believes that <a href="http://webservices.xml.com/pub/a/ws/2002/02/06/rest.html">pure HTTP web services are the future of the Internet</a>.
+ </li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="../scripts_and_streams/summary.html">&lt;&lt;&nbsp;Summary</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<span class="thispage">1</span> <span class="divider">|</span> <a href="review.html" title="11.2.&nbsp;How not to fetch data over HTTP">2</a> <span class="divider">|</span> <a href="http_features.html" title="11.3.&nbsp;Features of HTTP">3</a> <span class="divider">|</span> <a href="debugging.html" title="11.4.&nbsp;Debugging HTTP web services">4</a> <span class="divider">|</span> <a href="user_agent.html" title="11.5.&nbsp;Setting the User-Agent">5</a> <span class="divider">|</span> <a href="etags.html" title="11.6.&nbsp;Handling Last-Modified and ETag">6</a> <span class="divider">|</span> <a href="redirects.html" title="11.7.&nbsp;Handling redirects">7</a> <span class="divider">|</span> <a href="gzip_compression.html" title="11.8.&nbsp;Handling compressed data">8</a> <span class="divider">|</span> <a href="alltogether.html" title="11.9.&nbsp;Putting it all together">9</a> <span class="divider">|</span> <a href="summary.html" title="11.10.&nbsp;Summary">10</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="review.html">How not to fetch data over HTTP&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/http_web_services/redirects.html b/help/diveintopython-5.4/html/http_web_services/redirects.html
new file mode 100644
index 0000000..67aa816
--- /dev/null
+++ b/help/diveintopython-5.4/html/http_web_services/redirects.html
@@ -0,0 +1,345 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>11.7.&nbsp;Handling redirects</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;11.&nbsp;HTTP Web Services">
+ <link rel="previous" href="etags.html" title="11.6.&nbsp;Handling Last-Modified and ETag">
+ <link rel="next" href="gzip_compression.html" title="11.8.&nbsp;Handling compressed data">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">HTTP Web Services</a>&nbsp;&gt;&nbsp;<span class="thispage">Handling redirects</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="etags.html" title="Prev: &#8220;Handling Last-Modified and ETag&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="gzip_compression.html" title="Next: &#8220;Handling compressed data&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="oa.redirect"></a>11.7.&nbsp;Handling redirects
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>You can support permanent and temporary redirects using a different kind of custom URL handler.</p>
+ </div>
+ <p>First, let's see why a redirect handler is necessary in the first place.</p>
+ <div class="example"><a name="d0e28730"></a><h3 class="title">Example&nbsp;11.10.&nbsp;Accessing web services without a redirect handler</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> urllib2, httplib</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">httplib.HTTPConnection.debuglevel = 1</span> <a name="oa.redirect.1.0"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">request = urllib2.Request(</span>
+<tt class="prompt">... </tt><span class="userinput"><span class='pystring'>'http://diveintomark.org/redir/example301.xml'</span>)</span> <a name="oa.redirect.1.1"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">opener = urllib2.build_opener()</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">f = opener.open(request)</span>
+<span class="computeroutput">connect: (diveintomark.org, 80)
+send: '
+GET /redir/example301.xml HTTP/1.0
+Host: diveintomark.org
+User-agent: Python-urllib/2.1
+'
+reply: 'HTTP/1.1 301 Moved Permanently\r\n'</span> <a name="oa.redirect.1.2"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">header: Date: Thu, 15 Apr 2004 22:06:25 GMT
+header: Server: Apache/2.0.49 (Debian GNU/Linux)
+header: Location: http://diveintomark.org/xml/atom.xml</span> <a name="oa.redirect.1.3"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">header: Content-Length: 338
+header: Connection: close
+header: Content-Type: text/html; charset=iso-8859-1
+connect: (diveintomark.org, 80)
+send: '
+GET /xml/atom.xml HTTP/1.0</span> <a name="oa.redirect.1.4"></a><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12">
+<span class="computeroutput">Host: diveintomark.org
+User-agent: Python-urllib/2.1
+'
+reply: 'HTTP/1.1 200 OK\r\n'
+header: Date: Thu, 15 Apr 2004 22:06:25 GMT
+header: Server: Apache/2.0.49 (Debian GNU/Linux)
+header: Last-Modified: Thu, 15 Apr 2004 19:45:21 GMT
+header: ETag: "e842a-3e53-55d97640"
+header: Accept-Ranges: bytes
+header: Content-Length: 15955
+header: Connection: close
+header: Content-Type: application/atom+xml</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">f.url</span> <a name="oa.redirect.1.5"></a><img src="../images/callouts/6.png" alt="6" border="0" width="12" height="12">
+<span class="computeroutput">'http://diveintomark.org/xml/atom.xml'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">f.headers.dict</span>
+<span class="computeroutput">{'content-length': '15955',
+'accept-ranges': 'bytes',
+'server': 'Apache/2.0.49 (Debian GNU/Linux)',
+'last-modified': 'Thu, 15 Apr 2004 19:45:21 GMT',
+'connection': 'close',
+'etag': '"e842a-3e53-55d97640"',
+'date': 'Thu, 15 Apr 2004 22:06:25 GMT',
+'content-type': 'application/atom+xml'}</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">f.status</span>
+<span class="traceback">Traceback (most recent call last):
+ File "&lt;stdin&gt;", line 1, in ?
+AttributeError: addinfourl instance has no attribute 'status'</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.redirect.1.0"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You'll be better able to see what's happening if you turn on debugging.</td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.redirect.1.1"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This is a URL which I have set up to permanently redirect to my Atom feed at <tt class="literal">http://diveintomark.org/xml/atom.xml</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.redirect.1.2"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Sure enough, when you try to download the data at that address, the server sends back a <tt class="literal">301</tt> status code, telling you that the resource has moved permanently.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.redirect.1.3"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The server also sends back a <tt class="literal">Location:</tt> header that gives the new address of this data.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.redirect.1.4"><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="filename">urllib2</tt> notices the redirect status code and automatically tries to retrieve the data at the new location specified in the <tt class="literal">Location:</tt> header.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.redirect.1.5"><img src="../images/callouts/6.png" alt="6" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The object you get back from the <tt class="varname">opener</tt> contains the new permanent address and all the headers returned from the second request (retrieved from the new permanent
+ address). But the status code is missing, so you have no way of knowing programmatically whether this redirect was temporary
+ or permanent. And that matters very much: if it was a temporary redirect, then you should continue to ask for the data at
+ the old location. But if it was a permanent redirect (as this was), you should ask for the data at the new location from
+ now on.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>This is suboptimal, but easy to fix. <tt class="filename">urllib2</tt> doesn't behave exactly as you want it to when it encounters a <tt class="literal">301</tt> or <tt class="literal">302</tt>, so let's override its behavior. How? With a custom URL handler, <a href="etags.html" title="11.6.&nbsp;Handling Last-Modified and ETag">just like you did to handle <tt class="literal">304</tt> codes</a>.
+ </p>
+ <div class="example"><a name="d0e28866"></a><h3 class="title">Example&nbsp;11.11.&nbsp;Defining the redirect handler</h3>
+ <p>This class is defined in <tt class="filename">openanything.py</tt>.
+ </p><pre class="programlisting"><span class='pykeyword'>
+class</span> SmartRedirectHandler(urllib2.HTTPRedirectHandler): <a name="oa.redirect.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ <span class='pykeyword'>def</span><span class='pyclass'> http_error_301</span>(self, req, fp, code, msg, headers):
+ result = urllib2.HTTPRedirectHandler.http_error_301( <a name="oa.redirect.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+ self, req, fp, code, msg, headers)
+ result.status = code <a name="oa.redirect.2.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+ <span class='pykeyword'>return</span> result
+
+ <span class='pykeyword'>def</span><span class='pyclass'> http_error_302</span>(self, req, fp, code, msg, headers): <a name="oa.redirect.2.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+ result = urllib2.HTTPRedirectHandler.http_error_302(
+ self, req, fp, code, msg, headers)
+ result.status = code
+ <span class='pykeyword'>return</span> result
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.redirect.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Redirect behavior is defined in <tt class="filename">urllib2</tt> in a class called <tt class="classname">HTTPRedirectHandler</tt>. You don't want to completely override the behavior, you just want to extend it a little, so you'll subclass <tt class="classname">HTTPRedirectHandler</tt> so you can call the ancestor class to do all the hard work.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.redirect.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">When it encounters a <tt class="literal">301</tt> status code from the server, <tt class="filename">urllib2</tt> will search through its handlers and call the <tt class="methodname">http_error_301</tt> method. The first thing ours does is just call the <tt class="methodname">http_error_301</tt> method in the ancestor, which handles the grunt work of looking for the <tt class="literal">Location:</tt> header and following the redirect to the new address.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.redirect.2.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Here's the key: before you return, you store the status code (<tt class="literal">301</tt>), so that the calling program can access it later.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.redirect.2.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Temporary redirects (status code <tt class="literal">302</tt>) work the same way: override the <tt class="literal">http_error_302</tt> method, call the ancestor, and save the status code before returning.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>So what has this bought us? You can now build a URL opener with the custom redirect handler, and it will still automatically
+ follow redirects, but now it will also expose the redirect status code.
+ </p>
+ <div class="example"><a name="d0e28932"></a><h3 class="title">Example&nbsp;11.12.&nbsp;Using the redirect handler to detect permanent redirects</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">request = urllib2.Request(<span class='pystring'>'http://diveintomark.org/redir/example301.xml'</span>)</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> openanything, httplib</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">httplib.HTTPConnection.debuglevel = 1</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">opener = urllib2.build_opener(</span>
+<tt class="prompt">... </tt><span class="userinput">openanything.SmartRedirectHandler())</span> <a name="oa.redirect.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">f = opener.open(request)</span>
+<span class="computeroutput">connect: (diveintomark.org, 80)
+send: 'GET /redir/example301.xml HTTP/1.0
+Host: diveintomark.org
+User-agent: Python-urllib/2.1
+'
+reply: 'HTTP/1.1 301 Moved Permanently\r\n'</span> <a name="oa.redirect.3.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">header: Date: Thu, 15 Apr 2004 22:13:21 GMT
+header: Server: Apache/2.0.49 (Debian GNU/Linux)
+header: Location: http://diveintomark.org/xml/atom.xml
+header: Content-Length: 338
+header: Connection: close
+header: Content-Type: text/html; charset=iso-8859-1
+connect: (diveintomark.org, 80)
+send: '
+GET /xml/atom.xml HTTP/1.0
+Host: diveintomark.org
+User-agent: Python-urllib/2.1
+'
+reply: 'HTTP/1.1 200 OK\r\n'
+header: Date: Thu, 15 Apr 2004 22:13:21 GMT
+header: Server: Apache/2.0.49 (Debian GNU/Linux)
+header: Last-Modified: Thu, 15 Apr 2004 19:45:21 GMT
+header: ETag: "e842a-3e53-55d97640"
+header: Accept-Ranges: bytes
+header: Content-Length: 15955
+header: Connection: close
+header: Content-Type: application/atom+xml
+</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">f.status</span> <a name="oa.redirect.3.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">301</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">f.url</span>
+<span class="computeroutput">'http://diveintomark.org/xml/atom.xml'</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.redirect.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">First, build a URL opener with the redirect handler you just defined.</td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.redirect.3.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You sent off a request, and you got a <tt class="literal">301</tt> status code in response. At this point, the <tt class="methodname">http_error_301</tt> method gets called. You call the ancestor method, which follows the redirect and sends a request at the new location (<tt class="literal">http://diveintomark.org/xml/atom.xml</tt>).
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.redirect.3.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This is the payoff: now, not only do you have access to the new URL, but you have access to the redirect status code, so you
+ can tell that this was a permanent redirect. The next time you request this data, you should request it from the new location
+ (<tt class="literal">http://diveintomark.org/xml/atom.xml</tt>, as specified in <tt class="varname">f.url</tt>). If you had stored the location in a configuration file or a database, you need to update that so you don't keep pounding
+ the server with requests at the old address. It's time to update your address book.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>The same redirect handler can also tell you that you <span class="emphasis"><em>shouldn't</em></span> update your address book.
+ </p>
+ <div class="example"><a name="d0e29025"></a><h3 class="title">Example&nbsp;11.13.&nbsp;Using the redirect handler to detect temporary redirects</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">request = urllib2.Request(</span>
+<tt class="prompt">... </tt><span class="userinput"><span class='pystring'>'http://diveintomark.org/redir/example302.xml'</span>)</span> <a name="oa.redirect.4.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">f = opener.open(request)</span>
+<span class="computeroutput">connect: (diveintomark.org, 80)
+send: '
+GET /redir/example302.xml HTTP/1.0
+Host: diveintomark.org
+User-agent: Python-urllib/2.1
+'
+reply: 'HTTP/1.1 302 Found\r\n'</span> <a name="oa.redirect.4.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">header: Date: Thu, 15 Apr 2004 22:18:21 GMT
+header: Server: Apache/2.0.49 (Debian GNU/Linux)
+header: Location: http://diveintomark.org/xml/atom.xml
+header: Content-Length: 314
+header: Connection: close
+header: Content-Type: text/html; charset=iso-8859-1
+connect: (diveintomark.org, 80)
+send: '
+GET /xml/atom.xml HTTP/1.0</span> <a name="oa.redirect.4.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">Host: diveintomark.org
+User-agent: Python-urllib/2.1
+'
+reply: 'HTTP/1.1 200 OK\r\n'
+header: Date: Thu, 15 Apr 2004 22:18:21 GMT
+header: Server: Apache/2.0.49 (Debian GNU/Linux)
+header: Last-Modified: Thu, 15 Apr 2004 19:45:21 GMT
+header: ETag: "e842a-3e53-55d97640"
+header: Accept-Ranges: bytes
+header: Content-Length: 15955
+header: Connection: close
+header: Content-Type: application/atom+xml</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">f.status</span> <a name="oa.redirect.4.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">302</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">f.url</span>
+<span class="computeroutput">http://diveintomark.org/xml/atom.xml</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.redirect.4.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This is a sample URL I've set up that is configured to tell clients to <span class="emphasis"><em>temporarily</em></span> redirect to <tt class="literal">http://diveintomark.org/xml/atom.xml</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.redirect.4.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The server sends back a <tt class="literal">302</tt> status code, indicating a temporary redirect. The temporary new location of the data is given in the <tt class="literal">Location:</tt> header.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.redirect.4.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="filename">urllib2</tt> calls your <tt class="methodname">http_error_302</tt> method, which calls the ancestor method of the same name in <tt class="classname">urllib2.HTTPRedirectHandler</tt>, which follows the redirect to the new location. Then your <tt class="methodname">http_error_302</tt> method stores the status code (<tt class="literal">302</tt>) so the calling application can get it later.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.redirect.4.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">And here you are, having successfully followed the redirect to <tt class="literal">http://diveintomark.org/xml/atom.xml</tt>. <tt class="varname">f.status</tt> tells you that this was a temporary redirect, which means that you should continue to request data from the original address
+ (<tt class="literal">http://diveintomark.org/redir/example302.xml</tt>). Maybe it will redirect next time too, but maybe not. Maybe it will redirect to a different address. It's not for you
+ to say. The server said this redirect was only temporary, so you should respect that. And now you're exposing enough information
+ that the calling application can respect that.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="etags.html">&lt;&lt;&nbsp;Handling Last-Modified and ETag</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#oa.divein" title="11.1.&nbsp;Diving in">1</a> <span class="divider">|</span> <a href="review.html" title="11.2.&nbsp;How not to fetch data over HTTP">2</a> <span class="divider">|</span> <a href="http_features.html" title="11.3.&nbsp;Features of HTTP">3</a> <span class="divider">|</span> <a href="debugging.html" title="11.4.&nbsp;Debugging HTTP web services">4</a> <span class="divider">|</span> <a href="user_agent.html" title="11.5.&nbsp;Setting the User-Agent">5</a> <span class="divider">|</span> <a href="etags.html" title="11.6.&nbsp;Handling Last-Modified and ETag">6</a> <span class="divider">|</span> <span class="thispage">7</span> <span class="divider">|</span> <a href="gzip_compression.html" title="11.8.&nbsp;Handling compressed data">8</a> <span class="divider">|</span> <a href="alltogether.html" title="11.9.&nbsp;Putting it all together">9</a> <span class="divider">|</span> <a href="summary.html" title="11.10.&nbsp;Summary">10</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="gzip_compression.html">Handling compressed data&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/http_web_services/review.html b/help/diveintopython-5.4/html/http_web_services/review.html
new file mode 100644
index 0000000..11e9d2f
--- /dev/null
+++ b/help/diveintopython-5.4/html/http_web_services/review.html
@@ -0,0 +1,100 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>11.2.&nbsp;How not to fetch data over HTTP</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;11.&nbsp;HTTP Web Services">
+ <link rel="previous" href="index.html" title="Chapter&nbsp;11.&nbsp;HTTP Web Services">
+ <link rel="next" href="http_features.html" title="11.3.&nbsp;Features of HTTP">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">HTTP Web Services</a>&nbsp;&gt;&nbsp;<span class="thispage">How not to fetch data over HTTP</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="index.html" title="Prev: &#8220;HTTP Web Services&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="http_features.html" title="Next: &#8220;Features of HTTP&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="oa.review"></a>11.2.&nbsp;How not to fetch data over HTTP
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>Let's say you want to download a resource over HTTP, such as a syndicated Atom feed. But you don't just want to download
+ it once; you want to download it over and over again, every hour, to get the latest news from the site that's offering the
+ news feed. Let's do it the quick-and-dirty way first, and then see how you can do better.
+ </p>
+ </div>
+ <div class="example"><a name="d0e27543"></a><h3 class="title">Example&nbsp;11.2.&nbsp;Downloading a feed the quick-and-dirty way</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> urllib</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">data = urllib.urlopen(<span class='pystring'>'http://diveintomark.org/xml/atom.xml'</span>).read()</span> <a name="oa.review.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> data</span>
+<span class="computeroutput">&lt;?xml version="1.0" encoding="iso-8859-1"?&gt;
+&lt;feed version="0.3"
+ xmlns="http://purl.org/atom/ns#"
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xml:lang="en"&gt;
+ &lt;title mode="escaped"&gt;dive into mark&lt;/title&gt;
+ &lt;link rel="alternate" type="text/html" href="http://diveintomark.org/"/&gt;
+ &lt;-- rest of feed omitted for brevity --&gt;</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.review.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Downloading anything over HTTP is incredibly easy in <span class="application">Python</span>; in fact, it's a one-liner. The <tt class="filename">urllib</tt> module has a handy <tt class="function">urlopen</tt> function that takes the address of the page you want, and returns a file-like object that you can just <tt class="function">read()</tt> from to get the full contents of the page. It just can't get much easier.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>So what's wrong with this? Well, for a quick one-off during testing or development, there's nothing wrong with it. I do
+ it all the time. I wanted the contents of the feed, and I got the contents of the feed. The same technique works for any
+ web page. But once you start thinking in terms of a web service that you want to access on a regular basis -- and remember,
+ you said you were planning on retrieving this syndicated feed once an hour -- then you're being inefficient, and you're being
+ rude.
+ </p>
+ <p>Let's talk about some of the basic features of HTTP.</p>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="index.html">&lt;&lt;&nbsp;HTTP Web Services</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#oa.divein" title="11.1.&nbsp;Diving in">1</a> <span class="divider">|</span> <span class="thispage">2</span> <span class="divider">|</span> <a href="http_features.html" title="11.3.&nbsp;Features of HTTP">3</a> <span class="divider">|</span> <a href="debugging.html" title="11.4.&nbsp;Debugging HTTP web services">4</a> <span class="divider">|</span> <a href="user_agent.html" title="11.5.&nbsp;Setting the User-Agent">5</a> <span class="divider">|</span> <a href="etags.html" title="11.6.&nbsp;Handling Last-Modified and ETag">6</a> <span class="divider">|</span> <a href="redirects.html" title="11.7.&nbsp;Handling redirects">7</a> <span class="divider">|</span> <a href="gzip_compression.html" title="11.8.&nbsp;Handling compressed data">8</a> <span class="divider">|</span> <a href="alltogether.html" title="11.9.&nbsp;Putting it all together">9</a> <span class="divider">|</span> <a href="summary.html" title="11.10.&nbsp;Summary">10</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="http_features.html">Features of HTTP&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/http_web_services/summary.html b/help/diveintopython-5.4/html/http_web_services/summary.html
new file mode 100644
index 0000000..d1d46d6
--- /dev/null
+++ b/help/diveintopython-5.4/html/http_web_services/summary.html
@@ -0,0 +1,83 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>11.10.&nbsp;Summary</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;11.&nbsp;HTTP Web Services">
+ <link rel="previous" href="alltogether.html" title="11.9.&nbsp;Putting it all together">
+ <link rel="next" href="../soap_web_services/index.html" title="Chapter&nbsp;12.&nbsp;SOAP Web Services">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">HTTP Web Services</a>&nbsp;&gt;&nbsp;<span class="thispage">Summary</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="alltogether.html" title="Prev: &#8220;Putting it all together&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="../soap_web_services/index.html" title="Next: &#8220;SOAP Web Services&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="oa.summary"></a>11.10.&nbsp;Summary
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>The <tt class="filename">openanything.py</tt> and its functions should now make perfect sense.
+ </p>
+ </div>
+ <p>There are 5 important features of HTTP web services that every client should support:</p>
+ <div class="itemizedlist">
+ <ul>
+ <li>Identifying your application <a href="user_agent.html" title="11.5.&nbsp;Setting the User-Agent">by setting a proper <tt class="literal">User-Agent</tt></a>.
+ </li>
+ <li>Handling <a href="redirects.html" title="11.7.&nbsp;Handling redirects">permanent redirects properly</a>.
+ </li>
+ <li>Supporting <a href="etags.html" title="11.6.&nbsp;Handling Last-Modified and ETag"><tt class="literal">Last-Modified</tt> date checking</a> to avoid re-downloading data that hasn't changed.
+ </li>
+ <li>Supporting <a href="etags.html#oa.etags.example" title="Example&nbsp;11.9.&nbsp;Supporting ETag/If-None-Match"><tt class="literal">ETag</tt> hashes</a> to avoid re-downloading data that hasn't changed.
+ </li>
+ <li>Supporting <a href="gzip_compression.html" title="11.8.&nbsp;Handling compressed data">gzip compression</a> to reduce bandwidth even when data <span class="emphasis"><em>has</em></span> changed.
+ </li>
+ </ul>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="alltogether.html">&lt;&lt;&nbsp;Putting it all together</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#oa.divein" title="11.1.&nbsp;Diving in">1</a> <span class="divider">|</span> <a href="review.html" title="11.2.&nbsp;How not to fetch data over HTTP">2</a> <span class="divider">|</span> <a href="http_features.html" title="11.3.&nbsp;Features of HTTP">3</a> <span class="divider">|</span> <a href="debugging.html" title="11.4.&nbsp;Debugging HTTP web services">4</a> <span class="divider">|</span> <a href="user_agent.html" title="11.5.&nbsp;Setting the User-Agent">5</a> <span class="divider">|</span> <a href="etags.html" title="11.6.&nbsp;Handling Last-Modified and ETag">6</a> <span class="divider">|</span> <a href="redirects.html" title="11.7.&nbsp;Handling redirects">7</a> <span class="divider">|</span> <a href="gzip_compression.html" title="11.8.&nbsp;Handling compressed data">8</a> <span class="divider">|</span> <a href="alltogether.html" title="11.9.&nbsp;Putting it all together">9</a> <span class="divider">|</span> <span class="thispage">10</span>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="../soap_web_services/index.html">SOAP Web Services&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/http_web_services/user_agent.html b/help/diveintopython-5.4/html/http_web_services/user_agent.html
new file mode 100644
index 0000000..ac18a66
--- /dev/null
+++ b/help/diveintopython-5.4/html/http_web_services/user_agent.html
@@ -0,0 +1,178 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>11.5.&nbsp;Setting the User-Agent</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;11.&nbsp;HTTP Web Services">
+ <link rel="previous" href="debugging.html" title="11.4.&nbsp;Debugging HTTP web services">
+ <link rel="next" href="etags.html" title="11.6.&nbsp;Handling Last-Modified and ETag">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">HTTP Web Services</a>&nbsp;&gt;&nbsp;<span class="thispage">Setting the User-Agent</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="debugging.html" title="Prev: &#8220;Debugging HTTP web services&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="etags.html" title="Next: &#8220;Handling Last-Modified and ETag&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="oa.useragent"></a>11.5.&nbsp;Setting the <tt class="literal">User-Agent</tt></h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>The first step to improving your HTTP web services client is to identify yourself properly with a <tt class="literal">User-Agent</tt>. To do that, you need to move beyond the basic <tt class="filename">urllib</tt> and dive into <tt class="filename">urllib2</tt>.
+ </p>
+ </div>
+ <div class="example"><a name="d0e27984"></a><h3 class="title">Example&nbsp;11.4.&nbsp;Introducing <tt class="filename">urllib2</tt></h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> httplib</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">httplib.HTTPConnection.debuglevel = 1</span> <a name="oa.useragent.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> urllib2</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">request = urllib2.Request(<span class='pystring'>'http://diveintomark.org/xml/atom.xml'</span>)</span> <a name="oa.useragent.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">opener = urllib2.build_opener()</span> <a name="oa.useragent.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">feeddata = opener.open(request).read()</span> <a name="oa.useragent.1.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">connect: (diveintomark.org, 80)</span>
+<span class="computeroutput">send: '</span>
+<span class="computeroutput">GET /xml/atom.xml HTTP/1.0</span>
+<span class="computeroutput">Host: diveintomark.org</span>
+<span class="computeroutput">User-agent: Python-urllib/2.1</span>
+<span class="computeroutput">'</span>
+<span class="computeroutput">reply: 'HTTP/1.1 200 OK\r\n'</span>
+<span class="computeroutput">header: Date: Wed, 14 Apr 2004 23:23:12 GMT</span>
+<span class="computeroutput">header: Server: Apache/2.0.49 (Debian GNU/Linux)</span>
+<span class="computeroutput">header: Content-Type: application/atom+xml</span>
+<span class="computeroutput">header: Last-Modified: Wed, 14 Apr 2004 22:14:38 GMT</span>
+<span class="computeroutput">header: ETag: "e8284-68e0-4de30f80"</span>
+<span class="computeroutput">header: Accept-Ranges: bytes</span>
+<span class="computeroutput">header: Content-Length: 26848</span>
+<span class="computeroutput">header: Connection: close</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.useragent.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">If you still have your <span class="application">Python</span> <span class="acronym">IDE</span> open from the previous section's example, you can skip this, but this turns on <a href="debugging.html" title="11.4.&nbsp;Debugging HTTP web services">HTTP debugging</a> so you can see what you're actually sending over the wire, and what gets sent back.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.useragent.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Fetching an HTTP resource with <tt class="filename">urllib2</tt> is a three-step process, for good reasons that will become clear shortly. The first step is to create a <tt class="classname">Request</tt> object, which takes the URL of the resource you'll eventually get around to retrieving. Note that this step doesn't actually
+ retrieve anything yet.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.useragent.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The second step is to build a URL opener. This can take any number of handlers, which control how responses are handled.
+ But you can also build an opener without any custom handlers, which is what you're doing here. You'll see how to define
+ and use custom handlers later in this chapter when you explore redirects.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.useragent.1.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The final step is to tell the opener to open the URL, using the <tt class="classname">Request</tt> object you created. As you can see from all the debugging information that gets printed, this step actually retrieves the
+ resource and stores the returned data in <tt class="varname">feeddata</tt>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="d0e28108"></a><h3 class="title">Example&nbsp;11.5.&nbsp;Adding headers with the <tt class="classname">Request</tt></h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">request</span> <a name="oa.useragent.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">&lt;urllib2.Request instance at 0x00250AA8&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">request.get_full_url()</span>
+<span class="computeroutput">http://diveintomark.org/xml/atom.xml</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">request.add_header(<span class='pystring'>'User-Agent'</span>,
+<tt class="prompt">... </tt><span class='pystring'>'OpenAnything/1.0 +http://diveintopython.org/'</span>)</span> <a name="oa.useragent.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">feeddata = opener.open(request).read()</span> <a name="oa.useragent.2.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">connect: (diveintomark.org, 80)</span>
+<span class="computeroutput">send: '</span>
+<span class="computeroutput">GET /xml/atom.xml HTTP/1.0</span>
+<span class="computeroutput">Host: diveintomark.org</span>
+<span class="computeroutput">User-agent: OpenAnything/1.0 +http://diveintopython.org/</span> <a name="oa.useragent.2.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">'</span>
+<span class="computeroutput">reply: 'HTTP/1.1 200 OK\r\n'</span>
+<span class="computeroutput">header: Date: Wed, 14 Apr 2004 23:45:17 GMT</span>
+<span class="computeroutput">header: Server: Apache/2.0.49 (Debian GNU/Linux)</span>
+<span class="computeroutput">header: Content-Type: application/atom+xml</span>
+<span class="computeroutput">header: Last-Modified: Wed, 14 Apr 2004 22:14:38 GMT</span>
+<span class="computeroutput">header: ETag: "e8284-68e0-4de30f80"</span>
+<span class="computeroutput">header: Accept-Ranges: bytes</span>
+<span class="computeroutput">header: Content-Length: 26848</span>
+<span class="computeroutput">header: Connection: close</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.useragent.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You're continuing from the previous example; you've already created a <tt class="classname">Request</tt> object with the URL you want to access.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.useragent.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Using the <tt class="function">add_header</tt> method on the <tt class="classname">Request</tt> object, you can add arbitrary HTTP headers to the request. The first argument is the header, the second is the value you're
+ providing for that header. Convention dictates that a <tt class="literal">User-Agent</tt> should be in this specific format: an application name, followed by a slash, followed by a version number. The rest is free-form,
+ and you'll see a lot of variations in the wild, but somewhere it should include a URL of your application. The <tt class="literal">User-Agent</tt> is usually logged by the server along with other details of your request, and including a URL of your application allows
+ server administrators looking through their access logs to contact you if something is wrong.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.useragent.2.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="varname">opener</tt> object you created before can be reused too, and it will retrieve the same feed again, but with your custom <tt class="literal">User-Agent</tt> header.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#oa.useragent.2.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">And here's you sending your custom <tt class="literal">User-Agent</tt>, in place of the generic one that <span class="application">Python</span> sends by default. If you look closely, you'll notice that you defined a <tt class="literal">User-Agent</tt> header, but you actually sent a <tt class="literal">User-agent</tt> header. See the difference? <tt class="filename">urllib2</tt> changed the case so that only the first letter was capitalized. It doesn't really matter; HTTP specifies that header field
+ names are completely case-insensitive.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="debugging.html">&lt;&lt;&nbsp;Debugging HTTP web services</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#oa.divein" title="11.1.&nbsp;Diving in">1</a> <span class="divider">|</span> <a href="review.html" title="11.2.&nbsp;How not to fetch data over HTTP">2</a> <span class="divider">|</span> <a href="http_features.html" title="11.3.&nbsp;Features of HTTP">3</a> <span class="divider">|</span> <a href="debugging.html" title="11.4.&nbsp;Debugging HTTP web services">4</a> <span class="divider">|</span> <span class="thispage">5</span> <span class="divider">|</span> <a href="etags.html" title="11.6.&nbsp;Handling Last-Modified and ETag">6</a> <span class="divider">|</span> <a href="redirects.html" title="11.7.&nbsp;Handling redirects">7</a> <span class="divider">|</span> <a href="gzip_compression.html" title="11.8.&nbsp;Handling compressed data">8</a> <span class="divider">|</span> <a href="alltogether.html" title="11.9.&nbsp;Putting it all together">9</a> <span class="divider">|</span> <a href="summary.html" title="11.10.&nbsp;Summary">10</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="etags.html">Handling Last-Modified and ETag&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/images/callouts/1.png b/help/diveintopython-5.4/html/images/callouts/1.png
new file mode 100644
index 0000000..7d47343
--- /dev/null
+++ b/help/diveintopython-5.4/html/images/callouts/1.png
Binary files differ
diff --git a/help/diveintopython-5.4/html/images/callouts/10.png b/help/diveintopython-5.4/html/images/callouts/10.png
new file mode 100644
index 0000000..997bbc8
--- /dev/null
+++ b/help/diveintopython-5.4/html/images/callouts/10.png
Binary files differ
diff --git a/help/diveintopython-5.4/html/images/callouts/2.png b/help/diveintopython-5.4/html/images/callouts/2.png
new file mode 100644
index 0000000..5d09341
--- /dev/null
+++ b/help/diveintopython-5.4/html/images/callouts/2.png
Binary files differ
diff --git a/help/diveintopython-5.4/html/images/callouts/3.png b/help/diveintopython-5.4/html/images/callouts/3.png
new file mode 100644
index 0000000..ef7b700
--- /dev/null
+++ b/help/diveintopython-5.4/html/images/callouts/3.png
Binary files differ
diff --git a/help/diveintopython-5.4/html/images/callouts/4.png b/help/diveintopython-5.4/html/images/callouts/4.png
new file mode 100644
index 0000000..adb8364
--- /dev/null
+++ b/help/diveintopython-5.4/html/images/callouts/4.png
Binary files differ
diff --git a/help/diveintopython-5.4/html/images/callouts/5.png b/help/diveintopython-5.4/html/images/callouts/5.png
new file mode 100644
index 0000000..4d7eb46
--- /dev/null
+++ b/help/diveintopython-5.4/html/images/callouts/5.png
Binary files differ
diff --git a/help/diveintopython-5.4/html/images/callouts/6.png b/help/diveintopython-5.4/html/images/callouts/6.png
new file mode 100644
index 0000000..0ba694a
--- /dev/null
+++ b/help/diveintopython-5.4/html/images/callouts/6.png
Binary files differ
diff --git a/help/diveintopython-5.4/html/images/callouts/7.png b/help/diveintopython-5.4/html/images/callouts/7.png
new file mode 100644
index 0000000..472e96f
--- /dev/null
+++ b/help/diveintopython-5.4/html/images/callouts/7.png
Binary files differ
diff --git a/help/diveintopython-5.4/html/images/callouts/8.png b/help/diveintopython-5.4/html/images/callouts/8.png
new file mode 100644
index 0000000..5e60973
--- /dev/null
+++ b/help/diveintopython-5.4/html/images/callouts/8.png
Binary files differ
diff --git a/help/diveintopython-5.4/html/images/callouts/9.png b/help/diveintopython-5.4/html/images/callouts/9.png
new file mode 100644
index 0000000..a0676d2
--- /dev/null
+++ b/help/diveintopython-5.4/html/images/callouts/9.png
Binary files differ
diff --git a/help/diveintopython-5.4/html/images/caution.png b/help/diveintopython-5.4/html/images/caution.png
new file mode 100644
index 0000000..5b7809c
--- /dev/null
+++ b/help/diveintopython-5.4/html/images/caution.png
Binary files differ
diff --git a/help/diveintopython-5.4/html/images/diveintopython.png b/help/diveintopython-5.4/html/images/diveintopython.png
new file mode 100644
index 0000000..a3cbea0
--- /dev/null
+++ b/help/diveintopython-5.4/html/images/diveintopython.png
Binary files differ
diff --git a/help/diveintopython-5.4/html/images/dot.png b/help/diveintopython-5.4/html/images/dot.png
new file mode 100644
index 0000000..dfa6b34
--- /dev/null
+++ b/help/diveintopython-5.4/html/images/dot.png
Binary files differ
diff --git a/help/diveintopython-5.4/html/images/important.png b/help/diveintopython-5.4/html/images/important.png
new file mode 100644
index 0000000..fc1db35
--- /dev/null
+++ b/help/diveintopython-5.4/html/images/important.png
Binary files differ
diff --git a/help/diveintopython-5.4/html/images/note.png b/help/diveintopython-5.4/html/images/note.png
new file mode 100644
index 0000000..d0c3c64
--- /dev/null
+++ b/help/diveintopython-5.4/html/images/note.png
Binary files differ
diff --git a/help/diveintopython-5.4/html/images/tip.png b/help/diveintopython-5.4/html/images/tip.png
new file mode 100644
index 0000000..5c4aab3
--- /dev/null
+++ b/help/diveintopython-5.4/html/images/tip.png
Binary files differ
diff --git a/help/diveintopython-5.4/html/images/warning.png b/help/diveintopython-5.4/html/images/warning.png
new file mode 100644
index 0000000..1c33db8
--- /dev/null
+++ b/help/diveintopython-5.4/html/images/warning.png
Binary files differ
diff --git a/help/diveintopython-5.4/html/index.html b/help/diveintopython-5.4/html/index.html
new file mode 100644
index 0000000..e471337
--- /dev/null
+++ b/help/diveintopython-5.4/html/index.html
@@ -0,0 +1,208 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html lang="en">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+
+ <title>Dive Into Python</title>
+ <link rel="stylesheet" href="diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="description" content=" This book lives at . If you're reading it somewhere else, you may not have the latest version.">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <link rel="alternate" type="application/rss+xml" title="RSS" href="http://diveintopython.org/history.xml">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="6">&nbsp;</td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo">Dive Into Python</h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <div id="wrapper">
+ <div id="main">
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="intro"></a></h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p><i class="citetitle">Dive Into <span class="application">Python</span></i> is a free <span class="application">Python</span> book for experienced programmers. You can <a href="toc/index.html">read the book</a> online, or <a href="#download" title="Download Dive Into Python">download it</a> in a variety of formats. It is also available in <a href="#languages" title="Dive Into Python in your language">multiple languages</a>.
+ </p>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="read"></a>Read <a href="toc/index.html"><i class="citetitle">Dive Into <span class="application">Python</span></i></a></h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p>This book is still being written. You can <a href="appendix/history.html">read the revision history</a> to see what's new. <strong>Updated 20 May 2004</strong></p>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="download"></a>Download <i class="citetitle">Dive Into <span class="application">Python</span></i></h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="itemizedlist">
+ <ul>
+ <li><a href="download/diveintopython-html-5.4.zip" title="Download as HTML (846 KB)"><span class="acronym">HTML</span></a></li>
+ <li><a href="download/diveintopython-pdf-5.4.zip" title="Download as PDF (764 KB)"><span class="acronym">PDF</span></a></li>
+ <li><a href="download/diveintopython-word-5.4.zip" title="Download in Microsoft Word format (686 KB)"><span class="application">Microsoft Word 97</span></a></li>
+ <li><a href="download/diveintopython-text-5.4.zip" title="Download as plain text (368 KB)">plain text</a></li>
+ <li><a href="download/diveintopython-html-flat-5.4.zip" title="Download as single HTML file (459 KB)"><span class="acronym">HTML</span> (single file)</a></li>
+ <li><a href="download/diveintopython-xml-5.4.zip" title="Download XML source (286 KB)">XML (DocBook)</a></li>
+ <li><a href="download/diveintopython-common-5.4.zip" title="Download build tools and auxiliary files (2917 KB)">Build scripts</a> (for translators)
+ </li>
+ </ul>
+ </div>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="languages"></a><i class="citetitle">Dive Into <span class="application">Python</span></i> in your language
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p><a href="appendix/fdl_translation.html">Translations are freely permitted</a> as long as they are released under the <span class="acronym">GNU</span> Free Documentation License. <i class="citetitle">Dive Into <span class="application">Python</span></i> has already been fully or partially translated into several languages. If you translate it into another language and would
+ like to be listed here, just <a href="mailto:mark@diveintopython.org">let me know</a>.
+ </p>
+ <div class="itemizedlist">
+ <ul>
+ <li><a href="http://it.diveintopython.org/">Italian</a></li>
+ <li><a href="http://fr.diveintopython.org/">French</a></li>
+ <li><a href="http://es.diveintopython.org/">Spanish</a></li>
+ <li><a href="http://cn.diveintopython.org/">Chinese</a></li>
+ <li><a href="http://kr.diveintopython.org/">Korean</a></li>
+ <li><a href="http://ru.diveintopython.org/">Russian</a></li>
+ </ul>
+ </div>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="republish"></a>Republish <i class="citetitle">Dive Into <span class="application">Python</span></i></h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p>Want to mirror this web site? Publish this book on your corporate intranet? Distribute it on <span class="acronym">CD-ROM</span>? Feel free. This book is published under the <span class="acronym">GNU</span> Free Documentation License, which gives you enormous freedoms to modify and redistribute it in all its forms. If you're familiar
+ with the <span class="acronym">GNU</span> General Public License for software, you already understand these freedoms; the <span class="acronym">FDL</span> is the <span class="acronym">GPL</span> for books. You can <a href="appendix/fdl.html">read the license</a> for all the details.
+ </p>
+ </div><br><div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </div>
+ </div>
+ <div id="menu">
+ <div class="appendix">
+ <h2>Download <span class="application">Python</span></h2>
+ <div class="itemizedlist">
+ <ul>
+ <li><a href="http://www.activestate.com/Products/ActivePython/">ActivePython</a> (freeware, Windows)
+ </li>
+ <li><a href="http://www.python.org/ftp/python/">IDLE</a> (open source, Windows)
+ </li>
+ <li><a href="http://www.activestate.com/Products/Komodo/">Komodo</a> (commercial, Windows)
+ </li>
+ <li><a href="http://www.python.org/ftp/python/2.3.3/rpms/">RPMs</a> (open source, Linux)
+ </li>
+ <li><a href="http://www.python.org/ftp/python/">Source code</a> (all platforms)
+ </li>
+ <li><a href="http://www.python.org/emacs/python-mode/"><span class="application">python-mode</span></a> for <a href="http://www.gnu.org/software/emacs/"><span class="application">Emacs</span></a></li>
+ <li><a href="http://homepages.cwi.nl/~jack/macpython/download.html">Jack Jansen's binaries</a> (open source, <span class="abbrev">Mac</span> <span class="acronym">OS</span>, <span class="abbrev">Mac</span> <span class="acronym">OS</span> X)
+ </li>
+ <li><a href="http://people.ucsc.edu/~jacobkm/tkinter_osx_howto.html">Fink</a> (open source, <span class="abbrev">Mac</span> <span class="acronym">OS</span> X)
+ </li>
+ <li><a href="http://www.jython.org/download.html">Jython</a> (open source, <span class="application">Java</span>)
+ </li>
+ <li><a href="http://www.python.org/download/">more platforms</a></li>
+ </ul>
+ </div>
+ </div>
+ <div class="appendix">
+ <h2>Learn <span class="application">Python</span></h2>
+ <div class="itemizedlist">
+ <ul>
+ <li><a href="http://www.freenetpages.co.uk/hp/alan.gauld/" title="Python book for first-time programmers"><i class="citetitle">Learning to Program</i></a></li>
+ <li><a href="http://www.ibiblio.org/obp/thinkCSpy/" title="Python book for computer science majors"><i class="citetitle">How to Think Like a Computer Scientist</i></a></li>
+ <li><a href="http://www.mindview.net/Books/TIPython" title="advanced book on design patterns in Python"><i class="citetitle">Thinking in Python</i></a></li>
+ <li><a href="http://www.python.org/doc/Intros.html" title="Python articles for beginners and experts">Introductions</a></li>
+ <li><a href="http://python.oreilly.com/" title="books for sale, plus online articles">O'Reilly <span class="application">Python</span> Center</a></li>
+ <li><a href="http://www.python.org/doc/NonEnglish.html" title="tutorials in over a dozen languages">Non-English resources</a></li>
+ <li><a href="http://directory.google.com/Top/Computers/Programming/Languages/Python/FAQs,_Help,_and_Tutorials/">more tutorials</a></li>
+ </ul>
+ </div>
+ </div>
+ <div class="appendix">
+ <h2><span class="application">Python</span> reference
+ </h2>
+ <div class="itemizedlist">
+ <ul>
+ <li><a href="http://www.python.org/doc/current/" title="official Python documentation">Official documentation</a></li>
+ <li><a href="http://www.brunningonline.net/simon/python/PQR.html" title="all essential Python syntax, on one page">Quick Reference</a></li>
+ </ul>
+ </div>
+ </div>
+ <div class="appendix">
+ <h2><span class="application">Python</span> community
+ </h2>
+ <div class="itemizedlist">
+ <ul>
+ <li><a href="http://www.python.org/" title="Python language home page">Python.org</a></li>
+ <li><a href="http://groups.google.com/groups?group=comp.lang.python" title="lively discussion of all things Python">comp.lang.python</a></li>
+ <li><a href="http://groups.google.com/groups?group=comp.lang.python.announce" title="announcements of new and updated software, books, and other resources">c.l.p.announce</a></li>
+ <li><a href="http://mail.python.org/mailman/listinfo/tutor" title="mailing list for beginners">Tutor</a></li>
+ <li><a href="http://mail.python.org/mailman/listinfo" title="email discussions of specific Python topics"><span class="application">Python</span> mailing lists</a></li>
+ <li><a href="http://directory.google.com/Top/Computers/Programming/Languages/Python/">more links</a></li>
+ </ul>
+ </div>
+ </div>
+ <div class="appendix">
+ <h2><span class="application">Python</span> code
+ </h2>
+ <div class="itemizedlist">
+ <ul>
+ <li><a href="http://www.activestate.com/ASPN/Python/Cookbook/" title="growing archive of annotated code samples"><span class="application">Python</span> Cookbook</a></li>
+ <li><a href="http://www.vex.net/parnassus/" title="central repository for 3rd party Python software">Vaults of Parnassus</a></li>
+ <li><a href="http://www.faqts.com/knowledge-base/index.phtml/fid/199/" title="community-maintained knowledge base"><span class="application">Python</span>.faqts</a></li>
+ </ul>
+ </div>
+ </div>
+ <div class="appendix">
+ <h2>Also by the author</h2>
+ <div class="itemizedlist">
+ <ul>
+ <li><a href="http://diveintoaccessibility.org/" title="Free book for web designers">Dive Into Accessibility</a></li>
+ <li><a href="http://diveintoosx.org/" title="Free repository for Macintosh system administrators">Dive Into OS X</a></li>
+ <li><a href="http://diveintomark.org/" title="author's own Python projects, web services and other fun stuff">dive into mark</a></li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/installing_python/debian.html b/help/diveintopython-5.4/html/installing_python/debian.html
new file mode 100644
index 0000000..6462c85
--- /dev/null
+++ b/help/diveintopython-5.4/html/installing_python/debian.html
@@ -0,0 +1,102 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>1.6.&nbsp;Python on Debian GNU/Linux</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;1.&nbsp;Installing Python">
+ <link rel="previous" href="redhat.html" title="1.5.&nbsp;Python on RedHat Linux">
+ <link rel="next" href="source.html" title="1.7.&nbsp;Python Installation from Source">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Installing Python</a>&nbsp;&gt;&nbsp;<span class="thispage">Python on Debian GNU/Linux</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="redhat.html" title="Prev: &#8220;Python on RedHat Linux&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="source.html" title="Next: &#8220;Python Installation from Source&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="install.debian"></a>1.6.&nbsp;<span class="application">Python</span> on Debian <span class="acronym">GNU</span>/Linux
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>If you are lucky enough to be running Debian <span class="acronym">GNU</span>/Linux, you install <span class="application">Python</span> through the <span><b class="command">apt</b></span> command.
+ </p>
+ </div>
+ <div class="example"><a name="d0e3634"></a><h3 class="title">Example&nbsp;1.3.&nbsp;Installing on Debian <span class="acronym">GNU</span>/Linux
+ </h3><pre class="screen">
+<tt class="prompt">localhost:~$ </tt><span class="userinput">su -</span>
+<tt class="prompt">Password: </tt><span class="userinput">[enter your root password]</span>
+<tt class="prompt">localhost:~# </tt><span class="userinput">apt-get install python</span>
+<span class="computeroutput">Reading Package Lists... Done
+Building Dependency Tree... Done
+The following extra packages will be installed:
+ python2.3
+Suggested packages:
+ python-tk python2.3-doc
+The following NEW packages will be installed:
+ python python2.3
+0 upgraded, 2 newly installed, 0 to remove and 3 not upgraded.
+Need to get 0B/2880kB of archives.
+After unpacking 9351kB of additional disk space will be used.</span>
+<tt class="prompt">Do you want to continue? [Y/n] </tt><span class="userinput">Y</span>
+<span class="computeroutput">Selecting previously deselected package python2.3.
+(Reading database ... 22848 files and directories currently installed.)
+Unpacking python2.3 (from .../python2.3_2.3.1-1_i386.deb) ...
+Selecting previously deselected package python.
+Unpacking python (from .../python_2.3.1-1_all.deb) ...
+Setting up python (2.3.1-1) ...
+Setting up python2.3 (2.3.1-1) ...
+Compiling python modules in /usr/lib/python2.3 ...
+Compiling optimized python modules in /usr/lib/python2.3 ...</span>
+<tt class="prompt">localhost:~# </tt><span class="userinput">exit</span>
+<span class="computeroutput">logout</span>
+<tt class="prompt">localhost:~$ </tt><span class="userinput">python</span>
+<span class="computeroutput">Python 2.3.1 (#2, Sep 24 2003, 11:39:14)
+[GCC 3.3.2 20030908 (Debian prerelease)] on linux2
+Type "help", "copyright", "credits" or "license" for more information.</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">[press Ctrl+D to exit]</span>
+</pre></div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="redhat.html">&lt;&lt;&nbsp;Python on RedHat Linux</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#install.choosing" title="1.1.&nbsp;Which Python is right for you?">1</a> <span class="divider">|</span> <a href="windows.html" title="1.2.&nbsp;Python on Windows">2</a> <span class="divider">|</span> <a href="macosx.html" title="1.3.&nbsp;Python on Mac OS X">3</a> <span class="divider">|</span> <a href="macos9.html" title="1.4.&nbsp;Python on Mac OS 9">4</a> <span class="divider">|</span> <a href="redhat.html" title="1.5.&nbsp;Python on RedHat Linux">5</a> <span class="divider">|</span> <span class="thispage">6</span> <span class="divider">|</span> <a href="source.html" title="1.7.&nbsp;Python Installation from Source">7</a> <span class="divider">|</span> <a href="shell.html" title="1.8.&nbsp;The Interactive Shell">8</a> <span class="divider">|</span> <a href="summary.html" title="1.9.&nbsp;Summary">9</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="source.html">Python Installation from Source&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/installing_python/index.html b/help/diveintopython-5.4/html/installing_python/index.html
new file mode 100644
index 0000000..0161635
--- /dev/null
+++ b/help/diveintopython-5.4/html/installing_python/index.html
@@ -0,0 +1,106 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>Chapter&nbsp;1.&nbsp;Installing Python</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="../toc/index.html" title="Dive Into Python">
+ <link rel="previous" href="../toc/index.html" title="Dive Into Python">
+ <link rel="next" href="windows.html" title="1.2.&nbsp;Python on Windows">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<span class="thispage">Installing Python</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="../toc/index.html" title="Prev: &#8220;Dive Into Python&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="windows.html" title="Next: &#8220;Python on Windows&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="chapter" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="install"></a>Chapter&nbsp;1.&nbsp;Installing <span class="application">Python</span></h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="toc">
+ <ul>
+ <li><span class="section"><a href="index.html#install.choosing">1.1. Which Python is right for you?</a></span></li>
+ <li><span class="section"><a href="windows.html">1.2. Python on Windows</a></span></li>
+ <li><span class="section"><a href="macosx.html">1.3. Python on Mac OS X</a></span></li>
+ <li><span class="section"><a href="macos9.html">1.4. Python on Mac OS 9</a></span></li>
+ <li><span class="section"><a href="redhat.html">1.5. Python on RedHat Linux</a></span></li>
+ <li><span class="section"><a href="debian.html">1.6. Python on Debian GNU/Linux</a></span></li>
+ <li><span class="section"><a href="source.html">1.7. Python Installation from Source</a></span></li>
+ <li><span class="section"><a href="shell.html">1.8. The Interactive Shell</a></span></li>
+ <li><span class="section"><a href="summary.html">1.9. Summary</a></span></li>
+ </ul>
+ </div>
+ <div class="abstract">
+ <p>Welcome to <span class="application">Python</span>. Let's dive in. In this chapter, you'll install the version of <span class="application">Python</span> that's right for you.
+ </p>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="install.choosing"></a>1.1.&nbsp;Which <span class="application">Python</span> is right for you?
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>The first thing you need to do with <span class="application">Python</span> is install it. Or do you?
+ </p>
+ </div>
+ <p>If you're using an account on a hosted server, your ISP may have already installed <span class="application">Python</span>. Most popular Linux distributions come with <span class="application">Python</span> in the default installation. <span class="abbrev">Mac</span> <span class="acronym">OS</span> X 10.2 and later includes a command-line version of <span class="application">Python</span>, although you'll probably want to install a version that includes a more Mac-like graphical interface.
+ </p>
+ <p>Windows does not come with any version of <span class="application">Python</span>, but don't despair! There are several ways to point-and-click your way to <span class="application">Python</span> on Windows.
+ </p>
+ <p>As you can see already, <span class="application">Python</span> runs on a great many operating systems. The full list includes Windows, <span class="abbrev">Mac</span> <span class="acronym">OS</span>, <span class="abbrev">Mac</span> <span class="acronym">OS</span> X, and all varieties of free <span class="acronym">UNIX</span>-compatible systems like Linux. There are also versions that run on Sun Solaris, AS/400, Amiga, OS/2, BeOS, and a plethora
+ of other platforms you've probably never even heard of.
+ </p>
+ <p>What's more, <span class="application">Python</span> programs written on one platform can, with a little care, run on <span class="emphasis"><em>any</em></span> supported platform. For instance, I regularly develop <span class="application">Python</span> programs on Windows and later deploy them on Linux.
+ </p>
+ <p>So back to the question that started this section, &#8220;<span class="quote">Which <span class="application">Python</span> is right for you?</span>&#8221; The answer is whichever one runs on the computer you already have.
+ </p>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="../toc/index.html">&lt;&lt;&nbsp;Dive Into Python</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<span class="thispage">1</span> <span class="divider">|</span> <a href="windows.html" title="1.2.&nbsp;Python on Windows">2</a> <span class="divider">|</span> <a href="macosx.html" title="1.3.&nbsp;Python on Mac OS X">3</a> <span class="divider">|</span> <a href="macos9.html" title="1.4.&nbsp;Python on Mac OS 9">4</a> <span class="divider">|</span> <a href="redhat.html" title="1.5.&nbsp;Python on RedHat Linux">5</a> <span class="divider">|</span> <a href="debian.html" title="1.6.&nbsp;Python on Debian GNU/Linux">6</a> <span class="divider">|</span> <a href="source.html" title="1.7.&nbsp;Python Installation from Source">7</a> <span class="divider">|</span> <a href="shell.html" title="1.8.&nbsp;The Interactive Shell">8</a> <span class="divider">|</span> <a href="summary.html" title="1.9.&nbsp;Summary">9</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="windows.html">Python on Windows&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/installing_python/macos9.html b/help/diveintopython-5.4/html/installing_python/macos9.html
new file mode 100644
index 0000000..422a739
--- /dev/null
+++ b/help/diveintopython-5.4/html/installing_python/macos9.html
@@ -0,0 +1,111 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>1.4.&nbsp;Python on Mac OS 9</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;1.&nbsp;Installing Python">
+ <link rel="previous" href="macosx.html" title="1.3.&nbsp;Python on Mac OS X">
+ <link rel="next" href="redhat.html" title="1.5.&nbsp;Python on RedHat Linux">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Installing Python</a>&nbsp;&gt;&nbsp;<span class="thispage">Python on Mac OS 9</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="macosx.html" title="Prev: &#8220;Python on Mac OS X&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="redhat.html" title="Next: &#8220;Python on RedHat Linux&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="install.macos9"></a>1.4.&nbsp;<span class="application">Python</span> on <span class="abbrev">Mac</span> <span class="acronym">OS</span> 9
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p><span class="abbrev">Mac</span> <span class="acronym">OS</span> 9 does not come with any version of <span class="application">Python</span>, but installation is very simple, and there is only one choice.
+ </p>
+ </div>
+ <div class="procedure">
+ <p>Follow these steps to install <span class="application">Python</span> on <span class="abbrev">Mac</span> <span class="acronym">OS</span> 9:
+ </p>
+ <ol type="1">
+ <li>
+ <p>Download the <tt class="filename">MacPython23full.bin</tt> file from <a href="http://homepages.cwi.nl/~jack/macpython/download.html">http://homepages.cwi.nl/~jack/macpython/download.html</a>.
+ </p>
+ </li>
+ <li>
+ <p>If your browser does not decompress the file automatically, double-click <tt class="filename">MacPython23full.bin</tt> to decompress the file with <span class="application">Stuffit Expander</span>.
+ </p>
+ </li>
+ <li>
+ <p>Double-click the installer, <tt class="filename">MacPython23full</tt>.
+ </p>
+ </li>
+ <li>
+ <p>Step through the installer program.</p>
+ </li>
+ <li>
+ <p>AFter installation is complete, close the installer and open the <tt class="filename">/Applications</tt> folder.
+ </p>
+ </li>
+ <li>
+ <p>Open the <tt class="filename">MacPython-OS9 2.3</tt> folder.
+ </p>
+ </li>
+ <li>
+ <p>Double-click <tt class="filename">Python IDE</tt> to launch <span class="application">Python</span>.
+ </p>
+ </li>
+ </ol>
+ </div>
+ <p>The <span class="application">MacPython</span> <span class="acronym">IDE</span> should display a splash screen, and then take you to the interactive shell. If the interactive shell does not appear, select
+ <span class="guimenu">Window</span>-&gt;<span class="guimenuitem">Python Interactive</span> (<span><b class="shortcut"><span><b class="keycap">Cmd</b></span>-<span class="keysym">0</span></b></span>). You'll see a screen like this:
+ </p>
+ <div class="informalexample"><pre class="screen">
+<span class="computeroutput">Python 2.3 (#2, Jul 30 2003, 11:45:28)
+[GCC 3.1 20020420 (prerelease)]
+Type "copyright", "credits" or "license" for more information.
+MacPython IDE 1.0.1</span>
+<tt class="prompt">&gt;&gt;&gt; </tt>
+</pre></div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="macosx.html">&lt;&lt;&nbsp;Python on Mac OS X</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#install.choosing" title="1.1.&nbsp;Which Python is right for you?">1</a> <span class="divider">|</span> <a href="windows.html" title="1.2.&nbsp;Python on Windows">2</a> <span class="divider">|</span> <a href="macosx.html" title="1.3.&nbsp;Python on Mac OS X">3</a> <span class="divider">|</span> <span class="thispage">4</span> <span class="divider">|</span> <a href="redhat.html" title="1.5.&nbsp;Python on RedHat Linux">5</a> <span class="divider">|</span> <a href="debian.html" title="1.6.&nbsp;Python on Debian GNU/Linux">6</a> <span class="divider">|</span> <a href="source.html" title="1.7.&nbsp;Python Installation from Source">7</a> <span class="divider">|</span> <a href="shell.html" title="1.8.&nbsp;The Interactive Shell">8</a> <span class="divider">|</span> <a href="summary.html" title="1.9.&nbsp;Summary">9</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="redhat.html">Python on RedHat Linux&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/installing_python/macosx.html b/help/diveintopython-5.4/html/installing_python/macosx.html
new file mode 100644
index 0000000..8ef5af1
--- /dev/null
+++ b/help/diveintopython-5.4/html/installing_python/macosx.html
@@ -0,0 +1,172 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>1.3.&nbsp;Python on Mac OS X</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;1.&nbsp;Installing Python">
+ <link rel="previous" href="windows.html" title="1.2.&nbsp;Python on Windows">
+ <link rel="next" href="macos9.html" title="1.4.&nbsp;Python on Mac OS 9">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Installing Python</a>&nbsp;&gt;&nbsp;<span class="thispage">Python on Mac OS X</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="windows.html" title="Prev: &#8220;Python on Windows&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="macos9.html" title="Next: &#8220;Python on Mac OS 9&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="install.macosx"></a>1.3.&nbsp;<span class="application">Python</span> on <span class="abbrev">Mac</span> <span class="acronym">OS</span> X
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>On <span class="abbrev">Mac</span> <span class="acronym">OS</span> X, you have two choices for installing <span class="application">Python</span>: install it, or don't install it. You probably want to install it.
+ </p>
+ </div>
+ <p><span class="abbrev">Mac</span> <span class="acronym">OS</span> X 10.2 and later comes with a command-line version of <span class="application">Python</span> preinstalled. If you are comfortable with the command line, you can use this version for the first third of the book. However,
+ the preinstalled version does not come with an <span class="acronym">XML</span> parser, so when you get to the <span class="acronym">XML</span> chapter, you'll need to install the full version.
+ </p>
+ <p>Rather than using the preinstalled version, you'll probably want to install the latest version, which also comes with a graphical
+ interactive shell.
+ </p>
+ <div class="procedure">
+ <h3 class="title">Procedure&nbsp;1.3.&nbsp;Running the Preinstalled Version of <span class="application">Python</span> on <span class="abbrev">Mac</span> <span class="acronym">OS</span> X
+ </h3>
+ <p>To use the preinstalled version of <span class="application">Python</span>, follow these steps:
+ </p>
+ <ol type="1">
+ <li>
+ <p>Open the <tt class="filename">/Applications</tt> folder.
+ </p>
+ </li>
+ <li>
+ <p>Open the <tt class="filename">Utilities</tt> folder.
+ </p>
+ </li>
+ <li>
+ <p>Double-click <tt class="filename">Terminal</tt> to open a terminal window and get to a command line.
+ </p>
+ </li>
+ <li>
+ <p>Type <b class="userinput"><tt>python</tt></b> at the command prompt.
+ </p>
+ </li>
+ </ol>
+ </div>
+ <p>Try it out:</p>
+ <div class="informalexample"><pre class="screen">
+<span class="computeroutput">Welcome to Darwin!</span>
+<tt class="prompt">[localhost:~] you% </tt><span class="userinput">python</span>
+<span class="computeroutput">Python 2.2 (#1, 07/14/02, 23:25:09)
+[GCC Apple cpp-precomp 6.14] on darwin
+Type "help", "copyright", "credits", or "license" for more information.</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">[press Ctrl+D to get back to the command prompt]</span>
+<tt class="prompt">[localhost:~] you% </tt>
+</pre></div>
+ <div class="procedure">
+ <h3 class="title">Procedure&nbsp;1.4.&nbsp;Installing the Latest Version of <span class="application">Python</span> on <span class="abbrev">Mac</span> <span class="acronym">OS</span> X
+ </h3>
+ <p>Follow these steps to download and install the latest version of <span class="application">Python</span>:
+ </p>
+ <ol type="1">
+ <li>
+ <p>Download the <tt class="filename">MacPython-OSX</tt> disk image from <a href="http://homepages.cwi.nl/~jack/macpython/download.html">http://homepages.cwi.nl/~jack/macpython/download.html</a>.
+ </p>
+ </li>
+ <li>
+ <p>If your browser has not already done so, double-click <tt class="filename">MacPython-OSX-2.3-1.dmg</tt> to mount the disk image on your desktop.
+ </p>
+ </li>
+ <li>
+ <p>Double-click the installer, <tt class="filename">MacPython-OSX.pkg</tt>.
+ </p>
+ </li>
+ <li>
+ <p>The installer will prompt you for your administrative username and password.</p>
+ </li>
+ <li>
+ <p>Step through the installer program.</p>
+ </li>
+ <li>
+ <p>After installation is complete, close the installer and open the <tt class="filename">/Applications</tt> folder.
+ </p>
+ </li>
+ <li>
+ <p>Open the <tt class="filename">MacPython-2.3</tt> folder
+ </p>
+ </li>
+ <li>
+ <p>Double-click <tt class="filename">PythonIDE</tt> to launch <span class="application">Python</span>.
+ </p>
+ </li>
+ </ol>
+ </div>
+ <p>The <span class="application">MacPython</span> <span class="acronym">IDE</span> should display a splash screen, then take you to the interactive shell. If the interactive shell does not appear, select
+ <span class="guimenu">Window</span>-&gt;<span class="guimenuitem">Python Interactive</span> (<span><b class="shortcut"><span><b class="keycap">Cmd</b></span>-<span class="keysym">0</span></b></span>). The opening window will look something like this:
+ </p>
+ <div class="informalexample"><pre class="screen">
+<span class="computeroutput">Python 2.3 (#2, Jul 30 2003, 11:45:28)
+[GCC 3.1 20020420 (prerelease)]
+Type "copyright", "credits" or "license" for more information.
+MacPython IDE 1.0.1</span>
+<tt class="prompt">&gt;&gt;&gt; </tt>
+</pre></div>
+ <p>Note that once you install the latest version, the pre-installed version is still present. If you are running scripts from
+ the command line, you need to be aware which version of <span class="application">Python</span> you are using.
+ </p>
+ <div class="example"><a name="d0e3331"></a><h3 class="title">Example&nbsp;1.1.&nbsp;Two versions of <span class="application">Python</span></h3><pre class="screen">
+<tt class="prompt">[localhost:~] you% </tt><span class="userinput">python</span>
+<span class="computeroutput">Python 2.2 (#1, 07/14/02, 23:25:09)
+[GCC Apple cpp-precomp 6.14] on darwin
+Type "help", "copyright", "credits", or "license" for more information.</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">[press Ctrl+D to get back to the command prompt]</span>
+<tt class="prompt">[localhost:~] you% </tt><span class="userinput">/usr/local/bin/python</span>
+<span class="computeroutput">Python 2.3 (#2, Jul 30 2003, 11:45:28)
+[GCC 3.1 20020420 (prerelease)] on darwin
+Type "help", "copyright", "credits", or "license" for more information.</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">[press Ctrl+D to get back to the command prompt]</span>
+<tt class="prompt">[localhost:~] you% </tt>
+</pre></div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="windows.html">&lt;&lt;&nbsp;Python on Windows</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#install.choosing" title="1.1.&nbsp;Which Python is right for you?">1</a> <span class="divider">|</span> <a href="windows.html" title="1.2.&nbsp;Python on Windows">2</a> <span class="divider">|</span> <span class="thispage">3</span> <span class="divider">|</span> <a href="macos9.html" title="1.4.&nbsp;Python on Mac OS 9">4</a> <span class="divider">|</span> <a href="redhat.html" title="1.5.&nbsp;Python on RedHat Linux">5</a> <span class="divider">|</span> <a href="debian.html" title="1.6.&nbsp;Python on Debian GNU/Linux">6</a> <span class="divider">|</span> <a href="source.html" title="1.7.&nbsp;Python Installation from Source">7</a> <span class="divider">|</span> <a href="shell.html" title="1.8.&nbsp;The Interactive Shell">8</a> <span class="divider">|</span> <a href="summary.html" title="1.9.&nbsp;Summary">9</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="macos9.html">Python on Mac OS 9&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/installing_python/redhat.html b/help/diveintopython-5.4/html/installing_python/redhat.html
new file mode 100644
index 0000000..3c2b939
--- /dev/null
+++ b/help/diveintopython-5.4/html/installing_python/redhat.html
@@ -0,0 +1,118 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>1.5.&nbsp;Python on RedHat Linux</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;1.&nbsp;Installing Python">
+ <link rel="previous" href="macos9.html" title="1.4.&nbsp;Python on Mac OS 9">
+ <link rel="next" href="debian.html" title="1.6.&nbsp;Python on Debian GNU/Linux">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Installing Python</a>&nbsp;&gt;&nbsp;<span class="thispage">Python on RedHat Linux</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="macos9.html" title="Prev: &#8220;Python on Mac OS 9&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="debian.html" title="Next: &#8220;Python on Debian GNU/Linux&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="install.redhat"></a>1.5.&nbsp;<span class="application">Python</span> on RedHat Linux
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p>Installing under UNIX-compatible operating systems such as Linux is easy if you're willing to install a binary package. Pre-built
+ binary packages are available for most popular Linux distributions. Or you can always compile from source.
+ </p>
+ <div class="abstract">
+ <p>Download the latest <span class="application">Python</span> <span class="acronym">RPM</span> by going to <a href="http://www.python.org/ftp/python/">http://www.python.org/ftp/python/</a> and selecting the highest version number listed, then selecting the <tt class="filename">rpms/</tt> directory within that. Then download the <span class="acronym">RPM</span> with the highest version number. You can install it with the <span><b class="command">rpm</b></span> command, as shown here:
+ </p>
+ </div>
+ <div class="example"><a name="d0e3510"></a><h3 class="title">Example&nbsp;1.2.&nbsp;Installing on RedHat Linux 9</h3><pre class="screen">
+<tt class="prompt">localhost:~$ </tt><span class="userinput">su -</span>
+<tt class="prompt">Password: </tt><span class="userinput">[enter your root password]</span>
+<tt class="prompt">[root@localhost root]# </tt><span class="userinput">wget http://python.org/ftp/python/2.3/rpms/redhat-9/python2.3-2.3-5pydotorg.i386.rpm</span>
+<span class="computeroutput">Resolving python.org... done.
+Connecting to python.org[194.109.137.226]:80... connected.
+HTTP request sent, awaiting response... 200 OK
+Length: 7,495,111 [application/octet-stream]
+...</span>
+<tt class="prompt">[root@localhost root]# </tt><span class="userinput">rpm -Uvh python2.3-2.3-5pydotorg.i386.rpm</span>
+<span class="computeroutput">Preparing... ########################################### [100%]
+ 1:python2.3 ########################################### [100%]</span>
+<tt class="prompt">[root@localhost root]# </tt><span class="userinput">python</span> <a name="install.unix.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">Python 2.2.2 (#1, Feb 24 2003, 19:13:11)
+[GCC 3.2.2 20030222 (Red Hat Linux 3.2.2-4)] on linux2
+Type "help", "copyright", "credits", or "license" for more information.</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">[press Ctrl+D to exit]</span>
+<tt class="prompt">[root@localhost root]# </tt><span class="userinput">python2.3</span> <a name="install.unix.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">Python 2.3 (#1, Sep 12 2003, 10:53:56)
+[GCC 3.2.2 20030222 (Red Hat Linux 3.2.2-5)] on linux2
+Type "help", "copyright", "credits", or "license" for more information.</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">[press Ctrl+D to exit]</span>
+<tt class="prompt">[root@localhost root]# </tt><span class="userinput">which python2.3</span> <a name="install.unix.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">/usr/bin/python2.3</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#install.unix.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Whoops! Just typing <b class="userinput"><tt>python</tt></b> gives you the older version of <span class="application">Python</span> -- the one that was installed by default. That's not the one you want.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#install.unix.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">At the time of this writing, the newest version is called <b class="userinput"><tt>python2.3</tt></b>. You'll probably want to change the path on the first line of the sample scripts to point to the newer version.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#install.unix.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This is the complete path of the newer version of <span class="application">Python</span> that you just installed. Use this on the <tt class="literal">#!</tt> line (the first line of each script) to ensure that scripts are running under the latest version of <span class="application">Python</span>, and be sure to type <b class="userinput"><tt>python2.3</tt></b> to get into the interactive shell.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="macos9.html">&lt;&lt;&nbsp;Python on Mac OS 9</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#install.choosing" title="1.1.&nbsp;Which Python is right for you?">1</a> <span class="divider">|</span> <a href="windows.html" title="1.2.&nbsp;Python on Windows">2</a> <span class="divider">|</span> <a href="macosx.html" title="1.3.&nbsp;Python on Mac OS X">3</a> <span class="divider">|</span> <a href="macos9.html" title="1.4.&nbsp;Python on Mac OS 9">4</a> <span class="divider">|</span> <span class="thispage">5</span> <span class="divider">|</span> <a href="debian.html" title="1.6.&nbsp;Python on Debian GNU/Linux">6</a> <span class="divider">|</span> <a href="source.html" title="1.7.&nbsp;Python Installation from Source">7</a> <span class="divider">|</span> <a href="shell.html" title="1.8.&nbsp;The Interactive Shell">8</a> <span class="divider">|</span> <a href="summary.html" title="1.9.&nbsp;Summary">9</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="debian.html">Python on Debian GNU/Linux&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/installing_python/shell.html b/help/diveintopython-5.4/html/installing_python/shell.html
new file mode 100644
index 0000000..3f9e9e2
--- /dev/null
+++ b/help/diveintopython-5.4/html/installing_python/shell.html
@@ -0,0 +1,107 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>1.8.&nbsp;The Interactive Shell</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;1.&nbsp;Installing Python">
+ <link rel="previous" href="source.html" title="1.7.&nbsp;Python Installation from Source">
+ <link rel="next" href="summary.html" title="1.9.&nbsp;Summary">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Installing Python</a>&nbsp;&gt;&nbsp;<span class="thispage">The Interactive Shell</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="source.html" title="Prev: &#8220;Python Installation from Source&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="summary.html" title="Next: &#8220;Summary&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="install.shell"></a>1.8.&nbsp;The Interactive Shell
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>Now that you have <span class="application">Python</span> installed, what's this interactive shell thing you're running?
+ </p>
+ </div>
+ <p>It's like this: <span class="application">Python</span> leads a double life. It's an interpreter for scripts that you can run from the command line or run like applications, by
+ double-clicking the scripts. But it's also an interactive shell that can evaluate arbitrary statements and expressions.
+ This is extremely useful for debugging, quick hacking, and testing. I even know some people who use the <span class="application">Python</span> interactive shell in lieu of a calculator!
+ </p>
+ <p>Launch the <span class="application">Python</span> interactive shell in whatever way works on your platform, and let's dive in with the steps shown here:
+ </p>
+ <div class="example"><a name="d0e3829"></a><h3 class="title">Example&nbsp;1.5.&nbsp;First Steps in the Interactive Shell</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">1 + 1</span> <a name="install.shell.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">2</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> <span class='pystring'>'hello world'</span></span> <a name="install.shell.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">hello world</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">x = 1</span> <a name="install.shell.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">y = 2</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">x + y</span>
+<span class="computeroutput">3</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#install.shell.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <span class="application">Python</span> interactive shell can evaluate arbitrary <span class="application">Python</span> expressions, including any basic arithmetic expression.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#install.shell.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The interactive shell can execute arbitrary <span class="application">Python</span> statements, including the <span><b class="command">print</b></span> statement.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#install.shell.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You can also assign values to variables, and the values will be remembered as long as the shell is open (but not any longer
+ than that).
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="source.html">&lt;&lt;&nbsp;Python Installation from Source</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#install.choosing" title="1.1.&nbsp;Which Python is right for you?">1</a> <span class="divider">|</span> <a href="windows.html" title="1.2.&nbsp;Python on Windows">2</a> <span class="divider">|</span> <a href="macosx.html" title="1.3.&nbsp;Python on Mac OS X">3</a> <span class="divider">|</span> <a href="macos9.html" title="1.4.&nbsp;Python on Mac OS 9">4</a> <span class="divider">|</span> <a href="redhat.html" title="1.5.&nbsp;Python on RedHat Linux">5</a> <span class="divider">|</span> <a href="debian.html" title="1.6.&nbsp;Python on Debian GNU/Linux">6</a> <span class="divider">|</span> <a href="source.html" title="1.7.&nbsp;Python Installation from Source">7</a> <span class="divider">|</span> <span class="thispage">8</span> <span class="divider">|</span> <a href="summary.html" title="1.9.&nbsp;Summary">9</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="summary.html">Summary&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/installing_python/source.html b/help/diveintopython-5.4/html/installing_python/source.html
new file mode 100644
index 0000000..0f96de4
--- /dev/null
+++ b/help/diveintopython-5.4/html/installing_python/source.html
@@ -0,0 +1,106 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>1.7.&nbsp;Python Installation from Source</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;1.&nbsp;Installing Python">
+ <link rel="previous" href="debian.html" title="1.6.&nbsp;Python on Debian GNU/Linux">
+ <link rel="next" href="shell.html" title="1.8.&nbsp;The Interactive Shell">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Installing Python</a>&nbsp;&gt;&nbsp;<span class="thispage">Python Installation from Source</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="debian.html" title="Prev: &#8220;Python on Debian GNU/Linux&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="shell.html" title="Next: &#8220;The Interactive Shell&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="install.source"></a>1.7.&nbsp;<span class="application">Python</span> Installation from Source
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>If you prefer to build from source, you can download the <span class="application">Python</span> source code from <a href="http://www.python.org/ftp/python/">http://www.python.org/ftp/python/</a>. Select the highest version number listed, download the <tt class="filename">.tgz</tt> file), and then do the usual <b class="userinput"><tt>configure</tt></b>, <b class="userinput"><tt>make</tt></b>, <b class="userinput"><tt>make install</tt></b> dance.
+ </p>
+ </div>
+ <div class="example"><a name="d0e3716"></a><h3 class="title">Example&nbsp;1.4.&nbsp;Installing from source</h3><pre class="screen">
+<tt class="prompt">localhost:~$ </tt><span class="userinput">su -</span>
+<tt class="prompt">Password: </tt><span class="userinput">[enter your root password]</span>
+<tt class="prompt">localhost:~# </tt><span class="userinput">wget http://www.python.org/ftp/python/2.3/Python-2.3.tgz</span>
+<span class="computeroutput">Resolving www.python.org... done.
+Connecting to www.python.org[194.109.137.226]:80... connected.
+HTTP request sent, awaiting response... 200 OK
+Length: 8,436,880 [application/x-tar]
+...</span>
+<tt class="prompt">localhost:~# </tt><span class="userinput">tar xfz Python-2.3.tgz</span>
+<tt class="prompt">localhost:~# </tt><span class="userinput">cd Python-2.3</span>
+<tt class="prompt">localhost:~/Python-2.3# </tt><span class="userinput">./configure</span>
+<span class="computeroutput">checking MACHDEP... linux2
+checking EXTRAPLATDIR...
+checking for --without-gcc... no
+...</span>
+<tt class="prompt">localhost:~/Python-2.3# </tt><span class="userinput">make</span>
+<span class="computeroutput">gcc -pthread -c -fno-strict-aliasing -DNDEBUG -g -O3 -Wall -Wstrict-prototypes
+-I. -I./Include -DPy_BUILD_CORE -o Modules/python.o Modules/python.c
+gcc -pthread -c -fno-strict-aliasing -DNDEBUG -g -O3 -Wall -Wstrict-prototypes
+-I. -I./Include -DPy_BUILD_CORE -o Parser/acceler.o Parser/acceler.c
+gcc -pthread -c -fno-strict-aliasing -DNDEBUG -g -O3 -Wall -Wstrict-prototypes
+-I. -I./Include -DPy_BUILD_CORE -o Parser/grammar1.o Parser/grammar1.c
+...</span>
+<tt class="prompt">localhost:~/Python-2.3# </tt><span class="userinput">make install</span>
+<span class="computeroutput">/usr/bin/install -c python /usr/local/bin/python2.3
+...</span>
+<tt class="prompt">localhost:~/Python-2.3# </tt><span class="userinput">exit</span>
+<span class="computeroutput">logout</span>
+<tt class="prompt">localhost:~$ </tt><span class="userinput">which python</span>
+<span class="computeroutput">/usr/local/bin/python</span>
+<tt class="prompt">localhost:~$ </tt><span class="userinput">python</span>
+<span class="computeroutput">Python 2.3.1 (#2, Sep 24 2003, 11:39:14)
+[GCC 3.3.2 20030908 (Debian prerelease)] on linux2
+Type "help", "copyright", "credits" or "license" for more information.</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">[press Ctrl+D to get back to the command prompt]</span>
+<tt class="prompt">localhost:~$ </tt>
+</pre></div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="debian.html">&lt;&lt;&nbsp;Python on Debian GNU/Linux</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#install.choosing" title="1.1.&nbsp;Which Python is right for you?">1</a> <span class="divider">|</span> <a href="windows.html" title="1.2.&nbsp;Python on Windows">2</a> <span class="divider">|</span> <a href="macosx.html" title="1.3.&nbsp;Python on Mac OS X">3</a> <span class="divider">|</span> <a href="macos9.html" title="1.4.&nbsp;Python on Mac OS 9">4</a> <span class="divider">|</span> <a href="redhat.html" title="1.5.&nbsp;Python on RedHat Linux">5</a> <span class="divider">|</span> <a href="debian.html" title="1.6.&nbsp;Python on Debian GNU/Linux">6</a> <span class="divider">|</span> <span class="thispage">7</span> <span class="divider">|</span> <a href="shell.html" title="1.8.&nbsp;The Interactive Shell">8</a> <span class="divider">|</span> <a href="summary.html" title="1.9.&nbsp;Summary">9</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="shell.html">The Interactive Shell&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/installing_python/summary.html b/help/diveintopython-5.4/html/installing_python/summary.html
new file mode 100644
index 0000000..1c6007a
--- /dev/null
+++ b/help/diveintopython-5.4/html/installing_python/summary.html
@@ -0,0 +1,72 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>1.9.&nbsp;Summary</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;1.&nbsp;Installing Python">
+ <link rel="previous" href="shell.html" title="1.8.&nbsp;The Interactive Shell">
+ <link rel="next" href="../getting_to_know_python/index.html" title="Chapter&nbsp;2.&nbsp;Your First Python Program">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Installing Python</a>&nbsp;&gt;&nbsp;<span class="thispage">Summary</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="shell.html" title="Prev: &#8220;The Interactive Shell&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="../getting_to_know_python/index.html" title="Next: &#8220;Your First Python Program&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="install.summary"></a>1.9.&nbsp;Summary
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>You should now have a version of <span class="application">Python</span> installed that works for you.
+ </p>
+ </div>
+ <p>Depending on your platform, you may have more than one version of <span class="application">Python</span> intsalled. If so, you need to be aware of your paths. If simply typing <span><b class="command">python</b></span> on the command line doesn't run the version of <span class="application">Python</span> that you want to use, you may need to enter the full pathname of your preferred version.
+ </p>
+ <p>Congratulations, and welcome to <span class="application">Python</span>.
+ </p>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="shell.html">&lt;&lt;&nbsp;The Interactive Shell</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#install.choosing" title="1.1.&nbsp;Which Python is right for you?">1</a> <span class="divider">|</span> <a href="windows.html" title="1.2.&nbsp;Python on Windows">2</a> <span class="divider">|</span> <a href="macosx.html" title="1.3.&nbsp;Python on Mac OS X">3</a> <span class="divider">|</span> <a href="macos9.html" title="1.4.&nbsp;Python on Mac OS 9">4</a> <span class="divider">|</span> <a href="redhat.html" title="1.5.&nbsp;Python on RedHat Linux">5</a> <span class="divider">|</span> <a href="debian.html" title="1.6.&nbsp;Python on Debian GNU/Linux">6</a> <span class="divider">|</span> <a href="source.html" title="1.7.&nbsp;Python Installation from Source">7</a> <span class="divider">|</span> <a href="shell.html" title="1.8.&nbsp;The Interactive Shell">8</a> <span class="divider">|</span> <span class="thispage">9</span>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="../getting_to_know_python/index.html">Your First Python Program&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/installing_python/windows.html b/help/diveintopython-5.4/html/installing_python/windows.html
new file mode 100644
index 0000000..4718083
--- /dev/null
+++ b/help/diveintopython-5.4/html/installing_python/windows.html
@@ -0,0 +1,154 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>1.2.&nbsp;Python on Windows</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;1.&nbsp;Installing Python">
+ <link rel="previous" href="index.html" title="Chapter&nbsp;1.&nbsp;Installing Python">
+ <link rel="next" href="macosx.html" title="1.3.&nbsp;Python on Mac OS X">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Installing Python</a>&nbsp;&gt;&nbsp;<span class="thispage">Python on Windows</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="index.html" title="Prev: &#8220;Installing Python&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="macosx.html" title="Next: &#8220;Python on Mac OS X&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="install.windows"></a>1.2.&nbsp;<span class="application">Python</span> on Windows
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>On Windows, you have a couple choices for installing <span class="application">Python</span>.
+ </p>
+ </div>
+ <p>ActiveState makes a Windows installer for <span class="application">Python</span> called <span class="application">ActivePython</span>, which includes a complete version of <span class="application">Python</span>, an <span class="acronym">IDE</span> with a <span class="application">Python</span>-aware code editor, plus some Windows extensions for <span class="application">Python</span> that allow complete access to Windows-specific services, <span class="acronym">API</span>s, and the Windows Registry.
+ </p>
+ <p><span class="application">ActivePython</span> is freely downloadable, although it is not open source. It is the <span class="acronym">IDE</span> I used to learn <span class="application">Python</span>, and I recommend you try it unless you have a specific reason not to. One such reason might be that ActiveState is generally
+ several months behind in updating their <span class="application">ActivePython</span> installer when new version of <span class="application">Python</span> are released. If you absolutely need the latest version of <span class="application">Python</span> and <span class="application">ActivePython</span> is still a version behind as you read this, you'll want to use the second option for installing <span class="application">Python</span> on Windows.
+ </p>
+ <p>The second option is the &#8220;<span class="quote">official</span>&#8221; <span class="application">Python</span> installer, distributed by the people who develop <span class="application">Python</span> itself. It is freely downloadable and open source, and it is always current with the latest version of <span class="application">Python</span>.
+ </p>
+ <div class="procedure">
+ <h3 class="title">Procedure&nbsp;1.1.&nbsp;Option 1: Installing <span class="application">ActivePython</span></h3>
+ <p>Here is the procedure for installing <span class="application">ActivePython</span>:
+ </p>
+ <ol type="1">
+ <li>
+ <p>Download <span class="application">ActivePython</span> from <a href="http://www.activestate.com/Products/ActivePython/">http://www.activestate.com/Products/ActivePython/</a>.
+ </p>
+ </li>
+ <li>
+ <p>If you are using Windows 95, Windows 98, or Windows ME, you will also need to download and install <a href="http://download.microsoft.com/download/WindowsInstaller/Install/2.0/W9XMe/EN-US/InstMsiA.exe">Windows Installer 2.0</a> before installing <span class="application">ActivePython</span>.
+ </p>
+ </li>
+ <li>
+ <p>Double-click the installer, <tt class="filename">ActivePython-2.2.2-224-win32-ix86.msi</tt>.
+ </p>
+ </li>
+ <li>
+ <p>Step through the installer program.</p>
+ </li>
+ <li>
+ <p>If space is tight, you can do a custom installation and deselect the documentation, but I don't recommend this unless you
+ absolutely can't spare the 14MB.
+ </p>
+ </li>
+ <li>
+ <p>After the installation is complete, close the installer and choose <span class="guimenu">Start</span>-&gt;<span class="guimenuitem">Programs</span>-&gt;<span class="guimenuitem">ActiveState ActivePython 2.2</span>-&gt;<span class="guimenuitem">PythonWin IDE</span>. You'll see something like the following:
+ </p>
+ </li>
+ </ol>
+ </div>
+ <div class="informalexample"><pre class="screen">
+<span class="computeroutput">PythonWin 2.2.2 (#37, Nov 26 2002, 10:24:37) [MSC 32 bit (Intel)] on win32.
+Portions Copyright 1994-2001 Mark Hammond (mhammond@skippinet.com.au) -
+see 'Help/About PythonWin' for further copyright information.</span>
+<tt class="prompt">&gt;&gt;&gt; </tt>
+</pre></div>
+ <div class="procedure">
+ <h3 class="title">Procedure&nbsp;1.2.&nbsp;Option 2: Installing <span class="application">Python</span> from <a href="http://www.python.org/" title="Python language home page">Python.org</a></h3>
+ <ol type="1">
+ <li>
+ <p>Download the latest <span class="application">Python</span> Windows installer by going to <a href="http://www.python.org/ftp/python/">http://www.python.org/ftp/python/</a> and selecting the highest version number listed, then downloading the <tt class="literal">.exe</tt> installer.
+ </p>
+ </li>
+ <li>
+ <p>Double-click the installer, <tt class="filename">Python-2.xxx.yyy.exe</tt>. The name will depend on the version of <span class="application">Python</span> available when you read this.
+ </p>
+ </li>
+ <li>
+ <p>Step through the installer program.</p>
+ </li>
+ <li>
+ <p>If disk space is tight, you can deselect the HTMLHelp file, the utility scripts (<tt class="filename">Tools/</tt>), and/or the test suite (<tt class="filename">Lib/test/</tt>).
+ </p>
+ </li>
+ <li>
+ <p>If you do not have administrative rights on your machine, you can select <span class="guibutton">Advanced Options</span>, then choose <span class="guilabel">Non-Admin Install</span>. This just affects where Registry entries and Start menu shortcuts are created.
+ </p>
+ </li>
+ <li>
+ <p>After the installation is complete, close the installer and select <span class="guimenu">Start</span>-&gt;<span class="guimenuitem">Programs</span>-&gt;<span class="guimenuitem">Python 2.3</span>-&gt;<span class="guimenuitem">IDLE (Python GUI)</span>. You'll see something like the following:
+ </p>
+ </li>
+ </ol>
+ </div>
+ <div class="informalexample"><pre class="screen">
+<span class="computeroutput">Python 2.3.2 (#49, Oct 2 2003, 20:02:00) [MSC v.1200 32 bit (Intel)] on win32
+Type "copyright", "credits" or "license()" for more information.
+
+ ****************************************************************
+ Personal firewall software may warn about the connection IDLE
+ makes to its subprocess using this computer's internal loopback
+ interface. This connection is not visible on any external
+ interface and no data is sent to or received from the Internet.
+ ****************************************************************
+
+IDLE 1.0</span>
+<tt class="prompt">&gt;&gt;&gt; </tt>
+</pre></div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="index.html">&lt;&lt;&nbsp;Installing Python</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#install.choosing" title="1.1.&nbsp;Which Python is right for you?">1</a> <span class="divider">|</span> <span class="thispage">2</span> <span class="divider">|</span> <a href="macosx.html" title="1.3.&nbsp;Python on Mac OS X">3</a> <span class="divider">|</span> <a href="macos9.html" title="1.4.&nbsp;Python on Mac OS 9">4</a> <span class="divider">|</span> <a href="redhat.html" title="1.5.&nbsp;Python on RedHat Linux">5</a> <span class="divider">|</span> <a href="debian.html" title="1.6.&nbsp;Python on Debian GNU/Linux">6</a> <span class="divider">|</span> <a href="source.html" title="1.7.&nbsp;Python Installation from Source">7</a> <span class="divider">|</span> <a href="shell.html" title="1.8.&nbsp;The Interactive Shell">8</a> <span class="divider">|</span> <a href="summary.html" title="1.9.&nbsp;Summary">9</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="macosx.html">Python on Mac OS X&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/native_data_types/chef.html b/help/diveintopython-5.4/html/native_data_types/chef.html
new file mode 100644
index 0000000..d58b3f6
--- /dev/null
+++ b/help/diveintopython-5.4/html/native_data_types/chef.html
@@ -0,0 +1,506 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>3.2.&nbsp;Introdoocing Leests</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;3.&nbsp;Native Datatypes">
+ <link rel="previous" href="index.html" title="Chapter&nbsp;3.&nbsp;Native Datatypes">
+ <link rel="next" href="tuples.html" title="3.3.&nbsp;Introducing Tuples">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">Yooo ire-a here-a: <a href="../index.html">Home-a</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dife-a Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Netife-a Detetypes</a>&nbsp;&gt;&nbsp;<span class="thispage">Introdoocing Leests</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="index.html" title="Prev: &#8220;Native Datatypes&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="tuples.html" title="Next: &#8220;Introducing Tuples&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dife-a Into Python</a></h1>
+ <p id="tagline">Python from nofice-a to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="odbchelper.list"></a>3.2.&nbsp;Introdoocing Lists
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="toc">
+ <ul>
+ <li><span class="section"><a href="lists.html#d0e5623">3.2.1. Deffining Leests</a></span></li>
+ <li><span class="section"><a href="lists.html#d0e5887">3.2.2. Idding Ilements to Leests</a></span></li>
+ <li><span class="section"><a href="lists.html#d0e6115">3.2.3. Seerching Leests</a></span></li>
+ <li><span class="section"><a href="lists.html#d0e6277">3.2.4. Deleting List Ilements</a></span></li>
+ <li><span class="section"><a href="lists.html#d0e6392">3.2.5. Using List Ooperetors</a></span></li>
+ </ul>
+ </div>
+ <div class="abstract">
+ <p>Lists ire-a <span class="application">Python</span>'s workhorse-a detetype-a. Bork Bork Bork! Iff yooor oonly ixperience-a wit lists is irreys in <span class="application">Fisooel Beseec</span> oor (God forbid) zee-a detestore-a in <span class="application">Powerbooeelder</span>, brece-a yooorselff for <span class="application">Python</span> lists. Bork Bork Bork!
+ </p>
+ </div><a name="compare.list.perl"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">A list in <span class="application">Python</span> is like-a un irrey in <span class="application">Perl</span>. In <span class="application">Perl</span>, feriebles zeet store-a irreys ilweys stert wit zee-a <tt class="literal">@</tt> cherecter; in <span class="application">Python</span>, feriebles coon be-a nemed unything, und <span class="application">Python</span> keeps treck ooff zee-a detetype-a internelly. Bork Bork Bork!
+ </td>
+ </tr>
+ </table><a name="compare.list.java"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">A list in <span class="application">Python</span> is mooch more-a thoon un irrey in <span class="application">Jefa</span> (ilthooogh it coon be-a used is oone-a iff zeet's reelly ill yooo woont oooot ooff liffe-a). A better unelogy wooold be-a to zee-a <tt class="classname">IrreyLeest</tt> cless, which coon hold irbitrery oobjects und coon ixpoond dynemicelly is noo items ire-a idded. Bork Bork Bork!
+ </td>
+ </tr>
+ </table>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e5623"></a>3.2.1.&nbsp;Deffining Lists
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="example"><a name="d0e5626"></a><h3 class="title">Ixemple-a&nbsp;3.6.&nbsp;Deffining a Leest</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li = [<span class="pystring">"a"</span>, <span class="pystring">"b"</span>, <span class="pystring">"mpilgrim"</span>, <span class="pystring">"z"</span>, <span class="pystring">"example"</span>]</span> <a name="odbchelper.list.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'mpilgrim', 'z', 'example']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li[0]</span> <a name="odbchelper.list.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">'a'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li[4]</span> <a name="odbchelper.list.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">'example'</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Foorst, yooo deffine-a a list ooff fife-a ilements. Bork Bork Bork! Note-a zeet zeey retein zeeoor ooriginel oorder. Bork Bork Bork! This is not un iccident. Bork Bork Bork! A list
+ is un oordered set ooff ilements inclosed in sqooere-a breckets. Bork Bork Bork!
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">A list coon be-a used like-a a zero-besed irrey. Bork Bork Bork! Zee-a foorst ilement ooff uny non-impty list is ilweys <tt class="literal">li[0]</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Zee-a lest ilement ooff this fife-a-ilement list is <tt class="literal">li[4]</tt>, becoooose-a lists ire-a ilweys zero-besed. Bork Bork Bork!
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="odbchelper.negative.example"></a><h3 class="title">Ixemple-a&nbsp;3.7.&nbsp;Negetife-a List Indeeces</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'mpilgrim', 'z', 'example']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li[-1]</span> <a name="odbchelper.list.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">'example'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li[-3]</span> <a name="odbchelper.list.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">'mpilgrim'</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">A negetife-a index iccesses ilements from zee-a ind ooff zee-a list cooonting beckwerds. Bork Bork Bork! Zee-a lest ilement ooff uny non-impty list is
+ ilweys <tt class="literal">li[-1]</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Iff zee-a negetife-a index is conffoosing to yooo, think ooff it this wey: <tt class="literal">li[-n] == li[lee-a(li) - n]</tt>. So in this list, <tt class="literal">li[-3] == li[5 - 3] == li[2]</tt>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="odbchelper.list.slice"></a><h3 class="title">Ixemple-a&nbsp;3.8.&nbsp;Slicing a Leest</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'mpilgrim', 'z', 'example']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li[1:3]</span> <a name="odbchelper.list.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">['b', 'mpilgrim']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li[1:-1]</span> <a name="odbchelper.list.3.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">['b', 'mpilgrim', 'z']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li[0:3]</span> <a name="odbchelper.list.3.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">['a', 'b', 'mpilgrim']</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Yooo coon get a soobset ooff a list, celled a &#8220;<span class="quote">slice-a</span>&#8221;, by speciffying two indices. Bork Bork Bork! Zee-a retoorn felooe-a is a noo list conteining ill zee-a ilements ooff zee-a list, in oorder, sterting
+ wit zee-a foorst slice-a index (in this cese-a <tt class="literal">li[1]</tt>), up to boot not inclooding zee-a second slice-a index (in this cese-a <tt class="literal">li[3]</tt>).
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.3.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Slicing works iff oone-a oor bot ooff zee-a slice-a indices is negetife-a. Bork Bork Bork! Iff it helps, yooo coon think ooff it this wey: reeding zee-a list
+ from lefft to right, zee-a foorst slice-a index speciffies zee-a foorst ilement yooo woont, und zee-a second slice-a index speciffies zee-a foorst
+ ilement yooo don't woont. Bork Bork Bork! Zee-a retoorn felooe-a is iferything in betweee-a. Bork Bork Bork!
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.3.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Lists ire-a zero-besed, so <tt class="literal">li[0:3]</tt> retoorns zee-a foorst three-a ilements ooff zee-a list, sterting it <tt class="literal">li[0]</tt>, up to boot not inclooding <tt class="literal">li[3]</tt>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="odbchelper.list.slicing.example"></a><h3 class="title">Ixemple-a&nbsp;3.9.&nbsp;Slicing Shorthoond</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'mpilgrim', 'z', 'example']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li[:3]</span> <a name="odbchelper.list.4.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">['a', 'b', 'mpilgrim']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li[3:]</span> <a name="odbchelper.list.4.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"> <a name="odbchelper.list.4.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">['z', 'example']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li[:]</span> <a name="odbchelper.list.4.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">['a', 'b', 'mpilgrim', 'z', 'example']</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.4.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Iff zee-a lefft slice-a index is 0, yooo coon leefe-a it oooot, und 0 is implied. Bork Bork Bork! So <tt class="literal">li[:3]</tt> is zee-a seme-a is <tt class="literal">li[0:3]</tt> from <a href="lists.html#odbchelper.list.slice" title="Example&nbsp;3.8.&nbsp;Slicing a List">Ixemple-a&nbsp;3.8, &#8220;Slicing a Leest&#8221;</a>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.4.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Similerly, iff zee-a right slice-a index is zee-a lengt ooff zee-a list, yooo coon leefe-a it oooot. Bork Bork Bork! So <tt class="literal">li[3:]</tt> is zee-a seme-a is <tt class="literal">li[3:5]</tt>, becoooose-a this list hes fife-a ilements. Bork Bork Bork!
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.4.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Note-a zee-a symmetry here-a. Bork Bork Bork! In this fife-a-ilement list, <tt class="literal">li[:3]</tt> retoorns zee-a foorst 3 ilements, und <tt class="literal">li[3:]</tt> retoorns zee-a lest two ilements. Bork Bork Bork! In fect, <tt class="literal">li[:n]</tt> will ilweys retoorn zee-a foorst <tt class="literal">n</tt> ilements, und <tt class="literal">li[n:]</tt> will retoorn zee-a rest, regerdless ooff zee-a lengt ooff zee-a list. Bork Bork Bork!
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.4.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Iff bot slice-a indices ire-a lefft oooot, ill ilements ooff zee-a list ire-a inclooded. Bork Bork Bork! Boot this is not zee-a seme-a is zee-a ooriginel <tt class="varname">lee</tt> list; it is a noo list zeet heppens to hefe-a ill zee-a seme-a ilements. Bork Bork Bork! <tt class="literal">li[:]</tt> is shorthoond for meking a complete-a copy ooff a list. Bork Bork Bork!
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e5887"></a>3.2.2.&nbsp;Idding Ilements to Lists
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="example"><a name="d0e5890"></a><h3 class="title">Ixemple-a&nbsp;3.10.&nbsp;Idding Ilements to a Leest</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'mpilgrim', 'z', 'example']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li.append(<span class="pystring">"new"</span>)</span> <a name="odbchelper.list.5.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'mpilgrim', 'z', 'example', 'new']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li.insert(2, <span class="pystring">"new"</span>)</span> <a name="odbchelper.list.5.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li.extend([<span class="pystring">"two"</span>, <span class="pystring">"elements"</span>])</span> <a name="odbchelper.list.5.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new', 'two', 'elements']</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.5.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">eeppend</tt> idds a single-a ilement to zee-a ind ooff zee-a list. Bork Bork Bork!
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.5.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">eensert</tt> inserts a single-a ilement into a list. Bork Bork Bork! Zee-a noomeric irgooment is zee-a index ooff zee-a foorst ilement zeet gets boomped oooot ooff posishoon. Bork Bork Bork!
+ Note-a zeet list ilements do not need to be-a uniqooe-a; zeere-a ire-a now two seperete-a ilements wit zee-a felooe-a <tt class="literal">'noo'</tt>, <tt class="literal">li[2]</tt> und <tt class="literal">li[6]</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.5.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">eextend</tt> concetenetes lists. Bork Bork Bork! Note-a zeet yooo do not cell <tt class="function">eextend</tt> wit mooltiple-a irgooments; yooo cell it wit oone-a irgooment, a list. Bork Bork Bork! In this cese-a, zeet list hes two ilements. Bork Bork Bork!
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="odbchelper.list.append.vs.extend"></a><h3 class="title">Ixemple-a&nbsp;3.11.&nbsp;Zee-a Difffference-a betweee-a <tt class="function">eextend</tt> und <tt class="function">eeppend</tt></h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li = [<span class="pystring">'a'</span>, <span class="pystring">'b'</span>, <span class="pystring">'c'</span>]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li.extend([<span class="pystring">'d'</span>, <span class="pystring">'e'</span>, <span class="pystring">'f'</span>])</span> <a name="odbchelper.list.5.4"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'c', 'd', 'e', 'f']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">len(li)</span> <a name="odbchelper.list.5.5"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">6</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li[-1]</span>
+<span class="computeroutput">'f'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li = [<span class="pystring">'a'</span>, <span class="pystring">'b'</span>, <span class="pystring">'c'</span>]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li.append([<span class="pystring">'d'</span>, <span class="pystring">'e'</span>, <span class="pystring">'f'</span>])</span> <a name="odbchelper.list.5.6"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'c', ['d', 'e', 'f']]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">len(li)</span> <a name="odbchelper.list.5.7"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">4</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li[-1]</span>
+<span class="computeroutput">['d', 'e', 'f']</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.5.4"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Lists hefe-a two methods, <tt class="function">eextend</tt> und <tt class="function">eeppend</tt>, zeet look like-a zeey do zee-a seme-a thing, boot ire-a in fect completely difffferent. Bork Bork Bork! <tt class="function">eextend</tt> tekes a single-a irgooment, which is ilweys a list, und idds iech ooff zee-a ilements ooff zeet list to zee-a ooriginel list. Bork Bork Bork!
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.5.5"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Here-a yooo sterted wit a list ooff three-a ilements (<tt class="literal">'a'</tt>, <tt class="literal">'b'</tt>, und <tt class="literal">'c'</tt>), und yooo ixtended zee-a list wit a list ooff unozeer three-a ilements (<tt class="literal">'d'</tt>, <tt class="literal">'i'</tt>, und <tt class="literal">'f'</tt>), so yooo now hefe-a a list ooff six ilements. Bork Bork Bork!
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.5.6"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Oon zee-a oozeer hoond, <tt class="function">eeppend</tt> tekes oone-a irgooment, which coon be-a uny deta type-a, und simply idds it to zee-a ind ooff zee-a list. Bork Bork Bork! Here-a, yooo're-a celling zee-a <tt class="function">eeppend</tt> method wit a single-a irgooment, which is a list ooff three-a ilements. Bork Bork Bork!
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.5.7"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Now zee-a ooriginel list, which sterted is a list ooff three-a ilements, conteins fooor ilements. Bork Bork Bork! Why fooor? Becoooose-a zee-a lest ilement
+ zeet yooo joost ippended <span class="emphasis"><em>is itselff a leest</em></span>. Lists coon contein uny type-a ooff deta, inclooding oozeer lists. Bork Bork Bork! Zeet mey be-a whet yooo woont, oor meybe-a not. Bork Bork Bork! Don't use-a <tt class="function">eeppend</tt> iff yooo meoon <tt class="function">eextend</tt>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e6115"></a>3.2.3.&nbsp;Seerching Lists
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="example"><a name="odbchelper.list.search"></a><h3 class="title">Ixemple-a&nbsp;3.12.&nbsp;Seerching a Leest</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new', 'two', 'elements']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li.index(<span class="pystring">"example"</span>)</span> <a name="odbchelper.list.6.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">5</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li.index(<span class="pystring">"new"</span>)</span> <a name="odbchelper.list.6.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">2</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li.index(<span class="pystring">"c"</span>)</span> <a name="odbchelper.list.6.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="traceback">Traceback (innermost last):
+ File "&lt;interactive input&gt;", line 1, in ?
+ValueError: list.index(x): x not in list</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class="pystring">"c"</span> <span class="pykeyword">in</span> li</span> <a name="odbchelper.list.6.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">False</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.6.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">eendex</tt> finds zee-a foorst ooccoorrence-a ooff a felooe-a in zee-a list und retoorns zee-a index. Bork Bork Bork!
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.6.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">eendex</tt> finds zee-a <span class="emphasis"><em>foorst</em></span> ooccoorrence-a ooff a felooe-a in zee-a list. Bork Bork Bork! In this cese-a, <tt class="literal">'noo'</tt> ooccoors twice-a in zee-a list, in <tt class="literal">li[2]</tt> und <tt class="literal">li[6]</tt>, boot <tt class="function">eendex</tt> will retoorn oonly zee-a foorst index, <tt class="literal">2</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.6.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Iff zee-a felooe-a is not fooond in zee-a list, <span class="application">Python</span> reises un ixcepshoon. Bork Bork Bork! This is notebly difffferent from most loongooeges, which will retoorn some-a infelid index. Bork Bork Bork! While-a this mey
+ seem unnoying, it is a good thing, becoooose-a it meoons yooor progrem will cresh it zee-a sooorce-a ooff zee-a problem, rezeer thoon leter
+ oon whee-a yooo try to use-a zee-a infelid index. Bork Bork Bork!
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.6.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">To test whezeer a felooe-a is in zee-a list, use-a <tt class="function">een</tt>, which retoorns <tt class="constant">Trooe-a</tt> iff zee-a felooe-a is fooond oor <tt class="constant">Felse-a</tt> iff it is not. Bork Bork Bork!
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div><a name="tip.boolean"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">Beffore-a fersion 2.2.1, <span class="application">Python</span> hed no seperete-a booleoon detetype-a. Bork Bork Bork! To compensete-a for this, <span class="application">Python</span> iccepted ilmost unything in a booleoon context (like-a un <tt class="literal">eeff</tt> stetement), iccording to zee-a following rooles:
+ <div class="itemizedlist">
+ <ul>
+ <li><tt class="constant">0</tt> is felse-a; ill oozeer noombers ire-a trooe-a. Bork Bork Bork!
+ </li>
+ <li>Un impty string (<tt class="literal">""</tt>) is felse-a, ill oozeer strings ire-a trooe-a. Bork Bork Bork!
+ </li>
+ <li>Un impty list (<tt class="literal">[]</tt>) is felse-a; ill oozeer lists ire-a trooe-a. Bork Bork Bork!
+ </li>
+ <li>Un impty toople-a (<tt class="literal">()</tt>) is felse-a; ill oozeer tooples ire-a trooe-a. Bork Bork Bork!
+ </li>
+ <li>Un impty dicshoonery (<tt class="literal">{}</tt>) is felse-a; ill oozeer dicshooneries ire-a trooe-a. Bork Bork Bork!
+ </li>
+ </ul>
+ </div>Zeese-a rooles still ipply in <span class="application">Python</span> 2.2.1 und beyond, boot now yooo coon ilso use-a un ictooel booleoon, which hes a felooe-a ooff <tt class="literal">Trooe-a</tt> oor <tt class="literal">Felse-a</tt>. Note-a zee-a cepitelizeshoon; zeese-a felooes, like-a iferything ilse-a in <span class="application">Python</span>, ire-a cese-a-sensitife-a. Bork Bork Bork!
+ </td>
+ </tr>
+ </table>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e6277"></a>3.2.4.&nbsp;Deleting List Ilements
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="example"><a name="odbchelper.list.removingelements"></a><h3 class="title">Ixemple-a&nbsp;3.13.&nbsp;Remofing Ilements from a Leest</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new', 'two', 'elements']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li.remove(<span class="pystring">"z"</span>)</span> <a name="odbchelper.list.7.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'new', 'mpilgrim', 'example', 'new', 'two', 'elements']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li.remove(<span class="pystring">"new"</span>)</span> <a name="odbchelper.list.7.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'mpilgrim', 'example', 'new', 'two', 'elements']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li.remove(<span class="pystring">"c"</span>)</span> <a name="odbchelper.list.7.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="traceback">Traceback (innermost last):
+ File "&lt;interactive input&gt;", line 1, in ?
+ValueError: list.remove(x): x not in list</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li.pop()</span> <a name="odbchelper.list.7.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">'elements'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'mpilgrim', 'example', 'new', 'two']</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.7.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">remofe-a</tt> remofes zee-a foorst ooccoorrence-a ooff a felooe-a from a list. Bork Bork Bork!
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.7.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">remofe-a</tt> remofes <span class="emphasis"><em>oonly</em></span> zee-a foorst ooccoorrence-a ooff a felooe-a. Bork Bork Bork! In this cese-a, <tt class="literal">'noo'</tt> ippeered twice-a in zee-a list, boot <tt class="literal">li. Bork Bork Bork!remofe-a("noo")</tt> remofed oonly zee-a foorst ooccoorrence-a. Bork Bork Bork!
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.7.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Iff zee-a felooe-a is not fooond in zee-a list, <span class="application">Python</span> reises un ixcepshoon. Bork Bork Bork! This moorrors zee-a behefior ooff zee-a <tt class="function">eendex</tt> method. Bork Bork Bork!
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.7.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">pop</tt> is un interesting beest. Bork Bork Bork! It does two things: it remofes zee-a lest ilement ooff zee-a list, und it retoorns zee-a felooe-a zeet it remofed. Bork Bork Bork!
+ Note-a zeet this is difffferent from <tt class="literal">li[-1]</tt>, which retoorns a felooe-a boot does not choonge-a zee-a list, und difffferent from <tt class="literal">li. Bork Bork Bork!remofe-a(<i class="replaceable">felooe-a</i>)</tt>, which choonges zee-a list boot does not retoorn a felooe-a. Bork Bork Bork!
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e6392"></a>3.2.5.&nbsp;Using List Ooperetors
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="example"><a name="odbchelper.list.operators"></a><h3 class="title">Ixemple-a&nbsp;3.14.&nbsp;List Ooperetors</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li = [<span class="pystring">'a'</span>, <span class="pystring">'b'</span>, <span class="pystring">'mpilgrim'</span>]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li = li + [<span class="pystring">'example'</span>, <span class="pystring">'new'</span>]</span> <a name="odbchelper.list.8.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'mpilgrim', 'example', 'new']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li += [<span class="pystring">'two'</span>]</span> <a name="odbchelper.list.8.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'mpilgrim', 'example', 'new', 'two']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li = [1, 2] * 3</span> <a name="odbchelper.list.8.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">[1, 2, 1, 2, 1, 2]</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.8.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Lists coon ilso be-a conceteneted wit zee-a <tt class="literal">+</tt> ooperetor. Bork Bork Bork! <tt class="literal"><i class="replaceable">leest</i> = <i class="replaceable">leest</i> + <i class="replaceable">oozeerleest</i></tt> hes zee-a seme-a resoolt is <tt class="literal"><i class="replaceable">leest</i>.ixtend(<i class="replaceable">oozeerleest</i>)</tt>. Boot zee-a <tt class="literal">+</tt> ooperetor retoorns a noo (conceteneted) list is a felooe-a, wherees <tt class="function">eextend</tt> oonly ilters un ixisting list. Bork Bork Bork! This meoons zeet <tt class="function">eextend</tt> is fester, ispecielly for lerge-a lists. Bork Bork Bork!
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.8.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><span class="application">Python</span> soopports zee-a <tt class="literal">+=</tt> ooperetor. Bork Bork Bork! <tt class="literal">li += ['two']</tt> is iqooifelent to <tt class="literal">li. Bork Bork Bork!ixtend(['two'])</tt>. Zee-a <tt class="literal">+=</tt> ooperetor works for lists, strings, und integers, und it coon be-a ooferloeded to work for user-deffined clesses is well. Bork Bork Bork! (More-a
+ oon clesses in <a href="../object_oriented_framework/index.html">Chepter 5</a>.)
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.8.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Zee-a <tt class="literal">*</tt> ooperetor works oon lists is a repeeter. Bork Bork Bork! <tt class="literal">li = [1, 2] * 3</tt> is iqooifelent to <tt class="literal">li = [1, 2] + [1, 2] + [1, 2]</tt>, which concetenetes zee-a three-a lists into oone-a. Bork Bork Bork!
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="furtherreading">
+ <h3>Foorzeer Reeding oon Leests</h3>
+ <ul>
+ <li><a href="http://www.ibiblio.org/obp/thinkCSpy/" title="Python book for computer science majors"><i class="citetitle">How to Think Like-a a Compooter Sceeentist</i></a> teeches ibooot lists und mekes un importoont point ibooot <a href="http://www.ibiblio.org/obp/thinkCSpy/chap08.htm">pessing lists is fooncshoon eergooments</a>.
+ </li>
+ <li><a href="http://www.python.org/doc/current/tut/tut.html"><i class="citetitle"><span class="application">Python</span> Tootoreeel</i></a> shows how to <a href="http://www.python.org/doc/current/tut/node7.html#SECTION007110000000000000000">use-a lists is stecks und qooeooes</a>.
+ </li>
+ <li><a href="http://www.faqts.com/knowledge-base/index.phtml/fid/199/"><span class="application">Python</span> Knowledge-a Bese-a</a> unswers <a href="http://www.faqts.com/knowledge-base/index.phtml/fid/534">common qooesshoons ibooot leests</a> und hes a lot ooff <a href="http://www.faqts.com/knowledge-base/index.phtml/fid/540">ixemple-a code-a using leests</a>.
+ </li>
+ <li><a href="http://www.python.org/doc/current/lib/"><i class="citetitle"><span class="application">Python</span> Librery Refference-a</i></a> soommerizes <a href="http://www.python.org/doc/current/lib/typesseq-mutable.html">ill zee-a list methods</a>.
+ </li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="index.html">&lt;&lt;&nbsp;Netife-a Detetypes</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#odbchelper.dict" title="3.1.&nbsp;Introducing Dictionaries">1</a> <span class="divider">|</span> <span class="thispage">2</span> <span class="divider">|</span> <a href="tuples.html" title="3.3.&nbsp;Introducing Tuples">3</a> <span class="divider">|</span> <a href="declaring_variables.html" title="3.4.&nbsp;Declaring variables">4</a> <span class="divider">|</span> <a href="formatting_strings.html" title="3.5.&nbsp;Formatting Strings">5</a> <span class="divider">|</span> <a href="mapping_lists.html" title="3.6.&nbsp;Mapping Lists">6</a> <span class="divider">|</span> <a href="joining_lists.html" title="3.7.&nbsp;Joining Lists and Splitting Strings">7</a> <span class="divider">|</span> <a href="summary.html" title="3.8.&nbsp;Summary">8</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="tuples.html">Introdoocing Tooples&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Merk Peelgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/native_data_types/declaring_variables.html b/help/diveintopython-5.4/html/native_data_types/declaring_variables.html
new file mode 100644
index 0000000..491443c
--- /dev/null
+++ b/help/diveintopython-5.4/html/native_data_types/declaring_variables.html
@@ -0,0 +1,200 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>3.4.&nbsp;Declaring variables</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;3.&nbsp;Native Datatypes">
+ <link rel="previous" href="tuples.html" title="3.3.&nbsp;Introducing Tuples">
+ <link rel="next" href="formatting_strings.html" title="3.5.&nbsp;Formatting Strings">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Native Datatypes</a>&nbsp;&gt;&nbsp;<span class="thispage">Declaring variables</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="tuples.html" title="Prev: &#8220;Introducing Tuples&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="formatting_strings.html" title="Next: &#8220;Formatting Strings&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="odbchelper.vardef"></a>3.4.&nbsp;Declaring variables
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="toc">
+ <ul>
+ <li><span class="section"><a href="declaring_variables.html#d0e6873">3.4.1. Referencing Variables</a></span></li>
+ <li><span class="section"><a href="declaring_variables.html#odbchelper.multiassign">3.4.2. Assigning Multiple Values at Once</a></span></li>
+ </ul>
+ </div>
+ <p>Now that you know something about dictionaries, tuples, and lists (oh my!), let's get back to the sample program from <a href="../getting_to_know_python/index.html">Chapter 2</a>, <tt class="filename">odbchelper.py</tt>.
+ </p>
+ <div class="abstract">
+ <p><span class="application">Python</span> has local and global variables like most other languages, but it has no explicit variable declarations. Variables spring
+ into existence by being assigned a value, and they are automatically destroyed when they go out of scope.
+ </p>
+ </div>
+ <div class="example"><a name="myparamsdef"></a><h3 class="title">Example&nbsp;3.17.&nbsp;Defining the <tt class="varname">myParams</tt> Variable
+ </h3><pre class="programlisting"><span class='pykeyword'>
+if</span> __name__ == <span class='pystring'>"__main__"</span>:
+ myParams = {<span class='pystring'>"server"</span>:<span class='pystring'>"mpilgrim"</span>, \
+ <span class='pystring'>"database"</span>:<span class='pystring'>"master"</span>, \
+ <span class='pystring'>"uid"</span>:<span class='pystring'>"sa"</span>, \
+ <span class='pystring'>"pwd"</span>:<span class='pystring'>"secret"</span> \
+ }</pre></div>
+ <p>Notice the indentation. An <tt class="literal">if</tt> statement is a code block and needs to be indented just like a function.
+ </p>
+ <p>Also notice that the variable assignment is one command split over several lines, with a backslash (&#8220;<span class="quote"><tt class="literal">\</tt></span>&#8221;) serving as a line-continuation marker.
+ </p><a name="tip.multiline"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">When a command is split among several lines with the line-continuation marker (&#8220;<span class="quote"><tt class="literal">\</tt></span>&#8221;), the continued lines can be indented in any manner; <span class="application">Python</span>'s normally stringent indentation rules do not apply. If your <span class="application">Python</span> <span class="acronym">IDE</span> auto-indents the continued line, you should probably accept its default unless you have a burning reason not to.
+ </td>
+ </tr>
+ </table>
+ <p><a name="tip.implicitmultiline"></a>Strictly speaking, expressions in parentheses, straight brackets, or curly braces (like <a href="declaring_variables.html#myparamsdef" title="Example&nbsp;3.17.&nbsp;Defining the myParams Variable">defining a dictionary</a>) can be split into multiple lines with or without the line continuation character (&#8220;<span class="quote"><tt class="literal">\</tt></span>&#8221;). I like to include the backslash even when it's not required because I think it makes the code easier to read, but that's
+ a matter of style.
+ </p>
+ <p>Third, you never declared the variable <tt class="varname">myParams</tt>, you just assigned a value to it. This is like <span class="application">VBScript</span> without the <tt class="option">option explicit</tt> option. Luckily, unlike <span class="application">VBScript</span>, <span class="application">Python</span> will not allow you to reference a variable that has never been assigned a value; trying to do so will raise an exception.
+ </p>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e6873"></a>3.4.1.&nbsp;Referencing Variables
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="example"><a name="odbchelper.unboundvariable"></a><h3 class="title">Example&nbsp;3.18.&nbsp;Referencing an Unbound Variable</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">x</span>
+<span class="traceback">Traceback (innermost last):
+ File "&lt;interactive input&gt;", line 1, in ?
+NameError: There is no variable named 'x'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">x = 1</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">x</span>
+<span class="computeroutput">1</span></pre></div>
+ <p>You will thank <span class="application">Python</span> for this one day.
+ </p>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="odbchelper.multiassign"></a>3.4.2.&nbsp;Assigning Multiple Values at Once
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p>One of the cooler programming shortcuts in <span class="application">Python</span> is using sequences to assign multiple values at once.
+ </p>
+ <div class="example"><a name="d0e6913"></a><h3 class="title">Example&nbsp;3.19.&nbsp;Assigning multiple values at once</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">v = (<span class='pystring'>'a'</span>, <span class='pystring'>'b'</span>, <span class='pystring'>'e'</span>)</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">(x, y, z) = v</span> <a name="odbchelper.multiassign.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">x</span>
+<span class="computeroutput">'a'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">y</span>
+<span class="computeroutput">'b'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">z</span>
+<span class="computeroutput">'e'</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.multiassign.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="varname">v</tt> is a tuple of three elements, and <tt class="literal">(x, y, z)</tt> is a tuple of three variables. Assigning one to the other assigns each of the values of <tt class="varname">v</tt> to each of the variables, in order.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>This has all sorts of uses. I often want to assign names to a range of values. In <span class="application"><span class="acronym">C</span></span>, you would use <tt class="literal">enum</tt> and manually list each constant and its associated value, which seems especially tedious when the values are consecutive.
+ In <span class="application">Python</span>, you can use the built-in <tt class="function">range</tt> function with multi-variable assignment to quickly assign consecutive values.
+ </p>
+ <div class="example"><a name="odbchelper.multiassign.range"></a><h3 class="title">Example&nbsp;3.20.&nbsp;Assigning Consecutive Values</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">range(7)</span> <a name="odbchelper.multiassign.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">[0, 1, 2, 3, 4, 5, 6]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">(MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY) = range(7)</span> <a name="odbchelper.multiassign.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">MONDAY</span> <a name="odbchelper.multiassign.2.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">0</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">TUESDAY</span>
+<span class="computeroutput">1</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">SUNDAY</span>
+<span class="computeroutput">6</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.multiassign.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The built-in <tt class="function">range</tt> function returns a list of integers. In its simplest form, it takes an upper limit and returns a zero-based list counting
+ up to but not including the upper limit. (If you like, you can pass other parameters to specify a base other than <tt class="constant">0</tt> and a step other than <tt class="constant">1</tt>. You can <tt class="literal">print range.__doc__</tt> for details.)
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.multiassign.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="varname">MONDAY</tt>, <tt class="varname">TUESDAY</tt>, <tt class="varname">WEDNESDAY</tt>, <tt class="varname">THURSDAY</tt>, <tt class="varname">FRIDAY</tt>, <tt class="varname">SATURDAY</tt>, and <tt class="varname">SUNDAY</tt> are the variables you're defining. (This example came from the <tt class="filename">calendar</tt> module, a fun little module that prints calendars, like the <span class="acronym">UNIX</span> program <tt class="filename">cal</tt>. The <tt class="filename">calendar</tt> module defines integer constants for days of the week.)
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.multiassign.2.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Now each variable has its value: <tt class="varname">MONDAY</tt> is <tt class="constant">0</tt>, <tt class="varname">TUESDAY</tt> is <tt class="constant">1</tt>, and so forth.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>You can also use multi-variable assignment to build functions that return multiple values, simply by returning a tuple of
+ all the values. The caller can treat it as a tuple, or assign the values to individual variables. Many standard <span class="application">Python</span> libraries do this, including the <tt class="filename">os</tt> module, which you'll discuss in <a href="../file_handling/index.html">Chapter 6</a>.
+ </p>
+ <div class="furtherreading">
+ <h3>Further Reading on Variables</h3>
+ <ul>
+ <li><a href="http://www.python.org/doc/current/ref/"><i class="citetitle"><span class="application">Python</span> Reference Manual</i></a> shows examples of <a href="http://www.python.org/doc/current/ref/implicit-joining.html">when you can skip the line continuation character</a> and <a href="http://www.python.org/doc/current/ref/explicit-joining.html">when you need to use it</a>.
+ </li>
+ <li><a href="http://www.ibiblio.org/obp/thinkCSpy/" title="Python book for computer science majors"><i class="citetitle">How to Think Like a Computer Scientist</i></a> shows how to use multi-variable assignment to <a href="http://www.ibiblio.org/obp/thinkCSpy/chap09.htm">swap the values of two variables</a>.
+ </li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="tuples.html">&lt;&lt;&nbsp;Introducing Tuples</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#odbchelper.dict" title="3.1.&nbsp;Introducing Dictionaries">1</a> <span class="divider">|</span> <a href="lists.html" title="3.2.&nbsp;Introducing Lists">2</a> <span class="divider">|</span> <a href="tuples.html" title="3.3.&nbsp;Introducing Tuples">3</a> <span class="divider">|</span> <span class="thispage">4</span> <span class="divider">|</span> <a href="formatting_strings.html" title="3.5.&nbsp;Formatting Strings">5</a> <span class="divider">|</span> <a href="mapping_lists.html" title="3.6.&nbsp;Mapping Lists">6</a> <span class="divider">|</span> <a href="joining_lists.html" title="3.7.&nbsp;Joining Lists and Splitting Strings">7</a> <span class="divider">|</span> <a href="summary.html" title="3.8.&nbsp;Summary">8</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="formatting_strings.html">Formatting Strings&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/native_data_types/formatting_strings.html b/help/diveintopython-5.4/html/native_data_types/formatting_strings.html
new file mode 100644
index 0000000..74e30d4
--- /dev/null
+++ b/help/diveintopython-5.4/html/native_data_types/formatting_strings.html
@@ -0,0 +1,187 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>3.5.&nbsp;Formatting Strings</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;3.&nbsp;Native Datatypes">
+ <link rel="previous" href="declaring_variables.html" title="3.4.&nbsp;Declaring variables">
+ <link rel="next" href="mapping_lists.html" title="3.6.&nbsp;Mapping Lists">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Native Datatypes</a>&nbsp;&gt;&nbsp;<span class="thispage">Formatting Strings</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="declaring_variables.html" title="Prev: &#8220;Declaring variables&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="mapping_lists.html" title="Next: &#8220;Mapping Lists&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="odbchelper.stringformatting"></a>3.5.&nbsp;Formatting Strings
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p><span class="application">Python</span> supports formatting values into strings. Although this can include very complicated expressions, the most basic usage is
+ to insert values into a string with the <tt class="literal">%s</tt> placeholder.
+ </p>
+ </div><a name="compare.stringformatting.c"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">String formatting in <span class="application">Python</span> uses the same syntax as the <tt class="function">sprintf</tt> function in <span class="application"><span class="acronym">C</span></span>.
+ </td>
+ </tr>
+ </table>
+ <div class="example"><a name="d0e7165"></a><h3 class="title">Example&nbsp;3.21.&nbsp;Introducing String Formatting</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">k = <span class='pystring'>"uid"</span></span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">v = <span class='pystring'>"sa"</span></span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pystring'>"%s=%s"</span> % (k, v)</span> <a name="odbchelper.stringformatting.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">'uid=sa'</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.stringformatting.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The whole expression evaluates to a string. The first <tt class="literal">%s</tt> is replaced by the value of <tt class="varname">k</tt>; the second <tt class="literal">%s</tt> is replaced by the value of <tt class="varname">v</tt>. All other characters in the string (in this case, the equal sign) stay as they are.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>Note that <tt class="literal">(k, v)</tt> is a tuple. I told you they were good for something.
+ </p>
+ <p>You might be thinking that this is a lot of work just to do simple string concatentation, and you would be right, except that
+ string formatting isn't just concatenation. It's not even just formatting. It's also type coercion.
+ </p>
+ <div class="example"><a name="odbchelper.stringformatting.coerce"></a><h3 class="title">Example&nbsp;3.22.&nbsp;String Formatting vs. Concatenating</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">uid = <span class='pystring'>"sa"</span></span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">pwd = <span class='pystring'>"secret"</span></span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> pwd + <span class='pystring'>" is not a good password for "</span> + uid</span> <a name="odbchelper.stringformatting.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">secret is not a good password for sa</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> <span class='pystring'>"%s is not a good password for %s"</span> % (pwd, uid)</span> <a name="odbchelper.stringformatting.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">secret is not a good password for sa</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">userCount = 6</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> <span class='pystring'>"Users connected: %d"</span> % (userCount, )</span> <a name="odbchelper.stringformatting.2.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"> <a name="odbchelper.stringformatting.2.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">Users connected: 6</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> <span class='pystring'>"Users connected: "</span> + userCount</span> <a name="odbchelper.stringformatting.2.5"></a><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12">
+<span class="traceback">Traceback (innermost last):
+ File "&lt;interactive input&gt;", line 1, in ?
+TypeError: cannot concatenate 'str' and 'int' objects</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.stringformatting.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="literal">+</tt> is the string concatenation operator.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.stringformatting.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">In this trivial case, string formatting accomplishes the same result as concatentation.</td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.stringformatting.2.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="literal">(userCount, )</tt> is a tuple with one element. Yes, the syntax is a little strange, but there's a good reason for it: it's unambiguously a
+ tuple. In fact, you can always include a comma after the last element when defining a list, tuple, or dictionary, but the
+ comma is required when defining a tuple with one element. If the comma weren't required, <span class="application">Python</span> wouldn't know whether <tt class="literal">(userCount)</tt> was a tuple with one element or just the value of <tt class="varname">userCount</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.stringformatting.2.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">String formatting works with integers by specifying <tt class="literal">%d</tt> instead of <tt class="literal">%s</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.stringformatting.2.5"><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Trying to concatenate a string with a non-string raises an exception. Unlike string formatting, string concatenation works
+ only when everything is already a string.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>As with <tt class="function">printf</tt> in <span class="application"><span class="acronym">C</span></span>, string formatting in <span class="application">Python</span> is like a Swiss Army knife. There are options galore, and modifier strings to specially format many different types of values.
+ </p>
+ <div class="example"><a name="odbchelper.stringformatting.numbers"></a><h3 class="title">Example&nbsp;3.23.&nbsp;Formatting Numbers</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> <span class='pystring'>"Today's stock price: %f"</span> % 50.4625</span> <a name="odbchelper.stringformatting.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">50.462500</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> <span class='pystring'>"Today's stock price: %.2f"</span> % 50.4625</span> <a name="odbchelper.stringformatting.3.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">50.46</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> <span class='pystring'>"Change since yesterday: %+.2f"</span> % 1.5</span> <a name="odbchelper.stringformatting.3.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">+1.50</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.stringformatting.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="literal">%f</tt> string formatting option treats the value as a decimal, and prints it to six decimal places.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.stringformatting.3.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The ".2" modifier of the <tt class="literal">%f</tt> option truncates the value to two decimal places.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.stringformatting.3.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You can even combine modifiers. Adding the <tt class="literal">+</tt> modifier displays a plus or minus sign before the value. Note that the ".2" modifier is still in place, and is padding
+ the value to exactly two decimal places.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="furtherreading">
+ <h3>Further Reading on String Formatting</h3>
+ <ul>
+ <li><a href="http://www.python.org/doc/current/lib/"><i class="citetitle"><span class="application">Python</span> Library Reference</i></a> summarizes <a href="http://www.python.org/doc/current/lib/typesseq-strings.html">all the string formatting format characters</a>.
+ </li>
+ <li><a href="http://www-gnats.gnu.org:8080/cgi-bin/info2www?(gawk)Top"><i class="citetitle">Effective <span class="acronym">AWK</span> Programming</i></a> discusses <a href="http://www-gnats.gnu.org:8080/cgi-bin/info2www?(gawk)Control+Letters">all the format characters</a> and advanced string formatting techniques like <a href="http://www-gnats.gnu.org:8080/cgi-bin/info2www?(gawk)Format+Modifiers">specifying width, precision, and zero-padding</a>.
+ </li>
+ </ul>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="declaring_variables.html">&lt;&lt;&nbsp;Declaring variables</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#odbchelper.dict" title="3.1.&nbsp;Introducing Dictionaries">1</a> <span class="divider">|</span> <a href="lists.html" title="3.2.&nbsp;Introducing Lists">2</a> <span class="divider">|</span> <a href="tuples.html" title="3.3.&nbsp;Introducing Tuples">3</a> <span class="divider">|</span> <a href="declaring_variables.html" title="3.4.&nbsp;Declaring variables">4</a> <span class="divider">|</span> <span class="thispage">5</span> <span class="divider">|</span> <a href="mapping_lists.html" title="3.6.&nbsp;Mapping Lists">6</a> <span class="divider">|</span> <a href="joining_lists.html" title="3.7.&nbsp;Joining Lists and Splitting Strings">7</a> <span class="divider">|</span> <a href="summary.html" title="3.8.&nbsp;Summary">8</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="mapping_lists.html">Mapping Lists&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/native_data_types/fudd.html b/help/diveintopython-5.4/html/native_data_types/fudd.html
new file mode 100644
index 0000000..39003c9
--- /dev/null
+++ b/help/diveintopython-5.4/html/native_data_types/fudd.html
@@ -0,0 +1,506 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>3.2.&nbsp;Intwoducing Lists</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;3.&nbsp;Native Datatypes">
+ <link rel="previous" href="index.html" title="Chapter&nbsp;3.&nbsp;Native Datatypes">
+ <link rel="next" href="tuples.html" title="3.3.&nbsp;Introducing Tuples">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You awe hewe: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Pydon</a>&nbsp;&gt;&nbsp;<a href="index.html">Native Datatypes</a>&nbsp;&gt;&nbsp;<span class="thispage">Intwoducing Lists</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="index.html" title="Prev: &#8220;Native Datatypes&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="tuples.html" title="Next: &#8220;Introducing Tuples&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Pydon</a></h1>
+ <p id="tagline">Pydon fwom novice to pwo</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="odbchelper.list"></a>3.2.&nbsp;Intwoducing Lists
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="toc">
+ <ul>
+ <li><span class="section"><a href="lists.html#d0e5623">3.2.1. Defining Lists</a></span></li>
+ <li><span class="section"><a href="lists.html#d0e5887">3.2.2. Adding Ewements to Lists</a></span></li>
+ <li><span class="section"><a href="lists.html#d0e6115">3.2.3. Seawching Lists</a></span></li>
+ <li><span class="section"><a href="lists.html#d0e6277">3.2.4. Deweting List Ewements</a></span></li>
+ <li><span class="section"><a href="lists.html#d0e6392">3.2.5. Using List Opewatows</a></span></li>
+ </ul>
+ </div>
+ <div class="abstract">
+ <p>Lists awe <span class="application">Pydon</span>'s wowkhowse datatype. If youw onwy expewience wif wists is awways in <span class="application">Visuaw Basic</span> ow (God fowbid) de datastowe in <span class="application">Powewbuiwdew</span>, bwace youwsewf fow <span class="application">Pydon</span> wists.
+ </p>
+ </div><a name="compare.list.perl"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">A wist in <span class="application">Pydon</span> is wike an awway in <span class="application">Peww</span>. In <span class="application">Peww</span>, vawiabwes dat stowe awways awways stawt wif de <tt class="literal">@</tt> chawactew; in <span class="application">Pydon</span>, vawiabwes can be named anyding, and <span class="application">Pydon</span> keeps twack of de datatype intewnawwy.
+ </td>
+ </tr>
+ </table><a name="compare.list.java"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">A wist in <span class="application">Pydon</span> is much mowe dan an awway in <span class="application">Java</span> (awdough it can be used as one if dat's weawwy aww you want out of wife). A bettew anawogy wouwd be to de <tt class="classname">AwwayList</tt> cwass, which can howd awbitwawy objects and can expand dynamicawwy as new items awe added.
+ </td>
+ </tr>
+ </table>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e5623"></a>3.2.1.&nbsp;Defining Lists
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="example"><a name="d0e5626"></a><h3 class="title">Exampwe&nbsp;3.6.&nbsp;Defining a List</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li = [<span class="pystring">"a"</span>, <span class="pystring">"b"</span>, <span class="pystring">"mpilgrim"</span>, <span class="pystring">"z"</span>, <span class="pystring">"example"</span>]</span> <a name="odbchelper.list.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'mpilgrim', 'z', 'example']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li[0]</span> <a name="odbchelper.list.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">'a'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li[4]</span> <a name="odbchelper.list.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">'example'</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Fiwst, you define a wist of five ewements. Note dat dey wetain deiw owiginaw owdew. This is not an accident. A wist
+ is an owdewed set of ewements encwosed in sqwawe bwackets.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">A wist can be used wike a zewo-based awway. The fiwst ewement of any non-empty wist is awways <tt class="literal">wi[0]</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The wast ewement of dis five-ewement wist is <tt class="literal">wi[4]</tt>, because wists awe awways zewo-based.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="odbchelper.negative.example"></a><h3 class="title">Exampwe&nbsp;3.7.&nbsp;Negative List Indices</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'mpilgrim', 'z', 'example']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li[-1]</span> <a name="odbchelper.list.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">'example'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li[-3]</span> <a name="odbchelper.list.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">'mpilgrim'</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">A negative index accesses ewements fwom de end of de wist counting backwawds. The wast ewement of any non-empty wist is
+ awways <tt class="literal">wi[-1]</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">If de negative index is confusing to you, dink of it dis way: <tt class="literal">wi[-n] == wi[wen(wi) - n]</tt>. So in dis wist, <tt class="literal">wi[-3] == wi[5 - 3] == wi[2]</tt>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="odbchelper.list.slice"></a><h3 class="title">Exampwe&nbsp;3.8.&nbsp;Swicing a List</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'mpilgrim', 'z', 'example']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li[1:3]</span> <a name="odbchelper.list.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">['b', 'mpilgrim']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li[1:-1]</span> <a name="odbchelper.list.3.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">['b', 'mpilgrim', 'z']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li[0:3]</span> <a name="odbchelper.list.3.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">['a', 'b', 'mpilgrim']</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You can get a subset of a wist, cawwed a &#8220;<span class="quote">swice</span>&#8221;, by specifying two indices. The wetuwn vawue is a new wist containing aww de ewements of de wist, in owdew, stawting
+ wif de fiwst swice index (in dis case <tt class="literal">wi[1]</tt>), up to but not incwuding de second swice index (in dis case <tt class="literal">wi[3]</tt>).
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.3.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Swicing wowks if one ow bof of de swice indices is negative. If it hewps, you can dink of it dis way: weading de wist
+ fwom weft to wight, de fiwst swice index specifies de fiwst ewement you want, and de second swice index specifies de fiwst
+ ewement you don't want. The wetuwn vawue is evewyding in between, uh-hah-hah-hah.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.3.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Lists awe zewo-based, so <tt class="literal">wi[0:3]</tt> wetuwns de fiwst dwee ewements of de wist, stawting at <tt class="literal">wi[0]</tt>, up to but not incwuding <tt class="literal">wi[3]</tt>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="odbchelper.list.slicing.example"></a><h3 class="title">Exampwe&nbsp;3.9.&nbsp;Swicing Showdand</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'mpilgrim', 'z', 'example']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li[:3]</span> <a name="odbchelper.list.4.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">['a', 'b', 'mpilgrim']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li[3:]</span> <a name="odbchelper.list.4.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"> <a name="odbchelper.list.4.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">['z', 'example']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li[:]</span> <a name="odbchelper.list.4.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">['a', 'b', 'mpilgrim', 'z', 'example']</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.4.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">If de weft swice index is 0, you can weave it out, and 0 is impwied. So <tt class="literal">wi[:3]</tt> is de same as <tt class="literal">wi[0:3]</tt> fwom <a href="lists.html#odbchelper.list.slice" title="Example&nbsp;3.8.&nbsp;Slicing a List">Exampwe&nbsp;3.8, &#8220;Swicing a List&#8221;</a>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.4.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Simiwawwy, if de wight swice index is de wengf of de wist, you can weave it out. So <tt class="literal">wi[3:]</tt> is de same as <tt class="literal">wi[3:5]</tt>, because dis wist has five ewements.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.4.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Note de symmetwy hewe. In dis five-ewement wist, <tt class="literal">wi[:3]</tt> wetuwns de fiwst 3 ewements, and <tt class="literal">wi[3:]</tt> wetuwns de wast two ewements. In fact, <tt class="literal">wi[:n]</tt> wiww awways wetuwn de fiwst <tt class="literal">n</tt> ewements, and <tt class="literal">wi[n:]</tt> wiww wetuwn de west, wegawdwess of de wengf of de wist.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.4.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">If bof swice indices awe weft out, aww ewements of de wist awe incwuded. But dis is not de same as de owiginaw <tt class="varname">wi</tt> wist; it is a new wist dat happens to have aww de same ewements. <tt class="literal">wi[:]</tt> is showdand fow making a compwete copy of a wist.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e5887"></a>3.2.2.&nbsp;Adding Ewements to Lists
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="example"><a name="d0e5890"></a><h3 class="title">Exampwe&nbsp;3.10.&nbsp;Adding Ewements to a List</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'mpilgrim', 'z', 'example']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li.append(<span class="pystring">"new"</span>)</span> <a name="odbchelper.list.5.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'mpilgrim', 'z', 'example', 'new']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li.insert(2, <span class="pystring">"new"</span>)</span> <a name="odbchelper.list.5.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li.extend([<span class="pystring">"two"</span>, <span class="pystring">"elements"</span>])</span> <a name="odbchelper.list.5.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new', 'two', 'elements']</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.5.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">append</tt> adds a singwe ewement to de end of de wist.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.5.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">insewt</tt> insewts a singwe ewement into a wist. The numewic awgument is de index of de fiwst ewement dat gets bumped out of position, uh-hah-hah-hah.
+ Note dat wist ewements do not need to be uniqwe; dewe awe now two sepawate ewements wif de vawue <tt class="literal">'new'</tt>, <tt class="literal">wi[2]</tt> and <tt class="literal">wi[6]</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.5.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">extend</tt> concatenates wists. Note dat you do not caww <tt class="function">extend</tt> wif muwtipwe awguments; you caww it wif one awgument, a wist. In dis case, dat wist has two ewements.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="odbchelper.list.append.vs.extend"></a><h3 class="title">Exampwe&nbsp;3.11.&nbsp;The Diffewence between <tt class="function">extend</tt> and <tt class="function">append</tt></h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li = [<span class="pystring">'a'</span>, <span class="pystring">'b'</span>, <span class="pystring">'c'</span>]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li.extend([<span class="pystring">'d'</span>, <span class="pystring">'e'</span>, <span class="pystring">'f'</span>])</span> <a name="odbchelper.list.5.4"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'c', 'd', 'e', 'f']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">len(li)</span> <a name="odbchelper.list.5.5"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">6</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li[-1]</span>
+<span class="computeroutput">'f'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li = [<span class="pystring">'a'</span>, <span class="pystring">'b'</span>, <span class="pystring">'c'</span>]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li.append([<span class="pystring">'d'</span>, <span class="pystring">'e'</span>, <span class="pystring">'f'</span>])</span> <a name="odbchelper.list.5.6"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'c', ['d', 'e', 'f']]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">len(li)</span> <a name="odbchelper.list.5.7"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">4</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li[-1]</span>
+<span class="computeroutput">['d', 'e', 'f']</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.5.4"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Lists have two medods, <tt class="function">extend</tt> and <tt class="function">append</tt>, dat wook wike dey do de same ding, but awe in fact compwetewy diffewent. <tt class="function">extend</tt> takes a singwe awgument, which is awways a wist, and adds each of de ewements of dat wist to de owiginaw wist.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.5.5"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Hewe you stawted wif a wist of dwee ewements (<tt class="literal">'a'</tt>, <tt class="literal">'b'</tt>, and <tt class="literal">'c'</tt>), and you extended de wist wif a wist of anodew dwee ewements (<tt class="literal">'d'</tt>, <tt class="literal">'e'</tt>, and <tt class="literal">'f'</tt>), so you now have a wist of six ewements.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.5.6"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">On de odew hand, <tt class="function">append</tt> takes one awgument, which can be any data type, and simpwy adds it to de end of de wist. Hewe, you'we cawwing de <tt class="function">append</tt> medod wif a singwe awgument, which is a wist of dwee ewements.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.5.7"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Now de owiginaw wist, which stawted as a wist of dwee ewements, contains fouw ewements. Why fouw? Because de wast ewement
+ dat you just appended <span class="emphasis"><em>is itsewf a wist</em></span>. Lists can contain any type of data, incwuding odew wists. That may be what you want, ow maybe not. Don't use <tt class="function">append</tt> if you mean <tt class="function">extend</tt>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e6115"></a>3.2.3.&nbsp;Seawching Lists
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="example"><a name="odbchelper.list.search"></a><h3 class="title">Exampwe&nbsp;3.12.&nbsp;Seawching a List</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new', 'two', 'elements']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li.index(<span class="pystring">"example"</span>)</span> <a name="odbchelper.list.6.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">5</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li.index(<span class="pystring">"new"</span>)</span> <a name="odbchelper.list.6.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">2</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li.index(<span class="pystring">"c"</span>)</span> <a name="odbchelper.list.6.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="traceback">Traceback (innermost last):
+ File "&lt;interactive input&gt;", line 1, in ?
+ValueError: list.index(x): x not in list</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class="pystring">"c"</span> <span class="pykeyword">in</span> li</span> <a name="odbchelper.list.6.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">False</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.6.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">index</tt> finds de fiwst occuwwence of a vawue in de wist and wetuwns de index.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.6.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">index</tt> finds de <span class="emphasis"><em>fiwst</em></span> occuwwence of a vawue in de wist. In dis case, <tt class="literal">'new'</tt> occuws twice in de wist, in <tt class="literal">wi[2]</tt> and <tt class="literal">wi[6]</tt>, but <tt class="function">index</tt> wiww wetuwn onwy de fiwst index, <tt class="literal">2</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.6.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">If de vawue is not found in de wist, <span class="application">Pydon</span> waises an exception, uh-hah-hah-hah. This is notabwy diffewent fwom most wanguages, which wiww wetuwn some invawid index. Whiwe dis may
+ seem annoying, it is a good ding, because it means youw pwogwam wiww cwash at de souwce of de pwobwem, wadew dan watew
+ on when you twy to use de invawid index.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.6.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">To test whedew a vawue is in de wist, use <tt class="function">in</tt>, which wetuwns <tt class="constant">Twue</tt> if de vawue is found ow <tt class="constant">Fawse</tt> if it is not.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div><a name="tip.boolean"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">Befowe vewsion 2.2.1, <span class="application">Pydon</span> had no sepawate boowean datatype. To compensate fow dis, <span class="application">Pydon</span> accepted awmost anyding in a boowean context (wike an <tt class="literal">if</tt> statement), accowding to de fowwowing wuwes:
+ <div class="itemizedlist">
+ <ul>
+ <li><tt class="constant">0</tt> is fawse; aww odew numbews awe twue.
+ </li>
+ <li>An empty stwing (<tt class="literal">""</tt>) is fawse, aww odew stwings awe twue.
+ </li>
+ <li>An empty wist (<tt class="literal">[]</tt>) is fawse; aww odew wists awe twue.
+ </li>
+ <li>An empty tupwe (<tt class="literal">()</tt>) is fawse; aww odew tupwes awe twue.
+ </li>
+ <li>An empty dictionawy (<tt class="literal">{}</tt>) is fawse; aww odew dictionawies awe twue.
+ </li>
+ </ul>
+ </div>These wuwes stiww appwy in <span class="application">Pydon</span> 2.2.1 and beyond, but now you can awso use an actuaw boowean, which has a vawue of <tt class="literal">Twue</tt> ow <tt class="literal">Fawse</tt>. Note de capitawization; dese vawues, wike evewyding ewse in <span class="application">Pydon</span>, awe case-sensitive.
+ </td>
+ </tr>
+ </table>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e6277"></a>3.2.4.&nbsp;Deweting List Ewements
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="example"><a name="odbchelper.list.removingelements"></a><h3 class="title">Exampwe&nbsp;3.13.&nbsp;Removing Ewements fwom a List</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new', 'two', 'elements']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li.remove(<span class="pystring">"z"</span>)</span> <a name="odbchelper.list.7.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'new', 'mpilgrim', 'example', 'new', 'two', 'elements']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li.remove(<span class="pystring">"new"</span>)</span> <a name="odbchelper.list.7.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'mpilgrim', 'example', 'new', 'two', 'elements']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li.remove(<span class="pystring">"c"</span>)</span> <a name="odbchelper.list.7.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="traceback">Traceback (innermost last):
+ File "&lt;interactive input&gt;", line 1, in ?
+ValueError: list.remove(x): x not in list</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li.pop()</span> <a name="odbchelper.list.7.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">'elements'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'mpilgrim', 'example', 'new', 'two']</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.7.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">wemove</tt> wemoves de fiwst occuwwence of a vawue fwom a wist.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.7.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">wemove</tt> wemoves <span class="emphasis"><em>onwy</em></span> de fiwst occuwwence of a vawue. In dis case, <tt class="literal">'new'</tt> appeawed twice in de wist, but <tt class="literal">wi.wemove("new")</tt> wemoved onwy de fiwst occuwwence.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.7.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">If de vawue is not found in de wist, <span class="application">Pydon</span> waises an exception, uh-hah-hah-hah. This miwwows de behaviow of de <tt class="function">index</tt> medod.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.7.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">pop</tt> is an intewesting beast. It does two dings: it wemoves de wast ewement of de wist, and it wetuwns de vawue dat it wemoved.
+ Note dat dis is diffewent fwom <tt class="literal">wi[-1]</tt>, which wetuwns a vawue but does not change de wist, and diffewent fwom <tt class="literal">wi.wemove(<i class="replaceable">vawue</i>)</tt>, which changes de wist but does not wetuwn a vawue.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e6392"></a>3.2.5.&nbsp;Using List Opewatows
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="example"><a name="odbchelper.list.operators"></a><h3 class="title">Exampwe&nbsp;3.14.&nbsp;List Opewatows</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li = [<span class="pystring">'a'</span>, <span class="pystring">'b'</span>, <span class="pystring">'mpilgrim'</span>]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li = li + [<span class="pystring">'example'</span>, <span class="pystring">'new'</span>]</span> <a name="odbchelper.list.8.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'mpilgrim', 'example', 'new']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li += [<span class="pystring">'two'</span>]</span> <a name="odbchelper.list.8.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'mpilgrim', 'example', 'new', 'two']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li = [1, 2] * 3</span> <a name="odbchelper.list.8.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">[1, 2, 1, 2, 1, 2]</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.8.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Lists can awso be concatenated wif de <tt class="literal">+</tt> opewatow. <tt class="literal"><i class="replaceable">wist</i> = <i class="replaceable">wist</i> + <i class="replaceable">odewwist</i></tt> has de same wesuwt as <tt class="literal"><i class="replaceable">wist</i>.extend(<i class="replaceable">odewwist</i>)</tt>. But de <tt class="literal">+</tt> opewatow wetuwns a new (concatenated) wist as a vawue, wheweas <tt class="function">extend</tt> onwy awtews an existing wist. This means dat <tt class="function">extend</tt> is fastew, especiawwy fow wawge wists.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.8.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><span class="application">Pydon</span> suppowts de <tt class="literal">+=</tt> opewatow. <tt class="literal">wi += ['two']</tt> is eqwivawent to <tt class="literal">wi.extend(['two'])</tt>. The <tt class="literal">+=</tt> opewatow wowks fow wists, stwings, and integews, and it can be ovewwoaded to wowk fow usew-defined cwasses as weww. (Mowe
+ on cwasses in <a href="../object_oriented_framework/index.html">Chaptew 5</a>.)
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.8.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="literal">*</tt> opewatow wowks on wists as a wepeatew. <tt class="literal">wi = [1, 2] * 3</tt> is eqwivawent to <tt class="literal">wi = [1, 2] + [1, 2] + [1, 2]</tt>, which concatenates de dwee wists into one.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="furtherreading">
+ <h3>Fuwdew Reading on Lists</h3>
+ <ul>
+ <li><a href="http://www.ibiblio.org/obp/thinkCSpy/" title="Python book for computer science majors"><i class="citetitle">How to Think Like a Computew Scientist</i></a> teaches about wists and makes an impowtant point about <a href="http://www.ibiblio.org/obp/thinkCSpy/chap08.htm">passing wists as function awguments</a>.
+ </li>
+ <li><a href="http://www.python.org/doc/current/tut/tut.html"><i class="citetitle"><span class="application">Pydon</span> Tutowiaw</i></a> shows how to <a href="http://www.python.org/doc/current/tut/node7.html#SECTION007110000000000000000">use wists as stacks and qweues</a>.
+ </li>
+ <li><a href="http://www.faqts.com/knowledge-base/index.phtml/fid/199/"><span class="application">Pydon</span> Knowwedge Base</a> answews <a href="http://www.faqts.com/knowledge-base/index.phtml/fid/534">common qwestions about wists</a> and has a wot of <a href="http://www.faqts.com/knowledge-base/index.phtml/fid/540">exampwe code using wists</a>.
+ </li>
+ <li><a href="http://www.python.org/doc/current/lib/"><i class="citetitle"><span class="application">Pydon</span> Libwawy Refewence</i></a> summawizes <a href="http://www.python.org/doc/current/lib/typesseq-mutable.html">aww de wist medods</a>.
+ </li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="index.html">&lt;&lt;&nbsp;Native Datatypes</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#odbchelper.dict" title="3.1.&nbsp;Introducing Dictionaries">1</a> <span class="divider">|</span> <span class="thispage">2</span> <span class="divider">|</span> <a href="tuples.html" title="3.3.&nbsp;Introducing Tuples">3</a> <span class="divider">|</span> <a href="declaring_variables.html" title="3.4.&nbsp;Declaring variables">4</a> <span class="divider">|</span> <a href="formatting_strings.html" title="3.5.&nbsp;Formatting Strings">5</a> <span class="divider">|</span> <a href="mapping_lists.html" title="3.6.&nbsp;Mapping Lists">6</a> <span class="divider">|</span> <a href="joining_lists.html" title="3.7.&nbsp;Joining Lists and Splitting Strings">7</a> <span class="divider">|</span> <a href="summary.html" title="3.8.&nbsp;Summary">8</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="tuples.html">Intwoducing Tupwes&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copywight &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mawk Piwgwim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/native_data_types/index.html b/help/diveintopython-5.4/html/native_data_types/index.html
new file mode 100644
index 0000000..150e298
--- /dev/null
+++ b/help/diveintopython-5.4/html/native_data_types/index.html
@@ -0,0 +1,346 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>Chapter&nbsp;3.&nbsp;Native Datatypes</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="../toc/index.html" title="Dive Into Python">
+ <link rel="previous" href="../getting_to_know_python/testing_modules.html" title="2.6.&nbsp;Testing Modules">
+ <link rel="next" href="lists.html" title="3.2.&nbsp;Introducing Lists">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<span class="thispage">Native Datatypes</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="../getting_to_know_python/testing_modules.html" title="Prev: &#8220;Testing Modules&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="lists.html" title="Next: &#8220;Introducing Lists&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="chapter" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="datatypes"></a>Chapter&nbsp;3.&nbsp;Native Datatypes
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="toc">
+ <ul>
+ <li><span class="section"><a href="index.html#odbchelper.dict">3.1. Introducing Dictionaries</a></span><ul>
+ <li><span class="section"><a href="index.html#d0e5174">3.1.1. Defining Dictionaries</a></span></li>
+ <li><span class="section"><a href="index.html#d0e5269">3.1.2. Modifying Dictionaries</a></span></li>
+ <li><span class="section"><a href="index.html#d0e5450">3.1.3. Deleting Items From Dictionaries</a></span></li>
+ </ul>
+ </li>
+ <li><span class="section"><a href="lists.html">3.2. Introducing Lists</a></span><ul>
+ <li><span class="section"><a href="lists.html#d0e5623">3.2.1. Defining Lists</a></span></li>
+ <li><span class="section"><a href="lists.html#d0e5887">3.2.2. Adding Elements to Lists</a></span></li>
+ <li><span class="section"><a href="lists.html#d0e6115">3.2.3. Searching Lists</a></span></li>
+ <li><span class="section"><a href="lists.html#d0e6277">3.2.4. Deleting List Elements</a></span></li>
+ <li><span class="section"><a href="lists.html#d0e6392">3.2.5. Using List Operators</a></span></li>
+ </ul>
+ </li>
+ <li><span class="section"><a href="tuples.html">3.3. Introducing Tuples</a></span></li>
+ <li><span class="section"><a href="declaring_variables.html">3.4. Declaring variables</a></span><ul>
+ <li><span class="section"><a href="declaring_variables.html#d0e6873">3.4.1. Referencing Variables</a></span></li>
+ <li><span class="section"><a href="declaring_variables.html#odbchelper.multiassign">3.4.2. Assigning Multiple Values at Once</a></span></li>
+ </ul>
+ </li>
+ <li><span class="section"><a href="formatting_strings.html">3.5. Formatting Strings</a></span></li>
+ <li><span class="section"><a href="mapping_lists.html">3.6. Mapping Lists</a></span></li>
+ <li><span class="section"><a href="joining_lists.html">3.7. Joining Lists and Splitting Strings</a></span><ul>
+ <li><span class="section"><a href="joining_lists.html#d0e7982">3.7.1. Historical Note on String Methods</a></span></li>
+ </ul>
+ </li>
+ <li><span class="section"><a href="summary.html">3.8. Summary</a></span></li>
+ </ul>
+ </div>
+ <p>You'll get back to your first <span class="application">Python</span> program in just a minute. But first, a short digression is in order, because you need to know about dictionaries, tuples,
+ and lists (oh my!). If you're a <span class="application">Perl</span> hacker, you can probably skim the bits about dictionaries and lists, but you should still pay attention to tuples.
+ </p>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="odbchelper.dict"></a>3.1.&nbsp;Introducing Dictionaries
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="toc">
+ <ul>
+ <li><span class="section"><a href="index.html#d0e5174">3.1.1. Defining Dictionaries</a></span></li>
+ <li><span class="section"><a href="index.html#d0e5269">3.1.2. Modifying Dictionaries</a></span></li>
+ <li><span class="section"><a href="index.html#d0e5450">3.1.3. Deleting Items From Dictionaries</a></span></li>
+ </ul>
+ </div>
+ <div class="abstract">
+ <p>One of <span class="application">Python</span>'s built-in datatypes is the dictionary, which defines one-to-one relationships between keys and values.
+ </p>
+ </div><a name="compare.dict.perl"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">A dictionary in <span class="application">Python</span> is like a hash in <span class="application">Perl</span>. In <span class="application">Perl</span>, variables that store hashes always start with a <tt class="literal">%</tt> character. In <span class="application">Python</span>, variables can be named anything, and <span class="application">Python</span> keeps track of the datatype internally.
+ </td>
+ </tr>
+ </table><a name="compare.dict.java"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">A dictionary in <span class="application">Python</span> is like an instance of the <tt class="classname">Hashtable</tt> class in <span class="application">Java</span>.
+ </td>
+ </tr>
+ </table><a name="compare.dict.vb"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">A dictionary in <span class="application">Python</span> is like an instance of the <tt class="classname">Scripting.Dictionary</tt> object in <span class="application">Visual Basic</span>.
+ </td>
+ </tr>
+ </table>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e5174"></a>3.1.1.&nbsp;Defining Dictionaries
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="example"><a name="odbchelper.dict.define"></a><h3 class="title">Example&nbsp;3.1.&nbsp;Defining a Dictionary</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">d = {<span class='pystring'>"server"</span>:<span class='pystring'>"mpilgrim"</span>, <span class='pystring'>"database"</span>:<span class='pystring'>"master"</span>}</span> <a name="odbchelper.dict.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">d</span>
+<span class="computeroutput">{'server': 'mpilgrim', 'database': 'master'}</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">d[<span class='pystring'>"server"</span>]</span> <a name="odbchelper.dict.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">'mpilgrim'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">d[<span class='pystring'>"database"</span>]</span> <a name="odbchelper.dict.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">'master'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">d[<span class='pystring'>"mpilgrim"</span>]</span> <a name="odbchelper.dict.1.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="traceback">Traceback (innermost last):
+ File "&lt;interactive input&gt;", line 1, in ?
+KeyError: mpilgrim</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.dict.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">First, you create a new dictionary with two elements and assign it to the variable <tt class="varname">d</tt>. Each element is a key-value pair, and the whole set of elements is enclosed in curly braces.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.dict.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="literal">'server'</tt> is a key, and its associated value, referenced by <tt class="literal">d["server"]</tt>, is <tt class="literal">'mpilgrim'</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.dict.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="literal">'database'</tt> is a key, and its associated value, referenced by <tt class="literal">d["database"]</tt>, is <tt class="literal">'master'</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.dict.1.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You can get values by key, but you can't get keys by value. So <tt class="literal">d["server"]</tt> is <tt class="literal">'mpilgrim'</tt>, but <tt class="literal">d["mpilgrim"]</tt> raises an exception, because <tt class="literal">'mpilgrim'</tt> is not a key.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e5269"></a>3.1.2.&nbsp;Modifying Dictionaries
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="example"><a name="odbchelper.dict.modify"></a><h3 class="title">Example&nbsp;3.2.&nbsp;Modifying a Dictionary</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">d</span>
+<span class="computeroutput">{'server': 'mpilgrim', 'database': 'master'}</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">d[<span class='pystring'>"database"</span>] = <span class='pystring'>"pubs"</span></span> <a name="odbchelper.dict.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">d</span>
+<span class="computeroutput">{'server': 'mpilgrim', 'database': 'pubs'}</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">d[<span class='pystring'>"uid"</span>] = <span class='pystring'>"sa"</span></span> <a name="odbchelper.dict.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">d</span>
+<span class="computeroutput">{'server': 'mpilgrim', 'uid': 'sa', 'database': 'pubs'}</span></pre></div>
+ <div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.dict.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You can not have duplicate keys in a dictionary. Assigning a value to an existing key will wipe out the old value.</td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.dict.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You can add new key-value pairs at any time. This syntax is identical to modifying existing values. (Yes, this will annoy
+ you someday when you think you are adding new values but are actually just modifying the same value over and over because
+ your key isn't changing the way you think it is.)
+ </td>
+ </tr>
+ </table>
+ </div>
+ <p>Note that the new element (key <tt class="literal">'uid'</tt>, value <tt class="literal">'sa'</tt>) appears to be in the middle. In fact, it was just a coincidence that the elements appeared to be in order in the first
+ example; it is just as much a coincidence that they appear to be out of order now.
+ </p><a name="tip.dictorder"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">Dictionaries have no concept of order among elements. It is incorrect to say that the elements are &#8220;<span class="quote">out of order</span>&#8221;; they are simply unordered. This is an important distinction that will annoy you when you want to access the elements of
+ a dictionary in a specific, repeatable order (like alphabetical order by key). There are ways of doing this, but they're
+ not built into the dictionary.
+ </td>
+ </tr>
+ </table>
+ <p>When working with dictionaries, you need to be aware that dictionary keys are case-sensitive.</p>
+ <div class="example"><a name="odbchelper.dict.case"></a><h3 class="title">Example&nbsp;3.3.&nbsp;Dictionary Keys Are Case-Sensitive</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">d = {}</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">d[<span class='pystring'>"key"</span>] = <span class='pystring'>"value"</span></span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">d[<span class='pystring'>"key"</span>] = <span class='pystring'>"other value"</span></span> <a name="odbchelper.dict.5.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">d</span>
+<span class="computeroutput">{'key': 'other value'}</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">d[<span class='pystring'>"Key"</span>] = <span class='pystring'>"third value"</span></span> <a name="odbchelper.dict.5.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">d</span>
+<span class="computeroutput">{'Key': 'third value', 'key': 'other value'}</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.dict.5.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Assigning a value to an existing dictionary key simply replaces the old value with a new one.</td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.dict.5.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This is not assigning a value to an existing dictionary key, because strings in <span class="application">Python</span> are case-sensitive, so <tt class="literal">'key'</tt> is not the same as <tt class="literal">'Key'</tt>. This creates a new key/value pair in the dictionary; it may look similar to you, but as far as <span class="application">Python</span> is concerned, it's completely different.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="odbchelper.dictionarytypes"></a><h3 class="title">Example&nbsp;3.4.&nbsp;Mixing Datatypes in a Dictionary</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">d</span>
+<span class="computeroutput">{'server': 'mpilgrim', 'uid': 'sa', 'database': 'pubs'}</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">d[<span class='pystring'>"retrycount"</span>] = 3</span> <a name="odbchelper.dict.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">d</span>
+<span class="computeroutput">{'server': 'mpilgrim', 'uid': 'sa', 'database': 'master', 'retrycount': 3}</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">d[42] = <span class='pystring'>"douglas"</span></span> <a name="odbchelper.dict.3.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">d</span>
+<span class="computeroutput">{'server': 'mpilgrim', 'uid': 'sa', 'database': 'master',
+42: 'douglas', 'retrycount': 3}</span></pre></div>
+ <div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.dict.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Dictionaries aren't just for strings. Dictionary values can be any datatype, including strings, integers, objects, or even
+ other dictionaries. And within a single dictionary, the values don't all need to be the same type; you can mix and match
+ as needed.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.dict.3.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Dictionary keys are more restricted, but they can be strings, integers, and a few other types. You can also mix and match
+ key datatypes within a dictionary.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e5450"></a>3.1.3.&nbsp;Deleting Items From Dictionaries
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="example"><a name="odbchelper.dict.del"></a><h3 class="title">Example&nbsp;3.5.&nbsp;Deleting Items from a Dictionary</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">d</span>
+<span class="computeroutput">{'server': 'mpilgrim', 'uid': 'sa', 'database': 'master',
+42: 'douglas', 'retrycount': 3}</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>del</span> d[42]</span> <a name="odbchelper.dict.4.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">d</span>
+<span class="computeroutput">{'server': 'mpilgrim', 'uid': 'sa', 'database': 'master', 'retrycount': 3}</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">d.clear()</span> <a name="odbchelper.dict.4.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">d</span>
+<span class="computeroutput">{}</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.dict.4.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">del</tt> lets you delete individual items from a dictionary by key.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.dict.4.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">clear</tt> deletes all items from a dictionary. Note that the set of empty curly braces signifies a dictionary without any items.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="furtherreading">
+ <h3>Further Reading on Dictionaries</h3>
+ <ul>
+ <li><a href="http://www.ibiblio.org/obp/thinkCSpy/" title="Python book for computer science majors"><i class="citetitle">How to Think Like a Computer Scientist</i></a> teaches about dictionaries and shows how to <a href="http://www.ibiblio.org/obp/thinkCSpy/chap10.htm">use dictionaries to model sparse matrices</a>.
+ </li>
+ <li><a href="http://www.faqts.com/knowledge-base/index.phtml/fid/199/"><span class="application">Python</span> Knowledge Base</a> has a lot of <a href="http://www.faqts.com/knowledge-base/index.phtml/fid/541">example code using dictionaries</a>.
+ </li>
+ <li><a href="http://www.activestate.com/ASPN/Python/Cookbook/" title="growing archive of annotated code samples"><span class="application">Python</span> Cookbook</a> discusses <a href="http://www.activestate.com/ASPN/Python/Cookbook/Recipe/52306">how to sort the values of a dictionary by key</a>.
+ </li>
+ <li><a href="http://www.python.org/doc/current/lib/"><i class="citetitle"><span class="application">Python</span> Library Reference</i></a> summarizes <a href="http://www.python.org/doc/current/lib/typesmapping.html">all the dictionary methods</a>.
+ </li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="../getting_to_know_python/testing_modules.html">&lt;&lt;&nbsp;Testing Modules</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<span class="thispage">1</span> <span class="divider">|</span> <a href="lists.html" title="3.2.&nbsp;Introducing Lists">2</a> <span class="divider">|</span> <a href="tuples.html" title="3.3.&nbsp;Introducing Tuples">3</a> <span class="divider">|</span> <a href="declaring_variables.html" title="3.4.&nbsp;Declaring variables">4</a> <span class="divider">|</span> <a href="formatting_strings.html" title="3.5.&nbsp;Formatting Strings">5</a> <span class="divider">|</span> <a href="mapping_lists.html" title="3.6.&nbsp;Mapping Lists">6</a> <span class="divider">|</span> <a href="joining_lists.html" title="3.7.&nbsp;Joining Lists and Splitting Strings">7</a> <span class="divider">|</span> <a href="summary.html" title="3.8.&nbsp;Summary">8</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="lists.html">Introducing Lists&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/native_data_types/joining_lists.html b/help/diveintopython-5.4/html/native_data_types/joining_lists.html
new file mode 100644
index 0000000..006b429
--- /dev/null
+++ b/help/diveintopython-5.4/html/native_data_types/joining_lists.html
@@ -0,0 +1,165 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>3.7.&nbsp;Joining Lists and Splitting Strings</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;3.&nbsp;Native Datatypes">
+ <link rel="previous" href="mapping_lists.html" title="3.6.&nbsp;Mapping Lists">
+ <link rel="next" href="summary.html" title="3.8.&nbsp;Summary">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Native Datatypes</a>&nbsp;&gt;&nbsp;<span class="thispage">Joining Lists and Splitting Strings</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="mapping_lists.html" title="Prev: &#8220;Mapping Lists&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="summary.html" title="Next: &#8220;Summary&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="odbchelper.join"></a>3.7.&nbsp;Joining Lists and Splitting Strings
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="toc">
+ <ul>
+ <li><span class="section"><a href="joining_lists.html#d0e7982">3.7.1. Historical Note on String Methods</a></span></li>
+ </ul>
+ </div>
+ <div class="abstract">
+ <p>You have a list of key-value pairs in the form <tt class="literal"><i class="replaceable">key</i>=<i class="replaceable">value</i></tt>, and you want to join them into a single string. To join any list of strings into a single string, use the <tt class="function">join</tt> method of a string object.
+ </p>
+ </div>
+ <div class="informalexample">
+ <p>Here is an example of joining a list from the <tt class="function">buildConnectionString</tt> function:
+ </p><pre class="programlisting">
+ <span class='pykeyword'>return</span> <span class='pystring'>";"</span>.join([<span class='pystring'>"%s=%s"</span> % (k, v) <span class='pykeyword'>for</span> k, v <span class='pykeyword'>in</span> params.items()])</pre></div>
+ <p>One interesting note before you continue. I keep repeating that functions are objects, strings are objects... everything
+ is an object. You might have thought I meant that string <span class="emphasis"><em>variables</em></span> are objects. But no, look closely at this example and you'll see that the string <tt class="literal">";"</tt> itself is an object, and you are calling its <tt class="function">join</tt> method.
+ </p>
+ <p>The <tt class="function">join</tt> method joins the elements of the list into a single string, with each element separated by a semi-colon. The delimiter doesn't
+ need to be a semi-colon; it doesn't even need to be a single character. It can be any string.
+ </p><a name="tip.join"></a><table class="caution" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/caution.png" alt="Caution" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%"><tt class="function">join</tt> works only on lists of strings; it does not do any type coercion. Joining a list that has one or more non-string elements
+ will raise an exception.
+ </td>
+ </tr>
+ </table>
+ <div class="example"><a name="odbchelper.join.example"></a><h3 class="title">Example&nbsp;3.27.&nbsp;Output of <tt class="filename">odbchelper.py</tt></h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">params = {<span class='pystring'>"server"</span>:<span class='pystring'>"mpilgrim"</span>, <span class='pystring'>"database"</span>:<span class='pystring'>"master"</span>, <span class='pystring'>"uid"</span>:<span class='pystring'>"sa"</span>, <span class='pystring'>"pwd"</span>:<span class='pystring'>"secret"</span>}</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">[<span class='pystring'>"%s=%s"</span> % (k, v) <span class='pykeyword'>for</span> k, v <span class='pykeyword'>in</span> params.items()]</span>
+<span class="computeroutput">['server=mpilgrim', 'uid=sa', 'database=master', 'pwd=secret']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pystring'>";"</span>.join([<span class='pystring'>"%s=%s"</span> % (k, v) <span class='pykeyword'>for</span> k, v <span class='pykeyword'>in</span> params.items()])</span>
+<span class="computeroutput">'server=mpilgrim;uid=sa;database=master;pwd=secret'</span></pre></div>
+ <p>This string is then returned from the <tt class="function">odbchelper</tt> function and printed by the calling block, which gives you the output that you marveled at when you started reading this
+ chapter.
+ </p>
+ <p>You're probably wondering if there's an analogous method to split a string into a list. And of course there is, and it's
+ called <tt class="function">split</tt>.
+ </p>
+ <div class="example"><a name="odbchelper.split.example"></a><h3 class="title">Example&nbsp;3.28.&nbsp;Splitting a String</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li = [<span class='pystring'>'server=mpilgrim'</span>, <span class='pystring'>'uid=sa'</span>, <span class='pystring'>'database=master'</span>, <span class='pystring'>'pwd=secret'</span>]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">s = <span class='pystring'>";"</span>.join(li)</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">s</span>
+<span class="computeroutput">'server=mpilgrim;uid=sa;database=master;pwd=secret'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">s.split(<span class='pystring'>";"</span>)</span> <a name="odbchelper.join.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">['server=mpilgrim', 'uid=sa', 'database=master', 'pwd=secret']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">s.split(<span class='pystring'>";"</span>, 1)</span> <a name="odbchelper.join.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">['server=mpilgrim', 'uid=sa;database=master;pwd=secret']</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.join.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">split</tt> reverses <tt class="function">join</tt> by splitting a string into a multi-element list. Note that the delimiter (&#8220;<span class="quote"><tt class="literal">;</tt></span>&#8221;) is stripped out completely; it does not appear in any of the elements of the returned list.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.join.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">split</tt> takes an optional second argument, which is the number of times to split. (&#8220;<span class="quote">"Oooooh, optional arguments...</span>&#8221; You'll learn how to do this in your own functions in the next chapter.)
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div><a name="tip.split"></a><table class="tip" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/tip.png" alt="Tip" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%"><tt class="literal"><i class="replaceable">anystring</i>.<tt class="function">split</tt>(<i class="replaceable">delimiter</i>, 1)</tt> is a useful technique when you want to search a string for a substring and then work with everything before the substring
+ (which ends up in the first element of the returned list) and everything after it (which ends up in the second element).
+ </td>
+ </tr>
+ </table>
+ <div class="furtherreading">
+ <h3>Further Reading on String Methods</h3>
+ <ul>
+ <li><a href="http://www.faqts.com/knowledge-base/index.phtml/fid/199/"><span class="application">Python</span> Knowledge Base</a> answers <a href="http://www.faqts.com/knowledge-base/index.phtml/fid/480">common questions about strings</a> and has a lot of <a href="http://www.faqts.com/knowledge-base/index.phtml/fid/539">example code using strings</a>.
+ </li>
+ <li><a href="http://www.python.org/doc/current/lib/"><i class="citetitle"><span class="application">Python</span> Library Reference</i></a> summarizes <a href="http://www.python.org/doc/current/lib/string-methods.html">all the string methods</a>.
+ </li>
+ <li><a href="http://www.python.org/doc/current/lib/"><i class="citetitle"><span class="application">Python</span> Library Reference</i></a> documents the <a href="http://www.python.org/doc/current/lib/module-string.html"><tt class="filename">string</tt> module</a>.
+ </li>
+ <li><a href="http://www.python.org/doc/FAQ.html"><i class="citetitle">The Whole <span class="application">Python</span> <span class="acronym">FAQ</span></i></a> explains <a href="http://www.python.org/cgi-bin/faqw.py?query=4.96&amp;querytype=simple&amp;casefold=yes&amp;req=search">why <tt class="function">join</tt> is a string method</a> instead of a list method.
+ </li>
+ </ul>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e7982"></a>3.7.1.&nbsp;Historical Note on String Methods
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p>When I first learned <span class="application">Python</span>, I expected <tt class="function">join</tt> to be a method of a list, which would take the delimiter as an argument. Many people feel the same way, and there's a story
+ behind the <tt class="function">join</tt> method. Prior to <span class="application">Python</span> 1.6, strings didn't have all these useful methods. There was a separate <tt class="filename">string</tt> module that contained all the string functions; each function took a string as its first argument. The functions were deemed
+ important enough to put onto the strings themselves, which made sense for functions like <tt class="function">lower</tt>, <tt class="function">upper</tt>, and <tt class="function">split</tt>. But many hard-core <span class="application">Python</span> programmers objected to the new <tt class="function">join</tt> method, arguing that it should be a method of the list instead, or that it shouldn't move at all but simply stay a part of
+ the old <tt class="filename">string</tt> module (which still has a lot of useful stuff in it). I use the new <tt class="function">join</tt> method exclusively, but you will see code written either way, and if it really bothers you, you can use the old <tt class="function">string.join</tt> function instead.
+ </p>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="mapping_lists.html">&lt;&lt;&nbsp;Mapping Lists</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#odbchelper.dict" title="3.1.&nbsp;Introducing Dictionaries">1</a> <span class="divider">|</span> <a href="lists.html" title="3.2.&nbsp;Introducing Lists">2</a> <span class="divider">|</span> <a href="tuples.html" title="3.3.&nbsp;Introducing Tuples">3</a> <span class="divider">|</span> <a href="declaring_variables.html" title="3.4.&nbsp;Declaring variables">4</a> <span class="divider">|</span> <a href="formatting_strings.html" title="3.5.&nbsp;Formatting Strings">5</a> <span class="divider">|</span> <a href="mapping_lists.html" title="3.6.&nbsp;Mapping Lists">6</a> <span class="divider">|</span> <span class="thispage">7</span> <span class="divider">|</span> <a href="summary.html" title="3.8.&nbsp;Summary">8</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="summary.html">Summary&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/native_data_types/lists.html b/help/diveintopython-5.4/html/native_data_types/lists.html
new file mode 100644
index 0000000..66daf20
--- /dev/null
+++ b/help/diveintopython-5.4/html/native_data_types/lists.html
@@ -0,0 +1,506 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>3.2.&nbsp;Introducing Lists</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;3.&nbsp;Native Datatypes">
+ <link rel="previous" href="index.html" title="Chapter&nbsp;3.&nbsp;Native Datatypes">
+ <link rel="next" href="tuples.html" title="3.3.&nbsp;Introducing Tuples">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Native Datatypes</a>&nbsp;&gt;&nbsp;<span class="thispage">Introducing Lists</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="index.html" title="Prev: &#8220;Native Datatypes&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="tuples.html" title="Next: &#8220;Introducing Tuples&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="odbchelper.list"></a>3.2.&nbsp;Introducing Lists
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="toc">
+ <ul>
+ <li><span class="section"><a href="lists.html#d0e5623">3.2.1. Defining Lists</a></span></li>
+ <li><span class="section"><a href="lists.html#d0e5887">3.2.2. Adding Elements to Lists</a></span></li>
+ <li><span class="section"><a href="lists.html#d0e6115">3.2.3. Searching Lists</a></span></li>
+ <li><span class="section"><a href="lists.html#d0e6277">3.2.4. Deleting List Elements</a></span></li>
+ <li><span class="section"><a href="lists.html#d0e6392">3.2.5. Using List Operators</a></span></li>
+ </ul>
+ </div>
+ <div class="abstract">
+ <p>Lists are <span class="application">Python</span>'s workhorse datatype. If your only experience with lists is arrays in <span class="application">Visual Basic</span> or (God forbid) the datastore in <span class="application">Powerbuilder</span>, brace yourself for <span class="application">Python</span> lists.
+ </p>
+ </div><a name="compare.list.perl"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">A list in <span class="application">Python</span> is like an array in <span class="application">Perl</span>. In <span class="application">Perl</span>, variables that store arrays always start with the <tt class="literal">@</tt> character; in <span class="application">Python</span>, variables can be named anything, and <span class="application">Python</span> keeps track of the datatype internally.
+ </td>
+ </tr>
+ </table><a name="compare.list.java"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">A list in <span class="application">Python</span> is much more than an array in <span class="application">Java</span> (although it can be used as one if that's really all you want out of life). A better analogy would be to the <tt class="classname">ArrayList</tt> class, which can hold arbitrary objects and can expand dynamically as new items are added.
+ </td>
+ </tr>
+ </table>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e5623"></a>3.2.1.&nbsp;Defining Lists
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="example"><a name="d0e5626"></a><h3 class="title">Example&nbsp;3.6.&nbsp;Defining a List</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li = [<span class='pystring'>"a"</span>, <span class='pystring'>"b"</span>, <span class='pystring'>"mpilgrim"</span>, <span class='pystring'>"z"</span>, <span class='pystring'>"example"</span>]</span> <a name="odbchelper.list.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'mpilgrim', 'z', 'example']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li[0]</span> <a name="odbchelper.list.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">'a'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li[4]</span> <a name="odbchelper.list.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">'example'</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">First, you define a list of five elements. Note that they retain their original order. This is not an accident. A list
+ is an ordered set of elements enclosed in square brackets.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">A list can be used like a zero-based array. The first element of any non-empty list is always <tt class="literal">li[0]</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The last element of this five-element list is <tt class="literal">li[4]</tt>, because lists are always zero-based.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="odbchelper.negative.example"></a><h3 class="title">Example&nbsp;3.7.&nbsp;Negative List Indices</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'mpilgrim', 'z', 'example']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li[-1]</span> <a name="odbchelper.list.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">'example'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li[-3]</span> <a name="odbchelper.list.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">'mpilgrim'</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">A negative index accesses elements from the end of the list counting backwards. The last element of any non-empty list is
+ always <tt class="literal">li[-1]</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">If the negative index is confusing to you, think of it this way: <tt class="literal">li[-n] == li[len(li) - n]</tt>. So in this list, <tt class="literal">li[-3] == li[5 - 3] == li[2]</tt>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="odbchelper.list.slice"></a><h3 class="title">Example&nbsp;3.8.&nbsp;Slicing a List</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'mpilgrim', 'z', 'example']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li[1:3]</span> <a name="odbchelper.list.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">['b', 'mpilgrim']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li[1:-1]</span> <a name="odbchelper.list.3.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">['b', 'mpilgrim', 'z']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li[0:3]</span> <a name="odbchelper.list.3.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">['a', 'b', 'mpilgrim']</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You can get a subset of a list, called a &#8220;<span class="quote">slice</span>&#8221;, by specifying two indices. The return value is a new list containing all the elements of the list, in order, starting
+ with the first slice index (in this case <tt class="literal">li[1]</tt>), up to but not including the second slice index (in this case <tt class="literal">li[3]</tt>).
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.3.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Slicing works if one or both of the slice indices is negative. If it helps, you can think of it this way: reading the list
+ from left to right, the first slice index specifies the first element you want, and the second slice index specifies the first
+ element you don't want. The return value is everything in between.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.3.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Lists are zero-based, so <tt class="literal">li[0:3]</tt> returns the first three elements of the list, starting at <tt class="literal">li[0]</tt>, up to but not including <tt class="literal">li[3]</tt>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="odbchelper.list.slicing.example"></a><h3 class="title">Example&nbsp;3.9.&nbsp;Slicing Shorthand</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'mpilgrim', 'z', 'example']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li[:3]</span> <a name="odbchelper.list.4.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">['a', 'b', 'mpilgrim']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li[3:]</span> <a name="odbchelper.list.4.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"> <a name="odbchelper.list.4.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">['z', 'example']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li[:]</span> <a name="odbchelper.list.4.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">['a', 'b', 'mpilgrim', 'z', 'example']</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.4.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">If the left slice index is 0, you can leave it out, and 0 is implied. So <tt class="literal">li[:3]</tt> is the same as <tt class="literal">li[0:3]</tt> from <a href="lists.html#odbchelper.list.slice" title="Example&nbsp;3.8.&nbsp;Slicing a List">Example&nbsp;3.8, &#8220;Slicing a List&#8221;</a>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.4.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Similarly, if the right slice index is the length of the list, you can leave it out. So <tt class="literal">li[3:]</tt> is the same as <tt class="literal">li[3:5]</tt>, because this list has five elements.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.4.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Note the symmetry here. In this five-element list, <tt class="literal">li[:3]</tt> returns the first 3 elements, and <tt class="literal">li[3:]</tt> returns the last two elements. In fact, <tt class="literal">li[:n]</tt> will always return the first <tt class="literal">n</tt> elements, and <tt class="literal">li[n:]</tt> will return the rest, regardless of the length of the list.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.4.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">If both slice indices are left out, all elements of the list are included. But this is not the same as the original <tt class="varname">li</tt> list; it is a new list that happens to have all the same elements. <tt class="literal">li[:]</tt> is shorthand for making a complete copy of a list.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e5887"></a>3.2.2.&nbsp;Adding Elements to Lists
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="example"><a name="d0e5890"></a><h3 class="title">Example&nbsp;3.10.&nbsp;Adding Elements to a List</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'mpilgrim', 'z', 'example']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li.append(<span class='pystring'>"new"</span>)</span> <a name="odbchelper.list.5.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'mpilgrim', 'z', 'example', 'new']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li.insert(2, <span class='pystring'>"new"</span>)</span> <a name="odbchelper.list.5.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li.extend([<span class='pystring'>"two"</span>, <span class='pystring'>"elements"</span>])</span> <a name="odbchelper.list.5.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new', 'two', 'elements']</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.5.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">append</tt> adds a single element to the end of the list.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.5.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">insert</tt> inserts a single element into a list. The numeric argument is the index of the first element that gets bumped out of position.
+ Note that list elements do not need to be unique; there are now two separate elements with the value <tt class="literal">'new'</tt>, <tt class="literal">li[2]</tt> and <tt class="literal">li[6]</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.5.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">extend</tt> concatenates lists. Note that you do not call <tt class="function">extend</tt> with multiple arguments; you call it with one argument, a list. In this case, that list has two elements.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="odbchelper.list.append.vs.extend"></a><h3 class="title">Example&nbsp;3.11.&nbsp;The Difference between <tt class="function">extend</tt> and <tt class="function">append</tt></h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li = [<span class='pystring'>'a'</span>, <span class='pystring'>'b'</span>, <span class='pystring'>'c'</span>]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li.extend([<span class='pystring'>'d'</span>, <span class='pystring'>'e'</span>, <span class='pystring'>'f'</span>])</span> <a name="odbchelper.list.5.4"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'c', 'd', 'e', 'f']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">len(li)</span> <a name="odbchelper.list.5.5"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">6</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li[-1]</span>
+<span class="computeroutput">'f'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li = [<span class='pystring'>'a'</span>, <span class='pystring'>'b'</span>, <span class='pystring'>'c'</span>]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li.append([<span class='pystring'>'d'</span>, <span class='pystring'>'e'</span>, <span class='pystring'>'f'</span>])</span> <a name="odbchelper.list.5.6"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'c', ['d', 'e', 'f']]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">len(li)</span> <a name="odbchelper.list.5.7"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">4</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li[-1]</span>
+<span class="computeroutput">['d', 'e', 'f']</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.5.4"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Lists have two methods, <tt class="function">extend</tt> and <tt class="function">append</tt>, that look like they do the same thing, but are in fact completely different. <tt class="function">extend</tt> takes a single argument, which is always a list, and adds each of the elements of that list to the original list.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.5.5"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Here you started with a list of three elements (<tt class="literal">'a'</tt>, <tt class="literal">'b'</tt>, and <tt class="literal">'c'</tt>), and you extended the list with a list of another three elements (<tt class="literal">'d'</tt>, <tt class="literal">'e'</tt>, and <tt class="literal">'f'</tt>), so you now have a list of six elements.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.5.6"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">On the other hand, <tt class="function">append</tt> takes one argument, which can be any data type, and simply adds it to the end of the list. Here, you're calling the <tt class="function">append</tt> method with a single argument, which is a list of three elements.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.5.7"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Now the original list, which started as a list of three elements, contains four elements. Why four? Because the last element
+ that you just appended <span class="emphasis"><em>is itself a list</em></span>. Lists can contain any type of data, including other lists. That may be what you want, or maybe not. Don't use <tt class="function">append</tt> if you mean <tt class="function">extend</tt>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e6115"></a>3.2.3.&nbsp;Searching Lists
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="example"><a name="odbchelper.list.search"></a><h3 class="title">Example&nbsp;3.12.&nbsp;Searching a List</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new', 'two', 'elements']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li.index(<span class='pystring'>"example"</span>)</span> <a name="odbchelper.list.6.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">5</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li.index(<span class='pystring'>"new"</span>)</span> <a name="odbchelper.list.6.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">2</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li.index(<span class='pystring'>"c"</span>)</span> <a name="odbchelper.list.6.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="traceback">Traceback (innermost last):
+ File "&lt;interactive input&gt;", line 1, in ?
+ValueError: list.index(x): x not in list</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pystring'>"c"</span> <span class='pykeyword'>in</span> li</span> <a name="odbchelper.list.6.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">False</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.6.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">index</tt> finds the first occurrence of a value in the list and returns the index.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.6.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">index</tt> finds the <span class="emphasis"><em>first</em></span> occurrence of a value in the list. In this case, <tt class="literal">'new'</tt> occurs twice in the list, in <tt class="literal">li[2]</tt> and <tt class="literal">li[6]</tt>, but <tt class="function">index</tt> will return only the first index, <tt class="literal">2</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.6.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">If the value is not found in the list, <span class="application">Python</span> raises an exception. This is notably different from most languages, which will return some invalid index. While this may
+ seem annoying, it is a good thing, because it means your program will crash at the source of the problem, rather than later
+ on when you try to use the invalid index.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.6.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">To test whether a value is in the list, use <tt class="function">in</tt>, which returns <tt class="constant">True</tt> if the value is found or <tt class="constant">False</tt> if it is not.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div><a name="tip.boolean"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">Before version 2.2.1, <span class="application">Python</span> had no separate boolean datatype. To compensate for this, <span class="application">Python</span> accepted almost anything in a boolean context (like an <tt class="literal">if</tt> statement), according to the following rules:
+ <div class="itemizedlist">
+ <ul>
+ <li><tt class="constant">0</tt> is false; all other numbers are true.
+ </li>
+ <li>An empty string (<tt class="literal">""</tt>) is false, all other strings are true.
+ </li>
+ <li>An empty list (<tt class="literal">[]</tt>) is false; all other lists are true.
+ </li>
+ <li>An empty tuple (<tt class="literal">()</tt>) is false; all other tuples are true.
+ </li>
+ <li>An empty dictionary (<tt class="literal">{}</tt>) is false; all other dictionaries are true.
+ </li>
+ </ul>
+ </div>These rules still apply in <span class="application">Python</span> 2.2.1 and beyond, but now you can also use an actual boolean, which has a value of <tt class="literal">True</tt> or <tt class="literal">False</tt>. Note the capitalization; these values, like everything else in <span class="application">Python</span>, are case-sensitive.
+ </td>
+ </tr>
+ </table>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e6277"></a>3.2.4.&nbsp;Deleting List Elements
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="example"><a name="odbchelper.list.removingelements"></a><h3 class="title">Example&nbsp;3.13.&nbsp;Removing Elements from a List</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new', 'two', 'elements']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li.remove(<span class='pystring'>"z"</span>)</span> <a name="odbchelper.list.7.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'new', 'mpilgrim', 'example', 'new', 'two', 'elements']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li.remove(<span class='pystring'>"new"</span>)</span> <a name="odbchelper.list.7.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'mpilgrim', 'example', 'new', 'two', 'elements']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li.remove(<span class='pystring'>"c"</span>)</span> <a name="odbchelper.list.7.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="traceback">Traceback (innermost last):
+ File "&lt;interactive input&gt;", line 1, in ?
+ValueError: list.remove(x): x not in list</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li.pop()</span> <a name="odbchelper.list.7.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">'elements'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'mpilgrim', 'example', 'new', 'two']</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.7.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">remove</tt> removes the first occurrence of a value from a list.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.7.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">remove</tt> removes <span class="emphasis"><em>only</em></span> the first occurrence of a value. In this case, <tt class="literal">'new'</tt> appeared twice in the list, but <tt class="literal">li.remove("new")</tt> removed only the first occurrence.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.7.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">If the value is not found in the list, <span class="application">Python</span> raises an exception. This mirrors the behavior of the <tt class="function">index</tt> method.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.7.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">pop</tt> is an interesting beast. It does two things: it removes the last element of the list, and it returns the value that it removed.
+ Note that this is different from <tt class="literal">li[-1]</tt>, which returns a value but does not change the list, and different from <tt class="literal">li.remove(<i class="replaceable">value</i>)</tt>, which changes the list but does not return a value.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e6392"></a>3.2.5.&nbsp;Using List Operators
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="example"><a name="odbchelper.list.operators"></a><h3 class="title">Example&nbsp;3.14.&nbsp;List Operators</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li = [<span class='pystring'>'a'</span>, <span class='pystring'>'b'</span>, <span class='pystring'>'mpilgrim'</span>]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li = li + [<span class='pystring'>'example'</span>, <span class='pystring'>'new'</span>]</span> <a name="odbchelper.list.8.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'mpilgrim', 'example', 'new']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li += [<span class='pystring'>'two'</span>]</span> <a name="odbchelper.list.8.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'mpilgrim', 'example', 'new', 'two']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li = [1, 2] * 3</span> <a name="odbchelper.list.8.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">[1, 2, 1, 2, 1, 2]</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.8.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Lists can also be concatenated with the <tt class="literal">+</tt> operator. <tt class="literal"><i class="replaceable">list</i> = <i class="replaceable">list</i> + <i class="replaceable">otherlist</i></tt> has the same result as <tt class="literal"><i class="replaceable">list</i>.extend(<i class="replaceable">otherlist</i>)</tt>. But the <tt class="literal">+</tt> operator returns a new (concatenated) list as a value, whereas <tt class="function">extend</tt> only alters an existing list. This means that <tt class="function">extend</tt> is faster, especially for large lists.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.8.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><span class="application">Python</span> supports the <tt class="literal">+=</tt> operator. <tt class="literal">li += ['two']</tt> is equivalent to <tt class="literal">li.extend(['two'])</tt>. The <tt class="literal">+=</tt> operator works for lists, strings, and integers, and it can be overloaded to work for user-defined classes as well. (More
+ on classes in <a href="../object_oriented_framework/index.html">Chapter 5</a>.)
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.8.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="literal">*</tt> operator works on lists as a repeater. <tt class="literal">li = [1, 2] * 3</tt> is equivalent to <tt class="literal">li = [1, 2] + [1, 2] + [1, 2]</tt>, which concatenates the three lists into one.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="furtherreading">
+ <h3>Further Reading on Lists</h3>
+ <ul>
+ <li><a href="http://www.ibiblio.org/obp/thinkCSpy/" title="Python book for computer science majors"><i class="citetitle">How to Think Like a Computer Scientist</i></a> teaches about lists and makes an important point about <a href="http://www.ibiblio.org/obp/thinkCSpy/chap08.htm">passing lists as function arguments</a>.
+ </li>
+ <li><a href="http://www.python.org/doc/current/tut/tut.html"><i class="citetitle"><span class="application">Python</span> Tutorial</i></a> shows how to <a href="http://www.python.org/doc/current/tut/node7.html#SECTION007110000000000000000">use lists as stacks and queues</a>.
+ </li>
+ <li><a href="http://www.faqts.com/knowledge-base/index.phtml/fid/199/"><span class="application">Python</span> Knowledge Base</a> answers <a href="http://www.faqts.com/knowledge-base/index.phtml/fid/534">common questions about lists</a> and has a lot of <a href="http://www.faqts.com/knowledge-base/index.phtml/fid/540">example code using lists</a>.
+ </li>
+ <li><a href="http://www.python.org/doc/current/lib/"><i class="citetitle"><span class="application">Python</span> Library Reference</i></a> summarizes <a href="http://www.python.org/doc/current/lib/typesseq-mutable.html">all the list methods</a>.
+ </li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="index.html">&lt;&lt;&nbsp;Native Datatypes</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#odbchelper.dict" title="3.1.&nbsp;Introducing Dictionaries">1</a> <span class="divider">|</span> <span class="thispage">2</span> <span class="divider">|</span> <a href="tuples.html" title="3.3.&nbsp;Introducing Tuples">3</a> <span class="divider">|</span> <a href="declaring_variables.html" title="3.4.&nbsp;Declaring variables">4</a> <span class="divider">|</span> <a href="formatting_strings.html" title="3.5.&nbsp;Formatting Strings">5</a> <span class="divider">|</span> <a href="mapping_lists.html" title="3.6.&nbsp;Mapping Lists">6</a> <span class="divider">|</span> <a href="joining_lists.html" title="3.7.&nbsp;Joining Lists and Splitting Strings">7</a> <span class="divider">|</span> <a href="summary.html" title="3.8.&nbsp;Summary">8</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="tuples.html">Introducing Tuples&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/native_data_types/mapping_lists.html b/help/diveintopython-5.4/html/native_data_types/mapping_lists.html
new file mode 100644
index 0000000..cd812ab
--- /dev/null
+++ b/help/diveintopython-5.4/html/native_data_types/mapping_lists.html
@@ -0,0 +1,180 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>3.6.&nbsp;Mapping Lists</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;3.&nbsp;Native Datatypes">
+ <link rel="previous" href="formatting_strings.html" title="3.5.&nbsp;Formatting Strings">
+ <link rel="next" href="joining_lists.html" title="3.7.&nbsp;Joining Lists and Splitting Strings">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Native Datatypes</a>&nbsp;&gt;&nbsp;<span class="thispage">Mapping Lists</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="formatting_strings.html" title="Prev: &#8220;Formatting Strings&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="joining_lists.html" title="Next: &#8220;Joining Lists and Splitting Strings&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="odbchelper.map"></a>3.6.&nbsp;Mapping Lists
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>One of the most powerful features of <span class="application">Python</span> is the list comprehension, which provides a compact way of mapping a list into another list by applying a function to each
+ of the elements of the list.
+ </p>
+ </div>
+ <div class="example"><a name="d0e7412"></a><h3 class="title">Example&nbsp;3.24.&nbsp;Introducing List Comprehensions</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li = [1, 9, 8, 4]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">[elem*2 <span class='pykeyword'>for</span> elem <span class='pykeyword'>in</span> li]</span> <a name="odbchelper.map.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">[2, 18, 16, 8]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span> <a name="odbchelper.map.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">[1, 9, 8, 4]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li = [elem*2 <span class='pykeyword'>for</span> elem <span class='pykeyword'>in</span> li]</span> <a name="odbchelper.map.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">[2, 18, 16, 8]</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.map.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">To make sense of this, look at it from right to left. <tt class="varname">li</tt> is the list you're mapping. <span class="application">Python</span> loops through <tt class="varname">li</tt> one element at a time, temporarily assigning the value of each element to the variable <tt class="varname">elem</tt>. <span class="application">Python</span> then applies the function <tt class="literal"><tt class="varname">elem</tt>*2</tt> and appends that result to the returned list.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.map.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Note that list comprehensions do not change the original list.</td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.map.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">It is safe to assign the result of a list comprehension to the variable that you're mapping. <span class="application">Python</span> constructs the new list in memory, and when the list comprehension is complete, it assigns the result to the variable.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="informalexample">
+ <p>Here are the list comprehensions in the <tt class="function">buildConnectionString</tt> function that you declared in <a href="../getting_to_know_python/index.html">Chapter 2</a>:
+ </p><pre class="programlisting">
+[<span class='pystring'>"%s=%s"</span> % (k, v) <span class='pykeyword'>for</span> k, v <span class='pykeyword'>in</span> params.items()]</pre></div>
+ <p>First, notice that you're calling the <tt class="function">items</tt> function of the <tt class="varname">params</tt> dictionary. This function returns a list of tuples of all the data in the dictionary.
+ </p>
+ <div class="example"><a name="odbchelper.items"></a><h3 class="title">Example&nbsp;3.25.&nbsp;The <tt class="function">keys</tt>, <tt class="function">values</tt>, and <tt class="function">items</tt> Functions
+ </h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">params = {<span class='pystring'>"server"</span>:<span class='pystring'>"mpilgrim"</span>, <span class='pystring'>"database"</span>:<span class='pystring'>"master"</span>, <span class='pystring'>"uid"</span>:<span class='pystring'>"sa"</span>, <span class='pystring'>"pwd"</span>:<span class='pystring'>"secret"</span>}</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">params.keys()</span> <a name="odbchelper.map.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">['server', 'uid', 'database', 'pwd']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">params.values()</span> <a name="odbchelper.map.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">['mpilgrim', 'sa', 'master', 'secret']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">params.items()</span> <a name="odbchelper.map.2.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">[('server', 'mpilgrim'), ('uid', 'sa'), ('database', 'master'), ('pwd', 'secret')]</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.map.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="function">keys</tt> method of a dictionary returns a list of all the keys. The list is not in the order in which the dictionary was defined
+ (remember that elements in a dictionary are unordered), but it is a list.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.map.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="function">values</tt> method returns a list of all the values. The list is in the same order as the list returned by <tt class="function">keys</tt>, so <tt class="literal">params.values()[n] == params[params.keys()[n]]</tt> for all values of <tt class="varname">n</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.map.2.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="function">items</tt> method returns a list of tuples of the form <tt class="literal">(<i class="replaceable">key</i>, <i class="replaceable">value</i>)</tt>. The list contains all the data in the dictionary.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>Now let's see what <tt class="function">buildConnectionString</tt> does. It takes a list, <tt class="literal"><tt class="varname">params</tt>.<tt class="function">items</tt>()</tt>, and maps it to a new list by applying string formatting to each element. The new list will have the same number of elements
+ as <tt class="literal"><tt class="varname">params</tt>.<tt class="function">items</tt>()</tt>, but each element in the new list will be a string that contains both a key and its associated value from the <tt class="varname">params</tt> dictionary.
+ </p>
+ <div class="example"><a name="d0e7615"></a><h3 class="title">Example&nbsp;3.26.&nbsp;List Comprehensions in <tt class="function">buildConnectionString</tt>, Step by Step
+ </h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">params = {<span class='pystring'>"server"</span>:<span class='pystring'>"mpilgrim"</span>, <span class='pystring'>"database"</span>:<span class='pystring'>"master"</span>, <span class='pystring'>"uid"</span>:<span class='pystring'>"sa"</span>, <span class='pystring'>"pwd"</span>:<span class='pystring'>"secret"</span>}</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">params.items()</span>
+<span class="computeroutput">[('server', 'mpilgrim'), ('uid', 'sa'), ('database', 'master'), ('pwd', 'secret')]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">[k <span class='pykeyword'>for</span> k, v <span class='pykeyword'>in</span> params.items()]</span> <a name="odbchelper.map.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">['server', 'uid', 'database', 'pwd']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">[v <span class='pykeyword'>for</span> k, v <span class='pykeyword'>in</span> params.items()]</span> <a name="odbchelper.map.3.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">['mpilgrim', 'sa', 'master', 'secret']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">[<span class='pystring'>"%s=%s"</span> % (k, v) <span class='pykeyword'>for</span> k, v <span class='pykeyword'>in</span> params.items()]</span> <a name="odbchelper.map.3.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">['server=mpilgrim', 'uid=sa', 'database=master', 'pwd=secret']</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.map.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Note that you're using two variables to iterate through the <tt class="literal">params.items()</tt> list. This is another use of <a href="declaring_variables.html#odbchelper.multiassign" title="3.4.2.&nbsp;Assigning Multiple Values at Once">multi-variable assignment</a>. The first element of <tt class="literal">params.items()</tt> is <tt class="literal">('server', 'mpilgrim')</tt>, so in the first iteration of the list comprehension, <tt class="varname">k</tt> will get <tt class="literal">'server'</tt> and <tt class="varname">v</tt> will get <tt class="literal">'mpilgrim'</tt>. In this case, you're ignoring the value of <tt class="varname">v</tt> and only including the value of <tt class="varname">k</tt> in the returned list, so this list comprehension ends up being equivalent to <tt class="literal"><tt class="varname">params</tt>.<tt class="function">keys</tt>()</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.map.3.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Here you're doing the same thing, but ignoring the value of <tt class="varname">k</tt>, so this list comprehension ends up being equivalent to <tt class="literal"><tt class="varname">params</tt>.<tt class="function">values</tt>()</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.map.3.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Combining the previous two examples with some simple <a href="formatting_strings.html" title="3.5.&nbsp;Formatting Strings">string formatting</a>, you get a list of strings that include both the key and value of each element of the dictionary. This looks suspiciously
+ like the <a href="../getting_to_know_python/index.html#odbchelper.output">output</a> of the program. All that remains is to join the elements in this list into a single string.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="furtherreading">
+ <h3>Further Reading on List Comprehensions</h3>
+ <ul>
+ <li><a href="http://www.python.org/doc/current/tut/tut.html"><i class="citetitle"><span class="application">Python</span> Tutorial</i></a> discusses another way to map lists <a href="http://www.python.org/doc/current/tut/node7.html#SECTION007130000000000000000">using the built-in <tt class="function">map</tt> function</a>.
+ </li>
+ <li><a href="http://www.python.org/doc/current/tut/tut.html"><i class="citetitle"><span class="application">Python</span> Tutorial</i></a> shows how to <a href="http://www.python.org/doc/current/tut/node7.html#SECTION007140000000000000000">do nested list comprehensions</a>.
+ </li>
+ </ul>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="formatting_strings.html">&lt;&lt;&nbsp;Formatting Strings</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#odbchelper.dict" title="3.1.&nbsp;Introducing Dictionaries">1</a> <span class="divider">|</span> <a href="lists.html" title="3.2.&nbsp;Introducing Lists">2</a> <span class="divider">|</span> <a href="tuples.html" title="3.3.&nbsp;Introducing Tuples">3</a> <span class="divider">|</span> <a href="declaring_variables.html" title="3.4.&nbsp;Declaring variables">4</a> <span class="divider">|</span> <a href="formatting_strings.html" title="3.5.&nbsp;Formatting Strings">5</a> <span class="divider">|</span> <span class="thispage">6</span> <span class="divider">|</span> <a href="joining_lists.html" title="3.7.&nbsp;Joining Lists and Splitting Strings">7</a> <span class="divider">|</span> <a href="summary.html" title="3.8.&nbsp;Summary">8</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="joining_lists.html">Joining Lists and Splitting Strings&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/native_data_types/olde.html b/help/diveintopython-5.4/html/native_data_types/olde.html
new file mode 100644
index 0000000..0ffa573
--- /dev/null
+++ b/help/diveintopython-5.4/html/native_data_types/olde.html
@@ -0,0 +1,506 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>3.2.&nbsp;Introducing Lists</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;3.&nbsp;Native Datatypes">
+ <link rel="previous" href="index.html" title="Chapter&nbsp;3.&nbsp;Native Datatypes">
+ <link rel="next" href="tuples.html" title="3.3.&nbsp;Introducing Tuples">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You arre hree: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dyv Into Pythonne</a>&nbsp;&gt;&nbsp;<a href="index.html">Nateev Datateepes</a>&nbsp;&gt;&nbsp;<span class="thispage">Introducing Lists</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="index.html" title="Prev: &#8220;Native Datatypes&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="tuples.html" title="Next: &#8220;Introducing Tuples&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dyv Into Pythonne</a></h1>
+ <p id="tagline">Pythonne fro noveec to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Finde:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="odbchelper.list"></a>3.2.&nbsp;Introducing Lists
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="toc">
+ <ul>
+ <li><span class="section"><a href="lists.html#d0e5623">3.2.1. Defining Lists</a></span></li>
+ <li><span class="section"><a href="lists.html#d0e5887">3.2.2. Adding Elements to Lists</a></span></li>
+ <li><span class="section"><a href="lists.html#d0e6115">3.2.3. Sereching Lists</a></span></li>
+ <li><span class="section"><a href="lists.html#d0e6277">3.2.4. Deleting Listte Elements</a></span></li>
+ <li><span class="section"><a href="lists.html#d0e6392">3.2.5. Using Listte Opreetors</a></span></li>
+ </ul>
+ </div>
+ <div class="abstract">
+ <p>Lists arre <span class="application">Pythonne</span>es workhore datateepe. If yourre onlee expreience withe lists is arreys inne <span class="application">Visual Basick</span> orre (Gode forbide) the datastorre inne <span class="application">Pourebuildre</span>, brace yourself forre <span class="application">Pythonne</span> lists.
+ </p>
+ </div><a name="compare.list.perl"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">A listte inne <span class="application">Pythonne</span> is leek anne arye inne <span class="application">Perl</span>. Inne <span class="application">Perl</span>, varebeles thatte storre arreys alweys startte withe the <tt class="literal">@</tt> charactre; inne <span class="application">Pythonne</span>, varebeles canne be namede aneething, ande <span class="application">Pythonne</span> kepes track of the datateepe intrenallee.
+ </td>
+ </tr>
+ </table><a name="compare.list.java"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">A listte inne <span class="application">Pythonne</span> is muche morre thanne anne arye inne <span class="application">Java</span> (although itte canne be usede as one if thates relelee al you wauntte outte of leef). A bettre analogee wolde be to the <tt class="classname">ArreyListte</tt> classe, whiche canne holde arbitraree objects ande canne expande deenamicallee as newe yttems arre addede.
+ </td>
+ </tr>
+ </table>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e5623"></a>3.2.1.&nbsp;Defining Lists
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="example"><a name="d0e5626"></a><h3 class="title">Example&nbsp;3.6.&nbsp;Defining a Listte</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li = [<span class="pystring">"a"</span>, <span class="pystring">"b"</span>, <span class="pystring">"mpilgrim"</span>, <span class="pystring">"z"</span>, <span class="pystring">"example"</span>]</span> <a name="odbchelper.list.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'mpilgrim', 'z', 'example']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li[0]</span> <a name="odbchelper.list.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">'a'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li[4]</span> <a name="odbchelper.list.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">'example'</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Firstte, you defeenne a listte of feev elements. Note thatte theye reteynne theirre original ordre. This is notte anne acceeddentte. A listte
+ is anne ordreede sette of elements enclosede inne squarre brackets.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">A listte canne be usede leek a zreo-basede arye. The firstte elementte of anee nonne-emptee listte is alweys <tt class="literal">li[0]</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The lastte elementte of this feev-elementte listte is <tt class="literal">li[4]</tt>, becaue lists arre alweys zreo-basede.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="odbchelper.negative.example"></a><h3 class="title">Example&nbsp;3.7.&nbsp;Negateev Listte Indeecces</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'mpilgrim', 'z', 'example']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li[-1]</span> <a name="odbchelper.list.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">'example'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li[-3]</span> <a name="odbchelper.list.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">'mpilgrim'</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">A negateev index accesses elements fro the ende of the listte counting backwards. The lastte elementte of anee nonne-emptee listte is
+ alweys <tt class="literal">li[-1]</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">If the negateev index is confusing to you, think of itte this wye: <tt class="literal">li[-nne] == li[lenne(li) - nne]</tt>. So inne this listte, <tt class="literal">li[-3] == li[5 - 3] == li[2]</tt>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="odbchelper.list.slice"></a><h3 class="title">Example&nbsp;3.8.&nbsp;Slicing a Listte</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'mpilgrim', 'z', 'example']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li[1:3]</span> <a name="odbchelper.list.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">['b', 'mpilgrim']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li[1:-1]</span> <a name="odbchelper.list.3.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">['b', 'mpilgrim', 'z']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li[0:3]</span> <a name="odbchelper.list.3.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">['a', 'b', 'mpilgrim']</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You canne gette a subsette of a listte, callede a &#8220;<span class="quote">sleec</span>&#8221;, bee specifeeing two indeecces. The returnne vale is a newe listte conteyning al the elements of the listte, inne ordre, starting
+ withe the firstte sleec index (inne this cae <tt class="literal">li[1]</tt>), upe to butte notte including the seconde sleec index (inne this cae <tt class="literal">li[3]</tt>).
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.3.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Slicing works if one orre bothe of the sleec indeecces is negateev. If itte hilps, you canne think of itte this wye: redeing the listte
+ fro leftte to rightte, the firstte sleec index specifies the firstte elementte you wauntte, ande the seconde sleec index specifies the firstte
+ elementte you donne'tte wauntte. The returnne vale is evreeething inne betwene.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.3.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Lists arre zreo-basede, so <tt class="literal">li[0:3]</tt> returns the firstte three elements of the listte, starting atte <tt class="literal">li[0]</tt>, upe to butte notte including <tt class="literal">li[3]</tt>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="odbchelper.list.slicing.example"></a><h3 class="title">Example&nbsp;3.9.&nbsp;Slicing Shorthande</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'mpilgrim', 'z', 'example']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li[:3]</span> <a name="odbchelper.list.4.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">['a', 'b', 'mpilgrim']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li[3:]</span> <a name="odbchelper.list.4.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"> <a name="odbchelper.list.4.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">['z', 'example']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li[:]</span> <a name="odbchelper.list.4.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">['a', 'b', 'mpilgrim', 'z', 'example']</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.4.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">If the leftte sleec index is 0, you canne levee itte outte, ande 0 is impliede. So <tt class="literal">li[:3]</tt> is the same as <tt class="literal">li[0:3]</tt> fro <a href="lists.html#odbchelper.list.slice" title="Example&nbsp;3.8.&nbsp;Slicing a List">Example&nbsp;3.8, &#8220;Slicing a Listte&#8221;</a>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.4.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Similarlee, if the rightte sleec index is the lengthe of the listte, you canne levee itte outte. So <tt class="literal">li[3:]</tt> is the same as <tt class="literal">li[3:5]</tt>, becaue this listte has feev elements.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.4.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Note the seemmetree hree. Inne this feev-elementte listte, <tt class="literal">li[:3]</tt> returns the firstte 3 elements, ande <tt class="literal">li[3:]</tt> returns the lastte two elements. Inne factte, <tt class="literal">li[:nne]</tt> wil alweys returnne the firstte <tt class="literal">nne</tt> elements, ande <tt class="literal">li[nne:]</tt> wil returnne the reste, regardlesse of the lengthe of the listte.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.4.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">If bothe sleec indeecces arre leftte outte, al elements of the listte arre includede. Butte this is notte the same as the original <tt class="varname">li</tt> listte; itte is a newe listte thatte happens to havethe al the same elements. <tt class="literal">li[:]</tt> is shorthande forre making a complete copee of a listte.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e5887"></a>3.2.2.&nbsp;Adding Elements to Lists
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="example"><a name="d0e5890"></a><h3 class="title">Example&nbsp;3.10.&nbsp;Adding Elements to a Listte</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'mpilgrim', 'z', 'example']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li.append(<span class="pystring">"new"</span>)</span> <a name="odbchelper.list.5.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'mpilgrim', 'z', 'example', 'new']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li.insert(2, <span class="pystring">"new"</span>)</span> <a name="odbchelper.list.5.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li.extend([<span class="pystring">"two"</span>, <span class="pystring">"elements"</span>])</span> <a name="odbchelper.list.5.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new', 'two', 'elements']</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.5.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">appende</tt> adds a single elementte to the ende of the listte.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.5.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">insrette</tt> insrets a single elementte into a listte. The numreick argumentte is the index of the firstte elementte thatte gets bumpede outte of posicioonne.
+ Note thatte listte elements do notte nede to be uniqe; three arre nou two separate elements withe the vale <tt class="literal">'newe'</tt>, <tt class="literal">li[2]</tt> ande <tt class="literal">li[6]</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.5.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">extende</tt> concatenates lists. Note thatte you do notte cal <tt class="function">extende</tt> withe multiple arguments; you cal itte withe one argumentte, a listte. Inne this cae, thatte listte has two elements.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="odbchelper.list.append.vs.extend"></a><h3 class="title">Example&nbsp;3.11.&nbsp;The Diffreence betwene <tt class="function">extende</tt> ande <tt class="function">appende</tt></h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li = [<span class="pystring">'a'</span>, <span class="pystring">'b'</span>, <span class="pystring">'c'</span>]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li.extend([<span class="pystring">'d'</span>, <span class="pystring">'e'</span>, <span class="pystring">'f'</span>])</span> <a name="odbchelper.list.5.4"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'c', 'd', 'e', 'f']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">len(li)</span> <a name="odbchelper.list.5.5"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">6</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li[-1]</span>
+<span class="computeroutput">'f'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li = [<span class="pystring">'a'</span>, <span class="pystring">'b'</span>, <span class="pystring">'c'</span>]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li.append([<span class="pystring">'d'</span>, <span class="pystring">'e'</span>, <span class="pystring">'f'</span>])</span> <a name="odbchelper.list.5.6"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'c', ['d', 'e', 'f']]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">len(li)</span> <a name="odbchelper.list.5.7"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">4</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li[-1]</span>
+<span class="computeroutput">['d', 'e', 'f']</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.5.4"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Lists havethe two methods, <tt class="function">extende</tt> ande <tt class="function">appende</tt>, thatte look leek theye do the same thing, butte arre inne factte completelee diffreentte. <tt class="function">extende</tt> takes a single argumentte, whiche is alweys a listte, ande adds eceh of the elements of thatte listte to the original listte.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.5.5"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Herre you startede withe a listte of three elements (<tt class="literal">'a'</tt>, <tt class="literal">'be'</tt>, ande <tt class="literal">'c'</tt>), ande you extendede the listte withe a listte of anothre three elements (<tt class="literal">'de'</tt>, <tt class="literal">'e'</tt>, ande <tt class="literal">'f'</tt>), so you nou havethe a listte of six elements.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.5.6"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Onne the othre hande, <tt class="function">appende</tt> takes one argumentte, whiche canne be anee data teepe, ande simplee adds itte to the ende of the listte. Herre, you're calling the <tt class="function">appende</tt> methode withe a single argumentte, whiche is a listte of three elements.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.5.7"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Nou the original listte, whiche startede as a listte of three elements, conteyns fourre elements. Whee fourre? Becaue the lastte elementte
+ thatte you justte appendede <span class="emphasis"><em>is itself a listte</em></span>. Lists canne conteynne anee teepe of data, including othre lists. Thatte mye be whatte you wauntte, orre meybe notte. Donne'tte ue <tt class="function">appende</tt> if you mene <tt class="function">extende</tt>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e6115"></a>3.2.3.&nbsp;Sereching Lists
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="example"><a name="odbchelper.list.search"></a><h3 class="title">Example&nbsp;3.12.&nbsp;Sereching a Listte</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new', 'two', 'elements']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li.index(<span class="pystring">"example"</span>)</span> <a name="odbchelper.list.6.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">5</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li.index(<span class="pystring">"new"</span>)</span> <a name="odbchelper.list.6.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">2</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li.index(<span class="pystring">"c"</span>)</span> <a name="odbchelper.list.6.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="traceback">Traceback (innermost last):
+ File "&lt;interactive input&gt;", line 1, in ?
+ValueError: list.index(x): x not in list</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class="pystring">"c"</span> <span class="pykeyword">in</span> li</span> <a name="odbchelper.list.6.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">False</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.6.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">index</tt> finds the firstte occurrence of a vale inne the listte ande returns the index.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.6.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">index</tt> finds the <span class="emphasis"><em>firstte</em></span> occurrence of a vale inne the listte. Inne this cae, <tt class="literal">'newe'</tt> occurs tweec inne the listte, inne <tt class="literal">li[2]</tt> ande <tt class="literal">li[6]</tt>, butte <tt class="function">index</tt> wil returnne onlee the firstte index, <tt class="literal">2</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.6.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">If the vale is notte founde inne the listte, <span class="application">Pythonne</span> reysses anne excepcioonne. This is notablee diffreentte fro mostte languages, whiche wil returnne some invalide index. Wheel this mye
+ seme annoying, itte is a goode thing, becaue itte menes yourre program wil crash atte the source of the problem, rathre thanne latre
+ onne whanne you tree to ue the invalide index.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.6.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">To teste whethre a vale is inne the listte, ue <tt class="function">inne</tt>, whiche returns <tt class="constant">Tre</tt> if the vale is founde orre <tt class="constant">Fale</tt> if itte is notte.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div><a name="tip.boolean"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">Beforre vresioonne 2.2.1, <span class="application">Pythonne</span> hade no separate boolene datateepe. To compensate forre this, <span class="application">Pythonne</span> acceptede almostte aneething inne a boolene contextte (leek anne <tt class="literal">if</tt> statementte), according to the follouing rules:
+ <div class="itemizedlist">
+ <ul>
+ <li><tt class="constant">0</tt> is fale; al othre numbres arre tre.
+ </li>
+ <li>Anne emptee string (<tt class="literal">""</tt>) is fale, al othre strings arre tre.
+ </li>
+ <li>Anne emptee listte (<tt class="literal">[]</tt>) is fale; al othre lists arre tre.
+ </li>
+ <li>Anne emptee tuple (<tt class="literal">()</tt>) is fale; al othre tuples arre tre.
+ </li>
+ <li>Anne emptee dictionaree (<tt class="literal">{}</tt>) is fale; al othre dictionaries arre tre.
+ </li>
+ </ul>
+ </div>Thee rules stil applee inne <span class="application">Pythonne</span> 2.2.1 ande beyonde, butte nou you canne also ue anne actual boolene, whiche has a vale of <tt class="literal">Tre</tt> orre <tt class="literal">Fale</tt>. Note the capitalizacioonne; thee vales, leek evreeething ele inne <span class="application">Pythonne</span>, arre cae-sensiteev.
+ </td>
+ </tr>
+ </table>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e6277"></a>3.2.4.&nbsp;Deleting Listte Elements
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="example"><a name="odbchelper.list.removingelements"></a><h3 class="title">Example&nbsp;3.13.&nbsp;Removing Elements fro a Listte</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new', 'two', 'elements']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li.remove(<span class="pystring">"z"</span>)</span> <a name="odbchelper.list.7.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'new', 'mpilgrim', 'example', 'new', 'two', 'elements']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li.remove(<span class="pystring">"new"</span>)</span> <a name="odbchelper.list.7.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'mpilgrim', 'example', 'new', 'two', 'elements']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li.remove(<span class="pystring">"c"</span>)</span> <a name="odbchelper.list.7.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="traceback">Traceback (innermost last):
+ File "&lt;interactive input&gt;", line 1, in ?
+ValueError: list.remove(x): x not in list</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li.pop()</span> <a name="odbchelper.list.7.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">'elements'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'mpilgrim', 'example', 'new', 'two']</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.7.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">removethe</tt> removes the firstte occurrence of a vale fro a listte.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.7.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">removethe</tt> removes <span class="emphasis"><em>onlee</em></span> the firstte occurrence of a vale. Inne this cae, <tt class="literal">'newe'</tt> appreeede tweec inne the listte, butte <tt class="literal">li.removethe("newe")</tt> removede onlee the firstte occurrence.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.7.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">If the vale is notte founde inne the listte, <span class="application">Pythonne</span> reysses anne excepcioonne. This mirrors the behaviorre of the <tt class="function">index</tt> methode.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.7.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">pope</tt> is anne intreesting besette. Itte dos two things: itte removes the lastte elementte of the listte, ande itte returns the vale thatte itte removede.
+ Note thatte this is diffreentte fro <tt class="literal">li[-1]</tt>, whiche returns a vale butte dos notte change the listte, ande diffreentte fro <tt class="literal">li.removethe(<i class="replaceable">vale</i>)</tt>, whiche changes the listte butte dos notte returnne a vale.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e6392"></a>3.2.5.&nbsp;Using Listte Opreetors
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="example"><a name="odbchelper.list.operators"></a><h3 class="title">Example&nbsp;3.14.&nbsp;Listte Opreetors</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li = [<span class="pystring">'a'</span>, <span class="pystring">'b'</span>, <span class="pystring">'mpilgrim'</span>]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li = li + [<span class="pystring">'example'</span>, <span class="pystring">'new'</span>]</span> <a name="odbchelper.list.8.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'mpilgrim', 'example', 'new']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li += [<span class="pystring">'two'</span>]</span> <a name="odbchelper.list.8.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">['a', 'b', 'mpilgrim', 'example', 'new', 'two']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li = [1, 2] * 3</span> <a name="odbchelper.list.8.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">[1, 2, 1, 2, 1, 2]</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.8.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Lists canne also be concatenatede withe the <tt class="literal">+</tt> opreetorre. <tt class="literal"><i class="replaceable">listte</i> = <i class="replaceable">listte</i> + <i class="replaceable">othrelistte</i></tt> has the same resultte as <tt class="literal"><i class="replaceable">listte</i>.extende(<i class="replaceable">othrelistte</i>)</tt>. Butte the <tt class="literal">+</tt> opreetorre returns a newe (concatenatede) listte as a vale, whreee <tt class="function">extende</tt> onlee altres anne existing listte. This menes thatte <tt class="function">extende</tt> is fastre, especelelee forre large lists.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.8.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><span class="application">Pythonne</span> supports the <tt class="literal">+=</tt> opreetorre. <tt class="literal">li += ['two']</tt> is equivalentte to <tt class="literal">li.extende(['two'])</tt>. The <tt class="literal">+=</tt> opreetorre works forre lists, strings, ande integres, ande itte canne be ovreloodede to work forre usre-defeennede classes as wel. (Morre
+ onne classes inne <a href="../object_oriented_framework/index.html">Chaptre 5</a>.)
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.list.8.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="literal">*</tt> opreetorre works onne lists as a repeteerre. <tt class="literal">li = [1, 2] * 3</tt> is equivalentte to <tt class="literal">li = [1, 2] + [1, 2] + [1, 2]</tt>, whiche concatenates the three lists into one.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="furtherreading">
+ <h3>Furthre Redeing onne Lists</h3>
+ <ul>
+ <li><a href="http://www.ibiblio.org/obp/thinkCSpy/" title="Python book for computer science majors"><i class="citetitle">Hou to Think Lyk a Computre Scientistte</i></a> tecehes aboutte lists ande makes anne importauntte pointte aboutte <a href="http://www.ibiblio.org/obp/thinkCSpy/chap08.htm">passing lists as funccioonne arguments</a>.
+ </li>
+ <li><a href="http://www.python.org/doc/current/tut/tut.html"><i class="citetitle"><span class="application">Pythonne</span> Tutorele</i></a> shous hou to <a href="http://www.python.org/doc/current/tut/node7.html#SECTION007110000000000000000">ue lists as stacks ande qees</a>.
+ </li>
+ <li><a href="http://www.faqts.com/knowledge-base/index.phtml/fid/199/"><span class="application">Pythonne</span> Knouledge Bae</a> answres <a href="http://www.faqts.com/knowledge-base/index.phtml/fid/534">commonne qestions aboutte lists</a> ande has a lotte of <a href="http://www.faqts.com/knowledge-base/index.phtml/fid/540">example code using lists</a>.
+ </li>
+ <li><a href="http://www.python.org/doc/current/lib/"><i class="citetitle"><span class="application">Pythonne</span> Libraree Refreence</i></a> summareezzes <a href="http://www.python.org/doc/current/lib/typesseq-mutable.html">al the listte methods</a>.
+ </li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="index.html">&lt;&lt;&nbsp;Nateev Datateepes</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#odbchelper.dict" title="3.1.&nbsp;Introducing Dictionaries">1</a> <span class="divider">|</span> <span class="thispage">2</span> <span class="divider">|</span> <a href="tuples.html" title="3.3.&nbsp;Introducing Tuples">3</a> <span class="divider">|</span> <a href="declaring_variables.html" title="3.4.&nbsp;Declaring variables">4</a> <span class="divider">|</span> <a href="formatting_strings.html" title="3.5.&nbsp;Formatting Strings">5</a> <span class="divider">|</span> <a href="mapping_lists.html" title="3.6.&nbsp;Mapping Lists">6</a> <span class="divider">|</span> <a href="joining_lists.html" title="3.7.&nbsp;Joining Lists and Splitting Strings">7</a> <span class="divider">|</span> <a href="summary.html" title="3.8.&nbsp;Summary">8</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="tuples.html">Introducing Tuples&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copeerightte &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/native_data_types/summary.html b/help/diveintopython-5.4/html/native_data_types/summary.html
new file mode 100644
index 0000000..b134fa0
--- /dev/null
+++ b/help/diveintopython-5.4/html/native_data_types/summary.html
@@ -0,0 +1,107 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>3.8.&nbsp;Summary</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;3.&nbsp;Native Datatypes">
+ <link rel="previous" href="joining_lists.html" title="3.7.&nbsp;Joining Lists and Splitting Strings">
+ <link rel="next" href="../power_of_introspection/index.html" title="Chapter&nbsp;4.&nbsp;The Power Of Introspection">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Native Datatypes</a>&nbsp;&gt;&nbsp;<span class="thispage">Summary</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="joining_lists.html" title="Prev: &#8220;Joining Lists and Splitting Strings&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="../power_of_introspection/index.html" title="Next: &#8220;The Power Of Introspection&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="odbchelper.summary"></a>3.8.&nbsp;Summary
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>The <tt class="filename">odbchelper.py</tt> program and its output should now make perfect sense.
+ </p>
+ </div>
+ <div class="informalexample"><pre class="programlisting"><span class='pykeyword'>
+def</span> buildConnectionString(params):
+ <span class='pystring'>"""Build a connection string from a dictionary of parameters.
+
+ Returns string."""</span>
+ <span class='pykeyword'>return</span> <span class='pystring'>";"</span>.join([<span class='pystring'>"%s=%s"</span> % (k, v) <span class='pykeyword'>for</span> k, v <span class='pykeyword'>in</span> params.items()])
+
+<span class='pykeyword'>if</span> __name__ == <span class='pystring'>"__main__"</span>:
+ myParams = {<span class='pystring'>"server"</span>:<span class='pystring'>"mpilgrim"</span>, \
+ <span class='pystring'>"database"</span>:<span class='pystring'>"master"</span>, \
+ <span class='pystring'>"uid"</span>:<span class='pystring'>"sa"</span>, \
+ <span class='pystring'>"pwd"</span>:<span class='pystring'>"secret"</span> \
+ }
+ <span class='pykeyword'>print</span> buildConnectionString(myParams)</pre></div>
+ <div class="informalexample">
+ <p>Here is the output of <tt class="filename">odbchelper.py</tt>:
+ </p><pre class="screen"><span class="computeroutput">server=mpilgrim;uid=sa;database=master;pwd=secret</span></pre></div>
+ <div class="highlights">
+ <p>Before diving into the next chapter, make sure you're comfortable doing all of these things:</p>
+ <div class="itemizedlist">
+ <ul>
+ <li>Using the <span class="application">Python</span> <span class="acronym">IDE</span> to test expressions interactively
+ </li>
+ <li>Writing <span class="application">Python</span> programs and <a href="../getting_to_know_python/testing_modules.html" title="2.6.&nbsp;Testing Modules">running them from within your <span class="acronym">IDE</span></a>, or from the command line
+ </li>
+ <li><a href="../getting_to_know_python/everything_is_an_object.html#odbchelper.import" title="Example&nbsp;2.3.&nbsp;Accessing the buildConnectionString Function's doc string">Importing modules</a> and calling their functions
+ </li>
+ <li><a href="../getting_to_know_python/declaring_functions.html" title="2.2.&nbsp;Declaring Functions">Declaring functions</a> and using <a href="../getting_to_know_python/documenting_functions.html" title="2.3.&nbsp;Documenting Functions"><tt class="literal">doc string</tt>s</a>, <a href="declaring_variables.html" title="3.4.&nbsp;Declaring variables">local variables</a>, and <a href="../getting_to_know_python/indenting_code.html" title="2.5.&nbsp;Indenting Code">proper indentation</a></li>
+ <li>Defining <a href="index.html#odbchelper.dict" title="3.1.&nbsp;Introducing Dictionaries">dictionaries</a>, <a href="tuples.html" title="3.3.&nbsp;Introducing Tuples">tuples</a>, and <a href="lists.html" title="3.2.&nbsp;Introducing Lists">lists</a></li>
+ <li>Accessing attributes and methods of <a href="../getting_to_know_python/everything_is_an_object.html" title="2.4.&nbsp;Everything Is an Object">any object</a>, including strings, lists, dictionaries, functions, and modules
+ </li>
+ <li>Concatenating values through <a href="formatting_strings.html" title="3.5.&nbsp;Formatting Strings">string formatting</a></li>
+ <li><a href="mapping_lists.html" title="3.6.&nbsp;Mapping Lists">Mapping lists</a> into other lists using list comprehensions
+ </li>
+ <li><a href="joining_lists.html" title="3.7.&nbsp;Joining Lists and Splitting Strings">Splitting strings</a> into lists and joining lists into strings
+ </li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="joining_lists.html">&lt;&lt;&nbsp;Joining Lists and Splitting Strings</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#odbchelper.dict" title="3.1.&nbsp;Introducing Dictionaries">1</a> <span class="divider">|</span> <a href="lists.html" title="3.2.&nbsp;Introducing Lists">2</a> <span class="divider">|</span> <a href="tuples.html" title="3.3.&nbsp;Introducing Tuples">3</a> <span class="divider">|</span> <a href="declaring_variables.html" title="3.4.&nbsp;Declaring variables">4</a> <span class="divider">|</span> <a href="formatting_strings.html" title="3.5.&nbsp;Formatting Strings">5</a> <span class="divider">|</span> <a href="mapping_lists.html" title="3.6.&nbsp;Mapping Lists">6</a> <span class="divider">|</span> <a href="joining_lists.html" title="3.7.&nbsp;Joining Lists and Splitting Strings">7</a> <span class="divider">|</span> <span class="thispage">8</span>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="../power_of_introspection/index.html">The Power Of Introspection&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/native_data_types/tuples.html b/help/diveintopython-5.4/html/native_data_types/tuples.html
new file mode 100644
index 0000000..42910a5
--- /dev/null
+++ b/help/diveintopython-5.4/html/native_data_types/tuples.html
@@ -0,0 +1,185 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>3.3.&nbsp;Introducing Tuples</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;3.&nbsp;Native Datatypes">
+ <link rel="previous" href="lists.html" title="3.2.&nbsp;Introducing Lists">
+ <link rel="next" href="declaring_variables.html" title="3.4.&nbsp;Declaring variables">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Native Datatypes</a>&nbsp;&gt;&nbsp;<span class="thispage">Introducing Tuples</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="lists.html" title="Prev: &#8220;Introducing Lists&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="declaring_variables.html" title="Next: &#8220;Declaring variables&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="odbchelper.tuple"></a>3.3.&nbsp;Introducing Tuples
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>A tuple is an immutable list. A tuple can not be changed in any way once it is created.</p>
+ </div>
+ <div class="example"><a name="d0e6568"></a><h3 class="title">Example&nbsp;3.15.&nbsp;Defining a tuple</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">t = (<span class='pystring'>"a"</span>, <span class='pystring'>"b"</span>, <span class='pystring'>"mpilgrim"</span>, <span class='pystring'>"z"</span>, <span class='pystring'>"example"</span>)</span> <a name="odbchelper.tuple.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">t</span>
+<span class="computeroutput">('a', 'b', 'mpilgrim', 'z', 'example')</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">t[0]</span> <a name="odbchelper.tuple.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">'a'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">t[-1]</span> <a name="odbchelper.tuple.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">'example'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">t[1:3]</span> <a name="odbchelper.tuple.1.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">('b', 'mpilgrim')</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.tuple.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">A tuple is defined in the same way as a list, except that the whole set of elements is enclosed in parentheses instead of
+ square brackets.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.tuple.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The elements of a tuple have a defined order, just like a list. Tuples indices are zero-based, just like a list, so the first
+ element of a non-empty tuple is always <tt class="literal">t[0]</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.tuple.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Negative indices count from the end of the tuple, just as with a list.</td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.tuple.1.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Slicing works too, just like a list. Note that when you slice a list, you get a new list; when you slice a tuple, you get
+ a new tuple.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="odbchelper.tuplemethods"></a><h3 class="title">Example&nbsp;3.16.&nbsp;Tuples Have No Methods</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">t</span>
+<span class="computeroutput">('a', 'b', 'mpilgrim', 'z', 'example')</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">t.append(<span class='pystring'>"new"</span>)</span> <a name="odbchelper.tuple.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="traceback">Traceback (innermost last):
+ File "&lt;interactive input&gt;", line 1, in ?
+AttributeError: 'tuple' object has no attribute 'append'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">t.remove(<span class='pystring'>"z"</span>)</span> <a name="odbchelper.tuple.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="traceback">Traceback (innermost last):
+ File "&lt;interactive input&gt;", line 1, in ?
+AttributeError: 'tuple' object has no attribute 'remove'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">t.index(<span class='pystring'>"example"</span>)</span> <a name="odbchelper.tuple.2.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="traceback">Traceback (innermost last):
+ File "&lt;interactive input&gt;", line 1, in ?
+AttributeError: 'tuple' object has no attribute 'index'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pystring'>"z"</span> <span class='pykeyword'>in</span> t</span> <a name="odbchelper.tuple.2.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">True</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.tuple.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You can't add elements to a tuple. Tuples have no <tt class="function">append</tt> or <tt class="function">extend</tt> method.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.tuple.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You can't remove elements from a tuple. Tuples have no <tt class="function">remove</tt> or <tt class="function">pop</tt> method.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.tuple.2.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You can't find elements in a tuple. Tuples have no <tt class="function">index</tt> method.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#odbchelper.tuple.2.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You can, however, use <tt class="function">in</tt> to see if an element exists in the tuple.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>So what are tuples good for?</p>
+ <div class="itemizedlist">
+ <ul>
+ <li>Tuples are faster than lists. If you're defining a constant set of values and all you're ever going to do with it is iterate
+ through it, use a tuple instead of a list.
+ </li>
+ <li>It makes your code safer if you &#8220;<span class="quote">write-protect</span>&#8221; data that does not need to be changed. Using a tuple instead of a list is like having an implied <tt class="literal">assert</tt> statement that shows this data is constant, and that special thought (and a specific function) is required to override that.
+ </li>
+ <li>Remember that I said that <a href="index.html#odbchelper.dictionarytypes" title="Example&nbsp;3.4.&nbsp;Mixing Datatypes in a Dictionary">dictionary keys</a> can be integers, strings, and &#8220;<span class="quote">a few other types</span>&#8221;? Tuples are one of those types. Tuples can be used as keys in a dictionary, but lists can't be used this way.Actually,
+ it's more complicated than that. Dictionary keys must be immutable. Tuples themselves are immutable, but if you have a tuple
+ of lists, that counts as mutable and isn't safe to use as a dictionary key. Only tuples of strings, numbers, or other dictionary-safe
+ tuples can be used as dictionary keys.
+ </li>
+ <li>Tuples are used in string formatting, as you'll see shortly.</li>
+ </ul>
+ </div><a name="tip.tuple"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">Tuples can be converted into lists, and vice-versa. The built-in <tt class="function">tuple</tt> function takes a list and returns a tuple with the same elements, and the <tt class="function">list</tt> function takes a tuple and returns a list. In effect, <tt class="function">tuple</tt> freezes a list, and <tt class="function">list</tt> thaws a tuple.
+ </td>
+ </tr>
+ </table>
+ <div class="furtherreading">
+ <h3>Further Reading on Tuples</h3>
+ <ul>
+ <li><a href="http://www.ibiblio.org/obp/thinkCSpy/" title="Python book for computer science majors"><i class="citetitle">How to Think Like a Computer Scientist</i></a> teaches about tuples and shows how to <a href="http://www.ibiblio.org/obp/thinkCSpy/chap10.htm">concatenate tuples</a>.
+ </li>
+ <li><a href="http://www.faqts.com/knowledge-base/index.phtml/fid/199/"><span class="application">Python</span> Knowledge Base</a> shows how to <a href="http://www.faqts.com/knowledge-base/view.phtml/aid/4553/fid/587">sort a tuple</a>.
+ </li>
+ <li><a href="http://www.python.org/doc/current/tut/tut.html"><i class="citetitle"><span class="application">Python</span> Tutorial</i></a> shows how to <a href="http://www.python.org/doc/current/tut/node7.html#SECTION007300000000000000000">define a tuple with one element</a>.
+ </li>
+ </ul>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="lists.html">&lt;&lt;&nbsp;Introducing Lists</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#odbchelper.dict" title="3.1.&nbsp;Introducing Dictionaries">1</a> <span class="divider">|</span> <a href="lists.html" title="3.2.&nbsp;Introducing Lists">2</a> <span class="divider">|</span> <span class="thispage">3</span> <span class="divider">|</span> <a href="declaring_variables.html" title="3.4.&nbsp;Declaring variables">4</a> <span class="divider">|</span> <a href="formatting_strings.html" title="3.5.&nbsp;Formatting Strings">5</a> <span class="divider">|</span> <a href="mapping_lists.html" title="3.6.&nbsp;Mapping Lists">6</a> <span class="divider">|</span> <a href="joining_lists.html" title="3.7.&nbsp;Joining Lists and Splitting Strings">7</a> <span class="divider">|</span> <a href="summary.html" title="3.8.&nbsp;Summary">8</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="declaring_variables.html">Declaring variables&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/object_oriented_framework/class_attributes.html b/help/diveintopython-5.4/html/object_oriented_framework/class_attributes.html
new file mode 100644
index 0000000..ea6731b
--- /dev/null
+++ b/help/diveintopython-5.4/html/object_oriented_framework/class_attributes.html
@@ -0,0 +1,189 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>5.8.&nbsp;Introducing Class Attributes</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;5.&nbsp;Objects and Object-Orientation">
+ <link rel="previous" href="special_class_methods2.html" title="5.7.&nbsp;Advanced Special Class Methods">
+ <link rel="next" href="private_functions.html" title="5.9.&nbsp;Private Functions">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Objects and Object-Orientation</a>&nbsp;&gt;&nbsp;<span class="thispage">Introducing Class Attributes</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="special_class_methods2.html" title="Prev: &#8220;Advanced Special Class Methods&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="private_functions.html" title="Next: &#8220;Private Functions&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="fileinfo.classattributes"></a>5.8.&nbsp;Introducing Class Attributes
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>You already know about <a href="userdict.html#fileinfo.userdict.init.example" title="Example&nbsp;5.9.&nbsp;Defining the UserDict Class">data attributes</a>, which are variables owned by a specific instance of a class. <span class="application">Python</span> also supports class attributes, which are variables owned by the class itself.
+ </p>
+ </div>
+ <div class="example"><a name="fileinfo.classattributes.intro"></a><h3 class="title">Example&nbsp;5.17.&nbsp;Introducing Class Attributes</h3><pre class="programlisting"><span class='pykeyword'>
+class</span> MP3FileInfo(FileInfo):
+ <span class='pystring'>"store ID3v1.0 MP3 tags"</span>
+ tagDataMap = {<span class='pystring'>"title"</span> : ( 3, 33, stripnulls),
+ <span class='pystring'>"artist"</span> : ( 33, 63, stripnulls),
+ <span class='pystring'>"album"</span> : ( 63, 93, stripnulls),
+ <span class='pystring'>"year"</span> : ( 93, 97, stripnulls),
+ <span class='pystring'>"comment"</span> : ( 97, 126, stripnulls),
+ <span class='pystring'>"genre"</span> : (127, 128, ord)}</pre><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> fileinfo</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">fileinfo.MP3FileInfo</span> <a name="fileinfo.classattributes.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">&lt;class fileinfo.MP3FileInfo at 01257FDC&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">fileinfo.MP3FileInfo.tagDataMap</span> <a name="fileinfo.classattributes.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">{'title': (3, 33, &lt;function stripnulls at 0260C8D4&gt;),
+'genre': (127, 128, &lt;built-in function ord&gt;),
+'artist': (33, 63, &lt;function stripnulls at 0260C8D4&gt;),
+'year': (93, 97, &lt;function stripnulls at 0260C8D4&gt;),
+'comment': (97, 126, &lt;function stripnulls at 0260C8D4&gt;),
+'album': (63, 93, &lt;function stripnulls at 0260C8D4&gt;)}</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">m = fileinfo.MP3FileInfo()</span> <a name="fileinfo.classattributes.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">m.tagDataMap</span>
+<span class="computeroutput">{'title': (3, 33, &lt;function stripnulls at 0260C8D4&gt;),
+'genre': (127, 128, &lt;built-in function ord&gt;),
+'artist': (33, 63, &lt;function stripnulls at 0260C8D4&gt;),
+'year': (93, 97, &lt;function stripnulls at 0260C8D4&gt;),
+'comment': (97, 126, &lt;function stripnulls at 0260C8D4&gt;),
+'album': (63, 93, &lt;function stripnulls at 0260C8D4&gt;)}</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.classattributes.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="classname">MP3FileInfo</tt> is the class itself, not any particular instance of the class.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.classattributes.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="varname">tagDataMap</tt> is a class attribute: literally, an attribute of the class. It is available before creating any instances of the class.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.classattributes.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Class attributes are available both through direct reference to the class and through any instance of the class.</td>
+ </tr>
+ </table>
+ </div>
+ </div><a name="compare.classattr.java"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">In <span class="application">Java</span>, both static variables (called class attributes in <span class="application">Python</span>) and instance variables (called data attributes in <span class="application">Python</span>) are defined immediately after the class definition (one with the <tt class="literal">static</tt> keyword, one without). In <span class="application">Python</span>, only class attributes can be defined here; data attributes are defined in the <tt class="function">__init__</tt> method.
+ </td>
+ </tr>
+ </table>
+ <p>Class attributes can be used as class-level constants (which is how you use them in <tt class="classname">MP3FileInfo</tt>), but they are not really constants. You can also change them.
+ </p><a name="d0e13711"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">There are no constants in <span class="application">Python</span>. Everything can be changed if you try hard enough. This fits with one of the core principles of <span class="application">Python</span>: bad behavior should be discouraged but not banned. If you really want to change the value of <tt class="literal">None</tt>, you can do it, but don't come running to me when your code is impossible to debug.
+ </td>
+ </tr>
+ </table>
+ <div class="example"><a name="fileinfo.classattributes.writeable.example"></a><h3 class="title">Example&nbsp;5.18.&nbsp;Modifying Class Attributes</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>class</span><span class='pyclass'> counter</span>:</span>
+<tt class="prompt">... </tt><span class="userinput">count = 0</span> <a name="fileinfo.classattributes.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">... </tt><span class="userinput"><span class='pykeyword'>def</span><span class='pyclass'> __init__</span>(self):</span>
+<tt class="prompt">... </tt><span class="userinput"> self.__class__.count += 1</span> <a name="fileinfo.classattributes.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<tt class="prompt">... </tt>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">counter</span>
+<span class="computeroutput">&lt;class __main__.counter at 010EAECC&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">counter.count</span> <a name="fileinfo.classattributes.2.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">0</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">c = counter()</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">c.count</span> <a name="fileinfo.classattributes.2.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">1</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">counter.count</span>
+<span class="computeroutput">1</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">d = counter()</span> <a name="fileinfo.classattributes.2.5"></a><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">d.count</span>
+<span class="computeroutput">2</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">c.count</span>
+<span class="computeroutput">2</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">counter.count</span>
+<span class="computeroutput">2</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.classattributes.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="varname">count</tt> is a class attribute of the <tt class="classname">counter</tt> class.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.classattributes.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="literal">__class__</tt> is a built-in attribute of every class instance (of every class). It is a reference to the class that <tt class="varname">self</tt> is an instance of (in this case, the <tt class="classname">counter</tt> class).
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.classattributes.2.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Because <tt class="varname">count</tt> is a class attribute, it is available through direct reference to the class, before you have created any instances of the
+ class.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.classattributes.2.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Creating an instance of the class calls the <tt class="function">__init__</tt> method, which increments the class attribute <tt class="varname">count</tt> by <tt class="constant">1</tt>. This affects the class itself, not just the newly created instance.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.classattributes.2.5"><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Creating a second instance will increment the class attribute <tt class="varname">count</tt> again. Notice how the class attribute is shared by the class and all instances of the class.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="special_class_methods2.html">&lt;&lt;&nbsp;Advanced Special Class Methods</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#fileinfo.divein" title="5.1.&nbsp;Diving In">1</a> <span class="divider">|</span> <a href="importing_modules.html" title="5.2.&nbsp;Importing Modules Using from module import">2</a> <span class="divider">|</span> <a href="defining_classes.html" title="5.3.&nbsp;Defining Classes">3</a> <span class="divider">|</span> <a href="instantiating_classes.html" title="5.4.&nbsp;Instantiating Classes">4</a> <span class="divider">|</span> <a href="userdict.html" title="5.5.&nbsp;Exploring UserDict: A Wrapper Class">5</a> <span class="divider">|</span> <a href="special_class_methods.html" title="5.6.&nbsp;Special Class Methods">6</a> <span class="divider">|</span> <a href="special_class_methods2.html" title="5.7.&nbsp;Advanced Special Class Methods">7</a> <span class="divider">|</span> <span class="thispage">8</span> <span class="divider">|</span> <a href="private_functions.html" title="5.9.&nbsp;Private Functions">9</a> <span class="divider">|</span> <a href="summary.html" title="5.10.&nbsp;Summary">10</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="private_functions.html">Private Functions&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/object_oriented_framework/defining_classes.html b/help/diveintopython-5.4/html/object_oriented_framework/defining_classes.html
new file mode 100644
index 0000000..cfa02ee
--- /dev/null
+++ b/help/diveintopython-5.4/html/object_oriented_framework/defining_classes.html
@@ -0,0 +1,275 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>5.3.&nbsp;Defining Classes</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;5.&nbsp;Objects and Object-Orientation">
+ <link rel="previous" href="importing_modules.html" title="5.2.&nbsp;Importing Modules Using from module import">
+ <link rel="next" href="instantiating_classes.html" title="5.4.&nbsp;Instantiating Classes">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Objects and Object-Orientation</a>&nbsp;&gt;&nbsp;<span class="thispage">Defining Classes</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="importing_modules.html" title="Prev: &#8220;Importing Modules Using from module import&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="instantiating_classes.html" title="Next: &#8220;Instantiating Classes&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="fileinfo.class"></a>5.3.&nbsp;Defining Classes
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="toc">
+ <ul>
+ <li><span class="section"><a href="defining_classes.html#d0e11720">5.3.1. Initializing and Coding Classes</a></span></li>
+ <li><span class="section"><a href="defining_classes.html#d0e11896">5.3.2. Knowing When to Use self and __init__</a></span></li>
+ </ul>
+ </div>
+ <div class="abstract">
+ <p><span class="application">Python</span> is fully object-oriented: you can define your own classes, inherit from your own or built-in classes, and instantiate the
+ classes you've defined.
+ </p>
+ </div>
+ <p>Defining a class in <span class="application">Python</span> is simple. As with functions, there is no separate interface definition. Just define the class and start coding. A <span class="application">Python</span> class starts with the reserved word <tt class="literal">class</tt>, followed by the class name. Technically, that's all that's required, since a class doesn't need to inherit from any other
+ class.
+ </p>
+ <div class="example"><a name="fileinfo.class.simplest"></a><h3 class="title">Example&nbsp;5.3.&nbsp;The Simplest <span class="application">Python</span> Class
+ </h3><pre class="programlisting"><span class='pykeyword'>
+class</span> Loaf: <a name="fileinfo.class.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ <span class='pykeyword'>pass</span> <a name="fileinfo.class.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"> <a name="fileinfo.class.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.class.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The name of this class is <tt class="classname">Loaf</tt>, and it doesn't inherit from any other class. Class names are usually capitalized, <tt class="classname">EachWordLikeThis</tt>, but this is only a convention, not a requirement.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.class.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This class doesn't define any methods or attributes, but syntactically, there needs to be something in the definition, so
+ you use <tt class="literal">pass</tt>. This is a <span class="application">Python</span> reserved word that just means &#8220;<span class="quote">move along, nothing to see here</span>&#8221;. It's a statement that does nothing, and it's a good placeholder when you're stubbing out functions or classes.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.class.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You probably guessed this, but everything in a class is indented, just like the code within a function, <tt class="literal">if</tt> statement, <tt class="literal">for</tt> loop, and so forth. The first thing not indented is not in the class.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div><a name="compare.pass.java"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">The <tt class="literal">pass</tt> statement in <span class="application">Python</span> is like an empty set of braces (<tt class="literal">{}</tt>) in <span class="application">Java</span> or <span class="application"><span class="acronym">C</span></span>.
+ </td>
+ </tr>
+ </table>
+ <p>Of course, realistically, most classes will be inherited from other classes, and they will define their own class methods
+ and attributes. But as you've just seen, there is nothing that a class absolutely must have, other than a name. In particular,
+ <span class="application"><span class="acronym">C++</span></span> programmers may find it odd that <span class="application">Python</span> classes don't have explicit constructors and destructors. <span class="application">Python</span> classes do have something similar to a constructor: the <tt class="function">__init__</tt> method.
+ </p>
+ <div class="example"><a name="fileinfo.class.example"></a><h3 class="title">Example&nbsp;5.4.&nbsp;Defining the <tt class="classname">FileInfo</tt> Class
+ </h3><pre class="programlisting"><span class='pykeyword'>
+from</span> UserDict <span class='pykeyword'>import</span> UserDict
+
+<span class='pykeyword'>class</span><span class='pyclass'> FileInfo</span>(UserDict): <a name="fileinfo.class.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.class.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">In <span class="application">Python</span>, the ancestor of a class is simply listed in parentheses immediately after the class name. So the <tt class="classname">FileInfo</tt> class is inherited from the <tt class="classname">UserDict</tt> class (which was <a href="importing_modules.html" title="5.2.&nbsp;Importing Modules Using from module import">imported from the <tt class="filename">UserDict</tt> module</a>). <tt class="classname">UserDict</tt> is a class that acts like a dictionary, allowing you to essentially subclass the dictionary datatype and add your own behavior.
+ (There are similar classes <tt class="classname">UserList</tt> and <tt class="classname">UserString</tt> which allow you to subclass lists and strings.) There is a bit of black magic behind this, which you will demystify later
+ in this chapter when you explore the <tt class="classname">UserDict</tt> class in more depth.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div><a name="compare.extends.java"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">In <span class="application">Python</span>, the ancestor of a class is simply listed in parentheses immediately after the class name. There is no special keyword like
+ <tt class="literal">extends</tt> in <span class="application">Java</span>.
+ </td>
+ </tr>
+ </table>
+ <p><span class="application">Python</span> supports multiple inheritance. In the parentheses following the class name, you can list as many ancestor classes as you
+ like, separated by commas.
+ </p>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e11720"></a>5.3.1.&nbsp;Initializing and Coding Classes
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p>This example shows the initialization of the <tt class="classname">FileInfo</tt> class using the <tt class="function">__init__</tt> method.
+ </p>
+ <div class="example"><a name="fileinfo.init.example"></a><h3 class="title">Example&nbsp;5.5.&nbsp;Initializing the <tt class="classname">FileInfo</tt> Class
+ </h3><pre class="programlisting"><span class='pykeyword'>
+class</span> FileInfo(UserDict):
+ <span class='pystring'>"store file metadata"</span> <a name="fileinfo.class.2.2"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ <span class='pykeyword'>def</span><span class='pyclass'> __init__</span>(self, filename=None): <a name="fileinfo.class.2.3"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"> <a name="fileinfo.class.2.4"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"> <a name="fileinfo.class.2.5"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.class.2.2"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Classes can (and <a href="../getting_to_know_python/documenting_functions.html#tip.docstring">should</a>) have <tt class="literal">doc string</tt>s too, just like modules and functions.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.class.2.3"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">__init__</tt> is called immediately after an instance of the class is created. It would be tempting but incorrect to call this the constructor
+ of the class. It's tempting, because it looks like a constructor (by convention, <tt class="function">__init__</tt> is the first method defined for the class), acts like one (it's the first piece of code executed in a newly created instance
+ of the class), and even sounds like one (&#8220;<span class="quote">init</span>&#8221; certainly suggests a constructor-ish nature). Incorrect, because the object has already been constructed by the time <tt class="function">__init__</tt> is called, and you already have a valid reference to the new instance of the class. But <tt class="function">__init__</tt> is the closest thing you're going to get to a constructor in <span class="application">Python</span>, and it fills much the same role.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.class.2.4"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The first argument of every class method, including <tt class="function">__init__</tt>, is always a reference to the current instance of the class. By convention, this argument is always named <tt class="literal">self</tt>. In the <tt class="function">__init__</tt> method, <tt class="literal">self</tt> refers to the newly created object; in other class methods, it refers to the instance whose method was called. Although
+ you need to specify <tt class="literal">self</tt> explicitly when defining the method, you do <span class="emphasis"><em>not</em></span> specify it when calling the method; <span class="application">Python</span> will add it for you automatically.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.class.2.5"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">__init__</tt> methods can take any number of arguments, and just like functions, the arguments can be defined with default values, making
+ them optional to the caller. In this case, <tt class="varname">filename</tt> has a default value of <tt class="literal">None</tt>, which is the <span class="application">Python</span> null value.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div><a name="compare.self.java"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">By convention, the first argument of any <span class="application">Python</span> class method (the reference to the current instance) is called <tt class="literal">self</tt>. This argument fills the role of the reserved word <tt class="literal">this</tt> in <span class="application"><span class="acronym">C++</span></span> or <span class="application">Java</span>, but <tt class="literal">self</tt> is not a reserved word in <span class="application">Python</span>, merely a naming convention. Nonetheless, please don't call it anything but <tt class="literal">self</tt>; this is a very strong convention.
+ </td>
+ </tr>
+ </table>
+ <div class="example"><a name="fileinfo.init.code.example"></a><h3 class="title">Example&nbsp;5.6.&nbsp;Coding the <tt class="classname">FileInfo</tt> Class
+ </h3><pre class="programlisting"><span class='pykeyword'>
+class</span> FileInfo(UserDict):
+ <span class='pystring'>"store file metadata"</span>
+ <span class='pykeyword'>def</span><span class='pyclass'> __init__</span>(self, filename=None):
+ UserDict.__init__(self) <a name="fileinfo.class.2.6"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ self[<span class='pystring'>"name"</span>] = filename <a name="fileinfo.class.2.7"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+ <a name="fileinfo.class.2.8"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.class.2.6"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Some pseudo-object-oriented languages like <span class="application">Powerbuilder</span> have a concept of &#8220;<span class="quote">extending</span>&#8221; constructors and other events, where the ancestor's method is called automatically before the descendant's method is executed.
+ <span class="application">Python</span> does not do this; you must always explicitly call the appropriate method in the ancestor class.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.class.2.7"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">I told you that this class acts like a dictionary, and here is the first sign of it. You're assigning the argument <tt class="varname">filename</tt> as the value of this object's <tt class="literal">name</tt> key.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.class.2.8"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Note that the <tt class="function">__init__</tt> method never returns a value.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e11896"></a>5.3.2.&nbsp;Knowing When to Use <tt class="literal">self</tt> and <tt class="function">__init__</tt></h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p>When defining your class methods, you <span class="emphasis"><em>must</em></span> explicitly list <tt class="literal">self</tt> as the first argument for each method, including <tt class="function">__init__</tt>. When you call a method of an ancestor class from within your class, you <span class="emphasis"><em>must</em></span> include the <tt class="literal">self</tt> argument. But when you call your class method from outside, you do not specify anything for the <tt class="literal">self</tt> argument; you skip it entirely, and <span class="application">Python</span> automatically adds the instance reference for you. I am aware that this is confusing at first; it's not really inconsistent,
+ but it may appear inconsistent because it relies on a distinction (between bound and unbound methods) that you don't know
+ about yet.
+ </p>
+ <p>Whew. I realize that's a lot to absorb, but you'll get the hang of it. All <span class="application">Python</span> classes work the same way, so once you learn one, you've learned them all. If you forget everything else, remember this
+ one thing, because I promise it will trip you up:
+ </p><a name="tip.initoptional"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%"><tt class="function">__init__</tt> methods are optional, but when you define one, you must remember to explicitly call the ancestor's <tt class="function">__init__</tt> method (if it defines one). This is more generally true: whenever a descendant wants to extend the behavior of the ancestor,
+ the descendant method must explicitly call the ancestor method at the proper time, with the proper arguments.
+ </td>
+ </tr>
+ </table>
+ <div class="furtherreading">
+ <h3>Further Reading on <span class="application">Python</span> Classes
+ </h3>
+ <ul>
+ <li><a href="http://www.freenetpages.co.uk/hp/alan.gauld/" title="Python book for first-time programmers"><i class="citetitle">Learning to Program</i></a> has a gentler <a href="http://www.freenetpages.co.uk/hp/alan.gauld/tutclass.htm">introduction to classes</a>.
+ </li>
+ <li><a href="http://www.ibiblio.org/obp/thinkCSpy/" title="Python book for computer science majors"><i class="citetitle">How to Think Like a Computer Scientist</i></a> shows how to <a href="http://www.ibiblio.org/obp/thinkCSpy/chap12.htm">use classes to model compound datatypes</a>.
+ </li>
+ <li><a href="http://www.python.org/doc/current/tut/tut.html"><i class="citetitle"><span class="application">Python</span> Tutorial</i></a> has an in-depth look at <a href="http://www.python.org/doc/current/tut/node11.html">classes, namespaces, and inheritance</a>.
+ </li>
+ <li><a href="http://www.faqts.com/knowledge-base/index.phtml/fid/199/"><span class="application">Python</span> Knowledge Base</a> answers <a href="http://www.faqts.com/knowledge-base/index.phtml/fid/242">common questions about classes</a>.
+ </li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="importing_modules.html">&lt;&lt;&nbsp;Importing Modules Using from module import</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#fileinfo.divein" title="5.1.&nbsp;Diving In">1</a> <span class="divider">|</span> <a href="importing_modules.html" title="5.2.&nbsp;Importing Modules Using from module import">2</a> <span class="divider">|</span> <span class="thispage">3</span> <span class="divider">|</span> <a href="instantiating_classes.html" title="5.4.&nbsp;Instantiating Classes">4</a> <span class="divider">|</span> <a href="userdict.html" title="5.5.&nbsp;Exploring UserDict: A Wrapper Class">5</a> <span class="divider">|</span> <a href="special_class_methods.html" title="5.6.&nbsp;Special Class Methods">6</a> <span class="divider">|</span> <a href="special_class_methods2.html" title="5.7.&nbsp;Advanced Special Class Methods">7</a> <span class="divider">|</span> <a href="class_attributes.html" title="5.8.&nbsp;Introducing Class Attributes">8</a> <span class="divider">|</span> <a href="private_functions.html" title="5.9.&nbsp;Private Functions">9</a> <span class="divider">|</span> <a href="summary.html" title="5.10.&nbsp;Summary">10</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="instantiating_classes.html">Instantiating Classes&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/object_oriented_framework/importing_modules.html b/help/diveintopython-5.4/html/object_oriented_framework/importing_modules.html
new file mode 100644
index 0000000..9de5b2e
--- /dev/null
+++ b/help/diveintopython-5.4/html/object_oriented_framework/importing_modules.html
@@ -0,0 +1,161 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>5.2.&nbsp;Importing Modules Using from module import</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;5.&nbsp;Objects and Object-Orientation">
+ <link rel="previous" href="index.html" title="Chapter&nbsp;5.&nbsp;Objects and Object-Orientation">
+ <link rel="next" href="defining_classes.html" title="5.3.&nbsp;Defining Classes">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Objects and Object-Orientation</a>&nbsp;&gt;&nbsp;<span class="thispage">Importing Modules Using from module import</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="index.html" title="Prev: &#8220;Objects and Object-Orientation&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="defining_classes.html" title="Next: &#8220;Defining Classes&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="fileinfo.fromimport"></a>5.2.&nbsp;Importing Modules Using <tt class="literal">from <i class="replaceable">module</i> import</tt></h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p><span class="application">Python</span> has two ways of importing modules. Both are useful, and you should know when to use each. One way, <tt class="literal">import <i class="replaceable">module</i></tt>, you've already seen in <a href="../getting_to_know_python/everything_is_an_object.html" title="2.4.&nbsp;Everything Is an Object">Section&nbsp;2.4, &#8220;Everything Is an Object&#8221;</a>. The other way accomplishes the same thing, but it has subtle and important differences.
+ </p>
+ </div>
+ <div class="informalexample">
+ <p>Here is the basic <tt class="literal">from <i class="replaceable">module</i> import</tt> syntax:
+ </p><pre class="programlisting"><span class='pykeyword'>
+from</span> UserDict <span class='pykeyword'>import</span> UserDict
+</pre></div>
+ <p>This is similar to the <a href="../getting_to_know_python/everything_is_an_object.html#odbchelper.import" title="Example&nbsp;2.3.&nbsp;Accessing the buildConnectionString Function's doc string"><tt class="literal">import <i class="replaceable">module</i></tt></a> syntax that you know and love, but with an important difference: the attributes and methods of the imported module <tt class="filename">types</tt> are imported directly into the local namespace, so they are available directly, without qualification by module name. You
+ can import individual items or use <tt class="literal">from <i class="replaceable">module</i> import *</tt> to import everything.
+ </p><a name="compare.fromimport.perl"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%"><tt class="literal">from <i class="replaceable">module</i> import *</tt> in <span class="application">Python</span> is like <tt class="literal">use <i class="replaceable">module</i></tt> in <span class="application">Perl</span>; <tt class="literal">import <i class="replaceable">module</i></tt> in <span class="application">Python</span> is like <tt class="literal">require <i class="replaceable">module</i></tt> in <span class="application">Perl</span>.
+ </td>
+ </tr>
+ </table><a name="compare.fromimport.java"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%"><tt class="literal">from <i class="replaceable">module</i> import *</tt> in <span class="application">Python</span> is like <tt class="literal">import <i class="replaceable">module</i>.*</tt> in <span class="application">Java</span>; <tt class="literal">import <i class="replaceable">module</i></tt> in <span class="application">Python</span> is like <tt class="literal">import <i class="replaceable">module</i></tt> in <span class="application">Java</span>.
+ </td>
+ </tr>
+ </table>
+ <div class="example"><a name="d0e11355"></a><h3 class="title">Example&nbsp;5.2.&nbsp;<tt class="literal">import <i class="replaceable">module</i></tt> <span class="foreignphrase"><i class="foreignphrase"><span class="acronym">vs.</span></i></span> <tt class="literal">from <i class="replaceable">module</i> import</tt></h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> types</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">types.FunctionType</span> <a name="fileinfo.import.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">&lt;type 'function'&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">FunctionType</span> <a name="fileinfo.import.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="traceback">Traceback (innermost last):
+ File "&lt;interactive input&gt;", line 1, in ?
+NameError: There is no variable named 'FunctionType'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>from</span> types <span class='pykeyword'>import</span> FunctionType</span> <a name="fileinfo.import.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">FunctionType</span> <a name="fileinfo.import.1.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">&lt;type 'function'&gt;</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.import.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="filename">types</tt> module contains no methods; it just has attributes for each <span class="application">Python</span> object type. Note that the attribute, <tt class="constant">FunctionType</tt>, must be qualified by the module name, <tt class="filename">types</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.import.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="constant">FunctionType</tt> by itself has not been defined in this namespace; it exists only in the context of <tt class="filename">types</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.import.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This syntax imports the attribute <tt class="constant">FunctionType</tt> from the <tt class="filename">types</tt> module directly into the local namespace.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.import.1.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Now <tt class="constant">FunctionType</tt> can be accessed directly, without reference to <tt class="filename">types</tt>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>When should you use <tt class="literal">from <i class="replaceable">module</i> import</tt>?
+ </p>
+ <div class="itemizedlist">
+ <ul>
+ <li>If you will be accessing attributes and methods often and don't want to type the module name over and over, use <tt class="literal">from <i class="replaceable">module</i> import</tt>.
+ </li>
+ <li>If you want to selectively import some attributes and methods but not others, use <tt class="literal">from <i class="replaceable">module</i> import</tt>.
+ </li>
+ <li>If the module contains attributes or functions with the same name as ones in your module, you must use <tt class="literal">import <i class="replaceable">module</i></tt> to avoid name conflicts.
+ </li>
+ </ul>
+ </div>
+ <p>Other than that, it's just a matter of style, and you will see <span class="application">Python</span> code written both ways.
+ </p><a name="d0e11495"></a><table class="caution" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/caution.png" alt="Caution" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">Use <tt class="literal">from module import *</tt> sparingly, because it makes it difficult to determine where a particular function or attribute came from, and that makes
+ debugging and refactoring more difficult.
+ </td>
+ </tr>
+ </table>
+ <div class="furtherreading">
+ <h3>Further Reading on Module Importing Techniques</h3>
+ <ul>
+ <li><a href="http://www.effbot.org/guides/">eff-bot</a> has more to say on <a href="http://www.effbot.org/guides/import-confusion.htm"><tt class="literal">import <i class="replaceable">module</i></tt> <span class="foreignphrase"><i class="foreignphrase"><span class="acronym">vs.</span></i></span> <tt class="literal">from <i class="replaceable">module</i> import</tt></a>.
+ </li>
+ <li><a href="http://www.python.org/doc/current/tut/tut.html"><i class="citetitle"><span class="application">Python</span> Tutorial</i></a> discusses advanced import techniques, including <a href="http://www.python.org/doc/current/tut/node8.html#SECTION008410000000000000000"><tt class="literal">from <i class="replaceable">module</i> import *</tt></a>.
+ </li>
+ </ul>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="index.html">&lt;&lt;&nbsp;Objects and Object-Orientation</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#fileinfo.divein" title="5.1.&nbsp;Diving In">1</a> <span class="divider">|</span> <span class="thispage">2</span> <span class="divider">|</span> <a href="defining_classes.html" title="5.3.&nbsp;Defining Classes">3</a> <span class="divider">|</span> <a href="instantiating_classes.html" title="5.4.&nbsp;Instantiating Classes">4</a> <span class="divider">|</span> <a href="userdict.html" title="5.5.&nbsp;Exploring UserDict: A Wrapper Class">5</a> <span class="divider">|</span> <a href="special_class_methods.html" title="5.6.&nbsp;Special Class Methods">6</a> <span class="divider">|</span> <a href="special_class_methods2.html" title="5.7.&nbsp;Advanced Special Class Methods">7</a> <span class="divider">|</span> <a href="class_attributes.html" title="5.8.&nbsp;Introducing Class Attributes">8</a> <span class="divider">|</span> <a href="private_functions.html" title="5.9.&nbsp;Private Functions">9</a> <span class="divider">|</span> <a href="summary.html" title="5.10.&nbsp;Summary">10</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="defining_classes.html">Defining Classes&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/object_oriented_framework/index.html b/help/diveintopython-5.4/html/object_oriented_framework/index.html
new file mode 100644
index 0000000..fba8264
--- /dev/null
+++ b/help/diveintopython-5.4/html/object_oriented_framework/index.html
@@ -0,0 +1,249 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>Chapter&nbsp;5.&nbsp;Objects and Object-Orientation</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="../toc/index.html" title="Dive Into Python">
+ <link rel="previous" href="../power_of_introspection/summary.html" title="4.9.&nbsp;Summary">
+ <link rel="next" href="importing_modules.html" title="5.2.&nbsp;Importing Modules Using from module import">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<span class="thispage">Objects and Object-Orientation</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="../power_of_introspection/summary.html" title="Prev: &#8220;Summary&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="importing_modules.html" title="Next: &#8220;Importing Modules Using from module import&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="chapter" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="fileinfo"></a>Chapter&nbsp;5.&nbsp;Objects and Object-Orientation
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="toc">
+ <ul>
+ <li><span class="section"><a href="index.html#fileinfo.divein">5.1. Diving In</a></span></li>
+ <li><span class="section"><a href="importing_modules.html">5.2. Importing Modules Using from module import</a></span></li>
+ <li><span class="section"><a href="defining_classes.html">5.3. Defining Classes</a></span><ul>
+ <li><span class="section"><a href="defining_classes.html#d0e11720">5.3.1. Initializing and Coding Classes</a></span></li>
+ <li><span class="section"><a href="defining_classes.html#d0e11896">5.3.2. Knowing When to Use self and __init__</a></span></li>
+ </ul>
+ </li>
+ <li><span class="section"><a href="instantiating_classes.html">5.4. Instantiating Classes</a></span><ul>
+ <li><span class="section"><a href="instantiating_classes.html#d0e12165">5.4.1. Garbage Collection</a></span></li>
+ </ul>
+ </li>
+ <li><span class="section"><a href="userdict.html">5.5. Exploring UserDict: A Wrapper Class</a></span></li>
+ <li><span class="section"><a href="special_class_methods.html">5.6. Special Class Methods</a></span><ul>
+ <li><span class="section"><a href="special_class_methods.html#d0e12822">5.6.1. Getting and Setting Items</a></span></li>
+ </ul>
+ </li>
+ <li><span class="section"><a href="special_class_methods2.html">5.7. Advanced Special Class Methods</a></span></li>
+ <li><span class="section"><a href="class_attributes.html">5.8. Introducing Class Attributes</a></span></li>
+ <li><span class="section"><a href="private_functions.html">5.9. Private Functions</a></span></li>
+ <li><span class="section"><a href="summary.html">5.10. Summary</a></span></li>
+ </ul>
+ </div>
+ <div class="abstract">
+ <p>This chapter, and pretty much every chapter after this, deals with object-oriented <span class="application">Python</span> programming.
+ </p>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="fileinfo.divein"></a>5.1.&nbsp;Diving In
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>Here is a complete, working <span class="application">Python</span> program. Read the <a href="../getting_to_know_python/documenting_functions.html" title="2.3.&nbsp;Documenting Functions"><tt class="literal">doc string</tt>s</a> of the module, the classes, and the functions to get an overview of what this program does and how it works. As usual, don't
+ worry about the stuff you don't understand; that's what the rest of the chapter is for.
+ </p>
+ </div>
+ <div class="example"><a name="d0e11177"></a><h3 class="title">Example&nbsp;5.1.&nbsp;<tt class="filename">fileinfo.py</tt></h3>
+ <p>If you have not already done so, you can <a href="http://diveintopython.org/download/diveintopython-examples-5.4.zip" title="Download example scripts">download this and other examples</a> used in this book.
+ </p><pre class="programlisting">
+<span class='pystring'>"""Framework for getting filetype-specific metadata.
+
+Instantiate appropriate class with filename. Returned object acts like a
+dictionary, with key-value pairs for each piece of metadata.
+ import fileinfo
+ info = fileinfo.MP3FileInfo("/music/ap/mahadeva.mp3")
+ print "\\n".join(["%s=%s" % (k, v) for k, v in info.items()])
+
+Or use listDirectory function to get info on all files in a directory.
+ for info in fileinfo.listDirectory("/music/ap/", [".mp3"]):
+ ...
+
+Framework can be extended by adding classes for particular file types, e.g.
+HTMLFileInfo, MPGFileInfo, DOCFileInfo. Each class is completely responsible for
+parsing its files appropriately; see MP3FileInfo for example.
+"""</span>
+<span class='pykeyword'>import</span> os
+<span class='pykeyword'>import</span> sys
+<span class='pykeyword'>from</span> UserDict <span class='pykeyword'>import</span> UserDict
+
+<span class='pykeyword'>def</span><span class='pyclass'> stripnulls</span>(data):
+ <span class='pystring'>"strip whitespace and nulls"</span>
+ <span class='pykeyword'>return</span> data.replace(<span class='pystring'>"\00"</span>, <span class='pystring'>""</span>).strip()
+
+<span class='pykeyword'>class</span><span class='pyclass'> FileInfo</span>(UserDict):
+ <span class='pystring'>"store file metadata"</span>
+ <span class='pykeyword'>def</span><span class='pyclass'> __init__</span>(self, filename=None):
+ UserDict.__init__(self)
+ self[<span class='pystring'>"name"</span>] = filename
+
+<span class='pykeyword'>class</span><span class='pyclass'> MP3FileInfo</span>(FileInfo):
+ <span class='pystring'>"store ID3v1.0 MP3 tags"</span>
+ tagDataMap = {<span class='pystring'>"title"</span> : ( 3, 33, stripnulls),
+ <span class='pystring'>"artist"</span> : ( 33, 63, stripnulls),
+ <span class='pystring'>"album"</span> : ( 63, 93, stripnulls),
+ <span class='pystring'>"year"</span> : ( 93, 97, stripnulls),
+ <span class='pystring'>"comment"</span> : ( 97, 126, stripnulls),
+ <span class='pystring'>"genre"</span> : (127, 128, ord)}
+
+ <span class='pykeyword'>def</span><span class='pyclass'> __parse</span>(self, filename):
+ <span class='pystring'>"parse ID3v1.0 tags from MP3 file"</span>
+ self.clear()
+ <span class='pykeyword'>try</span>:
+ fsock = open(filename, <span class='pystring'>"rb"</span>, 0)
+ <span class='pykeyword'>try</span>:
+ fsock.seek(-128, 2)
+ tagdata = fsock.read(128)
+ <span class='pykeyword'>finally</span>:
+ fsock.close()
+ <span class='pykeyword'>if</span> tagdata[:3] == <span class='pystring'>"TAG"</span>:
+ <span class='pykeyword'>for</span> tag, (start, end, parseFunc) <span class='pykeyword'>in</span> self.tagDataMap.items():
+ self[tag] = parseFunc(tagdata[start:end])
+ <span class='pykeyword'>except</span> IOError:
+ <span class='pykeyword'>pass</span>
+
+ <span class='pykeyword'>def</span><span class='pyclass'> __setitem__</span>(self, key, item):
+ <span class='pykeyword'>if</span> key == <span class='pystring'>"name"</span> <span class='pykeyword'>and</span> item:
+ self.__parse(item)
+ FileInfo.__setitem__(self, key, item)
+
+<span class='pykeyword'>def</span><span class='pyclass'> listDirectory</span>(directory, fileExtList):
+ <span class='pystring'>"get list of file info objects for files of particular extensions"</span>
+ fileList = [os.path.normcase(f)
+ <span class='pykeyword'>for</span> f <span class='pykeyword'>in</span> os.listdir(directory)]
+ fileList = [os.path.join(directory, f)
+ <span class='pykeyword'>for</span> f <span class='pykeyword'>in</span> fileList
+ <span class='pykeyword'>if</span> os.path.splitext(f)[1] <span class='pykeyword'>in</span> fileExtList]
+ <span class='pykeyword'>def</span><span class='pyclass'> getFileInfoClass</span>(filename, module=sys.modules[FileInfo.__module__]):
+ <span class='pystring'>"get file info class from filename extension"</span>
+ subclass = <span class='pystring'>"%sFileInfo"</span> % os.path.splitext(filename)[1].upper()[1:]
+ <span class='pykeyword'>return</span> hasattr(module, subclass) <span class='pykeyword'>and</span> getattr(module, subclass) <span class='pykeyword'>or</span> FileInfo
+ <span class='pykeyword'>return</span> [getFileInfoClass(f)(f) <span class='pykeyword'>for</span> f <span class='pykeyword'>in</span> fileList]
+
+<span class='pykeyword'>if</span> __name__ == <span class='pystring'>"__main__"</span>:
+ <span class='pykeyword'>for</span> info <span class='pykeyword'>in</span> listDirectory(<span class='pystring'>"/music/_singles/"</span>, [<span class='pystring'>".mp3"</span>]): <a name="fileinfo_divein.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ <span class='pykeyword'>print</span> <span class='pystring'>"\n"</span>.join([<span class='pystring'>"%s=%s"</span> % (k, v) <span class='pykeyword'>for</span> k, v <span class='pykeyword'>in</span> info.items()])
+ print</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo_divein.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This program's output depends on the files on your hard drive. To get meaningful output, you'll need to change the directory
+ path to point to a directory of MP3 files on your own machine.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="informalexample">
+ <p>This is the output I got on my machine. Your output will be different, unless, by some startling coincidence, you share my
+ exact taste in music.
+ </p><pre class="screen"><span class="computeroutput">album=
+artist=Ghost in the Machine
+title=A Time Long Forgotten (Concept
+genre=31
+name=/music/_singles/a_time_long_forgotten_con.mp3
+year=1999
+comment=http://mp3.com/ghostmachine
+
+album=Rave Mix
+artist=***DJ MARY-JANE***
+title=HELLRAISER****Trance from Hell
+genre=31
+name=/music/_singles/hellraiser.mp3
+year=2000
+comment=http://mp3.com/DJMARYJANE
+
+album=Rave Mix
+artist=***DJ MARY-JANE***
+title=KAIRO****THE BEST GOA
+genre=31
+name=/music/_singles/kairo.mp3
+year=2000
+comment=http://mp3.com/DJMARYJANE
+
+album=Journeys
+artist=Masters of Balance
+title=Long Way Home
+genre=31
+name=/music/_singles/long_way_home1.mp3
+year=2000
+comment=http://mp3.com/MastersofBalan
+
+album=
+artist=The Cynic Project
+title=Sidewinder
+genre=18
+name=/music/_singles/sidewinder.mp3
+year=2000
+comment=http://mp3.com/cynicproject
+
+album=Digitosis@128k
+artist=VXpanded
+title=Spinning
+genre=255
+name=/music/_singles/spinning.mp3
+year=2000
+comment=http://mp3.com/artists/95/vxp</span></pre></div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="../power_of_introspection/summary.html">&lt;&lt;&nbsp;Summary</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<span class="thispage">1</span> <span class="divider">|</span> <a href="importing_modules.html" title="5.2.&nbsp;Importing Modules Using from module import">2</a> <span class="divider">|</span> <a href="defining_classes.html" title="5.3.&nbsp;Defining Classes">3</a> <span class="divider">|</span> <a href="instantiating_classes.html" title="5.4.&nbsp;Instantiating Classes">4</a> <span class="divider">|</span> <a href="userdict.html" title="5.5.&nbsp;Exploring UserDict: A Wrapper Class">5</a> <span class="divider">|</span> <a href="special_class_methods.html" title="5.6.&nbsp;Special Class Methods">6</a> <span class="divider">|</span> <a href="special_class_methods2.html" title="5.7.&nbsp;Advanced Special Class Methods">7</a> <span class="divider">|</span> <a href="class_attributes.html" title="5.8.&nbsp;Introducing Class Attributes">8</a> <span class="divider">|</span> <a href="private_functions.html" title="5.9.&nbsp;Private Functions">9</a> <span class="divider">|</span> <a href="summary.html" title="5.10.&nbsp;Summary">10</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="importing_modules.html">Importing Modules Using from module import&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/object_oriented_framework/instantiating_classes.html b/help/diveintopython-5.4/html/object_oriented_framework/instantiating_classes.html
new file mode 100644
index 0000000..1b8ba26
--- /dev/null
+++ b/help/diveintopython-5.4/html/object_oriented_framework/instantiating_classes.html
@@ -0,0 +1,173 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>5.4.&nbsp;Instantiating Classes</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;5.&nbsp;Objects and Object-Orientation">
+ <link rel="previous" href="defining_classes.html" title="5.3.&nbsp;Defining Classes">
+ <link rel="next" href="userdict.html" title="5.5.&nbsp;Exploring UserDict: A Wrapper Class">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Objects and Object-Orientation</a>&nbsp;&gt;&nbsp;<span class="thispage">Instantiating Classes</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="defining_classes.html" title="Prev: &#8220;Defining Classes&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="userdict.html" title="Next: &#8220;Exploring UserDict: A Wrapper Class&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="fileinfo.create"></a>5.4.&nbsp;Instantiating Classes
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="toc">
+ <ul>
+ <li><span class="section"><a href="instantiating_classes.html#d0e12165">5.4.1. Garbage Collection</a></span></li>
+ </ul>
+ </div>
+ <div class="abstract">
+ <p>Instantiating classes in <span class="application">Python</span> is straightforward. To instantiate a class, simply call the class as if it were a function, passing the arguments that the
+ <tt class="function">__init__</tt> method defines. The return value will be the newly created object.
+ </p>
+ </div>
+ <div class="example"><a name="d0e12003"></a><h3 class="title">Example&nbsp;5.7.&nbsp;Creating a <tt class="classname">FileInfo</tt> Instance
+ </h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> fileinfo</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">f = fileinfo.FileInfo(<span class='pystring'>"/music/_singles/kairo.mp3"</span>)</span> <a name="fileinfo.create.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">f.__class__</span> <a name="fileinfo.create.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">&lt;class fileinfo.FileInfo at 010EC204&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">f.__doc__</span> <a name="fileinfo.create.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">'store file metadata'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">f</span> <a name="fileinfo.create.1.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">{'name': '/music/_singles/kairo.mp3'}</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.create.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You are creating an instance of the <tt class="classname">FileInfo</tt> class (defined in the <tt class="filename">fileinfo</tt> module) and assigning the newly created instance to the variable <tt class="varname">f</tt>. You are passing one parameter, <tt class="literal">/music/_singles/kairo.mp3</tt>, which will end up as the <tt class="varname">filename</tt> argument in <tt class="classname">FileInfo</tt>'s <tt class="function">__init__</tt> method.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.create.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Every class instance has a built-in attribute, <tt class="literal">__class__</tt>, which is the object's class. (Note that the representation of this includes the physical address of the instance on my
+ machine; your representation will be different.) <span class="application">Java</span> programmers may be familiar with the <tt class="classname">Class</tt> class, which contains methods like <tt class="function">getName</tt> and <tt class="function">getSuperclass</tt> to get metadata information about an object. In <span class="application">Python</span>, this kind of metadata is available directly on the object itself through attributes like <tt class="literal">__class__</tt>, <tt class="literal">__name__</tt>, and <tt class="literal">__bases__</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.create.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You can access the instance's <tt class="literal">doc string</tt> just as with a function or a module. All instances of a class share the same <tt class="literal">doc string</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.create.1.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Remember when the <tt class="function">__init__</tt> method <a href="defining_classes.html#fileinfo.class.example" title="Example&nbsp;5.4.&nbsp;Defining the FileInfo Class">assigned its <tt class="varname">filename</tt> argument to <tt class="literal">self["name"]</tt></a>? Well, here's the result. The arguments you pass when you create the class instance get sent right along to the <tt class="function">__init__</tt> method (along with the object reference, <tt class="literal">self</tt>, which <span class="application">Python</span> adds for free).
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div><a name="compare.new.java"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">In <span class="application">Python</span>, simply call a class as if it were a function to create a new instance of the class. There is no explicit <tt class="literal">new</tt> operator like <span class="application"><span class="acronym">C++</span></span> or <span class="application">Java</span>.
+ </td>
+ </tr>
+ </table>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e12165"></a>5.4.1.&nbsp;Garbage Collection
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p>If creating new instances is easy, destroying them is even easier. In general, there is no need to explicitly free instances,
+ because they are freed automatically when the variables assigned to them go out of scope. Memory leaks are rare in <span class="application">Python</span>.
+ </p>
+ <div class="example"><a name="fileinfo.scope"></a><h3 class="title">Example&nbsp;5.8.&nbsp;Trying to Implement a Memory Leak</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>def</span><span class='pyclass'> leakmem</span>():</span>
+<tt class="prompt">... </tt><span class="userinput">f = fileinfo.FileInfo(<span class='pystring'>'/music/_singles/kairo.mp3'</span>)</span> <a name="fileinfo.create.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">... </tt>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>for</span> i <span class='pykeyword'>in</span> range(100):</span>
+<tt class="prompt">... </tt><span class="userinput">leakmem()</span> <a name="fileinfo.create.2.3"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.create.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Every time the <tt class="function">leakmem</tt> function is called, you are creating an instance of <tt class="classname">FileInfo</tt> and assigning it to the variable <tt class="varname">f</tt>, which is a local variable within the function. Then the function ends without ever freeing <tt class="varname">f</tt>, so you would expect a memory leak, but you would be wrong. When the function ends, the local variable <tt class="varname">f</tt> goes out of scope. At this point, there are no longer any references to the newly created instance of <tt class="classname">FileInfo</tt> (since you never assigned it to anything other than <tt class="varname">f</tt>), so <span class="application">Python</span> destroys the instance for us.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.create.2.3"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">No matter how many times you call the <tt class="function">leakmem</tt> function, it will never leak memory, because every time, <span class="application">Python</span> will destroy the newly created <tt class="classname">FileInfo</tt> class before returning from <tt class="function">leakmem</tt>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>The technical term for this form of garbage collection is &#8220;<span class="quote">reference counting</span>&#8221;. <span class="application">Python</span> keeps a list of references to every instance created. In the above example, there was only one reference to the <tt class="classname">FileInfo</tt> instance: the local variable <tt class="varname">f</tt>. When the function ends, the variable <tt class="varname">f</tt> goes out of scope, so the reference count drops to <tt class="constant">0</tt>, and <span class="application">Python</span> destroys the instance automatically.
+ </p>
+ <p>In previous versions of <span class="application">Python</span>, there were situations where reference counting failed, and <span class="application">Python</span> couldn't clean up after you. If you created two instances that referenced each other (for instance, a doubly-linked list,
+ where each node has a pointer to the previous and next node in the list), neither instance would ever be destroyed automatically
+ because <span class="application">Python</span> (correctly) believed that there is always a reference to each instance. <span class="application">Python</span> 2.0 has an additional form of garbage collection called &#8220;<span class="quote">mark-and-sweep</span>&#8221; which is smart enough to notice this virtual gridlock and clean up circular references correctly.
+ </p>
+ <p>As a former philosophy major, it disturbs me to think that things disappear when no one is looking at them, but that's exactly
+ what happens in <span class="application">Python</span>. In general, you can simply forget about memory management and let <span class="application">Python</span> clean up after you.
+ </p>
+ <div class="furtherreading">
+ <h3>Further Reading on Garbage Collection</h3>
+ <ul>
+ <li><a href="http://www.python.org/doc/current/lib/"><i class="citetitle"><span class="application">Python</span> Library Reference</i></a> summarizes <a href="http://www.python.org/doc/current/lib/specialattrs.html">built-in attributes like <tt class="literal">__class__</tt></a>.
+ </li>
+ <li><a href="http://www.python.org/doc/current/lib/"><i class="citetitle"><span class="application">Python</span> Library Reference</i></a> documents the <a href="http://www.python.org/doc/current/lib/module-gc.html"><tt class="filename">gc</tt> module</a>, which gives you low-level control over <span class="application">Python</span>'s garbage collection.
+ </li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="defining_classes.html">&lt;&lt;&nbsp;Defining Classes</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#fileinfo.divein" title="5.1.&nbsp;Diving In">1</a> <span class="divider">|</span> <a href="importing_modules.html" title="5.2.&nbsp;Importing Modules Using from module import">2</a> <span class="divider">|</span> <a href="defining_classes.html" title="5.3.&nbsp;Defining Classes">3</a> <span class="divider">|</span> <span class="thispage">4</span> <span class="divider">|</span> <a href="userdict.html" title="5.5.&nbsp;Exploring UserDict: A Wrapper Class">5</a> <span class="divider">|</span> <a href="special_class_methods.html" title="5.6.&nbsp;Special Class Methods">6</a> <span class="divider">|</span> <a href="special_class_methods2.html" title="5.7.&nbsp;Advanced Special Class Methods">7</a> <span class="divider">|</span> <a href="class_attributes.html" title="5.8.&nbsp;Introducing Class Attributes">8</a> <span class="divider">|</span> <a href="private_functions.html" title="5.9.&nbsp;Private Functions">9</a> <span class="divider">|</span> <a href="summary.html" title="5.10.&nbsp;Summary">10</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="userdict.html">Exploring UserDict: A Wrapper Class&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/object_oriented_framework/private_functions.html b/help/diveintopython-5.4/html/object_oriented_framework/private_functions.html
new file mode 100644
index 0000000..d336a7f
--- /dev/null
+++ b/help/diveintopython-5.4/html/object_oriented_framework/private_functions.html
@@ -0,0 +1,119 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>5.9.&nbsp;Private Functions</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;5.&nbsp;Objects and Object-Orientation">
+ <link rel="previous" href="class_attributes.html" title="5.8.&nbsp;Introducing Class Attributes">
+ <link rel="next" href="summary.html" title="5.10.&nbsp;Summary">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Objects and Object-Orientation</a>&nbsp;&gt;&nbsp;<span class="thispage">Private Functions</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="class_attributes.html" title="Prev: &#8220;Introducing Class Attributes&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="summary.html" title="Next: &#8220;Summary&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="fileinfo.private"></a>5.9.&nbsp;Private Functions
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p>Like most languages, <span class="application">Python</span> has the concept of private elements:
+ </p>
+ <div class="itemizedlist">
+ <ul>
+ <li>Private functions, which can't be called from outside their module</li>
+ <li>Private class methods, which can't be called from outside their class</li>
+ <li>Private attributes, which can't be accessed from outside their class.</li>
+ </ul>
+ </div>
+ <div class="abstract">
+ <p>Unlike in most languages, whether a <span class="application">Python</span> function, method, or attribute is private or public is determined entirely by its name.
+ </p>
+ </div>
+ <p>If the name of a <span class="application">Python</span> function, class method, or attribute starts with (but doesn't end with) two underscores, it's private; everything else is
+ public. <span class="application">Python</span> has no concept of <span class="emphasis"><em>protected</em></span> class methods (accessible only in their own class and descendant classes). Class methods are either private (accessible
+ only in their own class) or public (accessible from anywhere).
+ </p>
+ <p>In <tt class="classname">MP3FileInfo</tt>, there are two methods: <tt class="function">__parse</tt> and <tt class="function">__setitem__</tt>. As you have already discussed, <tt class="function">__setitem__</tt> is a <a href="special_class_methods.html#fileinfo.specialmethods.setitem.example" title="Example&nbsp;5.13.&nbsp;The __setitem__ Special Method">special method</a>; normally, you would call it indirectly by using the dictionary syntax on a class instance, but it is public, and you could
+ call it directly (even from outside the <tt class="filename">fileinfo</tt> module) if you had a really good reason. However, <tt class="function">__parse</tt> is private, because it has two underscores at the beginning of its name.
+ </p><a name="tip.specialmethodnames"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">In <span class="application">Python</span>, all special methods (like <a href="special_class_methods.html#fileinfo.specialmethods.setitem.example" title="Example&nbsp;5.13.&nbsp;The __setitem__ Special Method"><tt class="function">__setitem__</tt></a>) and built-in attributes (like <a href="../getting_to_know_python/everything_is_an_object.html#odbchelper.import" title="Example&nbsp;2.3.&nbsp;Accessing the buildConnectionString Function's doc string"><tt class="literal">__doc__</tt></a>) follow a standard naming convention: they both start with and end with two underscores. Don't name your own methods and
+ attributes this way, because it will only confuse you (and others) later.
+ </td>
+ </tr>
+ </table>
+ <div class="example"><a name="d0e13946"></a><h3 class="title">Example&nbsp;5.19.&nbsp;Trying to Call a Private Method</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> fileinfo</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">m = fileinfo.MP3FileInfo()</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">m.__parse(<span class='pystring'>"/music/_singles/kairo.mp3"</span>)</span> <a name="fileinfo.private.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="traceback">Traceback (innermost last):
+ File "&lt;interactive input&gt;", line 1, in ?
+AttributeError: 'MP3FileInfo' instance has no attribute '__parse'</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.private.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">If you try to call a private method, <span class="application">Python</span> will raise a slightly misleading exception, saying that the method does not exist. Of course it does exist, but it's private,
+ so it's not accessible outside the class.Strictly speaking, private methods are accessible outside their class, just not <span class="emphasis"><em>easily</em></span> accessible. Nothing in <span class="application">Python</span> is truly private; internally, the names of private methods and attributes are mangled and unmangled on the fly to make them
+ seem inaccessible by their given names. You can access the <tt class="function">__parse</tt> method of the <tt class="classname">MP3FileInfo</tt> class by the name <tt class="function">_MP3FileInfo__parse</tt>. Acknowledge that this is interesting, but promise to never, ever do it in real code. Private methods are private for a
+ reason, but like many other things in <span class="application">Python</span>, their privateness is ultimately a matter of convention, not force.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="furtherreading">
+ <h3>Further Reading on Private Functions</h3>
+ <ul>
+ <li><a href="http://www.python.org/doc/current/tut/tut.html"><i class="citetitle"><span class="application">Python</span> Tutorial</i></a> discusses the inner workings of <a href="http://www.python.org/doc/current/tut/node11.html#SECTION0011600000000000000000">private variables</a>.
+ </li>
+ </ul>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="class_attributes.html">&lt;&lt;&nbsp;Introducing Class Attributes</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#fileinfo.divein" title="5.1.&nbsp;Diving In">1</a> <span class="divider">|</span> <a href="importing_modules.html" title="5.2.&nbsp;Importing Modules Using from module import">2</a> <span class="divider">|</span> <a href="defining_classes.html" title="5.3.&nbsp;Defining Classes">3</a> <span class="divider">|</span> <a href="instantiating_classes.html" title="5.4.&nbsp;Instantiating Classes">4</a> <span class="divider">|</span> <a href="userdict.html" title="5.5.&nbsp;Exploring UserDict: A Wrapper Class">5</a> <span class="divider">|</span> <a href="special_class_methods.html" title="5.6.&nbsp;Special Class Methods">6</a> <span class="divider">|</span> <a href="special_class_methods2.html" title="5.7.&nbsp;Advanced Special Class Methods">7</a> <span class="divider">|</span> <a href="class_attributes.html" title="5.8.&nbsp;Introducing Class Attributes">8</a> <span class="divider">|</span> <span class="thispage">9</span> <span class="divider">|</span> <a href="summary.html" title="5.10.&nbsp;Summary">10</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="summary.html">Summary&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/object_oriented_framework/special_class_methods.html b/help/diveintopython-5.4/html/object_oriented_framework/special_class_methods.html
new file mode 100644
index 0000000..5439809
--- /dev/null
+++ b/help/diveintopython-5.4/html/object_oriented_framework/special_class_methods.html
@@ -0,0 +1,234 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>5.6.&nbsp;Special Class Methods</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;5.&nbsp;Objects and Object-Orientation">
+ <link rel="previous" href="userdict.html" title="5.5.&nbsp;Exploring UserDict: A Wrapper Class">
+ <link rel="next" href="special_class_methods2.html" title="5.7.&nbsp;Advanced Special Class Methods">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Objects and Object-Orientation</a>&nbsp;&gt;&nbsp;<span class="thispage">Special Class Methods</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="userdict.html" title="Prev: &#8220;Exploring UserDict: A Wrapper Class&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="special_class_methods2.html" title="Next: &#8220;Advanced Special Class Methods&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="fileinfo.specialmethods"></a>5.6.&nbsp;Special Class Methods
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="toc">
+ <ul>
+ <li><span class="section"><a href="special_class_methods.html#d0e12822">5.6.1. Getting and Setting Items</a></span></li>
+ </ul>
+ </div>
+ <div class="abstract">
+ <p>In addition to normal class methods, there are a number of special methods that <span class="application">Python</span> classes can define. Instead of being called directly by your code (like normal methods), special methods are called for
+ you by <span class="application">Python</span> in particular circumstances or when specific syntax is used.
+ </p>
+ </div>
+ <p>As you saw in the <a href="userdict.html" title="5.5.&nbsp;Exploring UserDict: A Wrapper Class">previous section</a>, normal methods go a long way towards wrapping a dictionary in a class. But normal methods alone are not enough, because
+ there are a lot of things you can do with dictionaries besides call methods on them. For starters, you can <a href="../native_data_types/index.html#odbchelper.dict.define" title="Example&nbsp;3.1.&nbsp;Defining a Dictionary">get</a> and <a href="../native_data_types/index.html#odbchelper.dict.modify" title="Example&nbsp;3.2.&nbsp;Modifying a Dictionary">set</a> items with a syntax that doesn't include explicitly invoking methods. This is where special class methods come in: they
+ provide a way to map non-method-calling syntax into method calls.
+ </p>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e12822"></a>5.6.1.&nbsp;Getting and Setting Items
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="example"><a name="d0e12825"></a><h3 class="title">Example&nbsp;5.12.&nbsp;The <tt class="function">__getitem__</tt> Special Method
+ </h3><pre class="programlisting">
+ <span class='pykeyword'>def</span><span class='pyclass'> __getitem__</span>(self, key): <span class='pykeyword'>return</span> self.data[key]</pre><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">f = fileinfo.FileInfo(<span class='pystring'>"/music/_singles/kairo.mp3"</span>)</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">f</span>
+<span class="computeroutput">{'name':'/music/_singles/kairo.mp3'}</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">f.__getitem__(<span class='pystring'>"name"</span>)</span> <a name="fileinfo.specialmethods.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">'/music/_singles/kairo.mp3'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">f[<span class='pystring'>"name"</span>]</span> <a name="fileinfo.specialmethods.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">'/music/_singles/kairo.mp3'</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.specialmethods.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="function">__getitem__</tt> special method looks simple enough. Like the normal methods <tt class="function">clear</tt>, <tt class="function">keys</tt>, and <tt class="function">values</tt>, it just redirects to the dictionary to return its value. But how does it get called? Well, you can call <tt class="function">__getitem__</tt> directly, but in practice you wouldn't actually do that; I'm just doing it here to show you how it works. The right way
+ to use <tt class="function">__getitem__</tt> is to get <span class="application">Python</span> to call it for you.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.specialmethods.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This looks just like the syntax you would use to <a href="../native_data_types/index.html#odbchelper.dict.define" title="Example&nbsp;3.1.&nbsp;Defining a Dictionary">get a dictionary value</a>, and in fact it returns the value you would expect. But here's the missing link: under the covers, <span class="application">Python</span> has converted this syntax to the method call <tt class="literal">f.__getitem__("name")</tt>. That's why <tt class="function">__getitem__</tt> is a special class method; not only can you call it yourself, you can get <span class="application">Python</span> to call it for you by using the right syntax.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>Of course, <span class="application">Python</span> has a <tt class="function">__setitem__</tt> special method to go along with <tt class="function">__getitem__</tt>, as shown in the next example.
+ </p>
+ <div class="example"><a name="fileinfo.specialmethods.setitem.example"></a><h3 class="title">Example&nbsp;5.13.&nbsp;The <tt class="function">__setitem__</tt> Special Method
+ </h3><pre class="programlisting">
+ <span class='pykeyword'>def</span><span class='pyclass'> __setitem__</span>(self, key, item): self.data[key] = item</pre><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">f</span>
+<span class="computeroutput">{'name':'/music/_singles/kairo.mp3'}</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">f.__setitem__(<span class='pystring'>"genre"</span>, 31)</span> <a name="fileinfo.specialmethods.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">f</span>
+<span class="computeroutput">{'name':'/music/_singles/kairo.mp3', 'genre':31}</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">f[<span class='pystring'>"genre"</span>] = 32</span> <a name="fileinfo.specialmethods.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">f</span>
+<span class="computeroutput">{'name':'/music/_singles/kairo.mp3', 'genre':32}</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.specialmethods.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Like the <tt class="function">__getitem__</tt> method, <tt class="function">__setitem__</tt> simply redirects to the real dictionary <tt class="varname">self.data</tt> to do its work. And like <tt class="function">__getitem__</tt>, you wouldn't ordinarily call it directly like this; <span class="application">Python</span> calls <tt class="function">__setitem__</tt> for you when you use the right syntax.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.specialmethods.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This looks like regular dictionary syntax, except of course that <tt class="varname">f</tt> is really a class that's trying very hard to masquerade as a dictionary, and <tt class="function">__setitem__</tt> is an essential part of that masquerade. This line of code actually calls <tt class="literal">f.__setitem__("genre", 32)</tt> under the covers.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p><tt class="function">__setitem__</tt> is a special class method because it gets called for you, but it's still a class method. Just as easily as the <tt class="function">__setitem__</tt> method was defined in <tt class="classname">UserDict</tt>, you can redefine it in the descendant class to override the ancestor method. This allows you to define classes that act
+ like dictionaries in some ways but define their own behavior above and beyond the built-in dictionary.
+ </p>
+ <p>This concept is the basis of the entire framework you're studying in this chapter. Each file type can have a handler class
+ that knows how to get metadata from a particular type of file. Once some attributes (like the file's name and location) are
+ known, the handler class knows how to derive other attributes automatically. This is done by overriding the <tt class="function">__setitem__</tt> method, checking for particular keys, and adding additional processing when they are found.
+ </p>
+ <p>For example, <tt class="classname">MP3FileInfo</tt> is a descendant of <tt class="classname">FileInfo</tt>. When an <tt class="classname">MP3FileInfo</tt>'s <tt class="literal">name</tt> is set, it doesn't just set the <tt class="literal">name</tt> key (like the ancestor <tt class="classname">FileInfo</tt> does); it also looks in the file itself for <span class="abbrev">MP3</span> tags and populates a whole set of keys. The next example shows how this works.
+ </p>
+ <div class="example"><a name="d0e13038"></a><h3 class="title">Example&nbsp;5.14.&nbsp;Overriding <tt class="function">__setitem__</tt> in <tt class="classname">MP3FileInfo</tt></h3><pre class="programlisting">
+ <span class='pykeyword'>def</span><span class='pyclass'> __setitem__</span>(self, key, item): <a name="fileinfo.specialmethods.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ <span class='pykeyword'>if</span> key == <span class='pystring'>"name"</span> <span class='pykeyword'>and</span> item: <a name="fileinfo.specialmethods.3.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+ self.__parse(item) <a name="fileinfo.specialmethods.3.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+ FileInfo.__setitem__(self, key, item) <a name="fileinfo.specialmethods.3.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.specialmethods.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Notice that this <tt class="function">__setitem__</tt> method is defined exactly the same way as the ancestor method. This is important, since <span class="application">Python</span> will be calling the method for you, and it expects it to be defined with a certain number of arguments. (Technically speaking,
+ the names of the arguments don't matter; only the number of arguments is important.)
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.specialmethods.3.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Here's the crux of the entire <tt class="classname">MP3FileInfo</tt> class: if you're assigning a value to the <tt class="literal">name</tt> key, you want to do something extra.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.specialmethods.3.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The extra processing you do for <tt class="literal">name</tt>s is encapsulated in the <tt class="function">__parse</tt> method. This is another class method defined in <tt class="classname">MP3FileInfo</tt>, and when you call it, you qualify it with <tt class="varname">self</tt>. Just calling <tt class="function">__parse</tt> would look for a normal function defined outside the class, which is not what you want. Calling <tt class="function">self.__parse</tt> will look for a class method defined within the class. This isn't anything new; you reference <a href="userdict.html#fileinfo.userdict.normalmethods" title="Example&nbsp;5.10.&nbsp;UserDict Normal Methods">data attributes</a> the same way.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.specialmethods.3.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">After doing this extra processing, you want to call the ancestor method. Remember that this is never done for you in <span class="application">Python</span>; you must do it manually. Note that you're calling the immediate ancestor, <tt class="classname">FileInfo</tt>, even though it doesn't have a <tt class="function">__setitem__</tt> method. That's okay, because <span class="application">Python</span> will walk up the ancestor tree until it finds a class with the method you're calling, so this line of code will eventually
+ find and call the <tt class="function">__setitem__</tt> defined in <tt class="classname">UserDict</tt>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div><a name="tip.self.call"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">When accessing data attributes within a class, you need to qualify the attribute name: <tt class="literal">self.<i class="replaceable">attribute</i></tt>. When calling other methods within a class, you need to qualify the method name: <tt class="literal">self.<i class="replaceable">method</i></tt>.
+ </td>
+ </tr>
+ </table>
+ <div class="example"><a name="fileinfo.specialmethods.setname"></a><h3 class="title">Example&nbsp;5.15.&nbsp;Setting an <tt class="classname">MP3FileInfo</tt>'s <tt class="literal">name</tt></h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> fileinfo</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">mp3file = fileinfo.MP3FileInfo()</span> <a name="fileinfo.specialmethods.4.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">mp3file</span>
+<span class="computeroutput">{'name':None}</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">mp3file[<span class='pystring'>"name"</span>] = <span class='pystring'>"/music/_singles/kairo.mp3"</span></span> <a name="fileinfo.specialmethods.4.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">mp3file</span>
+<span class="computeroutput">{'album': 'Rave Mix', 'artist': '***DJ MARY-JANE***', 'genre': 31,
+'title': 'KAIRO****THE BEST GOA', 'name': '/music/_singles/kairo.mp3',
+'year': '2000', 'comment': 'http://mp3.com/DJMARYJANE'}</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">mp3file[<span class='pystring'>"name"</span>] = <span class='pystring'>"/music/_singles/sidewinder.mp3"</span></span> <a name="fileinfo.specialmethods.4.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">mp3file</span>
+<span class="computeroutput">{'album': '', 'artist': 'The Cynic Project', 'genre': 18, 'title': 'Sidewinder',
+'name': '/music/_singles/sidewinder.mp3', 'year': '2000',
+'comment': 'http://mp3.com/cynicproject'}</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.specialmethods.4.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">First, you create an instance of <tt class="classname">MP3FileInfo</tt>, without passing it a filename. (You can get away with this because the <tt class="varname">filename</tt> argument of the <tt class="function">__init__</tt> method is <a href="../power_of_introspection/optional_arguments.html" title="4.2.&nbsp;Using Optional and Named Arguments">optional</a>.) Since <tt class="classname">MP3FileInfo</tt> has no <tt class="function">__init__</tt> method of its own, <span class="application">Python</span> walks up the ancestor tree and finds the <tt class="function">__init__</tt> method of <tt class="classname">FileInfo</tt>. This <tt class="function">__init__</tt> method manually calls the <tt class="function">__init__</tt> method of <tt class="classname">UserDict</tt> and then sets the <tt class="literal">name</tt> key to <tt class="varname">filename</tt>, which is <tt class="literal">None</tt>, since you didn't pass a filename. Thus, <tt class="varname">mp3file</tt> initially looks like a dictionary with one key, <tt class="literal">name</tt>, whose value is <tt class="literal">None</tt>.
+
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.specialmethods.4.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Now the real fun begins. Setting the <tt class="literal">name</tt> key of <tt class="varname">mp3file</tt> triggers the <tt class="function">__setitem__</tt> method on <tt class="classname">MP3FileInfo</tt> (not <tt class="classname">UserDict</tt>), which notices that you're setting the <tt class="literal">name</tt> key with a real value and calls <tt class="function">self.__parse</tt>. Although you haven't traced through the <tt class="function">__parse</tt> method yet, you can see from the output that it sets several other keys: <tt class="literal">album</tt>, <tt class="literal">artist</tt>, <tt class="literal">genre</tt>, <tt class="literal">title</tt>, <tt class="literal">year</tt>, and <tt class="literal">comment</tt>.
+
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.specialmethods.4.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Modifying the <tt class="literal">name</tt> key will go through the same process again: <span class="application">Python</span> calls <tt class="function">__setitem__</tt>, which calls <tt class="function">self.__parse</tt>, which sets all the other keys.
+
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="userdict.html">&lt;&lt;&nbsp;Exploring UserDict: A Wrapper Class</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#fileinfo.divein" title="5.1.&nbsp;Diving In">1</a> <span class="divider">|</span> <a href="importing_modules.html" title="5.2.&nbsp;Importing Modules Using from module import">2</a> <span class="divider">|</span> <a href="defining_classes.html" title="5.3.&nbsp;Defining Classes">3</a> <span class="divider">|</span> <a href="instantiating_classes.html" title="5.4.&nbsp;Instantiating Classes">4</a> <span class="divider">|</span> <a href="userdict.html" title="5.5.&nbsp;Exploring UserDict: A Wrapper Class">5</a> <span class="divider">|</span> <span class="thispage">6</span> <span class="divider">|</span> <a href="special_class_methods2.html" title="5.7.&nbsp;Advanced Special Class Methods">7</a> <span class="divider">|</span> <a href="class_attributes.html" title="5.8.&nbsp;Introducing Class Attributes">8</a> <span class="divider">|</span> <a href="private_functions.html" title="5.9.&nbsp;Private Functions">9</a> <span class="divider">|</span> <a href="summary.html" title="5.10.&nbsp;Summary">10</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="special_class_methods2.html">Advanced Special Class Methods&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/object_oriented_framework/special_class_methods2.html b/help/diveintopython-5.4/html/object_oriented_framework/special_class_methods2.html
new file mode 100644
index 0000000..620bf18
--- /dev/null
+++ b/help/diveintopython-5.4/html/object_oriented_framework/special_class_methods2.html
@@ -0,0 +1,144 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>5.7.&nbsp;Advanced Special Class Methods</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;5.&nbsp;Objects and Object-Orientation">
+ <link rel="previous" href="special_class_methods.html" title="5.6.&nbsp;Special Class Methods">
+ <link rel="next" href="class_attributes.html" title="5.8.&nbsp;Introducing Class Attributes">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Objects and Object-Orientation</a>&nbsp;&gt;&nbsp;<span class="thispage">Advanced Special Class Methods</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="special_class_methods.html" title="Prev: &#8220;Special Class Methods&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="class_attributes.html" title="Next: &#8220;Introducing Class Attributes&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="fileinfo.morespecial"></a>5.7.&nbsp;Advanced Special Class Methods
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p><span class="application">Python</span> has more special methods than just <tt class="function">__getitem__</tt> and <tt class="function">__setitem__</tt>. Some of them let you emulate functionality that you may not even know about.
+ </p>
+ </div>
+ <p>This example shows some of the other special methods in <tt class="filename">UserDict</tt>.
+ </p>
+ <div class="example"><a name="fileinfo.morespecial.example"></a><h3 class="title">Example&nbsp;5.16.&nbsp;More Special Methods in <tt class="classname">UserDict</tt></h3><pre class="programlisting">
+ <span class='pykeyword'>def</span><span class='pyclass'> __repr__</span>(self): <span class='pykeyword'>return</span> repr(self.data) <a name="fileinfo.morespecial.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ <span class='pykeyword'>def</span><span class='pyclass'> __cmp__</span>(self, dict): <a name="fileinfo.morespecial.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+ <span class='pykeyword'>if</span> isinstance(dict, UserDict):
+ <span class='pykeyword'>return</span> cmp(self.data, dict.data)
+ <span class='pykeyword'>else</span>:
+ <span class='pykeyword'>return</span> cmp(self.data, dict)
+ <span class='pykeyword'>def</span><span class='pyclass'> __len__</span>(self): <span class='pykeyword'>return</span> len(self.data) <a name="fileinfo.morespecial.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+ <span class='pykeyword'>def</span><span class='pyclass'> __delitem__</span>(self, key): <span class='pykeyword'>del</span> self.data[key] <a name="fileinfo.morespecial.1.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.morespecial.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">__repr__</tt> is a special method that is called when you call <tt class="literal">repr(<i class="replaceable">instance</i>)</tt>. The <tt class="function">repr</tt> function is a built-in function that returns a string representation of an object. It works on any object, not just class
+ instances. You're already intimately familiar with <tt class="function">repr</tt> and you don't even know it. In the interactive window, when you type just a variable name and press the <span><b class="keycap">ENTER</b></span> key, <span class="application">Python</span> uses <tt class="function">repr</tt> to display the variable's value. Go create a dictionary <tt class="varname">d</tt> with some data and then <tt class="literal">print repr(d)</tt> to see for yourself.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.morespecial.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">__cmp__</tt> is called when you compare class instances. In general, you can compare any two <span class="application">Python</span> objects, not just class instances, by using <tt class="literal">==</tt>. There are rules that define when built-in datatypes are considered equal; for instance, dictionaries are equal when they
+ have all the same keys and values, and strings are equal when they are the same length and contain the same sequence of characters.
+ For class instances, you can define the <tt class="function">__cmp__</tt> method and code the comparison logic yourself, and then you can use <tt class="literal">==</tt> to compare instances of your class and <span class="application">Python</span> will call your <tt class="function">__cmp__</tt> special method for you.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.morespecial.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">__len__</tt> is called when you call <tt class="literal">len(<i class="replaceable">instance</i>)</tt>. The <tt class="function">len</tt> function is a built-in function that returns the length of an object. It works on any object that could reasonably be thought
+ of as having a length. The <tt class="function">len</tt> of a string is its number of characters; the <tt class="function">len</tt> of a dictionary is its number of keys; the <tt class="function">len</tt> of a list or tuple is its number of elements. For class instances, define the <tt class="function">__len__</tt> method and code the length calculation yourself, and then call <tt class="literal">len(<i class="replaceable">instance</i>)</tt> and <span class="application">Python</span> will call your <tt class="function">__len__</tt> special method for you.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.morespecial.1.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">__delitem__</tt> is called when you call <tt class="literal">del <i class="replaceable">instance</i>[<i class="replaceable">key</i>]</tt>, which you may remember as the way to <a href="../native_data_types/index.html#odbchelper.dict.del" title="Example&nbsp;3.5.&nbsp;Deleting Items from a Dictionary">delete individual items from a dictionary</a>. When you use <tt class="function">del</tt> on a class instance, <span class="application">Python</span> calls the <tt class="function">__delitem__</tt> special method for you.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div><a name="compare.strequals.java"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">In <span class="application">Java</span>, you determine whether two string variables reference the same physical memory location by using <tt class="literal">str1 == str2</tt>. This is called <span class="emphasis"><em>object identity</em></span>, and it is written in <span class="application">Python</span> as <tt class="literal">str1 is str2</tt>. To compare string values in <span class="application">Java</span>, you would use <tt class="literal">str1.equals(str2)</tt>; in <span class="application">Python</span>, you would use <tt class="literal">str1 == str2</tt>. <span class="application">Java</span> programmers who have been taught to believe that the world is a better place because <tt class="literal">==</tt> in <span class="application">Java</span> compares by identity instead of by value may have a difficult time adjusting to <span class="application">Python</span>'s lack of such &#8220;<span class="quote">gotchas</span>&#8221;.
+ </td>
+ </tr>
+ </table>
+ <p>At this point, you may be thinking, &#8220;<span class="quote">All this work just to do something in a class that I can do with a built-in datatype.</span>&#8221; And it's true that life would be easier (and the entire <tt class="classname">UserDict</tt> class would be unnecessary) if you could inherit from built-in datatypes like a dictionary. But even if you could, special
+ methods would still be useful, because they can be used in any class, not just wrapper classes like <tt class="classname">UserDict</tt>.
+ </p>
+ <p>Special methods mean that <span class="emphasis"><em>any class</em></span> can store key/value pairs like a dictionary, just by defining the <tt class="function">__setitem__</tt> method. <span class="emphasis"><em>Any class</em></span> can act like a sequence, just by defining the <tt class="function">__getitem__</tt> method. Any class that defines the <tt class="function">__cmp__</tt> method can be compared with <tt class="literal">==</tt>. And if your class represents something that has a length, don't define a <tt class="function">GetLength</tt> method; define the <tt class="function">__len__</tt> method and use <tt class="literal">len(<i class="replaceable">instance</i>)</tt>.
+ </p><a name="note.physical.v.logical"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">While other object-oriented languages only let you define the physical model of an object (&#8220;<span class="quote">this object has a <tt class="function">GetLength</tt> method</span>&#8221;), <span class="application">Python</span>'s special class methods like <tt class="function">__len__</tt> allow you to define the logical model of an object (&#8220;<span class="quote">this object has a length</span>&#8221;).
+ </td>
+ </tr>
+ </table>
+ <p><span class="application">Python</span> has a lot of other special methods. There's a whole set of them that let classes act like numbers, allowing you to add,
+ subtract, and do other arithmetic operations on class instances. (The canonical example of this is a class that represents
+ complex numbers, numbers with both real and imaginary components.) The <tt class="function">__call__</tt> method lets a class act like a function, allowing you to call a class instance directly. And there are other special methods
+ that allow classes to have read-only and write-only data attributes; you'll talk more about those in later chapters.
+ </p>
+ <div class="furtherreading">
+ <h3>Further Reading on Special Class Methods</h3>
+ <ul>
+ <li><a href="http://www.python.org/doc/current/ref/"><i class="citetitle"><span class="application">Python</span> Reference Manual</i></a> documents <a href="http://www.python.org/doc/current/ref/specialnames.html">all the special class methods</a>.
+ </li>
+ </ul>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="special_class_methods.html">&lt;&lt;&nbsp;Special Class Methods</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#fileinfo.divein" title="5.1.&nbsp;Diving In">1</a> <span class="divider">|</span> <a href="importing_modules.html" title="5.2.&nbsp;Importing Modules Using from module import">2</a> <span class="divider">|</span> <a href="defining_classes.html" title="5.3.&nbsp;Defining Classes">3</a> <span class="divider">|</span> <a href="instantiating_classes.html" title="5.4.&nbsp;Instantiating Classes">4</a> <span class="divider">|</span> <a href="userdict.html" title="5.5.&nbsp;Exploring UserDict: A Wrapper Class">5</a> <span class="divider">|</span> <a href="special_class_methods.html" title="5.6.&nbsp;Special Class Methods">6</a> <span class="divider">|</span> <span class="thispage">7</span> <span class="divider">|</span> <a href="class_attributes.html" title="5.8.&nbsp;Introducing Class Attributes">8</a> <span class="divider">|</span> <a href="private_functions.html" title="5.9.&nbsp;Private Functions">9</a> <span class="divider">|</span> <a href="summary.html" title="5.10.&nbsp;Summary">10</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="class_attributes.html">Introducing Class Attributes&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/object_oriented_framework/summary.html b/help/diveintopython-5.4/html/object_oriented_framework/summary.html
new file mode 100644
index 0000000..e9398f7
--- /dev/null
+++ b/help/diveintopython-5.4/html/object_oriented_framework/summary.html
@@ -0,0 +1,85 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>5.10.&nbsp;Summary</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;5.&nbsp;Objects and Object-Orientation">
+ <link rel="previous" href="private_functions.html" title="5.9.&nbsp;Private Functions">
+ <link rel="next" href="../file_handling/index.html" title="Chapter&nbsp;6.&nbsp;Exceptions and File Handling">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Objects and Object-Orientation</a>&nbsp;&gt;&nbsp;<span class="thispage">Summary</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="private_functions.html" title="Prev: &#8220;Private Functions&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="../file_handling/index.html" title="Next: &#8220;Exceptions and File Handling&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="fileinfo.summary"></a>5.10.&nbsp;Summary
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>That's it for the hard-core object trickery. You'll see a real-world application of special class methods in <a href="../soap_web_services/index.html">Chapter 12</a>, which uses <tt class="function">getattr</tt> to create a proxy to a remote web service.
+ </p>
+ </div>
+ <p>The next chapter will continue using this code sample to explore other <span class="application">Python</span> concepts, such as exceptions, file objects, and <tt class="literal">for</tt> loops.
+ </p>
+ <p>Before diving into the next chapter, make sure you're comfortable doing all of these things:</p>
+ <div class="itemizedlist">
+ <ul>
+ <li>Importing modules using either <a href="../getting_to_know_python/everything_is_an_object.html#odbchelper.import" title="Example&nbsp;2.3.&nbsp;Accessing the buildConnectionString Function's doc string"><tt class="literal">import <i class="replaceable">module</i></tt></a> or <a href="importing_modules.html" title="5.2.&nbsp;Importing Modules Using from module import"><tt class="literal">from <i class="replaceable">module</i> import</tt></a></li>
+ <li><a href="defining_classes.html" title="5.3.&nbsp;Defining Classes">Defining</a> and <a href="instantiating_classes.html" title="5.4.&nbsp;Instantiating Classes">instantiating</a> classes
+ </li>
+ <li>Defining <a href="defining_classes.html#fileinfo.class.example" title="Example&nbsp;5.4.&nbsp;Defining the FileInfo Class"><tt class="function">__init__</tt> methods</a> and other <a href="special_class_methods.html" title="5.6.&nbsp;Special Class Methods">special class methods</a>, and understanding when they are called
+ </li>
+ <li>Subclassing <a href="userdict.html" title="5.5.&nbsp;Exploring UserDict: A Wrapper Class"><tt class="classname">UserDict</tt></a> to define classes that act like dictionaries
+ </li>
+ <li>Defining <a href="userdict.html#fileinfo.userdict.init.example" title="Example&nbsp;5.9.&nbsp;Defining the UserDict Class">data attributes</a> and <a href="class_attributes.html" title="5.8.&nbsp;Introducing Class Attributes">class attributes</a>, and understanding the differences between them
+ </li>
+ <li>Defining <a href="private_functions.html" title="5.9.&nbsp;Private Functions">private attributes and methods</a></li>
+ </ul>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="private_functions.html">&lt;&lt;&nbsp;Private Functions</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#fileinfo.divein" title="5.1.&nbsp;Diving In">1</a> <span class="divider">|</span> <a href="importing_modules.html" title="5.2.&nbsp;Importing Modules Using from module import">2</a> <span class="divider">|</span> <a href="defining_classes.html" title="5.3.&nbsp;Defining Classes">3</a> <span class="divider">|</span> <a href="instantiating_classes.html" title="5.4.&nbsp;Instantiating Classes">4</a> <span class="divider">|</span> <a href="userdict.html" title="5.5.&nbsp;Exploring UserDict: A Wrapper Class">5</a> <span class="divider">|</span> <a href="special_class_methods.html" title="5.6.&nbsp;Special Class Methods">6</a> <span class="divider">|</span> <a href="special_class_methods2.html" title="5.7.&nbsp;Advanced Special Class Methods">7</a> <span class="divider">|</span> <a href="class_attributes.html" title="5.8.&nbsp;Introducing Class Attributes">8</a> <span class="divider">|</span> <a href="private_functions.html" title="5.9.&nbsp;Private Functions">9</a> <span class="divider">|</span> <span class="thispage">10</span>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="../file_handling/index.html">Exceptions and File Handling&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/object_oriented_framework/userdict.html b/help/diveintopython-5.4/html/object_oriented_framework/userdict.html
new file mode 100644
index 0000000..cd1f562
--- /dev/null
+++ b/help/diveintopython-5.4/html/object_oriented_framework/userdict.html
@@ -0,0 +1,244 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>5.5.&nbsp;Exploring UserDict: A Wrapper Class</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;5.&nbsp;Objects and Object-Orientation">
+ <link rel="previous" href="instantiating_classes.html" title="5.4.&nbsp;Instantiating Classes">
+ <link rel="next" href="special_class_methods.html" title="5.6.&nbsp;Special Class Methods">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Objects and Object-Orientation</a>&nbsp;&gt;&nbsp;<span class="thispage">Exploring UserDict: A Wrapper Class</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="instantiating_classes.html" title="Prev: &#8220;Instantiating Classes&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="special_class_methods.html" title="Next: &#8220;Special Class Methods&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="fileinfo.userdict"></a>5.5.&nbsp;Exploring <tt class="classname">UserDict</tt>: A Wrapper Class
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>As you've seen, <tt class="classname">FileInfo</tt> is a class that acts like a dictionary. To explore this further, let's look at the <tt class="classname">UserDict</tt> class in the <tt class="filename">UserDict</tt> module, which is the ancestor of the <tt class="classname">FileInfo</tt> class. This is nothing special; the class is written in <span class="application">Python</span> and stored in a <tt class="literal">.py</tt> file, just like any other <span class="application">Python</span> code. In particular, it's stored in the <tt class="filename">lib</tt> directory in your <span class="application">Python</span> installation.
+ </p>
+ </div><a name="tip.locate"></a><table class="tip" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/tip.png" alt="Tip" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">In the <span class="application">ActivePython</span> <span class="acronym">IDE</span> on Windows, you can quickly open any module in your library path by selecting
+ <span class="guimenu">File</span>-&gt;<span class="guimenuitem"><span class="accel">L</span>ocate...</span> (<span><b class="shortcut"><span><b class="keycap">Ctrl</b></span>-<span class="keysym">L</span></b></span>).
+ </td>
+ </tr>
+ </table>
+ <div class="example"><a name="fileinfo.userdict.init.example"></a><h3 class="title">Example&nbsp;5.9.&nbsp;Defining the <tt class="classname">UserDict</tt> Class
+ </h3><pre class="programlisting"><span class='pykeyword'>
+class</span> UserDict: <a name="fileinfo.userdict.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ <span class='pykeyword'>def</span><span class='pyclass'> __init__</span>(self, dict=None): <a name="fileinfo.userdict.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+ self.data = {} <a name="fileinfo.userdict.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+ <span class='pykeyword'>if</span> dict <span class='pykeyword'>is</span> <span class='pykeyword'>not</span> None: self.update(dict) <a name="fileinfo.userdict.1.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"> <a name="fileinfo.userdict.1.5"></a><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12">
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.userdict.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Note that <tt class="classname">UserDict</tt> is a base class, not inherited from any other class.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.userdict.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This is the <tt class="function">__init__</tt> method that you <a href="defining_classes.html#fileinfo.class.example" title="Example&nbsp;5.4.&nbsp;Defining the FileInfo Class">overrode in the <tt class="classname">FileInfo</tt> class</a>. Note that the argument list in this ancestor class is different than the descendant. That's okay; each subclass can have
+ its own set of arguments, as long as it calls the ancestor with the correct arguments. Here the ancestor class has a way
+ to define initial values (by passing a dictionary in the <tt class="varname">dict</tt> argument) which the <tt class="classname">FileInfo</tt> does not use.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.userdict.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><span class="application">Python</span> supports data attributes (called &#8220;<span class="quote">instance variables</span>&#8221; in <span class="application">Java</span> and <span class="application">Powerbuilder</span>, and &#8220;<span class="quote">member variables</span>&#8221; in <span class="application"><span class="acronym">C++</span></span>). Data attributes are pieces of data held by a specific instance of a class. In this case, each instance of <tt class="classname">UserDict</tt> will have a data attribute <tt class="varname">data</tt>. To reference this attribute from code outside the class, you qualify it with the instance name, <tt class="literal"><i class="replaceable">instance</i>.data</tt>, in the same way that you qualify a function with its module name. To reference a data attribute from within the class,
+ you use <tt class="literal">self</tt> as the qualifier. By convention, all data attributes are initialized to reasonable values in the <tt class="function">__init__</tt> method. However, this is not required, since data attributes, like local variables, <a href="../native_data_types/declaring_variables.html" title="3.4.&nbsp;Declaring variables">spring into existence</a> when they are first assigned a value.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.userdict.1.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="function">update</tt> method is a dictionary duplicator: it copies all the keys and values from one dictionary to another. This does <span class="emphasis"><em>not</em></span> clear the target dictionary first; if the target dictionary already has some keys, the ones from the source dictionary will
+ be overwritten, but others will be left untouched. Think of <tt class="function">update</tt> as a merge function, not a copy function.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.userdict.1.5"><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This is a syntax you may not have seen before (I haven't used it in the examples in this book). It's an <tt class="literal">if</tt> statement, but instead of having an indented block starting on the next line, there is just a single statement on the same
+ line, after the colon. This is perfectly legal syntax, which is just a shortcut you can use when you have only one statement
+ in a block. (It's like specifying a single statement without braces in <span class="application"><span class="acronym">C++</span></span>.) You can use this syntax, or you can have indented code on subsequent lines, but you can't do both for the same block.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div><a name="compare.overloading"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%"><span class="application">Java</span> and <span class="application">Powerbuilder</span> support function overloading by argument list, <span class="foreignphrase"><i class="foreignphrase"><span class="acronym">i.e.</span></i></span> one class can have multiple methods with the same name but a different number of arguments, or arguments of different types.
+ Other languages (most notably <span class="acronym">PL/SQL</span>) even support function overloading by argument name; <span class="foreignphrase"><i class="foreignphrase"><span class="acronym">i.e.</span></i></span> one class can have multiple methods with the same name and the same number of arguments of the same type but different argument
+ names. <span class="application">Python</span> supports neither of these; it has no form of function overloading whatsoever. Methods are defined solely by their name,
+ and there can be only one method per class with a given name. So if a descendant class has an <tt class="function">__init__</tt> method, it <span class="emphasis"><em>always</em></span> overrides the ancestor <tt class="function">__init__</tt> method, even if the descendant defines it with a different argument list. And the same rule applies to any other method.
+ </td>
+ </tr>
+ </table><a name="fileinfo.derivedclasses"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">Guido, the original author of <span class="application">Python</span>, explains method overriding this way: "Derived classes may override methods of their base classes. Because methods have no
+ special privileges when calling other methods of the same object, a method of a base class that calls another method defined
+ in the same base class, may in fact end up calling a method of a derived class that overrides it. (For <span class="application"><span class="acronym">C++</span></span> programmers: all methods in <span class="application">Python</span> are effectively virtual.)" If that doesn't make sense to you (it confuses the hell out of me), feel free to ignore it.
+ I just thought I'd pass it along.
+ </td>
+ </tr>
+ </table><a name="note.dataattributes"></a><table class="caution" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/caution.png" alt="Caution" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">Always assign an initial value to all of an instance's data attributes in the <tt class="function">__init__</tt> method. It will save you hours of debugging later, tracking down <tt class="classname">AttributeError</tt> exceptions because you're referencing uninitialized (and therefore non-existent) attributes.
+ </td>
+ </tr>
+ </table>
+ <div class="example"><a name="fileinfo.userdict.normalmethods"></a><h3 class="title">Example&nbsp;5.10.&nbsp;<tt class="classname">UserDict</tt> Normal Methods
+ </h3><pre class="programlisting">
+ <span class='pykeyword'>def</span><span class='pyclass'> clear</span>(self): self.data.clear() <a name="fileinfo.userdict.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ <span class='pykeyword'>def</span><span class='pyclass'> copy</span>(self): <a name="fileinfo.userdict.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+ <span class='pykeyword'>if</span> self.__class__ <span class='pykeyword'>is</span> UserDict: <a name="fileinfo.userdict.2.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+ <span class='pykeyword'>return</span> UserDict(self.data)
+ <span class='pykeyword'>import</span> copy <a name="fileinfo.userdict.2.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+ <span class='pykeyword'>return</span> copy.copy(self)
+ <span class='pykeyword'>def</span><span class='pyclass'> keys</span>(self): <span class='pykeyword'>return</span> self.data.keys() <a name="fileinfo.userdict.2.5"></a><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12">
+ <span class='pykeyword'>def</span><span class='pyclass'> items</span>(self): <span class='pykeyword'>return</span> self.data.items()
+ <span class='pykeyword'>def</span><span class='pyclass'> values</span>(self): <span class='pykeyword'>return</span> self.data.values()
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.userdict.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">clear</tt> is a normal class method; it is publicly available to be called by anyone at any time. Notice that <tt class="function">clear</tt>, like all class methods, has <tt class="literal">self</tt> as its first argument. (Remember that you don't include <tt class="literal">self</tt> when you call the method; it's something that <span class="application">Python</span> adds for you.) Also note the basic technique of this wrapper class: store a real dictionary (<tt class="varname">data</tt>) as a data attribute, define all the methods that a real dictionary has, and have each class method redirect to the corresponding
+ method on the real dictionary. (In case you'd forgotten, a dictionary's <tt class="function">clear</tt> method <a href="../native_data_types/index.html#odbchelper.dict.del" title="Example&nbsp;3.5.&nbsp;Deleting Items from a Dictionary">deletes all of its keys</a> and their associated values.)
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.userdict.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="filename">copy</tt> method of a real dictionary returns a new dictionary that is an exact duplicate of the original (all the same key-value pairs).
+ But <tt class="classname">UserDict</tt> can't simply redirect to <tt class="function">self.data.copy</tt>, because that method returns a real dictionary, and what you want is to return a new instance that is the same class as <tt class="literal">self</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.userdict.2.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You use the <tt class="literal">__class__</tt> attribute to see if <tt class="literal">self</tt> is a <tt class="classname">UserDict</tt>; if so, you're golden, because you know how to copy a <tt class="classname">UserDict</tt>: just create a new <tt class="classname">UserDict</tt> and give it the real dictionary that you've squirreled away in <tt class="varname">self.data</tt>. Then you immediately return the new <tt class="classname">UserDict</tt> you don't even get to the <tt class="literal">import copy</tt> on the next line.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.userdict.2.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">If <tt class="literal"><span class="literal">self</span>.<span class="literal">__class__</span></tt> is not <tt class="classname">UserDict</tt>, then <tt class="literal">self</tt> must be some subclass of <tt class="classname">UserDict</tt> (like maybe <tt class="classname">FileInfo</tt>), in which case life gets trickier. <tt class="classname">UserDict</tt> doesn't know how to make an exact copy of one of its descendants; there could, for instance, be other data attributes defined
+ in the subclass, so you would need to iterate through them and make sure to copy all of them. Luckily, <span class="application">Python</span> comes with a module to do exactly this, and it's called <tt class="filename">copy</tt>. I won't go into the details here (though it's a wicked cool module, if you're ever inclined to dive into it on your own).
+ Suffice it to say that <tt class="filename">copy</tt> can copy arbitrary <span class="application">Python</span> objects, and that's how you're using it here.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.userdict.2.5"><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The rest of the methods are straightforward, redirecting the calls to the built-in methods on <tt class="varname">self.data</tt>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div><a name="d0e12692"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">In versions of <span class="application">Python</span> prior to 2.2, you could not directly subclass built-in datatypes like strings, lists, and dictionaries. To compensate for
+ this, <span class="application">Python</span> comes with wrapper classes that mimic the behavior of these built-in datatypes: <tt class="classname">UserString</tt>, <tt class="classname">UserList</tt>, and <tt class="classname">UserDict</tt>. Using a combination of normal and special methods, the <tt class="classname">UserDict</tt> class does an excellent imitation of a dictionary. In <span class="application">Python</span> 2.2 and later, you can inherit classes directly from built-in datatypes like <tt class="classname">dict</tt>. An example of this is given in the examples that come with this book, in <tt class="filename">fileinfo_fromdict.py</tt>.
+ </td>
+ </tr>
+ </table>
+ <p>In <span class="application">Python</span>, you can inherit directly from the <tt class="classname">dict</tt> built-in datatype, as shown in this example. There are three differences here compared to the <tt class="filename">UserDict</tt> version.
+ </p>
+ <div class="example"><a name="fileinfo.userdict.fromdict"></a><h3 class="title">Example&nbsp;5.11.&nbsp;Inheriting Directly from Built-In Datatype <tt class="classname">dict</tt></h3><pre class="programlisting"><span class='pykeyword'>
+class</span> FileInfo(dict): <a name="fileinfo.userdict.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ <span class='pystring'>"store file metadata"</span>
+ <span class='pykeyword'>def</span><span class='pyclass'> __init__</span>(self, filename=None): <a name="fileinfo.userdict.3.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+ self[<span class='pystring'>"name"</span>] = filename
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.userdict.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The first difference is that you don't need to import the <tt class="filename">UserDict</tt> module, since <tt class="classname">dict</tt> is a built-in datatype and is always available. The second is that you are inheriting from <tt class="classname">dict</tt> directly, instead of from <tt class="function">UserDict.UserDict</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#fileinfo.userdict.3.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The third difference is subtle but important. Because of the way <tt class="filename">UserDict</tt> works internally, it requires you to manually call its <tt class="function">__init__</tt> method to properly initialize its internal data structures. <tt class="classname">dict</tt> does not work like this; it is not a wrapper, and it requires no explicit initialization.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="furtherreading">
+ <h3>Further Reading on <tt class="filename">UserDict</tt></h3>
+ <ul>
+ <li><a href="http://www.python.org/doc/current/lib/"><i class="citetitle"><span class="application">Python</span> Library Reference</i></a> documents the <a href="http://www.python.org/doc/current/lib/module-UserDict.html"><tt class="filename">UserDict</tt> module</a> and the <a href="http://www.python.org/doc/current/lib/module-copy.html"><tt class="filename">copy</tt> module</a>.
+ </li>
+ </ul>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="instantiating_classes.html">&lt;&lt;&nbsp;Instantiating Classes</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#fileinfo.divein" title="5.1.&nbsp;Diving In">1</a> <span class="divider">|</span> <a href="importing_modules.html" title="5.2.&nbsp;Importing Modules Using from module import">2</a> <span class="divider">|</span> <a href="defining_classes.html" title="5.3.&nbsp;Defining Classes">3</a> <span class="divider">|</span> <a href="instantiating_classes.html" title="5.4.&nbsp;Instantiating Classes">4</a> <span class="divider">|</span> <span class="thispage">5</span> <span class="divider">|</span> <a href="special_class_methods.html" title="5.6.&nbsp;Special Class Methods">6</a> <span class="divider">|</span> <a href="special_class_methods2.html" title="5.7.&nbsp;Advanced Special Class Methods">7</a> <span class="divider">|</span> <a href="class_attributes.html" title="5.8.&nbsp;Introducing Class Attributes">8</a> <span class="divider">|</span> <a href="private_functions.html" title="5.9.&nbsp;Private Functions">9</a> <span class="divider">|</span> <a href="summary.html" title="5.10.&nbsp;Summary">10</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="special_class_methods.html">Special Class Methods&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/performance_tuning/dictionary_lookups.html b/help/diveintopython-5.4/html/performance_tuning/dictionary_lookups.html
new file mode 100644
index 0000000..0cdd263
--- /dev/null
+++ b/help/diveintopython-5.4/html/performance_tuning/dictionary_lookups.html
@@ -0,0 +1,210 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>18.4.&nbsp;Optimizing Dictionary Lookups</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;18.&nbsp;Performance Tuning">
+ <link rel="previous" href="regular_expressions.html" title="18.3.&nbsp;Optimizing Regular Expressions">
+ <link rel="next" href="list_operations.html" title="18.5.&nbsp;Optimizing List Operations">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Performance Tuning</a>&nbsp;&gt;&nbsp;<span class="thispage">Optimizing Dictionary Lookups</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="regular_expressions.html" title="Prev: &#8220;Optimizing Regular Expressions&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="list_operations.html" title="Next: &#8220;Optimizing List Operations&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="soundex.stage2"></a>18.4.&nbsp;Optimizing Dictionary Lookups
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>The second step of the Soundex algorithm is to convert characters to digits in a specific pattern. What's the best way to
+ do this?
+ </p>
+ </div>
+ <p>The most obvious solution is to define a dictionary with individual characters as keys and their corresponding digits as values,
+ and do dictionary lookups on each character. This is what we have in <tt class="filename">soundex/stage1/soundex1c.py</tt> (the current best result so far):
+ </p>
+ <div class="informalexample"><pre class="programlisting">
+charToSoundex = {<span class='pystring'>"A"</span>: <span class='pystring'>"9"</span>,
+ <span class='pystring'>"B"</span>: <span class='pystring'>"1"</span>,
+ <span class='pystring'>"C"</span>: <span class='pystring'>"2"</span>,
+ <span class='pystring'>"D"</span>: <span class='pystring'>"3"</span>,
+ <span class='pystring'>"E"</span>: <span class='pystring'>"9"</span>,
+ <span class='pystring'>"F"</span>: <span class='pystring'>"1"</span>,
+ <span class='pystring'>"G"</span>: <span class='pystring'>"2"</span>,
+ <span class='pystring'>"H"</span>: <span class='pystring'>"9"</span>,
+ <span class='pystring'>"I"</span>: <span class='pystring'>"9"</span>,
+ <span class='pystring'>"J"</span>: <span class='pystring'>"2"</span>,
+ <span class='pystring'>"K"</span>: <span class='pystring'>"2"</span>,
+ <span class='pystring'>"L"</span>: <span class='pystring'>"4"</span>,
+ <span class='pystring'>"M"</span>: <span class='pystring'>"5"</span>,
+ <span class='pystring'>"N"</span>: <span class='pystring'>"5"</span>,
+ <span class='pystring'>"O"</span>: <span class='pystring'>"9"</span>,
+ <span class='pystring'>"P"</span>: <span class='pystring'>"1"</span>,
+ <span class='pystring'>"Q"</span>: <span class='pystring'>"2"</span>,
+ <span class='pystring'>"R"</span>: <span class='pystring'>"6"</span>,
+ <span class='pystring'>"S"</span>: <span class='pystring'>"2"</span>,
+ <span class='pystring'>"T"</span>: <span class='pystring'>"3"</span>,
+ <span class='pystring'>"U"</span>: <span class='pystring'>"9"</span>,
+ <span class='pystring'>"V"</span>: <span class='pystring'>"1"</span>,
+ <span class='pystring'>"W"</span>: <span class='pystring'>"9"</span>,
+ <span class='pystring'>"X"</span>: <span class='pystring'>"2"</span>,
+ <span class='pystring'>"Y"</span>: <span class='pystring'>"9"</span>,
+ <span class='pystring'>"Z"</span>: <span class='pystring'>"2"</span>}
+
+<span class='pykeyword'>def</span><span class='pyclass'> soundex</span>(source):
+ <span class='pycomment'># ... input check omitted for brevity ...</span>
+ source = source[0].upper() + source[1:]
+ digits = source[0]
+ <span class='pykeyword'>for</span> s <span class='pykeyword'>in</span> source[1:]:
+ s = s.upper()
+ digits += charToSoundex[s]
+</pre></div>
+ <p>You timed <tt class="filename">soundex1c.py</tt> already; this is how it performs:
+ </p>
+ <div class="informalexample"><pre class="screen">
+<tt class="prompt">C:\samples\soundex\stage1&gt;</tt><span class="userinput">python soundex1c.py</span>
+<span class="computeroutput">Woo W000 14.5341678901
+Pilgrim P426 19.2650071448
+Flingjingwaller F452 30.1003563302</span>
+</pre></div>
+ <p>This code is straightforward, but is it the best solution? Calling <tt class="methodname">upper()</tt> on each individual character seems inefficient; it would probably be better to call <tt class="methodname">upper()</tt> once on the entire string.
+ </p>
+ <p>Then there's the matter of incrementally building the <tt class="varname">digits</tt> string. Incrementally building strings like this is horribly inefficient; internally, the <span class="application">Python</span> interpreter needs to create a new string each time through the loop, then discard the old one.
+ </p>
+ <p><span class="application">Python</span> is good at lists, though. It can treat a string as a list of characters automatically. And lists are easy to combine into
+ strings again, using the string method <tt class="methodname">join()</tt>.
+ </p>
+ <p>Here is <tt class="filename">soundex/stage2/soundex2a.py</tt>, which converts letters to digits by using &#8614; and <tt class="literal">lambda</tt>:
+ </p>
+ <div class="informalexample"><pre class="programlisting"><span class='pykeyword'>
+def</span> soundex(source):
+ <span class='pycomment'># ...</span>
+ source = source.upper()
+ digits = source[0] + <span class='pystring'>""</span>.join(map(<span class='pykeyword'>lambda</span> c: charToSoundex[c], source[1:]))
+</pre></div>
+ <p>Surprisingly, <tt class="filename">soundex2a.py</tt> is not faster:
+ </p>
+ <div class="informalexample"><pre class="screen">
+<tt class="prompt">C:\samples\soundex\stage2&gt;</tt><span class="userinput">python soundex2a.py</span>
+<span class="computeroutput">Woo W000 15.0097526362
+Pilgrim P426 19.254806407
+Flingjingwaller F452 29.3790847719</span>
+</pre></div>
+ <p>The overhead of the anonymous <tt class="literal">lambda</tt> function kills any performance you gain by dealing with the string as a list of characters.
+ </p>
+ <p><tt class="filename">soundex/stage2/soundex2b.py</tt> uses a list comprehension instead of &#8614; and <tt class="literal">lambda</tt>:
+ </p>
+ <div class="informalexample"><pre class="programlisting">
+ source = source.upper()
+ digits = source[0] + <span class='pystring'>""</span>.join([charToSoundex[c] <span class='pykeyword'>for</span> c <span class='pykeyword'>in</span> source[1:]])
+</pre></div>
+ <p>Using a list comprehension in <tt class="filename">soundex2b.py</tt> is faster than using &#8614; and <tt class="literal">lambda</tt> in <tt class="filename">soundex2a.py</tt>, but still not faster than the original code (incrementally building a string in <tt class="filename">soundex1c.py</tt>):
+ </p>
+ <div class="informalexample"><pre class="screen">
+<tt class="prompt">C:\samples\soundex\stage2&gt;</tt><span class="userinput">python soundex2b.py</span>
+<span class="computeroutput">Woo W000 13.4221324219
+Pilgrim P426 16.4901234654
+Flingjingwaller F452 25.8186157738</span>
+</pre></div>
+ <p>It's time for a radically different approach. Dictionary lookups are a general purpose tool. Dictionary keys can be any
+ length string (or many other data types), but in this case we are only dealing with single-character keys <span class="emphasis"><em>and</em></span> single-character values. It turns out that <span class="application">Python</span> has a specialized function for handling exactly this situation: the <tt class="function">string.maketrans</tt> function.
+ </p>
+ <p>This is <tt class="filename">soundex/stage2/soundex2c.py</tt>:
+ </p>
+ <div class="informalexample"><pre class="programlisting">
+allChar = string.uppercase + string.lowercase
+charToSoundex = string.maketrans(allChar, <span class='pystring'>"91239129922455912623919292"</span> * 2)
+<span class='pykeyword'>def</span><span class='pyclass'> soundex</span>(source):
+ <span class='pycomment'># ...</span>
+ digits = source[0].upper() + source[1:].translate(charToSoundex)
+</pre></div>
+ <p>What the heck is going on here? <tt class="function">string.maketrans</tt> creates a translation matrix between two strings: the first argument and the second argument. In this case, the first argument
+ is the string <tt class="literal">ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz</tt>, and the second argument is the string <tt class="literal">9123912992245591262391929291239129922455912623919292</tt>. See the pattern? It's the same conversion pattern we were setting up longhand with a dictionary. A maps to 9, B maps
+ to 1, C maps to 2, and so forth. But it's not a dictionary; it's a specialized data structure that you can access using the
+ string method <tt class="methodname">translate</tt>, which translates each character into the corresponding digit, according to the matrix defined by <tt class="function">string.maketrans</tt>.
+ </p>
+ <p><tt class="filename">timeit</tt> shows that <tt class="filename">soundex2c.py</tt> is significantly faster than defining a dictionary and looping through the input and building the output incrementally:
+ </p>
+ <div class="informalexample"><pre class="screen">
+<tt class="prompt">C:\samples\soundex\stage2&gt;</tt><span class="userinput">python soundex2c.py</span>
+<span class="computeroutput">Woo W000 11.437645008
+Pilgrim P426 13.2825062962
+Flingjingwaller F452 18.5570110168</span>
+</pre></div>
+ <p>You're not going to get much better than that. <span class="application">Python</span> has a specialized function that does exactly what you want to do; use it and move on.
+ </p>
+ <div class="example"><a name="d0e39507"></a><h3 class="title">Example&nbsp;18.4.&nbsp;Best Result So Far: <tt class="filename">soundex/stage2/soundex2c.py</tt></h3><pre class="programlisting"><span class='pykeyword'>
+import</span> string, re
+
+allChar = string.uppercase + string.lowercase
+charToSoundex = string.maketrans(allChar, <span class='pystring'>"91239129922455912623919292"</span> * 2)
+isOnlyChars = re.compile(<span class='pystring'>'^[A-Za-z]+$'</span>).search
+
+<span class='pykeyword'>def</span><span class='pyclass'> soundex</span>(source):
+ <span class='pykeyword'>if</span> <span class='pykeyword'>not</span> isOnlyChars(source):
+ <span class='pykeyword'>return</span> <span class='pystring'>"0000"</span>
+ digits = source[0].upper() + source[1:].translate(charToSoundex)
+ digits2 = digits[0]
+ <span class='pykeyword'>for</span> d <span class='pykeyword'>in</span> digits[1:]:
+ <span class='pykeyword'>if</span> digits2[-1] != d:
+ digits2 += d
+ digits3 = re.sub(<span class='pystring'>'9'</span>, <span class='pystring'>''</span>, digits2)
+ <span class='pykeyword'>while</span> len(digits3) &lt; 4:
+ digits3 += <span class='pystring'>"0"</span>
+ <span class='pykeyword'>return</span> digits3[:4]
+
+<span class='pykeyword'>if</span> __name__ == <span class='pystring'>'__main__'</span>:
+ <span class='pykeyword'>from</span> timeit <span class='pykeyword'>import</span> Timer
+ names = (<span class='pystring'>'Woo'</span>, <span class='pystring'>'Pilgrim'</span>, <span class='pystring'>'Flingjingwaller'</span>)
+ <span class='pykeyword'>for</span> name <span class='pykeyword'>in</span> names:
+ statement = <span class='pystring'>"soundex('%s')"</span> % name
+ t = Timer(statement, <span class='pystring'>"from __main__ import soundex"</span>)
+ <span class='pykeyword'>print</span> name.ljust(15), soundex(name), min(t.repeat())
+</pre></div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="regular_expressions.html">&lt;&lt;&nbsp;Optimizing Regular Expressions</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#soundex.divein" title="18.1.&nbsp;Diving in">1</a> <span class="divider">|</span> <a href="timeit.html" title="18.2.&nbsp;Using the timeit Module">2</a> <span class="divider">|</span> <a href="regular_expressions.html" title="18.3.&nbsp;Optimizing Regular Expressions">3</a> <span class="divider">|</span> <span class="thispage">4</span> <span class="divider">|</span> <a href="list_operations.html" title="18.5.&nbsp;Optimizing List Operations">5</a> <span class="divider">|</span> <a href="string_manipulation.html" title="18.6.&nbsp;Optimizing String Manipulation">6</a> <span class="divider">|</span> <a href="summary.html" title="18.7.&nbsp;Summary">7</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="list_operations.html">Optimizing List Operations&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/performance_tuning/index.html b/help/diveintopython-5.4/html/performance_tuning/index.html
new file mode 100644
index 0000000..28ceaba
--- /dev/null
+++ b/help/diveintopython-5.4/html/performance_tuning/index.html
@@ -0,0 +1,223 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>Chapter&nbsp;18.&nbsp;Performance Tuning</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="../toc/index.html" title="Dive Into Python">
+ <link rel="previous" href="../dynamic_functions/summary.html" title="17.8.&nbsp;Summary">
+ <link rel="next" href="timeit.html" title="18.2.&nbsp;Using the timeit Module">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<span class="thispage">Performance Tuning</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="../dynamic_functions/summary.html" title="Prev: &#8220;Summary&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="timeit.html" title="Next: &#8220;Using the timeit Module&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="chapter" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="soundex"></a>Chapter&nbsp;18.&nbsp;Performance Tuning
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="toc">
+ <ul>
+ <li><span class="section"><a href="index.html#soundex.divein">18.1. Diving in</a></span></li>
+ <li><span class="section"><a href="timeit.html">18.2. Using the timeit Module</a></span></li>
+ <li><span class="section"><a href="regular_expressions.html">18.3. Optimizing Regular Expressions</a></span></li>
+ <li><span class="section"><a href="dictionary_lookups.html">18.4. Optimizing Dictionary Lookups</a></span></li>
+ <li><span class="section"><a href="list_operations.html">18.5. Optimizing List Operations</a></span></li>
+ <li><span class="section"><a href="string_manipulation.html">18.6. Optimizing String Manipulation</a></span></li>
+ <li><span class="section"><a href="summary.html">18.7. Summary</a></span></li>
+ </ul>
+ </div>
+ <div class="abstract">
+ <p>Performance tuning is a many-splendored thing. Just because <span class="application">Python</span> is an interpreted language doesn't mean you shouldn't worry about code optimization. But don't worry about it <span class="emphasis"><em>too</em></span> much.
+ </p>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="soundex.divein"></a>18.1.&nbsp;Diving in
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>There are so many pitfalls involved in optimizing your code, it's hard to know where to start.</p>
+ </div>
+ <p>Let's start here: <span class="emphasis"><em>are you sure you need to do it at all?</em></span> Is your code really so bad? Is it worth the time to tune it? Over the lifetime of your application, how much time is going
+ to be spent running that code, compared to the time spent waiting for a remote database server, or waiting for user input?
+ </p>
+ <p>Second, <span class="emphasis"><em>are you sure you're done coding?</em></span> Premature optimization is like spreading frosting on a half-baked cake. You spend hours or days (or more) optimizing your
+ code for performance, only to discover it doesn't do what you need it to do. That's time down the drain.
+ </p>
+ <p>This is not to say that code optimization is worthless, but you need to look at the whole system and decide whether it's the
+ best use of your time. Every minute you spend optimizing code is a minute you're not spending adding new features, or writing
+ documentation, or playing with your kids, or writing unit tests.
+ </p>
+ <p>Oh yes, unit tests. It should go without saying that you need a complete set of unit tests before you begin performance tuning.
+ The last thing you need is to introduce new bugs while fiddling with your algorithms.
+ </p>
+ <p>With these caveats in place, let's look at some techniques for optimizing <span class="application">Python</span> code. The code in question is an implementation of the Soundex algorithm. Soundex was a method used in the early 20th century
+ for categorizing surnames in the United States census. It grouped similar-sounding names together, so even if a name was
+ misspelled, researchers had a chance of finding it. Soundex is still used today for much the same reason, although of course
+ we use computerized database servers now. Most database servers include a Soundex function.
+ </p>
+ <p>There are several subtle variations of the Soundex algorithm. This is the one used in this chapter:</p>
+ <div class="orderedlist">
+ <ol type="1">
+ <li>Keep the first letter of the name as-is.</li>
+ <li>Convert the remaining letters to digits, according to a specific table:
+ <div class="itemizedlist">
+ <ul>
+ <li>B, F, P, and V become 1.</li>
+ <li>C, G, J, K, Q, S, X, and Z become 2.</li>
+ <li>D and T become 3.</li>
+ <li>L becomes 4.</li>
+ <li>M and N become 5.</li>
+ <li>R becomes 6.</li>
+ <li>All other letters become 9.</li>
+ </ul>
+ </div>
+ </li>
+ <li>Remove consecutive duplicates.</li>
+ <li>Remove all 9s altogether.</li>
+ <li>If the result is shorter than four characters (the first letter plus three digits), pad the result with trailing zeros.</li>
+ <li>if the result is longer than four characters, discard everything after the fourth character.</li>
+ </ol>
+ </div>
+ <p>For example, my name, <tt class="literal">Pilgrim</tt>, becomes P942695. That has no consecutive duplicates, so nothing to do there. Then you remove the 9s, leaving P4265. That's
+ too long, so you discard the excess character, leaving P426.
+ </p>
+ <p>Another example: <tt class="literal">Woo</tt> becomes W99, which becomes W9, which becomes W, which gets padded with zeros to become W000.
+ </p>
+ <p>Here's a first attempt at a Soundex function:</p>
+ <div class="example"><a name="d0e38889"></a><h3 class="title">Example&nbsp;18.1.&nbsp;<tt class="filename">soundex/stage1/soundex1a.py</tt></h3>
+ <p>If you have not already done so, you can <a href="http://diveintopython.org/download/diveintopython-examples-5.4.zip" title="Download example scripts">download this and other examples</a> used in this book.
+ </p><pre class="programlisting"><span class='pykeyword'>
+import</span> string, re
+
+charToSoundex = {<span class='pystring'>"A"</span>: <span class='pystring'>"9"</span>,
+ <span class='pystring'>"B"</span>: <span class='pystring'>"1"</span>,
+ <span class='pystring'>"C"</span>: <span class='pystring'>"2"</span>,
+ <span class='pystring'>"D"</span>: <span class='pystring'>"3"</span>,
+ <span class='pystring'>"E"</span>: <span class='pystring'>"9"</span>,
+ <span class='pystring'>"F"</span>: <span class='pystring'>"1"</span>,
+ <span class='pystring'>"G"</span>: <span class='pystring'>"2"</span>,
+ <span class='pystring'>"H"</span>: <span class='pystring'>"9"</span>,
+ <span class='pystring'>"I"</span>: <span class='pystring'>"9"</span>,
+ <span class='pystring'>"J"</span>: <span class='pystring'>"2"</span>,
+ <span class='pystring'>"K"</span>: <span class='pystring'>"2"</span>,
+ <span class='pystring'>"L"</span>: <span class='pystring'>"4"</span>,
+ <span class='pystring'>"M"</span>: <span class='pystring'>"5"</span>,
+ <span class='pystring'>"N"</span>: <span class='pystring'>"5"</span>,
+ <span class='pystring'>"O"</span>: <span class='pystring'>"9"</span>,
+ <span class='pystring'>"P"</span>: <span class='pystring'>"1"</span>,
+ <span class='pystring'>"Q"</span>: <span class='pystring'>"2"</span>,
+ <span class='pystring'>"R"</span>: <span class='pystring'>"6"</span>,
+ <span class='pystring'>"S"</span>: <span class='pystring'>"2"</span>,
+ <span class='pystring'>"T"</span>: <span class='pystring'>"3"</span>,
+ <span class='pystring'>"U"</span>: <span class='pystring'>"9"</span>,
+ <span class='pystring'>"V"</span>: <span class='pystring'>"1"</span>,
+ <span class='pystring'>"W"</span>: <span class='pystring'>"9"</span>,
+ <span class='pystring'>"X"</span>: <span class='pystring'>"2"</span>,
+ <span class='pystring'>"Y"</span>: <span class='pystring'>"9"</span>,
+ <span class='pystring'>"Z"</span>: <span class='pystring'>"2"</span>}
+
+<span class='pykeyword'>def</span><span class='pyclass'> soundex</span>(source):
+ <span class='pystring'>"convert string to Soundex equivalent"</span>
+
+ <span class='pycomment'># Soundex requirements:</span>
+ <span class='pycomment'># source string must be at least 1 character</span>
+ <span class='pycomment'># and must consist entirely of letters</span>
+ allChars = string.uppercase + string.lowercase
+ <span class='pykeyword'>if</span> <span class='pykeyword'>not</span> re.search(<span class='pystring'>'^[%s]+$'</span> % allChars, source):
+ <span class='pykeyword'>return</span> <span class='pystring'>"0000"</span>
+
+ <span class='pycomment'># Soundex algorithm:</span>
+ <span class='pycomment'># 1. make first character uppercase</span>
+ source = source[0].upper() + source[1:]
+
+ <span class='pycomment'># 2. translate all other characters to Soundex digits</span>
+ digits = source[0]
+ <span class='pykeyword'>for</span> s <span class='pykeyword'>in</span> source[1:]:
+ s = s.upper()
+ digits += charToSoundex[s]
+
+ <span class='pycomment'># 3. remove consecutive duplicates</span>
+ digits2 = digits[0]
+ <span class='pykeyword'>for</span> d <span class='pykeyword'>in</span> digits[1:]:
+ <span class='pykeyword'>if</span> digits2[-1] != d:
+ digits2 += d
+
+ <span class='pycomment'># 4. remove all "9"s</span>
+ digits3 = re.sub(<span class='pystring'>'9'</span>, <span class='pystring'>''</span>, digits2)
+
+ <span class='pycomment'># 5. pad end with "0"s to 4 characters</span>
+ <span class='pykeyword'>while</span> len(digits3) &lt; 4:
+ digits3 += <span class='pystring'>"0"</span>
+
+ <span class='pycomment'># 6. return first 4 characters</span>
+ <span class='pykeyword'>return</span> digits3[:4]
+
+<span class='pykeyword'>if</span> __name__ == <span class='pystring'>'__main__'</span>:
+ <span class='pykeyword'>from</span> timeit <span class='pykeyword'>import</span> Timer
+ names = (<span class='pystring'>'Woo'</span>, <span class='pystring'>'Pilgrim'</span>, <span class='pystring'>'Flingjingwaller'</span>)
+ <span class='pykeyword'>for</span> name <span class='pykeyword'>in</span> names:
+ statement = <span class='pystring'>"soundex('%s')"</span> % name
+ t = Timer(statement, <span class='pystring'>"from __main__ import soundex"</span>)
+ <span class='pykeyword'>print</span> name.ljust(15), soundex(name), min(t.repeat())
+</pre></div>
+ <div class="furtherreading">
+ <h3>Further Reading on Soundex</h3>
+ <ul>
+ <li><a href="http://www.avotaynu.com/soundex.html">Soundexing and Genealogy</a> gives a chronology of the evolution of the Soundex and its regional variations.
+ </li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="../dynamic_functions/summary.html">&lt;&lt;&nbsp;Summary</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<span class="thispage">1</span> <span class="divider">|</span> <a href="timeit.html" title="18.2.&nbsp;Using the timeit Module">2</a> <span class="divider">|</span> <a href="regular_expressions.html" title="18.3.&nbsp;Optimizing Regular Expressions">3</a> <span class="divider">|</span> <a href="dictionary_lookups.html" title="18.4.&nbsp;Optimizing Dictionary Lookups">4</a> <span class="divider">|</span> <a href="list_operations.html" title="18.5.&nbsp;Optimizing List Operations">5</a> <span class="divider">|</span> <a href="string_manipulation.html" title="18.6.&nbsp;Optimizing String Manipulation">6</a> <span class="divider">|</span> <a href="summary.html" title="18.7.&nbsp;Summary">7</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="timeit.html">Using the timeit Module&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/performance_tuning/list_operations.html b/help/diveintopython-5.4/html/performance_tuning/list_operations.html
new file mode 100644
index 0000000..4cef65c
--- /dev/null
+++ b/help/diveintopython-5.4/html/performance_tuning/list_operations.html
@@ -0,0 +1,180 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>18.5.&nbsp;Optimizing List Operations</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;18.&nbsp;Performance Tuning">
+ <link rel="previous" href="dictionary_lookups.html" title="18.4.&nbsp;Optimizing Dictionary Lookups">
+ <link rel="next" href="string_manipulation.html" title="18.6.&nbsp;Optimizing String Manipulation">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Performance Tuning</a>&nbsp;&gt;&nbsp;<span class="thispage">Optimizing List Operations</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="dictionary_lookups.html" title="Prev: &#8220;Optimizing Dictionary Lookups&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="string_manipulation.html" title="Next: &#8220;Optimizing String Manipulation&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="soundex.stage3"></a>18.5.&nbsp;Optimizing List Operations
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>The third step in the Soundex algorithm is eliminating consecutive duplicate digits. What's the best way to do this?</p>
+ </div>
+ <p>Here's the code we have so far, in <tt class="filename">soundex/stage2/soundex2c.py</tt>:
+ </p>
+ <div class="informalexample"><pre class="programlisting">
+ digits2 = digits[0]
+ <span class='pykeyword'>for</span> d <span class='pykeyword'>in</span> digits[1:]:
+ <span class='pykeyword'>if</span> digits2[-1] != d:
+ digits2 += d
+</pre></div>
+ <p>Here are the performance results for <tt class="filename">soundex2c.py</tt>:
+ </p>
+ <div class="informalexample"><pre class="screen">
+<tt class="prompt">C:\samples\soundex\stage2&gt;</tt><span class="userinput">python soundex2c.py</span>
+<span class="computeroutput">Woo W000 12.6070768771
+Pilgrim P426 14.4033353401
+Flingjingwaller F452 19.7774882003</span>
+</pre></div>
+ <p>The first thing to consider is whether it's efficient to check <tt class="varname">digits[-1]</tt> each time through the loop. Are list indexes expensive? Would we be better off maintaining the last digit in a separate
+ variable, and checking that instead?
+ </p>
+ <p>To answer this question, here is <tt class="filename">soundex/stage3/soundex3a.py</tt>:
+ </p>
+ <div class="informalexample"><pre class="programlisting">
+ digits2 = <span class='pystring'>''</span>
+ last_digit = <span class='pystring'>''</span>
+ <span class='pykeyword'>for</span> d <span class='pykeyword'>in</span> digits:
+ <span class='pykeyword'>if</span> d != last_digit:
+ digits2 += d
+ last_digit = d
+</pre></div>
+ <p><tt class="filename">soundex3a.py</tt> does not run any faster than <tt class="filename">soundex2c.py</tt>, and may even be slightly slower (although it's not enough of a difference to say for sure):
+ </p>
+ <div class="informalexample"><pre class="screen">
+<tt class="prompt">C:\samples\soundex\stage3&gt;</tt><span class="userinput">python soundex3a.py</span>
+<span class="computeroutput">Woo W000 11.5346048171
+Pilgrim P426 13.3950636184
+Flingjingwaller F452 18.6108927252</span>
+</pre></div>
+ <p>Why isn't <tt class="filename">soundex3a.py</tt> faster? It turns out that list indexes in <span class="application">Python</span> are extremely efficient. Repeatedly accessing <tt class="varname">digits2[-1]</tt> is no problem at all. On the other hand, manually maintaining the last seen digit in a separate variable means we have <span class="emphasis"><em>two</em></span> variable assignments for each digit we're storing, which wipes out any small gains we might have gotten from eliminating
+ the list lookup.
+ </p>
+ <p>Let's try something radically different. If it's possible to treat a string as a list of characters, it should be possible
+ to use a list comprehension to iterate through the list. The problem is, the code needs access to the previous character
+ in the list, and that's not easy to do with a straightforward list comprehension.
+ </p>
+ <p>However, it is possible to create a list of index numbers using the built-in <tt class="function">range()</tt> function, and use those index numbers to progressively search through the list and pull out each character that is different
+ from the previous character. That will give you a list of characters, and you can use the string method <tt class="methodname">join()</tt> to reconstruct a string from that.
+ </p>
+ <p>Here is <tt class="filename">soundex/stage3/soundex3b.py</tt>:
+ </p>
+ <div class="informalexample"><pre class="programlisting">
+ digits2 = <span class='pystring'>""</span>.join([digits[i] <span class='pykeyword'>for</span> i <span class='pykeyword'>in</span> range(len(digits))
+ <span class='pykeyword'>if</span> i == 0 <span class='pykeyword'>or</span> digits[i-1] != digits[i]])
+</pre></div>
+ <p>Is this faster? In a word, no.</p>
+ <div class="informalexample"><pre class="screen">
+<tt class="prompt">C:\samples\soundex\stage3&gt;</tt><span class="userinput">python soundex3b.py</span>
+<span class="computeroutput">Woo W000 14.2245271396
+Pilgrim P426 17.8337165757
+Flingjingwaller F452 25.9954005327</span>
+</pre></div>
+ <p>It's possible that the techniques so far as have been &#8220;<span class="quote">string-centric</span>&#8221;. <span class="application">Python</span> can convert a string into a list of characters with a single command: <tt class="function">list('abc')</tt> returns <tt class="literal">['a', 'b', 'c']</tt>. Furthermore, lists can be <span class="emphasis"><em>modified in place</em></span> very quickly. Instead of incrementally building a new list (or string) out of the source string, why not move elements around
+ within a single list?
+ </p>
+ <p>Here is <tt class="filename">soundex/stage3/soundex3c.py</tt>, which modifies a list in place to remove consecutive duplicate elements:
+ </p>
+ <div class="informalexample"><pre class="programlisting">
+ digits = list(source[0].upper() + source[1:].translate(charToSoundex))
+ i=0
+ <span class='pykeyword'>for</span> item <span class='pykeyword'>in</span> digits:
+ <span class='pykeyword'>if</span> item==digits[i]: <span class='pykeyword'>continue</span>
+ i+=1
+ digits[i]=item
+ <span class='pykeyword'>del</span> digits[i+1:]
+ digits2 = <span class='pystring'>""</span>.join(digits)
+</pre></div>
+ <p>Is this faster than <tt class="filename">soundex3a.py</tt> or <tt class="filename">soundex3b.py</tt>? No, in fact it's the slowest method yet:
+ </p>
+ <div class="informalexample"><pre class="screen">
+<tt class="prompt">C:\samples\soundex\stage3&gt;</tt><span class="userinput">python soundex3c.py</span>
+<span class="computeroutput">Woo W000 14.1662554878
+Pilgrim P426 16.0397885765
+Flingjingwaller F452 22.1789341942</span>
+</pre></div>
+ <p>We haven't made any progress here at all, except to try and rule out several &#8220;<span class="quote">clever</span>&#8221; techniques. The fastest code we've seen so far was the original, most straightforward method (<tt class="filename">soundex2c.py</tt>). Sometimes it doesn't pay to be clever.
+ </p>
+ <div class="example"><a name="d0e39674"></a><h3 class="title">Example&nbsp;18.5.&nbsp;Best Result So Far: <tt class="filename">soundex/stage2/soundex2c.py</tt></h3><pre class="programlisting"><span class='pykeyword'>
+import</span> string, re
+
+allChar = string.uppercase + string.lowercase
+charToSoundex = string.maketrans(allChar, <span class='pystring'>"91239129922455912623919292"</span> * 2)
+isOnlyChars = re.compile(<span class='pystring'>'^[A-Za-z]+$'</span>).search
+
+<span class='pykeyword'>def</span><span class='pyclass'> soundex</span>(source):
+ <span class='pykeyword'>if</span> <span class='pykeyword'>not</span> isOnlyChars(source):
+ <span class='pykeyword'>return</span> <span class='pystring'>"0000"</span>
+ digits = source[0].upper() + source[1:].translate(charToSoundex)
+ digits2 = digits[0]
+ <span class='pykeyword'>for</span> d <span class='pykeyword'>in</span> digits[1:]:
+ <span class='pykeyword'>if</span> digits2[-1] != d:
+ digits2 += d
+ digits3 = re.sub(<span class='pystring'>'9'</span>, <span class='pystring'>''</span>, digits2)
+ <span class='pykeyword'>while</span> len(digits3) &lt; 4:
+ digits3 += <span class='pystring'>"0"</span>
+ <span class='pykeyword'>return</span> digits3[:4]
+
+<span class='pykeyword'>if</span> __name__ == <span class='pystring'>'__main__'</span>:
+ <span class='pykeyword'>from</span> timeit <span class='pykeyword'>import</span> Timer
+ names = (<span class='pystring'>'Woo'</span>, <span class='pystring'>'Pilgrim'</span>, <span class='pystring'>'Flingjingwaller'</span>)
+ <span class='pykeyword'>for</span> name <span class='pykeyword'>in</span> names:
+ statement = <span class='pystring'>"soundex('%s')"</span> % name
+ t = Timer(statement, <span class='pystring'>"from __main__ import soundex"</span>)
+ <span class='pykeyword'>print</span> name.ljust(15), soundex(name), min(t.repeat())
+</pre></div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="dictionary_lookups.html">&lt;&lt;&nbsp;Optimizing Dictionary Lookups</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#soundex.divein" title="18.1.&nbsp;Diving in">1</a> <span class="divider">|</span> <a href="timeit.html" title="18.2.&nbsp;Using the timeit Module">2</a> <span class="divider">|</span> <a href="regular_expressions.html" title="18.3.&nbsp;Optimizing Regular Expressions">3</a> <span class="divider">|</span> <a href="dictionary_lookups.html" title="18.4.&nbsp;Optimizing Dictionary Lookups">4</a> <span class="divider">|</span> <span class="thispage">5</span> <span class="divider">|</span> <a href="string_manipulation.html" title="18.6.&nbsp;Optimizing String Manipulation">6</a> <span class="divider">|</span> <a href="summary.html" title="18.7.&nbsp;Summary">7</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="string_manipulation.html">Optimizing String Manipulation&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/performance_tuning/regular_expressions.html b/help/diveintopython-5.4/html/performance_tuning/regular_expressions.html
new file mode 100644
index 0000000..a8e8af3
--- /dev/null
+++ b/help/diveintopython-5.4/html/performance_tuning/regular_expressions.html
@@ -0,0 +1,235 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>18.3.&nbsp;Optimizing Regular Expressions</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;18.&nbsp;Performance Tuning">
+ <link rel="previous" href="timeit.html" title="18.2.&nbsp;Using the timeit Module">
+ <link rel="next" href="dictionary_lookups.html" title="18.4.&nbsp;Optimizing Dictionary Lookups">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Performance Tuning</a>&nbsp;&gt;&nbsp;<span class="thispage">Optimizing Regular Expressions</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="timeit.html" title="Prev: &#8220;Using the timeit Module&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="dictionary_lookups.html" title="Next: &#8220;Optimizing Dictionary Lookups&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="soundex.stage1"></a>18.3.&nbsp;Optimizing Regular Expressions
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>The first thing the Soundex function checks is whether the input is a non-empty string of letters. What's the best way to
+ do this?
+ </p>
+ </div>
+ <p>If you answered &#8220;<span class="quote">regular expressions</span>&#8221;, go sit in the corner and contemplate your bad instincts. Regular expressions are almost never the right answer; they should
+ be avoided whenever possible. Not only for performance reasons, but simply because they're difficult to debug and maintain.
+ Also for performance reasons.
+ </p>
+ <p>This code fragment from <tt class="filename">soundex/stage1/soundex1a.py</tt> checks whether the function argument <tt class="varname">source</tt> is a word made entirely of letters, with at least one letter (not the empty string):
+ </p>
+ <div class="informalexample"><pre class="programlisting">
+ allChars = string.uppercase + string.lowercase
+ <span class='pykeyword'>if</span> <span class='pykeyword'>not</span> re.search(<span class='pystring'>'^[%s]+$'</span> % allChars, source):
+ <span class='pykeyword'>return</span> <span class='pystring'>"0000"</span>
+</pre></div>
+ <p>How does <tt class="filename">soundex1a.py</tt> perform? For convenience, the <tt class="literal">__main__</tt> section of the script contains this code that calls the <tt class="filename">timeit</tt> module, sets up a timing test with three different names, tests each name three times, and displays the minimum time for
+ each:
+ </p>
+ <div class="informalexample"><pre class="programlisting"><span class='pykeyword'>
+if</span> __name__ == <span class='pystring'>'__main__'</span>:
+ <span class='pykeyword'>from</span> timeit <span class='pykeyword'>import</span> Timer
+ names = (<span class='pystring'>'Woo'</span>, <span class='pystring'>'Pilgrim'</span>, <span class='pystring'>'Flingjingwaller'</span>)
+ <span class='pykeyword'>for</span> name <span class='pykeyword'>in</span> names:
+ statement = <span class='pystring'>"soundex('%s')"</span> % name
+ t = Timer(statement, <span class='pystring'>"from __main__ import soundex"</span>)
+ <span class='pykeyword'>print</span> name.ljust(15), soundex(name), min(t.repeat())
+</pre></div>
+ <p>So how does <tt class="filename">soundex1a.py</tt> perform with this regular expression?
+ </p>
+ <div class="informalexample"><pre class="screen">
+<tt class="prompt">C:\samples\soundex\stage1&gt;</tt><span class="userinput">python soundex1a.py</span>
+<span class="computeroutput">Woo W000 19.3356647283
+Pilgrim P426 24.0772053431
+Flingjingwaller F452 35.0463220884</span>
+</pre></div>
+ <p>As you might expect, the algorithm takes significantly longer when called with longer names. There will be a few things we
+ can do to narrow that gap (make the function take less relative time for longer input), but the nature of the algorithm dictates
+ that it will never run in constant time.
+ </p>
+ <p>The other thing to keep in mind is that we are testing a representative sample of names. <tt class="literal">Woo</tt> is a kind of trivial case, in that it gets shorted down to a single letter and then padded with zeros. <tt class="literal">Pilgrim</tt> is a normal case, of average length and a mixture of significant and ignored letters. <tt class="literal">Flingjingwaller</tt> is extraordinarily long and contains consecutive duplicates. Other tests might also be helpful, but this hits a good range
+ of different cases.
+ </p>
+ <p>So what about that regular expression? Well, it's inefficient. Since the expression is testing for ranges of characters
+ (<tt class="literal">A-Z</tt> in uppercase, and <tt class="literal">a-z</tt> in lowercase), we can use a shorthand regular expression syntax. Here is <tt class="filename">soundex/stage1/soundex1b.py</tt>:
+ </p>
+ <div class="informalexample"><pre class="programlisting">
+ <span class='pykeyword'>if</span> <span class='pykeyword'>not</span> re.search(<span class='pystring'>'^[A-Za-z]+$'</span>, source):
+ <span class='pykeyword'>return</span> <span class='pystring'>"0000"</span>
+</pre></div>
+ <p><tt class="filename">timeit</tt> says <tt class="filename">soundex1b.py</tt> is slightly faster than <tt class="filename">soundex1a.py</tt>, but nothing to get terribly excited about:
+ </p>
+ <div class="informalexample"><pre class="screen">
+<tt class="prompt">C:\samples\soundex\stage1&gt;</tt><span class="userinput">python soundex1b.py</span>
+<span class="computeroutput">Woo W000 17.1361133887
+Pilgrim P426 21.8201693232
+Flingjingwaller F452 32.7262294509</span>
+</pre></div>
+ <p>We saw in <a href="../refactoring/refactoring.html" title="15.3.&nbsp;Refactoring">Section&nbsp;15.3, &#8220;Refactoring&#8221;</a> that regular expressions can be compiled and reused for faster results. Since this regular expression never changes across
+ function calls, we can compile it once and use the compiled version. Here is <tt class="filename">soundex/stage1/soundex1c.py</tt>:
+ </p>
+ <div class="informalexample"><pre class="programlisting">
+isOnlyChars = re.compile(<span class='pystring'>'^[A-Za-z]+$'</span>).search
+<span class='pykeyword'>def</span><span class='pyclass'> soundex</span>(source):
+ <span class='pykeyword'>if</span> <span class='pykeyword'>not</span> isOnlyChars(source):
+ <span class='pykeyword'>return</span> <span class='pystring'>"0000"</span>
+</pre></div>
+ <p>Using a compiled regular expression in <tt class="filename">soundex1c.py</tt> is significantly faster:
+ </p>
+ <div class="informalexample"><pre class="screen">
+<tt class="prompt">C:\samples\soundex\stage1&gt;</tt><span class="userinput">python soundex1c.py</span>
+<span class="computeroutput">Woo W000 14.5348347346
+Pilgrim P426 19.2784703084
+Flingjingwaller F452 30.0893873383</span>
+</pre></div>
+ <p>But is this the wrong path? The logic here is simple: the input <tt class="varname">source</tt> needs to be non-empty, and it needs to be composed entirely of letters. Wouldn't it be faster to write a loop checking each
+ character, and do away with regular expressions altogether?
+ </p>
+ <p>Here is <tt class="filename">soundex/stage1/soundex1d.py</tt>:
+ </p>
+ <div class="informalexample"><pre class="programlisting">
+ <span class='pykeyword'>if</span> <span class='pykeyword'>not</span> source:
+ <span class='pykeyword'>return</span> <span class='pystring'>"0000"</span>
+ <span class='pykeyword'>for</span> c <span class='pykeyword'>in</span> source:
+ <span class='pykeyword'>if</span> <span class='pykeyword'>not</span> (<span class='pystring'>'A'</span> &lt;= c &lt;= <span class='pystring'>'Z'</span>) <span class='pykeyword'>and</span> <span class='pykeyword'>not</span> (<span class='pystring'>'a'</span> &lt;= c &lt;= <span class='pystring'>'z'</span>):
+ <span class='pykeyword'>return</span> <span class='pystring'>"0000"</span>
+</pre></div>
+ <p>It turns out that this technique in <tt class="filename">soundex1d.py</tt> is <span class="emphasis"><em>not</em></span> faster than using a compiled regular expression (although it is faster than using a non-compiled regular expression):
+ </p>
+ <div class="informalexample"><pre class="screen">
+<tt class="prompt">C:\samples\soundex\stage1&gt;</tt><span class="userinput">python soundex1d.py</span>
+<span class="computeroutput">Woo W000 15.4065058548
+Pilgrim P426 22.2753567842
+Flingjingwaller F452 37.5845122774</span>
+</pre></div>
+ <p>Why isn't <tt class="filename">soundex1d.py</tt> faster? The answer lies in the interpreted nature of <span class="application">Python</span>. The regular expression engine is written in C, and compiled to run natively on your computer. On the other hand, this
+ loop is written in <span class="application">Python</span>, and runs through the <span class="application">Python</span> interpreter. Even though the loop is relatively simple, it's not simple enough to make up for the overhead of being interpreted.
+ Regular expressions are never the right answer... except when they are.
+ </p>
+ <p>It turns out that <span class="application">Python</span> offers an obscure string method. You can be excused for not knowing about it, since it's never been mentioned in this book.
+ The method is called <tt class="methodname">isalpha()</tt>, and it checks whether a string contains only letters.
+ </p>
+ <p>This is <tt class="filename">soundex/stage1/soundex1e.py</tt>:
+ </p>
+ <div class="informalexample"><pre class="programlisting">
+ <span class='pykeyword'>if</span> (<span class='pykeyword'>not</span> source) <span class='pykeyword'>and</span> (<span class='pykeyword'>not</span> source.isalpha()):
+ <span class='pykeyword'>return</span> <span class='pystring'>"0000"</span>
+</pre></div>
+ <p>How much did we gain by using this specific method in <tt class="filename">soundex1e.py</tt>? Quite a bit.
+ </p>
+ <div class="informalexample"><pre class="screen">
+<tt class="prompt">C:\samples\soundex\stage1&gt;</tt><span class="userinput">python soundex1e.py</span>
+<span class="computeroutput">Woo W000 13.5069504644
+Pilgrim P426 18.2199394057
+Flingjingwaller F452 28.9975225902</span>
+</pre></div>
+ <div class="example"><a name="d0e39318"></a><h3 class="title">Example&nbsp;18.3.&nbsp;Best Result So Far: <tt class="filename">soundex/stage1/soundex1e.py</tt></h3><pre class="programlisting"><span class='pykeyword'>
+import</span> string, re
+
+charToSoundex = {<span class='pystring'>"A"</span>: <span class='pystring'>"9"</span>,
+ <span class='pystring'>"B"</span>: <span class='pystring'>"1"</span>,
+ <span class='pystring'>"C"</span>: <span class='pystring'>"2"</span>,
+ <span class='pystring'>"D"</span>: <span class='pystring'>"3"</span>,
+ <span class='pystring'>"E"</span>: <span class='pystring'>"9"</span>,
+ <span class='pystring'>"F"</span>: <span class='pystring'>"1"</span>,
+ <span class='pystring'>"G"</span>: <span class='pystring'>"2"</span>,
+ <span class='pystring'>"H"</span>: <span class='pystring'>"9"</span>,
+ <span class='pystring'>"I"</span>: <span class='pystring'>"9"</span>,
+ <span class='pystring'>"J"</span>: <span class='pystring'>"2"</span>,
+ <span class='pystring'>"K"</span>: <span class='pystring'>"2"</span>,
+ <span class='pystring'>"L"</span>: <span class='pystring'>"4"</span>,
+ <span class='pystring'>"M"</span>: <span class='pystring'>"5"</span>,
+ <span class='pystring'>"N"</span>: <span class='pystring'>"5"</span>,
+ <span class='pystring'>"O"</span>: <span class='pystring'>"9"</span>,
+ <span class='pystring'>"P"</span>: <span class='pystring'>"1"</span>,
+ <span class='pystring'>"Q"</span>: <span class='pystring'>"2"</span>,
+ <span class='pystring'>"R"</span>: <span class='pystring'>"6"</span>,
+ <span class='pystring'>"S"</span>: <span class='pystring'>"2"</span>,
+ <span class='pystring'>"T"</span>: <span class='pystring'>"3"</span>,
+ <span class='pystring'>"U"</span>: <span class='pystring'>"9"</span>,
+ <span class='pystring'>"V"</span>: <span class='pystring'>"1"</span>,
+ <span class='pystring'>"W"</span>: <span class='pystring'>"9"</span>,
+ <span class='pystring'>"X"</span>: <span class='pystring'>"2"</span>,
+ <span class='pystring'>"Y"</span>: <span class='pystring'>"9"</span>,
+ <span class='pystring'>"Z"</span>: <span class='pystring'>"2"</span>}
+
+<span class='pykeyword'>def</span><span class='pyclass'> soundex</span>(source):
+ <span class='pykeyword'>if</span> (<span class='pykeyword'>not</span> source) <span class='pykeyword'>and</span> (<span class='pykeyword'>not</span> source.isalpha()):
+ <span class='pykeyword'>return</span> <span class='pystring'>"0000"</span>
+ source = source[0].upper() + source[1:]
+ digits = source[0]
+ <span class='pykeyword'>for</span> s <span class='pykeyword'>in</span> source[1:]:
+ s = s.upper()
+ digits += charToSoundex[s]
+ digits2 = digits[0]
+ <span class='pykeyword'>for</span> d <span class='pykeyword'>in</span> digits[1:]:
+ <span class='pykeyword'>if</span> digits2[-1] != d:
+ digits2 += d
+ digits3 = re.sub(<span class='pystring'>'9'</span>, <span class='pystring'>''</span>, digits2)
+ <span class='pykeyword'>while</span> len(digits3) &lt; 4:
+ digits3 += <span class='pystring'>"0"</span>
+ <span class='pykeyword'>return</span> digits3[:4]
+
+<span class='pykeyword'>if</span> __name__ == <span class='pystring'>'__main__'</span>:
+ <span class='pykeyword'>from</span> timeit <span class='pykeyword'>import</span> Timer
+ names = (<span class='pystring'>'Woo'</span>, <span class='pystring'>'Pilgrim'</span>, <span class='pystring'>'Flingjingwaller'</span>)
+ <span class='pykeyword'>for</span> name <span class='pykeyword'>in</span> names:
+ statement = <span class='pystring'>"soundex('%s')"</span> % name
+ t = Timer(statement, <span class='pystring'>"from __main__ import soundex"</span>)
+ <span class='pykeyword'>print</span> name.ljust(15), soundex(name), min(t.repeat())
+</pre></div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="timeit.html">&lt;&lt;&nbsp;Using the timeit Module</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#soundex.divein" title="18.1.&nbsp;Diving in">1</a> <span class="divider">|</span> <a href="timeit.html" title="18.2.&nbsp;Using the timeit Module">2</a> <span class="divider">|</span> <span class="thispage">3</span> <span class="divider">|</span> <a href="dictionary_lookups.html" title="18.4.&nbsp;Optimizing Dictionary Lookups">4</a> <span class="divider">|</span> <a href="list_operations.html" title="18.5.&nbsp;Optimizing List Operations">5</a> <span class="divider">|</span> <a href="string_manipulation.html" title="18.6.&nbsp;Optimizing String Manipulation">6</a> <span class="divider">|</span> <a href="summary.html" title="18.7.&nbsp;Summary">7</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="dictionary_lookups.html">Optimizing Dictionary Lookups&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/performance_tuning/string_manipulation.html b/help/diveintopython-5.4/html/performance_tuning/string_manipulation.html
new file mode 100644
index 0000000..79b6a5d
--- /dev/null
+++ b/help/diveintopython-5.4/html/performance_tuning/string_manipulation.html
@@ -0,0 +1,155 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>18.6.&nbsp;Optimizing String Manipulation</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;18.&nbsp;Performance Tuning">
+ <link rel="previous" href="list_operations.html" title="18.5.&nbsp;Optimizing List Operations">
+ <link rel="next" href="summary.html" title="18.7.&nbsp;Summary">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Performance Tuning</a>&nbsp;&gt;&nbsp;<span class="thispage">Optimizing String Manipulation</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="list_operations.html" title="Prev: &#8220;Optimizing List Operations&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="summary.html" title="Next: &#8220;Summary&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="soundex.stage4"></a>18.6.&nbsp;Optimizing String Manipulation
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>The final step of the Soundex algorithm is padding short results with zeros, and truncating long results. What is the best
+ way to do this?
+ </p>
+ </div>
+ <p>This is what we have so far, taken from <tt class="filename">soundex/stage2/soundex2c.py</tt>:
+ </p>
+ <div class="informalexample"><pre class="programlisting">
+ digits3 = re.sub(<span class='pystring'>'9'</span>, <span class='pystring'>''</span>, digits2)
+ <span class='pykeyword'>while</span> len(digits3) &lt; 4:
+ digits3 += <span class='pystring'>"0"</span>
+ <span class='pykeyword'>return</span> digits3[:4]
+</pre></div>
+ <p>These are the results for <tt class="filename">soundex2c.py</tt>:
+ </p>
+ <div class="informalexample"><pre class="screen">
+<tt class="prompt">C:\samples\soundex\stage2&gt;</tt><span class="userinput">python soundex2c.py</span>
+<span class="computeroutput">Woo W000 12.6070768771
+Pilgrim P426 14.4033353401
+Flingjingwaller F452 19.7774882003</span>
+</pre></div>
+ <p>The first thing to consider is replacing that regular expression with a loop. This code is from <tt class="filename">soundex/stage4/soundex4a.py</tt>:
+ </p>
+ <div class="informalexample"><pre class="programlisting">
+ digits3 = <span class='pystring'>''</span>
+ <span class='pykeyword'>for</span> d <span class='pykeyword'>in</span> digits2:
+ <span class='pykeyword'>if</span> d != <span class='pystring'>'9'</span>:
+ digits3 += d
+</pre></div>
+ <p>Is <tt class="filename">soundex4a.py</tt> faster? Yes it is:
+ </p>
+ <div class="informalexample"><pre class="screen">
+<tt class="prompt">C:\samples\soundex\stage4&gt;</tt><span class="userinput">python soundex4a.py</span>
+<span class="computeroutput">Woo W000 6.62865531792
+Pilgrim P426 9.02247576158
+Flingjingwaller F452 13.6328416042</span>
+</pre></div>
+ <p>But wait a minute. A loop to remove characters from a string? We can use a simple string method for that. Here's <tt class="filename">soundex/stage4/soundex4b.py</tt>:
+ </p>
+ <div class="informalexample"><pre class="programlisting">
+ digits3 = digits2.replace(<span class='pystring'>'9'</span>, <span class='pystring'>''</span>)
+</pre></div>
+ <p>Is <tt class="filename">soundex4b.py</tt> faster? That's an interesting question. It depends on the input:
+ </p>
+ <div class="informalexample"><pre class="screen">
+<tt class="prompt">C:\samples\soundex\stage4&gt;</tt><span class="userinput">python soundex4b.py</span>
+<span class="computeroutput">Woo W000 6.75477414029
+Pilgrim P426 7.56652144337
+Flingjingwaller F452 10.8727729362</span>
+</pre></div>
+ <p>The string method in <tt class="filename">soundex4b.py</tt> is faster than the loop for most names, but it's actually slightly slower than <tt class="filename">soundex4a.py</tt> in the trivial case (of a very short name). Performance optimizations aren't always uniform; tuning that makes one case
+ faster can sometimes make other cases slower. In this case, the majority of cases will benefit from the change, so let's
+ leave it at that, but the principle is an important one to remember.
+ </p>
+ <p>Last but not least, let's examine the final two steps of the algorithm: padding short results with zeros, and truncating long
+ results to four characters. The code you see in <tt class="filename">soundex4b.py</tt> does just that, but it's horribly inefficient. Take a look at <tt class="filename">soundex/stage4/soundex4c.py</tt> to see why:
+ </p>
+ <div class="informalexample"><pre class="programlisting">
+ digits3 += <span class='pystring'>'000'</span>
+ <span class='pykeyword'>return</span> digits3[:4]
+</pre></div>
+ <p>Why do we need a <tt class="literal">while</tt> loop to pad out the result? We know in advance that we're going to truncate the result to four characters, and we know that
+ we already have at least one character (the initial letter, which is passed unchanged from the original <tt class="varname">source</tt> variable). That means we can simply add three zeros to the output, then truncate it. Don't get stuck in a rut over the
+ exact wording of the problem; looking at the problem slightly differently can lead to a simpler solution.
+ </p>
+ <p>How much speed do we gain in <tt class="filename">soundex4c.py</tt> by dropping the <tt class="literal">while</tt> loop? It's significant:
+ </p>
+ <div class="informalexample"><pre class="screen">
+<tt class="prompt">C:\samples\soundex\stage4&gt;</tt><span class="userinput">python soundex4c.py</span>
+<span class="computeroutput">Woo W000 4.89129791636
+Pilgrim P426 7.30642134685
+Flingjingwaller F452 10.689832367</span>
+</pre></div>
+ <p>Finally, there is still one more thing you can do to these three lines of code to make them faster: you can combine them into
+ one line. Take a look at <tt class="filename">soundex/stage4/soundex4d.py</tt>:
+ </p>
+ <div class="informalexample"><pre class="programlisting">
+ <span class='pykeyword'>return</span> (digits2.replace(<span class='pystring'>'9'</span>, <span class='pystring'>''</span>) + <span class='pystring'>'000'</span>)[:4]
+</pre></div>
+ <p>Putting all this code on one line in <tt class="filename">soundex4d.py</tt> is barely faster than <tt class="filename">soundex4c.py</tt>:
+ </p>
+ <div class="informalexample"><pre class="screen">
+<tt class="prompt">C:\samples\soundex\stage4&gt;</tt><span class="userinput">python soundex4d.py</span>
+<span class="computeroutput">Woo W000 4.93624105857
+Pilgrim P426 7.19747593619
+Flingjingwaller F452 10.5490700634</span>
+</pre></div>
+ <p>It is also significantly less readable, and for not much performance gain. Is that worth it? I hope you have good comments.
+ Performance isn't everything. Your optimization efforts must always be balanced against threats to your program's readability
+ and maintainability.
+ </p>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="list_operations.html">&lt;&lt;&nbsp;Optimizing List Operations</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#soundex.divein" title="18.1.&nbsp;Diving in">1</a> <span class="divider">|</span> <a href="timeit.html" title="18.2.&nbsp;Using the timeit Module">2</a> <span class="divider">|</span> <a href="regular_expressions.html" title="18.3.&nbsp;Optimizing Regular Expressions">3</a> <span class="divider">|</span> <a href="dictionary_lookups.html" title="18.4.&nbsp;Optimizing Dictionary Lookups">4</a> <span class="divider">|</span> <a href="list_operations.html" title="18.5.&nbsp;Optimizing List Operations">5</a> <span class="divider">|</span> <span class="thispage">6</span> <span class="divider">|</span> <a href="summary.html" title="18.7.&nbsp;Summary">7</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="summary.html">Summary&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/performance_tuning/summary.html b/help/diveintopython-5.4/html/performance_tuning/summary.html
new file mode 100644
index 0000000..44ad713
--- /dev/null
+++ b/help/diveintopython-5.4/html/performance_tuning/summary.html
@@ -0,0 +1,88 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>18.7.&nbsp;Summary</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;18.&nbsp;Performance Tuning">
+ <link rel="previous" href="string_manipulation.html" title="18.6.&nbsp;Optimizing String Manipulation">
+ <link rel="next" href="../appendix/furtherreading.html" title="Appendix&nbsp;A.&nbsp;Further reading">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Performance Tuning</a>&nbsp;&gt;&nbsp;<span class="thispage">Summary</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="string_manipulation.html" title="Prev: &#8220;Optimizing String Manipulation&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="../appendix/furtherreading.html" title="Next: &#8220;Further reading&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="soundex.summary"></a>18.7.&nbsp;Summary
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>This chapter has illustrated several important aspects of performance tuning in <span class="application">Python</span>, and performance tuning in general.
+ </p>
+ </div>
+ <div class="itemizedlist">
+ <ul>
+ <li>If you need to choose between regular expressions and writing a loop, choose regular expressions. The regular expression
+ engine is compiled in C and runs natively on your computer; your loop is written in <span class="application">Python</span> and runs through the <span class="application">Python</span> interpreter.
+ </li>
+ <li>If you need to choose between regular expressions and string methods, choose string methods. Both are compiled in C, so choose
+ the simpler one.
+ </li>
+ <li>General-purpose dictionary lookups are fast, but specialtiy functions such as <tt class="function">string.maketrans</tt> and string methods such as <tt class="methodname">isalpha()</tt> are faster. If <span class="application">Python</span> has a custom-tailored function for you, use it.
+ </li>
+ <li>Don't be too clever. Sometimes the most obvious algorithm is also the fastest.</li>
+ <li>Don't sweat it too much. Performance isn't everything.</li>
+ </ul>
+ </div>
+ <p>I can't emphasize that last point strongly enough. Over the course of this chapter, you made this function three times faster
+ and saved 20 seconds over 1 million function calls. Great. Now think: over the course of those million function calls, how
+ many seconds will your surrounding application wait for a database connection? Or wait for disk I/O? Or wait for user input?
+ Don't spend too much time over-optimizing one algorithm, or you'll ignore obvious improvements somewhere else. Develop an
+ instinct for the sort of code that <span class="application">Python</span> runs well, correct obvious blunders if you find them, and leave the rest alone.
+ </p>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="string_manipulation.html">&lt;&lt;&nbsp;Optimizing String Manipulation</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#soundex.divein" title="18.1.&nbsp;Diving in">1</a> <span class="divider">|</span> <a href="timeit.html" title="18.2.&nbsp;Using the timeit Module">2</a> <span class="divider">|</span> <a href="regular_expressions.html" title="18.3.&nbsp;Optimizing Regular Expressions">3</a> <span class="divider">|</span> <a href="dictionary_lookups.html" title="18.4.&nbsp;Optimizing Dictionary Lookups">4</a> <span class="divider">|</span> <a href="list_operations.html" title="18.5.&nbsp;Optimizing List Operations">5</a> <span class="divider">|</span> <a href="string_manipulation.html" title="18.6.&nbsp;Optimizing String Manipulation">6</a> <span class="divider">|</span> <span class="thispage">7</span>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="../appendix/furtherreading.html">Further reading&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/performance_tuning/timeit.html b/help/diveintopython-5.4/html/performance_tuning/timeit.html
new file mode 100644
index 0000000..664aa4a
--- /dev/null
+++ b/help/diveintopython-5.4/html/performance_tuning/timeit.html
@@ -0,0 +1,146 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>18.2.&nbsp;Using the timeit Module</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;18.&nbsp;Performance Tuning">
+ <link rel="previous" href="index.html" title="Chapter&nbsp;18.&nbsp;Performance Tuning">
+ <link rel="next" href="regular_expressions.html" title="18.3.&nbsp;Optimizing Regular Expressions">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Performance Tuning</a>&nbsp;&gt;&nbsp;<span class="thispage">Using the timeit Module</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="index.html" title="Prev: &#8220;Performance Tuning&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="regular_expressions.html" title="Next: &#8220;Optimizing Regular Expressions&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="soundex.timeit"></a>18.2.&nbsp;Using the <tt class="filename">timeit</tt> Module
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>The most important thing you need to know about optimizing <span class="application">Python</span> code is that you shouldn't write your own timing function.
+ </p>
+ </div>
+ <p>Timing short pieces of code is incredibly complex. How much processor time is your computer devoting to running this code?
+ Are there things running in the background? Are you sure? Every modern computer has background processes running, some
+ all the time, some intermittently. Cron jobs fire off at consistent intervals; background services occasionally &#8220;<span class="quote">wake up</span>&#8221; to do useful things like check for new mail, connect to instant messaging servers, check for application updates, scan for
+ viruses, check whether a disk has been inserted into your CD drive in the last 100 nanoseconds, and so on. Before you start
+ your timing tests, turn everything off and disconnect from the network. Then turn off all the things you forgot to turn off
+ the first time, then turn off the service that's incessantly checking whether the network has come back yet, then ...
+ </p>
+ <p>And then there's the matter of the variations introduced by the timing framework itself. Does the <span class="application">Python</span> interpreter cache method name lookups? Does it cache code block compilations? Regular expressions? Will your code have
+ side effects if run more than once? Don't forget that you're dealing with small fractions of a second, so small mistakes
+ in your timing framework will irreparably skew your results.
+ </p>
+ <p>The <span class="application">Python</span> community has a saying: &#8220;<span class="quote"><span class="application">Python</span> comes with batteries included.</span>&#8221; Don't write your own timing framework. <span class="application">Python</span> 2.3 comes with a perfectly good one called <tt class="filename">timeit</tt>.
+ </p>
+ <div class="example"><a name="d0e38948"></a><h3 class="title">Example&nbsp;18.2.&nbsp;Introducing <tt class="filename">timeit</tt></h3>
+ <p>If you have not already done so, you can <a href="http://diveintopython.org/download/diveintopython-examples-5.4.zip" title="Download example scripts">download this and other examples</a> used in this book.
+ </p><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> timeit</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">t = timeit.Timer(<span class='pystring'>"soundex.soundex('Pilgrim')"</span>,</span>
+<tt class="prompt">... </tt><span class="userinput"><span class='pystring'>"import soundex"</span>)</span> <a name="soundex.timeit.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">t.timeit()</span> <a name="soundex.timeit.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">8.21683733547</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">t.repeat(3, 2000000)</span> <a name="soundex.timeit.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">[16.48319309109, 16.46128984923, 16.44203948912]</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#soundex.timeit.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="filename">timeit</tt> module defines one class, <tt class="classname">Timer</tt>, which takes two arguments. Both arguments are strings. The first argument is the statement you wish to time; in this case,
+ you are timing a call to the Soundex function within the <tt class="filename">soundex</tt> with an argument of <tt class="literal">'Pilgrim'</tt>. The second argument to the <tt class="classname">Timer</tt> class is the import statement that sets up the environment for the statement. Internally, <tt class="filename">timeit</tt> sets up an isolated virtual environment, manually executes the setup statement (importing the <tt class="filename">soundex</tt> module), then manually compiles and executes the timed statement (calling the Soundex function).
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#soundex.timeit.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Once you have the <tt class="classname">Timer</tt> object, the easiest thing to do is call <tt class="methodname">timeit()</tt>, which calls your function 1 million times and returns the number of seconds it took to do it.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#soundex.timeit.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The other major method of the <tt class="classname">Timer</tt> object is <tt class="methodname">repeat()</tt>, which takes two optional arguments. The first argument is the number of times to repeat the entire test, and the second
+ argument is the number of times to call the timed statement within each test. Both arguments are optional, and they default
+ to <tt class="literal">3</tt> and <tt class="literal">1000000</tt> respectively. The <tt class="methodname">repeat()</tt> method returns a list of the times each test cycle took, in seconds.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div><a name="d0e39049"></a><table class="tip" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/tip.png" alt="Tip" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">You can use the <tt class="filename">timeit</tt> module on the command line to test an existing <span class="application">Python</span> program, without modifying the code. See <a href="http://docs.python.org/lib/node396.html">http://docs.python.org/lib/node396.html</a> for documentation on the command-line flags.
+ </td>
+ </tr>
+ </table>
+ <p>Note that <tt class="methodname">repeat()</tt> returns a list of times. The times will almost never be identical, due to slight variations in how much processor time the
+ <span class="application">Python</span> interpreter is getting (and those pesky background processes that you can't get rid of). Your first thought might be to
+ say &#8220;<span class="quote">Let's take the average and call that The True Number.</span>&#8221;
+ </p>
+ <p>In fact, that's almost certainly wrong. The tests that took longer didn't take longer because of variations in your code
+ or in the <span class="application">Python</span> interpreter; they took longer because of those pesky background processes, or other factors outside of the <span class="application">Python</span> interpreter that you can't fully eliminate. If the different timing results differ by more than a few percent, you still
+ have too much variability to trust the results. Otherwise, take the minimum time and discard the rest.
+ </p>
+ <p><span class="application">Python</span> has a handy <tt class="function">min</tt> function that takes a list and returns the smallest value:
+ </p>
+ <div class="informalexample"><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">min(t.repeat(3, 1000000))</span>
+<span class="computeroutput">8.22203948912</span>
+</pre></div><a name="d0e39097"></a><table class="tip" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/tip.png" alt="Tip" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">The <tt class="filename">timeit</tt> module only works if you already know what piece of code you need to optimize. If you have a larger <span class="application">Python</span> program and don't know where your performance problems are, check out <a href="http://docs.python.org/lib/module-hotshot.html">the <tt class="filename">hotshot</tt> module.</a></td>
+ </tr>
+ </table>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="index.html">&lt;&lt;&nbsp;Performance Tuning</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#soundex.divein" title="18.1.&nbsp;Diving in">1</a> <span class="divider">|</span> <span class="thispage">2</span> <span class="divider">|</span> <a href="regular_expressions.html" title="18.3.&nbsp;Optimizing Regular Expressions">3</a> <span class="divider">|</span> <a href="dictionary_lookups.html" title="18.4.&nbsp;Optimizing Dictionary Lookups">4</a> <span class="divider">|</span> <a href="list_operations.html" title="18.5.&nbsp;Optimizing List Operations">5</a> <span class="divider">|</span> <a href="string_manipulation.html" title="18.6.&nbsp;Optimizing String Manipulation">6</a> <span class="divider">|</span> <a href="summary.html" title="18.7.&nbsp;Summary">7</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="regular_expressions.html">Optimizing Regular Expressions&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/power_of_introspection/all_together.html b/help/diveintopython-5.4/html/power_of_introspection/all_together.html
new file mode 100644
index 0000000..b40c80c
--- /dev/null
+++ b/help/diveintopython-5.4/html/power_of_introspection/all_together.html
@@ -0,0 +1,211 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>4.8.&nbsp;Putting It All Together</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;4.&nbsp;The Power Of Introspection">
+ <link rel="previous" href="lambda_functions.html" title="4.7.&nbsp;Using lambda Functions">
+ <link rel="next" href="summary.html" title="4.9.&nbsp;Summary">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">The Power Of Introspection</a>&nbsp;&gt;&nbsp;<span class="thispage">Putting It All Together</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="lambda_functions.html" title="Prev: &#8220;Using lambda Functions&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="summary.html" title="Next: &#8220;Summary&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="apihelper.alltogether"></a>4.8.&nbsp;Putting It All Together
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>The last line of code, the only one you haven't deconstructed yet, is the one that does all the work. But by now the work
+ is easy, because everything you need is already set up just the way you need it. All the dominoes are in place; it's time
+ to knock them down.
+ </p>
+ </div>
+ <div class="informalexample">
+ <p>This is the meat of <tt class="filename">apihelper.py</tt>:
+ </p><pre class="programlisting">
+ <span class='pykeyword'>print</span> <span class='pystring'>"\n"</span>.join([<span class='pystring'>"%s %s"</span> %
+ (method.ljust(spacing),
+ processFunc(str(getattr(object, method).__doc__)))
+ <span class='pykeyword'>for</span> method <span class='pykeyword'>in</span> methodList])</pre></div>
+ <p>Note that this is one command, split over multiple lines, but it doesn't use the line continuation character (<tt class="literal">\</tt>). Remember when I said that <a href="../native_data_types/declaring_variables.html#tip.implicitmultiline">some expressions can be split into multiple lines</a> without using a backslash? A list comprehension is one of those expressions, since the entire expression is contained in
+ square brackets.
+ </p>
+ <p>Now, let's take it from the end and work backwards. The </p><pre class="programlisting"><span class='pykeyword'>
+for</span> method <span class='pykeyword'>in</span> methodList</pre><p>shows that this is a <a href="../native_data_types/mapping_lists.html" title="3.6.&nbsp;Mapping Lists">list comprehension</a>. As you know, <tt class="varname">methodList</tt> is a list of <a href="filtering_lists.html#apihelper.filter.care">all the methods you care about</a> in <tt class="varname">object</tt>. So you're looping through that list with <tt class="varname">method</tt>.
+ </p>
+ <div class="example"><a name="d0e10681"></a><h3 class="title">Example&nbsp;4.22.&nbsp;Getting a <tt class="literal">doc string</tt> Dynamically
+ </h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> odbchelper</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">object = odbchelper</span> <a name="apihelper.alltogether.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">method = <span class='pystring'>'buildConnectionString'</span></span> <a name="apihelper.alltogether.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">getattr(object, method)</span> <a name="apihelper.alltogether.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">&lt;function buildConnectionString at 010D6D74&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> getattr(object, method).__doc__</span> <a name="apihelper.alltogether.1.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">Build a connection string from a dictionary of parameters.
+
+ Returns string.</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.alltogether.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">In the <tt class="function">info</tt> function, <tt class="varname">object</tt> is the object you're getting help on, passed in as an argument.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.alltogether.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">As you're looping through <tt class="varname">methodList</tt>, <tt class="varname">method</tt> is the name of the current method.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.alltogether.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Using the <a href="getattr.html" title="4.4.&nbsp;Getting Object References With getattr"><tt class="function">getattr</tt></a> function, you're getting a reference to the <i class="replaceable"><tt>method</tt></i> function in the <i class="replaceable"><tt>object</tt></i> module.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.alltogether.1.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Now, printing the actual <tt class="literal">doc string</tt> of the method is easy.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>The next piece of the puzzle is the use of <tt class="function">str</tt> around the <tt class="literal">doc string</tt>. As you may recall, <tt class="function">str</tt> is a built-in function that <a href="built_in_functions.html" title="4.3.&nbsp;Using type, str, dir, and Other Built-In Functions">coerces data into a string</a>. But a <tt class="literal">doc string</tt> is always a string, so why bother with the <tt class="function">str</tt> function? The answer is that not every function has a <tt class="literal">doc string</tt>, and if it doesn't, its <tt class="literal">__doc__</tt> attribute is <tt class="literal">None</tt>.
+ </p>
+ <div class="example"><a name="d0e10793"></a><h3 class="title">Example&nbsp;4.23.&nbsp;Why Use <tt class="function">str</tt> on a <tt class="literal">doc string</tt>?
+ </h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">&gt;&gt;&gt; <span class='pykeyword'>def</span><span class='pyclass'> foo</span>(): <span class='pykeyword'>print</span> 2</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">&gt;&gt;&gt; foo()</span>
+<span class="computeroutput">2</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">&gt;&gt;&gt; foo.__doc__</span> <a name="apihelper.alltogether.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">foo.__doc__ == None</span> <a name="apihelper.alltogether.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">True</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">str(foo.__doc__)</span> <a name="apihelper.alltogether.2.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">'None'</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.alltogether.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You can easily define a function that has no <tt class="literal">doc string</tt>, so its <tt class="literal">__doc__</tt> attribute is <tt class="literal">None</tt>. Confusingly, if you evaluate the <tt class="literal">__doc__</tt> attribute directly, the <span class="application">Python</span> <span class="acronym">IDE</span> prints nothing at all, which makes sense if you think about it, but is still unhelpful.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.alltogether.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You can verify that the value of the <tt class="literal">__doc__</tt> attribute is actually <tt class="literal">None</tt> by comparing it directly.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.alltogether.2.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="function">str</tt> function takes the null value and returns a string representation of it, <tt class="literal">'None'</tt>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div><a name="compare.isnull.sql"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">In <span class="acronym">SQL</span>, you must use <tt class="literal">IS NULL</tt> instead of <tt class="literal">= NULL</tt> to compare a null value. In <span class="application">Python</span>, you can use either <tt class="literal">== None</tt> or <tt class="literal">is None</tt>, but <tt class="literal">is None</tt> is faster.
+ </td>
+ </tr>
+ </table>
+ <p>Now that you are guaranteed to have a string, you can pass the string to <tt class="varname">processFunc</tt>, which you have <a href="lambda_functions.html" title="4.7.&nbsp;Using lambda Functions">already defined</a> as a function that either does or doesn't collapse whitespace. Now you see why it was important to use <tt class="function">str</tt> to convert a <tt class="literal">None</tt> value into a string representation. <tt class="varname">processFunc</tt> is assuming a string argument and calling its <tt class="function">split</tt> method, which would crash if you passed it <tt class="literal">None</tt> because <tt class="literal">None</tt> doesn't have a <tt class="function">split</tt> method.
+ </p>
+ <p>Stepping back even further, you see that you're using string formatting again to concatenate the return value of <tt class="varname">processFunc</tt> with the return value of <tt class="varname">method</tt>'s <tt class="function">ljust</tt> method. This is a new string method that you haven't seen before.
+ </p>
+ <div class="example"><a name="d0e10958"></a><h3 class="title">Example&nbsp;4.24.&nbsp;Introducing <tt class="function">ljust</tt></h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">s = <span class='pystring'>'buildConnectionString'</span></span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">s.ljust(30)</span> <a name="apihelper.alltogether.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">'buildConnectionString '</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">s.ljust(20)</span> <a name="apihelper.alltogether.3.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">'buildConnectionString'</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.alltogether.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">ljust</tt> pads the string with spaces to the given length. This is what the <tt class="function">info</tt> function uses to make two columns of output and line up all the <tt class="literal">doc string</tt>s in the second column.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.alltogether.3.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">If the given length is smaller than the length of the string, <tt class="function">ljust</tt> will simply return the string unchanged. It never truncates the string.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>You're almost finished. Given the padded method name from the <tt class="function">ljust</tt> method and the (possibly collapsed) <tt class="literal">doc string</tt> from the call to <tt class="varname">processFunc</tt>, you concatenate the two and get a single string. Since you're mapping <tt class="varname">methodList</tt>, you end up with a list of strings. Using the <tt class="function">join</tt> method of the string <tt class="literal">"\n"</tt>, you join this list into a single string, with each element of the list on a separate line, and print the result.
+ </p>
+ <div class="example"><a name="d0e11026"></a><h3 class="title">Example&nbsp;4.25.&nbsp;Printing a List</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li = [<span class='pystring'>'a'</span>, <span class='pystring'>'b'</span>, <span class='pystring'>'c'</span>]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> <span class='pystring'>"\n"</span>.join(li)</span> <a name="apihelper.alltogether.4.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">a
+b
+c</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.alltogether.4.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This is also a useful debugging trick when you're working with lists. And in <span class="application">Python</span>, you're always working with lists.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>That's the last piece of the puzzle. You should now understand this code.</p>
+ <div class="informalexample"><pre class="programlisting">
+ <span class='pykeyword'>print</span> <span class='pystring'>"\n"</span>.join([<span class='pystring'>"%s %s"</span> %
+ (method.ljust(spacing),
+ processFunc(str(getattr(object, method).__doc__)))
+ <span class='pykeyword'>for</span> method <span class='pykeyword'>in</span> methodList])</pre></div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="lambda_functions.html">&lt;&lt;&nbsp;Using lambda Functions</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#apihelper.divein" title="4.1.&nbsp;Diving In">1</a> <span class="divider">|</span> <a href="optional_arguments.html" title="4.2.&nbsp;Using Optional and Named Arguments">2</a> <span class="divider">|</span> <a href="built_in_functions.html" title="4.3.&nbsp;Using type, str, dir, and Other Built-In Functions">3</a> <span class="divider">|</span> <a href="getattr.html" title="4.4.&nbsp;Getting Object References With getattr">4</a> <span class="divider">|</span> <a href="filtering_lists.html" title="4.5.&nbsp;Filtering Lists">5</a> <span class="divider">|</span> <a href="and_or.html" title="4.6.&nbsp;The Peculiar Nature of and and or">6</a> <span class="divider">|</span> <a href="lambda_functions.html" title="4.7.&nbsp;Using lambda Functions">7</a> <span class="divider">|</span> <span class="thispage">8</span> <span class="divider">|</span> <a href="summary.html" title="4.9.&nbsp;Summary">9</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="summary.html">Summary&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/power_of_introspection/and_or.html b/help/diveintopython-5.4/html/power_of_introspection/and_or.html
new file mode 100644
index 0000000..b41a7a1
--- /dev/null
+++ b/help/diveintopython-5.4/html/power_of_introspection/and_or.html
@@ -0,0 +1,229 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>4.6.&nbsp;The Peculiar Nature of and and or</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;4.&nbsp;The Power Of Introspection">
+ <link rel="previous" href="filtering_lists.html" title="4.5.&nbsp;Filtering Lists">
+ <link rel="next" href="lambda_functions.html" title="4.7.&nbsp;Using lambda Functions">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">The Power Of Introspection</a>&nbsp;&gt;&nbsp;<span class="thispage">The Peculiar Nature of and and or</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="filtering_lists.html" title="Prev: &#8220;Filtering Lists&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="lambda_functions.html" title="Next: &#8220;Using lambda Functions&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="apihelper.andor"></a>4.6.&nbsp;The Peculiar Nature of <tt class="literal">and</tt> and <tt class="literal">or</tt></h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="toc">
+ <ul>
+ <li><span class="section"><a href="and_or.html#d0e9975">4.6.1. Using the and-or Trick</a></span></li>
+ </ul>
+ </div>
+ <div class="abstract">
+ <p>In <span class="application">Python</span>, <tt class="literal">and</tt> and <tt class="literal">or</tt> perform boolean logic as you would expect, but they do not return boolean values; instead, they return one of the actual
+ values they are comparing.
+ </p>
+ </div>
+ <div class="example"><a name="apihelper.andor.intro.example"></a><h3 class="title">Example&nbsp;4.15.&nbsp;Introducing <tt class="literal">and</tt></h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pystring'>'a'</span> <span class='pykeyword'>and</span> <span class='pystring'>'b'</span></span> <a name="apihelper.andor.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">'b'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pystring'>''</span> <span class='pykeyword'>and</span> <span class='pystring'>'b'</span></span> <a name="apihelper.andor.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">''</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pystring'>'a'</span> <span class='pykeyword'>and</span> <span class='pystring'>'b'</span> <span class='pykeyword'>and</span> <span class='pystring'>'c'</span></span> <a name="apihelper.andor.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">'c'</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.andor.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">When using <tt class="literal">and</tt>, values are evaluated in a boolean context from left to right. <tt class="constant">0</tt>, <tt class="literal">''</tt>, <tt class="literal">[]</tt>, <tt class="literal">()</tt>, <tt class="literal">{}</tt>, and <tt class="literal">None</tt> are false in a boolean context; everything else is true. Well, almost everything. By default, instances of classes are
+ true in a boolean context, but you can define special methods in your class to make an instance evaluate to false. You'll
+ learn all about classes and special methods in <a href="../object_oriented_framework/index.html">Chapter 5</a>. If all values are true in a boolean context, <tt class="literal">and</tt> returns the last value. In this case, <tt class="literal">and</tt> evaluates <tt class="literal">'a'</tt>, which is true, then <tt class="literal">'b'</tt>, which is true, and returns <tt class="literal">'b'</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.andor.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">If any value is false in a boolean context, <tt class="literal">and</tt> returns the first false value. In this case, <tt class="literal">''</tt> is the first false value.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.andor.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">All values are true, so <tt class="literal">and</tt> returns the last value, <tt class="literal">'c'</tt>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="d0e9812"></a><h3 class="title">Example&nbsp;4.16.&nbsp;Introducing <tt class="literal">or</tt></h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pystring'>'a'</span> <span class='pykeyword'>or</span> <span class='pystring'>'b'</span></span> <a name="apihelper.andor.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">'a'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pystring'>''</span> <span class='pykeyword'>or</span> <span class='pystring'>'b'</span></span> <a name="apihelper.andor.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">'b'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pystring'>''</span> <span class='pykeyword'>or</span> [] <span class='pykeyword'>or</span> {}</span> <a name="apihelper.andor.2.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">{}</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>def</span><span class='pyclass'> sidefx</span>():</span>
+<tt class="prompt">... </tt><span class="userinput"><span class='pykeyword'>print</span> <span class='pystring'>"in sidefx()"</span></span>
+<tt class="prompt">... </tt><span class="userinput"><span class='pykeyword'>return</span> 1</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pystring'>'a'</span> <span class='pykeyword'>or</span> sidefx()</span> <a name="apihelper.andor.2.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">'a'</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.andor.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">When using <tt class="literal">or</tt>, values are evaluated in a boolean context from left to right, just like <tt class="literal">and</tt>. If any value is true, <tt class="literal">or</tt> returns that value immediately. In this case, <tt class="literal">'a'</tt> is the first true value.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.andor.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="literal">or</tt> evaluates <tt class="literal">''</tt>, which is false, then <tt class="literal">'b'</tt>, which is true, and returns <tt class="literal">'b'</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.andor.2.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">If all values are false, <tt class="literal">or</tt> returns the last value. <tt class="literal">or</tt> evaluates <tt class="literal">''</tt>, which is false, then <tt class="literal">[]</tt>, which is false, then <tt class="literal">{}</tt>, which is false, and returns <tt class="literal">{}</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.andor.2.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Note that <tt class="literal">or</tt> evaluates values only until it finds one that is true in a boolean context, and then it ignores the rest. This distinction
+ is important if some values can have side effects. Here, the function <tt class="function">sidefx</tt> is never called, because <tt class="literal">or</tt> evaluates <tt class="literal">'a'</tt>, which is true, and returns <tt class="literal">'a'</tt> immediately.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>If you're a <span class="application"><span class="acronym">C</span></span> hacker, you are certainly familiar with the <tt class="literal"><i class="replaceable">bool</i> ? <tt class="varname">a</tt> : <tt class="varname">b</tt></tt> expression, which evaluates to <tt class="varname">a</tt> if <i class="replaceable"><tt>bool</tt></i> is true, and <tt class="varname">b</tt> otherwise. Because of the way <tt class="literal">and</tt> and <tt class="literal">or</tt> work in <span class="application">Python</span>, you can accomplish the same thing.
+ </p>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e9975"></a>4.6.1.&nbsp;Using the <tt class="literal">and-or</tt> Trick
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="example"><a name="apihelper.andortrick.intro"></a><h3 class="title">Example&nbsp;4.17.&nbsp;Introducing the <tt class="literal">and-or</tt> Trick
+ </h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">a = <span class='pystring'>"first"</span></span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">b = <span class='pystring'>"second"</span></span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">1 <span class='pykeyword'>and</span> a <span class='pykeyword'>or</span> b</span> <a name="apihelper.andor.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">'first'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">0 <span class='pykeyword'>and</span> a <span class='pykeyword'>or</span> b</span> <a name="apihelper.andor.3.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">'second'</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.andor.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This syntax looks similar to the <tt class="literal"><i class="replaceable">bool</i> ? <tt class="varname">a</tt> : <tt class="varname">b</tt></tt> expression in <span class="application"><span class="acronym">C</span></span>. The entire expression is evaluated from left to right, so the <tt class="literal">and</tt> is evaluated first. <tt class="literal">1 and 'first'</tt> evalutes to <tt class="literal">'first'</tt>, then <tt class="literal">'first' or 'second'</tt> evalutes to <tt class="literal">'first'</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.andor.3.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="literal">0 and 'first'</tt> evalutes to <tt class="constant">False</tt>, and then <tt class="literal">0 or 'second'</tt> evaluates to <tt class="literal">'second'</tt>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>However, since this <span class="application">Python</span> expression is simply boolean logic, and not a special construct of the language, there is one extremely important difference
+ between this <tt class="literal">and-or</tt> trick in <span class="application">Python</span> and the <tt class="literal"><i class="replaceable">bool</i> ? <tt class="varname">a</tt> : <tt class="varname">b</tt></tt> syntax in <span class="application"><span class="acronym">C</span></span>. If the value of <tt class="varname">a</tt> is false, the expression will not work as you would expect it to. (Can you tell I was bitten by this? More than once?)
+ </p>
+ <div class="example"><a name="d0e10093"></a><h3 class="title">Example&nbsp;4.18.&nbsp;When the <tt class="literal">and-or</tt> Trick Fails
+ </h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">a = <span class='pystring'>""</span></span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">b = <span class='pystring'>"second"</span></span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">1 <span class='pykeyword'>and</span> a <span class='pykeyword'>or</span> b</span> <a name="apihelper.andor.4.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">'second'</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.andor.4.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Since <tt class="varname">a</tt> is an empty string, which <span class="application">Python</span> considers false in a boolean context, <tt class="literal">1 and ''</tt> evalutes to <tt class="literal">''</tt>, and then <tt class="literal">'' or 'second'</tt> evalutes to <tt class="literal">'second'</tt>. Oops! That's not what you wanted.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>The <tt class="literal">and-or</tt> trick, <tt class="literal"><i class="replaceable">bool</i> and <tt class="varname">a</tt> or <tt class="varname">b</tt></tt>, will not work like the <span class="application"><span class="acronym">C</span></span> expression <tt class="literal"><i class="replaceable">bool</i> ? <tt class="varname">a</tt> : <tt class="varname">b</tt></tt> when <tt class="varname">a</tt> is false in a boolean context.
+ </p>
+ <p>The real trick behind the <tt class="literal">and-or</tt> trick, then, is to make sure that the value of <tt class="varname">a</tt> is never false. One common way of doing this is to turn <tt class="varname">a</tt> into <tt class="literal">[<tt class="varname">a</tt>]</tt> and <tt class="varname">b</tt> into <tt class="literal">[<tt class="varname">b</tt>]</tt>, then taking the first element of the returned list, which will be either <tt class="varname">a</tt> or <tt class="varname">b</tt>.
+ </p>
+ <div class="example"><a name="d0e10205"></a><h3 class="title">Example&nbsp;4.19.&nbsp;Using the <tt class="literal">and-or</tt> Trick Safely
+ </h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">a = <span class='pystring'>""</span></span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">b = <span class='pystring'>"second"</span></span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">(1 <span class='pykeyword'>and</span> [a] <span class='pykeyword'>or</span> [b])[0]</span> <a name="apihelper.andor.5.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">''</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.andor.5.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Since <tt class="literal">[<tt class="varname">a</tt>]</tt> is a non-empty list, it is never false. Even if <tt class="varname">a</tt> is <tt class="constant">0</tt> or <tt class="literal">''</tt> or some other false value, the list <tt class="literal">[<tt class="varname">a</tt>]</tt> is true because it has one element.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>By now, this trick may seem like more trouble than it's worth. You could, after all, accomplish the same thing with an <tt class="literal">if</tt> statement, so why go through all this fuss? Well, in many cases, you are choosing between two constant values, so you can
+ use the simpler syntax and not worry, because you know that the <tt class="varname">a</tt> value will always be true. And even if you need to use the more complicated safe form, there are good reasons to do so.
+ For example, there are some cases in <span class="application">Python</span> where <tt class="literal">if</tt> statements are not allowed, such as in <tt class="literal">lambda</tt> functions.
+ </p>
+ <div class="furtherreading">
+ <h3>Further Reading on the <tt class="literal">and-or</tt> Trick
+ </h3>
+ <ul>
+ <li><a href="http://www.activestate.com/ASPN/Python/Cookbook/" title="growing archive of annotated code samples"><span class="application">Python</span> Cookbook</a> discusses <a href="http://www.activestate.com/ASPN/Python/Cookbook/Recipe/52310">alternatives to the <tt class="literal">and-or</tt> trick</a>.
+ </li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="filtering_lists.html">&lt;&lt;&nbsp;Filtering Lists</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#apihelper.divein" title="4.1.&nbsp;Diving In">1</a> <span class="divider">|</span> <a href="optional_arguments.html" title="4.2.&nbsp;Using Optional and Named Arguments">2</a> <span class="divider">|</span> <a href="built_in_functions.html" title="4.3.&nbsp;Using type, str, dir, and Other Built-In Functions">3</a> <span class="divider">|</span> <a href="getattr.html" title="4.4.&nbsp;Getting Object References With getattr">4</a> <span class="divider">|</span> <a href="filtering_lists.html" title="4.5.&nbsp;Filtering Lists">5</a> <span class="divider">|</span> <span class="thispage">6</span> <span class="divider">|</span> <a href="lambda_functions.html" title="4.7.&nbsp;Using lambda Functions">7</a> <span class="divider">|</span> <a href="all_together.html" title="4.8.&nbsp;Putting It All Together">8</a> <span class="divider">|</span> <a href="summary.html" title="4.9.&nbsp;Summary">9</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="lambda_functions.html">Using lambda Functions&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/power_of_introspection/built_in_functions.html b/help/diveintopython-5.4/html/power_of_introspection/built_in_functions.html
new file mode 100644
index 0000000..53434b4
--- /dev/null
+++ b/help/diveintopython-5.4/html/power_of_introspection/built_in_functions.html
@@ -0,0 +1,322 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>4.3.&nbsp;Using type, str, dir, and Other Built-In Functions</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;4.&nbsp;The Power Of Introspection">
+ <link rel="previous" href="optional_arguments.html" title="4.2.&nbsp;Using Optional and Named Arguments">
+ <link rel="next" href="getattr.html" title="4.4.&nbsp;Getting Object References With getattr">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">The Power Of Introspection</a>&nbsp;&gt;&nbsp;<span class="thispage">Using type, str, dir, and Other Built-In Functions</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="optional_arguments.html" title="Prev: &#8220;Using Optional and Named Arguments&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="getattr.html" title="Next: &#8220;Getting Object References With getattr&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="apihelper.builtin"></a>4.3.&nbsp;Using <tt class="function">type</tt>, <tt class="function">str</tt>, <tt class="function">dir</tt>, and Other Built-In Functions
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="toc">
+ <ul>
+ <li><span class="section"><a href="built_in_functions.html#d0e8510">4.3.1. The type Function</a></span></li>
+ <li><span class="section"><a href="built_in_functions.html#d0e8609">4.3.2. The str Function</a></span></li>
+ <li><span class="section"><a href="built_in_functions.html#d0e8958">4.3.3. Built-In Functions</a></span></li>
+ </ul>
+ </div>
+ <div class="abstract">
+ <p><span class="application">Python</span> has a small set of extremely useful built-in functions. All other functions are partitioned off into modules. This was
+ actually a conscious design decision, to keep the core language from getting bloated like other scripting languages (cough
+ cough, <span class="application">Visual Basic</span>).
+ </p>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e8510"></a>4.3.1.&nbsp;The <tt class="function">type</tt> Function
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p>The <tt class="function">type</tt> function returns the datatype of any arbitrary object. The possible types are listed in the <tt class="filename">types</tt> module. This is useful for helper functions that can handle several types of data.
+ </p>
+ <div class="example"><a name="apihelper.type.intro"></a><h3 class="title">Example&nbsp;4.5.&nbsp;Introducing <tt class="function">type</tt></h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">type(1)</span> <a name="apihelper.builtin.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">&lt;type 'int'&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li = []</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">type(li)</span> <a name="apihelper.builtin.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">&lt;type 'list'&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> odbchelper</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">type(odbchelper)</span> <a name="apihelper.builtin.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">&lt;type 'module'&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> types</span> <a name="apihelper.builtin.1.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">type(odbchelper) == types.ModuleType</span>
+<span class="computeroutput">True</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.builtin.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">type</tt> takes anything -- and I mean anything -- and returns its datatype. Integers, strings, lists, dictionaries, tuples, functions,
+ classes, modules, even types are acceptable.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.builtin.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">type</tt> can take a variable and return its datatype.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.builtin.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">type</tt> also works on modules.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.builtin.1.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You can use the constants in the <tt class="filename">types</tt> module to compare types of objects. This is what the <tt class="function">info</tt> function does, as you'll see shortly.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e8609"></a>4.3.2.&nbsp;The <tt class="function">str</tt> Function
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p>The <tt class="function">str</tt> coerces data into a string. Every datatype can be coerced into a string.
+ </p>
+ <div class="example"><a name="apihelper.str.intro"></a><h3 class="title">Example&nbsp;4.6.&nbsp;Introducing <tt class="function">str</tt></h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">str(1)</span> <a name="apihelper.builtin.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">'1'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">horsemen = [<span class='pystring'>'war'</span>, <span class='pystring'>'pestilence'</span>, <span class='pystring'>'famine'</span>]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">horsemen</span>
+<span class="computeroutput">['war', 'pestilence', 'famine']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">horsemen.append('<span class="application">Powerbuilder</span>')</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">str(horsemen)</span> <a name="apihelper.builtin.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">"['war', 'pestilence', 'famine', '<span class="application">Powerbuilder</span>']"</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">str(odbchelper)</span> <a name="apihelper.builtin.2.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">"&lt;module 'odbchelper' from 'c:\\docbook\\dip\\py\\odbchelper.py'&gt;"</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">str(None)</span> <a name="apihelper.builtin.2.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">'None'</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.builtin.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">For simple datatypes like integers, you would expect <tt class="function">str</tt> to work, because almost every language has a function to convert an integer to a string.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.builtin.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">However, <tt class="function">str</tt> works on any object of any type. Here it works on a list which you've constructed in bits and pieces.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.builtin.2.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">str</tt> also works on modules. Note that the string representation of the module includes the pathname of the module on disk, so
+ yours will be different.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.builtin.2.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">A subtle but important behavior of <tt class="function">str</tt> is that it works on <tt class="literal">None</tt>, the <span class="application">Python</span> null value. It returns the string <tt class="literal">'None'</tt>. You'll use this to your advantage in the <tt class="function">info</tt> function, as you'll see shortly.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>At the heart of the <tt class="function">info</tt> function is the powerful <tt class="function">dir</tt> function. <tt class="function">dir</tt> returns a list of the attributes and methods of any object: modules, functions, strings, lists, dictionaries... pretty much
+ anything.
+ </p>
+ <div class="example"><a name="apihelper.dir.intro"></a><h3 class="title">Example&nbsp;4.7.&nbsp;Introducing <tt class="function">dir</tt></h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li = []</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">dir(li)</span> <a name="apihelper.builtin.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">['append', 'count', 'extend', 'index', 'insert',
+'pop', 'remove', 'reverse', 'sort']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">d = {}</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">dir(d)</span> <a name="apihelper.builtin.3.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">['clear', 'copy', 'get', 'has_key', 'items', 'keys', 'setdefault', 'update', 'values']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> odbchelper</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">dir(odbchelper)</span> <a name="apihelper.builtin.3.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">['__builtins__', '__doc__', '__file__', '__name__', 'buildConnectionString']</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.builtin.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="varname">li</tt> is a list, so <tt class="literal"><tt class="function">dir</tt>(<tt class="varname">li</tt>)</tt> returns a list of all the methods of a list. Note that the returned list contains the names of the methods as strings, not
+ the methods themselves.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.builtin.3.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="varname">d</tt> is a dictionary, so <tt class="literal"><tt class="function">dir</tt>(<tt class="varname">d</tt>)</tt> returns a list of the names of dictionary methods. At least one of these, <a href="../native_data_types/mapping_lists.html#odbchelper.items" title="Example&nbsp;3.25.&nbsp;The keys, values, and items Functions"><tt class="function">keys</tt></a>, should look familiar.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.builtin.3.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This is where it really gets interesting. <tt class="filename">odbchelper</tt> is a module, so <tt class="literal"><tt class="function">dir</tt>(<tt class="filename">odbchelper</tt>)</tt> returns a list of all kinds of stuff defined in the module, including built-in attributes, like <a href="../getting_to_know_python/testing_modules.html#odbchelper.ifnametrick"><tt class="literal">__name__</tt></a>, <a href="../getting_to_know_python/everything_is_an_object.html#odbchelper.import" title="Example&nbsp;2.3.&nbsp;Accessing the buildConnectionString Function's doc string"><tt class="literal">__doc__</tt></a>, and whatever other attributes and methods you define. In this case, <tt class="filename">odbchelper</tt> has only one user-defined method, the <tt class="function">buildConnectionString</tt> function described in <a href="../getting_to_know_python/index.html">Chapter 2</a>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>Finally, the <tt class="function">callable</tt> function takes any object and returns <tt class="constant">True</tt> if the object can be called, or <tt class="constant">False</tt> otherwise. Callable objects include functions, class methods, even classes themselves. (More on classes in the next chapter.)
+ </p>
+ <div class="example"><a name="apihelper.builtin.callable"></a><h3 class="title">Example&nbsp;4.8.&nbsp;Introducing <tt class="function">callable</tt></h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> string</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">string.punctuation</span> <a name="apihelper.builtin.4.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">'!"#$%&amp;\'()*+,-./:;&lt;=&gt;?@[\\]^_`{|}~'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">string.join</span> <a name="apihelper.builtin.4.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">&lt;function join at 00C55A7C&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">callable(string.punctuation)</span> <a name="apihelper.builtin.4.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">False</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">callable(string.join)</span> <a name="apihelper.builtin.4.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">True</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> string.join.__doc__</span> <a name="apihelper.builtin.4.5"></a><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12">
+<span class="computeroutput">join(list [,sep]) -&gt; string
+
+ Return a string composed of the words in list, with
+ intervening occurrences of sep. The default separator is a
+ single space.
+
+ (joinfields and join are synonymous)</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.builtin.4.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The functions in the <tt class="filename">string</tt> module are deprecated (although many people still use the <tt class="function">join</tt> function), but the module contains a lot of useful constants like this <tt class="varname">string.punctuation</tt>, which contains all the standard punctuation characters.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.builtin.4.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><a href="../native_data_types/joining_lists.html" title="3.7.&nbsp;Joining Lists and Splitting Strings"><tt class="function">string.join</tt></a> is a function that joins a list of strings.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.builtin.4.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="varname">string.punctuation</tt> is not callable; it is a string. (A string does have callable methods, but the string itself is not callable.)
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.builtin.4.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">string.join</tt> is callable; it's a function that takes two arguments.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.builtin.4.5"><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Any callable object may have a <tt class="literal">doc string</tt>. By using the <tt class="function">callable</tt> function on each of an object's attributes, you can determine which attributes you care about (methods, functions, classes)
+ and which you want to ignore (constants and so on) without knowing anything about the object ahead of time.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e8958"></a>4.3.3.&nbsp;Built-In Functions
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p><tt class="function">type</tt>, <tt class="function">str</tt>, <tt class="function">dir</tt>, and all the rest of <span class="application">Python</span>'s built-in functions are grouped into a special module called <tt class="filename">__builtin__</tt>. (That's two underscores before and after.) If it helps, you can think of <span class="application">Python</span> automatically executing <tt class="literal">from __builtin__ import *</tt> on startup, which imports all the &#8220;<span class="quote">built-in</span>&#8221; functions into the namespace so you can use them directly.
+ </p>
+ <p>The advantage of thinking like this is that you can access all the built-in functions and attributes as a group by getting
+ information about the <tt class="filename">__builtin__</tt> module. And guess what, <span class="application">Python</span> has a function called <tt class="function">info</tt>. Try it yourself and skim through the list now. We'll dive into some of the more important functions later. (Some of the
+ built-in error classes, like <a href="../native_data_types/tuples.html#odbchelper.tuplemethods" title="Example&nbsp;3.16.&nbsp;Tuples Have No Methods"><tt class="errorcode">AttributeError</tt></a>, should already look familiar.)
+ </p>
+ <div class="example"><a name="apihelper.builtin.list"></a><h3 class="title">Example&nbsp;4.9.&nbsp;Built-in Attributes and Functions</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>from</span> apihelper <span class='pykeyword'>import</span> info</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> __builtin__</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">info(__builtin__, 20)</span>
+<span class="computeroutput">ArithmeticError Base class for arithmetic errors.
+AssertionError Assertion failed.
+AttributeError Attribute not found.
+EOFError Read beyond end of file.
+EnvironmentError Base class for I/O related errors.
+Exception Common base class for all exceptions.
+FloatingPointError Floating point operation failed.
+IOError I/O operation failed.
+
+[...snip...]</span></pre></div><a name="tip.manuals"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%"><span class="application">Python</span> comes with excellent reference manuals, which you should peruse thoroughly to learn all the modules <span class="application">Python</span> has to offer. But unlike most languages, where you would find yourself referring back to the manuals or man pages to remind
+ yourself how to use these modules, <span class="application">Python</span> is largely self-documenting.
+ </td>
+ </tr>
+ </table>
+ <div class="furtherreading">
+ <h3>Further Reading on Built-In Functions</h3>
+ <ul>
+ <li><a href="http://www.python.org/doc/current/lib/"><i class="citetitle"><span class="application">Python</span> Library Reference</i></a> documents <a href="http://www.python.org/doc/current/lib/built-in-funcs.html">all the built-in functions</a> and <a href="http://www.python.org/doc/current/lib/module-exceptions.html">all the built-in exceptions</a>.
+ </li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="optional_arguments.html">&lt;&lt;&nbsp;Using Optional and Named Arguments</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#apihelper.divein" title="4.1.&nbsp;Diving In">1</a> <span class="divider">|</span> <a href="optional_arguments.html" title="4.2.&nbsp;Using Optional and Named Arguments">2</a> <span class="divider">|</span> <span class="thispage">3</span> <span class="divider">|</span> <a href="getattr.html" title="4.4.&nbsp;Getting Object References With getattr">4</a> <span class="divider">|</span> <a href="filtering_lists.html" title="4.5.&nbsp;Filtering Lists">5</a> <span class="divider">|</span> <a href="and_or.html" title="4.6.&nbsp;The Peculiar Nature of and and or">6</a> <span class="divider">|</span> <a href="lambda_functions.html" title="4.7.&nbsp;Using lambda Functions">7</a> <span class="divider">|</span> <a href="all_together.html" title="4.8.&nbsp;Putting It All Together">8</a> <span class="divider">|</span> <a href="summary.html" title="4.9.&nbsp;Summary">9</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="getattr.html">Getting Object References With getattr&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/power_of_introspection/filtering_lists.html b/help/diveintopython-5.4/html/power_of_introspection/filtering_lists.html
new file mode 100644
index 0000000..c6d913b
--- /dev/null
+++ b/help/diveintopython-5.4/html/power_of_introspection/filtering_lists.html
@@ -0,0 +1,129 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>4.5.&nbsp;Filtering Lists</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;4.&nbsp;The Power Of Introspection">
+ <link rel="previous" href="getattr.html" title="4.4.&nbsp;Getting Object References With getattr">
+ <link rel="next" href="and_or.html" title="4.6.&nbsp;The Peculiar Nature of and and or">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">The Power Of Introspection</a>&nbsp;&gt;&nbsp;<span class="thispage">Filtering Lists</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="getattr.html" title="Prev: &#8220;Getting Object References With getattr&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="and_or.html" title="Next: &#8220;The Peculiar Nature of and and or&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="apihelper.filter"></a>4.5.&nbsp;Filtering Lists
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>As you know, <span class="application">Python</span> has powerful capabilities for mapping lists into other lists, via list comprehensions (<a href="../native_data_types/mapping_lists.html" title="3.6.&nbsp;Mapping Lists">Section&nbsp;3.6, &#8220;Mapping Lists&#8221;</a>). This can be combined with a filtering mechanism, where some elements in the list are mapped while others are skipped entirely.
+ </p>
+ </div>
+ <div class="informalexample">
+ <p>Here is the list filtering syntax:</p><pre class="programlisting">
+[<i class="replaceable"><tt>mapping-expression</tt></i><span class='pykeyword'> for</span> <i class="replaceable"><tt>element</tt></i><span class='pykeyword'> in</span> <i class="replaceable"><tt>source-list</tt></i><span class='pykeyword'> if</span> <i class="replaceable"><tt>filter-expression</tt></i>]</pre></div>
+ <p>This is an extension of the <a href="../native_data_types/mapping_lists.html" title="3.6.&nbsp;Mapping Lists">list comprehensions</a> that you know and love. The first two thirds are the same; the last part, starting with the <tt class="literal">if</tt>, is the filter expression. A filter expression can be any expression that evaluates true or false (which in <span class="application">Python</span> can be <a href="../native_data_types/lists.html#tip.boolean">almost anything</a>). Any element for which the filter expression evaluates true will be included in the mapping. All other elements are ignored,
+ so they are never put through the mapping expression and are not included in the output list.
+ </p>
+ <div class="example"><a name="d0e9539"></a><h3 class="title">Example&nbsp;4.14.&nbsp;Introducing List Filtering</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li = [<span class='pystring'>"a"</span>, <span class='pystring'>"mpilgrim"</span>, <span class='pystring'>"foo"</span>, <span class='pystring'>"b"</span>, <span class='pystring'>"c"</span>, <span class='pystring'>"b"</span>, <span class='pystring'>"d"</span>, <span class='pystring'>"d"</span>]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">[elem <span class='pykeyword'>for</span> elem <span class='pykeyword'>in</span> li <span class='pykeyword'>if</span> len(elem) &gt; 1]</span> <a name="apihelper.filter.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">['mpilgrim', 'foo']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">[elem <span class='pykeyword'>for</span> elem <span class='pykeyword'>in</span> li <span class='pykeyword'>if</span> elem != <span class='pystring'>"b"</span>]</span> <a name="apihelper.filter.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">['a', 'mpilgrim', 'foo', 'c', 'd', 'd']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">[elem <span class='pykeyword'>for</span> elem <span class='pykeyword'>in</span> li <span class='pykeyword'>if</span> li.count(elem) == 1]</span> <a name="apihelper.filter.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">['a', 'mpilgrim', 'foo', 'c']</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.filter.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The mapping expression here is simple (it just returns the value of each element), so concentrate on the filter expression.
+ As <span class="application">Python</span> loops through the list, it runs each element through the filter expression. If the filter expression is true, the element
+ is mapped and the result of the mapping expression is included in the returned list. Here, you are filtering out all the
+ one-character strings, so you're left with a list of all the longer strings.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.filter.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Here, you are filtering out a specific value, <tt class="literal">b</tt>. Note that this filters all occurrences of <tt class="literal">b</tt>, since each time it comes up, the filter expression will be false.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.filter.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">count</tt> is a list method that returns the number of times a value occurs in a list. You might think that this filter would eliminate
+ duplicates from a list, returning a list containing only one copy of each value in the original list. But it doesn't, because
+ values that appear twice in the original list (in this case, <tt class="literal">b</tt> and <tt class="literal">d</tt>) are excluded completely. There are ways of eliminating duplicates from a list, but filtering is not the solution.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="informalexample"><a name="apihelper.filter.care"></a><p>Let's get back to this line from <tt class="filename">apihelper.py</tt>:
+ </p><pre class="programlisting">
+ methodList = [method <span class='pykeyword'>for</span> method <span class='pykeyword'>in</span> dir(object) <span class='pykeyword'>if</span> callable(getattr(object, method))]</pre></div>
+ <p>This looks complicated, and it is complicated, but the basic structure is the same. The whole filter expression returns a
+ list, which is assigned to the <tt class="varname">methodList</tt> variable. The first half of the expression is the list mapping part. The mapping expression is an identity expression,
+ which it returns the value of each element. <tt class="literal"><tt class="function">dir</tt>(<tt class="varname">object</tt>)</tt> returns a list of <tt class="varname">object</tt>'s attributes and methods -- that's the list you're mapping. So the only new part is the filter expression after the <tt class="literal">if</tt>.
+ </p>
+ <p>The filter expression looks scary, but it's not. You already know about <a href="built_in_functions.html#apihelper.builtin.callable" title="Example&nbsp;4.8.&nbsp;Introducing callable"><tt class="function">callable</tt></a>, <a href="getattr.html#apihelper.getattr.intro" title="Example&nbsp;4.10.&nbsp;Introducing getattr"><tt class="function">getattr</tt></a>, and <a href="../native_data_types/tuples.html#odbchelper.tuplemethods" title="Example&nbsp;3.16.&nbsp;Tuples Have No Methods"><tt class="literal">in</tt></a>. As you saw in the <a href="getattr.html" title="4.4.&nbsp;Getting Object References With getattr">previous section</a>, the expression <tt class="literal">getattr(object, method)</tt> returns a function object if <tt class="varname">object</tt> is a module and <tt class="varname">method</tt> is the name of a function in that module.
+ </p>
+ <p>So this expression takes an object (named <tt class="varname">object</tt>). Then it gets a list of the names of the object's attributes, methods, functions, and a few other things. Then it filters
+ that list to weed out all the stuff that you don't care about. You do the weeding out by taking the name of each attribute/method/function
+ and getting a reference to the real thing, via the <tt class="function">getattr</tt> function. Then you check to see if that object is callable, which will be any methods and functions, both built-in (like
+ the <tt class="function">pop</tt> method of a list) and user-defined (like the <tt class="function">buildConnectionString</tt> function of the <tt class="filename">odbchelper</tt> module). You don't care about other attributes, like the <tt class="literal">__name__</tt> attribute that's built in to every module.
+ </p>
+ <div class="furtherreading">
+ <h3>Further Reading on Filtering Lists</h3>
+ <ul>
+ <li><a href="http://www.python.org/doc/current/tut/tut.html"><i class="citetitle"><span class="application">Python</span> Tutorial</i></a> discusses another way to filter lists <a href="http://www.python.org/doc/current/tut/node7.html#SECTION007130000000000000000">using the built-in <tt class="function">filter</tt> function</a>.
+ </li>
+ </ul>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="getattr.html">&lt;&lt;&nbsp;Getting Object References With getattr</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#apihelper.divein" title="4.1.&nbsp;Diving In">1</a> <span class="divider">|</span> <a href="optional_arguments.html" title="4.2.&nbsp;Using Optional and Named Arguments">2</a> <span class="divider">|</span> <a href="built_in_functions.html" title="4.3.&nbsp;Using type, str, dir, and Other Built-In Functions">3</a> <span class="divider">|</span> <a href="getattr.html" title="4.4.&nbsp;Getting Object References With getattr">4</a> <span class="divider">|</span> <span class="thispage">5</span> <span class="divider">|</span> <a href="and_or.html" title="4.6.&nbsp;The Peculiar Nature of and and or">6</a> <span class="divider">|</span> <a href="lambda_functions.html" title="4.7.&nbsp;Using lambda Functions">7</a> <span class="divider">|</span> <a href="all_together.html" title="4.8.&nbsp;Putting It All Together">8</a> <span class="divider">|</span> <a href="summary.html" title="4.9.&nbsp;Summary">9</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="and_or.html">The Peculiar Nature of and and or&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/power_of_introspection/getattr.html b/help/diveintopython-5.4/html/power_of_introspection/getattr.html
new file mode 100644
index 0000000..7a1e6e6
--- /dev/null
+++ b/help/diveintopython-5.4/html/power_of_introspection/getattr.html
@@ -0,0 +1,260 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>4.4.&nbsp;Getting Object References With getattr</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;4.&nbsp;The Power Of Introspection">
+ <link rel="previous" href="built_in_functions.html" title="4.3.&nbsp;Using type, str, dir, and Other Built-In Functions">
+ <link rel="next" href="filtering_lists.html" title="4.5.&nbsp;Filtering Lists">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">The Power Of Introspection</a>&nbsp;&gt;&nbsp;<span class="thispage">Getting Object References With getattr</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="built_in_functions.html" title="Prev: &#8220;Using type, str, dir, and Other Built-In Functions&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="filtering_lists.html" title="Next: &#8220;Filtering Lists&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="apihelper.getattr"></a>4.4.&nbsp;Getting Object References With <tt class="function">getattr</tt></h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="toc">
+ <ul>
+ <li><span class="section"><a href="getattr.html#d0e9194">4.4.1. getattr with Modules</a></span></li>
+ <li><span class="section"><a href="getattr.html#d0e9362">4.4.2. getattr As a Dispatcher</a></span></li>
+ </ul>
+ </div>
+ <div class="abstract">
+ <p>You already know that <a href="../getting_to_know_python/everything_is_an_object.html" title="2.4.&nbsp;Everything Is an Object"><span class="application">Python</span> functions are objects</a>. What you don't know is that you can get a reference to a function without knowing its name until run-time, by using the
+ <tt class="function">getattr</tt> function.
+ </p>
+ </div>
+ <div class="example"><a name="apihelper.getattr.intro"></a><h3 class="title">Example&nbsp;4.10.&nbsp;Introducing <tt class="function">getattr</tt></h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li = [<span class='pystring'>"Larry"</span>, <span class='pystring'>"Curly"</span>]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li.pop</span> <a name="apihelper.getattr.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">&lt;built-in method pop of list object at 010DF884&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">getattr(li, <span class='pystring'>"pop"</span>)</span> <a name="apihelper.getattr.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">&lt;built-in method pop of list object at 010DF884&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">getattr(li, <span class='pystring'>"append"</span>)(<span class='pystring'>"Moe"</span>)</span> <a name="apihelper.getattr.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li</span>
+<span class="computeroutput">["Larry", "Curly", "Moe"]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">getattr({}, <span class='pystring'>"clear"</span>)</span> <a name="apihelper.getattr.1.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">&lt;built-in method clear of dictionary object at 00F113D4&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">getattr((), <span class='pystring'>"pop"</span>)</span> <a name="apihelper.getattr.1.5"></a><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12">
+<span class="traceback">Traceback (innermost last):
+ File "&lt;interactive input&gt;", line 1, in ?
+AttributeError: 'tuple' object has no attribute 'pop'</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.getattr.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This gets a reference to the <tt class="function">pop</tt> method of the list. Note that this is not calling the <tt class="function">pop</tt> method; that would be <tt class="literal">li.pop()</tt>. This is the method itself.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.getattr.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This also returns a reference to the <tt class="function">pop</tt> method, but this time, the method name is specified as a string argument to the <tt class="function">getattr</tt> function. <tt class="function">getattr</tt> is an incredibly useful built-in function that returns any attribute of any object. In this case, the object is a list,
+ and the attribute is the <tt class="function">pop</tt> method.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.getattr.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">In case it hasn't sunk in just how incredibly useful this is, try this: the return value of <tt class="function">getattr</tt> <span class="emphasis"><em>is</em></span> the method, which you can then call just as if you had said <tt class="literal">li.append("Moe")</tt> directly. But you didn't call the function directly; you specified the function name as a string instead.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.getattr.1.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">getattr</tt> also works on dictionaries.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.getattr.1.5"><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">In theory, <tt class="function">getattr</tt> would work on tuples, except that <a href="../native_data_types/tuples.html#odbchelper.tuplemethods" title="Example&nbsp;3.16.&nbsp;Tuples Have No Methods">tuples have no methods</a>, so <tt class="function">getattr</tt> will raise an exception no matter what attribute name you give.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e9194"></a>4.4.1.&nbsp;<tt class="function">getattr</tt> with Modules
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p><tt class="function">getattr</tt> isn't just for built-in datatypes. It also works on modules.
+ </p>
+ <div class="example"><a name="apihelper.getattr.example"></a><h3 class="title">Example&nbsp;4.11.&nbsp;The <tt class="function">getattr</tt> Function in <tt class="filename">apihelper.py</tt></h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> odbchelper</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">odbchelper.buildConnectionString</span> <a name="apihelper.getattr.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">&lt;function buildConnectionString at 00D18DD4&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">getattr(odbchelper, <span class='pystring'>"buildConnectionString"</span>)</span> <a name="apihelper.getattr.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">&lt;function buildConnectionString at 00D18DD4&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">object = odbchelper</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">method = <span class='pystring'>"buildConnectionString"</span></span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">getattr(object, method)</span> <a name="apihelper.getattr.2.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">&lt;function buildConnectionString at 00D18DD4&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">type(getattr(object, method))</span> <a name="apihelper.getattr.2.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">&lt;type 'function'&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> types</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">type(getattr(object, method)) == types.FunctionType</span>
+<span class="computeroutput">True</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">callable(getattr(object, method))</span> <a name="apihelper.getattr.2.5"></a><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12">
+<span class="computeroutput">True</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.getattr.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This returns a reference to the <tt class="function">buildConnectionString</tt> function in the <tt class="filename">odbchelper</tt> module, which you studied in <a href="../getting_to_know_python/index.html" title="Chapter&nbsp;2.&nbsp;Your First Python Program">Chapter&nbsp;2, <i>Your First Python Program</i></a>. (The hex address you see is specific to my machine; your output will be different.)
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.getattr.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Using <tt class="function">getattr</tt>, you can get the same reference to the same function. In general, <tt class="literal"><tt class="function">getattr</tt>(<i class="replaceable">object</i>, "<i class="replaceable">attribute</i>")</tt> is equivalent to <tt class="literal"><i class="replaceable">object</i>.<i class="replaceable">attribute</i></tt>. If <i class="replaceable"><tt>object</tt></i> is a module, then <i class="replaceable"><tt>attribute</tt></i> can be anything defined in the module: a function, class, or global variable.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.getattr.2.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">And this is what you actually use in the <tt class="function">info</tt> function. <tt class="varname">object</tt> is passed into the function as an argument; <tt class="varname">method</tt> is a string which is the name of a method or function.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.getattr.2.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">In this case, <tt class="varname">method</tt> is the name of a function, which you can prove by getting its <a href="built_in_functions.html#apihelper.type.intro" title="Example&nbsp;4.5.&nbsp;Introducing type"><tt class="function">type</tt></a>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.getattr.2.5"><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Since <tt class="varname">method</tt> is a function, it is <a href="built_in_functions.html#apihelper.builtin.callable" title="Example&nbsp;4.8.&nbsp;Introducing callable">callable</a>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e9362"></a>4.4.2.&nbsp;<tt class="function">getattr</tt> As a Dispatcher
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p>A common usage pattern of <tt class="function">getattr</tt> is as a dispatcher. For example, if you had a program that could output data in a variety of different formats, you could
+ define separate functions for each output format and use a single dispatch function to call the right one.
+ </p>
+ <p>For example, let's imagine a program that prints site statistics in <span class="acronym">HTML</span>, <span class="acronym">XML</span>, and plain text formats. The choice of output format could be specified on the command line, or stored in a configuration
+ file. A <tt class="filename">statsout</tt> module defines three functions, <tt class="function">output_html</tt>, <tt class="function">output_xml</tt>, and <tt class="function">output_text</tt>. Then the main program defines a single output function, like this:
+ </p>
+ <div class="example"><a name="apihelper.getattr.dispatch"></a><h3 class="title">Example&nbsp;4.12.&nbsp;Creating a Dispatcher with <tt class="function">getattr</tt></h3><pre class="programlisting"><span class='pykeyword'>
+import</span> statsout
+
+<span class='pykeyword'>def</span><span class='pyclass'> output</span>(data, format=<span class='pystring'>"text"</span>): <a name="apihelper.getattr.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ output_function = getattr(statsout, <span class='pystring'>"output_%s"</span> % format) <a name="apihelper.getattr.3.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+ <span class='pykeyword'>return</span> output_function(data) <a name="apihelper.getattr.3.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+</pre></div>
+ <div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.getattr.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="function">output</tt> function takes one required argument, <tt class="varname">data</tt>, and one optional argument, <tt class="varname">format</tt>. If <tt class="varname">format</tt> is not specified, it defaults to <tt class="literal">text</tt>, and you will end up calling the plain text output function.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.getattr.3.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You concatenate the <tt class="varname">format</tt> argument with "output_" to produce a function name, and then go get that function from the <tt class="filename">statsout</tt> module. This allows you to easily extend the program later to support other output formats, without changing this dispatch
+ function. Just add another function to <tt class="filename">statsout</tt> named, for instance, <tt class="function">output_pdf</tt>, and pass "pdf" as the <tt class="varname">format</tt> into the <tt class="function">output</tt> function.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.getattr.3.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Now you can simply call the output function in the same way as any other function. The <tt class="varname">output_function</tt> variable is a reference to the appropriate function from the <tt class="filename">statsout</tt> module.
+ </td>
+ </tr>
+ </table>
+ </div>
+ <p>Did you see the bug in the previous example? This is a very loose coupling of strings and functions, and there is no error
+ checking. What happens if the user passes in a format that doesn't have a corresponding function defined in <tt class="filename">statsout</tt>? Well, <tt class="function">getattr</tt> will return <tt class="literal">None</tt>, which will be assigned to <tt class="varname">output_function</tt> instead of a valid function, and the next line that attempts to call that function will crash and raise an exception. That's
+ bad.
+ </p>
+ <p>Luckily, <tt class="function">getattr</tt> takes an optional third argument, a default value.
+ </p>
+ <div class="example"><a name="apihelper.getattr.default"></a><h3 class="title">Example&nbsp;4.13.&nbsp;<tt class="function">getattr</tt> Default Values
+ </h3><pre class="programlisting"><span class='pykeyword'>
+import</span> statsout
+
+<span class='pykeyword'>def</span><span class='pyclass'> output</span>(data, format=<span class='pystring'>"text"</span>):
+ output_function = getattr(statsout, <span class='pystring'>"output_%s"</span> % format, statsout.output_text)
+ <span class='pykeyword'>return</span> output_function(data) <a name="apihelper.getattr.4.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.getattr.4.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This function call is guaranteed to work, because you added a third argument to the call to <tt class="function">getattr</tt>. The third argument is a default value that is returned if the attribute or method specified by the second argument wasn't
+ found.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>As you can see, <tt class="function">getattr</tt> is quite powerful. It is the heart of introspection, and you'll see even more powerful examples of it in later chapters.
+ </p>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="built_in_functions.html">&lt;&lt;&nbsp;Using type, str, dir, and Other Built-In Functions</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#apihelper.divein" title="4.1.&nbsp;Diving In">1</a> <span class="divider">|</span> <a href="optional_arguments.html" title="4.2.&nbsp;Using Optional and Named Arguments">2</a> <span class="divider">|</span> <a href="built_in_functions.html" title="4.3.&nbsp;Using type, str, dir, and Other Built-In Functions">3</a> <span class="divider">|</span> <span class="thispage">4</span> <span class="divider">|</span> <a href="filtering_lists.html" title="4.5.&nbsp;Filtering Lists">5</a> <span class="divider">|</span> <a href="and_or.html" title="4.6.&nbsp;The Peculiar Nature of and and or">6</a> <span class="divider">|</span> <a href="lambda_functions.html" title="4.7.&nbsp;Using lambda Functions">7</a> <span class="divider">|</span> <a href="all_together.html" title="4.8.&nbsp;Putting It All Together">8</a> <span class="divider">|</span> <a href="summary.html" title="4.9.&nbsp;Summary">9</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="filtering_lists.html">Filtering Lists&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/power_of_introspection/index.html b/help/diveintopython-5.4/html/power_of_introspection/index.html
new file mode 100644
index 0000000..cbfc3aa
--- /dev/null
+++ b/help/diveintopython-5.4/html/power_of_introspection/index.html
@@ -0,0 +1,193 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>Chapter&nbsp;4.&nbsp;The Power Of Introspection</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="../toc/index.html" title="Dive Into Python">
+ <link rel="previous" href="../native_data_types/summary.html" title="3.8.&nbsp;Summary">
+ <link rel="next" href="optional_arguments.html" title="4.2.&nbsp;Using Optional and Named Arguments">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<span class="thispage">The Power Of Introspection</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="../native_data_types/summary.html" title="Prev: &#8220;Summary&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="optional_arguments.html" title="Next: &#8220;Using Optional and Named Arguments&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="chapter" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="apihelper"></a>Chapter&nbsp;4.&nbsp;The Power Of Introspection
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="toc">
+ <ul>
+ <li><span class="section"><a href="index.html#apihelper.divein">4.1. Diving In</a></span></li>
+ <li><span class="section"><a href="optional_arguments.html">4.2. Using Optional and Named Arguments</a></span></li>
+ <li><span class="section"><a href="built_in_functions.html">4.3. Using type, str, dir, and Other Built-In Functions</a></span><ul>
+ <li><span class="section"><a href="built_in_functions.html#d0e8510">4.3.1. The type Function</a></span></li>
+ <li><span class="section"><a href="built_in_functions.html#d0e8609">4.3.2. The str Function</a></span></li>
+ <li><span class="section"><a href="built_in_functions.html#d0e8958">4.3.3. Built-In Functions</a></span></li>
+ </ul>
+ </li>
+ <li><span class="section"><a href="getattr.html">4.4. Getting Object References With getattr</a></span><ul>
+ <li><span class="section"><a href="getattr.html#d0e9194">4.4.1. getattr with Modules</a></span></li>
+ <li><span class="section"><a href="getattr.html#d0e9362">4.4.2. getattr As a Dispatcher</a></span></li>
+ </ul>
+ </li>
+ <li><span class="section"><a href="filtering_lists.html">4.5. Filtering Lists</a></span></li>
+ <li><span class="section"><a href="and_or.html">4.6. The Peculiar Nature of and and or</a></span><ul>
+ <li><span class="section"><a href="and_or.html#d0e9975">4.6.1. Using the and-or Trick</a></span></li>
+ </ul>
+ </li>
+ <li><span class="section"><a href="lambda_functions.html">4.7. Using lambda Functions</a></span><ul>
+ <li><span class="section"><a href="lambda_functions.html#d0e10403">4.7.1. Real-World lambda Functions</a></span></li>
+ </ul>
+ </li>
+ <li><span class="section"><a href="all_together.html">4.8. Putting It All Together</a></span></li>
+ <li><span class="section"><a href="summary.html">4.9. Summary</a></span></li>
+ </ul>
+ </div>
+ <div class="abstract">
+ <p>This chapter covers one of <span class="application">Python</span>'s strengths: introspection. As you know, <a href="../getting_to_know_python/everything_is_an_object.html" title="2.4.&nbsp;Everything Is an Object">everything in <span class="application">Python</span> is an object</a>, and introspection is code looking at other modules and functions in memory as objects, getting information about them, and
+ manipulating them. Along the way, you'll define functions with no name, call functions with arguments out of order, and reference
+ functions whose names you don't even know ahead of time.
+ </p>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="apihelper.divein"></a>4.1.&nbsp;Diving In
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>Here is a complete, working <span class="application">Python</span> program. You should understand a good deal about it just by looking at it. The numbered lines illustrate concepts covered
+ in <a href="../getting_to_know_python/index.html" title="Chapter&nbsp;2.&nbsp;Your First Python Program">Chapter&nbsp;2, <i>Your First Python Program</i></a>. Don't worry if the rest of the code looks intimidating; you'll learn all about it throughout this chapter.
+ </p>
+ </div>
+ <div class="example"><a name="d0e8158"></a><h3 class="title">Example&nbsp;4.1.&nbsp;<tt class="filename">apihelper.py</tt></h3>
+ <p>If you have not already done so, you can <a href="http://diveintopython.org/download/diveintopython-examples-5.4.zip" title="Download example scripts">download this and other examples</a> used in this book.
+ </p><pre class="programlisting"><span class='pykeyword'>
+def</span> info(object, spacing=10, collapse=1): <a name="apihelper.intro.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"> <a name="apihelper.intro.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"> <a name="apihelper.intro.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+ <span class='pystring'>"""Print methods and doc strings.
+
+ Takes module, class, list, dictionary, or string."""</span>
+ methodList = [method <span class='pykeyword'>for</span> method <span class='pykeyword'>in</span> dir(object) <span class='pykeyword'>if</span> callable(getattr(object, method))]
+ processFunc = collapse <span class='pykeyword'>and</span> (<span class='pykeyword'>lambda</span> s: <span class='pystring'>" "</span>.join(s.split())) <span class='pykeyword'>or</span> (<span class='pykeyword'>lambda</span> s: s)
+ <span class='pykeyword'>print</span> <span class='pystring'>"\n"</span>.join([<span class='pystring'>"%s %s"</span> %
+ (method.ljust(spacing),
+ processFunc(str(getattr(object, method).__doc__)))
+ <span class='pykeyword'>for</span> method <span class='pykeyword'>in</span> methodList])
+
+<span class='pykeyword'>if</span> __name__ == <span class='pystring'>"__main__"</span>: <a name="apihelper.intro.1.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"> <a name="apihelper.intro.1.5"></a><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12">
+ <span class='pykeyword'>print</span> info.__doc__</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.intro.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This module has one function, <tt class="function">info</tt>. According to its <a href="../getting_to_know_python/declaring_functions.html" title="2.2.&nbsp;Declaring Functions">function declaration</a>, it takes three parameters: <tt class="varname">object</tt>, <tt class="varname">spacing</tt>, and <tt class="varname">collapse</tt>. The last two are actually optional parameters, as you'll see shortly.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.intro.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="function">info</tt> function has a multi-line <a href="../getting_to_know_python/documenting_functions.html" title="2.3.&nbsp;Documenting Functions"><tt class="literal">doc string</tt></a> that succinctly describes the function's purpose. Note that no return value is mentioned; this function will be used solely
+ for its effects, rather than its value.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.intro.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Code within the function is <a href="../getting_to_know_python/indenting_code.html" title="2.5.&nbsp;Indenting Code">indented</a>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.intro.1.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="literal"><span class="literal">if</span> <span class="literal">__name__</span></tt> <a href="../getting_to_know_python/testing_modules.html#odbchelper.ifnametrick">trick</a> allows this program do something useful when run by itself, without interfering with its use as a module for other programs.
+ In this case, the program simply prints out the <tt class="literal">doc string</tt> of the <tt class="function">info</tt> function.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.intro.1.5"><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><a href="../getting_to_know_python/testing_modules.html#odbchelper.ifnametrick"><tt class="literal">if</tt> statements</a> use <tt class="literal">==</tt> for comparison, and parentheses are not required.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>The <tt class="function">info</tt> function is designed to be used by you, the programmer, while working in the <span class="application">Python</span> <span class="acronym">IDE</span>. It takes any object that has functions or methods (like a module, which has functions, or a list, which has methods) and
+ prints out the functions and their <tt class="literal">doc string</tt>s.
+ </p>
+ <div class="example"><a name="d0e8257"></a><h3 class="title">Example&nbsp;4.2.&nbsp;Sample Usage of <tt class="filename">apihelper.py</tt></h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>from</span> apihelper <span class='pykeyword'>import</span> info</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li = []</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">info(li)</span>
+<span class="computeroutput">append L.append(object) -- append object to end
+count L.count(value) -&gt; integer -- return number of occurrences of value
+extend L.extend(list) -- extend list by appending list elements
+index L.index(value) -&gt; integer -- return index of first occurrence of value
+insert L.insert(index, object) -- insert object before index
+pop L.pop([index]) -&gt; item -- remove and return item at index (default last)
+remove L.remove(value) -- remove first occurrence of value
+reverse L.reverse() -- reverse *IN PLACE*
+sort L.sort([cmpfunc]) -- sort *IN PLACE*; if given, cmpfunc(x, y) -&gt; -1, 0, 1</span></pre></div>
+ <p>By default the output is formatted to be easy to read. Multi-line <tt class="literal">doc string</tt>s are collapsed into a single long line, but this option can be changed by specifying <tt class="constant">0</tt> for the <i class="parameter"><tt>collapse</tt></i> argument. If the function names are longer than 10 characters, you can specify a larger value for the <i class="parameter"><tt>spacing</tt></i> argument to make the output easier to read.
+ </p>
+ <div class="example"><a name="d0e8294"></a><h3 class="title">Example&nbsp;4.3.&nbsp;Advanced Usage of <tt class="filename">apihelper.py</tt></h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> odbchelper</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">info(odbchelper)</span>
+<span class="computeroutput">buildConnectionString Build a connection string from a dictionary Returns string.</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">info(odbchelper, 30)</span>
+<span class="computeroutput">buildConnectionString Build a connection string from a dictionary Returns string.</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">info(odbchelper, 30, 0)</span>
+<span class="computeroutput">buildConnectionString Build a connection string from a dictionary
+
+ Returns string.
+</span></pre></div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="../native_data_types/summary.html">&lt;&lt;&nbsp;Summary</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<span class="thispage">1</span> <span class="divider">|</span> <a href="optional_arguments.html" title="4.2.&nbsp;Using Optional and Named Arguments">2</a> <span class="divider">|</span> <a href="built_in_functions.html" title="4.3.&nbsp;Using type, str, dir, and Other Built-In Functions">3</a> <span class="divider">|</span> <a href="getattr.html" title="4.4.&nbsp;Getting Object References With getattr">4</a> <span class="divider">|</span> <a href="filtering_lists.html" title="4.5.&nbsp;Filtering Lists">5</a> <span class="divider">|</span> <a href="and_or.html" title="4.6.&nbsp;The Peculiar Nature of and and or">6</a> <span class="divider">|</span> <a href="lambda_functions.html" title="4.7.&nbsp;Using lambda Functions">7</a> <span class="divider">|</span> <a href="all_together.html" title="4.8.&nbsp;Putting It All Together">8</a> <span class="divider">|</span> <a href="summary.html" title="4.9.&nbsp;Summary">9</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="optional_arguments.html">Using Optional and Named Arguments&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/power_of_introspection/lambda_functions.html b/help/diveintopython-5.4/html/power_of_introspection/lambda_functions.html
new file mode 100644
index 0000000..316c2e5
--- /dev/null
+++ b/help/diveintopython-5.4/html/power_of_introspection/lambda_functions.html
@@ -0,0 +1,189 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>4.7.&nbsp;Using lambda Functions</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;4.&nbsp;The Power Of Introspection">
+ <link rel="previous" href="and_or.html" title="4.6.&nbsp;The Peculiar Nature of and and or">
+ <link rel="next" href="all_together.html" title="4.8.&nbsp;Putting It All Together">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">The Power Of Introspection</a>&nbsp;&gt;&nbsp;<span class="thispage">Using lambda Functions</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="and_or.html" title="Prev: &#8220;The Peculiar Nature of and and or&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="all_together.html" title="Next: &#8220;Putting It All Together&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="apihelper.lambda"></a>4.7.&nbsp;Using <tt class="literal">lambda</tt> Functions
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="toc">
+ <ul>
+ <li><span class="section"><a href="lambda_functions.html#d0e10403">4.7.1. Real-World lambda Functions</a></span></li>
+ </ul>
+ </div>
+ <div class="abstract">
+ <p><span class="application">Python</span> supports an interesting syntax that lets you define one-line mini-functions on the fly. Borrowed from <span class="application">Lisp</span>, these so-called <tt class="literal">lambda</tt> functions can be used anywhere a function is required.
+ </p>
+ </div>
+ <div class="example"><a name="d0e10311"></a><h3 class="title">Example&nbsp;4.20.&nbsp;Introducing <tt class="literal">lambda</tt> Functions
+ </h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>def</span><span class='pyclass'> f</span>(x):</span>
+<tt class="prompt">... </tt><span class="userinput"><span class='pykeyword'>return</span> x*2</span>
+<tt class="prompt">... </tt><span class="userinput"></span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">f(3)</span>
+<span class="computeroutput">6</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">g = <span class='pykeyword'>lambda</span> x: x*2</span> <a name="apihelper.lambda.1.2"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">g(3)</span>
+<span class="computeroutput">6</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>(lambda</span> x: x*2)(3)</span> <a name="apihelper.lambda.1.3"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">6</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.lambda.1.2"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This is a <tt class="literal">lambda</tt> function that accomplishes the same thing as the normal function above it. Note the abbreviated syntax here: there are no
+ parentheses around the argument list, and the <tt class="literal">return</tt> keyword is missing (it is implied, since the entire function can only be one expression). Also, the function has no name,
+ but it can be called through the variable it is assigned to.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.lambda.1.3"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You can use a <tt class="literal">lambda</tt> function without even assigning it to a variable. This may not be the most useful thing in the world, but it just goes to
+ show that a lambda is just an in-line function.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>To generalize, a <tt class="literal">lambda</tt> function is a function that takes any number of arguments (including <a href="optional_arguments.html" title="4.2.&nbsp;Using Optional and Named Arguments">optional arguments</a>) and returns the value of a single expression. <tt class="literal">lambda</tt> functions can not contain commands, and they can not contain more than one expression. Don't try to squeeze too much into
+ a <tt class="literal">lambda</tt> function; if you need something more complex, define a normal function instead and make it as long as you want.
+ </p><a name="tip.lambda"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%"><tt class="literal">lambda</tt> functions are a matter of style. Using them is never required; anywhere you could use them, you could define a separate
+ normal function and use that instead. I use them in places where I want to encapsulate specific, non-reusable code without
+ littering my code with a lot of little one-line functions.
+ </td>
+ </tr>
+ </table>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e10403"></a>4.7.1.&nbsp;Real-World <tt class="literal">lambda</tt> Functions
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="informalexample">
+ <p>Here are the <tt class="literal">lambda</tt> functions in <tt class="filename">apihelper.py</tt>:
+ </p><pre class="programlisting">
+ processFunc = collapse <span class='pykeyword'>and</span> (<span class='pykeyword'>lambda</span> s: <span class='pystring'>" "</span>.join(s.split())) <span class='pykeyword'>or</span> (<span class='pykeyword'>lambda</span> s: s)</pre></div>
+ <p>Notice that this uses the simple form of the <a href="and_or.html" title="4.6.&nbsp;The Peculiar Nature of and and or"><tt class="literal">and-or</tt></a> trick, which is okay, because a <tt class="literal">lambda</tt> function is always true <a href="../native_data_types/lists.html#tip.boolean">in a boolean context</a>. (That doesn't mean that a <tt class="literal">lambda</tt> function can't return a false value. The function is always true; its return value could be anything.)
+ </p>
+ <p>Also notice that you're using the <tt class="function">split</tt> function with no arguments. You've already seen it used with <a href="../native_data_types/joining_lists.html#odbchelper.split.example" title="Example&nbsp;3.28.&nbsp;Splitting a String">one or two arguments</a>, but without any arguments it splits on whitespace.
+ </p>
+ <div class="example"><a name="d0e10444"></a><h3 class="title">Example&nbsp;4.21.&nbsp;<tt class="function">split</tt> With No Arguments
+ </h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">s = <span class='pystring'>"this is\na\ttest"</span></span> <a name="apihelper.split.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> s</span>
+<span class="computeroutput">this is
+a test</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> s.split()</span> <a name="apihelper.split.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">['this', 'is', 'a', 'test']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> <span class='pystring'>" "</span>.join(s.split())</span> <a name="apihelper.split.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">'this is a test'</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.split.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This is a multiline string, defined by escape characters instead of <a href="../getting_to_know_python/documenting_functions.html#odbchelper.triplequotes" title="Example&nbsp;2.2.&nbsp;Defining the buildConnectionString Function's doc string">triple quotes</a>. <tt class="literal">\n</tt> is a carriage return, and <tt class="literal">\t</tt> is a tab character.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.split.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">split</tt> without any arguments splits on whitespace. So three spaces, a carriage return, and a tab character are all the same.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper.split.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You can normalize whitespace by splitting a string with <tt class="function">split</tt> and then rejoining it with <tt class="function">join</tt>, using a single space as a delimiter. This is what the <tt class="function">info</tt> function does to collapse multi-line <tt class="literal">doc string</tt>s into a single line.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>So what is the <tt class="function">info</tt> function actually doing with these <tt class="literal">lambda</tt> functions, <tt class="function">split</tt>s, and <tt class="literal">and-or</tt> tricks?
+ </p>
+ <div class="informalexample"><a name="apihelper.funcassign"></a><pre class="programlisting">
+ processFunc = collapse <span class='pykeyword'>and</span> (<span class='pykeyword'>lambda</span> s: <span class='pystring'>" "</span>.join(s.split())) <span class='pykeyword'>or</span> (<span class='pykeyword'>lambda</span> s: s)</pre></div>
+ <p><tt class="varname">processFunc</tt> is now a function, but which function it is depends on the value of the <tt class="varname">collapse</tt> variable. If <tt class="varname">collapse</tt> is true, <tt class="literal"><tt class="varname">processFunc</tt>(<i class="replaceable">string</i>)</tt> will collapse whitespace; otherwise, <tt class="literal"><tt class="varname">processFunc</tt>(<i class="replaceable">string</i>)</tt> will return its argument unchanged.
+ </p>
+ <p>To do this in a less robust language, like <span class="application">Visual Basic</span>, you would probably create a function that took a string and a <i class="parameter"><tt>collapse</tt></i> argument and used an <tt class="literal">if</tt> statement to decide whether to collapse the whitespace or not, then returned the appropriate value. This would be inefficient,
+ because the function would need to handle every possible case. Every time you called it, it would need to decide whether
+ to collapse whitespace before it could give you what you wanted. In <span class="application">Python</span>, you can take that decision logic out of the function and define a <tt class="literal">lambda</tt> function that is custom-tailored to give you exactly (and only) what you want. This is more efficient, more elegant, and
+ less prone to those nasty oh-I-thought-those-arguments-were-reversed kinds of errors.
+ </p>
+ <div class="furtherreading">
+ <h3>Further Reading on <tt class="literal">lambda</tt> Functions
+ </h3>
+ <ul>
+ <li><a href="http://www.faqts.com/knowledge-base/index.phtml/fid/199/"><span class="application">Python</span> Knowledge Base</a> discusses using <tt class="literal">lambda</tt> to <a href="http://www.faqts.com/knowledge-base/view.phtml/aid/6081/fid/241">call functions indirectly</a>.
+ </li>
+ <li><a href="http://www.python.org/doc/current/tut/tut.html"><i class="citetitle"><span class="application">Python</span> Tutorial</i></a> shows how to <a href="http://www.python.org/doc/current/tut/node6.html#SECTION006740000000000000000">access outside variables from inside a <tt class="literal">lambda</tt> function</a>. (<a href="http://python.sourceforge.net/peps/pep-0227.html"><span class="acronym">PEP</span> 227</a> explains how this will change in future versions of <span class="application">Python</span>.)
+ </li>
+ <li><a href="http://www.python.org/doc/FAQ.html"><i class="citetitle">The Whole <span class="application">Python</span> <span class="acronym">FAQ</span></i></a> has examples of <a href="http://www.python.org/cgi-bin/faqw.py?query=4.15&amp;querytype=simple&amp;casefold=yes&amp;req=search">obfuscated one-liners using <tt class="literal">lambda</tt></a>.
+ </li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="and_or.html">&lt;&lt;&nbsp;The Peculiar Nature of and and or</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#apihelper.divein" title="4.1.&nbsp;Diving In">1</a> <span class="divider">|</span> <a href="optional_arguments.html" title="4.2.&nbsp;Using Optional and Named Arguments">2</a> <span class="divider">|</span> <a href="built_in_functions.html" title="4.3.&nbsp;Using type, str, dir, and Other Built-In Functions">3</a> <span class="divider">|</span> <a href="getattr.html" title="4.4.&nbsp;Getting Object References With getattr">4</a> <span class="divider">|</span> <a href="filtering_lists.html" title="4.5.&nbsp;Filtering Lists">5</a> <span class="divider">|</span> <a href="and_or.html" title="4.6.&nbsp;The Peculiar Nature of and and or">6</a> <span class="divider">|</span> <span class="thispage">7</span> <span class="divider">|</span> <a href="all_together.html" title="4.8.&nbsp;Putting It All Together">8</a> <span class="divider">|</span> <a href="summary.html" title="4.9.&nbsp;Summary">9</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="all_together.html">Putting It All Together&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/power_of_introspection/optional_arguments.html b/help/diveintopython-5.4/html/power_of_introspection/optional_arguments.html
new file mode 100644
index 0000000..adcb827
--- /dev/null
+++ b/help/diveintopython-5.4/html/power_of_introspection/optional_arguments.html
@@ -0,0 +1,130 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>4.2.&nbsp;Using Optional and Named Arguments</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;4.&nbsp;The Power Of Introspection">
+ <link rel="previous" href="index.html" title="Chapter&nbsp;4.&nbsp;The Power Of Introspection">
+ <link rel="next" href="built_in_functions.html" title="4.3.&nbsp;Using type, str, dir, and Other Built-In Functions">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">The Power Of Introspection</a>&nbsp;&gt;&nbsp;<span class="thispage">Using Optional and Named Arguments</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="index.html" title="Prev: &#8220;The Power Of Introspection&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="built_in_functions.html" title="Next: &#8220;Using type, str, dir, and Other Built-In Functions&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="apihelper.optional"></a>4.2.&nbsp;Using Optional and Named Arguments
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p><span class="application">Python</span> allows function arguments to have default values; if the function is called without the argument, the argument gets its default
+ value. Futhermore, arguments can be specified in any order by using named arguments. Stored procedures in <span class="application">SQL Server</span> Transact/<span class="acronym">SQL</span> can do this, so if you're a <span class="application">SQL Server</span> scripting guru, you can skim this part.
+ </p>
+ </div>
+ <div class="informalexample">
+ <p>Here is an example of <tt class="function">info</tt>, a function with two optional arguments:
+ </p><pre class="programlisting"><span class='pykeyword'>
+def</span> info(object, spacing=10, collapse=1):</pre></div>
+ <p><tt class="varname">spacing</tt> and <tt class="varname">collapse</tt> are optional, because they have default values defined. <tt class="varname">object</tt> is required, because it has no default value. If <tt class="function">info</tt> is called with only one argument, <tt class="varname">spacing</tt> defaults to <tt class="constant">10</tt> and <tt class="varname">collapse</tt> defaults to <tt class="constant">1</tt>. If <tt class="function">info</tt> is called with two arguments, <tt class="varname">collapse</tt> still defaults to <tt class="constant">1</tt>.
+ </p>
+ <p>Say you want to specify a value for <tt class="varname">collapse</tt> but want to accept the default value for <tt class="varname">spacing</tt>. In most languages, you would be out of luck, because you would need to call the function with three arguments. But in
+ <span class="application">Python</span>, arguments can be specified by name, in any order.
+ </p>
+ <div class="example"><a name="d0e8401"></a><h3 class="title">Example&nbsp;4.4.&nbsp;Valid Calls of <tt class="function">info</tt></h3><pre class="programlisting">
+info(odbchelper) <a name="apihelper_args.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+info(odbchelper, 12) <a name="apihelper_args.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+info(odbchelper, collapse=0) <a name="apihelper_args.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+info(spacing=15, object=odbchelper) <a name="apihelper_args.1.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper_args.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">With only one argument, <tt class="varname">spacing</tt> gets its default value of <tt class="literal">10</tt> and <tt class="varname">collapse</tt> gets its default value of <tt class="constant">1</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper_args.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">With two arguments, <tt class="varname">collapse</tt> gets its default value of <tt class="constant">1</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper_args.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Here you are naming the <tt class="varname">collapse</tt> argument explicitly and specifying its value. <tt class="varname">spacing</tt> still gets its default value of <tt class="literal">10</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#apihelper_args.1.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Even required arguments (like <tt class="varname">object</tt>, which has no default value) can be named, and named arguments can appear in any order.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>This looks totally whacked until you realize that arguments are simply a dictionary. The &#8220;<span class="quote">normal</span>&#8221; method of calling functions without argument names is actually just a shorthand where <span class="application">Python</span> matches up the values with the argument names in the order they're specified in the function declaration. And most of the
+ time, you'll call functions the &#8220;<span class="quote">normal</span>&#8221; way, but you always have the additional flexibility if you need it.
+ </p><a name="tip.arguments"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">The only thing you need to do to call a function is specify a value (somehow) for each required argument; the manner and order
+ in which you do that is up to you.
+ </td>
+ </tr>
+ </table>
+ <div class="furtherreading">
+ <h3>Further Reading on Optional Arguments</h3>
+ <ul>
+ <li><a href="http://www.python.org/doc/current/tut/tut.html"><i class="citetitle"><span class="application">Python</span> Tutorial</i></a> discusses exactly <a href="http://www.python.org/doc/current/tut/node6.html#SECTION006710000000000000000">when and how default arguments are evaluated</a>, which matters when the default value is a list or an expression with side effects.
+ </li>
+ </ul>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="index.html">&lt;&lt;&nbsp;The Power Of Introspection</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#apihelper.divein" title="4.1.&nbsp;Diving In">1</a> <span class="divider">|</span> <span class="thispage">2</span> <span class="divider">|</span> <a href="built_in_functions.html" title="4.3.&nbsp;Using type, str, dir, and Other Built-In Functions">3</a> <span class="divider">|</span> <a href="getattr.html" title="4.4.&nbsp;Getting Object References With getattr">4</a> <span class="divider">|</span> <a href="filtering_lists.html" title="4.5.&nbsp;Filtering Lists">5</a> <span class="divider">|</span> <a href="and_or.html" title="4.6.&nbsp;The Peculiar Nature of and and or">6</a> <span class="divider">|</span> <a href="lambda_functions.html" title="4.7.&nbsp;Using lambda Functions">7</a> <span class="divider">|</span> <a href="all_together.html" title="4.8.&nbsp;Putting It All Together">8</a> <span class="divider">|</span> <a href="summary.html" title="4.9.&nbsp;Summary">9</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="built_in_functions.html">Using type, str, dir, and Other Built-In Functions&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/power_of_introspection/summary.html b/help/diveintopython-5.4/html/power_of_introspection/summary.html
new file mode 100644
index 0000000..1b18182
--- /dev/null
+++ b/help/diveintopython-5.4/html/power_of_introspection/summary.html
@@ -0,0 +1,115 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>4.9.&nbsp;Summary</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;4.&nbsp;The Power Of Introspection">
+ <link rel="previous" href="all_together.html" title="4.8.&nbsp;Putting It All Together">
+ <link rel="next" href="../object_oriented_framework/index.html" title="Chapter&nbsp;5.&nbsp;Objects and Object-Orientation">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">The Power Of Introspection</a>&nbsp;&gt;&nbsp;<span class="thispage">Summary</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="all_together.html" title="Prev: &#8220;Putting It All Together&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="../object_oriented_framework/index.html" title="Next: &#8220;Objects and Object-Orientation&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="apihelper.summary"></a>4.9.&nbsp;Summary
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>The <tt class="filename">apihelper.py</tt> program and its output should now make perfect sense.
+ </p>
+ </div>
+ <div class="informalexample"><pre class="programlisting"><span class='pykeyword'>
+def</span> info(object, spacing=10, collapse=1):
+ <span class='pystring'>"""Print methods and doc strings.
+
+ Takes module, class, list, dictionary, or string."""</span>
+ methodList = [method <span class='pykeyword'>for</span> method <span class='pykeyword'>in</span> dir(object) <span class='pykeyword'>if</span> callable(getattr(object, method))]
+ processFunc = collapse <span class='pykeyword'>and</span> (<span class='pykeyword'>lambda</span> s: <span class='pystring'>" "</span>.join(s.split())) <span class='pykeyword'>or</span> (<span class='pykeyword'>lambda</span> s: s)
+ <span class='pykeyword'>print</span> <span class='pystring'>"\n"</span>.join([<span class='pystring'>"%s %s"</span> %
+ (method.ljust(spacing),
+ processFunc(str(getattr(object, method).__doc__)))
+ <span class='pykeyword'>for</span> method <span class='pykeyword'>in</span> methodList])
+
+<span class='pykeyword'>if</span> __name__ == <span class='pystring'>"__main__"</span>:
+ <span class='pykeyword'>print</span> info.__doc__</pre></div>
+ <div class="informalexample">
+ <p>Here is the output of <tt class="filename">apihelper.py</tt>:
+ </p><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>from</span> apihelper <span class='pykeyword'>import</span> info</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">li = []</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">info(li)</span>
+<span class="computeroutput">append L.append(object) -- append object to end
+count L.count(value) -&gt; integer -- return number of occurrences of value
+extend L.extend(list) -- extend list by appending list elements
+index L.index(value) -&gt; integer -- return index of first occurrence of value
+insert L.insert(index, object) -- insert object before index
+pop L.pop([index]) -&gt; item -- remove and return item at index (default last)
+remove L.remove(value) -- remove first occurrence of value
+reverse L.reverse() -- reverse *IN PLACE*
+sort L.sort([cmpfunc]) -- sort *IN PLACE*; if given, cmpfunc(x, y) -&gt; -1, 0, 1</span></pre></div>
+ <div class="highlights">
+ <p>Before diving into the next chapter, make sure you're comfortable doing all of these things:</p>
+ <div class="itemizedlist">
+ <ul>
+ <li>Defining and calling functions with <a href="optional_arguments.html" title="4.2.&nbsp;Using Optional and Named Arguments">optional and named arguments</a></li>
+ <li>Using <a href="built_in_functions.html#apihelper.str.intro" title="Example&nbsp;4.6.&nbsp;Introducing str"><tt class="function">str</tt></a> to coerce any arbitrary value into a string representation
+ </li>
+ <li>Using <a href="getattr.html" title="4.4.&nbsp;Getting Object References With getattr"><tt class="function">getattr</tt></a> to get references to functions and other attributes dynamically
+ </li>
+ <li>Extending the list comprehension syntax to do <a href="filtering_lists.html" title="4.5.&nbsp;Filtering Lists">list filtering</a></li>
+ <li>Recognizing <a href="and_or.html" title="4.6.&nbsp;The Peculiar Nature of and and or">the <tt class="literal">and-or</tt> trick</a> and using it safely
+ </li>
+ <li>Defining <a href="lambda_functions.html" title="4.7.&nbsp;Using lambda Functions"><tt class="literal">lambda</tt> functions</a></li>
+ <li><a href="lambda_functions.html#apihelper.funcassign">Assigning functions to variables</a> and calling the function by referencing the variable. I can't emphasize this enough, because this mode of thought is vital
+ to advancing your understanding of <span class="application">Python</span>. You'll see more complex applications of this concept throughout this book.
+ </li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="all_together.html">&lt;&lt;&nbsp;Putting It All Together</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#apihelper.divein" title="4.1.&nbsp;Diving In">1</a> <span class="divider">|</span> <a href="optional_arguments.html" title="4.2.&nbsp;Using Optional and Named Arguments">2</a> <span class="divider">|</span> <a href="built_in_functions.html" title="4.3.&nbsp;Using type, str, dir, and Other Built-In Functions">3</a> <span class="divider">|</span> <a href="getattr.html" title="4.4.&nbsp;Getting Object References With getattr">4</a> <span class="divider">|</span> <a href="filtering_lists.html" title="4.5.&nbsp;Filtering Lists">5</a> <span class="divider">|</span> <a href="and_or.html" title="4.6.&nbsp;The Peculiar Nature of and and or">6</a> <span class="divider">|</span> <a href="lambda_functions.html" title="4.7.&nbsp;Using lambda Functions">7</a> <span class="divider">|</span> <a href="all_together.html" title="4.8.&nbsp;Putting It All Together">8</a> <span class="divider">|</span> <span class="thispage">9</span>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="../object_oriented_framework/index.html">Objects and Object-Orientation&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/refactoring/handling_changing_requirements.html b/help/diveintopython-5.4/html/refactoring/handling_changing_requirements.html
new file mode 100644
index 0000000..c2df986
--- /dev/null
+++ b/help/diveintopython-5.4/html/refactoring/handling_changing_requirements.html
@@ -0,0 +1,456 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>15.2.&nbsp;Handling changing requirements</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;15.&nbsp;Refactoring">
+ <link rel="previous" href="index.html" title="Chapter&nbsp;15.&nbsp;Refactoring">
+ <link rel="next" href="refactoring.html" title="15.3.&nbsp;Refactoring">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Refactoring</a>&nbsp;&gt;&nbsp;<span class="thispage">Handling changing requirements</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="index.html" title="Prev: &#8220;Refactoring&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="refactoring.html" title="Next: &#8220;Refactoring&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="roman.change"></a>15.2.&nbsp;Handling changing requirements
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>Despite your best efforts to pin your customers to the ground and extract exact requirements from them on pain of horrible
+ nasty things involving scissors and hot wax, requirements will change. Most customers don't know what they want until they
+ see it, and even if they do, they aren't that good at articulating what they want precisely enough to be useful. And even
+ if they do, they'll want more in the next release anyway. So be prepared to update your test cases as requirements change.
+ </p>
+ </div>
+ <p>Suppose, for instance, that you wanted to expand the range of the Roman numeral conversion functions. Remember <a href="../unit_testing/diving_in.html" title="13.2.&nbsp;Diving in">the rule</a> that said that no character could be repeated more than three times? Well, the Romans were willing to make an exception
+ to that rule by having 4 <tt class="literal">M</tt> characters in a row to represent <tt class="literal">4000</tt>. If you make this change, you'll be able to expand the range of convertible numbers from <tt class="literal">1..3999</tt> to <tt class="literal">1..4999</tt>. But first, you need to make some changes to the test cases.
+ </p>
+ <div class="example"><a name="d0e34307"></a><h3 class="title">Example&nbsp;15.6.&nbsp;Modifying test cases for new requirements (<tt class="filename">romantest71.py</tt>)
+ </h3>
+ <p>This file is available in <tt class="filename">py/roman/stage7/</tt> in the examples directory.
+ </p>
+ <p>If you have not already done so, you can <a href="http://diveintopython.org/download/diveintopython-examples-5.4.zip" title="Download example scripts">download this and other examples</a> used in this book.
+ </p><pre class="programlisting"><span class='pykeyword'>
+import</span> roman71
+<span class='pykeyword'>import</span> unittest
+
+<span class='pykeyword'>class</span><span class='pyclass'> KnownValues</span>(unittest.TestCase):
+ knownValues = ( (1, <span class='pystring'>'I'</span>),
+ (2, <span class='pystring'>'II'</span>),
+ (3, <span class='pystring'>'III'</span>),
+ (4, <span class='pystring'>'IV'</span>),
+ (5, <span class='pystring'>'V'</span>),
+ (6, <span class='pystring'>'VI'</span>),
+ (7, <span class='pystring'>'VII'</span>),
+ (8, <span class='pystring'>'VIII'</span>),
+ (9, <span class='pystring'>'IX'</span>),
+ (10, <span class='pystring'>'X'</span>),
+ (50, <span class='pystring'>'L'</span>),
+ (100, <span class='pystring'>'C'</span>),
+ (500, <span class='pystring'>'D'</span>),
+ (1000, <span class='pystring'>'M'</span>),
+ (31, <span class='pystring'>'XXXI'</span>),
+ (148, <span class='pystring'>'CXLVIII'</span>),
+ (294, <span class='pystring'>'CCXCIV'</span>),
+ (312, <span class='pystring'>'CCCXII'</span>),
+ (421, <span class='pystring'>'CDXXI'</span>),
+ (528, <span class='pystring'>'DXXVIII'</span>),
+ (621, <span class='pystring'>'DCXXI'</span>),
+ (782, <span class='pystring'>'DCCLXXXII'</span>),
+ (870, <span class='pystring'>'DCCCLXX'</span>),
+ (941, <span class='pystring'>'CMXLI'</span>),
+ (1043, <span class='pystring'>'MXLIII'</span>),
+ (1110, <span class='pystring'>'MCX'</span>),
+ (1226, <span class='pystring'>'MCCXXVI'</span>),
+ (1301, <span class='pystring'>'MCCCI'</span>),
+ (1485, <span class='pystring'>'MCDLXXXV'</span>),
+ (1509, <span class='pystring'>'MDIX'</span>),
+ (1607, <span class='pystring'>'MDCVII'</span>),
+ (1754, <span class='pystring'>'MDCCLIV'</span>),
+ (1832, <span class='pystring'>'MDCCCXXXII'</span>),
+ (1993, <span class='pystring'>'MCMXCIII'</span>),
+ (2074, <span class='pystring'>'MMLXXIV'</span>),
+ (2152, <span class='pystring'>'MMCLII'</span>),
+ (2212, <span class='pystring'>'MMCCXII'</span>),
+ (2343, <span class='pystring'>'MMCCCXLIII'</span>),
+ (2499, <span class='pystring'>'MMCDXCIX'</span>),
+ (2574, <span class='pystring'>'MMDLXXIV'</span>),
+ (2646, <span class='pystring'>'MMDCXLVI'</span>),
+ (2723, <span class='pystring'>'MMDCCXXIII'</span>),
+ (2892, <span class='pystring'>'MMDCCCXCII'</span>),
+ (2975, <span class='pystring'>'MMCMLXXV'</span>),
+ (3051, <span class='pystring'>'MMMLI'</span>),
+ (3185, <span class='pystring'>'MMMCLXXXV'</span>),
+ (3250, <span class='pystring'>'MMMCCL'</span>),
+ (3313, <span class='pystring'>'MMMCCCXIII'</span>),
+ (3408, <span class='pystring'>'MMMCDVIII'</span>),
+ (3501, <span class='pystring'>'MMMDI'</span>),
+ (3610, <span class='pystring'>'MMMDCX'</span>),
+ (3743, <span class='pystring'>'MMMDCCXLIII'</span>),
+ (3844, <span class='pystring'>'MMMDCCCXLIV'</span>),
+ (3888, <span class='pystring'>'MMMDCCCLXXXVIII'</span>),
+ (3940, <span class='pystring'>'MMMCMXL'</span>),
+ (3999, <span class='pystring'>'MMMCMXCIX'</span>),
+ (4000, <span class='pystring'>'MMMM'</span>), <a name="roman.change.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ (4500, <span class='pystring'>'MMMMD'</span>),
+ (4888, <span class='pystring'>'MMMMDCCCLXXXVIII'</span>),
+ (4999, <span class='pystring'>'MMMMCMXCIX'</span>))
+
+ <span class='pykeyword'>def</span><span class='pyclass'> testToRomanKnownValues</span>(self):
+ <span class='pystring'>"""toRoman should give known result with known input"""</span>
+ <span class='pykeyword'>for</span> integer, numeral <span class='pykeyword'>in</span> self.knownValues:
+ result = roman71.toRoman(integer)
+ self.assertEqual(numeral, result)
+
+ <span class='pykeyword'>def</span><span class='pyclass'> testFromRomanKnownValues</span>(self):
+ <span class='pystring'>"""fromRoman should give known result with known input"""</span>
+ <span class='pykeyword'>for</span> integer, numeral <span class='pykeyword'>in</span> self.knownValues:
+ result = roman71.fromRoman(numeral)
+ self.assertEqual(integer, result)
+
+<span class='pykeyword'>class</span><span class='pyclass'> ToRomanBadInput</span>(unittest.TestCase):
+ <span class='pykeyword'>def</span><span class='pyclass'> testTooLarge</span>(self):
+ <span class='pystring'>"""toRoman should fail with large input"""</span>
+ self.assertRaises(roman71.OutOfRangeError, roman71.toRoman, 5000) <a name="roman.change.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+
+ <span class='pykeyword'>def</span><span class='pyclass'> testZero</span>(self):
+ <span class='pystring'>"""toRoman should fail with 0 input"""</span>
+ self.assertRaises(roman71.OutOfRangeError, roman71.toRoman, 0)
+
+ <span class='pykeyword'>def</span><span class='pyclass'> testNegative</span>(self):
+ <span class='pystring'>"""toRoman should fail with negative input"""</span>
+ self.assertRaises(roman71.OutOfRangeError, roman71.toRoman, -1)
+
+ <span class='pykeyword'>def</span><span class='pyclass'> testNonInteger</span>(self):
+ <span class='pystring'>"""toRoman should fail with non-integer input"""</span>
+ self.assertRaises(roman71.NotIntegerError, roman71.toRoman, 0.5)
+
+<span class='pykeyword'>class</span><span class='pyclass'> FromRomanBadInput</span>(unittest.TestCase):
+ <span class='pykeyword'>def</span><span class='pyclass'> testTooManyRepeatedNumerals</span>(self):
+ <span class='pystring'>"""fromRoman should fail with too many repeated numerals"""</span>
+ <span class='pykeyword'>for</span> s <span class='pykeyword'>in</span> (<span class='pystring'>'MMMMM'</span>, <span class='pystring'>'DD'</span>, <span class='pystring'>'CCCC'</span>, <span class='pystring'>'LL'</span>, <span class='pystring'>'XXXX'</span>, <span class='pystring'>'VV'</span>, <span class='pystring'>'IIII'</span>): <a name="roman.change.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+ self.assertRaises(roman71.InvalidRomanNumeralError, roman71.fromRoman, s)
+
+ <span class='pykeyword'>def</span><span class='pyclass'> testRepeatedPairs</span>(self):
+ <span class='pystring'>"""fromRoman should fail with repeated pairs of numerals"""</span>
+ <span class='pykeyword'>for</span> s <span class='pykeyword'>in</span> (<span class='pystring'>'CMCM'</span>, <span class='pystring'>'CDCD'</span>, <span class='pystring'>'XCXC'</span>, <span class='pystring'>'XLXL'</span>, <span class='pystring'>'IXIX'</span>, <span class='pystring'>'IVIV'</span>):
+ self.assertRaises(roman71.InvalidRomanNumeralError, roman71.fromRoman, s)
+
+ <span class='pykeyword'>def</span><span class='pyclass'> testMalformedAntecedent</span>(self):
+ <span class='pystring'>"""fromRoman should fail with malformed antecedents"""</span>
+ <span class='pykeyword'>for</span> s <span class='pykeyword'>in</span> (<span class='pystring'>'IIMXCC'</span>, <span class='pystring'>'VX'</span>, <span class='pystring'>'DCM'</span>, <span class='pystring'>'CMM'</span>, <span class='pystring'>'IXIV'</span>,
+ <span class='pystring'>'MCMC'</span>, <span class='pystring'>'XCX'</span>, <span class='pystring'>'IVI'</span>, <span class='pystring'>'LM'</span>, <span class='pystring'>'LD'</span>, <span class='pystring'>'LC'</span>):
+ self.assertRaises(roman71.InvalidRomanNumeralError, roman71.fromRoman, s)
+
+ <span class='pykeyword'>def</span><span class='pyclass'> testBlank</span>(self):
+ <span class='pystring'>"""fromRoman should fail with blank string"""</span>
+ self.assertRaises(roman71.InvalidRomanNumeralError, roman71.fromRoman, <span class='pystring'>""</span>)
+
+<span class='pykeyword'>class</span><span class='pyclass'> SanityCheck</span>(unittest.TestCase):
+ <span class='pykeyword'>def</span><span class='pyclass'> testSanity</span>(self):
+ <span class='pystring'>"""fromRoman(toRoman(n))==n for all n"""</span>
+ <span class='pykeyword'>for</span> integer <span class='pykeyword'>in</span> range(1, 5000): <a name="roman.change.1.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+ numeral = roman71.toRoman(integer)
+ result = roman71.fromRoman(numeral)
+ self.assertEqual(integer, result)
+
+<span class='pykeyword'>class</span><span class='pyclass'> CaseCheck</span>(unittest.TestCase):
+ <span class='pykeyword'>def</span><span class='pyclass'> testToRomanCase</span>(self):
+ <span class='pystring'>"""toRoman should always return uppercase"""</span>
+ <span class='pykeyword'>for</span> integer <span class='pykeyword'>in</span> range(1, 5000):
+ numeral = roman71.toRoman(integer)
+ self.assertEqual(numeral, numeral.upper())
+
+ <span class='pykeyword'>def</span><span class='pyclass'> testFromRomanCase</span>(self):
+ <span class='pystring'>"""fromRoman should only accept uppercase input"""</span>
+ <span class='pykeyword'>for</span> integer <span class='pykeyword'>in</span> range(1, 5000):
+ numeral = roman71.toRoman(integer)
+ roman71.fromRoman(numeral.upper())
+ self.assertRaises(roman71.InvalidRomanNumeralError,
+ roman71.fromRoman, numeral.lower())
+
+<span class='pykeyword'>if</span> __name__ == <span class='pystring'>"__main__"</span>:
+ unittest.main()
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.change.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The existing known values don't change (they're all still reasonable values to test), but you need to add a few more in the
+ <tt class="literal">4000</tt> range. Here I've included <tt class="literal">4000</tt> (the shortest), <tt class="literal">4500</tt> (the second shortest), <tt class="literal">4888</tt> (the longest), and <tt class="literal">4999</tt> (the largest).
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.change.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The definition of &#8220;<span class="quote">large input</span>&#8221; has changed. This test used to call <tt class="function">toRoman</tt> with <tt class="literal">4000</tt> and expect an error; now that <tt class="literal">4000-4999</tt> are good values, you need to bump this up to <tt class="literal">5000</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.change.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The definition of &#8220;<span class="quote">too many repeated numerals</span>&#8221; has also changed. This test used to call <tt class="function">fromRoman</tt> with <tt class="literal">'MMMM'</tt> and expect an error; now that <tt class="literal">MMMM</tt> is considered a valid Roman numeral, you need to bump this up to <tt class="literal">'MMMMM'</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.change.1.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The sanity check and case checks loop through every number in the range, from <tt class="constant">1</tt> to <tt class="literal">3999</tt>. Since the range has now expanded, these <tt class="literal">for</tt> loops need to be updated as well to go up to <tt class="literal">4999</tt>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>Now your test cases are up to date with the new requirements, but your code is not, so you expect several of the test cases
+ to fail.
+ </p>
+ <div class="example"><a name="d0e34405"></a><h3 class="title">Example&nbsp;15.7.&nbsp;Output of <tt class="filename">romantest71.py</tt> against <tt class="filename">roman71.py</tt></h3><pre class="screen"><span class="computeroutput">
+fromRoman should only accept uppercase input ... ERROR </span><a name="roman.change.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"><span class="computeroutput">
+toRoman should always return uppercase ... ERROR
+fromRoman should fail with blank string ... ok
+fromRoman should fail with malformed antecedents ... ok
+fromRoman should fail with repeated pairs of numerals ... ok
+fromRoman should fail with too many repeated numerals ... ok
+fromRoman should give known result with known input ... ERROR </span><a name="roman.change.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"><span class="computeroutput">
+toRoman should give known result with known input ... ERROR </span><a name="roman.change.2.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"><span class="computeroutput">
+fromRoman(toRoman(n))==n for all n ... ERROR </span><a name="roman.change.2.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"><span class="computeroutput">
+toRoman should fail with non-integer input ... ok
+toRoman should fail with negative input ... ok
+toRoman should fail with large input ... ok
+toRoman should fail with 0 input ... ok
+</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.change.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Our case checks now fail because they loop from <tt class="constant">1</tt> to <tt class="literal">4999</tt>, but <tt class="function">toRoman</tt> only accepts numbers from <tt class="constant">1</tt> to <tt class="literal">3999</tt>, so it will fail as soon the test case hits <tt class="literal">4000</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.change.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="function">fromRoman</tt> known values test will fail as soon as it hits <tt class="literal">'MMMM'</tt>, because <tt class="function">fromRoman</tt> still thinks this is an invalid Roman numeral.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.change.2.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="function">toRoman</tt> known values test will fail as soon as it hits <tt class="literal">4000</tt>, because <tt class="function">toRoman</tt> still thinks this is out of range.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.change.2.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The sanity check will also fail as soon as it hits <tt class="literal">4000</tt>, because <tt class="function">toRoman</tt> still thinks this is out of range.
+ </td>
+ </tr>
+ </table>
+ </div><pre class="screen"><span class="computeroutput">
+======================================================================
+ERROR: fromRoman should only accept uppercase input
+----------------------------------------------------------------------
+</span><span class="traceback">Traceback (most recent call last):
+ File "C:\docbook\dip\py\roman\stage7\romantest71.py", line 161, in testFromRomanCase
+ numeral = roman71.toRoman(integer)
+ File "roman71.py", line 28, in toRoman
+ raise OutOfRangeError, "number out of range (must be 1..3999)"
+OutOfRangeError: number out of range (must be 1..3999)</span><span class="computeroutput">
+======================================================================
+ERROR: toRoman should always return uppercase
+----------------------------------------------------------------------
+</span><span class="traceback">Traceback (most recent call last):
+ File "C:\docbook\dip\py\roman\stage7\romantest71.py", line 155, in testToRomanCase
+ numeral = roman71.toRoman(integer)
+ File "roman71.py", line 28, in toRoman
+ raise OutOfRangeError, "number out of range (must be 1..3999)"
+OutOfRangeError: number out of range (must be 1..3999)</span><span class="computeroutput">
+======================================================================
+ERROR: fromRoman should give known result with known input
+----------------------------------------------------------------------
+</span><span class="traceback">Traceback (most recent call last):
+ File "C:\docbook\dip\py\roman\stage7\romantest71.py", line 102, in testFromRomanKnownValues
+ result = roman71.fromRoman(numeral)
+ File "roman71.py", line 47, in fromRoman
+ raise InvalidRomanNumeralError, 'Invalid Roman numeral: %s' % s
+InvalidRomanNumeralError: Invalid Roman numeral: MMMM</span><span class="computeroutput">
+======================================================================
+ERROR: toRoman should give known result with known input
+----------------------------------------------------------------------
+</span><span class="traceback">Traceback (most recent call last):
+ File "C:\docbook\dip\py\roman\stage7\romantest71.py", line 96, in testToRomanKnownValues
+ result = roman71.toRoman(integer)
+ File "roman71.py", line 28, in toRoman
+ raise OutOfRangeError, "number out of range (must be 1..3999)"
+OutOfRangeError: number out of range (must be 1..3999)</span><span class="computeroutput">
+======================================================================
+ERROR: fromRoman(toRoman(n))==n for all n
+----------------------------------------------------------------------
+</span><span class="traceback">Traceback (most recent call last):
+ File "C:\docbook\dip\py\roman\stage7\romantest71.py", line 147, in testSanity
+ numeral = roman71.toRoman(integer)
+ File "roman71.py", line 28, in toRoman
+ raise OutOfRangeError, "number out of range (must be 1..3999)"
+OutOfRangeError: number out of range (must be 1..3999)</span><span class="computeroutput">
+----------------------------------------------------------------------
+Ran 13 tests in 2.213s
+
+FAILED (errors=5)</span></pre></div>
+ <p>Now that you have test cases that fail due to the new requirements, you can think about fixing the code to bring it in line
+ with the test cases. (One thing that takes some getting used to when you first start coding unit tests is that the code being
+ tested is never &#8220;<span class="quote">ahead</span>&#8221; of the test cases. While it's behind, you still have some work to do, and as soon as it catches up to the test cases, you
+ stop coding.)
+ </p>
+ <div class="example"><a name="d0e34511"></a><h3 class="title">Example&nbsp;15.8.&nbsp;Coding the new requirements (<tt class="filename">roman72.py</tt>)
+ </h3>
+ <p>This file is available in <tt class="filename">py/roman/stage7/</tt> in the examples directory.
+ </p><pre class="programlisting">
+<span class='pystring'>"""Convert to and from Roman numerals"""</span>
+<span class='pykeyword'>import</span> re
+
+<span class='pycomment'>#Define exceptions</span>
+<span class='pykeyword'>class</span><span class='pyclass'> RomanError</span>(Exception): <span class='pykeyword'>pass</span>
+<span class='pykeyword'>class</span><span class='pyclass'> OutOfRangeError</span>(RomanError): <span class='pykeyword'>pass</span>
+<span class='pykeyword'>class</span><span class='pyclass'> NotIntegerError</span>(RomanError): <span class='pykeyword'>pass</span>
+<span class='pykeyword'>class</span><span class='pyclass'> InvalidRomanNumeralError</span>(RomanError): <span class='pykeyword'>pass</span>
+
+<span class='pycomment'>#Define digit mapping</span>
+romanNumeralMap = ((<span class='pystring'>'M'</span>, 1000),
+ (<span class='pystring'>'CM'</span>, 900),
+ (<span class='pystring'>'D'</span>, 500),
+ (<span class='pystring'>'CD'</span>, 400),
+ (<span class='pystring'>'C'</span>, 100),
+ (<span class='pystring'>'XC'</span>, 90),
+ (<span class='pystring'>'L'</span>, 50),
+ (<span class='pystring'>'XL'</span>, 40),
+ (<span class='pystring'>'X'</span>, 10),
+ (<span class='pystring'>'IX'</span>, 9),
+ (<span class='pystring'>'V'</span>, 5),
+ (<span class='pystring'>'IV'</span>, 4),
+ (<span class='pystring'>'I'</span>, 1))
+
+<span class='pykeyword'>def</span><span class='pyclass'> toRoman</span>(n):
+ <span class='pystring'>"""convert integer to Roman numeral"""</span>
+ <span class='pykeyword'>if</span> <span class='pykeyword'>not</span> (0 &lt; n &lt; 5000): <a name="roman.change.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ <span class='pykeyword'>raise</span> OutOfRangeError, <span class='pystring'>"number out of range (must be 1..4999)"</span>
+ <span class='pykeyword'>if</span> int(n) &lt;&gt; n:
+ <span class='pykeyword'>raise</span> NotIntegerError, <span class='pystring'>"non-integers can not be converted"</span>
+
+ result = <span class='pystring'>""</span>
+ <span class='pykeyword'>for</span> numeral, integer <span class='pykeyword'>in</span> romanNumeralMap:
+ <span class='pykeyword'>while</span> n &gt;= integer:
+ result += numeral
+ n -= integer
+ <span class='pykeyword'>return</span> result
+
+<span class='pycomment'>#Define pattern to detect valid Roman numerals</span>
+romanNumeralPattern = <span class='pystring'>'^M?M?M?M?(CM|CD|D?C?C?C?)(XC|XL|L?X?X?X?)(IX|IV|V?I?I?I?)$'</span> <a name="roman.change.3.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+
+<span class='pykeyword'>def</span><span class='pyclass'> fromRoman</span>(s):
+ <span class='pystring'>"""convert Roman numeral to integer"""</span>
+ <span class='pykeyword'>if</span> <span class='pykeyword'>not</span> s:
+ <span class='pykeyword'>raise</span> InvalidRomanNumeralError, <span class='pystring'>'Input can not be blank'</span>
+ <span class='pykeyword'>if</span> <span class='pykeyword'>not</span> re.search(romanNumeralPattern, s):
+ <span class='pykeyword'>raise</span> InvalidRomanNumeralError, <span class='pystring'>'Invalid Roman numeral: %s'</span> % s
+
+ result = 0
+ index = 0
+ <span class='pykeyword'>for</span> numeral, integer <span class='pykeyword'>in</span> romanNumeralMap:
+ <span class='pykeyword'>while</span> s[index:index+len(numeral)] == numeral:
+ result += integer
+ index += len(numeral)
+ <span class='pykeyword'>return</span> result
+</pre></div>
+ <div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.change.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">toRoman</tt> only needs one small change, in the range check. Where you used to check <tt class="literal">0 &lt; n &lt; 4000</tt>, you now check <tt class="literal">0 &lt; n &lt; 5000</tt>. And you change the error message that you <tt class="literal">raise</tt> to reflect the new acceptable range (<tt class="literal">1..4999</tt> instead of <tt class="literal">1..3999</tt>). You don't need to make any changes to the rest of the function; it handles the new cases already. (It merrily adds <tt class="literal">'M'</tt> for each thousand that it finds; given <tt class="literal">4000</tt>, it will spit out <tt class="literal">'MMMM'</tt>. The only reason it didn't do this before is that you explicitly stopped it with the range check.)
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.change.3.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You don't need to make any changes to <tt class="function">fromRoman</tt> at all. The only change is to <tt class="varname">romanNumeralPattern</tt>; if you look closely, you'll notice that you added another optional <tt class="literal">M</tt> in the first section of the regular expression. This will allow up to 4 <tt class="literal">M</tt> characters instead of 3, meaning you will allow the Roman numeral equivalents of <tt class="literal">4999</tt> instead of <tt class="literal">3999</tt>. The actual <tt class="function">fromRoman</tt> function is completely general; it just looks for repeated Roman numeral characters and adds them up, without caring how
+ many times they repeat. The only reason it didn't handle <tt class="literal">'MMMM'</tt> before is that you explicitly stopped it with the regular expression pattern matching.
+ </td>
+ </tr>
+ </table>
+ </div>
+ <p>You may be skeptical that these two small changes are all that you need. Hey, don't take my word for it; see for yourself:</p>
+ <div class="example"><a name="roman.roman72.output"></a><h3 class="title">Example&nbsp;15.9.&nbsp;Output of <tt class="filename">romantest72.py</tt> against <tt class="filename">roman72.py</tt></h3><pre class="screen"><span class="computeroutput">fromRoman should only accept uppercase input ... ok
+toRoman should always return uppercase ... ok
+fromRoman should fail with blank string ... ok
+fromRoman should fail with malformed antecedents ... ok
+fromRoman should fail with repeated pairs of numerals ... ok
+fromRoman should fail with too many repeated numerals ... ok
+fromRoman should give known result with known input ... ok
+toRoman should give known result with known input ... ok
+fromRoman(toRoman(n))==n for all n ... ok
+toRoman should fail with non-integer input ... ok
+toRoman should fail with negative input ... ok
+toRoman should fail with large input ... ok
+toRoman should fail with 0 input ... ok
+
+----------------------------------------------------------------------
+Ran 13 tests in 3.685s
+
+OK</span> <a name="roman.change.4.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.change.4.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">All the test cases pass. Stop coding.</td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>Comprehensive unit testing means never having to rely on a programmer who says &#8220;<span class="quote">Trust me.</span>&#8221;
+ </p>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="index.html">&lt;&lt;&nbsp;Refactoring</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#roman.bugs" title="15.1.&nbsp;Handling bugs">1</a> <span class="divider">|</span> <span class="thispage">2</span> <span class="divider">|</span> <a href="refactoring.html" title="15.3.&nbsp;Refactoring">3</a> <span class="divider">|</span> <a href="postscript.html" title="15.4.&nbsp;Postscript">4</a> <span class="divider">|</span> <a href="summary.html" title="15.5.&nbsp;Summary">5</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="refactoring.html">Refactoring&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/refactoring/index.html b/help/diveintopython-5.4/html/refactoring/index.html
new file mode 100644
index 0000000..7be2e03
--- /dev/null
+++ b/help/diveintopython-5.4/html/refactoring/index.html
@@ -0,0 +1,223 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>Chapter&nbsp;15.&nbsp;Refactoring</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="../toc/index.html" title="Dive Into Python">
+ <link rel="previous" href="../unit_testing/stage_5.html" title="14.5.&nbsp;roman.py, stage 5">
+ <link rel="next" href="handling_changing_requirements.html" title="15.2.&nbsp;Handling changing requirements">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<span class="thispage">Refactoring</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="../unit_testing/stage_5.html" title="Prev: &#8220;roman.py, stage 5&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="handling_changing_requirements.html" title="Next: &#8220;Handling changing requirements&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="chapter" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="roman2"></a>Chapter&nbsp;15.&nbsp;Refactoring
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="toc">
+ <ul>
+ <li><span class="section"><a href="index.html#roman.bugs">15.1. Handling bugs</a></span></li>
+ <li><span class="section"><a href="handling_changing_requirements.html">15.2. Handling changing requirements</a></span></li>
+ <li><span class="section"><a href="refactoring.html">15.3. Refactoring</a></span></li>
+ <li><span class="section"><a href="postscript.html">15.4. Postscript</a></span></li>
+ <li><span class="section"><a href="summary.html">15.5. Summary</a></span></li>
+ </ul>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="roman.bugs"></a>15.1.&nbsp;Handling bugs
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>Despite your best efforts to write comprehensive unit tests, bugs happen. What do I mean by &#8220;<span class="quote">bug</span>&#8221;? A bug is a test case you haven't written yet.
+ </p>
+ </div>
+ <div class="example"><a name="d0e34158"></a><h3 class="title">Example&nbsp;15.1.&nbsp;The bug</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> roman5</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">roman5.fromRoman(<span class='pystring'>""</span>)</span> <a name="roman.bugs.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">0</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.bugs.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Remember in the <a href="../unit_testing/stage_5.html" title="14.5.&nbsp;roman.py, stage 5">previous section</a> when you kept seeing that an empty string would match the regular expression you were using to check for valid Roman numerals?
+ Well, it turns out that this is still true for the final version of the regular expression. And that's a bug; you want an
+ empty string to raise an <tt class="errorcode">InvalidRomanNumeralError</tt> exception just like any other sequence of characters that don't represent a valid Roman numeral.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>After reproducing the bug, and before fixing it, you should write a test case that fails, thus illustrating the bug.</p>
+ <div class="example"><a name="d0e34188"></a><h3 class="title">Example&nbsp;15.2.&nbsp;Testing for the bug (<tt class="filename">romantest61.py</tt>)
+ </h3><pre class="programlisting"><span class='pykeyword'>
+class</span> FromRomanBadInput(unittest.TestCase):
+
+ <span class='pycomment'># previous test cases omitted for clarity (they haven't changed)</span>
+
+ <span class='pykeyword'>def</span><span class='pyclass'> testBlank</span>(self):
+ <span class='pystring'>"""fromRoman should fail with blank string"""</span>
+ self.assertRaises(roman.InvalidRomanNumeralError, roman.fromRoman, <span class='pystring'>""</span>) <a name="roman.bugs.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.bugs.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Pretty simple stuff here. Call <tt class="function">fromRoman</tt> with an empty string and make sure it raises an <tt class="errorcode">InvalidRomanNumeralError</tt> exception. The hard part was finding the bug; now that you know about it, testing for it is the easy part.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>Since your code has a bug, and you now have a test case that tests this bug, the test case will fail:</p>
+ <div class="example"><a name="d0e34210"></a><h3 class="title">Example&nbsp;15.3.&nbsp;Output of <tt class="filename">romantest61.py</tt> against <tt class="filename">roman61.py</tt></h3><pre class="screen"><span class="computeroutput">fromRoman should only accept uppercase input ... ok
+toRoman should always return uppercase ... ok
+fromRoman should fail with blank string ... FAIL
+fromRoman should fail with malformed antecedents ... ok
+fromRoman should fail with repeated pairs of numerals ... ok
+fromRoman should fail with too many repeated numerals ... ok
+fromRoman should give known result with known input ... ok
+toRoman should give known result with known input ... ok
+fromRoman(toRoman(n))==n for all n ... ok
+toRoman should fail with non-integer input ... ok
+toRoman should fail with negative input ... ok
+toRoman should fail with large input ... ok
+toRoman should fail with 0 input ... ok
+
+======================================================================
+FAIL: fromRoman should fail with blank string
+----------------------------------------------------------------------
+</span><span class="traceback">Traceback (most recent call last):
+ File "C:\docbook\dip\py\roman\stage6\romantest61.py", line 137, in testBlank
+ self.assertRaises(roman61.InvalidRomanNumeralError, roman61.fromRoman, "")
+ File "c:\python21\lib\unittest.py", line 266, in failUnlessRaises
+ raise self.failureException, excName
+AssertionError: InvalidRomanNumeralError</span><span class="computeroutput">
+----------------------------------------------------------------------
+Ran 13 tests in 2.864s
+
+FAILED (failures=1)</span></pre></div>
+ <p><span class="emphasis"><em>Now</em></span> you can fix the bug.
+ </p>
+ <div class="example"><a name="d0e34229"></a><h3 class="title">Example&nbsp;15.4.&nbsp;Fixing the bug (<tt class="filename">roman62.py</tt>)
+ </h3>
+ <p>This file is available in <tt class="filename">py/roman/stage6/</tt> in the examples directory.
+ </p><pre class="programlisting"><span class='pykeyword'>
+def</span> fromRoman(s):
+ <span class='pystring'>"""convert Roman numeral to integer"""</span>
+ <span class='pykeyword'>if</span> <span class='pykeyword'>not</span> s: <a name="roman.bugs.4.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ <span class='pykeyword'>raise</span> InvalidRomanNumeralError, <span class='pystring'>'Input can not be blank'</span>
+ <span class='pykeyword'>if</span> <span class='pykeyword'>not</span> re.search(romanNumeralPattern, s):
+ <span class='pykeyword'>raise</span> InvalidRomanNumeralError, <span class='pystring'>'Invalid Roman numeral: %s'</span> % s
+
+ result = 0
+ index = 0
+ <span class='pykeyword'>for</span> numeral, integer <span class='pykeyword'>in</span> romanNumeralMap:
+ <span class='pykeyword'>while</span> s[index:index+len(numeral)] == numeral:
+ result += integer
+ index += len(numeral)
+ <span class='pykeyword'>return</span> result
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.bugs.4.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Only two lines of code are required: an explicit check for an empty string, and a <tt class="literal">raise</tt> statement.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="d0e34251"></a><h3 class="title">Example&nbsp;15.5.&nbsp;Output of <tt class="filename">romantest62.py</tt> against <tt class="filename">roman62.py</tt></h3><pre class="screen"><span class="computeroutput">fromRoman should only accept uppercase input ... ok
+toRoman should always return uppercase ... ok
+fromRoman should fail with blank string ... ok </span><a name="roman.bugs.5.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"><span class="computeroutput">
+fromRoman should fail with malformed antecedents ... ok
+fromRoman should fail with repeated pairs of numerals ... ok
+fromRoman should fail with too many repeated numerals ... ok
+fromRoman should give known result with known input ... ok
+toRoman should give known result with known input ... ok
+fromRoman(toRoman(n))==n for all n ... ok
+toRoman should fail with non-integer input ... ok
+toRoman should fail with negative input ... ok
+toRoman should fail with large input ... ok
+toRoman should fail with 0 input ... ok
+
+----------------------------------------------------------------------
+Ran 13 tests in 2.834s
+
+OK</span> <a name="roman.bugs.5.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.bugs.5.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The blank string test case now passes, so the bug is fixed.</td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.bugs.5.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">All the other test cases still pass, which means that this bug fix didn't break anything else. Stop coding.</td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>Coding this way does not make fixing bugs any easier. Simple bugs (like this one) require simple test cases; complex bugs
+ will require complex test cases. In a testing-centric environment, it may <span class="emphasis"><em>seem</em></span> like it takes longer to fix a bug, since you need to articulate in code exactly what the bug is (to write the test case),
+ then fix the bug itself. Then if the test case doesn't pass right away, you need to figure out whether the fix was wrong,
+ or whether the test case itself has a bug in it. However, in the long run, this back-and-forth between test code and code
+ tested pays for itself, because it makes it more likely that bugs are fixed correctly the first time. Also, since you can
+ easily re-run <span class="emphasis"><em>all</em></span> the test cases along with your new one, you are much less likely to break old code when fixing new code. Today's unit test
+ is tomorrow's regression test.
+ </p>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="../unit_testing/stage_5.html">&lt;&lt;&nbsp;roman.py, stage 5</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<span class="thispage">1</span> <span class="divider">|</span> <a href="handling_changing_requirements.html" title="15.2.&nbsp;Handling changing requirements">2</a> <span class="divider">|</span> <a href="refactoring.html" title="15.3.&nbsp;Refactoring">3</a> <span class="divider">|</span> <a href="postscript.html" title="15.4.&nbsp;Postscript">4</a> <span class="divider">|</span> <a href="summary.html" title="15.5.&nbsp;Summary">5</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="handling_changing_requirements.html">Handling changing requirements&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/refactoring/postscript.html b/help/diveintopython-5.4/html/refactoring/postscript.html
new file mode 100644
index 0000000..11d9614
--- /dev/null
+++ b/help/diveintopython-5.4/html/refactoring/postscript.html
@@ -0,0 +1,169 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>15.4.&nbsp;Postscript</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;15.&nbsp;Refactoring">
+ <link rel="previous" href="refactoring.html" title="15.3.&nbsp;Refactoring">
+ <link rel="next" href="summary.html" title="15.5.&nbsp;Summary">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Refactoring</a>&nbsp;&gt;&nbsp;<span class="thispage">Postscript</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="refactoring.html" title="Prev: &#8220;Refactoring&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="summary.html" title="Next: &#8220;Summary&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="roman.postscript"></a>15.4.&nbsp;Postscript
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>A clever reader read the <a href="refactoring.html" title="15.3.&nbsp;Refactoring">previous section</a> and took it to the next level. The biggest headache (and performance drain) in the program as it is currently written is
+ the regular expression, which is required because you have no other way of breaking down a Roman numeral. But there's only
+ 5000 of them; why don't you just build a lookup table once, then simply read that? This idea gets even better when you realize
+ that you don't need to use regular expressions at all. As you build the lookup table for converting integers to Roman numerals,
+ you can build the reverse lookup table to convert Roman numerals to integers.
+ </p>
+ </div>
+ <p>And best of all, he already had a complete set of unit tests. He changed over half the code in the module, but the unit tests
+ stayed the same, so he could prove that his code worked just as well as the original.
+ </p>
+ <div class="example"><a name="d0e35088"></a><h3 class="title">Example&nbsp;15.17.&nbsp;<tt class="filename">roman9.py</tt></h3>
+ <p>This file is available in <tt class="filename">py/roman/stage9/</tt> in the examples directory.
+ </p>
+ <p>If you have not already done so, you can <a href="http://diveintopython.org/download/diveintopython-examples-5.4.zip" title="Download example scripts">download this and other examples</a> used in this book.
+ </p><pre class="programlisting">
+<span class='pycomment'>#Define exceptions</span>
+<span class='pykeyword'>class</span><span class='pyclass'> RomanError</span>(Exception): <span class='pykeyword'>pass</span>
+<span class='pykeyword'>class</span><span class='pyclass'> OutOfRangeError</span>(RomanError): <span class='pykeyword'>pass</span>
+<span class='pykeyword'>class</span><span class='pyclass'> NotIntegerError</span>(RomanError): <span class='pykeyword'>pass</span>
+<span class='pykeyword'>class</span><span class='pyclass'> InvalidRomanNumeralError</span>(RomanError): <span class='pykeyword'>pass</span>
+
+<span class='pycomment'>#Roman numerals must be less than 5000</span>
+MAX_ROMAN_NUMERAL = 4999
+
+<span class='pycomment'>#Define digit mapping</span>
+romanNumeralMap = ((<span class='pystring'>'M'</span>, 1000),
+ (<span class='pystring'>'CM'</span>, 900),
+ (<span class='pystring'>'D'</span>, 500),
+ (<span class='pystring'>'CD'</span>, 400),
+ (<span class='pystring'>'C'</span>, 100),
+ (<span class='pystring'>'XC'</span>, 90),
+ (<span class='pystring'>'L'</span>, 50),
+ (<span class='pystring'>'XL'</span>, 40),
+ (<span class='pystring'>'X'</span>, 10),
+ (<span class='pystring'>'IX'</span>, 9),
+ (<span class='pystring'>'V'</span>, 5),
+ (<span class='pystring'>'IV'</span>, 4),
+ (<span class='pystring'>'I'</span>, 1))
+
+<span class='pycomment'>#Create tables for fast conversion of roman numerals.</span>
+<span class='pycomment'>#See fillLookupTables() below.</span>
+toRomanTable = [ None ] <span class='pycomment'># Skip an index since Roman numerals have no zero</span>
+fromRomanTable = {}
+
+<span class='pykeyword'>def</span><span class='pyclass'> toRoman</span>(n):
+ <span class='pystring'>"""convert integer to Roman numeral"""</span>
+ <span class='pykeyword'>if</span> <span class='pykeyword'>not</span> (0 &lt; n &lt;= MAX_ROMAN_NUMERAL):
+ <span class='pykeyword'>raise</span> OutOfRangeError, <span class='pystring'>"number out of range (must be 1..%s)"</span> % MAX_ROMAN_NUMERAL
+ <span class='pykeyword'>if</span> int(n) &lt;&gt; n:
+ <span class='pykeyword'>raise</span> NotIntegerError, <span class='pystring'>"non-integers can not be converted"</span>
+ <span class='pykeyword'>return</span> toRomanTable[n]
+
+<span class='pykeyword'>def</span><span class='pyclass'> fromRoman</span>(s):
+ <span class='pystring'>"""convert Roman numeral to integer"""</span>
+ <span class='pykeyword'>if</span> <span class='pykeyword'>not</span> s:
+ <span class='pykeyword'>raise</span> InvalidRomanNumeralError, <span class='pystring'>"Input can not be blank"</span>
+ <span class='pykeyword'>if</span> <span class='pykeyword'>not</span> fromRomanTable.has_key(s):
+ <span class='pykeyword'>raise</span> InvalidRomanNumeralError, <span class='pystring'>"Invalid Roman numeral: %s"</span> % s
+ <span class='pykeyword'>return</span> fromRomanTable[s]
+
+<span class='pykeyword'>def</span><span class='pyclass'> toRomanDynamic</span>(n):
+ <span class='pystring'>"""convert integer to Roman numeral using dynamic programming"""</span>
+ result = <span class='pystring'>""</span>
+ <span class='pykeyword'>for</span> numeral, integer <span class='pykeyword'>in</span> romanNumeralMap:
+ <span class='pykeyword'>if</span> n &gt;= integer:
+ result = numeral
+ n -= integer
+ <span class='pykeyword'>break</span>
+ <span class='pykeyword'>if</span> n &gt; 0:
+ result += toRomanTable[n]
+ <span class='pykeyword'>return</span> result
+
+<span class='pykeyword'>def</span><span class='pyclass'> fillLookupTables</span>():
+ <span class='pystring'>"""compute all the possible roman numerals"""</span>
+ <span class='pycomment'>#Save the values in two global tables to convert to and from integers.</span>
+ <span class='pykeyword'>for</span> integer <span class='pykeyword'>in</span> range(1, MAX_ROMAN_NUMERAL + 1):
+ romanNumber = toRomanDynamic(integer)
+ toRomanTable.append(romanNumber)
+ fromRomanTable[romanNumber] = integer
+
+fillLookupTables()
+</pre></div>
+ <p>So how fast is it?</p>
+ <div class="example"><a name="d0e35106"></a><h3 class="title">Example&nbsp;15.18.&nbsp;Output of <tt class="filename">romantest9.py</tt> against <tt class="filename">roman9.py</tt></h3><pre class="screen">
+<span class="computeroutput">
+.............
+----------------------------------------------------------------------
+Ran 13 tests in 0.791s
+
+OK
+</span>
+</pre></div>
+ <p>Remember, the best performance you ever got in the original version was 13 tests in 3.315 seconds. Of course, it's not entirely
+ a fair comparison, because this version will take longer to import (when it fills the lookup tables). But since import is
+ only done once, this is negligible in the long run.
+ </p>
+ <p>The moral of the story?</p>
+ <div class="itemizedlist">
+ <ul>
+ <li>Simplicity is a virtue.</li>
+ <li>Especially when regular expressions are involved.</li>
+ <li>And unit tests can give you the confidence to do large-scale refactoring... even if you didn't write the original code.</li>
+ </ul>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="refactoring.html">&lt;&lt;&nbsp;Refactoring</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#roman.bugs" title="15.1.&nbsp;Handling bugs">1</a> <span class="divider">|</span> <a href="handling_changing_requirements.html" title="15.2.&nbsp;Handling changing requirements">2</a> <span class="divider">|</span> <a href="refactoring.html" title="15.3.&nbsp;Refactoring">3</a> <span class="divider">|</span> <span class="thispage">4</span> <span class="divider">|</span> <a href="summary.html" title="15.5.&nbsp;Summary">5</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="summary.html">Summary&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/refactoring/refactoring.html b/help/diveintopython-5.4/html/refactoring/refactoring.html
new file mode 100644
index 0000000..15c3374
--- /dev/null
+++ b/help/diveintopython-5.4/html/refactoring/refactoring.html
@@ -0,0 +1,320 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>15.3.&nbsp;Refactoring</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;15.&nbsp;Refactoring">
+ <link rel="previous" href="handling_changing_requirements.html" title="15.2.&nbsp;Handling changing requirements">
+ <link rel="next" href="postscript.html" title="15.4.&nbsp;Postscript">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Refactoring</a>&nbsp;&gt;&nbsp;<span class="thispage">Refactoring</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="handling_changing_requirements.html" title="Prev: &#8220;Handling changing requirements&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="postscript.html" title="Next: &#8220;Postscript&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="roman.refactoring"></a>15.3.&nbsp;Refactoring
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>The best thing about comprehensive unit testing is not the feeling you get when all your test cases finally pass, or even
+ the feeling you get when someone else blames you for breaking their code and you can actually <span class="emphasis"><em>prove</em></span> that you didn't. The best thing about unit testing is that it gives you the freedom to refactor mercilessly.
+ </p>
+ </div>
+ <p>Refactoring is the process of taking working code and making it work better. Usually, &#8220;<span class="quote">better</span>&#8221; means &#8220;<span class="quote">faster</span>&#8221;, although it can also mean &#8220;<span class="quote">using less memory</span>&#8221;, or &#8220;<span class="quote">using less disk space</span>&#8221;, or simply &#8220;<span class="quote">more elegantly</span>&#8221;. Whatever it means to you, to your project, in your environment, refactoring is important to the long-term health of any
+ program.
+ </p>
+ <p>Here, &#8220;<span class="quote">better</span>&#8221; means &#8220;<span class="quote">faster</span>&#8221;. Specifically, the <tt class="function">fromRoman</tt> function is slower than it needs to be, because of that big nasty regular expression that you use to validate Roman numerals.
+ It's probably not worth trying to do away with the regular expression altogether (it would be difficult, and it might not
+ end up any faster), but you can speed up the function by precompiling the regular expression.
+ </p>
+ <div class="example"><a name="d0e34647"></a><h3 class="title">Example&nbsp;15.10.&nbsp;Compiling regular expressions</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> re</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">pattern = <span class='pystring'>'^M?M?M?$'</span></span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">re.search(pattern, <span class='pystring'>'M'</span>)</span> <a name="roman.refactoring.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">&lt;SRE_Match object at 01090490&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">compiledPattern = re.compile(pattern)</span> <a name="roman.refactoring.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">compiledPattern</span>
+<span class="computeroutput">&lt;SRE_Pattern object at 00F06E28&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">dir(compiledPattern)</span> <a name="roman.refactoring.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">['findall', 'match', 'scanner', 'search', 'split', 'sub', 'subn']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">compiledPattern.search(<span class='pystring'>'M'</span>)</span> <a name="roman.refactoring.1.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">&lt;SRE_Match object at 01104928&gt;</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.refactoring.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This is the syntax you've seen before: <tt class="function">re.search</tt> takes a regular expression as a string (<tt class="varname">pattern</tt>) and a string to match against it (<tt class="literal">'M'</tt>). If the pattern matches, the function returns a match object which can be queried to find out exactly what matched and
+ how.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.refactoring.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This is the new syntax: <tt class="function">re.compile</tt> takes a regular expression as a string and returns a pattern object. Note there is no string to match here. Compiling a
+ regular expression has nothing to do with matching it against any specific strings (like <tt class="literal">'M'</tt>); it only involves the regular expression itself.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.refactoring.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The compiled pattern object returned from <tt class="function">re.compile</tt> has several useful-looking functions, including several (like <tt class="function">search</tt> and <tt class="function">sub</tt>) that are available directly in the <tt class="filename">re</tt> module.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.refactoring.1.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Calling the compiled pattern object's <tt class="function">search</tt> function with the string <tt class="literal">'M'</tt> accomplishes the same thing as calling <tt class="function">re.search</tt> with both the regular expression and the string <tt class="literal">'M'</tt>. Only much, much faster. (In fact, the <tt class="function">re.search</tt> function simply compiles the regular expression and calls the resulting pattern object's <tt class="function">search</tt> method for you.)
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div><a name="d0e34764"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">Whenever you are going to use a regular expression more than once, you should compile it to get a pattern object, then call
+ the methods on the pattern object directly.
+ </td>
+ </tr>
+ </table>
+ <div class="example"><a name="d0e34769"></a><h3 class="title">Example&nbsp;15.11.&nbsp;Compiled regular expressions in <tt class="filename">roman81.py</tt></h3>
+ <p>This file is available in <tt class="filename">py/roman/stage8/</tt> in the examples directory.
+ </p>
+ <p>If you have not already done so, you can <a href="http://diveintopython.org/download/diveintopython-examples-5.4.zip" title="Download example scripts">download this and other examples</a> used in this book.
+ </p><pre class="programlisting">
+<span class='pycomment'># toRoman and rest of module omitted for clarity</span>
+
+romanNumeralPattern = \
+ re.compile(<span class='pystring'>'^M?M?M?M?(CM|CD|D?C?C?C?)(XC|XL|L?X?X?X?)(IX|IV|V?I?I?I?)$'</span>) <a name="roman.refactoring.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+
+<span class='pykeyword'>def</span><span class='pyclass'> fromRoman</span>(s):
+ <span class='pystring'>"""convert Roman numeral to integer"""</span>
+ <span class='pykeyword'>if</span> <span class='pykeyword'>not</span> s:
+ <span class='pykeyword'>raise</span> InvalidRomanNumeralError, <span class='pystring'>'Input can not be blank'</span>
+ <span class='pykeyword'>if</span> <span class='pykeyword'>not</span> romanNumeralPattern.search(s): <a name="roman.refactoring.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+ <span class='pykeyword'>raise</span> InvalidRomanNumeralError, <span class='pystring'>'Invalid Roman numeral: %s'</span> % s
+
+ result = 0
+ index = 0
+ <span class='pykeyword'>for</span> numeral, integer <span class='pykeyword'>in</span> romanNumeralMap:
+ <span class='pykeyword'>while</span> s[index:index+len(numeral)] == numeral:
+ result += integer
+ index += len(numeral)
+ <span class='pykeyword'>return</span> result
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.refactoring.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This looks very similar, but in fact a lot has changed. <tt class="varname">romanNumeralPattern</tt> is no longer a string; it is a pattern object which was returned from <tt class="function">re.compile</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.refactoring.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">That means that you can call methods on <tt class="varname">romanNumeralPattern</tt> directly. This will be much, much faster than calling <tt class="function">re.search</tt> every time. The regular expression is compiled once and stored in <tt class="varname">romanNumeralPattern</tt> when the module is first imported; then, every time you call <tt class="function">fromRoman</tt>, you can immediately match the input string against the regular expression, without any intermediate steps occurring under
+ the covers.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>So how much faster is it to compile regular expressions? See for yourself:</p>
+ <div class="example"><a name="roman.stage8.1.output"></a><h3 class="title">Example&nbsp;15.12.&nbsp;Output of <tt class="filename">romantest81.py</tt> against <tt class="filename">roman81.py</tt></h3><pre class="screen"><span class="computeroutput">............. </span><a name="roman.refactoring.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"><span class="computeroutput">
+----------------------------------------------------------------------
+Ran 13 tests in 3.385s </span><a name="roman.refactoring.3.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"><span class="computeroutput">
+
+OK</span> <a name="roman.refactoring.3.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.refactoring.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Just a note in passing here: this time, I ran the unit test <span class="emphasis"><em>without</em></span> the <tt class="option">-v</tt> option, so instead of the full <tt class="literal">doc string</tt> for each test, you only get a dot for each test that passes. (If a test failed, you'd get an <tt class="literal">F</tt>, and if it had an error, you'd get an <tt class="literal">E</tt>. You'd still get complete tracebacks for each failure and error, so you could track down any problems.)
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.refactoring.3.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You ran <tt class="literal">13</tt> tests in <tt class="literal">3.385</tt> seconds, compared to <a href="handling_changing_requirements.html#roman.roman72.output" title="Example&nbsp;15.9.&nbsp;Output of romantest72.py against roman72.py"><tt class="literal">3.685</tt> seconds</a> without precompiling the regular expressions. That's an <tt class="literal">8%</tt> improvement overall, and remember that most of the time spent during the unit test is spent doing other things. (Separately,
+ I time-tested the regular expressions by themselves, apart from the rest of the unit tests, and found that compiling this
+ regular expression speeds up the <tt class="function">search</tt> by an average of <tt class="literal">54%</tt>.) Not bad for such a simple fix.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.refactoring.3.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Oh, and in case you were wondering, precompiling the regular expression didn't break anything, and you just proved it.</td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>There is one other performance optimization that I want to try. Given the complexity of regular expression syntax, it should
+ come as no surprise that there is frequently more than one way to write the same expression. After some discussion about
+ this module on <a href="http://groups.google.com/groups?group=comp.lang.python">comp.lang.python</a>, someone suggested that I try using the <tt class="literal">{<i class="replaceable">m</i>,<i class="replaceable">n</i>}</tt> syntax for the optional repeated characters.
+ </p>
+ <div class="example"><a name="d0e34895"></a><h3 class="title">Example&nbsp;15.13.&nbsp;<tt class="filename">roman82.py</tt></h3>
+ <p>This file is available in <tt class="filename">py/roman/stage8/</tt> in the examples directory.
+ </p>
+ <p>If you have not already done so, you can <a href="http://diveintopython.org/download/diveintopython-examples-5.4.zip" title="Download example scripts">download this and other examples</a> used in this book.
+ </p><pre class="programlisting">
+<span class='pycomment'># rest of program omitted for clarity</span>
+
+<span class='pycomment'>#old version</span>
+<span class='pycomment'>#romanNumeralPattern = \</span>
+<span class='pycomment'># re.compile('^M?M?M?M?(CM|CD|D?C?C?C?)(XC|XL|L?X?X?X?)(IX|IV|V?I?I?I?)$')</span>
+
+<span class='pycomment'>#new version</span>
+romanNumeralPattern = \
+ re.compile(<span class='pystring'>'^M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$'</span>) <a name="roman.refactoring.4.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.refactoring.4.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You have replaced <tt class="literal">M?M?M?M?</tt> with <tt class="literal">M{0,4}</tt>. Both mean the same thing: &#8220;<span class="quote">match 0 to 4 <tt class="literal">M</tt> characters</span>&#8221;. Similarly, <tt class="literal">C?C?C?</tt> became <tt class="literal">C{0,3}</tt> (&#8220;<span class="quote">match 0 to 3 <tt class="literal">C</tt> characters</span>&#8221;) and so forth for <tt class="literal">X</tt> and <tt class="literal">I</tt>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>This form of the regular expression is a little shorter (though not any more readable). The big question is, is it any faster?</p>
+ <div class="example"><a name="d0e34949"></a><h3 class="title">Example&nbsp;15.14.&nbsp;Output of <tt class="filename">romantest82.py</tt> against <tt class="filename">roman82.py</tt></h3><pre class="screen"><span class="computeroutput">.............
+----------------------------------------------------------------------
+Ran 13 tests in 3.315s </span><a name="roman.refactoring.5.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"><span class="computeroutput">
+
+OK</span> <a name="roman.refactoring.5.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.refactoring.5.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Overall, the unit tests run 2% faster with this form of regular expression. That doesn't sound exciting, but remember that
+ the <tt class="function">search</tt> function is a small part of the overall unit test; most of the time is spent doing other things. (Separately, I time-tested
+ just the regular expressions, and found that the <tt class="function">search</tt> function is <tt class="literal">11%</tt> faster with this syntax.) By precompiling the regular expression and rewriting part of it to use this new syntax, you've
+ improved the regular expression performance by over <tt class="literal">60%</tt>, and improved the overall performance of the entire unit test by over <tt class="literal">10%</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.refactoring.5.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">More important than any performance boost is the fact that the module still works perfectly. This is the freedom I was talking
+ about earlier: the freedom to tweak, change, or rewrite any piece of it and verify that you haven't messed anything up in
+ the process. This is not a license to endlessly tweak your code just for the sake of tweaking it; you had a very specific
+ objective (&#8220;<span class="quote">make <tt class="function">fromRoman</tt> faster</span>&#8221;), and you were able to accomplish that objective without any lingering doubts about whether you introduced new bugs in the
+ process.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>One other tweak I would like to make, and then I promise I'll stop refactoring and put this module to bed. As you've seen
+ repeatedly, regular expressions can get pretty hairy and unreadable pretty quickly. I wouldn't like to come back to this
+ module in six months and try to maintain it. Sure, the test cases pass, so I know that it works, but if I can't figure out
+ <span class="emphasis"><em>how</em></span> it works, it's still going to be difficult to add new features, fix new bugs, or otherwise maintain it. As you saw in <a href="../regular_expressions/verbose.html" title="7.5.&nbsp;Verbose Regular Expressions">Section&nbsp;7.5, &#8220;Verbose Regular Expressions&#8221;</a>, <span class="application">Python</span> provides a way to document your logic line-by-line.
+ </p>
+ <div class="example"><a name="d0e35003"></a><h3 class="title">Example&nbsp;15.15.&nbsp;<tt class="filename">roman83.py</tt></h3>
+ <p>This file is available in <tt class="filename">py/roman/stage8/</tt> in the examples directory.
+ </p>
+ <p>If you have not already done so, you can <a href="http://diveintopython.org/download/diveintopython-examples-5.4.zip" title="Download example scripts">download this and other examples</a> used in this book.
+ </p><pre class="programlisting">
+<span class='pycomment'># rest of program omitted for clarity</span>
+
+<span class='pycomment'>#old version</span>
+<span class='pycomment'>#romanNumeralPattern = \</span>
+<span class='pycomment'># re.compile('^M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$')</span>
+
+<span class='pycomment'>#new version</span>
+romanNumeralPattern = re.compile(<span class='pystring'>'''
+ ^ # beginning of string
+ M{0,4} # thousands - 0 to 4 M's
+ (CM|CD|D?C{0,3}) # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 C's),
+ # or 500-800 (D, followed by 0 to 3 C's)
+ (XC|XL|L?X{0,3}) # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 X's),
+ # or 50-80 (L, followed by 0 to 3 X's)
+ (IX|IV|V?I{0,3}) # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 I's),
+ # or 5-8 (V, followed by 0 to 3 I's)
+ $ # end of string
+ '''</span>, re.VERBOSE) <a name="roman.refactoring.6.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.refactoring.6.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="function">re.compile</tt> function can take an optional second argument, which is a set of one or more flags that control various options about the
+ compiled regular expression. Here you're specifying the <tt class="literal">re.VERBOSE</tt> flag, which tells <span class="application">Python</span> that there are in-line comments within the regular expression itself. The comments and all the whitespace around them are
+ <span class="emphasis"><em>not</em></span> considered part of the regular expression; the <tt class="function">re.compile</tt> function simply strips them all out when it compiles the expression. This new, &#8220;<span class="quote">verbose</span>&#8221; version is identical to the old version, but it is infinitely more readable.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="d0e35043"></a><h3 class="title">Example&nbsp;15.16.&nbsp;Output of <tt class="filename">romantest83.py</tt> against <tt class="filename">roman83.py</tt></h3><pre class="screen"><span class="computeroutput">.............
+----------------------------------------------------------------------
+Ran 13 tests in 3.315s </span><a name="roman.refactoring.7.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"><span class="computeroutput">
+
+OK</span> <a name="roman.refactoring.7.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.refactoring.7.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This new, &#8220;<span class="quote">verbose</span>&#8221; version runs at exactly the same speed as the old version. In fact, the compiled pattern objects are the same, since the
+ <tt class="function">re.compile</tt> function strips out all the stuff you added.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.refactoring.7.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This new, &#8220;<span class="quote">verbose</span>&#8221; version passes all the same tests as the old version. Nothing has changed, except that the programmer who comes back to
+ this module in six months stands a fighting chance of understanding how the function works.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="handling_changing_requirements.html">&lt;&lt;&nbsp;Handling changing requirements</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#roman.bugs" title="15.1.&nbsp;Handling bugs">1</a> <span class="divider">|</span> <a href="handling_changing_requirements.html" title="15.2.&nbsp;Handling changing requirements">2</a> <span class="divider">|</span> <span class="thispage">3</span> <span class="divider">|</span> <a href="postscript.html" title="15.4.&nbsp;Postscript">4</a> <span class="divider">|</span> <a href="summary.html" title="15.5.&nbsp;Summary">5</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="postscript.html">Postscript&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/refactoring/summary.html b/help/diveintopython-5.4/html/refactoring/summary.html
new file mode 100644
index 0000000..076a5ab
--- /dev/null
+++ b/help/diveintopython-5.4/html/refactoring/summary.html
@@ -0,0 +1,116 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>15.5.&nbsp;Summary</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;15.&nbsp;Refactoring">
+ <link rel="previous" href="postscript.html" title="15.4.&nbsp;Postscript">
+ <link rel="next" href="../functional_programming/index.html" title="Chapter&nbsp;16.&nbsp;Functional Programming">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Refactoring</a>&nbsp;&gt;&nbsp;<span class="thispage">Summary</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="postscript.html" title="Prev: &#8220;Postscript&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="../functional_programming/index.html" title="Next: &#8220;Functional Programming&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="roman.summary"></a>15.5.&nbsp;Summary
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>Unit testing is a powerful concept which, if properly implemented, can both reduce maintenance costs and increase flexibility
+ in any long-term project. It is also important to understand that unit testing is not a panacea, a Magic Problem Solver,
+ or a silver bullet. Writing good test cases is hard, and keeping them up to date takes discipline (especially when customers
+ are screaming for critical bug fixes). Unit testing is not a replacement for other forms of testing, including functional
+ testing, integration testing, and user acceptance testing. But it is feasible, and it does work, and once you've seen it
+ work, you'll wonder how you ever got along without it.
+ </p>
+ </div>
+ <p>This chapter covered a lot of ground, and much of it wasn't even <span class="application">Python</span>-specific. There are unit testing frameworks for many languages, all of which require you to understand the same basic concepts:
+ </p>
+ <div class="highlights">
+ <div class="itemizedlist">
+ <ul>
+ <li>Designing test cases that are specific, automated, and independent</li>
+ <li>Writing test cases <span class="emphasis"><em>before</em></span> the code they are testing
+ </li>
+ <li>Writing tests that <a href="../unit_testing/testing_for_success.html" title="13.4.&nbsp;Testing for success">test good input</a> and check for proper results
+ </li>
+ <li>Writing tests that <a href="../unit_testing/testing_for_failure.html" title="13.5.&nbsp;Testing for failure">test bad input</a> and check for proper failures
+ </li>
+ <li>Writing and updating test cases to <a href="index.html#roman.bugs" title="15.1.&nbsp;Handling bugs">illustrate bugs</a> or <a href="handling_changing_requirements.html" title="15.2.&nbsp;Handling changing requirements">reflect new requirements</a></li>
+ <li><a href="refactoring.html" title="15.3.&nbsp;Refactoring">Refactoring</a> mercilessly to improve performance, scalability, readability, maintainability, or whatever other -ility you're lacking
+ </li>
+ </ul>
+ </div>
+ </div>
+ <p>Additionally, you should be comfortable doing all of the following <span class="application">Python</span>-specific things:
+ </p>
+ <div class="highlights">
+ <div class="itemizedlist">
+ <ul>
+ <li><a href="../unit_testing/testing_for_success.html#roman.testtoromanknownvalues.example" title="Example&nbsp;13.2.&nbsp;testToRomanKnownValues">Subclassing <tt class="literal">unittest.TestCase</tt></a> and writing methods for individual test cases
+ </li>
+ <li>Using <a href="../unit_testing/testing_for_success.html#roman.testtoromanknownvalues.example" title="Example&nbsp;13.2.&nbsp;testToRomanKnownValues"><tt class="function">assertEqual</tt></a> to check that a function returns a known value
+ </li>
+ <li>Using <a href="../unit_testing/testing_for_failure.html#roman.tobadinput.example" title="Example&nbsp;13.3.&nbsp;Testing bad input to toRoman"><tt class="function">assertRaises</tt></a> to check that a function raises a known exception
+ </li>
+ <li>Calling <a href="../unit_testing/stage_1.html#roman.stage1.output" title="Example&nbsp;14.2.&nbsp;Output of romantest1.py against roman1.py"><tt class="literal">unittest.main()</tt></a> in your <tt class="literal">if __name__</tt> clause to run all your test cases at once
+ </li>
+ <li>Running unit tests in <a href="../unit_testing/stage_1.html#roman.stage1.output" title="Example&nbsp;14.2.&nbsp;Output of romantest1.py against roman1.py">verbose</a> or <a href="refactoring.html#roman.stage8.1.output" title="Example&nbsp;15.12.&nbsp;Output of romantest81.py against roman81.py">regular</a> mode
+ </li>
+ </ul>
+ </div>
+ </div>
+ <div class="furtherreading">
+ <h3>Further reading</h3>
+ <ul>
+ <li><a href="http://www.xprogramming.com/">XProgramming.com</a> has links to <a href="http://www.xprogramming.com/software.htm">download unit testing frameworks</a> for many different languages.
+ </li>
+ </ul>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="postscript.html">&lt;&lt;&nbsp;Postscript</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#roman.bugs" title="15.1.&nbsp;Handling bugs">1</a> <span class="divider">|</span> <a href="handling_changing_requirements.html" title="15.2.&nbsp;Handling changing requirements">2</a> <span class="divider">|</span> <a href="refactoring.html" title="15.3.&nbsp;Refactoring">3</a> <span class="divider">|</span> <a href="postscript.html" title="15.4.&nbsp;Postscript">4</a> <span class="divider">|</span> <span class="thispage">5</span>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="../functional_programming/index.html">Functional Programming&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/regular_expressions/index.html b/help/diveintopython-5.4/html/regular_expressions/index.html
new file mode 100644
index 0000000..fd5b797
--- /dev/null
+++ b/help/diveintopython-5.4/html/regular_expressions/index.html
@@ -0,0 +1,110 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>Chapter&nbsp;7.&nbsp;Regular Expressions</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="../toc/index.html" title="Dive Into Python">
+ <link rel="previous" href="../file_handling/summary.html" title="6.7.&nbsp;Summary">
+ <link rel="next" href="street_addresses.html" title="7.2.&nbsp;Case Study: Street Addresses">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<span class="thispage">Regular Expressions</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="../file_handling/summary.html" title="Prev: &#8220;Summary&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="street_addresses.html" title="Next: &#8220;Case Study: Street Addresses&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="chapter" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="re"></a>Chapter&nbsp;7.&nbsp;Regular Expressions
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="toc">
+ <ul>
+ <li><span class="section"><a href="index.html#re.intro">7.1. Diving In</a></span></li>
+ <li><span class="section"><a href="street_addresses.html">7.2. Case Study: Street Addresses</a></span></li>
+ <li><span class="section"><a href="roman_numerals.html">7.3. Case Study: Roman Numerals</a></span><ul>
+ <li><span class="section"><a href="roman_numerals.html#d0e17592">7.3.1. Checking for Thousands</a></span></li>
+ <li><span class="section"><a href="roman_numerals.html#d0e17785">7.3.2. Checking for Hundreds</a></span></li>
+ </ul>
+ </li>
+ <li><span class="section"><a href="n_m_syntax.html">7.4. Using the {n,m} Syntax</a></span><ul>
+ <li><span class="section"><a href="n_m_syntax.html#d0e18326">7.4.1. Checking for Tens and Ones</a></span></li>
+ </ul>
+ </li>
+ <li><span class="section"><a href="verbose.html">7.5. Verbose Regular Expressions</a></span></li>
+ <li><span class="section"><a href="phone_numbers.html">7.6. Case study: Parsing Phone Numbers</a></span></li>
+ <li><span class="section"><a href="summary.html">7.7. Summary</a></span></li>
+ </ul>
+ </div>
+ <div class="abstract">
+ <p>Regular expressions are a powerful and standardized way of searching, replacing, and parsing text with complex patterns of
+ characters. If you've used regular expressions in other languages (like <span class="application">Perl</span>), the syntax will be very familiar, and you get by just reading the summary of the <a href="http://www.python.org/doc/current/lib/module-re.html"><tt class="filename">re</tt> module</a> to get an overview of the available functions and their arguments.
+ </p>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="re.intro"></a>7.1.&nbsp;Diving In
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p>Strings have methods for searching (<tt class="function">index</tt>, <tt class="function">find</tt>, and <tt class="function">count</tt>), replacing (<tt class="function">replace</tt>), and parsing (<tt class="function">split</tt>), but they are limited to the simplest of cases. The search methods look for a single, hard-coded substring, and they are
+ always case-sensitive. To do case-insensitive searches of a string <tt class="varname">s</tt>, you must call <tt class="function">s.lower()</tt> or <tt class="function">s.upper()</tt> and make sure your search strings are the appropriate case to match. The <tt class="function">replace</tt> and <tt class="function">split</tt> methods have the same limitations.
+ </p>
+ <div class="abstract">
+ <p>If what you're trying to do can be accomplished with string functions, you should use them. They're fast and simple and easy
+ to read, and there's a lot to be said for fast, simple, readable code. But if you find yourself using a lot of different
+ string functions with <tt class="literal">if</tt> statements to handle special cases, or if you're combining them with <tt class="function">split</tt> and <tt class="function">join</tt> and list comprehensions in weird unreadable ways, you may need to move up to regular expressions.
+ </p>
+ </div>
+ <p>Although the regular expression syntax is tight and unlike normal code, the result can end up being <span class="emphasis"><em>more</em></span> readable than a hand-rolled solution that uses a long chain of string functions. There are even ways of embedding comments
+ within regular expressions to make them practically self-documenting.
+ </p>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="../file_handling/summary.html">&lt;&lt;&nbsp;Summary</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<span class="thispage">1</span> <span class="divider">|</span> <a href="street_addresses.html" title="7.2.&nbsp;Case Study: Street Addresses">2</a> <span class="divider">|</span> <a href="roman_numerals.html" title="7.3.&nbsp;Case Study: Roman Numerals">3</a> <span class="divider">|</span> <a href="n_m_syntax.html" title="7.4.&nbsp;Using the {n,m} Syntax">4</a> <span class="divider">|</span> <a href="verbose.html" title="7.5.&nbsp;Verbose Regular Expressions">5</a> <span class="divider">|</span> <a href="phone_numbers.html" title="7.6.&nbsp;Case study: Parsing Phone Numbers">6</a> <span class="divider">|</span> <a href="summary.html" title="7.7.&nbsp;Summary">7</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="street_addresses.html">Case Study: Street Addresses&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/regular_expressions/n_m_syntax.html b/help/diveintopython-5.4/html/regular_expressions/n_m_syntax.html
new file mode 100644
index 0000000..0f9c192
--- /dev/null
+++ b/help/diveintopython-5.4/html/regular_expressions/n_m_syntax.html
@@ -0,0 +1,283 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>7.4.&nbsp;Using the {n,m} Syntax</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;7.&nbsp;Regular Expressions">
+ <link rel="previous" href="roman_numerals.html" title="7.3.&nbsp;Case Study: Roman Numerals">
+ <link rel="next" href="verbose.html" title="7.5.&nbsp;Verbose Regular Expressions">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Regular Expressions</a>&nbsp;&gt;&nbsp;<span class="thispage">Using the {n,m} Syntax</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="roman_numerals.html" title="Prev: &#8220;Case Study: Roman Numerals&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="verbose.html" title="Next: &#8220;Verbose Regular Expressions&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="re.nm"></a>7.4.&nbsp;Using the <tt class="literal">{n,m}</tt> Syntax
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="toc">
+ <ul>
+ <li><span class="section"><a href="n_m_syntax.html#d0e18326">7.4.1. Checking for Tens and Ones</a></span></li>
+ </ul>
+ </div>
+ <div class="abstract">
+ <p>In <a href="roman_numerals.html" title="7.3.&nbsp;Case Study: Roman Numerals">the previous section</a>, you were dealing with a pattern where the same character could be repeated up to three times. There is another way to express
+ this in regular expressions, which some people find more readable. First look at the method we already used in the previous
+ example.
+ </p>
+ </div>
+ <div class="example"><a name="d0e18113"></a><h3 class="title">Example&nbsp;7.5.&nbsp;The Old Way: Every Character Optional</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> re</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">pattern = <span class='pystring'>'^M?M?M?$'</span></span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">re.search(pattern, <span class='pystring'>'M'</span>)</span> <a name="re.nm.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">&lt;_sre.SRE_Match object at 0x008EE090&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">pattern = <span class='pystring'>'^M?M?M?$'</span></span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">re.search(pattern, <span class='pystring'>'MM'</span>)</span> <a name="re.nm.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">&lt;_sre.SRE_Match object at 0x008EEB48&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">pattern = <span class='pystring'>'^M?M?M?$'</span></span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">re.search(pattern, <span class='pystring'>'MMM'</span>)</span> <a name="re.nm.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">&lt;_sre.SRE_Match object at 0x008EE090&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">re.search(pattern, <span class='pystring'>'MMMM'</span>)</span> <a name="re.nm.1.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.nm.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This matches the start of the string, and then the first optional <tt class="literal">M</tt>, but not the second and third <tt class="literal">M</tt> (but that's okay because they're optional), and then the end of the string.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.nm.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This matches the start of the string, and then the first and second optional <tt class="literal">M</tt>, but not the third <tt class="literal">M</tt> (but that's okay because it's optional), and then the end of the string.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.nm.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This matches the start of the string, and then all three optional <tt class="literal">M</tt>, and then the end of the string.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.nm.1.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This matches the start of the string, and then all three optional <tt class="literal">M</tt>, but then does not match the the end of the string (because there is still one unmatched <tt class="literal">M</tt>), so the pattern does not match and returns <tt class="literal">None</tt>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="d0e18215"></a><h3 class="title">Example&nbsp;7.6.&nbsp;The New Way: From <tt class="literal">n</tt> o <tt class="literal">m</tt></h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">pattern = <span class='pystring'>'^M{0,3}$'</span></span> <a name="re.nm.2.0"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">re.search(pattern, <span class='pystring'>'M'</span>)</span> <a name="re.nm.2.1"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">&lt;_sre.SRE_Match object at 0x008EEB48&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">re.search(pattern, <span class='pystring'>'MM'</span>)</span> <a name="re.nm.2.2"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">&lt;_sre.SRE_Match object at 0x008EE090&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">re.search(pattern, <span class='pystring'>'MMM'</span>)</span> <a name="re.nm.2.3"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">&lt;_sre.SRE_Match object at 0x008EEDA8&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">re.search(pattern, <span class='pystring'>'MMMM'</span>)</span> <a name="re.nm.2.4"></a><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.nm.2.0"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This pattern says: &#8220;<span class="quote">Match the start of the string, then anywhere from zero to three <tt class="literal">M</tt> characters, then the end of the string.</span>&#8221; The 0 and 3 can be any numbers; if you want to match at least one but no more than three <tt class="literal">M</tt> characters, you could say <tt class="literal">M{1,3}</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.nm.2.1"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This matches the start of the string, then one <tt class="literal">M</tt> out of a possible three, then the end of the string.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.nm.2.2"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This matches the start of the string, then two <tt class="literal">M</tt> out of a possible three, then the end of the string.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.nm.2.3"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This matches the start of the string, then three <tt class="literal">M</tt> out of a possible three, then the end of the string.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.nm.2.4"><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This matches the start of the string, then three <tt class="literal">M</tt> out of a possible three, but then <span class="emphasis"><em>does not match</em></span> the end of the string. The regular expression allows for up to only three <tt class="literal">M</tt> characters before the end of the string, but you have four, so the pattern does not match and returns <tt class="literal">None</tt>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div><a name="d0e18321"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">There is no way to programmatically determine that two regular expressions are equivalent. The best you can do is write a
+ lot of test cases to make sure they behave the same way on all relevant inputs. You'll talk more about writing test cases
+ later in this book.
+ </td>
+ </tr>
+ </table>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e18326"></a>7.4.1.&nbsp;Checking for Tens and Ones
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p>Now let's expand the Roman numeral regular expression to cover the tens and ones place. This example shows the check for
+ tens.
+ </p>
+ <div class="example"><a name="re.tens.example"></a><h3 class="title">Example&nbsp;7.7.&nbsp;Checking for Tens</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">pattern = <span class='pystring'>'^M?M?M?M?(CM|CD|D?C?C?C?)(XC|XL|L?X?X?X?)$'</span></span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">re.search(pattern, <span class='pystring'>'MCMXL'</span>)</span> <a name="re.nm.3.3"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">&lt;_sre.SRE_Match object at 0x008EEB48&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">re.search(pattern, <span class='pystring'>'MCML'</span>)</span> <a name="re.nm.3.4"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">&lt;_sre.SRE_Match object at 0x008EEB48&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">re.search(pattern, <span class='pystring'>'MCMLX'</span>)</span> <a name="re.nm.3.5"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">&lt;_sre.SRE_Match object at 0x008EEB48&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">re.search(pattern, <span class='pystring'>'MCMLXXX'</span>)</span> <a name="re.nm.3.7"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">&lt;_sre.SRE_Match object at 0x008EEB48&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">re.search(pattern, <span class='pystring'>'MCMLXXXX'</span>)</span> <a name="re.nm.3.8"></a><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.nm.3.3"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This matches the start of the string, then the first optional <tt class="literal">M</tt>, then <tt class="literal">CM</tt>, then <tt class="literal">XL</tt>, then the end of the string. Remember, the <tt class="literal">(A|B|C)</tt> syntax means &#8220;<span class="quote">match exactly one of A, B, or C</span>&#8221;. You match <tt class="literal">XL</tt>, so you ignore the <tt class="literal">XC</tt> and <tt class="literal">L?X?X?X?</tt> choices, and then move on to the end of the string. <tt class="literal">MCML</tt> is the Roman numeral representation of <tt class="literal">1940</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.nm.3.4"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This matches the start of the string, then the first optional <tt class="literal">M</tt>, then <tt class="literal">CM</tt>, then <tt class="literal">L?X?X?X?</tt>. Of the <tt class="literal">L?X?X?X?</tt>, it matches the <tt class="literal">L</tt> and skips all three optional <tt class="literal">X</tt> characters. Then you move to the end of the string. <tt class="literal">MCML</tt> is the Roman numeral representation of <tt class="literal">1950</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.nm.3.5"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This matches the start of the string, then the first optional <tt class="literal">M</tt>, then <tt class="literal">CM</tt>, then the optional <tt class="literal">L</tt> and the first optional <tt class="literal">X</tt>, skips the second and third optional <tt class="literal">X</tt>, then the end of the string. <tt class="literal">MCMLX</tt> is the Roman numeral representation of <tt class="literal">1960</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.nm.3.7"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This matches the start of the string, then the first optional <tt class="literal">M</tt>, then <tt class="literal">CM</tt>, then the optional <tt class="literal">L</tt> and all three optional <tt class="literal">X</tt> characters, then the end of the string. <tt class="literal">MCMLXXX</tt> is the Roman numeral representation of <tt class="literal">1980</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.nm.3.8"><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This matches the start of the string, then the first optional <tt class="literal">M</tt>, then <tt class="literal">CM</tt>, then the optional <tt class="literal">L</tt> and all three optional <tt class="literal">X</tt> characters, then <span class="emphasis"><em>fails to match</em></span> the end of the string because there is still one more <tt class="literal">X</tt> unaccounted for. So the entire pattern fails to match, and returns <tt class="literal">None</tt>. <tt class="literal">MCMLXXXX</tt> is not a valid Roman numeral.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>The expression for the ones place follows the same pattern. I'll spare you the details and show you the end result.</p>
+ <div class="informalexample"><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">pattern = <span class='pystring'>'^M?M?M?M?(CM|CD|D?C?C?C?)(XC|XL|L?X?X?X?)(IX|IV|V?I?I?I?)$'</span></span>
+</pre></div>
+ <p>So what does that look like using this alternate <tt class="literal">{n,m}</tt> syntax? This example shows the new syntax.
+ </p>
+ <div class="example"><a name="re.nm.example"></a><h3 class="title">Example&nbsp;7.8.&nbsp;Validating Roman Numerals with <tt class="literal">{n,m}</tt></h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">pattern = <span class='pystring'>'^M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$'</span></span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">re.search(pattern, <span class='pystring'>'MDLV'</span>)</span> <a name="re.nm.4.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">&lt;_sre.SRE_Match object at 0x008EEB48&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">re.search(pattern, <span class='pystring'>'MMDCLXVI'</span>)</span> <a name="re.nm.4.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">&lt;_sre.SRE_Match object at 0x008EEB48&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">re.search(pattern, <span class='pystring'>'MMMMDCCCLXXXVIII'</span>)</span> <a name="re.nm.4.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">&lt;_sre.SRE_Match object at 0x008EEB48&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">re.search(pattern, <span class='pystring'>'I'</span>)</span> <a name="re.nm.4.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">&lt;_sre.SRE_Match object at 0x008EEB48&gt;</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.nm.4.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This matches the start of the string, then one of a possible four <tt class="literal">M</tt> characters, then <tt class="literal">D?C{0,3}</tt>. Of that, it matches the optional <tt class="literal">D</tt> and zero of three possible <tt class="literal">C</tt> characters. Moving on, it matches <tt class="literal">L?X{0,3}</tt> by matching the optional <tt class="literal">L</tt> and zero of three possible <tt class="literal">X</tt> characters. Then it matches <tt class="literal">V?I{0,3}</tt> by matching the optional V and zero of three possible <tt class="literal">I</tt> characters, and finally the end of the string. <tt class="literal">MDLV</tt> is the Roman numeral representation of <tt class="literal">1555</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.nm.4.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This matches the start of the string, then two of a possible four <tt class="literal">M</tt> characters, then the <tt class="literal">D?C{0,3}</tt> with a <tt class="literal">D</tt> and one of three possible <tt class="literal">C</tt> characters; then <tt class="literal">L?X{0,3}</tt> with an <tt class="literal">L</tt> and one of three possible <tt class="literal">X</tt> characters; then <tt class="literal">V?I{0,3}</tt> with a <tt class="literal">V</tt> and one of three possible <tt class="literal">I</tt> characters; then the end of the string. <tt class="literal">MMDCLXVI</tt> is the Roman numeral representation of <tt class="literal">2666</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.nm.4.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This matches the start of the string, then four out of four <tt class="literal">M</tt> characters, then <tt class="literal">D?C{0,3}</tt> with a <tt class="literal">D</tt> and three out of three <tt class="literal">C</tt> characters; then <tt class="literal">L?X{0,3}</tt> with an <tt class="literal">L</tt> and three out of three <tt class="literal">X</tt> characters; then <tt class="literal">V?I{0,3}</tt> with a <tt class="literal">V</tt> and three out of three <tt class="literal">I</tt> characters; then the end of the string. <tt class="literal">MMMMDCCCLXXXVIII</tt> is the Roman numeral representation of <tt class="literal">3888</tt>, and it's the longest Roman numeral you can write without extended syntax.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.nm.4.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Watch closely. (I feel like a magician. &#8220;<span class="quote">Watch closely, kids, I'm going to pull a rabbit out of my hat.</span>&#8221;) This matches the start of the string, then zero out of four <tt class="literal">M</tt>, then matches <tt class="literal">D?C{0,3}</tt> by skipping the optional <tt class="literal">D</tt> and matching zero out of three <tt class="literal">C</tt>, then matches <tt class="literal">L?X{0,3}</tt> by skipping the optional <tt class="literal">L</tt> and matching zero out of three <tt class="literal">X</tt>, then matches <tt class="literal">V?I{0,3}</tt> by skipping the optional <tt class="literal">V</tt> and matching one out of three <tt class="literal">I</tt>. Then the end of the string. Whoa.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>If you followed all that and understood it on the first try, you're doing better than I did. Now imagine trying to understand
+ someone else's regular expressions, in the middle of a critical function of a large program. Or even imagine coming back
+ to your own regular expressions a few months later. I've done it, and it's not a pretty sight.
+ </p>
+ <p>In the next section you'll explore an alternate syntax that can help keep your expressions maintainable.</p>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="roman_numerals.html">&lt;&lt;&nbsp;Case Study: Roman Numerals</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#re.intro" title="7.1.&nbsp;Diving In">1</a> <span class="divider">|</span> <a href="street_addresses.html" title="7.2.&nbsp;Case Study: Street Addresses">2</a> <span class="divider">|</span> <a href="roman_numerals.html" title="7.3.&nbsp;Case Study: Roman Numerals">3</a> <span class="divider">|</span> <span class="thispage">4</span> <span class="divider">|</span> <a href="verbose.html" title="7.5.&nbsp;Verbose Regular Expressions">5</a> <span class="divider">|</span> <a href="phone_numbers.html" title="7.6.&nbsp;Case study: Parsing Phone Numbers">6</a> <span class="divider">|</span> <a href="summary.html" title="7.7.&nbsp;Summary">7</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="verbose.html">Verbose Regular Expressions&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/regular_expressions/phone_numbers.html b/help/diveintopython-5.4/html/regular_expressions/phone_numbers.html
new file mode 100644
index 0000000..0e18082
--- /dev/null
+++ b/help/diveintopython-5.4/html/regular_expressions/phone_numbers.html
@@ -0,0 +1,401 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>7.6.&nbsp;Case study: Parsing Phone Numbers</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;7.&nbsp;Regular Expressions">
+ <link rel="previous" href="verbose.html" title="7.5.&nbsp;Verbose Regular Expressions">
+ <link rel="next" href="summary.html" title="7.7.&nbsp;Summary">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Regular Expressions</a>&nbsp;&gt;&nbsp;<span class="thispage">Case study: Parsing Phone Numbers</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="verbose.html" title="Prev: &#8220;Verbose Regular Expressions&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="summary.html" title="Next: &#8220;Summary&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="re.phone"></a>7.6.&nbsp;Case study: Parsing Phone Numbers
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>So far you've concentrated on matching whole patterns. Either the pattern matches, or it doesn't. But regular expressions
+ are much more powerful than that. When a regular expression <span class="emphasis"><em>does</em></span> match, you can pick out specific pieces of it. You can find out what matched where.
+ </p>
+ </div>
+ <p>This example came from another real-world problem I encountered, again from a previous day job. The problem: parsing an American
+ phone number. The client wanted to be able to enter the number free-form (in a single field), but then wanted to store the
+ area code, trunk, number, and optionally an extension separately in the company's database. I scoured the Web and found many
+ examples of regular expressions that purported to do this, but none of them were permissive enough.
+ </p>
+ <p>Here are the phone numbers I needed to be able to accept:</p>
+ <div class="itemizedlist">
+ <ul>
+ <li><tt class="literal">800-555-1212</tt></li>
+ <li><tt class="literal">800 555 1212</tt></li>
+ <li><tt class="literal">800.555.1212</tt></li>
+ <li><tt class="literal">(800) 555-1212</tt></li>
+ <li><tt class="literal">1-800-555-1212</tt></li>
+ <li><tt class="literal">800-555-1212-1234</tt></li>
+ <li><tt class="literal">800-555-1212x1234</tt></li>
+ <li><tt class="literal">800-555-1212 ext. 1234</tt></li>
+ <li><tt class="literal">work 1-(800) 555.1212 #1234</tt></li>
+ </ul>
+ </div>
+ <p>Quite a variety! In each of these cases, I need to know that the area code was <tt class="literal">800</tt>, the trunk was <tt class="literal">555</tt>, and the rest of the phone number was <tt class="literal">1212</tt>. For those with an extension, I need to know that the extension was <tt class="literal">1234</tt>.
+ </p>
+ <p>Let's work through developing a solution for phone number parsing. This example shows the first step.</p>
+ <div class="example"><a name="re.phone.example"></a><h3 class="title">Example&nbsp;7.10.&nbsp;Finding Numbers</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">phonePattern = re.compile(r<span class='pystring'>'^(\d{3})-(\d{3})-(\d{4})$'</span>)</span> <a name="re.phone.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">phonePattern.search(<span class='pystring'>'800-555-1212'</span>).groups()</span> <a name="re.phone.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">('800', '555', '1212')</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">phonePattern.search(<span class='pystring'>'800-555-1212-1234'</span>)</span> <a name="re.phone.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.phone.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Always read regular expressions from left to right. This one matches the beginning of the string, and then <tt class="literal">(\d{3})</tt>. What's <tt class="literal">\d{3}</tt>? Well, the <tt class="literal">{3}</tt> means &#8220;<span class="quote">match exactly three numeric digits</span>&#8221;; it's a variation on the <a href="n_m_syntax.html" title="7.4.&nbsp;Using the {n,m} Syntax"><tt class="literal">{n,m} syntax</tt></a> you saw earlier. <tt class="literal">\d</tt> means &#8220;<span class="quote">any numeric digit</span>&#8221; (<tt class="literal">0</tt> through <tt class="literal">9</tt>). Putting it in parentheses means &#8220;<span class="quote">match exactly three numeric digits, <span class="emphasis"><em>and then remember them as a group that I can ask for later</em></span></span>&#8221;. Then match a literal hyphen. Then match another group of exactly three digits. Then another literal hyphen. Then another
+ group of exactly four digits. Then match the end of the string.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.phone.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">To get access to the groups that the regular expression parser remembered along the way, use the <tt class="function">groups()</tt> method on the object that the <tt class="function">search</tt> function returns. It will return a tuple of however many groups were defined in the regular expression. In this case, you
+ defined three groups, one with three digits, one with three digits, and one with four digits.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.phone.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This regular expression is not the final answer, because it doesn't handle a phone number with an extension on the end. For
+ that, you'll need to expand the regular expression.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="d0e19043"></a><h3 class="title">Example&nbsp;7.11.&nbsp;Finding the Extension</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">phonePattern = re.compile(r<span class='pystring'>'^(\d{3})-(\d{3})-(\d{4})-(\d+)$'</span>)</span> <a name="re.phone.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">phonePattern.search(<span class='pystring'>'800-555-1212-1234'</span>).groups()</span> <a name="re.phone.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">('800', '555', '1212', '1234')</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">phonePattern.search(<span class='pystring'>'800 555 1212 1234'</span>)</span> <a name="re.phone.2.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">phonePattern.search(<span class='pystring'>'800-555-1212'</span>)</span> <a name="re.phone.2.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.phone.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This regular expression is almost identical to the previous one. Just as before, you match the beginning of the string, then
+ a remembered group of three digits, then a hyphen, then a remembered group of three digits, then a hyphen, then a remembered
+ group of four digits. What's new is that you then match another hyphen, and a remembered group of one or more digits, then
+ the end of the string.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.phone.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="function">groups()</tt> method now returns a tuple of four elements, since the regular expression now defines four groups to remember.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.phone.2.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Unfortunately, this regular expression is not the final answer either, because it assumes that the different parts of the
+ phone number are separated by hyphens. What if they're separated by spaces, or commas, or dots? You need a more general
+ solution to match several different types of separators.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.phone.2.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Oops! Not only does this regular expression not do everything you want, it's actually a step backwards, because now you can't
+ parse phone numbers <span class="emphasis"><em>without</em></span> an extension. That's not what you wanted at all; if the extension is there, you want to know what it is, but if it's not
+ there, you still want to know what the different parts of the main number are.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>The next example shows the regular expression to handle separators between the different parts of the phone number.</p>
+ <div class="example"><a name="d0e19106"></a><h3 class="title">Example&nbsp;7.12.&nbsp;Handling Different Separators</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">phonePattern = re.compile(r<span class='pystring'>'^(\d{3})\D+(\d{3})\D+(\d{4})\D+(\d+)$'</span>)</span> <a name="re.phone.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">phonePattern.search(<span class='pystring'>'800 555 1212 1234'</span>).groups()</span> <a name="re.phone.3.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">('800', '555', '1212', '1234')</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">phonePattern.search(<span class='pystring'>'800-555-1212-1234'</span>).groups()</span> <a name="re.phone.3.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">('800', '555', '1212', '1234')</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">phonePattern.search(<span class='pystring'>'80055512121234'</span>)</span> <a name="re.phone.3.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">phonePattern.search(<span class='pystring'>'800-555-1212'</span>)</span> <a name="re.phone.3.5"></a><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.phone.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Hang on to your hat. You're matching the beginning of the string, then a group of three digits, then <tt class="literal">\D+</tt>. What the heck is that? Well, <tt class="literal">\D</tt> matches any character <span class="emphasis"><em>except</em></span> a numeric digit, and <tt class="literal">+</tt> means &#8220;<span class="quote">1 or more</span>&#8221;. So <tt class="literal">\D+</tt> matches one or more characters that are not digits. This is what you're using instead of a literal hyphen, to try to match
+ different separators.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.phone.3.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Using <tt class="literal">\D+</tt> instead of <tt class="literal">-</tt> means you can now match phone numbers where the parts are separated by spaces instead of hyphens.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.phone.3.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Of course, phone numbers separated by hyphens still work too.</td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.phone.3.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Unfortunately, this is still not the final answer, because it assumes that there is a separator at all. What if the phone
+ number is entered without any spaces or hyphens at all?
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.phone.3.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Oops! This still hasn't fixed the problem of requiring extensions. Now you have two problems, but you can solve both of
+ them with the same technique.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>The next example shows the regular expression for handling phone numbers <span class="emphasis"><em>without</em></span> separators.
+ </p>
+ <div class="example"><a name="d0e19203"></a><h3 class="title">Example&nbsp;7.13.&nbsp;Handling Numbers Without Separators</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">phonePattern = re.compile(r<span class='pystring'>'^(\d{3})\D*(\d{3})\D*(\d{4})\D*(\d*)$'</span>)</span> <a name="re.phone.4.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">phonePattern.search(<span class='pystring'>'80055512121234'</span>).groups()</span> <a name="re.phone.4.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">('800', '555', '1212', '1234')</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">phonePattern.search(<span class='pystring'>'800.555.1212 x1234'</span>).groups()</span> <a name="re.phone.4.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">('800', '555', '1212', '1234')</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">phonePattern.search(<span class='pystring'>'800-555-1212'</span>).groups()</span> <a name="re.phone.4.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">('800', '555', '1212', '')</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">phonePattern.search(<span class='pystring'>'(800)5551212 x1234'</span>)</span> <a name="re.phone.4.5"></a><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.phone.4.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The only change you've made since that last step is changing all the <tt class="literal">+</tt> to <tt class="literal">*</tt>. Instead of <tt class="literal">\D+</tt> between the parts of the phone number, you now match on <tt class="literal">\D*</tt>. Remember that <tt class="literal">+</tt> means &#8220;<span class="quote">1 or more</span>&#8221;? Well, <tt class="literal">*</tt> means &#8220;<span class="quote">zero or more</span>&#8221;. So now you should be able to parse phone numbers even when there is no separator character at all.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.phone.4.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Lo and behold, it actually works. Why? You matched the beginning of the string, then a remembered group of three digits
+ (<tt class="literal">800</tt>), then zero non-numeric characters, then a remembered group of three digits (<tt class="literal">555</tt>), then zero non-numeric characters, then a remembered group of four digits (<tt class="literal">1212</tt>), then zero non-numeric characters, then a remembered group of an arbitrary number of digits (<tt class="literal">1234</tt>), then the end of the string.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.phone.4.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Other variations work now too: dots instead of hyphens, and both a space and an <tt class="literal">x</tt> before the extension.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.phone.4.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Finally, you've solved the other long-standing problem: extensions are optional again. If no extension is found, the <tt class="function">groups()</tt> method still returns a tuple of four elements, but the fourth element is just an empty string.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.phone.4.5"><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">I hate to be the bearer of bad news, but you're not finished yet. What's the problem here? There's an extra character before
+ the area code, but the regular expression assumes that the area code is the first thing at the beginning of the string. No
+ problem, you can use the same technique of &#8220;<span class="quote">zero or more non-numeric characters</span>&#8221; to skip over the leading characters before the area code.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>The next example shows how to handle leading characters in phone numbers.</p>
+ <div class="example"><a name="d0e19318"></a><h3 class="title">Example&nbsp;7.14.&nbsp;Handling Leading Characters</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">phonePattern = re.compile(r<span class='pystring'>'^\D*(\d{3})\D*(\d{3})\D*(\d{4})\D*(\d*)$'</span>)</span> <a name="re.phone.5.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">phonePattern.search(<span class='pystring'>'(800)5551212 ext. 1234'</span>).groups()</span> <a name="re.phone.5.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">('800', '555', '1212', '1234')</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">phonePattern.search(<span class='pystring'>'800-555-1212'</span>).groups()</span> <a name="re.phone.5.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">('800', '555', '1212', '')</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">phonePattern.search(<span class='pystring'>'work 1-(800) 555.1212 #1234'</span>)</span> <a name="re.phone.5.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.phone.5.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This is the same as in the previous example, except now you're matching <tt class="literal">\D*</tt>, zero or more non-numeric characters, before the first remembered group (the area code). Notice that you're not remembering
+ these non-numeric characters (they're not in parentheses). If you find them, you'll just skip over them and then start remembering
+ the area code whenever you get to it.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.phone.5.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You can successfully parse the phone number, even with the leading left parenthesis before the area code. (The right parenthesis
+ after the area code is already handled; it's treated as a non-numeric separator and matched by the <tt class="literal">\D*</tt> after the first remembered group.)
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.phone.5.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Just a sanity check to make sure you haven't broken anything that used to work. Since the leading characters are entirely
+ optional, this matches the beginning of the string, then zero non-numeric characters, then a remembered group of three digits
+ (<tt class="literal">800</tt>), then one non-numeric character (the hyphen), then a remembered group of three digits (<tt class="literal">555</tt>), then one non-numeric character (the hyphen), then a remembered group of four digits (<tt class="literal">1212</tt>), then zero non-numeric characters, then a remembered group of zero digits, then the end of the string.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.phone.5.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This is where regular expressions make me want to gouge my eyes out with a blunt object. Why doesn't this phone number match?
+ Because there's a <tt class="literal">1</tt> before the area code, but you assumed that all the leading characters before the area code were non-numeric characters (<tt class="literal">\D*</tt>). Aargh.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>Let's back up for a second. So far the regular expressions have all matched from the beginning of the string. But now you
+ see that there may be an indeterminate amount of stuff at the beginning of the string that you want to ignore. Rather than
+ trying to match it all just so you can skip over it, let's take a different approach: don't explicitly match the beginning
+ of the string at all. This approach is shown in the next example.
+ </p>
+ <div class="example"><a name="d0e19396"></a><h3 class="title">Example&nbsp;7.15.&nbsp;Phone Number, Wherever I May Find Ye</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">phonePattern = re.compile(r<span class='pystring'>'(\d{3})\D*(\d{3})\D*(\d{4})\D*(\d*)$'</span>)</span> <a name="re.phone.6.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">phonePattern.search(<span class='pystring'>'work 1-(800) 555.1212 #1234'</span>).groups()</span> <a name="re.phone.6.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">('800', '555', '1212', '1234')</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">phonePattern.search(<span class='pystring'>'800-555-1212'</span>)</span> <a name="re.phone.6.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">('800', '555', '1212', '')</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">phonePattern.search(<span class='pystring'>'80055512121234'</span>)</span> <a name="re.phone.6.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">('800', '555', '1212', '1234')</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.phone.6.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Note the lack of <tt class="literal">^</tt> in this regular expression. You are not matching the beginning of the string anymore. There's nothing that says you need
+ to match the entire input with your regular expression. The regular expression engine will do the hard work of figuring out
+ where the input string starts to match, and go from there.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.phone.6.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Now you can successfully parse a phone number that includes leading characters and a leading digit, plus any number of any
+ kind of separators around each part of the phone number.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.phone.6.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Sanity check. this still works.</td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.phone.6.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">That still works too.</td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>See how quickly a regular expression can get out of control? Take a quick glance at any of the previous iterations. Can
+ you tell the difference between one and the next?
+ </p>
+ <p>While you still understand the final answer (and it is the final answer; if you've discovered a case it doesn't handle, I
+ don't want to know about it), let's write it out as a verbose regular expression, before you forget why you made the choices
+ you made.
+ </p>
+ <div class="example"><a name="d0e19458"></a><h3 class="title">Example&nbsp;7.16.&nbsp;Parsing Phone Numbers (Final Version)</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">phonePattern = re.compile(r<span class='pystring'>'''
+ # don't match beginning of string, number can start anywhere
+ (\d{3}) # area code is 3 digits (e.g. '800')
+ \D* # optional separator is any number of non-digits
+ (\d{3}) # trunk is 3 digits (e.g. '555')
+ \D* # optional separator
+ (\d{4}) # rest of number is 4 digits (e.g. '1212')
+ \D* # optional separator
+ (\d*) # extension is optional and can be any number of digits
+ $ # end of string
+ '''</span>, re.VERBOSE)</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">phonePattern.search(<span class='pystring'>'work 1-(800) 555.1212 #1234'</span>).groups()</span> <a name="re.phone.7.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">('800', '555', '1212', '1234')</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">phonePattern.search(<span class='pystring'>'800-555-1212'</span>)</span> <a name="re.phone.7.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">('800', '555', '1212', '')</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.phone.7.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Other than being spread out over multiple lines, this is exactly the same regular expression as the last step, so it's no
+ surprise that it parses the same inputs.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.phone.7.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Final sanity check. Yes, this still works. You're done.</td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="furtherreading">
+ <h3>Further Reading on Regular Expressions</h3>
+ <ul>
+ <li><a href="http://py-howto.sourceforge.net/regex/regex.html">Regular Expression HOWTO</a> teaches about regular expressions and how to use them in <span class="application">Python</span>.
+ </li>
+ <li><a href="http://www.python.org/doc/current/lib/"><i class="citetitle"><span class="application">Python</span> Library Reference</i></a> summarizes the <a href="http://www.python.org/doc/current/lib/module-re.html"><tt class="filename">re</tt> module</a>.
+ </li>
+ </ul>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="verbose.html">&lt;&lt;&nbsp;Verbose Regular Expressions</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#re.intro" title="7.1.&nbsp;Diving In">1</a> <span class="divider">|</span> <a href="street_addresses.html" title="7.2.&nbsp;Case Study: Street Addresses">2</a> <span class="divider">|</span> <a href="roman_numerals.html" title="7.3.&nbsp;Case Study: Roman Numerals">3</a> <span class="divider">|</span> <a href="n_m_syntax.html" title="7.4.&nbsp;Using the {n,m} Syntax">4</a> <span class="divider">|</span> <a href="verbose.html" title="7.5.&nbsp;Verbose Regular Expressions">5</a> <span class="divider">|</span> <span class="thispage">6</span> <span class="divider">|</span> <a href="summary.html" title="7.7.&nbsp;Summary">7</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="summary.html">Summary&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/regular_expressions/roman_numerals.html b/help/diveintopython-5.4/html/regular_expressions/roman_numerals.html
new file mode 100644
index 0000000..eff0d3e
--- /dev/null
+++ b/help/diveintopython-5.4/html/regular_expressions/roman_numerals.html
@@ -0,0 +1,288 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>7.3.&nbsp;Case Study: Roman Numerals</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;7.&nbsp;Regular Expressions">
+ <link rel="previous" href="street_addresses.html" title="7.2.&nbsp;Case Study: Street Addresses">
+ <link rel="next" href="n_m_syntax.html" title="7.4.&nbsp;Using the {n,m} Syntax">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Regular Expressions</a>&nbsp;&gt;&nbsp;<span class="thispage">Case Study: Roman Numerals</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="street_addresses.html" title="Prev: &#8220;Case Study: Street Addresses&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="n_m_syntax.html" title="Next: &#8220;Using the {n,m} Syntax&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="re.roman"></a>7.3.&nbsp;Case Study: Roman Numerals
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="toc">
+ <ul>
+ <li><span class="section"><a href="roman_numerals.html#d0e17592">7.3.1. Checking for Thousands</a></span></li>
+ <li><span class="section"><a href="roman_numerals.html#d0e17785">7.3.2. Checking for Hundreds</a></span></li>
+ </ul>
+ </div>
+ <div class="abstract">
+ <p>You've most likely seen Roman numerals, even if you didn't recognize them. You may have seen them in copyrights of old movies
+ and television shows (&#8220;<span class="quote">Copyright <tt class="literal">MCMXLVI</tt></span>&#8221; instead of &#8220;<span class="quote">Copyright <tt class="literal">1946</tt></span>&#8221;), or on the dedication walls of libraries or universities (&#8220;<span class="quote">established <tt class="literal">MDCCCLXXXVIII</tt></span>&#8221; instead of &#8220;<span class="quote">established <tt class="literal">1888</tt></span>&#8221;). You may also have seen them in outlines and bibliographical references. It's a system of representing numbers that really
+ does date back to the ancient Roman empire (hence the name).
+ </p>
+ </div>
+ <p>In Roman numerals, there are seven characters that are repeated and combined in various ways to represent numbers.</p>
+ <div class="itemizedlist">
+ <ul>
+ <li><tt class="literal">I</tt> = <tt class="literal">1</tt></li>
+ <li><tt class="literal">V</tt> = <tt class="literal">5</tt></li>
+ <li><tt class="literal">X</tt> = <tt class="literal">10</tt></li>
+ <li><tt class="literal">L</tt> = <tt class="literal">50</tt></li>
+ <li><tt class="literal">C</tt> = <tt class="literal">100</tt></li>
+ <li><tt class="literal">D</tt> = <tt class="literal">500</tt></li>
+ <li><tt class="literal">M</tt> = <tt class="literal">1000</tt></li>
+ </ul>
+ </div>
+ <p>The following are some general rules for constructing Roman numerals:</p>
+ <div class="itemizedlist">
+ <ul>
+ <li>Characters are additive. <tt class="literal">I</tt> is <tt class="constant">1</tt>, <tt class="literal">II</tt> is <tt class="literal">2</tt>, and <tt class="literal">III</tt> is <tt class="literal">3</tt>. <tt class="literal">VI</tt> is <tt class="literal">6</tt> (literally, &#8220;<span class="quote"><tt class="literal">5</tt> and <tt class="literal">1</tt></span>&#8221;), <tt class="literal">VII</tt> is <tt class="literal">7</tt>, and <tt class="literal">VIII</tt> is <tt class="literal">8</tt>.
+ </li>
+ <li>The tens characters (<tt class="literal">I</tt>, <tt class="literal">X</tt>, <tt class="literal">C</tt>, and <tt class="literal">M</tt>) can be repeated up to three times. At <tt class="literal">4</tt>, you need to subtract from the next highest fives character. You can't represent <tt class="literal">4</tt> as <tt class="literal">IIII</tt>; instead, it is represented as <tt class="literal">IV</tt> (&#8220;<span class="quote"><tt class="literal">1</tt> less than <tt class="literal">5</tt></span>&#8221;). The number <tt class="literal">40</tt> is written as <tt class="literal">XL</tt> (<tt class="literal">10</tt> less than <tt class="literal">50</tt>), <tt class="literal">41</tt> as <tt class="literal">XLI</tt>, <tt class="literal">42</tt> as <tt class="literal">XLII</tt>, <tt class="literal">43</tt> as <tt class="literal">XLIII</tt>, and then <tt class="literal">44</tt> as <tt class="literal">XLIV</tt> (<tt class="literal">10</tt> less than <tt class="literal">50</tt>, then <tt class="literal">1</tt> less than <tt class="literal">5</tt>).
+ </li>
+ <li>Similarly, at <tt class="literal">9</tt>, you need to subtract from the next highest tens character: <tt class="literal">8</tt> is <tt class="literal">VIII</tt>, but <tt class="literal">9</tt> is <tt class="literal">IX</tt> (<tt class="literal">1</tt> less than <tt class="literal">10</tt>), not <tt class="literal">VIIII</tt> (since the <tt class="literal">I</tt> character can not be repeated four times). The number <tt class="literal">90</tt> is <tt class="literal">XC</tt>, <tt class="literal">900</tt> is <tt class="literal">CM</tt>.
+ </li>
+ <li>The fives characters can not be repeated. The number <tt class="literal">10</tt> is always represented as <tt class="literal">X</tt>, never as <tt class="literal">VV</tt>. The number <tt class="literal">100</tt> is always <tt class="literal">C</tt>, never <tt class="literal">LL</tt>.
+ </li>
+ <li>Roman numerals are always written highest to lowest, and read left to right, so the order the of characters matters very much.
+ <tt class="literal">DC</tt> is <tt class="literal">600</tt>; <tt class="literal">CD</tt> is a completely different number (<tt class="literal">400</tt>, <tt class="literal">100</tt> less than <tt class="literal">500</tt>). <tt class="literal">CI</tt> is <tt class="literal">101</tt>; <tt class="literal">IC</tt> is not even a valid Roman numeral (because you can't subtract <tt class="literal">1</tt> directly from <tt class="literal">100</tt>; you would need to write it as <tt class="literal">XCIX</tt>, for <tt class="literal">10</tt> less than <tt class="literal">100</tt>, then <tt class="literal">1</tt> less than <tt class="literal">10</tt>).
+ </li>
+ </ul>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e17592"></a>7.3.1.&nbsp;Checking for Thousands
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p>What would it take to validate that an arbitrary string is a valid Roman numeral? Let's take it one digit at a time. Since
+ Roman numerals are always written highest to lowest, let's start with the highest: the thousands place. For numbers 1000
+ and higher, the thousands are represented by a series of <tt class="literal">M</tt> characters.
+ </p>
+ <div class="example"><a name="d0e17600"></a><h3 class="title">Example&nbsp;7.3.&nbsp;Checking for Thousands</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> re</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">pattern = <span class='pystring'>'^M?M?M?$'</span></span> <a name="re.roman.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">re.search(pattern, <span class='pystring'>'M'</span>)</span> <a name="re.roman.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">&lt;SRE_Match object at 0106FB58&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">re.search(pattern, <span class='pystring'>'MM'</span>)</span> <a name="re.roman.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">&lt;SRE_Match object at 0106C290&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">re.search(pattern, <span class='pystring'>'MMM'</span>)</span> <a name="re.roman.1.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">&lt;SRE_Match object at 0106AA38&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">re.search(pattern, <span class='pystring'>'MMMM'</span>)</span> <a name="re.roman.1.5"></a><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">re.search(pattern, <span class='pystring'>''</span>)</span> <a name="re.roman.1.6"></a><img src="../images/callouts/6.png" alt="6" border="0" width="12" height="12">
+<span class="computeroutput">&lt;SRE_Match object at 0106F4A8&gt;</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.roman.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This pattern has three parts:
+ <div class="itemizedlist">
+ <ul>
+ <li><tt class="literal">^</tt> to match what follows only at the beginning of the string. If this were not specified, the pattern would match no matter
+ where the <tt class="literal">M</tt> characters were, which is not what you want. You want to make sure that the <tt class="literal">M</tt> characters, if they're there, are at the beginning of the string.
+ </li>
+ <li><tt class="literal">M?</tt> to optionally match a single <tt class="literal">M</tt> character. Since this is repeated three times, you're matching anywhere from zero to three <tt class="literal">M</tt> characters in a row.
+ </li>
+ <li><tt class="literal">$</tt> to match what precedes only at the end of the string. When combined with the <tt class="literal">^</tt> character at the beginning, this means that the pattern must match the entire string, with no other characters before or
+ after the <tt class="literal">M</tt> characters.
+ </li>
+ </ul>
+ </div>
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.roman.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The essence of the <tt class="filename">re</tt> module is the <tt class="function">search</tt> function, that takes a regular expression (<tt class="varname">pattern</tt>) and a string (<tt class="literal">'M'</tt>) to try to match against the regular expression. If a match is found, <tt class="function">search</tt> returns an object which has various methods to describe the match; if no match is found, <tt class="function">search</tt> returns <tt class="literal">None</tt>, the <span class="application">Python</span> null value. All you care about at the moment is whether the pattern matches, which you can tell by just looking at the return
+ value of <tt class="function">search</tt>. <tt class="literal">'M'</tt> matches this regular expression, because the first optional <tt class="literal">M</tt> matches and the second and third optional <tt class="literal">M</tt> characters are ignored.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.roman.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="literal">'MM'</tt> matches because the first and second optional <tt class="literal">M</tt> characters match and the third <tt class="literal">M</tt> is ignored.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.roman.1.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="literal">'MMM'</tt> matches because all three <tt class="literal">M</tt> characters match.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.roman.1.5"><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="literal">'MMMM'</tt> does not match. All three <tt class="literal">M</tt> characters match, but then the regular expression insists on the string ending (because of the <tt class="literal">$</tt> character), and the string doesn't end yet (because of the fourth <tt class="literal">M</tt>). So <tt class="function">search</tt> returns <tt class="literal">None</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.roman.1.6"><img src="../images/callouts/6.png" alt="6" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Interestingly, an empty string also matches this regular expression, since all the <tt class="literal">M</tt> characters are optional.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e17785"></a>7.3.2.&nbsp;Checking for Hundreds
+ </h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p>The hundreds place is more difficult than the thousands, because there are several mutually exclusive ways it could be expressed,
+ depending on its value.
+ </p>
+ <div class="itemizedlist">
+ <ul>
+ <li><tt class="literal">100</tt> = <tt class="literal">C</tt></li>
+ <li><tt class="literal">200</tt> = <tt class="literal">CC</tt></li>
+ <li><tt class="literal">300</tt> = <tt class="literal">CCC</tt></li>
+ <li><tt class="literal">400</tt> = <tt class="literal">CD</tt></li>
+ <li><tt class="literal">500</tt> = <tt class="literal">D</tt></li>
+ <li><tt class="literal">600</tt> = <tt class="literal">DC</tt></li>
+ <li><tt class="literal">700</tt> = <tt class="literal">DCC</tt></li>
+ <li><tt class="literal">800</tt> = <tt class="literal">DCCC</tt></li>
+ <li><tt class="literal">900</tt> = <tt class="literal">CM</tt></li>
+ </ul>
+ </div>
+ <p>So there are four possible patterns:</p>
+ <div class="itemizedlist">
+ <ul>
+ <li><tt class="literal">CM</tt></li>
+ <li><tt class="literal">CD</tt></li>
+ <li>Zero to three <tt class="literal">C</tt> characters (zero if the hundreds place is 0)
+ </li>
+ <li><tt class="literal">D</tt>, followed by zero to three <tt class="literal">C</tt> characters
+ </li>
+ </ul>
+ </div>
+ <p>The last two patterns can be combined:</p>
+ <div class="itemizedlist">
+ <ul>
+ <li>an optional <tt class="literal">D</tt>, followed by zero to three <tt class="literal">C</tt> characters
+ </li>
+ </ul>
+ </div>
+ <p>This example shows how to validate the hundreds place of a Roman numeral.</p>
+ <div class="example"><a name="re.roman.hundreds"></a><h3 class="title">Example&nbsp;7.4.&nbsp;Checking for Hundreds</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> re</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">pattern = <span class='pystring'>'^M?M?M?(CM|CD|D?C?C?C?)$'</span></span> <a name="re.roman.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">re.search(pattern, <span class='pystring'>'MCM'</span>)</span> <a name="re.roman.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">&lt;SRE_Match object at 01070390&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">re.search(pattern, <span class='pystring'>'MD'</span>)</span> <a name="re.roman.2.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">&lt;SRE_Match object at 01073A50&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">re.search(pattern, <span class='pystring'>'MMMCCC'</span>)</span> <a name="re.roman.2.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">&lt;SRE_Match object at 010748A8&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">re.search(pattern, <span class='pystring'>'MCMC'</span>)</span> <a name="re.roman.2.5"></a><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">re.search(pattern, <span class='pystring'>''</span>)</span> <a name="re.roman.2.6"></a><img src="../images/callouts/6.png" alt="6" border="0" width="12" height="12">
+<span class="computeroutput">&lt;SRE_Match object at 01071D98&gt;</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.roman.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This pattern starts out the same as the previous one, checking for the beginning of the string (<tt class="literal">^</tt>), then the thousands place (<tt class="literal">M?M?M?</tt>). Then it has the new part, in parentheses, which defines a set of three mutually exclusive patterns, separated by vertical
+ bars: <tt class="literal">CM</tt>, <tt class="literal">CD</tt>, and <tt class="literal">D?C?C?C?</tt> (which is an optional <tt class="literal">D</tt> followed by zero to three optional <tt class="literal">C</tt> characters). The regular expression parser checks for each of these patterns in order (from left to right), takes the first
+ one that matches, and ignores the rest.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.roman.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="literal">'MCM'</tt> matches because the first <tt class="literal">M</tt> matches, the second and third <tt class="literal">M</tt> characters are ignored, and the <tt class="literal">CM</tt> matches (so the <tt class="literal">CD</tt> and <tt class="literal">D?C?C?C?</tt> patterns are never even considered). <tt class="literal">MCM</tt> is the Roman numeral representation of <tt class="literal">1900</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.roman.2.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="literal">'MD'</tt> matches because the first <tt class="literal">M</tt> matches, the second and third <tt class="literal">M</tt> characters are ignored, and the <tt class="literal">D?C?C?C?</tt> pattern matches <tt class="literal">D</tt> (each of the three <tt class="literal">C</tt> characters are optional and are ignored). <tt class="literal">MD</tt> is the Roman numeral representation of <tt class="literal">1500</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.roman.2.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="literal">'MMMCCC'</tt> matches because all three <tt class="literal">M</tt> characters match, and the <tt class="literal">D?C?C?C?</tt> pattern matches <tt class="literal">CCC</tt> (the <tt class="literal">D</tt> is optional and is ignored). <tt class="literal">MMMCCC</tt> is the Roman numeral representation of <tt class="literal">3300</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.roman.2.5"><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="literal">'MCMC'</tt> does not match. The first <tt class="literal">M</tt> matches, the second and third <tt class="literal">M</tt> characters are ignored, and the <tt class="literal">CM</tt> matches, but then the <tt class="literal">$</tt> does not match because you're not at the end of the string yet (you still have an unmatched <tt class="literal">C</tt> character). The <tt class="literal">C</tt> does <span class="emphasis"><em>not</em></span> match as part of the <tt class="literal">D?C?C?C?</tt> pattern, because the mutually exclusive <tt class="literal">CM</tt> pattern has already matched.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.roman.2.6"><img src="../images/callouts/6.png" alt="6" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Interestingly, an empty string still matches this pattern, because all the <tt class="literal">M</tt> characters are optional and ignored, and the empty string matches the <tt class="literal">D?C?C?C?</tt> pattern where all the characters are optional and ignored.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>Whew! See how quickly regular expressions can get nasty? And you've only covered the thousands and hundreds places of Roman
+ numerals. But if you followed all that, the tens and ones places are easy, because they're exactly the same pattern. But
+ let's look at another way to express the pattern.
+ </p>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="street_addresses.html">&lt;&lt;&nbsp;Case Study: Street Addresses</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#re.intro" title="7.1.&nbsp;Diving In">1</a> <span class="divider">|</span> <a href="street_addresses.html" title="7.2.&nbsp;Case Study: Street Addresses">2</a> <span class="divider">|</span> <span class="thispage">3</span> <span class="divider">|</span> <a href="n_m_syntax.html" title="7.4.&nbsp;Using the {n,m} Syntax">4</a> <span class="divider">|</span> <a href="verbose.html" title="7.5.&nbsp;Verbose Regular Expressions">5</a> <span class="divider">|</span> <a href="phone_numbers.html" title="7.6.&nbsp;Case study: Parsing Phone Numbers">6</a> <span class="divider">|</span> <a href="summary.html" title="7.7.&nbsp;Summary">7</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="n_m_syntax.html">Using the {n,m} Syntax&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/regular_expressions/street_addresses.html b/help/diveintopython-5.4/html/regular_expressions/street_addresses.html
new file mode 100644
index 0000000..c51de04
--- /dev/null
+++ b/help/diveintopython-5.4/html/regular_expressions/street_addresses.html
@@ -0,0 +1,172 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>7.2.&nbsp;Case Study: Street Addresses</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;7.&nbsp;Regular Expressions">
+ <link rel="previous" href="index.html" title="Chapter&nbsp;7.&nbsp;Regular Expressions">
+ <link rel="next" href="roman_numerals.html" title="7.3.&nbsp;Case Study: Roman Numerals">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Regular Expressions</a>&nbsp;&gt;&nbsp;<span class="thispage">Case Study: Street Addresses</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="index.html" title="Prev: &#8220;Regular Expressions&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="roman_numerals.html" title="Next: &#8220;Case Study: Roman Numerals&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="re.matching"></a>7.2.&nbsp;Case Study: Street Addresses
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>This series of examples was inspired by a real-life problem I had in my day job several years ago, when I needed to scrub
+ and standardize street addresses exported from a legacy system before importing them into a newer system. (See, I don't just
+ make this stuff up; it's actually useful.) This example shows how I approached the problem.
+ </p>
+ </div>
+ <div class="example"><a name="d0e16923"></a><h3 class="title">Example&nbsp;7.1.&nbsp;Matching at the End of a String</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">s = <span class='pystring'>'100 NORTH MAIN ROAD'</span></span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">s.replace(<span class='pystring'>'ROAD'</span>, <span class='pystring'>'RD.'</span>)</span> <a name="re.matching.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">'100 NORTH MAIN RD.'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">s = <span class='pystring'>'100 NORTH BROAD ROAD'</span></span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">s.replace(<span class='pystring'>'ROAD'</span>, <span class='pystring'>'RD.'</span>)</span> <a name="re.matching.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">'100 NORTH BRD. RD.'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">s[:-4] + s[-4:].replace(<span class='pystring'>'ROAD'</span>, <span class='pystring'>'RD.'</span>)</span> <a name="re.matching.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">'100 NORTH BROAD RD.'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> re</span> <a name="re.matching.1.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">re.sub(<span class='pystring'>'ROAD$'</span>, <span class='pystring'>'RD.'</span>, s)</span> <a name="re.matching.1.5"></a><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12"> <a name="re.matching.1.6"></a><img src="../images/callouts/6.png" alt="6" border="0" width="12" height="12">
+<span class="computeroutput">'100 NORTH BROAD RD.'</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.matching.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">My goal is to standardize a street address so that <tt class="literal">'ROAD'</tt> is always abbreviated as <tt class="literal">'RD.'</tt>. At first glance, I thought this was simple enough that I could just use the string method <tt class="function">replace</tt>. After all, all the data was already uppercase, so case mismatches would not be a problem. And the search string, <tt class="literal">'ROAD'</tt>, was a constant. And in this deceptively simple example, <tt class="function">s.replace</tt> does indeed work.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.matching.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Life, unfortunately, is full of counterexamples, and I quickly discovered this one. The problem here is that <tt class="literal">'ROAD'</tt> appears twice in the address, once as part of the street name <tt class="literal">'BROAD'</tt> and once as its own word. The <tt class="function">replace</tt> method sees these two occurrences and blindly replaces both of them; meanwhile, I see my addresses getting destroyed.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.matching.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">To solve the problem of addresses with more than one <tt class="literal">'ROAD'</tt> substring, you could resort to something like this: only search and replace <tt class="literal">'ROAD'</tt> in the last four characters of the address (<tt class="literal">s[-4:]</tt>), and leave the string alone (<tt class="literal">s[:-4]</tt>). But you can see that this is already getting unwieldy. For example, the pattern is dependent on the length of the string
+ you're replacing (if you were replacing <tt class="literal">'STREET'</tt> with <tt class="literal">'ST.'</tt>, you would need to use <tt class="literal">s[:-6]</tt> and <tt class="literal">s[-6:].replace(...)</tt>). Would you like to come back in six months and debug this? I know I wouldn't.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.matching.1.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">It's time to move up to regular expressions. In <span class="application">Python</span>, all functionality related to regular expressions is contained in the <tt class="filename">re</tt> module.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.matching.1.5"><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Take a look at the first parameter: <tt class="literal">'ROAD$'</tt>. This is a simple regular expression that matches <tt class="literal">'ROAD'</tt> only when it occurs at the end of a string. The <tt class="literal">$</tt> means &#8220;<span class="quote">end of the string</span>&#8221;. (There is a corresponding character, the caret <tt class="literal">^</tt>, which means &#8220;<span class="quote">beginning of the string</span>&#8221;.)
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.matching.1.6"><img src="../images/callouts/6.png" alt="6" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Using the <tt class="function">re.sub</tt> function, you search the string <tt class="varname">s</tt> for the regular expression <tt class="literal">'ROAD$'</tt> and replace it with <tt class="literal">'RD.'</tt>. This matches the <tt class="literal">ROAD</tt> at the end of the string <tt class="varname">s</tt>, but does <span class="emphasis"><em>not</em></span> match the <tt class="literal">ROAD</tt> that's part of the word <tt class="literal">BROAD</tt>, because that's in the middle of <tt class="varname">s</tt>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>Continuing with my story of scrubbing addresses, I soon discovered that the previous example, matching <tt class="literal">'ROAD'</tt> at the end of the address, was not good enough, because not all addresses included a street designation at all; some just
+ ended with the street name. Most of the time, I got away with it, but if the street name was <tt class="literal">'BROAD'</tt>, then the regular expression would match <tt class="literal">'ROAD'</tt> at the end of the string as part of the word <tt class="literal">'BROAD'</tt>, which is not what I wanted.
+ </p>
+ <div class="example"><a name="d0e17121"></a><h3 class="title">Example&nbsp;7.2.&nbsp;Matching Whole Words</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">s = <span class='pystring'>'100 BROAD'</span></span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">re.sub(<span class='pystring'>'ROAD$'</span>, <span class='pystring'>'RD.'</span>, s)</span>
+<span class="computeroutput">'100 BRD.'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">re.sub(<span class='pystring'>'\\bROAD$'</span>, <span class='pystring'>'RD.'</span>, s)</span> <a name="re.matching.2.2"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">'100 BROAD'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">re.sub(r<span class='pystring'>'\bROAD$'</span>, <span class='pystring'>'RD.'</span>, s)</span> <a name="re.matching.2.3"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">'100 BROAD'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">s = <span class='pystring'>'100 BROAD ROAD APT. 3'</span></span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">re.sub(r<span class='pystring'>'\bROAD$'</span>, <span class='pystring'>'RD.'</span>, s)</span> <a name="re.matching.2.4"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">'100 BROAD ROAD APT. 3'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">re.sub(r<span class='pystring'>'\bROAD\b'</span>, <span class='pystring'>'RD.'</span>, s)</span> <a name="re.matching.2.5"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">'100 BROAD RD. APT 3'</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.matching.2.2"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">What I <span class="emphasis"><em>really</em></span> wanted was to match <tt class="literal">'ROAD'</tt> when it was at the end of the string <span class="emphasis"><em>and</em></span> it was its own whole word, not a part of some larger word. To express this in a regular expression, you use <tt class="literal">\b</tt>, which means &#8220;<span class="quote">a word boundary must occur right here</span>&#8221;. In <span class="application">Python</span>, this is complicated by the fact that the <tt class="literal">'\'</tt> character in a string must itself be escaped. This is sometimes referred to as the backslash plague, and it is one reason
+ why regular expressions are easier in <span class="application">Perl</span> than in <span class="application">Python</span>. On the down side, <span class="application">Perl</span> mixes regular expressions with other syntax, so if you have a bug, it may be hard to tell whether it's a bug in syntax or
+ a bug in your regular expression.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.matching.2.3"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">To work around the backslash plague, you can use what is called a raw string, by prefixing the string with the letter <tt class="literal">r</tt>. This tells <span class="application">Python</span> that nothing in this string should be escaped; <tt class="literal">'\t'</tt> is a tab character, but <tt class="literal">r'\t'</tt> is really the backslash character <tt class="literal">\</tt> followed by the letter <tt class="literal">t</tt>. I recommend always using raw strings when dealing with regular expressions; otherwise, things get too confusing too quickly
+ (and regular expressions get confusing quickly enough all by themselves).
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.matching.2.4"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><span class="emphasis"><em>*sigh*</em></span> Unfortunately, I soon found more cases that contradicted my logic. In this case, the street address contained the word
+ <tt class="literal">'ROAD'</tt> as a whole word by itself, but it wasn't at the end, because the address had an apartment number after the street designation.
+ Because <tt class="literal">'ROAD'</tt> isn't at the very end of the string, it doesn't match, so the entire call to <tt class="function">re.sub</tt> ends up replacing nothing at all, and you get the original string back, which is not what you want.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.matching.2.5"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">To solve this problem, I removed the <tt class="literal">$</tt> character and added another <tt class="literal">\b</tt>. Now the regular expression reads &#8220;<span class="quote">match <tt class="literal">'ROAD'</tt> when it's a whole word by itself anywhere in the string,</span>&#8221; whether at the end, the beginning, or somewhere in the middle.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="index.html">&lt;&lt;&nbsp;Regular Expressions</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#re.intro" title="7.1.&nbsp;Diving In">1</a> <span class="divider">|</span> <span class="thispage">2</span> <span class="divider">|</span> <a href="roman_numerals.html" title="7.3.&nbsp;Case Study: Roman Numerals">3</a> <span class="divider">|</span> <a href="n_m_syntax.html" title="7.4.&nbsp;Using the {n,m} Syntax">4</a> <span class="divider">|</span> <a href="verbose.html" title="7.5.&nbsp;Verbose Regular Expressions">5</a> <span class="divider">|</span> <a href="phone_numbers.html" title="7.6.&nbsp;Case study: Parsing Phone Numbers">6</a> <span class="divider">|</span> <a href="summary.html" title="7.7.&nbsp;Summary">7</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="roman_numerals.html">Case Study: Roman Numerals&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/regular_expressions/summary.html b/help/diveintopython-5.4/html/regular_expressions/summary.html
new file mode 100644
index 0000000..5ce8379
--- /dev/null
+++ b/help/diveintopython-5.4/html/regular_expressions/summary.html
@@ -0,0 +1,116 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>7.7.&nbsp;Summary</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;7.&nbsp;Regular Expressions">
+ <link rel="previous" href="phone_numbers.html" title="7.6.&nbsp;Case study: Parsing Phone Numbers">
+ <link rel="next" href="../html_processing/index.html" title="Chapter&nbsp;8.&nbsp;HTML Processing">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Regular Expressions</a>&nbsp;&gt;&nbsp;<span class="thispage">Summary</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="phone_numbers.html" title="Prev: &#8220;Case study: Parsing Phone Numbers&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="../html_processing/index.html" title="Next: &#8220;HTML Processing&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="re.summary"></a>7.7.&nbsp;Summary
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>This is just the tiniest tip of the iceberg of what regular expressions can do. In other words, even though you're completely
+ overwhelmed by them now, believe me, you ain't seen nothing yet.
+ </p>
+ </div>
+ <p>You should now be familiar with the following techniques:</p>
+ <div class="itemizedlist">
+ <ul>
+ <li><tt class="literal">^</tt> matches the beginning of a string.
+ </li>
+ <li><tt class="literal">$</tt> matches the end of a string.
+ </li>
+ <li><tt class="literal">\b</tt> matches a word boundary.
+ </li>
+ <li><tt class="literal">\d</tt> matches any numeric digit.
+ </li>
+ <li><tt class="literal">\D</tt> matches any non-numeric character.
+ </li>
+ <li><tt class="literal">x?</tt> matches an optional <tt class="literal">x</tt> character (in other words, it matches an <tt class="literal">x</tt> zero or one times).
+ </li>
+ <li><tt class="literal">x*</tt> matches <tt class="literal">x</tt> zero or more times.
+ </li>
+ <li><tt class="literal">x+</tt> matches <tt class="literal">x</tt> one or more times.
+ </li>
+ <li><tt class="literal">x{n,m}</tt> matches an <tt class="literal">x</tt> character at least <tt class="literal">n</tt> times, but not more than <tt class="literal">m</tt> times.
+ </li>
+ <li><tt class="literal">(a|b|c)</tt> matches either <tt class="literal">a</tt> or <tt class="literal">b</tt> or <tt class="literal">c</tt>.
+ </li>
+ <li><tt class="literal">(x)</tt> in general is a <span class="emphasis"><em>remembered group</em></span>. You can get the value of what matched by using the <tt class="function">groups()</tt> method of the object returned by <tt class="function">re.search</tt>.
+ </li>
+ </ul>
+ </div>
+ <p>Regular expressions are extremely powerful, but they are not the correct solution for every problem. You should learn enough
+ about them to know when they are appropriate, when they will solve your problems, and when they will cause more problems than
+ they solve.
+ </p>
+ <div class="blockquote">
+ <table border="0" width="100%" cellspacing="0" cellpadding="0" class="blockquote" summary="Block quote">
+ <tr>
+ <td width="10%" valign="top">&nbsp;</td>
+ <td width="80%" valign="top">
+ <p>Some people, when confronted with a problem, think &#8220;<span class="quote">I know, I'll use regular expressions.</span>&#8221; Now they have two problems.
+ </p>
+ </td>
+ <td width="10%" valign="top">&nbsp;</td>
+ </tr>
+ <tr>
+ <td colspan="2" align="right" valign="top">--<span class="attribution">Jamie Zawinski, <a href="http://groups.google.com/groups?selm=33F0C496.370D7C45%40netscape.com">in comp.emacs.xemacs</a></span></td>
+ <td width="10%" valign="top">&nbsp;</td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="phone_numbers.html">&lt;&lt;&nbsp;Case study: Parsing Phone Numbers</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#re.intro" title="7.1.&nbsp;Diving In">1</a> <span class="divider">|</span> <a href="street_addresses.html" title="7.2.&nbsp;Case Study: Street Addresses">2</a> <span class="divider">|</span> <a href="roman_numerals.html" title="7.3.&nbsp;Case Study: Roman Numerals">3</a> <span class="divider">|</span> <a href="n_m_syntax.html" title="7.4.&nbsp;Using the {n,m} Syntax">4</a> <span class="divider">|</span> <a href="verbose.html" title="7.5.&nbsp;Verbose Regular Expressions">5</a> <span class="divider">|</span> <a href="phone_numbers.html" title="7.6.&nbsp;Case study: Parsing Phone Numbers">6</a> <span class="divider">|</span> <span class="thispage">7</span>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="../html_processing/index.html">HTML Processing&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/regular_expressions/verbose.html b/help/diveintopython-5.4/html/regular_expressions/verbose.html
new file mode 100644
index 0000000..6e5e5e4
--- /dev/null
+++ b/help/diveintopython-5.4/html/regular_expressions/verbose.html
@@ -0,0 +1,136 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>7.5.&nbsp;Verbose Regular Expressions</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;7.&nbsp;Regular Expressions">
+ <link rel="previous" href="n_m_syntax.html" title="7.4.&nbsp;Using the {n,m} Syntax">
+ <link rel="next" href="phone_numbers.html" title="7.6.&nbsp;Case study: Parsing Phone Numbers">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Regular Expressions</a>&nbsp;&gt;&nbsp;<span class="thispage">Verbose Regular Expressions</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="n_m_syntax.html" title="Prev: &#8220;Using the {n,m} Syntax&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="phone_numbers.html" title="Next: &#8220;Case study: Parsing Phone Numbers&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="re.verbose"></a>7.5.&nbsp;Verbose Regular Expressions
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>So far you've just been dealing with what I'll call &#8220;<span class="quote">compact</span>&#8221; regular expressions. As you've seen, they are difficult to read, and even if you figure out what one does, that's no guarantee
+ that you'll be able to understand it six months later. What you really need is inline documentation.
+ </p>
+ </div>
+ <p><span class="application">Python</span> allows you to do this with something called <span class="emphasis"><em>verbose regular expressions</em></span>. A verbose regular expression is different from a compact regular expression in two ways:
+ </p>
+ <div class="itemizedlist">
+ <ul>
+ <li>Whitespace is ignored. Spaces, tabs, and carriage returns are not matched as spaces, tabs, and carriage returns. They're
+ not matched at all. (If you want to match a space in a verbose regular expression, you'll need to escape it by putting a
+ backslash in front of it.)
+ </li>
+ <li>Comments are ignored. A comment in a verbose regular expression is just like a comment in Python code: it starts with a <tt class="literal">#</tt> character and goes until the end of the line. In this case it's a comment within a multi-line string instead of within your
+ source code, but it works the same way.
+ </li>
+ </ul>
+ </div>
+ <p>This will be more clear with an example. Let's revisit the compact regular expression you've been working with, and make
+ it a verbose regular expression. This example shows how.
+ </p>
+ <div class="example"><a name="d0e18777"></a><h3 class="title">Example&nbsp;7.9.&nbsp;Regular Expressions with Inline Comments</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">pattern = <span class='pystring'>"""
+ ^ # beginning of string
+ M{0,4} # thousands - 0 to 4 M's
+ (CM|CD|D?C{0,3}) # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 C's),
+ # or 500-800 (D, followed by 0 to 3 C's)
+ (XC|XL|L?X{0,3}) # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 X's),
+ # or 50-80 (L, followed by 0 to 3 X's)
+ (IX|IV|V?I{0,3}) # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 I's),
+ # or 5-8 (V, followed by 0 to 3 I's)
+ $ # end of string
+ """</span></span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">re.search(pattern, <span class='pystring'>'M'</span>, re.VERBOSE)</span> <a name="re.verbose.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">&lt;_sre.SRE_Match object at 0x008EEB48&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">re.search(pattern, <span class='pystring'>'MCMLXXXIX'</span>, re.VERBOSE)</span> <a name="re.verbose.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">&lt;_sre.SRE_Match object at 0x008EEB48&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">re.search(pattern, <span class='pystring'>'MMMMDCCCLXXXVIII'</span>, re.VERBOSE)</span> <a name="re.verbose.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">&lt;_sre.SRE_Match object at 0x008EEB48&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">re.search(pattern, <span class='pystring'>'M'</span>)</span> <a name="re.verbose.1.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.verbose.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The most important thing to remember when using verbose regular expressions is that you need to pass an extra argument when
+ working with them: <tt class="literal">re.VERBOSE</tt> is a constant defined in the <tt class="filename">re</tt> module that signals that the pattern should be treated as a verbose regular expression. As you can see, this pattern has
+ quite a bit of whitespace (all of which is ignored), and several comments (all of which are ignored). Once you ignore the
+ whitespace and the comments, this is exactly the same regular expression as you saw in <a href="n_m_syntax.html" title="7.4.&nbsp;Using the {n,m} Syntax">the previous section</a>, but it's a lot more readable.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.verbose.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This matches the start of the string, then one of a possible four <tt class="literal">M</tt>, then <tt class="literal">CM</tt>, then <tt class="literal">L</tt> and three of a possible three <tt class="literal">X</tt>, then <tt class="literal">IX</tt>, then the end of the string.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.verbose.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This matches the start of the string, then four of a possible four <tt class="literal">M</tt>, then <tt class="literal">D</tt> and three of a possible three <tt class="literal">C</tt>, then <tt class="literal">L</tt> and three of a possible three <tt class="literal">X</tt>, then <tt class="literal">V</tt> and three of a possible three <tt class="literal">I</tt>, then the end of the string.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#re.verbose.1.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This does not match. Why? Because it doesn't have the <tt class="literal">re.VERBOSE</tt> flag, so the <tt class="function">re.search</tt> function is treating the pattern as a compact regular expression, with significant whitespace and literal hash marks. <span class="application">Python</span> can't auto-detect whether a regular expression is verbose or not. <span class="application">Python</span> assumes every regular expression is compact unless you explicitly state that it is verbose.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="n_m_syntax.html">&lt;&lt;&nbsp;Using the {n,m} Syntax</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#re.intro" title="7.1.&nbsp;Diving In">1</a> <span class="divider">|</span> <a href="street_addresses.html" title="7.2.&nbsp;Case Study: Street Addresses">2</a> <span class="divider">|</span> <a href="roman_numerals.html" title="7.3.&nbsp;Case Study: Roman Numerals">3</a> <span class="divider">|</span> <a href="n_m_syntax.html" title="7.4.&nbsp;Using the {n,m} Syntax">4</a> <span class="divider">|</span> <span class="thispage">5</span> <span class="divider">|</span> <a href="phone_numbers.html" title="7.6.&nbsp;Case study: Parsing Phone Numbers">6</a> <span class="divider">|</span> <a href="summary.html" title="7.7.&nbsp;Summary">7</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="phone_numbers.html">Case study: Parsing Phone Numbers&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/scripts_and_streams/all_together.html b/help/diveintopython-5.4/html/scripts_and_streams/all_together.html
new file mode 100644
index 0000000..6fa4906
--- /dev/null
+++ b/help/diveintopython-5.4/html/scripts_and_streams/all_together.html
@@ -0,0 +1,142 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>10.7.&nbsp;Putting it all together</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;10.&nbsp;Scripts and Streams">
+ <link rel="previous" href="command_line_arguments.html" title="10.6.&nbsp;Handling command-line arguments">
+ <link rel="next" href="summary.html" title="10.8.&nbsp;Summary">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Scripts and Streams</a>&nbsp;&gt;&nbsp;<span class="thispage">Putting it all together</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="command_line_arguments.html" title="Prev: &#8220;Handling command-line arguments&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="summary.html" title="Next: &#8220;Summary&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="kgp.alltogether"></a>10.7.&nbsp;Putting it all together
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>You've covered a lot of ground. Let's step back and see how all the pieces fit together.</p>
+ </div>
+ <p>To start with, this is a script that <a href="command_line_arguments.html" title="10.6.&nbsp;Handling command-line arguments">takes its arguments on the command line</a>, using the <tt class="filename">getopt</tt> module.
+ </p>
+ <div class="informalexample"><pre class="programlisting"><span class='pykeyword'>
+def</span> main(argv):
+...
+ <span class='pykeyword'>try</span>:
+ opts, args = getopt.getopt(argv, <span class='pystring'>"hg:d"</span>, [<span class='pystring'>"help"</span>, <span class='pystring'>"grammar="</span>])
+ <span class='pykeyword'>except</span> getopt.GetoptError:
+...
+ <span class='pykeyword'>for</span> opt, arg <span class='pykeyword'>in</span> opts:
+...</pre></div>
+ <p>You create a new instance of the <tt class="classname">KantGenerator</tt> class, and pass it the grammar file and source that may or may not have been specified on the command line.
+ </p>
+ <div class="informalexample"><pre class="programlisting">
+ k = KantGenerator(grammar, source)</pre></div>
+ <p>The <tt class="classname">KantGenerator</tt> instance automatically loads the grammar, which is an <span class="acronym">XML</span> file. You use your custom <tt class="function">openAnything</tt> function to open the file (which <a href="index.html#kgp.openanything" title="10.1.&nbsp;Abstracting input sources">could be stored in a local file or a remote web server</a>), then use the built-in <tt class="filename">minidom</tt> parsing functions to <a href="../xml_processing/parsing_xml.html" title="9.3.&nbsp;Parsing XML">parse the <span class="acronym">XML</span> into a tree of <span class="application">Python</span> objects</a>.
+ </p>
+ <div class="informalexample"><pre class="programlisting">
+ <span class='pykeyword'>def</span><span class='pyclass'> _load</span>(self, source):
+ sock = toolbox.openAnything(source)
+ xmldoc = minidom.parse(sock).documentElement
+ sock.close()</pre></div>
+ <p>Oh, and along the way, you take advantage of your knowledge of the structure of the <span class="acronym">XML</span> document to <a href="caching.html" title="10.3.&nbsp;Caching node lookups">set up a little cache of references</a>, which are just elements in the <span class="acronym">XML</span> document.
+ </p>
+ <div class="informalexample"><pre class="programlisting">
+ <span class='pykeyword'>def</span><span class='pyclass'> loadGrammar</span>(self, grammar):
+ <span class='pykeyword'>for</span> ref <span class='pykeyword'>in</span> self.grammar.getElementsByTagName(<span class='pystring'>"ref"</span>):
+ self.refs[ref.attributes[<span class='pystring'>"id"</span>].value] = ref </pre></div>
+ <p>If you specified some source material on the command line, you use that; otherwise you rip through the grammar looking for
+ the "top-level" reference (that isn't referenced by anything else) and use that as a starting point.
+ </p>
+ <div class="informalexample"><pre class="programlisting">
+ <span class='pykeyword'>def</span><span class='pyclass'> getDefaultSource</span>(self):
+ xrefs = {}
+ <span class='pykeyword'>for</span> xref <span class='pykeyword'>in</span> self.grammar.getElementsByTagName(<span class='pystring'>"xref"</span>):
+ xrefs[xref.attributes[<span class='pystring'>"id"</span>].value] = 1
+ xrefs = xrefs.keys()
+ standaloneXrefs = [e <span class='pykeyword'>for</span> e <span class='pykeyword'>in</span> self.refs.keys() <span class='pykeyword'>if</span> e <span class='pykeyword'>not</span> <span class='pykeyword'>in</span> xrefs]
+ <span class='pykeyword'>return</span> <span class='pystring'>'&lt;xref id="%s"/&gt;'</span> % random.choice(standaloneXrefs)</pre></div>
+ <p>Now you rip through the source material. The source material is also <span class="acronym">XML</span>, and you parse it one node at a time. To keep the code separated and more maintainable, you use <a href="handlers_by_node_type.html" title="10.5.&nbsp;Creating separate handlers by node type">separate handlers for each node type</a>.
+ </p>
+ <div class="informalexample"><pre class="programlisting">
+ <span class='pykeyword'>def</span><span class='pyclass'> parse_Element</span>(self, node):
+ handlerMethod = getattr(self, <span class='pystring'>"do_%s"</span> % node.tagName)
+ handlerMethod(node)</pre></div>
+ <p>You bounce through the grammar, <a href="child_nodes.html" title="10.4.&nbsp;Finding direct children of a node">parsing all the children</a> of each <tt class="sgmltag-element">p</tt> element,
+ </p>
+ <div class="informalexample"><pre class="programlisting">
+ <span class='pykeyword'>def</span><span class='pyclass'> do_p</span>(self, node):
+...
+ <span class='pykeyword'>if</span> doit:
+ <span class='pykeyword'>for</span> child <span class='pykeyword'>in</span> node.childNodes: self.parse(child)</pre></div>
+ <p>replacing <tt class="sgmltag-element">choice</tt> elements with a random child,
+ </p>
+ <div class="informalexample"><pre class="programlisting">
+ <span class='pykeyword'>def</span><span class='pyclass'> do_choice</span>(self, node):
+ self.parse(self.randomChildElement(node))</pre></div>
+ <p>and replacing <tt class="sgmltag-element">xref</tt> elements with a random child of the corresponding <tt class="sgmltag-element">ref</tt> element, which you previously cached.
+ </p>
+ <div class="informalexample"><pre class="programlisting">
+ <span class='pykeyword'>def</span><span class='pyclass'> do_xref</span>(self, node):
+ id = node.attributes[<span class='pystring'>"id"</span>].value
+ self.parse(self.randomChildElement(self.refs[id]))</pre></div>
+ <p>Eventually, you parse your way down to plain text,</p>
+ <div class="informalexample"><pre class="programlisting">
+ <span class='pykeyword'>def</span><span class='pyclass'> parse_Text</span>(self, node):
+ text = node.data
+...
+ self.pieces.append(text)</pre></div>
+ <p>which you print out.</p>
+ <div class="informalexample"><pre class="programlisting"><span class='pykeyword'>
+def</span> main(argv):
+...
+ k = KantGenerator(grammar, source)
+ <span class='pykeyword'>print</span> k.output()</pre></div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="command_line_arguments.html">&lt;&lt;&nbsp;Handling command-line arguments</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#kgp.openanything" title="10.1.&nbsp;Abstracting input sources">1</a> <span class="divider">|</span> <a href="stdin_stdout_stderr.html" title="10.2.&nbsp;Standard input, output, and error">2</a> <span class="divider">|</span> <a href="caching.html" title="10.3.&nbsp;Caching node lookups">3</a> <span class="divider">|</span> <a href="child_nodes.html" title="10.4.&nbsp;Finding direct children of a node">4</a> <span class="divider">|</span> <a href="handlers_by_node_type.html" title="10.5.&nbsp;Creating separate handlers by node type">5</a> <span class="divider">|</span> <a href="command_line_arguments.html" title="10.6.&nbsp;Handling command-line arguments">6</a> <span class="divider">|</span> <span class="thispage">7</span> <span class="divider">|</span> <a href="summary.html" title="10.8.&nbsp;Summary">8</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="summary.html">Summary&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/scripts_and_streams/caching.html b/help/diveintopython-5.4/html/scripts_and_streams/caching.html
new file mode 100644
index 0000000..c1ff6ca
--- /dev/null
+++ b/help/diveintopython-5.4/html/scripts_and_streams/caching.html
@@ -0,0 +1,118 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>10.3.&nbsp;Caching node lookups</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;10.&nbsp;Scripts and Streams">
+ <link rel="previous" href="stdin_stdout_stderr.html" title="10.2.&nbsp;Standard input, output, and error">
+ <link rel="next" href="child_nodes.html" title="10.4.&nbsp;Finding direct children of a node">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Scripts and Streams</a>&nbsp;&gt;&nbsp;<span class="thispage">Caching node lookups</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="stdin_stdout_stderr.html" title="Prev: &#8220;Standard input, output, and error&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="child_nodes.html" title="Next: &#8220;Finding direct children of a node&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="kgp.cache"></a>10.3.&nbsp;Caching node lookups
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p><tt class="filename">kgp.py</tt> employs several tricks which may or may not be useful to you in your <span class="acronym">XML</span> processing. The first one takes advantage of the consistent structure of the input documents to build a cache of nodes.
+ </p>
+ </div>
+ <p>A grammar file defines a series of <tt class="sgmltag-element">ref</tt> elements. Each <tt class="sgmltag-element">ref</tt> contains one or more <tt class="sgmltag-element">p</tt> elements, which can contain a lot of different things, including <tt class="sgmltag-element">xref</tt>s. Whenever you encounter an <tt class="sgmltag-element">xref</tt>, you look for a corresponding <tt class="sgmltag-element">ref</tt> element with the same <tt class="sgmltag-element">id</tt> attribute, and choose one of the <tt class="sgmltag-element">ref</tt> element's children and parse it. (You'll see how this random choice is made in the next section.)
+ </p>
+ <p>This is how you build up the grammar: define <tt class="sgmltag-element">ref</tt> elements for the smallest pieces, then define <tt class="sgmltag-element">ref</tt> elements which "include" the first <tt class="sgmltag-element">ref</tt> elements by using <tt class="sgmltag-element">xref</tt>, and so forth. Then you parse the "largest" reference and follow each <tt class="sgmltag-element">xref</tt>, and eventually output real text. The text you output depends on the (random) decisions you make each time you fill in an
+ <tt class="sgmltag-element">xref</tt>, so the output is different each time.
+ </p>
+ <p>This is all very flexible, but there is one downside: performance. When you find an <tt class="sgmltag-element">xref</tt> and need to find the corresponding <tt class="sgmltag-element">ref</tt> element, you have a problem. The <tt class="sgmltag-element">xref</tt> has an <tt class="sgmltag-element">id</tt> attribute, and you want to find the <tt class="sgmltag-element">ref</tt> element that has that same <tt class="sgmltag-element">id</tt> attribute, but there is no easy way to do that. The slow way to do it would be to get the entire list of <tt class="sgmltag-element">ref</tt> elements each time, then manually loop through and look at each <tt class="sgmltag-element">id</tt> attribute. The fast way is to do that once and build a cache, in the form of a dictionary.
+ </p>
+ <div class="example"><a name="d0e26362"></a><h3 class="title">Example&nbsp;10.14.&nbsp;<tt class="function">loadGrammar</tt></h3><pre class="programlisting">
+ <span class='pykeyword'>def</span><span class='pyclass'> loadGrammar</span>(self, grammar):
+ self.grammar = self._load(grammar)
+ self.refs = {} <a name="kgp.cache.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ <span class='pykeyword'>for</span> ref <span class='pykeyword'>in</span> self.grammar.getElementsByTagName(<span class='pystring'>"ref"</span>): <a name="kgp.cache.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+ self.refs[ref.attributes[<span class='pystring'>"id"</span>].value] = ref <a name="kgp.cache.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"> <a name="kgp.cache.1.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.cache.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Start by creating an empty dictionary, <tt class="varname">self.refs</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.cache.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">As you saw in <a href="../xml_processing/searching.html" title="9.5.&nbsp;Searching for elements">Section&nbsp;9.5, &#8220;Searching for elements&#8221;</a>, <tt class="function">getElementsByTagName</tt> returns a list of all the elements of a particular name. You easily can get a list of all the <tt class="sgmltag-element">ref</tt> elements, then simply loop through that list.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.cache.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">As you saw in <a href="../xml_processing/attributes.html" title="9.6.&nbsp;Accessing element attributes">Section&nbsp;9.6, &#8220;Accessing element attributes&#8221;</a>, you can access individual attributes of an element by name, using standard dictionary syntax. So the keys of the <tt class="varname">self.refs</tt> dictionary will be the values of the <tt class="sgmltag-element">id</tt> attribute of each <tt class="sgmltag-element">ref</tt> element.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.cache.1.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The values of the <tt class="varname">self.refs</tt> dictionary will be the <tt class="sgmltag-element">ref</tt> elements themselves. As you saw in <a href="../xml_processing/parsing_xml.html" title="9.3.&nbsp;Parsing XML">Section&nbsp;9.3, &#8220;Parsing XML&#8221;</a>, each element, each node, each comment, each piece of text in a parsed <span class="acronym">XML</span> document is an object.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>Once you build this cache, whenever you come across an <tt class="sgmltag-element">xref</tt> and need to find the <tt class="sgmltag-element">ref</tt> element with the same <tt class="sgmltag-element">id</tt> attribute, you can simply look it up in <tt class="varname">self.refs</tt>.
+ </p>
+ <div class="example"><a name="d0e26435"></a><h3 class="title">Example&nbsp;10.15.&nbsp;Using the <tt class="sgmltag-element">ref</tt> element cache
+ </h3><pre class="programlisting">
+ <span class='pykeyword'>def</span><span class='pyclass'> do_xref</span>(self, node):
+ id = node.attributes[<span class='pystring'>"id"</span>].value
+ self.parse(self.randomChildElement(self.refs[id]))</pre></div>
+ <p>You'll explore the <tt class="function">randomChildElement</tt> function in the next section.
+ </p>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="stdin_stdout_stderr.html">&lt;&lt;&nbsp;Standard input, output, and error</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#kgp.openanything" title="10.1.&nbsp;Abstracting input sources">1</a> <span class="divider">|</span> <a href="stdin_stdout_stderr.html" title="10.2.&nbsp;Standard input, output, and error">2</a> <span class="divider">|</span> <span class="thispage">3</span> <span class="divider">|</span> <a href="child_nodes.html" title="10.4.&nbsp;Finding direct children of a node">4</a> <span class="divider">|</span> <a href="handlers_by_node_type.html" title="10.5.&nbsp;Creating separate handlers by node type">5</a> <span class="divider">|</span> <a href="command_line_arguments.html" title="10.6.&nbsp;Handling command-line arguments">6</a> <span class="divider">|</span> <a href="all_together.html" title="10.7.&nbsp;Putting it all together">7</a> <span class="divider">|</span> <a href="summary.html" title="10.8.&nbsp;Summary">8</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="child_nodes.html">Finding direct children of a node&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/scripts_and_streams/child_nodes.html b/help/diveintopython-5.4/html/scripts_and_streams/child_nodes.html
new file mode 100644
index 0000000..f54eb71
--- /dev/null
+++ b/help/diveintopython-5.4/html/scripts_and_streams/child_nodes.html
@@ -0,0 +1,106 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>10.4.&nbsp;Finding direct children of a node</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;10.&nbsp;Scripts and Streams">
+ <link rel="previous" href="caching.html" title="10.3.&nbsp;Caching node lookups">
+ <link rel="next" href="handlers_by_node_type.html" title="10.5.&nbsp;Creating separate handlers by node type">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Scripts and Streams</a>&nbsp;&gt;&nbsp;<span class="thispage">Finding direct children of a node</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="caching.html" title="Prev: &#8220;Caching node lookups&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="handlers_by_node_type.html" title="Next: &#8220;Creating separate handlers by node type&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="kgp.child"></a>10.4.&nbsp;Finding direct children of a node
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>Another useful techique when parsing <span class="acronym">XML</span> documents is finding all the direct child elements of a particular element. For instance, in the grammar files, a <tt class="sgmltag-element">ref</tt> element can have several <tt class="sgmltag-element">p</tt> elements, each of which can contain many things, including other <tt class="sgmltag-element">p</tt> elements. You want to find just the <tt class="sgmltag-element">p</tt> elements that are children of the <tt class="sgmltag-element">ref</tt>, not <tt class="sgmltag-element">p</tt> elements that are children of other <tt class="sgmltag-element">p</tt> elements.
+ </p>
+ </div>
+ <p>You might think you could simply use <tt class="function">getElementsByTagName</tt> for this, but you can't. <tt class="function">getElementsByTagName</tt> searches recursively and returns a single list for all the elements it finds. Since <tt class="sgmltag-element">p</tt> elements can contain other <tt class="sgmltag-element">p</tt> elements, you can't use <tt class="function">getElementsByTagName</tt>, because it would return nested <tt class="sgmltag-element">p</tt> elements that you don't want. To find only direct child elements, you'll need to do it yourself.
+ </p>
+ <div class="example"><a name="d0e26500"></a><h3 class="title">Example&nbsp;10.16.&nbsp;Finding direct child elements</h3><pre class="programlisting">
+ <span class='pykeyword'>def</span><span class='pyclass'> randomChildElement</span>(self, node):
+ choices = [e <span class='pykeyword'>for</span> e <span class='pykeyword'>in</span> node.childNodes
+ <span class='pykeyword'>if</span> e.nodeType == e.ELEMENT_NODE] <a name="kgp.child.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"> <a name="kgp.child.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"> <a name="kgp.child.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+ chosen = random.choice(choices) <a name="kgp.child.1.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+ <span class='pykeyword'>return</span> chosen </pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.child.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">As you saw in <a href="../xml_processing/parsing_xml.html#kgp.parse.gettingchildnodes.example" title="Example&nbsp;9.9.&nbsp;Getting child nodes">Example&nbsp;9.9, &#8220;Getting child nodes&#8221;</a>, the <tt class="function">childNodes</tt> attribute returns a list of all the child nodes of an element.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.child.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">However, as you saw in <a href="../xml_processing/parsing_xml.html#kgp.parse.childnodescanbetext.example" title="Example&nbsp;9.11.&nbsp;Child nodes can be text">Example&nbsp;9.11, &#8220;Child nodes can be text&#8221;</a>, the list returned by <tt class="function">childNodes</tt> contains all different types of nodes, including text nodes. That's not what you're looking for here. You only want the
+ children that are elements.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.child.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Each node has a <tt class="varname">nodeType</tt> attribute, which can be <tt class="literal">ELEMENT_NODE</tt>, <tt class="literal">TEXT_NODE</tt>, <tt class="literal">COMMENT_NODE</tt>, or any number of other values. The complete list of possible values is in the <tt class="filename">__init__.py</tt> file in the <tt class="classname">xml.dom</tt> package. (See <a href="../xml_processing/packages.html" title="9.2.&nbsp;Packages">Section&nbsp;9.2, &#8220;Packages&#8221;</a> for more on packages.) But you're just interested in nodes that are elements, so you can filter the list to only include
+ those nodes whose <tt class="varname">nodeType</tt> is <tt class="literal">ELEMENT_NODE</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.child.1.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Once you have a list of actual elements, choosing a random one is easy. <span class="application">Python</span> comes with a module called <tt class="filename">random</tt> which includes several useful functions. The <tt class="function">random.choice</tt> function takes a list of any number of items and returns a random item. For example, if the <tt class="sgmltag-element">ref</tt> elements contains several <tt class="sgmltag-element">p</tt> elements, then <tt class="varname">choices</tt> would be a list of <tt class="sgmltag-element">p</tt> elements, and <tt class="varname">chosen</tt> would end up being assigned exactly one of them, selected at random.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="caching.html">&lt;&lt;&nbsp;Caching node lookups</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#kgp.openanything" title="10.1.&nbsp;Abstracting input sources">1</a> <span class="divider">|</span> <a href="stdin_stdout_stderr.html" title="10.2.&nbsp;Standard input, output, and error">2</a> <span class="divider">|</span> <a href="caching.html" title="10.3.&nbsp;Caching node lookups">3</a> <span class="divider">|</span> <span class="thispage">4</span> <span class="divider">|</span> <a href="handlers_by_node_type.html" title="10.5.&nbsp;Creating separate handlers by node type">5</a> <span class="divider">|</span> <a href="command_line_arguments.html" title="10.6.&nbsp;Handling command-line arguments">6</a> <span class="divider">|</span> <a href="all_together.html" title="10.7.&nbsp;Putting it all together">7</a> <span class="divider">|</span> <a href="summary.html" title="10.8.&nbsp;Summary">8</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="handlers_by_node_type.html">Creating separate handlers by node type&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/scripts_and_streams/command_line_arguments.html b/help/diveintopython-5.4/html/scripts_and_streams/command_line_arguments.html
new file mode 100644
index 0000000..1d9a2e9
--- /dev/null
+++ b/help/diveintopython-5.4/html/scripts_and_streams/command_line_arguments.html
@@ -0,0 +1,293 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>10.6.&nbsp;Handling command-line arguments</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;10.&nbsp;Scripts and Streams">
+ <link rel="previous" href="handlers_by_node_type.html" title="10.5.&nbsp;Creating separate handlers by node type">
+ <link rel="next" href="all_together.html" title="10.7.&nbsp;Putting it all together">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Scripts and Streams</a>&nbsp;&gt;&nbsp;<span class="thispage">Handling command-line arguments</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="handlers_by_node_type.html" title="Prev: &#8220;Creating separate handlers by node type&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="all_together.html" title="Next: &#8220;Putting it all together&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="kgp.commandline"></a>10.6.&nbsp;Handling command-line arguments
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p><span class="application">Python</span> fully supports creating programs that can be run on the command line, complete with command-line arguments and either short-
+ or long-style flags to specify various options. None of this is <span class="acronym">XML</span>-specific, but this script makes good use of command-line processing, so it seemed like a good time to mention it.
+ </p>
+ </div>
+ <p>It's difficult to talk about command-line processing without understanding how command-line arguments are exposed to your
+ <span class="application">Python</span> program, so let's write a simple program to see them.
+ </p>
+ <div class="example"><a name="d0e26871"></a><h3 class="title">Example&nbsp;10.20.&nbsp;Introducing <tt class="varname">sys.argv</tt></h3>
+ <p>If you have not already done so, you can <a href="http://diveintopython.org/download/diveintopython-examples-5.4.zip" title="Download example scripts">download this and other examples</a> used in this book.
+ </p><pre class="programlisting">
+<span class='pycomment'>#argecho.py</span>
+<span class='pykeyword'>import</span> sys
+
+<span class='pykeyword'>for</span> arg <span class='pykeyword'>in</span> sys.argv: <a name="kgp.commandline.0.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ <span class='pykeyword'>print</span> arg</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.commandline.0.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Each command-line argument passed to the program will be in <tt class="varname">sys.argv</tt>, which is just a list. Here you are printing each argument on a separate line.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="d0e26892"></a><h3 class="title">Example&nbsp;10.21.&nbsp;The contents of <tt class="varname">sys.argv</tt></h3><pre class="screen">
+<tt class="prompt">[you@localhost py]$ </tt><span class="userinput">python argecho.py</span> <a name="kgp.commandline.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">argecho.py</span>
+<tt class="prompt">[you@localhost py]$ </tt><span class="userinput">python argecho.py abc def</span> <a name="kgp.commandline.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">argecho.py
+abc
+def</span>
+<tt class="prompt">[you@localhost py]$ </tt><span class="userinput">python argecho.py --help</span> <a name="kgp.commandline.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">argecho.py
+--help</span>
+<tt class="prompt">[you@localhost py]$ </tt><span class="userinput">python argecho.py -m kant.xml</span> <a name="kgp.commandline.1.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">argecho.py
+-m
+kant.xml</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.commandline.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The first thing to know about <tt class="varname">sys.argv</tt> is that it contains the name of the script you're calling. You will actually use this knowledge to your advantage later,
+ in <a href="../functional_programming/index.html" title="Chapter&nbsp;16.&nbsp;Functional Programming">Chapter&nbsp;16, <i>Functional Programming</i></a>. Don't worry about it for now.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.commandline.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Command-line arguments are separated by spaces, and each shows up as a separate element in the <tt class="varname">sys.argv</tt> list.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.commandline.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Command-line flags, like <tt class="literal">--help</tt>, also show up as their own element in the <tt class="varname">sys.argv</tt> list.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.commandline.1.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">To make things even more interesting, some command-line flags themselves take arguments. For instance, here you have a flag
+ (<tt class="literal">-m</tt>) which takes an argument (<tt class="literal">kant.xml</tt>). Both the flag itself and the flag's argument are simply sequential elements in the <tt class="varname">sys.argv</tt> list. No attempt is made to associate one with the other; all you get is a list.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>So as you can see, you certainly have all the information passed on the command line, but then again, it doesn't look like
+ it's going to be all that easy to actually use it. For simple programs that only take a single argument and have no flags,
+ you can simply use <tt class="literal">sys.argv[1]</tt> to access the argument. There's no shame in this; I do it all the time. For more complex programs, you need the <tt class="filename">getopt</tt> module.
+ </p>
+ <div class="example"><a name="d0e26982"></a><h3 class="title">Example&nbsp;10.22.&nbsp;Introducing <tt class="filename">getopt</tt></h3><pre class="programlisting"><span class='pykeyword'>
+def</span> main(argv):
+ grammar = <span class='pystring'>"kant.xml"</span> <a name="kgp.commandline.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ <span class='pykeyword'>try</span>:
+ opts, args = getopt.getopt(argv, <span class='pystring'>"hg:d"</span>, [<span class='pystring'>"help"</span>, <span class='pystring'>"grammar="</span>]) <a name="kgp.commandline.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+ <span class='pykeyword'>except</span> getopt.GetoptError: <a name="kgp.commandline.2.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+ usage() <a name="kgp.commandline.2.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+ sys.exit(2)
+
+...
+
+<span class='pykeyword'>if</span> __name__ == <span class='pystring'>"__main__"</span>:
+ main(sys.argv[1:])</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.commandline.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">First off, look at the bottom of the example and notice that you're calling the <tt class="function">main</tt> function with <tt class="literal">sys.argv[1:]</tt>. Remember, <tt class="literal">sys.argv[0]</tt> is the name of the script that you're running; you don't care about that for command-line processing, so you chop it off
+ and pass the rest of the list.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.commandline.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This is where all the interesting processing happens. The <tt class="function">getopt</tt> function of the <tt class="filename">getopt</tt> module takes three parameters: the argument list (which you got from <tt class="literal">sys.argv[1:]</tt>), a string containing all the possible single-character command-line flags that this program accepts, and a list of longer
+ command-line flags that are equivalent to the single-character versions. This is quite confusing at first glance, and is
+ explained in more detail below.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.commandline.2.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">If anything goes wrong trying to parse these command-line flags, <tt class="filename">getopt</tt> will raise an exception, which you catch. You told <tt class="filename">getopt</tt> all the flags you understand, so this probably means that the end user passed some command-line flag that you don't understand.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.commandline.2.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">As is standard practice in the <span class="acronym">UNIX</span> world, when the script is passed flags it doesn't understand, you print out a summary of proper usage and exit gracefully.
+ Note that I haven't shown the <tt class="function">usage</tt> function here. You would still need to code that somewhere and have it print out the appropriate summary; it's not automatic.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>So what are all those parameters you pass to the <tt class="function">getopt</tt> function? Well, the first one is simply the raw list of command-line flags and arguments (not including the first element,
+ the script name, which you already chopped off before calling the <tt class="function">main</tt> function). The second is the list of short command-line flags that the script accepts.
+ </p>
+ <div class="variablelist">
+ <h3 class="title"><tt class="literal">"hg:d"</tt></h3>
+ <dl>
+ <dt><span class="term"><tt class="literal">-h</tt></span></dt>
+ <dd>print usage summary</dd>
+ <dt><span class="term"><tt class="literal">-g ...</tt></span></dt>
+ <dd>use specified grammar file or URL</dd>
+ <dt><span class="term"><tt class="literal">-d</tt></span></dt>
+ <dd>show debugging information while parsing</dd>
+ </dl>
+ </div>
+ <p>The first and third flags are simply standalone flags; you specify them or you don't, and they do things (print help) or change
+ state (turn on debugging). However, the second flag (<tt class="literal">-g</tt>) <span class="emphasis"><em>must</em></span> be followed by an argument, which is the name of the grammar file to read from. In fact it can be a filename or a web address,
+ and you don't know which yet (you'll figure it out later), but you know it has to be <span class="emphasis"><em>something</em></span>. So you tell <tt class="filename">getopt</tt> this by putting a colon after the <tt class="literal">g</tt> in that second parameter to the <tt class="function">getopt</tt> function.
+ </p>
+ <p>To further complicate things, the script accepts either short flags (like <tt class="literal">-h</tt>) or long flags (like <tt class="literal">--help</tt>), and you want them to do the same thing. This is what the third parameter to <tt class="function">getopt</tt> is for, to specify a list of the long flags that correspond to the short flags you specified in the second parameter.
+ </p>
+ <div class="variablelist">
+ <h3 class="title"><tt class="literal">["help", "grammar="]</tt></h3>
+ <dl>
+ <dt><span class="term"><tt class="literal">--help</tt></span></dt>
+ <dd>print usage summary</dd>
+ <dt><span class="term"><tt class="literal">--grammar ...</tt></span></dt>
+ <dd>use specified grammar file or URL</dd>
+ </dl>
+ </div>
+ <p>Three things of note here:</p>
+ <div class="orderedlist">
+ <ol type="1">
+ <li>All long flags are preceded by two dashes on the command line, but you don't include those dashes when calling <tt class="function">getopt</tt>. They are understood.
+ </li>
+ <li>The <tt class="literal">--grammar</tt> flag must always be followed by an additional argument, just like the <tt class="literal">-g</tt> flag. This is notated by an equals sign, <tt class="literal">"grammar="</tt>.
+ </li>
+ <li>The list of long flags is shorter than the list of short flags, because the <tt class="literal">-d</tt> flag does not have a corresponding long version. This is fine; only <tt class="literal">-d</tt> will turn on debugging. But the order of short and long flags needs to be the same, so you'll need to specify all the short
+ flags that <span class="emphasis"><em>do</em></span> have corresponding long flags first, then all the rest of the short flags.
+ </li>
+ </ol>
+ </div>
+ <p>Confused yet? Let's look at the actual code and see if it makes sense in context.</p>
+ <div class="example"><a name="d0e27157"></a><h3 class="title">Example&nbsp;10.23.&nbsp;Handling command-line arguments in <tt class="filename">kgp.py</tt></h3><pre class="programlisting"><span class='pykeyword'>
+def</span> main(argv): <a name="kgp.commandline.3.0"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ grammar = <span class='pystring'>"kant.xml"</span>
+ <span class='pykeyword'>try</span>:
+ opts, args = getopt.getopt(argv, <span class='pystring'>"hg:d"</span>, [<span class='pystring'>"help"</span>, <span class='pystring'>"grammar="</span>])
+ <span class='pykeyword'>except</span> getopt.GetoptError:
+ usage()
+ sys.exit(2)
+ <span class='pykeyword'>for</span> opt, arg <span class='pykeyword'>in</span> opts: <a name="kgp.commandline.3.1"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+ <span class='pykeyword'>if</span> opt <span class='pykeyword'>in</span> (<span class='pystring'>"-h"</span>, <span class='pystring'>"--help"</span>): <a name="kgp.commandline.3.2"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+ usage()
+ sys.exit()
+ <span class='pykeyword'>elif</span> opt == <span class='pystring'>'-d'</span>: <a name="kgp.commandline.3.3"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+ <span class='pykeyword'>global</span> _debug
+ _debug = 1
+ <span class='pykeyword'>elif</span> opt <span class='pykeyword'>in</span> (<span class='pystring'>"-g"</span>, <span class='pystring'>"--grammar"</span>): <a name="kgp.commandline.3.4"></a><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12">
+ grammar = arg
+
+ source = <span class='pystring'>""</span>.join(args) <a name="kgp.commandline.3.5"></a><img src="../images/callouts/6.png" alt="6" border="0" width="12" height="12">
+
+ k = KantGenerator(grammar, source)
+ <span class='pykeyword'>print</span> k.output()</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.commandline.3.0"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="varname">grammar</tt> variable will keep track of the grammar file you're using. You initialize it here in case it's not specified on the command
+ line (using either the <tt class="literal">-g</tt> or the <tt class="literal">--grammar</tt> flag).
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.commandline.3.1"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="varname">opts</tt> variable that you get back from <tt class="function">getopt</tt> contains a list of tuples: <tt class="varname">flag</tt> and <tt class="varname">argument</tt>. If the flag doesn't take an argument, then <tt class="varname">arg</tt> will simply be <tt class="literal">None</tt>. This makes it easier to loop through the flags.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.commandline.3.2"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">getopt</tt> validates that the command-line flags are acceptable, but it doesn't do any sort of conversion between short and long flags.
+ If you specify the <tt class="literal">-h</tt> flag, <tt class="varname">opt</tt> will contain <tt class="literal">"-h"</tt>; if you specify the <tt class="literal">--help</tt> flag, <tt class="varname">opt</tt> will contain <tt class="literal">"--help"</tt>. So you need to check for both.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.commandline.3.3"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Remember, the <tt class="literal">-d</tt> flag didn't have a corresponding long flag, so you only need to check for the short form. If you find it, you set a global
+ variable that you'll refer to later to print out debugging information. (I used this during the development of the script.
+ What, you thought all these examples worked on the first try?)
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.commandline.3.4"><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">If you find a grammar file, either with a <tt class="literal">-g</tt> flag or a <tt class="literal">--grammar</tt> flag, you save the argument that followed it (stored in <tt class="varname">arg</tt>) into the <tt class="varname">grammar</tt> variable, overwriting the default that you initialized at the top of the <tt class="function">main</tt> function.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.commandline.3.5"><img src="../images/callouts/6.png" alt="6" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">That's it. You've looped through and dealt with all the command-line flags. That means that anything left must be command-line
+ arguments. These come back from the <tt class="function">getopt</tt> function in the <tt class="varname">args</tt> variable. In this case, you're treating them as source material for the parser. If there are no command-line arguments
+ specified, <tt class="varname">args</tt> will be an empty list, and <tt class="varname">source</tt> will end up as the empty string.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="handlers_by_node_type.html">&lt;&lt;&nbsp;Creating separate handlers by node type</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#kgp.openanything" title="10.1.&nbsp;Abstracting input sources">1</a> <span class="divider">|</span> <a href="stdin_stdout_stderr.html" title="10.2.&nbsp;Standard input, output, and error">2</a> <span class="divider">|</span> <a href="caching.html" title="10.3.&nbsp;Caching node lookups">3</a> <span class="divider">|</span> <a href="child_nodes.html" title="10.4.&nbsp;Finding direct children of a node">4</a> <span class="divider">|</span> <a href="handlers_by_node_type.html" title="10.5.&nbsp;Creating separate handlers by node type">5</a> <span class="divider">|</span> <span class="thispage">6</span> <span class="divider">|</span> <a href="all_together.html" title="10.7.&nbsp;Putting it all together">7</a> <span class="divider">|</span> <a href="summary.html" title="10.8.&nbsp;Summary">8</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="all_together.html">Putting it all together&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/scripts_and_streams/handlers_by_node_type.html b/help/diveintopython-5.4/html/scripts_and_streams/handlers_by_node_type.html
new file mode 100644
index 0000000..9c715de
--- /dev/null
+++ b/help/diveintopython-5.4/html/scripts_and_streams/handlers_by_node_type.html
@@ -0,0 +1,187 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>10.5.&nbsp;Creating separate handlers by node type</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;10.&nbsp;Scripts and Streams">
+ <link rel="previous" href="child_nodes.html" title="10.4.&nbsp;Finding direct children of a node">
+ <link rel="next" href="command_line_arguments.html" title="10.6.&nbsp;Handling command-line arguments">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Scripts and Streams</a>&nbsp;&gt;&nbsp;<span class="thispage">Creating separate handlers by node type</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="child_nodes.html" title="Prev: &#8220;Finding direct children of a node&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="command_line_arguments.html" title="Next: &#8220;Handling command-line arguments&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="kgp.handler"></a>10.5.&nbsp;Creating separate handlers by node type
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>The third useful <span class="acronym">XML</span> processing tip involves separating your code into logical functions, based on node types and element names. Parsed <span class="acronym">XML</span> documents are made up of various types of nodes, each represented by a <span class="application">Python</span> object. The root level of the document itself is represented by a <tt class="classname">Document</tt> object. The <tt class="classname">Document</tt> then contains one or more <tt class="classname">Element</tt> objects (for actual <span class="acronym">XML</span> tags), each of which may contain other <tt class="classname">Element</tt> objects, <tt class="classname">Text</tt> objects (for bits of text), or <tt class="classname">Comment</tt> objects (for embedded comments). <span class="application">Python</span> makes it easy to write a dispatcher to separate the logic for each node type.
+ </p>
+ </div>
+ <div class="example"><a name="d0e26627"></a><h3 class="title">Example&nbsp;10.17.&nbsp;Class names of parsed <span class="acronym">XML</span> objects
+ </h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>from</span> xml.dom <span class='pykeyword'>import</span> minidom</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">xmldoc = minidom.parse(<span class='pystring'>'kant.xml'</span>)</span> <a name="kgp.handler.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">xmldoc</span>
+<span class="computeroutput">&lt;xml.dom.minidom.Document instance at 0x01359DE8&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">xmldoc.__class__</span> <a name="kgp.handler.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">&lt;class xml.dom.minidom.Document at 0x01105D40&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">xmldoc.__class__.__name__</span> <a name="kgp.handler.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">'Document'</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.handler.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Assume for a moment that <tt class="filename">kant.xml</tt> is in the current directory.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.handler.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">As you saw in <a href="../xml_processing/packages.html" title="9.2.&nbsp;Packages">Section&nbsp;9.2, &#8220;Packages&#8221;</a>, the object returned by parsing an <span class="acronym">XML</span> document is a <tt class="classname">Document</tt> object, as defined in the <tt class="filename">minidom.py</tt> in the <tt class="filename">xml.dom</tt> package. As you saw in <a href="../object_oriented_framework/instantiating_classes.html" title="5.4.&nbsp;Instantiating Classes">Section&nbsp;5.4, &#8220;Instantiating Classes&#8221;</a>, <tt class="literal">__class__</tt> is built-in attribute of every <span class="application">Python</span> object.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.handler.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Furthermore, <tt class="literal">__name__</tt> is a built-in attribute of every <span class="application">Python</span> class, and it is a string. This string is not mysterious; it's the same as the class name you type when you define a class
+ yourself. (See <a href="../object_oriented_framework/defining_classes.html" title="5.3.&nbsp;Defining Classes">Section&nbsp;5.3, &#8220;Defining Classes&#8221;</a>.)
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>Fine, so now you can get the class name of any particular <span class="acronym">XML</span> node (since each <span class="acronym">XML</span> node is represented as a <span class="application">Python</span> object). How can you use this to your advantage to separate the logic of parsing each node type? The answer is <tt class="function">getattr</tt>, which you first saw in <a href="../power_of_introspection/getattr.html" title="4.4.&nbsp;Getting Object References With getattr">Section&nbsp;4.4, &#8220;Getting Object References With getattr&#8221;</a>.
+ </p>
+ <div class="example"><a name="d0e26733"></a><h3 class="title">Example&nbsp;10.18.&nbsp;<tt class="function">parse</tt>, a generic <span class="acronym">XML</span> node dispatcher
+ </h3><pre class="programlisting">
+ <span class='pykeyword'>def</span><span class='pyclass'> parse</span>(self, node):
+ parseMethod = getattr(self, <span class='pystring'>"parse_%s"</span> % node.__class__.__name__) <a name="kgp.handler.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"> <a name="kgp.handler.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+ parseMethod(node) <a name="kgp.handler.2.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.handler.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">First off, notice that you're constructing a larger string based on the class name of the node you were passed (in the <tt class="varname">node</tt> argument). So if you're passed a <tt class="classname">Document</tt> node, you're constructing the string <tt class="literal">'parse_Document'</tt>, and so forth.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.handler.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Now you can treat that string as a function name, and get a reference to the function itself using <tt class="function">getattr</tt></td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.handler.2.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Finally, you can call that function and pass the node itself as an argument. The next example shows the definitions of each
+ of these functions.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="d0e26769"></a><h3 class="title">Example&nbsp;10.19.&nbsp;Functions called by the <tt class="function">parse</tt> dispatcher
+ </h3><pre class="programlisting">
+ <span class='pykeyword'>def</span><span class='pyclass'> parse_Document</span>(self, node): <a name="kgp.handler.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ self.parse(node.documentElement)
+
+ <span class='pykeyword'>def</span><span class='pyclass'> parse_Text</span>(self, node): <a name="kgp.handler.3.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+ text = node.data
+ <span class='pykeyword'>if</span> self.capitalizeNextWord:
+ self.pieces.append(text[0].upper())
+ self.pieces.append(text[1:])
+ self.capitalizeNextWord = 0
+ <span class='pykeyword'>else</span>:
+ self.pieces.append(text)
+
+ <span class='pykeyword'>def</span><span class='pyclass'> parse_Comment</span>(self, node): <a name="kgp.handler.3.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+ <span class='pykeyword'>pass</span>
+
+ <span class='pykeyword'>def</span><span class='pyclass'> parse_Element</span>(self, node): <a name="kgp.handler.3.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+ handlerMethod = getattr(self, <span class='pystring'>"do_%s"</span> % node.tagName)
+ handlerMethod(node)</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.handler.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">parse_Document</tt> is only ever called once, since there is only one <tt class="classname">Document</tt> node in an <span class="acronym">XML</span> document, and only one <tt class="classname">Document</tt> object in the parsed <span class="acronym">XML</span> representation. It simply turns around and parses the root element of the grammar file.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.handler.3.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">parse_Text</tt> is called on nodes that represent bits of text. The function itself does some special processing to handle automatic capitalization
+ of the first word of a sentence, but otherwise simply appends the represented text to a list.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.handler.3.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">parse_Comment</tt> is just a <tt class="literal">pass</tt>, since you don't care about embedded comments in the grammar files. Note, however, that you still need to define the function
+ and explicitly make it do nothing. If the function did not exist, the generic <tt class="function">parse</tt> function would fail as soon as it stumbled on a comment, because it would try to find the non-existent <tt class="function">parse_Comment</tt> function. Defining a separate function for every node type, even ones you don't use, allows the generic <tt class="function">parse</tt> function to stay simple and dumb.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.handler.3.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="function">parse_Element</tt> method is actually itself a dispatcher, based on the name of the element's tag. The basic idea is the same: take what distinguishes
+ elements from each other (their tag names) and dispatch to a separate function for each of them. You construct a string like
+ <tt class="literal">'do_xref'</tt> (for an <tt class="sgmltag-element">&lt;xref&gt;</tt> tag), find a function of that name, and call it. And so forth for each of the other tag names that might be found in the
+ course of parsing a grammar file (<tt class="sgmltag-element">&lt;p&gt;</tt> tags, <tt class="sgmltag-element">&lt;choice&gt;</tt> tags).
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>In this example, the dispatch functions <tt class="function">parse</tt> and <tt class="function">parse_Element</tt> simply find other methods in the same class. If your processing is very complex (or you have many different tag names),
+ you could break up your code into separate modules, and use dynamic importing to import each module and call whatever functions
+ you needed. Dynamic importing will be discussed in <a href="../functional_programming/index.html" title="Chapter&nbsp;16.&nbsp;Functional Programming">Chapter&nbsp;16, <i>Functional Programming</i></a>.
+ </p>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="child_nodes.html">&lt;&lt;&nbsp;Finding direct children of a node</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#kgp.openanything" title="10.1.&nbsp;Abstracting input sources">1</a> <span class="divider">|</span> <a href="stdin_stdout_stderr.html" title="10.2.&nbsp;Standard input, output, and error">2</a> <span class="divider">|</span> <a href="caching.html" title="10.3.&nbsp;Caching node lookups">3</a> <span class="divider">|</span> <a href="child_nodes.html" title="10.4.&nbsp;Finding direct children of a node">4</a> <span class="divider">|</span> <span class="thispage">5</span> <span class="divider">|</span> <a href="command_line_arguments.html" title="10.6.&nbsp;Handling command-line arguments">6</a> <span class="divider">|</span> <a href="all_together.html" title="10.7.&nbsp;Putting it all together">7</a> <span class="divider">|</span> <a href="summary.html" title="10.8.&nbsp;Summary">8</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="command_line_arguments.html">Handling command-line arguments&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/scripts_and_streams/index.html b/help/diveintopython-5.4/html/scripts_and_streams/index.html
new file mode 100644
index 0000000..db45766
--- /dev/null
+++ b/help/diveintopython-5.4/html/scripts_and_streams/index.html
@@ -0,0 +1,366 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>Chapter&nbsp;10.&nbsp;Scripts and Streams</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="../toc/index.html" title="Dive Into Python">
+ <link rel="previous" href="../xml_processing/summary.html" title="9.7.&nbsp;Segue">
+ <link rel="next" href="stdin_stdout_stderr.html" title="10.2.&nbsp;Standard input, output, and error">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<span class="thispage">Scripts and Streams</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="../xml_processing/summary.html" title="Prev: &#8220;Segue&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="stdin_stdout_stderr.html" title="Next: &#8220;Standard input, output, and error&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="chapter" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="streams"></a>Chapter&nbsp;10.&nbsp;Scripts and Streams
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="toc">
+ <ul>
+ <li><span class="section"><a href="index.html#kgp.openanything">10.1. Abstracting input sources</a></span></li>
+ <li><span class="section"><a href="stdin_stdout_stderr.html">10.2. Standard input, output, and error</a></span></li>
+ <li><span class="section"><a href="caching.html">10.3. Caching node lookups</a></span></li>
+ <li><span class="section"><a href="child_nodes.html">10.4. Finding direct children of a node</a></span></li>
+ <li><span class="section"><a href="handlers_by_node_type.html">10.5. Creating separate handlers by node type</a></span></li>
+ <li><span class="section"><a href="command_line_arguments.html">10.6. Handling command-line arguments</a></span></li>
+ <li><span class="section"><a href="all_together.html">10.7. Putting it all together</a></span></li>
+ <li><span class="section"><a href="summary.html">10.8. Summary</a></span></li>
+ </ul>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="kgp.openanything"></a>10.1.&nbsp;Abstracting input sources
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>One of <span class="application">Python</span>'s greatest strengths is its dynamic binding, and one powerful use of dynamic binding is the <span class="emphasis"><em>file-like object</em></span>.
+ </p>
+ </div>
+ <p>Many functions which require an input source could simply take a filename, go open the file for reading, read it, and close
+ it when they're done. But they don't. Instead, they take a <span class="emphasis"><em>file-like object</em></span>.
+ </p>
+ <p>In the simplest case, a <span class="emphasis"><em>file-like object</em></span> is any object with a <tt class="function">read</tt> method with an optional <tt class="varname">size</tt> parameter, which returns a string. When called with no <tt class="varname">size</tt> parameter, it reads everything there is to read from the input source and returns all the data as a single string. When
+ called with a <tt class="varname">size</tt> parameter, it reads that much from the input source and returns that much data; when called again, it picks up where it left
+ off and returns the next chunk of data.
+ </p>
+ <p>This is how <a href="../file_handling/file_objects.html" title="6.2.&nbsp;Working with File Objects">reading from real files</a> works; the difference is that you're not limiting yourself to real files. The input source could be anything: a file on
+ disk, a web page, even a hard-coded string. As long as you pass a file-like object to the function, and the function simply
+ calls the object's <tt class="function">read</tt> method, the function can handle any kind of input source without specific code to handle each kind.
+ </p>
+ <p>In case you were wondering how this relates to <span class="acronym">XML</span> processing, <tt class="function">minidom.parse</tt> is one such function which can take a file-like object.
+ </p>
+ <div class="example"><a name="d0e25118"></a><h3 class="title">Example&nbsp;10.1.&nbsp;Parsing <span class="acronym">XML</span> from a file
+ </h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>from</span> xml.dom <span class='pykeyword'>import</span> minidom</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">fsock = open(<span class='pystring'>'binary.xml'</span>)</span> <a name="kgp.openanything.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">xmldoc = minidom.parse(fsock)</span> <a name="kgp.openanything.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">fsock.close()</span> <a name="kgp.openanything.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> xmldoc.toxml()</span> <a name="kgp.openanything.1.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">&lt;?xml version="1.0" ?&gt;
+&lt;grammar&gt;
+&lt;ref id="bit"&gt;
+ &lt;p&gt;0&lt;/p&gt;
+ &lt;p&gt;1&lt;/p&gt;
+&lt;/ref&gt;
+&lt;ref id="byte"&gt;
+ &lt;p&gt;&lt;xref id="bit"/&gt;&lt;xref id="bit"/&gt;&lt;xref id="bit"/&gt;&lt;xref id="bit"/&gt;\
+&lt;xref id="bit"/&gt;&lt;xref id="bit"/&gt;&lt;xref id="bit"/&gt;&lt;xref id="bit"/&gt;&lt;/p&gt;
+&lt;/ref&gt;
+&lt;/grammar&gt;</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.openanything.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">First, you open the file on disk. This gives you a <a href="../file_handling/file_objects.html" title="6.2.&nbsp;Working with File Objects">file object</a>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.openanything.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You pass the file object to <tt class="function">minidom.parse</tt>, which calls the <tt class="function">read</tt> method of <tt class="varname">fsock</tt> and reads the <span class="acronym">XML</span> document from the file on disk.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.openanything.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Be sure to call the <tt class="function">close</tt> method of the file object after you're done with it. <tt class="function">minidom.parse</tt> will not do this for you.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.openanything.1.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Calling the <tt class="methodname">toxml()</tt> method on the returned <span class="acronym">XML</span> document prints out the entire thing.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>Well, that all seems like a colossal waste of time. After all, you've already seen that <tt class="function">minidom.parse</tt> can simply take the filename and do all the opening and closing nonsense automatically. And it's true that if you know you're
+ just going to be parsing a local file, you can pass the filename and <tt class="function">minidom.parse</tt> is smart enough to <span class="trademark">Do The Right Thing</span>&#8482;. But notice how similar -- and easy -- it is to parse an <span class="acronym">XML</span> document straight from the Internet.
+ </p>
+ <div class="example"><a name="kgp.openanything.urllib"></a><h3 class="title">Example&nbsp;10.2.&nbsp;Parsing <span class="acronym">XML</span> from a <span class="acronym">URL</span></h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> urllib</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">usock = urllib.urlopen(<span class='pystring'>'http://slashdot.org/slashdot.rdf'</span>)</span> <a name="kgp.openanything.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">xmldoc = minidom.parse(usock)</span> <a name="kgp.openanything.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">usock.close()</span> <a name="kgp.openanything.2.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> xmldoc.toxml()</span> <a name="kgp.openanything.2.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">&lt;?xml version="1.0" ?&gt;
+&lt;rdf:RDF xmlns="http://my.netscape.com/rdf/simple/0.9/"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"&gt;
+
+&lt;channel&gt;
+&lt;title&gt;Slashdot&lt;/title&gt;
+&lt;link&gt;http://slashdot.org/&lt;/link&gt;
+&lt;description&gt;News for nerds, stuff that matters&lt;/description&gt;
+&lt;/channel&gt;
+
+&lt;image&gt;
+&lt;title&gt;Slashdot&lt;/title&gt;
+&lt;url&gt;http://images.slashdot.org/topics/topicslashdot.gif&lt;/url&gt;
+&lt;link&gt;http://slashdot.org/&lt;/link&gt;
+&lt;/image&gt;
+
+&lt;item&gt;
+&lt;title&gt;To HDTV or Not to HDTV?&lt;/title&gt;
+&lt;link&gt;http://slashdot.org/article.pl?sid=01/12/28/0421241&lt;/link&gt;
+&lt;/item&gt;
+
+[...snip...]</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.openanything.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">As you saw <a href="../html_processing/extracting_data.html#dialect.extract.urllib" title="Example&nbsp;8.5.&nbsp;Introducing urllib">in a previous chapter</a>, <tt class="function">urlopen</tt> takes a web page <span class="acronym">URL</span> and returns a file-like object. Most importantly, this object has a <tt class="function">read</tt> method which returns the <span class="acronym">HTML</span> source of the web page.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.openanything.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Now you pass the file-like object to <tt class="function">minidom.parse</tt>, which obediently calls the <tt class="function">read</tt> method of the object and parses the <span class="acronym">XML</span> data that the <tt class="function">read</tt> method returns. The fact that this <span class="acronym">XML</span> data is now coming straight from a web page is completely irrelevant. <tt class="function">minidom.parse</tt> doesn't know about web pages, and it doesn't care about web pages; it just knows about file-like objects.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.openanything.2.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">As soon as you're done with it, be sure to close the file-like object that <tt class="function">urlopen</tt> gives you.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.openanything.2.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">By the way, this <span class="acronym">URL</span> is real, and it really is <span class="acronym">XML</span>. It's an <span class="acronym">XML</span> representation of the current headlines on <a href="http://slashdot.org/">Slashdot</a>, a technical news and gossip site.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="d0e25321"></a><h3 class="title">Example&nbsp;10.3.&nbsp;Parsing <span class="acronym">XML</span> from a string (the easy but inflexible way)
+ </h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">contents = <span class='pystring'>"&lt;grammar&gt;&lt;ref id='bit'&gt;&lt;p&gt;0&lt;/p&gt;&lt;p&gt;1&lt;/p&gt;&lt;/ref&gt;&lt;/grammar&gt;"</span></span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">xmldoc = minidom.parseString(contents)</span> <a name="kgp.openanything.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> xmldoc.toxml()</span>
+<span class="computeroutput">&lt;?xml version="1.0" ?&gt;
+&lt;grammar&gt;&lt;ref id="bit"&gt;&lt;p&gt;0&lt;/p&gt;&lt;p&gt;1&lt;/p&gt;&lt;/ref&gt;&lt;/grammar&gt;</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.openanything.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="filename">minidom</tt> has a method, <tt class="function">parseString</tt>, which takes an entire <span class="acronym">XML</span> document as a string and parses it. You can use this instead of <tt class="function">minidom.parse</tt> if you know you already have your entire <span class="acronym">XML</span> document in a string.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>OK, so you can use the <tt class="function">minidom.parse</tt> function for parsing both local files and remote <span class="acronym">URL</span>s, but for parsing strings, you use... a different function. That means that if you want to be able to take input from a
+ file, a <span class="acronym">URL</span>, or a string, you'll need special logic to check whether it's a string, and call the <tt class="function">parseString</tt> function instead. How unsatisfying.
+ </p>
+ <p>If there were a way to turn a string into a file-like object, then you could simply pass this object to <tt class="function">minidom.parse</tt>. And in fact, there is a module specifically designed for doing just that: <tt class="filename">StringIO</tt>.
+ </p>
+ <div class="example"><a name="kgp.openanything.stringio.example"></a><h3 class="title">Example&nbsp;10.4.&nbsp;Introducing <tt class="filename">StringIO</tt></h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">contents = <span class='pystring'>"&lt;grammar&gt;&lt;ref id='bit'&gt;&lt;p&gt;0&lt;/p&gt;&lt;p&gt;1&lt;/p&gt;&lt;/ref&gt;&lt;/grammar&gt;"</span></span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> StringIO</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">ssock = StringIO.StringIO(contents)</span> <a name="kgp.openanything.4.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">ssock.read()</span> <a name="kgp.openanything.4.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">"&lt;grammar&gt;&lt;ref id='bit'&gt;&lt;p&gt;0&lt;/p&gt;&lt;p&gt;1&lt;/p&gt;&lt;/ref&gt;&lt;/grammar&gt;"</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">ssock.read()</span> <a name="kgp.openanything.4.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">''</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">ssock.seek(0)</span> <a name="kgp.openanything.4.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">ssock.read(15)</span> <a name="kgp.openanything.4.5"></a><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12">
+<span class="computeroutput">'&lt;grammar&gt;&lt;ref i'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">ssock.read(15)</span>
+<span class="computeroutput">"d='bit'&gt;&lt;p&gt;0&lt;/p"</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">ssock.read()</span>
+<span class="computeroutput">'&gt;&lt;p&gt;1&lt;/p&gt;&lt;/ref&gt;&lt;/grammar&gt;'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">ssock.close()</span> <a name="kgp.openanything.4.6"></a><img src="../images/callouts/6.png" alt="6" border="0" width="12" height="12"></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.openanything.4.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="filename">StringIO</tt> module contains a single class, also called <tt class="classname">StringIO</tt>, which allows you to turn a string into a file-like object. The <tt class="classname">StringIO</tt> class takes the string as a parameter when creating an instance.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.openanything.4.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Now you have a file-like object, and you can do all sorts of file-like things with it. Like <tt class="function">read</tt>, which returns the original string.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.openanything.4.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Calling <tt class="function">read</tt> again returns an empty string. This is how real file objects work too; once you read the entire file, you can't read any
+ more without explicitly seeking to the beginning of the file. The <tt class="classname">StringIO</tt> object works the same way.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.openanything.4.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You can explicitly seek to the beginning of the string, just like seeking through a file, by using the <tt class="function">seek</tt> method of the <tt class="classname">StringIO</tt> object.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.openanything.4.5"><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You can also read the string in chunks, by passing a <tt class="varname">size</tt> parameter to the <tt class="function">read</tt> method.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.openanything.4.6"><img src="../images/callouts/6.png" alt="6" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">At any time, <tt class="function">read</tt> will return the rest of the string that you haven't read yet. All of this is exactly how file objects work; hence the term
+ <span class="emphasis"><em>file-like object</em></span>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="d0e25526"></a><h3 class="title">Example&nbsp;10.5.&nbsp;Parsing <span class="acronym">XML</span> from a string (the file-like object way)
+ </h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">contents = <span class='pystring'>"&lt;grammar&gt;&lt;ref id='bit'&gt;&lt;p&gt;0&lt;/p&gt;&lt;p&gt;1&lt;/p&gt;&lt;/ref&gt;&lt;/grammar&gt;"</span></span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">ssock = StringIO.StringIO(contents)</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">xmldoc = minidom.parse(ssock)</span> <a name="kgp.openanything.5.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">ssock.close()</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> xmldoc.toxml()</span>
+<span class="computeroutput">&lt;?xml version="1.0" ?&gt;
+&lt;grammar&gt;&lt;ref id="bit"&gt;&lt;p&gt;0&lt;/p&gt;&lt;p&gt;1&lt;/p&gt;&lt;/ref&gt;&lt;/grammar&gt;</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.openanything.5.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Now you can pass the file-like object (really a <tt class="classname">StringIO</tt>) to <tt class="function">minidom.parse</tt>, which will call the object's <tt class="function">read</tt> method and happily parse away, never knowing that its input came from a hard-coded string.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>So now you know how to use a single function, <tt class="function">minidom.parse</tt>, to parse an <span class="acronym">XML</span> document stored on a web page, in a local file, or in a hard-coded string. For a web page, you use <tt class="function">urlopen</tt> to get a file-like object; for a local file, you use <tt class="function">open</tt>; and for a string, you use <tt class="classname">StringIO</tt>. Now let's take it one step further and generalize <span class="emphasis"><em>these</em></span> differences as well.
+ </p>
+ <div class="example"><a name="kgp.openanything.example"></a><h3 class="title">Example&nbsp;10.6.&nbsp;<tt class="function">openAnything</tt></h3><pre class="programlisting"><span class='pykeyword'>
+def</span> openAnything(source): <a name="kgp.openanything.6.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ <span class='pycomment'># try to open with urllib (if source is http, ftp, or file URL)</span>
+ <span class='pykeyword'>import</span> urllib
+ <span class='pykeyword'>try</span>:
+ <span class='pykeyword'>return</span> urllib.urlopen(source) <a name="kgp.openanything.6.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+ <span class='pykeyword'>except</span> (IOError, OSError):
+ <span class='pykeyword'>pass</span>
+
+ <span class='pycomment'># try to open with native open function (if source is pathname)</span>
+ <span class='pykeyword'>try</span>:
+ <span class='pykeyword'>return</span> open(source) <a name="kgp.openanything.6.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+ <span class='pykeyword'>except</span> (IOError, OSError):
+ <span class='pykeyword'>pass</span>
+
+ <span class='pycomment'># treat source as string</span>
+ <span class='pykeyword'>import</span> StringIO
+ <span class='pykeyword'>return</span> StringIO.StringIO(str(source)) <a name="kgp.openanything.6.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.openanything.6.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="function">openAnything</tt> function takes a single parameter, <tt class="varname">source</tt>, and returns a file-like object. <tt class="varname">source</tt> is a string of some sort; it can either be a <span class="acronym">URL</span> (like <tt class="literal">'http://slashdot.org/slashdot.rdf'</tt>), a full or partial pathname to a local file (like <tt class="literal">'binary.xml'</tt>), or a string that contains actual <span class="acronym">XML</span> data to be parsed.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.openanything.6.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">First, you see if <tt class="varname">source</tt> is a <span class="acronym">URL</span>. You do this through brute force: you try to open it as a <span class="acronym">URL</span> and silently ignore errors caused by trying to open something which is not a <span class="acronym">URL</span>. This is actually elegant in the sense that, if <tt class="filename">urllib</tt> ever supports new types of <span class="acronym">URL</span>s in the future, you will also support them without recoding. If <tt class="filename">urllib</tt> is able to open <tt class="varname">source</tt>, then the <tt class="literal">return</tt> kicks you out of the function immediately and the following <tt class="literal">try</tt> statements never execute.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.openanything.6.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">On the other hand, if <tt class="filename">urllib</tt> yelled at you and told you that <tt class="varname">source</tt> wasn't a valid <span class="acronym">URL</span>, you assume it's a path to a file on disk and try to open it. Again, you don't do anything fancy to check whether <tt class="varname">source</tt> is a valid filename or not (the rules for valid filenames vary wildly between different platforms anyway, so you'd probably
+ get them wrong anyway). Instead, you just blindly open the file, and silently trap any errors.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.openanything.6.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">By this point, you need to assume that <tt class="varname">source</tt> is a string that has hard-coded data in it (since nothing else worked), so you use <tt class="classname">StringIO</tt> to create a file-like object out of it and return that. (In fact, since you're using the <tt class="function">str</tt> function, <tt class="varname">source</tt> doesn't even need to be a string; it could be any object, and you'll use its string representation, as defined by its <tt class="function">__str__</tt> <a href="../object_oriented_framework/special_class_methods2.html" title="5.7.&nbsp;Advanced Special Class Methods">special method</a>.)
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>Now you can use this <tt class="function">openAnything</tt> function in conjunction with <tt class="function">minidom.parse</tt> to make a function that takes a <tt class="varname">source</tt> that refers to an <span class="acronym">XML</span> document somehow (either as a <span class="acronym">URL</span>, or a local filename, or a hard-coded <span class="acronym">XML</span> document in a string) and parses it.
+ </p>
+ <div class="example"><a name="d0e25723"></a><h3 class="title">Example&nbsp;10.7.&nbsp;Using <tt class="function">openAnything</tt> in <tt class="filename">kgp.py</tt></h3><pre class="programlisting"><span class='pykeyword'>
+class</span> KantGenerator:
+ <span class='pykeyword'>def</span><span class='pyclass'> _load</span>(self, source):
+ sock = toolbox.openAnything(source)
+ xmldoc = minidom.parse(sock).documentElement
+ sock.close()
+ <span class='pykeyword'>return</span> xmldoc</pre></div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="../xml_processing/summary.html">&lt;&lt;&nbsp;Segue</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<span class="thispage">1</span> <span class="divider">|</span> <a href="stdin_stdout_stderr.html" title="10.2.&nbsp;Standard input, output, and error">2</a> <span class="divider">|</span> <a href="caching.html" title="10.3.&nbsp;Caching node lookups">3</a> <span class="divider">|</span> <a href="child_nodes.html" title="10.4.&nbsp;Finding direct children of a node">4</a> <span class="divider">|</span> <a href="handlers_by_node_type.html" title="10.5.&nbsp;Creating separate handlers by node type">5</a> <span class="divider">|</span> <a href="command_line_arguments.html" title="10.6.&nbsp;Handling command-line arguments">6</a> <span class="divider">|</span> <a href="all_together.html" title="10.7.&nbsp;Putting it all together">7</a> <span class="divider">|</span> <a href="summary.html" title="10.8.&nbsp;Summary">8</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="stdin_stdout_stderr.html">Standard input, output, and error&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/scripts_and_streams/stdin_stdout_stderr.html b/help/diveintopython-5.4/html/scripts_and_streams/stdin_stdout_stderr.html
new file mode 100644
index 0000000..6bc7d20
--- /dev/null
+++ b/help/diveintopython-5.4/html/scripts_and_streams/stdin_stdout_stderr.html
@@ -0,0 +1,317 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>10.2.&nbsp;Standard input, output, and error</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;10.&nbsp;Scripts and Streams">
+ <link rel="previous" href="index.html" title="Chapter&nbsp;10.&nbsp;Scripts and Streams">
+ <link rel="next" href="caching.html" title="10.3.&nbsp;Caching node lookups">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Scripts and Streams</a>&nbsp;&gt;&nbsp;<span class="thispage">Standard input, output, and error</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="index.html" title="Prev: &#8220;Scripts and Streams&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="caching.html" title="Next: &#8220;Caching node lookups&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="kgp.stdio"></a>10.2.&nbsp;Standard input, output, and error
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p><span class="acronym">UNIX</span> users are already familiar with the concept of standard input, standard output, and standard error. This section is for
+ the rest of you.
+ </p>
+ </div>
+ <p>Standard output and standard error (commonly abbreviated <tt class="literal">stdout</tt> and <tt class="literal">stderr</tt>) are pipes that are built into every <span class="acronym">UNIX</span> system. When you <tt class="function">print</tt> something, it goes to the <tt class="literal">stdout</tt> pipe; when your program crashes and prints out debugging information (like a traceback in <span class="application">Python</span>), it goes to the <tt class="literal">stderr</tt> pipe. Both of these pipes are ordinarily just connected to the terminal window where you are working, so when a program
+ prints, you see the output, and when a program crashes, you see the debugging information. (If you're working on a system
+ with a window-based <span class="application">Python</span> <span class="acronym">IDE</span>, <tt class="literal">stdout</tt> and <tt class="literal">stderr</tt> default to your &#8220;<span class="quote">Interactive Window</span>&#8221;.)
+ </p>
+ <div class="example"><a name="d0e25781"></a><h3 class="title">Example&nbsp;10.8.&nbsp;Introducing <tt class="literal">stdout</tt> and <tt class="literal">stderr</tt></h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>for</span> i <span class='pykeyword'>in</span> range(3):</span>
+<tt class="prompt">... </tt><span class="userinput"><span class='pykeyword'>print</span> <span class='pystring'>'Dive in'</span></span> <a name="kgp.stdio.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">Dive in
+Dive in
+Dive in</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> sys</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>for</span> i <span class='pykeyword'>in</span> range(3):</span>
+<tt class="prompt">... </tt><span class="userinput">sys.stdout.write(<span class='pystring'>'Dive in'</span>)</span> <a name="kgp.stdio.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">Dive inDive inDive in</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>for</span> i <span class='pykeyword'>in</span> range(3):</span>
+<tt class="prompt">... </tt><span class="userinput">sys.stderr.write(<span class='pystring'>'Dive in'</span>)</span> <a name="kgp.stdio.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">Dive inDive inDive in</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.stdio.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">As you saw in <a href="../file_handling/for_loops.html#fileinfo.for.counter" title="Example&nbsp;6.9.&nbsp;Simple Counters">Example&nbsp;6.9, &#8220;Simple Counters&#8221;</a>, you can use <span class="application">Python</span>'s built-in <tt class="function">range</tt> function to build simple counter loops that repeat something a set number of times.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.stdio.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="literal">stdout</tt> is a file-like object; calling its <tt class="function">write</tt> function will print out whatever string you give it. In fact, this is what the <tt class="function">print</tt> function really does; it adds a carriage return to the end of the string you're printing, and calls <tt class="function">sys.stdout.write</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.stdio.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">In the simplest case, <tt class="literal">stdout</tt> and <tt class="literal">stderr</tt> send their output to the same place: the <span class="application">Python</span> <span class="acronym">IDE</span> (if you're in one), or the terminal (if you're running <span class="application">Python</span> from the command line). Like <tt class="literal">stdout</tt>, <tt class="literal">stderr</tt> does not add carriage returns for you; if you want them, add them yourself.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p><tt class="literal">stdout</tt> and <tt class="literal">stderr</tt> are both file-like objects, like the ones you discussed in <a href="index.html#kgp.openanything" title="10.1.&nbsp;Abstracting input sources">Section&nbsp;10.1, &#8220;Abstracting input sources&#8221;</a>, but they are both write-only. They have no <tt class="function">read</tt> method, only <tt class="function">write</tt>. Still, they are file-like objects, and you can assign any other file- or file-like object to them to redirect their output.
+ </p>
+ <div class="example"><a name="d0e25905"></a><h3 class="title">Example&nbsp;10.9.&nbsp;Redirecting output</h3><pre class="screen">
+<tt class="prompt">[you@localhost kgp]$ </tt><span class="userinput">python stdout.py</span>
+<span class="computeroutput">Dive in</span>
+<tt class="prompt">[you@localhost kgp]$ </tt><span class="userinput">cat out.log</span>
+<span class="computeroutput">This message will be logged instead of displayed</span></pre><p>(On Windows, you can use <tt class="literal">type</tt> instead of <tt class="literal">cat</tt> to display the contents of a file.)
+ </p>
+ <p>If you have not already done so, you can <a href="http://diveintopython.org/download/diveintopython-examples-5.4.zip" title="Download example scripts">download this and other examples</a> used in this book.
+ </p><pre class="programlisting">
+<span class='pycomment'>#stdout.py</span>
+<span class='pykeyword'>import</span> sys
+
+<span class='pykeyword'>print</span> <span class='pystring'>'Dive in'</span> <a name="kgp.stdio.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+saveout = sys.stdout <a name="kgp.stdio.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+fsock = open(<span class='pystring'>'out.log'</span>, <span class='pystring'>'w'</span>) <a name="kgp.stdio.2.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+sys.stdout = fsock <a name="kgp.stdio.2.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"><span class='pykeyword'>
+print</span> <span class='pystring'>'This message will be logged instead of displayed'</span> <a name="kgp.stdio.2.5"></a><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12">
+sys.stdout = saveout <a name="kgp.stdio.2.6"></a><img src="../images/callouts/6.png" alt="6" border="0" width="12" height="12">
+fsock.close() <a name="kgp.stdio.2.7"></a><img src="../images/callouts/7.png" alt="7" border="0" width="12" height="12">
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.stdio.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This will print to the <span class="acronym">IDE</span> &#8220;<span class="quote">Interactive Window</span>&#8221; (or the terminal, if running the script from the command line).
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.stdio.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Always save <tt class="literal">stdout</tt> before redirecting it, so you can set it back to normal later.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.stdio.2.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Open a file for writing. If the file doesn't exist, it will be created. If the file does exist, it will be overwritten.</td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.stdio.2.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Redirect all further output to the new file you just opened.</td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.stdio.2.5"><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This will be &#8220;<span class="quote">printed</span>&#8221; to the log file only; it will not be visible in the <span class="acronym">IDE</span> window or on the screen.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.stdio.2.6"><img src="../images/callouts/6.png" alt="6" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Set <tt class="literal">stdout</tt> back to the way it was before you mucked with it.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.stdio.2.7"><img src="../images/callouts/7.png" alt="7" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Close the log file.</td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>Redirecting <tt class="literal">stderr</tt> works exactly the same way, using <tt class="function">sys.stderr</tt> instead of <tt class="function">sys.stdout</tt>.
+ </p>
+ <div class="example"><a name="d0e26005"></a><h3 class="title">Example&nbsp;10.10.&nbsp;Redirecting error information</h3><pre class="screen">
+<tt class="prompt">[you@localhost kgp]$ </tt><span class="userinput">python stderr.py</span>
+<tt class="prompt">[you@localhost kgp]$ </tt><span class="userinput">cat error.log</span>
+<span class="computeroutput">Traceback (most recent line last):
+ File "stderr.py", line 5, in ?
+ raise Exception, 'this error will be logged'
+Exception: this error will be logged</span></pre><p>If you have not already done so, you can <a href="http://diveintopython.org/download/diveintopython-examples-5.4.zip" title="Download example scripts">download this and other examples</a> used in this book.
+ </p><pre class="programlisting">
+<span class='pycomment'>#stderr.py</span>
+<span class='pykeyword'>import</span> sys
+
+fsock = open(<span class='pystring'>'error.log'</span>, <span class='pystring'>'w'</span>) <a name="kgp.stdio.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+sys.stderr = fsock <a name="kgp.stdio.3.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"><span class='pykeyword'>
+raise</span> Exception, <span class='pystring'>'this error will be logged'</span> <a name="kgp.stdio.3.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"> <a name="kgp.stdio.3.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.stdio.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Open the log file where you want to store debugging information.</td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.stdio.3.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Redirect standard error by assigning the file object of the newly-opened log file to <tt class="literal">stderr</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.stdio.3.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Raise an exception. Note from the screen output that this does <span class="emphasis"><em>not</em></span> print anything on screen. All the normal traceback information has been written to <tt class="filename">error.log</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.stdio.3.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Also note that you're not explicitly closing your log file, nor are you setting <tt class="literal">stderr</tt> back to its original value. This is fine, since once the program crashes (because of the exception), <span class="application">Python</span> will clean up and close the file for us, and it doesn't make any difference that <tt class="literal">stderr</tt> is never restored, since, as I mentioned, the program crashes and <span class="application">Python</span> ends. Restoring the original is more important for <tt class="literal">stdout</tt>, if you expect to go do other stuff within the same script afterwards.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>Since it is so common to write error messages to standard error, there is a shorthand syntax that can be used instead of going
+ through the hassle of redirecting it outright.
+ </p>
+ <div class="example"><a name="kgp.stdio.print.example"></a><h3 class="title">Example&nbsp;10.11.&nbsp;Printing to <tt class="literal">stderr</tt></h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> <span class='pystring'>'entering function'</span></span>
+<span class="computeroutput">entering function</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> sys</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> &gt;&gt; sys.stderr, <span class='pystring'>'entering function'</span></span> <a name="kgp.stdio.6.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">entering function</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.stdio.6.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This shorthand syntax of the <tt class="function">print</tt> statement can be used to write to any open file, or file-like object. In this case, you can redirect a single <tt class="function">print</tt> statement to <tt class="literal">stderr</tt> without affecting subsequent <tt class="function">print</tt> statements.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>Standard input, on the other hand, is a read-only file object, and it represents the data flowing into the program from some
+ previous program. This will likely not make much sense to classic <span class="abbrev">Mac</span> <span class="acronym">OS</span> users, or even Windows users unless you were ever fluent on the <span class="acronym">MS-DOS</span> command line. The way it works is that you can construct a chain of commands in a single line, so that one program's output
+ becomes the input for the next program in the chain. The first program simply outputs to standard output (without doing any
+ special redirecting itself, just doing normal <tt class="function">print</tt> statements or whatever), and the next program reads from standard input, and the operating system takes care of connecting
+ one program's output to the next program's input.
+ </p>
+ <div class="example"><a name="d0e26136"></a><h3 class="title">Example&nbsp;10.12.&nbsp;Chaining commands</h3><pre class="screen">
+<tt class="prompt">[you@localhost kgp]$ </tt><span class="userinput">python kgp.py -g binary.xml</span> <a name="kgp.stdio.4.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">01100111</span>
+<tt class="prompt">[you@localhost kgp]$ </tt><span class="userinput">cat binary.xml</span> <a name="kgp.stdio.4.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">&lt;?xml version="1.0"?&gt;
+&lt;!DOCTYPE grammar PUBLIC "-//diveintopython.org//DTD Kant Generator Pro v1.0//EN" "kgp.dtd"&gt;
+&lt;grammar&gt;
+&lt;ref id="bit"&gt;
+ &lt;p&gt;0&lt;/p&gt;
+ &lt;p&gt;1&lt;/p&gt;
+&lt;/ref&gt;
+&lt;ref id="byte"&gt;
+ &lt;p&gt;&lt;xref id="bit"/&gt;&lt;xref id="bit"/&gt;&lt;xref id="bit"/&gt;&lt;xref id="bit"/&gt;\
+&lt;xref id="bit"/&gt;&lt;xref id="bit"/&gt;&lt;xref id="bit"/&gt;&lt;xref id="bit"/&gt;&lt;/p&gt;
+&lt;/ref&gt;
+&lt;/grammar&gt;</span>
+<tt class="prompt">[you@localhost kgp]$ </tt><span class="userinput">cat binary.xml | python kgp.py -g -</span> <a name="kgp.stdio.4.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"> <a name="kgp.stdio.4.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">10110001</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.stdio.4.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">As you saw in <a href="../xml_processing/index.html#kgp.divein" title="9.1.&nbsp;Diving in">Section&nbsp;9.1, &#8220;Diving in&#8221;</a>, this will print a string of eight random bits, <tt class="constant">0</tt> or <tt class="constant">1</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.stdio.4.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This simply prints out the entire contents of <tt class="filename">binary.xml</tt>. (Windows users should use <tt class="literal">type</tt> instead of <tt class="literal">cat</tt>.)
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.stdio.4.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This prints the contents of <tt class="filename">binary.xml</tt>, but the &#8220;<span class="quote"><tt class="literal">|</tt></span>&#8221; character, called the &#8220;<span class="quote">pipe</span>&#8221; character, means that the contents will not be printed to the screen. Instead, they will become the standard input of the
+ next command, which in this case calls your <span class="application">Python</span> script.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.stdio.4.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Instead of specifying a module (like <tt class="filename">binary.xml</tt>), you specify &#8220;<span class="quote"><tt class="literal">-</tt></span>&#8221;, which causes your script to load the grammar from standard input instead of from a specific file on disk. (More on how
+ this happens in the next example.) So the effect is the same as the first syntax, where you specified the grammar filename
+ directly, but think of the expansion possibilities here. Instead of simply doing <tt class="literal">cat binary.xml</tt>, you could run a script that dynamically generates the grammar, then you can pipe it into your script. It could come from
+ anywhere: a database, or some grammar-generating meta-script, or whatever. The point is that you don't need to change your
+ <tt class="filename">kgp.py</tt> script at all to incorporate any of this functionality. All you need to do is be able to take grammar files from standard
+ input, and you can separate all the other logic into another program.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>So how does the script &#8220;<span class="quote">know</span>&#8221; to read from standard input when the grammar file is &#8220;<span class="quote"><tt class="literal">-</tt></span>&#8221;? It's not magic; it's just code.
+ </p>
+ <div class="example"><a name="d0e26237"></a><h3 class="title">Example&nbsp;10.13.&nbsp;Reading from standard input in <tt class="filename">kgp.py</tt></h3><pre class="programlisting"><span class='pykeyword'>
+def</span> openAnything(source):
+ <span class='pykeyword'>if</span> source == <span class='pystring'>"-"</span>: <a name="kgp.stdio.5.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ <span class='pykeyword'>import</span> sys
+ <span class='pykeyword'>return</span> sys.stdin
+
+ <span class='pycomment'># try to open with urllib (if source is http, ftp, or file URL)</span>
+ <span class='pykeyword'>import</span> urllib
+ <span class='pykeyword'>try</span>:
+
+[... snip ...]</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.stdio.5.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This is the <tt class="function">openAnything</tt> function from <tt class="filename">toolbox.py</tt>, which you previously examined in <a href="index.html#kgp.openanything" title="10.1.&nbsp;Abstracting input sources">Section&nbsp;10.1, &#8220;Abstracting input sources&#8221;</a>. All you've done is add three lines of code at the beginning of the function to check if the source is &#8220;<span class="quote"><tt class="literal">-</tt></span>&#8221;; if so, you return <tt class="literal">sys.stdin</tt>. Really, that's it! Remember, <tt class="literal">stdin</tt> is a file-like object with a <tt class="function">read</tt> method, so the rest of the code (in <tt class="filename">kgp.py</tt>, where you call <tt class="function">openAnything</tt>) doesn't change a bit.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="index.html">&lt;&lt;&nbsp;Scripts and Streams</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#kgp.openanything" title="10.1.&nbsp;Abstracting input sources">1</a> <span class="divider">|</span> <span class="thispage">2</span> <span class="divider">|</span> <a href="caching.html" title="10.3.&nbsp;Caching node lookups">3</a> <span class="divider">|</span> <a href="child_nodes.html" title="10.4.&nbsp;Finding direct children of a node">4</a> <span class="divider">|</span> <a href="handlers_by_node_type.html" title="10.5.&nbsp;Creating separate handlers by node type">5</a> <span class="divider">|</span> <a href="command_line_arguments.html" title="10.6.&nbsp;Handling command-line arguments">6</a> <span class="divider">|</span> <a href="all_together.html" title="10.7.&nbsp;Putting it all together">7</a> <span class="divider">|</span> <a href="summary.html" title="10.8.&nbsp;Summary">8</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="caching.html">Caching node lookups&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/scripts_and_streams/summary.html b/help/diveintopython-5.4/html/scripts_and_streams/summary.html
new file mode 100644
index 0000000..0745bfb
--- /dev/null
+++ b/help/diveintopython-5.4/html/scripts_and_streams/summary.html
@@ -0,0 +1,79 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>10.8.&nbsp;Summary</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;10.&nbsp;Scripts and Streams">
+ <link rel="previous" href="all_together.html" title="10.7.&nbsp;Putting it all together">
+ <link rel="next" href="../http_web_services/index.html" title="Chapter&nbsp;11.&nbsp;HTTP Web Services">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Scripts and Streams</a>&nbsp;&gt;&nbsp;<span class="thispage">Summary</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="all_together.html" title="Prev: &#8220;Putting it all together&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="../http_web_services/index.html" title="Next: &#8220;HTTP Web Services&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="kgp.summary"></a>10.8.&nbsp;Summary
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p><span class="application">Python</span> comes with powerful libraries for parsing and manipulating <span class="acronym">XML</span> documents. The <tt class="filename">minidom</tt> takes an <span class="acronym">XML</span> file and parses it into <span class="application">Python</span> objects, providing for random access to arbitrary elements. Furthermore, this chapter shows how <span class="application">Python</span> can be used to create a "real" standalone command-line script, complete with command-line flags, command-line arguments,
+ error handling, even the ability to take input from the piped result of a previous program.
+ </p>
+ </div>
+ <p>Before moving on to the next chapter, you should be comfortable doing all of these things:</p>
+ <div class="itemizedlist">
+ <ul>
+ <li><a href="stdin_stdout_stderr.html" title="10.2.&nbsp;Standard input, output, and error">Chaining programs</a> with standard input and output
+ </li>
+ <li><a href="handlers_by_node_type.html" title="10.5.&nbsp;Creating separate handlers by node type">Defining dynamic dispatchers</a> with <tt class="function">getattr</tt>.
+ </li>
+ <li><a href="command_line_arguments.html" title="10.6.&nbsp;Handling command-line arguments">Using command-line flags</a> and validating them with <tt class="filename">getopt</tt></li>
+ </ul>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="all_together.html">&lt;&lt;&nbsp;Putting it all together</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#kgp.openanything" title="10.1.&nbsp;Abstracting input sources">1</a> <span class="divider">|</span> <a href="stdin_stdout_stderr.html" title="10.2.&nbsp;Standard input, output, and error">2</a> <span class="divider">|</span> <a href="caching.html" title="10.3.&nbsp;Caching node lookups">3</a> <span class="divider">|</span> <a href="child_nodes.html" title="10.4.&nbsp;Finding direct children of a node">4</a> <span class="divider">|</span> <a href="handlers_by_node_type.html" title="10.5.&nbsp;Creating separate handlers by node type">5</a> <span class="divider">|</span> <a href="command_line_arguments.html" title="10.6.&nbsp;Handling command-line arguments">6</a> <span class="divider">|</span> <a href="all_together.html" title="10.7.&nbsp;Putting it all together">7</a> <span class="divider">|</span> <span class="thispage">8</span>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="../http_web_services/index.html">HTTP Web Services&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/soap_web_services/debugging.html b/help/diveintopython-5.4/html/soap_web_services/debugging.html
new file mode 100644
index 0000000..10b5772
--- /dev/null
+++ b/help/diveintopython-5.4/html/soap_web_services/debugging.html
@@ -0,0 +1,200 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>12.4.&nbsp;Debugging SOAP Web Services</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;12.&nbsp;SOAP Web Services">
+ <link rel="previous" href="first_steps.html" title="12.3.&nbsp;First Steps with SOAP">
+ <link rel="next" href="wsdl.html" title="12.5.&nbsp;Introducing WSDL">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">SOAP Web Services</a>&nbsp;&gt;&nbsp;<span class="thispage">Debugging SOAP Web Services</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="first_steps.html" title="Prev: &#8220;First Steps with SOAP&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="wsdl.html" title="Next: &#8220;Introducing WSDL&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="soap.debug"></a>12.4.&nbsp;Debugging <span class="acronym">SOAP</span> Web Services
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>The <span class="acronym">SOAP</span> libraries provide an easy way to see what's going on behind the scenes.
+ </p>
+ </div>
+ <p>Turning on debugging is a simple matter of setting two flags in the <tt class="classname">SOAPProxy</tt>'s configuration.
+ </p>
+ <div class="example"><a name="d0e30423"></a><h3 class="title">Example&nbsp;12.7.&nbsp;Debugging <span class="acronym">SOAP</span> Web Services
+ </h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>from</span> SOAPpy <span class='pykeyword'>import</span> SOAPProxy</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">url = <span class='pystring'>'http://services.xmethods.net:80/soap/servlet/rpcrouter'</span></span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">n = <span class='pystring'>'urn:xmethods-Temperature'</span></span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">server = SOAPProxy(url, namespace=n)</span> <a name="soap.debug.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">server.config.dumpSOAPOut = 1</span> <a name="soap.debug.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">server.config.dumpSOAPIn = 1</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">temperature = server.getTemp(<span class='pystring'>'27502'</span>)</span> <a name="soap.debug.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">*** Outgoing SOAP ******************************************************
+&lt;?xml version="1.0" encoding="UTF-8"?&gt;
+&lt;SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
+ xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
+ xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
+ xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
+ xmlns:xsd="http://www.w3.org/1999/XMLSchema"&gt;
+&lt;SOAP-ENV:Body&gt;
+&lt;ns1:getTemp xmlns:ns1="urn:xmethods-Temperature" SOAP-ENC:root="1"&gt;
+&lt;v1 xsi:type="xsd:string"&gt;27502&lt;/v1&gt;
+&lt;/ns1:getTemp&gt;
+&lt;/SOAP-ENV:Body&gt;
+&lt;/SOAP-ENV:Envelope&gt;
+************************************************************************
+*** Incoming SOAP ******************************************************
+&lt;?xml version='1.0' encoding='UTF-8'?&gt;
+&lt;SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"&gt;
+&lt;SOAP-ENV:Body&gt;
+&lt;ns1:getTempResponse xmlns:ns1="urn:xmethods-Temperature"
+ SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"&gt;
+&lt;return xsi:type="xsd:float"&gt;80.0&lt;/return&gt;
+&lt;/ns1:getTempResponse&gt;
+
+&lt;/SOAP-ENV:Body&gt;
+&lt;/SOAP-ENV:Envelope&gt;
+************************************************************************
+</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">temperature</span>
+<span class="computeroutput">80.0</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#soap.debug.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">First, create the <tt class="classname">SOAPProxy</tt> like normal, with the service <span class="acronym">URL</span> and the namespace.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#soap.debug.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Second, turn on debugging by setting <tt class="varname">server.config.dumpSOAPIn</tt> and <tt class="varname">server.config.dumpSOAPOut</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#soap.debug.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Third, call the remote <span class="acronym">SOAP</span> method as usual. The <span class="acronym">SOAP</span> library will print out both the outgoing XML request document, and the incoming XML response document. This is all the hard
+ work that <tt class="classname">SOAPProxy</tt> is doing for you. Intimidating, isn't it? Let's break it down.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>Most of the XML request document that gets sent to the server is just boilerplate. Ignore all the namespace declarations;
+ they're going to be the same (or similar) for all <span class="acronym">SOAP</span> calls. The heart of the &#8220;<span class="quote">function call</span>&#8221; is this fragment within the <tt class="sgmltag-element">&lt;Body&gt;</tt> element:
+ </p>
+ <div class="informalexample"><pre class="programlisting">
+&lt;ns1:getTemp <a name="soap.debug.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ xmlns:ns1=<span class='pystring'>"urn:xmethods-Temperature"</span> <a name="soap.debug.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+ SOAP-ENC:root=<span class='pystring'>"1"</span>&gt;
+&lt;v1 xsi:type=<span class='pystring'>"xsd:string"</span>&gt;27502&lt;/v1&gt; <a name="soap.debug.2.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+&lt;/ns1:getTemp&gt;
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#soap.debug.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The element name is the function name, <tt class="function">getTemp</tt>. <tt class="classname">SOAPProxy</tt> uses <a href="../scripts_and_streams/handlers_by_node_type.html" title="10.5.&nbsp;Creating separate handlers by node type"><tt class="function">getattr</tt> as a dispatcher</a>. Instead of calling separate local methods based on the method name, it actually uses the method name to construct the XML
+ request document.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#soap.debug.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The function's XML element is contained in a specific namespace, which is the namespace you specified when you created the
+ <tt class="classname">SOAPProxy</tt> object. Don't worry about the <tt class="literal">SOAP-ENC:root</tt>; that's boilerplate too.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#soap.debug.2.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The arguments of the function also got translated into XML. <tt class="classname">SOAPProxy</tt> introspects each argument to determine its datatype (in this case it's a string). The argument datatype goes into the <tt class="literal">xsi:type</tt> attribute, followed by the actual string value.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>The XML return document is equally easy to understand, once you know what to ignore. Focus on this fragment within the <tt class="sgmltag-element">&lt;Body&gt;</tt>:
+ </p>
+ <div class="informalexample"><pre class="programlisting">
+&lt;ns1:getTempResponse <a name="soap.debug.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ xmlns:ns1=<span class='pystring'>"urn:xmethods-Temperature"</span> <a name="soap.debug.3.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+ SOAP-ENV:encodingStyle=<span class='pystring'>"http://schemas.xmlsoap.org/soap/encoding/"</span>&gt;
+&lt;<span class='pykeyword'>return</span> xsi:type=<span class='pystring'>"xsd:float"</span>&gt;80.0&lt;/<span class='pykeyword'>return</span>&gt; <a name="soap.debug.3.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+&lt;/ns1:getTempResponse&gt;
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#soap.debug.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The server wraps the function return value within a <tt class="sgmltag-element">&lt;getTempResponse&gt;</tt> element. By convention, this wrapper element is the name of the function, plus <tt class="literal">Response</tt>. But it could really be almost anything; the important thing that <tt class="classname">SOAPProxy</tt> notices is not the element name, but the namespace.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#soap.debug.3.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The server returns the response in the same namespace we used in the request, the same namespace we specified when we first
+ create the <tt class="classname">SOAPProxy</tt>. Later in this chapter we'll see what happens if you forget to specify the namespace when creating the <tt class="classname">SOAPProxy</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#soap.debug.3.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The return value is specified, along with its datatype (it's a float). <tt class="classname">SOAPProxy</tt> uses this explicit datatype to create a <span class="application">Python</span> object of the correct native datatype and return it.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="first_steps.html">&lt;&lt;&nbsp;First Steps with SOAP</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#soap.divein" title="12.1.&nbsp;Diving In">1</a> <span class="divider">|</span> <a href="install.html" title="12.2.&nbsp;Installing the SOAP Libraries">2</a> <span class="divider">|</span> <a href="first_steps.html" title="12.3.&nbsp;First Steps with SOAP">3</a> <span class="divider">|</span> <span class="thispage">4</span> <span class="divider">|</span> <a href="wsdl.html" title="12.5.&nbsp;Introducing WSDL">5</a> <span class="divider">|</span> <a href="introspection.html" title="12.6.&nbsp;Introspecting SOAP Web Services with WSDL">6</a> <span class="divider">|</span> <a href="google.html" title="12.7.&nbsp;Searching Google">7</a> <span class="divider">|</span> <a href="troubleshooting.html" title="12.8.&nbsp;Troubleshooting SOAP Web Services">8</a> <span class="divider">|</span> <a href="summary.html" title="12.9.&nbsp;Summary">9</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="wsdl.html">Introducing WSDL&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/soap_web_services/first_steps.html b/help/diveintopython-5.4/html/soap_web_services/first_steps.html
new file mode 100644
index 0000000..803cf3d
--- /dev/null
+++ b/help/diveintopython-5.4/html/soap_web_services/first_steps.html
@@ -0,0 +1,111 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>12.3.&nbsp;First Steps with SOAP</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;12.&nbsp;SOAP Web Services">
+ <link rel="previous" href="install.html" title="12.2.&nbsp;Installing the SOAP Libraries">
+ <link rel="next" href="debugging.html" title="12.4.&nbsp;Debugging SOAP Web Services">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">SOAP Web Services</a>&nbsp;&gt;&nbsp;<span class="thispage">First Steps with SOAP</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="install.html" title="Prev: &#8220;Installing the SOAP Libraries&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="debugging.html" title="Next: &#8220;Debugging SOAP Web Services&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="soap.firststeps"></a>12.3.&nbsp;First Steps with <span class="acronym">SOAP</span></h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>The heart of <span class="acronym">SOAP</span> is the ability to call remote functions. There are a number of public access <span class="acronym">SOAP</span> servers that provide simple functions for demonstration purposes.
+ </p>
+ </div>
+ <p>The most popular public access <span class="acronym">SOAP</span> server is <a href="http://www.xmethods.net/">http://www.xmethods.net/</a>. This example uses a demonstration function that takes a United States zip code and returns the current temperature in that
+ region.
+ </p>
+ <div class="example"><a name="d0e30286"></a><h3 class="title">Example&nbsp;12.6.&nbsp;Getting the Current Temperature</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>from</span> SOAPpy <span class='pykeyword'>import</span> SOAPProxy</span> <a name="soap.firststeps.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">url = <span class='pystring'>'http://services.xmethods.net:80/soap/servlet/rpcrouter'</span></span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">namespace = <span class='pystring'>'urn:xmethods-Temperature'</span></span> <a name="soap.firststeps.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">server = SOAPProxy(url, namespace)</span> <a name="soap.firststeps.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">server.getTemp(<span class='pystring'>'27502'</span>)</span> <a name="soap.firststeps.1.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">80.0</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#soap.firststeps.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You access the remote <span class="acronym">SOAP</span> server through a proxy class, <tt class="classname">SOAPProxy</tt>. The proxy handles all the internals of <span class="acronym">SOAP</span> for you, including creating the XML request document out of the function name and argument list, sending the request over
+ HTTP to the remote <span class="acronym">SOAP</span> server, parsing the XML response document, and creating native <span class="application">Python</span> values to return. You'll see what these XML documents look like in the next section.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#soap.firststeps.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Every <span class="acronym">SOAP</span> service has a <span class="acronym">URL</span> which handles all the requests. The same <span class="acronym">URL</span> is used for all function calls. This particular service only has a single function, but later in this chapter you'll see
+ examples of the Google <span class="acronym">API</span>, which has several functions. The service <span class="acronym">URL</span> is shared by all functions.Each <span class="acronym">SOAP</span> service also has a namespace, which is defined by the server and is completely arbitrary. It's simply part of the configuration
+ required to call <span class="acronym">SOAP</span> methods. It allows the server to share a single service <span class="acronym">URL</span> and route requests between several unrelated services. It's like dividing <span class="application">Python</span> modules into <a href="../xml_processing/packages.html" title="9.2.&nbsp;Packages">packages</a>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#soap.firststeps.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You're creating the <tt class="classname">SOAPProxy</tt> with the service <span class="acronym">URL</span> and the service namespace. This doesn't make any connection to the <span class="acronym">SOAP</span> server; it simply creates a local <span class="application">Python</span> object.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#soap.firststeps.1.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Now with everything configured properly, you can actually call remote <span class="acronym">SOAP</span> methods as if they were local functions. You pass arguments just like a normal function, and you get a return value just
+ like a normal function. But under the covers, there's a heck of a lot going on.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>Let's peek under those covers.</p>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="install.html">&lt;&lt;&nbsp;Installing the SOAP Libraries</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#soap.divein" title="12.1.&nbsp;Diving In">1</a> <span class="divider">|</span> <a href="install.html" title="12.2.&nbsp;Installing the SOAP Libraries">2</a> <span class="divider">|</span> <span class="thispage">3</span> <span class="divider">|</span> <a href="debugging.html" title="12.4.&nbsp;Debugging SOAP Web Services">4</a> <span class="divider">|</span> <a href="wsdl.html" title="12.5.&nbsp;Introducing WSDL">5</a> <span class="divider">|</span> <a href="introspection.html" title="12.6.&nbsp;Introspecting SOAP Web Services with WSDL">6</a> <span class="divider">|</span> <a href="google.html" title="12.7.&nbsp;Searching Google">7</a> <span class="divider">|</span> <a href="troubleshooting.html" title="12.8.&nbsp;Troubleshooting SOAP Web Services">8</a> <span class="divider">|</span> <a href="summary.html" title="12.9.&nbsp;Summary">9</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="debugging.html">Debugging SOAP Web Services&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/soap_web_services/google.html b/help/diveintopython-5.4/html/soap_web_services/google.html
new file mode 100644
index 0000000..8e099c9
--- /dev/null
+++ b/help/diveintopython-5.4/html/soap_web_services/google.html
@@ -0,0 +1,236 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>12.7.&nbsp;Searching Google</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;12.&nbsp;SOAP Web Services">
+ <link rel="previous" href="introspection.html" title="12.6.&nbsp;Introspecting SOAP Web Services with WSDL">
+ <link rel="next" href="troubleshooting.html" title="12.8.&nbsp;Troubleshooting SOAP Web Services">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">SOAP Web Services</a>&nbsp;&gt;&nbsp;<span class="thispage">Searching Google</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="introspection.html" title="Prev: &#8220;Introspecting SOAP Web Services with WSDL&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="troubleshooting.html" title="Next: &#8220;Troubleshooting SOAP Web Services&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="soap.google"></a>12.7.&nbsp;Searching Google
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>Let's finally turn to the sample code that you saw that the beginning of this chapter, which does something more useful and
+ exciting than get the current temperature.
+ </p>
+ </div>
+ <p>Google provides a <span class="acronym">SOAP</span> <span class="acronym">API</span> for programmatically accessing Google search results. To use it, you will need to sign up for Google Web Services.
+ </p>
+ <div class="procedure">
+ <h3 class="title">Procedure&nbsp;12.4.&nbsp;Signing Up for Google Web Services</h3>
+ <ol type="1">
+ <li>
+ <p>Go to <a href="http://www.google.com/apis/">http://www.google.com/apis/</a> and create a Google account. This requires only an email address. After you sign up you will receive your Google API license
+ key by email. You will need this key to pass as a parameter whenever you call Google's search functions.
+ </p>
+ </li>
+ <li>
+ <p>Also on <a href="http://www.google.com/apis/">http://www.google.com/apis/</a>, download the Google Web APIs developer kit. This includes some sample code in several programming languages (but not <span class="application">Python</span>), and more importantly, it includes the <span class="acronym">WSDL</span> file.
+ </p>
+ </li>
+ <li>
+ <p>Decompress the developer kit file and find <tt class="filename">GoogleSearch.wsdl</tt>. Copy this file to some permanent location on your local drive. You will need it later in this chapter.
+ </p>
+ </li>
+ </ol>
+ </div>
+ <p>Once you have your developer key and your Google <span class="acronym">WSDL</span> file in a known place, you can start poking around with Google Web Services.
+ </p>
+ <div class="example"><a name="d0e31206"></a><h3 class="title">Example&nbsp;12.12.&nbsp;Introspecting Google Web Services</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>from</span> SOAPpy <span class='pykeyword'>import</span> WSDL</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">server = WSDL.Proxy(<span class='pystring'>'/path/to/your/GoogleSearch.wsdl'</span>)</span> <a name="soap.google.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">server.methods.keys()</span> <a name="soap.google.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">[u'doGoogleSearch', u'doGetCachedPage', u'doSpellingSuggestion']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">callInfo = server.methods[<span class='pystring'>'doGoogleSearch'</span>]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>for</span> arg <span class='pykeyword'>in</span> callInfo.inparams:</span> <a name="soap.google.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<tt class="prompt">... </tt><span class="userinput"><span class='pykeyword'>print</span> arg.name.ljust(15), arg.type</span>
+<span class="computeroutput">key (u'http://www.w3.org/2001/XMLSchema', u'string')
+q (u'http://www.w3.org/2001/XMLSchema', u'string')
+start (u'http://www.w3.org/2001/XMLSchema', u'int')
+maxResults (u'http://www.w3.org/2001/XMLSchema', u'int')
+filter (u'http://www.w3.org/2001/XMLSchema', u'boolean')
+restrict (u'http://www.w3.org/2001/XMLSchema', u'string')
+safeSearch (u'http://www.w3.org/2001/XMLSchema', u'boolean')
+lr (u'http://www.w3.org/2001/XMLSchema', u'string')
+ie (u'http://www.w3.org/2001/XMLSchema', u'string')
+oe (u'http://www.w3.org/2001/XMLSchema', u'string')</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#soap.google.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Getting started with Google web services is easy: just create a <tt class="classname">WSDL.Proxy</tt> object and point it at your local copy of Google's <span class="acronym">WSDL</span> file.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#soap.google.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">According to the <span class="acronym">WSDL</span> file, Google offers three functions: <tt class="function">doGoogleSearch</tt>, <tt class="function">doGetCachedPage</tt>, and <tt class="function">doSpellingSuggestion</tt>. These do exactly what they sound like: perform a Google search and return the results programmatically, get access to the
+ cached version of a page from the last time Google saw it, and offer spelling suggestions for commonly misspelled search words.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#soap.google.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="function">doGoogleSearch</tt> function takes a number of parameters of various types. Note that while the <span class="acronym">WSDL</span> file can tell you what the arguments are called and what datatype they are, it can't tell you what they mean or how to use
+ them. It could theoretically tell you the acceptable range of values for each parameter, if only specific values were allowed,
+ but Google's <span class="acronym">WSDL</span> file is not that detailed. <tt class="classname">WSDL.Proxy</tt> can't work magic; it can only give you the information provided in the <span class="acronym">WSDL</span> file.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>Here is a brief synopsis of all the parameters to the <tt class="function">doGoogleSearch</tt> function:
+ </p>
+ <div class="itemizedlist">
+ <ul>
+ <li><tt class="varname">key</tt> - Your Google API key, which you received when you signed up for Google web services.
+ </li>
+ <li><tt class="varname">q</tt> - The search word or phrase you're looking for. The syntax is exactly the same as Google's web form, so if you know any
+ advanced search syntax or tricks, they all work here as well.
+ </li>
+ <li><tt class="varname">start</tt> - The index of the result to start on. Like the interactive web version of Google, this function returns 10 results at a
+ time. If you wanted to get the second &#8220;<span class="quote">page</span>&#8221; of results, you would set <tt class="varname">start</tt> to 10.
+ </li>
+ <li><tt class="varname">maxResults</tt> - The number of results to return. Currently capped at 10, although you can specify fewer if you are only interested in
+ a few results and want to save a little bandwidth.
+ </li>
+ <li><tt class="varname">filter</tt> - If <tt class="constant">True</tt>, Google will filter out duplicate pages from the results.
+ </li>
+ <li><tt class="varname">restrict</tt> - Set this to <tt class="literal">country</tt> plus a country code to get results only from a particular country. Example: <tt class="literal">countryUK</tt> to search pages in the United Kingdom. You can also specify <tt class="literal">linux</tt>, <tt class="literal">mac</tt>, or <tt class="literal">bsd</tt> to search a Google-defined set of technical sites, or <tt class="literal">unclesam</tt> to search sites about the United States government.
+ </li>
+ <li><tt class="varname">safeSearch</tt> - If <tt class="constant">True</tt>, Google will filter out porn sites.
+ </li>
+ <li><tt class="varname">lr</tt> (&#8220;<span class="quote">language restrict</span>&#8221;) - Set this to a language code to get results only in a particular language.
+ </li>
+ <li><tt class="varname">ie</tt> and <tt class="varname">oe</tt> (&#8220;<span class="quote">input encoding</span>&#8221; and &#8220;<span class="quote">output encoding</span>&#8221;) - Deprecated, both must be <tt class="literal">utf-8</tt>.
+ </li>
+ </ul>
+ </div>
+ <div class="example"><a name="d0e31392"></a><h3 class="title">Example&nbsp;12.13.&nbsp;Searching Google</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>from</span> SOAPpy <span class='pykeyword'>import</span> WSDL</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">server = WSDL.Proxy(<span class='pystring'>'/path/to/your/GoogleSearch.wsdl'</span>)</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">key = <span class='pystring'>'YOUR_GOOGLE_API_KEY'</span></span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">results = server.doGoogleSearch(key, <span class='pystring'>'mark'</span>, 0, 10, False, <span class='pystring'>""</span>,</span>
+<tt class="prompt">... </tt><span class="userinput">False, <span class='pystring'>""</span>, <span class='pystring'>"utf-8"</span>, <span class='pystring'>"utf-8"</span>)</span> <a name="soap.google.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">len(results.resultElements)</span> <a name="soap.google.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">10</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">results.resultElements[0].URL</span> <a name="soap.google.2.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">'http://diveintomark.org/'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">results.resultElements[0].title</span>
+<span class="computeroutput">'dive into &lt;b&gt;mark&lt;/b&gt;'</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#soap.google.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">After setting up the <tt class="classname">WSDL.Proxy</tt> object, you can call <tt class="function">server.doGoogleSearch</tt> with all ten parameters. Remember to use your own Google API key that you received when you signed up for Google web services.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#soap.google.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">There's a lot of information returned, but let's look at the actual search results first. They're stored in <tt class="varname">results.resultElements</tt>, and you can access them just like a normal <span class="application">Python</span> list.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#soap.google.2.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Each element in the <tt class="varname">resultElements</tt> is an object that has a <tt class="varname">URL</tt>, <tt class="varname">title</tt>, <tt class="varname">snippet</tt>, and other useful attributes. At this point you can use normal <span class="application">Python</span> introspection techniques like <b class="userinput"><tt>dir(results.resultElements[0])</tt></b> to see the available attributes. Or you can introspect through the <span class="acronym">WSDL</span> proxy object and look through the function's <tt class="varname">outparams</tt>. Each technique will give you the same information.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>The <tt class="varname">results</tt> object contains more than the actual search results. It also contains information about the search itself, such as how long
+ it took and how many results were found (even though only 10 were returned). The Google web interface shows this information,
+ and you can access it programmatically too.
+ </p>
+ <div class="example"><a name="d0e31503"></a><h3 class="title">Example&nbsp;12.14.&nbsp;Accessing Secondary Information From Google</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">results.searchTime</span> <a name="soap.google.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">0.224919</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">results.estimatedTotalResultsCount</span> <a name="soap.google.3.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">29800000</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">results.directoryCategories</span> <a name="soap.google.3.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">[&lt;SOAPpy.Types.structType item at 14367400&gt;:
+ {'fullViewableName':
+ 'Top/Arts/Literature/World_Literature/American/19th_Century/Twain,_Mark',
+ 'specialEncoding': ''}]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">results.directoryCategories[0].fullViewableName</span>
+<span class="computeroutput">'Top/Arts/Literature/World_Literature/American/19th_Century/Twain,_Mark'</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#soap.google.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This search took 0.224919 seconds. That does not include the time spent sending and receiving the actual <span class="acronym">SOAP</span> XML documents. It's just the time that Google spent processing your request once it received it.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#soap.google.3.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">In total, there were approximately 30 million results. You can access them 10 at a time by changing the <tt class="varname">start</tt> parameter and calling <tt class="function">server.doGoogleSearch</tt> again.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#soap.google.3.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">For some queries, Google also returns a list of related categories in the <a href="http://directory.google.com/">Google Directory</a>. You can append these URLs to <a href="http://directory.google.com/">http://directory.google.com/</a> to construct the link to the directory category page.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="introspection.html">&lt;&lt;&nbsp;Introspecting SOAP Web Services with WSDL</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#soap.divein" title="12.1.&nbsp;Diving In">1</a> <span class="divider">|</span> <a href="install.html" title="12.2.&nbsp;Installing the SOAP Libraries">2</a> <span class="divider">|</span> <a href="first_steps.html" title="12.3.&nbsp;First Steps with SOAP">3</a> <span class="divider">|</span> <a href="debugging.html" title="12.4.&nbsp;Debugging SOAP Web Services">4</a> <span class="divider">|</span> <a href="wsdl.html" title="12.5.&nbsp;Introducing WSDL">5</a> <span class="divider">|</span> <a href="introspection.html" title="12.6.&nbsp;Introspecting SOAP Web Services with WSDL">6</a> <span class="divider">|</span> <span class="thispage">7</span> <span class="divider">|</span> <a href="troubleshooting.html" title="12.8.&nbsp;Troubleshooting SOAP Web Services">8</a> <span class="divider">|</span> <a href="summary.html" title="12.9.&nbsp;Summary">9</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="troubleshooting.html">Troubleshooting SOAP Web Services&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/soap_web_services/index.html b/help/diveintopython-5.4/html/soap_web_services/index.html
new file mode 100644
index 0000000..a4855cd
--- /dev/null
+++ b/help/diveintopython-5.4/html/soap_web_services/index.html
@@ -0,0 +1,178 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>Chapter&nbsp;12.&nbsp;SOAP Web Services</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="../toc/index.html" title="Dive Into Python">
+ <link rel="previous" href="../http_web_services/summary.html" title="11.10.&nbsp;Summary">
+ <link rel="next" href="install.html" title="12.2.&nbsp;Installing the SOAP Libraries">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<span class="thispage">SOAP Web Services</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="../http_web_services/summary.html" title="Prev: &#8220;Summary&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="install.html" title="Next: &#8220;Installing the SOAP Libraries&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="chapter" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="soap"></a>Chapter&nbsp;12.&nbsp;<span class="acronym">SOAP</span> Web Services
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="toc">
+ <ul>
+ <li><span class="section"><a href="index.html#soap.divein">12.1. Diving In</a></span></li>
+ <li><span class="section"><a href="install.html">12.2. Installing the SOAP Libraries</a></span><ul>
+ <li><span class="section"><a href="install.html#d0e29967">12.2.1. Installing PyXML</a></span></li>
+ <li><span class="section"><a href="install.html#d0e30070">12.2.2. Installing fpconst</a></span></li>
+ <li><span class="section"><a href="install.html#d0e30171">12.2.3. Installing SOAPpy</a></span></li>
+ </ul>
+ </li>
+ <li><span class="section"><a href="first_steps.html">12.3. First Steps with SOAP</a></span></li>
+ <li><span class="section"><a href="debugging.html">12.4. Debugging SOAP Web Services</a></span></li>
+ <li><span class="section"><a href="wsdl.html">12.5. Introducing WSDL</a></span></li>
+ <li><span class="section"><a href="introspection.html">12.6. Introspecting SOAP Web Services with WSDL</a></span></li>
+ <li><span class="section"><a href="google.html">12.7. Searching Google</a></span></li>
+ <li><span class="section"><a href="troubleshooting.html">12.8. Troubleshooting SOAP Web Services</a></span></li>
+ <li><span class="section"><a href="summary.html">12.9. Summary</a></span></li>
+ </ul>
+ </div>
+ <div class="abstract">
+ <p><a href="../http_web_services/index.html">Chapter 11</a> focused on document-oriented web services over HTTP. The &#8220;<span class="quote">input parameter</span>&#8221; was the <span class="acronym">URL</span>, and the &#8220;<span class="quote">return value</span>&#8221; was an actual XML document which it was your responsibility to parse.
+ </p>
+ <p>This chapter will focus on <span class="acronym">SOAP</span> web services, which take a more structured approach. Rather than dealing with HTTP requests and XML documents directly,
+ <span class="acronym">SOAP</span> allows you to simulate calling functions that return native data types. As you will see, the illusion is almost perfect;
+ you can &#8220;<span class="quote">call</span>&#8221; a function through a <span class="acronym">SOAP</span> library, with the standard <span class="application">Python</span> calling syntax, and the function appears to return <span class="application">Python</span> objects and values. But under the covers, the <span class="acronym">SOAP</span> library has actually performed a complex transaction involving multiple XML documents and a remote server.
+ </p>
+ <p><span class="acronym">SOAP</span> is a complex specification, and it is somewhat misleading to say that <span class="acronym">SOAP</span> is all about calling remote functions. Some people would pipe up to add that <span class="acronym">SOAP</span> allows for one-way asynchronous message passing, and document-oriented web services. And those people would be correct;
+ <span class="acronym">SOAP</span> can be used that way, and in many different ways. But this chapter will focus on so-called &#8220;<span class="quote">RPC-style</span>&#8221; <span class="acronym">SOAP</span> -- calling a remote function and getting results back.
+ </p>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="soap.divein"></a>12.1.&nbsp;Diving In
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>You use Google, right? It's a popular search engine. Have you ever wished you could programmatically access Google search
+ results? Now you can. Here is a program to search Google from <span class="application">Python</span>.
+ </p>
+ </div>
+ <div class="example"><a name="d0e29893"></a><h3 class="title">Example&nbsp;12.1.&nbsp;<tt class="filename">search.py</tt></h3><pre class="programlisting"><span class='pykeyword'>from</span> SOAPpy <span class='pykeyword'>import</span> WSDL
+
+<span class='pycomment'># you'll need to configure these two values;</span>
+<span class='pycomment'># see http://www.google.com/apis/</span>
+WSDLFILE = <span class='pystring'>'/path/to/copy/of/GoogleSearch.wsdl'</span>
+APIKEY = <span class='pystring'>'YOUR_GOOGLE_API_KEY'</span>
+
+_server = WSDL.Proxy(WSDLFILE)
+<span class='pykeyword'>def</span><span class='pyclass'> search</span>(q):
+ <span class='pystring'>"""Search Google and return list of {title, link, description}"""</span>
+ results = _server.doGoogleSearch(
+ APIKEY, q, 0, 10, False, <span class='pystring'>""</span>, False, <span class='pystring'>""</span>, <span class='pystring'>"utf-8"</span>, <span class='pystring'>"utf-8"</span>)
+ <span class='pykeyword'>return</span> [{<span class='pystring'>"title"</span>: r.title.encode(<span class='pystring'>"utf-8"</span>),
+ <span class='pystring'>"link"</span>: r.URL.encode(<span class='pystring'>"utf-8"</span>),
+ <span class='pystring'>"description"</span>: r.snippet.encode(<span class='pystring'>"utf-8"</span>)}
+ <span class='pykeyword'>for</span> r <span class='pykeyword'>in</span> results.resultElements]
+
+<span class='pykeyword'>if</span> __name__ == <span class='pystring'>'__main__'</span>:
+ <span class='pykeyword'>import</span> sys
+ <span class='pykeyword'>for</span> r <span class='pykeyword'>in</span> search(sys.argv[1])[:5]:
+ <span class='pykeyword'>print</span> r[<span class='pystring'>'title'</span>]
+ <span class='pykeyword'>print</span> r[<span class='pystring'>'link'</span>]
+ <span class='pykeyword'>print</span> r[<span class='pystring'>'description'</span>]
+ print</pre></div>
+ <p>You can import this as a module and use it from a larger program, or you can run the script from the command line. On the
+ command line, you give the search query as a command-line argument, and it prints out the URL, title, and description of the
+ top five Google search results.
+ </p>
+ <p>Here is the sample output for a search for the word &#8220;<span class="quote">python</span>&#8221;.
+ </p>
+ <div class="example"><a name="d0e29906"></a><h3 class="title">Example&nbsp;12.2.&nbsp;Sample Usage of <tt class="filename">search.py</tt></h3><pre class="screen">
+<tt class="prompt">C:\diveintopython\common\py&gt;</tt> <span class="userinput">python search.py <span class='pystring'>"python"</span></span>
+<span class="computeroutput">&lt;b&gt;Python&lt;/b&gt; Programming Language
+http://www.python.org/
+Home page for &lt;b&gt;Python&lt;/b&gt;, an interpreted, interactive, object-oriented,
+extensible&lt;br&gt; programming language. &lt;b&gt;...&lt;/b&gt; &lt;b&gt;Python&lt;/b&gt;
+is OSI Certified Open Source: OSI Certified.
+
+&lt;b&gt;Python&lt;/b&gt; Documentation Index
+http://www.python.org/doc/
+ &lt;b&gt;...&lt;/b&gt; New-style classes (aka descrintro). Regular expressions. Database
+API. Email Us.&lt;br&gt; docs@&lt;b&gt;python&lt;/b&gt;.org. (c) 2004. &lt;b&gt;Python&lt;/b&gt;
+Software Foundation. &lt;b&gt;Python&lt;/b&gt; Documentation. &lt;b&gt;...&lt;/b&gt;
+
+Download &lt;b&gt;Python&lt;/b&gt; Software
+http://www.python.org/download/
+Download Standard &lt;b&gt;Python&lt;/b&gt; Software. &lt;b&gt;Python&lt;/b&gt; 2.3.3 is the
+current production&lt;br&gt; version of &lt;b&gt;Python&lt;/b&gt;. &lt;b&gt;...&lt;/b&gt;
+&lt;b&gt;Python&lt;/b&gt; is OSI Certified Open Source:
+
+Pythonline
+http://www.pythonline.com/
+
+
+Dive Into &lt;b&gt;Python&lt;/b&gt;
+http://diveintopython.org/
+Dive Into &lt;b&gt;Python&lt;/b&gt;. &lt;b&gt;Python&lt;/b&gt; from novice to pro. Find:
+&lt;b&gt;...&lt;/b&gt; It is also available in multiple&lt;br&gt; languages. Read
+Dive Into &lt;b&gt;Python&lt;/b&gt;. This book is still being written. &lt;b&gt;...&lt;/b&gt;</span>
+</pre></div>
+ <div class="furtherreading">
+ <h3>Further Reading on <span class="acronym">SOAP</span></h3>
+ <ul>
+ <li><a href="http://www.xmethods.net/">http://www.xmethods.net/</a> is a repository of public access <span class="acronym">SOAP</span> web services.
+ </li>
+ <li>The <a href="http://www.w3.org/TR/soap/"><span class="acronym">SOAP</span> specification</a> is surprisingly readable, if you like that sort of thing.
+ </li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="../http_web_services/summary.html">&lt;&lt;&nbsp;Summary</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<span class="thispage">1</span> <span class="divider">|</span> <a href="install.html" title="12.2.&nbsp;Installing the SOAP Libraries">2</a> <span class="divider">|</span> <a href="first_steps.html" title="12.3.&nbsp;First Steps with SOAP">3</a> <span class="divider">|</span> <a href="debugging.html" title="12.4.&nbsp;Debugging SOAP Web Services">4</a> <span class="divider">|</span> <a href="wsdl.html" title="12.5.&nbsp;Introducing WSDL">5</a> <span class="divider">|</span> <a href="introspection.html" title="12.6.&nbsp;Introspecting SOAP Web Services with WSDL">6</a> <span class="divider">|</span> <a href="google.html" title="12.7.&nbsp;Searching Google">7</a> <span class="divider">|</span> <a href="troubleshooting.html" title="12.8.&nbsp;Troubleshooting SOAP Web Services">8</a> <span class="divider">|</span> <a href="summary.html" title="12.9.&nbsp;Summary">9</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="install.html">Installing the SOAP Libraries&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/soap_web_services/install.html b/help/diveintopython-5.4/html/soap_web_services/install.html
new file mode 100644
index 0000000..5b42ddd
--- /dev/null
+++ b/help/diveintopython-5.4/html/soap_web_services/install.html
@@ -0,0 +1,226 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>12.2.&nbsp;Installing the SOAP Libraries</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;12.&nbsp;SOAP Web Services">
+ <link rel="previous" href="index.html" title="Chapter&nbsp;12.&nbsp;SOAP Web Services">
+ <link rel="next" href="first_steps.html" title="12.3.&nbsp;First Steps with SOAP">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">SOAP Web Services</a>&nbsp;&gt;&nbsp;<span class="thispage">Installing the SOAP Libraries</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="index.html" title="Prev: &#8220;SOAP Web Services&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="first_steps.html" title="Next: &#8220;First Steps with SOAP&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="soap.install"></a>12.2.&nbsp;Installing the SOAP Libraries
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="toc">
+ <ul>
+ <li><span class="section"><a href="install.html#d0e29967">12.2.1. Installing PyXML</a></span></li>
+ <li><span class="section"><a href="install.html#d0e30070">12.2.2. Installing fpconst</a></span></li>
+ <li><span class="section"><a href="install.html#d0e30171">12.2.3. Installing SOAPpy</a></span></li>
+ </ul>
+ </div>
+ <div class="abstract">
+ <p>Unlike the other code in this book, this chapter relies on libraries that do not come pre-installed with <span class="application">Python</span>.
+ </p>
+ </div>
+ <p>Before you can dive into <span class="acronym">SOAP</span> web services, you'll need to install three libraries: <span class="application">PyXML</span>, <span class="application">fpconst</span>, and <span class="application">SOAPpy</span>.
+ </p>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e29967"></a>12.2.1.&nbsp;Installing <span class="application">PyXML</span></h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p>The first library you need is <span class="application">PyXML</span>, an advanced set of <span class="acronym">XML</span> libraries that provide more functionality than the built-in <span class="acronym">XML</span> libraries we studied in <a href="../xml_processing/index.html">Chapter 9</a>.
+ </p>
+ <div class="procedure">
+ <h3 class="title">Procedure&nbsp;12.1.&nbsp;</h3>
+ <p>Here is the procedure for installing <span class="application">PyXML</span>:
+ </p>
+ <ol type="1">
+ <li>
+ <p>Go to <a href="http://pyxml.sourceforge.net/">http://pyxml.sourceforge.net/</a>, click Downloads, and download the latest version for your operating system.
+ </p>
+ </li>
+ <li>
+ <p>If you are using Windows, there are several choices. Make sure to download the version of <span class="application">PyXML</span> that matches the version of <span class="application">Python</span> you are using.
+ </p>
+ </li>
+ <li>
+ <p>Double-click the installer. If you download <span class="application">PyXML</span> 0.8.3 for Windows and <span class="application">Python</span> 2.3, the installer program will be <tt class="filename">PyXML-0.8.3.win32-py2.3.exe</tt>.
+ </p>
+ </li>
+ <li>
+ <p>Step through the installer program.</p>
+ </li>
+ <li>
+ <p>After the installation is complete, close the installer. There will not be any visible indication of success (no programs
+ installed on the Start Menu or shortcuts installed on the desktop). <span class="application">PyXML</span> is simply a collection of <span class="acronym">XML</span> libraries used by other programs.
+ </p>
+ </li>
+ </ol>
+ </div>
+ <p>To verify that you installed <span class="application">PyXML</span> correctly, run your <span class="application">Python</span> <span class="acronym">IDE</span> and check the version of the <span class="acronym">XML</span> libraries you have installed, as shown here.
+ </p>
+ <div class="example"><a name="d0e30044"></a><h3 class="title">Example&nbsp;12.3.&nbsp;Verifying <span class="application">PyXML</span> Installation
+ </h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> xml</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">xml.__version__</span>
+<span class="computeroutput">'0.8.3'</span>
+</pre><p>This version number should match the version number of the <span class="application">PyXML</span> installer program you downloaded and ran.
+ </p>
+ </div>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e30070"></a>12.2.2.&nbsp;Installing <span class="application">fpconst</span></h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p>The second library you need is <span class="application">fpconst</span>, a set of constants and functions for working with IEEE754 double-precision special values. This provides support for the
+ special values Not-a-Number (NaN), Positive Infinity (Inf), and Negative Infinity (-Inf), which are part of the <span class="acronym">SOAP</span> datatype specification.
+ </p>
+ <div class="procedure">
+ <h3 class="title">Procedure&nbsp;12.2.&nbsp;</h3>
+ <p>Here is the procedure for installing <span class="application">fpconst</span>:
+ </p>
+ <ol type="1">
+ <li>
+ <p>Download the latest version of <span class="application">fpconst</span> from <a href="http://www.analytics.washington.edu/statcomp/projects/rzope/fpconst/">http://www.analytics.washington.edu/statcomp/projects/rzope/fpconst/</a>.
+ </p>
+ </li>
+ <li>
+ <p>There are two downloads available, one in <tt class="filename">.tar.gz</tt> format, the other in <tt class="filename">.zip</tt> format. If you are using Windows, download the <tt class="filename">.zip</tt> file; otherwise, download the <tt class="filename">.tar.gz</tt> file.
+ </p>
+ </li>
+ <li>
+ <p>Decompress the downloaded file. On Windows XP, you can right-click on the file and choose Extract All; on earlier versions
+ of Windows, you will need a third-party program such as WinZip. On <span class="abbrev">Mac</span> <span class="acronym">OS</span> X, you can double-click the compressed file to decompress it with Stuffit Expander.
+ </p>
+ </li>
+ <li>
+ <p>Open a command prompt and navigate to the directory where you decompressed the <span class="application">fpconst</span> files.
+ </p>
+ </li>
+ <li>
+ <p>Type <b class="userinput"><tt>python setup.py install</tt></b> to run the installation program.
+ </p>
+ </li>
+ </ol>
+ </div>
+ <p>To verify that you installed <span class="application">fpconst</span> correctly, run your <span class="application">Python</span> <span class="acronym">IDE</span> and check the version number.
+ </p>
+ <div class="example"><a name="d0e30145"></a><h3 class="title">Example&nbsp;12.4.&nbsp;Verifying <span class="application">fpconst</span> Installation
+ </h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> fpconst</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">fpconst.__version__</span>
+<span class="computeroutput">'0.6.0'</span>
+</pre><p>This version number should match the version number of the <span class="application">fpconst</span> archive you downloaded and installed.
+ </p>
+ </div>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h3 class="title"><a name="d0e30171"></a>12.2.3.&nbsp;Installing <span class="application">SOAPpy</span></h3>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p>The third and final requirement is the <span class="acronym">SOAP</span> library itself: <span class="application">SOAPpy</span>.
+ </p>
+ <div class="procedure">
+ <h3 class="title">Procedure&nbsp;12.3.&nbsp;</h3>
+ <p>Here is the procedure for installing <span class="application">SOAPpy</span>:
+ </p>
+ <ol type="1">
+ <li>
+ <p>Go to <a href="http://pywebsvcs.sourceforge.net/">http://pywebsvcs.sourceforge.net/</a> and select Latest Official Release under the <span class="application">SOAPpy</span> section.
+ </p>
+ </li>
+ <li>
+ <p>There are two downloads available. If you are using Windows, download the <tt class="filename">.zip</tt> file; otherwise, download the <tt class="filename">.tar.gz</tt> file.
+ </p>
+ </li>
+ <li>
+ <p>Decompress the downloaded file, just as you did with <span class="application">fpconst</span>.
+ </p>
+ </li>
+ <li>
+ <p>Open a command prompt and navigate to the directory where you decompressed the <span class="application">SOAPpy</span> files.
+ </p>
+ </li>
+ <li>
+ <p>Type <b class="userinput"><tt>python setup.py install</tt></b> to run the installation program.
+ </p>
+ </li>
+ </ol>
+ </div>
+ <p>To verify that you installed <span class="application">SOAPpy</span> correctly, run your <span class="application">Python</span> <span class="acronym">IDE</span> and check the version number.
+ </p>
+ <div class="example"><a name="d0e30237"></a><h3 class="title">Example&nbsp;12.5.&nbsp;Verifying <span class="application">SOAPpy</span> Installation
+ </h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> SOAPpy</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">SOAPpy.__version__</span>
+<span class="computeroutput">'0.11.4'</span>
+</pre><p>This version number should match the version number of the <span class="application">SOAPpy</span> archive you downloaded and installed.
+ </p>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="index.html">&lt;&lt;&nbsp;SOAP Web Services</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#soap.divein" title="12.1.&nbsp;Diving In">1</a> <span class="divider">|</span> <span class="thispage">2</span> <span class="divider">|</span> <a href="first_steps.html" title="12.3.&nbsp;First Steps with SOAP">3</a> <span class="divider">|</span> <a href="debugging.html" title="12.4.&nbsp;Debugging SOAP Web Services">4</a> <span class="divider">|</span> <a href="wsdl.html" title="12.5.&nbsp;Introducing WSDL">5</a> <span class="divider">|</span> <a href="introspection.html" title="12.6.&nbsp;Introspecting SOAP Web Services with WSDL">6</a> <span class="divider">|</span> <a href="google.html" title="12.7.&nbsp;Searching Google">7</a> <span class="divider">|</span> <a href="troubleshooting.html" title="12.8.&nbsp;Troubleshooting SOAP Web Services">8</a> <span class="divider">|</span> <a href="summary.html" title="12.9.&nbsp;Summary">9</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="first_steps.html">First Steps with SOAP&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/soap_web_services/introspection.html b/help/diveintopython-5.4/html/soap_web_services/introspection.html
new file mode 100644
index 0000000..a06a794
--- /dev/null
+++ b/help/diveintopython-5.4/html/soap_web_services/introspection.html
@@ -0,0 +1,232 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>12.6.&nbsp;Introspecting SOAP Web Services with WSDL</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;12.&nbsp;SOAP Web Services">
+ <link rel="previous" href="wsdl.html" title="12.5.&nbsp;Introducing WSDL">
+ <link rel="next" href="google.html" title="12.7.&nbsp;Searching Google">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">SOAP Web Services</a>&nbsp;&gt;&nbsp;<span class="thispage">Introspecting SOAP Web Services with WSDL</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="wsdl.html" title="Prev: &#8220;Introducing WSDL&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="google.html" title="Next: &#8220;Searching Google&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="soap.introspection"></a>12.6.&nbsp;Introspecting <span class="acronym">SOAP</span> Web Services with <span class="acronym">WSDL</span></h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>Like many things in the web services arena, <span class="acronym">WSDL</span> has a long and checkered history, full of political strife and intrigue. I will skip over this history entirely, since it
+ bores me to tears. There were other standards that tried to do similar things, but <span class="acronym">WSDL</span> won, so let's learn how to use it.
+ </p>
+ </div>
+ <p>The most fundamental thing that <span class="acronym">WSDL</span> allows you to do is discover the available methods offered by a <span class="acronym">SOAP</span> server.
+ </p>
+ <div class="example"><a name="d0e30755"></a><h3 class="title">Example&nbsp;12.8.&nbsp;Discovering The Available Methods</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>from</span> SOAPpy <span class='pykeyword'>import</span> WSDL</span> <a name="soap.introspection.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">wsdlFile = <span class='pystring'>'http://www.xmethods.net/sd/2001/TemperatureService.wsdl'</span>)</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">server = WSDL.Proxy(wsdlFile)</span> <a name="soap.introspection.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">server.methods.keys()</span> <a name="soap.introspection.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">[u'getTemp']</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#soap.introspection.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><span class="application">SOAPpy</span> includes a <span class="acronym">WSDL</span> parser. At the time of this writing, it was labeled as being in the early stages of development, but I had no problem parsing
+ any of the <span class="acronym">WSDL</span> files I tried.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#soap.introspection.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">To use a <span class="acronym">WSDL</span> file, you again use a proxy class, <tt class="classname">WSDL.Proxy</tt>, which takes a single argument: the <span class="acronym">WSDL</span> file. Note that in this case you are passing in the <span class="acronym">URL</span> of a <span class="acronym">WSDL</span> file stored on the remote server, but the proxy class works just as well with a local copy of the <span class="acronym">WSDL</span> file. The act of creating the <span class="acronym">WSDL</span> proxy will download the <span class="acronym">WSDL</span> file and parse it, so it there are any errors in the <span class="acronym">WSDL</span> file (or it can't be fetched due to networking problems), you'll know about it immediately.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#soap.introspection.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <span class="acronym">WSDL</span> proxy class exposes the available functions as a <span class="application">Python</span> dictionary, <tt class="varname">server.methods</tt>. So getting the list of available methods is as simple as calling the dictionary method <tt class="methodname">keys()</tt>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>Okay, so you know that this <span class="acronym">SOAP</span> server offers a single method: <tt class="methodname">getTemp</tt>. But how do you call it? The <span class="acronym">WSDL</span> proxy object can tell you that too.
+ </p>
+ <div class="example"><a name="d0e30857"></a><h3 class="title">Example&nbsp;12.9.&nbsp;Discovering A Method's Arguments</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">callInfo = server.methods[<span class='pystring'>'getTemp'</span>]</span> <a name="soap.introspection.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">callInfo.inparams</span> <a name="soap.introspection.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">[&lt;SOAPpy.wstools.WSDLTools.ParameterInfo instance at 0x00CF3AD0&gt;]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">callInfo.inparams[0].name</span> <a name="soap.introspection.2.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">u'zipcode'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">callInfo.inparams[0].type</span> <a name="soap.introspection.2.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">(u'http://www.w3.org/2001/XMLSchema', u'string')</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#soap.introspection.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="varname">server.methods</tt> dictionary is filled with a <span class="application">SOAPpy</span>-specific structure called <tt class="classname">CallInfo</tt>. A <tt class="classname">CallInfo</tt> object contains information about one specific function, including the function arguments.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#soap.introspection.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The function arguments are stored in <tt class="varname">callInfo.inparams</tt>, which is a <span class="application">Python</span> list of <tt class="classname">ParameterInfo</tt> objects that hold information about each parameter.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#soap.introspection.2.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Each <tt class="classname">ParameterInfo</tt> object contains a <tt class="varname">name</tt> attribute, which is the argument name. You are not required to know the argument name to call the function through <span class="acronym">SOAP</span>, but <span class="acronym">SOAP</span> does support calling functions with named arguments (just like <span class="application">Python</span>), and <tt class="classname">WSDL.Proxy</tt> will correctly handle mapping named arguments to the remote function if you choose to use them.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#soap.introspection.2.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Each parameter is also explicitly typed, using datatypes defined in XML Schema. You saw this in the wire trace in the previous
+ section; the XML Schema namespace was part of the &#8220;<span class="quote">boilerplate</span>&#8221; I told you to ignore. For our purposes here, you may continue to ignore it. The <tt class="varname">zipcode</tt> parameter is a string, and if you pass in a <span class="application">Python</span> string to the <tt class="classname">WSDL.Proxy</tt> object, it will map it correctly and send it to the server.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p><span class="acronym">WSDL</span> also lets you introspect into a function's return values.
+ </p>
+ <div class="example"><a name="d0e30967"></a><h3 class="title">Example&nbsp;12.10.&nbsp;Discovering A Method's Return Values</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">callInfo.outparams</span> <a name="soap.introspection.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">[&lt;SOAPpy.wstools.WSDLTools.ParameterInfo instance at 0x00CF3AF8&gt;]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">callInfo.outparams[0].name</span> <a name="soap.introspection.3.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">u'return'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">callInfo.outparams[0].type</span>
+<span class="computeroutput">(u'http://www.w3.org/2001/XMLSchema', u'float')</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#soap.introspection.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The adjunct to <tt class="varname">callInfo.inparams</tt> for function arguments is <tt class="varname">callInfo.outparams</tt> for return value. It is also a list, because functions called through <span class="acronym">SOAP</span> can return multiple values, just like <span class="application">Python</span> functions.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#soap.introspection.3.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Each <tt class="classname">ParameterInfo</tt> object contains <tt class="varname">name</tt> and <tt class="varname">type</tt>. This function returns a single value, named <tt class="varname">return</tt>, which is a float.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>Let's put it all together, and call a <span class="acronym">SOAP</span> web service through a <span class="acronym">WSDL</span> proxy.
+ </p>
+ <div class="example"><a name="d0e31039"></a><h3 class="title">Example&nbsp;12.11.&nbsp;Calling A Web Service Through A <span class="acronym">WSDL</span> Proxy
+ </h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>from</span> SOAPpy <span class='pykeyword'>import</span> WSDL</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">wsdlFile = <span class='pystring'>'http://www.xmethods.net/sd/2001/TemperatureService.wsdl'</span>)</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">server = WSDL.Proxy(wsdlFile)</span> <a name="soap.introspection.4.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">server.getTemp(<span class='pystring'>'90210'</span>)</span> <a name="soap.introspection.4.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">66.0</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">server.soapproxy.config.dumpSOAPOut = 1</span> <a name="soap.introspection.4.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">server.soapproxy.config.dumpSOAPIn = 1</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">temperature = server.getTemp(<span class='pystring'>'90210'</span>)</span>
+<span class="computeroutput">*** Outgoing SOAP ******************************************************
+&lt;?xml version="1.0" encoding="UTF-8"?&gt;
+&lt;SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
+ xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
+ xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
+ xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
+ xmlns:xsd="http://www.w3.org/1999/XMLSchema"&gt;
+&lt;SOAP-ENV:Body&gt;
+&lt;ns1:getTemp xmlns:ns1="urn:xmethods-Temperature" SOAP-ENC:root="1"&gt;
+&lt;v1 xsi:type="xsd:string"&gt;90210&lt;/v1&gt;
+&lt;/ns1:getTemp&gt;
+&lt;/SOAP-ENV:Body&gt;
+&lt;/SOAP-ENV:Envelope&gt;
+************************************************************************
+*** Incoming SOAP ******************************************************
+&lt;?xml version='1.0' encoding='UTF-8'?&gt;
+&lt;SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"&gt;
+&lt;SOAP-ENV:Body&gt;
+&lt;ns1:getTempResponse xmlns:ns1="urn:xmethods-Temperature"
+ SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"&gt;
+&lt;return xsi:type="xsd:float"&gt;66.0&lt;/return&gt;
+&lt;/ns1:getTempResponse&gt;
+
+&lt;/SOAP-ENV:Body&gt;
+&lt;/SOAP-ENV:Envelope&gt;
+************************************************************************
+</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">temperature</span>
+<span class="computeroutput">66.0</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#soap.introspection.4.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The configuration is simpler than calling the <span class="acronym">SOAP</span> service directly, since the <span class="acronym">WSDL</span> file contains the both service <span class="acronym">URL</span> and namespace you need to call the service. Creating the <tt class="classname">WSDL.Proxy</tt> object downloads the <span class="acronym">WSDL</span> file, parses it, and configures a <tt class="classname">SOAPProxy</tt> object that it uses to call the actual <span class="acronym">SOAP</span> web service.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#soap.introspection.4.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Once the <tt class="classname">WSDL.Proxy</tt> object is created, you can call a function as easily as you did with the <tt class="classname">SOAPProxy</tt> object. This is not surprising; the <tt class="classname">WSDL.Proxy</tt> is just a wrapper around the <tt class="classname">SOAPProxy</tt> with some introspection methods added, so the syntax for calling functions is the same.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#soap.introspection.4.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You can access the <tt class="classname">WSDL.Proxy</tt>'s <tt class="classname">SOAPProxy</tt> with <tt class="varname">server.soapproxy</tt>. This is useful to turning on debugging, so that when you can call functions through the <span class="acronym">WSDL</span> proxy, its <tt class="classname">SOAPProxy</tt> will dump the outgoing and incoming XML documents that are going over the wire.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="wsdl.html">&lt;&lt;&nbsp;Introducing WSDL</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#soap.divein" title="12.1.&nbsp;Diving In">1</a> <span class="divider">|</span> <a href="install.html" title="12.2.&nbsp;Installing the SOAP Libraries">2</a> <span class="divider">|</span> <a href="first_steps.html" title="12.3.&nbsp;First Steps with SOAP">3</a> <span class="divider">|</span> <a href="debugging.html" title="12.4.&nbsp;Debugging SOAP Web Services">4</a> <span class="divider">|</span> <a href="wsdl.html" title="12.5.&nbsp;Introducing WSDL">5</a> <span class="divider">|</span> <span class="thispage">6</span> <span class="divider">|</span> <a href="google.html" title="12.7.&nbsp;Searching Google">7</a> <span class="divider">|</span> <a href="troubleshooting.html" title="12.8.&nbsp;Troubleshooting SOAP Web Services">8</a> <span class="divider">|</span> <a href="summary.html" title="12.9.&nbsp;Summary">9</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="google.html">Searching Google&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/soap_web_services/summary.html b/help/diveintopython-5.4/html/soap_web_services/summary.html
new file mode 100644
index 0000000..bb97d34
--- /dev/null
+++ b/help/diveintopython-5.4/html/soap_web_services/summary.html
@@ -0,0 +1,84 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>12.9.&nbsp;Summary</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;12.&nbsp;SOAP Web Services">
+ <link rel="previous" href="troubleshooting.html" title="12.8.&nbsp;Troubleshooting SOAP Web Services">
+ <link rel="next" href="../unit_testing/index.html" title="Chapter&nbsp;13.&nbsp;Unit Testing">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">SOAP Web Services</a>&nbsp;&gt;&nbsp;<span class="thispage">Summary</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="troubleshooting.html" title="Prev: &#8220;Troubleshooting SOAP Web Services&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="../unit_testing/index.html" title="Next: &#8220;Unit Testing&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="soap.summary"></a>12.9.&nbsp;Summary
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p><span class="acronym">SOAP</span> web services are very complicated. The specification is very ambitious and tries to cover many different use cases for web
+ services. This chapter has touched on some of the simpler use cases.
+ </p>
+ </div>
+ <div class="highlights">
+ <p>Before diving into the next chapter, make sure you're comfortable doing all of these things:</p>
+ <div class="itemizedlist">
+ <ul>
+ <li>Connecting to a <span class="acronym">SOAP</span> server and calling remote methods
+ </li>
+ <li>Loading a <span class="acronym">WSDL</span> file and introspecting remote methods
+ </li>
+ <li>Debugging <span class="acronym">SOAP</span> calls with wire traces
+ </li>
+ <li>Troubleshooting common <span class="acronym">SOAP</span>-related errors
+ </li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="troubleshooting.html">&lt;&lt;&nbsp;Troubleshooting SOAP Web Services</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#soap.divein" title="12.1.&nbsp;Diving In">1</a> <span class="divider">|</span> <a href="install.html" title="12.2.&nbsp;Installing the SOAP Libraries">2</a> <span class="divider">|</span> <a href="first_steps.html" title="12.3.&nbsp;First Steps with SOAP">3</a> <span class="divider">|</span> <a href="debugging.html" title="12.4.&nbsp;Debugging SOAP Web Services">4</a> <span class="divider">|</span> <a href="wsdl.html" title="12.5.&nbsp;Introducing WSDL">5</a> <span class="divider">|</span> <a href="introspection.html" title="12.6.&nbsp;Introspecting SOAP Web Services with WSDL">6</a> <span class="divider">|</span> <a href="google.html" title="12.7.&nbsp;Searching Google">7</a> <span class="divider">|</span> <a href="troubleshooting.html" title="12.8.&nbsp;Troubleshooting SOAP Web Services">8</a> <span class="divider">|</span> <span class="thispage">9</span>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="../unit_testing/index.html">Unit Testing&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/soap_web_services/troubleshooting.html b/help/diveintopython-5.4/html/soap_web_services/troubleshooting.html
new file mode 100644
index 0000000..a677786
--- /dev/null
+++ b/help/diveintopython-5.4/html/soap_web_services/troubleshooting.html
@@ -0,0 +1,271 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>12.8.&nbsp;Troubleshooting SOAP Web Services</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;12.&nbsp;SOAP Web Services">
+ <link rel="previous" href="google.html" title="12.7.&nbsp;Searching Google">
+ <link rel="next" href="summary.html" title="12.9.&nbsp;Summary">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">SOAP Web Services</a>&nbsp;&gt;&nbsp;<span class="thispage">Troubleshooting SOAP Web Services</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="google.html" title="Prev: &#8220;Searching Google&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="summary.html" title="Next: &#8220;Summary&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="soap.troubleshooting"></a>12.8.&nbsp;Troubleshooting <span class="acronym">SOAP</span> Web Services
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>Of course, the world of <span class="acronym">SOAP</span> web services is not all happiness and light. Sometimes things go wrong.
+ </p>
+ </div>
+ <p>As you've seen throughout this chapter, <span class="acronym">SOAP</span> involves several layers. There's the HTTP layer, since <span class="acronym">SOAP</span> is sending XML documents to, and receiving XML documents from, an HTTP server. So all the debugging techniques you learned
+ in <a href="../http_web_services/index.html" title="Chapter&nbsp;11.&nbsp;HTTP Web Services">Chapter&nbsp;11, <i>HTTP Web Services</i></a> come into play here. You can <b class="userinput"><tt>import httplib</tt></b> and then set <b class="userinput"><tt>httplib.HTTPConnection.debuglevel = 1</tt></b> to see the underlying HTTP traffic.
+ </p>
+ <p>Beyond the underlying HTTP layer, there are a number of things that can go wrong. <span class="application">SOAPpy</span> does an admirable job hiding the <span class="acronym">SOAP</span> syntax from you, but that also means it can be difficult to determine where the problem is when things don't work.
+ </p>
+ <p>Here are a few examples of common mistakes that I've made in using <span class="acronym">SOAP</span> web services, and the errors they generated.
+ </p>
+ <div class="example"><a name="d0e31615"></a><h3 class="title">Example&nbsp;12.15.&nbsp;Calling a Method With an Incorrectly Configured Proxy</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>from</span> SOAPpy <span class='pykeyword'>import</span> SOAPProxy</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">url = <span class='pystring'>'http://services.xmethods.net:80/soap/servlet/rpcrouter'</span></span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">server = SOAPProxy(url)</span> <a name="soap.troubleshooting.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">server.getTemp(<span class='pystring'>'27502'</span>)</span> <a name="soap.troubleshooting.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="traceback">&lt;Fault SOAP-ENV:Server.BadTargetObjectURI:
+Unable to determine object id from call: is the method element namespaced?&gt;
+Traceback (most recent call last):
+ File "&lt;stdin&gt;", line 1, in ?
+ File "c:\python23\Lib\site-packages\SOAPpy\Client.py", line 453, in __call__
+ return self.__r_call(*args, **kw)
+ File "c:\python23\Lib\site-packages\SOAPpy\Client.py", line 475, in __r_call
+ self.__hd, self.__ma)
+ File "c:\python23\Lib\site-packages\SOAPpy\Client.py", line 389, in __call
+ raise p
+SOAPpy.Types.faultType: &lt;Fault SOAP-ENV:Server.BadTargetObjectURI:
+Unable to determine object id from call: is the method element namespaced?&gt;</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#soap.troubleshooting.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Did you spot the mistake? You're creating a <tt class="classname">SOAPProxy</tt> manually, and you've correctly specified the service <span class="acronym">URL</span>, but you haven't specified the namespace. Since multiple services may be routed through the same service <span class="acronym">URL</span>, the namespace is essential to determine which service you're trying to talk to, and therefore which method you're really
+ calling.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#soap.troubleshooting.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The server responds by sending a <span class="acronym">SOAP</span> Fault, which <span class="application">SOAPpy</span> turns into a <span class="application">Python</span> exception of type <tt class="classname">SOAPpy.Types.faultType</tt>. All errors returned from any <span class="acronym">SOAP</span> server will always be <span class="acronym">SOAP</span> Faults, so you can easily catch this exception. In this case, the human-readable part of the <span class="acronym">SOAP</span> Fault gives a clue to the problem: the method element is not namespaced, because the original <tt class="classname">SOAPProxy</tt> object was not configured with a service namespace.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>Misconfiguring the basic elements of the <span class="acronym">SOAP</span> service is one of the problems that <span class="acronym">WSDL</span> aims to solve. The <span class="acronym">WSDL</span> file contains the service <span class="acronym">URL</span> and namespace, so you can't get it wrong. Of course, there are still other things you can get wrong.
+ </p>
+ <div class="example"><a name="d0e31701"></a><h3 class="title">Example&nbsp;12.16.&nbsp;Calling a Method With the Wrong Arguments</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">wsdlFile = <span class='pystring'>'http://www.xmethods.net/sd/2001/TemperatureService.wsdl'</span></span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">server = WSDL.Proxy(wsdlFile)</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">temperature = server.getTemp(27502)</span> <a name="soap.troubleshooting.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="traceback">&lt;Fault SOAP-ENV:Server: Exception while handling service request:
+services.temperature.TempService.getTemp(int) -- no signature match&gt; <a name="soap.troubleshooting.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+Traceback (most recent call last):
+ File "&lt;stdin&gt;", line 1, in ?
+ File "c:\python23\Lib\site-packages\SOAPpy\Client.py", line 453, in __call__
+ return self.__r_call(*args, **kw)
+ File "c:\python23\Lib\site-packages\SOAPpy\Client.py", line 475, in __r_call
+ self.__hd, self.__ma)
+ File "c:\python23\Lib\site-packages\SOAPpy\Client.py", line 389, in __call
+ raise p
+SOAPpy.Types.faultType: &lt;Fault SOAP-ENV:Server: Exception while handling service request:
+services.temperature.TempService.getTemp(int) -- no signature match&gt;</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#soap.troubleshooting.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Did you spot the mistake? It's a subtle one: you're calling <tt class="function">server.getTemp</tt> with an integer instead of a string. As you saw from introspecting the <span class="acronym">WSDL</span> file, the <tt class="function">getTemp()</tt> <span class="acronym">SOAP</span> function takes a single argument, <tt class="varname">zipcode</tt>, which must be a string. <tt class="classname">WSDL.Proxy</tt> will <span class="emphasis"><em>not</em></span> coerce datatypes for you; you need to pass the exact datatypes that the server expects.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#soap.troubleshooting.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Again, the server returns a <span class="acronym">SOAP</span> Fault, and the human-readable part of the error gives a clue as to the problem: you're calling a <tt class="function">getTemp</tt> function with an integer value, but there is no function defined with that name that takes an integer. In theory, <span class="acronym">SOAP</span> allows you to <span class="emphasis"><em>overload</em></span> functions, so you could have two functions in the same <span class="acronym">SOAP</span> service with the same name and the same number of arguments, but the arguments were of different datatypes. This is why
+ it's important to match the datatypes exactly, and why <tt class="classname">WSDL.Proxy</tt> doesn't coerce datatypes for you. If it did, you could end up calling a completely different function! Good luck debugging
+ that one. It's much easier to be picky about datatypes and fail as quickly as possible if you get them wrong.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>It's also possible to write <span class="application">Python</span> code that expects a different number of return values than the remote function actually returns.
+ </p>
+ <div class="example"><a name="d0e31779"></a><h3 class="title">Example&nbsp;12.17.&nbsp;Calling a Method and Expecting the Wrong Number of Return Values</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">wsdlFile = <span class='pystring'>'http://www.xmethods.net/sd/2001/TemperatureService.wsdl'</span></span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">server = WSDL.Proxy(wsdlFile)</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">(city, temperature) = server.getTemp(27502)</span> <a name="soap.troubleshooting.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="traceback">Traceback (most recent call last):
+ File "&lt;stdin&gt;", line 1, in ?
+TypeError: unpack non-sequence</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#soap.troubleshooting.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Did you spot the mistake? <tt class="function">server.getTemp</tt> only returns one value, a float, but you've written code that assumes you're getting two values and trying to assign them
+ to two different variables. Note that this does not fail with a <span class="acronym">SOAP</span> fault. As far as the remote server is concerned, nothing went wrong at all. The error only occurred <span class="emphasis"><em>after</em></span> the <span class="acronym">SOAP</span> transaction was complete, <tt class="classname">WSDL.Proxy</tt> returned a float, and your local <span class="application">Python</span> interpreter tried to accomodate your request to split it into two different variables. Since the function only returned
+ one value, you get a <span class="application">Python</span> exception trying to split it, not a <span class="acronym">SOAP</span> Fault.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>What about Google's web service? The most common problem I've had with it is that I forget to set the application key properly.</p>
+ <div class="example"><a name="d0e31834"></a><h3 class="title">Example&nbsp;12.18.&nbsp;Calling a Method With An Application-Specific Error</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>from</span> SOAPpy <span class='pykeyword'>import</span> WSDL</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">server = WSDL.Proxy(r<span class='pystring'>'/path/to/local/GoogleSearch.wsdl'</span>)</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">results = server.doGoogleSearch(<span class='pystring'>'foo'</span>, <span class='pystring'>'mark'</span>, 0, 10, False, <span class='pystring'>""</span>,</span> <a name="soap.troubleshooting.4.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">... </tt><span class="userinput">False, <span class='pystring'>""</span>, <span class='pystring'>"utf-8"</span>, <span class='pystring'>"utf-8"</span>)</span>
+<span class="traceback">&lt;Fault SOAP-ENV:Server: <a name="soap.troubleshooting.4.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+ Exception from service object: Invalid authorization key: foo:
+ &lt;SOAPpy.Types.structType detail at 14164616&gt;:
+ {'stackTrace':
+ 'com.google.soap.search.GoogleSearchFault: Invalid authorization key: foo
+ at com.google.soap.search.QueryLimits.lookUpAndLoadFromINSIfNeedBe(
+ QueryLimits.java:220)
+ at com.google.soap.search.QueryLimits.validateKey(QueryLimits.java:127)
+ at com.google.soap.search.GoogleSearchService.doPublicMethodChecks(
+ GoogleSearchService.java:825)
+ at com.google.soap.search.GoogleSearchService.doGoogleSearch(
+ GoogleSearchService.java:121)
+ at sun.reflect.GeneratedMethodAccessor13.invoke(Unknown Source)
+ at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
+ at java.lang.reflect.Method.invoke(Unknown Source)
+ at org.apache.soap.server.RPCRouter.invoke(RPCRouter.java:146)
+ at org.apache.soap.providers.RPCJavaProvider.invoke(
+ RPCJavaProvider.java:129)
+ at org.apache.soap.server.http.RPCRouterServlet.doPost(
+ RPCRouterServlet.java:288)
+ at javax.servlet.http.HttpServlet.service(HttpServlet.java:760)
+ at javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
+ at com.google.gse.HttpConnection.runServlet(HttpConnection.java:237)
+ at com.google.gse.HttpConnection.run(HttpConnection.java:195)
+ at com.google.gse.DispatchQueue$WorkerThread.run(DispatchQueue.java:201)
+Caused by: com.google.soap.search.UserKeyInvalidException: Key was of wrong size.
+ at com.google.soap.search.UserKey.&lt;init&gt;(UserKey.java:59)
+ at com.google.soap.search.QueryLimits.lookUpAndLoadFromINSIfNeedBe(
+ QueryLimits.java:217)
+ ... 14 more
+'}&gt;
+Traceback (most recent call last):
+ File "&lt;stdin&gt;", line 1, in ?
+ File "c:\python23\Lib\site-packages\SOAPpy\Client.py", line 453, in __call__
+ return self.__r_call(*args, **kw)
+ File "c:\python23\Lib\site-packages\SOAPpy\Client.py", line 475, in __r_call
+ self.__hd, self.__ma)
+ File "c:\python23\Lib\site-packages\SOAPpy\Client.py", line 389, in __call
+ raise p
+SOAPpy.Types.faultType: &lt;Fault SOAP-ENV:Server: Exception from service object:
+Invalid authorization key: foo:
+&lt;SOAPpy.Types.structType detail at 14164616&gt;:
+{'stackTrace':
+ 'com.google.soap.search.GoogleSearchFault: Invalid authorization key: foo
+ at com.google.soap.search.QueryLimits.lookUpAndLoadFromINSIfNeedBe(
+ QueryLimits.java:220)
+ at com.google.soap.search.QueryLimits.validateKey(QueryLimits.java:127)
+ at com.google.soap.search.GoogleSearchService.doPublicMethodChecks(
+ GoogleSearchService.java:825)
+ at com.google.soap.search.GoogleSearchService.doGoogleSearch(
+ GoogleSearchService.java:121)
+ at sun.reflect.GeneratedMethodAccessor13.invoke(Unknown Source)
+ at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
+ at java.lang.reflect.Method.invoke(Unknown Source)
+ at org.apache.soap.server.RPCRouter.invoke(RPCRouter.java:146)
+ at org.apache.soap.providers.RPCJavaProvider.invoke(
+ RPCJavaProvider.java:129)
+ at org.apache.soap.server.http.RPCRouterServlet.doPost(
+ RPCRouterServlet.java:288)
+ at javax.servlet.http.HttpServlet.service(HttpServlet.java:760)
+ at javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
+ at com.google.gse.HttpConnection.runServlet(HttpConnection.java:237)
+ at com.google.gse.HttpConnection.run(HttpConnection.java:195)
+ at com.google.gse.DispatchQueue$WorkerThread.run(DispatchQueue.java:201)
+Caused by: com.google.soap.search.UserKeyInvalidException: Key was of wrong size.
+ at com.google.soap.search.UserKey.&lt;init&gt;(UserKey.java:59)
+ at com.google.soap.search.QueryLimits.lookUpAndLoadFromINSIfNeedBe(
+ QueryLimits.java:217)
+ ... 14 more
+'}&gt;</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#soap.troubleshooting.4.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Can you spot the mistake? There's nothing wrong with the calling syntax, or the number of arguments, or the datatypes. The
+ problem is application-specific: the first argument is supposed to be my application key, but <tt class="literal">foo</tt> is not a valid Google key.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#soap.troubleshooting.4.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The Google server responds with a <span class="acronym">SOAP</span> Fault and an incredibly long error message, which includes a complete Java stack trace. Remember that <span class="emphasis"><em>all</em></span> <span class="acronym">SOAP</span> errors are signified by <span class="acronym">SOAP</span> Faults: errors in configuration, errors in function arguments, and application-specific errors like this. Buried in there
+ somewhere is the crucial piece of information: <tt class="literal">Invalid authorization key: foo</tt>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="furtherreading">
+ <h3>Further Reading on Troubleshooting <span class="acronym">SOAP</span></h3>
+ <ul>
+ <li><a href="http://www-106.ibm.com/developerworks/webservices/library/ws-pyth17.html">New developments for <span class="application">SOAPpy</span></a> steps through trying to connect to another <span class="acronym">SOAP</span> service that doesn't quite work as advertised.
+ </li>
+ </ul>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="google.html">&lt;&lt;&nbsp;Searching Google</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#soap.divein" title="12.1.&nbsp;Diving In">1</a> <span class="divider">|</span> <a href="install.html" title="12.2.&nbsp;Installing the SOAP Libraries">2</a> <span class="divider">|</span> <a href="first_steps.html" title="12.3.&nbsp;First Steps with SOAP">3</a> <span class="divider">|</span> <a href="debugging.html" title="12.4.&nbsp;Debugging SOAP Web Services">4</a> <span class="divider">|</span> <a href="wsdl.html" title="12.5.&nbsp;Introducing WSDL">5</a> <span class="divider">|</span> <a href="introspection.html" title="12.6.&nbsp;Introspecting SOAP Web Services with WSDL">6</a> <span class="divider">|</span> <a href="google.html" title="12.7.&nbsp;Searching Google">7</a> <span class="divider">|</span> <span class="thispage">8</span> <span class="divider">|</span> <a href="summary.html" title="12.9.&nbsp;Summary">9</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="summary.html">Summary&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/soap_web_services/wsdl.html b/help/diveintopython-5.4/html/soap_web_services/wsdl.html
new file mode 100644
index 0000000..7e0a635
--- /dev/null
+++ b/help/diveintopython-5.4/html/soap_web_services/wsdl.html
@@ -0,0 +1,99 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>12.5.&nbsp;Introducing WSDL</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;12.&nbsp;SOAP Web Services">
+ <link rel="previous" href="debugging.html" title="12.4.&nbsp;Debugging SOAP Web Services">
+ <link rel="next" href="introspection.html" title="12.6.&nbsp;Introspecting SOAP Web Services with WSDL">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">SOAP Web Services</a>&nbsp;&gt;&nbsp;<span class="thispage">Introducing WSDL</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="debugging.html" title="Prev: &#8220;Debugging SOAP Web Services&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="introspection.html" title="Next: &#8220;Introspecting SOAP Web Services with WSDL&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="soap.wsdl"></a>12.5.&nbsp;Introducing <span class="acronym">WSDL</span></h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>The <tt class="classname">SOAPProxy</tt> class proxies local method calls and transparently turns then into invocations of remote <span class="acronym">SOAP</span> methods. As you've seen, this is a lot of work, and <tt class="classname">SOAPProxy</tt> does it quickly and transparently. What it doesn't do is provide any means of method introspection.
+ </p>
+ </div>
+ <p>Consider this: the previous two sections showed an example of calling a simple remote <span class="acronym">SOAP</span> method with one argument and one return value, both of simple data types. This required knowing, and keeping track of, the
+ service <span class="acronym">URL</span>, the service namespace, the function name, the number of arguments, and the datatype of each argument. If any of these is
+ missing or wrong, the whole thing falls apart.
+ </p>
+ <p>That shouldn't come as a big surprise. If I wanted to call a local function, I would need to know what package or module
+ it was in (the equivalent of service <span class="acronym">URL</span> and namespace). I would need to know the correct function name and the correct number of arguments. <span class="application">Python</span> deftly handles datatyping without explicit types, but I would still need to know how many argument to pass, and how many
+ return values to expect.
+ </p>
+ <p>The big difference is introspection. As you saw in <a href="../power_of_introspection/index.html">Chapter 4</a>, <span class="application">Python</span> excels at letting you discover things about modules and functions at runtime. You can list the available functions within
+ a module, and with a little work, drill down to individual function declarations and arguments.
+ </p>
+ <p><span class="acronym">WSDL</span> lets you do that with <span class="acronym">SOAP</span> web services. <span class="acronym">WSDL</span> stands for &#8220;<span class="quote">Web Services Description Language</span>&#8221;. Although designed to be flexible enough to describe many types of web services, it is most often used to describe <span class="acronym">SOAP</span> web services.
+ </p>
+ <p>A <span class="acronym">WSDL</span> file is just that: a file. More specifically, it's an XML file. It usually lives on the same server you use to access the
+ <span class="acronym">SOAP</span> web services it describes, although there's nothing special about it. Later in this chapter, we'll download the <span class="acronym">WSDL</span> file for the Google API and use it locally. That doesn't mean we're calling Google locally; the <span class="acronym">WSDL</span> file still describes the remote functions sitting on Google's server.
+ </p>
+ <p>A <span class="acronym">WSDL</span> file contains a description of everything involved in calling a <span class="acronym">SOAP</span> web service:
+ </p>
+ <div class="itemizedlist">
+ <ul>
+ <li>The service <span class="acronym">URL</span> and namespace
+ </li>
+ <li>The type of web service (probably function calls using <span class="acronym">SOAP</span>, although as I mentioned, <span class="acronym">WSDL</span> is flexible enough to describe a wide variety of web services)
+ </li>
+ <li>The list of available functions</li>
+ <li>The arguments for each function</li>
+ <li>The datatype of each argument</li>
+ <li>The return values of each function, and the datatype of each return value</li>
+ </ul>
+ </div>
+ <p>In other words, a <span class="acronym">WSDL</span> file tells you everything you need to know to be able to call a <span class="acronym">SOAP</span> web service.
+ </p>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="debugging.html">&lt;&lt;&nbsp;Debugging SOAP Web Services</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#soap.divein" title="12.1.&nbsp;Diving In">1</a> <span class="divider">|</span> <a href="install.html" title="12.2.&nbsp;Installing the SOAP Libraries">2</a> <span class="divider">|</span> <a href="first_steps.html" title="12.3.&nbsp;First Steps with SOAP">3</a> <span class="divider">|</span> <a href="debugging.html" title="12.4.&nbsp;Debugging SOAP Web Services">4</a> <span class="divider">|</span> <span class="thispage">5</span> <span class="divider">|</span> <a href="introspection.html" title="12.6.&nbsp;Introspecting SOAP Web Services with WSDL">6</a> <span class="divider">|</span> <a href="google.html" title="12.7.&nbsp;Searching Google">7</a> <span class="divider">|</span> <a href="troubleshooting.html" title="12.8.&nbsp;Troubleshooting SOAP Web Services">8</a> <span class="divider">|</span> <a href="summary.html" title="12.9.&nbsp;Summary">9</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="introspection.html">Introspecting SOAP Web Services with WSDL&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/toc/index.html b/help/diveintopython-5.4/html/toc/index.html
new file mode 100644
index 0000000..cbbcc76
--- /dev/null
+++ b/help/diveintopython-5.4/html/toc/index.html
@@ -0,0 +1,393 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>Dive Into Python</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="description" content=" This book lives at . If you're reading it somewhere else, you may not have the latest version.">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="index.html" title="Dive Into Python">
+ <link rel="next" href="../installing_python/index.html" title="Chapter&nbsp;1.&nbsp;Installing Python">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<span class="thispage">Dive Into Python</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="../installing_python/index.html" title="Next: &#8220;Installing Python&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="book" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h1 class="title"><a name="d0e1"></a>Dive Into <span class="application">Python</span></h1>
+ </div>
+ <div>
+ <p class="pubdate">20 May 2004</p>
+ </div>
+ <div>
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ <div>
+ <div class="abstract">
+ <h3 class="title"></h3>
+ <p>This book lives at <a href="http://diveintopython.org/">http://diveintopython.org/</a>. If you're reading it somewhere else, you may not have the latest version.
+ </p>
+ </div>
+ </div>
+ <div>
+ <div class="legalnotice">
+ <p>Permission is granted to copy, distribute, and/or modify this document under the terms of the <span class="acronym">GNU</span> Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation; with no Invariant
+ Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in <a href="../appendix/fdl.html" title="Appendix&nbsp;G.&nbsp;GNU Free Documentation License">Appendix&nbsp;G, <i>GNU Free Documentation License</i></a>.
+ </p>
+ <p>The example programs in this book are free software; you can redistribute and/or modify them under the terms of the <span class="application">Python</span> license as published by the <span class="application">Python</span> Software Foundation. A copy of the license is included in <a href="../appendix/license.html" title="Appendix&nbsp;H.&nbsp;Python license">Appendix&nbsp;H, <i>Python license</i></a>.
+ </p>
+ </div>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="toc">
+ <p><b>Table of Contents</b></p>
+ <ul>
+ <li><span class="chapter"><a href="../installing_python/index.html">1. Installing Python</a></span><ul>
+ <li><span class="section"><a href="../installing_python/index.html#install.choosing">1.1. Which Python is right for you?</a></span></li>
+ <li><span class="section"><a href="../installing_python/windows.html">1.2. Python on Windows</a></span></li>
+ <li><span class="section"><a href="../installing_python/macosx.html">1.3. Python on Mac OS X</a></span></li>
+ <li><span class="section"><a href="../installing_python/macos9.html">1.4. Python on Mac OS 9</a></span></li>
+ <li><span class="section"><a href="../installing_python/redhat.html">1.5. Python on RedHat Linux</a></span></li>
+ <li><span class="section"><a href="../installing_python/debian.html">1.6. Python on Debian GNU/Linux</a></span></li>
+ <li><span class="section"><a href="../installing_python/source.html">1.7. Python Installation from Source</a></span></li>
+ <li><span class="section"><a href="../installing_python/shell.html">1.8. The Interactive Shell</a></span></li>
+ <li><span class="section"><a href="../installing_python/summary.html">1.9. Summary</a></span></li>
+ </ul>
+ </li>
+ <li><span class="chapter"><a href="../getting_to_know_python/index.html">2. Your First Python Program</a></span><ul>
+ <li><span class="section"><a href="../getting_to_know_python/index.html#odbchelper.divein">2.1. Diving in</a></span></li>
+ <li><span class="section"><a href="../getting_to_know_python/declaring_functions.html">2.2. Declaring Functions</a></span><ul>
+ <li><span class="section"><a href="../getting_to_know_python/declaring_functions.html#d0e4188">2.2.1. How Python's Datatypes Compare to Other Programming Languages</a></span></li>
+ </ul>
+ </li>
+ <li><span class="section"><a href="../getting_to_know_python/documenting_functions.html">2.3. Documenting Functions</a></span></li>
+ <li><span class="section"><a href="../getting_to_know_python/everything_is_an_object.html">2.4. Everything Is an Object</a></span><ul>
+ <li><span class="section"><a href="../getting_to_know_python/everything_is_an_object.html#d0e4550">2.4.1. The Import Search Path</a></span></li>
+ <li><span class="section"><a href="../getting_to_know_python/everything_is_an_object.html#d0e4665">2.4.2. What's an Object?</a></span></li>
+ </ul>
+ </li>
+ <li><span class="section"><a href="../getting_to_know_python/indenting_code.html">2.5. Indenting Code</a></span></li>
+ <li><span class="section"><a href="../getting_to_know_python/testing_modules.html">2.6. Testing Modules</a></span></li>
+ </ul>
+ </li>
+ <li><span class="chapter"><a href="../native_data_types/index.html">3. Native Datatypes</a></span><ul>
+ <li><span class="section"><a href="../native_data_types/index.html#odbchelper.dict">3.1. Introducing Dictionaries</a></span><ul>
+ <li><span class="section"><a href="../native_data_types/index.html#d0e5174">3.1.1. Defining Dictionaries</a></span></li>
+ <li><span class="section"><a href="../native_data_types/index.html#d0e5269">3.1.2. Modifying Dictionaries</a></span></li>
+ <li><span class="section"><a href="../native_data_types/index.html#d0e5450">3.1.3. Deleting Items From Dictionaries</a></span></li>
+ </ul>
+ </li>
+ <li><span class="section"><a href="../native_data_types/lists.html">3.2. Introducing Lists</a></span><ul>
+ <li><span class="section"><a href="../native_data_types/lists.html#d0e5623">3.2.1. Defining Lists</a></span></li>
+ <li><span class="section"><a href="../native_data_types/lists.html#d0e5887">3.2.2. Adding Elements to Lists</a></span></li>
+ <li><span class="section"><a href="../native_data_types/lists.html#d0e6115">3.2.3. Searching Lists</a></span></li>
+ <li><span class="section"><a href="../native_data_types/lists.html#d0e6277">3.2.4. Deleting List Elements</a></span></li>
+ <li><span class="section"><a href="../native_data_types/lists.html#d0e6392">3.2.5. Using List Operators</a></span></li>
+ </ul>
+ </li>
+ <li><span class="section"><a href="../native_data_types/tuples.html">3.3. Introducing Tuples</a></span></li>
+ <li><span class="section"><a href="../native_data_types/declaring_variables.html">3.4. Declaring variables</a></span><ul>
+ <li><span class="section"><a href="../native_data_types/declaring_variables.html#d0e6873">3.4.1. Referencing Variables</a></span></li>
+ <li><span class="section"><a href="../native_data_types/declaring_variables.html#odbchelper.multiassign">3.4.2. Assigning Multiple Values at Once</a></span></li>
+ </ul>
+ </li>
+ <li><span class="section"><a href="../native_data_types/formatting_strings.html">3.5. Formatting Strings</a></span></li>
+ <li><span class="section"><a href="../native_data_types/mapping_lists.html">3.6. Mapping Lists</a></span></li>
+ <li><span class="section"><a href="../native_data_types/joining_lists.html">3.7. Joining Lists and Splitting Strings</a></span><ul>
+ <li><span class="section"><a href="../native_data_types/joining_lists.html#d0e7982">3.7.1. Historical Note on String Methods</a></span></li>
+ </ul>
+ </li>
+ <li><span class="section"><a href="../native_data_types/summary.html">3.8. Summary</a></span></li>
+ </ul>
+ </li>
+ <li><span class="chapter"><a href="../power_of_introspection/index.html">4. The Power Of Introspection</a></span><ul>
+ <li><span class="section"><a href="../power_of_introspection/index.html#apihelper.divein">4.1. Diving In</a></span></li>
+ <li><span class="section"><a href="../power_of_introspection/optional_arguments.html">4.2. Using Optional and Named Arguments</a></span></li>
+ <li><span class="section"><a href="../power_of_introspection/built_in_functions.html">4.3. Using type, str, dir, and Other Built-In Functions</a></span><ul>
+ <li><span class="section"><a href="../power_of_introspection/built_in_functions.html#d0e8510">4.3.1. The type Function</a></span></li>
+ <li><span class="section"><a href="../power_of_introspection/built_in_functions.html#d0e8609">4.3.2. The str Function</a></span></li>
+ <li><span class="section"><a href="../power_of_introspection/built_in_functions.html#d0e8958">4.3.3. Built-In Functions</a></span></li>
+ </ul>
+ </li>
+ <li><span class="section"><a href="../power_of_introspection/getattr.html">4.4. Getting Object References With getattr</a></span><ul>
+ <li><span class="section"><a href="../power_of_introspection/getattr.html#d0e9194">4.4.1. getattr with Modules</a></span></li>
+ <li><span class="section"><a href="../power_of_introspection/getattr.html#d0e9362">4.4.2. getattr As a Dispatcher</a></span></li>
+ </ul>
+ </li>
+ <li><span class="section"><a href="../power_of_introspection/filtering_lists.html">4.5. Filtering Lists</a></span></li>
+ <li><span class="section"><a href="../power_of_introspection/and_or.html">4.6. The Peculiar Nature of and and or</a></span><ul>
+ <li><span class="section"><a href="../power_of_introspection/and_or.html#d0e9975">4.6.1. Using the and-or Trick</a></span></li>
+ </ul>
+ </li>
+ <li><span class="section"><a href="../power_of_introspection/lambda_functions.html">4.7. Using lambda Functions</a></span><ul>
+ <li><span class="section"><a href="../power_of_introspection/lambda_functions.html#d0e10403">4.7.1. Real-World lambda Functions</a></span></li>
+ </ul>
+ </li>
+ <li><span class="section"><a href="../power_of_introspection/all_together.html">4.8. Putting It All Together</a></span></li>
+ <li><span class="section"><a href="../power_of_introspection/summary.html">4.9. Summary</a></span></li>
+ </ul>
+ </li>
+ <li><span class="chapter"><a href="../object_oriented_framework/index.html">5. Objects and Object-Orientation</a></span><ul>
+ <li><span class="section"><a href="../object_oriented_framework/index.html#fileinfo.divein">5.1. Diving In</a></span></li>
+ <li><span class="section"><a href="../object_oriented_framework/importing_modules.html">5.2. Importing Modules Using from module import</a></span></li>
+ <li><span class="section"><a href="../object_oriented_framework/defining_classes.html">5.3. Defining Classes</a></span><ul>
+ <li><span class="section"><a href="../object_oriented_framework/defining_classes.html#d0e11720">5.3.1. Initializing and Coding Classes</a></span></li>
+ <li><span class="section"><a href="../object_oriented_framework/defining_classes.html#d0e11896">5.3.2. Knowing When to Use self and __init__</a></span></li>
+ </ul>
+ </li>
+ <li><span class="section"><a href="../object_oriented_framework/instantiating_classes.html">5.4. Instantiating Classes</a></span><ul>
+ <li><span class="section"><a href="../object_oriented_framework/instantiating_classes.html#d0e12165">5.4.1. Garbage Collection</a></span></li>
+ </ul>
+ </li>
+ <li><span class="section"><a href="../object_oriented_framework/userdict.html">5.5. Exploring UserDict: A Wrapper Class</a></span></li>
+ <li><span class="section"><a href="../object_oriented_framework/special_class_methods.html">5.6. Special Class Methods</a></span><ul>
+ <li><span class="section"><a href="../object_oriented_framework/special_class_methods.html#d0e12822">5.6.1. Getting and Setting Items</a></span></li>
+ </ul>
+ </li>
+ <li><span class="section"><a href="../object_oriented_framework/special_class_methods2.html">5.7. Advanced Special Class Methods</a></span></li>
+ <li><span class="section"><a href="../object_oriented_framework/class_attributes.html">5.8. Introducing Class Attributes</a></span></li>
+ <li><span class="section"><a href="../object_oriented_framework/private_functions.html">5.9. Private Functions</a></span></li>
+ <li><span class="section"><a href="../object_oriented_framework/summary.html">5.10. Summary</a></span></li>
+ </ul>
+ </li>
+ <li><span class="chapter"><a href="../file_handling/index.html">6. Exceptions and File Handling</a></span><ul>
+ <li><span class="section"><a href="../file_handling/index.html#fileinfo.exception">6.1. Handling Exceptions</a></span><ul>
+ <li><span class="section"><a href="../file_handling/index.html#d0e14344">6.1.1. Using Exceptions For Other Purposes</a></span></li>
+ </ul>
+ </li>
+ <li><span class="section"><a href="../file_handling/file_objects.html">6.2. Working with File Objects</a></span><ul>
+ <li><span class="section"><a href="../file_handling/file_objects.html#d0e14670">6.2.1. Reading Files</a></span></li>
+ <li><span class="section"><a href="../file_handling/file_objects.html#d0e14800">6.2.2. Closing Files</a></span></li>
+ <li><span class="section"><a href="../file_handling/file_objects.html#d0e14928">6.2.3. Handling I/O Errors</a></span></li>
+ <li><span class="section"><a href="../file_handling/file_objects.html#d0e15055">6.2.4. Writing to Files</a></span></li>
+ </ul>
+ </li>
+ <li><span class="section"><a href="../file_handling/for_loops.html">6.3. Iterating with for Loops</a></span></li>
+ <li><span class="section"><a href="../file_handling/more_on_modules.html">6.4. Using sys.modules</a></span></li>
+ <li><span class="section"><a href="../file_handling/os_module.html">6.5. Working with Directories</a></span></li>
+ <li><span class="section"><a href="../file_handling/all_together.html">6.6. Putting It All Together</a></span></li>
+ <li><span class="section"><a href="../file_handling/summary.html">6.7. Summary</a></span></li>
+ </ul>
+ </li>
+ <li><span class="chapter"><a href="../regular_expressions/index.html">7. Regular Expressions</a></span><ul>
+ <li><span class="section"><a href="../regular_expressions/index.html#re.intro">7.1. Diving In</a></span></li>
+ <li><span class="section"><a href="../regular_expressions/street_addresses.html">7.2. Case Study: Street Addresses</a></span></li>
+ <li><span class="section"><a href="../regular_expressions/roman_numerals.html">7.3. Case Study: Roman Numerals</a></span><ul>
+ <li><span class="section"><a href="../regular_expressions/roman_numerals.html#d0e17592">7.3.1. Checking for Thousands</a></span></li>
+ <li><span class="section"><a href="../regular_expressions/roman_numerals.html#d0e17785">7.3.2. Checking for Hundreds</a></span></li>
+ </ul>
+ </li>
+ <li><span class="section"><a href="../regular_expressions/n_m_syntax.html">7.4. Using the {n,m} Syntax</a></span><ul>
+ <li><span class="section"><a href="../regular_expressions/n_m_syntax.html#d0e18326">7.4.1. Checking for Tens and Ones</a></span></li>
+ </ul>
+ </li>
+ <li><span class="section"><a href="../regular_expressions/verbose.html">7.5. Verbose Regular Expressions</a></span></li>
+ <li><span class="section"><a href="../regular_expressions/phone_numbers.html">7.6. Case study: Parsing Phone Numbers</a></span></li>
+ <li><span class="section"><a href="../regular_expressions/summary.html">7.7. Summary</a></span></li>
+ </ul>
+ </li>
+ <li><span class="chapter"><a href="../html_processing/index.html">8. HTML Processing</a></span><ul>
+ <li><span class="section"><a href="../html_processing/index.html#dialect.divein">8.1. Diving in</a></span></li>
+ <li><span class="section"><a href="../html_processing/introducing_sgmllib.html">8.2. Introducing sgmllib.py</a></span></li>
+ <li><span class="section"><a href="../html_processing/extracting_data.html">8.3. Extracting data from HTML documents</a></span></li>
+ <li><span class="section"><a href="../html_processing/basehtmlprocessor.html">8.4. Introducing BaseHTMLProcessor.py</a></span></li>
+ <li><span class="section"><a href="../html_processing/locals_and_globals.html">8.5. locals and globals</a></span></li>
+ <li><span class="section"><a href="../html_processing/dictionary_based_string_formatting.html">8.6. Dictionary-based string formatting</a></span></li>
+ <li><span class="section"><a href="../html_processing/quoting_attribute_values.html">8.7. Quoting attribute values</a></span></li>
+ <li><span class="section"><a href="../html_processing/dialect.html">8.8. Introducing dialect.py</a></span></li>
+ <li><span class="section"><a href="../html_processing/all_together.html">8.9. Putting it all together</a></span></li>
+ <li><span class="section"><a href="../html_processing/summary.html">8.10. Summary</a></span></li>
+ </ul>
+ </li>
+ <li><span class="chapter"><a href="../xml_processing/index.html">9. XML Processing</a></span><ul>
+ <li><span class="section"><a href="../xml_processing/index.html#kgp.divein">9.1. Diving in</a></span></li>
+ <li><span class="section"><a href="../xml_processing/packages.html">9.2. Packages</a></span></li>
+ <li><span class="section"><a href="../xml_processing/parsing_xml.html">9.3. Parsing XML</a></span></li>
+ <li><span class="section"><a href="../xml_processing/unicode.html">9.4. Unicode</a></span></li>
+ <li><span class="section"><a href="../xml_processing/searching.html">9.5. Searching for elements</a></span></li>
+ <li><span class="section"><a href="../xml_processing/attributes.html">9.6. Accessing element attributes</a></span></li>
+ <li><span class="section"><a href="../xml_processing/summary.html">9.7. Segue</a></span></li>
+ </ul>
+ </li>
+ <li><span class="chapter"><a href="../scripts_and_streams/index.html">10. Scripts and Streams</a></span><ul>
+ <li><span class="section"><a href="../scripts_and_streams/index.html#kgp.openanything">10.1. Abstracting input sources</a></span></li>
+ <li><span class="section"><a href="../scripts_and_streams/stdin_stdout_stderr.html">10.2. Standard input, output, and error</a></span></li>
+ <li><span class="section"><a href="../scripts_and_streams/caching.html">10.3. Caching node lookups</a></span></li>
+ <li><span class="section"><a href="../scripts_and_streams/child_nodes.html">10.4. Finding direct children of a node</a></span></li>
+ <li><span class="section"><a href="../scripts_and_streams/handlers_by_node_type.html">10.5. Creating separate handlers by node type</a></span></li>
+ <li><span class="section"><a href="../scripts_and_streams/command_line_arguments.html">10.6. Handling command-line arguments</a></span></li>
+ <li><span class="section"><a href="../scripts_and_streams/all_together.html">10.7. Putting it all together</a></span></li>
+ <li><span class="section"><a href="../scripts_and_streams/summary.html">10.8. Summary</a></span></li>
+ </ul>
+ </li>
+ <li><span class="chapter"><a href="../http_web_services/index.html">11. HTTP Web Services</a></span><ul>
+ <li><span class="section"><a href="../http_web_services/index.html#oa.divein">11.1. Diving in</a></span></li>
+ <li><span class="section"><a href="../http_web_services/review.html">11.2. How not to fetch data over HTTP</a></span></li>
+ <li><span class="section"><a href="../http_web_services/http_features.html">11.3. Features of HTTP</a></span><ul>
+ <li><span class="section"><a href="../http_web_services/http_features.html#d0e27596">11.3.1. User-Agent</a></span></li>
+ <li><span class="section"><a href="../http_web_services/http_features.html#d0e27616">11.3.2. Redirects</a></span></li>
+ <li><span class="section"><a href="../http_web_services/http_features.html#d0e27689">11.3.3. Last-Modified/If-Modified-Since</a></span></li>
+ <li><span class="section"><a href="../http_web_services/http_features.html#d0e27724">11.3.4. ETag/If-None-Match</a></span></li>
+ <li><span class="section"><a href="../http_web_services/http_features.html#d0e27752">11.3.5. Compression</a></span></li>
+ </ul>
+ </li>
+ <li><span class="section"><a href="../http_web_services/debugging.html">11.4. Debugging HTTP web services</a></span></li>
+ <li><span class="section"><a href="../http_web_services/user_agent.html">11.5. Setting the User-Agent</a></span></li>
+ <li><span class="section"><a href="../http_web_services/etags.html">11.6. Handling Last-Modified and ETag</a></span></li>
+ <li><span class="section"><a href="../http_web_services/redirects.html">11.7. Handling redirects</a></span></li>
+ <li><span class="section"><a href="../http_web_services/gzip_compression.html">11.8. Handling compressed data</a></span></li>
+ <li><span class="section"><a href="../http_web_services/alltogether.html">11.9. Putting it all together</a></span></li>
+ <li><span class="section"><a href="../http_web_services/summary.html">11.10. Summary</a></span></li>
+ </ul>
+ </li>
+ <li><span class="chapter"><a href="../soap_web_services/index.html">12. SOAP Web Services</a></span><ul>
+ <li><span class="section"><a href="../soap_web_services/index.html#soap.divein">12.1. Diving In</a></span></li>
+ <li><span class="section"><a href="../soap_web_services/install.html">12.2. Installing the SOAP Libraries</a></span><ul>
+ <li><span class="section"><a href="../soap_web_services/install.html#d0e29967">12.2.1. Installing PyXML</a></span></li>
+ <li><span class="section"><a href="../soap_web_services/install.html#d0e30070">12.2.2. Installing fpconst</a></span></li>
+ <li><span class="section"><a href="../soap_web_services/install.html#d0e30171">12.2.3. Installing SOAPpy</a></span></li>
+ </ul>
+ </li>
+ <li><span class="section"><a href="../soap_web_services/first_steps.html">12.3. First Steps with SOAP</a></span></li>
+ <li><span class="section"><a href="../soap_web_services/debugging.html">12.4. Debugging SOAP Web Services</a></span></li>
+ <li><span class="section"><a href="../soap_web_services/wsdl.html">12.5. Introducing WSDL</a></span></li>
+ <li><span class="section"><a href="../soap_web_services/introspection.html">12.6. Introspecting SOAP Web Services with WSDL</a></span></li>
+ <li><span class="section"><a href="../soap_web_services/google.html">12.7. Searching Google</a></span></li>
+ <li><span class="section"><a href="../soap_web_services/troubleshooting.html">12.8. Troubleshooting SOAP Web Services</a></span></li>
+ <li><span class="section"><a href="../soap_web_services/summary.html">12.9. Summary</a></span></li>
+ </ul>
+ </li>
+ <li><span class="chapter"><a href="../unit_testing/index.html">13. Unit Testing</a></span><ul>
+ <li><span class="section"><a href="../unit_testing/index.html#roman.intro">13.1. Introduction to Roman numerals</a></span></li>
+ <li><span class="section"><a href="../unit_testing/diving_in.html">13.2. Diving in</a></span></li>
+ <li><span class="section"><a href="../unit_testing/romantest.html">13.3. Introducing romantest.py</a></span></li>
+ <li><span class="section"><a href="../unit_testing/testing_for_success.html">13.4. Testing for success</a></span></li>
+ <li><span class="section"><a href="../unit_testing/testing_for_failure.html">13.5. Testing for failure</a></span></li>
+ <li><span class="section"><a href="../unit_testing/testing_for_sanity.html">13.6. Testing for sanity</a></span></li>
+ </ul>
+ </li>
+ <li><span class="chapter"><a href="../unit_testing/stage_1.html">14. Test-First Programming</a></span><ul>
+ <li><span class="section"><a href="../unit_testing/stage_1.html#roman.stage1">14.1. roman.py, stage 1</a></span></li>
+ <li><span class="section"><a href="../unit_testing/stage_2.html">14.2. roman.py, stage 2</a></span></li>
+ <li><span class="section"><a href="../unit_testing/stage_3.html">14.3. roman.py, stage 3</a></span></li>
+ <li><span class="section"><a href="../unit_testing/stage_4.html">14.4. roman.py, stage 4</a></span></li>
+ <li><span class="section"><a href="../unit_testing/stage_5.html">14.5. roman.py, stage 5</a></span></li>
+ </ul>
+ </li>
+ <li><span class="chapter"><a href="../refactoring/index.html">15. Refactoring</a></span><ul>
+ <li><span class="section"><a href="../refactoring/index.html#roman.bugs">15.1. Handling bugs</a></span></li>
+ <li><span class="section"><a href="../refactoring/handling_changing_requirements.html">15.2. Handling changing requirements</a></span></li>
+ <li><span class="section"><a href="../refactoring/refactoring.html">15.3. Refactoring</a></span></li>
+ <li><span class="section"><a href="../refactoring/postscript.html">15.4. Postscript</a></span></li>
+ <li><span class="section"><a href="../refactoring/summary.html">15.5. Summary</a></span></li>
+ </ul>
+ </li>
+ <li><span class="chapter"><a href="../functional_programming/index.html">16. Functional Programming</a></span><ul>
+ <li><span class="section"><a href="../functional_programming/index.html#regression.divein">16.1. Diving in</a></span></li>
+ <li><span class="section"><a href="../functional_programming/finding_the_path.html">16.2. Finding the path</a></span></li>
+ <li><span class="section"><a href="../functional_programming/filtering_lists.html">16.3. Filtering lists revisited</a></span></li>
+ <li><span class="section"><a href="../functional_programming/mapping_lists.html">16.4. Mapping lists revisited</a></span></li>
+ <li><span class="section"><a href="../functional_programming/data_centric.html">16.5. Data-centric programming</a></span></li>
+ <li><span class="section"><a href="../functional_programming/dynamic_import.html">16.6. Dynamically importing modules</a></span></li>
+ <li><span class="section"><a href="../functional_programming/all_together.html">16.7. Putting it all together</a></span></li>
+ <li><span class="section"><a href="../functional_programming/summary.html">16.8. Summary</a></span></li>
+ </ul>
+ </li>
+ <li><span class="chapter"><a href="../dynamic_functions/index.html">17. Dynamic functions</a></span><ul>
+ <li><span class="section"><a href="../dynamic_functions/index.html#plural.divein">17.1. Diving in</a></span></li>
+ <li><span class="section"><a href="../dynamic_functions/stage1.html">17.2. plural.py, stage 1</a></span></li>
+ <li><span class="section"><a href="../dynamic_functions/stage2.html">17.3. plural.py, stage 2</a></span></li>
+ <li><span class="section"><a href="../dynamic_functions/stage3.html">17.4. plural.py, stage 3</a></span></li>
+ <li><span class="section"><a href="../dynamic_functions/stage4.html">17.5. plural.py, stage 4</a></span></li>
+ <li><span class="section"><a href="../dynamic_functions/stage5.html">17.6. plural.py, stage 5</a></span></li>
+ <li><span class="section"><a href="../dynamic_functions/stage6.html">17.7. plural.py, stage 6</a></span></li>
+ <li><span class="section"><a href="../dynamic_functions/summary.html">17.8. Summary</a></span></li>
+ </ul>
+ </li>
+ <li><span class="chapter"><a href="../performance_tuning/index.html">18. Performance Tuning</a></span><ul>
+ <li><span class="section"><a href="../performance_tuning/index.html#soundex.divein">18.1. Diving in</a></span></li>
+ <li><span class="section"><a href="../performance_tuning/timeit.html">18.2. Using the timeit Module</a></span></li>
+ <li><span class="section"><a href="../performance_tuning/regular_expressions.html">18.3. Optimizing Regular Expressions</a></span></li>
+ <li><span class="section"><a href="../performance_tuning/dictionary_lookups.html">18.4. Optimizing Dictionary Lookups</a></span></li>
+ <li><span class="section"><a href="../performance_tuning/list_operations.html">18.5. Optimizing List Operations</a></span></li>
+ <li><span class="section"><a href="../performance_tuning/string_manipulation.html">18.6. Optimizing String Manipulation</a></span></li>
+ <li><span class="section"><a href="../performance_tuning/summary.html">18.7. Summary</a></span></li>
+ </ul>
+ </li>
+ <li><span class="appendix"><a href="../appendix/furtherreading.html">A. Further reading</a></span></li>
+ <li><span class="appendix"><a href="../appendix/abstracts.html">B. A 5-minute review</a></span></li>
+ <li><span class="appendix"><a href="../appendix/tips.html">C. Tips and tricks</a></span></li>
+ <li><span class="appendix"><a href="../appendix/examples.html">D. List of examples</a></span></li>
+ <li><span class="appendix"><a href="../appendix/history.html">E. Revision history</a></span></li>
+ <li><span class="appendix"><a href="../appendix/about.html">F. About the book</a></span></li>
+ <li><span class="appendix"><a href="../appendix/fdl.html">G. GNU Free Documentation License</a></span><ul>
+ <li><span class="section"><a href="../appendix/fdl.html#d0e40006">G.0. Preamble</a></span></li>
+ <li><span class="section"><a href="../appendix/fdl_applicability.html">G.1. Applicability and definitions</a></span></li>
+ <li><span class="section"><a href="../appendix/fdl_copying.html">G.2. Verbatim copying</a></span></li>
+ <li><span class="section"><a href="../appendix/fdl_copyinginquantity.html">G.3. Copying in quantity</a></span></li>
+ <li><span class="section"><a href="../appendix/fdl_modifications.html">G.4. Modifications</a></span></li>
+ <li><span class="section"><a href="../appendix/fdl_combining.html">G.5. Combining documents</a></span></li>
+ <li><span class="section"><a href="../appendix/fdl_collections.html">G.6. Collections of documents</a></span></li>
+ <li><span class="section"><a href="../appendix/fdl_aggregation.html">G.7. Aggregation with independent works</a></span></li>
+ <li><span class="section"><a href="../appendix/fdl_translation.html">G.8. Translation</a></span></li>
+ <li><span class="section"><a href="../appendix/fdl_termination.html">G.9. Termination</a></span></li>
+ <li><span class="section"><a href="../appendix/fdl_future.html">G.10. Future revisions of this license</a></span></li>
+ <li><span class="section"><a href="../appendix/fdl_howto.html">G.11. How to use this License for your documents</a></span></li>
+ </ul>
+ </li>
+ <li><span class="appendix"><a href="../appendix/license.html">H. Python license</a></span><ul>
+ <li><span class="section"><a href="../appendix/license.html#d0e40180">H.A. History of the software</a></span></li>
+ <li><span class="section"><a href="../appendix/license_terms.html">H.B. Terms and conditions for accessing or otherwise using Python</a></span><ul>
+ <li><span class="section"><a href="../appendix/license_terms.html#d0e40195">H.B.1. PSF license agreement</a></span></li>
+ <li><span class="section"><a href="../appendix/license_terms.html#d0e40223">H.B.2. BeOpen Python open source license agreement version 1</a></span></li>
+ <li><span class="section"><a href="../appendix/license_terms.html#d0e40248">H.B.3. CNRI open source GPL-compatible license agreement</a></span></li>
+ <li><span class="section"><a href="../appendix/license_terms.html#d0e40276">H.B.4. CWI permissions statement and disclaimer</a></span></li>
+ </ul>
+ </li>
+ </ul>
+ </li>
+ </ul>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="../installing_python/index.html">Installing Python&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/unit_testing/diving_in.html b/help/diveintopython-5.4/html/unit_testing/diving_in.html
new file mode 100644
index 0000000..12b0042
--- /dev/null
+++ b/help/diveintopython-5.4/html/unit_testing/diving_in.html
@@ -0,0 +1,102 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>13.2.&nbsp;Diving in</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;13.&nbsp;Unit Testing">
+ <link rel="previous" href="index.html" title="Chapter&nbsp;13.&nbsp;Unit Testing">
+ <link rel="next" href="romantest.html" title="13.3.&nbsp;Introducing romantest.py">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Unit Testing</a>&nbsp;&gt;&nbsp;<span class="thispage">Diving in</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="index.html" title="Prev: &#8220;Unit Testing&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="romantest.html" title="Next: &#8220;Introducing romantest.py&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="roman.divein"></a>13.2.&nbsp;Diving in
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>Now that you've completely defined the behavior you expect from your conversion functions, you're going to do something a
+ little unexpected: you're going to write a test suite that puts these functions through their paces and makes sure that they
+ behave the way you want them to. You read that right: you're going to write code that tests code that you haven't written
+ yet.
+ </p>
+ </div>
+ <p>This is called unit testing, since the set of two conversion functions can be written and tested as a unit, separate from
+ any larger program they may become part of later. <span class="application">Python</span> has a framework for unit testing, the appropriately-named <tt class="filename">unittest</tt> module.
+ </p><a name="note.unittest"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%"><tt class="filename">unittest</tt> is included with <span class="application">Python</span> 2.1 and later. <span class="application">Python</span> 2.0 users can download it from <a href="http://pyunit.sourceforge.net/"><tt class="systemitem">pyunit.sourceforge.net</tt></a>.
+ </td>
+ </tr>
+ </table>
+ <p>Unit testing is an important part of an overall testing-centric development strategy. If you write unit tests, it is important
+ to write them early (preferably before writing the code that they test), and to keep them updated as code and requirements
+ change. Unit testing is not a replacement for higher-level functional or system testing, but it is important in all phases
+ of development:
+ </p>
+ <div class="itemizedlist">
+ <ul>
+ <li>Before writing code, it forces you to detail your requirements in a useful fashion.</li>
+ <li>While writing code, it keeps you from over-coding. When all the test cases pass, the function is complete.</li>
+ <li>When refactoring code, it assures you that the new version behaves the same way as the old version.</li>
+ <li>When maintaining code, it helps you cover your ass when someone comes screaming that your latest change broke their old code.
+ (&#8220;<span class="quote">But <span class="emphasis"><em>sir</em></span>, all the unit tests passed when I checked it in...</span>&#8221;)
+ </li>
+ <li>When writing code in a team, it increases confidence that the code you're about to commit isn't going to break other peoples'
+ code, because you can run their unittests first. (I've seen this sort of thing in code sprints. A team breaks up the assignment,
+ everybody takes the specs for their task, writes unit tests for it, then shares their unit tests with the rest of the team.
+ That way, nobody goes off too far into developing code that won't play well with others.)
+ </li>
+ </ul>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="index.html">&lt;&lt;&nbsp;Unit Testing</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#roman.intro" title="13.1.&nbsp;Introduction to Roman numerals">1</a> <span class="divider">|</span> <span class="thispage">2</span> <span class="divider">|</span> <a href="romantest.html" title="13.3.&nbsp;Introducing romantest.py">3</a> <span class="divider">|</span> <a href="testing_for_success.html" title="13.4.&nbsp;Testing for success">4</a> <span class="divider">|</span> <a href="testing_for_failure.html" title="13.5.&nbsp;Testing for failure">5</a> <span class="divider">|</span> <a href="testing_for_sanity.html" title="13.6.&nbsp;Testing for sanity">6</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="romantest.html">Introducing romantest.py&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/unit_testing/index.html b/help/diveintopython-5.4/html/unit_testing/index.html
new file mode 100644
index 0000000..2dae3af
--- /dev/null
+++ b/help/diveintopython-5.4/html/unit_testing/index.html
@@ -0,0 +1,138 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>Chapter&nbsp;13.&nbsp;Unit Testing</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="../toc/index.html" title="Dive Into Python">
+ <link rel="previous" href="../soap_web_services/summary.html" title="12.9.&nbsp;Summary">
+ <link rel="next" href="diving_in.html" title="13.2.&nbsp;Diving in">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<span class="thispage">Unit Testing</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="../soap_web_services/summary.html" title="Prev: &#8220;Summary&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="diving_in.html" title="Next: &#8220;Diving in&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="chapter" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="roman"></a>Chapter&nbsp;13.&nbsp;Unit Testing
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="toc">
+ <ul>
+ <li><span class="section"><a href="index.html#roman.intro">13.1. Introduction to Roman numerals</a></span></li>
+ <li><span class="section"><a href="diving_in.html">13.2. Diving in</a></span></li>
+ <li><span class="section"><a href="romantest.html">13.3. Introducing romantest.py</a></span></li>
+ <li><span class="section"><a href="testing_for_success.html">13.4. Testing for success</a></span></li>
+ <li><span class="section"><a href="testing_for_failure.html">13.5. Testing for failure</a></span></li>
+ <li><span class="section"><a href="testing_for_sanity.html">13.6. Testing for sanity</a></span></li>
+ </ul>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="roman.intro"></a>13.1.&nbsp;Introduction to Roman numerals
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>In previous chapters, you &#8220;<span class="quote">dived in</span>&#8221; by immediately looking at code and trying to understand it as quickly as possible. Now that you have some <span class="application">Python</span> under your belt, you're going to step back and look at the steps that happen <span class="emphasis"><em>before</em></span> the code gets written.
+ </p>
+ </div>
+ <p>In the next few chapters, you're going to write, debug, and optimize a set of utility functions to convert to and from Roman
+ numerals. You saw the mechanics of constructing and validating Roman numerals in <a href="../regular_expressions/roman_numerals.html" title="7.3.&nbsp;Case Study: Roman Numerals">Section&nbsp;7.3, &#8220;Case Study: Roman Numerals&#8221;</a>, but now let's step back and consider what it would take to expand that into a two-way utility.
+ </p>
+ <p><a href="../regular_expressions/roman_numerals.html" title="7.3.&nbsp;Case Study: Roman Numerals">The rules for Roman numerals</a> lead to a number of interesting observations:
+ </p>
+ <div class="orderedlist">
+ <ol type="1">
+ <li>There is only one correct way to represent a particular number as Roman numerals.</li>
+ <li>The converse is also true: if a string of characters is a valid Roman numeral, it represents only one number (<span class="foreignphrase"><i class="foreignphrase"><span class="acronym">i.e.</span></i></span> it can only be read one way).
+ </li>
+ <li>There is a limited range of numbers that can be expressed as Roman numerals, specifically <tt class="literal">1</tt> through <tt class="literal">3999</tt>. (The Romans did have several ways of expressing larger numbers, for instance by having a bar over a numeral to represent
+ that its normal value should be multiplied by <tt class="literal">1000</tt>, but you're not going to deal with that. For the purposes of this chapter, let's stipulate that Roman numerals go from <tt class="literal">1</tt> to <tt class="literal">3999</tt>.)
+ </li>
+ <li>There is no way to represent <tt class="constant">0</tt> in Roman numerals. (Amazingly, the ancient Romans had no concept of <tt class="constant">0</tt> as a number. Numbers were for counting things you had; how can you count what you don't have?)
+ </li>
+ <li>There is no way to represent negative numbers in Roman numerals.</li>
+ <li>There is no way to represent fractions or non-integer numbers in Roman numerals.</li>
+ </ol>
+ </div>
+ <p>Given all of this, what would you expect out of a set of functions to convert to and from Roman numerals?</p>
+ <div class="orderedlist"><a name="roman.requirements"></a><h3 class="title"><tt class="filename">roman.py</tt> requirements
+ </h3>
+ <ol type="1">
+ <li><tt class="function">toRoman</tt> should return the Roman numeral representation for all integers <tt class="constant">1</tt> to <tt class="literal">3999</tt>.
+ </li>
+ <li><tt class="function">toRoman</tt> should fail when given an integer outside the range <tt class="constant">1</tt> to <tt class="literal">3999</tt>.
+ </li>
+ <li><tt class="function">toRoman</tt> should fail when given a non-integer number.
+ </li>
+ <li><tt class="function">fromRoman</tt> should take a valid Roman numeral and return the number that it represents.
+ </li>
+ <li><tt class="function">fromRoman</tt> should fail when given an invalid Roman numeral.
+ </li>
+ <li>If you take a number, convert it to Roman numerals, then convert that back to a number, you should end up with the number
+ you started with. So <tt class="literal">fromRoman(toRoman(n)) == n</tt> for all <tt class="varname">n</tt> in <tt class="literal">1..3999</tt>.
+ </li>
+ <li><tt class="function">toRoman</tt> should always return a Roman numeral using uppercase letters.
+ </li>
+ <li><tt class="function">fromRoman</tt> should only accept uppercase Roman numerals (<span class="foreignphrase"><i class="foreignphrase"><span class="acronym">i.e.</span></i></span> it should fail when given lowercase input).
+ </li>
+ </ol>
+ </div>
+ <div class="furtherreading">
+ <h3>Further reading</h3>
+ <ul>
+ <li><a href="http://www.wilkiecollins.demon.co.uk/roman/front.htm">This site</a> has more on Roman numerals, including a fascinating <a href="http://www.wilkiecollins.demon.co.uk/roman/intro.htm">history</a> of how Romans and other civilizations really used them (short answer: haphazardly and inconsistently).
+ </li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="../soap_web_services/summary.html">&lt;&lt;&nbsp;Summary</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<span class="thispage">1</span> <span class="divider">|</span> <a href="diving_in.html" title="13.2.&nbsp;Diving in">2</a> <span class="divider">|</span> <a href="romantest.html" title="13.3.&nbsp;Introducing romantest.py">3</a> <span class="divider">|</span> <a href="testing_for_success.html" title="13.4.&nbsp;Testing for success">4</a> <span class="divider">|</span> <a href="testing_for_failure.html" title="13.5.&nbsp;Testing for failure">5</a> <span class="divider">|</span> <a href="testing_for_sanity.html" title="13.6.&nbsp;Testing for sanity">6</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="diving_in.html">Diving in&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/unit_testing/romantest.html b/help/diveintopython-5.4/html/unit_testing/romantest.html
new file mode 100644
index 0000000..498cd26
--- /dev/null
+++ b/help/diveintopython-5.4/html/unit_testing/romantest.html
@@ -0,0 +1,221 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>13.3.&nbsp;Introducing romantest.py</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;13.&nbsp;Unit Testing">
+ <link rel="previous" href="diving_in.html" title="13.2.&nbsp;Diving in">
+ <link rel="next" href="testing_for_success.html" title="13.4.&nbsp;Testing for success">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Unit Testing</a>&nbsp;&gt;&nbsp;<span class="thispage">Introducing romantest.py</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="diving_in.html" title="Prev: &#8220;Diving in&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="testing_for_success.html" title="Next: &#8220;Testing for success&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="roman.romantest"></a>13.3.&nbsp;Introducing <tt class="filename">romantest.py</tt></h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>This is the complete test suite for your Roman numeral conversion functions, which are yet to be written but will eventually
+ be in <tt class="filename">roman.py</tt>. It is not immediately obvious how it all fits together; none of these classes or methods reference any of the others.
+ There are good reasons for this, as you'll see shortly.
+ </p>
+ </div>
+ <div class="example"><a name="d0e32173"></a><h3 class="title">Example&nbsp;13.1.&nbsp;<tt class="filename">romantest.py</tt></h3>
+ <p>If you have not already done so, you can <a href="http://diveintopython.org/download/diveintopython-examples-5.4.zip" title="Download example scripts">download this and other examples</a> used in this book.
+ </p><pre class="programlisting">
+<span class='pystring'>"""Unit test for roman.py"""</span>
+
+<span class='pykeyword'>import</span> roman
+<span class='pykeyword'>import</span> unittest
+
+<span class='pykeyword'>class</span><span class='pyclass'> KnownValues</span>(unittest.TestCase):
+ knownValues = ( (1, <span class='pystring'>'I'</span>),
+ (2, <span class='pystring'>'II'</span>),
+ (3, <span class='pystring'>'III'</span>),
+ (4, <span class='pystring'>'IV'</span>),
+ (5, <span class='pystring'>'V'</span>),
+ (6, <span class='pystring'>'VI'</span>),
+ (7, <span class='pystring'>'VII'</span>),
+ (8, <span class='pystring'>'VIII'</span>),
+ (9, <span class='pystring'>'IX'</span>),
+ (10, <span class='pystring'>'X'</span>),
+ (50, <span class='pystring'>'L'</span>),
+ (100, <span class='pystring'>'C'</span>),
+ (500, <span class='pystring'>'D'</span>),
+ (1000, <span class='pystring'>'M'</span>),
+ (31, <span class='pystring'>'XXXI'</span>),
+ (148, <span class='pystring'>'CXLVIII'</span>),
+ (294, <span class='pystring'>'CCXCIV'</span>),
+ (312, <span class='pystring'>'CCCXII'</span>),
+ (421, <span class='pystring'>'CDXXI'</span>),
+ (528, <span class='pystring'>'DXXVIII'</span>),
+ (621, <span class='pystring'>'DCXXI'</span>),
+ (782, <span class='pystring'>'DCCLXXXII'</span>),
+ (870, <span class='pystring'>'DCCCLXX'</span>),
+ (941, <span class='pystring'>'CMXLI'</span>),
+ (1043, <span class='pystring'>'MXLIII'</span>),
+ (1110, <span class='pystring'>'MCX'</span>),
+ (1226, <span class='pystring'>'MCCXXVI'</span>),
+ (1301, <span class='pystring'>'MCCCI'</span>),
+ (1485, <span class='pystring'>'MCDLXXXV'</span>),
+ (1509, <span class='pystring'>'MDIX'</span>),
+ (1607, <span class='pystring'>'MDCVII'</span>),
+ (1754, <span class='pystring'>'MDCCLIV'</span>),
+ (1832, <span class='pystring'>'MDCCCXXXII'</span>),
+ (1993, <span class='pystring'>'MCMXCIII'</span>),
+ (2074, <span class='pystring'>'MMLXXIV'</span>),
+ (2152, <span class='pystring'>'MMCLII'</span>),
+ (2212, <span class='pystring'>'MMCCXII'</span>),
+ (2343, <span class='pystring'>'MMCCCXLIII'</span>),
+ (2499, <span class='pystring'>'MMCDXCIX'</span>),
+ (2574, <span class='pystring'>'MMDLXXIV'</span>),
+ (2646, <span class='pystring'>'MMDCXLVI'</span>),
+ (2723, <span class='pystring'>'MMDCCXXIII'</span>),
+ (2892, <span class='pystring'>'MMDCCCXCII'</span>),
+ (2975, <span class='pystring'>'MMCMLXXV'</span>),
+ (3051, <span class='pystring'>'MMMLI'</span>),
+ (3185, <span class='pystring'>'MMMCLXXXV'</span>),
+ (3250, <span class='pystring'>'MMMCCL'</span>),
+ (3313, <span class='pystring'>'MMMCCCXIII'</span>),
+ (3408, <span class='pystring'>'MMMCDVIII'</span>),
+ (3501, <span class='pystring'>'MMMDI'</span>),
+ (3610, <span class='pystring'>'MMMDCX'</span>),
+ (3743, <span class='pystring'>'MMMDCCXLIII'</span>),
+ (3844, <span class='pystring'>'MMMDCCCXLIV'</span>),
+ (3888, <span class='pystring'>'MMMDCCCLXXXVIII'</span>),
+ (3940, <span class='pystring'>'MMMCMXL'</span>),
+ (3999, <span class='pystring'>'MMMCMXCIX'</span>))
+
+ <span class='pykeyword'>def</span><span class='pyclass'> testToRomanKnownValues</span>(self):
+ <span class='pystring'>"""toRoman should give known result with known input"""</span>
+ <span class='pykeyword'>for</span> integer, numeral <span class='pykeyword'>in</span> self.knownValues:
+ result = roman.toRoman(integer)
+ self.assertEqual(numeral, result)
+
+ <span class='pykeyword'>def</span><span class='pyclass'> testFromRomanKnownValues</span>(self):
+ <span class='pystring'>"""fromRoman should give known result with known input"""</span>
+ <span class='pykeyword'>for</span> integer, numeral <span class='pykeyword'>in</span> self.knownValues:
+ result = roman.fromRoman(numeral)
+ self.assertEqual(integer, result)
+
+<span class='pykeyword'>class</span><span class='pyclass'> ToRomanBadInput</span>(unittest.TestCase):
+ <span class='pykeyword'>def</span><span class='pyclass'> testTooLarge</span>(self):
+ <span class='pystring'>"""toRoman should fail with large input"""</span>
+ self.assertRaises(roman.OutOfRangeError, roman.toRoman, 4000)
+
+ <span class='pykeyword'>def</span><span class='pyclass'> testZero</span>(self):
+ <span class='pystring'>"""toRoman should fail with 0 input"""</span>
+ self.assertRaises(roman.OutOfRangeError, roman.toRoman, 0)
+
+ <span class='pykeyword'>def</span><span class='pyclass'> testNegative</span>(self):
+ <span class='pystring'>"""toRoman should fail with negative input"""</span>
+ self.assertRaises(roman.OutOfRangeError, roman.toRoman, -1)
+
+ <span class='pykeyword'>def</span><span class='pyclass'> testNonInteger</span>(self):
+ <span class='pystring'>"""toRoman should fail with non-integer input"""</span>
+ self.assertRaises(roman.NotIntegerError, roman.toRoman, 0.5)
+
+<span class='pykeyword'>class</span><span class='pyclass'> FromRomanBadInput</span>(unittest.TestCase):
+ <span class='pykeyword'>def</span><span class='pyclass'> testTooManyRepeatedNumerals</span>(self):
+ <span class='pystring'>"""fromRoman should fail with too many repeated numerals"""</span>
+ <span class='pykeyword'>for</span> s <span class='pykeyword'>in</span> (<span class='pystring'>'MMMM'</span>, <span class='pystring'>'DD'</span>, <span class='pystring'>'CCCC'</span>, <span class='pystring'>'LL'</span>, <span class='pystring'>'XXXX'</span>, <span class='pystring'>'VV'</span>, <span class='pystring'>'IIII'</span>):
+ self.assertRaises(roman.InvalidRomanNumeralError, roman.fromRoman, s)
+
+ <span class='pykeyword'>def</span><span class='pyclass'> testRepeatedPairs</span>(self):
+ <span class='pystring'>"""fromRoman should fail with repeated pairs of numerals"""</span>
+ <span class='pykeyword'>for</span> s <span class='pykeyword'>in</span> (<span class='pystring'>'CMCM'</span>, <span class='pystring'>'CDCD'</span>, <span class='pystring'>'XCXC'</span>, <span class='pystring'>'XLXL'</span>, <span class='pystring'>'IXIX'</span>, <span class='pystring'>'IVIV'</span>):
+ self.assertRaises(roman.InvalidRomanNumeralError, roman.fromRoman, s)
+
+ <span class='pykeyword'>def</span><span class='pyclass'> testMalformedAntecedent</span>(self):
+ <span class='pystring'>"""fromRoman should fail with malformed antecedents"""</span>
+ <span class='pykeyword'>for</span> s <span class='pykeyword'>in</span> (<span class='pystring'>'IIMXCC'</span>, <span class='pystring'>'VX'</span>, <span class='pystring'>'DCM'</span>, <span class='pystring'>'CMM'</span>, <span class='pystring'>'IXIV'</span>,
+ <span class='pystring'>'MCMC'</span>, <span class='pystring'>'XCX'</span>, <span class='pystring'>'IVI'</span>, <span class='pystring'>'LM'</span>, <span class='pystring'>'LD'</span>, <span class='pystring'>'LC'</span>):
+ self.assertRaises(roman.InvalidRomanNumeralError, roman.fromRoman, s)
+
+<span class='pykeyword'>class</span><span class='pyclass'> SanityCheck</span>(unittest.TestCase):
+ <span class='pykeyword'>def</span><span class='pyclass'> testSanity</span>(self):
+ <span class='pystring'>"""fromRoman(toRoman(n))==n for all n"""</span>
+ <span class='pykeyword'>for</span> integer <span class='pykeyword'>in</span> range(1, 4000):
+ numeral = roman.toRoman(integer)
+ result = roman.fromRoman(numeral)
+ self.assertEqual(integer, result)
+
+<span class='pykeyword'>class</span><span class='pyclass'> CaseCheck</span>(unittest.TestCase):
+ <span class='pykeyword'>def</span><span class='pyclass'> testToRomanCase</span>(self):
+ <span class='pystring'>"""toRoman should always return uppercase"""</span>
+ <span class='pykeyword'>for</span> integer <span class='pykeyword'>in</span> range(1, 4000):
+ numeral = roman.toRoman(integer)
+ self.assertEqual(numeral, numeral.upper())
+
+ <span class='pykeyword'>def</span><span class='pyclass'> testFromRomanCase</span>(self):
+ <span class='pystring'>"""fromRoman should only accept uppercase input"""</span>
+ <span class='pykeyword'>for</span> integer <span class='pykeyword'>in</span> range(1, 4000):
+ numeral = roman.toRoman(integer)
+ roman.fromRoman(numeral.upper())
+ self.assertRaises(roman.InvalidRomanNumeralError,
+ roman.fromRoman, numeral.lower())
+
+<span class='pykeyword'>if</span> __name__ == <span class='pystring'>"__main__"</span>:
+ unittest.main() </pre></div>
+ <div class="furtherreading">
+ <h3>Further reading</h3>
+ <ul>
+ <li><a href="http://pyunit.sourceforge.net/">The <span class="application">PyUnit</span> home page</a> has an in-depth discussion of <a href="http://pyunit.sourceforge.net/pyunit.html">using the <tt class="filename">unittest</tt> framework</a>, including advanced features not covered in this chapter.
+ </li>
+ <li><a href="http://pyunit.sourceforge.net/pyunit.html">The <span class="application">PyUnit</span> <span class="acronym">FAQ</span></a> explains <a href="http://pyunit.sourceforge.net/pyunit.html#WHERE">why test cases are stored separately</a> from the code they test.
+ </li>
+ <li><a href="http://www.python.org/doc/current/lib/"><i class="citetitle"><span class="application">Python</span> Library Reference</i></a> summarizes the <a href="http://www.python.org/doc/current/lib/module-unittest.html"><tt class="filename">unittest</tt></a> module.
+ </li>
+ <li><a href="http://www.extremeprogramming.org/">ExtremeProgramming.org</a> discusses <a href="http://www.extremeprogramming.org/rules/unittests.html">why you should write unit tests</a>.
+ </li>
+ <li><a href="http://www.c2.com/cgi/wiki">The Portland Pattern Repository</a> has an ongoing discussion of <a href="http://www.c2.com/cgi/wiki?UnitTests">unit tests</a>, including a <a href="http://www.c2.com/cgi/wiki?StandardDefinitionOfUnitTest">standard definition</a>, why you should <a href="http://www.c2.com/cgi/wiki?CodeUnitTestFirst">code unit tests first</a>, and several in-depth <a href="http://www.c2.com/cgi/wiki?UnitTestTrial">case studies</a>.
+ </li>
+ </ul>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="diving_in.html">&lt;&lt;&nbsp;Diving in</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#roman.intro" title="13.1.&nbsp;Introduction to Roman numerals">1</a> <span class="divider">|</span> <a href="diving_in.html" title="13.2.&nbsp;Diving in">2</a> <span class="divider">|</span> <span class="thispage">3</span> <span class="divider">|</span> <a href="testing_for_success.html" title="13.4.&nbsp;Testing for success">4</a> <span class="divider">|</span> <a href="testing_for_failure.html" title="13.5.&nbsp;Testing for failure">5</a> <span class="divider">|</span> <a href="testing_for_sanity.html" title="13.6.&nbsp;Testing for sanity">6</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="testing_for_success.html">Testing for success&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/unit_testing/stage_1.html b/help/diveintopython-5.4/html/unit_testing/stage_1.html
new file mode 100644
index 0000000..b139b12
--- /dev/null
+++ b/help/diveintopython-5.4/html/unit_testing/stage_1.html
@@ -0,0 +1,297 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>Chapter&nbsp;14.&nbsp;Test-First Programming</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="../toc/index.html" title="Dive Into Python">
+ <link rel="previous" href="testing_for_sanity.html" title="13.6.&nbsp;Testing for sanity">
+ <link rel="next" href="stage_2.html" title="14.2.&nbsp;roman.py, stage 2">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<span class="thispage">Test-First Programming</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="testing_for_sanity.html" title="Prev: &#8220;Testing for sanity&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="stage_2.html" title="Next: &#8220;roman.py, stage 2&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="chapter" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="roman1.5"></a>Chapter&nbsp;14.&nbsp;Test-First Programming
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="toc">
+ <ul>
+ <li><span class="section"><a href="stage_1.html#roman.stage1">14.1. roman.py, stage 1</a></span></li>
+ <li><span class="section"><a href="stage_2.html">14.2. roman.py, stage 2</a></span></li>
+ <li><span class="section"><a href="stage_3.html">14.3. roman.py, stage 3</a></span></li>
+ <li><span class="section"><a href="stage_4.html">14.4. roman.py, stage 4</a></span></li>
+ <li><span class="section"><a href="stage_5.html">14.5. roman.py, stage 5</a></span></li>
+ </ul>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="roman.stage1"></a>14.1.&nbsp;<tt class="filename">roman.py</tt>, stage 1
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>Now that the unit tests are complete, it's time to start writing the code that the test cases are attempting to test. You're
+ going to do this in stages, so you can see all the unit tests fail, then watch them pass one by one as you fill in the gaps
+ in <tt class="filename">roman.py</tt>.
+ </p>
+ </div>
+ <div class="example"><a name="d0e32864"></a><h3 class="title">Example&nbsp;14.1.&nbsp;<tt class="filename">roman1.py</tt></h3>
+ <p>This file is available in <tt class="filename">py/roman/stage1/</tt> in the examples directory.
+ </p>
+ <p>If you have not already done so, you can <a href="http://diveintopython.org/download/diveintopython-examples-5.4.zip" title="Download example scripts">download this and other examples</a> used in this book.
+ </p><pre class="programlisting">
+<span class='pystring'>"""Convert to and from Roman numerals"""</span>
+
+<span class='pycomment'>#Define exceptions</span>
+<span class='pykeyword'>class</span><span class='pyclass'> RomanError</span>(Exception): <span class='pykeyword'>pass</span> <a name="roman.stage1.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"><span class='pykeyword'>
+class</span> OutOfRangeError(RomanError): <span class='pykeyword'>pass</span> <a name="roman.stage1.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"><span class='pykeyword'>
+class</span> NotIntegerError(RomanError): <span class='pykeyword'>pass</span>
+<span class='pykeyword'>class</span><span class='pyclass'> InvalidRomanNumeralError</span>(RomanError): <span class='pykeyword'>pass</span> <a name="roman.stage1.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+
+<span class='pykeyword'>def</span><span class='pyclass'> toRoman</span>(n):
+ <span class='pystring'>"""convert integer to Roman numeral"""</span>
+ <span class='pykeyword'>pass</span> <a name="roman.stage1.1.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+
+<span class='pykeyword'>def</span><span class='pyclass'> fromRoman</span>(s):
+ <span class='pystring'>"""convert Roman numeral to integer"""</span>
+ <span class='pykeyword'>pass</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.stage1.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This is how you define your own custom exceptions in <span class="application">Python</span>. Exceptions are classes, and you create your own by subclassing existing exceptions. It is strongly recommended (but not
+ required) that you subclass <tt class="errorcode">Exception</tt>, which is the base class that all built-in exceptions inherit from. Here I am defining <tt class="errorcode">RomanError</tt> (inherited from <tt class="errorcode">Exception</tt>) to act as the base class for all my other custom exceptions to follow. This is a matter of style; I could just as easily
+ have inherited each individual exception from the <tt class="errorcode">Exception</tt> class directly.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.stage1.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="errorcode">OutOfRangeError</tt> and <tt class="errorcode">NotIntegerError</tt> exceptions will eventually be used by <tt class="function">toRoman</tt> to flag various forms of invalid input, as specified in <a href="testing_for_failure.html#roman.tobadinput.example" title="Example&nbsp;13.3.&nbsp;Testing bad input to toRoman"><tt class="classname">ToRomanBadInput</tt></a>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.stage1.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="errorcode">InvalidRomanNumeralError</tt> exception will eventually be used by <tt class="function">fromRoman</tt> to flag invalid input, as specified in <a href="testing_for_failure.html#roman.frombadinput.example" title="Example&nbsp;13.4.&nbsp;Testing bad input to fromRoman"><tt class="classname">FromRomanBadInput</tt></a>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.stage1.1.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">At this stage, you want to define the <span class="acronym">API</span> of each of your functions, but you don't want to code them yet, so you stub them out using the <span class="application">Python</span> reserved word <a href="../object_oriented_framework/defining_classes.html#fileinfo.class.simplest" title="Example&nbsp;5.3.&nbsp;The Simplest Python Class"><tt class="literal">pass</tt></a>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>Now for the big moment (drum roll please): you're finally going to run the unit test against this stubby little module. At
+ this point, every test case should fail. In fact, if any test case passes in stage 1, you should go back to <tt class="filename">romantest.py</tt> and re-evaluate why you coded a test so useless that it passes with do-nothing functions.
+ </p>
+ <p>Run <tt class="filename">romantest1.py</tt> with the <tt class="option">-v</tt> command-line option, which will give more verbose output so you can see exactly what's going on as each test case runs.
+ With any luck, your output should look like this:
+ </p>
+ <div class="example"><a name="roman.stage1.output"></a><h3 class="title">Example&nbsp;14.2.&nbsp;Output of <tt class="filename">romantest1.py</tt> against <tt class="filename">roman1.py</tt></h3><pre class="screen"><span class="computeroutput">fromRoman should only accept uppercase input ... ERROR
+toRoman should always return uppercase ... ERROR
+fromRoman should fail with malformed antecedents ... FAIL
+fromRoman should fail with repeated pairs of numerals ... FAIL
+fromRoman should fail with too many repeated numerals ... FAIL
+fromRoman should give known result with known input ... FAIL
+toRoman should give known result with known input ... FAIL
+fromRoman(toRoman(n))==n for all n ... FAIL
+toRoman should fail with non-integer input ... FAIL
+toRoman should fail with negative input ... FAIL
+toRoman should fail with large input ... FAIL
+toRoman should fail with 0 input ... FAIL
+
+======================================================================
+ERROR: fromRoman should only accept uppercase input
+----------------------------------------------------------------------
+</span><span class="traceback">Traceback (most recent call last):
+ File "C:\docbook\dip\py\roman\stage1\romantest1.py", line 154, in testFromRomanCase
+ roman1.fromRoman(numeral.upper())
+AttributeError: 'None' object has no attribute 'upper'</span><span class="computeroutput">
+======================================================================
+ERROR: toRoman should always return uppercase
+----------------------------------------------------------------------
+</span><span class="traceback">Traceback (most recent call last):
+ File "C:\docbook\dip\py\roman\stage1\romantest1.py", line 148, in testToRomanCase
+ self.assertEqual(numeral, numeral.upper())
+AttributeError: 'None' object has no attribute 'upper'</span><span class="computeroutput">
+======================================================================
+FAIL: fromRoman should fail with malformed antecedents
+----------------------------------------------------------------------
+</span><span class="traceback">Traceback (most recent call last):
+ File "C:\docbook\dip\py\roman\stage1\romantest1.py", line 133, in testMalformedAntecedent
+ self.assertRaises(roman1.InvalidRomanNumeralError, roman1.fromRoman, s)
+ File "c:\python21\lib\unittest.py", line 266, in failUnlessRaises
+ raise self.failureException, excName
+AssertionError: InvalidRomanNumeralError</span><span class="computeroutput">
+======================================================================
+FAIL: fromRoman should fail with repeated pairs of numerals
+----------------------------------------------------------------------
+</span><span class="traceback">Traceback (most recent call last):
+ File "C:\docbook\dip\py\roman\stage1\romantest1.py", line 127, in testRepeatedPairs
+ self.assertRaises(roman1.InvalidRomanNumeralError, roman1.fromRoman, s)
+ File "c:\python21\lib\unittest.py", line 266, in failUnlessRaises
+ raise self.failureException, excName
+AssertionError: InvalidRomanNumeralError</span><span class="computeroutput">
+======================================================================
+FAIL: fromRoman should fail with too many repeated numerals
+----------------------------------------------------------------------
+</span><span class="traceback">Traceback (most recent call last):
+ File "C:\docbook\dip\py\roman\stage1\romantest1.py", line 122, in testTooManyRepeatedNumerals
+ self.assertRaises(roman1.InvalidRomanNumeralError, roman1.fromRoman, s)
+ File "c:\python21\lib\unittest.py", line 266, in failUnlessRaises
+ raise self.failureException, excName
+AssertionError: InvalidRomanNumeralError</span><span class="computeroutput">
+======================================================================
+FAIL: fromRoman should give known result with known input
+----------------------------------------------------------------------
+</span><span class="traceback">Traceback (most recent call last):
+ File "C:\docbook\dip\py\roman\stage1\romantest1.py", line 99, in testFromRomanKnownValues
+ self.assertEqual(integer, result)
+ File "c:\python21\lib\unittest.py", line 273, in failUnlessEqual
+ raise self.failureException, (msg or '%s != %s' % (first, second))
+AssertionError: 1 != None</span><span class="computeroutput">
+======================================================================
+FAIL: toRoman should give known result with known input
+----------------------------------------------------------------------
+</span><span class="traceback">Traceback (most recent call last):
+ File "C:\docbook\dip\py\roman\stage1\romantest1.py", line 93, in testToRomanKnownValues
+ self.assertEqual(numeral, result)
+ File "c:\python21\lib\unittest.py", line 273, in failUnlessEqual
+ raise self.failureException, (msg or '%s != %s' % (first, second))
+AssertionError: I != None</span><span class="computeroutput">
+======================================================================
+FAIL: fromRoman(toRoman(n))==n for all n
+----------------------------------------------------------------------
+</span><span class="traceback">Traceback (most recent call last):
+ File "C:\docbook\dip\py\roman\stage1\romantest1.py", line 141, in testSanity
+ self.assertEqual(integer, result)
+ File "c:\python21\lib\unittest.py", line 273, in failUnlessEqual
+ raise self.failureException, (msg or '%s != %s' % (first, second))
+AssertionError: 1 != None</span><span class="computeroutput">
+======================================================================
+FAIL: toRoman should fail with non-integer input
+----------------------------------------------------------------------
+</span><span class="traceback">Traceback (most recent call last):
+ File "C:\docbook\dip\py\roman\stage1\romantest1.py", line 116, in testNonInteger
+ self.assertRaises(roman1.NotIntegerError, roman1.toRoman, 0.5)
+ File "c:\python21\lib\unittest.py", line 266, in failUnlessRaises
+ raise self.failureException, excName
+AssertionError: NotIntegerError</span><span class="computeroutput">
+======================================================================
+FAIL: toRoman should fail with negative input
+----------------------------------------------------------------------
+</span><span class="traceback">Traceback (most recent call last):
+ File "C:\docbook\dip\py\roman\stage1\romantest1.py", line 112, in testNegative
+ self.assertRaises(roman1.OutOfRangeError, roman1.toRoman, -1)
+ File "c:\python21\lib\unittest.py", line 266, in failUnlessRaises
+ raise self.failureException, excName
+AssertionError: OutOfRangeError</span><span class="computeroutput">
+======================================================================
+FAIL: toRoman should fail with large input
+----------------------------------------------------------------------
+</span><span class="traceback">Traceback (most recent call last):
+ File "C:\docbook\dip\py\roman\stage1\romantest1.py", line 104, in testTooLarge
+ self.assertRaises(roman1.OutOfRangeError, roman1.toRoman, 4000)
+ File "c:\python21\lib\unittest.py", line 266, in failUnlessRaises
+ raise self.failureException, excName
+AssertionError: OutOfRangeError</span><span class="computeroutput">
+======================================================================
+FAIL: toRoman should fail with 0 input </span><a name="roman.stage1.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"><span class="computeroutput">
+----------------------------------------------------------------------
+</span><span class="traceback">Traceback (most recent call last):
+ File "C:\docbook\dip\py\roman\stage1\romantest1.py", line 108, in testZero
+ self.assertRaises(roman1.OutOfRangeError, roman1.toRoman, 0)
+ File "c:\python21\lib\unittest.py", line 266, in failUnlessRaises
+ raise self.failureException, excName
+AssertionError: OutOfRangeError </span><a name="roman.stage1.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"><span class="computeroutput">
+----------------------------------------------------------------------
+Ran 12 tests in 0.040s </span><a name="roman.stage1.2.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"><span class="computeroutput">
+
+FAILED (failures=10, errors=2) </span><a name="roman.stage1.2.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.stage1.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Running the script runs <tt class="function">unittest.main()</tt>, which runs each test case, which is to say each method defined in each class within <tt class="filename">romantest.py</tt>. For each test case, it prints out the <tt class="literal">doc string</tt> of the method and whether that test passed or failed. As expected, none of the test cases passed.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.stage1.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">For each failed test case, <tt class="filename">unittest</tt> displays the trace information showing exactly what happened. In this case, the call to <tt class="function">assertRaises</tt> (also called <tt class="function">failUnlessRaises</tt>) raised an <tt class="errorcode">AssertionError</tt> because it was expecting <tt class="function">toRoman</tt> to raise an <tt class="errorcode">OutOfRangeError</tt> and it didn't.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.stage1.2.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">After the detail, <tt class="filename">unittest</tt> displays a summary of how many tests were performed and how long it took.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.stage1.2.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Overall, the unit test failed because at least one test case did not pass. When a test case doesn't pass, <tt class="filename">unittest</tt> distinguishes between failures and errors. A failure is a call to an <tt class="function">assertXYZ</tt> method, like <tt class="function">assertEqual</tt> or <tt class="function">assertRaises</tt>, that fails because the asserted condition is not true or the expected exception was not raised. An error is any other sort
+ of exception raised in the code you're testing or the unit test case itself. For instance, the <tt class="function">testFromRomanCase</tt> method (&#8220;<span class="quote"><tt class="function">fromRoman</tt> should only accept uppercase input</span>&#8221;) was an error, because the call to <tt class="function">numeral.upper()</tt> raised an <tt class="errorcode">AttributeError</tt> exception, because <tt class="function">toRoman</tt> was supposed to return a string but didn't. But <tt class="function">testZero</tt> (&#8220;<span class="quote"><tt class="function">toRoman</tt> should fail with 0 input</span>&#8221;) was a failure, because the call to <tt class="function">fromRoman</tt> did not raise the <tt class="errorcode">InvalidRomanNumeral</tt> exception that <tt class="function">assertRaises</tt> was looking for.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="testing_for_sanity.html">&lt;&lt;&nbsp;Testing for sanity</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<span class="thispage">1</span> <span class="divider">|</span> <a href="stage_2.html" title="14.2.&nbsp;roman.py, stage 2">2</a> <span class="divider">|</span> <a href="stage_3.html" title="14.3.&nbsp;roman.py, stage 3">3</a> <span class="divider">|</span> <a href="stage_4.html" title="14.4.&nbsp;roman.py, stage 4">4</a> <span class="divider">|</span> <a href="stage_5.html" title="14.5.&nbsp;roman.py, stage 5">5</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="stage_2.html">roman.py, stage 2&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/unit_testing/stage_2.html b/help/diveintopython-5.4/html/unit_testing/stage_2.html
new file mode 100644
index 0000000..fca6356
--- /dev/null
+++ b/help/diveintopython-5.4/html/unit_testing/stage_2.html
@@ -0,0 +1,289 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>14.2.&nbsp;roman.py, stage 2</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="stage_1.html" title="Chapter&nbsp;14.&nbsp;Test-First Programming">
+ <link rel="previous" href="stage_1.html" title="Chapter&nbsp;14.&nbsp;Test-First Programming">
+ <link rel="next" href="stage_3.html" title="14.3.&nbsp;roman.py, stage 3">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="stage_1.html">Test-First Programming</a>&nbsp;&gt;&nbsp;<span class="thispage">roman.py, stage 2</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="stage_1.html" title="Prev: &#8220;Test-First Programming&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="stage_3.html" title="Next: &#8220;roman.py, stage 3&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="roman.stage2"></a>14.2.&nbsp;<tt class="filename">roman.py</tt>, stage 2
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>Now that you have the framework of the <tt class="filename">roman</tt> module laid out, it's time to start writing code and passing test cases.
+ </p>
+ </div>
+ <div class="example"><a name="roman.stage2.example"></a><h3 class="title">Example&nbsp;14.3.&nbsp;<tt class="filename">roman2.py</tt></h3>
+ <p>This file is available in <tt class="filename">py/roman/stage2/</tt> in the examples directory.
+ </p>
+ <p>If you have not already done so, you can <a href="http://diveintopython.org/download/diveintopython-examples-5.4.zip" title="Download example scripts">download this and other examples</a> used in this book.
+ </p><pre class="programlisting">
+<span class='pystring'>"""Convert to and from Roman numerals"""</span>
+
+<span class='pycomment'>#Define exceptions</span>
+<span class='pykeyword'>class</span><span class='pyclass'> RomanError</span>(Exception): <span class='pykeyword'>pass</span>
+<span class='pykeyword'>class</span><span class='pyclass'> OutOfRangeError</span>(RomanError): <span class='pykeyword'>pass</span>
+<span class='pykeyword'>class</span><span class='pyclass'> NotIntegerError</span>(RomanError): <span class='pykeyword'>pass</span>
+<span class='pykeyword'>class</span><span class='pyclass'> InvalidRomanNumeralError</span>(RomanError): <span class='pykeyword'>pass</span>
+
+<span class='pycomment'>#Define digit mapping</span>
+romanNumeralMap = ((<span class='pystring'>'M'</span>, 1000), <a name="roman.stage2.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ (<span class='pystring'>'CM'</span>, 900),
+ (<span class='pystring'>'D'</span>, 500),
+ (<span class='pystring'>'CD'</span>, 400),
+ (<span class='pystring'>'C'</span>, 100),
+ (<span class='pystring'>'XC'</span>, 90),
+ (<span class='pystring'>'L'</span>, 50),
+ (<span class='pystring'>'XL'</span>, 40),
+ (<span class='pystring'>'X'</span>, 10),
+ (<span class='pystring'>'IX'</span>, 9),
+ (<span class='pystring'>'V'</span>, 5),
+ (<span class='pystring'>'IV'</span>, 4),
+ (<span class='pystring'>'I'</span>, 1))
+
+<span class='pykeyword'>def</span><span class='pyclass'> toRoman</span>(n):
+ <span class='pystring'>"""convert integer to Roman numeral"""</span>
+ result = <span class='pystring'>""</span>
+ <span class='pykeyword'>for</span> numeral, integer <span class='pykeyword'>in</span> romanNumeralMap:
+ <span class='pykeyword'>while</span> n &gt;= integer: <a name="roman.stage2.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+ result += numeral
+ n -= integer
+ <span class='pykeyword'>return</span> result
+
+<span class='pykeyword'>def</span><span class='pyclass'> fromRoman</span>(s):
+ <span class='pystring'>"""convert Roman numeral to integer"""</span>
+ <span class='pykeyword'>pass</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.stage2.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="varname">romanNumeralMap</tt> is a tuple of tuples which defines three things:
+ <div class="orderedlist">
+ <ol type="1">
+ <li>The character representations of the most basic Roman numerals. Note that this is not just the single-character Roman numerals;
+ you're also defining two-character pairs like <tt class="literal">CM</tt> (&#8220;<span class="quote">one hundred less than one thousand</span>&#8221;); this will make the <tt class="function">toRoman</tt> code simpler later.
+ </li>
+ <li>The order of the Roman numerals. They are listed in descending value order, from <tt class="literal">M</tt> all the way down to <tt class="literal">I</tt>.
+ </li>
+ <li>The value of each Roman numeral. Each inner tuple is a pair of <tt class="literal">(<i class="replaceable">numeral</i>, <i class="replaceable">value</i>)</tt>.
+ </li>
+ </ol>
+ </div>
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.stage2.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Here's where your rich data structure pays off, because you don't need any special logic to handle the subtraction rule.
+ To convert to Roman numerals, you simply iterate through <tt class="varname">romanNumeralMap</tt> looking for the largest integer value less than or equal to the input. Once found, you add the Roman numeral representation
+ to the end of the output, subtract the corresponding integer value from the input, lather, rinse, repeat.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="d0e33197"></a><h3 class="title">Example&nbsp;14.4.&nbsp;How <tt class="function">toRoman</tt> works
+ </h3>
+ <p>If you're not clear how <tt class="function">toRoman</tt> works, add a <tt class="function">print</tt> statement to the end of the <tt class="literal">while</tt> loop:
+ </p><pre class="programlisting">
+ <span class='pykeyword'>while</span> n &gt;= integer:
+ result += numeral
+ n -= integer
+ <span class='pykeyword'>print</span> <span class='pystring'>'subtracting'</span>, integer, <span class='pystring'>'from input, adding'</span>, numeral, <span class='pystring'>'to output'</span></pre><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> roman2</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">roman2.toRoman(1424)</span>
+<span class="computeroutput">subtracting 1000 from input, adding M to output
+subtracting 400 from input, adding CD to output
+subtracting 10 from input, adding X to output
+subtracting 10 from input, adding X to output
+subtracting 4 from input, adding IV to output
+'MCDXXIV'</span>
+</pre></div>
+ <p>So <tt class="function">toRoman</tt> appears to work, at least in this manual spot check. But will it pass the unit testing? Well no, not entirely.
+ </p>
+ <div class="example"><a name="d0e33236"></a><h3 class="title">Example&nbsp;14.5.&nbsp;Output of <tt class="filename">romantest2.py</tt> against <tt class="filename">roman2.py</tt></h3>
+ <p>Remember to run <tt class="filename">romantest2.py</tt> with the <tt class="literal">-v</tt> command-line flag to enable verbose mode.
+ </p><pre class="screen"><span class="computeroutput">fromRoman should only accept uppercase input ... FAIL
+toRoman should always return uppercase ... ok </span><a name="roman.stage2.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"><span class="computeroutput">
+fromRoman should fail with malformed antecedents ... FAIL
+fromRoman should fail with repeated pairs of numerals ... FAIL
+fromRoman should fail with too many repeated numerals ... FAIL
+fromRoman should give known result with known input ... FAIL
+toRoman should give known result with known input ... ok </span><a name="roman.stage2.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"><span class="computeroutput">
+fromRoman(toRoman(n))==n for all n ... FAIL
+toRoman should fail with non-integer input ... FAIL </span><a name="roman.stage2.2.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"><span class="computeroutput">
+toRoman should fail with negative input ... FAIL
+toRoman should fail with large input ... FAIL
+toRoman should fail with 0 input ... FAIL</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.stage2.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">toRoman</tt> does, in fact, always return uppercase, because <tt class="varname">romanNumeralMap</tt> defines the Roman numeral representations as uppercase. So this test passes already.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.stage2.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Here's the big news: this version of the <tt class="function">toRoman</tt> function passes the <a href="testing_for_success.html#roman.testtoromanknownvalues.example" title="Example&nbsp;13.2.&nbsp;testToRomanKnownValues">known values test</a>. Remember, it's not comprehensive, but it does put the function through its paces with a variety of good inputs, including
+ inputs that produce every single-character Roman numeral, the largest possible input (<tt class="literal">3999</tt>), and the input that produces the longest possible Roman numeral (<tt class="literal">3888</tt>). At this point, you can be reasonably confident that the function works for any good input value you could throw at it.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.stage2.2.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">However, the function does not &#8220;<span class="quote">work</span>&#8221; for bad values; it fails every single <a href="testing_for_failure.html#roman.tobadinput.example" title="Example&nbsp;13.3.&nbsp;Testing bad input to toRoman">bad input test</a>. That makes sense, because you didn't include any checks for bad input. Those test cases look for specific exceptions to
+ be raised (via <tt class="function">assertRaises</tt>), and you're never raising them. You'll do that in the next stage.
+ </td>
+ </tr>
+ </table>
+ </div>
+ <p>Here's the rest of the output of the unit test, listing the details of all the failures. You're down to 10.</p><pre class="screen"><span class="computeroutput">
+======================================================================
+FAIL: fromRoman should only accept uppercase input
+----------------------------------------------------------------------
+</span><span class="traceback">Traceback (most recent call last):
+ File "C:\docbook\dip\py\roman\stage2\romantest2.py", line 156, in testFromRomanCase
+ roman2.fromRoman, numeral.lower())
+ File "c:\python21\lib\unittest.py", line 266, in failUnlessRaises
+ raise self.failureException, excName
+AssertionError: InvalidRomanNumeralError</span><span class="computeroutput">
+======================================================================
+FAIL: fromRoman should fail with malformed antecedents
+----------------------------------------------------------------------
+</span><span class="traceback">Traceback (most recent call last):
+ File "C:\docbook\dip\py\roman\stage2\romantest2.py", line 133, in testMalformedAntecedent
+ self.assertRaises(roman2.InvalidRomanNumeralError, roman2.fromRoman, s)
+ File "c:\python21\lib\unittest.py", line 266, in failUnlessRaises
+ raise self.failureException, excName
+AssertionError: InvalidRomanNumeralError</span><span class="computeroutput">
+======================================================================
+FAIL: fromRoman should fail with repeated pairs of numerals
+----------------------------------------------------------------------
+</span><span class="traceback">Traceback (most recent call last):
+ File "C:\docbook\dip\py\roman\stage2\romantest2.py", line 127, in testRepeatedPairs
+ self.assertRaises(roman2.InvalidRomanNumeralError, roman2.fromRoman, s)
+ File "c:\python21\lib\unittest.py", line 266, in failUnlessRaises
+ raise self.failureException, excName
+AssertionError: InvalidRomanNumeralError</span><span class="computeroutput">
+======================================================================
+FAIL: fromRoman should fail with too many repeated numerals
+----------------------------------------------------------------------
+</span><span class="traceback">Traceback (most recent call last):
+ File "C:\docbook\dip\py\roman\stage2\romantest2.py", line 122, in testTooManyRepeatedNumerals
+ self.assertRaises(roman2.InvalidRomanNumeralError, roman2.fromRoman, s)
+ File "c:\python21\lib\unittest.py", line 266, in failUnlessRaises
+ raise self.failureException, excName
+AssertionError: InvalidRomanNumeralError</span><span class="computeroutput">
+======================================================================
+FAIL: fromRoman should give known result with known input
+----------------------------------------------------------------------
+</span><span class="traceback">Traceback (most recent call last):
+ File "C:\docbook\dip\py\roman\stage2\romantest2.py", line 99, in testFromRomanKnownValues
+ self.assertEqual(integer, result)
+ File "c:\python21\lib\unittest.py", line 273, in failUnlessEqual
+ raise self.failureException, (msg or '%s != %s' % (first, second))
+AssertionError: 1 != None</span><span class="computeroutput">
+======================================================================
+FAIL: fromRoman(toRoman(n))==n for all n
+----------------------------------------------------------------------
+</span><span class="traceback">Traceback (most recent call last):
+ File "C:\docbook\dip\py\roman\stage2\romantest2.py", line 141, in testSanity
+ self.assertEqual(integer, result)
+ File "c:\python21\lib\unittest.py", line 273, in failUnlessEqual
+ raise self.failureException, (msg or '%s != %s' % (first, second))
+AssertionError: 1 != None</span><span class="computeroutput">
+======================================================================
+FAIL: toRoman should fail with non-integer input
+----------------------------------------------------------------------
+</span><span class="traceback">Traceback (most recent call last):
+ File "C:\docbook\dip\py\roman\stage2\romantest2.py", line 116, in testNonInteger
+ self.assertRaises(roman2.NotIntegerError, roman2.toRoman, 0.5)
+ File "c:\python21\lib\unittest.py", line 266, in failUnlessRaises
+ raise self.failureException, excName
+AssertionError: NotIntegerError</span><span class="computeroutput">
+======================================================================
+FAIL: toRoman should fail with negative input
+----------------------------------------------------------------------
+</span><span class="traceback">Traceback (most recent call last):
+ File "C:\docbook\dip\py\roman\stage2\romantest2.py", line 112, in testNegative
+ self.assertRaises(roman2.OutOfRangeError, roman2.toRoman, -1)
+ File "c:\python21\lib\unittest.py", line 266, in failUnlessRaises
+ raise self.failureException, excName
+AssertionError: OutOfRangeError</span><span class="computeroutput">
+======================================================================
+FAIL: toRoman should fail with large input
+----------------------------------------------------------------------
+</span><span class="traceback">Traceback (most recent call last):
+ File "C:\docbook\dip\py\roman\stage2\romantest2.py", line 104, in testTooLarge
+ self.assertRaises(roman2.OutOfRangeError, roman2.toRoman, 4000)
+ File "c:\python21\lib\unittest.py", line 266, in failUnlessRaises
+ raise self.failureException, excName
+AssertionError: OutOfRangeError</span><span class="computeroutput">
+======================================================================
+FAIL: toRoman should fail with 0 input
+----------------------------------------------------------------------
+</span><span class="traceback">Traceback (most recent call last):
+ File "C:\docbook\dip\py\roman\stage2\romantest2.py", line 108, in testZero
+ self.assertRaises(roman2.OutOfRangeError, roman2.toRoman, 0)
+ File "c:\python21\lib\unittest.py", line 266, in failUnlessRaises
+ raise self.failureException, excName
+AssertionError: OutOfRangeError</span><span class="computeroutput">
+----------------------------------------------------------------------
+Ran 12 tests in 0.320s
+
+FAILED (failures=10)</span></pre></div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="stage_1.html">&lt;&lt;&nbsp;Test-First Programming</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="stage_1.html#roman.stage1" title="14.1.&nbsp;roman.py, stage 1">1</a> <span class="divider">|</span> <span class="thispage">2</span> <span class="divider">|</span> <a href="stage_3.html" title="14.3.&nbsp;roman.py, stage 3">3</a> <span class="divider">|</span> <a href="stage_4.html" title="14.4.&nbsp;roman.py, stage 4">4</a> <span class="divider">|</span> <a href="stage_5.html" title="14.5.&nbsp;roman.py, stage 5">5</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="stage_3.html">roman.py, stage 3&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/unit_testing/stage_3.html b/help/diveintopython-5.4/html/unit_testing/stage_3.html
new file mode 100644
index 0000000..5732b5a
--- /dev/null
+++ b/help/diveintopython-5.4/html/unit_testing/stage_3.html
@@ -0,0 +1,268 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>14.3.&nbsp;roman.py, stage 3</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="stage_1.html" title="Chapter&nbsp;14.&nbsp;Test-First Programming">
+ <link rel="previous" href="stage_2.html" title="14.2.&nbsp;roman.py, stage 2">
+ <link rel="next" href="stage_4.html" title="14.4.&nbsp;roman.py, stage 4">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="stage_1.html">Test-First Programming</a>&nbsp;&gt;&nbsp;<span class="thispage">roman.py, stage 3</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="stage_2.html" title="Prev: &#8220;roman.py, stage 2&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="stage_4.html" title="Next: &#8220;roman.py, stage 4&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="roman.stage3"></a>14.3.&nbsp;<tt class="filename">roman.py</tt>, stage 3
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>Now that <tt class="function">toRoman</tt> behaves correctly with good input (integers from <tt class="literal">1</tt> to <tt class="literal">3999</tt>), it's time to make it behave correctly with bad input (everything else).
+ </p>
+ </div>
+ <div class="example"><a name="d0e33364"></a><h3 class="title">Example&nbsp;14.6.&nbsp;<tt class="filename">roman3.py</tt></h3>
+ <p>This file is available in <tt class="filename">py/roman/stage3/</tt> in the examples directory.
+ </p>
+ <p>If you have not already done so, you can <a href="http://diveintopython.org/download/diveintopython-examples-5.4.zip" title="Download example scripts">download this and other examples</a> used in this book.
+ </p><pre class="programlisting">
+<span class='pystring'>"""Convert to and from Roman numerals"""</span>
+
+<span class='pycomment'>#Define exceptions</span>
+<span class='pykeyword'>class</span><span class='pyclass'> RomanError</span>(Exception): <span class='pykeyword'>pass</span>
+<span class='pykeyword'>class</span><span class='pyclass'> OutOfRangeError</span>(RomanError): <span class='pykeyword'>pass</span>
+<span class='pykeyword'>class</span><span class='pyclass'> NotIntegerError</span>(RomanError): <span class='pykeyword'>pass</span>
+<span class='pykeyword'>class</span><span class='pyclass'> InvalidRomanNumeralError</span>(RomanError): <span class='pykeyword'>pass</span>
+
+<span class='pycomment'>#Define digit mapping</span>
+romanNumeralMap = ((<span class='pystring'>'M'</span>, 1000),
+ (<span class='pystring'>'CM'</span>, 900),
+ (<span class='pystring'>'D'</span>, 500),
+ (<span class='pystring'>'CD'</span>, 400),
+ (<span class='pystring'>'C'</span>, 100),
+ (<span class='pystring'>'XC'</span>, 90),
+ (<span class='pystring'>'L'</span>, 50),
+ (<span class='pystring'>'XL'</span>, 40),
+ (<span class='pystring'>'X'</span>, 10),
+ (<span class='pystring'>'IX'</span>, 9),
+ (<span class='pystring'>'V'</span>, 5),
+ (<span class='pystring'>'IV'</span>, 4),
+ (<span class='pystring'>'I'</span>, 1))
+
+<span class='pykeyword'>def</span><span class='pyclass'> toRoman</span>(n):
+ <span class='pystring'>"""convert integer to Roman numeral"""</span>
+ <span class='pykeyword'>if</span> <span class='pykeyword'>not</span> (0 &lt; n &lt; 4000): <a name="roman.stage3.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ <span class='pykeyword'>raise</span> OutOfRangeError, <span class='pystring'>"number out of range (must be 1..3999)"</span> <a name="roman.stage3.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+ <span class='pykeyword'>if</span> int(n) &lt;&gt; n: <a name="roman.stage3.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+ <span class='pykeyword'>raise</span> NotIntegerError, <span class='pystring'>"non-integers can not be converted"</span>
+
+ result = <span class='pystring'>""</span> <a name="roman.stage3.1.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+ <span class='pykeyword'>for</span> numeral, integer <span class='pykeyword'>in</span> romanNumeralMap:
+ <span class='pykeyword'>while</span> n &gt;= integer:
+ result += numeral
+ n -= integer
+ <span class='pykeyword'>return</span> result
+
+<span class='pykeyword'>def</span><span class='pyclass'> fromRoman</span>(s):
+ <span class='pystring'>"""convert Roman numeral to integer"""</span>
+ <span class='pykeyword'>pass</span>
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.stage3.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This is a nice <span class="application">Python</span>ic shortcut: multiple comparisons at once. This is equivalent to <tt class="literal">if not ((0 &lt; n) and (n &lt; 4000))</tt>, but it's much easier to read. This is the range check, and it should catch inputs that are too large, negative, or zero.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.stage3.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You raise exceptions yourself with the <tt class="literal">raise</tt> statement. You can raise any of the built-in exceptions, or you can raise any of your custom exceptions that you've defined.
+ The second parameter, the error message, is optional; if given, it is displayed in the traceback that is printed if the exception
+ is never handled.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.stage3.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This is the non-integer check. Non-integers can not be converted to Roman numerals.</td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.stage3.1.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The rest of the function is unchanged.</td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="d0e33410"></a><h3 class="title">Example&nbsp;14.7.&nbsp;Watching <tt class="function">toRoman</tt> handle bad input
+ </h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> roman3</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">roman3.toRoman(4000)</span>
+<span class="traceback">Traceback (most recent call last):
+ File "&lt;interactive input&gt;", line 1, in ?
+ File "roman3.py", line 27, in toRoman
+ raise OutOfRangeError, "number out of range (must be 1..3999)"
+OutOfRangeError: number out of range (must be 1..3999)</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">roman3.toRoman(1.5)</span>
+<span class="traceback">Traceback (most recent call last):
+ File "&lt;interactive input&gt;", line 1, in ?
+ File "roman3.py", line 29, in toRoman
+ raise NotIntegerError, "non-integers can not be converted"
+NotIntegerError: non-integers can not be converted</span>
+</pre></div>
+ <div class="example"><a name="d0e33439"></a><h3 class="title">Example&nbsp;14.8.&nbsp;Output of <tt class="filename">romantest3.py</tt> against <tt class="filename">roman3.py</tt></h3><pre class="screen"><span class="computeroutput">fromRoman should only accept uppercase input ... FAIL
+toRoman should always return uppercase ... ok
+fromRoman should fail with malformed antecedents ... FAIL
+fromRoman should fail with repeated pairs of numerals ... FAIL
+fromRoman should fail with too many repeated numerals ... FAIL
+fromRoman should give known result with known input ... FAIL
+toRoman should give known result with known input ... ok </span><a name="roman.stage3.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"><span class="computeroutput">
+fromRoman(toRoman(n))==n for all n ... FAIL
+toRoman should fail with non-integer input ... ok </span><a name="roman.stage3.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"><span class="computeroutput">
+toRoman should fail with negative input ... ok </span><a name="roman.stage3.2.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"><span class="computeroutput">
+toRoman should fail with large input ... ok
+toRoman should fail with 0 input ... ok</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.stage3.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">toRoman</tt> still passes the <a href="testing_for_success.html#roman.testtoromanknownvalues.example" title="Example&nbsp;13.2.&nbsp;testToRomanKnownValues">known values test</a>, which is comforting. All the tests that passed in <a href="stage_2.html" title="14.2.&nbsp;roman.py, stage 2">stage 2</a> still pass, so the latest code hasn't broken anything.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.stage3.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">More exciting is the fact that all of the <a href="testing_for_failure.html#roman.tobadinput.example" title="Example&nbsp;13.3.&nbsp;Testing bad input to toRoman">bad input tests</a> now pass. This test, <tt class="function">testNonInteger</tt>, passes because of the <tt class="literal">int(n) &lt;&gt; n</tt> check. When a non-integer is passed to <tt class="function">toRoman</tt>, the <tt class="literal">int(n) &lt;&gt; n</tt> check notices it and raises the <tt class="errorcode">NotIntegerError</tt> exception, which is what <tt class="function">testNonInteger</tt> is looking for.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.stage3.2.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This test, <tt class="function">testNegative</tt>, passes because of the <tt class="literal">not (0 &lt; n &lt; 4000)</tt> check, which raises an <tt class="errorcode">OutOfRangeError</tt> exception, which is what <tt class="function">testNegative</tt> is looking for.
+ </td>
+ </tr>
+ </table>
+ </div><pre class="screen"><span class="computeroutput">
+======================================================================
+FAIL: fromRoman should only accept uppercase input
+----------------------------------------------------------------------
+</span><span class="traceback">Traceback (most recent call last):
+ File "C:\docbook\dip\py\roman\stage3\romantest3.py", line 156, in testFromRomanCase
+ roman3.fromRoman, numeral.lower())
+ File "c:\python21\lib\unittest.py", line 266, in failUnlessRaises
+ raise self.failureException, excName
+AssertionError: InvalidRomanNumeralError</span><span class="computeroutput">
+======================================================================
+FAIL: fromRoman should fail with malformed antecedents
+----------------------------------------------------------------------
+</span><span class="traceback">Traceback (most recent call last):
+ File "C:\docbook\dip\py\roman\stage3\romantest3.py", line 133, in testMalformedAntecedent
+ self.assertRaises(roman3.InvalidRomanNumeralError, roman3.fromRoman, s)
+ File "c:\python21\lib\unittest.py", line 266, in failUnlessRaises
+ raise self.failureException, excName
+AssertionError: InvalidRomanNumeralError</span><span class="computeroutput">
+======================================================================
+FAIL: fromRoman should fail with repeated pairs of numerals
+----------------------------------------------------------------------
+</span><span class="traceback">Traceback (most recent call last):
+ File "C:\docbook\dip\py\roman\stage3\romantest3.py", line 127, in testRepeatedPairs
+ self.assertRaises(roman3.InvalidRomanNumeralError, roman3.fromRoman, s)
+ File "c:\python21\lib\unittest.py", line 266, in failUnlessRaises
+ raise self.failureException, excName
+AssertionError: InvalidRomanNumeralError</span><span class="computeroutput">
+======================================================================
+FAIL: fromRoman should fail with too many repeated numerals
+----------------------------------------------------------------------
+</span><span class="traceback">Traceback (most recent call last):
+ File "C:\docbook\dip\py\roman\stage3\romantest3.py", line 122, in testTooManyRepeatedNumerals
+ self.assertRaises(roman3.InvalidRomanNumeralError, roman3.fromRoman, s)
+ File "c:\python21\lib\unittest.py", line 266, in failUnlessRaises
+ raise self.failureException, excName
+AssertionError: InvalidRomanNumeralError</span><span class="computeroutput">
+======================================================================
+FAIL: fromRoman should give known result with known input
+----------------------------------------------------------------------
+</span><span class="traceback">Traceback (most recent call last):
+ File "C:\docbook\dip\py\roman\stage3\romantest3.py", line 99, in testFromRomanKnownValues
+ self.assertEqual(integer, result)
+ File "c:\python21\lib\unittest.py", line 273, in failUnlessEqual
+ raise self.failureException, (msg or '%s != %s' % (first, second))
+AssertionError: 1 != None</span><span class="computeroutput">
+======================================================================
+FAIL: fromRoman(toRoman(n))==n for all n
+----------------------------------------------------------------------
+</span><span class="traceback">Traceback (most recent call last):
+ File "C:\docbook\dip\py\roman\stage3\romantest3.py", line 141, in testSanity
+ self.assertEqual(integer, result)
+ File "c:\python21\lib\unittest.py", line 273, in failUnlessEqual
+ raise self.failureException, (msg or '%s != %s' % (first, second))
+AssertionError: 1 != None</span><span class="computeroutput">
+----------------------------------------------------------------------
+Ran 12 tests in 0.401s
+
+FAILED (failures=6)</span> <a name="roman.stage3.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.stage3.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You're down to 6 failures, and all of them involve <tt class="function">fromRoman</tt>: the known values test, the three separate bad input tests, the case check, and the sanity check. That means that <tt class="function">toRoman</tt> has passed all the tests it can pass by itself. (It's involved in the sanity check, but that also requires that <tt class="function">fromRoman</tt> be written, which it isn't yet.) Which means that you must stop coding <tt class="function">toRoman</tt> now. No tweaking, no twiddling, no extra checks &#8220;<span class="quote">just in case</span>&#8221;. Stop. Now. Back away from the keyboard.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div><a name="d0e33558"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">The most important thing that comprehensive unit testing can tell you is when to stop coding. When all the unit tests for
+ a function pass, stop coding the function. When all the unit tests for an entire module pass, stop coding the module.
+ </td>
+ </tr>
+ </table>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="stage_2.html">&lt;&lt;&nbsp;roman.py, stage 2</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="stage_1.html#roman.stage1" title="14.1.&nbsp;roman.py, stage 1">1</a> <span class="divider">|</span> <a href="stage_2.html" title="14.2.&nbsp;roman.py, stage 2">2</a> <span class="divider">|</span> <span class="thispage">3</span> <span class="divider">|</span> <a href="stage_4.html" title="14.4.&nbsp;roman.py, stage 4">4</a> <span class="divider">|</span> <a href="stage_5.html" title="14.5.&nbsp;roman.py, stage 5">5</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="stage_4.html">roman.py, stage 4&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/unit_testing/stage_4.html b/help/diveintopython-5.4/html/unit_testing/stage_4.html
new file mode 100644
index 0000000..995f6b2
--- /dev/null
+++ b/help/diveintopython-5.4/html/unit_testing/stage_4.html
@@ -0,0 +1,206 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>14.4.&nbsp;roman.py, stage 4</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="stage_1.html" title="Chapter&nbsp;14.&nbsp;Test-First Programming">
+ <link rel="previous" href="stage_3.html" title="14.3.&nbsp;roman.py, stage 3">
+ <link rel="next" href="stage_5.html" title="14.5.&nbsp;roman.py, stage 5">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="stage_1.html">Test-First Programming</a>&nbsp;&gt;&nbsp;<span class="thispage">roman.py, stage 4</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="stage_3.html" title="Prev: &#8220;roman.py, stage 3&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="stage_5.html" title="Next: &#8220;roman.py, stage 5&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="roman.stage4"></a>14.4.&nbsp;<tt class="filename">roman.py</tt>, stage 4
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>Now that <tt class="function">toRoman</tt> is done, it's time to start coding <tt class="function">fromRoman</tt>. Thanks to the rich data structure that maps individual Roman numerals to integer values, this is no more difficult than
+ the <tt class="function">toRoman</tt> function.
+ </p>
+ </div>
+ <div class="example"><a name="d0e33582"></a><h3 class="title">Example&nbsp;14.9.&nbsp;<tt class="filename">roman4.py</tt></h3>
+ <p>This file is available in <tt class="filename">py/roman/stage4/</tt> in the examples directory.
+ </p>
+ <p>If you have not already done so, you can <a href="http://diveintopython.org/download/diveintopython-examples-5.4.zip" title="Download example scripts">download this and other examples</a> used in this book.
+ </p><pre class="programlisting">
+<span class='pystring'>"""Convert to and from Roman numerals"""</span>
+
+<span class='pycomment'>#Define exceptions</span>
+<span class='pykeyword'>class</span><span class='pyclass'> RomanError</span>(Exception): <span class='pykeyword'>pass</span>
+<span class='pykeyword'>class</span><span class='pyclass'> OutOfRangeError</span>(RomanError): <span class='pykeyword'>pass</span>
+<span class='pykeyword'>class</span><span class='pyclass'> NotIntegerError</span>(RomanError): <span class='pykeyword'>pass</span>
+<span class='pykeyword'>class</span><span class='pyclass'> InvalidRomanNumeralError</span>(RomanError): <span class='pykeyword'>pass</span>
+
+<span class='pycomment'>#Define digit mapping</span>
+romanNumeralMap = ((<span class='pystring'>'M'</span>, 1000),
+ (<span class='pystring'>'CM'</span>, 900),
+ (<span class='pystring'>'D'</span>, 500),
+ (<span class='pystring'>'CD'</span>, 400),
+ (<span class='pystring'>'C'</span>, 100),
+ (<span class='pystring'>'XC'</span>, 90),
+ (<span class='pystring'>'L'</span>, 50),
+ (<span class='pystring'>'XL'</span>, 40),
+ (<span class='pystring'>'X'</span>, 10),
+ (<span class='pystring'>'IX'</span>, 9),
+ (<span class='pystring'>'V'</span>, 5),
+ (<span class='pystring'>'IV'</span>, 4),
+ (<span class='pystring'>'I'</span>, 1))
+
+<span class='pycomment'># toRoman function omitted for clarity (it hasn't changed)</span>
+
+<span class='pykeyword'>def</span><span class='pyclass'> fromRoman</span>(s):
+ <span class='pystring'>"""convert Roman numeral to integer"""</span>
+ result = 0
+ index = 0
+ <span class='pykeyword'>for</span> numeral, integer <span class='pykeyword'>in</span> romanNumeralMap:
+ <span class='pykeyword'>while</span> s[index:index+len(numeral)] == numeral: <a name="roman.stage4.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ result += integer
+ index += len(numeral)
+ <span class='pykeyword'>return</span> result
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.stage4.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The pattern here is the same as <a href="stage_2.html#roman.stage2.example" title="Example&nbsp;14.3.&nbsp;roman2.py"><tt class="function">toRoman</tt></a>. You iterate through your Roman numeral data structure (a tuple of tuples), and instead of matching the highest integer
+ values as often as possible, you match the &#8220;<span class="quote">highest</span>&#8221; Roman numeral character strings as often as possible.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="d0e33611"></a><h3 class="title">Example&nbsp;14.10.&nbsp;How <tt class="function">fromRoman</tt> works
+ </h3>
+ <p>If you're not clear how <tt class="function">fromRoman</tt> works, add a <tt class="function">print</tt> statement to the end of the <tt class="literal">while</tt> loop:
+ </p><pre class="programlisting">
+ <span class='pykeyword'>while</span> s[index:index+len(numeral)] == numeral:
+ result += integer
+ index += len(numeral)
+ <span class='pykeyword'>print</span> <span class='pystring'>'found'</span>, numeral, <span class='pystring'>'of length'</span>, len(numeral), <span class='pystring'>', adding'</span>, integer</pre><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> roman4</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">roman4.fromRoman(<span class='pystring'>'MCMLXXII'</span>)</span>
+<span class="computeroutput">found M , of length 1, adding 1000
+found CM , of length 2, adding 900
+found L , of length 1, adding 50
+found X , of length 1, adding 10
+found X , of length 1, adding 10
+found I , of length 1, adding 1
+found I , of length 1, adding 1
+1972</span></pre></div>
+ <div class="example"><a name="d0e33644"></a><h3 class="title">Example&nbsp;14.11.&nbsp;Output of <tt class="filename">romantest4.py</tt> against <tt class="filename">roman4.py</tt></h3><pre class="screen"><span class="computeroutput">fromRoman should only accept uppercase input ... FAIL
+toRoman should always return uppercase ... ok
+fromRoman should fail with malformed antecedents ... FAIL
+fromRoman should fail with repeated pairs of numerals ... FAIL
+fromRoman should fail with too many repeated numerals ... FAIL
+fromRoman should give known result with known input ... ok </span><a name="roman.stage4.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"><span class="computeroutput">
+toRoman should give known result with known input ... ok
+fromRoman(toRoman(n))==n for all n ... ok </span><a name="roman.stage4.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"><span class="computeroutput">
+toRoman should fail with non-integer input ... ok
+toRoman should fail with negative input ... ok
+toRoman should fail with large input ... ok
+toRoman should fail with 0 input ... ok</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.stage4.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Two pieces of exciting news here. The first is that <tt class="function">fromRoman</tt> works for good input, at least for all the <a href="testing_for_success.html#roman.testtoromanknownvalues.example" title="Example&nbsp;13.2.&nbsp;testToRomanKnownValues">known values</a> you test.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.stage4.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The second is that the <a href="testing_for_sanity.html#roman.sanity.example" title="Example&nbsp;13.5.&nbsp;Testing toRoman against fromRoman">sanity check</a> also passed. Combined with the known values tests, you can be reasonably sure that both <tt class="function">toRoman</tt> and <tt class="function">fromRoman</tt> work properly for all possible good values. (This is not guaranteed; it is theoretically possible that <tt class="function">toRoman</tt> has a bug that produces the wrong Roman numeral for some particular set of inputs, <span class="emphasis"><em>and</em></span> that <tt class="function">fromRoman</tt> has a reciprocal bug that produces the same wrong integer values for exactly that set of Roman numerals that <tt class="function">toRoman</tt> generated incorrectly. Depending on your application and your requirements, this possibility may bother you; if so, write
+ more comprehensive test cases until it doesn't bother you.)
+ </td>
+ </tr>
+ </table>
+ </div><pre class="screen"><span class="computeroutput">
+======================================================================
+FAIL: fromRoman should only accept uppercase input
+----------------------------------------------------------------------
+</span><span class="traceback">Traceback (most recent call last):
+ File "C:\docbook\dip\py\roman\stage4\romantest4.py", line 156, in testFromRomanCase
+ roman4.fromRoman, numeral.lower())
+ File "c:\python21\lib\unittest.py", line 266, in failUnlessRaises
+ raise self.failureException, excName
+AssertionError: InvalidRomanNumeralError</span><span class="computeroutput">
+======================================================================
+FAIL: fromRoman should fail with malformed antecedents
+----------------------------------------------------------------------
+</span><span class="traceback">Traceback (most recent call last):
+ File "C:\docbook\dip\py\roman\stage4\romantest4.py", line 133, in testMalformedAntecedent
+ self.assertRaises(roman4.InvalidRomanNumeralError, roman4.fromRoman, s)
+ File "c:\python21\lib\unittest.py", line 266, in failUnlessRaises
+ raise self.failureException, excName
+AssertionError: InvalidRomanNumeralError</span><span class="computeroutput">
+======================================================================
+FAIL: fromRoman should fail with repeated pairs of numerals
+----------------------------------------------------------------------
+</span><span class="traceback">Traceback (most recent call last):
+ File "C:\docbook\dip\py\roman\stage4\romantest4.py", line 127, in testRepeatedPairs
+ self.assertRaises(roman4.InvalidRomanNumeralError, roman4.fromRoman, s)
+ File "c:\python21\lib\unittest.py", line 266, in failUnlessRaises
+ raise self.failureException, excName
+AssertionError: InvalidRomanNumeralError</span><span class="computeroutput">
+======================================================================
+FAIL: fromRoman should fail with too many repeated numerals
+----------------------------------------------------------------------
+</span><span class="traceback">Traceback (most recent call last):
+ File "C:\docbook\dip\py\roman\stage4\romantest4.py", line 122, in testTooManyRepeatedNumerals
+ self.assertRaises(roman4.InvalidRomanNumeralError, roman4.fromRoman, s)
+ File "c:\python21\lib\unittest.py", line 266, in failUnlessRaises
+ raise self.failureException, excName
+AssertionError: InvalidRomanNumeralError</span><span class="computeroutput">
+----------------------------------------------------------------------
+Ran 12 tests in 1.222s
+
+FAILED (failures=4)</span></pre></div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="stage_3.html">&lt;&lt;&nbsp;roman.py, stage 3</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="stage_1.html#roman.stage1" title="14.1.&nbsp;roman.py, stage 1">1</a> <span class="divider">|</span> <a href="stage_2.html" title="14.2.&nbsp;roman.py, stage 2">2</a> <span class="divider">|</span> <a href="stage_3.html" title="14.3.&nbsp;roman.py, stage 3">3</a> <span class="divider">|</span> <span class="thispage">4</span> <span class="divider">|</span> <a href="stage_5.html" title="14.5.&nbsp;roman.py, stage 5">5</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="stage_5.html">roman.py, stage 5&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/unit_testing/stage_5.html b/help/diveintopython-5.4/html/unit_testing/stage_5.html
new file mode 100644
index 0000000..a7c2b5a
--- /dev/null
+++ b/help/diveintopython-5.4/html/unit_testing/stage_5.html
@@ -0,0 +1,222 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>14.5.&nbsp;roman.py, stage 5</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="stage_1.html" title="Chapter&nbsp;14.&nbsp;Test-First Programming">
+ <link rel="previous" href="stage_4.html" title="14.4.&nbsp;roman.py, stage 4">
+ <link rel="next" href="../refactoring/index.html" title="Chapter&nbsp;15.&nbsp;Refactoring">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="stage_1.html">Test-First Programming</a>&nbsp;&gt;&nbsp;<span class="thispage">roman.py, stage 5</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="stage_4.html" title="Prev: &#8220;roman.py, stage 4&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="../refactoring/index.html" title="Next: &#8220;Refactoring&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="roman.stage5"></a>14.5.&nbsp;<tt class="filename">roman.py</tt>, stage 5
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>Now that <tt class="function">fromRoman</tt> works properly with good input, it's time to fit in the last piece of the puzzle: making it work properly with bad input.
+ That means finding a way to look at a string and determine if it's a valid Roman numeral. This is inherently more difficult
+ than <a href="stage_3.html" title="14.3.&nbsp;roman.py, stage 3">validating numeric input</a> in <tt class="function">toRoman</tt>, but you have a powerful tool at your disposal: regular expressions.
+ </p>
+ </div>
+ <p>If you're not familiar with regular expressions and didn't read <a href="../regular_expressions/index.html" title="Chapter&nbsp;7.&nbsp;Regular Expressions">Chapter&nbsp;7, <i>Regular Expressions</i></a>, now would be a good time.
+ </p>
+ <p>As you saw in <a href="../regular_expressions/roman_numerals.html" title="7.3.&nbsp;Case Study: Roman Numerals">Section&nbsp;7.3, &#8220;Case Study: Roman Numerals&#8221;</a>, there are several simple rules for constructing a Roman numeral, using the letters <tt class="literal">M</tt>, <tt class="literal">D</tt>, <tt class="literal">C</tt>, <tt class="literal">L</tt>, <tt class="literal">X</tt>, <tt class="literal">V</tt>, and <tt class="literal">I</tt>. Let's review the rules:
+ </p>
+ <div class="orderedlist">
+ <ol type="1">
+ <li>Characters are additive. <tt class="literal">I</tt> is <tt class="constant">1</tt>, <tt class="literal">II</tt> is <tt class="literal">2</tt>, and <tt class="literal">III</tt> is <tt class="literal">3</tt>. <tt class="literal">VI</tt> is <tt class="literal">6</tt> (literally, &#8220;<span class="quote"><tt class="literal">5</tt> and <tt class="literal">1</tt></span>&#8221;), <tt class="literal">VII</tt> is <tt class="literal">7</tt>, and <tt class="literal">VIII</tt> is <tt class="literal">8</tt>.
+ </li>
+ <li>The tens characters (<tt class="literal">I</tt>, <tt class="literal">X</tt>, <tt class="literal">C</tt>, and <tt class="literal">M</tt>) can be repeated up to three times. At <tt class="literal">4</tt>, you need to subtract from the next highest fives character. You can't represent <tt class="literal">4</tt> as <tt class="literal">IIII</tt>; instead, it is represented as <tt class="literal">IV</tt> (&#8220;<span class="quote"><tt class="literal">1</tt> less than <tt class="literal">5</tt></span>&#8221;). <tt class="literal">40</tt> is written as <tt class="literal">XL</tt> (&#8220;<span class="quote"><tt class="literal">10</tt> less than <tt class="literal">50</tt></span>&#8221;), <tt class="literal">41</tt> as <tt class="literal">XLI</tt>, <tt class="literal">42</tt> as <tt class="literal">XLII</tt>, <tt class="literal">43</tt> as <tt class="literal">XLIII</tt>, and then <tt class="literal">44</tt> as <tt class="literal">XLIV</tt> (&#8220;<span class="quote"><tt class="literal">10</tt> less than <tt class="literal">50</tt>, then <tt class="literal">1</tt> less than <tt class="literal">5</tt></span>&#8221;).
+ </li>
+ <li>Similarly, at <tt class="literal">9</tt>, you need to subtract from the next highest tens character: <tt class="literal">8</tt> is <tt class="literal">VIII</tt>, but <tt class="literal">9</tt> is <tt class="literal">IX</tt> (&#8220;<span class="quote"><tt class="literal">1</tt> less than <tt class="literal">10</tt></span>&#8221;), not <tt class="literal">VIIII</tt> (since the <tt class="literal">I</tt> character can not be repeated four times). <tt class="literal">90</tt> is <tt class="literal">XC</tt>, <tt class="literal">900</tt> is <tt class="literal">CM</tt>.
+ </li>
+ <li>The fives characters can not be repeated. <tt class="literal">10</tt> is always represented as <tt class="literal">X</tt>, never as <tt class="literal">VV</tt>. <tt class="literal">100</tt> is always <tt class="literal">C</tt>, never <tt class="literal">LL</tt>.
+ </li>
+ <li>Roman numerals are always written highest to lowest, and read left to right, so order of characters matters very much. <tt class="literal">DC</tt> is <tt class="literal">600</tt>; <tt class="literal">CD</tt> is a completely different number (<tt class="literal">400</tt>, &#8220;<span class="quote"><tt class="literal">100</tt> less than <tt class="literal">500</tt></span>&#8221;). <tt class="literal">CI</tt> is <tt class="literal">101</tt>; <tt class="literal">IC</tt> is not even a valid Roman numeral (because you can't subtract <tt class="literal">1</tt> directly from <tt class="literal">100</tt>; you would need to write it as <tt class="literal">XCIX</tt>, &#8220;<span class="quote"><tt class="literal">10</tt> less than <tt class="literal">100</tt>, then <tt class="literal">1</tt> less than <tt class="literal">10</tt></span>&#8221;).
+ </li>
+ </ol>
+ </div>
+ <div class="example"><a name="d0e34010"></a><h3 class="title">Example&nbsp;14.12.&nbsp;<tt class="filename">roman5.py</tt></h3>
+ <p>This file is available in <tt class="filename">py/roman/stage5/</tt> in the examples directory.
+ </p>
+ <p>If you have not already done so, you can <a href="http://diveintopython.org/download/diveintopython-examples-5.4.zip" title="Download example scripts">download this and other examples</a> used in this book.
+ </p><pre class="programlisting">
+<span class='pystring'>"""Convert to and from Roman numerals"""</span>
+<span class='pykeyword'>import</span> re
+
+<span class='pycomment'>#Define exceptions</span>
+<span class='pykeyword'>class</span><span class='pyclass'> RomanError</span>(Exception): <span class='pykeyword'>pass</span>
+<span class='pykeyword'>class</span><span class='pyclass'> OutOfRangeError</span>(RomanError): <span class='pykeyword'>pass</span>
+<span class='pykeyword'>class</span><span class='pyclass'> NotIntegerError</span>(RomanError): <span class='pykeyword'>pass</span>
+<span class='pykeyword'>class</span><span class='pyclass'> InvalidRomanNumeralError</span>(RomanError): <span class='pykeyword'>pass</span>
+
+<span class='pycomment'>#Define digit mapping</span>
+romanNumeralMap = ((<span class='pystring'>'M'</span>, 1000),
+ (<span class='pystring'>'CM'</span>, 900),
+ (<span class='pystring'>'D'</span>, 500),
+ (<span class='pystring'>'CD'</span>, 400),
+ (<span class='pystring'>'C'</span>, 100),
+ (<span class='pystring'>'XC'</span>, 90),
+ (<span class='pystring'>'L'</span>, 50),
+ (<span class='pystring'>'XL'</span>, 40),
+ (<span class='pystring'>'X'</span>, 10),
+ (<span class='pystring'>'IX'</span>, 9),
+ (<span class='pystring'>'V'</span>, 5),
+ (<span class='pystring'>'IV'</span>, 4),
+ (<span class='pystring'>'I'</span>, 1))
+
+<span class='pykeyword'>def</span><span class='pyclass'> toRoman</span>(n):
+ <span class='pystring'>"""convert integer to Roman numeral"""</span>
+ <span class='pykeyword'>if</span> <span class='pykeyword'>not</span> (0 &lt; n &lt; 4000):
+ <span class='pykeyword'>raise</span> OutOfRangeError, <span class='pystring'>"number out of range (must be 1..3999)"</span>
+ <span class='pykeyword'>if</span> int(n) &lt;&gt; n:
+ <span class='pykeyword'>raise</span> NotIntegerError, <span class='pystring'>"non-integers can not be converted"</span>
+
+ result = <span class='pystring'>""</span>
+ <span class='pykeyword'>for</span> numeral, integer <span class='pykeyword'>in</span> romanNumeralMap:
+ <span class='pykeyword'>while</span> n &gt;= integer:
+ result += numeral
+ n -= integer
+ <span class='pykeyword'>return</span> result
+
+<span class='pycomment'>#Define pattern to detect valid Roman numerals</span>
+romanNumeralPattern = <span class='pystring'>'^M?M?M?(CM|CD|D?C?C?C?)(XC|XL|L?X?X?X?)(IX|IV|V?I?I?I?)$'</span> <a name="roman.stage5.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+
+<span class='pykeyword'>def</span><span class='pyclass'> fromRoman</span>(s):
+ <span class='pystring'>"""convert Roman numeral to integer"""</span>
+ <span class='pykeyword'>if</span> <span class='pykeyword'>not</span> re.search(romanNumeralPattern, s): <a name="roman.stage5.3.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+ <span class='pykeyword'>raise</span> InvalidRomanNumeralError, <span class='pystring'>'Invalid Roman numeral: %s'</span> % s
+
+ result = 0
+ index = 0
+ <span class='pykeyword'>for</span> numeral, integer <span class='pykeyword'>in</span> romanNumeralMap:
+ <span class='pykeyword'>while</span> s[index:index+len(numeral)] == numeral:
+ result += integer
+ index += len(numeral)
+ <span class='pykeyword'>return</span> result
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.stage5.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This is just a continuation of the pattern you discussed in <a href="../regular_expressions/roman_numerals.html" title="7.3.&nbsp;Case Study: Roman Numerals">Section&nbsp;7.3, &#8220;Case Study: Roman Numerals&#8221;</a>. The tens places is either <tt class="literal">XC</tt> (<tt class="literal">90</tt>), <tt class="literal">XL</tt> (<tt class="literal">40</tt>), or an optional <tt class="literal">L</tt> followed by 0 to 3 optional <tt class="literal">X</tt> characters. The ones place is either <tt class="literal">IX</tt> (<tt class="literal">9</tt>), <tt class="literal">IV</tt> (<tt class="literal">4</tt>), or an optional <tt class="literal">V</tt> followed by 0 to 3 optional <tt class="literal">I</tt> characters.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.stage5.3.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Having encoded all that logic into a regular expression, the code to check for invalid Roman numerals becomes trivial. If
+ <tt class="function">re.search</tt> returns an object, then the regular expression matched and the input is valid; otherwise, the input is invalid.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>At this point, you are allowed to be skeptical that that big ugly regular expression could possibly catch all the types of
+ invalid Roman numerals. But don't take my word for it, look at the results:
+ </p>
+ <div class="example"><a name="d0e34080"></a><h3 class="title">Example&nbsp;14.13.&nbsp;Output of <tt class="filename">romantest5.py</tt> against <tt class="filename">roman5.py</tt></h3><pre class="screen"><span class="computeroutput">
+fromRoman should only accept uppercase input ... ok </span><a name="roman.stage5.4.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"><span class="computeroutput">
+toRoman should always return uppercase ... ok
+fromRoman should fail with malformed antecedents ... ok </span><a name="roman.stage5.4.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"><span class="computeroutput">
+fromRoman should fail with repeated pairs of numerals ... ok </span><a name="roman.stage5.4.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"><span class="computeroutput">
+fromRoman should fail with too many repeated numerals ... ok
+fromRoman should give known result with known input ... ok
+toRoman should give known result with known input ... ok
+fromRoman(toRoman(n))==n for all n ... ok
+toRoman should fail with non-integer input ... ok
+toRoman should fail with negative input ... ok
+toRoman should fail with large input ... ok
+toRoman should fail with 0 input ... ok
+
+----------------------------------------------------------------------
+Ran 12 tests in 2.864s
+
+OK </span><a name="roman.stage5.4.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.stage5.4.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">One thing I didn't mention about regular expressions is that, by default, they are case-sensitive. Since the regular expression
+ <tt class="varname">romanNumeralPattern</tt> was expressed in uppercase characters, the <tt class="function">re.search</tt> check will reject any input that isn't completely uppercase. So the uppercase input test passes.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.stage5.4.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">More importantly, the bad input tests pass. For instance, the malformed antecedents test checks cases like <tt class="literal">MCMC</tt>. As you've seen, this does not match the regular expression, so <tt class="function">fromRoman</tt> raises an <tt class="errorcode">InvalidRomanNumeralError</tt> exception, which is what the malformed antecedents test case is looking for, so the test passes.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.stage5.4.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">In fact, all the bad input tests pass. This regular expression catches everything you could think of when you made your test
+ cases.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.stage5.4.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">And the anticlimax award of the year goes to the word &#8220;<span class="quote"><tt class="literal">OK</tt></span>&#8221;, which is printed by the <tt class="filename">unittest</tt> module when all the tests pass.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div><a name="d0e34136"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">When all of your tests pass, stop coding.</td>
+ </tr>
+ </table>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="stage_4.html">&lt;&lt;&nbsp;roman.py, stage 4</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="stage_1.html#roman.stage1" title="14.1.&nbsp;roman.py, stage 1">1</a> <span class="divider">|</span> <a href="stage_2.html" title="14.2.&nbsp;roman.py, stage 2">2</a> <span class="divider">|</span> <a href="stage_3.html" title="14.3.&nbsp;roman.py, stage 3">3</a> <span class="divider">|</span> <a href="stage_4.html" title="14.4.&nbsp;roman.py, stage 4">4</a> <span class="divider">|</span> <span class="thispage">5</span>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="../refactoring/index.html">Refactoring&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/unit_testing/testing_for_failure.html b/help/diveintopython-5.4/html/unit_testing/testing_for_failure.html
new file mode 100644
index 0000000..0addafe
--- /dev/null
+++ b/help/diveintopython-5.4/html/unit_testing/testing_for_failure.html
@@ -0,0 +1,164 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>13.5.&nbsp;Testing for failure</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;13.&nbsp;Unit Testing">
+ <link rel="previous" href="testing_for_success.html" title="13.4.&nbsp;Testing for success">
+ <link rel="next" href="testing_for_sanity.html" title="13.6.&nbsp;Testing for sanity">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Unit Testing</a>&nbsp;&gt;&nbsp;<span class="thispage">Testing for failure</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="testing_for_success.html" title="Prev: &#8220;Testing for success&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="testing_for_sanity.html" title="Next: &#8220;Testing for sanity&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="roman.failure"></a>13.5.&nbsp;Testing for failure
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>It is not enough to test that functions succeed when given good input; you must also test that they fail when given bad input.
+ And not just any sort of failure; they must fail in the way you expect.
+ </p>
+ </div>
+ <p>Remember the <a href="index.html#roman.requirements">other requirements</a> for <tt class="function">toRoman</tt>:
+ </p>
+ <div class="orderedlist">
+ <ol start="2" type="1">
+ <li><tt class="function">toRoman</tt> should fail when given an integer outside the range <tt class="constant">1</tt> to <tt class="literal">3999</tt>.
+ </li>
+ <li><tt class="function">toRoman</tt> should fail when given a non-integer number.
+ </li>
+ </ol>
+ </div>
+ <p>In <span class="application">Python</span>, functions indicate failure by raising <a href="../file_handling/index.html#fileinfo.exception" title="6.1.&nbsp;Handling Exceptions">exceptions</a>, and the <tt class="filename">unittest</tt> module provides methods for testing whether a function raises a particular exception when given bad input.
+ </p>
+ <div class="example"><a name="roman.tobadinput.example"></a><h3 class="title">Example&nbsp;13.3.&nbsp;Testing bad input to <tt class="function">toRoman</tt></h3><pre class="programlisting"><span class='pykeyword'>
+class</span> ToRomanBadInput(unittest.TestCase):
+ <span class='pykeyword'>def</span><span class='pyclass'> testTooLarge</span>(self):
+ <span class='pystring'>"""toRoman should fail with large input"""</span>
+ self.assertRaises(roman.OutOfRangeError, roman.toRoman, 4000) <a name="roman.failure.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+
+ <span class='pykeyword'>def</span><span class='pyclass'> testZero</span>(self):
+ <span class='pystring'>"""toRoman should fail with 0 input"""</span>
+ self.assertRaises(roman.OutOfRangeError, roman.toRoman, 0) <a name="roman.failure.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+
+ <span class='pykeyword'>def</span><span class='pyclass'> testNegative</span>(self):
+ <span class='pystring'>"""toRoman should fail with negative input"""</span>
+ self.assertRaises(roman.OutOfRangeError, roman.toRoman, -1)
+
+ <span class='pykeyword'>def</span><span class='pyclass'> testNonInteger</span>(self):
+ <span class='pystring'>"""toRoman should fail with non-integer input"""</span>
+ self.assertRaises(roman.NotIntegerError, roman.toRoman, 0.5) <a name="roman.failure.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.failure.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="classname">TestCase</tt> class of the <tt class="filename">unittest</tt> provides the <tt class="function">assertRaises</tt> method, which takes the following arguments: the exception you're expecting, the function you're testing, and the arguments
+ you're passing that function. (If the function you're testing takes more than one argument, pass them all to <tt class="function">assertRaises</tt>, in order, and it will pass them right along to the function you're testing.) Pay close attention to what you're doing here:
+ instead of calling <tt class="function">toRoman</tt> directly and manually checking that it raises a particular exception (by wrapping it in a <a href="../file_handling/index.html#fileinfo.exception" title="6.1.&nbsp;Handling Exceptions"><tt class="literal">try...except</tt> block</a>), <tt class="function">assertRaises</tt> has encapsulated all of that for us. All you do is give it the exception (<tt class="errorcode">roman.OutOfRangeError</tt>), the function (<tt class="function">toRoman</tt>), and <tt class="function">toRoman</tt>'s arguments (<tt class="literal">4000</tt>), and <tt class="function">assertRaises</tt> takes care of calling <tt class="function">toRoman</tt> and checking to make sure that it raises <tt class="errorcode">roman.OutOfRangeError</tt>. (Also note that you're passing the <tt class="function">toRoman</tt> function itself as an argument; you're not calling it, and you're not passing the name of it as a string. Have I mentioned
+ recently how handy it is that <a href="../getting_to_know_python/everything_is_an_object.html" title="2.4.&nbsp;Everything Is an Object">everything in <span class="application">Python</span> is an object</a>, including functions and exceptions?)
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.failure.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Along with testing numbers that are too large, you need to test numbers that are too small. Remember, Roman numerals cannot
+ express <tt class="constant">0</tt> or negative numbers, so you have a test case for each of those (<tt class="function">testZero</tt> and <tt class="function">testNegative</tt>). In <tt class="function">testZero</tt>, you are testing that <tt class="function">toRoman</tt> raises a <tt class="errorcode">roman.OutOfRangeError</tt> exception when called with <tt class="constant">0</tt>; if it does <span class="emphasis"><em>not</em></span> raise a <tt class="errorcode">roman.OutOfRangeError</tt> (either because it returns an actual value, or because it raises some other exception), this test is considered failed.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.failure.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><a href="index.html#roman.requirements">Requirement #3</a> specifies that <tt class="function">toRoman</tt> cannot accept a non-integer number, so here you test to make sure that <tt class="function">toRoman</tt> raises a <tt class="errorcode">roman.NotIntegerError</tt> exception when called with <tt class="literal">0.5</tt>. If <tt class="function">toRoman</tt> does not raise a <tt class="errorcode">roman.NotIntegerError</tt>, this test is considered failed.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>The next two <a href="index.html#roman.requirements">requirements</a> are similar to the first three, except they apply to <tt class="function">fromRoman</tt> instead of <tt class="function">toRoman</tt>:
+ </p>
+ <div class="orderedlist">
+ <ol start="4" type="1">
+ <li><tt class="function">fromRoman</tt> should take a valid Roman numeral and return the number that it represents.
+ </li>
+ <li><tt class="function">fromRoman</tt> should fail when given an invalid Roman numeral.
+ </li>
+ </ol>
+ </div>
+ <p>Requirement #4 is handled in the same way as <a href="testing_for_success.html#roman.testtoromanknownvalues.example" title="Example&nbsp;13.2.&nbsp;testToRomanKnownValues">requirement #1</a>, iterating through a sampling of known values and testing each in turn. Requirement #5 is handled in the same way as requirements
+ #2 and #3, by testing a series of bad inputs and making sure <tt class="function">fromRoman</tt> raises the appropriate exception.
+ </p>
+ <div class="example"><a name="roman.frombadinput.example"></a><h3 class="title">Example&nbsp;13.4.&nbsp;Testing bad input to <tt class="function">fromRoman</tt></h3><pre class="programlisting"><span class='pykeyword'>
+class</span> FromRomanBadInput(unittest.TestCase):
+ <span class='pykeyword'>def</span><span class='pyclass'> testTooManyRepeatedNumerals</span>(self):
+ <span class='pystring'>"""fromRoman should fail with too many repeated numerals"""</span>
+ <span class='pykeyword'>for</span> s <span class='pykeyword'>in</span> (<span class='pystring'>'MMMM'</span>, <span class='pystring'>'DD'</span>, <span class='pystring'>'CCCC'</span>, <span class='pystring'>'LL'</span>, <span class='pystring'>'XXXX'</span>, <span class='pystring'>'VV'</span>, <span class='pystring'>'IIII'</span>):
+ self.assertRaises(roman.InvalidRomanNumeralError, roman.fromRoman, s) <a name="roman.failure.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+
+ <span class='pykeyword'>def</span><span class='pyclass'> testRepeatedPairs</span>(self):
+ <span class='pystring'>"""fromRoman should fail with repeated pairs of numerals"""</span>
+ <span class='pykeyword'>for</span> s <span class='pykeyword'>in</span> (<span class='pystring'>'CMCM'</span>, <span class='pystring'>'CDCD'</span>, <span class='pystring'>'XCXC'</span>, <span class='pystring'>'XLXL'</span>, <span class='pystring'>'IXIX'</span>, <span class='pystring'>'IVIV'</span>):
+ self.assertRaises(roman.InvalidRomanNumeralError, roman.fromRoman, s)
+
+ <span class='pykeyword'>def</span><span class='pyclass'> testMalformedAntecedent</span>(self):
+ <span class='pystring'>"""fromRoman should fail with malformed antecedents"""</span>
+ <span class='pykeyword'>for</span> s <span class='pykeyword'>in</span> (<span class='pystring'>'IIMXCC'</span>, <span class='pystring'>'VX'</span>, <span class='pystring'>'DCM'</span>, <span class='pystring'>'CMM'</span>, <span class='pystring'>'IXIV'</span>,
+ <span class='pystring'>'MCMC'</span>, <span class='pystring'>'XCX'</span>, <span class='pystring'>'IVI'</span>, <span class='pystring'>'LM'</span>, <span class='pystring'>'LD'</span>, <span class='pystring'>'LC'</span>):
+ self.assertRaises(roman.InvalidRomanNumeralError, roman.fromRoman, s)</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.failure.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Not much new to say about these; the pattern is exactly the same as the one you used to test bad input to <tt class="function">toRoman</tt>. I will briefly note that you have another exception: <tt class="errorcode">roman.InvalidRomanNumeralError</tt>. That makes a total of three custom exceptions that will need to be defined in <tt class="filename">roman.py</tt> (along with <tt class="errorcode">roman.OutOfRangeError</tt> and <tt class="errorcode">roman.NotIntegerError</tt>). You'll see how to define these custom exceptions when you actually start writing <tt class="filename">roman.py</tt>, later in this chapter.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="testing_for_success.html">&lt;&lt;&nbsp;Testing for success</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#roman.intro" title="13.1.&nbsp;Introduction to Roman numerals">1</a> <span class="divider">|</span> <a href="diving_in.html" title="13.2.&nbsp;Diving in">2</a> <span class="divider">|</span> <a href="romantest.html" title="13.3.&nbsp;Introducing romantest.py">3</a> <span class="divider">|</span> <a href="testing_for_success.html" title="13.4.&nbsp;Testing for success">4</a> <span class="divider">|</span> <span class="thispage">5</span> <span class="divider">|</span> <a href="testing_for_sanity.html" title="13.6.&nbsp;Testing for sanity">6</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="testing_for_sanity.html">Testing for sanity&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/unit_testing/testing_for_sanity.html b/help/diveintopython-5.4/html/unit_testing/testing_for_sanity.html
new file mode 100644
index 0000000..3014754
--- /dev/null
+++ b/help/diveintopython-5.4/html/unit_testing/testing_for_sanity.html
@@ -0,0 +1,181 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>13.6.&nbsp;Testing for sanity</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;13.&nbsp;Unit Testing">
+ <link rel="previous" href="testing_for_failure.html" title="13.5.&nbsp;Testing for failure">
+ <link rel="next" href="stage_1.html" title="Chapter&nbsp;14.&nbsp;Test-First Programming">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Unit Testing</a>&nbsp;&gt;&nbsp;<span class="thispage">Testing for sanity</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="testing_for_failure.html" title="Prev: &#8220;Testing for failure&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="stage_1.html" title="Next: &#8220;Test-First Programming&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="roman.sanity"></a>13.6.&nbsp;Testing for sanity
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>Often, you will find that a unit of code contains a set of reciprocal functions, usually in the form of conversion functions
+ where one converts A to B and the other converts B to A. In these cases, it is useful to create a &#8220;<span class="quote">sanity check</span>&#8221; to make sure that you can convert A to B and back to A without losing precision, incurring rounding errors, or triggering
+ any other sort of bug.
+ </p>
+ </div>
+ <p>Consider this <a href="index.html#roman.requirements">requirement</a>:
+ </p>
+ <div class="orderedlist">
+ <ol start="6" type="1">
+ <li>If you take a number, convert it to Roman numerals, then convert that back to a number, you should end up with the number
+ you started with. So <tt class="literal">fromRoman(toRoman(n)) == n</tt> for all <tt class="varname">n</tt> in <tt class="literal">1..3999</tt>.
+ </li>
+ </ol>
+ </div>
+ <div class="example"><a name="roman.sanity.example"></a><h3 class="title">Example&nbsp;13.5.&nbsp;Testing <tt class="function">toRoman</tt> against <tt class="function">fromRoman</tt></h3><pre class="programlisting"><span class='pykeyword'>
+class</span> SanityCheck(unittest.TestCase):
+ <span class='pykeyword'>def</span><span class='pyclass'> testSanity</span>(self):
+ <span class='pystring'>"""fromRoman(toRoman(n))==n for all n"""</span>
+ <span class='pykeyword'>for</span> integer <span class='pykeyword'>in</span> range(1, 4000): <a name="roman.sanity.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"> <a name="roman.sanity.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+ numeral = roman.toRoman(integer)
+ result = roman.fromRoman(numeral)
+ self.assertEqual(integer, result) <a name="roman.sanity.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.sanity.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You've seen <a href="../native_data_types/declaring_variables.html#odbchelper.multiassign.range" title="Example&nbsp;3.20.&nbsp;Assigning Consecutive Values">the <tt class="function">range</tt> function</a> before, but here it is called with two arguments, which returns a list of integers starting at the first argument (<tt class="constant">1</tt>) and counting consecutively up to <span class="emphasis"><em>but not including</em></span> the second argument (<tt class="literal">4000</tt>). Thus, <tt class="literal">1..3999</tt>, which is the valid range for converting to Roman numerals.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.sanity.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">I just wanted to mention in passing that <tt class="varname">integer</tt> is not a keyword in <span class="application">Python</span>; here it's just a variable name like any other.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.sanity.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The actual testing logic here is straightforward: take a number (<tt class="varname">integer</tt>), convert it to a Roman numeral (<tt class="varname">numeral</tt>), then convert it back to a number (<tt class="varname">result</tt>) and make sure you end up with the same number you started with. If not, <tt class="function">assertEqual</tt> will raise an exception and the test will immediately be considered failed. If all the numbers match, <tt class="function">assertEqual</tt> will always return silently, the entire <tt class="function">testSanity</tt> method will eventually return silently, and the test will be considered passed.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>The <a href="index.html#roman.requirements">last two requirements</a> are different from the others because they seem both arbitrary and trivial:
+ </p>
+ <div class="orderedlist">
+ <ol start="7" type="1">
+ <li><tt class="function">toRoman</tt> should always return a Roman numeral using uppercase letters.
+ </li>
+ <li><tt class="function">fromRoman</tt> should only accept uppercase Roman numerals (<span class="foreignphrase"><i class="foreignphrase"><span class="acronym">i.e.</span></i></span> it should fail when given lowercase input).
+ </li>
+ </ol>
+ </div>
+ <p>In fact, they are somewhat arbitrary. You could, for instance, have stipulated that <tt class="function">fromRoman</tt> accept lowercase and mixed case input. But they are not completely arbitrary; if <tt class="function">toRoman</tt> is always returning uppercase output, then <tt class="function">fromRoman</tt> must at least accept uppercase input, or the &#8220;<span class="quote">sanity check</span>&#8221; (requirement #6) would fail. The fact that it <span class="emphasis"><em>only</em></span> accepts uppercase input is arbitrary, but as any systems integrator will tell you, case always matters, so it's worth specifying
+ the behavior up front. And if it's worth specifying, it's worth testing.
+ </p>
+ <div class="example"><a name="d0e32750"></a><h3 class="title">Example&nbsp;13.6.&nbsp;Testing for case</h3><pre class="programlisting"><span class='pykeyword'>
+class</span> CaseCheck(unittest.TestCase):
+ <span class='pykeyword'>def</span><span class='pyclass'> testToRomanCase</span>(self):
+ <span class='pystring'>"""toRoman should always return uppercase"""</span>
+ <span class='pykeyword'>for</span> integer <span class='pykeyword'>in</span> range(1, 4000):
+ numeral = roman.toRoman(integer)
+ self.assertEqual(numeral, numeral.upper()) <a name="roman.sanity.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+
+ <span class='pykeyword'>def</span><span class='pyclass'> testFromRomanCase</span>(self):
+ <span class='pystring'>"""fromRoman should only accept uppercase input"""</span>
+ <span class='pykeyword'>for</span> integer <span class='pykeyword'>in</span> range(1, 4000):
+ numeral = roman.toRoman(integer)
+ roman.fromRoman(numeral.upper()) <a name="roman.sanity.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"> <a name="roman.sanity.2.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+ self.assertRaises(roman.InvalidRomanNumeralError,
+ roman.fromRoman, numeral.lower()) <a name="roman.sanity.2.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.sanity.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The most interesting thing about this test case is all the things it doesn't test. It doesn't test that the value returned
+ from <tt class="function">toRoman</tt> is <a href="testing_for_success.html#roman.testtoromanknownvalues.example" title="Example&nbsp;13.2.&nbsp;testToRomanKnownValues">right</a> or even <a href="testing_for_sanity.html#roman.sanity.example" title="Example&nbsp;13.5.&nbsp;Testing toRoman against fromRoman">consistent</a>; those questions are answered by separate test cases. You have a whole test case just to test for uppercase-ness. You might
+ be tempted to combine this with the <a href="testing_for_sanity.html#roman.sanity.example" title="Example&nbsp;13.5.&nbsp;Testing toRoman against fromRoman">sanity check</a>, since both run through the entire range of values and call <tt class="function">toRoman</tt>.<sup>[<a name="d0e32781" href="#ftn.d0e32781">6</a>]</sup> But that would violate one of the <a href="testing_for_success.html" title="13.4.&nbsp;Testing for success">fundamental rules</a>: each test case should answer only a single question. Imagine that you combined this case check with the sanity check, and
+ then that test case failed. You would need to do further analysis to figure out which part of the test case failed to determine
+ what the problem was. If you need to analyze the results of your unit testing just to figure out what they mean, it's a sure
+ sign that you've mis-designed your test cases.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.sanity.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">There's a similar lesson to be learned here: even though &#8220;<span class="quote">you know</span>&#8221; that <tt class="function">toRoman</tt> always returns uppercase, you are explicitly converting its return value to uppercase here to test that <tt class="function">fromRoman</tt> accepts uppercase input. Why? Because the fact that <tt class="function">toRoman</tt> always returns uppercase is an independent requirement. If you changed that requirement so that, for instance, it always
+ returned lowercase, the <tt class="function">testToRomanCase</tt> test case would need to change, but this test case would still work. This was another of the <a href="testing_for_success.html" title="13.4.&nbsp;Testing for success">fundamental rules</a>: each test case must be able to work in isolation from any of the others. Every test case is an island.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.sanity.2.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Note that you're not assigning the return value of <tt class="function">fromRoman</tt> to anything. This is legal syntax in <span class="application">Python</span>; if a function returns a value but nobody's listening, <span class="application">Python</span> just throws away the return value. In this case, that's what you want. This test case doesn't test anything about the return
+ value; it just tests that <tt class="function">fromRoman</tt> accepts the uppercase input without raising an exception.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.sanity.2.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This is a complicated line, but it's very similar to what you did in the <tt class="classname">ToRomanBadInput</tt> and <tt class="classname">FromRomanBadInput</tt> tests. You are testing to make sure that calling a particular function (<tt class="function">roman.fromRoman</tt>) with a particular value (<tt class="literal">numeral.lower()</tt>, the lowercase version of the current Roman numeral in the loop) raises a particular exception (<tt class="literal">roman.InvalidRomanNumeralError</tt>). If it does (each time through the loop), the test passes; if even one time it does something else (like raises a different
+ exception, or returning a value without raising an exception at all), the test fails.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>In the next chapter, you'll see how to write code that passes these tests.</p>
+ <div class="footnotes">
+ <h3 class="footnotetitle">Footnotes</h3>
+ <div class="footnote">
+ <p><sup>[<a name="ftn.d0e32781" href="#d0e32781">6</a>] </sup>&#8220;<span class="quote">I can resist everything except temptation.</span>&#8221; --Oscar Wilde
+ </p>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="testing_for_failure.html">&lt;&lt;&nbsp;Testing for failure</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#roman.intro" title="13.1.&nbsp;Introduction to Roman numerals">1</a> <span class="divider">|</span> <a href="diving_in.html" title="13.2.&nbsp;Diving in">2</a> <span class="divider">|</span> <a href="romantest.html" title="13.3.&nbsp;Introducing romantest.py">3</a> <span class="divider">|</span> <a href="testing_for_success.html" title="13.4.&nbsp;Testing for success">4</a> <span class="divider">|</span> <a href="testing_for_failure.html" title="13.5.&nbsp;Testing for failure">5</a> <span class="divider">|</span> <span class="thispage">6</span>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="stage_1.html">Test-First Programming&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/unit_testing/testing_for_success.html b/help/diveintopython-5.4/html/unit_testing/testing_for_success.html
new file mode 100644
index 0000000..26a314d
--- /dev/null
+++ b/help/diveintopython-5.4/html/unit_testing/testing_for_success.html
@@ -0,0 +1,195 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>13.4.&nbsp;Testing for success</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;13.&nbsp;Unit Testing">
+ <link rel="previous" href="romantest.html" title="13.3.&nbsp;Introducing romantest.py">
+ <link rel="next" href="testing_for_failure.html" title="13.5.&nbsp;Testing for failure">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">Unit Testing</a>&nbsp;&gt;&nbsp;<span class="thispage">Testing for success</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="romantest.html" title="Prev: &#8220;Introducing romantest.py&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="testing_for_failure.html" title="Next: &#8220;Testing for failure&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="roman.success"></a>13.4.&nbsp;Testing for success
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>The most fundamental part of unit testing is constructing individual test cases. A test case answers a single question about
+ the code it is testing.
+ </p>
+ </div>
+ <p>A test case should be able to...</p>
+ <div class="itemizedlist">
+ <ul>
+ <li>...run completely by itself, without any human input. Unit testing is about automation.</li>
+ <li>...determine by itself whether the function it is testing has passed or failed, without a human interpreting the results.</li>
+ <li>...run in isolation, separate from any other test cases (even if they test the same functions). Each test case is an island.</li>
+ </ul>
+ </div>
+ <p>Given that, let's build the first test case. You have the following <a href="index.html#roman.requirements">requirement</a>:
+ </p>
+ <div class="orderedlist">
+ <ol type="1">
+ <li><tt class="function">toRoman</tt> should return the Roman numeral representation for all integers <tt class="constant">1</tt> to <tt class="literal">3999</tt>.
+ </li>
+ </ol>
+ </div>
+ <div class="example"><a name="roman.testtoromanknownvalues.example"></a><h3 class="title">Example&nbsp;13.2.&nbsp;<tt class="function">testToRomanKnownValues</tt></h3><pre class="programlisting"><span class='pykeyword'>
+class</span> KnownValues(unittest.TestCase): <a name="roman.success.1.0"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+ knownValues = ( (1, <span class='pystring'>'I'</span>),
+ (2, <span class='pystring'>'II'</span>),
+ (3, <span class='pystring'>'III'</span>),
+ (4, <span class='pystring'>'IV'</span>),
+ (5, <span class='pystring'>'V'</span>),
+ (6, <span class='pystring'>'VI'</span>),
+ (7, <span class='pystring'>'VII'</span>),
+ (8, <span class='pystring'>'VIII'</span>),
+ (9, <span class='pystring'>'IX'</span>),
+ (10, <span class='pystring'>'X'</span>),
+ (50, <span class='pystring'>'L'</span>),
+ (100, <span class='pystring'>'C'</span>),
+ (500, <span class='pystring'>'D'</span>),
+ (1000, <span class='pystring'>'M'</span>),
+ (31, <span class='pystring'>'XXXI'</span>),
+ (148, <span class='pystring'>'CXLVIII'</span>),
+ (294, <span class='pystring'>'CCXCIV'</span>),
+ (312, <span class='pystring'>'CCCXII'</span>),
+ (421, <span class='pystring'>'CDXXI'</span>),
+ (528, <span class='pystring'>'DXXVIII'</span>),
+ (621, <span class='pystring'>'DCXXI'</span>),
+ (782, <span class='pystring'>'DCCLXXXII'</span>),
+ (870, <span class='pystring'>'DCCCLXX'</span>),
+ (941, <span class='pystring'>'CMXLI'</span>),
+ (1043, <span class='pystring'>'MXLIII'</span>),
+ (1110, <span class='pystring'>'MCX'</span>),
+ (1226, <span class='pystring'>'MCCXXVI'</span>),
+ (1301, <span class='pystring'>'MCCCI'</span>),
+ (1485, <span class='pystring'>'MCDLXXXV'</span>),
+ (1509, <span class='pystring'>'MDIX'</span>),
+ (1607, <span class='pystring'>'MDCVII'</span>),
+ (1754, <span class='pystring'>'MDCCLIV'</span>),
+ (1832, <span class='pystring'>'MDCCCXXXII'</span>),
+ (1993, <span class='pystring'>'MCMXCIII'</span>),
+ (2074, <span class='pystring'>'MMLXXIV'</span>),
+ (2152, <span class='pystring'>'MMCLII'</span>),
+ (2212, <span class='pystring'>'MMCCXII'</span>),
+ (2343, <span class='pystring'>'MMCCCXLIII'</span>),
+ (2499, <span class='pystring'>'MMCDXCIX'</span>),
+ (2574, <span class='pystring'>'MMDLXXIV'</span>),
+ (2646, <span class='pystring'>'MMDCXLVI'</span>),
+ (2723, <span class='pystring'>'MMDCCXXIII'</span>),
+ (2892, <span class='pystring'>'MMDCCCXCII'</span>),
+ (2975, <span class='pystring'>'MMCMLXXV'</span>),
+ (3051, <span class='pystring'>'MMMLI'</span>),
+ (3185, <span class='pystring'>'MMMCLXXXV'</span>),
+ (3250, <span class='pystring'>'MMMCCL'</span>),
+ (3313, <span class='pystring'>'MMMCCCXIII'</span>),
+ (3408, <span class='pystring'>'MMMCDVIII'</span>),
+ (3501, <span class='pystring'>'MMMDI'</span>),
+ (3610, <span class='pystring'>'MMMDCX'</span>),
+ (3743, <span class='pystring'>'MMMDCCXLIII'</span>),
+ (3844, <span class='pystring'>'MMMDCCCXLIV'</span>),
+ (3888, <span class='pystring'>'MMMDCCCLXXXVIII'</span>),
+ (3940, <span class='pystring'>'MMMCMXL'</span>),
+ (3999, <span class='pystring'>'MMMCMXCIX'</span>)) <a name="roman.success.1.1"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+
+ <span class='pykeyword'>def</span><span class='pyclass'> testToRomanKnownValues</span>(self): <a name="roman.success.1.2"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+ <span class='pystring'>"""toRoman should give known result with known input"""</span>
+ <span class='pykeyword'>for</span> integer, numeral <span class='pykeyword'>in</span> self.knownValues:
+ result = roman.toRoman(integer) <a name="roman.success.1.3"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"> <a name="roman.success.1.4"></a><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12">
+ self.assertEqual(numeral, result) <a name="roman.success.1.5"></a><img src="../images/callouts/6.png" alt="6" border="0" width="12" height="12"></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.success.1.0"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">To write a test case, first subclass the <tt class="classname">TestCase</tt> class of the <tt class="filename">unittest</tt> module. This class provides many useful methods which you can use in your test case to test specific conditions.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.success.1.1"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This is a list of integer/numeral pairs that I verified manually. It includes the lowest ten numbers, the highest number,
+ every number that translates to a single-character Roman numeral, and a random sampling of other valid numbers. The point
+ of a unit test is not to test every possible input, but to test a representative sample.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.success.1.2"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Every individual test is its own method, which must take no parameters and return no value. If the method exits normally
+ without raising an exception, the test is considered passed; if the method raises an exception, the test is considered failed.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.success.1.3"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Here you call the actual <tt class="function">toRoman</tt> function. (Well, the function hasn't be written yet, but once it is, this is the line that will call it.) Notice that you
+ have now defined the <span class="acronym">API</span> for the <tt class="function">toRoman</tt> function: it must take an integer (the number to convert) and return a string (the Roman numeral representation). If the
+ <span class="acronym">API</span> is different than that, this test is considered failed.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.success.1.4"><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Also notice that you are not trapping any exceptions when you call <tt class="function">toRoman</tt>. This is intentional. <tt class="function">toRoman</tt> shouldn't raise an exception when you call it with valid input, and these input values are all valid. If <tt class="function">toRoman</tt> raises an exception, this test is considered failed.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#roman.success.1.5"><img src="../images/callouts/6.png" alt="6" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Assuming the <tt class="function">toRoman</tt> function was defined correctly, called correctly, completed successfully, and returned a value, the last step is to check
+ whether it returned the <span class="emphasis"><em>right</em></span> value. This is a common question, and the <tt class="classname">TestCase</tt> class provides a method, <tt class="function">assertEqual</tt>, to check whether two values are equal. If the result returned from <tt class="function">toRoman</tt> (<tt class="varname">result</tt>) does not match the known value you were expecting (<tt class="varname">numeral</tt>), <tt class="function">assertEqual</tt> will raise an exception and the test will fail. If the two values are equal, <tt class="function">assertEqual</tt> will do nothing. If every value returned from <tt class="function">toRoman</tt> matches the known value you expect, <tt class="function">assertEqual</tt> never raises an exception, so <tt class="function">testToRomanKnownValues</tt> eventually exits normally, which means <tt class="function">toRoman</tt> has passed this test.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="romantest.html">&lt;&lt;&nbsp;Introducing romantest.py</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#roman.intro" title="13.1.&nbsp;Introduction to Roman numerals">1</a> <span class="divider">|</span> <a href="diving_in.html" title="13.2.&nbsp;Diving in">2</a> <span class="divider">|</span> <a href="romantest.html" title="13.3.&nbsp;Introducing romantest.py">3</a> <span class="divider">|</span> <span class="thispage">4</span> <span class="divider">|</span> <a href="testing_for_failure.html" title="13.5.&nbsp;Testing for failure">5</a> <span class="divider">|</span> <a href="testing_for_sanity.html" title="13.6.&nbsp;Testing for sanity">6</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="testing_for_failure.html">Testing for failure&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/xml_processing/attributes.html b/help/diveintopython-5.4/html/xml_processing/attributes.html
new file mode 100644
index 0000000..4bd25c4
--- /dev/null
+++ b/help/diveintopython-5.4/html/xml_processing/attributes.html
@@ -0,0 +1,164 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>9.6.&nbsp;Accessing element attributes</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;9.&nbsp;XML Processing">
+ <link rel="previous" href="searching.html" title="9.5.&nbsp;Searching for elements">
+ <link rel="next" href="summary.html" title="9.7.&nbsp;Segue">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">XML Processing</a>&nbsp;&gt;&nbsp;<span class="thispage">Accessing element attributes</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="searching.html" title="Prev: &#8220;Searching for elements&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="summary.html" title="Next: &#8220;Segue&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="kgp.attributes"></a>9.6.&nbsp;Accessing element attributes
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p><span class="acronym">XML</span> elements can have one or more attributes, and it is incredibly simple to access them once you have parsed an <span class="acronym">XML</span> document.
+ </p>
+ </div>
+ <p>For this section, you'll be using the <tt class="filename">binary.xml</tt> grammar file that you saw in the <a href="searching.html" title="9.5.&nbsp;Searching for elements">previous section</a>.
+ </p><a name="d0e24744"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">This section may be a little confusing, because of some overlapping terminology. Elements in an <span class="acronym">XML</span> document have attributes, and <span class="application">Python</span> objects also have attributes. When you parse an <span class="acronym">XML</span> document, you get a bunch of <span class="application">Python</span> objects that represent all the pieces of the <span class="acronym">XML</span> document, and some of these <span class="application">Python</span> objects represent attributes of the <span class="acronym">XML</span> elements. But the (<span class="application">Python</span>) objects that represent the (<span class="acronym">XML</span>) attributes also have (<span class="application">Python</span>) attributes, which are used to access various parts of the (<span class="acronym">XML</span>) attribute that the object represents. I told you it was confusing. I am open to suggestions on how to distinguish these
+ more clearly.
+ </td>
+ </tr>
+ </table>
+ <div class="example"><a name="d0e24787"></a><h3 class="title">Example&nbsp;9.24.&nbsp;Accessing element attributes</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">xmldoc = minidom.parse(<span class='pystring'>'binary.xml'</span>)</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">reflist = xmldoc.getElementsByTagName(<span class='pystring'>'ref'</span>)</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">bitref = reflist[0]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> bitref.toxml()</span>
+<span class="computeroutput">&lt;ref id="bit"&gt;
+ &lt;p&gt;0&lt;/p&gt;
+ &lt;p&gt;1&lt;/p&gt;
+&lt;/ref&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">bitref.attributes</span> <a name="kgp.attributes.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">&lt;xml.dom.minidom.NamedNodeMap instance at 0x81e0c9c&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">bitref.attributes.keys()</span> <a name="kgp.attributes.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"> <a name="kgp.attributes.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">[u'id']</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">bitref.attributes.values()</span> <a name="kgp.attributes.1.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">[&lt;xml.dom.minidom.Attr instance at 0x81d5044&gt;]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">bitref.attributes[<span class='pystring'>"id"</span>]</span> <a name="kgp.attributes.1.5"></a><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12">
+<span class="computeroutput">&lt;xml.dom.minidom.Attr instance at 0x81d5044&gt;</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.attributes.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Each <tt class="classname">Element</tt> object has an attribute called <tt class="literal">attributes</tt>, which is a <tt class="classname">NamedNodeMap</tt> object. This sounds scary, but it's not, because a <tt class="classname">NamedNodeMap</tt> is an object that <a href="../object_oriented_framework/userdict.html" title="5.5.&nbsp;Exploring UserDict: A Wrapper Class">acts like a dictionary</a>, so you already know how to use it.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.attributes.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Treating the <tt class="classname">NamedNodeMap</tt> as a dictionary, you can get a list of the names of the attributes of this element by using <tt class="function">attributes.keys()</tt>. This element has only one attribute, <tt class="literal">'id'</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.attributes.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Attribute names, like all other text in an <span class="acronym">XML</span> document, are stored in <a href="unicode.html" title="9.4.&nbsp;Unicode">unicode</a>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.attributes.1.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Again treating the <tt class="classname">NamedNodeMap</tt> as a dictionary, you can get a list of the values of the attributes by using <tt class="function">attributes.values()</tt>. The values are themselves objects, of type <tt class="classname">Attr</tt>. You'll see how to get useful information out of this object in the next example.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.attributes.1.5"><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Still treating the <tt class="classname">NamedNodeMap</tt> as a dictionary, you can access an individual attribute by name, using normal dictionary syntax. (Readers who have been
+ paying extra-close attention will already know how the <tt class="classname">NamedNodeMap</tt> class accomplishes this neat trick: by defining a <a href="../object_oriented_framework/special_class_methods.html" title="5.6.&nbsp;Special Class Methods"><tt class="function">__getitem__</tt> special method</a>. Other readers can take comfort in the fact that they don't need to understand how it works in order to use it effectively.)
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="d0e24922"></a><h3 class="title">Example&nbsp;9.25.&nbsp;Accessing individual attributes</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">a = bitref.attributes[<span class='pystring'>"id"</span>]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">a</span>
+<span class="computeroutput">&lt;xml.dom.minidom.Attr instance at 0x81d5044&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">a.name</span> <a name="kgp.attributes.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">u'id'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">a.value</span> <a name="kgp.attributes.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">u'bit'</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.attributes.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="classname">Attr</tt> object completely represents a single <span class="acronym">XML</span> attribute of a single <span class="acronym">XML</span> element. The name of the attribute (the same name as you used to find this object in the <tt class="literal">bitref.attributes</tt> <tt class="classname">NamedNodeMap</tt> pseudo-dictionary) is stored in <tt class="literal">a.name</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.attributes.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The actual text value of this <span class="acronym">XML</span> attribute is stored in <tt class="literal">a.value</tt>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div><a name="d0e24990"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">Like a dictionary, attributes of an <span class="acronym">XML</span> element have no ordering. Attributes may <span class="emphasis"><em>happen to be</em></span> listed in a certain order in the original <span class="acronym">XML</span> document, and the <tt class="classname">Attr</tt> objects may <span class="emphasis"><em>happen to be</em></span> listed in a certain order when the <span class="acronym">XML</span> document is parsed into <span class="application">Python</span> objects, but these orders are arbitrary and should carry no special meaning. You should always access individual attributes
+ by name, like the keys of a dictionary.
+ </td>
+ </tr>
+ </table>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="searching.html">&lt;&lt;&nbsp;Searching for elements</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#kgp.divein" title="9.1.&nbsp;Diving in">1</a> <span class="divider">|</span> <a href="packages.html" title="9.2.&nbsp;Packages">2</a> <span class="divider">|</span> <a href="parsing_xml.html" title="9.3.&nbsp;Parsing XML">3</a> <span class="divider">|</span> <a href="unicode.html" title="9.4.&nbsp;Unicode">4</a> <span class="divider">|</span> <a href="searching.html" title="9.5.&nbsp;Searching for elements">5</a> <span class="divider">|</span> <span class="thispage">6</span> <span class="divider">|</span> <a href="summary.html" title="9.7.&nbsp;Segue">7</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="summary.html">Segue&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/xml_processing/index.html b/help/diveintopython-5.4/html/xml_processing/index.html
new file mode 100644
index 0000000..d39f01c
--- /dev/null
+++ b/help/diveintopython-5.4/html/xml_processing/index.html
@@ -0,0 +1,447 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>Chapter&nbsp;9.&nbsp;XML Processing</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="../toc/index.html" title="Dive Into Python">
+ <link rel="previous" href="../html_processing/summary.html" title="8.10.&nbsp;Summary">
+ <link rel="next" href="packages.html" title="9.2.&nbsp;Packages">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<span class="thispage">XML Processing</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="../html_processing/summary.html" title="Prev: &#8220;Summary&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="packages.html" title="Next: &#8220;Packages&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="chapter" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="kgp"></a>Chapter&nbsp;9.&nbsp;<span class="acronym">XML</span> Processing
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="toc">
+ <ul>
+ <li><span class="section"><a href="index.html#kgp.divein">9.1. Diving in</a></span></li>
+ <li><span class="section"><a href="packages.html">9.2. Packages</a></span></li>
+ <li><span class="section"><a href="parsing_xml.html">9.3. Parsing XML</a></span></li>
+ <li><span class="section"><a href="unicode.html">9.4. Unicode</a></span></li>
+ <li><span class="section"><a href="searching.html">9.5. Searching for elements</a></span></li>
+ <li><span class="section"><a href="attributes.html">9.6. Accessing element attributes</a></span></li>
+ <li><span class="section"><a href="summary.html">9.7. Segue</a></span></li>
+ </ul>
+ </div>
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="kgp.divein"></a>9.1.&nbsp;Diving in
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <p>These next two chapters are about <span class="acronym">XML</span> processing in <span class="application">Python</span>. It would be helpful if you already knew what an <span class="acronym">XML</span> document looks like, that it's made up of structured tags to form a hierarchy of elements, and so on. If this doesn't make
+ sense to you, there are <a href="http://directory.google.com/Top/Computers/Data_Formats/Markup_Languages/XML/Resources/FAQs,_Help,_and_Tutorials/">many <span class="acronym">XML</span> tutorials</a> that can explain the basics.
+ </p>
+ <p>If you're not particularly interested in XML, you should still read these chapters, which cover important topics like <span class="application">Python</span> packages, Unicode, command line arguments, and how to use <tt class="function">getattr</tt> for method dispatching.
+ </p>
+ <p>Being a philosophy major is not required, although if you have ever had the misfortune of being subjected to the writings
+ of Immanuel Kant, you will appreciate the example program a lot more than if you majored in something useful, like computer
+ science.
+ </p>
+ <div class="abstract">
+ <p>There are two basic ways to work with <span class="acronym">XML</span>. One is called <span class="acronym">SAX</span> (&#8220;<span class="quote">Simple <span class="acronym">API</span> for <span class="acronym">XML</span></span>&#8221;), and it works by reading the <span class="acronym">XML</span> a little bit at a time and calling a method for each element it finds. (If you read <a href="../html_processing/index.html" title="Chapter&nbsp;8.&nbsp;HTML Processing">Chapter&nbsp;8, <i>HTML Processing</i></a>, this should sound familiar, because that's how the <tt class="filename">sgmllib</tt> module works.) The other is called <span class="acronym">DOM</span> (&#8220;<span class="quote">Document Object Model</span>&#8221;), and it works by reading in the entire <span class="acronym">XML</span> document at once and creating an internal representation of it using native <span class="application">Python</span> classes linked in a tree structure. <span class="application">Python</span> has standard modules for both kinds of parsing, but this chapter will only deal with using the <span class="acronym">DOM</span>.
+ </p>
+ </div>
+ <p>The following is a complete <span class="application">Python</span> program which generates pseudo-random output based on a context-free grammar defined in an <span class="acronym">XML</span> format. Don't worry yet if you don't understand what that means; you'll examine both the program's input and its output
+ in more depth throughout these next two chapters.
+ </p>
+ <div class="example"><a name="d0e22845"></a><h3 class="title">Example&nbsp;9.1.&nbsp;<tt class="filename">kgp.py</tt></h3>
+ <p>If you have not already done so, you can <a href="http://diveintopython.org/download/diveintopython-examples-5.4.zip" title="Download example scripts">download this and other examples</a> used in this book.
+ </p><pre class="programlisting">
+<span class='pystring'>"""Kant Generator for Python
+
+Generates mock philosophy based on a context-free grammar
+
+Usage: python kgp.py [options] [source]
+
+Options:
+ -g ..., --grammar=... use specified grammar file or URL
+ -h, --help show this help
+ -d show debugging information while parsing
+
+Examples:
+ kgp.py generates several paragraphs of Kantian philosophy
+ kgp.py -g husserl.xml generates several paragraphs of Husserl
+ kpg.py "&lt;xref id='paragraph'/&gt;" generates a paragraph of Kant
+ kgp.py template.xml reads from template.xml to decide what to generate
+"""</span>
+<span class='pykeyword'>from</span> xml.dom <span class='pykeyword'>import</span> minidom
+<span class='pykeyword'>import</span> random
+<span class='pykeyword'>import</span> toolbox
+<span class='pykeyword'>import</span> sys
+<span class='pykeyword'>import</span> getopt
+
+_debug = 0
+
+<span class='pykeyword'>class</span><span class='pyclass'> NoSourceError</span>(Exception): <span class='pykeyword'>pass</span>
+
+<span class='pykeyword'>class</span><span class='pyclass'> KantGenerator</span>:
+ <span class='pystring'>"""generates mock philosophy based on a context-free grammar"""</span>
+
+ <span class='pykeyword'>def</span><span class='pyclass'> __init__</span>(self, grammar, source=None):
+ self.loadGrammar(grammar)
+ self.loadSource(source <span class='pykeyword'>and</span> source <span class='pykeyword'>or</span> self.getDefaultSource())
+ self.refresh()
+
+ <span class='pykeyword'>def</span><span class='pyclass'> _load</span>(self, source):
+ <span class='pystring'>"""load XML input source, return parsed XML document
+
+ - a URL of a remote XML file ("http://diveintopython.org/kant.xml")
+ - a filename of a local XML file ("~/diveintopython/common/py/kant.xml")
+ - standard input ("-")
+ - the actual XML document, as a string
+ """</span>
+ sock = toolbox.openAnything(source)
+ xmldoc = minidom.parse(sock).documentElement
+ sock.close()
+ <span class='pykeyword'>return</span> xmldoc
+
+ <span class='pykeyword'>def</span><span class='pyclass'> loadGrammar</span>(self, grammar):
+ <span class='pystring'>"""load context-free grammar"""</span>
+ self.grammar = self._load(grammar)
+ self.refs = {}
+ <span class='pykeyword'>for</span> ref <span class='pykeyword'>in</span> self.grammar.getElementsByTagName(<span class='pystring'>"ref"</span>):
+ self.refs[ref.attributes[<span class='pystring'>"id"</span>].value] = ref
+
+ <span class='pykeyword'>def</span><span class='pyclass'> loadSource</span>(self, source):
+ <span class='pystring'>"""load source"""</span>
+ self.source = self._load(source)
+
+ <span class='pykeyword'>def</span><span class='pyclass'> getDefaultSource</span>(self):
+ <span class='pystring'>"""guess default source of the current grammar
+
+ The default source will be one of the &lt;ref&gt;s that is not
+ cross-referenced. This sounds complicated but it's not.
+ Example: The default source for kant.xml is
+ "&lt;xref id='section'/&gt;", because 'section' is the one &lt;ref&gt;
+ that is not &lt;xref&gt;'d anywhere in the grammar.
+ In most grammars, the default source will produce the
+ longest (and most interesting) output.
+ """</span>
+ xrefs = {}
+ <span class='pykeyword'>for</span> xref <span class='pykeyword'>in</span> self.grammar.getElementsByTagName(<span class='pystring'>"xref"</span>):
+ xrefs[xref.attributes[<span class='pystring'>"id"</span>].value] = 1
+ xrefs = xrefs.keys()
+ standaloneXrefs = [e <span class='pykeyword'>for</span> e <span class='pykeyword'>in</span> self.refs.keys() <span class='pykeyword'>if</span> e <span class='pykeyword'>not</span> <span class='pykeyword'>in</span> xrefs]
+ <span class='pykeyword'>if</span> <span class='pykeyword'>not</span> standaloneXrefs:
+ <span class='pykeyword'>raise</span> NoSourceError, <span class='pystring'>"can't guess source, and no source specified"</span>
+ <span class='pykeyword'>return</span> <span class='pystring'>'&lt;xref id="%s"/&gt;'</span> % random.choice(standaloneXrefs)
+
+ <span class='pykeyword'>def</span><span class='pyclass'> reset</span>(self):
+ <span class='pystring'>"""reset parser"""</span>
+ self.pieces = []
+ self.capitalizeNextWord = 0
+
+ <span class='pykeyword'>def</span><span class='pyclass'> refresh</span>(self):
+ <span class='pystring'>"""reset output buffer, re-parse entire source file, and return output
+
+ Since parsing involves a good deal of randomness, this is an
+ easy way to get new output without having to reload a grammar file
+ each time.
+ """</span>
+ self.reset()
+ self.parse(self.source)
+ <span class='pykeyword'>return</span> self.output()
+
+ <span class='pykeyword'>def</span><span class='pyclass'> output</span>(self):
+ <span class='pystring'>"""output generated text"""</span>
+ <span class='pykeyword'>return</span> <span class='pystring'>""</span>.join(self.pieces)
+
+ <span class='pykeyword'>def</span><span class='pyclass'> randomChildElement</span>(self, node):
+ <span class='pystring'>"""choose a random child element of a node
+
+ This is a utility method used by do_xref and do_choice.
+ """</span>
+ choices = [e <span class='pykeyword'>for</span> e <span class='pykeyword'>in</span> node.childNodes
+ <span class='pykeyword'>if</span> e.nodeType == e.ELEMENT_NODE]
+ chosen = random.choice(choices)
+ <span class='pykeyword'>if</span> _debug:
+ sys.stderr.write(<span class='pystring'>'%s available choices: %s\n'</span> % \
+ (len(choices), [e.toxml() <span class='pykeyword'>for</span> e <span class='pykeyword'>in</span> choices]))
+ sys.stderr.write(<span class='pystring'>'Chosen: %s\n'</span> % chosen.toxml())
+ <span class='pykeyword'>return</span> chosen
+
+ <span class='pykeyword'>def</span><span class='pyclass'> parse</span>(self, node):
+ <span class='pystring'>"""parse a single XML node
+
+ A parsed XML document (from minidom.parse) is a tree of nodes
+ of various types. Each node is represented by an instance of the
+ corresponding Python class (Element for a tag, Text for
+ text data, Document for the top-level document). The following
+ statement constructs the name of a class method based on the type
+ of node we're parsing ("parse_Element" for an Element node,
+ "parse_Text" for a Text node, etc.) and then calls the method.
+ """</span>
+ parseMethod = getattr(self, <span class='pystring'>"parse_%s"</span> % node.__class__.__name__)
+ parseMethod(node)
+
+ <span class='pykeyword'>def</span><span class='pyclass'> parse_Document</span>(self, node):
+ <span class='pystring'>"""parse the document node
+
+ The document node by itself isn't interesting (to us), but
+ its only child, node.documentElement, is: it's the root node
+ of the grammar.
+ """</span>
+ self.parse(node.documentElement)
+
+ <span class='pykeyword'>def</span><span class='pyclass'> parse_Text</span>(self, node):
+ <span class='pystring'>"""parse a text node
+
+ The text of a text node is usually added to the output buffer
+ verbatim. The one exception is that &lt;p class='sentence'&gt; sets
+ a flag to capitalize the first letter of the next word. If
+ that flag is set, we capitalize the text and reset the flag.
+ """</span>
+ text = node.data
+ <span class='pykeyword'>if</span> self.capitalizeNextWord:
+ self.pieces.append(text[0].upper())
+ self.pieces.append(text[1:])
+ self.capitalizeNextWord = 0
+ <span class='pykeyword'>else</span>:
+ self.pieces.append(text)
+
+ <span class='pykeyword'>def</span><span class='pyclass'> parse_Element</span>(self, node):
+ <span class='pystring'>"""parse an element
+
+ An XML element corresponds to an actual tag in the source:
+ &lt;xref id='...'&gt;, &lt;p chance='...'&gt;, &lt;choice&gt;, etc.
+ Each element type is handled in its own method. Like we did in
+ parse(), we construct a method name based on the name of the
+ element ("do_xref" for an &lt;xref&gt; tag, etc.) and
+ call the method.
+ """</span>
+ handlerMethod = getattr(self, <span class='pystring'>"do_%s"</span> % node.tagName)
+ handlerMethod(node)
+
+ <span class='pykeyword'>def</span><span class='pyclass'> parse_Comment</span>(self, node):
+ <span class='pystring'>"""parse a comment
+
+ The grammar can contain XML comments, but we ignore them
+ """</span>
+ <span class='pykeyword'>pass</span>
+
+ <span class='pykeyword'>def</span><span class='pyclass'> do_xref</span>(self, node):
+ <span class='pystring'>"""handle &lt;xref id='...'&gt; tag
+
+ An &lt;xref id='...'&gt; tag is a cross-reference to a &lt;ref id='...'&gt;
+ tag. &lt;xref id='sentence'/&gt; evaluates to a randomly chosen child of
+ &lt;ref id='sentence'&gt;.
+ """</span>
+ id = node.attributes[<span class='pystring'>"id"</span>].value
+ self.parse(self.randomChildElement(self.refs[id]))
+
+ <span class='pykeyword'>def</span><span class='pyclass'> do_p</span>(self, node):
+ <span class='pystring'>"""handle &lt;p&gt; tag
+
+ The &lt;p&gt; tag is the core of the grammar. It can contain almost
+ anything: freeform text, &lt;choice&gt; tags, &lt;xref&gt; tags, even other
+ &lt;p&gt; tags. If a "class='sentence'" attribute is found, a flag
+ is set and the next word will be capitalized. If a "chance='X'"
+ attribute is found, there is an X% chance that the tag will be
+ evaluated (and therefore a (100-X)% chance that it will be
+ completely ignored)
+ """</span>
+ keys = node.attributes.keys()
+ <span class='pykeyword'>if</span> <span class='pystring'>"class"</span> <span class='pykeyword'>in</span> keys:
+ <span class='pykeyword'>if</span> node.attributes[<span class='pystring'>"class"</span>].value == <span class='pystring'>"sentence"</span>:
+ self.capitalizeNextWord = 1
+ <span class='pykeyword'>if</span> <span class='pystring'>"chance"</span> <span class='pykeyword'>in</span> keys:
+ chance = int(node.attributes[<span class='pystring'>"chance"</span>].value)
+ doit = (chance &gt; random.randrange(100))
+ <span class='pykeyword'>else</span>:
+ doit = 1
+ <span class='pykeyword'>if</span> doit:
+ <span class='pykeyword'>for</span> child <span class='pykeyword'>in</span> node.childNodes: self.parse(child)
+
+ <span class='pykeyword'>def</span><span class='pyclass'> do_choice</span>(self, node):
+ <span class='pystring'>"""handle &lt;choice&gt; tag
+
+ A &lt;choice&gt; tag contains one or more &lt;p&gt; tags. One &lt;p&gt; tag
+ is chosen at random and evaluated; the rest are ignored.
+ """</span>
+ self.parse(self.randomChildElement(node))
+
+<span class='pykeyword'>def</span><span class='pyclass'> usage</span>():
+ <span class='pykeyword'>print</span> __doc__
+
+<span class='pykeyword'>def</span><span class='pyclass'> main</span>(argv):
+ grammar = <span class='pystring'>"kant.xml"</span>
+ <span class='pykeyword'>try</span>:
+ opts, args = getopt.getopt(argv, <span class='pystring'>"hg:d"</span>, [<span class='pystring'>"help"</span>, <span class='pystring'>"grammar="</span>])
+ <span class='pykeyword'>except</span> getopt.GetoptError:
+ usage()
+ sys.exit(2)
+ <span class='pykeyword'>for</span> opt, arg <span class='pykeyword'>in</span> opts:
+ <span class='pykeyword'>if</span> opt <span class='pykeyword'>in</span> (<span class='pystring'>"-h"</span>, <span class='pystring'>"--help"</span>):
+ usage()
+ sys.exit()
+ <span class='pykeyword'>elif</span> opt == <span class='pystring'>'-d'</span>:
+ <span class='pykeyword'>global</span> _debug
+ _debug = 1
+ <span class='pykeyword'>elif</span> opt <span class='pykeyword'>in</span> (<span class='pystring'>"-g"</span>, <span class='pystring'>"--grammar"</span>):
+ grammar = arg
+
+ source = <span class='pystring'>""</span>.join(args)
+
+ k = KantGenerator(grammar, source)
+ <span class='pykeyword'>print</span> k.output()
+
+<span class='pykeyword'>if</span> __name__ == <span class='pystring'>"__main__"</span>:
+ main(sys.argv[1:])
+</pre></div>
+ <div class="example"><a name="d0e22856"></a><h3 class="title">Example&nbsp;9.2.&nbsp;<tt class="filename">toolbox.py</tt></h3><pre class="programlisting">
+<span class='pystring'>"""Miscellaneous utility functions"""</span>
+
+<span class='pykeyword'>def</span><span class='pyclass'> openAnything</span>(source):
+ <span class='pystring'>"""URI, filename, or string --&gt; stream
+
+ This function lets you define parsers that take any input source
+ (URL, pathname to local or network file, or actual data as a string)
+ and deal with it in a uniform manner. Returned object is guaranteed
+ to have all the basic stdio read methods (read, readline, readlines).
+ Just .close() the object when you're done with it.
+
+ Examples:
+ &gt;&gt;&gt; from xml.dom import minidom
+ &gt;&gt;&gt; sock = openAnything("http://localhost/kant.xml")
+ &gt;&gt;&gt; doc = minidom.parse(sock)
+ &gt;&gt;&gt; sock.close()
+ &gt;&gt;&gt; sock = openAnything("c:\\inetpub\\wwwroot\\kant.xml")
+ &gt;&gt;&gt; doc = minidom.parse(sock)
+ &gt;&gt;&gt; sock.close()
+ &gt;&gt;&gt; sock = openAnything("&lt;ref id='conjunction'&gt;&lt;text&gt;and&lt;/text&gt;&lt;text&gt;or&lt;/text&gt;&lt;/ref&gt;")
+ &gt;&gt;&gt; doc = minidom.parse(sock)
+ &gt;&gt;&gt; sock.close()
+ """</span>
+ <span class='pykeyword'>if</span> hasattr(source, <span class='pystring'>"read"</span>):
+ <span class='pykeyword'>return</span> source
+
+ <span class='pykeyword'>if</span> source == <span class='pystring'>'-'</span>:
+ <span class='pykeyword'>import</span> sys
+ <span class='pykeyword'>return</span> sys.stdin
+
+ <span class='pycomment'># try to open with urllib (if source is http, ftp, or file URL)</span>
+ <span class='pykeyword'>import</span> urllib
+ <span class='pykeyword'>try</span>:
+ <span class='pykeyword'>return</span> urllib.urlopen(source)
+ <span class='pykeyword'>except</span> (IOError, OSError):
+ <span class='pykeyword'>pass</span>
+
+ <span class='pycomment'># try to open with native open function (if source is pathname)</span>
+ <span class='pykeyword'>try</span>:
+ <span class='pykeyword'>return</span> open(source)
+ <span class='pykeyword'>except</span> (IOError, OSError):
+ <span class='pykeyword'>pass</span>
+
+ <span class='pycomment'># treat source as string</span>
+ <span class='pykeyword'>import</span> StringIO
+ <span class='pykeyword'>return</span> StringIO.StringIO(str(source))
+</pre></div>
+ <p>Run the program <tt class="filename">kgp.py</tt> by itself, and it will parse the default <span class="acronym">XML</span>-based grammar, in <tt class="filename">kant.xml</tt>, and print several paragraphs worth of philosophy in the style of Immanuel Kant.
+ </p>
+ <div class="example"><a name="d0e22873"></a><h3 class="title">Example&nbsp;9.3.&nbsp;Sample output of <tt class="filename">kgp.py</tt></h3><pre class="screen"><tt class="prompt">[you@localhost kgp]$ python kgp.py</tt>
+<span class="computeroutput"> As is shown in the writings of Hume, our a priori concepts, in
+reference to ends, abstract from all content of knowledge; in the study
+of space, the discipline of human reason, in accordance with the
+principles of philosophy, is the clue to the discovery of the
+Transcendental Deduction. The transcendental aesthetic, in all
+theoretical sciences, occupies part of the sphere of human reason
+concerning the existence of our ideas in general; still, the
+never-ending regress in the series of empirical conditions constitutes
+the whole content for the transcendental unity of apperception. What
+we have alone been able to show is that, even as this relates to the
+architectonic of human reason, the Ideal may not contradict itself, but
+it is still possible that it may be in contradictions with the
+employment of the pure employment of our hypothetical judgements, but
+natural causes (and I assert that this is the case) prove the validity
+of the discipline of pure reason. As we have already seen, time (and
+it is obvious that this is true) proves the validity of time, and the
+architectonic of human reason, in the full sense of these terms,
+abstracts from all content of knowledge. I assert, in the case of the
+discipline of practical reason, that the Antinomies are just as
+necessary as natural causes, since knowledge of the phenomena is a
+posteriori.
+ The discipline of human reason, as I have elsewhere shown, is by
+its very nature contradictory, but our ideas exclude the possibility of
+the Antinomies. We can deduce that, on the contrary, the pure
+employment of philosophy, on the contrary, is by its very nature
+contradictory, but our sense perceptions are a representation of, in
+the case of space, metaphysics. The thing in itself is a
+representation of philosophy. Applied logic is the clue to the
+discovery of natural causes. However, what we have alone been able to
+show is that our ideas, in other words, should only be used as a canon
+for the Ideal, because of our necessary ignorance of the conditions.
+
+[...snip...]</span></pre></div>
+ <p>This is, of course, complete gibberish. Well, not complete gibberish. It is syntactically and grammatically correct (although
+ very verbose -- Kant wasn't what you would call a get-to-the-point kind of guy). Some of it may actually be true (or at least
+ the sort of thing that Kant would have agreed with), some of it is blatantly false, and most of it is simply incoherent.
+ But all of it is in the style of Immanuel Kant.
+ </p>
+ <p>Let me repeat that this is much, much funnier if you are now or have ever been a philosophy major.</p>
+ <p>The interesting thing about this program is that there is nothing Kant-specific about it. All the content in the previous
+ example was derived from the grammar file, <tt class="filename">kant.xml</tt>. If you tell the program to use a different grammar file (which you can specify on the command line), the output will be
+ completely different.
+ </p>
+ <div class="example"><a name="d0e22893"></a><h3 class="title">Example&nbsp;9.4.&nbsp;Simpler output from <tt class="filename">kgp.py</tt></h3><pre class="screen"><tt class="prompt">[you@localhost kgp]$ python kgp.py -g binary.xml</tt>
+<span class="computeroutput">00101001</span>
+<tt class="prompt">[you@localhost kgp]$ python kgp.py -g binary.xml</tt>
+<span class="computeroutput">10110100</span></pre></div>
+ <p>You will take a closer look at the structure of the grammar file later in this chapter. For now, all you need to know is
+ that the grammar file defines the structure of the output, and the <tt class="filename">kgp.py</tt> program reads through the grammar and makes random decisions about which words to plug in where.
+ </p>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="../html_processing/summary.html">&lt;&lt;&nbsp;Summary</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<span class="thispage">1</span> <span class="divider">|</span> <a href="packages.html" title="9.2.&nbsp;Packages">2</a> <span class="divider">|</span> <a href="parsing_xml.html" title="9.3.&nbsp;Parsing XML">3</a> <span class="divider">|</span> <a href="unicode.html" title="9.4.&nbsp;Unicode">4</a> <span class="divider">|</span> <a href="searching.html" title="9.5.&nbsp;Searching for elements">5</a> <span class="divider">|</span> <a href="attributes.html" title="9.6.&nbsp;Accessing element attributes">6</a> <span class="divider">|</span> <a href="summary.html" title="9.7.&nbsp;Segue">7</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="packages.html">Packages&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/xml_processing/packages.html b/help/diveintopython-5.4/html/xml_processing/packages.html
new file mode 100644
index 0000000..71ec6c4
--- /dev/null
+++ b/help/diveintopython-5.4/html/xml_processing/packages.html
@@ -0,0 +1,165 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>9.2.&nbsp;Packages</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;9.&nbsp;XML Processing">
+ <link rel="previous" href="index.html" title="Chapter&nbsp;9.&nbsp;XML Processing">
+ <link rel="next" href="parsing_xml.html" title="9.3.&nbsp;Parsing XML">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">XML Processing</a>&nbsp;&gt;&nbsp;<span class="thispage">Packages</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="index.html" title="Prev: &#8220;XML Processing&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="parsing_xml.html" title="Next: &#8220;Parsing XML&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="kgp.packages"></a>9.2.&nbsp;Packages
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>Actually parsing an <span class="acronym">XML</span> document is very simple: one line of code. However, before you get to that line of code, you need to take a short detour
+ to talk about packages.
+ </p>
+ </div>
+ <div class="example"><a name="d0e22925"></a><h3 class="title">Example&nbsp;9.5.&nbsp;Loading an <span class="acronym">XML</span> document (a sneak peek)
+ </h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>from</span> xml.dom <span class='pykeyword'>import</span> minidom</span> <a name="kgp.packages.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">xmldoc = minidom.parse(<span class='pystring'>'~/diveintopython/common/py/kgp/binary.xml'</span>)</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.packages.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This is a syntax you haven't seen before. It looks almost like the <tt class="literal">from <i class="replaceable">module</i> import</tt> you know and love, but the <tt class="literal">"."</tt> gives it away as something above and beyond a simple import. In fact, <tt class="filename">xml</tt> is what is known as a package, <tt class="filename">dom</tt> is a nested package within <tt class="filename">xml</tt>, and <tt class="filename">minidom</tt> is a module within <tt class="filename">xml.dom</tt>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>That sounds complicated, but it's really not. Looking at the actual implementation may help. Packages are little more than
+ directories of modules; nested packages are subdirectories. The modules within a package (or a nested package) are still
+ just <tt class="filename">.py</tt> files, like always, except that they're in a subdirectory instead of the main <tt class="filename">lib/</tt> directory of your <span class="application">Python</span> installation.
+ </p>
+ <div class="example"><a name="d0e22983"></a><h3 class="title">Example&nbsp;9.6.&nbsp;File layout of a package</h3><pre class="screen"><span class="computeroutput"><span class="application">Python</span>21/ root <span class="application">Python</span> installation (home of the executable)
+|
++--lib/ library directory (home of the standard library modules)
+ |
+ +-- xml/ xml package (really just a directory with other stuff in it)
+ |
+ +--sax/ xml.sax package (again, just a directory)
+ |
+ +--dom/ xml.dom package (contains minidom.py)
+ |
+ +--parsers/ xml.parsers package (used internally)</span></pre></div>
+ <p>So when you say <tt class="literal">from xml.dom import minidom</tt>, <span class="application">Python</span> figures out that that means &#8220;<span class="quote">look in the <tt class="filename">xml</tt> directory for a <tt class="filename">dom</tt> directory, and look in <span class="emphasis"><em>that</em></span> for the <tt class="filename">minidom</tt> module, and import it as <tt class="filename">minidom</tt></span>&#8221;. But <span class="application">Python</span> is even smarter than that; not only can you import entire modules contained within a package, you can selectively import
+ specific classes or functions from a module contained within a package. You can also import the package itself as a module.
+ The syntax is all the same; <span class="application">Python</span> figures out what you mean based on the file layout of the package, and automatically does the right thing.
+ </p>
+ <div class="example"><a name="d0e23025"></a><h3 class="title">Example&nbsp;9.7.&nbsp;Packages are modules, too</h3><pre class="screen"><tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>from</span> xml.dom <span class='pykeyword'>import</span> minidom</span> <a name="kgp.packages.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">minidom</span>
+<span class="computeroutput">&lt;module 'xml.dom.minidom' from 'C:\Python21\lib\xml\dom\minidom.pyc'&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">minidom.Element</span>
+<span class="computeroutput">&lt;class xml.dom.minidom.Element at 01095744&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>from</span> xml.dom.minidom <span class='pykeyword'>import</span> Element</span> <a name="kgp.packages.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">Element</span>
+<span class="computeroutput">&lt;class xml.dom.minidom.Element at 01095744&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">minidom.Element</span>
+<span class="computeroutput">&lt;class xml.dom.minidom.Element at 01095744&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>from</span> xml <span class='pykeyword'>import</span> dom</span> <a name="kgp.packages.2.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">dom</span>
+<span class="computeroutput">&lt;module 'xml.dom' from 'C:\Python21\lib\xml\dom\__init__.pyc'&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> xml</span> <a name="kgp.packages.2.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">xml</span>
+<span class="computeroutput">&lt;module 'xml' from 'C:\Python21\lib\xml\__init__.pyc'&gt;</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.packages.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Here you're importing a module (<tt class="filename">minidom</tt>) from a nested package (<tt class="filename">xml.dom</tt>). The result is that <tt class="filename">minidom</tt> is imported into your <a href="../html_processing/locals_and_globals.html" title="8.5.&nbsp;locals and globals">namespace</a>, and in order to reference classes within the <tt class="filename">minidom</tt> module (like <tt class="classname">Element</tt>), you need to preface them with the module name.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.packages.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Here you are importing a class (<tt class="classname">Element</tt>) from a module (<tt class="filename">minidom</tt>) from a nested package (<tt class="filename">xml.dom</tt>). The result is that <tt class="classname">Element</tt> is imported directly into your namespace. Note that this does not interfere with the previous import; the <tt class="classname">Element</tt> class can now be referenced in two ways (but it's all still the same class).
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.packages.2.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Here you are importing the <tt class="filename">dom</tt> package (a nested package of <tt class="filename">xml</tt>) as a module in and of itself. Any level of a package can be treated as a module, as you'll see in a moment. It can even
+ have its own attributes and methods, just the modules you've seen before.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.packages.2.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Here you are importing the root level <tt class="filename">xml</tt> package as a module.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>So how can a package (which is just a directory on disk) be imported and treated as a module (which is always a file on disk)?
+ The answer is the magical <tt class="filename">__init__.py</tt> file. You see, packages are not simply directories; they are directories with a specific file, <tt class="filename">__init__.py</tt>, inside. This file defines the attributes and methods of the package. For instance, <tt class="filename">xml.dom</tt> contains a <tt class="classname">Node</tt> class, which is defined in <tt class="filename">xml/dom/__init__.py</tt>. When you import a package as a module (like <tt class="filename">dom</tt> from <tt class="filename">xml</tt>), you're really importing its <tt class="filename">__init__.py</tt> file.
+ </p><a name="d0e23185"></a><table class="note" border="0" summary="">
+ <tr>
+ <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="Note" title="" width="24" height="24"></td>
+ </tr>
+ <tr>
+ <td colspan="2" align="left" valign="top" width="99%">A package is a directory with the special <tt class="filename">__init__.py</tt> file in it. The <tt class="filename">__init__.py</tt> file defines the attributes and methods of the package. It doesn't need to define anything; it can just be an empty file,
+ but it has to exist. But if <tt class="filename">__init__.py</tt> doesn't exist, the directory is just a directory, not a package, and it can't be imported or contain modules or nested packages.
+ </td>
+ </tr>
+ </table>
+ <p>So why bother with packages? Well, they provide a way to logically group related modules. Instead of having an <tt class="filename">xml</tt> package with <tt class="filename">sax</tt> and <tt class="filename">dom</tt> packages inside, the authors could have chosen to put all the <tt class="filename">sax</tt> functionality in <tt class="filename">xmlsax.py</tt> and all the <tt class="filename">dom</tt> functionality in <tt class="filename">xmldom.py</tt>, or even put all of it in a single module. But that would have been unwieldy (as of this writing, the <span class="acronym">XML</span> package has over 3000 lines of code) and difficult to manage (separate source files mean multiple people can work on different
+ areas simultaneously).
+ </p>
+ <p>If you ever find yourself writing a large subsystem in <span class="application">Python</span> (or, more likely, when you realize that your small subsystem has grown into a large one), invest some time designing a good
+ package architecture. It's one of the many things <span class="application">Python</span> is good at, so take advantage of it.
+ </p>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="index.html">&lt;&lt;&nbsp;XML Processing</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#kgp.divein" title="9.1.&nbsp;Diving in">1</a> <span class="divider">|</span> <span class="thispage">2</span> <span class="divider">|</span> <a href="parsing_xml.html" title="9.3.&nbsp;Parsing XML">3</a> <span class="divider">|</span> <a href="unicode.html" title="9.4.&nbsp;Unicode">4</a> <span class="divider">|</span> <a href="searching.html" title="9.5.&nbsp;Searching for elements">5</a> <span class="divider">|</span> <a href="attributes.html" title="9.6.&nbsp;Accessing element attributes">6</a> <span class="divider">|</span> <a href="summary.html" title="9.7.&nbsp;Segue">7</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="parsing_xml.html">Parsing XML&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/xml_processing/parsing_xml.html b/help/diveintopython-5.4/html/xml_processing/parsing_xml.html
new file mode 100644
index 0000000..cb96df4
--- /dev/null
+++ b/help/diveintopython-5.4/html/xml_processing/parsing_xml.html
@@ -0,0 +1,279 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>9.3.&nbsp;Parsing XML</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;9.&nbsp;XML Processing">
+ <link rel="previous" href="packages.html" title="9.2.&nbsp;Packages">
+ <link rel="next" href="unicode.html" title="9.4.&nbsp;Unicode">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">XML Processing</a>&nbsp;&gt;&nbsp;<span class="thispage">Parsing XML</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="packages.html" title="Prev: &#8220;Packages&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="unicode.html" title="Next: &#8220;Unicode&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="kgp.parse"></a>9.3.&nbsp;Parsing <span class="acronym">XML</span></h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>As I was saying, actually parsing an <span class="acronym">XML</span> document is very simple: one line of code. Where you go from there is up to you.
+ </p>
+ </div>
+ <div class="example"><a name="d0e23245"></a><h3 class="title">Example&nbsp;9.8.&nbsp;Loading an <span class="acronym">XML</span> document (for real this time)
+ </h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>from</span> xml.dom <span class='pykeyword'>import</span> minidom</span> <a name="kgp.parse.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">xmldoc = minidom.parse(<span class='pystring'>'~/diveintopython/common/py/kgp/binary.xml'</span>)</span> <a name="kgp.parse.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">xmldoc</span> <a name="kgp.parse.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">&lt;xml.dom.minidom.Document instance at 010BE87C&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> xmldoc.toxml()</span> <a name="kgp.parse.1.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">&lt;?xml version="1.0" ?&gt;
+&lt;grammar&gt;
+&lt;ref id="bit"&gt;
+ &lt;p&gt;0&lt;/p&gt;
+ &lt;p&gt;1&lt;/p&gt;
+&lt;/ref&gt;
+&lt;ref id="byte"&gt;
+ &lt;p&gt;&lt;xref id="bit"/&gt;&lt;xref id="bit"/&gt;&lt;xref id="bit"/&gt;&lt;xref id="bit"/&gt;\
+&lt;xref id="bit"/&gt;&lt;xref id="bit"/&gt;&lt;xref id="bit"/&gt;&lt;xref id="bit"/&gt;&lt;/p&gt;
+&lt;/ref&gt;
+&lt;/grammar&gt;</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.parse.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">As you saw in the <a href="packages.html" title="9.2.&nbsp;Packages">previous section</a>, this imports the <tt class="filename">minidom</tt> module from the <tt class="filename">xml.dom</tt> package.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.parse.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Here is the one line of code that does all the work: <tt class="function">minidom.parse</tt> takes one argument and returns a parsed representation of the <span class="acronym">XML</span> document. The argument can be many things; in this case, it's simply a filename of an <span class="acronym">XML</span> document on my local disk. (To follow along, you'll need to change the path to point to your downloaded examples directory.)
+ But you can also pass a <a href="../file_handling/file_objects.html" title="6.2.&nbsp;Working with File Objects">file object</a>, or even a <a href="../html_processing/extracting_data.html#dialect.extract.urllib" title="Example&nbsp;8.5.&nbsp;Introducing urllib">file-like object</a>. You'll take advantage of this flexibility later in this chapter.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.parse.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The object returned from <tt class="function">minidom.parse</tt> is a <tt class="classname">Document</tt> object, a descendant of the <tt class="classname">Node</tt> class. This <tt class="classname">Document</tt> object is the root level of a complex tree-like structure of interlocking <span class="application">Python</span> objects that completely represent the <span class="acronym">XML</span> document you passed to <tt class="function">minidom.parse</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.parse.1.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">toxml</tt> is a method of the <tt class="classname">Node</tt> class (and is therefore available on the <tt class="classname">Document</tt> object you got from <tt class="function">minidom.parse</tt>). <tt class="function">toxml</tt> prints out the <span class="acronym">XML</span> that this <tt class="classname">Node</tt> represents. For the <tt class="classname">Document</tt> node, this prints out the entire <span class="acronym">XML</span> document.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>Now that you have an <span class="acronym">XML</span> document in memory, you can start traversing through it.
+ </p>
+ <div class="example"><a name="kgp.parse.gettingchildnodes.example"></a><h3 class="title">Example&nbsp;9.9.&nbsp;Getting child nodes</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">xmldoc.childNodes</span> <a name="kgp.parse.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">[&lt;DOM Element: grammar at 17538908&gt;]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">xmldoc.childNodes[0]</span> <a name="kgp.parse.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">&lt;DOM Element: grammar at 17538908&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">xmldoc.firstChild</span> <a name="kgp.parse.2.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">&lt;DOM Element: grammar at 17538908&gt;</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.parse.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Every <tt class="classname">Node</tt> has a <tt class="function">childNodes</tt> attribute, which is a list of the <tt class="classname">Node</tt> objects. A <tt class="classname">Document</tt> always has only one child node, the root element of the <span class="acronym">XML</span> document (in this case, the <tt class="sgmltag-element">grammar</tt> element).
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.parse.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">To get the first (and in this case, the only) child node, just use regular list syntax. Remember, there is nothing special
+ going on here; this is just a regular <span class="application">Python</span> list of regular <span class="application">Python</span> objects.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.parse.2.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Since getting the first child node of a node is a useful and common activity, the <tt class="classname">Node</tt> class has a <tt class="function">firstChild</tt> attribute, which is synonymous with <tt class="literal">childNodes[0]</tt>. (There is also a <tt class="function">lastChild</tt> attribute, which is synonymous with <tt class="literal">childNodes[-1]</tt>.)
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="d0e23458"></a><h3 class="title">Example&nbsp;9.10.&nbsp;<tt class="function">toxml</tt> works on any node
+ </h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">grammarNode = xmldoc.firstChild</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> grammarNode.toxml()</span> <a name="kgp.parse.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">&lt;grammar&gt;
+&lt;ref id="bit"&gt;
+ &lt;p&gt;0&lt;/p&gt;
+ &lt;p&gt;1&lt;/p&gt;
+&lt;/ref&gt;
+&lt;ref id="byte"&gt;
+ &lt;p&gt;&lt;xref id="bit"/&gt;&lt;xref id="bit"/&gt;&lt;xref id="bit"/&gt;&lt;xref id="bit"/&gt;\
+&lt;xref id="bit"/&gt;&lt;xref id="bit"/&gt;&lt;xref id="bit"/&gt;&lt;xref id="bit"/&gt;&lt;/p&gt;
+&lt;/ref&gt;
+&lt;/grammar&gt;</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.parse.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Since the <tt class="function">toxml</tt> method is defined in the <tt class="classname">Node</tt> class, it is available on any <span class="acronym">XML</span> node, not just the <tt class="classname">Document</tt> element.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="kgp.parse.childnodescanbetext.example"></a><h3 class="title">Example&nbsp;9.11.&nbsp;Child nodes can be text</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">grammarNode.childNodes</span> <a name="kgp.parse.4.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">[&lt;DOM Text node "\n"&gt;, &lt;DOM Element: ref at 17533332&gt;, \
+&lt;DOM Text node "\n"&gt;, &lt;DOM Element: ref at 17549660&gt;, &lt;DOM Text node "\n"&gt;]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> grammarNode.firstChild.toxml()</span> <a name="kgp.parse.4.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">
+
+</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> grammarNode.childNodes[1].toxml()</span> <a name="kgp.parse.4.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">&lt;ref id="bit"&gt;
+ &lt;p&gt;0&lt;/p&gt;
+ &lt;p&gt;1&lt;/p&gt;
+&lt;/ref&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> grammarNode.childNodes[3].toxml()</span> <a name="kgp.parse.4.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">&lt;ref id="byte"&gt;
+ &lt;p&gt;&lt;xref id="bit"/&gt;&lt;xref id="bit"/&gt;&lt;xref id="bit"/&gt;&lt;xref id="bit"/&gt;\
+&lt;xref id="bit"/&gt;&lt;xref id="bit"/&gt;&lt;xref id="bit"/&gt;&lt;xref id="bit"/&gt;&lt;/p&gt;
+&lt;/ref&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> grammarNode.lastChild.toxml()</span> <a name="kgp.parse.4.5"></a><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12">
+<span class="computeroutput">
+
+</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.parse.4.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Looking at the <span class="acronym">XML</span> in <tt class="filename">binary.xml</tt>, you might think that the <tt class="sgmltag-element">grammar</tt> has only two child nodes, the two <tt class="sgmltag-element">ref</tt> elements. But you're missing something: the carriage returns! After the <tt class="literal">'&lt;grammar&gt;'</tt> and before the first <tt class="literal">'&lt;ref&gt;'</tt> is a carriage return, and this text counts as a child node of the <tt class="sgmltag-element">grammar</tt> element. Similarly, there is a carriage return after each <tt class="literal">'&lt;/ref&gt;'</tt>; these also count as child nodes. So <tt class="literal">grammar.childNodes</tt> is actually a list of 5 objects: 3 <tt class="classname">Text</tt> objects and 2 <tt class="classname">Element</tt> objects.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.parse.4.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The first child is a <tt class="classname">Text</tt> object representing the carriage return after the <tt class="literal">'&lt;grammar&gt;'</tt> tag and before the first <tt class="literal">'&lt;ref&gt;'</tt> tag.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.parse.4.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The second child is an <tt class="classname">Element</tt> object representing the first <tt class="sgmltag-element">ref</tt> element.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.parse.4.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The fourth child is an <tt class="classname">Element</tt> object representing the second <tt class="sgmltag-element">ref</tt> element.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.parse.4.5"><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The last child is a <tt class="classname">Text</tt> object representing the carriage return after the <tt class="literal">'&lt;/ref&gt;'</tt> end tag and before the <tt class="literal">'&lt;/grammar&gt;'</tt> end tag.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="d0e23628"></a><h3 class="title">Example&nbsp;9.12.&nbsp;Drilling down all the way to text</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">grammarNode</span>
+<span class="computeroutput">&lt;DOM Element: grammar at 19167148&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">refNode = grammarNode.childNodes[1]</span> <a name="kgp.parse.5.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">refNode</span>
+<span class="computeroutput">&lt;DOM Element: ref at 17987740&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">refNode.childNodes</span> <a name="kgp.parse.5.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">[&lt;DOM Text node "\n"&gt;, &lt;DOM Text node " "&gt;, &lt;DOM Element: p at 19315844&gt;, \
+&lt;DOM Text node "\n"&gt;, &lt;DOM Text node " "&gt;, \
+&lt;DOM Element: p at 19462036&gt;, &lt;DOM Text node "\n"&gt;]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">pNode = refNode.childNodes[2]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">pNode</span>
+<span class="computeroutput">&lt;DOM Element: p at 19315844&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> pNode.toxml()</span> <a name="kgp.parse.5.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">&lt;p&gt;0&lt;/p&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">pNode.firstChild</span> <a name="kgp.parse.5.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<span class="computeroutput">&lt;DOM Text node "0"&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">pNode.firstChild.data</span> <a name="kgp.parse.5.5"></a><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12">
+<span class="computeroutput">u'0'</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.parse.5.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">As you saw in the previous example, the first <tt class="sgmltag-element">ref</tt> element is <tt class="literal">grammarNode.childNodes[1]</tt>, since childNodes[0] is a <tt class="classname">Text</tt> node for the carriage return.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.parse.5.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="sgmltag-element">ref</tt> element has its own set of child nodes, one for the carriage return, a separate one for the spaces, one for the <tt class="sgmltag-element">p</tt> element, and so forth.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.parse.5.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You can even use the <tt class="function">toxml</tt> method here, deeply nested within the document.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.parse.5.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="sgmltag-element">p</tt> element has only one child node (you can't tell that from this example, but look at <tt class="literal">pNode.childNodes</tt> if you don't believe me), and it is a <tt class="classname">Text</tt> node for the single character <tt class="literal">'0'</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.parse.5.5"><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The <tt class="literal">.data</tt> attribute of a <tt class="classname">Text</tt> node gives you the actual string that the text node represents. But what is that <tt class="literal">'u'</tt> in front of the string? The answer to that deserves its own section.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="packages.html">&lt;&lt;&nbsp;Packages</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#kgp.divein" title="9.1.&nbsp;Diving in">1</a> <span class="divider">|</span> <a href="packages.html" title="9.2.&nbsp;Packages">2</a> <span class="divider">|</span> <span class="thispage">3</span> <span class="divider">|</span> <a href="unicode.html" title="9.4.&nbsp;Unicode">4</a> <span class="divider">|</span> <a href="searching.html" title="9.5.&nbsp;Searching for elements">5</a> <span class="divider">|</span> <a href="attributes.html" title="9.6.&nbsp;Accessing element attributes">6</a> <span class="divider">|</span> <a href="summary.html" title="9.7.&nbsp;Segue">7</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="unicode.html">Unicode&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/xml_processing/searching.html b/help/diveintopython-5.4/html/xml_processing/searching.html
new file mode 100644
index 0000000..08147c2
--- /dev/null
+++ b/help/diveintopython-5.4/html/xml_processing/searching.html
@@ -0,0 +1,181 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>9.5.&nbsp;Searching for elements</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;9.&nbsp;XML Processing">
+ <link rel="previous" href="unicode.html" title="9.4.&nbsp;Unicode">
+ <link rel="next" href="attributes.html" title="9.6.&nbsp;Accessing element attributes">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">XML Processing</a>&nbsp;&gt;&nbsp;<span class="thispage">Searching for elements</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="unicode.html" title="Prev: &#8220;Unicode&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="attributes.html" title="Next: &#8220;Accessing element attributes&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="kgp.search"></a>9.5.&nbsp;Searching for elements
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>Traversing <span class="acronym">XML</span> documents by stepping through each node can be tedious. If you're looking for something in particular, buried deep within
+ your <span class="acronym">XML</span> document, there is a shortcut you can use to find it quickly: <tt class="function">getElementsByTagName</tt>.
+ </p>
+ </div>
+ <p>For this section, you'll be using the <tt class="filename">binary.xml</tt> grammar file, which looks like this:
+ </p>
+ <div class="example"><a name="d0e24431"></a><h3 class="title">Example&nbsp;9.20.&nbsp;<tt class="filename">binary.xml</tt></h3><pre class="screen"><span class="computeroutput">&lt;?xml version="1.0"?&gt;
+&lt;!DOCTYPE grammar PUBLIC "-//diveintopython.org//DTD Kant Generator Pro v1.0//EN" "kgp.dtd"&gt;
+&lt;grammar&gt;
+&lt;ref id="bit"&gt;
+ &lt;p&gt;0&lt;/p&gt;
+ &lt;p&gt;1&lt;/p&gt;
+&lt;/ref&gt;
+&lt;ref id="byte"&gt;
+ &lt;p&gt;&lt;xref id="bit"/&gt;&lt;xref id="bit"/&gt;&lt;xref id="bit"/&gt;&lt;xref id="bit"/&gt;\
+&lt;xref id="bit"/&gt;&lt;xref id="bit"/&gt;&lt;xref id="bit"/&gt;&lt;xref id="bit"/&gt;&lt;/p&gt;
+&lt;/ref&gt;
+&lt;/grammar&gt;</span></pre></div>
+ <p>It has two <tt class="sgmltag-element">ref</tt>s, <tt class="literal">'bit'</tt> and <tt class="literal">'byte'</tt>. A <tt class="literal">bit</tt> is either a <tt class="literal">'0'</tt> or <tt class="literal">'1'</tt>, and a <tt class="literal">byte</tt> is 8 <tt class="literal">bit</tt>s.
+ </p>
+ <div class="example"><a name="d0e24464"></a><h3 class="title">Example&nbsp;9.21.&nbsp;Introducing <tt class="function">getElementsByTagName</tt></h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>from</span> xml.dom <span class='pykeyword'>import</span> minidom</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">xmldoc = minidom.parse(<span class='pystring'>'binary.xml'</span>)</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">reflist = xmldoc.getElementsByTagName(<span class='pystring'>'ref'</span>)</span> <a name="kgp.search.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">reflist</span>
+<span class="computeroutput">[&lt;DOM Element: ref at 136138108&gt;, &lt;DOM Element: ref at 136144292&gt;]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> reflist[0].toxml()</span>
+<span class="computeroutput">&lt;ref id="bit"&gt;
+ &lt;p&gt;0&lt;/p&gt;
+ &lt;p&gt;1&lt;/p&gt;
+&lt;/ref&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> reflist[1].toxml()</span>
+<span class="computeroutput">&lt;ref id="byte"&gt;
+ &lt;p&gt;&lt;xref id="bit"/&gt;&lt;xref id="bit"/&gt;&lt;xref id="bit"/&gt;&lt;xref id="bit"/&gt;\
+&lt;xref id="bit"/&gt;&lt;xref id="bit"/&gt;&lt;xref id="bit"/&gt;&lt;xref id="bit"/&gt;&lt;/p&gt;
+&lt;/ref&gt;
+</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.search.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">getElementsByTagName</tt> takes one argument, the name of the element you wish to find. It returns a list of <tt class="classname">Element</tt> objects, corresponding to the <span class="acronym">XML</span> elements that have that name. In this case, you find two <tt class="literal">ref</tt> elements.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="d0e24526"></a><h3 class="title">Example&nbsp;9.22.&nbsp;Every element is searchable</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">firstref = reflist[0]</span> <a name="kgp.search.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> firstref.toxml()</span>
+<span class="computeroutput">&lt;ref id="bit"&gt;
+ &lt;p&gt;0&lt;/p&gt;
+ &lt;p&gt;1&lt;/p&gt;
+&lt;/ref&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">plist = firstref.getElementsByTagName(<span class='pystring'>"p"</span>)</span> <a name="kgp.search.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">plist</span>
+<span class="computeroutput">[&lt;DOM Element: p at 136140116&gt;, &lt;DOM Element: p at 136142172&gt;]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> plist[0].toxml()</span> <a name="kgp.search.2.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">&lt;p&gt;0&lt;/p&gt;</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> plist[1].toxml()</span>
+<span class="computeroutput">&lt;p&gt;1&lt;/p&gt;</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.search.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Continuing from the previous example, the first object in your <tt class="varname">reflist</tt> is the <tt class="literal">'bit'</tt> <tt class="sgmltag-element">ref</tt> element.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.search.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You can use the same <tt class="function">getElementsByTagName</tt> method on this <tt class="classname">Element</tt> to find all the <tt class="sgmltag-element">&lt;p&gt;</tt> elements within the <tt class="literal">'bit'</tt> <tt class="sgmltag-element">ref</tt> element.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.search.2.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Just as before, the <tt class="function">getElementsByTagName</tt> method returns a list of all the elements it found. In this case, you have two, one for each bit.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="d0e24615"></a><h3 class="title">Example&nbsp;9.23.&nbsp;Searching is actually recursive</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">plist = xmldoc.getElementsByTagName(<span class='pystring'>"p"</span>)</span> <a name="kgp.search.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">plist</span>
+<span class="computeroutput">[&lt;DOM Element: p at 136140116&gt;, &lt;DOM Element: p at 136142172&gt;, &lt;DOM Element: p at 136146124&gt;]</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">plist[0].toxml()</span> <a name="kgp.search.3.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">'&lt;p&gt;0&lt;/p&gt;'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">plist[1].toxml()</span>
+<span class="computeroutput">'&lt;p&gt;1&lt;/p&gt;'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">plist[2].toxml()</span> <a name="kgp.search.3.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">'&lt;p&gt;&lt;xref id="bit"/&gt;&lt;xref id="bit"/&gt;&lt;xref id="bit"/&gt;&lt;xref id="bit"/&gt;\
+&lt;xref id="bit"/&gt;&lt;xref id="bit"/&gt;&lt;xref id="bit"/&gt;&lt;xref id="bit"/&gt;&lt;/p&gt;'</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.search.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Note carefully the difference between this and the previous example. Previously, you were searching for <tt class="sgmltag-element">p</tt> elements within <tt class="varname">firstref</tt>, but here you are searching for <tt class="sgmltag-element">p</tt> elements within <tt class="varname">xmldoc</tt>, the root-level object that represents the entire <span class="acronym">XML</span> document. This <span class="emphasis"><em>does</em></span> find the <tt class="sgmltag-element">p</tt> elements nested within the <tt class="sgmltag-element">ref</tt> elements within the root <tt class="sgmltag-element">grammar</tt> element.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.search.3.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The first two <tt class="sgmltag-element">p</tt> elements are within the first <tt class="sgmltag-element">ref</tt> (the <tt class="literal">'bit'</tt> <tt class="sgmltag-element">ref</tt>).
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.search.3.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The last <tt class="sgmltag-element">p</tt> element is the one within the second <tt class="sgmltag-element">ref</tt> (the <tt class="literal">'byte'</tt> <tt class="sgmltag-element">ref</tt>).
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="unicode.html">&lt;&lt;&nbsp;Unicode</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#kgp.divein" title="9.1.&nbsp;Diving in">1</a> <span class="divider">|</span> <a href="packages.html" title="9.2.&nbsp;Packages">2</a> <span class="divider">|</span> <a href="parsing_xml.html" title="9.3.&nbsp;Parsing XML">3</a> <span class="divider">|</span> <a href="unicode.html" title="9.4.&nbsp;Unicode">4</a> <span class="divider">|</span> <span class="thispage">5</span> <span class="divider">|</span> <a href="attributes.html" title="9.6.&nbsp;Accessing element attributes">6</a> <span class="divider">|</span> <a href="summary.html" title="9.7.&nbsp;Segue">7</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="attributes.html">Accessing element attributes&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/xml_processing/summary.html b/help/diveintopython-5.4/html/xml_processing/summary.html
new file mode 100644
index 0000000..c488d7c
--- /dev/null
+++ b/help/diveintopython-5.4/html/xml_processing/summary.html
@@ -0,0 +1,78 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>9.7.&nbsp;Segue</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;9.&nbsp;XML Processing">
+ <link rel="previous" href="attributes.html" title="9.6.&nbsp;Accessing element attributes">
+ <link rel="next" href="../scripts_and_streams/index.html" title="Chapter&nbsp;10.&nbsp;Scripts and Streams">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">XML Processing</a>&nbsp;&gt;&nbsp;<span class="thispage">Segue</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="attributes.html" title="Prev: &#8220;Accessing element attributes&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="../scripts_and_streams/index.html" title="Next: &#8220;Scripts and Streams&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="kgp.segue"></a>9.7.&nbsp;Segue
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>OK, that's it for the hard-core XML stuff. The next chapter will continue to use these same example programs, but focus on
+ other aspects that make the program more flexible: using streams for input processing, using <tt class="function">getattr</tt> for method dispatching, and using command-line flags to allow users to reconfigure the program without changing the code.
+ </p>
+ </div>
+ <p>Before moving on to the next chapter, you should be comfortable doing all of these things:</p>
+ <div class="itemizedlist">
+ <ul>
+ <li><a href="parsing_xml.html" title="9.3.&nbsp;Parsing XML">Parsing <span class="acronym">XML</span> documents</a> using <tt class="filename">minidom</tt>, <a href="searching.html" title="9.5.&nbsp;Searching for elements">searching through the parsed document</a>, and accessing arbitrary <a href="attributes.html" title="9.6.&nbsp;Accessing element attributes">element attributes</a> and <a href="../scripts_and_streams/child_nodes.html" title="10.4.&nbsp;Finding direct children of a node">element children</a></li>
+ <li>Organizing complex libraries into <a href="packages.html" title="9.2.&nbsp;Packages">packages</a></li>
+ <li><a href="unicode.html" title="9.4.&nbsp;Unicode">Converting unicode strings</a> to different character encodings
+ </li>
+ </ul>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="attributes.html">&lt;&lt;&nbsp;Accessing element attributes</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#kgp.divein" title="9.1.&nbsp;Diving in">1</a> <span class="divider">|</span> <a href="packages.html" title="9.2.&nbsp;Packages">2</a> <span class="divider">|</span> <a href="parsing_xml.html" title="9.3.&nbsp;Parsing XML">3</a> <span class="divider">|</span> <a href="unicode.html" title="9.4.&nbsp;Unicode">4</a> <span class="divider">|</span> <a href="searching.html" title="9.5.&nbsp;Searching for elements">5</a> <span class="divider">|</span> <a href="attributes.html" title="9.6.&nbsp;Accessing element attributes">6</a> <span class="divider">|</span> <span class="thispage">7</span>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="../scripts_and_streams/index.html">Scripts and Streams&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/html/xml_processing/unicode.html b/help/diveintopython-5.4/html/xml_processing/unicode.html
new file mode 100644
index 0000000..bacefa5
--- /dev/null
+++ b/help/diveintopython-5.4/html/xml_processing/unicode.html
@@ -0,0 +1,308 @@
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <title>9.4.&nbsp;Unicode</title>
+ <link rel="stylesheet" href="../diveintopython.css" type="text/css">
+ <link rev="made" href="mailto:f8dy@diveintopython.org">
+ <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
+ <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
+ <meta name="description" content="Python from novice to pro">
+ <link rel="home" href="../toc/index.html" title="Dive Into Python">
+ <link rel="up" href="index.html" title="Chapter&nbsp;9.&nbsp;XML Processing">
+ <link rel="previous" href="parsing_xml.html" title="9.3.&nbsp;Parsing XML">
+ <link rel="next" href="searching.html" title="9.5.&nbsp;Searching for elements">
+ </head>
+ <body>
+ <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td id="breadcrumb" colspan="5" align="left" valign="top">You are here: <a href="../index.html">Home</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">XML Processing</a>&nbsp;&gt;&nbsp;<span class="thispage">Unicode</span></td>
+ <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="parsing_xml.html" title="Prev: &#8220;Parsing XML&#8221;">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="searching.html" title="Next: &#8220;Searching for elements&#8221;">&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3" id="logocontainer">
+ <h1 id="logo"><a href="../index.html" accesskey="1">Dive Into Python</a></h1>
+ <p id="tagline">Python from novice to pro</p>
+ </td>
+ <td colspan="3" align="right">
+ <form id="search" method="GET" action="http://www.google.com/custom">
+ <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=" "> <input type="submit" value="Search"><input type="hidden" name="cof" value="LW:752;L:http://diveintopython.org/images/diveintopython.png;LH:42;AH:left;GL:0;AWFID:3ced2bb1f7f1b212;"><input type="hidden" name="domains" value="diveintopython.org"><input type="hidden" name="sitesearch" value="diveintopython.org"></p>
+ </form>
+ </td>
+ </tr>
+ </table>
+ <!--#include virtual="/inc/ads" -->
+ <div class="section" lang="en">
+ <div class="titlepage">
+ <div>
+ <div>
+ <h2 class="title"><a name="kgp.unicode"></a>9.4.&nbsp;Unicode
+ </h2>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ <div class="abstract">
+ <p>Unicode is a system to represent characters from all the world's different languages. When <span class="application">Python</span> parses an <span class="acronym">XML</span> document, all data is stored in memory as unicode.
+ </p>
+ </div>
+ <p>You'll get to all that in a minute, but first, some background.</p>
+ <p><b>Historical note.&nbsp;</b>Before unicode, there were separate character encoding systems for each language, each using the same numbers (0-255) to represent
+ that language's characters. Some languages (like Russian) have multiple conflicting standards about how to represent the
+ same characters; other languages (like Japanese) have so many characters that they require multiple-byte character sets.
+ Exchanging documents between systems was difficult because there was no way for a computer to tell for certain which character
+ encoding scheme the document author had used; the computer only saw numbers, and the numbers could mean different things.
+ Then think about trying to store these documents in the same place (like in the same database table); you would need to store
+ the character encoding alongside each piece of text, and make sure to pass it around whenever you passed the text around.
+ Then think about multilingual documents, with characters from multiple languages in the same document. (They typically used
+ escape codes to switch modes; poof, you're in Russian koi8-r mode, so character 241 means this; poof, now you're in Mac Greek
+ mode, so character 241 means something else. And so on.) These are the problems which unicode was designed to solve.
+ </p>
+ <p>To solve these problems, unicode represents each character as a 2-byte number, from 0 to 65535.<sup>[<a name="d0e23786" href="#ftn.d0e23786">5</a>]</sup> Each 2-byte number represents a unique character used in at least one of the world's languages. (Characters that are used
+ in multiple languages have the same numeric code.) There is exactly 1 number per character, and exactly 1 character per number.
+ Unicode data is never ambiguous.
+ </p>
+ <p>Of course, there is still the matter of all these legacy encoding systems. 7-bit <span class="acronym">ASCII</span>, for instance, which stores English characters as numbers ranging from 0 to 127. (65 is capital &#8220;<span class="quote"><tt class="literal">A</tt></span>&#8221;, 97 is lowercase &#8220;<span class="quote"><tt class="literal">a</tt></span>&#8221;, and so forth.) English has a very simple alphabet, so it can be completely expressed in 7-bit <span class="acronym">ASCII</span>. Western European languages like French, Spanish, and German all use an encoding system called ISO-8859-1 (also called &#8220;<span class="quote">latin-1</span>&#8221;), which uses the 7-bit <span class="acronym">ASCII</span> characters for the numbers 0 through 127, but then extends into the 128-255 range for characters like n-with-a-tilde-over-it
+ (241), and u-with-two-dots-over-it (252). And unicode uses the same characters as 7-bit <span class="acronym">ASCII</span> for 0 through 127, and the same characters as ISO-8859-1 for 128 through 255, and then extends from there into characters
+ for other languages with the remaining numbers, 256 through 65535.
+ </p>
+ <p>When dealing with unicode data, you may at some point need to convert the data back into one of these other legacy encoding
+ systems. For instance, to integrate with some other computer system which expects its data in a specific 1-byte encoding
+ scheme, or to print it to a non-unicode-aware terminal or printer. Or to store it in an <span class="acronym">XML</span> document which explicitly specifies the encoding scheme.
+ </p>
+ <p>And on that note, let's get back to <span class="application">Python</span>.
+ </p>
+ <p><span class="application">Python</span> has had unicode support throughout the language since version 2.0. The <span class="acronym">XML</span> package uses unicode to store all parsed <span class="acronym">XML</span> data, but you can use unicode anywhere.
+ </p>
+ <div class="example"><a name="d0e23841"></a><h3 class="title">Example&nbsp;9.13.&nbsp;Introducing unicode</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">s = u<span class='pystring'>'Dive in'</span></span> <a name="kgp.unicode.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">s</span>
+<span class="computeroutput">u'Dive in'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> s</span> <a name="kgp.unicode.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">Dive in</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.unicode.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">To create a unicode string instead of a regular <span class="acronym">ASCII</span> string, add the letter &#8220;<span class="quote"><tt class="literal">u</tt></span>&#8221; before the string. Note that this particular string doesn't have any non-<span class="acronym">ASCII</span> characters. That's fine; unicode is a superset of <span class="acronym">ASCII</span> (a very large superset at that), so any regular <span class="acronym">ASCII</span> string can also be stored as unicode.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.unicode.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">When printing a string, <span class="application">Python</span> will attempt to convert it to your default encoding, which is usually <span class="acronym">ASCII</span>. (More on this in a minute.) Since this unicode string is made up of characters that are also <span class="acronym">ASCII</span> characters, printing it has the same result as printing a normal <span class="acronym">ASCII</span> string; the conversion is seamless, and if you didn't know that <tt class="varname">s</tt> was a unicode string, you'd never notice the difference.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="d0e23908"></a><h3 class="title">Example&nbsp;9.14.&nbsp;Storing non-<span class="acronym">ASCII</span> characters
+ </h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">s = u<span class='pystring'>'La Pe\xf1a'</span></span> <a name="kgp.unicode.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> s</span> <a name="kgp.unicode.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="traceback">Traceback (innermost last):
+ File "&lt;interactive input&gt;", line 1, in ?
+UnicodeError: ASCII encoding error: ordinal not in range(128)</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> s.encode(<span class='pystring'>'latin-1'</span>)</span> <a name="kgp.unicode.2.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="computeroutput">La Pe&ntilde;a</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.unicode.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">The real advantage of unicode, of course, is its ability to store non-<span class="acronym">ASCII</span> characters, like the Spanish &#8220;<span class="quote"><tt class="literal">&ntilde;</tt></span>&#8221; (<tt class="literal">n</tt> with a tilde over it). The unicode character code for the tilde-n is <tt class="literal">0xf1</tt> in hexadecimal (241 in decimal), which you can type like this: <tt class="literal">\xf1</tt>.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.unicode.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Remember I said that the <tt class="function">print</tt> function attempts to convert a unicode string to <span class="acronym">ASCII</span> so it can print it? Well, that's not going to work here, because your unicode string contains non-<span class="acronym">ASCII</span> characters, so <span class="application">Python</span> raises a <tt class="errorname">UnicodeError</tt> error.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.unicode.2.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Here's where the conversion-from-unicode-to-other-encoding-schemes comes in. <tt class="varname">s</tt> is a unicode string, but <tt class="function">print</tt> can only print a regular string. To solve this problem, you call the <tt class="function">encode</tt> method, available on every unicode string, to convert the unicode string to a regular string in the given encoding scheme,
+ which you pass as a parameter. In this case, you're using <tt class="literal">latin-1</tt> (also known as <tt class="literal">iso-8859-1</tt>), which includes the tilde-n (whereas the default <span class="acronym">ASCII</span> encoding scheme did not, since it only includes characters numbered 0 through 127).
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>Remember I said <span class="application">Python</span> usually converted unicode to <span class="acronym">ASCII</span> whenever it needed to make a regular string out of a unicode string? Well, this default encoding scheme is an option which
+ you can customize.
+ </p>
+ <div class="example"><a name="d0e24009"></a><h3 class="title">Example&nbsp;9.15.&nbsp;<tt class="filename">sitecustomize.py</tt></h3><pre class="programlisting">
+<span class='pycomment'># sitecustomize.py </span><a name="kgp.unicode.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class='pycomment'># this file can be anywhere in your Python path,</span>
+<span class='pycomment'># but it usually goes in ${pythondir}/lib/site-packages/</span>
+<span class='pykeyword'>import</span> sys
+sys.setdefaultencoding(<span class='pystring'>'iso-8859-1'</span>) <a name="kgp.unicode.3.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+</pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.unicode.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="filename">sitecustomize.py</tt> is a special script; <span class="application">Python</span> will try to import it on startup, so any code in it will be run automatically. As the comment mentions, it can go anywhere
+ (as long as <tt class="literal">import</tt> can find it), but it usually goes in the <tt class="filename">site-packages</tt> directory within your <span class="application">Python</span> <tt class="filename">lib</tt> directory.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.unicode.3.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left"><tt class="function">setdefaultencoding</tt> function sets, well, the default encoding. This is the encoding scheme that <span class="application">Python</span> will try to use whenever it needs to auto-coerce a unicode string into a regular string.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="d0e24048"></a><h3 class="title">Example&nbsp;9.16.&nbsp;Effects of setting the default encoding</h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> sys</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">sys.getdefaultencoding()</span> <a name="kgp.unicode.4.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<span class="computeroutput">'iso-8859-1'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">s = u<span class='pystring'>'La Pe\xf1a'</span></span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> s</span> <a name="kgp.unicode.4.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">La Pe&ntilde;a</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.unicode.4.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This example assumes that you have made the changes listed in the previous example to your <tt class="filename">sitecustomize.py</tt> file, and restarted <span class="application">Python</span>. If your default encoding still says <tt class="literal">'ascii'</tt>, you didn't set up your <tt class="filename">sitecustomize.py</tt> properly, or you didn't restart <span class="application">Python</span>. The default encoding can only be changed during <span class="application">Python</span> startup; you can't change it later. (Due to some wacky programming tricks that I won't get into right now, you can't even
+ call <tt class="function">sys.setdefaultencoding</tt> after <span class="application">Python</span> has started up. Dig into <tt class="filename">site.py</tt> and search for &#8220;<span class="quote"><tt class="literal">setdefaultencoding</tt></span>&#8221; to find out how.)
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.unicode.4.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Now that the default encoding scheme includes all the characters you use in your string, <span class="application">Python</span> has no problem auto-coercing the string and printing it.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="d0e24123"></a><h3 class="title">Example&nbsp;9.17.&nbsp;Specifying encoding in <tt class="filename">.py</tt> files
+ </h3>
+ <p>If you are going to be storing non-ASCII strings within your <span class="application">Python</span> code, you'll need to specify the encoding of each individual <tt class="filename">.py</tt> file by putting an encoding declaration at the top of each file. This declaration defines the <tt class="filename">.py</tt> file to be UTF-8:
+ </p><pre class="programlisting">
+<span class='pycomment'>#!/usr/bin/env python</span>
+<span class='pycomment'># -*- coding: UTF-8 -*-</span>
+</pre></div>
+ <p>Now, what about <span class="acronym">XML</span>? Well, every <span class="acronym">XML</span> document is in a specific encoding. Again, ISO-8859-1 is a popular encoding for data in Western European languages. KOI8-R
+ is popular for Russian texts. The encoding, if specified, is in the header of the <span class="acronym">XML</span> document.
+ </p>
+ <div class="example"><a name="d0e24153"></a><h3 class="title">Example&nbsp;9.18.&nbsp;<tt class="filename">russiansample.xml</tt></h3><pre class="screen"><span class="computeroutput">
+&lt;?xml version="1.0" encoding="koi8-r"?&gt; </span><a name="kgp.unicode.5.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"><span class="computeroutput">
+&lt;preface&gt;
+&lt;title&gt;&#1055;&#1088;&#1077;&#1076;&#1080;&#1089;&#1083;&#1086;&#1074;&#1080;&#1077;&lt;/title&gt; </span><a name="kgp.unicode.5.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"><span class="computeroutput">
+&lt;/preface&gt;</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.unicode.5.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">This is a sample extract from a real Russian <span class="acronym">XML</span> document; it's part of a Russian translation of this very book. Note the encoding, <tt class="literal">koi8-r</tt>, specified in the header.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.unicode.5.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">These are Cyrillic characters which, as far as I know, spell the Russian word for &#8220;<span class="quote">Preface</span>&#8221;. If you open this file in a regular text editor, the characters will most likely like gibberish, because they're encoded
+ using the <tt class="literal">koi8-r</tt> encoding scheme, but they're being displayed in <tt class="literal">iso-8859-1</tt>.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="example"><a name="d0e24188"></a><h3 class="title">Example&nbsp;9.19.&nbsp;Parsing <tt class="filename">russiansample.xml</tt></h3><pre class="screen">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>from</span> xml.dom <span class='pykeyword'>import</span> minidom</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">xmldoc = minidom.parse(<span class='pystring'>'russiansample.xml'</span>)</span> <a name="kgp.unicode.6.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">title = xmldoc.getElementsByTagName(<span class='pystring'>'title'</span>)[0].firstChild.data</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">title</span> <a name="kgp.unicode.6.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
+<span class="computeroutput">u'\u041f\u0440\u0435\u0434\u0438\u0441\u043b\u043e\u0432\u0438\u0435'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> title</span> <a name="kgp.unicode.6.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
+<span class="traceback">Traceback (innermost last):
+ File "&lt;interactive input&gt;", line 1, in ?
+UnicodeError: ASCII encoding error: ordinal not in range(128)</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">convertedtitle = title.encode(<span class='pystring'>'koi8-r'</span>)</span> <a name="kgp.unicode.6.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">convertedtitle</span>
+<span class="computeroutput">'\xf0\xd2\xc5\xc4\xc9\xd3\xcc\xcf\xd7\xc9\xc5'</span>
+<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>print</span> convertedtitle</span> <a name="kgp.unicode.6.5"></a><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12">
+<span class="computeroutput">&#1055;&#1088;&#1077;&#1076;&#1080;&#1089;&#1083;&#1086;&#1074;&#1080;&#1077;</span></pre><div class="calloutlist">
+ <table border="0" summary="Callout list">
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.unicode.6.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">I'm assuming here that you saved the previous example as <tt class="filename">russiansample.xml</tt> in the current directory. I am also, for the sake of completeness, assuming that you've changed your default encoding back
+ to <tt class="literal">'ascii'</tt> by removing your <tt class="filename">sitecustomize.py</tt> file, or at least commenting out the <tt class="function">setdefaultencoding</tt> line.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.unicode.6.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Note that the text data of the <tt class="sgmltag-element">title</tt> tag (now in the <tt class="varname">title</tt> variable, thanks to that long concatenation of <span class="application">Python</span> functions which I hastily skipped over and, annoyingly, won't explain until the next section) -- the text data inside the
+ <span class="acronym">XML</span> document's <tt class="sgmltag-element">title</tt> element is stored in unicode.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.unicode.6.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Printing the title is not possible, because this unicode string contains non-<span class="acronym">ASCII</span> characters, so <span class="application">Python</span> can't convert it to <span class="acronym">ASCII</span> because that doesn't make sense.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.unicode.6.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">You can, however, explicitly convert it to <tt class="literal">koi8-r</tt>, in which case you get a (regular, not unicode) string of single-byte characters (<tt class="literal">f0</tt>, <tt class="literal">d2</tt>, <tt class="literal">c5</tt>, and so forth) that are the <tt class="literal">koi8-r</tt>-encoded versions of the characters in the original unicode string.
+ </td>
+ </tr>
+ <tr>
+ <td width="12" valign="top" align="left"><a href="#kgp.unicode.6.5"><img src="../images/callouts/5.png" alt="5" border="0" width="12" height="12"></a>
+ </td>
+ <td valign="top" align="left">Printing the <tt class="literal">koi8-r</tt>-encoded string will probably show gibberish on your screen, because your <span class="application">Python</span> <span class="acronym">IDE</span> is interpreting those characters as <tt class="literal">iso-8859-1</tt>, not <tt class="literal">koi8-r</tt>. But at least they do print. (And, if you look carefully, it's the same gibberish that you saw when you opened the original
+ <span class="acronym">XML</span> document in a non-unicode-aware text editor. <span class="application">Python</span> converted it from <tt class="literal">koi8-r</tt> into unicode when it parsed the <span class="acronym">XML</span> document, and you've just converted it back.)
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <p>To sum up, unicode itself is a bit intimidating if you've never seen it before, but unicode data is really very easy to handle
+ in <span class="application">Python</span>. If your <span class="acronym">XML</span> documents are all 7-bit <span class="acronym">ASCII</span> (like the examples in this chapter), you will literally never think about unicode. <span class="application">Python</span> will convert the <span class="acronym">ASCII</span> data in the <span class="acronym">XML</span> documents into unicode while parsing, and auto-coerce it back to <span class="acronym">ASCII</span> whenever necessary, and you'll never even notice. But if you need to deal with that in other languages, <span class="application">Python</span> is ready.
+ </p>
+ <div class="furtherreading">
+ <h3>Further reading</h3>
+ <ul>
+ <li><a href="http://www.unicode.org/">Unicode.org</a> is the home page of the unicode standard, including a brief <a href="http://www.unicode.org/standard/principles.html">technical introduction</a>.
+ </li>
+ <li><a href="http://www.reportlab.com/i18n/python_unicode_tutorial.html">Unicode Tutorial</a> has some more examples of how to use <span class="application">Python</span>'s unicode functions, including how to force <span class="application">Python</span> to coerce unicode into <span class="acronym">ASCII</span> even when it doesn't really want to.
+ </li>
+ <li><a href="http://www.python.org/peps/pep-0263.html">PEP 263</a> goes into more detail about how and when to define a character encoding in your <tt class="filename">.py</tt> files.
+ </li>
+ </ul>
+ </div>
+ <div class="footnotes">
+ <h3 class="footnotetitle">Footnotes</h3>
+ <div class="footnote">
+ <p><sup>[<a name="ftn.d0e23786" href="#d0e23786">5</a>] </sup>This, sadly, is <span class="emphasis"><em>still</em></span> an oversimplification. Unicode now has been extended to handle ancient Chinese, Korean, and Japanese texts, which had so
+ many different characters that the 2-byte unicode system could not represent them all. But <span class="application">Python</span> doesn't currently support that out of the box, and I don't know if there is a project afoot to add it. You've reached the
+ limits of my expertise, sorry.
+ </p>
+ </div>
+ </div>
+ </div>
+ <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
+ <tr>
+ <td width="35%" align="left"><br><a class="NavigationArrow" href="parsing_xml.html">&lt;&lt;&nbsp;Parsing XML</a></td>
+ <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#kgp.divein" title="9.1.&nbsp;Diving in">1</a> <span class="divider">|</span> <a href="packages.html" title="9.2.&nbsp;Packages">2</a> <span class="divider">|</span> <a href="parsing_xml.html" title="9.3.&nbsp;Parsing XML">3</a> <span class="divider">|</span> <span class="thispage">4</span> <span class="divider">|</span> <a href="searching.html" title="9.5.&nbsp;Searching for elements">5</a> <span class="divider">|</span> <a href="attributes.html" title="9.6.&nbsp;Accessing element attributes">6</a> <span class="divider">|</span> <a href="summary.html" title="9.7.&nbsp;Segue">7</a>&nbsp;<span class="divider">|</span>&nbsp;
+ </td>
+ <td width="35%" align="right"><br><a class="NavigationArrow" href="searching.html">Searching for elements&nbsp;&gt;&gt;</a></td>
+ </tr>
+ <tr>
+ <td colspan="3"><br></td>
+ </tr>
+ </table>
+ <div class="Footer">
+ <p class="copyright">Copyright &copy; 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/diveintopython-5.4/py/BaseHTMLProcessor.py b/help/diveintopython-5.4/py/BaseHTMLProcessor.py
new file mode 100644
index 0000000..bc65f9d
--- /dev/null
+++ b/help/diveintopython-5.4/py/BaseHTMLProcessor.py
@@ -0,0 +1,93 @@
+"""Base class for creating HTML processing modules
+
+This class is designed to take HTML as input and spit out equivalent
+HTML as output. By itself it's not very interesting; you use it by
+subclassing it and providing the methods you need to create your HTML
+transformation.
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.2 $"
+__date__ = "$Date: 2004/05/05 21:57:19 $"
+__copyright__ = "Copyright (c) 2001 Mark Pilgrim"
+__license__ = "Python"
+
+from sgmllib import SGMLParser
+import htmlentitydefs
+
+class BaseHTMLProcessor(SGMLParser):
+ def reset(self):
+ # extend (called by SGMLParser.__init__)
+ self.pieces = []
+ SGMLParser.reset(self)
+
+ def unknown_starttag(self, tag, attrs):
+ # called for each start tag
+ # attrs is a list of (attr, value) tuples
+ # e.g. for <pre class="screen">, tag="pre", attrs=[("class", "screen")]
+ # Ideally we would like to reconstruct original tag and attributes, but
+ # we may end up quoting attribute values that weren't quoted in the source
+ # document, or we may change the type of quotes around the attribute value
+ # (single to double quotes).
+ # Note that improperly embedded non-HTML code (like client-side Javascript)
+ # may be parsed incorrectly by the ancestor, causing runtime script errors.
+ # All non-HTML code must be enclosed in HTML comment tags (<!-- code -->)
+ # to ensure that it will pass through this parser unaltered (in handle_comment).
+ strattrs = "".join([' %s="%s"' % (key, value) for key, value in attrs])
+ self.pieces.append("<%(tag)s%(strattrs)s>" % locals())
+
+ def unknown_endtag(self, tag):
+ # called for each end tag, e.g. for </pre>, tag will be "pre"
+ # Reconstruct the original end tag.
+ self.pieces.append("</%(tag)s>" % locals())
+
+ def handle_charref(self, ref):
+ # called for each character reference, e.g. for "&#160;", ref will be "160"
+ # Reconstruct the original character reference.
+ self.pieces.append("&#%(ref)s;" % locals())
+
+ def handle_entityref(self, ref):
+ # called for each entity reference, e.g. for "&copy;", ref will be "copy"
+ # Reconstruct the original entity reference.
+ self.pieces.append("&%(ref)s" % locals())
+ # standard HTML entities are closed with a semicolon; other entities are not
+ if htmlentitydefs.entitydefs.has_key(ref):
+ self.pieces.append(";")
+
+ def handle_data(self, text):
+ # called for each block of plain text, i.e. outside of any tag and
+ # not containing any character or entity references
+ # Store the original text verbatim.
+ self.pieces.append(text)
+
+ def handle_comment(self, text):
+ # called for each HTML comment, e.g. <!-- insert Javascript code here -->
+ # Reconstruct the original comment.
+ # It is especially important that the source document enclose client-side
+ # code (like Javascript) within comments so it can pass through this
+ # processor undisturbed; see comments in unknown_starttag for details.
+ self.pieces.append("<!--%(text)s-->" % locals())
+
+ def handle_pi(self, text):
+ # called for each processing instruction, e.g. <?instruction>
+ # Reconstruct original processing instruction.
+ self.pieces.append("<?%(text)s>" % locals())
+
+ def handle_decl(self, text):
+ # called for the DOCTYPE, if present, e.g.
+ # <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ # "http://www.w3.org/TR/html4/loose.dtd">
+ # Reconstruct original DOCTYPE
+ self.pieces.append("<!%(text)s>" % locals())
+
+ def output(self):
+ """Return processed HTML as a single string"""
+ return "".join(self.pieces)
+
+if __name__ == "__main__":
+ for k, v in globals().items():
+ print k, "=", v
diff --git a/help/diveintopython-5.4/py/LICENSE.txt b/help/diveintopython-5.4/py/LICENSE.txt
new file mode 100644
index 0000000..29ec14f
--- /dev/null
+++ b/help/diveintopython-5.4/py/LICENSE.txt
@@ -0,0 +1,234 @@
+Python 2.1.1 license (http://www.python.org/2.1.1/license.html)
+
+A. HISTORY OF THE SOFTWARE
+==========================
+
+Python was created in the early 1990s by Guido van Rossum at Stichting
+Mathematisch Centrum (CWI) in the Netherlands as a successor of a
+language called ABC. Guido is Python's principal author, although it
+includes many contributions from others. The last version released
+from CWI was Python 1.2. In 1995, Guido continued his work on Python
+at the Corporation for National Research Initiatives (CNRI) in Reston,
+Virginia where he released several versions of the software. Python
+1.6 was the last of the versions released by CNRI. In 2000, Guido and
+the Python core development team moved to BeOpen.com to form the
+BeOpen PythonLabs team. Python 2.0 was the first and only release
+from BeOpen.com.
+
+Following the release of Python 1.6, and after Guido van Rossum left
+CNRI to work with commercial software developers, it became clear that
+the ability to use Python with software available under the GNU Public
+License (GPL) was very desirable. CNRI and the Free Software
+Foundation (FSF) interacted to develop enabling wording changes to the
+Python license. Python 1.6.1 is essentially the same as Python 1.6,
+with a few minor bug fixes, and with a different license that enables
+later versions to be GPL-compatible. Python 2.1 is a derivative work
+of Python 1.6.1, as well as of Python 2.0.
+
+After Python 2.0 was released by BeOpen.com, Guido van Rossum and the
+other PythonLabs developers joined Digital Creations. All
+intellectual property added from this point on, starting with Python
+2.1 and its alpha and beta releases, is owned by the Python Software
+Foundation (PSF), a non-profit modeled after the Apache Software
+Foundation. See http://www.python.org/psf/ for more information about
+the PSF.
+
+Thanks to the many outside volunteers who have worked under Guido's
+direction to make these releases possible.
+
+
+B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON
+===============================================================
+
+PSF LICENSE AGREEMENT
+---------------------
+
+1. This LICENSE AGREEMENT is between the Python Software Foundation
+("PSF"), and the Individual or Organization ("Licensee") accessing and
+otherwise using Python 2.1.1 software in source or binary form and its
+associated documentation.
+
+2. Subject to the terms and conditions of this License Agreement, PSF
+hereby grants Licensee a nonexclusive, royalty-free, world-wide
+license to reproduce, analyze, test, perform and/or display publicly,
+prepare derivative works, distribute, and otherwise use Python 2.1.1
+alone or in any derivative version, provided, however, that PSF's
+License Agreement and PSF's notice of copyright, i.e., "Copyright (c)
+2001 Python Software Foundation; All Rights Reserved" are retained in
+Python 2.1.1 alone or in any derivative version prepared by Licensee.
+
+3. In the event Licensee prepares a derivative work that is based on
+or incorporates Python 2.1.1 or any part thereof, and wants to make
+the derivative work available to others as provided herein, then
+Licensee hereby agrees to include in any such work a brief summary of
+the changes made to Python 2.1.1.
+
+4. PSF is making Python 2.1.1 available to Licensee on an "AS IS"
+basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
+DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
+FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 2.1.1 WILL NOT
+INFRINGE ANY THIRD PARTY RIGHTS.
+
+5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
+2.1.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
+A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 2.1.1,
+OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+6. This License Agreement will automatically terminate upon a material
+breach of its terms and conditions.
+
+7. Nothing in this License Agreement shall be deemed to create any
+relationship of agency, partnership, or joint venture between PSF and
+Licensee. This License Agreement does not grant permission to use PSF
+trademarks or trade name in a trademark sense to endorse or promote
+products or services of Licensee, or any third party.
+
+8. By copying, installing or otherwise using Python 2.1.1, Licensee
+agrees to be bound by the terms and conditions of this License
+Agreement.
+
+
+BEOPEN.COM TERMS AND CONDITIONS FOR PYTHON 2.0
+----------------------------------------------
+
+BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1
+
+1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an
+office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the
+Individual or Organization ("Licensee") accessing and otherwise using
+this software in source or binary form and its associated
+documentation ("the Software").
+
+2. Subject to the terms and conditions of this BeOpen Python License
+Agreement, BeOpen hereby grants Licensee a non-exclusive,
+royalty-free, world-wide license to reproduce, analyze, test, perform
+and/or display publicly, prepare derivative works, distribute, and
+otherwise use the Software alone or in any derivative version,
+provided, however, that the BeOpen Python License is retained in the
+Software, alone or in any derivative version prepared by Licensee.
+
+3. BeOpen is making the Software available to Licensee on an "AS IS"
+basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND
+DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
+FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT
+INFRINGE ANY THIRD PARTY RIGHTS.
+
+4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE
+SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS
+AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY
+DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+5. This License Agreement will automatically terminate upon a material
+breach of its terms and conditions.
+
+6. This License Agreement shall be governed by and interpreted in all
+respects by the law of the State of California, excluding conflict of
+law provisions. Nothing in this License Agreement shall be deemed to
+create any relationship of agency, partnership, or joint venture
+between BeOpen and Licensee. This License Agreement does not grant
+permission to use BeOpen trademarks or trade names in a trademark
+sense to endorse or promote products or services of Licensee, or any
+third party. As an exception, the "BeOpen Python" logos available at
+http://www.pythonlabs.com/logos.html may be used according to the
+permissions granted on that web page.
+
+7. By copying, installing or otherwise using the software, Licensee
+agrees to be bound by the terms and conditions of this License
+Agreement.
+
+
+CNRI OPEN SOURCE GPL-COMPATIBLE LICENSE AGREEMENT
+-------------------------------------------------
+
+1. This LICENSE AGREEMENT is between the Corporation for National
+Research Initiatives, having an office at 1895 Preston White Drive,
+Reston, VA 20191 ("CNRI"), and the Individual or Organization
+("Licensee") accessing and otherwise using Python 1.6.1 software in
+source or binary form and its associated documentation.
+
+2. Subject to the terms and conditions of this License Agreement, CNRI
+hereby grants Licensee a nonexclusive, royalty-free, world-wide
+license to reproduce, analyze, test, perform and/or display publicly,
+prepare derivative works, distribute, and otherwise use Python 1.6.1
+alone or in any derivative version, provided, however, that CNRI's
+License Agreement and CNRI's notice of copyright, i.e., "Copyright (c)
+1995-2001 Corporation for National Research Initiatives; All Rights
+Reserved" are retained in Python 1.6.1 alone or in any derivative
+version prepared by Licensee. Alternately, in lieu of CNRI's License
+Agreement, Licensee may substitute the following text (omitting the
+quotes): "Python 1.6.1 is made available subject to the terms and
+conditions in CNRI's License Agreement. This Agreement together with
+Python 1.6.1 may be located on the Internet using the following
+unique, persistent identifier (known as a handle): 1895.22/1013. This
+Agreement may also be obtained from a proxy server on the Internet
+using the following URL: http://hdl.handle.net/1895.22/1013".
+
+3. In the event Licensee prepares a derivative work that is based on
+or incorporates Python 1.6.1 or any part thereof, and wants to make
+the derivative work available to others as provided herein, then
+Licensee hereby agrees to include in any such work a brief summary of
+the changes made to Python 1.6.1.
+
+4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS"
+basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND
+DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
+FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT
+INFRINGE ANY THIRD PARTY RIGHTS.
+
+5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
+1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
+A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1,
+OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+6. This License Agreement will automatically terminate upon a material
+breach of its terms and conditions.
+
+7. This License Agreement shall be governed by the federal
+intellectual property law of the United States, including without
+limitation the federal copyright law, and, to the extent such
+U.S. federal law does not apply, by the law of the Commonwealth of
+Virginia, excluding Virginia's conflict of law provisions.
+Notwithstanding the foregoing, with regard to derivative works based
+on Python 1.6.1 that incorporate non-separable material that was
+previously distributed under the GNU General Public License (GPL), the
+law of the Commonwealth of Virginia shall govern this License
+Agreement only as to issues arising under or with respect to
+Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this
+License Agreement shall be deemed to create any relationship of
+agency, partnership, or joint venture between CNRI and Licensee. This
+License Agreement does not grant permission to use CNRI trademarks or
+trade name in a trademark sense to endorse or promote products or
+services of Licensee, or any third party.
+
+8. By clicking on the "ACCEPT" button where indicated, or by copying,
+installing or otherwise using Python 1.6.1, Licensee agrees to be
+bound by the terms and conditions of this License Agreement.
+
+ ACCEPT
+
+
+CWI PERMISSIONS STATEMENT AND DISCLAIMER
+----------------------------------------
+
+Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam,
+The Netherlands. All rights reserved.
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of Stichting Mathematisch
+Centrum or CWI not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
+FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/help/diveintopython-5.4/py/apihelper.py b/help/diveintopython-5.4/py/apihelper.py
new file mode 100644
index 0000000..b8cc3e5
--- /dev/null
+++ b/help/diveintopython-5.4/py/apihelper.py
@@ -0,0 +1,47 @@
+"""Cheap and simple API helper
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.3 $"
+__date__ = "$Date: 2004/05/05 21:57:19 $"
+__copyright__ = "Copyright (c) 2001 Mark Pilgrim"
+__license__ = "Python"
+
+# While this is a good example script to teach about introspection,
+# in real life it has been superceded by PyDoc, which is part of the
+# standard library in Python 2.1 and later.
+#
+# Your IDE may already import the "help" function from pydoc
+# automatically on startup; if not, do this:
+#
+# >>> from pydoc import help
+#
+# The help function in this module takes the object itself to get
+# help on, but PyDoc can also take a string, like this:
+#
+# >>> help("string") # gets help on the string module
+# >>> help("apihelper.help") # gets help on the function below
+# >>> help() # enters an interactive help mode
+#
+# PyDoc can also act as an HTTP server to dynamically produce
+# HTML-formatted documentation of any module in your path.
+# That's wicked cool. Read more about PyDoc here:
+# http://www.onlamp.com/pub/a/python/2001/04/18/pydoc.html
+
+def info(object, spacing=10, collapse=1):
+ """Print methods and doc strings.
+
+ Takes module, class, list, dictionary, or string."""
+ methodList = [e for e in dir(object) if callable(getattr(object, e))]
+ processFunc = collapse and (lambda s: " ".join(s.split())) or (lambda s: s)
+ print "\n".join(["%s %s" %
+ (method.ljust(spacing),
+ processFunc(str(getattr(object, method).__doc__)))
+ for method in methodList])
+
+if __name__ == "__main__":
+ print help.__doc__
diff --git a/help/diveintopython-5.4/py/apihelpertest.py b/help/diveintopython-5.4/py/apihelpertest.py
new file mode 100644
index 0000000..39edebd
--- /dev/null
+++ b/help/diveintopython-5.4/py/apihelpertest.py
@@ -0,0 +1,62 @@
+"""Unit test for apihelper.py
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.4 $"
+__date__ = "$Date: 2004/05/05 21:57:19 $"
+__copyright__ = "Copyright (c) 2001 Mark Pilgrim"
+__license__ = "Python"
+
+import unittest
+import apihelper
+import sys
+from StringIO import StringIO
+
+class Redirector(unittest.TestCase):
+ def setUp(self):
+ self.savestdout = sys.stdout
+ self.redirect = StringIO()
+ sys.stdout = self.redirect
+
+ def tearDown(self):
+ sys.stdout = self.savestdout
+
+class KnownValues(Redirector):
+ def testApiHelper(self):
+ """info should return known result for apihelper"""
+ apihelper.info(apihelper)
+ self.redirect.seek(0)
+ self.assertEqual(self.redirect.read(),
+"""info Print methods and doc strings. Takes module, class, list, dictionary, or string.
+""")
+
+class ParamChecks(Redirector):
+ def testSpacing(self):
+ """info should honor spacing argument"""
+ apihelper.info(apihelper, spacing=20)
+ self.redirect.seek(0)
+ self.assertEqual(self.redirect.read(),
+"""info Print methods and doc strings. Takes module, class, list, dictionary, or string.
+""")
+
+ def testCollapse(self):
+ """info should honor collapse argument"""
+ apihelper.info(apihelper, collapse=0)
+ self.redirect.seek(0)
+ self.assertEqual(self.redirect.read(),
+"""info Print methods and doc strings.
+
+ Takes module, class, list, dictionary, or string.
+""")
+
+class BadInput(unittest.TestCase):
+ def testNoObject(self):
+ """info should fail with no object"""
+ self.assertRaises(TypeError, apihelper.info, spacing=20)
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/help/diveintopython-5.4/py/argecho.py b/help/diveintopython-5.4/py/argecho.py
new file mode 100644
index 0000000..362da00
--- /dev/null
+++ b/help/diveintopython-5.4/py/argecho.py
@@ -0,0 +1,17 @@
+"""Echo command line arguments
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.2 $"
+__date__ = "$Date: 2004/05/05 21:57:19 $"
+__copyright__ = "Copyright (c) 2002 Mark Pilgrim"
+__license__ = "Python"
+
+import sys
+
+for arg in sys.argv:
+ print arg
diff --git a/help/diveintopython-5.4/py/autosize.py b/help/diveintopython-5.4/py/autosize.py
new file mode 100644
index 0000000..33011db
--- /dev/null
+++ b/help/diveintopython-5.4/py/autosize.py
@@ -0,0 +1,83 @@
+"""
+Add size of all downloadable archives as title attribute of download link
+
+This script is used during the build process of "Dive Into Python"
+(http://diveintopython.org/) to add size descriptions to all download links
+on the home page. Requires that the links be relative paths from the current
+working directory. Also requires that the download links already have some
+title already; download size is appended to the existing title.
+
+Looks for two arguments on the command line. First: if a file, the file is
+processed. If a directory, all .html files in the directory are processed.
+Second: directory of files to use for sizing information.
+If no arguments given, a test suite is performed on a hard-coded test file
+which saves the output to a temporary file and opens it in a web browser locally.
+
+Not safe to run on the same file(s) more than once, since the size information
+is simply concatenated to the existing title.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.2 $"
+__date__ = "$Date: 2004/05/05 21:57:19 $"
+__copyright__ = "Copyright (c) 2001 Mark Pilgrim"
+__license__ = "Python"
+
+import sys
+import os
+import stat
+import urlparse
+from BaseHTMLProcessor import BaseHTMLProcessor
+
+class AutosizeParser(BaseHTMLProcessor):
+ def __init__(self, basedir):
+ BaseHTMLProcessor.__init__(self)
+ self.basedir = basedir
+
+ def start_a(self, attrs):
+ try:
+ href = [e[1] for e in attrs if e[0]=='href'][0]
+ title = [e[1] for e in attrs if e[0]=='title'][0]
+ except IndexError:
+ pass
+ else:
+ filename = os.path.split(urlparse.urlparse(href)[2])[1]
+ if os.path.splitext(filename)[1] in ('.zip', '.tgz', '.hqx'):
+ zipfile = os.path.join(self.basedir, filename)
+ title += " (%d KB)" % ((os.stat(zipfile)[stat.ST_SIZE] + 1023)/1024,)
+ attrs = tuple([e for e in attrs if e[0]<>'title'] + [('title', title)])
+ self.unknown_starttag("a", attrs)
+
+def process(filename, basedir, outfile=None):
+ if not outfile:
+ outfile = filename
+ sock = open(filename, "r")
+ parser = AutosizeParser(basedir)
+ parser.feed(sock.read())
+ output = parser.output()
+ sock.close()
+ sock = open(outfile, "w")
+ sock.write(output)
+ sock.close()
+ return output
+
+def test(filename, basedir, outfile="c:\\out.html"):
+ output = process(filename, basedir, outfile)
+ print output
+ import webbrowser
+ webbrowser.open(outfile)
+
+if __name__ == "__main__":
+ if sys.argv[1:]:
+ filedir = sys.argv[1]
+ basedir = sys.argv[2]
+ if os.path.isdir(filedir):
+ for f in [os.path.join(filedir, s) for s in os.listdir(filedir) if os.path.splitext(s)[1].lower() == '.html']:
+## print "Autosizing %s" % os.path.basename(f)
+ process(f, basedir)
+ else:
+## print "Autosizing %s" % os.path.basename(filedir)
+ process(filedir, basedir)
+ else:
+ test("c:\\docbook\\dip\\dist\\html\\index.html", "c:\\docbook\\dip\\dist\\download\\")
+
diff --git a/help/diveintopython-5.4/py/builddialectexamples.py b/help/diveintopython-5.4/py/builddialectexamples.py
new file mode 100644
index 0000000..7d4762f
--- /dev/null
+++ b/help/diveintopython-5.4/py/builddialectexamples.py
@@ -0,0 +1,32 @@
+"""Build examples of output of dialect module
+
+This script is used during the build process of "Dive Into Python"
+(http://diveintopython.org/) to create examples of the output of the
+code in chapter 4 (dialect.py and BaseHTMLProcessor.py).
+
+It takes one argument, the source HTML file to translate. It outputs
+chef.html, fudd.html, and olde.html in the same directory as the source.
+
+Safe to run more than once. Output files are silently overridden if
+they already exist.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.2 $"
+__date__ = "$Date: 2004/05/05 21:57:19 $"
+__copyright__ = "Copyright (c) 2001 Mark Pilgrim"
+__license__ = "Python"
+
+import dialect
+import sys, os
+
+def translateAndWrite(filename, dialectname):
+ targetfilename = os.path.join(os.path.split(filename)[0], "%s.html" % dialectname)
+ fsock = open(targetfilename, "wb")
+ fsock.write(dialect.translate(filename, dialectname))
+ fsock.close()
+
+if __name__ == "__main__":
+ filename = sys.argv[1]
+ for dialectname in ("chef", "fudd", "olde"):
+ translateAndWrite(filename, dialectname)
diff --git a/help/diveintopython-5.4/py/colorize.py b/help/diveintopython-5.4/py/colorize.py
new file mode 100644
index 0000000..e2a3cc3
--- /dev/null
+++ b/help/diveintopython-5.4/py/colorize.py
@@ -0,0 +1,142 @@
+"""
+Colorize Python program listings embedded in HTML pages
+
+This script is used during the build process of "Dive Into Python"
+(http://diveintopython.org/) to recreate syntax highlighting of the Python
+program listings and code examples embedded in the HTML pages by wrapping
+Python keywords in <span> or <font> tags. The following
+tags are presumed to contain Python code:
+ <pre class="programlisting">...</pre>
+ <span class="userinput">...</span>
+(These tags are generated automatically by the DocBook XSL stylesheets when
+the book is transformed from XML to HTML.)
+
+Looks for 2 arguments on the command line. The first argument is a file or directory.
+If a file, the file is processed; if a directory, all .html files in the directory
+are processed.
+
+The second argument, if given, is a flag for the type of tags to wrap around
+keywords.
+ 0 (default) - use <span class="xxx"> tags, where xxx in
+ ('comment', 'string', 'keyword', 'function', 'class'). Actual
+ syntax highlighting must be defined in a <style> definition
+ elsewhere in the document, or in an external style sheet.
+ 1 - use <font> tags. See ColorizeParser.fontDataMap for the color values.
+
+If no arguments are given, a test suite is performed on a hard-coded test file
+which saves the output to a temporary file and opens it in a web browser locally.
+
+Not safe to run on the same file(s) more than once, since it does not check for
+existing <span> or <font> tags in the program listings.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.3 $"
+__date__ = "$Date: 2004/05/05 21:57:19 $"
+__copyright__ = "Copyright (c) 2001 Mark Pilgrim"
+__license__ = "Python"
+
+import sys
+import os
+from BaseHTMLProcessor import BaseHTMLProcessor
+import pyfontify
+
+class ColorizeParser(BaseHTMLProcessor):
+ fontDataMap = {"comment":("<font color='green'><i>", "</i></font>"),
+ "string":("<font color='olive'>", "</font>"),
+ "keyword":("<font color='navy'><b>", "</b></font>"),
+ "function":("<font color='teal'><b>", "</b></font>"),
+ "class":("<font color='blue'><b>", "</b></font>")}
+
+ def __init__(self, usefonts=0):
+ BaseHTMLProcessor.__init__(self)
+ self.usefonts = usefonts
+
+ def reset(self):
+ BaseHTMLProcessor.reset(self)
+ self.colorindex = 0
+ self.needcolor = 0
+
+ def HTMLfontify(self, text):
+ fontmap = pyfontify.fontify(text)
+ fontmap.reverse()
+ for token, start, end, dummy in fontmap:
+ if self.usefonts:
+ text = "%s%s%s%s%s" % (text[:start], self.fontDataMap[token][0], text[start:end], \
+ self.fontDataMap[token][1], text[end:])
+ else:
+ text = "%s<span class='py%s'>%s</span>%s" % (text[:start], token, text[start:end], text[end:])
+ return text
+
+ def flushcolor(self):
+ if self.colorindex:
+ buffer = "".join(self.pieces[self.colorindex:])
+ self.pieces = self.pieces[:self.colorindex]
+ self.colorindex = 0
+ BaseHTMLProcessor.handle_data(self, self.HTMLfontify(buffer))
+
+ def unknown_starttag(self, tag, attrs):
+ self.flushcolor()
+ BaseHTMLProcessor.unknown_starttag(self, tag, attrs)
+ if self.needcolor:
+ self.colorindex = len(self.pieces)
+
+ def unknown_endtag(self, tag):
+ self.flushcolor()
+ BaseHTMLProcessor.unknown_endtag(self, tag)
+ if self.needcolor:
+ self.colorindex = len(self.pieces)
+
+ def start_pre(self, attrs):
+ self.unknown_starttag("pre", attrs)
+ if ("class", "programlisting") in attrs:
+ self.needcolor = 1
+ self.colorindex = len(self.pieces)
+
+ def end_pre(self):
+ self.needcolor = 0
+ self.unknown_endtag("pre")
+
+ def start_span(self, attrs):
+ self.unknown_starttag("span", attrs)
+ if ("class", "userinput") in attrs:
+ self.needcolor = 1
+ self.colorindex = len(self.pieces)
+
+ def end_span(self):
+ self.needcolor = 0
+ self.unknown_endtag("span")
+
+def process(filename, usefonts=0, outfile=None):
+ if not outfile:
+ outfile = filename
+ sock = open(filename, "r")
+ parser = ColorizeParser(usefonts)
+ parser.feed(sock.read())
+ output = parser.output()
+ sock.close()
+ sock = open(outfile, "w")
+ sock.write(output)
+ sock.close()
+ return output
+
+def test(filename, usefonts=0, outfile="c:\\out.html"):
+ output = process(filename, usefonts, outfile)
+## print output
+ import webbrowser
+ webbrowser.open(outfile)
+
+if __name__ == "__main__":
+ if sys.argv[1:]:
+ filedir = sys.argv[1]
+ usefonts = sys.argv[2:] and sys.argv[2] or 0
+ if os.path.isdir(filedir):
+ import glob
+ for f in glob.glob(os.path.join(filedir, '**', '*.html')):
+ print "Colorizing %s" % os.path.basename(f)
+ process(f, usefonts)
+ else:
+ print "Colorizing %s" % os.path.basename(filedir)
+ process(filedir, usefonts)
+ else:
+ print 'usage: colorize.py directory-or-file'
diff --git a/help/diveintopython-5.4/py/dialect.py b/help/diveintopython-5.4/py/dialect.py
new file mode 100644
index 0000000..7026fb8
--- /dev/null
+++ b/help/diveintopython-5.4/py/dialect.py
@@ -0,0 +1,166 @@
+"""Dialectizer for Python
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.2 $"
+__date__ = "$Date: 2004/05/05 21:57:19 $"
+__copyright__ = "Copyright (c) 2001 Mark Pilgrim"
+__license__ = "Python"
+
+import re
+from BaseHTMLProcessor import BaseHTMLProcessor
+
+class Dialectizer(BaseHTMLProcessor):
+ subs = ()
+
+ def reset(self):
+ # extend (called from __init__ in ancestor)
+ # Reset all data attributes
+ self.verbatim = 0
+ BaseHTMLProcessor.reset(self)
+
+ def start_pre(self, attrs):
+ # called for every <pre> tag in HTML source
+ # Increment verbatim mode count, then handle tag like normal
+ self.verbatim += 1
+ self.unknown_starttag("pre", attrs)
+
+ def end_pre(self):
+ # called for every </pre> tag in HTML source
+ # Decrement verbatim mode count
+ self.unknown_endtag("pre")
+ self.verbatim -= 1
+
+ def handle_data(self, text):
+ # override
+ # called for every block of text in HTML source
+ # If in verbatim mode, save text unaltered;
+ # otherwise process the text with a series of substitutions
+ self.pieces.append(self.verbatim and text or self.process(text))
+
+ def process(self, text):
+ # called from handle_data
+ # Process text block by performing series of regular expression
+ # substitutions (actual substitions are defined in descendant)
+ for fromPattern, toPattern in self.subs:
+ text = re.sub(fromPattern, toPattern, text)
+ return text
+
+class ChefDialectizer(Dialectizer):
+ """convert HTML to Swedish Chef-speak
+
+ based on the classic chef.x, copyright (c) 1992, 1993 John Hagerman
+ """
+ subs = ((r'a([nu])', r'u\1'),
+ (r'A([nu])', r'U\1'),
+ (r'a\B', r'e'),
+ (r'A\B', r'E'),
+ (r'en\b', r'ee'),
+ (r'\Bew', r'oo'),
+ (r'\Be\b', r'e-a'),
+ (r'\be', r'i'),
+ (r'\bE', r'I'),
+ (r'\Bf', r'ff'),
+ (r'\Bir', r'ur'),
+ (r'(\w*?)i(\w*?)$', r'\1ee\2'),
+ (r'\bow', r'oo'),
+ (r'\bo', r'oo'),
+ (r'\bO', r'Oo'),
+ (r'the', r'zee'),
+ (r'The', r'Zee'),
+ (r'th\b', r't'),
+ (r'\Btion', r'shun'),
+ (r'\Bu', r'oo'),
+ (r'\BU', r'Oo'),
+ (r'v', r'f'),
+ (r'V', r'F'),
+ (r'w', r'w'),
+ (r'W', r'W'),
+ (r'([a-z])[.]', r'\1. Bork Bork Bork!'))
+
+class FuddDialectizer(Dialectizer):
+ """convert HTML to Elmer Fudd-speak"""
+ subs = ((r'[rl]', r'w'),
+ (r'qu', r'qw'),
+ (r'th\b', r'f'),
+ (r'th', r'd'),
+ (r'n[.]', r'n, uh-hah-hah-hah.'))
+
+class OldeDialectizer(Dialectizer):
+ """convert HTML to mock Middle English"""
+ subs = ((r'i([bcdfghjklmnpqrstvwxyz])e\b', r'y\1'),
+ (r'i([bcdfghjklmnpqrstvwxyz])e', r'y\1\1e'),
+ (r'ick\b', r'yk'),
+ (r'ia([bcdfghjklmnpqrstvwxyz])', r'e\1e'),
+ (r'e[ea]([bcdfghjklmnpqrstvwxyz])', r'e\1e'),
+ (r'([bcdfghjklmnpqrstvwxyz])y', r'\1ee'),
+ (r'([bcdfghjklmnpqrstvwxyz])er', r'\1re'),
+ (r'([aeiou])re\b', r'\1r'),
+ (r'ia([bcdfghjklmnpqrstvwxyz])', r'i\1e'),
+ (r'tion\b', r'cioun'),
+ (r'ion\b', r'ioun'),
+ (r'aid', r'ayde'),
+ (r'ai', r'ey'),
+ (r'ay\b', r'y'),
+ (r'ay', r'ey'),
+ (r'ant', r'aunt'),
+ (r'ea', r'ee'),
+ (r'oa', r'oo'),
+ (r'ue', r'e'),
+ (r'oe', r'o'),
+ (r'ou', r'ow'),
+ (r'ow', r'ou'),
+ (r'\bhe', r'hi'),
+ (r've\b', r'veth'),
+ (r'se\b', r'e'),
+ (r"'s\b", r'es'),
+ (r'ic\b', r'ick'),
+ (r'ics\b', r'icc'),
+ (r'ical\b', r'ick'),
+ (r'tle\b', r'til'),
+ (r'll\b', r'l'),
+ (r'ould\b', r'olde'),
+ (r'own\b', r'oune'),
+ (r'un\b', r'onne'),
+ (r'rry\b', r'rye'),
+ (r'est\b', r'este'),
+ (r'pt\b', r'pte'),
+ (r'th\b', r'the'),
+ (r'ch\b', r'che'),
+ (r'ss\b', r'sse'),
+ (r'([wybdp])\b', r'\1e'),
+ (r'([rnt])\b', r'\1\1e'),
+ (r'from', r'fro'),
+ (r'when', r'whan'))
+
+def translate(url, dialectName="chef"):
+ """fetch URL and translate using dialect
+
+ dialect in ("chef", "fudd", "olde")"""
+ import urllib
+ sock = urllib.urlopen(url)
+ htmlSource = sock.read()
+ sock.close()
+ parserName = "%sDialectizer" % dialectName.capitalize()
+ parserClass = globals()[parserName]
+ parser = parserClass()
+ parser.feed(htmlSource)
+ parser.close()
+ return parser.output()
+
+def test(url):
+ """test all dialects against URL"""
+ for dialect in ("chef", "fudd", "olde"):
+ outfile = "%s.html" % dialect
+ fsock = open(outfile, "wb")
+ fsock.write(translate(url, dialect))
+ fsock.close()
+ import webbrowser
+ webbrowser.open_new(outfile)
+
+if __name__ == "__main__":
+ test("http://diveintopython.org/odbchelper_list.html")
diff --git a/help/diveintopython-5.4/py/fibonacci.py b/help/diveintopython-5.4/py/fibonacci.py
new file mode 100644
index 0000000..b9b7ae3
--- /dev/null
+++ b/help/diveintopython-5.4/py/fibonacci.py
@@ -0,0 +1,21 @@
+"""Fibonacci sequences using generators
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.2 $"
+__date__ = "$Date: 2004/05/05 21:57:19 $"
+__copyright__ = "Copyright (c) 2004 Mark Pilgrim"
+__license__ = "Python"
+
+def fibonacci(max):
+ a, b = 0, 1
+ while a < max:
+ yield a
+ a, b = b, a+b
+
+for n in fibonacci(1000):
+ print n,
diff --git a/help/diveintopython-5.4/py/fileinfo.py b/help/diveintopython-5.4/py/fileinfo.py
new file mode 100644
index 0000000..0f8ac6b
--- /dev/null
+++ b/help/diveintopython-5.4/py/fileinfo.py
@@ -0,0 +1,86 @@
+"""Framework for getting filetype-specific metadata.
+
+Instantiate appropriate class with filename. Returned object acts like a
+dictionary, with key-value pairs for each piece of metadata.
+ import fileinfo
+ info = fileinfo.MP3FileInfo("/music/ap/mahadeva.mp3")
+ print "\\n".join(["%s=%s" % (k, v) for k, v in info.items()])
+
+Or use listDirectory function to get info on all files in a directory.
+ for info in fileinfo.listDirectory("/music/ap/", [".mp3"]):
+ ...
+
+Framework can be extended by adding classes for particular file types, e.g.
+HTMLFileInfo, MPGFileInfo, DOCFileInfo. Each class is completely responsible for
+parsing its files appropriately; see MP3FileInfo for example.
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.3 $"
+__date__ = "$Date: 2004/05/05 21:57:19 $"
+__copyright__ = "Copyright (c) 2001 Mark Pilgrim"
+__license__ = "Python"
+
+import os
+import sys
+from UserDict import UserDict
+
+def stripnulls(data):
+ "strip whitespace and nulls"
+ return data.replace("\00", " ").strip()
+
+class FileInfo(UserDict):
+ "store file metadata"
+ def __init__(self, filename=None):
+ UserDict.__init__(self)
+ self["name"] = filename
+
+class MP3FileInfo(FileInfo):
+ "store ID3v1.0 MP3 tags"
+ tagDataMap = {"title" : ( 3, 33, stripnulls),
+ "artist" : ( 33, 63, stripnulls),
+ "album" : ( 63, 93, stripnulls),
+ "year" : ( 93, 97, stripnulls),
+ "comment" : ( 97, 126, stripnulls),
+ "genre" : (127, 128, ord)}
+
+ def __parse(self, filename):
+ "parse ID3v1.0 tags from MP3 file"
+ self.clear()
+ try:
+ fsock = open(filename, "rb", 0)
+ try:
+ fsock.seek(-128, 2)
+ tagdata = fsock.read(128)
+ finally:
+ fsock.close()
+ if tagdata[:3] == 'TAG':
+ for tag, (start, end, parseFunc) in self.tagDataMap.items():
+ self[tag] = parseFunc(tagdata[start:end])
+ except IOError:
+ pass
+
+ def __setitem__(self, key, item):
+ if key == "name" and item:
+ self.__parse(item)
+ FileInfo.__setitem__(self, key, item)
+
+def listDirectory(directory, fileExtList):
+ "get list of file info objects for files of particular extensions"
+ fileList = [os.path.normcase(f) for f in os.listdir(directory)]
+ fileList = [os.path.join(directory, f) for f in fileList \
+ if os.path.splitext(f)[1] in fileExtList]
+ def getFileInfoClass(filename, module=sys.modules[FileInfo.__module__]):
+ "get file info class from filename extension"
+ subclass = "%sFileInfo" % os.path.splitext(filename)[1].upper()[1:]
+ return hasattr(module, subclass) and getattr(module, subclass) or FileInfo
+ return [getFileInfoClass(f)(f) for f in fileList]
+
+if __name__ == "__main__":
+ for info in listDirectory("/music/_singles/", [".mp3"]):
+ print "\n".join(["%s=%s" % (k, v) for k, v in info.items()])
+ print
diff --git a/help/diveintopython-5.4/py/fileinfo_fromdict.py b/help/diveintopython-5.4/py/fileinfo_fromdict.py
new file mode 100644
index 0000000..19ea22a
--- /dev/null
+++ b/help/diveintopython-5.4/py/fileinfo_fromdict.py
@@ -0,0 +1,75 @@
+"""Framework for getting filetype-specific metadata.
+
+This is the same as fileinfo.py with one difference:
+instead of inheriting from UserDict, we inherit directly from dict.
+This capability was introduced in Python 2.2, and makes UserDict
+unnecessary (along with its cousins, UserList and UserString).
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.2 $"
+__date__ = "$Date: 2004/05/05 21:57:19 $"
+__copyright__ = "Copyright (c) 2001 Mark Pilgrim"
+__license__ = "Python"
+
+import os
+import sys
+
+def stripnulls(data):
+ "strip whitespace and nulls"
+ return data.replace("\00", " ").strip()
+
+class FileInfo(dict):
+ "store file metadata"
+ def __init__(self, filename=None):
+ self["name"] = filename
+
+class MP3FileInfo(FileInfo):
+ "store ID3v1.0 MP3 tags"
+ tagDataMap = {"title" : ( 3, 33, stripnulls),
+ "artist" : ( 33, 63, stripnulls),
+ "album" : ( 63, 93, stripnulls),
+ "year" : ( 93, 97, stripnulls),
+ "comment" : ( 97, 126, stripnulls),
+ "genre" : (127, 128, ord)}
+
+ def __parse(self, filename):
+ "parse ID3v1.0 tags from MP3 file"
+ self.clear()
+ try:
+ fsock = open(filename, "rb", 0)
+ try:
+ fsock.seek(-128, 2)
+ tagdata = fsock.read(128)
+ finally:
+ fsock.close()
+ if tagdata[:3] == 'TAG':
+ for tag, (start, end, parseFunc) in self.tagDataMap.items():
+ self[tag] = parseFunc(tagdata[start:end])
+ except IOError:
+ pass
+
+ def __setitem__(self, key, item):
+ if key == "name" and item:
+ self.__parse(item)
+ FileInfo.__setitem__(self, key, item)
+
+def listDirectory(directory, fileExtList):
+ "get list of file info objects for files of particular extensions"
+ fileList = [os.path.normcase(f) for f in os.listdir(directory)]
+ fileList = [os.path.join(directory, f) for f in fileList \
+ if os.path.splitext(f)[1] in fileExtList]
+ def getFileInfoClass(filename, module=sys.modules[FileInfo.__module__]):
+ "get file info class from filename extension"
+ subclass = "%sFileInfo" % os.path.splitext(filename)[1].upper()[1:]
+ return hasattr(module, subclass) and getattr(module, subclass) or FileInfo
+ return [getFileInfoClass(f)(f) for f in fileList]
+
+if __name__ == "__main__":
+ for info in listDirectory("/music/_singles/", [".mp3"]):
+ print "\n".join(["%s=%s" % (k, v) for k, v in info.items()])
+ print
diff --git a/help/diveintopython-5.4/py/fullpath.py b/help/diveintopython-5.4/py/fullpath.py
new file mode 100644
index 0000000..2a44678
--- /dev/null
+++ b/help/diveintopython-5.4/py/fullpath.py
@@ -0,0 +1,6 @@
+import sys, os
+
+print 'sys.argv[0] =', sys.argv[0]
+pathname = os.path.dirname(sys.argv[0])
+print 'path =', pathname
+print 'full path =', os.path.abspath(pathname)
diff --git a/help/diveintopython-5.4/py/kgp/binary.xml b/help/diveintopython-5.4/py/kgp/binary.xml
new file mode 100644
index 0000000..b02ab32
--- /dev/null
+++ b/help/diveintopython-5.4/py/kgp/binary.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<!DOCTYPE grammar PUBLIC "-//diveintopython.org//DTD Kant Generator Pro v1.0//EN" "kgp.dtd">
+<grammar>
+<ref id="bit">
+ <p>0</p>
+ <p>1</p>
+</ref>
+<ref id="byte">
+ <p><xref id="bit"/><xref id="bit"/><xref id="bit"/><xref id="bit"/><xref id="bit"/><xref id="bit"/><xref id="bit"/><xref id="bit"/></p>
+</ref>
+</grammar>
diff --git a/help/diveintopython-5.4/py/kgp/husserl.xml b/help/diveintopython-5.4/py/kgp/husserl.xml
new file mode 100644
index 0000000..02026a1
--- /dev/null
+++ b/help/diveintopython-5.4/py/kgp/husserl.xml
@@ -0,0 +1,178 @@
+<?xml version="1.0"?>
+<!DOCTYPE grammar PUBLIC "-//diveintopython.org//DTD Kant Generator Pro v1.0//EN" "kgp.dtd">
+<grammar>
+<ref id="Ns">
+ <p>the phenomenon</p>
+ <p>an object</p>
+ <p>the cogitatum<p chance="50"> (qua cogitatum)</p></p>
+ <p><p chance="50">transcendental </p>phenomenology</p>
+ <p><choice><p>pure<p chance="50"> and genuine</p></p><p>scientific</p></choice> evidence</p>
+ <p>cognition</p>
+ <p>the ego cogito</p>
+ <p>transcendental subjectivity</p>
+ <p>the transcendental-phenomenological reduction</p>
+ <p>the <p chance="50">phenomenological </p>epoche</p>
+ <p>the Objective world</p>
+ <p>a transcendental grounding of <choice><p><xref id="Ns"/></p><p><xref id="Np"/></p></choice></p>
+ <p>philosophy</p>
+ <p>the stream of <xref id="Np"/></p>
+ <p>what is itself given</p>
+ <p>the repeatable act of grounding<p chance="50"> of <xref id="Np"/></p></p>
+ <p>an infinite horizon of approximations</p>
+ <p>the <xref id="ego.type"/> Ego</p>
+ <p>the fundamental form of this universal synthesis</p>
+ <p>the <p chance="50">all-embracing </p>consciousness of internal time</p>
+ <p>immanent time</p>
+ <p>the task of clarifying <xref id="Np"/></p>
+ <p>the whole of conscious life</p>
+</ref>
+
+<ref id="Np">
+ <p>noetic acts</p>
+ <p>cogitationes</p>
+ <p>noematic descriptions</p>
+ <p><p chance="50">separated </p>modes of consciousness</p>
+ <p>multiplicities of <xref id="Ns"/></p>
+ <p>experiences</p>
+</ref>
+
+<ref id="Vst">
+ <p>denotes a universal primal phenomenon of</p>
+ <p>is only a modality of</p>
+ <p>becomes modalized also in correlation with</p>
+ <p>stands in contrast to the accidental being "for me" of</p>
+ <p>is a clarification of the striving for</p>
+ <p>becomes adjusted to</p>
+</ref>
+
+<ref id="Vpt">
+ <p>exist for us thanks to</p>
+ <p>denote the universal primary phenomena of</p>
+ <p>are only modalities of</p>
+ <p>become modalized also in correlation with</p>
+ <p>stand in contrast to<p chance="50"> the accident being "for me" of</p></p>
+ <p>become adjusted to</p>
+</ref>
+
+<ref id="Vsi">
+ <p>inhibits acceptance of <xref id="Ns"/> as existent</p>
+ <p>is actual</p>
+ <p>does not yet produce for us any abiding being</p>
+ <p>is "in itself"</p>
+ <p>is an infinite idea, related to infinities of harmoniously combinable <xref id="Np"/></p>
+ <p>is an agreement of <xref id="Ns"/> with the judged <xref id="Np"/></p>
+ <p>can be seen as full proof that, in spite of the continual experiencedness of <xref id="Np"/>, a non-being of <xref id="Ns"/> is conceivable</p>
+ <p>needs to be criticized with regard to its validity and range, before it can be used for the purposes of a radical grounding of <xref id="Ns"/></p>
+ <p>is precisely what makes critical decisions about <xref id="Np"/> at all possible</p>
+ <p>is unified synthetically</p>
+ <p>synthetically constitutes all particular <xref id="Np"/> that ever become prominent</p>
+</ref>
+
+<ref id="Vpi">
+ <p>inhibit <p chance="50"><choice><p>my</p><p>our</p></choice> </p>acceptance of <choice><p><xref id="Ns"/></p><p><xref id="Np"/></p></choice> as existent</p>
+ <p>do not yet produce for <choice><p>us</p><p>me</p></choice> any abiding being<p chance="50"> apart from their relation to <choice><p><xref id="Ns"/></p><p><xref id="Np"/></p></choice></p></p>
+ <p>are "in themselves"</p>
+ <p>are infinite ideas, related to infinities of harmoniously combinable <xref id="Np"/><p chance="50"> and <xref id="Np"/></p></p>
+ <p>can be seen as <p chance="50">full </p>proof that, in spite of the continual experiencedness of <xref id="Ns"/>, a non-being of <choice><p><xref id="Ns"/></p><p><xref id="Np"/></p></choice> is <choice><p>conceivable</p><p>possible</p></choice></p>
+ <p>need to be criticized with regard to their validity and range, before they can be used for <p chance="50">the purposes of </p>a radical grounding of <choice><p><xref id="Ns"/></p><p><xref id="Np"/></p></choice></p>
+ <p>are precisely what make critical decisions about <choice><p><xref id="Ns"/></p><p><xref id="Np"/></p></choice> at all possible</p>
+ <p>are unified synthetically</p>
+ <p>synthetically constitute all particular instances of <xref id="Ns"/> that ever become prominent</p>
+</ref>
+
+<ref id="intro.clause">
+ <p>in the natural attitude</p>
+ <p>de facto</p>
+ <p>owing to the instability and ambiguity of <choice><p><xref id="Ns"/></p><p><xref id="Np"/></p></choice></p>
+ <p>by immersing ourselves in such a striving</p>
+ <p>in other words</p>
+ <p>by this preliminary work, here roughly indicated rather than done explicitly</p>
+ <p>where this is still wanting</p>
+ <p>since the form belonging to a systematic order of <choice><p><xref id="Ns"/></p><p><xref id="Np"/></p></choice> is part of this idea</p>
+ <p>in the broadest sense</p>
+ <p>as we have said</p>
+ <p>in the attitude established by transcendental reduction</p>
+ <p>in a maximally broad sense</p>
+ <p>if we maintain this attitude</p>
+ <p>in the broadest Cartesian sense</p>
+</ref>
+
+<ref id="certainty.clause">
+ <p>it is plain that</p>
+ <p>by immersing ourselves meditatively in the general intentions of <choice><p><xref id="Ns"/></p><p><xref id="Np"/></p></choice>, we discover that</p>
+ <p>if we follow up this doubt, it becomes manifest that</p>
+ <p>by virtue of my free epoche with respect to the being of the experienced world, the momentous fact is that</p>
+ <p>yet it must not be overlooked that</p>
+ <p>the fact is that</p>
+ <p>we can be sure that</p>
+ <p>hence it follows without more ado that</p>
+ <p><choice><p><xref id="Ns"/> calls</p><p><xref id="Np"/> call</p></choice> our attention to the fact that</p>
+ <p>we see in advance that</p>
+ <p>the fact is evident<p chance="50">, even apodictically evident,</p> that</p>
+ <p>it becomes evident that</p>
+</ref>
+
+<ref id="throwaway.clause">
+ <p>in an extremely broad sense</p>
+ <p>consequently</p>
+ <p>in respect of this evidence</p>
+ <p>however</p>
+ <p>mediately</p>
+ <p>naturally</p>
+ <p>even with respect to the evidence in which <choice><p><xref id="Ns"/> presents itself</p><p><xref id="Np"/> present themselves</p></choice></p>
+ <p>as a matter of essential necessity</p>
+ <p>perchance</p>
+ <p>when we let our thoughts hasten in this manner</p>
+</ref>
+
+<ref id="how.clause">
+ <p>by conscious conversion into the corresponding <xref id="Np"/></p>
+ <p>by virture of a synthesis in which what is meant coincides and agree with <xref id="Ns"/></p>
+ <p>by a freely actualizable return to <choice><p><xref id="Ns"/></p><p><xref id="Np"/></p></choice></p>
+ <p>by reconciling with <choice><p><xref id="Ns"/></p><p><xref id="Np"/></p></choice></p>
+ <p>by orienting <choice><p><xref id="Ns"/></p><p><xref id="Np"/></p></choice> according to accured insights</p>
+ <p>by the fundamental nature of <choice><p><xref id="Ns"/></p><p><xref id="Np"/></p></choice></p>
+</ref>
+
+<ref id="main.clause">
+ <p><xref id="Ns"/><p chance="50">, <xref id="throwaway.clause"/>,</p> <xref id="Vst"/> <choice><p><xref id="Ns"/></p><p><xref id="Np"/></p></choice><p chance="50">; <xref id="subject.clause"/></p></p>
+ <p><xref id="Ns"/><p chance="50"> (<xref id="intro.clause"/>)</p> <xref id="Vsi"/><p chance="50"> <xref id="how.clause"/></p></p>
+ <p><xref id="Np"/><p chance="50">, <xref id="throwaway.clause"/>,</p> <xref id="Vpt"/><p chance="50">, <xref id="how.clause"/>,</p> <choice><p><xref id="Ns"/></p><p><xref id="Np"/></p></choice></p>
+ <p><xref id="Np"/><p chance="50"> (<xref id="intro.clause"/>)</p> <xref id="Vpi"/><p chance="50">, <xref id="how.clause"/></p><p chance="50">; <xref id="subject.clause"/></p></p>
+</ref>
+
+<ref id="ego.type">
+ <p>reflecting</p>
+ <p>phenomenological</p>
+ <p>transcendental</p>
+ <p>worldly</p>
+</ref>
+
+<ref id="subject.clause">
+ <p><choice><p>I</p><p>we</p></choice> now shift the weight of transcendental evidence of <choice><p><xref id="Ns"/></p><p><xref id="Np"/></p></choice> <p chance="50">(<xref id="intro.clause"/>) </p>from the <p chance="50"><xref id="ego.type"/> </p>ego to <choice><p><xref id="Ns"/></p><p><xref id="Np"/></p></choice></p>
+ <p>we must not let ourselves be frightened by considerations of <xref id="Ns"/> and <xref id="Np"/></p>
+ <p>only in reflection do we "direct" ourselves to <xref id="Ns"/> and to its perceptual directedness to <xref id="Np"/></p>
+ <p>we have not simply lost <xref id="Ns"/> for phenomenology; we retain it<p chance="50">, <xref id="throwaway.clause"/>,</p> <xref id="how.clause"/></p>
+ <p>I have the reflection that <xref id="Ns"/> is given continuously as an objective unity in a multi-form and changeable multiplicity of <xref id="Np"/>, which belong determinately to it</p>
+ <p>I<p chance="50">, the meditating phenomenologist,</p> set myself the all-embracing task of uncovering <choice><p>myself</p><p><choice><p><xref id="Ns"/></p><p><xref id="Np"/></p></choice></p></choice> <xref id="how.clause"/></p>
+</ref>
+
+<ref id="sentence">
+ <p class="sentence"><p chance="50"><xref id="certainty.clause"/> </p><xref id="main.clause"/>.</p>
+ <p class="sentence"><p chance="50"><xref id="certainty.clause"/> </p><xref id="main.clause"/>.</p>
+ <p class="sentence"><p chance="50"><xref id="certainty.clause"/><p chance="50">, <xref id="how.clause"/>,</p> </p><xref id="subject.clause"/>.</p>
+</ref>
+
+<ref id="paragraph">
+ <p> <p chance="50"><xref id="sentence"/> </p><p chance="50"><xref id="sentence"/> </p><p chance="50"><xref id="sentence"/> </p><p chance="50"><xref id="sentence"/> </p><xref id="sentence"/> <xref id="sentence"/> <xref id="sentence"/> <xref id="sentence"/> <xref id="sentence"/>
+</p>
+ <p> <p chance="50"><xref id="sentence"/> </p><p chance="50"><xref id="sentence"/> </p><xref id="sentence"/> <xref id="sentence"/> <xref id="sentence"/> <xref id="sentence"/> <xref id="sentence"/>
+</p>
+ <p> <p chance="50"><xref id="sentence"/> </p><p chance="50"><xref id="sentence"/> </p><p chance="50"><xref id="sentence"/> </p><p chance="50"><xref id="sentence"/> </p><xref id="sentence"/> <xref id="sentence"/> <xref id="sentence"/> <xref id="sentence"/>
+</p>
+</ref>
+
+<ref id="section">
+ <p><xref id="paragraph"/><xref id="paragraph"/><xref id="paragraph"/><xref id="paragraph"/><p chance="50"><xref id="paragraph"/></p><p chance="50"><xref id="paragraph"/></p><p chance="50"><xref id="paragraph"/></p><p chance="50"><xref id="paragraph"/></p><p chance="50"><xref id="paragraph"/></p><p chance="50"><xref id="paragraph"/></p></p>
+</ref>
+</grammar>
diff --git a/help/diveintopython-5.4/py/kgp/kant.xml b/help/diveintopython-5.4/py/kgp/kant.xml
new file mode 100644
index 0000000..9598c33
--- /dev/null
+++ b/help/diveintopython-5.4/py/kgp/kant.xml
@@ -0,0 +1,306 @@
+<?xml version="1.0"?>
+<!DOCTYPE grammar PUBLIC "-//diveintopython.org//DTD Kant Generator Pro v1.0//EN" "kgp.dtd">
+<grammar>
+<ref id="conjunction">
+ <p>and</p>
+ <p>but</p>
+ <p>yet</p>
+</ref>
+
+<ref id="quantity">
+ <p>all of</p>
+ <p>some of</p>
+ <p>none of</p>
+</ref>
+
+<ref id="logic.type">
+ <p>general</p>
+ <p>applied</p>
+ <p>pure</p>
+ <p>transcendental</p>
+ <p>formal</p>
+</ref>
+
+<ref id="rule.type">
+ <p>universal</p>
+ <p>necessary</p>
+ <p>practical</p>
+ <p>contradictory</p>
+ <p>sufficient</p>
+</ref>
+
+<ref id="judgement.type">
+ <p>hypothetical</p>
+ <p>problematic</p>
+ <p>analytic</p>
+ <p>synthetic</p>
+ <p>ampliative</p>
+ <p>inductive</p>
+ <p>speculative</p>
+ <p>disjunctive</p>
+ <p><xref id="knowledge.type"/></p>
+</ref>
+
+<ref id="knowledge.type">
+ <p>a priori</p>
+ <p>a posteriori</p>
+</ref>
+
+<ref id="reason.type">
+ <p>pure</p>
+ <p>practical</p>
+ <p>human</p>
+ <p>natural</p>
+</ref>
+
+<ref id="object.type">
+ <p>intelligible</p>
+ <p>transcendental</p>
+ <p>empirical</p>
+</ref>
+
+<ref id="philosopher">
+ <p>Aristotle</p>
+ <p>Hume</p>
+ <p>Galileo</p>
+</ref>
+
+<ref id="Ns">
+ <p>the transcendental aesthetic</p>
+ <p><xref id="logic.type"/> logic</p>
+ <p>the Ideal of <xref id="reason.type"/> reason</p>
+ <p>the architectonic of <xref id="reason.type"/> reason</p>
+ <p>the discipline of <xref id="reason.type"/> reason</p>
+ <p>the <p chance="50"><choice><p>pure</p><p>practical</p></choice> </p>employment of <choice><p><xref id="Ns"/></p><p><xref id="Np"/></p></choice></p>
+ <p>the Ideal</p>
+ <p>the manifold</p>
+ <p>the Transcendental Deduction</p>
+ <p>our experience</p>
+ <p>philosophy</p>
+ <p>metaphysics</p>
+ <p>the thing in itself</p>
+ <p>our understanding</p>
+ <p>our <p chance="50"><xref id="knowledge.type"/> </p>knowledge</p>
+ <p><xref id="reason.type"/> reason</p>
+ <p>space</p>
+ <p>time</p>
+ <p>the transcendental unity of apperception</p>
+ <p>necessity</p>
+ <p>the never-ending regress in the series of empirical conditions</p>
+</ref>
+
+<ref id="Np">
+ <p>the Antinomies</p>
+ <p>the paralogisms<p chance="50"> of <xref id="reason.type"/> reason</p></p>
+ <p>the Categories</p>
+ <p>our sense perceptions</p>
+ <p>our faculties</p>
+ <p>our <p chance="50"><xref id="judgement.type"/> </p>judgements</p>
+ <p>the objects in space and time</p>
+ <p>the things in themselves</p>
+ <p>natural causes</p>
+ <p>our ideas</p>
+ <p>our <p chance="50"><xref id="knowledge.type"/> </p>concepts</p>
+ <p>the <p chance="50"><xref id="object.type"/> </p>objects in space and time</p>
+ <p>the noumena</p>
+ <p>the phenomena</p>
+</ref>
+
+<ref id="Vst">
+ <p>is what first gives rise to</p>
+ <p>can thereby determine in its totality</p>
+ <p>has lying before it</p>
+ <p>constitutes the whole content for</p>
+ <p>may not contradict itself, but it is still possible that it may be in contradictions with</p>
+ <p>would thereby be made to contradict</p>
+ <p>teaches us nothing whatsoever regarding the content of</p>
+ <p>can not take account of</p>
+ <p>has nothing to do with</p>
+ <p>stands in need of</p>
+ <p>is the key to understanding</p>
+ <p>proves the validity of</p>
+ <p>is just as necessary as</p>
+ <p>is the clue to the discovery of</p>
+ <p>is a representation of</p>
+ <p>depends on</p>
+ <p>excludes the possibility of</p>
+</ref>
+
+<ref id="Vsi">
+ <p>is the mere result of the power of <xref id="Ns"/>, a blind but indispensable function of the soul</p>
+ <p>occupies part of the sphere of <xref id="Ns"/> concerning the existence of <xref id="Np"/> in general</p>
+ <p>is by its very nature contradictory</p>
+ <p>would be falsified</p>
+ <p>abstracts from all content of <p chance="50"><xref id="knowledge.type"/> </p>knowledge</p>
+ <p>is a body of demonstrated science, and <xref id="quantity"/> it must be known <xref id="knowledge.type"/></p>
+ <p>can never furnish a true and demonstrated science, because, like <xref id="Ns"/>, it <xref id="Vst"/> <xref id="judgement.type"/> principles</p>
+ <p>can be treated like <choice><p><xref id="Ns"/></p><p><xref id="Np"/></p></choice></p>
+ <p>exists in <choice><p><xref id="Ns"/></p><p><xref id="Np"/></p></choice></p>
+</ref>
+
+<ref id="Vpt">
+ <p>are what first give rise to</p>
+ <p>have lying before them</p>
+ <p>constitute the whole content of</p>
+ <p>would thereby be made to contradict</p>
+ <p>can not take account of</p>
+ <p>have nothing to do with</p>
+ <p>stand in need to</p>
+ <p>are the clue to the discovery of</p>
+ <p>prove the validity of</p>
+ <p>are just as necessary as</p>
+ <p>are a representation of</p>
+ <p>exclude the possibility of</p>
+</ref>
+
+<ref id="Vpi">
+ <p>are the mere results of the power of <xref id="Ns"/>, a blind but indispensable function of the soul</p>
+ <p>occupy part of the sphere of <xref id="Ns"/> concerning the existence of <xref id="Np"/> in general</p>
+ <p>are by their very nature contradictory</p>
+ <p>would be falsified</p>
+ <p>abstract from all content of <p chance="50"><xref id="knowledge.type"/> </p>knowledge</p>
+ <p>constitute a body of demonstrated doctrine, and <xref id="quantity"/> this body must be known <xref id="knowledge.type"/></p>
+ <p>can never, as a whole, furnish a true and demonstrated science, because, like <xref id="Ns"/>, they <xref id="Vpt"/> <xref id="judgement.type"/> principles</p>
+ <p>can be treated like <choice><p><xref id="Ns"/></p><p><xref id="Np"/></p></choice></p>
+ <p>should only be used as a canon for <choice><p><xref id="Ns"/></p><p><xref id="Np"/></p></choice></p>
+ <p>exist in <choice><p><xref id="Ns"/></p><p><xref id="Np"/></p></choice></p>
+</ref>
+
+<ref id="intro.clause">
+ <p>in all theoretical sciences</p>
+ <p>in view of these considerations</p>
+ <p>thus</p>
+ <p>by means of <xref id="Ns"/></p>
+ <p>in the study of <xref id="Ns"/></p>
+ <p>therefore</p>
+ <p>with the sole exception of <xref id="Ns"/></p>
+ <p>certainly</p>
+ <p>still</p>
+ <p>as I have elsewhere shown</p>
+ <p>on the other hand</p>
+ <p>for these reasons</p>
+ <p>in the case of <xref id="Ns"/></p>
+ <p>however</p>
+ <p>in natural theology</p>
+ <p>consequently</p>
+</ref>
+
+<ref id="certainty.clause">
+ <p>it must not be supposed that</p>
+ <p>there can be no doubt that</p>
+ <p>we can deduce that</p>
+ <p>it is not at all certain that</p>
+ <p><xref id="philosopher"/> tells us that</p>
+ <p>it remains a mystery why</p>
+ <p>I assert<p chance="50">, <xref id="intro.clause"/>,</p> that</p>
+ <p>to avoid all misapprehension, it is necessary to explain that</p>
+ <p>let us suppose that</p>
+ <p>it is obvious that</p>
+ <p>the reader should be careful to observe that</p>
+ <p>what we have alone been able to show is that</p>
+</ref>
+
+<ref id="proof">
+ <p>because of our necessary ignorance of the conditions</p>
+ <p>as is shown in the writings of <xref id="philosopher"/></p>
+ <p>as is proven in the ontological manuals</p>
+ <p>as any dedicated reader can clearly see</p>
+ <p>as is evident upon close examination</p>
+ <p>as will easily be shown in the next section</p>
+ <p>since knowledge of <xref id="Np"/> is <xref id="knowledge.type"/></p>
+ <p>by virtue of <xref id="reason.type"/> reason</p>
+ <p>as we have already seen</p>
+ <p>since <xref id="quantity"/> <xref id="Np"/> are <xref id="judgement.type"/></p>
+ <p>because of the relation between <xref id="Ns"/> and <xref id="Np"/></p>
+ <p>by means of analysis</p>
+ <p>by means of analytic unity</p>
+</ref>
+
+<ref id="throwaway.clause">
+ <p>in so far as this expounds the <xref id="rule.type"/> rules of <choice><p><xref id="Ns"/></p><p><xref id="Np"/></p></choice></p>
+ <p>when thus treated as <choice><p><xref id="Ns"/></p><p><xref id="Np"/></p></choice></p>
+ <p>in other words</p>
+ <p>in the full sense of these terms</p>
+ <p>insomuch as <xref id="Ns"/> relies on <xref id="Np"/></p>
+ <p>indeed</p>
+ <p>then</p>
+ <p>that is to say</p>
+ <p>even as this relates to <xref id="Ns"/></p>
+ <p>in respect of the intelligible character</p>
+ <p>so regarded</p>
+ <p>for example</p>
+ <p>irrespective of all empirical conditions</p>
+ <p>so far as regards <xref id="Ns"/><p chance="50"> and <xref id="Np"/></p></p>
+ <p>on the contrary</p>
+ <p>in accordance with the principles of <choice><p><xref id="Ns"/></p><p><xref id="Np"/></p></choice></p>
+ <p>in reference to ends</p>
+ <p>in particular</p>
+ <p>so far as I know</p>
+</ref>
+
+<ref id="main.clause">
+ <p><xref id="Ns"/><p chance="50"><choice><p> (and <xref id="certainty.clause"/> this is true)</p><p>, <xref id="throwaway.clause"/>,</p></choice></p> <xref id="Vst"/> <choice><p><xref id="Ns"/></p><p><xref id="Np"/></p></choice></p>
+ <p><xref id="Ns"/> <xref id="Vst"/><p chance="50">, <choice><p><xref id="throwaway.clause"/></p><p><xref id="intro.clause"/></p></choice>,</p> <choice><p><xref id="Ns"/></p><p><xref id="Np"/></p></choice></p>
+ <p><xref id="Ns"/><p chance="50">, <choice><p><xref id="throwaway.clause"/></p><p><xref id="intro.clause"/></p></choice>,</p> <xref id="Vsi"/></p>
+ <p><xref id="Np"/><p chance="50"><choice><p> (and <xref id="certainty.clause"/> this is the case)</p><p>, <xref id="intro.clause"/>,</p></choice></p> <xref id="Vpt"/> <choice><p><xref id="Ns"/></p><p><xref id="Np"/></p></choice></p>
+ <p><xref id="Np"/> <xref id="Vpt"/><p chance="50">, <choice><p><xref id="throwaway.clause"/></p><p><xref id="intro.clause"/></p></choice>,</p> <choice><p><xref id="Ns"/></p><p><xref id="Np"/></p></choice></p>
+ <p><xref id="Np"/><p chance="50">, <choice><p><xref id="throwaway.clause"/></p><p><xref id="intro.clause"/></p></choice>,</p> <xref id="Vpi"/></p>
+</ref>
+
+<ref id="sentence">
+ <p class="sentence"><p chance="50"><xref id="intro.clause"/>, </p><p chance="50"><xref id="certainty.clause"/> </p><xref id="main.clause"/><p chance="50">, <xref id="proof"/></p>.</p>
+ <p class="sentence"><p chance="50"><xref id="proof"/>, </p><p chance="50"><xref id="certainty.clause"/>, <xref id="throwaway.clause"/>, </p><xref id="main.clause"/><p chance="50">, <xref id="conjunction"/> <xref id="main.clause"/></p>.</p>
+ <p class="sentence"><p chance="50"><xref id="proof"/>, </p><p chance="50"><xref id="certainty.clause"/> </p><xref id="main.clause"/><p chance="50">; <xref id="intro.clause"/>, <xref id="main.clause"/></p>.</p>
+</ref>
+
+<ref id="question">
+ <p>Whence comes <xref id="Ns"/>, the solution of which involves the relation between <choice><p><xref id="Ns"/></p><p><xref id="Np"/></p></choice> and <choice><p><xref id="Ns"/></p><p><xref id="Np"/></p></choice>?</p>
+<p class="sentence"><p chance="50"><xref id="intro.clause"/>, </p>is it <choice><p>true</p><p>the case</p></choice> that <xref id="Ns"/> <xref id="Vst"/> <choice><p><xref id="Ns"/></p><p><xref id="Np"/></p></choice>, or is the real question whether <xref id="Np"/> <xref id="Vpi"/>?</p>
+ <p>Has it ever been suggested that<p chance="50">, <xref id="proof"/>,</p> <xref id="certainty.clause"/> there is <choice><p>no relation</p><p>a causal connection</p></choice> bewteen <choice><p><xref id="Ns"/></p><p><xref id="Np"/></p></choice> and <choice><p><xref id="Ns"/></p><p><xref id="Np"/></p></choice>?</p>
+ <p>In which of our cognitive faculties are <choice><p><xref id="Ns"/></p><p><xref id="Np"/></p></choice> and <choice><p><xref id="Ns"/></p><p><xref id="Np"/></p></choice> connected together?</p>
+<p class="sentence"><xref id="conjunction"/> can I entertain <xref id="Ns"/> in thought, or does it present itself to me?</p>
+</ref>
+
+<ref id="throwaway.sentence">
+ <p>But we have fallen short of the necessary interconnection that we have in mind when we speak of <choice><p><xref id="Ns"/></p><p><xref id="Np"/></p></choice>.</p>
+ <p>We thus have a pure synthesis of apprehension.</p>
+ <p>And similarly with all the others.</p>
+ <p>The question of this matter's relation to objects is not in any way under discussion.</p>
+ <p>This distinction must have some ground in the nature of <choice><p><xref id="Ns"/></p><p><xref id="Np"/></p></choice>.</p>
+ <p>The divisions are thus provided; all that is required is to fill them.</p>
+ <p>This could not be passed over in a complete system of transcendental philosophy, but in a merely critical essay the simple mention of the fact may suffice.</p>
+ <p>This is not something we are in a position to establish.</p>
+ <p>This is the sense in which it is to be understood in this work.</p>
+ <p>But this need not worry us.</p>
+ <p>Let us apply this to <xref id="Ns"/>.</p>
+ <p>But to this matter no answer is possible.</p>
+ <p>But the proof of this is a task from which we can here be absolved.</p>
+ <p>But at present we shall turn our attention to <xref id="Ns"/>.</p>
+ <p>This may be clear with an example.</p>
+ <p>I feel I have sufficiently shown this to be true.</p>
+ <p>This is what chiefly concerns us.</p>
+ <p>On this matter, what has been said already should in any case suffice by itself.</p>
+ <p>In my present remarks I am referring to <xref id="Ns"/> only in so far as it is founded on <xref id="judgement.type"/> principles.</p>
+ <p>But this is to be dismissed as random groping.</p>
+</ref>
+
+<ref id="paragraph">
+ <p> <xref id="sentence"/> <xref id="sentence"/> <p chance="50"><xref id="sentence"/> </p><xref id="sentence"/> <p chance="50"><xref id="sentence"/> </p><p chance="50"><xref id="question"/> </p><p chance="50"><xref id="sentence"/> </p><p chance="50"><xref id="sentence"/> </p><xref id="sentence"/> <p chance="50"><xref id="throwaway.sentence"/></p></p>
+ <p> <xref id="sentence"/> <xref id="sentence"/> <p chance="50"><xref id="sentence"/> </p><xref id="sentence"/> <p chance="50">(<xref id="sentence"/>) </p><xref id="sentence"/> <xref id="sentence"/> <p chance="50"><xref id="throwaway.sentence"/></p></p>
+ <p> <xref id="sentence"/> <xref id="sentence"/> <p chance="50"><xref id="sentence"/> </p><xref id="sentence"/> <p chance="50"><xref id="sentence"/> </p><p chance="50"><xref id="sentence"/> </p><p chance="50"><xref id="sentence"/> </p><xref id="sentence"/></p>
+</ref>
+
+<ref id="section">
+ <p><xref id="paragraph"/>
+<xref id="paragraph"/>
+<xref id="paragraph"/>
+<xref id="paragraph"/>
+<p chance="50"><xref id="paragraph"/>
+</p><p chance="50"><xref id="paragraph"/>
+</p><p chance="50"><xref id="paragraph"/>
+</p><p chance="50"><xref id="paragraph"/>
+</p><p chance="50"><xref id="paragraph"/>
+</p><p chance="50"><xref id="paragraph"/>
+</p></p>
+</ref>
+</grammar>
diff --git a/help/diveintopython-5.4/py/kgp/kgp.dtd b/help/diveintopython-5.4/py/kgp/kgp.dtd
new file mode 100644
index 0000000..3172e36
--- /dev/null
+++ b/help/diveintopython-5.4/py/kgp/kgp.dtd
@@ -0,0 +1,9 @@
+<!ELEMENT grammar (ref)+>
+<!ELEMENT ref (p)+>
+<!ATTLIST ref id ID #REQUIRED>
+<!ELEMENT xref EMPTY>
+<!ATTLIST xref id IDREF #REQUIRED>
+<!ELEMENT choice (p)+>
+<!ELEMENT p (#PCDATA|p|xref|choice)*>
+<!ATTLIST p class CDATA #IMPLIED>
+<!ATTLIST p chance CDATA #IMPLIED>
diff --git a/help/diveintopython-5.4/py/kgp/kgp.py b/help/diveintopython-5.4/py/kgp/kgp.py
new file mode 100644
index 0000000..e10e8ed
--- /dev/null
+++ b/help/diveintopython-5.4/py/kgp/kgp.py
@@ -0,0 +1,251 @@
+#!/usr/bin/env python2
+"""Kant Generator for Python
+
+Generates mock philosophy based on a context-free grammar
+
+Usage: python kgp.py [options] [source]
+
+Options:
+ -g ..., --grammar=... use specified grammar file or URL
+ -h, --help show this help
+ -d show debugging information while parsing
+
+Examples:
+ kgp.py generates several paragraphs of Kantian philosophy
+ kgp.py -g husserl.xml generates several paragraphs of Husserl
+ kpg.py "<xref id='paragraph'/>" generates a paragraph of Kant
+ kgp.py template.xml reads from template.xml to decide what to generate
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.4 $"
+__date__ = "$Date: 2004/05/05 21:57:19 $"
+__copyright__ = "Copyright (c) 2001 Mark Pilgrim"
+__license__ = "Python"
+
+from xml.dom import minidom
+import random
+import toolbox
+import sys
+import getopt
+
+_debug = 0
+
+class NoSourceError(Exception): pass
+
+class KantGenerator:
+ """generates mock philosophy based on a context-free grammar"""
+
+ def __init__(self, grammar, source=None):
+ self.loadGrammar(grammar)
+ self.loadSource(source and source or self.getDefaultSource())
+ self.refresh()
+
+ def _load(self, source):
+ """load XML input source, return parsed XML document
+
+ - a URL of a remote XML file ("http://diveintopython.org/kant.xml")
+ - a filename of a local XML file ("~/diveintopython/common/py/kant.xml")
+ - standard input ("-")
+ - the actual XML document, as a string
+ """
+ sock = toolbox.openAnything(source)
+ xmldoc = minidom.parse(sock).documentElement
+ sock.close()
+ return xmldoc
+
+ def loadGrammar(self, grammar):
+ """load context-free grammar"""
+ self.grammar = self._load(grammar)
+ self.refs = {}
+ for ref in self.grammar.getElementsByTagName("ref"):
+ self.refs[ref.attributes["id"].value] = ref
+
+ def loadSource(self, source):
+ """load source"""
+ self.source = self._load(source)
+
+ def getDefaultSource(self):
+ """guess default source of the current grammar
+
+ The default source will be one of the <ref>s that is not
+ cross-referenced. This sounds complicated but it's not.
+ Example: The default source for kant.xml is
+ "<xref id='section'/>", because 'section' is the one <ref>
+ that is not <xref>'d anywhere in the grammar.
+ In most grammars, the default source will produce the
+ longest (and most interesting) output.
+ """
+ xrefs = {}
+ for xref in self.grammar.getElementsByTagName("xref"):
+ xrefs[xref.attributes["id"].value] = 1
+ xrefs = xrefs.keys()
+ standaloneXrefs = [e for e in self.refs.keys() if e not in xrefs]
+ if not standaloneXrefs:
+ raise NoSourceError, "can't guess source, and no source specified"
+ return '<xref id="%s"/>' % random.choice(standaloneXrefs)
+
+ def reset(self):
+ """reset parser"""
+ self.pieces = []
+ self.capitalizeNextWord = 0
+
+ def refresh(self):
+ """reset output buffer, re-parse entire source file, and return output
+
+ Since parsing involves a good deal of randomness, this is an
+ easy way to get new output without having to reload a grammar file
+ each time.
+ """
+ self.reset()
+ self.parse(self.source)
+ return self.output()
+
+ def output(self):
+ """output generated text"""
+ return "".join(self.pieces)
+
+ def randomChildElement(self, node):
+ """choose a random child element of a node
+
+ This is a utility method used by do_xref and do_choice.
+ """
+ choices = [e for e in node.childNodes
+ if e.nodeType == e.ELEMENT_NODE]
+ chosen = random.choice(choices)
+ if _debug:
+ sys.stderr.write('%s available choices: %s\n' % \
+ (len(choices), [e.toxml() for e in choices]))
+ sys.stderr.write('Chosen: %s\n' % chosen.toxml())
+ return chosen
+
+ def parse(self, node):
+ """parse a single XML node
+
+ A parsed XML document (from minidom.parse) is a tree of nodes
+ of various types. Each node is represented by an instance of the
+ corresponding Python class (Element for a tag, Text for
+ text data, Document for the top-level document). The following
+ statement constructs the name of a class method based on the type
+ of node we're parsing ("parse_Element" for an Element node,
+ "parse_Text" for a Text node, etc.) and then calls the method.
+ """
+ parseMethod = getattr(self, "parse_%s" % node.__class__.__name__)
+ parseMethod(node)
+
+ def parse_Document(self, node):
+ """parse the document node
+
+ The document node by itself isn't interesting (to us), but
+ its only child, node.documentElement, is: it's the root node
+ of the grammar.
+ """
+ self.parse(node.documentElement)
+
+ def parse_Text(self, node):
+ """parse a text node
+
+ The text of a text node is usually added to the output buffer
+ verbatim. The one exception is that <p class='sentence'> sets
+ a flag to capitalize the first letter of the next word. If
+ that flag is set, we capitalize the text and reset the flag.
+ """
+ text = node.data
+ if self.capitalizeNextWord:
+ self.pieces.append(text[0].upper())
+ self.pieces.append(text[1:])
+ self.capitalizeNextWord = 0
+ else:
+ self.pieces.append(text)
+
+ def parse_Element(self, node):
+ """parse an element
+
+ An XML element corresponds to an actual tag in the source:
+ <xref id='...'>, <p chance='...'>, <choice>, etc.
+ Each element type is handled in its own method. Like we did in
+ parse(), we construct a method name based on the name of the
+ element ("do_xref" for an <xref> tag, etc.) and
+ call the method.
+ """
+ handlerMethod = getattr(self, "do_%s" % node.tagName)
+ handlerMethod(node)
+
+ def parse_Comment(self, node):
+ """parse a comment
+
+ The grammar can contain XML comments, but we ignore them
+ """
+ pass
+
+ def do_xref(self, node):
+ """handle <xref id='...'> tag
+
+ An <xref id='...'> tag is a cross-reference to a <ref id='...'>
+ tag. <xref id='sentence'/> evaluates to a randomly chosen child of
+ <ref id='sentence'>.
+ """
+ id = node.attributes["id"].value
+ self.parse(self.randomChildElement(self.refs[id]))
+
+ def do_p(self, node):
+ """handle <p> tag
+
+ The <p> tag is the core of the grammar. It can contain almost
+ anything: freeform text, <choice> tags, <xref> tags, even other
+ <p> tags. If a "class='sentence'" attribute is found, a flag
+ is set and the next word will be capitalized. If a "chance='X'"
+ attribute is found, there is an X% chance that the tag will be
+ evaluated (and therefore a (100-X)% chance that it will be
+ completely ignored)
+ """
+ keys = node.attributes.keys()
+ if "class" in keys:
+ if node.attributes["class"].value == "sentence":
+ self.capitalizeNextWord = 1
+ if "chance" in keys:
+ chance = int(node.attributes["chance"].value)
+ doit = (chance > random.randrange(100))
+ else:
+ doit = 1
+ if doit:
+ for child in node.childNodes: self.parse(child)
+
+ def do_choice(self, node):
+ """handle <choice> tag
+
+ A <choice> tag contains one or more <p> tags. One <p> tag
+ is chosen at random and evaluated; the rest are ignored.
+ """
+ self.parse(self.randomChildElement(node))
+
+def usage():
+ print __doc__
+
+def main(argv):
+ grammar = "kant.xml"
+ try:
+ opts, args = getopt.getopt(argv, "hg:d", ["help", "grammar="])
+ except getopt.GetoptError:
+ usage()
+ sys.exit(2)
+ for opt, arg in opts:
+ if opt in ("-h", "--help"):
+ usage()
+ sys.exit()
+ elif opt == '-d':
+ global _debug
+ _debug = 1
+ elif opt in ("-g", "--grammar"):
+ grammar = arg
+
+ source = "".join(args)
+ k = KantGenerator(grammar, source)
+ print k.output()
+
+if __name__ == "__main__":
+ main(sys.argv[1:])
diff --git a/help/diveintopython-5.4/py/kgp/russiansample.xml b/help/diveintopython-5.4/py/kgp/russiansample.xml
new file mode 100644
index 0000000..1115183
--- /dev/null
+++ b/help/diveintopython-5.4/py/kgp/russiansample.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="koi8-r"?>
+<preface>
+<title>ðÒÅÄÉÓÌÏ×ÉÅ</title>
+</preface>
diff --git a/help/diveintopython-5.4/py/kgp/stderr.py b/help/diveintopython-5.4/py/kgp/stderr.py
new file mode 100644
index 0000000..cec0e96
--- /dev/null
+++ b/help/diveintopython-5.4/py/kgp/stderr.py
@@ -0,0 +1,5 @@
+import sys
+
+fsock = open('error.log', 'w')
+sys.stderr = fsock
+raise Exception, 'this error will be logged'
diff --git a/help/diveintopython-5.4/py/kgp/stdout.py b/help/diveintopython-5.4/py/kgp/stdout.py
new file mode 100644
index 0000000..0bf0c2f
--- /dev/null
+++ b/help/diveintopython-5.4/py/kgp/stdout.py
@@ -0,0 +1,9 @@
+import sys
+
+print 'Dive in'
+saveout = sys.stdout
+fsock = open('out.log', 'w')
+sys.stdout = fsock
+print 'This message will be logged instead of displayed'
+sys.stdout = saveout
+fsock.close()
diff --git a/help/diveintopython-5.4/py/kgp/template.xml b/help/diveintopython-5.4/py/kgp/template.xml
new file mode 100644
index 0000000..6550c8d
--- /dev/null
+++ b/help/diveintopython-5.4/py/kgp/template.xml
@@ -0,0 +1 @@
+<xref id="sentence"/>
diff --git a/help/diveintopython-5.4/py/kgp/test.xml b/help/diveintopython-5.4/py/kgp/test.xml
new file mode 100644
index 0000000..072b738
--- /dev/null
+++ b/help/diveintopython-5.4/py/kgp/test.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<!DOCTYPE grammar PUBLIC "-//diveintopython.org//DTD Kant Generator Pro v1.0//EN" "kgp.dtd">
+<grammar>
+<ref id="a">
+ <p>0</p>
+</ref>
+<ref id="b">
+ <p>1</p>
+ <p>1</p>
+</ref>
+<ref id="c">
+ <p chance="100">2</p>
+</ref>
+<ref id="d">
+ <p chance="0">3</p>
+</ref>
+<ref id="e">
+ <p><xref id="a"/></p>
+</ref>
+<ref id="f">
+ <p><xref id="b"/><xref id="a"/></p>
+</ref>
+<ref id="g">
+ <p><choice><p>1</p><p>1</p></choice></p>
+</ref>
+</grammar>
diff --git a/help/diveintopython-5.4/py/kgp/thanks.xml b/help/diveintopython-5.4/py/kgp/thanks.xml
new file mode 100644
index 0000000..3275cd2
--- /dev/null
+++ b/help/diveintopython-5.4/py/kgp/thanks.xml
@@ -0,0 +1,436 @@
+<?xml version="1.0"?>
+<!DOCTYPE grammar PUBLIC "-//diveintopython.org//DTD Kant Generator Pro v1.0//EN" "kgp.dtd">
+<grammar>
+
+<ref id="money.object">
+ <p>new clothes</p>
+ <p>a really good book</p>
+ <p>drugs</p>
+ <p>comic books</p>
+ <p>booze for a party I'm throwing this weekend</p>
+ <p>new computer hardware</p>
+ <p>a stuffed animal</p>
+ <p>a cute little pewter castle with crystals on the towers</p>
+ <p>sexy underwear</p>
+ <p>a bread machine</p>
+ <p>car repairs</p>
+ <p>a digital watch</p>
+ <p>a new pet hamster</p>
+ <p>a new toaster</p>
+ <p>shampoo</p>
+ <p>things for my new baby</p>
+ <p>legal fees</p>
+ <p>my divorce</p>
+ <p>this month's rent</p>
+ <p>food<p chance="50"> <choice><p>for the baby</p><p>for the next <choice><p>week</p><p>few days</p></choice></p></choice></p></p>
+ <p>plastic surgery</p>
+</ref>
+
+<ref id="thank.you.paragraph">
+ <p> <p class="sentence"><xref id="money.thanks"/></p></p>
+ <p> <p class="sentence"><xref id="gift.thanks"/></p></p>
+</ref>
+
+<ref id="closing">
+ <p><xref id="closing.line"/>
+<choice><p><xref id="male.name"/></p><p><xref id="female.name"/></p></choice></p>
+</ref>
+
+<ref id="gift.used">
+ <p>I'm planning to take it to the shooting range the next time I go.</p>
+ <p>I'm sure I will put it to good use.</p>
+ <p>Everyone I konw is envious.</p>
+ <p>It looks lovely in my <xref id="room"/>.</p>
+ <p>I've made it the central focus of my <xref id="room"/>.</p>
+ <p>My <xref id="room"/> looked empty without it.</p>
+</ref>
+
+<ref id="money.thanks">
+ <p><xref id="money.received"/> <choice><p><xref id="money.spent"/></p><p><xref id="money.saved"/></p></choice> <xref id="money.tag.line"/></p>
+</ref>
+
+<ref id="male.name">
+ <p>Bob</p>
+ <p>Jim</p>
+ <p>John</p>
+ <p>Fred</p>
+ <p>Elmer</p>
+ <p>Charlie</p>
+ <p>Lester</p>
+ <p>David</p>
+ <p>Mark</p>
+ <p>Andrew</p>
+ <p>Pete</p>
+ <p>Bill</p>
+ <p>William</p>
+ <p>James</p>
+ <p>Richard</p>
+ <p>Scott</p>
+ <p>Nathan</p>
+ <p>Matt</p>
+ <p>Jeff</p>
+ <p>Archie</p>
+ <p>Tom</p>
+ <p>Harry</p>
+ <p>Vinnie</p>
+ <p>Michael</p>
+ <p>Dan</p>
+ <p>Ray</p>
+ <p>Roy</p>
+ <p>Todd</p>
+ <p>Chad</p>
+ <p>Jeremy</p>
+ <p>Jason</p>
+ <p>Kurt</p>
+ <p>Keith</p>
+ <p>Ken</p>
+ <p>Tim</p>
+ <p>Randall</p>
+ <p>Eric</p>
+ <p>Stuart</p>
+ <p>Roger</p>
+ <p>Alex</p>
+ <p>Joel</p>
+ <p>Don</p>
+ <p>Ron</p>
+ <p>Arnold</p>
+ <p>Frank</p>
+ <p>Ted</p>
+ <p>Gary</p>
+ <p>Josh</p>
+ <p>Warren</p>
+ <p>Nick</p>
+ <p>Ben</p>
+ <p>Calvin</p>
+ <p>Martin</p>
+ <p>Jake</p>
+ <p>Ed</p>
+</ref>
+
+<ref id="gift.thanks">
+ <p><xref id="gift.received"/> <xref id="gift.used"/> <xref id="gift.tag.line"/></p>
+</ref>
+
+<ref id="money.amount">
+ <p>$5</p>
+ <p>$10</p>
+ <p>$15</p>
+ <p>$20</p>
+ <p>$25</p>
+ <p>$30</p>
+ <p>$35</p>
+ <p>$40</p>
+ <p>$45</p>
+ <p>$50</p>
+ <p>$75</p>
+ <p>$100</p>
+</ref>
+
+<ref id="female.name">
+ <p>Mary</p>
+ <p>Emily</p>
+ <p>Anne</p>
+ <p>Kathy</p>
+ <p>Natalie</p>
+ <p>Ellen</p>
+ <p>Joan</p>
+ <p>Jean</p>
+ <p>Jill</p>
+ <p>Rachel</p>
+ <p>Kendra</p>
+ <p>Sabina</p>
+ <p>Sheila</p>
+ <p>Jessica</p>
+ <p>Andrea</p>
+ <p>Megan</p>
+ <p>Alison</p>
+ <p>Robin</p>
+ <p>Lynn</p>
+ <p>Joy</p>
+ <p>Wendy</p>
+ <p>Kristin</p>
+ <p>Donna</p>
+ <p>Kim</p>
+ <p>Jen</p>
+ <p>Beth</p>
+ <p>Lisa</p>
+ <p>Angie</p>
+ <p>Sarah</p>
+ <p>Peggy</p>
+ <p>Becky</p>
+ <p>Laura</p>
+ <p>Nicole</p>
+ <p>Melanie</p>
+ <p>Miriam</p>
+ <p>Alicia</p>
+ <p>Sylvia</p>
+ <p>Clara</p>
+ <p>Julie</p>
+ <p>Rhoda</p>
+ <p>Rhonda</p>
+ <p>Greta</p>
+ <p>Amelia</p>
+ <p>Emma</p>
+ <p>Courtney</p>
+ <p>Ashley</p>
+ <p>Stephanie</p>
+ <p>Vicky</p>
+ <p>Lois</p>
+ <p>Thelma</p>
+ <p>Ruth</p>
+ <p>Elizabeth</p>
+ <p>Sandy</p>
+ <p>Stella</p>
+ <p>Carolyn</p>
+ <p>Maria</p>
+ <p>Marjorie</p>
+ <p>Edith</p>
+ <p>Teresa</p>
+ <p>Linda</p>
+ <p>Sue</p>
+ <p>Rose</p>
+ <p>April</p>
+ <p>Frances</p>
+ <p>Dora</p>
+</ref>
+
+<ref id="room">
+ <p>living room</p>
+ <p>bathroom</p>
+ <p>basement</p>
+ <p>bedroom</p>
+ <p>closet</p>
+ <p>kitchen</p>
+ <p>garage</p>
+ <p>attic</p>
+ <p>dining room</p>
+ <p>hallway</p>
+ <p>guest room</p>
+ <p>sewing room</p>
+ <p>office</p>
+ <p>billiard parlor</p>
+ <p>junk drawer</p>
+ <p>backyard</p>
+ <p>doghouse</p>
+</ref>
+
+<ref id="person">
+ <p><xref id="male"/></p>
+ <p><xref id="female"/></p>
+ <p><xref id="female"/> and <xref id="male"/></p>
+ <p><xref id="male"/> and <xref id="female"/></p>
+ <p><xref id="male.name"/> and <xref id="male.name"/></p>
+ <p><xref id="female.name"/> and <xref id="female.name"/></p>
+</ref>
+
+<ref id="magazine">
+ <p>Maxim</p>
+ <p>The New Yorker</p>
+ <p>Time</p>
+ <p>Newsweek</p>
+ <p>Guns and Ammo</p>
+ <p>Esquire</p>
+ <p>GQ</p>
+ <p>Cosmopolitan</p>
+ <p>The American Spectator</p>
+ <p>The Nation</p>
+ <p>Mother Jones</p>
+ <p>Field and Stream</p>
+ <p>Reader's Digest</p>
+ <p>The Journal of the American Chemical Society</p>
+ <p>Mind</p>
+ <p>Discover</p>
+ <p>Games</p>
+ <p>MacWorld</p>
+ <p>New Republic</p>
+ <p>Wired</p>
+</ref>
+
+<ref id="female">
+ <p>Grandma<p chance="50"> <xref id="female.name"/></p></p>
+ <p>Mom</p>
+ <p>Aunt <xref id="female.name"/></p>
+ <p>sister</p>
+ <p><xref id="female.name"/></p>
+ <p><xref id="female.name"/></p>
+ <p><xref id="female.name"/></p>
+</ref>
+
+<ref id="male">
+ <p>Grandpa<p chance="50"> <xref id="male.name"/></p></p>
+ <p>Dad</p>
+ <p>Uncle <xref id="male.name"/></p>
+ <p>brother</p>
+ <p><xref id="male.name"/></p>
+ <p><xref id="male.name"/></p>
+ <p><xref id="male.name"/></p>
+</ref>
+
+<ref id="state">
+ <p>dead</p>
+ <p>in prison</p>
+ <p>in a labor camp in Siberia</p>
+ <p>in the hospital</p>
+ <p>reported missing last month</p>
+ <p>broke</p>
+ <p>destitute</p>
+ <p>in the witness relocation program</p>
+</ref>
+
+<ref id="money.saved">
+ <p>I've already <choice><p>put</p><p>stashed</p></choice> it in <choice><p>the bank</p><p>a shoebox</p></choice><p chance="50"> to save for <xref id="money.object"/></p>.</p>
+ <p><p chance="50">I'd love to spend it, but </p>I'm saving it to buy <xref id="money.object"/>.</p>
+ <p><p chance="50">It's nice to have some "fun money" to spend, but </p>I've decided to save it for <xref id="money.object"/>.</p>
+ <p><p chance="50">I'd love to spend it<p chance="50"><choice><p>immediately</p><p>right away</p></choice></p>, but </p>I need to save up for <xref id="money.object"/>.</p>
+</ref>
+
+<ref id="greeting">
+ <p>Dear <xref id="person"/>,</p>
+</ref>
+
+<ref id="money.tag.line">
+ <p class="sentence">It's not much by today's standards, but every little bit helps!</p>
+ <p class="sentence">It was either that or give it to the poor.</p>
+ <p class="sentence"><xref id="tag.line"/></p>
+ <p class="sentence"><xref id="tag.line"/></p>
+ <p class="sentence"><xref id="tag.line"/></p>
+ <p class="sentence"><xref id="tag.line"/></p>
+ <p class="sentence"><xref id="tag.line"/></p>
+ <p class="sentence"><xref id="tag.line"/></p>
+ <p class="sentence"><xref id="tag.line"/></p>
+</ref>
+
+<ref id="money.received">
+<p class="sentence"><p chance="50">This is </p>just a brief note to <choice><p>say <choice><p>thanks</p><p>"thank you"</p></choice></p><p>thank you</p></choice> for the <xref id="money.amount"/> <choice><p>you sent</p><p>I received from you</p></choice> for <xref id="occasion"/>.</p>
+<p class="sentence">Of all the <choice><p>presents</p><p>gifts</p><p>things</p><p>stuff</p></choice> I <choice><p>received</p><p>got</p></choice> for <xref id="occasion"/>, I <choice><p>liked</p><p>loved</p></choice> your <p chance="50">gift of </p><xref id="money.amount"/> <choice><p>the most</p><p>more than anything else</p></choice>.</p>
+<p class="sentence">I <p chance="50">really </p><choice><p>appreciate</p><p>enjoyed receiving</p></choice> the <xref id="money.amount"/> you <choice><p>gave</p><p>sent</p></choice> me for <xref id="occasion"/>.</p>
+<p class="sentence">I <p chance="50">really </p>love <choice><p>getting</p><p>receiving</p></choice> money for <xref id="occasion"/>, <choice><p>since</p><p>because</p></choice> <choice><p>that</p><p>it</p></choice> means I can <p chance="50">always </p><p chance="50">go out and </p><choice><p>spend it on</p><p>use it for</p></choice> what I really <choice><p>want</p><p>need</p></choice>. <choice><p>Thanks</p><p>Thank you</p></choice> for the <xref id="money.amount"/>.</p>
+<p class="sentence">You can't imagine how surprised I was to discover that you had sent me <xref id="money.amount"/> for <xref id="occasion"/>.</p>
+<p class="sentence"><choice><p>Thanks</p><p>Thank you</p></choice> for the <xref id="money.amount"/><choice><p>. I</p><p>; i</p></choice>t was <choice><p>the perfect</p><p>a great</p></choice> <choice><p>present</p><p>gift</p></choice> for <xref id="occasion"/>.</p>
+<p class="sentence">I don't know how to thank you <p chance="50"><choice><p>properly</p><p>enough</p></choice> </p>for the <xref id="money.amount"/> you <choice><p>sent</p><p>gave</p></choice> <p chance="50">me </p>for <xref id="occasion"/>.</p>
+<p class="sentence">I'm <p chance="50">just </p>writing to say <choice><p>thanks</p><p>"thank you"</p></choice> for the <xref id="money.amount"/> you <p chance="50">graciously </p><choice><p>gave</p><p>sent</p></choice> me for <xref id="occasion"/>.</p>
+<p class="sentence"><choice><p>Thank you</p><p>Thanks</p></choice> for the <xref id="money.amount"/> you <choice><p>bestowed upon</p><p>sent</p></choice> me for <xref id="occasion"/>.</p>
+<p class="sentence"><p chance="50">This is </p>just a quick note to <choice><p>say "thank you"</p><p>thank you</p></choice> for the <xref id="money.amount"/> <choice><p>I <choice><p>got</p><p>received</p></choice> from you</p><p>you sent<p chance="50"> me</p></p></choice> for <xref id="occasion"/>.</p>
+</ref>
+
+<ref id="gift.received">
+<p class="sentence"><p chance="50">This is </p>just a brief note to <choice><p>say <choice><p>thanks</p><p>"thank you"</p></choice></p><p>thank you</p></choice> for the <xref id="gift.object"/> <choice><p>you sent</p><p>I received from you</p></choice> for <xref id="occasion"/>.</p>
+<p class="sentence">Of all the <choice><p>presents</p><p>gifts</p><p>things</p><p>stuff</p></choice> I <choice><p>received</p><p>got</p></choice> for <xref id="occasion"/>, I <choice><p>liked</p><p>loved</p></choice> your <p chance="50">gift of </p><xref id="gift.object"/> <choice><p>the most</p><p>more than anything else</p></choice>.</p>
+<p class="sentence">I <p chance="50">really </p><choice><p>appreciate</p><p>enjoyed receiving</p></choice> the <xref id="gift.object"/> you <choice><p>gave</p><p>sent</p></choice> me for <xref id="occasion"/>.</p>
+<p class="sentence">I <p chance="50">really </p>love <choice><p>getting</p><p>receiving</p></choice> money for <xref id="occasion"/>, <choice><p>since</p><p>because</p></choice> <choice><p>that</p><p>it</p></choice> means I can <p chance="50">always </p><p chance="50">go out and </p><choice><p>spend it on</p><p>use it for</p></choice> what I really <choice><p>want</p><p>need</p></choice>. <choice><p>Thanks</p><p>Thank you</p></choice> for the <xref id="gift.object"/>.</p>
+<p class="sentence">You can't imagine how surprised I was to discover that you had sent me <xref id="gift.object"/> for <xref id="occasion"/>.</p>
+<p class="sentence"><choice><p>Thanks</p><p>Thank you</p></choice> for the <xref id="gift.object"/><choice><p>. I</p><p>; i</p></choice>t was <choice><p>the perfect</p><p>a great</p></choice> <choice><p>present</p><p>gift</p></choice> for <xref id="occasion"/>.</p>
+<p class="sentence">I don't know how to thank you <p chance="50"><choice><p>properly</p><p>enough</p></choice> </p>for the <xref id="gift.object"/> you <choice><p>sent</p><p>gave</p></choice> <p chance="50">me </p>for <xref id="occasion"/>.</p>
+<p class="sentence">I'm <p chance="50">just </p>writing to say <choice><p>thanks</p><p>"thank you"</p></choice> for the <xref id="gift.object"/> you <p chance="50">graciously </p><choice><p>gave</p><p>sent</p></choice> me for <xref id="occasion"/>.</p>
+<p class="sentence"><choice><p>Thank you</p><p>Thanks</p></choice> for the <xref id="gift.object"/> you <choice><p>bestowed upon</p><p>sent</p></choice> me for <xref id="occasion"/>.</p>
+<p class="sentence"><p chance="50">This is </p>just a quick note to <choice><p>say "thank you"</p><p>thank you</p></choice> for the <xref id="gift.object"/> <choice><p>I <choice><p>got</p><p>received</p></choice> from you</p><p>you sent<p chance="50"> me</p></p></choice> for <xref id="occasion"/>.</p>
+</ref>
+
+<ref id="occasion">
+ <p>Christmas</p>
+ <p>Valentine's Day</p>
+ <p>my birthday</p>
+ <p>Easter</p>
+ <p>New Year's</p>
+ <p>Hanukkah</p>
+ <p>our wedding</p>
+ <p>our divorce</p>
+ <p>my half-birthday</p>
+ <p>my confirmation</p>
+ <p>my Bar Mitzvah</p>
+ <p>my debutante ball</p>
+ <p>my coming-out party</p>
+ <p>our first baby</p>
+ <p>my bachelor party</p>
+ <p>my bridal shower</p>
+ <p>our housewarming party</p>
+</ref>
+
+<ref id="gift.tag.line">
+ <p><xref id="tag.line"/></p>
+</ref>
+
+<ref id="tag.line">
+ <p class="sentence">I know how much of a sacrifice this sort of gift is for you.</p>
+ <p class="sentence"><xref id="male.name"/> and <xref id="female.name"/> tried to steal it from me, but I was too quick for them.</p>
+ <p class="sentence"><p chance="50">I'm </p>looking forward to getting your next gift for <xref id="occasion"/>.</p>
+ <p class="sentence"><p chance="50">Frankly, </p>it was <p chance="50">a little </p>strange to get anything from you<p chance="50"> at all</p>, because <choice><p>I thought</p><p>my friends to me that</p></choice> you were <xref id="state"/>.</p>
+ <p class="sentence">How thoughtful of you.</p>
+ <p class="sentence">Give my love to <choice><p><xref id="male.name"/></p><p><xref id="female.name"/></p></choice>.</p>
+ <p class="sentence">Best wishes to you<p chance="50"> and <xref id="person"/></p>.</p>
+</ref>
+
+<ref id="closing.line">
+ <p>Sincerely</p>
+ <p>Love<p chance="50"> always</p>,</p>
+ <p>Thank you<p chance="50"> again</p>,</p>
+ <p>See you soon,</p>
+ <p>Hugs and kisses,</p>
+ <p>From,</p>
+ <p>Thanks<p chance="50"> again</p>,</p>
+ <p>Peace,</p>
+ <p>Faithfully,</p>
+</ref>
+
+<ref id="thank.you.note">
+ <p><xref id="greeting"/>
+<xref id="thank.you.paragraph"/>
+
+<xref id="closing"/></p>
+</ref>
+
+<ref id="money.spent">
+ <p class="sentence"><p chance="50">You'll be happy to know that </p>I've already spent it on <xref id="money.object"/>.</p>
+ <p class="sentence">It<choice><p>'s</p><p> has</p></choice> <p chance="50">already </p>been well-spent on <xref id="money.object"/>.</p>
+ <p class="sentence">My <choice><p>mother</p><p>father</p></choice> insisted that I spend it on <xref id="money.object"/>.</p>
+ <p class="sentence">Now I <p chance="50"> finally</p>have enough money for <xref id="money.object"/>.</p>
+ <p class="sentence"><p chance="50"><choice><p>As soon as I can, </p><p>When I get a chance, </p></choice></p>I'm going <p chance="50">to the mall </p>and spending it on <xref id="money.object"/>.</p>
+ <p class="sentence"><p chance="50">To be honest, </p><choice><p>I tried to get it to the bank</p><p>I wanted to save it</p></choice>, but I <p chance="50">realized I </p><choice><p>needed</p><p>had</p></choice> to spend it on <xref id="money.object"/><p chance="50"> instead</p>.</p>
+ <p class="sentence"><p chance="50">I just wanted to let you know that </p>it's already gone towards <xref id="money.object"/>.</p>
+ <p class="sentence">I <p chance="50"><choice><p>immediately</p><p>rushed right out and</p></choice> </p>spent it on <xref id="money.object"/><p chance="50"> for the first time<p chance="50"> in years</p></p>.</p>
+ <p class="sentence"><p chance="50">As soon as I finish writing this letter, </p>I'm going to put it towards <xref id="money.object"/>.</p>
+ <p class="sentence"><p chance="50">I have to admit that </p>I already spent it on this month's protection.</p>
+</ref>
+
+<ref id="gift.object">
+ <p>toaster</p>
+ <p>blender</p>
+ <p>pajamas</p>
+ <p>wallet</p>
+ <p>umbrella</p>
+ <p>shampoo</p>
+ <p>mouthwash</p>
+ <p>beer</p>
+ <p>disk drive</p>
+ <p>mousepad</p>
+ <p>stereo</p>
+ <p>compact disc</p>
+ <p>dart board</p>
+ <p>bread machine</p>
+ <p>moustache comb</p>
+ <p>fruitcake</p>
+ <p>towel rack</p>
+ <p>bong</p>
+ <p>jigsaw puzzle</p>
+ <p>Star Trek "Picard" doll</p>
+ <p>stuffed animal</p>
+ <p>beanbag chair</p>
+ <p>box of chocolates</p>
+ <p>microwave oven</p>
+ <p>snowblower</p>
+ <p>jacket</p>
+ <p>sweatshirt</p>
+ <p>tie</p>
+ <p>laundry detergent</p>
+ <p>fake tree</p>
+ <p>makeup kit</p>
+ <p>miniature pool table</p>
+ <p>carton of cigarettes</p>
+ <p>basketball</p>
+ <p>fake vomit</p>
+ <p>book</p>
+ <p>subscription to <xref id="magazine"/></p>
+ <p>"Critique of Pure Reason"</p>
+</ref>
+
+</grammar>
diff --git a/help/diveintopython-5.4/py/kgp/toolbox.py b/help/diveintopython-5.4/py/kgp/toolbox.py
new file mode 100644
index 0000000..0a1a6fd
--- /dev/null
+++ b/help/diveintopython-5.4/py/kgp/toolbox.py
@@ -0,0 +1,58 @@
+"""Miscellaneous utility functions
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.3 $"
+__date__ = "$Date: 2004/05/05 21:57:20 $"
+__copyright__ = "Copyright (c) 2001 Mark Pilgrim"
+__license__ = "Python"
+
+def openAnything(source):
+ """URI, filename, or string --> stream
+
+ This function lets you define parsers that take any input source
+ (URL, pathname to local or network file, or actual data as a string)
+ and deal with it in a uniform manner. Returned object is guaranteed
+ to have all the basic stdio read methods (read, readline, readlines).
+ Just .close() the object when you're done with it.
+
+ Examples:
+ >>> from xml.dom import minidom
+ >>> sock = openAnything("http://localhost/kant.xml")
+ >>> doc = minidom.parse(sock)
+ >>> sock.close()
+ >>> sock = openAnything("c:\\inetpub\\wwwroot\\kant.xml")
+ >>> doc = minidom.parse(sock)
+ >>> sock.close()
+ >>> sock = openAnything("<ref id='conjunction'><text>and</text><text>or</text></ref>")
+ >>> doc = minidom.parse(sock)
+ >>> sock.close()
+ """
+
+ if hasattr(source, "read"):
+ return source
+
+ if source == "-":
+ import sys
+ return sys.stdin
+
+ # try to open with urllib (if source is http, ftp, or file URL)
+ import urllib
+ try:
+ return urllib.urlopen(source)
+ except (IOError, OSError):
+ pass
+
+ # try to open with native open function (if source is pathname)
+ try:
+ return open(source)
+ except (IOError, OSError):
+ pass
+
+ # treat source as string
+ import StringIO
+ return StringIO.StringIO(str(source))
diff --git a/help/diveintopython-5.4/py/kgptest.py b/help/diveintopython-5.4/py/kgptest.py
new file mode 100644
index 0000000..5f46ee5
--- /dev/null
+++ b/help/diveintopython-5.4/py/kgptest.py
@@ -0,0 +1,65 @@
+"""Unit test for kgp.py
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.2 $"
+__date__ = "$Date: 2004/05/05 21:57:19 $"
+__copyright__ = "Copyright (c) 2001 Mark Pilgrim"
+__license__ = "Python"
+
+import unittest
+import sys
+if 'kgp' not in sys.path:
+ sys.path.append('kgp')
+import kgp
+
+class KGPTest(unittest.TestCase):
+ resultsMap = {"a":"0",
+ "b":"1",
+ "c":"2",
+ "d":"",
+ "e":"0",
+ "f":"10",
+ "g":"1"}
+
+ def setUp(self):
+ self.parser = kgp.KantGenerator('kgp/test.xml')
+
+ def doTest(self, key):
+ self.parser.loadSource('<xref id="%s"/>' % key)
+ self.assertEqual(self.resultsMap[key], self.parser.refresh())
+
+ def testA(self):
+ """kgp a ref test"""
+ self.doTest("a")
+
+ def testB(self):
+ """kgp b ref test"""
+ self.doTest("b")
+
+ def testC(self):
+ """kgp c ref test"""
+ self.doTest("c")
+
+ def testD(self):
+ """kgp d ref test"""
+ self.doTest("d")
+
+ def testE(self):
+ """kgp e ref test"""
+ self.doTest("e")
+
+ def testF(self):
+ """kgp f ref test"""
+ self.doTest("f")
+
+ def testG(self):
+ """kgp g ref test"""
+ self.doTest("g")
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/help/diveintopython-5.4/py/makerealworddoc.py b/help/diveintopython-5.4/py/makerealworddoc.py
new file mode 100644
index 0000000..1e02946
--- /dev/null
+++ b/help/diveintopython-5.4/py/makerealworddoc.py
@@ -0,0 +1,62 @@
+"""Convert HTML page to Word 97 document
+
+This script is used during the build process of "Dive Into Python"
+(http://diveintopython.org/) to create the downloadable Word 97 version
+of the book (http://diveintopython.org/diveintopython.doc)
+
+Looks for 2 arguments on the command line. The first argument is the input (HTML)
+file; the second argument is the output (.doc) file.
+
+Only runs on Windows. Requires Microsoft Word 2000.
+
+Safe to run on the same file(s) more than once. The output file will be
+silently overwritten if it already exists.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.2 $"
+__date__ = "$Date: 2004/05/05 21:57:19 $"
+__copyright__ = "Copyright (c) 2001 Mark Pilgrim"
+__license__ = "Python"
+
+import sys, os
+from win32com.client import gencache, constants
+
+def makeRealWordDoc(infile, outfile):
+ word = gencache.EnsureDispatch("Word.Application")
+ try:
+ worddoc = word.Documents.Open(FileName=infile)
+ try:
+ worddoc.TablesOfContents.Add(Range=word.ActiveWindow.Selection.Range, \
+ RightAlignPageNumbers=1, \
+ UseHeadingStyles=1, \
+ UpperHeadingLevel=1, \
+ LowerHeadingLevel=2, \
+ IncludePageNumbers=1, \
+ AddedStyles='', \
+ UseHyperlinks=1, \
+ HidePageNumbersInWeb=1)
+ worddoc.TablesOfContents(1).TabLeader = constants.wdTabLeaderDots
+ worddoc.TablesOfContents.Format = constants.wdIndexIndent
+
+ word.ActiveWindow.ActivePane.View.SeekView = constants.wdSeekCurrentPageHeader
+ word.Selection.TypeText(Text="Dive Into Python\t\thttp://diveintopython.org/")
+ word.ActiveWindow.ActivePane.View.SeekView = constants.wdSeekCurrentPageFooter
+ word.NormalTemplate.AutoTextEntries("- PAGE -").Insert(Where=word.ActiveWindow.Selection.Range)
+ word.ActiveWindow.View.Type = constants.wdPrintView
+
+ worddoc.TablesOfContents(1).Update()
+
+ worddoc.SaveAs(FileName=outfile, \
+ FileFormat=constants.wdFormatDocument)
+ finally:
+ worddoc.Close(0)
+ del worddoc
+ finally:
+ word.Quit()
+ del word
+
+if __name__ == "__main__":
+ infile = os.path.normpath(os.path.join(os.getcwd(), sys.argv[1]))
+ outfile = os.path.normpath(os.path.join(os.getcwd(), sys.argv[2]))
+ makeRealWordDoc(infile, outfile)
diff --git a/help/diveintopython-5.4/py/odbchelper.py b/help/diveintopython-5.4/py/odbchelper.py
new file mode 100644
index 0000000..548d9ef
--- /dev/null
+++ b/help/diveintopython-5.4/py/odbchelper.py
@@ -0,0 +1,30 @@
+"""odbchelper.py sample script
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+
+All this stuff at the top of the script is just optional metadata;
+the real code starts on the "def buildConnectionString" line
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.2 $"
+__date__ = "$Date: 2004/05/05 21:57:19 $"
+__copyright__ = "Copyright (c) 2001 Mark Pilgrim"
+__license__ = "Python"
+
+def buildConnectionString(params):
+ """Build a connection string from a dictionary
+
+ Returns string.
+ """
+ return ";".join(["%s=%s" % (k, v) for k, v in params.items()])
+
+if __name__ == "__main__":
+ myParams = {"server":"mpilgrim", \
+ "database":"master", \
+ "uid":"sa", \
+ "pwd":"secret"
+ }
+ print buildConnectionString(myParams)
diff --git a/help/diveintopython-5.4/py/odbchelpertest.py b/help/diveintopython-5.4/py/odbchelpertest.py
new file mode 100644
index 0000000..1e8b02b
--- /dev/null
+++ b/help/diveintopython-5.4/py/odbchelpertest.py
@@ -0,0 +1,47 @@
+"""Unit test for odbchelper.py
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.2 $"
+__date__ = "$Date: 2004/05/05 21:57:19 $"
+__copyright__ = "Copyright (c) 2001 Mark Pilgrim"
+__license__ = "Python"
+
+import unittest
+import odbchelper
+
+class GoodInput(unittest.TestCase):
+ def testBlank(self):
+ """buildConnectionString handles empty dictionary"""
+ self.assertEqual("", odbchelper.buildConnectionString({}))
+ def testKnownValue(self):
+ """buildConnectionString returns known result with known input"""
+ params = {"server":"mpilgrim", "database":"master", "uid":"sa", "pwd":"secret"}
+ knownItems = params.items()
+ knownItems.sort()
+ knownString = repr(knownItems)
+ result = odbchelper.buildConnectionString(params)
+ resultItems = [tuple(e.split("=")) for e in result.split(";")]
+ resultItems.sort()
+ resultString = repr(resultItems)
+ self.assertEqual(knownString, resultString)
+
+class BadInput(unittest.TestCase):
+ def testString(self):
+ """buildConnectionString should fail with string input"""
+ self.assertRaises(AttributeError, odbchelper.buildConnectionString, "")
+
+ def testList(self):
+ """buildConnectionString should fail with list input"""
+ self.assertRaises(AttributeError, odbchelper.buildConnectionString, [])
+
+ def testTuple(self):
+ """buildConnectionString should fail with tuple input"""
+ self.assertRaises(AttributeError, odbchelper.buildConnectionString, ())
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/help/diveintopython-5.4/py/openanything.py b/help/diveintopython-5.4/py/openanything.py
new file mode 100644
index 0000000..413f576
--- /dev/null
+++ b/help/diveintopython-5.4/py/openanything.py
@@ -0,0 +1,107 @@
+'''OpenAnything: a kind and thoughtful library for HTTP web services
+
+This program is part of 'Dive Into Python', a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+'''
+
+__author__ = 'Mark Pilgrim (mark@diveintopython.org)'
+__version__ = '$Revision: 1.6 $'[11:-2]
+__date__ = '$Date: 2004/04/16 21:16:24 $'
+__copyright__ = 'Copyright (c) 2004 Mark Pilgrim'
+__license__ = 'Python'
+
+import urllib2, urlparse, gzip
+from StringIO import StringIO
+
+USER_AGENT = 'OpenAnything/%s +http://diveintopython.org/http_web_services/' % __version__
+
+class SmartRedirectHandler(urllib2.HTTPRedirectHandler):
+ def http_error_301(self, req, fp, code, msg, headers):
+ result = urllib2.HTTPRedirectHandler.http_error_301(
+ self, req, fp, code, msg, headers)
+ result.status = code
+ return result
+
+ def http_error_302(self, req, fp, code, msg, headers):
+ result = urllib2.HTTPRedirectHandler.http_error_302(
+ self, req, fp, code, msg, headers)
+ result.status = code
+ return result
+
+class DefaultErrorHandler(urllib2.HTTPDefaultErrorHandler):
+ def http_error_default(self, req, fp, code, msg, headers):
+ result = urllib2.HTTPError(
+ req.get_full_url(), code, msg, headers, fp)
+ result.status = code
+ return result
+
+def openAnything(source, etag=None, lastmodified=None, agent=USER_AGENT):
+ """URL, filename, or string --> stream
+
+ This function lets you define parsers that take any input source
+ (URL, pathname to local or network file, or actual data as a string)
+ and deal with it in a uniform manner. Returned object is guaranteed
+ to have all the basic stdio read methods (read, readline, readlines).
+ Just .close() the object when you're done with it.
+
+ If the etag argument is supplied, it will be used as the value of an
+ If-None-Match request header.
+
+ If the lastmodified argument is supplied, it must be a formatted
+ date/time string in GMT (as returned in the Last-Modified header of
+ a previous request). The formatted date/time will be used
+ as the value of an If-Modified-Since request header.
+
+ If the agent argument is supplied, it will be used as the value of a
+ User-Agent request header.
+ """
+
+ if hasattr(source, 'read'):
+ return source
+
+ if source == '-':
+ return sys.stdin
+
+ if urlparse.urlparse(source)[0] == 'http':
+ # open URL with urllib2
+ request = urllib2.Request(source)
+ request.add_header('User-Agent', agent)
+ if lastmodified:
+ request.add_header('If-Modified-Since', lastmodified)
+ if etag:
+ request.add_header('If-None-Match', etag)
+ request.add_header('Accept-encoding', 'gzip')
+ opener = urllib2.build_opener(SmartRedirectHandler(), DefaultErrorHandler())
+ return opener.open(request)
+
+ # try to open with native open function (if source is a filename)
+ try:
+ return open(source)
+ except (IOError, OSError):
+ pass
+
+ # treat source as string
+ return StringIO(str(source))
+
+def fetch(source, etag=None, lastmodified=None, agent=USER_AGENT):
+ '''Fetch data and metadata from a URL, file, stream, or string'''
+ result = {}
+ f = openAnything(source, etag, lastmodified, agent)
+ result['data'] = f.read()
+ if hasattr(f, 'headers'):
+ # save ETag, if the server sent one
+ result['etag'] = f.headers.get('ETag')
+ # save Last-Modified header, if the server sent one
+ result['lastmodified'] = f.headers.get('Last-Modified')
+ if f.headers.get('content-encoding') == 'gzip':
+ # data came back gzip-compressed, decompress it
+ result['data'] = gzip.GzipFile(fileobj=StringIO(result['data'])).read()
+ if hasattr(f, 'url'):
+ result['url'] = f.url
+ result['status'] = 200
+ if hasattr(f, 'status'):
+ result['status'] = f.status
+ f.close()
+ return result
+
diff --git a/help/diveintopython-5.4/py/parsephone.py b/help/diveintopython-5.4/py/parsephone.py
new file mode 100644
index 0000000..9d4c71f
--- /dev/null
+++ b/help/diveintopython-5.4/py/parsephone.py
@@ -0,0 +1,37 @@
+"""Parse U.S. phone numbers
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.3 $"
+__date__ = "$Date: 2004/05/05 21:57:19 $"
+__copyright__ = "Copyright (c) 2002 Mark Pilgrim"
+__license__ = "Python"
+
+import re
+
+class InvalidPhoneNumber(Exception): pass
+
+phonePattern = re.compile(r"""
+ ^ # match beginning of string
+ \D* # swallow anything that isn't numeric
+ 1? # swallow leading 1, if present
+ \D* # swallow anything that isn't numeric
+ (\d{3}) # capture 3-digit area code
+ \D* # swallow anything that isn't numeric
+ (\d{3}) # capture 3-digit trunk
+ \D* # swallow anything that isn't numeric
+ (\d{4}) # capture 4-digit number
+ \D* # swallow anything that isn't numeric
+ (\d*) # capture extension, if present
+ """, re.VERBOSE)
+
+def parsePhoneNumber(phoneNumber):
+ match = phonePattern.search(phoneNumber)
+ if match:
+ return match.groups()
+ else:
+ raise InvalidPhoneNumber, phoneNumber
diff --git a/help/diveintopython-5.4/py/piglatin.py b/help/diveintopython-5.4/py/piglatin.py
new file mode 100644
index 0000000..ffba488
--- /dev/null
+++ b/help/diveintopython-5.4/py/piglatin.py
@@ -0,0 +1,33 @@
+"""Convert text to Pig Latin
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.2 $"
+__date__ = "$Date: 2004/05/05 21:57:19 $"
+__copyright__ = "Copyright (c) 2002 Mark Pilgrim"
+__license__ = "Python"
+
+import re
+
+def _wordToPigLatin(match):
+ word = match.group()
+ consonants = match.group(1)
+ restOfWord = match.group(2)
+ # put consonants after rest of word, and add "ay"
+ result = "%s%say" % (restOfWord, consonants)
+ # if word was all uppercase, make result uppercase
+ if word == word.upper():
+ result = result.upper()
+ # if word was capitalized, make result capitalized
+ elif word == word.capitalize():
+ result = result.capitalize()
+ return result
+
+def pigLatin(source):
+ pattern = re.compile(r'\b([bcdfghjklmnpqrstvwxyz]*)(\w+)\b', re.IGNORECASE)
+ return pattern.sub(_wordToPigLatin, source)
+
diff --git a/help/diveintopython-5.4/py/plural-rules.en b/help/diveintopython-5.4/py/plural-rules.en
new file mode 100644
index 0000000..0aa3b38
--- /dev/null
+++ b/help/diveintopython-5.4/py/plural-rules.en
@@ -0,0 +1,19 @@
+^(sheep|deer|fish|moose|aircraft|series|haiku)$ ($) \1
+[ml]ouse$ ouse$ ice
+child$ $ ren
+booth$ $ s
+foot$ oot$ eet
+ooth$ ooth$ eeth
+l[eo]af$ af$ aves
+sis$ sis$ ses
+^(hu|ro)man$ $ s
+man$ man$ men
+^lowlife$ $ s
+ife$ ife$ ives
+eau$ $ x
+^[dp]elf$ $ s
+lf$ lf$ lves
+[sxz]$ $ es
+[^aeioudgkprt]h$ $ es
+(qu|[^aeiou])y$ y$ ies
+$ $ s
diff --git a/help/diveintopython-5.4/py/plural.py b/help/diveintopython-5.4/py/plural.py
new file mode 100644
index 0000000..c3e672a
--- /dev/null
+++ b/help/diveintopython-5.4/py/plural.py
@@ -0,0 +1,36 @@
+"""Pluralize English nouns (stage 6)
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+
+Command line usage:
+$ python plural6.py noun
+nouns
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.7 $"
+__date__ = "$Date: 2004/05/03 19:40:42 $"
+__copyright__ = "Copyright (c) 2004 Mark Pilgrim"
+__license__ = "Python"
+
+import re
+
+def rules(language):
+ for line in file('plural-rules.%s' % language):
+ pattern, search, replace = line.split()
+ yield lambda word: re.search(pattern, word) and re.sub(search, replace, word)
+
+def plural(noun, language='en'):
+ """returns the plural form of a noun"""
+ for applyRule in rules(language):
+ result = applyRule(noun)
+ if result: return result
+
+if __name__ == '__main__':
+ import sys
+ if sys.argv[1:]:
+ print plural(sys.argv[1])
+ else:
+ print __doc__
diff --git a/help/diveintopython-5.4/py/plural/stage1/plural1.py b/help/diveintopython-5.4/py/plural/stage1/plural1.py
new file mode 100644
index 0000000..7aea074
--- /dev/null
+++ b/help/diveintopython-5.4/py/plural/stage1/plural1.py
@@ -0,0 +1,35 @@
+"""Pluralize English nouns (stage 1)
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+
+Command line usage:
+$ python plural1.py noun
+nouns
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.3 $"
+__date__ = "$Date: 2004/03/18 16:43:37 $"
+__copyright__ = "Copyright (c) 2004 Mark Pilgrim"
+__license__ = "Python"
+
+import re
+
+def plural(noun):
+ if re.search('[sxz]$', noun):
+ return re.sub('$', 'es', noun)
+ elif re.search('[^aeioudgkprt]h$', noun):
+ return re.sub('$', 'es', noun)
+ elif re.search('[^aeiou]y$', noun):
+ return re.sub('y$', 'ies', noun)
+ else:
+ return noun + 's'
+
+if __name__ == '__main__':
+ import sys
+ if sys.argv[1:]:
+ print plural(sys.argv[1])
+ else:
+ print __doc__
diff --git a/help/diveintopython-5.4/py/plural/stage1/pluraltest1.py b/help/diveintopython-5.4/py/plural/stage1/pluraltest1.py
new file mode 100644
index 0000000..b5f6f65
--- /dev/null
+++ b/help/diveintopython-5.4/py/plural/stage1/pluraltest1.py
@@ -0,0 +1,50 @@
+"""Unit test for plural1.py
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.2 $"
+__date__ = "$Date: 2004/03/17 14:34:40 $"
+__copyright__ = "Copyright (c) 2004 Mark Pilgrim"
+__license__ = "Python"
+
+from plural1 import plural
+import unittest, new
+
+class KnownValues(unittest.TestCase):
+ nouns = {'bass': 'basses',
+ 'bus': 'buses',
+ 'walrus': 'walruses',
+ 'box': 'boxes',
+ 'fax': 'faxes',
+ 'suffix': 'suffixes',
+ 'mailbox': 'mailboxes',
+ 'buzz': 'buzzes',
+ 'waltz': 'waltzes',
+ 'coach': 'coaches',
+ 'glitch': 'glitches',
+ 'rash': 'rashes',
+ 'watch': 'watches',
+ 'cheetah': 'cheetahs',
+ 'cough': 'coughs',
+ 'utility': 'utilities',
+ 'vacancy': 'vacancies',
+ 'boy': 'boys',
+ 'day': 'days',
+ 'computer': 'computers',
+ 'rock': 'rocks',
+ 'paper': 'papers',
+ }
+
+for noun, pluralnoun in KnownValues.nouns.items():
+ func = lambda self, noun=noun, pluralnoun=pluralnoun: \
+ KnownValues.failUnlessEqual(self, plural(noun), pluralnoun)
+ func.__doc__ = "%s --> %s" % (noun, pluralnoun)
+ instanceMethod = new.instancemethod(func, None, KnownValues)
+ setattr(KnownValues, "test_%s" % noun, instanceMethod)
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/help/diveintopython-5.4/py/plural/stage2/plural2.py b/help/diveintopython-5.4/py/plural/stage2/plural2.py
new file mode 100644
index 0000000..967b9d7
--- /dev/null
+++ b/help/diveintopython-5.4/py/plural/stage2/plural2.py
@@ -0,0 +1,60 @@
+"""Pluralize English nouns (stage 2)
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+
+Command line usage:
+$ python plural2.py noun
+nouns
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.4 $"
+__date__ = "$Date: 2004/03/18 18:55:45 $"
+__copyright__ = "Copyright (c) 2004 Mark Pilgrim"
+__license__ = "Python"
+
+import re
+
+def match_sxz(noun):
+ return re.search('[sxz]$', noun)
+
+def apply_sxz(noun):
+ return re.sub('$', 'es', noun)
+
+def match_h(noun):
+ return re.search('[^aeioudgkprt]h$', noun)
+
+def apply_h(noun):
+ return re.sub('$', 'es', noun)
+
+def match_y(noun):
+ return re.search('[^aeiou]y$', noun)
+
+def apply_y(noun):
+ return re.sub('y$', 'ies', noun)
+
+def match_default(moun):
+ return 1
+
+def apply_default(noun):
+ return noun + 's'
+
+rules = ((match_sxz, apply_sxz),
+ (match_h, apply_h),
+ (match_y, apply_y),
+ (match_default, apply_default)
+ )
+
+def plural(noun):
+ for matchesRule, applyRule in rules:
+ if matchesRule(noun):
+ return applyRule(noun)
+
+if __name__ == '__main__':
+ import sys
+ if sys.argv[1:]:
+ print plural(sys.argv[1])
+ else:
+ print __doc__
diff --git a/help/diveintopython-5.4/py/plural/stage2/pluraltest2.py b/help/diveintopython-5.4/py/plural/stage2/pluraltest2.py
new file mode 100644
index 0000000..4bace86
--- /dev/null
+++ b/help/diveintopython-5.4/py/plural/stage2/pluraltest2.py
@@ -0,0 +1,50 @@
+"""Unit test for plural2.py
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.2 $"
+__date__ = "$Date: 2004/03/17 14:34:40 $"
+__copyright__ = "Copyright (c) 2004 Mark Pilgrim"
+__license__ = "Python"
+
+from plural2 import plural
+import unittest, new
+
+class KnownValues(unittest.TestCase):
+ nouns = {'bass': 'basses',
+ 'bus': 'buses',
+ 'walrus': 'walruses',
+ 'box': 'boxes',
+ 'fax': 'faxes',
+ 'suffix': 'suffixes',
+ 'mailbox': 'mailboxes',
+ 'buzz': 'buzzes',
+ 'waltz': 'waltzes',
+ 'coach': 'coaches',
+ 'glitch': 'glitches',
+ 'rash': 'rashes',
+ 'watch': 'watches',
+ 'cheetah': 'cheetahs',
+ 'cough': 'coughs',
+ 'utility': 'utilities',
+ 'vacancy': 'vacancies',
+ 'boy': 'boys',
+ 'day': 'days',
+ 'computer': 'computers',
+ 'rock': 'rocks',
+ 'paper': 'papers',
+ }
+
+for noun, pluralnoun in KnownValues.nouns.items():
+ func = lambda self, noun=noun, pluralnoun=pluralnoun: \
+ KnownValues.failUnlessEqual(self, plural(noun), pluralnoun)
+ func.__doc__ = "%s --> %s" % (noun, pluralnoun)
+ instanceMethod = new.instancemethod(func, None, KnownValues)
+ setattr(KnownValues, "test_%s" % noun, instanceMethod)
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/help/diveintopython-5.4/py/plural/stage3/plural3.py b/help/diveintopython-5.4/py/plural/stage3/plural3.py
new file mode 100644
index 0000000..e6b75be
--- /dev/null
+++ b/help/diveintopython-5.4/py/plural/stage3/plural3.py
@@ -0,0 +1,50 @@
+"""Pluralize English nouns (stage 3)
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+
+Command line usage:
+$ python plural3.py noun
+nouns
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.3 $"
+__date__ = "$Date: 2004/03/18 16:43:37 $"
+__copyright__ = "Copyright (c) 2004 Mark Pilgrim"
+__license__ = "Python"
+
+import re
+
+rules = \
+ (
+ (
+ lambda word: re.search('[sxz]$', word),
+ lambda word: re.sub('$', 'es', word)
+ ),
+ (
+ lambda word: re.search('[^aeioudgkprt]h$', word),
+ lambda word: re.sub('$', 'es', word)
+ ),
+ (
+ lambda word: re.search('[^aeiou]y$', word),
+ lambda word: re.sub('y$', 'ies', word)
+ ),
+ (
+ lambda word: re.search('$', word),
+ lambda word: re.sub('$', 's', word)
+ )
+ )
+
+def plural(noun):
+ for matchesRule, applyRule in rules:
+ if matchesRule(noun):
+ return applyRule(noun)
+
+if __name__ == '__main__':
+ import sys
+ if sys.argv[1:]:
+ print plural(sys.argv[1])
+ else:
+ print __doc__
diff --git a/help/diveintopython-5.4/py/plural/stage3/pluraltest3.py b/help/diveintopython-5.4/py/plural/stage3/pluraltest3.py
new file mode 100644
index 0000000..7580855
--- /dev/null
+++ b/help/diveintopython-5.4/py/plural/stage3/pluraltest3.py
@@ -0,0 +1,50 @@
+"""Unit test for plural3.py
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.2 $"
+__date__ = "$Date: 2004/03/17 14:34:40 $"
+__copyright__ = "Copyright (c) 2004 Mark Pilgrim"
+__license__ = "Python"
+
+from plural3 import plural
+import unittest, new
+
+class KnownValues(unittest.TestCase):
+ nouns = {'bass': 'basses',
+ 'bus': 'buses',
+ 'walrus': 'walruses',
+ 'box': 'boxes',
+ 'fax': 'faxes',
+ 'suffix': 'suffixes',
+ 'mailbox': 'mailboxes',
+ 'buzz': 'buzzes',
+ 'waltz': 'waltzes',
+ 'coach': 'coaches',
+ 'glitch': 'glitches',
+ 'rash': 'rashes',
+ 'watch': 'watches',
+ 'cheetah': 'cheetahs',
+ 'cough': 'coughs',
+ 'utility': 'utilities',
+ 'vacancy': 'vacancies',
+ 'boy': 'boys',
+ 'day': 'days',
+ 'computer': 'computers',
+ 'rock': 'rocks',
+ 'paper': 'papers',
+ }
+
+for noun, pluralnoun in KnownValues.nouns.items():
+ func = lambda self, noun=noun, pluralnoun=pluralnoun: \
+ KnownValues.failUnlessEqual(self, plural(noun), pluralnoun)
+ func.__doc__ = "%s --> %s" % (noun, pluralnoun)
+ instanceMethod = new.instancemethod(func, None, KnownValues)
+ setattr(KnownValues, "test_%s" % noun, instanceMethod)
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/help/diveintopython-5.4/py/plural/stage4/plural4.py b/help/diveintopython-5.4/py/plural/stage4/plural4.py
new file mode 100644
index 0000000..ef02e0e
--- /dev/null
+++ b/help/diveintopython-5.4/py/plural/stage4/plural4.py
@@ -0,0 +1,44 @@
+"""Pluralize English nouns (stage 4)
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+
+Command line usage:
+$ python plural4.py noun
+nouns
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.3 $"
+__date__ = "$Date: 2004/03/18 16:43:37 $"
+__copyright__ = "Copyright (c) 2004 Mark Pilgrim"
+__license__ = "Python"
+
+import re
+
+def buildMatchAndApplyFunctions((pattern, search, replace)):
+ matchFunction = lambda word: re.search(pattern, word)
+ applyFunction = lambda word: re.sub(search, replace, word)
+ return (matchFunction, applyFunction)
+
+patterns = \
+ (
+ ('[sxz]$', '$', 'es'),
+ ('[^aeioudgkprt]h$', '$', 'es'),
+ ('(qu|[^aeiou])y$', 'y$', 'ies'),
+ ('$', '$', 's')
+ )
+rules = map(buildMatchAndApplyFunctions, patterns)
+
+def plural(noun):
+ for matchesRule, applyRule in rules:
+ if matchesRule(noun):
+ return applyRule(noun)
+
+if __name__ == '__main__':
+ import sys
+ if sys.argv[1:]:
+ print plural(sys.argv[1])
+ else:
+ print __doc__
diff --git a/help/diveintopython-5.4/py/plural/stage4/pluraltest4.py b/help/diveintopython-5.4/py/plural/stage4/pluraltest4.py
new file mode 100644
index 0000000..405e842
--- /dev/null
+++ b/help/diveintopython-5.4/py/plural/stage4/pluraltest4.py
@@ -0,0 +1,50 @@
+"""Unit test for plural4.py
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.2 $"
+__date__ = "$Date: 2004/03/17 14:34:40 $"
+__copyright__ = "Copyright (c) 2004 Mark Pilgrim"
+__license__ = "Python"
+
+from plural4 import plural
+import unittest, new
+
+class KnownValues(unittest.TestCase):
+ nouns = {'bass': 'basses',
+ 'bus': 'buses',
+ 'walrus': 'walruses',
+ 'box': 'boxes',
+ 'fax': 'faxes',
+ 'suffix': 'suffixes',
+ 'mailbox': 'mailboxes',
+ 'buzz': 'buzzes',
+ 'waltz': 'waltzes',
+ 'coach': 'coaches',
+ 'glitch': 'glitches',
+ 'rash': 'rashes',
+ 'watch': 'watches',
+ 'cheetah': 'cheetahs',
+ 'cough': 'coughs',
+ 'utility': 'utilities',
+ 'vacancy': 'vacancies',
+ 'boy': 'boys',
+ 'day': 'days',
+ 'computer': 'computers',
+ 'rock': 'rocks',
+ 'paper': 'papers',
+ }
+
+for noun, pluralnoun in KnownValues.nouns.items():
+ func = lambda self, noun=noun, pluralnoun=pluralnoun: \
+ KnownValues.failUnlessEqual(self, plural(noun), pluralnoun)
+ func.__doc__ = "%s --> %s" % (noun, pluralnoun)
+ instanceMethod = new.instancemethod(func, None, KnownValues)
+ setattr(KnownValues, "test_%s" % noun, instanceMethod)
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/help/diveintopython-5.4/py/plural/stage5/plural5.py b/help/diveintopython-5.4/py/plural/stage5/plural5.py
new file mode 100644
index 0000000..6a19360
--- /dev/null
+++ b/help/diveintopython-5.4/py/plural/stage5/plural5.py
@@ -0,0 +1,37 @@
+"""Pluralize English nouns (stage 5)
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+
+Command line usage:
+$ python plural5.py noun
+nouns
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.3 $"
+__date__ = "$Date: 2004/03/25 15:51:13 $"
+__copyright__ = "Copyright (c) 2004 Mark Pilgrim"
+__license__ = "Python"
+
+import re
+import string
+
+def buildRule((pattern, search, replace)):
+ return lambda word: re.search(pattern, word) and re.sub(search, replace, word)
+
+def plural(noun, language='en'):
+ lines = file('rules.%s' % language).readlines()
+ patterns = map(string.split, lines)
+ rules = map(buildRule, patterns)
+ for rule in rules:
+ result = rule(noun)
+ if result: return result
+
+if __name__ == '__main__':
+ import sys
+ if sys.argv[1:]:
+ print plural(sys.argv[1])
+ else:
+ print __doc__
diff --git a/help/diveintopython-5.4/py/plural/stage5/pluraltest5.py b/help/diveintopython-5.4/py/plural/stage5/pluraltest5.py
new file mode 100644
index 0000000..8eef6d8
--- /dev/null
+++ b/help/diveintopython-5.4/py/plural/stage5/pluraltest5.py
@@ -0,0 +1,50 @@
+"""Unit test for plural5.py
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.1 $"
+__date__ = "$Date: 2004/03/17 14:35:42 $"
+__copyright__ = "Copyright (c) 2004 Mark Pilgrim"
+__license__ = "Python"
+
+from plural5 import plural
+import unittest, new
+
+class KnownValues(unittest.TestCase):
+ nouns = {'bass': 'basses',
+ 'bus': 'buses',
+ 'walrus': 'walruses',
+ 'box': 'boxes',
+ 'fax': 'faxes',
+ 'suffix': 'suffixes',
+ 'mailbox': 'mailboxes',
+ 'buzz': 'buzzes',
+ 'waltz': 'waltzes',
+ 'coach': 'coaches',
+ 'glitch': 'glitches',
+ 'rash': 'rashes',
+ 'watch': 'watches',
+ 'cheetah': 'cheetahs',
+ 'cough': 'coughs',
+ 'utility': 'utilities',
+ 'vacancy': 'vacancies',
+ 'boy': 'boys',
+ 'day': 'days',
+ 'computer': 'computers',
+ 'rock': 'rocks',
+ 'paper': 'papers',
+ }
+
+for noun, pluralnoun in KnownValues.nouns.items():
+ func = lambda self, noun=noun, pluralnoun=pluralnoun: \
+ KnownValues.failUnlessEqual(self, plural(noun), pluralnoun)
+ func.__doc__ = "%s --> %s" % (noun, pluralnoun)
+ instanceMethod = new.instancemethod(func, None, KnownValues)
+ setattr(KnownValues, "test_%s" % noun, instanceMethod)
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/help/diveintopython-5.4/py/plural/stage5/rules.en b/help/diveintopython-5.4/py/plural/stage5/rules.en
new file mode 100644
index 0000000..72a8d58
--- /dev/null
+++ b/help/diveintopython-5.4/py/plural/stage5/rules.en
@@ -0,0 +1,4 @@
+[sxz]$ $ es
+[^aeioudgkprt]h$ $ es
+[^aeiou]y$ y$ ies
+$ $ s
diff --git a/help/diveintopython-5.4/py/plural/stage6/plural6.py b/help/diveintopython-5.4/py/plural/stage6/plural6.py
new file mode 100644
index 0000000..ba83e52
--- /dev/null
+++ b/help/diveintopython-5.4/py/plural/stage6/plural6.py
@@ -0,0 +1,35 @@
+"""Pluralize English nouns (stage 6)
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+
+Command line usage:
+$ python plural6.py noun
+nouns
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.2 $"
+__date__ = "$Date: 2004/03/25 15:51:13 $"
+__copyright__ = "Copyright (c) 2004 Mark Pilgrim"
+__license__ = "Python"
+
+import re
+
+def rules(language):
+ for line in file('rules.%s' % language):
+ pattern, search, replace = line.split()
+ yield lambda word: re.search(pattern, word) and re.sub(search, replace, word)
+
+def plural(noun, language='en'):
+ for rule in rules(language):
+ result = rule(noun)
+ if result: return result
+
+if __name__ == '__main__':
+ import sys
+ if sys.argv[1:]:
+ print plural(sys.argv[1])
+ else:
+ print __doc__
diff --git a/help/diveintopython-5.4/py/plural/stage6/pluraltest6.py b/help/diveintopython-5.4/py/plural/stage6/pluraltest6.py
new file mode 100644
index 0000000..5513d6b
--- /dev/null
+++ b/help/diveintopython-5.4/py/plural/stage6/pluraltest6.py
@@ -0,0 +1,67 @@
+"""Unit test for plural6.py
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.1 $"
+__date__ = "$Date: 2004/03/17 14:34:40 $"
+__copyright__ = "Copyright (c) 2004 Mark Pilgrim"
+__license__ = "Python"
+
+from plural6 import plural
+import unittest, new
+
+class KnownValues(unittest.TestCase):
+ nouns = {'bass': 'basses',
+ 'bus': 'buses',
+ 'walrus': 'walruses',
+ 'box': 'boxes',
+ 'fax': 'faxes',
+ 'suffix': 'suffixes',
+ 'mailbox': 'mailboxes',
+ 'buzz': 'buzzes',
+ 'waltz': 'waltzes',
+ 'coach': 'coaches',
+ 'glitch': 'glitches',
+ 'rash': 'rashes',
+ 'watch': 'watches',
+ 'cheetah': 'cheetahs',
+ 'cough': 'coughs',
+ 'utility': 'utilities',
+ 'vacancy': 'vacancies',
+ 'soliloquy': 'soliloquies',
+ 'boy': 'boys',
+ 'day': 'days',
+ 'computer': 'computers',
+ 'rock': 'rocks',
+ 'paper': 'papers',
+
+ 'mouse': 'mice',
+ 'louse': 'lice',
+ 'child': 'children',
+ 'foot': 'feet',
+ 'booth': 'booths',
+ 'tooth': 'teeth',
+ 'leaf': 'leaves',
+ 'loaf': 'loaves',
+ 'thesis': 'theses',
+ 'man': 'men',
+ 'mailman': 'mailmen',
+ 'knife': 'knives',
+ 'wife': 'wives',
+ 'tableau': 'tableaux',
+ 'elf': 'elves',
+ 'shelf': 'shelves',
+ }
+
+for noun, correctPlural in KnownValues.nouns.items():
+ testMethod = lambda self: KnownValues.failUnlessEqual(self, plural(noun), correctPlural)
+ testMethod.__doc__ = "%s --> %s" % (noun, correctPlural)
+ instanceMethod = new.instancemethod(testMethod, None, KnownValues)
+ setattr(KnownValues, "test_%s" % noun, instanceMethod)
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/help/diveintopython-5.4/py/plural/stage6/rules.en b/help/diveintopython-5.4/py/plural/stage6/rules.en
new file mode 100644
index 0000000..2f37330
--- /dev/null
+++ b/help/diveintopython-5.4/py/plural/stage6/rules.en
@@ -0,0 +1,15 @@
+[ml]ouse$ ([ml])ouse$ \1ice
+child$ child$ children
+booth$ booth$ booths
+foot$ foot$ feet
+ooth$ ooth$ eeth
+l[eo]af$ l([eo])af$ l\1aves
+sis$ sis$ ses
+man$ man$ men
+ife$ ife$ ives
+eau$ eau$ eaux
+lf$ lf$ lves
+[sxz]$ $ es
+[^aeioudgkprt]h$ $ es
+(qu|[^aeiou])y$ y$ ies
+$ $ s
diff --git a/help/diveintopython-5.4/py/pluraltest.py b/help/diveintopython-5.4/py/pluraltest.py
new file mode 100644
index 0000000..2e58ae6
--- /dev/null
+++ b/help/diveintopython-5.4/py/pluraltest.py
@@ -0,0 +1,80 @@
+"""Unit test for plural.py
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.2 $"
+__date__ = "$Date: 2004/03/17 14:34:40 $"
+__copyright__ = "Copyright (c) 2004 Mark Pilgrim"
+__license__ = "Python"
+
+from plural import plural
+import unittest, new
+
+class KnownValues(unittest.TestCase):
+ nouns = {'bass': 'basses',
+ 'bus': 'buses',
+ 'walrus': 'walruses',
+ 'box': 'boxes',
+ 'fax': 'faxes',
+ 'suffix': 'suffixes',
+ 'mailbox': 'mailboxes',
+ 'buzz': 'buzzes',
+ 'waltz': 'waltzes',
+ 'coach': 'coaches',
+ 'glitch': 'glitches',
+ 'rash': 'rashes',
+ 'watch': 'watches',
+ 'cheetah': 'cheetahs',
+ 'cough': 'coughs',
+ 'utility': 'utilities',
+ 'vacancy': 'vacancies',
+ 'soliloquy': 'soliloquies',
+ 'boy': 'boys',
+ 'day': 'days',
+ 'computer': 'computers',
+ 'rock': 'rocks',
+ 'paper': 'papers',
+
+ 'mouse': 'mice',
+ 'louse': 'lice',
+ 'child': 'children',
+ 'foot': 'feet',
+ 'booth': 'booths',
+ 'tooth': 'teeth',
+ 'leaf': 'leaves',
+ 'loaf': 'loaves',
+ 'thesis': 'theses',
+ 'man': 'men',
+ 'mailman': 'mailmen',
+ 'knife': 'knives',
+ 'wife': 'wives',
+ 'tableau': 'tableaux',
+ 'elf': 'elves',
+ 'shelf': 'shelves',
+ 'sheep': 'sheep',
+ 'deer': 'deer',
+ 'fish': 'fish',
+ 'moose': 'moose',
+ 'aircraft': 'aircraft',
+ 'series': 'series',
+ 'haiku': 'haiku',
+ 'delf': 'delfs',
+ 'pelf': 'pelfs',
+ 'human': 'humans',
+ 'roman': 'romans',
+ 'lowlife': 'lowlifes',
+ }
+
+for noun, pluralnoun in KnownValues.nouns.items():
+ func = lambda self, noun=noun, pluralnoun=pluralnoun: \
+ KnownValues.failUnlessEqual(self, plural(noun), pluralnoun)
+ func.__doc__ = "%s --> %s" % (noun, pluralnoun)
+ instanceMethod = new.instancemethod(func, None, KnownValues)
+ setattr(KnownValues, "test_%s" % noun, instanceMethod)
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/help/diveintopython-5.4/py/pyfontify.py b/help/diveintopython-5.4/py/pyfontify.py
new file mode 100644
index 0000000..878cbeb
--- /dev/null
+++ b/help/diveintopython-5.4/py/pyfontify.py
@@ -0,0 +1,131 @@
+"""Module to analyze Python source code; for syntax coloring tools.
+
+Interface:
+ tags = fontify(pytext, searchfrom, searchto)
+
+The 'pytext' argument is a string containing Python source code.
+The (optional) arguments 'searchfrom' and 'searchto' may contain a slice in pytext.
+The returned value is a list of tuples, formatted like this:
+ [('keyword', 0, 6, None), ('keyword', 11, 17, None), ('comment', 23, 53, None), etc. ]
+The tuple contents are always like this:
+ (tag, startindex, endindex, sublist)
+tag is one of ('comment', 'string', 'keyword', 'function', 'class')
+sublist is not used, hence always None.
+"""
+
+# Based on FontText.py by Mitchell S. Chapman,
+# which was modified by Zachary Roadhouse,
+# then un-Tk'd by Just van Rossum.
+# Many thanks for regular expression debugging & authoring are due to:
+# Tim (the-incredib-ly y'rs) Peters and Cristian Tismer
+# So, who owns the copyright? ;-) How about this:
+# Copyright 1996-1997:
+# Mitchell S. Chapman,
+# Zachary Roadhouse,
+# Tim Peters,
+# Just van Rossum
+#
+# Version 0.4 - changes copyright (C) 2001 Mark Pilgrim (mark@diveintopython.org)
+# 2001/02/05 - MAP - distinguish between class and function identifiers
+# 2001/03/21 - MAP - get keywords from keyword module (instead of hard-coded list)
+# 2001/03/22 - MAP - use re module instead of deprecated regex module
+
+__version__ = "0.4"
+
+import string, re, keyword
+
+# Build up a regular expression which will match anything
+# interesting, including multi-line triple-quoted strings.
+commentPat = "#.*"
+
+pat = "q[^\q\n]*(\\\\[\000-\377][^\q\n]*)*q"
+quotePat = string.replace(pat, "q", "'") + "|" + string.replace(pat, 'q', '"')
+
+# Way to go, Tim!
+pat = """
+ qqq
+ [^\\q]*
+ (
+ ( \\\\[\000-\377]
+ | q
+ ( \\\\[\000-\377]
+ | [^\\q]
+ | q
+ ( \\\\[\000-\377]
+ | [^\\q]
+ )
+ )
+ )
+ [^\\q]*
+ )*
+ qqq
+"""
+pat = string.join(string.split(pat), '') # get rid of whitespace
+tripleQuotePat = string.replace(pat, "q", "'") + "|" + string.replace(pat, 'q', '"')
+
+# Build up a regular expression which matches all and only
+# Python keywords. This will let us skip the uninteresting
+# identifier references.
+# nonKeyPat identifies characters which may legally precede
+# a keyword pattern.
+nonKeyPat = "(^|[^a-zA-Z0-9_.\"'])"
+keywordsPat = string.join(keyword.kwlist, "|")
+keyPat = nonKeyPat + "(" + keywordsPat + ")" + nonKeyPat
+
+matchPat = keyPat + "|" + commentPat + "|" + tripleQuotePat + "|" + quotePat
+matchRE = re.compile(matchPat)
+
+idKeyPat = "[ \t]*[A-Za-z_][A-Za-z_0-9.]*" # Ident w. leading whitespace.
+idRE = re.compile(idKeyPat)
+
+def fontify(pytext, searchfrom=0, searchto=None):
+ if searchto is None:
+ searchto = len(pytext)
+ tags = []
+ commentTag = 'comment'
+ stringTag = 'string'
+ keywordTag = 'keyword'
+ functionTag = 'function'
+ classTag = 'class'
+
+ start = 0
+ end = searchfrom
+ while 1:
+ matchObject = matchRE.search(pytext, end)
+ if not matchObject: break
+ (start, end) = matchObject.span()
+ match = matchObject.group(0)
+ c = match[0]
+ if c not in "#'\"":
+ # Must have matched a keyword.
+ if start <> searchfrom:
+ # there's still a redundant char before and after it, strip!
+ match = match[1:-1]
+ start = start + 1
+ else:
+ # this is the first keyword in the text.
+ # Only a space at the end.
+ match = match[:-1]
+ end = end - 1
+ tags.append((keywordTag, start, end, None))
+ # If this was a defining keyword, look ahead to the
+ # following identifier.
+ if match in ["def", "class"]:
+ idMatchObject = idRE.search(pytext, end)
+ if idMatchObject:
+ (start, end) = idMatchObject.span()
+ match = idMatchObject.group(0)
+ tags.append(((match=='def') and functionTag or classTag, start, end, None))
+ elif c == "#":
+ tags.append((commentTag, start, end, None))
+ else:
+ tags.append((stringTag, start, end, None))
+ return tags
+
+def test(path):
+ f = open(path)
+ text = f.read()
+ f.close()
+ tags = fontify(text)
+ for tag, start, end, sublist in tags:
+ print tag, `text[start:end]`, start, end
diff --git a/help/diveintopython-5.4/py/regression.py b/help/diveintopython-5.4/py/regression.py
new file mode 100644
index 0000000..2964e6c
--- /dev/null
+++ b/help/diveintopython-5.4/py/regression.py
@@ -0,0 +1,34 @@
+"""Regression testing framework
+
+This module will search for scripts in the same directory named
+XYZtest.py. Each such script should be a test suite that tests a
+module through PyUnit. (As of Python 2.1, PyUnit is included in
+the standard library as 'unittest'.) This script will aggregate all
+found test suites into one big test suite and run them all at once.
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.4 $"
+__date__ = "$Date: 2004/05/05 21:57:19 $"
+__copyright__ = "Copyright (c) 2001 Mark Pilgrim"
+__license__ = "Python"
+
+import sys, os, re, unittest
+
+def regressionTest():
+ path = os.path.abspath(os.path.dirname(sys.argv[0]))
+ files = os.listdir(path)
+ test = re.compile("test\.py$", re.IGNORECASE)
+ files = filter(test.search, files)
+ filenameToModuleName = lambda f: os.path.splitext(f)[0]
+ moduleNames = map(filenameToModuleName, files)
+ modules = map(__import__, moduleNames)
+ load = unittest.defaultTestLoader.loadTestsFromModule
+ return unittest.TestSuite(map(load, modules))
+
+if __name__ == "__main__":
+ unittest.main(defaultTest="regressionTest")
diff --git a/help/diveintopython-5.4/py/roman.py b/help/diveintopython-5.4/py/roman.py
new file mode 100644
index 0000000..fb09c8d
--- /dev/null
+++ b/help/diveintopython-5.4/py/roman.py
@@ -0,0 +1,77 @@
+"""Convert to and from Roman numerals
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.3 $"
+__date__ = "$Date: 2004/05/05 21:57:19 $"
+__copyright__ = "Copyright (c) 2001 Mark Pilgrim"
+__license__ = "Python"
+
+import re
+
+#Define exceptions
+class RomanError(Exception): pass
+class OutOfRangeError(RomanError): pass
+class NotIntegerError(RomanError): pass
+class InvalidRomanNumeralError(RomanError): pass
+
+#Define digit mapping
+romanNumeralMap = (('M', 1000),
+ ('CM', 900),
+ ('D', 500),
+ ('CD', 400),
+ ('C', 100),
+ ('XC', 90),
+ ('L', 50),
+ ('XL', 40),
+ ('X', 10),
+ ('IX', 9),
+ ('V', 5),
+ ('IV', 4),
+ ('I', 1))
+
+def toRoman(n):
+ """convert integer to Roman numeral"""
+ if not (0 < n < 5000):
+ raise OutOfRangeError, "number out of range (must be 1..4999)"
+ if int(n) <> n:
+ raise NotIntegerError, "non-integers can not be converted"
+
+ result = ""
+ for numeral, integer in romanNumeralMap:
+ while n >= integer:
+ result += numeral
+ n -= integer
+ return result
+
+#Define pattern to detect valid Roman numerals
+romanNumeralPattern = re.compile('''
+ ^ # beginning of string
+ M{0,4} # thousands - 0 to 4 M's
+ (CM|CD|D?C{0,3}) # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 C's),
+ # or 500-800 (D, followed by 0 to 3 C's)
+ (XC|XL|L?X{0,3}) # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 X's),
+ # or 50-80 (L, followed by 0 to 3 X's)
+ (IX|IV|V?I{0,3}) # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 I's),
+ # or 5-8 (V, followed by 0 to 3 I's)
+ $ # end of string
+ ''' ,re.VERBOSE)
+
+def fromRoman(s):
+ """convert Roman numeral to integer"""
+ if not s:
+ raise InvalidRomanNumeralError, 'Input can not be blank'
+ if not romanNumeralPattern.search(s):
+ raise InvalidRomanNumeralError, 'Invalid Roman numeral: %s' % s
+
+ result = 0
+ index = 0
+ for numeral, integer in romanNumeralMap:
+ while s[index:index+len(numeral)] == numeral:
+ result += integer
+ index += len(numeral)
+ return result
diff --git a/help/diveintopython-5.4/py/roman/stage1/roman1.py b/help/diveintopython-5.4/py/roman/stage1/roman1.py
new file mode 100644
index 0000000..5784bf2
--- /dev/null
+++ b/help/diveintopython-5.4/py/roman/stage1/roman1.py
@@ -0,0 +1,26 @@
+"""Convert to and from Roman numerals
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.2 $"
+__date__ = "$Date: 2004/05/05 21:57:20 $"
+__copyright__ = "Copyright (c) 2001 Mark Pilgrim"
+__license__ = "Python"
+
+#Define exceptions
+class RomanError(Exception): pass
+class OutOfRangeError(RomanError): pass
+class NotIntegerError(RomanError): pass
+class InvalidRomanNumeralError(RomanError): pass
+
+def toRoman(n):
+ """convert integer to Roman numeral"""
+ pass
+
+def fromRoman(s):
+ """convert Roman numeral to integer"""
+ pass
diff --git a/help/diveintopython-5.4/py/roman/stage1/romantest1.py b/help/diveintopython-5.4/py/roman/stage1/romantest1.py
new file mode 100644
index 0000000..20f011f
--- /dev/null
+++ b/help/diveintopython-5.4/py/roman/stage1/romantest1.py
@@ -0,0 +1,145 @@
+"""Unit test for roman1.py
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.3 $"
+__date__ = "$Date: 2004/05/05 21:57:20 $"
+__copyright__ = "Copyright (c) 2001 Mark Pilgrim"
+__license__ = "Python"
+
+import roman1
+import unittest
+
+class KnownValues(unittest.TestCase):
+ knownValues = ( (1, 'I'),
+ (2, 'II'),
+ (3, 'III'),
+ (4, 'IV'),
+ (5, 'V'),
+ (6, 'VI'),
+ (7, 'VII'),
+ (8, 'VIII'),
+ (9, 'IX'),
+ (10, 'X'),
+ (50, 'L'),
+ (100, 'C'),
+ (500, 'D'),
+ (1000, 'M'),
+ (31, 'XXXI'),
+ (148, 'CXLVIII'),
+ (294, 'CCXCIV'),
+ (312, 'CCCXII'),
+ (421, 'CDXXI'),
+ (528, 'DXXVIII'),
+ (621, 'DCXXI'),
+ (782, 'DCCLXXXII'),
+ (870, 'DCCCLXX'),
+ (941, 'CMXLI'),
+ (1043, 'MXLIII'),
+ (1110, 'MCX'),
+ (1226, 'MCCXXVI'),
+ (1301, 'MCCCI'),
+ (1485, 'MCDLXXXV'),
+ (1509, 'MDIX'),
+ (1607, 'MDCVII'),
+ (1754, 'MDCCLIV'),
+ (1832, 'MDCCCXXXII'),
+ (1993, 'MCMXCIII'),
+ (2074, 'MMLXXIV'),
+ (2152, 'MMCLII'),
+ (2212, 'MMCCXII'),
+ (2343, 'MMCCCXLIII'),
+ (2499, 'MMCDXCIX'),
+ (2574, 'MMDLXXIV'),
+ (2646, 'MMDCXLVI'),
+ (2723, 'MMDCCXXIII'),
+ (2892, 'MMDCCCXCII'),
+ (2975, 'MMCMLXXV'),
+ (3051, 'MMMLI'),
+ (3185, 'MMMCLXXXV'),
+ (3250, 'MMMCCL'),
+ (3313, 'MMMCCCXIII'),
+ (3408, 'MMMCDVIII'),
+ (3501, 'MMMDI'),
+ (3610, 'MMMDCX'),
+ (3743, 'MMMDCCXLIII'),
+ (3844, 'MMMDCCCXLIV'),
+ (3888, 'MMMDCCCLXXXVIII'),
+ (3940, 'MMMCMXL'),
+ (3999, 'MMMCMXCIX'))
+
+ def testToRomanKnownValues(self):
+ """toRoman should give known result with known input"""
+ for integer, numeral in self.knownValues:
+ result = roman1.toRoman(integer)
+ self.assertEqual(numeral, result)
+
+ def testFromRomanKnownValues(self):
+ """fromRoman should give known result with known input"""
+ for integer, numeral in self.knownValues:
+ result = roman1.fromRoman(numeral)
+ self.assertEqual(integer, result)
+
+class ToRomanBadInput(unittest.TestCase):
+ def testTooLarge(self):
+ """toRoman should fail with large input"""
+ self.assertRaises(roman1.OutOfRangeError, roman1.toRoman, 4000)
+
+ def testZero(self):
+ """toRoman should fail with 0 input"""
+ self.assertRaises(roman1.OutOfRangeError, roman1.toRoman, 0)
+
+ def testNegative(self):
+ """toRoman should fail with negative input"""
+ self.assertRaises(roman1.OutOfRangeError, roman1.toRoman, -1)
+
+ def testNonInteger(self):
+ """toRoman should fail with non-integer input"""
+ self.assertRaises(roman1.NotIntegerError, roman1.toRoman, 0.5)
+
+class FromRomanBadInput(unittest.TestCase):
+ def testTooManyRepeatedNumerals(self):
+ """fromRoman should fail with too many repeated numerals"""
+ for s in ('MMMM', 'DD', 'CCCC', 'LL', 'XXXX', 'VV', 'IIII'):
+ self.assertRaises(roman1.InvalidRomanNumeralError, roman1.fromRoman, s)
+
+ def testRepeatedPairs(self):
+ """fromRoman should fail with repeated pairs of numerals"""
+ for s in ('CMCM', 'CDCD', 'XCXC', 'XLXL', 'IXIX', 'IVIV'):
+ self.assertRaises(roman1.InvalidRomanNumeralError, roman1.fromRoman, s)
+
+ def testMalformedAntecedent(self):
+ """fromRoman should fail with malformed antecedents"""
+ for s in ('IIMXCC', 'VX', 'DCM', 'CMM', 'IXIV',
+ 'MCMC', 'XCX', 'IVI', 'LM', 'LD', 'LC'):
+ self.assertRaises(roman1.InvalidRomanNumeralError, roman1.fromRoman, s)
+
+class SanityCheck(unittest.TestCase):
+ def testSanity(self):
+ """fromRoman(toRoman(n))==n for all n"""
+ for integer in range(1, 4000):
+ numeral = roman1.toRoman(integer)
+ result = roman1.fromRoman(numeral)
+ self.assertEqual(integer, result)
+
+class CaseCheck(unittest.TestCase):
+ def testToRomanCase(self):
+ """toRoman should always return uppercase"""
+ for integer in range(1, 4000):
+ numeral = roman1.toRoman(integer)
+ self.assertEqual(numeral, numeral.upper())
+
+ def testFromRomanCase(self):
+ """fromRoman should only accept uppercase input"""
+ for integer in range(1, 4000):
+ numeral = roman1.toRoman(integer)
+ roman1.fromRoman(numeral.upper())
+ self.assertRaises(roman1.InvalidRomanNumeralError,
+ roman1.fromRoman, numeral.lower())
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/help/diveintopython-5.4/py/roman/stage2/roman2.py b/help/diveintopython-5.4/py/roman/stage2/roman2.py
new file mode 100644
index 0000000..929ee82
--- /dev/null
+++ b/help/diveintopython-5.4/py/roman/stage2/roman2.py
@@ -0,0 +1,46 @@
+"""Convert to and from Roman numerals
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.2 $"
+__date__ = "$Date: 2004/05/05 21:57:20 $"
+__copyright__ = "Copyright (c) 2001 Mark Pilgrim"
+__license__ = "Python"
+
+#Define exceptions
+class RomanError(Exception): pass
+class OutOfRangeError(RomanError): pass
+class NotIntegerError(RomanError): pass
+class InvalidRomanNumeralError(RomanError): pass
+
+#Define digit mapping
+romanNumeralMap = (('M', 1000),
+ ('CM', 900),
+ ('D', 500),
+ ('CD', 400),
+ ('C', 100),
+ ('XC', 90),
+ ('L', 50),
+ ('XL', 40),
+ ('X', 10),
+ ('IX', 9),
+ ('V', 5),
+ ('IV', 4),
+ ('I', 1))
+
+def toRoman(n):
+ """convert integer to Roman numeral"""
+ result = ""
+ for numeral, integer in romanNumeralMap:
+ while n >= integer:
+ result += numeral
+ n -= integer
+ return result
+
+def fromRoman(s):
+ """convert Roman numeral to integer"""
+ pass
diff --git a/help/diveintopython-5.4/py/roman/stage2/romantest2.py b/help/diveintopython-5.4/py/roman/stage2/romantest2.py
new file mode 100644
index 0000000..7e58b37
--- /dev/null
+++ b/help/diveintopython-5.4/py/roman/stage2/romantest2.py
@@ -0,0 +1,145 @@
+"""Unit test for roman2.py
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.3 $"
+__date__ = "$Date: 2004/05/05 21:57:20 $"
+__copyright__ = "Copyright (c) 2001 Mark Pilgrim"
+__license__ = "Python"
+
+import roman2
+import unittest
+
+class KnownValues(unittest.TestCase):
+ knownValues = ( (1, 'I'),
+ (2, 'II'),
+ (3, 'III'),
+ (4, 'IV'),
+ (5, 'V'),
+ (6, 'VI'),
+ (7, 'VII'),
+ (8, 'VIII'),
+ (9, 'IX'),
+ (10, 'X'),
+ (50, 'L'),
+ (100, 'C'),
+ (500, 'D'),
+ (1000, 'M'),
+ (31, 'XXXI'),
+ (148, 'CXLVIII'),
+ (294, 'CCXCIV'),
+ (312, 'CCCXII'),
+ (421, 'CDXXI'),
+ (528, 'DXXVIII'),
+ (621, 'DCXXI'),
+ (782, 'DCCLXXXII'),
+ (870, 'DCCCLXX'),
+ (941, 'CMXLI'),
+ (1043, 'MXLIII'),
+ (1110, 'MCX'),
+ (1226, 'MCCXXVI'),
+ (1301, 'MCCCI'),
+ (1485, 'MCDLXXXV'),
+ (1509, 'MDIX'),
+ (1607, 'MDCVII'),
+ (1754, 'MDCCLIV'),
+ (1832, 'MDCCCXXXII'),
+ (1993, 'MCMXCIII'),
+ (2074, 'MMLXXIV'),
+ (2152, 'MMCLII'),
+ (2212, 'MMCCXII'),
+ (2343, 'MMCCCXLIII'),
+ (2499, 'MMCDXCIX'),
+ (2574, 'MMDLXXIV'),
+ (2646, 'MMDCXLVI'),
+ (2723, 'MMDCCXXIII'),
+ (2892, 'MMDCCCXCII'),
+ (2975, 'MMCMLXXV'),
+ (3051, 'MMMLI'),
+ (3185, 'MMMCLXXXV'),
+ (3250, 'MMMCCL'),
+ (3313, 'MMMCCCXIII'),
+ (3408, 'MMMCDVIII'),
+ (3501, 'MMMDI'),
+ (3610, 'MMMDCX'),
+ (3743, 'MMMDCCXLIII'),
+ (3844, 'MMMDCCCXLIV'),
+ (3888, 'MMMDCCCLXXXVIII'),
+ (3940, 'MMMCMXL'),
+ (3999, 'MMMCMXCIX'))
+
+ def testToRomanKnownValues(self):
+ """toRoman should give known result with known input"""
+ for integer, numeral in self.knownValues:
+ result = roman2.toRoman(integer)
+ self.assertEqual(numeral, result)
+
+ def testFromRomanKnownValues(self):
+ """fromRoman should give known result with known input"""
+ for integer, numeral in self.knownValues:
+ result = roman2.fromRoman(numeral)
+ self.assertEqual(integer, result)
+
+class ToRomanBadInput(unittest.TestCase):
+ def testTooLarge(self):
+ """toRoman should fail with large input"""
+ self.assertRaises(roman2.OutOfRangeError, roman2.toRoman, 4000)
+
+ def testZero(self):
+ """toRoman should fail with 0 input"""
+ self.assertRaises(roman2.OutOfRangeError, roman2.toRoman, 0)
+
+ def testNegative(self):
+ """toRoman should fail with negative input"""
+ self.assertRaises(roman2.OutOfRangeError, roman2.toRoman, -1)
+
+ def testNonInteger(self):
+ """toRoman should fail with non-integer input"""
+ self.assertRaises(roman2.NotIntegerError, roman2.toRoman, 0.5)
+
+class FromRomanBadInput(unittest.TestCase):
+ def testTooManyRepeatedNumerals(self):
+ """fromRoman should fail with too many repeated numerals"""
+ for s in ('MMMM', 'DD', 'CCCC', 'LL', 'XXXX', 'VV', 'IIII'):
+ self.assertRaises(roman2.InvalidRomanNumeralError, roman2.fromRoman, s)
+
+ def testRepeatedPairs(self):
+ """fromRoman should fail with repeated pairs of numerals"""
+ for s in ('CMCM', 'CDCD', 'XCXC', 'XLXL', 'IXIX', 'IVIV'):
+ self.assertRaises(roman2.InvalidRomanNumeralError, roman2.fromRoman, s)
+
+ def testMalformedAntecedent(self):
+ """fromRoman should fail with malformed antecedents"""
+ for s in ('IIMXCC', 'VX', 'DCM', 'CMM', 'IXIV',
+ 'MCMC', 'XCX', 'IVI', 'LM', 'LD', 'LC'):
+ self.assertRaises(roman2.InvalidRomanNumeralError, roman2.fromRoman, s)
+
+class SanityCheck(unittest.TestCase):
+ def testSanity(self):
+ """fromRoman(toRoman(n))==n for all n"""
+ for integer in range(1, 4000):
+ numeral = roman2.toRoman(integer)
+ result = roman2.fromRoman(numeral)
+ self.assertEqual(integer, result)
+
+class CaseCheck(unittest.TestCase):
+ def testToRomanCase(self):
+ """toRoman should always return uppercase"""
+ for integer in range(1, 4000):
+ numeral = roman2.toRoman(integer)
+ self.assertEqual(numeral, numeral.upper())
+
+ def testFromRomanCase(self):
+ """fromRoman should only accept uppercase input"""
+ for integer in range(1, 4000):
+ numeral = roman2.toRoman(integer)
+ roman2.fromRoman(numeral.upper())
+ self.assertRaises(roman2.InvalidRomanNumeralError,
+ roman2.fromRoman, numeral.lower())
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/help/diveintopython-5.4/py/roman/stage3/roman3.py b/help/diveintopython-5.4/py/roman/stage3/roman3.py
new file mode 100644
index 0000000..2d8d062
--- /dev/null
+++ b/help/diveintopython-5.4/py/roman/stage3/roman3.py
@@ -0,0 +1,51 @@
+"""Convert to and from Roman numerals
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.3 $"
+__date__ = "$Date: 2004/05/05 21:57:20 $"
+__copyright__ = "Copyright (c) 2001 Mark Pilgrim"
+__license__ = "Python"
+
+#Define exceptions
+class RomanError(Exception): pass
+class OutOfRangeError(RomanError): pass
+class NotIntegerError(RomanError): pass
+class InvalidRomanNumeralError(RomanError): pass
+
+#Define digit mapping
+romanNumeralMap = (('M', 1000),
+ ('CM', 900),
+ ('D', 500),
+ ('CD', 400),
+ ('C', 100),
+ ('XC', 90),
+ ('L', 50),
+ ('XL', 40),
+ ('X', 10),
+ ('IX', 9),
+ ('V', 5),
+ ('IV', 4),
+ ('I', 1))
+
+def toRoman(n):
+ """convert integer to Roman numeral"""
+ if not (0 < n < 4000):
+ raise OutOfRangeError, "number out of range (must be 1..3999)"
+ if int(n) <> n:
+ raise NotIntegerError, "non-integers can not be converted"
+
+ result = ""
+ for numeral, integer in romanNumeralMap:
+ while n >= integer:
+ result += numeral
+ n -= integer
+ return result
+
+def fromRoman(s):
+ """convert Roman numeral to integer"""
+ pass
diff --git a/help/diveintopython-5.4/py/roman/stage3/romantest3.py b/help/diveintopython-5.4/py/roman/stage3/romantest3.py
new file mode 100644
index 0000000..ee4695e
--- /dev/null
+++ b/help/diveintopython-5.4/py/roman/stage3/romantest3.py
@@ -0,0 +1,145 @@
+"""Unit test for roman3.py
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.3 $"
+__date__ = "$Date: 2004/05/05 21:57:20 $"
+__copyright__ = "Copyright (c) 2001 Mark Pilgrim"
+__license__ = "Python"
+
+import roman3
+import unittest
+
+class KnownValues(unittest.TestCase):
+ knownValues = ( (1, 'I'),
+ (2, 'II'),
+ (3, 'III'),
+ (4, 'IV'),
+ (5, 'V'),
+ (6, 'VI'),
+ (7, 'VII'),
+ (8, 'VIII'),
+ (9, 'IX'),
+ (10, 'X'),
+ (50, 'L'),
+ (100, 'C'),
+ (500, 'D'),
+ (1000, 'M'),
+ (31, 'XXXI'),
+ (148, 'CXLVIII'),
+ (294, 'CCXCIV'),
+ (312, 'CCCXII'),
+ (421, 'CDXXI'),
+ (528, 'DXXVIII'),
+ (621, 'DCXXI'),
+ (782, 'DCCLXXXII'),
+ (870, 'DCCCLXX'),
+ (941, 'CMXLI'),
+ (1043, 'MXLIII'),
+ (1110, 'MCX'),
+ (1226, 'MCCXXVI'),
+ (1301, 'MCCCI'),
+ (1485, 'MCDLXXXV'),
+ (1509, 'MDIX'),
+ (1607, 'MDCVII'),
+ (1754, 'MDCCLIV'),
+ (1832, 'MDCCCXXXII'),
+ (1993, 'MCMXCIII'),
+ (2074, 'MMLXXIV'),
+ (2152, 'MMCLII'),
+ (2212, 'MMCCXII'),
+ (2343, 'MMCCCXLIII'),
+ (2499, 'MMCDXCIX'),
+ (2574, 'MMDLXXIV'),
+ (2646, 'MMDCXLVI'),
+ (2723, 'MMDCCXXIII'),
+ (2892, 'MMDCCCXCII'),
+ (2975, 'MMCMLXXV'),
+ (3051, 'MMMLI'),
+ (3185, 'MMMCLXXXV'),
+ (3250, 'MMMCCL'),
+ (3313, 'MMMCCCXIII'),
+ (3408, 'MMMCDVIII'),
+ (3501, 'MMMDI'),
+ (3610, 'MMMDCX'),
+ (3743, 'MMMDCCXLIII'),
+ (3844, 'MMMDCCCXLIV'),
+ (3888, 'MMMDCCCLXXXVIII'),
+ (3940, 'MMMCMXL'),
+ (3999, 'MMMCMXCIX'))
+
+ def testToRomanKnownValues(self):
+ """toRoman should give known result with known input"""
+ for integer, numeral in self.knownValues:
+ result = roman3.toRoman(integer)
+ self.assertEqual(numeral, result)
+
+ def testFromRomanKnownValues(self):
+ """fromRoman should give known result with known input"""
+ for integer, numeral in self.knownValues:
+ result = roman3.fromRoman(numeral)
+ self.assertEqual(integer, result)
+
+class ToRomanBadInput(unittest.TestCase):
+ def testTooLarge(self):
+ """toRoman should fail with large input"""
+ self.assertRaises(roman3.OutOfRangeError, roman3.toRoman, 4000)
+
+ def testZero(self):
+ """toRoman should fail with 0 input"""
+ self.assertRaises(roman3.OutOfRangeError, roman3.toRoman, 0)
+
+ def testNegative(self):
+ """toRoman should fail with negative input"""
+ self.assertRaises(roman3.OutOfRangeError, roman3.toRoman, -1)
+
+ def testNonInteger(self):
+ """toRoman should fail with non-integer input"""
+ self.assertRaises(roman3.NotIntegerError, roman3.toRoman, 0.5)
+
+class FromRomanBadInput(unittest.TestCase):
+ def testTooManyRepeatedNumerals(self):
+ """fromRoman should fail with too many repeated numerals"""
+ for s in ('MMMM', 'DD', 'CCCC', 'LL', 'XXXX', 'VV', 'IIII'):
+ self.assertRaises(roman3.InvalidRomanNumeralError, roman3.fromRoman, s)
+
+ def testRepeatedPairs(self):
+ """fromRoman should fail with repeated pairs of numerals"""
+ for s in ('CMCM', 'CDCD', 'XCXC', 'XLXL', 'IXIX', 'IVIV'):
+ self.assertRaises(roman3.InvalidRomanNumeralError, roman3.fromRoman, s)
+
+ def testMalformedAntecedent(self):
+ """fromRoman should fail with malformed antecedents"""
+ for s in ('IIMXCC', 'VX', 'DCM', 'CMM', 'IXIV',
+ 'MCMC', 'XCX', 'IVI', 'LM', 'LD', 'LC'):
+ self.assertRaises(roman3.InvalidRomanNumeralError, roman3.fromRoman, s)
+
+class SanityCheck(unittest.TestCase):
+ def testSanity(self):
+ """fromRoman(toRoman(n))==n for all n"""
+ for integer in range(1, 4000):
+ numeral = roman3.toRoman(integer)
+ result = roman3.fromRoman(numeral)
+ self.assertEqual(integer, result)
+
+class CaseCheck(unittest.TestCase):
+ def testToRomanCase(self):
+ """toRoman should always return uppercase"""
+ for integer in range(1, 4000):
+ numeral = roman3.toRoman(integer)
+ self.assertEqual(numeral, numeral.upper())
+
+ def testFromRomanCase(self):
+ """fromRoman should only accept uppercase input"""
+ for integer in range(1, 4000):
+ numeral = roman3.toRoman(integer)
+ roman3.fromRoman(numeral.upper())
+ self.assertRaises(roman3.InvalidRomanNumeralError,
+ roman3.fromRoman, numeral.lower())
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/help/diveintopython-5.4/py/roman/stage4/roman4.py b/help/diveintopython-5.4/py/roman/stage4/roman4.py
new file mode 100644
index 0000000..edeab70
--- /dev/null
+++ b/help/diveintopython-5.4/py/roman/stage4/roman4.py
@@ -0,0 +1,57 @@
+"""Convert to and from Roman numerals
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.3 $"
+__date__ = "$Date: 2004/05/05 21:57:20 $"
+__copyright__ = "Copyright (c) 2001 Mark Pilgrim"
+__license__ = "Python"
+
+#Define exceptions
+class RomanError(Exception): pass
+class OutOfRangeError(RomanError): pass
+class NotIntegerError(RomanError): pass
+class InvalidRomanNumeralError(RomanError): pass
+
+#Define digit mapping
+romanNumeralMap = (('M', 1000),
+ ('CM', 900),
+ ('D', 500),
+ ('CD', 400),
+ ('C', 100),
+ ('XC', 90),
+ ('L', 50),
+ ('XL', 40),
+ ('X', 10),
+ ('IX', 9),
+ ('V', 5),
+ ('IV', 4),
+ ('I', 1))
+
+def toRoman(n):
+ """convert integer to Roman numeral"""
+ if not (0 < n < 4000):
+ raise OutOfRangeError, "number out of range (must be 1..3999)"
+ if int(n) <> n:
+ raise NotIntegerError, "non-integers can not be converted"
+
+ result = ""
+ for numeral, integer in romanNumeralMap:
+ while n >= integer:
+ result += numeral
+ n -= integer
+ return result
+
+def fromRoman(s):
+ """convert Roman numeral to integer"""
+ result = 0
+ index = 0
+ for numeral, integer in romanNumeralMap:
+ while s[index:index+len(numeral)] == numeral:
+ result += integer
+ index += len(numeral)
+ return result
diff --git a/help/diveintopython-5.4/py/roman/stage4/romantest4.py b/help/diveintopython-5.4/py/roman/stage4/romantest4.py
new file mode 100644
index 0000000..887ccc7
--- /dev/null
+++ b/help/diveintopython-5.4/py/roman/stage4/romantest4.py
@@ -0,0 +1,145 @@
+"""Unit test for roman4.py
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.3 $"
+__date__ = "$Date: 2004/05/05 21:57:20 $"
+__copyright__ = "Copyright (c) 2001 Mark Pilgrim"
+__license__ = "Python"
+
+import roman4
+import unittest
+
+class KnownValues(unittest.TestCase):
+ knownValues = ( (1, 'I'),
+ (2, 'II'),
+ (3, 'III'),
+ (4, 'IV'),
+ (5, 'V'),
+ (6, 'VI'),
+ (7, 'VII'),
+ (8, 'VIII'),
+ (9, 'IX'),
+ (10, 'X'),
+ (50, 'L'),
+ (100, 'C'),
+ (500, 'D'),
+ (1000, 'M'),
+ (31, 'XXXI'),
+ (148, 'CXLVIII'),
+ (294, 'CCXCIV'),
+ (312, 'CCCXII'),
+ (421, 'CDXXI'),
+ (528, 'DXXVIII'),
+ (621, 'DCXXI'),
+ (782, 'DCCLXXXII'),
+ (870, 'DCCCLXX'),
+ (941, 'CMXLI'),
+ (1043, 'MXLIII'),
+ (1110, 'MCX'),
+ (1226, 'MCCXXVI'),
+ (1301, 'MCCCI'),
+ (1485, 'MCDLXXXV'),
+ (1509, 'MDIX'),
+ (1607, 'MDCVII'),
+ (1754, 'MDCCLIV'),
+ (1832, 'MDCCCXXXII'),
+ (1993, 'MCMXCIII'),
+ (2074, 'MMLXXIV'),
+ (2152, 'MMCLII'),
+ (2212, 'MMCCXII'),
+ (2343, 'MMCCCXLIII'),
+ (2499, 'MMCDXCIX'),
+ (2574, 'MMDLXXIV'),
+ (2646, 'MMDCXLVI'),
+ (2723, 'MMDCCXXIII'),
+ (2892, 'MMDCCCXCII'),
+ (2975, 'MMCMLXXV'),
+ (3051, 'MMMLI'),
+ (3185, 'MMMCLXXXV'),
+ (3250, 'MMMCCL'),
+ (3313, 'MMMCCCXIII'),
+ (3408, 'MMMCDVIII'),
+ (3501, 'MMMDI'),
+ (3610, 'MMMDCX'),
+ (3743, 'MMMDCCXLIII'),
+ (3844, 'MMMDCCCXLIV'),
+ (3888, 'MMMDCCCLXXXVIII'),
+ (3940, 'MMMCMXL'),
+ (3999, 'MMMCMXCIX'))
+
+ def testToRomanKnownValues(self):
+ """toRoman should give known result with known input"""
+ for integer, numeral in self.knownValues:
+ result = roman4.toRoman(integer)
+ self.assertEqual(numeral, result)
+
+ def testFromRomanKnownValues(self):
+ """fromRoman should give known result with known input"""
+ for integer, numeral in self.knownValues:
+ result = roman4.fromRoman(numeral)
+ self.assertEqual(integer, result)
+
+class ToRomanBadInput(unittest.TestCase):
+ def testTooLarge(self):
+ """toRoman should fail with large input"""
+ self.assertRaises(roman4.OutOfRangeError, roman4.toRoman, 4000)
+
+ def testZero(self):
+ """toRoman should fail with 0 input"""
+ self.assertRaises(roman4.OutOfRangeError, roman4.toRoman, 0)
+
+ def testNegative(self):
+ """toRoman should fail with negative input"""
+ self.assertRaises(roman4.OutOfRangeError, roman4.toRoman, -1)
+
+ def testNonInteger(self):
+ """toRoman should fail with non-integer input"""
+ self.assertRaises(roman4.NotIntegerError, roman4.toRoman, 0.5)
+
+class FromRomanBadInput(unittest.TestCase):
+ def testTooManyRepeatedNumerals(self):
+ """fromRoman should fail with too many repeated numerals"""
+ for s in ('MMMM', 'DD', 'CCCC', 'LL', 'XXXX', 'VV', 'IIII'):
+ self.assertRaises(roman4.InvalidRomanNumeralError, roman4.fromRoman, s)
+
+ def testRepeatedPairs(self):
+ """fromRoman should fail with repeated pairs of numerals"""
+ for s in ('CMCM', 'CDCD', 'XCXC', 'XLXL', 'IXIX', 'IVIV'):
+ self.assertRaises(roman4.InvalidRomanNumeralError, roman4.fromRoman, s)
+
+ def testMalformedAntecedent(self):
+ """fromRoman should fail with malformed antecedents"""
+ for s in ('IIMXCC', 'VX', 'DCM', 'CMM', 'IXIV',
+ 'MCMC', 'XCX', 'IVI', 'LM', 'LD', 'LC'):
+ self.assertRaises(roman4.InvalidRomanNumeralError, roman4.fromRoman, s)
+
+class SanityCheck(unittest.TestCase):
+ def testSanity(self):
+ """fromRoman(toRoman(n))==n for all n"""
+ for integer in range(1, 4000):
+ numeral = roman4.toRoman(integer)
+ result = roman4.fromRoman(numeral)
+ self.assertEqual(integer, result)
+
+class CaseCheck(unittest.TestCase):
+ def testToRomanCase(self):
+ """toRoman should always return uppercase"""
+ for integer in range(1, 4000):
+ numeral = roman4.toRoman(integer)
+ self.assertEqual(numeral, numeral.upper())
+
+ def testFromRomanCase(self):
+ """fromRoman should only accept uppercase input"""
+ for integer in range(1, 4000):
+ numeral = roman4.toRoman(integer)
+ roman4.fromRoman(numeral.upper())
+ self.assertRaises(roman4.InvalidRomanNumeralError,
+ roman4.fromRoman, numeral.lower())
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/help/diveintopython-5.4/py/roman/stage5/roman5.py b/help/diveintopython-5.4/py/roman/stage5/roman5.py
new file mode 100644
index 0000000..b4f0c1f
--- /dev/null
+++ b/help/diveintopython-5.4/py/roman/stage5/roman5.py
@@ -0,0 +1,65 @@
+"""Convert to and from Roman numerals
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.3 $"
+__date__ = "$Date: 2004/05/05 21:57:20 $"
+__copyright__ = "Copyright (c) 2001 Mark Pilgrim"
+__license__ = "Python"
+
+import re
+
+#Define exceptions
+class RomanError(Exception): pass
+class OutOfRangeError(RomanError): pass
+class NotIntegerError(RomanError): pass
+class InvalidRomanNumeralError(RomanError): pass
+
+#Define digit mapping
+romanNumeralMap = (('M', 1000),
+ ('CM', 900),
+ ('D', 500),
+ ('CD', 400),
+ ('C', 100),
+ ('XC', 90),
+ ('L', 50),
+ ('XL', 40),
+ ('X', 10),
+ ('IX', 9),
+ ('V', 5),
+ ('IV', 4),
+ ('I', 1))
+
+def toRoman(n):
+ """convert integer to Roman numeral"""
+ if not (0 < n < 4000):
+ raise OutOfRangeError, "number out of range (must be 1..3999)"
+ if int(n) <> n:
+ raise NotIntegerError, "non-integers can not be converted"
+
+ result = ""
+ for numeral, integer in romanNumeralMap:
+ while n >= integer:
+ result += numeral
+ n -= integer
+ return result
+
+#Define pattern to detect valid Roman numerals
+romanNumeralPattern = '^M?M?M?(CM|CD|D?C?C?C?)(XC|XL|L?X?X?X?)(IX|IV|V?I?I?I?)$'
+
+def fromRoman(s):
+ """convert Roman numeral to integer"""
+ if not re.search(romanNumeralPattern, s):
+ raise InvalidRomanNumeralError, 'Invalid Roman numeral: %s' % s
+
+ result = 0
+ index = 0
+ for numeral, integer in romanNumeralMap:
+ while s[index:index+len(numeral)] == numeral:
+ result += integer
+ index += len(numeral)
+ return result
diff --git a/help/diveintopython-5.4/py/roman/stage5/romantest5.py b/help/diveintopython-5.4/py/roman/stage5/romantest5.py
new file mode 100644
index 0000000..b0270a3
--- /dev/null
+++ b/help/diveintopython-5.4/py/roman/stage5/romantest5.py
@@ -0,0 +1,145 @@
+"""Unit test for roman5.py
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.3 $"
+__date__ = "$Date: 2004/05/05 21:57:20 $"
+__copyright__ = "Copyright (c) 2001 Mark Pilgrim"
+__license__ = "Python"
+
+import roman5
+import unittest
+
+class KnownValues(unittest.TestCase):
+ knownValues = ( (1, 'I'),
+ (2, 'II'),
+ (3, 'III'),
+ (4, 'IV'),
+ (5, 'V'),
+ (6, 'VI'),
+ (7, 'VII'),
+ (8, 'VIII'),
+ (9, 'IX'),
+ (10, 'X'),
+ (50, 'L'),
+ (100, 'C'),
+ (500, 'D'),
+ (1000, 'M'),
+ (31, 'XXXI'),
+ (148, 'CXLVIII'),
+ (294, 'CCXCIV'),
+ (312, 'CCCXII'),
+ (421, 'CDXXI'),
+ (528, 'DXXVIII'),
+ (621, 'DCXXI'),
+ (782, 'DCCLXXXII'),
+ (870, 'DCCCLXX'),
+ (941, 'CMXLI'),
+ (1043, 'MXLIII'),
+ (1110, 'MCX'),
+ (1226, 'MCCXXVI'),
+ (1301, 'MCCCI'),
+ (1485, 'MCDLXXXV'),
+ (1509, 'MDIX'),
+ (1607, 'MDCVII'),
+ (1754, 'MDCCLIV'),
+ (1832, 'MDCCCXXXII'),
+ (1993, 'MCMXCIII'),
+ (2074, 'MMLXXIV'),
+ (2152, 'MMCLII'),
+ (2212, 'MMCCXII'),
+ (2343, 'MMCCCXLIII'),
+ (2499, 'MMCDXCIX'),
+ (2574, 'MMDLXXIV'),
+ (2646, 'MMDCXLVI'),
+ (2723, 'MMDCCXXIII'),
+ (2892, 'MMDCCCXCII'),
+ (2975, 'MMCMLXXV'),
+ (3051, 'MMMLI'),
+ (3185, 'MMMCLXXXV'),
+ (3250, 'MMMCCL'),
+ (3313, 'MMMCCCXIII'),
+ (3408, 'MMMCDVIII'),
+ (3501, 'MMMDI'),
+ (3610, 'MMMDCX'),
+ (3743, 'MMMDCCXLIII'),
+ (3844, 'MMMDCCCXLIV'),
+ (3888, 'MMMDCCCLXXXVIII'),
+ (3940, 'MMMCMXL'),
+ (3999, 'MMMCMXCIX'))
+
+ def testToRomanKnownValues(self):
+ """toRoman should give known result with known input"""
+ for integer, numeral in self.knownValues:
+ result = roman5.toRoman(integer)
+ self.assertEqual(numeral, result)
+
+ def testFromRomanKnownValues(self):
+ """fromRoman should give known result with known input"""
+ for integer, numeral in self.knownValues:
+ result = roman5.fromRoman(numeral)
+ self.assertEqual(integer, result)
+
+class ToRomanBadInput(unittest.TestCase):
+ def testTooLarge(self):
+ """toRoman should fail with large input"""
+ self.assertRaises(roman5.OutOfRangeError, roman5.toRoman, 4000)
+
+ def testZero(self):
+ """toRoman should fail with 0 input"""
+ self.assertRaises(roman5.OutOfRangeError, roman5.toRoman, 0)
+
+ def testNegative(self):
+ """toRoman should fail with negative input"""
+ self.assertRaises(roman5.OutOfRangeError, roman5.toRoman, -1)
+
+ def testNonInteger(self):
+ """toRoman should fail with non-integer input"""
+ self.assertRaises(roman5.NotIntegerError, roman5.toRoman, 0.5)
+
+class FromRomanBadInput(unittest.TestCase):
+ def testTooManyRepeatedNumerals(self):
+ """fromRoman should fail with too many repeated numerals"""
+ for s in ('MMMM', 'DD', 'CCCC', 'LL', 'XXXX', 'VV', 'IIII'):
+ self.assertRaises(roman5.InvalidRomanNumeralError, roman5.fromRoman, s)
+
+ def testRepeatedPairs(self):
+ """fromRoman should fail with repeated pairs of numerals"""
+ for s in ('CMCM', 'CDCD', 'XCXC', 'XLXL', 'IXIX', 'IVIV'):
+ self.assertRaises(roman5.InvalidRomanNumeralError, roman5.fromRoman, s)
+
+ def testMalformedAntecedent(self):
+ """fromRoman should fail with malformed antecedents"""
+ for s in ('IIMXCC', 'VX', 'DCM', 'CMM', 'IXIV',
+ 'MCMC', 'XCX', 'IVI', 'LM', 'LD', 'LC'):
+ self.assertRaises(roman5.InvalidRomanNumeralError, roman5.fromRoman, s)
+
+class SanityCheck(unittest.TestCase):
+ def testSanity(self):
+ """fromRoman(toRoman(n))==n for all n"""
+ for integer in range(1, 4000):
+ numeral = roman5.toRoman(integer)
+ result = roman5.fromRoman(numeral)
+ self.assertEqual(integer, result)
+
+class CaseCheck(unittest.TestCase):
+ def testToRomanCase(self):
+ """toRoman should always return uppercase"""
+ for integer in range(1, 4000):
+ numeral = roman5.toRoman(integer)
+ self.assertEqual(numeral, numeral.upper())
+
+ def testFromRomanCase(self):
+ """fromRoman should only accept uppercase input"""
+ for integer in range(1, 4000):
+ numeral = roman5.toRoman(integer)
+ roman5.fromRoman(numeral.upper())
+ self.assertRaises(roman5.InvalidRomanNumeralError,
+ roman5.fromRoman, numeral.lower())
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/help/diveintopython-5.4/py/roman/stage6/roman61.py b/help/diveintopython-5.4/py/roman/stage6/roman61.py
new file mode 100644
index 0000000..b4f0c1f
--- /dev/null
+++ b/help/diveintopython-5.4/py/roman/stage6/roman61.py
@@ -0,0 +1,65 @@
+"""Convert to and from Roman numerals
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.3 $"
+__date__ = "$Date: 2004/05/05 21:57:20 $"
+__copyright__ = "Copyright (c) 2001 Mark Pilgrim"
+__license__ = "Python"
+
+import re
+
+#Define exceptions
+class RomanError(Exception): pass
+class OutOfRangeError(RomanError): pass
+class NotIntegerError(RomanError): pass
+class InvalidRomanNumeralError(RomanError): pass
+
+#Define digit mapping
+romanNumeralMap = (('M', 1000),
+ ('CM', 900),
+ ('D', 500),
+ ('CD', 400),
+ ('C', 100),
+ ('XC', 90),
+ ('L', 50),
+ ('XL', 40),
+ ('X', 10),
+ ('IX', 9),
+ ('V', 5),
+ ('IV', 4),
+ ('I', 1))
+
+def toRoman(n):
+ """convert integer to Roman numeral"""
+ if not (0 < n < 4000):
+ raise OutOfRangeError, "number out of range (must be 1..3999)"
+ if int(n) <> n:
+ raise NotIntegerError, "non-integers can not be converted"
+
+ result = ""
+ for numeral, integer in romanNumeralMap:
+ while n >= integer:
+ result += numeral
+ n -= integer
+ return result
+
+#Define pattern to detect valid Roman numerals
+romanNumeralPattern = '^M?M?M?(CM|CD|D?C?C?C?)(XC|XL|L?X?X?X?)(IX|IV|V?I?I?I?)$'
+
+def fromRoman(s):
+ """convert Roman numeral to integer"""
+ if not re.search(romanNumeralPattern, s):
+ raise InvalidRomanNumeralError, 'Invalid Roman numeral: %s' % s
+
+ result = 0
+ index = 0
+ for numeral, integer in romanNumeralMap:
+ while s[index:index+len(numeral)] == numeral:
+ result += integer
+ index += len(numeral)
+ return result
diff --git a/help/diveintopython-5.4/py/roman/stage6/roman62.py b/help/diveintopython-5.4/py/roman/stage6/roman62.py
new file mode 100644
index 0000000..5181582
--- /dev/null
+++ b/help/diveintopython-5.4/py/roman/stage6/roman62.py
@@ -0,0 +1,67 @@
+"""Convert to and from Roman numerals
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.3 $"
+__date__ = "$Date: 2004/05/05 21:57:20 $"
+__copyright__ = "Copyright (c) 2001 Mark Pilgrim"
+__license__ = "Python"
+
+import re
+
+#Define exceptions
+class RomanError(Exception): pass
+class OutOfRangeError(RomanError): pass
+class NotIntegerError(RomanError): pass
+class InvalidRomanNumeralError(RomanError): pass
+
+#Define digit mapping
+romanNumeralMap = (('M', 1000),
+ ('CM', 900),
+ ('D', 500),
+ ('CD', 400),
+ ('C', 100),
+ ('XC', 90),
+ ('L', 50),
+ ('XL', 40),
+ ('X', 10),
+ ('IX', 9),
+ ('V', 5),
+ ('IV', 4),
+ ('I', 1))
+
+def toRoman(n):
+ """convert integer to Roman numeral"""
+ if not (0 < n < 4000):
+ raise OutOfRangeError, "number out of range (must be 1..3999)"
+ if int(n) <> n:
+ raise NotIntegerError, "non-integers can not be converted"
+
+ result = ""
+ for numeral, integer in romanNumeralMap:
+ while n >= integer:
+ result += numeral
+ n -= integer
+ return result
+
+#Define pattern to detect valid Roman numerals
+romanNumeralPattern = '^M?M?M?(CM|CD|D?C?C?C?)(XC|XL|L?X?X?X?)(IX|IV|V?I?I?I?)$'
+
+def fromRoman(s):
+ """convert Roman numeral to integer"""
+ if not s:
+ raise InvalidRomanNumeralError, 'Input can not be blank'
+ if not re.search(romanNumeralPattern, s):
+ raise InvalidRomanNumeralError, 'Invalid Roman numeral: %s' % s
+
+ result = 0
+ index = 0
+ for numeral, integer in romanNumeralMap:
+ while s[index:index+len(numeral)] == numeral:
+ result += integer
+ index += len(numeral)
+ return result
diff --git a/help/diveintopython-5.4/py/roman/stage6/romantest61.py b/help/diveintopython-5.4/py/roman/stage6/romantest61.py
new file mode 100644
index 0000000..5f960cc
--- /dev/null
+++ b/help/diveintopython-5.4/py/roman/stage6/romantest61.py
@@ -0,0 +1,149 @@
+"""Unit test for roman61.py
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.3 $"
+__date__ = "$Date: 2004/05/05 21:57:20 $"
+__copyright__ = "Copyright (c) 2001 Mark Pilgrim"
+__license__ = "Python"
+
+import roman61
+import unittest
+
+class KnownValues(unittest.TestCase):
+ knownValues = ( (1, 'I'),
+ (2, 'II'),
+ (3, 'III'),
+ (4, 'IV'),
+ (5, 'V'),
+ (6, 'VI'),
+ (7, 'VII'),
+ (8, 'VIII'),
+ (9, 'IX'),
+ (10, 'X'),
+ (50, 'L'),
+ (100, 'C'),
+ (500, 'D'),
+ (1000, 'M'),
+ (31, 'XXXI'),
+ (148, 'CXLVIII'),
+ (294, 'CCXCIV'),
+ (312, 'CCCXII'),
+ (421, 'CDXXI'),
+ (528, 'DXXVIII'),
+ (621, 'DCXXI'),
+ (782, 'DCCLXXXII'),
+ (870, 'DCCCLXX'),
+ (941, 'CMXLI'),
+ (1043, 'MXLIII'),
+ (1110, 'MCX'),
+ (1226, 'MCCXXVI'),
+ (1301, 'MCCCI'),
+ (1485, 'MCDLXXXV'),
+ (1509, 'MDIX'),
+ (1607, 'MDCVII'),
+ (1754, 'MDCCLIV'),
+ (1832, 'MDCCCXXXII'),
+ (1993, 'MCMXCIII'),
+ (2074, 'MMLXXIV'),
+ (2152, 'MMCLII'),
+ (2212, 'MMCCXII'),
+ (2343, 'MMCCCXLIII'),
+ (2499, 'MMCDXCIX'),
+ (2574, 'MMDLXXIV'),
+ (2646, 'MMDCXLVI'),
+ (2723, 'MMDCCXXIII'),
+ (2892, 'MMDCCCXCII'),
+ (2975, 'MMCMLXXV'),
+ (3051, 'MMMLI'),
+ (3185, 'MMMCLXXXV'),
+ (3250, 'MMMCCL'),
+ (3313, 'MMMCCCXIII'),
+ (3408, 'MMMCDVIII'),
+ (3501, 'MMMDI'),
+ (3610, 'MMMDCX'),
+ (3743, 'MMMDCCXLIII'),
+ (3844, 'MMMDCCCXLIV'),
+ (3888, 'MMMDCCCLXXXVIII'),
+ (3940, 'MMMCMXL'),
+ (3999, 'MMMCMXCIX'))
+
+ def testToRomanKnownValues(self):
+ """toRoman should give known result with known input"""
+ for integer, numeral in self.knownValues:
+ result = roman61.toRoman(integer)
+ self.assertEqual(numeral, result)
+
+ def testFromRomanKnownValues(self):
+ """fromRoman should give known result with known input"""
+ for integer, numeral in self.knownValues:
+ result = roman61.fromRoman(numeral)
+ self.assertEqual(integer, result)
+
+class ToRomanBadInput(unittest.TestCase):
+ def testTooLarge(self):
+ """toRoman should fail with large input"""
+ self.assertRaises(roman61.OutOfRangeError, roman61.toRoman, 4000)
+
+ def testZero(self):
+ """toRoman should fail with 0 input"""
+ self.assertRaises(roman61.OutOfRangeError, roman61.toRoman, 0)
+
+ def testNegative(self):
+ """toRoman should fail with negative input"""
+ self.assertRaises(roman61.OutOfRangeError, roman61.toRoman, -1)
+
+ def testNonInteger(self):
+ """toRoman should fail with non-integer input"""
+ self.assertRaises(roman61.NotIntegerError, roman61.toRoman, 0.5)
+
+class FromRomanBadInput(unittest.TestCase):
+ def testTooManyRepeatedNumerals(self):
+ """fromRoman should fail with too many repeated numerals"""
+ for s in ('MMMM', 'DD', 'CCCC', 'LL', 'XXXX', 'VV', 'IIII'):
+ self.assertRaises(roman61.InvalidRomanNumeralError, roman61.fromRoman, s)
+
+ def testRepeatedPairs(self):
+ """fromRoman should fail with repeated pairs of numerals"""
+ for s in ('CMCM', 'CDCD', 'XCXC', 'XLXL', 'IXIX', 'IVIV'):
+ self.assertRaises(roman61.InvalidRomanNumeralError, roman61.fromRoman, s)
+
+ def testMalformedAntecedent(self):
+ """fromRoman should fail with malformed antecedents"""
+ for s in ('IIMXCC', 'VX', 'DCM', 'CMM', 'IXIV',
+ 'MCMC', 'XCX', 'IVI', 'LM', 'LD', 'LC'):
+ self.assertRaises(roman61.InvalidRomanNumeralError, roman61.fromRoman, s)
+
+ def testBlank(self):
+ """fromRoman should fail with blank string"""
+ self.assertRaises(roman61.InvalidRomanNumeralError, roman61.fromRoman, "")
+
+class SanityCheck(unittest.TestCase):
+ def testSanity(self):
+ """fromRoman(toRoman(n))==n for all n"""
+ for integer in range(1, 4000):
+ numeral = roman61.toRoman(integer)
+ result = roman61.fromRoman(numeral)
+ self.assertEqual(integer, result)
+
+class CaseCheck(unittest.TestCase):
+ def testToRomanCase(self):
+ """toRoman should always return uppercase"""
+ for integer in range(1, 4000):
+ numeral = roman61.toRoman(integer)
+ self.assertEqual(numeral, numeral.upper())
+
+ def testFromRomanCase(self):
+ """fromRoman should only accept uppercase input"""
+ for integer in range(1, 4000):
+ numeral = roman61.toRoman(integer)
+ roman61.fromRoman(numeral.upper())
+ self.assertRaises(roman61.InvalidRomanNumeralError,
+ roman61.fromRoman, numeral.lower())
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/help/diveintopython-5.4/py/roman/stage6/romantest62.py b/help/diveintopython-5.4/py/roman/stage6/romantest62.py
new file mode 100644
index 0000000..71a5c0f
--- /dev/null
+++ b/help/diveintopython-5.4/py/roman/stage6/romantest62.py
@@ -0,0 +1,149 @@
+"""Unit test for roman62.py
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.3 $"
+__date__ = "$Date: 2004/05/05 21:57:20 $"
+__copyright__ = "Copyright (c) 2001 Mark Pilgrim"
+__license__ = "Python"
+
+import roman62
+import unittest
+
+class KnownValues(unittest.TestCase):
+ knownValues = ( (1, 'I'),
+ (2, 'II'),
+ (3, 'III'),
+ (4, 'IV'),
+ (5, 'V'),
+ (6, 'VI'),
+ (7, 'VII'),
+ (8, 'VIII'),
+ (9, 'IX'),
+ (10, 'X'),
+ (50, 'L'),
+ (100, 'C'),
+ (500, 'D'),
+ (1000, 'M'),
+ (31, 'XXXI'),
+ (148, 'CXLVIII'),
+ (294, 'CCXCIV'),
+ (312, 'CCCXII'),
+ (421, 'CDXXI'),
+ (528, 'DXXVIII'),
+ (621, 'DCXXI'),
+ (782, 'DCCLXXXII'),
+ (870, 'DCCCLXX'),
+ (941, 'CMXLI'),
+ (1043, 'MXLIII'),
+ (1110, 'MCX'),
+ (1226, 'MCCXXVI'),
+ (1301, 'MCCCI'),
+ (1485, 'MCDLXXXV'),
+ (1509, 'MDIX'),
+ (1607, 'MDCVII'),
+ (1754, 'MDCCLIV'),
+ (1832, 'MDCCCXXXII'),
+ (1993, 'MCMXCIII'),
+ (2074, 'MMLXXIV'),
+ (2152, 'MMCLII'),
+ (2212, 'MMCCXII'),
+ (2343, 'MMCCCXLIII'),
+ (2499, 'MMCDXCIX'),
+ (2574, 'MMDLXXIV'),
+ (2646, 'MMDCXLVI'),
+ (2723, 'MMDCCXXIII'),
+ (2892, 'MMDCCCXCII'),
+ (2975, 'MMCMLXXV'),
+ (3051, 'MMMLI'),
+ (3185, 'MMMCLXXXV'),
+ (3250, 'MMMCCL'),
+ (3313, 'MMMCCCXIII'),
+ (3408, 'MMMCDVIII'),
+ (3501, 'MMMDI'),
+ (3610, 'MMMDCX'),
+ (3743, 'MMMDCCXLIII'),
+ (3844, 'MMMDCCCXLIV'),
+ (3888, 'MMMDCCCLXXXVIII'),
+ (3940, 'MMMCMXL'),
+ (3999, 'MMMCMXCIX'))
+
+ def testToRomanKnownValues(self):
+ """toRoman should give known result with known input"""
+ for integer, numeral in self.knownValues:
+ result = roman62.toRoman(integer)
+ self.assertEqual(numeral, result)
+
+ def testFromRomanKnownValues(self):
+ """fromRoman should give known result with known input"""
+ for integer, numeral in self.knownValues:
+ result = roman62.fromRoman(numeral)
+ self.assertEqual(integer, result)
+
+class ToRomanBadInput(unittest.TestCase):
+ def testTooLarge(self):
+ """toRoman should fail with large input"""
+ self.assertRaises(roman62.OutOfRangeError, roman62.toRoman, 4000)
+
+ def testZero(self):
+ """toRoman should fail with 0 input"""
+ self.assertRaises(roman62.OutOfRangeError, roman62.toRoman, 0)
+
+ def testNegative(self):
+ """toRoman should fail with negative input"""
+ self.assertRaises(roman62.OutOfRangeError, roman62.toRoman, -1)
+
+ def testNonInteger(self):
+ """toRoman should fail with non-integer input"""
+ self.assertRaises(roman62.NotIntegerError, roman62.toRoman, 0.5)
+
+class FromRomanBadInput(unittest.TestCase):
+ def testTooManyRepeatedNumerals(self):
+ """fromRoman should fail with too many repeated numerals"""
+ for s in ('MMMM', 'DD', 'CCCC', 'LL', 'XXXX', 'VV', 'IIII'):
+ self.assertRaises(roman62.InvalidRomanNumeralError, roman62.fromRoman, s)
+
+ def testRepeatedPairs(self):
+ """fromRoman should fail with repeated pairs of numerals"""
+ for s in ('CMCM', 'CDCD', 'XCXC', 'XLXL', 'IXIX', 'IVIV'):
+ self.assertRaises(roman62.InvalidRomanNumeralError, roman62.fromRoman, s)
+
+ def testMalformedAntecedent(self):
+ """fromRoman should fail with malformed antecedents"""
+ for s in ('IIMXCC', 'VX', 'DCM', 'CMM', 'IXIV',
+ 'MCMC', 'XCX', 'IVI', 'LM', 'LD', 'LC'):
+ self.assertRaises(roman62.InvalidRomanNumeralError, roman62.fromRoman, s)
+
+ def testBlank(self):
+ """fromRoman should fail with blank string"""
+ self.assertRaises(roman62.InvalidRomanNumeralError, roman62.fromRoman, "")
+
+class SanityCheck(unittest.TestCase):
+ def testSanity(self):
+ """fromRoman(toRoman(n))==n for all n"""
+ for integer in range(1, 4000):
+ numeral = roman62.toRoman(integer)
+ result = roman62.fromRoman(numeral)
+ self.assertEqual(integer, result)
+
+class CaseCheck(unittest.TestCase):
+ def testToRomanCase(self):
+ """toRoman should always return uppercase"""
+ for integer in range(1, 4000):
+ numeral = roman62.toRoman(integer)
+ self.assertEqual(numeral, numeral.upper())
+
+ def testFromRomanCase(self):
+ """fromRoman should only accept uppercase input"""
+ for integer in range(1, 4000):
+ numeral = roman62.toRoman(integer)
+ roman62.fromRoman(numeral.upper())
+ self.assertRaises(roman62.InvalidRomanNumeralError,
+ roman62.fromRoman, numeral.lower())
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/help/diveintopython-5.4/py/roman/stage7/roman71.py b/help/diveintopython-5.4/py/roman/stage7/roman71.py
new file mode 100644
index 0000000..5181582
--- /dev/null
+++ b/help/diveintopython-5.4/py/roman/stage7/roman71.py
@@ -0,0 +1,67 @@
+"""Convert to and from Roman numerals
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.3 $"
+__date__ = "$Date: 2004/05/05 21:57:20 $"
+__copyright__ = "Copyright (c) 2001 Mark Pilgrim"
+__license__ = "Python"
+
+import re
+
+#Define exceptions
+class RomanError(Exception): pass
+class OutOfRangeError(RomanError): pass
+class NotIntegerError(RomanError): pass
+class InvalidRomanNumeralError(RomanError): pass
+
+#Define digit mapping
+romanNumeralMap = (('M', 1000),
+ ('CM', 900),
+ ('D', 500),
+ ('CD', 400),
+ ('C', 100),
+ ('XC', 90),
+ ('L', 50),
+ ('XL', 40),
+ ('X', 10),
+ ('IX', 9),
+ ('V', 5),
+ ('IV', 4),
+ ('I', 1))
+
+def toRoman(n):
+ """convert integer to Roman numeral"""
+ if not (0 < n < 4000):
+ raise OutOfRangeError, "number out of range (must be 1..3999)"
+ if int(n) <> n:
+ raise NotIntegerError, "non-integers can not be converted"
+
+ result = ""
+ for numeral, integer in romanNumeralMap:
+ while n >= integer:
+ result += numeral
+ n -= integer
+ return result
+
+#Define pattern to detect valid Roman numerals
+romanNumeralPattern = '^M?M?M?(CM|CD|D?C?C?C?)(XC|XL|L?X?X?X?)(IX|IV|V?I?I?I?)$'
+
+def fromRoman(s):
+ """convert Roman numeral to integer"""
+ if not s:
+ raise InvalidRomanNumeralError, 'Input can not be blank'
+ if not re.search(romanNumeralPattern, s):
+ raise InvalidRomanNumeralError, 'Invalid Roman numeral: %s' % s
+
+ result = 0
+ index = 0
+ for numeral, integer in romanNumeralMap:
+ while s[index:index+len(numeral)] == numeral:
+ result += integer
+ index += len(numeral)
+ return result
diff --git a/help/diveintopython-5.4/py/roman/stage7/roman72.py b/help/diveintopython-5.4/py/roman/stage7/roman72.py
new file mode 100644
index 0000000..68ebf87
--- /dev/null
+++ b/help/diveintopython-5.4/py/roman/stage7/roman72.py
@@ -0,0 +1,67 @@
+"""Convert to and from Roman numerals
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.3 $"
+__date__ = "$Date: 2004/05/05 21:57:20 $"
+__copyright__ = "Copyright (c) 2001 Mark Pilgrim"
+__license__ = "Python"
+
+import re
+
+#Define exceptions
+class RomanError(Exception): pass
+class OutOfRangeError(RomanError): pass
+class NotIntegerError(RomanError): pass
+class InvalidRomanNumeralError(RomanError): pass
+
+#Define digit mapping
+romanNumeralMap = (('M', 1000),
+ ('CM', 900),
+ ('D', 500),
+ ('CD', 400),
+ ('C', 100),
+ ('XC', 90),
+ ('L', 50),
+ ('XL', 40),
+ ('X', 10),
+ ('IX', 9),
+ ('V', 5),
+ ('IV', 4),
+ ('I', 1))
+
+def toRoman(n):
+ """convert integer to Roman numeral"""
+ if not (0 < n < 5000):
+ raise OutOfRangeError, "number out of range (must be 1..4999)"
+ if int(n) <> n:
+ raise NotIntegerError, "non-integers can not be converted"
+
+ result = ""
+ for numeral, integer in romanNumeralMap:
+ while n >= integer:
+ result += numeral
+ n -= integer
+ return result
+
+#Define pattern to detect valid Roman numerals
+romanNumeralPattern = '^M?M?M?M?(CM|CD|D?C?C?C?)(XC|XL|L?X?X?X?)(IX|IV|V?I?I?I?)$'
+
+def fromRoman(s):
+ """convert Roman numeral to integer"""
+ if not s:
+ raise InvalidRomanNumeralError, 'Input can not be blank'
+ if not re.search(romanNumeralPattern, s):
+ raise InvalidRomanNumeralError, 'Invalid Roman numeral: %s' % s
+
+ result = 0
+ index = 0
+ for numeral, integer in romanNumeralMap:
+ while s[index:index+len(numeral)] == numeral:
+ result += integer
+ index += len(numeral)
+ return result
diff --git a/help/diveintopython-5.4/py/roman/stage7/romantest71.py b/help/diveintopython-5.4/py/roman/stage7/romantest71.py
new file mode 100644
index 0000000..c1e8fc8
--- /dev/null
+++ b/help/diveintopython-5.4/py/roman/stage7/romantest71.py
@@ -0,0 +1,153 @@
+"""Unit test for roman71.py
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.3 $"
+__date__ = "$Date: 2004/05/05 21:57:20 $"
+__copyright__ = "Copyright (c) 2001 Mark Pilgrim"
+__license__ = "Python"
+
+import roman71
+import unittest
+
+class KnownValues(unittest.TestCase):
+ knownValues = ( (1, 'I'),
+ (2, 'II'),
+ (3, 'III'),
+ (4, 'IV'),
+ (5, 'V'),
+ (6, 'VI'),
+ (7, 'VII'),
+ (8, 'VIII'),
+ (9, 'IX'),
+ (10, 'X'),
+ (50, 'L'),
+ (100, 'C'),
+ (500, 'D'),
+ (1000, 'M'),
+ (31, 'XXXI'),
+ (148, 'CXLVIII'),
+ (294, 'CCXCIV'),
+ (312, 'CCCXII'),
+ (421, 'CDXXI'),
+ (528, 'DXXVIII'),
+ (621, 'DCXXI'),
+ (782, 'DCCLXXXII'),
+ (870, 'DCCCLXX'),
+ (941, 'CMXLI'),
+ (1043, 'MXLIII'),
+ (1110, 'MCX'),
+ (1226, 'MCCXXVI'),
+ (1301, 'MCCCI'),
+ (1485, 'MCDLXXXV'),
+ (1509, 'MDIX'),
+ (1607, 'MDCVII'),
+ (1754, 'MDCCLIV'),
+ (1832, 'MDCCCXXXII'),
+ (1993, 'MCMXCIII'),
+ (2074, 'MMLXXIV'),
+ (2152, 'MMCLII'),
+ (2212, 'MMCCXII'),
+ (2343, 'MMCCCXLIII'),
+ (2499, 'MMCDXCIX'),
+ (2574, 'MMDLXXIV'),
+ (2646, 'MMDCXLVI'),
+ (2723, 'MMDCCXXIII'),
+ (2892, 'MMDCCCXCII'),
+ (2975, 'MMCMLXXV'),
+ (3051, 'MMMLI'),
+ (3185, 'MMMCLXXXV'),
+ (3250, 'MMMCCL'),
+ (3313, 'MMMCCCXIII'),
+ (3408, 'MMMCDVIII'),
+ (3501, 'MMMDI'),
+ (3610, 'MMMDCX'),
+ (3743, 'MMMDCCXLIII'),
+ (3844, 'MMMDCCCXLIV'),
+ (3888, 'MMMDCCCLXXXVIII'),
+ (3940, 'MMMCMXL'),
+ (3999, 'MMMCMXCIX'),
+ (4000, 'MMMM'),
+ (4500, 'MMMMD'),
+ (4888, 'MMMMDCCCLXXXVIII'),
+ (4999, 'MMMMCMXCIX'))
+
+ def testToRomanKnownValues(self):
+ """toRoman should give known result with known input"""
+ for integer, numeral in self.knownValues:
+ result = roman71.toRoman(integer)
+ self.assertEqual(numeral, result)
+
+ def testFromRomanKnownValues(self):
+ """fromRoman should give known result with known input"""
+ for integer, numeral in self.knownValues:
+ result = roman71.fromRoman(numeral)
+ self.assertEqual(integer, result)
+
+class ToRomanBadInput(unittest.TestCase):
+ def testTooLarge(self):
+ """toRoman should fail with large input"""
+ self.assertRaises(roman71.OutOfRangeError, roman71.toRoman, 5000)
+
+ def testZero(self):
+ """toRoman should fail with 0 input"""
+ self.assertRaises(roman71.OutOfRangeError, roman71.toRoman, 0)
+
+ def testNegative(self):
+ """toRoman should fail with negative input"""
+ self.assertRaises(roman71.OutOfRangeError, roman71.toRoman, -1)
+
+ def testNonInteger(self):
+ """toRoman should fail with non-integer input"""
+ self.assertRaises(roman71.NotIntegerError, roman71.toRoman, 0.5)
+
+class FromRomanBadInput(unittest.TestCase):
+ def testTooManyRepeatedNumerals(self):
+ """fromRoman should fail with too many repeated numerals"""
+ for s in ('MMMMM', 'DD', 'CCCC', 'LL', 'XXXX', 'VV', 'IIII'):
+ self.assertRaises(roman71.InvalidRomanNumeralError, roman71.fromRoman, s)
+
+ def testRepeatedPairs(self):
+ """fromRoman should fail with repeated pairs of numerals"""
+ for s in ('CMCM', 'CDCD', 'XCXC', 'XLXL', 'IXIX', 'IVIV'):
+ self.assertRaises(roman71.InvalidRomanNumeralError, roman71.fromRoman, s)
+
+ def testMalformedAntecedent(self):
+ """fromRoman should fail with malformed antecedents"""
+ for s in ('IIMXCC', 'VX', 'DCM', 'CMM', 'IXIV',
+ 'MCMC', 'XCX', 'IVI', 'LM', 'LD', 'LC'):
+ self.assertRaises(roman71.InvalidRomanNumeralError, roman71.fromRoman, s)
+
+ def testBlank(self):
+ """fromRoman should fail with blank string"""
+ self.assertRaises(roman71.InvalidRomanNumeralError, roman71.fromRoman, "")
+
+class SanityCheck(unittest.TestCase):
+ def testSanity(self):
+ """fromRoman(toRoman(n))==n for all n"""
+ for integer in range(1, 5000):
+ numeral = roman71.toRoman(integer)
+ result = roman71.fromRoman(numeral)
+ self.assertEqual(integer, result)
+
+class CaseCheck(unittest.TestCase):
+ def testToRomanCase(self):
+ """toRoman should always return uppercase"""
+ for integer in range(1, 5000):
+ numeral = roman71.toRoman(integer)
+ self.assertEqual(numeral, numeral.upper())
+
+ def testFromRomanCase(self):
+ """fromRoman should only accept uppercase input"""
+ for integer in range(1, 5000):
+ numeral = roman71.toRoman(integer)
+ roman71.fromRoman(numeral.upper())
+ self.assertRaises(roman71.InvalidRomanNumeralError,
+ roman71.fromRoman, numeral.lower())
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/help/diveintopython-5.4/py/roman/stage7/romantest72.py b/help/diveintopython-5.4/py/roman/stage7/romantest72.py
new file mode 100644
index 0000000..f8375db
--- /dev/null
+++ b/help/diveintopython-5.4/py/roman/stage7/romantest72.py
@@ -0,0 +1,153 @@
+"""Unit test for roman72.py
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.3 $"
+__date__ = "$Date: 2004/05/05 21:57:20 $"
+__copyright__ = "Copyright (c) 2001 Mark Pilgrim"
+__license__ = "Python"
+
+import roman72
+import unittest
+
+class KnownValues(unittest.TestCase):
+ knownValues = ( (1, 'I'),
+ (2, 'II'),
+ (3, 'III'),
+ (4, 'IV'),
+ (5, 'V'),
+ (6, 'VI'),
+ (7, 'VII'),
+ (8, 'VIII'),
+ (9, 'IX'),
+ (10, 'X'),
+ (50, 'L'),
+ (100, 'C'),
+ (500, 'D'),
+ (1000, 'M'),
+ (31, 'XXXI'),
+ (148, 'CXLVIII'),
+ (294, 'CCXCIV'),
+ (312, 'CCCXII'),
+ (421, 'CDXXI'),
+ (528, 'DXXVIII'),
+ (621, 'DCXXI'),
+ (782, 'DCCLXXXII'),
+ (870, 'DCCCLXX'),
+ (941, 'CMXLI'),
+ (1043, 'MXLIII'),
+ (1110, 'MCX'),
+ (1226, 'MCCXXVI'),
+ (1301, 'MCCCI'),
+ (1485, 'MCDLXXXV'),
+ (1509, 'MDIX'),
+ (1607, 'MDCVII'),
+ (1754, 'MDCCLIV'),
+ (1832, 'MDCCCXXXII'),
+ (1993, 'MCMXCIII'),
+ (2074, 'MMLXXIV'),
+ (2152, 'MMCLII'),
+ (2212, 'MMCCXII'),
+ (2343, 'MMCCCXLIII'),
+ (2499, 'MMCDXCIX'),
+ (2574, 'MMDLXXIV'),
+ (2646, 'MMDCXLVI'),
+ (2723, 'MMDCCXXIII'),
+ (2892, 'MMDCCCXCII'),
+ (2975, 'MMCMLXXV'),
+ (3051, 'MMMLI'),
+ (3185, 'MMMCLXXXV'),
+ (3250, 'MMMCCL'),
+ (3313, 'MMMCCCXIII'),
+ (3408, 'MMMCDVIII'),
+ (3501, 'MMMDI'),
+ (3610, 'MMMDCX'),
+ (3743, 'MMMDCCXLIII'),
+ (3844, 'MMMDCCCXLIV'),
+ (3888, 'MMMDCCCLXXXVIII'),
+ (3940, 'MMMCMXL'),
+ (3999, 'MMMCMXCIX'),
+ (4000, 'MMMM'),
+ (4500, 'MMMMD'),
+ (4888, 'MMMMDCCCLXXXVIII'),
+ (4999, 'MMMMCMXCIX'))
+
+ def testToRomanKnownValues(self):
+ """toRoman should give known result with known input"""
+ for integer, numeral in self.knownValues:
+ result = roman72.toRoman(integer)
+ self.assertEqual(numeral, result)
+
+ def testFromRomanKnownValues(self):
+ """fromRoman should give known result with known input"""
+ for integer, numeral in self.knownValues:
+ result = roman72.fromRoman(numeral)
+ self.assertEqual(integer, result)
+
+class ToRomanBadInput(unittest.TestCase):
+ def testTooLarge(self):
+ """toRoman should fail with large input"""
+ self.assertRaises(roman72.OutOfRangeError, roman72.toRoman, 5000)
+
+ def testZero(self):
+ """toRoman should fail with 0 input"""
+ self.assertRaises(roman72.OutOfRangeError, roman72.toRoman, 0)
+
+ def testNegative(self):
+ """toRoman should fail with negative input"""
+ self.assertRaises(roman72.OutOfRangeError, roman72.toRoman, -1)
+
+ def testNonInteger(self):
+ """toRoman should fail with non-integer input"""
+ self.assertRaises(roman72.NotIntegerError, roman72.toRoman, 0.5)
+
+class FromRomanBadInput(unittest.TestCase):
+ def testTooManyRepeatedNumerals(self):
+ """fromRoman should fail with too many repeated numerals"""
+ for s in ('MMMMM', 'DD', 'CCCC', 'LL', 'XXXX', 'VV', 'IIII'):
+ self.assertRaises(roman72.InvalidRomanNumeralError, roman72.fromRoman, s)
+
+ def testRepeatedPairs(self):
+ """fromRoman should fail with repeated pairs of numerals"""
+ for s in ('CMCM', 'CDCD', 'XCXC', 'XLXL', 'IXIX', 'IVIV'):
+ self.assertRaises(roman72.InvalidRomanNumeralError, roman72.fromRoman, s)
+
+ def testMalformedAntecedent(self):
+ """fromRoman should fail with malformed antecedents"""
+ for s in ('IIMXCC', 'VX', 'DCM', 'CMM', 'IXIV',
+ 'MCMC', 'XCX', 'IVI', 'LM', 'LD', 'LC'):
+ self.assertRaises(roman72.InvalidRomanNumeralError, roman72.fromRoman, s)
+
+ def testBlank(self):
+ """fromRoman should fail with blank string"""
+ self.assertRaises(roman72.InvalidRomanNumeralError, roman72.fromRoman, "")
+
+class SanityCheck(unittest.TestCase):
+ def testSanity(self):
+ """fromRoman(toRoman(n))==n for all n"""
+ for integer in range(1, 5000):
+ numeral = roman72.toRoman(integer)
+ result = roman72.fromRoman(numeral)
+ self.assertEqual(integer, result)
+
+class CaseCheck(unittest.TestCase):
+ def testToRomanCase(self):
+ """toRoman should always return uppercase"""
+ for integer in range(1, 5000):
+ numeral = roman72.toRoman(integer)
+ self.assertEqual(numeral, numeral.upper())
+
+ def testFromRomanCase(self):
+ """fromRoman should only accept uppercase input"""
+ for integer in range(1, 5000):
+ numeral = roman72.toRoman(integer)
+ roman72.fromRoman(numeral.upper())
+ self.assertRaises(roman72.InvalidRomanNumeralError,
+ roman72.fromRoman, numeral.lower())
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/help/diveintopython-5.4/py/roman/stage8/roman81.py b/help/diveintopython-5.4/py/roman/stage8/roman81.py
new file mode 100644
index 0000000..7530df3
--- /dev/null
+++ b/help/diveintopython-5.4/py/roman/stage8/roman81.py
@@ -0,0 +1,68 @@
+"""Convert to and from Roman numerals
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.3 $"
+__date__ = "$Date: 2004/05/05 21:57:20 $"
+__copyright__ = "Copyright (c) 2001 Mark Pilgrim"
+__license__ = "Python"
+
+import re
+
+#Define exceptions
+class RomanError(Exception): pass
+class OutOfRangeError(RomanError): pass
+class NotIntegerError(RomanError): pass
+class InvalidRomanNumeralError(RomanError): pass
+
+#Define digit mapping
+romanNumeralMap = (('M', 1000),
+ ('CM', 900),
+ ('D', 500),
+ ('CD', 400),
+ ('C', 100),
+ ('XC', 90),
+ ('L', 50),
+ ('XL', 40),
+ ('X', 10),
+ ('IX', 9),
+ ('V', 5),
+ ('IV', 4),
+ ('I', 1))
+
+def toRoman(n):
+ """convert integer to Roman numeral"""
+ if not (0 < n < 5000):
+ raise OutOfRangeError, "number out of range (must be 1..4999)"
+ if int(n) <> n:
+ raise NotIntegerError, "non-integers can not be converted"
+
+ result = ""
+ for numeral, integer in romanNumeralMap:
+ while n >= integer:
+ result += numeral
+ n -= integer
+ return result
+
+#Define pattern to detect valid Roman numerals
+romanNumeralPattern = \
+ re.compile('^M?M?M?M?(CM|CD|D?C?C?C?)(XC|XL|L?X?X?X?)(IX|IV|V?I?I?I?)$')
+
+def fromRoman(s):
+ """convert Roman numeral to integer"""
+ if not s:
+ raise InvalidRomanNumeralError, 'Input can not be blank'
+ if not romanNumeralPattern.search(s):
+ raise InvalidRomanNumeralError, 'Invalid Roman numeral: %s' % s
+
+ result = 0
+ index = 0
+ for numeral, integer in romanNumeralMap:
+ while s[index:index+len(numeral)] == numeral:
+ result += integer
+ index += len(numeral)
+ return result
diff --git a/help/diveintopython-5.4/py/roman/stage8/roman82.py b/help/diveintopython-5.4/py/roman/stage8/roman82.py
new file mode 100644
index 0000000..aacd3f4
--- /dev/null
+++ b/help/diveintopython-5.4/py/roman/stage8/roman82.py
@@ -0,0 +1,68 @@
+"""Convert to and from Roman numerals
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.3 $"
+__date__ = "$Date: 2004/05/05 21:57:20 $"
+__copyright__ = "Copyright (c) 2001 Mark Pilgrim"
+__license__ = "Python"
+
+import re
+
+#Define exceptions
+class RomanError(Exception): pass
+class OutOfRangeError(RomanError): pass
+class NotIntegerError(RomanError): pass
+class InvalidRomanNumeralError(RomanError): pass
+
+#Define digit mapping
+romanNumeralMap = (('M', 1000),
+ ('CM', 900),
+ ('D', 500),
+ ('CD', 400),
+ ('C', 100),
+ ('XC', 90),
+ ('L', 50),
+ ('XL', 40),
+ ('X', 10),
+ ('IX', 9),
+ ('V', 5),
+ ('IV', 4),
+ ('I', 1))
+
+def toRoman(n):
+ """convert integer to Roman numeral"""
+ if not (0 < n < 5000):
+ raise OutOfRangeError, "number out of range (must be 1..4999)"
+ if int(n) <> n:
+ raise NotIntegerError, "non-integers can not be converted"
+
+ result = ""
+ for numeral, integer in romanNumeralMap:
+ while n >= integer:
+ result += numeral
+ n -= integer
+ return result
+
+#Define pattern to detect valid Roman numerals
+romanNumeralPattern = \
+ re.compile('^M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$')
+
+def fromRoman(s):
+ """convert Roman numeral to integer"""
+ if not s:
+ raise InvalidRomanNumeralError, 'Input can not be blank'
+ if not romanNumeralPattern.search(s):
+ raise InvalidRomanNumeralError, 'Invalid Roman numeral: %s' % s
+
+ result = 0
+ index = 0
+ for numeral, integer in romanNumeralMap:
+ while s[index:index+len(numeral)] == numeral:
+ result += integer
+ index += len(numeral)
+ return result
diff --git a/help/diveintopython-5.4/py/roman/stage8/roman83.py b/help/diveintopython-5.4/py/roman/stage8/roman83.py
new file mode 100644
index 0000000..14eeb8f
--- /dev/null
+++ b/help/diveintopython-5.4/py/roman/stage8/roman83.py
@@ -0,0 +1,77 @@
+"""Convert to and from Roman numerals
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.3 $"
+__date__ = "$Date: 2004/05/05 21:57:20 $"
+__copyright__ = "Copyright (c) 2001 Mark Pilgrim"
+__license__ = "Python"
+
+import re
+
+#Define exceptions
+class RomanError(Exception): pass
+class OutOfRangeError(RomanError): pass
+class NotIntegerError(RomanError): pass
+class InvalidRomanNumeralError(RomanError): pass
+
+#Define digit mapping
+romanNumeralMap = (('M', 1000),
+ ('CM', 900),
+ ('D', 500),
+ ('CD', 400),
+ ('C', 100),
+ ('XC', 90),
+ ('L', 50),
+ ('XL', 40),
+ ('X', 10),
+ ('IX', 9),
+ ('V', 5),
+ ('IV', 4),
+ ('I', 1))
+
+def toRoman(n):
+ """convert integer to Roman numeral"""
+ if not (0 < n < 5000):
+ raise OutOfRangeError, "number out of range (must be 1..4999)"
+ if int(n) <> n:
+ raise NotIntegerError, "non-integers can not be converted"
+
+ result = ""
+ for numeral, integer in romanNumeralMap:
+ while n >= integer:
+ result += numeral
+ n -= integer
+ return result
+
+#Define pattern to detect valid Roman numerals
+romanNumeralPattern = re.compile('''
+ ^ # beginning of string
+ M{0,4} # thousands - 0 to 4 M's
+ (CM|CD|D?C{0,3}) # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 C's),
+ # or 500-800 (D, followed by 0 to 3 C's)
+ (XC|XL|L?X{0,3}) # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 X's),
+ # or 50-80 (L, followed by 0 to 3 X's)
+ (IX|IV|V?I{0,3}) # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 I's),
+ # or 5-8 (V, followed by 0 to 3 I's)
+ $ # end of string
+ ''' ,re.VERBOSE)
+
+def fromRoman(s):
+ """convert Roman numeral to integer"""
+ if not s:
+ raise InvalidRomanNumeralError, 'Input can not be blank'
+ if not romanNumeralPattern.search(s):
+ raise InvalidRomanNumeralError, 'Invalid Roman numeral: %s' % s
+
+ result = 0
+ index = 0
+ for numeral, integer in romanNumeralMap:
+ while s[index:index+len(numeral)] == numeral:
+ result += integer
+ index += len(numeral)
+ return result
diff --git a/help/diveintopython-5.4/py/roman/stage8/romantest81.py b/help/diveintopython-5.4/py/roman/stage8/romantest81.py
new file mode 100644
index 0000000..c7cb461
--- /dev/null
+++ b/help/diveintopython-5.4/py/roman/stage8/romantest81.py
@@ -0,0 +1,153 @@
+"""Unit test for roman81.py
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.3 $"
+__date__ = "$Date: 2004/05/05 21:57:20 $"
+__copyright__ = "Copyright (c) 2001 Mark Pilgrim"
+__license__ = "Python"
+
+import roman81
+import unittest
+
+class KnownValues(unittest.TestCase):
+ knownValues = ( (1, 'I'),
+ (2, 'II'),
+ (3, 'III'),
+ (4, 'IV'),
+ (5, 'V'),
+ (6, 'VI'),
+ (7, 'VII'),
+ (8, 'VIII'),
+ (9, 'IX'),
+ (10, 'X'),
+ (50, 'L'),
+ (100, 'C'),
+ (500, 'D'),
+ (1000, 'M'),
+ (31, 'XXXI'),
+ (148, 'CXLVIII'),
+ (294, 'CCXCIV'),
+ (312, 'CCCXII'),
+ (421, 'CDXXI'),
+ (528, 'DXXVIII'),
+ (621, 'DCXXI'),
+ (782, 'DCCLXXXII'),
+ (870, 'DCCCLXX'),
+ (941, 'CMXLI'),
+ (1043, 'MXLIII'),
+ (1110, 'MCX'),
+ (1226, 'MCCXXVI'),
+ (1301, 'MCCCI'),
+ (1485, 'MCDLXXXV'),
+ (1509, 'MDIX'),
+ (1607, 'MDCVII'),
+ (1754, 'MDCCLIV'),
+ (1832, 'MDCCCXXXII'),
+ (1993, 'MCMXCIII'),
+ (2074, 'MMLXXIV'),
+ (2152, 'MMCLII'),
+ (2212, 'MMCCXII'),
+ (2343, 'MMCCCXLIII'),
+ (2499, 'MMCDXCIX'),
+ (2574, 'MMDLXXIV'),
+ (2646, 'MMDCXLVI'),
+ (2723, 'MMDCCXXIII'),
+ (2892, 'MMDCCCXCII'),
+ (2975, 'MMCMLXXV'),
+ (3051, 'MMMLI'),
+ (3185, 'MMMCLXXXV'),
+ (3250, 'MMMCCL'),
+ (3313, 'MMMCCCXIII'),
+ (3408, 'MMMCDVIII'),
+ (3501, 'MMMDI'),
+ (3610, 'MMMDCX'),
+ (3743, 'MMMDCCXLIII'),
+ (3844, 'MMMDCCCXLIV'),
+ (3888, 'MMMDCCCLXXXVIII'),
+ (3940, 'MMMCMXL'),
+ (3999, 'MMMCMXCIX'),
+ (4000, 'MMMM'),
+ (4500, 'MMMMD'),
+ (4888, 'MMMMDCCCLXXXVIII'),
+ (4999, 'MMMMCMXCIX'))
+
+ def testToRomanKnownValues(self):
+ """toRoman should give known result with known input"""
+ for integer, numeral in self.knownValues:
+ result = roman81.toRoman(integer)
+ self.assertEqual(numeral, result)
+
+ def testFromRomanKnownValues(self):
+ """fromRoman should give known result with known input"""
+ for integer, numeral in self.knownValues:
+ result = roman81.fromRoman(numeral)
+ self.assertEqual(integer, result)
+
+class ToRomanBadInput(unittest.TestCase):
+ def testTooLarge(self):
+ """toRoman should fail with large input"""
+ self.assertRaises(roman81.OutOfRangeError, roman81.toRoman, 5000)
+
+ def testZero(self):
+ """toRoman should fail with 0 input"""
+ self.assertRaises(roman81.OutOfRangeError, roman81.toRoman, 0)
+
+ def testNegative(self):
+ """toRoman should fail with negative input"""
+ self.assertRaises(roman81.OutOfRangeError, roman81.toRoman, -1)
+
+ def testNonInteger(self):
+ """toRoman should fail with non-integer input"""
+ self.assertRaises(roman81.NotIntegerError, roman81.toRoman, 0.5)
+
+class FromRomanBadInput(unittest.TestCase):
+ def testTooManyRepeatedNumerals(self):
+ """fromRoman should fail with too many repeated numerals"""
+ for s in ('MMMMM', 'DD', 'CCCC', 'LL', 'XXXX', 'VV', 'IIII'):
+ self.assertRaises(roman81.InvalidRomanNumeralError, roman81.fromRoman, s)
+
+ def testRepeatedPairs(self):
+ """fromRoman should fail with repeated pairs of numerals"""
+ for s in ('CMCM', 'CDCD', 'XCXC', 'XLXL', 'IXIX', 'IVIV'):
+ self.assertRaises(roman81.InvalidRomanNumeralError, roman81.fromRoman, s)
+
+ def testMalformedAntecedent(self):
+ """fromRoman should fail with malformed antecedents"""
+ for s in ('IIMXCC', 'VX', 'DCM', 'CMM', 'IXIV',
+ 'MCMC', 'XCX', 'IVI', 'LM', 'LD', 'LC'):
+ self.assertRaises(roman81.InvalidRomanNumeralError, roman81.fromRoman, s)
+
+ def testBlank(self):
+ """fromRoman should fail with blank string"""
+ self.assertRaises(roman81.InvalidRomanNumeralError, roman81.fromRoman, "")
+
+class SanityCheck(unittest.TestCase):
+ def testSanity(self):
+ """fromRoman(toRoman(n))==n for all n"""
+ for integer in range(1, 5000):
+ numeral = roman81.toRoman(integer)
+ result = roman81.fromRoman(numeral)
+ self.assertEqual(integer, result)
+
+class CaseCheck(unittest.TestCase):
+ def testToRomanCase(self):
+ """toRoman should always return uppercase"""
+ for integer in range(1, 5000):
+ numeral = roman81.toRoman(integer)
+ self.assertEqual(numeral, numeral.upper())
+
+ def testFromRomanCase(self):
+ """fromRoman should only accept uppercase input"""
+ for integer in range(1, 5000):
+ numeral = roman81.toRoman(integer)
+ roman81.fromRoman(numeral.upper())
+ self.assertRaises(roman81.InvalidRomanNumeralError,
+ roman81.fromRoman, numeral.lower())
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/help/diveintopython-5.4/py/roman/stage8/romantest82.py b/help/diveintopython-5.4/py/roman/stage8/romantest82.py
new file mode 100644
index 0000000..96f0dff
--- /dev/null
+++ b/help/diveintopython-5.4/py/roman/stage8/romantest82.py
@@ -0,0 +1,153 @@
+"""Unit test for roman82.py
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.3 $"
+__date__ = "$Date: 2004/05/05 21:57:20 $"
+__copyright__ = "Copyright (c) 2001 Mark Pilgrim"
+__license__ = "Python"
+
+import roman82
+import unittest
+
+class KnownValues(unittest.TestCase):
+ knownValues = ( (1, 'I'),
+ (2, 'II'),
+ (3, 'III'),
+ (4, 'IV'),
+ (5, 'V'),
+ (6, 'VI'),
+ (7, 'VII'),
+ (8, 'VIII'),
+ (9, 'IX'),
+ (10, 'X'),
+ (50, 'L'),
+ (100, 'C'),
+ (500, 'D'),
+ (1000, 'M'),
+ (31, 'XXXI'),
+ (148, 'CXLVIII'),
+ (294, 'CCXCIV'),
+ (312, 'CCCXII'),
+ (421, 'CDXXI'),
+ (528, 'DXXVIII'),
+ (621, 'DCXXI'),
+ (782, 'DCCLXXXII'),
+ (870, 'DCCCLXX'),
+ (941, 'CMXLI'),
+ (1043, 'MXLIII'),
+ (1110, 'MCX'),
+ (1226, 'MCCXXVI'),
+ (1301, 'MCCCI'),
+ (1485, 'MCDLXXXV'),
+ (1509, 'MDIX'),
+ (1607, 'MDCVII'),
+ (1754, 'MDCCLIV'),
+ (1832, 'MDCCCXXXII'),
+ (1993, 'MCMXCIII'),
+ (2074, 'MMLXXIV'),
+ (2152, 'MMCLII'),
+ (2212, 'MMCCXII'),
+ (2343, 'MMCCCXLIII'),
+ (2499, 'MMCDXCIX'),
+ (2574, 'MMDLXXIV'),
+ (2646, 'MMDCXLVI'),
+ (2723, 'MMDCCXXIII'),
+ (2892, 'MMDCCCXCII'),
+ (2975, 'MMCMLXXV'),
+ (3051, 'MMMLI'),
+ (3185, 'MMMCLXXXV'),
+ (3250, 'MMMCCL'),
+ (3313, 'MMMCCCXIII'),
+ (3408, 'MMMCDVIII'),
+ (3501, 'MMMDI'),
+ (3610, 'MMMDCX'),
+ (3743, 'MMMDCCXLIII'),
+ (3844, 'MMMDCCCXLIV'),
+ (3888, 'MMMDCCCLXXXVIII'),
+ (3940, 'MMMCMXL'),
+ (3999, 'MMMCMXCIX'),
+ (4000, 'MMMM'),
+ (4500, 'MMMMD'),
+ (4888, 'MMMMDCCCLXXXVIII'),
+ (4999, 'MMMMCMXCIX'))
+
+ def testToRomanKnownValues(self):
+ """toRoman should give known result with known input"""
+ for integer, numeral in self.knownValues:
+ result = roman82.toRoman(integer)
+ self.assertEqual(numeral, result)
+
+ def testFromRomanKnownValues(self):
+ """fromRoman should give known result with known input"""
+ for integer, numeral in self.knownValues:
+ result = roman82.fromRoman(numeral)
+ self.assertEqual(integer, result)
+
+class ToRomanBadInput(unittest.TestCase):
+ def testTooLarge(self):
+ """toRoman should fail with large input"""
+ self.assertRaises(roman82.OutOfRangeError, roman82.toRoman, 5000)
+
+ def testZero(self):
+ """toRoman should fail with 0 input"""
+ self.assertRaises(roman82.OutOfRangeError, roman82.toRoman, 0)
+
+ def testNegative(self):
+ """toRoman should fail with negative input"""
+ self.assertRaises(roman82.OutOfRangeError, roman82.toRoman, -1)
+
+ def testNonInteger(self):
+ """toRoman should fail with non-integer input"""
+ self.assertRaises(roman82.NotIntegerError, roman82.toRoman, 0.5)
+
+class FromRomanBadInput(unittest.TestCase):
+ def testTooManyRepeatedNumerals(self):
+ """fromRoman should fail with too many repeated numerals"""
+ for s in ('MMMMM', 'DD', 'CCCC', 'LL', 'XXXX', 'VV', 'IIII'):
+ self.assertRaises(roman82.InvalidRomanNumeralError, roman82.fromRoman, s)
+
+ def testRepeatedPairs(self):
+ """fromRoman should fail with repeated pairs of numerals"""
+ for s in ('CMCM', 'CDCD', 'XCXC', 'XLXL', 'IXIX', 'IVIV'):
+ self.assertRaises(roman82.InvalidRomanNumeralError, roman82.fromRoman, s)
+
+ def testMalformedAntecedent(self):
+ """fromRoman should fail with malformed antecedents"""
+ for s in ('IIMXCC', 'VX', 'DCM', 'CMM', 'IXIV',
+ 'MCMC', 'XCX', 'IVI', 'LM', 'LD', 'LC'):
+ self.assertRaises(roman82.InvalidRomanNumeralError, roman82.fromRoman, s)
+
+ def testBlank(self):
+ """fromRoman should fail with blank string"""
+ self.assertRaises(roman82.InvalidRomanNumeralError, roman82.fromRoman, "")
+
+class SanityCheck(unittest.TestCase):
+ def testSanity(self):
+ """fromRoman(toRoman(n))==n for all n"""
+ for integer in range(1, 5000):
+ numeral = roman82.toRoman(integer)
+ result = roman82.fromRoman(numeral)
+ self.assertEqual(integer, result)
+
+class CaseCheck(unittest.TestCase):
+ def testToRomanCase(self):
+ """toRoman should always return uppercase"""
+ for integer in range(1, 5000):
+ numeral = roman82.toRoman(integer)
+ self.assertEqual(numeral, numeral.upper())
+
+ def testFromRomanCase(self):
+ """fromRoman should only accept uppercase input"""
+ for integer in range(1, 5000):
+ numeral = roman82.toRoman(integer)
+ roman82.fromRoman(numeral.upper())
+ self.assertRaises(roman82.InvalidRomanNumeralError,
+ roman82.fromRoman, numeral.lower())
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/help/diveintopython-5.4/py/roman/stage8/romantest83.py b/help/diveintopython-5.4/py/roman/stage8/romantest83.py
new file mode 100644
index 0000000..c2909ef
--- /dev/null
+++ b/help/diveintopython-5.4/py/roman/stage8/romantest83.py
@@ -0,0 +1,153 @@
+"""Unit test for roman83.py
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.3 $"
+__date__ = "$Date: 2004/05/05 21:57:20 $"
+__copyright__ = "Copyright (c) 2001 Mark Pilgrim"
+__license__ = "Python"
+
+import roman83
+import unittest
+
+class KnownValues(unittest.TestCase):
+ knownValues = ( (1, 'I'),
+ (2, 'II'),
+ (3, 'III'),
+ (4, 'IV'),
+ (5, 'V'),
+ (6, 'VI'),
+ (7, 'VII'),
+ (8, 'VIII'),
+ (9, 'IX'),
+ (10, 'X'),
+ (50, 'L'),
+ (100, 'C'),
+ (500, 'D'),
+ (1000, 'M'),
+ (31, 'XXXI'),
+ (148, 'CXLVIII'),
+ (294, 'CCXCIV'),
+ (312, 'CCCXII'),
+ (421, 'CDXXI'),
+ (528, 'DXXVIII'),
+ (621, 'DCXXI'),
+ (782, 'DCCLXXXII'),
+ (870, 'DCCCLXX'),
+ (941, 'CMXLI'),
+ (1043, 'MXLIII'),
+ (1110, 'MCX'),
+ (1226, 'MCCXXVI'),
+ (1301, 'MCCCI'),
+ (1485, 'MCDLXXXV'),
+ (1509, 'MDIX'),
+ (1607, 'MDCVII'),
+ (1754, 'MDCCLIV'),
+ (1832, 'MDCCCXXXII'),
+ (1993, 'MCMXCIII'),
+ (2074, 'MMLXXIV'),
+ (2152, 'MMCLII'),
+ (2212, 'MMCCXII'),
+ (2343, 'MMCCCXLIII'),
+ (2499, 'MMCDXCIX'),
+ (2574, 'MMDLXXIV'),
+ (2646, 'MMDCXLVI'),
+ (2723, 'MMDCCXXIII'),
+ (2892, 'MMDCCCXCII'),
+ (2975, 'MMCMLXXV'),
+ (3051, 'MMMLI'),
+ (3185, 'MMMCLXXXV'),
+ (3250, 'MMMCCL'),
+ (3313, 'MMMCCCXIII'),
+ (3408, 'MMMCDVIII'),
+ (3501, 'MMMDI'),
+ (3610, 'MMMDCX'),
+ (3743, 'MMMDCCXLIII'),
+ (3844, 'MMMDCCCXLIV'),
+ (3888, 'MMMDCCCLXXXVIII'),
+ (3940, 'MMMCMXL'),
+ (3999, 'MMMCMXCIX'),
+ (4000, 'MMMM'),
+ (4500, 'MMMMD'),
+ (4888, 'MMMMDCCCLXXXVIII'),
+ (4999, 'MMMMCMXCIX'))
+
+ def testToRomanKnownValues(self):
+ """toRoman should give known result with known input"""
+ for integer, numeral in self.knownValues:
+ result = roman83.toRoman(integer)
+ self.assertEqual(numeral, result)
+
+ def testFromRomanKnownValues(self):
+ """fromRoman should give known result with known input"""
+ for integer, numeral in self.knownValues:
+ result = roman83.fromRoman(numeral)
+ self.assertEqual(integer, result)
+
+class ToRomanBadInput(unittest.TestCase):
+ def testTooLarge(self):
+ """toRoman should fail with large input"""
+ self.assertRaises(roman83.OutOfRangeError, roman83.toRoman, 5000)
+
+ def testZero(self):
+ """toRoman should fail with 0 input"""
+ self.assertRaises(roman83.OutOfRangeError, roman83.toRoman, 0)
+
+ def testNegative(self):
+ """toRoman should fail with negative input"""
+ self.assertRaises(roman83.OutOfRangeError, roman83.toRoman, -1)
+
+ def testNonInteger(self):
+ """toRoman should fail with non-integer input"""
+ self.assertRaises(roman83.NotIntegerError, roman83.toRoman, 0.5)
+
+class FromRomanBadInput(unittest.TestCase):
+ def testTooManyRepeatedNumerals(self):
+ """fromRoman should fail with too many repeated numerals"""
+ for s in ('MMMMM', 'DD', 'CCCC', 'LL', 'XXXX', 'VV', 'IIII'):
+ self.assertRaises(roman83.InvalidRomanNumeralError, roman83.fromRoman, s)
+
+ def testRepeatedPairs(self):
+ """fromRoman should fail with repeated pairs of numerals"""
+ for s in ('CMCM', 'CDCD', 'XCXC', 'XLXL', 'IXIX', 'IVIV'):
+ self.assertRaises(roman83.InvalidRomanNumeralError, roman83.fromRoman, s)
+
+ def testMalformedAntecedent(self):
+ """fromRoman should fail with malformed antecedents"""
+ for s in ('IIMXCC', 'VX', 'DCM', 'CMM', 'IXIV',
+ 'MCMC', 'XCX', 'IVI', 'LM', 'LD', 'LC'):
+ self.assertRaises(roman83.InvalidRomanNumeralError, roman83.fromRoman, s)
+
+ def testBlank(self):
+ """fromRoman should fail with blank string"""
+ self.assertRaises(roman83.InvalidRomanNumeralError, roman83.fromRoman, "")
+
+class SanityCheck(unittest.TestCase):
+ def testSanity(self):
+ """fromRoman(toRoman(n))==n for all n"""
+ for integer in range(1, 5000):
+ numeral = roman83.toRoman(integer)
+ result = roman83.fromRoman(numeral)
+ self.assertEqual(integer, result)
+
+class CaseCheck(unittest.TestCase):
+ def testToRomanCase(self):
+ """toRoman should always return uppercase"""
+ for integer in range(1, 5000):
+ numeral = roman83.toRoman(integer)
+ self.assertEqual(numeral, numeral.upper())
+
+ def testFromRomanCase(self):
+ """fromRoman should only accept uppercase input"""
+ for integer in range(1, 5000):
+ numeral = roman83.toRoman(integer)
+ roman83.fromRoman(numeral.upper())
+ self.assertRaises(roman83.InvalidRomanNumeralError,
+ roman83.fromRoman, numeral.lower())
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/help/diveintopython-5.4/py/roman/stage9/roman9.py b/help/diveintopython-5.4/py/roman/stage9/roman9.py
new file mode 100644
index 0000000..eae654c
--- /dev/null
+++ b/help/diveintopython-5.4/py/roman/stage9/roman9.py
@@ -0,0 +1,83 @@
+"""Convert to and from Roman numerals
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Steve Lamm, Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.3 $"
+__date__ = "$Date: 2004/05/05 21:57:20 $"
+__copyright__ = "Copyright (c) 2001 Steve Lamm, Copyright (c) 2001 Mark Pilgrim"
+__license__ = "Python"
+
+import re
+
+#Define exceptions
+class RomanError(Exception): pass
+class OutOfRangeError(RomanError): pass
+class NotIntegerError(RomanError): pass
+class InvalidRomanNumeralError(RomanError): pass
+
+#Roman numerals must be less than 5000
+MAX_ROMAN_NUMERAL = 4999
+
+#Define digit mapping
+romanNumeralMap = (('M', 1000),
+ ('CM', 900),
+ ('D', 500),
+ ('CD', 400),
+ ('C', 100),
+ ('XC', 90),
+ ('L', 50),
+ ('XL', 40),
+ ('X', 10),
+ ('IX', 9),
+ ('V', 5),
+ ('IV', 4),
+ ('I', 1))
+
+#Create tables for fast conversion of roman numerals.
+#See fillLookupTables() below.
+toRomanTable = [ None ] # Skip an index since Roman numerals have no zero
+fromRomanTable = {}
+
+def toRoman(n):
+ """convert integer to Roman numeral"""
+ if not (0 < n <= MAX_ROMAN_NUMERAL):
+ raise OutOfRangeError, "number out of range (must be 1..4999)"
+ if int(n) <> n:
+ raise NotIntegerError, "non-integers can not be converted"
+ return toRomanTable[n]
+
+def fromRoman(s):
+ """convert Roman numeral to integer"""
+ if not s:
+ raise InvalidRomanNumeralError, 'Input can not be blank'
+ if not fromRomanTable.has_key(s):
+ raise InvalidRomanNumeralError, 'Invalid Roman numeral: %s' % s
+ return fromRomanTable[s]
+
+def toRomanDynamic(n):
+ """convert integer to Roman numeral using dynamic programming"""
+ assert(0 < n <= MAX_ROMAN_NUMERAL)
+ assert(int(n) == n)
+ result = ""
+ for numeral, integer in romanNumeralMap:
+ if n >= integer:
+ result = numeral
+ n -= integer
+ break
+ if n > 0:
+ result += toRomanTable[n]
+ return result
+
+def fillLookupTables():
+ """compute all the possible roman numerals"""
+ #Save the values in two global tables to convert to and from integers.
+ for integer in range(1, MAX_ROMAN_NUMERAL + 1):
+ romanNumber = toRomanDynamic(integer)
+ toRomanTable.append(romanNumber)
+ fromRomanTable[romanNumber] = integer
+
+fillLookupTables()
diff --git a/help/diveintopython-5.4/py/roman/stage9/romantest9.py b/help/diveintopython-5.4/py/roman/stage9/romantest9.py
new file mode 100644
index 0000000..d00fdd9
--- /dev/null
+++ b/help/diveintopython-5.4/py/roman/stage9/romantest9.py
@@ -0,0 +1,153 @@
+"""Unit test for roman9.py
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.3 $"
+__date__ = "$Date: 2004/05/05 21:57:20 $"
+__copyright__ = "Copyright (c) 2001 Mark Pilgrim"
+__license__ = "Python"
+
+import roman9
+import unittest
+
+class KnownValues(unittest.TestCase):
+ knownValues = ( (1, 'I'),
+ (2, 'II'),
+ (3, 'III'),
+ (4, 'IV'),
+ (5, 'V'),
+ (6, 'VI'),
+ (7, 'VII'),
+ (8, 'VIII'),
+ (9, 'IX'),
+ (10, 'X'),
+ (50, 'L'),
+ (100, 'C'),
+ (500, 'D'),
+ (1000, 'M'),
+ (31, 'XXXI'),
+ (148, 'CXLVIII'),
+ (294, 'CCXCIV'),
+ (312, 'CCCXII'),
+ (421, 'CDXXI'),
+ (528, 'DXXVIII'),
+ (621, 'DCXXI'),
+ (782, 'DCCLXXXII'),
+ (870, 'DCCCLXX'),
+ (941, 'CMXLI'),
+ (1043, 'MXLIII'),
+ (1110, 'MCX'),
+ (1226, 'MCCXXVI'),
+ (1301, 'MCCCI'),
+ (1485, 'MCDLXXXV'),
+ (1509, 'MDIX'),
+ (1607, 'MDCVII'),
+ (1754, 'MDCCLIV'),
+ (1832, 'MDCCCXXXII'),
+ (1993, 'MCMXCIII'),
+ (2074, 'MMLXXIV'),
+ (2152, 'MMCLII'),
+ (2212, 'MMCCXII'),
+ (2343, 'MMCCCXLIII'),
+ (2499, 'MMCDXCIX'),
+ (2574, 'MMDLXXIV'),
+ (2646, 'MMDCXLVI'),
+ (2723, 'MMDCCXXIII'),
+ (2892, 'MMDCCCXCII'),
+ (2975, 'MMCMLXXV'),
+ (3051, 'MMMLI'),
+ (3185, 'MMMCLXXXV'),
+ (3250, 'MMMCCL'),
+ (3313, 'MMMCCCXIII'),
+ (3408, 'MMMCDVIII'),
+ (3501, 'MMMDI'),
+ (3610, 'MMMDCX'),
+ (3743, 'MMMDCCXLIII'),
+ (3844, 'MMMDCCCXLIV'),
+ (3888, 'MMMDCCCLXXXVIII'),
+ (3940, 'MMMCMXL'),
+ (3999, 'MMMCMXCIX'),
+ (4000, 'MMMM'),
+ (4500, 'MMMMD'),
+ (4888, 'MMMMDCCCLXXXVIII'),
+ (4999, 'MMMMCMXCIX'))
+
+ def testToRomanKnownValues(self):
+ """toRoman should give known result with known input"""
+ for integer, numeral in self.knownValues:
+ result = roman9.toRoman(integer)
+ self.assertEqual(numeral, result)
+
+ def testFromRomanKnownValues(self):
+ """fromRoman should give known result with known input"""
+ for integer, numeral in self.knownValues:
+ result = roman9.fromRoman(numeral)
+ self.assertEqual(integer, result)
+
+class ToRomanBadInput(unittest.TestCase):
+ def testTooLarge(self):
+ """toRoman should fail with large input"""
+ self.assertRaises(roman9.OutOfRangeError, roman9.toRoman, 5000)
+
+ def testZero(self):
+ """toRoman should fail with 0 input"""
+ self.assertRaises(roman9.OutOfRangeError, roman9.toRoman, 0)
+
+ def testNegative(self):
+ """toRoman should fail with negative input"""
+ self.assertRaises(roman9.OutOfRangeError, roman9.toRoman, -1)
+
+ def testNonInteger(self):
+ """toRoman should fail with non-integer input"""
+ self.assertRaises(roman9.NotIntegerError, roman9.toRoman, 0.5)
+
+class FromRomanBadInput(unittest.TestCase):
+ def testTooManyRepeatedNumerals(self):
+ """fromRoman should fail with too many repeated numerals"""
+ for s in ('MMMMM', 'DD', 'CCCC', 'LL', 'XXXX', 'VV', 'IIII'):
+ self.assertRaises(roman9.InvalidRomanNumeralError, roman9.fromRoman, s)
+
+ def testRepeatedPairs(self):
+ """fromRoman should fail with repeated pairs of numerals"""
+ for s in ('CMCM', 'CDCD', 'XCXC', 'XLXL', 'IXIX', 'IVIV'):
+ self.assertRaises(roman9.InvalidRomanNumeralError, roman9.fromRoman, s)
+
+ def testMalformedAntecedent(self):
+ """fromRoman should fail with malformed antecedents"""
+ for s in ('IIMXCC', 'VX', 'DCM', 'CMM', 'IXIV',
+ 'MCMC', 'XCX', 'IVI', 'LM', 'LD', 'LC'):
+ self.assertRaises(roman9.InvalidRomanNumeralError, roman9.fromRoman, s)
+
+ def testBlank(self):
+ """fromRoman should fail with blank string"""
+ self.assertRaises(roman9.InvalidRomanNumeralError, roman9.fromRoman, "")
+
+class SanityCheck(unittest.TestCase):
+ def testSanity(self):
+ """fromRoman(toRoman(n))==n for all n"""
+ for integer in range(1, 5000):
+ numeral = roman9.toRoman(integer)
+ result = roman9.fromRoman(numeral)
+ self.assertEqual(integer, result)
+
+class CaseCheck(unittest.TestCase):
+ def testToRomanCase(self):
+ """toRoman should always return uppercase"""
+ for integer in range(1, 5000):
+ numeral = roman9.toRoman(integer)
+ self.assertEqual(numeral, numeral.upper())
+
+ def testFromRomanCase(self):
+ """fromRoman should only accept uppercase input"""
+ for integer in range(1, 5000):
+ numeral = roman9.toRoman(integer)
+ roman9.fromRoman(numeral.upper())
+ self.assertRaises(roman9.InvalidRomanNumeralError,
+ roman9.fromRoman, numeral.lower())
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/help/diveintopython-5.4/py/romantest.py b/help/diveintopython-5.4/py/romantest.py
new file mode 100644
index 0000000..a20cef2
--- /dev/null
+++ b/help/diveintopython-5.4/py/romantest.py
@@ -0,0 +1,153 @@
+"""Unit test for roman.py
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.2 $"
+__date__ = "$Date: 2004/05/05 21:57:19 $"
+__copyright__ = "Copyright (c) 2001 Mark Pilgrim"
+__license__ = "Python"
+
+import roman
+import unittest
+
+class KnownValues(unittest.TestCase):
+ knownValues = ( (1, 'I'),
+ (2, 'II'),
+ (3, 'III'),
+ (4, 'IV'),
+ (5, 'V'),
+ (6, 'VI'),
+ (7, 'VII'),
+ (8, 'VIII'),
+ (9, 'IX'),
+ (10, 'X'),
+ (50, 'L'),
+ (100, 'C'),
+ (500, 'D'),
+ (1000, 'M'),
+ (31, 'XXXI'),
+ (148, 'CXLVIII'),
+ (294, 'CCXCIV'),
+ (312, 'CCCXII'),
+ (421, 'CDXXI'),
+ (528, 'DXXVIII'),
+ (621, 'DCXXI'),
+ (782, 'DCCLXXXII'),
+ (870, 'DCCCLXX'),
+ (941, 'CMXLI'),
+ (1043, 'MXLIII'),
+ (1110, 'MCX'),
+ (1226, 'MCCXXVI'),
+ (1301, 'MCCCI'),
+ (1485, 'MCDLXXXV'),
+ (1509, 'MDIX'),
+ (1607, 'MDCVII'),
+ (1754, 'MDCCLIV'),
+ (1832, 'MDCCCXXXII'),
+ (1993, 'MCMXCIII'),
+ (2074, 'MMLXXIV'),
+ (2152, 'MMCLII'),
+ (2212, 'MMCCXII'),
+ (2343, 'MMCCCXLIII'),
+ (2499, 'MMCDXCIX'),
+ (2574, 'MMDLXXIV'),
+ (2646, 'MMDCXLVI'),
+ (2723, 'MMDCCXXIII'),
+ (2892, 'MMDCCCXCII'),
+ (2975, 'MMCMLXXV'),
+ (3051, 'MMMLI'),
+ (3185, 'MMMCLXXXV'),
+ (3250, 'MMMCCL'),
+ (3313, 'MMMCCCXIII'),
+ (3408, 'MMMCDVIII'),
+ (3501, 'MMMDI'),
+ (3610, 'MMMDCX'),
+ (3743, 'MMMDCCXLIII'),
+ (3844, 'MMMDCCCXLIV'),
+ (3888, 'MMMDCCCLXXXVIII'),
+ (3940, 'MMMCMXL'),
+ (3999, 'MMMCMXCIX'),
+ (4000, 'MMMM'),
+ (4500, 'MMMMD'),
+ (4888, 'MMMMDCCCLXXXVIII'),
+ (4999, 'MMMMCMXCIX'))
+
+ def testToRomanKnownValues(self):
+ """toRoman should give known result with known input"""
+ for integer, numeral in self.knownValues:
+ result = roman.toRoman(integer)
+ self.assertEqual(numeral, result)
+
+ def testFromRomanKnownValues(self):
+ """fromRoman should give known result with known input"""
+ for integer, numeral in self.knownValues:
+ result = roman.fromRoman(numeral)
+ self.assertEqual(integer, result)
+
+class ToRomanBadInput(unittest.TestCase):
+ def testTooLarge(self):
+ """toRoman should fail with large input"""
+ self.assertRaises(roman.OutOfRangeError, roman.toRoman, 5000)
+
+ def testZero(self):
+ """toRoman should fail with 0 input"""
+ self.assertRaises(roman.OutOfRangeError, roman.toRoman, 0)
+
+ def testNegative(self):
+ """toRoman should fail with negative input"""
+ self.assertRaises(roman.OutOfRangeError, roman.toRoman, -1)
+
+ def testDecimal(self):
+ """toRoman should fail with non-integer input"""
+ self.assertRaises(roman.NotIntegerError, roman.toRoman, 0.5)
+
+class FromRomanBadInput(unittest.TestCase):
+ def testTooManyRepeatedNumerals(self):
+ """fromRoman should fail with too many repeated numerals"""
+ for s in ('MMMMM', 'DD', 'CCCC', 'LL', 'XXXX', 'VV', 'IIII'):
+ self.assertRaises(roman.InvalidRomanNumeralError, roman.fromRoman, s)
+
+ def testRepeatedPairs(self):
+ """fromRoman should fail with repeated pairs of numerals"""
+ for s in ('CMCM', 'CDCD', 'XCXC', 'XLXL', 'IXIX', 'IVIV'):
+ self.assertRaises(roman.InvalidRomanNumeralError, roman.fromRoman, s)
+
+ def testMalformedAntecedent(self):
+ """fromRoman should fail with malformed antecedents"""
+ for s in ('IIMXCC', 'VX', 'DCM', 'CMM', 'IXIV',
+ 'MCMC', 'XCX', 'IVI', 'LM', 'LD', 'LC'):
+ self.assertRaises(roman.InvalidRomanNumeralError, roman.fromRoman, s)
+
+ def testBlank(self):
+ """fromRoman should fail with blank string"""
+ self.assertRaises(roman.InvalidRomanNumeralError, roman.fromRoman, "")
+
+class SanityCheck(unittest.TestCase):
+ def testSanity(self):
+ """fromRoman(toRoman(n))==n for all n"""
+ for integer in range(1, 5000):
+ numeral = roman.toRoman(integer)
+ result = roman.fromRoman(numeral)
+ self.assertEqual(integer, result)
+
+class CaseCheck(unittest.TestCase):
+ def testToRomanCase(self):
+ """toRoman should always return uppercase"""
+ for integer in range(1, 5000):
+ numeral = roman.toRoman(integer)
+ self.assertEqual(numeral, numeral.upper())
+
+ def testFromRomanCase(self):
+ """fromRoman should only accept uppercase input"""
+ for integer in range(1, 5000):
+ numeral = roman.toRoman(integer)
+ roman.fromRoman(numeral.upper())
+ self.assertRaises(roman.InvalidRomanNumeralError,
+ roman.fromRoman, numeral.lower())
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/help/diveintopython-5.4/py/search.py b/help/diveintopython-5.4/py/search.py
new file mode 100644
index 0000000..8a8df97
--- /dev/null
+++ b/help/diveintopython-5.4/py/search.py
@@ -0,0 +1,37 @@
+"""Search Google from the command line
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.2 $"
+__date__ = "$Date: 2004/05/20 18:53:59 $"
+__copyright__ = "Copyright (c) 2004 Mark Pilgrim"
+__license__ = "Python"
+
+from SOAPpy import WSDL
+
+# you'll need to configure these two values;
+# see http://www.google.com/apis/
+WSDLFILE = '/path/to/copy/of/GoogleSearch.wsdl'
+APIKEY = 'YOUR_GOOGLE_API_KEY'
+
+_server = WSDL.Proxy(WSDLFILE)
+def search(q):
+ """Search Google and return list of {title, link, description}"""
+ results = _server.doGoogleSearch(
+ APIKEY, q, 0, 10, False, "", False, "", "utf-8", "utf-8")
+ return [{"title": r.title.encode("utf-8"),
+ "link": r.URL.encode("utf-8"),
+ "description": r.snippet.encode("utf-8")}
+ for r in results.resultElements]
+
+if __name__ == '__main__':
+ import sys
+ for r in search(sys.argv[1])[:5]:
+ print r['title']
+ print r['link']
+ print r['description']
+ print
diff --git a/help/diveintopython-5.4/py/soundex.py b/help/diveintopython-5.4/py/soundex.py
new file mode 100644
index 0000000..05f93d4
--- /dev/null
+++ b/help/diveintopython-5.4/py/soundex.py
@@ -0,0 +1,53 @@
+"""Soundex algorithm
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.5 $"
+__date__ = "$Date: 2004/05/11 19:11:21 $"
+__copyright__ = "Copyright (c) 2004 Mark Pilgrim"
+__license__ = "Python"
+
+import string
+
+allChar = string.uppercase + string.lowercase
+charToSoundex = string.maketrans(allChar, "91239129922455912623919292" * 2)
+
+def soundex(source):
+ "convert string to Soundex equivalent"
+
+ # Soundex requirements:
+ # source string must be at least 1 character
+ # and must consist entirely of letters
+ if (not source) or (not source.isalpha()):
+ return "0000"
+
+ # Soundex algorithm:
+ # 1. make first character uppercase
+ # 2. translate all other characters to Soundex digits
+ digits = source[0].upper() + source[1:].translate(charToSoundex)
+
+ # 3. remove consecutive duplicates
+ digits2 = digits[0]
+ for d in digits[1:]:
+ if digits2[-1] != d:
+ digits2 += d
+
+ # 4. remove all "9"s
+ # 5. pad end with "0"s to 4 characters
+ return (digits2.replace('9', '') + '000')[:4]
+
+if __name__ == '__main__':
+ import sys
+ if sys.argv[1:]:
+ print soundex(sys.argv[1])
+ else:
+ from timeit import Timer
+ names = ('Woo', 'Pilgrim', 'Flingjingwaller')
+ for name in names:
+ statement = "soundex('%s')" % name
+ t = Timer(statement, "from __main__ import soundex")
+ print name.ljust(15), soundex(name), min(t.repeat())
diff --git a/help/diveintopython-5.4/py/soundex/stage1/soundex1a.py b/help/diveintopython-5.4/py/soundex/stage1/soundex1a.py
new file mode 100644
index 0000000..6f0ffb9
--- /dev/null
+++ b/help/diveintopython-5.4/py/soundex/stage1/soundex1a.py
@@ -0,0 +1,85 @@
+"""Soundex algorithm
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.2 $"
+__date__ = "$Date: 2004/05/06 21:36:36 $"
+__copyright__ = "Copyright (c) 2004 Mark Pilgrim"
+__license__ = "Python"
+
+import string, re
+
+charToSoundex = {"A": "9",
+ "B": "1",
+ "C": "2",
+ "D": "3",
+ "E": "9",
+ "F": "1",
+ "G": "2",
+ "H": "9",
+ "I": "9",
+ "J": "2",
+ "K": "2",
+ "L": "4",
+ "M": "5",
+ "N": "5",
+ "O": "9",
+ "P": "1",
+ "Q": "2",
+ "R": "6",
+ "S": "2",
+ "T": "3",
+ "U": "9",
+ "V": "1",
+ "W": "9",
+ "X": "2",
+ "Y": "9",
+ "Z": "2"}
+
+def soundex(source):
+ "convert string to Soundex equivalent"
+
+ # Soundex requirements:
+ # source string must be at least 1 character
+ # and must consist entirely of letters
+ allChars = string.uppercase + string.lowercase
+ if not re.search('^[%s]+$' % allChars, source):
+ return "0000"
+
+ # Soundex algorithm:
+ # 1. make first character uppercase
+ source = source[0].upper() + source[1:]
+
+ # 2. translate all other characters to Soundex digits
+ digits = source[0]
+ for s in source[1:]:
+ s = s.upper()
+ digits += charToSoundex[s]
+
+ # 3. remove consecutive duplicates
+ digits2 = digits[0]
+ for d in digits[1:]:
+ if digits2[-1] != d:
+ digits2 += d
+
+ # 4. remove all "9"s
+ digits3 = re.sub('9', '', digits2)
+
+ # 5. pad end with "0"s to 4 characters
+ while len(digits3) < 4:
+ digits3 += "0"
+
+ # 6. return first 4 characters
+ return digits3[:4]
+
+if __name__ == '__main__':
+ from timeit import Timer
+ names = ('Woo', 'Pilgrim', 'Flingjingwaller')
+ for name in names:
+ statement = "soundex('%s')" % name
+ t = Timer(statement, "from __main__ import soundex")
+ print name.ljust(15), soundex(name), min(t.repeat())
diff --git a/help/diveintopython-5.4/py/soundex/stage1/soundex1b.py b/help/diveintopython-5.4/py/soundex/stage1/soundex1b.py
new file mode 100644
index 0000000..99142f9
--- /dev/null
+++ b/help/diveintopython-5.4/py/soundex/stage1/soundex1b.py
@@ -0,0 +1,84 @@
+"""Soundex algorithm
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.2 $"
+__date__ = "$Date: 2004/05/06 21:36:36 $"
+__copyright__ = "Copyright (c) 2004 Mark Pilgrim"
+__license__ = "Python"
+
+import string, re
+
+charToSoundex = {"A": "9",
+ "B": "1",
+ "C": "2",
+ "D": "3",
+ "E": "9",
+ "F": "1",
+ "G": "2",
+ "H": "9",
+ "I": "9",
+ "J": "2",
+ "K": "2",
+ "L": "4",
+ "M": "5",
+ "N": "5",
+ "O": "9",
+ "P": "1",
+ "Q": "2",
+ "R": "6",
+ "S": "2",
+ "T": "3",
+ "U": "9",
+ "V": "1",
+ "W": "9",
+ "X": "2",
+ "Y": "9",
+ "Z": "2"}
+
+def soundex(source):
+ "convert string to Soundex equivalent"
+
+ # Soundex requirements:
+ # source string must be at least 1 character
+ # and must consist entirely of letters
+ if not re.search('^[A-Za-z]+$', source):
+ return "0000"
+
+ # Soundex algorithm:
+ # 1. make first character uppercase
+ source = source[0].upper() + source[1:]
+
+ # 2. translate all other characters to Soundex digits
+ digits = source[0]
+ for s in source[1:]:
+ s = s.upper()
+ digits += charToSoundex[s]
+
+ # 3. remove consecutive duplicates
+ digits2 = digits[0]
+ for d in digits[1:]:
+ if digits2[-1] != d:
+ digits2 += d
+
+ # 4. remove all "9"s
+ digits3 = re.sub('9', '', digits2)
+
+ # 5. pad end with "0"s to 4 characters
+ while len(digits3) < 4:
+ digits3 += "0"
+
+ # 6. return first 4 characters
+ return digits3[:4]
+
+if __name__ == '__main__':
+ from timeit import Timer
+ names = ('Woo', 'Pilgrim', 'Flingjingwaller')
+ for name in names:
+ statement = "soundex('%s')" % name
+ t = Timer(statement, "from __main__ import soundex")
+ print name.ljust(15), soundex(name), min(t.repeat())
diff --git a/help/diveintopython-5.4/py/soundex/stage1/soundex1c.py b/help/diveintopython-5.4/py/soundex/stage1/soundex1c.py
new file mode 100644
index 0000000..d7df4f6
--- /dev/null
+++ b/help/diveintopython-5.4/py/soundex/stage1/soundex1c.py
@@ -0,0 +1,85 @@
+"""Soundex algorithm
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.2 $"
+__date__ = "$Date: 2004/05/06 21:36:36 $"
+__copyright__ = "Copyright (c) 2004 Mark Pilgrim"
+__license__ = "Python"
+
+import string, re
+
+charToSoundex = {"A": "9",
+ "B": "1",
+ "C": "2",
+ "D": "3",
+ "E": "9",
+ "F": "1",
+ "G": "2",
+ "H": "9",
+ "I": "9",
+ "J": "2",
+ "K": "2",
+ "L": "4",
+ "M": "5",
+ "N": "5",
+ "O": "9",
+ "P": "1",
+ "Q": "2",
+ "R": "6",
+ "S": "2",
+ "T": "3",
+ "U": "9",
+ "V": "1",
+ "W": "9",
+ "X": "2",
+ "Y": "9",
+ "Z": "2"}
+isOnlyChars = re.compile('^[A-Za-z]+$').search
+
+def soundex(source):
+ "convert string to Soundex equivalent"
+
+ # Soundex requirements:
+ # source string must be at least 1 character
+ # and must consist entirely of letters
+ if not isOnlyChars(source):
+ return "0000"
+
+ # Soundex algorithm:
+ # 1. make first character uppercase
+ source = source[0].upper() + source[1:]
+
+ # 2. translate all other characters to Soundex digits
+ digits = source[0]
+ for s in source[1:]:
+ s = s.upper()
+ digits += charToSoundex[s]
+
+ # 3. remove consecutive duplicates
+ digits2 = digits[0]
+ for d in digits[1:]:
+ if digits2[-1] != d:
+ digits2 += d
+
+ # 4. remove all "9"s
+ digits3 = re.sub('9', '', digits2)
+
+ # 5. pad end with "0"s to 4 characters
+ while len(digits3) < 4:
+ digits3 += "0"
+
+ # 6. return first 4 characters
+ return digits3[:4]
+
+if __name__ == '__main__':
+ from timeit import Timer
+ names = ('Woo', 'Pilgrim', 'Flingjingwaller')
+ for name in names:
+ statement = "soundex('%s')" % name
+ t = Timer(statement, "from __main__ import soundex")
+ print name.ljust(15), soundex(name), min(t.repeat())
diff --git a/help/diveintopython-5.4/py/soundex/stage1/soundex1d.py b/help/diveintopython-5.4/py/soundex/stage1/soundex1d.py
new file mode 100644
index 0000000..f9ccca0
--- /dev/null
+++ b/help/diveintopython-5.4/py/soundex/stage1/soundex1d.py
@@ -0,0 +1,87 @@
+"""Soundex algorithm
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.2 $"
+__date__ = "$Date: 2004/05/06 21:36:36 $"
+__copyright__ = "Copyright (c) 2004 Mark Pilgrim"
+__license__ = "Python"
+
+import string, re
+
+charToSoundex = {"A": "9",
+ "B": "1",
+ "C": "2",
+ "D": "3",
+ "E": "9",
+ "F": "1",
+ "G": "2",
+ "H": "9",
+ "I": "9",
+ "J": "2",
+ "K": "2",
+ "L": "4",
+ "M": "5",
+ "N": "5",
+ "O": "9",
+ "P": "1",
+ "Q": "2",
+ "R": "6",
+ "S": "2",
+ "T": "3",
+ "U": "9",
+ "V": "1",
+ "W": "9",
+ "X": "2",
+ "Y": "9",
+ "Z": "2"}
+
+def soundex(source):
+ "convert string to Soundex equivalent"
+
+ # Soundex requirements:
+ # source string must be at least 1 character
+ # and must consist entirely of letters
+ if not source:
+ return "0000"
+ for c in source:
+ if not ('A' <= c <= 'Z') and not ('a' <= c <= 'z'):
+ return "0000"
+
+ # Soundex algorithm:
+ # 1. make first character uppercase
+ source = source[0].upper() + source[1:]
+
+ # 2. translate all other characters to Soundex digits
+ digits = source[0]
+ for s in source[1:]:
+ s = s.upper()
+ digits += charToSoundex[s]
+
+ # 3. remove consecutive duplicates
+ digits2 = digits[0]
+ for d in digits[1:]:
+ if digits2[-1] != d:
+ digits2 += d
+
+ # 4. remove all "9"s
+ digits3 = re.sub('9', '', digits2)
+
+ # 5. pad end with "0"s to 4 characters
+ while len(digits3) < 4:
+ digits3 += "0"
+
+ # 6. return first 4 characters
+ return digits3[:4]
+
+if __name__ == '__main__':
+ from timeit import Timer
+ names = ('Woo', 'Pilgrim', 'Flingjingwaller')
+ for name in names:
+ statement = "soundex('%s')" % name
+ t = Timer(statement, "from __main__ import soundex")
+ print name.ljust(15), soundex(name), min(t.repeat())
diff --git a/help/diveintopython-5.4/py/soundex/stage1/soundex1e.py b/help/diveintopython-5.4/py/soundex/stage1/soundex1e.py
new file mode 100644
index 0000000..52edf37
--- /dev/null
+++ b/help/diveintopython-5.4/py/soundex/stage1/soundex1e.py
@@ -0,0 +1,84 @@
+"""Soundex algorithm
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.3 $"
+__date__ = "$Date: 2004/05/11 19:11:21 $"
+__copyright__ = "Copyright (c) 2004 Mark Pilgrim"
+__license__ = "Python"
+
+import string, re
+
+charToSoundex = {"A": "9",
+ "B": "1",
+ "C": "2",
+ "D": "3",
+ "E": "9",
+ "F": "1",
+ "G": "2",
+ "H": "9",
+ "I": "9",
+ "J": "2",
+ "K": "2",
+ "L": "4",
+ "M": "5",
+ "N": "5",
+ "O": "9",
+ "P": "1",
+ "Q": "2",
+ "R": "6",
+ "S": "2",
+ "T": "3",
+ "U": "9",
+ "V": "1",
+ "W": "9",
+ "X": "2",
+ "Y": "9",
+ "Z": "2"}
+
+def soundex(source):
+ "convert string to Soundex equivalent"
+
+ # Soundex requirements:
+ # source string must be at least 1 character
+ # and must consist entirely of letters
+ if (not source) or (not source.isalpha()):
+ return "0000"
+
+ # Soundex algorithm:
+ # 1. make first character uppercase
+ source = source[0].upper() + source[1:]
+
+ # 2. translate all other characters to Soundex digits
+ digits = source[0]
+ for s in source[1:]:
+ s = s.upper()
+ digits += charToSoundex[s]
+
+ # 3. remove consecutive duplicates
+ digits2 = digits[0]
+ for d in digits[1:]:
+ if digits2[-1] != d:
+ digits2 += d
+
+ # 4. remove all "9"s
+ digits3 = re.sub('9', '', digits2)
+
+ # 5. pad end with "0"s to 4 characters
+ while len(digits3) < 4:
+ digits3 += "0"
+
+ # 6. return first 4 characters
+ return digits3[:4]
+
+if __name__ == '__main__':
+ from timeit import Timer
+ names = ('Woo', 'Pilgrim', 'Flingjingwaller')
+ for name in names:
+ statement = "soundex('%s')" % name
+ t = Timer(statement, "from __main__ import soundex")
+ print name.ljust(15), soundex(name), min(t.repeat())
diff --git a/help/diveintopython-5.4/py/soundex/stage2/soundex2a.py b/help/diveintopython-5.4/py/soundex/stage2/soundex2a.py
new file mode 100644
index 0000000..cc84483
--- /dev/null
+++ b/help/diveintopython-5.4/py/soundex/stage2/soundex2a.py
@@ -0,0 +1,80 @@
+"""Soundex algorithm
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.3 $"
+__date__ = "$Date: 2004/05/11 19:11:21 $"
+__copyright__ = "Copyright (c) 2004 Mark Pilgrim"
+__license__ = "Python"
+
+import string, re
+
+charToSoundex = {"A": "9",
+ "B": "1",
+ "C": "2",
+ "D": "3",
+ "E": "9",
+ "F": "1",
+ "G": "2",
+ "H": "9",
+ "I": "9",
+ "J": "2",
+ "K": "2",
+ "L": "4",
+ "M": "5",
+ "N": "5",
+ "O": "9",
+ "P": "1",
+ "Q": "2",
+ "R": "6",
+ "S": "2",
+ "T": "3",
+ "U": "9",
+ "V": "1",
+ "W": "9",
+ "X": "2",
+ "Y": "9",
+ "Z": "2"}
+
+def soundex(source):
+ "convert string to Soundex equivalent"
+
+ # Soundex requirements:
+ # source string must be at least 1 character
+ # and must consist entirely of letters
+ if (not source) or (not source.isalpha()):
+ return "0000"
+
+ # Soundex algorithm:
+ # 1. make first character uppercase
+ # 2. translate all other characters to Soundex digits
+ source = source.upper()
+ digits = source[0] + "".join(map(lambda c: charToSoundex[c], source[1:]))
+
+ # 3. remove consecutive duplicates
+ digits2 = digits[0]
+ for d in digits[1:]:
+ if digits2[-1] != d:
+ digits2 += d
+
+ # 4. remove all "9"s
+ digits3 = re.sub('9', '', digits2)
+
+ # 5. pad end with "0"s to 4 characters
+ while len(digits3) < 4:
+ digits3 += "0"
+
+ # 6. return first 4 characters
+ return digits3[:4]
+
+if __name__ == '__main__':
+ from timeit import Timer
+ names = ('Woo', 'Pilgrim', 'Flingjingwaller')
+ for name in names:
+ statement = "soundex('%s')" % name
+ t = Timer(statement, "from __main__ import soundex")
+ print name.ljust(15), soundex(name), min(t.repeat())
diff --git a/help/diveintopython-5.4/py/soundex/stage2/soundex2b.py b/help/diveintopython-5.4/py/soundex/stage2/soundex2b.py
new file mode 100644
index 0000000..dd2e8af
--- /dev/null
+++ b/help/diveintopython-5.4/py/soundex/stage2/soundex2b.py
@@ -0,0 +1,80 @@
+"""Soundex algorithm
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.3 $"
+__date__ = "$Date: 2004/05/11 19:11:21 $"
+__copyright__ = "Copyright (c) 2004 Mark Pilgrim"
+__license__ = "Python"
+
+import string, re
+
+charToSoundex = {"A": "9",
+ "B": "1",
+ "C": "2",
+ "D": "3",
+ "E": "9",
+ "F": "1",
+ "G": "2",
+ "H": "9",
+ "I": "9",
+ "J": "2",
+ "K": "2",
+ "L": "4",
+ "M": "5",
+ "N": "5",
+ "O": "9",
+ "P": "1",
+ "Q": "2",
+ "R": "6",
+ "S": "2",
+ "T": "3",
+ "U": "9",
+ "V": "1",
+ "W": "9",
+ "X": "2",
+ "Y": "9",
+ "Z": "2"}
+
+def soundex(source):
+ "convert string to Soundex equivalent"
+
+ # Soundex requirements:
+ # source string must be at least 1 character
+ # and must consist entirely of letters
+ if (not source) or (not source.isalpha()):
+ return "0000"
+
+ # Soundex algorithm:
+ # 1. make first character uppercase
+ # 2. translate all other characters to Soundex digits
+ source = source.upper()
+ digits = source[0] + "".join([charToSoundex[c] for c in source[1:]])
+
+ # 3. remove consecutive duplicates
+ digits2 = re.sub('9', '', digits)
+
+ # 4. remove all "9"s
+ digits3 = ''
+ for d in digits2:
+ if d != '9':
+ digits3 += d
+
+ # 5. pad end with "0"s to 4 characters
+ while len(digits3) < 4:
+ digits3 += "0"
+
+ # 6. return first 4 characters
+ return digits3[:4]
+
+if __name__ == '__main__':
+ from timeit import Timer
+ names = ('Woo', 'Pilgrim', 'Flingjingwaller')
+ for name in names:
+ statement = "soundex('%s')" % name
+ t = Timer(statement, "from __main__ import soundex")
+ print name.ljust(15), soundex(name), min(t.repeat())
diff --git a/help/diveintopython-5.4/py/soundex/stage2/soundex2c.py b/help/diveintopython-5.4/py/soundex/stage2/soundex2c.py
new file mode 100644
index 0000000..1f0d331
--- /dev/null
+++ b/help/diveintopython-5.4/py/soundex/stage2/soundex2c.py
@@ -0,0 +1,55 @@
+"""Soundex algorithm
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.3 $"
+__date__ = "$Date: 2004/05/11 19:11:21 $"
+__copyright__ = "Copyright (c) 2004 Mark Pilgrim"
+__license__ = "Python"
+
+import string, re
+
+allChar = string.uppercase + string.lowercase
+charToSoundex = string.maketrans(allChar, "91239129922455912623919292" * 2)
+
+def soundex(source):
+ "convert string to Soundex equivalent"
+
+ # Soundex requirements:
+ # source string must be at least 1 character
+ # and must consist entirely of letters
+ if (not source) or (not source.isalpha()):
+ return "0000"
+
+ # Soundex algorithm:
+ # 1. make first character uppercase
+ # 2. translate all other characters to Soundex digits
+ digits = source[0].upper() + source[1:].translate(charToSoundex)
+
+ # 3. remove consecutive duplicates
+ digits2 = digits[0]
+ for d in digits[1:]:
+ if digits2[-1] != d:
+ digits2 += d
+
+ # 4. remove all "9"s
+ digits3 = re.sub('9', '', digits2)
+
+ # 5. pad end with "0"s to 4 characters
+ while len(digits3) < 4:
+ digits3 += "0"
+
+ # 6. return first 4 characters
+ return digits3[:4]
+
+if __name__ == '__main__':
+ from timeit import Timer
+ names = ('Woo', 'Pilgrim', 'Flingjingwaller')
+ for name in names:
+ statement = "soundex('%s')" % name
+ t = Timer(statement, "from __main__ import soundex")
+ print name.ljust(15), soundex(name), min(t.repeat())
diff --git a/help/diveintopython-5.4/py/soundex/stage3/soundex3a.py b/help/diveintopython-5.4/py/soundex/stage3/soundex3a.py
new file mode 100644
index 0000000..b069b1a
--- /dev/null
+++ b/help/diveintopython-5.4/py/soundex/stage3/soundex3a.py
@@ -0,0 +1,57 @@
+"""Soundex algorithm
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.3 $"
+__date__ = "$Date: 2004/05/11 19:11:21 $"
+__copyright__ = "Copyright (c) 2004 Mark Pilgrim"
+__license__ = "Python"
+
+import string, re
+
+allChar = string.uppercase + string.lowercase
+charToSoundex = string.maketrans(allChar, "91239129922455912623919292" * 2)
+
+def soundex(source):
+ "convert string to Soundex equivalent"
+
+ # Soundex requirements:
+ # source string must be at least 1 character
+ # and must consist entirely of letters
+ if (not source) or (not source.isalpha()):
+ return "0000"
+
+ # Soundex algorithm:
+ # 1. make first character uppercase
+ # 2. translate all other characters to Soundex digits
+ digits = source[0].upper() + source[1:].translate(charToSoundex)
+
+ # 3. remove consecutive duplicates
+ digits2 = ''
+ last_digit = ''
+ for d in digits:
+ if d != last_digit:
+ digits2 += d
+ last_digit = d
+
+ # 4. remove all "9"s
+ digits3 = re.sub('9', '', digits2)
+
+ # 5. pad end with "0"s to 4 characters
+ while len(digits3) < 4:
+ digits3 += "0"
+
+ # 6. return first 4 characters
+ return digits3[:4]
+
+if __name__ == '__main__':
+ from timeit import Timer
+ names = ('Woo', 'Pilgrim', 'Flingjingwaller')
+ for name in names:
+ statement = "soundex('%s')" % name
+ t = Timer(statement, "from __main__ import soundex")
+ print name.ljust(15), soundex(name), min(t.repeat())
diff --git a/help/diveintopython-5.4/py/soundex/stage3/soundex3b.py b/help/diveintopython-5.4/py/soundex/stage3/soundex3b.py
new file mode 100644
index 0000000..0bcbacd
--- /dev/null
+++ b/help/diveintopython-5.4/py/soundex/stage3/soundex3b.py
@@ -0,0 +1,53 @@
+"""Soundex algorithm
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.4 $"
+__date__ = "$Date: 2004/05/11 19:11:21 $"
+__copyright__ = "Copyright (c) 2004 Mark Pilgrim"
+__license__ = "Python"
+
+import string, re
+
+allChar = string.uppercase + string.lowercase
+charToSoundex = string.maketrans(allChar, "91239129922455912623919292" * 2)
+
+def soundex(source):
+ "convert string to Soundex equivalent"
+
+ # Soundex requirements:
+ # source string must be at least 1 character
+ # and must consist entirely of letters
+ if (not source) or (not source.isalpha()):
+ return "0000"
+
+ # Soundex algorithm:
+ # 1. make first character uppercase
+ # 2. translate all other characters to Soundex digits
+ digits = source[0].upper() + source[1:].translate(charToSoundex)
+
+ # 3. remove consecutive duplicates
+ digits2 = "".join([digits[i] for i in range(len(digits))
+ if i == 0 or digits[i-1] != digits[i]])
+
+ # 4. remove all "9"s
+ digits3 = re.sub('9', '', digits2)
+
+ # 5. pad end with "0"s to 4 characters
+ while len(digits3) < 4:
+ digits3 += "0"
+
+ # 6. return first 4 characters
+ return digits3[:4]
+
+if __name__ == '__main__':
+ from timeit import Timer
+ names = ('Woo', 'Pilgrim', 'Flingjingwaller')
+ for name in names:
+ statement = "soundex('%s')" % name
+ t = Timer(statement, "from __main__ import soundex")
+ print name.ljust(15), soundex(name), min(t.repeat())
diff --git a/help/diveintopython-5.4/py/soundex/stage3/soundex3c.py b/help/diveintopython-5.4/py/soundex/stage3/soundex3c.py
new file mode 100644
index 0000000..e2330f4
--- /dev/null
+++ b/help/diveintopython-5.4/py/soundex/stage3/soundex3c.py
@@ -0,0 +1,58 @@
+"""Soundex algorithm
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.3 $"
+__date__ = "$Date: 2004/05/11 19:11:21 $"
+__copyright__ = "Copyright (c) 2004 Mark Pilgrim"
+__license__ = "Python"
+
+import string, re
+
+allChar = string.uppercase + string.lowercase
+charToSoundex = string.maketrans(allChar, "91239129922455912623919292" * 2)
+
+def soundex(source):
+ "convert string to Soundex equivalent"
+
+ # Soundex requirements:
+ # source string must be at least 1 character
+ # and must consist entirely of letters
+ if (not source) or (not source.isalpha()):
+ return "0000"
+
+ # Soundex algorithm:
+ # 1. make first character uppercase
+ # 2. translate all other characters to Soundex digits
+ digits = list(source[0].upper() + source[1:].translate(charToSoundex))
+
+ # 3. remove consecutive duplicates
+ i=0
+ for item in digits:
+ if item==digits[i]: continue
+ i+=1
+ digits[i]=item
+ del digits[i+1:]
+ digits2 = "".join(digits)
+
+ # 4. remove all "9"s
+ digits3 = re.sub('9', '', digits2)
+
+ # 5. pad end with "0"s to 4 characters
+ while len(digits3) < 4:
+ digits3 += "0"
+
+ # 6. return first 4 characters
+ return digits3[:4]
+
+if __name__ == '__main__':
+ from timeit import Timer
+ names = ('Woo', 'Pilgrim', 'Flingjingwaller')
+ for name in names:
+ statement = "soundex('%s')" % name
+ t = Timer(statement, "from __main__ import soundex")
+ print name.ljust(15), soundex(name), min(t.repeat())
diff --git a/help/diveintopython-5.4/py/soundex/stage3/soundex3d.py b/help/diveintopython-5.4/py/soundex/stage3/soundex3d.py
new file mode 100644
index 0000000..1f0d331
--- /dev/null
+++ b/help/diveintopython-5.4/py/soundex/stage3/soundex3d.py
@@ -0,0 +1,55 @@
+"""Soundex algorithm
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.3 $"
+__date__ = "$Date: 2004/05/11 19:11:21 $"
+__copyright__ = "Copyright (c) 2004 Mark Pilgrim"
+__license__ = "Python"
+
+import string, re
+
+allChar = string.uppercase + string.lowercase
+charToSoundex = string.maketrans(allChar, "91239129922455912623919292" * 2)
+
+def soundex(source):
+ "convert string to Soundex equivalent"
+
+ # Soundex requirements:
+ # source string must be at least 1 character
+ # and must consist entirely of letters
+ if (not source) or (not source.isalpha()):
+ return "0000"
+
+ # Soundex algorithm:
+ # 1. make first character uppercase
+ # 2. translate all other characters to Soundex digits
+ digits = source[0].upper() + source[1:].translate(charToSoundex)
+
+ # 3. remove consecutive duplicates
+ digits2 = digits[0]
+ for d in digits[1:]:
+ if digits2[-1] != d:
+ digits2 += d
+
+ # 4. remove all "9"s
+ digits3 = re.sub('9', '', digits2)
+
+ # 5. pad end with "0"s to 4 characters
+ while len(digits3) < 4:
+ digits3 += "0"
+
+ # 6. return first 4 characters
+ return digits3[:4]
+
+if __name__ == '__main__':
+ from timeit import Timer
+ names = ('Woo', 'Pilgrim', 'Flingjingwaller')
+ for name in names:
+ statement = "soundex('%s')" % name
+ t = Timer(statement, "from __main__ import soundex")
+ print name.ljust(15), soundex(name), min(t.repeat())
diff --git a/help/diveintopython-5.4/py/soundex/stage4/soundex4a.py b/help/diveintopython-5.4/py/soundex/stage4/soundex4a.py
new file mode 100644
index 0000000..8397887
--- /dev/null
+++ b/help/diveintopython-5.4/py/soundex/stage4/soundex4a.py
@@ -0,0 +1,58 @@
+"""Soundex algorithm
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.3 $"
+__date__ = "$Date: 2004/05/11 19:11:21 $"
+__copyright__ = "Copyright (c) 2004 Mark Pilgrim"
+__license__ = "Python"
+
+import string
+
+allChar = string.uppercase + string.lowercase
+charToSoundex = string.maketrans(allChar, "91239129922455912623919292" * 2)
+
+def soundex(source):
+ "convert string to Soundex equivalent"
+
+ # Soundex requirements:
+ # source string must be at least 1 character
+ # and must consist entirely of letters
+ if (not source) or (not source.isalpha()):
+ return "0000"
+
+ # Soundex algorithm:
+ # 1. make first character uppercase
+ # 2. translate all other characters to Soundex digits
+ digits = source[0].upper() + source[1:].translate(charToSoundex)
+
+ # 3. remove consecutive duplicates
+ digits2 = digits[0]
+ for d in digits[1:]:
+ if digits2[-1] != d:
+ digits2 += d
+
+ # 4. remove all "9"s
+ digits3 = ''
+ for d in digits2:
+ if d != '9':
+ digits3 += d
+
+ # 5. pad end with "0"s to 4 characters
+ while len(digits3) < 4:
+ digits3 += "0"
+
+ # 6. return first 4 characters
+ return digits3[:4]
+
+if __name__ == '__main__':
+ from timeit import Timer
+ names = ('Woo', 'Pilgrim', 'Flingjingwaller')
+ for name in names:
+ statement = "soundex('%s')" % name
+ t = Timer(statement, "from __main__ import soundex")
+ print name.ljust(15), soundex(name), min(t.repeat())
diff --git a/help/diveintopython-5.4/py/soundex/stage4/soundex4b.py b/help/diveintopython-5.4/py/soundex/stage4/soundex4b.py
new file mode 100644
index 0000000..af6bfed
--- /dev/null
+++ b/help/diveintopython-5.4/py/soundex/stage4/soundex4b.py
@@ -0,0 +1,55 @@
+"""Soundex algorithm
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.3 $"
+__date__ = "$Date: 2004/05/11 19:11:21 $"
+__copyright__ = "Copyright (c) 2004 Mark Pilgrim"
+__license__ = "Python"
+
+import string
+
+allChar = string.uppercase + string.lowercase
+charToSoundex = string.maketrans(allChar, "91239129922455912623919292" * 2)
+
+def soundex(source):
+ "convert string to Soundex equivalent"
+
+ # Soundex requirements:
+ # source string must be at least 1 character
+ # and must consist entirely of letters
+ if (not source) or (not source.isalpha()):
+ return "0000"
+
+ # Soundex algorithm:
+ # 1. make first character uppercase
+ # 2. translate all other characters to Soundex digits
+ digits = source[0].upper() + source[1:].translate(charToSoundex)
+
+ # 3. remove consecutive duplicates
+ digits2 = digits[0]
+ for d in digits[1:]:
+ if digits2[-1] != d:
+ digits2 += d
+
+ # 4. remove all "9"s
+ digits3 = digits2.replace('9', '')
+
+ # 5. pad end with "0"s to 4 characters
+ while len(digits3) < 4:
+ digits3 += "0"
+
+ # 6. return first 4 characters
+ return digits3[:4]
+
+if __name__ == '__main__':
+ from timeit import Timer
+ names = ('Woo', 'Pilgrim', 'Flingjingwaller')
+ for name in names:
+ statement = "soundex('%s')" % name
+ t = Timer(statement, "from __main__ import soundex")
+ print name.ljust(15), soundex(name), min(t.repeat())
diff --git a/help/diveintopython-5.4/py/soundex/stage4/soundex4c.py b/help/diveintopython-5.4/py/soundex/stage4/soundex4c.py
new file mode 100644
index 0000000..4c787bd
--- /dev/null
+++ b/help/diveintopython-5.4/py/soundex/stage4/soundex4c.py
@@ -0,0 +1,54 @@
+"""Soundex algorithm
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.4 $"
+__date__ = "$Date: 2004/05/11 19:11:21 $"
+__copyright__ = "Copyright (c) 2004 Mark Pilgrim"
+__license__ = "Python"
+
+import string
+
+allChar = string.uppercase + string.lowercase
+charToSoundex = string.maketrans(allChar, "91239129922455912623919292" * 2)
+
+def soundex(source):
+ "convert string to Soundex equivalent"
+
+ # Soundex requirements:
+ # source string must be at least 1 character
+ # and must consist entirely of letters
+ if (not source) or (not source.isalpha()):
+ return "0000"
+
+ # Soundex algorithm:
+ # 1. make first character uppercase
+ # 2. translate all other characters to Soundex digits
+ digits = source[0].upper() + source[1:].translate(charToSoundex)
+
+ # 3. remove consecutive duplicates
+ digits2 = digits[0]
+ for d in digits[1:]:
+ if digits2[-1] != d:
+ digits2 += d
+
+ # 4. remove all "9"s
+ digits3 = digits2.replace('9', '')
+
+ # 5. pad end with "0"s to 4 characters
+ digits3 += '000'
+
+ # 6. return first 4 characters
+ return digits3[:4]
+
+if __name__ == '__main__':
+ from timeit import Timer
+ names = ('Woo', 'Pilgrim', 'Flingjingwaller')
+ for name in names:
+ statement = "soundex('%s')" % name
+ t = Timer(statement, "from __main__ import soundex")
+ print name.ljust(15), soundex(name), min(t.repeat())
diff --git a/help/diveintopython-5.4/py/soundex/stage4/soundex4d.py b/help/diveintopython-5.4/py/soundex/stage4/soundex4d.py
new file mode 100644
index 0000000..7306516
--- /dev/null
+++ b/help/diveintopython-5.4/py/soundex/stage4/soundex4d.py
@@ -0,0 +1,49 @@
+"""Soundex algorithm
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.4 $"
+__date__ = "$Date: 2004/05/11 19:11:21 $"
+__copyright__ = "Copyright (c) 2004 Mark Pilgrim"
+__license__ = "Python"
+
+import string
+
+allChar = string.uppercase + string.lowercase
+charToSoundex = string.maketrans(allChar, "91239129922455912623919292" * 2)
+
+def soundex(source):
+ "convert string to Soundex equivalent"
+
+ # Soundex requirements:
+ # source string must be at least 1 character
+ # and must consist entirely of letters
+ if (not source) or (not source.isalpha()):
+ return "0000"
+
+ # Soundex algorithm:
+ # 1. make first character uppercase
+ # 2. translate all other characters to Soundex digits
+ digits = source[0].upper() + source[1:].translate(charToSoundex)
+
+ # 3. remove consecutive duplicates
+ digits2 = digits[0]
+ for d in digits[1:]:
+ if digits2[-1] != d:
+ digits2 += d
+
+ # 4. remove all "9"s
+ # 5. pad end with "0"s to 4 characters
+ return (digits2.replace('9', '') + '000')[:4]
+
+if __name__ == '__main__':
+ from timeit import Timer
+ names = ('Woo', 'Pilgrim', 'Flingjingwaller')
+ for name in names:
+ statement = "soundex('%s')" % name
+ t = Timer(statement, "from __main__ import soundex")
+ print name.ljust(15), soundex(name), min(t.repeat())
diff --git a/help/diveintopython-5.4/py/soundextest.py b/help/diveintopython-5.4/py/soundextest.py
new file mode 100644
index 0000000..39baadf
--- /dev/null
+++ b/help/diveintopython-5.4/py/soundextest.py
@@ -0,0 +1,41 @@
+"""Unit test for soundex.py
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.1 $"
+__date__ = "$Date: 2004/05/06 17:18:17 $"
+__copyright__ = "Copyright (c) 2004 Mark Pilgrim"
+__license__ = "Python"
+
+import soundex
+import unittest
+
+class KnownValues(unittest.TestCase):
+ knownValues = (('', '0000'),
+ ('Woo', 'W000'),
+ ('Pilgrim', 'P426'),
+ ('Radiohead', 'R330'),
+ ('Flingjingwaller', 'F452'),
+ ('Euler', 'E460'),
+ ('Ellery', 'E460'),
+ ('Gauss', 'G200'),
+ ('Ghosh', 'G200'),
+ ('Hilbert', 'H416'),
+ ('Heilbronn', 'H416'),
+ ('Knuth', 'K530'),
+ ('Kant', 'K530'),
+ ('Lukasiewicz', 'L222'),
+ ('Lissajous', 'L222')
+ )
+
+ def testKnownValues(self):
+ """soundex should give known result with known input"""
+ for name, result in self.knownValues:
+ self.assertEqual(soundex.soundex(name), result)
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/help/diveintopython-5.4/py/statsout.py b/help/diveintopython-5.4/py/statsout.py
new file mode 100644
index 0000000..251094b
--- /dev/null
+++ b/help/diveintopython-5.4/py/statsout.py
@@ -0,0 +1,22 @@
+"""Prototype multi-output module
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.2 $"
+__date__ = "$Date: 2004/05/05 21:57:19 $"
+__copyright__ = "Copyright (c) 2004 Mark Pilgrim"
+__license__ = "Python"
+
+def statsout_html(data):
+ """Format data as HTML"""
+
+def statsout_xml(data):
+ """Format data as XML"""
+
+def statsout_text(data):
+ """Format data in plain text"""
+
diff --git a/help/diveintopython-5.4/py/unicode2koi8r.py b/help/diveintopython-5.4/py/unicode2koi8r.py
new file mode 100644
index 0000000..c0b5e16
--- /dev/null
+++ b/help/diveintopython-5.4/py/unicode2koi8r.py
@@ -0,0 +1,130 @@
+"""Convert Cyrillic from iso-8859-1 Unicode-encoded to KOI8-R-encoded
+
+This script is used during the build process of the Russian translation
+of "Dive Into Python" (http://diveintopython.org/).
+
+It takes one argument, which can be either an HTML file or a directory.
+If a file, it converts the file in place; if a directory, it converts
+every HTML file in the immediate directory (but not recursively).
+
+Safe but pointless to run more than once on the same file or directory.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.2 $"
+__date__ = "$Date: 2004/05/05 21:57:19 $"
+__copyright__ = "Copyright (c) 2001 Mark Pilgrim"
+__license__ = "Python"
+
+import os
+import sys
+import re
+
+unicodeToKOI8R = { \
+ '&#1025;': '\xb3',
+ '&#1040;': '\xe1',
+ '&#1041;': '\xe2',
+ '&#1042;': '\xf7',
+ '&#1043;': '\xe7',
+ '&#1044;': '\xe4',
+ '&#1045;': '\xe5',
+ '&#1046;': '\xf6',
+ '&#1047;': '\xfa',
+ '&#1048;': '\xe9',
+ '&#1049;': '\xea',
+ '&#1050;': '\xeb',
+ '&#1051;': '\xec',
+ '&#1052;': '\xed',
+ '&#1053;': '\xee',
+ '&#1054;': '\xef',
+ '&#1055;': '\xf0',
+ '&#1056;': '\xf2',
+ '&#1057;': '\xf3',
+ '&#1058;': '\xf4',
+ '&#1059;': '\xf5',
+ '&#1060;': '\xe6',
+ '&#1061;': '\xe8',
+ '&#1062;': '\xe3',
+ '&#1063;': '\xfe',
+ '&#1064;': '\xfb',
+ '&#1065;': '\xfd',
+ '&#1066;': '\xff',
+ '&#1067;': '\xf9',
+ '&#1068;': '\xf8',
+ '&#1069;': '\xfc',
+ '&#1070;': '\xe0',
+ '&#1071;': '\xf1',
+ '&#1072;': '\xc1',
+ '&#1073;': '\xc2',
+ '&#1074;': '\xd7',
+ '&#1075;': '\xc7',
+ '&#1076;': '\xc4',
+ '&#1077;': '\xc5',
+ '&#1078;': '\xd6',
+ '&#1079;': '\xda',
+ '&#1080;': '\xc9',
+ '&#1081;': '\xca',
+ '&#1082;': '\xcb',
+ '&#1083;': '\xcc',
+ '&#1084;': '\xcd',
+ '&#1085;': '\xce',
+ '&#1086;': '\xcf',
+ '&#1087;': '\xd0',
+ '&#1088;': '\xd2',
+ '&#1089;': '\xd3',
+ '&#1090;': '\xd4',
+ '&#1091;': '\xd5',
+ '&#1092;': '\xc6',
+ '&#1093;': '\xc8',
+ '&#1094;': '\xc3',
+ '&#1095;': '\xde',
+ '&#1096;': '\xdb',
+ '&#1097;': '\xdd',
+ '&#1098;': '\xdf',
+ '&#1099;': '\xd9',
+ '&#1100;': '\xd8',
+ '&#1101;': '\xdc',
+ '&#1102;': '\xc0',
+ '&#1103;': '\xd1',
+ '&#1105;': '\xa3' }
+
+unicodePattern = re.compile(r'&#[0-9]{4,4};')
+charsetPattern = re.compile(r'ISO-8859-1', re.IGNORECASE)
+
+def translateMatch(match):
+ unicode = match.group(0)
+ if unicodeToKOI8R.has_key(unicode):
+ return unicodeToKOI8R[unicode]
+ else:
+ return unicode
+
+def translateBuffer(buffer):
+ buffer = unicodePattern.sub(translateMatch, buffer)
+ buffer = charsetPattern.sub('KOI8-R', buffer)
+ return buffer
+
+def translateFile(filename, outfilename=None):
+ if not outfilename:
+ outfilename = filename
+ fsock = open(filename)
+ buffer = fsock.read()
+ fsock.close()
+ buffer = translateBuffer(buffer)
+ fsock = open(outfilename, 'wb')
+ fsock.write(buffer)
+ fsock.close()
+
+def htmlFilter(filename):
+ return os.path.splitext(filename)[1] == '.html'
+
+def translateDirectory(directoryname, filterFunc=htmlFilter):
+ fileList = [os.path.join(directoryname, f) for f in os.listdir(directoryname)]
+ fileList = filter(filterFunc, fileList)
+ map(translateFile, fileList)
+
+if __name__ == "__main__":
+ name = sys.argv[1]
+ if os.path.isdir(name):
+ translateDirectory(name)
+ else:
+ translateFile(name)
diff --git a/help/diveintopython-5.4/py/urllister.py b/help/diveintopython-5.4/py/urllister.py
new file mode 100644
index 0000000..ad1e391
--- /dev/null
+++ b/help/diveintopython-5.4/py/urllister.py
@@ -0,0 +1,33 @@
+"""Extract list of URLs in a web page
+
+This program is part of "Dive Into Python", a free Python book for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+"""
+
+__author__ = "Mark Pilgrim (mark@diveintopython.org)"
+__version__ = "$Revision: 1.2 $"
+__date__ = "$Date: 2004/05/05 21:57:19 $"
+__copyright__ = "Copyright (c) 2001 Mark Pilgrim"
+__license__ = "Python"
+
+from sgmllib import SGMLParser
+
+class URLLister(SGMLParser):
+ def reset(self):
+ SGMLParser.reset(self)
+ self.urls = []
+
+ def start_a(self, attrs):
+ href = [v for k, v in attrs if k=='href']
+ if href:
+ self.urls.extend(href)
+
+if __name__ == "__main__":
+ import urllib
+ usock = urllib.urlopen("http://diveintopython.org/")
+ parser = URLLister()
+ parser.feed(usock.read())
+ parser.close()
+ usock.close()
+ for url in parser.urls: print url
diff --git a/help/images/3080617962_604fcfe2ed.jpg b/help/images/3080617962_604fcfe2ed.jpg
new file mode 100644
index 0000000..6dced90
--- /dev/null
+++ b/help/images/3080617962_604fcfe2ed.jpg
Binary files differ
diff --git a/help/images/Edit Page.jpg b/help/images/Edit Page.jpg
new file mode 100644
index 0000000..a3bc8c0
--- /dev/null
+++ b/help/images/Edit Page.jpg
Binary files differ
diff --git a/help/images/Help Page.jpg b/help/images/Help Page.jpg
new file mode 100644
index 0000000..cff5e83
--- /dev/null
+++ b/help/images/Help Page.jpg
Binary files differ
diff --git a/help/images/Project Page.jpg b/help/images/Project Page.jpg
new file mode 100644
index 0000000..057cb2a
--- /dev/null
+++ b/help/images/Project Page.jpg
Binary files differ
diff --git a/help/images/Terminal_Ipython Page.jpg b/help/images/Terminal_Ipython Page.jpg
new file mode 100644
index 0000000..3f8a225
--- /dev/null
+++ b/help/images/Terminal_Ipython Page.jpg
Binary files differ
diff --git a/help/images/Your Program Output Page.jpg b/help/images/Your Program Output Page.jpg
new file mode 100644
index 0000000..7b73038
--- /dev/null
+++ b/help/images/Your Program Output Page.jpg
Binary files differ
diff --git a/help/images/journal.jpg b/help/images/journal.jpg
new file mode 100644
index 0000000..9df3033
--- /dev/null
+++ b/help/images/journal.jpg
Binary files differ
diff --git a/help/images/project page.png b/help/images/project page.png
new file mode 100644
index 0000000..4a79bea
--- /dev/null
+++ b/help/images/project page.png
Binary files differ
diff --git a/help/images/project page_2.png b/help/images/project page_2.png
new file mode 100644
index 0000000..3acc589
--- /dev/null
+++ b/help/images/project page_2.png
Binary files differ
diff --git a/help/images/project page_3.png b/help/images/project page_3.png
new file mode 100644
index 0000000..d1d28c4
--- /dev/null
+++ b/help/images/project page_3.png
Binary files differ
diff --git a/help/images/project_whole.jpg b/help/images/project_whole.jpg
new file mode 100644
index 0000000..988d7b1
--- /dev/null
+++ b/help/images/project_whole.jpg
Binary files differ
diff --git a/help/ipythonbook/doc/rel-0.10/html/_images/inheritance471b45c3f1.png b/help/ipythonbook/doc/rel-0.10/html/_images/inheritance471b45c3f1.png
new file mode 100644
index 0000000..3279b4a
--- /dev/null
+++ b/help/ipythonbook/doc/rel-0.10/html/_images/inheritance471b45c3f1.png
Binary files differ
diff --git a/help/ipythonbook/doc/rel-0.10/html/_sources/interactive/reference.txt b/help/ipythonbook/doc/rel-0.10/html/_sources/interactive/reference.txt
new file mode 100644
index 0000000..023a5ec
--- /dev/null
+++ b/help/ipythonbook/doc/rel-0.10/html/_sources/interactive/reference.txt
@@ -0,0 +1,1631 @@
+=================
+IPython reference
+=================
+
+.. _command_line_options:
+
+Command-line usage
+==================
+
+You start IPython with the command::
+
+ $ ipython [options] files
+
+If invoked with no options, it executes all the files listed in sequence
+and drops you into the interpreter while still acknowledging any options
+you may have set in your ipythonrc file. This behavior is different from
+standard Python, which when called as python -i will only execute one
+file and ignore your configuration setup.
+
+Please note that some of the configuration options are not available at
+the command line, simply because they are not practical here. Look into
+your ipythonrc configuration file for details on those. This file
+typically installed in the $HOME/.ipython directory. For Windows users,
+$HOME resolves to C:\\Documents and Settings\\YourUserName in most
+instances. In the rest of this text, we will refer to this directory as
+IPYTHONDIR.
+
+.. _Threading options:
+
+
+Special Threading Options
+-------------------------
+
+The following special options are ONLY valid at the beginning of the
+command line, and not later. This is because they control the initial-
+ization of ipython itself, before the normal option-handling mechanism
+is active.
+
+ -gthread, -qthread, -q4thread, -wthread, -pylab:
+ Only one of these can be given, and it can only be given as
+ the first option passed to IPython (it will have no effect in
+ any other position). They provide threading support for the
+ GTK, Qt (versions 3 and 4) and WXPython toolkits, and for the
+ matplotlib library.
+
+ With any of the first four options, IPython starts running a
+ separate thread for the graphical toolkit's operation, so that
+ you can open and control graphical elements from within an
+ IPython command line, without blocking. All four provide
+ essentially the same functionality, respectively for GTK, Qt3,
+ Qt4 and WXWidgets (via their Python interfaces).
+
+ Note that with -wthread, you can additionally use the
+ -wxversion option to request a specific version of wx to be
+ used. This requires that you have the wxversion Python module
+ installed, which is part of recent wxPython distributions.
+
+ If -pylab is given, IPython loads special support for the mat
+ plotlib library (http://matplotlib.sourceforge.net), allowing
+ interactive usage of any of its backends as defined in the
+ user's ~/.matplotlib/matplotlibrc file. It automatically
+ activates GTK, Qt or WX threading for IPyhton if the choice of
+ matplotlib backend requires it. It also modifies the %run
+ command to correctly execute (without blocking) any
+ matplotlib-based script which calls show() at the end.
+
+ -tk
+ The -g/q/q4/wthread options, and -pylab (if matplotlib is
+ configured to use GTK, Qt3, Qt4 or WX), will normally block Tk
+ graphical interfaces. This means that when either GTK, Qt or WX
+ threading is active, any attempt to open a Tk GUI will result in a
+ dead window, and possibly cause the Python interpreter to crash.
+ An extra option, -tk, is available to address this issue. It can
+ only be given as a second option after any of the above (-gthread,
+ -wthread or -pylab).
+
+ If -tk is given, IPython will try to coordinate Tk threading
+ with GTK, Qt or WX. This is however potentially unreliable, and
+ you will have to test on your platform and Python configuration to
+ determine whether it works for you. Debian users have reported
+ success, apparently due to the fact that Debian builds all of Tcl,
+ Tk, Tkinter and Python with pthreads support. Under other Linux
+ environments (such as Fedora Core 2/3), this option has caused
+ random crashes and lockups of the Python interpreter. Under other
+ operating systems (Mac OSX and Windows), you'll need to try it to
+ find out, since currently no user reports are available.
+
+ There is unfortunately no way for IPython to determine at run time
+ whether -tk will work reliably or not, so you will need to do some
+ experiments before relying on it for regular work.
+
+
+
+Regular Options
+---------------
+
+After the above threading options have been given, regular options can
+follow in any order. All options can be abbreviated to their shortest
+non-ambiguous form and are case-sensitive. One or two dashes can be
+used. Some options have an alternate short form, indicated after a ``|``.
+
+Most options can also be set from your ipythonrc configuration file. See
+the provided example for more details on what the options do. Options
+given at the command line override the values set in the ipythonrc file.
+
+All options with a [no] prepended can be specified in negated form
+(-nooption instead of -option) to turn the feature off.
+
+ -help print a help message and exit.
+
+ -pylab
+ this can only be given as the first option passed to IPython
+ (it will have no effect in any other position). It adds
+ special support for the matplotlib library
+ (http://matplotlib.sourceforge.ne), allowing interactive usage
+ of any of its backends as defined in the user's .matplotlibrc
+ file. It automatically activates GTK or WX threading for
+ IPyhton if the choice of matplotlib backend requires it. It
+ also modifies the %run command to correctly execute (without
+ blocking) any matplotlib-based script which calls show() at
+ the end. See `Matplotlib support`_ for more details.
+
+ -autocall <val>
+ Make IPython automatically call any callable object even if you
+ didn't type explicit parentheses. For example, 'str 43' becomes
+ 'str(43)' automatically. The value can be '0' to disable the feature,
+ '1' for smart autocall, where it is not applied if there are no more
+ arguments on the line, and '2' for full autocall, where all callable
+ objects are automatically called (even if no arguments are
+ present). The default is '1'.
+
+ -[no]autoindent
+ Turn automatic indentation on/off.
+
+ -[no]automagic
+ make magic commands automatic (without needing their first character
+ to be %). Type %magic at the IPython prompt for more information.
+
+ -[no]autoedit_syntax
+ When a syntax error occurs after editing a file, automatically
+ open the file to the trouble causing line for convenient
+ fixing.
+
+ -[no]banner Print the initial information banner (default on).
+
+ -c <command>
+ execute the given command string. This is similar to the -c
+ option in the normal Python interpreter.
+
+ -cache_size, cs <n>
+ size of the output cache (maximum number of entries to hold in
+ memory). The default is 1000, you can change it permanently in your
+ config file. Setting it to 0 completely disables the caching system,
+ and the minimum value accepted is 20 (if you provide a value less than
+ 20, it is reset to 0 and a warning is issued) This limit is defined
+ because otherwise you'll spend more time re-flushing a too small cache
+ than working.
+
+ -classic, cl
+ Gives IPython a similar feel to the classic Python
+ prompt.
+
+ -colors <scheme>
+ Color scheme for prompts and exception reporting. Currently
+ implemented: NoColor, Linux and LightBG.
+
+ -[no]color_info
+ IPython can display information about objects via a set of functions,
+ and optionally can use colors for this, syntax highlighting source
+ code and various other elements. However, because this information is
+ passed through a pager (like 'less') and many pagers get confused with
+ color codes, this option is off by default. You can test it and turn
+ it on permanently in your ipythonrc file if it works for you. As a
+ reference, the 'less' pager supplied with Mandrake 8.2 works ok, but
+ that in RedHat 7.2 doesn't.
+
+ Test it and turn it on permanently if it works with your
+ system. The magic function %color_info allows you to toggle this
+ interactively for testing.
+
+ -[no]debug
+ Show information about the loading process. Very useful to pin down
+ problems with your configuration files or to get details about
+ session restores.
+
+ -[no]deep_reload:
+ IPython can use the deep_reload module which reloads changes in
+ modules recursively (it replaces the reload() function, so you don't
+ need to change anything to use it). deep_reload() forces a full
+ reload of modules whose code may have changed, which the default
+ reload() function does not.
+
+ When deep_reload is off, IPython will use the normal reload(),
+ but deep_reload will still be available as dreload(). This
+ feature is off by default [which means that you have both
+ normal reload() and dreload()].
+
+ -editor <name>
+ Which editor to use with the %edit command. By default,
+ IPython will honor your EDITOR environment variable (if not
+ set, vi is the Unix default and notepad the Windows one).
+ Since this editor is invoked on the fly by IPython and is
+ meant for editing small code snippets, you may want to use a
+ small, lightweight editor here (in case your default EDITOR is
+ something like Emacs).
+
+ -ipythondir <name>
+ name of your IPython configuration directory IPYTHONDIR. This
+ can also be specified through the environment variable
+ IPYTHONDIR.
+
+ -log, l
+ generate a log file of all input. The file is named
+ ipython_log.py in your current directory (which prevents logs
+ from multiple IPython sessions from trampling each other). You
+ can use this to later restore a session by loading your
+ logfile as a file to be executed with option -logplay (see
+ below).
+
+ -logfile, lf <name> specify the name of your logfile.
+
+ -logplay, lp <name>
+
+ you can replay a previous log. For restoring a session as close as
+ possible to the state you left it in, use this option (don't just run
+ the logfile). With -logplay, IPython will try to reconstruct the
+ previous working environment in full, not just execute the commands in
+ the logfile.
+
+ When a session is restored, logging is automatically turned on
+ again with the name of the logfile it was invoked with (it is
+ read from the log header). So once you've turned logging on for
+ a session, you can quit IPython and reload it as many times as
+ you want and it will continue to log its history and restore
+ from the beginning every time.
+
+ Caveats: there are limitations in this option. The history
+ variables _i*,_* and _dh don't get restored properly. In the
+ future we will try to implement full session saving by writing
+ and retrieving a 'snapshot' of the memory state of IPython. But
+ our first attempts failed because of inherent limitations of
+ Python's Pickle module, so this may have to wait.
+
+ -[no]messages
+ Print messages which IPython collects about its startup
+ process (default on).
+
+ -[no]pdb
+ Automatically call the pdb debugger after every uncaught
+ exception. If you are used to debugging using pdb, this puts
+ you automatically inside of it after any call (either in
+ IPython or in code called by it) which triggers an exception
+ which goes uncaught.
+
+ -pydb
+ Makes IPython use the third party "pydb" package as debugger,
+ instead of pdb. Requires that pydb is installed.
+
+ -[no]pprint
+ ipython can optionally use the pprint (pretty printer) module
+ for displaying results. pprint tends to give a nicer display
+ of nested data structures. If you like it, you can turn it on
+ permanently in your config file (default off).
+
+ -profile, p <name>
+
+ assume that your config file is ipythonrc-<name> or
+ ipy_profile_<name>.py (looks in current dir first, then in
+ IPYTHONDIR). This is a quick way to keep and load multiple
+ config files for different tasks, especially if you use the
+ include option of config files. You can keep a basic
+ IPYTHONDIR/ipythonrc file and then have other 'profiles' which
+ include this one and load extra things for particular
+ tasks. For example:
+
+ 1. $HOME/.ipython/ipythonrc : load basic things you always want.
+ 2. $HOME/.ipython/ipythonrc-math : load (1) and basic math-related modules.
+ 3. $HOME/.ipython/ipythonrc-numeric : load (1) and Numeric and plotting modules.
+
+ Since it is possible to create an endless loop by having
+ circular file inclusions, IPython will stop if it reaches 15
+ recursive inclusions.
+
+ -prompt_in1, pi1 <string>
+
+ Specify the string used for input prompts. Note that if you are using
+ numbered prompts, the number is represented with a '\#' in the
+ string. Don't forget to quote strings with spaces embedded in
+ them. Default: 'In [\#]:'. The :ref:`prompts section <prompts>`
+ discusses in detail all the available escapes to customize your
+ prompts.
+
+ -prompt_in2, pi2 <string>
+ Similar to the previous option, but used for the continuation
+ prompts. The special sequence '\D' is similar to '\#', but
+ with all digits replaced dots (so you can have your
+ continuation prompt aligned with your input prompt). Default:
+ ' .\D.:' (note three spaces at the start for alignment with
+ 'In [\#]').
+
+ -prompt_out,po <string>
+ String used for output prompts, also uses numbers like
+ prompt_in1. Default: 'Out[\#]:'
+
+ -quick start in bare bones mode (no config file loaded).
+
+ -rcfile <name>
+ name of your IPython resource configuration file. Normally
+ IPython loads ipythonrc (from current directory) or
+ IPYTHONDIR/ipythonrc.
+
+ If the loading of your config file fails, IPython starts with
+ a bare bones configuration (no modules loaded at all).
+
+ -[no]readline
+ use the readline library, which is needed to support name
+ completion and command history, among other things. It is
+ enabled by default, but may cause problems for users of
+ X/Emacs in Python comint or shell buffers.
+
+ Note that X/Emacs 'eterm' buffers (opened with M-x term) support
+ IPython's readline and syntax coloring fine, only 'emacs' (M-x
+ shell and C-c !) buffers do not.
+
+ -screen_length, sl <n>
+ number of lines of your screen. This is used to control
+ printing of very long strings. Strings longer than this number
+ of lines will be sent through a pager instead of directly
+ printed.
+
+ The default value for this is 0, which means IPython will
+ auto-detect your screen size every time it needs to print certain
+ potentially long strings (this doesn't change the behavior of the
+ 'print' keyword, it's only triggered internally). If for some
+ reason this isn't working well (it needs curses support), specify
+ it yourself. Otherwise don't change the default.
+
+ -separate_in, si <string>
+
+ separator before input prompts.
+ Default: '\n'
+
+ -separate_out, so <string>
+ separator before output prompts.
+ Default: nothing.
+
+ -separate_out2, so2
+ separator after output prompts.
+ Default: nothing.
+ For these three options, use the value 0 to specify no separator.
+
+ -nosep
+ shorthand for '-SeparateIn 0 -SeparateOut 0 -SeparateOut2
+ 0'. Simply removes all input/output separators.
+
+ -upgrade
+ allows you to upgrade your IPYTHONDIR configuration when you
+ install a new version of IPython. Since new versions may
+ include new command line options or example files, this copies
+ updated ipythonrc-type files. However, it backs up (with a
+ .old extension) all files which it overwrites so that you can
+ merge back any customizations you might have in your personal
+ files. Note that you should probably use %upgrade instead,
+ it's a safer alternative.
+
+
+ -Version print version information and exit.
+
+ -wxversion <string>
+ Select a specific version of wxPython (used in conjunction
+ with -wthread). Requires the wxversion module, part of recent
+ wxPython distributions
+
+ -xmode <modename>
+
+ Mode for exception reporting.
+
+ Valid modes: Plain, Context and Verbose.
+
+ * Plain: similar to python's normal traceback printing.
+ * Context: prints 5 lines of context source code around each
+ line in the traceback.
+ * Verbose: similar to Context, but additionally prints the
+ variables currently visible where the exception happened
+ (shortening their strings if too long). This can potentially be
+ very slow, if you happen to have a huge data structure whose
+ string representation is complex to compute. Your computer may
+ appear to freeze for a while with cpu usage at 100%. If this
+ occurs, you can cancel the traceback with Ctrl-C (maybe hitting it
+ more than once).
+
+Interactive use
+===============
+
+Warning: IPython relies on the existence of a global variable called
+_ip which controls the shell itself. If you redefine _ip to anything,
+bizarre behavior will quickly occur.
+
+Other than the above warning, IPython is meant to work as a drop-in
+replacement for the standard interactive interpreter. As such, any code
+which is valid python should execute normally under IPython (cases where
+this is not true should be reported as bugs). It does, however, offer
+many features which are not available at a standard python prompt. What
+follows is a list of these.
+
+
+Caution for Windows users
+-------------------------
+
+Windows, unfortunately, uses the '\' character as a path
+separator. This is a terrible choice, because '\' also represents the
+escape character in most modern programming languages, including
+Python. For this reason, using '/' character is recommended if you
+have problems with ``\``. However, in Windows commands '/' flags
+options, so you can not use it for the root directory. This means that
+paths beginning at the root must be typed in a contrived manner like:
+``%copy \opt/foo/bar.txt \tmp``
+
+.. _magic:
+
+Magic command system
+--------------------
+
+IPython will treat any line whose first character is a % as a special
+call to a 'magic' function. These allow you to control the behavior of
+IPython itself, plus a lot of system-type features. They are all
+prefixed with a % character, but parameters are given without
+parentheses or quotes.
+
+Example: typing '%cd mydir' (without the quotes) changes you working
+directory to 'mydir', if it exists.
+
+If you have 'automagic' enabled (in your ipythonrc file, via the command
+line option -automagic or with the %automagic function), you don't need
+to type in the % explicitly. IPython will scan its internal list of
+magic functions and call one if it exists. With automagic on you can
+then just type 'cd mydir' to go to directory 'mydir'. The automagic
+system has the lowest possible precedence in name searches, so defining
+an identifier with the same name as an existing magic function will
+shadow it for automagic use. You can still access the shadowed magic
+function by explicitly using the % character at the beginning of the line.
+
+An example (with automagic on) should clarify all this::
+
+ In [1]: cd ipython # %cd is called by automagic
+
+ /home/fperez/ipython
+
+ In [2]: cd=1 # now cd is just a variable
+
+ In [3]: cd .. # and doesn't work as a function anymore
+
+ ------------------------------
+
+ File "<console>", line 1
+
+ cd ..
+
+ ^
+
+ SyntaxError: invalid syntax
+
+ In [4]: %cd .. # but %cd always works
+
+ /home/fperez
+
+ In [5]: del cd # if you remove the cd variable
+
+ In [6]: cd ipython # automagic can work again
+
+ /home/fperez/ipython
+
+You can define your own magic functions to extend the system. The
+following example defines a new magic command, %impall::
+
+ import IPython.ipapi
+
+ ip = IPython.ipapi.get()
+
+ def doimp(self, arg):
+
+ ip = self.api
+
+ ip.ex("import %s; reload(%s); from %s import *" % (
+
+ arg,arg,arg)
+
+ )
+
+ ip.expose_magic('impall', doimp)
+
+You can also define your own aliased names for magic functions. In your
+ipythonrc file, placing a line like::
+
+ execute __IP.magic_cl = __IP.magic_clear
+
+will define %cl as a new name for %clear.
+
+Type %magic for more information, including a list of all available
+magic functions at any time and their docstrings. You can also type
+%magic_function_name? (see sec. 6.4 <#sec:dyn-object-info> for
+information on the '?' system) to get information about any particular
+magic function you are interested in.
+
+The API documentation for the :mod:`IPython.Magic` module contains the full
+docstrings of all currently available magic commands.
+
+
+Access to the standard Python help
+----------------------------------
+
+As of Python 2.1, a help system is available with access to object docstrings
+and the Python manuals. Simply type 'help' (no quotes) to access it. You can
+also type help(object) to obtain information about a given object, and
+help('keyword') for information on a keyword. As noted :ref:`here
+<accessing_help>`, you need to properly configure your environment variable
+PYTHONDOCS for this feature to work correctly.
+
+.. _dynamic_object_info:
+
+Dynamic object information
+--------------------------
+
+Typing ?word or word? prints detailed information about an object. If
+certain strings in the object are too long (docstrings, code, etc.) they
+get snipped in the center for brevity. This system gives access variable
+types and values, full source code for any object (if available),
+function prototypes and other useful information.
+
+Typing ??word or word?? gives access to the full information without
+snipping long strings. Long strings are sent to the screen through the
+less pager if longer than the screen and printed otherwise. On systems
+lacking the less command, IPython uses a very basic internal pager.
+
+The following magic functions are particularly useful for gathering
+information about your working environment. You can get more details by
+typing %magic or querying them individually (use %function_name? with or
+without the %), this is just a summary:
+
+ * **%pdoc <object>**: Print (or run through a pager if too long) the
+ docstring for an object. If the given object is a class, it will
+ print both the class and the constructor docstrings.
+ * **%pdef <object>**: Print the definition header for any callable
+ object. If the object is a class, print the constructor information.
+ * **%psource <object>**: Print (or run through a pager if too long)
+ the source code for an object.
+ * **%pfile <object>**: Show the entire source file where an object was
+ defined via a pager, opening it at the line where the object
+ definition begins.
+ * **%who/%whos**: These functions give information about identifiers
+ you have defined interactively (not things you loaded or defined
+ in your configuration files). %who just prints a list of
+ identifiers and %whos prints a table with some basic details about
+ each identifier.
+
+Note that the dynamic object information functions (?/??, %pdoc, %pfile,
+%pdef, %psource) give you access to documentation even on things which
+are not really defined as separate identifiers. Try for example typing
+{}.get? or after doing import os, type os.path.abspath??.
+
+
+.. _readline:
+
+Readline-based features
+-----------------------
+
+These features require the GNU readline library, so they won't work if
+your Python installation lacks readline support. We will first describe
+the default behavior IPython uses, and then how to change it to suit
+your preferences.
+
+
+Command line completion
++++++++++++++++++++++++
+
+At any time, hitting TAB will complete any available python commands or
+variable names, and show you a list of the possible completions if
+there's no unambiguous one. It will also complete filenames in the
+current directory if no python names match what you've typed so far.
+
+
+Search command history
+++++++++++++++++++++++
+
+IPython provides two ways for searching through previous input and thus
+reduce the need for repetitive typing:
+
+ 1. Start typing, and then use Ctrl-p (previous,up) and Ctrl-n
+ (next,down) to search through only the history items that match
+ what you've typed so far. If you use Ctrl-p/Ctrl-n at a blank
+ prompt, they just behave like normal arrow keys.
+ 2. Hit Ctrl-r: opens a search prompt. Begin typing and the system
+ searches your history for lines that contain what you've typed so
+ far, completing as much as it can.
+
+
+Persistent command history across sessions
+++++++++++++++++++++++++++++++++++++++++++
+
+IPython will save your input history when it leaves and reload it next
+time you restart it. By default, the history file is named
+$IPYTHONDIR/history, but if you've loaded a named profile,
+'-PROFILE_NAME' is appended to the name. This allows you to keep
+separate histories related to various tasks: commands related to
+numerical work will not be clobbered by a system shell history, for
+example.
+
+
+Autoindent
+++++++++++
+
+IPython can recognize lines ending in ':' and indent the next line,
+while also un-indenting automatically after 'raise' or 'return'.
+
+This feature uses the readline library, so it will honor your ~/.inputrc
+configuration (or whatever file your INPUTRC variable points to). Adding
+the following lines to your .inputrc file can make indenting/unindenting
+more convenient (M-i indents, M-u unindents)::
+
+ $if Python
+ "\M-i": " "
+ "\M-u": "\d\d\d\d"
+ $endif
+
+Note that there are 4 spaces between the quote marks after "M-i" above.
+
+Warning: this feature is ON by default, but it can cause problems with
+the pasting of multi-line indented code (the pasted code gets
+re-indented on each line). A magic function %autoindent allows you to
+toggle it on/off at runtime. You can also disable it permanently on in
+your ipythonrc file (set autoindent 0).
+
+
+Customizing readline behavior
++++++++++++++++++++++++++++++
+
+All these features are based on the GNU readline library, which has an
+extremely customizable interface. Normally, readline is configured via a
+file which defines the behavior of the library; the details of the
+syntax for this can be found in the readline documentation available
+with your system or on the Internet. IPython doesn't read this file (if
+it exists) directly, but it does support passing to readline valid
+options via a simple interface. In brief, you can customize readline by
+setting the following options in your ipythonrc configuration file (note
+that these options can not be specified at the command line):
+
+ * **readline_parse_and_bind**: this option can appear as many times as
+ you want, each time defining a string to be executed via a
+ readline.parse_and_bind() command. The syntax for valid commands
+ of this kind can be found by reading the documentation for the GNU
+ readline library, as these commands are of the kind which readline
+ accepts in its configuration file.
+ * **readline_remove_delims**: a string of characters to be removed
+ from the default word-delimiters list used by readline, so that
+ completions may be performed on strings which contain them. Do not
+ change the default value unless you know what you're doing.
+ * **readline_omit__names**: when tab-completion is enabled, hitting
+ <tab> after a '.' in a name will complete all attributes of an
+ object, including all the special methods whose names include
+ double underscores (like __getitem__ or __class__). If you'd
+ rather not see these names by default, you can set this option to
+ 1. Note that even when this option is set, you can still see those
+ names by explicitly typing a _ after the period and hitting <tab>:
+ 'name._<tab>' will always complete attribute names starting with '_'.
+
+ This option is off by default so that new users see all
+ attributes of any objects they are dealing with.
+
+You will find the default values along with a corresponding detailed
+explanation in your ipythonrc file.
+
+
+Session logging and restoring
+-----------------------------
+
+You can log all input from a session either by starting IPython with the
+command line switches -log or -logfile (see :ref:`here <command_line_options>`)
+or by activating the logging at any moment with the magic function %logstart.
+
+Log files can later be reloaded with the -logplay option and IPython
+will attempt to 'replay' the log by executing all the lines in it, thus
+restoring the state of a previous session. This feature is not quite
+perfect, but can still be useful in many cases.
+
+The log files can also be used as a way to have a permanent record of
+any code you wrote while experimenting. Log files are regular text files
+which you can later open in your favorite text editor to extract code or
+to 'clean them up' before using them to replay a session.
+
+The %logstart function for activating logging in mid-session is used as
+follows:
+
+%logstart [log_name [log_mode]]
+
+If no name is given, it defaults to a file named 'log' in your
+IPYTHONDIR directory, in 'rotate' mode (see below).
+
+'%logstart name' saves to file 'name' in 'backup' mode. It saves your
+history up to that point and then continues logging.
+
+%logstart takes a second optional parameter: logging mode. This can be
+one of (note that the modes are given unquoted):
+
+ * [over:] overwrite existing log_name.
+ * [backup:] rename (if exists) to log_name~ and start log_name.
+ * [append:] well, that says it.
+ * [rotate:] create rotating logs log_name.1~, log_name.2~, etc.
+
+The %logoff and %logon functions allow you to temporarily stop and
+resume logging to a file which had previously been started with
+%logstart. They will fail (with an explanation) if you try to use them
+before logging has been started.
+
+.. _system_shell_access:
+
+System shell access
+-------------------
+
+Any input line beginning with a ! character is passed verbatim (minus
+the !, of course) to the underlying operating system. For example,
+typing !ls will run 'ls' in the current directory.
+
+Manual capture of command output
+--------------------------------
+
+If the input line begins with two exclamation marks, !!, the command is
+executed but its output is captured and returned as a python list, split
+on newlines. Any output sent by the subprocess to standard error is
+printed separately, so that the resulting list only captures standard
+output. The !! syntax is a shorthand for the %sx magic command.
+
+Finally, the %sc magic (short for 'shell capture') is similar to %sx,
+but allowing more fine-grained control of the capture details, and
+storing the result directly into a named variable. The direct use of
+%sc is now deprecated, and you should ise the ``var = !cmd`` syntax
+instead.
+
+IPython also allows you to expand the value of python variables when
+making system calls. Any python variable or expression which you prepend
+with $ will get expanded before the system call is made::
+
+ In [1]: pyvar='Hello world'
+ In [2]: !echo "A python variable: $pyvar"
+ A python variable: Hello world
+
+If you want the shell to actually see a literal $, you need to type it
+twice::
+
+ In [3]: !echo "A system variable: $$HOME"
+ A system variable: /home/fperez
+
+You can pass arbitrary expressions, though you'll need to delimit them
+with {} if there is ambiguity as to the extent of the expression::
+
+ In [5]: x=10
+ In [6]: y=20
+ In [13]: !echo $x+y
+ 10+y
+ In [7]: !echo ${x+y}
+ 30
+
+Even object attributes can be expanded::
+
+ In [12]: !echo $sys.argv
+ [/home/fperez/usr/bin/ipython]
+
+
+System command aliases
+----------------------
+
+The %alias magic function and the alias option in the ipythonrc
+configuration file allow you to define magic functions which are in fact
+system shell commands. These aliases can have parameters.
+
+'%alias alias_name cmd' defines 'alias_name' as an alias for 'cmd'
+
+Then, typing '%alias_name params' will execute the system command 'cmd
+params' (from your underlying operating system).
+
+You can also define aliases with parameters using %s specifiers (one per
+parameter). The following example defines the %parts function as an
+alias to the command 'echo first %s second %s' where each %s will be
+replaced by a positional parameter to the call to %parts::
+
+ In [1]: alias parts echo first %s second %s
+ In [2]: %parts A B
+ first A second B
+ In [3]: %parts A
+ Incorrect number of arguments: 2 expected.
+ parts is an alias to: 'echo first %s second %s'
+
+If called with no parameters, %alias prints the table of currently
+defined aliases.
+
+The %rehash/rehashx magics allow you to load your entire $PATH as
+ipython aliases. See their respective docstrings (or sec. 6.2
+<#sec:magic> for further details).
+
+
+.. _dreload:
+
+Recursive reload
+----------------
+
+The dreload function does a recursive reload of a module: changes made
+to the module since you imported will actually be available without
+having to exit.
+
+
+Verbose and colored exception traceback printouts
+-------------------------------------------------
+
+IPython provides the option to see very detailed exception tracebacks,
+which can be especially useful when debugging large programs. You can
+run any Python file with the %run function to benefit from these
+detailed tracebacks. Furthermore, both normal and verbose tracebacks can
+be colored (if your terminal supports it) which makes them much easier
+to parse visually.
+
+See the magic xmode and colors functions for details (just type %magic).
+
+These features are basically a terminal version of Ka-Ping Yee's cgitb
+module, now part of the standard Python library.
+
+
+.. _input_caching:
+
+Input caching system
+--------------------
+
+IPython offers numbered prompts (In/Out) with input and output caching
+(also referred to as 'input history'). All input is saved and can be
+retrieved as variables (besides the usual arrow key recall), in
+addition to the %rep magic command that brings a history entry
+up for editing on the next command line.
+
+The following GLOBAL variables always exist (so don't overwrite them!):
+_i: stores previous input. _ii: next previous. _iii: next-next previous.
+_ih : a list of all input _ih[n] is the input from line n and this list
+is aliased to the global variable In. If you overwrite In with a
+variable of your own, you can remake the assignment to the internal list
+with a simple 'In=_ih'.
+
+Additionally, global variables named _i<n> are dynamically created (<n>
+being the prompt counter), such that
+_i<n> == _ih[<n>] == In[<n>].
+
+For example, what you typed at prompt 14 is available as _i14, _ih[14]
+and In[14].
+
+This allows you to easily cut and paste multi line interactive prompts
+by printing them out: they print like a clean string, without prompt
+characters. You can also manipulate them like regular variables (they
+are strings), modify or exec them (typing 'exec _i9' will re-execute the
+contents of input prompt 9, 'exec In[9:14]+In[18]' will re-execute lines
+9 through 13 and line 18).
+
+You can also re-execute multiple lines of input easily by using the
+magic %macro function (which automates the process and allows
+re-execution without having to type 'exec' every time). The macro system
+also allows you to re-execute previous lines which include magic
+function calls (which require special processing). Type %macro? or see
+sec. 6.2 <#sec:magic> for more details on the macro system.
+
+A history function %hist allows you to see any part of your input
+history by printing a range of the _i variables.
+
+You can also search ('grep') through your history by typing
+'%hist -g somestring'. This also searches through the so called *shadow history*,
+which remembers all the commands (apart from multiline code blocks)
+you have ever entered. Handy for searching for svn/bzr URL's, IP adrresses
+etc. You can bring shadow history entries listed by '%hist -g' up for editing
+(or re-execution by just pressing ENTER) with %rep command. Shadow history
+entries are not available as _iNUMBER variables, and they are identified by
+the '0' prefix in %hist -g output. That is, history entry 12 is a normal
+history entry, but 0231 is a shadow history entry.
+
+Shadow history was added because the readline history is inherently very
+unsafe - if you have multiple IPython sessions open, the last session
+to close will overwrite the history of previountly closed session. Likewise,
+if a crash occurs, history is never saved, whereas shadow history entries
+are added after entering every command (so a command executed
+in another IPython session is immediately available in other IPython
+sessions that are open).
+
+To conserve space, a command can exist in shadow history only once - it doesn't
+make sense to store a common line like "cd .." a thousand times. The idea is
+mainly to provide a reliable place where valuable, hard-to-remember commands can
+always be retrieved, as opposed to providing an exact sequence of commands
+you have entered in actual order.
+
+Because shadow history has all the commands you have ever executed,
+time taken by %hist -g will increase oven time. If it ever starts to take
+too long (or it ends up containing sensitive information like passwords),
+clear the shadow history by `%clear shadow_nuke`.
+
+Time taken to add entries to shadow history should be negligible, but
+in any case, if you start noticing performance degradation after using
+IPython for a long time (or running a script that floods the shadow history!),
+you can 'compress' the shadow history by executing
+`%clear shadow_compress`. In practice, this should never be necessary
+in normal use.
+
+.. _output_caching:
+
+Output caching system
+---------------------
+
+For output that is returned from actions, a system similar to the input
+cache exists but using _ instead of _i. Only actions that produce a
+result (NOT assignments, for example) are cached. If you are familiar
+with Mathematica, IPython's _ variables behave exactly like
+Mathematica's % variables.
+
+The following GLOBAL variables always exist (so don't overwrite them!):
+
+ * [_] (a single underscore) : stores previous output, like Python's
+ default interpreter.
+ * [__] (two underscores): next previous.
+ * [___] (three underscores): next-next previous.
+
+Additionally, global variables named _<n> are dynamically created (<n>
+being the prompt counter), such that the result of output <n> is always
+available as _<n> (don't use the angle brackets, just the number, e.g.
+_21).
+
+These global variables are all stored in a global dictionary (not a
+list, since it only has entries for lines which returned a result)
+available under the names _oh and Out (similar to _ih and In). So the
+output from line 12 can be obtained as _12, Out[12] or _oh[12]. If you
+accidentally overwrite the Out variable you can recover it by typing
+'Out=_oh' at the prompt.
+
+This system obviously can potentially put heavy memory demands on your
+system, since it prevents Python's garbage collector from removing any
+previously computed results. You can control how many results are kept
+in memory with the option (at the command line or in your ipythonrc
+file) cache_size. If you set it to 0, the whole system is completely
+disabled and the prompts revert to the classic '>>>' of normal Python.
+
+
+Directory history
+-----------------
+
+Your history of visited directories is kept in the global list _dh, and
+the magic %cd command can be used to go to any entry in that list. The
+%dhist command allows you to view this history. Do ``cd -<TAB`` to
+conventiently view the directory history.
+
+
+Automatic parentheses and quotes
+--------------------------------
+
+These features were adapted from Nathan Gray's LazyPython. They are
+meant to allow less typing for common situations.
+
+
+Automatic parentheses
+---------------------
+
+Callable objects (i.e. functions, methods, etc) can be invoked like this
+(notice the commas between the arguments)::
+
+ >>> callable_ob arg1, arg2, arg3
+
+and the input will be translated to this::
+
+ -> callable_ob(arg1, arg2, arg3)
+
+You can force automatic parentheses by using '/' as the first character
+of a line. For example::
+
+ >>> /globals # becomes 'globals()'
+
+Note that the '/' MUST be the first character on the line! This won't work::
+
+ >>> print /globals # syntax error
+
+In most cases the automatic algorithm should work, so you should rarely
+need to explicitly invoke /. One notable exception is if you are trying
+to call a function with a list of tuples as arguments (the parenthesis
+will confuse IPython)::
+
+ In [1]: zip (1,2,3),(4,5,6) # won't work
+
+but this will work::
+
+ In [2]: /zip (1,2,3),(4,5,6)
+ ---> zip ((1,2,3),(4,5,6))
+ Out[2]= [(1, 4), (2, 5), (3, 6)]
+
+IPython tells you that it has altered your command line by displaying
+the new command line preceded by ->. e.g.::
+
+ In [18]: callable list
+ ----> callable (list)
+
+
+Automatic quoting
+-----------------
+
+You can force automatic quoting of a function's arguments by using ','
+or ';' as the first character of a line. For example::
+
+ >>> ,my_function /home/me # becomes my_function("/home/me")
+
+If you use ';' instead, the whole argument is quoted as a single string
+(while ',' splits on whitespace)::
+
+ >>> ,my_function a b c # becomes my_function("a","b","c")
+
+ >>> ;my_function a b c # becomes my_function("a b c")
+
+Note that the ',' or ';' MUST be the first character on the line! This
+won't work::
+
+ >>> x = ,my_function /home/me # syntax error
+
+IPython as your default Python environment
+==========================================
+
+Python honors the environment variable PYTHONSTARTUP and will execute at
+startup the file referenced by this variable. If you put at the end of
+this file the following two lines of code::
+
+ import IPython
+ IPython.Shell.IPShell().mainloop(sys_exit=1)
+
+then IPython will be your working environment anytime you start Python.
+The sys_exit=1 is needed to have IPython issue a call to sys.exit() when
+it finishes, otherwise you'll be back at the normal Python '>>>'
+prompt.
+
+This is probably useful to developers who manage multiple Python
+versions and don't want to have correspondingly multiple IPython
+versions. Note that in this mode, there is no way to pass IPython any
+command-line options, as those are trapped first by Python itself.
+
+.. _Embedding:
+
+Embedding IPython
+=================
+
+It is possible to start an IPython instance inside your own Python
+programs. This allows you to evaluate dynamically the state of your
+code, operate with your variables, analyze them, etc. Note however that
+any changes you make to values while in the shell do not propagate back
+to the running code, so it is safe to modify your values because you
+won't break your code in bizarre ways by doing so.
+
+This feature allows you to easily have a fully functional python
+environment for doing object introspection anywhere in your code with a
+simple function call. In some cases a simple print statement is enough,
+but if you need to do more detailed analysis of a code fragment this
+feature can be very valuable.
+
+It can also be useful in scientific computing situations where it is
+common to need to do some automatic, computationally intensive part and
+then stop to look at data, plots, etc.
+Opening an IPython instance will give you full access to your data and
+functions, and you can resume program execution once you are done with
+the interactive part (perhaps to stop again later, as many times as
+needed).
+
+The following code snippet is the bare minimum you need to include in
+your Python programs for this to work (detailed examples follow later)::
+
+ from IPython.Shell import IPShellEmbed
+
+ ipshell = IPShellEmbed()
+
+ ipshell() # this call anywhere in your program will start IPython
+
+You can run embedded instances even in code which is itself being run at
+the IPython interactive prompt with '%run <filename>'. Since it's easy
+to get lost as to where you are (in your top-level IPython or in your
+embedded one), it's a good idea in such cases to set the in/out prompts
+to something different for the embedded instances. The code examples
+below illustrate this.
+
+You can also have multiple IPython instances in your program and open
+them separately, for example with different options for data
+presentation. If you close and open the same instance multiple times,
+its prompt counters simply continue from each execution to the next.
+
+Please look at the docstrings in the Shell.py module for more details on
+the use of this system.
+
+The following sample file illustrating how to use the embedding
+functionality is provided in the examples directory as example-embed.py.
+It should be fairly self-explanatory::
+
+
+ #!/usr/bin/env python
+
+ """An example of how to embed an IPython shell into a running program.
+
+ Please see the documentation in the IPython.Shell module for more details.
+
+ The accompanying file example-embed-short.py has quick code fragments for
+ embedding which you can cut and paste in your code once you understand how
+ things work.
+
+ The code in this file is deliberately extra-verbose, meant for learning."""
+
+ # The basics to get you going:
+
+ # IPython sets the __IPYTHON__ variable so you can know if you have nested
+ # copies running.
+
+ # Try running this code both at the command line and from inside IPython (with
+ # %run example-embed.py)
+ try:
+ __IPYTHON__
+ except NameError:
+ nested = 0
+ args = ['']
+ else:
+ print "Running nested copies of IPython."
+ print "The prompts for the nested copy have been modified"
+ nested = 1
+ # what the embedded instance will see as sys.argv:
+ args = ['-pi1','In <\\#>: ','-pi2',' .\\D.: ',
+ '-po','Out<\\#>: ','-nosep']
+
+ # First import the embeddable shell class
+ from IPython.Shell import IPShellEmbed
+
+ # Now create an instance of the embeddable shell. The first argument is a
+ # string with options exactly as you would type them if you were starting
+ # IPython at the system command line. Any parameters you want to define for
+ # configuration can thus be specified here.
+ ipshell = IPShellEmbed(args,
+ banner = 'Dropping into IPython',
+ exit_msg = 'Leaving Interpreter, back to program.')
+
+ # Make a second instance, you can have as many as you want.
+ if nested:
+ args[1] = 'In2<\\#>'
+ else:
+ args = ['-pi1','In2<\\#>: ','-pi2',' .\\D.: ',
+ '-po','Out<\\#>: ','-nosep']
+ ipshell2 = IPShellEmbed(args,banner = 'Second IPython instance.')
+
+ print '\nHello. This is printed from the main controller program.\n'
+
+ # You can then call ipshell() anywhere you need it (with an optional
+ # message):
+ ipshell('***Called from top level. '
+ 'Hit Ctrl-D to exit interpreter and continue program.\n'
+ 'Note that if you use %kill_embedded, you can fully deactivate\n'
+ 'This embedded instance so it will never turn on again')
+
+ print '\nBack in caller program, moving along...\n'
+
+ #---------------------------------------------------------------------------
+ # More details:
+
+ # IPShellEmbed instances don't print the standard system banner and
+ # messages. The IPython banner (which actually may contain initialization
+ # messages) is available as <instance>.IP.BANNER in case you want it.
+
+ # IPShellEmbed instances print the following information everytime they
+ # start:
+
+ # - A global startup banner.
+
+ # - A call-specific header string, which you can use to indicate where in the
+ # execution flow the shell is starting.
+
+ # They also print an exit message every time they exit.
+
+ # Both the startup banner and the exit message default to None, and can be set
+ # either at the instance constructor or at any other time with the
+ # set_banner() and set_exit_msg() methods.
+
+ # The shell instance can be also put in 'dummy' mode globally or on a per-call
+ # basis. This gives you fine control for debugging without having to change
+ # code all over the place.
+
+ # The code below illustrates all this.
+
+
+ # This is how the global banner and exit_msg can be reset at any point
+ ipshell.set_banner('Entering interpreter - New Banner')
+ ipshell.set_exit_msg('Leaving interpreter - New exit_msg')
+
+ def foo(m):
+ s = 'spam'
+ ipshell('***In foo(). Try @whos, or print s or m:')
+ print 'foo says m = ',m
+
+ def bar(n):
+ s = 'eggs'
+ ipshell('***In bar(). Try @whos, or print s or n:')
+ print 'bar says n = ',n
+
+ # Some calls to the above functions which will trigger IPython:
+ print 'Main program calling foo("eggs")\n'
+ foo('eggs')
+
+ # The shell can be put in 'dummy' mode where calls to it silently return. This
+ # allows you, for example, to globally turn off debugging for a program with a
+ # single call.
+ ipshell.set_dummy_mode(1)
+ print '\nTrying to call IPython which is now "dummy":'
+ ipshell()
+ print 'Nothing happened...'
+ # The global 'dummy' mode can still be overridden for a single call
+ print '\nOverriding dummy mode manually:'
+ ipshell(dummy=0)
+
+ # Reactivate the IPython shell
+ ipshell.set_dummy_mode(0)
+
+ print 'You can even have multiple embedded instances:'
+ ipshell2()
+
+ print '\nMain program calling bar("spam")\n'
+ bar('spam')
+
+ print 'Main program finished. Bye!'
+
+ #********************** End of file <example-embed.py> ***********************
+
+Once you understand how the system functions, you can use the following
+code fragments in your programs which are ready for cut and paste::
+
+
+ """Quick code snippets for embedding IPython into other programs.
+
+ See example-embed.py for full details, this file has the bare minimum code for
+ cut and paste use once you understand how to use the system."""
+
+ #---------------------------------------------------------------------------
+ # This code loads IPython but modifies a few things if it detects it's running
+ # embedded in another IPython session (helps avoid confusion)
+
+ try:
+ __IPYTHON__
+ except NameError:
+ argv = ['']
+ banner = exit_msg = ''
+ else:
+ # Command-line options for IPython (a list like sys.argv)
+ argv = ['-pi1','In <\\#>:','-pi2',' .\\D.:','-po','Out<\\#>:']
+ banner = '*** Nested interpreter ***'
+ exit_msg = '*** Back in main IPython ***'
+
+ # First import the embeddable shell class
+ from IPython.Shell import IPShellEmbed
+ # Now create the IPython shell instance. Put ipshell() anywhere in your code
+ # where you want it to open.
+ ipshell = IPShellEmbed(argv,banner=banner,exit_msg=exit_msg)
+
+ #---------------------------------------------------------------------------
+ # This code will load an embeddable IPython shell always with no changes for
+ # nested embededings.
+
+ from IPython.Shell import IPShellEmbed
+ ipshell = IPShellEmbed()
+ # Now ipshell() will open IPython anywhere in the code.
+
+ #---------------------------------------------------------------------------
+ # This code loads an embeddable shell only if NOT running inside
+ # IPython. Inside IPython, the embeddable shell variable ipshell is just a
+ # dummy function.
+
+ try:
+ __IPYTHON__
+ except NameError:
+ from IPython.Shell import IPShellEmbed
+ ipshell = IPShellEmbed()
+ # Now ipshell() will open IPython anywhere in the code
+ else:
+ # Define a dummy ipshell() so the same code doesn't crash inside an
+ # interactive IPython
+ def ipshell(): pass
+
+ #******************* End of file <example-embed-short.py> ********************
+
+Using the Python debugger (pdb)
+===============================
+
+Running entire programs via pdb
+-------------------------------
+
+pdb, the Python debugger, is a powerful interactive debugger which
+allows you to step through code, set breakpoints, watch variables,
+etc. IPython makes it very easy to start any script under the control
+of pdb, regardless of whether you have wrapped it into a 'main()'
+function or not. For this, simply type '%run -d myscript' at an
+IPython prompt. See the %run command's documentation (via '%run?' or
+in Sec. magic_ for more details, including how to control where pdb
+will stop execution first.
+
+For more information on the use of the pdb debugger, read the included
+pdb.doc file (part of the standard Python distribution). On a stock
+Linux system it is located at /usr/lib/python2.3/pdb.doc, but the
+easiest way to read it is by using the help() function of the pdb module
+as follows (in an IPython prompt):
+
+In [1]: import pdb
+In [2]: pdb.help()
+
+This will load the pdb.doc document in a file viewer for you automatically.
+
+
+Automatic invocation of pdb on exceptions
+-----------------------------------------
+
+IPython, if started with the -pdb option (or if the option is set in
+your rc file) can call the Python pdb debugger every time your code
+triggers an uncaught exception. This feature
+can also be toggled at any time with the %pdb magic command. This can be
+extremely useful in order to find the origin of subtle bugs, because pdb
+opens up at the point in your code which triggered the exception, and
+while your program is at this point 'dead', all the data is still
+available and you can walk up and down the stack frame and understand
+the origin of the problem.
+
+Furthermore, you can use these debugging facilities both with the
+embedded IPython mode and without IPython at all. For an embedded shell
+(see sec. Embedding_), simply call the constructor with
+'-pdb' in the argument string and automatically pdb will be called if an
+uncaught exception is triggered by your code.
+
+For stand-alone use of the feature in your programs which do not use
+IPython at all, put the following lines toward the top of your 'main'
+routine::
+
+ import sys,IPython.ultraTB
+ sys.excepthook = IPython.ultraTB.FormattedTB(mode='Verbose',
+ color_scheme='Linux', call_pdb=1)
+
+The mode keyword can be either 'Verbose' or 'Plain', giving either very
+detailed or normal tracebacks respectively. The color_scheme keyword can
+be one of 'NoColor', 'Linux' (default) or 'LightBG'. These are the same
+options which can be set in IPython with -colors and -xmode.
+
+This will give any of your programs detailed, colored tracebacks with
+automatic invocation of pdb.
+
+
+Extensions for syntax processing
+================================
+
+This isn't for the faint of heart, because the potential for breaking
+things is quite high. But it can be a very powerful and useful feature.
+In a nutshell, you can redefine the way IPython processes the user input
+line to accept new, special extensions to the syntax without needing to
+change any of IPython's own code.
+
+In the IPython/Extensions directory you will find some examples
+supplied, which we will briefly describe now. These can be used 'as is'
+(and both provide very useful functionality), or you can use them as a
+starting point for writing your own extensions.
+
+
+Pasting of code starting with '>>> ' or '... '
+----------------------------------------------
+
+In the python tutorial it is common to find code examples which have
+been taken from real python sessions. The problem with those is that all
+the lines begin with either '>>> ' or '... ', which makes it impossible
+to paste them all at once. One must instead do a line by line manual
+copying, carefully removing the leading extraneous characters.
+
+This extension identifies those starting characters and removes them
+from the input automatically, so that one can paste multi-line examples
+directly into IPython, saving a lot of time. Please look at the file
+InterpreterPasteInput.py in the IPython/Extensions directory for details
+on how this is done.
+
+IPython comes with a special profile enabling this feature, called
+tutorial. Simply start IPython via 'ipython -p tutorial' and the feature
+will be available. In a normal IPython session you can activate the
+feature by importing the corresponding module with:
+In [1]: import IPython.Extensions.InterpreterPasteInput
+
+The following is a 'screenshot' of how things work when this extension
+is on, copying an example from the standard tutorial::
+
+ IPython profile: tutorial
+
+ *** Pasting of code with ">>>" or "..." has been enabled.
+
+ In [1]: >>> def fib2(n): # return Fibonacci series up to n
+ ...: ... """Return a list containing the Fibonacci series up to
+ n."""
+ ...: ... result = []
+ ...: ... a, b = 0, 1
+ ...: ... while b < n:
+ ...: ... result.append(b) # see below
+ ...: ... a, b = b, a+b
+ ...: ... return result
+ ...:
+
+ In [2]: fib2(10)
+ Out[2]: [1, 1, 2, 3, 5, 8]
+
+Note that as currently written, this extension does not recognize
+IPython's prompts for pasting. Those are more complicated, since the
+user can change them very easily, they involve numbers and can vary in
+length. One could however extract all the relevant information from the
+IPython instance and build an appropriate regular expression. This is
+left as an exercise for the reader.
+
+
+Input of physical quantities with units
+---------------------------------------
+
+The module PhysicalQInput allows a simplified form of input for physical
+quantities with units. This file is meant to be used in conjunction with
+the PhysicalQInteractive module (in the same directory) and
+Physics.PhysicalQuantities from Konrad Hinsen's ScientificPython
+(http://dirac.cnrs-orleans.fr/ScientificPython/).
+
+The Physics.PhysicalQuantities module defines PhysicalQuantity objects,
+but these must be declared as instances of a class. For example, to
+define v as a velocity of 3 m/s, normally you would write::
+
+ In [1]: v = PhysicalQuantity(3,'m/s')
+
+Using the PhysicalQ_Input extension this can be input instead as:
+In [1]: v = 3 m/s
+which is much more convenient for interactive use (even though it is
+blatantly invalid Python syntax).
+
+The physics profile supplied with IPython (enabled via 'ipython -p
+physics') uses these extensions, which you can also activate with:
+
+from math import * # math MUST be imported BEFORE PhysicalQInteractive
+from IPython.Extensions.PhysicalQInteractive import *
+import IPython.Extensions.PhysicalQInput
+
+
+Threading support
+=================
+
+WARNING: The threading support is still somewhat experimental, and it
+has only seen reasonable testing under Linux. Threaded code is
+particularly tricky to debug, and it tends to show extremely
+platform-dependent behavior. Since I only have access to Linux machines,
+I will have to rely on user's experiences and assistance for this area
+of IPython to improve under other platforms.
+
+IPython, via the -gthread , -qthread, -q4thread and -wthread options
+(described in Sec. `Threading options`_), can run in
+multithreaded mode to support pyGTK, Qt3, Qt4 and WXPython applications
+respectively. These GUI toolkits need to control the python main loop of
+execution, so under a normal Python interpreter, starting a pyGTK, Qt3,
+Qt4 or WXPython application will immediately freeze the shell.
+
+IPython, with one of these options (you can only use one at a time),
+separates the graphical loop and IPython's code execution run into
+different threads. This allows you to test interactively (with %run, for
+example) your GUI code without blocking.
+
+A nice mini-tutorial on using IPython along with the Qt Designer
+application is available at the SciPy wiki:
+http://www.scipy.org/Cookbook/Matplotlib/Qt_with_IPython_and_Designer.
+
+
+Tk issues
+---------
+
+As indicated in Sec. `Threading options`_, a special -tk option is
+provided to try and allow Tk graphical applications to coexist
+interactively with WX, Qt or GTK ones. Whether this works at all,
+however, is very platform and configuration dependent. Please
+experiment with simple test cases before committing to using this
+combination of Tk and GTK/Qt/WX threading in a production environment.
+
+
+I/O pitfalls
+------------
+
+Be mindful that the Python interpreter switches between threads every
+$N$ bytecodes, where the default value as of Python 2.3 is $N=100.$ This
+value can be read by using the sys.getcheckinterval() function, and it
+can be reset via sys.setcheckinterval(N). This switching of threads can
+cause subtly confusing effects if one of your threads is doing file I/O.
+In text mode, most systems only flush file buffers when they encounter a
+'\n'. An instruction as simple as::
+
+ print >> filehandle, ''hello world''
+
+actually consists of several bytecodes, so it is possible that the
+newline does not reach your file before the next thread switch.
+Similarly, if you are writing to a file in binary mode, the file won't
+be flushed until the buffer fills, and your other thread may see
+apparently truncated files.
+
+For this reason, if you are using IPython's thread support and have (for
+example) a GUI application which will read data generated by files
+written to from the IPython thread, the safest approach is to open all
+of your files in unbuffered mode (the third argument to the file/open
+function is the buffering value)::
+
+ filehandle = open(filename,mode,0)
+
+This is obviously a brute force way of avoiding race conditions with the
+file buffering. If you want to do it cleanly, and you have a resource
+which is being shared by the interactive IPython loop and your GUI
+thread, you should really handle it with thread locking and
+syncrhonization properties. The Python documentation discusses these.
+
+.. _interactive_demos:
+
+Interactive demos with IPython
+==============================
+
+IPython ships with a basic system for running scripts interactively in
+sections, useful when presenting code to audiences. A few tags embedded
+in comments (so that the script remains valid Python code) divide a file
+into separate blocks, and the demo can be run one block at a time, with
+IPython printing (with syntax highlighting) the block before executing
+it, and returning to the interactive prompt after each block. The
+interactive namespace is updated after each block is run with the
+contents of the demo's namespace.
+
+This allows you to show a piece of code, run it and then execute
+interactively commands based on the variables just created. Once you
+want to continue, you simply execute the next block of the demo. The
+following listing shows the markup necessary for dividing a script into
+sections for execution as a demo::
+
+
+ """A simple interactive demo to illustrate the use of IPython's Demo class.
+
+ Any python script can be run as a demo, but that does little more than showing
+ it on-screen, syntax-highlighted in one shot. If you add a little simple
+ markup, you can stop at specified intervals and return to the ipython prompt,
+ resuming execution later.
+ """
+
+ print 'Hello, welcome to an interactive IPython demo.'
+ print 'Executing this block should require confirmation before proceeding,'
+ print 'unless auto_all has been set to true in the demo object'
+
+ # The mark below defines a block boundary, which is a point where IPython will
+ # stop execution and return to the interactive prompt.
+ # Note that in actual interactive execution,
+ # <demo> --- stop ---
+
+ x = 1
+ y = 2
+
+ # <demo> --- stop ---
+
+ # the mark below makes this block as silent
+ # <demo> silent
+
+ print 'This is a silent block, which gets executed but not printed.'
+
+ # <demo> --- stop ---
+ # <demo> auto
+ print 'This is an automatic block.'
+ print 'It is executed without asking for confirmation, but printed.'
+ z = x+y
+
+ print 'z=',x
+
+ # <demo> --- stop ---
+ # This is just another normal block.
+ print 'z is now:', z
+
+ print 'bye!'
+
+In order to run a file as a demo, you must first make a Demo object out
+of it. If the file is named myscript.py, the following code will make a
+demo::
+
+ from IPython.demo import Demo
+
+ mydemo = Demo('myscript.py')
+
+This creates the mydemo object, whose blocks you run one at a time by
+simply calling the object with no arguments. If you have autocall active
+in IPython (the default), all you need to do is type::
+
+ mydemo
+
+and IPython will call it, executing each block. Demo objects can be
+restarted, you can move forward or back skipping blocks, re-execute the
+last block, etc. Simply use the Tab key on a demo object to see its
+methods, and call '?' on them to see their docstrings for more usage
+details. In addition, the demo module itself contains a comprehensive
+docstring, which you can access via::
+
+ from IPython import demo
+
+ demo?
+
+Limitations: It is important to note that these demos are limited to
+fairly simple uses. In particular, you can not put division marks in
+indented code (loops, if statements, function definitions, etc.)
+Supporting something like this would basically require tracking the
+internal execution state of the Python interpreter, so only top-level
+divisions are allowed. If you want to be able to open an IPython
+instance at an arbitrary point in a program, you can use IPython's
+embedding facilities, described in detail in Sec. 9
+
+
+.. _Matplotlib support:
+
+Plotting with matplotlib
+========================
+
+The matplotlib library (http://matplotlib.sourceforge.net
+http://matplotlib.sourceforge.net) provides high quality 2D plotting for
+Python. Matplotlib can produce plots on screen using a variety of GUI
+toolkits, including Tk, GTK and WXPython. It also provides a number of
+commands useful for scientific computing, all with a syntax compatible
+with that of the popular Matlab program.
+
+IPython accepts the special option -pylab (see :ref:`here
+<command_line_options>`). This configures it to support matplotlib, honoring
+the settings in the .matplotlibrc file. IPython will detect the user's choice
+of matplotlib GUI backend, and automatically select the proper threading model
+to prevent blocking. It also sets matplotlib in interactive mode and modifies
+%run slightly, so that any matplotlib-based script can be executed using %run
+and the final show() command does not block the interactive shell.
+
+The -pylab option must be given first in order for IPython to configure its
+threading mode. However, you can still issue other options afterwards. This
+allows you to have a matplotlib-based environment customized with additional
+modules using the standard IPython profile mechanism (see :ref:`here
+<profiles>`): ``ipython -pylab -p myprofile`` will load the profile defined in
+ipythonrc-myprofile after configuring matplotlib.
diff --git a/help/ipythonbook/doc/rel-0.10/html/_static/default.css b/help/ipythonbook/doc/rel-0.10/html/_static/default.css
new file mode 100644
index 0000000..005caa1
--- /dev/null
+++ b/help/ipythonbook/doc/rel-0.10/html/_static/default.css
@@ -0,0 +1,657 @@
+/**
+ * Sphinx Doc Design
+ */
+
+body {
+ font-family: sans-serif;
+ font-size: 100%;
+ background-color: #11303d;
+ color: #000;
+ margin: 0;
+ padding: 0;
+}
+
+/* :::: LAYOUT :::: */
+
+div.document {
+ background-color: #1c4e63;
+}
+
+div.documentwrapper {
+ float: left;
+ width: 100%;
+}
+
+div.bodywrapper {
+ margin: 0 0 0 230px;
+}
+
+div.body {
+ background-color: white;
+ padding: 0 20px 30px 20px;
+}
+
+div.sphinxsidebarwrapper {
+ padding: 10px 5px 0 10px;
+}
+
+div.sphinxsidebar {
+ float: left;
+ width: 230px;
+ margin-left: -100%;
+ font-size: 90%;
+}
+
+div.clearer {
+ clear: both;
+}
+
+div.footer {
+ color: #fff;
+ width: 100%;
+ padding: 9px 0 9px 0;
+ text-align: center;
+ font-size: 75%;
+}
+
+div.footer a {
+ color: #fff;
+ text-decoration: underline;
+}
+
+div.related {
+ background-color: #133f52;
+ color: #fff;
+ width: 100%;
+ line-height: 30px;
+ font-size: 90%;
+}
+
+div.related h3 {
+ display: none;
+}
+
+div.related ul {
+ margin: 0;
+ padding: 0 0 0 10px;
+ list-style: none;
+}
+
+div.related li {
+ display: inline;
+}
+
+div.related li.right {
+ float: right;
+ margin-right: 5px;
+}
+
+div.related a {
+ color: white;
+}
+
+/* ::: TOC :::: */
+div.sphinxsidebar h3 {
+ font-family: 'Trebuchet MS', sans-serif;
+ color: white;
+ font-size: 1.4em;
+ font-weight: normal;
+ margin: 0;
+ padding: 0;
+}
+
+div.sphinxsidebar h3 a {
+ color: white;
+}
+
+div.sphinxsidebar h4 {
+ font-family: 'Trebuchet MS', sans-serif;
+ color: white;
+ font-size: 1.3em;
+ font-weight: normal;
+ margin: 5px 0 0 0;
+ padding: 0;
+}
+
+div.sphinxsidebar p {
+ color: white;
+}
+
+div.sphinxsidebar p.topless {
+ margin: 5px 10px 10px 10px;
+}
+
+div.sphinxsidebar ul {
+ margin: 10px;
+ padding: 0;
+ list-style: none;
+ color: white;
+}
+
+div.sphinxsidebar ul ul,
+div.sphinxsidebar ul.want-points {
+ margin-left: 20px;
+ list-style: square;
+}
+
+div.sphinxsidebar ul ul {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+div.sphinxsidebar a {
+ color: #98dbcc;
+}
+
+div.sphinxsidebar form {
+ margin-top: 10px;
+}
+
+div.sphinxsidebar input {
+ border: 1px solid #98dbcc;
+ font-family: sans-serif;
+ font-size: 1em;
+}
+
+/* :::: MODULE CLOUD :::: */
+div.modulecloud {
+ margin: -5px 10px 5px 10px;
+ padding: 10px;
+ line-height: 160%;
+ border: 1px solid #cbe7e5;
+ background-color: #f2fbfd;
+}
+
+div.modulecloud a {
+ padding: 0 5px 0 5px;
+}
+
+/* :::: SEARCH :::: */
+ul.search {
+ margin: 10px 0 0 20px;
+ padding: 0;
+}
+
+ul.search li {
+ padding: 5px 0 5px 20px;
+ background-image: url(file.png);
+ background-repeat: no-repeat;
+ background-position: 0 7px;
+}
+
+ul.search li a {
+ font-weight: bold;
+}
+
+ul.search li div.context {
+ color: #888;
+ margin: 2px 0 0 30px;
+ text-align: left;
+}
+
+ul.keywordmatches li.goodmatch a {
+ font-weight: bold;
+}
+
+/* :::: COMMON FORM STYLES :::: */
+
+div.actions {
+ padding: 5px 10px 5px 10px;
+ border-top: 1px solid #cbe7e5;
+ border-bottom: 1px solid #cbe7e5;
+ background-color: #e0f6f4;
+}
+
+form dl {
+ color: #333;
+}
+
+form dt {
+ clear: both;
+ float: left;
+ min-width: 110px;
+ margin-right: 10px;
+ padding-top: 2px;
+}
+
+input#homepage {
+ display: none;
+}
+
+div.error {
+ margin: 5px 20px 0 0;
+ padding: 5px;
+ border: 1px solid #d00;
+ font-weight: bold;
+}
+
+/* :::: INDEX PAGE :::: */
+
+table.contentstable {
+ width: 90%;
+}
+
+table.contentstable p.biglink {
+ line-height: 150%;
+}
+
+a.biglink {
+ font-size: 1.3em;
+}
+
+span.linkdescr {
+ font-style: italic;
+ padding-top: 5px;
+ font-size: 90%;
+}
+
+/* :::: INDEX STYLES :::: */
+
+table.indextable td {
+ text-align: left;
+ vertical-align: top;
+}
+
+table.indextable dl, table.indextable dd {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+table.indextable tr.pcap {
+ height: 10px;
+}
+
+table.indextable tr.cap {
+ margin-top: 10px;
+ background-color: #f2f2f2;
+}
+
+img.toggler {
+ margin-right: 3px;
+ margin-top: 3px;
+ cursor: pointer;
+}
+
+form.pfform {
+ margin: 10px 0 20px 0;
+}
+
+/* :::: GLOBAL STYLES :::: */
+
+.docwarning {
+ background-color: #ffe4e4;
+ padding: 10px;
+ margin: 0 -20px 0 -20px;
+ border-bottom: 1px solid #f66;
+}
+
+p.subhead {
+ font-weight: bold;
+ margin-top: 20px;
+}
+
+a {
+ color: #355f7c;
+ text-decoration: none;
+}
+
+a:hover {
+ text-decoration: underline;
+}
+
+div.body h1,
+div.body h2,
+div.body h3,
+div.body h4,
+div.body h5,
+div.body h6 {
+ font-family: 'Trebuchet MS', sans-serif;
+ background-color: #f2f2f2;
+ font-weight: normal;
+ color: #20435c;
+ border-bottom: 1px solid #ccc;
+ margin: 20px -20px 10px -20px;
+ padding: 3px 0 3px 10px;
+}
+
+div.body h1 { margin-top: 0; font-size: 200%; }
+div.body h2 { font-size: 160%; }
+div.body h3 { font-size: 140%; }
+div.body h4 { font-size: 120%; }
+div.body h5 { font-size: 110%; }
+div.body h6 { font-size: 100%; }
+
+a.headerlink {
+ color: #c60f0f;
+ font-size: 0.8em;
+ padding: 0 4px 0 4px;
+ text-decoration: none;
+ visibility: hidden;
+}
+
+h1:hover > a.headerlink,
+h2:hover > a.headerlink,
+h3:hover > a.headerlink,
+h4:hover > a.headerlink,
+h5:hover > a.headerlink,
+h6:hover > a.headerlink,
+dt:hover > a.headerlink {
+ visibility: visible;
+}
+
+a.headerlink:hover {
+ background-color: #c60f0f;
+ color: white;
+}
+
+div.body p, div.body dd, div.body li {
+ text-align: justify;
+ line-height: 130%;
+}
+
+div.body p.caption {
+ text-align: inherit;
+}
+
+div.body td {
+ text-align: left;
+}
+
+ul.fakelist {
+ list-style: none;
+ margin: 10px 0 10px 20px;
+ padding: 0;
+}
+
+.field-list ul {
+ padding-left: 1em;
+}
+
+.first {
+ margin-top: 0 !important;
+}
+
+/* "Footnotes" heading */
+p.rubric {
+ margin-top: 30px;
+ font-weight: bold;
+}
+
+/* Sidebars */
+
+div.sidebar {
+ margin: 0 0 0.5em 1em;
+ border: 1px solid #ddb;
+ padding: 7px 7px 0 7px;
+ background-color: #ffe;
+ width: 40%;
+ float: right;
+}
+
+p.sidebar-title {
+ font-weight: bold;
+}
+
+/* "Topics" */
+
+div.topic {
+ background-color: #eee;
+ border: 1px solid #ccc;
+ padding: 7px 7px 0 7px;
+ margin: 10px 0 10px 0;
+}
+
+p.topic-title {
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 10px;
+}
+
+/* Admonitions */
+
+div.admonition {
+ margin-top: 10px;
+ margin-bottom: 10px;
+ padding: 7px;
+}
+
+div.admonition dt {
+ font-weight: bold;
+}
+
+div.admonition dl {
+ margin-bottom: 0;
+}
+
+div.admonition p.admonition-title + p {
+ display: inline;
+}
+
+div.seealso {
+ background-color: #ffc;
+ border: 1px solid #ff6;
+}
+
+div.warning {
+ background-color: #ffe4e4;
+ border: 1px solid #f66;
+}
+
+div.note {
+ background-color: #eee;
+ border: 1px solid #ccc;
+}
+
+p.admonition-title {
+ margin: 0px 10px 5px 0px;
+ font-weight: bold;
+ display: inline;
+}
+
+p.admonition-title:after {
+ content: ":";
+}
+
+div.body p.centered {
+ text-align: center;
+ margin-top: 25px;
+}
+
+table.docutils {
+ border: 0;
+}
+
+table.docutils td, table.docutils th {
+ padding: 1px 8px 1px 0;
+ border-top: 0;
+ border-left: 0;
+ border-right: 0;
+ border-bottom: 1px solid #aaa;
+}
+
+table.field-list td, table.field-list th {
+ border: 0 !important;
+}
+
+table.footnote td, table.footnote th {
+ border: 0 !important;
+}
+
+.field-list ul {
+ margin: 0;
+ padding-left: 1em;
+}
+
+.field-list p {
+ margin: 0;
+}
+
+dl {
+ margin-bottom: 15px;
+ clear: both;
+}
+
+dd p {
+ margin-top: 0px;
+}
+
+dd ul, dd table {
+ margin-bottom: 10px;
+}
+
+dd {
+ margin-top: 3px;
+ margin-bottom: 10px;
+ margin-left: 30px;
+}
+
+.refcount {
+ color: #060;
+}
+
+dt:target,
+.highlight {
+ background-color: #fbe54e;
+}
+
+dl.glossary dt {
+ font-weight: bold;
+ font-size: 1.1em;
+}
+
+th {
+ text-align: left;
+ padding-right: 5px;
+}
+
+pre {
+ padding: 5px;
+ background-color: #efc;
+ color: #333;
+ border: 1px solid #ac9;
+ border-left: none;
+ border-right: none;
+ overflow: auto;
+}
+
+td.linenos pre {
+ padding: 5px 0px;
+ border: 0;
+ background-color: transparent;
+ color: #aaa;
+}
+
+table.highlighttable {
+ margin-left: 0.5em;
+}
+
+table.highlighttable td {
+ padding: 0 0.5em 0 0.5em;
+}
+
+tt {
+ background-color: #ecf0f3;
+ padding: 0 1px 0 1px;
+ font-size: 0.95em;
+}
+
+tt.descname {
+ background-color: transparent;
+ font-weight: bold;
+ font-size: 1.2em;
+}
+
+tt.descclassname {
+ background-color: transparent;
+}
+
+tt.xref, a tt {
+ background-color: transparent;
+ font-weight: bold;
+}
+
+.footnote:target { background-color: #ffa }
+
+h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
+ background-color: transparent;
+}
+
+.optional {
+ font-size: 1.3em;
+}
+
+.versionmodified {
+ font-style: italic;
+}
+
+form.comment {
+ margin: 0;
+ padding: 10px 30px 10px 30px;
+ background-color: #eee;
+}
+
+form.comment h3 {
+ background-color: #326591;
+ color: white;
+ margin: -10px -30px 10px -30px;
+ padding: 5px;
+ font-size: 1.4em;
+}
+
+form.comment input,
+form.comment textarea {
+ border: 1px solid #ccc;
+ padding: 2px;
+ font-family: sans-serif;
+ font-size: 100%;
+}
+
+form.comment input[type="text"] {
+ width: 240px;
+}
+
+form.comment textarea {
+ width: 100%;
+ height: 200px;
+ margin-bottom: 10px;
+}
+
+.system-message {
+ background-color: #fda;
+ padding: 5px;
+ border: 3px solid red;
+}
+
+img.math {
+ vertical-align: middle;
+}
+
+div.math p {
+ text-align: center;
+}
+
+span.eqno {
+ float: right;
+}
+
+img.logo {
+ border: 0;
+}
+
+/* :::: PRINT :::: */
+@media print {
+ div.document,
+ div.documentwrapper,
+ div.bodywrapper {
+ margin: 0;
+ width : 100%;
+ }
+
+ div.sphinxsidebar,
+ div.related,
+ div.footer,
+ div#comments div.new-comment-box,
+ #top-link {
+ display: none;
+ }
+}
diff --git a/help/ipythonbook/doc/rel-0.10/html/_static/doctools.js b/help/ipythonbook/doc/rel-0.10/html/_static/doctools.js
new file mode 100644
index 0000000..be4bdc8
--- /dev/null
+++ b/help/ipythonbook/doc/rel-0.10/html/_static/doctools.js
@@ -0,0 +1,232 @@
+/// XXX: make it cross browser
+
+/**
+ * make the code below compatible with browsers without
+ * an installed firebug like debugger
+ */
+if (!window.console || !console.firebug) {
+ var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml",
+ "group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"];
+ window.console = {};
+ for (var i = 0; i < names.length; ++i)
+ window.console[names[i]] = function() {}
+}
+
+/**
+ * small helper function to urldecode strings
+ */
+jQuery.urldecode = function(x) {
+ return decodeURIComponent(x).replace(/\+/g, ' ');
+}
+
+/**
+ * small helper function to urlencode strings
+ */
+jQuery.urlencode = encodeURIComponent;
+
+/**
+ * This function returns the parsed url parameters of the
+ * current request. Multiple values per key are supported,
+ * it will always return arrays of strings for the value parts.
+ */
+jQuery.getQueryParameters = function(s) {
+ if (typeof s == 'undefined')
+ s = document.location.search;
+ var parts = s.substr(s.indexOf('?') + 1).split('&');
+ var result = {};
+ for (var i = 0; i < parts.length; i++) {
+ var tmp = parts[i].split('=', 2);
+ var key = jQuery.urldecode(tmp[0]);
+ var value = jQuery.urldecode(tmp[1]);
+ if (key in result)
+ result[key].push(value);
+ else
+ result[key] = [value];
+ }
+ return result;
+}
+
+/**
+ * small function to check if an array contains
+ * a given item.
+ */
+jQuery.contains = function(arr, item) {
+ for (var i = 0; i < arr.length; i++) {
+ if (arr[i] == item)
+ return true;
+ }
+ return false;
+}
+
+/**
+ * highlight a given string on a jquery object by wrapping it in
+ * span elements with the given class name.
+ */
+jQuery.fn.highlightText = function(text, className) {
+ function highlight(node) {
+ if (node.nodeType == 3) {
+ var val = node.nodeValue;
+ var pos = val.toLowerCase().indexOf(text);
+ if (pos >= 0 && !jQuery.className.has(node.parentNode, className)) {
+ var span = document.createElement("span");
+ span.className = className;
+ span.appendChild(document.createTextNode(val.substr(pos, text.length)));
+ node.parentNode.insertBefore(span, node.parentNode.insertBefore(
+ document.createTextNode(val.substr(pos + text.length)),
+ node.nextSibling));
+ node.nodeValue = val.substr(0, pos);
+ }
+ }
+ else if (!jQuery(node).is("button, select, textarea")) {
+ jQuery.each(node.childNodes, function() {
+ highlight(this)
+ });
+ }
+ }
+ return this.each(function() {
+ highlight(this);
+ });
+}
+
+/**
+ * Small JavaScript module for the documentation.
+ */
+var Documentation = {
+
+ init : function() {
+ this.fixFirefoxAnchorBug();
+ this.highlightSearchWords();
+ this.initModIndex();
+ },
+
+ /**
+ * i18n support
+ */
+ TRANSLATIONS : {},
+ PLURAL_EXPR : function(n) { return n == 1 ? 0 : 1; },
+ LOCALE : 'unknown',
+
+ // gettext and ngettext don't access this so that the functions
+ // can savely bound to a different name (_ = Documentation.gettext)
+ gettext : function(string) {
+ var translated = Documentation.TRANSLATIONS[string];
+ if (typeof translated == 'undefined')
+ return string;
+ return (typeof translated == 'string') ? translated : translated[0];
+ },
+
+ ngettext : function(singular, plural, n) {
+ var translated = Documentation.TRANSLATIONS[singular];
+ if (typeof translated == 'undefined')
+ return (n == 1) ? singular : plural;
+ return translated[Documentation.PLURALEXPR(n)];
+ },
+
+ addTranslations : function(catalog) {
+ for (var key in catalog.messages)
+ this.TRANSLATIONS[key] = catalog.messages[key];
+ this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')');
+ this.LOCALE = catalog.locale;
+ },
+
+ /**
+ * add context elements like header anchor links
+ */
+ addContextElements : function() {
+ $('div[@id] > :header:first').each(function() {
+ $('<a class="headerlink">\u00B6</a>').
+ attr('href', '#' + this.id).
+ attr('title', _('Permalink to this headline')).
+ appendTo(this);
+ });
+ $('dt[@id]').each(function() {
+ $('<a class="headerlink">\u00B6</a>').
+ attr('href', '#' + this.id).
+ attr('title', _('Permalink to this definition')).
+ appendTo(this);
+ });
+ },
+
+ /**
+ * workaround a firefox stupidity
+ */
+ fixFirefoxAnchorBug : function() {
+ if (document.location.hash && $.browser.mozilla)
+ window.setTimeout(function() {
+ document.location.href += '';
+ }, 10);
+ },
+
+ /**
+ * highlight the search words provided in the url in the text
+ */
+ highlightSearchWords : function() {
+ var params = $.getQueryParameters();
+ var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : [];
+ if (terms.length) {
+ var body = $('div.body');
+ window.setTimeout(function() {
+ $.each(terms, function() {
+ body.highlightText(this.toLowerCase(), 'highlight');
+ });
+ }, 10);
+ $('<li class="highlight-link"><a href="javascript:Documentation.' +
+ 'hideSearchWords()">' + _('Hide Search Matches') + '</a></li>')
+ .appendTo($('.sidebar .this-page-menu'));
+ }
+ },
+
+ /**
+ * init the modindex toggle buttons
+ */
+ initModIndex : function() {
+ var togglers = $('img.toggler').click(function() {
+ var src = $(this).attr('src');
+ var idnum = $(this).attr('id').substr(7);
+ console.log($('tr.cg-' + idnum).toggle());
+ if (src.substr(-9) == 'minus.png')
+ $(this).attr('src', src.substr(0, src.length-9) + 'plus.png');
+ else
+ $(this).attr('src', src.substr(0, src.length-8) + 'minus.png');
+ }).css('display', '');
+ if (DOCUMENTATION_OPTIONS.COLLAPSE_MODINDEX) {
+ togglers.click();
+ }
+ },
+
+ /**
+ * helper function to hide the search marks again
+ */
+ hideSearchWords : function() {
+ $('.sidebar .this-page-menu li.highlight-link').fadeOut(300);
+ $('span.highlight').removeClass('highlight');
+ },
+
+ /**
+ * make the url absolute
+ */
+ makeURL : function(relativeURL) {
+ return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL;
+ },
+
+ /**
+ * get the current relative url
+ */
+ getCurrentURL : function() {
+ var path = document.location.pathname;
+ var parts = path.split(/\//);
+ $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() {
+ if (this == '..')
+ parts.pop();
+ });
+ var url = parts.join('/');
+ return path.substring(url.lastIndexOf('/') + 1, path.length - 1);
+ }
+};
+
+// quick alias for translations
+_ = Documentation.gettext;
+
+$(document).ready(function() {
+ Documentation.init();
+});
diff --git a/help/ipythonbook/doc/rel-0.10/html/_static/jquery.js b/help/ipythonbook/doc/rel-0.10/html/_static/jquery.js
new file mode 100644
index 0000000..82b98e1
--- /dev/null
+++ b/help/ipythonbook/doc/rel-0.10/html/_static/jquery.js
@@ -0,0 +1,32 @@
+/*
+ * jQuery 1.2.6 - New Wave Javascript
+ *
+ * Copyright (c) 2008 John Resig (jquery.com)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * $Date: 2008-05-24 14:22:17 -0400 (Sat, 24 May 2008) $
+ * $Rev: 5685 $
+ */
+(function(){var _jQuery=window.jQuery,_$=window.$;var jQuery=window.jQuery=window.$=function(selector,context){return new jQuery.fn.init(selector,context);};var quickExpr=/^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/,isSimple=/^.[^:#\[\.]*$/,undefined;jQuery.fn=jQuery.prototype={init:function(selector,context){selector=selector||document;if(selector.nodeType){this[0]=selector;this.length=1;return this;}if(typeof selector=="string"){var match=quickExpr.exec(selector);if(match&&(match[1]||!context)){if(match[1])selector=jQuery.clean([match[1]],context);else{var elem=document.getElementById(match[3]);if(elem){if(elem.id!=match[3])return jQuery().find(selector);return jQuery(elem);}selector=[];}}else
+return jQuery(context).find(selector);}else if(jQuery.isFunction(selector))return jQuery(document)[jQuery.fn.ready?"ready":"load"](selector);return this.setArray(jQuery.makeArray(selector));},jquery:"1.2.6",size:function(){return this.length;},length:0,get:function(num){return num==undefined?jQuery.makeArray(this):this[num];},pushStack:function(elems){var ret=jQuery(elems);ret.prevObject=this;return ret;},setArray:function(elems){this.length=0;Array.prototype.push.apply(this,elems);return this;},each:function(callback,args){return jQuery.each(this,callback,args);},index:function(elem){var ret=-1;return jQuery.inArray(elem&&elem.jquery?elem[0]:elem,this);},attr:function(name,value,type){var options=name;if(name.constructor==String)if(value===undefined)return this[0]&&jQuery[type||"attr"](this[0],name);else{options={};options[name]=value;}return this.each(function(i){for(name in options)jQuery.attr(type?this.style:this,name,jQuery.prop(this,options[name],type,i,name));});},css:function(key,value){if((key=='width'||key=='height')&&parseFloat(value)<0)value=undefined;return this.attr(key,value,"curCSS");},text:function(text){if(typeof text!="object"&&text!=null)return this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(text));var ret="";jQuery.each(text||this,function(){jQuery.each(this.childNodes,function(){if(this.nodeType!=8)ret+=this.nodeType!=1?this.nodeValue:jQuery.fn.text([this]);});});return ret;},wrapAll:function(html){if(this[0])jQuery(html,this[0].ownerDocument).clone().insertBefore(this[0]).map(function(){var elem=this;while(elem.firstChild)elem=elem.firstChild;return elem;}).append(this);return this;},wrapInner:function(html){return this.each(function(){jQuery(this).contents().wrapAll(html);});},wrap:function(html){return this.each(function(){jQuery(this).wrapAll(html);});},append:function(){return this.domManip(arguments,true,false,function(elem){if(this.nodeType==1)this.appendChild(elem);});},prepend:function(){return this.domManip(arguments,true,true,function(elem){if(this.nodeType==1)this.insertBefore(elem,this.firstChild);});},before:function(){return this.domManip(arguments,false,false,function(elem){this.parentNode.insertBefore(elem,this);});},after:function(){return this.domManip(arguments,false,true,function(elem){this.parentNode.insertBefore(elem,this.nextSibling);});},end:function(){return this.prevObject||jQuery([]);},find:function(selector){var elems=jQuery.map(this,function(elem){return jQuery.find(selector,elem);});return this.pushStack(/[^+>] [^+>]/.test(selector)||selector.indexOf("..")>-1?jQuery.unique(elems):elems);},clone:function(events){var ret=this.map(function(){if(jQuery.browser.msie&&!jQuery.isXMLDoc(this)){var clone=this.cloneNode(true),container=document.createElement("div");container.appendChild(clone);return jQuery.clean([container.innerHTML])[0];}else
+return this.cloneNode(true);});var clone=ret.find("*").andSelf().each(function(){if(this[expando]!=undefined)this[expando]=null;});if(events===true)this.find("*").andSelf().each(function(i){if(this.nodeType==3)return;var events=jQuery.data(this,"events");for(var type in events)for(var handler in events[type])jQuery.event.add(clone[i],type,events[type][handler],events[type][handler].data);});return ret;},filter:function(selector){return this.pushStack(jQuery.isFunction(selector)&&jQuery.grep(this,function(elem,i){return selector.call(elem,i);})||jQuery.multiFilter(selector,this));},not:function(selector){if(selector.constructor==String)if(isSimple.test(selector))return this.pushStack(jQuery.multiFilter(selector,this,true));else
+selector=jQuery.multiFilter(selector,this);var isArrayLike=selector.length&&selector[selector.length-1]!==undefined&&!selector.nodeType;return this.filter(function(){return isArrayLike?jQuery.inArray(this,selector)<0:this!=selector;});},add:function(selector){return this.pushStack(jQuery.unique(jQuery.merge(this.get(),typeof selector=='string'?jQuery(selector):jQuery.makeArray(selector))));},is:function(selector){return!!selector&&jQuery.multiFilter(selector,this).length>0;},hasClass:function(selector){return this.is("."+selector);},val:function(value){if(value==undefined){if(this.length){var elem=this[0];if(jQuery.nodeName(elem,"select")){var index=elem.selectedIndex,values=[],options=elem.options,one=elem.type=="select-one";if(index<0)return null;for(var i=one?index:0,max=one?index+1:options.length;i<max;i++){var option=options[i];if(option.selected){value=jQuery.browser.msie&&!option.attributes.value.specified?option.text:option.value;if(one)return value;values.push(value);}}return values;}else
+return(this[0].value||"").replace(/\r/g,"");}return undefined;}if(value.constructor==Number)value+='';return this.each(function(){if(this.nodeType!=1)return;if(value.constructor==Array&&/radio|checkbox/.test(this.type))this.checked=(jQuery.inArray(this.value,value)>=0||jQuery.inArray(this.name,value)>=0);else if(jQuery.nodeName(this,"select")){var values=jQuery.makeArray(value);jQuery("option",this).each(function(){this.selected=(jQuery.inArray(this.value,values)>=0||jQuery.inArray(this.text,values)>=0);});if(!values.length)this.selectedIndex=-1;}else
+this.value=value;});},html:function(value){return value==undefined?(this[0]?this[0].innerHTML:null):this.empty().append(value);},replaceWith:function(value){return this.after(value).remove();},eq:function(i){return this.slice(i,i+1);},slice:function(){return this.pushStack(Array.prototype.slice.apply(this,arguments));},map:function(callback){return this.pushStack(jQuery.map(this,function(elem,i){return callback.call(elem,i,elem);}));},andSelf:function(){return this.add(this.prevObject);},data:function(key,value){var parts=key.split(".");parts[1]=parts[1]?"."+parts[1]:"";if(value===undefined){var data=this.triggerHandler("getData"+parts[1]+"!",[parts[0]]);if(data===undefined&&this.length)data=jQuery.data(this[0],key);return data===undefined&&parts[1]?this.data(parts[0]):data;}else
+return this.trigger("setData"+parts[1]+"!",[parts[0],value]).each(function(){jQuery.data(this,key,value);});},removeData:function(key){return this.each(function(){jQuery.removeData(this,key);});},domManip:function(args,table,reverse,callback){var clone=this.length>1,elems;return this.each(function(){if(!elems){elems=jQuery.clean(args,this.ownerDocument);if(reverse)elems.reverse();}var obj=this;if(table&&jQuery.nodeName(this,"table")&&jQuery.nodeName(elems[0],"tr"))obj=this.getElementsByTagName("tbody")[0]||this.appendChild(this.ownerDocument.createElement("tbody"));var scripts=jQuery([]);jQuery.each(elems,function(){var elem=clone?jQuery(this).clone(true)[0]:this;if(jQuery.nodeName(elem,"script"))scripts=scripts.add(elem);else{if(elem.nodeType==1)scripts=scripts.add(jQuery("script",elem).remove());callback.call(obj,elem);}});scripts.each(evalScript);});}};jQuery.fn.init.prototype=jQuery.fn;function evalScript(i,elem){if(elem.src)jQuery.ajax({url:elem.src,async:false,dataType:"script"});else
+jQuery.globalEval(elem.text||elem.textContent||elem.innerHTML||"");if(elem.parentNode)elem.parentNode.removeChild(elem);}function now(){return+new Date;}jQuery.extend=jQuery.fn.extend=function(){var target=arguments[0]||{},i=1,length=arguments.length,deep=false,options;if(target.constructor==Boolean){deep=target;target=arguments[1]||{};i=2;}if(typeof target!="object"&&typeof target!="function")target={};if(length==i){target=this;--i;}for(;i<length;i++)if((options=arguments[i])!=null)for(var name in options){var src=target[name],copy=options[name];if(target===copy)continue;if(deep&&copy&&typeof copy=="object"&&!copy.nodeType)target[name]=jQuery.extend(deep,src||(copy.length!=null?[]:{}),copy);else if(copy!==undefined)target[name]=copy;}return target;};var expando="jQuery"+now(),uuid=0,windowData={},exclude=/z-?index|font-?weight|opacity|zoom|line-?height/i,defaultView=document.defaultView||{};jQuery.extend({noConflict:function(deep){window.$=_$;if(deep)window.jQuery=_jQuery;return jQuery;},isFunction:function(fn){return!!fn&&typeof fn!="string"&&!fn.nodeName&&fn.constructor!=Array&&/^[\s[]?function/.test(fn+"");},isXMLDoc:function(elem){return elem.documentElement&&!elem.body||elem.tagName&&elem.ownerDocument&&!elem.ownerDocument.body;},globalEval:function(data){data=jQuery.trim(data);if(data){var head=document.getElementsByTagName("head")[0]||document.documentElement,script=document.createElement("script");script.type="text/javascript";if(jQuery.browser.msie)script.text=data;else
+script.appendChild(document.createTextNode(data));head.insertBefore(script,head.firstChild);head.removeChild(script);}},nodeName:function(elem,name){return elem.nodeName&&elem.nodeName.toUpperCase()==name.toUpperCase();},cache:{},data:function(elem,name,data){elem=elem==window?windowData:elem;var id=elem[expando];if(!id)id=elem[expando]=++uuid;if(name&&!jQuery.cache[id])jQuery.cache[id]={};if(data!==undefined)jQuery.cache[id][name]=data;return name?jQuery.cache[id][name]:id;},removeData:function(elem,name){elem=elem==window?windowData:elem;var id=elem[expando];if(name){if(jQuery.cache[id]){delete jQuery.cache[id][name];name="";for(name in jQuery.cache[id])break;if(!name)jQuery.removeData(elem);}}else{try{delete elem[expando];}catch(e){if(elem.removeAttribute)elem.removeAttribute(expando);}delete jQuery.cache[id];}},each:function(object,callback,args){var name,i=0,length=object.length;if(args){if(length==undefined){for(name in object)if(callback.apply(object[name],args)===false)break;}else
+for(;i<length;)if(callback.apply(object[i++],args)===false)break;}else{if(length==undefined){for(name in object)if(callback.call(object[name],name,object[name])===false)break;}else
+for(var value=object[0];i<length&&callback.call(value,i,value)!==false;value=object[++i]){}}return object;},prop:function(elem,value,type,i,name){if(jQuery.isFunction(value))value=value.call(elem,i);return value&&value.constructor==Number&&type=="curCSS"&&!exclude.test(name)?value+"px":value;},className:{add:function(elem,classNames){jQuery.each((classNames||"").split(/\s+/),function(i,className){if(elem.nodeType==1&&!jQuery.className.has(elem.className,className))elem.className+=(elem.className?" ":"")+className;});},remove:function(elem,classNames){if(elem.nodeType==1)elem.className=classNames!=undefined?jQuery.grep(elem.className.split(/\s+/),function(className){return!jQuery.className.has(classNames,className);}).join(" "):"";},has:function(elem,className){return jQuery.inArray(className,(elem.className||elem).toString().split(/\s+/))>-1;}},swap:function(elem,options,callback){var old={};for(var name in options){old[name]=elem.style[name];elem.style[name]=options[name];}callback.call(elem);for(var name in options)elem.style[name]=old[name];},css:function(elem,name,force){if(name=="width"||name=="height"){var val,props={position:"absolute",visibility:"hidden",display:"block"},which=name=="width"?["Left","Right"]:["Top","Bottom"];function getWH(){val=name=="width"?elem.offsetWidth:elem.offsetHeight;var padding=0,border=0;jQuery.each(which,function(){padding+=parseFloat(jQuery.curCSS(elem,"padding"+this,true))||0;border+=parseFloat(jQuery.curCSS(elem,"border"+this+"Width",true))||0;});val-=Math.round(padding+border);}if(jQuery(elem).is(":visible"))getWH();else
+jQuery.swap(elem,props,getWH);return Math.max(0,val);}return jQuery.curCSS(elem,name,force);},curCSS:function(elem,name,force){var ret,style=elem.style;function color(elem){if(!jQuery.browser.safari)return false;var ret=defaultView.getComputedStyle(elem,null);return!ret||ret.getPropertyValue("color")=="";}if(name=="opacity"&&jQuery.browser.msie){ret=jQuery.attr(style,"opacity");return ret==""?"1":ret;}if(jQuery.browser.opera&&name=="display"){var save=style.outline;style.outline="0 solid black";style.outline=save;}if(name.match(/float/i))name=styleFloat;if(!force&&style&&style[name])ret=style[name];else if(defaultView.getComputedStyle){if(name.match(/float/i))name="float";name=name.replace(/([A-Z])/g,"-$1").toLowerCase();var computedStyle=defaultView.getComputedStyle(elem,null);if(computedStyle&&!color(elem))ret=computedStyle.getPropertyValue(name);else{var swap=[],stack=[],a=elem,i=0;for(;a&&color(a);a=a.parentNode)stack.unshift(a);for(;i<stack.length;i++)if(color(stack[i])){swap[i]=stack[i].style.display;stack[i].style.display="block";}ret=name=="display"&&swap[stack.length-1]!=null?"none":(computedStyle&&computedStyle.getPropertyValue(name))||"";for(i=0;i<swap.length;i++)if(swap[i]!=null)stack[i].style.display=swap[i];}if(name=="opacity"&&ret=="")ret="1";}else if(elem.currentStyle){var camelCase=name.replace(/\-(\w)/g,function(all,letter){return letter.toUpperCase();});ret=elem.currentStyle[name]||elem.currentStyle[camelCase];if(!/^\d+(px)?$/i.test(ret)&&/^\d/.test(ret)){var left=style.left,rsLeft=elem.runtimeStyle.left;elem.runtimeStyle.left=elem.currentStyle.left;style.left=ret||0;ret=style.pixelLeft+"px";style.left=left;elem.runtimeStyle.left=rsLeft;}}return ret;},clean:function(elems,context){var ret=[];context=context||document;if(typeof context.createElement=='undefined')context=context.ownerDocument||context[0]&&context[0].ownerDocument||document;jQuery.each(elems,function(i,elem){if(!elem)return;if(elem.constructor==Number)elem+='';if(typeof elem=="string"){elem=elem.replace(/(<(\w+)[^>]*?)\/>/g,function(all,front,tag){return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?all:front+"></"+tag+">";});var tags=jQuery.trim(elem).toLowerCase(),div=context.createElement("div");var wrap=!tags.indexOf("<opt")&&[1,"<select multiple='multiple'>","</select>"]||!tags.indexOf("<leg")&&[1,"<fieldset>","</fieldset>"]||tags.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1,"<table>","</table>"]||!tags.indexOf("<tr")&&[2,"<table><tbody>","</tbody></table>"]||(!tags.indexOf("<td")||!tags.indexOf("<th"))&&[3,"<table><tbody><tr>","</tr></tbody></table>"]||!tags.indexOf("<col")&&[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"]||jQuery.browser.msie&&[1,"div<div>","</div>"]||[0,"",""];div.innerHTML=wrap[1]+elem+wrap[2];while(wrap[0]--)div=div.lastChild;if(jQuery.browser.msie){var tbody=!tags.indexOf("<table")&&tags.indexOf("<tbody")<0?div.firstChild&&div.firstChild.childNodes:wrap[1]=="<table>"&&tags.indexOf("<tbody")<0?div.childNodes:[];for(var j=tbody.length-1;j>=0;--j)if(jQuery.nodeName(tbody[j],"tbody")&&!tbody[j].childNodes.length)tbody[j].parentNode.removeChild(tbody[j]);if(/^\s/.test(elem))div.insertBefore(context.createTextNode(elem.match(/^\s*/)[0]),div.firstChild);}elem=jQuery.makeArray(div.childNodes);}if(elem.length===0&&(!jQuery.nodeName(elem,"form")&&!jQuery.nodeName(elem,"select")))return;if(elem[0]==undefined||jQuery.nodeName(elem,"form")||elem.options)ret.push(elem);else
+ret=jQuery.merge(ret,elem);});return ret;},attr:function(elem,name,value){if(!elem||elem.nodeType==3||elem.nodeType==8)return undefined;var notxml=!jQuery.isXMLDoc(elem),set=value!==undefined,msie=jQuery.browser.msie;name=notxml&&jQuery.props[name]||name;if(elem.tagName){var special=/href|src|style/.test(name);if(name=="selected"&&jQuery.browser.safari)elem.parentNode.selectedIndex;if(name in elem&&notxml&&!special){if(set){if(name=="type"&&jQuery.nodeName(elem,"input")&&elem.parentNode)throw"type property can't be changed";elem[name]=value;}if(jQuery.nodeName(elem,"form")&&elem.getAttributeNode(name))return elem.getAttributeNode(name).nodeValue;return elem[name];}if(msie&&notxml&&name=="style")return jQuery.attr(elem.style,"cssText",value);if(set)elem.setAttribute(name,""+value);var attr=msie&&notxml&&special?elem.getAttribute(name,2):elem.getAttribute(name);return attr===null?undefined:attr;}if(msie&&name=="opacity"){if(set){elem.zoom=1;elem.filter=(elem.filter||"").replace(/alpha\([^)]*\)/,"")+(parseInt(value)+''=="NaN"?"":"alpha(opacity="+value*100+")");}return elem.filter&&elem.filter.indexOf("opacity=")>=0?(parseFloat(elem.filter.match(/opacity=([^)]*)/)[1])/100)+'':"";}name=name.replace(/-([a-z])/ig,function(all,letter){return letter.toUpperCase();});if(set)elem[name]=value;return elem[name];},trim:function(text){return(text||"").replace(/^\s+|\s+$/g,"");},makeArray:function(array){var ret=[];if(array!=null){var i=array.length;if(i==null||array.split||array.setInterval||array.call)ret[0]=array;else
+while(i)ret[--i]=array[i];}return ret;},inArray:function(elem,array){for(var i=0,length=array.length;i<length;i++)if(array[i]===elem)return i;return-1;},merge:function(first,second){var i=0,elem,pos=first.length;if(jQuery.browser.msie){while(elem=second[i++])if(elem.nodeType!=8)first[pos++]=elem;}else
+while(elem=second[i++])first[pos++]=elem;return first;},unique:function(array){var ret=[],done={};try{for(var i=0,length=array.length;i<length;i++){var id=jQuery.data(array[i]);if(!done[id]){done[id]=true;ret.push(array[i]);}}}catch(e){ret=array;}return ret;},grep:function(elems,callback,inv){var ret=[];for(var i=0,length=elems.length;i<length;i++)if(!inv!=!callback(elems[i],i))ret.push(elems[i]);return ret;},map:function(elems,callback){var ret=[];for(var i=0,length=elems.length;i<length;i++){var value=callback(elems[i],i);if(value!=null)ret[ret.length]=value;}return ret.concat.apply([],ret);}});var userAgent=navigator.userAgent.toLowerCase();jQuery.browser={version:(userAgent.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/)||[])[1],safari:/webkit/.test(userAgent),opera:/opera/.test(userAgent),msie:/msie/.test(userAgent)&&!/opera/.test(userAgent),mozilla:/mozilla/.test(userAgent)&&!/(compatible|webkit)/.test(userAgent)};var styleFloat=jQuery.browser.msie?"styleFloat":"cssFloat";jQuery.extend({boxModel:!jQuery.browser.msie||document.compatMode=="CSS1Compat",props:{"for":"htmlFor","class":"className","float":styleFloat,cssFloat:styleFloat,styleFloat:styleFloat,readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing"}});jQuery.each({parent:function(elem){return elem.parentNode;},parents:function(elem){return jQuery.dir(elem,"parentNode");},next:function(elem){return jQuery.nth(elem,2,"nextSibling");},prev:function(elem){return jQuery.nth(elem,2,"previousSibling");},nextAll:function(elem){return jQuery.dir(elem,"nextSibling");},prevAll:function(elem){return jQuery.dir(elem,"previousSibling");},siblings:function(elem){return jQuery.sibling(elem.parentNode.firstChild,elem);},children:function(elem){return jQuery.sibling(elem.firstChild);},contents:function(elem){return jQuery.nodeName(elem,"iframe")?elem.contentDocument||elem.contentWindow.document:jQuery.makeArray(elem.childNodes);}},function(name,fn){jQuery.fn[name]=function(selector){var ret=jQuery.map(this,fn);if(selector&&typeof selector=="string")ret=jQuery.multiFilter(selector,ret);return this.pushStack(jQuery.unique(ret));};});jQuery.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(name,original){jQuery.fn[name]=function(){var args=arguments;return this.each(function(){for(var i=0,length=args.length;i<length;i++)jQuery(args[i])[original](this);});};});jQuery.each({removeAttr:function(name){jQuery.attr(this,name,"");if(this.nodeType==1)this.removeAttribute(name);},addClass:function(classNames){jQuery.className.add(this,classNames);},removeClass:function(classNames){jQuery.className.remove(this,classNames);},toggleClass:function(classNames){jQuery.className[jQuery.className.has(this,classNames)?"remove":"add"](this,classNames);},remove:function(selector){if(!selector||jQuery.filter(selector,[this]).r.length){jQuery("*",this).add(this).each(function(){jQuery.event.remove(this);jQuery.removeData(this);});if(this.parentNode)this.parentNode.removeChild(this);}},empty:function(){jQuery(">*",this).remove();while(this.firstChild)this.removeChild(this.firstChild);}},function(name,fn){jQuery.fn[name]=function(){return this.each(fn,arguments);};});jQuery.each(["Height","Width"],function(i,name){var type=name.toLowerCase();jQuery.fn[type]=function(size){return this[0]==window?jQuery.browser.opera&&document.body["client"+name]||jQuery.browser.safari&&window["inner"+name]||document.compatMode=="CSS1Compat"&&document.documentElement["client"+name]||document.body["client"+name]:this[0]==document?Math.max(Math.max(document.body["scroll"+name],document.documentElement["scroll"+name]),Math.max(document.body["offset"+name],document.documentElement["offset"+name])):size==undefined?(this.length?jQuery.css(this[0],type):null):this.css(type,size.constructor==String?size:size+"px");};});function num(elem,prop){return elem[0]&&parseInt(jQuery.curCSS(elem[0],prop,true),10)||0;}var chars=jQuery.browser.safari&&parseInt(jQuery.browser.version)<417?"(?:[\\w*_-]|\\\\.)":"(?:[\\w\u0128-\uFFFF*_-]|\\\\.)",quickChild=new RegExp("^>\\s*("+chars+"+)"),quickID=new RegExp("^("+chars+"+)(#)("+chars+"+)"),quickClass=new RegExp("^([#.]?)("+chars+"*)");jQuery.extend({expr:{"":function(a,i,m){return m[2]=="*"||jQuery.nodeName(a,m[2]);},"#":function(a,i,m){return a.getAttribute("id")==m[2];},":":{lt:function(a,i,m){return i<m[3]-0;},gt:function(a,i,m){return i>m[3]-0;},nth:function(a,i,m){return m[3]-0==i;},eq:function(a,i,m){return m[3]-0==i;},first:function(a,i){return i==0;},last:function(a,i,m,r){return i==r.length-1;},even:function(a,i){return i%2==0;},odd:function(a,i){return i%2;},"first-child":function(a){return a.parentNode.getElementsByTagName("*")[0]==a;},"last-child":function(a){return jQuery.nth(a.parentNode.lastChild,1,"previousSibling")==a;},"only-child":function(a){return!jQuery.nth(a.parentNode.lastChild,2,"previousSibling");},parent:function(a){return a.firstChild;},empty:function(a){return!a.firstChild;},contains:function(a,i,m){return(a.textContent||a.innerText||jQuery(a).text()||"").indexOf(m[3])>=0;},visible:function(a){return"hidden"!=a.type&&jQuery.css(a,"display")!="none"&&jQuery.css(a,"visibility")!="hidden";},hidden:function(a){return"hidden"==a.type||jQuery.css(a,"display")=="none"||jQuery.css(a,"visibility")=="hidden";},enabled:function(a){return!a.disabled;},disabled:function(a){return a.disabled;},checked:function(a){return a.checked;},selected:function(a){return a.selected||jQuery.attr(a,"selected");},text:function(a){return"text"==a.type;},radio:function(a){return"radio"==a.type;},checkbox:function(a){return"checkbox"==a.type;},file:function(a){return"file"==a.type;},password:function(a){return"password"==a.type;},submit:function(a){return"submit"==a.type;},image:function(a){return"image"==a.type;},reset:function(a){return"reset"==a.type;},button:function(a){return"button"==a.type||jQuery.nodeName(a,"button");},input:function(a){return/input|select|textarea|button/i.test(a.nodeName);},has:function(a,i,m){return jQuery.find(m[3],a).length;},header:function(a){return/h\d/i.test(a.nodeName);},animated:function(a){return jQuery.grep(jQuery.timers,function(fn){return a==fn.elem;}).length;}}},parse:[/^(\[) *@?([\w-]+) *([!*$^~=]*) *('?"?)(.*?)\4 *\]/,/^(:)([\w-]+)\("?'?(.*?(\(.*?\))?[^(]*?)"?'?\)/,new RegExp("^([:.#]*)("+chars+"+)")],multiFilter:function(expr,elems,not){var old,cur=[];while(expr&&expr!=old){old=expr;var f=jQuery.filter(expr,elems,not);expr=f.t.replace(/^\s*,\s*/,"");cur=not?elems=f.r:jQuery.merge(cur,f.r);}return cur;},find:function(t,context){if(typeof t!="string")return[t];if(context&&context.nodeType!=1&&context.nodeType!=9)return[];context=context||document;var ret=[context],done=[],last,nodeName;while(t&&last!=t){var r=[];last=t;t=jQuery.trim(t);var foundToken=false,re=quickChild,m=re.exec(t);if(m){nodeName=m[1].toUpperCase();for(var i=0;ret[i];i++)for(var c=ret[i].firstChild;c;c=c.nextSibling)if(c.nodeType==1&&(nodeName=="*"||c.nodeName.toUpperCase()==nodeName))r.push(c);ret=r;t=t.replace(re,"");if(t.indexOf(" ")==0)continue;foundToken=true;}else{re=/^([>+~])\s*(\w*)/i;if((m=re.exec(t))!=null){r=[];var merge={};nodeName=m[2].toUpperCase();m=m[1];for(var j=0,rl=ret.length;j<rl;j++){var n=m=="~"||m=="+"?ret[j].nextSibling:ret[j].firstChild;for(;n;n=n.nextSibling)if(n.nodeType==1){var id=jQuery.data(n);if(m=="~"&&merge[id])break;if(!nodeName||n.nodeName.toUpperCase()==nodeName){if(m=="~")merge[id]=true;r.push(n);}if(m=="+")break;}}ret=r;t=jQuery.trim(t.replace(re,""));foundToken=true;}}if(t&&!foundToken){if(!t.indexOf(",")){if(context==ret[0])ret.shift();done=jQuery.merge(done,ret);r=ret=[context];t=" "+t.substr(1,t.length);}else{var re2=quickID;var m=re2.exec(t);if(m){m=[0,m[2],m[3],m[1]];}else{re2=quickClass;m=re2.exec(t);}m[2]=m[2].replace(/\\/g,"");var elem=ret[ret.length-1];if(m[1]=="#"&&elem&&elem.getElementById&&!jQuery.isXMLDoc(elem)){var oid=elem.getElementById(m[2]);if((jQuery.browser.msie||jQuery.browser.opera)&&oid&&typeof oid.id=="string"&&oid.id!=m[2])oid=jQuery('[@id="'+m[2]+'"]',elem)[0];ret=r=oid&&(!m[3]||jQuery.nodeName(oid,m[3]))?[oid]:[];}else{for(var i=0;ret[i];i++){var tag=m[1]=="#"&&m[3]?m[3]:m[1]!=""||m[0]==""?"*":m[2];if(tag=="*"&&ret[i].nodeName.toLowerCase()=="object")tag="param";r=jQuery.merge(r,ret[i].getElementsByTagName(tag));}if(m[1]==".")r=jQuery.classFilter(r,m[2]);if(m[1]=="#"){var tmp=[];for(var i=0;r[i];i++)if(r[i].getAttribute("id")==m[2]){tmp=[r[i]];break;}r=tmp;}ret=r;}t=t.replace(re2,"");}}if(t){var val=jQuery.filter(t,r);ret=r=val.r;t=jQuery.trim(val.t);}}if(t)ret=[];if(ret&&context==ret[0])ret.shift();done=jQuery.merge(done,ret);return done;},classFilter:function(r,m,not){m=" "+m+" ";var tmp=[];for(var i=0;r[i];i++){var pass=(" "+r[i].className+" ").indexOf(m)>=0;if(!not&&pass||not&&!pass)tmp.push(r[i]);}return tmp;},filter:function(t,r,not){var last;while(t&&t!=last){last=t;var p=jQuery.parse,m;for(var i=0;p[i];i++){m=p[i].exec(t);if(m){t=t.substring(m[0].length);m[2]=m[2].replace(/\\/g,"");break;}}if(!m)break;if(m[1]==":"&&m[2]=="not")r=isSimple.test(m[3])?jQuery.filter(m[3],r,true).r:jQuery(r).not(m[3]);else if(m[1]==".")r=jQuery.classFilter(r,m[2],not);else if(m[1]=="["){var tmp=[],type=m[3];for(var i=0,rl=r.length;i<rl;i++){var a=r[i],z=a[jQuery.props[m[2]]||m[2]];if(z==null||/href|src|selected/.test(m[2]))z=jQuery.attr(a,m[2])||'';if((type==""&&!!z||type=="="&&z==m[5]||type=="!="&&z!=m[5]||type=="^="&&z&&!z.indexOf(m[5])||type=="$="&&z.substr(z.length-m[5].length)==m[5]||(type=="*="||type=="~=")&&z.indexOf(m[5])>=0)^not)tmp.push(a);}r=tmp;}else if(m[1]==":"&&m[2]=="nth-child"){var merge={},tmp=[],test=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(m[3]=="even"&&"2n"||m[3]=="odd"&&"2n+1"||!/\D/.test(m[3])&&"0n+"+m[3]||m[3]),first=(test[1]+(test[2]||1))-0,last=test[3]-0;for(var i=0,rl=r.length;i<rl;i++){var node=r[i],parentNode=node.parentNode,id=jQuery.data(parentNode);if(!merge[id]){var c=1;for(var n=parentNode.firstChild;n;n=n.nextSibling)if(n.nodeType==1)n.nodeIndex=c++;merge[id]=true;}var add=false;if(first==0){if(node.nodeIndex==last)add=true;}else if((node.nodeIndex-last)%first==0&&(node.nodeIndex-last)/first>=0)add=true;if(add^not)tmp.push(node);}r=tmp;}else{var fn=jQuery.expr[m[1]];if(typeof fn=="object")fn=fn[m[2]];if(typeof fn=="string")fn=eval("false||function(a,i){return "+fn+";}");r=jQuery.grep(r,function(elem,i){return fn(elem,i,m,r);},not);}}return{r:r,t:t};},dir:function(elem,dir){var matched=[],cur=elem[dir];while(cur&&cur!=document){if(cur.nodeType==1)matched.push(cur);cur=cur[dir];}return matched;},nth:function(cur,result,dir,elem){result=result||1;var num=0;for(;cur;cur=cur[dir])if(cur.nodeType==1&&++num==result)break;return cur;},sibling:function(n,elem){var r=[];for(;n;n=n.nextSibling){if(n.nodeType==1&&n!=elem)r.push(n);}return r;}});jQuery.event={add:function(elem,types,handler,data){if(elem.nodeType==3||elem.nodeType==8)return;if(jQuery.browser.msie&&elem.setInterval)elem=window;if(!handler.guid)handler.guid=this.guid++;if(data!=undefined){var fn=handler;handler=this.proxy(fn,function(){return fn.apply(this,arguments);});handler.data=data;}var events=jQuery.data(elem,"events")||jQuery.data(elem,"events",{}),handle=jQuery.data(elem,"handle")||jQuery.data(elem,"handle",function(){if(typeof jQuery!="undefined"&&!jQuery.event.triggered)return jQuery.event.handle.apply(arguments.callee.elem,arguments);});handle.elem=elem;jQuery.each(types.split(/\s+/),function(index,type){var parts=type.split(".");type=parts[0];handler.type=parts[1];var handlers=events[type];if(!handlers){handlers=events[type]={};if(!jQuery.event.special[type]||jQuery.event.special[type].setup.call(elem)===false){if(elem.addEventListener)elem.addEventListener(type,handle,false);else if(elem.attachEvent)elem.attachEvent("on"+type,handle);}}handlers[handler.guid]=handler;jQuery.event.global[type]=true;});elem=null;},guid:1,global:{},remove:function(elem,types,handler){if(elem.nodeType==3||elem.nodeType==8)return;var events=jQuery.data(elem,"events"),ret,index;if(events){if(types==undefined||(typeof types=="string"&&types.charAt(0)=="."))for(var type in events)this.remove(elem,type+(types||""));else{if(types.type){handler=types.handler;types=types.type;}jQuery.each(types.split(/\s+/),function(index,type){var parts=type.split(".");type=parts[0];if(events[type]){if(handler)delete events[type][handler.guid];else
+for(handler in events[type])if(!parts[1]||events[type][handler].type==parts[1])delete events[type][handler];for(ret in events[type])break;if(!ret){if(!jQuery.event.special[type]||jQuery.event.special[type].teardown.call(elem)===false){if(elem.removeEventListener)elem.removeEventListener(type,jQuery.data(elem,"handle"),false);else if(elem.detachEvent)elem.detachEvent("on"+type,jQuery.data(elem,"handle"));}ret=null;delete events[type];}}});}for(ret in events)break;if(!ret){var handle=jQuery.data(elem,"handle");if(handle)handle.elem=null;jQuery.removeData(elem,"events");jQuery.removeData(elem,"handle");}}},trigger:function(type,data,elem,donative,extra){data=jQuery.makeArray(data);if(type.indexOf("!")>=0){type=type.slice(0,-1);var exclusive=true;}if(!elem){if(this.global[type])jQuery("*").add([window,document]).trigger(type,data);}else{if(elem.nodeType==3||elem.nodeType==8)return undefined;var val,ret,fn=jQuery.isFunction(elem[type]||null),event=!data[0]||!data[0].preventDefault;if(event){data.unshift({type:type,target:elem,preventDefault:function(){},stopPropagation:function(){},timeStamp:now()});data[0][expando]=true;}data[0].type=type;if(exclusive)data[0].exclusive=true;var handle=jQuery.data(elem,"handle");if(handle)val=handle.apply(elem,data);if((!fn||(jQuery.nodeName(elem,'a')&&type=="click"))&&elem["on"+type]&&elem["on"+type].apply(elem,data)===false)val=false;if(event)data.shift();if(extra&&jQuery.isFunction(extra)){ret=extra.apply(elem,val==null?data:data.concat(val));if(ret!==undefined)val=ret;}if(fn&&donative!==false&&val!==false&&!(jQuery.nodeName(elem,'a')&&type=="click")){this.triggered=true;try{elem[type]();}catch(e){}}this.triggered=false;}return val;},handle:function(event){var val,ret,namespace,all,handlers;event=arguments[0]=jQuery.event.fix(event||window.event);namespace=event.type.split(".");event.type=namespace[0];namespace=namespace[1];all=!namespace&&!event.exclusive;handlers=(jQuery.data(this,"events")||{})[event.type];for(var j in handlers){var handler=handlers[j];if(all||handler.type==namespace){event.handler=handler;event.data=handler.data;ret=handler.apply(this,arguments);if(val!==false)val=ret;if(ret===false){event.preventDefault();event.stopPropagation();}}}return val;},fix:function(event){if(event[expando]==true)return event;var originalEvent=event;event={originalEvent:originalEvent};var props="altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target timeStamp toElement type view wheelDelta which".split(" ");for(var i=props.length;i;i--)event[props[i]]=originalEvent[props[i]];event[expando]=true;event.preventDefault=function(){if(originalEvent.preventDefault)originalEvent.preventDefault();originalEvent.returnValue=false;};event.stopPropagation=function(){if(originalEvent.stopPropagation)originalEvent.stopPropagation();originalEvent.cancelBubble=true;};event.timeStamp=event.timeStamp||now();if(!event.target)event.target=event.srcElement||document;if(event.target.nodeType==3)event.target=event.target.parentNode;if(!event.relatedTarget&&event.fromElement)event.relatedTarget=event.fromElement==event.target?event.toElement:event.fromElement;if(event.pageX==null&&event.clientX!=null){var doc=document.documentElement,body=document.body;event.pageX=event.clientX+(doc&&doc.scrollLeft||body&&body.scrollLeft||0)-(doc.clientLeft||0);event.pageY=event.clientY+(doc&&doc.scrollTop||body&&body.scrollTop||0)-(doc.clientTop||0);}if(!event.which&&((event.charCode||event.charCode===0)?event.charCode:event.keyCode))event.which=event.charCode||event.keyCode;if(!event.metaKey&&event.ctrlKey)event.metaKey=event.ctrlKey;if(!event.which&&event.button)event.which=(event.button&1?1:(event.button&2?3:(event.button&4?2:0)));return event;},proxy:function(fn,proxy){proxy.guid=fn.guid=fn.guid||proxy.guid||this.guid++;return proxy;},special:{ready:{setup:function(){bindReady();return;},teardown:function(){return;}},mouseenter:{setup:function(){if(jQuery.browser.msie)return false;jQuery(this).bind("mouseover",jQuery.event.special.mouseenter.handler);return true;},teardown:function(){if(jQuery.browser.msie)return false;jQuery(this).unbind("mouseover",jQuery.event.special.mouseenter.handler);return true;},handler:function(event){if(withinElement(event,this))return true;event.type="mouseenter";return jQuery.event.handle.apply(this,arguments);}},mouseleave:{setup:function(){if(jQuery.browser.msie)return false;jQuery(this).bind("mouseout",jQuery.event.special.mouseleave.handler);return true;},teardown:function(){if(jQuery.browser.msie)return false;jQuery(this).unbind("mouseout",jQuery.event.special.mouseleave.handler);return true;},handler:function(event){if(withinElement(event,this))return true;event.type="mouseleave";return jQuery.event.handle.apply(this,arguments);}}}};jQuery.fn.extend({bind:function(type,data,fn){return type=="unload"?this.one(type,data,fn):this.each(function(){jQuery.event.add(this,type,fn||data,fn&&data);});},one:function(type,data,fn){var one=jQuery.event.proxy(fn||data,function(event){jQuery(this).unbind(event,one);return(fn||data).apply(this,arguments);});return this.each(function(){jQuery.event.add(this,type,one,fn&&data);});},unbind:function(type,fn){return this.each(function(){jQuery.event.remove(this,type,fn);});},trigger:function(type,data,fn){return this.each(function(){jQuery.event.trigger(type,data,this,true,fn);});},triggerHandler:function(type,data,fn){return this[0]&&jQuery.event.trigger(type,data,this[0],false,fn);},toggle:function(fn){var args=arguments,i=1;while(i<args.length)jQuery.event.proxy(fn,args[i++]);return this.click(jQuery.event.proxy(fn,function(event){this.lastToggle=(this.lastToggle||0)%i;event.preventDefault();return args[this.lastToggle++].apply(this,arguments)||false;}));},hover:function(fnOver,fnOut){return this.bind('mouseenter',fnOver).bind('mouseleave',fnOut);},ready:function(fn){bindReady();if(jQuery.isReady)fn.call(document,jQuery);else
+jQuery.readyList.push(function(){return fn.call(this,jQuery);});return this;}});jQuery.extend({isReady:false,readyList:[],ready:function(){if(!jQuery.isReady){jQuery.isReady=true;if(jQuery.readyList){jQuery.each(jQuery.readyList,function(){this.call(document);});jQuery.readyList=null;}jQuery(document).triggerHandler("ready");}}});var readyBound=false;function bindReady(){if(readyBound)return;readyBound=true;if(document.addEventListener&&!jQuery.browser.opera)document.addEventListener("DOMContentLoaded",jQuery.ready,false);if(jQuery.browser.msie&&window==top)(function(){if(jQuery.isReady)return;try{document.documentElement.doScroll("left");}catch(error){setTimeout(arguments.callee,0);return;}jQuery.ready();})();if(jQuery.browser.opera)document.addEventListener("DOMContentLoaded",function(){if(jQuery.isReady)return;for(var i=0;i<document.styleSheets.length;i++)if(document.styleSheets[i].disabled){setTimeout(arguments.callee,0);return;}jQuery.ready();},false);if(jQuery.browser.safari){var numStyles;(function(){if(jQuery.isReady)return;if(document.readyState!="loaded"&&document.readyState!="complete"){setTimeout(arguments.callee,0);return;}if(numStyles===undefined)numStyles=jQuery("style, link[rel=stylesheet]").length;if(document.styleSheets.length!=numStyles){setTimeout(arguments.callee,0);return;}jQuery.ready();})();}jQuery.event.add(window,"load",jQuery.ready);}jQuery.each(("blur,focus,load,resize,scroll,unload,click,dblclick,"+"mousedown,mouseup,mousemove,mouseover,mouseout,change,select,"+"submit,keydown,keypress,keyup,error").split(","),function(i,name){jQuery.fn[name]=function(fn){return fn?this.bind(name,fn):this.trigger(name);};});var withinElement=function(event,elem){var parent=event.relatedTarget;while(parent&&parent!=elem)try{parent=parent.parentNode;}catch(error){parent=elem;}return parent==elem;};jQuery(window).bind("unload",function(){jQuery("*").add(document).unbind();});jQuery.fn.extend({_load:jQuery.fn.load,load:function(url,params,callback){if(typeof url!='string')return this._load(url);var off=url.indexOf(" ");if(off>=0){var selector=url.slice(off,url.length);url=url.slice(0,off);}callback=callback||function(){};var type="GET";if(params)if(jQuery.isFunction(params)){callback=params;params=null;}else{params=jQuery.param(params);type="POST";}var self=this;jQuery.ajax({url:url,type:type,dataType:"html",data:params,complete:function(res,status){if(status=="success"||status=="notmodified")self.html(selector?jQuery("<div/>").append(res.responseText.replace(/<script(.|\s)*?\/script>/g,"")).find(selector):res.responseText);self.each(callback,[res.responseText,status,res]);}});return this;},serialize:function(){return jQuery.param(this.serializeArray());},serializeArray:function(){return this.map(function(){return jQuery.nodeName(this,"form")?jQuery.makeArray(this.elements):this;}).filter(function(){return this.name&&!this.disabled&&(this.checked||/select|textarea/i.test(this.nodeName)||/text|hidden|password/i.test(this.type));}).map(function(i,elem){var val=jQuery(this).val();return val==null?null:val.constructor==Array?jQuery.map(val,function(val,i){return{name:elem.name,value:val};}):{name:elem.name,value:val};}).get();}});jQuery.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","),function(i,o){jQuery.fn[o]=function(f){return this.bind(o,f);};});var jsc=now();jQuery.extend({get:function(url,data,callback,type){if(jQuery.isFunction(data)){callback=data;data=null;}return jQuery.ajax({type:"GET",url:url,data:data,success:callback,dataType:type});},getScript:function(url,callback){return jQuery.get(url,null,callback,"script");},getJSON:function(url,data,callback){return jQuery.get(url,data,callback,"json");},post:function(url,data,callback,type){if(jQuery.isFunction(data)){callback=data;data={};}return jQuery.ajax({type:"POST",url:url,data:data,success:callback,dataType:type});},ajaxSetup:function(settings){jQuery.extend(jQuery.ajaxSettings,settings);},ajaxSettings:{url:location.href,global:true,type:"GET",timeout:0,contentType:"application/x-www-form-urlencoded",processData:true,async:true,data:null,username:null,password:null,accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},ajax:function(s){s=jQuery.extend(true,s,jQuery.extend(true,{},jQuery.ajaxSettings,s));var jsonp,jsre=/=\?(&|$)/g,status,data,type=s.type.toUpperCase();if(s.data&&s.processData&&typeof s.data!="string")s.data=jQuery.param(s.data);if(s.dataType=="jsonp"){if(type=="GET"){if(!s.url.match(jsre))s.url+=(s.url.match(/\?/)?"&":"?")+(s.jsonp||"callback")+"=?";}else if(!s.data||!s.data.match(jsre))s.data=(s.data?s.data+"&":"")+(s.jsonp||"callback")+"=?";s.dataType="json";}if(s.dataType=="json"&&(s.data&&s.data.match(jsre)||s.url.match(jsre))){jsonp="jsonp"+jsc++;if(s.data)s.data=(s.data+"").replace(jsre,"="+jsonp+"$1");s.url=s.url.replace(jsre,"="+jsonp+"$1");s.dataType="script";window[jsonp]=function(tmp){data=tmp;success();complete();window[jsonp]=undefined;try{delete window[jsonp];}catch(e){}if(head)head.removeChild(script);};}if(s.dataType=="script"&&s.cache==null)s.cache=false;if(s.cache===false&&type=="GET"){var ts=now();var ret=s.url.replace(/(\?|&)_=.*?(&|$)/,"$1_="+ts+"$2");s.url=ret+((ret==s.url)?(s.url.match(/\?/)?"&":"?")+"_="+ts:"");}if(s.data&&type=="GET"){s.url+=(s.url.match(/\?/)?"&":"?")+s.data;s.data=null;}if(s.global&&!jQuery.active++)jQuery.event.trigger("ajaxStart");var remote=/^(?:\w+:)?\/\/([^\/?#]+)/;if(s.dataType=="script"&&type=="GET"&&remote.test(s.url)&&remote.exec(s.url)[1]!=location.host){var head=document.getElementsByTagName("head")[0];var script=document.createElement("script");script.src=s.url;if(s.scriptCharset)script.charset=s.scriptCharset;if(!jsonp){var done=false;script.onload=script.onreadystatechange=function(){if(!done&&(!this.readyState||this.readyState=="loaded"||this.readyState=="complete")){done=true;success();complete();head.removeChild(script);}};}head.appendChild(script);return undefined;}var requestDone=false;var xhr=window.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest();if(s.username)xhr.open(type,s.url,s.async,s.username,s.password);else
+xhr.open(type,s.url,s.async);try{if(s.data)xhr.setRequestHeader("Content-Type",s.contentType);if(s.ifModified)xhr.setRequestHeader("If-Modified-Since",jQuery.lastModified[s.url]||"Thu, 01 Jan 1970 00:00:00 GMT");xhr.setRequestHeader("X-Requested-With","XMLHttpRequest");xhr.setRequestHeader("Accept",s.dataType&&s.accepts[s.dataType]?s.accepts[s.dataType]+", */*":s.accepts._default);}catch(e){}if(s.beforeSend&&s.beforeSend(xhr,s)===false){s.global&&jQuery.active--;xhr.abort();return false;}if(s.global)jQuery.event.trigger("ajaxSend",[xhr,s]);var onreadystatechange=function(isTimeout){if(!requestDone&&xhr&&(xhr.readyState==4||isTimeout=="timeout")){requestDone=true;if(ival){clearInterval(ival);ival=null;}status=isTimeout=="timeout"&&"timeout"||!jQuery.httpSuccess(xhr)&&"error"||s.ifModified&&jQuery.httpNotModified(xhr,s.url)&&"notmodified"||"success";if(status=="success"){try{data=jQuery.httpData(xhr,s.dataType,s.dataFilter);}catch(e){status="parsererror";}}if(status=="success"){var modRes;try{modRes=xhr.getResponseHeader("Last-Modified");}catch(e){}if(s.ifModified&&modRes)jQuery.lastModified[s.url]=modRes;if(!jsonp)success();}else
+jQuery.handleError(s,xhr,status);complete();if(s.async)xhr=null;}};if(s.async){var ival=setInterval(onreadystatechange,13);if(s.timeout>0)setTimeout(function(){if(xhr){xhr.abort();if(!requestDone)onreadystatechange("timeout");}},s.timeout);}try{xhr.send(s.data);}catch(e){jQuery.handleError(s,xhr,null,e);}if(!s.async)onreadystatechange();function success(){if(s.success)s.success(data,status);if(s.global)jQuery.event.trigger("ajaxSuccess",[xhr,s]);}function complete(){if(s.complete)s.complete(xhr,status);if(s.global)jQuery.event.trigger("ajaxComplete",[xhr,s]);if(s.global&&!--jQuery.active)jQuery.event.trigger("ajaxStop");}return xhr;},handleError:function(s,xhr,status,e){if(s.error)s.error(xhr,status,e);if(s.global)jQuery.event.trigger("ajaxError",[xhr,s,e]);},active:0,httpSuccess:function(xhr){try{return!xhr.status&&location.protocol=="file:"||(xhr.status>=200&&xhr.status<300)||xhr.status==304||xhr.status==1223||jQuery.browser.safari&&xhr.status==undefined;}catch(e){}return false;},httpNotModified:function(xhr,url){try{var xhrRes=xhr.getResponseHeader("Last-Modified");return xhr.status==304||xhrRes==jQuery.lastModified[url]||jQuery.browser.safari&&xhr.status==undefined;}catch(e){}return false;},httpData:function(xhr,type,filter){var ct=xhr.getResponseHeader("content-type"),xml=type=="xml"||!type&&ct&&ct.indexOf("xml")>=0,data=xml?xhr.responseXML:xhr.responseText;if(xml&&data.documentElement.tagName=="parsererror")throw"parsererror";if(filter)data=filter(data,type);if(type=="script")jQuery.globalEval(data);if(type=="json")data=eval("("+data+")");return data;},param:function(a){var s=[];if(a.constructor==Array||a.jquery)jQuery.each(a,function(){s.push(encodeURIComponent(this.name)+"="+encodeURIComponent(this.value));});else
+for(var j in a)if(a[j]&&a[j].constructor==Array)jQuery.each(a[j],function(){s.push(encodeURIComponent(j)+"="+encodeURIComponent(this));});else
+s.push(encodeURIComponent(j)+"="+encodeURIComponent(jQuery.isFunction(a[j])?a[j]():a[j]));return s.join("&").replace(/%20/g,"+");}});jQuery.fn.extend({show:function(speed,callback){return speed?this.animate({height:"show",width:"show",opacity:"show"},speed,callback):this.filter(":hidden").each(function(){this.style.display=this.oldblock||"";if(jQuery.css(this,"display")=="none"){var elem=jQuery("<"+this.tagName+" />").appendTo("body");this.style.display=elem.css("display");if(this.style.display=="none")this.style.display="block";elem.remove();}}).end();},hide:function(speed,callback){return speed?this.animate({height:"hide",width:"hide",opacity:"hide"},speed,callback):this.filter(":visible").each(function(){this.oldblock=this.oldblock||jQuery.css(this,"display");this.style.display="none";}).end();},_toggle:jQuery.fn.toggle,toggle:function(fn,fn2){return jQuery.isFunction(fn)&&jQuery.isFunction(fn2)?this._toggle.apply(this,arguments):fn?this.animate({height:"toggle",width:"toggle",opacity:"toggle"},fn,fn2):this.each(function(){jQuery(this)[jQuery(this).is(":hidden")?"show":"hide"]();});},slideDown:function(speed,callback){return this.animate({height:"show"},speed,callback);},slideUp:function(speed,callback){return this.animate({height:"hide"},speed,callback);},slideToggle:function(speed,callback){return this.animate({height:"toggle"},speed,callback);},fadeIn:function(speed,callback){return this.animate({opacity:"show"},speed,callback);},fadeOut:function(speed,callback){return this.animate({opacity:"hide"},speed,callback);},fadeTo:function(speed,to,callback){return this.animate({opacity:to},speed,callback);},animate:function(prop,speed,easing,callback){var optall=jQuery.speed(speed,easing,callback);return this[optall.queue===false?"each":"queue"](function(){if(this.nodeType!=1)return false;var opt=jQuery.extend({},optall),p,hidden=jQuery(this).is(":hidden"),self=this;for(p in prop){if(prop[p]=="hide"&&hidden||prop[p]=="show"&&!hidden)return opt.complete.call(this);if(p=="height"||p=="width"){opt.display=jQuery.css(this,"display");opt.overflow=this.style.overflow;}}if(opt.overflow!=null)this.style.overflow="hidden";opt.curAnim=jQuery.extend({},prop);jQuery.each(prop,function(name,val){var e=new jQuery.fx(self,opt,name);if(/toggle|show|hide/.test(val))e[val=="toggle"?hidden?"show":"hide":val](prop);else{var parts=val.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),start=e.cur(true)||0;if(parts){var end=parseFloat(parts[2]),unit=parts[3]||"px";if(unit!="px"){self.style[name]=(end||1)+unit;start=((end||1)/e.cur(true))*start;self.style[name]=start+unit;}if(parts[1])end=((parts[1]=="-="?-1:1)*end)+start;e.custom(start,end,unit);}else
+e.custom(start,val,"");}});return true;});},queue:function(type,fn){if(jQuery.isFunction(type)||(type&&type.constructor==Array)){fn=type;type="fx";}if(!type||(typeof type=="string"&&!fn))return queue(this[0],type);return this.each(function(){if(fn.constructor==Array)queue(this,type,fn);else{queue(this,type).push(fn);if(queue(this,type).length==1)fn.call(this);}});},stop:function(clearQueue,gotoEnd){var timers=jQuery.timers;if(clearQueue)this.queue([]);this.each(function(){for(var i=timers.length-1;i>=0;i--)if(timers[i].elem==this){if(gotoEnd)timers[i](true);timers.splice(i,1);}});if(!gotoEnd)this.dequeue();return this;}});var queue=function(elem,type,array){if(elem){type=type||"fx";var q=jQuery.data(elem,type+"queue");if(!q||array)q=jQuery.data(elem,type+"queue",jQuery.makeArray(array));}return q;};jQuery.fn.dequeue=function(type){type=type||"fx";return this.each(function(){var q=queue(this,type);q.shift();if(q.length)q[0].call(this);});};jQuery.extend({speed:function(speed,easing,fn){var opt=speed&&speed.constructor==Object?speed:{complete:fn||!fn&&easing||jQuery.isFunction(speed)&&speed,duration:speed,easing:fn&&easing||easing&&easing.constructor!=Function&&easing};opt.duration=(opt.duration&&opt.duration.constructor==Number?opt.duration:jQuery.fx.speeds[opt.duration])||jQuery.fx.speeds.def;opt.old=opt.complete;opt.complete=function(){if(opt.queue!==false)jQuery(this).dequeue();if(jQuery.isFunction(opt.old))opt.old.call(this);};return opt;},easing:{linear:function(p,n,firstNum,diff){return firstNum+diff*p;},swing:function(p,n,firstNum,diff){return((-Math.cos(p*Math.PI)/2)+0.5)*diff+firstNum;}},timers:[],timerId:null,fx:function(elem,options,prop){this.options=options;this.elem=elem;this.prop=prop;if(!options.orig)options.orig={};}});jQuery.fx.prototype={update:function(){if(this.options.step)this.options.step.call(this.elem,this.now,this);(jQuery.fx.step[this.prop]||jQuery.fx.step._default)(this);if(this.prop=="height"||this.prop=="width")this.elem.style.display="block";},cur:function(force){if(this.elem[this.prop]!=null&&this.elem.style[this.prop]==null)return this.elem[this.prop];var r=parseFloat(jQuery.css(this.elem,this.prop,force));return r&&r>-10000?r:parseFloat(jQuery.curCSS(this.elem,this.prop))||0;},custom:function(from,to,unit){this.startTime=now();this.start=from;this.end=to;this.unit=unit||this.unit||"px";this.now=this.start;this.pos=this.state=0;this.update();var self=this;function t(gotoEnd){return self.step(gotoEnd);}t.elem=this.elem;jQuery.timers.push(t);if(jQuery.timerId==null){jQuery.timerId=setInterval(function(){var timers=jQuery.timers;for(var i=0;i<timers.length;i++)if(!timers[i]())timers.splice(i--,1);if(!timers.length){clearInterval(jQuery.timerId);jQuery.timerId=null;}},13);}},show:function(){this.options.orig[this.prop]=jQuery.attr(this.elem.style,this.prop);this.options.show=true;this.custom(0,this.cur());if(this.prop=="width"||this.prop=="height")this.elem.style[this.prop]="1px";jQuery(this.elem).show();},hide:function(){this.options.orig[this.prop]=jQuery.attr(this.elem.style,this.prop);this.options.hide=true;this.custom(this.cur(),0);},step:function(gotoEnd){var t=now();if(gotoEnd||t>this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;var done=true;for(var i in this.options.curAnim)if(this.options.curAnim[i]!==true)done=false;if(done){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;this.elem.style.display=this.options.display;if(jQuery.css(this.elem,"display")=="none")this.elem.style.display="block";}if(this.options.hide)this.elem.style.display="none";if(this.options.hide||this.options.show)for(var p in this.options.curAnim)jQuery.attr(this.elem.style,p,this.options.orig[p]);}if(done)this.options.complete.call(this.elem);return false;}else{var n=t-this.startTime;this.state=n/this.options.duration;this.pos=jQuery.easing[this.options.easing||(jQuery.easing.swing?"swing":"linear")](this.state,n,0,1,this.options.duration);this.now=this.start+((this.end-this.start)*this.pos);this.update();}return true;}};jQuery.extend(jQuery.fx,{speeds:{slow:600,fast:200,def:400},step:{scrollLeft:function(fx){fx.elem.scrollLeft=fx.now;},scrollTop:function(fx){fx.elem.scrollTop=fx.now;},opacity:function(fx){jQuery.attr(fx.elem.style,"opacity",fx.now);},_default:function(fx){fx.elem.style[fx.prop]=fx.now+fx.unit;}}});jQuery.fn.offset=function(){var left=0,top=0,elem=this[0],results;if(elem)with(jQuery.browser){var parent=elem.parentNode,offsetChild=elem,offsetParent=elem.offsetParent,doc=elem.ownerDocument,safari2=safari&&parseInt(version)<522&&!/adobeair/i.test(userAgent),css=jQuery.curCSS,fixed=css(elem,"position")=="fixed";if(elem.getBoundingClientRect){var box=elem.getBoundingClientRect();add(box.left+Math.max(doc.documentElement.scrollLeft,doc.body.scrollLeft),box.top+Math.max(doc.documentElement.scrollTop,doc.body.scrollTop));add(-doc.documentElement.clientLeft,-doc.documentElement.clientTop);}else{add(elem.offsetLeft,elem.offsetTop);while(offsetParent){add(offsetParent.offsetLeft,offsetParent.offsetTop);if(mozilla&&!/^t(able|d|h)$/i.test(offsetParent.tagName)||safari&&!safari2)border(offsetParent);if(!fixed&&css(offsetParent,"position")=="fixed")fixed=true;offsetChild=/^body$/i.test(offsetParent.tagName)?offsetChild:offsetParent;offsetParent=offsetParent.offsetParent;}while(parent&&parent.tagName&&!/^body|html$/i.test(parent.tagName)){if(!/^inline|table.*$/i.test(css(parent,"display")))add(-parent.scrollLeft,-parent.scrollTop);if(mozilla&&css(parent,"overflow")!="visible")border(parent);parent=parent.parentNode;}if((safari2&&(fixed||css(offsetChild,"position")=="absolute"))||(mozilla&&css(offsetChild,"position")!="absolute"))add(-doc.body.offsetLeft,-doc.body.offsetTop);if(fixed)add(Math.max(doc.documentElement.scrollLeft,doc.body.scrollLeft),Math.max(doc.documentElement.scrollTop,doc.body.scrollTop));}results={top:top,left:left};}function border(elem){add(jQuery.curCSS(elem,"borderLeftWidth",true),jQuery.curCSS(elem,"borderTopWidth",true));}function add(l,t){left+=parseInt(l,10)||0;top+=parseInt(t,10)||0;}return results;};jQuery.fn.extend({position:function(){var left=0,top=0,results;if(this[0]){var offsetParent=this.offsetParent(),offset=this.offset(),parentOffset=/^body|html$/i.test(offsetParent[0].tagName)?{top:0,left:0}:offsetParent.offset();offset.top-=num(this,'marginTop');offset.left-=num(this,'marginLeft');parentOffset.top+=num(offsetParent,'borderTopWidth');parentOffset.left+=num(offsetParent,'borderLeftWidth');results={top:offset.top-parentOffset.top,left:offset.left-parentOffset.left};}return results;},offsetParent:function(){var offsetParent=this[0].offsetParent;while(offsetParent&&(!/^body|html$/i.test(offsetParent.tagName)&&jQuery.css(offsetParent,'position')=='static'))offsetParent=offsetParent.offsetParent;return jQuery(offsetParent);}});jQuery.each(['Left','Top'],function(i,name){var method='scroll'+name;jQuery.fn[method]=function(val){if(!this[0])return;return val!=undefined?this.each(function(){this==window||this==document?window.scrollTo(!i?val:jQuery(window).scrollLeft(),i?val:jQuery(window).scrollTop()):this[method]=val;}):this[0]==window||this[0]==document?self[i?'pageYOffset':'pageXOffset']||jQuery.boxModel&&document.documentElement[method]||document.body[method]:this[0][method];};});jQuery.each(["Height","Width"],function(i,name){var tl=i?"Left":"Top",br=i?"Right":"Bottom";jQuery.fn["inner"+name]=function(){return this[name.toLowerCase()]()+num(this,"padding"+tl)+num(this,"padding"+br);};jQuery.fn["outer"+name]=function(margin){return this["inner"+name]()+num(this,"border"+tl+"Width")+num(this,"border"+br+"Width")+(margin?num(this,"margin"+tl)+num(this,"margin"+br):0);};});})(); \ No newline at end of file
diff --git a/help/ipythonbook/doc/rel-0.10/html/_static/minus.png b/help/ipythonbook/doc/rel-0.10/html/_static/minus.png
new file mode 100644
index 0000000..da1c562
--- /dev/null
+++ b/help/ipythonbook/doc/rel-0.10/html/_static/minus.png
Binary files differ
diff --git a/help/ipythonbook/doc/rel-0.10/html/_static/pygments.css b/help/ipythonbook/doc/rel-0.10/html/_static/pygments.css
new file mode 100644
index 0000000..a55a324
--- /dev/null
+++ b/help/ipythonbook/doc/rel-0.10/html/_static/pygments.css
@@ -0,0 +1,59 @@
+.c { color: #408090; font-style: italic } /* Comment */
+.err { border: 1px solid #FF0000 } /* Error */
+.k { color: #007020; font-weight: bold } /* Keyword */
+.o { color: #666666 } /* Operator */
+.cm { color: #408090; font-style: italic } /* Comment.Multiline */
+.cp { color: #007020 } /* Comment.Preproc */
+.c1 { color: #408090; font-style: italic } /* Comment.Single */
+.cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */
+.gd { color: #A00000 } /* Generic.Deleted */
+.ge { font-style: italic } /* Generic.Emph */
+.gr { color: #FF0000 } /* Generic.Error */
+.gh { color: #000080; font-weight: bold } /* Generic.Heading */
+.gi { color: #00A000 } /* Generic.Inserted */
+.go { color: #303030 } /* Generic.Output */
+.gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */
+.gs { font-weight: bold } /* Generic.Strong */
+.gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+.gt { color: #0040D0 } /* Generic.Traceback */
+.kc { color: #007020; font-weight: bold } /* Keyword.Constant */
+.kd { color: #007020; font-weight: bold } /* Keyword.Declaration */
+.kp { color: #007020 } /* Keyword.Pseudo */
+.kr { color: #007020; font-weight: bold } /* Keyword.Reserved */
+.kt { color: #902000 } /* Keyword.Type */
+.m { color: #208050 } /* Literal.Number */
+.s { color: #4070a0 } /* Literal.String */
+.na { color: #4070a0 } /* Name.Attribute */
+.nb { color: #007020 } /* Name.Builtin */
+.nc { color: #0e84b5; font-weight: bold } /* Name.Class */
+.no { color: #60add5 } /* Name.Constant */
+.nd { color: #555555; font-weight: bold } /* Name.Decorator */
+.ni { color: #d55537; font-weight: bold } /* Name.Entity */
+.ne { color: #007020 } /* Name.Exception */
+.nf { color: #06287e } /* Name.Function */
+.nl { color: #002070; font-weight: bold } /* Name.Label */
+.nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */
+.nt { color: #062873; font-weight: bold } /* Name.Tag */
+.nv { color: #bb60d5 } /* Name.Variable */
+.ow { color: #007020; font-weight: bold } /* Operator.Word */
+.w { color: #bbbbbb } /* Text.Whitespace */
+.mf { color: #208050 } /* Literal.Number.Float */
+.mh { color: #208050 } /* Literal.Number.Hex */
+.mi { color: #208050 } /* Literal.Number.Integer */
+.mo { color: #208050 } /* Literal.Number.Oct */
+.sb { color: #4070a0 } /* Literal.String.Backtick */
+.sc { color: #4070a0 } /* Literal.String.Char */
+.sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */
+.s2 { color: #4070a0 } /* Literal.String.Double */
+.se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */
+.sh { color: #4070a0 } /* Literal.String.Heredoc */
+.si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */
+.sx { color: #c65d09 } /* Literal.String.Other */
+.sr { color: #235388 } /* Literal.String.Regex */
+.s1 { color: #4070a0 } /* Literal.String.Single */
+.ss { color: #517918 } /* Literal.String.Symbol */
+.bp { color: #007020 } /* Name.Builtin.Pseudo */
+.vc { color: #bb60d5 } /* Name.Variable.Class */
+.vg { color: #bb60d5 } /* Name.Variable.Global */
+.vi { color: #bb60d5 } /* Name.Variable.Instance */
+.il { color: #208050 } /* Literal.Number.Integer.Long */ \ No newline at end of file
diff --git a/help/ipythonbook/doc/rel-0.10/html/api/generated/IPython.Magic.html b/help/ipythonbook/doc/rel-0.10/html/api/generated/IPython.Magic.html
new file mode 100644
index 0000000..7704d85
--- /dev/null
+++ b/help/ipythonbook/doc/rel-0.10/html/api/generated/IPython.Magic.html
@@ -0,0 +1,1565 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+ <title>Magic &mdash; IPython v0.10 documentation</title>
+ <link rel="stylesheet" href="../../_static/default.css" type="text/css" />
+ <link rel="stylesheet" href="../../_static/pygments.css" type="text/css" />
+ <script type="text/javascript">
+ var DOCUMENTATION_OPTIONS = {
+ URL_ROOT: '../../',
+ VERSION: '0.10',
+ COLLAPSE_MODINDEX: false,
+ FILE_SUFFIX: '.html',
+ HAS_SOURCE: true
+ };
+ </script>
+ <script type="text/javascript" src="../../_static/jquery.js"></script>
+ <script type="text/javascript" src="../../_static/doctools.js"></script>
+ <link rel="top" title="IPython v0.10 documentation" href="../../index.html" />
+ <link rel="up" title="The IPython API" href="../index.html" />
+ <link rel="next" title="OInspect" href="IPython.OInspect.html" />
+ <link rel="prev" title="Logger" href="IPython.Logger.html" />
+ </head>
+ <body>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../../modindex.html" title="Global Module Index"
+ accesskey="M">modules</a> |</li>
+ <li class="right" >
+ <a href="IPython.OInspect.html" title="OInspect"
+ accesskey="N">next</a> |</li>
+ <li class="right" >
+ <a href="IPython.Logger.html" title="Logger"
+ accesskey="P">previous</a> |</li>
+ <li><a href="../../index.html">IPython v0.10 documentation</a> &raquo;</li>
+ <li><a href="../index.html" accesskey="U">The IPython API</a> &raquo;</li>
+ </ul>
+ </div>
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body">
+
+
+ <div class="section" id="magic">
+<h1>Magic<a class="headerlink" href="#magic" title="Permalink to this headline">¶</a></h1>
+<div class="section" id="module-IPython.Magic">
+<h2>Module: <tt class="xref docutils literal"><span class="pre">Magic</span></tt><a class="headerlink" href="#module-IPython.Magic" title="Permalink to this headline">¶</a></h2>
+<p>Inheritance diagram for <tt class="docutils literal"><span class="pre">IPython.Magic</span></tt>:</p>
+<img src="../../_images/inheritance471b45c3f1.png" usemap="#inheritance471b45c3f1" class="inheritance"/><map id="inheritance471b45c3f1" name="inheritance471b45c3f1">
+<area shape="rect" href="#IPython.Magic.Bunch" title="IPython.Magic.Bunch" alt="" coords="7,56,159,83"/>
+<area shape="rect" href="#IPython.Magic.Magic" title="IPython.Magic.Magic" alt="" coords="8,5,157,32"/>
+</map>
+<p>Magic functions for InteractiveShell.</p>
+</div>
+<div class="section" id="classes">
+<h2>Classes<a class="headerlink" href="#classes" title="Permalink to this headline">¶</a></h2>
+<div class="section" id="bunch">
+<h3><a title="IPython.Magic.Bunch" class="reference internal" href="#IPython.Magic.Bunch"><tt class="xref docutils literal"><span class="pre">Bunch</span></tt></a><a class="headerlink" href="#bunch" title="Permalink to this headline">¶</a></h3>
+<dl class="class">
+<dt id="IPython.Magic.Bunch">
+<!--[IPython.Magic.Bunch]-->class <tt class="descclassname">IPython.Magic.</tt><tt class="descname">Bunch</tt><a class="headerlink" href="#IPython.Magic.Bunch" title="Permalink to this definition">¶</a></dt>
+<dd></dd></dl>
+
+</div>
+<div class="section" id="id1">
+<h3><a title="IPython.Magic.Magic" class="reference internal" href="#IPython.Magic.Magic"><tt class="xref docutils literal"><span class="pre">Magic</span></tt></a><a class="headerlink" href="#id1" title="Permalink to this headline">¶</a></h3>
+<dl class="class">
+<dt id="IPython.Magic.Magic">
+<!--[IPython.Magic.Magic]-->class <tt class="descclassname">IPython.Magic.</tt><tt class="descname">Magic</tt><big>(</big><em>shell</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic" title="Permalink to this definition">¶</a></dt>
+<dd><p>Magic functions for InteractiveShell.</p>
+<p>Shell functions which can be reached as %function_name. All magic
+functions should accept a string, which they can parse for their own
+needs. This can make some functions easier to type, eg <cite>%cd ../</cite>
+vs. <cite>%cd(&#8220;../&#8221;)</cite></p>
+<p>ALL definitions MUST begin with the prefix <a href="#id6"><span class="problematic" id="id7">magic_</span></a>. The user won&#8217;t need it
+at the command line, but it is is needed in the definition.</p>
+<dl class="method">
+<dt id="IPython.Magic.Magic.__init__">
+<!--[IPython.Magic.Magic.__init__]--><tt class="descname">__init__</tt><big>(</big><em>shell</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.__init__" title="Permalink to this definition">¶</a></dt>
+<dd></dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.arg_err">
+<!--[IPython.Magic.Magic.arg_err]--><tt class="descname">arg_err</tt><big>(</big><em>func</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.arg_err" title="Permalink to this definition">¶</a></dt>
+<dd>Print docstring if incorrect arguments were passed</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.default_option">
+<!--[IPython.Magic.Magic.default_option]--><tt class="descname">default_option</tt><big>(</big><em>fn</em>, <em>optstr</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.default_option" title="Permalink to this definition">¶</a></dt>
+<dd>Make an entry in the options_table for fn, with value optstr</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.extract_input_slices">
+<!--[IPython.Magic.Magic.extract_input_slices]--><tt class="descname">extract_input_slices</tt><big>(</big><em>slices</em>, <em>raw=False</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.extract_input_slices" title="Permalink to this definition">¶</a></dt>
+<dd><p>Return as a string a set of input history slices.</p>
+<p>Inputs:</p>
+<blockquote>
+<ul class="simple">
+<li>slices: the set of slices is given as a list of strings (like</li>
+</ul>
+<p>[&#8216;1&#8217;,&#8216;4:8&#8217;,&#8216;9&#8217;], since this function is for use by magic functions
+which get their arguments as strings.</p>
+</blockquote>
+<p>Optional inputs:</p>
+<blockquote>
+<ul class="simple">
+<li>raw(False): by default, the processed input is used. If this is</li>
+</ul>
+<p>true, the raw input history is used instead.</p>
+</blockquote>
+<p>Note that slices can be called with two notations:</p>
+<p>N:M -&gt; standard python form, means including items N...(M-1).</p>
+<p>N-M -&gt; include items N..M (closed endpoint).</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.format_latex">
+<!--[IPython.Magic.Magic.format_latex]--><tt class="descname">format_latex</tt><big>(</big><em>strng</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.format_latex" title="Permalink to this definition">¶</a></dt>
+<dd>Format a string for latex inclusion.</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.format_screen">
+<!--[IPython.Magic.Magic.format_screen]--><tt class="descname">format_screen</tt><big>(</big><em>strng</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.format_screen" title="Permalink to this definition">¶</a></dt>
+<dd><p>Format a string for screen printing.</p>
+<p>This removes some latex-type format codes.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.lsmagic">
+<!--[IPython.Magic.Magic.lsmagic]--><tt class="descname">lsmagic</tt><big>(</big><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.lsmagic" title="Permalink to this definition">¶</a></dt>
+<dd><p>Return a list of currently available magic functions.</p>
+<p>Gives a list of the bare names after mangling ([&#8216;ls&#8217;,&#8217;cd&#8217;, ...], not
+[&#8216;magic_ls&#8217;,&#8217;magic_cd&#8217;,...]</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_Exit">
+<!--[IPython.Magic.Magic.magic_Exit]--><tt class="descname">magic_Exit</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_Exit" title="Permalink to this definition">¶</a></dt>
+<dd>Exit IPython without confirmation.</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_Pprint">
+<!--[IPython.Magic.Magic.magic_Pprint]--><tt class="descname">magic_Pprint</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_Pprint" title="Permalink to this definition">¶</a></dt>
+<dd>Toggle pretty printing on/off.</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_alias">
+<!--[IPython.Magic.Magic.magic_alias]--><tt class="descname">magic_alias</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_alias" title="Permalink to this definition">¶</a></dt>
+<dd><p>Define an alias for a system command.</p>
+<p>&#8216;%alias alias_name cmd&#8217; defines &#8216;alias_name&#8217; as an alias for &#8216;cmd&#8217;</p>
+<p>Then, typing &#8216;alias_name params&#8217; will execute the system command &#8216;cmd
+params&#8217; (from your underlying operating system).</p>
+<p>Aliases have lower precedence than magic functions and Python normal
+variables, so if &#8216;foo&#8217; is both a Python variable and an alias, the
+alias can not be executed until &#8216;del foo&#8217; removes the Python variable.</p>
+<p>You can use the %l specifier in an alias definition to represent the
+whole line when the alias is called. For example:</p>
+<blockquote>
+In [2]: alias all echo &#8220;Input in brackets: &lt;%l&gt;&#8221;
+In [3]: all hello world
+Input in brackets: &lt;hello world&gt;</blockquote>
+<p>You can also define aliases with parameters using %s specifiers (one
+per parameter):</p>
+<blockquote>
+In [1]: alias parts echo first %s second %s
+In [2]: %parts A B
+first A second B
+In [3]: %parts A
+Incorrect number of arguments: 2 expected.
+parts is an alias to: &#8216;echo first %s second %s&#8217;</blockquote>
+<p>Note that %l and %s are mutually exclusive. You can only use one or
+the other in your aliases.</p>
+<p>Aliases expand Python variables just like system calls using ! or !!
+do: all expressions prefixed with &#8216;$&#8217; get expanded. For details of
+the semantic rules, see PEP-215:
+<a class="reference external" href="http://www.python.org/peps/pep-0215.html">http://www.python.org/peps/pep-0215.html</a>. This is the library used by
+IPython for variable expansion. If you want to access a true shell
+variable, an extra $ is necessary to prevent its expansion by IPython:</p>
+<p>In [6]: alias show echo
+In [7]: PATH=&#8217;A Python string&#8217;
+In [8]: show $PATH
+A Python string
+In [9]: show $$PATH
+/usr/local/lf9560/bin:/usr/local/intel/compiler70/ia32/bin:...</p>
+<p>You can use the alias facility to acess all of $PATH. See the %rehash
+and %rehashx functions, which automatically create aliases for the
+contents of your $PATH.</p>
+<p>If called with no parameters, %alias prints the current alias table.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_autocall">
+<!--[IPython.Magic.Magic.magic_autocall]--><tt class="descname">magic_autocall</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_autocall" title="Permalink to this definition">¶</a></dt>
+<dd><p>Make functions callable without having to type parentheses.</p>
+<p>Usage:</p>
+<blockquote>
+%autocall [mode]</blockquote>
+<p>The mode can be one of: 0-&gt;Off, 1-&gt;Smart, 2-&gt;Full. If not given, the
+value is toggled on and off (remembering the previous state).</p>
+<p>In more detail, these values mean:</p>
+<p>0 -&gt; fully disabled</p>
+<p>1 -&gt; active, but do not apply if there are no arguments on the line.</p>
+<p>In this mode, you get:</p>
+<p>In [1]: callable
+Out[1]: &lt;built-in function callable&gt;</p>
+<p>In [2]: callable &#8216;hello&#8217;
+&#8212;&#8212;&gt; callable(&#8216;hello&#8217;)
+Out[2]: False</p>
+<p>2 -&gt; Active always. Even if no arguments are present, the callable
+object is called:</p>
+<p>In [2]: float
+&#8212;&#8212;&gt; float()
+Out[2]: 0.0</p>
+<p>Note that even with autocall off, you can still use &#8216;/&#8217; at the start of
+a line to treat the first argument on the command line as a function
+and add parentheses to it:</p>
+<p>In [8]: /str 43
+&#8212;&#8212;&gt; str(43)
+Out[8]: &#8216;43&#8217;</p>
+<p># all-random (note for auto-testing)</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_autoindent">
+<!--[IPython.Magic.Magic.magic_autoindent]--><tt class="descname">magic_autoindent</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_autoindent" title="Permalink to this definition">¶</a></dt>
+<dd>Toggle autoindent on/off (if available).</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_automagic">
+<!--[IPython.Magic.Magic.magic_automagic]--><tt class="descname">magic_automagic</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_automagic" title="Permalink to this definition">¶</a></dt>
+<dd><p>Make magic functions callable without having to type the initial %.</p>
+<p>Without argumentsl toggles on/off (when off, you must call it as
+%automagic, of course). With arguments it sets the value, and you can
+use any of (case insensitive):</p>
+<blockquote>
+<ul class="simple">
+<li>on,1,True: to activate</li>
+<li>off,0,False: to deactivate.</li>
+</ul>
+</blockquote>
+<p>Note that magic functions have lowest priority, so if there&#8217;s a
+variable whose name collides with that of a magic fn, automagic won&#8217;t
+work for that function (you get the variable instead). However, if you
+delete the variable (del var), the previously shadowed magic function
+becomes visible to automagic again.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_bg">
+<!--[IPython.Magic.Magic.magic_bg]--><tt class="descname">magic_bg</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_bg" title="Permalink to this definition">¶</a></dt>
+<dd><p>Run a job in the background, in a separate thread.</p>
+<p>For example,</p>
+<blockquote>
+%bg myfunc(x,y,z=1)</blockquote>
+<p>will execute &#8216;myfunc(x,y,z=1)&#8217; in a background thread. As soon as the
+execution starts, a message will be printed indicating the job
+number. If your job number is 5, you can use</p>
+<blockquote>
+myvar = jobs.result(5) or myvar = jobs[5].result</blockquote>
+<p>to assign this result to variable &#8216;myvar&#8217;.</p>
+<p>IPython has a job manager, accessible via the &#8216;jobs&#8217; object. You can
+type jobs? to get more information about it, and use jobs.&lt;TAB&gt; to see
+its attributes. All attributes not starting with an underscore are
+meant for public use.</p>
+<p>In particular, look at the jobs.new() method, which is used to create
+new jobs. This magic %bg function is just a convenience wrapper
+around jobs.new(), for expression-based jobs. If you want to create a
+new job with an explicit function object and arguments, you must call
+jobs.new() directly.</p>
+<p>The jobs.new docstring also describes in detail several important
+caveats associated with a thread-based model for background job
+execution. Type jobs.new? for details.</p>
+<p>You can check the status of all jobs with jobs.status().</p>
+<p>The jobs variable is set by IPython into the Python builtin namespace.
+If you ever declare a variable named &#8216;jobs&#8217;, you will shadow this
+name. You can either delete your global jobs variable to regain
+access to the job manager, or make a new name and assign it manually
+to the manager (stored in IPython&#8217;s namespace). For example, to
+assign the job manager to the Jobs name, use:</p>
+<blockquote>
+Jobs = __builtins__.jobs</blockquote>
+</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_bookmark">
+<!--[IPython.Magic.Magic.magic_bookmark]--><tt class="descname">magic_bookmark</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_bookmark" title="Permalink to this definition">¶</a></dt>
+<dd><p>Manage IPython&#8217;s bookmark system.</p>
+<p>%bookmark &lt;name&gt; - set bookmark to current dir
+%bookmark &lt;name&gt; &lt;dir&gt; - set bookmark to &lt;dir&gt;
+%bookmark -l - list all bookmarks
+%bookmark -d &lt;name&gt; - remove bookmark
+%bookmark -r - remove all bookmarks</p>
+<dl class="docutils">
+<dt>You can later on access a bookmarked folder with:</dt>
+<dd>%cd -b &lt;name&gt;</dd>
+</dl>
+<p>or simply &#8216;%cd &lt;name&gt;&#8217; if there is no directory called &lt;name&gt; AND
+there is such a bookmark defined.</p>
+<p>Your bookmarks persist through IPython sessions, but they are
+associated with each profile.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_cd">
+<!--[IPython.Magic.Magic.magic_cd]--><tt class="descname">magic_cd</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_cd" title="Permalink to this definition">¶</a></dt>
+<dd><p>Change the current working directory.</p>
+<p>This command automatically maintains an internal list of directories
+you visit during your IPython session, in the variable _dh. The
+command %dhist shows this history nicely formatted. You can also
+do &#8216;cd -&lt;tab&gt;&#8217; to see directory history conveniently.</p>
+<p>Usage:</p>
+<blockquote>
+<p>cd &#8216;dir&#8217;: changes to directory &#8216;dir&#8217;.</p>
+<p>cd -: changes to the last visited directory.</p>
+<p>cd -&lt;n&gt;: changes to the n-th directory in the directory history.</p>
+<p>cd &#8211;foo: change to directory that matches &#8216;foo&#8217; in history</p>
+<dl class="docutils">
+<dt>cd -b &lt;bookmark_name&gt;: jump to a bookmark set by %bookmark</dt>
+<dd><dl class="first last docutils">
+<dt>(note: cd &lt;bookmark_name&gt; is enough if there is no</dt>
+<dd>directory &lt;bookmark_name&gt;, but a bookmark with the name exists.)
+&#8216;cd -b &lt;tab&gt;&#8217; allows you to tab-complete bookmark names.</dd>
+</dl>
+</dd>
+</dl>
+</blockquote>
+<p>Options:</p>
+<p>-q: quiet. Do not print the working directory after the cd command is
+executed. By default IPython&#8217;s cd command does print this directory,
+since the default prompts do not display path information.</p>
+<p>Note that !cd doesn&#8217;t work for this purpose because the shell where
+!command runs is immediately discarded after executing &#8216;command&#8217;.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_color_info">
+<!--[IPython.Magic.Magic.magic_color_info]--><tt class="descname">magic_color_info</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_color_info" title="Permalink to this definition">¶</a></dt>
+<dd><p>Toggle color_info.</p>
+<p>The color_info configuration parameter controls whether colors are
+used for displaying object details (by things like %psource, %pfile or
+the &#8216;?&#8217; system). This function toggles this value with each call.</p>
+<p>Note that unless you have a fairly recent pager (less works better
+than more) in your system, using colored object information displays
+will not work properly. Test it and see.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_colors">
+<!--[IPython.Magic.Magic.magic_colors]--><tt class="descname">magic_colors</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_colors" title="Permalink to this definition">¶</a></dt>
+<dd><p>Switch color scheme for prompts, info system and exception handlers.</p>
+<p>Currently implemented schemes: NoColor, Linux, LightBG.</p>
+<p>Color scheme names are not case-sensitive.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_cpaste">
+<!--[IPython.Magic.Magic.magic_cpaste]--><tt class="descname">magic_cpaste</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_cpaste" title="Permalink to this definition">¶</a></dt>
+<dd><p>Allows you to paste &amp; execute a pre-formatted code block from clipboard.</p>
+<p>You must terminate the block with &#8216;&#8211;&#8217; (two minus-signs) alone on the
+line. You can also provide your own sentinel with &#8216;%paste -s %%&#8217; (&#8216;%%&#8217;
+is the new sentinel for this operation)</p>
+<p>The block is dedented prior to execution to enable execution of method
+definitions. &#8216;&gt;&#8217; and &#8216;+&#8217; characters at the beginning of a line are
+ignored, to allow pasting directly from e-mails, diff files and
+doctests (the &#8216;...&#8217; continuation prompt is also stripped). The
+executed block is also assigned to variable named &#8216;pasted_block&#8217; for
+later editing with &#8216;%edit pasted_block&#8217;.</p>
+<p>You can also pass a variable name as an argument, e.g. &#8216;%cpaste foo&#8217;.
+This assigns the pasted block to variable &#8216;foo&#8217; as string, without
+dedenting or executing it (preceding &gt;&gt;&gt; and + is still stripped)</p>
+<p>&#8216;%cpaste -r&#8217; re-executes the block previously entered by cpaste.</p>
+<p>Do not be alarmed by garbled output on Windows (it&#8217;s a readline bug).
+Just press enter and type &#8211; (and press enter again) and the block
+will be what was just pasted.</p>
+<p>IPython statements (magics, shell escapes) are not supported (yet).</p>
+<div class="admonition-see-also admonition seealso">
+<p class="first admonition-title">See also</p>
+<dl class="last docutils">
+<dt><tt class="xref docutils literal"><span class="pre">paste</span></tt></dt>
+<dd>automatically pull code from clipboard.</dd>
+</dl>
+</div>
+</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_debug">
+<!--[IPython.Magic.Magic.magic_debug]--><tt class="descname">magic_debug</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_debug" title="Permalink to this definition">¶</a></dt>
+<dd><p>Activate the interactive debugger in post-mortem mode.</p>
+<p>If an exception has just occurred, this lets you inspect its stack
+frames interactively. Note that this will always work only on the last
+traceback that occurred, so you must call this quickly after an
+exception that you wish to inspect has fired, because if another one
+occurs, it clobbers the previous one.</p>
+<p>If you want IPython to automatically do this on every exception, see
+the %pdb magic for more details.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_dhist">
+<!--[IPython.Magic.Magic.magic_dhist]--><tt class="descname">magic_dhist</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_dhist" title="Permalink to this definition">¶</a></dt>
+<dd><p>Print your history of visited directories.</p>
+<p>%dhist -&gt; print full history%dhist n -&gt; print last n entries only%dhist n1 n2 -&gt; print entries between n1 and n2 (n1 not included)</p>
+<p>This history is automatically maintained by the %cd command, and
+always available as the global list variable _dh. You can use %cd -&lt;n&gt;
+to go to directory number &lt;n&gt;.</p>
+<p>Note that most of time, you should view directory history by entering
+cd -&lt;TAB&gt;.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_dirs">
+<!--[IPython.Magic.Magic.magic_dirs]--><tt class="descname">magic_dirs</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_dirs" title="Permalink to this definition">¶</a></dt>
+<dd>Return the current directory stack.</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_doctest_mode">
+<!--[IPython.Magic.Magic.magic_doctest_mode]--><tt class="descname">magic_doctest_mode</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_doctest_mode" title="Permalink to this definition">¶</a></dt>
+<dd><p>Toggle doctest mode on and off.</p>
+<p>This mode allows you to toggle the prompt behavior between normal
+IPython prompts and ones that are as similar to the default IPython
+interpreter as possible.</p>
+<p>It also supports the pasting of code snippets that have leading &#8216;&gt;&gt;&gt;&#8217;
+and &#8216;...&#8217; prompts in them. This means that you can paste doctests from
+files or docstrings (even if they have leading whitespace), and the
+code will execute correctly. You can then use &#8216;%history -tn&#8217; to see
+the translated history without line numbers; this will give you the
+input after removal of all the leading prompts and whitespace, which
+can be pasted back into an editor.</p>
+<p>With these features, you can switch into this mode easily whenever you
+need to do testing and changes to doctests, without having to leave
+your existing IPython session.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_ed">
+<!--[IPython.Magic.Magic.magic_ed]--><tt class="descname">magic_ed</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_ed" title="Permalink to this definition">¶</a></dt>
+<dd>Alias to %edit.</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_edit">
+<!--[IPython.Magic.Magic.magic_edit]--><tt class="descname">magic_edit</tt><big>(</big><em>parameter_s=''</em>, <em>last_call=</em><span class="optional">[</span>, <em>''</em>, <em>''</em><span class="optional">]</span><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_edit" title="Permalink to this definition">¶</a></dt>
+<dd><p>Bring up an editor and execute the resulting code.</p>
+<dl class="docutils">
+<dt>Usage:</dt>
+<dd>%edit [options] [args]</dd>
+</dl>
+<p>%edit runs IPython&#8217;s editor hook. The default version of this hook is
+set to call the __IPYTHON__.rc.editor command. This is read from your
+environment variable $EDITOR. If this isn&#8217;t found, it will default to
+vi under Linux/Unix and to notepad under Windows. See the end of this
+docstring for how to change the editor hook.</p>
+<p>You can also set the value of this editor via the command line option
+&#8216;-editor&#8217; or in your ipythonrc file. This is useful if you wish to use
+specifically for IPython an editor different from your typical default
+(and for Windows users who typically don&#8217;t set environment variables).</p>
+<p>This command allows you to conveniently edit multi-line code right in
+your IPython session.</p>
+<p>If called without arguments, %edit opens up an empty editor with a
+temporary file and will execute the contents of this file when you
+close it (don&#8217;t forget to save it!).</p>
+<p>Options:</p>
+<p>-n &lt;number&gt;: open the editor at a specified line number. By default,
+the IPython editor hook uses the unix syntax &#8216;editor +N filename&#8217;, but
+you can configure this by providing your own modified hook if your
+favorite editor supports line-number specifications with a different
+syntax.</p>
+<p>-p: this will call the editor with the same data as the previous time
+it was used, regardless of how long ago (in your current session) it
+was.</p>
+<p>-r: use &#8216;raw&#8217; input. This option only applies to input taken from the
+user&#8217;s history. By default, the &#8216;processed&#8217; history is used, so that
+magics are loaded in their transformed version to valid Python. If
+this option is given, the raw input as typed as the command line is
+used instead. When you exit the editor, it will be executed by
+IPython&#8217;s own processor.</p>
+<p>-x: do not execute the edited code immediately upon exit. This is
+mainly useful if you are editing programs which need to be called with
+command line arguments, which you can then do using %run.</p>
+<p>Arguments:</p>
+<p>If arguments are given, the following possibilites exist:</p>
+<ul class="simple">
+<li>The arguments are numbers or pairs of colon-separated numbers (like</li>
+</ul>
+<p>1 4:8 9). These are interpreted as lines of previous input to be
+loaded into the editor. The syntax is the same of the %macro command.</p>
+<ul class="simple">
+<li>If the argument doesn&#8217;t start with a number, it is evaluated as a</li>
+</ul>
+<p>variable and its contents loaded into the editor. You can thus edit
+any string which contains python code (including the result of
+previous edits).</p>
+<ul class="simple">
+<li>If the argument is the name of an object (other than a string),</li>
+</ul>
+<p>IPython will try to locate the file where it was defined and open the
+editor at the point where it is defined. You can use <cite>%edit function</cite>
+to load an editor exactly at the point where &#8216;function&#8217; is defined,
+edit it and have the file be executed automatically.</p>
+<p>If the object is a macro (see %macro for details), this opens up your
+specified editor with a temporary file containing the macro&#8217;s data.
+Upon exit, the macro is reloaded with the contents of the file.</p>
+<p>Note: opening at an exact line is only supported under Unix, and some
+editors (like kedit and gedit up to Gnome 2.8) do not understand the
+&#8216;+NUMBER&#8217; parameter necessary for this feature. Good editors like
+(X)Emacs, vi, jed, pico and joe all do.</p>
+<ul class="simple">
+<li>If the argument is not found as a variable, IPython will look for a</li>
+</ul>
+<p>file with that name (adding .py if necessary) and load it into the
+editor. It will execute its contents with execfile() when you exit,
+loading any code in the file into your interactive namespace.</p>
+<p>After executing your code, %edit will return as output the code you
+typed in the editor (except when it was an existing file). This way
+you can reload the code in further invocations of %edit as a variable,
+via _&lt;NUMBER&gt; or Out[&lt;NUMBER&gt;], where &lt;NUMBER&gt; is the prompt number of
+the output.</p>
+<p>Note that %edit is also available through the alias %ed.</p>
+<p>This is an example of creating a simple function inside the editor and
+then modifying it. First, start up the editor:</p>
+<p>In [1]: ed
+Editing... done. Executing edited code...
+Out[1]: &#8216;def foo():n print &#8220;foo() was defined in an editing session&#8221;n&#8217;</p>
+<p>We can then call the function foo():</p>
+<p>In [2]: foo()
+foo() was defined in an editing session</p>
+<p>Now we edit foo. IPython automatically loads the editor with the
+(temporary) file where foo() was previously defined:</p>
+<p>In [3]: ed foo
+Editing... done. Executing edited code...</p>
+<p>And if we call foo() again we get the modified version:</p>
+<p>In [4]: foo()
+foo() has now been changed!</p>
+<p>Here is an example of how to edit a code snippet successive
+times. First we call the editor:</p>
+<p>In [5]: ed
+Editing... done. Executing edited code...
+hello
+Out[5]: &#8220;print &#8216;hello&#8217;n&#8221;</p>
+<p>Now we call it again with the previous output (stored in _):</p>
+<p>In [6]: ed _
+Editing... done. Executing edited code...
+hello world
+Out[6]: &#8220;print &#8216;hello world&#8217;n&#8221;</p>
+<p>Now we call it with the output #8 (stored in _8, also as Out[8]):</p>
+<p>In [7]: ed _8
+Editing... done. Executing edited code...
+hello again
+Out[7]: &#8220;print &#8216;hello again&#8217;n&#8221;</p>
+<p>Changing the default editor hook:</p>
+<p>If you wish to write your own editor hook, you can put it in a
+configuration file which you load at startup time. The default hook
+is defined in the IPython.hooks module, and you can use that as a
+starting example for further modifications. That file also has
+general instructions on how to set a new hook for use once you&#8217;ve
+defined it.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_env">
+<!--[IPython.Magic.Magic.magic_env]--><tt class="descname">magic_env</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_env" title="Permalink to this definition">¶</a></dt>
+<dd>List environment variables.</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_exit">
+<!--[IPython.Magic.Magic.magic_exit]--><tt class="descname">magic_exit</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_exit" title="Permalink to this definition">¶</a></dt>
+<dd><p>Exit IPython, confirming if configured to do so.</p>
+<p>You can configure whether IPython asks for confirmation upon exit by
+setting the confirm_exit flag in the ipythonrc file.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_logoff">
+<!--[IPython.Magic.Magic.magic_logoff]--><tt class="descname">magic_logoff</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_logoff" title="Permalink to this definition">¶</a></dt>
+<dd><p>Temporarily stop logging.</p>
+<p>You must have previously started logging.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_logon">
+<!--[IPython.Magic.Magic.magic_logon]--><tt class="descname">magic_logon</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_logon" title="Permalink to this definition">¶</a></dt>
+<dd><p>Restart logging.</p>
+<p>This function is for restarting logging which you&#8217;ve temporarily
+stopped with %logoff. For starting logging for the first time, you
+must use the %logstart function, which allows you to specify an
+optional log filename.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_logstart">
+<!--[IPython.Magic.Magic.magic_logstart]--><tt class="descname">magic_logstart</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_logstart" title="Permalink to this definition">¶</a></dt>
+<dd><p>Start logging anywhere in a session.</p>
+<p>%logstart [-o|-r|-t] [log_name [log_mode]]</p>
+<p>If no name is given, it defaults to a file named &#8216;ipython_log.py&#8217; in your
+current directory, in &#8216;rotate&#8217; mode (see below).</p>
+<p>&#8216;%logstart name&#8217; saves to file &#8216;name&#8217; in &#8216;backup&#8217; mode. It saves your
+history up to that point and then continues logging.</p>
+<p>%logstart takes a second optional parameter: logging mode. This can be one
+of (note that the modes are given unquoted):</p>
+<blockquote>
+append: well, that says it.backup: rename (if exists) to name~ and start name.global: single logfile in your home dir, appended to.over : overwrite existing log.rotate: create rotating logs name.1~, name.2~, etc.</blockquote>
+<p>Options:</p>
+<blockquote>
+<p>-o: log also IPython&#8217;s output. In this mode, all commands which
+generate an Out[NN] prompt are recorded to the logfile, right after
+their corresponding input line. The output lines are always
+prepended with a &#8216;#[Out]# &#8216; marker, so that the log remains valid
+Python code.</p>
+<p>Since this marker is always the same, filtering only the output from
+a log is very easy, using for example a simple awk call:</p>
+<blockquote>
+awk -F&#8217;#[Out]# &#8216; &#8216;{if($2) {print $2}}&#8217; ipython_log.py</blockquote>
+<p>-r: log &#8216;raw&#8217; input. Normally, IPython&#8217;s logs contain the processed
+input, so that user lines are logged in their final form, converted
+into valid Python. For example, %Exit is logged as
+&#8216;_ip.magic(&#8220;Exit&#8221;). If the -r flag is given, all input is logged
+exactly as typed, with no transformations applied.</p>
+<p>-t: put timestamps before each input line logged (these are put in
+comments).</p>
+</blockquote>
+</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_logstate">
+<!--[IPython.Magic.Magic.magic_logstate]--><tt class="descname">magic_logstate</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_logstate" title="Permalink to this definition">¶</a></dt>
+<dd>Print the status of the logging system.</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_logstop">
+<!--[IPython.Magic.Magic.magic_logstop]--><tt class="descname">magic_logstop</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_logstop" title="Permalink to this definition">¶</a></dt>
+<dd><p>Fully stop logging and close log file.</p>
+<p>In order to start logging again, a new %logstart call needs to be made,
+possibly (though not necessarily) with a new filename, mode and other
+options.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_lsmagic">
+<!--[IPython.Magic.Magic.magic_lsmagic]--><tt class="descname">magic_lsmagic</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_lsmagic" title="Permalink to this definition">¶</a></dt>
+<dd>List currently available magic functions.</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_macro">
+<!--[IPython.Magic.Magic.magic_macro]--><tt class="descname">magic_macro</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_macro" title="Permalink to this definition">¶</a></dt>
+<dd><p>Define a set of input lines as a macro for future re-execution.</p>
+<dl class="docutils">
+<dt>Usage:</dt>
+<dd>%macro [options] name n1-n2 n3-n4 ... n5 .. n6 ...</dd>
+</dl>
+<p>Options:</p>
+<blockquote>
+-r: use &#8216;raw&#8217; input. By default, the &#8216;processed&#8217; history is used,
+so that magics are loaded in their transformed version to valid
+Python. If this option is given, the raw input as typed as the
+command line is used instead.</blockquote>
+<p>This will define a global variable called <cite>name</cite> which is a string
+made of joining the slices and lines you specify (n1,n2,... numbers
+above) from your input history into a single string. This variable
+acts like an automatic function which re-executes those lines as if
+you had typed them. You just type &#8216;name&#8217; at the prompt and the code
+executes.</p>
+<p>The notation for indicating number ranges is: n1-n2 means &#8216;use line
+numbers n1,...n2&#8217; (the endpoint is included). That is, &#8216;5-7&#8217; means
+using the lines numbered 5,6 and 7.</p>
+<p>Note: as a &#8216;hidden&#8217; feature, you can also use traditional python slice
+notation, where N:M means numbers N through M-1.</p>
+<p>For example, if your history contains (%hist prints it):</p>
+<blockquote>
+44: x=1
+45: y=3
+46: z=x+y
+47: print x
+48: a=5
+49: print &#8216;x&#8217;,x,&#8217;y&#8217;,y</blockquote>
+<p>you can create a macro with lines 44 through 47 (included) and line 49
+called my_macro with:</p>
+<blockquote>
+In [55]: %macro my_macro 44-47 49</blockquote>
+<p>Now, typing <cite>my_macro</cite> (without quotes) will re-execute all this code
+in one pass.</p>
+<p>You don&#8217;t need to give the line-numbers in order, and any given line
+number can appear multiple times. You can assemble macros with any
+lines from your input history in any order.</p>
+<p>The macro is a simple object which holds its value in an attribute,
+but IPython&#8217;s display system checks for macros and executes them as
+code instead of printing them when you type their name.</p>
+<p>You can view a macro&#8217;s contents by explicitly printing it with:</p>
+<blockquote>
+&#8216;print macro_name&#8217;.</blockquote>
+<p>For one-off cases which DON&#8217;T contain magic function calls in them you
+can obtain similar results by explicitly executing slices from your
+input history with:</p>
+<blockquote>
+In [60]: exec In[44:48]+In[49]</blockquote>
+</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_magic">
+<!--[IPython.Magic.Magic.magic_magic]--><tt class="descname">magic_magic</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_magic" title="Permalink to this definition">¶</a></dt>
+<dd><p>Print information about the magic function system.</p>
+<p>Supported formats: -latex, -brief, -rest</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_page">
+<!--[IPython.Magic.Magic.magic_page]--><tt class="descname">magic_page</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_page" title="Permalink to this definition">¶</a></dt>
+<dd><p>Pretty print the object and display it through a pager.</p>
+<p>%page [options] OBJECT</p>
+<p>If no object is given, use _ (last output).</p>
+<p>Options:</p>
+<blockquote>
+-r: page str(object), don&#8217;t pretty-print it.</blockquote>
+</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_paste">
+<!--[IPython.Magic.Magic.magic_paste]--><tt class="descname">magic_paste</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_paste" title="Permalink to this definition">¶</a></dt>
+<dd><p>Allows you to paste &amp; execute a pre-formatted code block from clipboard.</p>
+<p>The text is pulled directly from the clipboard without user
+intervention.</p>
+<p>The block is dedented prior to execution to enable execution of method
+definitions. &#8216;&gt;&#8217; and &#8216;+&#8217; characters at the beginning of a line are
+ignored, to allow pasting directly from e-mails, diff files and
+doctests (the &#8216;...&#8217; continuation prompt is also stripped). The
+executed block is also assigned to variable named &#8216;pasted_block&#8217; for
+later editing with &#8216;%edit pasted_block&#8217;.</p>
+<p>You can also pass a variable name as an argument, e.g. &#8216;%paste foo&#8217;.
+This assigns the pasted block to variable &#8216;foo&#8217; as string, without
+dedenting or executing it (preceding &gt;&gt;&gt; and + is still stripped)</p>
+<p>&#8216;%paste -r&#8217; re-executes the block previously entered by cpaste.</p>
+<p>IPython statements (magics, shell escapes) are not supported (yet).</p>
+<div class="admonition-see-also admonition seealso">
+<p class="first admonition-title">See also</p>
+<dl class="last docutils">
+<dt><tt class="xref docutils literal"><span class="pre">cpaste</span></tt></dt>
+<dd>manually paste code into terminal until you mark its end.</dd>
+</dl>
+</div>
+</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_pdb">
+<!--[IPython.Magic.Magic.magic_pdb]--><tt class="descname">magic_pdb</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_pdb" title="Permalink to this definition">¶</a></dt>
+<dd><p>Control the automatic calling of the pdb interactive debugger.</p>
+<p>Call as &#8216;%pdb on&#8217;, &#8216;%pdb 1&#8217;, &#8216;%pdb off&#8217; or &#8216;%pdb 0&#8217;. If called without
+argument it works as a toggle.</p>
+<p>When an exception is triggered, IPython can optionally call the
+interactive pdb debugger after the traceback printout. %pdb toggles
+this feature on and off.</p>
+<p>The initial state of this feature is set in your ipythonrc
+configuration file (the variable is called &#8216;pdb&#8217;).</p>
+<p>If you want to just activate the debugger AFTER an exception has fired,
+without having to type &#8216;%pdb on&#8217; and rerunning your code, you can use
+the %debug magic.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_pdef">
+<!--[IPython.Magic.Magic.magic_pdef]--><tt class="descname">magic_pdef</tt><big>(</big><em>parameter_s=''</em>, <em>namespaces=None</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_pdef" title="Permalink to this definition">¶</a></dt>
+<dd><p>Print the definition header for any callable object.</p>
+<p>If the object is a class, print the constructor information.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_pdoc">
+<!--[IPython.Magic.Magic.magic_pdoc]--><tt class="descname">magic_pdoc</tt><big>(</big><em>parameter_s=''</em>, <em>namespaces=None</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_pdoc" title="Permalink to this definition">¶</a></dt>
+<dd><p>Print the docstring for an object.</p>
+<p>If the given object is a class, it will print both the class and the
+constructor docstrings.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_pfile">
+<!--[IPython.Magic.Magic.magic_pfile]--><tt class="descname">magic_pfile</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_pfile" title="Permalink to this definition">¶</a></dt>
+<dd><p>Print (or run through pager) the file where an object is defined.</p>
+<p>The file opens at the line where the object definition begins. IPython
+will honor the environment variable PAGER if set, and otherwise will
+do its best to print the file in a convenient form.</p>
+<p>If the given argument is not an object currently defined, IPython will
+try to interpret it as a filename (automatically adding a .py extension
+if needed). You can thus use %pfile as a syntax highlighting code
+viewer.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_pinfo">
+<!--[IPython.Magic.Magic.magic_pinfo]--><tt class="descname">magic_pinfo</tt><big>(</big><em>parameter_s=''</em>, <em>namespaces=None</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_pinfo" title="Permalink to this definition">¶</a></dt>
+<dd><p>Provide detailed information about an object.</p>
+<p>&#8216;%pinfo object&#8217; is just a synonym for object? or ?object.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_popd">
+<!--[IPython.Magic.Magic.magic_popd]--><tt class="descname">magic_popd</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_popd" title="Permalink to this definition">¶</a></dt>
+<dd>Change to directory popped off the top of the stack.</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_profile">
+<!--[IPython.Magic.Magic.magic_profile]--><tt class="descname">magic_profile</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_profile" title="Permalink to this definition">¶</a></dt>
+<dd>Print your currently active IPyhton profile.</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_prun">
+<!--[IPython.Magic.Magic.magic_prun]--><tt class="descname">magic_prun</tt><big>(</big><em>parameter_s=''</em>, <em>user_mode=1</em>, <em>opts=None</em>, <em>arg_lst=None</em>, <em>prog_ns=None</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_prun" title="Permalink to this definition">¶</a></dt>
+<dd><p>Run a statement through the python code profiler.</p>
+<blockquote>
+<dl class="docutils">
+<dt>Usage:</dt>
+<dd>%prun [options] statement</dd>
+</dl>
+<p>The given statement (which doesn&#8217;t require quote marks) is run via the
+python profiler in a manner similar to the profile.run() function.
+Namespaces are internally managed to work correctly; profile.run
+cannot be used in IPython because it makes certain assumptions about
+namespaces which do not hold under IPython.</p>
+<p>Options:</p>
+<p>-l &lt;limit&gt;: you can place restrictions on what or how much of the
+profile gets printed. The limit value can be:</p>
+<blockquote>
+<ul class="simple">
+<li>A string: only information for function names containing this string</li>
+</ul>
+<p>is printed.</p>
+<ul class="simple">
+<li>An integer: only these many lines are printed.</li>
+<li>A float (between 0 and 1): this fraction of the report is printed</li>
+</ul>
+<p>(for example, use a limit of 0.4 to see the topmost 40% only).</p>
+</blockquote>
+<p>You can combine several limits with repeated use of the option. For
+example, &#8216;-l __init__ -l 5&#8217; will print only the topmost 5 lines of
+information about class constructors.</p>
+<p>-r: return the pstats.Stats object generated by the profiling. This
+object has all the information about the profile in it, and you can
+later use it for further analysis or in other functions.</p>
+</blockquote>
+<dl class="docutils">
+<dt>-s &lt;key&gt;: sort profile by given key. You can provide more than one key</dt>
+<dd><p class="first">by using the option several times: &#8216;-s key1 -s key2 -s key3...&#8217;. The
+default sorting key is &#8216;time&#8217;.</p>
+<p>The following is copied verbatim from the profile documentation
+referenced below:</p>
+<p>When more than one key is provided, additional keys are used as
+secondary criteria when the there is equality in all keys selected
+before them.</p>
+<p>Abbreviations can be used for any key names, as long as the
+abbreviation is unambiguous. The following are the keys currently
+defined:</p>
+<blockquote>
+<dl class="docutils">
+<dt>Valid Arg Meaning</dt>
+<dd>&#8220;calls&#8221; call count
+&#8220;cumulative&#8221; cumulative time
+&#8220;file&#8221; file name
+&#8220;module&#8221; file name
+&#8220;pcalls&#8221; primitive call count
+&#8220;line&#8221; line number
+&#8220;name&#8221; function name
+&#8220;nfl&#8221; name/file/line
+&#8220;stdname&#8221; standard name
+&#8220;time&#8221; internal time</dd>
+</dl>
+</blockquote>
+<p>Note that all sorts on statistics are in descending order (placing
+most time consuming items first), where as name, file, and line number
+searches are in ascending order (i.e., alphabetical). The subtle
+distinction between &#8220;nfl&#8221; and &#8220;stdname&#8221; is that the standard name is a
+sort of the name as printed, which means that the embedded line
+numbers get compared in an odd way. For example, lines 3, 20, and 40
+would (if the file names were the same) appear in the string order
+&#8220;20&#8221; &#8220;3&#8221; and &#8220;40&#8221;. In contrast, &#8220;nfl&#8221; does a numeric compare of the
+line numbers. In fact, sort_stats(&#8220;nfl&#8221;) is the same as
+sort_stats(&#8220;name&#8221;, &#8220;file&#8221;, &#8220;line&#8221;).</p>
+<p>-T &lt;filename&gt;: save profile results as shown on screen to a text
+file. The profile is still shown on screen.</p>
+<p>-D &lt;filename&gt;: save (via dump_stats) profile statistics to given
+filename. This data is in a format understod by the pstats module, and
+is generated by a call to the dump_stats() method of profile
+objects. The profile is still shown on screen.</p>
+<p>If you want to run complete programs under the profiler&#8217;s control, use
+&#8216;%run -p [prof_opts] filename.py [args to program]&#8217; where prof_opts
+contains profiler specific options as described here.</p>
+<p>You can read the complete documentation for the profile module with:</p>
+<div class="last highlight-python"><pre>In [1]: import profile; profile.help()</pre>
+</div>
+</dd>
+</dl>
+</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_psearch">
+<!--[IPython.Magic.Magic.magic_psearch]--><tt class="descname">magic_psearch</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_psearch" title="Permalink to this definition">¶</a></dt>
+<dd><p>Search for object in namespaces by wildcard.</p>
+<p>%psearch [options] PATTERN [OBJECT TYPE]</p>
+<p>Note: ? can be used as a synonym for %psearch, at the beginning or at
+the end: both a*? and ?a* are equivalent to &#8216;%psearch a*&#8217;. Still, the
+rest of the command line must be unchanged (options come first), so
+for example the following forms are equivalent</p>
+<p>%psearch -i a* function
+-i a* function?
+?-i a* function</p>
+<p>Arguments:</p>
+<blockquote>
+<p>PATTERN</p>
+<p>where PATTERN is a string containing * as a wildcard similar to its
+use in a shell. The pattern is matched in all namespaces on the
+search path. By default objects starting with a single _ are not
+matched, many IPython generated objects have a single
+underscore. The default is case insensitive matching. Matching is
+also done on the attributes of objects and not only on the objects
+in a module.</p>
+<p>[OBJECT TYPE]</p>
+<p>Is the name of a python type from the types module. The name is
+given in lowercase without the ending type, ex. StringType is
+written string. By adding a type here only objects matching the
+given type are matched. Using all here makes the pattern match all
+types (this is the default).</p>
+</blockquote>
+<p>Options:</p>
+<blockquote>
+<p>-a: makes the pattern match even objects whose names start with a
+single underscore. These names are normally ommitted from the
+search.</p>
+<p>-i/-c: make the pattern case insensitive/sensitive. If neither of
+these options is given, the default is read from your ipythonrc
+file. The option name which sets this value is
+&#8216;wildcards_case_sensitive&#8217;. If this option is not specified in your
+ipythonrc file, IPython&#8217;s internal default is to do a case sensitive
+search.</p>
+<p>-e/-s NAMESPACE: exclude/search a given namespace. The pattern you
+specifiy can be searched in any of the following namespaces:
+&#8216;builtin&#8217;, &#8216;user&#8217;, &#8216;user_global&#8217;,&#8217;internal&#8217;, &#8216;alias&#8217;, where
+&#8216;builtin&#8217; and &#8216;user&#8217; are the search defaults. Note that you should
+not use quotes when specifying namespaces.</p>
+<p>&#8216;Builtin&#8217; contains the python module builtin, &#8216;user&#8217; contains all
+user data, &#8216;alias&#8217; only contain the shell aliases and no python
+objects, &#8216;internal&#8217; contains objects used by IPython. The
+&#8216;user_global&#8217; namespace is only used by embedded IPython instances,
+and it contains module-level globals. You can add namespaces to the
+search with -s or exclude them with -e (these options can be given
+more than once).</p>
+</blockquote>
+<p>Examples:</p>
+<p>%psearch a* -&gt; objects beginning with an a
+%psearch -e builtin a* -&gt; objects NOT in the builtin space starting in a
+%psearch a* function -&gt; all functions beginning with an a
+%psearch re.e* -&gt; objects beginning with an e in module re
+%psearch r*.e* -&gt; objects that start with e in modules starting in r
+%psearch r*.* string -&gt; all strings in modules beginning with r</p>
+<p>Case sensitve search:</p>
+<p>%psearch -c a* list all object beginning with lower case a</p>
+<p>Show objects beginning with a single _:</p>
+<p>%psearch -a _* list objects beginning with a single underscore</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_psource">
+<!--[IPython.Magic.Magic.magic_psource]--><tt class="descname">magic_psource</tt><big>(</big><em>parameter_s=''</em>, <em>namespaces=None</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_psource" title="Permalink to this definition">¶</a></dt>
+<dd>Print (or run through pager) the source code for an object.</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_pushd">
+<!--[IPython.Magic.Magic.magic_pushd]--><tt class="descname">magic_pushd</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_pushd" title="Permalink to this definition">¶</a></dt>
+<dd><p>Place the current dir on stack and change directory.</p>
+<dl class="docutils">
+<dt>Usage:</dt>
+<dd>%pushd [&#8216;dirname&#8217;]</dd>
+</dl>
+</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_pwd">
+<!--[IPython.Magic.Magic.magic_pwd]--><tt class="descname">magic_pwd</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_pwd" title="Permalink to this definition">¶</a></dt>
+<dd>Return the current working directory path.</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_pycat">
+<!--[IPython.Magic.Magic.magic_pycat]--><tt class="descname">magic_pycat</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_pycat" title="Permalink to this definition">¶</a></dt>
+<dd><p>Show a syntax-highlighted file through a pager.</p>
+<p>This magic is similar to the cat utility, but it will assume the file
+to be Python source and will show it with syntax highlighting.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_quickref">
+<!--[IPython.Magic.Magic.magic_quickref]--><tt class="descname">magic_quickref</tt><big>(</big><em>arg</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_quickref" title="Permalink to this definition">¶</a></dt>
+<dd>Show a quick reference sheet</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_quit">
+<!--[IPython.Magic.Magic.magic_quit]--><tt class="descname">magic_quit</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_quit" title="Permalink to this definition">¶</a></dt>
+<dd>Exit IPython, confirming if configured to do so (like %exit)</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_r">
+<!--[IPython.Magic.Magic.magic_r]--><tt class="descname">magic_r</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_r" title="Permalink to this definition">¶</a></dt>
+<dd><p>Repeat previous input.</p>
+<p>Note: Consider using the more powerfull %rep instead!</p>
+<p>If given an argument, repeats the previous command which starts with
+the same string, otherwise it just repeats the previous input.</p>
+<p>Shell escaped commands (with ! as first character) are not recognized
+by this system, only pure python code and magic commands.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_rehashx">
+<!--[IPython.Magic.Magic.magic_rehashx]--><tt class="descname">magic_rehashx</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_rehashx" title="Permalink to this definition">¶</a></dt>
+<dd><p>Update the alias table with all executable files in $PATH.</p>
+<p>This version explicitly checks that every entry in $PATH is a file
+with execute access (os.X_OK), so it is much slower than %rehash.</p>
+<p>Under Windows, it checks executability as a match agains a
+&#8216;|&#8217;-separated string of extensions, stored in the IPython config
+variable win_exec_ext. This defaults to &#8216;exe|com|bat&#8217;.</p>
+<p>This function also resets the root module cache of module completer,
+used on slow filesystems.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_reset">
+<!--[IPython.Magic.Magic.magic_reset]--><tt class="descname">magic_reset</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_reset" title="Permalink to this definition">¶</a></dt>
+<dd><p>Resets the namespace by removing all names defined by the user.</p>
+<p>Input/Output history are left around in case you need them.</p>
+<table class="docutils field-list" frame="void" rules="none">
+<col class="field-name" />
+<col class="field-body" />
+<tbody valign="top">
+<tr class="field"><th class="field-name">Parameters:</th><td class="field-body"><strong>-y</strong> : force reset without asking for confirmation.</td>
+</tr>
+</tbody>
+</table>
+<p class="rubric">Examples</p>
+<p>In [6]: a = 1</p>
+<p>In [7]: a
+Out[7]: 1</p>
+<p>In [8]: &#8216;a&#8217; in _ip.user_ns
+Out[8]: True</p>
+<p>In [9]: %reset -f</p>
+<p>In [10]: &#8216;a&#8217; in _ip.user_ns
+Out[10]: False</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_run">
+<!--[IPython.Magic.Magic.magic_run]--><tt class="descname">magic_run</tt><big>(</big><em>parameter_s=''</em>, <em>runner=None</em>, <em>file_finder=&lt;function get_py_filename at 0x97afa74&gt;</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_run" title="Permalink to this definition">¶</a></dt>
+<dd><p>Run the named file inside IPython as a program.</p>
+<dl class="docutils">
+<dt>Usage:</dt>
+<dd>%run [-n -i -t [-N&lt;N&gt;] -d [-b&lt;N&gt;] -p [profile options]] file [args]</dd>
+</dl>
+<p>Parameters after the filename are passed as command-line arguments to
+the program (put in sys.argv). Then, control returns to IPython&#8217;s
+prompt.</p>
+<dl class="docutils">
+<dt>This is similar to running at a system prompt:</dt>
+<dd>$ python file args</dd>
+</dl>
+<p>but with the advantage of giving you IPython&#8217;s tracebacks, and of
+loading all variables into your interactive namespace for further use
+(unless -p is used, see below).</p>
+<p>The file is executed in a namespace initially consisting only of
+__name__==&#8217;__main__&#8217; and sys.argv constructed as indicated. It thus
+sees its environment as if it were being run as a stand-alone program
+(except for sharing global objects such as previously imported
+modules). But after execution, the IPython interactive namespace gets
+updated with all variables defined in the program (except for __name__
+and sys.argv). This allows for very convenient loading of code for
+interactive work, while giving each program a &#8216;clean sheet&#8217; to run in.</p>
+<p>Options:</p>
+<p>-n: __name__ is NOT set to &#8216;__main__&#8217;, but to the running file&#8217;s name
+without extension (as python does under import). This allows running
+scripts and reloading the definitions in them without calling code
+protected by an &#8216; if __name__ == &#8220;__main__&#8221; &#8216; clause.</p>
+<p>-i: run the file in IPython&#8217;s namespace instead of an empty one. This
+is useful if you are experimenting with code written in a text editor
+which depends on variables defined interactively.</p>
+<p>-e: ignore sys.exit() calls or SystemExit exceptions in the script
+being run. This is particularly useful if IPython is being used to
+run unittests, which always exit with a sys.exit() call. In such
+cases you are interested in the output of the test results, not in
+seeing a traceback of the unittest module.</p>
+<p>-t: print timing information at the end of the run. IPython will give
+you an estimated CPU time consumption for your script, which under
+Unix uses the resource module to avoid the wraparound problems of
+time.clock(). Under Unix, an estimate of time spent on system tasks
+is also given (for Windows platforms this is reported as 0.0).</p>
+<p>If -t is given, an additional -N&lt;N&gt; option can be given, where &lt;N&gt;
+must be an integer indicating how many times you want the script to
+run. The final timing report will include total and per run results.</p>
+<p>For example (testing the script uniq_stable.py):</p>
+<blockquote>
+<p>In [1]: run -t uniq_stable</p>
+<dl class="docutils">
+<dt>IPython CPU timings (estimated):</dt>
+<dd>User : 0.19597 s.System: 0.0 s.</dd>
+</dl>
+<p>In [2]: run -t -N5 uniq_stable</p>
+<p>IPython CPU timings (estimated):Total runs performed: 5</p>
+<blockquote>
+Times : Total Per runUser : 0.910862 s, 0.1821724 s.System: 0.0 s, 0.0 s.</blockquote>
+</blockquote>
+<p>-d: run your program under the control of pdb, the Python debugger.
+This allows you to execute your program step by step, watch variables,
+etc. Internally, what IPython does is similar to calling:</p>
+<blockquote>
+pdb.run(&#8216;execfile(&#8220;YOURFILENAME&#8221;)&#8217;)</blockquote>
+<p>with a breakpoint set on line 1 of your file. You can change the line
+number for this automatic breakpoint to be &lt;N&gt; by using the -bN option
+(where N must be an integer). For example:</p>
+<blockquote>
+%run -d -b40 myscript</blockquote>
+<p>will set the first breakpoint at line 40 in myscript.py. Note that
+the first breakpoint must be set on a line which actually does
+something (not a comment or docstring) for it to stop execution.</p>
+<p>When the pdb debugger starts, you will see a (Pdb) prompt. You must
+first enter &#8216;c&#8217; (without qoutes) to start execution up to the first
+breakpoint.</p>
+<p>Entering &#8216;help&#8217; gives information about the use of the debugger. You
+can easily see pdb&#8217;s full documentation with &#8220;import pdb;pdb.help()&#8221;
+at a prompt.</p>
+<p>-p: run program under the control of the Python profiler module (which
+prints a detailed report of execution times, function calls, etc).</p>
+<p>You can pass other options after -p which affect the behavior of the
+profiler itself. See the docs for %prun for details.</p>
+<p>In this mode, the program&#8217;s variables do NOT propagate back to the
+IPython interactive namespace (because they remain in the namespace
+where the profiler executes them).</p>
+<p>Internally this triggers a call to %prun, see its documentation for
+details on the options available specifically for profiling.</p>
+<p>There is one special usage for which the text above doesn&#8217;t apply:
+if the filename ends with .ipy, the file is run as ipython script,
+just as if the commands were written on IPython prompt.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_runlog">
+<!--[IPython.Magic.Magic.magic_runlog]--><tt class="descname">magic_runlog</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_runlog" title="Permalink to this definition">¶</a></dt>
+<dd><p>Run files as logs.</p>
+<dl class="docutils">
+<dt>Usage:</dt>
+<dd>%runlog file1 file2 ...</dd>
+</dl>
+<p>Run the named files (treating them as log files) in sequence inside
+the interpreter, and return to the prompt. This is much slower than
+%run because each line is executed in a try/except block, but it
+allows running files with syntax errors in them.</p>
+<p>Normally IPython will guess when a file is one of its own logfiles, so
+you can typically use %run even for logs. This shorthand allows you to
+force any file to be treated as a log file.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_save">
+<!--[IPython.Magic.Magic.magic_save]--><tt class="descname">magic_save</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_save" title="Permalink to this definition">¶</a></dt>
+<dd><p>Save a set of lines to a given filename.</p>
+<dl class="docutils">
+<dt>Usage:</dt>
+<dd>%save [options] filename n1-n2 n3-n4 ... n5 .. n6 ...</dd>
+</dl>
+<p>Options:</p>
+<blockquote>
+-r: use &#8216;raw&#8217; input. By default, the &#8216;processed&#8217; history is used,
+so that magics are loaded in their transformed version to valid
+Python. If this option is given, the raw input as typed as the
+command line is used instead.</blockquote>
+<p>This function uses the same syntax as %macro for line extraction, but
+instead of creating a macro it saves the resulting string to the
+filename you specify.</p>
+<p>It adds a &#8216;.py&#8217; extension to the file if you don&#8217;t do so yourself, and
+it asks for confirmation before overwriting existing files.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_sc">
+<!--[IPython.Magic.Magic.magic_sc]--><tt class="descname">magic_sc</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_sc" title="Permalink to this definition">¶</a></dt>
+<dd><p>Shell capture - execute a shell command and capture its output.</p>
+<p>DEPRECATED. Suboptimal, retained for backwards compatibility.</p>
+<p>You should use the form &#8216;var = !command&#8217; instead. Example:</p>
+<blockquote>
+<p>&#8220;%sc -l myfiles = ls ~&#8221; should now be written as</p>
+<p>&#8220;myfiles = !ls ~&#8221;</p>
+</blockquote>
+<p>myfiles.s, myfiles.l and myfiles.n still apply as documented
+below.</p>
+<p>&#8211;
+%sc [options] varname=command</p>
+<p>IPython will run the given command using commands.getoutput(), and
+will then update the user&#8217;s interactive namespace with a variable
+called varname, containing the value of the call. Your command can
+contain shell wildcards, pipes, etc.</p>
+<p>The &#8216;=&#8217; sign in the syntax is mandatory, and the variable name you
+supply must follow Python&#8217;s standard conventions for valid names.</p>
+<p>(A special format without variable name exists for internal use)</p>
+<p>Options:</p>
+<blockquote>
+<p>-l: list output. Split the output on newlines into a list before
+assigning it to the given variable. By default the output is stored
+as a single string.</p>
+<p>-v: verbose. Print the contents of the variable.</p>
+</blockquote>
+<p>In most cases you should not need to split as a list, because the
+returned value is a special type of string which can automatically
+provide its contents either as a list (split on newlines) or as a
+space-separated string. These are convenient, respectively, either
+for sequential processing or to be passed to a shell command.</p>
+<p>For example:</p>
+<p># all-random</p>
+<blockquote>
+<p># Capture into variable a
+In [1]: sc a=ls <a href="#id2"><span class="problematic" id="id3">*</span></a>py</p>
+<p># a is a string with embedded newlines
+In [2]: a
+Out[2]: &#8216;setup.pynwin32_manual_post_install.py&#8217;</p>
+<p># which can be seen as a list:
+In [3]: a.l
+Out[3]: [&#8216;setup.py&#8217;, &#8216;win32_manual_post_install.py&#8217;]</p>
+<p># or as a whitespace-separated string:
+In [4]: a.s
+Out[4]: &#8216;setup.py win32_manual_post_install.py&#8217;</p>
+<p># a.s is useful to pass as a single command line:
+In [5]: !wc -l $a.s</p>
+<blockquote>
+146 setup.py
+130 win32_manual_post_install.py
+276 total</blockquote>
+<p># while the list form is useful to loop over:
+In [6]: for f in a.l:</p>
+<blockquote>
+...: !wc -l $f
+...:</blockquote>
+<p>146 setup.py
+130 win32_manual_post_install.py</p>
+</blockquote>
+<p>Similiarly, the lists returned by the -l option are also special, in
+the sense that you can equally invoke the .s attribute on them to
+automatically get a whitespace-separated string from their contents:</p>
+<blockquote>
+<p>In [7]: sc -l b=ls <a href="#id4"><span class="problematic" id="id5">*</span></a>py</p>
+<p>In [8]: b
+Out[8]: [&#8216;setup.py&#8217;, &#8216;win32_manual_post_install.py&#8217;]</p>
+<p>In [9]: b.s
+Out[9]: &#8216;setup.py win32_manual_post_install.py&#8217;</p>
+</blockquote>
+<p>In summary, both the lists and strings used for ouptut capture have
+the following special attributes:</p>
+<blockquote>
+.l (or .list) : value as list.
+.n (or .nlstr): value as newline-separated string.
+.s (or .spstr): value as space-separated string.</blockquote>
+</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_sx">
+<!--[IPython.Magic.Magic.magic_sx]--><tt class="descname">magic_sx</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_sx" title="Permalink to this definition">¶</a></dt>
+<dd><p>Shell execute - run a shell command and capture its output.</p>
+<p>%sx command</p>
+<p>IPython will run the given command using commands.getoutput(), and
+return the result formatted as a list (split on &#8216;n&#8217;). Since the
+output is _returned_, it will be stored in ipython&#8217;s regular output
+cache Out[N] and in the &#8216;_N&#8217; automatic variables.</p>
+<p>Notes:</p>
+<p>1) If an input line begins with &#8216;!!&#8217;, then %sx is automatically
+invoked. That is, while:</p>
+<blockquote>
+!ls</blockquote>
+<dl class="docutils">
+<dt>causes ipython to simply issue system(&#8216;ls&#8217;), typing</dt>
+<dd>!!ls</dd>
+<dt>is a shorthand equivalent to:</dt>
+<dd>%sx ls</dd>
+</dl>
+<p>2) %sx differs from %sc in that %sx automatically splits into a list,
+like &#8216;%sc -l&#8217;. The reason for this is to make it as easy as possible
+to process line-oriented shell output via further python commands.
+%sc is meant to provide much finer control, but requires more
+typing.</p>
+<ol class="arabic simple" start="3">
+<li>Just like %sc -l, this is a list with special attributes:</li>
+</ol>
+<blockquote>
+.l (or .list) : value as list.
+.n (or .nlstr): value as newline-separated string.
+.s (or .spstr): value as whitespace-separated string.</blockquote>
+<p>This is very useful when trying to use such lists as arguments to
+system commands.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_system_verbose">
+<!--[IPython.Magic.Magic.magic_system_verbose]--><tt class="descname">magic_system_verbose</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_system_verbose" title="Permalink to this definition">¶</a></dt>
+<dd><p>Set verbose printing of system calls.</p>
+<p>If called without an argument, act as a toggle</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_time">
+<!--[IPython.Magic.Magic.magic_time]--><tt class="descname">magic_time</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_time" title="Permalink to this definition">¶</a></dt>
+<dd><p>Time execution of a Python statement or expression.</p>
+<p>The CPU and wall clock times are printed, and the value of the
+expression (if any) is returned. Note that under Win32, system time
+is always reported as 0, since it can not be measured.</p>
+<p>This function provides very basic timing functionality. In Python
+2.3, the timeit module offers more control and sophistication, so this
+could be rewritten to use it (patches welcome).</p>
+<p>Some examples:</p>
+<blockquote>
+<p>In [1]: time 2**128
+CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
+Wall time: 0.00
+Out[1]: 340282366920938463463374607431768211456L</p>
+<p>In [2]: n = 1000000</p>
+<p>In [3]: time sum(range(n))
+CPU times: user 1.20 s, sys: 0.05 s, total: 1.25 s
+Wall time: 1.37
+Out[3]: 499999500000L</p>
+<p>In [4]: time print &#8216;hello world&#8217;
+hello world
+CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
+Wall time: 0.00</p>
+<p>Note that the time needed by Python to compile the given expression
+will be reported if it is more than 0.1s. In this example, the
+actual exponentiation is done by Python at compilation time, so while
+the expression can take a noticeable amount of time to compute, that
+time is purely due to the compilation:</p>
+<p>In [5]: time 3**9999;
+CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
+Wall time: 0.00 s</p>
+<p>In [6]: time 3**999999;
+CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
+Wall time: 0.00 s
+Compiler : 0.78 s</p>
+</blockquote>
+</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_timeit">
+<!--[IPython.Magic.Magic.magic_timeit]--><tt class="descname">magic_timeit</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_timeit" title="Permalink to this definition">¶</a></dt>
+<dd><p>Time execution of a Python statement or expression</p>
+<dl class="docutils">
+<dt>Usage:</dt>
+<dd>%timeit [-n&lt;N&gt; -r&lt;R&gt; [-t|-c]] statement</dd>
+</dl>
+<p>Time execution of a Python statement or expression using the timeit
+module.</p>
+<p>Options:
+-n&lt;N&gt;: execute the given statement &lt;N&gt; times in a loop. If this value
+is not given, a fitting value is chosen.</p>
+<p>-r&lt;R&gt;: repeat the loop iteration &lt;R&gt; times and take the best result.
+Default: 3</p>
+<p>-t: use time.time to measure the time, which is the default on Unix.
+This function measures wall time.</p>
+<p>-c: use time.clock to measure the time, which is the default on
+Windows and measures wall time. On Unix, resource.getrusage is used
+instead and returns the CPU user time.</p>
+<p>-p&lt;P&gt;: use a precision of &lt;P&gt; digits to display the timing result.
+Default: 3</p>
+<p>Examples:</p>
+<blockquote>
+<p>In [1]: %timeit pass
+10000000 loops, best of 3: 53.3 ns per loop</p>
+<p>In [2]: u = None</p>
+<p>In [3]: %timeit u is None
+10000000 loops, best of 3: 184 ns per loop</p>
+<p>In [4]: %timeit -r 4 u == None
+1000000 loops, best of 4: 242 ns per loop</p>
+<p>In [5]: import time</p>
+<p>In [6]: %timeit -n1 time.sleep(2)
+1 loops, best of 3: 2 s per loop</p>
+</blockquote>
+<p>The times reported by %timeit will be slightly higher than those
+reported by the timeit.py script when variables are accessed. This is
+due to the fact that %timeit executes the statement in the namespace
+of the shell, compared with timeit.py, which uses a single setup
+statement to import function or create variables. Generally, the bias
+does not matter as long as results from timeit.py are not mixed with
+those from %timeit.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_unalias">
+<!--[IPython.Magic.Magic.magic_unalias]--><tt class="descname">magic_unalias</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_unalias" title="Permalink to this definition">¶</a></dt>
+<dd>Remove an alias</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_upgrade">
+<!--[IPython.Magic.Magic.magic_upgrade]--><tt class="descname">magic_upgrade</tt><big>(</big><em>arg</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_upgrade" title="Permalink to this definition">¶</a></dt>
+<dd><p>Upgrade your IPython installation</p>
+<p>This will copy the config files that don&#8217;t yet exist in your
+ipython dir from the system config dir. Use this after upgrading
+IPython if you don&#8217;t wish to delete your .ipython dir.</p>
+<p>Call with -nolegacy to get rid of ipythonrc* files (recommended for
+new users)</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_who">
+<!--[IPython.Magic.Magic.magic_who]--><tt class="descname">magic_who</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_who" title="Permalink to this definition">¶</a></dt>
+<dd><p>Print all interactive variables, with some minimal formatting.</p>
+<p>If any arguments are given, only variables whose type matches one of
+these are printed. For example:</p>
+<blockquote>
+%who function str</blockquote>
+<p>will only list functions and strings, excluding all other types of
+variables. To find the proper type names, simply use type(var) at a
+command line to see how python prints type names. For example:</p>
+<blockquote>
+In [1]: type(&#8216;hello&#8217;)Out[1]: &lt;type &#8216;str&#8217;&gt;</blockquote>
+<p>indicates that the type name for strings is &#8216;str&#8217;.</p>
+<p>%who always excludes executed names loaded through your configuration
+file and things which are internal to IPython.</p>
+<p>This is deliberate, as typically you may load many modules and the
+purpose of %who is to show you only what you&#8217;ve manually defined.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_who_ls">
+<!--[IPython.Magic.Magic.magic_who_ls]--><tt class="descname">magic_who_ls</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_who_ls" title="Permalink to this definition">¶</a></dt>
+<dd><p>Return a sorted list of all interactive variables.</p>
+<p>If arguments are given, only variables of types matching these
+arguments are returned.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_whos">
+<!--[IPython.Magic.Magic.magic_whos]--><tt class="descname">magic_whos</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_whos" title="Permalink to this definition">¶</a></dt>
+<dd><p>Like %who, but gives some extra information about each variable.</p>
+<p>The same type filtering of %who can be applied here.</p>
+<p>For all variables, the type is printed. Additionally it prints:</p>
+<blockquote>
+<ul class="simple">
+<li>For {},[],(): their length.</li>
+<li>For numpy and Numeric arrays, a summary with shape, number of</li>
+</ul>
+<p>elements, typecode and size in memory.</p>
+<ul class="simple">
+<li>Everything else: a string representation, snipping their middle if</li>
+</ul>
+<p>too long.</p>
+</blockquote>
+</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.magic_xmode">
+<!--[IPython.Magic.Magic.magic_xmode]--><tt class="descname">magic_xmode</tt><big>(</big><em>parameter_s=''</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.magic_xmode" title="Permalink to this definition">¶</a></dt>
+<dd><p>Switch modes for the exception handlers.</p>
+<p>Valid modes: Plain, Context and Verbose.</p>
+<p>If called without arguments, acts as a toggle.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.parse_options">
+<!--[IPython.Magic.Magic.parse_options]--><tt class="descname">parse_options</tt><big>(</big><em>arg_str</em>, <em>opt_str</em>, <em>*long_opts</em>, <em>**kw</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.parse_options" title="Permalink to this definition">¶</a></dt>
+<dd><p>Parse options passed to an argument string.</p>
+<p>The interface is similar to that of getopt(), but it returns back a
+Struct with the options as keys and the stripped argument string still
+as a string.</p>
+<p>arg_str is quoted as a true sys.argv vector by using shlex.split.
+This allows us to easily expand variables, glob files, quote
+arguments, etc.</p>
+<dl class="docutils">
+<dt>Options:</dt>
+<dd><p class="first">-mode: default &#8216;string&#8217;. If given as &#8216;list&#8217;, the argument string is
+returned as a list (split on whitespace) instead of a string.</p>
+<p>-list_all: put all option values in lists. Normally only options
+appearing more than once are put in a list.</p>
+<p class="last">-posix (True): whether to split the input line in POSIX mode or not,
+as per the conventions outlined in the shlex module from the
+standard library.</p>
+</dd>
+</dl>
+</dd></dl>
+
+<dl class="method">
+<dt id="IPython.Magic.Magic.profile_missing_notice">
+<!--[IPython.Magic.Magic.profile_missing_notice]--><tt class="descname">profile_missing_notice</tt><big>(</big><em>*args</em>, <em>**kwargs</em><big>)</big><a class="headerlink" href="#IPython.Magic.Magic.profile_missing_notice" title="Permalink to this definition">¶</a></dt>
+<dd></dd></dl>
+
+</dd></dl>
+
+</div>
+</div>
+<div class="section" id="functions">
+<h2>Functions<a class="headerlink" href="#functions" title="Permalink to this headline">¶</a></h2>
+<dl class="function">
+<dt id="IPython.Magic.compress_dhist">
+<!--[IPython.Magic.compress_dhist]--><tt class="descclassname">IPython.Magic.</tt><tt class="descname">compress_dhist</tt><big>(</big><em>dh</em><big>)</big><a class="headerlink" href="#IPython.Magic.compress_dhist" title="Permalink to this definition">¶</a></dt>
+<dd></dd></dl>
+
+<dl class="function">
+<dt id="IPython.Magic.on_off">
+<!--[IPython.Magic.on_off]--><tt class="descclassname">IPython.Magic.</tt><tt class="descname">on_off</tt><big>(</big><em>tag</em><big>)</big><a class="headerlink" href="#IPython.Magic.on_off" title="Permalink to this definition">¶</a></dt>
+<dd>Return an ON/OFF string for a 1/0 input. Simple utility function.</dd></dl>
+
+</div>
+</div>
+
+
+ </div>
+ </div>
+ </div>
+ <div class="sphinxsidebar">
+ <div class="sphinxsidebarwrapper">
+ <h3><a href="../../index.html">Table Of Contents</a></h3>
+ <ul>
+<li><a class="reference external" href="">Magic</a><ul>
+<li><a class="reference external" href="#module-IPython.Magic">Module: <tt class="docutils literal"><span class="pre">Magic</span></tt></a></li>
+<li><a class="reference external" href="#classes">Classes</a><ul>
+<li><a class="reference external" href="#bunch"><tt class="docutils literal"><span class="pre">Bunch</span></tt></a></li>
+<li><a class="reference external" href="#id1"><tt class="docutils literal"><span class="pre">Magic</span></tt></a></li>
+</ul>
+</li>
+<li><a class="reference external" href="#functions">Functions</a></li>
+</ul>
+</li>
+</ul>
+
+ <h4>Previous topic</h4>
+ <p class="topless"><a href="IPython.Logger.html" title="previous chapter">Logger</a></p>
+ <h4>Next topic</h4>
+ <p class="topless"><a href="IPython.OInspect.html" title="next chapter">OInspect</a></p>
+ <h3>This Page</h3>
+ <ul class="this-page-menu">
+ <li><a href="../../_sources/api/generated/IPython.Magic.txt">Show Source</a></li>
+ </ul>
+ <h3>Quick search</h3>
+ <form class="search" action="../../search.html" method="get">
+ <input type="text" name="q" size="18" /> <input type="submit" value="Go" />
+ <input type="hidden" name="check_keywords" value="yes" />
+ <input type="hidden" name="area" value="default" />
+ </form>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../../modindex.html" title="Global Module Index"
+ accesskey="M">modules</a> |</li>
+ <li class="right" >
+ <a href="IPython.OInspect.html" title="OInspect"
+ accesskey="N">next</a> |</li>
+ <li class="right" >
+ <a href="IPython.Logger.html" title="Logger"
+ accesskey="P">previous</a> |</li>
+ <li><a href="../../index.html">IPython v0.10 documentation</a> &raquo;</li>
+ <li><a href="../index.html" accesskey="U">The IPython API</a> &raquo;</li>
+ </ul>
+ </div>
+ <div class="footer">
+ &copy; Copyright 2008, The IPython Development Team.
+ Last updated on Aug 04, 2009.
+ Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 0.5.2.
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/ipythonbook/doc/rel-0.10/html/config/customization.html b/help/ipythonbook/doc/rel-0.10/html/config/customization.html
new file mode 100644
index 0000000..473cb91
--- /dev/null
+++ b/help/ipythonbook/doc/rel-0.10/html/config/customization.html
@@ -0,0 +1,375 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+ <title>Customization of IPython &mdash; IPython v0.10 documentation</title>
+ <link rel="stylesheet" href="../_static/default.css" type="text/css" />
+ <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
+ <script type="text/javascript">
+ var DOCUMENTATION_OPTIONS = {
+ URL_ROOT: '../',
+ VERSION: '0.10',
+ COLLAPSE_MODINDEX: false,
+ FILE_SUFFIX: '.html',
+ HAS_SOURCE: true
+ };
+ </script>
+ <script type="text/javascript" src="../_static/jquery.js"></script>
+ <script type="text/javascript" src="../_static/doctools.js"></script>
+ <link rel="top" title="IPython v0.10 documentation" href="../index.html" />
+ <link rel="up" title="Configuration and customization" href="index.html" />
+ <link rel="next" title="New configuration system" href="new_config.html" />
+ <link rel="prev" title="Initial configuration of your environment" href="initial_config.html" />
+ </head>
+ <body>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../modindex.html" title="Global Module Index"
+ accesskey="M">modules</a> |</li>
+ <li class="right" >
+ <a href="new_config.html" title="New configuration system"
+ accesskey="N">next</a> |</li>
+ <li class="right" >
+ <a href="initial_config.html" title="Initial configuration of your environment"
+ accesskey="P">previous</a> |</li>
+ <li><a href="../index.html">IPython v0.10 documentation</a> &raquo;</li>
+ <li><a href="index.html" accesskey="U">Configuration and customization</a> &raquo;</li>
+ </ul>
+ </div>
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body">
+
+
+ <div class="section" id="customization-of-ipython">
+<span id="customization"></span><h1>Customization of IPython<a class="headerlink" href="#customization-of-ipython" title="Permalink to this headline">¶</a></h1>
+<p>There are 2 ways to configure IPython - the old way of using ipythonrc
+files (an INI-file like format), and the new way that involves editing
+your ipy_user_conf.py. Both configuration systems work at the same
+time, so you can set your options in both, but if you are hesitating
+about which alternative to choose, we recommend the ipy_user_conf.py
+approach, as it will give you more power and control in the long
+run. However, there are few options such as pylab_import_all that can
+only be specified in ipythonrc file or command line - the reason for
+this is that they are needed before IPython has been started up, and
+the IPApi object used in ipy_user_conf.py is not yet available at that
+time. A hybrid approach of specifying a few options in ipythonrc and
+doing the more advanced configuration in ipy_user_conf.py is also
+possible.</p>
+<div class="section" id="the-ipythonrc-approach">
+<span id="ipythonrc"></span><h2>The ipythonrc approach<a class="headerlink" href="#the-ipythonrc-approach" title="Permalink to this headline">¶</a></h2>
+<p>As we&#8217;ve already mentioned, IPython reads a configuration file which can
+be specified at the command line (-rcfile) or which by default is
+assumed to be called ipythonrc. Such a file is looked for in the current
+directory where IPython is started and then in your IPYTHONDIR, which
+allows you to have local configuration files for specific projects. In
+this section we will call these types of configuration files simply
+rcfiles (short for resource configuration file).</p>
+<p>The syntax of an rcfile is one of key-value pairs separated by
+whitespace, one per line. Lines beginning with a # are ignored as
+comments, but comments can not be put on lines with data (the parser is
+fairly primitive). Note that these are not python files, and this is
+deliberate, because it allows us to do some things which would be quite
+tricky to implement if they were normal python files.</p>
+<p>First, an rcfile can contain permanent default values for almost all command
+line options (except things like -help or -Version). <a class="reference external" href="../interactive/reference.html#command-line-options"><em>This section</em></a> contains a description of all command-line
+options. However, values you explicitly specify at the command line override
+the values defined in the rcfile.</p>
+<p>Besides command line option values, the rcfile can specify values for
+certain extra special options which are not available at the command
+line. These options are briefly described below.</p>
+<p>Each of these options may appear as many times as you need it in the file.</p>
+<blockquote>
+<ul class="simple">
+<li>include &lt;file1&gt; &lt;file2&gt; ...: you can name other rcfiles you want
+to recursively load up to 15 levels (don&#8217;t use the &lt;&gt; brackets in
+your names!). This feature allows you to define a &#8216;base&#8217; rcfile
+with general options and special-purpose files which can be loaded
+only when needed with particular configuration options. To make
+this more convenient, IPython accepts the -profile &lt;name&gt; option
+(abbreviates to -p &lt;name&gt;) which tells it to look for an rcfile
+named ipythonrc-&lt;name&gt;.</li>
+<li>import_mod &lt;mod1&gt; &lt;mod2&gt; ...: import modules with &#8216;import
+&lt;mod1&gt;,&lt;mod2&gt;,...&#8217;</li>
+<li>import_some &lt;mod&gt; &lt;f1&gt; &lt;f2&gt; ...: import functions with &#8216;from
+&lt;mod&gt; import &lt;f1&gt;,&lt;f2&gt;,...&#8217;</li>
+<li>import_all &lt;mod1&gt; &lt;mod2&gt; ...: for each module listed import
+functions with <tt class="docutils literal"><span class="pre">from</span> <span class="pre">&lt;mod&gt;</span> <span class="pre">import</span> <span class="pre">*</span></tt>.</li>
+<li>execute &lt;python code&gt;: give any single-line python code to be
+executed.</li>
+<li>execfile &lt;filename&gt;: execute the python file given with an
+&#8216;execfile(filename)&#8217; command. Username expansion is performed on
+the given names. So if you need any amount of extra fancy
+customization that won&#8217;t fit in any of the above &#8216;canned&#8217; options,
+you can just put it in a separate python file and execute it.</li>
+<li>alias &lt;alias_def&gt;: this is equivalent to calling
+&#8216;%alias &lt;alias_def&gt;&#8217; at the IPython command line. This way, from
+within IPython you can do common system tasks without having to
+exit it or use the ! escape. IPython isn&#8217;t meant to be a shell
+replacement, but it is often very useful to be able to do things
+with files while testing code. This gives you the flexibility to
+have within IPython any aliases you may be used to under your
+normal system shell.</li>
+</ul>
+</blockquote>
+</div>
+<div class="section" id="ipy-user-conf-py">
+<h2>ipy_user_conf.py<a class="headerlink" href="#ipy-user-conf-py" title="Permalink to this headline">¶</a></h2>
+<p>There should be a simple template ipy_user_conf.py file in your
+~/.ipython directory. It is a plain python module that is imported
+during IPython startup, so you can do pretty much what you want there
+- import modules, configure extensions, change options, define magic
+commands, put variables and functions in the IPython namespace,
+etc. You use the IPython extension api object, acquired by
+IPython.ipapi.get() and documented in the &#8220;IPython extension API&#8221;
+chapter, to interact with IPython. A sample ipy_user_conf.py is listed
+below for reference:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="c"># Most of your config files and extensions will probably start</span>
+<span class="c"># with this import</span>
+
+<span class="k">import</span> <span class="nn">IPython.ipapi</span>
+<span class="n">ip</span> <span class="o">=</span> <span class="n">IPython</span><span class="o">.</span><span class="n">ipapi</span><span class="o">.</span><span class="n">get</span><span class="p">()</span>
+
+<span class="c"># You probably want to uncomment this if you did %upgrade -nolegacy</span>
+<span class="c"># import ipy_defaults</span>
+
+<span class="k">import</span> <span class="nn">os</span>
+
+<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
+
+ <span class="c">#ip.dbg.debugmode = True</span>
+ <span class="n">ip</span><span class="o">.</span><span class="n">dbg</span><span class="o">.</span><span class="n">debug_stack</span><span class="p">()</span>
+
+ <span class="c"># uncomment if you want to get ipython -p sh behaviour</span>
+ <span class="c"># without having to use command line switches</span>
+ <span class="k">import</span> <span class="nn">ipy_profile_sh</span>
+ <span class="k">import</span> <span class="nn">jobctrl</span>
+
+ <span class="c"># Configure your favourite editor?</span>
+ <span class="c"># Good idea e.g. for %edit os.path.isfile</span>
+
+ <span class="c">#import ipy_editors</span>
+
+ <span class="c"># Choose one of these:</span>
+
+ <span class="c">#ipy_editors.scite()</span>
+ <span class="c">#ipy_editors.scite(&#39;c:/opt/scite/scite.exe&#39;)</span>
+ <span class="c">#ipy_editors.komodo()</span>
+ <span class="c">#ipy_editors.idle()</span>
+ <span class="c"># ... or many others, try &#39;ipy_editors??&#39; after import to see them</span>
+
+ <span class="c"># Or roll your own:</span>
+ <span class="c">#ipy_editors.install_editor(&quot;c:/opt/jed +$line $file&quot;)</span>
+
+
+ <span class="n">o</span> <span class="o">=</span> <span class="n">ip</span><span class="o">.</span><span class="n">options</span>
+ <span class="c"># An example on how to set options</span>
+ <span class="c">#o.autocall = 1</span>
+ <span class="n">o</span><span class="o">.</span><span class="n">system_verbose</span> <span class="o">=</span> <span class="mf">0</span>
+
+ <span class="c">#import_all(&quot;os sys&quot;)</span>
+ <span class="c">#execf(&#39;~/_ipython/ns.py&#39;)</span>
+
+
+ <span class="c"># -- prompt</span>
+ <span class="c"># A different, more compact set of prompts from the default ones, that</span>
+ <span class="c"># always show your current location in the filesystem:</span>
+
+ <span class="c">#o.prompt_in1 = r&#39;\C_LightBlue[\C_LightCyan\Y2\C_LightBlue]\C_Normal\n\C_Green|\#&gt;&#39;</span>
+ <span class="c">#o.prompt_in2 = r&#39;.\D: &#39;</span>
+ <span class="c">#o.prompt_out = r&#39;[\#] &#39;</span>
+
+ <span class="c"># Try one of these color settings if you can&#39;t read the text easily</span>
+ <span class="c"># autoexec is a list of IPython commands to execute on startup</span>
+ <span class="c">#o.autoexec.append(&#39;%colors LightBG&#39;)</span>
+ <span class="c">#o.autoexec.append(&#39;%colors NoColor&#39;)</span>
+ <span class="n">o</span><span class="o">.</span><span class="n">autoexec</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s">&#39;</span><span class="si">%c</span><span class="s">olors Linux&#39;</span><span class="p">)</span>
+
+
+<span class="c"># some config helper functions you can use</span>
+<span class="k">def</span> <span class="nf">import_all</span><span class="p">(</span><span class="n">modules</span><span class="p">):</span>
+ <span class="sd">&quot;&quot;&quot; Usage: import_all(&quot;os sys&quot;) &quot;&quot;&quot;</span>
+ <span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="n">modules</span><span class="o">.</span><span class="n">split</span><span class="p">():</span>
+ <span class="n">ip</span><span class="o">.</span><span class="n">ex</span><span class="p">(</span><span class="s">&quot;from </span><span class="si">%s</span><span class="s"> import *&quot;</span> <span class="o">%</span> <span class="n">m</span><span class="p">)</span>
+
+<span class="k">def</span> <span class="nf">execf</span><span class="p">(</span><span class="n">fname</span><span class="p">):</span>
+ <span class="sd">&quot;&quot;&quot; Execute a file in user namespace &quot;&quot;&quot;</span>
+ <span class="n">ip</span><span class="o">.</span><span class="n">ex</span><span class="p">(</span><span class="s">&#39;execfile(&quot;</span><span class="si">%s</span><span class="s">&quot;)&#39;</span> <span class="o">%</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">expanduser</span><span class="p">(</span><span class="n">fname</span><span class="p">))</span>
+
+<span class="n">main</span><span class="p">()</span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="fine-tuning-your-prompt">
+<span id="prompts"></span><h2>Fine-tuning your prompt<a class="headerlink" href="#fine-tuning-your-prompt" title="Permalink to this headline">¶</a></h2>
+<p>IPython&#8217;s prompts can be customized using a syntax similar to that of
+the bash shell. Many of bash&#8217;s escapes are supported, as well as a few
+additional ones. We list them below:</p>
+<div class="highlight-python"><pre>\#
+ the prompt/history count number. This escape is automatically
+ wrapped in the coloring codes for the currently active color scheme.
+\N
+ the 'naked' prompt/history count number: this is just the number
+ itself, without any coloring applied to it. This lets you produce
+ numbered prompts with your own colors.
+\D
+ the prompt/history count, with the actual digits replaced by dots.
+ Used mainly in continuation prompts (prompt_in2)
+\w
+ the current working directory
+\W
+ the basename of current working directory
+\Xn
+ where $n=0\ldots5.$ The current working directory, with $HOME
+ replaced by ~, and filtered out to contain only $n$ path elements
+\Yn
+ Similar to \Xn, but with the $n+1$ element included if it is ~ (this
+ is similar to the behavior of the %cn escapes in tcsh)
+\u
+ the username of the current user
+\$
+ if the effective UID is 0, a #, otherwise a $
+\h
+ the hostname up to the first '.'
+\H
+ the hostname
+\n
+ a newline
+\r
+ a carriage return
+\v
+ IPython version string</pre>
+</div>
+<p>In addition to these, ANSI color escapes can be insterted into the
+prompts, as C_ColorName. The list of valid color names is: Black, Blue,
+Brown, Cyan, DarkGray, Green, LightBlue, LightCyan, LightGray,
+LightGreen, LightPurple, LightRed, NoColor, Normal, Purple, Red, White,
+Yellow.</p>
+<p>Finally, IPython supports the evaluation of arbitrary expressions in
+your prompt string. The prompt strings are evaluated through the syntax
+of PEP 215, but basically you can use $x.y to expand the value of x.y,
+and for more complicated expressions you can use braces: ${foo()+x} will
+call function foo and add to it the value of x, before putting the
+result into your prompt. For example, using
+prompt_in1 &#8216;${commands.getoutput(&#8220;uptime&#8221;)}nIn [#]: &#8216;
+will print the result of the uptime command on each prompt (assuming the
+commands module has been imported in your ipythonrc file).</p>
+<blockquote>
+Prompt examples</blockquote>
+<p>The following options in an ipythonrc file will give you IPython&#8217;s
+default prompts:</p>
+<div class="highlight-python"><pre>prompt_in1 'In [\#]:'
+prompt_in2 ' .\D.:'
+prompt_out 'Out[\#]:'</pre>
+</div>
+<p>which look like this:</p>
+<div class="highlight-python"><pre>In [1]: 1+2
+Out[1]: 3
+
+In [2]: for i in (1,2,3):
+ ...: print i,
+ ...:
+1 2 3</pre>
+</div>
+<p>These will give you a very colorful prompt with path information:</p>
+<div class="highlight-python"><pre>#prompt_in1 '\C_Red\u\C_Blue[\C_Cyan\Y1\C_Blue]\C_LightGreen\#&gt;'
+prompt_in2 ' ..\D&gt;'
+prompt_out '&lt;\#&gt;'</pre>
+</div>
+<p>which look like this:</p>
+<div class="highlight-python"><pre>fperez[~/ipython]1&gt; 1+2
+ &lt;1&gt; 3
+fperez[~/ipython]2&gt; for i in (1,2,3):
+ ...&gt; print i,
+ ...&gt;
+1 2 3</pre>
+</div>
+</div>
+<div class="section" id="ipython-profiles">
+<span id="profiles"></span><h2>IPython profiles<a class="headerlink" href="#ipython-profiles" title="Permalink to this headline">¶</a></h2>
+<p>As we already mentioned, IPython supports the -profile command-line option (see
+<a class="reference external" href="../interactive/reference.html#command-line-options"><em>here</em></a>). A profile is nothing more than a
+particular configuration file like your basic ipythonrc one, but with
+particular customizations for a specific purpose. When you start IPython with
+&#8216;ipython -profile &lt;name&gt;&#8217;, it assumes that in your IPYTHONDIR there is a file
+called ipythonrc-&lt;name&gt; or ipy_profile_&lt;name&gt;.py, and loads it instead of the
+normal ipythonrc.</p>
+<p>This system allows you to maintain multiple configurations which load
+modules, set options, define functions, etc. suitable for different
+tasks and activate them in a very simple manner. In order to avoid
+having to repeat all of your basic options (common things that don&#8217;t
+change such as your color preferences, for example), any profile can
+include another configuration file. The most common way to use profiles
+is then to have each one include your basic ipythonrc file as a starting
+point, and then add further customizations.</p>
+</div>
+</div>
+
+
+ </div>
+ </div>
+ </div>
+ <div class="sphinxsidebar">
+ <div class="sphinxsidebarwrapper">
+ <h3><a href="../index.html">Table Of Contents</a></h3>
+ <ul>
+<li><a class="reference external" href="">Customization of IPython</a><ul>
+<li><a class="reference external" href="#the-ipythonrc-approach">The ipythonrc approach</a></li>
+<li><a class="reference external" href="#ipy-user-conf-py">ipy_user_conf.py</a></li>
+<li><a class="reference external" href="#fine-tuning-your-prompt">Fine-tuning your prompt</a></li>
+<li><a class="reference external" href="#ipython-profiles">IPython profiles</a></li>
+</ul>
+</li>
+</ul>
+
+ <h4>Previous topic</h4>
+ <p class="topless"><a href="initial_config.html" title="previous chapter">Initial configuration of your environment</a></p>
+ <h4>Next topic</h4>
+ <p class="topless"><a href="new_config.html" title="next chapter">New configuration system</a></p>
+ <h3>This Page</h3>
+ <ul class="this-page-menu">
+ <li><a href="../_sources/config/customization.txt">Show Source</a></li>
+ </ul>
+ <h3>Quick search</h3>
+ <form class="search" action="../search.html" method="get">
+ <input type="text" name="q" size="18" /> <input type="submit" value="Go" />
+ <input type="hidden" name="check_keywords" value="yes" />
+ <input type="hidden" name="area" value="default" />
+ </form>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../modindex.html" title="Global Module Index"
+ accesskey="M">modules</a> |</li>
+ <li class="right" >
+ <a href="new_config.html" title="New configuration system"
+ accesskey="N">next</a> |</li>
+ <li class="right" >
+ <a href="initial_config.html" title="Initial configuration of your environment"
+ accesskey="P">previous</a> |</li>
+ <li><a href="../index.html">IPython v0.10 documentation</a> &raquo;</li>
+ <li><a href="index.html" accesskey="U">Configuration and customization</a> &raquo;</li>
+ </ul>
+ </div>
+ <div class="footer">
+ &copy; Copyright 2008, The IPython Development Team.
+ Last updated on Aug 04, 2009.
+ Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 0.5.2.
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/ipythonbook/doc/rel-0.10/html/config/initial_config.html b/help/ipythonbook/doc/rel-0.10/html/config/initial_config.html
new file mode 100644
index 0000000..6c25934
--- /dev/null
+++ b/help/ipythonbook/doc/rel-0.10/html/config/initial_config.html
@@ -0,0 +1,332 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+ <title>Initial configuration of your environment &mdash; IPython v0.10 documentation</title>
+ <link rel="stylesheet" href="../_static/default.css" type="text/css" />
+ <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
+ <script type="text/javascript">
+ var DOCUMENTATION_OPTIONS = {
+ URL_ROOT: '../',
+ VERSION: '0.10',
+ COLLAPSE_MODINDEX: false,
+ FILE_SUFFIX: '.html',
+ HAS_SOURCE: true
+ };
+ </script>
+ <script type="text/javascript" src="../_static/jquery.js"></script>
+ <script type="text/javascript" src="../_static/doctools.js"></script>
+ <link rel="top" title="IPython v0.10 documentation" href="../index.html" />
+ <link rel="up" title="Configuration and customization" href="index.html" />
+ <link rel="next" title="Customization of IPython" href="customization.html" />
+ <link rel="prev" title="Configuration and customization" href="index.html" />
+ </head>
+ <body>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../modindex.html" title="Global Module Index"
+ accesskey="M">modules</a> |</li>
+ <li class="right" >
+ <a href="customization.html" title="Customization of IPython"
+ accesskey="N">next</a> |</li>
+ <li class="right" >
+ <a href="index.html" title="Configuration and customization"
+ accesskey="P">previous</a> |</li>
+ <li><a href="../index.html">IPython v0.10 documentation</a> &raquo;</li>
+ <li><a href="index.html" accesskey="U">Configuration and customization</a> &raquo;</li>
+ </ul>
+ </div>
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body">
+
+
+ <div class="section" id="initial-configuration-of-your-environment">
+<span id="initial-config"></span><h1>Initial configuration of your environment<a class="headerlink" href="#initial-configuration-of-your-environment" title="Permalink to this headline">¶</a></h1>
+<p>This section will help you set various things in your environment for
+your IPython sessions to be as efficient as possible. All of IPython&#8217;s
+configuration information, along with several example files, is stored
+in a directory named by default $HOME/.ipython. You can change this by
+defining the environment variable IPYTHONDIR, or at runtime with the
+command line option -ipythondir.</p>
+<p>If all goes well, the first time you run IPython it should automatically create
+a user copy of the config directory for you, based on its builtin defaults. You
+can look at the files it creates to learn more about configuring the
+system. The main file you will modify to configure IPython&#8217;s behavior is called
+ipythonrc (with a .ini extension under Windows), included for reference
+<a class="reference external" href="customization.html#ipythonrc"><em>here</em></a>. This file is very commented and has many variables you
+can change to suit your taste, you can find more details <a class="reference external" href="customization.html#customization"><em>here</em></a>. Here we discuss the basic things you will want to make sure
+things are working properly from the beginning.</p>
+<div class="section" id="access-to-the-python-help-system">
+<span id="accessing-help"></span><h2>Access to the Python help system<a class="headerlink" href="#access-to-the-python-help-system" title="Permalink to this headline">¶</a></h2>
+<p>This is true for Python in general (not just for IPython): you should have an
+environment variable called PYTHONDOCS pointing to the directory where your
+HTML Python documentation lives. In my system it&#8217;s
+<tt class="docutils literal"><span class="pre">/usr/share/doc/python-doc/html</span></tt>, check your local details or ask your
+systems administrator.</p>
+<p>This is the directory which holds the HTML version of the Python
+manuals. Unfortunately it seems that different Linux distributions
+package these files differently, so you may have to look around a bit.
+Below I show the contents of this directory on my system for reference:</p>
+<div class="highlight-python"><pre>[html]&gt; ls
+about.html dist/ icons/ lib/ python2.5.devhelp.gz whatsnew/
+acks.html doc/ index.html mac/ ref/
+api/ ext/ inst/ modindex.html tut/</pre>
+</div>
+<p>You should really make sure this variable is correctly set so that
+Python&#8217;s pydoc-based help system works. It is a powerful and convenient
+system with full access to the Python manuals and all modules accessible
+to you.</p>
+<p>Under Windows it seems that pydoc finds the documentation automatically,
+so no extra setup appears necessary.</p>
+</div>
+<div class="section" id="editor">
+<h2>Editor<a class="headerlink" href="#editor" title="Permalink to this headline">¶</a></h2>
+<p>The %edit command (and its alias %ed) will invoke the editor set in your
+environment as EDITOR. If this variable is not set, it will default to
+vi under Linux/Unix and to notepad under Windows. You may want to set
+this variable properly and to a lightweight editor which doesn&#8217;t take
+too long to start (that is, something other than a new instance of
+Emacs). This way you can edit multi-line code quickly and with the power
+of a real editor right inside IPython.</p>
+<p>If you are a dedicated Emacs user, you should set up the Emacs server so
+that new requests are handled by the original process. This means that
+almost no time is spent in handling the request (assuming an Emacs
+process is already running). For this to work, you need to set your
+EDITOR environment variable to &#8216;emacsclient&#8217;. The code below, supplied
+by Francois Pinard, can then be used in your .emacs file to enable the
+server:</p>
+<div class="highlight-python"><pre>(defvar server-buffer-clients)
+(when (and (fboundp 'server-start) (string-equal (getenv "TERM") 'xterm))
+ (server-start)
+ (defun fp-kill-server-with-buffer-routine ()
+ (and server-buffer-clients (server-done)))
+ (add-hook 'kill-buffer-hook 'fp-kill-server-with-buffer-routine))</pre>
+</div>
+<p>You can also set the value of this editor via the commmand-line option
+&#8216;-editor&#8217; or in your ipythonrc file. This is useful if you wish to use
+specifically for IPython an editor different from your typical default
+(and for Windows users who tend to use fewer environment variables).</p>
+</div>
+<div class="section" id="color">
+<h2>Color<a class="headerlink" href="#color" title="Permalink to this headline">¶</a></h2>
+<p>The default IPython configuration has most bells and whistles turned on
+(they&#8217;re pretty safe). But there&#8217;s one that may cause problems on some
+systems: the use of color on screen for displaying information. This is
+very useful, since IPython can show prompts and exception tracebacks
+with various colors, display syntax-highlighted source code, and in
+general make it easier to visually parse information.</p>
+<p>The following terminals seem to handle the color sequences fine:</p>
+<blockquote>
+<ul class="simple">
+<li>Linux main text console, KDE Konsole, Gnome Terminal, E-term,
+rxvt, xterm.</li>
+<li>CDE terminal (tested under Solaris). This one boldfaces light colors.</li>
+<li>(X)Emacs buffers. See the <a class="reference internal" href="#emacs">emacs</a> section for more details on
+using IPython with (X)Emacs.</li>
+<li>A Windows (XP/2k) command prompt with <a class="reference external" href="https://code.launchpad.net/pyreadline">pyreadline</a>.</li>
+<li>A Windows (XP/2k) CygWin shell. Although some users have reported
+problems; it is not clear whether there is an issue for everyone
+or only under specific configurations. If you have full color
+support under cygwin, please post to the IPython mailing list so
+this issue can be resolved for all users.</li>
+</ul>
+</blockquote>
+<p>These have shown problems:</p>
+<blockquote>
+<ul class="simple">
+<li>Windows command prompt in WinXP/2k logged into a Linux machine via
+telnet or ssh.</li>
+<li>Windows native command prompt in WinXP/2k, without Gary Bishop&#8217;s
+extensions. Once Gary&#8217;s readline library is installed, the normal
+WinXP/2k command prompt works perfectly.</li>
+</ul>
+</blockquote>
+<p>Currently the following color schemes are available:</p>
+<blockquote>
+<ul class="simple">
+<li>NoColor: uses no color escapes at all (all escapes are empty &#8216;&#8217; &#8216;&#8217;
+strings). This &#8216;scheme&#8217; is thus fully safe to use in any terminal.</li>
+<li>Linux: works well in Linux console type environments: dark
+background with light fonts. It uses bright colors for
+information, so it is difficult to read if you have a light
+colored background.</li>
+<li>LightBG: the basic colors are similar to those in the Linux scheme
+but darker. It is easy to read in terminals with light backgrounds.</li>
+</ul>
+</blockquote>
+<p>IPython uses colors for two main groups of things: prompts and
+tracebacks which are directly printed to the terminal, and the object
+introspection system which passes large sets of data through a pager.</p>
+</div>
+<div class="section" id="input-output-prompts-and-exception-tracebacks">
+<h2>Input/Output prompts and exception tracebacks<a class="headerlink" href="#input-output-prompts-and-exception-tracebacks" title="Permalink to this headline">¶</a></h2>
+<p>You can test whether the colored prompts and tracebacks work on your
+system interactively by typing &#8216;%colors Linux&#8217; at the prompt (use
+&#8216;%colors LightBG&#8217; if your terminal has a light background). If the input
+prompt shows garbage like:</p>
+<div class="highlight-python"><pre>[0;32mIn [[1;32m1[0;32m]: [0;00m</pre>
+</div>
+<p>instead of (in color) something like:</p>
+<div class="highlight-python"><pre>In [1]:</pre>
+</div>
+<p>this means that your terminal doesn&#8217;t properly handle color escape
+sequences. You can go to a &#8216;no color&#8217; mode by typing &#8216;%colors NoColor&#8217;.</p>
+<p>You can try using a different terminal emulator program (Emacs users,
+see below). To permanently set your color preferences, edit the file
+$HOME/.ipython/ipythonrc and set the colors option to the desired value.</p>
+</div>
+<div class="section" id="object-details-types-docstrings-source-code-etc">
+<h2>Object details (types, docstrings, source code, etc.)<a class="headerlink" href="#object-details-types-docstrings-source-code-etc" title="Permalink to this headline">¶</a></h2>
+<p>IPython has a set of special functions for studying the objects you are working
+with, discussed in detail <a class="reference external" href="../interactive/reference.html#dynamic-object-info"><em>here</em></a>. But this system
+relies on passing information which is longer than your screen through a data
+pager, such as the common Unix less and more programs. In order to be able to
+see this information in color, your pager needs to be properly configured. I
+strongly recommend using less instead of more, as it seems that more simply can
+not understand colored text correctly.</p>
+<p>In order to configure less as your default pager, do the following:</p>
+<blockquote>
+<ol class="arabic simple">
+<li>Set the environment PAGER variable to less.</li>
+<li>Set the environment LESS variable to -r (plus any other options
+you always want to pass to less by default). This tells less to
+properly interpret control sequences, which is how color
+information is given to your terminal.</li>
+</ol>
+</blockquote>
+<p>For the bash shell, add to your ~/.bashrc file the lines:</p>
+<div class="highlight-python"><pre>export PAGER=less
+export LESS=-r</pre>
+</div>
+<p>For the csh or tcsh shells, add to your ~/.cshrc file the lines:</p>
+<div class="highlight-python"><pre>setenv PAGER less
+setenv LESS -r</pre>
+</div>
+<p>There is similar syntax for other Unix shells, look at your system
+documentation for details.</p>
+<p>If you are on a system which lacks proper data pagers (such as Windows),
+IPython will use a very limited builtin pager.</p>
+</div>
+<div class="section" id="x-emacs-configuration">
+<span id="emacs"></span><h2>(X)Emacs configuration<a class="headerlink" href="#x-emacs-configuration" title="Permalink to this headline">¶</a></h2>
+<p>Thanks to the work of Alexander Schmolck and Prabhu Ramachandran,
+currently (X)Emacs and IPython get along very well.</p>
+<p>Important note: You will need to use a recent enough version of
+python-mode.el, along with the file ipython.el. You can check that the
+version you have of python-mode.el is new enough by either looking at
+the revision number in the file itself, or asking for it in (X)Emacs via
+M-x py-version. Versions 4.68 and newer contain the necessary fixes for
+proper IPython support.</p>
+<p>The file ipython.el is included with the IPython distribution, in the
+documentation directory (where this manual resides in PDF and HTML
+formats).</p>
+<p>Once you put these files in your Emacs path, all you need in your .emacs
+file is:</p>
+<div class="highlight-python"><pre>(require 'ipython)</pre>
+</div>
+<p>This should give you full support for executing code snippets via
+IPython, opening IPython as your Python shell via <tt class="docutils literal"><span class="pre">C-c</span> <span class="pre">!</span></tt>, etc.</p>
+<p>You can customize the arguments passed to the IPython instance at startup by
+setting the <tt class="docutils literal"><span class="pre">py-python-command-args</span></tt> variable. For example, to start always
+in <tt class="docutils literal"><span class="pre">pylab</span></tt> mode with hardcoded light-background colors, you can use:</p>
+<div class="highlight-python"><pre>(setq py-python-command-args '("-pylab" "-colors" "LightBG"))</pre>
+</div>
+<p>If you happen to get garbage instead of colored prompts as described in
+the previous section, you may need to set also in your .emacs file:</p>
+<div class="highlight-python"><pre>(setq ansi-color-for-comint-mode t)</pre>
+</div>
+<p>Notes:</p>
+<blockquote>
+<ul class="simple">
+<li>There is one caveat you should be aware of: you must start the
+IPython shell before attempting to execute any code regions via
+<tt class="docutils literal"><span class="pre">C-c</span> <span class="pre">|</span></tt>. Simply type C-c ! to start IPython before passing any code
+regions to the interpreter, and you shouldn&#8217;t experience any
+problems.
+This is due to a bug in Python itself, which has been fixed for
+Python 2.3, but exists as of Python 2.2.2 (reported as SF bug [
+737947 ]).</li>
+<li>The (X)Emacs support is maintained by Alexander Schmolck, so all
+comments/requests should be directed to him through the IPython
+mailing lists.</li>
+<li>This code is still somewhat experimental so it&#8217;s a bit rough
+around the edges (although in practice, it works quite well).</li>
+<li>Be aware that if you customize py-python-command previously, this
+value will override what ipython.el does (because loading the
+customization variables comes later).</li>
+</ul>
+</blockquote>
+</div>
+</div>
+
+
+ </div>
+ </div>
+ </div>
+ <div class="sphinxsidebar">
+ <div class="sphinxsidebarwrapper">
+ <h3><a href="../index.html">Table Of Contents</a></h3>
+ <ul>
+<li><a class="reference external" href="">Initial configuration of your environment</a><ul>
+<li><a class="reference external" href="#access-to-the-python-help-system">Access to the Python help system</a></li>
+<li><a class="reference external" href="#editor">Editor</a></li>
+<li><a class="reference external" href="#color">Color</a></li>
+<li><a class="reference external" href="#input-output-prompts-and-exception-tracebacks">Input/Output prompts and exception tracebacks</a></li>
+<li><a class="reference external" href="#object-details-types-docstrings-source-code-etc">Object details (types, docstrings, source code, etc.)</a></li>
+<li><a class="reference external" href="#x-emacs-configuration">(X)Emacs configuration</a></li>
+</ul>
+</li>
+</ul>
+
+ <h4>Previous topic</h4>
+ <p class="topless"><a href="index.html" title="previous chapter">Configuration and customization</a></p>
+ <h4>Next topic</h4>
+ <p class="topless"><a href="customization.html" title="next chapter">Customization of IPython</a></p>
+ <h3>This Page</h3>
+ <ul class="this-page-menu">
+ <li><a href="../_sources/config/initial_config.txt">Show Source</a></li>
+ </ul>
+ <h3>Quick search</h3>
+ <form class="search" action="../search.html" method="get">
+ <input type="text" name="q" size="18" /> <input type="submit" value="Go" />
+ <input type="hidden" name="check_keywords" value="yes" />
+ <input type="hidden" name="area" value="default" />
+ </form>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../modindex.html" title="Global Module Index"
+ accesskey="M">modules</a> |</li>
+ <li class="right" >
+ <a href="customization.html" title="Customization of IPython"
+ accesskey="N">next</a> |</li>
+ <li class="right" >
+ <a href="index.html" title="Configuration and customization"
+ accesskey="P">previous</a> |</li>
+ <li><a href="../index.html">IPython v0.10 documentation</a> &raquo;</li>
+ <li><a href="index.html" accesskey="U">Configuration and customization</a> &raquo;</li>
+ </ul>
+ </div>
+ <div class="footer">
+ &copy; Copyright 2008, The IPython Development Team.
+ Last updated on Aug 04, 2009.
+ Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 0.5.2.
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/ipythonbook/doc/rel-0.10/html/genindex.html b/help/ipythonbook/doc/rel-0.10/html/genindex.html
new file mode 100644
index 0000000..b7f4574
--- /dev/null
+++ b/help/ipythonbook/doc/rel-0.10/html/genindex.html
@@ -0,0 +1,3114 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+ <title>Index &mdash; IPython v0.10 documentation</title>
+ <link rel="stylesheet" href="_static/default.css" type="text/css" />
+ <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+ <script type="text/javascript">
+ var DOCUMENTATION_OPTIONS = {
+ URL_ROOT: '',
+ VERSION: '0.10',
+ COLLAPSE_MODINDEX: false,
+ FILE_SUFFIX: '.html',
+ HAS_SOURCE: true
+ };
+ </script>
+ <script type="text/javascript" src="_static/jquery.js"></script>
+ <script type="text/javascript" src="_static/doctools.js"></script>
+ <link rel="top" title="IPython v0.10 documentation" href="index.html" />
+ </head>
+ <body>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="modindex.html" title="Global Module Index"
+ accesskey="M">modules</a> |</li>
+ <li><a href="index.html">IPython v0.10 documentation</a> &raquo;</li>
+ </ul>
+ </div>
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body">
+
+
+ <h1 id="index">Index</h1>
+
+ <a href="#_"><strong>_</strong></a> | <a href="#A"><strong>A</strong></a> | <a href="#B"><strong>B</strong></a> | <a href="#C"><strong>C</strong></a> | <a href="#D"><strong>D</strong></a> | <a href="#E"><strong>E</strong></a> | <a href="#F"><strong>F</strong></a> | <a href="#G"><strong>G</strong></a> | <a href="#H"><strong>H</strong></a> | <a href="#I"><strong>I</strong></a> | <a href="#J"><strong>J</strong></a> | <a href="#K"><strong>K</strong></a> | <a href="#L"><strong>L</strong></a> | <a href="#M"><strong>M</strong></a> | <a href="#N"><strong>N</strong></a> | <a href="#O"><strong>O</strong></a> | <a href="#P"><strong>P</strong></a> | <a href="#Q"><strong>Q</strong></a> | <a href="#R"><strong>R</strong></a> | <a href="#S"><strong>S</strong></a> | <a href="#T"><strong>T</strong></a> | <a href="#U"><strong>U</strong></a> | <a href="#V"><strong>V</strong></a> | <a href="#W"><strong>W</strong></a> | <a href="#X"><strong>X</strong></a> | <a href="#Z"><strong>Z</strong></a>
+
+ <hr />
+
+
+<h2 id="_">_</h2>
+<table width="100%" class="indextable"><tr><td width="33%" valign="top">
+<dl>
+
+<dt><a href="api/generated/IPython.background_jobs.html#IPython.background_jobs.BackgroundJobBase.__init__">__init__() (IPython.background_jobs.BackgroundJobBase method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.ColorANSI.html#IPython.ColorANSI.ColorScheme.__init__">(IPython.ColorANSI.ColorScheme method)</a></dt>
+ <dt><a href="api/generated/IPython.ColorANSI.html#IPython.ColorANSI.ColorSchemeTable.__init__">(IPython.ColorANSI.ColorSchemeTable method)</a></dt>
+ <dt><a href="api/generated/IPython.ConfigLoader.html#IPython.ConfigLoader.ConfigLoader.__init__">(IPython.ConfigLoader.ConfigLoader method)</a></dt>
+ <dt><a href="api/generated/IPython.ConfigLoader.html#IPython.ConfigLoader.ConfigLoaderError.__init__">(IPython.ConfigLoader.ConfigLoaderError method)</a></dt>
+ <dt><a href="api/generated/IPython.CrashHandler.html#IPython.CrashHandler.CrashHandler.__init__">(IPython.CrashHandler.CrashHandler method)</a></dt>
+ <dt><a href="api/generated/IPython.CrashHandler.html#IPython.CrashHandler.IPythonCrashHandler.__init__">(IPython.CrashHandler.IPythonCrashHandler method)</a></dt>
+ <dt><a href="api/generated/IPython.DPyGetOpt.html#IPython.DPyGetOpt.ArgumentError.__init__">(IPython.DPyGetOpt.ArgumentError method)</a></dt>
+ <dt><a href="api/generated/IPython.DPyGetOpt.html#IPython.DPyGetOpt.DPyGetOpt.__init__">(IPython.DPyGetOpt.DPyGetOpt method)</a></dt>
+ <dt><a href="api/generated/IPython.DPyGetOpt.html#IPython.DPyGetOpt.Error.__init__">(IPython.DPyGetOpt.Error method)</a></dt>
+ <dt><a href="api/generated/IPython.DPyGetOpt.html#IPython.DPyGetOpt.SpecificationError.__init__">(IPython.DPyGetOpt.SpecificationError method)</a></dt>
+ <dt><a href="api/generated/IPython.DPyGetOpt.html#IPython.DPyGetOpt.TerminationError.__init__">(IPython.DPyGetOpt.TerminationError method)</a></dt>
+ <dt><a href="api/generated/IPython.Debugger.html#IPython.Debugger.Pdb.__init__">(IPython.Debugger.Pdb method)</a></dt>
+ <dt><a href="api/generated/IPython.Debugger.html#IPython.Debugger.Tracer.__init__">(IPython.Debugger.Tracer method)</a></dt>
+ <dt><a href="api/generated/IPython.Itpl.html#IPython.Itpl.Itpl.__init__">(IPython.Itpl.Itpl method)</a></dt>
+ <dt><a href="api/generated/IPython.Itpl.html#IPython.Itpl.ItplError.__init__">(IPython.Itpl.ItplError method)</a></dt>
+ <dt><a href="api/generated/IPython.Itpl.html#IPython.Itpl.ItplFile.__init__">(IPython.Itpl.ItplFile method)</a></dt>
+ <dt><a href="api/generated/IPython.Itpl.html#IPython.Itpl.ItplNS.__init__">(IPython.Itpl.ItplNS method)</a></dt>
+ <dt><a href="api/generated/IPython.Logger.html#IPython.Logger.Logger.__init__">(IPython.Logger.Logger method)</a></dt>
+ <dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.__init__">(IPython.Magic.Magic method)</a></dt>
+ <dt><a href="api/generated/IPython.OInspect.html#IPython.OInspect.Inspector.__init__">(IPython.OInspect.Inspector method)</a></dt>
+ <dt><a href="api/generated/IPython.OInspect.html#IPython.OInspect.myStringIO.__init__">(IPython.OInspect.myStringIO method)</a></dt>
+ <dt><a href="api/generated/IPython.OutputTrap.html#IPython.OutputTrap.OutputTrap.__init__">(IPython.OutputTrap.OutputTrap method)</a></dt>
+ <dt><a href="api/generated/IPython.OutputTrap.html#IPython.OutputTrap.OutputTrapError.__init__">(IPython.OutputTrap.OutputTrapError method)</a></dt>
+ <dt><a href="api/generated/IPython.Prompts.html#IPython.Prompts.BasePrompt.__init__">(IPython.Prompts.BasePrompt method)</a></dt>
+ <dt><a href="api/generated/IPython.Prompts.html#IPython.Prompts.CachedOutput.__init__">(IPython.Prompts.CachedOutput method)</a></dt>
+ <dt><a href="api/generated/IPython.Prompts.html#IPython.Prompts.Prompt1.__init__">(IPython.Prompts.Prompt1 method)</a></dt>
+ <dt><a href="api/generated/IPython.Prompts.html#IPython.Prompts.Prompt2.__init__">(IPython.Prompts.Prompt2 method)</a></dt>
+ <dt><a href="api/generated/IPython.Prompts.html#IPython.Prompts.PromptOut.__init__">(IPython.Prompts.PromptOut method)</a></dt>
+ <dt><a href="api/generated/IPython.PyColorize.html#IPython.PyColorize.Parser.__init__">(IPython.PyColorize.Parser method)</a></dt>
+ <dt><a href="api/generated/IPython.Shell.html#IPython.Shell.IPShell.__init__">(IPython.Shell.IPShell method)</a></dt>
+ <dt><a href="api/generated/IPython.Shell.html#IPython.Shell.IPShellEmbed.__init__">(IPython.Shell.IPShellEmbed method)</a></dt>
+ <dt><a href="api/generated/IPython.Shell.html#IPython.Shell.IPShellGTK.__init__">(IPython.Shell.IPShellGTK method)</a></dt>
+ <dt><a href="api/generated/IPython.Shell.html#IPython.Shell.IPShellMatplotlib.__init__">(IPython.Shell.IPShellMatplotlib method)</a></dt>
+ <dt><a href="api/generated/IPython.Shell.html#IPython.Shell.IPShellMatplotlibGTK.__init__">(IPython.Shell.IPShellMatplotlibGTK method)</a></dt>
+ <dt><a href="api/generated/IPython.Shell.html#IPython.Shell.IPShellMatplotlibQt.__init__">(IPython.Shell.IPShellMatplotlibQt method)</a></dt>
+ <dt><a href="api/generated/IPython.Shell.html#IPython.Shell.IPShellMatplotlibQt4.__init__">(IPython.Shell.IPShellMatplotlibQt4 method)</a></dt>
+ <dt><a href="api/generated/IPython.Shell.html#IPython.Shell.IPShellMatplotlibWX.__init__">(IPython.Shell.IPShellMatplotlibWX method)</a></dt>
+ <dt><a href="api/generated/IPython.Shell.html#IPython.Shell.IPShellQt.__init__">(IPython.Shell.IPShellQt method)</a></dt>
+ <dt><a href="api/generated/IPython.Shell.html#IPython.Shell.IPShellQt4.__init__">(IPython.Shell.IPShellQt4 method)</a></dt>
+ <dt><a href="api/generated/IPython.Shell.html#IPython.Shell.IPShellWX.__init__">(IPython.Shell.IPShellWX method)</a></dt>
+ <dt><a href="api/generated/IPython.Shell.html#IPython.Shell.IPThread.__init__">(IPython.Shell.IPThread method)</a></dt>
+ <dt><a href="api/generated/IPython.Shell.html#IPython.Shell.MTInteractiveShell.__init__">(IPython.Shell.MTInteractiveShell method)</a></dt>
+ <dt><a href="api/generated/IPython.Shell.html#IPython.Shell.MatplotlibMTShell.__init__">(IPython.Shell.MatplotlibMTShell method)</a></dt>
+ <dt><a href="api/generated/IPython.Shell.html#IPython.Shell.MatplotlibShell.__init__">(IPython.Shell.MatplotlibShell method)</a></dt>
+ <dt><a href="api/generated/IPython.background_jobs.html#IPython.background_jobs.BackgroundJobExpr.__init__">(IPython.background_jobs.BackgroundJobExpr method)</a></dt>
+ <dt><a href="api/generated/IPython.background_jobs.html#IPython.background_jobs.BackgroundJobFunc.__init__">(IPython.background_jobs.BackgroundJobFunc method)</a></dt>
+ <dt><a href="api/generated/IPython.background_jobs.html#IPython.background_jobs.BackgroundJobManager.__init__">(IPython.background_jobs.BackgroundJobManager method)</a></dt>
+ <dt><a href="api/generated/IPython.completer.html#IPython.completer.Completer.__init__">(IPython.completer.Completer method)</a></dt>
+ <dt><a href="api/generated/IPython.completer.html#IPython.completer.IPCompleter.__init__">(IPython.completer.IPCompleter method)</a></dt>
+ <dt><a href="api/generated/IPython.config.api.html#IPython.config.api.ConfigObjManager.__init__">(IPython.config.api.ConfigObjManager method)</a></dt>
+ <dt><a href="api/generated/IPython.demo.html#IPython.demo.ClearDemo.__init__">(IPython.demo.ClearDemo method)</a></dt>
+ <dt><a href="api/generated/IPython.demo.html#IPython.demo.ClearIPDemo.__init__">(IPython.demo.ClearIPDemo method)</a></dt>
+ <dt><a href="api/generated/IPython.demo.html#IPython.demo.ClearMixin.__init__">(IPython.demo.ClearMixin method)</a></dt>
+ <dt><a href="api/generated/IPython.demo.html#IPython.demo.Demo.__init__">(IPython.demo.Demo method)</a></dt>
+ <dt><a href="api/generated/IPython.demo.html#IPython.demo.DemoError.__init__">(IPython.demo.DemoError method)</a></dt>
+ <dt><a href="api/generated/IPython.demo.html#IPython.demo.IPythonDemo.__init__">(IPython.demo.IPythonDemo method)</a></dt>
+ <dt><a href="api/generated/IPython.demo.html#IPython.demo.IPythonLineDemo.__init__">(IPython.demo.IPythonLineDemo method)</a></dt>
+ <dt><a href="api/generated/IPython.demo.html#IPython.demo.LineDemo.__init__">(IPython.demo.LineDemo method)</a></dt>
+ <dt><a href="api/generated/IPython.external.Itpl.html#IPython.external.Itpl.Itpl.__init__">(IPython.external.Itpl.Itpl method)</a></dt>
+ <dt><a href="api/generated/IPython.external.Itpl.html#IPython.external.Itpl.ItplError.__init__">(IPython.external.Itpl.ItplError method)</a></dt>
+ <dt><a href="api/generated/IPython.external.Itpl.html#IPython.external.Itpl.ItplFile.__init__">(IPython.external.Itpl.ItplFile method)</a></dt>
+ <dt><a href="api/generated/IPython.external.Itpl.html#IPython.external.Itpl.ItplNS.__init__">(IPython.external.Itpl.ItplNS method)</a></dt>
+ <dt><a href="api/generated/IPython.external.argparse.html#IPython.external.argparse.Action.__init__">(IPython.external.argparse.Action method)</a></dt>
+ <dt><a href="api/generated/IPython.external.argparse.html#IPython.external.argparse.ArgumentDefaultsHelpFormatter.__init__">(IPython.external.argparse.ArgumentDefaultsHelpFormatter method)</a></dt>
+ <dt><a href="api/generated/IPython.external.argparse.html#IPython.external.argparse.ArgumentError.__init__">(IPython.external.argparse.ArgumentError method)</a></dt>
+ <dt><a href="api/generated/IPython.external.argparse.html#IPython.external.argparse.ArgumentParser.__init__">(IPython.external.argparse.ArgumentParser method)</a></dt>
+ <dt><a href="api/generated/IPython.external.argparse.html#IPython.external.argparse.FileType.__init__">(IPython.external.argparse.FileType method)</a></dt>
+ <dt><a href="api/generated/IPython.external.argparse.html#IPython.external.argparse.HelpFormatter.__init__">(IPython.external.argparse.HelpFormatter method)</a></dt>
+ <dt><a href="api/generated/IPython.external.argparse.html#IPython.external.argparse.Namespace.__init__">(IPython.external.argparse.Namespace method)</a></dt>
+ <dt><a href="api/generated/IPython.external.argparse.html#IPython.external.argparse.RawDescriptionHelpFormatter.__init__">(IPython.external.argparse.RawDescriptionHelpFormatter method)</a></dt>
+ <dt><a href="api/generated/IPython.external.argparse.html#IPython.external.argparse.RawTextHelpFormatter.__init__">(IPython.external.argparse.RawTextHelpFormatter method)</a></dt>
+ <dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.Builder.__init__">(IPython.external.configobj.Builder method)</a></dt>
+ <dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.ConfigObj.__init__">(IPython.external.configobj.ConfigObj method)</a></dt>
+ <dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.ConfigObjError.__init__">(IPython.external.configobj.ConfigObjError method)</a></dt>
+ <dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.ConfigParserInterpolation.__init__">(IPython.external.configobj.ConfigParserInterpolation method)</a></dt>
+ <dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.ConfigspecError.__init__">(IPython.external.configobj.ConfigspecError method)</a></dt>
+ <dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.DuplicateError.__init__">(IPython.external.configobj.DuplicateError method)</a></dt>
+ <dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.InterpolationEngine.__init__">(IPython.external.configobj.InterpolationEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.InterpolationError.__init__">(IPython.external.configobj.InterpolationError method)</a></dt>
+ <dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.InterpolationLoopError.__init__">(IPython.external.configobj.InterpolationLoopError method)</a></dt>
+ <dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.MissingInterpolationOption.__init__">(IPython.external.configobj.MissingInterpolationOption method)</a></dt>
+ <dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.NestingError.__init__">(IPython.external.configobj.NestingError method)</a></dt>
+ <dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.ParseError.__init__">(IPython.external.configobj.ParseError method)</a></dt>
+ <dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.ReloadError.__init__">(IPython.external.configobj.ReloadError method)</a></dt>
+ <dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.RepeatSectionError.__init__">(IPython.external.configobj.RepeatSectionError method)</a></dt>
+ <dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.Section.__init__">(IPython.external.configobj.Section method)</a></dt>
+ <dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.SimpleVal.__init__">(IPython.external.configobj.SimpleVal method)</a></dt>
+ <dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.TemplateInterpolation.__init__">(IPython.external.configobj.TemplateInterpolation method)</a></dt>
+ <dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.UnknownType.__init__">(IPython.external.configobj.UnknownType method)</a></dt>
+ <dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.UnreprError.__init__">(IPython.external.configobj.UnreprError method)</a></dt>
+ <dt><a href="api/generated/IPython.external.path.html#IPython.external.path.TreeWalkWarning.__init__">(IPython.external.path.TreeWalkWarning method)</a></dt>
+ <dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.__init__">(IPython.external.path.path method)</a></dt>
+ <dt><a href="api/generated/IPython.external.pretty.html#IPython.external.pretty.Breakable.__init__">(IPython.external.pretty.Breakable method)</a></dt>
+ <dt><a href="api/generated/IPython.external.pretty.html#IPython.external.pretty.Group.__init__">(IPython.external.pretty.Group method)</a></dt>
+ <dt><a href="api/generated/IPython.external.pretty.html#IPython.external.pretty.GroupQueue.__init__">(IPython.external.pretty.GroupQueue method)</a></dt>
+ <dt><a href="api/generated/IPython.external.pretty.html#IPython.external.pretty.PrettyPrinter.__init__">(IPython.external.pretty.PrettyPrinter method)</a></dt>
+ <dt><a href="api/generated/IPython.external.pretty.html#IPython.external.pretty.Printable.__init__">(IPython.external.pretty.Printable method)</a></dt>
+ <dt><a href="api/generated/IPython.external.pretty.html#IPython.external.pretty.RepresentationPrinter.__init__">(IPython.external.pretty.RepresentationPrinter method)</a></dt>
+ <dt><a href="api/generated/IPython.external.pretty.html#IPython.external.pretty.Text.__init__">(IPython.external.pretty.Text method)</a></dt>
+ <dt><a href="api/generated/IPython.external.validate.html#IPython.external.validate.ValidateError.__init__">(IPython.external.validate.ValidateError method)</a></dt>
+ <dt><a href="api/generated/IPython.external.validate.html#IPython.external.validate.Validator.__init__">(IPython.external.validate.Validator method)</a></dt>
+ <dt><a href="api/generated/IPython.external.validate.html#IPython.external.validate.VdtMissingValue.__init__">(IPython.external.validate.VdtMissingValue method)</a></dt>
+ <dt><a href="api/generated/IPython.external.validate.html#IPython.external.validate.VdtParamError.__init__">(IPython.external.validate.VdtParamError method)</a></dt>
+ <dt><a href="api/generated/IPython.external.validate.html#IPython.external.validate.VdtTypeError.__init__">(IPython.external.validate.VdtTypeError method)</a></dt>
+ <dt><a href="api/generated/IPython.external.validate.html#IPython.external.validate.VdtUnknownCheckError.__init__">(IPython.external.validate.VdtUnknownCheckError method)</a></dt>
+ <dt><a href="api/generated/IPython.external.validate.html#IPython.external.validate.VdtValueError.__init__">(IPython.external.validate.VdtValueError method)</a></dt>
+ <dt><a href="api/generated/IPython.external.validate.html#IPython.external.validate.VdtValueTooBigError.__init__">(IPython.external.validate.VdtValueTooBigError method)</a></dt>
+ <dt><a href="api/generated/IPython.external.validate.html#IPython.external.validate.VdtValueTooLongError.__init__">(IPython.external.validate.VdtValueTooLongError method)</a></dt>
+ <dt><a href="api/generated/IPython.external.validate.html#IPython.external.validate.VdtValueTooShortError.__init__">(IPython.external.validate.VdtValueTooShortError method)</a></dt>
+ <dt><a href="api/generated/IPython.external.validate.html#IPython.external.validate.VdtValueTooSmallError.__init__">(IPython.external.validate.VdtValueTooSmallError method)</a></dt>
+ <dt><a href="api/generated/IPython.frontend.asyncfrontendbase.html#IPython.frontend.asyncfrontendbase.AsyncFrontEndBase.__init__">(IPython.frontend.asyncfrontendbase.AsyncFrontEndBase method)</a></dt>
+ <dt><a href="api/generated/IPython.frontend.frontendbase.html#IPython.frontend.frontendbase.FrontEndBase.__init__">(IPython.frontend.frontendbase.FrontEndBase method)</a></dt>
+ <dt><a href="api/generated/IPython.frontend.frontendbase.html#IPython.frontend.frontendbase.IFrontEnd.__init__">(IPython.frontend.frontendbase.IFrontEnd static method)</a></dt>
+ <dt><a href="api/generated/IPython.frontend.frontendbase.html#IPython.frontend.frontendbase.IFrontEndFactory.__init__">(IPython.frontend.frontendbase.IFrontEndFactory static method)</a></dt>
+ <dt><a href="api/generated/IPython.frontend.linefrontendbase.html#IPython.frontend.linefrontendbase.LineFrontEndBase.__init__">(IPython.frontend.linefrontendbase.LineFrontEndBase method)</a></dt>
+ <dt><a href="api/generated/IPython.frontend.prefilterfrontend.html#IPython.frontend.prefilterfrontend.PrefilterFrontEnd.__init__">(IPython.frontend.prefilterfrontend.PrefilterFrontEnd method)</a></dt>
+ <dt><a href="api/generated/IPython.frontend.process.pipedprocess.html#IPython.frontend.process.pipedprocess.PipedProcess.__init__">(IPython.frontend.process.pipedprocess.PipedProcess method)</a></dt>
+ <dt><a href="api/generated/IPython.frontend.wx.console_widget.html#IPython.frontend.wx.console_widget.ConsoleWidget.__init__">(IPython.frontend.wx.console_widget.ConsoleWidget method)</a></dt>
+ <dt><a href="api/generated/IPython.frontend.wx.ipythonx.html#IPython.frontend.wx.ipythonx.IPythonX.__init__">(IPython.frontend.wx.ipythonx.IPythonX method)</a></dt>
+ <dt><a href="api/generated/IPython.frontend.wx.ipythonx.html#IPython.frontend.wx.ipythonx.IPythonXController.__init__">(IPython.frontend.wx.ipythonx.IPythonXController method)</a></dt>
+ <dt><a href="api/generated/IPython.frontend.wx.wx_frontend.html#IPython.frontend.wx.wx_frontend.WxController.__init__">(IPython.frontend.wx.wx_frontend.WxController method)</a></dt>
+ <dt><a href="api/generated/IPython.genutils.html#IPython.genutils.Error.__init__">(IPython.genutils.Error method)</a></dt>
+ <dt><a href="api/generated/IPython.genutils.html#IPython.genutils.HomeDirError.__init__">(IPython.genutils.HomeDirError method)</a></dt>
+ <dt><a href="api/generated/IPython.genutils.html#IPython.genutils.IOStream.__init__">(IPython.genutils.IOStream method)</a></dt>
+ <dt><a href="api/generated/IPython.genutils.html#IPython.genutils.IOTerm.__init__">(IPython.genutils.IOTerm method)</a></dt>
+ <dt><a href="api/generated/IPython.genutils.html#IPython.genutils.LSString.__init__">(IPython.genutils.LSString method)</a></dt>
+ <dt><a href="api/generated/IPython.genutils.html#IPython.genutils.NLprinter.__init__">(IPython.genutils.NLprinter method)</a></dt>
+ <dt><a href="api/generated/IPython.genutils.html#IPython.genutils.SList.__init__">(IPython.genutils.SList method)</a></dt>
+ <dt><a href="api/generated/IPython.genutils.html#IPython.genutils.SystemExec.__init__">(IPython.genutils.SystemExec method)</a></dt>
+ <dt><a href="api/generated/IPython.gui.wx.ipshell_nonblocking.html#IPython.gui.wx.ipshell_nonblocking.NonBlockingIPShell.__init__">(IPython.gui.wx.ipshell_nonblocking.NonBlockingIPShell method)</a></dt>
+ <dt><a href="api/generated/IPython.gui.wx.ipython_history.html#IPython.gui.wx.ipython_history.IPythonHistoryPanel.__init__">(IPython.gui.wx.ipython_history.IPythonHistoryPanel method)</a></dt>
+ <dt><a href="api/generated/IPython.gui.wx.ipython_history.html#IPython.gui.wx.ipython_history.PythonSTC.__init__">(IPython.gui.wx.ipython_history.PythonSTC method)</a></dt>
+ <dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.IPShellWidget.__init__">(IPython.gui.wx.ipython_view.IPShellWidget method)</a></dt>
+ <dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.WxConsoleView.__init__">(IPython.gui.wx.ipython_view.WxConsoleView method)</a></dt>
+ <dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.WxNonBlockingIPShell.__init__">(IPython.gui.wx.ipython_view.WxNonBlockingIPShell method)</a></dt>
+ <dt><a href="api/generated/IPython.gui.wx.thread_ex.html#IPython.gui.wx.thread_ex.ThreadEx.__init__">(IPython.gui.wx.thread_ex.ThreadEx method)</a></dt>
+ <dt><a href="api/generated/IPython.gui.wx.wxIPython.html#IPython.gui.wx.wxIPython.MyApp.__init__">(IPython.gui.wx.wxIPython.MyApp method)</a></dt>
+ <dt><a href="api/generated/IPython.gui.wx.wxIPython.html#IPython.gui.wx.wxIPython.MyFrame.__init__">(IPython.gui.wx.wxIPython.MyFrame method)</a></dt>
+ <dt><a href="api/generated/IPython.history.html#IPython.history.ShadowHist.__init__">(IPython.history.ShadowHist method)</a></dt>
+ <dt><a href="api/generated/IPython.hooks.html#IPython.hooks.CommandChainDispatcher.__init__">(IPython.hooks.CommandChainDispatcher method)</a></dt>
+ <dt><a href="api/generated/IPython.ipapi.html#IPython.ipapi.DebugTools.__init__">(IPython.ipapi.DebugTools method)</a></dt>
+ <dt><a href="api/generated/IPython.ipapi.html#IPython.ipapi.IPApi.__init__">(IPython.ipapi.IPApi method)</a></dt>
+ <dt><a href="api/generated/IPython.ipapi.html#IPython.ipapi.IPythonNotRunning.__init__">(IPython.ipapi.IPythonNotRunning method)</a></dt>
+ <dt><a href="api/generated/IPython.ipapi.html#IPython.ipapi.TryNext.__init__">(IPython.ipapi.TryNext method)</a></dt>
+ <dt><a href="api/generated/IPython.ipapi.html#IPython.ipapi.UsageError.__init__">(IPython.ipapi.UsageError method)</a></dt>
+ <dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InputList.__init__">(IPython.iplib.InputList method)</a></dt>
+ <dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.__init__">(IPython.iplib.InteractiveShell method)</a></dt>
+ <dt><a href="api/generated/IPython.iplib.html#IPython.iplib.Quitter.__init__">(IPython.iplib.Quitter method)</a></dt>
+ <dt><a href="api/generated/IPython.iplib.html#IPython.iplib.SpaceInInput.__init__">(IPython.iplib.SpaceInInput method)</a></dt>
+ <dt><a href="api/generated/IPython.iplib.html#IPython.iplib.SyntaxTB.__init__">(IPython.iplib.SyntaxTB method)</a></dt>
+ <dt><a href="api/generated/IPython.ipstruct.html#IPython.ipstruct.Struct.__init__">(IPython.ipstruct.Struct method)</a></dt>
+ <dt><a href="api/generated/IPython.irunner.html#IPython.irunner.IPythonRunner.__init__">(IPython.irunner.IPythonRunner method)</a></dt>
+ <dt><a href="api/generated/IPython.irunner.html#IPython.irunner.InteractiveRunner.__init__">(IPython.irunner.InteractiveRunner method)</a></dt>
+ <dt><a href="api/generated/IPython.irunner.html#IPython.irunner.PythonRunner.__init__">(IPython.irunner.PythonRunner method)</a></dt>
+ <dt><a href="api/generated/IPython.irunner.html#IPython.irunner.RunnerFactory.__init__">(IPython.irunner.RunnerFactory method)</a></dt>
+ <dt><a href="api/generated/IPython.irunner.html#IPython.irunner.SAGERunner.__init__">(IPython.irunner.SAGERunner method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.clientconnector.html#IPython.kernel.clientconnector.ClientConnector.__init__">(IPython.kernel.clientconnector.ClientConnector method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.clientinterfaces.html#IPython.kernel.clientinterfaces.IBlockingClientAdaptor.__init__">(IPython.kernel.clientinterfaces.IBlockingClientAdaptor static method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.clientinterfaces.html#IPython.kernel.clientinterfaces.IFCClientInterfaceProvider.__init__">(IPython.kernel.clientinterfaces.IFCClientInterfaceProvider static method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.contexts.html#IPython.kernel.contexts.RemoteContextBase.__init__">(IPython.kernel.contexts.RemoteContextBase method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.contexts.html#IPython.kernel.contexts.RemoteMultiEngine.__init__">(IPython.kernel.contexts.RemoteMultiEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.controllerservice.html#IPython.kernel.controllerservice.ControllerAdapterBase.__init__">(IPython.kernel.controllerservice.ControllerAdapterBase method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.controllerservice.html#IPython.kernel.controllerservice.ControllerService.__init__">(IPython.kernel.controllerservice.ControllerService method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.controllerservice.html#IPython.kernel.controllerservice.IControllerBase.__init__">(IPython.kernel.controllerservice.IControllerBase static method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.controllerservice.html#IPython.kernel.controllerservice.IControllerCore.__init__">(IPython.kernel.controllerservice.IControllerCore static method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.display_formatter.html#IPython.kernel.core.display_formatter.IDisplayFormatter.__init__">(IPython.kernel.core.display_formatter.IDisplayFormatter method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.display_formatter.html#IPython.kernel.core.display_formatter.PPrintDisplayFormatter.__init__">(IPython.kernel.core.display_formatter.PPrintDisplayFormatter method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.display_formatter.html#IPython.kernel.core.display_formatter.ReprDisplayFormatter.__init__">(IPython.kernel.core.display_formatter.ReprDisplayFormatter method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.display_trap.html#IPython.kernel.core.display_trap.DisplayTrap.__init__">(IPython.kernel.core.display_trap.DisplayTrap method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.error.html#IPython.kernel.core.error.ControllerCreationError.__init__">(IPython.kernel.core.error.ControllerCreationError method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.error.html#IPython.kernel.core.error.ControllerError.__init__">(IPython.kernel.core.error.ControllerError method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.error.html#IPython.kernel.core.error.EngineCreationError.__init__">(IPython.kernel.core.error.EngineCreationError method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.error.html#IPython.kernel.core.error.EngineError.__init__">(IPython.kernel.core.error.EngineError method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.error.html#IPython.kernel.core.error.IPythonError.__init__">(IPython.kernel.core.error.IPythonError method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.fd_redirector.html#IPython.kernel.core.fd_redirector.FDRedirector.__init__">(IPython.kernel.core.fd_redirector.FDRedirector method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.file_like.html#IPython.kernel.core.file_like.FileLike.__init__">(IPython.kernel.core.file_like.FileLike method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.history.html#IPython.kernel.core.history.FrontEndHistory.__init__">(IPython.kernel.core.history.FrontEndHistory method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.history.html#IPython.kernel.core.history.History.__init__">(IPython.kernel.core.history.History method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.history.html#IPython.kernel.core.history.InterpreterHistory.__init__">(IPython.kernel.core.history.InterpreterHistory method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.interpreter.html#IPython.kernel.core.interpreter.Interpreter.__init__">(IPython.kernel.core.interpreter.Interpreter method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.interpreter.html#IPython.kernel.core.interpreter.NotDefined.__init__">(IPython.kernel.core.interpreter.NotDefined method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.macro.html#IPython.kernel.core.macro.Macro.__init__">(IPython.kernel.core.macro.Macro method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.magic.html#IPython.kernel.core.magic.Magic.__init__">(IPython.kernel.core.magic.Magic method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.message_cache.html#IPython.kernel.core.message_cache.IMessageCache.__init__">(IPython.kernel.core.message_cache.IMessageCache method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.message_cache.html#IPython.kernel.core.message_cache.SimpleMessageCache.__init__">(IPython.kernel.core.message_cache.SimpleMessageCache method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.notification.html#IPython.kernel.core.notification.NotificationCenter.__init__">(IPython.kernel.core.notification.NotificationCenter method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.output_trap.html#IPython.kernel.core.output_trap.OutputTrap.__init__">(IPython.kernel.core.output_trap.OutputTrap method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.prompts.html#IPython.kernel.core.prompts.BasePrompt.__init__">(IPython.kernel.core.prompts.BasePrompt method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.prompts.html#IPython.kernel.core.prompts.CachedOutput.__init__">(IPython.kernel.core.prompts.CachedOutput method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.prompts.html#IPython.kernel.core.prompts.Prompt1.__init__">(IPython.kernel.core.prompts.Prompt1 method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.prompts.html#IPython.kernel.core.prompts.Prompt2.__init__">(IPython.kernel.core.prompts.Prompt2 method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.prompts.html#IPython.kernel.core.prompts.PromptOut.__init__">(IPython.kernel.core.prompts.PromptOut method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.redirector_output_trap.html#IPython.kernel.core.redirector_output_trap.RedirectorOutputTrap.__init__">(IPython.kernel.core.redirector_output_trap.RedirectorOutputTrap method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.sync_traceback_trap.html#IPython.kernel.core.sync_traceback_trap.SyncTracebackTrap.__init__">(IPython.kernel.core.sync_traceback_trap.SyncTracebackTrap method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.traceback_formatter.html#IPython.kernel.core.traceback_formatter.ITracebackFormatter.__init__">(IPython.kernel.core.traceback_formatter.ITracebackFormatter method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.traceback_formatter.html#IPython.kernel.core.traceback_formatter.PlainTracebackFormatter.__init__">(IPython.kernel.core.traceback_formatter.PlainTracebackFormatter method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.traceback_trap.html#IPython.kernel.core.traceback_trap.TracebackTrap.__init__">(IPython.kernel.core.traceback_trap.TracebackTrap method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.util.html#IPython.kernel.core.util.Bunch.__init__">(IPython.kernel.core.util.Bunch method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.util.html#IPython.kernel.core.util.InputList.__init__">(IPython.kernel.core.util.InputList method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.engineconnector.html#IPython.kernel.engineconnector.EngineConnector.__init__">(IPython.kernel.engineconnector.EngineConnector method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.EngineFromReference.__init__">(IPython.kernel.enginefc.EngineFromReference method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.FCEngineReferenceFromService.__init__">(IPython.kernel.enginefc.FCEngineReferenceFromService method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.FCRemoteEngineRefFromService.__init__">(IPython.kernel.enginefc.FCRemoteEngineRefFromService method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.IFCControllerBase.__init__">(IPython.kernel.enginefc.IFCControllerBase static method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.IFCEngine.__init__">(IPython.kernel.enginefc.IFCEngine static method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.Command.__init__">(IPython.kernel.engineservice.Command method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.EngineAPI.__init__">(IPython.kernel.engineservice.EngineAPI method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.EngineService.__init__">(IPython.kernel.engineservice.EngineService method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.IEngineBase.__init__">(IPython.kernel.engineservice.IEngineBase static method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.IEngineCore.__init__">(IPython.kernel.engineservice.IEngineCore static method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.IEngineProperties.__init__">(IPython.kernel.engineservice.IEngineProperties static method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.IEngineQueued.__init__">(IPython.kernel.engineservice.IEngineQueued static method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.IEngineSerialized.__init__">(IPython.kernel.engineservice.IEngineSerialized static method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.IEngineThreaded.__init__">(IPython.kernel.engineservice.IEngineThreaded static method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.QueuedEngine.__init__">(IPython.kernel.engineservice.QueuedEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.StrictDict.__init__">(IPython.kernel.engineservice.StrictDict method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.ThreadedEngineService.__init__">(IPython.kernel.engineservice.ThreadedEngineService method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.AbortedPendingDeferredError.__init__">(IPython.kernel.error.AbortedPendingDeferredError method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.ClientError.__init__">(IPython.kernel.error.ClientError method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.CompositeError.__init__">(IPython.kernel.error.CompositeError method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.ConnectionError.__init__">(IPython.kernel.error.ConnectionError method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.FileTimeoutError.__init__">(IPython.kernel.error.FileTimeoutError method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.IdInUse.__init__">(IPython.kernel.error.IdInUse method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.InvalidClientID.__init__">(IPython.kernel.error.InvalidClientID method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.InvalidDeferredID.__init__">(IPython.kernel.error.InvalidDeferredID method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.InvalidEngineID.__init__">(IPython.kernel.error.InvalidEngineID method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.InvalidProperty.__init__">(IPython.kernel.error.InvalidProperty method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.KernelError.__init__">(IPython.kernel.error.KernelError method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.MessageSizeError.__init__">(IPython.kernel.error.MessageSizeError method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.MissingBlockArgument.__init__">(IPython.kernel.error.MissingBlockArgument method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.NoEnginesRegistered.__init__">(IPython.kernel.error.NoEnginesRegistered method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.NotAPendingResult.__init__">(IPython.kernel.error.NotAPendingResult method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.NotDefined.__init__">(IPython.kernel.error.NotDefined method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.PBMessageSizeError.__init__">(IPython.kernel.error.PBMessageSizeError method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.ProtocolError.__init__">(IPython.kernel.error.ProtocolError method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.QueueCleared.__init__">(IPython.kernel.error.QueueCleared method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.ResultAlreadyRetrieved.__init__">(IPython.kernel.error.ResultAlreadyRetrieved method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.ResultNotCompleted.__init__">(IPython.kernel.error.ResultNotCompleted method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.SecurityError.__init__">(IPython.kernel.error.SecurityError method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.SerializationError.__init__">(IPython.kernel.error.SerializationError method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.StopLocalExecution.__init__">(IPython.kernel.error.StopLocalExecution method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.TaskAborted.__init__">(IPython.kernel.error.TaskAborted method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.TaskRejectError.__init__">(IPython.kernel.error.TaskRejectError method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.TaskTimeout.__init__">(IPython.kernel.error.TaskTimeout method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.UnpickleableException.__init__">(IPython.kernel.error.UnpickleableException method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.mapper.html#IPython.kernel.mapper.IMapper.__init__">(IPython.kernel.mapper.IMapper static method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.mapper.html#IPython.kernel.mapper.IMultiEngineMapperFactory.__init__">(IPython.kernel.mapper.IMultiEngineMapperFactory static method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.mapper.html#IPython.kernel.mapper.ITaskMapperFactory.__init__">(IPython.kernel.mapper.ITaskMapperFactory static method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.mapper.html#IPython.kernel.mapper.MultiEngineMapper.__init__">(IPython.kernel.mapper.MultiEngineMapper method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.mapper.html#IPython.kernel.mapper.SynchronousTaskMapper.__init__">(IPython.kernel.mapper.SynchronousTaskMapper method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.mapper.html#IPython.kernel.mapper.TaskMapper.__init__">(IPython.kernel.mapper.TaskMapper method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.IEngineMultiplexer.__init__">(IPython.kernel.multiengine.IEngineMultiplexer static method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.IFullMultiEngine.__init__">(IPython.kernel.multiengine.IFullMultiEngine static method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.IFullSynchronousMultiEngine.__init__">(IPython.kernel.multiengine.IFullSynchronousMultiEngine static method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.IMultiEngine.__init__">(IPython.kernel.multiengine.IMultiEngine static method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.IMultiEngineCoordinator.__init__">(IPython.kernel.multiengine.IMultiEngineCoordinator static method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.IMultiEngineExtras.__init__">(IPython.kernel.multiengine.IMultiEngineExtras static method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.ISynchronousEngineMultiplexer.__init__">(IPython.kernel.multiengine.ISynchronousEngineMultiplexer static method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.ISynchronousMultiEngine.__init__">(IPython.kernel.multiengine.ISynchronousMultiEngine static method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.ISynchronousMultiEngineCoordinator.__init__">(IPython.kernel.multiengine.ISynchronousMultiEngineCoordinator static method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.ISynchronousMultiEngineExtras.__init__">(IPython.kernel.multiengine.ISynchronousMultiEngineExtras static method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.MultiEngine.__init__">(IPython.kernel.multiengine.MultiEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.SynchronousMultiEngine.__init__">(IPython.kernel.multiengine.SynchronousMultiEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.FullBlockingMultiEngineClient.__init__">(IPython.kernel.multiengineclient.FullBlockingMultiEngineClient method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.IFullBlockingMultiEngineClient.__init__">(IPython.kernel.multiengineclient.IFullBlockingMultiEngineClient static method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.IPendingResult.__init__">(IPython.kernel.multiengineclient.IPendingResult static method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.InteractiveMultiEngineClient.__init__">(IPython.kernel.multiengineclient.InteractiveMultiEngineClient method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.PendingResult.__init__">(IPython.kernel.multiengineclient.PendingResult method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.QueueStatusList.__init__">(IPython.kernel.multiengineclient.QueueStatusList method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.ResultList.__init__">(IPython.kernel.multiengineclient.ResultList method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient.__init__">(IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCSynchronousMultiEngineFromMultiEngine.__init__">(IPython.kernel.multienginefc.FCSynchronousMultiEngineFromMultiEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.IFCSynchronousMultiEngine.__init__">(IPython.kernel.multienginefc.IFCSynchronousMultiEngine static method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.newserialized.html#IPython.kernel.newserialized.ISerialized.__init__">(IPython.kernel.newserialized.ISerialized static method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.newserialized.html#IPython.kernel.newserialized.IUnSerialized.__init__">(IPython.kernel.newserialized.IUnSerialized static method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.newserialized.html#IPython.kernel.newserialized.SerializeIt.__init__">(IPython.kernel.newserialized.SerializeIt method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.newserialized.html#IPython.kernel.newserialized.Serialized.__init__">(IPython.kernel.newserialized.Serialized method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.newserialized.html#IPython.kernel.newserialized.UnSerializeIt.__init__">(IPython.kernel.newserialized.UnSerializeIt method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.newserialized.html#IPython.kernel.newserialized.UnSerialized.__init__">(IPython.kernel.newserialized.UnSerialized method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.parallelfunction.html#IPython.kernel.parallelfunction.IMultiEngineParallelDecorator.__init__">(IPython.kernel.parallelfunction.IMultiEngineParallelDecorator static method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.parallelfunction.html#IPython.kernel.parallelfunction.IParallelFunction.__init__">(IPython.kernel.parallelfunction.IParallelFunction static method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.parallelfunction.html#IPython.kernel.parallelfunction.ITaskParallelDecorator.__init__">(IPython.kernel.parallelfunction.ITaskParallelDecorator static method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.parallelfunction.html#IPython.kernel.parallelfunction.ParallelFunction.__init__">(IPython.kernel.parallelfunction.ParallelFunction method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.pendingdeferred.html#IPython.kernel.pendingdeferred.PendingDeferredManager.__init__">(IPython.kernel.pendingdeferred.PendingDeferredManager method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.pickleutil.html#IPython.kernel.pickleutil.CannedFunction.__init__">(IPython.kernel.pickleutil.CannedFunction method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.pickleutil.html#IPython.kernel.pickleutil.CannedObject.__init__">(IPython.kernel.pickleutil.CannedObject method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.scripts.ipcluster.html#IPython.kernel.scripts.ipcluster.BatchEngineSet.__init__">(IPython.kernel.scripts.ipcluster.BatchEngineSet method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.scripts.ipcluster.html#IPython.kernel.scripts.ipcluster.ControllerLauncher.__init__">(IPython.kernel.scripts.ipcluster.ControllerLauncher method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.scripts.ipcluster.html#IPython.kernel.scripts.ipcluster.EngineLauncher.__init__">(IPython.kernel.scripts.ipcluster.EngineLauncher method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.scripts.ipcluster.html#IPython.kernel.scripts.ipcluster.LauncherProcessProtocol.__init__">(IPython.kernel.scripts.ipcluster.LauncherProcessProtocol method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.scripts.ipcluster.html#IPython.kernel.scripts.ipcluster.LocalEngineSet.__init__">(IPython.kernel.scripts.ipcluster.LocalEngineSet method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.scripts.ipcluster.html#IPython.kernel.scripts.ipcluster.PBSEngineSet.__init__">(IPython.kernel.scripts.ipcluster.PBSEngineSet method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.scripts.ipcluster.html#IPython.kernel.scripts.ipcluster.ProcessLauncher.__init__">(IPython.kernel.scripts.ipcluster.ProcessLauncher method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.scripts.ipcluster.html#IPython.kernel.scripts.ipcluster.ProcessStateError.__init__">(IPython.kernel.scripts.ipcluster.ProcessStateError method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.scripts.ipcluster.html#IPython.kernel.scripts.ipcluster.SSHEngineSet.__init__">(IPython.kernel.scripts.ipcluster.SSHEngineSet method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.scripts.ipcluster.html#IPython.kernel.scripts.ipcluster.UnknownStatus.__init__">(IPython.kernel.scripts.ipcluster.UnknownStatus method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.BaseTask.__init__">(IPython.kernel.task.BaseTask method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.FIFOScheduler.__init__">(IPython.kernel.task.FIFOScheduler method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.IScheduler.__init__">(IPython.kernel.task.IScheduler static method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.ITask.__init__">(IPython.kernel.task.ITask static method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.ITaskController.__init__">(IPython.kernel.task.ITaskController static method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.IWorker.__init__">(IPython.kernel.task.IWorker static method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.LIFOScheduler.__init__">(IPython.kernel.task.LIFOScheduler method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.MapTask.__init__">(IPython.kernel.task.MapTask method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.ResultNS.__init__">(IPython.kernel.task.ResultNS method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.StringTask.__init__">(IPython.kernel.task.StringTask method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.TaskController.__init__">(IPython.kernel.task.TaskController method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.TaskResult.__init__">(IPython.kernel.task.TaskResult method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.WorkerFromQueuedEngine.__init__">(IPython.kernel.task.WorkerFromQueuedEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.taskclient.html#IPython.kernel.taskclient.BlockingTaskClient.__init__">(IPython.kernel.taskclient.BlockingTaskClient method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.taskclient.html#IPython.kernel.taskclient.IBlockingTaskClient.__init__">(IPython.kernel.taskclient.IBlockingTaskClient static method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.taskfc.html#IPython.kernel.taskfc.FCTaskClient.__init__">(IPython.kernel.taskfc.FCTaskClient method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.taskfc.html#IPython.kernel.taskfc.FCTaskControllerFromTaskController.__init__">(IPython.kernel.taskfc.FCTaskControllerFromTaskController method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.taskfc.html#IPython.kernel.taskfc.IFCTaskController.__init__">(IPython.kernel.taskfc.IFCTaskController static method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.twistedutil.html#IPython.kernel.twistedutil.DeferredList.__init__">(IPython.kernel.twistedutil.DeferredList method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.twistedutil.html#IPython.kernel.twistedutil.ReactorInThread.__init__">(IPython.kernel.twistedutil.ReactorInThread method)</a></dt>
+ <dt><a href="api/generated/IPython.macro.html#IPython.macro.Macro.__init__">(IPython.macro.Macro method)</a></dt>
+ <dt><a href="api/generated/IPython.platutils.html#IPython.platutils.FindCmdError.__init__">(IPython.platutils.FindCmdError method)</a></dt>
+ <dt><a href="api/generated/IPython.prefilter.html#IPython.prefilter.LineInfo.__init__">(IPython.prefilter.LineInfo method)</a></dt>
+ <dt><a href="api/generated/IPython.strdispatch.html#IPython.strdispatch.StrDispatch.__init__">(IPython.strdispatch.StrDispatch method)</a></dt>
+ <dt><a href="api/generated/IPython.testing.iptest.html#IPython.testing.iptest.IPTester.__init__">(IPython.testing.iptest.IPTester method)</a></dt>
+ <dt><a href="api/generated/IPython.testing.mkdoctests.html#IPython.testing.mkdoctests.IndentOut.__init__">(IPython.testing.mkdoctests.IndentOut method)</a></dt>
+ <dt><a href="api/generated/IPython.testing.mkdoctests.html#IPython.testing.mkdoctests.RunnerFactory.__init__">(IPython.testing.mkdoctests.RunnerFactory method)</a></dt>
+ <dt><a href="api/generated/IPython.testing.plugin.show_refs.html#IPython.testing.plugin.show_refs.C.__init__">(IPython.testing.plugin.show_refs.C method)</a></dt>
+ <dt><a href="api/generated/IPython.testing.util.html#IPython.testing.util.DeferredTestCase.__init__">(IPython.testing.util.DeferredTestCase method)</a></dt>
+ <dt><a href="api/generated/IPython.tools.growl.html#IPython.tools.growl.IPythonGrowlError.__init__">(IPython.tools.growl.IPythonGrowlError method)</a></dt>
+ <dt><a href="api/generated/IPython.tools.growl.html#IPython.tools.growl.Notifier.__init__">(IPython.tools.growl.Notifier method)</a></dt>
+ <dt><a href="api/generated/IPython.twshell.html#IPython.twshell.IPShellTwisted.__init__">(IPython.twshell.IPShellTwisted method)</a></dt>
+ <dt><a href="api/generated/IPython.twshell.html#IPython.twshell.TwistedInteractiveShell.__init__">(IPython.twshell.TwistedInteractiveShell method)</a></dt>
+ <dt><a href="api/generated/IPython.ultraTB.html#IPython.ultraTB.AutoFormattedTB.__init__">(IPython.ultraTB.AutoFormattedTB method)</a></dt>
+ <dt><a href="api/generated/IPython.ultraTB.html#IPython.ultraTB.ColorTB.__init__">(IPython.ultraTB.ColorTB method)</a></dt>
+ <dt><a href="api/generated/IPython.ultraTB.html#IPython.ultraTB.FormattedTB.__init__">(IPython.ultraTB.FormattedTB method)</a></dt>
+ <dt><a href="api/generated/IPython.ultraTB.html#IPython.ultraTB.ListTB.__init__">(IPython.ultraTB.ListTB method)</a></dt>
+ <dt><a href="api/generated/IPython.ultraTB.html#IPython.ultraTB.TBTools.__init__">(IPython.ultraTB.TBTools method)</a></dt>
+ <dt><a href="api/generated/IPython.ultraTB.html#IPython.ultraTB.VerboseTB.__init__">(IPython.ultraTB.VerboseTB method)</a></dt>
+ <dt><a href="api/generated/IPython.wildcard.html#IPython.wildcard.NameSpace.__init__">(IPython.wildcard.NameSpace method)</a></dt>
+ </dl></dd></dl></td><td width="33%" valign="top"><dl>
+</dl></td></tr></table>
+
+<h2 id="A">A</h2>
+<table width="100%" class="indextable"><tr><td width="33%" valign="top">
+<dl>
+
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.abbrev_cwd">abbrev_cwd() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.TaskController.abort">abort() (IPython.kernel.task.TaskController method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.taskclient.html#IPython.kernel.taskclient.BlockingTaskClient.abort">(IPython.kernel.taskclient.BlockingTaskClient method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.taskfc.html#IPython.kernel.taskfc.FCTaskClient.abort">(IPython.kernel.taskfc.FCTaskClient method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.QueuedEngine.abortCommand">abortCommand() (IPython.kernel.engineservice.QueuedEngine method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.AbortedPendingDeferredError">AbortedPendingDeferredError (class in IPython.kernel.error)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.abspath">abspath() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.access">access() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.external.argparse.html#IPython.external.argparse.Action">Action (class in IPython.external.argparse)</a></dt>
+<dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.InteractiveMultiEngineClient.activate">activate() (IPython.kernel.multiengineclient.InteractiveMultiEngineClient method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient.adapt_to_blocking_client">adapt_to_blocking_client() (IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.taskfc.html#IPython.kernel.taskfc.FCTaskClient.adapt_to_blocking_client">(IPython.kernel.taskfc.FCTaskClient method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.external.pretty.html#IPython.external.pretty.Text.add">add() (IPython.external.pretty.Text method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.history.html#IPython.history.ShadowHist.add">(IPython.history.ShadowHist method)</a></dt>
+ <dt><a href="api/generated/IPython.hooks.html#IPython.hooks.CommandChainDispatcher.add">(IPython.hooks.CommandChainDispatcher method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.util.html#IPython.kernel.core.util.InputList.add">(IPython.kernel.core.util.InputList method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.external.argparse.html#IPython.external.argparse.HelpFormatter.add_argument">add_argument() (IPython.external.argparse.HelpFormatter method)</a></dt>
+<dt><a href="api/generated/IPython.external.argparse.html#IPython.external.argparse.HelpFormatter.add_arguments">add_arguments() (IPython.external.argparse.HelpFormatter method)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.add_builtins">add_builtins() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.PendingResult.add_callback">add_callback() (IPython.kernel.multiengineclient.PendingResult method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.history.html#IPython.kernel.core.history.FrontEndHistory.add_items">add_items() (IPython.kernel.core.history.FrontEndHistory method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.message_cache.html#IPython.kernel.core.message_cache.IMessageCache.add_message">add_message() (IPython.kernel.core.message_cache.IMessageCache method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.core.message_cache.html#IPython.kernel.core.message_cache.SimpleMessageCache.add_message">(IPython.kernel.core.message_cache.SimpleMessageCache method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.core.notification.html#IPython.kernel.core.notification.NotificationCenter.add_observer">add_observer() (IPython.kernel.core.notification.NotificationCenter method)</a></dt>
+<dt><a href="api/generated/IPython.strdispatch.html#IPython.strdispatch.StrDispatch.add_re">add_re() (IPython.strdispatch.StrDispatch method)</a></dt>
+<dt><a href="api/generated/IPython.strdispatch.html#IPython.strdispatch.StrDispatch.add_s">add_s() (IPython.strdispatch.StrDispatch method)</a></dt>
+<dt><a href="api/generated/IPython.ColorANSI.html#IPython.ColorANSI.ColorSchemeTable.add_scheme">add_scheme() (IPython.ColorANSI.ColorSchemeTable method)</a></dt>
+<dt><a href="api/generated/IPython.external.argparse.html#IPython.external.argparse.ArgumentParser.add_subparsers">add_subparsers() (IPython.external.argparse.ArgumentParser method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.FIFOScheduler.add_task">add_task() (IPython.kernel.task.FIFOScheduler method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.LIFOScheduler.add_task">(IPython.kernel.task.LIFOScheduler method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.external.argparse.html#IPython.external.argparse.HelpFormatter.add_text">add_text() (IPython.external.argparse.HelpFormatter method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.display_trap.html#IPython.kernel.core.display_trap.DisplayTrap.add_to_message">add_to_message() (IPython.kernel.core.display_trap.DisplayTrap method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.core.output_trap.html#IPython.kernel.core.output_trap.OutputTrap.add_to_message">(IPython.kernel.core.output_trap.OutputTrap method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.traceback_trap.html#IPython.kernel.core.traceback_trap.TracebackTrap.add_to_message">(IPython.kernel.core.traceback_trap.TracebackTrap method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.external.argparse.html#IPython.external.argparse.HelpFormatter.add_usage">add_usage() (IPython.external.argparse.HelpFormatter method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.FIFOScheduler.add_worker">add_worker() (IPython.kernel.task.FIFOScheduler method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.LIFOScheduler.add_worker">(IPython.kernel.task.LIFOScheduler method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.WxNonBlockingIPShell.addGUIShortcut">addGUIShortcut() (IPython.gui.wx.ipython_view.WxNonBlockingIPShell method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.EngineService.addIDToResult">addIDToResult() (IPython.kernel.engineservice.EngineService method)</a></dt>
+<dt><a href="api/generated/IPython.DPyGetOpt.html#IPython.DPyGetOpt.DPyGetOpt.addOptionConfigurationTuple">addOptionConfigurationTuple() (IPython.DPyGetOpt.DPyGetOpt method)</a></dt>
+<dt><a href="api/generated/IPython.DPyGetOpt.html#IPython.DPyGetOpt.DPyGetOpt.addOptionConfigurationTuples">addOptionConfigurationTuples() (IPython.DPyGetOpt.DPyGetOpt method)</a></dt></dl></td><td width="33%" valign="top"><dl>
+<dt><a href="api/generated/IPython.DPyGetOpt.html#IPython.DPyGetOpt.DPyGetOpt.addTerminator">addTerminator() (IPython.DPyGetOpt.DPyGetOpt method)</a></dt>
+<dt><a href="api/generated/IPython.frontend.linefrontendbase.html#IPython.frontend.linefrontendbase.LineFrontEndBase.after_execute">after_execute() (IPython.frontend.linefrontendbase.LineFrontEndBase method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.frontend.wx.wx_frontend.html#IPython.frontend.wx.wx_frontend.WxController.after_execute">(IPython.frontend.wx.wx_frontend.WxController method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.demo.html#IPython.demo.Demo.again">again() (IPython.demo.Demo method)</a></dt>
+<dt><a href="api/generated/IPython.completer.html#IPython.completer.IPCompleter.alias_matches">alias_matches() (IPython.completer.IPCompleter method)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.alias_table_validate">alias_table_validate() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.history.html#IPython.history.ShadowHist.all">all() (IPython.history.ShadowHist method)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.all_belong">all_belong() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.completer.html#IPython.completer.IPCompleter.all_completions">all_completions() (IPython.completer.IPCompleter method)</a></dt>
+<dt><a href="api/generated/IPython.ipstruct.html#IPython.ipstruct.Struct.allow_new_attr">allow_new_attr() (IPython.ipstruct.Struct method)</a></dt>
+<dt><a href="api/generated/IPython.numutils.html#IPython.numutils.amap">amap() (in module IPython.numutils)</a></dt>
+<dt><a href="api/generated/IPython.numutils.html#IPython.numutils.amax">amax() (in module IPython.numutils)</a></dt>
+<dt><a href="api/generated/IPython.numutils.html#IPython.numutils.amin">amin() (in module IPython.numutils)</a></dt>
+<dt><a href="api/generated/IPython.testing.decorators.html#IPython.testing.decorators.apply_wrapper">apply_wrapper() (in module IPython.testing.decorators)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.arg_err">arg_err() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.arg_split">arg_split() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.external.argparse.html#IPython.external.argparse.ArgumentDefaultsHelpFormatter">ArgumentDefaultsHelpFormatter (class in IPython.external.argparse)</a></dt>
+<dt><a href="api/generated/IPython.DPyGetOpt.html#IPython.DPyGetOpt.ArgumentError">ArgumentError (class in IPython.DPyGetOpt)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.external.argparse.html#IPython.external.argparse.ArgumentError">(class in IPython.external.argparse)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.external.argparse.html#IPython.external.argparse.ArgumentParser">ArgumentParser (class in IPython.external.argparse)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.Section.as_bool">as_bool() (IPython.external.configobj.Section method)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.Section.as_float">as_float() (IPython.external.configobj.Section method)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.Section.as_int">as_int() (IPython.external.configobj.Section method)</a></dt>
+<dt><a href="api/generated/IPython.frontend.wx.ipythonx.html#IPython.frontend.wx.ipythonx.IPythonXController.ask_exit">ask_exit() (IPython.frontend.wx.ipythonx.IPythonXController method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.ask_exit">(IPython.iplib.InteractiveShell method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.ask_yes_no">ask_yes_no() (in module IPython.genutils)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.ask_yes_no">(IPython.iplib.InteractiveShell method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.IPShellWidget.askExitCallback">askExitCallback() (IPython.gui.wx.ipython_view.IPShellWidget method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.IPShellWidget.askExitHandler">askExitHandler() (IPython.gui.wx.ipython_view.IPShellWidget method)</a></dt>
+<dt><a href="api/generated/IPython.testing.util.html#IPython.testing.util.DeferredTestCase.assertDeferredEquals">assertDeferredEquals() (IPython.testing.util.DeferredTestCase method)</a></dt>
+<dt><a href="api/generated/IPython.testing.util.html#IPython.testing.util.DeferredTestCase.assertDeferredRaises">assertDeferredRaises() (IPython.testing.util.DeferredTestCase method)</a></dt>
+<dt><a href="api/generated/IPython.frontend.asyncfrontendbase.html#IPython.frontend.asyncfrontendbase.AsyncFrontEndBase">AsyncFrontEndBase (class in IPython.frontend.asyncfrontendbase)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.WxConsoleView.asyncWrite">asyncWrite() (IPython.gui.wx.ipython_view.WxConsoleView method)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.atexit_operations">atexit_operations() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.atime">atime (IPython.external.path.path attribute)</a></dt>
+<dt><a href="api/generated/IPython.completer.html#IPython.completer.Completer.attr_matches">attr_matches() (IPython.completer.Completer method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.prompts.html#IPython.kernel.core.prompts.Prompt1.auto_rewrite">auto_rewrite() (IPython.kernel.core.prompts.Prompt1 method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.Prompts.html#IPython.Prompts.Prompt1.auto_rewrite">(IPython.Prompts.Prompt1 method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.ultraTB.html#IPython.ultraTB.AutoFormattedTB">AutoFormattedTB (class in IPython.ultraTB)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.autoindent_update">autoindent_update() (IPython.iplib.InteractiveShell method)</a></dt>
+</dl></td></tr></table>
+
+<h2 id="B">B</h2>
+<table width="100%" class="indextable"><tr><td width="33%" valign="top">
+<dl>
+
+<dt><a href="api/generated/IPython.demo.html#IPython.demo.Demo.back">back() (IPython.demo.Demo method)</a></dt>
+<dt><a href="api/generated/IPython.background_jobs.html#IPython.background_jobs.BackgroundJobBase">BackgroundJobBase (class in IPython.background_jobs)</a></dt>
+<dt><a href="api/generated/IPython.background_jobs.html#IPython.background_jobs.BackgroundJobExpr">BackgroundJobExpr (class in IPython.background_jobs)</a></dt>
+<dt><a href="api/generated/IPython.background_jobs.html#IPython.background_jobs.BackgroundJobFunc">BackgroundJobFunc (class in IPython.background_jobs)</a></dt>
+<dt><a href="api/generated/IPython.background_jobs.html#IPython.background_jobs.BackgroundJobManager">BackgroundJobManager (class in IPython.background_jobs)</a></dt>
+<dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.FullBlockingMultiEngineClient.barrier">barrier() (IPython.kernel.multiengineclient.FullBlockingMultiEngineClient method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.TaskController.barrier">(IPython.kernel.task.TaskController method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.taskclient.html#IPython.kernel.taskclient.BlockingTaskClient.barrier">(IPython.kernel.taskclient.BlockingTaskClient method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.taskfc.html#IPython.kernel.taskfc.FCTaskClient.barrier">(IPython.kernel.taskfc.FCTaskClient method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.numutils.html#IPython.numutils.base_repr">base_repr() (in module IPython.numutils)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.basename">basename() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.prompts.html#IPython.kernel.core.prompts.BasePrompt">BasePrompt (class in IPython.kernel.core.prompts)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.Prompts.html#IPython.Prompts.BasePrompt">(class in IPython.Prompts)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.BaseTask">BaseTask (class in IPython.kernel.task)</a></dt>
+<dt><a href="api/generated/IPython.kernel.scripts.ipcluster.html#IPython.kernel.scripts.ipcluster.BatchEngineSet">BatchEngineSet (class in IPython.kernel.scripts.ipcluster)</a></dt>
+<dt><a href="api/generated/IPython.Debugger.html#IPython.Debugger.BdbQuit_excepthook">BdbQuit_excepthook() (in module IPython.Debugger)</a></dt>
+<dt><a href="api/generated/IPython.Debugger.html#IPython.Debugger.BdbQuit_IPython_excepthook">BdbQuit_IPython_excepthook() (in module IPython.Debugger)</a></dt>
+<dt><a href="api/generated/IPython.external.pretty.html#IPython.external.pretty.PrettyPrinter.begin_group">begin_group() (IPython.external.pretty.PrettyPrinter method)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.belong">belong() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.FullBlockingMultiEngineClient.benchmark">benchmark() (IPython.kernel.multiengineclient.FullBlockingMultiEngineClient method)</a></dt>
+<dt><a href="api/generated/IPython.numutils.html#IPython.numutils.binary_repr">binary_repr() (in module IPython.numutils)</a></dt>
+<dt><a href="api/generated/IPython.kernel.taskclient.html#IPython.kernel.taskclient.BlockingTaskClient">BlockingTaskClient (class in IPython.kernel.taskclient)</a></dt></dl></td><td width="33%" valign="top"><dl>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.SystemExec.bq">bq() (IPython.genutils.SystemExec method)</a></dt>
+<dt><a href="api/generated/IPython.external.pretty.html#IPython.external.pretty.Breakable">Breakable (class in IPython.external.pretty)</a></dt>
+<dt><a href="api/generated/IPython.external.pretty.html#IPython.external.pretty.PrettyPrinter.breakable">breakable() (IPython.external.pretty.PrettyPrinter method)</a></dt>
+<dt><a href="api/generated/IPython.frontend.wx.wx_frontend.html#IPython.frontend.wx.wx_frontend.WxController.buffered_write">buffered_write() (IPython.frontend.wx.wx_frontend.WxController method)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.Builder.build">build() (IPython.external.configobj.Builder method)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.Builder.build_Add">build_Add() (IPython.external.configobj.Builder method)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.Builder.build_Const">build_Const() (IPython.external.configobj.Builder method)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.Builder.build_Dict">build_Dict() (IPython.external.configobj.Builder method)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.Builder.build_Getattr">build_Getattr() (IPython.external.configobj.Builder method)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.Builder.build_List">build_List() (IPython.external.configobj.Builder method)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.Builder.build_Name">build_Name() (IPython.external.configobj.Builder method)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.Builder.build_Tuple">build_Tuple() (IPython.external.configobj.Builder method)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.Builder.build_UnaryAdd">build_UnaryAdd() (IPython.external.configobj.Builder method)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.Builder.build_UnarySub">build_UnarySub() (IPython.external.configobj.Builder method)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.Builder">Builder (class in IPython.external.configobj)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.WxConsoleView.buildStyles">buildStyles() (IPython.gui.wx.ipython_view.WxConsoleView method)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.Bunch">Bunch (class in IPython.iplib)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Bunch">(class in IPython.Magic)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.util.html#IPython.kernel.core.util.Bunch">(class in IPython.kernel.core.util)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.bytes">bytes() (IPython.external.path.path method)</a></dt>
+</dl></td></tr></table>
+
+<h2 id="C">C</h2>
+<table width="100%" class="indextable"><tr><td width="33%" valign="top">
+<dl>
+
+<dt><a href="api/generated/IPython.testing.plugin.show_refs.html#IPython.testing.plugin.show_refs.C">C (class in IPython.testing.plugin.show_refs)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.cache_main_mod">cache_main_mod() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.prompts.html#IPython.kernel.core.prompts.CachedOutput">CachedOutput (class in IPython.kernel.core.prompts)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.Prompts.html#IPython.Prompts.CachedOutput">(class in IPython.Prompts)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.background_jobs.html#IPython.background_jobs.BackgroundJobExpr.call">call() (IPython.background_jobs.BackgroundJobExpr method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.background_jobs.html#IPython.background_jobs.BackgroundJobFunc.call">(IPython.background_jobs.BackgroundJobFunc method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.call_alias">call_alias() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.call_pdb">call_pdb (IPython.iplib.InteractiveShell attribute)</a></dt>
+<dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.EngineFromReference.callRemote">callRemote() (IPython.kernel.enginefc.EngineFromReference method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.pickleutil.html#IPython.kernel.pickleutil.can">can() (in module IPython.kernel.pickleutil)</a></dt>
+<dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.BaseTask.can_task">can_task() (IPython.kernel.task.BaseTask method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.MapTask.can_task">(IPython.kernel.task.MapTask method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.pickleutil.html#IPython.kernel.pickleutil.canDict">canDict() (in module IPython.kernel.pickleutil)</a></dt>
+<dt><a href="api/generated/IPython.kernel.pickleutil.html#IPython.kernel.pickleutil.CannedFunction">CannedFunction (class in IPython.kernel.pickleutil)</a></dt>
+<dt><a href="api/generated/IPython.kernel.pickleutil.html#IPython.kernel.pickleutil.CannedObject">CannedObject (class in IPython.kernel.pickleutil)</a></dt>
+<dt><a href="api/generated/IPython.kernel.pickleutil.html#IPython.kernel.pickleutil.canSequence">canSequence() (in module IPython.kernel.pickleutil)</a></dt>
+<dt><a href="api/generated/IPython.frontend.prefilterfrontend.html#IPython.frontend.prefilterfrontend.PrefilterFrontEnd.capture_output">capture_output() (IPython.frontend.prefilterfrontend.PrefilterFrontEnd method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.frontend.wx.wx_frontend.html#IPython.frontend.wx.wx_frontend.WxController.capture_output">(IPython.frontend.wx.wx_frontend.WxController method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.util.html#IPython.kernel.util.catcher">catcher() (in module IPython.kernel.util)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.WxConsoleView.changeLine">changeLine() (IPython.gui.wx.ipython_view.WxConsoleView method)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.SimpleVal.check">check() (IPython.external.configobj.SimpleVal method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.external.validate.html#IPython.external.validate.Validator.check">(IPython.external.validate.Validator method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.BaseTask.check_depend">check_depend() (IPython.kernel.task.BaseTask method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.fcutil.html#IPython.kernel.fcutil.check_furl_file_security">check_furl_file_security() (in module IPython.kernel.fcutil)</a></dt>
+<dt><a href="api/generated/IPython.ipapi.html#IPython.ipapi.DebugTools.check_hotname">check_hotname() (IPython.ipapi.DebugTools method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.scripts.ipcluster.html#IPython.kernel.scripts.ipcluster.check_reuse">check_reuse() (in module IPython.kernel.scripts.ipcluster)</a></dt>
+<dt><a href="api/generated/IPython.kernel.scripts.ipcluster.html#IPython.kernel.scripts.ipcluster.check_security">check_security() (in module IPython.kernel.scripts.ipcluster)</a></dt>
+<dt><a href="api/generated/IPython.prefilter.html#IPython.prefilter.checkAlias">checkAlias() (in module IPython.prefilter)</a></dt>
+<dt><a href="api/generated/IPython.prefilter.html#IPython.prefilter.checkAssignment">checkAssignment() (in module IPython.prefilter)</a></dt>
+<dt><a href="api/generated/IPython.prefilter.html#IPython.prefilter.checkAutocall">checkAutocall() (in module IPython.prefilter)</a></dt>
+<dt><a href="api/generated/IPython.prefilter.html#IPython.prefilter.checkAutomagic">checkAutomagic() (in module IPython.prefilter)</a></dt>
+<dt><a href="api/generated/IPython.prefilter.html#IPython.prefilter.checkEmacs">checkEmacs() (in module IPython.prefilter)</a></dt>
+<dt><a href="api/generated/IPython.prefilter.html#IPython.prefilter.checkEscChars">checkEscChars() (in module IPython.prefilter)</a></dt>
+<dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.TaskController.checkIdle">checkIdle() (IPython.kernel.task.TaskController method)</a></dt>
+<dt><a href="api/generated/IPython.prefilter.html#IPython.prefilter.checkIPyAutocall">checkIPyAutocall() (in module IPython.prefilter)</a></dt>
+<dt><a href="api/generated/IPython.kernel.pbutil.html#IPython.kernel.pbutil.checkMessageSize">checkMessageSize() (in module IPython.kernel.pbutil)</a></dt>
+<dt><a href="api/generated/IPython.prefilter.html#IPython.prefilter.checkMultiLineMagic">checkMultiLineMagic() (in module IPython.prefilter)</a></dt>
+<dt><a href="api/generated/IPython.prefilter.html#IPython.prefilter.checkPythonOps">checkPythonOps() (in module IPython.prefilter)</a></dt>
+<dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.EngineFromReference.checkReturnForFailure">checkReturnForFailure() (IPython.kernel.enginefc.EngineFromReference method)</a></dt>
+<dt><a href="api/generated/IPython.prefilter.html#IPython.prefilter.checkShellEscape">checkShellEscape() (in module IPython.prefilter)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.chmod">chmod() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.chop">chop() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.chown">chown() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.chroot">chroot() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.clean_builtins">clean_builtins() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.Section.clear">clear() (IPython.external.configobj.Section method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.ipstruct.html#IPython.ipstruct.Struct.clear">(IPython.ipstruct.Struct method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.display_trap.html#IPython.kernel.core.display_trap.DisplayTrap.clear">(IPython.kernel.core.display_trap.DisplayTrap method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.output_trap.html#IPython.kernel.core.output_trap.OutputTrap.clear">(IPython.kernel.core.output_trap.OutputTrap method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.traceback_trap.html#IPython.kernel.core.traceback_trap.TracebackTrap.clear">(IPython.kernel.core.traceback_trap.TracebackTrap method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.StrictDict.clear">(IPython.kernel.engineservice.StrictDict method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.TaskController.clear">(IPython.kernel.task.TaskController method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.taskclient.html#IPython.kernel.taskclient.BlockingTaskClient.clear">(IPython.kernel.taskclient.BlockingTaskClient method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.taskfc.html#IPython.kernel.taskfc.FCTaskClient.clear">(IPython.kernel.taskfc.FCTaskClient method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.SyntaxTB.clear_err_state">clear_err_state() (IPython.iplib.SyntaxTB method)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.clear_main_mod_cache">clear_main_mod_cache() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient.clear_pending_deferreds">clear_pending_deferreds() (IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.pendingdeferred.html#IPython.kernel.pendingdeferred.PendingDeferredManager.clear_pending_deferreds">(IPython.kernel.pendingdeferred.PendingDeferredManager method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.FullBlockingMultiEngineClient.clear_pending_results">clear_pending_results() (IPython.kernel.multiengineclient.FullBlockingMultiEngineClient method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.EngineFromReference.clear_properties">clear_properties() (IPython.kernel.enginefc.EngineFromReference method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.EngineService.clear_properties">(IPython.kernel.engineservice.EngineService method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.QueuedEngine.clear_properties">(IPython.kernel.engineservice.QueuedEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.MultiEngine.clear_properties">(IPython.kernel.multiengine.MultiEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.SynchronousMultiEngine.clear_properties">(IPython.kernel.multiengine.SynchronousMultiEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.FullBlockingMultiEngineClient.clear_properties">(IPython.kernel.multiengineclient.FullBlockingMultiEngineClient method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient.clear_properties">(IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.QueuedEngine.clear_queue">clear_queue() (IPython.kernel.engineservice.QueuedEngine method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.MultiEngine.clear_queue">(IPython.kernel.multiengine.MultiEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.SynchronousMultiEngine.clear_queue">(IPython.kernel.multiengine.SynchronousMultiEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.FullBlockingMultiEngineClient.clear_queue">(IPython.kernel.multiengineclient.FullBlockingMultiEngineClient method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient.clear_queue">(IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.frontend.wx.wx_frontend.html#IPython.frontend.wx.wx_frontend.WxController.clear_screen">clear_screen() (IPython.frontend.wx.wx_frontend.WxController method)</a></dt>
+<dt><a href="api/generated/IPython.demo.html#IPython.demo.ClearDemo">ClearDemo (class in IPython.demo)</a></dt>
+<dt><a href="api/generated/IPython.demo.html#IPython.demo.ClearIPDemo">ClearIPDemo (class in IPython.demo)</a></dt></dl></td><td width="33%" valign="top"><dl>
+<dt><a href="api/generated/IPython.demo.html#IPython.demo.ClearMixin">ClearMixin (class in IPython.demo)</a></dt>
+<dt><a href="api/generated/IPython.kernel.clientconnector.html#IPython.kernel.clientconnector.ClientConnector">ClientConnector (class in IPython.kernel.clientconnector)</a></dt>
+<dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.ClientError">ClientError (class in IPython.kernel.error)</a></dt>
+<dt><a href="api/generated/IPython.hooks.html#IPython.hooks.clipboard_get">clipboard_get() (in module IPython.hooks)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.IOStream.close">close() (IPython.genutils.IOStream method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.irunner.html#IPython.irunner.InteractiveRunner.close">(IPython.irunner.InteractiveRunner method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.file_like.html#IPython.kernel.core.file_like.FileLike.close">(IPython.kernel.core.file_like.FileLike method)</a></dt>
+ <dt><a href="api/generated/IPython.testing.mkdoctests.html#IPython.testing.mkdoctests.IndentOut.close">(IPython.testing.mkdoctests.IndentOut method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.Logger.html#IPython.Logger.Logger.close_log">close_log() (IPython.Logger.Logger method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.codeutil.html#IPython.kernel.codeutil.code_ctor">code_ctor() (in module IPython.kernel.codeutil)</a></dt>
+<dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.collect_exceptions">collect_exceptions() (in module IPython.kernel.error)</a></dt>
+<dt><a href="api/generated/IPython.ultraTB.html#IPython.ultraTB.TBTools.color_toggle">color_toggle() (IPython.ultraTB.TBTools method)</a></dt>
+<dt><a href="api/generated/IPython.ColorANSI.html#IPython.ColorANSI.ColorScheme">ColorScheme (class in IPython.ColorANSI)</a></dt>
+<dt><a href="api/generated/IPython.ColorANSI.html#IPython.ColorANSI.ColorSchemeTable">ColorSchemeTable (class in IPython.ColorANSI)</a></dt>
+<dt><a href="api/generated/IPython.ultraTB.html#IPython.ultraTB.ColorTB">ColorTB (class in IPython.ultraTB)</a></dt>
+<dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.Command">Command (class in IPython.kernel.engineservice)</a></dt>
+<dt><a href="api/generated/IPython.hooks.html#IPython.hooks.CommandChainDispatcher">CommandChainDispatcher (class in IPython.hooks)</a></dt>
+<dt><a href="api/generated/IPython.frontend.linefrontendbase.html#IPython.frontend.linefrontendbase.common_prefix">common_prefix() (in module IPython.frontend.linefrontendbase)</a></dt>
+<dt><a href="api/generated/IPython.completer.html#IPython.completer.Completer.complete">complete() (IPython.completer.Completer method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.completer.html#IPython.completer.IPCompleter.complete">(IPython.completer.IPCompleter method)</a></dt>
+ <dt><a href="api/generated/IPython.frontend.linefrontendbase.html#IPython.frontend.linefrontendbase.LineFrontEndBase.complete">(IPython.frontend.linefrontendbase.LineFrontEndBase method)</a></dt>
+ <dt><a href="api/generated/IPython.frontend.prefilterfrontend.html#IPython.frontend.prefilterfrontend.PrefilterFrontEnd.complete">(IPython.frontend.prefilterfrontend.PrefilterFrontEnd method)</a></dt>
+ <dt><a href="api/generated/IPython.gui.wx.ipshell_nonblocking.html#IPython.gui.wx.ipshell_nonblocking.NonBlockingIPShell.complete">(IPython.gui.wx.ipshell_nonblocking.NonBlockingIPShell method)</a></dt>
+ <dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.complete">(IPython.iplib.InteractiveShell method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.interpreter.html#IPython.kernel.core.interpreter.Interpreter.complete">(IPython.kernel.core.interpreter.Interpreter method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.frontend.linefrontendbase.html#IPython.frontend.linefrontendbase.LineFrontEndBase.complete_current_input">complete_current_input() (IPython.frontend.linefrontendbase.LineFrontEndBase method)</a></dt>
+<dt><a href="api/generated/IPython.generics.html#IPython.generics.complete_object">complete_object() (in module IPython.generics)</a></dt>
+<dt><a href="api/generated/IPython.completer.html#IPython.completer.Completer">Completer (class in IPython.completer)</a></dt>
+<dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.CompositeError">CompositeError (class in IPython.kernel.error)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.compress_dhist">compress_dhist() (in module IPython.Magic)</a></dt>
+<dt><a href="api/generated/IPython.kernel.map.html#IPython.kernel.map.Map.concatenate">concatenate() (IPython.kernel.map.Map method)</a></dt>
+<dt><a href="api/generated/IPython.ConfigLoader.html#IPython.ConfigLoader.ConfigLoader">ConfigLoader (class in IPython.ConfigLoader)</a></dt>
+<dt><a href="api/generated/IPython.ConfigLoader.html#IPython.ConfigLoader.ConfigLoaderError">ConfigLoaderError (class in IPython.ConfigLoader)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.ConfigObj">ConfigObj (class in IPython.external.configobj)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.ConfigObjError">ConfigObjError (class in IPython.external.configobj)</a></dt>
+<dt><a href="api/generated/IPython.config.api.html#IPython.config.api.ConfigObjManager">ConfigObjManager (class in IPython.config.api)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.ConfigParserInterpolation">ConfigParserInterpolation (class in IPython.external.configobj)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.ConfigspecError">ConfigspecError (class in IPython.external.configobj)</a></dt>
+<dt><a href="api/generated/IPython.frontend.wx.console_widget.html#IPython.frontend.wx.console_widget.ConsoleWidget.configure_scintilla">configure_scintilla() (IPython.frontend.wx.console_widget.ConsoleWidget method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.engineconnector.html#IPython.kernel.engineconnector.EngineConnector.connect_to_controller">connect_to_controller() (IPython.kernel.engineconnector.EngineConnector method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.ConnectionError">ConnectionError (class in IPython.kernel.error)</a></dt>
+<dt><a href="api/generated/IPython.kernel.scripts.ipcluster.html#IPython.kernel.scripts.ipcluster.LauncherProcessProtocol.connectionMade">connectionMade() (IPython.kernel.scripts.ipcluster.LauncherProcessProtocol method)</a></dt>
+<dt><a href="api/generated/IPython.frontend.wx.console_widget.html#IPython.frontend.wx.console_widget.ConsoleWidget">ConsoleWidget (class in IPython.frontend.wx.console_widget)</a></dt>
+<dt><a href="api/generated/IPython.ultraTB.html#IPython.ultraTB.FormattedTB.context">context() (IPython.ultraTB.FormattedTB method)</a></dt>
+<dt><a href="api/generated/IPython.frontend.frontendbase.html#IPython.frontend.frontendbase.FrontEndBase.continuation_prompt">continuation_prompt() (IPython.frontend.frontendbase.FrontEndBase method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.frontend.linefrontendbase.html#IPython.frontend.linefrontendbase.LineFrontEndBase.continuation_prompt">(IPython.frontend.linefrontendbase.LineFrontEndBase method)</a></dt>
+ <dt><a href="api/generated/IPython.frontend.wx.console_widget.html#IPython.frontend.wx.console_widget.ConsoleWidget.continuation_prompt">(IPython.frontend.wx.console_widget.ConsoleWidget method)</a></dt>
+ <dt><a href="api/generated/IPython.frontend.wx.wx_frontend.html#IPython.frontend.wx.wx_frontend.WxController.continuation_prompt">(IPython.frontend.wx.wx_frontend.WxController method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.controllerservice.html#IPython.kernel.controllerservice.ControllerAdapterBase">ControllerAdapterBase (class in IPython.kernel.controllerservice)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.error.html#IPython.kernel.core.error.ControllerCreationError">ControllerCreationError (class in IPython.kernel.core.error)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.error.html#IPython.kernel.core.error.ControllerError">ControllerError (class in IPython.kernel.core.error)</a></dt>
+<dt><a href="api/generated/IPython.kernel.scripts.ipcluster.html#IPython.kernel.scripts.ipcluster.ControllerLauncher">ControllerLauncher (class in IPython.kernel.scripts.ipcluster)</a></dt>
+<dt><a href="api/generated/IPython.kernel.controllerservice.html#IPython.kernel.controllerservice.ControllerService">ControllerService (class in IPython.kernel.controllerservice)</a></dt>
+<dt><a href="api/generated/IPython.ColorANSI.html#IPython.ColorANSI.ColorScheme.copy">copy() (IPython.ColorANSI.ColorScheme method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.ColorANSI.html#IPython.ColorANSI.ColorSchemeTable.copy">(IPython.ColorANSI.ColorSchemeTable method)</a></dt>
+ <dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.copy">(IPython.external.path.path method)</a></dt>
+ <dt><a href="api/generated/IPython.ipstruct.html#IPython.ipstruct.Struct.copy">(IPython.ipstruct.Struct method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.copy2">copy2() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.copyfile">copyfile() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.copymode">copymode() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.copystat">copystat() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.copytree">copytree() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.CrashHandler.html#IPython.CrashHandler.CrashHandler">CrashHandler (class in IPython.CrashHandler)</a></dt>
+<dt><a href="api/generated/IPython.wildcard.html#IPython.wildcard.create_typestr2type_dicts">create_typestr2type_dicts() (in module IPython.wildcard)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.wxIPython.html#IPython.gui.wx.wxIPython.MyFrame.createMenu">createMenu() (IPython.gui.wx.wxIPython.MyFrame method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.wxIPython.html#IPython.gui.wx.wxIPython.MyFrame.createStatus">createStatus() (IPython.gui.wx.wxIPython.MyFrame method)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.ctime">ctime (IPython.external.path.path attribute)</a></dt>
+<dt><a href="api/generated/IPython.kernel.util.html#IPython.kernel.util.curry">curry() (in module IPython.kernel.util)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.prompts.html#IPython.kernel.core.prompts.BasePrompt.cwd_filt">cwd_filt() (IPython.kernel.core.prompts.BasePrompt method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.Prompts.html#IPython.Prompts.BasePrompt.cwd_filt">(IPython.Prompts.BasePrompt method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.core.prompts.html#IPython.kernel.core.prompts.BasePrompt.cwd_filt2">cwd_filt2() (IPython.kernel.core.prompts.BasePrompt method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.Prompts.html#IPython.Prompts.BasePrompt.cwd_filt2">(IPython.Prompts.BasePrompt method)</a></dt>
+ </dl></dd>
+</dl></td></tr></table>
+
+<h2 id="D">D</h2>
+<table width="100%" class="indextable"><tr><td width="33%" valign="top">
+<dl>
+
+<dt><a href="api/generated/IPython.ipapi.html#IPython.ipapi.IPApi.db">db (IPython.ipapi.IPApi attribute)</a></dt>
+<dt><a href="api/generated/IPython.ipapi.html#IPython.ipapi.DebugTools.debug_stack">debug_stack() (IPython.ipapi.DebugTools method)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.debugger">debugger() (IPython.iplib.InteractiveShell method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.ultraTB.html#IPython.ultraTB.VerboseTB.debugger">(IPython.ultraTB.VerboseTB method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.ipapi.html#IPython.ipapi.DebugTools">DebugTools (class in IPython.ipapi)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.debugx">debugx() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.Section.decode">decode() (IPython.external.configobj.Section method)</a></dt>
+<dt><a href="api/generated/IPython.Debugger.html#IPython.Debugger.decorate_fn_with_doc">decorate_fn_with_doc() (in module IPython.Debugger)</a></dt>
+<dt><a href="api/generated/IPython.testing.decorator_msim.html#IPython.testing.decorator_msim.decorator">decorator() (in module IPython.testing.decorator_msim)</a></dt>
+<dt><a href="api/generated/IPython.deep_reload.html#IPython.deep_reload.deep_import_hook">deep_import_hook() (in module IPython.deep_reload)</a></dt>
+<dt><a href="api/generated/IPython.deep_reload.html#IPython.deep_reload.deep_reload_hook">deep_reload_hook() (in module IPython.deep_reload)</a></dt>
+<dt><a href="api/generated/IPython.ipapi.html#IPython.ipapi.IPApi.defalias">defalias() (IPython.ipapi.IPApi method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.interpreter.html#IPython.kernel.core.interpreter.default_display_formatters">default_display_formatters() (in module IPython.kernel.core.interpreter)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.default_option">default_option() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.interpreter.html#IPython.kernel.core.interpreter.default_traceback_formatters">default_traceback_formatters() (in module IPython.kernel.core.interpreter)</a></dt>
+<dt><a href="api/generated/IPython.kernel.twistedutil.html#IPython.kernel.twistedutil.DeferredList">DeferredList (class in IPython.kernel.twistedutil)</a></dt>
+<dt><a href="api/generated/IPython.testing.util.html#IPython.testing.util.DeferredTestCase">DeferredTestCase (class in IPython.testing.util)</a></dt>
+<dt><a href="api/generated/IPython.ipapi.html#IPython.ipapi.IPApi.defmacro">defmacro() (IPython.ipapi.IPApi method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.EngineFromReference.del_properties">del_properties() (IPython.kernel.enginefc.EngineFromReference method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.EngineService.del_properties">(IPython.kernel.engineservice.EngineService method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.QueuedEngine.del_properties">(IPython.kernel.engineservice.QueuedEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.MultiEngine.del_properties">(IPython.kernel.multiengine.MultiEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.SynchronousMultiEngine.del_properties">(IPython.kernel.multiengine.SynchronousMultiEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.FullBlockingMultiEngineClient.del_properties">(IPython.kernel.multiengineclient.FullBlockingMultiEngineClient method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient.del_properties">(IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.pendingdeferred.html#IPython.kernel.pendingdeferred.PendingDeferredManager.delete_pending_deferred">delete_pending_deferred() (IPython.kernel.pendingdeferred.PendingDeferredManager method)</a></dt>
+<dt><a href="api/generated/IPython.demo.html#IPython.demo.Demo">Demo (class in IPython.demo)</a></dt>
+<dt><a href="api/generated/IPython.demo.html#IPython.demo.DemoError">DemoError (class in IPython.demo)</a></dt>
+<dt><a href="api/generated/IPython.external.pretty.html#IPython.external.pretty.GroupQueue.deq">deq() (IPython.external.pretty.GroupQueue method)</a></dt>
+<dt><a href="api/generated/IPython.deep_reload.html#IPython.deep_reload.determine_parent">determine_parent() (in module IPython.deep_reload)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.dgrep">dgrep() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.dhook_wrap">dhook_wrap() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.numutils.html#IPython.numutils.diagonal_matrix">diagonal_matrix() (in module IPython.numutils)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.Section.dict">dict() (IPython.external.configobj.Section method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.ipstruct.html#IPython.ipstruct.Struct.dict">(IPython.ipstruct.Struct method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.ipstruct.html#IPython.ipstruct.Struct.dictcopy">dictcopy() (IPython.ipstruct.Struct method)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.dir2">dir2() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.dirname">dirname() (IPython.external.path.path method)</a></dt></dl></td><td width="33%" valign="top"><dl>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.dirs">dirs() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.strdispatch.html#IPython.strdispatch.StrDispatch.dispatch">dispatch() (IPython.strdispatch.StrDispatch method)</a></dt>
+<dt><a href="api/generated/IPython.completer.html#IPython.completer.IPCompleter.dispatch_custom_completer">dispatch_custom_completer() (IPython.completer.IPCompleter method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.prompts.html#IPython.kernel.core.prompts.CachedOutput.display">display() (IPython.kernel.core.prompts.CachedOutput method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.Prompts.html#IPython.Prompts.CachedOutput.display">(IPython.Prompts.CachedOutput method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.core.display_trap.html#IPython.kernel.core.display_trap.DisplayTrap">DisplayTrap (class in IPython.kernel.core.display_trap)</a></dt>
+<dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.TaskController.distributeTasks">distributeTasks() (IPython.kernel.task.TaskController method)</a></dt>
+<dt><a href="api/generated/IPython.frontend.wx.wx_frontend.html#IPython.frontend.wx.wx_frontend.WxController.do_calltip">do_calltip() (IPython.frontend.wx.wx_frontend.WxController method)</a></dt>
+<dt><a href="api/generated/IPython.Debugger.html#IPython.Debugger.Pdb.do_d">do_d() (IPython.Debugger.Pdb method)</a></dt>
+<dt><a href="api/generated/IPython.Debugger.html#IPython.Debugger.Pdb.do_down">do_down() (IPython.Debugger.Pdb method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipshell_nonblocking.html#IPython.gui.wx.ipshell_nonblocking.NonBlockingIPShell.do_execute">do_execute() (IPython.gui.wx.ipshell_nonblocking.NonBlockingIPShell method)</a></dt>
+<dt><a href="api/generated/IPython.frontend.prefilterfrontend.html#IPython.frontend.prefilterfrontend.PrefilterFrontEnd.do_exit">do_exit() (IPython.frontend.prefilterfrontend.PrefilterFrontEnd method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.frontend.wx.ipythonx.html#IPython.frontend.wx.ipythonx.IPythonXController.do_exit">(IPython.frontend.wx.ipythonx.IPythonXController method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.Debugger.html#IPython.Debugger.Pdb.do_l">do_l() (IPython.Debugger.Pdb method)</a></dt>
+<dt><a href="api/generated/IPython.Debugger.html#IPython.Debugger.Pdb.do_list">do_list() (IPython.Debugger.Pdb method)</a></dt>
+<dt><a href="api/generated/IPython.Debugger.html#IPython.Debugger.Pdb.do_pdef">do_pdef() (IPython.Debugger.Pdb method)</a></dt>
+<dt><a href="api/generated/IPython.Debugger.html#IPython.Debugger.Pdb.do_pdoc">do_pdoc() (IPython.Debugger.Pdb method)</a></dt>
+<dt><a href="api/generated/IPython.Debugger.html#IPython.Debugger.Pdb.do_pinfo">do_pinfo() (IPython.Debugger.Pdb method)</a></dt>
+<dt><a href="api/generated/IPython.Debugger.html#IPython.Debugger.Pdb.do_q">do_q() (IPython.Debugger.Pdb method)</a></dt>
+<dt><a href="api/generated/IPython.Debugger.html#IPython.Debugger.Pdb.do_quit">do_quit() (IPython.Debugger.Pdb method)</a></dt>
+<dt><a href="api/generated/IPython.Debugger.html#IPython.Debugger.Pdb.do_u">do_u() (IPython.Debugger.Pdb method)</a></dt>
+<dt><a href="api/generated/IPython.Debugger.html#IPython.Debugger.Pdb.do_up">do_up() (IPython.Debugger.Pdb method)</a></dt>
+<dt><a href="api/generated/IPython.testing.plugin.test_refs.html#IPython.testing.plugin.test_refs.doctest_ivars">doctest_ivars() (in module IPython.testing.plugin.test_refs)</a></dt>
+<dt><a href="api/generated/IPython.testing.plugin.test_ipdoctest.html#IPython.testing.plugin.test_ipdoctest.doctest_multiline1">doctest_multiline1() (in module IPython.testing.plugin.test_ipdoctest)</a></dt>
+<dt><a href="api/generated/IPython.testing.plugin.test_ipdoctest.html#IPython.testing.plugin.test_ipdoctest.doctest_multiline2">doctest_multiline2() (in module IPython.testing.plugin.test_ipdoctest)</a></dt>
+<dt><a href="api/generated/IPython.testing.plugin.test_ipdoctest.html#IPython.testing.plugin.test_ipdoctest.doctest_multiline3">doctest_multiline3() (in module IPython.testing.plugin.test_ipdoctest)</a></dt>
+<dt><a href="api/generated/IPython.testing.plugin.test_refs.html#IPython.testing.plugin.test_refs.doctest_refs">doctest_refs() (in module IPython.testing.plugin.test_refs)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.doctest_reload">doctest_reload() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.testing.plugin.test_refs.html#IPython.testing.plugin.test_refs.doctest_run">doctest_run() (in module IPython.testing.plugin.test_refs)</a></dt>
+<dt><a href="api/generated/IPython.testing.plugin.test_ipdoctest.html#IPython.testing.plugin.test_ipdoctest.doctest_run_builtins">doctest_run_builtins() (in module IPython.testing.plugin.test_ipdoctest)</a></dt>
+<dt><a href="api/generated/IPython.testing.plugin.test_refs.html#IPython.testing.plugin.test_refs.doctest_runvars">doctest_runvars() (in module IPython.testing.plugin.test_refs)</a></dt>
+<dt><a href="api/generated/IPython.testing.plugin.test_ipdoctest.html#IPython.testing.plugin.test_ipdoctest.doctest_simple">doctest_simple() (in module IPython.testing.plugin.test_ipdoctest)</a></dt>
+<dt><a href="api/generated/IPython.external.validate.html#IPython.external.validate.dottedQuadToNum">dottedQuadToNum() (in module IPython.external.validate)</a></dt>
+<dt><a href="api/generated/IPython.DPyGetOpt.html#IPython.DPyGetOpt.DPyGetOpt">DPyGetOpt (class in IPython.DPyGetOpt)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.drive">drive (IPython.external.path.path attribute)</a></dt>
+<dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.drop_engine">drop_engine() (in module IPython.kernel.engineservice)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.DuplicateError">DuplicateError (class in IPython.external.configobj)</a></dt>
+</dl></td></tr></table>
+
+<h2 id="E">E</h2>
+<table width="100%" class="indextable"><tr><td width="33%" valign="top">
+<dl>
+
+<dt><a href="api/generated/IPython.demo.html#IPython.demo.Demo.edit">edit() (IPython.demo.Demo method)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.edit_syntax_error">edit_syntax_error() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.hooks.html#IPython.hooks.editor">editor() (in module IPython.hooks)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.embed_mainloop">embed_mainloop() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.numutils.html#IPython.numutils.empty_like">empty_like() (in module IPython.numutils)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.Section.encode">encode() (IPython.external.configobj.Section method)</a></dt>
+<dt><a href="api/generated/IPython.external.pretty.html#IPython.external.pretty.PrettyPrinter.end_group">end_group() (IPython.external.pretty.PrettyPrinter method)</a></dt>
+<dt><a href="api/generated/IPython.external.argparse.html#IPython.external.argparse.HelpFormatter.end_section">end_section() (IPython.external.argparse.HelpFormatter method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.EngineAPI">EngineAPI (class in IPython.kernel.engineservice)</a></dt>
+<dt><a href="api/generated/IPython.kernel.engineconnector.html#IPython.kernel.engineconnector.EngineConnector">EngineConnector (class in IPython.kernel.engineconnector)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.error.html#IPython.kernel.core.error.EngineCreationError">EngineCreationError (class in IPython.kernel.core.error)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.error.html#IPython.kernel.core.error.EngineError">EngineError (class in IPython.kernel.core.error)</a></dt>
+<dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.EngineFromReference">EngineFromReference (class in IPython.kernel.enginefc)</a></dt>
+<dt><a href="api/generated/IPython.kernel.scripts.ipcluster.html#IPython.kernel.scripts.ipcluster.EngineLauncher">EngineLauncher (class in IPython.kernel.scripts.ipcluster)</a></dt>
+<dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.MultiEngine.engineList">engineList() (IPython.kernel.multiengine.MultiEngine method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.EngineService">EngineService (class in IPython.kernel.engineservice)</a></dt>
+<dt><a href="api/generated/IPython.external.pretty.html#IPython.external.pretty.GroupQueue.enq">enq() (IPython.external.pretty.GroupQueue method)</a></dt>
+<dt><a href="api/generated/IPython.deep_reload.html#IPython.deep_reload.ensure_fromlist">ensure_fromlist() (in module IPython.deep_reload)</a></dt>
+<dt>environment variable</dt>
+ <dd><dl>
+ <dt><a href="overview.html#index-0">PATH</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.core.output_trap.html#IPython.kernel.core.output_trap.OutputTrap.err_text">err_text (IPython.kernel.core.output_trap.OutputTrap attribute)</a></dt>
+<dt><a href="api/generated/IPython.DPyGetOpt.html#IPython.DPyGetOpt.Error">Error (class in IPython.DPyGetOpt)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.genutils.html#IPython.genutils.Error">(class in IPython.genutils)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.error">error() (in module IPython.genutils)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.external.argparse.html#IPython.external.argparse.ArgumentParser.error">(IPython.external.argparse.ArgumentParser method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.interpreter.html#IPython.kernel.core.interpreter.Interpreter.error">(IPython.kernel.core.interpreter.Interpreter method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.scripts.ipcluster.html#IPython.kernel.scripts.ipcluster.LauncherProcessProtocol.errReceived">errReceived() (IPython.kernel.scripts.ipcluster.LauncherProcessProtocol method)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.esc_quotes">esc_quotes() (in module IPython.genutils)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.core.util.html#IPython.kernel.core.util.esc_quotes">(in module IPython.kernel.core.util)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.ipapi.html#IPython.ipapi.IPApi.ev">ev() (IPython.ipapi.IPApi method)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.EvalDict">EvalDict (class in IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_history.html#IPython.gui.wx.ipython_history.IPythonHistoryPanel.evtCheckCmdFilter">evtCheckCmdFilter() (IPython.gui.wx.ipython_history.IPythonHistoryPanel method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_history.html#IPython.gui.wx.ipython_history.IPythonHistoryPanel.evtCheckDocFilter">evtCheckDocFilter() (IPython.gui.wx.ipython_history.IPythonHistoryPanel method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_history.html#IPython.gui.wx.ipython_history.IPythonHistoryPanel.evtCheckEmptyFilter">evtCheckEmptyFilter() (IPython.gui.wx.ipython_history.IPythonHistoryPanel method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_history.html#IPython.gui.wx.ipython_history.IPythonHistoryPanel.evtCheckMagicFilter">evtCheckMagicFilter() (IPython.gui.wx.ipython_history.IPythonHistoryPanel method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.IPShellWidget.evtCheckOptionBackgroundColor">evtCheckOptionBackgroundColor() (IPython.gui.wx.ipython_view.IPShellWidget method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.IPShellWidget.evtCheckOptionCompletion">evtCheckOptionCompletion() (IPython.gui.wx.ipython_view.IPShellWidget method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.IPShellWidget.evtCheckOptionThreading">evtCheckOptionThreading() (IPython.gui.wx.ipython_view.IPShellWidget method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.IPShellWidget.evtStateExecuteDone">evtStateExecuteDone() (IPython.gui.wx.ipython_view.IPShellWidget method)</a></dt>
+<dt><a href="api/generated/IPython.ipapi.html#IPython.ipapi.IPApi.ex">ex() (IPython.ipapi.IPApi method)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.excepthook">excepthook() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.excolors.html#IPython.excolors.exception_colors">exception_colors() (in module IPython.excolors)</a></dt></dl></td><td width="33%" valign="top"><dl>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.exec_init_cmd">exec_init_cmd() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.frontend.asyncfrontendbase.html#IPython.frontend.asyncfrontendbase.AsyncFrontEndBase.execute">execute() (IPython.frontend.asyncfrontendbase.AsyncFrontEndBase method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.frontend.frontendbase.html#IPython.frontend.frontendbase.FrontEndBase.execute">(IPython.frontend.frontendbase.FrontEndBase method)</a></dt>
+ <dt><a href="api/generated/IPython.frontend.linefrontendbase.html#IPython.frontend.linefrontendbase.LineFrontEndBase.execute">(IPython.frontend.linefrontendbase.LineFrontEndBase method)</a></dt>
+ <dt><a href="api/generated/IPython.frontend.prefilterfrontend.html#IPython.frontend.prefilterfrontend.PrefilterFrontEnd.execute">(IPython.frontend.prefilterfrontend.PrefilterFrontEnd method)</a></dt>
+ <dt><a href="api/generated/IPython.frontend.wx.wx_frontend.html#IPython.frontend.wx.wx_frontend.WxController.execute">(IPython.frontend.wx.wx_frontend.WxController method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.interpreter.html#IPython.kernel.core.interpreter.Interpreter.execute">(IPython.kernel.core.interpreter.Interpreter method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.EngineFromReference.execute">(IPython.kernel.enginefc.EngineFromReference method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.EngineService.execute">(IPython.kernel.engineservice.EngineService method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.QueuedEngine.execute">(IPython.kernel.engineservice.QueuedEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.ThreadedEngineService.execute">(IPython.kernel.engineservice.ThreadedEngineService method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.MultiEngine.execute">(IPython.kernel.multiengine.MultiEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.SynchronousMultiEngine.execute">(IPython.kernel.multiengine.SynchronousMultiEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.FullBlockingMultiEngineClient.execute">(IPython.kernel.multiengineclient.FullBlockingMultiEngineClient method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient.execute">(IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.core.interpreter.html#IPython.kernel.core.interpreter.Interpreter.execute_block">execute_block() (IPython.kernel.core.interpreter.Interpreter method)</a></dt>
+<dt><a href="api/generated/IPython.frontend.linefrontendbase.html#IPython.frontend.linefrontendbase.LineFrontEndBase.execute_command">execute_command() (IPython.frontend.linefrontendbase.LineFrontEndBase method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.frontend.wx.wx_frontend.html#IPython.frontend.wx.wx_frontend.WxController.execute_command">(IPython.frontend.wx.wx_frontend.WxController method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.core.interpreter.html#IPython.kernel.core.interpreter.Interpreter.execute_macro">execute_macro() (IPython.kernel.core.interpreter.Interpreter method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.interpreter.html#IPython.kernel.core.interpreter.Interpreter.execute_python">execute_python() (IPython.kernel.core.interpreter.Interpreter method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.EngineService.executeAndRaise">executeAndRaise() (IPython.kernel.engineservice.EngineService method)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.exists">exists() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.external.argparse.html#IPython.external.argparse.ArgumentParser.exit">exit() (IPython.external.argparse.ArgumentParser method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.exit">(IPython.iplib.InteractiveShell method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.numutils.html#IPython.numutils.exp_safe">exp_safe() (in module IPython.numutils)</a></dt>
+<dt><a href="api/generated/IPython.external.mglob.html#IPython.external.mglob.expand">expand() (in module IPython.external.mglob)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.expand">(IPython.external.path.path method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.gui.wx.ipython_history.html#IPython.gui.wx.ipython_history.PythonSTC.Expand">Expand() (IPython.gui.wx.ipython_history.PythonSTC method)</a></dt>
+<dt><a href="api/generated/IPython.ipapi.html#IPython.ipapi.IPApi.expand_alias">expand_alias() (IPython.ipapi.IPApi method)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.expand_aliases">expand_aliases() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.expanduser">expanduser() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.expandvars">expandvars() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.ipapi.html#IPython.ipapi.IPApi.expose_magic">expose_magic() (IPython.ipapi.IPApi method)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.ext">ext (IPython.external.path.path attribute)</a></dt>
+<dt><a href="api/generated/IPython.external.guid.html#IPython.external.guid.extract_counter">extract_counter() (in module IPython.external.guid)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.extract_input_slices">extract_input_slices() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.external.guid.html#IPython.external.guid.extract_ip">extract_ip() (in module IPython.external.guid)</a></dt>
+<dt><a href="api/generated/IPython.external.guid.html#IPython.external.guid.extract_time">extract_time() (in module IPython.external.guid)</a></dt>
+<dt><a href="api/generated/IPython.tools.utils.html#IPython.tools.utils.extractVars">extractVars() (in module IPython.tools.utils)</a></dt>
+<dt><a href="api/generated/IPython.tools.utils.html#IPython.tools.utils.extractVarsAbove">extractVarsAbove() (in module IPython.tools.utils)</a></dt>
+</dl></td></tr></table>
+
+<h2 id="F">F</h2>
+<table width="100%" class="indextable"><tr><td width="33%" valign="top">
+<dl>
+
+<dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.TaskController.failIdle">failIdle() (IPython.kernel.task.TaskController method)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.fatal">fatal() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.FCEngineReferenceFromService">FCEngineReferenceFromService (class in IPython.kernel.enginefc)</a></dt>
+<dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient">FCFullSynchronousMultiEngineClient (class in IPython.kernel.multienginefc)</a></dt>
+<dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.FCRemoteEngineRefFromService">FCRemoteEngineRefFromService (class in IPython.kernel.enginefc)</a></dt>
+<dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCSynchronousMultiEngineFromMultiEngine">FCSynchronousMultiEngineFromMultiEngine (class in IPython.kernel.multienginefc)</a></dt>
+<dt><a href="api/generated/IPython.kernel.taskfc.html#IPython.kernel.taskfc.FCTaskClient">FCTaskClient (class in IPython.kernel.taskfc)</a></dt>
+<dt><a href="api/generated/IPython.kernel.taskfc.html#IPython.kernel.taskfc.FCTaskControllerFromTaskController">FCTaskControllerFromTaskController (class in IPython.kernel.taskfc)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.fd_redirector.html#IPython.kernel.core.fd_redirector.FDRedirector">FDRedirector (class in IPython.kernel.core.fd_redirector)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.interpreter.html#IPython.kernel.core.interpreter.Interpreter.feed_block">feed_block() (IPython.kernel.core.interpreter.Interpreter method)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.SList.fields">fields() (IPython.genutils.SList method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.FIFOScheduler">FIFOScheduler (class in IPython.kernel.task)</a></dt>
+<dt><a href="api/generated/IPython.completer.html#IPython.completer.IPCompleter.file_matches">file_matches() (IPython.completer.IPCompleter method)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.file_read">file_read() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.file_readlines">file_readlines() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.filefind">filefind() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.file_like.html#IPython.kernel.core.file_like.FileLike">FileLike (class in IPython.kernel.core.file_like)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.files">files() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.FileTimeoutError">FileTimeoutError (class in IPython.kernel.error)</a></dt>
+<dt><a href="api/generated/IPython.external.argparse.html#IPython.external.argparse.FileType">FileType (class in IPython.external.argparse)</a></dt>
+<dt><a href="api/generated/IPython.external.Itpl.html#IPython.external.Itpl.filter">filter() (in module IPython.external.Itpl)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.wildcard.html#IPython.wildcard.NameSpace.filter">(IPython.wildcard.NameSpace method)</a></dt>
+ <dt><a href="api/generated/IPython.Itpl.html#IPython.Itpl.filter">(in module IPython.Itpl)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.platutils.html#IPython.platutils.find_cmd">find_cmd() (in module IPython.platutils)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.platutils_dummy.html#IPython.platutils_dummy.find_cmd">(in module IPython.platutils_dummy)</a></dt>
+ <dt><a href="api/generated/IPython.platutils_posix.html#IPython.platutils_posix.find_cmd">(in module IPython.platutils_posix)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.fcutil.html#IPython.kernel.fcutil.find_furl">find_furl() (in module IPython.kernel.fcutil)</a></dt>
+<dt><a href="api/generated/IPython.deep_reload.html#IPython.deep_reload.find_head_package">find_head_package() (in module IPython.deep_reload)</a></dt>
+<dt><a href="api/generated/IPython.platutils.html#IPython.platutils.FindCmdError">FindCmdError (class in IPython.platutils)</a></dt>
+<dt><a href="api/generated/IPython.ultraTB.html#IPython.ultraTB.findsource">findsource() (in module IPython.ultraTB)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.contexts.html#IPython.kernel.contexts.RemoteContextBase.findsource">(IPython.kernel.contexts.RemoteContextBase method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.InteractiveMultiEngineClient.findsource_file">findsource_file() (IPython.kernel.multiengineclient.InteractiveMultiEngineClient method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.InteractiveMultiEngineClient.findsource_ipython">findsource_ipython() (IPython.kernel.multiengineclient.InteractiveMultiEngineClient method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.QueuedEngine.finishCommand">finishCommand() (IPython.kernel.engineservice.QueuedEngine method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.scripts.ipcluster.html#IPython.kernel.scripts.ipcluster.ProcessLauncher.fire_start_deferred">fire_start_deferred() (IPython.kernel.scripts.ipcluster.ProcessLauncher method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.scripts.ipcluster.html#IPython.kernel.scripts.ipcluster.ProcessLauncher.fire_stop_deferred">fire_stop_deferred() (IPython.kernel.scripts.ipcluster.ProcessLauncher method)</a></dt>
+<dt><a href="api/generated/IPython.hooks.html#IPython.hooks.fix_error_editor">fix_error_editor() (in module IPython.hooks)</a></dt>
+<dt><a href="api/generated/IPython.ultraTB.html#IPython.ultraTB.fix_frame_records_filenames">fix_frame_records_filenames() (in module IPython.ultraTB)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.flag_calls">flag_calls() (in module IPython.genutils)</a></dt></dl></td><td width="33%" valign="top"><dl>
+<dt><a href="api/generated/IPython.strdispatch.html#IPython.strdispatch.StrDispatch.flat_matches">flat_matches() (IPython.strdispatch.StrDispatch method)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.flatten">flatten() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.flatten_errors">flatten_errors() (in module IPython.external.configobj)</a></dt>
+<dt><a href="api/generated/IPython.external.pretty.html#IPython.external.pretty.PrettyPrinter.flush">flush() (IPython.external.pretty.PrettyPrinter method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.OutputTrap.html#IPython.OutputTrap.OutputTrap.flush">(IPython.OutputTrap.OutputTrap method)</a></dt>
+ <dt><a href="api/generated/IPython.Prompts.html#IPython.Prompts.CachedOutput.flush">(IPython.Prompts.CachedOutput method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.fd_redirector.html#IPython.kernel.core.fd_redirector.FDRedirector.flush">(IPython.kernel.core.fd_redirector.FDRedirector method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.file_like.html#IPython.kernel.core.file_like.FileLike.flush">(IPython.kernel.core.file_like.FileLike method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.prompts.html#IPython.kernel.core.prompts.CachedOutput.flush">(IPython.kernel.core.prompts.CachedOutput method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.FullBlockingMultiEngineClient.flush">(IPython.kernel.multiengineclient.FullBlockingMultiEngineClient method)</a></dt>
+ <dt><a href="api/generated/IPython.testing.mkdoctests.html#IPython.testing.mkdoctests.IndentOut.flush">(IPython.testing.mkdoctests.IndentOut method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.OutputTrap.html#IPython.OutputTrap.OutputTrap.flush_all">flush_all() (IPython.OutputTrap.OutputTrap method)</a></dt>
+<dt><a href="api/generated/IPython.OutputTrap.html#IPython.OutputTrap.OutputTrap.flush_err">flush_err() (IPython.OutputTrap.OutputTrap method)</a></dt>
+<dt><a href="api/generated/IPython.background_jobs.html#IPython.background_jobs.BackgroundJobManager.flush_finished">flush_finished() (IPython.background_jobs.BackgroundJobManager method)</a></dt>
+<dt><a href="api/generated/IPython.OutputTrap.html#IPython.OutputTrap.OutputTrap.flush_out">flush_out() (IPython.OutputTrap.OutputTrap method)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.fnmatch">fnmatch() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_history.html#IPython.gui.wx.ipython_history.PythonSTC.FoldAll">FoldAll() (IPython.gui.wx.ipython_history.PythonSTC method)</a></dt>
+<dt><a href="api/generated/IPython.external.pretty.html#IPython.external.pretty.for_type">for_type() (in module IPython.external.pretty)</a></dt>
+<dt><a href="api/generated/IPython.external.pretty.html#IPython.external.pretty.for_type_by_name">for_type_by_name() (in module IPython.external.pretty)</a></dt>
+<dt><a href="api/generated/IPython.ipmaker.html#IPython.ipmaker.force_import">force_import() (in module IPython.ipmaker)</a></dt>
+<dt><a href="api/generated/IPython.PyColorize.html#IPython.PyColorize.Parser.format">format() (IPython.PyColorize.Parser method)</a></dt>
+<dt><a href="api/generated/IPython.PyColorize.html#IPython.PyColorize.Parser.format2">format2() (IPython.PyColorize.Parser method)</a></dt>
+<dt><a href="api/generated/IPython.external.argparse.html#IPython.external.argparse.ArgumentParser.format_help">format_help() (IPython.external.argparse.ArgumentParser method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.external.argparse.html#IPython.external.argparse.HelpFormatter.format_help">(IPython.external.argparse.HelpFormatter method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.format_latex">format_latex() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.format_screen">format_screen() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Debugger.html#IPython.Debugger.Pdb.format_stack_entry">format_stack_entry() (IPython.Debugger.Pdb method)</a></dt>
+<dt><a href="api/generated/IPython.external.argparse.html#IPython.external.argparse.ArgumentParser.format_usage">format_usage() (IPython.external.argparse.ArgumentParser method)</a></dt>
+<dt><a href="api/generated/IPython.external.argparse.html#IPython.external.argparse.ArgumentParser.format_version">format_version() (IPython.external.argparse.ArgumentParser method)</a></dt>
+<dt><a href="api/generated/IPython.ultraTB.html#IPython.ultraTB.FormattedTB">FormattedTB (class in IPython.ultraTB)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.interpreter.html#IPython.kernel.core.interpreter.Interpreter.formatTraceback">formatTraceback() (IPython.kernel.core.interpreter.Interpreter method)</a></dt>
+<dt><a href="api/generated/IPython.numutils.html#IPython.numutils.frange">frange() (in module IPython.numutils)</a></dt>
+<dt><a href="api/generated/IPython.platutils.html#IPython.platutils.freeze_term_title">freeze_term_title() (in module IPython.platutils)</a></dt>
+<dt><a href="api/generated/IPython.numutils.html#IPython.numutils.fromfunction_kw">fromfunction_kw() (in module IPython.numutils)</a></dt>
+<dt><a href="api/generated/IPython.frontend.frontendbase.html#IPython.frontend.frontendbase.FrontEndBase">FrontEndBase (class in IPython.frontend.frontendbase)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.history.html#IPython.kernel.core.history.FrontEndHistory">FrontEndHistory (class in IPython.kernel.core.history)</a></dt>
+<dt><a href="api/generated/IPython.testing.tools.html#IPython.testing.tools.full_path">full_path() (in module IPython.testing.tools)</a></dt>
+<dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.FullBlockingMultiEngineClient">FullBlockingMultiEngineClient (class in IPython.kernel.multiengineclient)</a></dt>
+</dl></td></tr></table>
+
+<h2 id="G">G</h2>
+<table width="100%" class="indextable"><tr><td width="33%" valign="top">
+<dl>
+
+<dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.FullBlockingMultiEngineClient.gather">gather() (IPython.kernel.multiengineclient.FullBlockingMultiEngineClient method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient.gather">(IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.twistedutil.html#IPython.kernel.twistedutil.gatherBoth">gatherBoth() (in module IPython.kernel.twistedutil)</a></dt>
+<dt><a href="api/generated/IPython.external.guid.html#IPython.external.guid.generate">generate() (in module IPython.external.guid)</a></dt>
+<dt><a href="api/generated/IPython.hooks.html#IPython.hooks.generate_output_prompt">generate_output_prompt() (in module IPython.hooks)</a></dt>
+<dt><a href="api/generated/IPython.hooks.html#IPython.hooks.generate_prompt">generate_prompt() (in module IPython.hooks)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.core.interpreter.html#IPython.kernel.core.interpreter.Interpreter.generate_prompt">(IPython.kernel.core.interpreter.Interpreter method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.external.simplegeneric.html#IPython.external.simplegeneric.generic">generic() (in module IPython.external.simplegeneric)</a></dt>
+<dt><a href="api/generated/IPython.ipapi.html#IPython.ipapi.get">get() (in module IPython.ipapi)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.Section.get">(IPython.external.configobj.Section method)</a></dt>
+ <dt><a href="api/generated/IPython.history.html#IPython.history.ShadowHist.get">(IPython.history.ShadowHist method)</a></dt>
+ <dt><a href="api/generated/IPython.ipstruct.html#IPython.ipstruct.Struct.get">(IPython.ipstruct.Struct method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.scripts.ipcluster.html#IPython.kernel.scripts.ipcluster.get_args">get_args() (in module IPython.kernel.scripts.ipcluster)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipshell_nonblocking.html#IPython.gui.wx.ipshell_nonblocking.NonBlockingIPShell.get_banner">get_banner() (IPython.gui.wx.ipshell_nonblocking.NonBlockingIPShell method)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.get_class_members">get_class_members() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.kernel.clientconnector.html#IPython.kernel.clientconnector.ClientConnector.get_client">get_client() (IPython.kernel.clientconnector.ClientConnector method)</a></dt>
+<dt><a href="api/generated/IPython.config.api.html#IPython.config.api.ConfigObjManager.get_config_obj">get_config_obj() (IPython.config.api.ConfigObjManager method)</a></dt>
+<dt><a href="api/generated/IPython.winconsole.html#IPython.winconsole.get_console_size">get_console_size() (in module IPython.winconsole)</a></dt>
+<dt><a href="api/generated/IPython.ipapi.html#IPython.ipapi.IPApi.get_db">get_db() (IPython.ipapi.IPApi method)</a></dt>
+<dt><a href="api/generated/IPython.external.validate.html#IPython.external.validate.Validator.get_default_value">get_default_value() (IPython.external.validate.Validator method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.pendingdeferred.html#IPython.kernel.pendingdeferred.PendingDeferredManager.get_deferred_id">get_deferred_id() (IPython.kernel.pendingdeferred.PendingDeferredManager method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipshell_nonblocking.html#IPython.gui.wx.ipshell_nonblocking.NonBlockingIPShell.get_doc_text">get_doc_text() (IPython.gui.wx.ipshell_nonblocking.NonBlockingIPShell method)</a></dt>
+<dt><a href="api/generated/IPython.Shell.html#IPython.Shell.IPShellEmbed.get_dummy_mode">get_dummy_mode() (IPython.Shell.IPShellEmbed method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.get_engine">get_engine() (in module IPython.kernel.engineservice)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipshell_nonblocking.html#IPython.gui.wx.ipshell_nonblocking.NonBlockingIPShell.get_help_text">get_help_text() (IPython.gui.wx.ipshell_nonblocking.NonBlockingIPShell method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.history.html#IPython.kernel.core.history.History.get_history_item">get_history_item() (IPython.kernel.core.history.History method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.core.history.html#IPython.kernel.core.history.InterpreterHistory.get_history_item">(IPython.kernel.core.history.InterpreterHistory method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.frontend.frontendbase.html#IPython.frontend.frontendbase.FrontEndBase.get_history_next">get_history_next() (IPython.frontend.frontendbase.FrontEndBase method)</a></dt>
+<dt><a href="api/generated/IPython.frontend.frontendbase.html#IPython.frontend.frontendbase.FrontEndBase.get_history_previous">get_history_previous() (IPython.frontend.frontendbase.FrontEndBase method)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.get_home_dir">get_home_dir() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.EngineFromReference.get_id">get_id() (IPython.kernel.enginefc.EngineFromReference method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.MultiEngine.get_ids">get_ids() (IPython.kernel.multiengine.MultiEngine method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.SynchronousMultiEngine.get_ids">(IPython.kernel.multiengine.SynchronousMultiEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.FullBlockingMultiEngineClient.get_ids">(IPython.kernel.multiengineclient.FullBlockingMultiEngineClient method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient.get_ids">(IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.gui.wx.ipshell_nonblocking.html#IPython.gui.wx.ipshell_nonblocking.NonBlockingIPShell.get_indentation">get_indentation() (IPython.gui.wx.ipshell_nonblocking.NonBlockingIPShell method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.history.html#IPython.kernel.core.history.InterpreterHistory.get_input_after">get_input_after() (IPython.kernel.core.history.InterpreterHistory method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.history.html#IPython.kernel.core.history.InterpreterHistory.get_input_cache">get_input_cache() (IPython.kernel.core.history.InterpreterHistory method)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.get_ipython_dir">get_ipython_dir() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.frontend.linefrontendbase.html#IPython.frontend.linefrontendbase.LineFrontEndBase.get_line_width">get_line_width() (IPython.frontend.linefrontendbase.LineFrontEndBase method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.frontend.wx.console_widget.html#IPython.frontend.wx.console_widget.ConsoleWidget.get_line_width">(IPython.frontend.wx.console_widget.ConsoleWidget method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.LSString.get_list">get_list() (IPython.genutils.LSString method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.genutils.html#IPython.genutils.SList.get_list">(IPython.genutils.SList method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.get_log_dir">get_log_dir() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.platutils.html#IPython.platutils.get_long_path_name">get_long_path_name() (in module IPython.platutils)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.platutils_dummy.html#IPython.platutils_dummy.get_long_path_name">(in module IPython.platutils_dummy)</a></dt>
+ <dt><a href="api/generated/IPython.platutils_posix.html#IPython.platutils_posix.get_long_path_name">(in module IPython.platutils_posix)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.core.message_cache.html#IPython.kernel.core.message_cache.IMessageCache.get_message">get_message() (IPython.kernel.core.message_cache.IMessageCache method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.core.message_cache.html#IPython.kernel.core.message_cache.SimpleMessageCache.get_message">(IPython.kernel.core.message_cache.SimpleMessageCache method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.client.html#IPython.kernel.client.get_multiengine_client">get_multiengine_client() (in module IPython.kernel.client)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.clientconnector.html#IPython.kernel.clientconnector.ClientConnector.get_multiengine_client">(IPython.kernel.clientconnector.ClientConnector method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.LSString.get_nlstr">get_nlstr() (IPython.genutils.LSString method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.genutils.html#IPython.genutils.SList.get_nlstr">(IPython.genutils.SList method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.wildcard.html#IPython.wildcard.NameSpace.get_ns">get_ns() (IPython.wildcard.NameSpace method)</a></dt>
+<dt><a href="api/generated/IPython.wildcard.html#IPython.wildcard.NameSpace.get_ns_names">get_ns_names() (IPython.wildcard.NameSpace method)</a></dt>
+<dt><a href="api/generated/IPython.ipapi.html#IPython.ipapi.IPApi.get_options">get_options() (IPython.ipapi.IPApi method)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.get_owner">get_owner() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.get_pager_cmd">get_pager_cmd() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.get_pager_start">get_pager_start() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.LSString.get_paths">get_paths() (IPython.genutils.LSString method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.genutils.html#IPython.genutils.SList.get_paths">(IPython.genutils.SList method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.FullBlockingMultiEngineClient.get_pending_deferred">get_pending_deferred() (IPython.kernel.multiengineclient.FullBlockingMultiEngineClient method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient.get_pending_deferred">(IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.pendingdeferred.html#IPython.kernel.pendingdeferred.PendingDeferredManager.get_pending_deferred">(IPython.kernel.pendingdeferred.PendingDeferredManager method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.gui.wx.ipshell_nonblocking.html#IPython.gui.wx.ipshell_nonblocking.NonBlockingIPShell.get_prompt">get_prompt() (IPython.gui.wx.ipshell_nonblocking.NonBlockingIPShell method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipshell_nonblocking.html#IPython.gui.wx.ipshell_nonblocking.NonBlockingIPShell.get_prompt_count">get_prompt_count() (IPython.gui.wx.ipshell_nonblocking.NonBlockingIPShell method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.EngineFromReference.get_properties">get_properties() (IPython.kernel.enginefc.EngineFromReference method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.EngineService.get_properties">(IPython.kernel.engineservice.EngineService method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.QueuedEngine.get_properties">(IPython.kernel.engineservice.QueuedEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.MultiEngine.get_properties">(IPython.kernel.multiengine.MultiEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.SynchronousMultiEngine.get_properties">(IPython.kernel.multiengine.SynchronousMultiEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.FullBlockingMultiEngineClient.get_properties">(IPython.kernel.multiengineclient.FullBlockingMultiEngineClient method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient.get_properties">(IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient method)</a></dt>
+ </dl></dd></dl></td><td width="33%" valign="top"><dl>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.get_py_filename">get_py_filename() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.kernel.clientconnector.html#IPython.kernel.clientconnector.ClientConnector.get_reference">get_reference() (IPython.kernel.clientconnector.ClientConnector method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.EngineFromReference.get_result">get_result() (IPython.kernel.enginefc.EngineFromReference method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.EngineService.get_result">(IPython.kernel.engineservice.EngineService method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.QueuedEngine.get_result">(IPython.kernel.engineservice.QueuedEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.MultiEngine.get_result">(IPython.kernel.multiengine.MultiEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.SynchronousMultiEngine.get_result">(IPython.kernel.multiengine.SynchronousMultiEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.FullBlockingMultiEngineClient.get_result">(IPython.kernel.multiengineclient.FullBlockingMultiEngineClient method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.PendingResult.get_result">(IPython.kernel.multiengineclient.PendingResult method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient.get_result">(IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.get_security_dir">get_security_dir() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.get_slice">get_slice() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.LSString.get_spstr">get_spstr() (IPython.genutils.LSString method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.genutils.html#IPython.genutils.SList.get_spstr">(IPython.genutils.SList method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.scripts.ipcluster.html#IPython.kernel.scripts.ipcluster.ProcessLauncher.get_stop_deferred">get_stop_deferred() (IPython.kernel.scripts.ipcluster.ProcessLauncher method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.client.html#IPython.kernel.client.get_task_client">get_task_client() (in module IPython.kernel.client)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.clientconnector.html#IPython.kernel.clientconnector.ClientConnector.get_task_client">(IPython.kernel.clientconnector.ClientConnector method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.TaskController.get_task_result">get_task_result() (IPython.kernel.task.TaskController method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.taskclient.html#IPython.kernel.taskclient.BlockingTaskClient.get_task_result">(IPython.kernel.taskclient.BlockingTaskClient method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.taskfc.html#IPython.kernel.taskfc.FCTaskClient.get_task_result">(IPython.kernel.taskfc.FCTaskClient method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.scripts.ipcontroller.html#IPython.kernel.scripts.ipcontroller.get_temp_furlfile">get_temp_furlfile() (in module IPython.kernel.scripts.ipcontroller)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipshell_nonblocking.html#IPython.gui.wx.ipshell_nonblocking.NonBlockingIPShell.get_threading">get_threading() (IPython.gui.wx.ipshell_nonblocking.NonBlockingIPShell method)</a></dt>
+<dt><a href="api/generated/IPython.Shell.html#IPython.Shell.get_tk">get_tk() (in module IPython.Shell)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.getapi">getapi() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.OInspect.html#IPython.OInspect.getargspec">getargspec() (in module IPython.OInspect)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.getatime">getatime() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.getattr_list">getattr_list() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.WxConsoleView.getBackgroundColor">getBackgroundColor() (IPython.gui.wx.ipython_view.WxConsoleView method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.interpreter.html#IPython.kernel.core.interpreter.Interpreter.getCommand">getCommand() (IPython.kernel.core.interpreter.Interpreter method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.WxConsoleView.getCompletionMethod">getCompletionMethod() (IPython.gui.wx.ipython_view.WxConsoleView method)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.getctime">getctime() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.WxConsoleView.getCurrentLine">getCurrentLine() (IPython.gui.wx.ipython_view.WxConsoleView method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.WxConsoleView.getCurrentLineEnd">getCurrentLineEnd() (IPython.gui.wx.ipython_view.WxConsoleView method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.WxConsoleView.getCurrentLineStart">getCurrentLineStart() (IPython.gui.wx.ipython_view.WxConsoleView method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.WxConsoleView.getCurrentPromptStart">getCurrentPromptStart() (IPython.gui.wx.ipython_view.WxConsoleView method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.WxConsoleView.getCursorPos">getCursorPos() (IPython.gui.wx.ipython_view.WxConsoleView method)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.getcwd">getcwd (IPython.external.path.path attribute)</a></dt>
+<dt><a href="api/generated/IPython.kernel.newserialized.html#IPython.kernel.newserialized.Serialized.getData">getData() (IPython.kernel.newserialized.Serialized method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.newserialized.html#IPython.kernel.newserialized.SerializeIt.getData">(IPython.kernel.newserialized.SerializeIt method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.newserialized.html#IPython.kernel.newserialized.Serialized.getDataSize">getDataSize() (IPython.kernel.newserialized.Serialized method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.newserialized.html#IPython.kernel.newserialized.SerializeIt.getDataSize">(IPython.kernel.newserialized.SerializeIt method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.OInspect.html#IPython.OInspect.getdoc">getdoc() (in module IPython.OInspect)</a></dt>
+<dt><a href="api/generated/IPython.kernel.pickleutil.html#IPython.kernel.pickleutil.CannedFunction.getFunction">getFunction() (IPython.kernel.pickleutil.CannedFunction method)</a></dt>
+<dt><a href="api/generated/IPython.testing.decorator_msim.html#IPython.testing.decorator_msim.getinfo">getinfo() (in module IPython.testing.decorator_msim)</a></dt>
+<dt><a href="api/generated/IPython.kernel.newserialized.html#IPython.kernel.newserialized.Serialized.getMetadata">getMetadata() (IPython.kernel.newserialized.Serialized method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.newserialized.html#IPython.kernel.newserialized.SerializeIt.getMetadata">(IPython.kernel.newserialized.SerializeIt method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.getmtime">getmtime() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.getObj">getObj() (in module IPython.external.configobj)</a></dt>
+<dt><a href="api/generated/IPython.kernel.newserialized.html#IPython.kernel.newserialized.UnSerialized.getObject">getObject() (IPython.kernel.newserialized.UnSerialized method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.newserialized.html#IPython.kernel.newserialized.UnSerializeIt.getObject">(IPython.kernel.newserialized.UnSerializeIt method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.gui.wx.ipython_history.html#IPython.gui.wx.ipython_history.IPythonHistoryPanel.getOptions">getOptions() (IPython.gui.wx.ipython_history.IPythonHistoryPanel method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.IPShellWidget.getOptions">(IPython.gui.wx.ipython_view.IPShellWidget method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.getoutput">getoutput() (in module IPython.genutils)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.genutils.html#IPython.genutils.SystemExec.getoutput">(IPython.genutils.SystemExec method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.getoutputerror">getoutputerror() (in module IPython.genutils)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.genutils.html#IPython.genutils.SystemExec.getoutputerror">(IPython.genutils.SystemExec method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.util.html#IPython.kernel.core.util.getoutputerror">(in module IPython.kernel.core.util)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.map.html#IPython.kernel.map.Map.getPartition">getPartition() (IPython.kernel.map.Map method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.map.html#IPython.kernel.map.RoundRobinMap.getPartition">(IPython.kernel.map.RoundRobinMap method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.WxConsoleView.getPromptLen">getPromptLen() (IPython.gui.wx.ipython_view.WxConsoleView method)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.getsize">getsize() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.OInspect.html#IPython.OInspect.getsource">getsource() (in module IPython.OInspect)</a></dt>
+<dt><a href="api/generated/IPython.kernel.newserialized.html#IPython.kernel.newserialized.Serialized.getTypeDescriptor">getTypeDescriptor() (IPython.kernel.newserialized.Serialized method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.newserialized.html#IPython.kernel.newserialized.SerializeIt.getTypeDescriptor">(IPython.kernel.newserialized.SerializeIt method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.core.fd_redirector.html#IPython.kernel.core.fd_redirector.FDRedirector.getvalue">getvalue() (IPython.kernel.core.fd_redirector.FDRedirector method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.core.file_like.html#IPython.kernel.core.file_like.FileLike.getvalue">(IPython.kernel.core.file_like.FileLike method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.glob">glob() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.completer.html#IPython.completer.Completer.global_matches">global_matches() (IPython.completer.Completer method)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.grep">grep() (in module IPython.genutils)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.genutils.html#IPython.genutils.SList.grep">(IPython.genutils.SList method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.external.pretty.html#IPython.external.pretty.Group">Group (class in IPython.external.pretty)</a></dt>
+<dt><a href="api/generated/IPython.external.pretty.html#IPython.external.pretty.GroupQueue">GroupQueue (class in IPython.external.pretty)</a></dt>
+</dl></td></tr></table>
+
+<h2 id="H">H</h2>
+<table width="100%" class="indextable"><tr><td width="33%" valign="top">
+<dl>
+
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.handle_alias">handle_alias() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.handle_auto">handle_auto() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.handle_emacs">handle_emacs() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.scripts.ipcluster.html#IPython.kernel.scripts.ipcluster.BatchEngineSet.handle_error">handle_error() (IPython.kernel.scripts.ipcluster.BatchEngineSet method)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.handle_help">handle_help() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.handle_magic">handle_magic() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.handle_normal">handle_normal() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.handle_shell_escape">handle_shell_escape() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.Command.handleError">handleError() (IPython.kernel.engineservice.Command method)</a></dt>
+<dt><a href="api/generated/IPython.ultraTB.html#IPython.ultraTB.VerboseTB.handler">handler() (IPython.ultraTB.VerboseTB method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.Command.handleResult">handleResult() (IPython.kernel.engineservice.Command method)</a></dt>
+<dt><a href="api/generated/IPython.ipstruct.html#IPython.ipstruct.Struct.has_key">has_key() (IPython.ipstruct.Struct method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.magic.html#IPython.kernel.core.magic.Magic.has_magic">has_magic() (IPython.kernel.core.magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.EngineFromReference.has_properties">has_properties() (IPython.kernel.enginefc.EngineFromReference method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.EngineService.has_properties">(IPython.kernel.engineservice.EngineService method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.QueuedEngine.has_properties">(IPython.kernel.engineservice.QueuedEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.MultiEngine.has_properties">(IPython.kernel.multiengine.MultiEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.SynchronousMultiEngine.has_properties">(IPython.kernel.multiengine.SynchronousMultiEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.FullBlockingMultiEngineClient.has_properties">(IPython.kernel.multiengineclient.FullBlockingMultiEngineClient method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient.has_properties">(IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient method)</a></dt>
+ </dl></dd></dl></td><td width="33%" valign="top"><dl>
+<dt><a href="api/generated/IPython.ipstruct.html#IPython.ipstruct.Struct.hasattr">hasattr() (IPython.ipstruct.Struct method)</a></dt>
+<dt><a href="api/generated/IPython.external.argparse.html#IPython.external.argparse.HelpFormatter">HelpFormatter (class in IPython.external.argparse)</a></dt>
+<dt><a href="api/generated/IPython.Shell.html#IPython.Shell.hijack_gtk">hijack_gtk() (in module IPython.Shell)</a></dt>
+<dt><a href="api/generated/IPython.Shell.html#IPython.Shell.hijack_qt">hijack_qt() (in module IPython.Shell)</a></dt>
+<dt><a href="api/generated/IPython.Shell.html#IPython.Shell.hijack_qt4">hijack_qt4() (in module IPython.Shell)</a></dt>
+<dt><a href="api/generated/IPython.twshell.html#IPython.twshell.hijack_reactor">hijack_reactor() (in module IPython.twshell)</a></dt>
+<dt><a href="api/generated/IPython.Shell.html#IPython.Shell.hijack_tk">hijack_tk() (in module IPython.Shell)</a></dt>
+<dt><a href="api/generated/IPython.Shell.html#IPython.Shell.hijack_wx">hijack_wx() (in module IPython.Shell)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.history.html#IPython.kernel.core.history.History">History (class in IPython.kernel.core.history)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipshell_nonblocking.html#IPython.gui.wx.ipshell_nonblocking.NonBlockingIPShell.history_back">history_back() (IPython.gui.wx.ipshell_nonblocking.NonBlockingIPShell method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipshell_nonblocking.html#IPython.gui.wx.ipshell_nonblocking.NonBlockingIPShell.history_forward">history_forward() (IPython.gui.wx.ipshell_nonblocking.NonBlockingIPShell method)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.history_saving_wrapper">history_saving_wrapper() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.HomeDirError">HomeDirError (class in IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.display_trap.html#IPython.kernel.core.display_trap.DisplayTrap.hook">hook() (IPython.kernel.core.display_trap.DisplayTrap method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.core.sync_traceback_trap.html#IPython.kernel.core.sync_traceback_trap.SyncTracebackTrap.hook">(IPython.kernel.core.sync_traceback_trap.SyncTracebackTrap method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.traceback_trap.html#IPython.kernel.core.traceback_trap.TracebackTrap.hook">(IPython.kernel.core.traceback_trap.TracebackTrap method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.ipapi.html#IPython.ipapi.DebugTools.hotname">hotname() (IPython.ipapi.DebugTools method)</a></dt>
+</dl></td></tr></table>
+
+<h2 id="I">I</h2>
+<table width="100%" class="indextable"><tr><td width="33%" valign="top">
+<dl>
+
+<dt><a href="api/generated/IPython.kernel.clientinterfaces.html#IPython.kernel.clientinterfaces.IBlockingClientAdaptor">IBlockingClientAdaptor (class in IPython.kernel.clientinterfaces)</a></dt>
+<dt><a href="api/generated/IPython.kernel.taskclient.html#IPython.kernel.taskclient.IBlockingTaskClient">IBlockingTaskClient (class in IPython.kernel.taskclient)</a></dt>
+<dt><a href="api/generated/IPython.kernel.controllerservice.html#IPython.kernel.controllerservice.IControllerBase">IControllerBase (class in IPython.kernel.controllerservice)</a></dt>
+<dt><a href="api/generated/IPython.kernel.controllerservice.html#IPython.kernel.controllerservice.IControllerCore">IControllerCore (class in IPython.kernel.controllerservice)</a></dt>
+<dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.EngineFromReference.id">id (IPython.kernel.enginefc.EngineFromReference attribute)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.EngineService.id">(IPython.kernel.engineservice.EngineService attribute)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.numutils.html#IPython.numutils.identity">identity() (in module IPython.numutils)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.idgrep">idgrep() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.IdInUse">IdInUse (class in IPython.kernel.error)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.display_formatter.html#IPython.kernel.core.display_formatter.IDisplayFormatter">IDisplayFormatter (class in IPython.kernel.core.display_formatter)</a></dt>
+<dt><a href="api/generated/IPython.dtutils.html#IPython.dtutils.idoctest">idoctest() (in module IPython.dtutils)</a></dt>
+<dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.IEngineBase">IEngineBase (class in IPython.kernel.engineservice)</a></dt>
+<dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.IEngineCore">IEngineCore (class in IPython.kernel.engineservice)</a></dt>
+<dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.IEngineMultiplexer">IEngineMultiplexer (class in IPython.kernel.multiengine)</a></dt>
+<dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.IEngineProperties">IEngineProperties (class in IPython.kernel.engineservice)</a></dt>
+<dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.IEngineQueued">IEngineQueued (class in IPython.kernel.engineservice)</a></dt>
+<dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.IEngineSerialized">IEngineSerialized (class in IPython.kernel.engineservice)</a></dt>
+<dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.IEngineThreaded">IEngineThreaded (class in IPython.kernel.engineservice)</a></dt>
+<dt><a href="api/generated/IPython.kernel.clientinterfaces.html#IPython.kernel.clientinterfaces.IFCClientInterfaceProvider">IFCClientInterfaceProvider (class in IPython.kernel.clientinterfaces)</a></dt>
+<dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.IFCControllerBase">IFCControllerBase (class in IPython.kernel.enginefc)</a></dt>
+<dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.IFCEngine">IFCEngine (class in IPython.kernel.enginefc)</a></dt>
+<dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.IFCSynchronousMultiEngine">IFCSynchronousMultiEngine (class in IPython.kernel.multienginefc)</a></dt>
+<dt><a href="api/generated/IPython.kernel.taskfc.html#IPython.kernel.taskfc.IFCTaskController">IFCTaskController (class in IPython.kernel.taskfc)</a></dt>
+<dt><a href="api/generated/IPython.frontend.frontendbase.html#IPython.frontend.frontendbase.IFrontEnd">IFrontEnd (class in IPython.frontend.frontendbase)</a></dt>
+<dt><a href="api/generated/IPython.frontend.frontendbase.html#IPython.frontend.frontendbase.IFrontEndFactory">IFrontEndFactory (class in IPython.frontend.frontendbase)</a></dt>
+<dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.IFullBlockingMultiEngineClient">IFullBlockingMultiEngineClient (class in IPython.kernel.multiengineclient)</a></dt>
+<dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.IFullMultiEngine">IFullMultiEngine (class in IPython.kernel.multiengine)</a></dt>
+<dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.IFullSynchronousMultiEngine">IFullSynchronousMultiEngine (class in IPython.kernel.multiengine)</a></dt>
+<dt><a href="api/generated/IPython.DPyGetOpt.html#IPython.DPyGetOpt.DPyGetOpt.ignoreCase">ignoreCase() (IPython.DPyGetOpt.DPyGetOpt method)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.igrep">igrep() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.kernel.mapper.html#IPython.kernel.mapper.IMapper">IMapper (class in IPython.kernel.mapper)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.message_cache.html#IPython.kernel.core.message_cache.IMessageCache">IMessageCache (class in IPython.kernel.core.message_cache)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.import_fail_info">import_fail_info() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.config.cutils.html#IPython.config.cutils.import_item">import_item() (in module IPython.config.cutils)</a></dt>
+<dt><a href="api/generated/IPython.deep_reload.html#IPython.deep_reload.import_module">import_module() (in module IPython.deep_reload)</a></dt>
+<dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.IMultiEngine">IMultiEngine (class in IPython.kernel.multiengine)</a></dt>
+<dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.IMultiEngineCoordinator">IMultiEngineCoordinator (class in IPython.kernel.multiengine)</a></dt>
+<dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.IMultiEngineExtras">IMultiEngineExtras (class in IPython.kernel.multiengine)</a></dt>
+<dt><a href="api/generated/IPython.kernel.mapper.html#IPython.kernel.mapper.IMultiEngineMapperFactory">IMultiEngineMapperFactory (class in IPython.kernel.mapper)</a></dt>
+<dt><a href="api/generated/IPython.kernel.parallelfunction.html#IPython.kernel.parallelfunction.IMultiEngineParallelDecorator">IMultiEngineParallelDecorator (class in IPython.kernel.parallelfunction)</a></dt>
+<dt><a href="api/generated/IPython.history.html#IPython.history.ShadowHist.inc_idx">inc_idx() (IPython.history.ShadowHist method)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.indent">indent() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.indent_current_str">indent_current_str() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.testing.mkdoctests.html#IPython.testing.mkdoctests.IndentOut">IndentOut (class in IPython.testing.mkdoctests)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.info">info() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.init_auto_alias">init_auto_alias() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.scripts.ipcontroller.html#IPython.kernel.scripts.ipcontroller.init_config">init_config() (in module IPython.kernel.scripts.ipcontroller)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.scripts.ipengine.html#IPython.kernel.scripts.ipengine.init_config">(in module IPython.kernel.scripts.ipengine)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.gui.wx.ipshell_nonblocking.html#IPython.gui.wx.ipshell_nonblocking.NonBlockingIPShell.init_history_index">init_history_index() (IPython.gui.wx.ipshell_nonblocking.NonBlockingIPShell method)</a></dt>
+<dt><a href="api/generated/IPython.external.mglob.html#IPython.external.mglob.init_ipython">init_ipython() (in module IPython.external.mglob)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.history.html#IPython.history.init_ipython">(in module IPython.history)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.gui.wx.ipshell_nonblocking.html#IPython.gui.wx.ipshell_nonblocking.NonBlockingIPShell.init_ipython0">init_ipython0() (IPython.gui.wx.ipshell_nonblocking.NonBlockingIPShell method)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.init_namespaces">init_namespaces() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.init_readline">init_readline() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.frontend.wx.console_widget.html#IPython.frontend.wx.console_widget.ConsoleWidget.input_buffer">input_buffer (IPython.frontend.wx.console_widget.ConsoleWidget attribute)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.frontend.wx.wx_frontend.html#IPython.frontend.wx.wx_frontend.WxController.input_buffer">(IPython.frontend.wx.wx_frontend.WxController attribute)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.hooks.html#IPython.hooks.input_prefilter">input_prefilter() (in module IPython.hooks)</a></dt>
+<dt><a href="api/generated/IPython.frontend.frontendbase.html#IPython.frontend.frontendbase.FrontEndBase.input_prompt">input_prompt() (IPython.frontend.frontendbase.FrontEndBase method)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InputList">InputList (class in IPython.iplib)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.core.util.html#IPython.kernel.core.util.InputList">(class in IPython.kernel.core.util)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.ColorANSI.html#IPython.ColorANSI.InputTermColors">InputTermColors (class in IPython.ColorANSI)</a></dt>
+<dt><a href="api/generated/IPython.ultraTB.html#IPython.ultraTB.inspect_error">inspect_error() (in module IPython.ultraTB)</a></dt>
+<dt><a href="api/generated/IPython.generics.html#IPython.generics.inspect_object">inspect_object() (in module IPython.generics)</a></dt>
+<dt><a href="api/generated/IPython.OInspect.html#IPython.OInspect.Inspector">Inspector (class in IPython.OInspect)</a></dt>
+<dt><a href="api/generated/IPython.twshell.html#IPython.twshell.install_gtk2">install_gtk2() (in module IPython.twshell)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.interact">interact() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.interact_handle_input">interact_handle_input() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.interact_prompt">interact_prompt() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.interact_with_readline">interact_with_readline() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.Debugger.html#IPython.Debugger.Pdb.interaction">interaction() (IPython.Debugger.Pdb method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.InteractiveMultiEngineClient">InteractiveMultiEngineClient (class in IPython.kernel.multiengineclient)</a></dt>
+<dt><a href="api/generated/IPython.irunner.html#IPython.irunner.InteractiveRunner">InteractiveRunner (class in IPython.irunner)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell">InteractiveShell (class in IPython.iplib)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.InterpolationEngine.interpolate">interpolate() (IPython.external.configobj.InterpolationEngine method)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.InterpolationEngine">InterpolationEngine (class in IPython.external.configobj)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.InterpolationError">InterpolationError (class in IPython.external.configobj)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.InterpolationLoopError">InterpolationLoopError (class in IPython.external.configobj)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.interpreter.html#IPython.kernel.core.interpreter.Interpreter">Interpreter (class in IPython.kernel.core.interpreter)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.history.html#IPython.kernel.core.history.InterpreterHistory">InterpreterHistory (class in IPython.kernel.core.history)</a></dt>
+<dt><a href="api/generated/IPython.kernel.scripts.ipcluster.html#IPython.kernel.scripts.ipcluster.LocalEngineSet.interrupt_then_kill">interrupt_then_kill() (IPython.kernel.scripts.ipcluster.LocalEngineSet method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.scripts.ipcluster.html#IPython.kernel.scripts.ipcluster.ProcessLauncher.interrupt_then_kill">(IPython.kernel.scripts.ipcluster.ProcessLauncher method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.InvalidClientID">InvalidClientID (class in IPython.kernel.error)</a></dt>
+<dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.InvalidDeferredID">InvalidDeferredID (class in IPython.kernel.error)</a></dt>
+<dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.InvalidEngineID">InvalidEngineID (class in IPython.kernel.error)</a></dt>
+<dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.InvalidProperty">InvalidProperty (class in IPython.kernel.error)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.IOStream">IOStream (class in IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.IOTerm">IOTerm (class in IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.ipalias">ipalias() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.ipapi.html#IPython.ipapi.IPApi">IPApi (class in IPython.ipapi)</a></dt>
+<dt><a href="api/generated/IPython.kernel.parallelfunction.html#IPython.kernel.parallelfunction.IParallelFunction">IParallelFunction (class in IPython.kernel.parallelfunction)</a></dt>
+<dt><a href="api/generated/IPython.completer.html#IPython.completer.IPCompleter">IPCompleter (class in IPython.completer)</a></dt>
+<dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.IPendingResult">IPendingResult (class in IPython.kernel.multiengineclient)</a></dt>
+<dt><a href="api/generated/IPython.testing.plugin.dtexample.html#IPython.testing.plugin.dtexample.ipfunc">ipfunc() (in module IPython.testing.plugin.dtexample)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.ipmagic">ipmagic() (IPython.iplib.InteractiveShell method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.core.interpreter.html#IPython.kernel.core.interpreter.Interpreter.ipmagic">(IPython.kernel.core.interpreter.Interpreter method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.testing.plugin.dtexample.html#IPython.testing.plugin.dtexample.iprand">iprand() (in module IPython.testing.plugin.dtexample)</a></dt>
+<dt><a href="api/generated/IPython.testing.plugin.dtexample.html#IPython.testing.plugin.dtexample.iprand_all">iprand_all() (in module IPython.testing.plugin.dtexample)</a></dt>
+<dt><a href="api/generated/IPython.Shell.html#IPython.Shell.IPShell">IPShell (class in IPython.Shell)</a></dt>
+<dt><a href="api/generated/IPython.Shell.html#IPython.Shell.IPShellEmbed">IPShellEmbed (class in IPython.Shell)</a></dt>
+<dt><a href="api/generated/IPython.Shell.html#IPython.Shell.IPShellGTK">IPShellGTK (class in IPython.Shell)</a></dt>
+<dt><a href="api/generated/IPython.Shell.html#IPython.Shell.IPShellMatplotlib">IPShellMatplotlib (class in IPython.Shell)</a></dt>
+<dt><a href="api/generated/IPython.Shell.html#IPython.Shell.IPShellMatplotlibGTK">IPShellMatplotlibGTK (class in IPython.Shell)</a></dt>
+<dt><a href="api/generated/IPython.Shell.html#IPython.Shell.IPShellMatplotlibQt">IPShellMatplotlibQt (class in IPython.Shell)</a></dt>
+<dt><a href="api/generated/IPython.Shell.html#IPython.Shell.IPShellMatplotlibQt4">IPShellMatplotlibQt4 (class in IPython.Shell)</a></dt>
+<dt><a href="api/generated/IPython.Shell.html#IPython.Shell.IPShellMatplotlibWX">IPShellMatplotlibWX (class in IPython.Shell)</a></dt>
+<dt><a href="api/generated/IPython.Shell.html#IPython.Shell.IPShellQt">IPShellQt (class in IPython.Shell)</a></dt>
+<dt><a href="api/generated/IPython.Shell.html#IPython.Shell.IPShellQt4">IPShellQt4 (class in IPython.Shell)</a></dt>
+<dt><a href="api/generated/IPython.twshell.html#IPython.twshell.IPShellTwisted">IPShellTwisted (class in IPython.twshell)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.IPShellWidget">IPShellWidget (class in IPython.gui.wx.ipython_view)</a></dt>
+<dt><a href="api/generated/IPython.Shell.html#IPython.Shell.IPShellWX">IPShellWX (class in IPython.Shell)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.ipsystem">ipsystem() (IPython.iplib.InteractiveShell method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.core.interpreter.html#IPython.kernel.core.interpreter.Interpreter.ipsystem">(IPython.kernel.core.interpreter.Interpreter method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.testing.iptest.html#IPython.testing.iptest.IPTester">IPTester (class in IPython.testing.iptest)</a></dt>
+<dt><a href="api/generated/IPython.Shell.html#IPython.Shell.IPThread">IPThread (class in IPython.Shell)</a></dt>
+<dt><a href="api/generated/IPython.ipapi.html#IPython.ipapi.IPyAutocall">IPyAutocall (class in IPython.ipapi)</a></dt>
+<dt><a href="api/generated/IPython.testing.plugin.simple.html#IPython.testing.plugin.simple.ipyfunc2">ipyfunc2() (in module IPython.testing.plugin.simple)</a></dt>
+<dt><a href="api/generated/IPython.background_jobs.html#module-IPython.background_jobs">IPython.background_jobs (module)</a></dt>
+<dt><a href="api/generated/IPython.clipboard.html#module-IPython.clipboard">IPython.clipboard (module)</a></dt>
+<dt><a href="api/generated/IPython.ColorANSI.html#module-IPython.ColorANSI">IPython.ColorANSI (module)</a></dt>
+<dt><a href="api/generated/IPython.completer.html#module-IPython.completer">IPython.completer (module)</a></dt>
+<dt><a href="api/generated/IPython.config.api.html#module-IPython.config.api">IPython.config.api (module)</a></dt>
+<dt><a href="api/generated/IPython.config.cutils.html#module-IPython.config.cutils">IPython.config.cutils (module)</a></dt>
+<dt><a href="api/generated/IPython.ConfigLoader.html#module-IPython.ConfigLoader">IPython.ConfigLoader (module)</a></dt>
+<dt><a href="api/generated/IPython.CrashHandler.html#module-IPython.CrashHandler">IPython.CrashHandler (module)</a></dt>
+<dt><a href="api/generated/IPython.Debugger.html#module-IPython.Debugger">IPython.Debugger (module)</a></dt>
+<dt><a href="api/generated/IPython.deep_reload.html#module-IPython.deep_reload">IPython.deep_reload (module)</a></dt>
+<dt><a href="api/generated/IPython.demo.html#module-IPython.demo">IPython.demo (module)</a></dt>
+<dt><a href="api/generated/IPython.DPyGetOpt.html#module-IPython.DPyGetOpt">IPython.DPyGetOpt (module)</a></dt>
+<dt><a href="api/generated/IPython.dtutils.html#module-IPython.dtutils">IPython.dtutils (module)</a></dt>
+<dt><a href="api/generated/IPython.excolors.html#module-IPython.excolors">IPython.excolors (module)</a></dt>
+<dt><a href="api/generated/IPython.external.argparse.html#module-IPython.external.argparse">IPython.external.argparse (module)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#module-IPython.external.configobj">IPython.external.configobj (module)</a></dt>
+<dt><a href="api/generated/IPython.external.guid.html#module-IPython.external.guid">IPython.external.guid (module)</a></dt>
+<dt><a href="api/generated/IPython.external.Itpl.html#module-IPython.external.Itpl">IPython.external.Itpl (module)</a></dt>
+<dt><a href="api/generated/IPython.external.mglob.html#module-IPython.external.mglob">IPython.external.mglob (module)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#module-IPython.external.path">IPython.external.path (module)</a></dt>
+<dt><a href="api/generated/IPython.external.pretty.html#module-IPython.external.pretty">IPython.external.pretty (module)</a></dt>
+<dt><a href="api/generated/IPython.external.simplegeneric.html#module-IPython.external.simplegeneric">IPython.external.simplegeneric (module)</a></dt>
+<dt><a href="api/generated/IPython.external.validate.html#module-IPython.external.validate">IPython.external.validate (module)</a></dt>
+<dt><a href="api/generated/IPython.frontend.asyncfrontendbase.html#module-IPython.frontend.asyncfrontendbase">IPython.frontend.asyncfrontendbase (module)</a></dt>
+<dt><a href="api/generated/IPython.frontend.frontendbase.html#module-IPython.frontend.frontendbase">IPython.frontend.frontendbase (module)</a></dt>
+<dt><a href="api/generated/IPython.frontend.linefrontendbase.html#module-IPython.frontend.linefrontendbase">IPython.frontend.linefrontendbase (module)</a></dt>
+<dt><a href="api/generated/IPython.frontend.prefilterfrontend.html#module-IPython.frontend.prefilterfrontend">IPython.frontend.prefilterfrontend (module)</a></dt>
+<dt><a href="api/generated/IPython.frontend.process.pipedprocess.html#module-IPython.frontend.process.pipedprocess">IPython.frontend.process.pipedprocess (module)</a></dt>
+<dt><a href="api/generated/IPython.frontend.wx.console_widget.html#module-IPython.frontend.wx.console_widget">IPython.frontend.wx.console_widget (module)</a></dt>
+<dt><a href="api/generated/IPython.frontend.wx.ipythonx.html#module-IPython.frontend.wx.ipythonx">IPython.frontend.wx.ipythonx (module)</a></dt>
+<dt><a href="api/generated/IPython.frontend.wx.wx_frontend.html#module-IPython.frontend.wx.wx_frontend">IPython.frontend.wx.wx_frontend (module)</a></dt>
+<dt><a href="api/generated/IPython.generics.html#module-IPython.generics">IPython.generics (module)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#module-IPython.genutils">IPython.genutils (module)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipshell_nonblocking.html#module-IPython.gui.wx.ipshell_nonblocking">IPython.gui.wx.ipshell_nonblocking (module)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_history.html#module-IPython.gui.wx.ipython_history">IPython.gui.wx.ipython_history (module)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_view.html#module-IPython.gui.wx.ipython_view">IPython.gui.wx.ipython_view (module)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.thread_ex.html#module-IPython.gui.wx.thread_ex">IPython.gui.wx.thread_ex (module)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.wxIPython.html#module-IPython.gui.wx.wxIPython">IPython.gui.wx.wxIPython (module)</a></dt>
+<dt><a href="api/generated/IPython.history.html#module-IPython.history">IPython.history (module)</a></dt>
+<dt><a href="api/generated/IPython.hooks.html#module-IPython.hooks">IPython.hooks (module)</a></dt>
+<dt><a href="api/generated/IPython.ipapi.html#module-IPython.ipapi">IPython.ipapi (module)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#module-IPython.iplib">IPython.iplib (module)</a></dt>
+<dt><a href="api/generated/IPython.ipmaker.html#module-IPython.ipmaker">IPython.ipmaker (module)</a></dt></dl></td><td width="33%" valign="top"><dl>
+<dt><a href="api/generated/IPython.ipstruct.html#module-IPython.ipstruct">IPython.ipstruct (module)</a></dt>
+<dt><a href="api/generated/IPython.irunner.html#module-IPython.irunner">IPython.irunner (module)</a></dt>
+<dt><a href="api/generated/IPython.Itpl.html#module-IPython.Itpl">IPython.Itpl (module)</a></dt>
+<dt><a href="api/generated/IPython.kernel.client.html#module-IPython.kernel.client">IPython.kernel.client (module)</a></dt>
+<dt><a href="api/generated/IPython.kernel.clientconnector.html#module-IPython.kernel.clientconnector">IPython.kernel.clientconnector (module)</a></dt>
+<dt><a href="api/generated/IPython.kernel.clientinterfaces.html#module-IPython.kernel.clientinterfaces">IPython.kernel.clientinterfaces (module)</a></dt>
+<dt><a href="api/generated/IPython.kernel.codeutil.html#module-IPython.kernel.codeutil">IPython.kernel.codeutil (module)</a></dt>
+<dt><a href="api/generated/IPython.kernel.contexts.html#module-IPython.kernel.contexts">IPython.kernel.contexts (module)</a></dt>
+<dt><a href="api/generated/IPython.kernel.controllerservice.html#module-IPython.kernel.controllerservice">IPython.kernel.controllerservice (module)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.display_formatter.html#module-IPython.kernel.core.display_formatter">IPython.kernel.core.display_formatter (module)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.display_trap.html#module-IPython.kernel.core.display_trap">IPython.kernel.core.display_trap (module)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.error.html#module-IPython.kernel.core.error">IPython.kernel.core.error (module)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.fd_redirector.html#module-IPython.kernel.core.fd_redirector">IPython.kernel.core.fd_redirector (module)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.file_like.html#module-IPython.kernel.core.file_like">IPython.kernel.core.file_like (module)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.history.html#module-IPython.kernel.core.history">IPython.kernel.core.history (module)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.interpreter.html#module-IPython.kernel.core.interpreter">IPython.kernel.core.interpreter (module)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.macro.html#module-IPython.kernel.core.macro">IPython.kernel.core.macro (module)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.magic.html#module-IPython.kernel.core.magic">IPython.kernel.core.magic (module)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.message_cache.html#module-IPython.kernel.core.message_cache">IPython.kernel.core.message_cache (module)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.notification.html#module-IPython.kernel.core.notification">IPython.kernel.core.notification (module)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.output_trap.html#module-IPython.kernel.core.output_trap">IPython.kernel.core.output_trap (module)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.prompts.html#module-IPython.kernel.core.prompts">IPython.kernel.core.prompts (module)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.redirector_output_trap.html#module-IPython.kernel.core.redirector_output_trap">IPython.kernel.core.redirector_output_trap (module)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.sync_traceback_trap.html#module-IPython.kernel.core.sync_traceback_trap">IPython.kernel.core.sync_traceback_trap (module)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.traceback_formatter.html#module-IPython.kernel.core.traceback_formatter">IPython.kernel.core.traceback_formatter (module)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.traceback_trap.html#module-IPython.kernel.core.traceback_trap">IPython.kernel.core.traceback_trap (module)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.util.html#module-IPython.kernel.core.util">IPython.kernel.core.util (module)</a></dt>
+<dt><a href="api/generated/IPython.kernel.engineconnector.html#module-IPython.kernel.engineconnector">IPython.kernel.engineconnector (module)</a></dt>
+<dt><a href="api/generated/IPython.kernel.enginefc.html#module-IPython.kernel.enginefc">IPython.kernel.enginefc (module)</a></dt>
+<dt><a href="api/generated/IPython.kernel.engineservice.html#module-IPython.kernel.engineservice">IPython.kernel.engineservice (module)</a></dt>
+<dt><a href="api/generated/IPython.kernel.error.html#module-IPython.kernel.error">IPython.kernel.error (module)</a></dt>
+<dt><a href="api/generated/IPython.kernel.fcutil.html#module-IPython.kernel.fcutil">IPython.kernel.fcutil (module)</a></dt>
+<dt><a href="api/generated/IPython.kernel.magic.html#module-IPython.kernel.magic">IPython.kernel.magic (module)</a></dt>
+<dt><a href="api/generated/IPython.kernel.map.html#module-IPython.kernel.map">IPython.kernel.map (module)</a></dt>
+<dt><a href="api/generated/IPython.kernel.mapper.html#module-IPython.kernel.mapper">IPython.kernel.mapper (module)</a></dt>
+<dt><a href="api/generated/IPython.kernel.multiengine.html#module-IPython.kernel.multiengine">IPython.kernel.multiengine (module)</a></dt>
+<dt><a href="api/generated/IPython.kernel.multiengineclient.html#module-IPython.kernel.multiengineclient">IPython.kernel.multiengineclient (module)</a></dt>
+<dt><a href="api/generated/IPython.kernel.multienginefc.html#module-IPython.kernel.multienginefc">IPython.kernel.multienginefc (module)</a></dt>
+<dt><a href="api/generated/IPython.kernel.newserialized.html#module-IPython.kernel.newserialized">IPython.kernel.newserialized (module)</a></dt>
+<dt><a href="api/generated/IPython.kernel.parallelfunction.html#module-IPython.kernel.parallelfunction">IPython.kernel.parallelfunction (module)</a></dt>
+<dt><a href="api/generated/IPython.kernel.pbutil.html#module-IPython.kernel.pbutil">IPython.kernel.pbutil (module)</a></dt>
+<dt><a href="api/generated/IPython.kernel.pendingdeferred.html#module-IPython.kernel.pendingdeferred">IPython.kernel.pendingdeferred (module)</a></dt>
+<dt><a href="api/generated/IPython.kernel.pickleutil.html#module-IPython.kernel.pickleutil">IPython.kernel.pickleutil (module)</a></dt>
+<dt><a href="api/generated/IPython.kernel.scripts.ipcluster.html#module-IPython.kernel.scripts.ipcluster">IPython.kernel.scripts.ipcluster (module)</a></dt>
+<dt><a href="api/generated/IPython.kernel.scripts.ipcontroller.html#module-IPython.kernel.scripts.ipcontroller">IPython.kernel.scripts.ipcontroller (module)</a></dt>
+<dt><a href="api/generated/IPython.kernel.scripts.ipengine.html#module-IPython.kernel.scripts.ipengine">IPython.kernel.scripts.ipengine (module)</a></dt>
+<dt><a href="api/generated/IPython.kernel.task.html#module-IPython.kernel.task">IPython.kernel.task (module)</a></dt>
+<dt><a href="api/generated/IPython.kernel.taskclient.html#module-IPython.kernel.taskclient">IPython.kernel.taskclient (module)</a></dt>
+<dt><a href="api/generated/IPython.kernel.taskfc.html#module-IPython.kernel.taskfc">IPython.kernel.taskfc (module)</a></dt>
+<dt><a href="api/generated/IPython.kernel.twistedutil.html#module-IPython.kernel.twistedutil">IPython.kernel.twistedutil (module)</a></dt>
+<dt><a href="api/generated/IPython.kernel.util.html#module-IPython.kernel.util">IPython.kernel.util (module)</a></dt>
+<dt><a href="api/generated/IPython.Logger.html#module-IPython.Logger">IPython.Logger (module)</a></dt>
+<dt><a href="api/generated/IPython.macro.html#module-IPython.macro">IPython.macro (module)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#module-IPython.Magic">IPython.Magic (module)</a></dt>
+<dt><a href="api/generated/IPython.numutils.html#module-IPython.numutils">IPython.numutils (module)</a></dt>
+<dt><a href="api/generated/IPython.OInspect.html#module-IPython.OInspect">IPython.OInspect (module)</a></dt>
+<dt><a href="api/generated/IPython.OutputTrap.html#module-IPython.OutputTrap">IPython.OutputTrap (module)</a></dt>
+<dt><a href="api/generated/IPython.platutils.html#module-IPython.platutils">IPython.platutils (module)</a></dt>
+<dt><a href="api/generated/IPython.platutils_dummy.html#module-IPython.platutils_dummy">IPython.platutils_dummy (module)</a></dt>
+<dt><a href="api/generated/IPython.platutils_posix.html#module-IPython.platutils_posix">IPython.platutils_posix (module)</a></dt>
+<dt><a href="api/generated/IPython.prefilter.html#module-IPython.prefilter">IPython.prefilter (module)</a></dt>
+<dt><a href="api/generated/IPython.Prompts.html#module-IPython.Prompts">IPython.Prompts (module)</a></dt>
+<dt><a href="api/generated/IPython.PyColorize.html#module-IPython.PyColorize">IPython.PyColorize (module)</a></dt>
+<dt><a href="api/generated/IPython.Shell.html#module-IPython.Shell">IPython.Shell (module)</a></dt>
+<dt><a href="api/generated/IPython.shellglobals.html#module-IPython.shellglobals">IPython.shellglobals (module)</a></dt>
+<dt><a href="api/generated/IPython.strdispatch.html#module-IPython.strdispatch">IPython.strdispatch (module)</a></dt>
+<dt><a href="api/generated/IPython.testing.decorator_msim.html#module-IPython.testing.decorator_msim">IPython.testing.decorator_msim (module)</a></dt>
+<dt><a href="api/generated/IPython.testing.decorators.html#module-IPython.testing.decorators">IPython.testing.decorators (module)</a></dt>
+<dt><a href="api/generated/IPython.testing.decorators_numpy.html#module-IPython.testing.decorators_numpy">IPython.testing.decorators_numpy (module)</a></dt>
+<dt><a href="api/generated/IPython.testing.decorators_trial.html#module-IPython.testing.decorators_trial">IPython.testing.decorators_trial (module)</a></dt>
+<dt><a href="api/generated/IPython.testing.iptest.html#module-IPython.testing.iptest">IPython.testing.iptest (module)</a></dt>
+<dt><a href="api/generated/IPython.testing.mkdoctests.html#module-IPython.testing.mkdoctests">IPython.testing.mkdoctests (module)</a></dt>
+<dt><a href="api/generated/IPython.testing.parametric.html#module-IPython.testing.parametric">IPython.testing.parametric (module)</a></dt>
+<dt><a href="api/generated/IPython.testing.plugin.dtexample.html#module-IPython.testing.plugin.dtexample">IPython.testing.plugin.dtexample (module)</a></dt>
+<dt><a href="api/generated/IPython.testing.plugin.show_refs.html#module-IPython.testing.plugin.show_refs">IPython.testing.plugin.show_refs (module)</a></dt>
+<dt><a href="api/generated/IPython.testing.plugin.simple.html#module-IPython.testing.plugin.simple">IPython.testing.plugin.simple (module)</a></dt>
+<dt><a href="api/generated/IPython.testing.plugin.test_ipdoctest.html#module-IPython.testing.plugin.test_ipdoctest">IPython.testing.plugin.test_ipdoctest (module)</a></dt>
+<dt><a href="api/generated/IPython.testing.plugin.test_refs.html#module-IPython.testing.plugin.test_refs">IPython.testing.plugin.test_refs (module)</a></dt>
+<dt><a href="api/generated/IPython.testing.tools.html#module-IPython.testing.tools">IPython.testing.tools (module)</a></dt>
+<dt><a href="api/generated/IPython.testing.util.html#module-IPython.testing.util">IPython.testing.util (module)</a></dt>
+<dt><a href="api/generated/IPython.tools.growl.html#module-IPython.tools.growl">IPython.tools.growl (module)</a></dt>
+<dt><a href="api/generated/IPython.tools.utils.html#module-IPython.tools.utils">IPython.tools.utils (module)</a></dt>
+<dt><a href="api/generated/IPython.twshell.html#module-IPython.twshell">IPython.twshell (module)</a></dt>
+<dt><a href="api/generated/IPython.ultraTB.html#module-IPython.ultraTB">IPython.ultraTB (module)</a></dt>
+<dt><a href="api/generated/IPython.upgrade_dir.html#module-IPython.upgrade_dir">IPython.upgrade_dir (module)</a></dt>
+<dt><a href="api/generated/IPython.wildcard.html#module-IPython.wildcard">IPython.wildcard (module)</a></dt>
+<dt><a href="api/generated/IPython.winconsole.html#module-IPython.winconsole">IPython.winconsole (module)</a></dt>
+<dt><a href="api/generated/IPython.CrashHandler.html#IPython.CrashHandler.IPythonCrashHandler">IPythonCrashHandler (class in IPython.CrashHandler)</a></dt>
+<dt><a href="api/generated/IPython.demo.html#IPython.demo.IPythonDemo">IPythonDemo (class in IPython.demo)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.error.html#IPython.kernel.core.error.IPythonError">IPythonError (class in IPython.kernel.core.error)</a></dt>
+<dt><a href="api/generated/IPython.tools.growl.html#IPython.tools.growl.IPythonGrowlError">IPythonGrowlError (class in IPython.tools.growl)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_history.html#IPython.gui.wx.ipython_history.IPythonHistoryPanel">IPythonHistoryPanel (class in IPython.gui.wx.ipython_history)</a></dt>
+<dt><a href="api/generated/IPython.demo.html#IPython.demo.IPythonLineDemo">IPythonLineDemo (class in IPython.demo)</a></dt>
+<dt><a href="api/generated/IPython.ipapi.html#IPython.ipapi.IPythonNotRunning">IPythonNotRunning (class in IPython.ipapi)</a></dt>
+<dt><a href="api/generated/IPython.irunner.html#IPython.irunner.IPythonRunner">IPythonRunner (class in IPython.irunner)</a></dt>
+<dt><a href="api/generated/IPython.frontend.wx.ipythonx.html#IPython.frontend.wx.ipythonx.IPythonX">IPythonX (class in IPython.frontend.wx.ipythonx)</a></dt>
+<dt><a href="api/generated/IPython.frontend.wx.ipythonx.html#IPython.frontend.wx.ipythonx.IPythonXController">IPythonXController (class in IPython.frontend.wx.ipythonx)</a></dt>
+<dt><a href="api/generated/IPython.external.validate.html#IPython.external.validate.is_bool_list">is_bool_list() (in module IPython.external.validate)</a></dt>
+<dt><a href="api/generated/IPython.external.validate.html#IPython.external.validate.is_boolean">is_boolean() (in module IPython.external.validate)</a></dt>
+<dt><a href="api/generated/IPython.frontend.frontendbase.html#IPython.frontend.frontendbase.FrontEndBase.is_complete">is_complete() (IPython.frontend.frontendbase.FrontEndBase method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.frontend.linefrontendbase.html#IPython.frontend.linefrontendbase.LineFrontEndBase.is_complete">(IPython.frontend.linefrontendbase.LineFrontEndBase method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.external.validate.html#IPython.external.validate.is_float">is_float() (in module IPython.external.validate)</a></dt>
+<dt><a href="api/generated/IPython.external.validate.html#IPython.external.validate.is_float_list">is_float_list() (in module IPython.external.validate)</a></dt>
+<dt><a href="api/generated/IPython.external.validate.html#IPython.external.validate.is_int_list">is_int_list() (in module IPython.external.validate)</a></dt>
+<dt><a href="api/generated/IPython.external.validate.html#IPython.external.validate.is_integer">is_integer() (in module IPython.external.validate)</a></dt>
+<dt><a href="api/generated/IPython.external.validate.html#IPython.external.validate.is_ip_addr">is_ip_addr() (in module IPython.external.validate)</a></dt>
+<dt><a href="api/generated/IPython.external.validate.html#IPython.external.validate.is_ip_addr_list">is_ip_addr_list() (in module IPython.external.validate)</a></dt>
+<dt><a href="api/generated/IPython.external.validate.html#IPython.external.validate.is_list">is_list() (in module IPython.external.validate)</a></dt>
+<dt><a href="api/generated/IPython.external.validate.html#IPython.external.validate.is_mixed_list">is_mixed_list() (in module IPython.external.validate)</a></dt>
+<dt><a href="api/generated/IPython.external.validate.html#IPython.external.validate.is_option">is_option() (in module IPython.external.validate)</a></dt>
+<dt><a href="api/generated/IPython.kernel.fcutil.html#IPython.kernel.fcutil.is_secure">is_secure() (in module IPython.kernel.fcutil)</a></dt>
+<dt><a href="api/generated/IPython.external.validate.html#IPython.external.validate.is_string">is_string() (in module IPython.external.validate)</a></dt>
+<dt><a href="api/generated/IPython.external.validate.html#IPython.external.validate.is_string_list">is_string_list() (in module IPython.external.validate)</a></dt>
+<dt><a href="api/generated/IPython.external.validate.html#IPython.external.validate.is_tuple">is_tuple() (in module IPython.external.validate)</a></dt>
+<dt><a href="api/generated/IPython.wildcard.html#IPython.wildcard.is_type">is_type() (in module IPython.wildcard)</a></dt>
+<dt><a href="api/generated/IPython.kernel.fcutil.html#IPython.kernel.fcutil.is_valid">is_valid() (in module IPython.kernel.fcutil)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.isabs">isabs() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.file_like.html#IPython.kernel.core.file_like.FileLike.isatty">isatty() (IPython.kernel.core.file_like.FileLike method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.IScheduler">IScheduler (class in IPython.kernel.task)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.isdir">isdir() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.newserialized.html#IPython.kernel.newserialized.ISerialized">ISerialized (class in IPython.kernel.newserialized)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.isfile">isfile() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.islink">islink() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.ismount">ismount() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.DPyGetOpt.html#IPython.DPyGetOpt.DPyGetOpt.isPosixCompliant">isPosixCompliant() (IPython.DPyGetOpt.DPyGetOpt method)</a></dt>
+<dt><a href="api/generated/IPython.numutils.html#IPython.numutils.ispower2">ispower2() (in module IPython.numutils)</a></dt>
+<dt><a href="api/generated/IPython.prefilter.html#IPython.prefilter.isShadowed">isShadowed() (in module IPython.prefilter)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.Section.istrue">istrue() (IPython.external.configobj.Section method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.ISynchronousEngineMultiplexer">ISynchronousEngineMultiplexer (class in IPython.kernel.multiengine)</a></dt>
+<dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.ISynchronousMultiEngine">ISynchronousMultiEngine (class in IPython.kernel.multiengine)</a></dt>
+<dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.ISynchronousMultiEngineCoordinator">ISynchronousMultiEngineCoordinator (class in IPython.kernel.multiengine)</a></dt>
+<dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.ISynchronousMultiEngineExtras">ISynchronousMultiEngineExtras (class in IPython.kernel.multiengine)</a></dt>
+<dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.ITask">ITask (class in IPython.kernel.task)</a></dt>
+<dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.ITaskController">ITaskController (class in IPython.kernel.task)</a></dt>
+<dt><a href="api/generated/IPython.kernel.mapper.html#IPython.kernel.mapper.ITaskMapperFactory">ITaskMapperFactory (class in IPython.kernel.mapper)</a></dt>
+<dt><a href="api/generated/IPython.kernel.parallelfunction.html#IPython.kernel.parallelfunction.ITaskParallelDecorator">ITaskParallelDecorator (class in IPython.kernel.parallelfunction)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.Section.items">items() (IPython.external.configobj.Section method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.ipstruct.html#IPython.ipstruct.Struct.items">(IPython.ipstruct.Struct method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.Section.iteritems">iteritems() (IPython.external.configobj.Section method)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.Section.iterkeys">iterkeys() (IPython.external.configobj.Section method)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.Section.itervalues">itervalues() (IPython.external.configobj.Section method)</a></dt>
+<dt><a href="api/generated/IPython.external.Itpl.html#IPython.external.Itpl.Itpl">Itpl (class in IPython.external.Itpl)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.Itpl.html#IPython.Itpl.Itpl">(class in IPython.Itpl)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.external.Itpl.html#IPython.external.Itpl.itpl">itpl() (in module IPython.external.Itpl)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.ipapi.html#IPython.ipapi.IPApi.itpl">(IPython.ipapi.IPApi method)</a></dt>
+ <dt><a href="api/generated/IPython.Itpl.html#IPython.Itpl.itpl">(in module IPython.Itpl)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.external.Itpl.html#IPython.external.Itpl.ItplError">ItplError (class in IPython.external.Itpl)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.Itpl.html#IPython.Itpl.ItplError">(class in IPython.Itpl)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.external.Itpl.html#IPython.external.Itpl.ItplFile">ItplFile (class in IPython.external.Itpl)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.Itpl.html#IPython.Itpl.ItplFile">(class in IPython.Itpl)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.external.Itpl.html#IPython.external.Itpl.ItplNS">ItplNS (class in IPython.external.Itpl)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.Itpl.html#IPython.Itpl.ItplNS">(class in IPython.Itpl)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.external.Itpl.html#IPython.external.Itpl.itplns">itplns() (in module IPython.external.Itpl)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.Itpl.html#IPython.Itpl.itplns">(in module IPython.Itpl)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.core.traceback_formatter.html#IPython.kernel.core.traceback_formatter.ITracebackFormatter">ITracebackFormatter (class in IPython.kernel.core.traceback_formatter)</a></dt>
+<dt><a href="api/generated/IPython.kernel.newserialized.html#IPython.kernel.newserialized.IUnSerialized">IUnSerialized (class in IPython.kernel.newserialized)</a></dt>
+<dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.IWorker">IWorker (class in IPython.kernel.task)</a></dt>
+</dl></td></tr></table>
+
+<h2 id="J">J</h2>
+<table width="100%" class="indextable"><tr><td width="33%" valign="top">
+<dl>
+
+<dt><a href="api/generated/IPython.kernel.map.html#IPython.kernel.map.Map.joinPartitions">joinPartitions() (IPython.kernel.map.Map method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.map.html#IPython.kernel.map.RoundRobinMap.joinPartitions">(IPython.kernel.map.RoundRobinMap method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.joinpath">joinpath() (IPython.external.path.path method)</a></dt></dl></td><td width="33%" valign="top"><dl>
+<dt><a href="api/generated/IPython.demo.html#IPython.demo.Demo.jump">jump() (IPython.demo.Demo method)</a></dt>
+</dl></td></tr></table>
+
+<h2 id="K">K</h2>
+<table width="100%" class="indextable"><tr><td width="33%" valign="top">
+<dl>
+
+<dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.KernelError">KernelError (class in IPython.kernel.error)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.IPShellWidget.keyPress">keyPress() (IPython.gui.wx.ipython_view.IPShellWidget method)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.Section.keys">keys() (IPython.external.configobj.Section method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.ipstruct.html#IPython.ipstruct.Struct.keys">(IPython.ipstruct.Struct method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.EngineFromReference.keys">(IPython.kernel.enginefc.EngineFromReference method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.EngineService.keys">(IPython.kernel.engineservice.EngineService method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.QueuedEngine.keys">(IPython.kernel.engineservice.QueuedEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.MultiEngine.keys">(IPython.kernel.multiengine.MultiEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.SynchronousMultiEngine.keys">(IPython.kernel.multiengine.SynchronousMultiEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.FullBlockingMultiEngineClient.keys">(IPython.kernel.multiengineclient.FullBlockingMultiEngineClient method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient.keys">(IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.gui.wx.thread_ex.html#IPython.gui.wx.thread_ex.ThreadEx.kill">kill() (IPython.gui.wx.thread_ex.ThreadEx method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.Shell.html#IPython.Shell.MTInteractiveShell.kill">(IPython.Shell.MTInteractiveShell method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.EngineFromReference.kill">(IPython.kernel.enginefc.EngineFromReference method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.EngineService.kill">(IPython.kernel.engineservice.EngineService method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.QueuedEngine.kill">(IPython.kernel.engineservice.QueuedEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.MultiEngine.kill">(IPython.kernel.multiengine.MultiEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.SynchronousMultiEngine.kill">(IPython.kernel.multiengine.SynchronousMultiEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.FullBlockingMultiEngineClient.kill">(IPython.kernel.multiengineclient.FullBlockingMultiEngineClient method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient.kill">(IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.scripts.ipcluster.html#IPython.kernel.scripts.ipcluster.BatchEngineSet.kill">(IPython.kernel.scripts.ipcluster.BatchEngineSet method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.scripts.ipcluster.html#IPython.kernel.scripts.ipcluster.SSHEngineSet.kill">(IPython.kernel.scripts.ipcluster.SSHEngineSet method)</a></dt>
+ <dt><a href="api/generated/IPython.twshell.html#IPython.twshell.TwistedInteractiveShell.kill">(IPython.twshell.TwistedInteractiveShell method)</a></dt>
+ </dl></dd></dl></td><td width="33%" valign="top"><dl>
+<dt><a href="api/generated/IPython.Shell.html#IPython.Shell.kill_embedded">kill_embedded() (in module IPython.Shell)</a></dt>
+<dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.EngineFromReference.killBack">killBack() (IPython.kernel.enginefc.EngineFromReference method)</a></dt>
+</dl></td></tr></table>
+
+<h2 id="L">L</h2>
+<table width="100%" class="indextable"><tr><td width="33%" valign="top">
+<dl>
+
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.LSString.l">l (IPython.genutils.LSString attribute)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.genutils.html#IPython.genutils.SList.l">(IPython.genutils.SList attribute)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.numutils.html#IPython.numutils.l1norm">l1norm() (in module IPython.numutils)</a></dt>
+<dt><a href="api/generated/IPython.numutils.html#IPython.numutils.l2norm">l2norm() (in module IPython.numutils)</a></dt>
+<dt><a href="api/generated/IPython.hooks.html#IPython.hooks.late_startup_hook">late_startup_hook() (in module IPython.hooks)</a></dt>
+<dt><a href="api/generated/IPython.ipapi.html#IPython.ipapi.launch_new_instance">launch_new_instance() (in module IPython.ipapi)</a></dt>
+<dt><a href="api/generated/IPython.kernel.scripts.ipcluster.html#IPython.kernel.scripts.ipcluster.LauncherProcessProtocol">LauncherProcessProtocol (class in IPython.kernel.scripts.ipcluster)</a></dt>
+<dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.LIFOScheduler">LIFOScheduler (class in IPython.kernel.task)</a></dt>
+<dt><a href="api/generated/IPython.demo.html#IPython.demo.LineDemo">LineDemo (class in IPython.demo)</a></dt>
+<dt><a href="api/generated/IPython.frontend.linefrontendbase.html#IPython.frontend.linefrontendbase.LineFrontEndBase">LineFrontEndBase (class in IPython.frontend.linefrontendbase)</a></dt>
+<dt><a href="api/generated/IPython.prefilter.html#IPython.prefilter.LineInfo">LineInfo (class in IPython.prefilter)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.lines">lines() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.link">link() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.LSString.list">list (IPython.genutils.LSString attribute)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.genutils.html#IPython.genutils.SList.list">(IPython.genutils.SList attribute)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.list2dict">list2dict() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.list2dict2">list2dict2() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.Debugger.html#IPython.Debugger.Pdb.list_command_pydb">list_command_pydb() (IPython.Debugger.Pdb method)</a></dt>
+<dt><a href="api/generated/IPython.wildcard.html#IPython.wildcard.list_namespace">list_namespace() (in module IPython.wildcard)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.list_strings">list_strings() (in module IPython.genutils)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.tools.utils.html#IPython.tools.utils.list_strings">(in module IPython.tools.utils)</a></dt>
+ </dl></dd></dl></td><td width="33%" valign="top"><dl>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.listdir">listdir() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.ultraTB.html#IPython.ultraTB.ListTB">ListTB (class in IPython.ultraTB)</a></dt>
+<dt><a href="api/generated/IPython.ConfigLoader.html#IPython.ConfigLoader.ConfigLoader.load">load() (IPython.ConfigLoader.ConfigLoader method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.ipapi.html#IPython.ipapi.IPApi.load">(IPython.ipapi.IPApi method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.deep_reload.html#IPython.deep_reload.load_tail">load_tail() (in module IPython.deep_reload)</a></dt>
+<dt><a href="api/generated/IPython.kernel.scripts.ipcluster.html#IPython.kernel.scripts.ipcluster.LocalEngineSet">LocalEngineSet (class in IPython.kernel.scripts.ipcluster)</a></dt>
+<dt><a href="api/generated/IPython.Logger.html#IPython.Logger.Logger.log">log() (IPython.Logger.Logger method)</a></dt>
+<dt><a href="api/generated/IPython.numutils.html#IPython.numutils.log2">log2() (in module IPython.numutils)</a></dt>
+<dt><a href="api/generated/IPython.Logger.html#IPython.Logger.Logger.log_write">log_write() (IPython.Logger.Logger method)</a></dt>
+<dt><a href="api/generated/IPython.Logger.html#IPython.Logger.Logger">Logger (class in IPython.Logger)</a></dt>
+<dt><a href="api/generated/IPython.Logger.html#IPython.Logger.Logger.logmode">logmode (IPython.Logger.Logger attribute)</a></dt>
+<dt><a href="api/generated/IPython.Logger.html#IPython.Logger.Logger.logstart">logstart() (IPython.Logger.Logger method)</a></dt>
+<dt><a href="api/generated/IPython.Logger.html#IPython.Logger.Logger.logstate">logstate() (IPython.Logger.Logger method)</a></dt>
+<dt><a href="api/generated/IPython.Logger.html#IPython.Logger.Logger.logstop">logstop() (IPython.Logger.Logger method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.lsmagic">lsmagic() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.LSString">LSString (class in IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.lstat">lstat() (IPython.external.path.path method)</a></dt>
+</dl></td></tr></table>
+
+<h2 id="M">M</h2>
+<table width="100%" class="indextable"><tr><td width="33%" valign="top">
+<dl>
+
+<dt><a href="api/generated/IPython.kernel.core.macro.html#IPython.kernel.core.macro.Macro">Macro (class in IPython.kernel.core.macro)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.macro.html#IPython.macro.Macro">(class in IPython.macro)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.core.magic.html#IPython.kernel.core.magic.Magic">Magic (class in IPython.kernel.core.magic)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic">(class in IPython.Magic)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_alias">magic_alias() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_autocall">magic_autocall() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_autoindent">magic_autoindent() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_automagic">magic_automagic() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_bg">magic_bg() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_bookmark">magic_bookmark() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_cd">magic_cd() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_color_info">magic_color_info() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_colors">magic_colors() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_cpaste">magic_cpaste() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_debug">magic_debug() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_dhist">magic_dhist() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_dirs">magic_dirs() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_doctest_mode">magic_doctest_mode() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_ed">magic_ed() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_edit">magic_edit() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.magic.html#IPython.kernel.core.magic.Magic.magic_env">magic_env() (IPython.kernel.core.magic.Magic method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_env">(IPython.Magic.Magic method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_Exit">magic_Exit() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_exit">magic_exit() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.history.html#IPython.history.magic_hist">magic_hist() (in module IPython.history)</a></dt>
+<dt><a href="api/generated/IPython.history.html#IPython.history.magic_history">magic_history() (in module IPython.history)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_logoff">magic_logoff() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_logon">magic_logon() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_logstart">magic_logstart() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_logstate">magic_logstate() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_logstop">magic_logstop() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_lsmagic">magic_lsmagic() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_macro">magic_macro() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_magic">magic_magic() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_page">magic_page() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_paste">magic_paste() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_pdb">magic_pdb() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_pdef">magic_pdef() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_pdoc">magic_pdoc() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_pfile">magic_pfile() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_pinfo">magic_pinfo() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_popd">magic_popd() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_Pprint">magic_Pprint() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_profile">magic_profile() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_prun">magic_prun() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_psearch">magic_psearch() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_psource">magic_psource() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_pushd">magic_pushd() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.magic.html#IPython.kernel.core.magic.Magic.magic_pwd">magic_pwd() (IPython.kernel.core.magic.Magic method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_pwd">(IPython.Magic.Magic method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_pycat">magic_pycat() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_quickref">magic_quickref() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_quit">magic_quit() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_r">magic_r() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_rehashx">magic_rehashx() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_reset">magic_reset() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_run">magic_run() (IPython.Magic.Magic method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.Shell.html#IPython.Shell.MatplotlibShellBase.magic_run">(IPython.Shell.MatplotlibShellBase method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_runlog">magic_runlog() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_save">magic_save() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_sc">magic_sc() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_sx">magic_sx() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_system_verbose">magic_system_verbose() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_time">magic_time() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_timeit">magic_timeit() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_unalias">magic_unalias() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_upgrade">magic_upgrade() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_who">magic_who() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_who_ls">magic_who_ls() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_whos">magic_whos() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.magic_xmode">magic_xmode() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.external.mglob.html#IPython.external.mglob.main">main() (in module IPython.external.mglob)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.irunner.html#IPython.irunner.InteractiveRunner.main">(IPython.irunner.InteractiveRunner method)</a></dt>
+ <dt><a href="api/generated/IPython.PyColorize.html#IPython.PyColorize.main">(in module IPython.PyColorize)</a></dt>
+ <dt><a href="api/generated/IPython.frontend.wx.ipythonx.html#IPython.frontend.wx.ipythonx.main">(in module IPython.frontend.wx.ipythonx)</a></dt>
+ <dt><a href="api/generated/IPython.gui.wx.wxIPython.html#IPython.gui.wx.wxIPython.main">(in module IPython.gui.wx.wxIPython)</a></dt>
+ <dt><a href="api/generated/IPython.irunner.html#IPython.irunner.main">(in module IPython.irunner)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.scripts.ipcluster.html#IPython.kernel.scripts.ipcluster.main">(in module IPython.kernel.scripts.ipcluster)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.scripts.ipcontroller.html#IPython.kernel.scripts.ipcontroller.main">(in module IPython.kernel.scripts.ipcontroller)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.scripts.ipengine.html#IPython.kernel.scripts.ipengine.main">(in module IPython.kernel.scripts.ipengine)</a></dt>
+ <dt><a href="api/generated/IPython.testing.iptest.html#IPython.testing.iptest.main">(in module IPython.testing.iptest)</a></dt>
+ <dt><a href="api/generated/IPython.testing.mkdoctests.html#IPython.testing.mkdoctests.main">(in module IPython.testing.mkdoctests)</a></dt>
+ </dl></dd></dl></td><td width="33%" valign="top"><dl>
+<dt><a href="api/generated/IPython.kernel.scripts.ipcluster.html#IPython.kernel.scripts.ipcluster.main_local">main_local() (in module IPython.kernel.scripts.ipcluster)</a></dt>
+<dt><a href="api/generated/IPython.kernel.scripts.ipcluster.html#IPython.kernel.scripts.ipcluster.main_mpi">main_mpi() (in module IPython.kernel.scripts.ipcluster)</a></dt>
+<dt><a href="api/generated/IPython.kernel.scripts.ipcluster.html#IPython.kernel.scripts.ipcluster.main_pbs">main_pbs() (in module IPython.kernel.scripts.ipcluster)</a></dt>
+<dt><a href="api/generated/IPython.kernel.scripts.ipcluster.html#IPython.kernel.scripts.ipcluster.main_ssh">main_ssh() (in module IPython.kernel.scripts.ipcluster)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.mainloop">mainloop() (IPython.iplib.InteractiveShell method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.Shell.html#IPython.Shell.IPShell.mainloop">(IPython.Shell.IPShell method)</a></dt>
+ <dt><a href="api/generated/IPython.Shell.html#IPython.Shell.IPShellGTK.mainloop">(IPython.Shell.IPShellGTK method)</a></dt>
+ <dt><a href="api/generated/IPython.Shell.html#IPython.Shell.IPShellQt.mainloop">(IPython.Shell.IPShellQt method)</a></dt>
+ <dt><a href="api/generated/IPython.Shell.html#IPython.Shell.IPShellQt4.mainloop">(IPython.Shell.IPShellQt4 method)</a></dt>
+ <dt><a href="api/generated/IPython.Shell.html#IPython.Shell.IPShellWX.mainloop">(IPython.Shell.IPShellWX method)</a></dt>
+ <dt><a href="api/generated/IPython.twshell.html#IPython.twshell.IPShellTwisted.mainloop">(IPython.twshell.IPShellTwisted method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.scripts.ipcontroller.html#IPython.kernel.scripts.ipcontroller.make_client_service">make_client_service() (in module IPython.kernel.scripts.ipcontroller)</a></dt>
+<dt><a href="api/generated/IPython.ColorANSI.html#IPython.ColorANSI.make_color_table">make_color_table() (in module IPython.ColorANSI)</a></dt>
+<dt><a href="api/generated/IPython.kernel.scripts.ipcontroller.html#IPython.kernel.scripts.ipcontroller.make_engine_service">make_engine_service() (in module IPython.kernel.scripts.ipcontroller)</a></dt>
+<dt><a href="api/generated/IPython.ipmaker.html#IPython.ipmaker.make_IPython">make_IPython() (in module IPython.ipmaker)</a></dt>
+<dt><a href="api/generated/IPython.testing.decorators.html#IPython.testing.decorators.make_label_dec">make_label_dec() (in module IPython.testing.decorators)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.make_quoted_expr">make_quoted_expr() (in module IPython.genutils)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.core.util.html#IPython.kernel.core.util.make_quoted_expr">(in module IPython.kernel.core.util)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.CrashHandler.html#IPython.CrashHandler.CrashHandler.make_report">make_report() (IPython.CrashHandler.CrashHandler method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.CrashHandler.html#IPython.CrashHandler.IPythonCrashHandler.make_report">(IPython.CrashHandler.IPythonCrashHandler method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.testing.iptest.html#IPython.testing.iptest.make_runners">make_runners() (in module IPython.testing.iptest)</a></dt>
+<dt><a href="api/generated/IPython.ipapi.html#IPython.ipapi.make_session">make_session() (in module IPython.ipapi)</a></dt>
+<dt><a href="api/generated/IPython.kernel.scripts.ipcontroller.html#IPython.kernel.scripts.ipcontroller.make_tub">make_tub() (in module IPython.kernel.scripts.ipcontroller)</a></dt>
+<dt><a href="api/generated/IPython.ipapi.html#IPython.ipapi.make_user_global_ns">make_user_global_ns() (in module IPython.ipapi)</a></dt>
+<dt><a href="api/generated/IPython.ipapi.html#IPython.ipapi.make_user_namespaces">make_user_namespaces() (in module IPython.ipapi)</a></dt>
+<dt><a href="api/generated/IPython.ipapi.html#IPython.ipapi.make_user_ns">make_user_ns() (in module IPython.ipapi)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.makedirs">makedirs() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.map.html#IPython.kernel.map.Map">Map (class in IPython.kernel.map)</a></dt>
+<dt><a href="api/generated/IPython.kernel.mapper.html#IPython.kernel.mapper.MultiEngineMapper.map">map() (IPython.kernel.mapper.MultiEngineMapper method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.mapper.html#IPython.kernel.mapper.SynchronousTaskMapper.map">(IPython.kernel.mapper.SynchronousTaskMapper method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.mapper.html#IPython.kernel.mapper.TaskMapper.map">(IPython.kernel.mapper.TaskMapper method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.FullBlockingMultiEngineClient.map">(IPython.kernel.multiengineclient.FullBlockingMultiEngineClient method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient.map">(IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.taskclient.html#IPython.kernel.taskclient.BlockingTaskClient.map">(IPython.kernel.taskclient.BlockingTaskClient method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.taskfc.html#IPython.kernel.taskfc.FCTaskClient.map">(IPython.kernel.taskfc.FCTaskClient method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.map_method">map_method() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.FullBlockingMultiEngineClient.mapper">mapper() (IPython.kernel.multiengineclient.FullBlockingMultiEngineClient method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient.mapper">(IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.taskclient.html#IPython.kernel.taskclient.BlockingTaskClient.mapper">(IPython.kernel.taskclient.BlockingTaskClient method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.taskfc.html#IPython.kernel.taskfc.FCTaskClient.mapper">(IPython.kernel.taskfc.FCTaskClient method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.MapTask">MapTask (class in IPython.kernel.task)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.marquee">marquee() (in module IPython.genutils)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.demo.html#IPython.demo.ClearMixin.marquee">(IPython.demo.ClearMixin method)</a></dt>
+ <dt><a href="api/generated/IPython.demo.html#IPython.demo.Demo.marquee">(IPython.demo.Demo method)</a></dt>
+ <dt><a href="api/generated/IPython.tools.utils.html#IPython.tools.utils.marquee">(in module IPython.tools.utils)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.match_utf8">match_utf8() (in module IPython.external.configobj)</a></dt>
+<dt><a href="api/generated/IPython.external.Itpl.html#IPython.external.Itpl.matchorfail">matchorfail() (in module IPython.external.Itpl)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.Itpl.html#IPython.Itpl.matchorfail">(in module IPython.Itpl)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.Shell.html#IPython.Shell.MatplotlibMTShell">MatplotlibMTShell (class in IPython.Shell)</a></dt>
+<dt><a href="api/generated/IPython.Shell.html#IPython.Shell.MatplotlibShell">MatplotlibShell (class in IPython.Shell)</a></dt>
+<dt><a href="api/generated/IPython.Shell.html#IPython.Shell.MatplotlibShellBase">MatplotlibShellBase (class in IPython.Shell)</a></dt>
+<dt><a href="api/generated/IPython.numutils.html#IPython.numutils.mean_flat">mean_flat() (in module IPython.numutils)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.Section.merge">merge() (IPython.external.configobj.Section method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.ipstruct.html#IPython.ipstruct.Struct.merge">(IPython.ipstruct.Struct method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.MessageSizeError">MessageSizeError (class in IPython.kernel.error)</a></dt>
+<dt><a href="api/generated/IPython.external.mglob.html#IPython.external.mglob.mglob_f">mglob_f() (in module IPython.external.mglob)</a></dt>
+<dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.MissingBlockArgument">MissingBlockArgument (class in IPython.kernel.error)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.MissingInterpolationOption">MissingInterpolationOption (class in IPython.external.configobj)</a></dt>
+<dt><a href="api/generated/IPython.frontend.prefilterfrontend.html#IPython.frontend.prefilterfrontend.mk_system_call">mk_system_call() (in module IPython.frontend.prefilterfrontend)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.mkdir">mkdir() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.mktempfile">mktempfile() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.move">move() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.WxConsoleView.moveCursor">moveCursor() (IPython.gui.wx.ipython_view.WxConsoleView method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.WxConsoleView.moveCursorOnNewValidKey">moveCursorOnNewValidKey() (IPython.gui.wx.ipython_view.WxConsoleView method)</a></dt>
+<dt><a href="api/generated/IPython.Shell.html#IPython.Shell.MatplotlibShellBase.mplot_exec">mplot_exec() (IPython.Shell.MatplotlibShellBase method)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.mtime">mtime (IPython.external.path.path attribute)</a></dt>
+<dt><a href="api/generated/IPython.Shell.html#IPython.Shell.MTInteractiveShell">MTInteractiveShell (class in IPython.Shell)</a></dt>
+<dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.MultiEngine">MultiEngine (class in IPython.kernel.multiengine)</a></dt>
+<dt><a href="api/generated/IPython.kernel.mapper.html#IPython.kernel.mapper.MultiEngineMapper">MultiEngineMapper (class in IPython.kernel.mapper)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.multiline_prefilter">multiline_prefilter() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.prompts.html#IPython.kernel.core.prompts.multiple_replace">multiple_replace() (in module IPython.kernel.core.prompts)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.Prompts.html#IPython.Prompts.multiple_replace">(in module IPython.Prompts)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.mutex_opts">mutex_opts() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.wxIPython.html#IPython.gui.wx.wxIPython.MyApp">MyApp (class in IPython.gui.wx.wxIPython)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.wxIPython.html#IPython.gui.wx.wxIPython.MyFrame">MyFrame (class in IPython.gui.wx.wxIPython)</a></dt>
+<dt><a href="api/generated/IPython.OInspect.html#IPython.OInspect.myStringIO">myStringIO (class in IPython.OInspect)</a></dt>
+</dl></td></tr></table>
+
+<h2 id="N">N</h2>
+<table width="100%" class="indextable"><tr><td width="33%" valign="top">
+<dl>
+
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.LSString.n">n (IPython.genutils.LSString attribute)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.genutils.html#IPython.genutils.SList.n">(IPython.genutils.SList attribute)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.name">name (IPython.external.path.path attribute)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.namebase">namebase (IPython.external.path.path attribute)</a></dt>
+<dt><a href="api/generated/IPython.external.argparse.html#IPython.external.argparse.Namespace">Namespace (class in IPython.external.argparse)</a></dt>
+<dt><a href="api/generated/IPython.wildcard.html#IPython.wildcard.NameSpace">NameSpace (class in IPython.wildcard)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.native_line_ends">native_line_ends() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.NestingError">NestingError (class in IPython.external.configobj)</a></dt>
+<dt><a href="api/generated/IPython.background_jobs.html#IPython.background_jobs.BackgroundJobManager.new">new() (IPython.background_jobs.BackgroundJobManager method)</a></dt>
+<dt><a href="api/generated/IPython.Debugger.html#IPython.Debugger.Pdb.new_do_down">new_do_down() (IPython.Debugger.Pdb method)</a></dt>
+<dt><a href="api/generated/IPython.Debugger.html#IPython.Debugger.Pdb.new_do_frame">new_do_frame() (IPython.Debugger.Pdb method)</a></dt>
+<dt><a href="api/generated/IPython.Debugger.html#IPython.Debugger.Pdb.new_do_quit">new_do_quit() (IPython.Debugger.Pdb method)</a></dt>
+<dt><a href="api/generated/IPython.Debugger.html#IPython.Debugger.Pdb.new_do_restart">new_do_restart() (IPython.Debugger.Pdb method)</a></dt>
+<dt><a href="api/generated/IPython.Debugger.html#IPython.Debugger.Pdb.new_do_up">new_do_up() (IPython.Debugger.Pdb method)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.new_main_mod">new_main_mod() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.frontend.linefrontendbase.html#IPython.frontend.linefrontendbase.LineFrontEndBase.new_prompt">new_prompt() (IPython.frontend.linefrontendbase.LineFrontEndBase method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.frontend.wx.console_widget.html#IPython.frontend.wx.console_widget.ConsoleWidget.new_prompt">(IPython.frontend.wx.console_widget.ConsoleWidget method)</a></dt>
+ <dt><a href="api/generated/IPython.frontend.wx.wx_frontend.html#IPython.frontend.wx.wx_frontend.WxController.new_prompt">(IPython.frontend.wx.wx_frontend.WxController method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.NLprinter">NLprinter (class in IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.LSString.nlstr">nlstr (IPython.genutils.LSString attribute)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.genutils.html#IPython.genutils.SList.nlstr">(IPython.genutils.SList attribute)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.NoEnginesRegistered">NoEnginesRegistered (class in IPython.kernel.error)</a></dt>
+<dt><a href="api/generated/IPython.OInspect.html#IPython.OInspect.Inspector.noinfo">noinfo() (IPython.OInspect.Inspector method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipshell_nonblocking.html#IPython.gui.wx.ipshell_nonblocking.NonBlockingIPShell">NonBlockingIPShell (class in IPython.gui.wx.ipshell_nonblocking)</a></dt></dl></td><td width="33%" valign="top"><dl>
+<dt><a href="api/generated/IPython.numutils.html#IPython.numutils.norm">norm() (in module IPython.numutils)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.normcase">normcase() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.normpath">normpath() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.NotAPendingResult">NotAPendingResult (class in IPython.kernel.error)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.interpreter.html#IPython.kernel.core.interpreter.NotDefined">NotDefined (class in IPython.kernel.core.interpreter)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.NotDefined">(class in IPython.kernel.error)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.NotGiven">NotGiven (class in IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.notification.html#IPython.kernel.core.notification.NotificationCenter">NotificationCenter (class in IPython.kernel.core.notification)</a></dt>
+<dt><a href="api/generated/IPython.tools.growl.html#IPython.tools.growl.Notifier">Notifier (class in IPython.tools.growl)</a></dt>
+<dt><a href="api/generated/IPython.tools.growl.html#IPython.tools.growl.notify">notify() (in module IPython.tools.growl)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.tools.growl.html#IPython.tools.growl.Notifier.notify">(IPython.tools.growl.Notifier method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.tools.growl.html#IPython.tools.growl.notify_deferred">notify_deferred() (in module IPython.tools.growl)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.tools.growl.html#IPython.tools.growl.Notifier.notify_deferred">(IPython.tools.growl.Notifier method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.TaskResult.ns">ns (IPython.kernel.task.TaskResult attribute)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.wildcard.html#IPython.wildcard.NameSpace.ns">(IPython.wildcard.NameSpace attribute)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.wildcard.html#IPython.wildcard.NameSpace.ns_names">ns_names (IPython.wildcard.NameSpace attribute)</a></dt>
+<dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.FIFOScheduler.ntasks">ntasks (IPython.kernel.task.FIFOScheduler attribute)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.num_cpus">num_cpus() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.num_ini_spaces">num_ini_spaces() (in module IPython.iplib)</a></dt>
+<dt><a href="api/generated/IPython.testing.decorators.html#IPython.testing.decorators.numpy_not_available">numpy_not_available() (in module IPython.testing.decorators)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.testing.decorators_trial.html#IPython.testing.decorators_trial.numpy_not_available">(in module IPython.testing.decorators_trial)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.external.validate.html#IPython.external.validate.numToDottedQuad">numToDottedQuad() (in module IPython.external.validate)</a></dt>
+<dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.FIFOScheduler.nworkers">nworkers (IPython.kernel.task.FIFOScheduler attribute)</a></dt>
+</dl></td></tr></table>
+
+<h2 id="O">O</h2>
+<table width="100%" class="indextable"><tr><td width="33%" valign="top">
+<dl>
+
+<dt><a href="api/generated/IPython.kernel.core.magic.html#IPython.kernel.core.magic.Magic.object_find">object_find() (IPython.kernel.core.magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.prefilter.html#IPython.prefilter.LineInfo.ofind">ofind() (IPython.prefilter.LineInfo method)</a></dt>
+<dt><a href="api/generated/IPython.frontend.wx.ipythonx.html#IPython.frontend.wx.ipythonx.IPythonX.on_close">on_close() (IPython.frontend.wx.ipythonx.IPythonX method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.redirector_output_trap.html#IPython.kernel.core.redirector_output_trap.RedirectorOutputTrap.on_err_write">on_err_write() (IPython.kernel.core.redirector_output_trap.RedirectorOutputTrap method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.controllerservice.html#IPython.kernel.controllerservice.ControllerAdapterBase.on_n_engines_registered_do">on_n_engines_registered_do() (IPython.kernel.controllerservice.ControllerAdapterBase method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.controllerservice.html#IPython.kernel.controllerservice.ControllerService.on_n_engines_registered_do">(IPython.kernel.controllerservice.ControllerService method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.on_off">on_off() (in module IPython.Magic)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.redirector_output_trap.html#IPython.kernel.core.redirector_output_trap.RedirectorOutputTrap.on_out_write">on_out_write() (IPython.kernel.core.redirector_output_trap.RedirectorOutputTrap method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.controllerservice.html#IPython.kernel.controllerservice.ControllerAdapterBase.on_register_engine_do">on_register_engine_do() (IPython.kernel.controllerservice.ControllerAdapterBase method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.controllerservice.html#IPython.kernel.controllerservice.ControllerService.on_register_engine_do">(IPython.kernel.controllerservice.ControllerService method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.controllerservice.html#IPython.kernel.controllerservice.ControllerAdapterBase.on_register_engine_do_not">on_register_engine_do_not() (IPython.kernel.controllerservice.ControllerAdapterBase method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.controllerservice.html#IPython.kernel.controllerservice.ControllerService.on_register_engine_do_not">(IPython.kernel.controllerservice.ControllerService method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.Shell.html#IPython.Shell.IPShellGTK.on_timer">on_timer() (IPython.Shell.IPShellGTK method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.Shell.html#IPython.Shell.IPShellQt.on_timer">(IPython.Shell.IPShellQt method)</a></dt>
+ <dt><a href="api/generated/IPython.Shell.html#IPython.Shell.IPShellQt4.on_timer">(IPython.Shell.IPShellQt4 method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.controllerservice.html#IPython.kernel.controllerservice.ControllerAdapterBase.on_unregister_engine_do">on_unregister_engine_do() (IPython.kernel.controllerservice.ControllerAdapterBase method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.controllerservice.html#IPython.kernel.controllerservice.ControllerService.on_unregister_engine_do">(IPython.kernel.controllerservice.ControllerService method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.controllerservice.html#IPython.kernel.controllerservice.ControllerAdapterBase.on_unregister_engine_do_not">on_unregister_engine_do_not() (IPython.kernel.controllerservice.ControllerAdapterBase method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.controllerservice.html#IPython.kernel.controllerservice.ControllerService.on_unregister_engine_do_not">(IPython.kernel.controllerservice.ControllerService method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.gui.wx.wxIPython.html#IPython.gui.wx.wxIPython.MyFrame.OnClose">OnClose() (IPython.gui.wx.wxIPython.MyFrame method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.wxIPython.html#IPython.gui.wx.wxIPython.MyFrame.OnExitDlg">OnExitDlg() (IPython.gui.wx.wxIPython.MyFrame method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_history.html#IPython.gui.wx.ipython_history.PythonSTC.OnKeyPressed">OnKeyPressed() (IPython.gui.wx.ipython_history.PythonSTC method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_history.html#IPython.gui.wx.ipython_history.PythonSTC.OnMarginClick">OnMarginClick() (IPython.gui.wx.ipython_history.PythonSTC method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.wxIPython.html#IPython.gui.wx.wxIPython.MyFrame.OnShowAbout">OnShowAbout() (IPython.gui.wx.wxIPython.MyFrame method)</a></dt></dl></td><td width="33%" valign="top"><dl>
+<dt><a href="api/generated/IPython.gui.wx.wxIPython.html#IPython.gui.wx.wxIPython.MyFrame.OnShowAllPanel">OnShowAllPanel() (IPython.gui.wx.wxIPython.MyFrame method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.wxIPython.html#IPython.gui.wx.wxIPython.MyFrame.OnShowHistoryPanel">OnShowHistoryPanel() (IPython.gui.wx.wxIPython.MyFrame method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.wxIPython.html#IPython.gui.wx.wxIPython.MyFrame.OnShowIPythonPanel">OnShowIPythonPanel() (IPython.gui.wx.wxIPython.MyFrame method)</a></dt>
+<dt><a href="api/generated/IPython.frontend.wx.console_widget.html#IPython.frontend.wx.console_widget.ConsoleWidget.OnUpdateUI">OnUpdateUI() (IPython.frontend.wx.console_widget.ConsoleWidget method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.frontend.wx.wx_frontend.html#IPython.frontend.wx.wx_frontend.WxController.OnUpdateUI">(IPython.frontend.wx.wx_frontend.WxController method)</a></dt>
+ <dt><a href="api/generated/IPython.gui.wx.ipython_history.html#IPython.gui.wx.ipython_history.PythonSTC.OnUpdateUI">(IPython.gui.wx.ipython_history.PythonSTC method)</a></dt>
+ <dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.WxConsoleView.OnUpdateUI">(IPython.gui.wx.ipython_view.WxConsoleView method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.open">open() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.wxIPython.html#IPython.gui.wx.wxIPython.MyFrame.optionLoad">optionLoad() (IPython.gui.wx.wxIPython.MyFrame method)</a></dt>
+<dt><a href="api/generated/IPython.ipapi.html#IPython.ipapi.IPApi.options">options (IPython.ipapi.IPApi attribute)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.wxIPython.html#IPython.gui.wx.wxIPython.MyFrame.optionSave">optionSave() (IPython.gui.wx.wxIPython.MyFrame method)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.optstr2types">optstr2types() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.clipboard.html#IPython.clipboard.osx_clipboard_get">osx_clipboard_get() (in module IPython.clipboard)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.output_trap.html#IPython.kernel.core.output_trap.OutputTrap.out_text">out_text (IPython.kernel.core.output_trap.OutputTrap attribute)</a></dt>
+<dt><a href="api/generated/IPython.external.pretty.html#IPython.external.pretty.Breakable.output">output() (IPython.external.pretty.Breakable method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.external.pretty.html#IPython.external.pretty.Printable.output">(IPython.external.pretty.Printable method)</a></dt>
+ <dt><a href="api/generated/IPython.external.pretty.html#IPython.external.pretty.Text.output">(IPython.external.pretty.Text method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.frontend.frontendbase.html#IPython.frontend.frontendbase.FrontEndBase.output_prompt">output_prompt() (IPython.frontend.frontendbase.FrontEndBase method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.output_trap.html#IPython.kernel.core.output_trap.OutputTrap">OutputTrap (class in IPython.kernel.core.output_trap)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.OutputTrap.html#IPython.OutputTrap.OutputTrap">(class in IPython.OutputTrap)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.OutputTrap.html#IPython.OutputTrap.OutputTrapError">OutputTrapError (class in IPython.OutputTrap)</a></dt>
+<dt><a href="api/generated/IPython.kernel.scripts.ipcluster.html#IPython.kernel.scripts.ipcluster.LauncherProcessProtocol.outReceived">outReceived() (IPython.kernel.scripts.ipcluster.LauncherProcessProtocol method)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.owner">owner (IPython.external.path.path attribute)</a></dt>
+</dl></td></tr></table>
+
+<h2 id="P">P</h2>
+<table width="100%" class="indextable"><tr><td width="33%" valign="top">
+<dl>
+
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.LSString.p">p (IPython.genutils.LSString attribute)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.genutils.html#IPython.genutils.SList.p">(IPython.genutils.SList attribute)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.core.prompts.html#IPython.kernel.core.prompts.BasePrompt.p_template">p_template (IPython.kernel.core.prompts.BasePrompt attribute)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.Prompts.html#IPython.Prompts.BasePrompt.p_template">(IPython.Prompts.BasePrompt attribute)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.core.interpreter.html#IPython.kernel.core.interpreter.Interpreter.pack_exception">pack_exception() (IPython.kernel.core.interpreter.Interpreter method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.pbutil.html#IPython.kernel.pbutil.packageFailure">packageFailure() (in module IPython.kernel.pbutil)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCSynchronousMultiEngineFromMultiEngine.packageFailure">(IPython.kernel.multienginefc.FCSynchronousMultiEngineFromMultiEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.taskfc.html#IPython.kernel.taskfc.FCTaskControllerFromTaskController.packageFailure">(IPython.kernel.taskfc.FCTaskControllerFromTaskController method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.packageResult">packageResult() (in module IPython.kernel.multienginefc)</a></dt>
+<dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCSynchronousMultiEngineFromMultiEngine.packageSuccess">packageSuccess() (IPython.kernel.multienginefc.FCSynchronousMultiEngineFromMultiEngine method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.taskfc.html#IPython.kernel.taskfc.FCTaskControllerFromTaskController.packageSuccess">(IPython.kernel.taskfc.FCTaskControllerFromTaskController method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.page">page() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.page_dumb">page_dumb() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.page_file">page_file() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.IPShellWidget.pager">pager() (IPython.gui.wx.ipython_view.IPShellWidget method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.FullBlockingMultiEngineClient.parallel">parallel() (IPython.kernel.multiengineclient.FullBlockingMultiEngineClient method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient.parallel">(IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.taskclient.html#IPython.kernel.taskclient.BlockingTaskClient.parallel">(IPython.kernel.taskclient.BlockingTaskClient method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.taskfc.html#IPython.kernel.taskfc.FCTaskClient.parallel">(IPython.kernel.taskfc.FCTaskClient method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.parallelfunction.html#IPython.kernel.parallelfunction.ParallelFunction">ParallelFunction (class in IPython.kernel.parallelfunction)</a></dt>
+<dt><a href="api/generated/IPython.testing.parametric.html#IPython.testing.parametric.parametric">parametric() (in module IPython.testing.parametric)</a></dt>
+<dt><a href="api/generated/IPython.testing.parametric.html#IPython.testing.parametric.Parametric">Parametric() (in module IPython.testing.parametric)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.parent">parent (IPython.external.path.path attribute)</a></dt>
+<dt><a href="api/generated/IPython.external.argparse.html#IPython.external.argparse.ArgumentParser.parse_args">parse_args() (IPython.external.argparse.ArgumentParser method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.scripts.ipcluster.html#IPython.kernel.scripts.ipcluster.BatchEngineSet.parse_job_id">parse_job_id() (IPython.kernel.scripts.ipcluster.BatchEngineSet method)</a></dt>
+<dt><a href="api/generated/IPython.external.argparse.html#IPython.external.argparse.ArgumentParser.parse_known_args">parse_known_args() (IPython.external.argparse.ArgumentParser method)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.parse_options">parse_options() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.DPyGetOpt.html#IPython.DPyGetOpt.DPyGetOpt.parseConfiguration">parseConfiguration() (IPython.DPyGetOpt.DPyGetOpt method)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.ParseError">ParseError (class in IPython.external.configobj)</a></dt>
+<dt><a href="api/generated/IPython.PyColorize.html#IPython.PyColorize.Parser">Parser (class in IPython.PyColorize)</a></dt>
+<dt><a href="api/generated/IPython.kernel.twistedutil.html#IPython.kernel.twistedutil.parseResults">parseResults() (in module IPython.kernel.twistedutil)</a></dt>
+<dt><a href="api/generated/IPython.testing.parametric.html#IPython.testing.parametric.partial">partial() (in module IPython.testing.parametric)</a></dt>
+<dt><a href="overview.html#index-0">PATH</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path">path (class in IPython.external.path)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.pathconf">pathconf() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.LSString.paths">paths (IPython.genutils.LSString attribute)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.genutils.html#IPython.genutils.SList.paths">(IPython.genutils.SList attribute)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.PBMessageSizeError">PBMessageSizeError (class in IPython.kernel.error)</a></dt>
+<dt><a href="api/generated/IPython.kernel.scripts.ipcluster.html#IPython.kernel.scripts.ipcluster.PBSEngineSet">PBSEngineSet (class in IPython.kernel.scripts.ipcluster)</a></dt>
+<dt><a href="api/generated/IPython.Debugger.html#IPython.Debugger.Pdb">Pdb (class in IPython.Debugger)</a></dt>
+<dt><a href="api/generated/IPython.OInspect.html#IPython.OInspect.Inspector.pdef">pdef() (IPython.OInspect.Inspector method)</a></dt>
+<dt><a href="api/generated/IPython.OInspect.html#IPython.OInspect.Inspector.pdoc">pdoc() (IPython.OInspect.Inspector method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.pendingdeferred.html#IPython.kernel.pendingdeferred.PendingDeferredManager">PendingDeferredManager (class in IPython.kernel.pendingdeferred)</a></dt>
+<dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.PendingResult">PendingResult (class in IPython.kernel.multiengineclient)</a></dt>
+<dt><a href="api/generated/IPython.irunner.html#IPython.irunner.pexpect_monkeypatch">pexpect_monkeypatch() (in module IPython.irunner)</a></dt>
+<dt><a href="api/generated/IPython.OInspect.html#IPython.OInspect.Inspector.pfile">pfile() (IPython.OInspect.Inspector method)</a></dt>
+<dt><a href="api/generated/IPython.OInspect.html#IPython.OInspect.Inspector.pinfo">pinfo() (IPython.OInspect.Inspector method)</a></dt>
+<dt><a href="api/generated/IPython.frontend.process.pipedprocess.html#IPython.frontend.process.pipedprocess.PipedProcess">PipedProcess (class in IPython.frontend.process.pipedprocess)</a></dt>
+<dt><a href="api/generated/IPython.ultraTB.html#IPython.ultraTB.FormattedTB.plain">plain() (IPython.ultraTB.FormattedTB method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.traceback_formatter.html#IPython.kernel.core.traceback_formatter.PlainTracebackFormatter">PlainTracebackFormatter (class in IPython.kernel.core.traceback_formatter)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.Section.pop">pop() (IPython.external.configobj.Section method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.StrictDict.pop">(IPython.kernel.engineservice.StrictDict method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.frontend.wx.console_widget.html#IPython.frontend.wx.console_widget.ConsoleWidget.pop_completion">pop_completion() (IPython.frontend.wx.console_widget.ConsoleWidget method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.FIFOScheduler.pop_task">pop_task() (IPython.kernel.task.FIFOScheduler method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.FIFOScheduler.pop_worker">pop_worker() (IPython.kernel.task.FIFOScheduler method)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.Section.popitem">popitem() (IPython.external.configobj.Section method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.ipstruct.html#IPython.ipstruct.Struct.popitem">(IPython.ipstruct.Struct method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.StrictDict.popitem">(IPython.kernel.engineservice.StrictDict method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.popkey">popkey() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.demo.html#IPython.demo.Demo.post_cmd">post_cmd() (IPython.demo.Demo method)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.post_config_initialization">post_config_initialization() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.notification.html#IPython.kernel.core.notification.NotificationCenter.post_notification">post_notification() (IPython.kernel.core.notification.NotificationCenter method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.BaseTask.post_task">post_task() (IPython.kernel.task.BaseTask method)</a></dt>
+<dt><a href="api/generated/IPython.Debugger.html#IPython.Debugger.Pdb.postloop">postloop() (IPython.Debugger.Pdb method)</a></dt>
+<dt><a href="api/generated/IPython.external.pretty.html#IPython.external.pretty.pprint">pprint() (in module IPython.external.pretty)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.display_formatter.html#IPython.kernel.core.display_formatter.PPrintDisplayFormatter">PPrintDisplayFormatter (class in IPython.kernel.core.display_formatter)</a></dt>
+<dt><a href="api/generated/IPython.demo.html#IPython.demo.ClearMixin.pre_cmd">pre_cmd() (IPython.demo.ClearMixin method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.demo.html#IPython.demo.Demo.pre_cmd">(IPython.demo.Demo method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.pre_config_initialization">pre_config_initialization() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.hooks.html#IPython.hooks.pre_prompt_hook">pre_prompt_hook() (in module IPython.hooks)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.pre_readline">pre_readline() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.hooks.html#IPython.hooks.pre_runcode_hook">pre_runcode_hook() (in module IPython.hooks)</a></dt>
+<dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.BaseTask.pre_task">pre_task() (IPython.kernel.task.BaseTask method)</a></dt>
+<dt><a href="api/generated/IPython.prefilter.html#IPython.prefilter.prefilter">prefilter() (in module IPython.prefilter)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.prefilter">(IPython.iplib.InteractiveShell method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.frontend.linefrontendbase.html#IPython.frontend.linefrontendbase.LineFrontEndBase.prefilter_input">prefilter_input() (IPython.frontend.linefrontendbase.LineFrontEndBase method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.frontend.prefilterfrontend.html#IPython.frontend.prefilterfrontend.PrefilterFrontEnd.prefilter_input">(IPython.frontend.prefilterfrontend.PrefilterFrontEnd method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.frontend.prefilterfrontend.html#IPython.frontend.prefilterfrontend.PrefilterFrontEnd">PrefilterFrontEnd (class in IPython.frontend.prefilterfrontend)</a></dt>
+<dt><a href="api/generated/IPython.external.pretty.html#IPython.external.pretty.pretty">pretty() (in module IPython.external.pretty)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.external.pretty.html#IPython.external.pretty.RepresentationPrinter.pretty">(IPython.external.pretty.RepresentationPrinter method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.external.pretty.html#IPython.external.pretty.PrettyPrinter">PrettyPrinter (class in IPython.external.pretty)</a></dt>
+<dt><a href="api/generated/IPython.external.argparse.html#IPython.external.argparse.ArgumentParser.print_help">print_help() (IPython.external.argparse.ArgumentParser method)</a></dt>
+<dt><a href="api/generated/IPython.Debugger.html#IPython.Debugger.Pdb.print_list_lines">print_list_lines() (IPython.Debugger.Pdb method)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.print_lsstring">print_lsstring() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.print_slist">print_slist() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.Debugger.html#IPython.Debugger.Pdb.print_stack_entry">print_stack_entry() (IPython.Debugger.Pdb method)</a></dt></dl></td><td width="33%" valign="top"><dl>
+<dt><a href="api/generated/IPython.Debugger.html#IPython.Debugger.Pdb.print_stack_trace">print_stack_trace() (IPython.Debugger.Pdb method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.CompositeError.print_tracebacks">print_tracebacks() (IPython.kernel.error.CompositeError method)</a></dt>
+<dt><a href="api/generated/IPython.external.argparse.html#IPython.external.argparse.ArgumentParser.print_usage">print_usage() (IPython.external.argparse.ArgumentParser method)</a></dt>
+<dt><a href="api/generated/IPython.external.argparse.html#IPython.external.argparse.ArgumentParser.print_version">print_version() (IPython.external.argparse.ArgumentParser method)</a></dt>
+<dt><a href="api/generated/IPython.external.pretty.html#IPython.external.pretty.Printable">Printable (class in IPython.external.pretty)</a></dt>
+<dt><a href="api/generated/IPython.kernel.util.html#IPython.kernel.util.printer">printer() (in module IPython.kernel.util)</a></dt>
+<dt><a href="api/generated/IPython.external.Itpl.html#IPython.external.Itpl.printpl">printpl() (in module IPython.external.Itpl)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.Itpl.html#IPython.Itpl.printpl">(in module IPython.Itpl)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.external.Itpl.html#IPython.external.Itpl.printplns">printplns() (in module IPython.external.Itpl)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.Itpl.html#IPython.Itpl.printplns">(in module IPython.Itpl)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.process_cmdline">process_cmdline() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.BaseTask.process_result">process_result() (IPython.kernel.task.BaseTask method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.StringTask.process_result">(IPython.kernel.task.StringTask method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.DPyGetOpt.html#IPython.DPyGetOpt.DPyGetOpt.processArguments">processArguments() (IPython.DPyGetOpt.DPyGetOpt method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.scripts.ipcluster.html#IPython.kernel.scripts.ipcluster.LauncherProcessProtocol.processEnded">processEnded() (IPython.kernel.scripts.ipcluster.LauncherProcessProtocol method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.scripts.ipcluster.html#IPython.kernel.scripts.ipcluster.ProcessLauncher">ProcessLauncher (class in IPython.kernel.scripts.ipcluster)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_history.html#IPython.gui.wx.ipython_history.IPythonHistoryPanel.processOptionCheckedEvt">processOptionCheckedEvt() (IPython.gui.wx.ipython_history.IPythonHistoryPanel method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.scripts.ipcluster.html#IPython.kernel.scripts.ipcluster.ProcessStateError">ProcessStateError (class in IPython.kernel.scripts.ipcluster)</a></dt>
+<dt><a href="api/generated/IPython.Magic.html#IPython.Magic.Magic.profile_missing_notice">profile_missing_notice() (IPython.Magic.Magic method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.prompts.html#IPython.kernel.core.prompts.Prompt1">Prompt1 (class in IPython.kernel.core.prompts)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.Prompts.html#IPython.Prompts.Prompt1">(class in IPython.Prompts)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.core.prompts.html#IPython.kernel.core.prompts.Prompt2">Prompt2 (class in IPython.kernel.core.prompts)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.Prompts.html#IPython.Prompts.Prompt2">(class in IPython.Prompts)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.core.prompts.html#IPython.kernel.core.prompts.PromptOut">PromptOut (class in IPython.kernel.core.prompts)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.Prompts.html#IPython.Prompts.PromptOut">(class in IPython.Prompts)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.EngineFromReference.properties">properties (IPython.kernel.enginefc.EngineFromReference attribute)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.QueuedEngine.properties">(IPython.kernel.engineservice.QueuedEngine attribute)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.WorkerFromQueuedEngine.properties">(IPython.kernel.task.WorkerFromQueuedEngine attribute)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.ProtocolError">ProtocolError (class in IPython.kernel.error)</a></dt>
+<dt><a href="api/generated/IPython.OInspect.html#IPython.OInspect.Inspector.psearch">psearch() (IPython.OInspect.Inspector method)</a></dt>
+<dt><a href="api/generated/IPython.OInspect.html#IPython.OInspect.Inspector.psource">psource() (IPython.OInspect.Inspector method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.interpreter.html#IPython.kernel.core.interpreter.Interpreter.pull">pull() (IPython.kernel.core.interpreter.Interpreter method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.EngineFromReference.pull">(IPython.kernel.enginefc.EngineFromReference method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.EngineService.pull">(IPython.kernel.engineservice.EngineService method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.QueuedEngine.pull">(IPython.kernel.engineservice.QueuedEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.MultiEngine.pull">(IPython.kernel.multiengine.MultiEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.SynchronousMultiEngine.pull">(IPython.kernel.multiengine.SynchronousMultiEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.FullBlockingMultiEngineClient.pull">(IPython.kernel.multiengineclient.FullBlockingMultiEngineClient method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient.pull">(IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.core.interpreter.html#IPython.kernel.core.interpreter.Interpreter.pull_function">pull_function() (IPython.kernel.core.interpreter.Interpreter method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.EngineFromReference.pull_function">(IPython.kernel.enginefc.EngineFromReference method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.EngineService.pull_function">(IPython.kernel.engineservice.EngineService method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.QueuedEngine.pull_function">(IPython.kernel.engineservice.QueuedEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.MultiEngine.pull_function">(IPython.kernel.multiengine.MultiEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.SynchronousMultiEngine.pull_function">(IPython.kernel.multiengine.SynchronousMultiEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.FullBlockingMultiEngineClient.pull_function">(IPython.kernel.multiengineclient.FullBlockingMultiEngineClient method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient.pull_function">(IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.EngineFromReference.pull_serialized">pull_serialized() (IPython.kernel.enginefc.EngineFromReference method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.EngineService.pull_serialized">(IPython.kernel.engineservice.EngineService method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.QueuedEngine.pull_serialized">(IPython.kernel.engineservice.QueuedEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.MultiEngine.pull_serialized">(IPython.kernel.multiengine.MultiEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.SynchronousMultiEngine.pull_serialized">(IPython.kernel.multiengine.SynchronousMultiEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.FullBlockingMultiEngineClient.pull_serialized">(IPython.kernel.multiengineclient.FullBlockingMultiEngineClient method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient.pull_serialized">(IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.push">push() (IPython.iplib.InteractiveShell method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.core.interpreter.html#IPython.kernel.core.interpreter.Interpreter.push">(IPython.kernel.core.interpreter.Interpreter method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.EngineFromReference.push">(IPython.kernel.enginefc.EngineFromReference method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.EngineService.push">(IPython.kernel.engineservice.EngineService method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.QueuedEngine.push">(IPython.kernel.engineservice.QueuedEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.MultiEngine.push">(IPython.kernel.multiengine.MultiEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.SynchronousMultiEngine.push">(IPython.kernel.multiengine.SynchronousMultiEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.FullBlockingMultiEngineClient.push">(IPython.kernel.multiengineclient.FullBlockingMultiEngineClient method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient.push">(IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.core.interpreter.html#IPython.kernel.core.interpreter.Interpreter.push_function">push_function() (IPython.kernel.core.interpreter.Interpreter method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.EngineFromReference.push_function">(IPython.kernel.enginefc.EngineFromReference method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.EngineService.push_function">(IPython.kernel.engineservice.EngineService method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.QueuedEngine.push_function">(IPython.kernel.engineservice.QueuedEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.MultiEngine.push_function">(IPython.kernel.multiengine.MultiEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.SynchronousMultiEngine.push_function">(IPython.kernel.multiengine.SynchronousMultiEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.FullBlockingMultiEngineClient.push_function">(IPython.kernel.multiengineclient.FullBlockingMultiEngineClient method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient.push_function">(IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.EngineFromReference.push_serialized">push_serialized() (IPython.kernel.enginefc.EngineFromReference method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.EngineService.push_serialized">(IPython.kernel.engineservice.EngineService method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.QueuedEngine.push_serialized">(IPython.kernel.engineservice.QueuedEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.MultiEngine.push_serialized">(IPython.kernel.multiengine.MultiEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.SynchronousMultiEngine.push_serialized">(IPython.kernel.multiengine.SynchronousMultiEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.FullBlockingMultiEngineClient.push_serialized">(IPython.kernel.multiengineclient.FullBlockingMultiEngineClient method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient.push_serialized">(IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.magic.html#IPython.kernel.magic.pxrunsource">pxrunsource() (in module IPython.kernel.magic)</a></dt>
+<dt><a href="api/generated/IPython.testing.plugin.dtexample.html#IPython.testing.plugin.dtexample.pyfunc">pyfunc() (in module IPython.testing.plugin.dtexample)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.testing.plugin.simple.html#IPython.testing.plugin.simple.pyfunc">(in module IPython.testing.plugin.simple)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.completer.html#IPython.completer.IPCompleter.python_func_kw_matches">python_func_kw_matches() (IPython.completer.IPCompleter method)</a></dt>
+<dt><a href="api/generated/IPython.completer.html#IPython.completer.IPCompleter.python_matches">python_matches() (IPython.completer.IPCompleter method)</a></dt>
+<dt><a href="api/generated/IPython.irunner.html#IPython.irunner.PythonRunner">PythonRunner (class in IPython.irunner)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_history.html#IPython.gui.wx.ipython_history.PythonSTC">PythonSTC (class in IPython.gui.wx.ipython_history)</a></dt>
+</dl></td></tr></table>
+
+<h2 id="Q">Q</h2>
+<table width="100%" class="indextable"><tr><td width="33%" valign="top">
+<dl>
+
+<dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.queue">queue() (in module IPython.kernel.engineservice)</a></dt>
+<dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.QueuedEngine.queue_status">queue_status() (IPython.kernel.engineservice.QueuedEngine method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.MultiEngine.queue_status">(IPython.kernel.multiengine.MultiEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.SynchronousMultiEngine.queue_status">(IPython.kernel.multiengine.SynchronousMultiEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.FullBlockingMultiEngineClient.queue_status">(IPython.kernel.multiengineclient.FullBlockingMultiEngineClient method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient.queue_status">(IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.TaskController.queue_status">(IPython.kernel.task.TaskController method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.taskclient.html#IPython.kernel.taskclient.BlockingTaskClient.queue_status">(IPython.kernel.taskclient.BlockingTaskClient method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.taskfc.html#IPython.kernel.taskfc.FCTaskClient.queue_status">(IPython.kernel.taskfc.FCTaskClient method)</a></dt>
+ </dl></dd></dl></td><td width="33%" valign="top"><dl>
+<dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.QueueCleared">QueueCleared (class in IPython.kernel.error)</a></dt>
+<dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.QueuedEngine">QueuedEngine (class in IPython.kernel.engineservice)</a></dt>
+<dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.QueueStatusList">QueueStatusList (class in IPython.kernel.multiengineclient)</a></dt>
+<dt><a href="api/generated/IPython.kernel.pendingdeferred.html#IPython.kernel.pendingdeferred.PendingDeferredManager.quick_has_id">quick_has_id() (IPython.kernel.pendingdeferred.PendingDeferredManager method)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.Quitter">Quitter (class in IPython.iplib)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.qw">qw() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.qw_lol">qw_lol() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.qwflat">qwflat() (in module IPython.genutils)</a></dt>
+</dl></td></tr></table>
+
+<h2 id="R">R</h2>
+<table width="100%" class="indextable"><tr><td width="33%" valign="top">
+<dl>
+
+<dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.PendingResult.r">r (IPython.kernel.multiengineclient.PendingResult attribute)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.thread_ex.html#IPython.gui.wx.thread_ex.ThreadEx.raise_exc">raise_exc() (IPython.gui.wx.thread_ex.ThreadEx method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.CompositeError.raise_exception">raise_exception() (IPython.kernel.error.CompositeError method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.TaskResult.raise_exception">(IPython.kernel.task.TaskResult method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.testing.plugin.dtexample.html#IPython.testing.plugin.dtexample.random_all">random_all() (in module IPython.testing.plugin.dtexample)</a></dt>
+<dt><a href="api/generated/IPython.testing.plugin.dtexample.html#IPython.testing.plugin.dtexample.ranfunc">ranfunc() (in module IPython.testing.plugin.dtexample)</a></dt>
+<dt><a href="api/generated/IPython.frontend.wx.wx_frontend.html#IPython.frontend.wx.wx_frontend.WxController.raw_input">raw_input() (IPython.frontend.wx.wx_frontend.WxController method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.raw_input">(IPython.iplib.InteractiveShell method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.raw_input_ext">raw_input_ext() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.raw_input_multi">raw_input_multi() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.FullBlockingMultiEngineClient.raw_map">raw_map() (IPython.kernel.multiengineclient.FullBlockingMultiEngineClient method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient.raw_map">(IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.external.argparse.html#IPython.external.argparse.RawDescriptionHelpFormatter">RawDescriptionHelpFormatter (class in IPython.external.argparse)</a></dt>
+<dt><a href="api/generated/IPython.external.argparse.html#IPython.external.argparse.RawTextHelpFormatter">RawTextHelpFormatter (class in IPython.external.argparse)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.rc_set_toggle">rc_set_toggle() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.demo.html#IPython.demo.re_mark">re_mark() (in module IPython.demo)</a></dt>
+<dt><a href="api/generated/IPython.kernel.twistedutil.html#IPython.kernel.twistedutil.ReactorInThread">ReactorInThread (class in IPython.kernel.twistedutil)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.read_dict">read_dict() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.read_md5">read_md5() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.readlink">readlink() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.readlinkabs">readlinkabs() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.TaskController.readmitWorker">readmitWorker() (IPython.kernel.task.TaskController method)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.realpath">realpath() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.pickleutil.html#IPython.kernel.pickleutil.rebindFunctionGlobals">rebindFunctionGlobals() (in module IPython.kernel.pickleutil)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.redirector_output_trap.html#IPython.kernel.core.redirector_output_trap.RedirectorOutputTrap">RedirectorOutputTrap (class in IPython.kernel.core.redirector_output_trap)</a></dt>
+<dt><a href="api/generated/IPython.kernel.codeutil.html#IPython.kernel.codeutil.reduce_code">reduce_code() (in module IPython.kernel.codeutil)</a></dt>
+<dt><a href="api/generated/IPython.kernel.controllerservice.html#IPython.kernel.controllerservice.ControllerAdapterBase.register_engine">register_engine() (IPython.kernel.controllerservice.ControllerAdapterBase method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.controllerservice.html#IPython.kernel.controllerservice.ControllerService.register_engine">(IPython.kernel.controllerservice.ControllerService method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.QueuedEngine.register_failure_observer">register_failure_observer() (IPython.kernel.engineservice.QueuedEngine method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.TaskController.registerWorker">registerWorker() (IPython.kernel.task.TaskController method)</a></dt>
+<dt><a href="api/generated/IPython.OutputTrap.html#IPython.OutputTrap.OutputTrap.release">release() (IPython.OutputTrap.OutputTrap method)</a></dt>
+<dt><a href="api/generated/IPython.OutputTrap.html#IPython.OutputTrap.OutputTrap.release_all">release_all() (IPython.OutputTrap.OutputTrap method)</a></dt>
+<dt><a href="api/generated/IPython.OutputTrap.html#IPython.OutputTrap.OutputTrap.release_err">release_err() (IPython.OutputTrap.OutputTrap method)</a></dt>
+<dt><a href="api/generated/IPython.OutputTrap.html#IPython.OutputTrap.OutputTrap.release_out">release_out() (IPython.OutputTrap.OutputTrap method)</a></dt>
+<dt><a href="api/generated/IPython.frontend.prefilterfrontend.html#IPython.frontend.prefilterfrontend.PrefilterFrontEnd.release_output">release_output() (IPython.frontend.prefilterfrontend.PrefilterFrontEnd method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.frontend.wx.wx_frontend.html#IPython.frontend.wx.wx_frontend.WxController.release_output">(IPython.frontend.wx.wx_frontend.WxController method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.deep_reload.html#IPython.deep_reload.reload">reload() (in module IPython.deep_reload)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.demo.html#IPython.demo.Demo.reload">(IPython.demo.Demo method)</a></dt>
+ <dt><a href="api/generated/IPython.demo.html#IPython.demo.LineDemo.reload">(IPython.demo.LineDemo method)</a></dt>
+ <dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.ConfigObj.reload">(IPython.external.configobj.ConfigObj method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.ReloadError">ReloadError (class in IPython.external.configobj)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.reloadhist">reloadhist() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_history.html#IPython.gui.wx.ipython_history.IPythonHistoryPanel.reloadOptions">reloadOptions() (IPython.gui.wx.ipython_history.IPythonHistoryPanel method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.IPShellWidget.reloadOptions">(IPython.gui.wx.ipython_view.IPShellWidget method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.relpath">relpath() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.relpathto">relpathto() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.contexts.html#IPython.kernel.contexts.remote">remote() (in module IPython.kernel.contexts)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.remote">(in module IPython.kernel.multiengineclient)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.taskfc.html#IPython.kernel.taskfc.FCTaskControllerFromTaskController.remote_abort">remote_abort() (IPython.kernel.taskfc.FCTaskControllerFromTaskController method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.taskfc.html#IPython.kernel.taskfc.FCTaskControllerFromTaskController.remote_barrier">remote_barrier() (IPython.kernel.taskfc.FCTaskControllerFromTaskController method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.taskfc.html#IPython.kernel.taskfc.FCTaskControllerFromTaskController.remote_clear">remote_clear() (IPython.kernel.taskfc.FCTaskControllerFromTaskController method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCSynchronousMultiEngineFromMultiEngine.remote_clear_pending_deferreds">remote_clear_pending_deferreds() (IPython.kernel.multienginefc.FCSynchronousMultiEngineFromMultiEngine method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.FCEngineReferenceFromService.remote_clear_properties">remote_clear_properties() (IPython.kernel.enginefc.FCEngineReferenceFromService method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCSynchronousMultiEngineFromMultiEngine.remote_clear_properties">(IPython.kernel.multienginefc.FCSynchronousMultiEngineFromMultiEngine method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCSynchronousMultiEngineFromMultiEngine.remote_clear_queue">remote_clear_queue() (IPython.kernel.multienginefc.FCSynchronousMultiEngineFromMultiEngine method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.FCEngineReferenceFromService.remote_del_properties">remote_del_properties() (IPython.kernel.enginefc.FCEngineReferenceFromService method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCSynchronousMultiEngineFromMultiEngine.remote_del_properties">(IPython.kernel.multienginefc.FCSynchronousMultiEngineFromMultiEngine method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.FCEngineReferenceFromService.remote_execute">remote_execute() (IPython.kernel.enginefc.FCEngineReferenceFromService method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCSynchronousMultiEngineFromMultiEngine.remote_execute">(IPython.kernel.multienginefc.FCSynchronousMultiEngineFromMultiEngine method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCSynchronousMultiEngineFromMultiEngine.remote_get_client_name">remote_get_client_name() (IPython.kernel.multienginefc.FCSynchronousMultiEngineFromMultiEngine method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.taskfc.html#IPython.kernel.taskfc.FCTaskControllerFromTaskController.remote_get_client_name">(IPython.kernel.taskfc.FCTaskControllerFromTaskController method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.FCEngineReferenceFromService.remote_get_id">remote_get_id() (IPython.kernel.enginefc.FCEngineReferenceFromService method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCSynchronousMultiEngineFromMultiEngine.remote_get_ids">remote_get_ids() (IPython.kernel.multienginefc.FCSynchronousMultiEngineFromMultiEngine method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCSynchronousMultiEngineFromMultiEngine.remote_get_pending_deferred">remote_get_pending_deferred() (IPython.kernel.multienginefc.FCSynchronousMultiEngineFromMultiEngine method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.FCEngineReferenceFromService.remote_get_properties">remote_get_properties() (IPython.kernel.enginefc.FCEngineReferenceFromService method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCSynchronousMultiEngineFromMultiEngine.remote_get_properties">(IPython.kernel.multienginefc.FCSynchronousMultiEngineFromMultiEngine method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.FCEngineReferenceFromService.remote_get_result">remote_get_result() (IPython.kernel.enginefc.FCEngineReferenceFromService method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCSynchronousMultiEngineFromMultiEngine.remote_get_result">(IPython.kernel.multienginefc.FCSynchronousMultiEngineFromMultiEngine method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.taskfc.html#IPython.kernel.taskfc.FCTaskControllerFromTaskController.remote_get_task_result">remote_get_task_result() (IPython.kernel.taskfc.FCTaskControllerFromTaskController method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.FCEngineReferenceFromService.remote_has_properties">remote_has_properties() (IPython.kernel.enginefc.FCEngineReferenceFromService method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCSynchronousMultiEngineFromMultiEngine.remote_has_properties">(IPython.kernel.multienginefc.FCSynchronousMultiEngineFromMultiEngine method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.FCEngineReferenceFromService.remote_keys">remote_keys() (IPython.kernel.enginefc.FCEngineReferenceFromService method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCSynchronousMultiEngineFromMultiEngine.remote_keys">(IPython.kernel.multienginefc.FCSynchronousMultiEngineFromMultiEngine method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.FCEngineReferenceFromService.remote_kill">remote_kill() (IPython.kernel.enginefc.FCEngineReferenceFromService method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCSynchronousMultiEngineFromMultiEngine.remote_kill">(IPython.kernel.multienginefc.FCSynchronousMultiEngineFromMultiEngine method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.FCEngineReferenceFromService.remote_pull">remote_pull() (IPython.kernel.enginefc.FCEngineReferenceFromService method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCSynchronousMultiEngineFromMultiEngine.remote_pull">(IPython.kernel.multienginefc.FCSynchronousMultiEngineFromMultiEngine method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.FCEngineReferenceFromService.remote_pull_function">remote_pull_function() (IPython.kernel.enginefc.FCEngineReferenceFromService method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCSynchronousMultiEngineFromMultiEngine.remote_pull_function">(IPython.kernel.multienginefc.FCSynchronousMultiEngineFromMultiEngine method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.FCEngineReferenceFromService.remote_pull_serialized">remote_pull_serialized() (IPython.kernel.enginefc.FCEngineReferenceFromService method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCSynchronousMultiEngineFromMultiEngine.remote_pull_serialized">(IPython.kernel.multienginefc.FCSynchronousMultiEngineFromMultiEngine method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.FCEngineReferenceFromService.remote_push">remote_push() (IPython.kernel.enginefc.FCEngineReferenceFromService method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCSynchronousMultiEngineFromMultiEngine.remote_push">(IPython.kernel.multienginefc.FCSynchronousMultiEngineFromMultiEngine method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.FCEngineReferenceFromService.remote_push_function">remote_push_function() (IPython.kernel.enginefc.FCEngineReferenceFromService method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCSynchronousMultiEngineFromMultiEngine.remote_push_function">(IPython.kernel.multienginefc.FCSynchronousMultiEngineFromMultiEngine method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.FCEngineReferenceFromService.remote_push_serialized">remote_push_serialized() (IPython.kernel.enginefc.FCEngineReferenceFromService method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCSynchronousMultiEngineFromMultiEngine.remote_push_serialized">(IPython.kernel.multienginefc.FCSynchronousMultiEngineFromMultiEngine method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCSynchronousMultiEngineFromMultiEngine.remote_queue_status">remote_queue_status() (IPython.kernel.multienginefc.FCSynchronousMultiEngineFromMultiEngine method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.taskfc.html#IPython.kernel.taskfc.FCTaskControllerFromTaskController.remote_queue_status">(IPython.kernel.taskfc.FCTaskControllerFromTaskController method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.FCRemoteEngineRefFromService.remote_register_engine">remote_register_engine() (IPython.kernel.enginefc.FCRemoteEngineRefFromService method)</a></dt></dl></td><td width="33%" valign="top"><dl>
+<dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.FCEngineReferenceFromService.remote_reset">remote_reset() (IPython.kernel.enginefc.FCEngineReferenceFromService method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCSynchronousMultiEngineFromMultiEngine.remote_reset">(IPython.kernel.multienginefc.FCSynchronousMultiEngineFromMultiEngine method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.taskfc.html#IPython.kernel.taskfc.FCTaskControllerFromTaskController.remote_run">remote_run() (IPython.kernel.taskfc.FCTaskControllerFromTaskController method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.FCEngineReferenceFromService.remote_set_id">remote_set_id() (IPython.kernel.enginefc.FCEngineReferenceFromService method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.FCEngineReferenceFromService.remote_set_properties">remote_set_properties() (IPython.kernel.enginefc.FCEngineReferenceFromService method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCSynchronousMultiEngineFromMultiEngine.remote_set_properties">(IPython.kernel.multienginefc.FCSynchronousMultiEngineFromMultiEngine method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.taskfc.html#IPython.kernel.taskfc.FCTaskControllerFromTaskController.remote_spin">remote_spin() (IPython.kernel.taskfc.FCTaskControllerFromTaskController method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.contexts.html#IPython.kernel.contexts.RemoteContextBase">RemoteContextBase (class in IPython.kernel.contexts)</a></dt>
+<dt><a href="api/generated/IPython.kernel.contexts.html#IPython.kernel.contexts.RemoteMultiEngine">RemoteMultiEngine (class in IPython.kernel.contexts)</a></dt>
+<dt><a href="api/generated/IPython.background_jobs.html#IPython.background_jobs.BackgroundJobManager.remove">remove() (IPython.background_jobs.BackgroundJobManager method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.remove">(IPython.external.path.path method)</a></dt>
+ <dt><a href="api/generated/IPython.external.pretty.html#IPython.external.pretty.GroupQueue.remove">(IPython.external.pretty.GroupQueue method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.core.notification.html#IPython.kernel.core.notification.NotificationCenter.remove_all_observers">remove_all_observers() (IPython.kernel.core.notification.NotificationCenter method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.WxConsoleView.removeCurrentLine">removeCurrentLine() (IPython.gui.wx.ipython_view.WxConsoleView method)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.removedirs">removedirs() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.WxConsoleView.removeFromTo">removeFromTo() (IPython.gui.wx.ipython_view.WxConsoleView method)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.Section.rename">rename() (IPython.external.configobj.Section method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.rename">(IPython.external.path.path method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.renames">renames() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.frontend.frontendbase.html#IPython.frontend.frontendbase.FrontEndBase.render_error">render_error() (IPython.frontend.frontendbase.FrontEndBase method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.frontend.linefrontendbase.html#IPython.frontend.linefrontendbase.LineFrontEndBase.render_error">(IPython.frontend.linefrontendbase.LineFrontEndBase method)</a></dt>
+ <dt><a href="api/generated/IPython.frontend.wx.wx_frontend.html#IPython.frontend.wx.wx_frontend.WxController.render_error">(IPython.frontend.wx.wx_frontend.WxController method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.frontend.frontendbase.html#IPython.frontend.frontendbase.FrontEndBase.render_result">render_result() (IPython.frontend.frontendbase.FrontEndBase method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.frontend.linefrontendbase.html#IPython.frontend.linefrontendbase.LineFrontEndBase.render_result">(IPython.frontend.linefrontendbase.LineFrontEndBase method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.history.html#IPython.history.rep_f">rep_f() (in module IPython.history)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.RepeatSectionError">RepeatSectionError (class in IPython.external.configobj)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.display_formatter.html#IPython.kernel.core.display_formatter.ReprDisplayFormatter">ReprDisplayFormatter (class in IPython.kernel.core.display_formatter)</a></dt>
+<dt><a href="api/generated/IPython.external.pretty.html#IPython.external.pretty.RepresentationPrinter">RepresentationPrinter (class in IPython.external.pretty)</a></dt>
+<dt><a href="api/generated/IPython.ConfigLoader.html#IPython.ConfigLoader.ConfigLoader.reset">reset() (IPython.ConfigLoader.ConfigLoader method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.demo.html#IPython.demo.Demo.reset">(IPython.demo.Demo method)</a></dt>
+ <dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.ConfigObj.reset">(IPython.external.configobj.ConfigObj method)</a></dt>
+ <dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.reset">(IPython.iplib.InteractiveShell method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.file_like.html#IPython.kernel.core.file_like.FileLike.reset">(IPython.kernel.core.file_like.FileLike method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.interpreter.html#IPython.kernel.core.interpreter.Interpreter.reset">(IPython.kernel.core.interpreter.Interpreter method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.EngineFromReference.reset">(IPython.kernel.enginefc.EngineFromReference method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.EngineService.reset">(IPython.kernel.engineservice.EngineService method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.QueuedEngine.reset">(IPython.kernel.engineservice.QueuedEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.MultiEngine.reset">(IPython.kernel.multiengine.MultiEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.SynchronousMultiEngine.reset">(IPython.kernel.multiengine.SynchronousMultiEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.FullBlockingMultiEngineClient.reset">(IPython.kernel.multiengineclient.FullBlockingMultiEngineClient method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient.reset">(IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.resetbuffer">resetbuffer() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.config.api.html#IPython.config.api.ConfigObjManager.resolve_file_path">resolve_file_path() (IPython.config.api.ConfigObjManager method)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.Section.restore_default">restore_default() (IPython.external.configobj.Section method)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.Section.restore_defaults">restore_defaults() (IPython.external.configobj.Section method)</a></dt>
+<dt><a href="api/generated/IPython.Shell.html#IPython.Shell.IPShellEmbed.restore_system_completer">restore_system_completer() (IPython.Shell.IPShellEmbed method)</a></dt>
+<dt><a href="api/generated/IPython.background_jobs.html#IPython.background_jobs.BackgroundJobManager.result">result() (IPython.background_jobs.BackgroundJobManager method)</a></dt>
+<dt><a href="api/generated/IPython.generics.html#IPython.generics.result_display">result_display() (in module IPython.generics)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.hooks.html#IPython.hooks.result_display">(in module IPython.hooks)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.ResultAlreadyRetrieved">ResultAlreadyRetrieved (class in IPython.kernel.error)</a></dt>
+<dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.ResultList">ResultList (class in IPython.kernel.multiengineclient)</a></dt>
+<dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.ResultNotCompleted">ResultNotCompleted (class in IPython.kernel.error)</a></dt>
+<dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.ResultNS">ResultNS (class in IPython.kernel.task)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.rmdir">rmdir() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.numutils.html#IPython.numutils.rms_flat">rms_flat() (in module IPython.numutils)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.rmtree">rmtree() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.map.html#IPython.kernel.map.RoundRobinMap">RoundRobinMap (class in IPython.kernel.map)</a></dt>
+<dt><a href="api/generated/IPython.background_jobs.html#IPython.background_jobs.BackgroundJobBase.run">run() (IPython.background_jobs.BackgroundJobBase method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.Shell.html#IPython.Shell.IPThread.run">(IPython.Shell.IPThread method)</a></dt>
+ <dt><a href="api/generated/IPython.frontend.process.pipedprocess.html#IPython.frontend.process.pipedprocess.PipedProcess.run">(IPython.frontend.process.pipedprocess.PipedProcess method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.FullBlockingMultiEngineClient.run">(IPython.kernel.multiengineclient.FullBlockingMultiEngineClient method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient.run">(IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.TaskController.run">(IPython.kernel.task.TaskController method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.WorkerFromQueuedEngine.run">(IPython.kernel.task.WorkerFromQueuedEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.taskclient.html#IPython.kernel.taskclient.BlockingTaskClient.run">(IPython.kernel.taskclient.BlockingTaskClient method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.taskfc.html#IPython.kernel.taskfc.FCTaskClient.run">(IPython.kernel.taskfc.FCTaskClient method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.twistedutil.html#IPython.kernel.twistedutil.ReactorInThread.run">(IPython.kernel.twistedutil.ReactorInThread method)</a></dt>
+ <dt><a href="api/generated/IPython.testing.iptest.html#IPython.testing.iptest.IPTester.run">(IPython.testing.iptest.IPTester method)</a></dt>
+ <dt><a href="api/generated/IPython.twshell.html#IPython.twshell.IPShellTwisted.run">(IPython.twshell.IPShellTwisted method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.irunner.html#IPython.irunner.InteractiveRunner.run_file">run_file() (IPython.irunner.InteractiveRunner method)</a></dt>
+<dt><a href="api/generated/IPython.shellglobals.html#IPython.shellglobals.run_in_frontend">run_in_frontend() (in module IPython.shellglobals)</a></dt>
+<dt><a href="api/generated/IPython.testing.iptest.html#IPython.testing.iptest.run_iptest">run_iptest() (in module IPython.testing.iptest)</a></dt>
+<dt><a href="api/generated/IPython.testing.iptest.html#IPython.testing.iptest.run_iptestall">run_iptestall() (in module IPython.testing.iptest)</a></dt>
+<dt><a href="api/generated/IPython.irunner.html#IPython.irunner.InteractiveRunner.run_source">run_source() (IPython.irunner.InteractiveRunner method)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.runcode">runcode() (IPython.iplib.InteractiveShell method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.Shell.html#IPython.Shell.MTInteractiveShell.runcode">(IPython.Shell.MTInteractiveShell method)</a></dt>
+ <dt><a href="api/generated/IPython.twshell.html#IPython.twshell.TwistedInteractiveShell.runcode">(IPython.twshell.TwistedInteractiveShell method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.QueuedEngine.runCurrentCommand">runCurrentCommand() (IPython.kernel.engineservice.QueuedEngine method)</a></dt>
+<dt><a href="api/generated/IPython.dtutils.html#IPython.dtutils.rundoctest">rundoctest() (in module IPython.dtutils)</a></dt>
+<dt><a href="api/generated/IPython.demo.html#IPython.demo.Demo.runlines">runlines() (IPython.demo.Demo method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.demo.html#IPython.demo.IPythonDemo.runlines">(IPython.demo.IPythonDemo method)</a></dt>
+ <dt><a href="api/generated/IPython.ipapi.html#IPython.ipapi.IPApi.runlines">(IPython.ipapi.IPApi method)</a></dt>
+ <dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.runlines">(IPython.iplib.InteractiveShell method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.irunner.html#IPython.irunner.RunnerFactory">RunnerFactory (class in IPython.irunner)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.testing.mkdoctests.html#IPython.testing.mkdoctests.RunnerFactory">(class in IPython.testing.mkdoctests)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.scripts.ipcluster.html#IPython.kernel.scripts.ipcluster.ProcessLauncher.running">running (IPython.kernel.scripts.ipcluster.ProcessLauncher attribute)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.runsource">runsource() (IPython.iplib.InteractiveShell method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.Shell.html#IPython.Shell.MTInteractiveShell.runsource">(IPython.Shell.MTInteractiveShell method)</a></dt>
+ <dt><a href="api/generated/IPython.twshell.html#IPython.twshell.TwistedInteractiveShell.runsource">(IPython.twshell.TwistedInteractiveShell method)</a></dt>
+ </dl></dd>
+</dl></td></tr></table>
+
+<h2 id="S">S</h2>
+<table width="100%" class="indextable"><tr><td width="33%" valign="top">
+<dl>
+
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.LSString.s">s (IPython.genutils.LSString attribute)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.genutils.html#IPython.genutils.SList.s">(IPython.genutils.SList attribute)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.strdispatch.html#IPython.strdispatch.StrDispatch.s_matches">s_matches() (IPython.strdispatch.StrDispatch method)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.safe_execfile">safe_execfile() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.irunner.html#IPython.irunner.SAGERunner">SAGERunner (class in IPython.irunner)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.samefile">samefile() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.frontend.prefilterfrontend.html#IPython.frontend.prefilterfrontend.PrefilterFrontEnd.save_output_hooks">save_output_hooks() (IPython.frontend.prefilterfrontend.PrefilterFrontEnd method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.frontend.wx.wx_frontend.html#IPython.frontend.wx.wx_frontend.WxController.save_output_hooks">(IPython.frontend.wx.wx_frontend.WxController method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.pendingdeferred.html#IPython.kernel.pendingdeferred.PendingDeferredManager.save_pending_deferred">save_pending_deferred() (IPython.kernel.pendingdeferred.PendingDeferredManager method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.clientconnector.html#IPython.kernel.clientconnector.ClientConnector.save_ref">save_ref() (IPython.kernel.clientconnector.ClientConnector method)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.savehist">savehist() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.QueuedEngine.saveResult">saveResult() (IPython.kernel.engineservice.QueuedEngine method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.FullBlockingMultiEngineClient.scatter">scatter() (IPython.kernel.multiengineclient.FullBlockingMultiEngineClient method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient.scatter">(IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.FIFOScheduler.schedule">schedule() (IPython.kernel.task.FIFOScheduler method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.TaskController.SchedulerClass">SchedulerClass() (IPython.kernel.task.TaskController method)</a></dt>
+<dt><a href="api/generated/IPython.frontend.wx.console_widget.html#IPython.frontend.wx.console_widget.ConsoleWidget.scroll_to_bottom">scroll_to_bottom() (IPython.frontend.wx.console_widget.ConsoleWidget method)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.Section">Section (class in IPython.external.configobj)</a></dt>
+<dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.SecurityError">SecurityError (class in IPython.kernel.error)</a></dt>
+<dt><a href="api/generated/IPython.demo.html#IPython.demo.Demo.seek">seek() (IPython.demo.Demo method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.WxConsoleView.selectFromTo">selectFromTo() (IPython.gui.wx.ipython_view.WxConsoleView method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.SerializationError">SerializationError (class in IPython.kernel.error)</a></dt>
+<dt><a href="api/generated/IPython.kernel.newserialized.html#IPython.kernel.newserialized.serialize">serialize() (in module IPython.kernel.newserialized)</a></dt>
+<dt><a href="api/generated/IPython.kernel.newserialized.html#IPython.kernel.newserialized.Serialized">Serialized (class in IPython.kernel.newserialized)</a></dt>
+<dt><a href="api/generated/IPython.kernel.newserialized.html#IPython.kernel.newserialized.SerializeIt">SerializeIt (class in IPython.kernel.newserialized)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.display_trap.html#IPython.kernel.core.display_trap.DisplayTrap.set">set() (IPython.kernel.core.display_trap.DisplayTrap method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.core.output_trap.html#IPython.kernel.core.output_trap.OutputTrap.set">(IPython.kernel.core.output_trap.OutputTrap method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.redirector_output_trap.html#IPython.kernel.core.redirector_output_trap.RedirectorOutputTrap.set">(IPython.kernel.core.redirector_output_trap.RedirectorOutputTrap method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.traceback_trap.html#IPython.kernel.core.traceback_trap.TracebackTrap.set">(IPython.kernel.core.traceback_trap.TracebackTrap method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.ColorANSI.html#IPython.ColorANSI.ColorSchemeTable.set_active_scheme">set_active_scheme() (IPython.ColorANSI.ColorSchemeTable method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.OInspect.html#IPython.OInspect.Inspector.set_active_scheme">(IPython.OInspect.Inspector method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.set_autoindent">set_autoindent() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.Shell.html#IPython.Shell.IPShellEmbed.set_banner">set_banner() (IPython.Shell.IPShellEmbed method)</a></dt>
+<dt><a href="api/generated/IPython.Debugger.html#IPython.Debugger.Pdb.set_colors">set_colors() (IPython.Debugger.Pdb method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.Prompts.html#IPython.Prompts.CachedOutput.set_colors">(IPython.Prompts.CachedOutput method)</a></dt>
+ <dt><a href="api/generated/IPython.Prompts.html#IPython.Prompts.Prompt1.set_colors">(IPython.Prompts.Prompt1 method)</a></dt>
+ <dt><a href="api/generated/IPython.Prompts.html#IPython.Prompts.Prompt2.set_colors">(IPython.Prompts.Prompt2 method)</a></dt>
+ <dt><a href="api/generated/IPython.Prompts.html#IPython.Prompts.PromptOut.set_colors">(IPython.Prompts.PromptOut method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.prompts.html#IPython.kernel.core.prompts.CachedOutput.set_colors">(IPython.kernel.core.prompts.CachedOutput method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.prompts.html#IPython.kernel.core.prompts.Prompt1.set_colors">(IPython.kernel.core.prompts.Prompt1 method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.prompts.html#IPython.kernel.core.prompts.Prompt2.set_colors">(IPython.kernel.core.prompts.Prompt2 method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.prompts.html#IPython.kernel.core.prompts.PromptOut.set_colors">(IPython.kernel.core.prompts.PromptOut method)</a></dt>
+ <dt><a href="api/generated/IPython.ultraTB.html#IPython.ultraTB.TBTools.set_colors">(IPython.ultraTB.TBTools method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.set_completer">set_completer() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.set_completer_frame">set_completer_frame() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.set_crash_handler">set_crash_handler() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.set_custom_completer">set_custom_completer() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.set_custom_exc">set_custom_exc() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.Shell.html#IPython.Shell.IPShellEmbed.set_dummy_mode">set_dummy_mode() (IPython.Shell.IPShellEmbed method)</a></dt>
+<dt><a href="api/generated/IPython.Shell.html#IPython.Shell.IPShellEmbed.set_exit_msg">set_exit_msg() (IPython.Shell.IPShellEmbed method)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.set_hook">set_hook() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.EngineFromReference.set_id">set_id() (IPython.kernel.enginefc.EngineFromReference method)</a></dt>
+<dt><a href="api/generated/IPython.ipapi.html#IPython.ipapi.IPyAutocall.set_ip">set_ip() (IPython.ipapi.IPyAutocall method)</a></dt>
+<dt><a href="api/generated/IPython.ultraTB.html#IPython.ultraTB.FormattedTB.set_mode">set_mode() (IPython.ultraTB.FormattedTB method)</a></dt>
+<dt><a href="api/generated/IPython.ipapi.html#IPython.ipapi.IPApi.set_next_input">set_next_input() (IPython.ipapi.IPApi method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.prompts.html#IPython.kernel.core.prompts.BasePrompt.set_p_str">set_p_str() (IPython.kernel.core.prompts.BasePrompt method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.Prompts.html#IPython.Prompts.BasePrompt.set_p_str">(IPython.Prompts.BasePrompt method)</a></dt>
+ <dt><a href="api/generated/IPython.Prompts.html#IPython.Prompts.Prompt2.set_p_str">(IPython.Prompts.Prompt2 method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.prompts.html#IPython.kernel.core.prompts.Prompt2.set_p_str">(IPython.kernel.core.prompts.Prompt2 method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.EngineFromReference.set_properties">set_properties() (IPython.kernel.enginefc.EngineFromReference method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.EngineService.set_properties">(IPython.kernel.engineservice.EngineService method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.QueuedEngine.set_properties">(IPython.kernel.engineservice.QueuedEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.MultiEngine.set_properties">(IPython.kernel.multiengine.MultiEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.SynchronousMultiEngine.set_properties">(IPython.kernel.multiengine.SynchronousMultiEngine method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.FullBlockingMultiEngineClient.set_properties">(IPython.kernel.multiengineclient.FullBlockingMultiEngineClient method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient.set_properties">(IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.platutils.html#IPython.platutils.set_term_title">set_term_title() (in module IPython.platutils)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.platutils_dummy.html#IPython.platutils_dummy.set_term_title">(in module IPython.platutils_dummy)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.gui.wx.ipshell_nonblocking.html#IPython.gui.wx.ipshell_nonblocking.NonBlockingIPShell.set_threading">set_threading() (IPython.gui.wx.ipshell_nonblocking.NonBlockingIPShell method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.interpreter.html#IPython.kernel.core.interpreter.Interpreter.set_traps">set_traps() (IPython.kernel.core.interpreter.Interpreter method)</a></dt>
+<dt><a href="api/generated/IPython.DPyGetOpt.html#IPython.DPyGetOpt.DPyGetOpt.setAllowAbbreviations">setAllowAbbreviations() (IPython.DPyGetOpt.DPyGetOpt method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.IPShellWidget.setAskExitHandler">setAskExitHandler() (IPython.gui.wx.ipython_view.IPShellWidget method)</a></dt>
+<dt><a href="api/generated/IPython.testing.decorators_numpy.html#IPython.testing.decorators_numpy.setastest">setastest() (in module IPython.testing.decorators_numpy)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.setattr_list">setattr_list() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.WxConsoleView.setBackgroundColor">setBackgroundColor() (IPython.gui.wx.ipython_view.WxConsoleView method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.WxConsoleView.setCompletionMethod">setCompletionMethod() (IPython.gui.wx.ipython_view.WxConsoleView method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.IPShellWidget.setCurrentState">setCurrentState() (IPython.gui.wx.ipython_view.IPShellWidget method)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.Section.setdefault">setdefault() (IPython.external.configobj.Section method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.ipstruct.html#IPython.ipstruct.Struct.setdefault">(IPython.ipstruct.Struct method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.Command.setDeferred">setDeferred() (IPython.kernel.engineservice.Command method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.IPShellWidget.setHistoryTrackerHook">setHistoryTrackerHook() (IPython.gui.wx.ipython_view.IPShellWidget method)</a></dt>
+<dt><a href="api/generated/IPython.DPyGetOpt.html#IPython.DPyGetOpt.DPyGetOpt.setIgnoreCase">setIgnoreCase() (IPython.DPyGetOpt.DPyGetOpt method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.WxConsoleView.setIndentation">setIndentation() (IPython.gui.wx.ipython_view.WxConsoleView method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_history.html#IPython.gui.wx.ipython_history.IPythonHistoryPanel.setOptionTrackerHook">setOptionTrackerHook() (IPython.gui.wx.ipython_history.IPythonHistoryPanel method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.IPShellWidget.setOptionTrackerHook">(IPython.gui.wx.ipython_view.IPShellWidget method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.DPyGetOpt.html#IPython.DPyGetOpt.DPyGetOpt.setPosixCompliance">setPosixCompliance() (IPython.DPyGetOpt.DPyGetOpt method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.WxConsoleView.setPrompt">setPrompt() (IPython.gui.wx.ipython_view.WxConsoleView method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.WxConsoleView.setPromptCount">setPromptCount() (IPython.gui.wx.ipython_view.WxConsoleView method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.IPShellWidget.setStatusTrackerHook">setStatusTrackerHook() (IPython.gui.wx.ipython_view.IPShellWidget method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.interpreter.html#IPython.kernel.core.interpreter.Interpreter.setup_message">setup_message() (IPython.kernel.core.interpreter.Interpreter method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.history.html#IPython.kernel.core.history.InterpreterHistory.setup_namespace">setup_namespace() (IPython.kernel.core.history.InterpreterHistory method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.core.interpreter.html#IPython.kernel.core.interpreter.Interpreter.setup_namespace">(IPython.kernel.core.interpreter.Interpreter method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.history.html#IPython.history.ShadowHist">ShadowHist (class in IPython.history)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.shell">shell() (in module IPython.genutils)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.genutils.html#IPython.genutils.SystemExec.shell">(IPython.genutils.SystemExec method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.hooks.html#IPython.hooks.shell_hook">shell_hook() (in module IPython.hooks)</a></dt>
+<dt><a href="api/generated/IPython.tools.utils.html#IPython.tools.utils.shexp">shexp() (in module IPython.tools.utils)</a></dt>
+<dt><a href="api/generated/IPython.demo.html#IPython.demo.Demo.show">show() (IPython.demo.Demo method)</a></dt></dl></td><td width="33%" valign="top"><dl>
+<dt><a href="api/generated/IPython.demo.html#IPython.demo.Demo.show_all">show_all() (IPython.demo.Demo method)</a></dt>
+<dt><a href="api/generated/IPython.wildcard.html#IPython.wildcard.show_hidden">show_hidden() (in module IPython.wildcard)</a></dt>
+<dt><a href="api/generated/IPython.hooks.html#IPython.hooks.show_in_pager">show_in_pager() (in module IPython.hooks)</a></dt>
+<dt><a href="api/generated/IPython.frontend.prefilterfrontend.html#IPython.frontend.prefilterfrontend.PrefilterFrontEnd.show_traceback">show_traceback() (IPython.frontend.prefilterfrontend.PrefilterFrontEnd method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.frontend.wx.wx_frontend.html#IPython.frontend.wx.wx_frontend.WxController.show_traceback">(IPython.frontend.wx.wx_frontend.WxController method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.upgrade_dir.html#IPython.upgrade_dir.showdiff">showdiff() (in module IPython.upgrade_dir)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.WxConsoleView.showPrompt">showPrompt() (IPython.gui.wx.ipython_view.WxConsoleView method)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.showsyntaxerror">showsyntaxerror() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.showtraceback">showtraceback() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.hooks.html#IPython.hooks.shutdown_hook">shutdown_hook() (in module IPython.hooks)</a></dt>
+<dt><a href="api/generated/IPython.kernel.scripts.ipcluster.html#IPython.kernel.scripts.ipcluster.LocalEngineSet.signal">signal() (IPython.kernel.scripts.ipcluster.LocalEngineSet method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.scripts.ipcluster.html#IPython.kernel.scripts.ipcluster.ProcessLauncher.signal">(IPython.kernel.scripts.ipcluster.ProcessLauncher method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.core.message_cache.html#IPython.kernel.core.message_cache.SimpleMessageCache">SimpleMessageCache (class in IPython.kernel.core.message_cache)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.SimpleVal">SimpleVal (class in IPython.external.configobj)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.size">size (IPython.external.path.path attribute)</a></dt>
+<dt><a href="api/generated/IPython.testing.decorators.html#IPython.testing.decorators.skip">skip() (in module IPython.testing.decorators)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.testing.decorators_trial.html#IPython.testing.decorators_trial.skip">(in module IPython.testing.decorators_trial)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.testing.decorators.html#IPython.testing.decorators.skipif">skipif() (in module IPython.testing.decorators)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.testing.decorators_numpy.html#IPython.testing.decorators_numpy.skipif">(in module IPython.testing.decorators_numpy)</a></dt>
+ <dt><a href="api/generated/IPython.testing.decorators_trial.html#IPython.testing.decorators_trial.skipif">(in module IPython.testing.decorators_trial)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.testing.decorators_numpy.html#IPython.testing.decorators_numpy.skipknownfailure">skipknownfailure() (in module IPython.testing.decorators_numpy)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.SList">SList (class in IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.testing.decorators_numpy.html#IPython.testing.decorators_numpy.slow">slow() (in module IPython.testing.decorators_numpy)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.snip_print">snip_print() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.softspace">softspace() (in module IPython.iplib)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.SList.sort">sort() (IPython.genutils.SList method)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.sort_compare">sort_compare() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.SpaceInInput">SpaceInInput (class in IPython.iplib)</a></dt>
+<dt><a href="api/generated/IPython.DPyGetOpt.html#IPython.DPyGetOpt.SpecificationError">SpecificationError (class in IPython.DPyGetOpt)</a></dt>
+<dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.TaskController.spin">spin() (IPython.kernel.task.TaskController method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.taskclient.html#IPython.kernel.taskclient.BlockingTaskClient.spin">(IPython.kernel.taskclient.BlockingTaskClient method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.taskfc.html#IPython.kernel.taskfc.FCTaskClient.spin">(IPython.kernel.taskfc.FCTaskClient method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.core.interpreter.html#IPython.kernel.core.interpreter.Interpreter.split_commands">split_commands() (IPython.kernel.core.interpreter.Interpreter method)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.split_user_input">split_user_input() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.splitall">splitall() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.splitdrive">splitdrive() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.splitext">splitext() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.splitpath">splitpath() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.prefilter.html#IPython.prefilter.splitUserInput">splitUserInput() (in module IPython.prefilter)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.LSString.spstr">spstr (IPython.genutils.LSString attribute)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.genutils.html#IPython.genutils.SList.spstr">(IPython.genutils.SList attribute)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.scripts.ipcluster.html#IPython.kernel.scripts.ipcluster.SSHEngineSet">SSHEngineSet (class in IPython.kernel.scripts.ipcluster)</a></dt>
+<dt><a href="api/generated/IPython.Shell.html#IPython.Shell.start">start() (in module IPython.Shell)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.frontend.linefrontendbase.html#IPython.frontend.linefrontendbase.LineFrontEndBase.start">(IPython.frontend.linefrontendbase.LineFrontEndBase method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.fd_redirector.html#IPython.kernel.core.fd_redirector.FDRedirector.start">(IPython.kernel.core.fd_redirector.FDRedirector method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.scripts.ipcluster.html#IPython.kernel.scripts.ipcluster.BatchEngineSet.start">(IPython.kernel.scripts.ipcluster.BatchEngineSet method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.scripts.ipcluster.html#IPython.kernel.scripts.ipcluster.LocalEngineSet.start">(IPython.kernel.scripts.ipcluster.LocalEngineSet method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.scripts.ipcluster.html#IPython.kernel.scripts.ipcluster.ProcessLauncher.start">(IPython.kernel.scripts.ipcluster.ProcessLauncher method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.scripts.ipcluster.html#IPython.kernel.scripts.ipcluster.SSHEngineSet.start">(IPython.kernel.scripts.ipcluster.SSHEngineSet method)</a></dt>
+ <dt><a href="api/generated/IPython.tools.growl.html#IPython.tools.growl.start">(in module IPython.tools.growl)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.scripts.ipcontroller.html#IPython.kernel.scripts.ipcontroller.start_controller">start_controller() (in module IPython.kernel.scripts.ipcontroller)</a></dt>
+<dt><a href="api/generated/IPython.kernel.scripts.ipengine.html#IPython.kernel.scripts.ipengine.start_engine">start_engine() (in module IPython.kernel.scripts.ipengine)</a></dt>
+<dt><a href="api/generated/IPython.external.argparse.html#IPython.external.argparse.HelpFormatter.start_section">start_section() (IPython.external.argparse.HelpFormatter method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.BaseTask.start_time">start_time() (IPython.kernel.task.BaseTask method)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.stat">stat() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.IPShellWidget.stateDoExecuteLine">stateDoExecuteLine() (IPython.gui.wx.ipython_view.IPShellWidget method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.IPShellWidget.stateShowPrompt">stateShowPrompt() (IPython.gui.wx.ipython_view.IPShellWidget method)</a></dt>
+<dt><a href="api/generated/IPython.background_jobs.html#IPython.background_jobs.BackgroundJobManager.status">status() (IPython.background_jobs.BackgroundJobManager method)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.statvfs">statvfs() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.fd_redirector.html#IPython.kernel.core.fd_redirector.FDRedirector.stop">stop() (IPython.kernel.core.fd_redirector.FDRedirector method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.twistedutil.html#IPython.kernel.twistedutil.ReactorInThread.stop">(IPython.kernel.twistedutil.ReactorInThread method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.BaseTask.stop_time">stop_time() (IPython.kernel.task.BaseTask method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.StopLocalExecution">StopLocalExecution (class in IPython.kernel.error)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.prompts.html#IPython.kernel.core.prompts.str_safe">str_safe() (in module IPython.kernel.core.prompts)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.Prompts.html#IPython.Prompts.str_safe">(in module IPython.Prompts)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.strdispatch.html#IPython.strdispatch.StrDispatch">StrDispatch (class in IPython.strdispatch)</a></dt>
+<dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.StrictDict">StrictDict (class in IPython.kernel.engineservice)</a></dt>
+<dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.StringTask">StringTask (class in IPython.kernel.task)</a></dt>
+<dt><a href="api/generated/IPython.kernel.contexts.html#IPython.kernel.contexts.strip_whitespace">strip_whitespace() (in module IPython.kernel.contexts)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.strip_whitespace">(in module IPython.kernel.multiengineclient)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.stripext">stripext() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.ipstruct.html#IPython.ipstruct.Struct">Struct (class in IPython.ipstruct)</a></dt>
+<dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.StrictDict.subDict">subDict() (IPython.kernel.engineservice.StrictDict method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.BaseTask.submit_task">submit_task() (IPython.kernel.task.BaseTask method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.MapTask.submit_task">(IPython.kernel.task.MapTask method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.StringTask.submit_task">(IPython.kernel.task.StringTask method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.QueuedEngine.submitCommand">submitCommand() (IPython.kernel.engineservice.QueuedEngine method)</a></dt>
+<dt><a href="api/generated/IPython.numutils.html#IPython.numutils.sum_flat">sum_flat() (in module IPython.numutils)</a></dt>
+<dt><a href="api/generated/IPython.OutputTrap.html#IPython.OutputTrap.OutputTrap.summary">summary() (IPython.OutputTrap.OutputTrap method)</a></dt>
+<dt><a href="api/generated/IPython.OutputTrap.html#IPython.OutputTrap.OutputTrap.summary_all">summary_all() (IPython.OutputTrap.OutputTrap method)</a></dt>
+<dt><a href="api/generated/IPython.OutputTrap.html#IPython.OutputTrap.OutputTrap.summary_err">summary_err() (IPython.OutputTrap.OutputTrap method)</a></dt>
+<dt><a href="api/generated/IPython.OutputTrap.html#IPython.OutputTrap.OutputTrap.summary_out">summary_out() (IPython.OutputTrap.OutputTrap method)</a></dt>
+<dt><a href="api/generated/IPython.Logger.html#IPython.Logger.Logger.switch_log">switch_log() (IPython.Logger.Logger method)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.symlink">symlink() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.hooks.html#IPython.hooks.synchronize_with_editor">synchronize_with_editor() (in module IPython.hooks)</a></dt>
+<dt><a href="api/generated/IPython.kernel.multiengine.html#IPython.kernel.multiengine.SynchronousMultiEngine">SynchronousMultiEngine (class in IPython.kernel.multiengine)</a></dt>
+<dt><a href="api/generated/IPython.kernel.mapper.html#IPython.kernel.mapper.SynchronousTaskMapper">SynchronousTaskMapper (class in IPython.kernel.mapper)</a></dt>
+<dt><a href="api/generated/IPython.kernel.enginefc.html#IPython.kernel.enginefc.EngineFromReference.syncProperties">syncProperties() (IPython.kernel.enginefc.EngineFromReference method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.sync_traceback_trap.html#IPython.kernel.core.sync_traceback_trap.SyncTracebackTrap">SyncTracebackTrap (class in IPython.kernel.core.sync_traceback_trap)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.SyntaxTB">SyntaxTB (class in IPython.iplib)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.system">system() (in module IPython.genutils)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.genutils.html#IPython.genutils.SystemExec.system">(IPython.genutils.SystemExec method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.frontend.prefilterfrontend.html#IPython.frontend.prefilterfrontend.PrefilterFrontEnd.system_call">system_call() (IPython.frontend.prefilterfrontend.PrefilterFrontEnd method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.frontend.wx.wx_frontend.html#IPython.frontend.wx.wx_frontend.WxController.system_call">(IPython.frontend.wx.wx_frontend.WxController method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.core.util.html#IPython.kernel.core.util.system_shell">system_shell() (in module IPython.kernel.core.util)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.SystemExec">SystemExec (class in IPython.genutils)</a></dt>
+</dl></td></tr></table>
+
+<h2 id="T">T</h2>
+<table width="100%" class="indextable"><tr><td width="33%" valign="top">
+<dl>
+
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.target_outdated">target_outdated() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.target_update">target_update() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.kernel.util.html#IPython.kernel.util.tarModule">tarModule() (in module IPython.kernel.util)</a></dt>
+<dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.TaskAborted">TaskAborted (class in IPython.kernel.error)</a></dt>
+<dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.TaskController.taskCompleted">taskCompleted() (IPython.kernel.task.TaskController method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.TaskController">TaskController (class in IPython.kernel.task)</a></dt>
+<dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.FIFOScheduler.taskids">taskids (IPython.kernel.task.FIFOScheduler attribute)</a></dt>
+<dt><a href="api/generated/IPython.kernel.mapper.html#IPython.kernel.mapper.TaskMapper">TaskMapper (class in IPython.kernel.mapper)</a></dt>
+<dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.TaskRejectError">TaskRejectError (class in IPython.kernel.error)</a></dt>
+<dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.TaskResult">TaskResult (class in IPython.kernel.task)</a></dt>
+<dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.TaskTimeout">TaskTimeout (class in IPython.kernel.error)</a></dt>
+<dt><a href="api/generated/IPython.ultraTB.html#IPython.ultraTB.TBTools">TBTools (class in IPython.ultraTB)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.TemplateInterpolation">TemplateInterpolation (class in IPython.external.configobj)</a></dt>
+<dt><a href="api/generated/IPython.platutils.html#IPython.platutils.term_clear">term_clear() (in module IPython.platutils)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.platutils_posix.html#IPython.platutils_posix.term_clear">(in module IPython.platutils_posix)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.ColorANSI.html#IPython.ColorANSI.TermColors">TermColors (class in IPython.ColorANSI)</a></dt>
+<dt><a href="api/generated/IPython.DPyGetOpt.html#IPython.DPyGetOpt.TerminationError">TerminationError (class in IPython.DPyGetOpt)</a></dt>
+<dt><a href="api/generated/IPython.external.mglob.html#IPython.external.mglob.test">test() (in module IPython.external.mglob)</a></dt>
+<dt><a href="api/generated/IPython.testing.iptest.html#IPython.testing.iptest.test_for">test_for() (in module IPython.testing.iptest)</a></dt>
+<dt><a href="api/generated/IPython.external.simplegeneric.html#IPython.external.simplegeneric.test_suite">test_suite() (in module IPython.external.simplegeneric)</a></dt>
+<dt><a href="api/generated/IPython.testing.plugin.test_refs.html#IPython.testing.plugin.test_refs.test_trivial">test_trivial() (in module IPython.testing.plugin.test_refs)</a></dt>
+<dt><a href="api/generated/IPython.external.pretty.html#IPython.external.pretty.Text">Text (class in IPython.external.pretty)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.text">text() (IPython.external.path.path method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.external.pretty.html#IPython.external.pretty.PrettyPrinter.text">(IPython.external.pretty.PrettyPrinter method)</a></dt>
+ <dt><a href="api/generated/IPython.ultraTB.html#IPython.ultraTB.AutoFormattedTB.text">(IPython.ultraTB.AutoFormattedTB method)</a></dt>
+ <dt><a href="api/generated/IPython.ultraTB.html#IPython.ultraTB.FormattedTB.text">(IPython.ultraTB.FormattedTB method)</a></dt>
+ <dt><a href="api/generated/IPython.ultraTB.html#IPython.ultraTB.ListTB.text">(IPython.ultraTB.ListTB method)</a></dt>
+ <dt><a href="api/generated/IPython.ultraTB.html#IPython.ultraTB.VerboseTB.text">(IPython.ultraTB.VerboseTB method)</a></dt>
+ </dl></dd></dl></td><td width="33%" valign="top"><dl>
+<dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.ThreadedEngineService">ThreadedEngineService (class in IPython.kernel.engineservice)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.thread_ex.html#IPython.gui.wx.thread_ex.ThreadEx">ThreadEx (class in IPython.gui.wx.thread_ex)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.timing">timing() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.timings">timings() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.timings_out">timings_out() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.frontend.wx.wx_frontend.html#IPython.frontend.wx.wx_frontend.WxController.title">title (IPython.frontend.wx.wx_frontend.WxController attribute)</a></dt>
+<dt><a href="api/generated/IPython.clipboard.html#IPython.clipboard.tkinter_clipboard_get">tkinter_clipboard_get() (in module IPython.clipboard)</a></dt>
+<dt><a href="api/generated/IPython.ipapi.html#IPython.ipapi.IPApi.to_user_ns">to_user_ns() (IPython.ipapi.IPApi method)</a></dt>
+<dt><a href="api/generated/IPython.platutils.html#IPython.platutils.toggle_set_term_title">toggle_set_term_title() (in module IPython.platutils)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.touch">touch() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.background_jobs.html#IPython.background_jobs.BackgroundJobBase.traceback">traceback() (IPython.background_jobs.BackgroundJobBase method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.background_jobs.html#IPython.background_jobs.BackgroundJobManager.traceback">(IPython.background_jobs.BackgroundJobManager method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.core.traceback_trap.html#IPython.kernel.core.traceback_trap.TracebackTrap">TracebackTrap (class in IPython.kernel.core.traceback_trap)</a></dt>
+<dt><a href="api/generated/IPython.Debugger.html#IPython.Debugger.Tracer">Tracer (class in IPython.Debugger)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.transform_alias">transform_alias() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.OutputTrap.html#IPython.OutputTrap.OutputTrap.trap">trap() (IPython.OutputTrap.OutputTrap method)</a></dt>
+<dt><a href="api/generated/IPython.OutputTrap.html#IPython.OutputTrap.OutputTrap.trap_all">trap_all() (IPython.OutputTrap.OutputTrap method)</a></dt>
+<dt><a href="api/generated/IPython.OutputTrap.html#IPython.OutputTrap.OutputTrap.trap_err">trap_err() (IPython.OutputTrap.OutputTrap method)</a></dt>
+<dt><a href="api/generated/IPython.OutputTrap.html#IPython.OutputTrap.OutputTrap.trap_out">trap_out() (IPython.OutputTrap.OutputTrap method)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.TreeWalkWarning">TreeWalkWarning (class in IPython.external.path)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.file_like.html#IPython.kernel.core.file_like.FileLike.truncate">truncate() (IPython.kernel.core.file_like.FileLike method)</a></dt>
+<dt><a href="api/generated/IPython.ipapi.html#IPython.ipapi.TryNext">TryNext (class in IPython.ipapi)</a></dt>
+<dt><a href="api/generated/IPython.twshell.html#IPython.twshell.TwistedInteractiveShell">TwistedInteractiveShell (class in IPython.twshell)</a></dt>
+<dt><a href="api/generated/IPython.kernel.pendingdeferred.html#IPython.kernel.pendingdeferred.two_phase">two_phase() (in module IPython.kernel.pendingdeferred)</a></dt>
+</dl></td></tr></table>
+
+<h2 id="U">U</h2>
+<table width="100%" class="indextable"><tr><td width="33%" valign="top">
+<dl>
+
+<dt><a href="api/generated/IPython.kernel.pickleutil.html#IPython.kernel.pickleutil.uncan">uncan() (in module IPython.kernel.pickleutil)</a></dt>
+<dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.BaseTask.uncan_task">uncan_task() (IPython.kernel.task.BaseTask method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.MapTask.uncan_task">(IPython.kernel.task.MapTask method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.pickleutil.html#IPython.kernel.pickleutil.uncanDict">uncanDict() (in module IPython.kernel.pickleutil)</a></dt>
+<dt><a href="api/generated/IPython.kernel.pickleutil.html#IPython.kernel.pickleutil.uncanSequence">uncanSequence() (in module IPython.kernel.pickleutil)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.Undefined">Undefined (class in IPython.iplib)</a></dt>
+<dt><a href="api/generated/IPython.external.Itpl.html#IPython.external.Itpl.unfilter">unfilter() (in module IPython.external.Itpl)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.Itpl.html#IPython.Itpl.unfilter">(in module IPython.Itpl)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.uniq_stable">uniq_stable() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.kernel.scripts.ipcluster.html#IPython.kernel.scripts.ipcluster.UnknownStatus">UnknownStatus (class in IPython.kernel.scripts.ipcluster)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.UnknownType">UnknownType (class in IPython.external.configobj)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.unlink">unlink() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient.unpackage">unpackage() (IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.taskfc.html#IPython.kernel.taskfc.FCTaskClient.unpackage">(IPython.kernel.taskfc.FCTaskClient method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.pbutil.html#IPython.kernel.pbutil.unpackageFailure">unpackageFailure() (in module IPython.kernel.pbutil)</a></dt>
+<dt><a href="api/generated/IPython.kernel.error.html#IPython.kernel.error.UnpickleableException">UnpickleableException (class in IPython.kernel.error)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.unquote_ends">unquote_ends() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.kernel.controllerservice.html#IPython.kernel.controllerservice.ControllerAdapterBase.unregister_engine">unregister_engine() (IPython.kernel.controllerservice.ControllerAdapterBase method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.controllerservice.html#IPython.kernel.controllerservice.ControllerService.unregister_engine">(IPython.kernel.controllerservice.ControllerService method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.QueuedEngine.unregister_failure_observer">unregister_failure_observer() (IPython.kernel.engineservice.QueuedEngine method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.TaskController.unregisterWorker">unregisterWorker() (IPython.kernel.task.TaskController method)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.unrepr">unrepr() (in module IPython.external.configobj)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.UnreprError">UnreprError (class in IPython.external.configobj)</a></dt>
+<dt><a href="api/generated/IPython.kernel.newserialized.html#IPython.kernel.newserialized.unserialize">unserialize() (in module IPython.kernel.newserialized)</a></dt>
+<dt><a href="api/generated/IPython.kernel.newserialized.html#IPython.kernel.newserialized.UnSerialized">UnSerialized (class in IPython.kernel.newserialized)</a></dt>
+<dt><a href="api/generated/IPython.kernel.newserialized.html#IPython.kernel.newserialized.UnSerializeIt">UnSerializeIt (class in IPython.kernel.newserialized)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.display_trap.html#IPython.kernel.core.display_trap.DisplayTrap.unset">unset() (IPython.kernel.core.display_trap.DisplayTrap method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.core.output_trap.html#IPython.kernel.core.output_trap.OutputTrap.unset">(IPython.kernel.core.output_trap.OutputTrap method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.redirector_output_trap.html#IPython.kernel.core.redirector_output_trap.RedirectorOutputTrap.unset">(IPython.kernel.core.redirector_output_trap.RedirectorOutputTrap method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.traceback_trap.html#IPython.kernel.core.traceback_trap.TracebackTrap.unset">(IPython.kernel.core.traceback_trap.TracebackTrap method)</a></dt>
+ </dl></dd></dl></td><td width="33%" valign="top"><dl>
+<dt><a href="api/generated/IPython.kernel.core.interpreter.html#IPython.kernel.core.interpreter.Interpreter.unset_traps">unset_traps() (IPython.kernel.core.interpreter.Interpreter method)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.Section.update">update() (IPython.external.configobj.Section method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.Prompts.html#IPython.Prompts.CachedOutput.update">(IPython.Prompts.CachedOutput method)</a></dt>
+ <dt><a href="api/generated/IPython.ipstruct.html#IPython.ipstruct.Struct.update">(IPython.ipstruct.Struct method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.prompts.html#IPython.kernel.core.prompts.CachedOutput.update">(IPython.kernel.core.prompts.CachedOutput method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.StrictDict.update">(IPython.kernel.engineservice.StrictDict method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.frontend.frontendbase.html#IPython.frontend.frontendbase.FrontEndBase.update_cell_prompt">update_cell_prompt() (IPython.frontend.frontendbase.FrontEndBase method)</a></dt>
+<dt><a href="api/generated/IPython.config.api.html#IPython.config.api.ConfigObjManager.update_config_obj">update_config_obj() (IPython.config.api.ConfigObjManager method)</a></dt>
+<dt><a href="api/generated/IPython.config.api.html#IPython.config.api.ConfigObjManager.update_config_obj_from_default_file">update_config_obj_from_default_file() (IPython.config.api.ConfigObjManager method)</a></dt>
+<dt><a href="api/generated/IPython.config.api.html#IPython.config.api.ConfigObjManager.update_config_obj_from_file">update_config_obj_from_file() (IPython.config.api.ConfigObjManager method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.history.html#IPython.kernel.core.history.InterpreterHistory.update_history">update_history() (IPython.kernel.core.history.InterpreterHistory method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipshell_nonblocking.html#IPython.gui.wx.ipshell_nonblocking.NonBlockingIPShell.update_namespace">update_namespace() (IPython.gui.wx.ipshell_nonblocking.NonBlockingIPShell method)</a></dt>
+<dt><a href="api/generated/IPython.Shell.html#IPython.Shell.update_tk">update_tk() (in module IPython.Shell)</a></dt>
+<dt><a href="api/generated/IPython.testing.decorator_msim.html#IPython.testing.decorator_msim.update_wrapper">update_wrapper() (in module IPython.testing.decorator_msim)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.IPShellWidget.updateHistoryTracker">updateHistoryTracker() (IPython.gui.wx.ipython_view.IPShellWidget method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_history.html#IPython.gui.wx.ipython_history.IPythonHistoryPanel.updateOptionTracker">updateOptionTracker() (IPython.gui.wx.ipython_history.IPythonHistoryPanel method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.IPShellWidget.updateOptionTracker">(IPython.gui.wx.ipython_view.IPShellWidget method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.gui.wx.wxIPython.html#IPython.gui.wx.wxIPython.MyFrame.updateStatus">updateStatus() (IPython.gui.wx.wxIPython.MyFrame method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.IPShellWidget.updateStatusTracker">updateStatusTracker() (IPython.gui.wx.ipython_view.IPShellWidget method)</a></dt>
+<dt><a href="api/generated/IPython.upgrade_dir.html#IPython.upgrade_dir.upgrade_dir">upgrade_dir() (in module IPython.upgrade_dir)</a></dt>
+<dt><a href="api/generated/IPython.ipapi.html#IPython.ipapi.UsageError">UsageError (class in IPython.ipapi)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.user_setup">user_setup() (in module IPython.iplib)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.user_setup">(IPython.iplib.InteractiveShell method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.utime">utime() (IPython.external.path.path method)</a></dt>
+</dl></td></tr></table>
+
+<h2 id="V">V</h2>
+<table width="100%" class="indextable"><tr><td width="33%" valign="top">
+<dl>
+
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.ConfigObj.validate">validate() (IPython.external.configobj.ConfigObj method)</a></dt>
+<dt><a href="api/generated/IPython.external.validate.html#IPython.external.validate.ValidateError">ValidateError (class in IPython.external.validate)</a></dt>
+<dt><a href="api/generated/IPython.external.validate.html#IPython.external.validate.Validator">Validator (class in IPython.external.validate)</a></dt>
+<dt><a href="api/generated/IPython.DPyGetOpt.html#IPython.DPyGetOpt.DPyGetOpt.valueForOption">valueForOption() (IPython.DPyGetOpt.DPyGetOpt method)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.Section.values">values() (IPython.external.configobj.Section method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.ipstruct.html#IPython.ipstruct.Struct.values">(IPython.ipstruct.Struct method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.var_expand">var_expand() (IPython.iplib.InteractiveShell method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.core.interpreter.html#IPython.kernel.core.interpreter.Interpreter.var_expand">(IPython.kernel.core.interpreter.Interpreter method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.external.validate.html#IPython.external.validate.VdtMissingValue">VdtMissingValue (class in IPython.external.validate)</a></dt>
+<dt><a href="api/generated/IPython.external.validate.html#IPython.external.validate.VdtParamError">VdtParamError (class in IPython.external.validate)</a></dt></dl></td><td width="33%" valign="top"><dl>
+<dt><a href="api/generated/IPython.external.validate.html#IPython.external.validate.VdtTypeError">VdtTypeError (class in IPython.external.validate)</a></dt>
+<dt><a href="api/generated/IPython.external.validate.html#IPython.external.validate.VdtUnknownCheckError">VdtUnknownCheckError (class in IPython.external.validate)</a></dt>
+<dt><a href="api/generated/IPython.external.validate.html#IPython.external.validate.VdtValueError">VdtValueError (class in IPython.external.validate)</a></dt>
+<dt><a href="api/generated/IPython.external.validate.html#IPython.external.validate.VdtValueTooBigError">VdtValueTooBigError (class in IPython.external.validate)</a></dt>
+<dt><a href="api/generated/IPython.external.validate.html#IPython.external.validate.VdtValueTooLongError">VdtValueTooLongError (class in IPython.external.validate)</a></dt>
+<dt><a href="api/generated/IPython.external.validate.html#IPython.external.validate.VdtValueTooShortError">VdtValueTooShortError (class in IPython.external.validate)</a></dt>
+<dt><a href="api/generated/IPython.external.validate.html#IPython.external.validate.VdtValueTooSmallError">VdtValueTooSmallError (class in IPython.external.validate)</a></dt>
+<dt><a href="api/generated/IPython.ultraTB.html#IPython.ultraTB.FormattedTB.verbose">verbose() (IPython.ultraTB.FormattedTB method)</a></dt>
+<dt><a href="api/generated/IPython.ultraTB.html#IPython.ultraTB.VerboseTB">VerboseTB (class in IPython.ultraTB)</a></dt>
+</dl></td></tr></table>
+
+<h2 id="W">W</h2>
+<table width="100%" class="indextable"><tr><td width="33%" valign="top">
+<dl>
+
+<dt><a href="api/generated/IPython.kernel.twistedutil.html#IPython.kernel.twistedutil.wait_for_file">wait_for_file() (in module IPython.kernel.twistedutil)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.Section.walk">walk() (IPython.external.configobj.Section method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.walk">(IPython.external.path.path method)</a></dt>
+ </dl></dd>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.walkdirs">walkdirs() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.walkfiles">walkfiles() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.warn">warn() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.DPyGetOpt.html#IPython.DPyGetOpt.DPyGetOpt.willAllowAbbreviations">willAllowAbbreviations() (IPython.DPyGetOpt.DPyGetOpt method)</a></dt>
+<dt><a href="api/generated/IPython.clipboard.html#IPython.clipboard.win32_clipboard_get">win32_clipboard_get() (in module IPython.clipboard)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.with_obj">with_obj() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.WorkerFromQueuedEngine">WorkerFromQueuedEngine (class in IPython.kernel.task)</a></dt>
+<dt><a href="api/generated/IPython.kernel.task.html#IPython.kernel.task.FIFOScheduler.workerids">workerids (IPython.kernel.task.FIFOScheduler attribute)</a></dt>
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.wrap_deprecated">wrap_deprecated() (in module IPython.genutils)</a></dt>
+<dt><a href="api/generated/IPython.kernel.engineservice.html#IPython.kernel.engineservice.ThreadedEngineService.wrapped_execute">wrapped_execute() (IPython.kernel.engineservice.ThreadedEngineService method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.wrapResultList">wrapResultList() (in module IPython.kernel.multiengineclient)</a></dt>
+<dt><a href="api/generated/IPython.external.configobj.html#IPython.external.configobj.ConfigObj.write">write() (IPython.external.configobj.ConfigObj method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.Itpl.html#IPython.Itpl.ItplFile.write">(IPython.Itpl.ItplFile method)</a></dt>
+ <dt><a href="api/generated/IPython.Prompts.html#IPython.Prompts.BasePrompt.write">(IPython.Prompts.BasePrompt method)</a></dt>
+ <dt><a href="api/generated/IPython.external.Itpl.html#IPython.external.Itpl.ItplFile.write">(IPython.external.Itpl.ItplFile method)</a></dt>
+ <dt><a href="api/generated/IPython.frontend.linefrontendbase.html#IPython.frontend.linefrontendbase.LineFrontEndBase.write">(IPython.frontend.linefrontendbase.LineFrontEndBase method)</a></dt>
+ <dt><a href="api/generated/IPython.frontend.wx.console_widget.html#IPython.frontend.wx.console_widget.ConsoleWidget.write">(IPython.frontend.wx.console_widget.ConsoleWidget method)</a></dt>
+ <dt><a href="api/generated/IPython.frontend.wx.wx_frontend.html#IPython.frontend.wx.wx_frontend.WxController.write">(IPython.frontend.wx.wx_frontend.WxController method)</a></dt>
+ <dt><a href="api/generated/IPython.genutils.html#IPython.genutils.IOStream.write">(IPython.genutils.IOStream method)</a></dt>
+ <dt><a href="api/generated/IPython.gui.wx.ipython_history.html#IPython.gui.wx.ipython_history.IPythonHistoryPanel.write">(IPython.gui.wx.ipython_history.IPythonHistoryPanel method)</a></dt>
+ <dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.WxConsoleView.write">(IPython.gui.wx.ipython_view.WxConsoleView method)</a></dt>
+ <dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.write">(IPython.iplib.InteractiveShell method)</a></dt>
+ <dt><a href="api/generated/IPython.kernel.core.prompts.html#IPython.kernel.core.prompts.BasePrompt.write">(IPython.kernel.core.prompts.BasePrompt method)</a></dt>
+ <dt><a href="api/generated/IPython.testing.mkdoctests.html#IPython.testing.mkdoctests.IndentOut.write">(IPython.testing.mkdoctests.IndentOut method)</a></dt>
+ </dl></dd></dl></td><td width="33%" valign="top"><dl>
+<dt><a href="api/generated/IPython.kernel.scripts.ipcluster.html#IPython.kernel.scripts.ipcluster.BatchEngineSet.write_batch_script">write_batch_script() (IPython.kernel.scripts.ipcluster.BatchEngineSet method)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.write_bytes">write_bytes() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.frontend.linefrontendbase.html#IPython.frontend.linefrontendbase.LineFrontEndBase.write_completion">write_completion() (IPython.frontend.linefrontendbase.LineFrontEndBase method)</a></dt>
+<dt><a href="api/generated/IPython.config.api.html#IPython.config.api.ConfigObjManager.write_config_obj_to_file">write_config_obj_to_file() (IPython.config.api.ConfigObjManager method)</a></dt>
+<dt><a href="api/generated/IPython.config.api.html#IPython.config.api.ConfigObjManager.write_default_config_file">write_default_config_file() (IPython.config.api.ConfigObjManager method)</a></dt>
+<dt><a href="api/generated/IPython.iplib.html#IPython.iplib.InteractiveShell.write_err">write_err() (IPython.iplib.InteractiveShell method)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.write_lines">write_lines() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.external.path.html#IPython.external.path.path.write_text">write_text() (IPython.external.path.path method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.WxConsoleView.writeCompletion">writeCompletion() (IPython.gui.wx.ipython_view.WxConsoleView method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.WxConsoleView.writeHistory">writeHistory() (IPython.gui.wx.ipython_view.WxConsoleView method)</a></dt>
+<dt><a href="api/generated/IPython.kernel.core.file_like.html#IPython.kernel.core.file_like.FileLike.writelines">writelines() (IPython.kernel.core.file_like.FileLike method)</a></dt>
+<dt><a href="api/generated/IPython.OInspect.html#IPython.OInspect.myStringIO.writeln">writeln() (IPython.OInspect.myStringIO method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.WxConsoleView">WxConsoleView (class in IPython.gui.wx.ipython_view)</a></dt>
+<dt><a href="api/generated/IPython.frontend.wx.wx_frontend.html#IPython.frontend.wx.wx_frontend.WxController">WxController (class in IPython.frontend.wx.wx_frontend)</a></dt>
+<dt><a href="api/generated/IPython.Shell.html#IPython.Shell.IPShellWX.wxexit">wxexit() (IPython.Shell.IPShellWX method)</a></dt>
+<dt><a href="api/generated/IPython.gui.wx.ipython_view.html#IPython.gui.wx.ipython_view.WxNonBlockingIPShell">WxNonBlockingIPShell (class in IPython.gui.wx.ipython_view)</a></dt>
+</dl></td></tr></table>
+
+<h2 id="X">X</h2>
+<table width="100%" class="indextable"><tr><td width="33%" valign="top">
+<dl>
+
+<dt><a href="api/generated/IPython.genutils.html#IPython.genutils.SystemExec.xsys">xsys() (IPython.genutils.SystemExec method)</a></dt></dl></td><td width="33%" valign="top"><dl>
+</dl></td></tr></table>
+
+<h2 id="Z">Z</h2>
+<table width="100%" class="indextable"><tr><td width="33%" valign="top">
+<dl>
+
+<dt><a href="api/generated/IPython.numutils.html#IPython.numutils.zeros_like">zeros_like() (in module IPython.numutils)</a></dt>
+<dt><a href="api/generated/IPython.kernel.multiengineclient.html#IPython.kernel.multiengineclient.FullBlockingMultiEngineClient.zip_pull">zip_pull() (IPython.kernel.multiengineclient.FullBlockingMultiEngineClient method)</a></dt>
+ <dd><dl>
+ <dt><a href="api/generated/IPython.kernel.multienginefc.html#IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient.zip_pull">(IPython.kernel.multienginefc.FCFullSynchronousMultiEngineClient method)</a></dt>
+ </dl></dd></dl></td><td width="33%" valign="top"><dl>
+</dl></td></tr></table>
+
+
+
+ </div>
+ </div>
+ </div>
+ <div class="sphinxsidebar">
+ <div class="sphinxsidebarwrapper">
+
+
+
+ <h3>Quick search</h3>
+ <form class="search" action="search.html" method="get">
+ <input type="text" name="q" size="18" /> <input type="submit" value="Go" />
+ <input type="hidden" name="check_keywords" value="yes" />
+ <input type="hidden" name="area" value="default" />
+ </form>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="modindex.html" title="Global Module Index"
+ accesskey="M">modules</a> |</li>
+ <li><a href="index.html">IPython v0.10 documentation</a> &raquo;</li>
+ </ul>
+ </div>
+ <div class="footer">
+ &copy; Copyright 2008, The IPython Development Team.
+ Last updated on Aug 04, 2009.
+ Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 0.5.2.
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/ipythonbook/doc/rel-0.10/html/index.html b/help/ipythonbook/doc/rel-0.10/html/index.html
new file mode 100644
index 0000000..9eecb78
--- /dev/null
+++ b/help/ipythonbook/doc/rel-0.10/html/index.html
@@ -0,0 +1,342 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+ <title>IPython Documentation &mdash; IPython v0.10 documentation</title>
+ <link rel="stylesheet" href="_static/default.css" type="text/css" />
+ <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+ <script type="text/javascript">
+ var DOCUMENTATION_OPTIONS = {
+ URL_ROOT: '',
+ VERSION: '0.10',
+ COLLAPSE_MODINDEX: false,
+ FILE_SUFFIX: '.html',
+ HAS_SOURCE: true
+ };
+ </script>
+ <script type="text/javascript" src="_static/jquery.js"></script>
+ <script type="text/javascript" src="_static/doctools.js"></script>
+ <link rel="top" title="IPython v0.10 documentation" href="" />
+ <link rel="next" title="Introduction" href="overview.html" />
+ </head>
+ <body>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="modindex.html" title="Global Module Index"
+ accesskey="M">modules</a> |</li>
+ <li class="right" >
+ <a href="overview.html" title="Introduction"
+ accesskey="N">next</a> |</li>
+ <li><a href="">IPython v0.10 documentation</a> &raquo;</li>
+ </ul>
+ </div>
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body">
+
+
+ <div class="section" id="ipython-documentation">
+<h1>IPython Documentation<a class="headerlink" href="#ipython-documentation" title="Permalink to this headline">¶</a></h1>
+<table class="docutils field-list" frame="void" rules="none">
+<col class="field-name" />
+<col class="field-body" />
+<tbody valign="top">
+<tr class="field"><th class="field-name">Release:</th><td class="field-body">0.10</td>
+</tr>
+<tr class="field"><th class="field-name">Date:</th><td class="field-body">August 04, 2009</td>
+</tr>
+</tbody>
+</table>
+<p>Contents:</p>
+<ul>
+<li class="toctree-l1"><a class="reference external" href="overview.html">Introduction</a><ul>
+<li class="toctree-l2"><a class="reference external" href="overview.html#id1">Overview</a></li>
+<li class="toctree-l2"><a class="reference external" href="overview.html#enhanced-interactive-python-shell">Enhanced interactive Python shell</a></li>
+<li class="toctree-l2"><a class="reference external" href="overview.html#interactive-parallel-computing">Interactive parallel computing</a></li>
+</ul>
+</li>
+</ul>
+<ul>
+<li class="toctree-l1"><a class="reference external" href="install/index.html">Installation</a><ul>
+<li class="toctree-l2"><a class="reference external" href="install/install.html">Overview</a></li>
+<li class="toctree-l2"><a class="reference external" href="install/install.html#quickstart">Quickstart</a></li>
+<li class="toctree-l2"><a class="reference external" href="install/install.html#installing-ipython-itself">Installing IPython itself</a></li>
+<li class="toctree-l2"><a class="reference external" href="install/install.html#basic-optional-dependencies">Basic optional dependencies</a></li>
+<li class="toctree-l2"><a class="reference external" href="install/install.html#dependencies-for-ipython-kernel-parallel-computing">Dependencies for IPython.kernel (parallel computing)</a></li>
+<li class="toctree-l2"><a class="reference external" href="install/install.html#dependencies-for-ipython-frontend-the-ipython-gui">Dependencies for IPython.frontend (the IPython GUI)</a></li>
+</ul>
+</li>
+</ul>
+<ul>
+<li class="toctree-l1"><a class="reference external" href="interactive/index.html">Using IPython for interactive work</a><ul>
+<li class="toctree-l2"><a class="reference external" href="interactive/tutorial.html">Quick IPython tutorial</a></li>
+<li class="toctree-l2"><a class="reference external" href="interactive/reference.html">IPython reference</a></li>
+<li class="toctree-l2"><a class="reference external" href="interactive/shell.html">IPython as a system shell</a></li>
+<li class="toctree-l2"><a class="reference external" href="interactive/extension_api.html">IPython extension API</a></li>
+</ul>
+</li>
+</ul>
+<ul>
+<li class="toctree-l1"><a class="reference external" href="parallel/index.html">Using IPython for parallel computing</a><ul>
+<li class="toctree-l2"><a class="reference external" href="parallel/parallel_intro.html">Overview and getting started</a></li>
+<li class="toctree-l2"><a class="reference external" href="parallel/parallel_process.html">Starting the IPython controller and engines</a></li>
+<li class="toctree-l2"><a class="reference external" href="parallel/parallel_multiengine.html">IPython&#8217;s multiengine interface</a></li>
+<li class="toctree-l2"><a class="reference external" href="parallel/parallel_task.html">The IPython task interface</a></li>
+<li class="toctree-l2"><a class="reference external" href="parallel/parallel_mpi.html">Using MPI with IPython</a></li>
+<li class="toctree-l2"><a class="reference external" href="parallel/parallel_security.html">Security details of IPython</a></li>
+<li class="toctree-l2"><a class="reference external" href="parallel/visionhpc.html">IPython/Vision Beam Pattern Demo</a></li>
+</ul>
+</li>
+</ul>
+<ul>
+<li class="toctree-l1"><a class="reference external" href="config/index.html">Configuration and customization</a><ul>
+<li class="toctree-l2"><a class="reference external" href="config/initial_config.html">Initial configuration of your environment</a></li>
+<li class="toctree-l2"><a class="reference external" href="config/customization.html">Customization of IPython</a></li>
+<li class="toctree-l2"><a class="reference external" href="config/new_config.html">New configuration system</a></li>
+</ul>
+</li>
+</ul>
+<ul>
+<li class="toctree-l1"><a class="reference external" href="faq.html">Frequently asked questions</a><ul>
+<li class="toctree-l2"><a class="reference external" href="faq.html#general-questions">General questions</a></li>
+<li class="toctree-l2"><a class="reference external" href="faq.html#questions-about-parallel-computing-with-ipython">Questions about parallel computing with IPython</a></li>
+</ul>
+</li>
+</ul>
+<ul>
+<li class="toctree-l1"><a class="reference external" href="history.html">History</a><ul>
+<li class="toctree-l2"><a class="reference external" href="history.html#origins">Origins</a></li>
+<li class="toctree-l2"><a class="reference external" href="history.html#today-and-how-we-got-here">Today and how we got here</a></li>
+</ul>
+</li>
+</ul>
+<ul>
+<li class="toctree-l1"><a class="reference external" href="changes.html">What&#8217;s new</a><ul>
+<li class="toctree-l2"><a class="reference external" href="changes.html#release-0-10">Release 0.10</a></li>
+<li class="toctree-l2"><a class="reference external" href="changes.html#release-0-9-1">Release 0.9.1</a></li>
+<li class="toctree-l2"><a class="reference external" href="changes.html#release-0-9">Release 0.9</a></li>
+<li class="toctree-l2"><a class="reference external" href="changes.html#release-0-8-4">Release 0.8.4</a></li>
+<li class="toctree-l2"><a class="reference external" href="changes.html#release-0-8-3">Release 0.8.3</a></li>
+<li class="toctree-l2"><a class="reference external" href="changes.html#release-0-8-2">Release 0.8.2</a></li>
+<li class="toctree-l2"><a class="reference external" href="changes.html#older-releases">Older releases</a></li>
+</ul>
+</li>
+</ul>
+<ul>
+<li class="toctree-l1"><a class="reference external" href="development/index.html">IPython Developer&#8217;s Guide</a><ul>
+<li class="toctree-l2"><a class="reference external" href="development/overview.html">IPython development guidelines</a></li>
+<li class="toctree-l2"><a class="reference external" href="development/coding_guide.html">Coding guide</a></li>
+<li class="toctree-l2"><a class="reference external" href="development/doc_guide.html">Documenting IPython</a></li>
+<li class="toctree-l2"><a class="reference external" href="development/roadmap.html">Development roadmap</a></li>
+<li class="toctree-l2"><a class="reference external" href="development/notification_blueprint.html">IPython.kernel.core.notification blueprint</a></li>
+<li class="toctree-l2"><a class="reference external" href="development/config_blueprint.html">Notes on the IPython configuration system</a></li>
+</ul>
+</li>
+</ul>
+<ul>
+<li class="toctree-l1"><a class="reference external" href="api/index.html">The IPython API</a><ul>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.ColorANSI.html">ColorANSI</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.ConfigLoader.html">ConfigLoader</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.CrashHandler.html">CrashHandler</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.DPyGetOpt.html">DPyGetOpt</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.Debugger.html">Debugger</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.Itpl.html">Itpl</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.Logger.html">Logger</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.Magic.html">Magic</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.OInspect.html">OInspect</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.OutputTrap.html">OutputTrap</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.Prompts.html">Prompts</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.PyColorize.html">PyColorize</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.Shell.html">Shell</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.UserConfig.ipy_user_conf.html">UserConfig.ipy_user_conf</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.background_jobs.html">background_jobs</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.clipboard.html">clipboard</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.completer.html">completer</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.config.api.html">config.api</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.config.cutils.html">config.cutils</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.deep_reload.html">deep_reload</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.demo.html">demo</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.dtutils.html">dtutils</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.excolors.html">excolors</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.external.Itpl.html">external.Itpl</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.external.argparse.html">external.argparse</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.external.configobj.html">external.configobj</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.external.guid.html">external.guid</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.external.mglob.html">external.mglob</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.external.path.html">external.path</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.external.pretty.html">external.pretty</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.external.simplegeneric.html">external.simplegeneric</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.external.validate.html">external.validate</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.frontend.asyncfrontendbase.html">frontend.asyncfrontendbase</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.frontend.frontendbase.html">frontend.frontendbase</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.frontend.linefrontendbase.html">frontend.linefrontendbase</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.frontend.prefilterfrontend.html">frontend.prefilterfrontend</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.frontend.process.pipedprocess.html">frontend.process.pipedprocess</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.frontend.wx.console_widget.html">frontend.wx.console_widget</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.frontend.wx.ipythonx.html">frontend.wx.ipythonx</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.frontend.wx.wx_frontend.html">frontend.wx.wx_frontend</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.generics.html">generics</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.genutils.html">genutils</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.gui.wx.ipshell_nonblocking.html">gui.wx.ipshell_nonblocking</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.gui.wx.ipython_history.html">gui.wx.ipython_history</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.gui.wx.ipython_view.html">gui.wx.ipython_view</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.gui.wx.thread_ex.html">gui.wx.thread_ex</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.gui.wx.wxIPython.html">gui.wx.wxIPython</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.history.html">history</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.hooks.html">hooks</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.ipapi.html">ipapi</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.iplib.html">iplib</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.ipmaker.html">ipmaker</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.ipstruct.html">ipstruct</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.irunner.html">irunner</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.kernel.client.html">kernel.client</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.kernel.clientconnector.html">kernel.clientconnector</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.kernel.clientinterfaces.html">kernel.clientinterfaces</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.kernel.codeutil.html">kernel.codeutil</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.kernel.contexts.html">kernel.contexts</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.kernel.controllerservice.html">kernel.controllerservice</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.kernel.core.display_formatter.html">kernel.core.display_formatter</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.kernel.core.display_trap.html">kernel.core.display_trap</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.kernel.core.error.html">kernel.core.error</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.kernel.core.fd_redirector.html">kernel.core.fd_redirector</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.kernel.core.file_like.html">kernel.core.file_like</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.kernel.core.history.html">kernel.core.history</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.kernel.core.interpreter.html">kernel.core.interpreter</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.kernel.core.macro.html">kernel.core.macro</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.kernel.core.magic.html">kernel.core.magic</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.kernel.core.message_cache.html">kernel.core.message_cache</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.kernel.core.notification.html">kernel.core.notification</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.kernel.core.output_trap.html">kernel.core.output_trap</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.kernel.core.prompts.html">kernel.core.prompts</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.kernel.core.redirector_output_trap.html">kernel.core.redirector_output_trap</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.kernel.core.sync_traceback_trap.html">kernel.core.sync_traceback_trap</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.kernel.core.traceback_formatter.html">kernel.core.traceback_formatter</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.kernel.core.traceback_trap.html">kernel.core.traceback_trap</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.kernel.core.util.html">kernel.core.util</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.kernel.engineconnector.html">kernel.engineconnector</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.kernel.enginefc.html">kernel.enginefc</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.kernel.engineservice.html">kernel.engineservice</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.kernel.error.html">kernel.error</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.kernel.fcutil.html">kernel.fcutil</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.kernel.magic.html">kernel.magic</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.kernel.map.html">kernel.map</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.kernel.mapper.html">kernel.mapper</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.kernel.multiengine.html">kernel.multiengine</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.kernel.multiengineclient.html">kernel.multiengineclient</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.kernel.multienginefc.html">kernel.multienginefc</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.kernel.newserialized.html">kernel.newserialized</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.kernel.parallelfunction.html">kernel.parallelfunction</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.kernel.pbutil.html">kernel.pbutil</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.kernel.pendingdeferred.html">kernel.pendingdeferred</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.kernel.pickleutil.html">kernel.pickleutil</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.kernel.scripts.ipcluster.html">kernel.scripts.ipcluster</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.kernel.scripts.ipcontroller.html">kernel.scripts.ipcontroller</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.kernel.scripts.ipengine.html">kernel.scripts.ipengine</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.kernel.task.html">kernel.task</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.kernel.taskclient.html">kernel.taskclient</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.kernel.taskfc.html">kernel.taskfc</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.kernel.twistedutil.html">kernel.twistedutil</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.kernel.util.html">kernel.util</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.macro.html">macro</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.numutils.html">numutils</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.platutils.html">platutils</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.platutils_dummy.html">platutils_dummy</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.platutils_posix.html">platutils_posix</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.platutils_win32.html">platutils_win32</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.prefilter.html">prefilter</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.shellglobals.html">shellglobals</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.strdispatch.html">strdispatch</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.testing.decorator_msim.html">testing.decorator_msim</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.testing.decorators.html">testing.decorators</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.testing.decorators_numpy.html">testing.decorators_numpy</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.testing.decorators_trial.html">testing.decorators_trial</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.testing.iptest.html">testing.iptest</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.testing.mkdoctests.html">testing.mkdoctests</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.testing.parametric.html">testing.parametric</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.testing.plugin.dtexample.html">testing.plugin.dtexample</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.testing.plugin.show_refs.html">testing.plugin.show_refs</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.testing.plugin.simple.html">testing.plugin.simple</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.testing.plugin.test_ipdoctest.html">testing.plugin.test_ipdoctest</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.testing.plugin.test_refs.html">testing.plugin.test_refs</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.testing.tools.html">testing.tools</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.testing.util.html">testing.util</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.tools.growl.html">tools.growl</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.tools.utils.html">tools.utils</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.twshell.html">twshell</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.ultraTB.html">ultraTB</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.upgrade_dir.html">upgrade_dir</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.wildcard.html">wildcard</a></li>
+<li class="toctree-l2"><a class="reference external" href="api/generated/IPython.winconsole.html">winconsole</a></li>
+</ul>
+</li>
+</ul>
+<ul>
+<li class="toctree-l1"><a class="reference external" href="license_and_copyright.html">License and Copyright</a><ul>
+<li class="toctree-l2"><a class="reference external" href="license_and_copyright.html#id1">License</a></li>
+<li class="toctree-l2"><a class="reference external" href="license_and_copyright.html#about-the-ipython-development-team">About the IPython Development Team</a></li>
+<li class="toctree-l2"><a class="reference external" href="license_and_copyright.html#our-copyright-policy">Our Copyright Policy</a></li>
+<li class="toctree-l2"><a class="reference external" href="license_and_copyright.html#miscellaneous">Miscellaneous</a></li>
+</ul>
+</li>
+</ul>
+<ul>
+<li class="toctree-l1"><a class="reference external" href="credits.html">Credits</a></li>
+</ul>
+<ul class="simple">
+<li><a class="reference external" href="genindex.html"><em>Index</em></a></li>
+<li><a class="reference external" href="modindex.html"><em>Module Index</em></a></li>
+<li><a class="reference external" href="search.html"><em>Search Page</em></a></li>
+</ul>
+</div>
+
+
+ </div>
+ </div>
+ </div>
+ <div class="sphinxsidebar">
+ <div class="sphinxsidebarwrapper">
+ <h4>Next topic</h4>
+ <p class="topless"><a href="overview.html" title="next chapter">Introduction</a></p>
+ <h3>This Page</h3>
+ <ul class="this-page-menu">
+ <li><a href="_sources/index.txt">Show Source</a></li>
+ </ul>
+ <h3>Quick search</h3>
+ <form class="search" action="search.html" method="get">
+ <input type="text" name="q" size="18" /> <input type="submit" value="Go" />
+ <input type="hidden" name="check_keywords" value="yes" />
+ <input type="hidden" name="area" value="default" />
+ </form>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="modindex.html" title="Global Module Index"
+ accesskey="M">modules</a> |</li>
+ <li class="right" >
+ <a href="overview.html" title="Introduction"
+ accesskey="N">next</a> |</li>
+ <li><a href="">IPython v0.10 documentation</a> &raquo;</li>
+ </ul>
+ </div>
+ <div class="footer">
+ &copy; Copyright 2008, The IPython Development Team.
+ Last updated on Aug 04, 2009.
+ Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 0.5.2.
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/ipythonbook/doc/rel-0.10/html/interactive/index.html b/help/ipythonbook/doc/rel-0.10/html/interactive/index.html
new file mode 100644
index 0000000..90748fc
--- /dev/null
+++ b/help/ipythonbook/doc/rel-0.10/html/interactive/index.html
@@ -0,0 +1,152 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+ <title>Using IPython for interactive work &mdash; IPython v0.10 documentation</title>
+ <link rel="stylesheet" href="../_static/default.css" type="text/css" />
+ <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
+ <script type="text/javascript">
+ var DOCUMENTATION_OPTIONS = {
+ URL_ROOT: '../',
+ VERSION: '0.10',
+ COLLAPSE_MODINDEX: false,
+ FILE_SUFFIX: '.html',
+ HAS_SOURCE: true
+ };
+ </script>
+ <script type="text/javascript" src="../_static/jquery.js"></script>
+ <script type="text/javascript" src="../_static/doctools.js"></script>
+ <link rel="top" title="IPython v0.10 documentation" href="../index.html" />
+ <link rel="next" title="Quick IPython tutorial" href="tutorial.html" />
+ <link rel="prev" title="Overview" href="../install/install.html" />
+ </head>
+ <body>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../modindex.html" title="Global Module Index"
+ accesskey="M">modules</a> |</li>
+ <li class="right" >
+ <a href="tutorial.html" title="Quick IPython tutorial"
+ accesskey="N">next</a> |</li>
+ <li class="right" >
+ <a href="../install/install.html" title="Overview"
+ accesskey="P">previous</a> |</li>
+ <li><a href="../index.html">IPython v0.10 documentation</a> &raquo;</li>
+ </ul>
+ </div>
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body">
+
+
+ <div class="section" id="using-ipython-for-interactive-work">
+<h1>Using IPython for interactive work<a class="headerlink" href="#using-ipython-for-interactive-work" title="Permalink to this headline">¶</a></h1>
+<ul>
+<li class="toctree-l1"><a class="reference external" href="tutorial.html">Quick IPython tutorial</a><ul>
+<li class="toctree-l2"><a class="reference external" href="tutorial.html#highlights">Highlights</a></li>
+<li class="toctree-l2"><a class="reference external" href="tutorial.html#source-code-handling-tips">Source code handling tips</a></li>
+<li class="toctree-l2"><a class="reference external" href="tutorial.html#lightweight-version-control">Lightweight &#8216;version control&#8217;</a></li>
+<li class="toctree-l2"><a class="reference external" href="tutorial.html#effective-logging">Effective logging</a></li>
+</ul>
+</li>
+</ul>
+<ul>
+<li class="toctree-l1"><a class="reference external" href="reference.html">IPython reference</a><ul>
+<li class="toctree-l2"><a class="reference external" href="reference.html#command-line-usage">Command-line usage</a></li>
+<li class="toctree-l2"><a class="reference external" href="reference.html#interactive-use">Interactive use</a></li>
+<li class="toctree-l2"><a class="reference external" href="reference.html#ipython-as-your-default-python-environment">IPython as your default Python environment</a></li>
+<li class="toctree-l2"><a class="reference external" href="reference.html#embedding-ipython">Embedding IPython</a></li>
+<li class="toctree-l2"><a class="reference external" href="reference.html#using-the-python-debugger-pdb">Using the Python debugger (pdb)</a></li>
+<li class="toctree-l2"><a class="reference external" href="reference.html#extensions-for-syntax-processing">Extensions for syntax processing</a></li>
+<li class="toctree-l2"><a class="reference external" href="reference.html#threading-support">Threading support</a></li>
+<li class="toctree-l2"><a class="reference external" href="reference.html#interactive-demos-with-ipython">Interactive demos with IPython</a></li>
+<li class="toctree-l2"><a class="reference external" href="reference.html#plotting-with-matplotlib">Plotting with matplotlib</a></li>
+</ul>
+</li>
+</ul>
+<ul>
+<li class="toctree-l1"><a class="reference external" href="shell.html">IPython as a system shell</a><ul>
+<li class="toctree-l2"><a class="reference external" href="shell.html#overview">Overview</a></li>
+<li class="toctree-l2"><a class="reference external" href="shell.html#aliases">Aliases</a></li>
+<li class="toctree-l2"><a class="reference external" href="shell.html#directory-management">Directory management</a></li>
+<li class="toctree-l2"><a class="reference external" href="shell.html#enabled-extensions">Enabled extensions</a></li>
+<li class="toctree-l2"><a class="reference external" href="shell.html#prompt-customization">Prompt customization</a></li>
+<li class="toctree-l2"><a class="reference external" href="shell.html#string-lists">String lists</a></li>
+<li class="toctree-l2"><a class="reference external" href="shell.html#real-world-example-remove-all-files-outside-version-control">Real world example: remove all files outside version control</a></li>
+<li class="toctree-l2"><a class="reference external" href="shell.html#the-s-n-p-properties">The .s, .n, .p properties</a></li>
+</ul>
+</li>
+</ul>
+<ul>
+<li class="toctree-l1"><a class="reference external" href="extension_api.html">IPython extension API</a><ul>
+<li class="toctree-l2"><a class="reference external" href="extension_api.html#getting-started">Getting started</a></li>
+<li class="toctree-l2"><a class="reference external" href="extension_api.html#getting-a-handle-to-the-api">Getting a handle to the api</a></li>
+<li class="toctree-l2"><a class="reference external" href="extension_api.html#changing-options">Changing options</a></li>
+<li class="toctree-l2"><a class="reference external" href="extension_api.html#executing-statements-in-ipython-namespace-with-ex-and-ev">Executing statements in IPython namespace with &#8216;ex&#8217; and &#8216;ev&#8217;</a></li>
+<li class="toctree-l2"><a class="reference external" href="extension_api.html#accessing-the-ipython-namespace">Accessing the IPython namespace</a></li>
+<li class="toctree-l2"><a class="reference external" href="extension_api.html#defining-new-magic-commands">Defining new magic commands</a></li>
+<li class="toctree-l2"><a class="reference external" href="extension_api.html#calling-magic-functions-and-system-commands">Calling magic functions and system commands</a></li>
+<li class="toctree-l2"><a class="reference external" href="extension_api.html#launching-ipython-instance-from-normal-python-code">Launching IPython instance from normal python code</a></li>
+<li class="toctree-l2"><a class="reference external" href="extension_api.html#accessing-unexposed-functionality">Accessing unexposed functionality</a></li>
+<li class="toctree-l2"><a class="reference external" href="extension_api.html#provided-extensions">Provided extensions</a></li>
+</ul>
+</li>
+</ul>
+</div>
+
+
+ </div>
+ </div>
+ </div>
+ <div class="sphinxsidebar">
+ <div class="sphinxsidebarwrapper">
+ <h4>Previous topic</h4>
+ <p class="topless"><a href="../install/install.html" title="previous chapter">Overview</a></p>
+ <h4>Next topic</h4>
+ <p class="topless"><a href="tutorial.html" title="next chapter">Quick IPython tutorial</a></p>
+ <h3>This Page</h3>
+ <ul class="this-page-menu">
+ <li><a href="../_sources/interactive/index.txt">Show Source</a></li>
+ </ul>
+ <h3>Quick search</h3>
+ <form class="search" action="../search.html" method="get">
+ <input type="text" name="q" size="18" /> <input type="submit" value="Go" />
+ <input type="hidden" name="check_keywords" value="yes" />
+ <input type="hidden" name="area" value="default" />
+ </form>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../modindex.html" title="Global Module Index"
+ accesskey="M">modules</a> |</li>
+ <li class="right" >
+ <a href="tutorial.html" title="Quick IPython tutorial"
+ accesskey="N">next</a> |</li>
+ <li class="right" >
+ <a href="../install/install.html" title="Overview"
+ accesskey="P">previous</a> |</li>
+ <li><a href="../index.html">IPython v0.10 documentation</a> &raquo;</li>
+ </ul>
+ </div>
+ <div class="footer">
+ &copy; Copyright 2008, The IPython Development Team.
+ Last updated on Aug 04, 2009.
+ Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 0.5.2.
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/ipythonbook/doc/rel-0.10/html/interactive/reference.html b/help/ipythonbook/doc/rel-0.10/html/interactive/reference.html
new file mode 100644
index 0000000..c5786c2
--- /dev/null
+++ b/help/ipythonbook/doc/rel-0.10/html/interactive/reference.html
@@ -0,0 +1,1651 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+ <title>IPython reference &mdash; IPython v0.10 documentation</title>
+ <link rel="stylesheet" href="../_static/default.css" type="text/css" />
+ <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
+ <script type="text/javascript">
+ var DOCUMENTATION_OPTIONS = {
+ URL_ROOT: '../',
+ VERSION: '0.10',
+ COLLAPSE_MODINDEX: false,
+ FILE_SUFFIX: '.html',
+ HAS_SOURCE: true
+ };
+ </script>
+ <script type="text/javascript" src="../_static/jquery.js"></script>
+ <script type="text/javascript" src="../_static/doctools.js"></script>
+ <link rel="top" title="IPython v0.10 documentation" href="../index.html" />
+ <link rel="up" title="Using IPython for interactive work" href="index.html" />
+ <link rel="next" title="IPython as a system shell" href="shell.html" />
+ <link rel="prev" title="Quick IPython tutorial" href="tutorial.html" />
+ </head>
+ <body>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../modindex.html" title="Global Module Index"
+ accesskey="M">modules</a> |</li>
+ <li class="right" >
+ <a href="shell.html" title="IPython as a system shell"
+ accesskey="N">next</a> |</li>
+ <li class="right" >
+ <a href="tutorial.html" title="Quick IPython tutorial"
+ accesskey="P">previous</a> |</li>
+ <li><a href="../index.html">IPython v0.10 documentation</a> &raquo;</li>
+ <li><a href="index.html" accesskey="U">Using IPython for interactive work</a> &raquo;</li>
+ </ul>
+ </div>
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body">
+
+
+ <div class="section" id="ipython-reference">
+<h1>IPython reference<a class="headerlink" href="#ipython-reference" title="Permalink to this headline">¶</a></h1>
+<div class="section" id="command-line-usage">
+<span id="command-line-options"></span><h2>Command-line usage<a class="headerlink" href="#command-line-usage" title="Permalink to this headline">¶</a></h2>
+<p>You start IPython with the command:</p>
+<div class="highlight-python"><pre>$ ipython [options] files</pre>
+</div>
+<p>If invoked with no options, it executes all the files listed in sequence
+and drops you into the interpreter while still acknowledging any options
+you may have set in your ipythonrc file. This behavior is different from
+standard Python, which when called as python -i will only execute one
+file and ignore your configuration setup.</p>
+<p>Please note that some of the configuration options are not available at
+the command line, simply because they are not practical here. Look into
+your ipythonrc configuration file for details on those. This file
+typically installed in the $HOME/.ipython directory. For Windows users,
+$HOME resolves to C:\Documents and Settings\YourUserName in most
+instances. In the rest of this text, we will refer to this directory as
+IPYTHONDIR.</p>
+<div class="section" id="special-threading-options">
+<span id="threading-options"></span><h3>Special Threading Options<a class="headerlink" href="#special-threading-options" title="Permalink to this headline">¶</a></h3>
+<p>The following special options are ONLY valid at the beginning of the
+command line, and not later. This is because they control the initial-
+ization of ipython itself, before the normal option-handling mechanism
+is active.</p>
+<blockquote>
+<dl class="docutils">
+<dt>-gthread, -qthread, -q4thread, -wthread, -pylab:</dt>
+<dd><p class="first">Only one of these can be given, and it can only be given as
+the first option passed to IPython (it will have no effect in
+any other position). They provide threading support for the
+GTK, Qt (versions 3 and 4) and WXPython toolkits, and for the
+matplotlib library.</p>
+<p>With any of the first four options, IPython starts running a
+separate thread for the graphical toolkit&#8217;s operation, so that
+you can open and control graphical elements from within an
+IPython command line, without blocking. All four provide
+essentially the same functionality, respectively for GTK, Qt3,
+Qt4 and WXWidgets (via their Python interfaces).</p>
+<p>Note that with -wthread, you can additionally use the
+-wxversion option to request a specific version of wx to be
+used. This requires that you have the wxversion Python module
+installed, which is part of recent wxPython distributions.</p>
+<p class="last">If -pylab is given, IPython loads special support for the mat
+plotlib library (<a class="reference external" href="http://matplotlib.sourceforge.net">http://matplotlib.sourceforge.net</a>), allowing
+interactive usage of any of its backends as defined in the
+user&#8217;s ~/.matplotlib/matplotlibrc file. It automatically
+activates GTK, Qt or WX threading for IPyhton if the choice of
+matplotlib backend requires it. It also modifies the %run
+command to correctly execute (without blocking) any
+matplotlib-based script which calls show() at the end.</p>
+</dd>
+</dl>
+<table class="docutils option-list" frame="void" rules="none">
+<col class="option" />
+<col class="description" />
+<tbody valign="top">
+<tr><td class="option-group">
+<kbd><span class="option">-t<var>k</var></span></kbd></td>
+<td><p class="first">The -g/q/q4/wthread options, and -pylab (if matplotlib is
+configured to use GTK, Qt3, Qt4 or WX), will normally block Tk
+graphical interfaces. This means that when either GTK, Qt or WX
+threading is active, any attempt to open a Tk GUI will result in a
+dead window, and possibly cause the Python interpreter to crash.
+An extra option, -tk, is available to address this issue. It can
+only be given as a second option after any of the above (-gthread,
+-wthread or -pylab).</p>
+<p>If -tk is given, IPython will try to coordinate Tk threading
+with GTK, Qt or WX. This is however potentially unreliable, and
+you will have to test on your platform and Python configuration to
+determine whether it works for you. Debian users have reported
+success, apparently due to the fact that Debian builds all of Tcl,
+Tk, Tkinter and Python with pthreads support. Under other Linux
+environments (such as Fedora Core 2/3), this option has caused
+random crashes and lockups of the Python interpreter. Under other
+operating systems (Mac OSX and Windows), you&#8217;ll need to try it to
+find out, since currently no user reports are available.</p>
+<p class="last">There is unfortunately no way for IPython to determine at run time
+whether -tk will work reliably or not, so you will need to do some
+experiments before relying on it for regular work.</p>
+</td></tr>
+</tbody>
+</table>
+</blockquote>
+</div>
+<div class="section" id="regular-options">
+<h3>Regular Options<a class="headerlink" href="#regular-options" title="Permalink to this headline">¶</a></h3>
+<p>After the above threading options have been given, regular options can
+follow in any order. All options can be abbreviated to their shortest
+non-ambiguous form and are case-sensitive. One or two dashes can be
+used. Some options have an alternate short form, indicated after a <tt class="docutils literal"><span class="pre">|</span></tt>.</p>
+<p>Most options can also be set from your ipythonrc configuration file. See
+the provided example for more details on what the options do. Options
+given at the command line override the values set in the ipythonrc file.</p>
+<p>All options with a [no] prepended can be specified in negated form
+(-nooption instead of -option) to turn the feature off.</p>
+<blockquote>
+<table class="docutils option-list" frame="void" rules="none">
+<col class="option" />
+<col class="description" />
+<tbody valign="top">
+<tr><td class="option-group">
+<kbd><span class="option">-h<var>elp</var></span></kbd></td>
+<td>print a help message and exit.</td></tr>
+<tr><td class="option-group">
+<kbd><span class="option">-p<var>ylab</var></span></kbd></td>
+<td>this can only be given as the first option passed to IPython
+(it will have no effect in any other position). It adds
+special support for the matplotlib library
+(<a class="reference external" href="http://matplotlib.sourceforge.ne">http://matplotlib.sourceforge.ne</a>), allowing interactive usage
+of any of its backends as defined in the user&#8217;s .matplotlibrc
+file. It automatically activates GTK or WX threading for
+IPyhton if the choice of matplotlib backend requires it. It
+also modifies the %run command to correctly execute (without
+blocking) any matplotlib-based script which calls show() at
+the end. See <a class="reference internal" href="#matplotlib-support">Matplotlib support</a> for more details.</td></tr>
+</tbody>
+</table>
+<dl class="docutils">
+<dt>-autocall &lt;val&gt;</dt>
+<dd>Make IPython automatically call any callable object even if you
+didn&#8217;t type explicit parentheses. For example, &#8216;str 43&#8217; becomes
+&#8216;str(43)&#8217; automatically. The value can be &#8216;0&#8217; to disable the feature,
+&#8216;1&#8217; for smart autocall, where it is not applied if there are no more
+arguments on the line, and &#8216;2&#8217; for full autocall, where all callable
+objects are automatically called (even if no arguments are
+present). The default is &#8216;1&#8217;.</dd>
+<dt>-[no]autoindent</dt>
+<dd>Turn automatic indentation on/off.</dd>
+<dt>-[no]automagic</dt>
+<dd>make magic commands automatic (without needing their first character
+to be %). Type %magic at the IPython prompt for more information.</dd>
+<dt>-[no]autoedit_syntax</dt>
+<dd>When a syntax error occurs after editing a file, automatically
+open the file to the trouble causing line for convenient
+fixing.</dd>
+</dl>
+<p>-[no]banner Print the initial information banner (default on).</p>
+<table class="docutils option-list" frame="void" rules="none">
+<col class="option" />
+<col class="description" />
+<tbody valign="top">
+<tr><td class="option-group">
+<kbd><span class="option">-c <var>&lt;command&gt;</var></span></kbd></td>
+<td>execute the given command string. This is similar to the -c
+option in the normal Python interpreter.</td></tr>
+</tbody>
+</table>
+<dl class="docutils">
+<dt>-cache_size, cs &lt;n&gt;</dt>
+<dd>size of the output cache (maximum number of entries to hold in
+memory). The default is 1000, you can change it permanently in your
+config file. Setting it to 0 completely disables the caching system,
+and the minimum value accepted is 20 (if you provide a value less than
+20, it is reset to 0 and a warning is issued) This limit is defined
+because otherwise you&#8217;ll spend more time re-flushing a too small cache
+than working.</dd>
+<dt>-classic, cl</dt>
+<dd>Gives IPython a similar feel to the classic Python
+prompt.</dd>
+<dt>-colors &lt;scheme&gt;</dt>
+<dd>Color scheme for prompts and exception reporting. Currently
+implemented: NoColor, Linux and LightBG.</dd>
+<dt>-[no]color_info</dt>
+<dd><p class="first">IPython can display information about objects via a set of functions,
+and optionally can use colors for this, syntax highlighting source
+code and various other elements. However, because this information is
+passed through a pager (like &#8216;less&#8217;) and many pagers get confused with
+color codes, this option is off by default. You can test it and turn
+it on permanently in your ipythonrc file if it works for you. As a
+reference, the &#8216;less&#8217; pager supplied with Mandrake 8.2 works ok, but
+that in RedHat 7.2 doesn&#8217;t.</p>
+<p class="last">Test it and turn it on permanently if it works with your
+system. The magic function %color_info allows you to toggle this
+interactively for testing.</p>
+</dd>
+<dt>-[no]debug</dt>
+<dd>Show information about the loading process. Very useful to pin down
+problems with your configuration files or to get details about
+session restores.</dd>
+<dt>-[no]deep_reload:</dt>
+<dd><p class="first">IPython can use the deep_reload module which reloads changes in
+modules recursively (it replaces the reload() function, so you don&#8217;t
+need to change anything to use it). deep_reload() forces a full
+reload of modules whose code may have changed, which the default
+reload() function does not.</p>
+<p class="last">When deep_reload is off, IPython will use the normal reload(),
+but deep_reload will still be available as dreload(). This
+feature is off by default [which means that you have both
+normal reload() and dreload()].</p>
+</dd>
+<dt>-editor &lt;name&gt;</dt>
+<dd>Which editor to use with the %edit command. By default,
+IPython will honor your EDITOR environment variable (if not
+set, vi is the Unix default and notepad the Windows one).
+Since this editor is invoked on the fly by IPython and is
+meant for editing small code snippets, you may want to use a
+small, lightweight editor here (in case your default EDITOR is
+something like Emacs).</dd>
+<dt>-ipythondir &lt;name&gt;</dt>
+<dd>name of your IPython configuration directory IPYTHONDIR. This
+can also be specified through the environment variable
+IPYTHONDIR.</dd>
+<dt>-log, l</dt>
+<dd>generate a log file of all input. The file is named
+ipython_log.py in your current directory (which prevents logs
+from multiple IPython sessions from trampling each other). You
+can use this to later restore a session by loading your
+logfile as a file to be executed with option -logplay (see
+below).</dd>
+</dl>
+<p>-logfile, lf &lt;name&gt; specify the name of your logfile.</p>
+<p>-logplay, lp &lt;name&gt;</p>
+<blockquote>
+<p>you can replay a previous log. For restoring a session as close as
+possible to the state you left it in, use this option (don&#8217;t just run
+the logfile). With -logplay, IPython will try to reconstruct the
+previous working environment in full, not just execute the commands in
+the logfile.</p>
+<p>When a session is restored, logging is automatically turned on
+again with the name of the logfile it was invoked with (it is
+read from the log header). So once you&#8217;ve turned logging on for
+a session, you can quit IPython and reload it as many times as
+you want and it will continue to log its history and restore
+from the beginning every time.</p>
+<p>Caveats: there are limitations in this option. The history
+variables _i*,_* and _dh don&#8217;t get restored properly. In the
+future we will try to implement full session saving by writing
+and retrieving a &#8216;snapshot&#8217; of the memory state of IPython. But
+our first attempts failed because of inherent limitations of
+Python&#8217;s Pickle module, so this may have to wait.</p>
+</blockquote>
+<dl class="docutils">
+<dt>-[no]messages</dt>
+<dd>Print messages which IPython collects about its startup
+process (default on).</dd>
+<dt>-[no]pdb</dt>
+<dd>Automatically call the pdb debugger after every uncaught
+exception. If you are used to debugging using pdb, this puts
+you automatically inside of it after any call (either in
+IPython or in code called by it) which triggers an exception
+which goes uncaught.</dd>
+</dl>
+<table class="docutils option-list" frame="void" rules="none">
+<col class="option" />
+<col class="description" />
+<tbody valign="top">
+<tr><td class="option-group">
+<kbd><span class="option">-p<var>ydb</var></span></kbd></td>
+<td>Makes IPython use the third party &#8220;pydb&#8221; package as debugger,
+instead of pdb. Requires that pydb is installed.</td></tr>
+</tbody>
+</table>
+<dl class="docutils">
+<dt>-[no]pprint</dt>
+<dd>ipython can optionally use the pprint (pretty printer) module
+for displaying results. pprint tends to give a nicer display
+of nested data structures. If you like it, you can turn it on
+permanently in your config file (default off).</dd>
+</dl>
+<p>-profile, p &lt;name&gt;</p>
+<blockquote>
+<p>assume that your config file is ipythonrc-&lt;name&gt; or
+ipy_profile_&lt;name&gt;.py (looks in current dir first, then in
+IPYTHONDIR). This is a quick way to keep and load multiple
+config files for different tasks, especially if you use the
+include option of config files. You can keep a basic
+IPYTHONDIR/ipythonrc file and then have other &#8216;profiles&#8217; which
+include this one and load extra things for particular
+tasks. For example:</p>
+<ol class="arabic simple">
+<li>$HOME/.ipython/ipythonrc : load basic things you always want.</li>
+<li>$HOME/.ipython/ipythonrc-math : load (1) and basic math-related modules.</li>
+<li>$HOME/.ipython/ipythonrc-numeric : load (1) and Numeric and plotting modules.</li>
+</ol>
+<p>Since it is possible to create an endless loop by having
+circular file inclusions, IPython will stop if it reaches 15
+recursive inclusions.</p>
+</blockquote>
+<p>-prompt_in1, pi1 &lt;string&gt;</p>
+<blockquote>
+Specify the string used for input prompts. Note that if you are using
+numbered prompts, the number is represented with a &#8216;#&#8217; in the
+string. Don&#8217;t forget to quote strings with spaces embedded in
+them. Default: &#8216;In [#]:&#8217;. The <a class="reference external" href="../config/customization.html#prompts"><em>prompts section</em></a>
+discusses in detail all the available escapes to customize your
+prompts.</blockquote>
+<dl class="docutils">
+<dt>-prompt_in2, pi2 &lt;string&gt;</dt>
+<dd>Similar to the previous option, but used for the continuation
+prompts. The special sequence &#8216;D&#8217; is similar to &#8216;#&#8217;, but
+with all digits replaced dots (so you can have your
+continuation prompt aligned with your input prompt). Default:
+&#8216; .D.:&#8217; (note three spaces at the start for alignment with
+&#8216;In [#]&#8217;).</dd>
+<dt>-prompt_out,po &lt;string&gt;</dt>
+<dd>String used for output prompts, also uses numbers like
+prompt_in1. Default: &#8216;Out[#]:&#8217;</dd>
+</dl>
+<table class="docutils option-list" frame="void" rules="none">
+<col class="option" />
+<col class="description" />
+<tbody valign="top">
+<tr><td class="option-group">
+<kbd><span class="option">-q<var>uick</var></span></kbd></td>
+<td>start in bare bones mode (no config file loaded).</td></tr>
+</tbody>
+</table>
+<dl class="docutils">
+<dt>-rcfile &lt;name&gt;</dt>
+<dd><p class="first">name of your IPython resource configuration file. Normally
+IPython loads ipythonrc (from current directory) or
+IPYTHONDIR/ipythonrc.</p>
+<p class="last">If the loading of your config file fails, IPython starts with
+a bare bones configuration (no modules loaded at all).</p>
+</dd>
+<dt>-[no]readline</dt>
+<dd><p class="first">use the readline library, which is needed to support name
+completion and command history, among other things. It is
+enabled by default, but may cause problems for users of
+X/Emacs in Python comint or shell buffers.</p>
+<p class="last">Note that X/Emacs &#8216;eterm&#8217; buffers (opened with M-x term) support
+IPython&#8217;s readline and syntax coloring fine, only &#8216;emacs&#8217; (M-x
+shell and C-c !) buffers do not.</p>
+</dd>
+<dt>-screen_length, sl &lt;n&gt;</dt>
+<dd><p class="first">number of lines of your screen. This is used to control
+printing of very long strings. Strings longer than this number
+of lines will be sent through a pager instead of directly
+printed.</p>
+<p class="last">The default value for this is 0, which means IPython will
+auto-detect your screen size every time it needs to print certain
+potentially long strings (this doesn&#8217;t change the behavior of the
+&#8216;print&#8217; keyword, it&#8217;s only triggered internally). If for some
+reason this isn&#8217;t working well (it needs curses support), specify
+it yourself. Otherwise don&#8217;t change the default.</p>
+</dd>
+</dl>
+<p>-separate_in, si &lt;string&gt;</p>
+<blockquote>
+separator before input prompts.
+Default: &#8216;n&#8217;</blockquote>
+<dl class="docutils">
+<dt>-separate_out, so &lt;string&gt;</dt>
+<dd>separator before output prompts.
+Default: nothing.</dd>
+<dt>-separate_out2, so2</dt>
+<dd>separator after output prompts.
+Default: nothing.
+For these three options, use the value 0 to specify no separator.</dd>
+</dl>
+<table class="docutils option-list" frame="void" rules="none">
+<col class="option" />
+<col class="description" />
+<tbody valign="top">
+<tr><td class="option-group">
+<kbd><span class="option">-n<var>osep</var></span></kbd></td>
+<td>shorthand for &#8216;-SeparateIn 0 -SeparateOut 0 -SeparateOut2
+0&#8217;. Simply removes all input/output separators.</td></tr>
+<tr><td class="option-group">
+<kbd><span class="option">-u<var>pgrade</var></span></kbd></td>
+<td>allows you to upgrade your IPYTHONDIR configuration when you
+install a new version of IPython. Since new versions may
+include new command line options or example files, this copies
+updated ipythonrc-type files. However, it backs up (with a
+.old extension) all files which it overwrites so that you can
+merge back any customizations you might have in your personal
+files. Note that you should probably use %upgrade instead,
+it&#8217;s a safer alternative.</td></tr>
+<tr><td class="option-group">
+<kbd><span class="option">-V<var>ersion</var></span></kbd></td>
+<td>print version information and exit.</td></tr>
+</tbody>
+</table>
+<dl class="docutils">
+<dt>-wxversion &lt;string&gt;</dt>
+<dd>Select a specific version of wxPython (used in conjunction
+with -wthread). Requires the wxversion module, part of recent
+wxPython distributions</dd>
+</dl>
+<p>-xmode &lt;modename&gt;</p>
+<blockquote>
+<p>Mode for exception reporting.</p>
+<p>Valid modes: Plain, Context and Verbose.</p>
+<ul class="simple">
+<li>Plain: similar to python&#8217;s normal traceback printing.</li>
+<li>Context: prints 5 lines of context source code around each
+line in the traceback.</li>
+<li>Verbose: similar to Context, but additionally prints the
+variables currently visible where the exception happened
+(shortening their strings if too long). This can potentially be
+very slow, if you happen to have a huge data structure whose
+string representation is complex to compute. Your computer may
+appear to freeze for a while with cpu usage at 100%. If this
+occurs, you can cancel the traceback with Ctrl-C (maybe hitting it
+more than once).</li>
+</ul>
+</blockquote>
+</blockquote>
+</div>
+</div>
+<div class="section" id="interactive-use">
+<h2>Interactive use<a class="headerlink" href="#interactive-use" title="Permalink to this headline">¶</a></h2>
+<p>Warning: IPython relies on the existence of a global variable called
+_ip which controls the shell itself. If you redefine _ip to anything,
+bizarre behavior will quickly occur.</p>
+<p>Other than the above warning, IPython is meant to work as a drop-in
+replacement for the standard interactive interpreter. As such, any code
+which is valid python should execute normally under IPython (cases where
+this is not true should be reported as bugs). It does, however, offer
+many features which are not available at a standard python prompt. What
+follows is a list of these.</p>
+<div class="section" id="caution-for-windows-users">
+<h3>Caution for Windows users<a class="headerlink" href="#caution-for-windows-users" title="Permalink to this headline">¶</a></h3>
+<p>Windows, unfortunately, uses the &#8216;&#8217; character as a path
+separator. This is a terrible choice, because &#8216;&#8217; also represents the
+escape character in most modern programming languages, including
+Python. For this reason, using &#8216;/&#8217; character is recommended if you
+have problems with <tt class="docutils literal"><span class="pre">\</span></tt>. However, in Windows commands &#8216;/&#8217; flags
+options, so you can not use it for the root directory. This means that
+paths beginning at the root must be typed in a contrived manner like:
+<tt class="docutils literal"><span class="pre">%copy</span> <span class="pre">\opt/foo/bar.txt</span> <span class="pre">\tmp</span></tt></p>
+</div>
+<div class="section" id="magic-command-system">
+<span id="magic"></span><h3>Magic command system<a class="headerlink" href="#magic-command-system" title="Permalink to this headline">¶</a></h3>
+<p>IPython will treat any line whose first character is a % as a special
+call to a &#8216;magic&#8217; function. These allow you to control the behavior of
+IPython itself, plus a lot of system-type features. They are all
+prefixed with a % character, but parameters are given without
+parentheses or quotes.</p>
+<p>Example: typing &#8216;%cd mydir&#8217; (without the quotes) changes you working
+directory to &#8216;mydir&#8217;, if it exists.</p>
+<p>If you have &#8216;automagic&#8217; enabled (in your ipythonrc file, via the command
+line option -automagic or with the %automagic function), you don&#8217;t need
+to type in the % explicitly. IPython will scan its internal list of
+magic functions and call one if it exists. With automagic on you can
+then just type &#8216;cd mydir&#8217; to go to directory &#8216;mydir&#8217;. The automagic
+system has the lowest possible precedence in name searches, so defining
+an identifier with the same name as an existing magic function will
+shadow it for automagic use. You can still access the shadowed magic
+function by explicitly using the % character at the beginning of the line.</p>
+<p>An example (with automagic on) should clarify all this:</p>
+<div class="highlight-python"><pre>In [1]: cd ipython # %cd is called by automagic
+
+/home/fperez/ipython
+
+In [2]: cd=1 # now cd is just a variable
+
+In [3]: cd .. # and doesn't work as a function anymore
+
+------------------------------
+
+ File "&lt;console&gt;", line 1
+
+ cd ..
+
+ ^
+
+SyntaxError: invalid syntax
+
+In [4]: %cd .. # but %cd always works
+
+/home/fperez
+
+In [5]: del cd # if you remove the cd variable
+
+In [6]: cd ipython # automagic can work again
+
+/home/fperez/ipython</pre>
+</div>
+<p>You can define your own magic functions to extend the system. The
+following example defines a new magic command, %impall:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="k">import</span> <span class="nn">IPython.ipapi</span>
+
+<span class="n">ip</span> <span class="o">=</span> <span class="n">IPython</span><span class="o">.</span><span class="n">ipapi</span><span class="o">.</span><span class="n">get</span><span class="p">()</span>
+
+<span class="k">def</span> <span class="nf">doimp</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">arg</span><span class="p">):</span>
+
+ <span class="n">ip</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">api</span>
+
+ <span class="n">ip</span><span class="o">.</span><span class="n">ex</span><span class="p">(</span><span class="s">&quot;import </span><span class="si">%s</span><span class="s">; reload(</span><span class="si">%s</span><span class="s">); from </span><span class="si">%s</span><span class="s"> import *&quot;</span> <span class="o">%</span> <span class="p">(</span>
+
+ <span class="n">arg</span><span class="p">,</span><span class="n">arg</span><span class="p">,</span><span class="n">arg</span><span class="p">)</span>
+
+ <span class="p">)</span>
+
+<span class="n">ip</span><span class="o">.</span><span class="n">expose_magic</span><span class="p">(</span><span class="s">&#39;impall&#39;</span><span class="p">,</span> <span class="n">doimp</span><span class="p">)</span>
+</pre></div>
+</div>
+<p>You can also define your own aliased names for magic functions. In your
+ipythonrc file, placing a line like:</p>
+<div class="highlight-python"><pre>execute __IP.magic_cl = __IP.magic_clear</pre>
+</div>
+<p>will define %cl as a new name for %clear.</p>
+<p>Type %magic for more information, including a list of all available
+magic functions at any time and their docstrings. You can also type
+%magic_function_name? (see sec. 6.4 &lt;#sec:dyn-object-info&gt; for
+information on the &#8216;?&#8217; system) to get information about any particular
+magic function you are interested in.</p>
+<p>The API documentation for the <a title="" class="reference external" href="../api/generated/IPython.Magic.html#module-IPython.Magic"><tt class="xref docutils literal"><span class="pre">IPython.Magic</span></tt></a> module contains the full
+docstrings of all currently available magic commands.</p>
+</div>
+<div class="section" id="access-to-the-standard-python-help">
+<h3>Access to the standard Python help<a class="headerlink" href="#access-to-the-standard-python-help" title="Permalink to this headline">¶</a></h3>
+<p>As of Python 2.1, a help system is available with access to object docstrings
+and the Python manuals. Simply type &#8216;help&#8217; (no quotes) to access it. You can
+also type help(object) to obtain information about a given object, and
+help(&#8216;keyword&#8217;) for information on a keyword. As noted <a class="reference external" href="../config/initial_config.html#accessing-help"><em>here</em></a>, you need to properly configure your environment variable
+PYTHONDOCS for this feature to work correctly.</p>
+</div>
+<div class="section" id="dynamic-object-information">
+<span id="dynamic-object-info"></span><h3>Dynamic object information<a class="headerlink" href="#dynamic-object-information" title="Permalink to this headline">¶</a></h3>
+<p>Typing ?word or word? prints detailed information about an object. If
+certain strings in the object are too long (docstrings, code, etc.) they
+get snipped in the center for brevity. This system gives access variable
+types and values, full source code for any object (if available),
+function prototypes and other useful information.</p>
+<p>Typing ??word or word?? gives access to the full information without
+snipping long strings. Long strings are sent to the screen through the
+less pager if longer than the screen and printed otherwise. On systems
+lacking the less command, IPython uses a very basic internal pager.</p>
+<p>The following magic functions are particularly useful for gathering
+information about your working environment. You can get more details by
+typing %magic or querying them individually (use %function_name? with or
+without the %), this is just a summary:</p>
+<blockquote>
+<ul class="simple">
+<li><strong>%pdoc &lt;object&gt;</strong>: Print (or run through a pager if too long) the
+docstring for an object. If the given object is a class, it will
+print both the class and the constructor docstrings.</li>
+<li><strong>%pdef &lt;object&gt;</strong>: Print the definition header for any callable
+object. If the object is a class, print the constructor information.</li>
+<li><strong>%psource &lt;object&gt;</strong>: Print (or run through a pager if too long)
+the source code for an object.</li>
+<li><strong>%pfile &lt;object&gt;</strong>: Show the entire source file where an object was
+defined via a pager, opening it at the line where the object
+definition begins.</li>
+<li><strong>%who/%whos</strong>: These functions give information about identifiers
+you have defined interactively (not things you loaded or defined
+in your configuration files). %who just prints a list of
+identifiers and %whos prints a table with some basic details about
+each identifier.</li>
+</ul>
+</blockquote>
+<p>Note that the dynamic object information functions (?/??, %pdoc, %pfile,
+%pdef, %psource) give you access to documentation even on things which
+are not really defined as separate identifiers. Try for example typing
+{}.get? or after doing import os, type os.path.abspath??.</p>
+</div>
+<div class="section" id="readline-based-features">
+<span id="readline"></span><h3>Readline-based features<a class="headerlink" href="#readline-based-features" title="Permalink to this headline">¶</a></h3>
+<p>These features require the GNU readline library, so they won&#8217;t work if
+your Python installation lacks readline support. We will first describe
+the default behavior IPython uses, and then how to change it to suit
+your preferences.</p>
+<div class="section" id="command-line-completion">
+<h4>Command line completion<a class="headerlink" href="#command-line-completion" title="Permalink to this headline">¶</a></h4>
+<p>At any time, hitting TAB will complete any available python commands or
+variable names, and show you a list of the possible completions if
+there&#8217;s no unambiguous one. It will also complete filenames in the
+current directory if no python names match what you&#8217;ve typed so far.</p>
+</div>
+<div class="section" id="search-command-history">
+<h4>Search command history<a class="headerlink" href="#search-command-history" title="Permalink to this headline">¶</a></h4>
+<p>IPython provides two ways for searching through previous input and thus
+reduce the need for repetitive typing:</p>
+<blockquote>
+<ol class="arabic simple">
+<li>Start typing, and then use Ctrl-p (previous,up) and Ctrl-n
+(next,down) to search through only the history items that match
+what you&#8217;ve typed so far. If you use Ctrl-p/Ctrl-n at a blank
+prompt, they just behave like normal arrow keys.</li>
+<li>Hit Ctrl-r: opens a search prompt. Begin typing and the system
+searches your history for lines that contain what you&#8217;ve typed so
+far, completing as much as it can.</li>
+</ol>
+</blockquote>
+</div>
+<div class="section" id="persistent-command-history-across-sessions">
+<h4>Persistent command history across sessions<a class="headerlink" href="#persistent-command-history-across-sessions" title="Permalink to this headline">¶</a></h4>
+<p>IPython will save your input history when it leaves and reload it next
+time you restart it. By default, the history file is named
+$IPYTHONDIR/history, but if you&#8217;ve loaded a named profile,
+&#8216;-PROFILE_NAME&#8217; is appended to the name. This allows you to keep
+separate histories related to various tasks: commands related to
+numerical work will not be clobbered by a system shell history, for
+example.</p>
+</div>
+<div class="section" id="autoindent">
+<h4>Autoindent<a class="headerlink" href="#autoindent" title="Permalink to this headline">¶</a></h4>
+<p>IPython can recognize lines ending in &#8216;:&#8217; and indent the next line,
+while also un-indenting automatically after &#8216;raise&#8217; or &#8216;return&#8217;.</p>
+<p>This feature uses the readline library, so it will honor your ~/.inputrc
+configuration (or whatever file your INPUTRC variable points to). Adding
+the following lines to your .inputrc file can make indenting/unindenting
+more convenient (M-i indents, M-u unindents):</p>
+<div class="highlight-python"><pre>$if Python
+"\M-i": " "
+"\M-u": "\d\d\d\d"
+$endif</pre>
+</div>
+<p>Note that there are 4 spaces between the quote marks after &#8220;M-i&#8221; above.</p>
+<p>Warning: this feature is ON by default, but it can cause problems with
+the pasting of multi-line indented code (the pasted code gets
+re-indented on each line). A magic function %autoindent allows you to
+toggle it on/off at runtime. You can also disable it permanently on in
+your ipythonrc file (set autoindent 0).</p>
+</div>
+<div class="section" id="customizing-readline-behavior">
+<h4>Customizing readline behavior<a class="headerlink" href="#customizing-readline-behavior" title="Permalink to this headline">¶</a></h4>
+<p>All these features are based on the GNU readline library, which has an
+extremely customizable interface. Normally, readline is configured via a
+file which defines the behavior of the library; the details of the
+syntax for this can be found in the readline documentation available
+with your system or on the Internet. IPython doesn&#8217;t read this file (if
+it exists) directly, but it does support passing to readline valid
+options via a simple interface. In brief, you can customize readline by
+setting the following options in your ipythonrc configuration file (note
+that these options can not be specified at the command line):</p>
+<blockquote>
+<ul>
+<li><p class="first"><strong>readline_parse_and_bind</strong>: this option can appear as many times as
+you want, each time defining a string to be executed via a
+readline.parse_and_bind() command. The syntax for valid commands
+of this kind can be found by reading the documentation for the GNU
+readline library, as these commands are of the kind which readline
+accepts in its configuration file.</p>
+</li>
+<li><p class="first"><strong>readline_remove_delims</strong>: a string of characters to be removed
+from the default word-delimiters list used by readline, so that
+completions may be performed on strings which contain them. Do not
+change the default value unless you know what you&#8217;re doing.</p>
+</li>
+<li><p class="first"><strong>readline_omit__names</strong>: when tab-completion is enabled, hitting
+&lt;tab&gt; after a &#8216;.&#8217; in a name will complete all attributes of an
+object, including all the special methods whose names include
+double underscores (like __getitem__ or __class__). If you&#8217;d
+rather not see these names by default, you can set this option to
+1. Note that even when this option is set, you can still see those
+names by explicitly typing a _ after the period and hitting &lt;tab&gt;:
+&#8216;name._&lt;tab&gt;&#8217; will always complete attribute names starting with &#8216;_&#8217;.</p>
+<p>This option is off by default so that new users see all
+attributes of any objects they are dealing with.</p>
+</li>
+</ul>
+</blockquote>
+<p>You will find the default values along with a corresponding detailed
+explanation in your ipythonrc file.</p>
+</div>
+</div>
+<div class="section" id="session-logging-and-restoring">
+<h3>Session logging and restoring<a class="headerlink" href="#session-logging-and-restoring" title="Permalink to this headline">¶</a></h3>
+<p>You can log all input from a session either by starting IPython with the
+command line switches -log or -logfile (see <a class="reference internal" href="#command-line-options"><em>here</em></a>)
+or by activating the logging at any moment with the magic function %logstart.</p>
+<p>Log files can later be reloaded with the -logplay option and IPython
+will attempt to &#8216;replay&#8217; the log by executing all the lines in it, thus
+restoring the state of a previous session. This feature is not quite
+perfect, but can still be useful in many cases.</p>
+<p>The log files can also be used as a way to have a permanent record of
+any code you wrote while experimenting. Log files are regular text files
+which you can later open in your favorite text editor to extract code or
+to &#8216;clean them up&#8217; before using them to replay a session.</p>
+<p>The %logstart function for activating logging in mid-session is used as
+follows:</p>
+<p>%logstart [log_name [log_mode]]</p>
+<p>If no name is given, it defaults to a file named &#8216;log&#8217; in your
+IPYTHONDIR directory, in &#8216;rotate&#8217; mode (see below).</p>
+<p>&#8216;%logstart name&#8217; saves to file &#8216;name&#8217; in &#8216;backup&#8217; mode. It saves your
+history up to that point and then continues logging.</p>
+<p>%logstart takes a second optional parameter: logging mode. This can be
+one of (note that the modes are given unquoted):</p>
+<blockquote>
+<ul class="simple">
+<li>[over:] overwrite existing log_name.</li>
+<li>[backup:] rename (if exists) to log_name~ and start log_name.</li>
+<li>[append:] well, that says it.</li>
+<li>[rotate:] create rotating logs log_name.1~, log_name.2~, etc.</li>
+</ul>
+</blockquote>
+<p>The %logoff and %logon functions allow you to temporarily stop and
+resume logging to a file which had previously been started with
+%logstart. They will fail (with an explanation) if you try to use them
+before logging has been started.</p>
+</div>
+<div class="section" id="id1">
+<span id="system-shell-access"></span><h3>System shell access<a class="headerlink" href="#id1" title="Permalink to this headline">¶</a></h3>
+<p>Any input line beginning with a ! character is passed verbatim (minus
+the !, of course) to the underlying operating system. For example,
+typing !ls will run &#8216;ls&#8217; in the current directory.</p>
+</div>
+<div class="section" id="manual-capture-of-command-output">
+<h3>Manual capture of command output<a class="headerlink" href="#manual-capture-of-command-output" title="Permalink to this headline">¶</a></h3>
+<p>If the input line begins with two exclamation marks, !!, the command is
+executed but its output is captured and returned as a python list, split
+on newlines. Any output sent by the subprocess to standard error is
+printed separately, so that the resulting list only captures standard
+output. The !! syntax is a shorthand for the %sx magic command.</p>
+<p>Finally, the %sc magic (short for &#8216;shell capture&#8217;) is similar to %sx,
+but allowing more fine-grained control of the capture details, and
+storing the result directly into a named variable. The direct use of
+%sc is now deprecated, and you should ise the <tt class="docutils literal"><span class="pre">var</span> <span class="pre">=</span> <span class="pre">!cmd</span></tt> syntax
+instead.</p>
+<p>IPython also allows you to expand the value of python variables when
+making system calls. Any python variable or expression which you prepend
+with $ will get expanded before the system call is made:</p>
+<div class="highlight-python"><pre>In [1]: pyvar='Hello world'
+In [2]: !echo "A python variable: $pyvar"
+A python variable: Hello world</pre>
+</div>
+<p>If you want the shell to actually see a literal $, you need to type it
+twice:</p>
+<div class="highlight-python"><pre>In [3]: !echo "A system variable: $$HOME"
+A system variable: /home/fperez</pre>
+</div>
+<p>You can pass arbitrary expressions, though you&#8217;ll need to delimit them
+with {} if there is ambiguity as to the extent of the expression:</p>
+<div class="highlight-python"><pre>In [5]: x=10
+In [6]: y=20
+In [13]: !echo $x+y
+10+y
+In [7]: !echo ${x+y}
+30</pre>
+</div>
+<p>Even object attributes can be expanded:</p>
+<div class="highlight-python"><pre>In [12]: !echo $sys.argv
+[/home/fperez/usr/bin/ipython]</pre>
+</div>
+</div>
+<div class="section" id="system-command-aliases">
+<h3>System command aliases<a class="headerlink" href="#system-command-aliases" title="Permalink to this headline">¶</a></h3>
+<p>The %alias magic function and the alias option in the ipythonrc
+configuration file allow you to define magic functions which are in fact
+system shell commands. These aliases can have parameters.</p>
+<p>&#8216;%alias alias_name cmd&#8217; defines &#8216;alias_name&#8217; as an alias for &#8216;cmd&#8217;</p>
+<p>Then, typing &#8216;%alias_name params&#8217; will execute the system command &#8216;cmd
+params&#8217; (from your underlying operating system).</p>
+<p>You can also define aliases with parameters using %s specifiers (one per
+parameter). The following example defines the %parts function as an
+alias to the command &#8216;echo first %s second %s&#8217; where each %s will be
+replaced by a positional parameter to the call to %parts:</p>
+<div class="highlight-python"><pre>In [1]: alias parts echo first %s second %s
+In [2]: %parts A B
+first A second B
+In [3]: %parts A
+Incorrect number of arguments: 2 expected.
+parts is an alias to: 'echo first %s second %s'</pre>
+</div>
+<p>If called with no parameters, %alias prints the table of currently
+defined aliases.</p>
+<p>The %rehash/rehashx magics allow you to load your entire $PATH as
+ipython aliases. See their respective docstrings (or sec. 6.2
+&lt;#sec:magic&gt; for further details).</p>
+</div>
+<div class="section" id="recursive-reload">
+<span id="dreload"></span><h3>Recursive reload<a class="headerlink" href="#recursive-reload" title="Permalink to this headline">¶</a></h3>
+<p>The dreload function does a recursive reload of a module: changes made
+to the module since you imported will actually be available without
+having to exit.</p>
+</div>
+<div class="section" id="verbose-and-colored-exception-traceback-printouts">
+<h3>Verbose and colored exception traceback printouts<a class="headerlink" href="#verbose-and-colored-exception-traceback-printouts" title="Permalink to this headline">¶</a></h3>
+<p>IPython provides the option to see very detailed exception tracebacks,
+which can be especially useful when debugging large programs. You can
+run any Python file with the %run function to benefit from these
+detailed tracebacks. Furthermore, both normal and verbose tracebacks can
+be colored (if your terminal supports it) which makes them much easier
+to parse visually.</p>
+<p>See the magic xmode and colors functions for details (just type %magic).</p>
+<p>These features are basically a terminal version of Ka-Ping Yee&#8217;s cgitb
+module, now part of the standard Python library.</p>
+</div>
+<div class="section" id="input-caching-system">
+<span id="input-caching"></span><h3>Input caching system<a class="headerlink" href="#input-caching-system" title="Permalink to this headline">¶</a></h3>
+<p>IPython offers numbered prompts (In/Out) with input and output caching
+(also referred to as &#8216;input history&#8217;). All input is saved and can be
+retrieved as variables (besides the usual arrow key recall), in
+addition to the %rep magic command that brings a history entry
+up for editing on the next command line.</p>
+<p>The following GLOBAL variables always exist (so don&#8217;t overwrite them!):
+_i: stores previous input. _ii: next previous. _iii: next-next previous.
+_ih : a list of all input _ih[n] is the input from line n and this list
+is aliased to the global variable In. If you overwrite In with a
+variable of your own, you can remake the assignment to the internal list
+with a simple &#8216;In=_ih&#8217;.</p>
+<p>Additionally, global variables named _i&lt;n&gt; are dynamically created (&lt;n&gt;
+being the prompt counter), such that
+_i&lt;n&gt; == _ih[&lt;n&gt;] == In[&lt;n&gt;].</p>
+<p>For example, what you typed at prompt 14 is available as _i14, _ih[14]
+and In[14].</p>
+<p>This allows you to easily cut and paste multi line interactive prompts
+by printing them out: they print like a clean string, without prompt
+characters. You can also manipulate them like regular variables (they
+are strings), modify or exec them (typing &#8216;exec _i9&#8217; will re-execute the
+contents of input prompt 9, &#8216;exec In[9:14]+In[18]&#8217; will re-execute lines
+9 through 13 and line 18).</p>
+<p>You can also re-execute multiple lines of input easily by using the
+magic %macro function (which automates the process and allows
+re-execution without having to type &#8216;exec&#8217; every time). The macro system
+also allows you to re-execute previous lines which include magic
+function calls (which require special processing). Type %macro? or see
+sec. 6.2 &lt;#sec:magic&gt; for more details on the macro system.</p>
+<p>A history function %hist allows you to see any part of your input
+history by printing a range of the _i variables.</p>
+<p>You can also search (&#8216;grep&#8217;) through your history by typing
+&#8216;%hist -g somestring&#8217;. This also searches through the so called <em>shadow history</em>,
+which remembers all the commands (apart from multiline code blocks)
+you have ever entered. Handy for searching for svn/bzr URL&#8217;s, IP adrresses
+etc. You can bring shadow history entries listed by &#8216;%hist -g&#8217; up for editing
+(or re-execution by just pressing ENTER) with %rep command. Shadow history
+entries are not available as _iNUMBER variables, and they are identified by
+the &#8216;0&#8217; prefix in %hist -g output. That is, history entry 12 is a normal
+history entry, but 0231 is a shadow history entry.</p>
+<p>Shadow history was added because the readline history is inherently very
+unsafe - if you have multiple IPython sessions open, the last session
+to close will overwrite the history of previountly closed session. Likewise,
+if a crash occurs, history is never saved, whereas shadow history entries
+are added after entering every command (so a command executed
+in another IPython session is immediately available in other IPython
+sessions that are open).</p>
+<p>To conserve space, a command can exist in shadow history only once - it doesn&#8217;t
+make sense to store a common line like &#8220;cd ..&#8221; a thousand times. The idea is
+mainly to provide a reliable place where valuable, hard-to-remember commands can
+always be retrieved, as opposed to providing an exact sequence of commands
+you have entered in actual order.</p>
+<p>Because shadow history has all the commands you have ever executed,
+time taken by %hist -g will increase oven time. If it ever starts to take
+too long (or it ends up containing sensitive information like passwords),
+clear the shadow history by <cite>%clear shadow_nuke</cite>.</p>
+<p>Time taken to add entries to shadow history should be negligible, but
+in any case, if you start noticing performance degradation after using
+IPython for a long time (or running a script that floods the shadow history!),
+you can &#8216;compress&#8217; the shadow history by executing
+<cite>%clear shadow_compress</cite>. In practice, this should never be necessary
+in normal use.</p>
+</div>
+<div class="section" id="output-caching-system">
+<span id="output-caching"></span><h3>Output caching system<a class="headerlink" href="#output-caching-system" title="Permalink to this headline">¶</a></h3>
+<p>For output that is returned from actions, a system similar to the input
+cache exists but using _ instead of _i. Only actions that produce a
+result (NOT assignments, for example) are cached. If you are familiar
+with Mathematica, IPython&#8217;s _ variables behave exactly like
+Mathematica&#8217;s % variables.</p>
+<p>The following GLOBAL variables always exist (so don&#8217;t overwrite them!):</p>
+<blockquote>
+<ul class="simple">
+<li>[_] (a single underscore) : stores previous output, like Python&#8217;s
+default interpreter.</li>
+<li>[__] (two underscores): next previous.</li>
+<li>[___] (three underscores): next-next previous.</li>
+</ul>
+</blockquote>
+<p>Additionally, global variables named _&lt;n&gt; are dynamically created (&lt;n&gt;
+being the prompt counter), such that the result of output &lt;n&gt; is always
+available as _&lt;n&gt; (don&#8217;t use the angle brackets, just the number, e.g.
+_21).</p>
+<p>These global variables are all stored in a global dictionary (not a
+list, since it only has entries for lines which returned a result)
+available under the names _oh and Out (similar to _ih and In). So the
+output from line 12 can be obtained as _12, Out[12] or _oh[12]. If you
+accidentally overwrite the Out variable you can recover it by typing
+&#8216;Out=_oh&#8217; at the prompt.</p>
+<p>This system obviously can potentially put heavy memory demands on your
+system, since it prevents Python&#8217;s garbage collector from removing any
+previously computed results. You can control how many results are kept
+in memory with the option (at the command line or in your ipythonrc
+file) cache_size. If you set it to 0, the whole system is completely
+disabled and the prompts revert to the classic &#8216;&gt;&gt;&gt;&#8217; of normal Python.</p>
+</div>
+<div class="section" id="directory-history">
+<h3>Directory history<a class="headerlink" href="#directory-history" title="Permalink to this headline">¶</a></h3>
+<p>Your history of visited directories is kept in the global list _dh, and
+the magic %cd command can be used to go to any entry in that list. The
+%dhist command allows you to view this history. Do <tt class="docutils literal"><span class="pre">cd</span> <span class="pre">-&lt;TAB</span></tt> to
+conventiently view the directory history.</p>
+</div>
+<div class="section" id="automatic-parentheses-and-quotes">
+<h3>Automatic parentheses and quotes<a class="headerlink" href="#automatic-parentheses-and-quotes" title="Permalink to this headline">¶</a></h3>
+<p>These features were adapted from Nathan Gray&#8217;s LazyPython. They are
+meant to allow less typing for common situations.</p>
+</div>
+<div class="section" id="automatic-parentheses">
+<h3>Automatic parentheses<a class="headerlink" href="#automatic-parentheses" title="Permalink to this headline">¶</a></h3>
+<p>Callable objects (i.e. functions, methods, etc) can be invoked like this
+(notice the commas between the arguments):</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">callable_ob</span> <span class="n">arg1</span><span class="p">,</span> <span class="n">arg2</span><span class="p">,</span> <span class="n">arg3</span>
+</pre></div>
+</div>
+<p>and the input will be translated to this:</p>
+<div class="highlight-python"><pre>-&gt; callable_ob(arg1, arg2, arg3)</pre>
+</div>
+<p>You can force automatic parentheses by using &#8216;/&#8217; as the first character
+of a line. For example:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="o">/</span><span class="nb">globals</span> <span class="c"># becomes &#39;globals()&#39;</span>
+</pre></div>
+</div>
+<p>Note that the &#8216;/&#8217; MUST be the first character on the line! This won&#8217;t work:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">print</span> <span class="o">/</span><span class="nb">globals</span> <span class="c"># syntax error</span>
+</pre></div>
+</div>
+<p>In most cases the automatic algorithm should work, so you should rarely
+need to explicitly invoke /. One notable exception is if you are trying
+to call a function with a list of tuples as arguments (the parenthesis
+will confuse IPython):</p>
+<div class="highlight-python"><pre>In [1]: zip (1,2,3),(4,5,6) # won't work</pre>
+</div>
+<p>but this will work:</p>
+<div class="highlight-python"><pre>In [2]: /zip (1,2,3),(4,5,6)
+---&gt; zip ((1,2,3),(4,5,6))
+Out[2]= [(1, 4), (2, 5), (3, 6)]</pre>
+</div>
+<p>IPython tells you that it has altered your command line by displaying
+the new command line preceded by -&gt;. e.g.:</p>
+<div class="highlight-python"><pre>In [18]: callable list
+----&gt; callable (list)</pre>
+</div>
+</div>
+<div class="section" id="automatic-quoting">
+<h3>Automatic quoting<a class="headerlink" href="#automatic-quoting" title="Permalink to this headline">¶</a></h3>
+<p>You can force automatic quoting of a function&#8217;s arguments by using &#8216;,&#8217;
+or &#8216;;&#8217; as the first character of a line. For example:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="p">,</span><span class="n">my_function</span> <span class="o">/</span><span class="n">home</span><span class="o">/</span><span class="n">me</span> <span class="c"># becomes my_function(&quot;/home/me&quot;)</span>
+</pre></div>
+</div>
+<p>If you use &#8216;;&#8217; instead, the whole argument is quoted as a single string
+(while &#8216;,&#8217; splits on whitespace):</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="p">,</span><span class="n">my_function</span> <span class="n">a</span> <span class="n">b</span> <span class="n">c</span> <span class="c"># becomes my_function(&quot;a&quot;,&quot;b&quot;,&quot;c&quot;)</span>
+
+<span class="gp">&gt;&gt;&gt; </span><span class="p">;</span><span class="n">my_function</span> <span class="n">a</span> <span class="n">b</span> <span class="n">c</span> <span class="c"># becomes my_function(&quot;a b c&quot;)</span>
+</pre></div>
+</div>
+<p>Note that the &#8216;,&#8217; or &#8216;;&#8217; MUST be the first character on the line! This
+won&#8217;t work:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">x</span> <span class="o">=</span> <span class="p">,</span><span class="n">my_function</span> <span class="o">/</span><span class="n">home</span><span class="o">/</span><span class="n">me</span> <span class="c"># syntax error</span>
+</pre></div>
+</div>
+</div>
+</div>
+<div class="section" id="ipython-as-your-default-python-environment">
+<h2>IPython as your default Python environment<a class="headerlink" href="#ipython-as-your-default-python-environment" title="Permalink to this headline">¶</a></h2>
+<p>Python honors the environment variable PYTHONSTARTUP and will execute at
+startup the file referenced by this variable. If you put at the end of
+this file the following two lines of code:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="k">import</span> <span class="nn">IPython</span>
+<span class="n">IPython</span><span class="o">.</span><span class="n">Shell</span><span class="o">.</span><span class="n">IPShell</span><span class="p">()</span><span class="o">.</span><span class="n">mainloop</span><span class="p">(</span><span class="n">sys_exit</span><span class="o">=</span><span class="mf">1</span><span class="p">)</span>
+</pre></div>
+</div>
+<p>then IPython will be your working environment anytime you start Python.
+The sys_exit=1 is needed to have IPython issue a call to sys.exit() when
+it finishes, otherwise you&#8217;ll be back at the normal Python &#8216;&gt;&gt;&gt;&#8217;
+prompt.</p>
+<p>This is probably useful to developers who manage multiple Python
+versions and don&#8217;t want to have correspondingly multiple IPython
+versions. Note that in this mode, there is no way to pass IPython any
+command-line options, as those are trapped first by Python itself.</p>
+</div>
+<div class="section" id="embedding-ipython">
+<span id="embedding"></span><h2>Embedding IPython<a class="headerlink" href="#embedding-ipython" title="Permalink to this headline">¶</a></h2>
+<p>It is possible to start an IPython instance inside your own Python
+programs. This allows you to evaluate dynamically the state of your
+code, operate with your variables, analyze them, etc. Note however that
+any changes you make to values while in the shell do not propagate back
+to the running code, so it is safe to modify your values because you
+won&#8217;t break your code in bizarre ways by doing so.</p>
+<p>This feature allows you to easily have a fully functional python
+environment for doing object introspection anywhere in your code with a
+simple function call. In some cases a simple print statement is enough,
+but if you need to do more detailed analysis of a code fragment this
+feature can be very valuable.</p>
+<p>It can also be useful in scientific computing situations where it is
+common to need to do some automatic, computationally intensive part and
+then stop to look at data, plots, etc.
+Opening an IPython instance will give you full access to your data and
+functions, and you can resume program execution once you are done with
+the interactive part (perhaps to stop again later, as many times as
+needed).</p>
+<p>The following code snippet is the bare minimum you need to include in
+your Python programs for this to work (detailed examples follow later):</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="k">from</span> <span class="nn">IPython.Shell</span> <span class="k">import</span> <span class="n">IPShellEmbed</span>
+
+<span class="n">ipshell</span> <span class="o">=</span> <span class="n">IPShellEmbed</span><span class="p">()</span>
+
+<span class="n">ipshell</span><span class="p">()</span> <span class="c"># this call anywhere in your program will start IPython</span>
+</pre></div>
+</div>
+<p>You can run embedded instances even in code which is itself being run at
+the IPython interactive prompt with &#8216;%run &lt;filename&gt;&#8217;. Since it&#8217;s easy
+to get lost as to where you are (in your top-level IPython or in your
+embedded one), it&#8217;s a good idea in such cases to set the in/out prompts
+to something different for the embedded instances. The code examples
+below illustrate this.</p>
+<p>You can also have multiple IPython instances in your program and open
+them separately, for example with different options for data
+presentation. If you close and open the same instance multiple times,
+its prompt counters simply continue from each execution to the next.</p>
+<p>Please look at the docstrings in the Shell.py module for more details on
+the use of this system.</p>
+<p>The following sample file illustrating how to use the embedding
+functionality is provided in the examples directory as example-embed.py.
+It should be fairly self-explanatory:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="c">#!/usr/bin/env python</span>
+
+<span class="sd">&quot;&quot;&quot;An example of how to embed an IPython shell into a running program.</span>
+
+<span class="sd">Please see the documentation in the IPython.Shell module for more details.</span>
+
+<span class="sd">The accompanying file example-embed-short.py has quick code fragments for</span>
+<span class="sd">embedding which you can cut and paste in your code once you understand how</span>
+<span class="sd">things work.</span>
+
+<span class="sd">The code in this file is deliberately extra-verbose, meant for learning.&quot;&quot;&quot;</span>
+
+<span class="c"># The basics to get you going:</span>
+
+<span class="c"># IPython sets the __IPYTHON__ variable so you can know if you have nested</span>
+<span class="c"># copies running.</span>
+
+<span class="c"># Try running this code both at the command line and from inside IPython (with</span>
+<span class="c"># %run example-embed.py)</span>
+<span class="k">try</span><span class="p">:</span>
+ <span class="n">__IPYTHON__</span>
+<span class="k">except</span> <span class="ne">NameError</span><span class="p">:</span>
+ <span class="n">nested</span> <span class="o">=</span> <span class="mf">0</span>
+ <span class="n">args</span> <span class="o">=</span> <span class="p">[</span><span class="s">&#39;&#39;</span><span class="p">]</span>
+<span class="k">else</span><span class="p">:</span>
+ <span class="k">print</span> <span class="s">&quot;Running nested copies of IPython.&quot;</span>
+ <span class="k">print</span> <span class="s">&quot;The prompts for the nested copy have been modified&quot;</span>
+ <span class="n">nested</span> <span class="o">=</span> <span class="mf">1</span>
+ <span class="c"># what the embedded instance will see as sys.argv:</span>
+ <span class="n">args</span> <span class="o">=</span> <span class="p">[</span><span class="s">&#39;-pi1&#39;</span><span class="p">,</span><span class="s">&#39;In &lt;</span><span class="se">\\</span><span class="s">#&gt;: &#39;</span><span class="p">,</span><span class="s">&#39;-pi2&#39;</span><span class="p">,</span><span class="s">&#39; .</span><span class="se">\\</span><span class="s">D.: &#39;</span><span class="p">,</span>
+ <span class="s">&#39;-po&#39;</span><span class="p">,</span><span class="s">&#39;Out&lt;</span><span class="se">\\</span><span class="s">#&gt;: &#39;</span><span class="p">,</span><span class="s">&#39;-nosep&#39;</span><span class="p">]</span>
+
+<span class="c"># First import the embeddable shell class</span>
+<span class="k">from</span> <span class="nn">IPython.Shell</span> <span class="k">import</span> <span class="n">IPShellEmbed</span>
+
+<span class="c"># Now create an instance of the embeddable shell. The first argument is a</span>
+<span class="c"># string with options exactly as you would type them if you were starting</span>
+<span class="c"># IPython at the system command line. Any parameters you want to define for</span>
+<span class="c"># configuration can thus be specified here.</span>
+<span class="n">ipshell</span> <span class="o">=</span> <span class="n">IPShellEmbed</span><span class="p">(</span><span class="n">args</span><span class="p">,</span>
+ <span class="n">banner</span> <span class="o">=</span> <span class="s">&#39;Dropping into IPython&#39;</span><span class="p">,</span>
+ <span class="n">exit_msg</span> <span class="o">=</span> <span class="s">&#39;Leaving Interpreter, back to program.&#39;</span><span class="p">)</span>
+
+<span class="c"># Make a second instance, you can have as many as you want.</span>
+<span class="k">if</span> <span class="n">nested</span><span class="p">:</span>
+ <span class="n">args</span><span class="p">[</span><span class="mf">1</span><span class="p">]</span> <span class="o">=</span> <span class="s">&#39;In2&lt;</span><span class="se">\\</span><span class="s">#&gt;&#39;</span>
+<span class="k">else</span><span class="p">:</span>
+ <span class="n">args</span> <span class="o">=</span> <span class="p">[</span><span class="s">&#39;-pi1&#39;</span><span class="p">,</span><span class="s">&#39;In2&lt;</span><span class="se">\\</span><span class="s">#&gt;: &#39;</span><span class="p">,</span><span class="s">&#39;-pi2&#39;</span><span class="p">,</span><span class="s">&#39; .</span><span class="se">\\</span><span class="s">D.: &#39;</span><span class="p">,</span>
+ <span class="s">&#39;-po&#39;</span><span class="p">,</span><span class="s">&#39;Out&lt;</span><span class="se">\\</span><span class="s">#&gt;: &#39;</span><span class="p">,</span><span class="s">&#39;-nosep&#39;</span><span class="p">]</span>
+<span class="n">ipshell2</span> <span class="o">=</span> <span class="n">IPShellEmbed</span><span class="p">(</span><span class="n">args</span><span class="p">,</span><span class="n">banner</span> <span class="o">=</span> <span class="s">&#39;Second IPython instance.&#39;</span><span class="p">)</span>
+
+<span class="k">print</span> <span class="s">&#39;</span><span class="se">\n</span><span class="s">Hello. This is printed from the main controller program.</span><span class="se">\n</span><span class="s">&#39;</span>
+
+<span class="c"># You can then call ipshell() anywhere you need it (with an optional</span>
+<span class="c"># message):</span>
+<span class="n">ipshell</span><span class="p">(</span><span class="s">&#39;***Called from top level. &#39;</span>
+ <span class="s">&#39;Hit Ctrl-D to exit interpreter and continue program.</span><span class="se">\n</span><span class="s">&#39;</span>
+ <span class="s">&#39;Note that if you use %kill_embedded, you can fully deactivate</span><span class="se">\n</span><span class="s">&#39;</span>
+ <span class="s">&#39;This embedded instance so it will never turn on again&#39;</span><span class="p">)</span>
+
+<span class="k">print</span> <span class="s">&#39;</span><span class="se">\n</span><span class="s">Back in caller program, moving along...</span><span class="se">\n</span><span class="s">&#39;</span>
+
+<span class="c">#---------------------------------------------------------------------------</span>
+<span class="c"># More details:</span>
+
+<span class="c"># IPShellEmbed instances don&#39;t print the standard system banner and</span>
+<span class="c"># messages. The IPython banner (which actually may contain initialization</span>
+<span class="c"># messages) is available as &lt;instance&gt;.IP.BANNER in case you want it.</span>
+
+<span class="c"># IPShellEmbed instances print the following information everytime they</span>
+<span class="c"># start:</span>
+
+<span class="c"># - A global startup banner.</span>
+
+<span class="c"># - A call-specific header string, which you can use to indicate where in the</span>
+<span class="c"># execution flow the shell is starting.</span>
+
+<span class="c"># They also print an exit message every time they exit.</span>
+
+<span class="c"># Both the startup banner and the exit message default to None, and can be set</span>
+<span class="c"># either at the instance constructor or at any other time with the</span>
+<span class="c"># set_banner() and set_exit_msg() methods.</span>
+
+<span class="c"># The shell instance can be also put in &#39;dummy&#39; mode globally or on a per-call</span>
+<span class="c"># basis. This gives you fine control for debugging without having to change</span>
+<span class="c"># code all over the place.</span>
+
+<span class="c"># The code below illustrates all this.</span>
+
+
+<span class="c"># This is how the global banner and exit_msg can be reset at any point</span>
+<span class="n">ipshell</span><span class="o">.</span><span class="n">set_banner</span><span class="p">(</span><span class="s">&#39;Entering interpreter - New Banner&#39;</span><span class="p">)</span>
+<span class="n">ipshell</span><span class="o">.</span><span class="n">set_exit_msg</span><span class="p">(</span><span class="s">&#39;Leaving interpreter - New exit_msg&#39;</span><span class="p">)</span>
+
+<span class="k">def</span> <span class="nf">foo</span><span class="p">(</span><span class="n">m</span><span class="p">):</span>
+ <span class="n">s</span> <span class="o">=</span> <span class="s">&#39;spam&#39;</span>
+ <span class="n">ipshell</span><span class="p">(</span><span class="s">&#39;***In foo(). Try @whos, or print s or m:&#39;</span><span class="p">)</span>
+ <span class="k">print</span> <span class="s">&#39;foo says m = &#39;</span><span class="p">,</span><span class="n">m</span>
+
+<span class="k">def</span> <span class="nf">bar</span><span class="p">(</span><span class="n">n</span><span class="p">):</span>
+ <span class="n">s</span> <span class="o">=</span> <span class="s">&#39;eggs&#39;</span>
+ <span class="n">ipshell</span><span class="p">(</span><span class="s">&#39;***In bar(). Try @whos, or print s or n:&#39;</span><span class="p">)</span>
+ <span class="k">print</span> <span class="s">&#39;bar says n = &#39;</span><span class="p">,</span><span class="n">n</span>
+
+<span class="c"># Some calls to the above functions which will trigger IPython:</span>
+<span class="k">print</span> <span class="s">&#39;Main program calling foo(&quot;eggs&quot;)</span><span class="se">\n</span><span class="s">&#39;</span>
+<span class="n">foo</span><span class="p">(</span><span class="s">&#39;eggs&#39;</span><span class="p">)</span>
+
+<span class="c"># The shell can be put in &#39;dummy&#39; mode where calls to it silently return. This</span>
+<span class="c"># allows you, for example, to globally turn off debugging for a program with a</span>
+<span class="c"># single call.</span>
+<span class="n">ipshell</span><span class="o">.</span><span class="n">set_dummy_mode</span><span class="p">(</span><span class="mf">1</span><span class="p">)</span>
+<span class="k">print</span> <span class="s">&#39;</span><span class="se">\n</span><span class="s">Trying to call IPython which is now &quot;dummy&quot;:&#39;</span>
+<span class="n">ipshell</span><span class="p">()</span>
+<span class="k">print</span> <span class="s">&#39;Nothing happened...&#39;</span>
+<span class="c"># The global &#39;dummy&#39; mode can still be overridden for a single call</span>
+<span class="k">print</span> <span class="s">&#39;</span><span class="se">\n</span><span class="s">Overriding dummy mode manually:&#39;</span>
+<span class="n">ipshell</span><span class="p">(</span><span class="n">dummy</span><span class="o">=</span><span class="mf">0</span><span class="p">)</span>
+
+<span class="c"># Reactivate the IPython shell</span>
+<span class="n">ipshell</span><span class="o">.</span><span class="n">set_dummy_mode</span><span class="p">(</span><span class="mf">0</span><span class="p">)</span>
+
+<span class="k">print</span> <span class="s">&#39;You can even have multiple embedded instances:&#39;</span>
+<span class="n">ipshell2</span><span class="p">()</span>
+
+<span class="k">print</span> <span class="s">&#39;</span><span class="se">\n</span><span class="s">Main program calling bar(&quot;spam&quot;)</span><span class="se">\n</span><span class="s">&#39;</span>
+<span class="n">bar</span><span class="p">(</span><span class="s">&#39;spam&#39;</span><span class="p">)</span>
+
+<span class="k">print</span> <span class="s">&#39;Main program finished. Bye!&#39;</span>
+
+<span class="c">#********************** End of file &lt;example-embed.py&gt; ***********************</span>
+</pre></div>
+</div>
+<p>Once you understand how the system functions, you can use the following
+code fragments in your programs which are ready for cut and paste:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="sd">&quot;&quot;&quot;Quick code snippets for embedding IPython into other programs.</span>
+
+<span class="sd">See example-embed.py for full details, this file has the bare minimum code for</span>
+<span class="sd">cut and paste use once you understand how to use the system.&quot;&quot;&quot;</span>
+
+<span class="c">#---------------------------------------------------------------------------</span>
+<span class="c"># This code loads IPython but modifies a few things if it detects it&#39;s running</span>
+<span class="c"># embedded in another IPython session (helps avoid confusion)</span>
+
+<span class="k">try</span><span class="p">:</span>
+ <span class="n">__IPYTHON__</span>
+<span class="k">except</span> <span class="ne">NameError</span><span class="p">:</span>
+ <span class="n">argv</span> <span class="o">=</span> <span class="p">[</span><span class="s">&#39;&#39;</span><span class="p">]</span>
+ <span class="n">banner</span> <span class="o">=</span> <span class="n">exit_msg</span> <span class="o">=</span> <span class="s">&#39;&#39;</span>
+<span class="k">else</span><span class="p">:</span>
+ <span class="c"># Command-line options for IPython (a list like sys.argv)</span>
+ <span class="n">argv</span> <span class="o">=</span> <span class="p">[</span><span class="s">&#39;-pi1&#39;</span><span class="p">,</span><span class="s">&#39;In &lt;</span><span class="se">\\</span><span class="s">#&gt;:&#39;</span><span class="p">,</span><span class="s">&#39;-pi2&#39;</span><span class="p">,</span><span class="s">&#39; .</span><span class="se">\\</span><span class="s">D.:&#39;</span><span class="p">,</span><span class="s">&#39;-po&#39;</span><span class="p">,</span><span class="s">&#39;Out&lt;</span><span class="se">\\</span><span class="s">#&gt;:&#39;</span><span class="p">]</span>
+ <span class="n">banner</span> <span class="o">=</span> <span class="s">&#39;*** Nested interpreter ***&#39;</span>
+ <span class="n">exit_msg</span> <span class="o">=</span> <span class="s">&#39;*** Back in main IPython ***&#39;</span>
+
+<span class="c"># First import the embeddable shell class</span>
+<span class="k">from</span> <span class="nn">IPython.Shell</span> <span class="k">import</span> <span class="n">IPShellEmbed</span>
+<span class="c"># Now create the IPython shell instance. Put ipshell() anywhere in your code</span>
+<span class="c"># where you want it to open.</span>
+<span class="n">ipshell</span> <span class="o">=</span> <span class="n">IPShellEmbed</span><span class="p">(</span><span class="n">argv</span><span class="p">,</span><span class="n">banner</span><span class="o">=</span><span class="n">banner</span><span class="p">,</span><span class="n">exit_msg</span><span class="o">=</span><span class="n">exit_msg</span><span class="p">)</span>
+
+<span class="c">#---------------------------------------------------------------------------</span>
+<span class="c"># This code will load an embeddable IPython shell always with no changes for</span>
+<span class="c"># nested embededings.</span>
+
+<span class="k">from</span> <span class="nn">IPython.Shell</span> <span class="k">import</span> <span class="n">IPShellEmbed</span>
+<span class="n">ipshell</span> <span class="o">=</span> <span class="n">IPShellEmbed</span><span class="p">()</span>
+<span class="c"># Now ipshell() will open IPython anywhere in the code.</span>
+
+<span class="c">#---------------------------------------------------------------------------</span>
+<span class="c"># This code loads an embeddable shell only if NOT running inside</span>
+<span class="c"># IPython. Inside IPython, the embeddable shell variable ipshell is just a</span>
+<span class="c"># dummy function.</span>
+
+<span class="k">try</span><span class="p">:</span>
+ <span class="n">__IPYTHON__</span>
+<span class="k">except</span> <span class="ne">NameError</span><span class="p">:</span>
+ <span class="k">from</span> <span class="nn">IPython.Shell</span> <span class="k">import</span> <span class="n">IPShellEmbed</span>
+ <span class="n">ipshell</span> <span class="o">=</span> <span class="n">IPShellEmbed</span><span class="p">()</span>
+ <span class="c"># Now ipshell() will open IPython anywhere in the code</span>
+<span class="k">else</span><span class="p">:</span>
+ <span class="c"># Define a dummy ipshell() so the same code doesn&#39;t crash inside an</span>
+ <span class="c"># interactive IPython</span>
+ <span class="k">def</span> <span class="nf">ipshell</span><span class="p">():</span> <span class="k">pass</span>
+
+<span class="c">#******************* End of file &lt;example-embed-short.py&gt; ********************</span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="using-the-python-debugger-pdb">
+<h2>Using the Python debugger (pdb)<a class="headerlink" href="#using-the-python-debugger-pdb" title="Permalink to this headline">¶</a></h2>
+<div class="section" id="running-entire-programs-via-pdb">
+<h3>Running entire programs via pdb<a class="headerlink" href="#running-entire-programs-via-pdb" title="Permalink to this headline">¶</a></h3>
+<p>pdb, the Python debugger, is a powerful interactive debugger which
+allows you to step through code, set breakpoints, watch variables,
+etc. IPython makes it very easy to start any script under the control
+of pdb, regardless of whether you have wrapped it into a &#8216;main()&#8217;
+function or not. For this, simply type &#8216;%run -d myscript&#8217; at an
+IPython prompt. See the %run command&#8217;s documentation (via &#8216;%run?&#8217; or
+in Sec. <a class="reference internal" href="#magic">magic</a> for more details, including how to control where pdb
+will stop execution first.</p>
+<p>For more information on the use of the pdb debugger, read the included
+pdb.doc file (part of the standard Python distribution). On a stock
+Linux system it is located at /usr/lib/python2.3/pdb.doc, but the
+easiest way to read it is by using the help() function of the pdb module
+as follows (in an IPython prompt):</p>
+<p>In [1]: import pdb
+In [2]: pdb.help()</p>
+<p>This will load the pdb.doc document in a file viewer for you automatically.</p>
+</div>
+<div class="section" id="automatic-invocation-of-pdb-on-exceptions">
+<h3>Automatic invocation of pdb on exceptions<a class="headerlink" href="#automatic-invocation-of-pdb-on-exceptions" title="Permalink to this headline">¶</a></h3>
+<p>IPython, if started with the -pdb option (or if the option is set in
+your rc file) can call the Python pdb debugger every time your code
+triggers an uncaught exception. This feature
+can also be toggled at any time with the %pdb magic command. This can be
+extremely useful in order to find the origin of subtle bugs, because pdb
+opens up at the point in your code which triggered the exception, and
+while your program is at this point &#8216;dead&#8217;, all the data is still
+available and you can walk up and down the stack frame and understand
+the origin of the problem.</p>
+<p>Furthermore, you can use these debugging facilities both with the
+embedded IPython mode and without IPython at all. For an embedded shell
+(see sec. <a class="reference internal" href="#embedding">Embedding</a>), simply call the constructor with
+&#8216;-pdb&#8217; in the argument string and automatically pdb will be called if an
+uncaught exception is triggered by your code.</p>
+<p>For stand-alone use of the feature in your programs which do not use
+IPython at all, put the following lines toward the top of your &#8216;main&#8217;
+routine:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="k">import</span> <span class="nn">sys</span><span class="o">,</span><span class="nn">IPython.ultraTB</span>
+<span class="n">sys</span><span class="o">.</span><span class="n">excepthook</span> <span class="o">=</span> <span class="n">IPython</span><span class="o">.</span><span class="n">ultraTB</span><span class="o">.</span><span class="n">FormattedTB</span><span class="p">(</span><span class="n">mode</span><span class="o">=</span><span class="s">&#39;Verbose&#39;</span><span class="p">,</span>
+<span class="n">color_scheme</span><span class="o">=</span><span class="s">&#39;Linux&#39;</span><span class="p">,</span> <span class="n">call_pdb</span><span class="o">=</span><span class="mf">1</span><span class="p">)</span>
+</pre></div>
+</div>
+<p>The mode keyword can be either &#8216;Verbose&#8217; or &#8216;Plain&#8217;, giving either very
+detailed or normal tracebacks respectively. The color_scheme keyword can
+be one of &#8216;NoColor&#8217;, &#8216;Linux&#8217; (default) or &#8216;LightBG&#8217;. These are the same
+options which can be set in IPython with -colors and -xmode.</p>
+<p>This will give any of your programs detailed, colored tracebacks with
+automatic invocation of pdb.</p>
+</div>
+</div>
+<div class="section" id="extensions-for-syntax-processing">
+<h2>Extensions for syntax processing<a class="headerlink" href="#extensions-for-syntax-processing" title="Permalink to this headline">¶</a></h2>
+<p>This isn&#8217;t for the faint of heart, because the potential for breaking
+things is quite high. But it can be a very powerful and useful feature.
+In a nutshell, you can redefine the way IPython processes the user input
+line to accept new, special extensions to the syntax without needing to
+change any of IPython&#8217;s own code.</p>
+<p>In the IPython/Extensions directory you will find some examples
+supplied, which we will briefly describe now. These can be used &#8216;as is&#8217;
+(and both provide very useful functionality), or you can use them as a
+starting point for writing your own extensions.</p>
+<div class="section" id="pasting-of-code-starting-with-or">
+<h3>Pasting of code starting with &#8216;&gt;&gt;&gt; &#8216; or &#8216;... &#8216;<a class="headerlink" href="#pasting-of-code-starting-with-or" title="Permalink to this headline">¶</a></h3>
+<p>In the python tutorial it is common to find code examples which have
+been taken from real python sessions. The problem with those is that all
+the lines begin with either &#8216;&gt;&gt;&gt; &#8216; or &#8216;... &#8216;, which makes it impossible
+to paste them all at once. One must instead do a line by line manual
+copying, carefully removing the leading extraneous characters.</p>
+<p>This extension identifies those starting characters and removes them
+from the input automatically, so that one can paste multi-line examples
+directly into IPython, saving a lot of time. Please look at the file
+InterpreterPasteInput.py in the IPython/Extensions directory for details
+on how this is done.</p>
+<p>IPython comes with a special profile enabling this feature, called
+tutorial. Simply start IPython via &#8216;ipython -p tutorial&#8217; and the feature
+will be available. In a normal IPython session you can activate the
+feature by importing the corresponding module with:
+In [1]: import IPython.Extensions.InterpreterPasteInput</p>
+<p>The following is a &#8216;screenshot&#8217; of how things work when this extension
+is on, copying an example from the standard tutorial:</p>
+<div class="highlight-python"><pre>IPython profile: tutorial
+
+*** Pasting of code with "&gt;&gt;&gt;" or "..." has been enabled.
+
+In [1]: &gt;&gt;&gt; def fib2(n): # return Fibonacci series up to n
+ ...: ... """Return a list containing the Fibonacci series up to
+n."""
+ ...: ... result = []
+ ...: ... a, b = 0, 1
+ ...: ... while b &lt; n:
+ ...: ... result.append(b) # see below
+ ...: ... a, b = b, a+b
+ ...: ... return result
+ ...:
+
+In [2]: fib2(10)
+Out[2]: [1, 1, 2, 3, 5, 8]</pre>
+</div>
+<p>Note that as currently written, this extension does not recognize
+IPython&#8217;s prompts for pasting. Those are more complicated, since the
+user can change them very easily, they involve numbers and can vary in
+length. One could however extract all the relevant information from the
+IPython instance and build an appropriate regular expression. This is
+left as an exercise for the reader.</p>
+</div>
+<div class="section" id="input-of-physical-quantities-with-units">
+<h3>Input of physical quantities with units<a class="headerlink" href="#input-of-physical-quantities-with-units" title="Permalink to this headline">¶</a></h3>
+<p>The module PhysicalQInput allows a simplified form of input for physical
+quantities with units. This file is meant to be used in conjunction with
+the PhysicalQInteractive module (in the same directory) and
+Physics.PhysicalQuantities from Konrad Hinsen&#8217;s ScientificPython
+(<a class="reference external" href="http://dirac.cnrs-orleans.fr/ScientificPython/">http://dirac.cnrs-orleans.fr/ScientificPython/</a>).</p>
+<p>The Physics.PhysicalQuantities module defines PhysicalQuantity objects,
+but these must be declared as instances of a class. For example, to
+define v as a velocity of 3 m/s, normally you would write:</p>
+<div class="highlight-python"><pre>In [1]: v = PhysicalQuantity(3,'m/s')</pre>
+</div>
+<p>Using the PhysicalQ_Input extension this can be input instead as:
+In [1]: v = 3 m/s
+which is much more convenient for interactive use (even though it is
+blatantly invalid Python syntax).</p>
+<p>The physics profile supplied with IPython (enabled via &#8216;ipython -p
+physics&#8217;) uses these extensions, which you can also activate with:</p>
+<p>from math import * # math MUST be imported BEFORE PhysicalQInteractive
+from IPython.Extensions.PhysicalQInteractive import *
+import IPython.Extensions.PhysicalQInput</p>
+</div>
+</div>
+<div class="section" id="threading-support">
+<h2>Threading support<a class="headerlink" href="#threading-support" title="Permalink to this headline">¶</a></h2>
+<p>WARNING: The threading support is still somewhat experimental, and it
+has only seen reasonable testing under Linux. Threaded code is
+particularly tricky to debug, and it tends to show extremely
+platform-dependent behavior. Since I only have access to Linux machines,
+I will have to rely on user&#8217;s experiences and assistance for this area
+of IPython to improve under other platforms.</p>
+<p>IPython, via the -gthread , -qthread, -q4thread and -wthread options
+(described in Sec. <a class="reference internal" href="#threading-options">Threading options</a>), can run in
+multithreaded mode to support pyGTK, Qt3, Qt4 and WXPython applications
+respectively. These GUI toolkits need to control the python main loop of
+execution, so under a normal Python interpreter, starting a pyGTK, Qt3,
+Qt4 or WXPython application will immediately freeze the shell.</p>
+<p>IPython, with one of these options (you can only use one at a time),
+separates the graphical loop and IPython&#8217;s code execution run into
+different threads. This allows you to test interactively (with %run, for
+example) your GUI code without blocking.</p>
+<p>A nice mini-tutorial on using IPython along with the Qt Designer
+application is available at the SciPy wiki:
+<a class="reference external" href="http://www.scipy.org/Cookbook/Matplotlib/Qt_with_IPython_and_Designer">http://www.scipy.org/Cookbook/Matplotlib/Qt_with_IPython_and_Designer</a>.</p>
+<div class="section" id="tk-issues">
+<h3>Tk issues<a class="headerlink" href="#tk-issues" title="Permalink to this headline">¶</a></h3>
+<p>As indicated in Sec. <a class="reference internal" href="#threading-options">Threading options</a>, a special -tk option is
+provided to try and allow Tk graphical applications to coexist
+interactively with WX, Qt or GTK ones. Whether this works at all,
+however, is very platform and configuration dependent. Please
+experiment with simple test cases before committing to using this
+combination of Tk and GTK/Qt/WX threading in a production environment.</p>
+</div>
+<div class="section" id="i-o-pitfalls">
+<h3>I/O pitfalls<a class="headerlink" href="#i-o-pitfalls" title="Permalink to this headline">¶</a></h3>
+<p>Be mindful that the Python interpreter switches between threads every
+$N$ bytecodes, where the default value as of Python 2.3 is $N=100.$ This
+value can be read by using the sys.getcheckinterval() function, and it
+can be reset via sys.setcheckinterval(N). This switching of threads can
+cause subtly confusing effects if one of your threads is doing file I/O.
+In text mode, most systems only flush file buffers when they encounter a
+&#8216;n&#8217;. An instruction as simple as:</p>
+<div class="highlight-python"><pre>print &gt;&gt; filehandle, ''hello world''</pre>
+</div>
+<p>actually consists of several bytecodes, so it is possible that the
+newline does not reach your file before the next thread switch.
+Similarly, if you are writing to a file in binary mode, the file won&#8217;t
+be flushed until the buffer fills, and your other thread may see
+apparently truncated files.</p>
+<p>For this reason, if you are using IPython&#8217;s thread support and have (for
+example) a GUI application which will read data generated by files
+written to from the IPython thread, the safest approach is to open all
+of your files in unbuffered mode (the third argument to the file/open
+function is the buffering value):</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="n">filehandle</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span><span class="n">mode</span><span class="p">,</span><span class="mf">0</span><span class="p">)</span>
+</pre></div>
+</div>
+<p>This is obviously a brute force way of avoiding race conditions with the
+file buffering. If you want to do it cleanly, and you have a resource
+which is being shared by the interactive IPython loop and your GUI
+thread, you should really handle it with thread locking and
+syncrhonization properties. The Python documentation discusses these.</p>
+</div>
+</div>
+<div class="section" id="interactive-demos-with-ipython">
+<span id="interactive-demos"></span><h2>Interactive demos with IPython<a class="headerlink" href="#interactive-demos-with-ipython" title="Permalink to this headline">¶</a></h2>
+<p>IPython ships with a basic system for running scripts interactively in
+sections, useful when presenting code to audiences. A few tags embedded
+in comments (so that the script remains valid Python code) divide a file
+into separate blocks, and the demo can be run one block at a time, with
+IPython printing (with syntax highlighting) the block before executing
+it, and returning to the interactive prompt after each block. The
+interactive namespace is updated after each block is run with the
+contents of the demo&#8217;s namespace.</p>
+<p>This allows you to show a piece of code, run it and then execute
+interactively commands based on the variables just created. Once you
+want to continue, you simply execute the next block of the demo. The
+following listing shows the markup necessary for dividing a script into
+sections for execution as a demo:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="sd">&quot;&quot;&quot;A simple interactive demo to illustrate the use of IPython&#39;s Demo class.</span>
+
+<span class="sd">Any python script can be run as a demo, but that does little more than showing</span>
+<span class="sd">it on-screen, syntax-highlighted in one shot. If you add a little simple</span>
+<span class="sd">markup, you can stop at specified intervals and return to the ipython prompt,</span>
+<span class="sd">resuming execution later.</span>
+<span class="sd">&quot;&quot;&quot;</span>
+
+<span class="k">print</span> <span class="s">&#39;Hello, welcome to an interactive IPython demo.&#39;</span>
+<span class="k">print</span> <span class="s">&#39;Executing this block should require confirmation before proceeding,&#39;</span>
+<span class="k">print</span> <span class="s">&#39;unless auto_all has been set to true in the demo object&#39;</span>
+
+<span class="c"># The mark below defines a block boundary, which is a point where IPython will</span>
+<span class="c"># stop execution and return to the interactive prompt.</span>
+<span class="c"># Note that in actual interactive execution,</span>
+<span class="c"># &lt;demo&gt; --- stop ---</span>
+
+<span class="n">x</span> <span class="o">=</span> <span class="mf">1</span>
+<span class="n">y</span> <span class="o">=</span> <span class="mf">2</span>
+
+<span class="c"># &lt;demo&gt; --- stop ---</span>
+
+<span class="c"># the mark below makes this block as silent</span>
+<span class="c"># &lt;demo&gt; silent</span>
+
+<span class="k">print</span> <span class="s">&#39;This is a silent block, which gets executed but not printed.&#39;</span>
+
+<span class="c"># &lt;demo&gt; --- stop ---</span>
+<span class="c"># &lt;demo&gt; auto</span>
+<span class="k">print</span> <span class="s">&#39;This is an automatic block.&#39;</span>
+<span class="k">print</span> <span class="s">&#39;It is executed without asking for confirmation, but printed.&#39;</span>
+<span class="n">z</span> <span class="o">=</span> <span class="n">x</span><span class="o">+</span><span class="n">y</span>
+
+<span class="k">print</span> <span class="s">&#39;z=&#39;</span><span class="p">,</span><span class="n">x</span>
+
+<span class="c"># &lt;demo&gt; --- stop ---</span>
+<span class="c"># This is just another normal block.</span>
+<span class="k">print</span> <span class="s">&#39;z is now:&#39;</span><span class="p">,</span> <span class="n">z</span>
+
+<span class="k">print</span> <span class="s">&#39;bye!&#39;</span>
+</pre></div>
+</div>
+<p>In order to run a file as a demo, you must first make a Demo object out
+of it. If the file is named myscript.py, the following code will make a
+demo:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="k">from</span> <span class="nn">IPython.demo</span> <span class="k">import</span> <span class="n">Demo</span>
+
+<span class="n">mydemo</span> <span class="o">=</span> <span class="n">Demo</span><span class="p">(</span><span class="s">&#39;myscript.py&#39;</span><span class="p">)</span>
+</pre></div>
+</div>
+<p>This creates the mydemo object, whose blocks you run one at a time by
+simply calling the object with no arguments. If you have autocall active
+in IPython (the default), all you need to do is type:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="n">mydemo</span>
+</pre></div>
+</div>
+<p>and IPython will call it, executing each block. Demo objects can be
+restarted, you can move forward or back skipping blocks, re-execute the
+last block, etc. Simply use the Tab key on a demo object to see its
+methods, and call &#8216;?&#8217; on them to see their docstrings for more usage
+details. In addition, the demo module itself contains a comprehensive
+docstring, which you can access via:</p>
+<div class="highlight-python"><pre>from IPython import demo
+
+demo?</pre>
+</div>
+<p>Limitations: It is important to note that these demos are limited to
+fairly simple uses. In particular, you can not put division marks in
+indented code (loops, if statements, function definitions, etc.)
+Supporting something like this would basically require tracking the
+internal execution state of the Python interpreter, so only top-level
+divisions are allowed. If you want to be able to open an IPython
+instance at an arbitrary point in a program, you can use IPython&#8217;s
+embedding facilities, described in detail in Sec. 9</p>
+</div>
+<div class="section" id="plotting-with-matplotlib">
+<span id="matplotlib-support"></span><h2>Plotting with matplotlib<a class="headerlink" href="#plotting-with-matplotlib" title="Permalink to this headline">¶</a></h2>
+<p>The matplotlib library (<a class="reference external" href="http://matplotlib.sourceforge.net">http://matplotlib.sourceforge.net</a>
+<a class="reference external" href="http://matplotlib.sourceforge.net">http://matplotlib.sourceforge.net</a>) provides high quality 2D plotting for
+Python. Matplotlib can produce plots on screen using a variety of GUI
+toolkits, including Tk, GTK and WXPython. It also provides a number of
+commands useful for scientific computing, all with a syntax compatible
+with that of the popular Matlab program.</p>
+<p>IPython accepts the special option -pylab (see <a class="reference internal" href="#command-line-options"><em>here</em></a>). This configures it to support matplotlib, honoring
+the settings in the .matplotlibrc file. IPython will detect the user&#8217;s choice
+of matplotlib GUI backend, and automatically select the proper threading model
+to prevent blocking. It also sets matplotlib in interactive mode and modifies
+%run slightly, so that any matplotlib-based script can be executed using %run
+and the final show() command does not block the interactive shell.</p>
+<p>The -pylab option must be given first in order for IPython to configure its
+threading mode. However, you can still issue other options afterwards. This
+allows you to have a matplotlib-based environment customized with additional
+modules using the standard IPython profile mechanism (see <a class="reference external" href="../config/customization.html#profiles"><em>here</em></a>): <tt class="docutils literal"><span class="pre">ipython</span> <span class="pre">-pylab</span> <span class="pre">-p</span> <span class="pre">myprofile</span></tt> will load the profile defined in
+ipythonrc-myprofile after configuring matplotlib.</p>
+</div>
+</div>
+
+
+ </div>
+ </div>
+ </div>
+ <div class="sphinxsidebar">
+ <div class="sphinxsidebarwrapper">
+ <h3><a href="../index.html">Table Of Contents</a></h3>
+ <ul>
+<li><a class="reference external" href="">IPython reference</a><ul>
+<li><a class="reference external" href="#command-line-usage">Command-line usage</a><ul>
+<li><a class="reference external" href="#special-threading-options">Special Threading Options</a></li>
+<li><a class="reference external" href="#regular-options">Regular Options</a></li>
+</ul>
+</li>
+<li><a class="reference external" href="#interactive-use">Interactive use</a><ul>
+<li><a class="reference external" href="#caution-for-windows-users">Caution for Windows users</a></li>
+<li><a class="reference external" href="#magic-command-system">Magic command system</a></li>
+<li><a class="reference external" href="#access-to-the-standard-python-help">Access to the standard Python help</a></li>
+<li><a class="reference external" href="#dynamic-object-information">Dynamic object information</a></li>
+<li><a class="reference external" href="#readline-based-features">Readline-based features</a><ul>
+<li><a class="reference external" href="#command-line-completion">Command line completion</a></li>
+<li><a class="reference external" href="#search-command-history">Search command history</a></li>
+<li><a class="reference external" href="#persistent-command-history-across-sessions">Persistent command history across sessions</a></li>
+<li><a class="reference external" href="#autoindent">Autoindent</a></li>
+<li><a class="reference external" href="#customizing-readline-behavior">Customizing readline behavior</a></li>
+</ul>
+</li>
+<li><a class="reference external" href="#session-logging-and-restoring">Session logging and restoring</a></li>
+<li><a class="reference external" href="#id1">System shell access</a></li>
+<li><a class="reference external" href="#manual-capture-of-command-output">Manual capture of command output</a></li>
+<li><a class="reference external" href="#system-command-aliases">System command aliases</a></li>
+<li><a class="reference external" href="#recursive-reload">Recursive reload</a></li>
+<li><a class="reference external" href="#verbose-and-colored-exception-traceback-printouts">Verbose and colored exception traceback printouts</a></li>
+<li><a class="reference external" href="#input-caching-system">Input caching system</a></li>
+<li><a class="reference external" href="#output-caching-system">Output caching system</a></li>
+<li><a class="reference external" href="#directory-history">Directory history</a></li>
+<li><a class="reference external" href="#automatic-parentheses-and-quotes">Automatic parentheses and quotes</a></li>
+<li><a class="reference external" href="#automatic-parentheses">Automatic parentheses</a></li>
+<li><a class="reference external" href="#automatic-quoting">Automatic quoting</a></li>
+</ul>
+</li>
+<li><a class="reference external" href="#ipython-as-your-default-python-environment">IPython as your default Python environment</a></li>
+<li><a class="reference external" href="#embedding-ipython">Embedding IPython</a></li>
+<li><a class="reference external" href="#using-the-python-debugger-pdb">Using the Python debugger (pdb)</a><ul>
+<li><a class="reference external" href="#running-entire-programs-via-pdb">Running entire programs via pdb</a></li>
+<li><a class="reference external" href="#automatic-invocation-of-pdb-on-exceptions">Automatic invocation of pdb on exceptions</a></li>
+</ul>
+</li>
+<li><a class="reference external" href="#extensions-for-syntax-processing">Extensions for syntax processing</a><ul>
+<li><a class="reference external" href="#pasting-of-code-starting-with-or">Pasting of code starting with &#8216;&gt;&gt;&gt; &#8216; or &#8216;... &#8216;</a></li>
+<li><a class="reference external" href="#input-of-physical-quantities-with-units">Input of physical quantities with units</a></li>
+</ul>
+</li>
+<li><a class="reference external" href="#threading-support">Threading support</a><ul>
+<li><a class="reference external" href="#tk-issues">Tk issues</a></li>
+<li><a class="reference external" href="#i-o-pitfalls">I/O pitfalls</a></li>
+</ul>
+</li>
+<li><a class="reference external" href="#interactive-demos-with-ipython">Interactive demos with IPython</a></li>
+<li><a class="reference external" href="#plotting-with-matplotlib">Plotting with matplotlib</a></li>
+</ul>
+</li>
+</ul>
+
+ <h4>Previous topic</h4>
+ <p class="topless"><a href="tutorial.html" title="previous chapter">Quick IPython tutorial</a></p>
+ <h4>Next topic</h4>
+ <p class="topless"><a href="shell.html" title="next chapter">IPython as a system shell</a></p>
+ <h3>This Page</h3>
+ <ul class="this-page-menu">
+ <li><a href="../_sources/interactive/reference.txt">Show Source</a></li>
+ </ul>
+ <h3>Quick search</h3>
+ <form class="search" action="../search.html" method="get">
+ <input type="text" name="q" size="18" /> <input type="submit" value="Go" />
+ <input type="hidden" name="check_keywords" value="yes" />
+ <input type="hidden" name="area" value="default" />
+ </form>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../modindex.html" title="Global Module Index"
+ accesskey="M">modules</a> |</li>
+ <li class="right" >
+ <a href="shell.html" title="IPython as a system shell"
+ accesskey="N">next</a> |</li>
+ <li class="right" >
+ <a href="tutorial.html" title="Quick IPython tutorial"
+ accesskey="P">previous</a> |</li>
+ <li><a href="../index.html">IPython v0.10 documentation</a> &raquo;</li>
+ <li><a href="index.html" accesskey="U">Using IPython for interactive work</a> &raquo;</li>
+ </ul>
+ </div>
+ <div class="footer">
+ &copy; Copyright 2008, The IPython Development Team.
+ Last updated on Aug 04, 2009.
+ Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 0.5.2.
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/ipythonbook/doc/rel-0.10/html/interactive/shell.html b/help/ipythonbook/doc/rel-0.10/html/interactive/shell.html
new file mode 100644
index 0000000..ac571ba
--- /dev/null
+++ b/help/ipythonbook/doc/rel-0.10/html/interactive/shell.html
@@ -0,0 +1,371 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+ <title>IPython as a system shell &mdash; IPython v0.10 documentation</title>
+ <link rel="stylesheet" href="../_static/default.css" type="text/css" />
+ <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
+ <script type="text/javascript">
+ var DOCUMENTATION_OPTIONS = {
+ URL_ROOT: '../',
+ VERSION: '0.10',
+ COLLAPSE_MODINDEX: false,
+ FILE_SUFFIX: '.html',
+ HAS_SOURCE: true
+ };
+ </script>
+ <script type="text/javascript" src="../_static/jquery.js"></script>
+ <script type="text/javascript" src="../_static/doctools.js"></script>
+ <link rel="top" title="IPython v0.10 documentation" href="../index.html" />
+ <link rel="up" title="Using IPython for interactive work" href="index.html" />
+ <link rel="next" title="IPython extension API" href="extension_api.html" />
+ <link rel="prev" title="IPython reference" href="reference.html" />
+ </head>
+ <body>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../modindex.html" title="Global Module Index"
+ accesskey="M">modules</a> |</li>
+ <li class="right" >
+ <a href="extension_api.html" title="IPython extension API"
+ accesskey="N">next</a> |</li>
+ <li class="right" >
+ <a href="reference.html" title="IPython reference"
+ accesskey="P">previous</a> |</li>
+ <li><a href="../index.html">IPython v0.10 documentation</a> &raquo;</li>
+ <li><a href="index.html" accesskey="U">Using IPython for interactive work</a> &raquo;</li>
+ </ul>
+ </div>
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body">
+
+
+ <div class="section" id="ipython-as-a-system-shell">
+<span id="ipython-as-shell"></span><h1>IPython as a system shell<a class="headerlink" href="#ipython-as-a-system-shell" title="Permalink to this headline">¶</a></h1>
+<div class="section" id="overview">
+<h2>Overview<a class="headerlink" href="#overview" title="Permalink to this headline">¶</a></h2>
+<p>The &#8216;sh&#8217; profile optimizes IPython for system shell usage. Apart from
+certain job control functionality that is present in unix (ctrl+z does
+&#8220;suspend&#8221;), the sh profile should provide you with most of the
+functionality you use daily in system shell, and more. Invoke IPython
+in &#8216;sh&#8217; profile by doing &#8216;ipython -p sh&#8217;, or (in win32) by launching
+the &#8220;pysh&#8221; shortcut in start menu.</p>
+<p>If you want to use the features of sh profile as your defaults (which
+might be a good idea if you use other profiles a lot of the time but
+still want the convenience of sh profile), add <tt class="docutils literal"><span class="pre">import</span> <span class="pre">ipy_profile_sh</span></tt>
+to your ~/.ipython/ipy_user_conf.py.</p>
+<p>The &#8216;sh&#8217; profile is different from the default profile in that:</p>
+<blockquote>
+<ul class="simple">
+<li>Prompt shows the current directory</li>
+<li>Spacing between prompts and input is more compact (no padding with
+empty lines). The startup banner is more compact as well.</li>
+<li>System commands are directly available (in alias table) without
+requesting %rehashx - however, if you install new programs along
+your PATH, you might want to run %rehashx to update the persistent
+alias table</li>
+<li>Macros are stored in raw format by default. That is, instead of
+&#8216;_ip.system(&#8220;cat foo&#8221;), the macro will contain text &#8216;cat foo&#8217;)</li>
+<li>Autocall is in full mode</li>
+<li>Calling &#8220;up&#8221; does &#8220;cd ..&#8221;</li>
+</ul>
+</blockquote>
+<p>The &#8216;sh&#8217; profile is different from the now-obsolete (and unavailable)
+&#8216;pysh&#8217; profile in that:</p>
+<blockquote>
+<ul class="simple">
+<li>&#8216;$$var = command&#8217; and &#8216;$var = command&#8217; syntax is not supported</li>
+<li>anymore. Use &#8216;var = !command&#8217; instead (incidentally, this is</li>
+<li>available in all IPython profiles). Note that !!command <em>will</em></li>
+<li>work.</li>
+</ul>
+</blockquote>
+</div>
+<div class="section" id="aliases">
+<h2>Aliases<a class="headerlink" href="#aliases" title="Permalink to this headline">¶</a></h2>
+<p>All of your $PATH has been loaded as IPython aliases, so you should be
+able to type any normal system command and have it executed. See
+%alias? and %unalias? for details on the alias facilities. See also
+%rehashx? for details on the mechanism used to load $PATH.</p>
+</div>
+<div class="section" id="directory-management">
+<h2>Directory management<a class="headerlink" href="#directory-management" title="Permalink to this headline">¶</a></h2>
+<p>Since each command passed by ipython to the underlying system is executed
+in a subshell which exits immediately, you can NOT use !cd to navigate
+the filesystem.</p>
+<p>IPython provides its own builtin &#8216;%cd&#8217; magic command to move in the
+filesystem (the % is not required with automagic on). It also maintains
+a list of visited directories (use %dhist to see it) and allows direct
+switching to any of them. Type &#8216;cd?&#8217; for more details.</p>
+<p>%pushd, %popd and %dirs are provided for directory stack handling.</p>
+</div>
+<div class="section" id="enabled-extensions">
+<h2>Enabled extensions<a class="headerlink" href="#enabled-extensions" title="Permalink to this headline">¶</a></h2>
+<p>Some extensions, listed below, are enabled as default in this profile.</p>
+<div class="section" id="envpersist">
+<h3>envpersist<a class="headerlink" href="#envpersist" title="Permalink to this headline">¶</a></h3>
+<p>%env can be used to &#8220;remember&#8221; environment variable manipulations. Examples:</p>
+<div class="highlight-python"><pre>%env - Show all environment variables
+%env VISUAL=jed - set VISUAL to jed
+%env PATH+=;/foo - append ;foo to PATH
+%env PATH+=;/bar - also append ;bar to PATH
+%env PATH-=/wbin; - prepend /wbin; to PATH
+%env -d VISUAL - forget VISUAL persistent val
+%env -p - print all persistent env modifications</pre>
+</div>
+</div>
+<div class="section" id="ipy-which">
+<h3>ipy_which<a class="headerlink" href="#ipy-which" title="Permalink to this headline">¶</a></h3>
+<p>%which magic command. Like &#8216;which&#8217; in unix, but knows about ipython aliases.</p>
+<p>Example:</p>
+<div class="highlight-python"><pre>[C:/ipython]|14&gt; %which st
+st -&gt; start .
+[C:/ipython]|15&gt; %which d
+d -&gt; dir /w /og /on
+[C:/ipython]|16&gt; %which cp
+cp -&gt; cp
+ == c:\bin\cp.exe
+c:\bin\cp.exe</pre>
+</div>
+</div>
+<div class="section" id="ipy-app-completers">
+<h3>ipy_app_completers<a class="headerlink" href="#ipy-app-completers" title="Permalink to this headline">¶</a></h3>
+<p>Custom tab completers for some apps like svn, hg, bzr, apt-get. Try &#8216;apt-get install &lt;TAB&gt;&#8217; in debian/ubuntu.</p>
+</div>
+<div class="section" id="ipy-rehashdir">
+<h3>ipy_rehashdir<a class="headerlink" href="#ipy-rehashdir" title="Permalink to this headline">¶</a></h3>
+<p>Allows you to add system command aliases for commands that are not along your path. Let&#8217;s say that you just installed Putty and want to be able to invoke it without adding it to path, you can create the alias for it with rehashdir:</p>
+<div class="highlight-python"><pre>[~]|22&gt; cd c:/opt/PuTTY/
+[c:opt/PuTTY]|23&gt; rehashdir .
+ &lt;23&gt; ['pageant', 'plink', 'pscp', 'psftp', 'putty', 'puttygen', 'unins000']</pre>
+</div>
+<p>Now, you can execute any of those commams directly:</p>
+<div class="highlight-python"><pre>[c:opt/PuTTY]|24&gt; cd
+[~]|25&gt; putty</pre>
+</div>
+<p>(the putty window opens).</p>
+<p>If you want to store the alias so that it will always be available, do &#8216;%store putty&#8217;. If you want to %store all these aliases persistently, just do it in a for loop:</p>
+<div class="highlight-python"><pre>[~]|27&gt; for a in _23:
+ |..&gt; %store $a
+ |..&gt;
+ |..&gt;
+Alias stored: pageant (0, 'c:\\opt\\PuTTY\\pageant.exe')
+Alias stored: plink (0, 'c:\\opt\\PuTTY\\plink.exe')
+Alias stored: pscp (0, 'c:\\opt\\PuTTY\\pscp.exe')
+Alias stored: psftp (0, 'c:\\opt\\PuTTY\\psftp.exe')
+...</pre>
+</div>
+</div>
+<div class="section" id="mglob">
+<h3>mglob<a class="headerlink" href="#mglob" title="Permalink to this headline">¶</a></h3>
+<p>Provide the magic function %mglob, which makes it easier (than the &#8216;find&#8217; command) to collect (possibly recursive) file lists. Examples:</p>
+<div class="highlight-python"><pre>[c:/ipython]|9&gt; mglob *.py
+[c:/ipython]|10&gt; mglob *.py rec:*.txt
+[c:/ipython]|19&gt; workfiles = %mglob !.svn/ !.hg/ !*_Data/ !*.bak rec:.</pre>
+</div>
+<p>Note that the first 2 calls will put the file list in result history (_, _9, _10), and the last one will assign it to &#8216;workfiles&#8217;.</p>
+</div>
+</div>
+<div class="section" id="prompt-customization">
+<h2>Prompt customization<a class="headerlink" href="#prompt-customization" title="Permalink to this headline">¶</a></h2>
+<p>The sh profile uses the following prompt configurations:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="n">o</span><span class="o">.</span><span class="n">prompt_in1</span><span class="o">=</span> <span class="s">r&#39;\C_LightBlue[\C_LightCyan\Y2\C_LightBlue]\C_Green|\#&gt;&#39;</span>
+<span class="n">o</span><span class="o">.</span><span class="n">prompt_in2</span><span class="o">=</span> <span class="s">r&#39;\C_Green|\C_LightGreen\D\C_Green&gt;&#39;</span>
+</pre></div>
+</div>
+<p>You can change the prompt configuration to your liking by editing
+ipy_user_conf.py.</p>
+</div>
+<div class="section" id="string-lists">
+<h2>String lists<a class="headerlink" href="#string-lists" title="Permalink to this headline">¶</a></h2>
+<p>String lists (IPython.genutils.SList) are handy way to process output
+from system commands. They are produced by <tt class="docutils literal"><span class="pre">var</span> <span class="pre">=</span> <span class="pre">!cmd</span></tt> syntax.</p>
+<p>First, we acquire the output of &#8216;ls -l&#8217;:</p>
+<div class="highlight-python"><pre>[Q:doc/examples]|2&gt; lines = !ls -l
+ ==
+['total 23',
+ '-rw-rw-rw- 1 ville None 1163 Sep 30 2006 example-demo.py',
+ '-rw-rw-rw- 1 ville None 1927 Sep 30 2006 example-embed-short.py',
+ '-rwxrwxrwx 1 ville None 4606 Sep 1 17:15 example-embed.py',
+ '-rwxrwxrwx 1 ville None 1017 Sep 30 2006 example-gnuplot.py',
+ '-rwxrwxrwx 1 ville None 339 Jun 11 18:01 extension.py',
+ '-rwxrwxrwx 1 ville None 113 Dec 20 2006 seteditor.py',
+ '-rwxrwxrwx 1 ville None 245 Dec 12 2006 seteditor.pyc']</pre>
+</div>
+<p>Now, let&#8217;s take a look at the contents of &#8216;lines&#8217; (the first number is
+the list element number):</p>
+<div class="highlight-python"><pre>[Q:doc/examples]|3&gt; lines
+ &lt;3&gt; SList (.p, .n, .l, .s, .grep(), .fields() available). Value:
+
+0: total 23
+1: -rw-rw-rw- 1 ville None 1163 Sep 30 2006 example-demo.py
+2: -rw-rw-rw- 1 ville None 1927 Sep 30 2006 example-embed-short.py
+3: -rwxrwxrwx 1 ville None 4606 Sep 1 17:15 example-embed.py
+4: -rwxrwxrwx 1 ville None 1017 Sep 30 2006 example-gnuplot.py
+5: -rwxrwxrwx 1 ville None 339 Jun 11 18:01 extension.py
+6: -rwxrwxrwx 1 ville None 113 Dec 20 2006 seteditor.py
+7: -rwxrwxrwx 1 ville None 245 Dec 12 2006 seteditor.pyc</pre>
+</div>
+<p>Now, let&#8217;s filter out the &#8216;embed&#8217; lines:</p>
+<div class="highlight-python"><pre>[Q:doc/examples]|4&gt; l2 = lines.grep('embed',prune=1)
+[Q:doc/examples]|5&gt; l2
+ &lt;5&gt; SList (.p, .n, .l, .s, .grep(), .fields() available). Value:
+
+0: total 23
+1: -rw-rw-rw- 1 ville None 1163 Sep 30 2006 example-demo.py
+2: -rwxrwxrwx 1 ville None 1017 Sep 30 2006 example-gnuplot.py
+3: -rwxrwxrwx 1 ville None 339 Jun 11 18:01 extension.py
+4: -rwxrwxrwx 1 ville None 113 Dec 20 2006 seteditor.py
+5: -rwxrwxrwx 1 ville None 245 Dec 12 2006 seteditor.pyc</pre>
+</div>
+<p>Now, we want strings having just file names and permissions:</p>
+<div class="highlight-python"><pre>[Q:doc/examples]|6&gt; l2.fields(8,0)
+ &lt;6&gt; SList (.p, .n, .l, .s, .grep(), .fields() available). Value:
+
+0: total
+1: example-demo.py -rw-rw-rw-
+2: example-gnuplot.py -rwxrwxrwx
+3: extension.py -rwxrwxrwx
+4: seteditor.py -rwxrwxrwx
+5: seteditor.pyc -rwxrwxrwx</pre>
+</div>
+<p>Note how the line with &#8216;total&#8217; does not raise IndexError.</p>
+<p>If you want to split these (yielding lists), call fields() without
+arguments:</p>
+<div class="highlight-python"><pre>[Q:doc/examples]|7&gt; _.fields()
+ &lt;7&gt;
+[['total'],
+ ['example-demo.py', '-rw-rw-rw-'],
+ ['example-gnuplot.py', '-rwxrwxrwx'],
+ ['extension.py', '-rwxrwxrwx'],
+ ['seteditor.py', '-rwxrwxrwx'],
+ ['seteditor.pyc', '-rwxrwxrwx']]</pre>
+</div>
+<p>If you want to pass these separated with spaces to a command (typical
+for lists if files), use the .s property:</p>
+<div class="highlight-python"><pre>[Q:doc/examples]|13&gt; files = l2.fields(8).s
+[Q:doc/examples]|14&gt; files
+ &lt;14&gt; 'example-demo.py example-gnuplot.py extension.py seteditor.py seteditor.pyc'
+[Q:doc/examples]|15&gt; ls $files
+example-demo.py example-gnuplot.py extension.py seteditor.py seteditor.pyc</pre>
+</div>
+<p>SLists are inherited from normal python lists, so every list method is
+available:</p>
+<div class="highlight-python"><pre>[Q:doc/examples]|21&gt; lines.append('hey')</pre>
+</div>
+</div>
+<div class="section" id="real-world-example-remove-all-files-outside-version-control">
+<h2>Real world example: remove all files outside version control<a class="headerlink" href="#real-world-example-remove-all-files-outside-version-control" title="Permalink to this headline">¶</a></h2>
+<p>First, capture output of &#8220;hg status&#8221;:</p>
+<div class="highlight-python"><pre>[Q:/ipython]|28&gt; out = !hg status
+ ==
+['M IPython\\Extensions\\ipy_kitcfg.py',
+ 'M IPython\\Extensions\\ipy_rehashdir.py',
+...
+ '? build\\lib\\IPython\\Debugger.py',
+ '? build\\lib\\IPython\\Extensions\\InterpreterExec.py',
+ '? build\\lib\\IPython\\Extensions\\InterpreterPasteInput.py',
+...</pre>
+</div>
+<p>(lines starting with ? are not under version control).</p>
+<div class="highlight-python"><pre>[Q:/ipython]|35&gt; junk = out.grep(r'^\?').fields(1)
+[Q:/ipython]|36&gt; junk
+ &lt;36&gt; SList (.p, .n, .l, .s, .grep(), .fields() availab
+...
+10: build\bdist.win32\winexe\temp\_ctypes.py
+11: build\bdist.win32\winexe\temp\_hashlib.py
+12: build\bdist.win32\winexe\temp\_socket.py</pre>
+</div>
+<p>Now we can just remove these files by doing &#8216;rm $junk.s&#8217;.</p>
+</div>
+<div class="section" id="the-s-n-p-properties">
+<h2>The .s, .n, .p properties<a class="headerlink" href="#the-s-n-p-properties" title="Permalink to this headline">¶</a></h2>
+<p>The &#8216;.s&#8217; property returns one string where lines are separated by
+single space (for convenient passing to system commands). The &#8216;.n&#8217;
+property return one string where the lines are separated by &#8216;n&#8217;
+(i.e. the original output of the function). If the items in string
+list are file names, &#8216;.p&#8217; can be used to get a list of &#8220;path&#8221; objects
+for convenient file manipulation.</p>
+</div>
+</div>
+
+
+ </div>
+ </div>
+ </div>
+ <div class="sphinxsidebar">
+ <div class="sphinxsidebarwrapper">
+ <h3><a href="../index.html">Table Of Contents</a></h3>
+ <ul>
+<li><a class="reference external" href="">IPython as a system shell</a><ul>
+<li><a class="reference external" href="#overview">Overview</a></li>
+<li><a class="reference external" href="#aliases">Aliases</a></li>
+<li><a class="reference external" href="#directory-management">Directory management</a></li>
+<li><a class="reference external" href="#enabled-extensions">Enabled extensions</a><ul>
+<li><a class="reference external" href="#envpersist">envpersist</a></li>
+<li><a class="reference external" href="#ipy-which">ipy_which</a></li>
+<li><a class="reference external" href="#ipy-app-completers">ipy_app_completers</a></li>
+<li><a class="reference external" href="#ipy-rehashdir">ipy_rehashdir</a></li>
+<li><a class="reference external" href="#mglob">mglob</a></li>
+</ul>
+</li>
+<li><a class="reference external" href="#prompt-customization">Prompt customization</a></li>
+<li><a class="reference external" href="#string-lists">String lists</a></li>
+<li><a class="reference external" href="#real-world-example-remove-all-files-outside-version-control">Real world example: remove all files outside version control</a></li>
+<li><a class="reference external" href="#the-s-n-p-properties">The .s, .n, .p properties</a></li>
+</ul>
+</li>
+</ul>
+
+ <h4>Previous topic</h4>
+ <p class="topless"><a href="reference.html" title="previous chapter">IPython reference</a></p>
+ <h4>Next topic</h4>
+ <p class="topless"><a href="extension_api.html" title="next chapter">IPython extension API</a></p>
+ <h3>This Page</h3>
+ <ul class="this-page-menu">
+ <li><a href="../_sources/interactive/shell.txt">Show Source</a></li>
+ </ul>
+ <h3>Quick search</h3>
+ <form class="search" action="../search.html" method="get">
+ <input type="text" name="q" size="18" /> <input type="submit" value="Go" />
+ <input type="hidden" name="check_keywords" value="yes" />
+ <input type="hidden" name="area" value="default" />
+ </form>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../modindex.html" title="Global Module Index"
+ accesskey="M">modules</a> |</li>
+ <li class="right" >
+ <a href="extension_api.html" title="IPython extension API"
+ accesskey="N">next</a> |</li>
+ <li class="right" >
+ <a href="reference.html" title="IPython reference"
+ accesskey="P">previous</a> |</li>
+ <li><a href="../index.html">IPython v0.10 documentation</a> &raquo;</li>
+ <li><a href="index.html" accesskey="U">Using IPython for interactive work</a> &raquo;</li>
+ </ul>
+ </div>
+ <div class="footer">
+ &copy; Copyright 2008, The IPython Development Team.
+ Last updated on Aug 04, 2009.
+ Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 0.5.2.
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/ipythonbook/doc/rel-0.10/html/interactive/tutorial.html b/help/ipythonbook/doc/rel-0.10/html/interactive/tutorial.html
new file mode 100644
index 0000000..c836f62
--- /dev/null
+++ b/help/ipythonbook/doc/rel-0.10/html/interactive/tutorial.html
@@ -0,0 +1,408 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+ <title>Quick IPython tutorial &mdash; IPython v0.10 documentation</title>
+ <link rel="stylesheet" href="../_static/default.css" type="text/css" />
+ <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
+ <script type="text/javascript">
+ var DOCUMENTATION_OPTIONS = {
+ URL_ROOT: '../',
+ VERSION: '0.10',
+ COLLAPSE_MODINDEX: false,
+ FILE_SUFFIX: '.html',
+ HAS_SOURCE: true
+ };
+ </script>
+ <script type="text/javascript" src="../_static/jquery.js"></script>
+ <script type="text/javascript" src="../_static/doctools.js"></script>
+ <link rel="top" title="IPython v0.10 documentation" href="../index.html" />
+ <link rel="up" title="Using IPython for interactive work" href="index.html" />
+ <link rel="next" title="IPython reference" href="reference.html" />
+ <link rel="prev" title="Using IPython for interactive work" href="index.html" />
+ </head>
+ <body>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../modindex.html" title="Global Module Index"
+ accesskey="M">modules</a> |</li>
+ <li class="right" >
+ <a href="reference.html" title="IPython reference"
+ accesskey="N">next</a> |</li>
+ <li class="right" >
+ <a href="index.html" title="Using IPython for interactive work"
+ accesskey="P">previous</a> |</li>
+ <li><a href="../index.html">IPython v0.10 documentation</a> &raquo;</li>
+ <li><a href="index.html" accesskey="U">Using IPython for interactive work</a> &raquo;</li>
+ </ul>
+ </div>
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body">
+
+
+ <div class="section" id="quick-ipython-tutorial">
+<span id="tutorial"></span><h1>Quick IPython tutorial<a class="headerlink" href="#quick-ipython-tutorial" title="Permalink to this headline">¶</a></h1>
+<p>IPython can be used as an improved replacement for the Python prompt,
+and for that you don&#8217;t really need to read any more of this manual. But
+in this section we&#8217;ll try to summarize a few tips on how to make the
+most effective use of it for everyday Python development, highlighting
+things you might miss in the rest of the manual (which is getting long).
+We&#8217;ll give references to parts in the manual which provide more detail
+when appropriate.</p>
+<p>The following article by Jeremy Jones provides an introductory tutorial
+about IPython: <a class="reference external" href="http://www.onlamp.com/pub/a/python/2005/01/27/ipython.html">http://www.onlamp.com/pub/a/python/2005/01/27/ipython.html</a></p>
+<div class="section" id="highlights">
+<h2>Highlights<a class="headerlink" href="#highlights" title="Permalink to this headline">¶</a></h2>
+<div class="section" id="tab-completion">
+<h3>Tab completion<a class="headerlink" href="#tab-completion" title="Permalink to this headline">¶</a></h3>
+<p>TAB-completion, especially for attributes, is a convenient way to explore the
+structure of any object you&#8217;re dealing with. Simply type object_name.&lt;TAB&gt; and
+a list of the object&#8217;s attributes will be printed (see <a class="reference external" href="reference.html#readline"><em>the readline
+section</em></a> for more). Tab completion also works on file and directory
+names, which combined with IPython&#8217;s alias system allows you to do from within
+IPython many of the things you normally would need the system shell for.</p>
+</div>
+<div class="section" id="explore-your-objects">
+<h3>Explore your objects<a class="headerlink" href="#explore-your-objects" title="Permalink to this headline">¶</a></h3>
+<p>Typing object_name? will print all sorts of details about any object,
+including docstrings, function definition lines (for call arguments) and
+constructor details for classes. The magic commands %pdoc, %pdef, %psource
+and %pfile will respectively print the docstring, function definition line,
+full source code and the complete file for any object (when they can be
+found). If automagic is on (it is by default), you don&#8217;t need to type the &#8216;%&#8217;
+explicitly. See <a class="reference external" href="reference.html#dynamic-object-info"><em>this section</em></a> for more.</p>
+</div>
+<div class="section" id="the-run-magic-command">
+<h3>The <cite>%run</cite> magic command<a class="headerlink" href="#the-run-magic-command" title="Permalink to this headline">¶</a></h3>
+<p>The %run magic command allows you to run any python script and load all of its
+data directly into the interactive namespace. Since the file is re-read from
+disk each time, changes you make to it are reflected immediately (in contrast
+to the behavior of import). I rarely use import for code I am testing, relying
+on %run instead. See <a class="reference external" href="reference.html#magic"><em>this section</em></a> for more on this and other
+magic commands, or type the name of any magic command and ? to get details on
+it. See also <a class="reference external" href="reference.html#dreload"><em>this section</em></a> for a recursive reload command. %run
+also has special flags for timing the execution of your scripts (-t) and for
+executing them under the control of either Python&#8217;s pdb debugger (-d) or
+profiler (-p). With all of these, %run can be used as the main tool for
+efficient interactive development of code which you write in your editor of
+choice.</p>
+</div>
+<div class="section" id="debug-a-python-script">
+<h3>Debug a Python script<a class="headerlink" href="#debug-a-python-script" title="Permalink to this headline">¶</a></h3>
+<p>Use the Python debugger, pdb. The %pdb command allows you to toggle on and off
+the automatic invocation of an IPython-enhanced pdb debugger (with coloring,
+tab completion and more) at any uncaught exception. The advantage of this is
+that pdb starts inside the function where the exception occurred, with all data
+still available. You can print variables, see code, execute statements and even
+walk up and down the call stack to track down the true source of the problem
+(which often is many layers in the stack above where the exception gets
+triggered). Running programs with %run and pdb active can be an efficient to
+develop and debug code, in many cases eliminating the need for print statements
+or external debugging tools. I often simply put a 1/0 in a place where I want
+to take a look so that pdb gets called, quickly view whatever variables I need
+to or test various pieces of code and then remove the 1/0. Note also that &#8216;%run
+-d&#8217; activates pdb and automatically sets initial breakpoints for you to step
+through your code, watch variables, etc. The <a class="reference external" href="reference.html#output-caching"><em>output caching section</em></a> has more details.</p>
+</div>
+<div class="section" id="use-the-output-cache">
+<h3>Use the output cache<a class="headerlink" href="#use-the-output-cache" title="Permalink to this headline">¶</a></h3>
+<p>All output results are automatically stored in a global dictionary named Out
+and variables named _1, _2, etc. alias them. For example, the result of input
+line 4 is available either as Out[4] or as _4. Additionally, three variables
+named _, __ and ___ are always kept updated with the for the last three
+results. This allows you to recall any previous result and further use it for
+new calculations. See <a class="reference external" href="reference.html#output-caching"><em>the output caching section</em></a> for
+more.</p>
+</div>
+<div class="section" id="suppress-output">
+<h3>Suppress output<a class="headerlink" href="#suppress-output" title="Permalink to this headline">¶</a></h3>
+<p>Put a &#8216;;&#8217; at the end of a line to suppress the printing of output. This is
+useful when doing calculations which generate long output you are not
+interested in seeing. The _* variables and the Out[] list do get updated with
+the contents of the output, even if it is not printed. You can thus still
+access the generated results this way for further processing.</p>
+</div>
+<div class="section" id="input-cache">
+<h3>Input cache<a class="headerlink" href="#input-cache" title="Permalink to this headline">¶</a></h3>
+<p>A similar system exists for caching input. All input is stored in a global
+list called In , so you can re-execute lines 22 through 28 plus line 34 by
+typing &#8216;exec In[22:29]+In[34]&#8217; (using Python slicing notation). If you need
+to execute the same set of lines often, you can assign them to a macro with
+the %macro function. See <a class="reference external" href="reference.html#input-caching"><em>here</em></a> for more.</p>
+</div>
+<div class="section" id="use-your-input-history">
+<h3>Use your input history<a class="headerlink" href="#use-your-input-history" title="Permalink to this headline">¶</a></h3>
+<p>The %hist command can show you all previous input, without line numbers if
+desired (option -n) so you can directly copy and paste code either back in
+IPython or in a text editor. You can also save all your history by turning on
+logging via %logstart; these logs can later be either reloaded as IPython
+sessions or used as code for your programs.</p>
+</div>
+<div class="section" id="define-your-own-system-aliases">
+<h3>Define your own system aliases<a class="headerlink" href="#define-your-own-system-aliases" title="Permalink to this headline">¶</a></h3>
+<p>Even though IPython gives you access to your system shell via the ! prefix,
+it is convenient to have aliases to the system commands you use most often.
+This allows you to work seamlessly from inside IPython with the same commands
+you are used to in your system shell. IPython comes with some pre-defined
+aliases and a complete system for changing directories, both via a stack (see
+%pushd, %popd and %dhist) and via direct %cd. The latter keeps a history of
+visited directories and allows you to go to any previously visited one.</p>
+</div>
+<div class="section" id="call-system-shell-commands">
+<h3>Call system shell commands<a class="headerlink" href="#call-system-shell-commands" title="Permalink to this headline">¶</a></h3>
+<p>Use Python to manipulate the results of system commands. The &#8216;!!&#8217; special
+syntax, and the %sc and %sx magic commands allow you to capture system output
+into Python variables.</p>
+</div>
+<div class="section" id="use-python-variables-when-calling-the-shell">
+<h3>Use Python variables when calling the shell<a class="headerlink" href="#use-python-variables-when-calling-the-shell" title="Permalink to this headline">¶</a></h3>
+<p>Expand python variables when calling the shell (either via &#8216;!&#8217; and &#8216;!!&#8217; or via
+aliases) by prepending a $ in front of them. You can also expand complete
+python expressions. See <a class="reference external" href="reference.html#system-shell-access"><em>our shell section</em></a> for
+more details.</p>
+</div>
+<div class="section" id="use-profiles">
+<h3>Use profiles<a class="headerlink" href="#use-profiles" title="Permalink to this headline">¶</a></h3>
+<p>Use profiles to maintain different configurations (modules to load, function
+definitions, option settings) for particular tasks. You can then have
+customized versions of IPython for specific purposes. <a class="reference external" href="../config/customization.html#profiles"><em>This section</em></a> has more details.</p>
+</div>
+<div class="section" id="embed-ipython-in-your-programs">
+<h3>Embed IPython in your programs<a class="headerlink" href="#embed-ipython-in-your-programs" title="Permalink to this headline">¶</a></h3>
+<p>A few lines of code are enough to load a complete IPython inside your own
+programs, giving you the ability to work with your data interactively after
+automatic processing has been completed. See <a class="reference external" href="reference.html#embedding"><em>here</em></a> for more.</p>
+</div>
+<div class="section" id="use-the-python-profiler">
+<h3>Use the Python profiler<a class="headerlink" href="#use-the-python-profiler" title="Permalink to this headline">¶</a></h3>
+<p>When dealing with performance issues, the %run command with a -p option
+allows you to run complete programs under the control of the Python profiler.
+The %prun command does a similar job for single Python expressions (like
+function calls).</p>
+</div>
+<div class="section" id="use-ipython-to-present-interactive-demos">
+<h3>Use IPython to present interactive demos<a class="headerlink" href="#use-ipython-to-present-interactive-demos" title="Permalink to this headline">¶</a></h3>
+<p>Use the IPython.demo.Demo class to load any Python script as an interactive
+demo. With a minimal amount of simple markup, you can control the execution of
+the script, stopping as needed. See <a class="reference external" href="reference.html#interactive-demos"><em>here</em></a> for more.</p>
+</div>
+<div class="section" id="run-doctests">
+<h3>Run doctests<a class="headerlink" href="#run-doctests" title="Permalink to this headline">¶</a></h3>
+<p>Run your doctests from within IPython for development and debugging. The
+special %doctest_mode command toggles a mode where the prompt, output and
+exceptions display matches as closely as possible that of the default Python
+interpreter. In addition, this mode allows you to directly paste in code that
+contains leading &#8216;&gt;&gt;&gt;&#8217; prompts, even if they have extra leading whitespace
+(as is common in doctest files). This combined with the &#8216;%history -tn&#8217; call
+to see your translated history (with these extra prompts removed and no line
+numbers) allows for an easy doctest workflow, where you can go from doctest
+to interactive execution to pasting into valid Python code as needed.</p>
+</div>
+</div>
+<div class="section" id="source-code-handling-tips">
+<h2>Source code handling tips<a class="headerlink" href="#source-code-handling-tips" title="Permalink to this headline">¶</a></h2>
+<p>IPython is a line-oriented program, without full control of the
+terminal. Therefore, it doesn&#8217;t support true multiline editing. However,
+it has a number of useful tools to help you in dealing effectively with
+more complex editing.</p>
+<p>The %edit command gives a reasonable approximation of multiline editing,
+by invoking your favorite editor on the spot. IPython will execute the
+code you type in there as if it were typed interactively. Type %edit?
+for the full details on the edit command.</p>
+<p>If you have typed various commands during a session, which you&#8217;d like to
+reuse, IPython provides you with a number of tools. Start by using %hist
+to see your input history, so you can see the line numbers of all input.
+Let us say that you&#8217;d like to reuse lines 10 through 20, plus lines 24
+and 28. All the commands below can operate on these with the syntax:</p>
+<div class="highlight-python"><pre>%command 10-20 24 28</pre>
+</div>
+<p>where the command given can be:</p>
+<blockquote>
+<ul class="simple">
+<li>%macro &lt;macroname&gt;: this stores the lines into a variable which,
+when called at the prompt, re-executes the input. Macros can be
+edited later using &#8216;%edit macroname&#8217;, and they can be stored
+persistently across sessions with &#8216;%store macroname&#8217; (the storage
+system is per-profile). The combination of quick macros,
+persistent storage and editing, allows you to easily refine
+quick-and-dirty interactive input into permanent utilities, always
+available both in IPython and as files for general reuse.</li>
+<li>%edit: this will open a text editor with those lines pre-loaded
+for further modification. It will then execute the resulting
+file&#8217;s contents as if you had typed it at the prompt.</li>
+<li>%save &lt;filename&gt;: this saves the lines directly to a named file on
+disk.</li>
+</ul>
+</blockquote>
+<p>While %macro saves input lines into memory for interactive re-execution,
+sometimes you&#8217;d like to save your input directly to a file. The %save
+magic does this: its input sytnax is the same as %macro, but it saves
+your input directly to a Python file. Note that the %logstart command
+also saves input, but it logs all input to disk (though you can
+temporarily suspend it and reactivate it with %logoff/%logon); %save
+allows you to select which lines of input you need to save.</p>
+</div>
+<div class="section" id="lightweight-version-control">
+<h2>Lightweight &#8216;version control&#8217;<a class="headerlink" href="#lightweight-version-control" title="Permalink to this headline">¶</a></h2>
+<p>When you call %edit with no arguments, IPython opens an empty editor
+with a temporary file, and it returns the contents of your editing
+session as a string variable. Thanks to IPython&#8217;s output caching
+mechanism, this is automatically stored:</p>
+<div class="highlight-python"><pre>In [1]: %edit
+
+IPython will make a temporary file named: /tmp/ipython_edit_yR-HCN.py
+
+Editing... done. Executing edited code...
+
+hello - this is a temporary file
+
+Out[1]: "print 'hello - this is a temporary file'\n"</pre>
+</div>
+<p>Now, if you call &#8216;%edit -p&#8217;, IPython tries to open an editor with the
+same data as the last time you used %edit. So if you haven&#8217;t used %edit
+in the meantime, this same contents will reopen; however, it will be
+done in a new file. This means that if you make changes and you later
+want to find an old version, you can always retrieve it by using its
+output number, via &#8216;%edit _NN&#8217;, where NN is the number of the output
+prompt.</p>
+<p>Continuing with the example above, this should illustrate this idea:</p>
+<div class="highlight-python"><pre>In [2]: edit -p
+
+IPython will make a temporary file named: /tmp/ipython_edit_nA09Qk.py
+
+Editing... done. Executing edited code...
+
+hello - now I made some changes
+
+Out[2]: "print 'hello - now I made some changes'\n"
+
+In [3]: edit _1
+
+IPython will make a temporary file named: /tmp/ipython_edit_gy6-zD.py
+
+Editing... done. Executing edited code...
+
+hello - this is a temporary file
+
+IPython version control at work :)
+
+Out[3]: "print 'hello - this is a temporary file'\nprint 'IPython version control at work :)'\n"</pre>
+</div>
+<p>This section was written after a contribution by Alexander Belchenko on
+the IPython user list.</p>
+</div>
+<div class="section" id="effective-logging">
+<h2>Effective logging<a class="headerlink" href="#effective-logging" title="Permalink to this headline">¶</a></h2>
+<p>A very useful suggestion sent in by Robert Kern follows:</p>
+<p>I recently happened on a nifty way to keep tidy per-project log files. I
+made a profile for my project (which is called &#8220;parkfield&#8221;):</p>
+<div class="highlight-python"><pre>include ipythonrc
+
+# cancel earlier logfile invocation:
+
+logfile ''
+
+execute import time
+
+execute __cmd = '/Users/kern/research/logfiles/parkfield-%s.log rotate'
+
+execute __IP.magic_logstart(__cmd % time.strftime('%Y-%m-%d'))</pre>
+</div>
+<p>I also added a shell alias for convenience:</p>
+<div class="highlight-python"><pre>alias parkfield="ipython -pylab -profile parkfield"</pre>
+</div>
+<p>Now I have a nice little directory with everything I ever type in,
+organized by project and date.</p>
+<p>Contribute your own: If you have your own favorite tip on using IPython
+efficiently for a certain task (especially things which can&#8217;t be done in
+the normal Python interpreter), don&#8217;t hesitate to send it!</p>
+</div>
+</div>
+
+
+ </div>
+ </div>
+ </div>
+ <div class="sphinxsidebar">
+ <div class="sphinxsidebarwrapper">
+ <h3><a href="../index.html">Table Of Contents</a></h3>
+ <ul>
+<li><a class="reference external" href="">Quick IPython tutorial</a><ul>
+<li><a class="reference external" href="#highlights">Highlights</a><ul>
+<li><a class="reference external" href="#tab-completion">Tab completion</a></li>
+<li><a class="reference external" href="#explore-your-objects">Explore your objects</a></li>
+<li><a class="reference external" href="#the-run-magic-command">The <cite>%run</cite> magic command</a></li>
+<li><a class="reference external" href="#debug-a-python-script">Debug a Python script</a></li>
+<li><a class="reference external" href="#use-the-output-cache">Use the output cache</a></li>
+<li><a class="reference external" href="#suppress-output">Suppress output</a></li>
+<li><a class="reference external" href="#input-cache">Input cache</a></li>
+<li><a class="reference external" href="#use-your-input-history">Use your input history</a></li>
+<li><a class="reference external" href="#define-your-own-system-aliases">Define your own system aliases</a></li>
+<li><a class="reference external" href="#call-system-shell-commands">Call system shell commands</a></li>
+<li><a class="reference external" href="#use-python-variables-when-calling-the-shell">Use Python variables when calling the shell</a></li>
+<li><a class="reference external" href="#use-profiles">Use profiles</a></li>
+<li><a class="reference external" href="#embed-ipython-in-your-programs">Embed IPython in your programs</a></li>
+<li><a class="reference external" href="#use-the-python-profiler">Use the Python profiler</a></li>
+<li><a class="reference external" href="#use-ipython-to-present-interactive-demos">Use IPython to present interactive demos</a></li>
+<li><a class="reference external" href="#run-doctests">Run doctests</a></li>
+</ul>
+</li>
+<li><a class="reference external" href="#source-code-handling-tips">Source code handling tips</a></li>
+<li><a class="reference external" href="#lightweight-version-control">Lightweight &#8216;version control&#8217;</a></li>
+<li><a class="reference external" href="#effective-logging">Effective logging</a></li>
+</ul>
+</li>
+</ul>
+
+ <h4>Previous topic</h4>
+ <p class="topless"><a href="index.html" title="previous chapter">Using IPython for interactive work</a></p>
+ <h4>Next topic</h4>
+ <p class="topless"><a href="reference.html" title="next chapter">IPython reference</a></p>
+ <h3>This Page</h3>
+ <ul class="this-page-menu">
+ <li><a href="../_sources/interactive/tutorial.txt">Show Source</a></li>
+ </ul>
+ <h3>Quick search</h3>
+ <form class="search" action="../search.html" method="get">
+ <input type="text" name="q" size="18" /> <input type="submit" value="Go" />
+ <input type="hidden" name="check_keywords" value="yes" />
+ <input type="hidden" name="area" value="default" />
+ </form>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../modindex.html" title="Global Module Index"
+ accesskey="M">modules</a> |</li>
+ <li class="right" >
+ <a href="reference.html" title="IPython reference"
+ accesskey="N">next</a> |</li>
+ <li class="right" >
+ <a href="index.html" title="Using IPython for interactive work"
+ accesskey="P">previous</a> |</li>
+ <li><a href="../index.html">IPython v0.10 documentation</a> &raquo;</li>
+ <li><a href="index.html" accesskey="U">Using IPython for interactive work</a> &raquo;</li>
+ </ul>
+ </div>
+ <div class="footer">
+ &copy; Copyright 2008, The IPython Development Team.
+ Last updated on Aug 04, 2009.
+ Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 0.5.2.
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/ipythonbook/doc/rel-0.10/html/modindex.html b/help/ipythonbook/doc/rel-0.10/html/modindex.html
new file mode 100644
index 0000000..700a139
--- /dev/null
+++ b/help/ipythonbook/doc/rel-0.10/html/modindex.html
@@ -0,0 +1,613 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+ <title>Global Module Index &mdash; IPython v0.10 documentation</title>
+ <link rel="stylesheet" href="_static/default.css" type="text/css" />
+ <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+ <script type="text/javascript">
+ var DOCUMENTATION_OPTIONS = {
+ URL_ROOT: '',
+ VERSION: '0.10',
+ COLLAPSE_MODINDEX: false,
+ FILE_SUFFIX: '.html',
+ HAS_SOURCE: true
+ };
+ </script>
+ <script type="text/javascript" src="_static/jquery.js"></script>
+ <script type="text/javascript" src="_static/doctools.js"></script>
+ <link rel="top" title="IPython v0.10 documentation" href="index.html" />
+
+
+
+ </head>
+ <body>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="" title="Global Module Index"
+ accesskey="M">modules</a> |</li>
+ <li><a href="index.html">IPython v0.10 documentation</a> &raquo;</li>
+ </ul>
+ </div>
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body">
+
+
+ <h1 id="global-module-index">Global Module Index</h1>
+
+
+ <a href="#cap-I"><strong>I</strong></a>
+ <hr/>
+
+ <table width="100%" class="indextable" cellspacing="0" cellpadding="2"><tr class="pcap"><td></td><td>&nbsp;</td><td></td></tr>
+ <tr class="cap"><td></td><td><a name="cap-I"><strong>I</strong></a></td><td></td></tr><tr>
+ <td><img src="_static/minus.png" id="toggle-1"
+ class="toggler" style="display: none" alt="-" /></td>
+ <td>
+ <tt class="xref">IPython</tt></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.background_jobs.html#module-IPython.background_jobs"><tt class="xref">IPython.background_jobs</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.clipboard.html#module-IPython.clipboard"><tt class="xref">IPython.clipboard</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.ColorANSI.html#module-IPython.ColorANSI"><tt class="xref">IPython.ColorANSI</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.completer.html#module-IPython.completer"><tt class="xref">IPython.completer</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.config.api.html#module-IPython.config.api"><tt class="xref">IPython.config.api</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.config.cutils.html#module-IPython.config.cutils"><tt class="xref">IPython.config.cutils</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.ConfigLoader.html#module-IPython.ConfigLoader"><tt class="xref">IPython.ConfigLoader</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.CrashHandler.html#module-IPython.CrashHandler"><tt class="xref">IPython.CrashHandler</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.Debugger.html#module-IPython.Debugger"><tt class="xref">IPython.Debugger</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.deep_reload.html#module-IPython.deep_reload"><tt class="xref">IPython.deep_reload</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.demo.html#module-IPython.demo"><tt class="xref">IPython.demo</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.DPyGetOpt.html#module-IPython.DPyGetOpt"><tt class="xref">IPython.DPyGetOpt</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.dtutils.html#module-IPython.dtutils"><tt class="xref">IPython.dtutils</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.excolors.html#module-IPython.excolors"><tt class="xref">IPython.excolors</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.external.argparse.html#module-IPython.external.argparse"><tt class="xref">IPython.external.argparse</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.external.configobj.html#module-IPython.external.configobj"><tt class="xref">IPython.external.configobj</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.external.guid.html#module-IPython.external.guid"><tt class="xref">IPython.external.guid</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.external.Itpl.html#module-IPython.external.Itpl"><tt class="xref">IPython.external.Itpl</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.external.mglob.html#module-IPython.external.mglob"><tt class="xref">IPython.external.mglob</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.external.path.html#module-IPython.external.path"><tt class="xref">IPython.external.path</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.external.pretty.html#module-IPython.external.pretty"><tt class="xref">IPython.external.pretty</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.external.simplegeneric.html#module-IPython.external.simplegeneric"><tt class="xref">IPython.external.simplegeneric</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.external.validate.html#module-IPython.external.validate"><tt class="xref">IPython.external.validate</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.frontend.asyncfrontendbase.html#module-IPython.frontend.asyncfrontendbase"><tt class="xref">IPython.frontend.asyncfrontendbase</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.frontend.frontendbase.html#module-IPython.frontend.frontendbase"><tt class="xref">IPython.frontend.frontendbase</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.frontend.linefrontendbase.html#module-IPython.frontend.linefrontendbase"><tt class="xref">IPython.frontend.linefrontendbase</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.frontend.prefilterfrontend.html#module-IPython.frontend.prefilterfrontend"><tt class="xref">IPython.frontend.prefilterfrontend</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.frontend.process.pipedprocess.html#module-IPython.frontend.process.pipedprocess"><tt class="xref">IPython.frontend.process.pipedprocess</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.frontend.wx.console_widget.html#module-IPython.frontend.wx.console_widget"><tt class="xref">IPython.frontend.wx.console_widget</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.frontend.wx.ipythonx.html#module-IPython.frontend.wx.ipythonx"><tt class="xref">IPython.frontend.wx.ipythonx</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.frontend.wx.wx_frontend.html#module-IPython.frontend.wx.wx_frontend"><tt class="xref">IPython.frontend.wx.wx_frontend</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.generics.html#module-IPython.generics"><tt class="xref">IPython.generics</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.genutils.html#module-IPython.genutils"><tt class="xref">IPython.genutils</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.gui.wx.ipshell_nonblocking.html#module-IPython.gui.wx.ipshell_nonblocking"><tt class="xref">IPython.gui.wx.ipshell_nonblocking</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.gui.wx.ipython_history.html#module-IPython.gui.wx.ipython_history"><tt class="xref">IPython.gui.wx.ipython_history</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.gui.wx.ipython_view.html#module-IPython.gui.wx.ipython_view"><tt class="xref">IPython.gui.wx.ipython_view</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.gui.wx.thread_ex.html#module-IPython.gui.wx.thread_ex"><tt class="xref">IPython.gui.wx.thread_ex</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.gui.wx.wxIPython.html#module-IPython.gui.wx.wxIPython"><tt class="xref">IPython.gui.wx.wxIPython</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.history.html#module-IPython.history"><tt class="xref">IPython.history</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.hooks.html#module-IPython.hooks"><tt class="xref">IPython.hooks</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.ipapi.html#module-IPython.ipapi"><tt class="xref">IPython.ipapi</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.iplib.html#module-IPython.iplib"><tt class="xref">IPython.iplib</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.ipmaker.html#module-IPython.ipmaker"><tt class="xref">IPython.ipmaker</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.ipstruct.html#module-IPython.ipstruct"><tt class="xref">IPython.ipstruct</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.irunner.html#module-IPython.irunner"><tt class="xref">IPython.irunner</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.Itpl.html#module-IPython.Itpl"><tt class="xref">IPython.Itpl</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.kernel.client.html#module-IPython.kernel.client"><tt class="xref">IPython.kernel.client</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.kernel.clientconnector.html#module-IPython.kernel.clientconnector"><tt class="xref">IPython.kernel.clientconnector</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.kernel.clientinterfaces.html#module-IPython.kernel.clientinterfaces"><tt class="xref">IPython.kernel.clientinterfaces</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.kernel.codeutil.html#module-IPython.kernel.codeutil"><tt class="xref">IPython.kernel.codeutil</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.kernel.contexts.html#module-IPython.kernel.contexts"><tt class="xref">IPython.kernel.contexts</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.kernel.controllerservice.html#module-IPython.kernel.controllerservice"><tt class="xref">IPython.kernel.controllerservice</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.kernel.core.display_formatter.html#module-IPython.kernel.core.display_formatter"><tt class="xref">IPython.kernel.core.display_formatter</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.kernel.core.display_trap.html#module-IPython.kernel.core.display_trap"><tt class="xref">IPython.kernel.core.display_trap</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.kernel.core.error.html#module-IPython.kernel.core.error"><tt class="xref">IPython.kernel.core.error</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.kernel.core.fd_redirector.html#module-IPython.kernel.core.fd_redirector"><tt class="xref">IPython.kernel.core.fd_redirector</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.kernel.core.file_like.html#module-IPython.kernel.core.file_like"><tt class="xref">IPython.kernel.core.file_like</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.kernel.core.history.html#module-IPython.kernel.core.history"><tt class="xref">IPython.kernel.core.history</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.kernel.core.interpreter.html#module-IPython.kernel.core.interpreter"><tt class="xref">IPython.kernel.core.interpreter</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.kernel.core.macro.html#module-IPython.kernel.core.macro"><tt class="xref">IPython.kernel.core.macro</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.kernel.core.magic.html#module-IPython.kernel.core.magic"><tt class="xref">IPython.kernel.core.magic</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.kernel.core.message_cache.html#module-IPython.kernel.core.message_cache"><tt class="xref">IPython.kernel.core.message_cache</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.kernel.core.notification.html#module-IPython.kernel.core.notification"><tt class="xref">IPython.kernel.core.notification</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.kernel.core.output_trap.html#module-IPython.kernel.core.output_trap"><tt class="xref">IPython.kernel.core.output_trap</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.kernel.core.prompts.html#module-IPython.kernel.core.prompts"><tt class="xref">IPython.kernel.core.prompts</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.kernel.core.redirector_output_trap.html#module-IPython.kernel.core.redirector_output_trap"><tt class="xref">IPython.kernel.core.redirector_output_trap</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.kernel.core.sync_traceback_trap.html#module-IPython.kernel.core.sync_traceback_trap"><tt class="xref">IPython.kernel.core.sync_traceback_trap</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.kernel.core.traceback_formatter.html#module-IPython.kernel.core.traceback_formatter"><tt class="xref">IPython.kernel.core.traceback_formatter</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.kernel.core.traceback_trap.html#module-IPython.kernel.core.traceback_trap"><tt class="xref">IPython.kernel.core.traceback_trap</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.kernel.core.util.html#module-IPython.kernel.core.util"><tt class="xref">IPython.kernel.core.util</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.kernel.engineconnector.html#module-IPython.kernel.engineconnector"><tt class="xref">IPython.kernel.engineconnector</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.kernel.enginefc.html#module-IPython.kernel.enginefc"><tt class="xref">IPython.kernel.enginefc</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.kernel.engineservice.html#module-IPython.kernel.engineservice"><tt class="xref">IPython.kernel.engineservice</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.kernel.error.html#module-IPython.kernel.error"><tt class="xref">IPython.kernel.error</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.kernel.fcutil.html#module-IPython.kernel.fcutil"><tt class="xref">IPython.kernel.fcutil</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.kernel.magic.html#module-IPython.kernel.magic"><tt class="xref">IPython.kernel.magic</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.kernel.map.html#module-IPython.kernel.map"><tt class="xref">IPython.kernel.map</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.kernel.mapper.html#module-IPython.kernel.mapper"><tt class="xref">IPython.kernel.mapper</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.kernel.multiengine.html#module-IPython.kernel.multiengine"><tt class="xref">IPython.kernel.multiengine</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.kernel.multiengineclient.html#module-IPython.kernel.multiengineclient"><tt class="xref">IPython.kernel.multiengineclient</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.kernel.multienginefc.html#module-IPython.kernel.multienginefc"><tt class="xref">IPython.kernel.multienginefc</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.kernel.newserialized.html#module-IPython.kernel.newserialized"><tt class="xref">IPython.kernel.newserialized</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.kernel.parallelfunction.html#module-IPython.kernel.parallelfunction"><tt class="xref">IPython.kernel.parallelfunction</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.kernel.pbutil.html#module-IPython.kernel.pbutil"><tt class="xref">IPython.kernel.pbutil</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.kernel.pendingdeferred.html#module-IPython.kernel.pendingdeferred"><tt class="xref">IPython.kernel.pendingdeferred</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.kernel.pickleutil.html#module-IPython.kernel.pickleutil"><tt class="xref">IPython.kernel.pickleutil</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.kernel.scripts.ipcluster.html#module-IPython.kernel.scripts.ipcluster"><tt class="xref">IPython.kernel.scripts.ipcluster</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.kernel.scripts.ipcontroller.html#module-IPython.kernel.scripts.ipcontroller"><tt class="xref">IPython.kernel.scripts.ipcontroller</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.kernel.scripts.ipengine.html#module-IPython.kernel.scripts.ipengine"><tt class="xref">IPython.kernel.scripts.ipengine</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.kernel.task.html#module-IPython.kernel.task"><tt class="xref">IPython.kernel.task</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.kernel.taskclient.html#module-IPython.kernel.taskclient"><tt class="xref">IPython.kernel.taskclient</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.kernel.taskfc.html#module-IPython.kernel.taskfc"><tt class="xref">IPython.kernel.taskfc</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.kernel.twistedutil.html#module-IPython.kernel.twistedutil"><tt class="xref">IPython.kernel.twistedutil</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.kernel.util.html#module-IPython.kernel.util"><tt class="xref">IPython.kernel.util</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.Logger.html#module-IPython.Logger"><tt class="xref">IPython.Logger</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.macro.html#module-IPython.macro"><tt class="xref">IPython.macro</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.Magic.html#module-IPython.Magic"><tt class="xref">IPython.Magic</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.numutils.html#module-IPython.numutils"><tt class="xref">IPython.numutils</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.OInspect.html#module-IPython.OInspect"><tt class="xref">IPython.OInspect</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.OutputTrap.html#module-IPython.OutputTrap"><tt class="xref">IPython.OutputTrap</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.platutils.html#module-IPython.platutils"><tt class="xref">IPython.platutils</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.platutils_dummy.html#module-IPython.platutils_dummy"><tt class="xref">IPython.platutils_dummy</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.platutils_posix.html#module-IPython.platutils_posix"><tt class="xref">IPython.platutils_posix</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.prefilter.html#module-IPython.prefilter"><tt class="xref">IPython.prefilter</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.Prompts.html#module-IPython.Prompts"><tt class="xref">IPython.Prompts</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.PyColorize.html#module-IPython.PyColorize"><tt class="xref">IPython.PyColorize</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.Shell.html#module-IPython.Shell"><tt class="xref">IPython.Shell</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.shellglobals.html#module-IPython.shellglobals"><tt class="xref">IPython.shellglobals</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.strdispatch.html#module-IPython.strdispatch"><tt class="xref">IPython.strdispatch</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.testing.decorator_msim.html#module-IPython.testing.decorator_msim"><tt class="xref">IPython.testing.decorator_msim</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.testing.decorators.html#module-IPython.testing.decorators"><tt class="xref">IPython.testing.decorators</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.testing.decorators_numpy.html#module-IPython.testing.decorators_numpy"><tt class="xref">IPython.testing.decorators_numpy</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.testing.decorators_trial.html#module-IPython.testing.decorators_trial"><tt class="xref">IPython.testing.decorators_trial</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.testing.iptest.html#module-IPython.testing.iptest"><tt class="xref">IPython.testing.iptest</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.testing.mkdoctests.html#module-IPython.testing.mkdoctests"><tt class="xref">IPython.testing.mkdoctests</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.testing.parametric.html#module-IPython.testing.parametric"><tt class="xref">IPython.testing.parametric</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.testing.plugin.dtexample.html#module-IPython.testing.plugin.dtexample"><tt class="xref">IPython.testing.plugin.dtexample</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.testing.plugin.show_refs.html#module-IPython.testing.plugin.show_refs"><tt class="xref">IPython.testing.plugin.show_refs</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.testing.plugin.simple.html#module-IPython.testing.plugin.simple"><tt class="xref">IPython.testing.plugin.simple</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.testing.plugin.test_ipdoctest.html#module-IPython.testing.plugin.test_ipdoctest"><tt class="xref">IPython.testing.plugin.test_ipdoctest</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.testing.plugin.test_refs.html#module-IPython.testing.plugin.test_refs"><tt class="xref">IPython.testing.plugin.test_refs</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.testing.tools.html#module-IPython.testing.tools"><tt class="xref">IPython.testing.tools</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.testing.util.html#module-IPython.testing.util"><tt class="xref">IPython.testing.util</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.tools.growl.html#module-IPython.tools.growl"><tt class="xref">IPython.tools.growl</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.tools.utils.html#module-IPython.tools.utils"><tt class="xref">IPython.tools.utils</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.twshell.html#module-IPython.twshell"><tt class="xref">IPython.twshell</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.ultraTB.html#module-IPython.ultraTB"><tt class="xref">IPython.ultraTB</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.upgrade_dir.html#module-IPython.upgrade_dir"><tt class="xref">IPython.upgrade_dir</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.wildcard.html#module-IPython.wildcard"><tt class="xref">IPython.wildcard</tt></a></td><td>
+ <em></em></td></tr><tr class="cg-1">
+ <td></td>
+ <td>&nbsp;&nbsp;&nbsp;
+ <a href="api/generated/IPython.winconsole.html#module-IPython.winconsole"><tt class="xref">IPython.winconsole</tt></a></td><td>
+ <em></em></td></tr>
+ </table>
+
+
+ </div>
+ </div>
+ </div>
+ <div class="sphinxsidebar">
+ <div class="sphinxsidebarwrapper">
+ <h3>Quick search</h3>
+ <form class="search" action="search.html" method="get">
+ <input type="text" name="q" size="18" /> <input type="submit" value="Go" />
+ <input type="hidden" name="check_keywords" value="yes" />
+ <input type="hidden" name="area" value="default" />
+ </form>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="" title="Global Module Index"
+ accesskey="M">modules</a> |</li>
+ <li><a href="index.html">IPython v0.10 documentation</a> &raquo;</li>
+ </ul>
+ </div>
+ <div class="footer">
+ &copy; Copyright 2008, The IPython Development Team.
+ Last updated on Aug 04, 2009.
+ Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 0.5.2.
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/help/ipythonbook/library/library.info b/help/ipythonbook/library/library.info
new file mode 100644
index 0000000..0cd0912
--- /dev/null
+++ b/help/ipythonbook/library/library.info
@@ -0,0 +1,9 @@
+[Library]
+name = ipythonbook
+global_name = ipythonbook
+long_name = ipythonbook
+category = media
+library_version = 1
+host_version = 1
+l10n = false
+locale = en
diff --git a/help_pd.py b/help_pd.py
new file mode 100644
index 0000000..b74bf3f
--- /dev/null
+++ b/help_pd.py
@@ -0,0 +1,195 @@
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+#
+#NOTE: The webview module shipped with FC11 does a get_Main_window.hide()
+# which makes it unusable in the PyDebug application. A more recent git version
+# toggles the visibility of the gecko engine and is more compatible.
+# The browser.py and webview.py modules included are essential for PyDebug
+#
+import os
+from gettext import gettext as _
+
+import gtk
+import gobject
+
+from sugar.activity import activity
+from sugar.graphics.toolbutton import ToolButton
+
+import hulahop
+hulahop.startup(os.path.join(activity.get_activity_root(), 'data/gecko'))
+from zipfile import ZipFile, ZipInfo
+
+#from hulahop.webview import WebView
+from browser import Browser
+#import xpcom
+#from xpcom.components import interfaces
+
+gobject.threads_init()
+
+#HOME = os.path.join(activity.get_bundle_path(), 'help/index.html')
+#HOME = "http://website.com/something.html"
+
+# Initialize logging.
+import logging
+from sugar import logger
+#Get the standard logging directory.
+_logger = logging.getLogger('PyDebug')
+
+ZIP_SUFFIXES = ['.xol','.zip',]
+sugar_activity_root = os.environ['SUGAR_ACTIVITY_ROOT']
+help_notebook_pages = []
+
+class HelpToolbar(gtk.Toolbar):
+ def __init__(self, parent):
+ gtk.Toolbar.__init__(self)
+ self.help_toolbar_parent = parent
+ self.child_root = os.path.join(os.environ['SUGAR_ACTIVITY_ROOT'],'tmp')
+
+ self._back = ToolButton('go-previous-paired')
+ self._back.set_tooltip(_('Back'))
+ self._back.props.sensitive = False
+ self._back.connect('clicked', self.help_toolbar_parent._go_back_cb)
+ self.insert(self._back, -1)
+ self._back.show()
+
+ self._forward = ToolButton('go-next-paired')
+ self._forward.set_tooltip(_('Forward'))
+ self._forward.props.sensitive = False
+ self._forward.connect('clicked', self.help_toolbar_parent._go_forward_cb)
+ self.insert(self._forward, -1)
+ self._forward.show()
+
+ home = ToolButton('zoom-home')
+ home.set_tooltip(_('Home'))
+ home.connect('clicked', self.help_toolbar_parent._go_home_cb)
+ self.insert(home, -1)
+ home.show()
+
+class Help():
+ current_url_prefix = ''
+ file_changed = False
+ current_web_view = None
+ web_view_list = []
+ def __init__(self, parent):
+ self.pydebug = parent
+ self.url_root = 'file://'+ self.sugar_bundle_path +"/"+_('help/PyDebug.htm')
+ self.help_toolbar = HelpToolbar(self.pydebug)
+ self.help_toolbar.show()
+ self.first_webview = self.new_tab(self.url_root)
+ self.web_view_list.append(self.first_webview)
+ self.current_web_view = self.first_webview
+ translation = self.translate_zip_url(self.url_root)
+ _logger.debug("this is url root: %s"%translation)
+ self.first_webview.load_uri(translation)
+
+ def get_help_toolbar(self):
+ return self.help_toolbar
+
+ def _get_help_canvas(self):
+ nb = gtk.Notebook()
+ nb.show()
+ nb.append_page(self.first_webview)
+ self.help_notebook = nb
+ return nb
+
+ def new_tab(self,url = None):
+ if url == None:
+ url = self.url_root
+ self._web_view = Browser()
+ _logger.debug('loading new tab with url: %s' % url )
+ self._web_view.load_uri(url)
+ self._web_view.connect('destroy',self._web_view.hide)
+ self.current_url = url
+ self._web_view.show()
+ progress_listener = self._web_view.progress
+ progress_listener.connect('location-changed',
+ self._location_changed_cb)
+ progress_listener.connect('loading-stop', self._loading_stop_cb)
+
+ return self._web_view
+
+ def repaint(self):
+ self._web_view.load_uri(self.current_url)
+
+ def get_first_webview(self):
+ return self.first_webview
+
+ def _location_changed_cb(self, progress_listener, uri):
+ myuri=''
+ myuri = str(uri)
+ _logger.debug('location changed callback %s'%(myuri))
+ self.update_navigation_buttons()
+ target = self.translate_zip_url(uri)
+ _logger.debug(' which translated to %s'%(target))
+ #self.current_webview.load_uri(target)
+ uri = target
+
+ def translate_zip_url(self,uri): #string in, string returned
+ #if this file is already unzipped then allow normal processing
+ if os.path.isfile(uri[7:]): #don't want the leading 'file://'
+ return uri
+ #look for the zip suffixes in the uri
+ self.current_url_prefix = ''
+ for pattern in ZIP_SUFFIXES:
+ if uri.find(pattern) > -1:
+ self.current_url_prefix = uri[:uri.find(pattern)] + pattern
+ found_pattern = pattern
+ if self.current_url_prefix == '':
+ return uri
+ _logger.debug('pattern found:%s. Prefix: %s'%(found_pattern,self.current_url_prefix))
+
+ #find the file in the zip, write it somewhere writeable, load this url instead
+ zipfile_name = self.current_url_prefix[7:] #clip off the leading "file:"
+ name_in_zip = uri[len(self.current_url_prefix)+1:]
+ try:
+ zf = ZipFile(zipfile_name,'r')
+ except:
+ _logger.debug('Opening Zip file failed: %s'%zipfile_name)
+ return uri
+ try: #first check to see if this location is already filled
+ dest = os.path.join(sugar_activity_root,'tmp')
+ write_zip_to_here = os.path.join(dest, name_in_zip)
+ if os.path.isfile(write_zip_to_here):
+ return write_zip_to_here
+ else:
+ zf.extract(name_in_zip,dest)
+ _logger.debug('Writing Zip file to %s '%(write_zip_to_here))
+ except:
+ _logger.debug('Extracting Zip file %s to %s failed'%(name_in_zip,dest))
+ #self.current_web_view.load_uri(dest)
+ self.last_file_unzipped = write_zip_to_here
+ url = 'file://' + self.last_file_unzipped
+ uri.replace(url)
+ return(url)
+
+ def _loading_stop_cb(self, progress_listener):
+ self.update_navigation_buttons()
+
+ def update_navigation_buttons(self):
+ can_go_back = self.current_web_view.web_navigation.canGoBack
+ self.help_toolbar._back.props.sensitive = can_go_back
+
+ can_go_forward = self.current_web_view.web_navigation.canGoForward
+ self.help_toolbar._forward.props.sensitive = can_go_forward
+
+ def _go_back_cb(self, button):
+ self.current_web_view.web_navigation.goBack()
+
+ def _go_forward_cb(self, button):
+ self.current_web_view.web_navigation.goForward()
+
+ def _go_home_cb(self, button):
+ self.current_web_view.load_uri(self.url_root)
+
+
diff --git a/history b/history
new file mode 100644
index 0000000..04c982d
--- /dev/null
+++ b/history
@@ -0,0 +1,1000 @@
+q
+go
+ll
+macro
+p go
+p gob
+gob
+go
+gob
+go
+debug
+go
+debug
+p handle
+dir(handle)
+p go
+u
+p sys.argv
+d
+p sys.argv
+d
+l
+p bundle_id
+d
+q
+go
+ll
+macro
+p go
+p gob
+gob
+go
+gob
+go
+debug
+p self.child_path
+who
+p name
+q
+go
+ll
+macro
+p go
+p gob
+gob
+go
+gob
+go
+debug
+go
+debug
+go
+o = _ip.options
+o.xmode
+o.xmode=
+o=_ip.options
+o.xmode='Plain'
+go
+o.xmode
+debug
+who
+gob
+macro
+gb
+o=_ip.options
+o.xmode
+o.xmode='Plain'
+o.xmode
+gb
+gb\
+gb
+who
+debug
+go
+who
+debug
+l
+u
+ed
+q
+go
+ll
+macro
+p go
+p gob
+gob
+go
+gob
+go
+debug
+p self.child_path
+who
+p name
+q
+go
+ll
+macro
+p go
+p gob
+gob
+go
+gob
+go
+debug
+go
+debug
+p handle
+dir(handle)
+p go
+u
+p sys.argv
+d
+p sys.argv
+d
+l
+p bundle_id
+d
+q
+go
+ll
+macro
+p go
+p gob
+gob
+go
+gob
+go
+debug
+p self.child_path
+who
+p name
+q
+go
+ll
+macro
+p go
+p gob
+gob
+go
+gob
+go
+debug
+go
+debug
+go
+o = _ip.options
+o.xmode
+o.xmode=
+o=_ip.options
+o.xmode='Plain'
+go
+o.xmode
+debug
+l
+q
+go
+ll
+macro
+p go
+p gob
+gob
+go
+gob
+go
+debug
+p self.child_path
+who
+p name
+q
+go
+ll
+macro
+p go
+p gob
+gob
+go
+gob
+go
+debug
+go
+debug
+p handle
+dir(handle)
+p go
+u
+p sys.argv
+d
+p sys.argv
+d
+l
+p bundle_id
+d
+q
+go
+ll
+macro
+p go
+p gob
+gob
+go
+gob
+go
+debug
+p self.child_path
+who
+p name
+q
+go
+ll
+macro
+p go
+p gob
+gob
+go
+gob
+go
+debug
+go
+debug
+go
+o = _ip.options
+o.xmode
+o.xmode=
+o=_ip.options
+o.xmode='Plain'
+go
+o.xmode
+debug
+who
+gob
+macro
+gb
+o=_ip.options
+o.xmode
+o.xmode='Plain'
+o.xmode
+gb
+gb\
+gb
+who
+debug
+go
+who
+debug
+who
+debug
+go
+o=-ip.options
+o=_ip.options
+p o.xmode
+go
+p o.xmode
+go
+import gtk.gdk
+dir(gtk.gdk)
+info(gtk.gdk)
+pinfo(gtk.gdk)
+from apihelper import info
+import gtk
+dm = gtk.gdk.DisplayManager
+dm??
+dm?
+dir(dm)
+dl = dm.list_displays
+dl
+dl = dm.list_displays()
+dm.list_displays?
+dm.list_displays??
+hist
+display = dm.get_display()
+display = gtk.gdk.get_display()
+str(display)
+dl = dm.list_displays(':0.0')
+dl = dm.list_displays(dm)
+hist
+dm?
+hist 1-
+hist 10
+go
+debug
+cmd_args
+l
+q
+go
+ll
+macro
+p go
+p gob
+gob
+go
+gob
+go
+debug
+p self.child_path
+who
+p name
+q
+go
+ll
+macro
+p go
+p gob
+gob
+go
+gob
+go
+debug
+go
+debug
+p handle
+dir(handle)
+p go
+u
+p sys.argv
+d
+p sys.argv
+d
+l
+p bundle_id
+d
+q
+go
+ll
+macro
+p go
+p gob
+gob
+go
+gob
+go
+debug
+p self.child_path
+who
+p name
+q
+go
+ll
+macro
+p go
+p gob
+gob
+go
+gob
+go
+debug
+go
+debug
+go
+o = _ip.options
+o.xmode
+o.xmode=
+o=_ip.options
+o.xmode='Plain'
+go
+o.xmode
+debug
+l
+q
+go
+ll
+macro
+p go
+p gob
+gob
+go
+gob
+go
+debug
+p self.child_path
+who
+p name
+q
+go
+ll
+macro
+p go
+p gob
+gob
+go
+gob
+go
+debug
+go
+debug
+p handle
+dir(handle)
+p go
+u
+p sys.argv
+d
+p sys.argv
+d
+l
+p bundle_id
+d
+q
+go
+ll
+macro
+p go
+p gob
+gob
+go
+gob
+go
+debug
+p self.child_path
+who
+p name
+q
+go
+ll
+macro
+p go
+p gob
+gob
+go
+gob
+go
+debug
+go
+debug
+go
+o = _ip.options
+o.xmode
+o.xmode=
+o=_ip.options
+o.xmode='Plain'
+go
+o.xmode
+debug
+who
+gob
+macro
+gb
+o=_ip.options
+o.xmode
+o.xmode='Plain'
+o.xmode
+gb
+gb\
+gb
+who
+debug
+go
+who
+debug
+l
+u
+ed
+q
+go
+ll
+macro
+p go
+p gob
+gob
+go
+gob
+go
+debug
+p self.child_path
+who
+p name
+q
+go
+ll
+macro
+p go
+p gob
+gob
+go
+gob
+go
+debug
+go
+debug
+p handle
+dir(handle)
+p go
+u
+p sys.argv
+d
+p sys.argv
+d
+l
+p bundle_id
+d
+q
+go
+ll
+macro
+p go
+p gob
+gob
+go
+gob
+go
+debug
+p self.child_path
+who
+p name
+q
+go
+ll
+macro
+p go
+p gob
+gob
+go
+gob
+go
+debug
+go
+debug
+go
+o = _ip.options
+o.xmode
+o.xmode=
+o=_ip.options
+o.xmode='Plain'
+go
+o.xmode
+debug
+l
+q
+go
+ll
+macro
+p go
+p gob
+gob
+go
+gob
+go
+debug
+p self.child_path
+who
+p name
+q
+go
+ll
+macro
+p go
+p gob
+gob
+go
+gob
+go
+debug
+go
+debug
+p handle
+dir(handle)
+p go
+u
+p sys.argv
+d
+p sys.argv
+d
+l
+p bundle_id
+d
+q
+go
+ll
+macro
+p go
+p gob
+gob
+go
+gob
+go
+debug
+p self.child_path
+who
+p name
+q
+go
+ll
+macro
+p go
+p gob
+gob
+go
+gob
+go
+debug
+go
+debug
+go
+o = _ip.options
+o.xmode
+o.xmode=
+o=_ip.options
+o.xmode='Plain'
+go
+o.xmode
+debug
+who
+gob
+macro
+gb
+o=_ip.options
+o.xmode
+o.xmode='Plain'
+o.xmode
+gb
+gb\
+gb
+who
+debug
+go
+who
+debug
+who
+debug
+u
+p handle
+dir(handle)
+p handle.object_id
+p handle.activity_id
+u
+p sys.argv
+q
+go
+ll
+macro
+p go
+p gob
+gob
+go
+gob
+go
+debug
+p self.child_path
+who
+p name
+q
+go
+ll
+macro
+p go
+p gob
+gob
+go
+gob
+go
+debug
+go
+debug
+p handle
+dir(handle)
+p go
+u
+p sys.argv
+d
+p sys.argv
+d
+l
+p bundle_id
+d
+q
+go
+ll
+macro
+p go
+p gob
+gob
+go
+gob
+go
+debug
+p self.child_path
+who
+p name
+q
+go
+ll
+macro
+p go
+p gob
+gob
+go
+gob
+go
+debug
+go
+debug
+go
+o = _ip.options
+o.xmode
+o.xmode=
+o=_ip.options
+o.xmode='Plain'
+go
+o.xmode
+debug
+l
+q
+go
+ll
+macro
+p go
+p gob
+gob
+go
+gob
+go
+debug
+p self.child_path
+who
+p name
+q
+go
+ll
+macro
+p go
+p gob
+gob
+go
+gob
+go
+debug
+go
+debug
+p handle
+dir(handle)
+p go
+u
+p sys.argv
+d
+p sys.argv
+d
+l
+p bundle_id
+d
+q
+go
+ll
+macro
+p go
+p gob
+gob
+go
+gob
+go
+debug
+p self.child_path
+who
+p name
+q
+go
+ll
+macro
+p go
+p gob
+gob
+go
+gob
+go
+debug
+go
+debug
+go
+o = _ip.options
+o.xmode
+o.xmode=
+o=_ip.options
+o.xmode='Plain'
+go
+o.xmode
+debug
+who
+gob
+macro
+gb
+o=_ip.options
+o.xmode
+o.xmode='Plain'
+o.xmode
+gb
+gb\
+gb
+who
+debug
+go
+who
+debug
+l
+u
+ed
+q
+go
+ll
+macro
+p go
+p gob
+gob
+go
+gob
+go
+debug
+p self.child_path
+who
+p name
+q
+go
+ll
+macro
+p go
+p gob
+gob
+go
+gob
+go
+debug
+go
+debug
+p handle
+dir(handle)
+p go
+u
+p sys.argv
+d
+p sys.argv
+d
+l
+p bundle_id
+d
+q
+go
+ll
+macro
+p go
+p gob
+gob
+go
+gob
+go
+debug
+p self.child_path
+who
+p name
+q
+go
+ll
+macro
+p go
+p gob
+gob
+go
+gob
+go
+debug
+go
+debug
+go
+o = _ip.options
+o.xmode
+o.xmode=
+o=_ip.options
+o.xmode='Plain'
+go
+o.xmode
+debug
+l
+q
+go
+ll
+macro
+p go
+p gob
+gob
+go
+gob
+go
+debug
+p self.child_path
+who
+p name
+q
+go
+ll
+macro
+p go
+p gob
+gob
+go
+gob
+go
+debug
+go
+debug
+p handle
+dir(handle)
+p go
+u
+p sys.argv
+d
+p sys.argv
+d
+l
+p bundle_id
+d
+q
+go
+ll
+macro
+p go
+p gob
+gob
+go
+gob
+go
+debug
+p self.child_path
+who
+p name
+q
+go
+ll
+macro
+p go
+p gob
+gob
+go
+gob
+go
+debug
+go
+debug
+go
+o = _ip.options
+o.xmode
+o.xmode=
+o=_ip.options
+o.xmode='Plain'
+go
+o.xmode
+debug
+who
+gob
+macro
+gb
+o=_ip.options
+o.xmode
+o.xmode='Plain'
+o.xmode
+gb
+gb\
+gb
+who
+debug
+go
+who
+debug
+who
+debug
+go
+o=-ip.options
+o=_ip.options
+p o.xmode
+go
+p o.xmode
+go
+import gtk.gdk
+dir(gtk.gdk)
+info(gtk.gdk)
+pinfo(gtk.gdk)
+from apihelper import info
+import gtk
+dm = gtk.gdk.DisplayManager
+dm??
+dm?
+dir(dm)
+dl = dm.list_displays
+dl
+dl = dm.list_displays()
+dm.list_displays?
+dm.list_displays??
+hist
+display = dm.get_display()
+display = gtk.gdk.get_display()
+str(display)
+dl = dm.list_displays(':0.0')
+dl = dm.list_displays(dm)
+hist
+dm?
+hist 1-
+hist 10
+go
+debug
+go
+debug
+go
+debug
+go
+g
+go
diff --git a/icons/activity-become-root.svg b/icons/activity-become-root.svg
new file mode 100644
index 0000000..64f256d
--- /dev/null
+++ b/icons/activity-become-root.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" ?><!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd' [
+ <!ENTITY stroke_color "#010101">
+ <!ENTITY fill_color "#FFFFFF">
+]><svg enable-background="new 0 0 55 55" height="55px" version="1.1" viewBox="0 0 55 55" width="55px" x="0px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" y="0px"><g display="block" id="activity-terminal">
+ <rect fill="&fill_color;" height="32.442" stroke="&stroke_color;" stroke-linecap="round" stroke-width="3.5" width="43.457" x="5.646" y="9.404"/>
+ <text fill="#000000;" stroke="&stroke_color;" font-size="18" x="10" y="27">#_</text>
+</g></svg>
diff --git a/ipy_user_conf.py b/ipy_user_conf.py
new file mode 100644
index 0000000..3cc5fbf
--- /dev/null
+++ b/ipy_user_conf.py
@@ -0,0 +1,117 @@
+""" User configuration file for IPython
+
+This is a more flexible and safe way to configure ipython than *rc files
+(ipythonrc, ipythonrc-pysh etc.)
+
+This file is always imported on ipython startup. You can import the
+ipython extensions you need here (see IPython/Extensions directory).
+
+Feel free to edit this file to customize your ipython experience.
+
+Note that as such this file does nothing, for backwards compatibility.
+Consult e.g. file 'ipy_profile_sh.py' for an example of the things
+you can do here.
+
+See http://ipython.scipy.org/moin/IpythonExtensionApi for detailed
+description on what you could do here.
+"""
+
+# Most of your config files and extensions will probably start with this import
+
+import IPython.ipapi
+ip = IPython.ipapi.get()
+
+# You probably want to uncomment this if you did %upgrade -nolegacy
+# import ipy_defaults
+
+import os
+
+def main():
+
+ # uncomment if you want to get ipython -p sh behaviour
+ # without having to use command line switches
+ # import ipy_profile_sh
+
+ # Configure your favourite editor?
+ # Good idea e.g. for %edit os.path.isfile
+
+ #import ipy_editors
+
+ # Choose one of these:
+
+ #ipy_editors.scite()
+ #ipy_editors.scite('c:/opt/scite/scite.exe')
+ #ipy_editors.komodo()
+ #ipy_editors.idle()
+ # ... or many others, try 'ipy_editors??' after import to see them
+
+ # Or roll your own:
+ #ipy_editors.install_editor("c:/opt/jed +$line $file")
+
+
+ o = ip.options
+ # An example on how to set options
+ #o.autocall = 1
+ o.system_verbose = 1
+
+ #import_all("os sys")
+ #execf('~/_ipython/ns.py')
+
+
+ # -- prompt
+ # A different, more compact set of prompts from the default ones, that
+ # always show your current location in the filesystem:
+
+ #o.prompt_in1 = r'\C_LightBlue[\C_LightCyan\Y2\C_LightBlue]\C_Normal\n\C_Green|\#>'
+ #o.prompt_in2 = r'.\D: '
+ #o.prompt_out = r'[\#] '
+
+ # Try one of these color settings if you can't read the text easily
+ # autoexec is a list of IPython commands to execute on startup
+ o.autoexec.append('%colors LightBG')
+ #o.autoexec.append('%colors NoColor')
+ #o.autoexec.append('%colors Linux')
+
+ # for sane integer division that converts to float (1/2 == 0.5)
+ #o.autoexec.append('from __future__ import division')
+
+ # For %tasks and %kill
+ #import jobctrl
+
+ # For autoreloading of modules (%autoreload, %aimport)
+ #import ipy_autoreload
+
+ # For winpdb support (%wdb)
+ #import ipy_winpdb
+
+ # For bzr completer, requires bzrlib (the python installation of bzr)
+ #ip.load('ipy_bzr')
+
+ # Tab completer that is not quite so picky (i.e.
+ # "foo".<TAB> and str(2).<TAB> will work). Complete
+ # at your own risk!
+ #import ipy_greedycompleter
+
+ # If you are on Linux, you may be annoyed by
+ # "Display all N possibilities? (y or n)" on tab completion,
+ # as well as the paging through "more". Uncomment the following
+ # lines to disable that behaviour
+ import readline
+ readline.parse_and_bind('set completion-query-items 1000')
+ readline.parse_and_bind('set page-completions no')
+
+ #set the context for the pydebug application within the user namespace
+ execf('./bin/start_debug.py')
+
+
+# some config helper functions you can use
+def import_all(modules):
+ """ Usage: import_all("os sys") """
+ for m in modules.split():
+ ip.ex("from %s import *" % m)
+
+def execf(fname):
+ """ Execute a file in user namespace """
+ ip.ex('execfile("%s")' % os.path.expanduser(fname))
+
+main()
diff --git a/ipythonrc b/ipythonrc
new file mode 100644
index 0000000..1499aa1
--- /dev/null
+++ b/ipythonrc
@@ -0,0 +1,632 @@
+# -*- Mode: Shell-Script -*- Not really, but shows comments correctly
+# $Id: ipythonrc 2156 2007-03-19 02:32:19Z fperez $
+
+#***************************************************************************
+#
+# Configuration file for IPython -- ipythonrc format
+#
+# ===========================================================
+# Deprecation note: you should look into modifying ipy_user_conf.py (located
+# in ~/.ipython or ~/_ipython, depending on your platform) instead, it's a
+# more flexible and robust (and better supported!) configuration
+# method.
+# ===========================================================
+#
+# The format of this file is simply one of 'key value' lines.
+# Lines containing only whitespace at the beginning and then a # are ignored
+# as comments. But comments can NOT be put on lines with data.
+
+# The meaning and use of each key are explained below.
+
+#---------------------------------------------------------------------------
+# Section: included files
+
+# Put one or more *config* files (with the syntax of this file) you want to
+# include. For keys with a unique value the outermost file has precedence. For
+# keys with multiple values, they all get assembled into a list which then
+# gets loaded by IPython.
+
+# In this file, all lists of things should simply be space-separated.
+
+# This allows you to build hierarchies of files which recursively load
+# lower-level services. If this is your main ~/.ipython/ipythonrc file, you
+# should only keep here basic things you always want available. Then you can
+# include it in every other special-purpose config file you create.
+include
+
+#---------------------------------------------------------------------------
+# Section: startup setup
+
+# These are mostly things which parallel a command line option of the same
+# name.
+
+# Keys in this section should only appear once. If any key from this section
+# is encountered more than once, the last value remains, all earlier ones get
+# discarded.
+
+
+# Automatic calling of callable objects. If set to 1 or 2, callable objects
+# are automatically called when invoked at the command line, even if you don't
+# type parentheses. IPython adds the parentheses for you. For example:
+
+#In [1]: str 45
+#------> str(45)
+#Out[1]: '45'
+
+# IPython reprints your line with '---->' indicating that it added
+# parentheses. While this option is very convenient for interactive use, it
+# may occasionally cause problems with objects which have side-effects if
+# called unexpectedly.
+
+# The valid values for autocall are:
+
+# autocall 0 -> disabled (you can toggle it at runtime with the %autocall magic)
+
+# autocall 1 -> active, but do not apply if there are no arguments on the line.
+
+# In this mode, you get:
+
+#In [1]: callable
+#Out[1]: <built-in function callable>
+
+#In [2]: callable 'hello'
+#------> callable('hello')
+#Out[2]: False
+
+# 2 -> Active always. Even if no arguments are present, the callable object
+# is called:
+
+#In [4]: callable
+#------> callable()
+
+# Note that even with autocall off, you can still use '/' at the start of a
+# line to treat the first argument on the command line as a function and add
+# parentheses to it:
+
+#In [8]: /str 43
+#------> str(43)
+#Out[8]: '43'
+
+autocall 1
+
+# Auto-edit syntax errors. When you use the %edit magic in ipython to edit
+# source code (see the 'editor' variable below), it is possible that you save
+# a file with syntax errors in it. If this variable is true, IPython will ask
+# you whether to re-open the editor immediately to correct such an error.
+
+autoedit_syntax 0
+
+# Auto-indent. IPython can recognize lines ending in ':' and indent the next
+# line, while also un-indenting automatically after 'raise' or 'return'.
+
+# This feature uses the readline library, so it will honor your ~/.inputrc
+# configuration (or whatever file your INPUTRC variable points to). Adding
+# the following lines to your .inputrc file can make indent/unindenting more
+# convenient (M-i indents, M-u unindents):
+
+# $if Python
+# "\M-i": " "
+# "\M-u": "\d\d\d\d"
+# $endif
+
+# The feature is potentially a bit dangerous, because it can cause problems
+# with pasting of indented code (the pasted code gets re-indented on each
+# line). But it's a huge time-saver when working interactively. The magic
+# function %autoindent allows you to toggle it on/off at runtime.
+
+autoindent 1
+
+# Auto-magic. This gives you access to all the magic functions without having
+# to prepend them with an % sign. If you define a variable with the same name
+# as a magic function (say who=1), you will need to access the magic function
+# with % (%who in this example). However, if later you delete your variable
+# (del who), you'll recover the automagic calling form.
+
+# Considering that many magic functions provide a lot of shell-like
+# functionality, automagic gives you something close to a full Python+system
+# shell environment (and you can extend it further if you want).
+
+automagic 1
+
+# Size of the output cache. After this many entries are stored, the cache will
+# get flushed. Depending on the size of your intermediate calculations, you
+# may have memory problems if you make it too big, since keeping things in the
+# cache prevents Python from reclaiming the memory for old results. Experiment
+# with a value that works well for you.
+
+# If you choose cache_size 0 IPython will revert to python's regular >>>
+# unnumbered prompt. You will still have _, __ and ___ for your last three
+# results, but that will be it. No dynamic _1, _2, etc. will be created. If
+# you are running on a slow machine or with very limited memory, this may
+# help.
+
+cache_size 1000
+
+# Classic mode: Setting 'classic 1' you lose many of IPython niceties,
+# but that's your choice! Classic 1 -> same as IPython -classic.
+# Note that this is _not_ the normal python interpreter, it's simply
+# IPython emulating most of the classic interpreter's behavior.
+classic 0
+
+# colors - Coloring option for prompts and traceback printouts.
+
+# Currently available schemes: NoColor, Linux, LightBG.
+
+# This option allows coloring the prompts and traceback printouts. This
+# requires a terminal which can properly handle color escape sequences. If you
+# are having problems with this, use the NoColor scheme (uses no color escapes
+# at all).
+
+# The Linux option works well in linux console type environments: dark
+# background with light fonts.
+
+# LightBG is similar to Linux but swaps dark/light colors to be more readable
+# in light background terminals.
+
+# keep uncommented only the one you want:
+#colors Linux
+colors LightBG
+#colors NoColor
+
+########################
+# Note to Windows users
+#
+# Color and readline support is avaialble to Windows users via Gary Bishop's
+# readline library. You can find Gary's tools at
+# http://sourceforge.net/projects/uncpythontools.
+# Note that his readline module requires in turn the ctypes library, available
+# at http://starship.python.net/crew/theller/ctypes.
+########################
+
+# color_info: IPython can display information about objects via a set of
+# functions, and optionally can use colors for this, syntax highlighting
+# source code and various other elements. This information is passed through a
+# pager (it defaults to 'less' if $PAGER is not set).
+
+# If your pager has problems, try to setting it to properly handle escapes
+# (see the less manpage for detail), or disable this option. The magic
+# function %color_info allows you to toggle this interactively for testing.
+
+color_info 1
+
+# confirm_exit: set to 1 if you want IPython to confirm when you try to exit
+# with an EOF (Control-d in Unix, Control-Z/Enter in Windows). Note that using
+# the magic functions %Exit or %Quit you can force a direct exit, bypassing
+# any confirmation.
+
+confirm_exit 1
+
+# Use deep_reload() as a substitute for reload() by default. deep_reload() is
+# still available as dreload() and appears as a builtin.
+
+deep_reload 0
+
+# Which editor to use with the %edit command. If you leave this at 0, IPython
+# will honor your EDITOR environment variable. Since this editor is invoked on
+# the fly by ipython and is meant for editing small code snippets, you may
+# want to use a small, lightweight editor here.
+
+# For Emacs users, setting up your Emacs server properly as described in the
+# manual is a good idea. An alternative is to use jed, a very light editor
+# with much of the feel of Emacs (though not as powerful for heavy-duty work).
+
+editor 0
+
+# log 1 -> same as ipython -log. This automatically logs to ./ipython.log
+log 0
+
+# Same as ipython -Logfile YourLogfileName.
+# Don't use with log 1 (use one or the other)
+logfile ''
+
+# banner 0 -> same as ipython -nobanner
+banner 1
+
+# messages 0 -> same as ipython -nomessages
+messages 1
+
+# Automatically call the pdb debugger after every uncaught exception. If you
+# are used to debugging using pdb, this puts you automatically inside of it
+# after any call (either in IPython or in code called by it) which triggers an
+# exception which goes uncaught.
+pdb 0
+
+# Enable the pprint module for printing. pprint tends to give a more readable
+# display (than print) for complex nested data structures.
+pprint 1
+
+# Prompt strings
+
+# Most bash-like escapes can be used to customize IPython's prompts, as well as
+# a few additional ones which are IPython-specific. All valid prompt escapes
+# are described in detail in the Customization section of the IPython HTML/PDF
+# manual.
+
+# Use \# to represent the current prompt number, and quote them to protect
+# spaces.
+prompt_in1 'In [\#]: '
+
+# \D is replaced by as many dots as there are digits in the
+# current value of \#.
+prompt_in2 ' .\D.: '
+
+prompt_out 'Out[\#]: '
+
+# Select whether to left-pad the output prompts to match the length of the
+# input ones. This allows you for example to use a simple '>' as an output
+# prompt, and yet have the output line up with the input. If set to false,
+# the output prompts will be unpadded (flush left).
+prompts_pad_left 1
+
+# Pylab support: when ipython is started with the -pylab switch, by default it
+# executes 'from matplotlib.pylab import *'. Set this variable to false if you
+# want to disable this behavior.
+
+# For details on pylab, see the matplotlib website:
+# http://matplotlib.sf.net
+pylab_import_all 1
+
+
+# quick 1 -> same as ipython -quick
+quick 0
+
+# Use the readline library (1) or not (0). Most users will want this on, but
+# if you experience strange problems with line management (mainly when using
+# IPython inside Emacs buffers) you may try disabling it. Not having it on
+# prevents you from getting command history with the arrow keys, searching and
+# name completion using TAB.
+
+readline 1
+
+# Screen Length: number of lines of your screen. This is used to control
+# printing of very long strings. Strings longer than this number of lines will
+# be paged with the less command instead of directly printed.
+
+# The default value for this is 0, which means IPython will auto-detect your
+# screen size every time it needs to print. If for some reason this isn't
+# working well (it needs curses support), specify it yourself. Otherwise don't
+# change the default.
+
+screen_length 0
+
+# Prompt separators for input and output.
+# Use \n for newline explicitly, without quotes.
+# Use 0 (like at the cmd line) to turn off a given separator.
+
+# The structure of prompt printing is:
+# (SeparateIn)Input....
+# (SeparateOut)Output...
+# (SeparateOut2), # that is, no newline is printed after Out2
+# By choosing these you can organize your output any way you want.
+
+separate_in \n
+separate_out 0
+separate_out2 0
+
+# 'nosep 1' is a shorthand for '-SeparateIn 0 -SeparateOut 0 -SeparateOut2 0'.
+# Simply removes all input/output separators, overriding the choices above.
+nosep 0
+
+# Wildcard searches - IPython has a system for searching names using
+# shell-like wildcards; type %psearch? for details. This variables sets
+# whether by default such searches should be case sensitive or not. You can
+# always override the default at the system command line or the IPython
+# prompt.
+
+wildcards_case_sensitive 1
+
+# Object information: at what level of detail to display the string form of an
+# object. If set to 0, ipython will compute the string form of any object X,
+# by calling str(X), when X? is typed. If set to 1, str(X) will only be
+# computed when X?? is given, and if set to 2 or higher, it will never be
+# computed (there is no X??? level of detail). This is mostly of use to
+# people who frequently manipulate objects whose string representation is
+# extremely expensive to compute.
+
+object_info_string_level 0
+
+# xmode - Exception reporting mode.
+
+# Valid modes: Plain, Context and Verbose.
+
+# Plain: similar to python's normal traceback printing.
+
+# Context: prints 5 lines of context source code around each line in the
+# traceback.
+
+# Verbose: similar to Context, but additionally prints the variables currently
+# visible where the exception happened (shortening their strings if too
+# long). This can potentially be very slow, if you happen to have a huge data
+# structure whose string representation is complex to compute. Your computer
+# may appear to freeze for a while with cpu usage at 100%. If this occurs, you
+# can cancel the traceback with Ctrl-C (maybe hitting it more than once).
+
+#xmode Plain
+xmode Context
+#xmode Verbose
+
+# multi_line_specials: if true, allow magics, aliases and shell escapes (via
+# !cmd) to be used in multi-line input (like for loops). For example, if you
+# have this active, the following is valid in IPython:
+#
+#In [17]: for i in range(3):
+# ....: mkdir $i
+# ....: !touch $i/hello
+# ....: ls -l $i
+
+multi_line_specials 1
+
+
+# System calls: When IPython makes system calls (e.g. via special syntax like
+# !cmd or !!cmd, or magics like %sc or %sx), it can print the command it is
+# executing to standard output, prefixed by a header string.
+
+system_header "IPython system call: "
+
+system_verbose 1
+
+# wxversion: request a specific wxPython version (used for -wthread)
+
+# Set this to the value of wxPython you want to use, but note that this
+# feature requires you to have the wxversion Python module to work. If you
+# don't have the wxversion module (try 'import wxversion' at the prompt to
+# check) or simply want to leave the system to pick up the default, leave this
+# variable at 0.
+
+wxversion 0
+
+#---------------------------------------------------------------------------
+# Section: Readline configuration (readline is not available for MS-Windows)
+
+# This is done via the following options:
+
+# (i) readline_parse_and_bind: this option can appear as many times as you
+# want, each time defining a string to be executed via a
+# readline.parse_and_bind() command. The syntax for valid commands of this
+# kind can be found by reading the documentation for the GNU readline library,
+# as these commands are of the kind which readline accepts in its
+# configuration file.
+
+# The TAB key can be used to complete names at the command line in one of two
+# ways: 'complete' and 'menu-complete'. The difference is that 'complete' only
+# completes as much as possible while 'menu-complete' cycles through all
+# possible completions. Leave the one you prefer uncommented.
+
+readline_parse_and_bind tab: complete
+#readline_parse_and_bind tab: menu-complete
+
+# This binds Control-l to printing the list of all possible completions when
+# there is more than one (what 'complete' does when hitting TAB twice, or at
+# the first TAB if show-all-if-ambiguous is on)
+readline_parse_and_bind "\C-l": possible-completions
+
+# This forces readline to automatically print the above list when tab
+# completion is set to 'complete'. You can still get this list manually by
+# using the key bound to 'possible-completions' (Control-l by default) or by
+# hitting TAB twice. Turning this on makes the printing happen at the first
+# TAB.
+readline_parse_and_bind set show-all-if-ambiguous on
+
+# If you have TAB set to complete names, you can rebind any key (Control-o by
+# default) to insert a true TAB character.
+readline_parse_and_bind "\C-o": tab-insert
+
+# These commands allow you to indent/unindent easily, with the 4-space
+# convention of the Python coding standards. Since IPython's internal
+# auto-indent system also uses 4 spaces, you should not change the number of
+# spaces in the code below.
+readline_parse_and_bind "\M-i": " "
+readline_parse_and_bind "\M-o": "\d\d\d\d"
+readline_parse_and_bind "\M-I": "\d\d\d\d"
+
+# Bindings for incremental searches in the history. These searches use the
+# string typed so far on the command line and search anything in the previous
+# input history containing them.
+readline_parse_and_bind "\C-r": reverse-search-history
+readline_parse_and_bind "\C-s": forward-search-history
+
+# Bindings for completing the current line in the history of previous
+# commands. This allows you to recall any previous command by typing its first
+# few letters and hitting Control-p, bypassing all intermediate commands which
+# may be in the history (much faster than hitting up-arrow 50 times!)
+readline_parse_and_bind "\C-p": history-search-backward
+readline_parse_and_bind "\C-n": history-search-forward
+
+# I also like to have the same functionality on the plain arrow keys. If you'd
+# rather have the arrows use all the history (and not just match what you've
+# typed so far), comment out or delete the next two lines.
+readline_parse_and_bind "\e[A": history-search-backward
+readline_parse_and_bind "\e[B": history-search-forward
+
+# These are typically on by default under *nix, but not win32.
+readline_parse_and_bind "\C-k": kill-line
+readline_parse_and_bind "\C-u": unix-line-discard
+
+# (ii) readline_remove_delims: a string of characters to be removed from the
+# default word-delimiters list used by readline, so that completions may be
+# performed on strings which contain them.
+
+readline_remove_delims -/~
+
+# (iii) readline_merge_completions: whether to merge the result of all
+# possible completions or not. If true, IPython will complete filenames,
+# python names and aliases and return all possible completions. If you set it
+# to false, each completer is used at a time, and only if it doesn't return
+# any completions is the next one used.
+
+# The default order is: [python_matches, file_matches, alias_matches]
+
+readline_merge_completions 1
+
+# (iv) readline_omit__names: normally hitting <tab> after a '.' in a name
+# will complete all attributes of an object, including all the special methods
+# whose names start with single or double underscores (like __getitem__ or
+# __class__).
+
+# This variable allows you to control this completion behavior:
+
+# readline_omit__names 1 -> completion will omit showing any names starting
+# with two __, but it will still show names starting with one _.
+
+# readline_omit__names 2 -> completion will omit all names beginning with one
+# _ (which obviously means filtering out the double __ ones).
+
+# Even when this option is set, you can still see those names by explicitly
+# typing a _ after the period and hitting <tab>: 'name._<tab>' will always
+# complete attribute names starting with '_'.
+
+# This option is off by default so that new users see all attributes of any
+# objects they are dealing with.
+
+readline_omit__names 0
+
+#---------------------------------------------------------------------------
+# Section: modules to be loaded with 'import ...'
+
+# List, separated by spaces, the names of the modules you want to import
+
+# Example:
+# import_mod sys os
+# will produce internally the statements
+# import sys
+# import os
+
+# Each import is executed in its own try/except block, so if one module
+# fails to load the others will still be ok.
+
+import_mod
+
+#---------------------------------------------------------------------------
+# Section: modules to import some functions from: 'from ... import ...'
+
+# List, one per line, the modules for which you want only to import some
+# functions. Give the module name first and then the name of functions to be
+# imported from that module.
+
+# Example:
+
+# import_some IPython.genutils timing timings
+# will produce internally the statement
+# from IPython.genutils import timing, timings
+
+# timing() and timings() are two IPython utilities for timing the execution of
+# your own functions, which you may find useful. Just commment out the above
+# line if you want to test them.
+
+# If you have more than one modules_some line, each gets its own try/except
+# block (like modules, see above).
+
+import_some
+
+#---------------------------------------------------------------------------
+# Section: modules to import all from : 'from ... import *'
+
+# List (same syntax as import_mod above) those modules for which you want to
+# import all functions. Remember, this is a potentially dangerous thing to do,
+# since it is very easy to overwrite names of things you need. Use with
+# caution.
+
+# Example:
+# import_all sys os
+# will produce internally the statements
+# from sys import *
+# from os import *
+
+# As before, each will be called in a separate try/except block.
+
+import_all
+
+#---------------------------------------------------------------------------
+# Section: Python code to execute.
+
+# Put here code to be explicitly executed (keep it simple!)
+# Put one line of python code per line. All whitespace is removed (this is a
+# feature, not a bug), so don't get fancy building loops here.
+# This is just for quick convenient creation of things you want available.
+
+# Example:
+# execute x = 1
+# execute print 'hello world'; y = z = 'a'
+# will produce internally
+# x = 1
+# print 'hello world'; y = z = 'a'
+# and each *line* (not each statement, we don't do python syntax parsing) is
+# executed in its own try/except block.
+
+execute
+
+# Note for the adventurous: you can use this to define your own names for the
+# magic functions, by playing some namespace tricks:
+
+# execute __IPYTHON__.magic_pf = __IPYTHON__.magic_profile
+
+# defines %pf as a new name for %profile.
+
+#---------------------------------------------------------------------------
+# Section: Pyhton files to load and execute.
+
+# Put here the full names of files you want executed with execfile(file). If
+# you want complicated initialization, just write whatever you want in a
+# regular python file and load it from here.
+
+# Filenames defined here (which *must* include the extension) are searched for
+# through all of sys.path. Since IPython adds your .ipython directory to
+# sys.path, they can also be placed in your .ipython dir and will be
+# found. Otherwise (if you want to execute things not in .ipyton nor in
+# sys.path) give a full path (you can use ~, it gets expanded)
+
+# Example:
+# execfile file1.py ~/file2.py
+# will generate
+# execfile('file1.py')
+# execfile('_path_to_your_home/file2.py')
+
+# As before, each file gets its own try/except block.
+
+execfile
+
+# If you are feeling adventurous, you can even add functionality to IPython
+# through here. IPython works through a global variable called __ip which
+# exists at the time when these files are read. If you know what you are doing
+# (read the source) you can add functions to __ip in files loaded here.
+
+# The file example-magic.py contains a simple but correct example. Try it:
+
+# execfile example-magic.py
+
+# Look at the examples in IPython/iplib.py for more details on how these magic
+# functions need to process their arguments.
+
+#---------------------------------------------------------------------------
+# Section: aliases for system shell commands
+
+# Here you can define your own names for system commands. The syntax is
+# similar to that of the builtin %alias function:
+
+# alias alias_name command_string
+
+# The resulting aliases are auto-generated magic functions (hence usable as
+# %alias_name)
+
+# For example:
+
+# alias myls ls -la
+
+# will define 'myls' as an alias for executing the system command 'ls -la'.
+# This allows you to customize IPython's environment to have the same aliases
+# you are accustomed to from your own shell.
+
+# You can also define aliases with parameters using %s specifiers (one per
+# parameter):
+
+# alias parts echo first %s second %s
+
+# will give you in IPython:
+# >>> %parts A B
+# first A second B
+
+# Use one 'alias' statement per alias you wish to define.
+
+# alias
+
+#************************* end of file <ipythonrc> ************************
diff --git a/lib/python2.5/site-packages/sugar/graphics/colorbutton.py b/lib/python2.5/site-packages/sugar/graphics/colorbutton.py
new file mode 100644
index 0000000..a5c7f0a
--- /dev/null
+++ b/lib/python2.5/site-packages/sugar/graphics/colorbutton.py
@@ -0,0 +1,531 @@
+# Copyright (C) 2007, Red Hat, Inc.
+# Copyright (C) 2008, Benjamin Berg <benjamin@sipsolutions.net>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the
+# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+import gettext
+import gtk
+import gobject
+import struct
+import logging
+
+from sugar.graphics import style
+from sugar.graphics.icon import Icon
+from sugar.graphics.palette import Palette, ToolInvoker, WidgetInvoker
+
+_ = lambda msg: gettext.dgettext('sugar-toolkit', msg)
+
+def get_svg_color_string(color):
+ return '#%.2X%.2X%.2X' % (color.red / 257, color.green / 257,
+ color.blue / 257)
+
+class _ColorButton(gtk.Button):
+ """This is a ColorButton for Sugar. It is similar to the gtk.ColorButton,
+ but does not have any alpha support.
+ Instead of a color selector dialog it will pop up a Sugar palette.
+
+ As a preview an sugar.graphics.Icon is used. The fill color will be set to
+ the current color, and the stroke color is set to the font color.
+ """
+
+ __gtype_name__ = 'SugarColorButton'
+ __gsignals__ = { 'color-set' : (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ tuple())}
+
+ def __init__(self, **kwargs):
+ self._title = _('Choose a color')
+ self._color = gtk.gdk.Color(0, 0, 0)
+ self._has_palette = True
+ self._has_invoker = True
+ self._palette = None
+ self._accept_drag = True
+
+ self._preview = Icon(icon_name='color-preview',
+ icon_size=gtk.ICON_SIZE_BUTTON)
+
+ gobject.GObject.__init__(self, **kwargs)
+
+ if self._accept_drag:
+ self.drag_dest_set(gtk.DEST_DEFAULT_MOTION |
+ gtk.DEST_DEFAULT_HIGHLIGHT |
+ gtk.DEST_DEFAULT_DROP,
+ [('application/x-color', 0, 0)],
+ gtk.gdk.ACTION_COPY)
+ self.drag_source_set(gtk.gdk.BUTTON1_MASK | gtk.gdk.BUTTON3_MASK,
+ [('application/x-color', 0, 0)],
+ gtk.gdk.ACTION_COPY)
+ self.connect('drag_data_received', self.__drag_data_received_cb)
+ self.connect('drag_data_get', self.__drag_data_get_cb)
+
+ self._preview.fill_color = get_svg_color_string(self._color)
+ self._preview.stroke_color = \
+ get_svg_color_string(self.style.fg[gtk.STATE_NORMAL])
+ self.set_image(self._preview)
+
+ if self._has_palette and self._has_invoker:
+ self._invoker = WidgetInvoker(self)
+ # FIXME: This is a hack.
+ self._invoker.has_rectangle_gap = lambda : False
+ self._invoker.palette = self._palette
+
+ def create_palette(self):
+ if self._has_palette:
+ self._palette = _ColorPalette(color=self._color,
+ primary_text=self._title)
+ self._palette.connect('color-set', self.__palette_color_set_cb)
+ self._palette.connect('notify::color', self.__palette_color_changed)
+
+ return self._palette
+
+ def __palette_color_set_cb(self, palette):
+ self.emit('color-set')
+
+ def __palette_color_changed(self, palette, pspec):
+ self.color = self._palette.color
+
+ def do_style_set(self, previous_style):
+ self._preview.stroke_color = \
+ get_svg_color_string(self.style.fg[gtk.STATE_NORMAL])
+
+ def do_clicked(self):
+ if self._palette:
+ if not self._palette.is_up():
+ self._palette.popup(immediate=True,
+ state=self._palette.SECONDARY)
+ else:
+ self._palette.popdown(immediate=True)
+ return True
+
+ def set_color(self, color):
+ assert isinstance(color, gtk.gdk.Color)
+
+ if self._color.red == color.red and \
+ self._color.green == color.green and \
+ self._color.blue == color.blue:
+ return
+
+ self._color = gtk.gdk.Color(color.red, color.green, color.blue)
+ self._preview.fill_color = get_svg_color_string(self._color)
+ if self._palette:
+ self._palette.props.color = self._color
+ self.notify('color')
+
+ def get_color(self):
+ return self._color
+
+ color = gobject.property(type=object, getter=get_color, setter=set_color)
+
+ def set_icon_name(self, icon_name):
+ self._preview.props.icon_name = icon_name
+
+ def get_icon_name(self):
+ return self._preview.props.icon_name
+
+ icon_name = gobject.property(type=str,
+ getter=get_icon_name, setter=set_icon_name)
+
+ def set_icon_size(self, icon_size):
+ self._preview.props.icon_size = icon_size
+
+ def get_icon_size(self):
+ return self._preview.props.icon_size
+
+ icon_size = gobject.property(type=int,
+ getter=get_icon_size, setter=set_icon_size)
+
+ def set_title(self, title):
+ self._title = title
+ if self._palette:
+ self._palette.primary_text = self._title
+
+ def get_title(self):
+ return self._title
+
+ title = gobject.property(type=str, getter=get_title, setter=set_title)
+
+ def _set_has_invoker(self, has_invoker):
+ self._has_invoker = has_invoker
+
+ def _get_has_invoker(self):
+ return self._has_invoker
+
+ has_invoker = gobject.property(type=bool, default=True,
+ flags=gobject.PARAM_READWRITE |
+ gobject.PARAM_CONSTRUCT_ONLY,
+ getter=_get_has_invoker,
+ setter=_set_has_invoker)
+
+ def _set_has_palette(self, has_palette):
+ self._has_palette = has_palette
+
+ def _get_has_palette(self):
+ return self._has_palette
+
+ has_palette = gobject.property(type=bool, default=True,
+ flags=gobject.PARAM_READWRITE |
+ gobject.PARAM_CONSTRUCT_ONLY,
+ getter=_get_has_palette,
+ setter=_set_has_palette)
+
+ def _set_accept_drag(self, accept_drag):
+ self._accept_drag = accept_drag
+
+ def _get_accept_drag(self):
+ return self._accept_drag
+
+ accept_drag = gobject.property(type=bool, default=True,
+ flags=gobject.PARAM_READWRITE |
+ gobject.PARAM_CONSTRUCT_ONLY,
+ getter=_get_accept_drag,
+ setter=_set_accept_drag)
+
+ # Drag and Drop
+ def __drag_begin_cb(self, widget, context):
+ pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8,
+ style.SMALL_ICON_SIZE,
+ style.SMALL_ICON_SIZE)
+
+ red = self._color.red / 257
+ green = self._color.green / 257
+ blue = self._color.blue / 257
+
+ pixbuf.fill(red << 24 + green << 16 + blue << 8 + 0xff)
+
+ context.set_icon_pixbuf(pixbuf)
+
+ def __drag_data_get_cb(self, widget, context, selection_data, info, time):
+ data = struct.pack('=HHHH', self._color.red, self._color.green,
+ self._color.blue, 65535)
+ selection_data.set(selection_data.target, 16, data)
+
+ def __drag_data_received_cb(self, widget, context, x, y, selection_data, \
+ info, time):
+ if len(selection_data.data) != 8:
+ return
+
+ dropped = selection_data.data
+ red = struct.unpack_from('=H', dropped, 0)[0]
+ green = struct.unpack_from('=H', dropped, 2)[0]
+ blue = struct.unpack_from('=H', dropped, 4)[0]
+ # dropped[6] and dropped[7] is alpha, but we ignore the alpha channel
+
+ color = gtk.gdk.Color(red, green, blue)
+ self.set_color(color)
+
+
+class _ColorPalette(Palette):
+ """This is a color picker palette. It will usually be used indirectly
+ trough a sugar.graphics.ColorButton.
+ """
+ _RED = 0
+ _GREEN = 1
+ _BLUE = 2
+
+ __gtype_name__ = 'SugarColorPalette'
+ # The color-set signal is emitted when the user is finished selecting
+ # a color.
+ __gsignals__ = { 'color-set' : (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ tuple())}
+
+ def __init__(self, **kwargs):
+ self._color = gtk.gdk.Color(0, 0, 0)
+ self._previous_color = self._color.copy()
+ self._scales = None
+
+ Palette.__init__(self, **kwargs)
+
+ self.connect('popup', self.__popup_cb)
+ self.connect('popdown', self.__popdown_cb)
+
+ self._picker_hbox = gtk.HBox()
+ self.set_content(self._picker_hbox)
+
+ self._swatch_tray = gtk.Table()
+
+ self._picker_hbox.pack_start(self._swatch_tray)
+ self._picker_hbox.pack_start(gtk.VSeparator(),
+ padding=style.DEFAULT_SPACING)
+
+ self._chooser_table = gtk.Table(3, 2)
+ self._chooser_table.set_col_spacing(0, style.DEFAULT_PADDING)
+
+ self._scales = []
+ self._scales.append(
+ self._create_color_scale(_('Red'), self._RED, 0))
+ self._scales.append(
+ self._create_color_scale(_('Green'), self._GREEN, 1))
+ self._scales.append(
+ self._create_color_scale(_('Blue'), self._BLUE, 2))
+
+ self._picker_hbox.add(self._chooser_table)
+
+ self._picker_hbox.show_all()
+
+ self._build_swatches()
+
+ def _create_color_scale(self, text, color, row):
+ label = gtk.Label(text)
+ label.props.xalign = 1.0
+ scale = gtk.HScale()
+ scale.set_size_request(style.zoom(250), -1)
+ scale.set_draw_value(False)
+ scale.set_range(0, 1.0)
+ scale.set_increments(0.1, 0.2)
+
+ if color == self._RED:
+ scale.set_value(self._color.red / 65535.0)
+ elif color == self._GREEN:
+ scale.set_value(self._color.green / 65535.0)
+ elif color == self._BLUE:
+ scale.set_value(self._color.blue / 65535.0)
+
+ scale.connect('value-changed',
+ self.__scale_value_changed_cb,
+ color)
+ self._chooser_table.attach(label, 0, 1, row, row + 1)
+ self._chooser_table.attach(scale, 1, 2, row, row + 1)
+
+ return scale
+
+
+
+ def _build_swatches(self):
+ for child in self._swatch_tray.get_children():
+ child.destroy()
+
+ # Use a hardcoded list of colors for now.
+ colors = ['#ed2529', '#69bc47', '#3c54a3',
+ '#f57f25', '#0b6b3a', '#00a0c6',
+ '#f6eb1a', '#b93f94', '#5b4a9c',
+ '#000000', '#919496', '#ffffff']
+
+ # We want 3 rows of colors.
+ rows = 3
+ i = 0
+ self._swatch_tray.props.n_rows = rows
+ self._swatch_tray.props.n_columns = (len(colors) + rows - 1) / rows
+ for color in colors:
+ button = _ColorButton(has_palette=False,
+ color=gtk.gdk.color_parse(color),
+ accept_drag=False,
+ icon_size=gtk.ICON_SIZE_LARGE_TOOLBAR)
+ button.set_relief(gtk.RELIEF_NONE)
+ self._swatch_tray.attach(button,
+ i % rows, i % rows + 1,
+ i / rows, i / rows + 1,
+ yoptions=0, xoptions=0)
+ button.connect('clicked', self.__swatch_button_clicked_cb)
+ i += 1
+
+ self._swatch_tray.show_all()
+
+ def __popup_cb(self, palette):
+ self._previous_color = self._color.copy()
+
+ def __popdown_cb(self, palette):
+ self.emit('color-set')
+
+ def __scale_value_changed_cb(self, widget, color):
+ new_color = self._color.copy()
+ if color == self._RED:
+ new_color.red = int(65535 * widget.get_value())
+ elif color == self._GREEN:
+ new_color.green = int(65535 * widget.get_value())
+ elif color == self._BLUE:
+ new_color.blue = int(65535 * widget.get_value())
+ self.color = new_color
+
+ def do_key_press_event(self, event):
+ if event.keyval == gtk.keysyms.Escape:
+ self.props.color = self._previous_color
+ self.popdown(immediate=True)
+ return True
+ elif event.keyval == gtk.keysyms.Return:
+ self.popdown(immediate=True)
+ return True
+ return False
+
+ def __swatch_button_clicked_cb(self, button):
+ self.props.color = button.get_color()
+
+ def set_color(self, color):
+ assert isinstance(color, gtk.gdk.Color)
+
+ if self._color.red == color.red and \
+ self._color.green == color.green and \
+ self._color.blue == color.blue:
+ return
+
+ self._color = color.copy()
+
+ if self._scales:
+ self._scales[self._RED].set_value(self._color.red / 65535.0)
+ self._scales[self._GREEN].set_value(self._color.green / 65535.0)
+ self._scales[self._BLUE].set_value(self._color.blue / 65535.0)
+
+ self.notify('color')
+
+ def get_color(self):
+ return self._color
+
+ color = gobject.property(type=object, getter=get_color, setter=set_color)
+
+
+
+def _add_accelerator(tool_button):
+ if not tool_button.props.accelerator or not tool_button.get_toplevel() or \
+ not tool_button.child:
+ return
+
+ # TODO: should we remove the accelerator from the prev top level?
+
+ accel_group = tool_button.get_toplevel().get_data('sugar-accel-group')
+ if not accel_group:
+ logging.warning('No gtk.AccelGroup in the top level window.')
+ return
+
+ keyval, mask = gtk.accelerator_parse(tool_button.props.accelerator)
+ # the accelerator needs to be set at the child, so the gtk.AccelLabel
+ # in the palette can pick it up.
+ tool_button.child.add_accelerator('clicked', accel_group, keyval, mask,
+ gtk.ACCEL_LOCKED | gtk.ACCEL_VISIBLE)
+
+def _hierarchy_changed_cb(tool_button, previous_toplevel):
+ _add_accelerator(tool_button)
+
+def setup_accelerator(tool_button):
+ _add_accelerator(tool_button)
+ tool_button.connect('hierarchy-changed', _hierarchy_changed_cb)
+
+# This not ideal. It would be better to subclass gtk.ToolButton, however
+# the python bindings do not seem to be powerfull enough for that.
+# (As we need to change a variable in the class structure.)
+class ColorToolButton(gtk.ToolItem):
+ __gtype_name__ = 'SugarColorToolButton'
+ __gsignals__ = { 'color-set' : (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ tuple())}
+
+ def __init__(self, icon_name='color-preview', **kwargs):
+ self._accelerator = None
+ self._tooltip = None
+ self._palette_invoker = ToolInvoker()
+ self._palette = None
+
+ gobject.GObject.__init__(self, **kwargs)
+
+ # The gtk.ToolButton has already added a normal button.
+ # Replace it with a ColorButton
+ color_button = _ColorButton(icon_name=icon_name, has_invoker=False)
+ self.add(color_button)
+
+ # The following is so that the behaviour on the toolbar is correct.
+ color_button.set_relief(gtk.RELIEF_NONE)
+ color_button.icon_size = gtk.ICON_SIZE_LARGE_TOOLBAR
+
+ self._palette_invoker.attach_tool(self)
+
+ # This widget just proxies the following properties to the colorbutton
+ color_button.connect('notify::color', self.__notify_change)
+ color_button.connect('notify::icon-name', self.__notify_change)
+ color_button.connect('notify::icon-size', self.__notify_change)
+ color_button.connect('notify::title', self.__notify_change)
+ color_button.connect('color-set', self.__color_set_cb)
+ color_button.connect('can-activate-accel',
+ self.__button_can_activate_accel_cb)
+
+ def __button_can_activate_accel_cb(self, button, signal_id):
+ # Accept activation via accelerators regardless of this widget's state
+ return True
+
+ def set_accelerator(self, accelerator):
+ self._accelerator = accelerator
+ setup_accelerator(self)
+
+ def get_accelerator(self):
+ return self._accelerator
+
+ accelerator = gobject.property(type=str, setter=set_accelerator,
+ getter=get_accelerator)
+
+ def create_palette(self):
+ self._palette = self.get_child().create_palette()
+ return self._palette
+
+ def get_palette_invoker(self):
+ return self._palette_invoker
+
+ def set_palette_invoker(self, palette_invoker):
+ self._palette_invoker.detach()
+ self._palette_invoker = palette_invoker
+
+ palette_invoker = gobject.property(
+ type=object, setter=set_palette_invoker, getter=get_palette_invoker)
+
+ def set_color(self, color):
+ self.get_child().props.color = color
+
+ def get_color(self):
+ return self.get_child().props.color
+
+ color = gobject.property(type=object, getter=get_color, setter=set_color)
+
+ def set_icon_name(self, icon_name):
+ self.get_child().props.icon_name = icon_name
+
+ def get_icon_name(self):
+ return self.get_child().props.icon_name
+
+ icon_name = gobject.property(type=str,
+ getter=get_icon_name, setter=set_icon_name)
+
+ def set_icon_size(self, icon_size):
+ self.get_child().props.icon_size = icon_size
+
+ def get_icon_size(self):
+ return self.get_child().props.icon_size
+
+ icon_size = gobject.property(type=int,
+ getter=get_icon_size, setter=set_icon_size)
+
+ def set_title(self, title):
+ self.get_child().props.title = title
+
+ def get_title(self):
+ return self.get_child().props.title
+
+ title = gobject.property(type=str, getter=get_title, setter=set_title)
+
+ def do_expose_event(self, event):
+ child = self.get_child()
+ allocation = self.get_allocation()
+ if self._palette and self._palette.is_up():
+ invoker = self._palette.props.invoker
+ invoker.draw_rectangle(event, self._palette)
+ elif child.state == gtk.STATE_PRELIGHT:
+ child.style.paint_box(event.window, gtk.STATE_PRELIGHT,
+ gtk.SHADOW_NONE, event.area,
+ child, 'toolbutton-prelight',
+ allocation.x, allocation.y,
+ allocation.width, allocation.height)
+
+ gtk.ToolButton.do_expose_event(self, event)
+
+ def __notify_change(self, widget, pspec):
+ self.notify(pspec.name)
+
+ def __color_set_cb(self, widget):
+ self.emit('color-set')
+
diff --git a/lib/python2.6/site-packages/browser.py b/lib/python2.6/site-packages/browser.py
new file mode 100644
index 0000000..b0a7ae7
--- /dev/null
+++ b/lib/python2.6/site-packages/browser.py
@@ -0,0 +1,229 @@
+# Copyright (C) 2006, Red Hat, Inc.
+# Copyright (C) 2007, One Laptop Per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import os
+import time
+import logging
+from gettext import gettext as _
+
+import gobject
+import gtk
+import hulahop
+import xpcom
+from xpcom.nsError import *
+from xpcom import components
+from xpcom.components import interfaces
+from hulahop.webview import WebView
+
+from sugar.datastore import datastore
+from sugar import profile
+from sugar import env
+from sugar.activity import activity
+from sugar.graphics import style
+
+import sessionstore
+from palettes import ContentInvoker
+from sessionhistory import HistoryListener
+from progresslistener import ProgressListener
+
+_ZOOM_AMOUNT = 0.1
+
+class GetSourceListener(object):
+ _com_interfaces_ = interfaces.nsIWebProgressListener
+
+ def __init__(self, file_path, async_cb, async_err_cb):
+ self._file_path = file_path
+ self._async_cb = async_cb
+ self._async_err_cb = async_err_cb
+
+ def onStateChange(self, webProgress, request, stateFlags, status):
+ if stateFlags & interfaces.nsIWebProgressListener.STATE_IS_REQUEST and \
+ stateFlags & interfaces.nsIWebProgressListener.STATE_STOP:
+ self._async_cb(self._file_path)
+
+ def onProgressChange(self, progress, request, curSelfProgress,
+ maxSelfProgress, curTotalProgress, maxTotalProgress):
+ pass
+
+ def onLocationChange(self, progress, request, location):
+ pass
+
+ def onStatusChange(self, progress, request, status, message):
+ pass
+
+ def onSecurityChange(self, progress, request, state):
+ pass
+
+class CommandListener(object):
+ _com_interfaces_ = interfaces.nsIDOMEventListener
+ def __init__(self, window):
+ self._window = window
+
+ def handleEvent(self, event):
+ if not event.isTrusted:
+ return
+
+ uri = event.originalTarget.ownerDocument.documentURI
+ if not uri.startswith('about:neterror?e=nssBadCert'):
+ return
+
+ cls = components.classes['@sugarlabs.org/add-cert-exception;1']
+ cert_exception = cls.createInstance(interfaces.hulahopAddCertException)
+ cert_exception.showDialog(self._window)
+
+class Browser(WebView):
+
+ AGENT_SHEET = os.path.join(activity.get_bundle_path(),
+ 'agent-stylesheet.css')
+ USER_SHEET = os.path.join(env.get_profile_path(), 'gecko',
+ 'user-stylesheet.css')
+
+ def __init__(self):
+ WebView.__init__(self)
+
+ self.history = HistoryListener()
+ self.progress = ProgressListener()
+
+ cls = components.classes["@mozilla.org/typeaheadfind;1"]
+ self.typeahead = cls.createInstance(interfaces.nsITypeAheadFind)
+
+ self._jobject = None
+
+ io_service_class = components.classes[ \
+ "@mozilla.org/network/io-service;1"]
+ io_service = io_service_class.getService(interfaces.nsIIOService)
+
+ # Use xpcom to turn off "offline mode" detection, which disables
+ # access to localhost for no good reason. (Trac #6250.)
+ io_service2 = io_service_class.getService(interfaces.nsIIOService2)
+ io_service2.manageOfflineStatus = False
+
+ cls = components.classes['@mozilla.org/content/style-sheet-service;1']
+ style_sheet_service = cls.getService(interfaces.nsIStyleSheetService)
+
+ if os.path.exists(Browser.AGENT_SHEET):
+ agent_sheet_uri = io_service.newURI('file:///' +
+ Browser.AGENT_SHEET,
+ None, None)
+ style_sheet_service.loadAndRegisterSheet(agent_sheet_uri,
+ interfaces.nsIStyleSheetService.AGENT_SHEET)
+
+ if os.path.exists(Browser.USER_SHEET):
+ user_sheet_uri = io_service.newURI('file:///' + Browser.USER_SHEET,
+ None, None)
+ style_sheet_service.loadAndRegisterSheet(user_sheet_uri,
+ interfaces.nsIStyleSheetService.USER_SHEET)
+
+ def do_setup(self):
+ WebView.do_setup(self)
+
+ listener = xpcom.server.WrapObject(ContentInvoker(self),
+ interfaces.nsIDOMEventListener)
+ self.window_root.addEventListener('click', listener, False)
+
+ listener = xpcom.server.WrapObject(CommandListener(self.dom_window),
+ interfaces.nsIDOMEventListener)
+ self.window_root.addEventListener('command', listener, False)
+
+ self.progress.setup(self)
+
+ self.history.setup(self.web_navigation)
+
+ self.typeahead.init(self.doc_shell)
+
+ def get_session(self):
+ return sessionstore.get_session(self)
+
+ def set_session(self, data):
+ return sessionstore.set_session(self, data)
+
+ def get_source(self, async_cb, async_err_cb):
+ cls = components.classes[ \
+ '@mozilla.org/embedding/browser/nsWebBrowserPersist;1']
+ persist = cls.createInstance(interfaces.nsIWebBrowserPersist)
+ # get the source from the cache
+ persist.persistFlags = \
+ interfaces.nsIWebBrowserPersist.PERSIST_FLAGS_FROM_CACHE
+
+ temp_path = os.path.join(activity.get_activity_root(), 'instance')
+ file_path = os.path.join(temp_path, '%i' % time.time())
+ cls = components.classes["@mozilla.org/file/local;1"]
+ local_file = cls.createInstance(interfaces.nsILocalFile)
+ local_file.initWithPath(file_path)
+
+ progresslistener = GetSourceListener(file_path, async_cb, async_err_cb)
+ persist.progressListener = xpcom.server.WrapObject(
+ progresslistener, interfaces.nsIWebProgressListener)
+
+ uri = self.web_navigation.currentURI
+ persist.saveURI(uri, self.doc_shell, None, None, None, local_file)
+
+ def zoom_in(self):
+ contentViewer = self.doc_shell.queryInterface( \
+ interfaces.nsIDocShell).contentViewer
+ if contentViewer is not None:
+ markupDocumentViewer = contentViewer.queryInterface( \
+ interfaces.nsIMarkupDocumentViewer)
+ markupDocumentViewer.fullZoom += _ZOOM_AMOUNT
+
+ def zoom_out(self):
+ contentViewer = self.doc_shell.queryInterface( \
+ interfaces.nsIDocShell).contentViewer
+ if contentViewer is not None:
+ markupDocumentViewer = contentViewer.queryInterface( \
+ interfaces.nsIMarkupDocumentViewer)
+ markupDocumentViewer.fullZoom -= _ZOOM_AMOUNT
+
+class PopupDialog(gtk.Window):
+ def __init__(self):
+ gtk.Window.__init__(self)
+
+ self.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG)
+
+ border = style.GRID_CELL_SIZE
+ self.set_default_size(gtk.gdk.screen_width() - border * 2,
+ gtk.gdk.screen_height() - border * 2)
+
+ self.view = WebView()
+ self.add(self.view)
+ self.view.realize()
+
+class WindowCreator:
+ _com_interfaces_ = interfaces.nsIWindowCreator
+
+ def createChromeWindow(self, parent, flags):
+ dialog = PopupDialog()
+
+ parent_dom_window = parent.webBrowser.contentDOMWindow
+ parent_view = hulahop.get_view_for_window(parent_dom_window)
+ if parent_view:
+ dialog.set_transient_for(parent_view.get_toplevel())
+
+ browser = dialog.view.browser
+
+ if flags & interfaces.nsIWebBrowserChrome.CHROME_OPENAS_CHROME:
+ dialog.view.is_chrome = True
+
+ item = browser.queryInterface(interfaces.nsIDocShellTreeItem)
+ item.itemType = interfaces.nsIDocShellTreeItem.typeChromeWrapper
+
+ return browser.containerWindow
+
+window_creator = WindowCreator()
+cls = components.classes['@mozilla.org/embedcomp/window-watcher;1']
+window_watcher = cls.getService(interfaces.nsIWindowWatcher)
+window_watcher.setWindowCreator(window_creator)
diff --git a/lib/python2.6/site-packages/sugar.save/activity/activityshim.py b/lib/python2.6/site-packages/sugar.save/activity/activityshim.py
new file mode 100644
index 0000000..5586162
--- /dev/null
+++ b/lib/python2.6/site-packages/sugar.save/activity/activityshim.py
@@ -0,0 +1,60 @@
+# Copyright (C) 2006-2007 Red Hat, Inc.
+# Copyright (C) 2007-2009 One Laptop Per Child
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the
+# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+import gettext
+import logging
+import os
+import time
+from hashlib import sha1
+import traceback
+import gconf
+
+import gtk
+import gobject
+import dbus
+import dbus.service
+import cjson
+
+from sugar import util
+from sugar.presence import presenceservice
+from sugar.activity.activityservice import ActivityService
+from sugar.activity.namingalert import NamingAlert
+from sugar.graphics import style
+from sugar.graphics.window import Window
+from sugar.graphics.toolbox import Toolbox
+from sugar.graphics.toolbutton import ToolButton
+from sugar.graphics.toolcombobox import ToolComboBox
+from sugar.graphics.alert import Alert
+from sugar.graphics.icon import Icon
+from sugar.graphics.xocolor import XoColor
+from sugar.datastore import datastore
+from sugar.session import XSMPClient
+from sugar import wm
+from sugar.activity.olpcactivity import ActivityShim
+
+class Activity(ActivityShim):
+ def __init__(self,handle, create_jobject=True):
+ ActivityShim.__init__(self, handle, create_jobject)
+
+ #define any super class redefinitions here
+ def set_canvas(self,canvas):
+ #from the source we see that the activity._vbox is the top level container below the main window
+ ActivityShim.set_canvas = self._vbox
+ self.set_canvas(canvas)
+
+
diff --git a/lib/python2.6/site-packages/sugar.save/activity/olpcactivity.pth b/lib/python2.6/site-packages/sugar.save/activity/olpcactivity.pth
new file mode 100644
index 0000000..4d8bfdc
--- /dev/null
+++ b/lib/python2.6/site-packages/sugar.save/activity/olpcactivity.pth
@@ -0,0 +1,2 @@
+/usr/lib/python2.6/site-packages/sugar/activity/activity.py
+
diff --git a/lib/python2.6/site-packages/terminal.py b/lib/python2.6/site-packages/terminal.py
new file mode 100644
index 0000000..dc52a13
--- /dev/null
+++ b/lib/python2.6/site-packages/terminal.py
@@ -0,0 +1,308 @@
+# Copyright (C) 2007, Eduardo Silva <edsiper@gmail.com>.
+# Copyright (C) 2008, One Laptop Per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import os, os.path, simplejson, ConfigParser
+
+from gettext import gettext as _
+
+# Initialize logging.
+import logging
+log = logging.getLogger('PyDebug')
+log.setLevel(logging.DEBUG)
+logging.basicConfig()
+
+import gtk
+import vte
+import pango
+
+from sugar.graphics.toolbutton import ToolButton
+import sugar.graphics.toolbutton
+import sugar.activity.activity
+import sugar.env
+
+MASKED_ENVIRONMENT = [
+ 'DBUS_SESSION_BUS_ADDRESS',
+ 'PPID'
+]
+
+class Terminal():
+
+ def __init__(self,handle):
+ pass
+
+ def _get_terminal_canvas(self):
+ self.terminal_notebook = gtk.Notebook()
+ self.terminal_notebook.set_property("tab-pos", gtk.POS_BOTTOM)
+ self.terminal_notebook.set_scrollable(True)
+ self.terminal_notebook.show()
+ return self.terminal_notebook
+
+ def _open_tab_cb(self, btn):
+ index = self._create_tab(None)
+ self.notebook.page = index
+
+ def _close_tab_cb(self, btn):
+ self._close_tab(self.notebook.props.page)
+
+ def _prev_tab_cb(self, btn):
+ if self.notebook.props.page == 0:
+ self.notebook.props.page = self.notebook.get_n_pages() - 1
+ else:
+ self.notebook.props.page = self.notebook.props.page - 1
+ vt = self.notebook.get_nth_page(self.notebook.get_current_page()).vt
+ vt.grab_focus()
+
+ def _next_tab_cb(self, btn):
+ if self.notebook.props.page == self.notebook.get_n_pages() - 1:
+ self.notebook.props.page = 0
+ else:
+ self.notebook.props.page = self.notebook.props.page + 1
+ vt = self.notebook.get_nth_page(self.notebook.get_current_page()).vt
+ vt.grab_focus()
+
+ def _close_tab(self, index):
+ self.notebook.remove_page(index)
+ if self.notebook.get_n_pages() == 0:
+ self.close()
+
+ def _tab_child_exited_cb(self, vt):
+ for i in range(self.notebook.get_n_pages()):
+ if self.notebook.get_nth_page(i).vt == vt:
+ self._close_tab(i)
+ return
+
+ def _tab_title_changed_cb(self, vt):
+ for i in range(self.notebook.get_n_pages()):
+ if self.notebook.get_nth_page(i).vt == vt:
+ label = self.notebook.get_nth_page(i).label
+ label.set_text(vt.get_window_title())
+ return
+
+ def _drag_data_received_cb(self, widget, context, x, y, selection, target, time):
+ widget.feed_child(selection.data)
+ context.finish(True, False, time)
+ return True
+
+ def _create_tab(self, tab_state):
+ vt = vte.Terminal()
+ vt.connect("child-exited", self._tab_child_exited_cb)
+ vt.connect("window-title-changed", self._tab_title_changed_cb)
+
+ vt.drag_dest_set(gtk.DEST_DEFAULT_MOTION|gtk.DEST_DEFAULT_DROP,
+ [('text/plain', 0, 0), ('STRING', 0, 1)],
+ gtk.gdk.ACTION_DEFAULT|
+ gtk.gdk.ACTION_COPY)
+ vt.connect('drag_data_received', self._drag_data_received_cb)
+
+ self._configure_vt(vt)
+
+ vt.show()
+
+ label = gtk.Label()
+
+ scrollbar = gtk.VScrollbar(vt.get_adjustment())
+ scrollbar.show()
+
+ box = gtk.HBox()
+ box.pack_start(vt)
+ box.pack_start(scrollbar)
+
+ box.vt = vt
+ box.label = label
+
+ index = self.terminal_notebook.append_page(box, label)
+ self.terminal_notebook.show_all()
+
+ # Uncomment this to only show the tab bar when there is at least one tab.
+ # I think it's useful to always see it, since it displays the 'window title'.
+ #self.notebook.props.show_tabs = self.notebook.get_n_pages() > 1
+
+ # Launch the default shell in the HOME directory.
+ os.chdir(os.environ["HOME"])
+
+ if tab_state:
+ # Restore the environment.
+ # This is currently not enabled.
+ env = tab_state['env']
+
+ filtered_env = []
+ for e in env:
+ var, sep, value = e.partition('=')
+ if var not in MASKED_ENVIRONMENT:
+ filtered_env.append(var + sep + value)
+
+ # TODO: Make the shell restore these environment variables, then clear out TERMINAL_ENV.
+ #os.environ['TERMINAL_ENV'] = '\n'.join(filtered_env)
+
+ # Restore the working directory.
+ if tab_state.has_key('cwd'):
+ os.chdir(tab_state['cwd'])
+
+ # Restore the scrollback buffer.
+ for l in tab_state['scrollback']:
+ vt.feed(l + '\r\n')
+
+ box.pid = vt.fork_command()
+
+ self.terminal_notebook.props.page = index
+ vt.grab_focus()
+
+ return index
+
+ def _copy_cb(self, button):
+ vt = self.terminal_notebook.get_nth_page(self.terminal_notebook.get_current_page()).vt
+ if vt.get_has_selection():
+ vt.copy_clipboard()
+
+ def _paste_cb(self, button):
+ vt = self.terminal_notebook.get_nth_page(self.terminal_notebook.get_current_page()).vt
+ vt.paste_clipboard()
+
+ def _become_root_cb(self, button):
+ vt = self.terminal_notebook.get_nth_page(self.terminal_notebook.get_current_page()).vt
+ vt.feed('\r\n')
+ vt.fork_command("/bin/su", ('/bin/su', '-'))
+
+ def _fullscreen_cb(self, btn):
+ self.fullscreen()
+
+ def _key_press_cb(self, window, event):
+ # Escape keypresses are routed directly to the vte and then dropped.
+ # This hack prevents Sugar from hijacking them and canceling fullscreen mode.
+ if gtk.gdk.keyval_name(event.keyval) == 'Escape':
+ vt = self.terminal_notebook.get_nth_page(self.terminal_notebook.get_current_page()).vt
+ vt.event(event)
+ return True
+
+ return False
+
+ def read_file(self, file_path):
+ if self.metadata['mime_type'] != 'text/plain':
+ return
+
+ fd = open(file_path, 'r')
+ text = fd.read()
+ data = simplejson.loads(text)
+ fd.close()
+
+ data_file = file_path
+
+ # Clean out any existing tabs.
+ while self.terminal_notebook.get_n_pages():
+ self.terminal_notebook.remove_page(0)
+
+ # Create new tabs from saved state.
+ for tab_state in data['tabs']:
+ self._create_tab(tab_state)
+
+ # Restore active tab.
+ self.terminal_notebook.props.page = data['current-tab']
+
+ # Create a blank one if this state had no terminals.
+ if self.terminal_notebook.get_n_pages() == 0:
+ self._create_tab(None)
+
+ def write_file(self, file_path):
+ if not self.metadata['mime_type']:
+ self.metadata['mime_type'] = 'text/plain'
+
+ data = {}
+ data['current-tab'] = self.terminal_notebook.get_current_page()
+ data['tabs'] = []
+
+ for i in range(self.terminal_notebook.get_n_pages()):
+ page = self.terminal_notebook.get_nth_page(i)
+
+ def selected_cb(terminal, c, row, cb_data):
+ return 1
+ (scrollback_text, attrs) = page.vt.get_text(selected_cb, 1)
+
+ scrollback_lines = scrollback_text.split('\n')
+
+ # Note- this currently gets the child's initial environment rather than the current
+ # environment, making it not very useful.
+ environment = open('/proc/%d/environ' % page.pid, 'r').read().split('\0')
+
+ cwd = os.readlink('/proc/%d/cwd' % page.pid)
+
+ tab_state = { 'env': environment, 'cwd': cwd, 'scrollback': scrollback_lines }
+
+ data['tabs'].append(tab_state)
+
+ fd = open(file_path, 'w')
+ text = simplejson.dumps(data)
+ fd.write(text)
+ fd.close()
+
+ def _get_conf(self, conf, var, default):
+ if conf.has_option('terminal', var):
+ if isinstance(default, bool):
+ return conf.getboolean('terminal', var)
+ elif isinstance(default, int):
+ return conf.getint('terminal', var)
+ else:
+ return conf.get('terminal', var)
+ else:
+ conf.set('terminal', var, default)
+
+ return default
+
+ def _configure_vt(self, vt):
+ conf = ConfigParser.ConfigParser()
+ conf_file = os.path.join(sugar.env.get_profile_path(), 'terminalrc')
+
+ if os.path.isfile(conf_file):
+ f = open(conf_file, 'r')
+ conf.readfp(f)
+ f.close()
+ else:
+ conf.add_section('terminal')
+
+ font = self._get_conf(conf, 'font', 'Monospace')
+ vt.set_font(pango.FontDescription(font))
+
+ fg_color = self._get_conf(conf, 'fg_color', '#000000')
+ bg_color = self._get_conf(conf, 'bg_color', '#FFFFFF')
+ vt.set_colors(gtk.gdk.color_parse(fg_color), gtk.gdk.color_parse(bg_color), [])
+
+ blink = self._get_conf(conf, 'cursor_blink', False)
+ vt.set_cursor_blinks(blink)
+
+ bell = self._get_conf(conf, 'bell', False)
+ vt.set_audible_bell(bell)
+
+ scrollback_lines = self._get_conf(conf, 'scrollback_lines', 1000)
+ vt.set_scrollback_lines(scrollback_lines)
+
+ vt.set_allow_bold(True)
+
+ scroll_key = self._get_conf(conf, 'scroll_on_keystroke', True)
+ vt.set_scroll_on_keystroke(scroll_key)
+
+ scroll_output = self._get_conf(conf, 'scroll_on_output', False)
+ vt.set_scroll_on_output(scroll_output)
+
+ emulation = self._get_conf(conf, 'emulation', 'xterm')
+ vt.set_emulation(emulation)
+
+ visible_bell = self._get_conf(conf, 'visible_bell', False)
+ vt.set_visible_bell(visible_bell)
+
+ conf.write(open(conf_file, 'w'))
+
+
+
diff --git a/locale/af/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/af/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..4c8e868
--- /dev/null
+++ b/locale/af/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/af/activity.linfo b/locale/af/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/af/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/am/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/am/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..551ba2b
--- /dev/null
+++ b/locale/am/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/am/activity.linfo b/locale/am/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/am/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/ar/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/ar/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..c41b178
--- /dev/null
+++ b/locale/ar/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/ar/activity.linfo b/locale/ar/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/ar/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/ay/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/ay/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..551ba2b
--- /dev/null
+++ b/locale/ay/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/ay/activity.linfo b/locale/ay/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/ay/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/bg/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/bg/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..551ba2b
--- /dev/null
+++ b/locale/bg/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/bg/activity.linfo b/locale/bg/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/bg/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/bi/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/bi/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..551ba2b
--- /dev/null
+++ b/locale/bi/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/bi/activity.linfo b/locale/bi/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/bi/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/bn/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/bn/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..551ba2b
--- /dev/null
+++ b/locale/bn/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/bn/activity.linfo b/locale/bn/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/bn/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/bn_IN/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/bn_IN/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..43e9977
--- /dev/null
+++ b/locale/bn_IN/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/bn_IN/activity.linfo b/locale/bn_IN/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/bn_IN/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/ca/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/ca/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..551ba2b
--- /dev/null
+++ b/locale/ca/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/ca/activity.linfo b/locale/ca/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/ca/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/cpp/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/cpp/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..551ba2b
--- /dev/null
+++ b/locale/cpp/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/cpp/activity.linfo b/locale/cpp/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/cpp/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/cs/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/cs/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..551ba2b
--- /dev/null
+++ b/locale/cs/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/cs/activity.linfo b/locale/cs/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/cs/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/de/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/de/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..3b566f1
--- /dev/null
+++ b/locale/de/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/de/activity.linfo b/locale/de/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/de/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/dz/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/dz/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..551ba2b
--- /dev/null
+++ b/locale/dz/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/dz/activity.linfo b/locale/dz/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/dz/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/el/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/el/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..ff44433
--- /dev/null
+++ b/locale/el/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/el/activity.linfo b/locale/el/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/el/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/en/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/en/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..551ba2b
--- /dev/null
+++ b/locale/en/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/en/activity.linfo b/locale/en/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/en/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/en_US/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/en_US/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..f49a722
--- /dev/null
+++ b/locale/en_US/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/en_US/activity.linfo b/locale/en_US/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/en_US/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/es/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/es/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..1d2193a
--- /dev/null
+++ b/locale/es/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/es/activity.linfo b/locale/es/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/es/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/fa/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/fa/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..551ba2b
--- /dev/null
+++ b/locale/fa/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/fa/activity.linfo b/locale/fa/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/fa/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/fa_AF/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/fa_AF/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..551ba2b
--- /dev/null
+++ b/locale/fa_AF/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/fa_AF/activity.linfo b/locale/fa_AF/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/fa_AF/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/ff/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/ff/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..551ba2b
--- /dev/null
+++ b/locale/ff/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/ff/activity.linfo b/locale/ff/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/ff/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/fi/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/fi/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..551ba2b
--- /dev/null
+++ b/locale/fi/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/fi/activity.linfo b/locale/fi/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/fi/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/fr/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/fr/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..436d748
--- /dev/null
+++ b/locale/fr/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/fr/activity.linfo b/locale/fr/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/fr/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/gu/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/gu/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..551ba2b
--- /dev/null
+++ b/locale/gu/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/gu/activity.linfo b/locale/gu/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/gu/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/ha/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/ha/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..551ba2b
--- /dev/null
+++ b/locale/ha/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/ha/activity.linfo b/locale/ha/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/ha/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/he/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/he/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..551ba2b
--- /dev/null
+++ b/locale/he/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/he/activity.linfo b/locale/he/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/he/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/hi/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/hi/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..551ba2b
--- /dev/null
+++ b/locale/hi/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/hi/activity.linfo b/locale/hi/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/hi/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/ht/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/ht/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..551ba2b
--- /dev/null
+++ b/locale/ht/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/ht/activity.linfo b/locale/ht/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/ht/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/hu/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/hu/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..551ba2b
--- /dev/null
+++ b/locale/hu/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/hu/activity.linfo b/locale/hu/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/hu/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/ig/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/ig/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..551ba2b
--- /dev/null
+++ b/locale/ig/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/ig/activity.linfo b/locale/ig/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/ig/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/is/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/is/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..551ba2b
--- /dev/null
+++ b/locale/is/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/is/activity.linfo b/locale/is/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/is/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/it/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/it/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..21e19b1
--- /dev/null
+++ b/locale/it/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/it/activity.linfo b/locale/it/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/it/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/ja/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/ja/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..07df127
--- /dev/null
+++ b/locale/ja/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/ja/activity.linfo b/locale/ja/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/ja/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/km/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/km/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..551ba2b
--- /dev/null
+++ b/locale/km/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/km/activity.linfo b/locale/km/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/km/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/ko/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/ko/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..551ba2b
--- /dev/null
+++ b/locale/ko/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/ko/activity.linfo b/locale/ko/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/ko/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/mi/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/mi/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..551ba2b
--- /dev/null
+++ b/locale/mi/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/mi/activity.linfo b/locale/mi/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/mi/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/mk/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/mk/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..551ba2b
--- /dev/null
+++ b/locale/mk/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/mk/activity.linfo b/locale/mk/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/mk/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/ml/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/ml/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..551ba2b
--- /dev/null
+++ b/locale/ml/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/ml/activity.linfo b/locale/ml/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/ml/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/mn/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/mn/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..5665f8e
--- /dev/null
+++ b/locale/mn/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/mn/activity.linfo b/locale/mn/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/mn/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/mr/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/mr/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..2e6cee4
--- /dev/null
+++ b/locale/mr/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/mr/activity.linfo b/locale/mr/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/mr/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/ms/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/ms/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..551ba2b
--- /dev/null
+++ b/locale/ms/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/ms/activity.linfo b/locale/ms/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/ms/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/mvo/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/mvo/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..551ba2b
--- /dev/null
+++ b/locale/mvo/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/mvo/activity.linfo b/locale/mvo/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/mvo/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/nb/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/nb/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..3332865
--- /dev/null
+++ b/locale/nb/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/nb/activity.linfo b/locale/nb/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/nb/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/ne/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/ne/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..d53791f
--- /dev/null
+++ b/locale/ne/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/ne/activity.linfo b/locale/ne/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/ne/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/nl/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/nl/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..8a6db30
--- /dev/null
+++ b/locale/nl/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/nl/activity.linfo b/locale/nl/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/nl/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/pa/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/pa/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..551ba2b
--- /dev/null
+++ b/locale/pa/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/pa/activity.linfo b/locale/pa/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/pa/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/pap/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/pap/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..b29c698
--- /dev/null
+++ b/locale/pap/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/pap/activity.linfo b/locale/pap/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/pap/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/pis/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/pis/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..551ba2b
--- /dev/null
+++ b/locale/pis/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/pis/activity.linfo b/locale/pis/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/pis/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/pl/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/pl/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..551ba2b
--- /dev/null
+++ b/locale/pl/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/pl/activity.linfo b/locale/pl/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/pl/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/ps/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/ps/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..551ba2b
--- /dev/null
+++ b/locale/ps/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/ps/activity.linfo b/locale/ps/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/ps/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/pt/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/pt/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..e9cecc3
--- /dev/null
+++ b/locale/pt/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/pt/activity.linfo b/locale/pt/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/pt/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/pt_BR/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/pt_BR/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..551ba2b
--- /dev/null
+++ b/locale/pt_BR/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/pt_BR/activity.linfo b/locale/pt_BR/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/pt_BR/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/qu/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/qu/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..551ba2b
--- /dev/null
+++ b/locale/qu/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/qu/activity.linfo b/locale/qu/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/qu/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/ro/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/ro/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..551ba2b
--- /dev/null
+++ b/locale/ro/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/ro/activity.linfo b/locale/ro/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/ro/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/ru/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/ru/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..551ba2b
--- /dev/null
+++ b/locale/ru/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/ru/activity.linfo b/locale/ru/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/ru/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/rw/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/rw/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..df2b70d
--- /dev/null
+++ b/locale/rw/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/rw/activity.linfo b/locale/rw/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/rw/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/sd/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/sd/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..551ba2b
--- /dev/null
+++ b/locale/sd/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/sd/activity.linfo b/locale/sd/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/sd/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/si/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/si/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..551ba2b
--- /dev/null
+++ b/locale/si/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/si/activity.linfo b/locale/si/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/si/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/sk/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/sk/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..551ba2b
--- /dev/null
+++ b/locale/sk/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/sk/activity.linfo b/locale/sk/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/sk/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/sl/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/sl/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..a49c1d6
--- /dev/null
+++ b/locale/sl/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/sl/activity.linfo b/locale/sl/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/sl/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/sv/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/sv/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..156fb29
--- /dev/null
+++ b/locale/sv/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/sv/activity.linfo b/locale/sv/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/sv/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/sw/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/sw/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..551ba2b
--- /dev/null
+++ b/locale/sw/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/sw/activity.linfo b/locale/sw/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/sw/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/te/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/te/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..4031fa0
--- /dev/null
+++ b/locale/te/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/te/activity.linfo b/locale/te/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/te/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/th/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/th/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..551ba2b
--- /dev/null
+++ b/locale/th/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/th/activity.linfo b/locale/th/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/th/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/tpi/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/tpi/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..551ba2b
--- /dev/null
+++ b/locale/tpi/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/tpi/activity.linfo b/locale/tpi/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/tpi/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/tr/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/tr/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..a154852
--- /dev/null
+++ b/locale/tr/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/tr/activity.linfo b/locale/tr/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/tr/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/ug/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/ug/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..551ba2b
--- /dev/null
+++ b/locale/ug/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/ug/activity.linfo b/locale/ug/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/ug/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/ur/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/ur/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..fa10d35
--- /dev/null
+++ b/locale/ur/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/ur/activity.linfo b/locale/ur/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/ur/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/vi/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/vi/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..951179f
--- /dev/null
+++ b/locale/vi/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/vi/activity.linfo b/locale/vi/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/vi/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/wa/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/wa/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..551ba2b
--- /dev/null
+++ b/locale/wa/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/wa/activity.linfo b/locale/wa/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/wa/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/yo/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/yo/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..551ba2b
--- /dev/null
+++ b/locale/yo/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/yo/activity.linfo b/locale/yo/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/yo/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/zh_CN/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/zh_CN/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..551ba2b
--- /dev/null
+++ b/locale/zh_CN/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/zh_CN/activity.linfo b/locale/zh_CN/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/zh_CN/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/locale/zh_TW/LC_MESSAGES/com.gmail.georgejhunt.mo b/locale/zh_TW/LC_MESSAGES/com.gmail.georgejhunt.mo
new file mode 100644
index 0000000..4f9966d
--- /dev/null
+++ b/locale/zh_TW/LC_MESSAGES/com.gmail.georgejhunt.mo
Binary files differ
diff --git a/locale/zh_TW/activity.linfo b/locale/zh_TW/activity.linfo
new file mode 100644
index 0000000..e8bc711
--- /dev/null
+++ b/locale/zh_TW/activity.linfo
@@ -0,0 +1,2 @@
+[Activity]
+name = PyDebug
diff --git a/notebook.py b/notebook.py
new file mode 100644
index 0000000..bdccf42
--- /dev/null
+++ b/notebook.py
@@ -0,0 +1,151 @@
+# Copyright (C) 2007, Eduardo Silva (edsiper@gmail.com)
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the
+# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+"""Notebook class
+
+This class create a gtk.Notebook() widget supporting
+a close button in every tab when the 'can-close-tabs' gproperty
+is enabled (True)
+
+STABLE.
+"""
+
+import gtk
+import gobject
+
+class Notebook(gtk.Notebook):
+ __gtype_name__ = 'SugarNotebook'
+
+ __gproperties__ = {
+ 'can-close-tabs': (bool, None, None, False,
+ gobject.PARAM_READWRITE |
+ gobject.PARAM_CONSTRUCT_ONLY)
+ }
+
+ def __init__(self, **kwargs):
+ # Initialise the Widget
+ #
+ # Side effects:
+ # Set the 'can-close-tabs' property using **kwargs
+ # Set True the scrollable notebook property
+
+ gobject.GObject.__init__(self, **kwargs)
+
+ self._can_close_tabs = None
+ self.interactive_close = False
+ self.set_scrollable(True)
+ self.show()
+
+ def do_set_property(self, pspec, value):
+ """
+ Set notebook property
+
+ Parameters
+ ----------
+ pspec :
+ property for which the value will be set
+
+ Returns
+ -------
+ None
+
+ Raises
+ ------
+ AssertionError
+
+ """
+ if pspec.name == 'can-close-tabs':
+ self._can_close_tabs = value
+ else:
+ raise AssertionError
+
+ def _add_icon_to_button(self, button):
+ icon_box = gtk.HBox()
+ image = gtk.Image()
+ image.set_from_stock(gtk.STOCK_CLOSE, gtk.ICON_SIZE_MENU)
+ gtk.Button.set_relief(button, gtk.RELIEF_NONE)
+
+ settings = gtk.Widget.get_settings(button)
+ w, h = gtk.icon_size_lookup_for_settings(settings, gtk.ICON_SIZE_MENU)
+ gtk.Widget.set_size_request(button, w + 4, h + 4)
+ image.show()
+ icon_box.pack_start(image, True, False, 0)
+ button.add(icon_box)
+ icon_box.show()
+
+ def _create_custom_tab(self, text, child):
+ event_box = gtk.EventBox()
+
+ tab_box = gtk.HBox(False, 2)
+ self.tab_label = gtk.Label(text)
+
+ tab_button = gtk.Button()
+ tab_button.connect('clicked', self._close_page, child)
+
+ # Add a picture on a button
+ self._add_icon_to_button(tab_button)
+
+ event_box.show()
+ tab_button.show()
+ self.tab_label.show()
+
+ tab_box.pack_start(self.tab_label, True)
+ tab_box.pack_start(tab_button, True)
+
+ tab_box.show_all()
+ event_box.add(tab_box)
+
+ return event_box
+
+ def add_page(self, text_label, widget):
+ """
+ Adds a page to the notebook.
+
+ Parameters
+ ----------
+ text_label :
+
+ widget :
+
+ Returns
+ -------
+ #Boolean
+ #Returns TRUE if the page is successfully added to th notebook.
+
+ """
+ # Add a new page to the notebook
+ if self._can_close_tabs:
+ eventbox = self._create_custom_tab(text_label, widget)
+ self.append_page(widget, eventbox)
+ else:
+ self.append_page(widget, gtk.Label(text_label))
+
+ pages = self.get_n_pages()
+
+ # Set the new page
+ self.set_current_page(pages - 1)
+ self.show_all()
+
+ return True
+
+ def _close_page(self, button, child):
+ # Remove a page from the notebook
+ page = self.page_num(child)
+ #If the close icon is clicked and file changed, ask about saving
+ self.interactive_close = True
+ if page != -1:
+ self.remove_page(page)
diff --git a/notebook.py~ b/notebook.py~
new file mode 100644
index 0000000..6e68400
--- /dev/null
+++ b/notebook.py~
@@ -0,0 +1,150 @@
+# Copyright (C) 2007, Eduardo Silva (edsiper@gmail.com)
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the
+# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+"""Notebook class
+
+This class create a gtk.Notebook() widget supporting
+a close button in every tab when the 'can-close-tabs' gproperty
+is enabled (True)
+
+STABLE.
+"""
+
+import gtk
+import gobject
+
+class Notebook(gtk.Notebook):
+ __gtype_name__ = 'SugarNotebook'
+
+ __gproperties__ = {
+ 'can-close-tabs': (bool, None, None, False,
+ gobject.PARAM_READWRITE |
+ gobject.PARAM_CONSTRUCT_ONLY)
+ }
+
+ def __init__(self, **kwargs):
+ # Initialise the Widget
+ #
+ # Side effects:
+ # Set the 'can-close-tabs' property using **kwargs
+ # Set True the scrollable notebook property
+
+ gobject.GObject.__init__(self, **kwargs)
+
+ self._can_close_tabs = None
+
+ self.set_scrollable(True)
+ self.show()
+
+ def do_set_property(self, pspec, value):
+ """
+ Set notebook property
+
+ Parameters
+ ----------
+ pspec :
+ property for which the value will be set
+
+ Returns
+ -------
+ None
+
+ Raises
+ ------
+ AssertionError
+
+ """
+ if pspec.name == 'can-close-tabs':
+ self._can_close_tabs = value
+ else:
+ raise AssertionError
+
+ def _add_icon_to_button(self, button):
+ icon_box = gtk.HBox()
+ image = gtk.Image()
+ image.set_from_stock(gtk.STOCK_CLOSE, gtk.ICON_SIZE_MENU)
+ gtk.Button.set_relief(button, gtk.RELIEF_NONE)
+
+ settings = gtk.Widget.get_settings(button)
+ w, h = gtk.icon_size_lookup_for_settings(settings, gtk.ICON_SIZE_MENU)
+ gtk.Widget.set_size_request(button, w + 4, h + 4)
+ image.show()
+ icon_box.pack_start(image, True, False, 0)
+ button.add(icon_box)
+ icon_box.show()
+
+ def _create_custom_tab(self, text, child):
+ event_box = gtk.EventBox()
+
+ tab_box = gtk.HBox(False, 2)
+ self.tab_label = gtk.Label(text)
+
+ tab_button = gtk.Button()
+ tab_button.connect('clicked', self._close_page, child)
+
+ # Add a picture on a button
+ self._add_icon_to_button(tab_button)
+
+ event_box.show()
+ tab_button.show()
+ self.tab_label.show()
+
+ tab_box.pack_start(self.tab_label, True)
+ tab_box.pack_start(tab_button, True)
+
+ tab_box.show_all()
+ event_box.add(tab_box)
+
+ return event_box
+
+ def add_page(self, text_label, widget):
+ """
+ Adds a page to the notebook.
+
+ Parameters
+ ----------
+ text_label :
+
+ widget :
+
+ Returns
+ -------
+ #Boolean
+ #Returns TRUE if the page is successfully added to th notebook.
+
+ """
+ # Add a new page to the notebook
+ if self._can_close_tabs:
+ eventbox = self._create_custom_tab(text_label, widget)
+ self.append_page(widget, eventbox)
+ else:
+ self.append_page(widget, gtk.Label(text_label))
+
+ pages = self.get_n_pages()
+
+ # Set the new page
+ self.set_current_page(pages - 1)
+ self.show_all()
+
+ return True
+
+ def _close_page(self, button, child):
+ # Remove a page from the notebook
+ page = self.page_num(child)
+
+ if page != -1:
+ self.remove_page(page)
diff --git a/po/Terminal.pot b/po/Terminal.pot
new file mode 100644
index 0000000..e2d4e9c
--- /dev/null
+++ b/po/Terminal.pot
@@ -0,0 +1,33 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr ""
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr ""
+
+#: terminal.py:49
+msgid "Edit"
+msgstr ""
+
+#: terminal.py:63
+msgid "Become root"
+msgstr ""
diff --git a/po/af.po b/po/af.po
new file mode 100644
index 0000000..b98a34f
--- /dev/null
+++ b/po/af.po
@@ -0,0 +1,32 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: 2008-06-20 18:07-0400\n"
+"Last-Translator: Morgan Collett <morgan.collett@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Pootle 1.1.0rc2\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr "Terminaal"
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr "Terminaal Aktiwiteit"
+
+#: terminal.py:49
+msgid "Edit"
+msgstr "Redigeer"
+
+#: terminal.py:63
+msgid "Become root"
+msgstr "Word root"
diff --git a/po/am.po b/po/am.po
new file mode 100644
index 0000000..ea86f77
--- /dev/null
+++ b/po/am.po
@@ -0,0 +1,33 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr ""
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr ""
+
+#: terminal.py:49
+msgid "Edit"
+msgstr ""
+
+#: terminal.py:63
+msgid "Become root"
+msgstr ""
diff --git a/po/ar.po b/po/ar.po
new file mode 100644
index 0000000..43ba784
--- /dev/null
+++ b/po/ar.po
@@ -0,0 +1,32 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: 2008-06-06 09:29-0400\n"
+"Last-Translator: Khaled Hosny <khaledhosny@eglug.org>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Pootle 1.1.0rc2\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr "الطرÙية"
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr "نشاط الطرÙية"
+
+#: terminal.py:49
+msgid "Edit"
+msgstr "تحرير"
+
+#: terminal.py:63
+msgid "Become root"
+msgstr "تحوّل إلى الجذر"
diff --git a/po/ay.po b/po/ay.po
new file mode 100644
index 0000000..ea86f77
--- /dev/null
+++ b/po/ay.po
@@ -0,0 +1,33 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr ""
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr ""
+
+#: terminal.py:49
+msgid "Edit"
+msgstr ""
+
+#: terminal.py:63
+msgid "Become root"
+msgstr ""
diff --git a/po/bg.po b/po/bg.po
new file mode 100644
index 0000000..ea86f77
--- /dev/null
+++ b/po/bg.po
@@ -0,0 +1,33 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr ""
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr ""
+
+#: terminal.py:49
+msgid "Edit"
+msgstr ""
+
+#: terminal.py:63
+msgid "Become root"
+msgstr ""
diff --git a/po/bi.po b/po/bi.po
new file mode 100644
index 0000000..ea86f77
--- /dev/null
+++ b/po/bi.po
@@ -0,0 +1,33 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr ""
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr ""
+
+#: terminal.py:49
+msgid "Edit"
+msgstr ""
+
+#: terminal.py:63
+msgid "Become root"
+msgstr ""
diff --git a/po/bn.po b/po/bn.po
new file mode 100644
index 0000000..ea86f77
--- /dev/null
+++ b/po/bn.po
@@ -0,0 +1,33 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr ""
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr ""
+
+#: terminal.py:49
+msgid "Edit"
+msgstr ""
+
+#: terminal.py:63
+msgid "Become root"
+msgstr ""
diff --git a/po/bn_IN.po b/po/bn_IN.po
new file mode 100644
index 0000000..98415ba
--- /dev/null
+++ b/po/bn_IN.po
@@ -0,0 +1,32 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: 2008-07-04 05:10-0400\n"
+"Last-Translator: Sankarshan Mukhopadhyay <sankarshan.mukhopadhyay@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Pootle 1.1.0rc2\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr "টারà§à¦®à¦¿à¦¨à¦¾à¦²"
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr "টারà§à¦®à¦¿à¦¨à¦¾à¦² করà§à¦®"
+
+#: terminal.py:49
+msgid "Edit"
+msgstr "সমà§à¦ªà¦¾à¦¦à¦¨"
+
+#: terminal.py:63
+msgid "Become root"
+msgstr "root হিসাবে কাজ করà§à¦¨"
diff --git a/po/ca.po b/po/ca.po
new file mode 100644
index 0000000..ea86f77
--- /dev/null
+++ b/po/ca.po
@@ -0,0 +1,33 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr ""
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr ""
+
+#: terminal.py:49
+msgid "Edit"
+msgstr ""
+
+#: terminal.py:63
+msgid "Become root"
+msgstr ""
diff --git a/po/cpp.po b/po/cpp.po
new file mode 100644
index 0000000..ea86f77
--- /dev/null
+++ b/po/cpp.po
@@ -0,0 +1,33 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr ""
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr ""
+
+#: terminal.py:49
+msgid "Edit"
+msgstr ""
+
+#: terminal.py:63
+msgid "Become root"
+msgstr ""
diff --git a/po/cs.po b/po/cs.po
new file mode 100644
index 0000000..ea86f77
--- /dev/null
+++ b/po/cs.po
@@ -0,0 +1,33 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr ""
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr ""
+
+#: terminal.py:49
+msgid "Edit"
+msgstr ""
+
+#: terminal.py:63
+msgid "Become root"
+msgstr ""
diff --git a/po/de.po b/po/de.po
new file mode 100644
index 0000000..c296967
--- /dev/null
+++ b/po/de.po
@@ -0,0 +1,32 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: 2008-06-14 15:34-0400\n"
+"Last-Translator: Markus Schlager <m.slg@gmx.de>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Pootle 1.1.0rc2\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr "Terminal"
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr "Terminal-Aktivitität"
+
+#: terminal.py:49
+msgid "Edit"
+msgstr "Bearbeiten"
+
+#: terminal.py:63
+msgid "Become root"
+msgstr "Root werden"
diff --git a/po/dz.po b/po/dz.po
new file mode 100644
index 0000000..ea86f77
--- /dev/null
+++ b/po/dz.po
@@ -0,0 +1,33 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr ""
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr ""
+
+#: terminal.py:49
+msgid "Edit"
+msgstr ""
+
+#: terminal.py:63
+msgid "Become root"
+msgstr ""
diff --git a/po/el.po b/po/el.po
new file mode 100644
index 0000000..4d93f2a
--- /dev/null
+++ b/po/el.po
@@ -0,0 +1,32 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: 2008-08-14 18:50-0400\n"
+"Last-Translator: John Sarlis <sarlis@sch.gr>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Pootle 1.1.0rc2\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr "ΤεÏματικό"
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr "ΔÏαστηÏιότητα τεÏματικοÏ"
+
+#: terminal.py:49
+msgid "Edit"
+msgstr "ΕπεξεÏγασία"
+
+#: terminal.py:63
+msgid "Become root"
+msgstr "Γίνε υπεÏχÏήστης"
diff --git a/po/en.po b/po/en.po
new file mode 100644
index 0000000..ea86f77
--- /dev/null
+++ b/po/en.po
@@ -0,0 +1,33 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr ""
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr ""
+
+#: terminal.py:49
+msgid "Edit"
+msgstr ""
+
+#: terminal.py:63
+msgid "Become root"
+msgstr ""
diff --git a/po/en_US.po b/po/en_US.po
new file mode 100644
index 0000000..1f179cb
--- /dev/null
+++ b/po/en_US.po
@@ -0,0 +1,32 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: 2008-11-02 23:20-0500\n"
+"Last-Translator: Desiree M Durham <desireemarie7@yahoo.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Pootle 1.1.0rc2\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr "Terminal"
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr "Terminal Activity"
+
+#: terminal.py:49
+msgid "Edit"
+msgstr "Edit"
+
+#: terminal.py:63
+msgid "Become root"
+msgstr "Become root"
diff --git a/po/es.po b/po/es.po
new file mode 100644
index 0000000..d009d4c
--- /dev/null
+++ b/po/es.po
@@ -0,0 +1,32 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: 2008-06-06 11:22-0400\n"
+"Last-Translator: Maria del Pilar Saenz Rodriguez <mapisaro@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Pootle 1.1.0rc2\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr "Terminal"
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr "Actividad Terminal"
+
+#: terminal.py:49
+msgid "Edit"
+msgstr "Editar"
+
+#: terminal.py:63
+msgid "Become root"
+msgstr "Convertirse en root"
diff --git a/po/fa.po b/po/fa.po
new file mode 100644
index 0000000..ea86f77
--- /dev/null
+++ b/po/fa.po
@@ -0,0 +1,33 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr ""
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr ""
+
+#: terminal.py:49
+msgid "Edit"
+msgstr ""
+
+#: terminal.py:63
+msgid "Become root"
+msgstr ""
diff --git a/po/fa_AF.po b/po/fa_AF.po
new file mode 100644
index 0000000..ea86f77
--- /dev/null
+++ b/po/fa_AF.po
@@ -0,0 +1,33 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr ""
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr ""
+
+#: terminal.py:49
+msgid "Edit"
+msgstr ""
+
+#: terminal.py:63
+msgid "Become root"
+msgstr ""
diff --git a/po/ff.po b/po/ff.po
new file mode 100644
index 0000000..ea86f77
--- /dev/null
+++ b/po/ff.po
@@ -0,0 +1,33 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr ""
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr ""
+
+#: terminal.py:49
+msgid "Edit"
+msgstr ""
+
+#: terminal.py:63
+msgid "Become root"
+msgstr ""
diff --git a/po/fi.po b/po/fi.po
new file mode 100644
index 0000000..ea86f77
--- /dev/null
+++ b/po/fi.po
@@ -0,0 +1,33 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr ""
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr ""
+
+#: terminal.py:49
+msgid "Edit"
+msgstr ""
+
+#: terminal.py:63
+msgid "Become root"
+msgstr ""
diff --git a/po/fr.po b/po/fr.po
new file mode 100644
index 0000000..dc697bb
--- /dev/null
+++ b/po/fr.po
@@ -0,0 +1,32 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: 2008-06-06 11:21-0400\n"
+"Last-Translator: samy boutayeb <s.boutayeb@free.fr>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Pootle 1.1.0rc2\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr "Terminal"
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr "Activité Terminal"
+
+#: terminal.py:49
+msgid "Edit"
+msgstr "Édition"
+
+#: terminal.py:63
+msgid "Become root"
+msgstr "Devenir administrateur"
diff --git a/po/gu.po b/po/gu.po
new file mode 100644
index 0000000..ea86f77
--- /dev/null
+++ b/po/gu.po
@@ -0,0 +1,33 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr ""
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr ""
+
+#: terminal.py:49
+msgid "Edit"
+msgstr ""
+
+#: terminal.py:63
+msgid "Become root"
+msgstr ""
diff --git a/po/ha.po b/po/ha.po
new file mode 100644
index 0000000..ea86f77
--- /dev/null
+++ b/po/ha.po
@@ -0,0 +1,33 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr ""
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr ""
+
+#: terminal.py:49
+msgid "Edit"
+msgstr ""
+
+#: terminal.py:63
+msgid "Become root"
+msgstr ""
diff --git a/po/he.po b/po/he.po
new file mode 100644
index 0000000..ea86f77
--- /dev/null
+++ b/po/he.po
@@ -0,0 +1,33 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr ""
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr ""
+
+#: terminal.py:49
+msgid "Edit"
+msgstr ""
+
+#: terminal.py:63
+msgid "Become root"
+msgstr ""
diff --git a/po/hi.po b/po/hi.po
new file mode 100644
index 0000000..ea86f77
--- /dev/null
+++ b/po/hi.po
@@ -0,0 +1,33 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr ""
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr ""
+
+#: terminal.py:49
+msgid "Edit"
+msgstr ""
+
+#: terminal.py:63
+msgid "Become root"
+msgstr ""
diff --git a/po/ht.po b/po/ht.po
new file mode 100644
index 0000000..ea86f77
--- /dev/null
+++ b/po/ht.po
@@ -0,0 +1,33 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr ""
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr ""
+
+#: terminal.py:49
+msgid "Edit"
+msgstr ""
+
+#: terminal.py:63
+msgid "Become root"
+msgstr ""
diff --git a/po/hu.po b/po/hu.po
new file mode 100644
index 0000000..ea86f77
--- /dev/null
+++ b/po/hu.po
@@ -0,0 +1,33 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr ""
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr ""
+
+#: terminal.py:49
+msgid "Edit"
+msgstr ""
+
+#: terminal.py:63
+msgid "Become root"
+msgstr ""
diff --git a/po/ig.po b/po/ig.po
new file mode 100644
index 0000000..ea86f77
--- /dev/null
+++ b/po/ig.po
@@ -0,0 +1,33 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr ""
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr ""
+
+#: terminal.py:49
+msgid "Edit"
+msgstr ""
+
+#: terminal.py:63
+msgid "Become root"
+msgstr ""
diff --git a/po/is.po b/po/is.po
new file mode 100644
index 0000000..ea86f77
--- /dev/null
+++ b/po/is.po
@@ -0,0 +1,33 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr ""
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr ""
+
+#: terminal.py:49
+msgid "Edit"
+msgstr ""
+
+#: terminal.py:63
+msgid "Become root"
+msgstr ""
diff --git a/po/it.po b/po/it.po
new file mode 100644
index 0000000..3792202
--- /dev/null
+++ b/po/it.po
@@ -0,0 +1,32 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: 2008-06-06 08:57-0400\n"
+"Last-Translator: Carlo Falciola <cfalciola@yahoo.it>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Pootle 1.1.0rc2\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr "Terminale"
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr "Attività Terminale"
+
+#: terminal.py:49
+msgid "Edit"
+msgstr "Modifica"
+
+#: terminal.py:63
+msgid "Become root"
+msgstr "Diventa root (amministratore)"
diff --git a/po/ja.po b/po/ja.po
new file mode 100644
index 0000000..a2ab2c5
--- /dev/null
+++ b/po/ja.po
@@ -0,0 +1,32 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: 2008-07-02 12:39-0400\n"
+"Last-Translator: korakurider <korakurider@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Pootle 1.1.0rc2\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr "ターミナル"
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr "ターミナル アクティビティ"
+
+#: terminal.py:49
+msgid "Edit"
+msgstr "編集"
+
+#: terminal.py:63
+msgid "Become root"
+msgstr "root(管ç†è€…ユーザ)ã«ãªã‚‹"
diff --git a/po/km.po b/po/km.po
new file mode 100644
index 0000000..ea86f77
--- /dev/null
+++ b/po/km.po
@@ -0,0 +1,33 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr ""
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr ""
+
+#: terminal.py:49
+msgid "Edit"
+msgstr ""
+
+#: terminal.py:63
+msgid "Become root"
+msgstr ""
diff --git a/po/ko.po b/po/ko.po
new file mode 100644
index 0000000..ea86f77
--- /dev/null
+++ b/po/ko.po
@@ -0,0 +1,33 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr ""
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr ""
+
+#: terminal.py:49
+msgid "Edit"
+msgstr ""
+
+#: terminal.py:63
+msgid "Become root"
+msgstr ""
diff --git a/po/mi.po b/po/mi.po
new file mode 100644
index 0000000..ea86f77
--- /dev/null
+++ b/po/mi.po
@@ -0,0 +1,33 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr ""
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr ""
+
+#: terminal.py:49
+msgid "Edit"
+msgstr ""
+
+#: terminal.py:63
+msgid "Become root"
+msgstr ""
diff --git a/po/mk.po b/po/mk.po
new file mode 100644
index 0000000..ea86f77
--- /dev/null
+++ b/po/mk.po
@@ -0,0 +1,33 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr ""
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr ""
+
+#: terminal.py:49
+msgid "Edit"
+msgstr ""
+
+#: terminal.py:63
+msgid "Become root"
+msgstr ""
diff --git a/po/ml.po b/po/ml.po
new file mode 100644
index 0000000..ea86f77
--- /dev/null
+++ b/po/ml.po
@@ -0,0 +1,33 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr ""
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr ""
+
+#: terminal.py:49
+msgid "Edit"
+msgstr ""
+
+#: terminal.py:63
+msgid "Become root"
+msgstr ""
diff --git a/po/mn.po b/po/mn.po
new file mode 100644
index 0000000..1044557
--- /dev/null
+++ b/po/mn.po
@@ -0,0 +1,32 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: 2008-06-27 03:05-0400\n"
+"Last-Translator: Odontsetseg Bat-Erdene <obat-erdene@suffolk.edu>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Pootle 1.1.0rc2\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr "Терминал"
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr "Терминалын үйл ажиллагаа"
+
+#: terminal.py:49
+msgid "Edit"
+msgstr "ЗаÑварлах"
+
+#: terminal.py:63
+msgid "Become root"
+msgstr "Давуу ÑрхтÑй Ñ…ÑÑ€ÑглÑгч болох"
diff --git a/po/mr.po b/po/mr.po
new file mode 100644
index 0000000..4c1d468
--- /dev/null
+++ b/po/mr.po
@@ -0,0 +1,32 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: 2008-06-21 02:28-0400\n"
+"Last-Translator: Rupali Sarode <rups23in@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Pootle 1.1.0rc2\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr "टरà¥à¤®à¤¿à¤¨à¤²"
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr "टरà¥à¤®à¤¿à¤¨à¤² आकà¥à¤Ÿà¤¿à¤µà¤¿à¤Ÿà¥€"
+
+#: terminal.py:49
+msgid "Edit"
+msgstr "संपादन करा"
+
+#: terminal.py:63
+msgid "Become root"
+msgstr "रूट बनवा"
diff --git a/po/ms.po b/po/ms.po
new file mode 100644
index 0000000..ea86f77
--- /dev/null
+++ b/po/ms.po
@@ -0,0 +1,33 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr ""
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr ""
+
+#: terminal.py:49
+msgid "Edit"
+msgstr ""
+
+#: terminal.py:63
+msgid "Become root"
+msgstr ""
diff --git a/po/mvo.po b/po/mvo.po
new file mode 100644
index 0000000..ea86f77
--- /dev/null
+++ b/po/mvo.po
@@ -0,0 +1,33 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr ""
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr ""
+
+#: terminal.py:49
+msgid "Edit"
+msgstr ""
+
+#: terminal.py:63
+msgid "Become root"
+msgstr ""
diff --git a/po/nb.po b/po/nb.po
new file mode 100644
index 0000000..27fafe5
--- /dev/null
+++ b/po/nb.po
@@ -0,0 +1,34 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: 2008-07-23 16:23+0100\n"
+"Last-Translator: Kent Dahl <kentda@pvv.org>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr "Konsoll"
+
+#: terminal.py:43
+#, fuzzy
+msgid "Terminal Activity"
+msgstr "Konsollsesjon"
+
+#: terminal.py:49
+msgid "Edit"
+msgstr "Endre"
+
+#: terminal.py:63
+#, fuzzy
+msgid "Become root"
+msgstr "Bli til rotbruker"
diff --git a/po/ne.po b/po/ne.po
new file mode 100644
index 0000000..19fa678
--- /dev/null
+++ b/po/ne.po
@@ -0,0 +1,32 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: 2008-07-17 01:19-0400\n"
+"Last-Translator: Pradosh Kharel <pradosh@olenepal.org>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Pootle 1.1.0rc2\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr "टरà¥à¤®à¤¿à¤¨à¤²"
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr "टरà¥à¤®à¤¿à¤¨à¤² कà¥à¤°à¤¿à¤¯à¤¾à¤•à¤²à¤¾à¤ª"
+
+#: terminal.py:49
+msgid "Edit"
+msgstr "समà¥à¤ªà¤¾à¤¦à¤¨"
+
+#: terminal.py:63
+msgid "Become root"
+msgstr "रà¥à¤Ÿ बन"
diff --git a/po/nl.po b/po/nl.po
new file mode 100644
index 0000000..9dceb13
--- /dev/null
+++ b/po/nl.po
@@ -0,0 +1,32 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: 2008-06-24 17:16-0400\n"
+"Last-Translator: Myckel Habets <myckel@sdf.lonestar.org>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Pootle 1.1.0rc2\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr "Terminal"
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr "Terminal activiteit"
+
+#: terminal.py:49
+msgid "Edit"
+msgstr "Bewerken"
+
+#: terminal.py:63
+msgid "Become root"
+msgstr "Root worden"
diff --git a/po/pa.po b/po/pa.po
new file mode 100644
index 0000000..ea86f77
--- /dev/null
+++ b/po/pa.po
@@ -0,0 +1,33 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr ""
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr ""
+
+#: terminal.py:49
+msgid "Edit"
+msgstr ""
+
+#: terminal.py:63
+msgid "Become root"
+msgstr ""
diff --git a/po/pap.po b/po/pap.po
new file mode 100644
index 0000000..fb68fd3
--- /dev/null
+++ b/po/pap.po
@@ -0,0 +1,32 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: 2008-06-18 18:26-0400\n"
+"Last-Translator: Urso Wieske <uwieske@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Pootle 1.1.0rc2\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr "Terminal"
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr "Aktividad di Terminal"
+
+#: terminal.py:49
+msgid "Edit"
+msgstr "Edita"
+
+#: terminal.py:63
+msgid "Become root"
+msgstr "Bira root"
diff --git a/po/pis.po b/po/pis.po
new file mode 100644
index 0000000..ea86f77
--- /dev/null
+++ b/po/pis.po
@@ -0,0 +1,33 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr ""
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr ""
+
+#: terminal.py:49
+msgid "Edit"
+msgstr ""
+
+#: terminal.py:63
+msgid "Become root"
+msgstr ""
diff --git a/po/pl.po b/po/pl.po
new file mode 100644
index 0000000..ea86f77
--- /dev/null
+++ b/po/pl.po
@@ -0,0 +1,33 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr ""
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr ""
+
+#: terminal.py:49
+msgid "Edit"
+msgstr ""
+
+#: terminal.py:63
+msgid "Become root"
+msgstr ""
diff --git a/po/ps.po b/po/ps.po
new file mode 100644
index 0000000..ea86f77
--- /dev/null
+++ b/po/ps.po
@@ -0,0 +1,33 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr ""
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr ""
+
+#: terminal.py:49
+msgid "Edit"
+msgstr ""
+
+#: terminal.py:63
+msgid "Become root"
+msgstr ""
diff --git a/po/pt.po b/po/pt.po
new file mode 100644
index 0000000..cf54b1c
--- /dev/null
+++ b/po/pt.po
@@ -0,0 +1,32 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: 2008-08-24 13:55-0400\n"
+"Last-Translator: Eduardo H. Silva <HoboPrimate@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Pootle 1.1.0rc2\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr "Terminal"
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr "Actividade Terminal"
+
+#: terminal.py:49
+msgid "Edit"
+msgstr "Editar"
+
+#: terminal.py:63
+msgid "Become root"
+msgstr "Tornar-se root"
diff --git a/po/pt_BR.po b/po/pt_BR.po
new file mode 100644
index 0000000..ea86f77
--- /dev/null
+++ b/po/pt_BR.po
@@ -0,0 +1,33 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr ""
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr ""
+
+#: terminal.py:49
+msgid "Edit"
+msgstr ""
+
+#: terminal.py:63
+msgid "Become root"
+msgstr ""
diff --git a/po/qu.po b/po/qu.po
new file mode 100644
index 0000000..ea86f77
--- /dev/null
+++ b/po/qu.po
@@ -0,0 +1,33 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr ""
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr ""
+
+#: terminal.py:49
+msgid "Edit"
+msgstr ""
+
+#: terminal.py:63
+msgid "Become root"
+msgstr ""
diff --git a/po/ro.po b/po/ro.po
new file mode 100644
index 0000000..ea86f77
--- /dev/null
+++ b/po/ro.po
@@ -0,0 +1,33 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr ""
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr ""
+
+#: terminal.py:49
+msgid "Edit"
+msgstr ""
+
+#: terminal.py:63
+msgid "Become root"
+msgstr ""
diff --git a/po/ru.po b/po/ru.po
new file mode 100644
index 0000000..ea86f77
--- /dev/null
+++ b/po/ru.po
@@ -0,0 +1,33 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr ""
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr ""
+
+#: terminal.py:49
+msgid "Edit"
+msgstr ""
+
+#: terminal.py:63
+msgid "Become root"
+msgstr ""
diff --git a/po/rw.po b/po/rw.po
new file mode 100644
index 0000000..26046ab
--- /dev/null
+++ b/po/rw.po
@@ -0,0 +1,32 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: 2008-07-10 12:28+0200\n"
+"Last-Translator: Mwesigye Robert <robmwesigye@yahoo.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr "Umusoozo"
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr "Umusoozo w'igikorwa"
+
+#: terminal.py:49
+msgid "Edit"
+msgstr "Hindura"
+
+#: terminal.py:63
+msgid "Become root"
+msgstr "Guhinduka umuzi"
diff --git a/po/sd.po b/po/sd.po
new file mode 100644
index 0000000..ea86f77
--- /dev/null
+++ b/po/sd.po
@@ -0,0 +1,33 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr ""
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr ""
+
+#: terminal.py:49
+msgid "Edit"
+msgstr ""
+
+#: terminal.py:63
+msgid "Become root"
+msgstr ""
diff --git a/po/si.po b/po/si.po
new file mode 100644
index 0000000..ea86f77
--- /dev/null
+++ b/po/si.po
@@ -0,0 +1,33 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr ""
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr ""
+
+#: terminal.py:49
+msgid "Edit"
+msgstr ""
+
+#: terminal.py:63
+msgid "Become root"
+msgstr ""
diff --git a/po/sk.po b/po/sk.po
new file mode 100644
index 0000000..ea86f77
--- /dev/null
+++ b/po/sk.po
@@ -0,0 +1,33 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr ""
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr ""
+
+#: terminal.py:49
+msgid "Edit"
+msgstr ""
+
+#: terminal.py:63
+msgid "Become root"
+msgstr ""
diff --git a/po/sl.po b/po/sl.po
new file mode 100644
index 0000000..f2fac75
--- /dev/null
+++ b/po/sl.po
@@ -0,0 +1,32 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: 2008-07-09 13:18-0400\n"
+"Last-Translator: Benjamin Martincic <beno@gambo.si>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Pootle 1.1.0rc2\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr "Terminal"
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr "Terminalska aktivnost"
+
+#: terminal.py:49
+msgid "Edit"
+msgstr "Urejanje"
+
+#: terminal.py:63
+msgid "Become root"
+msgstr "Postani root"
diff --git a/po/sv.po b/po/sv.po
new file mode 100644
index 0000000..36ff246
--- /dev/null
+++ b/po/sv.po
@@ -0,0 +1,32 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: 2008-10-03 07:24-0400\n"
+"Last-Translator: Mattias Ohlsson <mattias_oh@yahoo.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr "Terminal"
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr "Terminalsaktivitet"
+
+#: terminal.py:49
+msgid "Edit"
+msgstr "Redigera"
+
+#: terminal.py:63
+msgid "Become root"
+msgstr "Bli administratör"
diff --git a/po/sw.po b/po/sw.po
new file mode 100644
index 0000000..ea86f77
--- /dev/null
+++ b/po/sw.po
@@ -0,0 +1,33 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr ""
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr ""
+
+#: terminal.py:49
+msgid "Edit"
+msgstr ""
+
+#: terminal.py:63
+msgid "Become root"
+msgstr ""
diff --git a/po/te.po b/po/te.po
new file mode 100644
index 0000000..8b9c11d
--- /dev/null
+++ b/po/te.po
@@ -0,0 +1,32 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: 2008-07-24 12:51+0100\n"
+"Last-Translator: Satyanarayana Murthy Saladi <saladism@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr "టెరà±à°®à°¿à°¨à°²à±"
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr "టెరà±à°®à°¿à°¨à°²à± à°µà±à°¯à°¾à°ªà°•à°‚"
+
+#: terminal.py:49
+msgid "Edit"
+msgstr "కూరà±à°šà±"
+
+#: terminal.py:63
+msgid "Become root"
+msgstr "రూటౠగామారà±"
diff --git a/po/th.po b/po/th.po
new file mode 100644
index 0000000..ea86f77
--- /dev/null
+++ b/po/th.po
@@ -0,0 +1,33 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr ""
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr ""
+
+#: terminal.py:49
+msgid "Edit"
+msgstr ""
+
+#: terminal.py:63
+msgid "Become root"
+msgstr ""
diff --git a/po/tpi.po b/po/tpi.po
new file mode 100644
index 0000000..ea86f77
--- /dev/null
+++ b/po/tpi.po
@@ -0,0 +1,33 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr ""
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr ""
+
+#: terminal.py:49
+msgid "Edit"
+msgstr ""
+
+#: terminal.py:63
+msgid "Become root"
+msgstr ""
diff --git a/po/tr.po b/po/tr.po
new file mode 100644
index 0000000..941b43c
--- /dev/null
+++ b/po/tr.po
@@ -0,0 +1,32 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: 2008-07-18 04:54-0400\n"
+"Last-Translator: abdullah kocabas <abdullah.kocabas@abcdizustu.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Pootle 1.1.0rc2\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr "ana"
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr "ana etkinlik"
+
+#: terminal.py:49
+msgid "Edit"
+msgstr "düzenlemek"
+
+#: terminal.py:63
+msgid "Become root"
+msgstr "yerleÅŸmek"
diff --git a/po/ug.po b/po/ug.po
new file mode 100644
index 0000000..ea86f77
--- /dev/null
+++ b/po/ug.po
@@ -0,0 +1,33 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr ""
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr ""
+
+#: terminal.py:49
+msgid "Edit"
+msgstr ""
+
+#: terminal.py:63
+msgid "Become root"
+msgstr ""
diff --git a/po/ur.po b/po/ur.po
new file mode 100644
index 0000000..62689d1
--- /dev/null
+++ b/po/ur.po
@@ -0,0 +1,32 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: 2008-07-03 07:02-0400\n"
+"Last-Translator: salman minhas <sulmanminhas@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Pootle 1.1.0rc2\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr "ٹرمينل"
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr "ٹرمينل سرگرمی"
+
+#: terminal.py:49
+msgid "Edit"
+msgstr "تبديل کريں"
+
+#: terminal.py:63
+msgid "Become root"
+msgstr "روٹ بنيں"
diff --git a/po/vi.po b/po/vi.po
new file mode 100644
index 0000000..db366f1
--- /dev/null
+++ b/po/vi.po
@@ -0,0 +1,32 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: 2008-06-16 08:49-0400\n"
+"Last-Translator: Clytie Siddall <clytie@riverland.net.au>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Pootle 1.1.0rc2\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr "Thiết bị cuối"
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr "Hoạt động thiết bị cuối"
+
+#: terminal.py:49
+msgid "Edit"
+msgstr "Sá»­a"
+
+#: terminal.py:63
+msgid "Become root"
+msgstr "Trở thành ngÆ°á»i chủ"
diff --git a/po/wa.po b/po/wa.po
new file mode 100644
index 0000000..ea86f77
--- /dev/null
+++ b/po/wa.po
@@ -0,0 +1,33 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr ""
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr ""
+
+#: terminal.py:49
+msgid "Edit"
+msgstr ""
+
+#: terminal.py:63
+msgid "Become root"
+msgstr ""
diff --git a/po/yo.po b/po/yo.po
new file mode 100644
index 0000000..ea86f77
--- /dev/null
+++ b/po/yo.po
@@ -0,0 +1,33 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr ""
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr ""
+
+#: terminal.py:49
+msgid "Edit"
+msgstr ""
+
+#: terminal.py:63
+msgid "Become root"
+msgstr ""
diff --git a/po/zh_CN.po b/po/zh_CN.po
new file mode 100644
index 0000000..ea86f77
--- /dev/null
+++ b/po/zh_CN.po
@@ -0,0 +1,33 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.1.1rc4\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr ""
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr ""
+
+#: terminal.py:49
+msgid "Edit"
+msgstr ""
+
+#: terminal.py:63
+msgid "Become root"
+msgstr ""
diff --git a/po/zh_TW.po b/po/zh_TW.po
new file mode 100644
index 0000000..b44f650
--- /dev/null
+++ b/po/zh_TW.po
@@ -0,0 +1,32 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-05-21 20:48+0530\n"
+"PO-Revision-Date: 2008-07-18 19:14-0400\n"
+"Last-Translator: Yuan Chao <yuanchao@gmail.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Pootle 1.1.0rc2\n"
+
+#: activity/activity.info:2
+msgid "Terminal"
+msgstr "終端機"
+
+#: terminal.py:43
+msgid "Terminal Activity"
+msgstr "終端機活動"
+
+#: terminal.py:49
+msgid "Edit"
+msgstr "編輯"
+
+#: terminal.py:63
+msgid "Become root"
+msgstr "æˆç‚ºè¶…級管ç†å“¡"
diff --git a/progresslistener.py b/progresslistener.py
new file mode 100644
index 0000000..cf3cb43
--- /dev/null
+++ b/progresslistener.py
@@ -0,0 +1,89 @@
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import gobject
+import xpcom
+from xpcom.components import interfaces
+
+class ProgressListener(gobject.GObject):
+ _com_interfaces_ = interfaces.nsIWebProgressListener
+
+ __gsignals__ = {
+ 'location-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([object])),
+ 'loading-start': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([])),
+ 'loading-stop': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([])),
+ 'loading-progress': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([float]))
+ }
+
+ def __init__(self):
+ gobject.GObject.__init__(self)
+
+ self.total_requests = 0
+ self.completed_requests = 0
+
+ self._wrapped_self = xpcom.server.WrapObject( \
+ self, interfaces.nsIWebProgressListener)
+ weak_ref = xpcom.client.WeakReference(self._wrapped_self)
+
+ self._reset_requests_count()
+
+ def setup(self, browser):
+ mask = interfaces.nsIWebProgress.NOTIFY_STATE_NETWORK | \
+ interfaces.nsIWebProgress.NOTIFY_STATE_REQUEST | \
+ interfaces.nsIWebProgress.NOTIFY_LOCATION
+
+ browser.web_progress.addProgressListener(self._wrapped_self, mask)
+
+ def _reset_requests_count(self):
+ self.total_requests = 0
+ self.completed_requests = 0
+
+ def onLocationChange(self, webProgress, request, location):
+ self.emit('location-changed', location)
+
+ def onProgressChange(self, webProgress, request, curSelfProgress,
+ maxSelfProgress, curTotalProgress, maxTotalProgress):
+ pass
+
+ def onSecurityChange(self, webProgress, request, state):
+ pass
+
+ def onStateChange(self, webProgress, request, stateFlags, status):
+ if stateFlags & interfaces.nsIWebProgressListener.STATE_IS_REQUEST:
+ if stateFlags & interfaces.nsIWebProgressListener.STATE_START:
+ self.total_requests += 1
+ elif stateFlags & interfaces.nsIWebProgressListener.STATE_STOP:
+ self.completed_requests += 1
+
+ if stateFlags & interfaces.nsIWebProgressListener.STATE_IS_NETWORK:
+ if stateFlags & interfaces.nsIWebProgressListener.STATE_START:
+ self.emit('loading-start')
+ self._reset_requests_count()
+ elif stateFlags & interfaces.nsIWebProgressListener.STATE_STOP:
+ self.emit('loading-stop')
+
+ if self.total_requests < self.completed_requests:
+ self.emit('loading-progress', 1.0)
+ elif self.total_requests > 0:
+ self.emit('loading-progress', float(self.completed_requests) /
+ float(self.total_requests))
+ else:
+ self.emit('loading-progress', 0.0)
+
+ def onStatusChange(self, webProgress, request, status, message):
+ pass
diff --git a/project.glade b/project.glade
new file mode 100644
index 0000000..d5b02be
--- /dev/null
+++ b/project.glade
@@ -0,0 +1,949 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--Generated with glade3 3.4.5 on Mon Dec 28 17:54:52 2009 -->
+<glade-interface>
+ <widget class="GtkWindow" id="toplevel">
+ <property name="width_request">1200</property>
+ <property name="height_request">900</property>
+ <child>
+ <widget class="GtkHBox" id="contents">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkVBox" id="vbox2">
+ <property name="width_request">550</property>
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkFrame" id="frame1">
+ <property name="height_request">300</property>
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <child>
+ <widget class="GtkAlignment" id="alignment1">
+ <property name="visible">True</property>
+ <property name="left_padding">12</property>
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <child>
+ <widget class="GtkTreeView" id="journal">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="headers_clickable">True</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Journal&lt;/b&gt;</property>
+ <property name="use_markup">True</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">5</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkFrame" id="frame2">
+ <property name="height_request">300</property>
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">GTK_SHADOW_NONE</property>
+ <child>
+ <widget class="GtkAlignment" id="alignment2">
+ <property name="visible">True</property>
+ <property name="left_padding">12</property>
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow2">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <child>
+ <widget class="GtkTreeView" id="file_system">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip" translatable="yes">These are other examples of Activities you can examine.</property>
+ <property name="headers_clickable">True</property>
+ <signal name="toggle_cursor_row" handler="file_system_toggle_cursor_row_cb"/>
+ <signal name="row_activated" handler="file_system_row_activated_cb"/>
+ <signal name="cursor_changed" handler="file_system_row_activated_cb"/>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="file_system_label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Activities Directory&lt;/b&gt;</property>
+ <property name="use_markup">True</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">5</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkFrame" id="frame3">
+ <property name="height_request">200</property>
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">GTK_SHADOW_NONE</property>
+ <child>
+ <widget class="GtkAlignment" id="alignment3">
+ <property name="visible">True</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">5</property>
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow3">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <child>
+ <widget class="GtkTreeView" id="examples">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="headers_clickable">True</property>
+ <signal name="select_cursor_row" handler="file_system_select_cursor_row_cb"/>
+ <signal name="row_activated" handler="file_system_row_activated_cb"/>
+ <signal name="cursor_changed" handler="file_system_row_activated_cb"/>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label3">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Examples&lt;/b&gt;</property>
+ <property name="use_markup">True</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">5</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkTable" id="table1">
+ <property name="visible">True</property>
+ <property name="n_rows">20</property>
+ <property name="n_columns">1</property>
+ <property name="homogeneous">True</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <widget class="GtkButton" id="file_toggle">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="label" translatable="yes">Home</property>
+ <property name="response_id">0</property>
+ <signal name="clicked" handler="file_toggle_clicked_cb"/>
+ </widget>
+ <packing>
+ <property name="top_attach">13</property>
+ <property name="bottom_attach">14</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkButton" id="to_activities">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="response_id">0</property>
+ <signal name="clicked" handler="to_activities_clicked_cb"/>
+ <child>
+ <widget class="GtkArrow" id="arrow4">
+ <property name="visible">True</property>
+ <property name="arrow_type">GTK_ARROW_LEFT</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="top_attach">11</property>
+ <property name="bottom_attach">12</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkButton" id="from_examples">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="response_id">0</property>
+ <signal name="clicked" handler="from_examples_clicked_cb"/>
+ <child>
+ <widget class="GtkArrow" id="arrow7">
+ <property name="visible">True</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="top_attach">17</property>
+ <property name="bottom_attach">18</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkButton" id="from_activities">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="response_id">0</property>
+ <signal name="clicked" handler="from_activities_clicked_cb"/>
+ <child>
+ <widget class="GtkArrow" id="arrow3">
+ <property name="visible">True</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="top_attach">9</property>
+ <property name="bottom_attach">10</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkButton" id="to_journal">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="response_id">0</property>
+ <signal name="clicked" handler="to_journal_clicked_cb"/>
+ <child>
+ <widget class="GtkArrow" id="arrow2">
+ <property name="visible">True</property>
+ <property name="arrow_type">GTK_ARROW_LEFT</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkButton" id="from_journal">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="image_position">GTK_POS_TOP</property>
+ <property name="response_id">1</property>
+ <signal name="clicked" handler="from_journal_clicked_cb"/>
+ <child>
+ <widget class="GtkArrow" id="arrow1">
+ <property name="visible">True</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkFrame" id="PROJECT DETAILS">
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">GTK_SHADOW_ETCHED_OUT</property>
+ <child>
+ <widget class="GtkVBox" id="vbox1">
+ <property name="width_request">550</property>
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkTable" id="table2">
+ <property name="height_request">400</property>
+ <property name="visible">True</property>
+ <property name="n_rows">8</property>
+ <property name="n_columns">10</property>
+ <property name="homogeneous">True</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <widget class="GtkButton" id="button1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="label" translatable="yes">Delete File</property>
+ <property name="response_id">0</property>
+ <signal name="clicked" handler="delete_file_clicked_cb"/>
+ </widget>
+ <packing>
+ <property name="left_attach">7</property>
+ <property name="right_attach">10</property>
+ <property name="top_attach">7</property>
+ <property name="bottom_attach">8</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkButton" id="Run">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="label" translatable="yes">Run</property>
+ <property name="response_id">0</property>
+ <signal name="clicked" handler="Run_clicked_cb"/>
+ </widget>
+ <packing>
+ <property name="left_attach">8</property>
+ <property name="right_attach">10</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label13">
+ <property name="visible">True</property>
+ <property name="xalign">1</property>
+ <property name="label" translatable="yes">Version: </property>
+ <property name="justify">GTK_JUSTIFY_RIGHT</property>
+ </widget>
+ <packing>
+ <property name="left_attach">7</property>
+ <property name="right_attach">9</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkEntry" id="version">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <signal name="changed" handler="verson_changed_cb"/>
+ </widget>
+ <packing>
+ <property name="left_attach">9</property>
+ <property name="right_attach">10</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkEntry" id="class">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <signal name="changed" handler="class_changed_cb"/>
+ </widget>
+ <packing>
+ <property name="left_attach">7</property>
+ <property name="right_attach">10</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label11">
+ <property name="visible">True</property>
+ <property name="xalign">1</property>
+ <property name="label" translatable="yes">Class: </property>
+ </widget>
+ <packing>
+ <property name="left_attach">6</property>
+ <property name="right_attach">7</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label10">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Project Data</property>
+ </widget>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="right_attach">7</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label5">
+ <property name="visible">True</property>
+ <property name="xalign">1</property>
+ <property name="label" translatable="yes">Project Name: </property>
+ <property name="justify">GTK_JUSTIFY_RIGHT</property>
+ </widget>
+ <packing>
+ <property name="right_attach">3</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label6">
+ <property name="visible">True</property>
+ <property name="xalign">1</property>
+ <property name="label" translatable="yes">Unique id: </property>
+ <property name="justify">GTK_JUSTIFY_RIGHT</property>
+ </widget>
+ <packing>
+ <property name="right_attach">3</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label7">
+ <property name="visible">True</property>
+ <property name="xalign">1</property>
+ <property name="label" translatable="yes">Module: </property>
+ <property name="justify">GTK_JUSTIFY_RIGHT</property>
+ </widget>
+ <packing>
+ <property name="right_attach">3</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkEntry" id="name">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <signal name="changed" handler="name_changed_cb"/>
+ </widget>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="right_attach">7</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkEntry" id="bundle_id">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="right_attach">10</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkEntry" id="module">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <signal name="changed" handler="module_changed_cb"/>
+ </widget>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="right_attach">6</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkFrame" id="frame4">
+ <property name="height_request">500</property>
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">GTK_SHADOW_NONE</property>
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow4">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <child>
+ <widget class="GtkTreeView" id="manifest">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="headers_clickable">True</property>
+ <signal name="select_cursor_row" handler="file_system_select_cursor_row_cb"/>
+ <signal name="row_activated" handler="file_system_row_activated_cb"/>
+ <signal name="cursor_changed" handler="file_system_row_activated_cb"/>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label12">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Project Files&lt;/b&gt;</property>
+ <property name="use_markup">True</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label4">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;PROJECT INFORMATION&lt;/b&gt; -- from ./activity/activity.info</property>
+ <property name="use_markup">True</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">5</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <widget class="GtkWindow" id="find">
+ <property name="width_request">200</property>
+ <property name="height_request">100</property>
+ <property name="title" translatable="yes">Find / Replace</property>
+ <property name="resizable">False</property>
+ <property name="modal">True</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <signal name="destroy" handler="find_close_clicked_cb"/>
+ <child>
+ <widget class="GtkTable" id="table3">
+ <property name="visible">True</property>
+ <property name="n_rows">6</property>
+ <property name="n_columns">9</property>
+ <property name="column_spacing">1</property>
+ <property name="row_spacing">1</property>
+ <property name="homogeneous">True</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <widget class="GtkButton" id="find_close">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="label" translatable="yes">Close</property>
+ <property name="response_id">0</property>
+ <signal name="clicked" handler="find_close_clicked_cb"/>
+ </widget>
+ <packing>
+ <property name="left_attach">6</property>
+ <property name="right_attach">9</property>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label18">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Find What:</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkEntry" id="find_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <signal name="changed" handler="find_entry_changed_cb"/>
+ </widget>
+ <packing>
+ <property name="right_attach">5</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label19">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Replace with:</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">4</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkEntry" id="replace_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <signal name="changed" handler="replace_entry_changed_cb"/>
+ </widget>
+ <packing>
+ <property name="right_attach">5</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkCheckButton" id="checkbutton1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Match Case</property>
+ <property name="xalign">0.40000000596046448</property>
+ <property name="response_id">0</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="right_attach">5</property>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkButton" id="find_previous">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="label" translatable="yes"> Previous</property>
+ <property name="response_id">0</property>
+ <signal name="clicked" handler="find_previous_clicked_cb"/>
+ </widget>
+ <packing>
+ <property name="left_attach">6</property>
+ <property name="right_attach">9</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkButton" id="find_next">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="label" translatable="yes">Next</property>
+ <property name="response_id">0</property>
+ <signal name="clicked" handler="find_next_clicked_cb"/>
+ </widget>
+ <packing>
+ <property name="left_attach">6</property>
+ <property name="right_attach">9</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkButton" id="replace">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="label" translatable="yes">Replace</property>
+ <property name="response_id">0</property>
+ <signal name="clicked" handler="replace_clicked_cb"/>
+ </widget>
+ <packing>
+ <property name="left_attach">6</property>
+ <property name="right_attach">9</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkEntry" id="entry1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </widget>
+ <packing>
+ <property name="right_attach">9</property>
+ <property name="top_attach">5</property>
+ <property name="bottom_attach">6</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <widget class="GtkWindow" id="browser">
+ <property name="resizable">False</property>
+ <child>
+ <widget class="GtkNotebook" id="help_notebook">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow5">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">page 1</property>
+ </widget>
+ <packing>
+ <property name="type">tab</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label20">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">page 2</property>
+ </widget>
+ <packing>
+ <property name="type">tab</property>
+ <property name="position">1</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label21">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">page 3</property>
+ </widget>
+ <packing>
+ <property name="type">tab</property>
+ <property name="position">2</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+</glade-interface>
diff --git a/pydebug.py b/pydebug.py
new file mode 100644
index 0000000..98e28df
--- /dev/null
+++ b/pydebug.py
@@ -0,0 +1,1478 @@
+# Copyright (C) 2009, George Hunt <georgejhunt@gmail.com>
+# Copyright (C) 2009, One Laptop Per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+from __future__ import with_statement
+import os, os.path, simplejson, ConfigParser, shutil, sys
+from subprocess import Popen
+
+from gettext import gettext as _
+
+#major packages
+import gtk
+import gtk.glade
+import vte
+import pango
+import gconf
+#import glib
+import pickle
+import hashlib
+import time
+
+#sugar stuff
+from sugar.graphics.toolbutton import ToolButton
+import sugar.graphics.toolbutton
+
+import sugar.env
+from sugar.graphics.xocolor import XoColor
+from sugar.graphics.icon import Icon
+from sugar.graphics.objectchooser import ObjectChooser
+from sugar.datastore import datastore
+from sugar.graphics.alert import *
+import sugar.activity.bundlebuilder as bundlebuilder
+from sugar.bundle.activitybundle import ActivityBundle
+from sugar.activity import activityfactory
+
+#application stuff
+from terminal_pd import Terminal
+#public api for ipython
+
+#from IPython.core import ipapi 0.11 requires this
+from IPython import ipapi
+
+#from sourceview import SourceViewPd
+import sourceview_editor
+from sugar.activity.activity import Activity
+from help_pd import Help
+
+#following taken from Rpyc module
+#import Rpyc
+from Rpyc.Utils.Serving import start_threaded_server, DEFAULT_PORT
+from Rpyc.Connection import *
+from Rpyc.Stream import *
+import select
+from filetree import FileTree
+from datastoretree import DataStoreTree
+import pytoolbar
+#from pytoolbar import ActivityToolBox
+
+import logging
+from pydebug_logging import _logger, log_environment
+
+MASKED_ENVIRONMENT = [
+ 'DBUS_SESSION_BUS_ADDRESS',
+ 'PPID'
+]
+#PANES = ['TERMINAL','EDITOR','CHILD','PROJECT','HELP']
+PANES = ['TERMINAL','EDITOR','PROJECT','HELP']
+
+#global module variable communicates to debugged programs
+pydebug_instance = None
+
+#following options taken from Develop_App
+class Options:
+ def __init__(self, template = None, **kw):
+ if template:
+ self.__dict__ = template.__dict__.copy()
+ else:
+ self.__dict__ = {}
+ self.__dict__.update(kw)
+
+class SearchOptions(Options):
+ pass
+S_WHERE = sourceview_editor.S_WHERE
+
+class PyDebugActivity(Activity,Terminal,Help):
+ MIME_TYPE = 'application/vnd.olpc-sugar'
+ DEPRECATED_MIME_TYPE = 'application/vnd.olpc-x-sugar'
+ _zipped_extension = '.xo'
+ _unzipped_extension = '.activity'
+ dirty = False
+
+ def __init__(self, handle):
+ _logger.debug('Activity id:%s.Object id: %s. uri:%s'%(handle.activity_id, handle.object_id, handle.uri))
+ #Save a global poiinter so remote procedure calls can communicate with pydebug
+ global pydebug_instance
+ pydebug_instance = self
+
+ #init variables
+ self.make_paths()
+
+ self.source_directory = None
+ self.data_file = None
+ self.help = None
+ self.project_dirty = False
+ self.sock = None
+ self.last_filename = None
+ self.debug_dict = {}
+ self.activity_dict = {}
+ self.file_pane_is_activities = False
+ self.manifest_treeview = None #set up to recognize an re-display of playpen
+ self.set_title(_('PyDebug Activity'))
+ self.ds = None #datastore pointer
+ self._logger = _logger
+ self.traceback = 'Context'
+ self.abandon_changes = False
+
+ # init the Classes we are subclassing
+ Activity.__init__(self, handle, create_jobject = False)
+ #Terminal has no needs for init
+ Help.__init__(self,self)
+
+ # setup the search options
+ self.s_opts = SearchOptions(where = S_WHERE.multifile,
+ use_regex = False,
+ ignore_caps = True,
+ replace_all = False,
+
+ #defaults to avoid creating
+ #a new SearchOptions object for normal searches
+ #should never be changed, just make a copy like:
+ #SearchOptions(self.s_opts, forward=False)
+ forward = True,
+ stay = False
+ )
+ self.safe_to_replace = False
+
+
+ #set up the PANES for the different functions of the debugger
+ self.canvas_list = []
+ self.panes = {}
+ pane_index = 0
+ pane_index = self.new_pane(self._get_terminal_canvas,pane_index)
+ pane_index = self.new_pane(self._get_edit_canvas,pane_index)
+ #pane_index = self.new_pane(self._get_child_canvas,pane_index)
+ pane_index = self.new_pane(self._get_project_canvas,pane_index)
+ pane_index = self.new_pane(self._get_help_canvas,pane_index)
+
+ nb = gtk.Notebook()
+ nb.show()
+ nb.set_show_tabs(False)
+
+ for c in self.canvas_list:
+ nb.append_page(c)
+
+ self.pydebug_notebook = nb
+ #the following call to the activity code puts our notebook under the stock toolbar
+ self.set_canvas(nb)
+
+ #set up tool box/menu buttons
+ self.toolbox = pytoolbar.ActivityToolbox(self)
+ self.toolbox.connect('current_toolbar_changed',self._toolbar_changed_cb)
+
+ activity_toolbar = self.toolbox.get_activity_toolbar()
+ activity_toolbar.share.props.visible = True
+ activity_toolbar.keep.props.visible = True
+
+ separator = gtk.SeparatorToolItem()
+ separator.set_draw(True)
+ separator.show()
+ activity_toolbar.insert(separator, 0)
+
+ activity_go = ToolButton()
+ activity_go.set_stock_id('gtk-media-forward')
+ activity_go.set_icon_widget(None)
+ activity_go.set_tooltip(_('Start Debugging'))
+ activity_go.connect('clicked', self._read_file_cb)
+ #activity_go.props.accelerator = '<Ctrl>O'
+ activity_go.show()
+ activity_toolbar.insert(activity_go, 0)
+
+
+ activity_copy_tb = ToolButton('edit-copy')
+ activity_copy_tb.set_tooltip(_('Copy'))
+ activity_copy_tb.connect('clicked', self._copy_cb)
+ #activity_copy_tb.props.accelerator = '<Ctrl>C'
+ activity_toolbar.insert(activity_copy_tb, 3)
+ activity_copy_tb.show()
+
+ activity_paste_tb = ToolButton('edit-paste')
+ activity_paste_tb.set_tooltip(_('Paste'))
+ activity_paste_tb.connect('clicked', self._paste_cb)
+ #activity_paste_tb.props.accelerator = '<Ctrl>V'
+ activity_toolbar.insert(activity_paste_tb, 4)
+ activity_paste_tb.show()
+
+ activity_tab_tb = sugar.graphics.toolbutton.ToolButton('list-add')
+ activity_tab_tb.set_tooltip(_("Open New Tab"))
+ activity_tab_tb.props.accelerator = '<Ctrl>T'
+ activity_tab_tb.show()
+ activity_tab_tb.connect('clicked', self._open_tab_cb)
+ activity_toolbar.insert(activity_tab_tb, 5)
+
+ activity_tab_delete_tv = sugar.graphics.toolbutton.ToolButton('list-remove')
+ activity_tab_delete_tv.set_tooltip(_("Close Tab"))
+ activity_tab_delete_tv.props.accelerator = '<Ctrl><Shift>X'
+ activity_tab_delete_tv.show()
+ activity_tab_delete_tv.connect('clicked', self._close_tab_cb)
+ activity_toolbar.insert(activity_tab_delete_tv, 6)
+
+
+ activity_fullscreen_tb = sugar.graphics.toolbutton.ToolButton('view-fullscreen')
+ activity_fullscreen_tb.set_tooltip(_("Fullscreen"))
+ activity_fullscreen_tb.props.accelerator = '<Alt>Enter'
+ activity_fullscreen_tb.connect('clicked', self._fullscreen_cb)
+ activity_toolbar.insert(activity_fullscreen_tb, 7)
+ activity_fullscreen_tb.hide()
+
+ #Add editor functionality to the debugger
+ editbar = gtk.Toolbar()
+
+ editopen = ToolButton()
+ editopen.set_stock_id('gtk-new')
+ editopen.set_icon_widget(None)
+ editopen.set_tooltip(_('New File'))
+ editopen.connect('clicked', self._read_file_cb)
+ #editopen.props.accelerator = '<Ctrl>O'
+ editopen.show()
+ editbar.insert(editopen, -1)
+
+ editfile = ToolButton()
+ editfile.set_stock_id('gtk-open')
+ editfile.set_icon_widget(None)
+ editfile.set_tooltip(_('Open File'))
+ editfile.connect('clicked', self._read_file_cb)
+ editfile.props.accelerator = '<Ctrl>O'
+ editfile.show()
+ editbar.insert(editfile, -1)
+
+ editsave = ToolButton()
+ editsave.set_stock_id('gtk-save')
+ editsave.set_icon_widget(None)
+ editsave.set_tooltip(_('Save File'))
+ editsave.props.accelerator = '<Ctrl>S'
+ editsave.connect('clicked', self.save_cb)
+ editsave.show()
+ editbar.insert(editsave, -1)
+
+ editsaveas = ToolButton()
+ editsaveas.set_stock_id('gtk-save-as')
+ editsaveas.set_icon_widget(None)
+ editsaveas.set_tooltip(_('Save As'))
+ #editsaveas.props.accelerator = '<Ctrl>S'
+ editsaveas.connect('clicked', self.save_file_cb)
+ editsaveas.show()
+ editbar.insert(editsaveas, -1)
+
+
+ """
+ editjournal = ToolButton(tooltip=_('Open Journal'))
+ client = gconf.client_get_default()
+ color = XoColor(client.get_string('/desktop/sugar/user/color'))
+ journal_icon = Icon(icon_name='document-save', xo_color=color)
+ editjournal.set_icon_widget(journal_icon)
+ editjournal.connect('clicked', self._show_journal_object_picker_cb)
+ editjournal.props.accelerator = '<Ctrl>J'
+ editjournal.show()
+ editbar.insert(editjournal, -1)
+ """
+
+ separator = gtk.SeparatorToolItem()
+ separator.set_draw(True)
+ separator.show()
+ editbar.insert(separator, -1)
+
+ editundo = ToolButton('undo')
+ editundo.set_tooltip(_('Undo'))
+ editundo.connect('clicked', self.editor.undo)
+ editundo.props.accelerator = '<Ctrl>Z'
+ editundo.show()
+ editbar.insert(editundo, -1)
+
+ editredo = ToolButton('redo')
+ editredo.set_tooltip(_('Redo'))
+ editredo.connect('clicked', self.editor.redo)
+ editredo.props.accelerator = '<Ctrl>Y'
+ editredo.show()
+ editbar.insert(editredo, -1)
+
+ separator = gtk.SeparatorToolItem()
+ separator.set_draw(True)
+ separator.show()
+ editbar.insert(separator, -1)
+
+ editcut = ToolButton()
+ editcut.set_stock_id('gtk-cut')
+ editcut.set_icon_widget(None)
+ editcut.set_tooltip(_('Cut'))
+ self.edit_cut_handler_id = editcut.connect('clicked', self.editor.cut)
+ editcut.props.accelerator = '<Ctrl>X'
+ editbar.insert(editcut, -1)
+ editcut.show()
+
+ editcopy = ToolButton('edit-copy')
+ editcopy.set_tooltip(_('Copy'))
+ self.edit_copy_handler_id = editcopy.connect('clicked', self.editor.copy)
+ editcopy.props.accelerator = '<Ctrl>C'
+ editbar.insert(editcopy, -1)
+ editcopy.show()
+
+ editpaste = ToolButton('edit-paste')
+ editpaste.set_tooltip(_('Paste'))
+ self.edit_paste_handler_id = editpaste.connect('clicked', self.editor.paste)
+ editpaste.props.accelerator = '<Ctrl>V'
+ editpaste.show()
+ editbar.insert(editpaste, -1)
+
+ separator = gtk.SeparatorToolItem()
+ separator.set_draw(True)
+ separator.show()
+ editbar.insert(separator, -1)
+
+ editfind = ToolButton('viewmag1')
+ editfind.set_tooltip(_('Find and Replace'))
+ editfind.connect('clicked', self.show_find)
+ editfind.props.accelerator = '<Ctrl>F'
+ editfind.show()
+ editbar.insert(editfind, -1)
+
+ separator = gtk.SeparatorToolItem()
+ separator.set_draw(True)
+ separator.show()
+ editbar.insert(separator, -1)
+
+ self.zoomout = ToolButton('zoom-out')
+ self.zoomout.set_tooltip(_('Zoom out'))
+ self.zoomout.connect('clicked', self.__zoomout_clicked_cb)
+ editbar.insert(self.zoomout, -1)
+ self.zoomout.show()
+
+ self.zoomin = ToolButton('zoom-in')
+ self.zoomin.set_tooltip(_('Zoom in'))
+ self.zoomin.connect('clicked', self.__zoomin_clicked_cb)
+ editbar.insert(self.zoomin, -1)
+ self.zoomin.show()
+
+ editbar.show_all()
+ self.toolbox.add_toolbar(_('Edit'), editbar)
+
+ #childbar = gtk.Toolbar()
+ #childbar.show_all()
+ #self.toolbox.add_toolbar(_('Your Program'), childbar)
+
+ project_run = ToolButton()
+ project_run.set_stock_id('gtk-media-forward')
+ project_run.set_icon_widget(None)
+ project_run.set_tooltip(_('Start Debugging'))
+ project_run.connect('clicked', self.project_run_cb)
+ #project_run.props.accelerator = '<Ctrl>C'
+ project_run.show()
+
+ projectbar = gtk.Toolbar()
+ projectbar.show_all()
+ projectbar.insert(project_run, -1)
+ self.toolbox.add_toolbar(_('Project'), projectbar)
+
+ #self.help = Help(self)
+ helpbar = self.get_help_toolbar()
+ self.toolbox.add_toolbar(_('Help'), helpbar)
+
+
+ self.set_toolbox(self.toolbox)
+ self.toolbox.show()
+
+ #set the default contents for edit
+ self.font_size = self.debug_dict.get('font_size',8)
+
+
+ self.get_config ()
+
+ #set which PANE is visible initially
+ self.set_visible_canvas(self.panes['PROJECT'])
+ self.set_toolbar(self.panes['PROJECT'])
+ self.non_blocking_server()
+ #glib.idle_add(self.non_blocking_server)
+ self.setup_project_page()
+ _logger.debug('child path for program to be debugged is %r\nUser Id:%s'%(self.child_path,os.geteuid()))
+
+ #create the terminal tabs, start up the socket between 1st and 2nd terminal instances
+ self.setup_terminal()
+
+
+ def __stop_clicked_cb(self,button):
+ _logger('caught stop clicked call back')
+ self.close(skip_save = True)
+
+ def __zoomin_clicked_cb(self,button):
+ self.font_size += 1
+ self.editor.change_font_size(self.font_size)
+ self.debug_dict['font_size'] = self.font_size
+
+ def __zoomout_clicked_cb(self,botton):
+ self.font_size -= 1
+ self.editor.change_font_size(self.font_size)
+ self.debug_dict['font_size'] = self.font_size
+
+ #this code will probably be deleted
+ def non_blocking_server(self):
+ start_threaded_server()
+ """
+ if self.sock == None:
+ self.sock = create_listener_socket(DEFAULT_PORT)
+ self.sock.setblocking(0)
+ rlist, wlist, slist = select.select([self.sock],[],[],0)
+ try:
+ if bool(rlist):
+ self.conn = Connection(self.sock)
+ self.conn.poll()
+ self.conn.close()
+ except:
+ pass
+ return True #continue the call backs
+ """
+
+ def new_pane(self,funct,i):
+ self.panes[PANES[i]] = i
+ self.canvas_list.append(funct())
+ i += 1
+ return i
+ """
+ def _get_debug_page(self):
+ n = self.pydebug_notebook.get_current_page()
+ return self.pydebug_notebook.get_nth_page(n)
+ """
+
+ def make_paths(self):
+ self.pydebug_path = os.environ['SUGAR_BUNDLE_PATH']
+ p_path = os.environ['SUGAR_BUNDLE_PATH']
+ if not os.environ.get("PYTHONPATH",'') == '':
+ p_path = p_path + ':'
+ os.environ['PYTHONPATH'] = p_path + os.environ.get("PYTHONPATH",'')
+ _logger.debug('sugar_bundle_path:%s\nsugar_activity_root:%s'%(os.environ['SUGAR_BUNDLE_PATH'],
+ os.environ['SUGAR_ACTIVITY_ROOT']))
+ self.debugger_home = os.path.join(os.environ['SUGAR_ACTIVITY_ROOT'],'data')
+
+ os.environ["HOME"]=self.debugger_home
+ os.environ['PATH'] = os.path.join(self.pydebug_path,'bin:') + os.environ['PATH']
+ self.storage = os.path.join(os.environ['SUGAR_ACTIVITY_ROOT'],'data/pydebug')
+ self.sugar_bundle_path = os.environ['SUGAR_BUNDLE_PATH']
+ self.activity_playpen = os.path.join(self.storage,'playpen')
+ if not os.path.isdir(self.activity_playpen):
+ os.makedirs(self.activity_playpen)
+ """
+ loaded_list = os.listdir(self.activity_playpen)
+ basename = []
+ for f in loaded_list:
+ if f.startswith('.'):continue
+ if not f.endswith('.activity'):continue
+ basename.append(f) #if more than one pick the last
+ #when activity is loaded, child_path endswith '.activity' and is sub-dir of playpen
+ if basename != '':
+ self.child_path = os.path.join(self.activity_playpen,basename)
+ else:
+ self.child_path = None
+ #os.chdir(self.activity_playpen)
+ """
+
+ def _get_edit_canvas(self):
+ self.editor = sourceview_editor.GtkSourceview2Editor(self)
+ return self.editor
+
+ def setup_terminal(self):
+ os.environ['IPYTHONDIR'] = self.pydebug_path
+ _logger.debug('Set IPYTHONDIR to %s'%self.pydebug_path)
+ self._create_tab({'cwd':self.sugar_bundle_path})
+ self._create_tab({'cwd':self.sugar_bundle_path})
+ #start the debugger user interface
+ alias_cmd = 'alias go="%s"\n'%('./bin/ipython.py',)
+ self.feed_virtual_terminal(0,alias_cmd)
+
+ self.feed_virtual_terminal(0,'./bin/ipython.py \n')
+ #cmd = 'run ' + os.path.join(self.sugar_bundle_path,'bin','start_debug.py') + '\n'
+ #self.feed_virtual_terminal(0,cmd)
+
+
+ def start_debugging(self): #check for a start up script in bundle root or bundle_root/bin
+ command = self.activity_dict.get('command','')
+ if command == '':
+ self.alert('No Activity Loaded')
+ return
+ _logger.debug("Command to execute:%s."%command)
+ self.editor.save_all()
+
+ #try to restore a clean debugging environment
+ #self.feed_virtual_terminal(0,'quit()\r\n\r\n')
+
+ self.set_visible_canvas(self.panes['TERMINAL'])
+ #change the menus
+ self.toolbox.set_current_toolbar(self.panes['TERMINAL'])
+ message = _('\n\n Use the HELP in the Ipython interpreter to learn to DEBUG your program.\n')
+ self.message_terminal(0,message)
+
+ #get the ipython shell object
+ """ this works but is not needed now
+ ip = ipapi.get()
+ arg_str = 'run -d -b %s %s'%(self.pydebug_path,self.child_path)
+ ip.user_ns['go'] = arg_str
+ _logger.debug('about to use "%s" to start ipython debugger\n'%(arg_str))
+ """
+ self.feed_virtual_terminal(0,'go\n')
+
+ def find_import(self,fn):
+ _logger.debug('find_import in file %s'%fn)
+ try_fn = os.path.join(self.child_path,fn)
+ if not os.path.isfile(try_fn):
+ try_fn += '.py'
+ if not os.path.isfile(try_fn):
+ _logger.debug('in find_import, failed to find file %s'%try_fn)
+ return
+ line_no = 0
+ for line in open(try_fn,'r'):
+ if line.startswith('import'):
+ return line_no, try_fn
+ line_no += 1
+ return -1, None
+
+ def _get_child_canvas(self):
+ fr = gtk.Frame()
+ label = gtk.Label("This page will be replaced with the \noutput from your program")
+ label.show()
+ fr.add(label)
+ fr.show()
+ return fr
+
+
+ def get_icon_pixbuf(self, stock):
+ return self.treeview.render_icon(stock_id=getattr(gtk, stock),
+ size=gtk.ICON_SIZE_MENU,
+ detail=None)
+
+
+
+ def _get_help_canvas(self):
+ fr = gtk.Frame() #FIXME explore whether frame is still needed--was to fix webview problem
+ fr.show()
+ nb = gtk.Notebook()
+ nb.show()
+ fr.add(nb)
+ nb.append_page(self.get_first_webview())
+ self.help_notebook = nb
+ return fr
+
+
+ def _child_cb(self,event):
+ pass
+
+ def _project_cb(self,event):
+ pass
+
+ #lots of state to change whenever one of the major tabs is clicked
+ def set_visible_canvas(self,index): #track the toolbox tab clicks
+ self.pydebug_notebook.set_current_page(index)
+ if index == self.panes['TERMINAL']:
+ self.set_terminal_focus()
+ self.editor.save_all()
+ self.current_pd_page = index
+
+ def _toolbar_changed_cb(self,widget,tab_no):
+ _logger.debug('tool tab changed notification %d'%tab_no)
+ self.set_visible_canvas(tab_no)
+
+ def set_toolbar(self,page_no):
+ self.toolbox.set_current_toolbar(page_no)
+
+ def key_press_cb(self,widget,event):
+ state = event.get_state()
+ if state and gtk.gdk.SHIFT_MASK and gtk.gdk.CONTROL_MASK and gtk.gdk.MOD1_MASK == 0:
+ self.file_changed = True
+ #put a star in front of the filename
+ return False
+
+ ### following routines are copied from develop_app for use with sourceview_editor
+ def _replace_cb(self, button=None):
+ ftext = self._search_entry.props.text
+ rtext = self._replace_entry.props.text
+ _logger.debug('replace %s with %s usiing options %r'%(ftext,rtext,self.s_opts))
+ replaced, found = self.editor.replace(ftext, rtext,
+ self.s_opts)
+ if found:
+ self._replace_button.set_sensitive(True)
+
+ def _search_entry_activated_cb(self, entry):
+ text = self._search_entry.props.text
+ if text:
+ self._findnext_cb(None)
+
+ def _search_entry_changed_cb(self, entry):
+ self.safe_to_replace = False
+ text = self._search_entry.props.text
+ if not text:
+ self._findprev.set_sensitive(False)
+ self._findnext.set_sensitive(False)
+ else:
+ self._findprev.set_sensitive(True)
+ self._findnext.set_sensitive(True)
+ if not self.s_opts.use_regex: #do not do partial searches for regex
+ if self.editor.find_next(text,
+ SearchOptions(self.s_opts,
+ stay=True,
+ where=(self.s_opts.where if
+ self.s_opts.where != S_WHERE.multifile
+ else S_WHERE.file))):
+ #no multifile, or focus gets grabbed
+ self._replace_button.set_sensitive(True)
+
+ def _replace_entry_changed_cb(self, entry):
+ if self._replace_entry.props.text:
+ self.safe_to_replace = True
+
+ def _findprev_cb(self, button=None):
+ ftext = self._search_entry.props.text
+ if ftext:
+ if self.editor.find_next(ftext,
+ SearchOptions(self.s_opts,
+ forward=False)):
+ self._replace_button.set_sensitive(True)
+
+ def _findnext_cb(self, button=None):
+ ftext = self._search_entry.props.text
+ _logger.debug('find next %s'%ftext)
+ if ftext:
+ if self.editor.find_next(ftext, self.s_opts):
+ self._replace_button.set_sensitive(True)
+ self.editor.set_focus()
+
+
+ def show_find(self,button):
+ self.find_window = self.wTree.get_widget("find")
+ self.find_window.show()
+ self.find_window.connect('destroy',self.close_find_window)
+ self.find_connect()
+ self.find_window.set_title(_('FIND OR REPLACE'))
+ self.find_window.set_size_request(400, 200)
+ self.find_window.set_decorated(True)
+ self.find_window.set_resizable(True)
+ self.find_window.set_modal(False)
+ #self.find_window.set_position(gtk.WIN_POS_CENTER_ALWAYS)
+ self.find_window.set_border_width(10)
+
+
+ def find_connect(self):
+ mdict = {
+ 'find_close_clicked_cb':self.close_find_window,
+ 'find_entry_changed_cb':self.find_entry_changed_cb,
+ 'replace_entry_changed_cb':self.replace_entry_changed_cb,
+ 'find_previous_clicked_cb':self._findprev_cb,
+ 'find_next_clicked_cb':self._findnext_cb,
+ 'find_entry_changed_cb':self._search_entry_changed_cb,
+ 'replace_entry_changed_cb':self._replace_entry_changed_cb,
+ 'replace_clicked_cb':self._replace_cb,
+ #'replace_all_clicked_cb':self._findprev_cb,
+ }
+ self.wTree.signal_autoconnect(mdict)
+ self._findnext = self.wTree.get_widget("find_next")
+ self._findprev = self.wTree.get_widget("find_previous")
+ self._search_entry = self.wTree.get_widget("find_entry")
+ self._replace_entry = self.wTree.get_widget("replace_entry")
+ self._replace_button = self.wTree.get_widget("replace")
+ #self.replace_all = self.wTree.get_widget("replace_all")
+ self.find_where = self.wTree.get_widget("find_where")
+
+
+ def close_find_window(self,button):
+ self.find_window.hide()
+
+ def delete_event(self,widget,event):
+ if widget == self.find_window:
+ self.find_window.hide()
+ return True
+
+ def find_entry_changed_cb(self,button):
+ #self.editor.search_for =
+ pass
+ def replace_entry_changed_cb(self,button):
+ #self.editor.search_for =
+ pass
+
+ def project_run_cb(self,button):
+ _logger.debug('entered project_run_cb')
+ """
+ start_script = ['python','import sys','from Rpyc import *','from Rpyc.Utils import remote_interpreter',
+ 'c = SocketConnection("localhost")','remote_interpreter(c)']
+ for l in start_script:
+ self.feed_virtual_terminal(0,l+'\r\n')
+ """
+ self.start_debugging()
+
+
+
+
+ ###### SUGAR defined read and write routines -- do not let them overwrite what's on disk
+
+ def read_file(self, file_path):
+ interesting_keys = ['mtime','mime_type','package','checksum','title','timestamp','icon-color','uid']
+ for key in interesting_keys:
+ if self.metadata.has_key(key):
+ self.activity_dict[key] = self.metadata[key]
+ _logger.debug('RELOADING ACTIVITY DATA...Mime_type:%s. File_path:%s.'%(self.metadata['mime_type'],
+ file_path))
+ debugstr = ''
+ for key in self.activity_dict.keys():
+ debugstr += key + ':'+str(self.activity_dict[key]) + ', '
+ _logger.debug ('In read_file: activity dictionary==> %s'%debugstr)
+ return
+
+ def write_file(self, file_path):
+ """
+ The paradigm designed into the XO, ie an automatic load from the Journal at activity startup
+ does not make sense during a debugging session. An errant stack overflow can easily crash
+ the system and require a reboot. For the session manager to overwrite the changes that are stored
+ on disk, but not yet saved in the journal is highly undesireable. So we'll let the user save to
+ the journal, and perhaps optionally to the sd card (because it is removable, should the system die)
+ """
+ _logger.debug('write file object_id: %s'%self.debug_dict['jobject_id'])
+ self._jobject.metadata['title'] = 'PyDebug'
+ datastore.write(self._jobject)
+ self.write_activity_info()
+ self.put_config()
+ return
+
+ def write_binary_to_datastore(self):
+ """
+ Check to see if there is a child loaded.
+ Then copy the home directory data for this application into the bundle
+ then bundle it up and write it to the journal
+ lastly serialize the project information and write it to the journal
+ """
+ _logger.debug('Entered write_binary_to_datastore with child_path:%s'%self.child_path)
+ if not (os.path.isdir(self.child_path) and self.child_path.split('.')[-1:][0] == 'activity'):
+ self.alert(_('No Program loaded'))
+ return
+ dsobject = datastore.create()
+ dsobject.metadata['mime_type'] = 'binary'
+
+ #copy the home directory config stuff into the bundle
+ home_dir = os.path.join(self.child_path,'HOME')
+ try:
+ os.rmtree(home_dir)
+ except:
+ pass
+ try:
+ os.mkdir(home_dir)
+ except:
+ pass
+ source = self.debugger_home
+ dest = os.path.join(self.child_path,'HOME')
+ _logger.debug('writing HOME info from %s to %s.'%(source,dest))
+ for f in os.listdir(self.debugger_home):
+ if f == '.': continue
+ if f == '..': continue
+ if f == 'pydebug': continue
+ if f == '.sugar': continue
+ try:
+ if os.path.isdir(f):
+ shutil.copytree(f,dest)
+ else:
+ shutil.copy(f,dest)
+ except:
+ pass
+
+ #create the manifest for the bundle
+ try:
+ os.remove(os.path.join(self.child_path,'MANIFEST'))
+ except:
+ pass
+ dest = self.child_path
+ _logger.debug('Writing manifest to %s.'%(dest))
+ config = bundlebuilder.Config(dest)
+ b = bundlebuilder.Builder(config)
+ try:
+ b.fix_manifest()
+ except:
+ _logger.debug('fix manifest error: ',sys.exc_type,sys.exc_info[0],sys.exc_info[1])
+
+ #actually write the xo file
+ packager = bundlebuilder.XOPackager(bundlebuilder.Builder(config))
+ packager.package()
+ source = os.path.join(self.child_path,'dist',str(config.xo_name))
+ dest = os.path.join(self.get_activity_root(),'instance',str(config.xo_name))
+ _logger.debug('writing to the journal from %s to %s.'%(source,dest))
+ try:
+ shutil.copy(source,dest)
+ except IOError:
+ _logger.debug('shutil.copy error %d: %s. ',IOError[0],IOError[1])
+ #try:
+ dsobject.metadata['package'] = config.xo_name
+ dsobject.metadata['title'] = config.xo_name #_('PyDebug Zipped app')
+ dsobject.metadata['mime_type'] = 'binary'
+ dsobject.metadata['activity'] = 'org.laptop.PyDebug'
+ dsobject.metadata['icon'] = self.debug_dict.get('icon','')
+ #calculate and store the new md5sum
+ self.debug_dict['tree_md5'] = self.md5sum_tree(self.child_path)
+ dsobject.metadata['tree_md5'] = self.debug_dict['tree_md5']
+ dsobject.set_file_path(dest)
+
+ #actually make the call which writes to the journal
+ datastore.write(dsobject,transfer_ownership=True)
+ _logger.debug('succesfully wrote to the journal from %s.'%(dest))
+ #update the project display
+ self.journal_class = DataStoreTree(self,self.journal_treeview,self.wTree)
+
+ def load_activity_to_playpen(self,file_path):
+ """loads from a disk tree"""
+ self._new_child_path = os.path.join(self.activity_playpen,os.path.basename(file_path))
+ _logger.debug('copying file for %s to %s'%(file_path,self._new_child_path))
+ self._load_playpen(file_path)
+
+ def try_to_load_from_journal(self,object_id):
+ """
+ loads a zipped XO application file, asks whether it is ok to
+ delete/overwrite path if the md5 has changed.
+ """
+ self.ds = datastore.get(object_id[0])
+ if not self.ds:
+ _logger.debug('failed to get datastore object with id:%s'%object_id[0])
+ return
+ dsdict=self.ds.get_metadata()
+ file_name_from_ds = self.ds.get_file_path()
+ project = dsdict.get('package','')
+ if not project.endswith('.xo'):
+ self.alert(_('This journal item does not appear to be a zipped activity. Package:%s.'%project))
+ self.ds.destroy()
+ self.ds = None
+ return
+ filestat = os.stat(file_name_from_ds)
+ size = filestat.st_size
+
+ _logger.debug('In try_to_load_from_journal. Object_id %s. File_path %s. Size:%s'%(object_id[0], file_name_from_ds, size))
+ try:
+ self._bundler = ActivityBundle(file_name_from_ds)
+ except:
+ self.alert('Error: Malformed Activity Bundle')
+ self.ds.destroy()
+ self.ds = None
+ return
+ self._new_child_path = os.path.join(self.activity_playpen,self._bundler.get_name()+'.activity')
+ self._load_playpen(file_name_from_ds, iszip=True)
+
+ def _load_playpen(self,source_fn, iszip = False):
+ """entry point for both xo and file tree sources"""
+ self.iszip = iszip
+ self._load_to_playpen_source = source_fn
+ if self.child_path and os.path.isdir(self.child_path):
+ #check to see if it has been modified
+ stored_hash = self.debug_dict.get('tree_md5','')
+ if stored_hash != '' and stored_hash != self.md5sum_tree(self.child_path):
+ self.confirmation_alert(_('The currently loaded %s project in the playpen has been changed.'%os.path.basename(self.child_path)),_('Ok to abandon changes?'),self._clear_playpen_cb)
+ return
+ self._clear_playpen_cb(None,None)
+
+ def _clear_playpen_cb(self,alert, response):
+ #if necessary clean up contents of playpen
+ if alert != None: self.remove_alert(alert)
+ if self.child_path and os.path.isdir(self.child_path):
+ self.abandon_changes = True
+ self.debug_dict['tree_md5'] = ''
+ self.debug_dict['child_path'] = ''
+ self.editor.remove_all()
+ if self.child_path:
+ shutil.rmtree(self.child_path)
+ self.abandon_changes = False
+ if self._load_to_playpen_source == None:
+ #having done the clearing, just stop
+ return
+ if self.iszip:
+ self._bundler.install(self.activity_playpen)
+ if self.ds: self.ds.destroy()
+ self.ds = None
+ else:
+ if os.path.isdir(self._new_child_path):
+ shutil.rmtree(self._new_child_path)
+ shutil.copytree(self._load_to_playpen_source,self._new_child_path)
+ self.debug_dict['source_tree'] = self._load_to_playpen_source
+ self.child_path = self._new_child_path
+ self.setup_new_activity()
+
+ def setup_new_activity(self):
+ if self.child_path == None:
+ return
+ _logger.debug('child path before chdir:%s'%self.child_path)
+ os.chdir(self.child_path)
+ self.read_activity_info(self.child_path)
+ self.display_current_project()
+
+ #add the bin directory to path
+ os.environ['PATH'] = os.path.join(self.child_path,'bin') + ':' + os.environ['PATH']
+
+ #calculate and store the md5sum
+ self.debug_dict['tree_md5'] = self.md5sum_tree(self.child_path)
+
+ #find largest python files for editor
+ list = [f for f in os.listdir(self.child_path) if f[0] <> '.']
+ #list = self.manifest_class.get_filenames_list(self.child_path)
+ if not list: return
+ sizes = []
+ for f in list:
+ full_path = os.path.join(self.child_path,f)
+ if not f.endswith('.py'):continue
+ size = self.manifest_class.file_size(full_path)
+ sizes.append((size,full_path,))
+ #_logger.debug('python file "%s size %d'%(f,size))
+ for s,f in sorted(sizes,reverse=True)[:5]:
+ self.editor.load_object(f,os.path.basename(f))
+ self.editor.set_current_page(0)
+
+ ##################### ALERT ROUTINES ##################################
+
+ def alert(self,msg,title=None):
+ alert = NotifyAlert(10)
+ if title != None:
+ alert.props.title=_('There is no Activity file')
+ alert.props.msg = msg
+ alert.connect('response',self.no_file_cb)
+ self.add_alert(alert)
+
+ def no_file_cb(self,alert,response_id):
+ self.remove_alert(alert)
+
+ from sugar.graphics.alert import ConfirmationAlert
+
+ def confirmation_alert(self,msg,title=None,confirmation_cb = None):
+ alert = ConfirmationAlert()
+ alert.props.title=title
+ alert.props.msg = msg
+ alert.pydebug_cb = confirmation_cb
+ alert.connect('response', self._alert_response_cb)
+ self.add_alert(alert)
+
+ #### Method: _alert_response_cb, called when an alert object throws a
+ #response event.
+ def _alert_response_cb(self, alert, response_id):
+ #remove the alert from the screen, since either a response button
+ #was clicked or there was a timeout
+ this_alert = alert #keep a reference to it
+ self.remove_alert(alert)
+ #Do any work that is specific to the type of button clicked.
+ if response_id is gtk.RESPONSE_OK and this_alert.pydebug_cb != None:
+ this_alert.pydebug_cb (this_alert, response_id)
+
+
+ def _read_file_cb(self,widget):
+ _logger.debug('Reading a file into editor')
+ dialog = gtk.FileChooserDialog("Open..",
+ None,
+ gtk.FILE_CHOOSER_ACTION_OPEN,
+ (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
+ gtk.STOCK_OPEN, gtk.RESPONSE_OK))
+ dialog.set_default_response(gtk.RESPONSE_OK)
+ if self.last_filename == None:
+ self.last_filename = self.child_path
+ dialog.set_current_folder(os.path.dirname(self.last_filename))
+
+ filter = gtk.FileFilter()
+ filter.set_name("All files")
+ filter.add_pattern("*")
+ dialog.add_filter(filter)
+
+ filter = gtk.FileFilter()
+ filter.set_name("Python")
+ filter.add_pattern("*.py")
+ dialog.add_filter(filter)
+
+ filter = gtk.FileFilter()
+ filter.set_name("Activity")
+ filter.add_pattern("*.xo")
+ dialog.add_filter(filter)
+
+ response = dialog.run()
+ if response == gtk.RESPONSE_OK:
+ _logger.debug(dialog.get_filename(), 'selected')
+ fname = dialog.get_filename()
+ self.last_filename = fname
+ self.editor.load_object(fname,os.path.basename(fname))
+ elif response == gtk.RESPONSE_CANCEL:
+ _logger.debug( 'File chooseer closed, no files selected')
+ dialog.destroy()
+
+ def save_file_cb(self, button):
+ chooser = gtk.FileChooserDialog(title=None,action=gtk.FILE_CHOOSER_ACTION_SAVE,
+ buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_SAVE,
+ gtk.RESPONSE_OK))
+ file_path = self.editor.get_full_path()
+ _logger.debug('Saving file %s'%(file_path))
+ chooser.set_filename(file_path)
+ response = chooser.run()
+ new_fn = chooser.get_filename()
+ chooser.destroy()
+ if response == gtk.RESPONSE_CANCEL:
+ return
+ if response == gtk.RESPONSE_OK:
+ self.save_cb(None,new_fn)
+
+ def save_cb(self,button,new_fn=None):
+ if new_fn and not new_fn.startswith(self.child_root):
+ self.alert(_('You can only write %s to subdirectories of %s'%(os.path.basename(new_fn),
+ self.child_root,)))
+ return
+ page = self.editor._get_page()
+ if new_fn:
+ page.fullPath = new_fn
+ page.save(skip_md5 = True)
+ else:
+ page.save()
+ self.editor.clear_changed_star()
+ page.save_hash()
+
+ def set_dirty(self, dirty):
+ self.dirty = dirty
+
+ def md5sum_buffer(self, buffer, hash = None):
+ if hash == None:
+ hash = hashlib.md5()
+ hash.update(buffer)
+ return hash.hexdigest()
+
+ def md5sum(self, filename, hash = None):
+ h = self._md5sum(filename,hash)
+ return h.hexdigest()
+
+ def _md5sum(self, filename, hash = None):
+ if hash == None:
+ hash = hashlib.md5()
+ try:
+ fd = None
+ fd = open(filename, 'rb')
+ while True:
+ block = fd.read(128)
+ if not block: break
+ hash.update(block)
+ finally:
+ if fd != None:
+ fd.close()
+ return hash
+
+ def md5sum_tree(self,root):
+ if not os.path.isdir(root):
+ return None
+ h = hashlib.md5()
+ for dirpath, dirnames, filenames in os.walk(root):
+ for filename in filenames:
+ abs_path = os.path.join(dirpath, filename)
+ h = self._md5sum(abs_path,h)
+ #print abs_path
+ return h.hexdigest()
+
+
+
+ ############## Following code services the Project page #####################
+
+ def _get_project_canvas(self):
+ #initialize the link between program and the glade XML file
+ self.wTree=gtk.glade.XML(os.path.join(self.sugar_bundle_path,"project.glade"))
+ self.contents = self.wTree.get_widget("contents")
+ self.contents.unparent()
+ return self.contents
+
+ def setup_project_page(self):
+ self.activity_treeview = self.wTree.get_widget('file_system')
+ self.activity_window = FileTree(self, self.activity_treeview,self.wTree)
+ self.activity_window.set_file_sys_root('/home/olpc/Activities')
+ self.examples_treeview = self.wTree.get_widget('examples')
+ self.examples_window = FileTree(self, self.examples_treeview,self.wTree)
+ self.examples_window.set_file_sys_root(os.path.join(self.sugar_bundle_path,'examples'))
+ self.journal_treeview = self.wTree.get_widget('journal')
+ self.journal_class = DataStoreTree(self,self.journal_treeview,self.wTree)
+ self.connect_object() #make connections to signals from buttons
+ self.activity_toggled_cb(None)
+ if self.child_path and self.child_path.endswith('.activity') and \
+ os.path.isdir(self.child_path):
+ self.setup_new_activity()
+
+ def display_current_project(self):
+ self.manifest_treeview = self.wTree.get_widget('manifest')
+ self.manifest_class = FileTree(self, self.manifest_treeview,self.wTree)
+ if self.child_path:
+ self.manifest_class.set_file_sys_root(self.child_path)
+ else:
+ self.manifest_class.set_file_sys_root(self.activity_playpen)
+
+ self.wTree.get_widget('name').set_text(self.activity_dict.get('name',''))
+ self.wTree.get_widget('version').set_text(self.activity_dict.get('version',''))
+ self.wTree.get_widget('bundle_id').set_text(self.activity_dict.get('bundle_id',''))
+ self.wTree.get_widget('class').set_text(self.activity_dict.get('class',''))
+ self.wTree.get_widget('module').set_text(self.activity_dict.get('module',''))
+ """
+ self.wTree.get_widget('home_save').set_text(self.activity_dict.get('home_save',''))
+ self.wTree.get_widget('host').set_text(self.debug_dict.get('host',''))
+ self.wTree.get_widget('port').set_text(str(self.debug_dict.get('port','')))
+ activity_size = os.system('du --max-depth=0')
+ self.wTree.get_widget('activity_size').set_text(str(activity_size))
+ self.wTree.get_widget('icon').set_text(self.activity_dict.get('icon','').split('/')[-1:][0])
+ """
+
+ def manifest_point_to(self,fullpath):
+ if self.child_path:
+ self.manifest_class.set_file_sys_root(self.child_path)
+ else:
+ self.manifest_class.set_file_sys_root(self.activity_playpen)
+ self.manifest_class.position_to(fullpath)
+
+ #first connect the glade xml file to the servicing call backs
+ def connect_object(self, wTree=None):
+ """if wTree:
+ self.wTree=wTree
+ if self.wTree:"""
+ mdict = {
+ 'name_changed_cb':self.name_changed_cb,
+ 'bundle_id_changed_cb':self.bundle_id_changed_cb,
+ 'class_changed_cb':self.class_changed_cb,
+ 'icon_changed_cb':self.icon_changed_cb,
+ 'version_changed_cb':self.version_changed_cb,
+ 'file_toggle_clicked_cb':self.activity_toggled_cb,
+ 'to_activities_clicked_cb':self.to_home_clicked_cb,
+ 'from_activities_clicked_cb':self.from_home_clicked_cb,
+ 'from_examples_clicked_cb':self.from_examples_clicked_cb,
+ 'run_clicked_cb':self.project_run_cb,
+ 'delete_file_clicked_cb':self.delete_file_cb,
+ }
+ self.wTree.signal_autoconnect(mdict)
+ button = self.wTree.get_widget('file_toggle')
+ button.set_tooltip_text(_('Switch views between the "Installed" Activities directory and your "home" storage directory'))
+ button = self.wTree.get_widget('to_activities')
+ button.set_tooltip_text(_('Copy the files in the debug workplace to your "home" storage directory'))
+ button = self.wTree.get_widget('from_examples')
+ button.set_tooltip_text(_('Load and modify these example programs. See the help Tutorials'))
+
+
+ def name_changed_cb(self, widget):
+ self.activity_dict['name'] = widget.get_text()
+
+ def bundle_id_changed_cb(self,widget):
+ self.activity_dict['bundle_id'] = widget.get_text()
+
+ def class_changed_cb(self, widget):
+ self.activity_dict['class'] = widget.get_text()
+
+ def icon_changed_cb(self, widget):
+ self.activity_dict['icon'] = widget.get_text()
+
+ def version_changed_cb(self, widget):
+ self.activity_dict['version'] = widget.get_text()
+
+ def activity_toggled_cb(self, widget):
+ _logger.debug('Entered activity_toggled_cb. Button: %r'%self.file_pane_is_activities)
+ but = self.wTree.get_widget('to_activities')
+ to_what = self.wTree.get_widget('file_toggle')
+ window_label = self.wTree.get_widget('file_system_label')
+ if self.file_pane_is_activities == True:
+ to_what.set_label('Installed')
+ but.show()
+ display_label = self.storage[:18]+' . . . '+self.storage[-24:]
+ self.activity_window.set_file_sys_root(self.storage)
+ button = self.wTree.get_widget('from_activities')
+ button.set_tooltip_text(_('Copy the selected directory from your "home" storage to the debug workplace'))
+ window_label.set_text(display_label)
+ else:
+ to_what.set_label('home')
+ but.hide()
+ self.activity_window.set_file_sys_root('/home/olpc/Activities')
+ button = self.wTree.get_widget('from_activities')
+ button.set_tooltip_text(_('Copy the selected Activity to the debug workplace and start debugging'))
+ window_label.set_text('/home/olpc/Activities')
+ self.file_pane_is_activities = not self.file_pane_is_activities
+
+ def to_home_clicked_cb(self,widget):
+ _logger.debug('Entered to_home_clicked_cb')
+ self._to_home_dest = os.path.join(self.storage,self.activity_dict['name']+'.activity')
+ if os.path.isdir(self._to_home_dest):
+ target_md5sum = self.md5sum_tree(self._to_home_dest)
+ if target_md5sum != self.debug_dict.get('tree_md5',''):
+ self.confirmation_alert(_('OK to delete/overwrite %s?'%self._to_home_dest),
+ _('This destination has been changed by another application'),
+ self._to_home_cb)
+ return
+ self._to_home_cb( None, gtk.RESPONSE_OK)
+
+ def _to_home_cb(self, alert, response_id):
+ if alert != None: self.remove_alert(alert)
+ if response_id is gtk.RESPONSE_OK:
+ cmd = ['rsync','-av',self.child_path,self._to_home_dest]
+ _logger.debug('do to_home_cb with cmd:%s'%cmd)
+ p1 = Popen(cmd,stdout=PIPE)
+ output = p1.communicate()
+ if p1.returncode != 0:
+ self.alert('rsync command returned non zero\n'+output[0]+ 'COPY FAILURE')
+ return
+ #redraw the treeview
+ self.activity_window.set_file_sys_root(self.storage)
+
+ def from_home_clicked_cb(self,widget):
+ _logger.debug('Entered from_home_clicked_cb')
+ selection=self.activity_treeview.get_selection()
+ (model,iter)=selection.get_selected()
+ if iter == None:
+ self.alert(_('Must select File or Directory item to Load'))
+ return
+ fullpath = model.get(iter,4)[0]
+ if os.path.isdir(fullpath):
+ if not fullpath.endswith('.activity'):
+ self.alert(_('Use this button for Activities or Files'),
+ _('ERROR: This folder name does not end with ".activity"'))
+ return
+ self.load_activity_to_playpen(fullpath)
+ else:
+ #selected is a file, just copy it into the current project
+ basename = os.path.basename(fullpath)
+ if os.path.isfile(os.path.join(self.child_path,basename)):
+ #change name if necessary to prevent collision
+ basename = self.non_conflicting(self.child_path,basename)
+ shutil.copy(fullpath,os.path.join(self.child_path,basename))
+ self.manifest_point_to(os.path.join(self.child_path,basename))
+
+ def non_conflicting(self,root,basename):
+ """
+ create a non-conflicting filename by adding '-<number>' to a filename before extension
+ """
+ ext = ''
+ basename = basename.split('.')
+ word = basename[0]
+ if len(basename) > 1:
+ ext = basename[1]
+ adder = ''
+ index = 0
+ while os.path.isfile(os.path.join(root,word+adder+'.'+ext)):
+ index +=1
+ adder = '-%s'%index
+ return os.path.join(root,word+adder+'.'+ext)
+
+ def from_examples_clicked_cb(self,widget):
+ _logger.debug('Entered from_examples_clicked_cb')
+ selection=self.examples_treeview.get_selection()
+ (model,iter)=selection.get_selected()
+ if iter == None:
+ self.alert(_('Must select File or Directory item to Load'))
+ return
+ fullpath = model.get(iter,4)[0]
+ if fullpath.endswith('.activity'):
+ self.load_activity_to_playpen(fullpath)
+ return
+ self._load_to_playpen_source = fullpath
+ try:
+ self._bundler = ActivityBundle(fullpath)
+ except:
+ self.alert('Error: Malformed Activity Bundle')
+ return
+
+ self._new_child_path = os.path.join(self.activity_playpen,self._bundler._zip_root_dir)
+ #check to see if current activity in playpen needs to be saved, and load new activity if save is ok
+ self._load_playpen(fullpath, iszip=True)
+
+ def filetree_activated(self):
+ _logger.debug('entered pydebug filetree_activated')
+
+ def read_activity_info(self, path):
+ """
+ Parses the ./activity/activity.info file
+
+ filen = os.path.join(self.child_path,'activity','activity.info')
+ try:
+ fd = open(filen,'r')
+ except:
+ _logger.debug('failed to open %s'%filen)
+ return
+ for line in fd.readlines():
+ if line.lstrip() == '': continue
+ _logger.debug('activity line %s'%line)
+ tokens = line.split('=')
+
+ if len(tokens) > 1:
+ keyword = tokens[0].lower().rstrip()
+ rside = tokens[1].split()
+ if keyword == 'class':
+ if '.' in rside[0]:
+ self.activity_dict['class'] = rside[0].split('.')[1]
+ self.activity_dict['module'] = rside[0].split('.')[0]
+ elif keyword == 'exec':
+ if rside[0] == 'sugar-activity' and '.' in rside[1]:
+ self.activity_dict['class'] = rside[1].split('.')[1]
+ self.activity_dict['module'] = rside[1].split('.')[0]
+ else:
+ self.activity_dict['module'] = rside[0]
+ elif keyword == 'bundle_id' or keyword == 'service_name':
+ self.activity_dict['bundle_id'] = rside[0]
+ elif keyword == 'activity_version':
+ self.activity_dict['version'] = rside[0]
+ elif keyword == 'name':
+ self.activity_dict['name'] = rside[0]
+ elif keyword == 'icon':
+ self.activity_dict['icon'] = rside[0]
+ fd.close()
+
+ debugstr = ''
+ for key in self.activity_dict.keys():
+ debugstr += key + ':'+str(self.activity_dict[key]) + ', '
+ _logger.debug ('In read_activity: activity dictionary==> %s'%debugstr)
+ """
+ try:
+ bundle = ActivityBundle(path)
+ except:
+ msg = _('%s not recognized by ActivityBundle parser. Does activity/activity.info exist?'
+ %os.path.basename(path))
+ self.alert(msg)
+ return #maybe should issue an alert here
+ self.activity_dict['version'] = str(bundle.get_activity_version())
+ self.activity_dict['name'] = bundle.get_name()
+ self.activity_dict['bundle_id'] = bundle.get_bundle_id()
+ self.activity_dict['command'] = bundle.get_command()
+ cmd_args = activityfactory.get_command(bundle)
+ mod_class = cmd_args[1]
+ if '.' in mod_class:
+ self.activity_dict['class'] = mod_class.split('.')[1]
+ self.activity_dict['module'] = mod_class.split('.')[0]
+ self.activity_dict['icon'] = bundle.get_icon()
+
+ def write_activity_info(self):
+ #write the activity.info file
+ _logger.debug('entered write_actiity_info')
+ filen = os.path.join(self.child_path,'activity','activity.info')
+ #try:
+ with open(filen,'r') as fd:
+ #and also write to a new file
+ filewr = os.path.join(self.child_path,'activity','activity.new')
+ #try:
+ with open(filewr,'w') as fdw:
+ #write the required lines
+ _logger.debug('writing activity info to %s'%filewr)
+ fdw.write('[Activity]\n')
+ fdw.write('name = %s\n'%self.activity_dict.get('name'))
+ fdw.write('bundle_id = %s\n'%self.activity_dict.get('bundle_id'))
+ fdw.write('activity_version = %s\n'%self.activity_dict.get('version'))
+ icon = self.activity_dict.get('icon')[len(self.child_path)+10:-4]
+ fdw.write('icon = %s\n'%icon)
+ if self.activity_dict.get('class','') == '':
+ fdw.write('exec = %s\n'%self.activity_dict.get('module'))
+ else:
+ fdw.write('class = %s.%s\n'%(self.activity_dict.get('module'),
+ self.activity_dict.get('class')))
+ #pass the rest of the input to the output
+ passup = ('[activity]','exec','activity_version','name','bundle_id',
+ 'service_name','icon','class')
+ for line in fd.readlines():
+ tokens = line.split('=')
+ keyword = tokens[0].lower().rstrip()
+ if keyword in passup: continue
+ fdw.write(line)
+ """
+ except EnvironmentError:
+ _logger.debug('failed to open %s for writing. msg:%s'%(filewr,EnvironmentError[1]))
+
+ except EnvironmentError:
+ _logger.debug('failed to open %s msg:%s'%(filen,EnvironmentError[1]))
+ """
+
+ def delete_file_cb(self,widget):
+ selection=self.manifest_treeview.get_selection()
+ (model,iter)=selection.get_selected()
+ if iter == None:
+ self.alert(_('Must select File delete'))
+ return
+ fullpath = model.get(iter,4)[0]
+ _logger.debug(' delete_file_clicked_cb. File: %s'%os.path.basename(fullpath))
+ self.delete_file_storage = fullpath
+ if os.path.isdir(fullpath):
+ self.alert(_('Use the terminal "rm -rf <directory> --CAREFULLY','Cannot delete Folders!'))
+ return
+ self.confirmation_alert(_('Would you like to continue deleting %s?'%os.path.basename(fullpath)),
+ _('ABOUT TO DELETE A FILE!!'),self.do_delete)
+
+ def do_delete(self, alert, response):
+ _logger.debug('doing delete of: %s'%self.delete_file_storage)
+ self.manifest_point_to(self.delete_file_storage)
+ os.unlink(self.delete_file_storage)
+ self.manifest_class.set_file_sys_root(self.child_path)
+ self.manifest_class.position_recent()
+
+ ################ save config state from one invocation to another -- not activity state
+ def get_config(self):
+ try:
+ fd = open(os.path.join(self.debugger_home,'pickl'),'rb')
+ local = pickle.load(fd)
+ self.debug_dict = local.copy()
+ _logger.debug('unpickled successfully')
+ """
+ object_id = self.debug_dict.get('jobject_id','')
+ if object_id != '':
+ self._jobject = datastore.get(object_id)
+ else:
+ self._jobject = None
+ """
+ except:
+ try:
+ fd = open(os.path.join(self.debugger_home,'pickl'),'wb')
+ self.debug_dict['host'] = 'localhost'
+ self.debug_dict['port'] = 18812
+ self.debug_dict['autosave'] = True
+ self.debug_dict['child_path'] = ''
+ local = self.debug_dict.copy()
+ pickle.dump(local,fd,pickle.HIGHEST_PROTOCOL)
+ except IOError:
+ _logger.debug('get_config -- Error writing pickle file %s'
+ %os.path.join(self.debugger_home,'pickl'))
+ finally:
+ fd.close()
+ object_id = self.debug_dict.get('jobject_id','')
+ if object_id == '':
+ jobject = datastore.create()
+ jobject.metadata['title'] = 'PyDebug'
+ jobject.metadata['keep'] = '1'
+ jobject.metadata['preview'] = ''
+ self._jobject = jobject
+ datastore.write(self._jobject)
+ #self.metadata = jobject.metadata
+ self.debug_dict['jobject_id'] = str(self.metadata['uid'])
+ _logger.debug('in get_config created jobject id:%s'%self.debug_dict['jobject_id'])
+ else:
+ self._jobject = datastore.get(object_id)
+ self.child_path = self.debug_dict.get('child_path','')
+ if self.child_path == '' or not os.path.isdir(self.child_path):
+ self.child_path = None
+ """
+ debugstr = ''
+ for key in self.debug_dict.keys():
+ debugstr += key + ':'+str(self.debug_dict[key]) + ', '
+ _logger.debug ('In get_config: debug dictionary==> %s'%debugstr)
+ """
+ if self.child_path and self.debug_dict.get('tree_md5',''):
+ if self.debug_dict.get('tree_md5','') == self.md5sum_tree(self.child_path):
+ self.setup_new_activity()
+ #the tree is valid so take up where we left off
+ else:
+ self.confirmation_alert(_('Continue even though stored checksum does not match current checksum'),
+ _('CAUTION: The program in the playpen may have been changed.'),
+ self.startup_continue)
+
+ def startup_continue(self,alert,response):
+ self.setup_new_activity()
+
+ def put_config(self):
+ if self.child_path:
+ self.debug_dict['tree_md5'] = self.md5sum_tree(self.child_path)
+ self.debug_dict['child_path'] = self.child_path
+ try:
+ fd = open(os.path.join(self.debugger_home,'pickl'),'wb')
+ local = self.debug_dict.copy()
+ pickle.dump(local,fd,pickle.HIGHEST_PROTOCOL)
+ except IOError:
+ _logger.debug('put_config routine Error writing pickle file %s'
+ %os.path.join(self.debugger_home,'pickl'))
+ return
+ finally:
+ fd.close()
+ debugstr = ''
+ return
+ for key in self.debug_dict.keys():
+ debugstr += key + ':'+str(self.debug_dict[key]) + ', '
+ _logger.debug ('In put_config: debug dictionary==> %s'%debugstr)
+
diff --git a/pydebug.py~ b/pydebug.py~
new file mode 100644
index 0000000..588e3e1
--- /dev/null
+++ b/pydebug.py~
@@ -0,0 +1,1478 @@
+# Copyright (C) 2009, George Hunt <georgejhunt@gmail.com>
+# Copyright (C) 2009, One Laptop Per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+from __future__ import with_statement
+import os, os.path, simplejson, ConfigParser, shutil, sys
+from subprocess import Popen
+
+from gettext import gettext as _
+
+#major packages
+import gtk
+import gtk.glade
+import vte
+import pango
+import gconf
+#import glib
+import pickle
+import hashlib
+import time
+
+#sugar stuff
+from sugar.graphics.toolbutton import ToolButton
+import sugar.graphics.toolbutton
+
+import sugar.env
+from sugar.graphics.xocolor import XoColor
+from sugar.graphics.icon import Icon
+from sugar.graphics.objectchooser import ObjectChooser
+from sugar.datastore import datastore
+from sugar.graphics.alert import *
+import sugar.activity.bundlebuilder as bundlebuilder
+from sugar.bundle.activitybundle import ActivityBundle
+from sugar.activity import activityfactory
+
+#application stuff
+from terminal_pd import Terminal
+#public api for ipython
+
+#from IPython.core import ipapi 0.11 requires this
+from IPython import ipapi
+
+#from sourceview import SourceViewPd
+import sourceview_editor
+from sugar.activity.activity import Activity
+from help_pd import Help
+
+#following taken from Rpyc module
+#import Rpyc
+from Rpyc.Utils.Serving import start_threaded_server, DEFAULT_PORT
+from Rpyc.Connection import *
+from Rpyc.Stream import *
+import select
+from filetree import FileTree
+from datastoretree import DataStoreTree
+import pytoolbar
+#from pytoolbar import ActivityToolBox
+
+import logging
+from pydebug_logging import _logger, log_environment
+
+MASKED_ENVIRONMENT = [
+ 'DBUS_SESSION_BUS_ADDRESS',
+ 'PPID'
+]
+#PANES = ['TERMINAL','EDITOR','CHILD','PROJECT','HELP']
+PANES = ['TERMINAL','EDITOR','PROJECT','HELP']
+
+#global module variable communicates to debugged programs
+pydebug_instance = None
+
+#following options taken from Develop_App
+class Options:
+ def __init__(self, template = None, **kw):
+ if template:
+ self.__dict__ = template.__dict__.copy()
+ else:
+ self.__dict__ = {}
+ self.__dict__.update(kw)
+
+class SearchOptions(Options):
+ pass
+S_WHERE = sourceview_editor.S_WHERE
+
+class PyDebugActivity(Activity,Terminal,Help):
+ MIME_TYPE = 'application/vnd.olpc-sugar'
+ DEPRECATED_MIME_TYPE = 'application/vnd.olpc-x-sugar'
+ _zipped_extension = '.xo'
+ _unzipped_extension = '.activity'
+ dirty = False
+
+ def __init__(self, handle):
+ _logger.debug('Activity id:%s.Object id: %s. uri:%s'%(handle.activity_id, handle.object_id, handle.uri))
+ #Save a global poiinter so remote procedure calls can communicate with pydebug
+ global pydebug_instance
+ pydebug_instance = self
+
+ #init variables
+ self.make_paths()
+
+ self.source_directory = None
+ self.data_file = None
+ self.help = None
+ self.project_dirty = False
+ self.sock = None
+ self.last_filename = None
+ self.debug_dict = {}
+ self.activity_dict = {}
+ self.file_pane_is_activities = False
+ self.manifest_treeview = None #set up to recognize an re-display of playpen
+ self.set_title(_('PyDebug Activity'))
+ self.ds = None #datastore pointer
+ self._logger = _logger
+ self.traceback = 'Context'
+ self.abandon_changes = False
+
+ # init the Classes we are subclassing
+ Activity.__init__(self, handle, create_jobject = False)
+ #Terminal has no needs for init
+ Help.__init__(self,self)
+
+ # setup the search options
+ self.s_opts = SearchOptions(where = S_WHERE.multifile,
+ use_regex = False,
+ ignore_caps = True,
+ replace_all = False,
+
+ #defaults to avoid creating
+ #a new SearchOptions object for normal searches
+ #should never be changed, just make a copy like:
+ #SearchOptions(self.s_opts, forward=False)
+ forward = True,
+ stay = False
+ )
+ self.safe_to_replace = False
+
+
+ #set up the PANES for the different functions of the debugger
+ self.canvas_list = []
+ self.panes = {}
+ pane_index = 0
+ pane_index = self.new_pane(self._get_terminal_canvas,pane_index)
+ pane_index = self.new_pane(self._get_edit_canvas,pane_index)
+ #pane_index = self.new_pane(self._get_child_canvas,pane_index)
+ pane_index = self.new_pane(self._get_project_canvas,pane_index)
+ pane_index = self.new_pane(self._get_help_canvas,pane_index)
+
+ nb = gtk.Notebook()
+ nb.show()
+ nb.set_show_tabs(False)
+
+ for c in self.canvas_list:
+ nb.append_page(c)
+
+ self.pydebug_notebook = nb
+ #the following call to the activity code puts our notebook under the stock toolbar
+ self.set_canvas(nb)
+
+ #set up tool box/menu buttons
+ self.toolbox = pytoolbar.ActivityToolbox(self)
+ self.toolbox.connect('current_toolbar_changed',self._toolbar_changed_cb)
+
+ activity_toolbar = self.toolbox.get_activity_toolbar()
+ activity_toolbar.share.props.visible = True
+ activity_toolbar.keep.props.visible = True
+
+ separator = gtk.SeparatorToolItem()
+ separator.set_draw(True)
+ separator.show()
+ activity_toolbar.insert(separator, 0)
+
+ activity_go = ToolButton()
+ activity_go.set_stock_id('gtk-media-forward')
+ activity_go.set_icon_widget(None)
+ activity_go.set_tooltip(_('Start Debugging'))
+ activity_go.connect('clicked', self._read_file_cb)
+ #activity_go.props.accelerator = '<Ctrl>O'
+ activity_go.show()
+ activity_toolbar.insert(activity_go, 0)
+
+
+ activity_copy_tb = ToolButton('edit-copy')
+ activity_copy_tb.set_tooltip(_('Copy'))
+ activity_copy_tb.connect('clicked', self._copy_cb)
+ #activity_copy_tb.props.accelerator = '<Ctrl>C'
+ activity_toolbar.insert(activity_copy_tb, 3)
+ activity_copy_tb.show()
+
+ activity_paste_tb = ToolButton('edit-paste')
+ activity_paste_tb.set_tooltip(_('Paste'))
+ activity_paste_tb.connect('clicked', self._paste_cb)
+ #activity_paste_tb.props.accelerator = '<Ctrl>V'
+ activity_toolbar.insert(activity_paste_tb, 4)
+ activity_paste_tb.show()
+
+ activity_tab_tb = sugar.graphics.toolbutton.ToolButton('list-add')
+ activity_tab_tb.set_tooltip(_("Open New Tab"))
+ activity_tab_tb.props.accelerator = '<Ctrl>T'
+ activity_tab_tb.show()
+ activity_tab_tb.connect('clicked', self._open_tab_cb)
+ activity_toolbar.insert(activity_tab_tb, 5)
+
+ activity_tab_delete_tv = sugar.graphics.toolbutton.ToolButton('list-remove')
+ activity_tab_delete_tv.set_tooltip(_("Close Tab"))
+ activity_tab_delete_tv.props.accelerator = '<Ctrl><Shift>X'
+ activity_tab_delete_tv.show()
+ activity_tab_delete_tv.connect('clicked', self._close_tab_cb)
+ activity_toolbar.insert(activity_tab_delete_tv, 6)
+
+
+ activity_fullscreen_tb = sugar.graphics.toolbutton.ToolButton('view-fullscreen')
+ activity_fullscreen_tb.set_tooltip(_("Fullscreen"))
+ activity_fullscreen_tb.props.accelerator = '<Alt>Enter'
+ activity_fullscreen_tb.connect('clicked', self._fullscreen_cb)
+ activity_toolbar.insert(activity_fullscreen_tb, 7)
+ activity_fullscreen_tb.hide()
+
+ #Add editor functionality to the debugger
+ editbar = gtk.Toolbar()
+
+ editopen = ToolButton()
+ editopen.set_stock_id('gtk-new')
+ editopen.set_icon_widget(None)
+ editopen.set_tooltip(_('New File'))
+ editopen.connect('clicked', self._read_file_cb)
+ #editopen.props.accelerator = '<Ctrl>O'
+ editopen.show()
+ editbar.insert(editopen, -1)
+
+ editfile = ToolButton()
+ editfile.set_stock_id('gtk-open')
+ editfile.set_icon_widget(None)
+ editfile.set_tooltip(_('Open File'))
+ editfile.connect('clicked', self._read_file_cb)
+ editfile.props.accelerator = '<Ctrl>O'
+ editfile.show()
+ editbar.insert(editfile, -1)
+
+ editsave = ToolButton()
+ editsave.set_stock_id('gtk-save')
+ editsave.set_icon_widget(None)
+ editsave.set_tooltip(_('Save File'))
+ editsave.props.accelerator = '<Ctrl>S'
+ editsave.connect('clicked', self.save_cb)
+ editsave.show()
+ editbar.insert(editsave, -1)
+
+ editsaveas = ToolButton()
+ editsaveas.set_stock_id('gtk-save-as')
+ editsaveas.set_icon_widget(None)
+ editsaveas.set_tooltip(_('Save As'))
+ #editsaveas.props.accelerator = '<Ctrl>S'
+ editsaveas.connect('clicked', self.save_file_cb)
+ editsaveas.show()
+ editbar.insert(editsaveas, -1)
+
+
+ """
+ editjournal = ToolButton(tooltip=_('Open Journal'))
+ client = gconf.client_get_default()
+ color = XoColor(client.get_string('/desktop/sugar/user/color'))
+ journal_icon = Icon(icon_name='document-save', xo_color=color)
+ editjournal.set_icon_widget(journal_icon)
+ editjournal.connect('clicked', self._show_journal_object_picker_cb)
+ editjournal.props.accelerator = '<Ctrl>J'
+ editjournal.show()
+ editbar.insert(editjournal, -1)
+ """
+
+ separator = gtk.SeparatorToolItem()
+ separator.set_draw(True)
+ separator.show()
+ editbar.insert(separator, -1)
+
+ editundo = ToolButton('undo')
+ editundo.set_tooltip(_('Undo'))
+ editundo.connect('clicked', self.editor.undo)
+ editundo.props.accelerator = '<Ctrl>Z'
+ editundo.show()
+ editbar.insert(editundo, -1)
+
+ editredo = ToolButton('redo')
+ editredo.set_tooltip(_('Redo'))
+ editredo.connect('clicked', self.editor.redo)
+ editredo.props.accelerator = '<Ctrl>Y'
+ editredo.show()
+ editbar.insert(editredo, -1)
+
+ separator = gtk.SeparatorToolItem()
+ separator.set_draw(True)
+ separator.show()
+ editbar.insert(separator, -1)
+
+ editcut = ToolButton()
+ editcut.set_stock_id('gtk-cut')
+ editcut.set_icon_widget(None)
+ editcut.set_tooltip(_('Cut'))
+ self.edit_cut_handler_id = editcut.connect('clicked', self.editor.cut)
+ editcut.props.accelerator = '<Ctrl>X'
+ editbar.insert(editcut, -1)
+ editcut.show()
+
+ editcopy = ToolButton('edit-copy')
+ editcopy.set_tooltip(_('Copy'))
+ self.edit_copy_handler_id = editcopy.connect('clicked', self.editor.copy)
+ editcopy.props.accelerator = '<Ctrl>C'
+ editbar.insert(editcopy, -1)
+ editcopy.show()
+
+ editpaste = ToolButton('edit-paste')
+ editpaste.set_tooltip(_('Paste'))
+ self.edit_paste_handler_id = editpaste.connect('clicked', self.editor.paste)
+ editpaste.props.accelerator = '<Ctrl>V'
+ editpaste.show()
+ editbar.insert(editpaste, -1)
+
+ separator = gtk.SeparatorToolItem()
+ separator.set_draw(True)
+ separator.show()
+ editbar.insert(separator, -1)
+
+ editfind = ToolButton('viewmag1')
+ editfind.set_tooltip(_('Find and Replace'))
+ editfind.connect('clicked', self.show_find)
+ editfind.props.accelerator = '<Ctrl>F'
+ editfind.show()
+ editbar.insert(editfind, -1)
+
+ separator = gtk.SeparatorToolItem()
+ separator.set_draw(True)
+ separator.show()
+ editbar.insert(separator, -1)
+
+ self.zoomout = ToolButton('zoom-out')
+ self.zoomout.set_tooltip(_('Zoom out'))
+ self.zoomout.connect('clicked', self.__zoomout_clicked_cb)
+ editbar.insert(self.zoomout, -1)
+ self.zoomout.show()
+
+ self.zoomin = ToolButton('zoom-in')
+ self.zoomin.set_tooltip(_('Zoom in'))
+ self.zoomin.connect('clicked', self.__zoomin_clicked_cb)
+ editbar.insert(self.zoomin, -1)
+ self.zoomin.show()
+
+ editbar.show_all()
+ self.toolbox.add_toolbar(_('Edit'), editbar)
+
+ #childbar = gtk.Toolbar()
+ #childbar.show_all()
+ #self.toolbox.add_toolbar(_('Your Program'), childbar)
+
+ project_run = ToolButton()
+ project_run.set_stock_id('gtk-media-forward')
+ project_run.set_icon_widget(None)
+ project_run.set_tooltip(_('Start Debugging'))
+ project_run.connect('clicked', self.project_run_cb)
+ #project_run.props.accelerator = '<Ctrl>C'
+ project_run.show()
+
+ projectbar = gtk.Toolbar()
+ projectbar.show_all()
+ projectbar.insert(project_run, -1)
+ self.toolbox.add_toolbar(_('Project'), projectbar)
+
+ #self.help = Help(self)
+ helpbar = self.get_help_toolbar()
+ self.toolbox.add_toolbar(_('Help'), helpbar)
+
+
+ self.set_toolbox(self.toolbox)
+ self.toolbox.show()
+
+ #set the default contents for edit
+ self.font_size = self.debug_dict.get('font_size',8)
+
+
+ self.get_config ()
+
+ #set which PANE is visible initially
+ self.set_visible_canvas(self.panes['PROJECT'])
+ self.set_toolbar(self.panes['PROJECT'])
+ self.non_blocking_server()
+ #glib.idle_add(self.non_blocking_server)
+ self.setup_project_page()
+ _logger.debug('child path for program to be debugged is %r\nUser Id:%s'%(self.child_path,os.geteuid()))
+
+ #create the terminal tabs, start up the socket between 1st and 2nd terminal instances
+ self.setup_terminal()
+
+
+ def __stop_clicked_cb(self,button):
+ _logger('caught stop clicked call back')
+ self.close(skip_save = True)
+
+ def __zoomin_clicked_cb(self,button):
+ self.font_size += 1
+ self.editor.change_font_size(self.font_size)
+ self.debug_dict['font_size'] = self.font_size
+
+ def __zoomout_clicked_cb(self,botton):
+ self.font_size -= 1
+ self.editor.change_font_size(self.font_size)
+ self.debug_dict['font_size'] = self.font_size
+
+ #this code will probably be deleted
+ def non_blocking_server(self):
+ start_threaded_server()
+ """
+ if self.sock == None:
+ self.sock = create_listener_socket(DEFAULT_PORT)
+ self.sock.setblocking(0)
+ rlist, wlist, slist = select.select([self.sock],[],[],0)
+ try:
+ if bool(rlist):
+ self.conn = Connection(self.sock)
+ self.conn.poll()
+ self.conn.close()
+ except:
+ pass
+ return True #continue the call backs
+ """
+
+ def new_pane(self,funct,i):
+ self.panes[PANES[i]] = i
+ self.canvas_list.append(funct())
+ i += 1
+ return i
+ """
+ def _get_debug_page(self):
+ n = self.pydebug_notebook.get_current_page()
+ return self.pydebug_notebook.get_nth_page(n)
+ """
+
+ def make_paths(self):
+ self.pydebug_path = os.environ['SUGAR_BUNDLE_PATH']
+ p_path = os.environ['SUGAR_BUNDLE_PATH']
+ if not os.environ.get("PYTHONPATH",'') == '':
+ p_path = p_path + ':'
+ os.environ['PYTHONPATH'] = p_path + os.environ.get("PYTHONPATH",'')
+ _logger.debug('sugar_bundle_path:%s\nsugar_activity_root:%s'%(os.environ['SUGAR_BUNDLE_PATH'],
+ os.environ['SUGAR_ACTIVITY_ROOT']))
+ self.debugger_home = os.path.join(os.environ['SUGAR_ACTIVITY_ROOT'],'data')
+
+ os.environ["HOME"]=self.debugger_home
+ os.environ['PATH'] = os.path.join(self.pydebug_path,'bin:') + os.environ['PATH']
+ self.storage = os.path.join(os.environ['SUGAR_ACTIVITY_ROOT'],'data/pydebug')
+ self.sugar_bundle_path = os.environ['SUGAR_BUNDLE_PATH']
+ self.activity_playpen = os.path.join(self.storage,'playpen')
+ if not os.path.isdir(self.activity_playpen):
+ os.makedirs(self.activity_playpen)
+ """
+ loaded_list = os.listdir(self.activity_playpen)
+ basename = []
+ for f in loaded_list:
+ if f.startswith('.'):continue
+ if not f.endswith('.activity'):continue
+ basename.append(f) #if more than one pick the last
+ #when activity is loaded, child_path endswith '.activity' and is sub-dir of playpen
+ if basename != '':
+ self.child_path = os.path.join(self.activity_playpen,basename)
+ else:
+ self.child_path = None
+ #os.chdir(self.activity_playpen)
+ """
+
+ def _get_edit_canvas(self):
+ self.editor = sourceview_editor.GtkSourceview2Editor(self)
+ return self.editor
+
+ def setup_terminal(self):
+ os.environ['IPYTHONDIR'] = self.pydebug_path
+ _logger.debug('Set IPYTHONDIR to %s'%self.pydebug_path)
+ self._create_tab({'cwd':self.sugar_bundle_path})
+ self._create_tab({'cwd':self.sugar_bundle_path})
+ #start the debugger user interface
+ alias_cmd = 'alias go="%s"\n'%('./bin/ipython.py',)
+ self.feed_virtual_terminal(0,alias_cmd)
+
+ self.feed_virtual_terminal(0,'./bin/ipython.py \n')
+ #cmd = 'run ' + os.path.join(self.sugar_bundle_path,'bin','start_debug.py') + '\n'
+ #self.feed_virtual_terminal(0,cmd)
+
+
+ def start_debugging(self): #check for a start up script in bundle root or bundle_root/bin
+ command = self.activity_dict.get('command','')
+ if command == '':
+ self.alert('No Activity Loaded')
+ return
+ _logger.debug("Command to execute:%s."%command)
+ self.editor.save_all()
+
+ #try to restore a clean debugging environment
+ #self.feed_virtual_terminal(0,'quit()\r\n\r\n')
+
+ self.set_visible_canvas(self.panes['TERMINAL'])
+ #change the menus
+ self.toolbox.set_current_toolbar(self.panes['TERMINAL'])
+ message = _('\n\n Use the HELP in the Ipython interpreter to learn to DEBUG your program.\n')
+ self.message_terminal(0,message)
+
+ #get the ipython shell object
+ """ this works but is not needed now
+ ip = ipapi.get()
+ arg_str = 'run -d -b %s %s'%(self.pydebug_path,self.child_path)
+ ip.user_ns['go'] = arg_str
+ _logger.debug('about to use "%s" to start ipython debugger\n'%(arg_str))
+ """
+ self.feed_virtual_terminal(0,'go\n')
+
+ def find_import(self,fn):
+ _logger.debug('find_import in file %s'%fn)
+ try_fn = os.path.join(self.child_path,fn)
+ if not os.path.isfile(try_fn):
+ try_fn += '.py'
+ if not os.path.isfile(try_fn):
+ _logger.debug('in find_import, failed to find file %s'%try_fn)
+ return
+ line_no = 0
+ for line in open(try_fn,'r'):
+ if line.startswith('import'):
+ return line_no, try_fn
+ line_no += 1
+ return -1, None
+
+ def _get_child_canvas(self):
+ fr = gtk.Frame()
+ label = gtk.Label("This page will be replaced with the \noutput from your program")
+ label.show()
+ fr.add(label)
+ fr.show()
+ return fr
+
+
+ def get_icon_pixbuf(self, stock):
+ return self.treeview.render_icon(stock_id=getattr(gtk, stock),
+ size=gtk.ICON_SIZE_MENU,
+ detail=None)
+
+
+
+ def _get_help_canvas(self):
+ fr = gtk.Frame() #FIXME explore whether frame is still needed--was to fix webview problem
+ fr.show()
+ nb = gtk.Notebook()
+ nb.show()
+ fr.add(nb)
+ nb.append_page(self.get_first_webview())
+ self.help_notebook = nb
+ return fr
+
+
+ def _child_cb(self,event):
+ pass
+
+ def _project_cb(self,event):
+ pass
+
+ #lots of state to change whenever one of the major tabs is clicked
+ def set_visible_canvas(self,index): #track the toolbox tab clicks
+ self.pydebug_notebook.set_current_page(index)
+ if index == self.panes['TERMINAL']:
+ self.set_terminal_focus()
+ self.editor.save_all()
+ self.current_pd_page = index
+
+ def _toolbar_changed_cb(self,widget,tab_no):
+ _logger.debug('tool tab changed notification %d'%tab_no)
+ self.set_visible_canvas(tab_no)
+
+ def set_toolbar(self,page_no):
+ self.toolbox.set_current_toolbar(page_no)
+
+ def key_press_cb(self,widget,event):
+ state = event.get_state()
+ if state and gtk.gdk.SHIFT_MASK and gtk.gdk.CONTROL_MASK and gtk.gdk.MOD1_MASK == 0:
+ self.file_changed = True
+ #put a star in front of the filename
+ return False
+
+ ### following routines are copied from develop_app for use with sourceview_editor
+ def _replace_cb(self, button=None):
+ ftext = self._search_entry.props.text
+ rtext = self._replace_entry.props.text
+ _logger.debug('replace %s with %s usiing options %r'%(ftext,rtext,self.s_opts))
+ replaced, found = self.editor.replace(ftext, rtext,
+ self.s_opts)
+ if found:
+ self._replace_button.set_sensitive(True)
+
+ def _search_entry_activated_cb(self, entry):
+ text = self._search_entry.props.text
+ if text:
+ self._findnext_cb(None)
+
+ def _search_entry_changed_cb(self, entry):
+ self.safe_to_replace = False
+ text = self._search_entry.props.text
+ if not text:
+ self._findprev.set_sensitive(False)
+ self._findnext.set_sensitive(False)
+ else:
+ self._findprev.set_sensitive(True)
+ self._findnext.set_sensitive(True)
+ if not self.s_opts.use_regex: #do not do partial searches for regex
+ if self.editor.find_next(text,
+ SearchOptions(self.s_opts,
+ stay=True,
+ where=(self.s_opts.where if
+ self.s_opts.where != S_WHERE.multifile
+ else S_WHERE.file))):
+ #no multifile, or focus gets grabbed
+ self._replace_button.set_sensitive(True)
+
+ def _replace_entry_changed_cb(self, entry):
+ if self._replace_entry.props.text:
+ self.safe_to_replace = True
+
+ def _findprev_cb(self, button=None):
+ ftext = self._search_entry.props.text
+ if ftext:
+ if self.editor.find_next(ftext,
+ SearchOptions(self.s_opts,
+ forward=False)):
+ self._replace_button.set_sensitive(True)
+
+ def _findnext_cb(self, button=None):
+ ftext = self._search_entry.props.text
+ _logger.debug('find next %s'%ftext)
+ if ftext:
+ if self.editor.find_next(ftext, self.s_opts):
+ self._replace_button.set_sensitive(True)
+ self.editor.set_focus()
+
+
+ def show_find(self,button):
+ self.find_window = self.wTree.get_widget("find")
+ self.find_window.show()
+ self.find_window.connect('destroy',self.close_find_window)
+ self.find_connect()
+ self.find_window.set_title(_('FIND OR REPLACE'))
+ self.find_window.set_size_request(400, 200)
+ self.find_window.set_decorated(True)
+ self.find_window.set_resizable(True)
+ self.find_window.set_modal(False)
+ #self.find_window.set_position(gtk.WIN_POS_CENTER_ALWAYS)
+ self.find_window.set_border_width(10)
+
+
+ def find_connect(self):
+ mdict = {
+ 'find_close_clicked_cb':self.close_find_window,
+ 'find_entry_changed_cb':self.find_entry_changed_cb,
+ 'replace_entry_changed_cb':self.replace_entry_changed_cb,
+ 'find_previous_clicked_cb':self._findprev_cb,
+ 'find_next_clicked_cb':self._findnext_cb,
+ 'find_entry_changed_cb':self._search_entry_changed_cb,
+ 'replace_entry_changed_cb':self._replace_entry_changed_cb,
+ 'replace_clicked_cb':self._replace_cb,
+ #'replace_all_clicked_cb':self._findprev_cb,
+ }
+ self.wTree.signal_autoconnect(mdict)
+ self._findnext = self.wTree.get_widget("find_next")
+ self._findprev = self.wTree.get_widget("find_previous")
+ self._search_entry = self.wTree.get_widget("find_entry")
+ self._replace_entry = self.wTree.get_widget("replace_entry")
+ self._replace_button = self.wTree.get_widget("replace")
+ #self.replace_all = self.wTree.get_widget("replace_all")
+ self.find_where = self.wTree.get_widget("find_where")
+
+
+ def close_find_window(self,button):
+ self.find_window.hide()
+
+ def delete_event(self,widget,event):
+ if widget == self.find_window:
+ self.find_window.hide()
+ return True
+
+ def find_entry_changed_cb(self,button):
+ #self.editor.search_for =
+ pass
+ def replace_entry_changed_cb(self,button):
+ #self.editor.search_for =
+ pass
+
+ def project_run_cb(self,button):
+ _logger.debug('entered project_run_cb')
+ """
+ start_script = ['python','import sys','from Rpyc import *','from Rpyc.Utils import remote_interpreter',
+ 'c = SocketConnection("localhost")','remote_interpreter(c)']
+ for l in start_script:
+ self.feed_virtual_terminal(0,l+'\r\n')
+ """
+ self.start_debugging()
+
+
+
+
+ ###### SUGAR defined read and write routines -- do not let them overwrite what's on disk
+
+ def read_file(self, file_path):
+ interesting_keys = ['mtime','mime_type','package','checksum','title','timestamp','icon-color','uid']
+ for key in interesting_keys:
+ if self.metadata.has_key(key):
+ self.activity_dict[key] = self.metadata[key]
+ _logger.debug('RELOADING ACTIVITY DATA...Mime_type:%s. File_path:%s.'%(self.metadata['mime_type'],
+ file_path))
+ debugstr = ''
+ for key in self.activity_dict.keys():
+ debugstr += key + ':'+str(self.activity_dict[key]) + ', '
+ _logger.debug ('In read_file: activity dictionary==> %s'%debugstr)
+ return
+
+ def write_file(self, file_path):
+ """
+ The paradigm designed into the XO, ie an automatic load from the Journal at activity startup
+ does not make sense during a debugging session. An errant stack overflow can easily crash
+ the system and require a reboot. For the session manager to overwrite the changes that are stored
+ on disk, but not yet saved in the journal is highly undesireable. So we'll let the user save to
+ the journal, and perhaps optionally to the sd card (because it is removable, should the system die)
+ """
+ _logger.debug('write file object_id: %s'%self.debug_dict['jobject_id'])
+ self._jobject.metadata['title'] = 'PyDebug'
+ datastore.write(self._jobject)
+ self.write_activity_info()
+ self.put_config()
+ return
+
+ def write_binary_to_datastore(self):
+ """
+ Check to see if there is a child loaded.
+ Then copy the home directory data for this application into the bundle
+ then bundle it up and write it to the journal
+ lastly serialize the project information and write it to the journal
+ """
+ _logger.debug('Entered write_binary_to_datastore with child_path:%s'%self.child_path)
+ if not (os.path.isdir(self.child_path) and self.child_path.split('.')[-1:][0] == 'activity'):
+ self.alert(_('No Program loaded'))
+ return
+ dsobject = datastore.create()
+ dsobject.metadata['mime_type'] = 'binary'
+
+ #copy the home directory config stuff into the bundle
+ home_dir = os.path.join(self.child_path,'HOME')
+ try:
+ os.rmtree(home_dir)
+ except:
+ pass
+ try:
+ os.mkdir(home_dir)
+ except:
+ pass
+ source = self.debugger_home
+ dest = os.path.join(self.child_path,'HOME')
+ _logger.debug('writing HOME info from %s to %s.'%(source,dest))
+ for f in os.listdir(self.debugger_home):
+ if f == '.': continue
+ if f == '..': continue
+ if f == 'pydebug': continue
+ if f == '.sugar': continue
+ try:
+ if os.path.isdir(f):
+ shutil.copytree(f,dest)
+ else:
+ shutil.copy(f,dest)
+ except:
+ pass
+
+ #create the manifest for the bundle
+ try:
+ os.remove(os.path.join(self.child_path,'MANIFEST'))
+ except:
+ pass
+ dest = self.child_path
+ _logger.debug('Writing manifest to %s.'%(dest))
+ config = bundlebuilder.Config(dest)
+ b = bundlebuilder.Builder(config)
+ try:
+ b.fix_manifest()
+ except:
+ _logger.debug('fix manifest error: ',sys.exc_type,sys.exc_info[0],sys.exc_info[1])
+
+ #actually write the xo file
+ packager = bundlebuilder.XOPackager(bundlebuilder.Builder(config))
+ packager.package()
+ source = os.path.join(self.child_path,'dist',str(config.xo_name))
+ dest = os.path.join(self.get_activity_root(),'instance',str(config.xo_name))
+ _logger.debug('writing to the journal from %s to %s.'%(source,dest))
+ try:
+ shutil.copy(source,dest)
+ except IOError:
+ _logger.debug('shutil.copy error %d: %s. ',IOError[0],IOError[1])
+ #try:
+ dsobject.metadata['package'] = config.xo_name
+ dsobject.metadata['title'] = config.xo_name #_('PyDebug Zipped app')
+ dsobject.metadata['mime_type'] = 'binary'
+ dsobject.metadata['activity'] = 'org.laptop.PyDebug'
+ dsobject.metadata['icon'] = self.debug_dict.get('icon','')
+ #calculate and store the new md5sum
+ self.debug_dict['tree_md5'] = self.md5sum_tree(self.child_path)
+ dsobject.metadata['tree_md5'] = self.debug_dict['tree_md5']
+ dsobject.set_file_path(dest)
+
+ #actually make the call which writes to the journal
+ datastore.write(dsobject,transfer_ownership=True)
+ _logger.debug('succesfully wrote to the journal from %s.'%(dest))
+ #update the project display
+ self.journal_class = DataStoreTree(self,self.journal_treeview,self.wTree)
+
+ def load_activity_to_playpen(self,file_path):
+ """loads from a disk tree"""
+ self._new_child_path = os.path.join(self.activity_playpen,os.path.basename(file_path))
+ _logger.debug('copying file for %s to %s'%(file_path,self._new_child_path))
+ self._load_playpen(file_path)
+
+ def try_to_load_from_journal(self,object_id):
+ """
+ loads a zipped XO application file, asks whether it is ok to
+ delete/overwrite path if the md5 has changed.
+ """
+ self.ds = datastore.get(object_id[0])
+ if not self.ds:
+ _logger.debug('failed to get datastore object with id:%s'%object_id[0])
+ return
+ dsdict=self.ds.get_metadata()
+ file_name_from_ds = self.ds.get_file_path()
+ project = dsdict.get('package','')
+ if not project.endswith('.xo'):
+ self.alert(_('This journal item does not appear to be a zipped activity. Package:%s.'%project))
+ self.ds.destroy()
+ self.ds = None
+ return
+ filestat = os.stat(file_name_from_ds)
+ size = filestat.st_size
+
+ _logger.debug('In try_to_load_from_journal. Object_id %s. File_path %s. Size:%s'%(object_id[0], file_name_from_ds, size))
+ try:
+ self._bundler = ActivityBundle(file_name_from_ds)
+ except:
+ self.alert('Error: Malformed Activity Bundle')
+ self.ds.destroy()
+ self.ds = None
+ return
+ self._new_child_path = os.path.join(self.activity_playpen,self._bundler.get_name()+'.activity')
+ self._load_playpen(file_name_from_ds, iszip=True)
+
+ def _load_playpen(self,source_fn, iszip = False):
+ """entry point for both xo and file tree sources"""
+ self.iszip = iszip
+ self._load_to_playpen_source = source_fn
+ if self.child_path and os.path.isdir(self.child_path):
+ #check to see if it has been modified
+ stored_hash = self.debug_dict.get('tree_md5','')
+ if stored_hash != '' and stored_hash != self.md5sum_tree(self.child_path):
+ self.confirmation_alert(_('The currently loaded %s project in the playpen has been changed.'%os.path.basename(self.child_path)),_('Ok to abandon changes?'),self._clear_playpen_cb)
+ return
+ self._clear_playpen_cb(None,None)
+
+ def _clear_playpen_cb(self,alert, response):
+ #if necessary clean up contents of playpen
+ if alert != None: self.remove_alert(alert)
+ if self.child_path and os.path.isdir(self.child_path):
+ self.abandon_changes = True
+ self.debug_dict['tree_md5'] = ''
+ self.debug_dict['child_path'] = ''
+ self.editor.remove_all()
+ if self.child_path:
+ shutil.rmtree(self.child_path)
+ self.abandon_changes = False
+ if self._load_to_playpen_source == None:
+ #having done the clearing, just stop
+ return
+ if self.iszip:
+ self._bundler.install(self.activity_playpen)
+ if self.ds: self.ds.destroy()
+ self.ds = None
+ else:
+ if os.path.isdir(self._new_child_path):
+ shutil.rmtree(self._new_child_path)
+ shutil.copytree(self._load_to_playpen_source,self._new_child_path)
+ self.debug_dict['source_tree'] = self._load_to_playpen_source
+ self.child_path = self._new_child_path
+ self.setup_new_activity()
+
+ def setup_new_activity(self):
+ if self.child_path == None:
+ return
+ _logger.debug('child path before chdir:%s'%self.child_path)
+ os.chdir(self.child_path)
+ self.read_activity_info(self.child_path)
+ self.display_current_project()
+
+ #add the bin directory to path
+ os.environ['PATH'] = os.path.join(self.child_path,'bin') + ':' + os.environ['PATH']
+
+ #calculate and store the md5sum
+ self.debug_dict['tree_md5'] = self.md5sum_tree(self.child_path)
+
+ #find largest python files for editor
+ list = [f for f in os.listdir(self.child_path) if f[0] <> '.']
+ #list = self.manifest_class.get_filenames_list(self.child_path)
+ if not list: return
+ sizes = []
+ for f in list:
+ full_path = os.path.join(self.child_path,f)
+ if not f.endswith('.py'):continue
+ size = self.manifest_class.file_size(full_path)
+ sizes.append((size,full_path,))
+ #_logger.debug('python file "%s size %d'%(f,size))
+ for s,f in sorted(sizes,reverse=True)[:5]:
+ self.editor.load_object(f,os.path.basename(f))
+ self.editor.set_current_page(0)
+
+ ##################### ALERT ROUTINES ##################################
+
+ def alert(self,msg,title=None):
+ alert = NotifyAlert(10)
+ if title != None:
+ alert.props.title=_('There is no Activity file')
+ alert.props.msg = msg
+ alert.connect('response',self.no_file_cb)
+ self.add_alert(alert)
+
+ def no_file_cb(self,alert,response_id):
+ self.remove_alert(alert)
+
+ from sugar.graphics.alert import ConfirmationAlert
+
+ def confirmation_alert(self,msg,title=None,confirmation_cb = None):
+ alert = ConfirmationAlert()
+ alert.props.title=title
+ alert.props.msg = msg
+ alert.pydebug_cb = confirmation_cb
+ alert.connect('response', self._alert_response_cb)
+ self.add_alert(alert)
+
+ #### Method: _alert_response_cb, called when an alert object throws a
+ #response event.
+ def _alert_response_cb(self, alert, response_id):
+ #remove the alert from the screen, since either a response button
+ #was clicked or there was a timeout
+ this_alert = alert #keep a reference to it
+ self.remove_alert(alert)
+ #Do any work that is specific to the type of button clicked.
+ if response_id is gtk.RESPONSE_OK and this_alert.pydebug_cb != None:
+ this_alert.pydebug_cb (this_alert, response_id)
+
+
+ def _read_file_cb(self,widget):
+ _logger.debug('Reading a file into editor')
+ dialog = gtk.FileChooserDialog("Open..",
+ None,
+ gtk.FILE_CHOOSER_ACTION_OPEN,
+ (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
+ gtk.STOCK_OPEN, gtk.RESPONSE_OK))
+ dialog.set_default_response(gtk.RESPONSE_OK)
+ if self.last_filename == None:
+ self.last_filename = self.child_path
+ dialog.set_current_folder(os.path.dirname(self.last_filename))
+
+ filter = gtk.FileFilter()
+ filter.set_name("All files")
+ filter.add_pattern("*")
+ dialog.add_filter(filter)
+
+ filter = gtk.FileFilter()
+ filter.set_name("Python")
+ filter.add_pattern("*.py")
+ dialog.add_filter(filter)
+
+ filter = gtk.FileFilter()
+ filter.set_name("Activity")
+ filter.add_pattern("*.xo")
+ dialog.add_filter(filter)
+
+ response = dialog.run()
+ if response == gtk.RESPONSE_OK:
+ _logger.debug(dialog.get_filename(), 'selected')
+ fname = dialog.get_filename()
+ self.last_filename = fname
+ self.editor.load_object(fname,os.path.basename(fname))
+ elif response == gtk.RESPONSE_CANCEL:
+ _logger.debug( 'File chooseer closed, no files selected')
+ dialog.destroy()
+
+ def save_file_cb(self, button):
+ chooser = gtk.FileChooserDialog(title=None,action=gtk.FILE_CHOOSER_ACTION_SAVE,
+ buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_SAVE,
+ gtk.RESPONSE_OK))
+ file_path = self.editor.get_full_path()
+ _logger.debug('Saving file %s'%(file_path))
+ chooser.set_filename(file_path)
+ response = chooser.run()
+ new_fn = chooser.get_filename()
+ chooser.destroy()
+ if response == gtk.RESPONSE_CANCEL:
+ return
+ if response == gtk.RESPONSE_OK:
+ self.save_cb(None,new_fn)
+
+ def save_cb(self,button,new_fn=None):
+ if new_fn and not new_fn.startswith(self.child_root):
+ self.alert(_('You can only write %s to subdirectories of %s'%(os.path.basename(new_fn),
+ self.child_root,)))
+ return
+ page = self.editor._get_page()
+ if new_fn:
+ page.fullPath = new_fn
+ page.save(skip_md5 = True)
+ else:
+ page.save()
+ self.editor.clear_changed_star()
+ page.save_hash()
+
+ def set_dirty(self, dirty):
+ self.dirty = dirty
+
+ def md5sum_buffer(self, buffer, hash = None):
+ if hash == None:
+ hash = hashlib.md5()
+ hash.update(buffer)
+ return hash.hexdigest()
+
+ def md5sum(self, filename, hash = None):
+ h = self._md5sum(filename,hash)
+ return h.hexdigest()
+
+ def _md5sum(self, filename, hash = None):
+ if hash == None:
+ hash = hashlib.md5()
+ try:
+ fd = None
+ fd = open(filename, 'rb')
+ while True:
+ block = fd.read(128)
+ if not block: break
+ hash.update(block)
+ finally:
+ if fd != None:
+ fd.close()
+ return hash
+
+ def md5sum_tree(self,root):
+ if not os.path.isdir(root):
+ return None
+ h = hashlib.md5()
+ for dirpath, dirnames, filenames in os.walk(root):
+ for filename in filenames:
+ abs_path = os.path.join(dirpath, filename)
+ h = self._md5sum(abs_path,h)
+ #print abs_path
+ return h.hexdigest()
+
+
+
+ ############## Following code services the Project page #####################
+
+ def _get_project_canvas(self):
+ #initialize the link between program and the glade XML file
+ self.wTree=gtk.glade.XML(os.path.join(self.sugar_bundle_path,"project.glade"))
+ self.contents = self.wTree.get_widget("contents")
+ self.contents.unparent()
+ return self.contents
+
+ def setup_project_page(self):
+ self.activity_treeview = self.wTree.get_widget('file_system')
+ self.activity_window = FileTree(self, self.activity_treeview,self.wTree)
+ self.activity_window.set_file_sys_root('/home/olpc/Activities')
+ self.examples_treeview = self.wTree.get_widget('examples')
+ self.examples_window = FileTree(self, self.examples_treeview,self.wTree)
+ self.examples_window.set_file_sys_root(os.path.join(self.sugar_bundle_path,'examples'))
+ self.journal_treeview = self.wTree.get_widget('journal')
+ self.journal_class = DataStoreTree(self,self.journal_treeview,self.wTree)
+ self.connect_object() #make connections to signals from buttons
+ self.activity_toggled_cb(None)
+ if self.child_path and self.child_path.endswith('.activity') and \
+ os.path.isdir(self.child_path):
+ self.setup_new_activity()
+
+ def display_current_project(self):
+ self.manifest_treeview = self.wTree.get_widget('manifest')
+ self.manifest_class = FileTree(self, self.manifest_treeview,self.wTree)
+ if self.child_path:
+ self.manifest_class.set_file_sys_root(self.child_path)
+ else:
+ self.manifest_class.set_file_sys_root(self.activity_playpen)
+
+ self.wTree.get_widget('name').set_text(self.activity_dict.get('name',''))
+ self.wTree.get_widget('version').set_text(self.activity_dict.get('version',''))
+ self.wTree.get_widget('bundle_id').set_text(self.activity_dict.get('bundle_id',''))
+ self.wTree.get_widget('class').set_text(self.activity_dict.get('class',''))
+ self.wTree.get_widget('module').set_text(self.activity_dict.get('module',''))
+ """
+ self.wTree.get_widget('home_save').set_text(self.activity_dict.get('home_save',''))
+ self.wTree.get_widget('host').set_text(self.debug_dict.get('host',''))
+ self.wTree.get_widget('port').set_text(str(self.debug_dict.get('port','')))
+ activity_size = os.system('du --max-depth=0')
+ self.wTree.get_widget('activity_size').set_text(str(activity_size))
+ self.wTree.get_widget('icon').set_text(self.activity_dict.get('icon','').split('/')[-1:][0])
+ """
+
+ def manifest_point_to(self,fullpath):
+ if self.child_path:
+ self.manifest_class.set_file_sys_root(self.child_path)
+ else:
+ self.manifest_class.set_file_sys_root(self.activity_playpen)
+ self.manifest_class.position_to(fullpath)
+
+ #first connect the glade xml file to the servicing call backs
+ def connect_object(self, wTree=None):
+ """if wTree:
+ self.wTree=wTree
+ if self.wTree:"""
+ mdict = {
+ 'name_changed_cb':self.name_changed_cb,
+ 'bundle_id_changed_cb':self.bundle_id_changed_cb,
+ 'class_changed_cb':self.class_changed_cb,
+ 'icon_changed_cb':self.icon_changed_cb,
+ 'version_changed_cb':self.version_changed_cb,
+ 'file_toggle_clicked_cb':self.activity_toggled_cb,
+ 'to_activities_clicked_cb':self.to_home_clicked_cb,
+ 'from_activities_clicked_cb':self.from_home_clicked_cb,
+ 'from_examples_clicked_cb':self.from_examples_clicked_cb,
+ 'run_clicked_cb':self.project_run_cb,
+ 'delete_file_clicked_cb':self.delete_file_cb,
+ }
+ self.wTree.signal_autoconnect(mdict)
+ button = self.wTree.get_widget('file_toggle')
+ button.set_tooltip_text(_('Switch views between the "Installed" Activities directory and your "home" storage directory'))
+ button = self.wTree.get_widget('to_activities')
+ button.set_tooltip_text(_('Copy the files in the debug workplace to your "home" storage directory'))
+ button = self.wTree.get_widget('from_examples')
+ button.set_tooltip_text(_('Load and modify these example programs. See the help Tutorials'))
+
+
+ def name_changed_cb(self, widget):
+ self.activity_dict['name'] = widget.get_text()
+
+ def bundle_id_changed_cb(self,widget):
+ self.activity_dict['bundle_id'] = widget.get_text()
+
+ def class_changed_cb(self, widget):
+ self.activity_dict['class'] = widget.get_text()
+
+ def icon_changed_cb(self, widget):
+ self.activity_dict['icon'] = widget.get_text()
+
+ def version_changed_cb(self, widget):
+ self.activity_dict['version'] = widget.get_text()
+
+ def activity_toggled_cb(self, widget):
+ _logger.debug('Entered activity_toggled_cb. Button: %r'%self.file_pane_is_activities)
+ but = self.wTree.get_widget('to_activities')
+ to_what = self.wTree.get_widget('file_toggle')
+ window_label = self.wTree.get_widget('file_system_label')
+ if self.file_pane_is_activities == True:
+ to_what.set_label('Installed')
+ but.show()
+ display_label = self.storage[:18]+' . . . '+self.storage[-24:]
+ self.activity_window.set_file_sys_root(self.storage)
+ button = self.wTree.get_widget('from_activities')
+ button.set_tooltip_text(_('Copy the selected directory from your "home" storage to the debug workplace'))
+ window_label.set_text(display_label)
+ else:
+ to_what.set_label('home')
+ but.hide()
+ self.activity_window.set_file_sys_root('/home/olpc/Activities')
+ button = self.wTree.get_widget('from_activities')
+ button.set_tooltip_text(_('Copy the selected Activity to the debug workplace and start debugging'))
+ window_label.set_text('/home/olpc/Activities')
+ self.file_pane_is_activities = not self.file_pane_is_activities
+
+ def to_home_clicked_cb(self,widget):
+ _logger.debug('Entered to_home_clicked_cb')
+ self._to_home_dest = os.path.join(self.storage,self.activity_dict['name']+'.activity')
+ if os.path.isdir(self._to_home_dest):
+ target_md5sum = self.md5sum_tree(self._to_home_dest)
+ if target_md5sum != self.debug_dict.get('tree_md5',''):
+ self.confirmation_alert(_('OK to delete/overwrite %s?'%self._to_home_dest),
+ _('This destination has been changed by another application'),
+ self._to_home_cb)
+ return
+ self._to_home_cb( None, gtk.RESPONSE_OK)
+
+ def _to_home_cb(self, alert, response_id):
+ if alert != None: self.remove_alert(alert)
+ if response_id is gtk.RESPONSE_OK:
+ cmd = ['rsync','-av',self.child_path,self._to_home_dest]
+ _logger.debug('do to_home_cb with cmd:%s'%cmd)
+ p1 = Popen(cmd,stdout=PIPE)
+ output = p1.communicate()
+ if p1.returncode != 0:
+ self.alert('rsync command returned non zero\n'+output[0]+ 'COPY FAILURE')
+ return
+ #redraw the treeview
+ self.activity_window.set_file_sys_root(self.storage)
+
+ def from_home_clicked_cb(self,widget):
+ _logger.debug('Entered from_home_clicked_cb')
+ selection=self.activity_treeview.get_selection()
+ (model,iter)=selection.get_selected()
+ if iter == None:
+ self.alert(_('Must select File or Directory item to Load'))
+ return
+ fullpath = model.get(iter,4)[0]
+ if os.path.isdir(fullpath):
+ if not fullpath.endswith('.activity'):
+ self.alert(_('Use this button for Activities or Files'),
+ _('ERROR: This folder name does not end with ".activity"'))
+ return
+ self.load_activity_to_playpen(fullpath)
+ else:
+ #selected is a file, just copy it into the current project
+ basename = os.path.basename(fullpath)
+ if os.path.isfile(os.path.join(self.child_path,basename)):
+ #change name if necessary to prevent collision
+ basename = self.non_conflicting(self.child_path,basename)
+ shutil.copy(fullpath,os.path.join(self.child_path,basename))
+ self.manifest_point_to(os.path.join(self.child_path,basename))
+
+ def non_conflicting(self,root,basename):
+ """
+ create a non-conflicting filename by adding '-<number>' to a filename before extension
+ """
+ ext = ''
+ basename = basename.split('.')
+ word = basename[0]
+ if len(basename) > 1:
+ ext = basename[1]
+ adder = ''
+ index = 0
+ while os.path.isfile(os.path.join(root,word+adder+'.'+ext)):
+ index +=1
+ adder = '-%s'%index
+ return os.path.join(root,word+adder+'.'+ext)
+
+ def from_examples_clicked_cb(self,widget):
+ _logger.debug('Entered from_examples_clicked_cb')
+ selection=self.examples_treeview.get_selection()
+ (model,iter)=selection.get_selected()
+ if iter == None:
+ self.alert(_('Must select File or Directory item to Load'))
+ return
+ fullpath = model.get(iter,4)[0]
+ if fullpath.endswith('.activity'):
+ self.load_activity_to_playpen(fullpath)
+ return
+ self._load_to_playpen_source = fullpath
+ try:
+ self._bundler = ActivityBundle(fullpath)
+ except:
+ self.alert('Error: Malformed Activity Bundle')
+ return
+
+ self._new_child_path = os.path.join(self.activity_playpen,self._bundler._zip_root_dir)
+ #check to see if current activity in playpen needs to be saved, and load new activity if save is ok
+ self._load_playpen(fullpath, iszip=True)
+
+ def filetree_activated(self):
+ _logger.debug('entered pydebug filetree_activated')
+
+ def read_activity_info(self, path):
+ """
+ Parses the ./activity/activity.info file
+
+ filen = os.path.join(self.child_path,'activity','activity.info')
+ try:
+ fd = open(filen,'r')
+ except:
+ _logger.debug('failed to open %s'%filen)
+ return
+ for line in fd.readlines():
+ if line.lstrip() == '': continue
+ _logger.debug('activity line %s'%line)
+ tokens = line.split('=')
+
+ if len(tokens) > 1:
+ keyword = tokens[0].lower().rstrip()
+ rside = tokens[1].split()
+ if keyword == 'class':
+ if '.' in rside[0]:
+ self.activity_dict['class'] = rside[0].split('.')[1]
+ self.activity_dict['module'] = rside[0].split('.')[0]
+ elif keyword == 'exec':
+ if rside[0] == 'sugar-activity' and '.' in rside[1]:
+ self.activity_dict['class'] = rside[1].split('.')[1]
+ self.activity_dict['module'] = rside[1].split('.')[0]
+ else:
+ self.activity_dict['module'] = rside[0]
+ elif keyword == 'bundle_id' or keyword == 'service_name':
+ self.activity_dict['bundle_id'] = rside[0]
+ elif keyword == 'activity_version':
+ self.activity_dict['version'] = rside[0]
+ elif keyword == 'name':
+ self.activity_dict['name'] = rside[0]
+ elif keyword == 'icon':
+ self.activity_dict['icon'] = rside[0]
+ fd.close()
+
+ debugstr = ''
+ for key in self.activity_dict.keys():
+ debugstr += key + ':'+str(self.activity_dict[key]) + ', '
+ _logger.debug ('In read_activity: activity dictionary==> %s'%debugstr)
+ """
+ try:
+ bundle = ActivityBundle(path)
+ except:
+ msg = _('%s not recognized by ActivityBundle parser. Does activity/activity.info exist?'
+ %os.path.basename(path))
+ self.alert(msg)
+ return #maybe should issue an alert here
+ self.activity_dict['version'] = str(bundle.get_activity_version())
+ self.activity_dict['name'] = bundle.get_name()
+ self.activity_dict['bundle_id'] = bundle.get_bundle_id()
+ self.activity_dict['command'] = bundle.get_command()
+ cmd_args = activityfactory.get_command(bundle)
+ mod_class = cmd_args[1]
+ if '.' in mod_class:
+ self.activity_dict['class'] = mod_class.split('.')[1]
+ self.activity_dict['module'] = mod_class.split('.')[0]
+ self.activity_dict['icon'] = bundle.get_icon()
+
+ def write_activity_info(self):
+ #write the activity.info file
+ _logger.debug('entered write_actiity_info')
+ filen = os.path.join(self.child_path,'activity','activity.info')
+ #try:
+ with open(filen,'r') as fd:
+ #and also write to a new file
+ filewr = os.path.join(self.child_path,'activity','activity.new')
+ #try:
+ with open(filewr,'w') as fdw:
+ #write the required lines
+ _logger.debug('writing activity info to %s'%filewr)
+ fdw.write('[Activity]\n')
+ fdw.write('name = %s\n'%self.activity_dict.get('name'))
+ fdw.write('bundle_id = %s\n'%self.activity_dict.get('bundle_id'))
+ fdw.write('activity_version = %s\n'%self.activity_dict.get('version'))
+ icon = self.activity_dict.get('icon')[len(self.child_path)+9:]
+ fdw.write('icon = %s\n'%icon.split('.')[:-1])
+ if self.activity_dict.get('class','') == '':
+ fdw.write('exec = %s\n'%self.activity_dict.get('module'))
+ else:
+ fdw.write('class = %s.%s\n'%(self.activity_dict.get('module'),
+ self.activity_dict.get('class')))
+ #pass the rest of the input to the output
+ passup = ('[activity]','exec','activity_version','name','bundle_id',
+ 'service_name','icon','class')
+ for line in fd.readlines():
+ tokens = line.split('=')
+ keyword = tokens[0].lower().rstrip()
+ if keyword in passup: continue
+ fdw.write(line)
+ """
+ except EnvironmentError:
+ _logger.debug('failed to open %s for writing. msg:%s'%(filewr,EnvironmentError[1]))
+
+ except EnvironmentError:
+ _logger.debug('failed to open %s msg:%s'%(filen,EnvironmentError[1]))
+ """
+
+ def delete_file_cb(self,widget):
+ selection=self.manifest_treeview.get_selection()
+ (model,iter)=selection.get_selected()
+ if iter == None:
+ self.alert(_('Must select File delete'))
+ return
+ fullpath = model.get(iter,4)[0]
+ _logger.debug(' delete_file_clicked_cb. File: %s'%os.path.basename(fullpath))
+ self.delete_file_storage = fullpath
+ if os.path.isdir(fullpath):
+ self.alert(_('Use the terminal "rm -rf <directory> --CAREFULLY','Cannot delete Folders!'))
+ return
+ self.confirmation_alert(_('Would you like to continue deleting %s?'%os.path.basename(fullpath)),
+ _('ABOUT TO DELETE A FILE!!'),self.do_delete)
+
+ def do_delete(self, alert, response):
+ _logger.debug('doing delete of: %s'%self.delete_file_storage)
+ self.manifest_point_to(self.delete_file_storage)
+ os.unlink(self.delete_file_storage)
+ self.manifest_class.set_file_sys_root(self.child_path)
+ self.manifest_class.position_recent()
+
+ ################ save config state from one invocation to another -- not activity state
+ def get_config(self):
+ try:
+ fd = open(os.path.join(self.debugger_home,'pickl'),'rb')
+ local = pickle.load(fd)
+ self.debug_dict = local.copy()
+ _logger.debug('unpickled successfully')
+ """
+ object_id = self.debug_dict.get('jobject_id','')
+ if object_id != '':
+ self._jobject = datastore.get(object_id)
+ else:
+ self._jobject = None
+ """
+ except:
+ try:
+ fd = open(os.path.join(self.debugger_home,'pickl'),'wb')
+ self.debug_dict['host'] = 'localhost'
+ self.debug_dict['port'] = 18812
+ self.debug_dict['autosave'] = True
+ self.debug_dict['child_path'] = ''
+ local = self.debug_dict.copy()
+ pickle.dump(local,fd,pickle.HIGHEST_PROTOCOL)
+ except IOError:
+ _logger.debug('get_config -- Error writing pickle file %s'
+ %os.path.join(self.debugger_home,'pickl'))
+ finally:
+ fd.close()
+ object_id = self.debug_dict.get('jobject_id','')
+ if object_id == '':
+ jobject = datastore.create()
+ jobject.metadata['title'] = 'PyDebug'
+ jobject.metadata['keep'] = '1'
+ jobject.metadata['preview'] = ''
+ self._jobject = jobject
+ datastore.write(self._jobject)
+ #self.metadata = jobject.metadata
+ self.debug_dict['jobject_id'] = str(self.metadata['uid'])
+ _logger.debug('in get_config created jobject id:%s'%self.debug_dict['jobject_id'])
+ else:
+ self._jobject = datastore.get(object_id)
+ self.child_path = self.debug_dict.get('child_path','')
+ if self.child_path == '' or not os.path.isdir(self.child_path):
+ self.child_path = None
+ """
+ debugstr = ''
+ for key in self.debug_dict.keys():
+ debugstr += key + ':'+str(self.debug_dict[key]) + ', '
+ _logger.debug ('In get_config: debug dictionary==> %s'%debugstr)
+ """
+ if self.child_path and self.debug_dict.get('tree_md5',''):
+ if self.debug_dict.get('tree_md5','') == self.md5sum_tree(self.child_path):
+ self.setup_new_activity()
+ #the tree is valid so take up where we left off
+ else:
+ self.confirmation_alert(_('Continue even though stored checksum does not match current checksum'),
+ _('CAUTION: The program in the playpen may have been changed.'),
+ self.startup_continue)
+
+ def startup_continue(self,alert,response):
+ self.setup_new_activity()
+
+ def put_config(self):
+ if self.child_path:
+ self.debug_dict['tree_md5'] = self.md5sum_tree(self.child_path)
+ self.debug_dict['child_path'] = self.child_path
+ try:
+ fd = open(os.path.join(self.debugger_home,'pickl'),'wb')
+ local = self.debug_dict.copy()
+ pickle.dump(local,fd,pickle.HIGHEST_PROTOCOL)
+ except IOError:
+ _logger.debug('put_config routine Error writing pickle file %s'
+ %os.path.join(self.debugger_home,'pickl'))
+ return
+ finally:
+ fd.close()
+ debugstr = ''
+ return
+ for key in self.debug_dict.keys():
+ debugstr += key + ':'+str(self.debug_dict[key]) + ', '
+ _logger.debug ('In put_config: debug dictionary==> %s'%debugstr)
+
diff --git a/pydebug_logging.py b/pydebug_logging.py
new file mode 100644
index 0000000..1977760
--- /dev/null
+++ b/pydebug_logging.py
@@ -0,0 +1,47 @@
+#!/usr/bin/env python
+# Copyright (C) 2009, George Hunt <georgejhunt@gmail.com>
+# Copyright (C) 2009, One Laptop Per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import os
+
+# Initialize logging.
+import logging
+from sugar import logger
+#Get the standard logging directory.
+std_log_dir = logger.get_logs_dir()
+_logger = logging.getLogger('PyDebug')
+"""
+#First log handler: outputs to a file called 'VideoEdit.activity.log'
+file_handler = logging.FileHandler(os.path.join(std_log_dir,'PyDebug.activity.log')
+file_formatter = logging.Formatter('%(name)s -- %(asctime)s %(funcName)s: %(lineno)d\n %(message)s\n')
+file_handler.setFormatter(file_formatter)
+_logger.addHandler(file_handler)
+"""
+_logger.setLevel(logging.DEBUG)
+
+#Second log handler: outputs to a the console, using a slightly different output structure
+console_handler = logging.StreamHandler()
+console_formatter = logging.Formatter('%(name)s %(levelname)s %(funcName)s: %(lineno)d||| %(message)s')
+console_handler.setFormatter(console_formatter)
+_logger.addHandler(console_handler)
+
+def log_environment():
+ keys = []
+ for k in os.environ:
+ if k.find('SUGAR') > -1 or k.find('PATH')>-1:
+ print('%s => %s'%(k,os.environ[k]))
+ \ No newline at end of file
diff --git a/pytoolbar.py b/pytoolbar.py
new file mode 100644
index 0000000..5a592bc
--- /dev/null
+++ b/pytoolbar.py
@@ -0,0 +1,192 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2009, George Hunt <georgejhunt@gmail.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import gtk
+import gconf
+
+from sugar.graphics.toolbox import Toolbox
+from sugar.graphics.xocolor import XoColor
+from sugar.graphics.icon import Icon
+from sugar.graphics.toolcombobox import ToolComboBox
+from sugar.graphics.toolbutton import ToolButton
+from gettext import gettext as _
+
+class ActivityToolbar(gtk.Toolbar):
+ """The Activity toolbar with the Journal entry title, sharing,
+ Keep and Stop buttons
+
+ All activities should have this toolbar. It is easiest to add it to your
+ Activity by using the ActivityToolbox.
+ """
+ def __init__(self, activity):
+ gtk.Toolbar.__init__(self)
+
+ self._activity = activity
+ self._updating_share = False
+
+ activity.connect('shared', self.__activity_shared_cb)
+ activity.connect('joined', self.__activity_shared_cb)
+ activity.connect('notify::max_participants',
+ self.__max_participants_changed_cb)
+
+ if activity.metadata:
+ self.title = gtk.Entry()
+ self.title.set_size_request(int(gtk.gdk.screen_width() / 3), -1)
+ self.title.set_text(activity.metadata['title'])
+ self.title.connect('changed', self.__title_changed_cb)
+ self._add_widget(self.title)
+
+ activity.metadata.connect('updated', self.__jobject_updated_cb)
+
+ separator = gtk.SeparatorToolItem()
+ separator.props.draw = False
+ separator.set_expand(True)
+ self.insert(separator, -1)
+ separator.show()
+
+ self.share = ToolComboBox(label_text=_('Traceback:'))
+ self.share.combo.connect('changed', self.__traceback_changed_cb)
+ self.share.combo.append_item("traceback_plain", _('Plain'))
+ self.share.combo.append_item('traceback_context', _('Context'))
+ self.share.combo.append_item('traceback_verbose', _('Verbose'))
+ self.insert(self.share, -1)
+ self.share.show()
+
+ self._update_share()
+
+ self.keep = ToolButton(tooltip=_('Keep'))
+ client = gconf.client_get_default()
+ color = XoColor(client.get_string('/desktop/sugar/user/color'))
+ keep_icon = Icon(icon_name='document-save', xo_color=color)
+ self.keep.set_icon_widget(keep_icon)
+ keep_icon.show()
+ self.keep.props.accelerator = '<Ctrl>S'
+ self.keep.connect('clicked', self.__keep_clicked_cb)
+ self.insert(self.keep, -1)
+ self.keep.show()
+
+ self.stop = ToolButton('activity-stop', tooltip=_('Stop'))
+ self.stop.props.accelerator = '<Ctrl>Q'
+ self.stop.connect('clicked', self.__stop_clicked_cb)
+ self.insert(self.stop, -1)
+ self.stop.show()
+
+ self._update_title_sid = None
+
+ def _update_share(self):
+ self._updating_share = True
+
+ if self._activity.props.max_participants == 1:
+ self.share.hide()
+
+ if self._activity.get_shared():
+ self.share.set_sensitive(False)
+ self.share.combo.set_active(1)
+ else:
+ self.share.set_sensitive(True)
+ self.share.combo.set_active(0)
+
+ self._updating_share = False
+
+ def __traceback_changed_cb(self, combo):
+ model = self.share.combo.get_model()
+ it = self.share.combo.get_active_iter()
+ (scope, ) = model.get(it, 0)
+ if scope == 'traceback_plain':
+ self._activity.traceback = 'Plain'
+ self._activity.debug_dict['traceback'] = 'plain'
+ elif scope == 'traceback_context':
+ self._activity.traceback = 'Context'
+ self._activity.debug_dict['traceback'] = 'context'
+ elif scope == 'traceback_verbose':
+ self._activity.traceback = 'Verbose'
+ self._activity.debug_dict['traceback'] = 'verbose'
+
+ def __keep_clicked_cb(self, button):
+ self._activity.copy()
+
+ def __stop_clicked_cb(self, button):
+ self._activity.close()
+
+ def __jobject_updated_cb(self, jobject):
+ self.title.set_text(jobject['title'])
+
+ def __title_changed_cb(self, entry):
+ if not self._update_title_sid:
+ self._update_title_sid = gobject.timeout_add_seconds(
+ 1, self.__update_title_cb)
+
+ def __update_title_cb(self):
+ title = self.title.get_text()
+
+ self._activity.metadata['title'] = title
+ self._activity.metadata['title_set_by_user'] = '1'
+ self._activity.save()
+
+ shared_activity = self._activity.get_shared_activity()
+ if shared_activity:
+ shared_activity.props.name = title
+
+ self._update_title_sid = None
+ return False
+
+ def _add_widget(self, widget, expand=False):
+ tool_item = gtk.ToolItem()
+ tool_item.set_expand(expand)
+
+ tool_item.add(widget)
+ widget.show()
+
+ self.insert(tool_item, -1)
+ tool_item.show()
+
+ def __activity_shared_cb(self, activity):
+ self._update_share()
+
+ def __max_participants_changed_cb(self, activity, pspec):
+ self._update_share()
+
+class ActivityToolbox(Toolbox):
+ """Creates the Toolbox for the Activity
+
+ By default, the toolbox contains only the ActivityToolbar. After creating
+ the toolbox, you can add your activity specific toolbars, for example the
+ EditToolbar.
+
+ To add the ActivityToolbox to your Activity in MyActivity.__init__() do:
+
+ # Create the Toolbar with the ActivityToolbar:
+ toolbox = activity.ActivityToolbox(self)
+ ... your code, inserting all other toolbars you need, like EditToolbar
+
+ # Add the toolbox to the activity frame:
+ self.set_toolbox(toolbox)
+ # And make it visible:
+ toolbox.show()
+ """
+ def __init__(self, activity):
+ Toolbox.__init__(self)
+
+ self._activity_toolbar = ActivityToolbar(activity)
+ self.add_toolbar(_('Activity'), self._activity_toolbar)
+ self._activity_toolbar.show()
+
+ def get_activity_toolbar(self):
+ return self._activity_toolbar
+
+
diff --git a/pytoolbar.py~ b/pytoolbar.py~
new file mode 100644
index 0000000..1fb94cc
--- /dev/null
+++ b/pytoolbar.py~
@@ -0,0 +1,221 @@
+class ActivityToolbar(gtk.Toolbar):
+ """The Activity toolbar with the Journal entry title, sharing,
+ Keep and Stop buttons
+
+ All activities should have this toolbar. It is easiest to add it to your
+ Activity by using the ActivityToolbox.
+ """
+ def __init__(self, activity):
+ gtk.Toolbar.__init__(self)
+
+ self._activity = activity
+ self._updating_share = False
+
+ activity.connect('shared', self.__activity_shared_cb)
+ activity.connect('joined', self.__activity_shared_cb)
+ activity.connect('notify::max_participants',
+ self.__max_participants_changed_cb)
+
+ if activity.metadata:
+ self.title = gtk.Entry()
+ self.title.set_size_request(int(gtk.gdk.screen_width() / 3), -1)
+ self.title.set_text(activity.metadata['title'])
+ self.title.connect('changed', self.__title_changed_cb)
+ self._add_widget(self.title)
+
+ activity.metadata.connect('updated', self.__jobject_updated_cb)
+
+ separator = gtk.SeparatorToolItem()
+ separator.props.draw = False
+ separator.set_expand(True)
+ self.insert(separator, -1)
+ separator.show()
+
+ self.share = ToolComboBox(label_text=_('Share with:'))
+ self.share.combo.connect('changed', self.__share_changed_cb)
+ self.share.combo.append_item(SCOPE_PRIVATE, _('Private'), 'zoom-home')
+ self.share.combo.append_item(SCOPE_NEIGHBORHOOD, _('My Neighborhood'),
+ 'zoom-neighborhood')
+ self.insert(self.share, -1)
+ self.share.show()
+
+ self._update_share()
+
+ self.keep = ToolButton(tooltip=_('Keep'))
+ client = gconf.client_get_default()
+ color = XoColor(client.get_string('/desktop/sugar/user/color'))
+ keep_icon = Icon(icon_name='document-save', xo_color=color)
+ self.keep.set_icon_widget(keep_icon)
+ keep_icon.show()
+ self.keep.props.accelerator = '<Ctrl>S'
+ self.keep.connect('clicked', self.__keep_clicked_cb)
+ self.insert(self.keep, -1)
+ self.keep.show()
+
+ self.stop = ToolButton('activity-stop', tooltip=_('Stop'))
+ self.stop.props.accelerator = '<Ctrl>Q'
+ self.stop.connect('clicked', self.__stop_clicked_cb)
+ self.insert(self.stop, -1)
+ self.stop.show()
+
+ self._update_title_sid = None
+
+ def _update_share(self):
+ self._updating_share = True
+
+ if self._activity.props.max_participants == 1:
+ self.share.hide()
+
+ if self._activity.get_shared():
+ self.share.set_sensitive(False)
+ self.share.combo.set_active(1)
+ else:
+ self.share.set_sensitive(True)
+ self.share.combo.set_active(0)
+
+ self._updating_share = False
+
+ def __share_changed_cb(self, combo):
+ if self._updating_share:
+ return
+
+ model = self.share.combo.get_model()
+ it = self.share.combo.get_active_iter()
+ (scope, ) = model.get(it, 0)
+ if scope == SCOPE_NEIGHBORHOOD:
+ self._activity.share()
+
+ def __keep_clicked_cb(self, button):
+ self._activity.copy()
+
+ def __stop_clicked_cb(self, button):
+ self._activity.close()
+
+ def __jobject_updated_cb(self, jobject):
+ self.title.set_text(jobject['title'])
+
+ def __title_changed_cb(self, entry):
+ if not self._update_title_sid:
+ self._update_title_sid = gobject.timeout_add_seconds(
+ 1, self.__update_title_cb)
+
+ def __update_title_cb(self):
+ title = self.title.get_text()
+
+ self._activity.metadata['title'] = title
+ self._activity.metadata['title_set_by_user'] = '1'
+ self._activity.save()
+
+ shared_activity = self._activity.get_shared_activity()
+ if shared_activity:
+ shared_activity.props.name = title
+
+ self._update_title_sid = None
+ return False
+
+ def _add_widget(self, widget, expand=False):
+ tool_item = gtk.ToolItem()
+ tool_item.set_expand(expand)
+
+ tool_item.add(widget)
+ widget.show()
+
+ self.insert(tool_item, -1)
+ tool_item.show()
+
+ def __activity_shared_cb(self, activity):
+ self._update_share()
+
+ def __max_participants_changed_cb(self, activity, pspec):
+ self._update_share()
+
+class EditToolbar(gtk.Toolbar):
+ """Provides the standard edit toolbar for Activities.
+
+ Members:
+ undo -- the undo button
+ redo -- the redo button
+ copy -- the copy button
+ paste -- the paste button
+ separator -- A separator between undo/redo and copy/paste
+
+ This class only provides the 'edit' buttons in a standard layout,
+ your activity will need to either hide buttons which make no sense for your
+ Activity, or you need to connect the button events to your own callbacks:
+
+ ## Example from Read.activity:
+ # Create the edit toolbar:
+ self._edit_toolbar = EditToolbar(self._view)
+ # Hide undo and redo, they're not needed
+ self._edit_toolbar.undo.props.visible = False
+ self._edit_toolbar.redo.props.visible = False
+ # Hide the separator too:
+ self._edit_toolbar.separator.props.visible = False
+
+ # As long as nothing is selected, copy needs to be insensitive:
+ self._edit_toolbar.copy.set_sensitive(False)
+ # When the user clicks the button, call _edit_toolbar_copy_cb()
+ self._edit_toolbar.copy.connect('clicked', self._edit_toolbar_copy_cb)
+
+ # Add the edit toolbar:
+ toolbox.add_toolbar(_('Edit'), self._edit_toolbar)
+ # And make it visible:
+ self._edit_toolbar.show()
+ """
+ def __init__(self):
+ gtk.Toolbar.__init__(self)
+
+ self.undo = ToolButton('edit-undo')
+ self.undo.set_tooltip(_('Undo'))
+ self.insert(self.undo, -1)
+ self.undo.show()
+
+ self.redo = ToolButton('edit-redo')
+ self.redo.set_tooltip(_('Redo'))
+ self.insert(self.redo, -1)
+ self.redo.show()
+
+ self.separator = gtk.SeparatorToolItem()
+ self.separator.set_draw(True)
+ self.insert(self.separator, -1)
+ self.separator.show()
+
+ self.copy = ToolButton('edit-copy')
+ self.copy.set_tooltip(_('Copy'))
+ self.insert(self.copy, -1)
+ self.copy.show()
+
+ self.paste = ToolButton('edit-paste')
+ self.paste.set_tooltip(_('Paste'))
+ self.insert(self.paste, -1)
+ self.paste.show()
+
+class ActivityToolbox(Toolbox):
+ """Creates the Toolbox for the Activity
+
+ By default, the toolbox contains only the ActivityToolbar. After creating
+ the toolbox, you can add your activity specific toolbars, for example the
+ EditToolbar.
+
+ To add the ActivityToolbox to your Activity in MyActivity.__init__() do:
+
+ # Create the Toolbar with the ActivityToolbar:
+ toolbox = activity.ActivityToolbox(self)
+ ... your code, inserting all other toolbars you need, like EditToolbar
+
+ # Add the toolbox to the activity frame:
+ self.set_toolbox(toolbox)
+ # And make it visible:
+ toolbox.show()
+ """
+ def __init__(self, activity):
+ Toolbox.__init__(self)
+
+ self._activity_toolbar = ActivityToolbar(activity)
+ self.add_toolbar(_('Activity'), self._activity_toolbar)
+ self._activity_toolbar.show()
+
+ def get_activity_toolbar(self):
+ return self._activity_toolbar
+
+
diff --git a/setup.py b/setup.py
new file mode 100755
index 0000000..fae74b8
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+
+# Copyright (C) 2006, Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+from sugar.activity import bundlebuilder
+
+bundlebuilder.start()
+
diff --git a/sourceview_editor.py b/sourceview_editor.py
new file mode 100644
index 0000000..0ecd004
--- /dev/null
+++ b/sourceview_editor.py
@@ -0,0 +1,636 @@
+# Copyright 2008 Paul Swartz
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import gtk, gobject
+import pango
+import notebook
+import gtksourceview2
+import os.path
+import sys
+import re
+import mimetypes
+from exceptions import *
+import hashlib
+from gettext import gettext as _
+
+# Initialize logging.
+import logging
+from sugar import logger
+#Get the standard logging directory.
+std_log_dir = logger.get_logs_dir()
+_logger = logging.getLogger('PyDebug')
+
+_logger.setLevel(logging.DEBUG)
+
+class S_WHERE:
+ selection, file, multifile = range(3) #an enum
+
+class GtkSourceview2Editor(notebook.Notebook):
+ __gsignals__ = {
+ 'changed': (gobject.SIGNAL_RUN_FIRST, None, [])
+ }
+
+ def __init__(self, activity):
+ notebook.Notebook.__init__(self, can_close_tabs=True)
+ self._can_close_tabs = True #redundant, but above call broken for some reason
+ self.activity = activity
+ self.set_size_request(900, 350)
+ self.connect('page-removed', self._page_removed_cb)
+ self.connect('switch-page', self._switch_page_cb)
+
+ def _page_removed_cb(self, notebook, page, n):
+ _logger.debug('removing page %d'%n)
+ if self.interactive_close:
+ self.interactive_close = False
+ page.save(interactive_close=True)
+ page.save()
+
+ def _switch_page_cb(self, notebook, page_gptr, page_num):
+ pass
+ #self.activity.update_sidebar_to_page(self.get_nth_page(page_num))
+
+ def set_to_page_like(self,eq_to_page):
+ for n in range(self.get_n_pages()):
+ page = self.get_nth_page(n)
+ if page == eq_to_page:
+ self.set_current_page(n)
+ return True
+ return False
+
+ def load_object(self, fullPath, filename):
+ if self.set_to_page_like(fullPath):
+ return
+ page = GtkSourceview2Page(fullPath, self.activity)
+ label = filename
+ page.text_buffer.connect('changed', self._changed_cb)
+ self.add_page(label, page)
+ #label object is passed back in Notebook object -- remember it
+ page.label = self.tab_label
+ _logger.debug('new label text: %s'%page.label.get_text())
+ self.set_current_page(-1)
+ self._changed_cb(page.text_buffer)
+
+ def position_to(self, fullPath, line = 0, col = 0):
+ self.load_object(fullPath, os.path.basename(fullPath))
+ page = self._get_page()
+ page._scroll_to_line(line)
+
+
+ def _changed_cb(self, buffer):
+ if not buffer.can_undo():
+ buffer.set_modified(False)
+ self.clear_changed_star()
+ elif not self.activity.dirty:
+ self.activity.set_dirty(True)
+ self.emit('changed')
+ if buffer.can_undo():
+ self.set_changed_star()
+
+ def _get_page(self):
+ n = self.get_current_page()
+ return self.get_nth_page(n)
+
+ def get_full_path(self):
+ page = self._get_page()
+ return page.fullPath
+
+ def set_changed_star(self, button = None):
+ page = self._get_page()
+ if page:
+ current = page.label.get_text()
+ if current.startswith('*'):return
+ page.label.set_text('*' + current)
+
+ def clear_changed_star(self, button = None):
+ page = self._get_page()
+ if page:
+ current = os.path.basename(page.fullPath)
+ page.label.set_text(current)
+
+ def set_focus(self):
+ page = self._get_page()
+ if page:
+ page.text_view.grab_focus()
+
+
+ def can_undo_redo(self):
+ page = self._get_page()
+ if page is None:
+ return (False, False)
+ else:
+ return page.can_undo_redo()
+
+ def undo(self, button = None):
+ page = self._get_page()
+ if page:
+ page.undo()
+
+ def redo(self, button = None):
+ page = self._get_page()
+ if page:
+ page.redo()
+
+ def copy(self, button = None):
+ page = self._get_page()
+ if page:
+ page.copy()
+
+ def cut(self, button = None):
+ page = self._get_page()
+ if page:
+ page.cut()
+
+ def paste(self, button = None):
+ page = self._get_page()
+ if page:
+ page.paste()
+
+ def replace(self, ftext, rtext, s_opts):
+ replaced = False
+ if s_opts.use_regex and issubclass(type(ftext),basestring):
+ ftext = re.compile(ftext)
+ multifile = (s_opts.where == S_WHERE.multifile)
+ if multifile and s_opts.replace_all:
+ for n in range(self.get_n_pages()):
+ page = self.get_nth_page(n)
+ replaced = page.replace(ftext, rtext,
+ s_opts) or replaced
+ return (replaced, False) #not found-again
+
+ page = self._get_page()
+ if page:
+ selection = s_opts.where == S_WHERE.selection
+ replaced = page.replace(ftext, rtext, s_opts)
+ if s_opts.replace_all:
+ return (replaced, False)
+ elif not selection:
+ found = self.find_next(ftext,s_opts,page)
+ return (replaced, found)
+ else:
+ #for replace-in-selection, leave selection unmodified
+ return (replaced, replaced)
+
+ def find_next(self, ftext, s_opts, page=None):
+ if not page:
+ page = self._get_page()
+ if page:
+ if s_opts.use_regex and issubclass(type(ftext),basestring):
+ ftext = re.compile(ftext)
+ if page.find_next(ftext,s_opts,
+ wrap=(s_opts.where != S_WHERE.multifile)):
+ return True
+ else:
+ if (s_opts.where == S_WHERE.multifile):
+ current_page = self.get_current_page()
+ n_pages = self.get_n_pages()
+ for i in range(1,n_pages):
+ page = self.get_nth_page((current_page + i) % n_pages)
+ if isinstance(page,SearchablePage):
+ if page.find_next(ftext,s_opts,
+ wrap = True):
+ self.set_current_page((current_page + i) %
+ n_pages)
+ return True
+ return False
+ else:
+ return False #first file failed, not multifile
+ else:
+ return False #no open pages
+
+ def get_all_filenames(self):
+ for i in range(self.get_n_pages()):
+ page = self.get_nth_page(i)
+ if isinstance(page,GtkSourceview2Page):
+ yield page.fullPath
+
+ def save_all(self):
+ _logger.info('save all %i Editor pages' % self.get_n_pages())
+ #if self.activity.is_foreign_dir():
+ #_logger.info('save all aborting, still viewing in place')
+ #return
+ for i in range(self.get_n_pages()):
+ page = self.get_nth_page(i)
+ if isinstance(page,GtkSourceview2Page):
+ _logger.debug('%s' % page.fullPath)
+ page.save()
+
+ def remove_all(self):
+ for i in range(self.get_n_pages(),0,-1):
+ self.remove_page(i-1)
+ """
+ page = self.get_nth_page(i)
+ if isinstance(page,GtkSourceview2Page):
+ self._close_page(None,page
+ """
+ def reroot(self,olddir, newdir):
+ _logger.info('reroot from %s to %s' % (olddir,newdir))
+ for i in range(self.get_n_pages()):
+ page = self.get_nth_page(i)
+ if isinstance(page,GtkSourceview2Page):
+ if page.reroot(olddir, newdir):
+ _logger.info('rerooting page %s failed' %
+ page.fullPath)
+ else:
+ _logger.info('rerooting page %s succeeded' %
+ page.fullPath)
+
+ def get_selected(self):
+ return self._get_page().get_selected()
+
+ def change_font_size(self,size):
+ page = self._get_page()
+ page.set_font_size(size)
+
+class SearchablePage(gtk.ScrolledWindow):
+ def get_selected(self):
+ try:
+ start,end = self.text_buffer.get_selection_bounds()
+ return self.text_buffer.get_slice(start,end)
+ except ValueError:
+ return 0
+
+ def get_text(self):
+ """
+ Return the text that's currently being edited.
+ """
+ start, end = self.text_buffer.get_bounds()
+ return self.text_buffer.get_text(start, end)
+
+ def get_offset(self):
+ """
+ Return the current character position in the currnet file.
+ """
+ insert = self.text_buffer.get_insert()
+ _iter = self.text_buffer.get_iter_at_mark(insert)
+ return _iter.get_offset()
+
+ def copy(self):
+ """
+ Copy the currently selected text to the clipboard.
+ """
+ self.text_buffer.copy_clipboard(gtk.Clipboard())
+
+ def paste(self):
+ """
+ Cut the currently selected text the clipboard into the current file.
+ """
+ self.text_buffer.paste_clipboard(gtk.Clipboard(), None, True)
+
+ def cut(self):
+ """
+ Paste from the clipboard.
+ """
+ self.text_buffer.cut_clipboard(gtk.Clipboard(), True)
+
+ def _getMatches(self,buffertext,fpat,s_opts,offset):
+ if s_opts.use_regex:
+ while True:
+ match = fpat.search(buffertext,re.I if s_opts.ignore_caps else 0)
+ if match:
+ start,end = match.span()
+ yield (start+offset,end+offset,match)
+ else:
+ return
+ buffertext, offset = buffertext[end:],offset+end
+ else:
+ while True:
+ if s_opts.ignore_caps:
+ #possible optimization: turn fpat into a regex by escaping,
+ #then use re.i
+ buffertext = buffertext.lower()
+ fpat = fpat.lower()
+ match = buffertext.find(fpat)
+ if match >= 0:
+ end = match+len(fpat)
+ yield (offset + match, offset + end, None)
+ else:
+ return
+ buffertext, offset = buffertext[end:], offset + end
+
+ def _match(self, pattern, text, s_opts):
+ if s_opts.use_regex:
+ return pattern.match(text,re.I if s_opts.ignore_caps else 0)
+ else:
+ if s_opts.ignore_caps:
+ pattern = pattern.lower()
+ text = text.lower()
+ return pattern == text
+
+ def _find_in(self, text, fpat, offset, s_opts, offset_add = 0):
+ if s_opts.forward:
+ matches = self._getMatches(text[offset:],fpat,s_opts,
+ offset+offset_add)
+ try:
+ return matches.next()
+ except StopIteration:
+ return ()
+ else:
+ if offset != 0:
+ text = text[:offset]
+ matches = list(self._getMatches(text,fpat,s_opts,
+ offset_add))
+ if matches:
+ return matches[-1]
+ else:
+ return ()
+
+ def find_next(self, ftext, s_opts, wrap=True):
+ """
+ Scroll to the next place where the string text appears.
+ If stay is True and text is found at the current position, stay where we are.
+ """
+ if s_opts.where == S_WHERE.selection:
+ try:
+ selstart, selend = self.text_buffer.get_selection_bounds()
+ except (ValueError,TypeError):
+ return False
+ offsetadd = selstart.get_offset()
+ buffertext = self.text_buffer.get_slice(selstart,selend)
+ print buffertext
+ try:
+ start, end, match = self._find_in(buffertext, ftext, 0,
+ s_opts, offsetadd)
+ except (ValueError,TypeError):
+ return False
+ else:
+ offset = self.get_offset() + (not s_opts.stay) #add 1 if not stay.
+ text = self.get_text()
+ try:
+ start,end,match = self._find_in(text, ftext, offset,
+ s_opts, 0)
+ except (ValueError,TypeError):
+ #find failed.
+ if wrap:
+ try:
+ start,end,match = self._find_in(text, ftext, 0,
+ s_opts, 0)
+ except (ValueError,TypeError):
+ return False
+ else:
+ return False
+ self._scroll_to_offset(start,end)
+ self.text_view.grab_focus()
+ return True
+
+ def _scroll_to_offset(self, offset, bound):
+ _iter = self.text_buffer.get_iter_at_offset(offset)
+ _iter2 = self.text_buffer.get_iter_at_offset(bound)
+ self.text_buffer.select_range(_iter,_iter2)
+ self.text_view.scroll_mark_onscreen(self.text_buffer.get_insert())
+
+ def _scroll_to_line(self,line):
+ _iter = self.text_buffer.get_iter_at_line(line)
+ self.text_buffer.select_range(_iter,_iter)
+ self.text_view.scroll_mark_onscreen(self.text_buffer.get_insert())
+
+
+ def __eq__(self,other):
+ if isinstance(other,GtkSourceview2Page):
+ return self.fullPath == other.fullPath
+ #elif isinstance(other,type(self.fullPath)):
+ # other = other.metadata['source']
+ if isinstance(other,basestring):
+ return other == self.fullPath
+ else:
+ return False
+
+class GtkSourceview2Page(SearchablePage):
+
+ def __init__(self, fullPath, activity):
+ """
+ Do any initialization here.
+ """
+ gtk.ScrolledWindow.__init__(self)
+
+ self.fullPath = fullPath
+ self.activity = activity
+
+ self.text_buffer = gtksourceview2.Buffer()
+ self.text_view = gtksourceview2.View(self.text_buffer)
+
+ self.text_view.set_size_request(900, 350)
+ self.text_view.set_editable(True)
+ self.text_view.set_cursor_visible(True)
+ self.text_view.set_highlight_current_line(True)
+ self.text_view.set_show_line_numbers(True)
+ self.text_view.set_insert_spaces_instead_of_tabs(True)
+ if hasattr(self.text_view, 'set_tabs_width'):
+ self.text_view.set_tabs_width(4)
+ else:
+ self.text_view.set_tab_width(4)
+ self.text_view.set_auto_indent(True)
+
+ self.text_view.set_wrap_mode(gtk.WRAP_CHAR)
+ #self.text_view.modify_font(pango.FontDescription("Monospace 6.5"))
+ self.set_font_size(self.activity.font_size)
+
+ # We could change the color theme here, if we want to.
+ mgr = gtksourceview2.StyleSchemeManager()
+ mgr.prepend_search_path(self.activity.pydebug_path)
+ _logger.debug('search path for gtksourceview is %r'%mgr.get_search_path())
+ style_scheme = mgr.get_scheme('vibrant')
+ self.text_buffer.set_style_scheme(style_scheme)
+
+ self.set_policy(gtk.POLICY_AUTOMATIC,
+ gtk.POLICY_AUTOMATIC)
+ self.add(self.text_view)
+ self.text_view.show()
+ self.load_text()
+ self.show()
+
+ def set_font_size(self,font_size=None):
+ if font_size == None: font_size = self.activity.font_size
+ self.text_view.modify_font(pango.FontDescription("Monospace %d"%font_size))
+ _logger.debug('setting font size to %d'%font_size)
+
+ def load_text(self, offset=None):
+ """
+ Load the text, and optionally scroll to the given offset in the file.
+ """
+ self.text_buffer.begin_not_undoable_action()
+ _file = file(self.fullPath)
+ self.text_buffer.set_text(_file.read())
+ _file.close()
+ self.save_hash()
+ if offset is not None:
+ self._scroll_to_offset(offset)
+
+ if hasattr(self.text_buffer, 'set_highlight'):
+ self.text_buffer.set_highlight(False)
+ else:
+ self.text_buffer.set_highlight_syntax(False)
+ mime_type = mimetypes.guess_type(self.fullPath)[0]
+ if mime_type:
+ lang_manager = gtksourceview2.language_manager_get_default()
+ if hasattr(lang_manager, 'list_languages'):
+ langs = lang_manager.list_languages()
+ else:
+ lang_ids = lang_manager.get_language_ids()
+ langs = [lang_manager.get_language(i) for i in lang_ids]
+ for lang in langs:
+ for m in lang.get_mime_types():
+ if m == mime_type:
+ self.text_buffer.set_language(lang)
+ if hasattr(self.text_buffer, 'set_highlight'):
+ self.text_buffer.set_highlight(True)
+ else:
+ self.text_buffer.set_highlight_syntax(True)
+ self.text_buffer.end_not_undoable_action()
+ self.text_buffer.set_modified(False)
+ self.text_view.grab_focus()
+
+ def save_hash(self):
+ self.md5sum = self.activity.md5sum(self.fullPath)
+
+ def remove(self):
+ self.save()
+
+ def save(self,skip_md5 = False, interactive_close=False):
+ if not self.text_buffer.can_undo() or self.activity.abandon_changes:
+ if not self.text_buffer.can_undo():
+ _logger.debug('no changes for %s'%os.path.basename(self.fullPath))
+ return #only save if there's something to save
+ if not skip_md5:
+ hash = self.activity.md5sum(self.fullPath)
+ if self.md5sum != hash: #underlying file has changed
+ _logger.warning('md5sum stored:%s. Calculated:%s'%(self.md5sum,hash))
+ _logger.warning('md5sum changed outside editor for %s. Save file questioned'
+ %os.path.basename(self.fullPath))
+ self.activity.confirmation_alert(_('Would you like to overwrite the changes in %s?'%os.path.basename(self.fullPath)),
+ _('The Underlying File Has Been Changed By Another Application'),
+ self.continue_save)
+ return
+ if self.interactive_close and self.text_buffer.can_undo():
+ self.activity.confirmation_alert(_('Would you to Save the file, or cancel the Save?',
+ _('This File Has Been Changed'),self.continue_save))
+
+ self.continue_save(None)
+
+ def continue_save(self, alert, response = None):
+ if not self.fullPath.startswith(self.activity.debugger_home):
+ self.activity.alert(_('Can only save in locations under %s'%self.activity.debugger_home))
+ _logger.debug('failed to save self.fullPath: %s, Checked for starting with %s'%(self.fullPath, self.activity.debugger_home))
+ return
+ _logger.debug('saving %s'%os.path.basename(self.fullPath))
+ text = self.get_text()
+ _file = file(self.fullPath, 'w')
+ try:
+ _file.write(text)
+ _file.close()
+ self.save_hash()
+ self.label.set_text(os.path.basename(self.fullPath))
+ self.text_buffer.set_modified(False)
+ msg = _("File saved: %s md5sumn:%s"%(os.path.basename(self.fullPath),self.md5sum))
+ _logger.debug(msg)
+ except IOError as (errno, strerror):
+ msg = _("I/O error({0}): {1}".format(errno, strerror))
+ self.activity.alert(msg)
+ except:
+ msg = "Unexpected error:", sys.exc_info()[0]
+ self.activity.alert(msg)
+ if _file:
+ _file.close()
+
+ def underlying_change_cb(self,response):
+ #remove the alert from the screen, since either a response button
+ #was clicked or there was a timeout
+ self.remove_alert(alert)
+
+ #Do any work that is specific to the type of button clicked.
+ if response_id is gtk.RESPONSE_OK:
+ self.continue_save()
+ elif response_id is gtk.RESPONSE_CANCEL:
+ return
+
+ def can_undo_redo(self):
+ """
+ Returns a two-tuple (can_undo, can_redo) with Booleans of those abilities.
+ """
+ return (self.text_buffer.can_undo(), self.text_buffer.can_redo())
+
+ def undo(self):
+ """
+ Undo the last change in the file. If we can't do anything, ignore.
+ """
+ self.text_buffer.undo()
+
+ def redo(self):
+ """
+ Redo the last change in the file. If we can't do anything, ignore.
+ """
+ self.text_buffer.redo()
+
+ def replace(self, ftext, rtext, s_opts):
+ """returns true if replaced (succeeded)"""
+ selection = s_opts.where == S_WHERE.selection
+ if s_opts.replace_all or selection:
+ result = False
+ if selection:
+ try:
+ selstart, selend = self.text_buffer.get_selection_bounds()
+ except (ValueError,TypeError):
+ return False
+ offsetadd = selstart.get_offset()
+ buffertext = self.text_buffer.get_slice(selstart,selend)
+ else:
+ offsetadd = 0
+ buffertext = self.get_text()
+ results = list(self._getMatches(buffertext,ftext,
+ s_opts,offsetadd))
+ if not s_opts.replace_all:
+ results = [results[0]]
+ else:
+ results.reverse() #replace right-to-left so that
+ #unreplaced indexes remain valid.
+ self.text_buffer.begin_user_action()
+ for start, end, match in results:
+ start = self.text_buffer.get_iter_at_offset(start)
+ end = self.text_buffer.get_iter_at_offset(end)
+ self.text_buffer.delete(start,end)
+ self.text_buffer.insert(start, self.makereplace(rtext,match,s_opts.use_regex))
+ result = True
+ self.text_buffer.end_user_action()
+ return result
+ else: #replace, the &find part handled by caller
+ try:
+ start,end = self.text_buffer.get_selection_bounds()
+ except TypeError:
+ return False
+ match = self._match(ftext,
+ self.text_buffer.get_slice(start,end),
+ s_opts)
+ if match:
+ self.text_buffer.delete(start, end)
+ rtext = self.makereplace(rtext,match,s_opts.use_regex)
+ self.text_buffer.insert(start, rtext)
+ return True
+ else:
+ return False
+
+ def makereplace(self, rpat, match, use_regex):
+ if use_regex:
+ return match.expand(rpat)
+ else:
+ return rpat
+
+ def reroot(self,olddir,newdir):
+ """Returns False if it works"""
+ oldpath = self.fullPath
+ if oldpath.startswith(olddir):
+ self.fullPath = os.path.join(newdir, oldpath[len(olddir):])
+ return False
+ else:
+ return True
diff --git a/sourceview_editor.py~ b/sourceview_editor.py~
new file mode 100644
index 0000000..40368cd
--- /dev/null
+++ b/sourceview_editor.py~
@@ -0,0 +1,636 @@
+# Copyright 2008 Paul Swartz
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import gtk, gobject
+import pango
+import notebook
+import gtksourceview2
+import os.path
+import sys
+import re
+import mimetypes
+from exceptions import *
+import hashlib
+from gettext import gettext as _
+
+# Initialize logging.
+import logging
+from sugar import logger
+#Get the standard logging directory.
+std_log_dir = logger.get_logs_dir()
+_logger = logging.getLogger('PyDebug')
+
+_logger.setLevel(logging.DEBUG)
+
+class S_WHERE:
+ selection, file, multifile = range(3) #an enum
+
+class GtkSourceview2Editor(notebook.Notebook):
+ __gsignals__ = {
+ 'changed': (gobject.SIGNAL_RUN_FIRST, None, [])
+ }
+
+ def __init__(self, activity):
+ notebook.Notebook.__init__(self, can_close_tabs=True)
+ self._can_close_tabs = True #redundant, but above call broken for some reason
+ self.activity = activity
+ self.set_size_request(900, 350)
+ self.connect('page-removed', self._page_removed_cb)
+ self.connect('switch-page', self._switch_page_cb)
+
+ def _page_removed_cb(self, notebook, page, n):
+ _logger.debug('removing page %d'%n)
+ if self.interactive_close:
+ self.interactive_close = False
+ page.save(interactive_close=True)
+ page.save()
+
+ def _switch_page_cb(self, notebook, page_gptr, page_num):
+ pass
+ #self.activity.update_sidebar_to_page(self.get_nth_page(page_num))
+
+ def set_to_page_like(self,eq_to_page):
+ for n in range(self.get_n_pages()):
+ page = self.get_nth_page(n)
+ if page == eq_to_page:
+ self.set_current_page(n)
+ return True
+ return False
+
+ def load_object(self, fullPath, filename):
+ if self.set_to_page_like(fullPath):
+ return
+ page = GtkSourceview2Page(fullPath, self.activity)
+ label = filename
+ page.text_buffer.connect('changed', self._changed_cb)
+ self.add_page(label, page)
+ #label object is passed back in Notebook object -- remember it
+ page.label = self.tab_label
+ _logger.debug('new label text: %s'%page.label.get_text())
+ self.set_current_page(-1)
+ self._changed_cb(page.text_buffer)
+
+ def position_to(self, fullPath, line = 0, col = 0):
+ self.load_object(fullPath, os.path.basename(fullPath))
+ page = self._get_page()
+ page._scroll_to_line(line)
+
+
+ def _changed_cb(self, buffer):
+ if not buffer.can_undo():
+ buffer.set_modified(False)
+ self.clear_changed_star()
+ elif not self.activity.dirty:
+ self.activity.set_dirty(True)
+ self.emit('changed')
+ if buffer.can_undo():
+ self.set_changed_star()
+
+ def _get_page(self):
+ n = self.get_current_page()
+ return self.get_nth_page(n)
+
+ def get_full_path(self):
+ page = self._get_page()
+ return page.fullPath
+
+ def set_changed_star(self, button = None):
+ page = self._get_page()
+ if page:
+ current = page.label.get_text()
+ if current.startswith('*'):return
+ page.label.set_text('*' + current)
+
+ def clear_changed_star(self, button = None):
+ page = self._get_page()
+ if page:
+ current = os.path.basename(page.fullPath)
+ page.label.set_text(current)
+
+ def set_focus(self):
+ page = self._get_page()
+ if page:
+ page.text_view.grab_focus()
+
+
+ def can_undo_redo(self):
+ page = self._get_page()
+ if page is None:
+ return (False, False)
+ else:
+ return page.can_undo_redo()
+
+ def undo(self, button = None):
+ page = self._get_page()
+ if page:
+ page.undo()
+
+ def redo(self, button = None):
+ page = self._get_page()
+ if page:
+ page.redo()
+
+ def copy(self, button = None):
+ page = self._get_page()
+ if page:
+ page.copy()
+
+ def cut(self, button = None):
+ page = self._get_page()
+ if page:
+ page.cut()
+
+ def paste(self, button = None):
+ page = self._get_page()
+ if page:
+ page.paste()
+
+ def replace(self, ftext, rtext, s_opts):
+ replaced = False
+ if s_opts.use_regex and issubclass(type(ftext),basestring):
+ ftext = re.compile(ftext)
+ multifile = (s_opts.where == S_WHERE.multifile)
+ if multifile and s_opts.replace_all:
+ for n in range(self.get_n_pages()):
+ page = self.get_nth_page(n)
+ replaced = page.replace(ftext, rtext,
+ s_opts) or replaced
+ return (replaced, False) #not found-again
+
+ page = self._get_page()
+ if page:
+ selection = s_opts.where == S_WHERE.selection
+ replaced = page.replace(ftext, rtext, s_opts)
+ if s_opts.replace_all:
+ return (replaced, False)
+ elif not selection:
+ found = self.find_next(ftext,s_opts,page)
+ return (replaced, found)
+ else:
+ #for replace-in-selection, leave selection unmodified
+ return (replaced, replaced)
+
+ def find_next(self, ftext, s_opts, page=None):
+ if not page:
+ page = self._get_page()
+ if page:
+ if s_opts.use_regex and issubclass(type(ftext),basestring):
+ ftext = re.compile(ftext)
+ if page.find_next(ftext,s_opts,
+ wrap=(s_opts.where != S_WHERE.multifile)):
+ return True
+ else:
+ if (s_opts.where == S_WHERE.multifile):
+ current_page = self.get_current_page()
+ n_pages = self.get_n_pages()
+ for i in range(1,n_pages):
+ page = self.get_nth_page((current_page + i) % n_pages)
+ if isinstance(page,SearchablePage):
+ if page.find_next(ftext,s_opts,
+ wrap = True):
+ self.set_current_page((current_page + i) %
+ n_pages)
+ return True
+ return False
+ else:
+ return False #first file failed, not multifile
+ else:
+ return False #no open pages
+
+ def get_all_filenames(self):
+ for i in range(self.get_n_pages()):
+ page = self.get_nth_page(i)
+ if isinstance(page,GtkSourceview2Page):
+ yield page.fullPath
+
+ def save_all(self):
+ _logger.info('save all %i Editor pages' % self.get_n_pages())
+ #if self.activity.is_foreign_dir():
+ #_logger.info('save all aborting, still viewing in place')
+ #return
+ for i in range(self.get_n_pages()):
+ page = self.get_nth_page(i)
+ if isinstance(page,GtkSourceview2Page):
+ _logger.debug('%s' % page.fullPath)
+ page.save()
+
+ def remove_all(self):
+ for i in range(self.get_n_pages()):
+ self.remove_page(i)
+ """
+ page = self.get_nth_page(i)
+ if isinstance(page,GtkSourceview2Page):
+ self._close_page(None,page
+ """
+ def reroot(self,olddir, newdir):
+ _logger.info('reroot from %s to %s' % (olddir,newdir))
+ for i in range(self.get_n_pages()):
+ page = self.get_nth_page(i)
+ if isinstance(page,GtkSourceview2Page):
+ if page.reroot(olddir, newdir):
+ _logger.info('rerooting page %s failed' %
+ page.fullPath)
+ else:
+ _logger.info('rerooting page %s succeeded' %
+ page.fullPath)
+
+ def get_selected(self):
+ return self._get_page().get_selected()
+
+ def change_font_size(self,size):
+ page = self._get_page()
+ page.set_font_size(size)
+
+class SearchablePage(gtk.ScrolledWindow):
+ def get_selected(self):
+ try:
+ start,end = self.text_buffer.get_selection_bounds()
+ return self.text_buffer.get_slice(start,end)
+ except ValueError:
+ return 0
+
+ def get_text(self):
+ """
+ Return the text that's currently being edited.
+ """
+ start, end = self.text_buffer.get_bounds()
+ return self.text_buffer.get_text(start, end)
+
+ def get_offset(self):
+ """
+ Return the current character position in the currnet file.
+ """
+ insert = self.text_buffer.get_insert()
+ _iter = self.text_buffer.get_iter_at_mark(insert)
+ return _iter.get_offset()
+
+ def copy(self):
+ """
+ Copy the currently selected text to the clipboard.
+ """
+ self.text_buffer.copy_clipboard(gtk.Clipboard())
+
+ def paste(self):
+ """
+ Cut the currently selected text the clipboard into the current file.
+ """
+ self.text_buffer.paste_clipboard(gtk.Clipboard(), None, True)
+
+ def cut(self):
+ """
+ Paste from the clipboard.
+ """
+ self.text_buffer.cut_clipboard(gtk.Clipboard(), True)
+
+ def _getMatches(self,buffertext,fpat,s_opts,offset):
+ if s_opts.use_regex:
+ while True:
+ match = fpat.search(buffertext,re.I if s_opts.ignore_caps else 0)
+ if match:
+ start,end = match.span()
+ yield (start+offset,end+offset,match)
+ else:
+ return
+ buffertext, offset = buffertext[end:],offset+end
+ else:
+ while True:
+ if s_opts.ignore_caps:
+ #possible optimization: turn fpat into a regex by escaping,
+ #then use re.i
+ buffertext = buffertext.lower()
+ fpat = fpat.lower()
+ match = buffertext.find(fpat)
+ if match >= 0:
+ end = match+len(fpat)
+ yield (offset + match, offset + end, None)
+ else:
+ return
+ buffertext, offset = buffertext[end:], offset + end
+
+ def _match(self, pattern, text, s_opts):
+ if s_opts.use_regex:
+ return pattern.match(text,re.I if s_opts.ignore_caps else 0)
+ else:
+ if s_opts.ignore_caps:
+ pattern = pattern.lower()
+ text = text.lower()
+ return pattern == text
+
+ def _find_in(self, text, fpat, offset, s_opts, offset_add = 0):
+ if s_opts.forward:
+ matches = self._getMatches(text[offset:],fpat,s_opts,
+ offset+offset_add)
+ try:
+ return matches.next()
+ except StopIteration:
+ return ()
+ else:
+ if offset != 0:
+ text = text[:offset]
+ matches = list(self._getMatches(text,fpat,s_opts,
+ offset_add))
+ if matches:
+ return matches[-1]
+ else:
+ return ()
+
+ def find_next(self, ftext, s_opts, wrap=True):
+ """
+ Scroll to the next place where the string text appears.
+ If stay is True and text is found at the current position, stay where we are.
+ """
+ if s_opts.where == S_WHERE.selection:
+ try:
+ selstart, selend = self.text_buffer.get_selection_bounds()
+ except (ValueError,TypeError):
+ return False
+ offsetadd = selstart.get_offset()
+ buffertext = self.text_buffer.get_slice(selstart,selend)
+ print buffertext
+ try:
+ start, end, match = self._find_in(buffertext, ftext, 0,
+ s_opts, offsetadd)
+ except (ValueError,TypeError):
+ return False
+ else:
+ offset = self.get_offset() + (not s_opts.stay) #add 1 if not stay.
+ text = self.get_text()
+ try:
+ start,end,match = self._find_in(text, ftext, offset,
+ s_opts, 0)
+ except (ValueError,TypeError):
+ #find failed.
+ if wrap:
+ try:
+ start,end,match = self._find_in(text, ftext, 0,
+ s_opts, 0)
+ except (ValueError,TypeError):
+ return False
+ else:
+ return False
+ self._scroll_to_offset(start,end)
+ self.text_view.grab_focus()
+ return True
+
+ def _scroll_to_offset(self, offset, bound):
+ _iter = self.text_buffer.get_iter_at_offset(offset)
+ _iter2 = self.text_buffer.get_iter_at_offset(bound)
+ self.text_buffer.select_range(_iter,_iter2)
+ self.text_view.scroll_mark_onscreen(self.text_buffer.get_insert())
+
+ def _scroll_to_line(self,line):
+ _iter = self.text_buffer.get_iter_at_line(line)
+ self.text_buffer.select_range(_iter,_iter)
+ self.text_view.scroll_mark_onscreen(self.text_buffer.get_insert())
+
+
+ def __eq__(self,other):
+ if isinstance(other,GtkSourceview2Page):
+ return self.fullPath == other.fullPath
+ #elif isinstance(other,type(self.fullPath)):
+ # other = other.metadata['source']
+ if isinstance(other,basestring):
+ return other == self.fullPath
+ else:
+ return False
+
+class GtkSourceview2Page(SearchablePage):
+
+ def __init__(self, fullPath, activity):
+ """
+ Do any initialization here.
+ """
+ gtk.ScrolledWindow.__init__(self)
+
+ self.fullPath = fullPath
+ self.activity = activity
+
+ self.text_buffer = gtksourceview2.Buffer()
+ self.text_view = gtksourceview2.View(self.text_buffer)
+
+ self.text_view.set_size_request(900, 350)
+ self.text_view.set_editable(True)
+ self.text_view.set_cursor_visible(True)
+ self.text_view.set_highlight_current_line(True)
+ self.text_view.set_show_line_numbers(True)
+ self.text_view.set_insert_spaces_instead_of_tabs(True)
+ if hasattr(self.text_view, 'set_tabs_width'):
+ self.text_view.set_tabs_width(4)
+ else:
+ self.text_view.set_tab_width(4)
+ self.text_view.set_auto_indent(True)
+
+ self.text_view.set_wrap_mode(gtk.WRAP_CHAR)
+ #self.text_view.modify_font(pango.FontDescription("Monospace 6.5"))
+ self.set_font_size(self.activity.font_size)
+
+ # We could change the color theme here, if we want to.
+ mgr = gtksourceview2.StyleSchemeManager()
+ mgr.prepend_search_path(self.activity.pydebug_path)
+ _logger.debug('search path for gtksourceview is %r'%mgr.get_search_path())
+ style_scheme = mgr.get_scheme('vibrant')
+ self.text_buffer.set_style_scheme(style_scheme)
+
+ self.set_policy(gtk.POLICY_AUTOMATIC,
+ gtk.POLICY_AUTOMATIC)
+ self.add(self.text_view)
+ self.text_view.show()
+ self.load_text()
+ self.show()
+
+ def set_font_size(self,font_size=None):
+ if font_size == None: font_size = self.activity.font_size
+ self.text_view.modify_font(pango.FontDescription("Monospace %d"%font_size))
+ _logger.debug('setting font size to %d'%font_size)
+
+ def load_text(self, offset=None):
+ """
+ Load the text, and optionally scroll to the given offset in the file.
+ """
+ self.text_buffer.begin_not_undoable_action()
+ _file = file(self.fullPath)
+ self.text_buffer.set_text(_file.read())
+ _file.close()
+ self.save_hash()
+ if offset is not None:
+ self._scroll_to_offset(offset)
+
+ if hasattr(self.text_buffer, 'set_highlight'):
+ self.text_buffer.set_highlight(False)
+ else:
+ self.text_buffer.set_highlight_syntax(False)
+ mime_type = mimetypes.guess_type(self.fullPath)[0]
+ if mime_type:
+ lang_manager = gtksourceview2.language_manager_get_default()
+ if hasattr(lang_manager, 'list_languages'):
+ langs = lang_manager.list_languages()
+ else:
+ lang_ids = lang_manager.get_language_ids()
+ langs = [lang_manager.get_language(i) for i in lang_ids]
+ for lang in langs:
+ for m in lang.get_mime_types():
+ if m == mime_type:
+ self.text_buffer.set_language(lang)
+ if hasattr(self.text_buffer, 'set_highlight'):
+ self.text_buffer.set_highlight(True)
+ else:
+ self.text_buffer.set_highlight_syntax(True)
+ self.text_buffer.end_not_undoable_action()
+ self.text_buffer.set_modified(False)
+ self.text_view.grab_focus()
+
+ def save_hash(self):
+ self.md5sum = self.activity.md5sum(self.fullPath)
+
+ def remove(self):
+ self.save()
+
+ def save(self,skip_md5 = False, interactive_close=False):
+ if not self.text_buffer.can_undo() or self.activity.abandon_changes:
+ if not self.text_buffer.can_undo():
+ _logger.debug('no changes for %s'%os.path.basename(self.fullPath))
+ return #only save if there's something to save
+ if not skip_md5:
+ hash = self.activity.md5sum(self.fullPath)
+ if self.md5sum != hash: #underlying file has changed
+ _logger.warning('md5sum stored:%s. Calculated:%s'%(self.md5sum,hash))
+ _logger.warning('md5sum changed outside editor for %s. Save file questioned'
+ %os.path.basename(self.fullPath))
+ self.activity.confirmation_alert(_('Would you like to overwrite the changes in %s?'%os.path.basename(self.fullPath)),
+ _('The Underlying File Has Been Changed By Another Application'),
+ self.continue_save)
+ return
+ if self.interactive_close and self.text_buffer.can_undo():
+ self.activity.confirmation_alert(_('Would you to Save the file, or cancel the Save?',
+ _('This File Has Been Changed'),self.continue_save))
+
+ self.continue_save(None)
+
+ def continue_save(self, alert, response = None):
+ if not self.fullPath.startswith(self.activity.debugger_home):
+ self.activity.alert(_('Can only save in locations under %s'%self.activity.debugger_home))
+ _logger.debug('failed to save self.fullPath: %s, Checked for starting with %s'%(self.fullPath, self.activity.debugger_home))
+ return
+ _logger.debug('saving %s'%os.path.basename(self.fullPath))
+ text = self.get_text()
+ _file = file(self.fullPath, 'w')
+ try:
+ _file.write(text)
+ _file.close()
+ self.save_hash()
+ self.label.set_text(os.path.basename(self.fullPath))
+ self.text_buffer.set_modified(False)
+ msg = _("File saved: %s md5sumn:%s"%(os.path.basename(self.fullPath),self.md5sum))
+ _logger.debug(msg)
+ except IOError as (errno, strerror):
+ msg = _("I/O error({0}): {1}".format(errno, strerror))
+ self.activity.alert(msg)
+ except:
+ msg = "Unexpected error:", sys.exc_info()[0]
+ self.activity.alert(msg)
+ if _file:
+ _file.close()
+
+ def underlying_change_cb(self,response):
+ #remove the alert from the screen, since either a response button
+ #was clicked or there was a timeout
+ self.remove_alert(alert)
+
+ #Do any work that is specific to the type of button clicked.
+ if response_id is gtk.RESPONSE_OK:
+ self.continue_save()
+ elif response_id is gtk.RESPONSE_CANCEL:
+ return
+
+ def can_undo_redo(self):
+ """
+ Returns a two-tuple (can_undo, can_redo) with Booleans of those abilities.
+ """
+ return (self.text_buffer.can_undo(), self.text_buffer.can_redo())
+
+ def undo(self):
+ """
+ Undo the last change in the file. If we can't do anything, ignore.
+ """
+ self.text_buffer.undo()
+
+ def redo(self):
+ """
+ Redo the last change in the file. If we can't do anything, ignore.
+ """
+ self.text_buffer.redo()
+
+ def replace(self, ftext, rtext, s_opts):
+ """returns true if replaced (succeeded)"""
+ selection = s_opts.where == S_WHERE.selection
+ if s_opts.replace_all or selection:
+ result = False
+ if selection:
+ try:
+ selstart, selend = self.text_buffer.get_selection_bounds()
+ except (ValueError,TypeError):
+ return False
+ offsetadd = selstart.get_offset()
+ buffertext = self.text_buffer.get_slice(selstart,selend)
+ else:
+ offsetadd = 0
+ buffertext = self.get_text()
+ results = list(self._getMatches(buffertext,ftext,
+ s_opts,offsetadd))
+ if not s_opts.replace_all:
+ results = [results[0]]
+ else:
+ results.reverse() #replace right-to-left so that
+ #unreplaced indexes remain valid.
+ self.text_buffer.begin_user_action()
+ for start, end, match in results:
+ start = self.text_buffer.get_iter_at_offset(start)
+ end = self.text_buffer.get_iter_at_offset(end)
+ self.text_buffer.delete(start,end)
+ self.text_buffer.insert(start, self.makereplace(rtext,match,s_opts.use_regex))
+ result = True
+ self.text_buffer.end_user_action()
+ return result
+ else: #replace, the &find part handled by caller
+ try:
+ start,end = self.text_buffer.get_selection_bounds()
+ except TypeError:
+ return False
+ match = self._match(ftext,
+ self.text_buffer.get_slice(start,end),
+ s_opts)
+ if match:
+ self.text_buffer.delete(start, end)
+ rtext = self.makereplace(rtext,match,s_opts.use_regex)
+ self.text_buffer.insert(start, rtext)
+ return True
+ else:
+ return False
+
+ def makereplace(self, rpat, match, use_regex):
+ if use_regex:
+ return match.expand(rpat)
+ else:
+ return rpat
+
+ def reroot(self,olddir,newdir):
+ """Returns False if it works"""
+ oldpath = self.fullPath
+ if oldpath.startswith(olddir):
+ self.fullPath = os.path.join(newdir, oldpath[len(olddir):])
+ return False
+ else:
+ return True
diff --git a/start_debug.py b/start_debug.py
new file mode 100644
index 0000000..8120143
--- /dev/null
+++ b/start_debug.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2007, Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import os
+
+# Initialize logging.
+import logging
+_logger = logging.getLogger('PyDebug')
+_logger.setLevel(logging.DEBUG)
+
+from Rpyc import *
+try:
+ c = SocketConnection('localhost')
+ db = c.modules.pydebug.pydebug_instance
+except AttributeError:
+ _logger.error('cannot connect to localhost')
+except e:
+ print(e[1])
+ assert False
+pydebug_path = db.pydebug_path
+print('pydebug path: %s'%pydebug_path)
+#define interface with the command line ipython instance
+from IPython.core import ipapi
+from IPython.core.macro import Macro
+ip = ipapi.get()
+cmd = 'run -pdb -d %s\n'% os.path.join(pydebug_path,'bin','continue_debug.py')
+ip.user_ns['go'] = Macro(cmd)
+alias_cmd = '!alias go=%s'%os.path.join(pydebug_path,'bin','continue_debug.py')
+os.system(alias_cmd)
diff --git a/terminal_pd.py b/terminal_pd.py
new file mode 100644
index 0000000..a92cf23
--- /dev/null
+++ b/terminal_pd.py
@@ -0,0 +1,278 @@
+# Copyright (C) 2007, Eduardo Silva <edsiper@gmail.com>.
+# Copyright (C) 2008, One Laptop Per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import os, os.path, simplejson, ConfigParser, sys
+
+from gettext import gettext as _
+
+# Initialize logging.
+import logging
+_logger = logging.getLogger('PyDebug')
+
+import gtk
+import vte
+import pango
+
+from sugar.graphics.toolbutton import ToolButton
+import sugar.graphics.toolbutton
+import sugar.activity.activity
+import sugar.env
+import sugar.activity.bundlebuilder
+
+from shutil import copy, copytree
+
+MASKED_ENVIRONMENT = [
+ 'DBUS_SESSION_BUS_ADDRESS',
+ 'PPID'
+]
+
+class Terminal():
+
+ def __init__(self,handle):
+ pass
+
+ def _get_terminal_canvas(self):
+ self.terminal_notebook = gtk.Notebook()
+ self.terminal_notebook.set_property("tab-pos", gtk.POS_BOTTOM)
+ self.terminal_notebook.set_scrollable(True)
+ self.terminal_notebook.show()
+ return self.terminal_notebook
+
+ def _open_tab_cb(self, btn):
+ index = self._create_tab(None)
+ self.terminal_notebook.page = index
+
+ def _close_tab_cb(self, btn):
+ self._close_tab(self.terminal_notebook.props.page)
+
+ def _prev_tab_cb(self, btn):
+ if self.terminal_notebook.props.page == 0:
+ self.terminal_notebook.props.page = self.terminal_notebook.get_n_pages() - 1
+ else:
+ self.terminal_notebook.props.page = self.terminal_notebook.props.page - 1
+ vt = self.terminal_notebook.get_nth_page(self.terminal_notebook.get_current_page()).vt
+ vt.grab_focus()
+
+ def _next_tab_cb(self, btn):
+ if self.terminal_notebook.props.page == self.terminal_notebook.get_n_pages() - 1:
+ self.terminal_notebook.props.page = 0
+ else:
+ self.terminal_notebook.props.page = self.terminal_notebook.props.page + 1
+ vt = self.terminal_notebook.get_nth_page(self.terminal_notebook.get_current_page()).vt
+ vt.grab_focus()
+
+ def _close_tab(self, index):
+ self.terminal_notebook.remove_page(index)
+ if self.terminal_notebook.get_n_pages() == 0:
+ self.close()
+
+ def _tab_child_exited_cb(self, vt):
+ for i in range(self.terminal_notebook.get_n_pages()):
+ if self.terminal_notebook.get_nth_page(i).vt == vt:
+ self._close_tab(i)
+ return
+
+ def _tab_title_changed_cb(self, vt):
+ for i in range(self.terminal_notebook.get_n_pages()):
+ if self.terminal_notebook.get_nth_page(i).vt == vt:
+ label = self.terminal_notebook.get_nth_page(i).label
+ label.set_text(vt.get_window_title())
+ return
+
+ def _drag_data_received_cb(self, widget, context, x, y, selection, target, time):
+ widget.feed_child(selection.data)
+ context.finish(True, False, time)
+ return True
+
+ def _create_tab(self, tab_state):
+ vt = vte.Terminal()
+ vt.connect("child-exited", self._tab_child_exited_cb)
+ vt.connect("window-title-changed", self._tab_title_changed_cb)
+
+ vt.drag_dest_set(gtk.DEST_DEFAULT_MOTION|gtk.DEST_DEFAULT_DROP,
+ [('text/plain', 0, 0), ('STRING', 0, 1)],
+ gtk.gdk.ACTION_DEFAULT|
+ gtk.gdk.ACTION_COPY)
+ vt.connect('drag_data_received', self._drag_data_received_cb)
+
+ self._configure_vt(vt)
+
+ vt.show()
+
+ label = gtk.Label()
+
+ scrollbar = gtk.VScrollbar(vt.get_adjustment())
+ scrollbar.show()
+
+ box = gtk.HBox()
+ box.pack_start(vt)
+ box.pack_start(scrollbar)
+
+ box.vt = vt
+ box.label = label
+
+ index = self.terminal_notebook.append_page(box, label)
+ self.terminal_notebook.show_all()
+
+ # Uncomment this to only show the tab bar when there is at least one tab.
+ # I think it's useful to always see it, since it displays the 'window title'.
+ #self.terminal_notebook.props.show_tabs = self.terminal_notebook.get_n_pages() > 1
+
+ # Launch the default shell in the HOME directory.
+ os.chdir(os.environ["HOME"])
+
+ if tab_state:
+ # Restore the environment.
+ # This is currently not enabled.
+ env = tab_state.get('env',[])
+
+ filtered_env = []
+ for e in env:
+ var, sep, value = e.partition('=')
+ if var not in MASKED_ENVIRONMENT:
+ filtered_env.append(var + sep + value)
+
+ # TODO: Make the shell restore these environment variables, then clear out TERMINAL_ENV.
+ #os.environ['TERMINAL_ENV'] = '\n'.join(filtered_env)
+
+ # Restore the working directory.
+ if tab_state.has_key('cwd'):
+ os.chdir(tab_state['cwd'])
+
+ # Restore the scrollback buffer.
+ if tab_state.has_key('scrollback'):
+ for l in tab_state['scrollback']:
+ vt.feed(l + '\r\n')
+
+ box.pid = vt.fork_command()
+
+ self.terminal_notebook.props.page = index
+ vt.grab_focus()
+
+ return index
+
+ def feed_virtual_terminal(self,terminal,command):
+ if terminal > len(self.terminal_notebook)-1 or terminal < 0:
+ _logging.debug('in feed_virtual_terminal: terminal out of bounds %s'%terminal)
+ return
+ self.terminal_notebook.set_current_page(terminal)
+ vt = self.terminal_notebook.get_nth_page(terminal).vt
+ vt.feed_child(command)
+
+ def message_terminal(self,terminal,command):
+ if terminal > len(self.terminal_notebook)-1 or terminal < 0:
+ _logging.debug('in feed_virtual_terminal: terminal out of bounds %s'%terminal)
+ return
+ self.terminal_notebook.set_current_page(terminal)
+ vt = self.terminal_notebook.get_nth_page(terminal).vt
+ vt.feed(command)
+
+ def _copy_cb(self, button):
+ vt = self.terminal_notebook.get_nth_page(self.terminal_notebook.get_current_page()).vt
+ if vt.get_has_selection():
+ vt.copy_clipboard()
+
+ def _paste_cb(self, button):
+ vt = self.terminal_notebook.get_nth_page(self.terminal_notebook.get_current_page()).vt
+ vt.paste_clipboard()
+
+ def _become_root_cb(self, button):
+ vt = self.terminal_notebook.get_nth_page(self.terminal_notebook.get_current_page()).vt
+ vt.feed('\r\n')
+ vt.fork_command("/bin/su", ('/bin/su', '-'))
+
+ def set_terminal_focus(self):
+ self.terminal_notebook.grab_focus()
+ page = self.terminal_notebook.get_nth_page(self.terminal_notebook.get_current_page())
+ page.grab_focus()
+ vt = page.vt
+ vt.grab_focus()
+ _logger.debug('attemped to grab focus')
+
+ def _fullscreen_cb(self, btn):
+ self.fullscreen()
+
+ def _key_press_cb(self, window, event):
+ # Escape keypresses are routed directly to the vte and then dropped.
+ # This hack prevents Sugar from hijacking them and canceling fullscreen mode.
+ if gtk.gdk.keyval_name(event.keyval) == 'Escape':
+ vt = self.terminal_notebook.get_nth_page(self.terminal_notebook.get_current_page()).vt
+ vt.event(event)
+ return True
+
+ return False
+
+
+
+ def _get_conf(self, conf, var, default):
+ if conf.has_option('terminal', var):
+ if isinstance(default, bool):
+ return conf.getboolean('terminal', var)
+ elif isinstance(default, int):
+ return conf.getint('terminal', var)
+ else:
+ return conf.get('terminal', var)
+ else:
+ conf.set('terminal', var, default)
+
+ return default
+
+ def _configure_vt(self, vt):
+ conf = ConfigParser.ConfigParser()
+ conf_file = os.path.join(os.environ['HOME'], 'terminalrc')
+
+ if os.path.isfile(conf_file):
+ f = open(conf_file, 'r')
+ conf.readfp(f)
+ f.close()
+ else:
+ conf.add_section('terminal')
+
+ font = self._get_conf(conf, 'font', 'Monospace')
+ vt.set_font(pango.FontDescription(font))
+
+ fg_color = self._get_conf(conf, 'fg_color', '#000000')
+ bg_color = self._get_conf(conf, 'bg_color', '#FFFFFF')
+ vt.set_colors(gtk.gdk.color_parse(fg_color), gtk.gdk.color_parse(bg_color), [])
+
+ blink = self._get_conf(conf, 'cursor_blink', False)
+ vt.set_cursor_blinks(blink)
+
+ bell = self._get_conf(conf, 'bell', False)
+ vt.set_audible_bell(bell)
+
+ scrollback_lines = self._get_conf(conf, 'scrollback_lines', 1000)
+ vt.set_scrollback_lines(scrollback_lines)
+
+ vt.set_allow_bold(True)
+
+ scroll_key = self._get_conf(conf, 'scroll_on_keystroke', True)
+ vt.set_scroll_on_keystroke(scroll_key)
+
+ scroll_output = self._get_conf(conf, 'scroll_on_output', False)
+ vt.set_scroll_on_output(scroll_output)
+
+ emulation = self._get_conf(conf, 'emulation', 'xterm')
+ vt.set_emulation(emulation)
+
+ visible_bell = self._get_conf(conf, 'visible_bell', False)
+ vt.set_visible_bell(visible_bell)
+
+ conf.write(open(conf_file, 'w'))
+
+
+
diff --git a/tmp.py b/tmp.py
new file mode 100644
index 0000000..200058a
--- /dev/null
+++ b/tmp.py
@@ -0,0 +1,4 @@
+from Rpyc import *
+c = SocketConnection('localhost')
+print('instance %r'%c.modules.pydebug.pydebug_instance)
+print('pydebug home: %r'%c.modules.pydebug.pydebug_instance.pydebug_home) \ No newline at end of file
diff --git a/vibrant.xml b/vibrant.xml
new file mode 100644
index 0000000..cd32278
--- /dev/null
+++ b/vibrant.xml
@@ -0,0 +1,122 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<style-scheme id="vibrant" _name="Vibrant" version="1.0">
+ <author>Lateef Alabi-Oki</author>
+ <_description>Vibrant colors for your viewing pleasure</_description>
+
+<!-- ubuntu palette -->
+
+ <color name="orange_highlight" value="#eec73e"/>
+ <color name="orange" value="#f0a513"/>
+ <color name="orange_base" value="#fb8b00"/>
+ <color name="orange_shadow" value="#f44800"/>
+
+ <color name="environmental_blue_highlight" value="#aaccee"/>
+ <color name="environmental_blue_medium" value="#6699cc"/>
+ <color name="environmental_blue_base" value="#336699"/>
+ <color name="environmental_blue_shadow" value="#003366"/>
+
+ <color name="accent_yellow_highlight" value="#fdff99"/>
+ <color name="yellow" value="#ffff00"/>
+ <color name="accent_yellow_base" value="#fdca01"/>
+ <color name="accent_yellow_shadow" value="#986601"/>
+
+ <color name="accent_blue_highlight" value="#b3defd"/>
+ <color name="accent_blue" value="#0197fd"/>
+ <color name="accent_blue_base" value="#0169c9"/>
+ <color name="accent_blue_shadow" value="#013397"/>
+
+ <color name="accent_orange" value="#f44800"/>
+ <color name="pure_red" value="#ff0000"/>
+ <color name="accent_red" value="#fd3301"/>
+ <color name="accent_red_base" value="#d40000"/>
+ <color name="accent_deep_red" value="#980101"/>
+
+ <color name="accent_green_highlight" value="#ccff99"/>
+ <color name="accent_green" value="#98fc66"/>
+ <color name="accent_green_base" value="#339900"/>
+ <color name="accent_green_shadow" value="#015a01"/>
+
+ <color name="human_highlight" value="#fdd99b"/>
+ <color name="human" value="#d9bb7a"/>
+ <color name="human_base" value="#816647"/>
+ <color name="environmental_shadow" value="#565248"/>
+
+ <color name="ubuntu_toner" value="#002b3d"/>
+ <color name="accent_magenta_highlight" value="#ff9bff"/>
+ <color name="accent_magenta" value="#ff00ff"/>
+ <color name="accent_dark_violet" value="#6600cc"/>
+
+ <color name="white" value="#ffffff"/>
+ <color name="black" value="#000000"/>
+ <color name="text_fg" value="#4d4d4d"/>
+ <color name="number_color" value="#0000FF"/>
+ <!--color name="comment_color" value="#7F7F7F"/-->
+ <color name="comment_color" value="#ff0000"/>
+
+<!-- Global Settings -->
+
+ <style name="text" foreground="text_fg" background="white"/>
+ <style name="cursor" foreground="accent_deep_red" bold="true"/> <!-- Does not work -->
+ <style name="current-line" background="accent_yellow_highlight"/>
+ <style name="line-numbers" foreground="text_fg" background="human_highlight"/>
+
+<!-- Bracket Matching -->
+
+ <style name="bracket-match" foreground="environmental_blue_medium" background="environmental_blue_highlight"/>
+ <style name="bracket-mismatch" background="dark_maroon" bold="true"/>
+ <style name="search-match" foreground="yellow"/>
+
+<!-- Syntax color for styles
+
+Languages: plain, python, ruby, xml, html, ada, asp, awk, boo, c,
+changelog, chdr, cmake, cpp, csharp, css, d, def, desktop, diff,
+docbook, dosbatch, dot, dpatch, dtd, eiffel, erlang, forth, fortran,
+gap, gtkrc, haddock, haskell, haskell-literate, idl, ini, java,
+javascript, latex, libtool, lua, m4, makefile, msil, nermele, nsis,
+objc, ocaml, ocl, octave, pascal, perl, php, pkgconfig, po, prolog,
+R, rpmspec, scheme, sh, sql, t2t, tcl, texinfo, vala, vbnet, verilog,
+vhdl, xslt, yacc
+
+-->
+
+ <style name="def:string" foreground="accent_blue_base"/>
+ <style name="def:character" foreground="accent_blue_base"/>
+ <style name="def:special-char" foreground="accent_blue" bold="true"/>
+ <style name="def:number" foreground="accent_yellow_shadow"/>
+ <style name="def:decimal" foreground="accent_yellow_shadow"/>
+ <style name="def:floating-point" foreground="accent_dark_violet"/>
+ <style name="def:complex" foreground="environmental_blue_base" bold="true"/>
+ <style name="def:base-n-integer" foreground="black" bold="true"/>
+ <style name="def:boolean" foreground="accent_orange" bold="true"/>
+
+ <style name="def:identifier" foreground="accent_green_base" bold="true"/>
+ <style name="def:type" foreground="ubuntu_toner" bold="true"/>
+ <style name="def:operator" foreground="ubuntu_toner" bold="true"/>
+ <style name="def:keyword" foreground="accent_deep_red" bold="true"/>
+ <style name="def:builtin" foreground="human_base" bold="true"/>
+ <style name="def:function" foreground="human_base" bold="true"/>
+ <style name="def:preprocessor" foreground="accent_dark_violet" bold="true"/>
+ <style name="def:statement" foreground="accent_red_base" bold="true" italic="true"/>
+
+ <style name="def:constant" foreground="black" bold="true"/>
+ <style name="def:special-constant" foreground="accent_orange" bold="true"/>
+ <style name="def:note" foreground="accent_magenta" bold="true"/>
+ <style name="def:error" foreground="accent_red_base" background="black" bold="true"/>
+
+
+<!-- Comments -->
+
+ <style name="def:comment" foreground="accent_red" italic="true"/>
+ <style name="def:shebang" foreground="accent_red" italic="true"/>
+ <style name="def:doc-comment-element" foreground="accent_red" italic="true"/>
+
+<!-- Python Styles -->
+
+ <style name="string-conversion" foreground="accent_blue" italic="true"/>
+
+<!-- XML/HTML Styles Override -->
+
+ <style name="xml:attribute-name" foreground="accent_deep_red" bold="true"/>
+
+</style-scheme>
diff --git a/webview.py b/webview.py
new file mode 100644
index 0000000..8bb7b7e
--- /dev/null
+++ b/webview.py
@@ -0,0 +1,302 @@
+# Copyright (C) 2007, Red Hat, Inc.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the
+# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+import logging
+
+import gobject
+import gtk
+
+from hulahop import _hulahop
+
+import xpcom
+from xpcom import components
+from xpcom.components import interfaces
+from xpcom.nsError import *
+
+class _Chrome:
+ _com_interfaces_ = interfaces.nsIWebBrowserChrome, \
+ interfaces.nsIWebBrowserChrome2, \
+ interfaces.nsIEmbeddingSiteWindow, \
+ interfaces.nsIWebProgressListener, \
+ interfaces.nsIWindowProvider, \
+ interfaces.nsIInterfaceRequestor
+
+ def __init__(self, web_view):
+ self.web_view = web_view
+ self.title = ''
+ self._modal = False
+ self._chrome_flags = interfaces.nsIWebBrowserChrome.CHROME_ALL
+ self._visible = False
+
+ def provideWindow(self, parent, flags, position_specified,
+ size_specified, uri, name, features):
+ if name == "_blank":
+ return parent, False
+ else:
+ return None, False
+
+ # nsIWebBrowserChrome
+ def destroyBrowserWindow(self):
+ logging.debug("nsIWebBrowserChrome.destroyBrowserWindow")
+ if self._modal:
+ self.exitModalEventLoop(0)
+ self.web_view.get_toplevel().destroy()
+
+ def exitModalEventLoop(self, status):
+ logging.debug("nsIWebBrowserChrome.exitModalEventLoop: %r" % status)
+ """
+ if self._continue_modal_loop:
+ self.enable_parent(True)
+ """
+ if self._modal:
+ self._continue_modal_loop = False
+ self._modal = False
+ self._modal_status = status
+ #self.web_view.get_toplevel().grab_remove()
+
+ def isWindowModal(self):
+ logging.debug("nsIWebBrowserChrome.isWindowModal")
+ return self._modal
+
+ def setStatus(self, statusType, status):
+ #logging.debug("nsIWebBrowserChrome.setStatus")
+ self.web_view._set_status(status.encode('utf-8'))
+
+ def showAsModal(self):
+ logging.debug("nsIWebBrowserChrome.showAsModal")
+ self._modal = True
+ self._continue_modal_loop = True
+ self._modal_status = None
+ #EnableParent(PR_FALSE);
+ #self.web_view.get_toplevel().grab_add()
+
+ cls = components.classes["@mozilla.org/thread-manager;1"]
+ thread_manager = cls.getService(interfaces.nsIThreadManager)
+ current_thread = thread_manager.currentThread
+
+ self.web_view.push_js_context()
+ while self._continue_modal_loop:
+ processed = current_thread.processNextEvent(True)
+ if not processed:
+ break
+ self.web_view.pop_js_context()
+
+ self._modal = False
+ self._continue_modal_loop = False
+
+ return self._modal_status
+
+ def sizeBrowserTo(self, cx, cy):
+ logging.debug("nsIWebBrowserChrome.sizeBrowserTo: %r %r" % (cx, cy))
+ self.web_view.get_toplevel().resize(cx, cy)
+ self.web_view.type = WebView.TYPE_POPUP
+
+ # nsIWebBrowserChrome2
+ def setStatusWithContext(self, statusType, statusText, statusContext):
+ self.web_view._set_status(statusText.encode('utf-8'))
+
+ # nsIEmbeddingSiteWindow
+ def getDimensions(self, flags):
+ logging.debug("nsIEmbeddingSiteWindow.getDimensions: %r" % flags)
+ base_window = self.web_view.browser.queryInterface(interfaces.nsIBaseWindow)
+ if (flags & interfaces.nsIEmbeddingSiteWindow.DIM_FLAGS_POSITION) and \
+ ((flags & interfaces.nsIEmbeddingSiteWindow.DIM_FLAGS_SIZE_INNER) or \
+ (flags & interfaces.nsIEmbeddingSiteWindow.DIM_FLAGS_SIZE_OUTER)):
+ return base_window.getPositionAndSize()
+ elif flags & interfaces.nsIEmbeddingSiteWindow.DIM_FLAGS_POSITION:
+ x, y = base_window.getPosition()
+ return (x, y, 0, 0)
+ elif (flags & interfaces.nsIEmbeddingSiteWindow.DIM_FLAGS_SIZE_INNER) or \
+ (flags & interfaces.nsIEmbeddingSiteWindow.DIM_FLAGS_SIZE_OUTER):
+ width, height = base_window.getSize()
+ return (0, 0, width, height)
+ else:
+ raise xpcom.Exception('Invalid flags: %r' % flags)
+
+ def setDimensions(self, flags, x, y, cx, cy):
+ logging.debug("nsIEmbeddingSiteWindow.setDimensions: %r" % flags)
+
+ def setFocus(self):
+ logging.debug("nsIEmbeddingSiteWindow.setFocus")
+ base_window = self.web_view.browser.queryInterface(interfaces.nsIBaseWindow)
+ base_window.setFocus()
+
+ def get_title(self):
+ logging.debug("nsIEmbeddingSiteWindow.get_title: %r" % self.title)
+ return self.title
+
+ def set_title(self, title):
+ logging.debug("nsIEmbeddingSiteWindow.set_title: %r" % title)
+ self.title = title
+ self.web_view._notify_title_changed()
+
+ def get_webBrowser(self):
+ return self.web_view.browser
+
+ def get_chromeFlags(self):
+ return self._chrome_flags
+
+ def set_chromeFlags(self, flags):
+ self._chrome_flags = flags
+
+ def get_visibility(self):
+ logging.debug("nsIEmbeddingSiteWindow.get_visibility: %r" % self._visible)
+ # See bug https://bugzilla.mozilla.org/show_bug.cgi?id=312998
+ # Work around the problem that sometimes the window is already visible
+ # even though mVisibility isn't true yet.
+ visibility = self.web_view.props.visibility
+ mapped = self.web_view.flags() & gtk.MAPPED
+ return visibility or (not self.web_view.is_chrome and mapped)
+
+ def set_visibility(self, visibility):
+ logging.debug("nsIEmbeddingSiteWindow.set_visibility: %r" % visibility)
+ if visibility == self.web_view.props.visibility:
+ return
+ self.web_view.props.visibility = visibility
+
+ # nsIWebProgressListener
+ def onStateChange(self, web_progress, request, state_flags, status):
+ if (state_flags & interfaces.nsIWebProgressListener.STATE_STOP) and \
+ (state_flags & interfaces.nsIWebProgressListener.STATE_IS_NETWORK):
+ if self.web_view.is_chrome:
+ self.web_view.dom_window.sizeToContent()
+
+ def onStatusChange(self, web_progress, request, status, message): pass
+ def onSecurityChange(self, web_progress, request, state): pass
+ def onProgressChange(self, web_progress, request, cur_self_progress, max_self_progress, cur_total_progress, max_total_progress): pass
+ def onLocationChange(self, web_progress, request, location): pass
+
+ # nsIInterfaceRequestor
+ def queryInterface(self, uuid):
+ if uuid == interfaces.nsIDOMWindow:
+ return self.web_view.dom_window
+
+ if not uuid in self._com_interfaces_:
+ # Components.returnCode = Cr.NS_ERROR_NO_INTERFACE;
+ logging.warning('Interface %s not implemented by this instance: %r' % (uuid, self))
+ return None
+
+ return xpcom.server.WrapObject(self, uuid)
+
+ def getInterface(self, uuid):
+ result = self.queryInterface(uuid)
+
+ if not result:
+ # delegate to the nsIWebBrowser
+ requestor = self.web_view.browser.queryInterface(interfaces.nsIInterfaceRequestor)
+ try:
+ result = requestor.getInterface(uuid)
+ except xpcom.Exception:
+ logging.warning('Interface %s not implemented by this instance: %r' % (uuid, self.web_view.browser))
+ result = None
+
+ return result
+
+class WebView(_hulahop.WebView):
+
+ TYPE_WINDOW = 0
+ TYPE_POPUP = 1
+
+ __gproperties__ = {
+ 'title' : (str, None, None, None,
+ gobject.PARAM_READABLE),
+ 'status' : (str, None, None, None,
+ gobject.PARAM_READABLE),
+ 'visibility' : (bool, None, None, False,
+ gobject.PARAM_READWRITE)
+ }
+
+ def __init__(self):
+ _hulahop.WebView.__init__(self)
+
+ self.type = WebView.TYPE_WINDOW
+ self.is_chrome = False
+
+ chrome = _Chrome(self)
+
+ self._chrome = xpcom.server.WrapObject(chrome, interfaces.nsIEmbeddingSiteWindow)
+ weak_ref = xpcom.client.WeakReference(self._chrome)
+ self.browser.containerWindow = self._chrome
+
+ listener = xpcom.server.WrapObject(chrome, interfaces.nsIWebProgressListener)
+ weak_ref2 = xpcom.client.WeakReference(listener)
+ # FIXME: weak_ref2._comobj_ looks quite a bit ugly.
+ self.browser.addWebBrowserListener(weak_ref2._comobj_,
+ interfaces.nsIWebProgressListener)
+
+ self._status = ''
+ self._first_uri = None
+ self._visibility = False
+
+ def do_setup(self):
+ _hulahop.WebView.do_setup(self)
+
+ if self._first_uri:
+ self.load_uri(self._first_uri)
+
+ def _notify_title_changed(self):
+ self.notify('title')
+
+ def _set_status(self, status):
+ self._status = status
+ self.notify('status')
+
+ def do_get_property(self, pspec):
+ if pspec.name == 'title':
+ return self._chrome.title
+ elif pspec.name == 'status':
+ return self._status
+ elif pspec.name == 'visibility':
+ return self._visibility
+
+ def do_set_property(self, pspec, value):
+ if pspec.name == 'visibility':
+ self._visibility = value
+
+ def get_window_root(self):
+ return _hulahop.WebView.get_window_root(self)
+
+ def get_browser(self):
+ return _hulahop.WebView.get_browser(self)
+
+ def get_doc_shell(self):
+ requestor = self.browser.queryInterface(interfaces.nsIInterfaceRequestor)
+ return requestor.getInterface(interfaces.nsIDocShell)
+
+ def get_web_progress(self):
+ return self.doc_shell.queryInterface(interfaces.nsIWebProgress)
+
+ def get_web_navigation(self):
+ return self.browser.queryInterface(interfaces.nsIWebNavigation)
+
+ def get_dom_window(self):
+ return self.browser.contentDOMWindow
+
+ def load_uri(self, uri):
+ try:
+ self.web_navigation.loadURI(
+ uri, interfaces.nsIWebNavigation.LOAD_FLAGS_NONE,
+ None, None, None)
+ except xpcom.Exception:
+ self._first_uri = uri
+
+ dom_window = property(get_dom_window)
+ browser = property(get_browser)
+ window_root = property(get_window_root)
+ doc_shell = property(get_doc_shell)
+ web_progress = property(get_web_progress)
+ web_navigation = property(get_web_navigation)
+
diff --git a/zope/__init__.py b/zope/__init__.py
new file mode 100644
index 0000000..2e2033b
--- /dev/null
+++ b/zope/__init__.py
@@ -0,0 +1,7 @@
+# this is a namespace package
+try:
+ import pkg_resources
+ pkg_resources.declare_namespace(__name__)
+except ImportError:
+ import pkgutil
+ __path__ = pkgutil.extend_path(__path__, __name__)
diff --git a/zope/interface/__init__.py b/zope/interface/__init__.py
new file mode 100644
index 0000000..f45079b
--- /dev/null
+++ b/zope/interface/__init__.py
@@ -0,0 +1,80 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Interfaces
+
+This package implements the Python "scarecrow" proposal.
+
+The package exports two objects, `Interface` and `Attribute` directly. It also
+exports several helper methods. Interface is used to create an interface with
+a class statement, as in:
+
+ class IMyInterface(Interface):
+ '''Interface documentation
+ '''
+
+ def meth(arg1, arg2):
+ '''Documentation for meth
+ '''
+
+ # Note that there is no self argument
+
+To find out what you can do with interfaces, see the interface
+interface, `IInterface` in the `interfaces` module.
+
+The package has several public modules:
+
+ o `declarations` provides utilities to declare interfaces on objects. It
+ also provides a wide range of helpful utilities that aid in managing
+ declared interfaces. Most of its public names are however imported here.
+
+ o `document` has a utility for documenting an interface as structured text.
+
+ o `exceptions` has the interface-defined exceptions
+
+ o `interfaces` contains a list of all public interfaces for this package.
+
+ o `verify` has utilities for verifying implementations of interfaces.
+
+See the module doc strings for more information.
+
+$Id: __init__.py 67630 2006-04-27 00:54:03Z jim $
+"""
+__docformat__ = 'restructuredtext'
+
+from zope.interface.interface import Interface, _wire
+
+# Need to actually get the interface elements to implement the right interfaces
+_wire()
+del _wire
+
+from zope.interface.interface import Attribute, invariant
+
+from zope.interface.declarations import providedBy, implementedBy
+from zope.interface.declarations import classImplements, classImplementsOnly
+from zope.interface.declarations import directlyProvidedBy, directlyProvides
+from zope.interface.declarations import alsoProvides, implementer
+from zope.interface.declarations import implements, implementsOnly
+from zope.interface.declarations import classProvides, moduleProvides
+from zope.interface.declarations import noLongerProvides, Declaration
+from zope.interface.exceptions import Invalid
+
+# The following are to make spec pickles cleaner
+from zope.interface.declarations import Provides
+
+
+from zope.interface.interfaces import IInterfaceDeclaration
+
+moduleProvides(IInterfaceDeclaration)
+
+__all__ = ('Interface', 'Attribute') + tuple(IInterfaceDeclaration)
diff --git a/zope/interface/_flatten.py b/zope/interface/_flatten.py
new file mode 100644
index 0000000..f0df3a3
--- /dev/null
+++ b/zope/interface/_flatten.py
@@ -0,0 +1,37 @@
+##############################################################################
+#
+# Copyright (c) 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Adapter-style interface registry
+
+See Adapter class.
+
+$Id: _flatten.py 26551 2004-07-15 07:06:37Z srichter $
+"""
+from zope.interface import Declaration
+
+def _flatten(implements, include_None=0):
+
+ try:
+ r = implements.flattened()
+ except AttributeError:
+ if implements is None:
+ r=()
+ else:
+ r = Declaration(implements).flattened()
+
+ if not include_None:
+ return r
+
+ r = list(r)
+ r.append(None)
+ return r
diff --git a/zope/interface/adapter.py b/zope/interface/adapter.py
new file mode 100644
index 0000000..0cb8949
--- /dev/null
+++ b/zope/interface/adapter.py
@@ -0,0 +1,644 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Adapter management
+
+$Id: adapter.py 67796 2006-05-01 13:55:44Z jim $
+"""
+
+import weakref
+from zope.interface import providedBy, Interface, ro
+
+_marker = object
+class BaseAdapterRegistry(object):
+
+ # List of methods copied from lookup sub-objects:
+ _delegated = ('lookup', 'queryMultiAdapter', 'lookup1', 'queryAdapter',
+ 'adapter_hook', 'lookupAll', 'names',
+ 'subscriptions', 'subscribers')
+
+ # All registries maintain a generation that can be used by verifying
+ # registries
+ _generation = 0
+
+ def __init__(self, bases=()):
+
+ # {order -> {required -> {provided -> {name -> value}}}}
+ # where "interfaces" is really a nested key. So, for example:
+ # for order == 0, we have:
+ # {provided -> {name -> valie}}
+ # but for order == 2, we have:
+ # {r1 -> {r2 -> {provided -> {name -> valie}}}}
+ self._adapters = []
+
+ # {order -> {required -> {provided -> {name -> [value]}}}}
+ # where the remarks about adapters above apply
+ self._subscribers = []
+
+ # Set, with a reference count, keeping track of the interfaces
+ # for which we have provided components:
+ self._provided = {}
+
+ # Looup object to perform lookup. We make this a separate object to
+ # to make it easier, in the furture, to implement just the lookup
+ # functionality in C.
+ self._createLookup()
+
+ # Cache invalidation data. There are really 2 kinds of registries:
+
+ # Invalidating registries have caches that are invalidated
+ # when they or when base registies change. An invalidating
+ # registry can only have invalidating registries as bases.
+
+ # Verifying registies can't rely on getting invalidation message,
+ # so have to check the generations of base registries to determine
+ # if their cache data are current
+
+ # Base registries:
+ self.__bases__ = bases
+
+ def _setBases(self, bases):
+ self.__dict__['__bases__'] = bases
+ self.ro = ro.ro(self)
+ self.changed(self)
+
+ __bases__ = property(lambda self: self.__dict__['__bases__'],
+ lambda self, bases: self._setBases(bases),
+ )
+
+ def _createLookup(self):
+ self._v_lookup = self.LookupClass(self)
+ for name in self._delegated:
+ self.__dict__[name] = getattr(self._v_lookup, name)
+
+ def changed(self, originally_changed):
+ self._generation += 1
+ self._v_lookup.changed(originally_changed)
+
+ def register(self, required, provided, name, value):
+ if value is None:
+ self.unregister(required, provided, name, value)
+ return
+
+ required = tuple(map(_convert_None_to_Interface, required))
+ name = _normalize_name(name)
+ order = len(required)
+ byorder = self._adapters
+ while len(byorder) <= order:
+ byorder.append({})
+ components = byorder[order]
+ key = required + (provided,)
+
+ for k in key:
+ d = components.get(k)
+ if d is None:
+ d = {}
+ components[k] = d
+ components = d
+
+ if components.get(name) == value:
+ return
+
+ components[name] = value
+
+ n = self._provided.get(provided, 0) + 1
+ self._provided[provided] = n
+ if n == 1:
+ self._v_lookup.add_extendor(provided)
+
+ self.changed(self)
+
+ def registered(self, required, provided, name=u''):
+ required = tuple(map(_convert_None_to_Interface, required))
+ name = _normalize_name(name)
+ order = len(required)
+ byorder = self._adapters
+ if len(byorder) <= order:
+ return None
+
+ components = byorder[order]
+ key = required + (provided,)
+
+ for k in key:
+ d = components.get(k)
+ if d is None:
+ return None
+ components = d
+
+ return components.get(name)
+
+ def unregister(self, required, provided, name, value=None):
+ required = tuple(map(_convert_None_to_Interface, required))
+ order = len(required)
+ byorder = self._adapters
+ if order >= len(byorder):
+ return False
+ components = byorder[order]
+ key = required + (provided,)
+
+ for k in key:
+ d = components.get(k)
+ if d is None:
+ return
+ components = d
+
+ old = components.get(name)
+ if old is None:
+ return
+ if (value is not None) and (old != value):
+ return
+
+ del components[name]
+ n = self._provided[provided] - 1
+ if n == 0:
+ del self._provided[provided]
+ self._v_lookup.remove_extendor(provided)
+ else:
+ self._provided[provided] = n
+
+ self.changed(self)
+
+ return
+
+
+ def subscribe(self, required, provided, value):
+ required = tuple(map(_convert_None_to_Interface, required))
+ name = u''
+ order = len(required)
+ byorder = self._subscribers
+ while len(byorder) <= order:
+ byorder.append({})
+ components = byorder[order]
+ key = required + (provided,)
+
+ for k in key:
+ d = components.get(k)
+ if d is None:
+ d = {}
+ components[k] = d
+ components = d
+
+ components[name] = components.get(name, ()) + (value, )
+
+ if provided is not None:
+ n = self._provided.get(provided, 0) + 1
+ self._provided[provided] = n
+ if n == 1:
+ self._v_lookup.add_extendor(provided)
+
+ self.changed(self)
+
+ def unsubscribe(self, required, provided, value=None):
+ required = tuple(map(_convert_None_to_Interface, required))
+ order = len(required)
+ byorder = self._subscribers
+ if order >= len(byorder):
+ return
+ components = byorder[order]
+ key = required + (provided,)
+
+ for k in key:
+ d = components.get(k)
+ if d is None:
+ return
+ components = d
+
+ old = components.get(u'')
+ if not old:
+ return
+
+ if value is None:
+ new = ()
+ else:
+ new = tuple([v for v in old if v != value])
+
+ if new == old:
+ return
+
+ components[u''] = new
+
+ if provided is not None:
+ n = self._provided[provided] + len(new) - len(old)
+ if n == 0:
+ del self._provided[provided]
+ self._v_lookup.remove_extendor(provided)
+
+ self.changed(self)
+
+ # XXX hack to fake out twisted's use of a private api. We need to get them
+ # to use the new registed method.
+ def get(self, _):
+ class XXXTwistedFakeOut:
+ selfImplied = {}
+ return XXXTwistedFakeOut
+
+
+_not_in_mapping = object()
+class LookupBasePy(object):
+
+ def __init__(self):
+ self._cache = {}
+ self._mcache = {}
+ self._scache = {}
+
+ def changed(self, ignored=None):
+ self._cache.clear()
+ self._mcache.clear()
+ self._scache.clear()
+
+ def _getcache(self, provided, name):
+ cache = self._cache.get(provided)
+ if cache is None:
+ cache = {}
+ self._cache[provided] = cache
+ if name:
+ c = cache.get(name)
+ if c is None:
+ c = {}
+ cache[name] = c
+ cache = c
+ return cache
+
+ def lookup(self, required, provided, name=u'', default=None):
+ cache = self._getcache(provided, name)
+ if len(required) == 1:
+ result = cache.get(required[0], _not_in_mapping)
+ else:
+ result = cache.get(tuple(required), _not_in_mapping)
+
+ if result is _not_in_mapping:
+ result = self._uncached_lookup(required, provided, name)
+ if len(required) == 1:
+ cache[required[0]] = result
+ else:
+ cache[tuple(required)] = result
+
+ if result is None:
+ return default
+
+ return result
+
+ def lookup1(self, required, provided, name=u'', default=None):
+ cache = self._getcache(provided, name)
+ result = cache.get(required, _not_in_mapping)
+ if result is _not_in_mapping:
+ return self.lookup((required, ), provided, name, default)
+
+ if result is None:
+ return default
+
+ return result
+
+ def queryAdapter(self, object, provided, name=u'', default=None):
+ return self.adapter_hook(provided, object, name, default)
+
+ def adapter_hook(self, provided, object, name=u'', default=None):
+ required = providedBy(object)
+ cache = self._getcache(provided, name)
+ factory = cache.get(required, _not_in_mapping)
+ if factory is _not_in_mapping:
+ factory = self.lookup((required, ), provided, name)
+
+ if factory is not None:
+ result = factory(object)
+ if result is not None:
+ return result
+
+ return default
+
+ def lookupAll(self, required, provided):
+ cache = self._mcache.get(provided)
+ if cache is None:
+ cache = {}
+ self._mcache[provided] = cache
+
+ required = tuple(required)
+ result = cache.get(required, _not_in_mapping)
+ if result is _not_in_mapping:
+ result = self._uncached_lookupAll(required, provided)
+ cache[required] = result
+
+ return result
+
+
+ def subscriptions(self, required, provided):
+ cache = self._scache.get(provided)
+ if cache is None:
+ cache = {}
+ self._scache[provided] = cache
+
+ required = tuple(required)
+ result = cache.get(required, _not_in_mapping)
+ if result is _not_in_mapping:
+ result = self._uncached_subscriptions(required, provided)
+ cache[required] = result
+
+ return result
+
+LookupBase = LookupBasePy
+
+class VerifyingBasePy(LookupBasePy):
+
+ def changed(self, originally_changed):
+ LookupBasePy.changed(self, originally_changed)
+ self._verify_ro = self._registry.ro[1:]
+ self._verify_generations = [r._generation for r in self._verify_ro]
+
+ def _verify(self):
+ if ([r._generation for r in self._verify_ro]
+ != self._verify_generations):
+ self.changed(None)
+
+ def _getcache(self, provided, name):
+ self._verify()
+ return LookupBasePy._getcache(self, provided, name)
+
+ def lookupAll(self, required, provided):
+ self._verify()
+ return LookupBasePy.lookupAll(self, required, provided)
+
+ def subscriptions(self, required, provided):
+ self._verify()
+ return LookupBasePy.subscriptions(self, required, provided)
+
+VerifyingBase = VerifyingBasePy
+
+
+try:
+ import _zope_interface_coptimizations
+except ImportError:
+ pass
+else:
+ from _zope_interface_coptimizations import LookupBase, VerifyingBase
+
+class AdapterLookupBase(object):
+
+ def __init__(self, registry):
+ self._registry = registry
+ self._required = {}
+ self.init_extendors()
+ super(AdapterLookupBase, self).__init__()
+
+ def changed(self, ignored=None):
+ super(AdapterLookupBase, self).changed(None)
+ for r in self._required.keys():
+ r = r()
+ if r is not None:
+ r.unsubscribe(self)
+ self._required.clear()
+
+
+ # Extendors
+ # ---------
+
+ # When given an target interface for an adapter lookup, we need to consider
+ # adapters for interfaces that extend the target interface. This is
+ # what the extendors dictionary is about. It tells us all of the
+ # interfaces that extend an interface for which there are adapters
+ # registered.
+
+ # We could separate this by order and name, thus reducing the
+ # number of provided interfaces to search at run time. The tradeoff,
+ # however, is that we have to store more information. For example,
+ # is the same interface is provided for multiple names and if the
+ # interface extends many interfaces, we'll have to keep track of
+ # a fair bit of information for each name. It's better to
+ # be space efficient here and be time efficient in the cache
+ # implementation.
+
+ # TODO: add invalidation when a provided interface changes, in case
+ # the interface's __iro__ has changed. This is unlikely enough that
+ # we'll take our chances for now.
+
+ def init_extendors(self):
+ self._extendors = {}
+ for p in self._registry._provided:
+ self.add_extendor(p)
+
+ def add_extendor(self, provided):
+ _extendors = self._extendors
+ for i in provided.__iro__:
+ extendors = _extendors.get(i, ())
+ _extendors[i] = (
+ [e for e in extendors if provided.isOrExtends(e)]
+ +
+ [provided]
+ +
+ [e for e in extendors if not provided.isOrExtends(e)]
+ )
+
+ def remove_extendor(self, provided):
+ _extendors = self._extendors
+ for i in provided.__iro__:
+ _extendors[i] = [e for e in _extendors.get(i, ())
+ if e != provided]
+
+
+ def _subscribe(self, *required):
+ _refs = self._required
+ for r in required:
+ ref = r.weakref()
+ if ref not in _refs:
+ r.subscribe(self)
+ _refs[ref] = 1
+
+ def _uncached_lookup(self, required, provided, name=u''):
+ result = None
+ order = len(required)
+ for registry in self._registry.ro:
+ byorder = registry._adapters
+ if order >= len(byorder):
+ continue
+
+ extendors = registry._v_lookup._extendors.get(provided)
+ if not extendors:
+ continue
+
+ components = byorder[order]
+ result = _lookup(components, required, extendors, name, 0,
+ order)
+ if result is not None:
+ break
+
+ self._subscribe(*required)
+
+ return result
+
+ def queryMultiAdapter(self, objects, provided, name=u'', default=None):
+ factory = self.lookup(map(providedBy, objects), provided, name)
+ if factory is None:
+ return default
+
+ result = factory(*objects)
+ if result is None:
+ return default
+
+ return result
+
+ def _uncached_lookupAll(self, required, provided):
+ order = len(required)
+ result = {}
+ for registry in reversed(self._registry.ro):
+ byorder = registry._adapters
+ if order >= len(byorder):
+ continue
+ extendors = registry._v_lookup._extendors.get(provided)
+ if not extendors:
+ continue
+ components = byorder[order]
+ _lookupAll(components, required, extendors, result, 0, order)
+
+ self._subscribe(*required)
+
+ return tuple(result.iteritems())
+
+ def names(self, required, provided):
+ return [c[0] for c in self.lookupAll(required, provided)]
+
+ def _uncached_subscriptions(self, required, provided):
+ order = len(required)
+ result = []
+ for registry in reversed(self._registry.ro):
+ byorder = registry._subscribers
+ if order >= len(byorder):
+ continue
+
+ if provided is None:
+ extendors = (provided, )
+ else:
+ extendors = registry._v_lookup._extendors.get(provided)
+ if extendors is None:
+ continue
+
+ _subscriptions(byorder[order], required, extendors, u'',
+ result, 0, order)
+
+ self._subscribe(*required)
+
+ return result
+
+ def subscribers(self, objects, provided):
+ subscriptions = self.subscriptions(map(providedBy, objects), provided)
+ if provided is None:
+ result = ()
+ for subscription in subscriptions:
+ subscription(*objects)
+ else:
+ result = []
+ for subscription in subscriptions:
+ subscriber = subscription(*objects)
+ if subscriber is not None:
+ result.append(subscriber)
+ return result
+
+class AdapterLookup(AdapterLookupBase, LookupBase):
+ pass
+
+class AdapterRegistry(BaseAdapterRegistry):
+
+ LookupClass = AdapterLookup
+
+ def __init__(self, bases=()):
+ # AdapterRegisties are invalidating registries, so
+ # we need to keep track of out invalidating subregistries.
+ self._v_subregistries = weakref.WeakKeyDictionary()
+
+ super(AdapterRegistry, self).__init__(bases)
+
+ def _addSubregistry(self, r):
+ self._v_subregistries[r] = 1
+
+ def _removeSubregistry(self, r):
+ if r in self._v_subregistries:
+ del self._v_subregistries[r]
+
+ def _setBases(self, bases):
+ old = self.__dict__.get('__bases__', ())
+ for r in old:
+ if r not in bases:
+ r._removeSubregistry(self)
+ for r in bases:
+ if r not in old:
+ r._addSubregistry(self)
+
+ super(AdapterRegistry, self)._setBases(bases)
+
+ def changed(self, originally_changed):
+ super(AdapterRegistry, self).changed(originally_changed)
+
+ for sub in self._v_subregistries.keys():
+ sub.changed(originally_changed)
+
+
+class VerifyingAdapterLookup(AdapterLookupBase, VerifyingBase):
+ pass
+
+class VerifyingAdapterRegistry(BaseAdapterRegistry):
+
+ LookupClass = VerifyingAdapterLookup
+
+def _convert_None_to_Interface(x):
+ if x is None:
+ return Interface
+ else:
+ return x
+
+def _normalize_name(name):
+ if isinstance(name, basestring):
+ return unicode(name)
+
+ raise TypeError("name must be a regular or unicode string")
+
+def _lookup(components, specs, provided, name, i, l):
+ if i < l:
+ for spec in specs[i].__sro__:
+ comps = components.get(spec)
+ if comps:
+ r = _lookup(comps, specs, provided, name, i+1, l)
+ if r is not None:
+ return r
+ else:
+ for iface in provided:
+ comps = components.get(iface)
+ if comps:
+ r = comps.get(name)
+ if r is not None:
+ return r
+
+ return None
+
+def _lookupAll(components, specs, provided, result, i, l):
+ if i < l:
+ for spec in reversed(specs[i].__sro__):
+ comps = components.get(spec)
+ if comps:
+ _lookupAll(comps, specs, provided, result, i+1, l)
+ else:
+ for iface in reversed(provided):
+ comps = components.get(iface)
+ if comps:
+ result.update(comps)
+
+def _subscriptions(components, specs, provided, name, result, i, l):
+ if i < l:
+ for spec in reversed(specs[i].__sro__):
+ comps = components.get(spec)
+ if comps:
+ _subscriptions(comps, specs, provided, name, result, i+1, l)
+ else:
+ for iface in reversed(provided):
+ comps = components.get(iface)
+ if comps:
+ comps = comps.get(name)
+ if comps:
+ result.extend(comps)
diff --git a/zope/interface/advice.py b/zope/interface/advice.py
new file mode 100644
index 0000000..2d9e038
--- /dev/null
+++ b/zope/interface/advice.py
@@ -0,0 +1,192 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Class advice.
+
+This module was adapted from 'protocols.advice', part of the Python
+Enterprise Application Kit (PEAK). Please notify the PEAK authors
+(pje@telecommunity.com and tsarna@sarna.org) if bugs are found or
+Zope-specific changes are required, so that the PEAK version of this module
+can be kept in sync.
+
+PEAK is a Python application framework that interoperates with (but does
+not require) Zope 3 and Twisted. It provides tools for manipulating UML
+models, object-relational persistence, aspect-oriented programming, and more.
+Visit the PEAK home page at http://peak.telecommunity.com for more information.
+
+$Id: advice.py 25177 2004-06-02 13:17:31Z jim $
+"""
+
+from types import ClassType, FunctionType
+import sys
+
+def getFrameInfo(frame):
+ """Return (kind,module,locals,globals) for a frame
+
+ 'kind' is one of "exec", "module", "class", "function call", or "unknown".
+ """
+
+ f_locals = frame.f_locals
+ f_globals = frame.f_globals
+
+ sameNamespace = f_locals is f_globals
+ hasModule = '__module__' in f_locals
+ hasName = '__name__' in f_globals
+
+ sameName = hasModule and hasName
+ sameName = sameName and f_globals['__name__']==f_locals['__module__']
+
+ module = hasName and sys.modules.get(f_globals['__name__']) or None
+
+ namespaceIsModule = module and module.__dict__ is f_globals
+
+ if not namespaceIsModule:
+ # some kind of funky exec
+ kind = "exec"
+ elif sameNamespace and not hasModule:
+ kind = "module"
+ elif sameName and not sameNamespace:
+ kind = "class"
+ elif not sameNamespace:
+ kind = "function call"
+ else:
+ # How can you have f_locals is f_globals, and have '__module__' set?
+ # This is probably module-level code, but with a '__module__' variable.
+ kind = "unknown"
+ return kind, module, f_locals, f_globals
+
+
+def addClassAdvisor(callback, depth=2):
+ """Set up 'callback' to be passed the containing class upon creation
+
+ This function is designed to be called by an "advising" function executed
+ in a class suite. The "advising" function supplies a callback that it
+ wishes to have executed when the containing class is created. The
+ callback will be given one argument: the newly created containing class.
+ The return value of the callback will be used in place of the class, so
+ the callback should return the input if it does not wish to replace the
+ class.
+
+ The optional 'depth' argument to this function determines the number of
+ frames between this function and the targeted class suite. 'depth'
+ defaults to 2, since this skips this function's frame and one calling
+ function frame. If you use this function from a function called directly
+ in the class suite, the default will be correct, otherwise you will need
+ to determine the correct depth yourself.
+
+ This function works by installing a special class factory function in
+ place of the '__metaclass__' of the containing class. Therefore, only
+ callbacks *after* the last '__metaclass__' assignment in the containing
+ class will be executed. Be sure that classes using "advising" functions
+ declare any '__metaclass__' *first*, to ensure all callbacks are run."""
+
+ frame = sys._getframe(depth)
+ kind, module, caller_locals, caller_globals = getFrameInfo(frame)
+
+ # This causes a problem when zope interfaces are used from doctest.
+ # In these cases, kind == "exec".
+ #
+ #if kind != "class":
+ # raise SyntaxError(
+ # "Advice must be in the body of a class statement"
+ # )
+
+ previousMetaclass = caller_locals.get('__metaclass__')
+ defaultMetaclass = caller_globals.get('__metaclass__', ClassType)
+
+
+ def advise(name, bases, cdict):
+
+ if '__metaclass__' in cdict:
+ del cdict['__metaclass__']
+
+ if previousMetaclass is None:
+ if bases:
+ # find best metaclass or use global __metaclass__ if no bases
+ meta = determineMetaclass(bases)
+ else:
+ meta = defaultMetaclass
+
+ elif isClassAdvisor(previousMetaclass):
+ # special case: we can't compute the "true" metaclass here,
+ # so we need to invoke the previous metaclass and let it
+ # figure it out for us (and apply its own advice in the process)
+ meta = previousMetaclass
+
+ else:
+ meta = determineMetaclass(bases, previousMetaclass)
+
+ newClass = meta(name,bases,cdict)
+
+ # this lets the callback replace the class completely, if it wants to
+ return callback(newClass)
+
+ # introspection data only, not used by inner function
+ advise.previousMetaclass = previousMetaclass
+ advise.callback = callback
+
+ # install the advisor
+ caller_locals['__metaclass__'] = advise
+
+
+def isClassAdvisor(ob):
+ """True if 'ob' is a class advisor function"""
+ return isinstance(ob,FunctionType) and hasattr(ob,'previousMetaclass')
+
+
+def determineMetaclass(bases, explicit_mc=None):
+ """Determine metaclass from 1+ bases and optional explicit __metaclass__"""
+
+ meta = [getattr(b,'__class__',type(b)) for b in bases]
+
+ if explicit_mc is not None:
+ # The explicit metaclass needs to be verified for compatibility
+ # as well, and allowed to resolve the incompatible bases, if any
+ meta.append(explicit_mc)
+
+ if len(meta)==1:
+ # easy case
+ return meta[0]
+
+ candidates = minimalBases(meta) # minimal set of metaclasses
+
+ if not candidates:
+ # they're all "classic" classes
+ return ClassType
+
+ elif len(candidates)>1:
+ # We could auto-combine, but for now we won't...
+ raise TypeError("Incompatible metatypes",bases)
+
+ # Just one, return it
+ return candidates[0]
+
+
+def minimalBases(classes):
+ """Reduce a list of base classes to its ordered minimum equivalent"""
+
+ classes = [c for c in classes if c is not ClassType]
+ candidates = []
+
+ for m in classes:
+ for n in classes:
+ if issubclass(n,m) and m is not n:
+ break
+ else:
+ # m has no subclasses in 'classes'
+ if m in candidates:
+ candidates.remove(m) # ensure that we're later in the list
+ candidates.append(m)
+
+ return candidates
+
diff --git a/zope/interface/common/__init__.py b/zope/interface/common/__init__.py
new file mode 100644
index 0000000..b711d36
--- /dev/null
+++ b/zope/interface/common/__init__.py
@@ -0,0 +1,2 @@
+#
+# This file is necessary to make this directory a package.
diff --git a/zope/interface/common/idatetime.py b/zope/interface/common/idatetime.py
new file mode 100644
index 0000000..c77ea15
--- /dev/null
+++ b/zope/interface/common/idatetime.py
@@ -0,0 +1,577 @@
+##############################################################################
+# Copyright (c) 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+##############################################################################
+"""Datetime interfaces.
+
+This module is called idatetime because if it were called datetime the import
+of the real datetime would fail.
+
+$Id: idatetime.py 25177 2004-06-02 13:17:31Z jim $
+"""
+
+from zope.interface import Interface, Attribute
+from zope.interface import classImplements, directlyProvides
+
+from datetime import timedelta, date, datetime, time, tzinfo
+
+
+class ITimeDeltaClass(Interface):
+ """This is the timedelta class interface."""
+
+ min = Attribute("The most negative timedelta object")
+
+ max = Attribute("The most positive timedelta object")
+
+ resolution = Attribute(
+ "The smallest difference between non-equal timedelta objects")
+
+
+class ITimeDelta(ITimeDeltaClass):
+ """Represent the difference between two datetime objects.
+
+ Supported operators:
+
+ - add, subtract timedelta
+ - unary plus, minus, abs
+ - compare to timedelta
+ - multiply, divide by int/long
+
+ In addition, datetime supports subtraction of two datetime objects
+ returning a timedelta, and addition or subtraction of a datetime
+ and a timedelta giving a datetime.
+
+ Representation: (days, seconds, microseconds).
+ """
+
+ days = Attribute("Days between -999999999 and 999999999 inclusive")
+
+ seconds = Attribute("Seconds between 0 and 86399 inclusive")
+
+ microseconds = Attribute("Microseconds between 0 and 999999 inclusive")
+
+
+class IDateClass(Interface):
+ """This is the date class interface."""
+
+ min = Attribute("The earliest representable date")
+
+ max = Attribute("The latest representable date")
+
+ resolution = Attribute(
+ "The smallest difference between non-equal date objects")
+
+ def today():
+ """Return the current local time.
+
+ This is equivalent to date.fromtimestamp(time.time())"""
+
+ def fromtimestamp(timestamp):
+ """Return the local date from a POSIX timestamp (like time.time())
+
+ This may raise ValueError, if the timestamp is out of the range of
+ values supported by the platform C localtime() function. It's common
+ for this to be restricted to years from 1970 through 2038. Note that
+ on non-POSIX systems that include leap seconds in their notion of a
+ timestamp, leap seconds are ignored by fromtimestamp().
+ """
+
+ def fromordinal(ordinal):
+ """Return the date corresponding to the proleptic Gregorian ordinal.
+
+ January 1 of year 1 has ordinal 1. ValueError is raised unless
+ 1 <= ordinal <= date.max.toordinal().
+ For any date d, date.fromordinal(d.toordinal()) == d.
+ """
+
+
+class IDate(IDateClass):
+ """Represents a date (year, month and day) in an idealized calendar.
+
+ Operators:
+
+ __repr__, __str__
+ __cmp__, __hash__
+ __add__, __radd__, __sub__ (add/radd only with timedelta arg)
+ """
+
+ year = Attribute("Between MINYEAR and MAXYEAR inclusive.")
+
+ month = Attribute("Between 1 and 12 inclusive")
+
+ day = Attribute(
+ "Between 1 and the number of days in the given month of the given year.")
+
+ def replace(year, month, day):
+ """Return a date with the same value.
+
+ Except for those members given new values by whichever keyword
+ arguments are specified. For example, if d == date(2002, 12, 31), then
+ d.replace(day=26) == date(2000, 12, 26).
+ """
+
+ def timetuple():
+ """Return a 9-element tuple of the form returned by time.localtime().
+
+ The hours, minutes and seconds are 0, and the DST flag is -1.
+ d.timetuple() is equivalent to
+ (d.year, d.month, d.day, 0, 0, 0, d.weekday(), d.toordinal() -
+ date(d.year, 1, 1).toordinal() + 1, -1)
+ """
+
+ def toordinal():
+ """Return the proleptic Gregorian ordinal of the date
+
+ January 1 of year 1 has ordinal 1. For any date object d,
+ date.fromordinal(d.toordinal()) == d.
+ """
+
+ def weekday():
+ """Return the day of the week as an integer.
+
+ Monday is 0 and Sunday is 6. For example,
+ date(2002, 12, 4).weekday() == 2, a Wednesday.
+
+ See also isoweekday().
+ """
+
+ def isoweekday():
+ """Return the day of the week as an integer.
+
+ Monday is 1 and Sunday is 7. For example,
+ date(2002, 12, 4).isoweekday() == 3, a Wednesday.
+
+ See also weekday(), isocalendar().
+ """
+
+ def isocalendar():
+ """Return a 3-tuple, (ISO year, ISO week number, ISO weekday).
+
+ The ISO calendar is a widely used variant of the Gregorian calendar.
+ See http://www.phys.uu.nl/~vgent/calendar/isocalendar.htm for a good
+ explanation.
+
+ The ISO year consists of 52 or 53 full weeks, and where a week starts
+ on a Monday and ends on a Sunday. The first week of an ISO year is the
+ first (Gregorian) calendar week of a year containing a Thursday. This
+ is called week number 1, and the ISO year of that Thursday is the same
+ as its Gregorian year.
+
+ For example, 2004 begins on a Thursday, so the first week of ISO year
+ 2004 begins on Monday, 29 Dec 2003 and ends on Sunday, 4 Jan 2004, so
+ that date(2003, 12, 29).isocalendar() == (2004, 1, 1) and
+ date(2004, 1, 4).isocalendar() == (2004, 1, 7).
+ """
+
+ def isoformat():
+ """Return a string representing the date in ISO 8601 format.
+
+ This is 'YYYY-MM-DD'.
+ For example, date(2002, 12, 4).isoformat() == '2002-12-04'.
+ """
+
+ def __str__():
+ """For a date d, str(d) is equivalent to d.isoformat()."""
+
+ def ctime():
+ """Return a string representing the date.
+
+ For example date(2002, 12, 4).ctime() == 'Wed Dec 4 00:00:00 2002'.
+ d.ctime() is equivalent to time.ctime(time.mktime(d.timetuple()))
+ on platforms where the native C ctime() function
+ (which time.ctime() invokes, but which date.ctime() does not invoke)
+ conforms to the C standard.
+ """
+
+ def strftime(format):
+ """Return a string representing the date.
+
+ Controlled by an explicit format string. Format codes referring to
+ hours, minutes or seconds will see 0 values.
+ """
+
+
+class IDateTimeClass(Interface):
+ """This is the datetime class interface."""
+
+ min = Attribute("The earliest representable datetime")
+
+ max = Attribute("The latest representable datetime")
+
+ resolution = Attribute(
+ "The smallest possible difference between non-equal datetime objects")
+
+ def today():
+ """Return the current local datetime, with tzinfo None.
+
+ This is equivalent to datetime.fromtimestamp(time.time()).
+ See also now(), fromtimestamp().
+ """
+
+ def now(tz=None):
+ """Return the current local date and time.
+
+ If optional argument tz is None or not specified, this is like today(),
+ but, if possible, supplies more precision than can be gotten from going
+ through a time.time() timestamp (for example, this may be possible on
+ platforms supplying the C gettimeofday() function).
+
+ Else tz must be an instance of a class tzinfo subclass, and the current
+ date and time are converted to tz's time zone. In this case the result
+ is equivalent to tz.fromutc(datetime.utcnow().replace(tzinfo=tz)).
+
+ See also today(), utcnow().
+ """
+
+ def utcnow():
+ """Return the current UTC date and time, with tzinfo None.
+
+ This is like now(), but returns the current UTC date and time, as a
+ naive datetime object.
+
+ See also now().
+ """
+
+ def fromtimestamp(timestamp, tz=None):
+ """Return the local date and time corresponding to the POSIX timestamp.
+
+ Same as is returned by time.time(). If optional argument tz is None or
+ not specified, the timestamp is converted to the platform's local date
+ and time, and the returned datetime object is naive.
+
+ Else tz must be an instance of a class tzinfo subclass, and the
+ timestamp is converted to tz's time zone. In this case the result is
+ equivalent to
+ tz.fromutc(datetime.utcfromtimestamp(timestamp).replace(tzinfo=tz)).
+
+ fromtimestamp() may raise ValueError, if the timestamp is out of the
+ range of values supported by the platform C localtime() or gmtime()
+ functions. It's common for this to be restricted to years in 1970
+ through 2038. Note that on non-POSIX systems that include leap seconds
+ in their notion of a timestamp, leap seconds are ignored by
+ fromtimestamp(), and then it's possible to have two timestamps
+ differing by a second that yield identical datetime objects.
+
+ See also utcfromtimestamp().
+ """
+
+ def utcfromtimestamp(timestamp):
+ """Return the UTC datetime from the POSIX timestamp with tzinfo None.
+
+ This may raise ValueError, if the timestamp is out of the range of
+ values supported by the platform C gmtime() function. It's common for
+ this to be restricted to years in 1970 through 2038.
+
+ See also fromtimestamp().
+ """
+
+ def fromordinal(ordinal):
+ """Return the datetime from the proleptic Gregorian ordinal.
+
+ January 1 of year 1 has ordinal 1. ValueError is raised unless
+ 1 <= ordinal <= datetime.max.toordinal().
+ The hour, minute, second and microsecond of the result are all 0, and
+ tzinfo is None.
+ """
+
+ def combine(date, time):
+ """Return a new datetime object.
+
+ Its date members are equal to the given date object's, and whose time
+ and tzinfo members are equal to the given time object's. For any
+ datetime object d, d == datetime.combine(d.date(), d.timetz()).
+ If date is a datetime object, its time and tzinfo members are ignored.
+ """
+
+
+class IDateTime(IDate, IDateTimeClass):
+ """Object contains all the information from a date object and a time object.
+ """
+
+ year = Attribute("Year between MINYEAR and MAXYEAR inclusive")
+
+ month = Attribute("Month between 1 and 12 inclusive")
+
+ day = Attribute(
+ "Day between 1 and the number of days in the given month of the year")
+
+ hour = Attribute("Hour in range(24)")
+
+ minute = Attribute("Minute in range(60)")
+
+ second = Attribute("Second in range(60)")
+
+ microsecond = Attribute("Microsecond in range(1000000)")
+
+ tzinfo = Attribute(
+ """The object passed as the tzinfo argument to the datetime constructor
+ or None if none was passed""")
+
+ def date():
+ """Return date object with same year, month and day."""
+
+ def time():
+ """Return time object with same hour, minute, second, microsecond.
+
+ tzinfo is None. See also method timetz().
+ """
+
+ def timetz():
+ """Return time object with same hour, minute, second, microsecond,
+ and tzinfo.
+
+ See also method time().
+ """
+
+ def replace(year, month, day, hour, minute, second, microsecond, tzinfo):
+ """Return a datetime with the same members, except for those members
+ given new values by whichever keyword arguments are specified.
+
+ Note that tzinfo=None can be specified to create a naive datetime from
+ an aware datetime with no conversion of date and time members.
+ """
+
+ def astimezone(tz):
+ """Return a datetime object with new tzinfo member tz, adjusting the
+ date and time members so the result is the same UTC time as self, but
+ in tz's local time.
+
+ tz must be an instance of a tzinfo subclass, and its utcoffset() and
+ dst() methods must not return None. self must be aware (self.tzinfo
+ must not be None, and self.utcoffset() must not return None).
+
+ If self.tzinfo is tz, self.astimezone(tz) is equal to self: no
+ adjustment of date or time members is performed. Else the result is
+ local time in time zone tz, representing the same UTC time as self:
+ after astz = dt.astimezone(tz), astz - astz.utcoffset()
+ will usually have the same date and time members as dt - dt.utcoffset().
+ The discussion of class tzinfo explains the cases at Daylight Saving
+ Time transition boundaries where this cannot be achieved (an issue only
+ if tz models both standard and daylight time).
+
+ If you merely want to attach a time zone object tz to a datetime dt
+ without adjustment of date and time members, use dt.replace(tzinfo=tz).
+ If you merely want to remove the time zone object from an aware
+ datetime dt without conversion of date and time members, use
+ dt.replace(tzinfo=None).
+
+ Note that the default tzinfo.fromutc() method can be overridden in a
+ tzinfo subclass to effect the result returned by astimezone().
+ """
+
+ def utcoffset():
+ """Return the timezone offset in minutes east of UTC (negative west of
+ UTC)."""
+
+ def dst():
+ """Return 0 if DST is not in effect, or the DST offset (in minutes
+ eastward) if DST is in effect.
+ """
+
+ def tzname():
+ """Return the timezone name."""
+
+ def timetuple():
+ """Return a 9-element tuple of the form returned by time.localtime()."""
+
+ def utctimetuple():
+ """Return UTC time tuple compatilble with time.gmtimr()."""
+
+ def toordinal():
+ """Return the proleptic Gregorian ordinal of the date.
+
+ The same as self.date().toordinal().
+ """
+
+ def weekday():
+ """Return the day of the week as an integer.
+
+ Monday is 0 and Sunday is 6. The same as self.date().weekday().
+ See also isoweekday().
+ """
+
+ def isoweekday():
+ """Return the day of the week as an integer.
+
+ Monday is 1 and Sunday is 7. The same as self.date().isoweekday.
+ See also weekday(), isocalendar().
+ """
+
+ def isocalendar():
+ """Return a 3-tuple, (ISO year, ISO week number, ISO weekday).
+
+ The same as self.date().isocalendar().
+ """
+
+ def isoformat(sep='T'):
+ """Return a string representing the date and time in ISO 8601 format.
+
+ YYYY-MM-DDTHH:MM:SS.mmmmmm or YYYY-MM-DDTHH:MM:SS if microsecond is 0
+
+ If utcoffset() does not return None, a 6-character string is appended,
+ giving the UTC offset in (signed) hours and minutes:
+
+ YYYY-MM-DDTHH:MM:SS.mmmmmm+HH:MM or YYYY-MM-DDTHH:MM:SS+HH:MM
+ if microsecond is 0.
+
+ The optional argument sep (default 'T') is a one-character separator,
+ placed between the date and time portions of the result.
+ """
+
+ def __str__():
+ """For a datetime instance d, str(d) is equivalent to d.isoformat(' ').
+ """
+
+ def ctime():
+ """Return a string representing the date and time.
+
+ datetime(2002, 12, 4, 20, 30, 40).ctime() == 'Wed Dec 4 20:30:40 2002'.
+ d.ctime() is equivalent to time.ctime(time.mktime(d.timetuple())) on
+ platforms where the native C ctime() function (which time.ctime()
+ invokes, but which datetime.ctime() does not invoke) conforms to the
+ C standard.
+ """
+
+ def strftime(format):
+ """Return a string representing the date and time.
+
+ This is controlled by an explicit format string.
+ """
+
+
+class ITimeClass(Interface):
+ """This is the time class interface."""
+
+ min = Attribute("The earliest representable time")
+
+ max = Attribute("The latest representable time")
+
+ resolution = Attribute(
+ "The smallest possible difference between non-equal time objects")
+
+
+class ITime(ITimeClass):
+ """Represent time with time zone.
+
+ Operators:
+
+ __repr__, __str__
+ __cmp__, __hash__
+ """
+
+ hour = Attribute("Hour in range(24)")
+
+ minute = Attribute("Minute in range(60)")
+
+ second = Attribute("Second in range(60)")
+
+ microsecond = Attribute("Microsecond in range(1000000)")
+
+ tzinfo = Attribute(
+ """The object passed as the tzinfo argument to the time constructor
+ or None if none was passed.""")
+
+ def replace(hour, minute, second, microsecond, tzinfo):
+ """Return a time with the same value.
+
+ Except for those members given new values by whichever keyword
+ arguments are specified. Note that tzinfo=None can be specified
+ to create a naive time from an aware time, without conversion of the
+ time members.
+ """
+
+ def isoformat():
+ """Return a string representing the time in ISO 8601 format.
+
+ That is HH:MM:SS.mmmmmm or, if self.microsecond is 0, HH:MM:SS
+ If utcoffset() does not return None, a 6-character string is appended,
+ giving the UTC offset in (signed) hours and minutes:
+ HH:MM:SS.mmmmmm+HH:MM or, if self.microsecond is 0, HH:MM:SS+HH:MM
+ """
+
+ def __str__():
+ """For a time t, str(t) is equivalent to t.isoformat()."""
+
+ def strftime(format):
+ """Return a string representing the time.
+
+ This is controlled by an explicit format string.
+ """
+
+ def utcoffset():
+ """Return the timezone offset in minutes east of UTC (negative west of
+ UTC).
+
+ If tzinfo is None, returns None, else returns
+ self.tzinfo.utcoffset(None), and raises an exception if the latter
+ doesn't return None or a timedelta object representing a whole number
+ of minutes with magnitude less than one day.
+ """
+
+ def dst():
+ """Return 0 if DST is not in effect, or the DST offset (in minutes
+ eastward) if DST is in effect.
+
+ If tzinfo is None, returns None, else returns self.tzinfo.dst(None),
+ and raises an exception if the latter doesn't return None, or a
+ timedelta object representing a whole number of minutes with
+ magnitude less than one day.
+ """
+
+ def tzname():
+ """Return the timezone name.
+
+ If tzinfo is None, returns None, else returns self.tzinfo.tzname(None),
+ or raises an exception if the latter doesn't return None or a string
+ object.
+ """
+
+
+class ITZInfo(Interface):
+ """Time zone info class.
+ """
+
+ def utcoffset(dt):
+ """Return offset of local time from UTC, in minutes east of UTC.
+
+ If local time is west of UTC, this should be negative.
+ Note that this is intended to be the total offset from UTC;
+ for example, if a tzinfo object represents both time zone and DST
+ adjustments, utcoffset() should return their sum. If the UTC offset
+ isn't known, return None. Else the value returned must be a timedelta
+ object specifying a whole number of minutes in the range -1439 to 1439
+ inclusive (1440 = 24*60; the magnitude of the offset must be less
+ than one day).
+ """
+
+ def dst(dt):
+ """Return the daylight saving time (DST) adjustment, in minutes east
+ of UTC, or None if DST information isn't known.
+ """
+
+ def tzname(dt):
+ """Return the time zone name corresponding to the datetime object as
+ a string.
+ """
+
+ def fromutc(dt):
+ """Return an equivalent datetime in self's local time."""
+
+
+classImplements(timedelta, ITimeDelta)
+classImplements(date, IDate)
+classImplements(datetime, IDateTime)
+classImplements(time, ITime)
+classImplements(tzinfo, ITZInfo)
+
+## directlyProvides(timedelta, ITimeDeltaClass)
+## directlyProvides(date, IDateClass)
+## directlyProvides(datetime, IDateTimeClass)
+## directlyProvides(time, ITimeClass)
diff --git a/zope/interface/common/interfaces.py b/zope/interface/common/interfaces.py
new file mode 100644
index 0000000..a8585b0
--- /dev/null
+++ b/zope/interface/common/interfaces.py
@@ -0,0 +1,98 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Interfaces for standard python exceptions
+
+$Id: interfaces.py 25177 2004-06-02 13:17:31Z jim $
+"""
+from zope.interface import Interface
+from zope.interface import classImplements
+
+class IException(Interface): pass
+class IStandardError(IException): pass
+class IWarning(IException): pass
+class ISyntaxError(IStandardError): pass
+class ILookupError(IStandardError): pass
+class IValueError(IStandardError): pass
+class IRuntimeError(IStandardError): pass
+class IArithmeticError(IStandardError): pass
+class IAssertionError(IStandardError): pass
+class IAttributeError(IStandardError): pass
+class IDeprecationWarning(IWarning): pass
+class IEOFError(IStandardError): pass
+class IEnvironmentError(IStandardError): pass
+class IFloatingPointError(IArithmeticError): pass
+class IIOError(IEnvironmentError): pass
+class IImportError(IStandardError): pass
+class IIndentationError(ISyntaxError): pass
+class IIndexError(ILookupError): pass
+class IKeyError(ILookupError): pass
+class IKeyboardInterrupt(IStandardError): pass
+class IMemoryError(IStandardError): pass
+class INameError(IStandardError): pass
+class INotImplementedError(IRuntimeError): pass
+class IOSError(IEnvironmentError): pass
+class IOverflowError(IArithmeticError): pass
+class IOverflowWarning(IWarning): pass
+class IReferenceError(IStandardError): pass
+class IRuntimeWarning(IWarning): pass
+class IStopIteration(IException): pass
+class ISyntaxWarning(IWarning): pass
+class ISystemError(IStandardError): pass
+class ISystemExit(IException): pass
+class ITabError(IIndentationError): pass
+class ITypeError(IStandardError): pass
+class IUnboundLocalError(INameError): pass
+class IUnicodeError(IValueError): pass
+class IUserWarning(IWarning): pass
+class IZeroDivisionError(IArithmeticError): pass
+
+classImplements(ArithmeticError, IArithmeticError)
+classImplements(AssertionError, IAssertionError)
+classImplements(AttributeError, IAttributeError)
+classImplements(DeprecationWarning, IDeprecationWarning)
+classImplements(EnvironmentError, IEnvironmentError)
+classImplements(EOFError, IEOFError)
+classImplements(Exception, IException)
+classImplements(FloatingPointError, IFloatingPointError)
+classImplements(ImportError, IImportError)
+classImplements(IndentationError, IIndentationError)
+classImplements(IndexError, IIndexError)
+classImplements(IOError, IIOError)
+classImplements(KeyboardInterrupt, IKeyboardInterrupt)
+classImplements(KeyError, IKeyError)
+classImplements(LookupError, ILookupError)
+classImplements(MemoryError, IMemoryError)
+classImplements(NameError, INameError)
+classImplements(NotImplementedError, INotImplementedError)
+classImplements(OSError, IOSError)
+classImplements(OverflowError, IOverflowError)
+classImplements(OverflowWarning, IOverflowWarning)
+classImplements(ReferenceError, IReferenceError)
+classImplements(RuntimeError, IRuntimeError)
+classImplements(RuntimeWarning, IRuntimeWarning)
+classImplements(StandardError, IStandardError)
+classImplements(StopIteration, IStopIteration)
+classImplements(SyntaxError, ISyntaxError)
+classImplements(SyntaxWarning, ISyntaxWarning)
+classImplements(SystemError, ISystemError)
+classImplements(SystemExit, ISystemExit)
+classImplements(TabError, ITabError)
+classImplements(TypeError, ITypeError)
+classImplements(UnboundLocalError, IUnboundLocalError)
+classImplements(UnicodeError, IUnicodeError)
+classImplements(UserWarning, IUserWarning)
+classImplements(ValueError, IValueError)
+classImplements(Warning, IWarning)
+classImplements(ZeroDivisionError, IZeroDivisionError)
+
diff --git a/zope/interface/common/mapping.py b/zope/interface/common/mapping.py
new file mode 100644
index 0000000..ba29fd8
--- /dev/null
+++ b/zope/interface/common/mapping.py
@@ -0,0 +1,127 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Mapping Interfaces
+
+$Id: mapping.py 29359 2005-03-01 15:45:04Z poster $
+"""
+from zope.interface import Interface
+
+class IItemMapping(Interface):
+ """Simplest readable mapping object
+ """
+
+ def __getitem__(key):
+ """Get a value for a key
+
+ A KeyError is raised if there is no value for the key.
+ """
+
+
+class IReadMapping(IItemMapping):
+ """Basic mapping interface
+ """
+
+ def get(key, default=None):
+ """Get a value for a key
+
+ The default is returned if there is no value for the key.
+ """
+
+ def __contains__(key):
+ """Tell if a key exists in the mapping."""
+
+
+class IWriteMapping(Interface):
+ """Mapping methods for changing data"""
+
+ def __delitem__(key):
+ """Delete a value from the mapping using the key."""
+
+ def __setitem__(key, value):
+ """Set a new item in the mapping."""
+
+
+class IEnumerableMapping(IReadMapping):
+ """Mapping objects whose items can be enumerated.
+ """
+
+ def keys():
+ """Return the keys of the mapping object.
+ """
+
+ def __iter__():
+ """Return an iterator for the keys of the mapping object.
+ """
+
+ def values():
+ """Return the values of the mapping object.
+ """
+
+ def items():
+ """Return the items of the mapping object.
+ """
+
+ def __len__():
+ """Return the number of items.
+ """
+
+class IMapping(IWriteMapping, IEnumerableMapping):
+ ''' Simple mapping interface '''
+
+class IIterableMapping(IEnumerableMapping):
+
+ def iterkeys():
+ "iterate over keys; equivalent to __iter__"
+
+ def itervalues():
+ "iterate over values"
+
+ def iteritems():
+ "iterate over items"
+
+class IClonableMapping(Interface):
+
+ def copy():
+ "return copy of dict"
+
+class IExtendedReadMapping(IIterableMapping):
+
+ def has_key(key):
+ """Tell if a key exists in the mapping; equivalent to __contains__"""
+
+class IExtendedWriteMapping(IWriteMapping):
+
+ def clear():
+ "delete all items"
+
+ def update(d):
+ " Update D from E: for k in E.keys(): D[k] = E[k]"
+
+ def setdefault(key, default=None):
+ "D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D"
+
+ def pop(k, *args):
+ """remove specified key and return the corresponding value
+ *args may contain a single default value, or may not be supplied.
+ If key is not found, default is returned if given, otherwise
+ KeyError is raised"""
+
+ def popitem():
+ """remove and return some (key, value) pair as a
+ 2-tuple; but raise KeyError if mapping is empty"""
+
+class IFullMapping(
+ IExtendedReadMapping, IExtendedWriteMapping, IClonableMapping, IMapping):
+ ''' Full mapping interface ''' # IMapping included so tests for IMapping
+ # succeed with IFullMapping
diff --git a/zope/interface/common/sequence.py b/zope/interface/common/sequence.py
new file mode 100644
index 0000000..054d137
--- /dev/null
+++ b/zope/interface/common/sequence.py
@@ -0,0 +1,152 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Sequence Interfaces
+
+$Id: sequence.py 39752 2005-10-30 20:16:09Z srichter $
+"""
+__docformat__ = 'restructuredtext'
+from zope import interface
+
+class IMinimalSequence(interface.Interface):
+
+ def __getitem__(index):
+ """`x.__getitem__(index)` <==> `x[index]`
+
+ Declaring this interface does not specify whether `__getitem__`
+ supports slice objects."""
+
+ def __iter__():
+ """`x.__iter__()` <==> `iter(x)`"""
+
+class IFiniteSequence(IMinimalSequence):
+
+ def __len__():
+ """`x.__len__()` <==> `len(x)`"""
+
+class IReadSequence(IFiniteSequence):
+ """read interface shared by tuple and list"""
+
+ def __contains__(item):
+ """`x.__contains__(item)` <==> `item in x`"""
+
+ def __lt__(other):
+ """`x.__lt__(other)` <==> `x < other`"""
+
+ def __le__(other):
+ """`x.__le__(other)` <==> `x <= other`"""
+
+ def __eq__(other):
+ """`x.__eq__(other)` <==> `x == other`"""
+
+ def __ne__(other):
+ """`x.__ne__(other)` <==> `x != other`"""
+
+ def __gt__(other):
+ """`x.__gt__(other)` <==> `x > other`"""
+
+ def __ge__(other):
+ """`x.__ge__(other)` <==> `x >= other`"""
+
+ def __add__(other):
+ """`x.__add__(other)` <==> `x + other`"""
+
+ def __mul__(n):
+ """`x.__mul__(n)` <==> `x * n`"""
+
+ def __rmul__(n):
+ """`x.__rmul__(n)` <==> `n * x`"""
+
+ def __getslice__(i, j):
+ """`x.__getslice__(i, j)` <==> `x[i:j]`
+
+ Use of negative indices is not supported.
+
+ Deprecated since Python 2.0 but still a part of `UserList`.
+ """
+
+class IExtendedReadSequence(IReadSequence):
+ """Full read interface for lists"""
+
+ def count(item):
+ """Return number of occurrences of value"""
+
+ def index(item, *args):
+ """Return first index of value
+
+ `L.index(value, [start, [stop]])` -> integer"""
+
+class IUniqueMemberWriteSequence(interface.Interface):
+ """The write contract for a sequence that may enforce unique members"""
+
+ def __setitem__(index, item):
+ """`x.__setitem__(index, item)` <==> `x[index] = item`
+
+ Declaring this interface does not specify whether `__setitem__`
+ supports slice objects.
+ """
+
+ def __delitem__(index):
+ """`x.__delitem__(index)` <==> `del x[index]`
+
+ Declaring this interface does not specify whether `__delitem__`
+ supports slice objects.
+ """
+
+ def __setslice__(i, j, other):
+ """`x.__setslice__(i, j, other)` <==> `x[i:j]=other`
+
+ Use of negative indices is not supported.
+
+ Deprecated since Python 2.0 but still a part of `UserList`.
+ """
+
+ def __delslice__(i, j):
+ """`x.__delslice__(i, j)` <==> `del x[i:j]`
+
+ Use of negative indices is not supported.
+
+ Deprecated since Python 2.0 but still a part of `UserList`.
+ """
+ def __iadd__(y):
+ """`x.__iadd__(y)` <==> `x += y`"""
+
+ def append(item):
+ """Append item to end"""
+
+ def insert(index, item):
+ """Insert item before index"""
+
+ def pop(index=-1):
+ """Remove and return item at index (default last)"""
+
+ def remove(item):
+ """Remove first occurrence of value"""
+
+ def reverse():
+ """Reverse *IN PLACE*"""
+
+ def sort(cmpfunc=None):
+ """Stable sort *IN PLACE*; `cmpfunc(x, y)` -> -1, 0, 1"""
+
+ def extend(iterable):
+ """Extend list by appending elements from the iterable"""
+
+class IWriteSequence(IUniqueMemberWriteSequence):
+ """Full write contract for sequences"""
+
+ def __imul__(n):
+ """`x.__imul__(n)` <==> `x *= n`"""
+
+class ISequence(IReadSequence, IWriteSequence):
+ """Full sequence contract"""
diff --git a/zope/interface/declarations.py b/zope/interface/declarations.py
new file mode 100644
index 0000000..99e7898
--- /dev/null
+++ b/zope/interface/declarations.py
@@ -0,0 +1,1386 @@
+##############################################################################
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+##############################################################################
+"""Implementation of interface declarations
+
+There are three flavors of declarations:
+
+ - Declarations are used to simply name declared interfaces.
+
+ - ImplementsDeclarations are used to express the interfaces that a
+ class implements (that instances of the class provides).
+
+ Implements specifications support inheriting interfaces.
+
+ - ProvidesDeclarations are used to express interfaces directly
+ provided by objects.
+
+
+$Id: declarations.py 70112 2006-09-12 04:51:16Z baijum $
+"""
+__docformat__ = 'restructuredtext'
+
+import sys
+import types
+import weakref
+from zope.interface.interface import InterfaceClass, Specification
+from ro import mergeOrderings, ro
+import exceptions
+from types import ClassType, ModuleType
+from zope.interface.advice import addClassAdvisor
+
+# Registry of class-implementation specifications
+BuiltinImplementationSpecifications = {}
+
+class Declaration(Specification):
+ """Interface declarations"""
+
+ def __init__(self, *interfaces):
+ Specification.__init__(self, _normalizeargs(interfaces))
+
+ def changed(self, originally_changed):
+ Specification.changed(self, originally_changed)
+ try:
+ del self._v_attrs
+ except AttributeError:
+ pass
+
+ def __contains__(self, interface):
+ """Test whether an interface is in the specification
+
+ for example:
+
+ >>> from zope.interface import Interface
+ >>> class I1(Interface): pass
+ ...
+ >>> class I2(I1): pass
+ ...
+ >>> class I3(Interface): pass
+ ...
+ >>> class I4(I3): pass
+ ...
+ >>> spec = Declaration(I2, I3)
+ >>> spec = Declaration(I4, spec)
+ >>> int(I1 in spec)
+ 0
+ >>> int(I2 in spec)
+ 1
+ >>> int(I3 in spec)
+ 1
+ >>> int(I4 in spec)
+ 1
+ """
+ return self.extends(interface) and interface in self.interfaces()
+
+ def __iter__(self):
+ """Return an iterator for the interfaces in the specification
+
+ for example:
+
+ >>> from zope.interface import Interface
+ >>> class I1(Interface): pass
+ ...
+ >>> class I2(I1): pass
+ ...
+ >>> class I3(Interface): pass
+ ...
+ >>> class I4(I3): pass
+ ...
+ >>> spec = Declaration(I2, I3)
+ >>> spec = Declaration(I4, spec)
+ >>> i = iter(spec)
+ >>> i.next().getName()
+ 'I4'
+ >>> i.next().getName()
+ 'I2'
+ >>> i.next().getName()
+ 'I3'
+ >>> list(i)
+ []
+ """
+ return self.interfaces()
+
+ def flattened(self):
+ """Return an iterator of all included and extended interfaces
+
+ for example:
+
+ >>> from zope.interface import Interface
+ >>> class I1(Interface): pass
+ ...
+ >>> class I2(I1): pass
+ ...
+ >>> class I3(Interface): pass
+ ...
+ >>> class I4(I3): pass
+ ...
+ >>> spec = Declaration(I2, I3)
+ >>> spec = Declaration(I4, spec)
+ >>> i = spec.flattened()
+ >>> i.next().getName()
+ 'I4'
+ >>> i.next().getName()
+ 'I2'
+ >>> i.next().getName()
+ 'I1'
+ >>> i.next().getName()
+ 'I3'
+ >>> i.next().getName()
+ 'Interface'
+ >>> list(i)
+ []
+
+ """
+ return iter(self.__iro__)
+
+ def __sub__(self, other):
+ """Remove interfaces from a specification
+
+ Examples:
+
+ >>> from zope.interface import Interface
+ >>> class I1(Interface): pass
+ ...
+ >>> class I2(I1): pass
+ ...
+ >>> class I3(Interface): pass
+ ...
+ >>> class I4(I3): pass
+ ...
+ >>> spec = Declaration()
+ >>> [iface.getName() for iface in spec]
+ []
+ >>> spec -= I1
+ >>> [iface.getName() for iface in spec]
+ []
+ >>> spec -= Declaration(I1, I2)
+ >>> [iface.getName() for iface in spec]
+ []
+ >>> spec = Declaration(I2, I4)
+ >>> [iface.getName() for iface in spec]
+ ['I2', 'I4']
+ >>> [iface.getName() for iface in spec - I4]
+ ['I2']
+ >>> [iface.getName() for iface in spec - I1]
+ ['I4']
+ >>> [iface.getName() for iface
+ ... in spec - Declaration(I3, I4)]
+ ['I2']
+
+ """
+
+ return Declaration(
+ *[i for i in self.interfaces()
+ if not [j for j in other.interfaces()
+ if i.extends(j, 0)]
+ ]
+ )
+
+ def __add__(self, other):
+ """Add two specifications or a specification and an interface
+
+ Examples:
+
+ >>> from zope.interface import Interface
+ >>> class I1(Interface): pass
+ ...
+ >>> class I2(I1): pass
+ ...
+ >>> class I3(Interface): pass
+ ...
+ >>> class I4(I3): pass
+ ...
+ >>> spec = Declaration()
+ >>> [iface.getName() for iface in spec]
+ []
+ >>> [iface.getName() for iface in spec+I1]
+ ['I1']
+ >>> [iface.getName() for iface in I1+spec]
+ ['I1']
+ >>> spec2 = spec
+ >>> spec += I1
+ >>> [iface.getName() for iface in spec]
+ ['I1']
+ >>> [iface.getName() for iface in spec2]
+ []
+ >>> spec2 += Declaration(I3, I4)
+ >>> [iface.getName() for iface in spec2]
+ ['I3', 'I4']
+ >>> [iface.getName() for iface in spec+spec2]
+ ['I1', 'I3', 'I4']
+ >>> [iface.getName() for iface in spec2+spec]
+ ['I3', 'I4', 'I1']
+
+ """
+
+ seen = {}
+ result = []
+ for i in self.interfaces():
+ if i not in seen:
+ seen[i] = 1
+ result.append(i)
+ for i in other.interfaces():
+ if i not in seen:
+ seen[i] = 1
+ result.append(i)
+
+ return Declaration(*result)
+
+ __radd__ = __add__
+
+
+##############################################################################
+#
+# Implementation specifications
+#
+# These specify interfaces implemented by instances of classes
+
+class Implements(Declaration):
+
+ # class whose specification should be used as additional base
+ inherit = None
+
+ # interfaces actually declared for a class
+ declared = ()
+
+ __name__ = '?'
+
+ def __repr__(self):
+ return '<implementedBy %s>' % (self.__name__)
+
+ def __reduce__(self):
+ return implementedBy, (self.inherit, )
+
+def implementedByFallback(cls):
+ """Return the interfaces implemented for a class' instances
+
+ The value returned is an IDeclaration.
+
+ for example:
+
+ >>> from zope.interface import Interface
+ >>> class I1(Interface): pass
+ ...
+ >>> class I2(I1): pass
+ ...
+ >>> class I3(Interface): pass
+ ...
+ >>> class I4(I3): pass
+ ...
+ >>> class C1(object):
+ ... implements(I2)
+ >>> class C2(C1):
+ ... implements(I3)
+ >>> [i.getName() for i in implementedBy(C2)]
+ ['I3', 'I2']
+
+ Really, any object should be able to receive a successful answer, even
+ an instance:
+
+ >>> class Callable(object):
+ ... def __call__(self):
+ ... return self
+
+ >>> implementedBy(Callable())
+ <implementedBy zope.interface.declarations.?>
+
+ Note that the name of the spec ends with a '?', because the `Callable`
+ instance does not have a `__name__` attribute.
+ """
+ # This also manages storage of implementation specifications
+
+ try:
+ spec = cls.__dict__.get('__implemented__')
+ except AttributeError:
+
+ # we can't get the class dict. This is probably due to a
+ # security proxy. If this is the case, then probably no
+ # descriptor was installed for the class.
+
+ # We don't want to depend directly on zope.security in
+ # zope.interface, but we'll try to make reasonable
+ # accommodations in an indirect way.
+
+ # We'll check to see if there's an implements:
+
+ spec = getattr(cls, '__implemented__', None)
+ if spec is None:
+ # There's no spec stred in the class. Maybe its a builtin:
+ spec = BuiltinImplementationSpecifications.get(cls)
+ if spec is not None:
+ return spec
+ return _empty
+
+ if spec.__class__ == Implements:
+ # we defaulted to _empty or there was a spec. Good enough.
+ # Return it.
+ return spec
+
+ # TODO: need old style __implements__ compatibility?
+ # Hm, there's an __implemented__, but it's not a spec. Must be
+ # an old-style declaration. Just compute a spec for it
+ return Declaration(*_normalizeargs((spec, )))
+
+ if isinstance(spec, Implements):
+ return spec
+
+ if spec is None:
+ spec = BuiltinImplementationSpecifications.get(cls)
+ if spec is not None:
+ return spec
+
+ # TODO: need old style __implements__ compatibility?
+ if spec is not None:
+ # old-style __implemented__ = foo declaration
+ spec = (spec, ) # tuplefy, as it might be just an int
+ spec = Implements(*_normalizeargs(spec))
+ spec.inherit = None # old-style implies no inherit
+ del cls.__implemented__ # get rid of the old-style declaration
+ else:
+ try:
+ bases = cls.__bases__
+ except AttributeError:
+ if not callable(cls):
+ raise TypeError("ImplementedBy called for non-factory", cls)
+ bases = ()
+
+ spec = Implements(*[implementedBy(c) for c in bases])
+ spec.inherit = cls
+
+ spec.__name__ = (getattr(cls, '__module__', '?') or '?') + \
+ '.' + (getattr(cls, '__name__', '?') or '?')
+
+ try:
+ cls.__implemented__ = spec
+ if not hasattr(cls, '__providedBy__'):
+ cls.__providedBy__ = objectSpecificationDescriptor
+
+ if (isinstance(cls, DescriptorAwareMetaClasses)
+ and
+ '__provides__' not in cls.__dict__):
+ # Make sure we get a __provides__ descriptor
+ cls.__provides__ = ClassProvides(
+ cls,
+ getattr(cls, '__class__', type(cls)),
+ )
+
+ except TypeError:
+ if not isinstance(cls, type):
+ raise TypeError("ImplementedBy called for non-type", cls)
+ BuiltinImplementationSpecifications[cls] = spec
+
+ return spec
+
+implementedBy = implementedByFallback
+
+def classImplementsOnly(cls, *interfaces):
+ """Declare the only interfaces implemented by instances of a class
+
+ The arguments after the class are one or more interfaces or interface
+ specifications (``IDeclaration`` objects).
+
+ The interfaces given (including the interfaces in the specifications)
+ replace any previous declarations.
+
+ Consider the following example:
+
+ >>> from zope.interface import Interface
+ >>> class I1(Interface): pass
+ ...
+ >>> class I2(Interface): pass
+ ...
+ >>> class I3(Interface): pass
+ ...
+ >>> class I4(Interface): pass
+ ...
+ >>> class A(object):
+ ... implements(I3)
+ >>> class B(object):
+ ... implements(I4)
+ >>> class C(A, B):
+ ... pass
+ >>> classImplementsOnly(C, I1, I2)
+ >>> [i.getName() for i in implementedBy(C)]
+ ['I1', 'I2']
+
+ Instances of ``C`` provide only ``I1``, ``I2``, and regardless of
+ whatever interfaces instances of ``A`` and ``B`` implement.
+ """
+ spec = implementedBy(cls)
+ spec.declared = ()
+ spec.inherit = None
+ classImplements(cls, *interfaces)
+
+def classImplements(cls, *interfaces):
+ """Declare additional interfaces implemented for instances of a class
+
+ The arguments after the class are one or more interfaces or
+ interface specifications (``IDeclaration`` objects).
+
+ The interfaces given (including the interfaces in the specifications)
+ are added to any interfaces previously declared.
+
+ Consider the following example:
+
+ >>> from zope.interface import Interface
+ >>> class I1(Interface): pass
+ ...
+ >>> class I2(Interface): pass
+ ...
+ >>> class I3(Interface): pass
+ ...
+ >>> class I4(Interface): pass
+ ...
+ >>> class I5(Interface): pass
+ ...
+ >>> class A(object):
+ ... implements(I3)
+ >>> class B(object):
+ ... implements(I4)
+ >>> class C(A, B):
+ ... pass
+ >>> classImplements(C, I1, I2)
+ >>> [i.getName() for i in implementedBy(C)]
+ ['I1', 'I2', 'I3', 'I4']
+ >>> classImplements(C, I5)
+ >>> [i.getName() for i in implementedBy(C)]
+ ['I1', 'I2', 'I5', 'I3', 'I4']
+
+ Instances of ``C`` provide ``I1``, ``I2``, ``I5``, and whatever
+ interfaces instances of ``A`` and ``B`` provide.
+ """
+
+ spec = implementedBy(cls)
+ spec.declared += tuple(_normalizeargs(interfaces))
+
+ # compute the bases
+ bases = []
+ seen = {}
+ for b in spec.declared:
+ if b not in seen:
+ seen[b] = 1
+ bases.append(b)
+
+ if spec.inherit is not None:
+
+ for c in spec.inherit.__bases__:
+ b = implementedBy(c)
+ if b not in seen:
+ seen[b] = 1
+ bases.append(b)
+
+ spec.__bases__ = tuple(bases)
+
+def _implements_advice(cls):
+ interfaces, classImplements = cls.__dict__['__implements_advice_data__']
+ del cls.__implements_advice_data__
+ classImplements(cls, *interfaces)
+ return cls
+
+
+class implementer:
+
+ def __init__(self, *interfaces):
+ self.interfaces = interfaces
+
+ def __call__(self, ob):
+ if isinstance(ob, DescriptorAwareMetaClasses):
+ raise TypeError("Can't use implementer with classes. Use one of "
+ "the class-declaration functions instead."
+ )
+ spec = Implements(*self.interfaces)
+ try:
+ ob.__implemented__ = spec
+ except AttributeError:
+ raise TypeError("Can't declare implements", ob)
+ return ob
+
+def _implements(name, interfaces, classImplements):
+ frame = sys._getframe(2)
+ locals = frame.f_locals
+
+ # Try to make sure we were called from a class def. In 2.2.0 we can't
+ # check for __module__ since it doesn't seem to be added to the locals
+ # until later on.
+ if (locals is frame.f_globals) or (
+ ('__module__' not in locals) and sys.version_info[:3] > (2, 2, 0)):
+ raise TypeError(name+" can be used only from a class definition.")
+
+ if '__implements_advice_data__' in locals:
+ raise TypeError(name+" can be used only once in a class definition.")
+
+ locals['__implements_advice_data__'] = interfaces, classImplements
+ addClassAdvisor(_implements_advice, depth=3)
+
+def implements(*interfaces):
+ """Declare interfaces implemented by instances of a class
+
+ This function is called in a class definition.
+
+ The arguments are one or more interfaces or interface
+ specifications (IDeclaration objects).
+
+ The interfaces given (including the interfaces in the
+ specifications) are added to any interfaces previously
+ declared.
+
+ Previous declarations include declarations for base classes
+ unless implementsOnly was used.
+
+ This function is provided for convenience. It provides a more
+ convenient way to call classImplements. For example::
+
+ implements(I1)
+
+ is equivalent to calling::
+
+ classImplements(C, I1)
+
+ after the class has been created.
+
+ Consider the following example::
+
+
+ >>> from zope.interface import Interface
+ >>> class IA1(Interface): pass
+ ...
+ >>> class IA2(Interface): pass
+ ...
+ >>> class IB(Interface): pass
+ ...
+ >>> class IC(Interface): pass
+ ...
+ >>> class A(object): implements(IA1, IA2)
+ ...
+ >>> class B(object): implements(IB)
+ ...
+
+ >>> class C(A, B):
+ ... implements(IC)
+
+ >>> ob = C()
+ >>> int(IA1 in providedBy(ob))
+ 1
+ >>> int(IA2 in providedBy(ob))
+ 1
+ >>> int(IB in providedBy(ob))
+ 1
+ >>> int(IC in providedBy(ob))
+ 1
+
+ Instances of ``C`` implement ``I1``, ``I2``, and whatever interfaces
+ instances of ``A`` and ``B`` implement.
+
+ """
+ _implements("implements", interfaces, classImplements)
+
+def implementsOnly(*interfaces):
+ """Declare the only interfaces implemented by instances of a class
+
+ This function is called in a class definition.
+
+ The arguments are one or more interfaces or interface
+ specifications (IDeclaration objects).
+
+ Previous declarations including declarations for base classes
+ are overridden.
+
+ This function is provided for convenience. It provides a more
+ convenient way to call classImplementsOnly. For example::
+
+ implementsOnly(I1)
+
+ is equivalent to calling::
+
+ classImplementsOnly(I1)
+
+ after the class has been created.
+
+ Consider the following example::
+
+ >>> from zope.interface import Interface
+ >>> class IA1(Interface): pass
+ ...
+ >>> class IA2(Interface): pass
+ ...
+ >>> class IB(Interface): pass
+ ...
+ >>> class IC(Interface): pass
+ ...
+ >>> class A(object): implements(IA1, IA2)
+ ...
+ >>> class B(object): implements(IB)
+ ...
+
+ >>> class C(A, B):
+ ... implementsOnly(IC)
+
+ >>> ob = C()
+ >>> int(IA1 in providedBy(ob))
+ 0
+ >>> int(IA2 in providedBy(ob))
+ 0
+ >>> int(IB in providedBy(ob))
+ 0
+ >>> int(IC in providedBy(ob))
+ 1
+
+
+ Instances of ``C`` implement ``IC``, regardless of what
+ instances of ``A`` and ``B`` implement.
+
+ """
+ _implements("implementsOnly", interfaces, classImplementsOnly)
+
+##############################################################################
+#
+# Instance declarations
+
+class Provides(Declaration): # Really named ProvidesClass
+ """Implement __provides__, the instance-specific specification
+
+ When an object is pickled, we pickle the interfaces that it implements.
+ """
+
+ def __init__(self, cls, *interfaces):
+ self.__args = (cls, ) + interfaces
+ self._cls = cls
+ Declaration.__init__(self, *(interfaces + (implementedBy(cls), )))
+
+ def __reduce__(self):
+ return Provides, self.__args
+
+ __module__ = 'zope.interface'
+
+ def __get__(self, inst, cls):
+ """Make sure that a class __provides__ doesn't leak to an instance
+
+ For example:
+
+ >>> from zope.interface import Interface
+ >>> class IFooFactory(Interface): pass
+ ...
+
+ >>> class C(object):
+ ... pass
+
+ >>> C.__provides__ = ProvidesClass(C, IFooFactory)
+ >>> [i.getName() for i in C.__provides__]
+ ['IFooFactory']
+ >>> getattr(C(), '__provides__', 0)
+ 0
+
+ """
+ if inst is None and cls is self._cls:
+ # We were accessed through a class, so we are the class'
+ # provides spec. Just return this object, but only if we are
+ # being called on the same class that we were defined for:
+ return self
+
+ raise AttributeError('__provides__')
+
+ProvidesClass = Provides
+
+# Registry of instance declarations
+# This is a memory optimization to allow objects to share specifications.
+InstanceDeclarations = weakref.WeakValueDictionary()
+
+def Provides(*interfaces):
+ """Cache instance declarations
+
+ Instance declarations are shared among instances that have the same
+ declaration. The declarations are cached in a weak value dictionary.
+
+ (Note that, in the examples below, we are going to make assertions about
+ the size of the weakvalue dictionary. For the assertions to be
+ meaningful, we need to force garbage collection to make sure garbage
+ objects are, indeed, removed from the system. Depending on how Python
+ is run, we may need to make multiple calls to be sure. We provide a
+ collect function to help with this:
+
+ >>> import gc
+ >>> def collect():
+ ... for i in range(4):
+ ... gc.collect()
+
+ )
+
+ >>> collect()
+ >>> before = len(InstanceDeclarations)
+
+ >>> class C(object):
+ ... pass
+
+ >>> from zope.interface import Interface
+ >>> class I(Interface):
+ ... pass
+
+ >>> c1 = C()
+ >>> c2 = C()
+
+ >>> len(InstanceDeclarations) == before
+ 1
+
+ >>> directlyProvides(c1, I)
+ >>> len(InstanceDeclarations) == before + 1
+ 1
+
+ >>> directlyProvides(c2, I)
+ >>> len(InstanceDeclarations) == before + 1
+ 1
+
+ >>> del c1
+ >>> collect()
+ >>> len(InstanceDeclarations) == before + 1
+ 1
+
+ >>> del c2
+ >>> collect()
+ >>> len(InstanceDeclarations) == before
+ 1
+ """
+
+ spec = InstanceDeclarations.get(interfaces)
+ if spec is None:
+ spec = ProvidesClass(*interfaces)
+ InstanceDeclarations[interfaces] = spec
+
+ return spec
+Provides.__safe_for_unpickling__ = True
+
+
+DescriptorAwareMetaClasses = ClassType, type
+def directlyProvides(object, *interfaces):
+ """Declare interfaces declared directly for an object
+
+ The arguments after the object are one or more interfaces or interface
+ specifications (``IDeclaration`` objects).
+
+ The interfaces given (including the interfaces in the specifications)
+ replace interfaces previously declared for the object.
+
+ Consider the following example:
+
+ >>> from zope.interface import Interface
+ >>> class I1(Interface): pass
+ ...
+ >>> class I2(Interface): pass
+ ...
+ >>> class IA1(Interface): pass
+ ...
+ >>> class IA2(Interface): pass
+ ...
+ >>> class IB(Interface): pass
+ ...
+ >>> class IC(Interface): pass
+ ...
+ >>> class A(object): implements(IA1, IA2)
+ ...
+ >>> class B(object): implements(IB)
+ ...
+
+ >>> class C(A, B):
+ ... implements(IC)
+
+ >>> ob = C()
+ >>> directlyProvides(ob, I1, I2)
+ >>> int(I1 in providedBy(ob))
+ 1
+ >>> int(I2 in providedBy(ob))
+ 1
+ >>> int(IA1 in providedBy(ob))
+ 1
+ >>> int(IA2 in providedBy(ob))
+ 1
+ >>> int(IB in providedBy(ob))
+ 1
+ >>> int(IC in providedBy(ob))
+ 1
+
+ The object, ``ob`` provides ``I1``, ``I2``, and whatever interfaces
+ instances have been declared for instances of ``C``.
+
+ To remove directly provided interfaces, use ``directlyProvidedBy`` and
+ subtract the unwanted interfaces. For example:
+
+ >>> directlyProvides(ob, directlyProvidedBy(ob)-I2)
+ >>> int(I1 in providedBy(ob))
+ 1
+ >>> int(I2 in providedBy(ob))
+ 0
+
+ removes I2 from the interfaces directly provided by ``ob``. The object,
+ ``ob`` no longer directly provides ``I2``, although it might still
+ provide ``I2`` if it's class implements ``I2``.
+
+ To add directly provided interfaces, use ``directlyProvidedBy`` and
+ include additional interfaces. For example:
+
+ >>> int(I2 in providedBy(ob))
+ 0
+ >>> directlyProvides(ob, directlyProvidedBy(ob), I2)
+
+ adds ``I2`` to the interfaces directly provided by ob::
+
+ >>> int(I2 in providedBy(ob))
+ 1
+
+ """
+
+ # We need to avoid setting this attribute on meta classes that
+ # don't support descriptors.
+ # We can do away with this check when we get rid of the old EC
+ cls = getattr(object, '__class__', None)
+ if cls is not None and getattr(cls, '__class__', None) is cls:
+ # It's a meta class (well, at least it it could be an extension class)
+ if not isinstance(object, DescriptorAwareMetaClasses):
+ raise TypeError("Attempt to make an interface declaration on a "
+ "non-descriptor-aware class")
+
+ interfaces = _normalizeargs(interfaces)
+ if cls is None:
+ cls = type(object)
+
+ issub = False
+ for damc in DescriptorAwareMetaClasses:
+ if issubclass(cls, damc):
+ issub = True
+ break
+ if issub:
+ # we have a class or type. We'll use a special descriptor
+ # that provides some extra caching
+ object.__provides__ = ClassProvides(object, cls, *interfaces)
+ else:
+ object.__provides__ = Provides(cls, *interfaces)
+
+
+def alsoProvides(object, *interfaces):
+ """Declare interfaces declared directly for an object
+
+ The arguments after the object are one or more interfaces or interface
+ specifications (``IDeclaration`` objects).
+
+ The interfaces given (including the interfaces in the specifications) are
+ added to the interfaces previously declared for the object.
+
+ Consider the following example:
+
+ >>> from zope.interface import Interface
+ >>> class I1(Interface): pass
+ ...
+ >>> class I2(Interface): pass
+ ...
+ >>> class IA1(Interface): pass
+ ...
+ >>> class IA2(Interface): pass
+ ...
+ >>> class IB(Interface): pass
+ ...
+ >>> class IC(Interface): pass
+ ...
+ >>> class A(object): implements(IA1, IA2)
+ ...
+ >>> class B(object): implements(IB)
+ ...
+
+ >>> class C(A, B):
+ ... implements(IC)
+
+ >>> ob = C()
+ >>> directlyProvides(ob, I1)
+ >>> int(I1 in providedBy(ob))
+ 1
+ >>> int(I2 in providedBy(ob))
+ 0
+ >>> int(IA1 in providedBy(ob))
+ 1
+ >>> int(IA2 in providedBy(ob))
+ 1
+ >>> int(IB in providedBy(ob))
+ 1
+ >>> int(IC in providedBy(ob))
+ 1
+
+ >>> alsoProvides(ob, I2)
+ >>> int(I1 in providedBy(ob))
+ 1
+ >>> int(I2 in providedBy(ob))
+ 1
+ >>> int(IA1 in providedBy(ob))
+ 1
+ >>> int(IA2 in providedBy(ob))
+ 1
+ >>> int(IB in providedBy(ob))
+ 1
+ >>> int(IC in providedBy(ob))
+ 1
+
+ The object, ``ob`` provides ``I1``, ``I2``, and whatever interfaces
+ instances have been declared for instances of ``C``. Notice that the
+ alsoProvides just extends the provided interfaces.
+ """
+ directlyProvides(object, directlyProvidedBy(object), *interfaces)
+
+def noLongerProvides(object, interface):
+ """
+ This removes a directly provided interface from an object.
+ Consider the following two interfaces:
+
+ >>> from zope.interface import Interface
+ >>> class I1(Interface): pass
+ ...
+ >>> class I2(Interface): pass
+ ...
+
+ ``I1`` is provided through the class, ``I2`` is directly provided
+ by the object:
+
+ >>> class C(object):
+ ... implements(I1)
+ >>> c = C()
+ >>> alsoProvides(c, I2)
+ >>> I2.providedBy(c)
+ True
+
+ Remove I2 from c again:
+
+ >>> noLongerProvides(c, I2)
+ >>> I2.providedBy(c)
+ False
+
+ Removing an interface that is provided through the class is not possible:
+
+ >>> noLongerProvides(c, I1)
+ Traceback (most recent call last):
+ ...
+ ValueError: Can only remove directly provided interfaces.
+
+ """
+ directlyProvides(object, directlyProvidedBy(object)-interface)
+ if interface.providedBy(object):
+ raise ValueError("Can only remove directly provided interfaces.")
+
+class ClassProvidesBasePy(object):
+
+ def __get__(self, inst, cls):
+ if cls is self._cls:
+ # We only work if called on the class we were defined for
+
+ if inst is None:
+ # We were accessed through a class, so we are the class'
+ # provides spec. Just return this object as is:
+ return self
+
+ return self._implements
+
+ raise AttributeError('__provides__')
+
+ClassProvidesBase = ClassProvidesBasePy
+
+# Try to get C base:
+try:
+ import _zope_interface_coptimizations
+except ImportError:
+ pass
+else:
+ from _zope_interface_coptimizations import ClassProvidesBase
+
+
+class ClassProvides(Declaration, ClassProvidesBase):
+ """Special descriptor for class __provides__
+
+ The descriptor caches the implementedBy info, so that
+ we can get declarations for objects without instance-specific
+ interfaces a bit quicker.
+
+ For example:
+
+ >>> from zope.interface import Interface
+ >>> class IFooFactory(Interface):
+ ... pass
+ >>> class IFoo(Interface):
+ ... pass
+ >>> class C(object):
+ ... implements(IFoo)
+ ... classProvides(IFooFactory)
+ >>> [i.getName() for i in C.__provides__]
+ ['IFooFactory']
+
+ >>> [i.getName() for i in C().__provides__]
+ ['IFoo']
+ """
+
+ def __init__(self, cls, metacls, *interfaces):
+ self._cls = cls
+ self._implements = implementedBy(cls)
+ self.__args = (cls, metacls, ) + interfaces
+ Declaration.__init__(self, *(interfaces + (implementedBy(metacls), )))
+
+ def __reduce__(self):
+ return self.__class__, self.__args
+
+ # Copy base-class method for speed
+ __get__ = ClassProvidesBase.__get__
+
+def directlyProvidedBy(object):
+ """Return the interfaces directly provided by the given object
+
+ The value returned is an ``IDeclaration``.
+ """
+ provides = getattr(object, "__provides__", None)
+ if (provides is None # no spec
+ or
+ # We might have gotten the implements spec, as an
+ # optimization. If so, it's like having only one base, that we
+ # lop off to exclude class-supplied declarations:
+ isinstance(provides, Implements)
+ ):
+ return _empty
+
+ # Strip off the class part of the spec:
+ return Declaration(provides.__bases__[:-1])
+
+def classProvides(*interfaces):
+ """Declare interfaces provided directly by a class
+
+ This function is called in a class definition.
+
+ The arguments are one or more interfaces or interface specifications
+ (``IDeclaration`` objects).
+
+ The given interfaces (including the interfaces in the specifications)
+ are used to create the class's direct-object interface specification.
+ An error will be raised if the module class has an direct interface
+ specification. In other words, it is an error to call this function more
+ than once in a class definition.
+
+ Note that the given interfaces have nothing to do with the interfaces
+ implemented by instances of the class.
+
+ This function is provided for convenience. It provides a more convenient
+ way to call directlyProvidedByProvides for a class. For example::
+
+ classProvides(I1)
+
+ is equivalent to calling::
+
+ directlyProvides(theclass, I1)
+
+ after the class has been created.
+
+ For example:
+
+ >>> from zope.interface import Interface
+ >>> class IFoo(Interface): pass
+ ...
+ >>> class IFooFactory(Interface): pass
+ ...
+ >>> class C(object):
+ ... implements(IFoo)
+ ... classProvides(IFooFactory)
+ >>> [i.getName() for i in C.__providedBy__]
+ ['IFooFactory']
+ >>> [i.getName() for i in C().__providedBy__]
+ ['IFoo']
+
+ if equivalent to:
+
+ >>> from zope.interface import Interface
+ >>> class IFoo(Interface): pass
+ ...
+ >>> class IFooFactory(Interface): pass
+ ...
+ >>> class C(object):
+ ... implements(IFoo)
+ >>> directlyProvides(C, IFooFactory)
+ >>> [i.getName() for i in C.__providedBy__]
+ ['IFooFactory']
+ >>> [i.getName() for i in C().__providedBy__]
+ ['IFoo']
+
+ If classProvides is called outside of a class definition, it fails.
+
+ >>> classProvides(IFooFactory)
+ Traceback (most recent call last):
+ ...
+ TypeError: classProvides can be used only from a class definition.
+
+ """
+ frame = sys._getframe(1)
+ locals = frame.f_locals
+
+ # Try to make sure we were called from a class def
+ if (locals is frame.f_globals) or ('__module__' not in locals):
+ raise TypeError("classProvides can be used only from a class definition.")
+
+ if '__provides__' in locals:
+ raise TypeError(
+ "classProvides can only be used once in a class definition.")
+
+ locals["__provides__"] = _normalizeargs(interfaces)
+
+ addClassAdvisor(_classProvides_advice, depth=2)
+
+def _classProvides_advice(cls):
+ interfaces = cls.__dict__['__provides__']
+ del cls.__provides__
+ directlyProvides(cls, *interfaces)
+ return cls
+
+def moduleProvides(*interfaces):
+ """Declare interfaces provided by a module
+
+ This function is used in a module definition.
+
+ The arguments are one or more interfaces or interface specifications
+ (``IDeclaration`` objects).
+
+ The given interfaces (including the interfaces in the specifications) are
+ used to create the module's direct-object interface specification. An
+ error will be raised if the module already has an interface specification.
+ In other words, it is an error to call this function more than once in a
+ module definition.
+
+ This function is provided for convenience. It provides a more convenient
+ way to call directlyProvides. For example::
+
+ moduleImplements(I1)
+
+ is equivalent to::
+
+ directlyProvides(sys.modules[__name__], I1)
+ """
+ frame = sys._getframe(1)
+ locals = frame.f_locals
+
+ # Try to make sure we were called from a class def
+ if (locals is not frame.f_globals) or ('__name__' not in locals):
+ raise TypeError(
+ "moduleProvides can only be used from a module definition.")
+
+ if '__provides__' in locals:
+ raise TypeError(
+ "moduleProvides can only be used once in a module definition.")
+
+ locals["__provides__"] = Provides(ModuleType,
+ *_normalizeargs(interfaces))
+
+##############################################################################
+#
+# Declaration querying support
+
+def ObjectSpecification(direct, cls):
+ """Provide object specifications
+
+ These combine information for the object and for it's classes.
+
+ For example:
+
+ >>> from zope.interface import Interface
+ >>> class I1(Interface): pass
+ ...
+ >>> class I2(Interface): pass
+ ...
+ >>> class I3(Interface): pass
+ ...
+ >>> class I31(I3): pass
+ ...
+ >>> class I4(Interface): pass
+ ...
+ >>> class I5(Interface): pass
+ ...
+ >>> class A(object): implements(I1)
+ ...
+ >>> class B(object): __implemented__ = I2
+ ...
+ >>> class C(A, B): implements(I31)
+ ...
+ >>> c = C()
+ >>> directlyProvides(c, I4)
+ >>> [i.getName() for i in providedBy(c)]
+ ['I4', 'I31', 'I1', 'I2']
+ >>> [i.getName() for i in providedBy(c).flattened()]
+ ['I4', 'I31', 'I3', 'I1', 'I2', 'Interface']
+ >>> int(I1 in providedBy(c))
+ 1
+ >>> int(I3 in providedBy(c))
+ 0
+ >>> int(providedBy(c).extends(I3))
+ 1
+ >>> int(providedBy(c).extends(I31))
+ 1
+ >>> int(providedBy(c).extends(I5))
+ 0
+ >>> class COnly(A, B): implementsOnly(I31)
+ ...
+ >>> class D(COnly): implements(I5)
+ ...
+ >>> c = D()
+ >>> directlyProvides(c, I4)
+ >>> [i.getName() for i in providedBy(c)]
+ ['I4', 'I5', 'I31']
+ >>> [i.getName() for i in providedBy(c).flattened()]
+ ['I4', 'I5', 'I31', 'I3', 'Interface']
+ >>> int(I1 in providedBy(c))
+ 0
+ >>> int(I3 in providedBy(c))
+ 0
+ >>> int(providedBy(c).extends(I3))
+ 1
+ >>> int(providedBy(c).extends(I1))
+ 0
+ >>> int(providedBy(c).extends(I31))
+ 1
+ >>> int(providedBy(c).extends(I5))
+ 1
+ """
+
+ return Provides(cls, direct)
+
+def getObjectSpecification(ob):
+
+ provides = getattr(ob, '__provides__', None)
+ if provides is not None:
+ return provides
+
+ try:
+ cls = ob.__class__
+ except AttributeError:
+ # We can't get the class, so just consider provides
+ return _empty
+
+ return implementedBy(cls)
+
+def providedBy(ob):
+
+ # Here we have either a special object, an old-style declaration
+ # or a descriptor
+
+ # Try to get __providedBy__
+ try:
+ r = ob.__providedBy__
+ except AttributeError:
+ # Not set yet. Fall back to lower-level thing that computes it
+ return getObjectSpecification(ob)
+
+ try:
+ # We might have gotten a descriptor from an instance of a
+ # class (like an ExtensionClass) that doesn't support
+ # descriptors. We'll make sure we got one by trying to get
+ # the only attribute, which all specs have.
+ r.extends
+
+ except AttributeError:
+
+ # The object's class doesn't understand descriptors.
+ # Sigh. We need to get an object descriptor, but we have to be
+ # careful. We want to use the instance's __provides__, if
+ # there is one, but only if it didn't come from the class.
+
+ try:
+ r = ob.__provides__
+ except AttributeError:
+ # No __provides__, so just fall back to implementedBy
+ return implementedBy(ob.__class__)
+
+ # We need to make sure we got the __provides__ from the
+ # instance. We'll do this by making sure we don't get the same
+ # thing from the class:
+
+ try:
+ cp = ob.__class__.__provides__
+ except AttributeError:
+ # The ob doesn't have a class or the class has no
+ # provides, assume we're done:
+ return r
+
+ if r is cp:
+ # Oops, we got the provides from the class. This means
+ # the object doesn't have it's own. We should use implementedBy
+ return implementedBy(ob.__class__)
+
+ return r
+
+class ObjectSpecificationDescriptorPy(object):
+ """Implement the `__providedBy__` attribute
+
+ The `__providedBy__` attribute computes the interfaces peovided by
+ an object.
+ """
+
+ def __get__(self, inst, cls):
+ """Get an object specification for an object
+
+ For example:
+
+ >>> from zope.interface import Interface
+ >>> class IFoo(Interface): pass
+ ...
+ >>> class IFooFactory(Interface): pass
+ ...
+ >>> class C(object):
+ ... implements(IFoo)
+ ... classProvides(IFooFactory)
+ >>> [i.getName() for i in C.__providedBy__]
+ ['IFooFactory']
+ >>> [i.getName() for i in C().__providedBy__]
+ ['IFoo']
+
+ """
+
+ # Get an ObjectSpecification bound to either an instance or a class,
+ # depending on how we were accessed.
+
+ if inst is None:
+ return getObjectSpecification(cls)
+
+ provides = getattr(inst, '__provides__', None)
+ if provides is not None:
+ return provides
+
+ return implementedBy(cls)
+
+ObjectSpecificationDescriptor = ObjectSpecificationDescriptorPy
+
+##############################################################################
+
+def _normalizeargs(sequence, output = None):
+ """Normalize declaration arguments
+
+ Normalization arguments might contain Declarions, tuples, or single
+ interfaces.
+
+ Anything but individial interfaces or implements specs will be expanded.
+ """
+ if output is None:
+ output = []
+
+ cls = sequence.__class__
+ if InterfaceClass in cls.__mro__ or Implements in cls.__mro__:
+ output.append(sequence)
+ else:
+ for v in sequence:
+ _normalizeargs(v, output)
+
+ return output
+
+_empty = Declaration()
+
+try:
+ import _zope_interface_coptimizations
+except ImportError:
+ pass
+else:
+ from _zope_interface_coptimizations import implementedBy, providedBy
+ from _zope_interface_coptimizations import getObjectSpecification
+ from _zope_interface_coptimizations import ObjectSpecificationDescriptor
+
+objectSpecificationDescriptor = ObjectSpecificationDescriptor()
diff --git a/zope/interface/document.py b/zope/interface/document.py
new file mode 100644
index 0000000..282dadf
--- /dev/null
+++ b/zope/interface/document.py
@@ -0,0 +1,107 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+""" Pretty-Print an Interface object as structured text (Yum)
+
+This module provides a function, asStructuredText, for rendering an
+interface as structured text.
+
+$Id: document.py 39768 2005-10-31 13:57:35Z tlotze $
+"""
+import zope.interface
+
+def asStructuredText(I, munge=0):
+ """ Output structured text format. Note, this will whack any existing
+ 'structured' format of the text. """
+
+ r = [I.getName()]
+ outp = r.append
+ level = 1
+
+ if I.getDoc():
+ outp(_justify_and_indent(_trim_doc_string(I.getDoc()), level))
+
+ bases = [base
+ for base in I.__bases__
+ if base is not zope.interface.Interface
+ ]
+ if bases:
+ outp(_justify_and_indent("This interface extends:", level, munge))
+ level += 1
+ for b in bases:
+ item = "o %s" % b.getName()
+ outp(_justify_and_indent(_trim_doc_string(item), level, munge))
+ level -= 1
+
+ namesAndDescriptions = I.namesAndDescriptions()
+ namesAndDescriptions.sort()
+
+ outp(_justify_and_indent("Attributes:", level, munge))
+ level += 1
+ for name, desc in namesAndDescriptions:
+ if not hasattr(desc, 'getSignatureString'): # ugh...
+ item = "%s -- %s" % (desc.getName(),
+ desc.getDoc() or 'no documentation')
+ outp(_justify_and_indent(_trim_doc_string(item), level, munge))
+ level -= 1
+
+ outp(_justify_and_indent("Methods:", level, munge))
+ level += 1
+ for name, desc in namesAndDescriptions:
+ if hasattr(desc, 'getSignatureString'): # ugh...
+ item = "%s%s -- %s" % (desc.getName(),
+ desc.getSignatureString(),
+ desc.getDoc() or 'no documentation')
+ outp(_justify_and_indent(_trim_doc_string(item), level, munge))
+
+ return "\n\n".join(r) + "\n\n"
+
+
+def _trim_doc_string(text):
+ """ Trims a doc string to make it format
+ correctly with structured text. """
+
+ lines = text.replace('\r\n', '\n').split('\n')
+ nlines = [lines.pop(0)]
+ if lines:
+ min_indent = min([len(line) - len(line.lstrip())
+ for line in lines])
+ for line in lines:
+ nlines.append(line[min_indent:])
+
+ return '\n'.join(nlines)
+
+
+def _justify_and_indent(text, level, munge=0, width=72):
+ """ indent and justify text, rejustify (munge) if specified """
+
+ indent = " " * level
+
+ if munge:
+ lines = []
+ line = indent
+ text = text.split()
+
+ for word in text:
+ line = ' '.join([line, word])
+ if len(line) > width:
+ lines.append(line)
+ line = indent
+ else:
+ lines.append(line)
+
+ return '\n'.join(lines)
+
+ else:
+ return indent + \
+ text.strip().replace("\r\n", "\n") .replace("\n", "\n" + indent)
diff --git a/zope/interface/exceptions.py b/zope/interface/exceptions.py
new file mode 100644
index 0000000..c19171b
--- /dev/null
+++ b/zope/interface/exceptions.py
@@ -0,0 +1,69 @@
+##############################################################################
+#
+# Copyright (c) 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Interface-specific exceptions
+
+$Id: exceptions.py 67174 2006-04-20 14:11:55Z flindner $
+"""
+
+class Invalid(Exception):
+ """A specification is violated
+ """
+
+class DoesNotImplement(Invalid):
+ """ This object does not implement """
+ def __init__(self, interface):
+ self.interface = interface
+
+ def __str__(self):
+ return """An object does not implement interface %(interface)s
+
+ """ % self.__dict__
+
+class BrokenImplementation(Invalid):
+ """An attribute is not completely implemented.
+ """
+
+ def __init__(self, interface, name):
+ self.interface=interface
+ self.name=name
+
+ def __str__(self):
+ return """An object has failed to implement interface %(interface)s
+
+ The %(name)s attribute was not provided.
+ """ % self.__dict__
+
+class BrokenMethodImplementation(Invalid):
+ """An method is not completely implemented.
+ """
+
+ def __init__(self, method, mess):
+ self.method=method
+ self.mess=mess
+
+ def __str__(self):
+ return """The implementation of %(method)s violates its contract
+ because %(mess)s.
+ """ % self.__dict__
+
+class InvalidInterface(Exception):
+ """The interface has invalid contents
+ """
+
+class BadImplements(TypeError):
+ """An implementation assertion is invalid
+
+ because it doesn't contain an interface or a sequence of valid
+ implementation assertions.
+ """
diff --git a/zope/interface/interface.py b/zope/interface/interface.py
new file mode 100644
index 0000000..3eff8b6
--- /dev/null
+++ b/zope/interface/interface.py
@@ -0,0 +1,821 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Interface object implementation
+
+$Id: interface.py 67761 2006-04-30 13:56:44Z jim $
+"""
+
+from __future__ import generators
+
+import sys
+import warnings
+import weakref
+from types import FunctionType
+from ro import ro
+from zope.interface.exceptions import Invalid
+
+CO_VARARGS = 4
+CO_VARKEYWORDS = 8
+TAGGED_DATA = '__interface_tagged_values__'
+
+_decorator_non_return = object()
+
+def invariant(call):
+ f_locals = sys._getframe(1).f_locals
+ tags = f_locals.setdefault(TAGGED_DATA, {})
+ invariants = tags.setdefault('invariants', [])
+ invariants.append(call)
+ return _decorator_non_return
+
+class Element(object):
+
+ # We can't say this yet because we don't have enough
+ # infrastructure in place.
+ #
+ #implements(IElement)
+
+ def __init__(self, __name__, __doc__=''):
+ """Create an 'attribute' description
+ """
+ if not __doc__ and __name__.find(' ') >= 0:
+ __doc__ = __name__
+ __name__ = None
+
+ self.__name__=__name__
+ self.__doc__=__doc__
+ self.__tagged_values = {}
+
+ def getName(self):
+ """ Returns the name of the object. """
+ return self.__name__
+
+ def getDoc(self):
+ """ Returns the documentation for the object. """
+ return self.__doc__
+
+ def getTaggedValue(self, tag):
+ """ Returns the value associated with 'tag'. """
+ return self.__tagged_values[tag]
+
+ def queryTaggedValue(self, tag, default=None):
+ """ Returns the value associated with 'tag'. """
+ return self.__tagged_values.get(tag, default)
+
+ def getTaggedValueTags(self):
+ """ Returns a list of all tags. """
+ return self.__tagged_values.keys()
+
+ def setTaggedValue(self, tag, value):
+ """ Associates 'value' with 'key'. """
+ self.__tagged_values[tag] = value
+
+class SpecificationBasePy(object):
+
+ def providedBy(self, ob):
+ """Is the interface implemented by an object
+
+ >>> from zope.interface import *
+ >>> class I1(Interface):
+ ... pass
+ >>> class C(object):
+ ... implements(I1)
+ >>> c = C()
+ >>> class X(object):
+ ... pass
+ >>> x = X()
+ >>> I1.providedBy(x)
+ False
+ >>> I1.providedBy(C)
+ False
+ >>> I1.providedBy(c)
+ True
+ >>> directlyProvides(x, I1)
+ >>> I1.providedBy(x)
+ True
+ >>> directlyProvides(C, I1)
+ >>> I1.providedBy(C)
+ True
+
+ """
+ spec = providedBy(ob)
+ return self in spec._implied
+
+ def implementedBy(self, cls):
+ """Test whether the specification is implemented by a class or factory.
+ Raise TypeError if argument is neither a class nor a callable."""
+ spec = implementedBy(cls)
+ return self in spec._implied
+
+ def isOrExtends(self, interface):
+ """Is the interface the same as or extend the given interface
+
+ Examples::
+
+ >>> from zope.interface import Interface
+ >>> from zope.interface.declarations import Declaration
+ >>> class I1(Interface): pass
+ ...
+ >>> class I2(I1): pass
+ ...
+ >>> class I3(Interface): pass
+ ...
+ >>> class I4(I3): pass
+ ...
+ >>> spec = Declaration()
+ >>> int(spec.extends(Interface))
+ 1
+ >>> spec = Declaration(I2)
+ >>> int(spec.extends(Interface))
+ 1
+ >>> int(spec.extends(I1))
+ 1
+ >>> int(spec.extends(I2))
+ 1
+ >>> int(spec.extends(I3))
+ 0
+ >>> int(spec.extends(I4))
+ 0
+
+ """
+ return interface in self._implied
+
+ __call__ = isOrExtends
+
+SpecificationBase = SpecificationBasePy
+
+_marker = object()
+class InterfaceBasePy(object):
+ """Base class that wants to be replaced with a C base :)
+ """
+
+ def __call__(self, obj, alternate=_marker):
+ """Adapt an object to the interface
+ """
+ conform = getattr(obj, '__conform__', None)
+ if conform is not None:
+ adapter = self._call_conform(conform)
+ if adapter is not None:
+ return adapter
+
+ adapter = self.__adapt__(obj)
+
+ if adapter is not None:
+ return adapter
+ elif alternate is not _marker:
+ return alternate
+ else:
+ raise TypeError("Could not adapt", obj, self)
+
+ def __adapt__(self, obj):
+ """Adapt an object to the reciever
+ """
+ if self.providedBy(obj):
+ return obj
+
+ for hook in adapter_hooks:
+ adapter = hook(self, obj)
+ if adapter is not None:
+ return adapter
+
+InterfaceBase = InterfaceBasePy
+
+adapter_hooks = []
+
+try:
+ import _zope_interface_coptimizations
+except ImportError:
+ pass
+else:
+ from _zope_interface_coptimizations import SpecificationBase
+ from _zope_interface_coptimizations import InterfaceBase, adapter_hooks
+
+class Specification(SpecificationBase):
+ """Specifications
+
+ An interface specification is used to track interface declarations
+ and component registrations.
+
+ This class is a base class for both interfaces themselves and for
+ interface specifications (declarations).
+
+ Specifications are mutable. If you reassign their cases, their
+ relations with other specifications are adjusted accordingly.
+
+ For example:
+
+ >>> from zope.interface import Interface
+ >>> class I1(Interface):
+ ... pass
+ >>> class I2(I1):
+ ... pass
+ >>> class I3(I2):
+ ... pass
+
+ >>> [i.__name__ for i in I1.__bases__]
+ ['Interface']
+
+ >>> [i.__name__ for i in I2.__bases__]
+ ['I1']
+
+ >>> I3.extends(I1)
+ 1
+
+ >>> I2.__bases__ = (Interface, )
+
+ >>> [i.__name__ for i in I2.__bases__]
+ ['Interface']
+
+ >>> I3.extends(I1)
+ 0
+
+ """
+
+ # Copy some base class methods for speed
+ isOrExtends = SpecificationBase.isOrExtends
+ providedBy = SpecificationBase.providedBy
+
+ #########################################################################
+ # BBB 2004-07-13: Backward compatabilty. These methods have been
+ # deprecated in favour of providedBy and implementedBy.
+
+ def isImplementedByInstancesOf(self, cls):
+ warnings.warn(
+ "isImplementedByInstancesOf has been renamed to implementedBy",
+ DeprecationWarning, stacklevel=2,
+ )
+ return self.implementedBy(cls)
+
+ def isImplementedBy(self, ob):
+ warnings.warn(
+ "isImplementedBy has been renamed to providedBy",
+ DeprecationWarning, stacklevel=2,
+ )
+ return self.providedBy(ob)
+ #
+ #########################################################################
+
+ def __init__(self, bases=()):
+ self._implied = {}
+ self.dependents = weakref.WeakKeyDictionary()
+ self.__bases__ = tuple(bases)
+
+ def subscribe(self, dependent):
+ self.dependents[dependent] = self.dependents.get(dependent, 0) + 1
+
+ def unsubscribe(self, dependent):
+ n = self.dependents.get(dependent, 0) - 1
+ if not n:
+ del self.dependents[dependent]
+ elif n > 0:
+ self.dependents[dependent] = n
+ else:
+ raise KeyError(dependent)
+
+ def __setBases(self, bases):
+ # Register ourselves as a dependent of our old bases
+ for b in self.__bases__:
+ b.unsubscribe(self)
+
+ # Register ourselves as a dependent of our bases
+ self.__dict__['__bases__'] = bases
+ for b in bases:
+ b.subscribe(self)
+
+ self.changed(self)
+
+ __bases__ = property(
+
+ lambda self: self.__dict__.get('__bases__', ()),
+ __setBases,
+ )
+
+ def changed(self, originally_changed):
+ """We, or something we depend on, have changed
+ """
+
+ implied = self._implied
+ implied.clear()
+
+ ancestors = ro(self)
+
+ try:
+ if Interface not in ancestors:
+ ancestors.append(Interface)
+ except NameError:
+ pass # defining Interface itself
+
+ self.__sro__ = tuple(ancestors)
+ self.__iro__ = tuple([ancestor for ancestor in ancestors
+ if isinstance(ancestor, InterfaceClass)
+ ])
+
+ for ancestor in ancestors:
+ # We directly imply our ancestors:
+ implied[ancestor] = ()
+
+ # Now, advise our dependents of change:
+ for dependent in self.dependents.keys():
+ dependent.changed(originally_changed)
+
+
+ def interfaces(self):
+ """Return an iterator for the interfaces in the specification
+
+ for example::
+
+ >>> from zope.interface import Interface
+ >>> class I1(Interface): pass
+ ...
+ >>> class I2(I1): pass
+ ...
+ >>> class I3(Interface): pass
+ ...
+ >>> class I4(I3): pass
+ ...
+ >>> spec = Specification((I2, I3))
+ >>> spec = Specification((I4, spec))
+ >>> i = spec.interfaces()
+ >>> i.next().getName()
+ 'I4'
+ >>> i.next().getName()
+ 'I2'
+ >>> i.next().getName()
+ 'I3'
+ >>> list(i)
+ []
+ """
+ seen = {}
+ for base in self.__bases__:
+ for interface in base.interfaces():
+ if interface not in seen:
+ seen[interface] = 1
+ yield interface
+
+
+ def extends(self, interface, strict=True):
+ """Does the specification extend the given interface?
+
+ Test whether an interface in the specification extends the
+ given interface
+
+ Examples::
+
+ >>> from zope.interface import Interface
+ >>> from zope.interface.declarations import Declaration
+ >>> class I1(Interface): pass
+ ...
+ >>> class I2(I1): pass
+ ...
+ >>> class I3(Interface): pass
+ ...
+ >>> class I4(I3): pass
+ ...
+ >>> spec = Declaration()
+ >>> int(spec.extends(Interface))
+ 1
+ >>> spec = Declaration(I2)
+ >>> int(spec.extends(Interface))
+ 1
+ >>> int(spec.extends(I1))
+ 1
+ >>> int(spec.extends(I2))
+ 1
+ >>> int(spec.extends(I3))
+ 0
+ >>> int(spec.extends(I4))
+ 0
+ >>> I2.extends(I2)
+ 0
+ >>> I2.extends(I2, False)
+ 1
+ >>> I2.extends(I2, strict=False)
+ 1
+
+ """
+ return ((interface in self._implied)
+ and
+ ((not strict) or (self != interface))
+ )
+
+ def weakref(self, callback=None):
+ return weakref.ref(self, callback)
+
+ def get(self, name, default=None):
+ """Query for an attribute description
+ """
+ try:
+ attrs = self._v_attrs
+ except AttributeError:
+ attrs = self._v_attrs = {}
+ attr = attrs.get(name)
+ if attr is None:
+ for iface in self.__iro__:
+ attr = iface.direct(name)
+ if attr is not None:
+ attrs[name] = attr
+ break
+
+ if attr is None:
+ return default
+ else:
+ return attr
+
+class InterfaceClass(Element, InterfaceBase, Specification):
+ """Prototype (scarecrow) Interfaces Implementation."""
+
+ # We can't say this yet because we don't have enough
+ # infrastructure in place.
+ #
+ #implements(IInterface)
+
+ def __init__(self, name, bases=(), attrs=None, __doc__=None,
+ __module__=None):
+
+ if attrs is None:
+ attrs = {}
+
+ if __module__ is None:
+ __module__ = attrs.get('__module__')
+ if isinstance(__module__, str):
+ del attrs['__module__']
+ else:
+ try:
+ # Figure out what module defined the interface.
+ # This is how cPython figures out the module of
+ # a class, but of course it does it in C. :-/
+ __module__ = sys._getframe(1).f_globals['__name__']
+ except (AttributeError, KeyError):
+ pass
+
+ self.__module__ = __module__
+
+ d = attrs.get('__doc__')
+ if d is not None:
+ if not isinstance(d, Attribute):
+ if __doc__ is None:
+ __doc__ = d
+ del attrs['__doc__']
+
+ if __doc__ is None:
+ __doc__ = ''
+
+ Element.__init__(self, name, __doc__)
+
+ tagged_data = attrs.pop(TAGGED_DATA, None)
+ if tagged_data is not None:
+ for key, val in tagged_data.items():
+ self.setTaggedValue(key, val)
+
+ for base in bases:
+ if not isinstance(base, InterfaceClass):
+ raise TypeError('Expected base interfaces')
+
+ Specification.__init__(self, bases)
+
+ # Make sure that all recorded attributes (and methods) are of type
+ # `Attribute` and `Method`
+ for name, attr in attrs.items():
+ if isinstance(attr, Attribute):
+ attr.interface = self
+ if not attr.__name__:
+ attr.__name__ = name
+ elif isinstance(attr, FunctionType):
+ attrs[name] = fromFunction(attr, self, name=name)
+ elif attr is _decorator_non_return:
+ del attrs[name]
+ else:
+ raise InvalidInterface("Concrete attribute, " + name)
+
+ self.__attrs = attrs
+
+ self.__identifier__ = "%s.%s" % (self.__module__, self.__name__)
+
+ def interfaces(self):
+ """Return an iterator for the interfaces in the specification
+
+ for example::
+
+ >>> from zope.interface import Interface
+ >>> class I1(Interface): pass
+ ...
+ >>>
+ >>> i = I1.interfaces()
+ >>> i.next().getName()
+ 'I1'
+ >>> list(i)
+ []
+ """
+ yield self
+
+ def getBases(self):
+ return self.__bases__
+
+ def isEqualOrExtendedBy(self, other):
+ """Same interface or extends?"""
+ return self == other or other.extends(self)
+
+ def names(self, all=False):
+ """Return the attribute names defined by the interface."""
+ if not all:
+ return self.__attrs.keys()
+
+ r = self.__attrs.copy()
+
+ for base in self.__bases__:
+ r.update(dict.fromkeys(base.names(all)))
+
+ return r.keys()
+
+ def __iter__(self):
+ return iter(self.names(all=True))
+
+ def namesAndDescriptions(self, all=False):
+ """Return attribute names and descriptions defined by interface."""
+ if not all:
+ return self.__attrs.items()
+
+ r = {}
+ for base in self.__bases__[::-1]:
+ r.update(dict(base.namesAndDescriptions(all)))
+
+ r.update(self.__attrs)
+
+ return r.items()
+
+ def getDescriptionFor(self, name):
+ """Return the attribute description for the given name."""
+ r = self.get(name)
+ if r is not None:
+ return r
+
+ raise KeyError(name)
+
+ __getitem__ = getDescriptionFor
+
+ def __contains__(self, name):
+ return self.get(name) is not None
+
+ def direct(self, name):
+ return self.__attrs.get(name)
+
+ def queryDescriptionFor(self, name, default=None):
+ return self.get(name, default)
+
+ def deferred(self):
+ """Return a defered class corresponding to the interface."""
+ if hasattr(self, "_deferred"): return self._deferred
+
+ klass={}
+ exec "class %s: pass" % self.__name__ in klass
+ klass=klass[self.__name__]
+
+ self.__d(klass.__dict__)
+
+ self._deferred=klass
+
+ return klass
+
+ def validateInvariants(self, obj, errors=None):
+ """validate object to defined invariants."""
+ for call in self.queryTaggedValue('invariants', []):
+ try:
+ call(obj)
+ except Invalid, e:
+ if errors is None:
+ raise
+ else:
+ errors.append(e)
+ for base in self.__bases__:
+ try:
+ base.validateInvariants(obj, errors)
+ except Invalid:
+ if errors is None:
+ raise
+ if errors:
+ raise Invalid(errors)
+
+ def _getInterface(self, ob, name):
+ """Retrieve a named interface."""
+ return None
+
+ def __d(self, dict):
+
+ for k, v in self.__attrs.items():
+ if isinstance(v, Method) and not (k in dict):
+ dict[k]=v
+
+ for b in self.__bases__:
+ b.__d(dict)
+
+ def __repr__(self):
+ try:
+ return self._v_repr
+ except AttributeError:
+ name = self.__name__
+ m = self.__module__
+ if m:
+ name = '%s.%s' % (m, name)
+ r = "<%s %s>" % (self.__class__.__name__, name)
+ self._v_repr = r
+ return r
+
+ def _call_conform(self, conform):
+ try:
+ return conform(self)
+ except TypeError:
+ # We got a TypeError. It might be an error raised by
+ # the __conform__ implementation, or *we* may have
+ # made the TypeError by calling an unbound method
+ # (object is a class). In the later case, we behave
+ # as though there is no __conform__ method. We can
+ # detect this case by checking whether there is more
+ # than one traceback object in the traceback chain:
+ if sys.exc_info()[2].tb_next is not None:
+ # There is more than one entry in the chain, so
+ # reraise the error:
+ raise
+ # This clever trick is from Phillip Eby
+
+ return None
+
+ def __reduce__(self):
+ return self.__name__
+
+ def __cmp(self, o1, o2):
+ # Yes, I did mean to name this __cmp, rather than __cmp__.
+ # It is a private method used by __lt__ and __gt__.
+ # I don't want to override __eq__ because I want the default
+ # __eq__, which is really fast.
+ """Make interfaces sortable
+
+ TODO: It would ne nice if:
+
+ More specific interfaces should sort before less specific ones.
+ Otherwise, sort on name and module.
+
+ But this is too complicated, and we're going to punt on it
+ for now.
+
+ For now, sort on interface and module name.
+
+ None is treated as a pseudo interface that implies the loosest
+ contact possible, no contract. For that reason, all interfaces
+ sort before None.
+
+ """
+ if o1 == o2:
+ return 0
+
+ if o1 is None:
+ return 1
+ if o2 is None:
+ return -1
+
+ n1 = (getattr(o1, '__name__', ''),
+ getattr(getattr(o1, '__module__', None), '__name__', ''))
+ n2 = (getattr(o2, '__name__', ''),
+ getattr(getattr(o2, '__module__', None), '__name__', ''))
+
+ return cmp(n1, n2)
+
+ def __lt__(self, other):
+ c = self.__cmp(self, other)
+ #print '<', self, other, c < 0, c
+ return c < 0
+
+ def __gt__(self, other):
+ c = self.__cmp(self, other)
+ #print '>', self, other, c > 0, c
+ return c > 0
+
+
+Interface = InterfaceClass("Interface", __module__ = 'zope.interface')
+
+class Attribute(Element):
+ """Attribute descriptions
+ """
+
+ # We can't say this yet because we don't have enough
+ # infrastructure in place.
+ #
+ # implements(IAttribute)
+
+ interface = None
+
+
+class Method(Attribute):
+ """Method interfaces
+
+ The idea here is that you have objects that describe methods.
+ This provides an opportunity for rich meta-data.
+ """
+
+ # We can't say this yet because we don't have enough
+ # infrastructure in place.
+ #
+ # implements(IMethod)
+
+ def __call__(self, *args, **kw):
+ raise BrokenImplementation(self.interface, self.__name__)
+
+ def getSignatureInfo(self):
+ return {'positional': self.positional,
+ 'required': self.required,
+ 'optional': self.optional,
+ 'varargs': self.varargs,
+ 'kwargs': self.kwargs,
+ }
+
+ def getSignatureString(self):
+ sig = []
+ for v in self.positional:
+ sig.append(v)
+ if v in self.optional.keys():
+ sig[-1] += "=" + `self.optional[v]`
+ if self.varargs:
+ sig.append("*" + self.varargs)
+ if self.kwargs:
+ sig.append("**" + self.kwargs)
+
+ return "(%s)" % ", ".join(sig)
+
+
+def fromFunction(func, interface=None, imlevel=0, name=None):
+ name = name or func.__name__
+ method = Method(name, func.__doc__)
+ defaults = func.func_defaults or ()
+ code = func.func_code
+ # Number of positional arguments
+ na = code.co_argcount-imlevel
+ names = code.co_varnames[imlevel:]
+ opt = {}
+ # Number of required arguments
+ nr = na-len(defaults)
+ if nr < 0:
+ defaults=defaults[-nr:]
+ nr = 0
+
+ # Determine the optional arguments.
+ opt.update(dict(zip(names[nr:], defaults)))
+
+ method.positional = names[:na]
+ method.required = names[:nr]
+ method.optional = opt
+
+ argno = na
+
+ # Determine the function's variable argument's name (i.e. *args)
+ if code.co_flags & CO_VARARGS:
+ method.varargs = names[argno]
+ argno = argno + 1
+ else:
+ method.varargs = None
+
+ # Determine the function's keyword argument's name (i.e. **kw)
+ if code.co_flags & CO_VARKEYWORDS:
+ method.kwargs = names[argno]
+ else:
+ method.kwargs = None
+
+ method.interface = interface
+
+ for key, value in func.__dict__.items():
+ method.setTaggedValue(key, value)
+
+ return method
+
+
+def fromMethod(meth, interface=None, name=None):
+ func = meth.im_func
+ return fromFunction(func, interface, imlevel=1, name=name)
+
+
+# Now we can create the interesting interfaces and wire them up:
+def _wire():
+ from zope.interface.declarations import classImplements
+
+ from zope.interface.interfaces import IAttribute
+ classImplements(Attribute, IAttribute)
+
+ from zope.interface.interfaces import IMethod
+ classImplements(Method, IMethod)
+
+ from zope.interface.interfaces import IInterface, ISpecification
+ classImplements(InterfaceClass, IInterface)
+ classImplements(Specification, ISpecification)
+
+# We import this here to deal with module dependencies.
+from zope.interface.declarations import providedBy, implementedBy
+from zope.interface.exceptions import InvalidInterface
+from zope.interface.exceptions import BrokenImplementation
diff --git a/zope/interface/interfaces.py b/zope/interface/interfaces.py
new file mode 100644
index 0000000..6deac8c
--- /dev/null
+++ b/zope/interface/interfaces.py
@@ -0,0 +1,730 @@
+##############################################################################
+#
+# Copyright (c) 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Interface Package Interfaces
+
+$Id: interfaces.py 67803 2006-05-01 15:20:47Z jim $
+"""
+__docformat__ = 'restructuredtext'
+
+
+from zope.interface import Interface
+from zope.interface.interface import Attribute
+
+class IElement(Interface):
+ """Objects that have basic documentation and tagged values.
+ """
+
+ __name__ = Attribute('__name__', 'The object name')
+ __doc__ = Attribute('__doc__', 'The object doc string')
+
+ def getTaggedValue(tag):
+ """Returns the value associated with `tag`.
+
+ Raise a `KeyError` of the tag isn't set.
+ """
+
+ def queryTaggedValue(tag, default=None):
+ """Returns the value associated with `tag`.
+
+ Return the default value of the tag isn't set.
+ """
+
+ def getTaggedValueTags():
+ """Returns a list of all tags."""
+
+ def setTaggedValue(tag, value):
+ """Associates `value` with `key`."""
+
+
+class IAttribute(IElement):
+ """Attribute descriptors"""
+
+ interface = Attribute('interface',
+ 'Stores the interface instance in which the '
+ 'attribute is located.')
+
+
+class IMethod(IAttribute):
+ """Method attributes"""
+
+ def getSignatureInfo():
+ """Returns the signature information.
+
+ This method returns a dictionary with the following keys:
+
+ o `positional` - All positional arguments.
+
+ o `required` - A list of all required arguments.
+
+ o `optional` - A list of all optional arguments.
+
+ o `varargs` - The name of the varargs argument.
+
+ o `kwargs` - The name of the kwargs argument.
+ """
+
+ def getSignatureString():
+ """Return a signature string suitable for inclusion in documentation.
+
+ This method returns the function signature string. For example, if you
+ have `func(a, b, c=1, d='f')`, then the signature string is `(a, b,
+ c=1, d='f')`.
+ """
+
+class ISpecification(Interface):
+ """Object Behavioral specifications"""
+
+ def extends(other, strict=True):
+ """Test whether a specification extends another
+
+ The specification extends other if it has other as a base
+ interface or if one of it's bases extends other.
+
+ If strict is false, then the specification extends itself.
+ """
+
+ def isOrExtends(other):
+ """Test whether the specification is or extends another
+ """
+
+ def weakref(callback=None):
+ """Return a weakref to the specification
+
+ This method is, regrettably, needed to allow weakrefs to be
+ computed to security-proxied specifications. While the
+ zope.interface package does not require zope.security or
+ zope.proxy, it has to be able to coexist with it.
+
+ """
+
+ __bases__ = Attribute("""Base specifications
+
+ A tuple if specifications from which this specification is
+ directly derived.
+
+ """)
+
+ __sro__ = Attribute("""Specification-resolution order
+
+ A tuple of the specification and all of it's ancestor
+ specifications from most specific to least specific.
+
+ (This is similar to the method-resolution order for new-style classes.)
+ """)
+
+ def get(name, default=None):
+ """Look up the description for a name
+
+ If the named attribute is not defined, the default is
+ returned.
+ """
+
+
+class IInterface(ISpecification, IElement):
+ """Interface objects
+
+ Interface objects describe the behavior of an object by containing
+ useful information about the object. This information includes:
+
+ o Prose documentation about the object. In Python terms, this
+ is called the "doc string" of the interface. In this element,
+ you describe how the object works in prose language and any
+ other useful information about the object.
+
+ o Descriptions of attributes. Attribute descriptions include
+ the name of the attribute and prose documentation describing
+ the attributes usage.
+
+ o Descriptions of methods. Method descriptions can include:
+
+ - Prose "doc string" documentation about the method and its
+ usage.
+
+ - A description of the methods arguments; how many arguments
+ are expected, optional arguments and their default values,
+ the position or arguments in the signature, whether the
+ method accepts arbitrary arguments and whether the method
+ accepts arbitrary keyword arguments.
+
+ o Optional tagged data. Interface objects (and their attributes and
+ methods) can have optional, application specific tagged data
+ associated with them. Examples uses for this are examples,
+ security assertions, pre/post conditions, and other possible
+ information you may want to associate with an Interface or its
+ attributes.
+
+ Not all of this information is mandatory. For example, you may
+ only want the methods of your interface to have prose
+ documentation and not describe the arguments of the method in
+ exact detail. Interface objects are flexible and let you give or
+ take any of these components.
+
+ Interfaces are created with the Python class statement using
+ either Interface.Interface or another interface, as in::
+
+ from zope.interface import Interface
+
+ class IMyInterface(Interface):
+ '''Interface documentation'''
+
+ def meth(arg1, arg2):
+ '''Documentation for meth'''
+
+ # Note that there is no self argument
+
+ class IMySubInterface(IMyInterface):
+ '''Interface documentation'''
+
+ def meth2():
+ '''Documentation for meth2'''
+
+ You use interfaces in two ways:
+
+ o You assert that your object implement the interfaces.
+
+ There are several ways that you can assert that an object
+ implements an interface:
+
+ 1. Call zope.interface.implements in your class definition.
+
+ 2. Call zope.interfaces.directlyProvides on your object.
+
+ 3. Call 'zope.interface.classImplements' to assert that instances
+ of a class implement an interface.
+
+ For example::
+
+ from zope.interface import classImplements
+
+ classImplements(some_class, some_interface)
+
+ This approach is useful when it is not an option to modify
+ the class source. Note that this doesn't affect what the
+ class itself implements, but only what its instances
+ implement.
+
+ o You query interface meta-data. See the IInterface methods and
+ attributes for details.
+
+ """
+
+ def providedBy(object):
+ """Test whether the interface is implemented by the object
+
+ Return true of the object asserts that it implements the
+ interface, including asserting that it implements an extended
+ interface.
+ """
+
+ def implementedBy(class_):
+ """Test whether the interface is implemented by instances of the class
+
+ Return true of the class asserts that its instances implement the
+ interface, including asserting that they implement an extended
+ interface.
+ """
+
+ def names(all=False):
+ """Get the interface attribute names
+
+ Return a sequence of the names of the attributes, including
+ methods, included in the interface definition.
+
+ Normally, only directly defined attributes are included. If
+ a true positional or keyword argument is given, then
+ attributes defined by base classes will be included.
+ """
+
+ def namesAndDescriptions(all=False):
+ """Get the interface attribute names and descriptions
+
+ Return a sequence of the names and descriptions of the
+ attributes, including methods, as name-value pairs, included
+ in the interface definition.
+
+ Normally, only directly defined attributes are included. If
+ a true positional or keyword argument is given, then
+ attributes defined by base classes will be included.
+ """
+
+ def __getitem__(name):
+ """Get the description for a name
+
+ If the named attribute is not defined, a KeyError is raised.
+ """
+
+ def direct(name):
+ """Get the description for the name if it was defined by the interface
+
+ If the interface doesn't define the name, returns None.
+ """
+
+ def validateInvariants(obj, errors=None):
+ """Validate invariants
+
+ Validate object to defined invariants. If errors is None,
+ raises first Invalid error; if errors is a list, appends all errors
+ to list, then raises Invalid with the errors as the first element
+ of the "args" tuple."""
+
+ def __contains__(name):
+ """Test whether the name is defined by the interface"""
+
+ def __iter__():
+ """Return an iterator over the names defined by the interface
+
+ The names iterated include all of the names defined by the
+ interface directly and indirectly by base interfaces.
+ """
+
+ __module__ = Attribute("""The name of the module defining the interface""")
+
+class IDeclaration(ISpecification):
+ """Interface declaration
+
+ Declarations are used to express the interfaces implemented by
+ classes or provided by objects.
+ """
+
+ def __contains__(interface):
+ """Test whether an interface is in the specification
+
+ Return true if the given interface is one of the interfaces in
+ the specification and false otherwise.
+ """
+
+ def __iter__():
+ """Return an iterator for the interfaces in the specification
+ """
+
+ def flattened():
+ """Return an iterator of all included and extended interfaces
+
+ An iterator is returned for all interfaces either included in
+ or extended by interfaces included in the specifications
+ without duplicates. The interfaces are in "interface
+ resolution order". The interface resolution order is such that
+ base interfaces are listed after interfaces that extend them
+ and, otherwise, interfaces are included in the order that they
+ were defined in the specification.
+ """
+
+ def __sub__(interfaces):
+ """Create an interface specification with some interfaces excluded
+
+ The argument can be an interface or an interface
+ specifications. The interface or interfaces given in a
+ specification are subtracted from the interface specification.
+
+ Removing an interface that is not in the specification does
+ not raise an error. Doing so has no effect.
+
+ Removing an interface also removes sub-interfaces of the interface.
+
+ """
+
+ def __add__(interfaces):
+ """Create an interface specification with some interfaces added
+
+ The argument can be an interface or an interface
+ specifications. The interface or interfaces given in a
+ specification are added to the interface specification.
+
+ Adding an interface that is already in the specification does
+ not raise an error. Doing so has no effect.
+ """
+
+ def __nonzero__():
+ """Return a true value of the interface specification is non-empty
+ """
+
+class IInterfaceDeclaration(Interface):
+ """Declare and check the interfaces of objects
+
+ The functions defined in this interface are used to declare the
+ interfaces that objects provide and to query the interfaces that have
+ been declared.
+
+ Interfaces can be declared for objects in two ways:
+
+ - Interfaces are declared for instances of the object's class
+
+ - Interfaces are declared for the object directly.
+
+ The interfaces declared for an object are, therefore, the union of
+ interfaces declared for the object directly and the interfaces
+ declared for instances of the object's class.
+
+ Note that we say that a class implements the interfaces provided
+ by it's instances. An instance can also provide interfaces
+ directly. The interfaces provided by an object are the union of
+ the interfaces provided directly and the interfaces implemented by
+ the class.
+ """
+
+ def providedBy(ob):
+ """Return the interfaces provided by an object
+
+ This is the union of the interfaces directly provided by an
+ object and interfaces implemented by it's class.
+
+ The value returned is an IDeclaration.
+ """
+
+ def implementedBy(class_):
+ """Return the interfaces implemented for a class' instances
+
+ The value returned is an IDeclaration.
+ """
+
+ def classImplements(class_, *interfaces):
+ """Declare additional interfaces implemented for instances of a class
+
+ The arguments after the class are one or more interfaces or
+ interface specifications (IDeclaration objects).
+
+ The interfaces given (including the interfaces in the
+ specifications) are added to any interfaces previously
+ declared.
+
+ Consider the following example::
+
+ class C(A, B):
+ ...
+
+ classImplements(C, I1, I2)
+
+
+ Instances of ``C`` provide ``I1``, ``I2``, and whatever interfaces
+ instances of ``A`` and ``B`` provide.
+ """
+
+ def implementer(*interfaces):
+ """Create a decorator for declaring interfaces implemented by a facory
+
+ A callable is returned that makes an implements declaration on
+ objects passed to it.
+ """
+
+ def classImplementsOnly(class_, *interfaces):
+ """Declare the only interfaces implemented by instances of a class
+
+ The arguments after the class are one or more interfaces or
+ interface specifications (IDeclaration objects).
+
+ The interfaces given (including the interfaces in the
+ specifications) replace any previous declarations.
+
+ Consider the following example::
+
+ class C(A, B):
+ ...
+
+ classImplements(C, IA, IB. IC)
+ classImplementsOnly(C. I1, I2)
+
+ Instances of ``C`` provide only ``I1``, ``I2``, and regardless of
+ whatever interfaces instances of ``A`` and ``B`` implement.
+ """
+
+ def directlyProvidedBy(object):
+ """Return the interfaces directly provided by the given object
+
+ The value returned is an IDeclaration.
+ """
+
+ def directlyProvides(object, *interfaces):
+ """Declare interfaces declared directly for an object
+
+ The arguments after the object are one or more interfaces or
+ interface specifications (IDeclaration objects).
+
+ The interfaces given (including the interfaces in the
+ specifications) replace interfaces previously
+ declared for the object.
+
+ Consider the following example::
+
+ class C(A, B):
+ ...
+
+ ob = C()
+ directlyProvides(ob, I1, I2)
+
+ The object, ``ob`` provides ``I1``, ``I2``, and whatever interfaces
+ instances have been declared for instances of ``C``.
+
+ To remove directly provided interfaces, use ``directlyProvidedBy`` and
+ subtract the unwanted interfaces. For example::
+
+ directlyProvides(ob, directlyProvidedBy(ob)-I2)
+
+ removes I2 from the interfaces directly provided by
+ ``ob``. The object, ``ob`` no longer directly provides ``I2``,
+ although it might still provide ``I2`` if it's class
+ implements ``I2``.
+
+ To add directly provided interfaces, use ``directlyProvidedBy`` and
+ include additional interfaces. For example::
+
+ directlyProvides(ob, directlyProvidedBy(ob), I2)
+
+ adds I2 to the interfaces directly provided by ob.
+ """
+
+ def alsoProvides(object, *interfaces):
+ """Declare additional interfaces directly for an object::
+
+ alsoProvides(ob, I1)
+
+ is equivalent to::
+
+ directivelyProvides(ob, directlyProvidedBy(ob), I1)
+ """
+
+ def noLongerProvides(object, interface):
+ """Remove an interface from the list of an object's directly
+ provided interfaces::
+
+ noLongerProvides(ob, I1)
+
+ is equivalent to::
+
+ directlyProvides(ob, directlyProvidedBy(ob)-I1)
+
+ with the exception that if ``I1`` is an interface that is
+ provided by ``ob`` through the class's implementation,
+ ValueError is raised.
+ """
+
+ def implements(*interfaces):
+ """Declare interfaces implemented by instances of a class
+
+ This function is called in a class definition.
+
+ The arguments are one or more interfaces or interface
+ specifications (IDeclaration objects).
+
+ The interfaces given (including the interfaces in the
+ specifications) are added to any interfaces previously
+ declared.
+
+ Previous declarations include declarations for base classes
+ unless implementsOnly was used.
+
+ This function is provided for convenience. It provides a more
+ convenient way to call classImplements. For example::
+
+ implements(I1)
+
+ is equivalent to calling::
+
+ classImplements(C, I1)
+
+ after the class has been created.
+
+ Consider the following example::
+
+ class C(A, B):
+ implements(I1, I2)
+
+
+ Instances of ``C`` implement ``I1``, ``I2``, and whatever interfaces
+ instances of ``A`` and ``B`` implement.
+ """
+
+ def implementsOnly(*interfaces):
+ """Declare the only interfaces implemented by instances of a class
+
+ This function is called in a class definition.
+
+ The arguments are one or more interfaces or interface
+ specifications (IDeclaration objects).
+
+ Previous declarations including declarations for base classes
+ are overridden.
+
+ This function is provided for convenience. It provides a more
+ convenient way to call classImplementsOnly. For example::
+
+ implementsOnly(I1)
+
+ is equivalent to calling::
+
+ classImplementsOnly(I1)
+
+ after the class has been created.
+
+ Consider the following example::
+
+ class C(A, B):
+ implementsOnly(I1, I2)
+
+
+ Instances of ``C`` implement ``I1``, ``I2``, regardless of what
+ instances of ``A`` and ``B`` implement.
+ """
+
+ def classProvides(*interfaces):
+ """Declare interfaces provided directly by a class
+
+ This function is called in a class definition.
+
+ The arguments are one or more interfaces or interface
+ specifications (IDeclaration objects).
+
+ The given interfaces (including the interfaces in the
+ specifications) are used to create the class's direct-object
+ interface specification. An error will be raised if the module
+ class has an direct interface specification. In other words, it is
+ an error to call this function more than once in a class
+ definition.
+
+ Note that the given interfaces have nothing to do with the
+ interfaces implemented by instances of the class.
+
+ This function is provided for convenience. It provides a more
+ convenient way to call directlyProvides for a class. For example::
+
+ classProvides(I1)
+
+ is equivalent to calling::
+
+ directlyProvides(theclass, I1)
+
+ after the class has been created.
+ """
+
+ def moduleProvides(*interfaces):
+ """Declare interfaces provided by a module
+
+ This function is used in a module definition.
+
+ The arguments are one or more interfaces or interface
+ specifications (IDeclaration objects).
+
+ The given interfaces (including the interfaces in the
+ specifications) are used to create the module's direct-object
+ interface specification. An error will be raised if the module
+ already has an interface specification. In other words, it is
+ an error to call this function more than once in a module
+ definition.
+
+ This function is provided for convenience. It provides a more
+ convenient way to call directlyProvides for a module. For example::
+
+ moduleImplements(I1)
+
+ is equivalent to::
+
+ directlyProvides(sys.modules[__name__], I1)
+ """
+
+ def Declaration(*interfaces):
+ """Create an interface specification
+
+ The arguments are one or more interfaces or interface
+ specifications (IDeclaration objects).
+
+ A new interface specification (IDeclaration) with
+ the given interfaces is returned.
+ """
+
+class IAdapterRegistry(Interface):
+ """Provide an interface-based registry for adapters
+
+ This registry registers objects that are in some sense "from" a
+ sequence of specification to an interface and a name.
+
+ No specific semantics are assumed for the registered objects,
+ however, the most common application will be to register factories
+ that adapt objects providing required specifications to a provided
+ interface.
+ """
+
+ def register(required, provided, name, value):
+ """Register a value
+
+ A value is registered for a *sequence* of required specifications, a
+ provided interface, and a name.
+ """
+
+ def registered(required, provided, name=u''):
+ """Return the component registered for the given interfaces and name
+
+ Unlike the lookup method, this methods won't retrieve
+ components registered for more specific required interfaces or
+ less specific provided interfaces.
+
+ If no component was registered exactly for the given
+ interfaces and name, then None is returned.
+
+ """
+
+ def lookup(required, provided, name='', default=None):
+ """Lookup a value
+
+ A value is looked up based on a *sequence* of required
+ specifications, a provided interface, and a name.
+ """
+
+ def queryMultiAdapter(objects, provided, name=u'', default=None):
+ """Adapt a sequence of objects to a named, provided, interface
+ """
+
+ def lookup1(required, provided, name=u'', default=None):
+ """Lookup a value using a single required interface
+
+ A value is looked up based on a single required
+ specifications, a provided interface, and a name.
+ """
+
+ def queryAdapter(object, provided, name=u'', default=None):
+ """Adapt an object using a registered adapter factory.
+ """
+
+ def adapter_hook(provided, object, name=u'', default=None):
+ """Adapt an object using a registered adapter factory.
+ """
+
+ def lookupAll(required, provided):
+ """Find all adapters from the required to the provided interfaces
+
+ An iterable object is returned that provides name-value two-tuples.
+ """
+
+ def names(required, provided):
+ """Return the names for which there are registered objects
+ """
+
+ def subscribe(required, provided, subscriber, name=u''):
+ """Register a subscriber
+
+ A subscriber is registered for a *sequence* of required
+ specifications, a provided interface, and a name.
+
+ Multiple subscribers may be registered for the same (or
+ equivalent) interfaces.
+ """
+
+ def subscriptions(required, provided, name=u''):
+ """Get a sequence of subscribers
+
+ Subscribers for a *sequence* of required interfaces, and a provided
+ interface are returned.
+ """
+
+ def subscribers(objects, provided, name=u''):
+ """Get a sequence of subscription adapters
+ """
diff --git a/zope/interface/ro.py b/zope/interface/ro.py
new file mode 100644
index 0000000..e8e6115
--- /dev/null
+++ b/zope/interface/ro.py
@@ -0,0 +1,63 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Compute a resolution order for an object and it's bases
+
+$Id: ro.py 25177 2004-06-02 13:17:31Z jim $
+"""
+
+def ro(object):
+ """Compute a "resolution order" for an object
+ """
+ return mergeOrderings([_flatten(object, [])])
+
+def mergeOrderings(orderings, seen=None):
+ """Merge multiple orderings so that within-ordering order is preserved
+
+ Orderings are constrained in such a way that if an object appears
+ in two or more orderings, then the suffix that begins with the
+ object must be in both orderings.
+
+ For example:
+
+ >>> _mergeOrderings([
+ ... ['x', 'y', 'z'],
+ ... ['q', 'z'],
+ ... [1, 3, 5],
+ ... ['z']
+ ... ])
+ ['x', 'y', 'q', 1, 3, 5, 'z']
+
+ """
+
+ if seen is None:
+ seen = {}
+ result = []
+ orderings.reverse()
+ for ordering in orderings:
+ ordering = list(ordering)
+ ordering.reverse()
+ for o in ordering:
+ if o not in seen:
+ seen[o] = 1
+ result.append(o)
+
+ result.reverse()
+ return result
+
+def _flatten(ob, result):
+ result.append(ob)
+ for base in ob.__bases__:
+ _flatten(base, result)
+
+ return result
diff --git a/zope/interface/tests/__init__.py b/zope/interface/tests/__init__.py
new file mode 100644
index 0000000..b711d36
--- /dev/null
+++ b/zope/interface/tests/__init__.py
@@ -0,0 +1,2 @@
+#
+# This file is necessary to make this directory a package.
diff --git a/zope/interface/tests/dummy.py b/zope/interface/tests/dummy.py
new file mode 100644
index 0000000..f4a4f9d
--- /dev/null
+++ b/zope/interface/tests/dummy.py
@@ -0,0 +1,25 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Dummy Module
+
+$Id$
+"""
+from zope.interface import moduleProvides
+from zope.interface.tests.ifoo import IFoo
+from zope.interface import moduleProvides
+
+moduleProvides(IFoo)
+
+def bar(baz):
+ pass
diff --git a/zope/interface/tests/ifoo.py b/zope/interface/tests/ifoo.py
new file mode 100644
index 0000000..6ae2231
--- /dev/null
+++ b/zope/interface/tests/ifoo.py
@@ -0,0 +1,28 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""IFoo test module
+
+$Id$
+"""
+from zope.interface import Interface
+
+class IFoo(Interface):
+ """
+ Dummy interface for unit tests.
+ """
+
+ def bar(baz):
+ """
+ Just a note.
+ """
diff --git a/zope/interface/tests/m1.py b/zope/interface/tests/m1.py
new file mode 100644
index 0000000..86adad2
--- /dev/null
+++ b/zope/interface/tests/m1.py
@@ -0,0 +1,23 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Test module that declares an interface
+
+$Id$
+"""
+from zope.interface import Interface, moduleProvides
+
+class I1(Interface): pass
+class I2(Interface): pass
+
+moduleProvides(I1, I2)
diff --git a/zope/interface/tests/m2.py b/zope/interface/tests/m2.py
new file mode 100644
index 0000000..16762dd
--- /dev/null
+++ b/zope/interface/tests/m2.py
@@ -0,0 +1,17 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Test module that doesn't declare an interface
+
+$Id$
+"""
diff --git a/zope/interface/tests/odd.py b/zope/interface/tests/odd.py
new file mode 100644
index 0000000..7e31f30
--- /dev/null
+++ b/zope/interface/tests/odd.py
@@ -0,0 +1,129 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Odd meta class that doesn't subclass type.
+
+This is used for testing support for ExtensionClass in new interfaces.
+
+ >>> class A(object):
+ ... __metaclass__ = MetaClass
+ ... a = 1
+ ...
+ >>> A.__name__
+ 'A'
+ >>> A.__bases__
+ ()
+ >>> class B(object):
+ ... __metaclass__ = MetaClass
+ ... b = 1
+ ...
+ >>> class C(A, B): pass
+ ...
+ >>> C.__name__
+ 'C'
+ >>> int(C.__bases__ == (A, B))
+ 1
+ >>> a = A()
+ >>> aa = A()
+ >>> a.a
+ 1
+ >>> aa.a
+ 1
+ >>> aa.a = 2
+ >>> a.a
+ 1
+ >>> aa.a
+ 2
+ >>> c = C()
+ >>> c.a
+ 1
+ >>> c.b
+ 1
+ >>> c.b = 2
+ >>> c.b
+ 2
+ >>> C.c = 1
+ >>> c.c
+ 1
+ >>> from types import ClassType
+ >>> int(isinstance(C, (type, ClassType)))
+ 0
+ >>> int(C.__class__.__class__ is C.__class__)
+ 1
+
+$Id: odd.py 38178 2005-08-30 21:50:19Z mj $
+"""
+
+# class OddClass is an odd meta class
+
+class MetaMetaClass(type):
+
+ def __getattribute__(self, name):
+ if name == '__class__':
+ return self
+ return type.__getattribute__(self, name)
+
+
+class MetaClass(object):
+ """Odd classes
+ """
+ __metaclass__ = MetaMetaClass
+
+ def __init__(self, name, bases, dict):
+ self.__name__ = name
+ self.__bases__ = bases
+ self.__dict__.update(dict)
+
+ def __call__(self):
+ return OddInstance(self)
+
+ def __getattr__(self, name):
+ for b in self.__bases__:
+ v = getattr(b, name, self)
+ if v is not self:
+ return v
+ raise AttributeError(name)
+
+ def __repr__(self):
+ return "<odd class %s at %s>" % (self.__name__, hex(id(self)))
+
+class OddInstance(object):
+
+ def __init__(self, cls):
+ self.__dict__['__class__'] = cls
+
+ def __getattribute__(self, name):
+ dict = object.__getattribute__(self, '__dict__')
+ if name == '__dict__':
+ return dict
+ v = dict.get(name, self)
+ if v is not self:
+ return v
+ return getattr(dict['__class__'], name)
+
+ def __setattr__(self, name, v):
+ self.__dict__[name] = v
+
+ def __delattr__(self, name):
+ del self.__dict__[name]
+
+ def __repr__(self):
+ return "<odd %s instance at %s>" % (
+ self.__class__.__name__, hex(id(self)))
+
+
+
+# DocTest:
+if __name__ == "__main__":
+ import doctest, __main__
+ doctest.testmod(__main__, isprivate=lambda *a: False)
diff --git a/zope/interface/tests/test_adapter.py b/zope/interface/tests/test_adapter.py
new file mode 100644
index 0000000..a8d1d94
--- /dev/null
+++ b/zope/interface/tests/test_adapter.py
@@ -0,0 +1,335 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Adapter registry tests
+
+$Id: test_adapter.py 67795 2006-05-01 13:55:42Z jim $
+"""
+import unittest
+import zope.interface
+from zope.interface.adapter import AdapterRegistry
+import zope.interface
+
+
+class IF0(zope.interface.Interface):
+ pass
+class IF1(IF0):
+ pass
+
+class IB0(zope.interface.Interface):
+ pass
+class IB1(IB0):
+ pass
+
+class IR0(zope.interface.Interface):
+ pass
+class IR1(IR0):
+ pass
+
+def test_multi_adapter_get_best_match():
+ """
+ >>> registry = AdapterRegistry()
+
+ >>> class IB2(IB0):
+ ... pass
+ >>> class IB3(IB2, IB1):
+ ... pass
+ >>> class IB4(IB1, IB2):
+ ... pass
+
+ >>> registry.register([None, IB1], IR0, '', 'A1')
+ >>> registry.register([None, IB0], IR0, '', 'A0')
+ >>> registry.register([None, IB2], IR0, '', 'A2')
+
+ >>> registry.lookup((IF1, IB1), IR0, '')
+ 'A1'
+ >>> registry.lookup((IF1, IB2), IR0, '')
+ 'A2'
+ >>> registry.lookup((IF1, IB0), IR0, '')
+ 'A0'
+ >>> registry.lookup((IF1, IB3), IR0, '')
+ 'A2'
+ >>> registry.lookup((IF1, IB4), IR0, '')
+ 'A1'
+ """
+
+def test_multi_adapter_lookupAll_get_best_matches():
+ """
+ >>> registry = AdapterRegistry()
+
+ >>> class IB2(IB0):
+ ... pass
+ >>> class IB3(IB2, IB1):
+ ... pass
+ >>> class IB4(IB1, IB2):
+ ... pass
+
+ >>> registry.register([None, IB1], IR0, '', 'A1')
+ >>> registry.register([None, IB0], IR0, '', 'A0')
+ >>> registry.register([None, IB2], IR0, '', 'A2')
+
+ >>> tuple(registry.lookupAll((IF1, IB1), IR0))[0][1]
+ 'A1'
+ >>> tuple(registry.lookupAll((IF1, IB2), IR0))[0][1]
+ 'A2'
+ >>> tuple(registry.lookupAll((IF1, IB0), IR0))[0][1]
+ 'A0'
+ >>> tuple(registry.lookupAll((IF1, IB3), IR0))[0][1]
+ 'A2'
+ >>> tuple(registry.lookupAll((IF1, IB4), IR0))[0][1]
+ 'A1'
+ """
+
+
+def test_multi_adapter_w_default():
+ """
+ >>> registry = AdapterRegistry()
+
+ >>> registry.register([None, None], IB1, 'bob', 'A0')
+
+ >>> registry.lookup((IF1, IR1), IB0, 'bob')
+ 'A0'
+
+ >>> registry.register([None, IR0], IB1, 'bob', 'A1')
+
+ >>> registry.lookup((IF1, IR1), IB0, 'bob')
+ 'A1'
+
+ >>> registry.lookup((IF1, IR1), IB0, 'bruce')
+
+ >>> registry.register([None, IR1], IB1, 'bob', 'A2')
+ >>> registry.lookup((IF1, IR1), IB0, 'bob')
+ 'A2'
+ """
+
+def test_multi_adapter_w_inherited_and_multiple_registrations():
+ """
+ >>> registry = AdapterRegistry()
+
+ >>> class IX(zope.interface.Interface):
+ ... pass
+
+ >>> registry.register([IF0, IR0], IB1, 'bob', 'A1')
+ >>> registry.register([IF1, IX], IB1, 'bob', 'AX')
+
+ >>> registry.lookup((IF1, IR1), IB0, 'bob')
+ 'A1'
+ """
+
+def test_named_adapter_with_default():
+ """Query a named simple adapter
+
+ >>> registry = AdapterRegistry()
+
+ If we ask for a named adapter, we won't get a result unless there
+ is a named adapter, even if the object implements the interface:
+
+ >>> registry.lookup([IF1], IF0, 'bob')
+
+ >>> registry.register([None], IB1, 'bob', 'A1')
+ >>> registry.lookup([IF1], IB0, 'bob')
+ 'A1'
+
+ >>> registry.lookup([IF1], IB0, 'bruce')
+
+ >>> registry.register([None], IB0, 'bob', 'A2')
+ >>> registry.lookup([IF1], IB0, 'bob')
+ 'A2'
+ """
+
+def test_multi_adapter_gets_closest_provided():
+ """
+ >>> registry = AdapterRegistry()
+ >>> registry.register([IF1, IR0], IB0, 'bob', 'A1')
+ >>> registry.register((IF1, IR0), IB1, 'bob', 'A2')
+ >>> registry.lookup((IF1, IR1), IB0, 'bob')
+ 'A1'
+
+ >>> registry = AdapterRegistry()
+ >>> registry.register([IF1, IR0], IB1, 'bob', 'A2')
+ >>> registry.register([IF1, IR0], IB0, 'bob', 'A1')
+ >>> registry.lookup([IF1, IR0], IB0, 'bob')
+ 'A1'
+
+ >>> registry = AdapterRegistry()
+ >>> registry.register([IF1, IR0], IB0, 'bob', 'A1')
+ >>> registry.register([IF1, IR1], IB1, 'bob', 'A2')
+ >>> registry.lookup([IF1, IR1], IB0, 'bob')
+ 'A2'
+
+ >>> registry = AdapterRegistry()
+ >>> registry.register([IF1, IR1], IB1, 'bob', 2)
+ >>> registry.register([IF1, IR0], IB0, 'bob', 1)
+ >>> registry.lookup([IF1, IR1], IB0, 'bob')
+ 2
+ """
+
+def test_multi_adapter_check_non_default_dont_hide_default():
+ """
+ >>> registry = AdapterRegistry()
+
+ >>> class IX(zope.interface.Interface):
+ ... pass
+
+
+ >>> registry.register([None, IR0], IB0, 'bob', 1)
+ >>> registry.register([IF1, IX], IB0, 'bob', 2)
+ >>> registry.lookup([IF1, IR1], IB0, 'bob')
+ 1
+ """
+
+def test_adapter_hook_with_factory_producing_None():
+ """
+ >>> registry = AdapterRegistry()
+ >>> default = object()
+
+ >>> class Object1(object):
+ ... zope.interface.implements(IF0)
+ >>> class Object2(object):
+ ... zope.interface.implements(IF0)
+
+ >>> def factory(context):
+ ... if isinstance(context, Object1):
+ ... return 'adapter'
+ ... return None
+
+ >>> registry.register([IF0], IB0, '', factory)
+
+ >>> registry.adapter_hook(IB0, Object1())
+ 'adapter'
+ >>> registry.adapter_hook(IB0, Object2()) is None
+ True
+ >>> registry.adapter_hook(IB0, Object2(), default=default) is default
+ True
+ """
+
+def test_adapter_registry_update_upon_interface_bases_change():
+ """
+ Let's first create a adapter registry and a simple adaptation hook:
+
+ >>> globalRegistry = AdapterRegistry()
+
+ >>> def _hook(iface, ob, lookup=globalRegistry.lookup1):
+ ... factory = lookup(zope.interface.providedBy(ob), iface)
+ ... if factory is None:
+ ... return None
+ ... else:
+ ... return factory(ob)
+
+ >>> zope.interface.interface.adapter_hooks.append(_hook)
+
+ Now we create some interfaces and an implementation:
+
+ >>> class IX(zope.interface.Interface):
+ ... pass
+
+ >>> class IY(zope.interface.Interface):
+ ... pass
+
+ >>> class X(object):
+ ... pass
+
+ >>> class Y(object):
+ ... zope.interface.implements(IY)
+ ... def __init__(self, original):
+ ... self.original=original
+
+ and register an adapter:
+
+ >>> globalRegistry.register((IX,), IY, '', Y)
+
+ at first, we still expect the adapter lookup from `X` to `IY` to fail:
+
+ >>> IY(X()) #doctest: +NORMALIZE_WHITESPACE +ELLIPSIS
+ Traceback (most recent call last):
+ ...
+ TypeError: ('Could not adapt',
+ <zope.interface.tests.test_adapter.X object at ...>,
+ <InterfaceClass zope.interface.tests.test_adapter.IY>)
+
+ But after we declare an interface on the class `X`, it should pass:
+
+ >>> zope.interface.classImplementsOnly(X, IX)
+
+ >>> IY(X()) #doctest: +ELLIPSIS
+ <zope.interface.tests.test_adapter.Y object at ...>
+
+ >>> hook = zope.interface.interface.adapter_hooks.pop()
+ """
+
+
+def test_changing_declarations():
+ """
+
+ If we change declarations for a class, those adapter lookup should
+ eflect the changes:
+
+ >>> class I1(zope.interface.Interface):
+ ... pass
+ >>> class I2(zope.interface.Interface):
+ ... pass
+
+ >>> registry = AdapterRegistry()
+ >>> registry.register([I1], I2, '', 42)
+
+ >>> class C:
+ ... pass
+
+ >>> registry.lookup([zope.interface.implementedBy(C)], I2, '')
+
+ >>> zope.interface.classImplements(C, I1)
+
+ >>> registry.lookup([zope.interface.implementedBy(C)], I2, '')
+ 42
+ """
+
+def test_correct_multi_adapter_lookup():
+ """
+ >>> registry = AdapterRegistry()
+ >>> registry.register([IF0, IB1], IR0, '', 'A01')
+ >>> registry.register([IF1, IB0], IR0, '', 'A10')
+ >>> registry.lookup((IF1, IB1), IR0, '')
+ 'A10'
+ """
+
+def test_duplicate_bases():
+ """
+There was a bug that caused problems if a spec had multiple bases:
+
+ >>> class I(zope.interface.Interface):
+ ... pass
+ >>> class I2(I, I):
+ ... pass
+ >>> registry = AdapterRegistry()
+ >>> registry.register([I2], IR0, 'x', 'X')
+ >>> registry.lookup((I2, ), IR0, 'x')
+ 'X'
+ >>> registry.register([I2], IR0, 'y', 'Y')
+ >>> registry.lookup((I2, ), IR0, 'x')
+ 'X'
+ >>> registry.lookup((I2, ), IR0, 'y')
+ 'Y'
+"""
+
+
+def test_suite():
+ from zope.testing import doctest, doctestunit
+ return unittest.TestSuite((
+ doctestunit.DocFileSuite('../adapter.txt', '../human.txt',
+ '../human.ru.txt', 'foodforthought.txt',
+ globs={'__name__': '__main__'}),
+ doctest.DocTestSuite(),
+ ))
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
diff --git a/zope/interface/tests/test_advice.py b/zope/interface/tests/test_advice.py
new file mode 100644
index 0000000..7f61a06
--- /dev/null
+++ b/zope/interface/tests/test_advice.py
@@ -0,0 +1,178 @@
+
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Tests for advice
+
+This module was adapted from 'protocols.tests.advice', part of the Python
+Enterprise Application Kit (PEAK). Please notify the PEAK authors
+(pje@telecommunity.com and tsarna@sarna.org) if bugs are found or
+Zope-specific changes are required, so that the PEAK version of this module
+can be kept in sync.
+
+PEAK is a Python application framework that interoperates with (but does
+not require) Zope 3 and Twisted. It provides tools for manipulating UML
+models, object-relational persistence, aspect-oriented programming, and more.
+Visit the PEAK home page at http://peak.telecommunity.com for more information.
+
+$Id: test_advice.py 40836 2005-12-16 22:40:51Z benji_york $
+"""
+
+import unittest
+from unittest import TestCase, makeSuite, TestSuite
+from zope.interface.advice import *
+from types import ClassType
+import sys
+
+def ping(log, value):
+
+ def pong(klass):
+ log.append((value,klass))
+ return [klass]
+
+ addClassAdvisor(pong)
+
+class ClassicClass:
+ __metaclass__ = ClassType
+ classLevelFrameInfo = getFrameInfo(sys._getframe())
+
+class NewStyleClass:
+ __metaclass__ = type
+ classLevelFrameInfo = getFrameInfo(sys._getframe())
+
+moduleLevelFrameInfo = getFrameInfo(sys._getframe())
+
+class FrameInfoTest(TestCase):
+
+ classLevelFrameInfo = getFrameInfo(sys._getframe())
+
+ def checkModuleInfo(self):
+ kind, module, f_locals, f_globals = moduleLevelFrameInfo
+ self.assertEquals(kind, "module")
+ for d in module.__dict__, f_locals, f_globals:
+ self.assert_(d is globals())
+
+ def checkClassicClassInfo(self):
+ kind, module, f_locals, f_globals = ClassicClass.classLevelFrameInfo
+ self.assertEquals(kind, "class")
+
+ self.assert_(f_locals is ClassicClass.__dict__) # ???
+ for d in module.__dict__, f_globals:
+ self.assert_(d is globals())
+
+ def checkNewStyleClassInfo(self):
+ kind, module, f_locals, f_globals = NewStyleClass.classLevelFrameInfo
+ self.assertEquals(kind, "class")
+
+ for d in module.__dict__, f_globals:
+ self.assert_(d is globals())
+
+ def checkCallInfo(self):
+ kind, module, f_locals, f_globals = getFrameInfo(sys._getframe())
+ self.assertEquals(kind, "function call")
+ self.assert_(f_locals is locals()) # ???
+ for d in module.__dict__, f_globals:
+ self.assert_(d is globals())
+
+
+class AdviceTests(TestCase):
+
+ def checkOrder(self):
+ log = []
+ class Foo(object):
+ ping(log, 1)
+ ping(log, 2)
+ ping(log, 3)
+
+ # Strip the list nesting
+ for i in 1,2,3:
+ self.assert_(isinstance(Foo, list))
+ Foo, = Foo
+
+ self.assertEquals(log, [(1, Foo), (2, [Foo]), (3, [[Foo]])])
+
+ def TODOcheckOutside(self):
+ # Disabled because the check does not work with doctest tests.
+ try:
+ ping([], 1)
+ except SyntaxError:
+ pass
+ else:
+ raise AssertionError(
+ "Should have detected advice outside class body"
+ )
+
+ def checkDoubleType(self):
+ if sys.hexversion >= 0x02030000:
+ return # you can't duplicate bases in 2.3
+ class aType(type,type):
+ ping([],1)
+ aType, = aType
+ self.assert_(aType.__class__ is type)
+
+ def checkSingleExplicitMeta(self):
+
+ class M(type):
+ pass
+
+ class C(M):
+ __metaclass__ = M
+ ping([],1)
+
+ C, = C
+ self.assert_(C.__class__ is M)
+
+
+ def checkMixedMetas(self):
+
+ class M1(type): pass
+ class M2(type): pass
+
+ class B1: __metaclass__ = M1
+ class B2: __metaclass__ = M2
+
+ try:
+ class C(B1,B2):
+ ping([],1)
+ except TypeError:
+ pass
+ else:
+ raise AssertionError("Should have gotten incompatibility error")
+
+ class M3(M1,M2): pass
+
+ class C(B1,B2):
+ __metaclass__ = M3
+ ping([],1)
+
+ self.assert_(isinstance(C,list))
+ C, = C
+ self.assert_(isinstance(C,M3))
+
+ def checkMetaOfClass(self):
+
+ class metameta(type):
+ pass
+
+ class meta(type):
+ __metaclass__ = metameta
+
+ self.assertEquals(determineMetaclass((meta, type)), metameta)
+
+TestClasses = (AdviceTests, FrameInfoTest)
+
+def test_suite():
+ return TestSuite([makeSuite(t,'check') for t in TestClasses])
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
diff --git a/zope/interface/tests/test_declarations.py b/zope/interface/tests/test_declarations.py
new file mode 100644
index 0000000..29a7270
--- /dev/null
+++ b/zope/interface/tests/test_declarations.py
@@ -0,0 +1,416 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Test the new API for making and checking interface declarations
+
+$Id: test_declarations.py 67630 2006-04-27 00:54:03Z jim $
+"""
+import unittest
+from zope.interface import *
+from zope.testing.doctestunit import DocTestSuite
+from zope.interface import Interface
+
+class I1(Interface): pass
+class I2(Interface): pass
+class I3(Interface): pass
+class I4(Interface): pass
+class I5(Interface): pass
+
+class A(object):
+ implements(I1)
+class B(object):
+ implements(I2)
+class C(A, B):
+ implements(I3)
+
+class COnly(A, B):
+ implementsOnly(I3)
+
+class COnly_old(A, B):
+ __implemented__ = I3
+
+class D(COnly):
+ implements(I5)
+
+def test_ObjectSpecification_Simple():
+ """
+ >>> c = C()
+ >>> directlyProvides(c, I4)
+ >>> [i.__name__ for i in providedBy(c)]
+ ['I4', 'I3', 'I1', 'I2']
+ """
+
+def test_ObjectSpecification_Simple_w_only():
+ """
+ >>> c = COnly()
+ >>> directlyProvides(c, I4)
+ >>> [i.__name__ for i in providedBy(c)]
+ ['I4', 'I3']
+ """
+
+def test_ObjectSpecification_Simple_old_style():
+ """
+ >>> c = COnly_old()
+ >>> directlyProvides(c, I4)
+ >>> [i.__name__ for i in providedBy(c)]
+ ['I4', 'I3']
+ """
+
+
+class Test(unittest.TestCase):
+
+ # Note that most of the tests are in the doc strings of the
+ # declarations module.
+
+ def test_backward_compat(self):
+
+ class C1(object): __implemented__ = I1
+ class C2(C1): __implemented__ = I2, I5
+ class C3(C2): __implemented__ = I3, C2.__implemented__
+
+ self.assert_(C3.__implemented__.__class__ is tuple)
+
+ self.assertEqual(
+ [i.getName() for i in providedBy(C3())],
+ ['I3', 'I2', 'I5'],
+ )
+
+ class C4(C3):
+ implements(I4)
+
+ self.assertEqual(
+ [i.getName() for i in providedBy(C4())],
+ ['I4', 'I3', 'I2', 'I5'],
+ )
+
+ self.assertEqual(
+ [i.getName() for i in C4.__implemented__],
+ ['I4', 'I3', 'I2', 'I5'],
+ )
+
+ # Note that C3.__implemented__ should now be a sequence of interfaces
+ self.assertEqual(
+ [i.getName() for i in C3.__implemented__],
+ ['I3', 'I2', 'I5'],
+ )
+ self.failIf(C3.__implemented__.__class__ is tuple)
+
+ def test_module(self):
+ import zope.interface.tests.m1
+ import zope.interface.tests.m2
+ directlyProvides(zope.interface.tests.m2,
+ zope.interface.tests.m1.I1,
+ zope.interface.tests.m1.I2,
+ )
+ self.assertEqual(list(providedBy(zope.interface.tests.m1)),
+ list(providedBy(zope.interface.tests.m2)),
+ )
+
+ def test_builtins(self):
+ # Setup
+
+ intspec = implementedBy(int)
+ olddeclared = intspec.declared
+
+ classImplements(int, I1)
+ class myint(int):
+ implements(I2)
+
+ x = 42
+ self.assertEqual([i.getName() for i in providedBy(x)],
+ ['I1'])
+
+ x = myint(42)
+ directlyProvides(x, I3)
+ self.assertEqual([i.getName() for i in providedBy(x)],
+ ['I3', 'I2', 'I1'])
+
+ # cleanup
+ intspec.declared = olddeclared
+ classImplements(int)
+
+ x = 42
+ self.assertEqual([i.getName() for i in providedBy(x)],
+ [])
+
+
+def test_signature_w_no_class_interfaces():
+ """
+ >>> from zope.interface import *
+ >>> class C(object):
+ ... pass
+ >>> c = C()
+ >>> list(providedBy(c))
+ []
+
+ >>> class I(Interface):
+ ... pass
+ >>> directlyProvides(c, I)
+ >>> list(providedBy(c)) == list(directlyProvidedBy(c))
+ 1
+ """
+
+def test_classImplement_on_deeply_nested_classes():
+ """This test is in response to a bug found, which is why it's a bit
+ contrived
+
+ >>> from zope.interface import *
+ >>> class B1(object):
+ ... pass
+ >>> class B2(B1):
+ ... pass
+ >>> class B3(B2):
+ ... pass
+ >>> class D(object):
+ ... implements()
+ >>> class S(B3, D):
+ ... implements()
+
+ This failed due to a bug in the code for finding __providedBy__
+ descriptors for old-style classes.
+
+ """
+
+def test_pickle_provides_specs():
+ """
+ >>> from pickle import dumps, loads
+ >>> a = A()
+ >>> I2.providedBy(a)
+ 0
+ >>> directlyProvides(a, I2)
+ >>> I2.providedBy(a)
+ 1
+ >>> a2 = loads(dumps(a))
+ >>> I2.providedBy(a2)
+ 1
+
+ """
+
+def test_that_we_dont_inherit_class_provides():
+ """
+ >>> class X(object):
+ ... classProvides(I1)
+ >>> class Y(X):
+ ... pass
+ >>> [i.__name__ for i in X.__provides__]
+ ['I1']
+ >>> Y.__provides__
+ Traceback (most recent call last):
+ ...
+ AttributeError: __provides__
+
+ """
+
+def test_that_we_dont_inherit_provides_optimizations():
+ """
+
+ When we make a declaration for a class, we install a __provides__
+ descriptors that provides a default for instances that don't have
+ instance-specific declarations:
+
+ >>> class A(object):
+ ... implements(I1)
+
+ >>> class B(object):
+ ... implements(I2)
+
+ >>> [i.__name__ for i in A().__provides__]
+ ['I1']
+ >>> [i.__name__ for i in B().__provides__]
+ ['I2']
+
+ But it's important that we don't use this for subclasses without
+ declarations. This would cause incorrect results:
+
+ >>> class X(A, B):
+ ... pass
+
+ >>> X().__provides__
+ Traceback (most recent call last):
+ ...
+ AttributeError: __provides__
+
+ However, if we "induce" a declaration, by calling implementedBy
+ (even indirectly through providedBy):
+
+ >>> [i.__name__ for i in providedBy(X())]
+ ['I1', 'I2']
+
+
+ then the optimization will work:
+
+ >>> [i.__name__ for i in X().__provides__]
+ ['I1', 'I2']
+
+ """
+
+def test_classProvides_before_implements():
+ """Special descriptor for class __provides__
+
+ The descriptor caches the implementedBy info, so that
+ we can get declarations for objects without instance-specific
+ interfaces a bit quicker.
+
+ For example::
+
+ >>> from zope.interface import Interface
+ >>> class IFooFactory(Interface):
+ ... pass
+ >>> class IFoo(Interface):
+ ... pass
+ >>> class C(object):
+ ... classProvides(IFooFactory)
+ ... implements(IFoo)
+ >>> [i.getName() for i in C.__provides__]
+ ['IFooFactory']
+
+ >>> [i.getName() for i in C().__provides__]
+ ['IFoo']
+ """
+
+def test_getting_spec_for_proxied_builtin_class():
+ """
+
+ In general, we should be able to get a spec
+ for a proxied class if someone has declared or
+ asked for a spec before.
+
+ We don't want to depend on proxies in this (zope.interface)
+ package, but we do want to work with proxies. Proxies have the
+ effect that a class's __dict__ cannot be gotten. Further, for
+ built-in classes, we can't save, and thus, cannot get, any class
+ attributes. We'll emulate this by treating a plain object as a class:
+
+ >>> cls = object()
+
+ We'll create an implements specification:
+
+ >>> import zope.interface.declarations
+ >>> impl = zope.interface.declarations.Implements(I1, I2)
+
+ Now, we'll emulate a declaration for a built-in type by putting
+ it in BuiltinImplementationSpecifications:
+
+ >>> zope.interface.declarations.BuiltinImplementationSpecifications[
+ ... cls] = impl
+
+ Now, we should be able to get it back:
+
+ >>> implementedBy(cls) is impl
+ True
+
+ Of course, we don't want to leave it there. :)
+
+ >>> del zope.interface.declarations.BuiltinImplementationSpecifications[
+ ... cls]
+
+ """
+
+def test_declaration_get():
+ """
+ We can get definitions from a declaration:
+
+ >>> import zope.interface
+ >>> class I1(zope.interface.Interface):
+ ... a11 = zope.interface.Attribute('a11')
+ ... a12 = zope.interface.Attribute('a12')
+ >>> class I2(zope.interface.Interface):
+ ... a21 = zope.interface.Attribute('a21')
+ ... a22 = zope.interface.Attribute('a22')
+ ... a12 = zope.interface.Attribute('a212')
+ >>> class I11(I1):
+ ... a11 = zope.interface.Attribute('a111')
+
+ >>> decl = Declaration(I11, I2)
+ >>> decl.get('a11') is I11.get('a11')
+ True
+ >>> decl.get('a12') is I1.get('a12')
+ True
+ >>> decl.get('a21') is I2.get('a21')
+ True
+ >>> decl.get('a22') is I2.get('a22')
+ True
+ >>> decl.get('a')
+ >>> decl.get('a', 42)
+ 42
+
+ We get None even with no interfaces:
+
+ >>> decl = Declaration()
+ >>> decl.get('a11')
+ >>> decl.get('a11', 42)
+ 42
+
+ We get new data if e change interface bases:
+
+ >>> decl.__bases__ = I11, I2
+ >>> decl.get('a11') is I11.get('a11')
+ True
+ """
+
+def test_classImplements_after_classImplementsOnly_issue_402():
+ """http://www.zope.org/Collectors/Zope3-dev/402
+
+>>> from zope.interface import *
+>>> class I1(Interface):
+... pass
+>>> class I2(Interface):
+... pass
+>>> class C:
+... implements(I1)
+>>> class C2:
+... implementsOnly(I2)
+>>> class I3(Interface):
+... pass
+
+>>> [i.__name__ for i in providedBy(C2()).__iro__]
+['I2', 'Interface']
+
+>>> classImplements(C2, I3)
+>>> [i.__name__ for i in providedBy(C2()).__iro__]
+['I2', 'I3', 'Interface']
+
+>>> class I4(Interface):
+... pass
+>>> classImplements(C2, I4)
+>>> [i.__name__ for i in providedBy(C2()).__iro__]
+['I2', 'I3', 'I4', 'Interface']
+
+
+"""
+
+def test_picklability_of_implements_specifications():
+ """
+
+ Sometimes, we need to pickle implements specs. We should be able
+ to do so as long as the class is picklable.
+
+ >>> import pickle
+ >>> pickle.loads(pickle.dumps(implementedBy(C))) is implementedBy(C)
+ True
+
+
+ """
+
+
+def test_suite():
+ suite = unittest.TestSuite()
+ suite.addTest(unittest.makeSuite(Test))
+ suite.addTest(DocTestSuite("zope.interface.declarations"))
+ suite.addTest(DocTestSuite())
+
+ return suite
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/zope/interface/tests/test_document.py b/zope/interface/tests/test_document.py
new file mode 100644
index 0000000..a5bd879
--- /dev/null
+++ b/zope/interface/tests/test_document.py
@@ -0,0 +1,71 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Documentation tests.
+
+$Id: test_document.py 26560 2004-07-15 21:38:42Z srichter $
+"""
+from unittest import TestCase, main, makeSuite
+
+from zope.interface import Interface, Attribute
+
+class Test(TestCase):
+
+ def testBlech(self):
+ from zope.interface.document import asStructuredText
+
+ self.assertEqual(asStructuredText(I2), '''\
+I2
+
+ I2 doc
+
+ This interface extends:
+
+ o _I1
+
+ Attributes:
+
+ a1 -- no documentation
+
+ a2 -- a2 doc
+
+ Methods:
+
+ f21() -- f21 doc
+
+ f22() -- no documentation
+
+ f23() -- f23 doc
+
+''')
+
+
+def test_suite():
+ return makeSuite(Test)
+
+class _I1(Interface):
+ def f11(): pass
+ def f12(): pass
+
+class I2(_I1):
+ "I2 doc"
+
+ a1 = Attribute('a1')
+ a2 = Attribute('a2', 'a2 doc')
+
+ def f21(): "f21 doc"
+ def f22(): pass
+ def f23(): "f23 doc"
+
+if __name__=='__main__':
+ main(defaultTest='test_suite')
diff --git a/zope/interface/tests/test_element.py b/zope/interface/tests/test_element.py
new file mode 100644
index 0000000..33edc3f
--- /dev/null
+++ b/zope/interface/tests/test_element.py
@@ -0,0 +1,43 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Test Element meta-class.
+
+$Id: test_element.py 39768 2005-10-31 13:57:35Z tlotze $
+"""
+
+import unittest
+from zope.interface.interface import Element
+
+class TestElement(unittest.TestCase):
+
+ def test_taggedValues(self):
+ """Test that we can update tagged values of more than one element
+ """
+
+ e1 = Element("foo")
+ e2 = Element("bar")
+ e1.setTaggedValue("x", 1)
+ e2.setTaggedValue("x", 2)
+ self.assertEqual(e1.getTaggedValue("x"), 1)
+ self.assertEqual(e2.getTaggedValue("x"), 2)
+
+
+def test_suite():
+ suite = unittest.TestSuite()
+ suite.addTest(unittest.makeSuite(TestElement))
+ return suite
+
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
diff --git a/zope/interface/tests/test_interface.py b/zope/interface/tests/test_interface.py
new file mode 100644
index 0000000..f444c51
--- /dev/null
+++ b/zope/interface/tests/test_interface.py
@@ -0,0 +1,352 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Test Interface implementation
+
+$Id: test_interface.py 67761 2006-04-30 13:56:44Z jim $
+"""
+import sys
+import unittest
+from zope.testing.doctestunit import DocTestSuite
+from zope.interface.tests.unitfixtures import * # hehehe
+from zope.interface.exceptions import BrokenImplementation, Invalid
+from zope.interface import implementedBy, providedBy
+from zope.interface import Interface, directlyProvides, Attribute
+from zope import interface
+
+class InterfaceTests(unittest.TestCase):
+
+ def testInterfaceSetOnAttributes(self):
+ self.assertEqual(FooInterface['foobar'].interface,
+ FooInterface)
+ self.assertEqual(FooInterface['aMethod'].interface,
+ FooInterface)
+
+ def testClassImplements(self):
+ self.assert_(IC.implementedBy(C))
+
+ self.assert_(I1.implementedBy(A))
+ self.assert_(I1.implementedBy(B))
+ self.assert_(not I1.implementedBy(C))
+ self.assert_(I1.implementedBy(D))
+ self.assert_(I1.implementedBy(E))
+
+ self.assert_(not I2.implementedBy(A))
+ self.assert_(I2.implementedBy(B))
+ self.assert_(not I2.implementedBy(C))
+
+ # No longer after interfacegeddon
+ # self.assert_(not I2.implementedBy(D))
+
+ self.assert_(not I2.implementedBy(E))
+
+ def testUtil(self):
+ self.assert_(IC in implementedBy(C))
+ self.assert_(I1 in implementedBy(A))
+ self.assert_(not I1 in implementedBy(C))
+ self.assert_(I2 in implementedBy(B))
+ self.assert_(not I2 in implementedBy(C))
+
+ self.assert_(IC in providedBy(C()))
+ self.assert_(I1 in providedBy(A()))
+ self.assert_(not I1 in providedBy(C()))
+ self.assert_(I2 in providedBy(B()))
+ self.assert_(not I2 in providedBy(C()))
+
+
+ def testObjectImplements(self):
+ self.assert_(IC.providedBy(C()))
+
+ self.assert_(I1.providedBy(A()))
+ self.assert_(I1.providedBy(B()))
+ self.assert_(not I1.providedBy(C()))
+ self.assert_(I1.providedBy(D()))
+ self.assert_(I1.providedBy(E()))
+
+ self.assert_(not I2.providedBy(A()))
+ self.assert_(I2.providedBy(B()))
+ self.assert_(not I2.providedBy(C()))
+
+ # Not after interface geddon
+ # self.assert_(not I2.providedBy(D()))
+
+ self.assert_(not I2.providedBy(E()))
+
+ def testDeferredClass(self):
+ a = A()
+ self.assertRaises(BrokenImplementation, a.ma)
+
+
+ def testInterfaceExtendsInterface(self):
+ self.assert_(BazInterface.extends(BobInterface))
+ self.assert_(BazInterface.extends(BarInterface))
+ self.assert_(BazInterface.extends(FunInterface))
+ self.assert_(not BobInterface.extends(FunInterface))
+ self.assert_(not BobInterface.extends(BarInterface))
+ self.assert_(BarInterface.extends(FunInterface))
+ self.assert_(not BarInterface.extends(BazInterface))
+
+ def testVerifyImplementation(self):
+ from zope.interface.verify import verifyClass
+ self.assert_(verifyClass(FooInterface, Foo))
+ self.assert_(Interface.providedBy(I1))
+
+ def test_names(self):
+ names = list(_I2.names()); names.sort()
+ self.assertEqual(names, ['f21', 'f22', 'f23'])
+ names = list(_I2.names(all=True)); names.sort()
+ self.assertEqual(names, ['a1', 'f11', 'f12', 'f21', 'f22', 'f23'])
+
+ def test_namesAndDescriptions(self):
+ names = [nd[0] for nd in _I2.namesAndDescriptions()]; names.sort()
+ self.assertEqual(names, ['f21', 'f22', 'f23'])
+ names = [nd[0] for nd in _I2.namesAndDescriptions(1)]; names.sort()
+ self.assertEqual(names, ['a1', 'f11', 'f12', 'f21', 'f22', 'f23'])
+
+ for name, d in _I2.namesAndDescriptions(1):
+ self.assertEqual(name, d.__name__)
+
+ def test_getDescriptionFor(self):
+ self.assertEqual(_I2.getDescriptionFor('f11').__name__, 'f11')
+ self.assertEqual(_I2.getDescriptionFor('f22').__name__, 'f22')
+ self.assertEqual(_I2.queryDescriptionFor('f33', self), self)
+ self.assertRaises(KeyError, _I2.getDescriptionFor, 'f33')
+
+ def test___getitem__(self):
+ self.assertEqual(_I2['f11'].__name__, 'f11')
+ self.assertEqual(_I2['f22'].__name__, 'f22')
+ self.assertEqual(_I2.get('f33', self), self)
+ self.assertRaises(KeyError, _I2.__getitem__, 'f33')
+
+ def test___contains__(self):
+ self.failUnless('f11' in _I2)
+ self.failIf('f33' in _I2)
+
+ def test___iter__(self):
+ names = list(iter(_I2))
+ names.sort()
+ self.assertEqual(names, ['a1', 'f11', 'f12', 'f21', 'f22', 'f23'])
+
+ def testAttr(self):
+ description = _I2.getDescriptionFor('a1')
+ self.assertEqual(description.__name__, 'a1')
+ self.assertEqual(description.__doc__, 'This is an attribute')
+
+ def testFunctionAttributes(self):
+ # Make sure function attributes become tagged values.
+ meth = _I1['f12']
+ self.assertEqual(meth.getTaggedValue('optional'), 1)
+
+ def testInvariant(self):
+ # set up
+ o = InvariantC()
+ directlyProvides(o, IInvariant)
+ # a helper
+ def errorsEqual(self, o, error_len, error_msgs, interface=None):
+ if interface is None:
+ interface = IInvariant
+ self.assertRaises(Invalid, interface.validateInvariants, o)
+ e = []
+ try:
+ interface.validateInvariants(o, e)
+ except Invalid, error:
+ self.assertEquals(error.args[0], e)
+ else:
+ self._assert(0) # validateInvariants should always raise
+ # Invalid
+ self.assertEquals(len(e), error_len)
+ msgs = [error.args[0] for error in e]
+ msgs.sort()
+ for msg in msgs:
+ self.assertEquals(msg, error_msgs.pop(0))
+ # the tests
+ self.assertEquals(IInvariant.getTaggedValue('invariants'),
+ [ifFooThenBar])
+ self.assertEquals(IInvariant.validateInvariants(o), None)
+ o.bar = 27
+ self.assertEquals(IInvariant.validateInvariants(o), None)
+ o.foo = 42
+ self.assertEquals(IInvariant.validateInvariants(o), None)
+ del o.bar
+ errorsEqual(self, o, 1, ['If Foo, then Bar!'])
+ # nested interfaces with invariants:
+ self.assertEquals(ISubInvariant.getTaggedValue('invariants'),
+ [BarGreaterThanFoo])
+ o = InvariantC()
+ directlyProvides(o, ISubInvariant)
+ o.foo = 42
+ # even though the interface has changed, we should still only have one
+ # error.
+ errorsEqual(self, o, 1, ['If Foo, then Bar!'], ISubInvariant)
+ # however, if we set foo to 0 (Boolean False) and bar to a negative
+ # number then we'll get the new error
+ o.foo = 2
+ o.bar = 1
+ errorsEqual(self, o, 1, ['Please, Boo MUST be greater than Foo!'],
+ ISubInvariant)
+ # and if we set foo to a positive number and boo to 0, we'll
+ # get both errors!
+ o.foo = 1
+ o.bar = 0
+ errorsEqual(self, o, 2, ['If Foo, then Bar!',
+ 'Please, Boo MUST be greater than Foo!'],
+ ISubInvariant)
+ # for a happy ending, we'll make the invariants happy
+ o.foo = 1
+ o.bar = 2
+ self.assertEquals(IInvariant.validateInvariants(o), None) # woohoo
+ # now we'll do two invariants on the same interface,
+ # just to make sure that a small
+ # multi-invariant interface is at least minimally tested.
+ o = InvariantC()
+ directlyProvides(o, IInvariant)
+ o.foo = 42
+ old_invariants = IInvariant.getTaggedValue('invariants')
+ invariants = old_invariants[:]
+ invariants.append(BarGreaterThanFoo) # if you really need to mutate,
+ # then this would be the way to do it. Probably a bad idea, though. :-)
+ IInvariant.setTaggedValue('invariants', invariants)
+ #
+ # even though the interface has changed, we should still only have one
+ # error.
+ errorsEqual(self, o, 1, ['If Foo, then Bar!'])
+ # however, if we set foo to 0 (Boolean False) and bar to a negative
+ # number then we'll get the new error
+ o.foo = 2
+ o.bar = 1
+ errorsEqual(self, o, 1, ['Please, Boo MUST be greater than Foo!'])
+ # and if we set foo to a positive number and boo to 0, we'll
+ # get both errors!
+ o.foo = 1
+ o.bar = 0
+ errorsEqual(self, o, 2, ['If Foo, then Bar!',
+ 'Please, Boo MUST be greater than Foo!'])
+ # for another happy ending, we'll make the invariants happy again
+ o.foo = 1
+ o.bar = 2
+ self.assertEquals(IInvariant.validateInvariants(o), None) # bliss
+ # clean up
+ IInvariant.setTaggedValue('invariants', old_invariants)
+
+ def test___doc___element(self):
+ class I(Interface):
+ "xxx"
+
+ self.assertEqual(I.__doc__, "xxx")
+ self.assertEqual(list(I), [])
+
+ class I(Interface):
+ "xxx"
+
+ __doc__ = Attribute('the doc')
+
+ self.assertEqual(I.__doc__, "")
+ self.assertEqual(list(I), ['__doc__'])
+
+ def testIssue228(self):
+ # Test for http://collector.zope.org/Zope3-dev/228
+ class I(Interface):
+ "xxx"
+ class Bad:
+ __providedBy__ = None
+ # Old style classes don't have a '__class__' attribute
+ self.failUnlessRaises(AttributeError, I.providedBy, Bad)
+
+
+class _I1(Interface):
+
+ a1 = Attribute("This is an attribute")
+
+ def f11(): pass
+ def f12(): pass
+ f12.optional = 1
+
+class _I1_(_I1): pass
+class _I1__(_I1_): pass
+
+class _I2(_I1__):
+ def f21(): pass
+ def f22(): pass
+ f23 = f22
+
+
+
+if sys.version_info >= (2, 4):
+ def test_invariant_as_decorator():
+ """Invaiants can be deined in line
+
+ >>> class IRange(interface.Interface):
+ ... min = interface.Attribute("Lower bound")
+ ... max = interface.Attribute("Upper bound")
+ ...
+ ... @interface.invariant
+ ... def range_invariant(ob):
+ ... if ob.max < ob.min:
+ ... raise Invalid('max < min')
+
+
+ >>> class Range(object):
+ ... interface.implements(IRange)
+ ...
+ ... def __init__(self, min, max):
+ ... self.min, self.max = min, max
+
+ >>> IRange.validateInvariants(Range(1,2))
+ >>> IRange.validateInvariants(Range(1,1))
+ >>> IRange.validateInvariants(Range(2,1))
+ Traceback (most recent call last):
+ ...
+ Invalid: max < min
+
+
+ """
+
+def duplicate_bases_management():
+ """
+There was a bug that surfaced when an interface was repeated in
+a set of bases and the bases were changed:
+
+ >>> class I(interface.Interface):
+ ... pass
+
+ >>> class I2(I, I):
+ ... pass
+
+ >>> I2.__bases__ = (I,)
+
+
+"""
+
+def test_suite():
+ from zope.testing import doctest
+ suite = unittest.makeSuite(InterfaceTests)
+ suite.addTest(doctest.DocTestSuite("zope.interface.interface"))
+ if sys.version_info >= (2, 4):
+ suite.addTest(doctest.DocTestSuite())
+ suite.addTest(doctest.DocFileSuite(
+ '../README.txt',
+ globs={'__name__': '__main__'},
+ optionflags=doctest.NORMALIZE_WHITESPACE,
+ ))
+ suite.addTest(doctest.DocFileSuite(
+ '../README.ru.txt',
+ globs={'__name__': '__main__'},
+ optionflags=doctest.NORMALIZE_WHITESPACE,
+ ))
+ return suite
+
+def main():
+ unittest.TextTestRunner().run(test_suite())
+
+if __name__=="__main__":
+ main()
diff --git a/zope/interface/tests/test_odd_declarations.py b/zope/interface/tests/test_odd_declarations.py
new file mode 100644
index 0000000..4b6f399
--- /dev/null
+++ b/zope/interface/tests/test_odd_declarations.py
@@ -0,0 +1,204 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Test interface declarations against ExtensionClass-like classes.
+
+These tests are to make sure we do something sane in the presense of
+classic ExtensionClass classes and instances.
+
+$Id: test_odd_declarations.py 40836 2005-12-16 22:40:51Z benji_york $
+"""
+import unittest, odd
+from zope.interface import Interface, implements, implementsOnly
+from zope.interface import directlyProvides, providedBy, directlyProvidedBy
+from zope.interface import classImplements, classImplementsOnly, implementedBy
+
+class I1(Interface): pass
+class I2(Interface): pass
+class I3(Interface): pass
+class I31(I3): pass
+class I4(Interface): pass
+class I5(Interface): pass
+
+class Odd(object): __metaclass__ = odd.MetaClass
+
+class B(Odd): __implemented__ = I2
+
+
+# TODO: We are going to need more magic to make classProvides work with odd
+# classes. This will work in the next iteration. For now, we'll use
+# a different mechanism.
+
+# from zope.interface import classProvides
+
+class A(Odd):
+ implements(I1)
+
+class C(A, B):
+ implements(I31)
+
+
+class Test(unittest.TestCase):
+
+ def test_ObjectSpecification(self):
+ c = C()
+ directlyProvides(c, I4)
+ self.assertEqual([i.getName() for i in providedBy(c)],
+ ['I4', 'I31', 'I1', 'I2']
+ )
+ self.assertEqual([i.getName() for i in providedBy(c).flattened()],
+ ['I4', 'I31', 'I3', 'I1', 'I2', 'Interface']
+ )
+ self.assert_(I1 in providedBy(c))
+ self.failIf(I3 in providedBy(c))
+ self.assert_(providedBy(c).extends(I3))
+ self.assert_(providedBy(c).extends(I31))
+ self.failIf(providedBy(c).extends(I5))
+
+ class COnly(A, B):
+ implementsOnly(I31)
+
+ class D(COnly):
+ implements(I5)
+
+ classImplements(D, I5)
+
+ c = D()
+ directlyProvides(c, I4)
+ self.assertEqual([i.getName() for i in providedBy(c)],
+ ['I4', 'I5', 'I31'])
+ self.assertEqual([i.getName() for i in providedBy(c).flattened()],
+ ['I4', 'I5', 'I31', 'I3', 'Interface'])
+ self.failIf(I1 in providedBy(c))
+ self.failIf(I3 in providedBy(c))
+ self.assert_(providedBy(c).extends(I3))
+ self.failIf(providedBy(c).extends(I1))
+ self.assert_(providedBy(c).extends(I31))
+ self.assert_(providedBy(c).extends(I5))
+
+ class COnly(A, B): __implemented__ = I31
+ class D(COnly):
+ implements(I5)
+
+ classImplements(D, I5)
+ c = D()
+ directlyProvides(c, I4)
+ self.assertEqual([i.getName() for i in providedBy(c)],
+ ['I4', 'I5', 'I31'])
+ self.assertEqual([i.getName() for i in providedBy(c).flattened()],
+ ['I4', 'I5', 'I31', 'I3', 'Interface'])
+ self.failIf(I1 in providedBy(c))
+ self.failIf(I3 in providedBy(c))
+ self.assert_(providedBy(c).extends(I3))
+ self.failIf(providedBy(c).extends(I1))
+ self.assert_(providedBy(c).extends(I31))
+ self.assert_(providedBy(c).extends(I5))
+
+ def test_classImplements(self):
+ class A(Odd):
+ implements(I3)
+
+ class B(Odd):
+ implements(I4)
+
+ class C(A, B):
+ pass
+ classImplements(C, I1, I2)
+ self.assertEqual([i.getName() for i in implementedBy(C)],
+ ['I1', 'I2', 'I3', 'I4'])
+ classImplements(C, I5)
+ self.assertEqual([i.getName() for i in implementedBy(C)],
+ ['I1', 'I2', 'I5', 'I3', 'I4'])
+
+ def test_classImplementsOnly(self):
+ class A(Odd):
+ implements(I3)
+
+ class B(Odd):
+ implements(I4)
+
+ class C(A, B):
+ pass
+ classImplementsOnly(C, I1, I2)
+ self.assertEqual([i.__name__ for i in implementedBy(C)],
+ ['I1', 'I2'])
+
+
+ def test_directlyProvides(self):
+ class IA1(Interface): pass
+ class IA2(Interface): pass
+ class IB(Interface): pass
+ class IC(Interface): pass
+ class A(Odd):
+ implements(IA1, IA2)
+
+ class B(Odd):
+ implements(IB)
+
+ class C(A, B):
+ implements(IC)
+
+
+ ob = C()
+ directlyProvides(ob, I1, I2)
+ self.assert_(I1 in providedBy(ob))
+ self.assert_(I2 in providedBy(ob))
+ self.assert_(IA1 in providedBy(ob))
+ self.assert_(IA2 in providedBy(ob))
+ self.assert_(IB in providedBy(ob))
+ self.assert_(IC in providedBy(ob))
+
+ directlyProvides(ob, directlyProvidedBy(ob)-I2)
+ self.assert_(I1 in providedBy(ob))
+ self.failIf(I2 in providedBy(ob))
+ self.failIf(I2 in providedBy(ob))
+ directlyProvides(ob, directlyProvidedBy(ob), I2)
+ self.assert_(I2 in providedBy(ob))
+
+ def test_directlyProvides_fails_for_odd_class(self):
+ self.assertRaises(TypeError, directlyProvides, C, I5)
+
+ # see above
+ def TODO_test_classProvides_fails_for_odd_class(self):
+ try:
+ class A(Odd):
+ classProvides(I1)
+ except TypeError:
+ pass # Sucess
+ self.assert_(False,
+ "Shouldn't be able to use directlyProvides on odd class."
+ )
+
+ def test_implementedBy(self):
+ class I2(I1): pass
+
+ class C1(Odd):
+ implements(I2)
+
+ class C2(C1):
+ implements(I3)
+
+ self.assertEqual([i.getName() for i in implementedBy(C2)],
+ ['I3', 'I2'])
+
+
+
+
+def test_suite():
+ suite = unittest.TestSuite()
+ suite.addTest(unittest.makeSuite(Test))
+ return suite
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/zope/interface/tests/test_sorting.py b/zope/interface/tests/test_sorting.py
new file mode 100644
index 0000000..004485e
--- /dev/null
+++ b/zope/interface/tests/test_sorting.py
@@ -0,0 +1,49 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Test interface sorting
+
+$Id: test_sorting.py 25177 2004-06-02 13:17:31Z jim $
+"""
+
+from unittest import TestCase, TestSuite, main, makeSuite
+
+from zope.interface import Interface
+
+class I1(Interface): pass
+class I2(I1): pass
+class I3(I1): pass
+class I4(Interface): pass
+class I5(I4): pass
+class I6(I2): pass
+
+
+class Test(TestCase):
+
+ def test(self):
+ l = [I1, I3, I5, I6, I4, I2]
+ l.sort()
+ self.assertEqual(l, [I1, I2, I3, I4, I5, I6])
+
+ def test_w_None(self):
+ l = [I1, None, I3, I5, None, I6, I4, I2]
+ l.sort()
+ self.assertEqual(l, [I1, I2, I3, I4, I5, I6, None, None])
+
+def test_suite():
+ return TestSuite((
+ makeSuite(Test),
+ ))
+
+if __name__=='__main__':
+ main(defaultTest='test_suite')
diff --git a/zope/interface/tests/test_verify.py b/zope/interface/tests/test_verify.py
new file mode 100644
index 0000000..d4fac9a
--- /dev/null
+++ b/zope/interface/tests/test_verify.py
@@ -0,0 +1,196 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Interface Verify tests
+
+$Id: test_verify.py 26866 2004-08-02 20:57:00Z jim $
+"""
+from zope.interface import Interface, implements, classImplements, Attribute
+from zope.interface.verify import verifyClass, verifyObject
+from zope.interface.exceptions import DoesNotImplement, BrokenImplementation
+from zope.interface.exceptions import BrokenMethodImplementation
+
+import unittest
+
+class Test(unittest.TestCase):
+
+ def testNotImplemented(self):
+
+ class C(object): pass
+
+ class I(Interface): pass
+
+ self.assertRaises(DoesNotImplement, verifyClass, I, C)
+
+ classImplements(C, I)
+
+ verifyClass(I, C)
+
+ def testMissingAttr(self):
+
+ class I(Interface):
+ def f(): pass
+
+ class C(object):
+ implements(I)
+
+ self.assertRaises(BrokenImplementation, verifyClass, I, C)
+
+ C.f=lambda self: None
+
+ verifyClass(I, C)
+
+ def testMissingAttr_with_Extended_Interface(self):
+
+ class II(Interface):
+ def f():
+ pass
+
+ class I(II):
+ pass
+
+ class C(object):
+ implements(I)
+
+ self.assertRaises(BrokenImplementation, verifyClass, I, C)
+
+ C.f=lambda self: None
+
+ verifyClass(I, C)
+
+ def testWrongArgs(self):
+
+ class I(Interface):
+ def f(a): pass
+
+ class C(object):
+ def f(self, b): pass
+
+ implements(I)
+
+ # We no longer require names to match.
+ #self.assertRaises(BrokenMethodImplementation, verifyClass, I, C)
+
+ C.f=lambda self, a: None
+
+ verifyClass(I, C)
+
+ C.f=lambda self, **kw: None
+
+ self.assertRaises(BrokenMethodImplementation, verifyClass, I, C)
+
+ C.f=lambda self, a, *args: None
+
+ verifyClass(I, C)
+
+ C.f=lambda self, a, *args, **kw: None
+
+ verifyClass(I, C)
+
+ C.f=lambda self, *args: None
+
+ verifyClass(I, C)
+
+ def testExtraArgs(self):
+
+ class I(Interface):
+ def f(a): pass
+
+ class C(object):
+ def f(self, a, b): pass
+
+ implements(I)
+
+ self.assertRaises(BrokenMethodImplementation, verifyClass, I, C)
+
+ C.f=lambda self, a: None
+
+ verifyClass(I, C)
+
+ C.f=lambda self, a, b=None: None
+
+ verifyClass(I, C)
+
+ def testNoVar(self):
+
+ class I(Interface):
+ def f(a, *args): pass
+
+ class C(object):
+ def f(self, a): pass
+
+ implements(I)
+
+ self.assertRaises(BrokenMethodImplementation, verifyClass, I, C)
+
+ C.f=lambda self, a, *foo: None
+
+ verifyClass(I, C)
+
+ def testNoKW(self):
+
+ class I(Interface):
+ def f(a, **args): pass
+
+ class C(object):
+ def f(self, a): pass
+
+ implements(I)
+
+ self.assertRaises(BrokenMethodImplementation, verifyClass, I, C)
+
+ C.f=lambda self, a, **foo: None
+
+ verifyClass(I, C)
+
+ def testModule(self):
+
+ from zope.interface.tests.ifoo import IFoo
+ from zope.interface.tests import dummy
+
+ verifyObject(IFoo, dummy)
+
+ def testMethodForAttr(self):
+
+ class IFoo(Interface):
+ foo = Attribute("The foo Attribute")
+
+
+ class Foo:
+ implements(IFoo)
+
+ def foo(self):
+ pass
+
+ verifyClass(IFoo, Foo)
+
+ def testNonMethodForMethod(self):
+
+ class IBar(Interface):
+ def foo():
+ pass
+
+ class Bar:
+ implements(IBar)
+
+ foo = 1
+
+ self.assertRaises(BrokenMethodImplementation, verifyClass, IBar, Bar)
+
+
+def test_suite():
+ loader=unittest.TestLoader()
+ return loader.loadTestsFromTestCase(Test)
+
+if __name__=='__main__':
+ unittest.TextTestRunner().run(test_suite())
diff --git a/zope/interface/tests/unitfixtures.py b/zope/interface/tests/unitfixtures.py
new file mode 100644
index 0000000..1007b19
--- /dev/null
+++ b/zope/interface/tests/unitfixtures.py
@@ -0,0 +1,142 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Unit Test Fixtures
+
+$Id: unitfixtures.py 26898 2004-08-04 09:38:12Z hdima $
+"""
+from zope.interface import Interface, invariant
+from zope.interface.interface import Attribute
+from zope.interface.exceptions import Invalid
+
+class mytest(Interface):
+ pass
+
+class C(object):
+ def m1(self, a, b):
+ "return 1"
+ return 1
+
+ def m2(self, a, b):
+ "return 2"
+ return 2
+
+# testInstancesOfClassImplements
+
+# YAGNI IC=Interface.impliedInterface(C)
+class IC(Interface):
+ def m1(a, b):
+ "return 1"
+
+ def m2(a, b):
+ "return 2"
+
+
+
+C.__implemented__=IC
+
+class I1(Interface):
+ def ma():
+ "blah"
+
+class I2(I1): pass
+
+class I3(Interface): pass
+
+class I4(Interface): pass
+
+class A(I1.deferred()):
+ __implemented__=I1
+
+class B(object):
+ __implemented__=I2, I3
+
+class D(A, B): pass
+
+class E(A, B):
+ __implemented__ = A.__implemented__, C.__implemented__
+
+
+class FooInterface(Interface):
+ """ This is an Abstract Base Class """
+
+ foobar = Attribute("fuzzed over beyond all recognition")
+
+ def aMethod(foo, bar, bingo):
+ """ This is aMethod """
+
+ def anotherMethod(foo=6, bar="where you get sloshed", bingo=(1,3,)):
+ """ This is anotherMethod """
+
+ def wammy(zip, *argues):
+ """ yadda yadda """
+
+ def useless(**keywords):
+ """ useless code is fun! """
+
+class Foo(object):
+ """ A concrete class """
+
+ __implemented__ = FooInterface,
+
+ foobar = "yeah"
+
+ def aMethod(self, foo, bar, bingo):
+ """ This is aMethod """
+ return "barf!"
+
+ def anotherMethod(self, foo=6, bar="where you get sloshed", bingo=(1,3,)):
+ """ This is anotherMethod """
+ return "barf!"
+
+ def wammy(self, zip, *argues):
+ """ yadda yadda """
+ return "barf!"
+
+ def useless(self, **keywords):
+ """ useless code is fun! """
+ return "barf!"
+
+foo_instance = Foo()
+
+class Blah(object):
+ pass
+
+new = Interface.__class__
+FunInterface = new('FunInterface')
+BarInterface = new('BarInterface', [FunInterface])
+BobInterface = new('BobInterface')
+BazInterface = new('BazInterface', [BobInterface, BarInterface])
+
+# fixtures for invariant tests
+def ifFooThenBar(obj):
+ if getattr(obj, 'foo', None) and not getattr(obj, 'bar', None):
+ raise Invalid('If Foo, then Bar!')
+class IInvariant(Interface):
+ foo = Attribute('foo')
+ bar = Attribute('bar; must eval to Boolean True if foo does')
+ invariant(ifFooThenBar)
+def BarGreaterThanFoo(obj):
+ foo = getattr(obj, 'foo', None)
+ bar = getattr(obj, 'bar', None)
+ if foo is not None and isinstance(foo, type(bar)):
+ # type checking should be handled elsewhere (like, say,
+ # schema); these invariants should be intra-interface
+ # constraints. This is a hacky way to do it, maybe, but you
+ # get the idea
+ if not bar > foo:
+ raise Invalid('Please, Boo MUST be greater than Foo!')
+class ISubInvariant(IInvariant):
+ invariant(BarGreaterThanFoo)
+class InvariantC(object):
+ pass
diff --git a/zope/interface/verify.py b/zope/interface/verify.py
new file mode 100644
index 0000000..ae1b37a
--- /dev/null
+++ b/zope/interface/verify.py
@@ -0,0 +1,111 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Verify interface implementations
+
+$Id: verify.py 37426 2005-07-26 06:24:15Z hdima $
+"""
+from zope.interface.exceptions import BrokenImplementation, DoesNotImplement
+from zope.interface.exceptions import BrokenMethodImplementation
+from types import FunctionType, MethodType
+from zope.interface.interface import fromMethod, fromFunction, Method
+
+# This will be monkey-patched when running under Zope 2, so leave this
+# here:
+MethodTypes = (MethodType, )
+
+
+def _verify(iface, candidate, tentative=0, vtype=None):
+ """Verify that 'candidate' might correctly implements 'iface'.
+
+ This involves:
+
+ o Making sure the candidate defines all the necessary methods
+
+ o Making sure the methods have the correct signature
+
+ o Making sure the candidate asserts that it implements the interface
+
+ Note that this isn't the same as verifying that the class does
+ implement the interface.
+
+ If optional tentative is true, suppress the "is implemented by" test.
+ """
+
+ if vtype == 'c':
+ tester = iface.implementedBy
+ else:
+ tester = iface.providedBy
+
+ if not tentative and not tester(candidate):
+ raise DoesNotImplement(iface)
+
+ # Here the `desc` is either an `Attribute` or `Method` instance
+ for name, desc in iface.namesAndDescriptions(1):
+ if not hasattr(candidate, name):
+ if (not isinstance(desc, Method)) and vtype == 'c':
+ # We can't verify non-methods on classes, since the
+ # class may provide attrs in it's __init__.
+ continue
+
+ raise BrokenImplementation(iface, name)
+
+ attr = getattr(candidate, name)
+ if not isinstance(desc, Method):
+ # If it's not a method, there's nothing else we can test
+ continue
+
+ if isinstance(attr, FunctionType):
+ # should never get here, since classes should not provide functions
+ meth = fromFunction(attr, iface, name=name)
+ elif (isinstance(attr, MethodTypes)
+ and type(attr.im_func) is FunctionType):
+ meth = fromMethod(attr, iface, name)
+ else:
+ if not callable(attr):
+ raise BrokenMethodImplementation(name, "Not a method")
+ # sigh, it's callable, but we don't know how to intrspect it, so
+ # we have to give it a pass.
+ continue
+
+ # Make sure that the required and implemented method signatures are
+ # the same.
+ desc = desc.getSignatureInfo()
+ meth = meth.getSignatureInfo()
+
+ mess = _incompat(desc, meth)
+ if mess:
+ raise BrokenMethodImplementation(name, mess)
+
+ return True
+
+def verifyClass(iface, candidate, tentative=0):
+ return _verify(iface, candidate, tentative, vtype='c')
+
+def verifyObject(iface, candidate, tentative=0):
+ return _verify(iface, candidate, tentative, vtype='o')
+
+def _incompat(required, implemented):
+ #if (required['positional'] !=
+ # implemented['positional'][:len(required['positional'])]
+ # and implemented['kwargs'] is None):
+ # return 'imlementation has different argument names'
+ if len(implemented['required']) > len(required['required']):
+ return 'implementation requires too many arguments'
+ if ((len(implemented['positional']) < len(required['positional']))
+ and not implemented['varargs']):
+ return "implementation doesn't allow enough arguments"
+ if required['kwargs'] and not implemented['kwargs']:
+ return "implementation doesn't support keyword arguments"
+ if required['varargs'] and not implemented['varargs']:
+ return "implementation doesn't support variable arguments"